@assistant-ui/react 0.7.69 → 0.7.70

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.
Files changed (89) hide show
  1. package/dist/api/MessageRuntime.d.ts +2 -1
  2. package/dist/api/MessageRuntime.d.ts.map +1 -1
  3. package/dist/api/MessageRuntime.js +9 -2
  4. package/dist/api/MessageRuntime.js.map +1 -1
  5. package/dist/api/MessageRuntime.mjs +9 -2
  6. package/dist/api/MessageRuntime.mjs.map +1 -1
  7. package/dist/context/providers/ThreadRuntimeProvider.d.ts.map +1 -1
  8. package/dist/context/providers/ThreadRuntimeProvider.js +3 -5
  9. package/dist/context/providers/ThreadRuntimeProvider.js.map +1 -1
  10. package/dist/context/providers/ThreadRuntimeProvider.mjs +3 -5
  11. package/dist/context/providers/ThreadRuntimeProvider.mjs.map +1 -1
  12. package/dist/context/providers/ThreadViewportProvider.d.ts +3 -0
  13. package/dist/context/providers/ThreadViewportProvider.d.ts.map +1 -0
  14. package/dist/context/providers/ThreadViewportProvider.js +63 -0
  15. package/dist/context/providers/ThreadViewportProvider.js.map +1 -0
  16. package/dist/context/providers/ThreadViewportProvider.mjs +42 -0
  17. package/dist/context/providers/ThreadViewportProvider.mjs.map +1 -0
  18. package/dist/context/react/ThreadContext.d.ts +0 -18
  19. package/dist/context/react/ThreadContext.d.ts.map +1 -1
  20. package/dist/context/react/ThreadContext.js +2 -11
  21. package/dist/context/react/ThreadContext.js.map +1 -1
  22. package/dist/context/react/ThreadContext.mjs +1 -8
  23. package/dist/context/react/ThreadContext.mjs.map +1 -1
  24. package/dist/context/react/ThreadViewportContext.d.ts +24 -0
  25. package/dist/context/react/ThreadViewportContext.d.ts.map +1 -0
  26. package/dist/context/react/ThreadViewportContext.js +44 -0
  27. package/dist/context/react/ThreadViewportContext.js.map +1 -0
  28. package/dist/context/react/ThreadViewportContext.mjs +18 -0
  29. package/dist/context/react/ThreadViewportContext.mjs.map +1 -0
  30. package/dist/context/react/index.d.ts +2 -1
  31. package/dist/context/react/index.d.ts.map +1 -1
  32. package/dist/context/react/index.js +3 -2
  33. package/dist/context/react/index.js.map +1 -1
  34. package/dist/context/react/index.mjs +4 -2
  35. package/dist/context/react/index.mjs.map +1 -1
  36. package/dist/context/stores/ThreadViewport.d.ts.map +1 -1
  37. package/dist/context/stores/ThreadViewport.js +1 -0
  38. package/dist/context/stores/ThreadViewport.js.map +1 -1
  39. package/dist/context/stores/ThreadViewport.mjs +2 -0
  40. package/dist/context/stores/ThreadViewport.mjs.map +1 -1
  41. package/dist/model-context/ModelContextTypes.d.ts +3 -0
  42. package/dist/model-context/ModelContextTypes.d.ts.map +1 -1
  43. package/dist/model-context/ModelContextTypes.js.map +1 -1
  44. package/dist/model-context/ModelContextTypes.mjs.map +1 -1
  45. package/dist/primitives/thread/ThreadScrollToBottom.d.ts.map +1 -1
  46. package/dist/primitives/thread/ThreadScrollToBottom.js +3 -4
  47. package/dist/primitives/thread/ThreadScrollToBottom.js.map +1 -1
  48. package/dist/primitives/thread/ThreadScrollToBottom.mjs +1 -2
  49. package/dist/primitives/thread/ThreadScrollToBottom.mjs.map +1 -1
  50. package/dist/primitives/thread/ThreadViewport.d.ts.map +1 -1
  51. package/dist/primitives/thread/ThreadViewport.js +5 -1
  52. package/dist/primitives/thread/ThreadViewport.js.map +1 -1
  53. package/dist/primitives/thread/ThreadViewport.mjs +5 -1
  54. package/dist/primitives/thread/ThreadViewport.mjs.map +1 -1
  55. package/dist/primitives/thread/useThreadViewportAutoScroll.d.ts.map +1 -1
  56. package/dist/primitives/thread/useThreadViewportAutoScroll.js +2 -1
  57. package/dist/primitives/thread/useThreadViewportAutoScroll.js.map +1 -1
  58. package/dist/primitives/thread/useThreadViewportAutoScroll.mjs +2 -4
  59. package/dist/primitives/thread/useThreadViewportAutoScroll.mjs.map +1 -1
  60. package/dist/runtimes/composer/DefaultEditComposerRuntimeCore.d.ts +1 -1
  61. package/dist/runtimes/composer/DefaultEditComposerRuntimeCore.d.ts.map +1 -1
  62. package/dist/runtimes/composer/DefaultEditComposerRuntimeCore.js +1 -0
  63. package/dist/runtimes/composer/DefaultEditComposerRuntimeCore.js.map +1 -1
  64. package/dist/runtimes/composer/DefaultEditComposerRuntimeCore.mjs +1 -0
  65. package/dist/runtimes/composer/DefaultEditComposerRuntimeCore.mjs.map +1 -1
  66. package/dist/runtimes/edge/streams/toolResultStream.d.ts.map +1 -1
  67. package/dist/runtimes/edge/streams/toolResultStream.js +13 -15
  68. package/dist/runtimes/edge/streams/toolResultStream.js.map +1 -1
  69. package/dist/runtimes/edge/streams/toolResultStream.mjs +13 -15
  70. package/dist/runtimes/edge/streams/toolResultStream.mjs.map +1 -1
  71. package/dist/utils/hooks/useOnScrollToBottom.js +2 -2
  72. package/dist/utils/hooks/useOnScrollToBottom.js.map +1 -1
  73. package/dist/utils/hooks/useOnScrollToBottom.mjs +1 -1
  74. package/dist/utils/hooks/useOnScrollToBottom.mjs.map +1 -1
  75. package/package.json +3 -3
  76. package/src/api/MessageRuntime.ts +14 -5
  77. package/src/context/providers/ThreadRuntimeProvider.tsx +4 -5
  78. package/src/context/providers/ThreadViewportProvider.tsx +49 -0
  79. package/src/context/react/ThreadContext.ts +0 -8
  80. package/src/context/react/ThreadViewportContext.ts +23 -0
  81. package/src/context/react/index.ts +4 -1
  82. package/src/context/stores/ThreadViewport.tsx +2 -0
  83. package/src/model-context/ModelContextTypes.ts +7 -0
  84. package/src/primitives/thread/ThreadScrollToBottom.tsx +1 -2
  85. package/src/primitives/thread/ThreadViewport.tsx +13 -1
  86. package/src/primitives/thread/useThreadViewportAutoScroll.tsx +2 -4
  87. package/src/runtimes/composer/DefaultEditComposerRuntimeCore.tsx +4 -1
  88. package/src/runtimes/edge/streams/toolResultStream.ts +20 -18
  89. package/src/utils/hooks/useOnScrollToBottom.tsx +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/runtimes/composer/DefaultEditComposerRuntimeCore.tsx"],"sourcesContent":["import { AppendMessage, ThreadMessage } from \"../../types\";\nimport { getThreadMessageText } from \"../../utils/getThreadMessageText\";\nimport { AttachmentAdapter } from \"../adapters/attachment\";\nimport { ThreadRuntimeCore } from \"../core/ThreadRuntimeCore\";\nimport { BaseComposerRuntimeCore } from \"./BaseComposerRuntimeCore\";\n\nexport class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {\n public get canCancel() {\n return true;\n }\n\n protected getAttachmentAdapter() {\n return this.runtime.adapters?.attachments;\n }\n\n private _nonTextParts;\n private _previousText;\n private _parentId;\n private _sourceId;\n constructor(\n private runtime: Omit<ThreadRuntimeCore, \"composer\"> & {\n adapters?: { attachments?: AttachmentAdapter | undefined } | undefined;\n },\n private endEditCallback: () => void,\n { parentId, message }: { parentId: string | null; message: ThreadMessage },\n ) {\n super();\n this._parentId = parentId;\n this._sourceId = message.id;\n this._previousText = getThreadMessageText(message);\n this.setText(this._previousText);\n\n this.setRole(message.role);\n this.setAttachments(message.attachments ?? []);\n\n this._nonTextParts = message.content.filter(\n (part) => part.type !== \"text\" && part.type !== \"ui\",\n );\n }\n\n public async handleSend(\n message: Omit<AppendMessage, \"parentId\" | \"sourceId\">,\n ) {\n const text = getThreadMessageText(message as AppendMessage);\n if (text !== this._previousText) {\n this.runtime.append({\n ...message,\n content: [...message.content, ...this._nonTextParts] as any,\n parentId: this._parentId,\n sourceId: this._sourceId,\n });\n }\n\n this.handleCancel();\n }\n\n public handleCancel() {\n this.endEditCallback();\n this._notifySubscribers();\n }\n}\n"],"mappings":";AACA,SAAS,4BAA4B;AAGrC,SAAS,+BAA+B;AAEjC,IAAM,iCAAN,cAA6C,wBAAwB;AAAA,EAa1E,YACU,SAGA,iBACR,EAAE,UAAU,QAAQ,GACpB;AACA,UAAM;AANE;AAGA;AAIR,SAAK,YAAY;AACjB,SAAK,YAAY,QAAQ;AACzB,SAAK,gBAAgB,qBAAqB,OAAO;AACjD,SAAK,QAAQ,KAAK,aAAa;AAE/B,SAAK,QAAQ,QAAQ,IAAI;AACzB,SAAK,eAAe,QAAQ,eAAe,CAAC,CAAC;AAE7C,SAAK,gBAAgB,QAAQ,QAAQ;AAAA,MACnC,CAAC,SAAS,KAAK,SAAS,UAAU,KAAK,SAAS;AAAA,IAClD;AAAA,EACF;AAAA,EA/BA,IAAW,YAAY;AACrB,WAAO;AAAA,EACT;AAAA,EAEU,uBAAuB;AAC/B,WAAO,KAAK,QAAQ,UAAU;AAAA,EAChC;AAAA,EAEQ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAsBR,MAAa,WACX,SACA;AACA,UAAM,OAAO,qBAAqB,OAAwB;AAC1D,QAAI,SAAS,KAAK,eAAe;AAC/B,WAAK,QAAQ,OAAO;AAAA,QAClB,GAAG;AAAA,QACH,SAAS,CAAC,GAAG,QAAQ,SAAS,GAAG,KAAK,aAAa;AAAA,QACnD,UAAU,KAAK;AAAA,QACf,UAAU,KAAK;AAAA,MACjB,CAAC;AAAA,IACH;AAEA,SAAK,aAAa;AAAA,EACpB;AAAA,EAEO,eAAe;AACpB,SAAK,gBAAgB;AACrB,SAAK,mBAAmB;AAAA,EAC1B;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/runtimes/composer/DefaultEditComposerRuntimeCore.tsx"],"sourcesContent":["import { AppendMessage, ThreadMessage } from \"../../types\";\nimport { getThreadMessageText } from \"../../utils/getThreadMessageText\";\nimport { AttachmentAdapter } from \"../adapters/attachment\";\nimport { ThreadRuntimeCore } from \"../core/ThreadRuntimeCore\";\nimport { BaseComposerRuntimeCore } from \"./BaseComposerRuntimeCore\";\n\nexport class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {\n public get canCancel() {\n return true;\n }\n\n protected getAttachmentAdapter() {\n return this.runtime.adapters?.attachments;\n }\n\n private _nonTextParts;\n private _previousText;\n private _parentId;\n private _sourceId;\n constructor(\n private runtime: ThreadRuntimeCore & {\n adapters?: { attachments?: AttachmentAdapter | undefined } | undefined;\n },\n private endEditCallback: () => void,\n { parentId, message }: { parentId: string | null; message: ThreadMessage },\n ) {\n super();\n this._parentId = parentId;\n this._sourceId = message.id;\n this._previousText = getThreadMessageText(message);\n this.setText(this._previousText);\n\n this.setRole(message.role);\n this.setAttachments(message.attachments ?? []);\n\n this._nonTextParts = message.content.filter(\n (part) => part.type !== \"text\" && part.type !== \"ui\",\n );\n\n // Use the runConfig from the regular (non-edit) composer as the initial runConfig for the edit composer\n this.setRunConfig({ ...runtime.composer.runConfig });\n }\n\n public async handleSend(\n message: Omit<AppendMessage, \"parentId\" | \"sourceId\">,\n ) {\n const text = getThreadMessageText(message as AppendMessage);\n if (text !== this._previousText) {\n this.runtime.append({\n ...message,\n content: [...message.content, ...this._nonTextParts] as any,\n parentId: this._parentId,\n sourceId: this._sourceId,\n });\n }\n\n this.handleCancel();\n }\n\n public handleCancel() {\n this.endEditCallback();\n this._notifySubscribers();\n }\n}\n"],"mappings":";AACA,SAAS,4BAA4B;AAGrC,SAAS,+BAA+B;AAEjC,IAAM,iCAAN,cAA6C,wBAAwB;AAAA,EAa1E,YACU,SAGA,iBACR,EAAE,UAAU,QAAQ,GACpB;AACA,UAAM;AANE;AAGA;AAIR,SAAK,YAAY;AACjB,SAAK,YAAY,QAAQ;AACzB,SAAK,gBAAgB,qBAAqB,OAAO;AACjD,SAAK,QAAQ,KAAK,aAAa;AAE/B,SAAK,QAAQ,QAAQ,IAAI;AACzB,SAAK,eAAe,QAAQ,eAAe,CAAC,CAAC;AAE7C,SAAK,gBAAgB,QAAQ,QAAQ;AAAA,MACnC,CAAC,SAAS,KAAK,SAAS,UAAU,KAAK,SAAS;AAAA,IAClD;AAGA,SAAK,aAAa,EAAE,GAAG,QAAQ,SAAS,UAAU,CAAC;AAAA,EACrD;AAAA,EAlCA,IAAW,YAAY;AACrB,WAAO;AAAA,EACT;AAAA,EAEU,uBAAuB;AAC/B,WAAO,KAAK,QAAQ,UAAU;AAAA,EAChC;AAAA,EAEQ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAyBR,MAAa,WACX,SACA;AACA,UAAM,OAAO,qBAAqB,OAAwB;AAC1D,QAAI,SAAS,KAAK,eAAe;AAC/B,WAAK,QAAQ,OAAO;AAAA,QAClB,GAAG;AAAA,QACH,SAAS,CAAC,GAAG,QAAQ,SAAS,GAAG,KAAK,aAAa;AAAA,QACnD,UAAU,KAAK;AAAA,QACf,UAAU,KAAK;AAAA,MACjB,CAAC;AAAA,IACH;AAEA,SAAK,aAAa;AAAA,EACpB;AAAA,EAEO,eAAe;AACpB,SAAK,gBAAgB;AACrB,SAAK,mBAAmB;AAAA,EAC1B;AACF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"toolResultStream.d.ts","sourceRoot":"","sources":["../../../../src/runtimes/edge/streams/toolResultStream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,0CAA0C,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE,MAAM,MAAM,oBAAoB,GAC5B,yBAAyB,GACzB;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,iBAAiB,EAAE,CAAC;CAClC,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,iBAAiB,EAAE,CAAC;CAC3B,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,YAAY,EAAE,UAAU,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,YAAY,EACR,MAAM,GACN,QAAQ,GACR,gBAAgB,GAChB,YAAY,GACZ,OAAO,GACP,OAAO,GACP,SAAS,CAAC;IACd,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEN,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,SAAS,EACvC,WAAW,EAAE,WAAW,+DA0GzB"}
1
+ {"version":3,"file":"toolResultStream.d.ts","sourceRoot":"","sources":["../../../../src/runtimes/edge/streams/toolResultStream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,0CAA0C,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE,MAAM,MAAM,oBAAoB,GAC5B,yBAAyB,GACzB;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,iBAAiB,EAAE,CAAC;CAClC,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,iBAAiB,EAAE,CAAC;CAC3B,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,YAAY,EAAE,UAAU,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,YAAY,EACR,MAAM,GACN,QAAQ,GACR,gBAAgB,GAChB,YAAY,GACZ,OAAO,GACP,OAAO,GACP,SAAS,CAAC;IACd,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEN,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,SAAS,EACvC,WAAW,EAAE,WAAW,+DA4GzB"}
@@ -60,26 +60,24 @@ function toolResultStream(tools, abortSignal) {
60
60
  });
61
61
  return;
62
62
  }
63
- if (tool.parameters instanceof import_zod.z.ZodType) {
64
- const result = tool.parameters.safeParse(args);
65
- if (!result.success) {
66
- controller.enqueue({
67
- type: "tool-result",
68
- toolCallType,
69
- toolCallId,
70
- toolName,
71
- result: "Function parameter validation failed. " + JSON.stringify(result.error.issues),
72
- isError: true
73
- });
74
- return;
75
- }
76
- }
77
63
  toolCallExecutions.set(
78
64
  toolCallId,
79
65
  (async () => {
80
66
  if (!tool.execute) return;
67
+ let executeFn = tool.execute;
68
+ if (tool.parameters instanceof import_zod.z.ZodType) {
69
+ const result = tool.parameters.safeParse(args);
70
+ if (!result.success) {
71
+ executeFn = tool.experimental_onSchemaValidationError ?? (() => {
72
+ throw "Function parameter validation failed. " + JSON.stringify(result.error.issues);
73
+ });
74
+ }
75
+ }
81
76
  try {
82
- const result = await tool.execute(args, { abortSignal });
77
+ const result = await executeFn(args, {
78
+ toolCallId,
79
+ abortSignal
80
+ });
83
81
  controller.enqueue({
84
82
  type: "tool-result",
85
83
  toolCallType,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/runtimes/edge/streams/toolResultStream.ts"],"sourcesContent":["import { Tool } from \"../../../model-context/ModelContextTypes\";\nimport { LanguageModelV1StreamPart } from \"@ai-sdk/provider\";\nimport { z } from \"zod\";\nimport sjson from \"secure-json-parse\";\nimport { ReadonlyJSONValue } from \"../../../utils/json/json-value\";\n\nexport type ToolResultStreamPart =\n | LanguageModelV1StreamPart\n | {\n type: \"annotations\";\n annotations: ReadonlyJSONValue[];\n }\n | {\n type: \"data\";\n data: ReadonlyJSONValue[];\n }\n | {\n type: \"tool-result\";\n toolCallType: \"function\";\n toolCallId: string;\n toolName: string;\n result: unknown;\n isError?: boolean;\n }\n | {\n type: \"step-finish\";\n finishReason:\n | \"stop\"\n | \"length\"\n | \"content-filter\"\n | \"tool-calls\"\n | \"error\"\n | \"other\"\n | \"unknown\";\n usage: {\n promptTokens: number;\n completionTokens: number;\n };\n isContinued: boolean;\n };\n\nexport function toolResultStream(\n tools: Record<string, Tool> | undefined,\n abortSignal: AbortSignal,\n) {\n const toolCallExecutions = new Map<string, Promise<any>>();\n\n return new TransformStream<ToolResultStreamPart, ToolResultStreamPart>({\n transform(chunk, controller) {\n // forward everything\n controller.enqueue(chunk);\n\n // handle tool calls\n const chunkType = chunk.type;\n switch (chunkType) {\n case \"tool-call\": {\n const { toolCallId, toolCallType, toolName, args: argsText } = chunk;\n const tool = tools?.[toolName];\n if (!tool || !tool.execute) return;\n\n let args;\n try {\n args = sjson.parse(argsText);\n } catch (e) {\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result:\n \"Function parameter parsing failed. \" +\n JSON.stringify((e as Error).message),\n isError: true,\n });\n return;\n }\n\n if (tool.parameters instanceof z.ZodType) {\n const result = tool.parameters.safeParse(args);\n if (!result.success) {\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result:\n \"Function parameter validation failed. \" +\n JSON.stringify(result.error.issues),\n isError: true,\n });\n return;\n }\n }\n\n toolCallExecutions.set(\n toolCallId,\n (async () => {\n if (!tool.execute) return;\n\n try {\n const result = await tool.execute(args, { abortSignal });\n\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result,\n });\n } catch (error) {\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result: \"Error: \" + error,\n isError: true,\n });\n } finally {\n toolCallExecutions.delete(toolCallId);\n }\n })(),\n );\n break;\n }\n\n // ignore other parts\n case \"text-delta\":\n case \"tool-call-delta\":\n case \"tool-result\":\n case \"step-finish\":\n case \"finish\":\n case \"error\":\n case \"response-metadata\":\n case \"annotations\":\n case \"data\":\n break;\n\n default: {\n const unhandledType: never = chunkType;\n throw new Error(`Unhandled chunk type: ${unhandledType}`);\n }\n }\n },\n\n async flush() {\n await Promise.all(toolCallExecutions.values());\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,iBAAkB;AAClB,+BAAkB;AAsCX,SAAS,iBACd,OACA,aACA;AACA,QAAM,qBAAqB,oBAAI,IAA0B;AAEzD,SAAO,IAAI,gBAA4D;AAAA,IACrE,UAAU,OAAO,YAAY;AAE3B,iBAAW,QAAQ,KAAK;AAGxB,YAAM,YAAY,MAAM;AACxB,cAAQ,WAAW;AAAA,QACjB,KAAK,aAAa;AAChB,gBAAM,EAAE,YAAY,cAAc,UAAU,MAAM,SAAS,IAAI;AAC/D,gBAAM,OAAO,QAAQ,QAAQ;AAC7B,cAAI,CAAC,QAAQ,CAAC,KAAK,QAAS;AAE5B,cAAI;AACJ,cAAI;AACF,mBAAO,yBAAAA,QAAM,MAAM,QAAQ;AAAA,UAC7B,SAAS,GAAG;AACV,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN;AAAA,cACA;AAAA,cACA;AAAA,cACA,QACE,wCACA,KAAK,UAAW,EAAY,OAAO;AAAA,cACrC,SAAS;AAAA,YACX,CAAC;AACD;AAAA,UACF;AAEA,cAAI,KAAK,sBAAsB,aAAE,SAAS;AACxC,kBAAM,SAAS,KAAK,WAAW,UAAU,IAAI;AAC7C,gBAAI,CAAC,OAAO,SAAS;AACnB,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,QACE,2CACA,KAAK,UAAU,OAAO,MAAM,MAAM;AAAA,gBACpC,SAAS;AAAA,cACX,CAAC;AACD;AAAA,YACF;AAAA,UACF;AAEA,6BAAmB;AAAA,YACjB;AAAA,aACC,YAAY;AACX,kBAAI,CAAC,KAAK,QAAS;AAEnB,kBAAI;AACF,sBAAM,SAAS,MAAM,KAAK,QAAQ,MAAM,EAAE,YAAY,CAAC;AAEvD,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF,CAAC;AAAA,cACH,SAAS,OAAO;AACd,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA,QAAQ,YAAY;AAAA,kBACpB,SAAS;AAAA,gBACX,CAAC;AAAA,cACH,UAAE;AACA,mCAAmB,OAAO,UAAU;AAAA,cACtC;AAAA,YACF,GAAG;AAAA,UACL;AACA;AAAA,QACF;AAAA;AAAA,QAGA,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AACH;AAAA,QAEF,SAAS;AACP,gBAAM,gBAAuB;AAC7B,gBAAM,IAAI,MAAM,yBAAyB,aAAa,EAAE;AAAA,QAC1D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,QAAQ;AACZ,YAAM,QAAQ,IAAI,mBAAmB,OAAO,CAAC;AAAA,IAC/C;AAAA,EACF,CAAC;AACH;","names":["sjson"]}
1
+ {"version":3,"sources":["../../../../src/runtimes/edge/streams/toolResultStream.ts"],"sourcesContent":["import { Tool } from \"../../../model-context/ModelContextTypes\";\nimport { LanguageModelV1StreamPart } from \"@ai-sdk/provider\";\nimport { z } from \"zod\";\nimport sjson from \"secure-json-parse\";\nimport { ReadonlyJSONValue } from \"../../../utils/json/json-value\";\n\nexport type ToolResultStreamPart =\n | LanguageModelV1StreamPart\n | {\n type: \"annotations\";\n annotations: ReadonlyJSONValue[];\n }\n | {\n type: \"data\";\n data: ReadonlyJSONValue[];\n }\n | {\n type: \"tool-result\";\n toolCallType: \"function\";\n toolCallId: string;\n toolName: string;\n result: unknown;\n isError?: boolean;\n }\n | {\n type: \"step-finish\";\n finishReason:\n | \"stop\"\n | \"length\"\n | \"content-filter\"\n | \"tool-calls\"\n | \"error\"\n | \"other\"\n | \"unknown\";\n usage: {\n promptTokens: number;\n completionTokens: number;\n };\n isContinued: boolean;\n };\n\nexport function toolResultStream(\n tools: Record<string, Tool> | undefined,\n abortSignal: AbortSignal,\n) {\n const toolCallExecutions = new Map<string, Promise<any>>();\n\n return new TransformStream<ToolResultStreamPart, ToolResultStreamPart>({\n transform(chunk, controller) {\n // forward everything\n controller.enqueue(chunk);\n\n // handle tool calls\n const chunkType = chunk.type;\n switch (chunkType) {\n case \"tool-call\": {\n const { toolCallId, toolCallType, toolName, args: argsText } = chunk;\n const tool = tools?.[toolName];\n if (!tool || !tool.execute) return;\n\n let args;\n try {\n args = sjson.parse(argsText);\n } catch (e) {\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result:\n \"Function parameter parsing failed. \" +\n JSON.stringify((e as Error).message),\n isError: true,\n });\n return;\n }\n\n toolCallExecutions.set(\n toolCallId,\n (async () => {\n if (!tool.execute) return;\n\n let executeFn = tool.execute;\n\n if (tool.parameters instanceof z.ZodType) {\n const result = tool.parameters.safeParse(args);\n if (!result.success) {\n executeFn =\n tool.experimental_onSchemaValidationError ??\n (() => {\n throw (\n \"Function parameter validation failed. \" +\n JSON.stringify(result.error.issues)\n );\n });\n }\n }\n\n try {\n const result = await executeFn(args, {\n toolCallId,\n abortSignal,\n });\n\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result,\n });\n } catch (error) {\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result: \"Error: \" + error,\n isError: true,\n });\n } finally {\n toolCallExecutions.delete(toolCallId);\n }\n })(),\n );\n break;\n }\n\n // ignore other parts\n case \"text-delta\":\n case \"tool-call-delta\":\n case \"tool-result\":\n case \"step-finish\":\n case \"finish\":\n case \"error\":\n case \"response-metadata\":\n case \"annotations\":\n case \"data\":\n break;\n\n default: {\n const unhandledType: never = chunkType;\n throw new Error(`Unhandled chunk type: ${unhandledType}`);\n }\n }\n },\n\n async flush() {\n await Promise.all(toolCallExecutions.values());\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,iBAAkB;AAClB,+BAAkB;AAsCX,SAAS,iBACd,OACA,aACA;AACA,QAAM,qBAAqB,oBAAI,IAA0B;AAEzD,SAAO,IAAI,gBAA4D;AAAA,IACrE,UAAU,OAAO,YAAY;AAE3B,iBAAW,QAAQ,KAAK;AAGxB,YAAM,YAAY,MAAM;AACxB,cAAQ,WAAW;AAAA,QACjB,KAAK,aAAa;AAChB,gBAAM,EAAE,YAAY,cAAc,UAAU,MAAM,SAAS,IAAI;AAC/D,gBAAM,OAAO,QAAQ,QAAQ;AAC7B,cAAI,CAAC,QAAQ,CAAC,KAAK,QAAS;AAE5B,cAAI;AACJ,cAAI;AACF,mBAAO,yBAAAA,QAAM,MAAM,QAAQ;AAAA,UAC7B,SAAS,GAAG;AACV,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN;AAAA,cACA;AAAA,cACA;AAAA,cACA,QACE,wCACA,KAAK,UAAW,EAAY,OAAO;AAAA,cACrC,SAAS;AAAA,YACX,CAAC;AACD;AAAA,UACF;AAEA,6BAAmB;AAAA,YACjB;AAAA,aACC,YAAY;AACX,kBAAI,CAAC,KAAK,QAAS;AAEnB,kBAAI,YAAY,KAAK;AAErB,kBAAI,KAAK,sBAAsB,aAAE,SAAS;AACxC,sBAAM,SAAS,KAAK,WAAW,UAAU,IAAI;AAC7C,oBAAI,CAAC,OAAO,SAAS;AACnB,8BACE,KAAK,yCACJ,MAAM;AACL,0BACE,2CACA,KAAK,UAAU,OAAO,MAAM,MAAM;AAAA,kBAEtC;AAAA,gBACJ;AAAA,cACF;AAEA,kBAAI;AACF,sBAAM,SAAS,MAAM,UAAU,MAAM;AAAA,kBACnC;AAAA,kBACA;AAAA,gBACF,CAAC;AAED,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF,CAAC;AAAA,cACH,SAAS,OAAO;AACd,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA,QAAQ,YAAY;AAAA,kBACpB,SAAS;AAAA,gBACX,CAAC;AAAA,cACH,UAAE;AACA,mCAAmB,OAAO,UAAU;AAAA,cACtC;AAAA,YACF,GAAG;AAAA,UACL;AACA;AAAA,QACF;AAAA;AAAA,QAGA,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AACH;AAAA,QAEF,SAAS;AACP,gBAAM,gBAAuB;AAC7B,gBAAM,IAAI,MAAM,yBAAyB,aAAa,EAAE;AAAA,QAC1D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,QAAQ;AACZ,YAAM,QAAQ,IAAI,mBAAmB,OAAO,CAAC;AAAA,IAC/C;AAAA,EACF,CAAC;AACH;","names":["sjson"]}
@@ -26,26 +26,24 @@ function toolResultStream(tools, abortSignal) {
26
26
  });
27
27
  return;
28
28
  }
29
- if (tool.parameters instanceof z.ZodType) {
30
- const result = tool.parameters.safeParse(args);
31
- if (!result.success) {
32
- controller.enqueue({
33
- type: "tool-result",
34
- toolCallType,
35
- toolCallId,
36
- toolName,
37
- result: "Function parameter validation failed. " + JSON.stringify(result.error.issues),
38
- isError: true
39
- });
40
- return;
41
- }
42
- }
43
29
  toolCallExecutions.set(
44
30
  toolCallId,
45
31
  (async () => {
46
32
  if (!tool.execute) return;
33
+ let executeFn = tool.execute;
34
+ if (tool.parameters instanceof z.ZodType) {
35
+ const result = tool.parameters.safeParse(args);
36
+ if (!result.success) {
37
+ executeFn = tool.experimental_onSchemaValidationError ?? (() => {
38
+ throw "Function parameter validation failed. " + JSON.stringify(result.error.issues);
39
+ });
40
+ }
41
+ }
47
42
  try {
48
- const result = await tool.execute(args, { abortSignal });
43
+ const result = await executeFn(args, {
44
+ toolCallId,
45
+ abortSignal
46
+ });
49
47
  controller.enqueue({
50
48
  type: "tool-result",
51
49
  toolCallType,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/runtimes/edge/streams/toolResultStream.ts"],"sourcesContent":["import { Tool } from \"../../../model-context/ModelContextTypes\";\nimport { LanguageModelV1StreamPart } from \"@ai-sdk/provider\";\nimport { z } from \"zod\";\nimport sjson from \"secure-json-parse\";\nimport { ReadonlyJSONValue } from \"../../../utils/json/json-value\";\n\nexport type ToolResultStreamPart =\n | LanguageModelV1StreamPart\n | {\n type: \"annotations\";\n annotations: ReadonlyJSONValue[];\n }\n | {\n type: \"data\";\n data: ReadonlyJSONValue[];\n }\n | {\n type: \"tool-result\";\n toolCallType: \"function\";\n toolCallId: string;\n toolName: string;\n result: unknown;\n isError?: boolean;\n }\n | {\n type: \"step-finish\";\n finishReason:\n | \"stop\"\n | \"length\"\n | \"content-filter\"\n | \"tool-calls\"\n | \"error\"\n | \"other\"\n | \"unknown\";\n usage: {\n promptTokens: number;\n completionTokens: number;\n };\n isContinued: boolean;\n };\n\nexport function toolResultStream(\n tools: Record<string, Tool> | undefined,\n abortSignal: AbortSignal,\n) {\n const toolCallExecutions = new Map<string, Promise<any>>();\n\n return new TransformStream<ToolResultStreamPart, ToolResultStreamPart>({\n transform(chunk, controller) {\n // forward everything\n controller.enqueue(chunk);\n\n // handle tool calls\n const chunkType = chunk.type;\n switch (chunkType) {\n case \"tool-call\": {\n const { toolCallId, toolCallType, toolName, args: argsText } = chunk;\n const tool = tools?.[toolName];\n if (!tool || !tool.execute) return;\n\n let args;\n try {\n args = sjson.parse(argsText);\n } catch (e) {\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result:\n \"Function parameter parsing failed. \" +\n JSON.stringify((e as Error).message),\n isError: true,\n });\n return;\n }\n\n if (tool.parameters instanceof z.ZodType) {\n const result = tool.parameters.safeParse(args);\n if (!result.success) {\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result:\n \"Function parameter validation failed. \" +\n JSON.stringify(result.error.issues),\n isError: true,\n });\n return;\n }\n }\n\n toolCallExecutions.set(\n toolCallId,\n (async () => {\n if (!tool.execute) return;\n\n try {\n const result = await tool.execute(args, { abortSignal });\n\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result,\n });\n } catch (error) {\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result: \"Error: \" + error,\n isError: true,\n });\n } finally {\n toolCallExecutions.delete(toolCallId);\n }\n })(),\n );\n break;\n }\n\n // ignore other parts\n case \"text-delta\":\n case \"tool-call-delta\":\n case \"tool-result\":\n case \"step-finish\":\n case \"finish\":\n case \"error\":\n case \"response-metadata\":\n case \"annotations\":\n case \"data\":\n break;\n\n default: {\n const unhandledType: never = chunkType;\n throw new Error(`Unhandled chunk type: ${unhandledType}`);\n }\n }\n },\n\n async flush() {\n await Promise.all(toolCallExecutions.values());\n },\n });\n}\n"],"mappings":";AAEA,SAAS,SAAS;AAClB,OAAO,WAAW;AAsCX,SAAS,iBACd,OACA,aACA;AACA,QAAM,qBAAqB,oBAAI,IAA0B;AAEzD,SAAO,IAAI,gBAA4D;AAAA,IACrE,UAAU,OAAO,YAAY;AAE3B,iBAAW,QAAQ,KAAK;AAGxB,YAAM,YAAY,MAAM;AACxB,cAAQ,WAAW;AAAA,QACjB,KAAK,aAAa;AAChB,gBAAM,EAAE,YAAY,cAAc,UAAU,MAAM,SAAS,IAAI;AAC/D,gBAAM,OAAO,QAAQ,QAAQ;AAC7B,cAAI,CAAC,QAAQ,CAAC,KAAK,QAAS;AAE5B,cAAI;AACJ,cAAI;AACF,mBAAO,MAAM,MAAM,QAAQ;AAAA,UAC7B,SAAS,GAAG;AACV,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN;AAAA,cACA;AAAA,cACA;AAAA,cACA,QACE,wCACA,KAAK,UAAW,EAAY,OAAO;AAAA,cACrC,SAAS;AAAA,YACX,CAAC;AACD;AAAA,UACF;AAEA,cAAI,KAAK,sBAAsB,EAAE,SAAS;AACxC,kBAAM,SAAS,KAAK,WAAW,UAAU,IAAI;AAC7C,gBAAI,CAAC,OAAO,SAAS;AACnB,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,QACE,2CACA,KAAK,UAAU,OAAO,MAAM,MAAM;AAAA,gBACpC,SAAS;AAAA,cACX,CAAC;AACD;AAAA,YACF;AAAA,UACF;AAEA,6BAAmB;AAAA,YACjB;AAAA,aACC,YAAY;AACX,kBAAI,CAAC,KAAK,QAAS;AAEnB,kBAAI;AACF,sBAAM,SAAS,MAAM,KAAK,QAAQ,MAAM,EAAE,YAAY,CAAC;AAEvD,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF,CAAC;AAAA,cACH,SAAS,OAAO;AACd,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA,QAAQ,YAAY;AAAA,kBACpB,SAAS;AAAA,gBACX,CAAC;AAAA,cACH,UAAE;AACA,mCAAmB,OAAO,UAAU;AAAA,cACtC;AAAA,YACF,GAAG;AAAA,UACL;AACA;AAAA,QACF;AAAA;AAAA,QAGA,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AACH;AAAA,QAEF,SAAS;AACP,gBAAM,gBAAuB;AAC7B,gBAAM,IAAI,MAAM,yBAAyB,aAAa,EAAE;AAAA,QAC1D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,QAAQ;AACZ,YAAM,QAAQ,IAAI,mBAAmB,OAAO,CAAC;AAAA,IAC/C;AAAA,EACF,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../../../../src/runtimes/edge/streams/toolResultStream.ts"],"sourcesContent":["import { Tool } from \"../../../model-context/ModelContextTypes\";\nimport { LanguageModelV1StreamPart } from \"@ai-sdk/provider\";\nimport { z } from \"zod\";\nimport sjson from \"secure-json-parse\";\nimport { ReadonlyJSONValue } from \"../../../utils/json/json-value\";\n\nexport type ToolResultStreamPart =\n | LanguageModelV1StreamPart\n | {\n type: \"annotations\";\n annotations: ReadonlyJSONValue[];\n }\n | {\n type: \"data\";\n data: ReadonlyJSONValue[];\n }\n | {\n type: \"tool-result\";\n toolCallType: \"function\";\n toolCallId: string;\n toolName: string;\n result: unknown;\n isError?: boolean;\n }\n | {\n type: \"step-finish\";\n finishReason:\n | \"stop\"\n | \"length\"\n | \"content-filter\"\n | \"tool-calls\"\n | \"error\"\n | \"other\"\n | \"unknown\";\n usage: {\n promptTokens: number;\n completionTokens: number;\n };\n isContinued: boolean;\n };\n\nexport function toolResultStream(\n tools: Record<string, Tool> | undefined,\n abortSignal: AbortSignal,\n) {\n const toolCallExecutions = new Map<string, Promise<any>>();\n\n return new TransformStream<ToolResultStreamPart, ToolResultStreamPart>({\n transform(chunk, controller) {\n // forward everything\n controller.enqueue(chunk);\n\n // handle tool calls\n const chunkType = chunk.type;\n switch (chunkType) {\n case \"tool-call\": {\n const { toolCallId, toolCallType, toolName, args: argsText } = chunk;\n const tool = tools?.[toolName];\n if (!tool || !tool.execute) return;\n\n let args;\n try {\n args = sjson.parse(argsText);\n } catch (e) {\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result:\n \"Function parameter parsing failed. \" +\n JSON.stringify((e as Error).message),\n isError: true,\n });\n return;\n }\n\n toolCallExecutions.set(\n toolCallId,\n (async () => {\n if (!tool.execute) return;\n\n let executeFn = tool.execute;\n\n if (tool.parameters instanceof z.ZodType) {\n const result = tool.parameters.safeParse(args);\n if (!result.success) {\n executeFn =\n tool.experimental_onSchemaValidationError ??\n (() => {\n throw (\n \"Function parameter validation failed. \" +\n JSON.stringify(result.error.issues)\n );\n });\n }\n }\n\n try {\n const result = await executeFn(args, {\n toolCallId,\n abortSignal,\n });\n\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result,\n });\n } catch (error) {\n controller.enqueue({\n type: \"tool-result\",\n toolCallType,\n toolCallId,\n toolName,\n result: \"Error: \" + error,\n isError: true,\n });\n } finally {\n toolCallExecutions.delete(toolCallId);\n }\n })(),\n );\n break;\n }\n\n // ignore other parts\n case \"text-delta\":\n case \"tool-call-delta\":\n case \"tool-result\":\n case \"step-finish\":\n case \"finish\":\n case \"error\":\n case \"response-metadata\":\n case \"annotations\":\n case \"data\":\n break;\n\n default: {\n const unhandledType: never = chunkType;\n throw new Error(`Unhandled chunk type: ${unhandledType}`);\n }\n }\n },\n\n async flush() {\n await Promise.all(toolCallExecutions.values());\n },\n });\n}\n"],"mappings":";AAEA,SAAS,SAAS;AAClB,OAAO,WAAW;AAsCX,SAAS,iBACd,OACA,aACA;AACA,QAAM,qBAAqB,oBAAI,IAA0B;AAEzD,SAAO,IAAI,gBAA4D;AAAA,IACrE,UAAU,OAAO,YAAY;AAE3B,iBAAW,QAAQ,KAAK;AAGxB,YAAM,YAAY,MAAM;AACxB,cAAQ,WAAW;AAAA,QACjB,KAAK,aAAa;AAChB,gBAAM,EAAE,YAAY,cAAc,UAAU,MAAM,SAAS,IAAI;AAC/D,gBAAM,OAAO,QAAQ,QAAQ;AAC7B,cAAI,CAAC,QAAQ,CAAC,KAAK,QAAS;AAE5B,cAAI;AACJ,cAAI;AACF,mBAAO,MAAM,MAAM,QAAQ;AAAA,UAC7B,SAAS,GAAG;AACV,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN;AAAA,cACA;AAAA,cACA;AAAA,cACA,QACE,wCACA,KAAK,UAAW,EAAY,OAAO;AAAA,cACrC,SAAS;AAAA,YACX,CAAC;AACD;AAAA,UACF;AAEA,6BAAmB;AAAA,YACjB;AAAA,aACC,YAAY;AACX,kBAAI,CAAC,KAAK,QAAS;AAEnB,kBAAI,YAAY,KAAK;AAErB,kBAAI,KAAK,sBAAsB,EAAE,SAAS;AACxC,sBAAM,SAAS,KAAK,WAAW,UAAU,IAAI;AAC7C,oBAAI,CAAC,OAAO,SAAS;AACnB,8BACE,KAAK,yCACJ,MAAM;AACL,0BACE,2CACA,KAAK,UAAU,OAAO,MAAM,MAAM;AAAA,kBAEtC;AAAA,gBACJ;AAAA,cACF;AAEA,kBAAI;AACF,sBAAM,SAAS,MAAM,UAAU,MAAM;AAAA,kBACnC;AAAA,kBACA;AAAA,gBACF,CAAC;AAED,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF,CAAC;AAAA,cACH,SAAS,OAAO;AACd,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA,QAAQ,YAAY;AAAA,kBACpB,SAAS;AAAA,gBACX,CAAC;AAAA,cACH,UAAE;AACA,mCAAmB,OAAO,UAAU;AAAA,cACtC;AAAA,YACF,GAAG;AAAA,UACL;AACA;AAAA,QACF;AAAA;AAAA,QAGA,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AACH;AAAA,QAEF,SAAS;AACP,gBAAM,gBAAuB;AAC7B,gBAAM,IAAI,MAAM,yBAAyB,aAAa,EAAE;AAAA,QAC1D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,QAAQ;AACZ,YAAM,QAAQ,IAAI,mBAAmB,OAAO,CAAC;AAAA,IAC/C;AAAA,EACF,CAAC;AACH;","names":[]}
@@ -26,10 +26,10 @@ __export(useOnScrollToBottom_exports, {
26
26
  module.exports = __toCommonJS(useOnScrollToBottom_exports);
27
27
  var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref");
28
28
  var import_react = require("react");
29
- var import_ThreadContext = require("../../context/react/ThreadContext.js");
29
+ var import_ThreadViewportContext = require("../../context/react/ThreadViewportContext.js");
30
30
  var useOnScrollToBottom = (callback) => {
31
31
  const callbackRef = (0, import_react_use_callback_ref.useCallbackRef)(callback);
32
- const onScrollToBottom = (0, import_ThreadContext.useThreadViewport)((vp) => vp.onScrollToBottom);
32
+ const onScrollToBottom = (0, import_ThreadViewportContext.useThreadViewport)((vp) => vp.onScrollToBottom);
33
33
  (0, import_react.useEffect)(() => {
34
34
  return onScrollToBottom(callbackRef);
35
35
  }, [onScrollToBottom, callbackRef]);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/hooks/useOnScrollToBottom.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useEffect } from \"react\";\nimport { useThreadViewport } from \"../../context/react/ThreadContext\";\n\nexport const useOnScrollToBottom = (callback: () => void) => {\n const callbackRef = useCallbackRef(callback);\n const onScrollToBottom = useThreadViewport((vp) => vp.onScrollToBottom);\n\n useEffect(() => {\n return onScrollToBottom(callbackRef);\n }, [onScrollToBottom, callbackRef]);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,oCAA+B;AAC/B,mBAA0B;AAC1B,2BAAkC;AAE3B,IAAM,sBAAsB,CAAC,aAAyB;AAC3D,QAAM,kBAAc,8CAAe,QAAQ;AAC3C,QAAM,uBAAmB,wCAAkB,CAAC,OAAO,GAAG,gBAAgB;AAEtE,8BAAU,MAAM;AACd,WAAO,iBAAiB,WAAW;AAAA,EACrC,GAAG,CAAC,kBAAkB,WAAW,CAAC;AACpC;","names":[]}
1
+ {"version":3,"sources":["../../../src/utils/hooks/useOnScrollToBottom.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useEffect } from \"react\";\nimport { useThreadViewport } from \"../../context/react/ThreadViewportContext\";\n\nexport const useOnScrollToBottom = (callback: () => void) => {\n const callbackRef = useCallbackRef(callback);\n const onScrollToBottom = useThreadViewport((vp) => vp.onScrollToBottom);\n\n useEffect(() => {\n return onScrollToBottom(callbackRef);\n }, [onScrollToBottom, callbackRef]);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,oCAA+B;AAC/B,mBAA0B;AAC1B,mCAAkC;AAE3B,IAAM,sBAAsB,CAAC,aAAyB;AAC3D,QAAM,kBAAc,8CAAe,QAAQ;AAC3C,QAAM,uBAAmB,gDAAkB,CAAC,OAAO,GAAG,gBAAgB;AAEtE,8BAAU,MAAM;AACd,WAAO,iBAAiB,WAAW;AAAA,EACrC,GAAG,CAAC,kBAAkB,WAAW,CAAC;AACpC;","names":[]}
@@ -3,7 +3,7 @@
3
3
  // src/utils/hooks/useOnScrollToBottom.tsx
4
4
  import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
5
5
  import { useEffect } from "react";
6
- import { useThreadViewport } from "../../context/react/ThreadContext.mjs";
6
+ import { useThreadViewport } from "../../context/react/ThreadViewportContext.mjs";
7
7
  var useOnScrollToBottom = (callback) => {
8
8
  const callbackRef = useCallbackRef(callback);
9
9
  const onScrollToBottom = useThreadViewport((vp) => vp.onScrollToBottom);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/hooks/useOnScrollToBottom.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useEffect } from \"react\";\nimport { useThreadViewport } from \"../../context/react/ThreadContext\";\n\nexport const useOnScrollToBottom = (callback: () => void) => {\n const callbackRef = useCallbackRef(callback);\n const onScrollToBottom = useThreadViewport((vp) => vp.onScrollToBottom);\n\n useEffect(() => {\n return onScrollToBottom(callbackRef);\n }, [onScrollToBottom, callbackRef]);\n};\n"],"mappings":";;;AAEA,SAAS,sBAAsB;AAC/B,SAAS,iBAAiB;AAC1B,SAAS,yBAAyB;AAE3B,IAAM,sBAAsB,CAAC,aAAyB;AAC3D,QAAM,cAAc,eAAe,QAAQ;AAC3C,QAAM,mBAAmB,kBAAkB,CAAC,OAAO,GAAG,gBAAgB;AAEtE,YAAU,MAAM;AACd,WAAO,iBAAiB,WAAW;AAAA,EACrC,GAAG,CAAC,kBAAkB,WAAW,CAAC;AACpC;","names":[]}
1
+ {"version":3,"sources":["../../../src/utils/hooks/useOnScrollToBottom.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useEffect } from \"react\";\nimport { useThreadViewport } from \"../../context/react/ThreadViewportContext\";\n\nexport const useOnScrollToBottom = (callback: () => void) => {\n const callbackRef = useCallbackRef(callback);\n const onScrollToBottom = useThreadViewport((vp) => vp.onScrollToBottom);\n\n useEffect(() => {\n return onScrollToBottom(callbackRef);\n }, [onScrollToBottom, callbackRef]);\n};\n"],"mappings":";;;AAEA,SAAS,sBAAsB;AAC/B,SAAS,iBAAiB;AAC1B,SAAS,yBAAyB;AAE3B,IAAM,sBAAsB,CAAC,aAAyB;AAC3D,QAAM,cAAc,eAAe,QAAQ;AAC3C,QAAM,mBAAmB,kBAAkB,CAAC,OAAO,GAAG,gBAAgB;AAEtE,YAAU,MAAM;AACd,WAAO,iBAAiB,WAAW;AAAA,EACrC,GAAG,CAAC,kBAAkB,WAAW,CAAC;AACpC;","names":[]}
package/package.json CHANGED
@@ -29,7 +29,7 @@
29
29
  "conversational-ui",
30
30
  "conversational-ai"
31
31
  ],
32
- "version": "0.7.69",
32
+ "version": "0.7.70",
33
33
  "license": "MIT",
34
34
  "exports": {
35
35
  ".": {
@@ -117,9 +117,9 @@
117
117
  "tailwindcss": "^3.4.17",
118
118
  "tailwindcss-animate": "^1.0.7",
119
119
  "tsx": "^4.19.2",
120
- "@assistant-ui/tailwindcss-transformer": "0.1.0",
120
+ "@assistant-ui/tsbuildutils": "^0.0.1",
121
121
  "@assistant-ui/tsconfig": "0.0.0",
122
- "@assistant-ui/tsbuildutils": "^0.0.1"
122
+ "@assistant-ui/tailwindcss-transformer": "0.1.0"
123
123
  },
124
124
  "publishConfig": {
125
125
  "access": "public",
@@ -150,10 +150,7 @@ export class MessageRuntimeImpl implements MessageRuntime {
150
150
  ref: this.path.ref + `${this.path.ref}.composer`,
151
151
  composerSource: "edit",
152
152
  },
153
- getState: () =>
154
- this._threadBinding
155
- .getState()
156
- .getEditComposer(this._core.getState().id),
153
+ getState: this._getEditComposerRuntimeCore,
157
154
  subscribe: (callback) => this._threadBinding.subscribe(callback),
158
155
  }),
159
156
  () => this._threadBinding.getState().beginEdit(this._core.getState().id),
@@ -177,11 +174,23 @@ export class MessageRuntimeImpl implements MessageRuntime {
177
174
 
178
175
  public readonly composer;
179
176
 
177
+ private _getEditComposerRuntimeCore = () => {
178
+ return this._threadBinding
179
+ .getState()
180
+ .getEditComposer(this._core.getState().id);
181
+ };
182
+
180
183
  public getState() {
181
184
  return this._core.getState();
182
185
  }
183
186
 
184
- public reload({ runConfig = {} }: ReloadConfig = {}) {
187
+ public reload(reloadConfig: ReloadConfig = {}) {
188
+ const editComposerRuntimeCore = this._getEditComposerRuntimeCore();
189
+ const composerRuntimeCore =
190
+ editComposerRuntimeCore ?? this._threadBinding.getState().composer;
191
+ const composer = editComposerRuntimeCore ?? composerRuntimeCore;
192
+
193
+ const { runConfig = composer.runConfig } = reloadConfig;
185
194
  const state = this._core.getState();
186
195
  if (state.role !== "assistant")
187
196
  throw new Error("Can only reload assistant messages");
@@ -4,13 +4,13 @@ import type { FC, PropsWithChildren } from "react";
4
4
  import { useEffect, useState } from "react";
5
5
  import type { ThreadContextValue } from "../react/ThreadContext";
6
6
  import { ThreadContext } from "../react/ThreadContext";
7
- import { makeThreadViewportStore } from "../stores/ThreadViewport";
8
7
  import { writableStore } from "../ReadonlyStore";
9
8
  import { ThreadRuntime } from "../../api/ThreadRuntime";
10
9
  import { create } from "zustand";
11
10
  import { ThreadListItemRuntime } from "../../api/ThreadListItemRuntime";
12
11
  import { ThreadListItemRuntimeProvider } from "./ThreadListItemRuntimeProvider";
13
12
  import { ensureBinding } from "../react/utils/ensureBinding";
13
+ import { ThreadViewportProvider } from "./ThreadViewportProvider";
14
14
 
15
15
  type ThreadProviderProps = {
16
16
  listItemRuntime: ThreadListItemRuntime;
@@ -36,18 +36,17 @@ export const ThreadRuntimeProvider: FC<
36
36
  const useThreadRuntime = useThreadRuntimeStore(runtime);
37
37
 
38
38
  const [context] = useState<ThreadContextValue>(() => {
39
- const useViewport = makeThreadViewportStore();
40
-
41
39
  return {
42
40
  useThreadRuntime,
43
- useViewport,
44
41
  };
45
42
  });
46
43
 
47
44
  return (
48
45
  <ThreadListItemRuntimeProvider runtime={threadListItemRuntime}>
49
46
  <ThreadContext.Provider value={context}>
50
- {children}
47
+ {/* TODO temporarily allow accessing viewport state from outside the viewport */}
48
+ {/* TODO figure out if this behavior should be deprecated, since it is quite hacky */}
49
+ <ThreadViewportProvider>{children}</ThreadViewportProvider>
51
50
  </ThreadContext.Provider>
52
51
  </ThreadListItemRuntimeProvider>
53
52
  );
@@ -0,0 +1,49 @@
1
+ "use client";
2
+
3
+ import type { FC, PropsWithChildren } from "react";
4
+ import { useEffect, useState } from "react";
5
+ import { makeThreadViewportStore } from "../stores/ThreadViewport";
6
+ import {
7
+ ThreadViewportContext,
8
+ ThreadViewportContextValue,
9
+ useThreadViewportStore,
10
+ } from "../react/ThreadViewportContext";
11
+ import { writableStore } from "../ReadonlyStore";
12
+
13
+ const useThreadViewportStoreValue = () => {
14
+ const outerViewport = useThreadViewportStore({ optional: true });
15
+ const [store] = useState(() => makeThreadViewportStore());
16
+
17
+ useEffect(() => {
18
+ return outerViewport?.getState().onScrollToBottom(() => {
19
+ store.getState().scrollToBottom();
20
+ });
21
+ }, [outerViewport, store]);
22
+
23
+ useEffect(() => {
24
+ if (!outerViewport) return;
25
+ return store.subscribe((state) => {
26
+ if (outerViewport.getState().isAtBottom !== state.isAtBottom) {
27
+ writableStore(outerViewport).setState({ isAtBottom: state.isAtBottom });
28
+ }
29
+ });
30
+ }, [store, outerViewport]);
31
+
32
+ return store;
33
+ };
34
+
35
+ export const ThreadViewportProvider: FC<PropsWithChildren> = ({ children }) => {
36
+ const useThreadViewport = useThreadViewportStoreValue();
37
+
38
+ const [context] = useState<ThreadViewportContextValue>(() => {
39
+ return {
40
+ useThreadViewport,
41
+ };
42
+ });
43
+
44
+ return (
45
+ <ThreadViewportContext.Provider value={context}>
46
+ {children}
47
+ </ThreadViewportContext.Provider>
48
+ );
49
+ };
@@ -1,11 +1,9 @@
1
1
  "use client";
2
2
 
3
3
  import { createContext, useEffect, useState } from "react";
4
- import type { ThreadViewportState } from "../stores/ThreadViewport";
5
4
  import { ReadonlyStore } from "../ReadonlyStore";
6
5
  import { UseBoundStore } from "zustand";
7
6
  import { createContextHook } from "./utils/createContextHook";
8
- import { createContextStoreHook } from "./utils/createContextStoreHook";
9
7
  import { ThreadRuntime } from "../../api/ThreadRuntime";
10
8
  import { ModelContext } from "../../model-context";
11
9
  import { createStateHookForRuntime } from "./utils/createStateHookForRuntime";
@@ -13,7 +11,6 @@ import { ThreadComposerRuntime } from "../../api";
13
11
 
14
12
  export type ThreadContextValue = {
15
13
  useThreadRuntime: UseBoundStore<ReadonlyStore<ThreadRuntime>>;
16
- useViewport: UseBoundStore<ReadonlyStore<ThreadViewportState>>;
17
14
  };
18
15
 
19
16
  export const ThreadContext = createContext<ThreadContextValue | null>(null);
@@ -44,11 +41,6 @@ export const useThreadComposer = createStateHookForRuntime(
44
41
  useThreadComposerRuntime,
45
42
  );
46
43
 
47
- export const {
48
- useViewport: useThreadViewport,
49
- useViewportStore: useThreadViewportStore,
50
- } = createContextStoreHook(useThreadContext, "useViewport");
51
-
52
44
  export function useThreadModelContext(options?: {
53
45
  optional?: false | undefined;
54
46
  }): ModelContext;
@@ -0,0 +1,23 @@
1
+ "use client";
2
+
3
+ import { createContext } from "react";
4
+ import { ReadonlyStore } from "../ReadonlyStore";
5
+ import { UseBoundStore } from "zustand";
6
+ import { createContextHook } from "./utils/createContextHook";
7
+ import { createContextStoreHook } from "./utils/createContextStoreHook";
8
+ import { ThreadViewportState } from "../stores";
9
+
10
+ export type ThreadViewportContextValue = {
11
+ useThreadViewport: UseBoundStore<ReadonlyStore<ThreadViewportState>>;
12
+ };
13
+
14
+ export const ThreadViewportContext =
15
+ createContext<ThreadViewportContextValue | null>(null);
16
+
17
+ const useThreadViewportContext = createContextHook(
18
+ ThreadViewportContext,
19
+ "ThreadPrimitive.Viewport",
20
+ );
21
+
22
+ export const { useThreadViewport, useThreadViewportStore } =
23
+ createContextStoreHook(useThreadViewportContext, "useThreadViewport");
@@ -18,9 +18,12 @@ export {
18
18
  * @deprecated This method was renamed to `useThreadModelContext`.
19
19
  */
20
20
  useThreadModelContext as useThreadModelConfig,
21
+ } from "./ThreadContext";
22
+
23
+ export {
21
24
  useThreadViewport,
22
25
  useThreadViewportStore,
23
- } from "./ThreadContext";
26
+ } from "./ThreadViewportContext";
24
27
 
25
28
  export {
26
29
  useThreadListItemRuntime,
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  import { create } from "zustand";
2
4
  import type { Unsubscribe } from "../../types/Unsubscribe";
3
5
 
@@ -27,10 +27,16 @@ export type LanguageModelConfig = z.infer<typeof LanguageModelConfigSchema>;
27
27
  type ToolExecuteFunction<TArgs, TResult> = (
28
28
  args: TArgs,
29
29
  context: {
30
+ toolCallId: string;
30
31
  abortSignal: AbortSignal;
31
32
  },
32
33
  ) => TResult | Promise<TResult>;
33
34
 
35
+ type OnSchemaValidationErrorFunction<TResult> = ToolExecuteFunction<
36
+ unknown,
37
+ TResult
38
+ >;
39
+
34
40
  export type Tool<
35
41
  TArgs extends Record<string, unknown> = Record<string | number, unknown>,
36
42
  TResult = unknown,
@@ -38,6 +44,7 @@ export type Tool<
38
44
  description?: string | undefined;
39
45
  parameters: z.ZodSchema<TArgs> | JSONSchema7;
40
46
  execute?: ToolExecuteFunction<TArgs, TResult>;
47
+ experimental_onSchemaValidationError?: OnSchemaValidationErrorFunction<TResult>;
41
48
  };
42
49
 
43
50
  export type ModelContext = {
@@ -6,8 +6,7 @@ import {
6
6
  createActionButton,
7
7
  } from "../../utils/createActionButton";
8
8
  import { useCallback } from "react";
9
- import { useThreadViewport } from "../../context";
10
- import { useThreadViewportStore } from "../../context/react/ThreadContext";
9
+ import { useThreadViewport, useThreadViewportStore } from "../../context/react/ThreadViewportContext";
11
10
 
12
11
  const useThreadScrollToBottom = () => {
13
12
  const isAtBottom = useThreadViewport((s) => s.isAtBottom);
@@ -4,6 +4,7 @@ import { useComposedRefs } from "@radix-ui/react-compose-refs";
4
4
  import { Primitive } from "@radix-ui/react-primitive";
5
5
  import { type ComponentRef, forwardRef, ComponentPropsWithoutRef } from "react";
6
6
  import { useThreadViewportAutoScroll } from "./useThreadViewportAutoScroll";
7
+ import { ThreadViewportProvider } from "../../context/providers/ThreadViewportProvider";
7
8
 
8
9
  export namespace ThreadPrimitiveViewport {
9
10
  export type Element = ComponentRef<typeof Primitive.div>;
@@ -12,7 +13,7 @@ export namespace ThreadPrimitiveViewport {
12
13
  };
13
14
  }
14
15
 
15
- export const ThreadPrimitiveViewport = forwardRef<
16
+ const ThreadPrimitiveViewportScrollable = forwardRef<
16
17
  ThreadPrimitiveViewport.Element,
17
18
  ThreadPrimitiveViewport.Props
18
19
  >(({ autoScroll, children, ...rest }, forwardedRef) => {
@@ -29,4 +30,15 @@ export const ThreadPrimitiveViewport = forwardRef<
29
30
  );
30
31
  });
31
32
 
33
+ export const ThreadPrimitiveViewport = forwardRef<
34
+ ThreadPrimitiveViewport.Element,
35
+ ThreadPrimitiveViewport.Props
36
+ >((props, ref) => {
37
+ return (
38
+ <ThreadViewportProvider>
39
+ <ThreadPrimitiveViewportScrollable {...props} ref={ref} />
40
+ </ThreadViewportProvider>
41
+ );
42
+ });
43
+
32
44
  ThreadPrimitiveViewport.displayName = "ThreadPrimitive.Viewport";
@@ -2,14 +2,12 @@
2
2
 
3
3
  import { useComposedRefs } from "@radix-ui/react-compose-refs";
4
4
  import { RefCallback, useEffect, useRef } from "react";
5
- import {
6
- useThreadRuntime,
7
- useThreadViewportStore,
8
- } from "../../context/react/ThreadContext";
5
+ import { useThreadRuntime } from "../../context/react/ThreadContext";
9
6
  import { useOnResizeContent } from "../../utils/hooks/useOnResizeContent";
10
7
  import { useOnScrollToBottom } from "../../utils/hooks/useOnScrollToBottom";
11
8
  import { useManagedRef } from "../../utils/hooks/useManagedRef";
12
9
  import { writableStore } from "../../context/ReadonlyStore";
10
+ import { useThreadViewportStore } from "../../context/react/ThreadViewportContext";
13
11
 
14
12
  export namespace useThreadViewportAutoScroll {
15
13
  export type Options = {
@@ -18,7 +18,7 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
18
18
  private _parentId;
19
19
  private _sourceId;
20
20
  constructor(
21
- private runtime: Omit<ThreadRuntimeCore, "composer"> & {
21
+ private runtime: ThreadRuntimeCore & {
22
22
  adapters?: { attachments?: AttachmentAdapter | undefined } | undefined;
23
23
  },
24
24
  private endEditCallback: () => void,
@@ -36,6 +36,9 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
36
36
  this._nonTextParts = message.content.filter(
37
37
  (part) => part.type !== "text" && part.type !== "ui",
38
38
  );
39
+
40
+ // Use the runConfig from the regular (non-edit) composer as the initial runConfig for the edit composer
41
+ this.setRunConfig({ ...runtime.composer.runConfig });
39
42
  }
40
43
 
41
44
  public async handleSend(
@@ -75,30 +75,32 @@ export function toolResultStream(
75
75
  return;
76
76
  }
77
77
 
78
- if (tool.parameters instanceof z.ZodType) {
79
- const result = tool.parameters.safeParse(args);
80
- if (!result.success) {
81
- controller.enqueue({
82
- type: "tool-result",
83
- toolCallType,
84
- toolCallId,
85
- toolName,
86
- result:
87
- "Function parameter validation failed. " +
88
- JSON.stringify(result.error.issues),
89
- isError: true,
90
- });
91
- return;
92
- }
93
- }
94
-
95
78
  toolCallExecutions.set(
96
79
  toolCallId,
97
80
  (async () => {
98
81
  if (!tool.execute) return;
99
82
 
83
+ let executeFn = tool.execute;
84
+
85
+ if (tool.parameters instanceof z.ZodType) {
86
+ const result = tool.parameters.safeParse(args);
87
+ if (!result.success) {
88
+ executeFn =
89
+ tool.experimental_onSchemaValidationError ??
90
+ (() => {
91
+ throw (
92
+ "Function parameter validation failed. " +
93
+ JSON.stringify(result.error.issues)
94
+ );
95
+ });
96
+ }
97
+ }
98
+
100
99
  try {
101
- const result = await tool.execute(args, { abortSignal });
100
+ const result = await executeFn(args, {
101
+ toolCallId,
102
+ abortSignal,
103
+ });
102
104
 
103
105
  controller.enqueue({
104
106
  type: "tool-result",
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
4
4
  import { useEffect } from "react";
5
- import { useThreadViewport } from "../../context/react/ThreadContext";
5
+ import { useThreadViewport } from "../../context/react/ThreadViewportContext";
6
6
 
7
7
  export const useOnScrollToBottom = (callback: () => void) => {
8
8
  const callbackRef = useCallbackRef(callback);