You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
60 lines
1.7 KiB
60 lines
1.7 KiB
import type {
|
|
XChatWithToolsOptions,
|
|
XClientOptions,
|
|
XStreamEvent,
|
|
XToolCall,
|
|
} from "../core/types";
|
|
import { stream } from "./stream";
|
|
import {
|
|
buildAssistantMessage,
|
|
buildRequestBase,
|
|
createToolLoopConfig,
|
|
executeToolCalls,
|
|
throwIfMaxRoundsExceeded,
|
|
} from "./tool-loop-runner";
|
|
|
|
export const streamWithTools = async function* (
|
|
options: XClientOptions,
|
|
input: XChatWithToolsOptions,
|
|
executors: Record<string, (args: unknown, toolCall: import("../core/types").XToolCall) => Promise<unknown> | unknown>,
|
|
): AsyncGenerator<XStreamEvent> {
|
|
const config = createToolLoopConfig(input, options);
|
|
const requestBase = buildRequestBase(input, true);
|
|
|
|
let rounds = 0;
|
|
let currentMessages = [...input.messages];
|
|
|
|
while (rounds < config.maxRounds) {
|
|
rounds += 1;
|
|
const toolCalls: XToolCall[] = [];
|
|
let assistantText = "";
|
|
let assistantReasoning = "";
|
|
|
|
for await (const event of stream(options, {
|
|
...requestBase,
|
|
messages: currentMessages,
|
|
})) {
|
|
if (event.type === "text.delta") {
|
|
assistantText += event.text;
|
|
}
|
|
if (event.type === "reasoning.delta") {
|
|
assistantReasoning += event.text;
|
|
}
|
|
if (event.type === "tool_call.done") {
|
|
toolCalls.push(event.toolCall);
|
|
}
|
|
yield event;
|
|
}
|
|
|
|
if (toolCalls.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const { toolMessages } = await executeToolCalls(config.provider, toolCalls, executors, config.strategy);
|
|
|
|
const assistantMessage = buildAssistantMessage(assistantText, toolCalls, assistantReasoning);
|
|
currentMessages = [...currentMessages, assistantMessage, ...toolMessages];
|
|
}
|
|
|
|
throwIfMaxRoundsExceeded(config);
|
|
};
|
|
|