@athenaintel/react 0.23.3 → 0.24.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.
- package/README.md +6 -0
- package/dist/assets/AssetPanel.cjs +1 -1
- package/dist/assets/AssetPanel.cjs.map +1 -1
- package/dist/assets/AssetPanel.js +1 -1
- package/dist/assets/AssetPanel.js.map +1 -1
- package/dist/assets/AthenaAssetEmbed.cjs +1 -1
- package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
- package/dist/assets/AthenaAssetEmbed.js +1 -1
- package/dist/assets/AthenaAssetEmbed.js.map +1 -1
- package/dist/chat/AthenaChat.cjs +15 -23
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.d.ts +9 -4
- package/dist/chat/AthenaChat.js +15 -23
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/StatewireApprovalCard.cjs +3 -18
- package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
- package/dist/chat/StatewireApprovalCard.js +3 -18
- package/dist/chat/StatewireApprovalCard.js.map +1 -1
- package/dist/chat/StatewireClientToolBridge.cjs +2 -16
- package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
- package/dist/chat/StatewireClientToolBridge.js +2 -16
- package/dist/chat/StatewireClientToolBridge.js.map +1 -1
- package/dist/chat/StatewireQueuedMessages.cjs +5 -16
- package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
- package/dist/chat/StatewireQueuedMessages.js +5 -16
- package/dist/chat/StatewireQueuedMessages.js.map +1 -1
- package/dist/chat/WaitingOnYouBanner.cjs +3 -18
- package/dist/chat/WaitingOnYouBanner.cjs.map +1 -1
- package/dist/chat/WaitingOnYouBanner.js +3 -18
- package/dist/chat/WaitingOnYouBanner.js.map +1 -1
- package/dist/chat/run-activity.cjs +0 -16
- package/dist/chat/run-activity.cjs.map +1 -1
- package/dist/chat/run-activity.js +0 -16
- package/dist/chat/run-activity.js.map +1 -1
- package/dist/chat/statewire-client-tools.cjs +1 -17
- package/dist/chat/statewire-client-tools.cjs.map +1 -1
- package/dist/chat/statewire-client-tools.js +1 -17
- package/dist/chat/statewire-client-tools.js.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.cjs +0 -16
- package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.js +0 -16
- package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
- package/dist/chat/tiptap-text.cjs +1 -17
- package/dist/chat/tiptap-text.cjs.map +1 -1
- package/dist/chat/tiptap-text.js +1 -17
- package/dist/chat/tiptap-text.js.map +1 -1
- package/dist/chat/use-athena-run-live.cjs +0 -15
- package/dist/chat/use-athena-run-live.cjs.map +1 -1
- package/dist/chat/use-athena-run-live.js +0 -15
- package/dist/chat/use-athena-run-live.js.map +1 -1
- package/dist/chat/use-statewire-approval-request.cjs +4 -16
- package/dist/chat/use-statewire-approval-request.cjs.map +1 -1
- package/dist/chat/use-statewire-approval-request.d.ts +2 -0
- package/dist/chat/use-statewire-approval-request.js +4 -16
- package/dist/chat/use-statewire-approval-request.js.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.cjs +1 -16
- package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.js +1 -16
- package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
- package/dist/chat-ui/index.cjs +0 -16
- package/dist/chat-ui/index.cjs.map +1 -1
- package/dist/chat-ui/index.js +0 -16
- package/dist/chat-ui/index.js.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.cjs +1 -16
- package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.js +1 -16
- package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs +4 -6
- package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js +4 -6
- package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +2 -9
- package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/index.js +2 -9
- package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
- package/dist/chat-ui/messages/message-components.cjs +5 -19
- package/dist/chat-ui/messages/message-components.cjs.map +1 -1
- package/dist/chat-ui/messages/message-components.js +5 -19
- package/dist/chat-ui/messages/message-components.js.map +1 -1
- package/dist/chat-ui/messages/runtime-message.cjs +1 -16
- package/dist/chat-ui/messages/runtime-message.cjs.map +1 -1
- package/dist/chat-ui/messages/runtime-message.js +1 -16
- package/dist/chat-ui/messages/runtime-message.js.map +1 -1
- package/dist/chat-ui/messages/statewire-continue-run.cjs +3 -15
- package/dist/chat-ui/messages/statewire-continue-run.cjs.map +1 -1
- package/dist/chat-ui/messages/statewire-continue-run.js +3 -15
- package/dist/chat-ui/messages/statewire-continue-run.js.map +1 -1
- package/dist/chat-ui/messages/user-edit-composer.cjs +0 -16
- package/dist/chat-ui/messages/user-edit-composer.cjs.map +1 -1
- package/dist/chat-ui/messages/user-edit-composer.js +0 -16
- package/dist/chat-ui/messages/user-edit-composer.js.map +1 -1
- package/dist/chat-ui/messages/wake-marker.cjs +1 -16
- package/dist/chat-ui/messages/wake-marker.cjs.map +1 -1
- package/dist/chat-ui/messages/wake-marker.js +1 -16
- package/dist/chat-ui/messages/wake-marker.js.map +1 -1
- package/dist/chat-ui/statewire.cjs +0 -16
- package/dist/chat-ui/statewire.cjs.map +1 -1
- package/dist/chat-ui/statewire.js +0 -16
- package/dist/chat-ui/statewire.js.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.cjs +2 -17
- package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.js +2 -17
- package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
- package/dist/dictation/DictationStrip.cjs +2 -1
- package/dist/dictation/DictationStrip.cjs.map +1 -1
- package/dist/dictation/DictationStrip.d.ts +2 -0
- package/dist/dictation/DictationStrip.js +2 -1
- package/dist/dictation/DictationStrip.js.map +1 -1
- package/dist/dictation/dictation-engine.cjs.map +1 -1
- package/dist/dictation/dictation-engine.d.ts +8 -0
- package/dist/dictation/dictation-engine.js.map +1 -1
- package/dist/dictation/recorded-dictation-engine.cjs +153 -0
- package/dist/dictation/recorded-dictation-engine.cjs.map +1 -0
- package/dist/dictation/recorded-dictation-engine.d.ts +66 -0
- package/dist/dictation/recorded-dictation-engine.js +153 -0
- package/dist/dictation/recorded-dictation-engine.js.map +1 -0
- package/dist/dictation/use-athena-dictation-engine.cjs +64 -0
- package/dist/dictation/use-athena-dictation-engine.cjs.map +1 -0
- package/dist/dictation/use-athena-dictation-engine.d.ts +25 -0
- package/dist/dictation/use-athena-dictation-engine.js +64 -0
- package/dist/dictation/use-athena-dictation-engine.js.map +1 -0
- package/dist/dictation/use-dictation.cjs +17 -6
- package/dist/dictation/use-dictation.cjs.map +1 -1
- package/dist/dictation/use-dictation.d.ts +20 -4
- package/dist/dictation/use-dictation.js +17 -6
- package/dist/dictation/use-dictation.js.map +1 -1
- package/dist/index.cjs +28 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +10 -21
- package/dist/index.js.map +1 -1
- package/dist/packages/agent-runtime/src/edit-command.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/edit-command.js.map +1 -1
- package/dist/packages/agent-runtime/src/errors.cjs +18 -0
- package/dist/packages/agent-runtime/src/errors.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/errors.js +19 -1
- package/dist/packages/agent-runtime/src/errors.js.map +1 -1
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.cjs +1 -0
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.js +1 -0
- package/dist/packages/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
- package/dist/packages/agent-runtime/src/interrupts.cjs +61 -12
- package/dist/packages/agent-runtime/src/interrupts.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/interrupts.js +61 -12
- package/dist/packages/agent-runtime/src/interrupts.js.map +1 -1
- package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.cjs +49 -0
- package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.js +49 -0
- package/dist/packages/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
- package/dist/packages/agent-runtime/src/thread-status.js +1 -1
- package/dist/packages/agent-runtime/src/tool-metadata.cjs +1 -37
- package/dist/packages/agent-runtime/src/tool-metadata.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/tool-metadata.js +1 -37
- package/dist/packages/agent-runtime/src/tool-metadata.js.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-config.cjs +0 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-config.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-config.js +0 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-config.js.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
- package/dist/packages/react/package.json.cjs +1 -1
- package/dist/packages/react/package.json.js +1 -1
- package/dist/provider/AthenaProvider.cjs +3 -17
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.js +3 -17
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/runtime/statewire-lifecycle.cjs +0 -16
- package/dist/runtime/statewire-lifecycle.cjs.map +1 -1
- package/dist/runtime/statewire-lifecycle.js +0 -16
- package/dist/runtime/statewire-lifecycle.js.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.cjs +3 -17
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.js +3 -17
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/dist/threads/statewire-thread-list.cjs +4 -17
- package/dist/threads/statewire-thread-list.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.js +4 -17
- package/dist/threads/statewire-thread-list.js.map +1 -1
- package/dist/threads/use-rest-conversation-history.cjs +2 -16
- package/dist/threads/use-rest-conversation-history.cjs.map +1 -1
- package/dist/threads/use-rest-conversation-history.js +2 -16
- package/dist/threads/use-rest-conversation-history.js.map +1 -1
- package/dist/threads/use-statewire-conversation-history.cjs +2 -16
- package/dist/threads/use-statewire-conversation-history.cjs.map +1 -1
- package/dist/threads/use-statewire-conversation-history.js +2 -16
- package/dist/threads/use-statewire-conversation-history.js.map +1 -1
- package/dist/toolkits/index.cjs +0 -7
- package/dist/toolkits/index.cjs.map +1 -1
- package/dist/toolkits/index.d.ts +0 -2
- package/dist/toolkits/index.js +0 -7
- package/dist/toolkits/index.js.map +1 -1
- package/dist/tools/index.cjs +4 -20
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.js +1 -17
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/misc-tool-uis.cjs +2 -17
- package/dist/tools/misc-tool-uis.cjs.map +1 -1
- package/dist/tools/misc-tool-uis.js +2 -17
- package/dist/tools/misc-tool-uis.js.map +1 -1
- package/dist/tools/primitives.cjs +1 -16
- package/dist/tools/primitives.cjs.map +1 -1
- package/dist/tools/primitives.js +1 -16
- package/dist/tools/primitives.js.map +1 -1
- package/dist/tools/tool-fallback.cjs +2 -17
- package/dist/tools/tool-fallback.cjs.map +1 -1
- package/dist/tools/tool-fallback.js +2 -17
- package/dist/tools/tool-fallback.js.map +1 -1
- package/dist/tools/voice-update-tool-ui.cjs +1 -17
- package/dist/tools/voice-update-tool-ui.cjs.map +1 -1
- package/dist/tools/voice-update-tool-ui.js +1 -17
- package/dist/tools/voice-update-tool-ui.js.map +1 -1
- package/package.json +1 -1
- package/dist/node_modules/qrcode-generator/dist/qrcode.cjs +0 -32
- package/dist/node_modules/qrcode-generator/dist/qrcode.cjs.map +0 -1
- package/dist/node_modules/qrcode-generator/dist/qrcode.js +0 -31
- package/dist/node_modules/qrcode-generator/dist/qrcode.js.map +0 -1
- package/dist/node_modules/zod/v4/classic/errors.cjs +0 -44
- package/dist/node_modules/zod/v4/classic/errors.cjs.map +0 -1
- package/dist/node_modules/zod/v4/classic/errors.js +0 -44
- package/dist/node_modules/zod/v4/classic/errors.js.map +0 -1
- package/dist/node_modules/zod/v4/classic/iso.cjs +0 -43
- package/dist/node_modules/zod/v4/classic/iso.cjs.map +0 -1
- package/dist/node_modules/zod/v4/classic/iso.js +0 -43
- package/dist/node_modules/zod/v4/classic/iso.js.map +0 -1
- package/dist/node_modules/zod/v4/classic/parse.cjs +0 -29
- package/dist/node_modules/zod/v4/classic/parse.cjs.map +0 -1
- package/dist/node_modules/zod/v4/classic/parse.js +0 -29
- package/dist/node_modules/zod/v4/classic/parse.js.map +0 -1
- package/dist/node_modules/zod/v4/classic/schemas.cjs +0 -871
- package/dist/node_modules/zod/v4/classic/schemas.cjs.map +0 -1
- package/dist/node_modules/zod/v4/classic/schemas.js +0 -871
- package/dist/node_modules/zod/v4/classic/schemas.js.map +0 -1
- package/dist/node_modules/zod/v4/core/api.cjs +0 -570
- package/dist/node_modules/zod/v4/core/api.cjs.map +0 -1
- package/dist/node_modules/zod/v4/core/api.js +0 -570
- package/dist/node_modules/zod/v4/core/api.js.map +0 -1
- package/dist/node_modules/zod/v4/core/checks.cjs +0 -411
- package/dist/node_modules/zod/v4/core/checks.cjs.map +0 -1
- package/dist/node_modules/zod/v4/core/checks.js +0 -411
- package/dist/node_modules/zod/v4/core/checks.js.map +0 -1
- package/dist/node_modules/zod/v4/core/core.cjs +0 -77
- package/dist/node_modules/zod/v4/core/core.cjs.map +0 -1
- package/dist/node_modules/zod/v4/core/core.js +0 -77
- package/dist/node_modules/zod/v4/core/core.js.map +0 -1
- package/dist/node_modules/zod/v4/core/doc.cjs +0 -38
- package/dist/node_modules/zod/v4/core/doc.cjs.map +0 -1
- package/dist/node_modules/zod/v4/core/doc.js +0 -38
- package/dist/node_modules/zod/v4/core/doc.js.map +0 -1
- package/dist/node_modules/zod/v4/core/errors.cjs +0 -76
- package/dist/node_modules/zod/v4/core/errors.cjs.map +0 -1
- package/dist/node_modules/zod/v4/core/errors.js +0 -76
- package/dist/node_modules/zod/v4/core/errors.js.map +0 -1
- package/dist/node_modules/zod/v4/core/json-schema-processors.cjs +0 -312
- package/dist/node_modules/zod/v4/core/json-schema-processors.cjs.map +0 -1
- package/dist/node_modules/zod/v4/core/json-schema-processors.js +0 -312
- package/dist/node_modules/zod/v4/core/json-schema-processors.js.map +0 -1
- package/dist/node_modules/zod/v4/core/parse.cjs +0 -96
- package/dist/node_modules/zod/v4/core/parse.cjs.map +0 -1
- package/dist/node_modules/zod/v4/core/parse.js +0 -96
- package/dist/node_modules/zod/v4/core/parse.js.map +0 -1
- package/dist/node_modules/zod/v4/core/regexes.cjs +0 -86
- package/dist/node_modules/zod/v4/core/regexes.cjs.map +0 -1
- package/dist/node_modules/zod/v4/core/regexes.js +0 -86
- package/dist/node_modules/zod/v4/core/regexes.js.map +0 -1
- package/dist/node_modules/zod/v4/core/registries.cjs +0 -52
- package/dist/node_modules/zod/v4/core/registries.cjs.map +0 -1
- package/dist/node_modules/zod/v4/core/registries.js +0 -52
- package/dist/node_modules/zod/v4/core/registries.js.map +0 -1
- package/dist/node_modules/zod/v4/core/schemas.cjs +0 -1412
- package/dist/node_modules/zod/v4/core/schemas.cjs.map +0 -1
- package/dist/node_modules/zod/v4/core/schemas.js +0 -1413
- package/dist/node_modules/zod/v4/core/schemas.js.map +0 -1
- package/dist/node_modules/zod/v4/core/to-json-schema.cjs +0 -370
- package/dist/node_modules/zod/v4/core/to-json-schema.cjs.map +0 -1
- package/dist/node_modules/zod/v4/core/to-json-schema.js +0 -370
- package/dist/node_modules/zod/v4/core/to-json-schema.js.map +0 -1
- package/dist/node_modules/zod/v4/core/util.cjs +0 -444
- package/dist/node_modules/zod/v4/core/util.cjs.map +0 -1
- package/dist/node_modules/zod/v4/core/util.js +0 -444
- package/dist/node_modules/zod/v4/core/util.js.map +0 -1
- package/dist/node_modules/zod/v4/core/versions.cjs +0 -9
- package/dist/node_modules/zod/v4/core/versions.cjs.map +0 -1
- package/dist/node_modules/zod/v4/core/versions.js +0 -9
- package/dist/node_modules/zod/v4/core/versions.js.map +0 -1
- package/dist/packages/agent-runtime/src/thread-handoff.cjs +0 -85
- package/dist/packages/agent-runtime/src/thread-handoff.cjs.map +0 -1
- package/dist/packages/agent-runtime/src/thread-handoff.js +0 -85
- package/dist/packages/agent-runtime/src/thread-handoff.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-timeline.cjs","sources":["../../../src/chat/super-grouping/activity-timeline.ts"],"sourcesContent":["/**\n * The assistant turn's activity timeline — the one derivation of \"what did\n * this turn do, and how did each step end\" behind the grouped\n * (\"conversational\") view on every surface: the SDK's `AthenaChat`, Olympus's\n * Spaces chat, and the Chrome extension. Pure functions over assistant-ui\n * message parts; `SuperGroupingCard` renders them.\n *\n * Step states come from the shared classifier (`classifyToolResult`) plus the\n * approval outcomes a part carries (`approval`, `interrupt`, a rejection\n * result), so a call that reads as failed, paused, or rejected on one surface\n * cannot read as a green check on another. Copy comes from the shared tool\n * display registry (`toolStatusLabel`).\n */\nimport type {\n MessageStatus,\n ThreadAssistantMessagePart,\n ToolCallMessagePartStatus,\n} from '@assistant-ui/react';\nimport {\n classifyToolResult,\n readRejectedToolResult,\n type ToolStatusLabelState,\n toolStatusLabel,\n} from '@athenaintel/agent-runtime';\nimport type { GroupingFunction } from './grouping-function';\n\nexport type ActivityToolState = ToolStatusLabelState;\n\nexport type ActivityItem =\n | {\n kind: 'reasoning';\n id?: string;\n text: string;\n state: 'running' | 'complete';\n }\n | {\n kind: 'tool';\n id?: string;\n toolName: string;\n args?: ToolCallPart['args'];\n state: ActivityToolState;\n };\n\n/** The turn as a whole: still working, parked on the person, ended in error, or done. */\nexport type ActivityPhase = 'running' | 'waiting' | 'complete' | 'error';\n\ntype ToolCallPart = Extract<ThreadAssistantMessagePart, { type: 'tool-call' }>;\n\nexport interface ActivityTimelineOptions {\n /**\n * Tools whose unresolved call means the turn is waiting on the person even\n * without an interrupt or approval on the part (the Chrome extension's\n * device plan approval, which the tool UI itself collects).\n */\n waitingTools?: ReadonlySet<string>;\n /**\n * Tools whose result is an application payload relayed verbatim (the Chrome\n * extension's page JavaScript), so a `success: false` flag counts only with\n * an error detail — see `classifyToolResult`'s `passThroughPayload`.\n */\n passThroughTools?: ReadonlySet<string>;\n}\n\nconst NO_TOOLS: ReadonlySet<string> = new Set();\n\nfunction toolCallStatus(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n): ToolCallMessagePartStatus | undefined {\n if (part.result !== undefined) return { type: 'complete' };\n if (messageStatus?.type === 'incomplete') {\n return {\n type: 'incomplete',\n reason: messageStatus.reason === 'tool-calls' ? 'other' : messageStatus.reason,\n error: messageStatus.error,\n };\n }\n if (messageStatus?.type === 'complete') return { type: 'complete' };\n if (messageStatus?.type === 'requires-action') {\n return { type: 'requires-action', reason: messageStatus.reason };\n }\n if (messageStatus?.type === 'running') return { type: 'running' };\n return undefined;\n}\n\n/** How one tool call ended (or is going), reading the approval fields before the result. */\nexport function getActivityToolState(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n { waitingTools = NO_TOOLS, passThroughTools = NO_TOOLS }: ActivityTimelineOptions = {},\n): ActivityToolState {\n if (part.approval?.approved === false || readRejectedToolResult(part.result) !== null) {\n return 'rejected';\n }\n if (part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired') {\n return 'cancelled';\n }\n const unresolved = part.result === undefined;\n const messageIsActive =\n messageStatus === undefined ||\n messageStatus.type === 'running' ||\n messageStatus.type === 'requires-action';\n if (\n unresolved &&\n (part.interrupt?.type === 'human' ||\n (part.approval !== undefined &&\n part.approval.approved === undefined &&\n part.approval.resolution === undefined) ||\n (waitingTools.has(part.toolName) && messageIsActive))\n ) {\n return 'waiting';\n }\n\n const classification = classifyToolResult({\n status: toolCallStatus(part, messageStatus),\n result: part.result,\n isError: part.isError,\n passThroughPayload: passThroughTools.has(part.toolName),\n });\n if (classification.state === 'requires-action') return 'waiting';\n return classification.state;\n}\n\n/**\n * The compact reasoning/tool timeline in the order the parts streamed.\n *\n * A reasoning part is still streaming only while it is the final part of a\n * running message — once any later part appears, the thought has settled.\n * Settled reasoning parts with no text are dropped so the list never shows an\n * empty thinking row.\n */\nexport function buildActivityTimeline(\n content: readonly ThreadAssistantMessagePart[] | undefined,\n messageStatus: MessageStatus | undefined,\n options: ActivityTimelineOptions = {},\n): ActivityItem[] {\n if (!content?.length) return [];\n\n const lastPartIndex = content.length - 1;\n const timeline: ActivityItem[] = [];\n for (let index = 0; index < content.length; index += 1) {\n const part = content[index];\n if (part.type === 'tool-call') {\n timeline.push({\n kind: 'tool',\n id: part.toolCallId,\n args: part.args,\n toolName: part.toolName,\n state: getActivityToolState(part, messageStatus, options),\n });\n continue;\n }\n if (part.type !== 'reasoning') continue;\n\n const text = typeof part.text === 'string' ? part.text : '';\n const stillStreaming = messageStatus?.type === 'running' && index === lastPartIndex;\n if (!stillStreaming && text.trim() === '') continue;\n timeline.push({\n kind: 'reasoning',\n id: `reasoning-${index}`,\n text,\n state: stillStreaming ? 'running' : 'complete',\n });\n }\n return timeline;\n}\n\n/** Number of tool calls in the timeline. */\nexport function countActivityTools(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => (item.kind === 'tool' ? count + 1 : count), 0);\n}\n\n/**\n * The turn's phase. Waiting on the person wins over everything — a\n * `requires-action` status, a waiting tool, or a host's own `waitingForInput`\n * assertion (no in-repo host passes one) — then the message's own status.\n */\nexport function resolveActivityPhase(\n status: MessageStatus | undefined,\n timeline: readonly ActivityItem[],\n { waitingForInput = false }: { waitingForInput?: boolean } = {},\n): ActivityPhase {\n if (\n waitingForInput ||\n status?.type === 'requires-action' ||\n timeline.some((item) => item.kind === 'tool' && item.state === 'waiting')\n ) {\n return 'waiting';\n }\n if (status?.type === 'running') return 'running';\n if (status?.type === 'incomplete') return 'error';\n return 'complete';\n}\n\n/**\n * The status-row copy for one step. `resolveToolDisplayName` lets a host with\n * a richer tool catalog name tools the shared registry has no entry for.\n */\nexport function getActivityItemLabel(\n item: ActivityItem,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n): string {\n if (item.kind === 'reasoning') {\n return item.state === 'running' ? 'Thinking' : 'Thought through the next step';\n }\n return toolStatusLabel(item.toolName, item.state, resolveToolDisplayName?.(item.toolName));\n}\n\n/** The collapsed-card summary of a finished turn. */\nexport function getActivitySummary(timeline: readonly ActivityItem[]): string {\n const toolCount = countActivityTools(timeline);\n const hasIssue = timeline.some(\n (item) => item.kind === 'tool' && (item.state === 'error' || item.state === 'rejected'),\n );\n if (hasIssue) return 'Completed with issues';\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'cancelled')) {\n return 'Action cancelled';\n }\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'paused')) {\n return 'Paused during tool use';\n }\n if (toolCount > 0) return `Used ${toolCount} ${toolCount === 1 ? 'tool' : 'tools'}`;\n return 'Reasoning complete';\n}\n\n/** The part shape the final-text read needs; any message role's parts satisfy it. */\nexport type FinalTextPart = { readonly type: string; readonly text?: string };\n\n/**\n * The visible answer of a grouped turn: the text after the final tool call,\n * or all of it when the turn never called a tool. Intermediate text (before\n * or between tool calls) stays available in the details panel.\n */\nexport function getFinalText(content: readonly FinalTextPart[] | undefined): string | null {\n if (!content?.length) return null;\n\n let lastToolIndex = -1;\n for (let index = content.length - 1; index >= 0; index -= 1) {\n if (content[index]?.type === 'tool-call') {\n lastToolIndex = index;\n break;\n }\n }\n\n const texts: string[] = [];\n for (let index = lastToolIndex + 1; index < content.length; index += 1) {\n const part = content[index];\n if (part?.type === 'text' && part.text) texts.push(part.text);\n }\n return texts.length > 0 ? texts.join('\\n\\n') : null;\n}\n\n/**\n * Keep the final answer out of the details panel: it renders below the card\n * (`SuperGroupingFinalText`), so the details grouping drops every text part\n * after the last tool call and any group that becomes empty.\n */\nexport function excludeFinalTextFromGroups(grouping: GroupingFunction): GroupingFunction {\n return (parts) => {\n const lastToolIndex = parts.findLastIndex((part) => part?.type === 'tool-call');\n return grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => parts[index]?.type !== 'text' || index <= lastToolIndex),\n }))\n .filter((group) => group.indices.length > 0);\n };\n}\n"],"names":["readRejectedToolResult","classifyToolResult","toolStatusLabel"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"activity-timeline.cjs","sources":["../../../src/chat/super-grouping/activity-timeline.ts"],"sourcesContent":["/**\n * The assistant turn's activity timeline — the one derivation of \"what did\n * this turn do, and how did each step end\" behind the grouped\n * (\"conversational\") view on every surface: the SDK's `AthenaChat`, Olympus's\n * Spaces chat, and the Chrome extension. Pure functions over assistant-ui\n * message parts; `SuperGroupingCard` renders them.\n *\n * Step states come from the shared classifier (`classifyToolResult`) plus the\n * approval outcomes a part carries (`approval`, `interrupt`, a rejection\n * result), so a call that reads as failed, paused, or rejected on one surface\n * cannot read as a green check on another. Copy comes from the shared tool\n * display registry (`toolStatusLabel`).\n */\nimport type {\n MessageStatus,\n ThreadAssistantMessagePart,\n ToolCallMessagePartStatus,\n} from '@assistant-ui/react';\nimport {\n classifyToolResult,\n readRejectedToolResult,\n type ToolStatusLabelState,\n toolStatusLabel,\n} from '@athenaintel/agent-runtime';\nimport type { GroupingFunction } from './grouping-function';\n\nexport type ActivityToolState = ToolStatusLabelState;\n\nexport type ActivityItem =\n | {\n kind: 'reasoning';\n id?: string;\n text: string;\n state: 'running' | 'complete';\n }\n | {\n kind: 'tool';\n id?: string;\n toolName: string;\n args?: ToolCallPart['args'];\n state: ActivityToolState;\n };\n\n/** The turn as a whole: still working, parked on the person, ended in error, or done. */\nexport type ActivityPhase = 'running' | 'waiting' | 'complete' | 'error';\n\ntype ToolCallPart = Extract<ThreadAssistantMessagePart, { type: 'tool-call' }>;\n\nexport interface ActivityTimelineOptions {\n /**\n * Tools whose unresolved call means the turn is waiting on the person even\n * without an interrupt or approval on the part (the Chrome extension's\n * device plan approval, which the tool UI itself collects).\n */\n waitingTools?: ReadonlySet<string>;\n /**\n * Tools whose result is an application payload relayed verbatim (the Chrome\n * extension's page JavaScript), so a `success: false` flag counts only with\n * an error detail — see `classifyToolResult`'s `passThroughPayload`.\n */\n passThroughTools?: ReadonlySet<string>;\n}\n\nconst NO_TOOLS: ReadonlySet<string> = new Set();\n\nfunction toolCallStatus(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n): ToolCallMessagePartStatus | undefined {\n if (part.result !== undefined) return { type: 'complete' };\n if (messageStatus?.type === 'incomplete') {\n return {\n type: 'incomplete',\n reason: messageStatus.reason === 'tool-calls' ? 'other' : messageStatus.reason,\n error: messageStatus.error,\n };\n }\n if (messageStatus?.type === 'complete') return { type: 'complete' };\n if (messageStatus?.type === 'requires-action') {\n return { type: 'requires-action', reason: messageStatus.reason };\n }\n if (messageStatus?.type === 'running') return { type: 'running' };\n return undefined;\n}\n\n/** How one tool call ended (or is going), reading the approval fields before the result. */\nexport function getActivityToolState(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n { waitingTools = NO_TOOLS, passThroughTools = NO_TOOLS }: ActivityTimelineOptions = {},\n): ActivityToolState {\n if (part.approval?.approved === false || readRejectedToolResult(part.result) !== null) {\n return 'rejected';\n }\n if (part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired') {\n return 'cancelled';\n }\n const unresolved = part.result === undefined;\n const messageIsActive =\n messageStatus === undefined ||\n messageStatus.type === 'running' ||\n messageStatus.type === 'requires-action';\n if (\n unresolved &&\n (part.interrupt?.type === 'human' ||\n (part.approval !== undefined &&\n part.approval.approved === undefined &&\n part.approval.resolution === undefined) ||\n (waitingTools.has(part.toolName) && messageIsActive))\n ) {\n return 'waiting';\n }\n\n const classification = classifyToolResult({\n status: toolCallStatus(part, messageStatus),\n result: part.result,\n isError: part.isError,\n passThroughPayload: passThroughTools.has(part.toolName),\n });\n if (classification.state === 'requires-action') return 'waiting';\n return classification.state;\n}\n\n/**\n * The compact reasoning/tool timeline in the order the parts streamed.\n *\n * A reasoning part is still streaming only while it is the final part of a\n * running message — once any later part appears, the thought has settled.\n * Settled reasoning parts with no text are dropped so the list never shows an\n * empty thinking row.\n */\nexport function buildActivityTimeline(\n content: readonly ThreadAssistantMessagePart[] | undefined,\n messageStatus: MessageStatus | undefined,\n options: ActivityTimelineOptions = {},\n): ActivityItem[] {\n if (!content?.length) return [];\n\n const lastPartIndex = content.length - 1;\n const timeline: ActivityItem[] = [];\n for (let index = 0; index < content.length; index += 1) {\n const part = content[index];\n if (part.type === 'tool-call') {\n timeline.push({\n kind: 'tool',\n id: part.toolCallId,\n args: part.args,\n toolName: part.toolName,\n state: getActivityToolState(part, messageStatus, options),\n });\n continue;\n }\n if (part.type !== 'reasoning') continue;\n\n const text = typeof part.text === 'string' ? part.text : '';\n const stillStreaming = messageStatus?.type === 'running' && index === lastPartIndex;\n if (!stillStreaming && text.trim() === '') continue;\n timeline.push({\n kind: 'reasoning',\n id: `reasoning-${index}`,\n text,\n state: stillStreaming ? 'running' : 'complete',\n });\n }\n return timeline;\n}\n\n/** Number of tool calls in the timeline. */\nexport function countActivityTools(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => (item.kind === 'tool' ? count + 1 : count), 0);\n}\n\n/**\n * The turn's phase. Waiting on the person wins over everything — a\n * `requires-action` status, a waiting tool, or a host's own `waitingForInput`\n * assertion (no in-repo host passes one) — then the message's own status.\n */\nexport function resolveActivityPhase(\n status: MessageStatus | undefined,\n timeline: readonly ActivityItem[],\n { waitingForInput = false }: { waitingForInput?: boolean } = {},\n): ActivityPhase {\n if (\n waitingForInput ||\n status?.type === 'requires-action' ||\n timeline.some((item) => item.kind === 'tool' && item.state === 'waiting')\n ) {\n return 'waiting';\n }\n if (status?.type === 'running') return 'running';\n if (status?.type === 'incomplete') return 'error';\n return 'complete';\n}\n\n/**\n * The status-row copy for one step. `resolveToolDisplayName` lets a host with\n * a richer tool catalog name tools the shared registry has no entry for.\n */\nexport function getActivityItemLabel(\n item: ActivityItem,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n): string {\n if (item.kind === 'reasoning') {\n return item.state === 'running' ? 'Thinking' : 'Thought through the next step';\n }\n return toolStatusLabel(item.toolName, item.state, resolveToolDisplayName?.(item.toolName));\n}\n\n/** The collapsed-card summary of a finished turn. */\nexport function getActivitySummary(timeline: readonly ActivityItem[]): string {\n const toolCount = countActivityTools(timeline);\n const hasIssue = timeline.some(\n (item) => item.kind === 'tool' && (item.state === 'error' || item.state === 'rejected'),\n );\n if (hasIssue) return 'Completed with issues';\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'cancelled')) {\n return 'Action cancelled';\n }\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'paused')) {\n return 'Paused during tool use';\n }\n if (toolCount > 0) return `Used ${toolCount} ${toolCount === 1 ? 'tool' : 'tools'}`;\n return 'Reasoning complete';\n}\n\n/** The part shape the final-text read needs; any message role's parts satisfy it. */\nexport type FinalTextPart = { readonly type: string; readonly text?: string };\n\n/**\n * The visible answer of a grouped turn: the text after the final tool call,\n * or all of it when the turn never called a tool. Intermediate text (before\n * or between tool calls) stays available in the details panel.\n */\nexport function getFinalText(content: readonly FinalTextPart[] | undefined): string | null {\n if (!content?.length) return null;\n\n let lastToolIndex = -1;\n for (let index = content.length - 1; index >= 0; index -= 1) {\n if (content[index]?.type === 'tool-call') {\n lastToolIndex = index;\n break;\n }\n }\n\n const texts: string[] = [];\n for (let index = lastToolIndex + 1; index < content.length; index += 1) {\n const part = content[index];\n if (part?.type === 'text' && part.text) texts.push(part.text);\n }\n return texts.length > 0 ? texts.join('\\n\\n') : null;\n}\n\n/**\n * Keep the final answer out of the details panel: it renders below the card\n * (`SuperGroupingFinalText`), so the details grouping drops every text part\n * after the last tool call and any group that becomes empty.\n */\nexport function excludeFinalTextFromGroups(grouping: GroupingFunction): GroupingFunction {\n return (parts) => {\n const lastToolIndex = parts.findLastIndex((part) => part?.type === 'tool-call');\n return grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => parts[index]?.type !== 'text' || index <= lastToolIndex),\n }))\n .filter((group) => group.indices.length > 0);\n };\n}\n"],"names":["readRejectedToolResult","classifyToolResult","toolStatusLabel"],"mappings":"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"}
|
|
@@ -1,21 +1,5 @@
|
|
|
1
|
-
import "../../packages/agent-runtime/src/generated/runconfig-contract.js";
|
|
2
|
-
import "react";
|
|
3
|
-
import "@assistant-ui/tap";
|
|
4
|
-
import "statewire";
|
|
5
|
-
import "../../packages/agent-runtime/src/statewire-suspended.js";
|
|
6
|
-
import "../../packages/agent-runtime/src/conversation-list.js";
|
|
7
1
|
import { toolStatusLabel } from "../../packages/agent-runtime/src/tool-metadata.js";
|
|
8
2
|
import { readRejectedToolResult, classifyToolResult } from "../../packages/agent-runtime/src/tool-result.js";
|
|
9
|
-
import "@tanstack/react-query";
|
|
10
|
-
import "../../packages/agent-runtime/src/statewire-state.js";
|
|
11
|
-
import "../../packages/agent-runtime/src/messages.js";
|
|
12
|
-
import "@assistant-ui/store";
|
|
13
|
-
import "../../packages/agent-runtime/src/quota-safe-local-storage-session.js";
|
|
14
|
-
import "../../packages/agent-runtime/src/statewire-attach-observer.js";
|
|
15
|
-
import "../../packages/agent-runtime/src/thread-status.js";
|
|
16
|
-
import "@assistant-ui/react-statewire";
|
|
17
|
-
import "@assistant-ui/core";
|
|
18
|
-
import "../../packages/agent-runtime/src/thread-handoff.js";
|
|
19
3
|
const NO_TOOLS = /* @__PURE__ */ new Set();
|
|
20
4
|
function toolCallStatus(part, messageStatus) {
|
|
21
5
|
if (part.result !== void 0) return { type: "complete" };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-timeline.js","sources":["../../../src/chat/super-grouping/activity-timeline.ts"],"sourcesContent":["/**\n * The assistant turn's activity timeline — the one derivation of \"what did\n * this turn do, and how did each step end\" behind the grouped\n * (\"conversational\") view on every surface: the SDK's `AthenaChat`, Olympus's\n * Spaces chat, and the Chrome extension. Pure functions over assistant-ui\n * message parts; `SuperGroupingCard` renders them.\n *\n * Step states come from the shared classifier (`classifyToolResult`) plus the\n * approval outcomes a part carries (`approval`, `interrupt`, a rejection\n * result), so a call that reads as failed, paused, or rejected on one surface\n * cannot read as a green check on another. Copy comes from the shared tool\n * display registry (`toolStatusLabel`).\n */\nimport type {\n MessageStatus,\n ThreadAssistantMessagePart,\n ToolCallMessagePartStatus,\n} from '@assistant-ui/react';\nimport {\n classifyToolResult,\n readRejectedToolResult,\n type ToolStatusLabelState,\n toolStatusLabel,\n} from '@athenaintel/agent-runtime';\nimport type { GroupingFunction } from './grouping-function';\n\nexport type ActivityToolState = ToolStatusLabelState;\n\nexport type ActivityItem =\n | {\n kind: 'reasoning';\n id?: string;\n text: string;\n state: 'running' | 'complete';\n }\n | {\n kind: 'tool';\n id?: string;\n toolName: string;\n args?: ToolCallPart['args'];\n state: ActivityToolState;\n };\n\n/** The turn as a whole: still working, parked on the person, ended in error, or done. */\nexport type ActivityPhase = 'running' | 'waiting' | 'complete' | 'error';\n\ntype ToolCallPart = Extract<ThreadAssistantMessagePart, { type: 'tool-call' }>;\n\nexport interface ActivityTimelineOptions {\n /**\n * Tools whose unresolved call means the turn is waiting on the person even\n * without an interrupt or approval on the part (the Chrome extension's\n * device plan approval, which the tool UI itself collects).\n */\n waitingTools?: ReadonlySet<string>;\n /**\n * Tools whose result is an application payload relayed verbatim (the Chrome\n * extension's page JavaScript), so a `success: false` flag counts only with\n * an error detail — see `classifyToolResult`'s `passThroughPayload`.\n */\n passThroughTools?: ReadonlySet<string>;\n}\n\nconst NO_TOOLS: ReadonlySet<string> = new Set();\n\nfunction toolCallStatus(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n): ToolCallMessagePartStatus | undefined {\n if (part.result !== undefined) return { type: 'complete' };\n if (messageStatus?.type === 'incomplete') {\n return {\n type: 'incomplete',\n reason: messageStatus.reason === 'tool-calls' ? 'other' : messageStatus.reason,\n error: messageStatus.error,\n };\n }\n if (messageStatus?.type === 'complete') return { type: 'complete' };\n if (messageStatus?.type === 'requires-action') {\n return { type: 'requires-action', reason: messageStatus.reason };\n }\n if (messageStatus?.type === 'running') return { type: 'running' };\n return undefined;\n}\n\n/** How one tool call ended (or is going), reading the approval fields before the result. */\nexport function getActivityToolState(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n { waitingTools = NO_TOOLS, passThroughTools = NO_TOOLS }: ActivityTimelineOptions = {},\n): ActivityToolState {\n if (part.approval?.approved === false || readRejectedToolResult(part.result) !== null) {\n return 'rejected';\n }\n if (part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired') {\n return 'cancelled';\n }\n const unresolved = part.result === undefined;\n const messageIsActive =\n messageStatus === undefined ||\n messageStatus.type === 'running' ||\n messageStatus.type === 'requires-action';\n if (\n unresolved &&\n (part.interrupt?.type === 'human' ||\n (part.approval !== undefined &&\n part.approval.approved === undefined &&\n part.approval.resolution === undefined) ||\n (waitingTools.has(part.toolName) && messageIsActive))\n ) {\n return 'waiting';\n }\n\n const classification = classifyToolResult({\n status: toolCallStatus(part, messageStatus),\n result: part.result,\n isError: part.isError,\n passThroughPayload: passThroughTools.has(part.toolName),\n });\n if (classification.state === 'requires-action') return 'waiting';\n return classification.state;\n}\n\n/**\n * The compact reasoning/tool timeline in the order the parts streamed.\n *\n * A reasoning part is still streaming only while it is the final part of a\n * running message — once any later part appears, the thought has settled.\n * Settled reasoning parts with no text are dropped so the list never shows an\n * empty thinking row.\n */\nexport function buildActivityTimeline(\n content: readonly ThreadAssistantMessagePart[] | undefined,\n messageStatus: MessageStatus | undefined,\n options: ActivityTimelineOptions = {},\n): ActivityItem[] {\n if (!content?.length) return [];\n\n const lastPartIndex = content.length - 1;\n const timeline: ActivityItem[] = [];\n for (let index = 0; index < content.length; index += 1) {\n const part = content[index];\n if (part.type === 'tool-call') {\n timeline.push({\n kind: 'tool',\n id: part.toolCallId,\n args: part.args,\n toolName: part.toolName,\n state: getActivityToolState(part, messageStatus, options),\n });\n continue;\n }\n if (part.type !== 'reasoning') continue;\n\n const text = typeof part.text === 'string' ? part.text : '';\n const stillStreaming = messageStatus?.type === 'running' && index === lastPartIndex;\n if (!stillStreaming && text.trim() === '') continue;\n timeline.push({\n kind: 'reasoning',\n id: `reasoning-${index}`,\n text,\n state: stillStreaming ? 'running' : 'complete',\n });\n }\n return timeline;\n}\n\n/** Number of tool calls in the timeline. */\nexport function countActivityTools(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => (item.kind === 'tool' ? count + 1 : count), 0);\n}\n\n/**\n * The turn's phase. Waiting on the person wins over everything — a\n * `requires-action` status, a waiting tool, or a host's own `waitingForInput`\n * assertion (no in-repo host passes one) — then the message's own status.\n */\nexport function resolveActivityPhase(\n status: MessageStatus | undefined,\n timeline: readonly ActivityItem[],\n { waitingForInput = false }: { waitingForInput?: boolean } = {},\n): ActivityPhase {\n if (\n waitingForInput ||\n status?.type === 'requires-action' ||\n timeline.some((item) => item.kind === 'tool' && item.state === 'waiting')\n ) {\n return 'waiting';\n }\n if (status?.type === 'running') return 'running';\n if (status?.type === 'incomplete') return 'error';\n return 'complete';\n}\n\n/**\n * The status-row copy for one step. `resolveToolDisplayName` lets a host with\n * a richer tool catalog name tools the shared registry has no entry for.\n */\nexport function getActivityItemLabel(\n item: ActivityItem,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n): string {\n if (item.kind === 'reasoning') {\n return item.state === 'running' ? 'Thinking' : 'Thought through the next step';\n }\n return toolStatusLabel(item.toolName, item.state, resolveToolDisplayName?.(item.toolName));\n}\n\n/** The collapsed-card summary of a finished turn. */\nexport function getActivitySummary(timeline: readonly ActivityItem[]): string {\n const toolCount = countActivityTools(timeline);\n const hasIssue = timeline.some(\n (item) => item.kind === 'tool' && (item.state === 'error' || item.state === 'rejected'),\n );\n if (hasIssue) return 'Completed with issues';\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'cancelled')) {\n return 'Action cancelled';\n }\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'paused')) {\n return 'Paused during tool use';\n }\n if (toolCount > 0) return `Used ${toolCount} ${toolCount === 1 ? 'tool' : 'tools'}`;\n return 'Reasoning complete';\n}\n\n/** The part shape the final-text read needs; any message role's parts satisfy it. */\nexport type FinalTextPart = { readonly type: string; readonly text?: string };\n\n/**\n * The visible answer of a grouped turn: the text after the final tool call,\n * or all of it when the turn never called a tool. Intermediate text (before\n * or between tool calls) stays available in the details panel.\n */\nexport function getFinalText(content: readonly FinalTextPart[] | undefined): string | null {\n if (!content?.length) return null;\n\n let lastToolIndex = -1;\n for (let index = content.length - 1; index >= 0; index -= 1) {\n if (content[index]?.type === 'tool-call') {\n lastToolIndex = index;\n break;\n }\n }\n\n const texts: string[] = [];\n for (let index = lastToolIndex + 1; index < content.length; index += 1) {\n const part = content[index];\n if (part?.type === 'text' && part.text) texts.push(part.text);\n }\n return texts.length > 0 ? texts.join('\\n\\n') : null;\n}\n\n/**\n * Keep the final answer out of the details panel: it renders below the card\n * (`SuperGroupingFinalText`), so the details grouping drops every text part\n * after the last tool call and any group that becomes empty.\n */\nexport function excludeFinalTextFromGroups(grouping: GroupingFunction): GroupingFunction {\n return (parts) => {\n const lastToolIndex = parts.findLastIndex((part) => part?.type === 'tool-call');\n return grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => parts[index]?.type !== 'text' || index <= lastToolIndex),\n }))\n .filter((group) => group.indices.length > 0);\n };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AA+DA,MAAM,+BAAoC,IAAA;AAE1C,SAAS,eACP,MACA,eACuC;AACvC,MAAI,KAAK,WAAW,OAAW,QAAO,EAAE,MAAM,WAAA;AAC9C,OAAI,+CAAe,UAAS,cAAc;AACxC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ,cAAc,WAAW,eAAe,UAAU,cAAc;AAAA,MACxE,OAAO,cAAc;AAAA,IAAA;AAAA,EAEzB;AACA,OAAI,+CAAe,UAAS,WAAY,QAAO,EAAE,MAAM,WAAA;AACvD,OAAI,+CAAe,UAAS,mBAAmB;AAC7C,WAAO,EAAE,MAAM,mBAAmB,QAAQ,cAAc,OAAA;AAAA,EAC1D;AACA,OAAI,+CAAe,UAAS,UAAW,QAAO,EAAE,MAAM,UAAA;AACtD,SAAO;AACT;AAGO,SAAS,qBACd,MACA,eACA,EAAE,eAAe,UAAU,mBAAmB,SAAA,IAAsC,IACjE;;AACnB,QAAI,UAAK,aAAL,mBAAe,cAAa,SAAS,uBAAuB,KAAK,MAAM,MAAM,MAAM;AACrF,WAAO;AAAA,EACT;AACA,QAAI,UAAK,aAAL,mBAAe,gBAAe,iBAAe,UAAK,aAAL,mBAAe,gBAAe,WAAW;AACxF,WAAO;AAAA,EACT;AACA,QAAM,aAAa,KAAK,WAAW;AACnC,QAAM,kBACJ,kBAAkB,UAClB,cAAc,SAAS,aACvB,cAAc,SAAS;AACzB,MACE,iBACC,UAAK,cAAL,mBAAgB,UAAS,WACvB,KAAK,aAAa,UACjB,KAAK,SAAS,aAAa,UAC3B,KAAK,SAAS,eAAe,UAC9B,aAAa,IAAI,KAAK,QAAQ,KAAK,kBACtC;AACA,WAAO;AAAA,EACT;AAEA,QAAM,iBAAiB,mBAAmB;AAAA,IACxC,QAAQ,eAAe,MAAM,aAAa;AAAA,IAC1C,QAAQ,KAAK;AAAA,IACb,SAAS,KAAK;AAAA,IACd,oBAAoB,iBAAiB,IAAI,KAAK,QAAQ;AAAA,EAAA,CACvD;AACD,MAAI,eAAe,UAAU,kBAAmB,QAAO;AACvD,SAAO,eAAe;AACxB;AAUO,SAAS,sBACd,SACA,eACA,UAAmC,CAAA,GACnB;AAChB,MAAI,EAAC,mCAAS,QAAQ,QAAO,CAAA;AAE7B,QAAM,gBAAgB,QAAQ,SAAS;AACvC,QAAM,WAA2B,CAAA;AACjC,WAAS,QAAQ,GAAG,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtD,UAAM,OAAO,QAAQ,KAAK;AAC1B,QAAI,KAAK,SAAS,aAAa;AAC7B,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,OAAO,qBAAqB,MAAM,eAAe,OAAO;AAAA,MAAA,CACzD;AACD;AAAA,IACF;AACA,QAAI,KAAK,SAAS,YAAa;AAE/B,UAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AACzD,UAAM,kBAAiB,+CAAe,UAAS,aAAa,UAAU;AACtE,QAAI,CAAC,kBAAkB,KAAK,KAAA,MAAW,GAAI;AAC3C,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,IAAI,aAAa,KAAK;AAAA,MACtB;AAAA,MACA,OAAO,iBAAiB,YAAY;AAAA,IAAA,CACrC;AAAA,EACH;AACA,SAAO;AACT;AAGO,SAAS,mBAAmB,UAA2C;AAC5E,SAAO,SAAS,OAAO,CAAC,OAAO,SAAU,KAAK,SAAS,SAAS,QAAQ,IAAI,OAAQ,CAAC;AACvF;AAOO,SAAS,qBACd,QACA,UACA,EAAE,kBAAkB,MAAA,IAAyC,IAC9C;AACf,MACE,oBACA,iCAAQ,UAAS,qBACjB,SAAS,KAAK,CAAC,SAAS,KAAK,SAAS,UAAU,KAAK,UAAU,SAAS,GACxE;AACA,WAAO;AAAA,EACT;AACA,OAAI,iCAAQ,UAAS,UAAW,QAAO;AACvC,OAAI,iCAAQ,UAAS,aAAc,QAAO;AAC1C,SAAO;AACT;AAMO,SAAS,qBACd,MACA,wBACQ;AACR,MAAI,KAAK,SAAS,aAAa;AAC7B,WAAO,KAAK,UAAU,YAAY,aAAa;AAAA,EACjD;AACA,SAAO,gBAAgB,KAAK,UAAU,KAAK,OAAO,iEAAyB,KAAK,SAAS;AAC3F;AAGO,SAAS,mBAAmB,UAA2C;AAC5E,QAAM,YAAY,mBAAmB,QAAQ;AAC7C,QAAM,WAAW,SAAS;AAAA,IACxB,CAAC,SAAS,KAAK,SAAS,WAAW,KAAK,UAAU,WAAW,KAAK,UAAU;AAAA,EAAA;AAE9E,MAAI,SAAU,QAAO;AACrB,MAAI,SAAS,KAAK,CAAC,SAAS,KAAK,SAAS,UAAU,KAAK,UAAU,WAAW,GAAG;AAC/E,WAAO;AAAA,EACT;AACA,MAAI,SAAS,KAAK,CAAC,SAAS,KAAK,SAAS,UAAU,KAAK,UAAU,QAAQ,GAAG;AAC5E,WAAO;AAAA,EACT;AACA,MAAI,YAAY,EAAG,QAAO,QAAQ,SAAS,IAAI,cAAc,IAAI,SAAS,OAAO;AACjF,SAAO;AACT;AAUO,SAAS,aAAa,SAA8D;;AACzF,MAAI,EAAC,mCAAS,QAAQ,QAAO;AAE7B,MAAI,gBAAgB;AACpB,WAAS,QAAQ,QAAQ,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AAC3D,UAAI,aAAQ,KAAK,MAAb,mBAAgB,UAAS,aAAa;AACxC,sBAAgB;AAChB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAkB,CAAA;AACxB,WAAS,QAAQ,gBAAgB,GAAG,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtE,UAAM,OAAO,QAAQ,KAAK;AAC1B,SAAI,6BAAM,UAAS,UAAU,KAAK,KAAM,OAAM,KAAK,KAAK,IAAI;AAAA,EAC9D;AACA,SAAO,MAAM,SAAS,IAAI,MAAM,KAAK,MAAM,IAAI;AACjD;AAOO,SAAS,2BAA2B,UAA8C;AACvF,SAAO,CAAC,UAAU;AAChB,UAAM,gBAAgB,MAAM,cAAc,CAAC,UAAS,6BAAM,UAAS,WAAW;AAC9E,WAAO,SAAS,KAAK,EAClB,IAAI,CAAC,WAAW;AAAA,MACf,GAAG;AAAA,MACH,SAAS,MAAM,QAAQ,OAAO,CAAC,UAAA;;AAAU,4BAAM,KAAK,MAAX,mBAAc,UAAS,UAAU,SAAS;AAAA,OAAa;AAAA,IAAA,EAChG,EACD,OAAO,CAAC,UAAU,MAAM,QAAQ,SAAS,CAAC;AAAA,EAC/C;AACF;"}
|
|
1
|
+
{"version":3,"file":"activity-timeline.js","sources":["../../../src/chat/super-grouping/activity-timeline.ts"],"sourcesContent":["/**\n * The assistant turn's activity timeline — the one derivation of \"what did\n * this turn do, and how did each step end\" behind the grouped\n * (\"conversational\") view on every surface: the SDK's `AthenaChat`, Olympus's\n * Spaces chat, and the Chrome extension. Pure functions over assistant-ui\n * message parts; `SuperGroupingCard` renders them.\n *\n * Step states come from the shared classifier (`classifyToolResult`) plus the\n * approval outcomes a part carries (`approval`, `interrupt`, a rejection\n * result), so a call that reads as failed, paused, or rejected on one surface\n * cannot read as a green check on another. Copy comes from the shared tool\n * display registry (`toolStatusLabel`).\n */\nimport type {\n MessageStatus,\n ThreadAssistantMessagePart,\n ToolCallMessagePartStatus,\n} from '@assistant-ui/react';\nimport {\n classifyToolResult,\n readRejectedToolResult,\n type ToolStatusLabelState,\n toolStatusLabel,\n} from '@athenaintel/agent-runtime';\nimport type { GroupingFunction } from './grouping-function';\n\nexport type ActivityToolState = ToolStatusLabelState;\n\nexport type ActivityItem =\n | {\n kind: 'reasoning';\n id?: string;\n text: string;\n state: 'running' | 'complete';\n }\n | {\n kind: 'tool';\n id?: string;\n toolName: string;\n args?: ToolCallPart['args'];\n state: ActivityToolState;\n };\n\n/** The turn as a whole: still working, parked on the person, ended in error, or done. */\nexport type ActivityPhase = 'running' | 'waiting' | 'complete' | 'error';\n\ntype ToolCallPart = Extract<ThreadAssistantMessagePart, { type: 'tool-call' }>;\n\nexport interface ActivityTimelineOptions {\n /**\n * Tools whose unresolved call means the turn is waiting on the person even\n * without an interrupt or approval on the part (the Chrome extension's\n * device plan approval, which the tool UI itself collects).\n */\n waitingTools?: ReadonlySet<string>;\n /**\n * Tools whose result is an application payload relayed verbatim (the Chrome\n * extension's page JavaScript), so a `success: false` flag counts only with\n * an error detail — see `classifyToolResult`'s `passThroughPayload`.\n */\n passThroughTools?: ReadonlySet<string>;\n}\n\nconst NO_TOOLS: ReadonlySet<string> = new Set();\n\nfunction toolCallStatus(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n): ToolCallMessagePartStatus | undefined {\n if (part.result !== undefined) return { type: 'complete' };\n if (messageStatus?.type === 'incomplete') {\n return {\n type: 'incomplete',\n reason: messageStatus.reason === 'tool-calls' ? 'other' : messageStatus.reason,\n error: messageStatus.error,\n };\n }\n if (messageStatus?.type === 'complete') return { type: 'complete' };\n if (messageStatus?.type === 'requires-action') {\n return { type: 'requires-action', reason: messageStatus.reason };\n }\n if (messageStatus?.type === 'running') return { type: 'running' };\n return undefined;\n}\n\n/** How one tool call ended (or is going), reading the approval fields before the result. */\nexport function getActivityToolState(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n { waitingTools = NO_TOOLS, passThroughTools = NO_TOOLS }: ActivityTimelineOptions = {},\n): ActivityToolState {\n if (part.approval?.approved === false || readRejectedToolResult(part.result) !== null) {\n return 'rejected';\n }\n if (part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired') {\n return 'cancelled';\n }\n const unresolved = part.result === undefined;\n const messageIsActive =\n messageStatus === undefined ||\n messageStatus.type === 'running' ||\n messageStatus.type === 'requires-action';\n if (\n unresolved &&\n (part.interrupt?.type === 'human' ||\n (part.approval !== undefined &&\n part.approval.approved === undefined &&\n part.approval.resolution === undefined) ||\n (waitingTools.has(part.toolName) && messageIsActive))\n ) {\n return 'waiting';\n }\n\n const classification = classifyToolResult({\n status: toolCallStatus(part, messageStatus),\n result: part.result,\n isError: part.isError,\n passThroughPayload: passThroughTools.has(part.toolName),\n });\n if (classification.state === 'requires-action') return 'waiting';\n return classification.state;\n}\n\n/**\n * The compact reasoning/tool timeline in the order the parts streamed.\n *\n * A reasoning part is still streaming only while it is the final part of a\n * running message — once any later part appears, the thought has settled.\n * Settled reasoning parts with no text are dropped so the list never shows an\n * empty thinking row.\n */\nexport function buildActivityTimeline(\n content: readonly ThreadAssistantMessagePart[] | undefined,\n messageStatus: MessageStatus | undefined,\n options: ActivityTimelineOptions = {},\n): ActivityItem[] {\n if (!content?.length) return [];\n\n const lastPartIndex = content.length - 1;\n const timeline: ActivityItem[] = [];\n for (let index = 0; index < content.length; index += 1) {\n const part = content[index];\n if (part.type === 'tool-call') {\n timeline.push({\n kind: 'tool',\n id: part.toolCallId,\n args: part.args,\n toolName: part.toolName,\n state: getActivityToolState(part, messageStatus, options),\n });\n continue;\n }\n if (part.type !== 'reasoning') continue;\n\n const text = typeof part.text === 'string' ? part.text : '';\n const stillStreaming = messageStatus?.type === 'running' && index === lastPartIndex;\n if (!stillStreaming && text.trim() === '') continue;\n timeline.push({\n kind: 'reasoning',\n id: `reasoning-${index}`,\n text,\n state: stillStreaming ? 'running' : 'complete',\n });\n }\n return timeline;\n}\n\n/** Number of tool calls in the timeline. */\nexport function countActivityTools(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => (item.kind === 'tool' ? count + 1 : count), 0);\n}\n\n/**\n * The turn's phase. Waiting on the person wins over everything — a\n * `requires-action` status, a waiting tool, or a host's own `waitingForInput`\n * assertion (no in-repo host passes one) — then the message's own status.\n */\nexport function resolveActivityPhase(\n status: MessageStatus | undefined,\n timeline: readonly ActivityItem[],\n { waitingForInput = false }: { waitingForInput?: boolean } = {},\n): ActivityPhase {\n if (\n waitingForInput ||\n status?.type === 'requires-action' ||\n timeline.some((item) => item.kind === 'tool' && item.state === 'waiting')\n ) {\n return 'waiting';\n }\n if (status?.type === 'running') return 'running';\n if (status?.type === 'incomplete') return 'error';\n return 'complete';\n}\n\n/**\n * The status-row copy for one step. `resolveToolDisplayName` lets a host with\n * a richer tool catalog name tools the shared registry has no entry for.\n */\nexport function getActivityItemLabel(\n item: ActivityItem,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n): string {\n if (item.kind === 'reasoning') {\n return item.state === 'running' ? 'Thinking' : 'Thought through the next step';\n }\n return toolStatusLabel(item.toolName, item.state, resolveToolDisplayName?.(item.toolName));\n}\n\n/** The collapsed-card summary of a finished turn. */\nexport function getActivitySummary(timeline: readonly ActivityItem[]): string {\n const toolCount = countActivityTools(timeline);\n const hasIssue = timeline.some(\n (item) => item.kind === 'tool' && (item.state === 'error' || item.state === 'rejected'),\n );\n if (hasIssue) return 'Completed with issues';\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'cancelled')) {\n return 'Action cancelled';\n }\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'paused')) {\n return 'Paused during tool use';\n }\n if (toolCount > 0) return `Used ${toolCount} ${toolCount === 1 ? 'tool' : 'tools'}`;\n return 'Reasoning complete';\n}\n\n/** The part shape the final-text read needs; any message role's parts satisfy it. */\nexport type FinalTextPart = { readonly type: string; readonly text?: string };\n\n/**\n * The visible answer of a grouped turn: the text after the final tool call,\n * or all of it when the turn never called a tool. Intermediate text (before\n * or between tool calls) stays available in the details panel.\n */\nexport function getFinalText(content: readonly FinalTextPart[] | undefined): string | null {\n if (!content?.length) return null;\n\n let lastToolIndex = -1;\n for (let index = content.length - 1; index >= 0; index -= 1) {\n if (content[index]?.type === 'tool-call') {\n lastToolIndex = index;\n break;\n }\n }\n\n const texts: string[] = [];\n for (let index = lastToolIndex + 1; index < content.length; index += 1) {\n const part = content[index];\n if (part?.type === 'text' && part.text) texts.push(part.text);\n }\n return texts.length > 0 ? texts.join('\\n\\n') : null;\n}\n\n/**\n * Keep the final answer out of the details panel: it renders below the card\n * (`SuperGroupingFinalText`), so the details grouping drops every text part\n * after the last tool call and any group that becomes empty.\n */\nexport function excludeFinalTextFromGroups(grouping: GroupingFunction): GroupingFunction {\n return (parts) => {\n const lastToolIndex = parts.findLastIndex((part) => part?.type === 'tool-call');\n return grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => parts[index]?.type !== 'text' || index <= lastToolIndex),\n }))\n .filter((group) => group.indices.length > 0);\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,24 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
-
require("../packages/agent-runtime/src/generated/runconfig-contract.cjs");
|
|
5
|
-
require("react");
|
|
6
|
-
require("@assistant-ui/tap");
|
|
7
|
-
require("statewire");
|
|
8
|
-
require("../packages/agent-runtime/src/statewire-suspended.cjs");
|
|
9
|
-
require("../packages/agent-runtime/src/conversation-list.cjs");
|
|
10
|
-
require("@tanstack/react-query");
|
|
11
|
-
require("../packages/agent-runtime/src/statewire-state.cjs");
|
|
12
|
-
require("../packages/agent-runtime/src/messages.cjs");
|
|
13
|
-
require("@assistant-ui/store");
|
|
14
|
-
const streamingMarkdown = require("../packages/agent-runtime/src/streaming-markdown.cjs");
|
|
15
|
-
require("../packages/agent-runtime/src/quota-safe-local-storage-session.cjs");
|
|
16
|
-
require("../packages/agent-runtime/src/statewire-attach-observer.cjs");
|
|
17
|
-
require("../packages/agent-runtime/src/thread-status.cjs");
|
|
18
|
-
require("@assistant-ui/react-statewire");
|
|
19
|
-
require("@assistant-ui/core");
|
|
20
|
-
require("../packages/agent-runtime/src/thread-handoff.cjs");
|
|
21
4
|
const chatMessageBody = require("../chat-ui/rich-text/chat-message-body.cjs");
|
|
5
|
+
const streamingMarkdown = require("../packages/agent-runtime/src/streaming-markdown.cjs");
|
|
22
6
|
const TiptapText = ({ text, status }) => {
|
|
23
7
|
const isRunning = (status == null ? void 0 : status.type) === "running";
|
|
24
8
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tiptap-text.cjs","sources":["../../src/chat/tiptap-text.tsx"],"sourcesContent":["import type { TextMessagePartProps } from \"@assistant-ui/react\";\nimport { hideUnterminatedMarkdownLink } from \"@athenaintel/agent-runtime\";\nimport type { FC } from \"react\";\nimport { ChatMessageBody } from \"../chat-ui/rich-text/chat-message-body\";\n\n/**\n * The text part renderer `AthenaChat` mounts by default (and the one a host\n * that overrides `messageParts.Text` replaces). It is the shared static\n * message body every SDK surface renders — one document parse per message\n * instead of a live Tiptap editor per part — so links, source chips and asset\n * citations render identically here, in the Chrome extension and in the\n * Office add-in, and every click on them goes through the SDK's link-click\n * path (`useAthenaLinkClickHandler`: the provider's `linkClicks`, then the\n * asset panel for an Athena citation). While the part streams, a markdown\n * link whose destination has not closed is held back, as `MarkdownText` does.\n */\nexport const TiptapText: FC<{\n text: string;\n status?: TextMessagePartProps[\"status\"];\n}> = ({ text, status }) => {\n const isRunning = status?.type === \"running\";\n return (\n <ChatMessageBody\n text={isRunning ? hideUnterminatedMarkdownLink(text) : text}\n isRunning={isRunning}\n />\n );\n};\n"],"names":["jsx","ChatMessageBody","hideUnterminatedMarkdownLink"],"mappings":"
|
|
1
|
+
{"version":3,"file":"tiptap-text.cjs","sources":["../../src/chat/tiptap-text.tsx"],"sourcesContent":["import type { TextMessagePartProps } from \"@assistant-ui/react\";\nimport { hideUnterminatedMarkdownLink } from \"@athenaintel/agent-runtime\";\nimport type { FC } from \"react\";\nimport { ChatMessageBody } from \"../chat-ui/rich-text/chat-message-body\";\n\n/**\n * The text part renderer `AthenaChat` mounts by default (and the one a host\n * that overrides `messageParts.Text` replaces). It is the shared static\n * message body every SDK surface renders — one document parse per message\n * instead of a live Tiptap editor per part — so links, source chips and asset\n * citations render identically here, in the Chrome extension and in the\n * Office add-in, and every click on them goes through the SDK's link-click\n * path (`useAthenaLinkClickHandler`: the provider's `linkClicks`, then the\n * asset panel for an Athena citation). While the part streams, a markdown\n * link whose destination has not closed is held back, as `MarkdownText` does.\n */\nexport const TiptapText: FC<{\n text: string;\n status?: TextMessagePartProps[\"status\"];\n}> = ({ text, status }) => {\n const isRunning = status?.type === \"running\";\n return (\n <ChatMessageBody\n text={isRunning ? hideUnterminatedMarkdownLink(text) : text}\n isRunning={isRunning}\n />\n );\n};\n"],"names":["jsx","ChatMessageBody","hideUnterminatedMarkdownLink"],"mappings":";;;;;AAgBO,MAAM,aAGR,CAAC,EAAE,MAAM,aAAa;AACzB,QAAM,aAAY,iCAAQ,UAAS;AACnC,SACEA,2BAAAA;AAAAA,IAACC,gBAAAA;AAAAA,IAAA;AAAA,MACC,MAAM,YAAYC,+CAA6B,IAAI,IAAI;AAAA,MACvD;AAAA,IAAA;AAAA,EAAA;AAGN;;"}
|
package/dist/chat/tiptap-text.js
CHANGED
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import "../packages/agent-runtime/src/generated/runconfig-contract.js";
|
|
3
|
-
import "react";
|
|
4
|
-
import "@assistant-ui/tap";
|
|
5
|
-
import "statewire";
|
|
6
|
-
import "../packages/agent-runtime/src/statewire-suspended.js";
|
|
7
|
-
import "../packages/agent-runtime/src/conversation-list.js";
|
|
8
|
-
import "@tanstack/react-query";
|
|
9
|
-
import "../packages/agent-runtime/src/statewire-state.js";
|
|
10
|
-
import "../packages/agent-runtime/src/messages.js";
|
|
11
|
-
import "@assistant-ui/store";
|
|
12
|
-
import { hideUnterminatedMarkdownLink } from "../packages/agent-runtime/src/streaming-markdown.js";
|
|
13
|
-
import "../packages/agent-runtime/src/quota-safe-local-storage-session.js";
|
|
14
|
-
import "../packages/agent-runtime/src/statewire-attach-observer.js";
|
|
15
|
-
import "../packages/agent-runtime/src/thread-status.js";
|
|
16
|
-
import "@assistant-ui/react-statewire";
|
|
17
|
-
import "@assistant-ui/core";
|
|
18
|
-
import "../packages/agent-runtime/src/thread-handoff.js";
|
|
19
2
|
import { ChatMessageBody } from "../chat-ui/rich-text/chat-message-body.js";
|
|
3
|
+
import { hideUnterminatedMarkdownLink } from "../packages/agent-runtime/src/streaming-markdown.js";
|
|
20
4
|
const TiptapText = ({ text, status }) => {
|
|
21
5
|
const isRunning = (status == null ? void 0 : status.type) === "running";
|
|
22
6
|
return /* @__PURE__ */ jsx(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tiptap-text.js","sources":["../../src/chat/tiptap-text.tsx"],"sourcesContent":["import type { TextMessagePartProps } from \"@assistant-ui/react\";\nimport { hideUnterminatedMarkdownLink } from \"@athenaintel/agent-runtime\";\nimport type { FC } from \"react\";\nimport { ChatMessageBody } from \"../chat-ui/rich-text/chat-message-body\";\n\n/**\n * The text part renderer `AthenaChat` mounts by default (and the one a host\n * that overrides `messageParts.Text` replaces). It is the shared static\n * message body every SDK surface renders — one document parse per message\n * instead of a live Tiptap editor per part — so links, source chips and asset\n * citations render identically here, in the Chrome extension and in the\n * Office add-in, and every click on them goes through the SDK's link-click\n * path (`useAthenaLinkClickHandler`: the provider's `linkClicks`, then the\n * asset panel for an Athena citation). While the part streams, a markdown\n * link whose destination has not closed is held back, as `MarkdownText` does.\n */\nexport const TiptapText: FC<{\n text: string;\n status?: TextMessagePartProps[\"status\"];\n}> = ({ text, status }) => {\n const isRunning = status?.type === \"running\";\n return (\n <ChatMessageBody\n text={isRunning ? hideUnterminatedMarkdownLink(text) : text}\n isRunning={isRunning}\n />\n );\n};\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tiptap-text.js","sources":["../../src/chat/tiptap-text.tsx"],"sourcesContent":["import type { TextMessagePartProps } from \"@assistant-ui/react\";\nimport { hideUnterminatedMarkdownLink } from \"@athenaintel/agent-runtime\";\nimport type { FC } from \"react\";\nimport { ChatMessageBody } from \"../chat-ui/rich-text/chat-message-body\";\n\n/**\n * The text part renderer `AthenaChat` mounts by default (and the one a host\n * that overrides `messageParts.Text` replaces). It is the shared static\n * message body every SDK surface renders — one document parse per message\n * instead of a live Tiptap editor per part — so links, source chips and asset\n * citations render identically here, in the Chrome extension and in the\n * Office add-in, and every click on them goes through the SDK's link-click\n * path (`useAthenaLinkClickHandler`: the provider's `linkClicks`, then the\n * asset panel for an Athena citation). While the part streams, a markdown\n * link whose destination has not closed is held back, as `MarkdownText` does.\n */\nexport const TiptapText: FC<{\n text: string;\n status?: TextMessagePartProps[\"status\"];\n}> = ({ text, status }) => {\n const isRunning = status?.type === \"running\";\n return (\n <ChatMessageBody\n text={isRunning ? hideUnterminatedMarkdownLink(text) : text}\n isRunning={isRunning}\n />\n );\n};\n"],"names":[],"mappings":";;;AAgBO,MAAM,aAGR,CAAC,EAAE,MAAM,aAAa;AACzB,QAAM,aAAY,iCAAQ,UAAS;AACnC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAM,YAAY,6BAA6B,IAAI,IAAI;AAAA,MACvD;AAAA,IAAA;AAAA,EAAA;AAGN;"}
|
|
@@ -1,22 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const react = require("@assistant-ui/react");
|
|
4
|
-
require("../packages/agent-runtime/src/generated/runconfig-contract.cjs");
|
|
5
|
-
require("react");
|
|
6
|
-
require("@assistant-ui/tap");
|
|
7
|
-
require("statewire");
|
|
8
|
-
require("../packages/agent-runtime/src/statewire-suspended.cjs");
|
|
9
|
-
require("../packages/agent-runtime/src/conversation-list.cjs");
|
|
10
|
-
require("@tanstack/react-query");
|
|
11
|
-
require("../packages/agent-runtime/src/statewire-state.cjs");
|
|
12
|
-
require("../packages/agent-runtime/src/messages.cjs");
|
|
13
|
-
require("@assistant-ui/store");
|
|
14
|
-
require("../packages/agent-runtime/src/quota-safe-local-storage-session.cjs");
|
|
15
|
-
require("../packages/agent-runtime/src/statewire-attach-observer.cjs");
|
|
16
4
|
const threadStatus = require("../packages/agent-runtime/src/thread-status.cjs");
|
|
17
|
-
require("@assistant-ui/react-statewire");
|
|
18
|
-
require("@assistant-ui/core");
|
|
19
|
-
require("../packages/agent-runtime/src/thread-handoff.cjs");
|
|
20
5
|
function useAthenaRunLive() {
|
|
21
6
|
const connection = threadStatus.useDeepAgentConnection();
|
|
22
7
|
return react.useAuiState((s) => threadStatus.readRunLive(s.thread, connection));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-athena-run-live.cjs","sources":["../../src/chat/use-athena-run-live.ts"],"sourcesContent":["import { useAuiState } from '@assistant-ui/react';\nimport { readRunLive, useDeepAgentConnection } from '@athenaintel/agent-runtime';\n\n/**\n * Whether the thread has a live run — `thread.isRunning` folded through the\n * host's channel state, so a run behind a first dial (a new chat's first\n * send, switching back to a thread that was running) still reads as live\n * while a run behind a genuine reconnect or eviction does not. Surfaces\n * that gate on a live run (message edit, the voice card's live state, the\n * approval resume lock) read this instead of `thread.isRunning`, which\n * follows the presented status and blinks off for the attach round-trip.\n *\n * Scope: like every `useStatewire*` hook this reads the thread scope that\n * `AthenaChat` establishes, so call it from a component rendered inside\n * `AthenaChat` (a tool UI, a `components` override, a `composer` slot). A\n * sibling of `AthenaChat` under `AthenaProvider` has no thread scope and the\n * hook throws there; use `useAppendToComposer` / `useSendMessage` from such\n * placements instead.\n */\nexport function useAthenaRunLive(): boolean {\n const connection = useDeepAgentConnection();\n return useAuiState((s) => readRunLive(s.thread, connection));\n}\n"],"names":["useDeepAgentConnection","useAuiState","readRunLive"],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-athena-run-live.cjs","sources":["../../src/chat/use-athena-run-live.ts"],"sourcesContent":["import { useAuiState } from '@assistant-ui/react';\nimport { readRunLive, useDeepAgentConnection } from '@athenaintel/agent-runtime';\n\n/**\n * Whether the thread has a live run — `thread.isRunning` folded through the\n * host's channel state, so a run behind a first dial (a new chat's first\n * send, switching back to a thread that was running) still reads as live\n * while a run behind a genuine reconnect or eviction does not. Surfaces\n * that gate on a live run (message edit, the voice card's live state, the\n * approval resume lock) read this instead of `thread.isRunning`, which\n * follows the presented status and blinks off for the attach round-trip.\n *\n * Scope: like every `useStatewire*` hook this reads the thread scope that\n * `AthenaChat` establishes, so call it from a component rendered inside\n * `AthenaChat` (a tool UI, a `components` override, a `composer` slot). A\n * sibling of `AthenaChat` under `AthenaProvider` has no thread scope and the\n * hook throws there; use `useAppendToComposer` / `useSendMessage` from such\n * placements instead.\n */\nexport function useAthenaRunLive(): boolean {\n const connection = useDeepAgentConnection();\n return useAuiState((s) => readRunLive(s.thread, connection));\n}\n"],"names":["useDeepAgentConnection","useAuiState","readRunLive"],"mappings":";;;;AAmBO,SAAS,mBAA4B;AAC1C,QAAM,aAAaA,aAAAA,uBAAA;AACnB,SAAOC,MAAAA,YAAY,CAAC,MAAMC,aAAAA,YAAY,EAAE,QAAQ,UAAU,CAAC;AAC7D;;"}
|
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
import { useAuiState } from "@assistant-ui/react";
|
|
2
|
-
import "../packages/agent-runtime/src/generated/runconfig-contract.js";
|
|
3
|
-
import "react";
|
|
4
|
-
import "@assistant-ui/tap";
|
|
5
|
-
import "statewire";
|
|
6
|
-
import "../packages/agent-runtime/src/statewire-suspended.js";
|
|
7
|
-
import "../packages/agent-runtime/src/conversation-list.js";
|
|
8
|
-
import "@tanstack/react-query";
|
|
9
|
-
import "../packages/agent-runtime/src/statewire-state.js";
|
|
10
|
-
import "../packages/agent-runtime/src/messages.js";
|
|
11
|
-
import "@assistant-ui/store";
|
|
12
|
-
import "../packages/agent-runtime/src/quota-safe-local-storage-session.js";
|
|
13
|
-
import "../packages/agent-runtime/src/statewire-attach-observer.js";
|
|
14
2
|
import { useDeepAgentConnection, readRunLive } from "../packages/agent-runtime/src/thread-status.js";
|
|
15
|
-
import "@assistant-ui/react-statewire";
|
|
16
|
-
import "@assistant-ui/core";
|
|
17
|
-
import "../packages/agent-runtime/src/thread-handoff.js";
|
|
18
3
|
function useAthenaRunLive() {
|
|
19
4
|
const connection = useDeepAgentConnection();
|
|
20
5
|
return useAuiState((s) => readRunLive(s.thread, connection));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-athena-run-live.js","sources":["../../src/chat/use-athena-run-live.ts"],"sourcesContent":["import { useAuiState } from '@assistant-ui/react';\nimport { readRunLive, useDeepAgentConnection } from '@athenaintel/agent-runtime';\n\n/**\n * Whether the thread has a live run — `thread.isRunning` folded through the\n * host's channel state, so a run behind a first dial (a new chat's first\n * send, switching back to a thread that was running) still reads as live\n * while a run behind a genuine reconnect or eviction does not. Surfaces\n * that gate on a live run (message edit, the voice card's live state, the\n * approval resume lock) read this instead of `thread.isRunning`, which\n * follows the presented status and blinks off for the attach round-trip.\n *\n * Scope: like every `useStatewire*` hook this reads the thread scope that\n * `AthenaChat` establishes, so call it from a component rendered inside\n * `AthenaChat` (a tool UI, a `components` override, a `composer` slot). A\n * sibling of `AthenaChat` under `AthenaProvider` has no thread scope and the\n * hook throws there; use `useAppendToComposer` / `useSendMessage` from such\n * placements instead.\n */\nexport function useAthenaRunLive(): boolean {\n const connection = useDeepAgentConnection();\n return useAuiState((s) => readRunLive(s.thread, connection));\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-athena-run-live.js","sources":["../../src/chat/use-athena-run-live.ts"],"sourcesContent":["import { useAuiState } from '@assistant-ui/react';\nimport { readRunLive, useDeepAgentConnection } from '@athenaintel/agent-runtime';\n\n/**\n * Whether the thread has a live run — `thread.isRunning` folded through the\n * host's channel state, so a run behind a first dial (a new chat's first\n * send, switching back to a thread that was running) still reads as live\n * while a run behind a genuine reconnect or eviction does not. Surfaces\n * that gate on a live run (message edit, the voice card's live state, the\n * approval resume lock) read this instead of `thread.isRunning`, which\n * follows the presented status and blinks off for the attach round-trip.\n *\n * Scope: like every `useStatewire*` hook this reads the thread scope that\n * `AthenaChat` establishes, so call it from a component rendered inside\n * `AthenaChat` (a tool UI, a `components` override, a `composer` slot). A\n * sibling of `AthenaChat` under `AthenaProvider` has no thread scope and the\n * hook throws there; use `useAppendToComposer` / `useSendMessage` from such\n * placements instead.\n */\nexport function useAthenaRunLive(): boolean {\n const connection = useDeepAgentConnection();\n return useAuiState((s) => readRunLive(s.thread, connection));\n}\n"],"names":[],"mappings":";;AAmBO,SAAS,mBAA4B;AAC1C,QAAM,aAAa,uBAAA;AACnB,SAAO,YAAY,CAAC,MAAM,YAAY,EAAE,QAAQ,UAAU,CAAC;AAC7D;"}
|
|
@@ -1,30 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const reactStatewire = require("@assistant-ui/react-statewire");
|
|
4
|
-
require("../packages/agent-runtime/src/generated/runconfig-contract.cjs");
|
|
5
4
|
const react = require("react");
|
|
6
|
-
require("@assistant-ui/tap");
|
|
7
|
-
require("statewire");
|
|
8
|
-
require("../packages/agent-runtime/src/statewire-suspended.cjs");
|
|
9
|
-
require("../packages/agent-runtime/src/conversation-list.cjs");
|
|
10
|
-
require("@tanstack/react-query");
|
|
11
|
-
const interrupts = require("../packages/agent-runtime/src/interrupts.cjs");
|
|
12
|
-
require("../packages/agent-runtime/src/messages.cjs");
|
|
13
|
-
require("../packages/agent-runtime/src/statewire-state.cjs");
|
|
14
|
-
require("@assistant-ui/store");
|
|
15
|
-
require("../packages/agent-runtime/src/quota-safe-local-storage-session.cjs");
|
|
16
|
-
require("../packages/agent-runtime/src/statewire-attach-observer.cjs");
|
|
17
|
-
require("../packages/agent-runtime/src/thread-status.cjs");
|
|
18
|
-
require("@assistant-ui/core");
|
|
19
|
-
require("../packages/agent-runtime/src/thread-handoff.cjs");
|
|
20
5
|
const useAthenaRunLive = require("./use-athena-run-live.cjs");
|
|
6
|
+
const interrupts = require("../packages/agent-runtime/src/interrupts.cjs");
|
|
21
7
|
const NO_QUEUED_LANE_DECISIONS = Object.freeze({});
|
|
22
8
|
function useStatewireApprovalRequest(options = {}) {
|
|
23
9
|
var _a;
|
|
24
10
|
const {
|
|
25
11
|
interruptPredicate = interrupts.isApprovalCardInterrupt,
|
|
26
12
|
pendingResumeGraceMs = interrupts.HITL_PENDING_RESUME_GRACE_MS,
|
|
27
|
-
onResumeRejected
|
|
13
|
+
onResumeRejected,
|
|
14
|
+
onResumeRetry
|
|
28
15
|
} = options;
|
|
29
16
|
const sendCommand = reactStatewire.useStatewireSendCommand();
|
|
30
17
|
const request = (_a = reactStatewire.useStatewireRuns().inputRequests) == null ? void 0 : _a.find(interruptPredicate);
|
|
@@ -43,6 +30,7 @@ function useStatewireApprovalRequest(options = {}) {
|
|
|
43
30
|
isRunning,
|
|
44
31
|
pendingResumeGraceMs,
|
|
45
32
|
onResumeRejected,
|
|
33
|
+
onResumeRetry,
|
|
46
34
|
// The dispatch promise is handed to the lock: a refusal releases it and
|
|
47
35
|
// reaches `onResumeRejected`.
|
|
48
36
|
sendResume: (id, value) => sendCommand({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-statewire-approval-request.cjs","sources":["../../src/chat/use-statewire-approval-request.ts"],"sourcesContent":["import type { StatewireThread } from '@assistant-ui/react-statewire';\nimport {\n useStatewireRuns,\n useStatewireSendCommand,\n useStatewireState,\n} from '@assistant-ui/react-statewire';\nimport {\n type AbandonedInputRequest,\n asHitlApproval,\n findAbandonedInterrupt,\n HITL_PENDING_RESUME_GRACE_MS,\n type HitlApprovalPayload,\n interruptMirrorPayload,\n isApprovalCardInterrupt,\n type PendingActionRequest,\n pendingActionRequests,\n readAbandonedInputRequests,\n readInterruptMirror,\n readQueuedLaneDecisions,\n useApprovalResumeLock,\n} from '@athenaintel/agent-runtime';\nimport { useCallback, useMemo } from 'react';\nimport { useAthenaRunLive } from './use-athena-run-live';\n\ndeclare module '@assistant-ui/core' {\n namespace Assistant {\n interface Commands {\n /**\n * Decide per-dispatch subagent lanes while the parent run is still\n * streaming (`DeepAgentThread.run_lane_input`). Keys are the lanes'\n * langgraph interrupt ids; the host matches them against the lanes its\n * mirrored interrupt currently parks, answers at once when the run is\n * already parked, and otherwise holds them until it parks — stale or\n * unknown ids are ignored, never carried to a later interrupt.\n */\n runLaneInput: {\n readonly type: 'run/lane-input';\n readonly laneDecisions: Readonly<Record<string, StatewireThread.InputResponse>>;\n };\n }\n }\n}\n\nconst NO_QUEUED_LANE_DECISIONS: Readonly<Record<string, unknown>> = Object.freeze({});\n\n/** Selects which pending interrupt an approval surface answers. */\nexport type StatewireInterruptPredicate = (\n request: StatewireThread.InputRequestState,\n) => request is StatewireThread.CustomInputRequest;\n\nexport interface UseStatewireApprovalRequestOptions {\n /**\n * Which pending interrupt to answer. Defaults to `isApprovalCardInterrupt`\n * (client-tool parks excluded — the client-tool bridge owns those, and a\n * generic resume would corrupt the parked tool call).\n */\n interruptPredicate?: StatewireInterruptPredicate;\n /**\n * How long a sent decision keeps the actions locked when no resume run ever\n * starts. Defaults to {@link HITL_PENDING_RESUME_GRACE_MS}.\n */\n pendingResumeGraceMs?: number;\n /**\n * The host refused the `run/input` (or the transport lost it): the\n * optimistic fold rolls back, the request is on screen again with its\n * actions re-enabled, and this is the surface's one chance to say why.\n */\n onResumeRejected?: (error: unknown, requestId: string) => void;\n}\n\nexport interface StatewireApprovalRequest<TValue> {\n /** The pending interrupt this surface answers, if any. */\n request: StatewireThread.CustomInputRequest | undefined;\n requestId: string | undefined;\n /** The payload narrowed to the Athena HITL approval shape, or `null`. */\n hitl: HitlApprovalPayload | null;\n /** Every gated call the approval covers, in decision order (empty for non-HITL parks). */\n actionRequests: PendingActionRequest[];\n /** An interrupt a non-resume dispatch dropped — the \"approval was cancelled\" notice. */\n abandonedInterrupt: AbandonedInputRequest | undefined;\n /**\n * The mirrored interrupt's HITL payload while the run is still live and no\n * input request is answerable: per-dispatch `task` lanes parked on their\n * gates while sibling lanes stream. `null` once the run parks (the same\n * lanes are then `hitl` / `actionRequests`) and when nothing is parked.\n */\n liveHitl: HitlApprovalPayload | null;\n /** Every gated call `liveHitl` covers (empty when it is `null`). */\n liveActionRequests: PendingActionRequest[];\n /**\n * The decisions the host already holds from a `run/lane-input`, keyed by\n * langgraph interrupt id, to be answered when the run parks — a queued lane\n * reads as decided on every attached client, not just the one that sent it.\n */\n queuedLaneDecisions: Readonly<Record<string, unknown>>;\n /** True after a resume until the request identity changes (or recovery fires). */\n pending: boolean;\n /**\n * Answer the request with `{ type: 'run/input', requestId, response: { type: 'resume', value } }`.\n * Returns the dispatch promise (settles when the host accepts, rejects when\n * it refuses), or `undefined` when the lock dropped the send.\n */\n resume: (value: TValue) => Promise<unknown> | undefined;\n /**\n * Decide per-dispatch lanes by langgraph interrupt id. With a pending\n * request this is the native `lane_decisions` resume through the lock;\n * without one (the run is still streaming siblings) it is `run/lane-input`,\n * which the host queues and answers on the park. Returns the dispatch\n * promise, or `undefined` when the lock dropped a resume.\n */\n sendLaneDecisions: (\n lanes: Readonly<Record<string, StatewireThread.InputResponse>>,\n ) => Promise<unknown> | undefined;\n}\n\n/**\n * The headless half of every statewire approval surface: selects the pending\n * interrupt from the runs projection, narrows its payload, reads the\n * host-published abandoned interrupts, and wires the shared optimistic resume\n * lock to the thread's `run/input` command. `StatewireApprovalCard` renders\n * over it; hosts with their own decision UI (per-lane subagent cards) build\n * on it directly so the selection and lock semantics cannot drift.\n *\n * Requires a statewire aui scope (throws outside one, like every\n * `useStatewire*` hook) — gate the mount with `hasStatewireThreadExtras`.\n */\nexport function useStatewireApprovalRequest<\n TValue extends StatewireThread.InputResponse = Record<string, string>,\n>(options: UseStatewireApprovalRequestOptions = {}): StatewireApprovalRequest<TValue> {\n const {\n interruptPredicate = isApprovalCardInterrupt,\n pendingResumeGraceMs = HITL_PENDING_RESUME_GRACE_MS,\n onResumeRejected,\n } = options;\n const sendCommand = useStatewireSendCommand();\n // The runs projection is memoized by the lib, so this derivation is\n // reference-stable between state updates.\n const request = useStatewireRuns().inputRequests?.find(interruptPredicate);\n const requestId = request?.id;\n\n // The host publishes the interrupts a non-resume dispatch dropped. Select\n // the raw array reference (pre-stream-safe) and derive inline; a `.find`\n // selector would return a fresh object every update.\n const abandoned = useStatewireState(readAbandonedInputRequests);\n const abandonedInterrupt = findAbandonedInterrupt(abandoned);\n\n const hitl = asHitlApproval(request?.payload);\n const actionRequests = useMemo(() => pendingActionRequests(hitl), [hitl]);\n\n const isRunning = useAthenaRunLive();\n // The host mirrors the interrupt into state as soon as a lane parks — while\n // the run manager still reports `running` (siblings streaming) and has no\n // request to answer. Raw reference selectors; derive inline.\n const mirror = useStatewireState(readInterruptMirror);\n const liveHitl =\n request === undefined && isRunning ? asHitlApproval(interruptMirrorPayload(mirror)) : null;\n const liveActionRequests = useMemo(() => pendingActionRequests(liveHitl), [liveHitl]);\n const queuedLaneDecisions =\n useStatewireState(readQueuedLaneDecisions) ?? NO_QUEUED_LANE_DECISIONS;\n\n const { pending, resume } = useApprovalResumeLock<TValue>({\n requestId,\n isRunning,\n pendingResumeGraceMs,\n onResumeRejected,\n // The dispatch promise is handed to the lock: a refusal releases it and\n // reaches `onResumeRejected`.\n sendResume: (id, value) =>\n sendCommand({\n type: 'run/input',\n requestId: id,\n response: { type: 'resume', value },\n }),\n });\n\n const sendLaneDecisions = useCallback(\n (lanes: Readonly<Record<string, StatewireThread.InputResponse>>) =>\n requestId !== undefined\n ? resume({ lane_decisions: lanes } as unknown as TValue)\n : sendCommand({ type: 'run/lane-input', laneDecisions: lanes }),\n [requestId, resume, sendCommand],\n );\n\n return {\n request,\n requestId,\n hitl,\n actionRequests,\n liveHitl,\n liveActionRequests,\n queuedLaneDecisions,\n abandonedInterrupt,\n pending,\n resume,\n sendLaneDecisions,\n };\n}\n"],"names":["isApprovalCardInterrupt","HITL_PENDING_RESUME_GRACE_MS","useStatewireSendCommand","useStatewireRuns","useStatewireState","readAbandonedInputRequests","findAbandonedInterrupt","asHitlApproval","useMemo","pendingActionRequests","useAthenaRunLive","readInterruptMirror","interruptMirrorPayload","readQueuedLaneDecisions","useApprovalResumeLock","useCallback"],"mappings":";;;;;;;;;;;;;;;;;;;;AA2CA,MAAM,2BAA8D,OAAO,OAAO,EAAE;AAmF7E,SAAS,4BAEd,UAA8C,IAAsC;;AACpF,QAAM;AAAA,IACJ,qBAAqBA,WAAAA;AAAAA,IACrB,uBAAuBC,WAAAA;AAAAA,IACvB;AAAA,EAAA,IACE;AACJ,QAAM,cAAcC,eAAAA,wBAAA;AAGpB,QAAM,WAAUC,oBAAAA,iBAAA,EAAmB,kBAAnBA,mBAAkC,KAAK;AACvD,QAAM,YAAY,mCAAS;AAK3B,QAAM,YAAYC,eAAAA,kBAAkBC,qCAA0B;AAC9D,QAAM,qBAAqBC,WAAAA,uBAAuB,SAAS;AAE3D,QAAM,OAAOC,WAAAA,eAAe,mCAAS,OAAO;AAC5C,QAAM,iBAAiBC,MAAAA,QAAQ,MAAMC,WAAAA,sBAAsB,IAAI,GAAG,CAAC,IAAI,CAAC;AAExE,QAAM,YAAYC,iBAAAA,iBAAA;AAIlB,QAAM,SAASN,eAAAA,kBAAkBO,8BAAmB;AACpD,QAAM,WACJ,YAAY,UAAa,YAAYJ,WAAAA,eAAeK,WAAAA,uBAAuB,MAAM,CAAC,IAAI;AACxF,QAAM,qBAAqBJ,MAAAA,QAAQ,MAAMC,WAAAA,sBAAsB,QAAQ,GAAG,CAAC,QAAQ,CAAC;AACpF,QAAM,sBACJL,eAAAA,kBAAkBS,WAAAA,uBAAuB,KAAK;AAEhD,QAAM,EAAE,SAAS,OAAA,IAAWC,iCAA8B;AAAA,IACxD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA,IAGA,YAAY,CAAC,IAAI,UACf,YAAY;AAAA,MACV,MAAM;AAAA,MACN,WAAW;AAAA,MACX,UAAU,EAAE,MAAM,UAAU,MAAA;AAAA,IAAM,CACnC;AAAA,EAAA,CACJ;AAED,QAAM,oBAAoBC,MAAAA;AAAAA,IACxB,CAAC,UACC,cAAc,SACV,OAAO,EAAE,gBAAgB,MAAA,CAA4B,IACrD,YAAY,EAAE,MAAM,kBAAkB,eAAe,OAAO;AAAA,IAClE,CAAC,WAAW,QAAQ,WAAW;AAAA,EAAA;AAGjC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;;"}
|
|
1
|
+
{"version":3,"file":"use-statewire-approval-request.cjs","sources":["../../src/chat/use-statewire-approval-request.ts"],"sourcesContent":["import type { StatewireThread } from '@assistant-ui/react-statewire';\nimport {\n useStatewireRuns,\n useStatewireSendCommand,\n useStatewireState,\n} from '@assistant-ui/react-statewire';\nimport {\n type AbandonedInputRequest,\n asHitlApproval,\n findAbandonedInterrupt,\n HITL_PENDING_RESUME_GRACE_MS,\n type HitlApprovalPayload,\n interruptMirrorPayload,\n isApprovalCardInterrupt,\n type PendingActionRequest,\n pendingActionRequests,\n readAbandonedInputRequests,\n readInterruptMirror,\n readQueuedLaneDecisions,\n useApprovalResumeLock,\n} from '@athenaintel/agent-runtime';\nimport { useCallback, useMemo } from 'react';\nimport { useAthenaRunLive } from './use-athena-run-live';\n\ndeclare module '@assistant-ui/core' {\n namespace Assistant {\n interface Commands {\n /**\n * Decide per-dispatch subagent lanes while the parent run is still\n * streaming (`DeepAgentThread.run_lane_input`). Keys are the lanes'\n * langgraph interrupt ids; the host matches them against the lanes its\n * mirrored interrupt currently parks, answers at once when the run is\n * already parked, and otherwise holds them until it parks — stale or\n * unknown ids are ignored, never carried to a later interrupt.\n */\n runLaneInput: {\n readonly type: 'run/lane-input';\n readonly laneDecisions: Readonly<Record<string, StatewireThread.InputResponse>>;\n };\n }\n }\n}\n\nconst NO_QUEUED_LANE_DECISIONS: Readonly<Record<string, unknown>> = Object.freeze({});\n\n/** Selects which pending interrupt an approval surface answers. */\nexport type StatewireInterruptPredicate = (\n request: StatewireThread.InputRequestState,\n) => request is StatewireThread.CustomInputRequest;\n\nexport interface UseStatewireApprovalRequestOptions {\n /**\n * Which pending interrupt to answer. Defaults to `isApprovalCardInterrupt`\n * (client-tool parks excluded — the client-tool bridge owns those, and a\n * generic resume would corrupt the parked tool call).\n */\n interruptPredicate?: StatewireInterruptPredicate;\n /**\n * How long a sent decision keeps the actions locked when no resume run ever\n * starts. Defaults to {@link HITL_PENDING_RESUME_GRACE_MS}.\n */\n pendingResumeGraceMs?: number;\n /**\n * The host refused the `run/input` (or the transport lost it): the\n * optimistic fold rolls back, the request is on screen again with its\n * actions re-enabled, and this is the surface's one chance to say why.\n */\n onResumeRejected?: (error: unknown, requestId: string) => void;\n /** See {@link UseApprovalResumeLockOptions.onResumeRetry}. */\n onResumeRetry?: (error: unknown, requestId: string, attempt: number) => void;\n}\n\nexport interface StatewireApprovalRequest<TValue> {\n /** The pending interrupt this surface answers, if any. */\n request: StatewireThread.CustomInputRequest | undefined;\n requestId: string | undefined;\n /** The payload narrowed to the Athena HITL approval shape, or `null`. */\n hitl: HitlApprovalPayload | null;\n /** Every gated call the approval covers, in decision order (empty for non-HITL parks). */\n actionRequests: PendingActionRequest[];\n /** An interrupt a non-resume dispatch dropped — the \"approval was cancelled\" notice. */\n abandonedInterrupt: AbandonedInputRequest | undefined;\n /**\n * The mirrored interrupt's HITL payload while the run is still live and no\n * input request is answerable: per-dispatch `task` lanes parked on their\n * gates while sibling lanes stream. `null` once the run parks (the same\n * lanes are then `hitl` / `actionRequests`) and when nothing is parked.\n */\n liveHitl: HitlApprovalPayload | null;\n /** Every gated call `liveHitl` covers (empty when it is `null`). */\n liveActionRequests: PendingActionRequest[];\n /**\n * The decisions the host already holds from a `run/lane-input`, keyed by\n * langgraph interrupt id, to be answered when the run parks — a queued lane\n * reads as decided on every attached client, not just the one that sent it.\n */\n queuedLaneDecisions: Readonly<Record<string, unknown>>;\n /** True after a resume until the request identity changes (or recovery fires). */\n pending: boolean;\n /**\n * Answer the request with `{ type: 'run/input', requestId, response: { type: 'resume', value } }`.\n * Returns the dispatch promise (settles when the host accepts, rejects when\n * it refuses), or `undefined` when the lock dropped the send.\n */\n resume: (value: TValue) => Promise<unknown> | undefined;\n /**\n * Decide per-dispatch lanes by langgraph interrupt id. With a pending\n * request this is the native `lane_decisions` resume through the lock;\n * without one (the run is still streaming siblings) it is `run/lane-input`,\n * which the host queues and answers on the park. Returns the dispatch\n * promise, or `undefined` when the lock dropped a resume.\n */\n sendLaneDecisions: (\n lanes: Readonly<Record<string, StatewireThread.InputResponse>>,\n ) => Promise<unknown> | undefined;\n}\n\n/**\n * The headless half of every statewire approval surface: selects the pending\n * interrupt from the runs projection, narrows its payload, reads the\n * host-published abandoned interrupts, and wires the shared optimistic resume\n * lock to the thread's `run/input` command. `StatewireApprovalCard` renders\n * over it; hosts with their own decision UI (per-lane subagent cards) build\n * on it directly so the selection and lock semantics cannot drift.\n *\n * Requires a statewire aui scope (throws outside one, like every\n * `useStatewire*` hook) — gate the mount with `hasStatewireThreadExtras`.\n */\nexport function useStatewireApprovalRequest<\n TValue extends StatewireThread.InputResponse = Record<string, string>,\n>(options: UseStatewireApprovalRequestOptions = {}): StatewireApprovalRequest<TValue> {\n const {\n interruptPredicate = isApprovalCardInterrupt,\n pendingResumeGraceMs = HITL_PENDING_RESUME_GRACE_MS,\n onResumeRejected,\n onResumeRetry,\n } = options;\n const sendCommand = useStatewireSendCommand();\n // The runs projection is memoized by the lib, so this derivation is\n // reference-stable between state updates.\n const request = useStatewireRuns().inputRequests?.find(interruptPredicate);\n const requestId = request?.id;\n\n // The host publishes the interrupts a non-resume dispatch dropped. Select\n // the raw array reference (pre-stream-safe) and derive inline; a `.find`\n // selector would return a fresh object every update.\n const abandoned = useStatewireState(readAbandonedInputRequests);\n const abandonedInterrupt = findAbandonedInterrupt(abandoned);\n\n const hitl = asHitlApproval(request?.payload);\n const actionRequests = useMemo(() => pendingActionRequests(hitl), [hitl]);\n\n const isRunning = useAthenaRunLive();\n // The host mirrors the interrupt into state as soon as a lane parks — while\n // the run manager still reports `running` (siblings streaming) and has no\n // request to answer. Raw reference selectors; derive inline.\n const mirror = useStatewireState(readInterruptMirror);\n const liveHitl =\n request === undefined && isRunning ? asHitlApproval(interruptMirrorPayload(mirror)) : null;\n const liveActionRequests = useMemo(() => pendingActionRequests(liveHitl), [liveHitl]);\n const queuedLaneDecisions =\n useStatewireState(readQueuedLaneDecisions) ?? NO_QUEUED_LANE_DECISIONS;\n\n const { pending, resume } = useApprovalResumeLock<TValue>({\n requestId,\n isRunning,\n pendingResumeGraceMs,\n onResumeRejected,\n onResumeRetry,\n // The dispatch promise is handed to the lock: a refusal releases it and\n // reaches `onResumeRejected`.\n sendResume: (id, value) =>\n sendCommand({\n type: 'run/input',\n requestId: id,\n response: { type: 'resume', value },\n }),\n });\n\n const sendLaneDecisions = useCallback(\n (lanes: Readonly<Record<string, StatewireThread.InputResponse>>) =>\n requestId !== undefined\n ? resume({ lane_decisions: lanes } as unknown as TValue)\n : sendCommand({ type: 'run/lane-input', laneDecisions: lanes }),\n [requestId, resume, sendCommand],\n );\n\n return {\n request,\n requestId,\n hitl,\n actionRequests,\n liveHitl,\n liveActionRequests,\n queuedLaneDecisions,\n abandonedInterrupt,\n pending,\n resume,\n sendLaneDecisions,\n };\n}\n"],"names":["isApprovalCardInterrupt","HITL_PENDING_RESUME_GRACE_MS","useStatewireSendCommand","useStatewireRuns","useStatewireState","readAbandonedInputRequests","findAbandonedInterrupt","asHitlApproval","useMemo","pendingActionRequests","useAthenaRunLive","readInterruptMirror","interruptMirrorPayload","readQueuedLaneDecisions","useApprovalResumeLock","useCallback"],"mappings":";;;;;;AA2CA,MAAM,2BAA8D,OAAO,OAAO,EAAE;AAqF7E,SAAS,4BAEd,UAA8C,IAAsC;;AACpF,QAAM;AAAA,IACJ,qBAAqBA,WAAAA;AAAAA,IACrB,uBAAuBC,WAAAA;AAAAA,IACvB;AAAA,IACA;AAAA,EAAA,IACE;AACJ,QAAM,cAAcC,eAAAA,wBAAA;AAGpB,QAAM,WAAUC,oBAAAA,iBAAA,EAAmB,kBAAnBA,mBAAkC,KAAK;AACvD,QAAM,YAAY,mCAAS;AAK3B,QAAM,YAAYC,eAAAA,kBAAkBC,qCAA0B;AAC9D,QAAM,qBAAqBC,WAAAA,uBAAuB,SAAS;AAE3D,QAAM,OAAOC,WAAAA,eAAe,mCAAS,OAAO;AAC5C,QAAM,iBAAiBC,MAAAA,QAAQ,MAAMC,WAAAA,sBAAsB,IAAI,GAAG,CAAC,IAAI,CAAC;AAExE,QAAM,YAAYC,iBAAAA,iBAAA;AAIlB,QAAM,SAASN,eAAAA,kBAAkBO,8BAAmB;AACpD,QAAM,WACJ,YAAY,UAAa,YAAYJ,WAAAA,eAAeK,WAAAA,uBAAuB,MAAM,CAAC,IAAI;AACxF,QAAM,qBAAqBJ,MAAAA,QAAQ,MAAMC,WAAAA,sBAAsB,QAAQ,GAAG,CAAC,QAAQ,CAAC;AACpF,QAAM,sBACJL,eAAAA,kBAAkBS,WAAAA,uBAAuB,KAAK;AAEhD,QAAM,EAAE,SAAS,OAAA,IAAWC,iCAA8B;AAAA,IACxD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA,IAGA,YAAY,CAAC,IAAI,UACf,YAAY;AAAA,MACV,MAAM;AAAA,MACN,WAAW;AAAA,MACX,UAAU,EAAE,MAAM,UAAU,MAAA;AAAA,IAAM,CACnC;AAAA,EAAA,CACJ;AAED,QAAM,oBAAoBC,MAAAA;AAAAA,IACxB,CAAC,UACC,cAAc,SACV,OAAO,EAAE,gBAAgB,MAAA,CAA4B,IACrD,YAAY,EAAE,MAAM,kBAAkB,eAAe,OAAO;AAAA,IAClE,CAAC,WAAW,QAAQ,WAAW;AAAA,EAAA;AAGjC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;;"}
|
|
@@ -38,6 +38,8 @@ export interface UseStatewireApprovalRequestOptions {
|
|
|
38
38
|
* actions re-enabled, and this is the surface's one chance to say why.
|
|
39
39
|
*/
|
|
40
40
|
onResumeRejected?: (error: unknown, requestId: string) => void;
|
|
41
|
+
/** See {@link UseApprovalResumeLockOptions.onResumeRetry}. */
|
|
42
|
+
onResumeRetry?: (error: unknown, requestId: string, attempt: number) => void;
|
|
41
43
|
}
|
|
42
44
|
export interface StatewireApprovalRequest<TValue> {
|
|
43
45
|
/** The pending interrupt this surface answers, if any. */
|
|
@@ -1,28 +1,15 @@
|
|
|
1
1
|
import { useStatewireSendCommand, useStatewireRuns, useStatewireState } from "@assistant-ui/react-statewire";
|
|
2
|
-
import "../packages/agent-runtime/src/generated/runconfig-contract.js";
|
|
3
2
|
import { useMemo, useCallback } from "react";
|
|
4
|
-
import "@assistant-ui/tap";
|
|
5
|
-
import "statewire";
|
|
6
|
-
import "../packages/agent-runtime/src/statewire-suspended.js";
|
|
7
|
-
import "../packages/agent-runtime/src/conversation-list.js";
|
|
8
|
-
import "@tanstack/react-query";
|
|
9
|
-
import { isApprovalCardInterrupt, HITL_PENDING_RESUME_GRACE_MS, readAbandonedInputRequests, findAbandonedInterrupt, asHitlApproval, pendingActionRequests, readInterruptMirror, interruptMirrorPayload, readQueuedLaneDecisions, useApprovalResumeLock } from "../packages/agent-runtime/src/interrupts.js";
|
|
10
|
-
import "../packages/agent-runtime/src/messages.js";
|
|
11
|
-
import "../packages/agent-runtime/src/statewire-state.js";
|
|
12
|
-
import "@assistant-ui/store";
|
|
13
|
-
import "../packages/agent-runtime/src/quota-safe-local-storage-session.js";
|
|
14
|
-
import "../packages/agent-runtime/src/statewire-attach-observer.js";
|
|
15
|
-
import "../packages/agent-runtime/src/thread-status.js";
|
|
16
|
-
import "@assistant-ui/core";
|
|
17
|
-
import "../packages/agent-runtime/src/thread-handoff.js";
|
|
18
3
|
import { useAthenaRunLive } from "./use-athena-run-live.js";
|
|
4
|
+
import { isApprovalCardInterrupt, HITL_PENDING_RESUME_GRACE_MS, readAbandonedInputRequests, findAbandonedInterrupt, asHitlApproval, pendingActionRequests, readInterruptMirror, interruptMirrorPayload, readQueuedLaneDecisions, useApprovalResumeLock } from "../packages/agent-runtime/src/interrupts.js";
|
|
19
5
|
const NO_QUEUED_LANE_DECISIONS = Object.freeze({});
|
|
20
6
|
function useStatewireApprovalRequest(options = {}) {
|
|
21
7
|
var _a;
|
|
22
8
|
const {
|
|
23
9
|
interruptPredicate = isApprovalCardInterrupt,
|
|
24
10
|
pendingResumeGraceMs = HITL_PENDING_RESUME_GRACE_MS,
|
|
25
|
-
onResumeRejected
|
|
11
|
+
onResumeRejected,
|
|
12
|
+
onResumeRetry
|
|
26
13
|
} = options;
|
|
27
14
|
const sendCommand = useStatewireSendCommand();
|
|
28
15
|
const request = (_a = useStatewireRuns().inputRequests) == null ? void 0 : _a.find(interruptPredicate);
|
|
@@ -41,6 +28,7 @@ function useStatewireApprovalRequest(options = {}) {
|
|
|
41
28
|
isRunning,
|
|
42
29
|
pendingResumeGraceMs,
|
|
43
30
|
onResumeRejected,
|
|
31
|
+
onResumeRetry,
|
|
44
32
|
// The dispatch promise is handed to the lock: a refusal releases it and
|
|
45
33
|
// reaches `onResumeRejected`.
|
|
46
34
|
sendResume: (id, value) => sendCommand({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-statewire-approval-request.js","sources":["../../src/chat/use-statewire-approval-request.ts"],"sourcesContent":["import type { StatewireThread } from '@assistant-ui/react-statewire';\nimport {\n useStatewireRuns,\n useStatewireSendCommand,\n useStatewireState,\n} from '@assistant-ui/react-statewire';\nimport {\n type AbandonedInputRequest,\n asHitlApproval,\n findAbandonedInterrupt,\n HITL_PENDING_RESUME_GRACE_MS,\n type HitlApprovalPayload,\n interruptMirrorPayload,\n isApprovalCardInterrupt,\n type PendingActionRequest,\n pendingActionRequests,\n readAbandonedInputRequests,\n readInterruptMirror,\n readQueuedLaneDecisions,\n useApprovalResumeLock,\n} from '@athenaintel/agent-runtime';\nimport { useCallback, useMemo } from 'react';\nimport { useAthenaRunLive } from './use-athena-run-live';\n\ndeclare module '@assistant-ui/core' {\n namespace Assistant {\n interface Commands {\n /**\n * Decide per-dispatch subagent lanes while the parent run is still\n * streaming (`DeepAgentThread.run_lane_input`). Keys are the lanes'\n * langgraph interrupt ids; the host matches them against the lanes its\n * mirrored interrupt currently parks, answers at once when the run is\n * already parked, and otherwise holds them until it parks — stale or\n * unknown ids are ignored, never carried to a later interrupt.\n */\n runLaneInput: {\n readonly type: 'run/lane-input';\n readonly laneDecisions: Readonly<Record<string, StatewireThread.InputResponse>>;\n };\n }\n }\n}\n\nconst NO_QUEUED_LANE_DECISIONS: Readonly<Record<string, unknown>> = Object.freeze({});\n\n/** Selects which pending interrupt an approval surface answers. */\nexport type StatewireInterruptPredicate = (\n request: StatewireThread.InputRequestState,\n) => request is StatewireThread.CustomInputRequest;\n\nexport interface UseStatewireApprovalRequestOptions {\n /**\n * Which pending interrupt to answer. Defaults to `isApprovalCardInterrupt`\n * (client-tool parks excluded — the client-tool bridge owns those, and a\n * generic resume would corrupt the parked tool call).\n */\n interruptPredicate?: StatewireInterruptPredicate;\n /**\n * How long a sent decision keeps the actions locked when no resume run ever\n * starts. Defaults to {@link HITL_PENDING_RESUME_GRACE_MS}.\n */\n pendingResumeGraceMs?: number;\n /**\n * The host refused the `run/input` (or the transport lost it): the\n * optimistic fold rolls back, the request is on screen again with its\n * actions re-enabled, and this is the surface's one chance to say why.\n */\n onResumeRejected?: (error: unknown, requestId: string) => void;\n}\n\nexport interface StatewireApprovalRequest<TValue> {\n /** The pending interrupt this surface answers, if any. */\n request: StatewireThread.CustomInputRequest | undefined;\n requestId: string | undefined;\n /** The payload narrowed to the Athena HITL approval shape, or `null`. */\n hitl: HitlApprovalPayload | null;\n /** Every gated call the approval covers, in decision order (empty for non-HITL parks). */\n actionRequests: PendingActionRequest[];\n /** An interrupt a non-resume dispatch dropped — the \"approval was cancelled\" notice. */\n abandonedInterrupt: AbandonedInputRequest | undefined;\n /**\n * The mirrored interrupt's HITL payload while the run is still live and no\n * input request is answerable: per-dispatch `task` lanes parked on their\n * gates while sibling lanes stream. `null` once the run parks (the same\n * lanes are then `hitl` / `actionRequests`) and when nothing is parked.\n */\n liveHitl: HitlApprovalPayload | null;\n /** Every gated call `liveHitl` covers (empty when it is `null`). */\n liveActionRequests: PendingActionRequest[];\n /**\n * The decisions the host already holds from a `run/lane-input`, keyed by\n * langgraph interrupt id, to be answered when the run parks — a queued lane\n * reads as decided on every attached client, not just the one that sent it.\n */\n queuedLaneDecisions: Readonly<Record<string, unknown>>;\n /** True after a resume until the request identity changes (or recovery fires). */\n pending: boolean;\n /**\n * Answer the request with `{ type: 'run/input', requestId, response: { type: 'resume', value } }`.\n * Returns the dispatch promise (settles when the host accepts, rejects when\n * it refuses), or `undefined` when the lock dropped the send.\n */\n resume: (value: TValue) => Promise<unknown> | undefined;\n /**\n * Decide per-dispatch lanes by langgraph interrupt id. With a pending\n * request this is the native `lane_decisions` resume through the lock;\n * without one (the run is still streaming siblings) it is `run/lane-input`,\n * which the host queues and answers on the park. Returns the dispatch\n * promise, or `undefined` when the lock dropped a resume.\n */\n sendLaneDecisions: (\n lanes: Readonly<Record<string, StatewireThread.InputResponse>>,\n ) => Promise<unknown> | undefined;\n}\n\n/**\n * The headless half of every statewire approval surface: selects the pending\n * interrupt from the runs projection, narrows its payload, reads the\n * host-published abandoned interrupts, and wires the shared optimistic resume\n * lock to the thread's `run/input` command. `StatewireApprovalCard` renders\n * over it; hosts with their own decision UI (per-lane subagent cards) build\n * on it directly so the selection and lock semantics cannot drift.\n *\n * Requires a statewire aui scope (throws outside one, like every\n * `useStatewire*` hook) — gate the mount with `hasStatewireThreadExtras`.\n */\nexport function useStatewireApprovalRequest<\n TValue extends StatewireThread.InputResponse = Record<string, string>,\n>(options: UseStatewireApprovalRequestOptions = {}): StatewireApprovalRequest<TValue> {\n const {\n interruptPredicate = isApprovalCardInterrupt,\n pendingResumeGraceMs = HITL_PENDING_RESUME_GRACE_MS,\n onResumeRejected,\n } = options;\n const sendCommand = useStatewireSendCommand();\n // The runs projection is memoized by the lib, so this derivation is\n // reference-stable between state updates.\n const request = useStatewireRuns().inputRequests?.find(interruptPredicate);\n const requestId = request?.id;\n\n // The host publishes the interrupts a non-resume dispatch dropped. Select\n // the raw array reference (pre-stream-safe) and derive inline; a `.find`\n // selector would return a fresh object every update.\n const abandoned = useStatewireState(readAbandonedInputRequests);\n const abandonedInterrupt = findAbandonedInterrupt(abandoned);\n\n const hitl = asHitlApproval(request?.payload);\n const actionRequests = useMemo(() => pendingActionRequests(hitl), [hitl]);\n\n const isRunning = useAthenaRunLive();\n // The host mirrors the interrupt into state as soon as a lane parks — while\n // the run manager still reports `running` (siblings streaming) and has no\n // request to answer. Raw reference selectors; derive inline.\n const mirror = useStatewireState(readInterruptMirror);\n const liveHitl =\n request === undefined && isRunning ? asHitlApproval(interruptMirrorPayload(mirror)) : null;\n const liveActionRequests = useMemo(() => pendingActionRequests(liveHitl), [liveHitl]);\n const queuedLaneDecisions =\n useStatewireState(readQueuedLaneDecisions) ?? NO_QUEUED_LANE_DECISIONS;\n\n const { pending, resume } = useApprovalResumeLock<TValue>({\n requestId,\n isRunning,\n pendingResumeGraceMs,\n onResumeRejected,\n // The dispatch promise is handed to the lock: a refusal releases it and\n // reaches `onResumeRejected`.\n sendResume: (id, value) =>\n sendCommand({\n type: 'run/input',\n requestId: id,\n response: { type: 'resume', value },\n }),\n });\n\n const sendLaneDecisions = useCallback(\n (lanes: Readonly<Record<string, StatewireThread.InputResponse>>) =>\n requestId !== undefined\n ? resume({ lane_decisions: lanes } as unknown as TValue)\n : sendCommand({ type: 'run/lane-input', laneDecisions: lanes }),\n [requestId, resume, sendCommand],\n );\n\n return {\n request,\n requestId,\n hitl,\n actionRequests,\n liveHitl,\n liveActionRequests,\n queuedLaneDecisions,\n abandonedInterrupt,\n pending,\n resume,\n sendLaneDecisions,\n };\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-statewire-approval-request.js","sources":["../../src/chat/use-statewire-approval-request.ts"],"sourcesContent":["import type { StatewireThread } from '@assistant-ui/react-statewire';\nimport {\n useStatewireRuns,\n useStatewireSendCommand,\n useStatewireState,\n} from '@assistant-ui/react-statewire';\nimport {\n type AbandonedInputRequest,\n asHitlApproval,\n findAbandonedInterrupt,\n HITL_PENDING_RESUME_GRACE_MS,\n type HitlApprovalPayload,\n interruptMirrorPayload,\n isApprovalCardInterrupt,\n type PendingActionRequest,\n pendingActionRequests,\n readAbandonedInputRequests,\n readInterruptMirror,\n readQueuedLaneDecisions,\n useApprovalResumeLock,\n} from '@athenaintel/agent-runtime';\nimport { useCallback, useMemo } from 'react';\nimport { useAthenaRunLive } from './use-athena-run-live';\n\ndeclare module '@assistant-ui/core' {\n namespace Assistant {\n interface Commands {\n /**\n * Decide per-dispatch subagent lanes while the parent run is still\n * streaming (`DeepAgentThread.run_lane_input`). Keys are the lanes'\n * langgraph interrupt ids; the host matches them against the lanes its\n * mirrored interrupt currently parks, answers at once when the run is\n * already parked, and otherwise holds them until it parks — stale or\n * unknown ids are ignored, never carried to a later interrupt.\n */\n runLaneInput: {\n readonly type: 'run/lane-input';\n readonly laneDecisions: Readonly<Record<string, StatewireThread.InputResponse>>;\n };\n }\n }\n}\n\nconst NO_QUEUED_LANE_DECISIONS: Readonly<Record<string, unknown>> = Object.freeze({});\n\n/** Selects which pending interrupt an approval surface answers. */\nexport type StatewireInterruptPredicate = (\n request: StatewireThread.InputRequestState,\n) => request is StatewireThread.CustomInputRequest;\n\nexport interface UseStatewireApprovalRequestOptions {\n /**\n * Which pending interrupt to answer. Defaults to `isApprovalCardInterrupt`\n * (client-tool parks excluded — the client-tool bridge owns those, and a\n * generic resume would corrupt the parked tool call).\n */\n interruptPredicate?: StatewireInterruptPredicate;\n /**\n * How long a sent decision keeps the actions locked when no resume run ever\n * starts. Defaults to {@link HITL_PENDING_RESUME_GRACE_MS}.\n */\n pendingResumeGraceMs?: number;\n /**\n * The host refused the `run/input` (or the transport lost it): the\n * optimistic fold rolls back, the request is on screen again with its\n * actions re-enabled, and this is the surface's one chance to say why.\n */\n onResumeRejected?: (error: unknown, requestId: string) => void;\n /** See {@link UseApprovalResumeLockOptions.onResumeRetry}. */\n onResumeRetry?: (error: unknown, requestId: string, attempt: number) => void;\n}\n\nexport interface StatewireApprovalRequest<TValue> {\n /** The pending interrupt this surface answers, if any. */\n request: StatewireThread.CustomInputRequest | undefined;\n requestId: string | undefined;\n /** The payload narrowed to the Athena HITL approval shape, or `null`. */\n hitl: HitlApprovalPayload | null;\n /** Every gated call the approval covers, in decision order (empty for non-HITL parks). */\n actionRequests: PendingActionRequest[];\n /** An interrupt a non-resume dispatch dropped — the \"approval was cancelled\" notice. */\n abandonedInterrupt: AbandonedInputRequest | undefined;\n /**\n * The mirrored interrupt's HITL payload while the run is still live and no\n * input request is answerable: per-dispatch `task` lanes parked on their\n * gates while sibling lanes stream. `null` once the run parks (the same\n * lanes are then `hitl` / `actionRequests`) and when nothing is parked.\n */\n liveHitl: HitlApprovalPayload | null;\n /** Every gated call `liveHitl` covers (empty when it is `null`). */\n liveActionRequests: PendingActionRequest[];\n /**\n * The decisions the host already holds from a `run/lane-input`, keyed by\n * langgraph interrupt id, to be answered when the run parks — a queued lane\n * reads as decided on every attached client, not just the one that sent it.\n */\n queuedLaneDecisions: Readonly<Record<string, unknown>>;\n /** True after a resume until the request identity changes (or recovery fires). */\n pending: boolean;\n /**\n * Answer the request with `{ type: 'run/input', requestId, response: { type: 'resume', value } }`.\n * Returns the dispatch promise (settles when the host accepts, rejects when\n * it refuses), or `undefined` when the lock dropped the send.\n */\n resume: (value: TValue) => Promise<unknown> | undefined;\n /**\n * Decide per-dispatch lanes by langgraph interrupt id. With a pending\n * request this is the native `lane_decisions` resume through the lock;\n * without one (the run is still streaming siblings) it is `run/lane-input`,\n * which the host queues and answers on the park. Returns the dispatch\n * promise, or `undefined` when the lock dropped a resume.\n */\n sendLaneDecisions: (\n lanes: Readonly<Record<string, StatewireThread.InputResponse>>,\n ) => Promise<unknown> | undefined;\n}\n\n/**\n * The headless half of every statewire approval surface: selects the pending\n * interrupt from the runs projection, narrows its payload, reads the\n * host-published abandoned interrupts, and wires the shared optimistic resume\n * lock to the thread's `run/input` command. `StatewireApprovalCard` renders\n * over it; hosts with their own decision UI (per-lane subagent cards) build\n * on it directly so the selection and lock semantics cannot drift.\n *\n * Requires a statewire aui scope (throws outside one, like every\n * `useStatewire*` hook) — gate the mount with `hasStatewireThreadExtras`.\n */\nexport function useStatewireApprovalRequest<\n TValue extends StatewireThread.InputResponse = Record<string, string>,\n>(options: UseStatewireApprovalRequestOptions = {}): StatewireApprovalRequest<TValue> {\n const {\n interruptPredicate = isApprovalCardInterrupt,\n pendingResumeGraceMs = HITL_PENDING_RESUME_GRACE_MS,\n onResumeRejected,\n onResumeRetry,\n } = options;\n const sendCommand = useStatewireSendCommand();\n // The runs projection is memoized by the lib, so this derivation is\n // reference-stable between state updates.\n const request = useStatewireRuns().inputRequests?.find(interruptPredicate);\n const requestId = request?.id;\n\n // The host publishes the interrupts a non-resume dispatch dropped. Select\n // the raw array reference (pre-stream-safe) and derive inline; a `.find`\n // selector would return a fresh object every update.\n const abandoned = useStatewireState(readAbandonedInputRequests);\n const abandonedInterrupt = findAbandonedInterrupt(abandoned);\n\n const hitl = asHitlApproval(request?.payload);\n const actionRequests = useMemo(() => pendingActionRequests(hitl), [hitl]);\n\n const isRunning = useAthenaRunLive();\n // The host mirrors the interrupt into state as soon as a lane parks — while\n // the run manager still reports `running` (siblings streaming) and has no\n // request to answer. Raw reference selectors; derive inline.\n const mirror = useStatewireState(readInterruptMirror);\n const liveHitl =\n request === undefined && isRunning ? asHitlApproval(interruptMirrorPayload(mirror)) : null;\n const liveActionRequests = useMemo(() => pendingActionRequests(liveHitl), [liveHitl]);\n const queuedLaneDecisions =\n useStatewireState(readQueuedLaneDecisions) ?? NO_QUEUED_LANE_DECISIONS;\n\n const { pending, resume } = useApprovalResumeLock<TValue>({\n requestId,\n isRunning,\n pendingResumeGraceMs,\n onResumeRejected,\n onResumeRetry,\n // The dispatch promise is handed to the lock: a refusal releases it and\n // reaches `onResumeRejected`.\n sendResume: (id, value) =>\n sendCommand({\n type: 'run/input',\n requestId: id,\n response: { type: 'resume', value },\n }),\n });\n\n const sendLaneDecisions = useCallback(\n (lanes: Readonly<Record<string, StatewireThread.InputResponse>>) =>\n requestId !== undefined\n ? resume({ lane_decisions: lanes } as unknown as TValue)\n : sendCommand({ type: 'run/lane-input', laneDecisions: lanes }),\n [requestId, resume, sendCommand],\n );\n\n return {\n request,\n requestId,\n hitl,\n actionRequests,\n liveHitl,\n liveActionRequests,\n queuedLaneDecisions,\n abandonedInterrupt,\n pending,\n resume,\n sendLaneDecisions,\n };\n}\n"],"names":[],"mappings":";;;;AA2CA,MAAM,2BAA8D,OAAO,OAAO,EAAE;AAqF7E,SAAS,4BAEd,UAA8C,IAAsC;;AACpF,QAAM;AAAA,IACJ,qBAAqB;AAAA,IACrB,uBAAuB;AAAA,IACvB;AAAA,IACA;AAAA,EAAA,IACE;AACJ,QAAM,cAAc,wBAAA;AAGpB,QAAM,WAAU,sBAAA,EAAmB,kBAAnB,mBAAkC,KAAK;AACvD,QAAM,YAAY,mCAAS;AAK3B,QAAM,YAAY,kBAAkB,0BAA0B;AAC9D,QAAM,qBAAqB,uBAAuB,SAAS;AAE3D,QAAM,OAAO,eAAe,mCAAS,OAAO;AAC5C,QAAM,iBAAiB,QAAQ,MAAM,sBAAsB,IAAI,GAAG,CAAC,IAAI,CAAC;AAExE,QAAM,YAAY,iBAAA;AAIlB,QAAM,SAAS,kBAAkB,mBAAmB;AACpD,QAAM,WACJ,YAAY,UAAa,YAAY,eAAe,uBAAuB,MAAM,CAAC,IAAI;AACxF,QAAM,qBAAqB,QAAQ,MAAM,sBAAsB,QAAQ,GAAG,CAAC,QAAQ,CAAC;AACpF,QAAM,sBACJ,kBAAkB,uBAAuB,KAAK;AAEhD,QAAM,EAAE,SAAS,OAAA,IAAW,sBAA8B;AAAA,IACxD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA,IAGA,YAAY,CAAC,IAAI,UACf,YAAY;AAAA,MACV,MAAM;AAAA,MACN,WAAW;AAAA,MACX,UAAU,EAAE,MAAM,UAAU,MAAA;AAAA,IAAM,CACnC;AAAA,EAAA,CACJ;AAED,QAAM,oBAAoB;AAAA,IACxB,CAAC,UACC,cAAc,SACV,OAAO,EAAE,gBAAgB,MAAA,CAA4B,IACrD,YAAY,EAAE,MAAM,kBAAkB,eAAe,OAAO;AAAA,IAClE,CAAC,WAAW,QAAQ,WAAW;AAAA,EAAA;AAGjC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;"}
|
|
@@ -15,23 +15,8 @@ const mentionSuggestions_extension = require("../mentions/suggestions/mention-su
|
|
|
15
15
|
const mentionSuggestionPopup = require("../mentions/suggestions/components/mention-suggestion-popup.cjs");
|
|
16
16
|
const mentionSuggestionList = require("../mentions/suggestions/components/mention-suggestion-list.cjs");
|
|
17
17
|
const useMentionSuggestions = require("../mentions/suggestions/data/use-mention-suggestions.cjs");
|
|
18
|
-
const assetAttachment = require("../../packages/agent-runtime/src/asset-attachment.cjs");
|
|
19
|
-
require("../../packages/agent-runtime/src/generated/runconfig-contract.cjs");
|
|
20
|
-
require("@assistant-ui/tap");
|
|
21
|
-
require("statewire");
|
|
22
|
-
require("../../packages/agent-runtime/src/statewire-suspended.cjs");
|
|
23
|
-
require("../../packages/agent-runtime/src/conversation-list.cjs");
|
|
24
|
-
require("@tanstack/react-query");
|
|
25
|
-
require("../../packages/agent-runtime/src/statewire-state.cjs");
|
|
26
|
-
require("../../packages/agent-runtime/src/messages.cjs");
|
|
27
|
-
require("@assistant-ui/store");
|
|
28
|
-
require("../../packages/agent-runtime/src/quota-safe-local-storage-session.cjs");
|
|
29
|
-
require("../../packages/agent-runtime/src/statewire-attach-observer.cjs");
|
|
30
|
-
require("../../packages/agent-runtime/src/thread-status.cjs");
|
|
31
|
-
require("@assistant-ui/react-statewire");
|
|
32
|
-
require("@assistant-ui/core");
|
|
33
|
-
require("../../packages/agent-runtime/src/thread-handoff.cjs");
|
|
34
18
|
const pendingAttachmentUploads = require("./pending-attachment-uploads.cjs");
|
|
19
|
+
const assetAttachment = require("../../packages/agent-runtime/src/asset-attachment.cjs");
|
|
35
20
|
const cnfast = require("cnfast");
|
|
36
21
|
const SubmitKeybind = core.Extension.create({
|
|
37
22
|
name: "submitKeybind",
|