@assistant-ui/core 0.3.14 → 0.3.15

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 (137) hide show
  1. package/dist/adapters/voice.js +11 -0
  2. package/dist/adapters/voice.js.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/internal.d.ts +2 -1
  5. package/dist/internal.js +2 -1
  6. package/dist/model-context/frame/host.d.ts +1 -1
  7. package/dist/model-context/frame/host.d.ts.map +1 -1
  8. package/dist/model-context/frame/host.js +17 -3
  9. package/dist/model-context/frame/host.js.map +1 -1
  10. package/dist/model-context/frame/provider.d.ts +4 -0
  11. package/dist/model-context/frame/provider.d.ts.map +1 -1
  12. package/dist/model-context/frame/provider.js +50 -3
  13. package/dist/model-context/frame/provider.js.map +1 -1
  14. package/dist/model-context/frame/types.d.ts +4 -1
  15. package/dist/model-context/frame/types.d.ts.map +1 -1
  16. package/dist/model-context/frame/types.js.map +1 -1
  17. package/dist/react/client/RemoteThreadList.d.ts +1 -1
  18. package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
  19. package/dist/react/client/RemoteThreadList.js +95 -23
  20. package/dist/react/client/RemoteThreadList.js.map +1 -1
  21. package/dist/react/primitive-hooks/useActionBarCopy.js +7 -1
  22. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  23. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts +3 -0
  24. package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts.map +1 -1
  25. package/dist/react/primitive-hooks/useThreadIsEmpty.js +3 -0
  26. package/dist/react/primitive-hooks/useThreadIsEmpty.js.map +1 -1
  27. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts +3 -0
  28. package/dist/react/primitive-hooks/useThreadIsRunning.d.ts.map +1 -1
  29. package/dist/react/primitive-hooks/useThreadIsRunning.js +3 -0
  30. package/dist/react/primitive-hooks/useThreadIsRunning.js.map +1 -1
  31. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +2 -0
  32. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  33. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +6 -0
  34. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  35. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +6 -0
  36. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  37. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +192 -50
  38. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  39. package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
  40. package/dist/react/runtimes/RemoteThreadResource.js +2 -0
  41. package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
  42. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -1
  43. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js +1 -1
  44. package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
  45. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
  46. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +38 -5
  47. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  48. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  49. package/dist/runtime/utils/message-repository.js +27 -18
  50. package/dist/runtime/utils/message-repository.js.map +1 -1
  51. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  52. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +2 -0
  53. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  54. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts +102 -0
  55. package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts.map +1 -0
  56. package/dist/runtimes/inert/InertThreadRuntimeCore.js +156 -0
  57. package/dist/runtimes/inert/InertThreadRuntimeCore.js.map +1 -0
  58. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  59. package/dist/runtimes/local/local-thread-runtime-core.js +25 -6
  60. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  61. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +12 -60
  62. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  63. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +10 -145
  64. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
  65. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts +9 -0
  66. package/dist/runtimes/remote-thread-list/adapter-changed.d.ts.map +1 -0
  67. package/dist/runtimes/remote-thread-list/adapter-changed.js +13 -0
  68. package/dist/runtimes/remote-thread-list/adapter-changed.js.map +1 -0
  69. package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts.map +1 -1
  70. package/dist/runtimes/remote-thread-list/empty-thread-core.js +16 -155
  71. package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
  72. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +2 -0
  73. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
  74. package/dist/runtimes/remote-thread-list/optimistic-state.js +11 -0
  75. package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
  76. package/dist/runtimes/remote-thread-list/types.d.ts +3 -0
  77. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  78. package/dist/store/clients/external-thread.js +1 -1
  79. package/dist/store/clients/external-thread.js.map +1 -1
  80. package/dist/store/runtime-clients/handle-runtime-action.d.ts.map +1 -1
  81. package/dist/store/runtime-clients/handle-runtime-action.js +2 -0
  82. package/dist/store/runtime-clients/handle-runtime-action.js.map +1 -1
  83. package/dist/types/message.d.ts +1 -1
  84. package/dist/types/message.js.map +1 -1
  85. package/dist/utils/silent-runtime-action.d.ts +6 -0
  86. package/dist/utils/silent-runtime-action.d.ts.map +1 -0
  87. package/dist/utils/silent-runtime-action.js +7 -0
  88. package/dist/utils/silent-runtime-action.js.map +1 -0
  89. package/package.json +4 -4
  90. package/src/adapters/voice.test.ts +66 -1
  91. package/src/adapters/voice.ts +8 -0
  92. package/src/internal.ts +1 -0
  93. package/src/model-context/frame/host.test.ts +64 -5
  94. package/src/model-context/frame/host.ts +16 -3
  95. package/src/model-context/frame/provider.test.ts +347 -20
  96. package/src/model-context/frame/provider.ts +58 -2
  97. package/src/model-context/frame/types.ts +5 -0
  98. package/src/react/client/RemoteThreadList.test.ts +196 -0
  99. package/src/react/client/RemoteThreadList.ts +93 -24
  100. package/src/react/primitive-hooks/useActionBarCopy.test.ts +15 -0
  101. package/src/react/primitive-hooks/useActionBarCopy.ts +13 -3
  102. package/src/react/primitive-hooks/useThreadIsEmpty.ts +3 -0
  103. package/src/react/primitive-hooks/useThreadIsRunning.ts +3 -0
  104. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +12 -0
  105. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.republish.test.ts +87 -0
  106. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +268 -63
  107. package/src/react/runtimes/RemoteThreadResource.ts +2 -0
  108. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.test.tsx +58 -0
  109. package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.ts +3 -1
  110. package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +98 -3
  111. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +68 -6
  112. package/src/react/runtimes/useLocalRuntime.test.tsx +5 -5
  113. package/src/runtime/utils/message-repository.ts +26 -18
  114. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +4 -0
  115. package/src/runtimes/inert/InertThreadRuntimeCore.test.ts +253 -0
  116. package/src/runtimes/inert/InertThreadRuntimeCore.ts +232 -0
  117. package/src/runtimes/local/local-thread-runtime-core.test.ts +319 -0
  118. package/src/runtimes/local/local-thread-runtime-core.ts +38 -8
  119. package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +17 -209
  120. package/src/runtimes/remote-thread-list/adapter-changed.ts +10 -0
  121. package/src/runtimes/remote-thread-list/empty-thread-core.ts +28 -221
  122. package/src/runtimes/remote-thread-list/optimistic-state.test.ts +18 -0
  123. package/src/runtimes/remote-thread-list/optimistic-state.ts +13 -0
  124. package/src/runtimes/remote-thread-list/types.ts +4 -0
  125. package/src/store/clients/external-thread.ts +1 -1
  126. package/src/store/runtime-clients/handle-runtime-action.test.ts +40 -0
  127. package/src/store/runtime-clients/handle-runtime-action.ts +3 -0
  128. package/src/tests/MessageRepository.test.ts +48 -0
  129. package/src/tests/RemoteThreadListThreadListRuntimeCore-errors.test.ts +2 -2
  130. package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +8 -6
  131. package/src/tests/empty-thread-core.test.ts +6 -0
  132. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +20 -0
  133. package/src/tests/external-thread-isEmpty.test.tsx +100 -0
  134. package/src/tests/remote-thread-list-adapter-switch.test.ts +383 -0
  135. package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +67 -0
  136. package/src/types/message.ts +1 -1
  137. package/src/utils/silent-runtime-action.ts +6 -0
@@ -1 +1 @@
1
- {"version":3,"file":"useCloudThreadListAdapter.js","names":["process","env","Record","FC","PropsWithChildren","RefObject","useCallback","useEffect","useMemo","useRef","useState","AssistantCloud","RemoteThreadListAdapter","InMemoryThreadListAdapter","useAssistantCloudThreadHistoryAdapter","RuntimeAdapterProvider","RuntimeAdapters","CloudFileAttachmentAdapter","isRecord","ThreadData","externalId","CloudThreadListAdapterOptions","cloud","create","Promise","delete","threadId","toCustom","value","undefined","baseUrl","NEXT_PUBLIC_ASSISTANT_BASE_URL","autoCloud","anonymous","CLOUD_THREAD_PAGE_SIZE","useCloudThreadListAdapters","adapterRef","history","current","attachments","useCloudThreadListAdapter","adapter","unstable_useAdapters","useCloudAdapters","unstable_Provider","Provider","children","adapters","ref","inMemory","initialize","result","remoteId","list","after","threads","limit","map","t","status","is_archived","id","title","lastMessageAt","last_message_at","Date","external_id","custom","metadata","nextCursor","length","at","createTask","resolve","thread_id","rename","newTitle","update","updateCustom","archive","unarchive","generateTitle","messages","filteredMessages","msg","content","filter","part","type","runs","stream","assistant_id","fetch","thread","get"],"sources":["../../../../src/react/runtimes/cloud/useCloudThreadListAdapter.tsx"],"sourcesContent":["declare const process: { env: Record<string, string | undefined> };\n\nimport {\n type FC,\n type PropsWithChildren,\n type RefObject,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { AssistantCloud } from \"assistant-cloud\";\nimport type { RemoteThreadListAdapter } from \"../../../runtimes/remote-thread-list/types\";\nimport { InMemoryThreadListAdapter } from \"../../../runtimes/remote-thread-list/adapter/in-memory\";\nimport { useAssistantCloudThreadHistoryAdapter } from \"./AssistantCloudThreadHistoryAdapter\";\nimport {\n RuntimeAdapterProvider,\n type RuntimeAdapters,\n} from \"../RuntimeAdapterProvider\";\nimport { CloudFileAttachmentAdapter } from \"./CloudFileAttachmentAdapter\";\nimport { isRecord } from \"../../../utils/json/is-json\";\n\ntype ThreadData = {\n externalId: string | undefined;\n};\n\ntype CloudThreadListAdapterOptions = {\n cloud?: AssistantCloud | undefined;\n\n create?: (() => Promise<ThreadData>) | undefined;\n delete?: ((threadId: string) => Promise<void>) | undefined;\n};\n\nconst toCustom = (value: unknown): Record<string, unknown> | undefined =>\n isRecord(value) ? value : undefined;\n\nconst baseUrl =\n typeof process !== \"undefined\" &&\n process?.env?.NEXT_PUBLIC_ASSISTANT_BASE_URL;\nconst autoCloud = baseUrl\n ? new AssistantCloud({ baseUrl, anonymous: true })\n : undefined;\n\nconst CLOUD_THREAD_PAGE_SIZE = 20;\n\nconst useCloudThreadListAdapters = (\n adapterRef: RefObject<CloudThreadListAdapterOptions>,\n): RuntimeAdapters => {\n const history = useAssistantCloudThreadHistoryAdapter({\n get current() {\n return adapterRef.current.cloud ?? autoCloud!;\n },\n });\n const [attachments] = useState(\n () =>\n new CloudFileAttachmentAdapter(\n () => adapterRef.current.cloud ?? autoCloud!,\n ),\n );\n return useMemo(\n () => ({\n history,\n attachments,\n }),\n [history, attachments],\n );\n};\n\nexport const useCloudThreadListAdapter = (\n adapter: CloudThreadListAdapterOptions,\n): RemoteThreadListAdapter => {\n const adapterRef = useRef(adapter);\n useEffect(() => {\n adapterRef.current = adapter;\n }, [adapter]);\n\n const unstable_useAdapters = useCallback(function useCloudAdapters() {\n return useCloudThreadListAdapters(adapterRef);\n }, []);\n\n const unstable_Provider = useCallback<FC<PropsWithChildren>>(\n function Provider({ children }) {\n const adapters = useCloudThreadListAdapters(adapterRef);\n return (\n <RuntimeAdapterProvider adapters={adapters}>\n {children}\n </RuntimeAdapterProvider>\n );\n },\n [],\n );\n\n const cloud = adapter.cloud ?? autoCloud;\n return useMemo<RemoteThreadListAdapter>(() => {\n if (!cloud) {\n const ref = adapterRef;\n const inMemory = new InMemoryThreadListAdapter();\n inMemory.initialize = async (threadId: string) => {\n const result = await ref.current.create?.();\n return { remoteId: threadId, externalId: result?.externalId };\n };\n return inMemory;\n }\n\n return {\n list: async ({ after } = {}) => {\n const { threads } = await cloud.threads.list({\n limit: CLOUD_THREAD_PAGE_SIZE,\n ...(after ? { after } : {}),\n });\n return {\n threads: threads.map((t) => ({\n status: t.is_archived ? \"archived\" : \"regular\",\n remoteId: t.id,\n title: t.title,\n lastMessageAt: t.last_message_at\n ? new Date(t.last_message_at)\n : undefined,\n externalId: t.external_id ?? undefined,\n custom: toCustom(t.metadata),\n })),\n nextCursor:\n threads.length === CLOUD_THREAD_PAGE_SIZE\n ? threads.at(-1)?.id\n : undefined,\n };\n },\n\n initialize: async () => {\n const createTask = adapterRef.current.create?.() ?? Promise.resolve();\n const t = await createTask;\n const external_id = t ? t.externalId : undefined;\n const { thread_id: remoteId } = await cloud.threads.create({\n last_message_at: new Date(),\n external_id,\n });\n\n return { externalId: external_id, remoteId: remoteId };\n },\n\n rename: async (threadId, newTitle) => {\n return cloud.threads.update(threadId, { title: newTitle });\n },\n updateCustom: async (threadId, custom) => {\n return cloud.threads.update(threadId, { metadata: custom ?? null });\n },\n archive: async (threadId) => {\n return cloud.threads.update(threadId, { is_archived: true });\n },\n unarchive: async (threadId) => {\n return cloud.threads.update(threadId, { is_archived: false });\n },\n delete: async (threadId) => {\n await adapterRef.current.delete?.(threadId);\n return cloud.threads.delete(threadId);\n },\n\n generateTitle: async (threadId, messages) => {\n // Filter messages to only include content types the title generator understands\n // (reasoning, source, etc. are not needed for title generation)\n // TODO serialize these to a more efficient format\n const filteredMessages = messages.map((msg) => ({\n ...msg,\n content: msg.content.filter(\n (part) => part.type === \"text\" || part.type === \"tool-call\",\n ),\n }));\n\n return cloud.runs.stream({\n thread_id: threadId,\n assistant_id: \"system/thread_title\",\n messages: filteredMessages,\n });\n },\n\n fetch: async (threadId: string) => {\n const thread = await cloud.threads.get(threadId);\n return {\n status: thread.is_archived ? \"archived\" : \"regular\",\n remoteId: thread.id,\n title: thread.title,\n lastMessageAt: thread.last_message_at\n ? new Date(thread.last_message_at)\n : undefined,\n externalId: thread.external_id ?? undefined,\n custom: toCustom(thread.metadata),\n };\n },\n\n unstable_Provider,\n unstable_useAdapters,\n };\n }, [cloud, unstable_Provider, unstable_useAdapters]);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"useCloudThreadListAdapter.js","names":["process","env","Record","FC","PropsWithChildren","RefObject","useCallback","useEffect","useMemo","useRef","useState","AssistantCloud","RemoteThreadListAdapter","InMemoryThreadListAdapter","useAssistantCloudThreadHistoryAdapter","RuntimeAdapterProvider","RuntimeAdapters","CloudFileAttachmentAdapter","isRecord","ThreadData","externalId","CloudThreadListAdapterOptions","cloud","create","Promise","delete","threadId","toCustom","value","undefined","baseUrl","NEXT_PUBLIC_ASSISTANT_BASE_URL","autoCloud","anonymous","CLOUD_THREAD_PAGE_SIZE","CloudListCursor","activeCursor","archivedCursor","activeExhausted","archivedExhausted","parseListCursor","after","fallback","startsWith","parsed","JSON","parse","a","r","ae","re","useCloudThreadListAdapters","adapterRef","history","current","attachments","useCloudThreadListAdapter","adapter","unstable_useAdapters","useCloudAdapters","unstable_Provider","Provider","children","adapters","ref","inMemory","initialize","result","remoteId","list","threads","activeThreads","archivedThreads","all","resolve","limit","is_archived","activeNext","length","at","id","archivedNext","map","t","status","title","lastMessageAt","last_message_at","Date","external_id","custom","metadata","nextCursor","stringify","createTask","thread_id","rename","newTitle","update","updateCustom","archive","unarchive","generateTitle","messages","filteredMessages","msg","content","filter","part","type","runs","stream","assistant_id","fetch","thread","get"],"sources":["../../../../src/react/runtimes/cloud/useCloudThreadListAdapter.tsx"],"sourcesContent":["declare const process: { env: Record<string, string | undefined> };\n\nimport {\n type FC,\n type PropsWithChildren,\n type RefObject,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { AssistantCloud } from \"assistant-cloud\";\nimport type { RemoteThreadListAdapter } from \"../../../runtimes/remote-thread-list/types\";\nimport { InMemoryThreadListAdapter } from \"../../../runtimes/remote-thread-list/adapter/in-memory\";\nimport { useAssistantCloudThreadHistoryAdapter } from \"./AssistantCloudThreadHistoryAdapter\";\nimport {\n RuntimeAdapterProvider,\n type RuntimeAdapters,\n} from \"../RuntimeAdapterProvider\";\nimport { CloudFileAttachmentAdapter } from \"./CloudFileAttachmentAdapter\";\nimport { isRecord } from \"../../../utils/json/is-json\";\n\ntype ThreadData = {\n externalId: string | undefined;\n};\n\ntype CloudThreadListAdapterOptions = {\n cloud?: AssistantCloud | undefined;\n\n create?: (() => Promise<ThreadData>) | undefined;\n delete?: ((threadId: string) => Promise<void>) | undefined;\n};\n\nconst toCustom = (value: unknown): Record<string, unknown> | undefined =>\n isRecord(value) ? value : undefined;\n\nconst baseUrl =\n typeof process !== \"undefined\" &&\n process?.env?.NEXT_PUBLIC_ASSISTANT_BASE_URL;\nconst autoCloud = baseUrl\n ? new AssistantCloud({ baseUrl, anonymous: true })\n : undefined;\n\nconst CLOUD_THREAD_PAGE_SIZE = 20;\n\ntype CloudListCursor = {\n activeCursor: string | undefined;\n archivedCursor: string | undefined;\n activeExhausted: boolean;\n archivedExhausted: boolean;\n};\n\nconst parseListCursor = (after: string | undefined): CloudListCursor => {\n const fallback: CloudListCursor = {\n activeCursor: after,\n archivedCursor: undefined,\n activeExhausted: false,\n archivedExhausted: false,\n };\n if (!after || !after.startsWith(\"{\")) return fallback;\n try {\n const parsed = JSON.parse(after);\n if (!isRecord(parsed)) return fallback;\n return {\n activeCursor: typeof parsed.a === \"string\" ? parsed.a : undefined,\n archivedCursor: typeof parsed.r === \"string\" ? parsed.r : undefined,\n activeExhausted: parsed.ae === true,\n archivedExhausted: parsed.re === true,\n };\n } catch {\n return fallback;\n }\n};\n\nconst useCloudThreadListAdapters = (\n adapterRef: RefObject<CloudThreadListAdapterOptions>,\n): RuntimeAdapters => {\n const history = useAssistantCloudThreadHistoryAdapter({\n get current() {\n return adapterRef.current.cloud ?? autoCloud!;\n },\n });\n const [attachments] = useState(\n () =>\n new CloudFileAttachmentAdapter(\n () => adapterRef.current.cloud ?? autoCloud!,\n ),\n );\n return useMemo(\n () => ({\n history,\n attachments,\n }),\n [history, attachments],\n );\n};\n\nexport const useCloudThreadListAdapter = (\n adapter: CloudThreadListAdapterOptions,\n): RemoteThreadListAdapter => {\n const adapterRef = useRef(adapter);\n useEffect(() => {\n adapterRef.current = adapter;\n }, [adapter]);\n\n const unstable_useAdapters = useCallback(function useCloudAdapters() {\n return useCloudThreadListAdapters(adapterRef);\n }, []);\n\n const unstable_Provider = useCallback<FC<PropsWithChildren>>(\n function Provider({ children }) {\n const adapters = useCloudThreadListAdapters(adapterRef);\n return (\n <RuntimeAdapterProvider adapters={adapters}>\n {children}\n </RuntimeAdapterProvider>\n );\n },\n [],\n );\n\n const cloud = adapter.cloud ?? autoCloud;\n return useMemo<RemoteThreadListAdapter>(() => {\n if (!cloud) {\n const ref = adapterRef;\n const inMemory = new InMemoryThreadListAdapter();\n inMemory.initialize = async (threadId: string) => {\n const result = await ref.current.create?.();\n return { remoteId: threadId, externalId: result?.externalId };\n };\n return inMemory;\n }\n\n return {\n list: async ({ after } = {}) => {\n const {\n activeCursor,\n archivedCursor,\n activeExhausted,\n archivedExhausted,\n } = parseListCursor(after);\n const [{ threads: activeThreads }, { threads: archivedThreads }] =\n await Promise.all([\n activeExhausted\n ? Promise.resolve({ threads: [] })\n : cloud.threads.list({\n limit: CLOUD_THREAD_PAGE_SIZE,\n ...(activeCursor ? { after: activeCursor } : {}),\n }),\n archivedExhausted\n ? Promise.resolve({ threads: [] })\n : cloud.threads.list({\n is_archived: true,\n limit: CLOUD_THREAD_PAGE_SIZE,\n ...(archivedCursor ? { after: archivedCursor } : {}),\n }),\n ]);\n const activeNext =\n !activeExhausted && activeThreads.length === CLOUD_THREAD_PAGE_SIZE\n ? activeThreads.at(-1)?.id\n : undefined;\n const archivedNext =\n !archivedExhausted &&\n archivedThreads.length === CLOUD_THREAD_PAGE_SIZE\n ? archivedThreads.at(-1)?.id\n : undefined;\n const threads = [...activeThreads, ...archivedThreads];\n return {\n threads: threads.map((t) => ({\n status: t.is_archived ? \"archived\" : \"regular\",\n remoteId: t.id,\n title: t.title,\n lastMessageAt: t.last_message_at\n ? new Date(t.last_message_at)\n : undefined,\n externalId: t.external_id ?? undefined,\n custom: toCustom(t.metadata),\n })),\n nextCursor:\n activeNext || archivedNext\n ? JSON.stringify({\n a: activeNext,\n r: archivedNext,\n ...(activeNext === undefined ? { ae: true } : {}),\n ...(archivedNext === undefined ? { re: true } : {}),\n })\n : undefined,\n };\n },\n\n initialize: async () => {\n const createTask = adapterRef.current.create?.() ?? Promise.resolve();\n const t = await createTask;\n const external_id = t ? t.externalId : undefined;\n const { thread_id: remoteId } = await cloud.threads.create({\n last_message_at: new Date(),\n external_id,\n });\n\n return { externalId: external_id, remoteId: remoteId };\n },\n\n rename: async (threadId, newTitle) => {\n return cloud.threads.update(threadId, { title: newTitle });\n },\n updateCustom: async (threadId, custom) => {\n return cloud.threads.update(threadId, { metadata: custom ?? null });\n },\n archive: async (threadId) => {\n return cloud.threads.update(threadId, { is_archived: true });\n },\n unarchive: async (threadId) => {\n return cloud.threads.update(threadId, { is_archived: false });\n },\n delete: async (threadId) => {\n await adapterRef.current.delete?.(threadId);\n return cloud.threads.delete(threadId);\n },\n\n generateTitle: async (threadId, messages) => {\n // Filter messages to only include content types the title generator understands\n // (reasoning, source, etc. are not needed for title generation)\n // TODO serialize these to a more efficient format\n const filteredMessages = messages.map((msg) => ({\n ...msg,\n content: msg.content.filter(\n (part) => part.type === \"text\" || part.type === \"tool-call\",\n ),\n }));\n\n return cloud.runs.stream({\n thread_id: threadId,\n assistant_id: \"system/thread_title\",\n messages: filteredMessages,\n });\n },\n\n fetch: async (threadId: string) => {\n const thread = await cloud.threads.get(threadId);\n return {\n status: thread.is_archived ? \"archived\" : \"regular\",\n remoteId: thread.id,\n title: thread.title,\n lastMessageAt: thread.last_message_at\n ? new Date(thread.last_message_at)\n : undefined,\n externalId: thread.external_id ?? undefined,\n custom: toCustom(thread.metadata),\n };\n },\n\n unstable_Provider,\n unstable_useAdapters,\n };\n }, [cloud, unstable_Provider, unstable_useAdapters]);\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"message-repository.d.ts","names":[],"sources":["../../../src/runtime/utils/message-repository.ts"],"mappings":";;;KAOY;EACV,SAAS;EACT;EACA,YAAY;;KAGF;EACV;EACA,UAAU;IACR,SAAS;IACT;IACA,YAAY;;;cAIH;EAEC,YAAA,mBAAS,wBAClB;EAkBM,sBAAA;IACL,SAAS;IACT;OACC;IACS;QACX;;cA6DQ;UACH;UACA;UACA;UAKA;UAUA;UA0DA;MAQJ;MAIA;EAUJ,YAAY,2BAAe;EAuB3B,mBAAmB,yBAAyB,SAAS;EAiCrD,WAAW;;;;;EAcX,cAAc,mBAAmB;EAsCjC,YAAY;;;;;;;;;UAmBJ;EA+BR,eAAe;EAkBf,UAAU;EAgDV;EAUA,UAAU;EAwBV,SAAS,QAAQ,YAAY"}
1
+ {"version":3,"file":"message-repository.d.ts","names":[],"sources":["../../../src/runtime/utils/message-repository.ts"],"mappings":";;;KAOY;EACV,SAAS;EACT;EACA,YAAY;;KAGF;EACV;EACA,UAAU;IACR,SAAS;IACT;IACA,YAAY;;;cAIH;EAEC,YAAA,mBAAS,wBAClB;EAkBM,sBAAA;IACL,SAAS;IACT;OACC;IACS;QACX;;cA6DQ;UACH;UACA;UACA;UAKA;UAgBA;UA2DA;MAQJ;MAIA;EAUJ,YAAY,2BAAe;EAuB3B,mBAAmB,yBAAyB,SAAS;EAiCrD,WAAW;;;;;EAcX,cAAc,mBAAmB;EAsCjC,YAAY;;;;;;;;;UAmBJ;EA+BR,eAAe;EAkBf,UAAU;EAiDV;EAUA,UAAU;EAwBV,SAAS,QAAQ,YAAY"}
@@ -25,9 +25,9 @@ const ExportedMessageRepository = {
25
25
  }
26
26
  };
27
27
  const findHead = (message) => {
28
- if (message.next) return findHead(message.next);
29
- if ("current" in message) return message;
30
- return null;
28
+ let current = message;
29
+ while (current.next) current = current.next;
30
+ return "current" in current ? current : null;
31
31
  };
32
32
  var CachedValue = class {
33
33
  _value = null;
@@ -51,18 +51,28 @@ var MessageRepository = class {
51
51
  next: null
52
52
  };
53
53
  updateLevels(message, newLevel) {
54
- message.level = newLevel;
55
- for (const childId of message.children) {
56
- const childMessage = this.messages.get(childId);
57
- if (childMessage) this.updateLevels(childMessage, newLevel + 1);
54
+ const pending = [{
55
+ message,
56
+ level: newLevel
57
+ }];
58
+ while (pending.length > 0) {
59
+ const current = pending.pop();
60
+ current.message.level = current.level;
61
+ for (const childId of current.message.children) {
62
+ const childMessage = this.messages.get(childId);
63
+ if (childMessage) pending.push({
64
+ message: childMessage,
65
+ level: current.level + 1
66
+ });
67
+ }
58
68
  }
59
69
  }
60
70
  performOp(newParent, child, operation) {
61
71
  const parentOrRoot = child.prev ?? this.root;
62
72
  const newParentOrRoot = newParent ?? this.root;
63
73
  if (operation === "relink" && parentOrRoot === newParentOrRoot) return;
64
- if (operation !== "cut") {
65
- for (let current = newParent; current; current = current.prev) if (current.current.id === child.current.id) throw new Error("MessageRepository(performOp/link): A message with the same id already exists in the parent tree. This error occurs if the same message id is found multiple times. This is likely an internal bug in assistant-ui.");
74
+ if (operation === "relink") {
75
+ for (let current = newParent; current; current = current.prev) if (current.current.id === child.current.id) throw new Error("MessageRepository(performOp/relink): A message with the same id already exists in the parent tree. This error occurs if the same message id is found multiple times. This is likely an internal bug in assistant-ui.");
66
76
  }
67
77
  if (operation !== "link") {
68
78
  parentOrRoot.children = parentOrRoot.children.filter((m) => m !== child.current.id);
@@ -192,16 +202,15 @@ var MessageRepository = class {
192
202
  if (!message) throw new Error("MessageRepository(resetHead): Branch not found. This is likely an internal bug in assistant-ui.");
193
203
  const previousHead = this.head;
194
204
  if (message.children.length > 0) {
195
- const deleteDescendants = (msg) => {
196
- for (const childId of msg.children) {
197
- const childMessage = this.messages.get(childId);
198
- if (childMessage) {
199
- deleteDescendants(childMessage);
200
- this.messages.delete(childId);
201
- }
205
+ const pending = [...message.children];
206
+ while (pending.length > 0) {
207
+ const childId = pending.pop();
208
+ const childMessage = this.messages.get(childId);
209
+ if (childMessage) {
210
+ for (const descendantId of childMessage.children) pending.push(descendantId);
211
+ this.messages.delete(childId);
202
212
  }
203
- };
204
- deleteDescendants(message);
213
+ }
205
214
  message.children = [];
206
215
  message.next = null;
207
216
  }
@@ -1 +1 @@
1
- {"version":3,"file":"message-repository.js","names":["ThreadMessage","RunConfig","generateId","ThreadMessageLike","getAutoStatus","fromThreadMessageLike","ExportedMessageRepositoryItem","message","parentId","runConfig","ExportedMessageRepository","headId","messages","Array","fromArray","conv","map","m","undefined","idx","id","fromBranchableArray","items","options","fallbackStatus","Error","RepositoryParent","children","next","RepositoryMessage","prev","current","level","findHead","CachedValue","_value","T","func","constructor","value","dirty","MessageRepository","Map","head","root","updateLevels","newLevel","childId","childMessage","get","performOp","newParent","child","operation","parentOrRoot","newParentOrRoot","filter","fallbackId","at","fallback","_messages","canonicalHeadId","metadata","isOptimistic","getMessages","headMessage","addOrUpdateMessage","existingItem","newItem","set","getMessage","messageId","index","deleteMessage","replacementId","replacement","delete","getBranches","evictOffBranchOptimisticMessages","previousHead","currentHead","onHeadBranch","Set","add","stale","has","push","switchToBranch","prevOrRoot","resetHead","clear","length","deleteDescendants","msg","export","exportItems","import"],"sources":["../../../src/runtime/utils/message-repository.ts"],"sourcesContent":["import type { ThreadMessage } from \"../../types/message\";\nimport type { RunConfig } from \"../../types/message\";\nimport { generateId } from \"../../utils/id\";\nimport type { ThreadMessageLike } from \"./thread-message-like\";\nimport { getAutoStatus } from \"./auto-status\";\nimport { fromThreadMessageLike } from \"./thread-message-like\";\n\nexport type ExportedMessageRepositoryItem = {\n message: ThreadMessage;\n parentId: string | null;\n runConfig?: RunConfig;\n};\n\nexport type ExportedMessageRepository = {\n headId?: string | null;\n messages: Array<{\n message: ThreadMessage;\n parentId: string | null;\n runConfig?: RunConfig;\n }>;\n};\n\nexport const ExportedMessageRepository = {\n fromArray: (\n messages: readonly ThreadMessageLike[],\n ): ExportedMessageRepository => {\n const conv = messages.map((m) =>\n fromThreadMessageLike(\n m,\n generateId(),\n getAutoStatus(false, false, false, false, undefined),\n ),\n );\n\n return {\n messages: conv.map((m, idx) => ({\n parentId: idx > 0 ? conv[idx - 1]!.id : null,\n message: m,\n })),\n };\n },\n\n fromBranchableArray: (\n items: readonly {\n message: ThreadMessageLike;\n parentId: string | null;\n }[],\n options?: { headId?: string | null },\n ): ExportedMessageRepository => {\n const fallbackStatus = getAutoStatus(false, false, false, false, undefined);\n return {\n ...(options?.headId !== undefined\n ? { headId: options.headId }\n : undefined),\n messages: items.map(({ message, parentId }) => {\n if (!message.id) {\n throw new Error(\n \"ExportedMessageRepository.fromBranchableArray: Each message must have an 'id' field set.\",\n );\n }\n return {\n parentId,\n message: fromThreadMessageLike(message, message.id, fallbackStatus),\n };\n }),\n };\n },\n};\n\ntype RepositoryParent = {\n children: string[];\n next: RepositoryMessage | null;\n};\n\ntype RepositoryMessage = RepositoryParent & {\n prev: RepositoryMessage | null;\n current: ThreadMessage;\n level: number;\n};\n\nconst findHead = (\n message: RepositoryMessage | RepositoryParent,\n): RepositoryMessage | null => {\n if (message.next) return findHead(message.next);\n if (\"current\" in message) return message;\n return null;\n};\n\nclass CachedValue<T> {\n private _value: T | null = null;\n\n private func: () => T;\n\n constructor(func: () => T) {\n this.func = func;\n }\n\n get value() {\n if (this._value === null) {\n this._value = this.func();\n }\n return this._value;\n }\n\n dirty() {\n this._value = null;\n }\n}\n\nexport class MessageRepository {\n private messages = new Map<string, RepositoryMessage>();\n private head: RepositoryMessage | null = null;\n private root: RepositoryParent = {\n children: [],\n next: null,\n };\n\n private updateLevels(message: RepositoryMessage, newLevel: number) {\n message.level = newLevel;\n for (const childId of message.children) {\n const childMessage = this.messages.get(childId);\n if (childMessage) {\n this.updateLevels(childMessage, newLevel + 1);\n }\n }\n }\n\n private performOp(\n newParent: RepositoryMessage | null,\n child: RepositoryMessage,\n operation: \"cut\" | \"link\" | \"relink\",\n ) {\n const parentOrRoot = child.prev ?? this.root;\n const newParentOrRoot = newParent ?? this.root;\n\n if (operation === \"relink\" && parentOrRoot === newParentOrRoot) return;\n\n if (operation !== \"cut\") {\n for (\n let current: RepositoryMessage | null = newParent;\n current;\n current = current.prev\n ) {\n if (current.current.id === child.current.id) {\n throw new Error(\n \"MessageRepository(performOp/link): A message with the same id already exists in the parent tree. This error occurs if the same message id is found multiple times. This is likely an internal bug in assistant-ui.\",\n );\n }\n }\n }\n\n if (operation !== \"link\") {\n parentOrRoot.children = parentOrRoot.children.filter(\n (m) => m !== child.current.id,\n );\n\n if (parentOrRoot.next === child) {\n const fallbackId = parentOrRoot.children.at(-1);\n const fallback = fallbackId ? this.messages.get(fallbackId) : null;\n if (fallback === undefined) {\n throw new Error(\n \"MessageRepository(performOp/cut): Fallback sibling message not found. This is likely an internal bug in assistant-ui.\",\n );\n }\n parentOrRoot.next = fallback;\n }\n }\n\n if (operation !== \"cut\") {\n newParentOrRoot.children = [\n ...newParentOrRoot.children,\n child.current.id,\n ];\n\n if (findHead(child) === this.head || newParentOrRoot.next === null) {\n newParentOrRoot.next = child;\n }\n\n child.prev = newParent;\n\n const newLevel = newParent ? newParent.level + 1 : 0;\n this.updateLevels(child, newLevel);\n }\n }\n\n private _messages = new CachedValue<readonly ThreadMessage[]>(() => {\n const messages = new Array<ThreadMessage>((this.head?.level ?? -1) + 1);\n for (let current = this.head; current; current = current.prev) {\n messages[current.level] = current.current;\n }\n return messages;\n });\n\n get headId() {\n return this.head?.current.id ?? null;\n }\n\n get canonicalHeadId() {\n // Optimistic messages are ephemeral, so persisted callers need the nearest\n // non-optimistic ancestor rather than the raw head.\n let head = this.head;\n while (head?.current.metadata?.isOptimistic) {\n head = head.prev;\n }\n return head?.current.id ?? null;\n }\n\n getMessages(headId?: string) {\n if (headId === undefined || headId === this.head?.current.id) {\n return this._messages.value;\n }\n\n const headMessage = this.messages.get(headId);\n if (!headMessage) {\n throw new Error(\n \"MessageRepository(getMessages): Head message not found. This is likely an internal bug in assistant-ui.\",\n );\n }\n\n const messages = new Array<ThreadMessage>(headMessage.level + 1);\n for (\n let current: RepositoryMessage | null = headMessage;\n current;\n current = current.prev\n ) {\n messages[current.level] = current.current;\n }\n return messages;\n }\n\n addOrUpdateMessage(parentId: string | null, message: ThreadMessage) {\n const existingItem = this.messages.get(message.id);\n const prev = parentId ? this.messages.get(parentId) : null;\n if (prev === undefined)\n throw new Error(\n \"MessageRepository(addOrUpdateMessage): Parent message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n if (existingItem) {\n existingItem.current = message;\n this.performOp(prev, existingItem, \"relink\");\n this._messages.dirty();\n return;\n }\n\n const newItem: RepositoryMessage = {\n prev,\n current: message,\n next: null,\n children: [],\n level: prev ? prev.level + 1 : 0,\n };\n\n this.messages.set(message.id, newItem);\n this.performOp(prev, newItem, \"link\");\n\n if (this.head === prev) {\n this.head = newItem;\n }\n\n this._messages.dirty();\n }\n\n getMessage(messageId: string) {\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(updateMessage): Message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n return {\n parentId: message.prev?.current.id ?? null,\n message: message.current,\n index: message.level,\n };\n }\n\n deleteMessage(messageId: string, replacementId?: string | null | undefined) {\n const message = this.messages.get(messageId);\n\n if (!message)\n throw new Error(\n \"MessageRepository(deleteMessage): Message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const replacement =\n replacementId === undefined\n ? message.prev\n : replacementId === null\n ? null\n : this.messages.get(replacementId);\n if (replacement === undefined)\n throw new Error(\n \"MessageRepository(deleteMessage): Replacement not found. This is likely an internal bug in assistant-ui.\",\n );\n\n for (const child of message.children) {\n const childMessage = this.messages.get(child);\n if (!childMessage)\n throw new Error(\n \"MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui.\",\n );\n this.performOp(replacement, childMessage, \"relink\");\n }\n\n this.performOp(null, message, \"cut\");\n this.messages.delete(messageId);\n\n if (this.head === message) {\n this.head = findHead(replacement ?? this.root);\n }\n\n this._messages.dirty();\n }\n\n getBranches(messageId: string) {\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(getBranches): Message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const { children } = message.prev ?? this.root;\n return children;\n }\n\n /**\n * Evicts optimistic messages (`metadata.isOptimistic`) the head just moved\n * away from. Since eviction runs on every head move, the only optimistic\n * messages in the repository live on the branch the head previously pointed\n * at — so we walk just that branch rather than the whole repository. Keeps a\n * client→server id swap from leaving a phantom sibling, and drops off-branch\n * placeholders.\n */\n private evictOffBranchOptimisticMessages(\n previousHead: RepositoryMessage | null,\n currentHead: RepositoryMessage | null,\n ) {\n if (!previousHead) return;\n\n const onHeadBranch = new Set<string>();\n for (let current = currentHead; current; current = current.prev) {\n onHeadBranch.add(current.current.id);\n }\n\n const stale: string[] = [];\n for (\n let current: RepositoryMessage | null = previousHead;\n current;\n current = current.prev\n ) {\n // Stop at the first node shared with the current head branch: every\n // ancestor above it is shared too, so nothing further can be off-branch.\n if (onHeadBranch.has(current.current.id)) break;\n if (current.current.metadata?.isOptimistic) {\n stale.push(current.current.id);\n }\n }\n\n for (const id of stale) {\n // A prior deletion may have already removed this node.\n if (this.messages.has(id)) this.deleteMessage(id);\n }\n }\n\n switchToBranch(messageId: string) {\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(switchToBranch): Branch not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const previousHead = this.head;\n const prevOrRoot = message.prev ?? this.root;\n prevOrRoot.next = message;\n\n this.head = findHead(message);\n\n this.evictOffBranchOptimisticMessages(previousHead, this.head);\n\n this._messages.dirty();\n }\n\n resetHead(messageId: string | null) {\n if (messageId === null) {\n this.clear();\n return;\n }\n\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(resetHead): Branch not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const previousHead = this.head;\n\n if (message.children.length > 0) {\n const deleteDescendants = (msg: RepositoryMessage) => {\n for (const childId of msg.children) {\n const childMessage = this.messages.get(childId);\n if (childMessage) {\n deleteDescendants(childMessage);\n this.messages.delete(childId);\n }\n }\n };\n deleteDescendants(message);\n\n message.children = [];\n message.next = null;\n }\n\n this.head = message;\n for (\n let current: RepositoryMessage | null = message;\n current;\n current = current.prev\n ) {\n if (current.prev) {\n current.prev.next = current;\n } else {\n this.root.next = current;\n }\n }\n\n this.evictOffBranchOptimisticMessages(previousHead, this.head);\n\n this._messages.dirty();\n }\n\n clear(): void {\n this.messages.clear();\n this.head = null;\n this.root = {\n children: [],\n next: null,\n };\n this._messages.dirty();\n }\n\n export(): ExportedMessageRepository {\n const exportItems: ExportedMessageRepository[\"messages\"] = [];\n\n // Optimistic messages are ephemeral and never persisted. A persisted child\n // of an optimistic node is re-parented onto its nearest persisted ancestor\n // so the exported tree never references a skipped id.\n for (const [, message] of this.messages) {\n if (message.current.metadata?.isOptimistic) continue;\n let prev = message.prev;\n while (prev && prev.current.metadata?.isOptimistic) {\n prev = prev.prev;\n }\n exportItems.push({\n message: message.current,\n parentId: prev?.current.id ?? null,\n });\n }\n\n return {\n headId: this.canonicalHeadId,\n messages: exportItems,\n };\n }\n\n import({ headId, messages }: ExportedMessageRepository) {\n for (const { message, parentId } of messages) {\n this.addOrUpdateMessage(parentId, message);\n }\n\n this.resetHead(headId ?? messages.at(-1)?.message.id ?? null);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"message-repository.js","names":["ThreadMessage","RunConfig","generateId","ThreadMessageLike","getAutoStatus","fromThreadMessageLike","ExportedMessageRepositoryItem","message","parentId","runConfig","ExportedMessageRepository","headId","messages","Array","fromArray","conv","map","m","undefined","idx","id","fromBranchableArray","items","options","fallbackStatus","Error","RepositoryParent","children","next","RepositoryMessage","prev","current","level","findHead","CachedValue","_value","T","func","constructor","value","dirty","MessageRepository","Map","head","root","updateLevels","newLevel","pending","length","pop","childId","childMessage","get","push","performOp","newParent","child","operation","parentOrRoot","newParentOrRoot","filter","fallbackId","at","fallback","_messages","canonicalHeadId","metadata","isOptimistic","getMessages","headMessage","addOrUpdateMessage","existingItem","newItem","set","getMessage","messageId","index","deleteMessage","replacementId","replacement","delete","getBranches","evictOffBranchOptimisticMessages","previousHead","currentHead","onHeadBranch","Set","add","stale","has","switchToBranch","prevOrRoot","resetHead","clear","descendantId","export","exportItems","import"],"sources":["../../../src/runtime/utils/message-repository.ts"],"sourcesContent":["import type { ThreadMessage } from \"../../types/message\";\nimport type { RunConfig } from \"../../types/message\";\nimport { generateId } from \"../../utils/id\";\nimport type { ThreadMessageLike } from \"./thread-message-like\";\nimport { getAutoStatus } from \"./auto-status\";\nimport { fromThreadMessageLike } from \"./thread-message-like\";\n\nexport type ExportedMessageRepositoryItem = {\n message: ThreadMessage;\n parentId: string | null;\n runConfig?: RunConfig;\n};\n\nexport type ExportedMessageRepository = {\n headId?: string | null;\n messages: Array<{\n message: ThreadMessage;\n parentId: string | null;\n runConfig?: RunConfig;\n }>;\n};\n\nexport const ExportedMessageRepository = {\n fromArray: (\n messages: readonly ThreadMessageLike[],\n ): ExportedMessageRepository => {\n const conv = messages.map((m) =>\n fromThreadMessageLike(\n m,\n generateId(),\n getAutoStatus(false, false, false, false, undefined),\n ),\n );\n\n return {\n messages: conv.map((m, idx) => ({\n parentId: idx > 0 ? conv[idx - 1]!.id : null,\n message: m,\n })),\n };\n },\n\n fromBranchableArray: (\n items: readonly {\n message: ThreadMessageLike;\n parentId: string | null;\n }[],\n options?: { headId?: string | null },\n ): ExportedMessageRepository => {\n const fallbackStatus = getAutoStatus(false, false, false, false, undefined);\n return {\n ...(options?.headId !== undefined\n ? { headId: options.headId }\n : undefined),\n messages: items.map(({ message, parentId }) => {\n if (!message.id) {\n throw new Error(\n \"ExportedMessageRepository.fromBranchableArray: Each message must have an 'id' field set.\",\n );\n }\n return {\n parentId,\n message: fromThreadMessageLike(message, message.id, fallbackStatus),\n };\n }),\n };\n },\n};\n\ntype RepositoryParent = {\n children: string[];\n next: RepositoryMessage | null;\n};\n\ntype RepositoryMessage = RepositoryParent & {\n prev: RepositoryMessage | null;\n current: ThreadMessage;\n level: number;\n};\n\nconst findHead = (\n message: RepositoryMessage | RepositoryParent,\n): RepositoryMessage | null => {\n let current = message;\n while (current.next) current = current.next;\n return \"current\" in current ? current : null;\n};\n\nclass CachedValue<T> {\n private _value: T | null = null;\n\n private func: () => T;\n\n constructor(func: () => T) {\n this.func = func;\n }\n\n get value() {\n if (this._value === null) {\n this._value = this.func();\n }\n return this._value;\n }\n\n dirty() {\n this._value = null;\n }\n}\n\nexport class MessageRepository {\n private messages = new Map<string, RepositoryMessage>();\n private head: RepositoryMessage | null = null;\n private root: RepositoryParent = {\n children: [],\n next: null,\n };\n\n private updateLevels(message: RepositoryMessage, newLevel: number) {\n const pending = [{ message, level: newLevel }];\n\n while (pending.length > 0) {\n const current = pending.pop()!;\n current.message.level = current.level;\n\n for (const childId of current.message.children) {\n const childMessage = this.messages.get(childId);\n if (childMessage) {\n pending.push({ message: childMessage, level: current.level + 1 });\n }\n }\n }\n }\n\n private performOp(\n newParent: RepositoryMessage | null,\n child: RepositoryMessage,\n operation: \"cut\" | \"link\" | \"relink\",\n ) {\n const parentOrRoot = child.prev ?? this.root;\n const newParentOrRoot = newParent ?? this.root;\n\n if (operation === \"relink\" && parentOrRoot === newParentOrRoot) return;\n\n // `link` receives a fresh ID from `addOrUpdateMessage`; only `relink` can introduce a cycle.\n if (operation === \"relink\") {\n for (\n let current: RepositoryMessage | null = newParent;\n current;\n current = current.prev\n ) {\n if (current.current.id === child.current.id) {\n throw new Error(\n \"MessageRepository(performOp/relink): A message with the same id already exists in the parent tree. This error occurs if the same message id is found multiple times. This is likely an internal bug in assistant-ui.\",\n );\n }\n }\n }\n\n if (operation !== \"link\") {\n parentOrRoot.children = parentOrRoot.children.filter(\n (m) => m !== child.current.id,\n );\n\n if (parentOrRoot.next === child) {\n const fallbackId = parentOrRoot.children.at(-1);\n const fallback = fallbackId ? this.messages.get(fallbackId) : null;\n if (fallback === undefined) {\n throw new Error(\n \"MessageRepository(performOp/cut): Fallback sibling message not found. This is likely an internal bug in assistant-ui.\",\n );\n }\n parentOrRoot.next = fallback;\n }\n }\n\n if (operation !== \"cut\") {\n newParentOrRoot.children = [\n ...newParentOrRoot.children,\n child.current.id,\n ];\n\n if (findHead(child) === this.head || newParentOrRoot.next === null) {\n newParentOrRoot.next = child;\n }\n\n child.prev = newParent;\n\n const newLevel = newParent ? newParent.level + 1 : 0;\n this.updateLevels(child, newLevel);\n }\n }\n\n private _messages = new CachedValue<readonly ThreadMessage[]>(() => {\n const messages = new Array<ThreadMessage>((this.head?.level ?? -1) + 1);\n for (let current = this.head; current; current = current.prev) {\n messages[current.level] = current.current;\n }\n return messages;\n });\n\n get headId() {\n return this.head?.current.id ?? null;\n }\n\n get canonicalHeadId() {\n // Optimistic messages are ephemeral, so persisted callers need the nearest\n // non-optimistic ancestor rather than the raw head.\n let head = this.head;\n while (head?.current.metadata?.isOptimistic) {\n head = head.prev;\n }\n return head?.current.id ?? null;\n }\n\n getMessages(headId?: string) {\n if (headId === undefined || headId === this.head?.current.id) {\n return this._messages.value;\n }\n\n const headMessage = this.messages.get(headId);\n if (!headMessage) {\n throw new Error(\n \"MessageRepository(getMessages): Head message not found. This is likely an internal bug in assistant-ui.\",\n );\n }\n\n const messages = new Array<ThreadMessage>(headMessage.level + 1);\n for (\n let current: RepositoryMessage | null = headMessage;\n current;\n current = current.prev\n ) {\n messages[current.level] = current.current;\n }\n return messages;\n }\n\n addOrUpdateMessage(parentId: string | null, message: ThreadMessage) {\n const existingItem = this.messages.get(message.id);\n const prev = parentId ? this.messages.get(parentId) : null;\n if (prev === undefined)\n throw new Error(\n \"MessageRepository(addOrUpdateMessage): Parent message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n if (existingItem) {\n existingItem.current = message;\n this.performOp(prev, existingItem, \"relink\");\n this._messages.dirty();\n return;\n }\n\n const newItem: RepositoryMessage = {\n prev,\n current: message,\n next: null,\n children: [],\n level: prev ? prev.level + 1 : 0,\n };\n\n this.messages.set(message.id, newItem);\n this.performOp(prev, newItem, \"link\");\n\n if (this.head === prev) {\n this.head = newItem;\n }\n\n this._messages.dirty();\n }\n\n getMessage(messageId: string) {\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(updateMessage): Message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n return {\n parentId: message.prev?.current.id ?? null,\n message: message.current,\n index: message.level,\n };\n }\n\n deleteMessage(messageId: string, replacementId?: string | null | undefined) {\n const message = this.messages.get(messageId);\n\n if (!message)\n throw new Error(\n \"MessageRepository(deleteMessage): Message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const replacement =\n replacementId === undefined\n ? message.prev\n : replacementId === null\n ? null\n : this.messages.get(replacementId);\n if (replacement === undefined)\n throw new Error(\n \"MessageRepository(deleteMessage): Replacement not found. This is likely an internal bug in assistant-ui.\",\n );\n\n for (const child of message.children) {\n const childMessage = this.messages.get(child);\n if (!childMessage)\n throw new Error(\n \"MessageRepository(deleteMessage): Child message not found. This is likely an internal bug in assistant-ui.\",\n );\n this.performOp(replacement, childMessage, \"relink\");\n }\n\n this.performOp(null, message, \"cut\");\n this.messages.delete(messageId);\n\n if (this.head === message) {\n this.head = findHead(replacement ?? this.root);\n }\n\n this._messages.dirty();\n }\n\n getBranches(messageId: string) {\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(getBranches): Message not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const { children } = message.prev ?? this.root;\n return children;\n }\n\n /**\n * Evicts optimistic messages (`metadata.isOptimistic`) the head just moved\n * away from. Since eviction runs on every head move, the only optimistic\n * messages in the repository live on the branch the head previously pointed\n * at — so we walk just that branch rather than the whole repository. Keeps a\n * client→server id swap from leaving a phantom sibling, and drops off-branch\n * placeholders.\n */\n private evictOffBranchOptimisticMessages(\n previousHead: RepositoryMessage | null,\n currentHead: RepositoryMessage | null,\n ) {\n if (!previousHead) return;\n\n const onHeadBranch = new Set<string>();\n for (let current = currentHead; current; current = current.prev) {\n onHeadBranch.add(current.current.id);\n }\n\n const stale: string[] = [];\n for (\n let current: RepositoryMessage | null = previousHead;\n current;\n current = current.prev\n ) {\n // Stop at the first node shared with the current head branch: every\n // ancestor above it is shared too, so nothing further can be off-branch.\n if (onHeadBranch.has(current.current.id)) break;\n if (current.current.metadata?.isOptimistic) {\n stale.push(current.current.id);\n }\n }\n\n for (const id of stale) {\n // A prior deletion may have already removed this node.\n if (this.messages.has(id)) this.deleteMessage(id);\n }\n }\n\n switchToBranch(messageId: string) {\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(switchToBranch): Branch not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const previousHead = this.head;\n const prevOrRoot = message.prev ?? this.root;\n prevOrRoot.next = message;\n\n this.head = findHead(message);\n\n this.evictOffBranchOptimisticMessages(previousHead, this.head);\n\n this._messages.dirty();\n }\n\n resetHead(messageId: string | null) {\n if (messageId === null) {\n this.clear();\n return;\n }\n\n const message = this.messages.get(messageId);\n if (!message)\n throw new Error(\n \"MessageRepository(resetHead): Branch not found. This is likely an internal bug in assistant-ui.\",\n );\n\n const previousHead = this.head;\n\n if (message.children.length > 0) {\n const pending = [...message.children];\n while (pending.length > 0) {\n const childId = pending.pop()!;\n const childMessage = this.messages.get(childId);\n if (childMessage) {\n for (const descendantId of childMessage.children) {\n pending.push(descendantId);\n }\n this.messages.delete(childId);\n }\n }\n\n message.children = [];\n message.next = null;\n }\n\n this.head = message;\n for (\n let current: RepositoryMessage | null = message;\n current;\n current = current.prev\n ) {\n if (current.prev) {\n current.prev.next = current;\n } else {\n this.root.next = current;\n }\n }\n\n this.evictOffBranchOptimisticMessages(previousHead, this.head);\n\n this._messages.dirty();\n }\n\n clear(): void {\n this.messages.clear();\n this.head = null;\n this.root = {\n children: [],\n next: null,\n };\n this._messages.dirty();\n }\n\n export(): ExportedMessageRepository {\n const exportItems: ExportedMessageRepository[\"messages\"] = [];\n\n // Optimistic messages are ephemeral and never persisted. A persisted child\n // of an optimistic node is re-parented onto its nearest persisted ancestor\n // so the exported tree never references a skipped id.\n for (const [, message] of this.messages) {\n if (message.current.metadata?.isOptimistic) continue;\n let prev = message.prev;\n while (prev && prev.current.metadata?.isOptimistic) {\n prev = prev.prev;\n }\n exportItems.push({\n message: message.current,\n parentId: prev?.current.id ?? null,\n });\n }\n\n return {\n headId: this.canonicalHeadId,\n messages: exportItems,\n };\n }\n\n import({ headId, messages }: ExportedMessageRepository) {\n for (const { message, parentId } of messages) {\n this.addOrUpdateMessage(parentId, message);\n }\n\n this.resetHead(headId ?? messages.at(-1)?.message.id ?? null);\n }\n}\n"],"mappings":";;;;AAsBA,MAAaU,4BAA4B;CACvCI,YACEF,aAC8B;EAC9B,MAAMG,OAAOH,SAASI,KAAKC,MACzBZ,sBACEY,GACAf,WAAW,GACXE,cAAc,OAAO,OAAO,OAAO,OAAOc,KAAAA,CAAS,CACrD,CACF;EAEA,OAAO,EACLN,UAAUG,KAAKC,KAAKC,GAAGE,SAAS;GAC9BX,UAAUW,MAAM,IAAIJ,KAAKI,MAAM,EAAE,CAAEC,KAAK;GACxCb,SAASU;EACX,EAAE,EACJ;CACF;CAEAI,sBACEC,OAIAC,YAC8B;EAC9B,MAAMC,iBAAiBpB,cAAc,OAAO,OAAO,OAAO,OAAOc,KAAAA,CAAS;EAC1E,OAAO;GACL,GAAIK,SAASZ,WAAWO,KAAAA,IACpB,EAAEP,QAAQY,QAAQZ,OAAO,IACzBO,KAAAA;GACJN,UAAUU,MAAMN,KAAK,EAAET,SAASC,eAAe;IAC7C,IAAI,CAACD,QAAQa,IACX,MAAM,IAAIK,MACR,0FACF;IAEF,OAAO;KACLjB;KACAD,SAASF,sBAAsBE,SAASA,QAAQa,IAAII,cAAc;IACpE;GACF,CAAC;EACH;CACF;AACF;AAaA,MAAMS,YACJ1B,YAC6B;CAC7B,IAAIwB,UAAUxB;CACd,OAAOwB,QAAQH,MAAMG,UAAUA,QAAQH;CACvC,OAAO,aAAaG,UAAUA,UAAU;AAC1C;AAEA,IAAMG,cAAN,MAAqB;CACnB,SAA2B;CAE3B;CAEAI,YAAYD,MAAe;EACzB,KAAKA,OAAOA;CACd;CAEA,IAAIE,QAAQ;EACV,IAAI,KAAKJ,WAAW,MAClB,KAAKA,SAAS,KAAKE,KAAK;EAE1B,OAAO,KAAKF;CACd;CAEAK,QAAQ;EACN,KAAKL,SAAS;CAChB;AACF;AAEA,IAAaM,oBAAb,MAA+B;CAC7B,2BAAmB,IAAIC,IAA+B;CACtD,OAAyC;CACzC,OAAiC;EAC/Bf,UAAU,CAAA;EACVC,MAAM;CACR;CAEA,aAAqBrB,SAA4BuC,UAAkB;EACjE,MAAMC,UAAU,CAAC;GAAExC;GAASyB,OAAOc;EAAS,CAAC;EAE7C,OAAOC,QAAQC,SAAS,GAAG;GACzB,MAAMjB,UAAUgB,QAAQE,IAAI;GAC5BlB,QAAQxB,QAAQyB,QAAQD,QAAQC;GAEhC,KAAK,MAAMkB,WAAWnB,QAAQxB,QAAQoB,UAAU;IAC9C,MAAMwB,eAAe,KAAKvC,SAASwC,IAAIF,OAAO;IAC9C,IAAIC,cACFJ,QAAQM,KAAK;KAAE9C,SAAS4C;KAAcnB,OAAOD,QAAQC,QAAQ;IAAE,CAAC;GAEpE;EACF;CACF;CAEA,UACEuB,WACAC,OACAC,WACA;EACA,MAAMC,eAAeF,MAAM1B,QAAQ,KAAKc;EACxC,MAAMe,kBAAkBJ,aAAa,KAAKX;EAE1C,IAAIa,cAAc,YAAYC,iBAAiBC,iBAAiB;EAGhE,IAAIF,cAAc,UAEd;QAAA,IAAI1B,UAAoCwB,WACxCxB,SACAA,UAAUA,QAAQD,MAElB,IAAIC,QAAQA,QAAQX,OAAOoC,MAAMzB,QAAQX,IACvC,MAAM,IAAIK,MACR,sNACF;EAAA;EAKN,IAAIgC,cAAc,QAAQ;GACxBC,aAAa/B,WAAW+B,aAAa/B,SAASiC,QAC3C3C,MAAMA,MAAMuC,MAAMzB,QAAQX,EAC7B;GAEA,IAAIsC,aAAa9B,SAAS4B,OAAO;IAC/B,MAAMK,aAAaH,aAAa/B,SAASmC,GAAG,EAAE;IAC9C,MAAMC,WAAWF,aAAa,KAAKjD,SAASwC,IAAIS,UAAU,IAAI;IAC9D,IAAIE,aAAa7C,KAAAA,GACf,MAAM,IAAIO,MACR,uHACF;IAEFiC,aAAa9B,OAAOmC;GACtB;EACF;EAEA,IAAIN,cAAc,OAAO;GACvBE,gBAAgBhC,WAAW,CACzB,GAAGgC,gBAAgBhC,UACnB6B,MAAMzB,QAAQX,EAAE;GAGlB,IAAIa,SAASuB,KAAK,MAAM,KAAKb,QAAQgB,gBAAgB/B,SAAS,MAC5D+B,gBAAgB/B,OAAO4B;GAGzBA,MAAM1B,OAAOyB;GAEb,MAAMT,WAAWS,YAAYA,UAAUvB,QAAQ,IAAI;GACnD,KAAKa,aAAaW,OAAOV,QAAQ;EACnC;CACF;CAEA,YAAoB,IAAIZ,kBAA4C;EAClE,MAAMtB,WAAW,IAAIC,OAAsB,KAAK8B,MAAMX,SAAS,MAAM,CAAC;EACtE,KAAK,IAAID,UAAU,KAAKY,MAAMZ,SAASA,UAAUA,QAAQD,MACvDlB,SAASmB,QAAQC,SAASD,QAAQA;EAEpC,OAAOnB;CACT,CAAC;CAED,IAAID,SAAS;EACX,OAAO,KAAKgC,MAAMZ,QAAQX,MAAM;CAClC;CAEA,IAAI6C,kBAAkB;EAGpB,IAAItB,OAAO,KAAKA;EAChB,OAAOA,MAAMZ,QAAQmC,UAAUC,cAC7BxB,OAAOA,KAAKb;EAEd,OAAOa,MAAMZ,QAAQX,MAAM;CAC7B;CAEAgD,YAAYzD,QAAiB;EAC3B,IAAIA,WAAWO,KAAAA,KAAaP,WAAW,KAAKgC,MAAMZ,QAAQX,IACxD,OAAO,KAAK4C,UAAUzB;EAGxB,MAAM8B,cAAc,KAAKzD,SAASwC,IAAIzC,MAAM;EAC5C,IAAI,CAAC0D,aACH,MAAM,IAAI5C,MACR,yGACF;EAGF,MAAMb,WAAW,IAAIC,MAAqBwD,YAAYrC,QAAQ,CAAC;EAC/D,KACE,IAAID,UAAoCsC,aACxCtC,SACAA,UAAUA,QAAQD,MAElBlB,SAASmB,QAAQC,SAASD,QAAQA;EAEpC,OAAOnB;CACT;CAEA0D,mBAAmB9D,UAAyBD,SAAwB;EAClE,MAAMgE,eAAe,KAAK3D,SAASwC,IAAI7C,QAAQa,EAAE;EACjD,MAAMU,OAAOtB,WAAW,KAAKI,SAASwC,IAAI5C,QAAQ,IAAI;EACtD,IAAIsB,SAASZ,KAAAA,GACX,MAAM,IAAIO,MACR,kHACF;EAEF,IAAI8C,cAAc;GAChBA,aAAaxC,UAAUxB;GACvB,KAAK+C,UAAUxB,MAAMyC,cAAc,QAAQ;GAC3C,KAAKP,UAAUxB,MAAM;GACrB;EACF;EAEA,MAAMgC,UAA6B;GACjC1C;GACAC,SAASxB;GACTqB,MAAM;GACND,UAAU,CAAA;GACVK,OAAOF,OAAOA,KAAKE,QAAQ,IAAI;EACjC;EAEA,KAAKpB,SAAS6D,IAAIlE,QAAQa,IAAIoD,OAAO;EACrC,KAAKlB,UAAUxB,MAAM0C,SAAS,MAAM;EAEpC,IAAI,KAAK7B,SAASb,MAChB,KAAKa,OAAO6B;EAGd,KAAKR,UAAUxB,MAAM;CACvB;CAEAkC,WAAWC,WAAmB;EAC5B,MAAMpE,UAAU,KAAKK,SAASwC,IAAIuB,SAAS;EAC3C,IAAI,CAACpE,SACH,MAAM,IAAIkB,MACR,sGACF;EAEF,OAAO;GACLjB,UAAUD,QAAQuB,MAAMC,QAAQX,MAAM;GACtCb,SAASA,QAAQwB;GACjB6C,OAAOrE,QAAQyB;EACjB;CACF;CAEA6C,cAAcF,WAAmBG,eAA2C;EAC1E,MAAMvE,UAAU,KAAKK,SAASwC,IAAIuB,SAAS;EAE3C,IAAI,CAACpE,SACH,MAAM,IAAIkB,MACR,sGACF;EAEF,MAAMsD,cACJD,kBAAkB5D,KAAAA,IACdX,QAAQuB,OACRgD,kBAAkB,OAChB,OACA,KAAKlE,SAASwC,IAAI0B,aAAa;EACvC,IAAIC,gBAAgB7D,KAAAA,GAClB,MAAM,IAAIO,MACR,0GACF;EAEF,KAAK,MAAM+B,SAASjD,QAAQoB,UAAU;GACpC,MAAMwB,eAAe,KAAKvC,SAASwC,IAAII,KAAK;GAC5C,IAAI,CAACL,cACH,MAAM,IAAI1B,MACR,4GACF;GACF,KAAK6B,UAAUyB,aAAa5B,cAAc,QAAQ;EACpD;EAEA,KAAKG,UAAU,MAAM/C,SAAS,KAAK;EACnC,KAAKK,SAASoE,OAAOL,SAAS;EAE9B,IAAI,KAAKhC,SAASpC,SAChB,KAAKoC,OAAOV,SAAS8C,eAAe,KAAKnC,IAAI;EAG/C,KAAKoB,UAAUxB,MAAM;CACvB;CAEAyC,YAAYN,WAAmB;EAC7B,MAAMpE,UAAU,KAAKK,SAASwC,IAAIuB,SAAS;EAC3C,IAAI,CAACpE,SACH,MAAM,IAAIkB,MACR,oGACF;EAEF,MAAM,EAAEE,aAAapB,QAAQuB,QAAQ,KAAKc;EAC1C,OAAOjB;CACT;;;;;;;;;CAUA,iCACEwD,cACAC,aACA;EACA,IAAI,CAACD,cAAc;EAEnB,MAAME,+BAAe,IAAIC,IAAY;EACrC,KAAK,IAAIvD,UAAUqD,aAAarD,SAASA,UAAUA,QAAQD,MACzDuD,aAAaE,IAAIxD,QAAQA,QAAQX,EAAE;EAGrC,MAAMoE,QAAkB,CAAA;EACxB,KACE,IAAIzD,UAAoCoD,cACxCpD,SACAA,UAAUA,QAAQD,MAClB;GAGA,IAAIuD,aAAaI,IAAI1D,QAAQA,QAAQX,EAAE,GAAG;GAC1C,IAAIW,QAAQA,QAAQmC,UAAUC,cAC5BqB,MAAMnC,KAAKtB,QAAQA,QAAQX,EAAE;EAEjC;EAEA,KAAK,MAAMA,MAAMoE,OAEf,IAAI,KAAK5E,SAAS6E,IAAIrE,EAAE,GAAG,KAAKyD,cAAczD,EAAE;CAEpD;CAEAsE,eAAef,WAAmB;EAChC,MAAMpE,UAAU,KAAKK,SAASwC,IAAIuB,SAAS;EAC3C,IAAI,CAACpE,SACH,MAAM,IAAIkB,MACR,sGACF;EAEF,MAAM0D,eAAe,KAAKxC;EAC1B,MAAMgD,aAAapF,QAAQuB,QAAQ,KAAKc;EACxC+C,WAAW/D,OAAOrB;EAElB,KAAKoC,OAAOV,SAAS1B,OAAO;EAE5B,KAAK2E,iCAAiCC,cAAc,KAAKxC,IAAI;EAE7D,KAAKqB,UAAUxB,MAAM;CACvB;CAEAoD,UAAUjB,WAA0B;EAClC,IAAIA,cAAc,MAAM;GACtB,KAAKkB,MAAM;GACX;EACF;EAEA,MAAMtF,UAAU,KAAKK,SAASwC,IAAIuB,SAAS;EAC3C,IAAI,CAACpE,SACH,MAAM,IAAIkB,MACR,iGACF;EAEF,MAAM0D,eAAe,KAAKxC;EAE1B,IAAIpC,QAAQoB,SAASqB,SAAS,GAAG;GAC/B,MAAMD,UAAU,CAAC,GAAGxC,QAAQoB,QAAQ;GACpC,OAAOoB,QAAQC,SAAS,GAAG;IACzB,MAAME,UAAUH,QAAQE,IAAI;IAC5B,MAAME,eAAe,KAAKvC,SAASwC,IAAIF,OAAO;IAC9C,IAAIC,cAAc;KAChB,KAAK,MAAM2C,gBAAgB3C,aAAaxB,UACtCoB,QAAQM,KAAKyC,YAAY;KAE3B,KAAKlF,SAASoE,OAAO9B,OAAO;IAC9B;GACF;GAEA3C,QAAQoB,WAAW,CAAA;GACnBpB,QAAQqB,OAAO;EACjB;EAEA,KAAKe,OAAOpC;EACZ,KACE,IAAIwB,UAAoCxB,SACxCwB,SACAA,UAAUA,QAAQD,MAElB,IAAIC,QAAQD,MACVC,QAAQD,KAAKF,OAAOG;OAEpB,KAAKa,KAAKhB,OAAOG;EAIrB,KAAKmD,iCAAiCC,cAAc,KAAKxC,IAAI;EAE7D,KAAKqB,UAAUxB,MAAM;CACvB;CAEAqD,QAAc;EACZ,KAAKjF,SAASiF,MAAM;EACpB,KAAKlD,OAAO;EACZ,KAAKC,OAAO;GACVjB,UAAU,CAAA;GACVC,MAAM;EACR;EACA,KAAKoC,UAAUxB,MAAM;CACvB;CAEAuD,SAAoC;EAClC,MAAMC,cAAqD,CAAA;EAK3D,KAAK,MAAM,GAAGzF,YAAY,KAAKK,UAAU;GACvC,IAAIL,QAAQwB,QAAQmC,UAAUC,cAAc;GAC5C,IAAIrC,OAAOvB,QAAQuB;GACnB,OAAOA,QAAQA,KAAKC,QAAQmC,UAAUC,cACpCrC,OAAOA,KAAKA;GAEdkE,YAAY3C,KAAK;IACf9C,SAASA,QAAQwB;IACjBvB,UAAUsB,MAAMC,QAAQX,MAAM;GAChC,CAAC;EACH;EAEA,OAAO;GACLT,QAAQ,KAAKsD;GACbrD,UAAUoF;EACZ;CACF;CAEAC,OAAO,EAAEtF,QAAQC,YAAuC;EACtD,KAAK,MAAM,EAAEL,SAASC,cAAcI,UAClC,KAAK0D,mBAAmB9D,UAAUD,OAAO;EAG3C,KAAKqF,UAAUjF,UAAUC,SAASkD,GAAG,EAAE,CAAC,EAAEvD,QAAQa,MAAM,IAAI;CAC9D;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"external-store-thread-runtime-core.d.ts","names":[],"sources":["../../../src/runtimes/external-store/external-store-thread-runtime-core.ts"],"mappings":";;;;;;;;;;;;;;;;cAwEa,qBACX,oBACA,mBAAmB;cAKR,uCACH,iCACG;UAEH;MAiBG,gBAAY;UAIf;EACD;EACA;MACI;MAIA;YAIQ,6BAA6B;MAI5B,sEAAK,sDAAA;MAId;kBARqC;;;;;;;MAarC,iCAAiC;EAKrC,sBAAsB;EACtB;UAEC;UAEA;UAEA;EAED,mCACL,kBAAkB;UAKZ;;;;;UAMA;EAEQ,UAAU;EAQxB,YAAA,iBAAiB,sBACjB,OAAO;EAMF,sBAAsB,OAAO;;;;;;;UA2M5B;;;;;UAsEA;UACA;;;;;;;UAQA;EAmBQ,eAAe;;;;;;;;;UA6BvB;EAaK,OAAO,YAAY,gBAAgB;EAoEnC,cAAc,oBAAoB;EAoBxC,0BApBwC;EA0BxC,+BANa;EAUb,cAAc,qBAAqB,WAAW;EAI9C,gBAAgB;EAIV,SAAS,QAAQ,iBAAiB;EAYlC,UAAU,QAAQ,kBAAkB;EAO1C;EAOA,oBAAoB;;;;;;EAqBpB;EAKA;UA+EC;EAOD,cAAc,SAAS;EASvB,eAAe,SAAS;EAoBxB,sBAAsB,SAAS;EAStB,MAAM,2BAA2B;EAMjC,OAAO,MAAM;UAQrB"}
1
+ {"version":3,"file":"external-store-thread-runtime-core.d.ts","names":[],"sources":["../../../src/runtimes/external-store/external-store-thread-runtime-core.ts"],"mappings":";;;;;;;;;;;;;;;;cAwEa,qBACX,oBACA,mBAAmB;cAKR,uCACH,iCACG;UAEH;MAiBG,gBAAY;UAIf;EACD;EACA;MACI;MAIA;YAIQ,6BAA6B;MAI5B,sEAAK,sDAAA;MAId;kBARqC;;;;;;;MAarC,iCAAiC;EAKrC,sBAAsB;EACtB;UAEC;UAEA;UAEA;EAED,mCACL,kBAAkB;UAKZ;;;;;UAMA;EAEQ,UAAU;EAQxB,YAAA,iBAAiB,sBACjB,OAAO;EAMF,sBAAsB,OAAO;;;;;;;UA2M5B;;;;;UAsEA;UACA;;;;;;;UAQA;EAmBQ,eAAe;;;;;;;;;UA6BvB;EAaK,OAAO,YAAY,gBAAgB;EAoEnC,cAAc,oBAAoB;EAoBxC,0BApBwC;EA0BxC,+BANa;EAUb,cAAc,qBAAqB,WAAW;EAI9C,gBAAgB;EAIV,SAAS,QAAQ,iBAAiB;EAYlC,UAAU,QAAQ,kBAAkB;EAO1C;EAOA,oBAAoB;;;;;;EAqBpB;EAKA;UAmFC;EAOD,cAAc,SAAS;EASvB,eAAe,SAAS;EAoBxB,sBAAsB,SAAS;EAStB,MAAM,2BAA2B;EAMjC,OAAO,MAAM;UAQrB"}
@@ -371,6 +371,7 @@ var ExternalStoreThreadRuntimeCore = class extends BaseThreadRuntimeCore {
371
371
  }
372
372
  cancelRun() {
373
373
  if (!this._store.onCancel) throw new Error("Runtime does not support cancelling runs.");
374
+ const generation = captureThreadRuntimeGeneration(this);
374
375
  this._toolInvocations?.abort();
375
376
  this._store.queue?.__internal_notifyCancelled?.();
376
377
  observeAdapterCallback("onCancel", this._store.onCancel());
@@ -395,6 +396,7 @@ var ExternalStoreThreadRuntimeCore = class extends BaseThreadRuntimeCore {
395
396
  }
396
397
  if (!movedLeaf) this._notifySubscribers();
397
398
  setTimeout(() => {
399
+ if (!isThreadRuntimeGenerationCurrent(this, generation)) return;
398
400
  this.dropEmptyOptimisticHead();
399
401
  if (movedLeaf) {
400
402
  const current = this.repository.getMessages();
@@ -1 +1 @@
1
- {"version":3,"file":"external-store-thread-runtime-core.js","names":["AppendMessage","ThreadMessage","Attachment","AddToolResultOptions","ResumeRunConfig","ResumeToolCallOptions","RespondToToolApprovalOptions","StartRunConfig","ThreadSuggestion","ExternalStoreAdapter","ExternalStoreBranchChange","getExternalStoreMessages","bindExternalStoreMessage","ThreadMessageConverter","getAutoStatus","isAutoStatus","fromThreadMessageLike","ThreadMessageLike","getThreadMessageText","RuntimeCapabilities","ThreadRuntimeCore","ExternalThreadQueueAdapter","QueuePlacement","BaseThreadRuntimeCore","ModelContextProvider","ExportedMessageRepository","MessageRepository","generateId","ToolInvocationTracker","EMPTY_QUEUE_ITEMS","QuoteInfo","captureThreadRuntimeGeneration","isThreadRuntimeGenerationCurrent","EMPTY_ARRAY","Object","freeze","observeAdapterCallback","name","result","Promise","resolve","catch","error","console","shallowEqual","a","b","aKeys","keys","length","key","hasUpcomingMessage","isRunning","messages","role","ExternalStoreThreadRuntimeCore","_capabilities","switchToBranch","switchBranchDuringRun","edit","delete","reload","refetchThread","cancel","unstable_copy","speech","dictation","voice","attachments","feedback","queue","capabilities","_messages","isDisabled","isSendDisabled","isLoading","_store","_getBaseMessages","state","adapters","unstable_refetchThread","onRefetchThread","undefined","suggestions","extras","_converter","_getInitializePromise","__internal_setGetInitializePromise","getPromise","_transformedQueue","_toolInvocations","beginEdit","messageId","onEdit","Error","constructor","contextProvider","store","__internal_setAdapter","oldStore","__internal_setDispatchTransform","message","parentId","at","id","enrichAppendMetadata","newSuggestions","newCapabilities","setMessages","onDelete","onReload","onCancel","unstable_capabilities","copy","messageRepository","_notifySubscribers","incoming","headId","repository","resetHead","getMessages","incomingIds","Set","map","addOrUpdateMessage","export","has","deleteMessage","convertMessage","convertMessages","cache","m","idx","isLast","autoStatus","status","messageLike","newMessage","toString","seenIds","deduped","i","warn","add","push","reverse","parent","ensureInitialized","_notifyEventSubscribers","optimisticId","content","metadata","isOptimistic","type","_driveToolInvocations","unstable_enableToolInvocations","reset","setToolStatuses","getModelContext","tools","onResult","command","_findMessageIdForToolCall","toolCallId","onAddToolResult","toolName","isError","artifact","modelContent","err","onStatusesChange","statuses","fromEntries","setState","_toolCallToMessageId","Map","_messagesForToolCallIndex","clear","visit","Array","isArray","part","set","get","branchId","onBranchChange","unstable_onBranchChange","previousHeadId","canonicalHeadId","updateMessages","_notifyBranchChange","event","visibleMessageIds","append","rawMessage","isEdit","sourceId","generation","initPromise","steer","enqueue","startRun","abort","onNew","messageIndex","findIndex","filter","getQueueItems","items","getSteerQueueItems","steerItems","moveQueueItem","queueItemId","placement","move","removeQueueItem","remove","config","resumeRun","onResume","exportExternalState","onExportExternalState","importExternalState","onLoadExternalState","unstable_notifySessionReset","__internal_notifyCancelled","cancelRun","dropEmptyOptimisticHead","previousMessage","trailingUserLeaf","every","movedLeaf","draft","text","quote","custom","composer","restoreDraft","setTimeout","current","some","retractDraft","head","addToolResult","options","resumeToolCall","handled","resume","payload","onResumeToolCall","respondToToolApproval","onRespondToToolApproval","initialMessages","repo","import","fromArray","data","onImport","hasConverter","flatMap"],"sources":["../../../src/runtimes/external-store/external-store-thread-runtime-core.ts"],"sourcesContent":["import type { AppendMessage, ThreadMessage } from \"../../types/message\";\nimport type { Attachment } from \"../../types/attachment\";\nimport type {\n AddToolResultOptions,\n ResumeRunConfig,\n ResumeToolCallOptions,\n RespondToToolApprovalOptions,\n StartRunConfig,\n ThreadSuggestion,\n} from \"../../runtime/interfaces/thread-runtime-core\";\n\nimport type {\n ExternalStoreAdapter,\n ExternalStoreBranchChange,\n} from \"./external-store-adapter\";\nimport {\n getExternalStoreMessages,\n bindExternalStoreMessage,\n} from \"../../runtime/utils/external-store-message\";\nimport { ThreadMessageConverter } from \"./thread-message-converter\";\nimport { getAutoStatus, isAutoStatus } from \"../../runtime/utils/auto-status\";\nimport {\n fromThreadMessageLike,\n type ThreadMessageLike,\n} from \"../../runtime/utils/thread-message-like\";\nimport { getThreadMessageText } from \"../../utils/text\";\nimport type {\n RuntimeCapabilities,\n ThreadRuntimeCore,\n} from \"../../runtime/interfaces/thread-runtime-core\";\nimport type {\n ExternalThreadQueueAdapter,\n QueuePlacement,\n} from \"../../runtime/queue/external-thread-queue-adapter\";\nimport { BaseThreadRuntimeCore } from \"../../runtime/base/base-thread-runtime-core\";\nimport type { ModelContextProvider } from \"../../model-context/types\";\nimport {\n ExportedMessageRepository,\n MessageRepository,\n} from \"../../runtime/utils/message-repository\";\nimport { generateId } from \"../../utils/id\";\nimport { ToolInvocationTracker } from \"../tool-invocations/ToolInvocationTracker\";\nimport { EMPTY_QUEUE_ITEMS } from \"../../store/scopes/queue-item\";\nimport type { QuoteInfo } from \"../../types/quote\";\nimport {\n captureThreadRuntimeGeneration,\n isThreadRuntimeGenerationCurrent,\n} from \"../../runtime/utils/thread-runtime-lifecycle\";\n\nconst EMPTY_ARRAY: readonly ThreadSuggestion[] = Object.freeze([]);\n\nconst observeAdapterCallback = (\n name: \"onAddToolResult\" | \"onRespondToToolApproval\" | \"onCancel\",\n result: Promise<void> | void,\n) => {\n void Promise.resolve(result).catch((error) => {\n console.error(\n `[ExternalStoreThreadRuntimeCore] ${name} callback rejected`,\n error,\n );\n });\n};\n\nconst shallowEqual = (a: object, b: object): boolean => {\n const aKeys = Object.keys(a);\n if (aKeys.length !== Object.keys(b).length) return false;\n for (const key of aKeys) {\n if ((a as any)[key] !== (b as any)[key]) return false;\n }\n return true;\n};\n\nexport const hasUpcomingMessage = (\n isRunning: boolean,\n messages: readonly ThreadMessage[],\n) => {\n return isRunning && messages[messages.length - 1]?.role !== \"assistant\";\n};\n\nexport class ExternalStoreThreadRuntimeCore\n extends BaseThreadRuntimeCore\n implements ThreadRuntimeCore\n{\n private _capabilities: RuntimeCapabilities = {\n switchToBranch: false,\n switchBranchDuringRun: false,\n edit: false,\n delete: false,\n reload: false,\n refetchThread: false,\n cancel: false,\n unstable_copy: false,\n speech: false,\n dictation: false,\n voice: false,\n attachments: false,\n feedback: false,\n queue: false,\n };\n\n public get capabilities() {\n return this._capabilities;\n }\n\n private _messages!: readonly ThreadMessage[];\n public isDisabled!: boolean;\n public isSendDisabled!: boolean;\n public get isLoading() {\n return this._store.isLoading ?? false;\n }\n // Unlike `isLoading`: pass `undefined` through to preserve the `getThreadState` fallback.\n public get isRunning(): boolean | undefined {\n return this._store.isRunning;\n }\n\n protected override _getBaseMessages(): readonly ThreadMessage[] {\n return this._messages;\n }\n\n public override get state() {\n return this._store.state ?? super.state;\n }\n\n public get adapters() {\n return this._store.adapters;\n }\n\n // A getter, not a method, so its presence tracks the adapter.\n public get unstable_refetchThread(): (() => Promise<void>) | undefined {\n if (!this._store.onRefetchThread) return undefined;\n return () => this._store.onRefetchThread!();\n }\n\n public suggestions: readonly ThreadSuggestion[] = [];\n public extras: unknown = undefined;\n\n private _converter = new ThreadMessageConverter();\n\n private _store!: ExternalStoreAdapter<any>;\n\n private _getInitializePromise?: () => Promise<unknown> | undefined;\n\n public __internal_setGetInitializePromise(\n getPromise: () => Promise<unknown> | undefined,\n ) {\n this._getInitializePromise = getPromise;\n }\n\n private _transformedQueue: ExternalThreadQueueAdapter | undefined;\n\n /**\n * Client-side tool-invocations pipeline. Constructed lazily on first\n * snapshot — only when `adapter.unstable_enableToolInvocations === true`.\n */\n private _toolInvocations: ToolInvocationTracker | null = null;\n\n public override beginEdit(messageId: string) {\n if (!this._store.onEdit)\n throw new Error(\"Runtime does not support editing.\");\n\n super.beginEdit(messageId);\n }\n\n constructor(\n contextProvider: ModelContextProvider,\n store: ExternalStoreAdapter<any>,\n ) {\n super(contextProvider);\n this.__internal_setAdapter(store);\n }\n\n public __internal_setAdapter(store: ExternalStoreAdapter<any>) {\n if (this._store === store) return;\n\n const isRunning = store.isRunning ?? false;\n this.isDisabled = store.isDisabled ?? false;\n this.isSendDisabled = store.isSendDisabled ?? false;\n\n const oldStore = this._store as ExternalStoreAdapter<any> | undefined;\n this._store = store;\n if (oldStore?.queue !== store.queue) {\n this._transformedQueue = undefined;\n store.queue?.__internal_setDispatchTransform?.((message) => {\n // Re-point at the tail, as LocalThreadRuntimeCore's driver does, so\n // the prefix gated against is the one the message lands on whatever\n // the host routes by. Queuing only ever accepts a tail append, so a\n // later tail is the same intent.\n const parentId = this.messages.at(-1)?.id ?? null;\n return this.enrichAppendMetadata({ ...message, parentId }, parentId);\n });\n if (store.queue?.__internal_setDispatchTransform)\n this._transformedQueue = store.queue;\n }\n if (this.extras !== store.extras) {\n this.extras = store.extras;\n }\n\n const newSuggestions = store.suggestions ?? EMPTY_ARRAY;\n if (!shallowEqual(this.suggestions, newSuggestions)) {\n this.suggestions = newSuggestions;\n }\n\n const newCapabilities: RuntimeCapabilities = {\n switchToBranch: this._store.setMessages !== undefined,\n switchBranchDuringRun: false,\n edit: this._store.onEdit !== undefined,\n delete:\n this._store.onDelete !== undefined ||\n this._store.setMessages !== undefined,\n reload: this._store.onReload !== undefined,\n refetchThread: this._store.onRefetchThread !== undefined,\n cancel: this._store.onCancel !== undefined,\n speech: this._store.adapters?.speech !== undefined,\n dictation: this._store.adapters?.dictation !== undefined,\n voice: this._store.adapters?.voice !== undefined,\n unstable_copy: this._store.unstable_capabilities?.copy !== false,\n attachments: !!this._store.adapters?.attachments,\n feedback: !!this._store.adapters?.feedback,\n queue: this._store.queue !== undefined,\n };\n if (!shallowEqual(this._capabilities, newCapabilities)) {\n this._capabilities = newCapabilities;\n }\n\n let messages: readonly ThreadMessage[];\n\n if (store.messageRepository) {\n // Handle messageRepository\n if (\n oldStore &&\n oldStore.isRunning === store.isRunning &&\n oldStore.messageRepository === store.messageRepository\n ) {\n this._notifySubscribers();\n return;\n }\n\n const incoming = store.messageRepository.messages;\n const headId =\n store.messageRepository.headId ?? incoming.at(-1)?.message.id ?? null;\n\n if (oldStore && oldStore.messageRepository === store.messageRepository) {\n this.repository.resetHead(headId);\n messages = this.repository.getMessages();\n } else {\n const incomingIds = new Set(incoming.map(({ message }) => message.id));\n for (const { message, parentId } of incoming) {\n this.repository.addOrUpdateMessage(parentId, message);\n }\n for (const { message } of this.repository.export().messages) {\n if (!incomingIds.has(message.id)) {\n this.repository.deleteMessage(message.id);\n }\n }\n this.repository.resetHead(headId);\n messages = this.repository.getMessages();\n }\n } else if (store.messages) {\n // Handle messages array\n\n if (oldStore) {\n // flush the converter cache when the convertMessage prop changes\n if (oldStore.convertMessage !== store.convertMessage) {\n this._converter = new ThreadMessageConverter();\n } else if (\n oldStore.isRunning === store.isRunning &&\n oldStore.messages === store.messages\n ) {\n this._notifySubscribers();\n // no conversion update\n return;\n }\n }\n\n messages = !store.convertMessage\n ? store.messages\n : this._converter.convertMessages(store.messages, (cache, m, idx) => {\n if (!store.convertMessage) return m;\n\n const isLast = idx === (store.messages?.length ?? 0) - 1;\n const autoStatus = getAutoStatus(\n isLast,\n isRunning,\n false,\n false,\n undefined,\n );\n\n if (\n cache &&\n (cache.role !== \"assistant\" ||\n !isAutoStatus(cache.status) ||\n cache.status === autoStatus)\n )\n return cache;\n\n const messageLike = store.convertMessage(m, idx);\n const newMessage = fromThreadMessageLike(\n messageLike,\n idx.toString(),\n autoStatus,\n );\n bindExternalStoreMessage(newMessage, m);\n return newMessage;\n });\n\n const seenIds = new Set<string>();\n const deduped: ThreadMessage[] = [];\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i]!;\n if (seenIds.has(message.id)) {\n console.warn(\n `ExternalStoreThreadRuntimeCore: duplicate message id \"${message.id}\" in the provided messages array; keeping the last occurrence.`,\n );\n continue;\n }\n seenIds.add(message.id);\n deduped.push(message);\n }\n if (deduped.length !== messages.length) messages = deduped.reverse();\n\n for (let i = 0; i < messages.length; i++) {\n const message = messages[i]!;\n const parent = messages[i - 1];\n this.repository.addOrUpdateMessage(parent?.id ?? null, message);\n }\n } else {\n throw new Error(\n \"ExternalStoreAdapter must provide either 'messages' or 'messageRepository'\",\n );\n }\n\n // Common logic for both paths\n if (messages.length > 0) this.ensureInitialized();\n\n if ((oldStore?.isRunning ?? false) !== (store.isRunning ?? false)) {\n if (store.isRunning) {\n this._notifyEventSubscribers(\"runStart\", {});\n } else {\n this._notifyEventSubscribers(\"runEnd\", {});\n }\n }\n\n // Append an optimistic placeholder while running but before a trailing\n // assistant message exists. resetHead evicts off-branch optimistic messages\n // (prior placeholders, mid-run id-swap siblings); export() never persists them.\n let optimisticId: string | null = null;\n if (hasUpcomingMessage(isRunning, messages)) {\n optimisticId = generateId();\n this.repository.addOrUpdateMessage(\n messages.at(-1)?.id ?? null,\n fromThreadMessageLike(\n { role: \"assistant\", content: [], metadata: { isOptimistic: true } },\n optimisticId,\n { type: \"running\" },\n ),\n );\n }\n\n this.repository.resetHead(optimisticId ?? messages.at(-1)?.id ?? null);\n\n this._messages = this.repository.getMessages();\n\n this._driveToolInvocations();\n\n this._notifySubscribers();\n }\n\n /**\n * Feed the current message snapshot into the tool-invocations tracker.\n * Opt-in via `adapter.unstable_enableToolInvocations: true`. The tracker\n * itself is fail-silent — see ToolInvocationTracker for the\n * state-transition contract.\n */\n private _driveToolInvocations(): void {\n if (!this._store.unstable_enableToolInvocations) {\n // Adapter did not opt in (default). If a tracker was previously\n // constructed (e.g. the adapter just toggled the flag off via a\n // dynamic swap), drop it so subsequent snapshots are no-ops.\n if (this._toolInvocations) {\n this._toolInvocations.reset();\n this._toolInvocations = null;\n this._store.setToolStatuses?.({});\n }\n return;\n }\n\n if (!this._toolInvocations) {\n this._toolInvocations = new ToolInvocationTracker(\n () => this.getModelContext().tools,\n {\n onResult: (command) => {\n try {\n const messageId = this._findMessageIdForToolCall(\n command.toolCallId,\n );\n if (messageId === undefined) {\n // The tool call no longer exists in the snapshot (e.g.\n // rolled back). Drop the result.\n return;\n }\n observeAdapterCallback(\n \"onAddToolResult\",\n this._store.onAddToolResult?.({\n messageId,\n toolCallId: command.toolCallId,\n toolName: command.toolName,\n result: command.result,\n isError: command.isError,\n ...(command.artifact !== undefined && {\n artifact: command.artifact,\n }),\n ...(command.modelContent !== undefined && {\n modelContent: command.modelContent,\n }),\n }),\n );\n } catch (err) {\n console.error(\n \"[ExternalStoreThreadRuntimeCore] onAddToolResult dispatch failed\",\n err,\n );\n }\n },\n onStatusesChange: (statuses) => {\n this._store.setToolStatuses?.(Object.fromEntries(statuses));\n },\n },\n );\n }\n\n this._toolInvocations.setState({\n messages: this._messages,\n isRunning: this._store.isRunning ?? false,\n ...(this._store.isLoading !== undefined && {\n isLoading: this._store.isLoading,\n }),\n });\n }\n\n /**\n * Lookup table from `toolCallId` to the owning assistant message's `id`,\n * rebuilt lazily when `_messages` changes (see `_messagesForToolCallIndex`).\n */\n private _toolCallToMessageId = new Map<string, string>();\n private _messagesForToolCallIndex: readonly ThreadMessage[] | null = null;\n\n /**\n * Look up the assistant message that owns a tool-call part. Lazily builds\n * (and caches) a `toolCallId → messageId` map keyed off the current\n * `_messages` reference, so onResult dispatches stay O(1) instead of\n * walking the full thread on every result.\n */\n private _findMessageIdForToolCall(toolCallId: string): string | undefined {\n if (this._messagesForToolCallIndex !== this._messages) {\n this._toolCallToMessageId.clear();\n const visit = (messages: readonly ThreadMessage[]): void => {\n for (const message of messages) {\n if (!Array.isArray(message.content)) continue;\n for (const part of message.content) {\n if (!part || part.type !== \"tool-call\") continue;\n this._toolCallToMessageId.set(part.toolCallId, message.id);\n if (part.messages) visit(part.messages);\n }\n }\n };\n visit(this._messages);\n this._messagesForToolCallIndex = this._messages;\n }\n return this._toolCallToMessageId.get(toolCallId);\n }\n\n public override switchToBranch(branchId: string): void {\n if (!this._store.setMessages)\n throw new Error(\"Runtime does not support switching branches.\");\n\n // Silently ignore branch switches while running\n if (this._store.isRunning) {\n return;\n }\n\n const onBranchChange = this._store.unstable_onBranchChange;\n const previousHeadId = onBranchChange\n ? this.repository.canonicalHeadId\n : null;\n\n this.repository.switchToBranch(branchId);\n this.updateMessages(this.repository.getMessages());\n if (onBranchChange) {\n this._notifyBranchChange(previousHeadId, onBranchChange);\n }\n }\n\n /**\n * Emit `unstable_onBranchChange` for an explicit branch switch. Reads the\n * canonical head from the repository (which skips optimistic/transient\n * messages) and de-dupes switches that leave the canonical head unchanged.\n * Comparing against the head observed just before the switch — rather than the\n * last emitted head — keeps a switch firing after an adapter resync moved the\n * head elsewhere in the meantime.\n */\n private _notifyBranchChange(\n previousHeadId: string | null,\n onBranchChange: (event: ExternalStoreBranchChange) => void,\n ): void {\n const headId = this.repository.canonicalHeadId;\n if (headId === previousHeadId) return;\n\n onBranchChange({\n headId,\n visibleMessageIds: this.repository.getMessages().map((m) => m.id),\n });\n }\n\n public async append(rawMessage: AppendMessage): Promise<void> {\n // sourceId marks an edit send; the parent may coincide with the head\n // after a resync (e.g. cancelRun dropped the edited message).\n const isEdit =\n rawMessage.sourceId != null ||\n rawMessage.parentId !== (this.messages.at(-1)?.id ?? null);\n\n // A transformed-queue send is stamped at flush; any other queue's\n // transform would gate against its own thread's messages, so those stamp\n // at send.\n const message =\n !isEdit &&\n this._store.queue &&\n this._store.queue === this._transformedQueue\n ? rawMessage\n : this.enrichAppendMetadata(rawMessage);\n\n const generation = captureThreadRuntimeGeneration(this);\n this.ensureInitialized();\n\n // The getter call is what starts thread initialization.\n const initPromise = this._getInitializePromise?.();\n\n // The queue driver dispatches through the host adapter, outside this\n // core, so the initialization barrier must run before a message can\n // enter the queue.\n if (!isEdit && this._store.queue) {\n if (initPromise) {\n await initPromise;\n }\n if (!isThreadRuntimeGenerationCurrent(this, generation)) return;\n\n // Buffering does not start a run, so the tool-abort below must wait\n // until the queue flushes. By then the prior run (and its tools) has\n // settled.\n if (message.steer ?? this._store.isRunning ?? false)\n this._store.queue.steer(message);\n else this._store.queue.enqueue(message);\n return;\n }\n\n // The optimistic insert lives inside the adapter's dispatch, so holding\n // `onNew` on initialization would keep the message off screen for the\n // whole roundtrip. Seams that need the remote identity await\n // `threadListItem.initialize()` themselves, and a rejection surfaces\n // there.\n void initPromise?.catch(() => {});\n\n // Auto-abort in-flight client-side tool executions when a new run is\n // about to start. Without this, a tool that finishes after the new turn\n // begins would feed a stale result into `onAddToolResult`, racing with\n // the new turn the user just initiated. `startRun` defaults to true for\n // user messages — matches the satellites' historical opt-in cancel\n // behavior, which is now built in.\n if (message.startRun ?? message.role === \"user\") {\n await this._toolInvocations?.abort();\n }\n if (!isThreadRuntimeGenerationCurrent(this, generation)) return;\n\n if (isEdit) {\n if (!this._store.onEdit)\n throw new Error(\"Runtime does not support editing messages.\");\n await this._store.onEdit(message);\n } else {\n await this._store.onNew(message);\n }\n }\n\n public async deleteMessage(messageId: string): Promise<void> {\n if (this._store.onDelete) {\n await this._store.onDelete(messageId);\n return;\n }\n\n if (!this._store.setMessages)\n throw new Error(\"Runtime does not support deleting messages.\");\n\n if (this._store.isRunning) {\n await this._toolInvocations?.abort();\n }\n\n const messages = this.repository.getMessages();\n const messageIndex = messages.findIndex((m) => m.id === messageId);\n if (messageIndex === -1) throw new Error(\"Message not found.\");\n\n this.updateMessages(messages.filter((message) => message.id !== messageId));\n }\n\n public getQueueItems() {\n // The composer reads this during base-thread construction, before the\n // constructor assigns `_store`, so guard against the unset field.\n return this._store?.queue?.items ?? EMPTY_QUEUE_ITEMS;\n }\n\n public getSteerQueueItems() {\n return this._store?.queue?.steerItems ?? EMPTY_QUEUE_ITEMS;\n }\n\n public moveQueueItem(queueItemId: string, placement: QueuePlacement) {\n this._store?.queue?.move(queueItemId, placement);\n }\n\n public removeQueueItem(queueItemId: string) {\n this._store?.queue?.remove(queueItemId);\n }\n\n public async startRun(config: StartRunConfig): Promise<void> {\n if (!this._store.onReload)\n throw new Error(\"Runtime does not support reloading messages.\");\n\n // Auto-abort in-flight client-side tool executions when a run reloads;\n // any results that land afterward would target a turn that no longer\n // exists. See `append` above for full rationale.\n await this._toolInvocations?.abort();\n\n await this._store.onReload(config.parentId, config);\n }\n\n public async resumeRun(config: ResumeRunConfig): Promise<void> {\n if (!this._store.onResume)\n throw new Error(\"Runtime does not support resuming runs.\");\n\n await this._store.onResume(config);\n }\n\n public exportExternalState(): any {\n if (!this._store.onExportExternalState)\n throw new Error(\"Runtime does not support exporting external states.\");\n\n return this._store.onExportExternalState();\n }\n\n public importExternalState(state: any): void {\n if (!this._store.onLoadExternalState)\n throw new Error(\"Runtime does not support importing external states.\");\n\n // Re-arm the tracker so the next adapter snapshot (containing the\n // imported state) is treated as historical — no streamCall/execute\n // fires for the loaded tool calls. The adapter is expected to update\n // its messages in response to onLoadExternalState; that update flows\n // back here via __internal_setAdapter. The tracker publishes the\n // cleared status map itself, so adapter-side statuses reset only when\n // the tracker is the source of truth.\n this._toolInvocations?.reset();\n\n this._store.onLoadExternalState(state);\n }\n\n /**\n * Adapter-facing notification that the backing session was discarded.\n * Clears session-scoped tool-invocation state and parks queued work,\n * without run-cancel semantics (`onCancel`, composer draft restoration).\n */\n public unstable_notifySessionReset(): void {\n this._toolInvocations?.reset();\n this._store.queue?.__internal_notifyCancelled?.();\n }\n\n public cancelRun(): void {\n if (!this._store.onCancel)\n throw new Error(\"Runtime does not support cancelling runs.\");\n\n // Abort any in-flight client-side tool executions. Fire-and-forget —\n // the abort resolves once executions settle, but we don't gate the\n // cancel on it.\n void this._toolInvocations?.abort();\n\n // Before the run is aborted, so the settle it produces keeps the pending\n // items instead of dispatching the next one at the moment the user\n // stopped.\n this._store.queue?.__internal_notifyCancelled?.();\n\n observeAdapterCallback(\"onCancel\", this._store.onCancel());\n\n this.dropEmptyOptimisticHead();\n\n const messages = this.repository.getMessages();\n const previousMessage = messages[messages.length - 1];\n const trailingUserLeaf =\n this._store.setMessages !== undefined &&\n previousMessage?.role === \"user\" &&\n previousMessage.id === messages.at(-1)?.id && // ensure the previous message is a leaf node\n previousMessage.content.every((part) => part.type === \"text\")\n ? previousMessage\n : undefined;\n\n // Handing the message to the composer and taking it out of the thread are\n // one move: the composer refuses while the user is writing, and removing\n // the message then would leave it nowhere. A message the composer cannot\n // hold whole, carrying content parts it has no home for, is not moved.\n let movedLeaf:\n | {\n id: string;\n draft: {\n text: string;\n attachments: readonly Attachment[];\n quote: QuoteInfo | undefined;\n };\n }\n | undefined;\n if (trailingUserLeaf) {\n const draft = {\n text: getThreadMessageText(trailingUserLeaf),\n attachments: trailingUserLeaf.attachments,\n quote: trailingUserLeaf.metadata.custom.quote as QuoteInfo | undefined,\n };\n if (this.composer.restoreDraft(draft)) {\n this.repository.deleteMessage(trailingUserLeaf.id);\n movedLeaf = { id: trailingUserLeaf.id, draft };\n }\n }\n if (!movedLeaf) this._notifySubscribers();\n\n // The resync commits what the cancel left (a kept optimistic message, the\n // restored branch) back to the store a macrotask later. The store may move\n // in that gap; a server settling the cancelled turn lands in the same\n // tick. Read the repository at flush time and re-apply the rollbacks to\n // it, instead of stamping a snapshot captured above over the newer state.\n setTimeout(() => {\n this.dropEmptyOptimisticHead();\n if (movedLeaf) {\n const current = this.repository.getMessages();\n if (current.at(-1)?.id === movedLeaf.id) {\n // Unanswered tail: the removal has not reached the store yet.\n this.repository.deleteMessage(movedLeaf.id);\n } else if (current.some((m) => m.id === movedLeaf.id)) {\n // The store kept the turn in the thread; take the untouched draft\n // back so the same content does not sit in both places.\n this.composer.retractDraft(movedLeaf.draft);\n }\n }\n this.updateMessages(this.repository.getMessages());\n }, 0);\n }\n\n // Placeholder or pre-stream message; a partially-streamed one is kept and\n // committed to the store by the cancel resync.\n private dropEmptyOptimisticHead(): void {\n const head = this.repository.getMessages().at(-1);\n if (head && head.metadata.isOptimistic && head.content.length === 0) {\n this.repository.deleteMessage(head.id);\n }\n }\n\n public addToolResult(options: AddToolResultOptions) {\n if (!this._store.onAddToolResult)\n throw new Error(\"Runtime does not support tool results.\");\n observeAdapterCallback(\n \"onAddToolResult\",\n this._store.onAddToolResult(options),\n );\n }\n\n public resumeToolCall(options: ResumeToolCallOptions) {\n // Tracker owns its own human-input handlers — let it resume in-process\n // tool calls without round-tripping through the adapter. Falls back to\n // the adapter's onResumeToolCall (if any) for tool calls the tracker\n // doesn't know about.\n const handled =\n this._toolInvocations?.resume(options.toolCallId, options.payload) ??\n false;\n if (handled) return;\n\n if (this._store.onResumeToolCall) {\n this._store.onResumeToolCall(options);\n return;\n }\n\n throw new Error(\n `Tool call ${options.toolCallId} is not waiting for resume.`,\n );\n }\n\n public respondToToolApproval(options: RespondToToolApprovalOptions) {\n if (!this._store.onRespondToToolApproval)\n throw new Error(\"Runtime does not support tool approvals.\");\n observeAdapterCallback(\n \"onRespondToToolApproval\",\n this._store.onRespondToToolApproval(options),\n );\n }\n\n public override reset(initialMessages?: readonly ThreadMessageLike[]) {\n const repo = new MessageRepository();\n repo.import(ExportedMessageRepository.fromArray(initialMessages ?? []));\n this.updateMessages(repo.getMessages());\n }\n\n public override import(data: ExportedMessageRepository) {\n super.import(data);\n\n if (this._store.onImport) {\n this._store.onImport(this.repository.getMessages());\n }\n }\n\n private updateMessages = (messages: readonly ThreadMessage[]) => {\n const hasConverter = this._store.convertMessage !== undefined;\n if (hasConverter) {\n this._store.setMessages?.(messages.flatMap(getExternalStoreMessages));\n } else {\n // TODO mark this as readonly in v0.12.0\n this._store.setMessages?.(messages as ThreadMessage[]);\n }\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"external-store-thread-runtime-core.js","names":["AppendMessage","ThreadMessage","Attachment","AddToolResultOptions","ResumeRunConfig","ResumeToolCallOptions","RespondToToolApprovalOptions","StartRunConfig","ThreadSuggestion","ExternalStoreAdapter","ExternalStoreBranchChange","getExternalStoreMessages","bindExternalStoreMessage","ThreadMessageConverter","getAutoStatus","isAutoStatus","fromThreadMessageLike","ThreadMessageLike","getThreadMessageText","RuntimeCapabilities","ThreadRuntimeCore","ExternalThreadQueueAdapter","QueuePlacement","BaseThreadRuntimeCore","ModelContextProvider","ExportedMessageRepository","MessageRepository","generateId","ToolInvocationTracker","EMPTY_QUEUE_ITEMS","QuoteInfo","captureThreadRuntimeGeneration","isThreadRuntimeGenerationCurrent","EMPTY_ARRAY","Object","freeze","observeAdapterCallback","name","result","Promise","resolve","catch","error","console","shallowEqual","a","b","aKeys","keys","length","key","hasUpcomingMessage","isRunning","messages","role","ExternalStoreThreadRuntimeCore","_capabilities","switchToBranch","switchBranchDuringRun","edit","delete","reload","refetchThread","cancel","unstable_copy","speech","dictation","voice","attachments","feedback","queue","capabilities","_messages","isDisabled","isSendDisabled","isLoading","_store","_getBaseMessages","state","adapters","unstable_refetchThread","onRefetchThread","undefined","suggestions","extras","_converter","_getInitializePromise","__internal_setGetInitializePromise","getPromise","_transformedQueue","_toolInvocations","beginEdit","messageId","onEdit","Error","constructor","contextProvider","store","__internal_setAdapter","oldStore","__internal_setDispatchTransform","message","parentId","at","id","enrichAppendMetadata","newSuggestions","newCapabilities","setMessages","onDelete","onReload","onCancel","unstable_capabilities","copy","messageRepository","_notifySubscribers","incoming","headId","repository","resetHead","getMessages","incomingIds","Set","map","addOrUpdateMessage","export","has","deleteMessage","convertMessage","convertMessages","cache","m","idx","isLast","autoStatus","status","messageLike","newMessage","toString","seenIds","deduped","i","warn","add","push","reverse","parent","ensureInitialized","_notifyEventSubscribers","optimisticId","content","metadata","isOptimistic","type","_driveToolInvocations","unstable_enableToolInvocations","reset","setToolStatuses","getModelContext","tools","onResult","command","_findMessageIdForToolCall","toolCallId","onAddToolResult","toolName","isError","artifact","modelContent","err","onStatusesChange","statuses","fromEntries","setState","_toolCallToMessageId","Map","_messagesForToolCallIndex","clear","visit","Array","isArray","part","set","get","branchId","onBranchChange","unstable_onBranchChange","previousHeadId","canonicalHeadId","updateMessages","_notifyBranchChange","event","visibleMessageIds","append","rawMessage","isEdit","sourceId","generation","initPromise","steer","enqueue","startRun","abort","onNew","messageIndex","findIndex","filter","getQueueItems","items","getSteerQueueItems","steerItems","moveQueueItem","queueItemId","placement","move","removeQueueItem","remove","config","resumeRun","onResume","exportExternalState","onExportExternalState","importExternalState","onLoadExternalState","unstable_notifySessionReset","__internal_notifyCancelled","cancelRun","dropEmptyOptimisticHead","previousMessage","trailingUserLeaf","every","movedLeaf","draft","text","quote","custom","composer","restoreDraft","setTimeout","current","some","retractDraft","head","addToolResult","options","resumeToolCall","handled","resume","payload","onResumeToolCall","respondToToolApproval","onRespondToToolApproval","initialMessages","repo","import","fromArray","data","onImport","hasConverter","flatMap"],"sources":["../../../src/runtimes/external-store/external-store-thread-runtime-core.ts"],"sourcesContent":["import type { AppendMessage, ThreadMessage } from \"../../types/message\";\nimport type { Attachment } from \"../../types/attachment\";\nimport type {\n AddToolResultOptions,\n ResumeRunConfig,\n ResumeToolCallOptions,\n RespondToToolApprovalOptions,\n StartRunConfig,\n ThreadSuggestion,\n} from \"../../runtime/interfaces/thread-runtime-core\";\n\nimport type {\n ExternalStoreAdapter,\n ExternalStoreBranchChange,\n} from \"./external-store-adapter\";\nimport {\n getExternalStoreMessages,\n bindExternalStoreMessage,\n} from \"../../runtime/utils/external-store-message\";\nimport { ThreadMessageConverter } from \"./thread-message-converter\";\nimport { getAutoStatus, isAutoStatus } from \"../../runtime/utils/auto-status\";\nimport {\n fromThreadMessageLike,\n type ThreadMessageLike,\n} from \"../../runtime/utils/thread-message-like\";\nimport { getThreadMessageText } from \"../../utils/text\";\nimport type {\n RuntimeCapabilities,\n ThreadRuntimeCore,\n} from \"../../runtime/interfaces/thread-runtime-core\";\nimport type {\n ExternalThreadQueueAdapter,\n QueuePlacement,\n} from \"../../runtime/queue/external-thread-queue-adapter\";\nimport { BaseThreadRuntimeCore } from \"../../runtime/base/base-thread-runtime-core\";\nimport type { ModelContextProvider } from \"../../model-context/types\";\nimport {\n ExportedMessageRepository,\n MessageRepository,\n} from \"../../runtime/utils/message-repository\";\nimport { generateId } from \"../../utils/id\";\nimport { ToolInvocationTracker } from \"../tool-invocations/ToolInvocationTracker\";\nimport { EMPTY_QUEUE_ITEMS } from \"../../store/scopes/queue-item\";\nimport type { QuoteInfo } from \"../../types/quote\";\nimport {\n captureThreadRuntimeGeneration,\n isThreadRuntimeGenerationCurrent,\n} from \"../../runtime/utils/thread-runtime-lifecycle\";\n\nconst EMPTY_ARRAY: readonly ThreadSuggestion[] = Object.freeze([]);\n\nconst observeAdapterCallback = (\n name: \"onAddToolResult\" | \"onRespondToToolApproval\" | \"onCancel\",\n result: Promise<void> | void,\n) => {\n void Promise.resolve(result).catch((error) => {\n console.error(\n `[ExternalStoreThreadRuntimeCore] ${name} callback rejected`,\n error,\n );\n });\n};\n\nconst shallowEqual = (a: object, b: object): boolean => {\n const aKeys = Object.keys(a);\n if (aKeys.length !== Object.keys(b).length) return false;\n for (const key of aKeys) {\n if ((a as any)[key] !== (b as any)[key]) return false;\n }\n return true;\n};\n\nexport const hasUpcomingMessage = (\n isRunning: boolean,\n messages: readonly ThreadMessage[],\n) => {\n return isRunning && messages[messages.length - 1]?.role !== \"assistant\";\n};\n\nexport class ExternalStoreThreadRuntimeCore\n extends BaseThreadRuntimeCore\n implements ThreadRuntimeCore\n{\n private _capabilities: RuntimeCapabilities = {\n switchToBranch: false,\n switchBranchDuringRun: false,\n edit: false,\n delete: false,\n reload: false,\n refetchThread: false,\n cancel: false,\n unstable_copy: false,\n speech: false,\n dictation: false,\n voice: false,\n attachments: false,\n feedback: false,\n queue: false,\n };\n\n public get capabilities() {\n return this._capabilities;\n }\n\n private _messages!: readonly ThreadMessage[];\n public isDisabled!: boolean;\n public isSendDisabled!: boolean;\n public get isLoading() {\n return this._store.isLoading ?? false;\n }\n // Unlike `isLoading`: pass `undefined` through to preserve the `getThreadState` fallback.\n public get isRunning(): boolean | undefined {\n return this._store.isRunning;\n }\n\n protected override _getBaseMessages(): readonly ThreadMessage[] {\n return this._messages;\n }\n\n public override get state() {\n return this._store.state ?? super.state;\n }\n\n public get adapters() {\n return this._store.adapters;\n }\n\n // A getter, not a method, so its presence tracks the adapter.\n public get unstable_refetchThread(): (() => Promise<void>) | undefined {\n if (!this._store.onRefetchThread) return undefined;\n return () => this._store.onRefetchThread!();\n }\n\n public suggestions: readonly ThreadSuggestion[] = [];\n public extras: unknown = undefined;\n\n private _converter = new ThreadMessageConverter();\n\n private _store!: ExternalStoreAdapter<any>;\n\n private _getInitializePromise?: () => Promise<unknown> | undefined;\n\n public __internal_setGetInitializePromise(\n getPromise: () => Promise<unknown> | undefined,\n ) {\n this._getInitializePromise = getPromise;\n }\n\n private _transformedQueue: ExternalThreadQueueAdapter | undefined;\n\n /**\n * Client-side tool-invocations pipeline. Constructed lazily on first\n * snapshot — only when `adapter.unstable_enableToolInvocations === true`.\n */\n private _toolInvocations: ToolInvocationTracker | null = null;\n\n public override beginEdit(messageId: string) {\n if (!this._store.onEdit)\n throw new Error(\"Runtime does not support editing.\");\n\n super.beginEdit(messageId);\n }\n\n constructor(\n contextProvider: ModelContextProvider,\n store: ExternalStoreAdapter<any>,\n ) {\n super(contextProvider);\n this.__internal_setAdapter(store);\n }\n\n public __internal_setAdapter(store: ExternalStoreAdapter<any>) {\n if (this._store === store) return;\n\n const isRunning = store.isRunning ?? false;\n this.isDisabled = store.isDisabled ?? false;\n this.isSendDisabled = store.isSendDisabled ?? false;\n\n const oldStore = this._store as ExternalStoreAdapter<any> | undefined;\n this._store = store;\n if (oldStore?.queue !== store.queue) {\n this._transformedQueue = undefined;\n store.queue?.__internal_setDispatchTransform?.((message) => {\n // Re-point at the tail, as LocalThreadRuntimeCore's driver does, so\n // the prefix gated against is the one the message lands on whatever\n // the host routes by. Queuing only ever accepts a tail append, so a\n // later tail is the same intent.\n const parentId = this.messages.at(-1)?.id ?? null;\n return this.enrichAppendMetadata({ ...message, parentId }, parentId);\n });\n if (store.queue?.__internal_setDispatchTransform)\n this._transformedQueue = store.queue;\n }\n if (this.extras !== store.extras) {\n this.extras = store.extras;\n }\n\n const newSuggestions = store.suggestions ?? EMPTY_ARRAY;\n if (!shallowEqual(this.suggestions, newSuggestions)) {\n this.suggestions = newSuggestions;\n }\n\n const newCapabilities: RuntimeCapabilities = {\n switchToBranch: this._store.setMessages !== undefined,\n switchBranchDuringRun: false,\n edit: this._store.onEdit !== undefined,\n delete:\n this._store.onDelete !== undefined ||\n this._store.setMessages !== undefined,\n reload: this._store.onReload !== undefined,\n refetchThread: this._store.onRefetchThread !== undefined,\n cancel: this._store.onCancel !== undefined,\n speech: this._store.adapters?.speech !== undefined,\n dictation: this._store.adapters?.dictation !== undefined,\n voice: this._store.adapters?.voice !== undefined,\n unstable_copy: this._store.unstable_capabilities?.copy !== false,\n attachments: !!this._store.adapters?.attachments,\n feedback: !!this._store.adapters?.feedback,\n queue: this._store.queue !== undefined,\n };\n if (!shallowEqual(this._capabilities, newCapabilities)) {\n this._capabilities = newCapabilities;\n }\n\n let messages: readonly ThreadMessage[];\n\n if (store.messageRepository) {\n // Handle messageRepository\n if (\n oldStore &&\n oldStore.isRunning === store.isRunning &&\n oldStore.messageRepository === store.messageRepository\n ) {\n this._notifySubscribers();\n return;\n }\n\n const incoming = store.messageRepository.messages;\n const headId =\n store.messageRepository.headId ?? incoming.at(-1)?.message.id ?? null;\n\n if (oldStore && oldStore.messageRepository === store.messageRepository) {\n this.repository.resetHead(headId);\n messages = this.repository.getMessages();\n } else {\n const incomingIds = new Set(incoming.map(({ message }) => message.id));\n for (const { message, parentId } of incoming) {\n this.repository.addOrUpdateMessage(parentId, message);\n }\n for (const { message } of this.repository.export().messages) {\n if (!incomingIds.has(message.id)) {\n this.repository.deleteMessage(message.id);\n }\n }\n this.repository.resetHead(headId);\n messages = this.repository.getMessages();\n }\n } else if (store.messages) {\n // Handle messages array\n\n if (oldStore) {\n // flush the converter cache when the convertMessage prop changes\n if (oldStore.convertMessage !== store.convertMessage) {\n this._converter = new ThreadMessageConverter();\n } else if (\n oldStore.isRunning === store.isRunning &&\n oldStore.messages === store.messages\n ) {\n this._notifySubscribers();\n // no conversion update\n return;\n }\n }\n\n messages = !store.convertMessage\n ? store.messages\n : this._converter.convertMessages(store.messages, (cache, m, idx) => {\n if (!store.convertMessage) return m;\n\n const isLast = idx === (store.messages?.length ?? 0) - 1;\n const autoStatus = getAutoStatus(\n isLast,\n isRunning,\n false,\n false,\n undefined,\n );\n\n if (\n cache &&\n (cache.role !== \"assistant\" ||\n !isAutoStatus(cache.status) ||\n cache.status === autoStatus)\n )\n return cache;\n\n const messageLike = store.convertMessage(m, idx);\n const newMessage = fromThreadMessageLike(\n messageLike,\n idx.toString(),\n autoStatus,\n );\n bindExternalStoreMessage(newMessage, m);\n return newMessage;\n });\n\n const seenIds = new Set<string>();\n const deduped: ThreadMessage[] = [];\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i]!;\n if (seenIds.has(message.id)) {\n console.warn(\n `ExternalStoreThreadRuntimeCore: duplicate message id \"${message.id}\" in the provided messages array; keeping the last occurrence.`,\n );\n continue;\n }\n seenIds.add(message.id);\n deduped.push(message);\n }\n if (deduped.length !== messages.length) messages = deduped.reverse();\n\n for (let i = 0; i < messages.length; i++) {\n const message = messages[i]!;\n const parent = messages[i - 1];\n this.repository.addOrUpdateMessage(parent?.id ?? null, message);\n }\n } else {\n throw new Error(\n \"ExternalStoreAdapter must provide either 'messages' or 'messageRepository'\",\n );\n }\n\n // Common logic for both paths\n if (messages.length > 0) this.ensureInitialized();\n\n if ((oldStore?.isRunning ?? false) !== (store.isRunning ?? false)) {\n if (store.isRunning) {\n this._notifyEventSubscribers(\"runStart\", {});\n } else {\n this._notifyEventSubscribers(\"runEnd\", {});\n }\n }\n\n // Append an optimistic placeholder while running but before a trailing\n // assistant message exists. resetHead evicts off-branch optimistic messages\n // (prior placeholders, mid-run id-swap siblings); export() never persists them.\n let optimisticId: string | null = null;\n if (hasUpcomingMessage(isRunning, messages)) {\n optimisticId = generateId();\n this.repository.addOrUpdateMessage(\n messages.at(-1)?.id ?? null,\n fromThreadMessageLike(\n { role: \"assistant\", content: [], metadata: { isOptimistic: true } },\n optimisticId,\n { type: \"running\" },\n ),\n );\n }\n\n this.repository.resetHead(optimisticId ?? messages.at(-1)?.id ?? null);\n\n this._messages = this.repository.getMessages();\n\n this._driveToolInvocations();\n\n this._notifySubscribers();\n }\n\n /**\n * Feed the current message snapshot into the tool-invocations tracker.\n * Opt-in via `adapter.unstable_enableToolInvocations: true`. The tracker\n * itself is fail-silent — see ToolInvocationTracker for the\n * state-transition contract.\n */\n private _driveToolInvocations(): void {\n if (!this._store.unstable_enableToolInvocations) {\n // Adapter did not opt in (default). If a tracker was previously\n // constructed (e.g. the adapter just toggled the flag off via a\n // dynamic swap), drop it so subsequent snapshots are no-ops.\n if (this._toolInvocations) {\n this._toolInvocations.reset();\n this._toolInvocations = null;\n this._store.setToolStatuses?.({});\n }\n return;\n }\n\n if (!this._toolInvocations) {\n this._toolInvocations = new ToolInvocationTracker(\n () => this.getModelContext().tools,\n {\n onResult: (command) => {\n try {\n const messageId = this._findMessageIdForToolCall(\n command.toolCallId,\n );\n if (messageId === undefined) {\n // The tool call no longer exists in the snapshot (e.g.\n // rolled back). Drop the result.\n return;\n }\n observeAdapterCallback(\n \"onAddToolResult\",\n this._store.onAddToolResult?.({\n messageId,\n toolCallId: command.toolCallId,\n toolName: command.toolName,\n result: command.result,\n isError: command.isError,\n ...(command.artifact !== undefined && {\n artifact: command.artifact,\n }),\n ...(command.modelContent !== undefined && {\n modelContent: command.modelContent,\n }),\n }),\n );\n } catch (err) {\n console.error(\n \"[ExternalStoreThreadRuntimeCore] onAddToolResult dispatch failed\",\n err,\n );\n }\n },\n onStatusesChange: (statuses) => {\n this._store.setToolStatuses?.(Object.fromEntries(statuses));\n },\n },\n );\n }\n\n this._toolInvocations.setState({\n messages: this._messages,\n isRunning: this._store.isRunning ?? false,\n ...(this._store.isLoading !== undefined && {\n isLoading: this._store.isLoading,\n }),\n });\n }\n\n /**\n * Lookup table from `toolCallId` to the owning assistant message's `id`,\n * rebuilt lazily when `_messages` changes (see `_messagesForToolCallIndex`).\n */\n private _toolCallToMessageId = new Map<string, string>();\n private _messagesForToolCallIndex: readonly ThreadMessage[] | null = null;\n\n /**\n * Look up the assistant message that owns a tool-call part. Lazily builds\n * (and caches) a `toolCallId → messageId` map keyed off the current\n * `_messages` reference, so onResult dispatches stay O(1) instead of\n * walking the full thread on every result.\n */\n private _findMessageIdForToolCall(toolCallId: string): string | undefined {\n if (this._messagesForToolCallIndex !== this._messages) {\n this._toolCallToMessageId.clear();\n const visit = (messages: readonly ThreadMessage[]): void => {\n for (const message of messages) {\n if (!Array.isArray(message.content)) continue;\n for (const part of message.content) {\n if (!part || part.type !== \"tool-call\") continue;\n this._toolCallToMessageId.set(part.toolCallId, message.id);\n if (part.messages) visit(part.messages);\n }\n }\n };\n visit(this._messages);\n this._messagesForToolCallIndex = this._messages;\n }\n return this._toolCallToMessageId.get(toolCallId);\n }\n\n public override switchToBranch(branchId: string): void {\n if (!this._store.setMessages)\n throw new Error(\"Runtime does not support switching branches.\");\n\n // Silently ignore branch switches while running\n if (this._store.isRunning) {\n return;\n }\n\n const onBranchChange = this._store.unstable_onBranchChange;\n const previousHeadId = onBranchChange\n ? this.repository.canonicalHeadId\n : null;\n\n this.repository.switchToBranch(branchId);\n this.updateMessages(this.repository.getMessages());\n if (onBranchChange) {\n this._notifyBranchChange(previousHeadId, onBranchChange);\n }\n }\n\n /**\n * Emit `unstable_onBranchChange` for an explicit branch switch. Reads the\n * canonical head from the repository (which skips optimistic/transient\n * messages) and de-dupes switches that leave the canonical head unchanged.\n * Comparing against the head observed just before the switch — rather than the\n * last emitted head — keeps a switch firing after an adapter resync moved the\n * head elsewhere in the meantime.\n */\n private _notifyBranchChange(\n previousHeadId: string | null,\n onBranchChange: (event: ExternalStoreBranchChange) => void,\n ): void {\n const headId = this.repository.canonicalHeadId;\n if (headId === previousHeadId) return;\n\n onBranchChange({\n headId,\n visibleMessageIds: this.repository.getMessages().map((m) => m.id),\n });\n }\n\n public async append(rawMessage: AppendMessage): Promise<void> {\n // sourceId marks an edit send; the parent may coincide with the head\n // after a resync (e.g. cancelRun dropped the edited message).\n const isEdit =\n rawMessage.sourceId != null ||\n rawMessage.parentId !== (this.messages.at(-1)?.id ?? null);\n\n // A transformed-queue send is stamped at flush; any other queue's\n // transform would gate against its own thread's messages, so those stamp\n // at send.\n const message =\n !isEdit &&\n this._store.queue &&\n this._store.queue === this._transformedQueue\n ? rawMessage\n : this.enrichAppendMetadata(rawMessage);\n\n const generation = captureThreadRuntimeGeneration(this);\n this.ensureInitialized();\n\n // The getter call is what starts thread initialization.\n const initPromise = this._getInitializePromise?.();\n\n // The queue driver dispatches through the host adapter, outside this\n // core, so the initialization barrier must run before a message can\n // enter the queue.\n if (!isEdit && this._store.queue) {\n if (initPromise) {\n await initPromise;\n }\n if (!isThreadRuntimeGenerationCurrent(this, generation)) return;\n\n // Buffering does not start a run, so the tool-abort below must wait\n // until the queue flushes. By then the prior run (and its tools) has\n // settled.\n if (message.steer ?? this._store.isRunning ?? false)\n this._store.queue.steer(message);\n else this._store.queue.enqueue(message);\n return;\n }\n\n // The optimistic insert lives inside the adapter's dispatch, so holding\n // `onNew` on initialization would keep the message off screen for the\n // whole roundtrip. Seams that need the remote identity await\n // `threadListItem.initialize()` themselves, and a rejection surfaces\n // there.\n void initPromise?.catch(() => {});\n\n // Auto-abort in-flight client-side tool executions when a new run is\n // about to start. Without this, a tool that finishes after the new turn\n // begins would feed a stale result into `onAddToolResult`, racing with\n // the new turn the user just initiated. `startRun` defaults to true for\n // user messages — matches the satellites' historical opt-in cancel\n // behavior, which is now built in.\n if (message.startRun ?? message.role === \"user\") {\n await this._toolInvocations?.abort();\n }\n if (!isThreadRuntimeGenerationCurrent(this, generation)) return;\n\n if (isEdit) {\n if (!this._store.onEdit)\n throw new Error(\"Runtime does not support editing messages.\");\n await this._store.onEdit(message);\n } else {\n await this._store.onNew(message);\n }\n }\n\n public async deleteMessage(messageId: string): Promise<void> {\n if (this._store.onDelete) {\n await this._store.onDelete(messageId);\n return;\n }\n\n if (!this._store.setMessages)\n throw new Error(\"Runtime does not support deleting messages.\");\n\n if (this._store.isRunning) {\n await this._toolInvocations?.abort();\n }\n\n const messages = this.repository.getMessages();\n const messageIndex = messages.findIndex((m) => m.id === messageId);\n if (messageIndex === -1) throw new Error(\"Message not found.\");\n\n this.updateMessages(messages.filter((message) => message.id !== messageId));\n }\n\n public getQueueItems() {\n // The composer reads this during base-thread construction, before the\n // constructor assigns `_store`, so guard against the unset field.\n return this._store?.queue?.items ?? EMPTY_QUEUE_ITEMS;\n }\n\n public getSteerQueueItems() {\n return this._store?.queue?.steerItems ?? EMPTY_QUEUE_ITEMS;\n }\n\n public moveQueueItem(queueItemId: string, placement: QueuePlacement) {\n this._store?.queue?.move(queueItemId, placement);\n }\n\n public removeQueueItem(queueItemId: string) {\n this._store?.queue?.remove(queueItemId);\n }\n\n public async startRun(config: StartRunConfig): Promise<void> {\n if (!this._store.onReload)\n throw new Error(\"Runtime does not support reloading messages.\");\n\n // Auto-abort in-flight client-side tool executions when a run reloads;\n // any results that land afterward would target a turn that no longer\n // exists. See `append` above for full rationale.\n await this._toolInvocations?.abort();\n\n await this._store.onReload(config.parentId, config);\n }\n\n public async resumeRun(config: ResumeRunConfig): Promise<void> {\n if (!this._store.onResume)\n throw new Error(\"Runtime does not support resuming runs.\");\n\n await this._store.onResume(config);\n }\n\n public exportExternalState(): any {\n if (!this._store.onExportExternalState)\n throw new Error(\"Runtime does not support exporting external states.\");\n\n return this._store.onExportExternalState();\n }\n\n public importExternalState(state: any): void {\n if (!this._store.onLoadExternalState)\n throw new Error(\"Runtime does not support importing external states.\");\n\n // Re-arm the tracker so the next adapter snapshot (containing the\n // imported state) is treated as historical — no streamCall/execute\n // fires for the loaded tool calls. The adapter is expected to update\n // its messages in response to onLoadExternalState; that update flows\n // back here via __internal_setAdapter. The tracker publishes the\n // cleared status map itself, so adapter-side statuses reset only when\n // the tracker is the source of truth.\n this._toolInvocations?.reset();\n\n this._store.onLoadExternalState(state);\n }\n\n /**\n * Adapter-facing notification that the backing session was discarded.\n * Clears session-scoped tool-invocation state and parks queued work,\n * without run-cancel semantics (`onCancel`, composer draft restoration).\n */\n public unstable_notifySessionReset(): void {\n this._toolInvocations?.reset();\n this._store.queue?.__internal_notifyCancelled?.();\n }\n\n public cancelRun(): void {\n if (!this._store.onCancel)\n throw new Error(\"Runtime does not support cancelling runs.\");\n\n const generation = captureThreadRuntimeGeneration(this);\n\n // Abort any in-flight client-side tool executions. Fire-and-forget —\n // the abort resolves once executions settle, but we don't gate the\n // cancel on it.\n void this._toolInvocations?.abort();\n\n // Before the run is aborted, so the settle it produces keeps the pending\n // items instead of dispatching the next one at the moment the user\n // stopped.\n this._store.queue?.__internal_notifyCancelled?.();\n\n observeAdapterCallback(\"onCancel\", this._store.onCancel());\n\n this.dropEmptyOptimisticHead();\n\n const messages = this.repository.getMessages();\n const previousMessage = messages[messages.length - 1];\n const trailingUserLeaf =\n this._store.setMessages !== undefined &&\n previousMessage?.role === \"user\" &&\n previousMessage.id === messages.at(-1)?.id && // ensure the previous message is a leaf node\n previousMessage.content.every((part) => part.type === \"text\")\n ? previousMessage\n : undefined;\n\n // Handing the message to the composer and taking it out of the thread are\n // one move: the composer refuses while the user is writing, and removing\n // the message then would leave it nowhere. A message the composer cannot\n // hold whole, carrying content parts it has no home for, is not moved.\n let movedLeaf:\n | {\n id: string;\n draft: {\n text: string;\n attachments: readonly Attachment[];\n quote: QuoteInfo | undefined;\n };\n }\n | undefined;\n if (trailingUserLeaf) {\n const draft = {\n text: getThreadMessageText(trailingUserLeaf),\n attachments: trailingUserLeaf.attachments,\n quote: trailingUserLeaf.metadata.custom.quote as QuoteInfo | undefined,\n };\n if (this.composer.restoreDraft(draft)) {\n this.repository.deleteMessage(trailingUserLeaf.id);\n movedLeaf = { id: trailingUserLeaf.id, draft };\n }\n }\n if (!movedLeaf) this._notifySubscribers();\n\n // The resync commits what the cancel left (a kept optimistic message, the\n // restored branch) back to the store a macrotask later. The store may move\n // in that gap; a server settling the cancelled turn lands in the same\n // tick. Read the repository at flush time and re-apply the rollbacks to\n // it, instead of stamping a snapshot captured above over the newer state.\n setTimeout(() => {\n if (!isThreadRuntimeGenerationCurrent(this, generation)) return;\n\n this.dropEmptyOptimisticHead();\n if (movedLeaf) {\n const current = this.repository.getMessages();\n if (current.at(-1)?.id === movedLeaf.id) {\n // Unanswered tail: the removal has not reached the store yet.\n this.repository.deleteMessage(movedLeaf.id);\n } else if (current.some((m) => m.id === movedLeaf.id)) {\n // The store kept the turn in the thread; take the untouched draft\n // back so the same content does not sit in both places.\n this.composer.retractDraft(movedLeaf.draft);\n }\n }\n this.updateMessages(this.repository.getMessages());\n }, 0);\n }\n\n // Placeholder or pre-stream message; a partially-streamed one is kept and\n // committed to the store by the cancel resync.\n private dropEmptyOptimisticHead(): void {\n const head = this.repository.getMessages().at(-1);\n if (head && head.metadata.isOptimistic && head.content.length === 0) {\n this.repository.deleteMessage(head.id);\n }\n }\n\n public addToolResult(options: AddToolResultOptions) {\n if (!this._store.onAddToolResult)\n throw new Error(\"Runtime does not support tool results.\");\n observeAdapterCallback(\n \"onAddToolResult\",\n this._store.onAddToolResult(options),\n );\n }\n\n public resumeToolCall(options: ResumeToolCallOptions) {\n // Tracker owns its own human-input handlers — let it resume in-process\n // tool calls without round-tripping through the adapter. Falls back to\n // the adapter's onResumeToolCall (if any) for tool calls the tracker\n // doesn't know about.\n const handled =\n this._toolInvocations?.resume(options.toolCallId, options.payload) ??\n false;\n if (handled) return;\n\n if (this._store.onResumeToolCall) {\n this._store.onResumeToolCall(options);\n return;\n }\n\n throw new Error(\n `Tool call ${options.toolCallId} is not waiting for resume.`,\n );\n }\n\n public respondToToolApproval(options: RespondToToolApprovalOptions) {\n if (!this._store.onRespondToToolApproval)\n throw new Error(\"Runtime does not support tool approvals.\");\n observeAdapterCallback(\n \"onRespondToToolApproval\",\n this._store.onRespondToToolApproval(options),\n );\n }\n\n public override reset(initialMessages?: readonly ThreadMessageLike[]) {\n const repo = new MessageRepository();\n repo.import(ExportedMessageRepository.fromArray(initialMessages ?? []));\n this.updateMessages(repo.getMessages());\n }\n\n public override import(data: ExportedMessageRepository) {\n super.import(data);\n\n if (this._store.onImport) {\n this._store.onImport(this.repository.getMessages());\n }\n }\n\n private updateMessages = (messages: readonly ThreadMessage[]) => {\n const hasConverter = this._store.convertMessage !== undefined;\n if (hasConverter) {\n this._store.setMessages?.(messages.flatMap(getExternalStoreMessages));\n } else {\n // TODO mark this as readonly in v0.12.0\n this._store.setMessages?.(messages as ThreadMessage[]);\n }\n };\n}\n"],"mappings":"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"}