@athenaintel/react 0.30.0 → 0.32.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 (147) hide show
  1. package/README.md +61 -0
  2. package/dist/agent-runtime/src/athena-asset-drag.cjs +44 -0
  3. package/dist/agent-runtime/src/athena-asset-drag.cjs.map +1 -0
  4. package/dist/agent-runtime/src/athena-asset-drag.js +44 -0
  5. package/dist/agent-runtime/src/athena-asset-drag.js.map +1 -0
  6. package/dist/agent-runtime/src/config-mutations.cjs +59 -0
  7. package/dist/agent-runtime/src/config-mutations.cjs.map +1 -0
  8. package/dist/agent-runtime/src/config-mutations.js +59 -0
  9. package/dist/agent-runtime/src/config-mutations.js.map +1 -0
  10. package/dist/agent-runtime/src/generated/runconfig-contract.cjs +6 -0
  11. package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
  12. package/dist/agent-runtime/src/generated/runconfig-contract.js +6 -0
  13. package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
  14. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +48 -0
  15. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
  16. package/dist/agent-runtime/src/quota-safe-local-storage-session.js +49 -1
  17. package/dist/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
  18. package/dist/agent-runtime/src/tool-metadata.cjs +25 -6
  19. package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
  20. package/dist/agent-runtime/src/tool-metadata.js +25 -6
  21. package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
  22. package/dist/agent-runtime/src/use-deep-agent-config.cjs +117 -1
  23. package/dist/agent-runtime/src/use-deep-agent-config.cjs.map +1 -1
  24. package/dist/agent-runtime/src/use-deep-agent-config.js +118 -2
  25. package/dist/agent-runtime/src/use-deep-agent-config.js.map +1 -1
  26. package/dist/assets/AthenaAssetEmbed.cjs +6 -1
  27. package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
  28. package/dist/assets/AthenaAssetEmbed.d.ts +2 -0
  29. package/dist/assets/AthenaAssetEmbed.js +7 -2
  30. package/dist/assets/AthenaAssetEmbed.js.map +1 -1
  31. package/dist/assets/asset-embed-messages.cjs +6 -0
  32. package/dist/assets/asset-embed-messages.cjs.map +1 -1
  33. package/dist/assets/asset-embed-messages.d.ts +7 -0
  34. package/dist/assets/asset-embed-messages.js +6 -0
  35. package/dist/assets/asset-embed-messages.js.map +1 -1
  36. package/dist/chat/AthenaChat.cjs +41 -26
  37. package/dist/chat/AthenaChat.cjs.map +1 -1
  38. package/dist/chat/AthenaChat.js +41 -26
  39. package/dist/chat/AthenaChat.js.map +1 -1
  40. package/dist/chat/super-grouping/SuperGroupingCard.cjs +31 -11
  41. package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
  42. package/dist/chat/super-grouping/SuperGroupingCard.d.ts +14 -3
  43. package/dist/chat/super-grouping/SuperGroupingCard.js +32 -12
  44. package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
  45. package/dist/chat/super-grouping/SuperGroupingTranscript.cjs +80 -53
  46. package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
  47. package/dist/chat/super-grouping/SuperGroupingTranscript.d.ts +2 -2
  48. package/dist/chat/super-grouping/SuperGroupingTranscript.js +81 -54
  49. package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
  50. package/dist/chat/super-grouping/activity-timeline.cjs +19 -4
  51. package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
  52. package/dist/chat/super-grouping/activity-timeline.d.ts +20 -1
  53. package/dist/chat/super-grouping/activity-timeline.js +19 -4
  54. package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
  55. package/dist/chat/super-grouping/index.cjs +2 -0
  56. package/dist/chat/super-grouping/index.cjs.map +1 -1
  57. package/dist/chat/super-grouping/index.d.ts +1 -1
  58. package/dist/chat/super-grouping/index.js +3 -1
  59. package/dist/chat/super-grouping/toolkit-map.cjs +1 -0
  60. package/dist/chat/super-grouping/toolkit-map.cjs.map +1 -1
  61. package/dist/chat/super-grouping/toolkit-map.js +1 -0
  62. package/dist/chat/super-grouping/toolkit-map.js.map +1 -1
  63. package/dist/chat-ui/composer/tiptap-composer.cjs +40 -4
  64. package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
  65. package/dist/chat-ui/composer/tiptap-composer.js +40 -4
  66. package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
  67. package/dist/chat-ui/mentions/mention-chip.cjs +29 -2
  68. package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
  69. package/dist/chat-ui/mentions/mention-chip.d.ts +2 -5
  70. package/dist/chat-ui/mentions/mention-chip.js +30 -3
  71. package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
  72. package/dist/chat-ui/mentions/mention-extension.cjs +1 -1
  73. package/dist/chat-ui/mentions/mention-extension.cjs.map +1 -1
  74. package/dist/chat-ui/mentions/mention-extension.js +1 -1
  75. package/dist/chat-ui/mentions/mention-extension.js.map +1 -1
  76. package/dist/chat-ui/mentions/use-account-workspace-id.cjs +61 -0
  77. package/dist/chat-ui/mentions/use-account-workspace-id.cjs.map +1 -0
  78. package/dist/chat-ui/mentions/use-account-workspace-id.d.ts +3 -0
  79. package/dist/chat-ui/mentions/use-account-workspace-id.js +61 -0
  80. package/dist/chat-ui/mentions/use-account-workspace-id.js.map +1 -0
  81. package/dist/chat-ui/mentions/use-member-avatar.cjs +75 -0
  82. package/dist/chat-ui/mentions/use-member-avatar.cjs.map +1 -0
  83. package/dist/chat-ui/mentions/use-member-avatar.d.ts +2 -0
  84. package/dist/chat-ui/mentions/use-member-avatar.js +75 -0
  85. package/dist/chat-ui/mentions/use-member-avatar.js.map +1 -0
  86. package/dist/collab/client.cjs +80 -19
  87. package/dist/collab/client.cjs.map +1 -1
  88. package/dist/collab/client.d.ts +22 -0
  89. package/dist/collab/client.js +80 -19
  90. package/dist/collab/client.js.map +1 -1
  91. package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
  92. package/dist/diagnostics/athena-diagnostics.d.ts +3 -1
  93. package/dist/diagnostics/athena-diagnostics.js.map +1 -1
  94. package/dist/index.cjs +4 -0
  95. package/dist/index.cjs.map +1 -1
  96. package/dist/index.d.ts +3 -1
  97. package/dist/index.js +5 -1
  98. package/dist/index.js.map +1 -1
  99. package/dist/provider/AthenaProvider.cjs +34 -4
  100. package/dist/provider/AthenaProvider.cjs.map +1 -1
  101. package/dist/provider/AthenaProvider.d.ts +7 -1
  102. package/dist/provider/AthenaProvider.js +36 -6
  103. package/dist/provider/AthenaProvider.js.map +1 -1
  104. package/dist/react/package.json.cjs +1 -1
  105. package/dist/react/package.json.js +1 -1
  106. package/dist/runtime/StatewireModelLaneSync.cjs +96 -0
  107. package/dist/runtime/StatewireModelLaneSync.cjs.map +1 -0
  108. package/dist/runtime/StatewireModelLaneSync.d.ts +45 -0
  109. package/dist/runtime/StatewireModelLaneSync.js +96 -0
  110. package/dist/runtime/StatewireModelLaneSync.js.map +1 -0
  111. package/dist/runtime/statewire-lifecycle.cjs +5 -2
  112. package/dist/runtime/statewire-lifecycle.cjs.map +1 -1
  113. package/dist/runtime/statewire-lifecycle.d.ts +5 -0
  114. package/dist/runtime/statewire-lifecycle.js +5 -2
  115. package/dist/runtime/statewire-lifecycle.js.map +1 -1
  116. package/dist/runtime/statewire-model-lane.cjs +28 -0
  117. package/dist/runtime/statewire-model-lane.cjs.map +1 -0
  118. package/dist/runtime/statewire-model-lane.d.ts +64 -0
  119. package/dist/runtime/statewire-model-lane.js +28 -0
  120. package/dist/runtime/statewire-model-lane.js.map +1 -0
  121. package/dist/runtime/statewire-run-config.cjs +16 -2
  122. package/dist/runtime/statewire-run-config.cjs.map +1 -1
  123. package/dist/runtime/statewire-run-config.d.ts +10 -0
  124. package/dist/runtime/statewire-run-config.js +16 -2
  125. package/dist/runtime/statewire-run-config.js.map +1 -1
  126. package/dist/runtime/statewire-server-lane-context.cjs +24 -0
  127. package/dist/runtime/statewire-server-lane-context.cjs.map +1 -0
  128. package/dist/runtime/statewire-server-lane-context.d.ts +30 -0
  129. package/dist/runtime/statewire-server-lane-context.js +24 -0
  130. package/dist/runtime/statewire-server-lane-context.js.map +1 -0
  131. package/dist/runtime/useAthenaStatewireRuntime.cjs +38 -18
  132. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  133. package/dist/runtime/useAthenaStatewireRuntime.d.ts +8 -1
  134. package/dist/runtime/useAthenaStatewireRuntime.js +39 -19
  135. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  136. package/dist/styles.css +1 -1
  137. package/dist/threads/api.cjs +2 -1
  138. package/dist/threads/api.cjs.map +1 -1
  139. package/dist/threads/api.d.ts +1 -0
  140. package/dist/threads/api.js +2 -1
  141. package/dist/threads/api.js.map +1 -1
  142. package/dist/threads/use-athena-thread-model.cjs +14 -0
  143. package/dist/threads/use-athena-thread-model.cjs.map +1 -0
  144. package/dist/threads/use-athena-thread-model.d.ts +22 -0
  145. package/dist/threads/use-athena-thread-model.js +14 -0
  146. package/dist/threads/use-athena-thread-model.js.map +1 -0
  147. package/package.json +2 -2
@@ -11,6 +11,7 @@ const statewireRunConfig = require("./statewire-run-config.cjs");
11
11
  const runconfigContract = require("../agent-runtime/src/generated/runconfig-contract.cjs");
12
12
  const useDeepAgentRuntime = require("../agent-runtime/src/use-deep-agent-runtime.cjs");
13
13
  const errors = require("../agent-runtime/src/errors.cjs");
14
+ const statewireState = require("../agent-runtime/src/statewire-state.cjs");
14
15
  const composerMarkdown = require("../agent-runtime/src/composer-markdown.cjs");
15
16
  const ATHENA_SDK_MESSAGE_WINDOW = {
16
17
  size: runconfigContract.DEEP_AGENT_DEFAULT_MESSAGE_WINDOW
@@ -49,7 +50,8 @@ function useAthenaStatewireRuntime(config) {
49
50
  onError,
50
51
  onConnectionChange,
51
52
  onRawConnectionChange,
52
- onRunningChange
53
+ onRunningChange,
54
+ onServerState
53
55
  } = config;
54
56
  statewireRunConfig.resolveAgentProp({ agent });
55
57
  const clientTools = useStatewireClientTools(frontendToolkit);
@@ -65,6 +67,22 @@ function useAthenaStatewireRuntime(config) {
65
67
  { thread_id: threadId, is_new_chat: isNewChat }
66
68
  );
67
69
  }
70
+ const runConfigValue = statewireRunConfig.buildStatewireRunConfig({
71
+ model,
72
+ agent,
73
+ channel,
74
+ tools,
75
+ frontendToolIds,
76
+ workbench,
77
+ knowledgeBase,
78
+ systemPrompt,
79
+ appId,
80
+ extraRunConfig,
81
+ clientTools: statewireClientTools.statewireClientToolWireEntries(clientTools)
82
+ });
83
+ const runConfigKey = JSON.stringify(runConfigValue);
84
+ const lastStateRef = react.useRef(null);
85
+ const helloLandedRef = react.useRef(false);
68
86
  const auiTools = react.useMemo(() => react$1.Tools({ toolkit: frontendToolkit }), [frontendToolkit]);
69
87
  const useSdkClient = (thread) => react$1.useAui({ thread, tools: auiTools });
70
88
  return useDeepAgentRuntime.useDeepAgentRuntime({
@@ -102,12 +120,15 @@ function useAthenaStatewireRuntime(config) {
102
120
  // shows the text exactly as typed (`UserMessageText`).
103
121
  getMessageMetadata: composerMarkdown.withStagedComposerMarkdown({ threadId }),
104
122
  useClient: useSdkClient,
105
- onStateChange: () => {
123
+ onStateChange: (state) => {
106
124
  const endSpan = attachSpanRef.current;
107
125
  if (endSpan) {
108
126
  attachSpanRef.current = null;
109
127
  endSpan("statewire.snapshot", { data: { thread_id: threadId } });
110
128
  }
129
+ if (!statewireState.isDeepAgentStateHydrated(state)) return;
130
+ lastStateRef.current = state;
131
+ if (helloLandedRef.current) onServerState == null ? void 0 : onServerState(state);
111
132
  },
112
133
  onConnectionChange: (connection) => {
113
134
  athenaDiagnostics.athenaDiagnostics.gauge("statewire.connection", (connection == null ? void 0 : connection.status) ?? null);
@@ -123,25 +144,24 @@ function useAthenaStatewireRuntime(config) {
123
144
  }
124
145
  onConnectionChange == null ? void 0 : onConnectionChange(connection);
125
146
  },
126
- onRawConnectionChange,
147
+ onRawConnectionChange: (connection) => {
148
+ if (connection.status === "connected" && !helloLandedRef.current) {
149
+ helloLandedRef.current = true;
150
+ const helloState = lastStateRef.current;
151
+ if (helloState) onServerState == null ? void 0 : onServerState(helloState);
152
+ }
153
+ onRawConnectionChange == null ? void 0 : onRawConnectionChange(connection);
154
+ },
127
155
  onRunningChange,
128
156
  // Each model-context notification pulls the latest getter through the
129
- // core's per-render ref. Consumers commonly pass fresh array literals per
130
- // render, which must not thrash registration (no `key`: once per client).
157
+ // core's per-render ref; the value-stable key re-registers (and so
158
+ // notifies) only when the built runConfig actually changed. On a thread
159
+ // with a server config lane, agora keeps only the per-send keys of what
160
+ // this carries; `StatewireModelLaneSync` writes a changed `model` to the
161
+ // lane itself.
131
162
  runConfig: {
132
- get: () => statewireRunConfig.buildStatewireRunConfig({
133
- model,
134
- agent,
135
- channel,
136
- tools,
137
- frontendToolIds,
138
- workbench,
139
- knowledgeBase,
140
- systemPrompt,
141
- appId,
142
- extraRunConfig,
143
- clientTools: statewireClientTools.statewireClientToolWireEntries(clientTools)
144
- })
163
+ get: () => runConfigValue,
164
+ key: runConfigKey
145
165
  },
146
166
  onError: (error) => {
147
167
  if (!errors.isStatewireChannelTeardown(error)) {
@@ -1 +1 @@
1
- {"version":3,"file":"useAthenaStatewireRuntime.cjs","sources":["../../src/runtime/useAthenaStatewireRuntime.ts"],"sourcesContent":["import type { AssistantClient, Toolkit } from '@assistant-ui/react';\nimport { Tools, useAui } from '@assistant-ui/react';\nimport {\n DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n type DeepAgentMessageWindowDeclaration,\n type DeepAgentThreadElement,\n type DeepAgentThreadSnapshotCache,\n type DeepAgentToolOutputStore,\n isStatewireChannelTeardown,\n logUnhandledStatewireError,\n type RegisteredClientTool,\n useDeepAgentRuntime,\n type UseDeepAgentThreadOptions,\n withStagedComposerMarkdown,\n} from '@athenaintel/agent-runtime';\nimport { useContext, useMemo, useRef } from 'react';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport {\n collectStatewireClientTools,\n statewireClientToolWireEntries,\n} from '../chat/statewire-client-tools';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport {\n type AthenaStatewireTokenGetter,\n resolveStatewireAuthHeaders,\n} from './statewire-auth-headers';\nimport { statewireSessionKey } from './statewire-session-key';\n\ntype AthenaDiagnosticsSpanStarter = typeof athenaDiagnostics.span;\nimport {\n buildStatewireRunConfig,\n DEFAULT_STATEWIRE_MODEL,\n resolveAgentProp,\n} from './statewire-run-config';\n\nexport { DEFAULT_STATEWIRE_MODEL };\n\n/**\n * The head interest every SDK attach states (`athena/interest`): the host\n * mounts the transcript's tail as message documents instead of every message\n * — megabytes on long threads, over the 1 MiB frame limit of stock websocket\n * clients. Older pages load from the `StatewireHistoryEdge` row the chat UI\n * mounts above the messages, and cut tool outputs are fetched back for the\n * cards that show them.\n */\nexport const ATHENA_SDK_MESSAGE_WINDOW: DeepAgentMessageWindowDeclaration = {\n size: DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n};\n\nexport interface AthenaStatewireRuntimeConfig {\n /** Base URL of the statewire sync host (the `…/v2/threads` mount). */\n syncUrl: string;\n /** Thread ID the statewire session attaches to. */\n threadId: string;\n /** True only for a never-started local chat. Existing (or pre-assigned)\n * threads load until their server snapshot arrives. */\n isNewChat?: boolean;\n /** API key for authentication. Used when no auth token is provided. */\n apiKey?: string;\n /** Auth token. Takes priority over apiKey. */\n token?: string | null;\n /** Resolve the latest token immediately before a request (for expiring\n * clients). Called with `{ force: true }` right after the host refused the\n * previous credential (the transport's `staleAuth`), so a caching getter\n * mints a fresh token instead of returning the refused one. */\n getToken?: AthenaStatewireTokenGetter;\n /**\n * Per-provider LRU of each thread's last wire state. A switch back to a\n * remembered thread mounts with that snapshot and projects ready on the\n * first frame instead of a loading treatment; the attach snapshot then\n * replaces it. Owned above the per-thread mount so it survives switches.\n */\n snapshotCache?: DeepAgentThreadSnapshotCache;\n /** The head interest stated on the attach (see {@link ATHENA_SDK_MESSAGE_WINDOW}, the default). */\n messageWindow?: DeepAgentMessageWindowDeclaration;\n /**\n * Full tool outputs fetched back for a windowed wire's cut tool messages;\n * the thread re-converts when one lands. `AthenaProvider` owns one per\n * provider and hands the same store to `StatewireHistoryEdge`.\n */\n toolOutputs?: DeepAgentToolOutputStore;\n /** LLM model identifier. Defaults to the deep-agent default model. */\n model?: string;\n /** Agent selector: only `collab_agent:<asset_id>` refs are accepted (the run\n * executes AS that published collab agent). Any other non-empty value\n * throws — see `resolveAgentProp`. */\n agent?: string;\n /** Collab-agent channel id selecting that channel's overrides. */\n channel?: string;\n /** Backend toolkit IDs to enable. */\n tools?: string[];\n /** Frontend tool IDs to include in enabled_tools. */\n frontendToolIds?: string[];\n /** Frontend tools registered on the assistant client. Tools with a local\n * `execute` are also declared as `client_tools` and executed through the\n * statewire client-tool bridge. */\n frontendToolkit?: Toolkit;\n /** Asset IDs to include in the workbench. */\n workbench?: string[];\n /** Knowledge base IDs for RAG context. */\n knowledgeBase?: string[];\n /** System prompt override. */\n systemPrompt?: string;\n /** Client app identifier for session filtering. Sent as app_id in runConfig.custom. */\n appId?: string;\n /** Additional fields merged into runConfig.custom. */\n extraRunConfig?: Record<string, unknown>;\n /** Called on statewire transport errors (send rejections, stream failures). */\n onError?: (error: Error) => void;\n /** Projected connection status changes (deduped; null on unmount). */\n onConnectionChange?: UseDeepAgentThreadOptions['onConnectionChange'];\n /** Raw connection observer — carries the transport's reconnect handle. */\n onRawConnectionChange?: UseDeepAgentThreadOptions['onRawConnectionChange'];\n /** Notified when a run starts/stops. */\n onRunningChange?: UseDeepAgentThreadOptions['onRunningChange'];\n}\n\nconst EMPTY_TOOLKIT: Toolkit = {};\nconst EMPTY_TOOL_IDS: string[] = [];\n\n/** The client tools derived from the runtime's frontend toolkit — exposed so\n * the provider can mount the client-tool bridge with the same set. */\nexport function useStatewireClientTools(\n frontendToolkit: Toolkit | undefined,\n): RegisteredClientTool[] {\n return useMemo(\n () => collectStatewireClientTools(frontendToolkit ?? EMPTY_TOOLKIT),\n [frontendToolkit],\n );\n}\n\n/**\n * Statewire runtime for the Athena SDK — a thin shim over the shared\n * `@athenaintel/agent-runtime` `useDeepAgentRuntime`: it attaches to the\n * agora-hosted deep-agent thread at `${syncUrl}/${threadId}` and returns the\n * `AssistantClient` to mount via `AuiProvider` — the same integration shape as\n * the Olympus, Chrome extension, Office, and mobile statewire hosts.\n *\n * Auth: a token (resolved live through `getToken` when provided) rides\n * `Authorization: Bearer`, and an API key falls back to `X-API-KEY` — both\n * accepted by the statewire host.\n */\nexport function useAthenaStatewireRuntime(\n config: AthenaStatewireRuntimeConfig,\n): AssistantClient {\n const {\n syncUrl,\n threadId,\n isNewChat = false,\n apiKey,\n token,\n getToken,\n model,\n agent,\n channel,\n tools = EMPTY_TOOL_IDS,\n frontendToolIds = EMPTY_TOOL_IDS,\n frontendToolkit = EMPTY_TOOLKIT,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n snapshotCache,\n messageWindow = ATHENA_SDK_MESSAGE_WINDOW,\n toolOutputs,\n onError,\n onConnectionChange,\n onRawConnectionChange,\n onRunningChange,\n } = config;\n\n // Fail loud at mount, not at first send: the statewire host always runs the\n // Athena deep agent, so an `agent` outside the collab_agent namespace can\n // never apply. Throwing here (render time) is what makes a misconfigured\n // integration visible instead of quietly answering as the wrong agent.\n resolveAgentProp({ agent });\n\n const clientTools = useStatewireClientTools(frontendToolkit);\n\n // The persisted command lane is keyed by WHO is signed in as well as by host\n // and thread (see `statewireSessionKey`).\n const authContext = useContext(AthenaAuthContext);\n const principal = authContext?.user?.userId ?? '';\n\n // Attach → first server snapshot span, keyed per thread attach.\n const attachSpanRef = useRef<ReturnType<AthenaDiagnosticsSpanStarter> | null>(null);\n const attachThreadRef = useRef<string | null>(null);\n if (attachThreadRef.current !== threadId) {\n attachThreadRef.current = threadId;\n attachSpanRef.current = athenaDiagnostics.span(\n `statewire.attach:${threadId}`,\n 'statewire.attach.start',\n { thread_id: threadId, is_new_chat: isNewChat },\n );\n }\n\n const auiTools = useMemo(() => Tools({ toolkit: frontendToolkit }), [frontendToolkit]);\n // Web client for the shared runtime core (a `use*` name so the\n // rules-of-hooks lint sees the `useAui` call inside a custom hook; the core\n // invokes it unconditionally every render).\n const useSdkClient = (thread: DeepAgentThreadElement) => useAui({ thread, tools: auiTools });\n\n return useDeepAgentRuntime({\n surface: 'AthenaSDK',\n threadId,\n baseUrl: syncUrl,\n // Option closures are re-read per render by the core, so credential\n // rotation (new `token`/`getToken`/`apiKey` props) reaches the next\n // request without remounting the thread. The transport's `staleAuth`\n // (true right after a refused credential) is forwarded as `force`.\n headers: (ctx) => resolveStatewireAuthHeaders({ apiKey, token, getToken }, ctx),\n isNewChat,\n // Queued entries render in the SDK's queue panel, so only the steer lane\n // projects into the message tail.\n laneProjection: 'steer-only',\n // Durable session: a reload resumes the lane and resends whatever the\n // server has not marked durable. Scoped by host AND principal — a thread\n // id is only meaningful against the backend that minted it, and a stored\n // lane must never resend against another signed-in user. (Consumers\n // server-render this SDK; the core's availability probe keeps those\n // sessions process-local, as before the seam existed.)\n session: {\n kind: 'local-storage',\n key: (id) => statewireSessionKey({ syncUrl, principal, threadId: id }),\n },\n snapshotCache,\n // Head interest (see `ATHENA_SDK_MESSAGE_WINDOW`): the tail of the\n // transcript instead of every message; the chat UI's history edge pages\n // older ranges in and fetches cut tool outputs into `toolOutputs`.\n messageWindow,\n toolOutputs,\n capabilities: { edit: true, reload: true, continue: true },\n // The composer stages the draft each send came from right before it\n // sends; the message carries it as its composer markdown, so its bubble\n // shows the text exactly as typed (`UserMessageText`).\n getMessageMetadata: withStagedComposerMarkdown({ threadId }),\n useClient: useSdkClient,\n onStateChange: () => {\n // First snapshot for this attach ends the attach span (time-to-history).\n const endSpan = attachSpanRef.current;\n if (endSpan) {\n attachSpanRef.current = null;\n endSpan('statewire.snapshot', { data: { thread_id: threadId } });\n }\n },\n onConnectionChange: (connection) => {\n athenaDiagnostics.gauge('statewire.connection', connection?.status ?? null);\n if (connection?.status === 'stopped') {\n athenaDiagnostics.emit('statewire.connection', {\n level: 'warn',\n data: {\n status: connection.status,\n reason: connection.reason,\n message: connection.message,\n },\n });\n }\n onConnectionChange?.(connection);\n },\n onRawConnectionChange,\n onRunningChange,\n // Each model-context notification pulls the latest getter through the\n // core's per-render ref. Consumers commonly pass fresh array literals per\n // render, which must not thrash registration (no `key`: once per client).\n runConfig: {\n get: () =>\n buildStatewireRunConfig({\n model,\n agent,\n channel,\n tools,\n frontendToolIds,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n clientTools: statewireClientToolWireEntries(clientTools),\n }),\n },\n onError: (error) => {\n if (!isStatewireChannelTeardown(error)) {\n athenaDiagnostics.error(\n 'statewire.error',\n error,\n {\n code: 'statewire_rejected',\n message: 'The statewire host rejected a command',\n hint: 'Inspect error.detail — agora rejections carry a structured {code, message}.',\n },\n { thread_id: threadId },\n );\n }\n if (onError) {\n onError(error);\n return;\n }\n logUnhandledStatewireError('AthenaSDK', error);\n },\n });\n}\n"],"names":["DEEP_AGENT_DEFAULT_MESSAGE_WINDOW","useMemo","collectStatewireClientTools","resolveAgentProp","useContext","AthenaAuthContext","useRef","athenaDiagnostics","Tools","useAui","useDeepAgentRuntime","resolveStatewireAuthHeaders","statewireSessionKey","withStagedComposerMarkdown","buildStatewireRunConfig","statewireClientToolWireEntries","isStatewireChannelTeardown","logUnhandledStatewireError"],"mappings":"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"}
1
+ {"version":3,"file":"useAthenaStatewireRuntime.cjs","sources":["../../src/runtime/useAthenaStatewireRuntime.ts"],"sourcesContent":["import type { AssistantClient, Toolkit } from '@assistant-ui/react';\nimport { Tools, useAui } from '@assistant-ui/react';\nimport {\n DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n type DeepAgentMessageWindowDeclaration,\n type DeepAgentStreamValues,\n type DeepAgentThreadElement,\n type DeepAgentThreadSnapshotCache,\n type DeepAgentToolOutputStore,\n isDeepAgentStateHydrated,\n isStatewireChannelTeardown,\n logUnhandledStatewireError,\n type RegisteredClientTool,\n useDeepAgentRuntime,\n type UseDeepAgentThreadOptions,\n withStagedComposerMarkdown,\n} from '@athenaintel/agent-runtime';\nimport { useContext, useMemo, useRef } from 'react';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport {\n collectStatewireClientTools,\n statewireClientToolWireEntries,\n} from '../chat/statewire-client-tools';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport {\n type AthenaStatewireTokenGetter,\n resolveStatewireAuthHeaders,\n} from './statewire-auth-headers';\nimport { statewireSessionKey } from './statewire-session-key';\n\ntype AthenaDiagnosticsSpanStarter = typeof athenaDiagnostics.span;\nimport {\n buildStatewireRunConfig,\n DEFAULT_STATEWIRE_MODEL,\n resolveAgentProp,\n} from './statewire-run-config';\n\nexport { DEFAULT_STATEWIRE_MODEL };\n\n/**\n * The head interest every SDK attach states (`athena/interest`): the host\n * mounts the transcript's tail as message documents instead of every message\n * — megabytes on long threads, over the 1 MiB frame limit of stock websocket\n * clients. Older pages load from the `StatewireHistoryEdge` row the chat UI\n * mounts above the messages, and cut tool outputs are fetched back for the\n * cards that show them.\n */\nexport const ATHENA_SDK_MESSAGE_WINDOW: DeepAgentMessageWindowDeclaration = {\n size: DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n};\n\nexport interface AthenaStatewireRuntimeConfig {\n /** Base URL of the statewire sync host (the `…/v2/threads` mount). */\n syncUrl: string;\n /** Thread ID the statewire session attaches to. */\n threadId: string;\n /** True only for a never-started local chat. Existing (or pre-assigned)\n * threads load until their server snapshot arrives. */\n isNewChat?: boolean;\n /** API key for authentication. Used when no auth token is provided. */\n apiKey?: string;\n /** Auth token. Takes priority over apiKey. */\n token?: string | null;\n /** Resolve the latest token immediately before a request (for expiring\n * clients). Called with `{ force: true }` right after the host refused the\n * previous credential (the transport's `staleAuth`), so a caching getter\n * mints a fresh token instead of returning the refused one. */\n getToken?: AthenaStatewireTokenGetter;\n /**\n * Per-provider LRU of each thread's last wire state. A switch back to a\n * remembered thread mounts with that snapshot and projects ready on the\n * first frame instead of a loading treatment; the attach snapshot then\n * replaces it. Owned above the per-thread mount so it survives switches.\n */\n snapshotCache?: DeepAgentThreadSnapshotCache;\n /** The head interest stated on the attach (see {@link ATHENA_SDK_MESSAGE_WINDOW}, the default). */\n messageWindow?: DeepAgentMessageWindowDeclaration;\n /**\n * Full tool outputs fetched back for a windowed wire's cut tool messages;\n * the thread re-converts when one lands. `AthenaProvider` owns one per\n * provider and hands the same store to `StatewireHistoryEdge`.\n */\n toolOutputs?: DeepAgentToolOutputStore;\n /** LLM model identifier. Defaults to the deep-agent default model. */\n model?: string;\n /** Agent selector: only `collab_agent:<asset_id>` refs are accepted (the run\n * executes AS that published collab agent). Any other non-empty value\n * throws — see `resolveAgentProp`. */\n agent?: string;\n /** Collab-agent channel id selecting that channel's overrides. */\n channel?: string;\n /** Backend toolkit IDs to enable. */\n tools?: string[];\n /** Frontend tool IDs to include in enabled_tools. */\n frontendToolIds?: string[];\n /** Frontend tools registered on the assistant client. Tools with a local\n * `execute` are also declared as `client_tools` and executed through the\n * statewire client-tool bridge. */\n frontendToolkit?: Toolkit;\n /** Asset IDs to include in the workbench. */\n workbench?: string[];\n /** Knowledge base IDs for RAG context. */\n knowledgeBase?: string[];\n /** System prompt override. */\n systemPrompt?: string;\n /** Client app identifier for session filtering. Sent as app_id in runConfig.custom. */\n appId?: string;\n /** Additional fields merged into runConfig.custom. */\n extraRunConfig?: Record<string, unknown>;\n /** Called on statewire transport errors (send rejections, stream failures). */\n onError?: (error: Error) => void;\n /** Projected connection status changes (deduped; null on unmount). */\n onConnectionChange?: UseDeepAgentThreadOptions['onConnectionChange'];\n /** Raw connection observer — carries the transport's reconnect handle. */\n onRawConnectionChange?: UseDeepAgentThreadOptions['onRawConnectionChange'];\n /** Notified when a run starts/stops. */\n onRunningChange?: UseDeepAgentThreadOptions['onRunningChange'];\n /**\n * Observes the host's own state: called once the attach's hello has landed\n * (with the snapshot it carried) and then on every later frame — never with\n * the placeholder or remembered snapshot a thread renders before its hello.\n * Called per streamed token, so keep it cheap.\n */\n onServerState?: (state: DeepAgentStreamValues) => void;\n}\n\nconst EMPTY_TOOLKIT: Toolkit = {};\nconst EMPTY_TOOL_IDS: string[] = [];\n\n/** The client tools derived from the runtime's frontend toolkit — exposed so\n * the provider can mount the client-tool bridge with the same set. */\nexport function useStatewireClientTools(\n frontendToolkit: Toolkit | undefined,\n): RegisteredClientTool[] {\n return useMemo(\n () => collectStatewireClientTools(frontendToolkit ?? EMPTY_TOOLKIT),\n [frontendToolkit],\n );\n}\n\n/**\n * Statewire runtime for the Athena SDK — a thin shim over the shared\n * `@athenaintel/agent-runtime` `useDeepAgentRuntime`: it attaches to the\n * agora-hosted deep-agent thread at `${syncUrl}/${threadId}` and returns the\n * `AssistantClient` to mount via `AuiProvider` — the same integration shape as\n * the Olympus, Chrome extension, Office, and mobile statewire hosts.\n *\n * Auth: a token (resolved live through `getToken` when provided) rides\n * `Authorization: Bearer`, and an API key falls back to `X-API-KEY` — both\n * accepted by the statewire host.\n */\nexport function useAthenaStatewireRuntime(\n config: AthenaStatewireRuntimeConfig,\n): AssistantClient {\n const {\n syncUrl,\n threadId,\n isNewChat = false,\n apiKey,\n token,\n getToken,\n model,\n agent,\n channel,\n tools = EMPTY_TOOL_IDS,\n frontendToolIds = EMPTY_TOOL_IDS,\n frontendToolkit = EMPTY_TOOLKIT,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n snapshotCache,\n messageWindow = ATHENA_SDK_MESSAGE_WINDOW,\n toolOutputs,\n onError,\n onConnectionChange,\n onRawConnectionChange,\n onRunningChange,\n onServerState,\n } = config;\n\n // Fail loud at mount, not at first send: the statewire host always runs the\n // Athena deep agent, so an `agent` outside the collab_agent namespace can\n // never apply. Throwing here (render time) is what makes a misconfigured\n // integration visible instead of quietly answering as the wrong agent.\n resolveAgentProp({ agent });\n\n const clientTools = useStatewireClientTools(frontendToolkit);\n\n // The persisted command lane is keyed by WHO is signed in as well as by host\n // and thread (see `statewireSessionKey`).\n const authContext = useContext(AthenaAuthContext);\n const principal = authContext?.user?.userId ?? '';\n\n // Attach → first server snapshot span, keyed per thread attach.\n const attachSpanRef = useRef<ReturnType<AthenaDiagnosticsSpanStarter> | null>(null);\n const attachThreadRef = useRef<string | null>(null);\n if (attachThreadRef.current !== threadId) {\n attachThreadRef.current = threadId;\n attachSpanRef.current = athenaDiagnostics.span(\n `statewire.attach:${threadId}`,\n 'statewire.attach.start',\n { thread_id: threadId, is_new_chat: isNewChat },\n );\n }\n\n // Built every render so its JSON signature can key the model-context\n // registration below: consumers commonly pass fresh array literals per\n // render, which must not thrash registration, while a changed value (a new\n // `model`, channel, tool list, system prompt, …) must re-sync the context\n // before the next send. The core pulls this value only on model-context\n // notifications, which a key change triggers.\n const runConfigValue = buildStatewireRunConfig({\n model,\n agent,\n channel,\n tools,\n frontendToolIds,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n clientTools: statewireClientToolWireEntries(clientTools),\n });\n const runConfigKey = JSON.stringify(runConfigValue);\n\n // The host's state, told apart from what the thread renders before its\n // hello: statewire publishes the initial (placeholder or remembered) state\n // through `onStateChange` too, and reports `connected` in the same flush\n // right after publishing the state the hello carried. So the latest state\n // seen when the connection first turns `connected` is the hello's, and every\n // state after it is the host's. Refs are per attach: the runtime is mounted\n // per thread.\n const lastStateRef = useRef<DeepAgentStreamValues | null>(null);\n const helloLandedRef = useRef(false);\n\n const auiTools = useMemo(() => Tools({ toolkit: frontendToolkit }), [frontendToolkit]);\n // Web client for the shared runtime core (a `use*` name so the\n // rules-of-hooks lint sees the `useAui` call inside a custom hook; the core\n // invokes it unconditionally every render).\n const useSdkClient = (thread: DeepAgentThreadElement) => useAui({ thread, tools: auiTools });\n\n return useDeepAgentRuntime({\n surface: 'AthenaSDK',\n threadId,\n baseUrl: syncUrl,\n // Option closures are re-read per render by the core, so credential\n // rotation (new `token`/`getToken`/`apiKey` props) reaches the next\n // request without remounting the thread. The transport's `staleAuth`\n // (true right after a refused credential) is forwarded as `force`.\n headers: (ctx) => resolveStatewireAuthHeaders({ apiKey, token, getToken }, ctx),\n isNewChat,\n // Queued entries render in the SDK's queue panel, so only the steer lane\n // projects into the message tail.\n laneProjection: 'steer-only',\n // Durable session: a reload resumes the lane and resends whatever the\n // server has not marked durable. Scoped by host AND principal — a thread\n // id is only meaningful against the backend that minted it, and a stored\n // lane must never resend against another signed-in user. (Consumers\n // server-render this SDK; the core's availability probe keeps those\n // sessions process-local, as before the seam existed.)\n session: {\n kind: 'local-storage',\n key: (id) => statewireSessionKey({ syncUrl, principal, threadId: id }),\n },\n snapshotCache,\n // Head interest (see `ATHENA_SDK_MESSAGE_WINDOW`): the tail of the\n // transcript instead of every message; the chat UI's history edge pages\n // older ranges in and fetches cut tool outputs into `toolOutputs`.\n messageWindow,\n toolOutputs,\n capabilities: { edit: true, reload: true, continue: true },\n // The composer stages the draft each send came from right before it\n // sends; the message carries it as its composer markdown, so its bubble\n // shows the text exactly as typed (`UserMessageText`).\n getMessageMetadata: withStagedComposerMarkdown({ threadId }),\n useClient: useSdkClient,\n onStateChange: (state) => {\n // First snapshot for this attach ends the attach span (time-to-history).\n const endSpan = attachSpanRef.current;\n if (endSpan) {\n attachSpanRef.current = null;\n endSpan('statewire.snapshot', { data: { thread_id: threadId } });\n }\n // A replay boundary republishes the pre-stream default: not host state.\n if (!isDeepAgentStateHydrated(state)) return;\n lastStateRef.current = state;\n if (helloLandedRef.current) onServerState?.(state);\n },\n onConnectionChange: (connection) => {\n athenaDiagnostics.gauge('statewire.connection', connection?.status ?? null);\n if (connection?.status === 'stopped') {\n athenaDiagnostics.emit('statewire.connection', {\n level: 'warn',\n data: {\n status: connection.status,\n reason: connection.reason,\n message: connection.message,\n },\n });\n }\n onConnectionChange?.(connection);\n },\n onRawConnectionChange: (connection) => {\n if (connection.status === 'connected' && !helloLandedRef.current) {\n helloLandedRef.current = true;\n const helloState = lastStateRef.current;\n if (helloState) onServerState?.(helloState);\n }\n onRawConnectionChange?.(connection);\n },\n onRunningChange,\n // Each model-context notification pulls the latest getter through the\n // core's per-render ref; the value-stable key re-registers (and so\n // notifies) only when the built runConfig actually changed. On a thread\n // with a server config lane, agora keeps only the per-send keys of what\n // this carries; `StatewireModelLaneSync` writes a changed `model` to the\n // lane itself.\n runConfig: {\n get: () => runConfigValue,\n key: runConfigKey,\n },\n onError: (error) => {\n if (!isStatewireChannelTeardown(error)) {\n athenaDiagnostics.error(\n 'statewire.error',\n error,\n {\n code: 'statewire_rejected',\n message: 'The statewire host rejected a command',\n hint: 'Inspect error.detail — agora rejections carry a structured {code, message}.',\n },\n { thread_id: threadId },\n );\n }\n if (onError) {\n onError(error);\n return;\n }\n logUnhandledStatewireError('AthenaSDK', error);\n },\n });\n}\n"],"names":["DEEP_AGENT_DEFAULT_MESSAGE_WINDOW","useMemo","collectStatewireClientTools","resolveAgentProp","useContext","AthenaAuthContext","useRef","athenaDiagnostics","buildStatewireRunConfig","statewireClientToolWireEntries","Tools","useAui","useDeepAgentRuntime","resolveStatewireAuthHeaders","statewireSessionKey","withStagedComposerMarkdown","isDeepAgentStateHydrated","isStatewireChannelTeardown","logUnhandledStatewireError"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { AssistantClient, Toolkit } from '@assistant-ui/react';
2
- import { type DeepAgentMessageWindowDeclaration, type DeepAgentThreadSnapshotCache, type DeepAgentToolOutputStore, type RegisteredClientTool, type UseDeepAgentThreadOptions } from '@athenaintel/agent-runtime';
2
+ import { type DeepAgentMessageWindowDeclaration, type DeepAgentStreamValues, type DeepAgentThreadSnapshotCache, type DeepAgentToolOutputStore, type RegisteredClientTool, type UseDeepAgentThreadOptions } from '@athenaintel/agent-runtime';
3
3
  import { type AthenaStatewireTokenGetter } from './statewire-auth-headers';
4
4
  import { DEFAULT_STATEWIRE_MODEL } from './statewire-run-config';
5
5
  export { DEFAULT_STATEWIRE_MODEL };
@@ -78,6 +78,13 @@ export interface AthenaStatewireRuntimeConfig {
78
78
  onRawConnectionChange?: UseDeepAgentThreadOptions['onRawConnectionChange'];
79
79
  /** Notified when a run starts/stops. */
80
80
  onRunningChange?: UseDeepAgentThreadOptions['onRunningChange'];
81
+ /**
82
+ * Observes the host's own state: called once the attach's hello has landed
83
+ * (with the snapshot it carried) and then on every later frame — never with
84
+ * the placeholder or remembered snapshot a thread renders before its hello.
85
+ * Called per streamed token, so keep it cheap.
86
+ */
87
+ onServerState?: (state: DeepAgentStreamValues) => void;
81
88
  }
82
89
  /** The client tools derived from the runtime's frontend toolkit — exposed so
83
90
  * the provider can mount the client-tool bridge with the same set. */
@@ -1,7 +1,7 @@
1
1
  import { Tools, useAui } from "@assistant-ui/react";
2
2
  import { useContext, useRef, useMemo } from "react";
3
3
  import { AthenaAuthContext } from "../auth/AthenaAuthContext.js";
4
- import { collectStatewireClientTools, statewireClientToolWireEntries } from "../chat/statewire-client-tools.js";
4
+ import { statewireClientToolWireEntries, collectStatewireClientTools } from "../chat/statewire-client-tools.js";
5
5
  import { athenaDiagnostics } from "../diagnostics/athena-diagnostics.js";
6
6
  import { resolveStatewireAuthHeaders } from "./statewire-auth-headers.js";
7
7
  import { statewireSessionKey } from "./statewire-session-key.js";
@@ -10,6 +10,7 @@ import { DEFAULT_STATEWIRE_MODEL } from "./statewire-run-config.js";
10
10
  import { DEEP_AGENT_DEFAULT_MESSAGE_WINDOW } from "../agent-runtime/src/generated/runconfig-contract.js";
11
11
  import { useDeepAgentRuntime, logUnhandledStatewireError } from "../agent-runtime/src/use-deep-agent-runtime.js";
12
12
  import { isStatewireChannelTeardown } from "../agent-runtime/src/errors.js";
13
+ import { isDeepAgentStateHydrated } from "../agent-runtime/src/statewire-state.js";
13
14
  import { withStagedComposerMarkdown } from "../agent-runtime/src/composer-markdown.js";
14
15
  const ATHENA_SDK_MESSAGE_WINDOW = {
15
16
  size: DEEP_AGENT_DEFAULT_MESSAGE_WINDOW
@@ -48,7 +49,8 @@ function useAthenaStatewireRuntime(config) {
48
49
  onError,
49
50
  onConnectionChange,
50
51
  onRawConnectionChange,
51
- onRunningChange
52
+ onRunningChange,
53
+ onServerState
52
54
  } = config;
53
55
  resolveAgentProp({ agent });
54
56
  const clientTools = useStatewireClientTools(frontendToolkit);
@@ -64,6 +66,22 @@ function useAthenaStatewireRuntime(config) {
64
66
  { thread_id: threadId, is_new_chat: isNewChat }
65
67
  );
66
68
  }
69
+ const runConfigValue = buildStatewireRunConfig({
70
+ model,
71
+ agent,
72
+ channel,
73
+ tools,
74
+ frontendToolIds,
75
+ workbench,
76
+ knowledgeBase,
77
+ systemPrompt,
78
+ appId,
79
+ extraRunConfig,
80
+ clientTools: statewireClientToolWireEntries(clientTools)
81
+ });
82
+ const runConfigKey = JSON.stringify(runConfigValue);
83
+ const lastStateRef = useRef(null);
84
+ const helloLandedRef = useRef(false);
67
85
  const auiTools = useMemo(() => Tools({ toolkit: frontendToolkit }), [frontendToolkit]);
68
86
  const useSdkClient = (thread) => useAui({ thread, tools: auiTools });
69
87
  return useDeepAgentRuntime({
@@ -101,12 +119,15 @@ function useAthenaStatewireRuntime(config) {
101
119
  // shows the text exactly as typed (`UserMessageText`).
102
120
  getMessageMetadata: withStagedComposerMarkdown({ threadId }),
103
121
  useClient: useSdkClient,
104
- onStateChange: () => {
122
+ onStateChange: (state) => {
105
123
  const endSpan = attachSpanRef.current;
106
124
  if (endSpan) {
107
125
  attachSpanRef.current = null;
108
126
  endSpan("statewire.snapshot", { data: { thread_id: threadId } });
109
127
  }
128
+ if (!isDeepAgentStateHydrated(state)) return;
129
+ lastStateRef.current = state;
130
+ if (helloLandedRef.current) onServerState == null ? void 0 : onServerState(state);
110
131
  },
111
132
  onConnectionChange: (connection) => {
112
133
  athenaDiagnostics.gauge("statewire.connection", (connection == null ? void 0 : connection.status) ?? null);
@@ -122,25 +143,24 @@ function useAthenaStatewireRuntime(config) {
122
143
  }
123
144
  onConnectionChange == null ? void 0 : onConnectionChange(connection);
124
145
  },
125
- onRawConnectionChange,
146
+ onRawConnectionChange: (connection) => {
147
+ if (connection.status === "connected" && !helloLandedRef.current) {
148
+ helloLandedRef.current = true;
149
+ const helloState = lastStateRef.current;
150
+ if (helloState) onServerState == null ? void 0 : onServerState(helloState);
151
+ }
152
+ onRawConnectionChange == null ? void 0 : onRawConnectionChange(connection);
153
+ },
126
154
  onRunningChange,
127
155
  // Each model-context notification pulls the latest getter through the
128
- // core's per-render ref. Consumers commonly pass fresh array literals per
129
- // render, which must not thrash registration (no `key`: once per client).
156
+ // core's per-render ref; the value-stable key re-registers (and so
157
+ // notifies) only when the built runConfig actually changed. On a thread
158
+ // with a server config lane, agora keeps only the per-send keys of what
159
+ // this carries; `StatewireModelLaneSync` writes a changed `model` to the
160
+ // lane itself.
130
161
  runConfig: {
131
- get: () => buildStatewireRunConfig({
132
- model,
133
- agent,
134
- channel,
135
- tools,
136
- frontendToolIds,
137
- workbench,
138
- knowledgeBase,
139
- systemPrompt,
140
- appId,
141
- extraRunConfig,
142
- clientTools: statewireClientToolWireEntries(clientTools)
143
- })
162
+ get: () => runConfigValue,
163
+ key: runConfigKey
144
164
  },
145
165
  onError: (error) => {
146
166
  if (!isStatewireChannelTeardown(error)) {
@@ -1 +1 @@
1
- {"version":3,"file":"useAthenaStatewireRuntime.js","sources":["../../src/runtime/useAthenaStatewireRuntime.ts"],"sourcesContent":["import type { AssistantClient, Toolkit } from '@assistant-ui/react';\nimport { Tools, useAui } from '@assistant-ui/react';\nimport {\n DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n type DeepAgentMessageWindowDeclaration,\n type DeepAgentThreadElement,\n type DeepAgentThreadSnapshotCache,\n type DeepAgentToolOutputStore,\n isStatewireChannelTeardown,\n logUnhandledStatewireError,\n type RegisteredClientTool,\n useDeepAgentRuntime,\n type UseDeepAgentThreadOptions,\n withStagedComposerMarkdown,\n} from '@athenaintel/agent-runtime';\nimport { useContext, useMemo, useRef } from 'react';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport {\n collectStatewireClientTools,\n statewireClientToolWireEntries,\n} from '../chat/statewire-client-tools';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport {\n type AthenaStatewireTokenGetter,\n resolveStatewireAuthHeaders,\n} from './statewire-auth-headers';\nimport { statewireSessionKey } from './statewire-session-key';\n\ntype AthenaDiagnosticsSpanStarter = typeof athenaDiagnostics.span;\nimport {\n buildStatewireRunConfig,\n DEFAULT_STATEWIRE_MODEL,\n resolveAgentProp,\n} from './statewire-run-config';\n\nexport { DEFAULT_STATEWIRE_MODEL };\n\n/**\n * The head interest every SDK attach states (`athena/interest`): the host\n * mounts the transcript's tail as message documents instead of every message\n * — megabytes on long threads, over the 1 MiB frame limit of stock websocket\n * clients. Older pages load from the `StatewireHistoryEdge` row the chat UI\n * mounts above the messages, and cut tool outputs are fetched back for the\n * cards that show them.\n */\nexport const ATHENA_SDK_MESSAGE_WINDOW: DeepAgentMessageWindowDeclaration = {\n size: DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n};\n\nexport interface AthenaStatewireRuntimeConfig {\n /** Base URL of the statewire sync host (the `…/v2/threads` mount). */\n syncUrl: string;\n /** Thread ID the statewire session attaches to. */\n threadId: string;\n /** True only for a never-started local chat. Existing (or pre-assigned)\n * threads load until their server snapshot arrives. */\n isNewChat?: boolean;\n /** API key for authentication. Used when no auth token is provided. */\n apiKey?: string;\n /** Auth token. Takes priority over apiKey. */\n token?: string | null;\n /** Resolve the latest token immediately before a request (for expiring\n * clients). Called with `{ force: true }` right after the host refused the\n * previous credential (the transport's `staleAuth`), so a caching getter\n * mints a fresh token instead of returning the refused one. */\n getToken?: AthenaStatewireTokenGetter;\n /**\n * Per-provider LRU of each thread's last wire state. A switch back to a\n * remembered thread mounts with that snapshot and projects ready on the\n * first frame instead of a loading treatment; the attach snapshot then\n * replaces it. Owned above the per-thread mount so it survives switches.\n */\n snapshotCache?: DeepAgentThreadSnapshotCache;\n /** The head interest stated on the attach (see {@link ATHENA_SDK_MESSAGE_WINDOW}, the default). */\n messageWindow?: DeepAgentMessageWindowDeclaration;\n /**\n * Full tool outputs fetched back for a windowed wire's cut tool messages;\n * the thread re-converts when one lands. `AthenaProvider` owns one per\n * provider and hands the same store to `StatewireHistoryEdge`.\n */\n toolOutputs?: DeepAgentToolOutputStore;\n /** LLM model identifier. Defaults to the deep-agent default model. */\n model?: string;\n /** Agent selector: only `collab_agent:<asset_id>` refs are accepted (the run\n * executes AS that published collab agent). Any other non-empty value\n * throws — see `resolveAgentProp`. */\n agent?: string;\n /** Collab-agent channel id selecting that channel's overrides. */\n channel?: string;\n /** Backend toolkit IDs to enable. */\n tools?: string[];\n /** Frontend tool IDs to include in enabled_tools. */\n frontendToolIds?: string[];\n /** Frontend tools registered on the assistant client. Tools with a local\n * `execute` are also declared as `client_tools` and executed through the\n * statewire client-tool bridge. */\n frontendToolkit?: Toolkit;\n /** Asset IDs to include in the workbench. */\n workbench?: string[];\n /** Knowledge base IDs for RAG context. */\n knowledgeBase?: string[];\n /** System prompt override. */\n systemPrompt?: string;\n /** Client app identifier for session filtering. Sent as app_id in runConfig.custom. */\n appId?: string;\n /** Additional fields merged into runConfig.custom. */\n extraRunConfig?: Record<string, unknown>;\n /** Called on statewire transport errors (send rejections, stream failures). */\n onError?: (error: Error) => void;\n /** Projected connection status changes (deduped; null on unmount). */\n onConnectionChange?: UseDeepAgentThreadOptions['onConnectionChange'];\n /** Raw connection observer — carries the transport's reconnect handle. */\n onRawConnectionChange?: UseDeepAgentThreadOptions['onRawConnectionChange'];\n /** Notified when a run starts/stops. */\n onRunningChange?: UseDeepAgentThreadOptions['onRunningChange'];\n}\n\nconst EMPTY_TOOLKIT: Toolkit = {};\nconst EMPTY_TOOL_IDS: string[] = [];\n\n/** The client tools derived from the runtime's frontend toolkit — exposed so\n * the provider can mount the client-tool bridge with the same set. */\nexport function useStatewireClientTools(\n frontendToolkit: Toolkit | undefined,\n): RegisteredClientTool[] {\n return useMemo(\n () => collectStatewireClientTools(frontendToolkit ?? EMPTY_TOOLKIT),\n [frontendToolkit],\n );\n}\n\n/**\n * Statewire runtime for the Athena SDK — a thin shim over the shared\n * `@athenaintel/agent-runtime` `useDeepAgentRuntime`: it attaches to the\n * agora-hosted deep-agent thread at `${syncUrl}/${threadId}` and returns the\n * `AssistantClient` to mount via `AuiProvider` — the same integration shape as\n * the Olympus, Chrome extension, Office, and mobile statewire hosts.\n *\n * Auth: a token (resolved live through `getToken` when provided) rides\n * `Authorization: Bearer`, and an API key falls back to `X-API-KEY` — both\n * accepted by the statewire host.\n */\nexport function useAthenaStatewireRuntime(\n config: AthenaStatewireRuntimeConfig,\n): AssistantClient {\n const {\n syncUrl,\n threadId,\n isNewChat = false,\n apiKey,\n token,\n getToken,\n model,\n agent,\n channel,\n tools = EMPTY_TOOL_IDS,\n frontendToolIds = EMPTY_TOOL_IDS,\n frontendToolkit = EMPTY_TOOLKIT,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n snapshotCache,\n messageWindow = ATHENA_SDK_MESSAGE_WINDOW,\n toolOutputs,\n onError,\n onConnectionChange,\n onRawConnectionChange,\n onRunningChange,\n } = config;\n\n // Fail loud at mount, not at first send: the statewire host always runs the\n // Athena deep agent, so an `agent` outside the collab_agent namespace can\n // never apply. Throwing here (render time) is what makes a misconfigured\n // integration visible instead of quietly answering as the wrong agent.\n resolveAgentProp({ agent });\n\n const clientTools = useStatewireClientTools(frontendToolkit);\n\n // The persisted command lane is keyed by WHO is signed in as well as by host\n // and thread (see `statewireSessionKey`).\n const authContext = useContext(AthenaAuthContext);\n const principal = authContext?.user?.userId ?? '';\n\n // Attach → first server snapshot span, keyed per thread attach.\n const attachSpanRef = useRef<ReturnType<AthenaDiagnosticsSpanStarter> | null>(null);\n const attachThreadRef = useRef<string | null>(null);\n if (attachThreadRef.current !== threadId) {\n attachThreadRef.current = threadId;\n attachSpanRef.current = athenaDiagnostics.span(\n `statewire.attach:${threadId}`,\n 'statewire.attach.start',\n { thread_id: threadId, is_new_chat: isNewChat },\n );\n }\n\n const auiTools = useMemo(() => Tools({ toolkit: frontendToolkit }), [frontendToolkit]);\n // Web client for the shared runtime core (a `use*` name so the\n // rules-of-hooks lint sees the `useAui` call inside a custom hook; the core\n // invokes it unconditionally every render).\n const useSdkClient = (thread: DeepAgentThreadElement) => useAui({ thread, tools: auiTools });\n\n return useDeepAgentRuntime({\n surface: 'AthenaSDK',\n threadId,\n baseUrl: syncUrl,\n // Option closures are re-read per render by the core, so credential\n // rotation (new `token`/`getToken`/`apiKey` props) reaches the next\n // request without remounting the thread. The transport's `staleAuth`\n // (true right after a refused credential) is forwarded as `force`.\n headers: (ctx) => resolveStatewireAuthHeaders({ apiKey, token, getToken }, ctx),\n isNewChat,\n // Queued entries render in the SDK's queue panel, so only the steer lane\n // projects into the message tail.\n laneProjection: 'steer-only',\n // Durable session: a reload resumes the lane and resends whatever the\n // server has not marked durable. Scoped by host AND principal — a thread\n // id is only meaningful against the backend that minted it, and a stored\n // lane must never resend against another signed-in user. (Consumers\n // server-render this SDK; the core's availability probe keeps those\n // sessions process-local, as before the seam existed.)\n session: {\n kind: 'local-storage',\n key: (id) => statewireSessionKey({ syncUrl, principal, threadId: id }),\n },\n snapshotCache,\n // Head interest (see `ATHENA_SDK_MESSAGE_WINDOW`): the tail of the\n // transcript instead of every message; the chat UI's history edge pages\n // older ranges in and fetches cut tool outputs into `toolOutputs`.\n messageWindow,\n toolOutputs,\n capabilities: { edit: true, reload: true, continue: true },\n // The composer stages the draft each send came from right before it\n // sends; the message carries it as its composer markdown, so its bubble\n // shows the text exactly as typed (`UserMessageText`).\n getMessageMetadata: withStagedComposerMarkdown({ threadId }),\n useClient: useSdkClient,\n onStateChange: () => {\n // First snapshot for this attach ends the attach span (time-to-history).\n const endSpan = attachSpanRef.current;\n if (endSpan) {\n attachSpanRef.current = null;\n endSpan('statewire.snapshot', { data: { thread_id: threadId } });\n }\n },\n onConnectionChange: (connection) => {\n athenaDiagnostics.gauge('statewire.connection', connection?.status ?? null);\n if (connection?.status === 'stopped') {\n athenaDiagnostics.emit('statewire.connection', {\n level: 'warn',\n data: {\n status: connection.status,\n reason: connection.reason,\n message: connection.message,\n },\n });\n }\n onConnectionChange?.(connection);\n },\n onRawConnectionChange,\n onRunningChange,\n // Each model-context notification pulls the latest getter through the\n // core's per-render ref. Consumers commonly pass fresh array literals per\n // render, which must not thrash registration (no `key`: once per client).\n runConfig: {\n get: () =>\n buildStatewireRunConfig({\n model,\n agent,\n channel,\n tools,\n frontendToolIds,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n clientTools: statewireClientToolWireEntries(clientTools),\n }),\n },\n onError: (error) => {\n if (!isStatewireChannelTeardown(error)) {\n athenaDiagnostics.error(\n 'statewire.error',\n error,\n {\n code: 'statewire_rejected',\n message: 'The statewire host rejected a command',\n hint: 'Inspect error.detail — agora rejections carry a structured {code, message}.',\n },\n { thread_id: threadId },\n );\n }\n if (onError) {\n onError(error);\n return;\n }\n logUnhandledStatewireError('AthenaSDK', error);\n },\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useAthenaStatewireRuntime.js","sources":["../../src/runtime/useAthenaStatewireRuntime.ts"],"sourcesContent":["import type { AssistantClient, Toolkit } from '@assistant-ui/react';\nimport { Tools, useAui } from '@assistant-ui/react';\nimport {\n DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n type DeepAgentMessageWindowDeclaration,\n type DeepAgentStreamValues,\n type DeepAgentThreadElement,\n type DeepAgentThreadSnapshotCache,\n type DeepAgentToolOutputStore,\n isDeepAgentStateHydrated,\n isStatewireChannelTeardown,\n logUnhandledStatewireError,\n type RegisteredClientTool,\n useDeepAgentRuntime,\n type UseDeepAgentThreadOptions,\n withStagedComposerMarkdown,\n} from '@athenaintel/agent-runtime';\nimport { useContext, useMemo, useRef } from 'react';\nimport { AthenaAuthContext } from '../auth/AthenaAuthContext';\nimport {\n collectStatewireClientTools,\n statewireClientToolWireEntries,\n} from '../chat/statewire-client-tools';\nimport { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport {\n type AthenaStatewireTokenGetter,\n resolveStatewireAuthHeaders,\n} from './statewire-auth-headers';\nimport { statewireSessionKey } from './statewire-session-key';\n\ntype AthenaDiagnosticsSpanStarter = typeof athenaDiagnostics.span;\nimport {\n buildStatewireRunConfig,\n DEFAULT_STATEWIRE_MODEL,\n resolveAgentProp,\n} from './statewire-run-config';\n\nexport { DEFAULT_STATEWIRE_MODEL };\n\n/**\n * The head interest every SDK attach states (`athena/interest`): the host\n * mounts the transcript's tail as message documents instead of every message\n * — megabytes on long threads, over the 1 MiB frame limit of stock websocket\n * clients. Older pages load from the `StatewireHistoryEdge` row the chat UI\n * mounts above the messages, and cut tool outputs are fetched back for the\n * cards that show them.\n */\nexport const ATHENA_SDK_MESSAGE_WINDOW: DeepAgentMessageWindowDeclaration = {\n size: DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n};\n\nexport interface AthenaStatewireRuntimeConfig {\n /** Base URL of the statewire sync host (the `…/v2/threads` mount). */\n syncUrl: string;\n /** Thread ID the statewire session attaches to. */\n threadId: string;\n /** True only for a never-started local chat. Existing (or pre-assigned)\n * threads load until their server snapshot arrives. */\n isNewChat?: boolean;\n /** API key for authentication. Used when no auth token is provided. */\n apiKey?: string;\n /** Auth token. Takes priority over apiKey. */\n token?: string | null;\n /** Resolve the latest token immediately before a request (for expiring\n * clients). Called with `{ force: true }` right after the host refused the\n * previous credential (the transport's `staleAuth`), so a caching getter\n * mints a fresh token instead of returning the refused one. */\n getToken?: AthenaStatewireTokenGetter;\n /**\n * Per-provider LRU of each thread's last wire state. A switch back to a\n * remembered thread mounts with that snapshot and projects ready on the\n * first frame instead of a loading treatment; the attach snapshot then\n * replaces it. Owned above the per-thread mount so it survives switches.\n */\n snapshotCache?: DeepAgentThreadSnapshotCache;\n /** The head interest stated on the attach (see {@link ATHENA_SDK_MESSAGE_WINDOW}, the default). */\n messageWindow?: DeepAgentMessageWindowDeclaration;\n /**\n * Full tool outputs fetched back for a windowed wire's cut tool messages;\n * the thread re-converts when one lands. `AthenaProvider` owns one per\n * provider and hands the same store to `StatewireHistoryEdge`.\n */\n toolOutputs?: DeepAgentToolOutputStore;\n /** LLM model identifier. Defaults to the deep-agent default model. */\n model?: string;\n /** Agent selector: only `collab_agent:<asset_id>` refs are accepted (the run\n * executes AS that published collab agent). Any other non-empty value\n * throws — see `resolveAgentProp`. */\n agent?: string;\n /** Collab-agent channel id selecting that channel's overrides. */\n channel?: string;\n /** Backend toolkit IDs to enable. */\n tools?: string[];\n /** Frontend tool IDs to include in enabled_tools. */\n frontendToolIds?: string[];\n /** Frontend tools registered on the assistant client. Tools with a local\n * `execute` are also declared as `client_tools` and executed through the\n * statewire client-tool bridge. */\n frontendToolkit?: Toolkit;\n /** Asset IDs to include in the workbench. */\n workbench?: string[];\n /** Knowledge base IDs for RAG context. */\n knowledgeBase?: string[];\n /** System prompt override. */\n systemPrompt?: string;\n /** Client app identifier for session filtering. Sent as app_id in runConfig.custom. */\n appId?: string;\n /** Additional fields merged into runConfig.custom. */\n extraRunConfig?: Record<string, unknown>;\n /** Called on statewire transport errors (send rejections, stream failures). */\n onError?: (error: Error) => void;\n /** Projected connection status changes (deduped; null on unmount). */\n onConnectionChange?: UseDeepAgentThreadOptions['onConnectionChange'];\n /** Raw connection observer — carries the transport's reconnect handle. */\n onRawConnectionChange?: UseDeepAgentThreadOptions['onRawConnectionChange'];\n /** Notified when a run starts/stops. */\n onRunningChange?: UseDeepAgentThreadOptions['onRunningChange'];\n /**\n * Observes the host's own state: called once the attach's hello has landed\n * (with the snapshot it carried) and then on every later frame — never with\n * the placeholder or remembered snapshot a thread renders before its hello.\n * Called per streamed token, so keep it cheap.\n */\n onServerState?: (state: DeepAgentStreamValues) => void;\n}\n\nconst EMPTY_TOOLKIT: Toolkit = {};\nconst EMPTY_TOOL_IDS: string[] = [];\n\n/** The client tools derived from the runtime's frontend toolkit — exposed so\n * the provider can mount the client-tool bridge with the same set. */\nexport function useStatewireClientTools(\n frontendToolkit: Toolkit | undefined,\n): RegisteredClientTool[] {\n return useMemo(\n () => collectStatewireClientTools(frontendToolkit ?? EMPTY_TOOLKIT),\n [frontendToolkit],\n );\n}\n\n/**\n * Statewire runtime for the Athena SDK — a thin shim over the shared\n * `@athenaintel/agent-runtime` `useDeepAgentRuntime`: it attaches to the\n * agora-hosted deep-agent thread at `${syncUrl}/${threadId}` and returns the\n * `AssistantClient` to mount via `AuiProvider` — the same integration shape as\n * the Olympus, Chrome extension, Office, and mobile statewire hosts.\n *\n * Auth: a token (resolved live through `getToken` when provided) rides\n * `Authorization: Bearer`, and an API key falls back to `X-API-KEY` — both\n * accepted by the statewire host.\n */\nexport function useAthenaStatewireRuntime(\n config: AthenaStatewireRuntimeConfig,\n): AssistantClient {\n const {\n syncUrl,\n threadId,\n isNewChat = false,\n apiKey,\n token,\n getToken,\n model,\n agent,\n channel,\n tools = EMPTY_TOOL_IDS,\n frontendToolIds = EMPTY_TOOL_IDS,\n frontendToolkit = EMPTY_TOOLKIT,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n snapshotCache,\n messageWindow = ATHENA_SDK_MESSAGE_WINDOW,\n toolOutputs,\n onError,\n onConnectionChange,\n onRawConnectionChange,\n onRunningChange,\n onServerState,\n } = config;\n\n // Fail loud at mount, not at first send: the statewire host always runs the\n // Athena deep agent, so an `agent` outside the collab_agent namespace can\n // never apply. Throwing here (render time) is what makes a misconfigured\n // integration visible instead of quietly answering as the wrong agent.\n resolveAgentProp({ agent });\n\n const clientTools = useStatewireClientTools(frontendToolkit);\n\n // The persisted command lane is keyed by WHO is signed in as well as by host\n // and thread (see `statewireSessionKey`).\n const authContext = useContext(AthenaAuthContext);\n const principal = authContext?.user?.userId ?? '';\n\n // Attach → first server snapshot span, keyed per thread attach.\n const attachSpanRef = useRef<ReturnType<AthenaDiagnosticsSpanStarter> | null>(null);\n const attachThreadRef = useRef<string | null>(null);\n if (attachThreadRef.current !== threadId) {\n attachThreadRef.current = threadId;\n attachSpanRef.current = athenaDiagnostics.span(\n `statewire.attach:${threadId}`,\n 'statewire.attach.start',\n { thread_id: threadId, is_new_chat: isNewChat },\n );\n }\n\n // Built every render so its JSON signature can key the model-context\n // registration below: consumers commonly pass fresh array literals per\n // render, which must not thrash registration, while a changed value (a new\n // `model`, channel, tool list, system prompt, …) must re-sync the context\n // before the next send. The core pulls this value only on model-context\n // notifications, which a key change triggers.\n const runConfigValue = buildStatewireRunConfig({\n model,\n agent,\n channel,\n tools,\n frontendToolIds,\n workbench,\n knowledgeBase,\n systemPrompt,\n appId,\n extraRunConfig,\n clientTools: statewireClientToolWireEntries(clientTools),\n });\n const runConfigKey = JSON.stringify(runConfigValue);\n\n // The host's state, told apart from what the thread renders before its\n // hello: statewire publishes the initial (placeholder or remembered) state\n // through `onStateChange` too, and reports `connected` in the same flush\n // right after publishing the state the hello carried. So the latest state\n // seen when the connection first turns `connected` is the hello's, and every\n // state after it is the host's. Refs are per attach: the runtime is mounted\n // per thread.\n const lastStateRef = useRef<DeepAgentStreamValues | null>(null);\n const helloLandedRef = useRef(false);\n\n const auiTools = useMemo(() => Tools({ toolkit: frontendToolkit }), [frontendToolkit]);\n // Web client for the shared runtime core (a `use*` name so the\n // rules-of-hooks lint sees the `useAui` call inside a custom hook; the core\n // invokes it unconditionally every render).\n const useSdkClient = (thread: DeepAgentThreadElement) => useAui({ thread, tools: auiTools });\n\n return useDeepAgentRuntime({\n surface: 'AthenaSDK',\n threadId,\n baseUrl: syncUrl,\n // Option closures are re-read per render by the core, so credential\n // rotation (new `token`/`getToken`/`apiKey` props) reaches the next\n // request without remounting the thread. The transport's `staleAuth`\n // (true right after a refused credential) is forwarded as `force`.\n headers: (ctx) => resolveStatewireAuthHeaders({ apiKey, token, getToken }, ctx),\n isNewChat,\n // Queued entries render in the SDK's queue panel, so only the steer lane\n // projects into the message tail.\n laneProjection: 'steer-only',\n // Durable session: a reload resumes the lane and resends whatever the\n // server has not marked durable. Scoped by host AND principal — a thread\n // id is only meaningful against the backend that minted it, and a stored\n // lane must never resend against another signed-in user. (Consumers\n // server-render this SDK; the core's availability probe keeps those\n // sessions process-local, as before the seam existed.)\n session: {\n kind: 'local-storage',\n key: (id) => statewireSessionKey({ syncUrl, principal, threadId: id }),\n },\n snapshotCache,\n // Head interest (see `ATHENA_SDK_MESSAGE_WINDOW`): the tail of the\n // transcript instead of every message; the chat UI's history edge pages\n // older ranges in and fetches cut tool outputs into `toolOutputs`.\n messageWindow,\n toolOutputs,\n capabilities: { edit: true, reload: true, continue: true },\n // The composer stages the draft each send came from right before it\n // sends; the message carries it as its composer markdown, so its bubble\n // shows the text exactly as typed (`UserMessageText`).\n getMessageMetadata: withStagedComposerMarkdown({ threadId }),\n useClient: useSdkClient,\n onStateChange: (state) => {\n // First snapshot for this attach ends the attach span (time-to-history).\n const endSpan = attachSpanRef.current;\n if (endSpan) {\n attachSpanRef.current = null;\n endSpan('statewire.snapshot', { data: { thread_id: threadId } });\n }\n // A replay boundary republishes the pre-stream default: not host state.\n if (!isDeepAgentStateHydrated(state)) return;\n lastStateRef.current = state;\n if (helloLandedRef.current) onServerState?.(state);\n },\n onConnectionChange: (connection) => {\n athenaDiagnostics.gauge('statewire.connection', connection?.status ?? null);\n if (connection?.status === 'stopped') {\n athenaDiagnostics.emit('statewire.connection', {\n level: 'warn',\n data: {\n status: connection.status,\n reason: connection.reason,\n message: connection.message,\n },\n });\n }\n onConnectionChange?.(connection);\n },\n onRawConnectionChange: (connection) => {\n if (connection.status === 'connected' && !helloLandedRef.current) {\n helloLandedRef.current = true;\n const helloState = lastStateRef.current;\n if (helloState) onServerState?.(helloState);\n }\n onRawConnectionChange?.(connection);\n },\n onRunningChange,\n // Each model-context notification pulls the latest getter through the\n // core's per-render ref; the value-stable key re-registers (and so\n // notifies) only when the built runConfig actually changed. On a thread\n // with a server config lane, agora keeps only the per-send keys of what\n // this carries; `StatewireModelLaneSync` writes a changed `model` to the\n // lane itself.\n runConfig: {\n get: () => runConfigValue,\n key: runConfigKey,\n },\n onError: (error) => {\n if (!isStatewireChannelTeardown(error)) {\n athenaDiagnostics.error(\n 'statewire.error',\n error,\n {\n code: 'statewire_rejected',\n message: 'The statewire host rejected a command',\n hint: 'Inspect error.detail — agora rejections carry a structured {code, message}.',\n },\n { thread_id: threadId },\n );\n }\n if (onError) {\n onError(error);\n return;\n }\n logUnhandledStatewireError('AthenaSDK', error);\n },\n });\n}\n"],"names":[],"mappings":"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"}