Skip to content
English

正文与多工具调用的会话传输 ​

策略的具体实现如下。

ts
export function createSessionModelTransport<const Id extends string>(
  registration: SessionModelTransportRegistration & { readonly id: Id },
): ModelTransportDefinition<ResolvedSessionResult> & { readonly id: Id } {
  const id = registration.id;
  if (typeof id !== 'string' || !id.trim())
    throw new TypeError('Session transport requires an ID');
  const source = registration.tools;
  const options = snapshotModelOptions(registration.options ?? {});
  return Object.freeze({
    id,
    prepare() {
      return prepareSessionFunctions([...source.values()], {
        ...(options.temperature === undefined ? {} : { temperature: options.temperature }),
        ...(options.toolChoice === undefined ? {} : { toolChoice: options.toolChoice }),
        ...(options.parallelToolCalls === undefined
          ? {}
          : { parallelToolCalls: options.parallelToolCalls }),
      });
    },
  });
}

export function prepareSessionFunctions(
  tools: readonly RegisteredModelTool[],
  options: SessionFunctionOptions = {},
): PreparedSessionTransport {
  if (!tools.length) throw new TypeError('Session transport requires registered tools');
  const names = new Map(tools.map((tool) => [wireName(tool.id), tool.id]));
  if (names.size !== tools.length) throw new TypeError('Model wire name collision');
  const functions = tools.map((tool) => ({
    name: wireName(tool.id),
    description: tool.description,
    parameters: tool.inputSchema.jsonSchema,
    strict: false,
  }));
  const instruction =
    'You may answer directly or call one or more registered tools. Prose and calls may appear together. A call is a proposal, not proof of execution.';
  return {
    options: {
      json: false,
      functions,
      toolChoice: options.toolChoice ?? 'auto',
      ...(options.parallelToolCalls === undefined
        ? {}
        : { parallelToolCalls: options.parallelToolCalls }),
      ...(options.temperature === undefined ? {} : { temperature: options.temperature }),
    },
    schemaChars: JSON.stringify(functions).length + instruction.length,
    instruction,
    createResponse(): ModelResponseCollector<ResolvedSessionResult> {
      const collector = createToolCallCollector();
      let text = '';
      return {
        get outputChars() {
          return (
            text.length +
            collector.calls.reduce(
              (sum, call) => sum + call.id.length + call.name.length + call.arguments.length,
              0,
            )
          );
        },
        get calls() {
          try {
            return collector.complete().map((call) => ({
              id: call.id,
              name: call.name,
              argumentChars: call.arguments.length,
              toolId: names.get(call.name),
            }));
          } catch {
            return undefined;
          }
        },
        push(part: ModelPart) {
          if (typeof part === 'string') {
            text += part;
            return;
          }
          collector.push(part);
        },
        finish() {
          const completed = collector.complete();
          if (text.trim() === '' && completed.length === 0)
            modelProtocolError('Model response is empty', 'MODEL_INCOMPLETE');
          const calls = completed.map((call): ResolvedSessionCall => {
            const toolId = names.get(call.name);
            const input = parseArguments(call.arguments);
            return {
              index: call.index,
              id: call.id,
              name: call.name,
              arguments: call.arguments,
              argumentChars: call.arguments.length,
              ...(toolId === undefined ? {} : { toolId }),
              ...(input === undefined ? {} : { input }),
              ...(toolId === undefined
                ? { problem: 'unknown-tool' as const }
                : input === undefined
                  ? { problem: 'invalid-arguments' as const }
                  : {}),
            };
          });
          return { text, calls };
        },
      };
    },
  };
}

接口参考、使用示例与开发指南。