@assistant-ui/react 0.9.1 → 0.9.2

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 (64) hide show
  1. package/dist/model-context/ModelContextTypes.d.ts +11 -9
  2. package/dist/model-context/ModelContextTypes.d.ts.map +1 -1
  3. package/dist/model-context/ModelContextTypes.js.map +1 -1
  4. package/dist/model-context/ModelContextTypes.mjs.map +1 -1
  5. package/dist/model-context/type-path-utils.d.ts +19 -0
  6. package/dist/model-context/type-path-utils.d.ts.map +1 -0
  7. package/dist/model-context/type-path-utils.js +19 -0
  8. package/dist/model-context/type-path-utils.js.map +1 -0
  9. package/dist/model-context/type-path-utils.mjs +1 -0
  10. package/dist/model-context/type-path-utils.mjs.map +1 -0
  11. package/dist/primitives/contentPart/useContentPartText.d.ts +5 -3
  12. package/dist/primitives/contentPart/useContentPartText.d.ts.map +1 -1
  13. package/dist/primitives/contentPart/useContentPartText.js +2 -2
  14. package/dist/primitives/contentPart/useContentPartText.js.map +1 -1
  15. package/dist/primitives/contentPart/useContentPartText.mjs +2 -2
  16. package/dist/primitives/contentPart/useContentPartText.mjs.map +1 -1
  17. package/dist/runtimes/external-store/ThreadMessageLike.d.ts.map +1 -1
  18. package/dist/runtimes/external-store/ThreadMessageLike.js +2 -2
  19. package/dist/runtimes/external-store/ThreadMessageLike.js.map +1 -1
  20. package/dist/runtimes/external-store/ThreadMessageLike.mjs +3 -3
  21. package/dist/runtimes/external-store/ThreadMessageLike.mjs.map +1 -1
  22. package/dist/runtimes/external-store/index.d.ts +1 -1
  23. package/dist/runtimes/external-store/index.d.ts.map +1 -1
  24. package/dist/runtimes/external-store/index.js.map +1 -1
  25. package/dist/runtimes/external-store/index.mjs.map +1 -1
  26. package/dist/runtimes/local/LocalThreadRuntimeCore.d.ts.map +1 -1
  27. package/dist/runtimes/local/LocalThreadRuntimeCore.js +9 -3
  28. package/dist/runtimes/local/LocalThreadRuntimeCore.js.map +1 -1
  29. package/dist/runtimes/local/LocalThreadRuntimeCore.mjs +9 -3
  30. package/dist/runtimes/local/LocalThreadRuntimeCore.mjs.map +1 -1
  31. package/dist/tests/setup.js +8 -8
  32. package/dist/tests/setup.js.map +1 -1
  33. package/dist/tests/setup.mjs +8 -8
  34. package/dist/tests/setup.mjs.map +1 -1
  35. package/dist/types/ContentPartComponentTypes.d.ts +1 -1
  36. package/dist/types/ContentPartComponentTypes.d.ts.map +1 -1
  37. package/dist/types/ContentPartComponentTypes.js.map +1 -1
  38. package/dist/utils/smooth/useSmooth.d.ts +2 -2
  39. package/dist/utils/smooth/useSmooth.d.ts.map +1 -1
  40. package/dist/utils/smooth/useSmooth.js.map +1 -1
  41. package/dist/utils/smooth/useSmooth.mjs.map +1 -1
  42. package/dist/utils/useToolArgsFieldStatus.d.ts +12 -0
  43. package/dist/utils/useToolArgsFieldStatus.d.ts.map +1 -0
  44. package/dist/utils/useToolArgsFieldStatus.js +45 -0
  45. package/dist/utils/useToolArgsFieldStatus.js.map +1 -0
  46. package/dist/utils/useToolArgsFieldStatus.mjs +20 -0
  47. package/dist/utils/useToolArgsFieldStatus.mjs.map +1 -0
  48. package/package.json +5 -5
  49. package/src/model-context/ModelContextTypes.ts +28 -16
  50. package/src/model-context/type-path-utils.ts +32 -0
  51. package/src/primitives/contentPart/useContentPartText.tsx +4 -4
  52. package/src/runtimes/external-store/ThreadMessageLike.tsx +6 -3
  53. package/src/runtimes/external-store/index.ts +2 -0
  54. package/src/runtimes/local/LocalThreadRuntimeCore.tsx +11 -5
  55. package/src/types/ContentPartComponentTypes.tsx +1 -1
  56. package/src/utils/smooth/useSmooth.tsx +7 -3
  57. package/src/utils/useToolArgsFieldStatus.tsx +18 -0
  58. package/dist/utils/json/fix-json.d.ts +0 -2
  59. package/dist/utils/json/fix-json.d.ts.map +0 -1
  60. package/dist/utils/json/fix-json.js +0 -350
  61. package/dist/utils/json/fix-json.js.map +0 -1
  62. package/dist/utils/json/fix-json.mjs +0 -325
  63. package/dist/utils/json/fix-json.mjs.map +0 -1
  64. package/src/utils/json/fix-json.ts +0 -421
@@ -18,7 +18,7 @@ export type FileContentPartComponent = ComponentType<FileContentPartProps>;
18
18
  export type Unstable_AudioContentPartProps = ContentPartState & Unstable_AudioContentPart;
19
19
  export type Unstable_AudioContentPartComponent = ComponentType<Unstable_AudioContentPartProps>;
20
20
  export type ToolCallContentPartProps<TArgs = any, TResult = unknown> = ContentPartState & ToolCallContentPart<TArgs, TResult> & {
21
- addResult: (result: any) => void;
21
+ addResult: (result: TResult) => void;
22
22
  };
23
23
  export type ToolCallContentPartComponent<TArgs = any, TResult = any> = ComponentType<ToolCallContentPartProps<TArgs, TResult>>;
24
24
  //# sourceMappingURL=ContentPartComponentTypes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ContentPartComponentTypes.d.ts","sourceRoot":"","sources":["../../src/types/ContentPartComponentTypes.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,yBAAyB,EAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AACF,MAAM,MAAM,yBAAyB,GAAG,aAAa,CAAC,qBAAqB,CAAC,CAAC;AAE7E,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,eAAe,CAAC;AACtE,MAAM,MAAM,wBAAwB,GAAG,aAAa,CAAC,oBAAoB,CAAC,CAAC;AAE3E,MAAM,MAAM,yBAAyB,GAAG,gBAAgB,GAAG,oBAAoB,CAAC;AAChF,MAAM,MAAM,6BAA6B,GACvC,aAAa,CAAC,yBAAyB,CAAC,CAAC;AAE3C,MAAM,MAAM,sBAAsB,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAC1E,MAAM,MAAM,0BAA0B,GAAG,aAAa,CAAC,sBAAsB,CAAC,CAAC;AAE/E,MAAM,MAAM,qBAAqB,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;AACxE,MAAM,MAAM,yBAAyB,GAAG,aAAa,CAAC,qBAAqB,CAAC,CAAC;AAE7E,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,eAAe,CAAC;AACtE,MAAM,MAAM,wBAAwB,GAAG,aAAa,CAAC,oBAAoB,CAAC,CAAC;AAE3E,MAAM,MAAM,8BAA8B,GAAG,gBAAgB,GAC3D,yBAAyB,CAAC;AAC5B,MAAM,MAAM,kCAAkC,GAC5C,aAAa,CAAC,8BAA8B,CAAC,CAAC;AAEhD,MAAM,MAAM,wBAAwB,CAClC,KAAK,GAAG,GAAG,EACX,OAAO,GAAG,OAAO,IACf,gBAAgB,GAClB,mBAAmB,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG;IACpC,SAAS,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;CAClC,CAAC;AAEJ,MAAM,MAAM,4BAA4B,CACtC,KAAK,GAAG,GAAG,EACX,OAAO,GAAG,GAAG,IACX,aAAa,CAAC,wBAAwB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"ContentPartComponentTypes.d.ts","sourceRoot":"","sources":["../../src/types/ContentPartComponentTypes.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,yBAAyB,EAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AACF,MAAM,MAAM,yBAAyB,GAAG,aAAa,CAAC,qBAAqB,CAAC,CAAC;AAE7E,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,eAAe,CAAC;AACtE,MAAM,MAAM,wBAAwB,GAAG,aAAa,CAAC,oBAAoB,CAAC,CAAC;AAE3E,MAAM,MAAM,yBAAyB,GAAG,gBAAgB,GAAG,oBAAoB,CAAC;AAChF,MAAM,MAAM,6BAA6B,GACvC,aAAa,CAAC,yBAAyB,CAAC,CAAC;AAE3C,MAAM,MAAM,sBAAsB,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAC1E,MAAM,MAAM,0BAA0B,GAAG,aAAa,CAAC,sBAAsB,CAAC,CAAC;AAE/E,MAAM,MAAM,qBAAqB,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;AACxE,MAAM,MAAM,yBAAyB,GAAG,aAAa,CAAC,qBAAqB,CAAC,CAAC;AAE7E,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,eAAe,CAAC;AACtE,MAAM,MAAM,wBAAwB,GAAG,aAAa,CAAC,oBAAoB,CAAC,CAAC;AAE3E,MAAM,MAAM,8BAA8B,GAAG,gBAAgB,GAC3D,yBAAyB,CAAC;AAC5B,MAAM,MAAM,kCAAkC,GAC5C,aAAa,CAAC,8BAA8B,CAAC,CAAC;AAEhD,MAAM,MAAM,wBAAwB,CAClC,KAAK,GAAG,GAAG,EACX,OAAO,GAAG,OAAO,IACf,gBAAgB,GAClB,mBAAmB,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG;IACpC,SAAS,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC,CAAC;AAEJ,MAAM,MAAM,4BAA4B,CACtC,KAAK,GAAG,GAAG,EACX,OAAO,GAAG,GAAG,IACX,aAAa,CAAC,wBAAwB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/ContentPartComponentTypes.tsx"],"sourcesContent":["import type { ComponentType } from \"react\";\nimport type {\n ContentPartStatus,\n FileContentPart,\n ImageContentPart,\n ReasoningContentPart,\n SourceContentPart,\n TextContentPart,\n ToolCallContentPart,\n Unstable_AudioContentPart,\n} from \"./AssistantTypes\";\nimport { ContentPartState } from \"../api/ContentPartRuntime\";\n\nexport type EmptyContentPartProps = {\n status: ContentPartStatus;\n};\nexport type EmptyContentPartComponent = ComponentType<EmptyContentPartProps>;\n\nexport type TextContentPartProps = ContentPartState & TextContentPart;\nexport type TextContentPartComponent = ComponentType<TextContentPartProps>;\n\nexport type ReasoningContentPartProps = ContentPartState & ReasoningContentPart;\nexport type ReasoningContentPartComponent =\n ComponentType<ReasoningContentPartProps>;\n\nexport type SourceContentPartProps = ContentPartState & SourceContentPart;\nexport type SourceContentPartComponent = ComponentType<SourceContentPartProps>;\n\nexport type ImageContentPartProps = ContentPartState & ImageContentPart;\nexport type ImageContentPartComponent = ComponentType<ImageContentPartProps>;\n\nexport type FileContentPartProps = ContentPartState & FileContentPart;\nexport type FileContentPartComponent = ComponentType<FileContentPartProps>;\n\nexport type Unstable_AudioContentPartProps = ContentPartState &\n Unstable_AudioContentPart;\nexport type Unstable_AudioContentPartComponent =\n ComponentType<Unstable_AudioContentPartProps>;\n\nexport type ToolCallContentPartProps<\n TArgs = any,\n TResult = unknown,\n> = ContentPartState &\n ToolCallContentPart<TArgs, TResult> & {\n addResult: (result: any) => void;\n };\n\nexport type ToolCallContentPartComponent<\n TArgs = any,\n TResult = any,\n> = ComponentType<ToolCallContentPartProps<TArgs, TResult>>;\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../src/types/ContentPartComponentTypes.tsx"],"sourcesContent":["import type { ComponentType } from \"react\";\nimport type {\n ContentPartStatus,\n FileContentPart,\n ImageContentPart,\n ReasoningContentPart,\n SourceContentPart,\n TextContentPart,\n ToolCallContentPart,\n Unstable_AudioContentPart,\n} from \"./AssistantTypes\";\nimport { ContentPartState } from \"../api/ContentPartRuntime\";\n\nexport type EmptyContentPartProps = {\n status: ContentPartStatus;\n};\nexport type EmptyContentPartComponent = ComponentType<EmptyContentPartProps>;\n\nexport type TextContentPartProps = ContentPartState & TextContentPart;\nexport type TextContentPartComponent = ComponentType<TextContentPartProps>;\n\nexport type ReasoningContentPartProps = ContentPartState & ReasoningContentPart;\nexport type ReasoningContentPartComponent =\n ComponentType<ReasoningContentPartProps>;\n\nexport type SourceContentPartProps = ContentPartState & SourceContentPart;\nexport type SourceContentPartComponent = ComponentType<SourceContentPartProps>;\n\nexport type ImageContentPartProps = ContentPartState & ImageContentPart;\nexport type ImageContentPartComponent = ComponentType<ImageContentPartProps>;\n\nexport type FileContentPartProps = ContentPartState & FileContentPart;\nexport type FileContentPartComponent = ComponentType<FileContentPartProps>;\n\nexport type Unstable_AudioContentPartProps = ContentPartState &\n Unstable_AudioContentPart;\nexport type Unstable_AudioContentPartComponent =\n ComponentType<Unstable_AudioContentPartProps>;\n\nexport type ToolCallContentPartProps<\n TArgs = any,\n TResult = unknown,\n> = ContentPartState &\n ToolCallContentPart<TArgs, TResult> & {\n addResult: (result: TResult) => void;\n };\n\nexport type ToolCallContentPartComponent<\n TArgs = any,\n TResult = any,\n> = ComponentType<ToolCallContentPartProps<TArgs, TResult>>;\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -1,4 +1,4 @@
1
- import { TextContentPart } from "../../types/AssistantTypes";
1
+ import { ReasoningContentPart, TextContentPart } from "../../types/AssistantTypes";
2
2
  import { ContentPartState } from "../../api/ContentPartRuntime";
3
- export declare const useSmooth: (state: ContentPartState & TextContentPart, smooth?: boolean) => ContentPartState & TextContentPart;
3
+ export declare const useSmooth: (state: ContentPartState & (TextContentPart | ReasoningContentPart), smooth?: boolean) => ContentPartState & (TextContentPart | ReasoningContentPart);
4
4
  //# sourceMappingURL=useSmooth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSmooth.d.ts","sourceRoot":"","sources":["../../../src/utils/smooth/useSmooth.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAqB,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAIhF,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AA4DhE,eAAO,MAAM,SAAS,GACpB,OAAO,gBAAgB,GAAG,eAAe,EACzC,SAAQ,OAAe,KACtB,gBAAgB,GAAG,eA2ErB,CAAC"}
1
+ {"version":3,"file":"useSmooth.d.ts","sourceRoot":"","sources":["../../../src/utils/smooth/useSmooth.tsx"],"names":[],"mappings":"AAIA,OAAO,EAEL,oBAAoB,EACpB,eAAe,EAChB,MAAM,4BAA4B,CAAC;AAIpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AA4DhE,eAAO,MAAM,SAAS,GACpB,OAAO,gBAAgB,GAAG,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAClE,SAAQ,OAAe,KACtB,gBAAgB,GAAG,CAAC,eAAe,GAAG,oBAAoB,CA2E5D,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/smooth/useSmooth.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useMessage } from \"../../context\";\nimport { ContentPartStatus, TextContentPart } from \"../../types/AssistantTypes\";\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useSmoothStatusStore } from \"./SmoothContext\";\nimport { writableStore } from \"../../context/ReadonlyStore\";\nimport { ContentPartState } from \"../../api/ContentPartRuntime\";\n\nclass TextStreamAnimator {\n private animationFrameId: number | null = null;\n private lastUpdateTime: number = Date.now();\n\n public targetText: string = \"\";\n\n constructor(\n public currentText: string,\n private setText: (newText: string) => void,\n ) {}\n\n start() {\n if (this.animationFrameId !== null) return;\n this.lastUpdateTime = Date.now();\n this.animate();\n }\n\n stop() {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n }\n\n private animate = () => {\n const currentTime = Date.now();\n const deltaTime = currentTime - this.lastUpdateTime;\n let timeToConsume = deltaTime;\n\n const remainingChars = this.targetText.length - this.currentText.length;\n const baseTimePerChar = Math.min(5, 250 / remainingChars);\n\n let charsToAdd = 0;\n while (timeToConsume >= baseTimePerChar && charsToAdd < remainingChars) {\n charsToAdd++;\n timeToConsume -= baseTimePerChar;\n }\n\n if (charsToAdd !== remainingChars) {\n this.animationFrameId = requestAnimationFrame(this.animate);\n } else {\n this.animationFrameId = null;\n }\n if (charsToAdd === 0) return;\n\n this.currentText = this.targetText.slice(\n 0,\n this.currentText.length + charsToAdd,\n );\n this.lastUpdateTime = currentTime - timeToConsume;\n this.setText(this.currentText);\n };\n}\n\nconst SMOOTH_STATUS: ContentPartStatus = Object.freeze({\n type: \"running\",\n});\n\nexport const useSmooth = (\n state: ContentPartState & TextContentPart,\n smooth: boolean = false,\n): ContentPartState & TextContentPart => {\n const { text } = state;\n const id = useMessage({\n optional: true,\n selector: (m: { id: string }) => m.id,\n });\n\n const idRef = useRef(id);\n const [displayedText, setDisplayedText] = useState(text);\n\n const smoothStatusStore = useSmoothStatusStore({ optional: true });\n const setText = useCallbackRef((text: string) => {\n setDisplayedText(text);\n if (smoothStatusStore) {\n const target =\n displayedText !== text || state.status.type === \"running\"\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n });\n\n // TODO this is hacky\n useEffect(() => {\n if (smoothStatusStore) {\n const target =\n displayedText !== text || state.status.type === \"running\"\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n }, [smoothStatusStore, text, displayedText, state.status]);\n\n const [animatorRef] = useState<TextStreamAnimator>(\n new TextStreamAnimator(text, setText),\n );\n\n useEffect(() => {\n if (!smooth) {\n animatorRef.stop();\n return;\n }\n\n if (idRef.current !== id || !text.startsWith(animatorRef.targetText)) {\n idRef.current = id;\n setText(text);\n\n animatorRef.currentText = text;\n animatorRef.targetText = text;\n animatorRef.stop();\n\n return;\n }\n\n animatorRef.targetText = text;\n animatorRef.start();\n }, [setText, animatorRef, id, smooth, text]);\n\n useEffect(() => {\n return () => {\n animatorRef.stop();\n };\n }, [animatorRef]);\n\n return useMemo(\n () =>\n smooth\n ? {\n type: \"text\",\n text: displayedText,\n status: text === displayedText ? state.status : SMOOTH_STATUS,\n }\n : state,\n [smooth, displayedText, state, text],\n );\n};\n"],"mappings":"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","names":["text"]}
1
+ {"version":3,"sources":["../../../src/utils/smooth/useSmooth.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useMessage } from \"../../context\";\nimport {\n ContentPartStatus,\n ReasoningContentPart,\n TextContentPart,\n} from \"../../types/AssistantTypes\";\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useSmoothStatusStore } from \"./SmoothContext\";\nimport { writableStore } from \"../../context/ReadonlyStore\";\nimport { ContentPartState } from \"../../api/ContentPartRuntime\";\n\nclass TextStreamAnimator {\n private animationFrameId: number | null = null;\n private lastUpdateTime: number = Date.now();\n\n public targetText: string = \"\";\n\n constructor(\n public currentText: string,\n private setText: (newText: string) => void,\n ) {}\n\n start() {\n if (this.animationFrameId !== null) return;\n this.lastUpdateTime = Date.now();\n this.animate();\n }\n\n stop() {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n }\n\n private animate = () => {\n const currentTime = Date.now();\n const deltaTime = currentTime - this.lastUpdateTime;\n let timeToConsume = deltaTime;\n\n const remainingChars = this.targetText.length - this.currentText.length;\n const baseTimePerChar = Math.min(5, 250 / remainingChars);\n\n let charsToAdd = 0;\n while (timeToConsume >= baseTimePerChar && charsToAdd < remainingChars) {\n charsToAdd++;\n timeToConsume -= baseTimePerChar;\n }\n\n if (charsToAdd !== remainingChars) {\n this.animationFrameId = requestAnimationFrame(this.animate);\n } else {\n this.animationFrameId = null;\n }\n if (charsToAdd === 0) return;\n\n this.currentText = this.targetText.slice(\n 0,\n this.currentText.length + charsToAdd,\n );\n this.lastUpdateTime = currentTime - timeToConsume;\n this.setText(this.currentText);\n };\n}\n\nconst SMOOTH_STATUS: ContentPartStatus = Object.freeze({\n type: \"running\",\n});\n\nexport const useSmooth = (\n state: ContentPartState & (TextContentPart | ReasoningContentPart),\n smooth: boolean = false,\n): ContentPartState & (TextContentPart | ReasoningContentPart) => {\n const { text } = state;\n const id = useMessage({\n optional: true,\n selector: (m: { id: string }) => m.id,\n });\n\n const idRef = useRef(id);\n const [displayedText, setDisplayedText] = useState(text);\n\n const smoothStatusStore = useSmoothStatusStore({ optional: true });\n const setText = useCallbackRef((text: string) => {\n setDisplayedText(text);\n if (smoothStatusStore) {\n const target =\n displayedText !== text || state.status.type === \"running\"\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n });\n\n // TODO this is hacky\n useEffect(() => {\n if (smoothStatusStore) {\n const target =\n displayedText !== text || state.status.type === \"running\"\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n }, [smoothStatusStore, text, displayedText, state.status]);\n\n const [animatorRef] = useState<TextStreamAnimator>(\n new TextStreamAnimator(text, setText),\n );\n\n useEffect(() => {\n if (!smooth) {\n animatorRef.stop();\n return;\n }\n\n if (idRef.current !== id || !text.startsWith(animatorRef.targetText)) {\n idRef.current = id;\n setText(text);\n\n animatorRef.currentText = text;\n animatorRef.targetText = text;\n animatorRef.stop();\n\n return;\n }\n\n animatorRef.targetText = text;\n animatorRef.start();\n }, [setText, animatorRef, id, smooth, text]);\n\n useEffect(() => {\n return () => {\n animatorRef.stop();\n };\n }, [animatorRef]);\n\n return useMemo(\n () =>\n smooth\n ? {\n type: \"text\",\n text: displayedText,\n status: text === displayedText ? state.status : SMOOTH_STATUS,\n }\n : state,\n [smooth, displayedText, state, text],\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,mBAAqD;AACrD,qBAA2B;AAM3B,oCAA+B;AAC/B,2BAAqC;AACrC,2BAA8B;AAG9B,IAAM,qBAAN,MAAyB;AAAA,EAMvB,YACS,aACC,SACR;AAFO;AACC;AAAA,EACP;AAAA,EARK,mBAAkC;AAAA,EAClC,iBAAyB,KAAK,IAAI;AAAA,EAEnC,aAAqB;AAAA,EAO5B,QAAQ;AACN,QAAI,KAAK,qBAAqB,KAAM;AACpC,SAAK,iBAAiB,KAAK,IAAI;AAC/B,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,OAAO;AACL,QAAI,KAAK,qBAAqB,MAAM;AAClC,2BAAqB,KAAK,gBAAgB;AAC1C,WAAK,mBAAmB;AAAA,IAC1B;AAAA,EACF;AAAA,EAEQ,UAAU,MAAM;AACtB,UAAM,cAAc,KAAK,IAAI;AAC7B,UAAM,YAAY,cAAc,KAAK;AACrC,QAAI,gBAAgB;AAEpB,UAAM,iBAAiB,KAAK,WAAW,SAAS,KAAK,YAAY;AACjE,UAAM,kBAAkB,KAAK,IAAI,GAAG,MAAM,cAAc;AAExD,QAAI,aAAa;AACjB,WAAO,iBAAiB,mBAAmB,aAAa,gBAAgB;AACtE;AACA,uBAAiB;AAAA,IACnB;AAEA,QAAI,eAAe,gBAAgB;AACjC,WAAK,mBAAmB,sBAAsB,KAAK,OAAO;AAAA,IAC5D,OAAO;AACL,WAAK,mBAAmB;AAAA,IAC1B;AACA,QAAI,eAAe,EAAG;AAEtB,SAAK,cAAc,KAAK,WAAW;AAAA,MACjC;AAAA,MACA,KAAK,YAAY,SAAS;AAAA,IAC5B;AACA,SAAK,iBAAiB,cAAc;AACpC,SAAK,QAAQ,KAAK,WAAW;AAAA,EAC/B;AACF;AAEA,IAAM,gBAAmC,OAAO,OAAO;AAAA,EACrD,MAAM;AACR,CAAC;AAEM,IAAM,YAAY,CACvB,OACA,SAAkB,UAC8C;AAChE,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,SAAK,2BAAW;AAAA,IACpB,UAAU;AAAA,IACV,UAAU,CAAC,MAAsB,EAAE;AAAA,EACrC,CAAC;AAED,QAAM,YAAQ,qBAAO,EAAE;AACvB,QAAM,CAAC,eAAe,gBAAgB,QAAI,uBAAS,IAAI;AAEvD,QAAM,wBAAoB,2CAAqB,EAAE,UAAU,KAAK,CAAC;AACjE,QAAM,cAAU,8CAAe,CAACA,UAAiB;AAC/C,qBAAiBA,KAAI;AACrB,QAAI,mBAAmB;AACrB,YAAM,SACJ,kBAAkBA,SAAQ,MAAM,OAAO,SAAS,YAC5C,gBACA,MAAM;AACZ,8CAAc,iBAAiB,EAAE,SAAS,QAAQ,IAAI;AAAA,IACxD;AAAA,EACF,CAAC;AAGD,8BAAU,MAAM;AACd,QAAI,mBAAmB;AACrB,YAAM,SACJ,kBAAkB,QAAQ,MAAM,OAAO,SAAS,YAC5C,gBACA,MAAM;AACZ,8CAAc,iBAAiB,EAAE,SAAS,QAAQ,IAAI;AAAA,IACxD;AAAA,EACF,GAAG,CAAC,mBAAmB,MAAM,eAAe,MAAM,MAAM,CAAC;AAEzD,QAAM,CAAC,WAAW,QAAI;AAAA,IACpB,IAAI,mBAAmB,MAAM,OAAO;AAAA,EACtC;AAEA,8BAAU,MAAM;AACd,QAAI,CAAC,QAAQ;AACX,kBAAY,KAAK;AACjB;AAAA,IACF;AAEA,QAAI,MAAM,YAAY,MAAM,CAAC,KAAK,WAAW,YAAY,UAAU,GAAG;AACpE,YAAM,UAAU;AAChB,cAAQ,IAAI;AAEZ,kBAAY,cAAc;AAC1B,kBAAY,aAAa;AACzB,kBAAY,KAAK;AAEjB;AAAA,IACF;AAEA,gBAAY,aAAa;AACzB,gBAAY,MAAM;AAAA,EACpB,GAAG,CAAC,SAAS,aAAa,IAAI,QAAQ,IAAI,CAAC;AAE3C,8BAAU,MAAM;AACd,WAAO,MAAM;AACX,kBAAY,KAAK;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,aAAO;AAAA,IACL,MACE,SACI;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,QAAQ,SAAS,gBAAgB,MAAM,SAAS;AAAA,IAClD,IACA;AAAA,IACN,CAAC,QAAQ,eAAe,OAAO,IAAI;AAAA,EACrC;AACF;","names":["text"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/smooth/useSmooth.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useMessage } from \"../../context\";\nimport { ContentPartStatus, TextContentPart } from \"../../types/AssistantTypes\";\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useSmoothStatusStore } from \"./SmoothContext\";\nimport { writableStore } from \"../../context/ReadonlyStore\";\nimport { ContentPartState } from \"../../api/ContentPartRuntime\";\n\nclass TextStreamAnimator {\n private animationFrameId: number | null = null;\n private lastUpdateTime: number = Date.now();\n\n public targetText: string = \"\";\n\n constructor(\n public currentText: string,\n private setText: (newText: string) => void,\n ) {}\n\n start() {\n if (this.animationFrameId !== null) return;\n this.lastUpdateTime = Date.now();\n this.animate();\n }\n\n stop() {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n }\n\n private animate = () => {\n const currentTime = Date.now();\n const deltaTime = currentTime - this.lastUpdateTime;\n let timeToConsume = deltaTime;\n\n const remainingChars = this.targetText.length - this.currentText.length;\n const baseTimePerChar = Math.min(5, 250 / remainingChars);\n\n let charsToAdd = 0;\n while (timeToConsume >= baseTimePerChar && charsToAdd < remainingChars) {\n charsToAdd++;\n timeToConsume -= baseTimePerChar;\n }\n\n if (charsToAdd !== remainingChars) {\n this.animationFrameId = requestAnimationFrame(this.animate);\n } else {\n this.animationFrameId = null;\n }\n if (charsToAdd === 0) return;\n\n this.currentText = this.targetText.slice(\n 0,\n this.currentText.length + charsToAdd,\n );\n this.lastUpdateTime = currentTime - timeToConsume;\n this.setText(this.currentText);\n };\n}\n\nconst SMOOTH_STATUS: ContentPartStatus = Object.freeze({\n type: \"running\",\n});\n\nexport const useSmooth = (\n state: ContentPartState & TextContentPart,\n smooth: boolean = false,\n): ContentPartState & TextContentPart => {\n const { text } = state;\n const id = useMessage({\n optional: true,\n selector: (m: { id: string }) => m.id,\n });\n\n const idRef = useRef(id);\n const [displayedText, setDisplayedText] = useState(text);\n\n const smoothStatusStore = useSmoothStatusStore({ optional: true });\n const setText = useCallbackRef((text: string) => {\n setDisplayedText(text);\n if (smoothStatusStore) {\n const target =\n displayedText !== text || state.status.type === \"running\"\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n });\n\n // TODO this is hacky\n useEffect(() => {\n if (smoothStatusStore) {\n const target =\n displayedText !== text || state.status.type === \"running\"\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n }, [smoothStatusStore, text, displayedText, state.status]);\n\n const [animatorRef] = useState<TextStreamAnimator>(\n new TextStreamAnimator(text, setText),\n );\n\n useEffect(() => {\n if (!smooth) {\n animatorRef.stop();\n return;\n }\n\n if (idRef.current !== id || !text.startsWith(animatorRef.targetText)) {\n idRef.current = id;\n setText(text);\n\n animatorRef.currentText = text;\n animatorRef.targetText = text;\n animatorRef.stop();\n\n return;\n }\n\n animatorRef.targetText = text;\n animatorRef.start();\n }, [setText, animatorRef, id, smooth, text]);\n\n useEffect(() => {\n return () => {\n animatorRef.stop();\n };\n }, [animatorRef]);\n\n return useMemo(\n () =>\n smooth\n ? {\n type: \"text\",\n text: displayedText,\n status: text === displayedText ? state.status : SMOOTH_STATUS,\n }\n : state,\n [smooth, displayedText, state, text],\n );\n};\n"],"mappings":";;;AAEA,SAAS,WAAW,SAAS,QAAQ,gBAAgB;AACrD,SAAS,kBAAkB;AAE3B,SAAS,sBAAsB;AAC/B,SAAS,4BAA4B;AACrC,SAAS,qBAAqB;AAG9B,IAAM,qBAAN,MAAyB;AAAA,EAMvB,YACS,aACC,SACR;AAFO;AACC;AAAA,EACP;AAAA,EARK,mBAAkC;AAAA,EAClC,iBAAyB,KAAK,IAAI;AAAA,EAEnC,aAAqB;AAAA,EAO5B,QAAQ;AACN,QAAI,KAAK,qBAAqB,KAAM;AACpC,SAAK,iBAAiB,KAAK,IAAI;AAC/B,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,OAAO;AACL,QAAI,KAAK,qBAAqB,MAAM;AAClC,2BAAqB,KAAK,gBAAgB;AAC1C,WAAK,mBAAmB;AAAA,IAC1B;AAAA,EACF;AAAA,EAEQ,UAAU,MAAM;AACtB,UAAM,cAAc,KAAK,IAAI;AAC7B,UAAM,YAAY,cAAc,KAAK;AACrC,QAAI,gBAAgB;AAEpB,UAAM,iBAAiB,KAAK,WAAW,SAAS,KAAK,YAAY;AACjE,UAAM,kBAAkB,KAAK,IAAI,GAAG,MAAM,cAAc;AAExD,QAAI,aAAa;AACjB,WAAO,iBAAiB,mBAAmB,aAAa,gBAAgB;AACtE;AACA,uBAAiB;AAAA,IACnB;AAEA,QAAI,eAAe,gBAAgB;AACjC,WAAK,mBAAmB,sBAAsB,KAAK,OAAO;AAAA,IAC5D,OAAO;AACL,WAAK,mBAAmB;AAAA,IAC1B;AACA,QAAI,eAAe,EAAG;AAEtB,SAAK,cAAc,KAAK,WAAW;AAAA,MACjC;AAAA,MACA,KAAK,YAAY,SAAS;AAAA,IAC5B;AACA,SAAK,iBAAiB,cAAc;AACpC,SAAK,QAAQ,KAAK,WAAW;AAAA,EAC/B;AACF;AAEA,IAAM,gBAAmC,OAAO,OAAO;AAAA,EACrD,MAAM;AACR,CAAC;AAEM,IAAM,YAAY,CACvB,OACA,SAAkB,UACqB;AACvC,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,KAAK,WAAW;AAAA,IACpB,UAAU;AAAA,IACV,UAAU,CAAC,MAAsB,EAAE;AAAA,EACrC,CAAC;AAED,QAAM,QAAQ,OAAO,EAAE;AACvB,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,IAAI;AAEvD,QAAM,oBAAoB,qBAAqB,EAAE,UAAU,KAAK,CAAC;AACjE,QAAM,UAAU,eAAe,CAACA,UAAiB;AAC/C,qBAAiBA,KAAI;AACrB,QAAI,mBAAmB;AACrB,YAAM,SACJ,kBAAkBA,SAAQ,MAAM,OAAO,SAAS,YAC5C,gBACA,MAAM;AACZ,oBAAc,iBAAiB,EAAE,SAAS,QAAQ,IAAI;AAAA,IACxD;AAAA,EACF,CAAC;AAGD,YAAU,MAAM;AACd,QAAI,mBAAmB;AACrB,YAAM,SACJ,kBAAkB,QAAQ,MAAM,OAAO,SAAS,YAC5C,gBACA,MAAM;AACZ,oBAAc,iBAAiB,EAAE,SAAS,QAAQ,IAAI;AAAA,IACxD;AAAA,EACF,GAAG,CAAC,mBAAmB,MAAM,eAAe,MAAM,MAAM,CAAC;AAEzD,QAAM,CAAC,WAAW,IAAI;AAAA,IACpB,IAAI,mBAAmB,MAAM,OAAO;AAAA,EACtC;AAEA,YAAU,MAAM;AACd,QAAI,CAAC,QAAQ;AACX,kBAAY,KAAK;AACjB;AAAA,IACF;AAEA,QAAI,MAAM,YAAY,MAAM,CAAC,KAAK,WAAW,YAAY,UAAU,GAAG;AACpE,YAAM,UAAU;AAChB,cAAQ,IAAI;AAEZ,kBAAY,cAAc;AAC1B,kBAAY,aAAa;AACzB,kBAAY,KAAK;AAEjB;AAAA,IACF;AAEA,gBAAY,aAAa;AACzB,gBAAY,MAAM;AAAA,EACpB,GAAG,CAAC,SAAS,aAAa,IAAI,QAAQ,IAAI,CAAC;AAE3C,YAAU,MAAM;AACd,WAAO,MAAM;AACX,kBAAY,KAAK;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,SAAO;AAAA,IACL,MACE,SACI;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,QAAQ,SAAS,gBAAgB,MAAM,SAAS;AAAA,IAClD,IACA;AAAA,IACN,CAAC,QAAQ,eAAe,OAAO,IAAI;AAAA,EACrC;AACF;","names":["text"]}
1
+ {"version":3,"sources":["../../../src/utils/smooth/useSmooth.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useMessage } from \"../../context\";\nimport {\n ContentPartStatus,\n ReasoningContentPart,\n TextContentPart,\n} from \"../../types/AssistantTypes\";\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useSmoothStatusStore } from \"./SmoothContext\";\nimport { writableStore } from \"../../context/ReadonlyStore\";\nimport { ContentPartState } from \"../../api/ContentPartRuntime\";\n\nclass TextStreamAnimator {\n private animationFrameId: number | null = null;\n private lastUpdateTime: number = Date.now();\n\n public targetText: string = \"\";\n\n constructor(\n public currentText: string,\n private setText: (newText: string) => void,\n ) {}\n\n start() {\n if (this.animationFrameId !== null) return;\n this.lastUpdateTime = Date.now();\n this.animate();\n }\n\n stop() {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n }\n\n private animate = () => {\n const currentTime = Date.now();\n const deltaTime = currentTime - this.lastUpdateTime;\n let timeToConsume = deltaTime;\n\n const remainingChars = this.targetText.length - this.currentText.length;\n const baseTimePerChar = Math.min(5, 250 / remainingChars);\n\n let charsToAdd = 0;\n while (timeToConsume >= baseTimePerChar && charsToAdd < remainingChars) {\n charsToAdd++;\n timeToConsume -= baseTimePerChar;\n }\n\n if (charsToAdd !== remainingChars) {\n this.animationFrameId = requestAnimationFrame(this.animate);\n } else {\n this.animationFrameId = null;\n }\n if (charsToAdd === 0) return;\n\n this.currentText = this.targetText.slice(\n 0,\n this.currentText.length + charsToAdd,\n );\n this.lastUpdateTime = currentTime - timeToConsume;\n this.setText(this.currentText);\n };\n}\n\nconst SMOOTH_STATUS: ContentPartStatus = Object.freeze({\n type: \"running\",\n});\n\nexport const useSmooth = (\n state: ContentPartState & (TextContentPart | ReasoningContentPart),\n smooth: boolean = false,\n): ContentPartState & (TextContentPart | ReasoningContentPart) => {\n const { text } = state;\n const id = useMessage({\n optional: true,\n selector: (m: { id: string }) => m.id,\n });\n\n const idRef = useRef(id);\n const [displayedText, setDisplayedText] = useState(text);\n\n const smoothStatusStore = useSmoothStatusStore({ optional: true });\n const setText = useCallbackRef((text: string) => {\n setDisplayedText(text);\n if (smoothStatusStore) {\n const target =\n displayedText !== text || state.status.type === \"running\"\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n });\n\n // TODO this is hacky\n useEffect(() => {\n if (smoothStatusStore) {\n const target =\n displayedText !== text || state.status.type === \"running\"\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n }, [smoothStatusStore, text, displayedText, state.status]);\n\n const [animatorRef] = useState<TextStreamAnimator>(\n new TextStreamAnimator(text, setText),\n );\n\n useEffect(() => {\n if (!smooth) {\n animatorRef.stop();\n return;\n }\n\n if (idRef.current !== id || !text.startsWith(animatorRef.targetText)) {\n idRef.current = id;\n setText(text);\n\n animatorRef.currentText = text;\n animatorRef.targetText = text;\n animatorRef.stop();\n\n return;\n }\n\n animatorRef.targetText = text;\n animatorRef.start();\n }, [setText, animatorRef, id, smooth, text]);\n\n useEffect(() => {\n return () => {\n animatorRef.stop();\n };\n }, [animatorRef]);\n\n return useMemo(\n () =>\n smooth\n ? {\n type: \"text\",\n text: displayedText,\n status: text === displayedText ? state.status : SMOOTH_STATUS,\n }\n : state,\n [smooth, displayedText, state, text],\n );\n};\n"],"mappings":"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","names":["text"]}
@@ -0,0 +1,12 @@
1
+ export declare const useToolArgsFieldStatus: (fieldPath: (string | number)[]) => {
2
+ readonly type: "running";
3
+ } | {
4
+ readonly type: "complete";
5
+ } | {
6
+ readonly type: "incomplete";
7
+ readonly reason: "cancelled" | "length" | "content-filter" | "other" | "error";
8
+ readonly error?: unknown;
9
+ } | {
10
+ type: string;
11
+ };
12
+ //# sourceMappingURL=useToolArgsFieldStatus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useToolArgsFieldStatus.d.ts","sourceRoot":"","sources":["../../src/utils/useToolArgsFieldStatus.tsx"],"names":[],"mappings":"AAKA,eAAO,MAAM,sBAAsB,GAAI,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE;;;;;;;;;;CAYpE,CAAC"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/utils/useToolArgsFieldStatus.tsx
21
+ var useToolArgsFieldStatus_exports = {};
22
+ __export(useToolArgsFieldStatus_exports, {
23
+ useToolArgsFieldStatus: () => useToolArgsFieldStatus
24
+ });
25
+ module.exports = __toCommonJS(useToolArgsFieldStatus_exports);
26
+ var import_utils = require("assistant-stream/utils");
27
+ var import_context = require("../context/index.js");
28
+ var COMPLETE_STATUS = { type: "complete" };
29
+ var useToolArgsFieldStatus = (fieldPath) => {
30
+ return (0, import_context.useContentPart)((t) => {
31
+ if (t.type !== "tool-call")
32
+ throw new Error(
33
+ "useToolArgsFieldStatus can only be used inside tool-call content parts"
34
+ );
35
+ const state = (0, import_utils.getPartialJsonObjectFieldState)(t.args, fieldPath);
36
+ if (state === "complete" || t.status.type === "requires-action")
37
+ return COMPLETE_STATUS;
38
+ return t.status;
39
+ });
40
+ };
41
+ // Annotate the CommonJS export names for ESM import in node:
42
+ 0 && (module.exports = {
43
+ useToolArgsFieldStatus
44
+ });
45
+ //# sourceMappingURL=useToolArgsFieldStatus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/useToolArgsFieldStatus.tsx"],"sourcesContent":["import { getPartialJsonObjectFieldState } from \"assistant-stream/utils\";\nimport { useContentPart } from \"../context\";\n\nconst COMPLETE_STATUS = { type: \"complete\" };\n\nexport const useToolArgsFieldStatus = (fieldPath: (string | number)[]) => {\n return useContentPart((t) => {\n if (t.type !== \"tool-call\")\n throw new Error(\n \"useToolArgsFieldStatus can only be used inside tool-call content parts\",\n );\n\n const state = getPartialJsonObjectFieldState(t.args, fieldPath);\n if (state === \"complete\" || t.status.type === \"requires-action\")\n return COMPLETE_STATUS;\n return t.status;\n });\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA+C;AAC/C,qBAA+B;AAE/B,IAAM,kBAAkB,EAAE,MAAM,WAAW;AAEpC,IAAM,yBAAyB,CAAC,cAAmC;AACxE,aAAO,+BAAe,CAAC,MAAM;AAC3B,QAAI,EAAE,SAAS;AACb,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAEF,UAAM,YAAQ,6CAA+B,EAAE,MAAM,SAAS;AAC9D,QAAI,UAAU,cAAc,EAAE,OAAO,SAAS;AAC5C,aAAO;AACT,WAAO,EAAE;AAAA,EACX,CAAC;AACH;","names":[]}
@@ -0,0 +1,20 @@
1
+ // src/utils/useToolArgsFieldStatus.tsx
2
+ import { getPartialJsonObjectFieldState } from "assistant-stream/utils";
3
+ import { useContentPart } from "../context/index.mjs";
4
+ var COMPLETE_STATUS = { type: "complete" };
5
+ var useToolArgsFieldStatus = (fieldPath) => {
6
+ return useContentPart((t) => {
7
+ if (t.type !== "tool-call")
8
+ throw new Error(
9
+ "useToolArgsFieldStatus can only be used inside tool-call content parts"
10
+ );
11
+ const state = getPartialJsonObjectFieldState(t.args, fieldPath);
12
+ if (state === "complete" || t.status.type === "requires-action")
13
+ return COMPLETE_STATUS;
14
+ return t.status;
15
+ });
16
+ };
17
+ export {
18
+ useToolArgsFieldStatus
19
+ };
20
+ //# sourceMappingURL=useToolArgsFieldStatus.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/useToolArgsFieldStatus.tsx"],"sourcesContent":["import { getPartialJsonObjectFieldState } from \"assistant-stream/utils\";\nimport { useContentPart } from \"../context\";\n\nconst COMPLETE_STATUS = { type: \"complete\" };\n\nexport const useToolArgsFieldStatus = (fieldPath: (string | number)[]) => {\n return useContentPart((t) => {\n if (t.type !== \"tool-call\")\n throw new Error(\n \"useToolArgsFieldStatus can only be used inside tool-call content parts\",\n );\n\n const state = getPartialJsonObjectFieldState(t.args, fieldPath);\n if (state === \"complete\" || t.status.type === \"requires-action\")\n return COMPLETE_STATUS;\n return t.status;\n });\n};\n"],"mappings":";AAAA,SAAS,sCAAsC;AAC/C,SAAS,sBAAsB;AAE/B,IAAM,kBAAkB,EAAE,MAAM,WAAW;AAEpC,IAAM,yBAAyB,CAAC,cAAmC;AACxE,SAAO,eAAe,CAAC,MAAM;AAC3B,QAAI,EAAE,SAAS;AACb,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAEF,UAAM,QAAQ,+BAA+B,EAAE,MAAM,SAAS;AAC9D,QAAI,UAAU,cAAc,EAAE,OAAO,SAAS;AAC5C,aAAO;AACT,WAAO,EAAE;AAAA,EACX,CAAC;AACH;","names":[]}
package/package.json CHANGED
@@ -28,7 +28,7 @@
28
28
  "conversational-ui",
29
29
  "conversational-ai"
30
30
  ],
31
- "version": "0.9.1",
31
+ "version": "0.9.2",
32
32
  "license": "MIT",
33
33
  "exports": {
34
34
  ".": {
@@ -62,7 +62,7 @@
62
62
  "@radix-ui/react-slot": "^1.2.0",
63
63
  "@radix-ui/react-use-callback-ref": "^1.1.1",
64
64
  "@radix-ui/react-use-escape-keydown": "^1.1.1",
65
- "assistant-stream": "^0.1.1",
65
+ "assistant-stream": "^0.1.2",
66
66
  "nanoid": "5.1.5",
67
67
  "react-textarea-autosize": "^8.5.9",
68
68
  "zod": "^3.24.2",
@@ -86,12 +86,12 @@
86
86
  "@stryker-mutator/core": "^8.7.1",
87
87
  "@stryker-mutator/vitest-runner": "^8.7.1",
88
88
  "@types/json-schema": "^7.0.15",
89
- "@types/node": "^22.14.0",
89
+ "@types/node": "^22.14.1",
90
90
  "eslint": "^9",
91
91
  "eslint-config-next": "15.3.0",
92
92
  "tsx": "^4.19.3",
93
93
  "vitest": "^3.1.1",
94
- "@assistant-ui/tsbuildutils": "^0.0.1",
94
+ "@assistant-ui/tsbuildutils": "0.0.1",
95
95
  "@assistant-ui/tsconfig": "0.0.0"
96
96
  },
97
97
  "publishConfig": {
@@ -107,7 +107,7 @@
107
107
  "url": "https://github.com/assistant-ui/assistant-ui/issues"
108
108
  },
109
109
  "engines": {
110
- "node": ">=20.10.0"
110
+ "node": ">=20.0.0"
111
111
  },
112
112
  "scripts": {
113
113
  "build": "tsx scripts/build.mts",
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import type { JSONSchema7 } from "json-schema";
3
3
  import { Unsubscribe } from "../types/Unsubscribe";
4
+ import { TypePath, TypeAtPath, DeepPartial } from "./type-path-utils";
4
5
 
5
6
  export const LanguageModelV1CallSettingsSchema = z.object({
6
7
  maxTokens: z.number().int().positive().optional(),
@@ -24,27 +25,38 @@ export const LanguageModelConfigSchema = z.object({
24
25
 
25
26
  export type LanguageModelConfig = z.infer<typeof LanguageModelConfigSchema>;
26
27
 
28
+ type ToolExecutionContext = {
29
+ toolCallId: string;
30
+ abortSignal: AbortSignal;
31
+ };
32
+
33
+ type ReadableStreamIterator<T> = ReadableStream<T> &
34
+ AsyncGenerator<T, void, unknown>;
35
+
36
+ interface ToolCallReader<TArgs> {
37
+ get<PathT extends TypePath<TArgs>>(
38
+ ...fieldPath: PathT
39
+ ): Promise<TypeAtPath<TArgs, PathT>>;
40
+
41
+ stream<PathT extends TypePath<TArgs>>(
42
+ ...fieldPath: PathT
43
+ ): ReadableStreamIterator<DeepPartial<TypeAtPath<TArgs, PathT>>>;
44
+
45
+ forEach<PathT extends TypePath<TArgs>>(
46
+ ...fieldPath: PathT
47
+ ): TypeAtPath<TArgs, PathT> extends Array<infer U>
48
+ ? ReadableStreamIterator<U>
49
+ : never;
50
+ }
51
+
27
52
  export type ToolExecuteFunction<TArgs, TResult> = (
28
53
  args: TArgs,
29
- context: {
30
- toolCallId: string;
31
- abortSignal: AbortSignal;
32
- },
54
+ context: ToolExecutionContext,
33
55
  ) => TResult | Promise<TResult>;
34
56
 
35
57
  export type ToolStreamCallFunction<TArgs, TResult> = (
36
- iterator: AsyncGenerator<
37
- {
38
- args: TArgs;
39
- argsTextDelta: string;
40
- },
41
- void,
42
- unknown
43
- >,
44
- context: {
45
- toolCallId: string;
46
- abortSignal: AbortSignal;
47
- },
58
+ controller: ToolCallReader<TArgs>,
59
+ context: ToolExecutionContext,
48
60
  ) => TResult | Promise<TResult>;
49
61
 
50
62
  type OnSchemaValidationErrorFunction<TResult> = ToolExecuteFunction<
@@ -0,0 +1,32 @@
1
+ type AsNumber<K> = K extends `${infer N extends number}` ? N | K : K;
2
+ type TupleIndex<T extends readonly any[]> = Exclude<keyof T, keyof any[]>;
3
+ type IsTuple<T extends readonly any[]> = number extends T["length"]
4
+ ? false
5
+ : true;
6
+
7
+ export type TypePath<T> =
8
+ | []
9
+ | (T extends object
10
+ ? T extends readonly any[]
11
+ ? IsTuple<T> extends true
12
+ ? {
13
+ [K in TupleIndex<T>]: [AsNumber<K>, ...TypePath<T[K]>];
14
+ }[TupleIndex<T>]
15
+ : [number, ...TypePath<T[number]>]
16
+ : { [K in keyof T]: [K, ...TypePath<T[K]>] }[keyof T]
17
+ : []);
18
+
19
+ export type TypeAtPath<T, P extends readonly any[]> = P extends [
20
+ infer Head,
21
+ ...infer Rest,
22
+ ]
23
+ ? Head extends keyof T
24
+ ? TypeAtPath<T[Head], Rest>
25
+ : never
26
+ : T;
27
+
28
+ export type DeepPartial<T> = T extends readonly any[]
29
+ ? readonly DeepPartial<T[number]>[]
30
+ : T extends { [key: string]: any }
31
+ ? { readonly [K in keyof T]?: DeepPartial<T[K]> }
32
+ : T;
@@ -2,16 +2,16 @@
2
2
 
3
3
  import { ContentPartState } from "../../api/ContentPartRuntime";
4
4
  import { useContentPart } from "../../context/react/ContentPartContext";
5
- import { TextContentPart } from "../../types";
5
+ import { TextContentPart, ReasoningContentPart } from "../../types";
6
6
 
7
7
  export const useContentPartText = () => {
8
8
  const text = useContentPart((c) => {
9
- if (c.type !== "text")
9
+ if (c.type !== "text" && c.type !== "reasoning")
10
10
  throw new Error(
11
- "ContentPartText can only be used inside text content parts.",
11
+ "ContentPartText can only be used inside text or reasoning content parts.",
12
12
  );
13
13
 
14
- return c as ContentPartState & TextContentPart;
14
+ return c as ContentPartState & (TextContentPart | ReasoningContentPart);
15
15
  });
16
16
 
17
17
  return text;
@@ -1,4 +1,4 @@
1
- import { parsePartialJson } from "assistant-stream/utils";
1
+ import { parsePartialJsonObject } from "assistant-stream/utils";
2
2
  import { generateId } from "../../internal";
3
3
  import {
4
4
  MessageStatus,
@@ -78,7 +78,7 @@ export const fromThreadMessageLike = (
78
78
  ? [{ type: "text" as const, text: like.content }]
79
79
  : like.content;
80
80
 
81
- if (role !== "user" && attachments)
81
+ if (role !== "user" && attachments?.length)
82
82
  throw new Error("attachments are only supported for user messages");
83
83
 
84
84
  if (role !== "assistant" && status)
@@ -117,7 +117,10 @@ export const fromThreadMessageLike = (
117
117
  return {
118
118
  ...part,
119
119
  toolCallId: part.toolCallId ?? "tool-" + generateId(),
120
- args: part.args ?? parsePartialJson(part.argsText ?? "{}"),
120
+ args:
121
+ part.args ??
122
+ parsePartialJsonObject(part.argsText ?? "") ??
123
+ {},
121
124
  argsText: part.argsText ?? "",
122
125
  };
123
126
  }
@@ -1,6 +1,8 @@
1
1
  export type {
2
2
  ExternalStoreAdapter,
3
3
  ExternalStoreMessageConverter,
4
+ ExternalStoreThreadListAdapter,
5
+ ExternalStoreThreadData,
4
6
  } from "./ExternalStoreAdapter";
5
7
  export type { ThreadMessageLike } from "./ThreadMessageLike";
6
8
  export { useExternalStoreRuntime } from "./useExternalStoreRuntime";
@@ -297,10 +297,11 @@ export class LocalThreadRuntimeCore
297
297
  runCallback ??
298
298
  this.adapters.chatModel.run.bind(this.adapters.chatModel);
299
299
 
300
+ const abortSignal = this.abortController.signal;
300
301
  const promiseOrGenerator = runCallback({
301
302
  messages,
302
303
  runConfig: this._lastRunConfig,
303
- abortSignal: this.abortController.signal,
304
+ abortSignal,
304
305
  context,
305
306
  config: context,
306
307
  unstable_assistantMessageId: message.id,
@@ -312,22 +313,25 @@ export class LocalThreadRuntimeCore
312
313
  // handle async iterator for streaming results
313
314
  if (Symbol.asyncIterator in promiseOrGenerator) {
314
315
  for await (const r of promiseOrGenerator) {
316
+ if (abortSignal.aborted) {
317
+ updateMessage({
318
+ status: { type: "incomplete", reason: "cancelled" },
319
+ });
320
+ break;
321
+ }
322
+
315
323
  updateMessage(r);
316
324
  }
317
325
  } else {
318
326
  updateMessage(await promiseOrGenerator);
319
327
  }
320
328
 
321
- this.abortController = null;
322
-
323
329
  if (message.status.type === "running") {
324
330
  updateMessage({
325
331
  status: { type: "complete", reason: "unknown" },
326
332
  });
327
333
  }
328
334
  } catch (e) {
329
- this.abortController = null;
330
-
331
335
  // TODO this should be handled by the run result stream
332
336
  if (e instanceof Error && e.name === "AbortError") {
333
337
  updateMessage({
@@ -348,6 +352,8 @@ export class LocalThreadRuntimeCore
348
352
  throw e;
349
353
  }
350
354
  } finally {
355
+ this.abortController = null;
356
+
351
357
  if (
352
358
  message.status.type === "complete" ||
353
359
  message.status.type === "incomplete"
@@ -42,7 +42,7 @@ export type ToolCallContentPartProps<
42
42
  TResult = unknown,
43
43
  > = ContentPartState &
44
44
  ToolCallContentPart<TArgs, TResult> & {
45
- addResult: (result: any) => void;
45
+ addResult: (result: TResult) => void;
46
46
  };
47
47
 
48
48
  export type ToolCallContentPartComponent<
@@ -2,7 +2,11 @@
2
2
 
3
3
  import { useEffect, useMemo, useRef, useState } from "react";
4
4
  import { useMessage } from "../../context";
5
- import { ContentPartStatus, TextContentPart } from "../../types/AssistantTypes";
5
+ import {
6
+ ContentPartStatus,
7
+ ReasoningContentPart,
8
+ TextContentPart,
9
+ } from "../../types/AssistantTypes";
6
10
  import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
7
11
  import { useSmoothStatusStore } from "./SmoothContext";
8
12
  import { writableStore } from "../../context/ReadonlyStore";
@@ -67,9 +71,9 @@ const SMOOTH_STATUS: ContentPartStatus = Object.freeze({
67
71
  });
68
72
 
69
73
  export const useSmooth = (
70
- state: ContentPartState & TextContentPart,
74
+ state: ContentPartState & (TextContentPart | ReasoningContentPart),
71
75
  smooth: boolean = false,
72
- ): ContentPartState & TextContentPart => {
76
+ ): ContentPartState & (TextContentPart | ReasoningContentPart) => {
73
77
  const { text } = state;
74
78
  const id = useMessage({
75
79
  optional: true,
@@ -0,0 +1,18 @@
1
+ import { getPartialJsonObjectFieldState } from "assistant-stream/utils";
2
+ import { useContentPart } from "../context";
3
+
4
+ const COMPLETE_STATUS = { type: "complete" };
5
+
6
+ export const useToolArgsFieldStatus = (fieldPath: (string | number)[]) => {
7
+ return useContentPart((t) => {
8
+ if (t.type !== "tool-call")
9
+ throw new Error(
10
+ "useToolArgsFieldStatus can only be used inside tool-call content parts",
11
+ );
12
+
13
+ const state = getPartialJsonObjectFieldState(t.args, fieldPath);
14
+ if (state === "complete" || t.status.type === "requires-action")
15
+ return COMPLETE_STATUS;
16
+ return t.status;
17
+ });
18
+ };
@@ -1,2 +0,0 @@
1
- export declare function fixJson(input: string): [string, number];
2
- //# sourceMappingURL=fix-json.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fix-json.d.ts","sourceRoot":"","sources":["../../../src/utils/json/fix-json.ts"],"names":[],"mappings":"AA0CA,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA0XvD"}