assistant-stream 0.2.43 → 0.2.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/tool/ToolExecutionStream.d.ts +2 -0
- package/dist/core/tool/ToolExecutionStream.d.ts.map +1 -1
- package/dist/core/tool/ToolExecutionStream.js +13 -1
- package/dist/core/tool/ToolExecutionStream.js.map +1 -1
- package/dist/core/tool/index.d.ts +1 -1
- package/dist/core/tool/index.d.ts.map +1 -1
- package/dist/core/tool/index.js.map +1 -1
- package/dist/core/tool/toolResultStream.d.ts +5 -1
- package/dist/core/tool/toolResultStream.d.ts.map +1 -1
- package/dist/core/tool/toolResultStream.js +44 -12
- package/dist/core/tool/toolResultStream.js.map +1 -1
- package/package.json +2 -2
- package/src/core/tool/ToolExecutionStream.ts +22 -1
- package/src/core/tool/index.ts +1 -0
- package/src/core/tool/toolResultStream.ts +50 -6
|
@@ -16,6 +16,8 @@ type ToolStreamCallback = <TArgs extends ReadonlyJSONObject = ReadonlyJSONObject
|
|
|
16
16
|
type ToolExecutionOptions = {
|
|
17
17
|
execute: ToolCallback;
|
|
18
18
|
streamCall: ToolStreamCallback;
|
|
19
|
+
onExecutionStart?: ((toolCallId: string, toolName: string) => void) | undefined;
|
|
20
|
+
onExecutionEnd?: ((toolCallId: string, toolName: string) => void) | undefined;
|
|
19
21
|
};
|
|
20
22
|
export declare class ToolExecutionStream extends PipeableTransformStream<AssistantStreamChunk, AssistantStreamChunk> {
|
|
21
23
|
constructor(options: ToolExecutionOptions);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolExecutionStream.d.ts","sourceRoot":"","sources":["../../../src/core/tool/ToolExecutionStream.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAK/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAClF,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,KAAK,YAAY,GAAG,CAAC,QAAQ,EAAE;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,kBAAkB,CAAC;CAC1B,KACG,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC,GACxC,YAAY,CAAC,iBAAiB,CAAC,GAC/B,SAAS,CAAC;AAEd,KAAK,kBAAkB,GAAG,CACxB,KAAK,SAAS,kBAAkB,GAAG,kBAAkB,EACrD,OAAO,SAAS,iBAAiB,GAAG,iBAAiB,EACrD,QAAQ,EAAE;IACV,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,KAAK,IAAI,CAAC;AAEX,KAAK,oBAAoB,GAAG;IAC1B,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"ToolExecutionStream.d.ts","sourceRoot":"","sources":["../../../src/core/tool/ToolExecutionStream.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAK/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAClF,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,KAAK,YAAY,GAAG,CAAC,QAAQ,EAAE;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,kBAAkB,CAAC;CAC1B,KACG,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC,GACxC,YAAY,CAAC,iBAAiB,CAAC,GAC/B,SAAS,CAAC;AAEd,KAAK,kBAAkB,GAAG,CACxB,KAAK,SAAS,kBAAkB,GAAG,kBAAkB,EACrD,OAAO,SAAS,iBAAiB,GAAG,iBAAiB,EACrD,QAAQ,EAAE;IACV,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,KAAK,IAAI,CAAC;AAEX,KAAK,oBAAoB,GAAG;IAC1B,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,gBAAgB,CAAC,EACb,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC,GAChD,SAAS,CAAC;IACd,cAAc,CAAC,EAAE,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC/E,CAAC;AAEF,qBAAa,mBAAoB,SAAQ,uBAAuB,CAC9D,oBAAoB,EACpB,oBAAoB,CACrB;gBACa,OAAO,EAAE,oBAAoB;CAyK1C"}
|
|
@@ -61,6 +61,7 @@ var ToolExecutionStream = class extends PipeableTransformStream {
|
|
|
61
61
|
const streamController = toolCallControllers.get(toolCallId);
|
|
62
62
|
if (!streamController)
|
|
63
63
|
throw new Error("No controller found for tool call");
|
|
64
|
+
let isExecuting = false;
|
|
64
65
|
const promise = withPromiseOrValue(
|
|
65
66
|
() => {
|
|
66
67
|
let args;
|
|
@@ -71,13 +72,21 @@ var ToolExecutionStream = class extends PipeableTransformStream {
|
|
|
71
72
|
`Function parameter parsing failed. ${JSON.stringify(e.message)}`
|
|
72
73
|
);
|
|
73
74
|
}
|
|
74
|
-
|
|
75
|
+
const executeResult = options.execute({
|
|
75
76
|
toolCallId,
|
|
76
77
|
toolName,
|
|
77
78
|
args
|
|
78
79
|
});
|
|
80
|
+
if (executeResult !== void 0) {
|
|
81
|
+
isExecuting = true;
|
|
82
|
+
options.onExecutionStart?.(toolCallId, toolName);
|
|
83
|
+
}
|
|
84
|
+
return executeResult;
|
|
79
85
|
},
|
|
80
86
|
(c) => {
|
|
87
|
+
if (isExecuting) {
|
|
88
|
+
options.onExecutionEnd?.(toolCallId, toolName);
|
|
89
|
+
}
|
|
81
90
|
if (c === void 0) return;
|
|
82
91
|
const result = new ToolResponse({
|
|
83
92
|
artifact: c.artifact,
|
|
@@ -92,6 +101,9 @@ var ToolExecutionStream = class extends PipeableTransformStream {
|
|
|
92
101
|
});
|
|
93
102
|
},
|
|
94
103
|
(e) => {
|
|
104
|
+
if (isExecuting) {
|
|
105
|
+
options.onExecutionEnd?.(toolCallId, toolName);
|
|
106
|
+
}
|
|
95
107
|
const result = new ToolResponse({
|
|
96
108
|
result: String(e),
|
|
97
109
|
isError: true
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/tool/ToolExecutionStream.ts"],"sourcesContent":["import sjson from \"secure-json-parse\";\nimport { AssistantStreamChunk } from \"../AssistantStreamChunk\";\nimport {\n AssistantMetaStreamChunk,\n AssistantMetaTransformStream,\n} from \"../utils/stream/AssistantMetaTransformStream\";\nimport { PipeableTransformStream } from \"../utils/stream/PipeableTransformStream\";\nimport {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"../../utils/json/json-value\";\nimport { ToolResponse } from \"./ToolResponse\";\nimport { withPromiseOrValue } from \"../utils/withPromiseOrValue\";\nimport { ToolCallReaderImpl } from \"./ToolCallReader\";\nimport { ToolCallReader } from \"./tool-types\";\n\ntype ToolCallback = (toolCall: {\n toolCallId: string;\n toolName: string;\n args: ReadonlyJSONObject;\n}) =>\n | Promise<ToolResponse<ReadonlyJSONValue>>\n | ToolResponse<ReadonlyJSONValue>\n | undefined;\n\ntype ToolStreamCallback = <\n TArgs extends ReadonlyJSONObject = ReadonlyJSONObject,\n TResult extends ReadonlyJSONValue = ReadonlyJSONValue,\n>(toolCall: {\n reader: ToolCallReader<TArgs, TResult>;\n toolCallId: string;\n toolName: string;\n}) => void;\n\ntype ToolExecutionOptions = {\n execute: ToolCallback;\n streamCall: ToolStreamCallback;\n};\n\nexport class ToolExecutionStream extends PipeableTransformStream<\n AssistantStreamChunk,\n AssistantStreamChunk\n> {\n constructor(options: ToolExecutionOptions) {\n const toolCallPromises = new Map<string, PromiseLike<void>>();\n const toolCallControllers = new Map<\n string,\n ToolCallReaderImpl<ReadonlyJSONObject, ReadonlyJSONValue>\n >();\n\n super((readable) => {\n const transform = new TransformStream<\n AssistantMetaStreamChunk,\n AssistantStreamChunk\n >({\n transform(chunk, controller) {\n // forward everything\n if (chunk.type !== \"part-finish\" || chunk.meta.type !== \"tool-call\") {\n controller.enqueue(chunk);\n }\n\n const type = chunk.type;\n\n switch (type) {\n case \"part-start\":\n if (chunk.part.type === \"tool-call\") {\n const reader = new ToolCallReaderImpl<\n ReadonlyJSONObject,\n ReadonlyJSONValue\n >();\n toolCallControllers.set(chunk.part.toolCallId, reader);\n\n options.streamCall({\n reader,\n toolCallId: chunk.part.toolCallId,\n toolName: chunk.part.toolName,\n });\n }\n break;\n case \"text-delta\": {\n if (chunk.meta.type === \"tool-call\") {\n const toolCallId = chunk.meta.toolCallId;\n\n const controller = toolCallControllers.get(toolCallId);\n if (!controller)\n throw new Error(\"No controller found for tool call\");\n controller.appendArgsTextDelta(chunk.textDelta);\n }\n break;\n }\n case \"result\": {\n if (chunk.meta.type !== \"tool-call\") break;\n\n const { toolCallId } = chunk.meta;\n const controller = toolCallControllers.get(toolCallId);\n if (!controller)\n throw new Error(\"No controller found for tool call\");\n controller.setResponse(\n new ToolResponse({\n result: chunk.result,\n artifact: chunk.artifact,\n isError: chunk.isError,\n }),\n );\n break;\n }\n case \"tool-call-args-text-finish\": {\n if (chunk.meta.type !== \"tool-call\") break;\n\n const { toolCallId, toolName } = chunk.meta;\n const streamController = toolCallControllers.get(toolCallId)!;\n if (!streamController)\n throw new Error(\"No controller found for tool call\");\n\n const promise = withPromiseOrValue(\n () => {\n let args;\n try {\n args = sjson.parse(streamController.argsText);\n } catch (e) {\n throw new Error(\n `Function parameter parsing failed. ${JSON.stringify((e as Error).message)}`,\n );\n }\n\n return options.execute({\n toolCallId,\n toolName,\n args,\n });\n },\n (c) => {\n if (c === undefined) return;\n\n // TODO how to handle new ToolResult({ result: undefined })?\n const result = new ToolResponse({\n artifact: c.artifact,\n result: c.result,\n isError: c.isError,\n });\n streamController.setResponse(result);\n controller.enqueue({\n type: \"result\",\n path: chunk.path,\n ...result,\n });\n },\n (e) => {\n const result = new ToolResponse({\n result: String(e),\n isError: true,\n });\n\n streamController.setResponse(result);\n controller.enqueue({\n type: \"result\",\n path: chunk.path,\n ...result,\n });\n },\n );\n if (promise) {\n toolCallPromises.set(toolCallId, promise);\n }\n break;\n }\n\n case \"part-finish\": {\n if (chunk.meta.type !== \"tool-call\") break;\n\n const { toolCallId } = chunk.meta;\n const toolCallPromise = toolCallPromises.get(toolCallId);\n if (toolCallPromise) {\n toolCallPromise.then(() => {\n toolCallPromises.delete(toolCallId);\n toolCallControllers.delete(toolCallId);\n\n controller.enqueue(chunk);\n });\n } else {\n controller.enqueue(chunk);\n }\n }\n }\n },\n async flush() {\n await Promise.all(toolCallPromises.values());\n },\n });\n\n return readable\n .pipeThrough(new AssistantMetaTransformStream())\n .pipeThrough(transform);\n });\n }\n}\n"],"mappings":"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","names":["controller"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/tool/ToolExecutionStream.ts"],"sourcesContent":["import sjson from \"secure-json-parse\";\nimport { AssistantStreamChunk } from \"../AssistantStreamChunk\";\nimport {\n AssistantMetaStreamChunk,\n AssistantMetaTransformStream,\n} from \"../utils/stream/AssistantMetaTransformStream\";\nimport { PipeableTransformStream } from \"../utils/stream/PipeableTransformStream\";\nimport {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"../../utils/json/json-value\";\nimport { ToolResponse } from \"./ToolResponse\";\nimport { withPromiseOrValue } from \"../utils/withPromiseOrValue\";\nimport { ToolCallReaderImpl } from \"./ToolCallReader\";\nimport { ToolCallReader } from \"./tool-types\";\n\ntype ToolCallback = (toolCall: {\n toolCallId: string;\n toolName: string;\n args: ReadonlyJSONObject;\n}) =>\n | Promise<ToolResponse<ReadonlyJSONValue>>\n | ToolResponse<ReadonlyJSONValue>\n | undefined;\n\ntype ToolStreamCallback = <\n TArgs extends ReadonlyJSONObject = ReadonlyJSONObject,\n TResult extends ReadonlyJSONValue = ReadonlyJSONValue,\n>(toolCall: {\n reader: ToolCallReader<TArgs, TResult>;\n toolCallId: string;\n toolName: string;\n}) => void;\n\ntype ToolExecutionOptions = {\n execute: ToolCallback;\n streamCall: ToolStreamCallback;\n onExecutionStart?:\n | ((toolCallId: string, toolName: string) => void)\n | undefined;\n onExecutionEnd?: ((toolCallId: string, toolName: string) => void) | undefined;\n};\n\nexport class ToolExecutionStream extends PipeableTransformStream<\n AssistantStreamChunk,\n AssistantStreamChunk\n> {\n constructor(options: ToolExecutionOptions) {\n const toolCallPromises = new Map<string, PromiseLike<void>>();\n const toolCallControllers = new Map<\n string,\n ToolCallReaderImpl<ReadonlyJSONObject, ReadonlyJSONValue>\n >();\n\n super((readable) => {\n const transform = new TransformStream<\n AssistantMetaStreamChunk,\n AssistantStreamChunk\n >({\n transform(chunk, controller) {\n // forward everything\n if (chunk.type !== \"part-finish\" || chunk.meta.type !== \"tool-call\") {\n controller.enqueue(chunk);\n }\n\n const type = chunk.type;\n\n switch (type) {\n case \"part-start\":\n if (chunk.part.type === \"tool-call\") {\n const reader = new ToolCallReaderImpl<\n ReadonlyJSONObject,\n ReadonlyJSONValue\n >();\n toolCallControllers.set(chunk.part.toolCallId, reader);\n\n options.streamCall({\n reader,\n toolCallId: chunk.part.toolCallId,\n toolName: chunk.part.toolName,\n });\n }\n break;\n case \"text-delta\": {\n if (chunk.meta.type === \"tool-call\") {\n const toolCallId = chunk.meta.toolCallId;\n\n const controller = toolCallControllers.get(toolCallId);\n if (!controller)\n throw new Error(\"No controller found for tool call\");\n controller.appendArgsTextDelta(chunk.textDelta);\n }\n break;\n }\n case \"result\": {\n if (chunk.meta.type !== \"tool-call\") break;\n\n const { toolCallId } = chunk.meta;\n const controller = toolCallControllers.get(toolCallId);\n if (!controller)\n throw new Error(\"No controller found for tool call\");\n controller.setResponse(\n new ToolResponse({\n result: chunk.result,\n artifact: chunk.artifact,\n isError: chunk.isError,\n }),\n );\n break;\n }\n case \"tool-call-args-text-finish\": {\n if (chunk.meta.type !== \"tool-call\") break;\n\n const { toolCallId, toolName } = chunk.meta;\n const streamController = toolCallControllers.get(toolCallId)!;\n if (!streamController)\n throw new Error(\"No controller found for tool call\");\n\n let isExecuting = false;\n const promise = withPromiseOrValue(\n () => {\n let args;\n try {\n args = sjson.parse(streamController.argsText);\n } catch (e) {\n throw new Error(\n `Function parameter parsing failed. ${JSON.stringify((e as Error).message)}`,\n );\n }\n\n const executeResult = options.execute({\n toolCallId,\n toolName,\n args,\n });\n\n // Only mark as executing if the tool has frontend execution\n if (executeResult !== undefined) {\n isExecuting = true;\n options.onExecutionStart?.(toolCallId, toolName);\n }\n\n return executeResult;\n },\n (c) => {\n if (isExecuting) {\n options.onExecutionEnd?.(toolCallId, toolName);\n }\n\n if (c === undefined) return;\n\n // TODO how to handle new ToolResult({ result: undefined })?\n const result = new ToolResponse({\n artifact: c.artifact,\n result: c.result,\n isError: c.isError,\n });\n streamController.setResponse(result);\n controller.enqueue({\n type: \"result\",\n path: chunk.path,\n ...result,\n });\n },\n (e) => {\n if (isExecuting) {\n options.onExecutionEnd?.(toolCallId, toolName);\n }\n\n const result = new ToolResponse({\n result: String(e),\n isError: true,\n });\n\n streamController.setResponse(result);\n controller.enqueue({\n type: \"result\",\n path: chunk.path,\n ...result,\n });\n },\n );\n if (promise) {\n toolCallPromises.set(toolCallId, promise);\n }\n break;\n }\n\n case \"part-finish\": {\n if (chunk.meta.type !== \"tool-call\") break;\n\n const { toolCallId } = chunk.meta;\n const toolCallPromise = toolCallPromises.get(toolCallId);\n if (toolCallPromise) {\n toolCallPromise.then(() => {\n toolCallPromises.delete(toolCallId);\n toolCallControllers.delete(toolCallId);\n\n controller.enqueue(chunk);\n });\n } else {\n controller.enqueue(chunk);\n }\n }\n }\n },\n async flush() {\n await Promise.all(toolCallPromises.values());\n },\n });\n\n return readable\n .pipeThrough(new AssistantMetaTransformStream())\n .pipeThrough(transform);\n });\n }\n}\n"],"mappings":"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","names":["controller"]}
|
|
@@ -2,5 +2,5 @@ export type { Tool } from "./tool-types";
|
|
|
2
2
|
export { ToolResponse, type ToolResponseLike } from "./ToolResponse";
|
|
3
3
|
export { ToolExecutionStream } from "./ToolExecutionStream";
|
|
4
4
|
export type { ToolCallReader } from "./tool-types";
|
|
5
|
-
export { toolResultStream as unstable_toolResultStream, unstable_runPendingTools, } from "./toolResultStream";
|
|
5
|
+
export { toolResultStream as unstable_toolResultStream, unstable_runPendingTools, type ToolResultStreamOptions, } from "./toolResultStream";
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/tool/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EACL,gBAAgB,IAAI,yBAAyB,EAC7C,wBAAwB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/tool/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EACL,gBAAgB,IAAI,yBAAyB,EAC7C,wBAAwB,EACxB,KAAK,uBAAuB,GAC7B,MAAM,oBAAoB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/tool/index.ts"],"sourcesContent":["export type { Tool } from \"./tool-types\";\nexport { ToolResponse, type ToolResponseLike } from \"./ToolResponse\";\nexport { ToolExecutionStream } from \"./ToolExecutionStream\";\nexport type { ToolCallReader } from \"./tool-types\";\nexport {\n toolResultStream as unstable_toolResultStream,\n unstable_runPendingTools,\n} from \"./toolResultStream\";\n"],"mappings":";AACA,SAAS,oBAA2C;AACpD,SAAS,2BAA2B;AAEpC;AAAA,EACsB;AAAA,EACpB;AAAA,
|
|
1
|
+
{"version":3,"sources":["../../../src/core/tool/index.ts"],"sourcesContent":["export type { Tool } from \"./tool-types\";\nexport { ToolResponse, type ToolResponseLike } from \"./ToolResponse\";\nexport { ToolExecutionStream } from \"./ToolExecutionStream\";\nexport type { ToolCallReader } from \"./tool-types\";\nexport {\n toolResultStream as unstable_toolResultStream,\n unstable_runPendingTools,\n type ToolResultStreamOptions,\n} from \"./toolResultStream\";\n"],"mappings":";AACA,SAAS,oBAA2C;AACpD,SAAS,2BAA2B;AAEpC;AAAA,EACsB;AAAA,EACpB;AAAA,OAEK;","names":[]}
|
|
@@ -2,5 +2,9 @@ import { Tool } from "./tool-types";
|
|
|
2
2
|
import { ToolExecutionStream } from "./ToolExecutionStream";
|
|
3
3
|
import { AssistantMessage } from "../utils/types";
|
|
4
4
|
export declare function unstable_runPendingTools(message: AssistantMessage, tools: Record<string, Tool> | undefined, abortSignal: AbortSignal, human: (toolCallId: string, payload: unknown) => Promise<unknown>): Promise<AssistantMessage>;
|
|
5
|
-
export
|
|
5
|
+
export type ToolResultStreamOptions = {
|
|
6
|
+
onExecutionStart?: (toolCallId: string, toolName: string) => void;
|
|
7
|
+
onExecutionEnd?: (toolCallId: string, toolName: string) => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function toolResultStream(tools: Record<string, Tool> | (() => Record<string, Tool> | undefined) | undefined, abortSignal: AbortSignal | (() => AbortSignal), human: (toolCallId: string, payload: unknown) => Promise<unknown>, options?: ToolResultStreamOptions): ToolExecutionStream;
|
|
6
10
|
//# sourceMappingURL=toolResultStream.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolResultStream.d.ts","sourceRoot":"","sources":["../../../src/core/tool/toolResultStream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAuC,MAAM,cAAc,CAAC;AAGzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"toolResultStream.d.ts","sourceRoot":"","sources":["../../../src/core/tool/toolResultStream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAuC,MAAM,cAAc,CAAC;AAGzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AA+GlD,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,SAAS,EACvC,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,6BAiElE;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAClE,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACjE,CAAC;AAEF,wBAAgB,gBAAgB,CAC9B,KAAK,EACD,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GACpB,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC,GACxC,SAAS,EACb,WAAW,EAAE,WAAW,GAAG,CAAC,MAAM,WAAW,CAAC,EAC9C,KAAK,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,EACjE,OAAO,CAAC,EAAE,uBAAuB,uBAalC"}
|
|
@@ -8,24 +8,54 @@ function getToolResponse(tools, abortSignal, toolCall, human) {
|
|
|
8
8
|
const tool = tools?.[toolCall.toolName];
|
|
9
9
|
if (!tool || !tool.execute) return void 0;
|
|
10
10
|
const getResult = async (toolExecute) => {
|
|
11
|
+
if (abortSignal.aborted) {
|
|
12
|
+
return new ToolResponse({
|
|
13
|
+
result: "Tool execution was cancelled.",
|
|
14
|
+
isError: true
|
|
15
|
+
});
|
|
16
|
+
}
|
|
11
17
|
let executeFn = toolExecute;
|
|
12
18
|
if (isStandardSchemaV1(tool.parameters)) {
|
|
13
|
-
let
|
|
14
|
-
if (
|
|
15
|
-
if (
|
|
19
|
+
let result = tool.parameters["~standard"].validate(toolCall.args);
|
|
20
|
+
if (result instanceof Promise) result = await result;
|
|
21
|
+
if (result.issues) {
|
|
16
22
|
executeFn = tool.experimental_onSchemaValidationError ?? (() => {
|
|
17
23
|
throw new Error(
|
|
18
|
-
`Function parameter validation failed. ${JSON.stringify(
|
|
24
|
+
`Function parameter validation failed. ${JSON.stringify(result.issues)}`
|
|
19
25
|
);
|
|
20
26
|
});
|
|
21
27
|
}
|
|
22
28
|
}
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
const abortPromise = new Promise(
|
|
30
|
+
(resolve) => {
|
|
31
|
+
const onAbort = () => {
|
|
32
|
+
queueMicrotask(() => {
|
|
33
|
+
queueMicrotask(() => {
|
|
34
|
+
resolve(
|
|
35
|
+
new ToolResponse({
|
|
36
|
+
result: "Tool execution was cancelled.",
|
|
37
|
+
isError: true
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
if (abortSignal.aborted) {
|
|
44
|
+
onAbort();
|
|
45
|
+
} else {
|
|
46
|
+
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
const executePromise = (async () => {
|
|
51
|
+
const result = await executeFn(toolCall.args, {
|
|
52
|
+
toolCallId: toolCall.toolCallId,
|
|
53
|
+
abortSignal,
|
|
54
|
+
human: (payload) => human(toolCall.toolCallId, payload)
|
|
55
|
+
});
|
|
56
|
+
return ToolResponse.toResponse(result);
|
|
57
|
+
})();
|
|
58
|
+
return Promise.race([executePromise, abortPromise]);
|
|
29
59
|
};
|
|
30
60
|
return getResult(tool.execute);
|
|
31
61
|
}
|
|
@@ -91,12 +121,14 @@ async function unstable_runPendingTools(message, tools, abortSignal, human) {
|
|
|
91
121
|
content: updatedParts
|
|
92
122
|
};
|
|
93
123
|
}
|
|
94
|
-
function toolResultStream(tools, abortSignal, human) {
|
|
124
|
+
function toolResultStream(tools, abortSignal, human, options) {
|
|
95
125
|
const toolsFn = typeof tools === "function" ? tools : () => tools;
|
|
96
126
|
const abortSignalFn = typeof abortSignal === "function" ? abortSignal : () => abortSignal;
|
|
97
127
|
return new ToolExecutionStream({
|
|
98
128
|
execute: (toolCall) => getToolResponse(toolsFn(), abortSignalFn(), toolCall, human),
|
|
99
|
-
streamCall: ({ reader, ...context }) => getToolStreamResponse(toolsFn(), abortSignalFn(), reader, context, human)
|
|
129
|
+
streamCall: ({ reader, ...context }) => getToolStreamResponse(toolsFn(), abortSignalFn(), reader, context, human),
|
|
130
|
+
onExecutionStart: options?.onExecutionStart,
|
|
131
|
+
onExecutionEnd: options?.onExecutionEnd
|
|
100
132
|
});
|
|
101
133
|
}
|
|
102
134
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/tool/toolResultStream.ts"],"sourcesContent":["import { Tool, ToolCallReader, ToolExecuteFunction } from \"./tool-types\";\nimport { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { ToolResponse } from \"./ToolResponse\";\nimport { ToolExecutionStream } from \"./ToolExecutionStream\";\nimport { AssistantMessage } from \"../utils/types\";\nimport { ReadonlyJSONObject, ReadonlyJSONValue } from \"../../utils\";\n\nconst isStandardSchemaV1 = (\n schema: unknown,\n): schema is StandardSchemaV1<unknown> => {\n return (\n typeof schema === \"object\" &&\n schema !== null &&\n \"~standard\" in schema &&\n (schema as StandardSchemaV1<unknown>)[\"~standard\"].version === 1\n );\n};\n\nfunction getToolResponse(\n tools: Record<string, Tool> | undefined,\n abortSignal: AbortSignal,\n toolCall: {\n toolCallId: string;\n toolName: string;\n args: ReadonlyJSONObject;\n },\n human: (toolCallId: string, payload: unknown) => Promise<unknown>,\n) {\n const tool = tools?.[toolCall.toolName];\n if (!tool || !tool.execute) return undefined;\n\n const getResult = async (\n toolExecute: ToolExecuteFunction<ReadonlyJSONObject, unknown>,\n ): Promise<ToolResponse<ReadonlyJSONValue>> => {\n let executeFn = toolExecute;\n\n if (isStandardSchemaV1(tool.parameters)) {\n let result = tool.parameters[\"~standard\"].validate(toolCall.args);\n if (result instanceof Promise) result = await result;\n\n if (result.issues) {\n executeFn =\n tool.experimental_onSchemaValidationError ??\n (() => {\n throw new Error(\n `Function parameter validation failed. ${JSON.stringify(result.issues)}`,\n );\n });\n }\n }\n\n const result = (await executeFn(toolCall.args, {\n
|
|
1
|
+
{"version":3,"sources":["../../../src/core/tool/toolResultStream.ts"],"sourcesContent":["import { Tool, ToolCallReader, ToolExecuteFunction } from \"./tool-types\";\nimport { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { ToolResponse } from \"./ToolResponse\";\nimport { ToolExecutionStream } from \"./ToolExecutionStream\";\nimport { AssistantMessage } from \"../utils/types\";\nimport { ReadonlyJSONObject, ReadonlyJSONValue } from \"../../utils\";\n\nconst isStandardSchemaV1 = (\n schema: unknown,\n): schema is StandardSchemaV1<unknown> => {\n return (\n typeof schema === \"object\" &&\n schema !== null &&\n \"~standard\" in schema &&\n (schema as StandardSchemaV1<unknown>)[\"~standard\"].version === 1\n );\n};\n\nfunction getToolResponse(\n tools: Record<string, Tool> | undefined,\n abortSignal: AbortSignal,\n toolCall: {\n toolCallId: string;\n toolName: string;\n args: ReadonlyJSONObject;\n },\n human: (toolCallId: string, payload: unknown) => Promise<unknown>,\n) {\n const tool = tools?.[toolCall.toolName];\n if (!tool || !tool.execute) return undefined;\n\n const getResult = async (\n toolExecute: ToolExecuteFunction<ReadonlyJSONObject, unknown>,\n ): Promise<ToolResponse<ReadonlyJSONValue>> => {\n // Check if already aborted before starting\n if (abortSignal.aborted) {\n return new ToolResponse({\n result: \"Tool execution was cancelled.\",\n isError: true,\n });\n }\n\n let executeFn = toolExecute;\n\n if (isStandardSchemaV1(tool.parameters)) {\n let result = tool.parameters[\"~standard\"].validate(toolCall.args);\n if (result instanceof Promise) result = await result;\n\n if (result.issues) {\n executeFn =\n tool.experimental_onSchemaValidationError ??\n (() => {\n throw new Error(\n `Function parameter validation failed. ${JSON.stringify(result.issues)}`,\n );\n });\n }\n }\n\n // Create abort promise that resolves after 2 microtasks\n // This gives tools that handle abort a chance to win the race\n const abortPromise = new Promise<ToolResponse<ReadonlyJSONValue>>(\n (resolve) => {\n const onAbort = () => {\n queueMicrotask(() => {\n queueMicrotask(() => {\n resolve(\n new ToolResponse({\n result: \"Tool execution was cancelled.\",\n isError: true,\n }),\n );\n });\n });\n };\n if (abortSignal.aborted) {\n onAbort();\n } else {\n abortSignal.addEventListener(\"abort\", onAbort, { once: true });\n }\n },\n );\n\n const executePromise = (async () => {\n const result = (await executeFn(toolCall.args, {\n toolCallId: toolCall.toolCallId,\n abortSignal,\n human: (payload: unknown) => human(toolCall.toolCallId, payload),\n })) as unknown as ReadonlyJSONValue;\n return ToolResponse.toResponse(result);\n })();\n\n return Promise.race([executePromise, abortPromise]);\n };\n\n return getResult(tool.execute);\n}\n\nfunction getToolStreamResponse(\n tools: Record<string, Tool> | undefined,\n abortSignal: AbortSignal,\n reader: ToolCallReader<any, ReadonlyJSONValue>,\n context: {\n toolCallId: string;\n toolName: string;\n },\n human: (toolCallId: string, payload: unknown) => Promise<unknown>,\n) {\n tools?.[context.toolName]?.streamCall?.(reader, {\n toolCallId: context.toolCallId,\n abortSignal,\n human: (payload: unknown) => human(context.toolCallId, payload),\n });\n}\n\nexport async function unstable_runPendingTools(\n message: AssistantMessage,\n tools: Record<string, Tool> | undefined,\n abortSignal: AbortSignal,\n human: (toolCallId: string, payload: unknown) => Promise<unknown>,\n) {\n const toolCallPromises = message.parts\n .filter((part) => part.type === \"tool-call\")\n .map(async (part) => {\n const promiseOrUndefined = getToolResponse(\n tools,\n abortSignal,\n part,\n human ??\n (async () => {\n throw new Error(\n \"Tool human input is not supported in this context\",\n );\n }),\n );\n if (promiseOrUndefined) {\n const result = await promiseOrUndefined;\n return {\n toolCallId: part.toolCallId,\n result,\n };\n }\n return null;\n });\n\n const toolCallResults = (await Promise.all(toolCallPromises)).filter(\n (result) => result !== null,\n ) as { toolCallId: string; result: ToolResponse<ReadonlyJSONValue> }[];\n\n if (toolCallResults.length === 0) {\n return message;\n }\n\n const toolCallResultsById = toolCallResults.reduce(\n (acc, { toolCallId, result }) => {\n acc[toolCallId] = result;\n return acc;\n },\n {} as Record<string, ToolResponse<ReadonlyJSONValue>>,\n );\n\n const updatedParts = message.parts.map((p) => {\n if (p.type === \"tool-call\") {\n const toolResponse = toolCallResultsById[p.toolCallId];\n if (toolResponse) {\n return {\n ...p,\n state: \"result\" as const,\n ...(toolResponse.artifact !== undefined\n ? { artifact: toolResponse.artifact }\n : {}),\n result: toolResponse.result as ReadonlyJSONValue,\n isError: toolResponse.isError,\n };\n }\n }\n return p;\n });\n\n return {\n ...message,\n parts: updatedParts,\n content: updatedParts,\n };\n}\n\nexport type ToolResultStreamOptions = {\n onExecutionStart?: (toolCallId: string, toolName: string) => void;\n onExecutionEnd?: (toolCallId: string, toolName: string) => void;\n};\n\nexport function toolResultStream(\n tools:\n | Record<string, Tool>\n | (() => Record<string, Tool> | undefined)\n | undefined,\n abortSignal: AbortSignal | (() => AbortSignal),\n human: (toolCallId: string, payload: unknown) => Promise<unknown>,\n options?: ToolResultStreamOptions,\n) {\n const toolsFn = typeof tools === \"function\" ? tools : () => tools;\n const abortSignalFn =\n typeof abortSignal === \"function\" ? abortSignal : () => abortSignal;\n return new ToolExecutionStream({\n execute: (toolCall) =>\n getToolResponse(toolsFn(), abortSignalFn(), toolCall, human),\n streamCall: ({ reader, ...context }) =>\n getToolStreamResponse(toolsFn(), abortSignalFn(), reader, context, human),\n onExecutionStart: options?.onExecutionStart,\n onExecutionEnd: options?.onExecutionEnd,\n });\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "assistant-stream",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.45",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"sideEffects": false,
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@standard-schema/spec": "^1.0.0",
|
|
28
|
-
"@types/node": "^
|
|
28
|
+
"@types/node": "^25.0.0",
|
|
29
29
|
"tsx": "^4.21.0",
|
|
30
30
|
"vitest": "^4.0.15",
|
|
31
31
|
"@assistant-ui/x-buildutils": "0.0.1"
|
|
@@ -35,6 +35,10 @@ type ToolStreamCallback = <
|
|
|
35
35
|
type ToolExecutionOptions = {
|
|
36
36
|
execute: ToolCallback;
|
|
37
37
|
streamCall: ToolStreamCallback;
|
|
38
|
+
onExecutionStart?:
|
|
39
|
+
| ((toolCallId: string, toolName: string) => void)
|
|
40
|
+
| undefined;
|
|
41
|
+
onExecutionEnd?: ((toolCallId: string, toolName: string) => void) | undefined;
|
|
38
42
|
};
|
|
39
43
|
|
|
40
44
|
export class ToolExecutionStream extends PipeableTransformStream<
|
|
@@ -112,6 +116,7 @@ export class ToolExecutionStream extends PipeableTransformStream<
|
|
|
112
116
|
if (!streamController)
|
|
113
117
|
throw new Error("No controller found for tool call");
|
|
114
118
|
|
|
119
|
+
let isExecuting = false;
|
|
115
120
|
const promise = withPromiseOrValue(
|
|
116
121
|
() => {
|
|
117
122
|
let args;
|
|
@@ -123,13 +128,25 @@ export class ToolExecutionStream extends PipeableTransformStream<
|
|
|
123
128
|
);
|
|
124
129
|
}
|
|
125
130
|
|
|
126
|
-
|
|
131
|
+
const executeResult = options.execute({
|
|
127
132
|
toolCallId,
|
|
128
133
|
toolName,
|
|
129
134
|
args,
|
|
130
135
|
});
|
|
136
|
+
|
|
137
|
+
// Only mark as executing if the tool has frontend execution
|
|
138
|
+
if (executeResult !== undefined) {
|
|
139
|
+
isExecuting = true;
|
|
140
|
+
options.onExecutionStart?.(toolCallId, toolName);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return executeResult;
|
|
131
144
|
},
|
|
132
145
|
(c) => {
|
|
146
|
+
if (isExecuting) {
|
|
147
|
+
options.onExecutionEnd?.(toolCallId, toolName);
|
|
148
|
+
}
|
|
149
|
+
|
|
133
150
|
if (c === undefined) return;
|
|
134
151
|
|
|
135
152
|
// TODO how to handle new ToolResult({ result: undefined })?
|
|
@@ -146,6 +163,10 @@ export class ToolExecutionStream extends PipeableTransformStream<
|
|
|
146
163
|
});
|
|
147
164
|
},
|
|
148
165
|
(e) => {
|
|
166
|
+
if (isExecuting) {
|
|
167
|
+
options.onExecutionEnd?.(toolCallId, toolName);
|
|
168
|
+
}
|
|
169
|
+
|
|
149
170
|
const result = new ToolResponse({
|
|
150
171
|
result: String(e),
|
|
151
172
|
isError: true,
|
package/src/core/tool/index.ts
CHANGED
|
@@ -32,6 +32,14 @@ function getToolResponse(
|
|
|
32
32
|
const getResult = async (
|
|
33
33
|
toolExecute: ToolExecuteFunction<ReadonlyJSONObject, unknown>,
|
|
34
34
|
): Promise<ToolResponse<ReadonlyJSONValue>> => {
|
|
35
|
+
// Check if already aborted before starting
|
|
36
|
+
if (abortSignal.aborted) {
|
|
37
|
+
return new ToolResponse({
|
|
38
|
+
result: "Tool execution was cancelled.",
|
|
39
|
+
isError: true,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
35
43
|
let executeFn = toolExecute;
|
|
36
44
|
|
|
37
45
|
if (isStandardSchemaV1(tool.parameters)) {
|
|
@@ -49,12 +57,40 @@ function getToolResponse(
|
|
|
49
57
|
}
|
|
50
58
|
}
|
|
51
59
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
// Create abort promise that resolves after 2 microtasks
|
|
61
|
+
// This gives tools that handle abort a chance to win the race
|
|
62
|
+
const abortPromise = new Promise<ToolResponse<ReadonlyJSONValue>>(
|
|
63
|
+
(resolve) => {
|
|
64
|
+
const onAbort = () => {
|
|
65
|
+
queueMicrotask(() => {
|
|
66
|
+
queueMicrotask(() => {
|
|
67
|
+
resolve(
|
|
68
|
+
new ToolResponse({
|
|
69
|
+
result: "Tool execution was cancelled.",
|
|
70
|
+
isError: true,
|
|
71
|
+
}),
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
if (abortSignal.aborted) {
|
|
77
|
+
onAbort();
|
|
78
|
+
} else {
|
|
79
|
+
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const executePromise = (async () => {
|
|
85
|
+
const result = (await executeFn(toolCall.args, {
|
|
86
|
+
toolCallId: toolCall.toolCallId,
|
|
87
|
+
abortSignal,
|
|
88
|
+
human: (payload: unknown) => human(toolCall.toolCallId, payload),
|
|
89
|
+
})) as unknown as ReadonlyJSONValue;
|
|
90
|
+
return ToolResponse.toResponse(result);
|
|
91
|
+
})();
|
|
92
|
+
|
|
93
|
+
return Promise.race([executePromise, abortPromise]);
|
|
58
94
|
};
|
|
59
95
|
|
|
60
96
|
return getResult(tool.execute);
|
|
@@ -148,6 +184,11 @@ export async function unstable_runPendingTools(
|
|
|
148
184
|
};
|
|
149
185
|
}
|
|
150
186
|
|
|
187
|
+
export type ToolResultStreamOptions = {
|
|
188
|
+
onExecutionStart?: (toolCallId: string, toolName: string) => void;
|
|
189
|
+
onExecutionEnd?: (toolCallId: string, toolName: string) => void;
|
|
190
|
+
};
|
|
191
|
+
|
|
151
192
|
export function toolResultStream(
|
|
152
193
|
tools:
|
|
153
194
|
| Record<string, Tool>
|
|
@@ -155,6 +196,7 @@ export function toolResultStream(
|
|
|
155
196
|
| undefined,
|
|
156
197
|
abortSignal: AbortSignal | (() => AbortSignal),
|
|
157
198
|
human: (toolCallId: string, payload: unknown) => Promise<unknown>,
|
|
199
|
+
options?: ToolResultStreamOptions,
|
|
158
200
|
) {
|
|
159
201
|
const toolsFn = typeof tools === "function" ? tools : () => tools;
|
|
160
202
|
const abortSignalFn =
|
|
@@ -164,5 +206,7 @@ export function toolResultStream(
|
|
|
164
206
|
getToolResponse(toolsFn(), abortSignalFn(), toolCall, human),
|
|
165
207
|
streamCall: ({ reader, ...context }) =>
|
|
166
208
|
getToolStreamResponse(toolsFn(), abortSignalFn(), reader, context, human),
|
|
209
|
+
onExecutionStart: options?.onExecutionStart,
|
|
210
|
+
onExecutionEnd: options?.onExecutionEnd,
|
|
167
211
|
});
|
|
168
212
|
}
|