@athenaintel/react 0.53.1 → 0.55.0

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 (196) hide show
  1. package/README.md +37 -1
  2. package/dist/agent-runtime/src/call-recap.cjs +2 -3
  3. package/dist/agent-runtime/src/call-recap.cjs.map +1 -1
  4. package/dist/agent-runtime/src/call-recap.d.ts +1 -2
  5. package/dist/agent-runtime/src/call-recap.js +1 -2
  6. package/dist/agent-runtime/src/call-recap.js.map +1 -1
  7. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs +7 -3
  8. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
  9. package/dist/agent-runtime/src/deep-agent-transport-recipe.d.ts +10 -2
  10. package/dist/agent-runtime/src/deep-agent-transport-recipe.js +8 -4
  11. package/dist/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
  12. package/dist/agent-runtime/src/dictation-session.d.ts +158 -0
  13. package/dist/agent-runtime/src/edit-command.cjs +15 -3
  14. package/dist/agent-runtime/src/edit-command.cjs.map +1 -1
  15. package/dist/agent-runtime/src/edit-command.d.ts +8 -0
  16. package/dist/agent-runtime/src/edit-command.js +15 -3
  17. package/dist/agent-runtime/src/edit-command.js.map +1 -1
  18. package/dist/agent-runtime/src/generated/runconfig-contract.cjs +10 -0
  19. package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
  20. package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +25 -1
  21. package/dist/agent-runtime/src/generated/runconfig-contract.js +10 -0
  22. package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
  23. package/dist/agent-runtime/src/history-pages.cjs +279 -0
  24. package/dist/agent-runtime/src/history-pages.cjs.map +1 -0
  25. package/dist/agent-runtime/src/history-pages.d.ts +252 -0
  26. package/dist/agent-runtime/src/history-pages.js +279 -0
  27. package/dist/agent-runtime/src/history-pages.js.map +1 -0
  28. package/dist/agent-runtime/src/index.d.ts +8 -7
  29. package/dist/agent-runtime/src/message-window.cjs +111 -7
  30. package/dist/agent-runtime/src/message-window.cjs.map +1 -1
  31. package/dist/agent-runtime/src/message-window.d.ts +66 -6
  32. package/dist/agent-runtime/src/message-window.js +112 -8
  33. package/dist/agent-runtime/src/message-window.js.map +1 -1
  34. package/dist/agent-runtime/src/offline-status.cjs.map +1 -1
  35. package/dist/agent-runtime/src/offline-status.d.ts +64 -2
  36. package/dist/agent-runtime/src/offline-status.js.map +1 -1
  37. package/dist/agent-runtime/src/runtime.d.ts +4 -3
  38. package/dist/agent-runtime/src/subagent-transcripts.cjs +23 -1
  39. package/dist/agent-runtime/src/subagent-transcripts.cjs.map +1 -1
  40. package/dist/agent-runtime/src/subagent-transcripts.js +25 -3
  41. package/dist/agent-runtime/src/subagent-transcripts.js.map +1 -1
  42. package/dist/agent-runtime/src/subagents.cjs +112 -0
  43. package/dist/agent-runtime/src/subagents.cjs.map +1 -1
  44. package/dist/agent-runtime/src/subagents.d.ts +103 -0
  45. package/dist/agent-runtime/src/subagents.js +113 -1
  46. package/dist/agent-runtime/src/subagents.js.map +1 -1
  47. package/dist/agent-runtime/src/thread-handoff-protocol.d.ts +37 -9
  48. package/dist/agent-runtime/src/thread-handoff.d.ts +1 -1
  49. package/dist/agent-runtime/src/tool-metadata.cjs +8 -0
  50. package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
  51. package/dist/agent-runtime/src/tool-metadata.js +8 -0
  52. package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
  53. package/dist/agent-runtime/src/use-deep-agent-thread.cjs +22 -2
  54. package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  55. package/dist/agent-runtime/src/use-deep-agent-thread.d.ts +9 -1
  56. package/dist/agent-runtime/src/use-deep-agent-thread.js +23 -3
  57. package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
  58. package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs +106 -25
  59. package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs.map +1 -1
  60. package/dist/agent-runtime/src/use-deep-agent-window-sync.d.ts +41 -6
  61. package/dist/agent-runtime/src/use-deep-agent-window-sync.js +109 -28
  62. package/dist/agent-runtime/src/use-deep-agent-window-sync.js.map +1 -1
  63. package/dist/agent-runtime/src/use-thread-handoff-flow.d.ts +5 -9
  64. package/dist/agent-runtime/src/voice-presentation.cjs +34 -0
  65. package/dist/agent-runtime/src/voice-presentation.cjs.map +1 -1
  66. package/dist/agent-runtime/src/voice-presentation.d.ts +35 -0
  67. package/dist/agent-runtime/src/voice-presentation.js +34 -0
  68. package/dist/agent-runtime/src/voice-presentation.js.map +1 -1
  69. package/dist/assets/AthenaAssetEmbed.cjs +4 -2
  70. package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
  71. package/dist/assets/AthenaAssetEmbed.d.ts +17 -8
  72. package/dist/assets/AthenaAssetEmbed.js +4 -2
  73. package/dist/assets/AthenaAssetEmbed.js.map +1 -1
  74. package/dist/assets/use-asset-embed.cjs.map +1 -1
  75. package/dist/assets/use-asset-embed.d.ts +7 -5
  76. package/dist/assets/use-asset-embed.js.map +1 -1
  77. package/dist/auth/account-identity.cjs +69 -0
  78. package/dist/auth/account-identity.cjs.map +1 -0
  79. package/dist/auth/account-identity.d.ts +57 -0
  80. package/dist/auth/account-identity.js +69 -0
  81. package/dist/auth/account-identity.js.map +1 -0
  82. package/dist/chat/AthenaChat.cjs +1 -1
  83. package/dist/chat/AthenaChat.cjs.map +1 -1
  84. package/dist/chat/AthenaChat.js +1 -1
  85. package/dist/chat/AthenaChat.js.map +1 -1
  86. package/dist/chat/super-grouping/SuperGroupingCard.cjs +51 -43
  87. package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
  88. package/dist/chat/super-grouping/SuperGroupingCard.js +51 -43
  89. package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
  90. package/dist/chat/super-grouping/SuperGroupingTranscript.cjs +9 -4
  91. package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
  92. package/dist/chat/super-grouping/SuperGroupingTranscript.js +9 -4
  93. package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
  94. package/dist/chat/super-grouping/activity-timeline.cjs +7 -4
  95. package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
  96. package/dist/chat/super-grouping/activity-timeline.d.ts +10 -1
  97. package/dist/chat/super-grouping/activity-timeline.js +7 -4
  98. package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
  99. package/dist/chat/super-grouping/earlier-steps-button.cjs +50 -0
  100. package/dist/chat/super-grouping/earlier-steps-button.cjs.map +1 -0
  101. package/dist/chat/super-grouping/earlier-steps-button.d.ts +11 -0
  102. package/dist/chat/super-grouping/earlier-steps-button.js +50 -0
  103. package/dist/chat/super-grouping/earlier-steps-button.js.map +1 -0
  104. package/dist/chat/super-grouping/toolkit-map.cjs +1 -0
  105. package/dist/chat/super-grouping/toolkit-map.cjs.map +1 -1
  106. package/dist/chat/super-grouping/toolkit-map.js +1 -0
  107. package/dist/chat/super-grouping/toolkit-map.js.map +1 -1
  108. package/dist/chat/super-grouping/use-turn-steps.cjs +28 -0
  109. package/dist/chat/super-grouping/use-turn-steps.cjs.map +1 -0
  110. package/dist/chat/super-grouping/use-turn-steps.d.ts +23 -0
  111. package/dist/chat/super-grouping/use-turn-steps.js +28 -0
  112. package/dist/chat/super-grouping/use-turn-steps.js.map +1 -0
  113. package/dist/chat/use-statewire-approval-request.cjs +5 -5
  114. package/dist/chat/use-statewire-approval-request.cjs.map +1 -1
  115. package/dist/chat/use-statewire-approval-request.d.ts +7 -0
  116. package/dist/chat/use-statewire-approval-request.js +5 -5
  117. package/dist/chat/use-statewire-approval-request.js.map +1 -1
  118. package/dist/chat-ui/mentions/use-account-workspace-id.cjs +18 -58
  119. package/dist/chat-ui/mentions/use-account-workspace-id.cjs.map +1 -1
  120. package/dist/chat-ui/mentions/use-account-workspace-id.js +18 -58
  121. package/dist/chat-ui/mentions/use-account-workspace-id.js.map +1 -1
  122. package/dist/chat-ui/messages/voice-delegation-card.cjs +93 -25
  123. package/dist/chat-ui/messages/voice-delegation-card.cjs.map +1 -1
  124. package/dist/chat-ui/messages/voice-delegation-card.d.ts +16 -7
  125. package/dist/chat-ui/messages/voice-delegation-card.js +95 -27
  126. package/dist/chat-ui/messages/voice-delegation-card.js.map +1 -1
  127. package/dist/chat-ui/statewire.cjs +6 -0
  128. package/dist/chat-ui/statewire.cjs.map +1 -1
  129. package/dist/chat-ui/statewire.d.ts +3 -1
  130. package/dist/chat-ui/statewire.js +7 -1
  131. package/dist/chat-ui/statewire.js.map +1 -1
  132. package/dist/chat-ui/thread/handoff-cursor.cjs +2 -2
  133. package/dist/chat-ui/thread/handoff-cursor.cjs.map +1 -1
  134. package/dist/chat-ui/thread/handoff-cursor.js +3 -3
  135. package/dist/chat-ui/thread/handoff-cursor.js.map +1 -1
  136. package/dist/chat-ui/thread/statewire-history-edge.cjs +4 -0
  137. package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
  138. package/dist/chat-ui/thread/statewire-history-edge.d.ts +11 -1
  139. package/dist/chat-ui/thread/statewire-history-edge.js +5 -1
  140. package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
  141. package/dist/collab/client.cjs +134 -7
  142. package/dist/collab/client.cjs.map +1 -1
  143. package/dist/collab/client.d.ts +44 -0
  144. package/dist/collab/client.js +134 -7
  145. package/dist/collab/client.js.map +1 -1
  146. package/dist/collab/index.d.ts +1 -1
  147. package/dist/composer/QuoteContext.cjs +3 -3
  148. package/dist/composer/QuoteContext.cjs.map +1 -1
  149. package/dist/composer/QuoteContext.js +3 -3
  150. package/dist/composer/QuoteContext.js.map +1 -1
  151. package/dist/keryx-http/src/initial-sync.cjs +121 -0
  152. package/dist/keryx-http/src/initial-sync.cjs.map +1 -0
  153. package/dist/keryx-http/src/initial-sync.d.ts +77 -0
  154. package/dist/keryx-http/src/initial-sync.js +104 -0
  155. package/dist/keryx-http/src/initial-sync.js.map +1 -0
  156. package/dist/keryx-http/src/unconfirmed-update-attributions.cjs +8 -0
  157. package/dist/keryx-http/src/unconfirmed-update-attributions.cjs.map +1 -1
  158. package/dist/keryx-http/src/unconfirmed-update-attributions.d.ts +6 -0
  159. package/dist/keryx-http/src/unconfirmed-update-attributions.js +8 -0
  160. package/dist/keryx-http/src/unconfirmed-update-attributions.js.map +1 -1
  161. package/dist/provider/AthenaProvider.cjs +11 -3
  162. package/dist/provider/AthenaProvider.cjs.map +1 -1
  163. package/dist/provider/AthenaProvider.js +12 -4
  164. package/dist/provider/AthenaProvider.js.map +1 -1
  165. package/dist/provider/statewire-window-context.cjs +6 -0
  166. package/dist/provider/statewire-window-context.cjs.map +1 -1
  167. package/dist/provider/statewire-window-context.d.ts +10 -1
  168. package/dist/provider/statewire-window-context.js +6 -0
  169. package/dist/provider/statewire-window-context.js.map +1 -1
  170. package/dist/react/package.json.cjs +1 -1
  171. package/dist/react/package.json.js +1 -1
  172. package/dist/runtime/useAthenaStatewireRuntime.cjs +2 -0
  173. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  174. package/dist/runtime/useAthenaStatewireRuntime.d.ts +7 -1
  175. package/dist/runtime/useAthenaStatewireRuntime.js +2 -0
  176. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  177. package/dist/styles.css +1 -1
  178. package/dist/threads/api.cjs +1 -2
  179. package/dist/threads/api.cjs.map +1 -1
  180. package/dist/threads/api.d.ts +3 -2
  181. package/dist/threads/api.js +1 -2
  182. package/dist/threads/api.js.map +1 -1
  183. package/dist/threads/sessions-query.cjs +2 -0
  184. package/dist/threads/sessions-query.cjs.map +1 -1
  185. package/dist/threads/sessions-query.js +2 -0
  186. package/dist/threads/sessions-query.js.map +1 -1
  187. package/dist/threads/statewire-thread-list.cjs +5 -7
  188. package/dist/threads/statewire-thread-list.cjs.map +1 -1
  189. package/dist/threads/statewire-thread-list.js +7 -9
  190. package/dist/threads/statewire-thread-list.js.map +1 -1
  191. package/dist/tools/subagent-task-tool-ui.cjs +15 -5
  192. package/dist/tools/subagent-task-tool-ui.cjs.map +1 -1
  193. package/dist/tools/subagent-task-tool-ui.d.ts +5 -4
  194. package/dist/tools/subagent-task-tool-ui.js +16 -6
  195. package/dist/tools/subagent-task-tool-ui.js.map +1 -1
  196. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"use-deep-agent-window-sync.cjs","sources":["../../../../agent-runtime/src/use-deep-agent-window-sync.ts"],"sourcesContent":["import type { StatewireThread } from '@assistant-ui/react-statewire';\nimport { useAuiState } from '@assistant-ui/store';\nimport { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';\nimport { DEEP_AGENT_INTEREST_PROTOCOL, DEEP_AGENT_MAX_MESSAGE_WINDOW } from './generated/runconfig-contract';\nimport {\n buildToolOutputCommand,\n type DeepAgentInterestRequest,\n type DeepAgentMessageWindow,\n interestsCovered,\n pageInterestRequests,\n readDeepAgentMessageWindow,\n readToolOutputResult,\n readTruncatedToolOutputArtifact,\n} from './message-window';\nimport { hasStatewireThreadExtras } from './thread-extras';\nimport type { DeepAgentToolOutputStore } from './tool-outputs';\n\n/**\n * Pages of older history chained per approach to the top. A renderer lowers\n * its near-top level once prepended content has pushed the first message out\n * of its band; this bounds the case where it cannot (no viewport to scroll,\n * a list too short to overflow) so a 2,000-message thread never streams whole.\n */\nexport const DEEP_AGENT_MAX_CHAINED_HISTORY_LOADS = 3;\n\n/**\n * Pages of older history that add no converted message — every message on\n * them folds into the first loaded turn, such as one agent run's hundreds of\n * tool steps — loaded on top of a request (or an approach's chain) before it\n * stops. Such a page changes nothing the user can see, so it neither answers\n * an ask nor counts against the per-approach chain.\n *\n * A page loaded while the oldest loaded message is a reply lands inside that\n * reply's turn, so it asks for the host's largest window\n * (`DEEP_AGENT_MAX_MESSAGE_WINDOW`) instead of the thread's: a run of 373\n * tool calls is about 750 messages, nineteen round trips at the default\n * window and four at the largest, and the turn shows nothing new until its\n * prompt does. A page above a prompt keeps the thread's window.\n */\nexport const DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS = 25;\n\n/** The converted thread messages the tool-output half scans (web and native `ThreadMessage` both satisfy it). */\nexport interface DeepAgentWindowSyncMessage {\n readonly id: string;\n /** The converted role; lets the opening fill tell a turn's prompt from its reply. */\n readonly role?: string;\n readonly content: readonly { readonly type: string; readonly artifact?: unknown }[];\n}\n\n/** One page interest round trip, for the host's telemetry. */\nexport interface DeepAgentHistoryLoadEvent {\n /** The page's ordinal (`1` extends the head). */\n page: number;\n request: DeepAgentInterestRequest;\n durationMs: number;\n}\n\nexport interface UseDeepAgentWindowSyncOptions {\n /**\n * The converted thread messages — read by the host through its platform\n * `useAuiState((s) => s.thread.messages)`, so this hook imports neither\n * `@assistant-ui/react` nor `@assistant-ui/react-native`.\n */\n messages: readonly DeepAgentWindowSyncMessage[];\n /** Messages per page; the thread's window size by default. */\n pageSize?: number;\n /**\n * Full tool outputs fetched back for cut tool messages; the same store the\n * thread converts with (`useDeepAgentThread({ toolOutputs })`). Omitted, the\n * tool-output half is inert (a surface that never shows a cut output whole).\n */\n toolOutputs?: DeepAgentToolOutputStore | undefined;\n /**\n * The renderer's report that the top of the LOADED history is near — a\n * level, not an edge: while it holds and older messages exist, pages load\n * one after another (bounded by `maxChainedLoads` per approach). Omitted for\n * hosts with only a manual affordance (`loadOlder`).\n */\n nearTop?: boolean;\n /** Bumped on every rise of `nearTop` (and every explicit request), so the chain bound is per approach. */\n nearTopEpoch?: number;\n /**\n * Whether a message's content is mounted right now, so lazy fetches (cut\n * tool outputs) target what the user can see rather than the whole loaded\n * history. Omitted: every message counts as mounted (the flat renderers).\n */\n isMessageMounted?: ((messageId: string) => boolean) | undefined;\n /**\n * Cut tool outputs this mount reads at once; the rest wait for one to\n * settle. One mounted message can hold a whole agent run — a hundred tool\n * steps — and the host rate-limits a client's frames, so a reader that sends\n * them all together gets refusals back for most of them. Omitted: every\n * mounted output is asked for together (renderers whose mounted set is\n * already small).\n */\n maxConcurrentToolOutputs?: number;\n maxChainedLoads?: number;\n /** Pages adding no converted message loaded per request before it stops; see {@link DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS}. */\n maxUnseenLoads?: number;\n /** A page interest resolved (telemetry). */\n onHistoryLoad?: ((event: DeepAgentHistoryLoadEvent) => void) | undefined;\n /** A read failed; the sync itself recovers (the pending marks are released). */\n onError?: ((error: unknown, command: 'athena/interest' | 'history/tool_output') => void) | undefined;\n now?: () => number;\n}\n\nexport interface DeepAgentWindowSyncState {\n /** The joined window, or `null` while the head interest has not resolved (both halves are inert). */\n window: DeepAgentMessageWindow | null;\n /** Whether the host holds messages older than the loaded window. */\n hasOlder: boolean;\n /**\n * Whether the next page can be asked for: older messages exist and the\n * host's interest cap has room for them. `hasOlder && !canLoadOlder` is the\n * depth limit (`MAX_INTERESTS × MAX_MESSAGE_WINDOW` messages loaded in one\n * connection) — an edge row says so instead of offering a dead button.\n */\n canLoadOlder: boolean;\n /** A page of older history is in flight. */\n loading: boolean;\n /** Ask for the next page of older history now (an edge row's button, a keypress). A no-op before the head resolved or at the beginning. */\n loadOlder: () => void;\n}\n\nconst everyMessageMounted = (): boolean => true;\nconst defaultNow = (): number => Date.now();\nconst noopSubscribe = () => () => {};\n\n/** The statewire extras of the nearest aui thread; throws on a non-statewire thread like the library's own hooks. */\nconst useStatewireExtras = (): StatewireThread.Extras =>\n useAuiState((s) => {\n if (!hasStatewireThreadExtras(s.thread.extras)) {\n throw new Error('useDeepAgentWindowSync requires a statewire thread');\n }\n return s.thread.extras as StatewireThread.Extras;\n });\n\n/** The joined interest window of the nearest statewire thread. */\nexport function useDeepAgentMessageWindow(): DeepAgentMessageWindow | null {\n const documents = useStatewireExtras().documents;\n const mounted = useSyncExternalStore(\n documents?.subscribe ?? noopSubscribe,\n () => documents?.list(),\n () => documents?.list()\n );\n return useMemo(() => readDeepAgentMessageWindow(mounted), [mounted]);\n}\n\n/**\n * The client half of the interest window, shared by every surface — mounted\n * once per runtime, inside its aui provider.\n *\n * - **Older history.** While the host renderer reports the top of the loaded\n * history near (`nearTop`) and the window says older messages exist, this\n * re-states the interests with one more page (anchored at the window's\n * first message) — the host mounts its documents for this client alone —\n * chaining at most `maxChainedLoads` pages per approach; `loadOlder` asks\n * for one page on demand (an edge row's button). Never two loads in flight.\n * A reconnect whose hello does not carry the interests this mount last\n * stated (the host remembers a client id's view across its attaches; a new\n * host instance does not) re-states them.\n * - **Cut tool outputs.** Tool cards whose output the wire carried cut\n * (`artifact._athena_content_truncated`) get it fetched whole through\n * `history/tool_output` once their message is mounted, at most\n * `maxConcurrentToolOutputs` at a time; the converter puts it back\n * (`toolOutputs`), so the card re-renders complete. An output the host\n * replaced since (the marker's `chars` changed) is fetched again.\n */\n/**\n * Whether an older page put a new converted message ahead of the thread's\n * first one. Older history only ever merges into or lands before the first\n * converted message, so the second one is a stable landmark: it moved down iff\n * the page showed something. A new tail message does not move it. Without a\n * second message (or once it is gone) the converted count decides.\n */\nfunction pageShowedEarlierMessage(\n from: { count: number; secondId: string | undefined },\n messages: readonly DeepAgentWindowSyncMessage[]\n): boolean {\n if (from.secondId !== undefined) {\n const index = messages.findIndex((message) => message.id === from.secondId);\n if (index !== -1) return index > 1;\n }\n return messages.length > from.count;\n}\n\n/** Whether a converted message is a turn's reply rather than its prompt (unknown without a role). */\nfunction isReply(message: DeepAgentWindowSyncMessage | undefined): boolean {\n return message?.role !== undefined && message.role !== 'user';\n}\n\n/**\n * Whether the loaded thread still opens without context: it should open on a\n * prompt and hold at least one earlier turn, so the newest turn shows with the\n * one before it (a turn is a prompt followed by its reply). Queued and live\n * prompts land at the tail with no reply yet, so they never count; prompts\n * alone need nothing. Without roles, a lone converted message stands in for it.\n */\nfunction opensMidTurn(messages: readonly DeepAgentWindowSyncMessage[]): boolean {\n const first = messages[0];\n if (first === undefined) return false;\n if (messages.every((message) => message.role === undefined)) return messages.length < 2;\n if (first.role !== 'user') return true;\n if (messages.every((message) => message.role === 'user')) return false;\n let turns = 0;\n for (let index = 1; index < messages.length; index += 1) {\n if (messages[index - 1]!.role === 'user' && messages[index]!.role !== 'user') turns += 1;\n }\n return turns < 2;\n}\n\nexport function useDeepAgentWindowSync({\n messages,\n pageSize,\n toolOutputs,\n nearTop = false,\n nearTopEpoch = 0,\n isMessageMounted = everyMessageMounted,\n maxConcurrentToolOutputs = Number.POSITIVE_INFINITY,\n maxChainedLoads = DEEP_AGENT_MAX_CHAINED_HISTORY_LOADS,\n maxUnseenLoads = DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS,\n onHistoryLoad,\n onError,\n now = defaultNow,\n}: UseDeepAgentWindowSyncOptions): DeepAgentWindowSyncState {\n const { sendCommand, invoke, connection } = useStatewireExtras();\n const window = useDeepAgentMessageWindow();\n const [loading, setLoading] = useState(false);\n const [requests, setRequests] = useState(0);\n const servedRequestsRef = useRef(0);\n const inflightRef = useRef(false);\n const chainRef = useRef({ epoch: 0, loads: 0, unseen: 0, requested: false });\n // Pages loaded to show the opening turn's prompt; `null` once it shows, the\n // user took over, or a page failed — never re-armed for this mount.\n const openingFillRef = useRef<number | null>(0);\n // The converted thread when the in-flight page was stated; `null` once its\n // settle was judged (or it failed).\n const pageFromRef = useRef<{ count: number; secondId: string | undefined } | null>(null);\n const aliveRef = useRef(true);\n // The interests this mount last stated, re-stated on the next connected\n // session (a hello resets the documents) so a reconnect keeps the loaded history.\n const statedRef = useRef<DeepAgentInterestRequest[] | null>(null);\n const restatedConnectionRef = useRef<unknown>(null);\n // Outputs already asked for and answered by this mount — fetched, refused,\n // or failed — by the `chars` they were asked for. The converter re-runs on\n // every wire change, and the store is a bounded LRU: without this memory a\n // refused read would leave on every pass, and once a transcript holds more\n // cut outputs than the store retains, each fetch would evict a still-loaded\n // output and the next pass would fetch it again, forever. An evicted output\n // renders its cut text (the REST display limit) rather than re-entering the\n // loop; a marker whose `chars` moved (the host replaced the output) is asked\n // for again.\n const answeredRef = useRef(new Map<string, number>());\n // Reads this mount has in flight, and whether a pass left outputs waiting\n // for one to settle (`maxConcurrentToolOutputs`): only then does a settle\n // re-run the pass, so an unbounded mount renders no more than before.\n const toolOutputsInFlightRef = useRef(0);\n const toolOutputsWaitingRef = useRef(false);\n const [toolOutputSettles, setToolOutputSettles] = useState(0);\n const onHistoryLoadRef = useRef(onHistoryLoad);\n onHistoryLoadRef.current = onHistoryLoad;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const nowRef = useRef(now);\n nowRef.current = now;\n useEffect(() => {\n aliveRef.current = true;\n return () => {\n aliveRef.current = false;\n };\n }, []);\n\n useEffect(() => {\n if (connection.status !== 'connected' || restatedConnectionRef.current === connection) return;\n // Decided once per connected session, on the hello's interest document.\n if (window === null) return;\n restatedConnectionRef.current = connection;\n const stated = statedRef.current;\n if (stated === null || interestsCovered(window.requests, stated)) return;\n invoke(DEEP_AGENT_INTEREST_PROTOCOL, 'set', [stated]).catch((error: unknown) => {\n onErrorRef.current?.(error, 'athena/interest');\n });\n }, [connection, invoke, window]);\n\n useEffect(() => {\n if (window === null || inflightRef.current) return;\n const from = pageFromRef.current;\n pageFromRef.current = null;\n const lastPageUnseen =\n from !== null && from.count > 0 && !pageShowedEarlierMessage(from, messages);\n const pageRequests = pageInterestRequests(window, pageSize);\n if (pageRequests === null) return;\n const requested = requests !== servedRequestsRef.current;\n const chain = chainRef.current;\n let fillPage = false;\n if (\n openingFillRef.current !== null &&\n (requested || nearTop || (messages.length > 0 && !opensMidTurn(messages)))\n ) {\n openingFillRef.current = null;\n }\n if (requested) {\n // An explicit ask re-arms the chain for this approach.\n servedRequestsRef.current = requests;\n chainRef.current = { epoch: nearTopEpoch, loads: 1, unseen: 0, requested: true };\n } else if (lastPageUnseen && (chain.requested || (nearTop && chain.epoch === nearTopEpoch))) {\n // The page landed inside the first loaded turn: keep going until one shows.\n if (chain.unseen >= maxUnseenLoads) return;\n chain.unseen += 1;\n } else if (openingFillRef.current !== null && opensMidTurn(messages)) {\n if (openingFillRef.current >= maxUnseenLoads) return;\n openingFillRef.current += 1;\n fillPage = true;\n } else {\n if (!nearTop) return;\n if (chain.epoch !== nearTopEpoch) {\n chainRef.current = { epoch: nearTopEpoch, loads: 0, unseen: 0, requested: false };\n }\n if (chainRef.current.loads >= maxChainedLoads) return;\n chainRef.current.loads += 1;\n }\n // The page continues the oldest loaded turn (see DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS).\n const insideTurn = lastPageUnseen || isReply(messages[0]);\n const stated =\n (insideTurn && pageInterestRequests(window, DEEP_AGENT_MAX_MESSAGE_WINDOW)) || pageRequests;\n pageFromRef.current = { count: messages.length, secondId: messages[1]?.id };\n const page = window.pages + 1;\n const request = stated[stated.length - 1] as DeepAgentInterestRequest;\n inflightRef.current = true;\n setLoading(true);\n const startedAt = nowRef.current();\n invoke(DEEP_AGENT_INTEREST_PROTOCOL, 'set', [stated])\n .then(() => {\n statedRef.current = stated;\n onHistoryLoadRef.current?.({\n page,\n request,\n durationMs: Math.max(0, Math.round(nowRef.current() - startedAt)),\n });\n })\n .catch((error: unknown) => {\n pageFromRef.current = null;\n if (fillPage) openingFillRef.current = null;\n onErrorRef.current?.(error, 'athena/interest');\n })\n .finally(() => {\n inflightRef.current = false;\n if (aliveRef.current) setLoading(false);\n });\n // `loading` re-arms the chain once a page settled after its documents moved the window.\n }, [\n nearTop,\n nearTopEpoch,\n requests,\n window,\n loading,\n messages,\n invoke,\n maxChainedLoads,\n maxUnseenLoads,\n pageSize,\n ]);\n\n useEffect(() => {\n if (window === null || toolOutputs === undefined) return;\n toolOutputsWaitingRef.current = false;\n for (const message of messages) {\n if (!isMessageMounted(message.id)) continue;\n for (const part of message.content) {\n if (part.type !== 'tool-call') continue;\n const marker = readTruncatedToolOutputArtifact(part.artifact);\n if (marker === null || toolOutputs.isPending(marker.messageId)) continue;\n // Fetched for this very length already; a different length means the\n // host replaced the output under the same id since.\n if (toolOutputs.entry(marker.messageId)?.chars === marker.chars) continue;\n if (answeredRef.current.get(marker.messageId) === marker.chars) continue;\n if (toolOutputsInFlightRef.current >= maxConcurrentToolOutputs) {\n toolOutputsWaitingRef.current = true;\n return;\n }\n const { messageId, chars } = marker;\n toolOutputsInFlightRef.current += 1;\n toolOutputs.markPending(messageId);\n Promise.resolve(sendCommand(buildToolOutputCommand({ messageId })))\n .then((payload) => {\n answeredRef.current.set(messageId, chars);\n const result = readToolOutputResult(payload);\n if (result === null) {\n toolOutputs.clearPending(messageId);\n return;\n }\n toolOutputs.set(result.messageId, { content: result.content, chars });\n })\n .catch((error: unknown) => {\n answeredRef.current.set(messageId, chars);\n toolOutputs.clearPending(messageId);\n onErrorRef.current?.(error, 'history/tool_output');\n })\n .finally(() => {\n toolOutputsInFlightRef.current -= 1;\n if (toolOutputsWaitingRef.current && aliveRef.current) {\n setToolOutputSettles((count) => count + 1);\n }\n });\n }\n }\n }, [\n messages,\n isMessageMounted,\n window,\n sendCommand,\n toolOutputs,\n maxConcurrentToolOutputs,\n toolOutputSettles,\n ]);\n\n const loadOlder = useCallback(() => {\n setRequests((count) => count + 1);\n }, []);\n\n const canLoadOlder = useMemo(\n () => window !== null && pageInterestRequests(window, pageSize) !== null,\n [window, pageSize]\n );\n\n return { window, hasOlder: window?.hasOlder ?? false, canLoadOlder, loading, loadOlder };\n}\n"],"names":["useAuiState","hasStatewireThreadExtras","useSyncExternalStore","useMemo","readDeepAgentMessageWindow","useState","useRef","useEffect","interestsCovered","DEEP_AGENT_INTEREST_PROTOCOL","pageInterestRequests","DEEP_AGENT_MAX_MESSAGE_WINDOW","_a","readTruncatedToolOutputArtifact","buildToolOutputCommand","readToolOutputResult","useCallback"],"mappings":"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"}
1
+ {"version":3,"file":"use-deep-agent-window-sync.cjs","sources":["../../../../agent-runtime/src/use-deep-agent-window-sync.ts"],"sourcesContent":["import type { StatewireThread } from '@assistant-ui/react-statewire';\nimport { useAuiState } from '@assistant-ui/store';\nimport { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';\nimport {\n DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION,\n DEEP_AGENT_INTEREST_PROTOCOL,\n DEEP_AGENT_MAX_MESSAGE_WINDOW,\n DEEP_AGENT_OVERSIZED_INTEREST_CODE,\n} from './generated/runconfig-contract';\nimport {\n DEEP_AGENT_HISTORY_PAGE_TURNS,\n type DeepAgentHistorySnapshot,\n type DeepAgentHistoryStore,\n} from './history-pages';\nimport {\n buildToolOutputCommand,\n type DeepAgentInterestRequest,\n type DeepAgentMessageWindow,\n messageWindowCarries,\n pageInterestRequests,\n readDeepAgentMessageWindow,\n readToolOutputResult,\n readTruncatedToolOutputArtifact,\n restatedInterestRequests,\n} from './message-window';\nimport { readDeepAgentProtocol } from './protocol';\nimport { hasStatewireThreadExtras } from './thread-extras';\nimport type { DeepAgentToolOutputStore } from './tool-outputs';\n\n/**\n * Pages of older history chained per approach to the top. A renderer lowers\n * its near-top level once prepended content has pushed the first message out\n * of its band; this bounds the case where it cannot (no viewport to scroll,\n * a list too short to overflow) so a 2,000-message thread never streams whole.\n */\nexport const DEEP_AGENT_MAX_CHAINED_HISTORY_LOADS = 3;\n\n/**\n * Pages of older history that add no converted message — every message on\n * them folds into the first loaded turn, such as one agent run's hundreds of\n * tool steps — loaded on top of a request (or an approach's chain) before it\n * stops. Such a page changes nothing the user can see, so it neither answers\n * an ask nor counts against the per-approach chain.\n *\n * A page loaded while the oldest loaded message is a reply lands inside that\n * reply's turn, so it asks for the host's largest window\n * (`DEEP_AGENT_MAX_MESSAGE_WINDOW`) instead of the thread's: a run of 373\n * tool calls is about 750 messages, nineteen round trips at the default\n * window and four at the largest, and the turn shows nothing new until its\n * prompt does. A page above a prompt keeps the thread's window.\n */\nexport const DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS = 25;\n\n/** The converted thread messages the tool-output half scans (web and native `ThreadMessage` both satisfy it). */\nexport interface DeepAgentWindowSyncMessage {\n readonly id: string;\n /** The converted role; lets the opening fill tell a turn's prompt from its reply. */\n readonly role?: string;\n readonly content: readonly { readonly type: string; readonly artifact?: unknown }[];\n}\n\n/** One page interest round trip, for the host's telemetry. */\nexport interface DeepAgentHistoryLoadEvent {\n /** The page's ordinal (`1` extends the head). */\n page: number;\n request: DeepAgentInterestRequest;\n durationMs: number;\n}\n\n/** One `history/page` round trip, for the host's telemetry. */\nexport interface DeepAgentHistoryPageEvent {\n /** The message the page was asked before. */\n before: string;\n /** Turns asked for, and answered. */\n turns: number;\n answered: number;\n durationMs: number;\n}\n\nexport interface UseDeepAgentWindowSyncOptions {\n /**\n * The converted thread messages — read by the host through its platform\n * `useAuiState((s) => s.thread.messages)`, so this hook imports neither\n * `@assistant-ui/react` nor `@assistant-ui/react-native`.\n */\n messages: readonly DeepAgentWindowSyncMessage[];\n /** Messages per page; the thread's window size by default. */\n pageSize?: number;\n /**\n * Full tool outputs fetched back for cut tool messages; the same store the\n * thread converts with (`useDeepAgentThread({ toolOutputs })`). Omitted, the\n * tool-output half is inert (a surface that never shows a cut output whole).\n */\n toolOutputs?: DeepAgentToolOutputStore | undefined;\n /**\n * The renderer's report that the top of the LOADED history is near — a\n * level, not an edge: while it holds and older messages exist, pages load\n * one after another (bounded by `maxChainedLoads` per approach). Omitted for\n * hosts with only a manual affordance (`loadOlder`).\n */\n nearTop?: boolean;\n /** Bumped on every rise of `nearTop` (and every explicit request), so the chain bound is per approach. */\n nearTopEpoch?: number;\n /**\n * Whether a message's content is mounted right now, so lazy fetches (cut\n * tool outputs) target what the user can see rather than the whole loaded\n * history. Omitted: every message counts as mounted (the flat renderers).\n */\n isMessageMounted?: ((messageId: string) => boolean) | undefined;\n /**\n * Cut tool outputs this mount reads at once; the rest wait for one to\n * settle. One mounted message can hold a whole agent run — a hundred tool\n * steps — and the host rate-limits a client's frames, so a reader that sends\n * them all together gets refusals back for most of them. Omitted: every\n * mounted output is asked for together (renderers whose mounted set is\n * already small).\n */\n maxConcurrentToolOutputs?: number;\n maxChainedLoads?: number;\n /** Pages adding no converted message loaded per request before it stops; see {@link DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS}. */\n maxUnseenLoads?: number;\n /** A page interest resolved (telemetry). */\n onHistoryLoad?: ((event: DeepAgentHistoryLoadEvent) => void) | undefined;\n /**\n * Older turns paged by command (`history/page`, protocol 3) into this store:\n * the same one the thread joins in front of its live window\n * (`useDeepAgentThread({ historyStore })`). Used only against a host that\n * advertises `DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION`; there every older\n * page (the button, the near-top chain, the opening fill) is a `history/page`\n * of whole turns and no interest page is stated, so the attach's view stays\n * the head however far back the reader goes. Omitted, or an older host:\n * interest pages, as before.\n */\n historyPages?: DeepAgentHistoryStore | undefined;\n /** Turns one history page asks for. */\n historyPageTurns?: number;\n /** A history page resolved (telemetry). */\n onHistoryPage?: ((event: DeepAgentHistoryPageEvent) => void) | undefined;\n /** A read failed; the sync itself recovers (the pending marks are released). */\n onError?:\n | ((error: unknown, command: 'athena/interest' | 'history/page' | 'history/tool_output') => void)\n | undefined;\n now?: () => number;\n}\n\nexport interface DeepAgentWindowSyncState {\n /** The joined window, or `null` while the head interest has not resolved (both halves are inert). */\n window: DeepAgentMessageWindow | null;\n /** Whether the host holds messages older than the loaded window. */\n hasOlder: boolean;\n /**\n * Whether the next page can be asked for: older messages exist and the\n * view has room for them. `hasOlder && !canLoadOlder` is the depth limit —\n * an edge row says so instead of offering a dead button. The host bounds\n * one attach's view twice: `MAX_INTERESTS` requests, and an interest\n * document that lists every loaded message within a byte budget (about a\n * thousand messages). The second is found when the host refuses a page as\n * `oversized-interest` ({@link isOversizedInterestRejection}).\n */\n canLoadOlder: boolean;\n /** A page of older history is in flight. */\n loading: boolean;\n /** Ask for the next page of older history now (an edge row's button, a keypress). A no-op before the head resolved, at the beginning, or once `canLoadOlder` is false. */\n loadOlder: () => void;\n}\n\n/**\n * Whether an `athena/interest` `set` came back refused because the windows it\n * states resolve past what one attach's interest document carries: the view\n * is as deep as this connection can load, and asking again only gets the same\n * refusal.\n */\nexport function isOversizedInterestRejection(error: unknown): boolean {\n const failure = (error as { failure?: { fate?: unknown; code?: unknown } } | null | undefined)\n ?.failure;\n return failure?.fate === 'rejected' && failure.code === DEEP_AGENT_OVERSIZED_INTEREST_CODE;\n}\n\nconst everyMessageMounted = (): boolean => true;\nconst defaultNow = (): number => Date.now();\nconst noopSubscribe = () => () => {};\n\n/** The statewire extras of the nearest aui thread; throws on a non-statewire thread like the library's own hooks. */\nconst useStatewireExtras = (): StatewireThread.Extras =>\n useAuiState((s) => {\n if (!hasStatewireThreadExtras(s.thread.extras)) {\n throw new Error('useDeepAgentWindowSync requires a statewire thread');\n }\n return s.thread.extras as StatewireThread.Extras;\n });\n\n/** The joined interest window of the nearest statewire thread. */\nexport function useDeepAgentMessageWindow(): DeepAgentMessageWindow | null {\n const documents = useStatewireExtras().documents;\n const mounted = useSyncExternalStore(\n documents?.subscribe ?? noopSubscribe,\n () => documents?.list(),\n () => documents?.list()\n );\n return useMemo(() => readDeepAgentMessageWindow(mounted), [mounted]);\n}\n\n/**\n * The client half of the interest window, shared by every surface — mounted\n * once per runtime, inside its aui provider.\n *\n * - **Older history.** While the host renderer reports the top of the loaded\n * history near (`nearTop`) and the window says older messages exist, this\n * re-states the interests with one more page (anchored at the window's\n * first message) — the host mounts its documents for this client alone —\n * chaining at most `maxChainedLoads` pages per approach; `loadOlder` asks\n * for one page on demand (an edge row's button). Never two loads in flight.\n * A re-attach's hello carries the view the client declares on the attach\n * (`useDeepAgentThread`), every page in it however it was loaded (this\n * hook, a handover's or a search's reveal, an edit's parent). A hello that\n * does not carry the view the last connected session held — a host that\n * reads no declaration and has no memo of the client id — gets it stated\n * again ({@link restatedInterestRequests}).\n * - **Cut tool outputs.** Tool cards whose output the wire carried cut\n * (`artifact._athena_content_truncated`) get it fetched whole through\n * `history/tool_output` once their message is mounted, at most\n * `maxConcurrentToolOutputs` at a time; the converter puts it back\n * (`toolOutputs`), so the card re-renders complete. An output the host\n * replaced since (the marker's `chars` changed) is fetched again.\n */\n/**\n * Whether an older page put a new converted message ahead of the thread's\n * first one. Older history only ever merges into or lands before the first\n * converted message, so the second one is a stable landmark: it moved down iff\n * the page showed something. A new tail message does not move it. Without a\n * second message (or once it is gone) the converted count decides.\n */\nfunction pageShowedEarlierMessage(\n from: { count: number; secondId: string | undefined },\n messages: readonly DeepAgentWindowSyncMessage[]\n): boolean {\n if (from.secondId !== undefined) {\n const index = messages.findIndex((message) => message.id === from.secondId);\n if (index !== -1) return index > 1;\n }\n return messages.length > from.count;\n}\n\n/** Whether a converted message is a turn's reply rather than its prompt (unknown without a role). */\nfunction isReply(message: DeepAgentWindowSyncMessage | undefined): boolean {\n return message?.role !== undefined && message.role !== 'user';\n}\n\n/**\n * Whether the loaded thread still opens without context: it should open on a\n * prompt and hold at least one earlier turn, so the newest turn shows with the\n * one before it (a turn is a prompt followed by its reply). Queued and live\n * prompts land at the tail with no reply yet, so they never count; prompts\n * alone need nothing. Without roles, a lone converted message stands in for it.\n */\nfunction opensMidTurn(messages: readonly DeepAgentWindowSyncMessage[]): boolean {\n const first = messages[0];\n if (first === undefined) return false;\n if (messages.every((message) => message.role === undefined)) return messages.length < 2;\n if (first.role !== 'user') return true;\n if (messages.every((message) => message.role === 'user')) return false;\n let turns = 0;\n for (let index = 1; index < messages.length; index += 1) {\n if (messages[index - 1]!.role === 'user' && messages[index]!.role !== 'user') turns += 1;\n }\n return turns < 2;\n}\n\nexport function useDeepAgentWindowSync({\n messages,\n pageSize,\n toolOutputs,\n nearTop = false,\n nearTopEpoch = 0,\n isMessageMounted = everyMessageMounted,\n maxConcurrentToolOutputs = Number.POSITIVE_INFINITY,\n maxChainedLoads = DEEP_AGENT_MAX_CHAINED_HISTORY_LOADS,\n maxUnseenLoads = DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS,\n onHistoryLoad,\n historyPages,\n historyPageTurns = DEEP_AGENT_HISTORY_PAGE_TURNS,\n onHistoryPage,\n onError,\n now = defaultNow,\n}: UseDeepAgentWindowSyncOptions): DeepAgentWindowSyncState {\n const { sendCommand, invoke, connection } = useStatewireExtras();\n const window = useDeepAgentMessageWindow();\n const hostVersion = useAuiState((s) => {\n const extras = s.thread.extras as Partial<StatewireThread.Extras> | undefined;\n return readDeepAgentProtocol(extras?.state)?.version ?? 0;\n });\n // Older history comes by command when the surface keeps a store for it and\n // the host answers it; the view then stays the head.\n const pagesByCommand =\n historyPages !== undefined && hostVersion >= DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION;\n const historySnapshot = useSyncExternalStore(\n historyPages?.subscribe ?? noopSubscribe,\n () => historyPages?.getSnapshot() ?? null,\n () => historyPages?.getSnapshot() ?? null\n );\n const liveIds = useMemo(() => new Set(window?.chain.map((entry) => entry.id) ?? []), [window]);\n // The pages that still meet the live window; a detached store is cleared below.\n const history: DeepAgentHistorySnapshot | null =\n historySnapshot !== null &&\n window !== null &&\n historyPages !== undefined &&\n !historyPages.isDetached({ threadId: window.threadId, liveIds })\n ? historySnapshot\n : null;\n const onHistoryPageRef = useRef(onHistoryPage);\n onHistoryPageRef.current = onHistoryPage;\n const [loading, setLoading] = useState(false);\n // The view the host refused a page over as deeper than one attach holds\n // (`oversized-interest`): its conversation and how many messages it covered.\n // A view at least that large gets the same refusal (a run's appends only\n // grow it); one that shrank — an edit rewound the transcript, a re-attach\n // came back smaller — may fit a page again.\n const [spentDepth, setSpentDepth] = useState<{ threadId: string | undefined; loaded: number } | null>(\n null\n );\n const depthSpent =\n spentDepth !== null &&\n window !== null &&\n spentDepth.threadId === window.threadId &&\n window.chain.length >= spentDepth.loaded;\n const [requests, setRequests] = useState(0);\n const servedRequestsRef = useRef(0);\n const inflightRef = useRef(false);\n const chainRef = useRef({ epoch: 0, loads: 0, unseen: 0, requested: false });\n // Pages loaded to show the opening turn's prompt; `null` once it shows, the\n // user took over, or a page failed — never re-armed for this mount.\n const openingFillRef = useRef<number | null>(0);\n // The converted thread when the in-flight page was stated; `null` once its\n // settle was judged (or it failed).\n const pageFromRef = useRef<{ count: number; secondId: string | undefined } | null>(null);\n const aliveRef = useRef(true);\n // The window the last connected session held, whoever paged it in, and the\n // session whose hello it was last checked against (a hello resets the\n // documents to what the host seeded).\n const heldRef = useRef<DeepAgentMessageWindow | null>(null);\n const restatedConnectionRef = useRef<unknown>(null);\n // Outputs already asked for and answered by this mount — fetched, refused,\n // or failed — by the `chars` they were asked for. The converter re-runs on\n // every wire change, and the store is a bounded LRU: without this memory a\n // refused read would leave on every pass, and once a transcript holds more\n // cut outputs than the store retains, each fetch would evict a still-loaded\n // output and the next pass would fetch it again, forever. An evicted output\n // renders its cut text (the REST display limit) rather than re-entering the\n // loop; a marker whose `chars` moved (the host replaced the output) is asked\n // for again.\n const answeredRef = useRef(new Map<string, number>());\n // Reads this mount has in flight, and whether a pass left outputs waiting\n // for one to settle (`maxConcurrentToolOutputs`): only then does a settle\n // re-run the pass, so an unbounded mount renders no more than before.\n const toolOutputsInFlightRef = useRef(0);\n const toolOutputsWaitingRef = useRef(false);\n const [toolOutputSettles, setToolOutputSettles] = useState(0);\n const onHistoryLoadRef = useRef(onHistoryLoad);\n onHistoryLoadRef.current = onHistoryLoad;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const nowRef = useRef(now);\n nowRef.current = now;\n useEffect(() => {\n aliveRef.current = true;\n return () => {\n aliveRef.current = false;\n };\n }, []);\n\n // Pages that no longer meet the live window (another conversation, or an\n // edit rewound past their anchor) describe another transcript: drop them,\n // and the edge offers older history again from the window's first message.\n useEffect(() => {\n if (historyPages === undefined || historySnapshot === null || window === null) return;\n if (window.chain.length === 0) return;\n if (historyPages.isDetached({ threadId: window.threadId, liveIds })) historyPages.clear();\n }, [historyPages, historySnapshot, window, liveIds]);\n\n useEffect(() => {\n if (connection.status !== 'connected' || window === null) return;\n if (restatedConnectionRef.current === connection) {\n heldRef.current = window;\n return;\n }\n // Decided once per connected session, on the hello's interest document.\n restatedConnectionRef.current = connection;\n const held = heldRef.current;\n heldRef.current = window;\n // A page still in flight was stated over the held window: it restates it.\n if (held === null || inflightRef.current || messageWindowCarries({ hello: window, held })) return;\n // Another conversation's hello (the runtime switched threads under this mount).\n if (held.threadId !== undefined && window.threadId !== undefined && held.threadId !== window.threadId) {\n return;\n }\n // Held like a page, so no page is stated over it while it is in flight.\n inflightRef.current = true;\n setLoading(true);\n invoke(DEEP_AGENT_INTEREST_PROTOCOL, 'set', [restatedInterestRequests({ held, hello: window })])\n .catch((error: unknown) => {\n onErrorRef.current?.(error, 'athena/interest');\n })\n .finally(() => {\n inflightRef.current = false;\n if (aliveRef.current) setLoading(false);\n });\n }, [connection, invoke, window]);\n\n useEffect(() => {\n if (window === null || inflightRef.current) return;\n // Older turns by command when this surface keeps a store and the host\n // answers it (whole turns before the oldest message held, outside the\n // view); interest pages otherwise. The asks are the same either way.\n const store = pagesByCommand ? historyPages : undefined;\n if (depthSpent && store === undefined) {\n // An ask now would get the same refusal: answer it here, so it never\n // reaches another conversation this mount switches to.\n servedRequestsRef.current = requests;\n pageFromRef.current = null;\n return;\n }\n const from = pageFromRef.current;\n pageFromRef.current = null;\n // A page by command always shows a turn's prompt (it never sets `from`).\n const lastPageUnseen =\n from !== null && from.count > 0 && !pageShowedEarlierMessage(from, messages);\n const pageRequests = store === undefined ? pageInterestRequests(window, pageSize) : null;\n if (store === undefined ? pageRequests === null : !(history?.more ?? window.hasOlder)) return;\n const requested = requests !== servedRequestsRef.current;\n const chain = chainRef.current;\n let fillPage = false;\n if (\n openingFillRef.current !== null &&\n (requested || nearTop || (messages.length > 0 && !opensMidTurn(messages)))\n ) {\n openingFillRef.current = null;\n }\n if (requested) {\n // An explicit ask re-arms the chain for this approach.\n servedRequestsRef.current = requests;\n chainRef.current = { epoch: nearTopEpoch, loads: 1, unseen: 0, requested: true };\n } else if (lastPageUnseen && (chain.requested || (nearTop && chain.epoch === nearTopEpoch))) {\n // The page landed inside the first loaded turn: keep going until one shows.\n if (chain.unseen >= maxUnseenLoads) return;\n chain.unseen += 1;\n } else if (openingFillRef.current !== null && opensMidTurn(messages)) {\n if (openingFillRef.current >= maxUnseenLoads) return;\n openingFillRef.current += 1;\n fillPage = true;\n } else {\n if (!nearTop) return;\n if (chain.epoch !== nearTopEpoch) {\n chainRef.current = { epoch: nearTopEpoch, loads: 0, unseen: 0, requested: false };\n }\n if (chainRef.current.loads >= maxChainedLoads) return;\n chainRef.current.loads += 1;\n }\n const startedAt = nowRef.current();\n const durationMs = () => Math.max(0, Math.round(nowRef.current() - startedAt));\n const settle = () => {\n inflightRef.current = false;\n if (aliveRef.current) setLoading(false);\n };\n if (store !== undefined) {\n const before = history?.turns[0]?.id ?? window.chain[0]?.id;\n if (before === undefined) return;\n inflightRef.current = true;\n setLoading(true);\n store\n .requestOlder({\n send: sendCommand,\n threadId: window.threadId ?? '',\n before,\n beforeIsPrompt:\n history !== null || window.messages.find((message) => message.id === before)?.type === 'human',\n turns: historyPageTurns,\n })\n .then((answered) => {\n onHistoryPageRef.current?.({ before, turns: historyPageTurns, answered, durationMs: durationMs() });\n })\n .catch((error: unknown) => {\n if (fillPage) openingFillRef.current = null;\n onErrorRef.current?.(error, 'history/page');\n })\n .finally(settle);\n return;\n }\n if (pageRequests === null) return;\n // The page continues the oldest loaded turn (see DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS).\n const insideTurn = lastPageUnseen || isReply(messages[0]);\n const stated =\n (insideTurn && pageInterestRequests(window, DEEP_AGENT_MAX_MESSAGE_WINDOW)) || pageRequests;\n pageFromRef.current = { count: messages.length, secondId: messages[1]?.id };\n const page = window.pages + 1;\n const request = stated[stated.length - 1] as DeepAgentInterestRequest;\n inflightRef.current = true;\n setLoading(true);\n invoke(DEEP_AGENT_INTEREST_PROTOCOL, 'set', [stated])\n .then(() => {\n onHistoryLoadRef.current?.({ page, request, durationMs: durationMs() });\n })\n .catch((error: unknown) => {\n pageFromRef.current = null;\n if (fillPage) openingFillRef.current = null;\n if (isOversizedInterestRejection(error) && aliveRef.current) {\n setSpentDepth({ threadId: window.threadId, loaded: window.chain.length });\n }\n onErrorRef.current?.(error, 'athena/interest');\n })\n .finally(settle);\n // `loading` re-arms the chain once a page settled after its documents moved the window.\n }, [\n nearTop,\n nearTopEpoch,\n requests,\n window,\n loading,\n messages,\n invoke,\n maxChainedLoads,\n maxUnseenLoads,\n pageSize,\n depthSpent,\n pagesByCommand,\n historyPages,\n history,\n historyPageTurns,\n sendCommand,\n ]);\n\n useEffect(() => {\n if (window === null || toolOutputs === undefined) return;\n toolOutputsWaitingRef.current = false;\n for (const message of messages) {\n if (!isMessageMounted(message.id)) continue;\n for (const part of message.content) {\n if (part.type !== 'tool-call') continue;\n const marker = readTruncatedToolOutputArtifact(part.artifact);\n if (marker === null || toolOutputs.isPending(marker.messageId)) continue;\n // Fetched for this very length already; a different length means the\n // host replaced the output under the same id since.\n if (toolOutputs.entry(marker.messageId)?.chars === marker.chars) continue;\n if (answeredRef.current.get(marker.messageId) === marker.chars) continue;\n if (toolOutputsInFlightRef.current >= maxConcurrentToolOutputs) {\n toolOutputsWaitingRef.current = true;\n return;\n }\n const { messageId, chars } = marker;\n toolOutputsInFlightRef.current += 1;\n toolOutputs.markPending(messageId);\n Promise.resolve(sendCommand(buildToolOutputCommand({ messageId })))\n .then((payload) => {\n answeredRef.current.set(messageId, chars);\n const result = readToolOutputResult(payload);\n if (result === null) {\n toolOutputs.clearPending(messageId);\n return;\n }\n toolOutputs.set(result.messageId, { content: result.content, chars });\n })\n .catch((error: unknown) => {\n answeredRef.current.set(messageId, chars);\n toolOutputs.clearPending(messageId);\n onErrorRef.current?.(error, 'history/tool_output');\n })\n .finally(() => {\n toolOutputsInFlightRef.current -= 1;\n if (toolOutputsWaitingRef.current && aliveRef.current) {\n setToolOutputSettles((count) => count + 1);\n }\n });\n }\n }\n }, [\n messages,\n isMessageMounted,\n window,\n sendCommand,\n toolOutputs,\n maxConcurrentToolOutputs,\n toolOutputSettles,\n ]);\n\n const loadOlder = useCallback(() => {\n setRequests((count) => count + 1);\n }, []);\n\n // By command, the host bounds nothing but the transcript's start: older\n // turns exist while the pages say so (the window's own edge before any).\n const hasOlder = pagesByCommand\n ? history !== null\n ? history.more\n : (window?.hasOlder ?? false)\n : (window?.hasOlder ?? false);\n const canLoadOlder = useMemo(\n () =>\n pagesByCommand\n ? window !== null && hasOlder\n : window !== null && !depthSpent && pageInterestRequests(window, pageSize) !== null,\n [pagesByCommand, hasOlder, window, pageSize, depthSpent]\n );\n\n return { window, hasOlder, canLoadOlder, loading, loadOlder };\n}\n"],"names":["DEEP_AGENT_OVERSIZED_INTEREST_CODE","useAuiState","hasStatewireThreadExtras","useSyncExternalStore","useMemo","readDeepAgentMessageWindow","historyPages","DEEP_AGENT_HISTORY_PAGE_TURNS","readDeepAgentProtocol","DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION","useRef","useState","useEffect","messageWindowCarries","DEEP_AGENT_INTEREST_PROTOCOL","restatedInterestRequests","store","pageInterestRequests","_a","DEEP_AGENT_MAX_MESSAGE_WINDOW","readTruncatedToolOutputArtifact","buildToolOutputCommand","readToolOutputResult","useCallback"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { type DeepAgentHistoryStore } from './history-pages';
1
2
  import { type DeepAgentInterestRequest, type DeepAgentMessageWindow } from './message-window';
2
3
  import type { DeepAgentToolOutputStore } from './tool-outputs';
3
4
  /**
@@ -39,6 +40,15 @@ export interface DeepAgentHistoryLoadEvent {
39
40
  request: DeepAgentInterestRequest;
40
41
  durationMs: number;
41
42
  }
43
+ /** One `history/page` round trip, for the host's telemetry. */
44
+ export interface DeepAgentHistoryPageEvent {
45
+ /** The message the page was asked before. */
46
+ before: string;
47
+ /** Turns asked for, and answered. */
48
+ turns: number;
49
+ answered: number;
50
+ durationMs: number;
51
+ }
42
52
  export interface UseDeepAgentWindowSyncOptions {
43
53
  /**
44
54
  * The converted thread messages — read by the host through its platform
@@ -83,8 +93,23 @@ export interface UseDeepAgentWindowSyncOptions {
83
93
  maxUnseenLoads?: number;
84
94
  /** A page interest resolved (telemetry). */
85
95
  onHistoryLoad?: ((event: DeepAgentHistoryLoadEvent) => void) | undefined;
96
+ /**
97
+ * Older turns paged by command (`history/page`, protocol 3) into this store:
98
+ * the same one the thread joins in front of its live window
99
+ * (`useDeepAgentThread({ historyStore })`). Used only against a host that
100
+ * advertises `DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION`; there every older
101
+ * page (the button, the near-top chain, the opening fill) is a `history/page`
102
+ * of whole turns and no interest page is stated, so the attach's view stays
103
+ * the head however far back the reader goes. Omitted, or an older host:
104
+ * interest pages, as before.
105
+ */
106
+ historyPages?: DeepAgentHistoryStore | undefined;
107
+ /** Turns one history page asks for. */
108
+ historyPageTurns?: number;
109
+ /** A history page resolved (telemetry). */
110
+ onHistoryPage?: ((event: DeepAgentHistoryPageEvent) => void) | undefined;
86
111
  /** A read failed; the sync itself recovers (the pending marks are released). */
87
- onError?: ((error: unknown, command: 'athena/interest' | 'history/tool_output') => void) | undefined;
112
+ onError?: ((error: unknown, command: 'athena/interest' | 'history/page' | 'history/tool_output') => void) | undefined;
88
113
  now?: () => number;
89
114
  }
90
115
  export interface DeepAgentWindowSyncState {
@@ -94,16 +119,26 @@ export interface DeepAgentWindowSyncState {
94
119
  hasOlder: boolean;
95
120
  /**
96
121
  * Whether the next page can be asked for: older messages exist and the
97
- * host's interest cap has room for them. `hasOlder && !canLoadOlder` is the
98
- * depth limit (`MAX_INTERESTS × MAX_MESSAGE_WINDOW` messages loaded in one
99
- * connection) — an edge row says so instead of offering a dead button.
122
+ * view has room for them. `hasOlder && !canLoadOlder` is the depth limit —
123
+ * an edge row says so instead of offering a dead button. The host bounds
124
+ * one attach's view twice: `MAX_INTERESTS` requests, and an interest
125
+ * document that lists every loaded message within a byte budget (about a
126
+ * thousand messages). The second is found when the host refuses a page as
127
+ * `oversized-interest` ({@link isOversizedInterestRejection}).
100
128
  */
101
129
  canLoadOlder: boolean;
102
130
  /** A page of older history is in flight. */
103
131
  loading: boolean;
104
- /** Ask for the next page of older history now (an edge row's button, a keypress). A no-op before the head resolved or at the beginning. */
132
+ /** Ask for the next page of older history now (an edge row's button, a keypress). A no-op before the head resolved, at the beginning, or once `canLoadOlder` is false. */
105
133
  loadOlder: () => void;
106
134
  }
135
+ /**
136
+ * Whether an `athena/interest` `set` came back refused because the windows it
137
+ * states resolve past what one attach's interest document carries: the view
138
+ * is as deep as this connection can load, and asking again only gets the same
139
+ * refusal.
140
+ */
141
+ export declare function isOversizedInterestRejection(error: unknown): boolean;
107
142
  /** The joined interest window of the nearest statewire thread. */
108
143
  export declare function useDeepAgentMessageWindow(): DeepAgentMessageWindow | null;
109
- export declare function useDeepAgentWindowSync({ messages, pageSize, toolOutputs, nearTop, nearTopEpoch, isMessageMounted, maxConcurrentToolOutputs, maxChainedLoads, maxUnseenLoads, onHistoryLoad, onError, now, }: UseDeepAgentWindowSyncOptions): DeepAgentWindowSyncState;
144
+ export declare function useDeepAgentWindowSync({ messages, pageSize, toolOutputs, nearTop, nearTopEpoch, isMessageMounted, maxConcurrentToolOutputs, maxChainedLoads, maxUnseenLoads, onHistoryLoad, historyPages, historyPageTurns, onHistoryPage, onError, now, }: UseDeepAgentWindowSyncOptions): DeepAgentWindowSyncState;
@@ -1,10 +1,16 @@
1
1
  import { useAuiState } from "@assistant-ui/store";
2
- import { useState, useRef, useEffect, useCallback, useMemo, useSyncExternalStore } from "react";
3
- import { DEEP_AGENT_INTEREST_PROTOCOL, DEEP_AGENT_MAX_MESSAGE_WINDOW } from "./generated/runconfig-contract.js";
4
- import { interestsCovered, pageInterestRequests, readTruncatedToolOutputArtifact, buildToolOutputCommand, readToolOutputResult, readDeepAgentMessageWindow } from "./message-window.js";
2
+ import { useSyncExternalStore, useMemo, useRef, useState, useEffect, useCallback } from "react";
3
+ import { DEEP_AGENT_INTEREST_PROTOCOL, DEEP_AGENT_OVERSIZED_INTEREST_CODE, DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION, DEEP_AGENT_MAX_MESSAGE_WINDOW } from "./generated/runconfig-contract.js";
4
+ import { DEEP_AGENT_HISTORY_PAGE_TURNS } from "./history-pages.js";
5
+ import { messageWindowCarries, restatedInterestRequests, pageInterestRequests, readTruncatedToolOutputArtifact, buildToolOutputCommand, readToolOutputResult, readDeepAgentMessageWindow } from "./message-window.js";
6
+ import { readDeepAgentProtocol } from "./protocol.js";
5
7
  import { hasStatewireThreadExtras } from "./thread-extras.js";
6
8
  const DEEP_AGENT_MAX_CHAINED_HISTORY_LOADS = 3;
7
9
  const DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS = 25;
10
+ function isOversizedInterestRejection(error) {
11
+ const failure = error == null ? void 0 : error.failure;
12
+ return (failure == null ? void 0 : failure.fate) === "rejected" && failure.code === DEEP_AGENT_OVERSIZED_INTEREST_CODE;
13
+ }
8
14
  const everyMessageMounted = () => true;
9
15
  const defaultNow = () => Date.now();
10
16
  const noopSubscribe = () => () => {
@@ -57,12 +63,34 @@ function useDeepAgentWindowSync({
57
63
  maxChainedLoads = DEEP_AGENT_MAX_CHAINED_HISTORY_LOADS,
58
64
  maxUnseenLoads = DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS,
59
65
  onHistoryLoad,
66
+ historyPages,
67
+ historyPageTurns = DEEP_AGENT_HISTORY_PAGE_TURNS,
68
+ onHistoryPage,
60
69
  onError,
61
70
  now = defaultNow
62
71
  }) {
63
72
  const { sendCommand, invoke, connection } = useStatewireExtras();
64
73
  const window = useDeepAgentMessageWindow();
74
+ const hostVersion = useAuiState((s) => {
75
+ var _a;
76
+ const extras = s.thread.extras;
77
+ return ((_a = readDeepAgentProtocol(extras == null ? void 0 : extras.state)) == null ? void 0 : _a.version) ?? 0;
78
+ });
79
+ const pagesByCommand = historyPages !== void 0 && hostVersion >= DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION;
80
+ const historySnapshot = useSyncExternalStore(
81
+ (historyPages == null ? void 0 : historyPages.subscribe) ?? noopSubscribe,
82
+ () => (historyPages == null ? void 0 : historyPages.getSnapshot()) ?? null,
83
+ () => (historyPages == null ? void 0 : historyPages.getSnapshot()) ?? null
84
+ );
85
+ const liveIds = useMemo(() => new Set((window == null ? void 0 : window.chain.map((entry) => entry.id)) ?? []), [window]);
86
+ const history = historySnapshot !== null && window !== null && historyPages !== void 0 && !historyPages.isDetached({ threadId: window.threadId, liveIds }) ? historySnapshot : null;
87
+ const onHistoryPageRef = useRef(onHistoryPage);
88
+ onHistoryPageRef.current = onHistoryPage;
65
89
  const [loading, setLoading] = useState(false);
90
+ const [spentDepth, setSpentDepth] = useState(
91
+ null
92
+ );
93
+ const depthSpent = spentDepth !== null && window !== null && spentDepth.threadId === window.threadId && window.chain.length >= spentDepth.loaded;
66
94
  const [requests, setRequests] = useState(0);
67
95
  const servedRequestsRef = useRef(0);
68
96
  const inflightRef = useRef(false);
@@ -70,7 +98,7 @@ function useDeepAgentWindowSync({
70
98
  const openingFillRef = useRef(0);
71
99
  const pageFromRef = useRef(null);
72
100
  const aliveRef = useRef(true);
73
- const statedRef = useRef(null);
101
+ const heldRef = useRef(null);
74
102
  const restatedConnectionRef = useRef(null);
75
103
  const answeredRef = useRef(/* @__PURE__ */ new Map());
76
104
  const toolOutputsInFlightRef = useRef(0);
@@ -89,24 +117,47 @@ function useDeepAgentWindowSync({
89
117
  };
90
118
  }, []);
91
119
  useEffect(() => {
92
- if (connection.status !== "connected" || restatedConnectionRef.current === connection) return;
93
- if (window === null) return;
120
+ if (historyPages === void 0 || historySnapshot === null || window === null) return;
121
+ if (window.chain.length === 0) return;
122
+ if (historyPages.isDetached({ threadId: window.threadId, liveIds })) historyPages.clear();
123
+ }, [historyPages, historySnapshot, window, liveIds]);
124
+ useEffect(() => {
125
+ if (connection.status !== "connected" || window === null) return;
126
+ if (restatedConnectionRef.current === connection) {
127
+ heldRef.current = window;
128
+ return;
129
+ }
94
130
  restatedConnectionRef.current = connection;
95
- const stated = statedRef.current;
96
- if (stated === null || interestsCovered(window.requests, stated)) return;
97
- invoke(DEEP_AGENT_INTEREST_PROTOCOL, "set", [stated]).catch((error) => {
131
+ const held = heldRef.current;
132
+ heldRef.current = window;
133
+ if (held === null || inflightRef.current || messageWindowCarries({ hello: window, held })) return;
134
+ if (held.threadId !== void 0 && window.threadId !== void 0 && held.threadId !== window.threadId) {
135
+ return;
136
+ }
137
+ inflightRef.current = true;
138
+ setLoading(true);
139
+ invoke(DEEP_AGENT_INTEREST_PROTOCOL, "set", [restatedInterestRequests({ held, hello: window })]).catch((error) => {
98
140
  var _a;
99
141
  (_a = onErrorRef.current) == null ? void 0 : _a.call(onErrorRef, error, "athena/interest");
142
+ }).finally(() => {
143
+ inflightRef.current = false;
144
+ if (aliveRef.current) setLoading(false);
100
145
  });
101
146
  }, [connection, invoke, window]);
102
147
  useEffect(() => {
103
- var _a;
148
+ var _a, _b, _c, _d;
104
149
  if (window === null || inflightRef.current) return;
150
+ const store = pagesByCommand ? historyPages : void 0;
151
+ if (depthSpent && store === void 0) {
152
+ servedRequestsRef.current = requests;
153
+ pageFromRef.current = null;
154
+ return;
155
+ }
105
156
  const from = pageFromRef.current;
106
157
  pageFromRef.current = null;
107
158
  const lastPageUnseen = from !== null && from.count > 0 && !pageShowedEarlierMessage(from, messages);
108
- const pageRequests = pageInterestRequests(window, pageSize);
109
- if (pageRequests === null) return;
159
+ const pageRequests = store === void 0 ? pageInterestRequests(window, pageSize) : null;
160
+ if (store === void 0 ? pageRequests === null : !((history == null ? void 0 : history.more) ?? window.hasOlder)) return;
110
161
  const requested = requests !== servedRequestsRef.current;
111
162
  const chain = chainRef.current;
112
163
  let fillPage = false;
@@ -131,31 +182,53 @@ function useDeepAgentWindowSync({
131
182
  if (chainRef.current.loads >= maxChainedLoads) return;
132
183
  chainRef.current.loads += 1;
133
184
  }
185
+ const startedAt = nowRef.current();
186
+ const durationMs = () => Math.max(0, Math.round(nowRef.current() - startedAt));
187
+ const settle = () => {
188
+ inflightRef.current = false;
189
+ if (aliveRef.current) setLoading(false);
190
+ };
191
+ if (store !== void 0) {
192
+ const before = ((_a = history == null ? void 0 : history.turns[0]) == null ? void 0 : _a.id) ?? ((_b = window.chain[0]) == null ? void 0 : _b.id);
193
+ if (before === void 0) return;
194
+ inflightRef.current = true;
195
+ setLoading(true);
196
+ store.requestOlder({
197
+ send: sendCommand,
198
+ threadId: window.threadId ?? "",
199
+ before,
200
+ beforeIsPrompt: history !== null || ((_c = window.messages.find((message) => message.id === before)) == null ? void 0 : _c.type) === "human",
201
+ turns: historyPageTurns
202
+ }).then((answered) => {
203
+ var _a2;
204
+ (_a2 = onHistoryPageRef.current) == null ? void 0 : _a2.call(onHistoryPageRef, { before, turns: historyPageTurns, answered, durationMs: durationMs() });
205
+ }).catch((error) => {
206
+ var _a2;
207
+ if (fillPage) openingFillRef.current = null;
208
+ (_a2 = onErrorRef.current) == null ? void 0 : _a2.call(onErrorRef, error, "history/page");
209
+ }).finally(settle);
210
+ return;
211
+ }
212
+ if (pageRequests === null) return;
134
213
  const insideTurn = lastPageUnseen || isReply(messages[0]);
135
214
  const stated = insideTurn && pageInterestRequests(window, DEEP_AGENT_MAX_MESSAGE_WINDOW) || pageRequests;
136
- pageFromRef.current = { count: messages.length, secondId: (_a = messages[1]) == null ? void 0 : _a.id };
215
+ pageFromRef.current = { count: messages.length, secondId: (_d = messages[1]) == null ? void 0 : _d.id };
137
216
  const page = window.pages + 1;
138
217
  const request = stated[stated.length - 1];
139
218
  inflightRef.current = true;
140
219
  setLoading(true);
141
- const startedAt = nowRef.current();
142
220
  invoke(DEEP_AGENT_INTEREST_PROTOCOL, "set", [stated]).then(() => {
143
221
  var _a2;
144
- statedRef.current = stated;
145
- (_a2 = onHistoryLoadRef.current) == null ? void 0 : _a2.call(onHistoryLoadRef, {
146
- page,
147
- request,
148
- durationMs: Math.max(0, Math.round(nowRef.current() - startedAt))
149
- });
222
+ (_a2 = onHistoryLoadRef.current) == null ? void 0 : _a2.call(onHistoryLoadRef, { page, request, durationMs: durationMs() });
150
223
  }).catch((error) => {
151
224
  var _a2;
152
225
  pageFromRef.current = null;
153
226
  if (fillPage) openingFillRef.current = null;
227
+ if (isOversizedInterestRejection(error) && aliveRef.current) {
228
+ setSpentDepth({ threadId: window.threadId, loaded: window.chain.length });
229
+ }
154
230
  (_a2 = onErrorRef.current) == null ? void 0 : _a2.call(onErrorRef, error, "athena/interest");
155
- }).finally(() => {
156
- inflightRef.current = false;
157
- if (aliveRef.current) setLoading(false);
158
- });
231
+ }).finally(settle);
159
232
  }, [
160
233
  nearTop,
161
234
  nearTopEpoch,
@@ -166,7 +239,13 @@ function useDeepAgentWindowSync({
166
239
  invoke,
167
240
  maxChainedLoads,
168
241
  maxUnseenLoads,
169
- pageSize
242
+ pageSize,
243
+ depthSpent,
244
+ pagesByCommand,
245
+ historyPages,
246
+ history,
247
+ historyPageTurns,
248
+ sendCommand
170
249
  ]);
171
250
  useEffect(() => {
172
251
  var _a;
@@ -220,15 +299,17 @@ function useDeepAgentWindowSync({
220
299
  const loadOlder = useCallback(() => {
221
300
  setRequests((count) => count + 1);
222
301
  }, []);
302
+ const hasOlder = pagesByCommand ? history !== null ? history.more : (window == null ? void 0 : window.hasOlder) ?? false : (window == null ? void 0 : window.hasOlder) ?? false;
223
303
  const canLoadOlder = useMemo(
224
- () => window !== null && pageInterestRequests(window, pageSize) !== null,
225
- [window, pageSize]
304
+ () => pagesByCommand ? window !== null && hasOlder : window !== null && !depthSpent && pageInterestRequests(window, pageSize) !== null,
305
+ [pagesByCommand, hasOlder, window, pageSize, depthSpent]
226
306
  );
227
- return { window, hasOlder: (window == null ? void 0 : window.hasOlder) ?? false, canLoadOlder, loading, loadOlder };
307
+ return { window, hasOlder, canLoadOlder, loading, loadOlder };
228
308
  }
229
309
  export {
230
310
  DEEP_AGENT_MAX_CHAINED_HISTORY_LOADS,
231
311
  DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS,
312
+ isOversizedInterestRejection,
232
313
  useDeepAgentMessageWindow,
233
314
  useDeepAgentWindowSync
234
315
  };
@@ -1 +1 @@
1
- {"version":3,"file":"use-deep-agent-window-sync.js","sources":["../../../../agent-runtime/src/use-deep-agent-window-sync.ts"],"sourcesContent":["import type { StatewireThread } from '@assistant-ui/react-statewire';\nimport { useAuiState } from '@assistant-ui/store';\nimport { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';\nimport { DEEP_AGENT_INTEREST_PROTOCOL, DEEP_AGENT_MAX_MESSAGE_WINDOW } from './generated/runconfig-contract';\nimport {\n buildToolOutputCommand,\n type DeepAgentInterestRequest,\n type DeepAgentMessageWindow,\n interestsCovered,\n pageInterestRequests,\n readDeepAgentMessageWindow,\n readToolOutputResult,\n readTruncatedToolOutputArtifact,\n} from './message-window';\nimport { hasStatewireThreadExtras } from './thread-extras';\nimport type { DeepAgentToolOutputStore } from './tool-outputs';\n\n/**\n * Pages of older history chained per approach to the top. A renderer lowers\n * its near-top level once prepended content has pushed the first message out\n * of its band; this bounds the case where it cannot (no viewport to scroll,\n * a list too short to overflow) so a 2,000-message thread never streams whole.\n */\nexport const DEEP_AGENT_MAX_CHAINED_HISTORY_LOADS = 3;\n\n/**\n * Pages of older history that add no converted message — every message on\n * them folds into the first loaded turn, such as one agent run's hundreds of\n * tool steps — loaded on top of a request (or an approach's chain) before it\n * stops. Such a page changes nothing the user can see, so it neither answers\n * an ask nor counts against the per-approach chain.\n *\n * A page loaded while the oldest loaded message is a reply lands inside that\n * reply's turn, so it asks for the host's largest window\n * (`DEEP_AGENT_MAX_MESSAGE_WINDOW`) instead of the thread's: a run of 373\n * tool calls is about 750 messages, nineteen round trips at the default\n * window and four at the largest, and the turn shows nothing new until its\n * prompt does. A page above a prompt keeps the thread's window.\n */\nexport const DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS = 25;\n\n/** The converted thread messages the tool-output half scans (web and native `ThreadMessage` both satisfy it). */\nexport interface DeepAgentWindowSyncMessage {\n readonly id: string;\n /** The converted role; lets the opening fill tell a turn's prompt from its reply. */\n readonly role?: string;\n readonly content: readonly { readonly type: string; readonly artifact?: unknown }[];\n}\n\n/** One page interest round trip, for the host's telemetry. */\nexport interface DeepAgentHistoryLoadEvent {\n /** The page's ordinal (`1` extends the head). */\n page: number;\n request: DeepAgentInterestRequest;\n durationMs: number;\n}\n\nexport interface UseDeepAgentWindowSyncOptions {\n /**\n * The converted thread messages — read by the host through its platform\n * `useAuiState((s) => s.thread.messages)`, so this hook imports neither\n * `@assistant-ui/react` nor `@assistant-ui/react-native`.\n */\n messages: readonly DeepAgentWindowSyncMessage[];\n /** Messages per page; the thread's window size by default. */\n pageSize?: number;\n /**\n * Full tool outputs fetched back for cut tool messages; the same store the\n * thread converts with (`useDeepAgentThread({ toolOutputs })`). Omitted, the\n * tool-output half is inert (a surface that never shows a cut output whole).\n */\n toolOutputs?: DeepAgentToolOutputStore | undefined;\n /**\n * The renderer's report that the top of the LOADED history is near — a\n * level, not an edge: while it holds and older messages exist, pages load\n * one after another (bounded by `maxChainedLoads` per approach). Omitted for\n * hosts with only a manual affordance (`loadOlder`).\n */\n nearTop?: boolean;\n /** Bumped on every rise of `nearTop` (and every explicit request), so the chain bound is per approach. */\n nearTopEpoch?: number;\n /**\n * Whether a message's content is mounted right now, so lazy fetches (cut\n * tool outputs) target what the user can see rather than the whole loaded\n * history. Omitted: every message counts as mounted (the flat renderers).\n */\n isMessageMounted?: ((messageId: string) => boolean) | undefined;\n /**\n * Cut tool outputs this mount reads at once; the rest wait for one to\n * settle. One mounted message can hold a whole agent run — a hundred tool\n * steps — and the host rate-limits a client's frames, so a reader that sends\n * them all together gets refusals back for most of them. Omitted: every\n * mounted output is asked for together (renderers whose mounted set is\n * already small).\n */\n maxConcurrentToolOutputs?: number;\n maxChainedLoads?: number;\n /** Pages adding no converted message loaded per request before it stops; see {@link DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS}. */\n maxUnseenLoads?: number;\n /** A page interest resolved (telemetry). */\n onHistoryLoad?: ((event: DeepAgentHistoryLoadEvent) => void) | undefined;\n /** A read failed; the sync itself recovers (the pending marks are released). */\n onError?: ((error: unknown, command: 'athena/interest' | 'history/tool_output') => void) | undefined;\n now?: () => number;\n}\n\nexport interface DeepAgentWindowSyncState {\n /** The joined window, or `null` while the head interest has not resolved (both halves are inert). */\n window: DeepAgentMessageWindow | null;\n /** Whether the host holds messages older than the loaded window. */\n hasOlder: boolean;\n /**\n * Whether the next page can be asked for: older messages exist and the\n * host's interest cap has room for them. `hasOlder && !canLoadOlder` is the\n * depth limit (`MAX_INTERESTS × MAX_MESSAGE_WINDOW` messages loaded in one\n * connection) — an edge row says so instead of offering a dead button.\n */\n canLoadOlder: boolean;\n /** A page of older history is in flight. */\n loading: boolean;\n /** Ask for the next page of older history now (an edge row's button, a keypress). A no-op before the head resolved or at the beginning. */\n loadOlder: () => void;\n}\n\nconst everyMessageMounted = (): boolean => true;\nconst defaultNow = (): number => Date.now();\nconst noopSubscribe = () => () => {};\n\n/** The statewire extras of the nearest aui thread; throws on a non-statewire thread like the library's own hooks. */\nconst useStatewireExtras = (): StatewireThread.Extras =>\n useAuiState((s) => {\n if (!hasStatewireThreadExtras(s.thread.extras)) {\n throw new Error('useDeepAgentWindowSync requires a statewire thread');\n }\n return s.thread.extras as StatewireThread.Extras;\n });\n\n/** The joined interest window of the nearest statewire thread. */\nexport function useDeepAgentMessageWindow(): DeepAgentMessageWindow | null {\n const documents = useStatewireExtras().documents;\n const mounted = useSyncExternalStore(\n documents?.subscribe ?? noopSubscribe,\n () => documents?.list(),\n () => documents?.list()\n );\n return useMemo(() => readDeepAgentMessageWindow(mounted), [mounted]);\n}\n\n/**\n * The client half of the interest window, shared by every surface — mounted\n * once per runtime, inside its aui provider.\n *\n * - **Older history.** While the host renderer reports the top of the loaded\n * history near (`nearTop`) and the window says older messages exist, this\n * re-states the interests with one more page (anchored at the window's\n * first message) — the host mounts its documents for this client alone —\n * chaining at most `maxChainedLoads` pages per approach; `loadOlder` asks\n * for one page on demand (an edge row's button). Never two loads in flight.\n * A reconnect whose hello does not carry the interests this mount last\n * stated (the host remembers a client id's view across its attaches; a new\n * host instance does not) re-states them.\n * - **Cut tool outputs.** Tool cards whose output the wire carried cut\n * (`artifact._athena_content_truncated`) get it fetched whole through\n * `history/tool_output` once their message is mounted, at most\n * `maxConcurrentToolOutputs` at a time; the converter puts it back\n * (`toolOutputs`), so the card re-renders complete. An output the host\n * replaced since (the marker's `chars` changed) is fetched again.\n */\n/**\n * Whether an older page put a new converted message ahead of the thread's\n * first one. Older history only ever merges into or lands before the first\n * converted message, so the second one is a stable landmark: it moved down iff\n * the page showed something. A new tail message does not move it. Without a\n * second message (or once it is gone) the converted count decides.\n */\nfunction pageShowedEarlierMessage(\n from: { count: number; secondId: string | undefined },\n messages: readonly DeepAgentWindowSyncMessage[]\n): boolean {\n if (from.secondId !== undefined) {\n const index = messages.findIndex((message) => message.id === from.secondId);\n if (index !== -1) return index > 1;\n }\n return messages.length > from.count;\n}\n\n/** Whether a converted message is a turn's reply rather than its prompt (unknown without a role). */\nfunction isReply(message: DeepAgentWindowSyncMessage | undefined): boolean {\n return message?.role !== undefined && message.role !== 'user';\n}\n\n/**\n * Whether the loaded thread still opens without context: it should open on a\n * prompt and hold at least one earlier turn, so the newest turn shows with the\n * one before it (a turn is a prompt followed by its reply). Queued and live\n * prompts land at the tail with no reply yet, so they never count; prompts\n * alone need nothing. Without roles, a lone converted message stands in for it.\n */\nfunction opensMidTurn(messages: readonly DeepAgentWindowSyncMessage[]): boolean {\n const first = messages[0];\n if (first === undefined) return false;\n if (messages.every((message) => message.role === undefined)) return messages.length < 2;\n if (first.role !== 'user') return true;\n if (messages.every((message) => message.role === 'user')) return false;\n let turns = 0;\n for (let index = 1; index < messages.length; index += 1) {\n if (messages[index - 1]!.role === 'user' && messages[index]!.role !== 'user') turns += 1;\n }\n return turns < 2;\n}\n\nexport function useDeepAgentWindowSync({\n messages,\n pageSize,\n toolOutputs,\n nearTop = false,\n nearTopEpoch = 0,\n isMessageMounted = everyMessageMounted,\n maxConcurrentToolOutputs = Number.POSITIVE_INFINITY,\n maxChainedLoads = DEEP_AGENT_MAX_CHAINED_HISTORY_LOADS,\n maxUnseenLoads = DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS,\n onHistoryLoad,\n onError,\n now = defaultNow,\n}: UseDeepAgentWindowSyncOptions): DeepAgentWindowSyncState {\n const { sendCommand, invoke, connection } = useStatewireExtras();\n const window = useDeepAgentMessageWindow();\n const [loading, setLoading] = useState(false);\n const [requests, setRequests] = useState(0);\n const servedRequestsRef = useRef(0);\n const inflightRef = useRef(false);\n const chainRef = useRef({ epoch: 0, loads: 0, unseen: 0, requested: false });\n // Pages loaded to show the opening turn's prompt; `null` once it shows, the\n // user took over, or a page failed — never re-armed for this mount.\n const openingFillRef = useRef<number | null>(0);\n // The converted thread when the in-flight page was stated; `null` once its\n // settle was judged (or it failed).\n const pageFromRef = useRef<{ count: number; secondId: string | undefined } | null>(null);\n const aliveRef = useRef(true);\n // The interests this mount last stated, re-stated on the next connected\n // session (a hello resets the documents) so a reconnect keeps the loaded history.\n const statedRef = useRef<DeepAgentInterestRequest[] | null>(null);\n const restatedConnectionRef = useRef<unknown>(null);\n // Outputs already asked for and answered by this mount — fetched, refused,\n // or failed — by the `chars` they were asked for. The converter re-runs on\n // every wire change, and the store is a bounded LRU: without this memory a\n // refused read would leave on every pass, and once a transcript holds more\n // cut outputs than the store retains, each fetch would evict a still-loaded\n // output and the next pass would fetch it again, forever. An evicted output\n // renders its cut text (the REST display limit) rather than re-entering the\n // loop; a marker whose `chars` moved (the host replaced the output) is asked\n // for again.\n const answeredRef = useRef(new Map<string, number>());\n // Reads this mount has in flight, and whether a pass left outputs waiting\n // for one to settle (`maxConcurrentToolOutputs`): only then does a settle\n // re-run the pass, so an unbounded mount renders no more than before.\n const toolOutputsInFlightRef = useRef(0);\n const toolOutputsWaitingRef = useRef(false);\n const [toolOutputSettles, setToolOutputSettles] = useState(0);\n const onHistoryLoadRef = useRef(onHistoryLoad);\n onHistoryLoadRef.current = onHistoryLoad;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const nowRef = useRef(now);\n nowRef.current = now;\n useEffect(() => {\n aliveRef.current = true;\n return () => {\n aliveRef.current = false;\n };\n }, []);\n\n useEffect(() => {\n if (connection.status !== 'connected' || restatedConnectionRef.current === connection) return;\n // Decided once per connected session, on the hello's interest document.\n if (window === null) return;\n restatedConnectionRef.current = connection;\n const stated = statedRef.current;\n if (stated === null || interestsCovered(window.requests, stated)) return;\n invoke(DEEP_AGENT_INTEREST_PROTOCOL, 'set', [stated]).catch((error: unknown) => {\n onErrorRef.current?.(error, 'athena/interest');\n });\n }, [connection, invoke, window]);\n\n useEffect(() => {\n if (window === null || inflightRef.current) return;\n const from = pageFromRef.current;\n pageFromRef.current = null;\n const lastPageUnseen =\n from !== null && from.count > 0 && !pageShowedEarlierMessage(from, messages);\n const pageRequests = pageInterestRequests(window, pageSize);\n if (pageRequests === null) return;\n const requested = requests !== servedRequestsRef.current;\n const chain = chainRef.current;\n let fillPage = false;\n if (\n openingFillRef.current !== null &&\n (requested || nearTop || (messages.length > 0 && !opensMidTurn(messages)))\n ) {\n openingFillRef.current = null;\n }\n if (requested) {\n // An explicit ask re-arms the chain for this approach.\n servedRequestsRef.current = requests;\n chainRef.current = { epoch: nearTopEpoch, loads: 1, unseen: 0, requested: true };\n } else if (lastPageUnseen && (chain.requested || (nearTop && chain.epoch === nearTopEpoch))) {\n // The page landed inside the first loaded turn: keep going until one shows.\n if (chain.unseen >= maxUnseenLoads) return;\n chain.unseen += 1;\n } else if (openingFillRef.current !== null && opensMidTurn(messages)) {\n if (openingFillRef.current >= maxUnseenLoads) return;\n openingFillRef.current += 1;\n fillPage = true;\n } else {\n if (!nearTop) return;\n if (chain.epoch !== nearTopEpoch) {\n chainRef.current = { epoch: nearTopEpoch, loads: 0, unseen: 0, requested: false };\n }\n if (chainRef.current.loads >= maxChainedLoads) return;\n chainRef.current.loads += 1;\n }\n // The page continues the oldest loaded turn (see DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS).\n const insideTurn = lastPageUnseen || isReply(messages[0]);\n const stated =\n (insideTurn && pageInterestRequests(window, DEEP_AGENT_MAX_MESSAGE_WINDOW)) || pageRequests;\n pageFromRef.current = { count: messages.length, secondId: messages[1]?.id };\n const page = window.pages + 1;\n const request = stated[stated.length - 1] as DeepAgentInterestRequest;\n inflightRef.current = true;\n setLoading(true);\n const startedAt = nowRef.current();\n invoke(DEEP_AGENT_INTEREST_PROTOCOL, 'set', [stated])\n .then(() => {\n statedRef.current = stated;\n onHistoryLoadRef.current?.({\n page,\n request,\n durationMs: Math.max(0, Math.round(nowRef.current() - startedAt)),\n });\n })\n .catch((error: unknown) => {\n pageFromRef.current = null;\n if (fillPage) openingFillRef.current = null;\n onErrorRef.current?.(error, 'athena/interest');\n })\n .finally(() => {\n inflightRef.current = false;\n if (aliveRef.current) setLoading(false);\n });\n // `loading` re-arms the chain once a page settled after its documents moved the window.\n }, [\n nearTop,\n nearTopEpoch,\n requests,\n window,\n loading,\n messages,\n invoke,\n maxChainedLoads,\n maxUnseenLoads,\n pageSize,\n ]);\n\n useEffect(() => {\n if (window === null || toolOutputs === undefined) return;\n toolOutputsWaitingRef.current = false;\n for (const message of messages) {\n if (!isMessageMounted(message.id)) continue;\n for (const part of message.content) {\n if (part.type !== 'tool-call') continue;\n const marker = readTruncatedToolOutputArtifact(part.artifact);\n if (marker === null || toolOutputs.isPending(marker.messageId)) continue;\n // Fetched for this very length already; a different length means the\n // host replaced the output under the same id since.\n if (toolOutputs.entry(marker.messageId)?.chars === marker.chars) continue;\n if (answeredRef.current.get(marker.messageId) === marker.chars) continue;\n if (toolOutputsInFlightRef.current >= maxConcurrentToolOutputs) {\n toolOutputsWaitingRef.current = true;\n return;\n }\n const { messageId, chars } = marker;\n toolOutputsInFlightRef.current += 1;\n toolOutputs.markPending(messageId);\n Promise.resolve(sendCommand(buildToolOutputCommand({ messageId })))\n .then((payload) => {\n answeredRef.current.set(messageId, chars);\n const result = readToolOutputResult(payload);\n if (result === null) {\n toolOutputs.clearPending(messageId);\n return;\n }\n toolOutputs.set(result.messageId, { content: result.content, chars });\n })\n .catch((error: unknown) => {\n answeredRef.current.set(messageId, chars);\n toolOutputs.clearPending(messageId);\n onErrorRef.current?.(error, 'history/tool_output');\n })\n .finally(() => {\n toolOutputsInFlightRef.current -= 1;\n if (toolOutputsWaitingRef.current && aliveRef.current) {\n setToolOutputSettles((count) => count + 1);\n }\n });\n }\n }\n }, [\n messages,\n isMessageMounted,\n window,\n sendCommand,\n toolOutputs,\n maxConcurrentToolOutputs,\n toolOutputSettles,\n ]);\n\n const loadOlder = useCallback(() => {\n setRequests((count) => count + 1);\n }, []);\n\n const canLoadOlder = useMemo(\n () => window !== null && pageInterestRequests(window, pageSize) !== null,\n [window, pageSize]\n );\n\n return { window, hasOlder: window?.hasOlder ?? false, canLoadOlder, loading, loadOlder };\n}\n"],"names":["_a"],"mappings":"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"}
1
+ {"version":3,"file":"use-deep-agent-window-sync.js","sources":["../../../../agent-runtime/src/use-deep-agent-window-sync.ts"],"sourcesContent":["import type { StatewireThread } from '@assistant-ui/react-statewire';\nimport { useAuiState } from '@assistant-ui/store';\nimport { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';\nimport {\n DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION,\n DEEP_AGENT_INTEREST_PROTOCOL,\n DEEP_AGENT_MAX_MESSAGE_WINDOW,\n DEEP_AGENT_OVERSIZED_INTEREST_CODE,\n} from './generated/runconfig-contract';\nimport {\n DEEP_AGENT_HISTORY_PAGE_TURNS,\n type DeepAgentHistorySnapshot,\n type DeepAgentHistoryStore,\n} from './history-pages';\nimport {\n buildToolOutputCommand,\n type DeepAgentInterestRequest,\n type DeepAgentMessageWindow,\n messageWindowCarries,\n pageInterestRequests,\n readDeepAgentMessageWindow,\n readToolOutputResult,\n readTruncatedToolOutputArtifact,\n restatedInterestRequests,\n} from './message-window';\nimport { readDeepAgentProtocol } from './protocol';\nimport { hasStatewireThreadExtras } from './thread-extras';\nimport type { DeepAgentToolOutputStore } from './tool-outputs';\n\n/**\n * Pages of older history chained per approach to the top. A renderer lowers\n * its near-top level once prepended content has pushed the first message out\n * of its band; this bounds the case where it cannot (no viewport to scroll,\n * a list too short to overflow) so a 2,000-message thread never streams whole.\n */\nexport const DEEP_AGENT_MAX_CHAINED_HISTORY_LOADS = 3;\n\n/**\n * Pages of older history that add no converted message — every message on\n * them folds into the first loaded turn, such as one agent run's hundreds of\n * tool steps — loaded on top of a request (or an approach's chain) before it\n * stops. Such a page changes nothing the user can see, so it neither answers\n * an ask nor counts against the per-approach chain.\n *\n * A page loaded while the oldest loaded message is a reply lands inside that\n * reply's turn, so it asks for the host's largest window\n * (`DEEP_AGENT_MAX_MESSAGE_WINDOW`) instead of the thread's: a run of 373\n * tool calls is about 750 messages, nineteen round trips at the default\n * window and four at the largest, and the turn shows nothing new until its\n * prompt does. A page above a prompt keeps the thread's window.\n */\nexport const DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS = 25;\n\n/** The converted thread messages the tool-output half scans (web and native `ThreadMessage` both satisfy it). */\nexport interface DeepAgentWindowSyncMessage {\n readonly id: string;\n /** The converted role; lets the opening fill tell a turn's prompt from its reply. */\n readonly role?: string;\n readonly content: readonly { readonly type: string; readonly artifact?: unknown }[];\n}\n\n/** One page interest round trip, for the host's telemetry. */\nexport interface DeepAgentHistoryLoadEvent {\n /** The page's ordinal (`1` extends the head). */\n page: number;\n request: DeepAgentInterestRequest;\n durationMs: number;\n}\n\n/** One `history/page` round trip, for the host's telemetry. */\nexport interface DeepAgentHistoryPageEvent {\n /** The message the page was asked before. */\n before: string;\n /** Turns asked for, and answered. */\n turns: number;\n answered: number;\n durationMs: number;\n}\n\nexport interface UseDeepAgentWindowSyncOptions {\n /**\n * The converted thread messages — read by the host through its platform\n * `useAuiState((s) => s.thread.messages)`, so this hook imports neither\n * `@assistant-ui/react` nor `@assistant-ui/react-native`.\n */\n messages: readonly DeepAgentWindowSyncMessage[];\n /** Messages per page; the thread's window size by default. */\n pageSize?: number;\n /**\n * Full tool outputs fetched back for cut tool messages; the same store the\n * thread converts with (`useDeepAgentThread({ toolOutputs })`). Omitted, the\n * tool-output half is inert (a surface that never shows a cut output whole).\n */\n toolOutputs?: DeepAgentToolOutputStore | undefined;\n /**\n * The renderer's report that the top of the LOADED history is near — a\n * level, not an edge: while it holds and older messages exist, pages load\n * one after another (bounded by `maxChainedLoads` per approach). Omitted for\n * hosts with only a manual affordance (`loadOlder`).\n */\n nearTop?: boolean;\n /** Bumped on every rise of `nearTop` (and every explicit request), so the chain bound is per approach. */\n nearTopEpoch?: number;\n /**\n * Whether a message's content is mounted right now, so lazy fetches (cut\n * tool outputs) target what the user can see rather than the whole loaded\n * history. Omitted: every message counts as mounted (the flat renderers).\n */\n isMessageMounted?: ((messageId: string) => boolean) | undefined;\n /**\n * Cut tool outputs this mount reads at once; the rest wait for one to\n * settle. One mounted message can hold a whole agent run — a hundred tool\n * steps — and the host rate-limits a client's frames, so a reader that sends\n * them all together gets refusals back for most of them. Omitted: every\n * mounted output is asked for together (renderers whose mounted set is\n * already small).\n */\n maxConcurrentToolOutputs?: number;\n maxChainedLoads?: number;\n /** Pages adding no converted message loaded per request before it stops; see {@link DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS}. */\n maxUnseenLoads?: number;\n /** A page interest resolved (telemetry). */\n onHistoryLoad?: ((event: DeepAgentHistoryLoadEvent) => void) | undefined;\n /**\n * Older turns paged by command (`history/page`, protocol 3) into this store:\n * the same one the thread joins in front of its live window\n * (`useDeepAgentThread({ historyStore })`). Used only against a host that\n * advertises `DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION`; there every older\n * page (the button, the near-top chain, the opening fill) is a `history/page`\n * of whole turns and no interest page is stated, so the attach's view stays\n * the head however far back the reader goes. Omitted, or an older host:\n * interest pages, as before.\n */\n historyPages?: DeepAgentHistoryStore | undefined;\n /** Turns one history page asks for. */\n historyPageTurns?: number;\n /** A history page resolved (telemetry). */\n onHistoryPage?: ((event: DeepAgentHistoryPageEvent) => void) | undefined;\n /** A read failed; the sync itself recovers (the pending marks are released). */\n onError?:\n | ((error: unknown, command: 'athena/interest' | 'history/page' | 'history/tool_output') => void)\n | undefined;\n now?: () => number;\n}\n\nexport interface DeepAgentWindowSyncState {\n /** The joined window, or `null` while the head interest has not resolved (both halves are inert). */\n window: DeepAgentMessageWindow | null;\n /** Whether the host holds messages older than the loaded window. */\n hasOlder: boolean;\n /**\n * Whether the next page can be asked for: older messages exist and the\n * view has room for them. `hasOlder && !canLoadOlder` is the depth limit —\n * an edge row says so instead of offering a dead button. The host bounds\n * one attach's view twice: `MAX_INTERESTS` requests, and an interest\n * document that lists every loaded message within a byte budget (about a\n * thousand messages). The second is found when the host refuses a page as\n * `oversized-interest` ({@link isOversizedInterestRejection}).\n */\n canLoadOlder: boolean;\n /** A page of older history is in flight. */\n loading: boolean;\n /** Ask for the next page of older history now (an edge row's button, a keypress). A no-op before the head resolved, at the beginning, or once `canLoadOlder` is false. */\n loadOlder: () => void;\n}\n\n/**\n * Whether an `athena/interest` `set` came back refused because the windows it\n * states resolve past what one attach's interest document carries: the view\n * is as deep as this connection can load, and asking again only gets the same\n * refusal.\n */\nexport function isOversizedInterestRejection(error: unknown): boolean {\n const failure = (error as { failure?: { fate?: unknown; code?: unknown } } | null | undefined)\n ?.failure;\n return failure?.fate === 'rejected' && failure.code === DEEP_AGENT_OVERSIZED_INTEREST_CODE;\n}\n\nconst everyMessageMounted = (): boolean => true;\nconst defaultNow = (): number => Date.now();\nconst noopSubscribe = () => () => {};\n\n/** The statewire extras of the nearest aui thread; throws on a non-statewire thread like the library's own hooks. */\nconst useStatewireExtras = (): StatewireThread.Extras =>\n useAuiState((s) => {\n if (!hasStatewireThreadExtras(s.thread.extras)) {\n throw new Error('useDeepAgentWindowSync requires a statewire thread');\n }\n return s.thread.extras as StatewireThread.Extras;\n });\n\n/** The joined interest window of the nearest statewire thread. */\nexport function useDeepAgentMessageWindow(): DeepAgentMessageWindow | null {\n const documents = useStatewireExtras().documents;\n const mounted = useSyncExternalStore(\n documents?.subscribe ?? noopSubscribe,\n () => documents?.list(),\n () => documents?.list()\n );\n return useMemo(() => readDeepAgentMessageWindow(mounted), [mounted]);\n}\n\n/**\n * The client half of the interest window, shared by every surface — mounted\n * once per runtime, inside its aui provider.\n *\n * - **Older history.** While the host renderer reports the top of the loaded\n * history near (`nearTop`) and the window says older messages exist, this\n * re-states the interests with one more page (anchored at the window's\n * first message) — the host mounts its documents for this client alone —\n * chaining at most `maxChainedLoads` pages per approach; `loadOlder` asks\n * for one page on demand (an edge row's button). Never two loads in flight.\n * A re-attach's hello carries the view the client declares on the attach\n * (`useDeepAgentThread`), every page in it however it was loaded (this\n * hook, a handover's or a search's reveal, an edit's parent). A hello that\n * does not carry the view the last connected session held — a host that\n * reads no declaration and has no memo of the client id — gets it stated\n * again ({@link restatedInterestRequests}).\n * - **Cut tool outputs.** Tool cards whose output the wire carried cut\n * (`artifact._athena_content_truncated`) get it fetched whole through\n * `history/tool_output` once their message is mounted, at most\n * `maxConcurrentToolOutputs` at a time; the converter puts it back\n * (`toolOutputs`), so the card re-renders complete. An output the host\n * replaced since (the marker's `chars` changed) is fetched again.\n */\n/**\n * Whether an older page put a new converted message ahead of the thread's\n * first one. Older history only ever merges into or lands before the first\n * converted message, so the second one is a stable landmark: it moved down iff\n * the page showed something. A new tail message does not move it. Without a\n * second message (or once it is gone) the converted count decides.\n */\nfunction pageShowedEarlierMessage(\n from: { count: number; secondId: string | undefined },\n messages: readonly DeepAgentWindowSyncMessage[]\n): boolean {\n if (from.secondId !== undefined) {\n const index = messages.findIndex((message) => message.id === from.secondId);\n if (index !== -1) return index > 1;\n }\n return messages.length > from.count;\n}\n\n/** Whether a converted message is a turn's reply rather than its prompt (unknown without a role). */\nfunction isReply(message: DeepAgentWindowSyncMessage | undefined): boolean {\n return message?.role !== undefined && message.role !== 'user';\n}\n\n/**\n * Whether the loaded thread still opens without context: it should open on a\n * prompt and hold at least one earlier turn, so the newest turn shows with the\n * one before it (a turn is a prompt followed by its reply). Queued and live\n * prompts land at the tail with no reply yet, so they never count; prompts\n * alone need nothing. Without roles, a lone converted message stands in for it.\n */\nfunction opensMidTurn(messages: readonly DeepAgentWindowSyncMessage[]): boolean {\n const first = messages[0];\n if (first === undefined) return false;\n if (messages.every((message) => message.role === undefined)) return messages.length < 2;\n if (first.role !== 'user') return true;\n if (messages.every((message) => message.role === 'user')) return false;\n let turns = 0;\n for (let index = 1; index < messages.length; index += 1) {\n if (messages[index - 1]!.role === 'user' && messages[index]!.role !== 'user') turns += 1;\n }\n return turns < 2;\n}\n\nexport function useDeepAgentWindowSync({\n messages,\n pageSize,\n toolOutputs,\n nearTop = false,\n nearTopEpoch = 0,\n isMessageMounted = everyMessageMounted,\n maxConcurrentToolOutputs = Number.POSITIVE_INFINITY,\n maxChainedLoads = DEEP_AGENT_MAX_CHAINED_HISTORY_LOADS,\n maxUnseenLoads = DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS,\n onHistoryLoad,\n historyPages,\n historyPageTurns = DEEP_AGENT_HISTORY_PAGE_TURNS,\n onHistoryPage,\n onError,\n now = defaultNow,\n}: UseDeepAgentWindowSyncOptions): DeepAgentWindowSyncState {\n const { sendCommand, invoke, connection } = useStatewireExtras();\n const window = useDeepAgentMessageWindow();\n const hostVersion = useAuiState((s) => {\n const extras = s.thread.extras as Partial<StatewireThread.Extras> | undefined;\n return readDeepAgentProtocol(extras?.state)?.version ?? 0;\n });\n // Older history comes by command when the surface keeps a store for it and\n // the host answers it; the view then stays the head.\n const pagesByCommand =\n historyPages !== undefined && hostVersion >= DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION;\n const historySnapshot = useSyncExternalStore(\n historyPages?.subscribe ?? noopSubscribe,\n () => historyPages?.getSnapshot() ?? null,\n () => historyPages?.getSnapshot() ?? null\n );\n const liveIds = useMemo(() => new Set(window?.chain.map((entry) => entry.id) ?? []), [window]);\n // The pages that still meet the live window; a detached store is cleared below.\n const history: DeepAgentHistorySnapshot | null =\n historySnapshot !== null &&\n window !== null &&\n historyPages !== undefined &&\n !historyPages.isDetached({ threadId: window.threadId, liveIds })\n ? historySnapshot\n : null;\n const onHistoryPageRef = useRef(onHistoryPage);\n onHistoryPageRef.current = onHistoryPage;\n const [loading, setLoading] = useState(false);\n // The view the host refused a page over as deeper than one attach holds\n // (`oversized-interest`): its conversation and how many messages it covered.\n // A view at least that large gets the same refusal (a run's appends only\n // grow it); one that shrank — an edit rewound the transcript, a re-attach\n // came back smaller — may fit a page again.\n const [spentDepth, setSpentDepth] = useState<{ threadId: string | undefined; loaded: number } | null>(\n null\n );\n const depthSpent =\n spentDepth !== null &&\n window !== null &&\n spentDepth.threadId === window.threadId &&\n window.chain.length >= spentDepth.loaded;\n const [requests, setRequests] = useState(0);\n const servedRequestsRef = useRef(0);\n const inflightRef = useRef(false);\n const chainRef = useRef({ epoch: 0, loads: 0, unseen: 0, requested: false });\n // Pages loaded to show the opening turn's prompt; `null` once it shows, the\n // user took over, or a page failed — never re-armed for this mount.\n const openingFillRef = useRef<number | null>(0);\n // The converted thread when the in-flight page was stated; `null` once its\n // settle was judged (or it failed).\n const pageFromRef = useRef<{ count: number; secondId: string | undefined } | null>(null);\n const aliveRef = useRef(true);\n // The window the last connected session held, whoever paged it in, and the\n // session whose hello it was last checked against (a hello resets the\n // documents to what the host seeded).\n const heldRef = useRef<DeepAgentMessageWindow | null>(null);\n const restatedConnectionRef = useRef<unknown>(null);\n // Outputs already asked for and answered by this mount — fetched, refused,\n // or failed — by the `chars` they were asked for. The converter re-runs on\n // every wire change, and the store is a bounded LRU: without this memory a\n // refused read would leave on every pass, and once a transcript holds more\n // cut outputs than the store retains, each fetch would evict a still-loaded\n // output and the next pass would fetch it again, forever. An evicted output\n // renders its cut text (the REST display limit) rather than re-entering the\n // loop; a marker whose `chars` moved (the host replaced the output) is asked\n // for again.\n const answeredRef = useRef(new Map<string, number>());\n // Reads this mount has in flight, and whether a pass left outputs waiting\n // for one to settle (`maxConcurrentToolOutputs`): only then does a settle\n // re-run the pass, so an unbounded mount renders no more than before.\n const toolOutputsInFlightRef = useRef(0);\n const toolOutputsWaitingRef = useRef(false);\n const [toolOutputSettles, setToolOutputSettles] = useState(0);\n const onHistoryLoadRef = useRef(onHistoryLoad);\n onHistoryLoadRef.current = onHistoryLoad;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const nowRef = useRef(now);\n nowRef.current = now;\n useEffect(() => {\n aliveRef.current = true;\n return () => {\n aliveRef.current = false;\n };\n }, []);\n\n // Pages that no longer meet the live window (another conversation, or an\n // edit rewound past their anchor) describe another transcript: drop them,\n // and the edge offers older history again from the window's first message.\n useEffect(() => {\n if (historyPages === undefined || historySnapshot === null || window === null) return;\n if (window.chain.length === 0) return;\n if (historyPages.isDetached({ threadId: window.threadId, liveIds })) historyPages.clear();\n }, [historyPages, historySnapshot, window, liveIds]);\n\n useEffect(() => {\n if (connection.status !== 'connected' || window === null) return;\n if (restatedConnectionRef.current === connection) {\n heldRef.current = window;\n return;\n }\n // Decided once per connected session, on the hello's interest document.\n restatedConnectionRef.current = connection;\n const held = heldRef.current;\n heldRef.current = window;\n // A page still in flight was stated over the held window: it restates it.\n if (held === null || inflightRef.current || messageWindowCarries({ hello: window, held })) return;\n // Another conversation's hello (the runtime switched threads under this mount).\n if (held.threadId !== undefined && window.threadId !== undefined && held.threadId !== window.threadId) {\n return;\n }\n // Held like a page, so no page is stated over it while it is in flight.\n inflightRef.current = true;\n setLoading(true);\n invoke(DEEP_AGENT_INTEREST_PROTOCOL, 'set', [restatedInterestRequests({ held, hello: window })])\n .catch((error: unknown) => {\n onErrorRef.current?.(error, 'athena/interest');\n })\n .finally(() => {\n inflightRef.current = false;\n if (aliveRef.current) setLoading(false);\n });\n }, [connection, invoke, window]);\n\n useEffect(() => {\n if (window === null || inflightRef.current) return;\n // Older turns by command when this surface keeps a store and the host\n // answers it (whole turns before the oldest message held, outside the\n // view); interest pages otherwise. The asks are the same either way.\n const store = pagesByCommand ? historyPages : undefined;\n if (depthSpent && store === undefined) {\n // An ask now would get the same refusal: answer it here, so it never\n // reaches another conversation this mount switches to.\n servedRequestsRef.current = requests;\n pageFromRef.current = null;\n return;\n }\n const from = pageFromRef.current;\n pageFromRef.current = null;\n // A page by command always shows a turn's prompt (it never sets `from`).\n const lastPageUnseen =\n from !== null && from.count > 0 && !pageShowedEarlierMessage(from, messages);\n const pageRequests = store === undefined ? pageInterestRequests(window, pageSize) : null;\n if (store === undefined ? pageRequests === null : !(history?.more ?? window.hasOlder)) return;\n const requested = requests !== servedRequestsRef.current;\n const chain = chainRef.current;\n let fillPage = false;\n if (\n openingFillRef.current !== null &&\n (requested || nearTop || (messages.length > 0 && !opensMidTurn(messages)))\n ) {\n openingFillRef.current = null;\n }\n if (requested) {\n // An explicit ask re-arms the chain for this approach.\n servedRequestsRef.current = requests;\n chainRef.current = { epoch: nearTopEpoch, loads: 1, unseen: 0, requested: true };\n } else if (lastPageUnseen && (chain.requested || (nearTop && chain.epoch === nearTopEpoch))) {\n // The page landed inside the first loaded turn: keep going until one shows.\n if (chain.unseen >= maxUnseenLoads) return;\n chain.unseen += 1;\n } else if (openingFillRef.current !== null && opensMidTurn(messages)) {\n if (openingFillRef.current >= maxUnseenLoads) return;\n openingFillRef.current += 1;\n fillPage = true;\n } else {\n if (!nearTop) return;\n if (chain.epoch !== nearTopEpoch) {\n chainRef.current = { epoch: nearTopEpoch, loads: 0, unseen: 0, requested: false };\n }\n if (chainRef.current.loads >= maxChainedLoads) return;\n chainRef.current.loads += 1;\n }\n const startedAt = nowRef.current();\n const durationMs = () => Math.max(0, Math.round(nowRef.current() - startedAt));\n const settle = () => {\n inflightRef.current = false;\n if (aliveRef.current) setLoading(false);\n };\n if (store !== undefined) {\n const before = history?.turns[0]?.id ?? window.chain[0]?.id;\n if (before === undefined) return;\n inflightRef.current = true;\n setLoading(true);\n store\n .requestOlder({\n send: sendCommand,\n threadId: window.threadId ?? '',\n before,\n beforeIsPrompt:\n history !== null || window.messages.find((message) => message.id === before)?.type === 'human',\n turns: historyPageTurns,\n })\n .then((answered) => {\n onHistoryPageRef.current?.({ before, turns: historyPageTurns, answered, durationMs: durationMs() });\n })\n .catch((error: unknown) => {\n if (fillPage) openingFillRef.current = null;\n onErrorRef.current?.(error, 'history/page');\n })\n .finally(settle);\n return;\n }\n if (pageRequests === null) return;\n // The page continues the oldest loaded turn (see DEEP_AGENT_MAX_UNSEEN_HISTORY_LOADS).\n const insideTurn = lastPageUnseen || isReply(messages[0]);\n const stated =\n (insideTurn && pageInterestRequests(window, DEEP_AGENT_MAX_MESSAGE_WINDOW)) || pageRequests;\n pageFromRef.current = { count: messages.length, secondId: messages[1]?.id };\n const page = window.pages + 1;\n const request = stated[stated.length - 1] as DeepAgentInterestRequest;\n inflightRef.current = true;\n setLoading(true);\n invoke(DEEP_AGENT_INTEREST_PROTOCOL, 'set', [stated])\n .then(() => {\n onHistoryLoadRef.current?.({ page, request, durationMs: durationMs() });\n })\n .catch((error: unknown) => {\n pageFromRef.current = null;\n if (fillPage) openingFillRef.current = null;\n if (isOversizedInterestRejection(error) && aliveRef.current) {\n setSpentDepth({ threadId: window.threadId, loaded: window.chain.length });\n }\n onErrorRef.current?.(error, 'athena/interest');\n })\n .finally(settle);\n // `loading` re-arms the chain once a page settled after its documents moved the window.\n }, [\n nearTop,\n nearTopEpoch,\n requests,\n window,\n loading,\n messages,\n invoke,\n maxChainedLoads,\n maxUnseenLoads,\n pageSize,\n depthSpent,\n pagesByCommand,\n historyPages,\n history,\n historyPageTurns,\n sendCommand,\n ]);\n\n useEffect(() => {\n if (window === null || toolOutputs === undefined) return;\n toolOutputsWaitingRef.current = false;\n for (const message of messages) {\n if (!isMessageMounted(message.id)) continue;\n for (const part of message.content) {\n if (part.type !== 'tool-call') continue;\n const marker = readTruncatedToolOutputArtifact(part.artifact);\n if (marker === null || toolOutputs.isPending(marker.messageId)) continue;\n // Fetched for this very length already; a different length means the\n // host replaced the output under the same id since.\n if (toolOutputs.entry(marker.messageId)?.chars === marker.chars) continue;\n if (answeredRef.current.get(marker.messageId) === marker.chars) continue;\n if (toolOutputsInFlightRef.current >= maxConcurrentToolOutputs) {\n toolOutputsWaitingRef.current = true;\n return;\n }\n const { messageId, chars } = marker;\n toolOutputsInFlightRef.current += 1;\n toolOutputs.markPending(messageId);\n Promise.resolve(sendCommand(buildToolOutputCommand({ messageId })))\n .then((payload) => {\n answeredRef.current.set(messageId, chars);\n const result = readToolOutputResult(payload);\n if (result === null) {\n toolOutputs.clearPending(messageId);\n return;\n }\n toolOutputs.set(result.messageId, { content: result.content, chars });\n })\n .catch((error: unknown) => {\n answeredRef.current.set(messageId, chars);\n toolOutputs.clearPending(messageId);\n onErrorRef.current?.(error, 'history/tool_output');\n })\n .finally(() => {\n toolOutputsInFlightRef.current -= 1;\n if (toolOutputsWaitingRef.current && aliveRef.current) {\n setToolOutputSettles((count) => count + 1);\n }\n });\n }\n }\n }, [\n messages,\n isMessageMounted,\n window,\n sendCommand,\n toolOutputs,\n maxConcurrentToolOutputs,\n toolOutputSettles,\n ]);\n\n const loadOlder = useCallback(() => {\n setRequests((count) => count + 1);\n }, []);\n\n // By command, the host bounds nothing but the transcript's start: older\n // turns exist while the pages say so (the window's own edge before any).\n const hasOlder = pagesByCommand\n ? history !== null\n ? history.more\n : (window?.hasOlder ?? false)\n : (window?.hasOlder ?? false);\n const canLoadOlder = useMemo(\n () =>\n pagesByCommand\n ? window !== null && hasOlder\n : window !== null && !depthSpent && pageInterestRequests(window, pageSize) !== null,\n [pagesByCommand, hasOlder, window, pageSize, depthSpent]\n );\n\n return { window, hasOlder, canLoadOlder, loading, loadOlder };\n}\n"],"names":["_a"],"mappings":"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"}