@athenaintel/react 0.42.1 → 0.42.2

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 (96) hide show
  1. package/README.md +36 -7
  2. package/dist/agent-runtime/src/index.d.ts +2 -2
  3. package/dist/agent-runtime/src/messages.cjs +38 -7
  4. package/dist/agent-runtime/src/messages.cjs.map +1 -1
  5. package/dist/agent-runtime/src/messages.d.ts +26 -8
  6. package/dist/agent-runtime/src/messages.js +38 -7
  7. package/dist/agent-runtime/src/messages.js.map +1 -1
  8. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +10 -0
  9. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
  10. package/dist/agent-runtime/src/quota-safe-local-storage-session.d.ts +7 -0
  11. package/dist/agent-runtime/src/quota-safe-local-storage-session.js +10 -0
  12. package/dist/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
  13. package/dist/agent-runtime/src/session-lane-scope.cjs +25 -0
  14. package/dist/agent-runtime/src/session-lane-scope.cjs.map +1 -0
  15. package/dist/agent-runtime/src/session-lane-scope.d.ts +59 -0
  16. package/dist/agent-runtime/src/session-lane-scope.js +25 -0
  17. package/dist/agent-runtime/src/session-lane-scope.js.map +1 -0
  18. package/dist/agent-runtime/src/subagent-transcripts.cjs +2 -2
  19. package/dist/agent-runtime/src/subagent-transcripts.cjs.map +1 -1
  20. package/dist/agent-runtime/src/subagent-transcripts.d.ts +2 -2
  21. package/dist/agent-runtime/src/subagent-transcripts.js +3 -3
  22. package/dist/agent-runtime/src/subagent-transcripts.js.map +1 -1
  23. package/dist/agent-runtime/src/tool-names.cjs +4 -0
  24. package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
  25. package/dist/agent-runtime/src/tool-names.d.ts +7 -0
  26. package/dist/agent-runtime/src/tool-names.js +4 -0
  27. package/dist/agent-runtime/src/tool-names.js.map +1 -1
  28. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +18 -1
  29. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
  30. package/dist/agent-runtime/src/use-deep-agent-runtime.d.ts +19 -10
  31. package/dist/agent-runtime/src/use-deep-agent-runtime.js +19 -2
  32. package/dist/agent-runtime/src/use-deep-agent-runtime.js.map +1 -1
  33. package/dist/agent-runtime/src/use-deep-agent-thread.cjs +28 -10
  34. package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  35. package/dist/agent-runtime/src/use-deep-agent-thread.d.ts +35 -3
  36. package/dist/agent-runtime/src/use-deep-agent-thread.js +28 -10
  37. package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
  38. package/dist/agent-runtime/src/use-deep-agent-voice.cjs +20 -0
  39. package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
  40. package/dist/agent-runtime/src/use-deep-agent-voice.js +20 -0
  41. package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -1
  42. package/dist/agent-runtime/src/voice-presentation.cjs +2 -0
  43. package/dist/agent-runtime/src/voice-presentation.cjs.map +1 -1
  44. package/dist/agent-runtime/src/voice-presentation.js +2 -0
  45. package/dist/agent-runtime/src/voice-presentation.js.map +1 -1
  46. package/dist/catalog/runtime-catalog.js +1 -1
  47. package/dist/chat/AthenaChat.cjs +125 -103
  48. package/dist/chat/AthenaChat.cjs.map +1 -1
  49. package/dist/chat/AthenaChat.d.ts +9 -0
  50. package/dist/chat/AthenaChat.js +126 -104
  51. package/dist/chat/AthenaChat.js.map +1 -1
  52. package/dist/chat/chat-voice-controls.cjs +128 -0
  53. package/dist/chat/chat-voice-controls.cjs.map +1 -0
  54. package/dist/chat/chat-voice-controls.d.ts +19 -0
  55. package/dist/chat/chat-voice-controls.js +128 -0
  56. package/dist/chat/chat-voice-controls.js.map +1 -0
  57. package/dist/chat/use-statewire-approval-request.js +1 -1
  58. package/dist/chat-ui/composer/tiptap-composer.cjs +42 -22
  59. package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
  60. package/dist/chat-ui/composer/tiptap-composer.d.ts +1 -0
  61. package/dist/chat-ui/composer/tiptap-composer.js +43 -23
  62. package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
  63. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +2 -1
  64. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
  65. package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +3 -1
  66. package/dist/chat-ui/mentions/suggestions/data/api-client.js +2 -1
  67. package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
  68. package/dist/chat-ui/mentions/use-account-workspace-id.cjs +29 -51
  69. package/dist/chat-ui/mentions/use-account-workspace-id.cjs.map +1 -1
  70. package/dist/chat-ui/mentions/use-account-workspace-id.d.ts +2 -2
  71. package/dist/chat-ui/mentions/use-account-workspace-id.js +30 -52
  72. package/dist/chat-ui/mentions/use-account-workspace-id.js.map +1 -1
  73. package/dist/chat-ui/thread/composer-send-or-stop.cjs +2 -1
  74. package/dist/chat-ui/thread/composer-send-or-stop.cjs.map +1 -1
  75. package/dist/chat-ui/thread/composer-send-or-stop.d.ts +2 -0
  76. package/dist/chat-ui/thread/composer-send-or-stop.js +2 -1
  77. package/dist/chat-ui/thread/composer-send-or-stop.js.map +1 -1
  78. package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
  79. package/dist/diagnostics/athena-diagnostics.d.ts +1 -1
  80. package/dist/diagnostics/athena-diagnostics.js.map +1 -1
  81. package/dist/index.d.ts +1 -1
  82. package/dist/react/package.json.cjs +1 -1
  83. package/dist/react/package.json.js +1 -1
  84. package/dist/runtime/statewire-session-key.cjs.map +1 -1
  85. package/dist/runtime/statewire-session-key.d.ts +8 -5
  86. package/dist/runtime/statewire-session-key.js.map +1 -1
  87. package/dist/runtime/useAthenaStatewireRuntime.cjs +5 -2
  88. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  89. package/dist/runtime/useAthenaStatewireRuntime.js +5 -2
  90. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  91. package/dist/voice/use-chat-voice-enabled.cjs +43 -0
  92. package/dist/voice/use-chat-voice-enabled.cjs.map +1 -0
  93. package/dist/voice/use-chat-voice-enabled.d.ts +9 -0
  94. package/dist/voice/use-chat-voice-enabled.js +43 -0
  95. package/dist/voice/use-chat-voice-enabled.js.map +1 -0
  96. package/package.json +4 -8
@@ -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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"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const reactQuery = require("@tanstack/react-query");
4
+ const apiClient = require("../chat-ui/mentions/suggestions/data/api-client.cjs");
5
+ const runtimeCatalog = require("../catalog/runtime-catalog.cjs");
6
+ const CHAT_VOICE_ACCESS_QUERY = `
7
+ query AthenaChatVoiceAccess {
8
+ getCurrentUserWithWorkspace { workspace { id voiceModeConfig } }
9
+ }
10
+ `;
11
+ function readChatVoiceEnabled(data) {
12
+ if (typeof data !== "object" || data === null || !("getCurrentUserWithWorkspace" in data))
13
+ return false;
14
+ const account = data.getCurrentUserWithWorkspace;
15
+ if (typeof account !== "object" || account === null || !("workspace" in account)) return false;
16
+ const workspace = account.workspace;
17
+ if (typeof workspace !== "object" || workspace === null || !("voiceModeConfig" in workspace))
18
+ return false;
19
+ const config = workspace.voiceModeConfig;
20
+ return typeof config === "object" && config !== null && "enabled" in config && config.enabled === true;
21
+ }
22
+ function useChatVoiceEnabled({ enabled }) {
23
+ const auth = apiClient.useMentionAuth();
24
+ const principal = runtimeCatalog.useCatalogPrincipal();
25
+ const queryClient = runtimeCatalog.useCatalogQueryClient();
26
+ const query = reactQuery.useQuery(
27
+ {
28
+ queryKey: ["athena-sdk", "chat-voice-access", auth.backendUrl, principal, auth.workspaceId],
29
+ queryFn: async ({ signal }) => readChatVoiceEnabled(
30
+ await apiClient.fetchGraphQL(auth, CHAT_VOICE_ACCESS_QUERY, {}, { signal })
31
+ ),
32
+ enabled,
33
+ retry: false,
34
+ staleTime: 3e4,
35
+ refetchInterval: 3e4
36
+ },
37
+ queryClient
38
+ );
39
+ return enabled && !query.isError && query.data === true;
40
+ }
41
+ exports.readChatVoiceEnabled = readChatVoiceEnabled;
42
+ exports.useChatVoiceEnabled = useChatVoiceEnabled;
43
+ //# sourceMappingURL=use-chat-voice-enabled.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-chat-voice-enabled.cjs","sources":["../../src/voice/use-chat-voice-enabled.ts"],"sourcesContent":["import { useQuery } from '@tanstack/react-query';\nimport { useMentionAuth, fetchGraphQL } from '../chat-ui/mentions/suggestions/data/api-client';\nimport { useCatalogPrincipal, useCatalogQueryClient } from '../catalog/runtime-catalog';\n\nconst CHAT_VOICE_ACCESS_QUERY = `\n query AthenaChatVoiceAccess {\n getCurrentUserWithWorkspace { workspace { id voiceModeConfig } }\n }\n`;\n\n/** Only an explicit boolean enables voice; malformed or older answers fail closed. */\nexport function readChatVoiceEnabled(data: unknown): boolean {\n if (typeof data !== 'object' || data === null || !('getCurrentUserWithWorkspace' in data))\n return false;\n const account = data.getCurrentUserWithWorkspace;\n if (typeof account !== 'object' || account === null || !('workspace' in account)) return false;\n const workspace = account.workspace;\n if (typeof workspace !== 'object' || workspace === null || !('voiceModeConfig' in workspace))\n return false;\n const config = workspace.voiceModeConfig;\n return (\n typeof config === 'object' && config !== null && 'enabled' in config && config.enabled === true\n );\n}\n\n/**\n * The workspace read already folds in VOICE_MODE_ENABLED on the server. This\n * controls presentation; voice/start still enforces _require_voice_access.\n */\nexport function useChatVoiceEnabled({ enabled }: { enabled: boolean }): boolean {\n const auth = useMentionAuth();\n const principal = useCatalogPrincipal();\n const queryClient = useCatalogQueryClient();\n const query = useQuery(\n {\n queryKey: ['athena-sdk', 'chat-voice-access', auth.backendUrl, principal, auth.workspaceId],\n queryFn: async ({ signal }) =>\n readChatVoiceEnabled(\n await fetchGraphQL<unknown>(auth, CHAT_VOICE_ACCESS_QUERY, {}, { signal })\n ),\n enabled,\n retry: false,\n staleTime: 30_000,\n refetchInterval: 30_000,\n },\n queryClient\n );\n return enabled && !query.isError && query.data === true;\n}\n"],"names":["useMentionAuth","useCatalogPrincipal","useCatalogQueryClient","useQuery","fetchGraphQL"],"mappings":";;;;;AAIA,MAAM,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAOzB,SAAS,qBAAqB,MAAwB;AAC3D,MAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,EAAE,iCAAiC;AAClF,WAAO;AACT,QAAM,UAAU,KAAK;AACrB,MAAI,OAAO,YAAY,YAAY,YAAY,QAAQ,EAAE,eAAe,SAAU,QAAO;AACzF,QAAM,YAAY,QAAQ;AAC1B,MAAI,OAAO,cAAc,YAAY,cAAc,QAAQ,EAAE,qBAAqB;AAChF,WAAO;AACT,QAAM,SAAS,UAAU;AACzB,SACE,OAAO,WAAW,YAAY,WAAW,QAAQ,aAAa,UAAU,OAAO,YAAY;AAE/F;AAMO,SAAS,oBAAoB,EAAE,WAA0C;AAC9E,QAAM,OAAOA,UAAAA,eAAA;AACb,QAAM,YAAYC,eAAAA,oBAAA;AAClB,QAAM,cAAcC,eAAAA,sBAAA;AACpB,QAAM,QAAQC,WAAAA;AAAAA,IACZ;AAAA,MACE,UAAU,CAAC,cAAc,qBAAqB,KAAK,YAAY,WAAW,KAAK,WAAW;AAAA,MAC1F,SAAS,OAAO,EAAE,OAAA,MAChB;AAAA,QACE,MAAMC,UAAAA,aAAsB,MAAM,yBAAyB,CAAA,GAAI,EAAE,QAAQ;AAAA,MAAA;AAAA,MAE7E;AAAA,MACA,OAAO;AAAA,MACP,WAAW;AAAA,MACX,iBAAiB;AAAA,IAAA;AAAA,IAEnB;AAAA,EAAA;AAEF,SAAO,WAAW,CAAC,MAAM,WAAW,MAAM,SAAS;AACrD;;;"}
@@ -0,0 +1,9 @@
1
+ /** Only an explicit boolean enables voice; malformed or older answers fail closed. */
2
+ export declare function readChatVoiceEnabled(data: unknown): boolean;
3
+ /**
4
+ * The workspace read already folds in VOICE_MODE_ENABLED on the server. This
5
+ * controls presentation; voice/start still enforces _require_voice_access.
6
+ */
7
+ export declare function useChatVoiceEnabled({ enabled }: {
8
+ enabled: boolean;
9
+ }): boolean;
@@ -0,0 +1,43 @@
1
+ import { useQuery } from "@tanstack/react-query";
2
+ import { useMentionAuth, fetchGraphQL } from "../chat-ui/mentions/suggestions/data/api-client.js";
3
+ import { useCatalogPrincipal, useCatalogQueryClient } from "../catalog/runtime-catalog.js";
4
+ const CHAT_VOICE_ACCESS_QUERY = `
5
+ query AthenaChatVoiceAccess {
6
+ getCurrentUserWithWorkspace { workspace { id voiceModeConfig } }
7
+ }
8
+ `;
9
+ function readChatVoiceEnabled(data) {
10
+ if (typeof data !== "object" || data === null || !("getCurrentUserWithWorkspace" in data))
11
+ return false;
12
+ const account = data.getCurrentUserWithWorkspace;
13
+ if (typeof account !== "object" || account === null || !("workspace" in account)) return false;
14
+ const workspace = account.workspace;
15
+ if (typeof workspace !== "object" || workspace === null || !("voiceModeConfig" in workspace))
16
+ return false;
17
+ const config = workspace.voiceModeConfig;
18
+ return typeof config === "object" && config !== null && "enabled" in config && config.enabled === true;
19
+ }
20
+ function useChatVoiceEnabled({ enabled }) {
21
+ const auth = useMentionAuth();
22
+ const principal = useCatalogPrincipal();
23
+ const queryClient = useCatalogQueryClient();
24
+ const query = useQuery(
25
+ {
26
+ queryKey: ["athena-sdk", "chat-voice-access", auth.backendUrl, principal, auth.workspaceId],
27
+ queryFn: async ({ signal }) => readChatVoiceEnabled(
28
+ await fetchGraphQL(auth, CHAT_VOICE_ACCESS_QUERY, {}, { signal })
29
+ ),
30
+ enabled,
31
+ retry: false,
32
+ staleTime: 3e4,
33
+ refetchInterval: 3e4
34
+ },
35
+ queryClient
36
+ );
37
+ return enabled && !query.isError && query.data === true;
38
+ }
39
+ export {
40
+ readChatVoiceEnabled,
41
+ useChatVoiceEnabled
42
+ };
43
+ //# sourceMappingURL=use-chat-voice-enabled.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-chat-voice-enabled.js","sources":["../../src/voice/use-chat-voice-enabled.ts"],"sourcesContent":["import { useQuery } from '@tanstack/react-query';\nimport { useMentionAuth, fetchGraphQL } from '../chat-ui/mentions/suggestions/data/api-client';\nimport { useCatalogPrincipal, useCatalogQueryClient } from '../catalog/runtime-catalog';\n\nconst CHAT_VOICE_ACCESS_QUERY = `\n query AthenaChatVoiceAccess {\n getCurrentUserWithWorkspace { workspace { id voiceModeConfig } }\n }\n`;\n\n/** Only an explicit boolean enables voice; malformed or older answers fail closed. */\nexport function readChatVoiceEnabled(data: unknown): boolean {\n if (typeof data !== 'object' || data === null || !('getCurrentUserWithWorkspace' in data))\n return false;\n const account = data.getCurrentUserWithWorkspace;\n if (typeof account !== 'object' || account === null || !('workspace' in account)) return false;\n const workspace = account.workspace;\n if (typeof workspace !== 'object' || workspace === null || !('voiceModeConfig' in workspace))\n return false;\n const config = workspace.voiceModeConfig;\n return (\n typeof config === 'object' && config !== null && 'enabled' in config && config.enabled === true\n );\n}\n\n/**\n * The workspace read already folds in VOICE_MODE_ENABLED on the server. This\n * controls presentation; voice/start still enforces _require_voice_access.\n */\nexport function useChatVoiceEnabled({ enabled }: { enabled: boolean }): boolean {\n const auth = useMentionAuth();\n const principal = useCatalogPrincipal();\n const queryClient = useCatalogQueryClient();\n const query = useQuery(\n {\n queryKey: ['athena-sdk', 'chat-voice-access', auth.backendUrl, principal, auth.workspaceId],\n queryFn: async ({ signal }) =>\n readChatVoiceEnabled(\n await fetchGraphQL<unknown>(auth, CHAT_VOICE_ACCESS_QUERY, {}, { signal })\n ),\n enabled,\n retry: false,\n staleTime: 30_000,\n refetchInterval: 30_000,\n },\n queryClient\n );\n return enabled && !query.isError && query.data === true;\n}\n"],"names":[],"mappings":";;;AAIA,MAAM,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAOzB,SAAS,qBAAqB,MAAwB;AAC3D,MAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,EAAE,iCAAiC;AAClF,WAAO;AACT,QAAM,UAAU,KAAK;AACrB,MAAI,OAAO,YAAY,YAAY,YAAY,QAAQ,EAAE,eAAe,SAAU,QAAO;AACzF,QAAM,YAAY,QAAQ;AAC1B,MAAI,OAAO,cAAc,YAAY,cAAc,QAAQ,EAAE,qBAAqB;AAChF,WAAO;AACT,QAAM,SAAS,UAAU;AACzB,SACE,OAAO,WAAW,YAAY,WAAW,QAAQ,aAAa,UAAU,OAAO,YAAY;AAE/F;AAMO,SAAS,oBAAoB,EAAE,WAA0C;AAC9E,QAAM,OAAO,eAAA;AACb,QAAM,YAAY,oBAAA;AAClB,QAAM,cAAc,sBAAA;AACpB,QAAM,QAAQ;AAAA,IACZ;AAAA,MACE,UAAU,CAAC,cAAc,qBAAqB,KAAK,YAAY,WAAW,KAAK,WAAW;AAAA,MAC1F,SAAS,OAAO,EAAE,OAAA,MAChB;AAAA,QACE,MAAM,aAAsB,MAAM,yBAAyB,CAAA,GAAI,EAAE,QAAQ;AAAA,MAAA;AAAA,MAE7E;AAAA,MACA,OAAO;AAAA,MACP,WAAW;AAAA,MACX,iBAAiB;AAAA,IAAA;AAAA,IAEnB;AAAA,EAAA;AAEF,SAAO,WAAW,CAAC,MAAM,WAAW,MAAM,SAAS;AACrD;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@athenaintel/react",
3
- "version": "0.42.1",
3
+ "version": "0.42.2",
4
4
  "description": "Athena React SDK — Build AI-powered chat applications with the Athena platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -87,7 +87,6 @@
87
87
  "preinstall": "node -e \"if(!(process.env.npm_config_user_agent||'').startsWith('bun/')){console.error('\\n✗ This monorepo requires bun. Run \\`bun install\\` at the repo root.\\n https://bun.com/docs/installation\\n');process.exit(1)}\""
88
88
  },
89
89
  "peerDependencies": {
90
- "livekit-client": "^2.19.0",
91
90
  "posthog-js": "^1.0.0",
92
91
  "react": "^18.0.0 || ^19.0.0",
93
92
  "react-dom": "^18.0.0 || ^19.0.0",
@@ -97,9 +96,6 @@
97
96
  "@propelauth/react": {
98
97
  "optional": true
99
98
  },
100
- "livekit-client": {
101
- "optional": true
102
- },
103
99
  "posthog-js": {
104
100
  "optional": true
105
101
  }
@@ -120,11 +116,11 @@
120
116
  "@tiptap/core": "^3.31.3",
121
117
  "@tiptap/extension-code-block": "^3.31.3",
122
118
  "@tiptap/extension-image": "^3.31.3",
123
- "@tiptap/extension-task-item": "^3.31.3",
124
- "@tiptap/extension-task-list": "^3.31.3",
125
119
  "@tiptap/extension-link": "^3.31.3",
126
120
  "@tiptap/extension-placeholder": "^3.31.3",
127
121
  "@tiptap/extension-table": "^3.31.3",
122
+ "@tiptap/extension-task-item": "^3.31.3",
123
+ "@tiptap/extension-task-list": "^3.31.3",
128
124
  "@tiptap/pm": "^3.31.3",
129
125
  "@tiptap/react": "^3.31.3",
130
126
  "@tiptap/starter-kit": "^3.31.3",
@@ -134,6 +130,7 @@
134
130
  "assistant-stream": "0.3.54",
135
131
  "class-variance-authority": "^0.7.1",
136
132
  "cnfast": "0.0.8",
133
+ "livekit-client": "2.23.0",
137
134
  "lucide-react": "^0.575.0",
138
135
  "radix-ui": "^1.4.3",
139
136
  "remark-gfm": "^4.0.0",
@@ -150,7 +147,6 @@
150
147
  "@tailwindcss/cli": "^4.2.1",
151
148
  "@types/react": "^19.0.0",
152
149
  "@types/react-dom": "^19.0.0",
153
- "livekit-client": "2.23.0",
154
150
  "posthog-js": "^1.386.6",
155
151
  "react": "^19.0.0",
156
152
  "react-dom": "^19.0.0",