@assistant-ui/core 0.3.18 → 0.3.19

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 (274) hide show
  1. package/dist/adapters/speech.d.ts.map +1 -1
  2. package/dist/adapters/speech.js +13 -3
  3. package/dist/adapters/speech.js.map +1 -1
  4. package/dist/adapters/thread-history.d.ts +4 -0
  5. package/dist/adapters/thread-history.d.ts.map +1 -1
  6. package/dist/index.d.ts +2 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/internal.d.ts +1 -1
  9. package/dist/model-context/frame/host.d.ts.map +1 -1
  10. package/dist/model-context/frame/host.js +26 -11
  11. package/dist/model-context/frame/host.js.map +1 -1
  12. package/dist/model-context/interactable-composer-metadata.js +11 -9
  13. package/dist/model-context/interactable-composer-metadata.js.map +1 -1
  14. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  15. package/dist/react/adapters/LocalStorageThreadListAdapter.js +45 -7
  16. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  17. package/dist/react/client/DataRenderers.d.ts.map +1 -1
  18. package/dist/react/client/DataRenderers.js +20 -15
  19. package/dist/react/client/DataRenderers.js.map +1 -1
  20. package/dist/react/client/Interactables.d.ts.map +1 -1
  21. package/dist/react/client/Interactables.js +11 -5
  22. package/dist/react/client/Interactables.js.map +1 -1
  23. package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
  24. package/dist/react/client/RemoteThreadList.js +3 -2
  25. package/dist/react/client/RemoteThreadList.js.map +1 -1
  26. package/dist/react/client/interactable-model-context.d.ts.map +1 -1
  27. package/dist/react/client/interactable-model-context.js +3 -2
  28. package/dist/react/client/interactable-model-context.js.map +1 -1
  29. package/dist/react/index.d.ts +2 -2
  30. package/dist/react/index.js +2 -2
  31. package/dist/react/interactables-legacy/useAssistantInteractable.d.ts.map +1 -1
  32. package/dist/react/interactables-legacy/useAssistantInteractable.js +3 -0
  33. package/dist/react/interactables-legacy/useAssistantInteractable.js.map +1 -1
  34. package/dist/react/model-context/useInteractable.d.ts.map +1 -1
  35. package/dist/react/model-context/useInteractable.js +4 -1
  36. package/dist/react/model-context/useInteractable.js.map +1 -1
  37. package/dist/react/model-context/useInteractableVersions.js +1 -1
  38. package/dist/react/primitives/message/MessageGroupedParts.d.ts +11 -2
  39. package/dist/react/primitives/message/MessageGroupedParts.d.ts.map +1 -1
  40. package/dist/react/primitives/message/MessageGroupedParts.js +3 -2
  41. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
  42. package/dist/react/primitives/part/PartMessages.d.ts +1 -0
  43. package/dist/react/primitives/part/PartMessages.d.ts.map +1 -1
  44. package/dist/react/primitives/part/PartMessages.js +1 -0
  45. package/dist/react/primitives/part/PartMessages.js.map +1 -1
  46. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  47. package/dist/react/primitives/thread/ThreadMessages.js +6 -5
  48. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  49. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  50. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +2 -1
  51. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  52. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +2 -24
  53. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  54. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +135 -374
  55. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  56. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -0
  57. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  58. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +22 -2
  59. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  60. package/dist/react/runtimes/cloud/auiV0.d.ts +40 -15
  61. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  62. package/dist/react/runtimes/cloud/auiV0.js +62 -15
  63. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  64. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts +2 -1
  65. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts.map +1 -1
  66. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js +4 -0
  67. package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js.map +1 -1
  68. package/dist/react/runtimes/cloud/sdkIdentity.d.ts +6 -0
  69. package/dist/react/runtimes/cloud/sdkIdentity.d.ts.map +1 -0
  70. package/dist/react/runtimes/cloud/sdkIdentity.js +9 -0
  71. package/dist/react/runtimes/cloud/sdkIdentity.js.map +1 -0
  72. package/dist/react/runtimes/external-message-converter.d.ts +12 -2
  73. package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
  74. package/dist/react/runtimes/external-message-converter.js +26 -61
  75. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  76. package/dist/react/runtimes/useRemoteThreadListRuntime.js +1 -1
  77. package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
  78. package/dist/react/utils/groupParts.d.ts +6 -1
  79. package/dist/react/utils/groupParts.d.ts.map +1 -1
  80. package/dist/react/utils/groupParts.js +6 -0
  81. package/dist/react/utils/groupParts.js.map +1 -1
  82. package/dist/react/utils/useJSONEqual.d.ts +3 -1
  83. package/dist/react/utils/useJSONEqual.d.ts.map +1 -1
  84. package/dist/react/utils/useJSONEqual.js +6 -1
  85. package/dist/react/utils/useJSONEqual.js.map +1 -1
  86. package/dist/react/utils/useJSONSchemaDependency.d.ts +7 -0
  87. package/dist/react/utils/useJSONSchemaDependency.d.ts.map +1 -0
  88. package/dist/react/utils/useJSONSchemaDependency.js +20 -0
  89. package/dist/react/utils/useJSONSchemaDependency.js.map +1 -0
  90. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  91. package/dist/runtime/api/thread-runtime.js +2 -5
  92. package/dist/runtime/api/thread-runtime.js.map +1 -1
  93. package/dist/runtime/base/base-composer-runtime-core.d.ts +1 -0
  94. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  95. package/dist/runtime/base/base-composer-runtime-core.js +46 -10
  96. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  97. package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -0
  98. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  99. package/dist/runtime/base/base-thread-runtime-core.js +155 -64
  100. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  101. package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
  102. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  103. package/dist/runtime/queue/message-queue.d.ts +5 -0
  104. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  105. package/dist/runtime/queue/message-queue.js +61 -6
  106. package/dist/runtime/queue/message-queue.js.map +1 -1
  107. package/dist/runtime/utils/auto-status.d.ts +6 -2
  108. package/dist/runtime/utils/auto-status.d.ts.map +1 -1
  109. package/dist/runtime/utils/auto-status.js +12 -4
  110. package/dist/runtime/utils/auto-status.js.map +1 -1
  111. package/dist/runtime/utils/external-message-conversion.d.ts +16 -4
  112. package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -1
  113. package/dist/runtime/utils/external-message-conversion.js +48 -12
  114. package/dist/runtime/utils/external-message-conversion.js.map +1 -1
  115. package/dist/runtime/utils/message-repository.js +3 -3
  116. package/dist/runtime/utils/message-repository.js.map +1 -1
  117. package/dist/runtime/utils/thread-message-like.d.ts +2 -1
  118. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  119. package/dist/runtime/utils/thread-message-like.js +4 -2
  120. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  121. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  122. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +8 -1
  123. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  124. package/dist/runtimes/internal.d.ts +1 -1
  125. package/dist/runtimes/local/local-thread-runtime-core.d.ts +1 -1
  126. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  127. package/dist/runtimes/local/local-thread-runtime-core.js +4 -1
  128. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  129. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  130. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +2 -1
  131. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  132. package/dist/store/clients/external-thread.d.ts.map +1 -1
  133. package/dist/store/clients/external-thread.js +241 -200
  134. package/dist/store/clients/external-thread.js.map +1 -1
  135. package/dist/store/clients/thread-tasks.d.ts +13 -0
  136. package/dist/store/clients/thread-tasks.d.ts.map +1 -0
  137. package/dist/store/clients/thread-tasks.js +69 -0
  138. package/dist/store/clients/thread-tasks.js.map +1 -0
  139. package/dist/store/index.d.ts +3 -2
  140. package/dist/store/index.js +3 -3
  141. package/dist/store/primitive-predicates.d.ts.map +1 -1
  142. package/dist/store/primitive-predicates.js +4 -4
  143. package/dist/store/primitive-predicates.js.map +1 -1
  144. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  145. package/dist/store/runtime-clients/thread-runtime-client.js +176 -128
  146. package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
  147. package/dist/store/scope-registration.d.ts +2 -0
  148. package/dist/store/scope-registration.d.ts.map +1 -1
  149. package/dist/store/scopes/task.d.ts +36 -0
  150. package/dist/store/scopes/task.d.ts.map +1 -0
  151. package/dist/store/scopes/task.js +0 -0
  152. package/dist/store/scopes/thread.d.ts +20 -0
  153. package/dist/store/scopes/thread.d.ts.map +1 -1
  154. package/dist/subscribable/subscribable.d.ts +2 -1
  155. package/dist/subscribable/subscribable.d.ts.map +1 -1
  156. package/dist/subscribable/subscribable.js +23 -15
  157. package/dist/subscribable/subscribable.js.map +1 -1
  158. package/dist/types/index.d.ts +2 -2
  159. package/dist/types/message.d.ts +8 -1
  160. package/dist/types/message.d.ts.map +1 -1
  161. package/dist/types/message.js.map +1 -1
  162. package/dist/utils/abortable-iterable.d.ts.map +1 -1
  163. package/dist/utils/abortable-iterable.js +30 -14
  164. package/dist/utils/abortable-iterable.js.map +1 -1
  165. package/dist/utils/getGroupStatus.d.ts +18 -2
  166. package/dist/utils/getGroupStatus.d.ts.map +1 -1
  167. package/dist/utils/getGroupStatus.js +32 -7
  168. package/dist/utils/getGroupStatus.js.map +1 -1
  169. package/dist/utils/wire-media.d.ts.map +1 -1
  170. package/dist/utils/wire-media.js +2 -2
  171. package/dist/utils/wire-media.js.map +1 -1
  172. package/package.json +6 -6
  173. package/src/adapters/speech.test.ts +236 -0
  174. package/src/adapters/speech.ts +17 -10
  175. package/src/adapters/thread-history.ts +3 -0
  176. package/src/index.ts +1 -0
  177. package/src/model-context/frame/host.test.ts +113 -1
  178. package/src/model-context/frame/host.ts +39 -12
  179. package/src/model-context/interactable-composer-metadata.test.ts +30 -0
  180. package/src/model-context/interactable-composer-metadata.ts +10 -10
  181. package/src/react/adapters/LocalStorageThreadListAdapter.test.ts +244 -0
  182. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +104 -7
  183. package/src/react/client/DataRenderers.test.tsx +45 -0
  184. package/src/react/client/DataRenderers.ts +13 -9
  185. package/src/react/client/Interactables.test.ts +44 -1
  186. package/src/react/client/Interactables.ts +7 -1
  187. package/src/react/client/RemoteThreadList.test.ts +41 -1
  188. package/src/react/client/RemoteThreadList.ts +15 -2
  189. package/src/react/client/interactable-model-context.test.ts +44 -0
  190. package/src/react/client/interactable-model-context.ts +3 -2
  191. package/src/react/index.ts +5 -1
  192. package/src/react/interactables-legacy/useAssistantInteractable.test.tsx +132 -0
  193. package/src/react/interactables-legacy/useAssistantInteractable.ts +10 -1
  194. package/src/react/model-context/useInteractable.test.tsx +177 -0
  195. package/src/react/model-context/useInteractable.ts +3 -0
  196. package/src/react/primitive-hooks/useActionBarCopy.test.ts +0 -1
  197. package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +0 -1
  198. package/src/react/primitives/message/MessageGroupedParts.test.tsx +96 -0
  199. package/src/react/primitives/message/MessageGroupedParts.tsx +15 -4
  200. package/src/react/primitives/part/PartMessages.test.tsx +104 -1
  201. package/src/react/primitives/part/PartMessages.tsx +1 -0
  202. package/src/react/primitives/thread/ThreadMessages.test.tsx +142 -0
  203. package/src/react/primitives/thread/ThreadMessages.tsx +8 -5
  204. package/src/react/providers/ReadonlyThreadProvider.test.tsx +56 -0
  205. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +7 -1
  206. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +20 -14
  207. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +221 -1
  208. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +166 -512
  209. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.test.ts +77 -0
  210. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +27 -1
  211. package/src/react/runtimes/cloud/auiV0.ts +160 -25
  212. package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +21 -0
  213. package/src/react/runtimes/cloud/createCloudThreadListAdapter.ts +7 -1
  214. package/src/react/runtimes/cloud/sdkIdentity.ts +9 -0
  215. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +18 -4
  216. package/src/react/runtimes/external-message-converter.test.ts +136 -1
  217. package/src/react/runtimes/external-message-converter.ts +39 -93
  218. package/src/react/runtimes/useRemoteThreadListRuntime.ts +1 -1
  219. package/src/react/utils/groupParts.ts +12 -1
  220. package/src/react/utils/useJSONEqual.ts +9 -0
  221. package/src/react/utils/useJSONSchemaDependency.ts +22 -0
  222. package/src/runtime/api/thread-runtime.test.ts +58 -0
  223. package/src/runtime/api/thread-runtime.ts +2 -4
  224. package/src/runtime/base/base-composer-runtime-core.ts +69 -16
  225. package/src/runtime/base/base-thread-runtime-core.test.ts +1008 -1
  226. package/src/runtime/base/base-thread-runtime-core.ts +222 -83
  227. package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
  228. package/src/runtime/queue/message-queue.ts +68 -6
  229. package/src/runtime/utils/auto-status.test.ts +112 -1
  230. package/src/runtime/utils/auto-status.ts +31 -5
  231. package/src/runtime/utils/external-message-conversion.test.ts +134 -0
  232. package/src/runtime/utils/external-message-conversion.ts +122 -31
  233. package/src/runtime/utils/message-repository.test.ts +49 -0
  234. package/src/runtime/utils/message-repository.ts +3 -3
  235. package/src/runtime/utils/thread-message-like.test.ts +52 -0
  236. package/src/runtime/utils/thread-message-like.ts +4 -0
  237. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +31 -1
  238. package/src/runtimes/local/local-thread-runtime-core.test.ts +21 -0
  239. package/src/runtimes/local/local-thread-runtime-core.ts +11 -1
  240. package/src/runtimes/tool-invocations/EDGE_CASES.md +2 -6
  241. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +133 -0
  242. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +10 -6
  243. package/src/store/clients/external-thread.ts +19 -1
  244. package/src/store/clients/thread-tasks.test.ts +274 -0
  245. package/src/store/clients/thread-tasks.ts +138 -0
  246. package/src/store/index.ts +8 -0
  247. package/src/store/primitive-predicates.test.ts +48 -5
  248. package/src/store/primitive-predicates.ts +7 -2
  249. package/src/store/runtime-clients/thread-runtime-client.ts +31 -1
  250. package/src/store/scope-registration.ts +2 -0
  251. package/src/store/scopes/task.ts +34 -0
  252. package/src/store/scopes/thread.ts +16 -0
  253. package/src/store/thread-tasks.test.tsx +209 -0
  254. package/src/subscribable/subscribable.test.ts +156 -1
  255. package/src/subscribable/subscribable.ts +25 -15
  256. package/src/tests/MessageRepository.test.ts +1 -5
  257. package/src/tests/auiV0Encode.test.ts +300 -0
  258. package/src/tests/base-composer-runtime-core-send.test.ts +51 -0
  259. package/src/tests/base-composer-runtime-core.test.ts +314 -2
  260. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +151 -0
  261. package/src/tests/external-thread-attachments.test.tsx +69 -0
  262. package/src/tests/external-thread-parity.test.tsx +34 -0
  263. package/src/tests/groupParts.test.ts +71 -0
  264. package/src/tests/message-queue.test.ts +253 -0
  265. package/src/tests/remote-thread-list-reactive-threadId.test.ts +51 -0
  266. package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +43 -0
  267. package/src/types/index.ts +1 -0
  268. package/src/types/message.ts +8 -0
  269. package/src/utils/abortable-iterable.test.ts +115 -0
  270. package/src/utils/abortable-iterable.ts +34 -23
  271. package/src/utils/getGroupStatus.test.ts +70 -4
  272. package/src/utils/getGroupStatus.ts +35 -12
  273. package/src/utils/wire-media.test.ts +10 -0
  274. package/src/utils/wire-media.ts +6 -2
@@ -1 +1 @@
1
- {"version":3,"file":"interactable-model-context.js","names":["Tool","toJSONSchema","Unstable_InteractableDefinition","interactableToolName","shallowMergeInteractableState","Unstable_InteractableSnapshotEntry","generateId","isRecord","PartialJSONSchema","ReturnType","ID_PROPERTY","type","const","description","ITEM_ID_PROPERTY","hasIdProperty","schema","Record","properties","id","undefined","withRequiredItemId","required","withoutItemId","_omitted","Array","isArray","filter","key","toArrayUpdateSchema","field","itemSchema","items","idKeyed","add","remove","clear","update","additionalProperties","idKeyedArrayFieldNames","Set","names","value","Object","entries","withArrayUpdateSchemas","fromEntries","map","withRequiredId","partial","process","env","NODE_ENV","console","warn","_reserved","buildInteractableModelContext","definitions","partialSchemaCache","Map","setDefState","updater","prev","streamBaselines","targetId","state","tools","unstable_composerMetadata","values","length","byName","def","list","get","name","push","set","instances","toolName","first","partialSchema","idKeyedFields","resolveTarget","parameters","streamCall","reader","toolCallId","partialArgs","args","streamValues","keys","idIndex","indexOf","target","baseline","arrayBaseline","execute","validIds","d","success","error","JSON","stringify","join","delete","addedItemIds","idFactory","itemId","result","interactables"],"sources":["../../../src/react/client/interactable-model-context.ts"],"sourcesContent":["import type { Tool } from \"assistant-stream\";\nimport { toJSONSchema } from \"assistant-stream\";\nimport type { Unstable_InteractableDefinition } from \"../types/scopes/interactables\";\nimport {\n interactableToolName,\n shallowMergeInteractableState,\n type Unstable_InteractableSnapshotEntry,\n} from \"../../model-context/interactable-composer-metadata\";\nimport { generateId } from \"../../utils/id\";\nimport { isRecord } from \"../../utils/json/is-json\";\n\nexport type PartialJSONSchema = ReturnType<typeof toJSONSchema>;\n\nconst ID_PROPERTY = {\n type: \"string\" as const,\n description:\n \"The id of the instance to update, as shown in its state snapshot in the conversation.\",\n};\n\nconst ITEM_ID_PROPERTY = {\n type: \"string\" as const,\n description: \"The id of an item currently in this list.\",\n};\n\nconst hasIdProperty = (schema: Record<string, unknown>) => {\n const properties = schema.properties;\n return isRecord(properties) && properties.id !== undefined;\n};\n\nconst withRequiredItemId = (schema: Record<string, unknown>) => ({\n ...schema,\n required: [\"id\"],\n});\n\n// The framework assigns ids to new items, so the model never sees the `id`\n// field when adding (it can't address an item that doesn't exist yet).\nconst withoutItemId = (schema: Record<string, unknown>) => {\n const { id: _omitted, ...properties } = isRecord(schema.properties)\n ? schema.properties\n : {};\n const required = Array.isArray(schema.required)\n ? schema.required.filter((key) => key !== \"id\")\n : schema.required;\n return { ...schema, properties, required };\n};\n\nconst toArrayUpdateSchema = (schema: unknown, field: string) => {\n if (!isRecord(schema) || schema.type !== \"array\") return schema;\n const itemSchema = schema.items;\n if (Array.isArray(itemSchema) || !isRecord(itemSchema)) return schema;\n\n const idKeyed = hasIdProperty(itemSchema);\n const properties: Record<string, unknown> = {\n add: {\n type: \"array\",\n items: idKeyed ? withoutItemId(itemSchema) : itemSchema,\n },\n remove: {\n type: \"array\",\n items: idKeyed ? ITEM_ID_PROPERTY : itemSchema,\n },\n clear: { type: \"boolean\" },\n };\n\n if (idKeyed) {\n properties.update = {\n type: \"array\",\n items: withRequiredItemId(itemSchema),\n };\n }\n\n return {\n type: \"object\" as const,\n description:\n `Operations for array field \"${field}\". To change one item use update ` +\n `with its id; add new items (their ids are assigned for you), remove items ` +\n `by id, or clear to empty. Change only the items you mean to — never resend ` +\n `the whole array to edit one item.`,\n properties,\n additionalProperties: false,\n };\n};\n\n// Top-level array fields whose items carry an `id` — the fields the framework\n// mints ids for on add.\nconst idKeyedArrayFieldNames = (\n properties: Record<string, unknown>,\n): Set<string> => {\n const names = new Set<string>();\n for (const [key, value] of Object.entries(properties)) {\n if (\n isRecord(value) &&\n value.type === \"array\" &&\n isRecord(value.items) &&\n hasIdProperty(value.items)\n ) {\n names.add(key);\n }\n }\n return names;\n};\n\nconst withArrayUpdateSchemas = (properties: Record<string, unknown>) =>\n Object.fromEntries(\n Object.entries(properties).map(([key, value]) => [\n key,\n toArrayUpdateSchema(value, key),\n ]),\n );\n\n/**\n * Wraps an interactable's partial state schema with the required `id`\n * parameter. Falls back to a permissive schema when the partial conversion\n * failed at registration time.\n */\nfunction withRequiredId(partial: PartialJSONSchema | undefined) {\n if (!partial || typeof partial !== \"object\" || partial.type !== \"object\") {\n return {\n type: \"object\" as const,\n properties: { id: ID_PROPERTY },\n required: [\"id\"],\n additionalProperties: true,\n };\n }\n if (process.env.NODE_ENV !== \"production\" && partial.properties?.id) {\n console.warn(\n `[Interactables] a top-level \"id\" field in an interactable's stateSchema is ` +\n `reserved for instance addressing by the update tool and cannot be updated ` +\n `by the model. Rename the field to make it model-writable.`,\n );\n }\n const { id: _reserved, ...properties } = partial.properties ?? {};\n return {\n ...partial,\n properties: { id: ID_PROPERTY, ...withArrayUpdateSchemas(properties) },\n required: [\"id\"],\n };\n}\n\nexport function buildInteractableModelContext(\n definitions: Record<string, Unstable_InteractableDefinition>,\n partialSchemaCache: Map<string, PartialJSONSchema>,\n setDefState: (id: string, updater: (prev: unknown) => unknown) => void,\n streamBaselines = new Map<string, { targetId: string; state: unknown }>(),\n):\n | {\n tools: Record<string, Tool<any, any>>;\n unstable_composerMetadata?: Record<string, unknown>;\n }\n | undefined {\n const entries = Object.values(definitions);\n if (entries.length === 0) return undefined;\n\n const byName = new Map<string, Unstable_InteractableDefinition[]>();\n for (const def of entries) {\n const list = byName.get(def.name) ?? [];\n list.push(def);\n byName.set(def.name, list);\n }\n\n const tools: Record<string, Tool<any, any>> = {};\n\n for (const [name, instances] of byName) {\n const toolName = interactableToolName(name);\n if (tools[toolName]) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `[Interactables] interactable names \"${name}\" and another registered name ` +\n `both sanitize to the tool name \"${toolName}\". Rename one of them.`,\n );\n }\n continue;\n }\n\n const first = instances[0]!;\n const partialSchema = partialSchemaCache.get(first.id);\n const idKeyedFields =\n partialSchema && isRecord(partialSchema.properties)\n ? idKeyedArrayFieldNames(partialSchema.properties)\n : new Set<string>();\n\n // `id` resolves to a definition of this name; an id-less call is accepted\n // only while exactly one instance exists.\n const resolveTarget = (\n id: unknown,\n ): Unstable_InteractableDefinition | undefined => {\n if (typeof id === \"string\") {\n const def = definitions[id];\n return def?.name === name ? def : undefined;\n }\n return instances.length === 1 ? first : undefined;\n };\n\n tools[toolName] = {\n type: \"frontend\",\n description:\n `Update the state of interactable component \"${name}\". ${first.description} ` +\n `Pass the id of the instance to update — instance ids and current state ` +\n `appear in the conversation as state snapshots. Only include the fields ` +\n `you want to change; omitted fields keep their current values.`,\n parameters: withRequiredId(partialSchema),\n streamCall: async (reader, { toolCallId }) => {\n try {\n for await (const partialArgs of reader.args.streamValues()) {\n if (!partialArgs || typeof partialArgs !== \"object\") continue;\n const args = partialArgs as Record<string, unknown>;\n const keys = Object.keys(args);\n const idIndex = keys.indexOf(\"id\");\n if (idIndex === keys.length - 1) continue;\n\n const { id, ...partial } = args;\n if (Object.keys(partial).length === 0) continue;\n const target = resolveTarget(id);\n if (!target) continue;\n\n const baseline = streamBaselines.get(toolCallId);\n const arrayBaseline =\n baseline?.targetId === target.id ? baseline.state : target.state;\n if (!baseline || baseline.targetId !== target.id) {\n streamBaselines.set(toolCallId, {\n targetId: target.id,\n state: target.state,\n });\n }\n\n setDefState(target.id, (prev) =>\n shallowMergeInteractableState(prev, partial, { arrayBaseline }),\n );\n }\n } catch {\n // Non-fatal: execute handles the final state\n }\n },\n execute: async (args: unknown, { toolCallId }) => {\n const { id, ...partial } = (args ?? {}) as Record<string, unknown>;\n const target = resolveTarget(id);\n if (!target) {\n const validIds = instances.map((d) => d.id);\n return {\n success: false,\n error: `Unknown id ${JSON.stringify(id)} for interactable \"${name}\". Valid ids: ${validIds.join(\", \")}`,\n };\n }\n const baseline = streamBaselines.get(toolCallId);\n streamBaselines.delete(toolCallId);\n const addedItemIds: Record<string, string[]> = {};\n setDefState(target.id, (prev) =>\n shallowMergeInteractableState(prev, partial, {\n arrayBaseline:\n baseline?.targetId === target.id ? baseline.state : undefined,\n idFactory: (field) => {\n const itemId = generateId();\n (addedItemIds[field] ??= []).push(itemId);\n return itemId;\n },\n idKeyedFields,\n }),\n );\n // The resolved id lets an id-less call's UI (and the model) address\n // the instance that was actually updated.\n const result: {\n success: true;\n id: string;\n addedItemIds?: Record<string, string[]>;\n } = { success: true, id: target.id };\n if (Object.keys(addedItemIds).length > 0) {\n result.addedItemIds = addedItemIds;\n }\n return result;\n },\n };\n }\n\n const interactables: Unstable_InteractableSnapshotEntry[] = entries.map(\n (def) => ({\n id: def.id,\n name: def.name,\n state: def.state,\n }),\n );\n return { tools, unstable_composerMetadata: { interactables } };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"interactable-model-context.js","names":["Tool","toJSONSchema","Unstable_InteractableDefinition","interactableToolName","shallowMergeInteractableState","Unstable_InteractableSnapshotEntry","generateId","isRecord","nullProtoRecord","PartialJSONSchema","ReturnType","ID_PROPERTY","type","const","description","ITEM_ID_PROPERTY","hasIdProperty","schema","Record","properties","id","undefined","withRequiredItemId","required","withoutItemId","_omitted","Array","isArray","filter","key","toArrayUpdateSchema","field","itemSchema","items","idKeyed","add","remove","clear","update","additionalProperties","idKeyedArrayFieldNames","Set","names","value","Object","entries","withArrayUpdateSchemas","fromEntries","map","withRequiredId","partial","process","env","NODE_ENV","console","warn","_reserved","buildInteractableModelContext","definitions","partialSchemaCache","Map","setDefState","updater","prev","streamBaselines","targetId","state","tools","unstable_composerMetadata","values","length","byName","def","list","get","name","push","set","instances","toolName","first","partialSchema","idKeyedFields","resolveTarget","parameters","streamCall","reader","toolCallId","partialArgs","args","streamValues","keys","idIndex","indexOf","target","baseline","arrayBaseline","execute","validIds","d","success","error","JSON","stringify","join","delete","addedItemIds","idFactory","itemId","result","interactables"],"sources":["../../../src/react/client/interactable-model-context.ts"],"sourcesContent":["import type { Tool } from \"assistant-stream\";\nimport { toJSONSchema } from \"assistant-stream\";\nimport type { Unstable_InteractableDefinition } from \"../types/scopes/interactables\";\nimport {\n interactableToolName,\n shallowMergeInteractableState,\n type Unstable_InteractableSnapshotEntry,\n} from \"../../model-context/interactable-composer-metadata\";\nimport { generateId } from \"../../utils/id\";\nimport { isRecord } from \"../../utils/json/is-json\";\nimport { nullProtoRecord } from \"../../utils/record\";\n\nexport type PartialJSONSchema = ReturnType<typeof toJSONSchema>;\n\nconst ID_PROPERTY = {\n type: \"string\" as const,\n description:\n \"The id of the instance to update, as shown in its state snapshot in the conversation.\",\n};\n\nconst ITEM_ID_PROPERTY = {\n type: \"string\" as const,\n description: \"The id of an item currently in this list.\",\n};\n\nconst hasIdProperty = (schema: Record<string, unknown>) => {\n const properties = schema.properties;\n return isRecord(properties) && properties.id !== undefined;\n};\n\nconst withRequiredItemId = (schema: Record<string, unknown>) => ({\n ...schema,\n required: [\"id\"],\n});\n\n// The framework assigns ids to new items, so the model never sees the `id`\n// field when adding (it can't address an item that doesn't exist yet).\nconst withoutItemId = (schema: Record<string, unknown>) => {\n const { id: _omitted, ...properties } = isRecord(schema.properties)\n ? schema.properties\n : {};\n const required = Array.isArray(schema.required)\n ? schema.required.filter((key) => key !== \"id\")\n : schema.required;\n return { ...schema, properties, required };\n};\n\nconst toArrayUpdateSchema = (schema: unknown, field: string) => {\n if (!isRecord(schema) || schema.type !== \"array\") return schema;\n const itemSchema = schema.items;\n if (Array.isArray(itemSchema) || !isRecord(itemSchema)) return schema;\n\n const idKeyed = hasIdProperty(itemSchema);\n const properties: Record<string, unknown> = {\n add: {\n type: \"array\",\n items: idKeyed ? withoutItemId(itemSchema) : itemSchema,\n },\n remove: {\n type: \"array\",\n items: idKeyed ? ITEM_ID_PROPERTY : itemSchema,\n },\n clear: { type: \"boolean\" },\n };\n\n if (idKeyed) {\n properties.update = {\n type: \"array\",\n items: withRequiredItemId(itemSchema),\n };\n }\n\n return {\n type: \"object\" as const,\n description:\n `Operations for array field \"${field}\". To change one item use update ` +\n `with its id; add new items (their ids are assigned for you), remove items ` +\n `by id, or clear to empty. Change only the items you mean to — never resend ` +\n `the whole array to edit one item.`,\n properties,\n additionalProperties: false,\n };\n};\n\n// Top-level array fields whose items carry an `id` — the fields the framework\n// mints ids for on add.\nconst idKeyedArrayFieldNames = (\n properties: Record<string, unknown>,\n): Set<string> => {\n const names = new Set<string>();\n for (const [key, value] of Object.entries(properties)) {\n if (\n isRecord(value) &&\n value.type === \"array\" &&\n isRecord(value.items) &&\n hasIdProperty(value.items)\n ) {\n names.add(key);\n }\n }\n return names;\n};\n\nconst withArrayUpdateSchemas = (properties: Record<string, unknown>) =>\n Object.fromEntries(\n Object.entries(properties).map(([key, value]) => [\n key,\n toArrayUpdateSchema(value, key),\n ]),\n );\n\n/**\n * Wraps an interactable's partial state schema with the required `id`\n * parameter. Falls back to a permissive schema when the partial conversion\n * failed at registration time.\n */\nfunction withRequiredId(partial: PartialJSONSchema | undefined) {\n if (!partial || typeof partial !== \"object\" || partial.type !== \"object\") {\n return {\n type: \"object\" as const,\n properties: { id: ID_PROPERTY },\n required: [\"id\"],\n additionalProperties: true,\n };\n }\n if (process.env.NODE_ENV !== \"production\" && partial.properties?.id) {\n console.warn(\n `[Interactables] a top-level \"id\" field in an interactable's stateSchema is ` +\n `reserved for instance addressing by the update tool and cannot be updated ` +\n `by the model. Rename the field to make it model-writable.`,\n );\n }\n const { id: _reserved, ...properties } = partial.properties ?? {};\n return {\n ...partial,\n properties: { id: ID_PROPERTY, ...withArrayUpdateSchemas(properties) },\n required: [\"id\"],\n };\n}\n\nexport function buildInteractableModelContext(\n definitions: Record<string, Unstable_InteractableDefinition>,\n partialSchemaCache: Map<string, PartialJSONSchema>,\n setDefState: (id: string, updater: (prev: unknown) => unknown) => void,\n streamBaselines = new Map<string, { targetId: string; state: unknown }>(),\n):\n | {\n tools: Record<string, Tool<any, any>>;\n unstable_composerMetadata?: Record<string, unknown>;\n }\n | undefined {\n const entries = Object.values(definitions);\n if (entries.length === 0) return undefined;\n\n const byName = new Map<string, Unstable_InteractableDefinition[]>();\n for (const def of entries) {\n const list = byName.get(def.name) ?? [];\n list.push(def);\n byName.set(def.name, list);\n }\n\n const tools: Record<string, Tool<any, any>> = {};\n\n for (const [name, instances] of byName) {\n const toolName = interactableToolName(name);\n if (tools[toolName]) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `[Interactables] interactable names \"${name}\" and another registered name ` +\n `both sanitize to the tool name \"${toolName}\". Rename one of them.`,\n );\n }\n continue;\n }\n\n const first = instances[0]!;\n const partialSchema = partialSchemaCache.get(first.id);\n const idKeyedFields =\n partialSchema && isRecord(partialSchema.properties)\n ? idKeyedArrayFieldNames(partialSchema.properties)\n : new Set<string>();\n\n // `id` resolves to a definition of this name; an id-less call is accepted\n // only while exactly one instance exists.\n const resolveTarget = (\n id: unknown,\n ): Unstable_InteractableDefinition | undefined => {\n if (typeof id === \"string\") {\n const def = definitions[id];\n return def?.name === name ? def : undefined;\n }\n return instances.length === 1 ? first : undefined;\n };\n\n tools[toolName] = {\n type: \"frontend\",\n description:\n `Update the state of interactable component \"${name}\". ${first.description} ` +\n `Pass the id of the instance to update — instance ids and current state ` +\n `appear in the conversation as state snapshots. Only include the fields ` +\n `you want to change; omitted fields keep their current values.`,\n parameters: withRequiredId(partialSchema),\n streamCall: async (reader, { toolCallId }) => {\n try {\n for await (const partialArgs of reader.args.streamValues()) {\n if (!partialArgs || typeof partialArgs !== \"object\") continue;\n const args = partialArgs as Record<string, unknown>;\n const keys = Object.keys(args);\n const idIndex = keys.indexOf(\"id\");\n if (idIndex === keys.length - 1) continue;\n\n const { id, ...partial } = args;\n if (Object.keys(partial).length === 0) continue;\n const target = resolveTarget(id);\n if (!target) continue;\n\n const baseline = streamBaselines.get(toolCallId);\n const arrayBaseline =\n baseline?.targetId === target.id ? baseline.state : target.state;\n if (!baseline || baseline.targetId !== target.id) {\n streamBaselines.set(toolCallId, {\n targetId: target.id,\n state: target.state,\n });\n }\n\n setDefState(target.id, (prev) =>\n shallowMergeInteractableState(prev, partial, { arrayBaseline }),\n );\n }\n } catch {\n // Non-fatal: execute handles the final state\n }\n },\n execute: async (args: unknown, { toolCallId }) => {\n const { id, ...partial } = (args ?? {}) as Record<string, unknown>;\n const target = resolveTarget(id);\n if (!target) {\n const validIds = instances.map((d) => d.id);\n return {\n success: false,\n error: `Unknown id ${JSON.stringify(id)} for interactable \"${name}\". Valid ids: ${validIds.join(\", \")}`,\n };\n }\n const baseline = streamBaselines.get(toolCallId);\n streamBaselines.delete(toolCallId);\n const addedItemIds = nullProtoRecord<string[]>();\n setDefState(target.id, (prev) =>\n shallowMergeInteractableState(prev, partial, {\n arrayBaseline:\n baseline?.targetId === target.id ? baseline.state : undefined,\n idFactory: (field) => {\n const itemId = generateId();\n (addedItemIds[field] ??= []).push(itemId);\n return itemId;\n },\n idKeyedFields,\n }),\n );\n // The resolved id lets an id-less call's UI (and the model) address\n // the instance that was actually updated.\n const result: {\n success: true;\n id: string;\n addedItemIds?: Record<string, string[]>;\n } = { success: true, id: target.id };\n if (Object.keys(addedItemIds).length > 0) {\n result.addedItemIds = { ...addedItemIds };\n }\n return result;\n },\n };\n }\n\n const interactables: Unstable_InteractableSnapshotEntry[] = entries.map(\n (def) => ({\n id: def.id,\n name: def.name,\n state: def.state,\n }),\n );\n return { tools, unstable_composerMetadata: { interactables } };\n}\n"],"mappings":"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"}
@@ -5,7 +5,7 @@ import { PartState } from "../store/scopes/part.js";
5
5
  import { RuntimeAdapter } from "./RuntimeAdapter.js";
6
6
  import { RuntimeAdapters } from "../runtimes/remote-thread-list/types.js";
7
7
  import { JoinStrategy } from "../runtime/utils/external-message-conversion.js";
8
- import { convertExternalMessages, useExternalMessageConverter } from "./runtimes/external-message-converter.js";
8
+ import { ExternalMessageConversionCache, convertExternalMessages, createExternalMessageConversionCache, useExternalMessageConverter } from "./runtimes/external-message-converter.js";
9
9
  import { StreamingTimingAccessors, StreamingTimingOptions, StreamingTimingState } from "../runtime/utils/streaming-timing.js";
10
10
  import { useStreamingTiming } from "./runtimes/useStreamingTiming.js";
11
11
  import { DataMessagePartComponent, DataMessagePartProps, EmptyMessagePartComponent, EmptyMessagePartProps, FileMessagePartComponent, FileMessagePartProps, GenerativeUIComponentRegistry, GenerativeUIMessagePartComponent, GenerativeUIMessagePartProps, GenerativeUIRenderProps, ImageMessagePartComponent, ImageMessagePartProps, QuoteMessagePartComponent, QuoteMessagePartProps, ReasoningGroupComponent, ReasoningGroupProps, ReasoningMessagePartComponent, ReasoningMessagePartProps, SourceMessagePartComponent, SourceMessagePartProps, TextMessagePartComponent, TextMessagePartProps, ToolCallMessagePartComponent, ToolCallMessagePartProps, Unstable_AudioMessagePartComponent, Unstable_AudioMessagePartProps } from "./types/MessagePartComponentTypes.js";
@@ -119,4 +119,4 @@ import { useEditComposerCancel } from "./primitive-hooks/useEditComposerCancel.j
119
119
  import { useEditComposerSend } from "./primitive-hooks/useEditComposerSend.js";
120
120
  import { useMessageError } from "./primitive-hooks/useMessageError.js";
121
121
  import { LocalRuntimeOptions, splitLocalRuntimeOptions, useLocalRuntime } from "./runtimes/useLocalRuntime.js";
122
- export { type AssistantContextConfig, type AssistantDataUI, type AssistantDataUIProps, type AssistantInteractableProps, AssistantProviderBase, type AssistantProviderBaseProps, AssistantRuntimeProvider, type AssistantTool, type AssistantToolProps, type AssistantToolUI, type AssistantToolUIProps, type AssistantTransportCommand, type AssistantTransportConnectionMetadata, type AssistantTransportOptions, type AssistantTransportProtocol, type AsyncStorageLike, ChainOfThoughtByIndicesProvider, ChainOfThoughtPartByIndexProvider, ChainOfThoughtPrimitiveParts, CloudFileAttachmentAdapter, type CloudThreadListAdapterOptions, ComposerAttachmentByIndexProvider, ComposerPrimitiveAttachmentByIndex, ComposerPrimitiveAttachments, ComposerPrimitiveIf, ComposerPrimitiveQueue, type DataMessagePartComponent, type DataMessagePartProps, DataRenderers, type DataRenderersClientSchema, type DataRenderersMethods, type DataRenderersState, type EmptyMessagePartComponent, type EmptyMessagePartProps, type EnrichedPartState, type FileMessagePartComponent, type FileMessagePartProps, type GenerativeUIComponentRegistry, type GenerativeUIMessagePartComponent, type GenerativeUIMessagePartProps, GenerativeUIRender, GenerativeUIRenderError, type GenerativeUIRenderProps, type GroupByContext, type ImageMessagePartComponent, type ImageMessagePartProps, type InteractableDefinition, type InteractablePersistedState, type InteractablePersistenceAdapter, type InteractablePersistenceStatus, type InteractableRegistration, type InteractableStateSchema, Interactables, type InteractablesClientSchema, type InteractablesMethods, type InteractablesState, type JoinStrategy, type LocalRuntimeOptions, type McpAppResourceOutput, type McpToolkitDefinition, type McpToolkitEntry, type McpToolkitToolConfig, MessageAttachmentByIndexProvider, MessageByIndexProvider, MessagePartComponent, MessagePartPrimitiveInProgress, MessagePrimitiveAttachmentByIndex, MessagePrimitiveAttachments, MessagePrimitiveGenerativeUI, MessagePrimitiveGroupedParts, MessagePrimitivePartByIndex, MessagePrimitiveParts, MessagePrimitiveQuote, PartByIndexProvider, PartPrimitiveMessages, PartPrimitiveMessagesImpl, type PartState, type ProviderToolConfig, QueueItemByIndexProvider, type QueueItemByIndexProviderProps, type QuoteMessagePartComponent, type QuoteMessagePartProps, ReadonlyThreadProvider, type ReasoningGroupComponent, type ReasoningGroupProps, type ReasoningMessagePartComponent, type ReasoningMessagePartProps, RemoteThreadListHookInstanceManager, RemoteThreadListThreadListRuntimeCore, RuntimeAdapter, RuntimeAdapterProvider, type RuntimeAdapters, type RuntimeExtras, type SendCommandsRequestBody, type SourceMessagePartComponent, type SourceMessagePartProps, type StreamingTimingAccessors, type StreamingTimingOptions, type StreamingTimingState, SuggestionByIndexProvider, type SuggestionByIndexProviderProps, type TextMessagePartComponent, type TextMessagePartProps, TextMessagePartProvider, ThreadListItemByIndexProvider, ThreadListItemPrimitiveTitle, ThreadListItemRuntimeProvider, ThreadListPrimitiveItemByIndex, ThreadListPrimitiveItems, ThreadPrimitiveMessageByIndex, ThreadPrimitiveMessages, ThreadPrimitiveMessagesImpl, ThreadPrimitiveSuggestionByIndex, ThreadPrimitiveSuggestions, ThreadPrimitiveSuggestionsImpl, ThreadPrimitiveUnstable_MessageById, type TitleGenerationAdapter, type ToolArgsStatus, type ToolCallMessagePartComponent, type ToolCallMessagePartProps, type ToolCallText, type ToolDefinition, type Toolkit, type ToolkitDefinition, type ToolkitDefinitionEntry, Tools, type ToolsClientSchema, type ToolsMethods, type ToolsState, type Unstable_AudioMessagePartComponent, type Unstable_AudioMessagePartProps, type Unstable_InferInteractableState, type Unstable_InteractableConfig, type Unstable_InteractableDefinition, type Unstable_InteractablePersistedState, type Unstable_InteractablePersistenceAdapter, type Unstable_InteractablePersistenceStatus, type Unstable_InteractableRegistration, type Unstable_InteractableStateSchema, type Unstable_InteractableToolConfig, type Unstable_InteractableToolRenderProps, type Unstable_InteractableVersionInfo, type Unstable_InteractablesClientSchema, type Unstable_InteractablesConfig, type Unstable_InteractablesMethods, type Unstable_InteractablesState, type UseActionBarCopyOptions, type UseComposerIfProps, type UseSuggestionTriggerOptions, convertExternalMessages, createCloudThreadListAdapter, createLocalStorageAdapter, createMessageConverter, createRuntimeExtras, createSimpleTitleAdapter, defineMcpToolkit, defineToolkit, externalTool, getMessageQuote, getRenderComponent, groupPartByType, hitl, hitlTool, humanTool, makeAssistantDataUI, makeAssistantTool, makeAssistantToolUI, defaultComponents as messagePartsDefaultComponents, providerTool, splitLocalRuntimeOptions, stubTool, unstable_Interactables, unstable_createRuntimeExtrasFromBrand, unstable_interactableTool, unstable_useInteractable, unstable_useInteractableState, unstable_useInteractableVersions, unstable_useThreadMessageIds, useActionBarCopy, useActionBarEdit, useActionBarFeedbackNegative, useActionBarFeedbackPositive, useActionBarReload, useActionBarSpeak, useActionBarStopSpeaking, useAssistantCloudThreadHistoryAdapter, useAssistantContext, useAssistantDataUI, useAssistantInstructions, useAssistantInteractable, useAssistantTool, useAssistantToolUI, useAssistantTransportRuntime, useAssistantTransportSendCommand, useAssistantTransportState, useAuiToolOverrides, useBranchPickerNext, useBranchPickerPrevious, useCloudThreadListAdapter, useCloudThreadListRuntime, useComposerAddAttachment, useComposerCancel, useComposerDictate, useComposerSend, useEditComposerCancel, useEditComposerSend, useExternalMessageConverter, useExternalStoreRuntime, useExternalStoreSharedOptions, useInlineRender, useInteractableState, useLocalRuntime, useMessageBranching, useMessageError, useMessageReload, useRemoteThreadListRuntime, useRuntimeAdapters, useStreamingTiming, useSuggestionTrigger, useThreadIsEmpty, useThreadIsRunning, useThreadListItemArchive, useThreadListItemDelete, useThreadListItemTrigger, useThreadListItemUnarchive, useThreadListLoadMore, useThreadListNew, useThreadMessages, useToolArgsStatus, useVoiceControls, useVoiceState, useVoiceVolume };
122
+ export { type AssistantContextConfig, type AssistantDataUI, type AssistantDataUIProps, type AssistantInteractableProps, AssistantProviderBase, type AssistantProviderBaseProps, AssistantRuntimeProvider, type AssistantTool, type AssistantToolProps, type AssistantToolUI, type AssistantToolUIProps, type AssistantTransportCommand, type AssistantTransportConnectionMetadata, type AssistantTransportOptions, type AssistantTransportProtocol, type AsyncStorageLike, ChainOfThoughtByIndicesProvider, ChainOfThoughtPartByIndexProvider, ChainOfThoughtPrimitiveParts, CloudFileAttachmentAdapter, type CloudThreadListAdapterOptions, ComposerAttachmentByIndexProvider, ComposerPrimitiveAttachmentByIndex, ComposerPrimitiveAttachments, ComposerPrimitiveIf, ComposerPrimitiveQueue, type DataMessagePartComponent, type DataMessagePartProps, DataRenderers, type DataRenderersClientSchema, type DataRenderersMethods, type DataRenderersState, type EmptyMessagePartComponent, type EmptyMessagePartProps, type EnrichedPartState, type ExternalMessageConversionCache, type FileMessagePartComponent, type FileMessagePartProps, type GenerativeUIComponentRegistry, type GenerativeUIMessagePartComponent, type GenerativeUIMessagePartProps, GenerativeUIRender, GenerativeUIRenderError, type GenerativeUIRenderProps, type GroupByContext, type ImageMessagePartComponent, type ImageMessagePartProps, type InteractableDefinition, type InteractablePersistedState, type InteractablePersistenceAdapter, type InteractablePersistenceStatus, type InteractableRegistration, type InteractableStateSchema, Interactables, type InteractablesClientSchema, type InteractablesMethods, type InteractablesState, type JoinStrategy, type LocalRuntimeOptions, type McpAppResourceOutput, type McpToolkitDefinition, type McpToolkitEntry, type McpToolkitToolConfig, MessageAttachmentByIndexProvider, MessageByIndexProvider, MessagePartComponent, MessagePartPrimitiveInProgress, MessagePrimitiveAttachmentByIndex, MessagePrimitiveAttachments, MessagePrimitiveGenerativeUI, MessagePrimitiveGroupedParts, MessagePrimitivePartByIndex, MessagePrimitiveParts, MessagePrimitiveQuote, PartByIndexProvider, PartPrimitiveMessages, PartPrimitiveMessagesImpl, type PartState, type ProviderToolConfig, QueueItemByIndexProvider, type QueueItemByIndexProviderProps, type QuoteMessagePartComponent, type QuoteMessagePartProps, ReadonlyThreadProvider, type ReasoningGroupComponent, type ReasoningGroupProps, type ReasoningMessagePartComponent, type ReasoningMessagePartProps, RemoteThreadListHookInstanceManager, RemoteThreadListThreadListRuntimeCore, RuntimeAdapter, RuntimeAdapterProvider, type RuntimeAdapters, type RuntimeExtras, type SendCommandsRequestBody, type SourceMessagePartComponent, type SourceMessagePartProps, type StreamingTimingAccessors, type StreamingTimingOptions, type StreamingTimingState, SuggestionByIndexProvider, type SuggestionByIndexProviderProps, type TextMessagePartComponent, type TextMessagePartProps, TextMessagePartProvider, ThreadListItemByIndexProvider, ThreadListItemPrimitiveTitle, ThreadListItemRuntimeProvider, ThreadListPrimitiveItemByIndex, ThreadListPrimitiveItems, ThreadPrimitiveMessageByIndex, ThreadPrimitiveMessages, ThreadPrimitiveMessagesImpl, ThreadPrimitiveSuggestionByIndex, ThreadPrimitiveSuggestions, ThreadPrimitiveSuggestionsImpl, ThreadPrimitiveUnstable_MessageById, type TitleGenerationAdapter, type ToolArgsStatus, type ToolCallMessagePartComponent, type ToolCallMessagePartProps, type ToolCallText, type ToolDefinition, type Toolkit, type ToolkitDefinition, type ToolkitDefinitionEntry, Tools, type ToolsClientSchema, type ToolsMethods, type ToolsState, type Unstable_AudioMessagePartComponent, type Unstable_AudioMessagePartProps, type Unstable_InferInteractableState, type Unstable_InteractableConfig, type Unstable_InteractableDefinition, type Unstable_InteractablePersistedState, type Unstable_InteractablePersistenceAdapter, type Unstable_InteractablePersistenceStatus, type Unstable_InteractableRegistration, type Unstable_InteractableStateSchema, type Unstable_InteractableToolConfig, type Unstable_InteractableToolRenderProps, type Unstable_InteractableVersionInfo, type Unstable_InteractablesClientSchema, type Unstable_InteractablesConfig, type Unstable_InteractablesMethods, type Unstable_InteractablesState, type UseActionBarCopyOptions, type UseComposerIfProps, type UseSuggestionTriggerOptions, convertExternalMessages, createCloudThreadListAdapter, createExternalMessageConversionCache, createLocalStorageAdapter, createMessageConverter, createRuntimeExtras, createSimpleTitleAdapter, defineMcpToolkit, defineToolkit, externalTool, getMessageQuote, getRenderComponent, groupPartByType, hitl, hitlTool, humanTool, makeAssistantDataUI, makeAssistantTool, makeAssistantToolUI, defaultComponents as messagePartsDefaultComponents, providerTool, splitLocalRuntimeOptions, stubTool, unstable_Interactables, unstable_createRuntimeExtrasFromBrand, unstable_interactableTool, unstable_useInteractable, unstable_useInteractableState, unstable_useInteractableVersions, unstable_useThreadMessageIds, useActionBarCopy, useActionBarEdit, useActionBarFeedbackNegative, useActionBarFeedbackPositive, useActionBarReload, useActionBarSpeak, useActionBarStopSpeaking, useAssistantCloudThreadHistoryAdapter, useAssistantContext, useAssistantDataUI, useAssistantInstructions, useAssistantInteractable, useAssistantTool, useAssistantToolUI, useAssistantTransportRuntime, useAssistantTransportSendCommand, useAssistantTransportState, useAuiToolOverrides, useBranchPickerNext, useBranchPickerPrevious, useCloudThreadListAdapter, useCloudThreadListRuntime, useComposerAddAttachment, useComposerCancel, useComposerDictate, useComposerSend, useEditComposerCancel, useEditComposerSend, useExternalMessageConverter, useExternalStoreRuntime, useExternalStoreSharedOptions, useInlineRender, useInteractableState, useLocalRuntime, useMessageBranching, useMessageError, useMessageReload, useRemoteThreadListRuntime, useRuntimeAdapters, useStreamingTiming, useSuggestionTrigger, useThreadIsEmpty, useThreadIsRunning, useThreadListItemArchive, useThreadListItemDelete, useThreadListItemTrigger, useThreadListItemUnarchive, useThreadListLoadMore, useThreadListNew, useThreadMessages, useToolArgsStatus, useVoiceControls, useVoiceState, useVoiceVolume };
@@ -27,7 +27,7 @@ import { unstable_useInteractableVersions } from "./model-context/useInteractabl
27
27
  import { unstable_interactableTool } from "./model-context/interactableTool.js";
28
28
  import { useToolArgsStatus } from "./model-context/useToolArgsStatus.js";
29
29
  import { useRuntimeAdapters } from "./runtimes/useRuntimeAdapters.js";
30
- import { convertExternalMessages, useExternalMessageConverter } from "./runtimes/external-message-converter.js";
30
+ import { convertExternalMessages, createExternalMessageConversionCache, useExternalMessageConverter } from "./runtimes/external-message-converter.js";
31
31
  import { useStreamingTiming } from "./runtimes/useStreamingTiming.js";
32
32
  import { Interactables } from "./interactables-legacy/Interactables.js";
33
33
  import { unstable_Interactables } from "./client/Interactables.js";
@@ -105,4 +105,4 @@ import { useEditComposerCancel } from "./primitive-hooks/useEditComposerCancel.j
105
105
  import { useEditComposerSend } from "./primitive-hooks/useEditComposerSend.js";
106
106
  import { useMessageError } from "./primitive-hooks/useMessageError.js";
107
107
  import { splitLocalRuntimeOptions, useLocalRuntime } from "./runtimes/useLocalRuntime.js";
108
- export { AssistantProviderBase, AssistantRuntimeProvider, ChainOfThoughtByIndicesProvider, ChainOfThoughtPartByIndexProvider, ChainOfThoughtPrimitiveParts, CloudFileAttachmentAdapter, ComposerAttachmentByIndexProvider, ComposerPrimitiveAttachmentByIndex, ComposerPrimitiveAttachments, ComposerPrimitiveIf, ComposerPrimitiveQueue, DataRenderers, GenerativeUIRender, GenerativeUIRenderError, Interactables, MessageAttachmentByIndexProvider, MessageByIndexProvider, MessagePartComponent, MessagePartPrimitiveInProgress, MessagePrimitiveAttachmentByIndex, MessagePrimitiveAttachments, MessagePrimitiveGenerativeUI, MessagePrimitiveGroupedParts, MessagePrimitivePartByIndex, MessagePrimitiveParts, MessagePrimitiveQuote, PartByIndexProvider, PartPrimitiveMessages, PartPrimitiveMessagesImpl, QueueItemByIndexProvider, ReadonlyThreadProvider, RemoteThreadListHookInstanceManager, RemoteThreadListThreadListRuntimeCore, RuntimeAdapter, RuntimeAdapterProvider, SuggestionByIndexProvider, TextMessagePartProvider, ThreadListItemByIndexProvider, ThreadListItemPrimitiveTitle, ThreadListItemRuntimeProvider, ThreadListPrimitiveItemByIndex, ThreadListPrimitiveItems, ThreadPrimitiveMessageByIndex, ThreadPrimitiveMessages, ThreadPrimitiveMessagesImpl, ThreadPrimitiveSuggestionByIndex, ThreadPrimitiveSuggestions, ThreadPrimitiveSuggestionsImpl, ThreadPrimitiveUnstable_MessageById, Tools, convertExternalMessages, createCloudThreadListAdapter, createLocalStorageAdapter, createMessageConverter, createRuntimeExtras, createSimpleTitleAdapter, defineMcpToolkit, defineToolkit, externalTool, getMessageQuote, getRenderComponent, groupPartByType, hitl, hitlTool, humanTool, makeAssistantDataUI, makeAssistantTool, makeAssistantToolUI, defaultComponents as messagePartsDefaultComponents, providerTool, splitLocalRuntimeOptions, stubTool, unstable_Interactables, unstable_createRuntimeExtrasFromBrand, unstable_interactableTool, unstable_useInteractable, unstable_useInteractableState, unstable_useInteractableVersions, unstable_useThreadMessageIds, useActionBarCopy, useActionBarEdit, useActionBarFeedbackNegative, useActionBarFeedbackPositive, useActionBarReload, useActionBarSpeak, useActionBarStopSpeaking, useAssistantCloudThreadHistoryAdapter, useAssistantContext, useAssistantDataUI, useAssistantInstructions, useAssistantInteractable, useAssistantTool, useAssistantToolUI, useAssistantTransportRuntime, useAssistantTransportSendCommand, useAssistantTransportState, useAuiToolOverrides, useBranchPickerNext, useBranchPickerPrevious, useCloudThreadListAdapter, useCloudThreadListRuntime, useComposerAddAttachment, useComposerCancel, useComposerDictate, useComposerSend, useEditComposerCancel, useEditComposerSend, useExternalMessageConverter, useExternalStoreRuntime, useExternalStoreSharedOptions, useInlineRender, useInteractableState, useLocalRuntime, useMessageBranching, useMessageError, useMessageReload, useRemoteThreadListRuntime, useRuntimeAdapters, useStreamingTiming, useSuggestionTrigger, useThreadIsEmpty, useThreadIsRunning, useThreadListItemArchive, useThreadListItemDelete, useThreadListItemTrigger, useThreadListItemUnarchive, useThreadListLoadMore, useThreadListNew, useThreadMessages, useToolArgsStatus, useVoiceControls, useVoiceState, useVoiceVolume };
108
+ export { AssistantProviderBase, AssistantRuntimeProvider, ChainOfThoughtByIndicesProvider, ChainOfThoughtPartByIndexProvider, ChainOfThoughtPrimitiveParts, CloudFileAttachmentAdapter, ComposerAttachmentByIndexProvider, ComposerPrimitiveAttachmentByIndex, ComposerPrimitiveAttachments, ComposerPrimitiveIf, ComposerPrimitiveQueue, DataRenderers, GenerativeUIRender, GenerativeUIRenderError, Interactables, MessageAttachmentByIndexProvider, MessageByIndexProvider, MessagePartComponent, MessagePartPrimitiveInProgress, MessagePrimitiveAttachmentByIndex, MessagePrimitiveAttachments, MessagePrimitiveGenerativeUI, MessagePrimitiveGroupedParts, MessagePrimitivePartByIndex, MessagePrimitiveParts, MessagePrimitiveQuote, PartByIndexProvider, PartPrimitiveMessages, PartPrimitiveMessagesImpl, QueueItemByIndexProvider, ReadonlyThreadProvider, RemoteThreadListHookInstanceManager, RemoteThreadListThreadListRuntimeCore, RuntimeAdapter, RuntimeAdapterProvider, SuggestionByIndexProvider, TextMessagePartProvider, ThreadListItemByIndexProvider, ThreadListItemPrimitiveTitle, ThreadListItemRuntimeProvider, ThreadListPrimitiveItemByIndex, ThreadListPrimitiveItems, ThreadPrimitiveMessageByIndex, ThreadPrimitiveMessages, ThreadPrimitiveMessagesImpl, ThreadPrimitiveSuggestionByIndex, ThreadPrimitiveSuggestions, ThreadPrimitiveSuggestionsImpl, ThreadPrimitiveUnstable_MessageById, Tools, convertExternalMessages, createCloudThreadListAdapter, createExternalMessageConversionCache, createLocalStorageAdapter, createMessageConverter, createRuntimeExtras, createSimpleTitleAdapter, defineMcpToolkit, defineToolkit, externalTool, getMessageQuote, getRenderComponent, groupPartByType, hitl, hitlTool, humanTool, makeAssistantDataUI, makeAssistantTool, makeAssistantToolUI, defaultComponents as messagePartsDefaultComponents, providerTool, splitLocalRuntimeOptions, stubTool, unstable_Interactables, unstable_createRuntimeExtrasFromBrand, unstable_interactableTool, unstable_useInteractable, unstable_useInteractableState, unstable_useInteractableVersions, unstable_useThreadMessageIds, useActionBarCopy, useActionBarEdit, useActionBarFeedbackNegative, useActionBarFeedbackPositive, useActionBarReload, useActionBarSpeak, useActionBarStopSpeaking, useAssistantCloudThreadHistoryAdapter, useAssistantContext, useAssistantDataUI, useAssistantInstructions, useAssistantInteractable, useAssistantTool, useAssistantToolUI, useAssistantTransportRuntime, useAssistantTransportSendCommand, useAssistantTransportState, useAuiToolOverrides, useBranchPickerNext, useBranchPickerPrevious, useCloudThreadListAdapter, useCloudThreadListRuntime, useComposerAddAttachment, useComposerCancel, useComposerDictate, useComposerSend, useEditComposerCancel, useEditComposerSend, useExternalMessageConverter, useExternalStoreRuntime, useExternalStoreSharedOptions, useInlineRender, useInteractableState, useLocalRuntime, useMessageBranching, useMessageError, useMessageReload, useRemoteThreadListRuntime, useRuntimeAdapters, useStreamingTiming, useSuggestionTrigger, useThreadIsEmpty, useThreadIsRunning, useThreadListItemArchive, useThreadListItemDelete, useThreadListItemTrigger, useThreadListItemUnarchive, useThreadListLoadMore, useThreadListNew, useThreadMessages, useToolArgsStatus, useVoiceControls, useVoiceState, useVoiceVolume };
@@ -1 +1 @@
1
- {"version":3,"file":"useAssistantInteractable.d.ts","names":[],"sources":["../../../src/react/interactables-legacy/useAssistantInteractable.ts"],"mappings":";;;;;;;KASY;EACV;EACA,aAAa;EACb;EACA;EACA;;;;;;;;;;;;;;cAeW,2BACX,cACA,QAAQ"}
1
+ {"version":3,"file":"useAssistantInteractable.d.ts","names":[],"sources":["../../../src/react/interactables-legacy/useAssistantInteractable.ts"],"mappings":";;;;;;;KAUY;EACV;EACA,aAAa;EACb;EACA;EACA;;;;;;;;;;;;;;cAeW,2BACX,cACA,QAAQ"}
@@ -1,3 +1,4 @@
1
+ import { useJSONSchemaDependency } from "../utils/useJSONSchemaDependency.js";
1
2
  import { useEffect, useId, useRef } from "@assistant-ui/tap/react-shim";
2
3
  import { useAui } from "@assistant-ui/store";
3
4
  //#region src/react/interactables-legacy/useAssistantInteractable.ts
@@ -19,6 +20,7 @@ const useAssistantInteractable = (name, config) => {
19
20
  const id = config.id ?? autoId;
20
21
  const stateSchemaRef = useRef(config.stateSchema);
21
22
  stateSchemaRef.current = config.stateSchema;
23
+ const normalizedStateSchema = useJSONSchemaDependency(config.stateSchema);
22
24
  const initialStateRef = useRef(config.initialState);
23
25
  initialStateRef.current = config.initialState;
24
26
  useEffect(() => {
@@ -35,6 +37,7 @@ const useAssistantInteractable = (name, config) => {
35
37
  id,
36
38
  name,
37
39
  config.description,
40
+ normalizedStateSchema,
38
41
  config.selected
39
42
  ]);
40
43
  return id;
@@ -1 +1 @@
1
- {"version":3,"file":"useAssistantInteractable.js","names":["useEffect","useId","useRef","useAui","InteractableStateSchema","AssistantInteractableProps","description","stateSchema","initialState","id","selected","useAssistantInteractable","name","config","aui","autoId","replace","stateSchemaRef","current","initialStateRef","interactables","register"],"sources":["../../../src/react/interactables-legacy/useAssistantInteractable.ts"],"sourcesContent":["import { useEffect, useId, useRef } from \"react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport type { InteractableStateSchema } from \"./scopes\";\n\n/**\n * @deprecated Since 2026-06-14 — migrate to the Unstable / Experimental API.\n * Scheduled for removal on/after 2026-09-14. See\n * {@link https://www.assistant-ui.com/docs/tools/interactables#migrating-from-the-previous-api | Interactables migration guide}.\n */\nexport type AssistantInteractableProps = {\n description: string;\n stateSchema: InteractableStateSchema;\n initialState: unknown;\n id?: string;\n selected?: boolean;\n};\n\n/**\n * @deprecated Since 2026-06-14 — migrate to the Unstable / Experimental API.\n * Scheduled for removal on/after 2026-09-14. See\n * {@link https://www.assistant-ui.com/docs/tools/interactables#migrating-from-the-previous-api | Interactables migration guide}.\n *\n * Registers an interactable with the AI assistant.\n *\n * This hook handles registration only. To read and write the interactable's\n * state, use {@link useInteractableState} with the returned id.\n *\n * @returns The interactable instance id.\n */\nexport const useAssistantInteractable = (\n name: string,\n config: AssistantInteractableProps,\n): string => {\n const aui = useAui();\n\n const autoId = useId().replace(/[^a-zA-Z0-9]/g, \"\");\n const id = config.id ?? autoId;\n\n const stateSchemaRef = useRef(config.stateSchema);\n stateSchemaRef.current = config.stateSchema;\n const initialStateRef = useRef(config.initialState);\n initialStateRef.current = config.initialState;\n\n useEffect(() => {\n return aui.interactables.register({\n id,\n name,\n description: config.description,\n stateSchema: stateSchemaRef.current,\n initialState: initialStateRef.current,\n selected: config.selected,\n });\n }, [aui, id, name, config.description, config.selected]);\n\n return id;\n};\n"],"mappings":";;;;;;;;;;;;;;;AA6BA,MAAaW,4BACXC,MACAC,WACW;CACX,MAAMC,MAAMX,OAAO;CAEnB,MAAMY,SAASd,MAAM,CAAC,CAACe,QAAQ,iBAAiB,EAAE;CAClD,MAAMP,KAAKI,OAAOJ,MAAMM;CAExB,MAAME,iBAAiBf,OAAOW,OAAON,WAAW;CAChDU,eAAeC,UAAUL,OAAON;CAChC,MAAMY,kBAAkBjB,OAAOW,OAAOL,YAAY;CAClDW,gBAAgBD,UAAUL,OAAOL;CAEjCR,gBAAgB;EACd,OAAOc,IAAIM,cAAcC,SAAS;GAChCZ;GACAG;GACAN,aAAaO,OAAOP;GACpBC,aAAaU,eAAeC;GAC5BV,cAAcW,gBAAgBD;GAC9BR,UAAUG,OAAOH;EACnB,CAAC;CACH,GAAG;EAACI;EAAKL;EAAIG;EAAMC,OAAOP;EAAaO,OAAOH;CAAQ,CAAC;CAEvD,OAAOD;AACT"}
1
+ {"version":3,"file":"useAssistantInteractable.js","names":["useEffect","useId","useRef","useAui","useJSONSchemaDependency","InteractableStateSchema","AssistantInteractableProps","description","stateSchema","initialState","id","selected","useAssistantInteractable","name","config","aui","autoId","replace","stateSchemaRef","current","normalizedStateSchema","initialStateRef","interactables","register"],"sources":["../../../src/react/interactables-legacy/useAssistantInteractable.ts"],"sourcesContent":["import { useEffect, useId, useRef } from \"react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport { useJSONSchemaDependency } from \"../utils/useJSONSchemaDependency\";\nimport type { InteractableStateSchema } from \"./scopes\";\n\n/**\n * @deprecated Since 2026-06-14 — migrate to the Unstable / Experimental API.\n * Scheduled for removal on/after 2026-09-14. See\n * {@link https://www.assistant-ui.com/docs/tools/interactables#migrating-from-the-previous-api | Interactables migration guide}.\n */\nexport type AssistantInteractableProps = {\n description: string;\n stateSchema: InteractableStateSchema;\n initialState: unknown;\n id?: string;\n selected?: boolean;\n};\n\n/**\n * @deprecated Since 2026-06-14 — migrate to the Unstable / Experimental API.\n * Scheduled for removal on/after 2026-09-14. See\n * {@link https://www.assistant-ui.com/docs/tools/interactables#migrating-from-the-previous-api | Interactables migration guide}.\n *\n * Registers an interactable with the AI assistant.\n *\n * This hook handles registration only. To read and write the interactable's\n * state, use {@link useInteractableState} with the returned id.\n *\n * @returns The interactable instance id.\n */\nexport const useAssistantInteractable = (\n name: string,\n config: AssistantInteractableProps,\n): string => {\n const aui = useAui();\n\n const autoId = useId().replace(/[^a-zA-Z0-9]/g, \"\");\n const id = config.id ?? autoId;\n\n const stateSchemaRef = useRef(config.stateSchema);\n stateSchemaRef.current = config.stateSchema;\n const normalizedStateSchema = useJSONSchemaDependency(config.stateSchema);\n const initialStateRef = useRef(config.initialState);\n initialStateRef.current = config.initialState;\n\n useEffect(() => {\n return aui.interactables.register({\n id,\n name,\n description: config.description,\n stateSchema: stateSchemaRef.current,\n initialState: initialStateRef.current,\n selected: config.selected,\n });\n }, [\n aui,\n id,\n name,\n config.description,\n normalizedStateSchema,\n config.selected,\n ]);\n\n return id;\n};\n"],"mappings":";;;;;;;;;;;;;;;;AA8BA,MAAaY,4BACXC,MACAC,WACW;CACX,MAAMC,MAAMZ,OAAO;CAEnB,MAAMa,SAASf,MAAM,CAAC,CAACgB,QAAQ,iBAAiB,EAAE;CAClD,MAAMP,KAAKI,OAAOJ,MAAMM;CAExB,MAAME,iBAAiBhB,OAAOY,OAAON,WAAW;CAChDU,eAAeC,UAAUL,OAAON;CAChC,MAAMY,wBAAwBhB,wBAAwBU,OAAON,WAAW;CACxE,MAAMa,kBAAkBnB,OAAOY,OAAOL,YAAY;CAClDY,gBAAgBF,UAAUL,OAAOL;CAEjCT,gBAAgB;EACd,OAAOe,IAAIO,cAAcC,SAAS;GAChCb;GACAG;GACAN,aAAaO,OAAOP;GACpBC,aAAaU,eAAeC;GAC5BV,cAAcY,gBAAgBF;GAC9BR,UAAUG,OAAOH;EACnB,CAAC;CACH,GAAG;EACDI;EACAL;EACAG;EACAC,OAAOP;EACPa;EACAN,OAAOH;CAAQ,CAChB;CAED,OAAOD;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"useInteractable.d.ts","names":[],"sources":["../../../src/react/model-context/useInteractable.ts"],"mappings":";;;;;;;;KAkBY,gCAAgC,WAAW;EACrD;IAAe;MAAU,cAAc;;;IAErC;;;;;;KAQQ,iCAAiC;;EAE3C,OAAO;;EAEP;;EAEA;;;;;;KAOU,4BACV,gBAAgB;EAEhB;EACA,aAAa;EACb,cAAc,gCAAgC;;EAE9C;;;;;;;;EAQA,eAAe;;;;;;;;;;;;;;;;;;;;cAkJJ,2BACX,gBAAgB,kCAEhB,cACA,QAAQ,4BAA4B,uBAEpC,gCAAgC;EAE9B;EACA,SACI,iCACE,gCAAgC;EAGtC,WACE,SACI,gCAAgC,aAE9B,MAAM,gCAAgC,aACnC,gCAAgC;EAE3C;EACA;EACA,aAAa"}
1
+ {"version":3,"file":"useInteractable.d.ts","names":[],"sources":["../../../src/react/model-context/useInteractable.ts"],"mappings":";;;;;;;;KAmBY,gCAAgC,WAAW;EACrD;IAAe;MAAU,cAAc;;;IAErC;;;;;;KAQQ,iCAAiC;;EAE3C,OAAO;;EAEP;;EAEA;;;;;;KAOU,4BACV,gBAAgB;EAEhB;EACA,aAAa;EACb,cAAc,gCAAgC;;EAE9C;;;;;;;;EAQA,eAAe;;;;;;;;;;;;;;;;;;;;cAoJJ,2BACX,gBAAgB,kCAEhB,cACA,QAAQ,4BAA4B,uBAEpC,gCAAgC;EAE9B;EACA,SACI,iCACE,gCAAgC;EAGtC,WACE,SACI,gCAAgC,aAE9B,MAAM,gCAAgC,aACnC,gCAAgC;EAE3C;EACA;EACA,aAAa"}
@@ -1,7 +1,8 @@
1
1
  "use client";
2
2
  import { interactableToolName, unstable_getInteractableVersions } from "../../model-context/interactable-composer-metadata.js";
3
- import { unstable_useInteractableState } from "./useInteractableState.js";
4
3
  import { useJSONEqual } from "../utils/useJSONEqual.js";
4
+ import { useJSONSchemaDependency } from "../utils/useJSONSchemaDependency.js";
5
+ import { unstable_useInteractableState } from "./useInteractableState.js";
5
6
  import { useEffect, useId, useMemo, useRef } from "@assistant-ui/tap/react-shim";
6
7
  import { useAui, useAuiState } from "@assistant-ui/store";
7
8
  //#region src/react/model-context/useInteractable.ts
@@ -26,6 +27,7 @@ const useInteractable = (name, config) => {
26
27
  const internalScope = part?.toolName === name || part?.toolName === updateToolName ? "thread" : void 0;
27
28
  const stateSchemaRef = useRef(config.stateSchema);
28
29
  stateSchemaRef.current = config.stateSchema;
30
+ const normalizedStateSchema = useJSONSchemaDependency(config.stateSchema);
29
31
  const initialStateRef = useRef(config.initialState);
30
32
  initialStateRef.current = config.initialState;
31
33
  const interactables = useAuiState(() => aui.unstable_interactables);
@@ -44,6 +46,7 @@ const useInteractable = (name, config) => {
44
46
  id,
45
47
  name,
46
48
  config.description,
49
+ normalizedStateSchema,
47
50
  internalScope,
48
51
  config.updateRender
49
52
  ]);
@@ -1 +1 @@
1
- {"version":3,"file":"useInteractable.js","names":["useEffect","useId","useMemo","useRef","useAui","useAuiState","Unstable_InteractableStateSchema","ToolCallMessagePartComponent","unstable_getInteractableVersions","getInteractableVersions","interactableToolName","unstable_useInteractableState","useInteractableState","useJSONEqual","Unstable_InferInteractableState","TSchema","types","output","TOutput","Unstable_InteractableVersionInfo","state","TState","isLatest","restore","Unstable_InteractableConfig","description","stateSchema","initialState","id","updateRender","useInteractable","name","config","version","setState","updater","prev","isPending","error","flush","Promise","aui","autoId","replace","updateToolName","part","s","p","optional","type","undefined","inferredId","toolName","result","Record","args","success","internalScope","stateSchemaRef","current","initialStateRef","interactables","unstable_interactables","register","scope","Parameters","myToolCallId","toolCallId","registeredState","methods","versionValue","versions","thread","messages","some","v","origin","mine","find","latestToolCallId","findLast","const","unstable_useInteractable"],"sources":["../../../src/react/model-context/useInteractable.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useId, useMemo, useRef } from \"react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport type { Unstable_InteractableStateSchema } from \"../types/scopes/interactables\";\nimport type { ToolCallMessagePartComponent } from \"../types/MessagePartComponentTypes\";\nimport {\n unstable_getInteractableVersions as getInteractableVersions,\n interactableToolName,\n} from \"../../model-context/interactable-composer-metadata\";\nimport { unstable_useInteractableState as useInteractableState } from \"./useInteractableState\";\nimport { useJSONEqual } from \"../utils/useJSONEqual\";\n\n/**\n * The state type described by an interactable's `stateSchema`. Resolves the\n * output type of a StandardSchemaV1 schema (e.g. Zod); plain JSON Schema\n * falls back to `unknown`.\n */\nexport type Unstable_InferInteractableState<TSchema> = TSchema extends {\n \"~standard\": { types?: { output: infer TOutput } | undefined };\n}\n ? TOutput\n : unknown;\n\n/**\n * One message's version of an interactable, for components rendered inside\n * tool-call parts. Show `state` to display history; call `restore()` to set\n * the live instance back to it.\n */\nexport type Unstable_InteractableVersionInfo<TState> = {\n /** The interactable's state as it was at this message. */\n state: TState;\n /** Whether this message holds the instance's most recent tool-driven version. */\n isLatest: boolean;\n /** Sets the live state back to this version. */\n restore: () => void;\n};\n\n/**\n * Unstable / Experimental — the interactables API is still evolving and may change in any release.\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport type Unstable_InteractableConfig<\n TSchema extends Unstable_InteractableStateSchema,\n> = {\n description: string;\n stateSchema: TSchema;\n initialState: Unstable_InferInteractableState<TSchema>;\n /** Unique instance ID; required to address this instance when multiple interactables share a name. Auto-generated if omitted. */\n id?: string | undefined;\n /**\n * Component installed as the tool UI for this interactable's `update_{name}`\n * tool calls, so a model edit re-renders the interactable at the message\n * that made it instead of only mutating an earlier one. Prefer\n * `unstable_interactableTool`, which wires this up. Pass a stable component reference;\n * changing identity re-registers the tool UI.\n */\n updateRender?: ToolCallMessagePartComponent | undefined;\n};\n\nconst useInteractable = <TSchema extends Unstable_InteractableStateSchema>(\n name: string,\n config: Unstable_InteractableConfig<TSchema>,\n): readonly [\n Unstable_InferInteractableState<TSchema>,\n {\n id: string;\n /**\n * This message's version of the instance, when rendered inside a\n * tool-created interactable message part; `undefined` elsewhere.\n */\n version:\n | Unstable_InteractableVersionInfo<\n Unstable_InferInteractableState<TSchema>\n >\n | undefined;\n setState: (\n updater:\n | Unstable_InferInteractableState<TSchema>\n | ((\n prev: Unstable_InferInteractableState<TSchema>,\n ) => Unstable_InferInteractableState<TSchema>),\n ) => void;\n isPending: boolean;\n error: unknown;\n flush: () => Promise<void>;\n },\n] => {\n const aui = useAui();\n\n const autoId = useId().replace(/[^a-zA-Z0-9]/g, \"\");\n\n const updateToolName = interactableToolName(name);\n const part = useAuiState((s) => {\n const p = s.optional.part;\n return p?.type === \"tool-call\" ? p : undefined;\n });\n\n // Inside an update_{name} part, the instance id comes from the call itself:\n // the result's resolved id (covers id-less calls), or the id argument.\n let inferredId: string | undefined;\n if (part?.toolName === updateToolName) {\n const result = part.result as Record<string, unknown> | undefined;\n const args = part.args as Record<string, unknown> | undefined;\n if (result?.success !== false) {\n if (typeof result?.id === \"string\") inferredId = result.id;\n else if (typeof args?.id === \"string\") inferredId = args.id;\n }\n }\n\n const id = config.id ?? inferredId ?? autoId;\n const internalScope =\n part?.toolName === name || part?.toolName === updateToolName\n ? \"thread\"\n : undefined;\n\n const stateSchemaRef = useRef(config.stateSchema);\n stateSchemaRef.current = config.stateSchema;\n const initialStateRef = useRef(config.initialState);\n initialStateRef.current = config.initialState;\n\n const interactables = useAuiState(() => aui.unstable_interactables);\n\n useEffect(() => {\n return interactables.register({\n id,\n name,\n description: config.description,\n stateSchema: stateSchemaRef.current,\n initialState: initialStateRef.current,\n updateRender: config.updateRender,\n ...(internalScope ? { scope: internalScope } : {}),\n } as Parameters<typeof interactables.register>[0] & {\n scope?: \"thread\" | undefined;\n });\n }, [\n interactables,\n id,\n name,\n config.description,\n internalScope,\n config.updateRender,\n ]);\n\n const myToolCallId = part?.toolCallId;\n\n const [registeredState, methods] =\n useInteractableState<Unstable_InferInteractableState<TSchema>>(id);\n const { setState } = methods;\n\n const versionValue = useAuiState(\n useJSONEqual((s) => {\n if (!internalScope || !myToolCallId) return undefined;\n const versions = getInteractableVersions(s.thread.messages, id, name);\n if (!versions.some((v) => v.origin === \"create\" && v.toolCallId === id)) {\n return undefined;\n }\n const mine = versions.find((v) => v.toolCallId === myToolCallId);\n if (!mine) return undefined;\n const latestToolCallId = versions.findLast(\n (v) => v.toolCallId !== undefined,\n )?.toolCallId;\n return { state: mine.state, isLatest: latestToolCallId === myToolCallId };\n }),\n );\n\n const version = useMemo(\n () =>\n versionValue && {\n state: versionValue.state as Unstable_InferInteractableState<TSchema>,\n isLatest: versionValue.isLatest,\n restore: () =>\n setState(\n versionValue.state as Unstable_InferInteractableState<TSchema>,\n ),\n },\n [versionValue, setState],\n );\n\n const state =\n registeredState === undefined ? config.initialState : registeredState;\n\n return [state, { id, version, ...methods }] as const;\n};\n\n/**\n * Registers an interactable with the AI assistant and returns its live state,\n * like `useState` that the model can also read and update.\n *\n * Call this once per place that shows the interactable. Other components can\n * read and write the same instance by passing its `id` to\n * `unstable_useInteractableState`.\n *\n * For tool-created interactables rendered inside tool-call message parts,\n * `version` carries this message's version of the instance — its state as of\n * that point in the conversation, whether it is the most recent tool-driven\n * version, and a `restore()` back to it. Whether older messages render frozen history or stay\n * live-editable is the component's choice. Inside an `update_{name}` part the\n * instance `id` is inferred from the call, so the same component works at the\n * creating call and at update calls.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport const unstable_useInteractable: <\n TSchema extends Unstable_InteractableStateSchema,\n>(\n name: string,\n config: Unstable_InteractableConfig<TSchema>,\n) => readonly [\n Unstable_InferInteractableState<TSchema>,\n {\n id: string;\n version:\n | Unstable_InteractableVersionInfo<\n Unstable_InferInteractableState<TSchema>\n >\n | undefined;\n setState: (\n updater:\n | Unstable_InferInteractableState<TSchema>\n | ((\n prev: Unstable_InferInteractableState<TSchema>,\n ) => Unstable_InferInteractableState<TSchema>),\n ) => void;\n isPending: boolean;\n error: unknown;\n flush: () => Promise<void>;\n },\n] = useInteractable;\n"],"mappings":";;;;;;;AA4DA,MAAM8B,mBACJC,MACAC,WAyBG;CACH,MAAMS,MAAMrC,OAAO;CAEnB,MAAMsC,SAASzC,MAAM,CAAC,CAAC0C,QAAQ,iBAAiB,EAAE;CAElD,MAAMC,iBAAiBlC,qBAAqBqB,IAAI;CAChD,MAAMc,OAAOxC,aAAayC,MAAM;EAC9B,MAAMC,IAAID,EAAEE,SAASH;EACrB,OAAOE,GAAGE,SAAS,cAAcF,IAAIG,KAAAA;CACvC,CAAC;CAID,IAAIC;CACJ,IAAIN,MAAMO,aAAaR,gBAAgB;EACrC,MAAMS,SAASR,KAAKQ;EACpB,MAAME,OAAOV,KAAKU;EAClB,IAAIF,QAAQG,YAAY,OAAO;GAC7B,IAAI,OAAOH,QAAQzB,OAAO,UAAUuB,aAAaE,OAAOzB;QACnD,IAAI,OAAO2B,MAAM3B,OAAO,UAAUuB,aAAaI,KAAK3B;EAC3D;CACF;CAEA,MAAMA,KAAKI,OAAOJ,MAAMuB,cAAcT;CACtC,MAAMe,gBACJZ,MAAMO,aAAarB,QAAQc,MAAMO,aAAaR,iBAC1C,WACAM,KAAAA;CAEN,MAAMQ,iBAAiBvD,OAAO6B,OAAON,WAAW;CAChDgC,eAAeC,UAAU3B,OAAON;CAChC,MAAMkC,kBAAkBzD,OAAO6B,OAAOL,YAAY;CAClDiC,gBAAgBD,UAAU3B,OAAOL;CAEjC,MAAMkC,gBAAgBxD,kBAAkBoC,IAAIqB,sBAAsB;CAElE9D,gBAAgB;EACd,OAAO6D,cAAcE,SAAS;GAC5BnC;GACAG;GACAN,aAAaO,OAAOP;GACpBC,aAAagC,eAAeC;GAC5BhC,cAAciC,gBAAgBD;GAC9B9B,cAAcG,OAAOH;GACrB,GAAI4B,gBAAgB,EAAEO,OAAOP,cAAc,IAAI,CAAC;EAClD,CAEC;CACH,GAAG;EACDI;EACAjC;EACAG;EACAC,OAAOP;EACPgC;EACAzB,OAAOH;CAAY,CACpB;CAED,MAAMqC,eAAerB,MAAMsB;CAE3B,MAAM,CAACC,iBAAiBC,WACtBzD,8BAA+DgB,EAAE;CACnE,MAAM,EAAEM,aAAamC;CAErB,MAAMC,eAAejE,YACnBQ,cAAciC,QAAM;EAClB,IAAI,CAACW,iBAAiB,CAACS,cAAc,OAAOhB,KAAAA;EAC5C,MAAMqB,WAAW9D,iCAAwBqC,IAAE0B,OAAOC,UAAU7C,IAAIG,IAAI;EACpE,IAAI,CAACwC,SAASG,MAAMC,MAAMA,EAAEC,WAAW,YAAYD,EAAER,eAAevC,EAAE,GACpE;EAEF,MAAMiD,OAAON,SAASO,MAAMH,QAAMA,IAAER,eAAeD,YAAY;EAC/D,IAAI,CAACW,MAAM,OAAO3B,KAAAA;EAClB,MAAM6B,mBAAmBR,SAASS,UAC/BL,QAAMA,IAAER,eAAejB,KAAAA,CAC1B,CAAC,EAAEiB;EACH,OAAO;GAAE/C,OAAOyD,KAAKzD;GAAOE,UAAUyD,qBAAqBb;EAAa;CAC1E,CAAC,CACH;CAEA,MAAMjC,UAAU/B,cAEZoE,gBAAgB;EACdlD,OAAOkD,aAAalD;EACpBE,UAAUgD,aAAahD;EACvBC,eACEW,SACEoC,aAAalD,KACf;CACJ,GACF,CAACkD,cAAcpC,QAAQ,CACzB;CAKA,OAAO,CAFLkC,oBAAoBlB,KAAAA,IAAYlB,OAAOL,eAAeyC,iBAEzC;EAAExC;EAAIK;EAAS,GAAGoC;CAAQ,CAAC;AAC5C;;;;;;;;;;;;;;;;;;;AAoBA,MAAaa,2BAyBTpD"}
1
+ {"version":3,"file":"useInteractable.js","names":["useEffect","useId","useMemo","useRef","useAui","useAuiState","Unstable_InteractableStateSchema","ToolCallMessagePartComponent","unstable_getInteractableVersions","getInteractableVersions","interactableToolName","unstable_useInteractableState","useInteractableState","useJSONEqual","useJSONSchemaDependency","Unstable_InferInteractableState","TSchema","types","output","TOutput","Unstable_InteractableVersionInfo","state","TState","isLatest","restore","Unstable_InteractableConfig","description","stateSchema","initialState","id","updateRender","useInteractable","name","config","version","setState","updater","prev","isPending","error","flush","Promise","aui","autoId","replace","updateToolName","part","s","p","optional","type","undefined","inferredId","toolName","result","Record","args","success","internalScope","stateSchemaRef","current","normalizedStateSchema","initialStateRef","interactables","unstable_interactables","register","scope","Parameters","myToolCallId","toolCallId","registeredState","methods","versionValue","versions","thread","messages","some","v","origin","mine","find","latestToolCallId","findLast","const","unstable_useInteractable"],"sources":["../../../src/react/model-context/useInteractable.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useId, useMemo, useRef } from \"react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport type { Unstable_InteractableStateSchema } from \"../types/scopes/interactables\";\nimport type { ToolCallMessagePartComponent } from \"../types/MessagePartComponentTypes\";\nimport {\n unstable_getInteractableVersions as getInteractableVersions,\n interactableToolName,\n} from \"../../model-context/interactable-composer-metadata\";\nimport { unstable_useInteractableState as useInteractableState } from \"./useInteractableState\";\nimport { useJSONEqual } from \"../utils/useJSONEqual\";\nimport { useJSONSchemaDependency } from \"../utils/useJSONSchemaDependency\";\n\n/**\n * The state type described by an interactable's `stateSchema`. Resolves the\n * output type of a StandardSchemaV1 schema (e.g. Zod); plain JSON Schema\n * falls back to `unknown`.\n */\nexport type Unstable_InferInteractableState<TSchema> = TSchema extends {\n \"~standard\": { types?: { output: infer TOutput } | undefined };\n}\n ? TOutput\n : unknown;\n\n/**\n * One message's version of an interactable, for components rendered inside\n * tool-call parts. Show `state` to display history; call `restore()` to set\n * the live instance back to it.\n */\nexport type Unstable_InteractableVersionInfo<TState> = {\n /** The interactable's state as it was at this message. */\n state: TState;\n /** Whether this message holds the instance's most recent tool-driven version. */\n isLatest: boolean;\n /** Sets the live state back to this version. */\n restore: () => void;\n};\n\n/**\n * Unstable / Experimental — the interactables API is still evolving and may change in any release.\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport type Unstable_InteractableConfig<\n TSchema extends Unstable_InteractableStateSchema,\n> = {\n description: string;\n stateSchema: TSchema;\n initialState: Unstable_InferInteractableState<TSchema>;\n /** Unique instance ID; required to address this instance when multiple interactables share a name. Auto-generated if omitted. */\n id?: string | undefined;\n /**\n * Component installed as the tool UI for this interactable's `update_{name}`\n * tool calls, so a model edit re-renders the interactable at the message\n * that made it instead of only mutating an earlier one. Prefer\n * `unstable_interactableTool`, which wires this up. Pass a stable component reference;\n * changing identity re-registers the tool UI.\n */\n updateRender?: ToolCallMessagePartComponent | undefined;\n};\n\nconst useInteractable = <TSchema extends Unstable_InteractableStateSchema>(\n name: string,\n config: Unstable_InteractableConfig<TSchema>,\n): readonly [\n Unstable_InferInteractableState<TSchema>,\n {\n id: string;\n /**\n * This message's version of the instance, when rendered inside a\n * tool-created interactable message part; `undefined` elsewhere.\n */\n version:\n | Unstable_InteractableVersionInfo<\n Unstable_InferInteractableState<TSchema>\n >\n | undefined;\n setState: (\n updater:\n | Unstable_InferInteractableState<TSchema>\n | ((\n prev: Unstable_InferInteractableState<TSchema>,\n ) => Unstable_InferInteractableState<TSchema>),\n ) => void;\n isPending: boolean;\n error: unknown;\n flush: () => Promise<void>;\n },\n] => {\n const aui = useAui();\n\n const autoId = useId().replace(/[^a-zA-Z0-9]/g, \"\");\n\n const updateToolName = interactableToolName(name);\n const part = useAuiState((s) => {\n const p = s.optional.part;\n return p?.type === \"tool-call\" ? p : undefined;\n });\n\n // Inside an update_{name} part, the instance id comes from the call itself:\n // the result's resolved id (covers id-less calls), or the id argument.\n let inferredId: string | undefined;\n if (part?.toolName === updateToolName) {\n const result = part.result as Record<string, unknown> | undefined;\n const args = part.args as Record<string, unknown> | undefined;\n if (result?.success !== false) {\n if (typeof result?.id === \"string\") inferredId = result.id;\n else if (typeof args?.id === \"string\") inferredId = args.id;\n }\n }\n\n const id = config.id ?? inferredId ?? autoId;\n const internalScope =\n part?.toolName === name || part?.toolName === updateToolName\n ? \"thread\"\n : undefined;\n\n const stateSchemaRef = useRef(config.stateSchema);\n stateSchemaRef.current = config.stateSchema;\n const normalizedStateSchema = useJSONSchemaDependency(config.stateSchema);\n const initialStateRef = useRef(config.initialState);\n initialStateRef.current = config.initialState;\n\n const interactables = useAuiState(() => aui.unstable_interactables);\n\n useEffect(() => {\n return interactables.register({\n id,\n name,\n description: config.description,\n stateSchema: stateSchemaRef.current,\n initialState: initialStateRef.current,\n updateRender: config.updateRender,\n ...(internalScope ? { scope: internalScope } : {}),\n } as Parameters<typeof interactables.register>[0] & {\n scope?: \"thread\" | undefined;\n });\n }, [\n interactables,\n id,\n name,\n config.description,\n normalizedStateSchema,\n internalScope,\n config.updateRender,\n ]);\n\n const myToolCallId = part?.toolCallId;\n\n const [registeredState, methods] =\n useInteractableState<Unstable_InferInteractableState<TSchema>>(id);\n const { setState } = methods;\n\n const versionValue = useAuiState(\n useJSONEqual((s) => {\n if (!internalScope || !myToolCallId) return undefined;\n const versions = getInteractableVersions(s.thread.messages, id, name);\n if (!versions.some((v) => v.origin === \"create\" && v.toolCallId === id)) {\n return undefined;\n }\n const mine = versions.find((v) => v.toolCallId === myToolCallId);\n if (!mine) return undefined;\n const latestToolCallId = versions.findLast(\n (v) => v.toolCallId !== undefined,\n )?.toolCallId;\n return { state: mine.state, isLatest: latestToolCallId === myToolCallId };\n }),\n );\n\n const version = useMemo(\n () =>\n versionValue && {\n state: versionValue.state as Unstable_InferInteractableState<TSchema>,\n isLatest: versionValue.isLatest,\n restore: () =>\n setState(\n versionValue.state as Unstable_InferInteractableState<TSchema>,\n ),\n },\n [versionValue, setState],\n );\n\n const state =\n registeredState === undefined ? config.initialState : registeredState;\n\n return [state, { id, version, ...methods }] as const;\n};\n\n/**\n * Registers an interactable with the AI assistant and returns its live state,\n * like `useState` that the model can also read and update.\n *\n * Call this once per place that shows the interactable. Other components can\n * read and write the same instance by passing its `id` to\n * `unstable_useInteractableState`.\n *\n * For tool-created interactables rendered inside tool-call message parts,\n * `version` carries this message's version of the instance — its state as of\n * that point in the conversation, whether it is the most recent tool-driven\n * version, and a `restore()` back to it. Whether older messages render frozen history or stay\n * live-editable is the component's choice. Inside an `update_{name}` part the\n * instance `id` is inferred from the call, so the same component works at the\n * creating call and at update calls.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport const unstable_useInteractable: <\n TSchema extends Unstable_InteractableStateSchema,\n>(\n name: string,\n config: Unstable_InteractableConfig<TSchema>,\n) => readonly [\n Unstable_InferInteractableState<TSchema>,\n {\n id: string;\n version:\n | Unstable_InteractableVersionInfo<\n Unstable_InferInteractableState<TSchema>\n >\n | undefined;\n setState: (\n updater:\n | Unstable_InferInteractableState<TSchema>\n | ((\n prev: Unstable_InferInteractableState<TSchema>,\n ) => Unstable_InferInteractableState<TSchema>),\n ) => void;\n isPending: boolean;\n error: unknown;\n flush: () => Promise<void>;\n },\n] = useInteractable;\n"],"mappings":";;;;;;;;AA6DA,MAAM+B,mBACJC,MACAC,WAyBG;CACH,MAAMS,MAAMtC,OAAO;CAEnB,MAAMuC,SAAS1C,MAAM,CAAC,CAAC2C,QAAQ,iBAAiB,EAAE;CAElD,MAAMC,iBAAiBnC,qBAAqBsB,IAAI;CAChD,MAAMc,OAAOzC,aAAa0C,MAAM;EAC9B,MAAMC,IAAID,EAAEE,SAASH;EACrB,OAAOE,GAAGE,SAAS,cAAcF,IAAIG,KAAAA;CACvC,CAAC;CAID,IAAIC;CACJ,IAAIN,MAAMO,aAAaR,gBAAgB;EACrC,MAAMS,SAASR,KAAKQ;EACpB,MAAME,OAAOV,KAAKU;EAClB,IAAIF,QAAQG,YAAY,OAAO;GAC7B,IAAI,OAAOH,QAAQzB,OAAO,UAAUuB,aAAaE,OAAOzB;QACnD,IAAI,OAAO2B,MAAM3B,OAAO,UAAUuB,aAAaI,KAAK3B;EAC3D;CACF;CAEA,MAAMA,KAAKI,OAAOJ,MAAMuB,cAAcT;CACtC,MAAMe,gBACJZ,MAAMO,aAAarB,QAAQc,MAAMO,aAAaR,iBAC1C,WACAM,KAAAA;CAEN,MAAMQ,iBAAiBxD,OAAO8B,OAAON,WAAW;CAChDgC,eAAeC,UAAU3B,OAAON;CAChC,MAAMkC,wBAAwB/C,wBAAwBmB,OAAON,WAAW;CACxE,MAAMmC,kBAAkB3D,OAAO8B,OAAOL,YAAY;CAClDkC,gBAAgBF,UAAU3B,OAAOL;CAEjC,MAAMmC,gBAAgB1D,kBAAkBqC,IAAIsB,sBAAsB;CAElEhE,gBAAgB;EACd,OAAO+D,cAAcE,SAAS;GAC5BpC;GACAG;GACAN,aAAaO,OAAOP;GACpBC,aAAagC,eAAeC;GAC5BhC,cAAckC,gBAAgBF;GAC9B9B,cAAcG,OAAOH;GACrB,GAAI4B,gBAAgB,EAAEQ,OAAOR,cAAc,IAAI,CAAC;EAClD,CAEC;CACH,GAAG;EACDK;EACAlC;EACAG;EACAC,OAAOP;EACPmC;EACAH;EACAzB,OAAOH;CAAY,CACpB;CAED,MAAMsC,eAAetB,MAAMuB;CAE3B,MAAM,CAACC,iBAAiBC,WACtB3D,8BAA+DiB,EAAE;CACnE,MAAM,EAAEM,aAAaoC;CAErB,MAAMC,eAAenE,YACnBQ,cAAckC,QAAM;EAClB,IAAI,CAACW,iBAAiB,CAACU,cAAc,OAAOjB,KAAAA;EAC5C,MAAMsB,WAAWhE,iCAAwBsC,IAAE2B,OAAOC,UAAU9C,IAAIG,IAAI;EACpE,IAAI,CAACyC,SAASG,MAAMC,MAAMA,EAAEC,WAAW,YAAYD,EAAER,eAAexC,EAAE,GACpE;EAEF,MAAMkD,OAAON,SAASO,MAAMH,QAAMA,IAAER,eAAeD,YAAY;EAC/D,IAAI,CAACW,MAAM,OAAO5B,KAAAA;EAClB,MAAM8B,mBAAmBR,SAASS,UAC/BL,QAAMA,IAAER,eAAelB,KAAAA,CAC1B,CAAC,EAAEkB;EACH,OAAO;GAAEhD,OAAO0D,KAAK1D;GAAOE,UAAU0D,qBAAqBb;EAAa;CAC1E,CAAC,CACH;CAEA,MAAMlC,UAAUhC,cAEZsE,gBAAgB;EACdnD,OAAOmD,aAAanD;EACpBE,UAAUiD,aAAajD;EACvBC,eACEW,SACEqC,aAAanD,KACf;CACJ,GACF,CAACmD,cAAcrC,QAAQ,CACzB;CAKA,OAAO,CAFLmC,oBAAoBnB,KAAAA,IAAYlB,OAAOL,eAAe0C,iBAEzC;EAAEzC;EAAIK;EAAS,GAAGqC;CAAQ,CAAC;AAC5C;;;;;;;;;;;;;;;;;;;AAoBA,MAAaa,2BAyBTrD"}
@@ -1,6 +1,6 @@
1
1
  import { unstable_getInteractableVersions } from "../../model-context/interactable-composer-metadata.js";
2
- import { unstable_useInteractableState } from "./useInteractableState.js";
3
2
  import { useJSONEqual } from "../utils/useJSONEqual.js";
3
+ import { unstable_useInteractableState } from "./useInteractableState.js";
4
4
  import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
5
5
  import "@assistant-ui/tap/react-shim";
6
6
  import { useAuiState } from "@assistant-ui/store";
@@ -5,6 +5,13 @@ import { GroupByContext } from "../../utils/groupParts.js";
5
5
  import { ReactNode } from "react";
6
6
  //#region src/react/primitives/message/MessageGroupedParts.d.ts
7
7
  declare namespace MessagePrimitiveGroupedParts {
8
+ /** Per status tallies over the group's `indices`; they sum to `indices.length`. */
9
+ type GroupCounts = {
10
+ readonly running: number;
11
+ readonly complete: number;
12
+ readonly incomplete: number;
13
+ readonly requiresAction: number;
14
+ };
8
15
  /**
9
16
  * A coalesced group of adjacent parts. Surfaced through the same
10
17
  * `{ part }` channel as a leaf {@link EnrichedPartState} so consumers
@@ -15,6 +22,8 @@ declare namespace MessagePrimitiveGroupedParts {
15
22
  type GroupPart<TKey extends `group-${string}` = `group-${string}`> = {
16
23
  readonly type: TKey;
17
24
  readonly status: MessagePartStatus | ToolCallMessagePartStatus;
25
+ /** Per status tallies over `indices`. */
26
+ readonly counts: GroupCounts;
18
27
  readonly indices: readonly number[];
19
28
  };
20
29
  /**
@@ -68,10 +77,10 @@ declare namespace MessagePrimitiveGroupedParts {
68
77
  * `switch (part.type)` can tell groups apart from real part types.
69
78
  *
70
79
  * **Prefer {@link groupPartByType}** for the common case of mapping by
71
- * `part.type` — it ships a stable memo fingerprint so the tree
80
+ * `part.type` or tool name — it ships a stable memo fingerprint so the tree
72
81
  * survives unrelated re-renders. Use an inline function only when
73
82
  * the helper isn't expressive enough (e.g. branching on
74
- * `part.toolName` or part metadata).
83
+ * `part.parentId` or part metadata).
75
84
  *
76
85
  * The second argument is a {@link GroupByContext} carrying the tool-UI
77
86
  * registry, for grouping that depends on it (e.g. standalone tool calls).
@@ -1 +1 @@
1
- {"version":3,"file":"MessageGroupedParts.d.ts","names":[],"sources":["../../../../src/react/primitives/message/MessageGroupedParts.tsx"],"mappings":";;;;;;kBAmBiB;;;;;;;;OAQH,UAAU;aACX,MAAM;aACN,QAAQ,oBAAoB;aAC5B;;;;;;;;;;;;OAaC;aACD;;;;;;;;;;;;;OAcC;OAEA,WAAW;;;;;;;aAOZ,MAAM,UAAU,QAAQ,oBAAoB;;;;;;;aAO5C,UAAU;;OAGT,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aA8BP,UACP,MAAM,WACN,SAAS,4BACG;;;;;;;;;aAUL,YAAY;;;;;;;;;;;;aAaZ,WAAW,MAAM,WAAW,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAmHtC;GAAgC,kCAA8B,SAAA,WAAA,YAIxE,6BAA6B,MAAM,QAAQ"}
1
+ {"version":3,"file":"MessageGroupedParts.d.ts","names":[],"sources":["../../../../src/react/primitives/message/MessageGroupedParts.tsx"],"mappings":";;;;;;kBAmBiB;;OAEH;aACD;aACA;aACA;aACA;;;;;;;;;OAUC,UAAU;aACX,MAAM;aACN,QAAQ,oBAAoB;;aAE5B,QAAQ;aACR;;;;;;;;;;;;OAaC;aACD;;;;;;;;;;;;;OAcC;OAEA,WAAW;;;;;;;aAOZ,MAAM,UAAU,QAAQ,oBAAoB;;;;;;;aAO5C,UAAU;;OAGT,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aA8BP,UACP,MAAM,WACN,SAAS,4BACG;;;;;;;;;aAUL,YAAY;;;;;;;;;;;;aAaZ,WAAW,MAAM,WAAW,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAoHtC;GAAgC,kCAA8B,SAAA,WAAA,YAIxE,6BAA6B,MAAM,QAAQ"}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { getGroupStatus } from "../../../utils/getGroupStatus.js";
2
+ import { getGroupSummary } from "../../../utils/getGroupStatus.js";
3
3
  import { MessagePartChildren } from "./MessageParts.js";
4
4
  import { GROUPBY_MEMO_KEY, buildGroupTree } from "../../utils/groupParts.js";
5
5
  import { Fragment, useMemo } from "@assistant-ui/tap/react-shim";
@@ -36,10 +36,11 @@ const renderNode = (node, parts, render) => {
36
36
  children: /* @__PURE__ */ jsx(PartChildrenSentinel, {})
37
37
  })
38
38
  }, node.idKey ? `part-${node.idKey}` : `part-${node.index}`);
39
- const status = getGroupStatus(parts, node.indices);
39
+ const { status, counts } = getGroupSummary(parts, node.indices);
40
40
  const groupPart = {
41
41
  type: node.key,
42
42
  status,
43
+ counts,
43
44
  indices: node.indices
44
45
  };
45
46
  return /* @__PURE__ */ jsx(Fragment, { children: render({
@@ -1 +1 @@
1
- {"version":3,"file":"MessageGroupedParts.js","names":["Fragment","FC","ReactNode","useMemo","useAuiState","useShallowSelector","PartState","MessagePartStatus","ToolCallMessagePartStatus","getGroupStatus","buildGroupTree","GROUPBY_MEMO_KEY","GroupByContext","GroupNode","MessagePartChildren","EnrichedPartState","MessagePrimitiveGroupedParts","GroupPart","type","TKey","status","indices","IndicatorPart","IndicatorMode","RenderInfo","part","children","Props","groupBy","context","indicator","info","shouldShowIndicator","mode","parts","isRunning","length","last","undefined","PartChildrenSentinel","Error","renderNode","node","render","idKey","index","groupPart","key","nodeKey","map","child","s","message","toolUIs","tools","memoKey","memoDep","tree","toolCallId","displayName"],"sources":["../../../../src/react/primitives/message/MessageGroupedParts.tsx"],"sourcesContent":["\"use client\";\n\nimport { Fragment, type FC, type ReactNode, useMemo } from \"react\";\nimport { useAuiState } from \"@assistant-ui/store\";\nimport { useShallowSelector } from \"@assistant-ui/store/internal\";\nimport type { PartState } from \"../../../store/scopes/part\";\nimport type {\n MessagePartStatus,\n ToolCallMessagePartStatus,\n} from \"../../../types/message\";\nimport { getGroupStatus } from \"../../../utils/getGroupStatus\";\nimport {\n buildGroupTree,\n GROUPBY_MEMO_KEY,\n type GroupByContext,\n type GroupNode,\n} from \"../../utils/groupParts\";\nimport { MessagePartChildren, type EnrichedPartState } from \"./MessageParts\";\n\nexport namespace MessagePrimitiveGroupedParts {\n /**\n * A coalesced group of adjacent parts. Surfaced through the same\n * `{ part }` channel as a leaf {@link EnrichedPartState} so consumers\n * dispatch on a single `switch (part.type)`. `type` is the group key\n * (always `\"group-…\"`); `status` is running when any contained part runs,\n * otherwise it mirrors the last contained part.\n */\n export type GroupPart<TKey extends `group-${string}` = `group-${string}`> = {\n readonly type: TKey;\n readonly status: MessagePartStatus | ToolCallMessagePartStatus;\n readonly indices: readonly number[];\n };\n\n /**\n * Synthetic trailing slot for a streaming/loading affordance (a\n * \"thinking…\" dot, etc.). Surfaced through the same `{ part }` channel\n * as groups and leaf parts so a single `switch (part.type)` renders it\n * via `case \"indicator\"`.\n *\n * It is only ever emitted while the message is running, so its presence\n * alone means \"render your loading UI here\" — there's no `status` to\n * branch on.\n */\n export type IndicatorPart = {\n readonly type: \"indicator\";\n };\n\n /**\n * When to emit the synthetic {@link IndicatorPart}. It is **only** emitted\n * while the message is running (streaming); the mode further restricts\n * which running states qualify:\n * - `\"never\"` — never.\n * - `\"empty\"` — only when the message has no parts yet.\n * - `\"no-text\"` (default) — when the message has no parts yet or the last\n * part isn't `text`/`reasoning` (e.g. it ended on a tool call, so the\n * assistant likely isn't done).\n * - `\"always\"` — whenever the message is running, regardless of parts.\n */\n export type IndicatorMode = \"never\" | \"empty\" | \"no-text\" | \"always\";\n\n export type RenderInfo<TKey extends `group-${string}` = `group-${string}`> = {\n /**\n * Either a coalesced group ({@link GroupPart}, identified by a\n * `group-…` `type`), a single enriched leaf part, or the synthetic\n * {@link IndicatorPart} (`type: \"indicator\"`). Use one switch over\n * `part.type` to handle all three.\n */\n readonly part: GroupPart<TKey> | EnrichedPartState | IndicatorPart;\n /**\n * For group nodes: the recursively-rendered subtree (subgroups +\n * leaf parts). For leaf parts: a sentinel that throws when rendered\n * — accidental fall-through (`default: return children;`) errors\n * loudly instead of silently rendering nothing.\n */\n readonly children: ReactNode;\n };\n\n export type Props<TKey extends `group-${string}` = `group-${string}`> = {\n /**\n * Maps each part to a group-key path. Adjacent parts that share a\n * prefix coalesce into the same group. Return `[]` (or `null`) to\n * leave a part ungrouped.\n *\n * Group keys must start with `\"group-\"` so the renderer's\n * `switch (part.type)` can tell groups apart from real part types.\n *\n * **Prefer {@link groupPartByType}** for the common case of mapping by\n * `part.type` — it ships a stable memo fingerprint so the tree\n * survives unrelated re-renders. Use an inline function only when\n * the helper isn't expressive enough (e.g. branching on\n * `part.toolName` or part metadata).\n *\n * The second argument is a {@link GroupByContext} carrying the tool-UI\n * registry, for grouping that depends on it (e.g. standalone tool calls).\n *\n * @example\n * ```tsx\n * import { groupPartByType } from \"@assistant-ui/react\";\n *\n * <MessagePrimitive.GroupedParts\n * groupBy={groupPartByType({\n * reasoning: [\"group-thought\", \"group-reasoning\"],\n * \"tool-call\": [\"group-thought\", \"group-tool\"],\n * })}\n * >\n * ```\n */\n readonly groupBy: (\n part: PartState,\n context: GroupByContext,\n ) => readonly TKey[] | null;\n\n /**\n * Controls emission of the synthetic {@link IndicatorPart} — a\n * trailing `{ part: { type: \"indicator\", status } }` render call you\n * handle with `case \"indicator\"` to show loading/status UI.\n *\n * @default \"no-text\"\n * @see IndicatorMode\n */\n readonly indicator?: IndicatorMode;\n\n /**\n * Render function called once per group node, once per leaf part, and\n * (when the `indicator` condition is met) once for the trailing\n * {@link IndicatorPart}. Switch on `part.type`: `\"group-…\"` cases wrap\n * `children`; real part types (`\"text\"`, `\"tool-call\"`, …) render the\n * part directly; `\"indicator\"` renders status/loading UI.\n *\n * Leaf parts receive the same {@link EnrichedPartState} that\n * `<MessagePrimitive.Parts>` would produce (`toolUI`, `addResult`,\n * `resume`, `respondToApproval`, `dataRendererUI`).\n */\n readonly children: (info: RenderInfo<TKey>) => ReactNode;\n };\n}\n\nconst shouldShowIndicator = (\n mode: MessagePrimitiveGroupedParts.IndicatorMode,\n parts: readonly PartState[],\n isRunning: boolean,\n): boolean => {\n // The indicator is a streaming affordance — never show it on a settled\n // message, whatever the mode.\n if (!isRunning) return false;\n\n switch (mode) {\n case \"never\":\n return false;\n case \"always\":\n return true;\n case \"empty\":\n return parts.length === 0;\n case \"no-text\": {\n const last = parts[parts.length - 1];\n return (\n last === undefined ||\n (last.type !== \"text\" && last.type !== \"reasoning\")\n );\n }\n }\n};\n\n/**\n * `children` placeholder passed for leaf-part renders. Leaf parts have no\n * inner subtree; rendering this sentinel signals the consumer wrote\n * `default: return children;` and accidentally fell through for a part —\n * surface the bug loudly instead of silently rendering nothing.\n */\nconst PartChildrenSentinel: FC = () => {\n throw new Error(\n \"MessagePrimitive.GroupedParts: rendered `children` under a leaf \" +\n \"part. `children` is only meaningful for `group-…` cases — add a \" +\n \"matching case for the part type or return `null` to skip it.\",\n );\n};\n\nconst renderNode = <TKey extends `group-${string}`>(\n node: GroupNode,\n parts: readonly PartState[],\n render: (info: MessagePrimitiveGroupedParts.RenderInfo<TKey>) => ReactNode,\n): ReactNode => {\n if (node.type === \"part\") {\n // Key by part identity when available, else absolute part index — never\n // the structural nodeKey, which leaves zombie fiber subscriptions when\n // parts reshape (#4051).\n return (\n <MessagePartChildren\n key={node.idKey ? `part-${node.idKey}` : `part-${node.index}`}\n index={node.index}\n >\n {({ part }) => render({ part, children: <PartChildrenSentinel /> })}\n </MessagePartChildren>\n );\n }\n\n const status = getGroupStatus(parts, node.indices);\n const groupPart: MessagePrimitiveGroupedParts.GroupPart<TKey> = {\n type: node.key as TKey,\n status,\n indices: node.indices,\n };\n\n return (\n <Fragment key={node.idKey ?? node.nodeKey}>\n {render({\n part: groupPart,\n children: (\n <>{node.children.map((child) => renderNode(child, parts, render))}</>\n ),\n })}\n </Fragment>\n );\n};\n\n/**\n * Groups adjacent message parts into a tree of coalesced runs and\n * renders each node — group or part — through a single `children`\n * function.\n *\n * The render function receives `{ part, children }` where `part.type`\n * is either a `\"group-…\"` literal (for a group, `children` is the\n * recursively-rendered subtree) or a real part type (`\"text\"`,\n * `\"tool-call\"`, …) for a leaf (`children` is a sentinel that throws\n * if rendered — use `part.type` to distinguish).\n *\n * @example\n * ```tsx\n * <MessagePrimitive.GroupedParts\n * groupBy={groupPartByType({\n * reasoning: [\"group-thought\", \"group-reasoning\"],\n * \"tool-call\": [\"group-thought\", \"group-tool\"],\n * })}\n * >\n * {({ part, children }) => {\n * switch (part.type) {\n * case \"group-thought\": return <Thought>{children}</Thought>;\n * case \"group-reasoning\": return <Reasoning>{children}</Reasoning>;\n * case \"group-tool\": return <ToolStack>{children}</ToolStack>;\n * case \"text\": return <MarkdownText />;\n * case \"tool-call\": return part.toolUI ?? <ToolFallback {...part} />;\n * case \"indicator\": return <LoadingDots />;\n * default: return null;\n * }\n * }}\n * </MessagePrimitive.GroupedParts>\n * ```\n */\nexport const MessagePrimitiveGroupedParts = <TKey extends `group-${string}`>({\n groupBy,\n indicator = \"no-text\",\n children,\n}: MessagePrimitiveGroupedParts.Props<TKey>): ReactNode => {\n const parts = useAuiState(useShallowSelector((s) => s.message.parts));\n // Handed to `groupBy` as its `context` argument (see GroupByContext).\n const toolUIs = useAuiState((s) => s.tools.toolUIs);\n // Subscribe to a boolean, not the status object: the tree only needs to\n // re-render when running-ness flips, and `\"never\"` opts out entirely.\n const isRunning = useAuiState((s) =>\n indicator === \"never\" ? false : s.message.status?.type === \"running\",\n );\n\n // Helpers like `groupPartByType` tag the function with `GROUPBY_MEMO_KEY`\n // (a stable string fingerprint of the helper config). When present,\n // memo on `[parts, memoKey]` so the tree survives unrelated renders.\n // For inline `groupBy`, fall back to recomputing each render — O(n)\n // and cheap.\n const memoKey = (groupBy as { [GROUPBY_MEMO_KEY]?: string })[\n GROUPBY_MEMO_KEY\n ];\n const memoDep = memoKey ?? groupBy;\n const tree = useMemo(() => {\n const context: GroupByContext = { toolUIs };\n return buildGroupTree(\n parts.map((part) => groupBy(part, context) ?? []),\n parts.map((part) =>\n part.type === \"tool-call\" ? part.toolCallId : undefined,\n ),\n );\n // oxlint-disable-next-line react/exhaustive-deps -- groupBy is captured via memoDep (either its identity or the helper's memoKey fingerprint); listing it directly would defeat the helper-tagged memo path\n }, [parts, memoDep, toolUIs]);\n\n return (\n <>\n {tree.map((node) => renderNode(node, parts, children))}\n {shouldShowIndicator(indicator, parts, isRunning) &&\n children({\n part: { type: \"indicator\" },\n children: <PartChildrenSentinel />,\n })}\n </>\n );\n};\n\nMessagePrimitiveGroupedParts.displayName = \"MessagePrimitive.GroupedParts\";\n"],"mappings":";;;;;;;;;AAyIA,MAAMgC,uBACJC,MACAC,OACAC,cACY;CAGZ,IAAI,CAACA,WAAW,OAAO;CAEvB,QAAQF,MAAR;EACE,KAAK,SACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,SACH,OAAOC,MAAME,WAAW;EAC1B,KAAK,WAAW;GACd,MAAMC,OAAOH,MAAMA,MAAME,SAAS;GAClC,OACEC,SAASC,KAAAA,KACRD,KAAKnB,SAAS,UAAUmB,KAAKnB,SAAS;EAE3C;CACF;AACF;;;;;;;AAQA,MAAMqB,6BAAiC;CACrC,MAAM,IAAIC,MACR,8LAGF;AACF;AAEA,MAAMC,cACJC,MACAR,OACAS,WACc;CACd,IAAID,KAAKxB,SAAS,QAIhB,OACE,oBAAC,qBAAD;EAEE,OAAOwB,KAAKG;EAEV,WAAA,EAAEpB,WAAWkB,OAAO;GAAElB;GAAMC,UAAU,oBAAC,sBAAD,CAAqB,CAAA;EAAI,CAAC;CAC/C,GAJdgB,KAAKE,QAAQ,QAAQF,KAAKE,UAAU,QAAQF,KAAKG,OAInC;CAIzB,MAAMzB,SAASX,eAAeyB,OAAOQ,KAAKrB,OAAO;CACjD,MAAMyB,YAA0D;EAC9D5B,MAAMwB,KAAKK;EACX3B;EACAC,SAASqB,KAAKrB;CAChB;CAEA,OACE,oBAAC,UAAD,EAAA,UACGsB,OAAO;EACNlB,MAAMqB;EACNpB,UACE,oBAAA,YAAA,EAAA,UAAGgB,KAAKhB,SAASuB,KAAKC,UAAUT,WAAWS,OAAOhB,OAAOS,MAAM,CAAC,EAAE,CAAA;CAEtE,CAAC,EACO,GAPKD,KAAKE,SAASF,KAAKM,OAOxB;AAEd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,MAAahC,gCAAgE,EAC3EY,SACAE,YAAY,WACZJ,eACyD;CACzD,MAAMQ,QAAQ9B,YAAYC,oBAAoB8C,MAAMA,EAAEC,QAAQlB,KAAK,CAAC;CAEpE,MAAMmB,UAAUjD,aAAa+C,QAAMA,IAAEG,MAAMD,OAAO;CAGlD,MAAMlB,YAAY/B,aAAa+C,QAC7BrB,cAAc,UAAU,QAAQqB,IAAEC,QAAQhC,QAAQF,SAAS,SAC7D;CAUA,MAAMsC,UAHW5B,QACfjB,qBAEyBiB;CAC3B,MAAM6B,OAAOtD,cAAc;EACzB,MAAM0B,UAA0B,EAAEwB,QAAQ;EAC1C,OAAO3C,eACLwB,MAAMe,KAAKxB,SAASG,QAAQH,MAAMI,OAAO,KAAK,CAAA,CAAE,GAChDK,MAAMe,KAAKxB,WACTA,OAAKP,SAAS,cAAcO,OAAKiC,aAAapB,KAAAA,CAChD,CACF;CAEF,GAAG;EAACJ;EAAOsB;EAASH;CAAO,CAAC;CAE5B,OACE,qBAAA,YAAA,EAAA,UAAA,CACGI,KAAKR,KAAKP,SAASD,WAAWC,MAAMR,OAAOR,QAAQ,CAAC,GACpDM,oBAAoBF,WAAWI,OAAOC,SAAS,KAC9CT,SAAS;EACPD,MAAM,EAAEP,MAAM,YAAY;EAC1BQ,UAAU,oBAAC,sBAAD,CAAqB,CAAA;CACjC,CAAC,CACL,EAAA,CAAA;AAEJ;AAEAV,6BAA6B2C,cAAc"}
1
+ {"version":3,"file":"MessageGroupedParts.js","names":["Fragment","FC","ReactNode","useMemo","useAuiState","useShallowSelector","PartState","MessagePartStatus","ToolCallMessagePartStatus","getGroupSummary","buildGroupTree","GROUPBY_MEMO_KEY","GroupByContext","GroupNode","MessagePartChildren","EnrichedPartState","MessagePrimitiveGroupedParts","GroupCounts","running","complete","incomplete","requiresAction","GroupPart","type","TKey","status","counts","indices","IndicatorPart","IndicatorMode","RenderInfo","part","children","Props","groupBy","context","indicator","info","shouldShowIndicator","mode","parts","isRunning","length","last","undefined","PartChildrenSentinel","Error","renderNode","node","render","idKey","index","groupPart","key","nodeKey","map","child","s","message","toolUIs","tools","memoKey","memoDep","tree","toolCallId","displayName"],"sources":["../../../../src/react/primitives/message/MessageGroupedParts.tsx"],"sourcesContent":["\"use client\";\n\nimport { Fragment, type FC, type ReactNode, useMemo } from \"react\";\nimport { useAuiState } from \"@assistant-ui/store\";\nimport { useShallowSelector } from \"@assistant-ui/store/internal\";\nimport type { PartState } from \"../../../store/scopes/part\";\nimport type {\n MessagePartStatus,\n ToolCallMessagePartStatus,\n} from \"../../../types/message\";\nimport { getGroupSummary } from \"../../../utils/getGroupStatus\";\nimport {\n buildGroupTree,\n GROUPBY_MEMO_KEY,\n type GroupByContext,\n type GroupNode,\n} from \"../../utils/groupParts\";\nimport { MessagePartChildren, type EnrichedPartState } from \"./MessageParts\";\n\nexport namespace MessagePrimitiveGroupedParts {\n /** Per status tallies over the group's `indices`; they sum to `indices.length`. */\n export type GroupCounts = {\n readonly running: number;\n readonly complete: number;\n readonly incomplete: number;\n readonly requiresAction: number;\n };\n\n /**\n * A coalesced group of adjacent parts. Surfaced through the same\n * `{ part }` channel as a leaf {@link EnrichedPartState} so consumers\n * dispatch on a single `switch (part.type)`. `type` is the group key\n * (always `\"group-…\"`); `status` is running when any contained part runs,\n * otherwise it mirrors the last contained part.\n */\n export type GroupPart<TKey extends `group-${string}` = `group-${string}`> = {\n readonly type: TKey;\n readonly status: MessagePartStatus | ToolCallMessagePartStatus;\n /** Per status tallies over `indices`. */\n readonly counts: GroupCounts;\n readonly indices: readonly number[];\n };\n\n /**\n * Synthetic trailing slot for a streaming/loading affordance (a\n * \"thinking…\" dot, etc.). Surfaced through the same `{ part }` channel\n * as groups and leaf parts so a single `switch (part.type)` renders it\n * via `case \"indicator\"`.\n *\n * It is only ever emitted while the message is running, so its presence\n * alone means \"render your loading UI here\" — there's no `status` to\n * branch on.\n */\n export type IndicatorPart = {\n readonly type: \"indicator\";\n };\n\n /**\n * When to emit the synthetic {@link IndicatorPart}. It is **only** emitted\n * while the message is running (streaming); the mode further restricts\n * which running states qualify:\n * - `\"never\"` — never.\n * - `\"empty\"` — only when the message has no parts yet.\n * - `\"no-text\"` (default) — when the message has no parts yet or the last\n * part isn't `text`/`reasoning` (e.g. it ended on a tool call, so the\n * assistant likely isn't done).\n * - `\"always\"` — whenever the message is running, regardless of parts.\n */\n export type IndicatorMode = \"never\" | \"empty\" | \"no-text\" | \"always\";\n\n export type RenderInfo<TKey extends `group-${string}` = `group-${string}`> = {\n /**\n * Either a coalesced group ({@link GroupPart}, identified by a\n * `group-…` `type`), a single enriched leaf part, or the synthetic\n * {@link IndicatorPart} (`type: \"indicator\"`). Use one switch over\n * `part.type` to handle all three.\n */\n readonly part: GroupPart<TKey> | EnrichedPartState | IndicatorPart;\n /**\n * For group nodes: the recursively-rendered subtree (subgroups +\n * leaf parts). For leaf parts: a sentinel that throws when rendered\n * — accidental fall-through (`default: return children;`) errors\n * loudly instead of silently rendering nothing.\n */\n readonly children: ReactNode;\n };\n\n export type Props<TKey extends `group-${string}` = `group-${string}`> = {\n /**\n * Maps each part to a group-key path. Adjacent parts that share a\n * prefix coalesce into the same group. Return `[]` (or `null`) to\n * leave a part ungrouped.\n *\n * Group keys must start with `\"group-\"` so the renderer's\n * `switch (part.type)` can tell groups apart from real part types.\n *\n * **Prefer {@link groupPartByType}** for the common case of mapping by\n * `part.type` or tool name — it ships a stable memo fingerprint so the tree\n * survives unrelated re-renders. Use an inline function only when\n * the helper isn't expressive enough (e.g. branching on\n * `part.parentId` or part metadata).\n *\n * The second argument is a {@link GroupByContext} carrying the tool-UI\n * registry, for grouping that depends on it (e.g. standalone tool calls).\n *\n * @example\n * ```tsx\n * import { groupPartByType } from \"@assistant-ui/react\";\n *\n * <MessagePrimitive.GroupedParts\n * groupBy={groupPartByType({\n * reasoning: [\"group-thought\", \"group-reasoning\"],\n * \"tool-call\": [\"group-thought\", \"group-tool\"],\n * })}\n * >\n * ```\n */\n readonly groupBy: (\n part: PartState,\n context: GroupByContext,\n ) => readonly TKey[] | null;\n\n /**\n * Controls emission of the synthetic {@link IndicatorPart} — a\n * trailing `{ part: { type: \"indicator\", status } }` render call you\n * handle with `case \"indicator\"` to show loading/status UI.\n *\n * @default \"no-text\"\n * @see IndicatorMode\n */\n readonly indicator?: IndicatorMode;\n\n /**\n * Render function called once per group node, once per leaf part, and\n * (when the `indicator` condition is met) once for the trailing\n * {@link IndicatorPart}. Switch on `part.type`: `\"group-…\"` cases wrap\n * `children`; real part types (`\"text\"`, `\"tool-call\"`, …) render the\n * part directly; `\"indicator\"` renders status/loading UI.\n *\n * Leaf parts receive the same {@link EnrichedPartState} that\n * `<MessagePrimitive.Parts>` would produce (`toolUI`, `addResult`,\n * `resume`, `respondToApproval`, `dataRendererUI`).\n */\n readonly children: (info: RenderInfo<TKey>) => ReactNode;\n };\n}\n\nconst shouldShowIndicator = (\n mode: MessagePrimitiveGroupedParts.IndicatorMode,\n parts: readonly PartState[],\n isRunning: boolean,\n): boolean => {\n // The indicator is a streaming affordance — never show it on a settled\n // message, whatever the mode.\n if (!isRunning) return false;\n\n switch (mode) {\n case \"never\":\n return false;\n case \"always\":\n return true;\n case \"empty\":\n return parts.length === 0;\n case \"no-text\": {\n const last = parts[parts.length - 1];\n return (\n last === undefined ||\n (last.type !== \"text\" && last.type !== \"reasoning\")\n );\n }\n }\n};\n\n/**\n * `children` placeholder passed for leaf-part renders. Leaf parts have no\n * inner subtree; rendering this sentinel signals the consumer wrote\n * `default: return children;` and accidentally fell through for a part —\n * surface the bug loudly instead of silently rendering nothing.\n */\nconst PartChildrenSentinel: FC = () => {\n throw new Error(\n \"MessagePrimitive.GroupedParts: rendered `children` under a leaf \" +\n \"part. `children` is only meaningful for `group-…` cases — add a \" +\n \"matching case for the part type or return `null` to skip it.\",\n );\n};\n\nconst renderNode = <TKey extends `group-${string}`>(\n node: GroupNode,\n parts: readonly PartState[],\n render: (info: MessagePrimitiveGroupedParts.RenderInfo<TKey>) => ReactNode,\n): ReactNode => {\n if (node.type === \"part\") {\n // Key by part identity when available, else absolute part index — never\n // the structural nodeKey, which leaves zombie fiber subscriptions when\n // parts reshape (#4051).\n return (\n <MessagePartChildren\n key={node.idKey ? `part-${node.idKey}` : `part-${node.index}`}\n index={node.index}\n >\n {({ part }) => render({ part, children: <PartChildrenSentinel /> })}\n </MessagePartChildren>\n );\n }\n\n const { status, counts } = getGroupSummary(parts, node.indices);\n const groupPart: MessagePrimitiveGroupedParts.GroupPart<TKey> = {\n type: node.key as TKey,\n status,\n counts,\n indices: node.indices,\n };\n\n return (\n <Fragment key={node.idKey ?? node.nodeKey}>\n {render({\n part: groupPart,\n children: (\n <>{node.children.map((child) => renderNode(child, parts, render))}</>\n ),\n })}\n </Fragment>\n );\n};\n\n/**\n * Groups adjacent message parts into a tree of coalesced runs and\n * renders each node — group or part — through a single `children`\n * function.\n *\n * The render function receives `{ part, children }` where `part.type`\n * is either a `\"group-…\"` literal (for a group, `children` is the\n * recursively-rendered subtree) or a real part type (`\"text\"`,\n * `\"tool-call\"`, …) for a leaf (`children` is a sentinel that throws\n * if rendered — use `part.type` to distinguish).\n *\n * @example\n * ```tsx\n * <MessagePrimitive.GroupedParts\n * groupBy={groupPartByType({\n * reasoning: [\"group-thought\", \"group-reasoning\"],\n * \"tool-call\": [\"group-thought\", \"group-tool\"],\n * })}\n * >\n * {({ part, children }) => {\n * switch (part.type) {\n * case \"group-thought\": return <Thought>{children}</Thought>;\n * case \"group-reasoning\": return <Reasoning>{children}</Reasoning>;\n * case \"group-tool\": return <ToolStack>{children}</ToolStack>;\n * case \"text\": return <MarkdownText />;\n * case \"tool-call\": return part.toolUI ?? <ToolFallback {...part} />;\n * case \"indicator\": return <LoadingDots />;\n * default: return null;\n * }\n * }}\n * </MessagePrimitive.GroupedParts>\n * ```\n */\nexport const MessagePrimitiveGroupedParts = <TKey extends `group-${string}`>({\n groupBy,\n indicator = \"no-text\",\n children,\n}: MessagePrimitiveGroupedParts.Props<TKey>): ReactNode => {\n const parts = useAuiState(useShallowSelector((s) => s.message.parts));\n // Handed to `groupBy` as its `context` argument (see GroupByContext).\n const toolUIs = useAuiState((s) => s.tools.toolUIs);\n // Subscribe to a boolean, not the status object: the tree only needs to\n // re-render when running-ness flips, and `\"never\"` opts out entirely.\n const isRunning = useAuiState((s) =>\n indicator === \"never\" ? false : s.message.status?.type === \"running\",\n );\n\n // Helpers like `groupPartByType` tag the function with `GROUPBY_MEMO_KEY`\n // (a stable string fingerprint of the helper config). When present,\n // memo on `[parts, memoKey]` so the tree survives unrelated renders.\n // For inline `groupBy`, fall back to recomputing each render — O(n)\n // and cheap.\n const memoKey = (groupBy as { [GROUPBY_MEMO_KEY]?: string })[\n GROUPBY_MEMO_KEY\n ];\n const memoDep = memoKey ?? groupBy;\n const tree = useMemo(() => {\n const context: GroupByContext = { toolUIs };\n return buildGroupTree(\n parts.map((part) => groupBy(part, context) ?? []),\n parts.map((part) =>\n part.type === \"tool-call\" ? part.toolCallId : undefined,\n ),\n );\n // oxlint-disable-next-line react/exhaustive-deps -- groupBy is captured via memoDep (either its identity or the helper's memoKey fingerprint); listing it directly would defeat the helper-tagged memo path\n }, [parts, memoDep, toolUIs]);\n\n return (\n <>\n {tree.map((node) => renderNode(node, parts, children))}\n {shouldShowIndicator(indicator, parts, isRunning) &&\n children({\n part: { type: \"indicator\" },\n children: <PartChildrenSentinel />,\n })}\n </>\n );\n};\n\nMessagePrimitiveGroupedParts.displayName = \"MessagePrimitive.GroupedParts\";\n"],"mappings":";;;;;;;;;AAmJA,MAAMsC,uBACJC,MACAC,OACAC,cACY;CAGZ,IAAI,CAACA,WAAW,OAAO;CAEvB,QAAQF,MAAR;EACE,KAAK,SACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,SACH,OAAOC,MAAME,WAAW;EAC1B,KAAK,WAAW;GACd,MAAMC,OAAOH,MAAMA,MAAME,SAAS;GAClC,OACEC,SAASC,KAAAA,KACRD,KAAKpB,SAAS,UAAUoB,KAAKpB,SAAS;EAE3C;CACF;AACF;;;;;;;AAQA,MAAMsB,6BAAiC;CACrC,MAAM,IAAIC,MACR,8LAGF;AACF;AAEA,MAAMC,cACJC,MACAR,OACAS,WACc;CACd,IAAID,KAAKzB,SAAS,QAIhB,OACE,oBAAC,qBAAD;EAEE,OAAOyB,KAAKG;EAEV,WAAA,EAAEpB,WAAWkB,OAAO;GAAElB;GAAMC,UAAU,oBAAC,sBAAD,CAAqB,CAAA;EAAI,CAAC;CAC/C,GAJdgB,KAAKE,QAAQ,QAAQF,KAAKE,UAAU,QAAQF,KAAKG,OAInC;CAIzB,MAAM,EAAE1B,QAAQC,WAAWjB,gBAAgB+B,OAAOQ,KAAKrB,OAAO;CAC9D,MAAMyB,YAA0D;EAC9D7B,MAAMyB,KAAKK;EACX5B;EACAC;EACAC,SAASqB,KAAKrB;CAChB;CAEA,OACE,oBAAC,UAAD,EAAA,UACGsB,OAAO;EACNlB,MAAMqB;EACNpB,UACE,oBAAA,YAAA,EAAA,UAAGgB,KAAKhB,SAASuB,KAAKC,UAAUT,WAAWS,OAAOhB,OAAOS,MAAM,CAAC,EAAE,CAAA;CAEtE,CAAC,EACO,GAPKD,KAAKE,SAASF,KAAKM,OAOxB;AAEd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,MAAatC,gCAAgE,EAC3EkB,SACAE,YAAY,WACZJ,eACyD;CACzD,MAAMQ,QAAQpC,YAAYC,oBAAoBoD,MAAMA,EAAEC,QAAQlB,KAAK,CAAC;CAEpE,MAAMmB,UAAUvD,aAAaqD,QAAMA,IAAEG,MAAMD,OAAO;CAGlD,MAAMlB,YAAYrC,aAAaqD,QAC7BrB,cAAc,UAAU,QAAQqB,IAAEC,QAAQjC,QAAQF,SAAS,SAC7D;CAUA,MAAMuC,UAHW5B,QACfvB,qBAEyBuB;CAC3B,MAAM6B,OAAO5D,cAAc;EACzB,MAAMgC,UAA0B,EAAEwB,QAAQ;EAC1C,OAAOjD,eACL8B,MAAMe,KAAKxB,SAASG,QAAQH,MAAMI,OAAO,KAAK,CAAA,CAAE,GAChDK,MAAMe,KAAKxB,WACTA,OAAKR,SAAS,cAAcQ,OAAKiC,aAAapB,KAAAA,CAChD,CACF;CAEF,GAAG;EAACJ;EAAOsB;EAASH;CAAO,CAAC;CAE5B,OACE,qBAAA,YAAA,EAAA,UAAA,CACGI,KAAKR,KAAKP,SAASD,WAAWC,MAAMR,OAAOR,QAAQ,CAAC,GACpDM,oBAAoBF,WAAWI,OAAOC,SAAS,KAC9CT,SAAS;EACPD,MAAM,EAAER,MAAM,YAAY;EAC1BS,UAAU,oBAAC,sBAAD,CAAqB,CAAA;CACjC,CAAC,CACL,EAAA,CAAA;AAEJ;AAEAhB,6BAA6BiD,cAAc"}
@@ -20,6 +20,7 @@ declare namespace PartPrimitiveMessages {
20
20
  * This primitive reads `messages` from the current tool call part in the PartScope
21
21
  * and renders them using a readonly thread context. All existing message and part
22
22
  * primitives work inside, and parent tool UI registrations are inherited.
23
+ * The nested thread reports `isRunning` while its trailing assistant message is running.
23
24
  *
24
25
  * @example
25
26
  * ```tsx
@@ -1 +1 @@
1
- {"version":3,"file":"PartMessages.d.ts","names":[],"sources":["../../../../src/react/primitives/part/PartMessages.tsx"],"mappings":";;;;kBASiB;OACH;IAEN,YAAY,YAAY,wBAAwB;IAChD;;;IAIA,WAAW;MAAS,SAAS;UAAoB;IACjD;;;;;;;;;;;;;;;;;;;;;;;;;;;cAsCK,2BAA2B,GAAG,sBAAsB;cAyBpD,uCAAqB,qBAAA,sBAAA"}
1
+ {"version":3,"file":"PartMessages.d.ts","names":[],"sources":["../../../../src/react/primitives/part/PartMessages.tsx"],"mappings":";;;;kBASiB;OACH;IAEN,YAAY,YAAY,wBAAwB;IAChD;;;IAIA,WAAW;MAAS,SAAS;UAAoB;IACjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAuCK,2BAA2B,GAAG,sBAAsB;cAyBpD,uCAAqB,qBAAA,sBAAA"}
@@ -14,6 +14,7 @@ const usePartMessages = () => {
14
14
  * This primitive reads `messages` from the current tool call part in the PartScope
15
15
  * and renders them using a readonly thread context. All existing message and part
16
16
  * primitives work inside, and parent tool UI registrations are inherited.
17
+ * The nested thread reports `isRunning` while its trailing assistant message is running.
17
18
  *
18
19
  * @example
19
20
  * ```tsx
@@ -1 +1 @@
1
- {"version":3,"file":"PartMessages.js","names":["FC","ReactNode","memo","useAuiState","ThreadMessage","ReadonlyThreadProvider","ThreadPrimitiveMessages","ThreadPrimitiveMessagesImpl","PartPrimitiveMessages","Props","components","NonNullable","children","value","message","usePartMessages","_temp","PartPrimitiveMessagesImpl","t0","$","_c","messages","length","t1","t2","displayName","s","part","type","undefined"],"sources":["../../../../src/react/primitives/part/PartMessages.tsx"],"sourcesContent":["import { type FC, type ReactNode, memo } from \"react\";\nimport { useAuiState } from \"@assistant-ui/store\";\nimport type { ThreadMessage } from \"../../../types/message\";\nimport { ReadonlyThreadProvider } from \"../../providers/ReadonlyThreadProvider\";\nimport {\n type ThreadPrimitiveMessages,\n ThreadPrimitiveMessagesImpl,\n} from \"../thread/ThreadMessages\";\n\nexport namespace PartPrimitiveMessages {\n export type Props =\n | {\n components: NonNullable<ThreadPrimitiveMessages.Props[\"components\"]>;\n children?: never;\n }\n | {\n /** Render function called for each message. Receives the message. */\n children: (value: { message: ThreadMessage }) => ReactNode;\n components?: never;\n };\n}\n\nconst usePartMessages = (): readonly ThreadMessage[] | undefined => {\n return useAuiState((s) => {\n const part = s.part;\n if (part.type !== \"tool-call\") return undefined;\n return \"messages\" in part\n ? (part.messages as readonly ThreadMessage[] | undefined)\n : undefined;\n });\n};\n\n/**\n * Renders the nested messages of a tool call part (e.g. sub-agent conversation).\n *\n * This primitive reads `messages` from the current tool call part in the PartScope\n * and renders them using a readonly thread context. All existing message and part\n * primitives work inside, and parent tool UI registrations are inherited.\n *\n * @example\n * ```tsx\n * const toolkit = defineToolkit({\n * invoke_sub_agent: {\n * type: \"backend\",\n * render: () => (\n * <PartPrimitive.Messages>\n * {({ message }) => {\n * if (message.role === \"user\") return <MyUserMessage />;\n * return <MyAssistantMessage />;\n * }}\n * </PartPrimitive.Messages>\n * ),\n * },\n * });\n * ```\n */\nexport const PartPrimitiveMessagesImpl: FC<PartPrimitiveMessages.Props> = ({\n components,\n children,\n}) => {\n const messages = usePartMessages();\n\n if (!messages?.length) return null;\n\n if (components) {\n return (\n <ReadonlyThreadProvider messages={messages}>\n <ThreadPrimitiveMessagesImpl components={components} />\n </ReadonlyThreadProvider>\n );\n }\n\n return (\n <ReadonlyThreadProvider messages={messages}>\n <ThreadPrimitiveMessagesImpl>{children}</ThreadPrimitiveMessagesImpl>\n </ReadonlyThreadProvider>\n );\n};\n\nPartPrimitiveMessagesImpl.displayName = \"PartPrimitive.Messages\";\n\nexport const PartPrimitiveMessages = memo(PartPrimitiveMessagesImpl);\n"],"mappings":";;;;;;;AAsBA,MAAMe,wBAAkB;CAAA,OACfZ,YAAYa,KAMlB;AAAC;;;;;;;;;;;;;;;;;;;;;;;;;AA2BJ,MAAaC,6BAA6DC,OAAA;CAAA,MAAAC,IAAAC,EAAA,EAAA;CAAC,MAAA,EAAAV,YAAAE,aAAAM;CAIzE,MAAAG,WAAiBN,gBAAgB;CAEjC,IAAI,CAACM,UAAQC,QAAQ,OAAS;CAE9B,IAAIZ,YAAU;EAAA,IAAAa;EAAA,IAAAJ,EAAA,OAAAT,YAAA;GAGRa,KAAA,oBAAC,6BAAD,EAAyCb,WAAU,CAAA;GAAIS,EAAA,KAAAT;GAAAS,EAAA,KAAAI;EAAA,OAAAA,KAAAJ,EAAA;EAAA,IAAAK;EAAA,IAAAL,EAAA,OAAAE,YAAAF,EAAA,OAAAI,IAAA;GADzDC,KAAA,oBAAC,wBAAD;IAAkCH;IAChCE,UAAAA;GADqB,CAAA;GAEEJ,EAAA,KAAAE;GAAAF,EAAA,KAAAI;GAAAJ,EAAA,KAAAK;EAAA,OAAAA,KAAAL,EAAA;EAAA,OAFzBK;CAEyB;CAE5B,IAAAD;CAAA,IAAAJ,EAAA,OAAAP,UAAA;EAIGW,KAAA,oBAAC,6BAAD,EAA8BX,SAAF,CAAA;EAAyCO,EAAA,KAAAP;EAAAO,EAAA,KAAAI;CAAA,OAAAA,KAAAJ,EAAA;CAAA,IAAAK;CAAA,IAAAL,EAAA,OAAAE,YAAAF,EAAA,OAAAI,IAAA;EADvEC,KAAA,oBAAC,wBAAD;GAAkCH;GAChCE,UAAAA;EADqB,CAAA;EAEEJ,EAAA,KAAAE;EAAAF,EAAA,KAAAI;EAAAJ,EAAA,KAAAK;CAAA,OAAAA,KAAAL,EAAA;CAAA,OAFzBK;AAEyB;AAI7BP,0BAA0BQ,cAAc;AAExC,MAAajB,wBAAwBN,KAAKe,yBAAyB;AA3D3C,SAAAD,MAAAU,GAAA;CAEpB,MAAAC,OAAaD,EAACC;CACd,IAAIA,KAAIC,SAAU,aAAW;CAAmB,OACzC,cAAcD,OAChBA,KAAIN,WADFQ,KAAAA;AAEM"}
1
+ {"version":3,"file":"PartMessages.js","names":["FC","ReactNode","memo","useAuiState","ThreadMessage","ReadonlyThreadProvider","ThreadPrimitiveMessages","ThreadPrimitiveMessagesImpl","PartPrimitiveMessages","Props","components","NonNullable","children","value","message","usePartMessages","_temp","PartPrimitiveMessagesImpl","t0","$","_c","messages","length","t1","t2","displayName","s","part","type","undefined"],"sources":["../../../../src/react/primitives/part/PartMessages.tsx"],"sourcesContent":["import { type FC, type ReactNode, memo } from \"react\";\nimport { useAuiState } from \"@assistant-ui/store\";\nimport type { ThreadMessage } from \"../../../types/message\";\nimport { ReadonlyThreadProvider } from \"../../providers/ReadonlyThreadProvider\";\nimport {\n type ThreadPrimitiveMessages,\n ThreadPrimitiveMessagesImpl,\n} from \"../thread/ThreadMessages\";\n\nexport namespace PartPrimitiveMessages {\n export type Props =\n | {\n components: NonNullable<ThreadPrimitiveMessages.Props[\"components\"]>;\n children?: never;\n }\n | {\n /** Render function called for each message. Receives the message. */\n children: (value: { message: ThreadMessage }) => ReactNode;\n components?: never;\n };\n}\n\nconst usePartMessages = (): readonly ThreadMessage[] | undefined => {\n return useAuiState((s) => {\n const part = s.part;\n if (part.type !== \"tool-call\") return undefined;\n return \"messages\" in part\n ? (part.messages as readonly ThreadMessage[] | undefined)\n : undefined;\n });\n};\n\n/**\n * Renders the nested messages of a tool call part (e.g. sub-agent conversation).\n *\n * This primitive reads `messages` from the current tool call part in the PartScope\n * and renders them using a readonly thread context. All existing message and part\n * primitives work inside, and parent tool UI registrations are inherited.\n * The nested thread reports `isRunning` while its trailing assistant message is running.\n *\n * @example\n * ```tsx\n * const toolkit = defineToolkit({\n * invoke_sub_agent: {\n * type: \"backend\",\n * render: () => (\n * <PartPrimitive.Messages>\n * {({ message }) => {\n * if (message.role === \"user\") return <MyUserMessage />;\n * return <MyAssistantMessage />;\n * }}\n * </PartPrimitive.Messages>\n * ),\n * },\n * });\n * ```\n */\nexport const PartPrimitiveMessagesImpl: FC<PartPrimitiveMessages.Props> = ({\n components,\n children,\n}) => {\n const messages = usePartMessages();\n\n if (!messages?.length) return null;\n\n if (components) {\n return (\n <ReadonlyThreadProvider messages={messages}>\n <ThreadPrimitiveMessagesImpl components={components} />\n </ReadonlyThreadProvider>\n );\n }\n\n return (\n <ReadonlyThreadProvider messages={messages}>\n <ThreadPrimitiveMessagesImpl>{children}</ThreadPrimitiveMessagesImpl>\n </ReadonlyThreadProvider>\n );\n};\n\nPartPrimitiveMessagesImpl.displayName = \"PartPrimitive.Messages\";\n\nexport const PartPrimitiveMessages = memo(PartPrimitiveMessagesImpl);\n"],"mappings":";;;;;;;AAsBA,MAAMe,wBAAkB;CAAA,OACfZ,YAAYa,KAMlB;AAAC;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BJ,MAAaC,6BAA6DC,OAAA;CAAA,MAAAC,IAAAC,EAAA,EAAA;CAAC,MAAA,EAAAV,YAAAE,aAAAM;CAIzE,MAAAG,WAAiBN,gBAAgB;CAEjC,IAAI,CAACM,UAAQC,QAAQ,OAAS;CAE9B,IAAIZ,YAAU;EAAA,IAAAa;EAAA,IAAAJ,EAAA,OAAAT,YAAA;GAGRa,KAAA,oBAAC,6BAAD,EAAyCb,WAAU,CAAA;GAAIS,EAAA,KAAAT;GAAAS,EAAA,KAAAI;EAAA,OAAAA,KAAAJ,EAAA;EAAA,IAAAK;EAAA,IAAAL,EAAA,OAAAE,YAAAF,EAAA,OAAAI,IAAA;GADzDC,KAAA,oBAAC,wBAAD;IAAkCH;IAChCE,UAAAA;GADqB,CAAA;GAEEJ,EAAA,KAAAE;GAAAF,EAAA,KAAAI;GAAAJ,EAAA,KAAAK;EAAA,OAAAA,KAAAL,EAAA;EAAA,OAFzBK;CAEyB;CAE5B,IAAAD;CAAA,IAAAJ,EAAA,OAAAP,UAAA;EAIGW,KAAA,oBAAC,6BAAD,EAA8BX,SAAF,CAAA;EAAyCO,EAAA,KAAAP;EAAAO,EAAA,KAAAI;CAAA,OAAAA,KAAAJ,EAAA;CAAA,IAAAK;CAAA,IAAAL,EAAA,OAAAE,YAAAF,EAAA,OAAAI,IAAA;EADvEC,KAAA,oBAAC,wBAAD;GAAkCH;GAChCE,UAAAA;EADqB,CAAA;EAEEJ,EAAA,KAAAE;EAAAF,EAAA,KAAAI;EAAAJ,EAAA,KAAAK;CAAA,OAAAA,KAAAL,EAAA;CAAA,OAFzBK;AAEyB;AAI7BP,0BAA0BQ,cAAc;AAExC,MAAajB,wBAAwBN,KAAKe,yBAAyB;AA5D3C,SAAAD,MAAAU,GAAA;CAEpB,MAAAC,OAAaD,EAACC;CACd,IAAIA,KAAIC,SAAU,aAAW;CAAmB,OACzC,cAAcD,OAChBA,KAAIN,WADFQ,KAAAA;AAEM"}
@@ -1 +1 @@
1
- {"version":3,"file":"ThreadMessages.d.ts","names":[],"sources":["../../../../src/react/primitives/thread/ThreadMessages.tsx"],"mappings":";;;;KAYK;;EAGC,SAAS;;EAET,eAAe;;EAEf,mBAAmB;;EAEnB,wBAAwB;;EAExB,qBAAqB;;EAErB,cAAc;;EAEd,mBAAmB;;EAEnB,gBAAgB;;;EAIhB,UAAU;;EAEV,eAAe;;EAEf,mBAAmB;;EAEnB,wBAAwB;;EAExB,qBAAqB;;EAErB,aAAa;;EAEb,kBAAkB;;EAElB,gBAAgB;;kBAGL;OACH;;IAGN,YAAY;IACZ;;;IAIA,WAAW;MAAS,SAAS;UAAmB;IAChD;;;kBAsGS;OACH;IACV;IACA,YAAY;;;;;;cAOH,+BAA+B,GAAG,8BAA8B;kBAgB5D;OACH;IACV;IACA,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;cA2BH,qCAAqC,GAAG,oCAAoC;;;;;;;;;;;;;;cA4D5E,6BAA6B,GAAG,wBAAwB;cAkBxD,yCAAuB,qBAAA,wBAAA"}
1
+ {"version":3,"file":"ThreadMessages.d.ts","names":[],"sources":["../../../../src/react/primitives/thread/ThreadMessages.tsx"],"mappings":";;;;KAaK;;EAGC,SAAS;;EAET,eAAe;;EAEf,mBAAmB;;EAEnB,wBAAwB;;EAExB,qBAAqB;;EAErB,cAAc;;EAEd,mBAAmB;;EAEnB,gBAAgB;;;EAIhB,UAAU;;EAEV,eAAe;;EAEf,mBAAmB;;EAEnB,wBAAwB;;EAExB,qBAAqB;;EAErB,aAAa;;EAEb,kBAAkB;;EAElB,gBAAgB;;kBAGL;OACH;;IAGN,YAAY;IACZ;;;IAIA,WAAW;MAAS,SAAS;UAAmB;IAChD;;;kBAsGS;OACH;IACV;IACA,YAAY;;;;;;cAOH,+BAA+B,GAAG,8BAA8B;kBAgB5D;OACH;IACV;IACA,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;cA2BH,qCAAqC,GAAG,oCAAoC;;;;;;;;;;;;;;cA8D5E,6BAA6B,GAAG,wBAAwB;cAkBxD,yCAAuB,qBAAA,wBAAA"}
@@ -3,6 +3,7 @@ import { MessageByIdProvider } from "../../providers/MessageByIdProvider.js";
3
3
  import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
4
4
  import { memo, useMemo } from "@assistant-ui/tap/react-shim";
5
5
  import { RenderChildrenWithAccessor, useAuiState } from "@assistant-ui/store";
6
+ import { useShallowSelector } from "@assistant-ui/store/internal";
6
7
  import { jsx } from "react/jsx-runtime";
7
8
  //#region src/react/primitives/thread/ThreadMessages.tsx
8
9
  const isComponentsSame = (prev, next) => {
@@ -129,10 +130,10 @@ const ThreadPrimitiveUnstable_MessageById = memo((t0) => {
129
130
  }, (prev, next) => prev.messageId === next.messageId && isComponentsSame(prev.components, next.components));
130
131
  ThreadPrimitiveUnstable_MessageById.displayName = "ThreadPrimitive.Unstable_MessageById";
131
132
  const ThreadPrimitiveMessagesInner = ({ children }) => {
132
- const messagesLength = useAuiState((s) => s.thread.messages.length);
133
+ const messageIds = useAuiState(useShallowSelector((s) => s.thread.messages.map((message) => message.id)));
133
134
  return useMemo(() => {
134
- if (messagesLength === 0) return null;
135
- return Array.from({ length: messagesLength }, (_, index) => /* @__PURE__ */ jsx(MessageByIndexProvider, {
135
+ if (messageIds.length === 0) return null;
136
+ return messageIds.map((messageId, index) => /* @__PURE__ */ jsx(MessageByIndexProvider, {
136
137
  index,
137
138
  children: /* @__PURE__ */ jsx(RenderChildrenWithAccessor, {
138
139
  getItemState: (aui) => aui.thread.message({ index }).getState(),
@@ -140,8 +141,8 @@ const ThreadPrimitiveMessagesInner = ({ children }) => {
140
141
  return getItem();
141
142
  } })
142
143
  })
143
- }, index));
144
- }, [messagesLength, children]);
144
+ }, messageId));
145
+ }, [messageIds, children]);
145
146
  };
146
147
  /**
147
148
  * Renders all messages in the current thread.