@athenaintel/react 0.42.1 → 0.43.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 +46 -7
  2. package/dist/agent-runtime/src/conversation-list-groups.d.ts +74 -0
  3. package/dist/agent-runtime/src/index.d.ts +3 -2
  4. package/dist/agent-runtime/src/messages.cjs +38 -7
  5. package/dist/agent-runtime/src/messages.cjs.map +1 -1
  6. package/dist/agent-runtime/src/messages.d.ts +26 -8
  7. package/dist/agent-runtime/src/messages.js +38 -7
  8. package/dist/agent-runtime/src/messages.js.map +1 -1
  9. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +10 -0
  10. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
  11. package/dist/agent-runtime/src/quota-safe-local-storage-session.d.ts +7 -0
  12. package/dist/agent-runtime/src/quota-safe-local-storage-session.js +10 -0
  13. package/dist/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
  14. package/dist/agent-runtime/src/session-lane-scope.cjs +25 -0
  15. package/dist/agent-runtime/src/session-lane-scope.cjs.map +1 -0
  16. package/dist/agent-runtime/src/session-lane-scope.d.ts +59 -0
  17. package/dist/agent-runtime/src/session-lane-scope.js +25 -0
  18. package/dist/agent-runtime/src/session-lane-scope.js.map +1 -0
  19. package/dist/agent-runtime/src/subagent-transcripts.cjs +2 -2
  20. package/dist/agent-runtime/src/subagent-transcripts.cjs.map +1 -1
  21. package/dist/agent-runtime/src/subagent-transcripts.d.ts +2 -2
  22. package/dist/agent-runtime/src/subagent-transcripts.js +3 -3
  23. package/dist/agent-runtime/src/subagent-transcripts.js.map +1 -1
  24. package/dist/agent-runtime/src/tool-metadata.cjs +0 -8
  25. package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
  26. package/dist/agent-runtime/src/tool-metadata.js +0 -8
  27. package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
  28. package/dist/agent-runtime/src/tool-names.cjs +4 -0
  29. package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
  30. package/dist/agent-runtime/src/tool-names.d.ts +7 -0
  31. package/dist/agent-runtime/src/tool-names.js +4 -0
  32. package/dist/agent-runtime/src/tool-names.js.map +1 -1
  33. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +18 -1
  34. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
  35. package/dist/agent-runtime/src/use-deep-agent-runtime.d.ts +19 -10
  36. package/dist/agent-runtime/src/use-deep-agent-runtime.js +19 -2
  37. package/dist/agent-runtime/src/use-deep-agent-runtime.js.map +1 -1
  38. package/dist/agent-runtime/src/use-deep-agent-thread.cjs +28 -10
  39. package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  40. package/dist/agent-runtime/src/use-deep-agent-thread.d.ts +35 -3
  41. package/dist/agent-runtime/src/use-deep-agent-thread.js +28 -10
  42. package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
  43. package/dist/agent-runtime/src/use-deep-agent-voice.cjs +50 -15
  44. package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
  45. package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +8 -0
  46. package/dist/agent-runtime/src/use-deep-agent-voice.js +50 -15
  47. package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -1
  48. package/dist/agent-runtime/src/voice-presentation.cjs +2 -0
  49. package/dist/agent-runtime/src/voice-presentation.cjs.map +1 -1
  50. package/dist/agent-runtime/src/voice-presentation.js +2 -0
  51. package/dist/agent-runtime/src/voice-presentation.js.map +1 -1
  52. package/dist/catalog/runtime-catalog.js +1 -1
  53. package/dist/chat/AthenaChat.cjs +125 -103
  54. package/dist/chat/AthenaChat.cjs.map +1 -1
  55. package/dist/chat/AthenaChat.d.ts +9 -0
  56. package/dist/chat/AthenaChat.js +126 -104
  57. package/dist/chat/AthenaChat.js.map +1 -1
  58. package/dist/chat/chat-voice-controls.cjs +128 -0
  59. package/dist/chat/chat-voice-controls.cjs.map +1 -0
  60. package/dist/chat/chat-voice-controls.d.ts +19 -0
  61. package/dist/chat/chat-voice-controls.js +128 -0
  62. package/dist/chat/chat-voice-controls.js.map +1 -0
  63. package/dist/chat/super-grouping/SuperGroupingCard.cjs +8 -2
  64. package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
  65. package/dist/chat/super-grouping/SuperGroupingCard.d.ts +6 -1
  66. package/dist/chat/super-grouping/SuperGroupingCard.js +8 -2
  67. package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
  68. package/dist/chat/super-grouping/ToolTimeline.cjs +27 -0
  69. package/dist/chat/super-grouping/ToolTimeline.cjs.map +1 -1
  70. package/dist/chat/super-grouping/ToolTimeline.d.ts +5 -1
  71. package/dist/chat/super-grouping/ToolTimeline.js +27 -0
  72. package/dist/chat/super-grouping/ToolTimeline.js.map +1 -1
  73. package/dist/chat/super-grouping/index.d.ts +1 -0
  74. package/dist/chat/super-grouping/timeline-step.cjs +61 -2
  75. package/dist/chat/super-grouping/timeline-step.cjs.map +1 -1
  76. package/dist/chat/super-grouping/timeline-step.d.ts +13 -1
  77. package/dist/chat/super-grouping/timeline-step.js +61 -2
  78. package/dist/chat/super-grouping/timeline-step.js.map +1 -1
  79. package/dist/chat/use-statewire-approval-request.js +1 -1
  80. package/dist/chat-ui/composer/tiptap-composer.cjs +42 -22
  81. package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
  82. package/dist/chat-ui/composer/tiptap-composer.d.ts +1 -0
  83. package/dist/chat-ui/composer/tiptap-composer.js +43 -23
  84. package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
  85. package/dist/chat-ui/mentions/mention-chip.cjs +144 -35
  86. package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
  87. package/dist/chat-ui/mentions/mention-chip.d.ts +17 -1
  88. package/dist/chat-ui/mentions/mention-chip.js +146 -37
  89. package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
  90. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +2 -1
  91. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
  92. package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +3 -1
  93. package/dist/chat-ui/mentions/suggestions/data/api-client.js +2 -1
  94. package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
  95. package/dist/chat-ui/mentions/use-account-workspace-id.cjs +29 -51
  96. package/dist/chat-ui/mentions/use-account-workspace-id.cjs.map +1 -1
  97. package/dist/chat-ui/mentions/use-account-workspace-id.d.ts +2 -2
  98. package/dist/chat-ui/mentions/use-account-workspace-id.js +30 -52
  99. package/dist/chat-ui/mentions/use-account-workspace-id.js.map +1 -1
  100. package/dist/chat-ui/mentions/use-mention-asset.cjs +140 -0
  101. package/dist/chat-ui/mentions/use-mention-asset.cjs.map +1 -0
  102. package/dist/chat-ui/mentions/use-mention-asset.d.ts +16 -0
  103. package/dist/chat-ui/mentions/use-mention-asset.js +140 -0
  104. package/dist/chat-ui/mentions/use-mention-asset.js.map +1 -0
  105. package/dist/chat-ui/rich-text/chat-link.cjs +5 -4
  106. package/dist/chat-ui/rich-text/chat-link.cjs.map +1 -1
  107. package/dist/chat-ui/rich-text/chat-link.d.ts +2 -3
  108. package/dist/chat-ui/rich-text/chat-link.js +6 -5
  109. package/dist/chat-ui/rich-text/chat-link.js.map +1 -1
  110. package/dist/chat-ui/rich-text/chat-node-views.cjs +1 -0
  111. package/dist/chat-ui/rich-text/chat-node-views.cjs.map +1 -1
  112. package/dist/chat-ui/rich-text/chat-node-views.js +1 -0
  113. package/dist/chat-ui/rich-text/chat-node-views.js.map +1 -1
  114. package/dist/chat-ui/thread/composer-send-or-stop.cjs +2 -1
  115. package/dist/chat-ui/thread/composer-send-or-stop.cjs.map +1 -1
  116. package/dist/chat-ui/thread/composer-send-or-stop.d.ts +2 -0
  117. package/dist/chat-ui/thread/composer-send-or-stop.js +2 -1
  118. package/dist/chat-ui/thread/composer-send-or-stop.js.map +1 -1
  119. package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
  120. package/dist/diagnostics/athena-diagnostics.d.ts +1 -1
  121. package/dist/diagnostics/athena-diagnostics.js.map +1 -1
  122. package/dist/index.d.ts +1 -1
  123. package/dist/react/package.json.cjs +1 -1
  124. package/dist/react/package.json.js +1 -1
  125. package/dist/references/src/tool-option-schemas.d.ts +0 -34
  126. package/dist/runtime/statewire-session-key.cjs.map +1 -1
  127. package/dist/runtime/statewire-session-key.d.ts +8 -5
  128. package/dist/runtime/statewire-session-key.js.map +1 -1
  129. package/dist/runtime/useAthenaStatewireRuntime.cjs +5 -2
  130. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  131. package/dist/runtime/useAthenaStatewireRuntime.js +5 -2
  132. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  133. package/dist/styles.css +1 -1
  134. package/dist/threads/statewire-thread-list.cjs +6 -2
  135. package/dist/threads/statewire-thread-list.cjs.map +1 -1
  136. package/dist/threads/statewire-thread-list.js +6 -2
  137. package/dist/threads/statewire-thread-list.js.map +1 -1
  138. package/dist/tools/tool-summary.cjs +0 -2
  139. package/dist/tools/tool-summary.cjs.map +1 -1
  140. package/dist/tools/tool-summary.js +0 -2
  141. package/dist/tools/tool-summary.js.map +1 -1
  142. package/dist/voice/use-chat-voice-enabled.cjs +43 -0
  143. package/dist/voice/use-chat-voice-enabled.cjs.map +1 -0
  144. package/dist/voice/use-chat-voice-enabled.d.ts +9 -0
  145. package/dist/voice/use-chat-voice-enabled.js +43 -0
  146. package/dist/voice/use-chat-voice-enabled.js.map +1 -0
  147. package/package.json +4 -8
@@ -1 +1 @@
1
- {"version":3,"file":"athena-diagnostics.js","sources":["../../src/diagnostics/athena-diagnostics.ts"],"sourcesContent":["/**\n * SDK diagnostics: one structured event bus for everything the SDK does that\n * can be slow or can fail — auth acquisition, thread-list fetches, statewire\n * attach/snapshot/connection changes, sends, first tokens, and every error.\n *\n * Design:\n * - Module-level singleton (one SDK, one bus), configured by `AthenaProvider`\n * from its `debug` / `onDiagnostic` / `onError` props. Nothing here runs\n * until something calls `emit`, and with defaults it costs a ring-buffer push.\n * - Every event carries `t` (ms since page navigation start via\n * `performance.now()`) so the buffer reads as a waterfall. Timed spans use\n * `performance.mark` / `performance.measure` too, so the browser Performance\n * panel shows them as user timings without any extra tooling.\n * - Console output is opt-in (`debug` prop or `localStorage['athena:debug']`),\n * prefixed `[AthenaSDK]`, and level-gated. Errors always reach `onError`.\n * - PostHog forwarding (opt-in) sends the timing events as\n * `athena_sdk_<name>` with `duration_ms`, through the SDK's capture gate.\n *\n * Consumers read the buffer with `useAthenaDiagnostics()` or, in the browser\n * console, `window.__ATHENA_SDK__.diagnostics.snapshot()`.\n */\n\nimport { getPostHogInstance } from '../provider/PostHogProvider';\nimport { capturePosthogEvent, type PosthogCaptureClient } from '../lib/posthog/wrap-posthog-client';\nimport { ATHENA_REACT_SDK_VERSION } from '../version';\nimport { AthenaSdkError, isAthenaSdkError, toAthenaSdkError } from './errors';\n\nexport const ATHENA_DIAGNOSTIC_LEVELS = ['debug', 'info', 'warn', 'error'] as const;\nexport type AthenaDiagnosticLevel = (typeof ATHENA_DIAGNOSTIC_LEVELS)[number];\n\nconst LEVEL_RANK: Record<AthenaDiagnosticLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\n/**\n * Event names. Dotted `area.event` so a consumer can filter by prefix. Names\n * are part of the public contract: renaming one is a breaking change for\n * dashboards, so add new ones instead of repurposing.\n */\nexport type AthenaDiagnosticEventName =\n // Provider / configuration\n | 'sdk.init'\n | 'sdk.transport'\n | 'sdk.config.warning'\n // Auth acquisition + lifecycle\n | 'auth.bridge.start'\n | 'auth.bridge.ready'\n | 'auth.bridge.timeout'\n | 'auth.bridge.absent'\n | 'auth.bridge.error'\n | 'auth.bridge.retry'\n | 'auth.bridge.config_rejected'\n | 'auth.token.acquired'\n | 'auth.token.refreshed'\n | 'auth.token.refresh_failed'\n | 'auth.token.stale'\n | 'auth.sso.userinfo.start'\n | 'auth.sso.userinfo.done'\n | 'auth.sso.userinfo.error'\n | 'auth.sso.userinfo.retry'\n // Thread list + history\n | 'threads.list.start'\n | 'threads.list.done'\n | 'threads.list.error'\n | 'threads.list.aborted'\n | 'threads.history.start'\n | 'threads.history.done'\n | 'threads.history.error'\n | 'threads.history.aborted'\n // Statewire transport\n | 'statewire.attach.start'\n | 'statewire.snapshot'\n | 'statewire.connection'\n | 'statewire.parked'\n | 'statewire.error'\n | 'statewire.read_only'\n /** A write to the thread's server config lane (`config/patch`) was refused or dropped. */\n | 'statewire.config'\n // Runs\n | 'run.send'\n | 'run.first_token'\n | 'run.done'\n | 'run.error'\n // Composer\n | 'composer.attachment.error'\n /** Files offered while Athena can't be reached were not attached (they could not upload). */\n | 'composer.attachment.refused_offline'\n | 'composer.cancel.error'\n | 'composer.dictation'\n | 'composer.handoff'\n // Tool UIs + frontend tools\n | 'tools.schema.warning'\n | 'tools.debug'\n // Mention suggestions\n | 'mentions.fetch.error'\n // Catch-all\n | 'sdk.error';\n\nexport interface AthenaDiagnosticEvent {\n /** Monotonic sequence number within this page. */\n seq: number;\n /** `performance.now()` at emit time (ms since navigation start). */\n t: number;\n /** Wall-clock ISO timestamp, for exports. */\n at: string;\n name: AthenaDiagnosticEventName;\n level: AthenaDiagnosticLevel;\n /** Milliseconds for a completed span (set on `*.done` / `*.ready` / `run.first_token`). */\n durationMs?: number;\n /** Structured context. Never contains credentials — see `redact`. */\n data?: Record<string, unknown>;\n /** Present on error-level events. */\n error?: AthenaSdkError;\n}\n\nexport interface AthenaDiagnosticsConfig {\n /** Minimum level echoed to the console. `false` disables console output. */\n console: AthenaDiagnosticLevel | false;\n /** Forward timing + error events to PostHog as `athena_sdk_*` events. */\n posthog: boolean;\n /** Receives every event (already redacted). */\n onEvent?: (event: AthenaDiagnosticEvent) => void;\n /** Receives every error-level event's `AthenaSdkError`. */\n onError?: (error: AthenaSdkError, event: AthenaDiagnosticEvent) => void;\n /** Ring-buffer capacity. */\n bufferSize: number;\n}\n\nexport interface AthenaDiagnosticsSnapshot {\n sdkVersion: string;\n config: Omit<AthenaDiagnosticsConfig, 'onEvent' | 'onError'>;\n events: AthenaDiagnosticEvent[];\n /** Latest value per gauge (connection status, transport, auth mode, …). */\n gauges: Record<string, unknown>;\n /** Named span durations, most recent per name (`auth.bridge`, `threads.list`, …). */\n timings: Record<string, number>;\n}\n\nconst DEFAULT_CONFIG: AthenaDiagnosticsConfig = {\n console: false,\n posthog: false,\n bufferSize: 300,\n};\n\nconst CONSOLE_PREFIX = '[AthenaSDK]';\nconst LOCAL_STORAGE_DEBUG_KEY = 'athena:debug';\nconst GLOBAL_KEY = '__ATHENA_SDK__';\n\n// Keys whose values must never enter the buffer, the console, or PostHog.\nconst REDACT_KEYS = /token|secret|api[-_]?key|authorization|cookie|password/i;\n\nfunction redact(data: Record<string, unknown> | undefined): Record<string, unknown> | undefined {\n if (!data) return undefined;\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (REDACT_KEYS.test(key)) {\n out[key] = typeof value === 'string' && value.length > 0 ? `<redacted:${value.length}>` : '<redacted>';\n } else {\n out[key] = value;\n }\n }\n return out;\n}\n\nfunction nowMs(): number {\n return typeof performance !== 'undefined' && typeof performance.now === 'function'\n ? performance.now()\n : Date.now();\n}\n\nfunction readLocalDebugLevel(): AthenaDiagnosticLevel | null {\n try {\n if (typeof localStorage === 'undefined') return null;\n const raw = localStorage.getItem(LOCAL_STORAGE_DEBUG_KEY);\n if (!raw) return null;\n if ((ATHENA_DIAGNOSTIC_LEVELS as readonly string[]).includes(raw)) {\n return raw as AthenaDiagnosticLevel;\n }\n return raw === '1' || raw === 'true' ? 'debug' : null;\n } catch {\n return null;\n }\n}\n\ntype Listener = (event: AthenaDiagnosticEvent) => void;\n\nclass AthenaDiagnosticsBus {\n private config: AthenaDiagnosticsConfig = { ...DEFAULT_CONFIG };\n private events: AthenaDiagnosticEvent[] = [];\n private listeners = new Set<Listener>();\n private snapshotListeners = new Set<() => void>();\n private seq = 0;\n private gauges: Record<string, unknown> = {};\n private timings: Record<string, number> = {};\n private spans = new Map<string, number>();\n private cachedSnapshot: AthenaDiagnosticsSnapshot | null = null;\n\n configure(partial: Partial<AthenaDiagnosticsConfig>): void {\n this.config = { ...this.config, ...partial };\n if (this.events.length > this.config.bufferSize) {\n this.events = this.events.slice(-this.config.bufferSize);\n }\n this.invalidate();\n }\n\n getConfig(): AthenaDiagnosticsConfig {\n return this.config;\n }\n\n /** Effective console level: the configured one, or `localStorage['athena:debug']`. */\n private consoleLevel(): AthenaDiagnosticLevel | false {\n if (this.config.console !== false) return this.config.console;\n return readLocalDebugLevel() ?? false;\n }\n\n emit(\n name: AthenaDiagnosticEventName,\n options: {\n level?: AthenaDiagnosticLevel;\n data?: Record<string, unknown>;\n durationMs?: number;\n error?: unknown;\n } = {},\n ): AthenaDiagnosticEvent {\n const level = options.level ?? (options.error !== undefined ? 'error' : 'info');\n const error =\n options.error === undefined\n ? undefined\n : toAthenaSdkError(options.error, {\n code: 'unknown',\n message: `Unexpected error during ${name}`,\n });\n const event: AthenaDiagnosticEvent = {\n seq: ++this.seq,\n t: Math.round(nowMs() * 10) / 10,\n at: new Date().toISOString(),\n name,\n level,\n ...(options.durationMs !== undefined && { durationMs: Math.round(options.durationMs) }),\n ...(options.data && { data: redact(options.data) }),\n ...(error && { error }),\n };\n\n this.events.push(event);\n if (this.events.length > this.config.bufferSize) {\n this.events.splice(0, this.events.length - this.config.bufferSize);\n }\n if (event.durationMs !== undefined) {\n this.timings[name] = event.durationMs;\n }\n this.invalidate();\n\n this.echoToConsole(event);\n this.forwardToPostHog(event);\n for (const listener of this.listeners) {\n try {\n listener(event);\n } catch (listenerError) {\n console.error(`${CONSOLE_PREFIX} diagnostics listener threw`, listenerError);\n }\n }\n if (this.config.onEvent) {\n try {\n this.config.onEvent(event);\n } catch (callbackError) {\n console.error(`${CONSOLE_PREFIX} onDiagnostic callback threw`, callbackError);\n }\n }\n if (error && this.config.onError) {\n try {\n this.config.onError(error, event);\n } catch (callbackError) {\n console.error(`${CONSOLE_PREFIX} onError callback threw`, callbackError);\n }\n }\n for (const notify of this.snapshotListeners) notify();\n return event;\n }\n\n /** Record an error-level event. Returns the normalized `AthenaSdkError`. */\n error(\n name: AthenaDiagnosticEventName,\n error: unknown,\n fallback: { code: AthenaSdkError['code']; message: string; hint?: string },\n data?: Record<string, unknown>,\n ): AthenaSdkError {\n const normalized = toAthenaSdkError(error, fallback);\n this.emit(name, { level: 'error', error: normalized, data });\n return normalized;\n }\n\n /**\n * Start a named span. Returns a function that ends it and emits `doneName`\n * with `durationMs` (or `errorName` when passed an error). Also records a\n * `performance.measure` so the span shows in the browser's Performance panel.\n */\n span(\n spanName: string,\n startName: AthenaDiagnosticEventName,\n data?: Record<string, unknown>,\n ): (\n doneName: AthenaDiagnosticEventName,\n doneOptions?: { data?: Record<string, unknown>; error?: unknown },\n ) => number {\n const startedAt = nowMs();\n this.spans.set(spanName, startedAt);\n this.mark(`${spanName}:start`);\n this.emit(startName, { level: 'debug', data });\n return (doneName, doneOptions = {}) => {\n const durationMs = nowMs() - startedAt;\n this.spans.delete(spanName);\n this.mark(`${spanName}:end`);\n this.measure(spanName);\n this.emit(doneName, {\n level: doneOptions.error !== undefined ? 'error' : 'info',\n durationMs,\n data: doneOptions.data,\n error: doneOptions.error,\n });\n return durationMs;\n };\n }\n\n /** Set a gauge (latest-value metric): connection status, transport, auth mode. */\n gauge(name: string, value: unknown): void {\n if (this.gauges[name] === value) return;\n this.gauges[name] = value;\n this.invalidate();\n for (const notify of this.snapshotListeners) notify();\n }\n\n subscribe(listener: Listener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Additive consumer registration: every registered consumer receives every\n * event (and every error), unlike the single `onEvent`/`onError` config\n * slots which are last-writer-wins. `AthenaProvider` registers through this\n * so two mounted providers never clobber each other's callbacks.\n */\n addConsumer(consumer: {\n onEvent?: (event: AthenaDiagnosticEvent) => void;\n onError?: (error: AthenaSdkError, event: AthenaDiagnosticEvent) => void;\n }): () => void {\n return this.subscribe((event) => {\n try {\n consumer.onEvent?.(event);\n } catch (callbackError) {\n console.error(`${CONSOLE_PREFIX} onDiagnostic consumer threw`, callbackError);\n }\n if (event.error) {\n try {\n consumer.onError?.(event.error, event);\n } catch (callbackError) {\n console.error(`${CONSOLE_PREFIX} onError consumer threw`, callbackError);\n }\n }\n });\n }\n\n /** Subscribe to snapshot changes (for `useSyncExternalStore`). */\n subscribeSnapshot(listener: () => void): () => void {\n this.snapshotListeners.add(listener);\n return () => {\n this.snapshotListeners.delete(listener);\n };\n }\n\n snapshot(): AthenaDiagnosticsSnapshot {\n if (!this.cachedSnapshot) {\n const { onEvent: _onEvent, onError: _onError, ...config } = this.config;\n this.cachedSnapshot = {\n sdkVersion: ATHENA_REACT_SDK_VERSION,\n config,\n events: [...this.events],\n gauges: { ...this.gauges },\n timings: { ...this.timings },\n };\n }\n return this.cachedSnapshot;\n }\n\n /** Copy-paste-able JSON of the current snapshot (errors serialized). */\n export(): string {\n return JSON.stringify(\n this.snapshot(),\n (_key, value) => (isAthenaSdkError(value) ? value.toJSON() : value),\n 2,\n );\n }\n\n clear(): void {\n this.events = [];\n this.timings = {};\n this.invalidate();\n for (const notify of this.snapshotListeners) notify();\n }\n\n private invalidate(): void {\n this.cachedSnapshot = null;\n }\n\n private mark(name: string): void {\n try {\n if (typeof performance !== 'undefined' && typeof performance.mark === 'function') {\n performance.mark(`athena-sdk:${name}`);\n }\n } catch {\n // User Timing is best-effort.\n }\n }\n\n private measure(spanName: string): void {\n try {\n if (typeof performance !== 'undefined' && typeof performance.measure === 'function') {\n performance.measure(\n `athena-sdk:${spanName}`,\n `athena-sdk:${spanName}:start`,\n `athena-sdk:${spanName}:end`,\n );\n }\n } catch {\n // A missing start mark (e.g. after `performance.clearMarks`) is not an error.\n }\n }\n\n private echoToConsole(event: AthenaDiagnosticEvent): void {\n const level = this.consoleLevel();\n if (level === false) {\n // Errors are never silent: with console output off they still log once,\n // compactly, so a broken integration is visible without enabling debug.\n if (event.level === 'error' && event.error) {\n console.error(`${CONSOLE_PREFIX} ${event.name}: ${event.error.describe()}`, event.data ?? '');\n }\n return;\n }\n if (LEVEL_RANK[event.level] < LEVEL_RANK[level]) return;\n const suffix = event.durationMs !== undefined ? ` (${event.durationMs}ms)` : '';\n const line = `${CONSOLE_PREFIX} ${event.name}${suffix}`;\n const payload = event.error ? { ...event.data, error: event.error.describe() } : event.data;\n const method =\n event.level === 'error'\n ? console.error\n : event.level === 'warn'\n ? console.warn\n : event.level === 'debug'\n ? console.debug\n : console.info;\n method(line, payload ?? '');\n }\n\n private forwardToPostHog(event: AthenaDiagnosticEvent): void {\n if (!this.config.posthog) return;\n if (event.durationMs === undefined && event.level !== 'error') return;\n try {\n const client = getPostHogInstance<PosthogCaptureClient>();\n capturePosthogEvent(client, `athena_sdk_${event.name.replace(/\\./g, '_')}`, {\n sdk_version: ATHENA_REACT_SDK_VERSION,\n level: event.level,\n ...(event.durationMs !== undefined && { duration_ms: event.durationMs }),\n ...(event.error && {\n error_code: event.error.code,\n error_message: event.error.message,\n error_status: event.error.status,\n }),\n ...event.data,\n });\n } catch {\n // Analytics must never break the chat.\n }\n }\n}\n\nexport const athenaDiagnostics = new AthenaDiagnosticsBus();\n\n/**\n * Expose the bus on `window.__ATHENA_SDK__` so an integrator can inspect the\n * waterfall from the console (`__ATHENA_SDK__.diagnostics.snapshot()`) or turn\n * console echo on without a rebuild (`localStorage.setItem('athena:debug','debug')`).\n */\nexport function installAthenaDiagnosticsGlobal(): void {\n if (typeof window === 'undefined') return;\n const globalWindow = window as unknown as Record<string, unknown>;\n const existing = (globalWindow[GLOBAL_KEY] ?? {}) as Record<string, unknown>;\n globalWindow[GLOBAL_KEY] = {\n ...existing,\n version: ATHENA_REACT_SDK_VERSION,\n diagnostics: {\n snapshot: () => athenaDiagnostics.snapshot(),\n export: () => athenaDiagnostics.export(),\n clear: () => athenaDiagnostics.clear(),\n enableConsole: (level: AthenaDiagnosticLevel = 'debug') => {\n try {\n localStorage.setItem(LOCAL_STORAGE_DEBUG_KEY, level);\n } catch {\n // localStorage may be unavailable.\n }\n athenaDiagnostics.configure({ console: level });\n },\n disableConsole: () => {\n try {\n localStorage.removeItem(LOCAL_STORAGE_DEBUG_KEY);\n } catch {\n // localStorage may be unavailable.\n }\n athenaDiagnostics.configure({ console: false });\n },\n },\n };\n}\n\n/** Normalize the provider's `debug` prop into a diagnostics config patch. */\nexport function debugPropToDiagnosticsConfig(\n debug: boolean | AthenaDiagnosticLevel | Partial<AthenaDiagnosticsConfig> | undefined,\n): Partial<AthenaDiagnosticsConfig> {\n if (debug === undefined) return {};\n if (debug === true) return { console: 'debug' };\n if (debug === false) return { console: false };\n if (typeof debug === 'string') return { console: debug };\n return debug;\n}\n"],"names":[],"mappings":";;;;;;;AA2BO,MAAM,2BAA2B,CAAC,SAAS,QAAQ,QAAQ,OAAO;AAGzE,MAAM,aAAoD;AAAA,EACxD,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AA0GA,MAAM,iBAA0C;AAAA,EAC9C,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;AACd;AAEA,MAAM,iBAAiB;AACvB,MAAM,0BAA0B;AAChC,MAAM,aAAa;AAGnB,MAAM,cAAc;AAEpB,SAAS,OAAO,MAAgF;AAC9F,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,MAA+B,CAAA;AACrC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,QAAI,YAAY,KAAK,GAAG,GAAG;AACzB,UAAI,GAAG,IAAI,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,aAAa,MAAM,MAAM,MAAM;AAAA,IAC5F,OAAO;AACL,UAAI,GAAG,IAAI;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,QAAgB;AACvB,SAAO,OAAO,gBAAgB,eAAe,OAAO,YAAY,QAAQ,aACpE,YAAY,QACZ,KAAK,IAAA;AACX;AAEA,SAAS,sBAAoD;AAC3D,MAAI;AACF,QAAI,OAAO,iBAAiB,YAAa,QAAO;AAChD,UAAM,MAAM,aAAa,QAAQ,uBAAuB;AACxD,QAAI,CAAC,IAAK,QAAO;AACjB,QAAK,yBAA+C,SAAS,GAAG,GAAG;AACjE,aAAO;AAAA,IACT;AACA,WAAO,QAAQ,OAAO,QAAQ,SAAS,UAAU;AAAA,EACnD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,MAAM,qBAAqB;AAAA,EAA3B;AACU,kCAAkC,EAAE,GAAG,eAAA;AACvC,kCAAkC,CAAA;AAClC,yDAAgB,IAAA;AAChB,iEAAwB,IAAA;AACxB,+BAAM;AACN,kCAAkC,CAAA;AAClC,mCAAkC,CAAA;AAClC,qDAAY,IAAA;AACZ,0CAAmD;AAAA;AAAA,EAE3D,UAAU,SAAiD;AACzD,SAAK,SAAS,EAAE,GAAG,KAAK,QAAQ,GAAG,QAAA;AACnC,QAAI,KAAK,OAAO,SAAS,KAAK,OAAO,YAAY;AAC/C,WAAK,SAAS,KAAK,OAAO,MAAM,CAAC,KAAK,OAAO,UAAU;AAAA,IACzD;AACA,SAAK,WAAA;AAAA,EACP;AAAA,EAEA,YAAqC;AACnC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGQ,eAA8C;AACpD,QAAI,KAAK,OAAO,YAAY,MAAO,QAAO,KAAK,OAAO;AACtD,WAAO,yBAAyB;AAAA,EAClC;AAAA,EAEA,KACE,MACA,UAKI,IACmB;AACvB,UAAM,QAAQ,QAAQ,UAAU,QAAQ,UAAU,SAAY,UAAU;AACxE,UAAM,QACJ,QAAQ,UAAU,SACd,SACA,iBAAiB,QAAQ,OAAO;AAAA,MAC9B,MAAM;AAAA,MACN,SAAS,2BAA2B,IAAI;AAAA,IAAA,CACzC;AACP,UAAM,QAA+B;AAAA,MACnC,KAAK,EAAE,KAAK;AAAA,MACZ,GAAG,KAAK,MAAM,MAAA,IAAU,EAAE,IAAI;AAAA,MAC9B,KAAI,oBAAI,KAAA,GAAO,YAAA;AAAA,MACf;AAAA,MACA;AAAA,MACA,GAAI,QAAQ,eAAe,UAAa,EAAE,YAAY,KAAK,MAAM,QAAQ,UAAU,EAAA;AAAA,MACnF,GAAI,QAAQ,QAAQ,EAAE,MAAM,OAAO,QAAQ,IAAI,EAAA;AAAA,MAC/C,GAAI,SAAS,EAAE,MAAA;AAAA,IAAM;AAGvB,SAAK,OAAO,KAAK,KAAK;AACtB,QAAI,KAAK,OAAO,SAAS,KAAK,OAAO,YAAY;AAC/C,WAAK,OAAO,OAAO,GAAG,KAAK,OAAO,SAAS,KAAK,OAAO,UAAU;AAAA,IACnE;AACA,QAAI,MAAM,eAAe,QAAW;AAClC,WAAK,QAAQ,IAAI,IAAI,MAAM;AAAA,IAC7B;AACA,SAAK,WAAA;AAEL,SAAK,cAAc,KAAK;AACxB,SAAK,iBAAiB,KAAK;AAC3B,eAAW,YAAY,KAAK,WAAW;AACrC,UAAI;AACF,iBAAS,KAAK;AAAA,MAChB,SAAS,eAAe;AACtB,gBAAQ,MAAM,GAAG,cAAc,+BAA+B,aAAa;AAAA,MAC7E;AAAA,IACF;AACA,QAAI,KAAK,OAAO,SAAS;AACvB,UAAI;AACF,aAAK,OAAO,QAAQ,KAAK;AAAA,MAC3B,SAAS,eAAe;AACtB,gBAAQ,MAAM,GAAG,cAAc,gCAAgC,aAAa;AAAA,MAC9E;AAAA,IACF;AACA,QAAI,SAAS,KAAK,OAAO,SAAS;AAChC,UAAI;AACF,aAAK,OAAO,QAAQ,OAAO,KAAK;AAAA,MAClC,SAAS,eAAe;AACtB,gBAAQ,MAAM,GAAG,cAAc,2BAA2B,aAAa;AAAA,MACzE;AAAA,IACF;AACA,eAAW,UAAU,KAAK,kBAAmB,QAAA;AAC7C,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MACE,MACA,OACA,UACA,MACgB;AAChB,UAAM,aAAa,iBAAiB,OAAO,QAAQ;AACnD,SAAK,KAAK,MAAM,EAAE,OAAO,SAAS,OAAO,YAAY,MAAM;AAC3D,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,KACE,UACA,WACA,MAIU;AACV,UAAM,YAAY,MAAA;AAClB,SAAK,MAAM,IAAI,UAAU,SAAS;AAClC,SAAK,KAAK,GAAG,QAAQ,QAAQ;AAC7B,SAAK,KAAK,WAAW,EAAE,OAAO,SAAS,MAAM;AAC7C,WAAO,CAAC,UAAU,cAAc,OAAO;AACrC,YAAM,aAAa,UAAU;AAC7B,WAAK,MAAM,OAAO,QAAQ;AAC1B,WAAK,KAAK,GAAG,QAAQ,MAAM;AAC3B,WAAK,QAAQ,QAAQ;AACrB,WAAK,KAAK,UAAU;AAAA,QAClB,OAAO,YAAY,UAAU,SAAY,UAAU;AAAA,QACnD;AAAA,QACA,MAAM,YAAY;AAAA,QAClB,OAAO,YAAY;AAAA,MAAA,CACpB;AACD,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,MAAc,OAAsB;AACxC,QAAI,KAAK,OAAO,IAAI,MAAM,MAAO;AACjC,SAAK,OAAO,IAAI,IAAI;AACpB,SAAK,WAAA;AACL,eAAW,UAAU,KAAK,kBAAmB,QAAA;AAAA,EAC/C;AAAA,EAEA,UAAU,UAAgC;AACxC,SAAK,UAAU,IAAI,QAAQ;AAC3B,WAAO,MAAM;AACX,WAAK,UAAU,OAAO,QAAQ;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,UAGG;AACb,WAAO,KAAK,UAAU,CAAC,UAAU;;AAC/B,UAAI;AACF,uBAAS,YAAT,kCAAmB;AAAA,MACrB,SAAS,eAAe;AACtB,gBAAQ,MAAM,GAAG,cAAc,gCAAgC,aAAa;AAAA,MAC9E;AACA,UAAI,MAAM,OAAO;AACf,YAAI;AACF,yBAAS,YAAT,kCAAmB,MAAM,OAAO;AAAA,QAClC,SAAS,eAAe;AACtB,kBAAQ,MAAM,GAAG,cAAc,2BAA2B,aAAa;AAAA,QACzE;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,kBAAkB,UAAkC;AAClD,SAAK,kBAAkB,IAAI,QAAQ;AACnC,WAAO,MAAM;AACX,WAAK,kBAAkB,OAAO,QAAQ;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,WAAsC;AACpC,QAAI,CAAC,KAAK,gBAAgB;AACxB,YAAM,EAAE,SAAS,UAAU,SAAS,UAAU,GAAG,OAAA,IAAW,KAAK;AACjE,WAAK,iBAAiB;AAAA,QACpB,YAAY;AAAA,QACZ;AAAA,QACA,QAAQ,CAAC,GAAG,KAAK,MAAM;AAAA,QACvB,QAAQ,EAAE,GAAG,KAAK,OAAA;AAAA,QAClB,SAAS,EAAE,GAAG,KAAK,QAAA;AAAA,MAAQ;AAAA,IAE/B;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,SAAiB;AACf,WAAO,KAAK;AAAA,MACV,KAAK,SAAA;AAAA,MACL,CAAC,MAAM,UAAW,iBAAiB,KAAK,IAAI,MAAM,WAAW;AAAA,MAC7D;AAAA,IAAA;AAAA,EAEJ;AAAA,EAEA,QAAc;AACZ,SAAK,SAAS,CAAA;AACd,SAAK,UAAU,CAAA;AACf,SAAK,WAAA;AACL,eAAW,UAAU,KAAK,kBAAmB,QAAA;AAAA,EAC/C;AAAA,EAEQ,aAAmB;AACzB,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEQ,KAAK,MAAoB;AAC/B,QAAI;AACF,UAAI,OAAO,gBAAgB,eAAe,OAAO,YAAY,SAAS,YAAY;AAChF,oBAAY,KAAK,cAAc,IAAI,EAAE;AAAA,MACvC;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,QAAQ,UAAwB;AACtC,QAAI;AACF,UAAI,OAAO,gBAAgB,eAAe,OAAO,YAAY,YAAY,YAAY;AACnF,oBAAY;AAAA,UACV,cAAc,QAAQ;AAAA,UACtB,cAAc,QAAQ;AAAA,UACtB,cAAc,QAAQ;AAAA,QAAA;AAAA,MAE1B;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,cAAc,OAAoC;AACxD,UAAM,QAAQ,KAAK,aAAA;AACnB,QAAI,UAAU,OAAO;AAGnB,UAAI,MAAM,UAAU,WAAW,MAAM,OAAO;AAC1C,gBAAQ,MAAM,GAAG,cAAc,IAAI,MAAM,IAAI,KAAK,MAAM,MAAM,SAAA,CAAU,IAAI,MAAM,QAAQ,EAAE;AAAA,MAC9F;AACA;AAAA,IACF;AACA,QAAI,WAAW,MAAM,KAAK,IAAI,WAAW,KAAK,EAAG;AACjD,UAAM,SAAS,MAAM,eAAe,SAAY,KAAK,MAAM,UAAU,QAAQ;AAC7E,UAAM,OAAO,GAAG,cAAc,IAAI,MAAM,IAAI,GAAG,MAAM;AACrD,UAAM,UAAU,MAAM,QAAQ,EAAE,GAAG,MAAM,MAAM,OAAO,MAAM,MAAM,SAAA,EAAS,IAAM,MAAM;AACvF,UAAM,SACJ,MAAM,UAAU,UACZ,QAAQ,QACR,MAAM,UAAU,SACd,QAAQ,OACR,MAAM,UAAU,UACd,QAAQ,QACR,QAAQ;AAClB,WAAO,MAAM,WAAW,EAAE;AAAA,EAC5B;AAAA,EAEQ,iBAAiB,OAAoC;AAC3D,QAAI,CAAC,KAAK,OAAO,QAAS;AAC1B,QAAI,MAAM,eAAe,UAAa,MAAM,UAAU,QAAS;AAC/D,QAAI;AACF,YAAM,SAAS,mBAAA;AACf,0BAAoB,QAAQ,cAAc,MAAM,KAAK,QAAQ,OAAO,GAAG,CAAC,IAAI;AAAA,QAC1E,aAAa;AAAA,QACb,OAAO,MAAM;AAAA,QACb,GAAI,MAAM,eAAe,UAAa,EAAE,aAAa,MAAM,WAAA;AAAA,QAC3D,GAAI,MAAM,SAAS;AAAA,UACjB,YAAY,MAAM,MAAM;AAAA,UACxB,eAAe,MAAM,MAAM;AAAA,UAC3B,cAAc,MAAM,MAAM;AAAA,QAAA;AAAA,QAE5B,GAAG,MAAM;AAAA,MAAA,CACV;AAAA,IACH,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAEO,MAAM,oBAAoB,IAAI,qBAAA;AAO9B,SAAS,iCAAuC;AACrD,MAAI,OAAO,WAAW,YAAa;AACnC,QAAM,eAAe;AACrB,QAAM,WAAY,aAAa,UAAU,KAAK,CAAA;AAC9C,eAAa,UAAU,IAAI;AAAA,IACzB,GAAG;AAAA,IACH,SAAS;AAAA,IACT,aAAa;AAAA,MACX,UAAU,MAAM,kBAAkB,SAAA;AAAA,MAClC,QAAQ,MAAM,kBAAkB,OAAA;AAAA,MAChC,OAAO,MAAM,kBAAkB,MAAA;AAAA,MAC/B,eAAe,CAAC,QAA+B,YAAY;AACzD,YAAI;AACF,uBAAa,QAAQ,yBAAyB,KAAK;AAAA,QACrD,QAAQ;AAAA,QAER;AACA,0BAAkB,UAAU,EAAE,SAAS,MAAA,CAAO;AAAA,MAChD;AAAA,MACA,gBAAgB,MAAM;AACpB,YAAI;AACF,uBAAa,WAAW,uBAAuB;AAAA,QACjD,QAAQ;AAAA,QAER;AACA,0BAAkB,UAAU,EAAE,SAAS,MAAA,CAAO;AAAA,MAChD;AAAA,IAAA;AAAA,EACF;AAEJ;AAGO,SAAS,6BACd,OACkC;AAClC,MAAI,UAAU,OAAW,QAAO,CAAA;AAChC,MAAI,UAAU,KAAM,QAAO,EAAE,SAAS,QAAA;AACtC,MAAI,UAAU,MAAO,QAAO,EAAE,SAAS,MAAA;AACvC,MAAI,OAAO,UAAU,SAAU,QAAO,EAAE,SAAS,MAAA;AACjD,SAAO;AACT;"}
1
+ {"version":3,"file":"athena-diagnostics.js","sources":["../../src/diagnostics/athena-diagnostics.ts"],"sourcesContent":["/**\n * SDK diagnostics: one structured event bus for everything the SDK does that\n * can be slow or can fail — auth acquisition, thread-list fetches, statewire\n * attach/snapshot/connection changes, sends, first tokens, and every error.\n *\n * Design:\n * - Module-level singleton (one SDK, one bus), configured by `AthenaProvider`\n * from its `debug` / `onDiagnostic` / `onError` props. Nothing here runs\n * until something calls `emit`, and with defaults it costs a ring-buffer push.\n * - Every event carries `t` (ms since page navigation start via\n * `performance.now()`) so the buffer reads as a waterfall. Timed spans use\n * `performance.mark` / `performance.measure` too, so the browser Performance\n * panel shows them as user timings without any extra tooling.\n * - Console output is opt-in (`debug` prop or `localStorage['athena:debug']`),\n * prefixed `[AthenaSDK]`, and level-gated. Errors always reach `onError`.\n * - PostHog forwarding (opt-in) sends the timing events as\n * `athena_sdk_<name>` with `duration_ms`, through the SDK's capture gate.\n *\n * Consumers read the buffer with `useAthenaDiagnostics()` or, in the browser\n * console, `window.__ATHENA_SDK__.diagnostics.snapshot()`.\n */\n\nimport { getPostHogInstance } from '../provider/PostHogProvider';\nimport { capturePosthogEvent, type PosthogCaptureClient } from '../lib/posthog/wrap-posthog-client';\nimport { ATHENA_REACT_SDK_VERSION } from '../version';\nimport { AthenaSdkError, isAthenaSdkError, toAthenaSdkError } from './errors';\n\nexport const ATHENA_DIAGNOSTIC_LEVELS = ['debug', 'info', 'warn', 'error'] as const;\nexport type AthenaDiagnosticLevel = (typeof ATHENA_DIAGNOSTIC_LEVELS)[number];\n\nconst LEVEL_RANK: Record<AthenaDiagnosticLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\n/**\n * Event names. Dotted `area.event` so a consumer can filter by prefix. Names\n * are part of the public contract: renaming one is a breaking change for\n * dashboards, so add new ones instead of repurposing.\n */\nexport type AthenaDiagnosticEventName =\n // Provider / configuration\n | 'sdk.init'\n | 'sdk.transport'\n | 'sdk.config.warning'\n // Auth acquisition + lifecycle\n | 'auth.bridge.start'\n | 'auth.bridge.ready'\n | 'auth.bridge.timeout'\n | 'auth.bridge.absent'\n | 'auth.bridge.error'\n | 'auth.bridge.retry'\n | 'auth.bridge.config_rejected'\n | 'auth.token.acquired'\n | 'auth.token.refreshed'\n | 'auth.token.refresh_failed'\n | 'auth.token.stale'\n | 'auth.sso.userinfo.start'\n | 'auth.sso.userinfo.done'\n | 'auth.sso.userinfo.error'\n | 'auth.sso.userinfo.retry'\n // Thread list + history\n | 'threads.list.start'\n | 'threads.list.done'\n | 'threads.list.error'\n | 'threads.list.aborted'\n | 'threads.history.start'\n | 'threads.history.done'\n | 'threads.history.error'\n | 'threads.history.aborted'\n // Statewire transport\n | 'statewire.attach.start'\n | 'statewire.snapshot'\n | 'statewire.connection'\n | 'statewire.parked'\n | 'statewire.error'\n | 'statewire.read_only'\n /** A write to the thread's server config lane (`config/patch`) was refused or dropped. */\n | 'statewire.config'\n // Runs\n | 'run.send'\n | 'run.first_token'\n | 'run.done'\n | 'run.error'\n // Composer\n | 'composer.attachment.error'\n /** Files offered while Athena can't be reached were not attached (they could not upload). */\n | 'composer.attachment.refused_offline'\n | 'composer.cancel.error'\n | 'composer.dictation'\n | 'composer.handoff'\n | 'voice.chat'\n // Tool UIs + frontend tools\n | 'tools.schema.warning'\n | 'tools.debug'\n // Mention suggestions\n | 'mentions.fetch.error'\n // Catch-all\n | 'sdk.error';\n\nexport interface AthenaDiagnosticEvent {\n /** Monotonic sequence number within this page. */\n seq: number;\n /** `performance.now()` at emit time (ms since navigation start). */\n t: number;\n /** Wall-clock ISO timestamp, for exports. */\n at: string;\n name: AthenaDiagnosticEventName;\n level: AthenaDiagnosticLevel;\n /** Milliseconds for a completed span (set on `*.done` / `*.ready` / `run.first_token`). */\n durationMs?: number;\n /** Structured context. Never contains credentials — see `redact`. */\n data?: Record<string, unknown>;\n /** Present on error-level events. */\n error?: AthenaSdkError;\n}\n\nexport interface AthenaDiagnosticsConfig {\n /** Minimum level echoed to the console. `false` disables console output. */\n console: AthenaDiagnosticLevel | false;\n /** Forward timing + error events to PostHog as `athena_sdk_*` events. */\n posthog: boolean;\n /** Receives every event (already redacted). */\n onEvent?: (event: AthenaDiagnosticEvent) => void;\n /** Receives every error-level event's `AthenaSdkError`. */\n onError?: (error: AthenaSdkError, event: AthenaDiagnosticEvent) => void;\n /** Ring-buffer capacity. */\n bufferSize: number;\n}\n\nexport interface AthenaDiagnosticsSnapshot {\n sdkVersion: string;\n config: Omit<AthenaDiagnosticsConfig, 'onEvent' | 'onError'>;\n events: AthenaDiagnosticEvent[];\n /** Latest value per gauge (connection status, transport, auth mode, …). */\n gauges: Record<string, unknown>;\n /** Named span durations, most recent per name (`auth.bridge`, `threads.list`, …). */\n timings: Record<string, number>;\n}\n\nconst DEFAULT_CONFIG: AthenaDiagnosticsConfig = {\n console: false,\n posthog: false,\n bufferSize: 300,\n};\n\nconst CONSOLE_PREFIX = '[AthenaSDK]';\nconst LOCAL_STORAGE_DEBUG_KEY = 'athena:debug';\nconst GLOBAL_KEY = '__ATHENA_SDK__';\n\n// Keys whose values must never enter the buffer, the console, or PostHog.\nconst REDACT_KEYS = /token|secret|api[-_]?key|authorization|cookie|password/i;\n\nfunction redact(data: Record<string, unknown> | undefined): Record<string, unknown> | undefined {\n if (!data) return undefined;\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (REDACT_KEYS.test(key)) {\n out[key] = typeof value === 'string' && value.length > 0 ? `<redacted:${value.length}>` : '<redacted>';\n } else {\n out[key] = value;\n }\n }\n return out;\n}\n\nfunction nowMs(): number {\n return typeof performance !== 'undefined' && typeof performance.now === 'function'\n ? performance.now()\n : Date.now();\n}\n\nfunction readLocalDebugLevel(): AthenaDiagnosticLevel | null {\n try {\n if (typeof localStorage === 'undefined') return null;\n const raw = localStorage.getItem(LOCAL_STORAGE_DEBUG_KEY);\n if (!raw) return null;\n if ((ATHENA_DIAGNOSTIC_LEVELS as readonly string[]).includes(raw)) {\n return raw as AthenaDiagnosticLevel;\n }\n return raw === '1' || raw === 'true' ? 'debug' : null;\n } catch {\n return null;\n }\n}\n\ntype Listener = (event: AthenaDiagnosticEvent) => void;\n\nclass AthenaDiagnosticsBus {\n private config: AthenaDiagnosticsConfig = { ...DEFAULT_CONFIG };\n private events: AthenaDiagnosticEvent[] = [];\n private listeners = new Set<Listener>();\n private snapshotListeners = new Set<() => void>();\n private seq = 0;\n private gauges: Record<string, unknown> = {};\n private timings: Record<string, number> = {};\n private spans = new Map<string, number>();\n private cachedSnapshot: AthenaDiagnosticsSnapshot | null = null;\n\n configure(partial: Partial<AthenaDiagnosticsConfig>): void {\n this.config = { ...this.config, ...partial };\n if (this.events.length > this.config.bufferSize) {\n this.events = this.events.slice(-this.config.bufferSize);\n }\n this.invalidate();\n }\n\n getConfig(): AthenaDiagnosticsConfig {\n return this.config;\n }\n\n /** Effective console level: the configured one, or `localStorage['athena:debug']`. */\n private consoleLevel(): AthenaDiagnosticLevel | false {\n if (this.config.console !== false) return this.config.console;\n return readLocalDebugLevel() ?? false;\n }\n\n emit(\n name: AthenaDiagnosticEventName,\n options: {\n level?: AthenaDiagnosticLevel;\n data?: Record<string, unknown>;\n durationMs?: number;\n error?: unknown;\n } = {},\n ): AthenaDiagnosticEvent {\n const level = options.level ?? (options.error !== undefined ? 'error' : 'info');\n const error =\n options.error === undefined\n ? undefined\n : toAthenaSdkError(options.error, {\n code: 'unknown',\n message: `Unexpected error during ${name}`,\n });\n const event: AthenaDiagnosticEvent = {\n seq: ++this.seq,\n t: Math.round(nowMs() * 10) / 10,\n at: new Date().toISOString(),\n name,\n level,\n ...(options.durationMs !== undefined && { durationMs: Math.round(options.durationMs) }),\n ...(options.data && { data: redact(options.data) }),\n ...(error && { error }),\n };\n\n this.events.push(event);\n if (this.events.length > this.config.bufferSize) {\n this.events.splice(0, this.events.length - this.config.bufferSize);\n }\n if (event.durationMs !== undefined) {\n this.timings[name] = event.durationMs;\n }\n this.invalidate();\n\n this.echoToConsole(event);\n this.forwardToPostHog(event);\n for (const listener of this.listeners) {\n try {\n listener(event);\n } catch (listenerError) {\n console.error(`${CONSOLE_PREFIX} diagnostics listener threw`, listenerError);\n }\n }\n if (this.config.onEvent) {\n try {\n this.config.onEvent(event);\n } catch (callbackError) {\n console.error(`${CONSOLE_PREFIX} onDiagnostic callback threw`, callbackError);\n }\n }\n if (error && this.config.onError) {\n try {\n this.config.onError(error, event);\n } catch (callbackError) {\n console.error(`${CONSOLE_PREFIX} onError callback threw`, callbackError);\n }\n }\n for (const notify of this.snapshotListeners) notify();\n return event;\n }\n\n /** Record an error-level event. Returns the normalized `AthenaSdkError`. */\n error(\n name: AthenaDiagnosticEventName,\n error: unknown,\n fallback: { code: AthenaSdkError['code']; message: string; hint?: string },\n data?: Record<string, unknown>,\n ): AthenaSdkError {\n const normalized = toAthenaSdkError(error, fallback);\n this.emit(name, { level: 'error', error: normalized, data });\n return normalized;\n }\n\n /**\n * Start a named span. Returns a function that ends it and emits `doneName`\n * with `durationMs` (or `errorName` when passed an error). Also records a\n * `performance.measure` so the span shows in the browser's Performance panel.\n */\n span(\n spanName: string,\n startName: AthenaDiagnosticEventName,\n data?: Record<string, unknown>,\n ): (\n doneName: AthenaDiagnosticEventName,\n doneOptions?: { data?: Record<string, unknown>; error?: unknown },\n ) => number {\n const startedAt = nowMs();\n this.spans.set(spanName, startedAt);\n this.mark(`${spanName}:start`);\n this.emit(startName, { level: 'debug', data });\n return (doneName, doneOptions = {}) => {\n const durationMs = nowMs() - startedAt;\n this.spans.delete(spanName);\n this.mark(`${spanName}:end`);\n this.measure(spanName);\n this.emit(doneName, {\n level: doneOptions.error !== undefined ? 'error' : 'info',\n durationMs,\n data: doneOptions.data,\n error: doneOptions.error,\n });\n return durationMs;\n };\n }\n\n /** Set a gauge (latest-value metric): connection status, transport, auth mode. */\n gauge(name: string, value: unknown): void {\n if (this.gauges[name] === value) return;\n this.gauges[name] = value;\n this.invalidate();\n for (const notify of this.snapshotListeners) notify();\n }\n\n subscribe(listener: Listener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Additive consumer registration: every registered consumer receives every\n * event (and every error), unlike the single `onEvent`/`onError` config\n * slots which are last-writer-wins. `AthenaProvider` registers through this\n * so two mounted providers never clobber each other's callbacks.\n */\n addConsumer(consumer: {\n onEvent?: (event: AthenaDiagnosticEvent) => void;\n onError?: (error: AthenaSdkError, event: AthenaDiagnosticEvent) => void;\n }): () => void {\n return this.subscribe((event) => {\n try {\n consumer.onEvent?.(event);\n } catch (callbackError) {\n console.error(`${CONSOLE_PREFIX} onDiagnostic consumer threw`, callbackError);\n }\n if (event.error) {\n try {\n consumer.onError?.(event.error, event);\n } catch (callbackError) {\n console.error(`${CONSOLE_PREFIX} onError consumer threw`, callbackError);\n }\n }\n });\n }\n\n /** Subscribe to snapshot changes (for `useSyncExternalStore`). */\n subscribeSnapshot(listener: () => void): () => void {\n this.snapshotListeners.add(listener);\n return () => {\n this.snapshotListeners.delete(listener);\n };\n }\n\n snapshot(): AthenaDiagnosticsSnapshot {\n if (!this.cachedSnapshot) {\n const { onEvent: _onEvent, onError: _onError, ...config } = this.config;\n this.cachedSnapshot = {\n sdkVersion: ATHENA_REACT_SDK_VERSION,\n config,\n events: [...this.events],\n gauges: { ...this.gauges },\n timings: { ...this.timings },\n };\n }\n return this.cachedSnapshot;\n }\n\n /** Copy-paste-able JSON of the current snapshot (errors serialized). */\n export(): string {\n return JSON.stringify(\n this.snapshot(),\n (_key, value) => (isAthenaSdkError(value) ? value.toJSON() : value),\n 2,\n );\n }\n\n clear(): void {\n this.events = [];\n this.timings = {};\n this.invalidate();\n for (const notify of this.snapshotListeners) notify();\n }\n\n private invalidate(): void {\n this.cachedSnapshot = null;\n }\n\n private mark(name: string): void {\n try {\n if (typeof performance !== 'undefined' && typeof performance.mark === 'function') {\n performance.mark(`athena-sdk:${name}`);\n }\n } catch {\n // User Timing is best-effort.\n }\n }\n\n private measure(spanName: string): void {\n try {\n if (typeof performance !== 'undefined' && typeof performance.measure === 'function') {\n performance.measure(\n `athena-sdk:${spanName}`,\n `athena-sdk:${spanName}:start`,\n `athena-sdk:${spanName}:end`,\n );\n }\n } catch {\n // A missing start mark (e.g. after `performance.clearMarks`) is not an error.\n }\n }\n\n private echoToConsole(event: AthenaDiagnosticEvent): void {\n const level = this.consoleLevel();\n if (level === false) {\n // Errors are never silent: with console output off they still log once,\n // compactly, so a broken integration is visible without enabling debug.\n if (event.level === 'error' && event.error) {\n console.error(`${CONSOLE_PREFIX} ${event.name}: ${event.error.describe()}`, event.data ?? '');\n }\n return;\n }\n if (LEVEL_RANK[event.level] < LEVEL_RANK[level]) return;\n const suffix = event.durationMs !== undefined ? ` (${event.durationMs}ms)` : '';\n const line = `${CONSOLE_PREFIX} ${event.name}${suffix}`;\n const payload = event.error ? { ...event.data, error: event.error.describe() } : event.data;\n const method =\n event.level === 'error'\n ? console.error\n : event.level === 'warn'\n ? console.warn\n : event.level === 'debug'\n ? console.debug\n : console.info;\n method(line, payload ?? '');\n }\n\n private forwardToPostHog(event: AthenaDiagnosticEvent): void {\n if (!this.config.posthog) return;\n if (event.durationMs === undefined && event.level !== 'error') return;\n try {\n const client = getPostHogInstance<PosthogCaptureClient>();\n capturePosthogEvent(client, `athena_sdk_${event.name.replace(/\\./g, '_')}`, {\n sdk_version: ATHENA_REACT_SDK_VERSION,\n level: event.level,\n ...(event.durationMs !== undefined && { duration_ms: event.durationMs }),\n ...(event.error && {\n error_code: event.error.code,\n error_message: event.error.message,\n error_status: event.error.status,\n }),\n ...event.data,\n });\n } catch {\n // Analytics must never break the chat.\n }\n }\n}\n\nexport const athenaDiagnostics = new AthenaDiagnosticsBus();\n\n/**\n * Expose the bus on `window.__ATHENA_SDK__` so an integrator can inspect the\n * waterfall from the console (`__ATHENA_SDK__.diagnostics.snapshot()`) or turn\n * console echo on without a rebuild (`localStorage.setItem('athena:debug','debug')`).\n */\nexport function installAthenaDiagnosticsGlobal(): void {\n if (typeof window === 'undefined') return;\n const globalWindow = window as unknown as Record<string, unknown>;\n const existing = (globalWindow[GLOBAL_KEY] ?? {}) as Record<string, unknown>;\n globalWindow[GLOBAL_KEY] = {\n ...existing,\n version: ATHENA_REACT_SDK_VERSION,\n diagnostics: {\n snapshot: () => athenaDiagnostics.snapshot(),\n export: () => athenaDiagnostics.export(),\n clear: () => athenaDiagnostics.clear(),\n enableConsole: (level: AthenaDiagnosticLevel = 'debug') => {\n try {\n localStorage.setItem(LOCAL_STORAGE_DEBUG_KEY, level);\n } catch {\n // localStorage may be unavailable.\n }\n athenaDiagnostics.configure({ console: level });\n },\n disableConsole: () => {\n try {\n localStorage.removeItem(LOCAL_STORAGE_DEBUG_KEY);\n } catch {\n // localStorage may be unavailable.\n }\n athenaDiagnostics.configure({ console: false });\n },\n },\n };\n}\n\n/** Normalize the provider's `debug` prop into a diagnostics config patch. */\nexport function debugPropToDiagnosticsConfig(\n debug: boolean | AthenaDiagnosticLevel | Partial<AthenaDiagnosticsConfig> | undefined,\n): Partial<AthenaDiagnosticsConfig> {\n if (debug === undefined) return {};\n if (debug === true) return { console: 'debug' };\n if (debug === false) return { console: false };\n if (typeof debug === 'string') return { console: debug };\n return debug;\n}\n"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -17,7 +17,7 @@ export { getPostHogInstance } from './provider/PostHogProvider';
17
17
  export { capturePosthogEvent, capturePosthogException, getPosthogCaptureGate, wrapPosthogClient, } from './lib/posthog/wrap-posthog-client';
18
18
  export { buildCoalescedCaptureProperties, isCriticalPosthogEvent, withCaptureGateBypass, type CaptureGateSnapshot, type CoalescedCapturePayload, } from './lib/posthog/capture-gate';
19
19
  export { AthenaAssistantActionBar, AthenaAssistantMessage, AthenaChat, AthenaReasoningPart, AthenaUserMessage, } from './chat/AthenaChat';
20
- export type { AthenaAssistantActionBarProps, AthenaAssistantMessageProps, AthenaChatComponents, AthenaChatMessagePartComponents, AthenaChatProps, AthenaReasoningPartProps, AthenaUserMessageProps, } from './chat/AthenaChat';
20
+ export type { AthenaAssistantActionBarProps, AthenaAssistantMessageProps, AthenaChatComponents, AthenaChatMessagePartComponents, AthenaChatProps, AthenaChatVoiceOptions, AthenaReasoningPartProps, AthenaUserMessageProps, } from './chat/AthenaChat';
21
21
  export type { WelcomeSuggestion } from './chat/athena-chat-welcome';
22
22
  export { AthenaChatErrorBoundary } from './chat/AthenaChatErrorBoundary';
23
23
  export { type ActivityItem, type ActivityPhase, type ActivityTimelineOptions, type ActivityToolState, buildActivityTimeline, CollapsibleGroup, type CollapsibleGroupProps, countActivityTools, createToolBasedGroupingFunction, DEFAULT_TOOLKIT_THEME, defaultGetToolGroupKey, excludeFinalTextFromGroups, excludePartsFromGroups, type FinalTextPart, type FinalTextSegment, formatWorkDuration, getActivityItemLabel, getActivitySummary, getActivityToolState, getFinalText, getFinalTextParts, getReasoningLabel, type GetToolGroupKey, type GroupablePart, GroupedMessageParts, type GroupedMessagePartsProps, type GroupingFunction, type MessagePartGroup, readTurnTiming, resetRememberedExpansionsForTests, resolveActivityPhase, splitTurnSegments, SuperGroupingCard, type SuperGroupingCardProps, SuperGroupingFinalText, SuperGroupingProvider, SuperGroupingTranscript, type SuperGroupingTranscriptProps, TOOLKIT_THEMES, type ToolGroupKeyOptions, type ToolkitTheme, type TurnSegment, type TurnTiming, useActivityExpansion, workedDurationMs, } from './chat/super-grouping';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
- const version = "0.42.1";
3
+ const version = "0.43.0";
4
4
  const packageJson = {
5
5
  version
6
6
  };
@@ -1,4 +1,4 @@
1
- const version = "0.42.1";
1
+ const version = "0.43.0";
2
2
  const packageJson = {
3
3
  version
4
4
  };
@@ -97,23 +97,6 @@ export declare const GitHubToolkitOptionsSchema: z.ZodObject<{
97
97
  env_vars: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
98
98
  }, z.core.$strict>;
99
99
  export type GitHubToolkitOptions = z.infer<typeof GitHubToolkitOptionsSchema>;
100
- export declare const PerplexitySearchOptionsSchema: z.ZodObject<{
101
- model: z.ZodOptional<z.ZodEnum<{
102
- sonar: "sonar";
103
- "sonar-pro": "sonar-pro";
104
- "sonar-reasoning": "sonar-reasoning";
105
- }>>;
106
- search_recency_filter: z.ZodOptional<z.ZodEnum<{
107
- day: "day";
108
- hour: "hour";
109
- month: "month";
110
- week: "week";
111
- year: "year";
112
- }>>;
113
- search_domain_filter: z.ZodOptional<z.ZodArray<z.ZodString>>;
114
- max_results: z.ZodOptional<z.ZodNumber>;
115
- }, z.core.$strict>;
116
- export type PerplexitySearchOptions = z.infer<typeof PerplexitySearchOptionsSchema>;
117
100
  export declare const SendSlackMessageOptionsSchema: z.ZodObject<{
118
101
  channel_id: z.ZodOptional<z.ZodString>;
119
102
  channel_name: z.ZodOptional<z.ZodString>;
@@ -352,22 +335,6 @@ export declare const TOOL_OPTION_SCHEMAS: {
352
335
  secret_asset_id: z.ZodOptional<z.ZodString>;
353
336
  env_vars: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
354
337
  }, z.core.$strict>;
355
- readonly perplexity_search: z.ZodObject<{
356
- model: z.ZodOptional<z.ZodEnum<{
357
- sonar: "sonar";
358
- "sonar-pro": "sonar-pro";
359
- "sonar-reasoning": "sonar-reasoning";
360
- }>>;
361
- search_recency_filter: z.ZodOptional<z.ZodEnum<{
362
- day: "day";
363
- hour: "hour";
364
- month: "month";
365
- week: "week";
366
- year: "year";
367
- }>>;
368
- search_domain_filter: z.ZodOptional<z.ZodArray<z.ZodString>>;
369
- max_results: z.ZodOptional<z.ZodNumber>;
370
- }, z.core.$strict>;
371
338
  readonly send_slack_message: z.ZodObject<{
372
339
  channel_id: z.ZodOptional<z.ZodString>;
373
340
  channel_name: z.ZodOptional<z.ZodString>;
@@ -517,7 +484,6 @@ export type ToolOptionsMap = {
517
484
  python_toolkit: PythonToolkitOptions;
518
485
  toolkit_python: PythonToolkitOptions;
519
486
  github_toolkit: GitHubToolkitOptions;
520
- perplexity_search: PerplexitySearchOptions;
521
487
  send_slack_message: SendSlackMessageOptions;
522
488
  read_slack_channel: ReadSlackChannelOptions;
523
489
  track_website_changes: TrackWebChangesOptions;
@@ -1 +1 @@
1
- {"version":3,"file":"statewire-session-key.cjs","sources":["../../src/runtime/statewire-session-key.ts"],"sourcesContent":["import type { AthenaAuthState } from '../auth/types';\n\n/**\n * Scope of the persisted statewire command lane: the sync host, the signed-in\n * principal, and the thread. A thread id is only meaningful against the\n * backend that minted it, and a shared browser must never resend one user's\n * un-settled commands under the next user's token — so the key carries WHO is\n * signed in as well as where. The principal is a non-secret user id;\n * API-key-only hosts (no auth provider above) share one anonymous scope.\n */\nexport function statewireSessionKey({\n syncUrl,\n principal,\n threadId,\n}: {\n syncUrl: string;\n principal: string;\n threadId: string;\n}): string {\n return `${syncUrl}:${principal || 'anon'}:${threadId}`;\n}\n\n/**\n * The principal a thread's persisted command lane is scoped by\n * ({@link statewireSessionKey}): the signed-in user's id (also while the\n * sign-in provider refreshes and still names them), `''` (the one anonymous\n * scope) with no sign-in provider above or none signed in, and `null` while\n * the sign-in provider is still resolving who is signed in.\n *\n * A lane belongs to one principal for the life of the thread's mount: a\n * session mounted on a stand-in key keeps its client id, clock and journal when\n * the key changes, and leaves that record behind with the same client id, so a\n * later page load resends its journal below the server's watermark for the id\n * (`expired`). The lane therefore stays `pending` while this is `null` (see\n * `useAthenaStatewireRuntime`).\n */\nexport function statewireSessionPrincipal(\n auth: Pick<AthenaAuthState, 'isLoading' | 'user'> | null,\n): string | null {\n const userId = auth?.user?.userId;\n if (userId) return userId;\n return auth?.isLoading ? null : '';\n}\n"],"names":[],"mappings":";;AAUO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF,GAIW;AACT,SAAO,GAAG,OAAO,IAAI,aAAa,MAAM,IAAI,QAAQ;AACtD;AAgBO,SAAS,0BACd,MACe;;AACf,QAAM,UAAS,kCAAM,SAAN,mBAAY;AAC3B,MAAI,OAAQ,QAAO;AACnB,UAAO,6BAAM,aAAY,OAAO;AAClC;;;"}
1
+ {"version":3,"file":"statewire-session-key.cjs","sources":["../../src/runtime/statewire-session-key.ts"],"sourcesContent":["import type { AthenaAuthState } from '../auth/types';\n\n/**\n * Scope of the persisted statewire command lane: the sync host, the signed-in\n * principal, and the thread. A thread id is only meaningful against the\n * backend that minted it, and a shared browser must never resend one user's\n * un-settled commands under the next user's token — so the key carries WHO is\n * signed in as well as where. The principal is a non-secret user id;\n * API-key-only hosts (no auth provider above) share one anonymous scope.\n */\nexport function statewireSessionKey({\n syncUrl,\n principal,\n threadId,\n}: {\n syncUrl: string;\n principal: string;\n threadId: string;\n}): string {\n return `${syncUrl}:${principal || 'anon'}:${threadId}`;\n}\n\n/**\n * The principal a thread's persisted command lane is scoped by\n * ({@link statewireSessionKey}): the signed-in user's id (also while the\n * sign-in provider refreshes and still names them), `''` (the one anonymous\n * scope) with no sign-in provider above or none signed in, and `null` while\n * the sign-in provider is still resolving who is signed in.\n *\n * A lane belongs to one principal. When the principal changes under a mounted\n * chat (a provider signs a signed-out person in, or picks up another account),\n * the runtime remounts the conversation on the new principal's lane as a new\n * client: nothing the previous principal queued is sent as the new one, and\n * the previous principal's record stays for their next sign-in. While the\n * provider is still resolving who is signed in, the lane stays `pending`\n * (`null` here) rather than taking a stand-in key, which would make the first\n * sign-in a principal change and a second attach (see\n * `useAthenaStatewireRuntime`).\n */\nexport function statewireSessionPrincipal(\n auth: Pick<AthenaAuthState, 'isLoading' | 'user'> | null,\n): string | null {\n const userId = auth?.user?.userId;\n if (userId) return userId;\n return auth?.isLoading ? null : '';\n}\n"],"names":[],"mappings":";;AAUO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF,GAIW;AACT,SAAO,GAAG,OAAO,IAAI,aAAa,MAAM,IAAI,QAAQ;AACtD;AAmBO,SAAS,0BACd,MACe;;AACf,QAAM,UAAS,kCAAM,SAAN,mBAAY;AAC3B,MAAI,OAAQ,QAAO;AACnB,UAAO,6BAAM,aAAY,OAAO;AAClC;;;"}
@@ -19,11 +19,14 @@ export declare function statewireSessionKey({ syncUrl, principal, threadId, }: {
19
19
  * scope) with no sign-in provider above or none signed in, and `null` while
20
20
  * the sign-in provider is still resolving who is signed in.
21
21
  *
22
- * A lane belongs to one principal for the life of the thread's mount: a
23
- * session mounted on a stand-in key keeps its client id, clock and journal when
24
- * the key changes, and leaves that record behind with the same client id, so a
25
- * later page load resends its journal below the server's watermark for the id
26
- * (`expired`). The lane therefore stays `pending` while this is `null` (see
22
+ * A lane belongs to one principal. When the principal changes under a mounted
23
+ * chat (a provider signs a signed-out person in, or picks up another account),
24
+ * the runtime remounts the conversation on the new principal's lane as a new
25
+ * client: nothing the previous principal queued is sent as the new one, and
26
+ * the previous principal's record stays for their next sign-in. While the
27
+ * provider is still resolving who is signed in, the lane stays `pending`
28
+ * (`null` here) rather than taking a stand-in key, which would make the first
29
+ * sign-in a principal change and a second attach (see
27
30
  * `useAthenaStatewireRuntime`).
28
31
  */
29
32
  export declare function statewireSessionPrincipal(auth: Pick<AthenaAuthState, 'isLoading' | 'user'> | null): string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"statewire-session-key.js","sources":["../../src/runtime/statewire-session-key.ts"],"sourcesContent":["import type { AthenaAuthState } from '../auth/types';\n\n/**\n * Scope of the persisted statewire command lane: the sync host, the signed-in\n * principal, and the thread. A thread id is only meaningful against the\n * backend that minted it, and a shared browser must never resend one user's\n * un-settled commands under the next user's token — so the key carries WHO is\n * signed in as well as where. The principal is a non-secret user id;\n * API-key-only hosts (no auth provider above) share one anonymous scope.\n */\nexport function statewireSessionKey({\n syncUrl,\n principal,\n threadId,\n}: {\n syncUrl: string;\n principal: string;\n threadId: string;\n}): string {\n return `${syncUrl}:${principal || 'anon'}:${threadId}`;\n}\n\n/**\n * The principal a thread's persisted command lane is scoped by\n * ({@link statewireSessionKey}): the signed-in user's id (also while the\n * sign-in provider refreshes and still names them), `''` (the one anonymous\n * scope) with no sign-in provider above or none signed in, and `null` while\n * the sign-in provider is still resolving who is signed in.\n *\n * A lane belongs to one principal for the life of the thread's mount: a\n * session mounted on a stand-in key keeps its client id, clock and journal when\n * the key changes, and leaves that record behind with the same client id, so a\n * later page load resends its journal below the server's watermark for the id\n * (`expired`). The lane therefore stays `pending` while this is `null` (see\n * `useAthenaStatewireRuntime`).\n */\nexport function statewireSessionPrincipal(\n auth: Pick<AthenaAuthState, 'isLoading' | 'user'> | null,\n): string | null {\n const userId = auth?.user?.userId;\n if (userId) return userId;\n return auth?.isLoading ? null : '';\n}\n"],"names":[],"mappings":"AAUO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF,GAIW;AACT,SAAO,GAAG,OAAO,IAAI,aAAa,MAAM,IAAI,QAAQ;AACtD;AAgBO,SAAS,0BACd,MACe;AA5BV;AA6BL,QAAM,UAAS,kCAAM,SAAN,mBAAY;AAC3B,MAAI,OAAQ,QAAO;AACnB,UAAO,6BAAM,aAAY,OAAO;AAClC;"}
1
+ {"version":3,"file":"statewire-session-key.js","sources":["../../src/runtime/statewire-session-key.ts"],"sourcesContent":["import type { AthenaAuthState } from '../auth/types';\n\n/**\n * Scope of the persisted statewire command lane: the sync host, the signed-in\n * principal, and the thread. A thread id is only meaningful against the\n * backend that minted it, and a shared browser must never resend one user's\n * un-settled commands under the next user's token — so the key carries WHO is\n * signed in as well as where. The principal is a non-secret user id;\n * API-key-only hosts (no auth provider above) share one anonymous scope.\n */\nexport function statewireSessionKey({\n syncUrl,\n principal,\n threadId,\n}: {\n syncUrl: string;\n principal: string;\n threadId: string;\n}): string {\n return `${syncUrl}:${principal || 'anon'}:${threadId}`;\n}\n\n/**\n * The principal a thread's persisted command lane is scoped by\n * ({@link statewireSessionKey}): the signed-in user's id (also while the\n * sign-in provider refreshes and still names them), `''` (the one anonymous\n * scope) with no sign-in provider above or none signed in, and `null` while\n * the sign-in provider is still resolving who is signed in.\n *\n * A lane belongs to one principal. When the principal changes under a mounted\n * chat (a provider signs a signed-out person in, or picks up another account),\n * the runtime remounts the conversation on the new principal's lane as a new\n * client: nothing the previous principal queued is sent as the new one, and\n * the previous principal's record stays for their next sign-in. While the\n * provider is still resolving who is signed in, the lane stays `pending`\n * (`null` here) rather than taking a stand-in key, which would make the first\n * sign-in a principal change and a second attach (see\n * `useAthenaStatewireRuntime`).\n */\nexport function statewireSessionPrincipal(\n auth: Pick<AthenaAuthState, 'isLoading' | 'user'> | null,\n): string | null {\n const userId = auth?.user?.userId;\n if (userId) return userId;\n return auth?.isLoading ? null : '';\n}\n"],"names":[],"mappings":"AAUO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF,GAIW;AACT,SAAO,GAAG,OAAO,IAAI,aAAa,MAAM,IAAI,QAAQ;AACtD;AAmBO,SAAS,0BACd,MACe;AA/BV;AAgCL,QAAM,UAAS,kCAAM,SAAN,mBAAY;AAC3B,MAAI,OAAQ,QAAO;AACnB,UAAO,6BAAM,aAAY,OAAO;AAClC;"}
@@ -106,8 +106,11 @@ function useAthenaStatewireRuntime(config) {
106
106
  // server-render this SDK; the core's availability probe keeps those
107
107
  // sessions process-local, as before the seam existed.) Until the sign-in
108
108
  // provider knows who is signed in, the lane is pending: the transport
109
- // stays parked and nothing is mounted on a stand-in key the session could
110
- // not move off (`statewireSessionPrincipal`).
109
+ // stays parked and nothing is mounted on a stand-in key
110
+ // (`statewireSessionPrincipal`). A change to another principal remounts
111
+ // the conversation on that principal's lane instead of moving this one
112
+ // there (the runtime's lane epoch), so the previous principal's
113
+ // undelivered commands are never sent as the new one.
111
114
  session: principal === null ? { kind: "pending" } : {
112
115
  kind: "local-storage",
113
116
  key: (id) => statewireSessionKey.statewireSessionKey({ syncUrl, principal, threadId: id })
@@ -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 createSubagentTranscriptConversionCache,\n DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n type DeepAgentMessageWindowDeclaration,\n type DeepAgentStreamValues,\n type DeepAgentThreadElement,\n type DeepAgentThreadSnapshotCache,\n type DeepAgentToolOutputStore,\n isDeepAgentHostState,\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, statewireSessionPrincipal } 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 * Whether the chat this runtime serves loads a subagent lane's earlier steps\n * on request, as `AthenaChat`'s subagent card does (\"Load earlier steps\").\n * When true, its attaches declare the deep-agent lane-cut contract\n * (protocol 2): the host sends a finished subagent's card cut to its newest\n * steps, as it sends a running one, and the card reads the rest. Default\n * `false`, so a chat that does not page lanes declares the default contract\n * and finished lanes arrive whole; a host whose `AthenaChat` renders every\n * `task` call in the subagent card turns it on through `AthenaProvider`'s\n * `subagentLaneHistory`. Read once per attach.\n */\n subagentLaneHistory?: boolean;\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 /** The agent's mode picked for this thread (`AthenaProvider` `modes`). */\n mode?: 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 /** Every statewire command-lifecycle update (the chat outbox lets a handed-over message go on it). */\n onCommandChange?: UseDeepAgentThreadOptions['onCommandChange'];\n /**\n * Observes the host's own state: called with the attach snapshot and then on\n * every later frame (`isDeepAgentHostState`) — never with the placeholder or\n * remembered snapshot a thread renders before its snapshot applies, which\n * can be after the connection reports `connected`. Called per streamed\n * 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 mode,\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 subagentLaneHistory = false,\n toolOutputs,\n onError,\n onConnectionChange,\n onRawConnectionChange,\n onRunningChange,\n onCommandChange,\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`); `null` while the sign-in provider\n // above is still resolving who that is.\n const principal = statewireSessionPrincipal(useContext(AthenaAuthContext));\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 mode,\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 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.) Until the sign-in\n // provider knows who is signed in, the lane is pending: the transport\n // stays parked and nothing is mounted on a stand-in key the session could\n // not move off (`statewireSessionPrincipal`).\n session:\n principal === null\n ? { kind: 'pending' }\n : {\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 // Each `task` card's nested transcript becomes its tool-call part's\n // `messages` (assistant-ui's nested-thread channel), which the subagent\n // card (`SubagentTaskToolUI`) shows.\n createConversionCache: createSubagentTranscriptConversionCache,\n // The lane-cut contract only where the chat pages lanes (see `subagentLaneHistory`).\n laneHistory: subagentLaneHistory,\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 // Statewire publishes what the thread renders before its attach snapshot\n // through here too (the placeholder, a remembered snapshot, and a replay\n // boundary's pre-stream default), and on a thread mid-run it reports\n // `connected` before the snapshot applies: only a state the host sent\n // counts, whatever the connection says.\n if (!isDeepAgentHostState(state)) return;\n // The attach's first one 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 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,\n onRunningChange,\n ...(onCommandChange && { onCommandChange }),\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; `StatewireThreadConfigLaneSync` writes a changed model,\n // system prompt, tool list, workbench or knowledge base to the 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","statewireSessionPrincipal","useContext","AthenaAuthContext","useRef","athenaDiagnostics","buildStatewireRunConfig","statewireClientToolWireEntries","Tools","useAui","useDeepAgentRuntime","resolveStatewireAuthHeaders","statewireSessionKey","createSubagentTranscriptConversionCache","withStagedComposerMarkdown","isDeepAgentHostState","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 createSubagentTranscriptConversionCache,\n DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n type DeepAgentMessageWindowDeclaration,\n type DeepAgentStreamValues,\n type DeepAgentThreadElement,\n type DeepAgentThreadSnapshotCache,\n type DeepAgentToolOutputStore,\n isDeepAgentHostState,\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, statewireSessionPrincipal } 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 * Whether the chat this runtime serves loads a subagent lane's earlier steps\n * on request, as `AthenaChat`'s subagent card does (\"Load earlier steps\").\n * When true, its attaches declare the deep-agent lane-cut contract\n * (protocol 2): the host sends a finished subagent's card cut to its newest\n * steps, as it sends a running one, and the card reads the rest. Default\n * `false`, so a chat that does not page lanes declares the default contract\n * and finished lanes arrive whole; a host whose `AthenaChat` renders every\n * `task` call in the subagent card turns it on through `AthenaProvider`'s\n * `subagentLaneHistory`. Read once per attach.\n */\n subagentLaneHistory?: boolean;\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 /** The agent's mode picked for this thread (`AthenaProvider` `modes`). */\n mode?: 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 /** Every statewire command-lifecycle update (the chat outbox lets a handed-over message go on it). */\n onCommandChange?: UseDeepAgentThreadOptions['onCommandChange'];\n /**\n * Observes the host's own state: called with the attach snapshot and then on\n * every later frame (`isDeepAgentHostState`) — never with the placeholder or\n * remembered snapshot a thread renders before its snapshot applies, which\n * can be after the connection reports `connected`. Called per streamed\n * 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 mode,\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 subagentLaneHistory = false,\n toolOutputs,\n onError,\n onConnectionChange,\n onRawConnectionChange,\n onRunningChange,\n onCommandChange,\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`); `null` while the sign-in provider\n // above is still resolving who that is.\n const principal = statewireSessionPrincipal(useContext(AthenaAuthContext));\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 mode,\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 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.) Until the sign-in\n // provider knows who is signed in, the lane is pending: the transport\n // stays parked and nothing is mounted on a stand-in key\n // (`statewireSessionPrincipal`). A change to another principal remounts\n // the conversation on that principal's lane instead of moving this one\n // there (the runtime's lane epoch), so the previous principal's\n // undelivered commands are never sent as the new one.\n session:\n principal === null\n ? { kind: 'pending' }\n : {\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 // Each `task` card's nested transcript becomes its tool-call part's\n // `messages` (assistant-ui's nested-thread channel), which the subagent\n // card (`SubagentTaskToolUI`) shows.\n createConversionCache: createSubagentTranscriptConversionCache,\n // The lane-cut contract only where the chat pages lanes (see `subagentLaneHistory`).\n laneHistory: subagentLaneHistory,\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 // Statewire publishes what the thread renders before its attach snapshot\n // through here too (the placeholder, a remembered snapshot, and a replay\n // boundary's pre-stream default), and on a thread mid-run it reports\n // `connected` before the snapshot applies: only a state the host sent\n // counts, whatever the connection says.\n if (!isDeepAgentHostState(state)) return;\n // The attach's first one 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 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,\n onRunningChange,\n ...(onCommandChange && { onCommandChange }),\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; `StatewireThreadConfigLaneSync` writes a changed model,\n // system prompt, tool list, workbench or knowledge base to the 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","statewireSessionPrincipal","useContext","AthenaAuthContext","useRef","athenaDiagnostics","buildStatewireRunConfig","statewireClientToolWireEntries","Tools","useAui","useDeepAgentRuntime","resolveStatewireAuthHeaders","statewireSessionKey","createSubagentTranscriptConversionCache","withStagedComposerMarkdown","isDeepAgentHostState","isStatewireChannelTeardown","logUnhandledStatewireError"],"mappings":"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"}
@@ -105,8 +105,11 @@ function useAthenaStatewireRuntime(config) {
105
105
  // server-render this SDK; the core's availability probe keeps those
106
106
  // sessions process-local, as before the seam existed.) Until the sign-in
107
107
  // provider knows who is signed in, the lane is pending: the transport
108
- // stays parked and nothing is mounted on a stand-in key the session could
109
- // not move off (`statewireSessionPrincipal`).
108
+ // stays parked and nothing is mounted on a stand-in key
109
+ // (`statewireSessionPrincipal`). A change to another principal remounts
110
+ // the conversation on that principal's lane instead of moving this one
111
+ // there (the runtime's lane epoch), so the previous principal's
112
+ // undelivered commands are never sent as the new one.
110
113
  session: principal === null ? { kind: "pending" } : {
111
114
  kind: "local-storage",
112
115
  key: (id) => statewireSessionKey({ syncUrl, principal, threadId: id })
@@ -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 createSubagentTranscriptConversionCache,\n DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n type DeepAgentMessageWindowDeclaration,\n type DeepAgentStreamValues,\n type DeepAgentThreadElement,\n type DeepAgentThreadSnapshotCache,\n type DeepAgentToolOutputStore,\n isDeepAgentHostState,\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, statewireSessionPrincipal } 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 * Whether the chat this runtime serves loads a subagent lane's earlier steps\n * on request, as `AthenaChat`'s subagent card does (\"Load earlier steps\").\n * When true, its attaches declare the deep-agent lane-cut contract\n * (protocol 2): the host sends a finished subagent's card cut to its newest\n * steps, as it sends a running one, and the card reads the rest. Default\n * `false`, so a chat that does not page lanes declares the default contract\n * and finished lanes arrive whole; a host whose `AthenaChat` renders every\n * `task` call in the subagent card turns it on through `AthenaProvider`'s\n * `subagentLaneHistory`. Read once per attach.\n */\n subagentLaneHistory?: boolean;\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 /** The agent's mode picked for this thread (`AthenaProvider` `modes`). */\n mode?: 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 /** Every statewire command-lifecycle update (the chat outbox lets a handed-over message go on it). */\n onCommandChange?: UseDeepAgentThreadOptions['onCommandChange'];\n /**\n * Observes the host's own state: called with the attach snapshot and then on\n * every later frame (`isDeepAgentHostState`) — never with the placeholder or\n * remembered snapshot a thread renders before its snapshot applies, which\n * can be after the connection reports `connected`. Called per streamed\n * 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 mode,\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 subagentLaneHistory = false,\n toolOutputs,\n onError,\n onConnectionChange,\n onRawConnectionChange,\n onRunningChange,\n onCommandChange,\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`); `null` while the sign-in provider\n // above is still resolving who that is.\n const principal = statewireSessionPrincipal(useContext(AthenaAuthContext));\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 mode,\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 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.) Until the sign-in\n // provider knows who is signed in, the lane is pending: the transport\n // stays parked and nothing is mounted on a stand-in key the session could\n // not move off (`statewireSessionPrincipal`).\n session:\n principal === null\n ? { kind: 'pending' }\n : {\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 // Each `task` card's nested transcript becomes its tool-call part's\n // `messages` (assistant-ui's nested-thread channel), which the subagent\n // card (`SubagentTaskToolUI`) shows.\n createConversionCache: createSubagentTranscriptConversionCache,\n // The lane-cut contract only where the chat pages lanes (see `subagentLaneHistory`).\n laneHistory: subagentLaneHistory,\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 // Statewire publishes what the thread renders before its attach snapshot\n // through here too (the placeholder, a remembered snapshot, and a replay\n // boundary's pre-stream default), and on a thread mid-run it reports\n // `connected` before the snapshot applies: only a state the host sent\n // counts, whatever the connection says.\n if (!isDeepAgentHostState(state)) return;\n // The attach's first one 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 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,\n onRunningChange,\n ...(onCommandChange && { onCommandChange }),\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; `StatewireThreadConfigLaneSync` writes a changed model,\n // system prompt, tool list, workbench or knowledge base to the 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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"}
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 createSubagentTranscriptConversionCache,\n DEEP_AGENT_DEFAULT_MESSAGE_WINDOW,\n type DeepAgentMessageWindowDeclaration,\n type DeepAgentStreamValues,\n type DeepAgentThreadElement,\n type DeepAgentThreadSnapshotCache,\n type DeepAgentToolOutputStore,\n isDeepAgentHostState,\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, statewireSessionPrincipal } 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 * Whether the chat this runtime serves loads a subagent lane's earlier steps\n * on request, as `AthenaChat`'s subagent card does (\"Load earlier steps\").\n * When true, its attaches declare the deep-agent lane-cut contract\n * (protocol 2): the host sends a finished subagent's card cut to its newest\n * steps, as it sends a running one, and the card reads the rest. Default\n * `false`, so a chat that does not page lanes declares the default contract\n * and finished lanes arrive whole; a host whose `AthenaChat` renders every\n * `task` call in the subagent card turns it on through `AthenaProvider`'s\n * `subagentLaneHistory`. Read once per attach.\n */\n subagentLaneHistory?: boolean;\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 /** The agent's mode picked for this thread (`AthenaProvider` `modes`). */\n mode?: 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 /** Every statewire command-lifecycle update (the chat outbox lets a handed-over message go on it). */\n onCommandChange?: UseDeepAgentThreadOptions['onCommandChange'];\n /**\n * Observes the host's own state: called with the attach snapshot and then on\n * every later frame (`isDeepAgentHostState`) — never with the placeholder or\n * remembered snapshot a thread renders before its snapshot applies, which\n * can be after the connection reports `connected`. Called per streamed\n * 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 mode,\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 subagentLaneHistory = false,\n toolOutputs,\n onError,\n onConnectionChange,\n onRawConnectionChange,\n onRunningChange,\n onCommandChange,\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`); `null` while the sign-in provider\n // above is still resolving who that is.\n const principal = statewireSessionPrincipal(useContext(AthenaAuthContext));\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 mode,\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 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.) Until the sign-in\n // provider knows who is signed in, the lane is pending: the transport\n // stays parked and nothing is mounted on a stand-in key\n // (`statewireSessionPrincipal`). A change to another principal remounts\n // the conversation on that principal's lane instead of moving this one\n // there (the runtime's lane epoch), so the previous principal's\n // undelivered commands are never sent as the new one.\n session:\n principal === null\n ? { kind: 'pending' }\n : {\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 // Each `task` card's nested transcript becomes its tool-call part's\n // `messages` (assistant-ui's nested-thread channel), which the subagent\n // card (`SubagentTaskToolUI`) shows.\n createConversionCache: createSubagentTranscriptConversionCache,\n // The lane-cut contract only where the chat pages lanes (see `subagentLaneHistory`).\n laneHistory: subagentLaneHistory,\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 // Statewire publishes what the thread renders before its attach snapshot\n // through here too (the placeholder, a remembered snapshot, and a replay\n // boundary's pre-stream default), and on a thread mid-run it reports\n // `connected` before the snapshot applies: only a state the host sent\n // counts, whatever the connection says.\n if (!isDeepAgentHostState(state)) return;\n // The attach's first one 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 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,\n onRunningChange,\n ...(onCommandChange && { onCommandChange }),\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; `StatewireThreadConfigLaneSync` writes a changed model,\n // system prompt, tool list, workbench or knowledge base to the 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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"}