@athenaintel/react 0.42.2 → 0.48.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 +225 -3
- package/dist/agent-runtime/src/answer-label.cjs +137 -0
- package/dist/agent-runtime/src/answer-label.cjs.map +1 -0
- package/dist/agent-runtime/src/answer-label.d.ts +104 -0
- package/dist/agent-runtime/src/answer-label.js +137 -0
- package/dist/agent-runtime/src/answer-label.js.map +1 -0
- package/dist/agent-runtime/src/answer-rows.cjs +180 -0
- package/dist/agent-runtime/src/answer-rows.cjs.map +1 -0
- package/dist/agent-runtime/src/answer-rows.d.ts +86 -0
- package/dist/agent-runtime/src/answer-rows.js +180 -0
- package/dist/agent-runtime/src/answer-rows.js.map +1 -0
- package/dist/agent-runtime/src/client-tool-bridge.cjs +15 -15
- package/dist/agent-runtime/src/client-tool-bridge.cjs.map +1 -1
- package/dist/agent-runtime/src/conversation-index.cjs +8 -8
- package/dist/agent-runtime/src/conversation-index.cjs.map +1 -1
- package/dist/agent-runtime/src/conversation-list-groups.d.ts +74 -0
- package/dist/agent-runtime/src/decision-checks.cjs +207 -0
- package/dist/agent-runtime/src/decision-checks.cjs.map +1 -0
- package/dist/agent-runtime/src/decision-checks.d.ts +142 -0
- package/dist/agent-runtime/src/decision-checks.js +207 -0
- package/dist/agent-runtime/src/decision-checks.js.map +1 -0
- package/dist/agent-runtime/src/desktop-handoff.d.ts +12 -0
- package/dist/agent-runtime/src/errors.cjs +18 -0
- package/dist/agent-runtime/src/errors.cjs.map +1 -1
- package/dist/agent-runtime/src/errors.d.ts +7 -0
- package/dist/agent-runtime/src/errors.js +18 -0
- package/dist/agent-runtime/src/errors.js.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs +12 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +6 -6
- package/dist/agent-runtime/src/generated/runconfig-contract.js +12 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
- package/dist/agent-runtime/src/handoff-arrival.cjs +60 -0
- package/dist/agent-runtime/src/handoff-arrival.cjs.map +1 -0
- package/dist/agent-runtime/src/handoff-arrival.d.ts +46 -0
- package/dist/agent-runtime/src/handoff-arrival.js +60 -0
- package/dist/agent-runtime/src/handoff-arrival.js.map +1 -0
- package/dist/agent-runtime/src/index.d.ts +15 -8
- package/dist/agent-runtime/src/interrupts.cjs +43 -18
- package/dist/agent-runtime/src/interrupts.cjs.map +1 -1
- package/dist/agent-runtime/src/interrupts.d.ts +19 -2
- package/dist/agent-runtime/src/interrupts.js +28 -3
- package/dist/agent-runtime/src/interrupts.js.map +1 -1
- package/dist/agent-runtime/src/lane-history.cjs +8 -8
- package/dist/agent-runtime/src/lane-history.cjs.map +1 -1
- package/dist/agent-runtime/src/messages.cjs +43 -8
- package/dist/agent-runtime/src/messages.cjs.map +1 -1
- package/dist/agent-runtime/src/messages.d.ts +25 -3
- package/dist/agent-runtime/src/messages.js +43 -8
- package/dist/agent-runtime/src/messages.js.map +1 -1
- package/dist/agent-runtime/src/offline-status.cjs +36 -0
- package/dist/agent-runtime/src/offline-status.cjs.map +1 -0
- package/dist/agent-runtime/src/offline-status.d.ts +118 -3
- package/dist/agent-runtime/src/offline-status.js +36 -0
- package/dist/agent-runtime/src/offline-status.js.map +1 -0
- package/dist/agent-runtime/src/queue.cjs +0 -9
- package/dist/agent-runtime/src/queue.cjs.map +1 -1
- package/dist/agent-runtime/src/queue.js +0 -9
- package/dist/agent-runtime/src/queue.js.map +1 -1
- package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +9 -9
- package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
- package/dist/agent-runtime/src/runtime-catalog.cjs +42 -0
- package/dist/agent-runtime/src/runtime-catalog.cjs.map +1 -0
- package/dist/agent-runtime/src/runtime-catalog.d.ts +35 -0
- package/dist/agent-runtime/src/runtime-catalog.js +42 -0
- package/dist/agent-runtime/src/runtime-catalog.js.map +1 -0
- package/dist/agent-runtime/src/runtime-messages.cjs.map +1 -1
- package/dist/agent-runtime/src/runtime-messages.d.ts +1 -1
- package/dist/agent-runtime/src/runtime-messages.js.map +1 -1
- package/dist/agent-runtime/src/runtime.d.ts +40 -0
- package/dist/agent-runtime/src/statewire-suspended.cjs +3 -3
- package/dist/agent-runtime/src/statewire-suspended.cjs.map +1 -1
- package/dist/agent-runtime/src/subagents.cjs +32 -2
- package/dist/agent-runtime/src/subagents.cjs.map +1 -1
- package/dist/agent-runtime/src/subagents.d.ts +9 -0
- package/dist/agent-runtime/src/subagents.js +30 -0
- package/dist/agent-runtime/src/subagents.js.map +1 -1
- package/dist/agent-runtime/src/thread-driver.cjs +67 -0
- package/dist/agent-runtime/src/thread-driver.cjs.map +1 -0
- package/dist/agent-runtime/src/thread-driver.d.ts +49 -0
- package/dist/agent-runtime/src/thread-driver.js +67 -0
- package/dist/agent-runtime/src/thread-driver.js.map +1 -0
- package/dist/agent-runtime/src/thread-handoff-flow-machine.d.ts +172 -0
- package/dist/agent-runtime/src/thread-handoff-protocol.d.ts +756 -0
- package/dist/agent-runtime/src/thread-handoff-qr.d.ts +11 -0
- package/dist/agent-runtime/src/thread-handoff.d.ts +3 -364
- package/dist/agent-runtime/src/thread-status.cjs +3 -3
- package/dist/agent-runtime/src/thread-status.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.cjs +210 -33
- package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.d.ts +12 -0
- package/dist/agent-runtime/src/tool-metadata.js +210 -33
- package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
- package/dist/agent-runtime/src/tool-names.cjs +2 -0
- package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-names.d.ts +2 -0
- package/dist/agent-runtime/src/tool-names.js +2 -0
- package/dist/agent-runtime/src/tool-names.js.map +1 -1
- package/dist/agent-runtime/src/types.d.ts +10 -2
- package/dist/agent-runtime/src/use-conversation-list.cjs +11 -11
- package/dist/agent-runtime/src/use-conversation-list.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs +24 -19
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.d.ts +2 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js +6 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-config.cjs +14 -14
- package/dist/agent-runtime/src/use-deep-agent-config.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs +6 -6
- package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +16 -16
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs +45 -45
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs +572 -134
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +137 -10
- package/dist/agent-runtime/src/use-deep-agent-voice.js +514 -76
- package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs +26 -26
- package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs.map +1 -1
- package/dist/agent-runtime/src/use-historical-edit-attachments.cjs +4 -4
- package/dist/agent-runtime/src/use-historical-edit-attachments.cjs.map +1 -1
- package/dist/agent-runtime/src/use-thread-handoff-flow.d.ts +28 -26
- package/dist/agent-runtime/src/voice-media.cjs +117 -0
- package/dist/agent-runtime/src/voice-media.cjs.map +1 -0
- package/dist/agent-runtime/src/voice-media.d.ts +49 -0
- package/dist/agent-runtime/src/voice-media.js +117 -0
- package/dist/agent-runtime/src/voice-media.js.map +1 -0
- package/dist/agent-runtime/src/voice-wire-types.d.ts +32 -0
- package/dist/assets/AssetPanel.cjs +11 -11
- package/dist/assets/AssetPanel.cjs.map +1 -1
- package/dist/assets/AthenaAssetEmbed.cjs +11 -9
- package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
- package/dist/assets/AthenaAssetEmbed.d.ts +7 -0
- package/dist/assets/AthenaAssetEmbed.js +4 -2
- package/dist/assets/AthenaAssetEmbed.js.map +1 -1
- package/dist/assets/AthenaLayout.cjs +16 -16
- package/dist/assets/AthenaLayout.cjs.map +1 -1
- package/dist/assets/use-asset-content.cjs +4 -4
- package/dist/assets/use-asset-content.cjs.map +1 -1
- package/dist/assets/use-asset-embed.cjs +14 -7
- package/dist/assets/use-asset-embed.cjs.map +1 -1
- package/dist/assets/use-asset-embed.d.ts +11 -1
- package/dist/assets/use-asset-embed.js +10 -3
- package/dist/assets/use-asset-embed.js.map +1 -1
- package/dist/auth/AthenaAuthContext.cjs +3 -3
- package/dist/auth/AthenaAuthContext.cjs.map +1 -1
- package/dist/auth/AthenaAuthProvider.cjs +8 -8
- package/dist/auth/AthenaAuthProvider.cjs.map +1 -1
- package/dist/auth/AthenaCredentialSourceContext.cjs +5 -5
- package/dist/auth/AthenaCredentialSourceContext.cjs.map +1 -1
- package/dist/auth/AthenaSSOProvider.cjs +14 -14
- package/dist/auth/AthenaSSOProvider.cjs.map +1 -1
- package/dist/auth/credential-source.cjs +26 -13
- package/dist/auth/credential-source.cjs.map +1 -1
- package/dist/auth/credential-source.d.ts +8 -0
- package/dist/auth/credential-source.js +26 -13
- package/dist/auth/credential-source.js.map +1 -1
- package/dist/catalog/agent-model-options.cjs +25 -17
- package/dist/catalog/agent-model-options.cjs.map +1 -1
- package/dist/catalog/agent-model-options.d.ts +38 -5
- package/dist/catalog/agent-model-options.js +25 -17
- package/dist/catalog/agent-model-options.js.map +1 -1
- package/dist/catalog/channel-refusal.cjs +36 -0
- package/dist/catalog/channel-refusal.cjs.map +1 -0
- package/dist/catalog/channel-refusal.d.ts +29 -0
- package/dist/catalog/channel-refusal.js +36 -0
- package/dist/catalog/channel-refusal.js.map +1 -0
- package/dist/catalog/chat-pickers.cjs +60 -24
- package/dist/catalog/chat-pickers.cjs.map +1 -1
- package/dist/catalog/chat-pickers.d.ts +12 -2
- package/dist/catalog/chat-pickers.js +56 -20
- package/dist/catalog/chat-pickers.js.map +1 -1
- package/dist/catalog/runtime-catalog.cjs +89 -23
- package/dist/catalog/runtime-catalog.cjs.map +1 -1
- package/dist/catalog/runtime-catalog.d.ts +8 -2
- package/dist/catalog/runtime-catalog.js +83 -17
- package/dist/catalog/runtime-catalog.js.map +1 -1
- package/dist/catalog/use-athena-chat-mode.cjs +12 -12
- package/dist/catalog/use-athena-chat-mode.cjs.map +1 -1
- package/dist/chat/AthenaChat.cjs +155 -67
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.d.ts +42 -2
- package/dist/chat/AthenaChat.js +106 -18
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/AthenaChatErrorBoundary.cjs +3 -3
- package/dist/chat/AthenaChatErrorBoundary.cjs.map +1 -1
- package/dist/chat/DrivingOnChip.cjs +23 -0
- package/dist/chat/DrivingOnChip.cjs.map +1 -0
- package/dist/chat/DrivingOnChip.d.ts +17 -0
- package/dist/chat/DrivingOnChip.js +23 -0
- package/dist/chat/DrivingOnChip.js.map +1 -0
- package/dist/chat/StatewireApprovalCard.cjs +125 -31
- package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
- package/dist/chat/StatewireApprovalCard.d.ts +73 -1
- package/dist/chat/StatewireApprovalCard.js +115 -21
- package/dist/chat/StatewireApprovalCard.js.map +1 -1
- package/dist/chat/StatewireClientToolBridge.cjs +2 -2
- package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
- package/dist/chat/StatewireQueuedMessages.cjs +25 -63
- package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
- package/dist/chat/StatewireQueuedMessages.d.ts +11 -13
- package/dist/chat/StatewireQueuedMessages.js +16 -54
- package/dist/chat/StatewireQueuedMessages.js.map +1 -1
- package/dist/chat/WaitingOnYouBanner.cjs +3 -3
- package/dist/chat/WaitingOnYouBanner.cjs.map +1 -1
- package/dist/chat/athena-chat-welcome.cjs +2 -2
- package/dist/chat/athena-chat-welcome.cjs.map +1 -1
- package/dist/chat/athena-citation-links.cjs +5 -5
- package/dist/chat/athena-citation-links.cjs.map +1 -1
- package/dist/chat/athena-composer-controls.cjs +26 -16
- package/dist/chat/athena-composer-controls.cjs.map +1 -1
- package/dist/chat/athena-composer-controls.d.ts +6 -0
- package/dist/chat/athena-composer-controls.js +26 -16
- package/dist/chat/athena-composer-controls.js.map +1 -1
- package/dist/chat/athena-turn-end-status.cjs +42 -0
- package/dist/chat/athena-turn-end-status.cjs.map +1 -0
- package/dist/chat/athena-turn-end-status.d.ts +24 -0
- package/dist/chat/athena-turn-end-status.js +42 -0
- package/dist/chat/athena-turn-end-status.js.map +1 -0
- package/dist/chat/browser-decision-check.cjs +131 -0
- package/dist/chat/browser-decision-check.cjs.map +1 -0
- package/dist/chat/browser-decision-check.d.ts +61 -0
- package/dist/chat/browser-decision-check.js +131 -0
- package/dist/chat/browser-decision-check.js.map +1 -0
- package/dist/chat/chat-outbox-rows.cjs +3 -3
- package/dist/chat/chat-outbox-rows.cjs.map +1 -1
- package/dist/chat/chat-voice-controls.cjs +93 -28
- package/dist/chat/chat-voice-controls.cjs.map +1 -1
- package/dist/chat/chat-voice-controls.d.ts +36 -2
- package/dist/chat/chat-voice-controls.js +89 -24
- package/dist/chat/chat-voice-controls.js.map +1 -1
- package/dist/chat/composer-keyboard-hint.cjs +5 -5
- package/dist/chat/composer-keyboard-hint.cjs.map +1 -1
- package/dist/chat/device-operation.cjs +29 -0
- package/dist/chat/device-operation.cjs.map +1 -0
- package/dist/chat/device-operation.d.ts +34 -0
- package/dist/chat/device-operation.js +29 -0
- package/dist/chat/device-operation.js.map +1 -0
- package/dist/chat/super-grouping/CollapsibleGroup.cjs +14 -14
- package/dist/chat/super-grouping/CollapsibleGroup.cjs.map +1 -1
- package/dist/chat/super-grouping/GroupedMessageParts.cjs +4 -4
- package/dist/chat/super-grouping/GroupedMessageParts.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.cjs +60 -38
- package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.d.ts +24 -4
- package/dist/chat/super-grouping/SuperGroupingCard.js +37 -15
- package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs +32 -32
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.js +3 -3
- package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
- package/dist/chat/super-grouping/ToolTimeline.cjs +97 -37
- package/dist/chat/super-grouping/ToolTimeline.cjs.map +1 -1
- package/dist/chat/super-grouping/ToolTimeline.d.ts +14 -2
- package/dist/chat/super-grouping/ToolTimeline.js +94 -34
- package/dist/chat/super-grouping/ToolTimeline.js.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.cjs +47 -12
- package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.d.ts +21 -0
- package/dist/chat/super-grouping/activity-timeline.js +47 -12
- package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
- package/dist/chat/super-grouping/grouping-function.cjs +4 -0
- package/dist/chat/super-grouping/grouping-function.cjs.map +1 -1
- package/dist/chat/super-grouping/grouping-function.d.ts +7 -0
- package/dist/chat/super-grouping/grouping-function.js +5 -1
- package/dist/chat/super-grouping/grouping-function.js.map +1 -1
- package/dist/chat/super-grouping/index.cjs +6 -0
- package/dist/chat/super-grouping/index.cjs.map +1 -1
- package/dist/chat/super-grouping/index.d.ts +6 -2
- package/dist/chat/super-grouping/index.js +7 -1
- package/dist/chat/super-grouping/index.js.map +1 -1
- package/dist/chat/super-grouping/timeline-step.cjs +61 -2
- package/dist/chat/super-grouping/timeline-step.cjs.map +1 -1
- package/dist/chat/super-grouping/timeline-step.d.ts +13 -1
- package/dist/chat/super-grouping/timeline-step.js +61 -2
- package/dist/chat/super-grouping/timeline-step.js.map +1 -1
- package/dist/chat/super-grouping/tool-part-placement.cjs +17 -0
- package/dist/chat/super-grouping/tool-part-placement.cjs.map +1 -0
- package/dist/chat/super-grouping/tool-part-placement.d.ts +22 -0
- package/dist/chat/super-grouping/tool-part-placement.js +17 -0
- package/dist/chat/super-grouping/tool-part-placement.js.map +1 -0
- package/dist/chat/thread-scroll-to-bottom.cjs +2 -2
- package/dist/chat/thread-scroll-to-bottom.cjs.map +1 -1
- package/dist/chat/thread-scroll-to-bottom.d.ts +10 -7
- package/dist/chat/thread-scroll-to-bottom.js +2 -2
- package/dist/chat/thread-scroll-to-bottom.js.map +1 -1
- package/dist/chat/tooltip-icon-button.cjs +2 -2
- package/dist/chat/tooltip-icon-button.cjs.map +1 -1
- package/dist/chat/use-athena-voice-live.cjs +11 -0
- package/dist/chat/use-athena-voice-live.cjs.map +1 -0
- package/dist/chat/use-athena-voice-live.d.ts +11 -0
- package/dist/chat/use-athena-voice-live.js +11 -0
- package/dist/chat/use-athena-voice-live.js.map +1 -0
- package/dist/chat/use-statewire-approval-request.cjs +56 -24
- package/dist/chat/use-statewire-approval-request.cjs.map +1 -1
- package/dist/chat/use-statewire-approval-request.d.ts +33 -4
- package/dist/chat/use-statewire-approval-request.js +41 -9
- package/dist/chat/use-statewire-approval-request.js.map +1 -1
- package/dist/chat-ui/auth/sign-in-card.cjs +2 -2
- package/dist/chat-ui/auth/sign-in-card.cjs.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.cjs +138 -107
- package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.d.ts +20 -4
- package/dist/chat-ui/composer/tiptap-composer.js +85 -54
- package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
- package/dist/chat-ui/header/conversation-history-panel.cjs +49 -23
- package/dist/chat-ui/header/conversation-history-panel.cjs.map +1 -1
- package/dist/chat-ui/header/conversation-history-panel.d.ts +12 -1
- package/dist/chat-ui/header/conversation-history-panel.js +38 -12
- package/dist/chat-ui/header/conversation-history-panel.js.map +1 -1
- package/dist/chat-ui/index.cjs +18 -0
- package/dist/chat-ui/index.cjs.map +1 -1
- package/dist/chat-ui/index.d.ts +7 -1
- package/dist/chat-ui/index.js +18 -0
- package/dist/chat-ui/index.js.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.cjs +147 -38
- package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.d.ts +17 -1
- package/dist/chat-ui/mentions/mention-chip.js +146 -37
- package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.cjs +10 -9
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.js +3 -2
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-popup.cjs +2 -2
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-popup.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/menu-list.cjs +29 -6
- package/dist/chat-ui/mentions/suggestions/components/menu-list.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/menu-list.d.ts +7 -1
- package/dist/chat-ui/mentions/suggestions/components/menu-list.js +25 -2
- package/dist/chat-ui/mentions/suggestions/components/menu-list.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/use-keyboard-navigation.cjs +2 -2
- package/dist/chat-ui/mentions/suggestions/components/use-keyboard-navigation.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/use-menu-navigation.cjs +2 -2
- package/dist/chat-ui/mentions/suggestions/components/use-menu-navigation.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +3 -3
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.cjs +56 -2
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.d.ts +12 -0
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.js +56 -2
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +24 -3
- package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/index.d.ts +7 -0
- package/dist/chat-ui/mentions/suggestions/data/sources/index.js +24 -3
- package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs +35 -13
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.d.ts +15 -1
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js +28 -6
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.cjs +9 -6
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.d.ts +3 -0
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.js +5 -2
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.js.map +1 -1
- package/dist/chat-ui/mentions/use-account-workspace-id.cjs +45 -10
- package/dist/chat-ui/mentions/use-account-workspace-id.cjs.map +1 -1
- package/dist/chat-ui/mentions/use-account-workspace-id.d.ts +24 -1
- package/dist/chat-ui/mentions/use-account-workspace-id.js +46 -11
- package/dist/chat-ui/mentions/use-account-workspace-id.js.map +1 -1
- package/dist/chat-ui/mentions/use-member-avatar.cjs +4 -4
- package/dist/chat-ui/mentions/use-member-avatar.cjs.map +1 -1
- package/dist/chat-ui/mentions/use-mention-asset.cjs +140 -0
- package/dist/chat-ui/mentions/use-mention-asset.cjs.map +1 -0
- package/dist/chat-ui/mentions/use-mention-asset.d.ts +16 -0
- package/dist/chat-ui/mentions/use-mention-asset.js +140 -0
- package/dist/chat-ui/mentions/use-mention-asset.js.map +1 -0
- package/dist/chat-ui/messages/answer-label.cjs +42 -0
- package/dist/chat-ui/messages/answer-label.cjs.map +1 -0
- package/dist/chat-ui/messages/answer-label.d.ts +33 -0
- package/dist/chat-ui/messages/answer-label.js +42 -0
- package/dist/chat-ui/messages/answer-label.js.map +1 -0
- package/dist/chat-ui/messages/arrival-animation.cjs +13 -0
- package/dist/chat-ui/messages/arrival-animation.cjs.map +1 -0
- package/dist/chat-ui/messages/arrival-animation.d.ts +14 -0
- package/dist/chat-ui/messages/arrival-animation.js +13 -0
- package/dist/chat-ui/messages/arrival-animation.js.map +1 -0
- package/dist/chat-ui/messages/continue-pill.cjs +5 -5
- package/dist/chat-ui/messages/continue-pill.cjs.map +1 -1
- package/dist/chat-ui/messages/handoff-arrival-divider.cjs +44 -0
- package/dist/chat-ui/messages/handoff-arrival-divider.cjs.map +1 -0
- package/dist/chat-ui/messages/handoff-arrival-divider.d.ts +17 -0
- package/dist/chat-ui/messages/handoff-arrival-divider.js +44 -0
- package/dist/chat-ui/messages/handoff-arrival-divider.js.map +1 -0
- package/dist/chat-ui/messages/message-actions-config.cjs +3 -3
- package/dist/chat-ui/messages/message-actions-config.cjs.map +1 -1
- package/dist/chat-ui/messages/message-components.cjs +8 -4
- package/dist/chat-ui/messages/message-components.cjs.map +1 -1
- package/dist/chat-ui/messages/message-components.js +5 -1
- package/dist/chat-ui/messages/message-components.js.map +1 -1
- package/dist/chat-ui/messages/message-images.cjs +66 -0
- package/dist/chat-ui/messages/message-images.cjs.map +1 -0
- package/dist/chat-ui/messages/message-images.d.ts +16 -0
- package/dist/chat-ui/messages/message-images.js +66 -0
- package/dist/chat-ui/messages/message-images.js.map +1 -0
- package/dist/chat-ui/messages/user-edit-composer.cjs +2 -2
- package/dist/chat-ui/messages/user-edit-composer.cjs.map +1 -1
- package/dist/chat-ui/messages/wake-marker.cjs +3 -3
- package/dist/chat-ui/messages/wake-marker.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-link.cjs +7 -6
- package/dist/chat-ui/rich-text/chat-link.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-link.d.ts +2 -3
- package/dist/chat-ui/rich-text/chat-link.js +6 -5
- package/dist/chat-ui/rich-text/chat-link.js.map +1 -1
- package/dist/chat-ui/rich-text/chat-message-body.cjs +8 -8
- package/dist/chat-ui/rich-text/chat-message-body.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-node-views.cjs +7 -6
- package/dist/chat-ui/rich-text/chat-node-views.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-node-views.js +1 -0
- package/dist/chat-ui/rich-text/chat-node-views.js.map +1 -1
- package/dist/chat-ui/rich-text/dom-output-spec.cjs +2 -2
- package/dist/chat-ui/rich-text/dom-output-spec.cjs.map +1 -1
- package/dist/chat-ui/statewire.cjs +3 -0
- package/dist/chat-ui/statewire.cjs.map +1 -1
- package/dist/chat-ui/statewire.d.ts +2 -1
- package/dist/chat-ui/statewire.js +3 -0
- package/dist/chat-ui/statewire.js.map +1 -1
- package/dist/chat-ui/thread/chat-thread-shell.cjs +43 -14
- package/dist/chat-ui/thread/chat-thread-shell.cjs.map +1 -1
- package/dist/chat-ui/thread/chat-thread-shell.d.ts +16 -2
- package/dist/chat-ui/thread/chat-thread-shell.js +35 -6
- package/dist/chat-ui/thread/chat-thread-shell.js.map +1 -1
- package/dist/chat-ui/thread/composer-send-or-stop.cjs +30 -20
- package/dist/chat-ui/thread/composer-send-or-stop.cjs.map +1 -1
- package/dist/chat-ui/thread/composer-send-or-stop.d.ts +8 -0
- package/dist/chat-ui/thread/composer-send-or-stop.js +29 -19
- package/dist/chat-ui/thread/composer-send-or-stop.js.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.cjs +20 -21
- package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.js +3 -4
- package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
- package/dist/chat-ui/thread/thread-loading-overlay.cjs +5 -5
- package/dist/chat-ui/thread/thread-loading-overlay.cjs.map +1 -1
- package/dist/collab/client.cjs +40 -3
- package/dist/collab/client.cjs.map +1 -1
- package/dist/collab/client.d.ts +25 -0
- package/dist/collab/client.js +40 -3
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/document-status.cjs +150 -0
- package/dist/collab/document-status.cjs.map +1 -0
- package/dist/collab/document-status.d.ts +68 -0
- package/dist/collab/document-status.js +150 -0
- package/dist/collab/document-status.js.map +1 -0
- package/dist/collab/index.cjs +7 -0
- package/dist/collab/index.cjs.map +1 -1
- package/dist/collab/index.d.ts +6 -1
- package/dist/collab/index.js +7 -0
- package/dist/collab/index.js.map +1 -1
- package/dist/collab/presence-react.cjs +11 -11
- package/dist/collab/presence-react.cjs.map +1 -1
- package/dist/collab/react.cjs +6 -6
- package/dist/collab/react.cjs.map +1 -1
- package/dist/composer/AttachmentContext.cjs +24 -11
- package/dist/composer/AttachmentContext.cjs.map +1 -1
- package/dist/composer/AttachmentContext.js +18 -5
- package/dist/composer/AttachmentContext.js.map +1 -1
- package/dist/composer/ComposerAttachmentPreview.cjs +78 -23
- package/dist/composer/ComposerAttachmentPreview.cjs.map +1 -1
- package/dist/composer/ComposerAttachmentPreview.d.ts +5 -3
- package/dist/composer/ComposerAttachmentPreview.js +79 -24
- package/dist/composer/ComposerAttachmentPreview.js.map +1 -1
- package/dist/composer/ComposerDropZone.cjs +7 -7
- package/dist/composer/ComposerDropZone.cjs.map +1 -1
- package/dist/composer/FileUploadButton.cjs +37 -22
- package/dist/composer/FileUploadButton.cjs.map +1 -1
- package/dist/composer/FileUploadButton.d.ts +6 -0
- package/dist/composer/FileUploadButton.js +34 -19
- package/dist/composer/FileUploadButton.js.map +1 -1
- package/dist/composer/QuoteContext.cjs +8 -8
- package/dist/composer/QuoteContext.cjs.map +1 -1
- package/dist/composer/composer-handoff.cjs +4 -4
- package/dist/composer/composer-handoff.cjs.map +1 -1
- package/dist/composer/useAppendToComposer.cjs +4 -4
- package/dist/composer/useAppendToComposer.cjs.map +1 -1
- package/dist/composer/useAttachFiles.cjs +23 -6
- package/dist/composer/useAttachFiles.cjs.map +1 -1
- package/dist/composer/useAttachFiles.d.ts +15 -7
- package/dist/composer/useAttachFiles.js +22 -5
- package/dist/composer/useAttachFiles.js.map +1 -1
- package/dist/composer/useComposerAttachment.cjs +4 -4
- package/dist/composer/useComposerAttachment.cjs.map +1 -1
- package/dist/composer/useFileUpload.cjs +21 -16
- package/dist/composer/useFileUpload.cjs.map +1 -1
- package/dist/composer/useFileUpload.d.ts +12 -0
- package/dist/composer/useFileUpload.js +12 -7
- package/dist/composer/useFileUpload.js.map +1 -1
- package/dist/composer/useReadComposerDraft.cjs +2 -2
- package/dist/composer/useReadComposerDraft.cjs.map +1 -1
- package/dist/composer/useSendMessage.cjs +4 -4
- package/dist/composer/useSendMessage.cjs.map +1 -1
- package/dist/diagnostics/useAthenaDiagnostics.cjs +4 -4
- package/dist/diagnostics/useAthenaDiagnostics.cjs.map +1 -1
- package/dist/dictation/audio-level-history.cjs +3 -3
- package/dist/dictation/audio-level-history.cjs.map +1 -1
- package/dist/dictation/dictation-controls.cjs +24 -20
- package/dist/dictation/dictation-controls.cjs.map +1 -1
- package/dist/dictation/dictation-controls.d.ts +6 -1
- package/dist/dictation/dictation-controls.js +24 -20
- package/dist/dictation/dictation-controls.js.map +1 -1
- package/dist/dictation/use-athena-dictation-engine.cjs +3 -3
- package/dist/dictation/use-athena-dictation-engine.cjs.map +1 -1
- package/dist/dictation/use-dictation.cjs +22 -22
- package/dist/dictation/use-dictation.cjs.map +1 -1
- package/dist/index.cjs +26 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +15 -3
- package/dist/index.js +26 -2
- package/dist/index.js.map +1 -1
- package/dist/keryx-http/src/receive-only-socket.cjs +40 -0
- package/dist/keryx-http/src/receive-only-socket.cjs.map +1 -0
- package/dist/keryx-http/src/receive-only-socket.d.ts +27 -0
- package/dist/keryx-http/src/receive-only-socket.js +40 -0
- package/dist/keryx-http/src/receive-only-socket.js.map +1 -0
- package/dist/keryx-http/src/update-attributions.cjs +111 -0
- package/dist/keryx-http/src/update-attributions.cjs.map +1 -0
- package/dist/keryx-http/src/update-attributions.d.ts +75 -0
- package/dist/keryx-http/src/update-attributions.js +111 -0
- package/dist/keryx-http/src/update-attributions.js.map +1 -0
- package/dist/lib/owner-document.cjs +6 -6
- package/dist/lib/owner-document.cjs.map +1 -1
- package/dist/lib/use-athena-rest-query.cjs +4 -4
- package/dist/lib/use-athena-rest-query.cjs.map +1 -1
- package/dist/lib/use-document-active.cjs +4 -4
- package/dist/lib/use-document-active.cjs.map +1 -1
- package/dist/lib/use-prefers-reduced-motion.cjs +2 -2
- package/dist/lib/use-prefers-reduced-motion.cjs.map +1 -1
- package/dist/offline/offline-history.cjs +7 -7
- package/dist/offline/offline-history.cjs.map +1 -1
- package/dist/provider/AthenaContext.cjs +3 -3
- package/dist/provider/AthenaContext.cjs.map +1 -1
- package/dist/provider/AthenaProvider.cjs +116 -79
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.js +40 -3
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/provider/PostHogProvider.cjs +2 -2
- package/dist/provider/PostHogProvider.cjs.map +1 -1
- package/dist/provider/agent-selection-context.cjs +2 -2
- package/dist/provider/agent-selection-context.cjs.map +1 -1
- package/dist/provider/chat-mode-context.cjs +2 -2
- package/dist/provider/chat-mode-context.cjs.map +1 -1
- package/dist/provider/session-persistence-context.cjs +10 -0
- package/dist/provider/session-persistence-context.cjs.map +1 -0
- package/dist/provider/session-persistence-context.d.ts +15 -0
- package/dist/provider/session-persistence-context.js +10 -0
- package/dist/provider/session-persistence-context.js.map +1 -0
- package/dist/provider/statewire-history-context.cjs +4 -4
- package/dist/provider/statewire-history-context.cjs.map +1 -1
- package/dist/provider/statewire-lifecycle-context.cjs +3 -3
- package/dist/provider/statewire-lifecycle-context.cjs.map +1 -1
- package/dist/provider/statewire-window-context.cjs +3 -3
- package/dist/provider/statewire-window-context.cjs.map +1 -1
- package/dist/provider/theme-style-context.cjs +3 -3
- package/dist/provider/theme-style-context.cjs.map +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/references/src/tool-option-schemas.d.ts +0 -34
- package/dist/runtime/StatewireThreadConfigLaneSync.cjs +10 -10
- package/dist/runtime/StatewireThreadConfigLaneSync.cjs.map +1 -1
- package/dist/runtime/auth-refusal-restart.cjs +7 -7
- package/dist/runtime/auth-refusal-restart.cjs.map +1 -1
- package/dist/runtime/auth.cjs +13 -13
- package/dist/runtime/auth.cjs.map +1 -1
- package/dist/runtime/statewire-lifecycle.cjs +1 -0
- package/dist/runtime/statewire-lifecycle.cjs.map +1 -1
- package/dist/runtime/statewire-lifecycle.d.ts +3 -1
- package/dist/runtime/statewire-lifecycle.js +2 -1
- package/dist/runtime/statewire-lifecycle.js.map +1 -1
- package/dist/runtime/statewire-server-lane-context.cjs +2 -2
- package/dist/runtime/statewire-server-lane-context.cjs.map +1 -1
- package/dist/runtime/statewire-session-lane.cjs +4 -4
- package/dist/runtime/statewire-session-lane.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.cjs +10 -8
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.d.ts +2 -0
- package/dist/runtime/useAthenaStatewireRuntime.js +2 -0
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/threads/Inbox.cjs +8 -8
- package/dist/threads/Inbox.cjs.map +1 -1
- package/dist/threads/SessionList.cjs +9 -9
- package/dist/threads/SessionList.cjs.map +1 -1
- package/dist/threads/SessionsPage.cjs +11 -11
- package/dist/threads/SessionsPage.cjs.map +1 -1
- package/dist/threads/index-triggered-refresh.cjs +10 -10
- package/dist/threads/index-triggered-refresh.cjs.map +1 -1
- package/dist/threads/mark-viewed-thread-read.cjs +12 -12
- package/dist/threads/mark-viewed-thread-read.cjs.map +1 -1
- package/dist/threads/offline-session-list.cjs +3 -3
- package/dist/threads/offline-session-list.cjs.map +1 -1
- package/dist/threads/session-list-tab-share.cjs +5 -5
- package/dist/threads/session-list-tab-share.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.cjs +55 -51
- package/dist/threads/statewire-thread-list.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.js +6 -2
- package/dist/threads/statewire-thread-list.js.map +1 -1
- package/dist/threads/thread-id-context.cjs +5 -5
- package/dist/threads/thread-id-context.cjs.map +1 -1
- package/dist/threads/use-athena-session-attention.cjs +2 -2
- package/dist/threads/use-athena-session-attention.cjs.map +1 -1
- package/dist/threads/use-athena-sessions.cjs +10 -10
- package/dist/threads/use-athena-sessions.cjs.map +1 -1
- package/dist/threads/use-athena-thread-model.cjs +3 -3
- package/dist/threads/use-athena-thread-model.cjs.map +1 -1
- package/dist/threads/use-rest-conversation-history.cjs +3 -3
- package/dist/threads/use-rest-conversation-history.cjs.map +1 -1
- package/dist/threads/use-statewire-conversation-history.cjs +8 -8
- package/dist/threads/use-statewire-conversation-history.cjs.map +1 -1
- package/dist/threads/use-thread-archive.cjs +9 -9
- package/dist/threads/use-thread-archive.cjs.map +1 -1
- package/dist/threads/use-thread-favorite.cjs +2 -2
- package/dist/threads/use-thread-favorite.cjs.map +1 -1
- package/dist/threads/use-thread-field-override.cjs +20 -20
- package/dist/threads/use-thread-field-override.cjs.map +1 -1
- package/dist/threads/use-thread-read-state.cjs +4 -4
- package/dist/threads/use-thread-read-state.cjs.map +1 -1
- package/dist/threads/use-thread-rename.cjs +2 -2
- package/dist/threads/use-thread-rename.cjs.map +1 -1
- package/dist/threads/useAthenaThreadManager.cjs +2 -2
- package/dist/threads/useAthenaThreadManager.cjs.map +1 -1
- package/dist/tools/NestedPtcMessages.cjs +6 -6
- package/dist/tools/NestedPtcMessages.cjs.map +1 -1
- package/dist/tools/append-document-tool-ui.cjs +7 -7
- package/dist/tools/append-document-tool-ui.cjs.map +1 -1
- package/dist/tools/file-tool-uis.cjs +2 -2
- package/dist/tools/file-tool-uis.cjs.map +1 -1
- package/dist/tools/misc-tool-uis.cjs +2 -2
- package/dist/tools/misc-tool-uis.cjs.map +1 -1
- package/dist/tools/primitives.cjs +6 -6
- package/dist/tools/primitives.cjs.map +1 -1
- package/dist/tools/read-asset-tool-ui.cjs +6 -6
- package/dist/tools/read-asset-tool-ui.cjs.map +1 -1
- package/dist/tools/subagent-task-tool-ui.cjs +21 -21
- package/dist/tools/subagent-task-tool-ui.cjs.map +1 -1
- package/dist/tools/test-recording-tool-uis.cjs +16 -16
- package/dist/tools/test-recording-tool-uis.cjs.map +1 -1
- package/dist/tools/todo-plan-store.cjs +4 -4
- package/dist/tools/todo-plan-store.cjs.map +1 -1
- package/dist/tools/tool-appearance.cjs +3 -3
- package/dist/tools/tool-appearance.cjs.map +1 -1
- package/dist/tools/tool-fallback.cjs +14 -14
- package/dist/tools/tool-fallback.cjs.map +1 -1
- package/dist/tools/tool-summary.cjs +0 -2
- package/dist/tools/tool-summary.cjs.map +1 -1
- package/dist/tools/tool-summary.js +0 -2
- package/dist/tools/tool-summary.js.map +1 -1
- package/dist/tools/tool-uis.cjs +74 -74
- package/dist/tools/tool-uis.cjs.map +1 -1
- package/dist/tools/use-elapsed-seconds.cjs +3 -3
- package/dist/tools/use-elapsed-seconds.cjs.map +1 -1
- package/dist/tools/write-todos-tool-ui.cjs +9 -9
- package/dist/tools/write-todos-tool-ui.cjs.map +1 -1
- package/dist/ui/image-viewer.cjs +382 -0
- package/dist/ui/image-viewer.cjs.map +1 -0
- package/dist/ui/image-viewer.d.ts +50 -0
- package/dist/ui/image-viewer.js +382 -0
- package/dist/ui/image-viewer.js.map +1 -0
- package/dist/voice/chat.cjs +6 -0
- package/dist/voice/chat.cjs.map +1 -1
- package/dist/voice/chat.d.ts +1 -1
- package/dist/voice/chat.js +8 -2
- package/dist/voice/livekit-join.cjs +52 -101
- package/dist/voice/livekit-join.cjs.map +1 -1
- package/dist/voice/livekit-join.d.ts +1 -6
- package/dist/voice/livekit-join.js +52 -101
- package/dist/voice/livekit-join.js.map +1 -1
- package/dist/voice/livekit.cjs.map +1 -1
- package/dist/voice/livekit.d.ts +11 -1
- package/dist/voice/livekit.js.map +1 -1
- package/dist/voice/use-athena-voice-session.cjs +34 -34
- package/dist/voice/use-athena-voice-session.cjs.map +1 -1
- package/dist/workbench/ComputerLiveDesktop.cjs +13 -13
- package/dist/workbench/ComputerLiveDesktop.cjs.map +1 -1
- package/dist/workbench/SessionWorkbench.cjs +22 -22
- package/dist/workbench/SessionWorkbench.cjs.map +1 -1
- package/dist/workbench/session-workbench-context.cjs +3 -3
- package/dist/workbench/session-workbench-context.cjs.map +1 -1
- package/dist/workbench/session-workbench-panes.cjs +8 -8
- package/dist/workbench/session-workbench-panes.cjs.map +1 -1
- package/dist/workbench/workbench-layout-context.cjs +3 -3
- package/dist/workbench/workbench-layout-context.cjs.map +1 -1
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statewire-suspended.cjs","sources":["../../../../agent-runtime/src/statewire-suspended.ts"],"sourcesContent":["import { resource } from '@assistant-ui/tap';\nimport type { ResourceElement } from '@assistant-ui/tap';\nimport { useRef, useState } from 'react';\nimport type { Statewire, StatewireClient } from 'statewire';\nimport { StatewireSendError } from 'statewire';\n\nexport interface SuspendedStatewireOptions {\n /**\n * Why the transport is parked; surfaced as the connection message. Omitted\n * for a park that is part of normal startup rather than a refusal (a\n * `pending` session lane, whose principal is still loading): the connection\n * then carries no message and reads like a never-started chat, which hosts\n * render as ready rather than paused.\n */\n message?: string | undefined;\n /**\n * Invoked when a surface asks the parked connection to `reconnect()` (the\n * connection indicator's retry affordance). Hosts that park for a reason\n * only they can clear (e.g. the user has no workspace) omit it.\n */\n onReconnectRequested?: (() => void) | undefined;\n}\n\nconst suspendedCommands = <\n TCommands extends Statewire.Commands,\n>(): Statewire.CommandsProxy<TCommands> =>\n new Proxy({} as Statewire.CommandsProxy<TCommands>, {\n get: (_target, method) => {\n if (typeof method !== 'string') return undefined;\n // Settle like a locally-dead channel: hosts already classify\n // non-\"server\" causes as channel teardown (quiet log, no user error).\n return () =>\n Promise.reject(new StatewireSendError({ fate: 'aborted', cause: 'stream-gone' }));\n },\n });\n\nconst useSuspendedStatewire = <TCommands extends Statewire.Commands = Statewire.Commands>(\n options: SuspendedStatewireOptions\n): Statewire<undefined, TCommands> => {\n const latest = useRef(options);\n latest.current = options;\n // `state` stays undefined so the thread keeps serving its `initialState`\n // (the same contract a live transport has before its attach snapshot).\n const [value] = useState((): Statewire<undefined, TCommands> => {\n const connection: StatewireClient.Connection & { readonly message: string | undefined } = {\n status: 'standby',\n reason: 'deferred',\n get message() {\n return latest.current.message;\n },\n reconnect: () => latest.current.onReconnectRequested?.(),\n degraded: false,\n };\n return {\n state: undefined,\n commands: suspendedCommands<TCommands>(),\n connection,\n // Context updates while parked are local and must never start a dial.\n // The live transport receives the current snapshot when it replaces us.\n setContext: () => {},\n isBusy: false,\n };\n });\n return value;\n};\n\n/**\n * A statewire transport that never dials.\n *\n * Swapped in for the live WS/SSE transport when attaching is known to be\n * pointless — the host gates it (no workspace) or repeated `unauthorized`\n * denials parked it — so the thread element stays mounted for assistant-ui\n * consumers while the reconnect loop stops entirely.\n */\nexport const StatewireSuspended = resource(useSuspendedStatewire) as <\n TCommands extends Statewire.Commands = Statewire.Commands,\n>(\n options: SuspendedStatewireOptions\n) => ResourceElement<Statewire<undefined, TCommands>>;\n"],"names":["StatewireSendError","useRef","useState","resource"],"mappings":";;;;;AAuBA,MAAM,oBAAoB,MAGxB,IAAI,MAAM,IAA0C;AAAA,EAClD,KAAK,CAAC,SAAS,WAAW;AACxB,QAAI,OAAO,WAAW,SAAU,QAAO;AAGvC,WAAO,MACL,QAAQ,OAAO,IAAIA,UAAAA,mBAAmB,EAAE,MAAM,WAAW,OAAO,cAAA,CAAe,CAAC;AAAA,EACpF;AACF,CAAC;AAEH,MAAM,wBAAwB,CAC5B,YACoC;AACpC,QAAM,SAASC,
|
|
1
|
+
{"version":3,"file":"statewire-suspended.cjs","sources":["../../../../agent-runtime/src/statewire-suspended.ts"],"sourcesContent":["import { resource } from '@assistant-ui/tap';\nimport type { ResourceElement } from '@assistant-ui/tap';\nimport { useRef, useState } from 'react';\nimport type { Statewire, StatewireClient } from 'statewire';\nimport { StatewireSendError } from 'statewire';\n\nexport interface SuspendedStatewireOptions {\n /**\n * Why the transport is parked; surfaced as the connection message. Omitted\n * for a park that is part of normal startup rather than a refusal (a\n * `pending` session lane, whose principal is still loading): the connection\n * then carries no message and reads like a never-started chat, which hosts\n * render as ready rather than paused.\n */\n message?: string | undefined;\n /**\n * Invoked when a surface asks the parked connection to `reconnect()` (the\n * connection indicator's retry affordance). Hosts that park for a reason\n * only they can clear (e.g. the user has no workspace) omit it.\n */\n onReconnectRequested?: (() => void) | undefined;\n}\n\nconst suspendedCommands = <\n TCommands extends Statewire.Commands,\n>(): Statewire.CommandsProxy<TCommands> =>\n new Proxy({} as Statewire.CommandsProxy<TCommands>, {\n get: (_target, method) => {\n if (typeof method !== 'string') return undefined;\n // Settle like a locally-dead channel: hosts already classify\n // non-\"server\" causes as channel teardown (quiet log, no user error).\n return () =>\n Promise.reject(new StatewireSendError({ fate: 'aborted', cause: 'stream-gone' }));\n },\n });\n\nconst useSuspendedStatewire = <TCommands extends Statewire.Commands = Statewire.Commands>(\n options: SuspendedStatewireOptions\n): Statewire<undefined, TCommands> => {\n const latest = useRef(options);\n latest.current = options;\n // `state` stays undefined so the thread keeps serving its `initialState`\n // (the same contract a live transport has before its attach snapshot).\n const [value] = useState((): Statewire<undefined, TCommands> => {\n const connection: StatewireClient.Connection & { readonly message: string | undefined } = {\n status: 'standby',\n reason: 'deferred',\n get message() {\n return latest.current.message;\n },\n reconnect: () => latest.current.onReconnectRequested?.(),\n degraded: false,\n };\n return {\n state: undefined,\n commands: suspendedCommands<TCommands>(),\n connection,\n // Context updates while parked are local and must never start a dial.\n // The live transport receives the current snapshot when it replaces us.\n setContext: () => {},\n isBusy: false,\n };\n });\n return value;\n};\n\n/**\n * A statewire transport that never dials.\n *\n * Swapped in for the live WS/SSE transport when attaching is known to be\n * pointless — the host gates it (no workspace) or repeated `unauthorized`\n * denials parked it — so the thread element stays mounted for assistant-ui\n * consumers while the reconnect loop stops entirely.\n */\nexport const StatewireSuspended = resource(useSuspendedStatewire) as <\n TCommands extends Statewire.Commands = Statewire.Commands,\n>(\n options: SuspendedStatewireOptions\n) => ResourceElement<Statewire<undefined, TCommands>>;\n"],"names":["StatewireSendError","useRef","useState","resource"],"mappings":";;;;;AAuBA,MAAM,oBAAoB,MAGxB,IAAI,MAAM,IAA0C;AAAA,EAClD,KAAK,CAAC,SAAS,WAAW;AACxB,QAAI,OAAO,WAAW,SAAU,QAAO;AAGvC,WAAO,MACL,QAAQ,OAAO,IAAIA,UAAAA,mBAAmB,EAAE,MAAM,WAAW,OAAO,cAAA,CAAe,CAAC;AAAA,EACpF;AACF,CAAC;AAEH,MAAM,wBAAwB,CAC5B,YACoC;AACpC,QAAM,SAASC,WAAAA,OAAO,OAAO;AAC7B,SAAO,UAAU;AAGjB,QAAM,CAAC,KAAK,IAAIC,WAAAA,SAAS,MAAuC;AAC9D,UAAM,aAAoF;AAAA,MACxF,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,IAAI,UAAU;AACZ,eAAO,OAAO,QAAQ;AAAA,MACxB;AAAA,MACA,WAAW,MAAA;;AAAM,kCAAO,SAAQ,yBAAf;AAAA;AAAA,MACjB,UAAU;AAAA,IAAA;AAEZ,WAAO;AAAA,MACL,OAAO;AAAA,MACP,UAAU,kBAAA;AAAA,MACV;AAAA;AAAA;AAAA,MAGA,YAAY,MAAM;AAAA,MAAC;AAAA,MACnB,QAAQ;AAAA,IAAA;AAAA,EAEZ,CAAC;AACD,SAAO;AACT;AAUO,MAAM,qBAAqBC,IAAAA,SAAS,qBAAqB;;"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const core = require("@assistant-ui/core");
|
|
4
4
|
const store = require("@assistant-ui/store");
|
|
5
|
-
const
|
|
5
|
+
const require$$0 = require("react");
|
|
6
6
|
const runconfigContract = require("./generated/runconfig-contract.cjs");
|
|
7
7
|
const messageText = require("./message-text.cjs");
|
|
8
8
|
const subagentTranscripts = require("./subagent-transcripts.cjs");
|
|
@@ -65,6 +65,34 @@ function nestedTodosFromArtifact(artifact) {
|
|
|
65
65
|
const todos = (_a = a == null ? void 0 : a.subgraph_state) == null ? void 0 : _a.todos;
|
|
66
66
|
return Array.isArray(todos) ? todos : void 0;
|
|
67
67
|
}
|
|
68
|
+
function ptcSubagentsFromArtifact(artifact) {
|
|
69
|
+
const a = artifact;
|
|
70
|
+
const entries = a == null ? void 0 : a.ptc_subagents;
|
|
71
|
+
if (!Array.isArray(entries)) return [];
|
|
72
|
+
return entries.filter(
|
|
73
|
+
(entry) => !!entry && typeof entry === "object" && typeof entry.id === "string" && !!entry.id
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
const inEvalDispatchCounts = /* @__PURE__ */ new WeakMap();
|
|
77
|
+
function countInEvalDispatches(artifact) {
|
|
78
|
+
if (typeof artifact !== "object" || artifact === null) return 0;
|
|
79
|
+
const cached = inEvalDispatchCounts.get(artifact);
|
|
80
|
+
if (cached !== void 0) return cached;
|
|
81
|
+
const summaries = new Set(ptcSubagentsFromArtifact(artifact).map((entry) => entry.id));
|
|
82
|
+
let count = summaries.size;
|
|
83
|
+
if (count === 0) {
|
|
84
|
+
const dispatches = /* @__PURE__ */ new Set();
|
|
85
|
+
for (const message of nestedMessagesFromArtifact(artifact)) {
|
|
86
|
+
if (message.type !== "ai" || !message.tool_calls) continue;
|
|
87
|
+
for (const call of message.tool_calls) {
|
|
88
|
+
if (call.name === toolNames.TASK_TOOL_NAME && call.id) dispatches.add(call.id);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
count = dispatches.size;
|
|
92
|
+
}
|
|
93
|
+
inEvalDispatchCounts.set(artifact, count);
|
|
94
|
+
return count;
|
|
95
|
+
}
|
|
68
96
|
const EMPTY_TRANSCRIPT_DERIVATION = {
|
|
69
97
|
currentText: "",
|
|
70
98
|
model: void 0,
|
|
@@ -234,14 +262,16 @@ function useTurnToolCallsAwaitingApproval(toolCallIds) {
|
|
|
234
262
|
TOOL_CALL_ID_SEPARATOR
|
|
235
263
|
)
|
|
236
264
|
);
|
|
237
|
-
return
|
|
265
|
+
return require$$0.useMemo(
|
|
238
266
|
() => key === "" ? NO_WAITING_TOOL_CALLS : new Set(key.split(TOOL_CALL_ID_SEPARATOR)),
|
|
239
267
|
[key]
|
|
240
268
|
);
|
|
241
269
|
}
|
|
270
|
+
exports.countInEvalDispatches = countInEvalDispatches;
|
|
242
271
|
exports.isTerminalSubagentStatus = isTerminalSubagentStatus;
|
|
243
272
|
exports.nestedMessagesFromArtifact = nestedMessagesFromArtifact;
|
|
244
273
|
exports.nestedTodosFromArtifact = nestedTodosFromArtifact;
|
|
274
|
+
exports.ptcSubagentsFromArtifact = ptcSubagentsFromArtifact;
|
|
245
275
|
exports.readLaneUsage = readLaneUsage;
|
|
246
276
|
exports.readTruncatedLane = readTruncatedLane;
|
|
247
277
|
exports.subagentAwaitingApproval = subagentAwaitingApproval;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagents.cjs","sources":["../../../../agent-runtime/src/subagents.ts"],"sourcesContent":["/**\n * Subagent discovery: every subagent lane a deep-agent thread has spawned, as\n * the card view model the surfaces that draw subagent lanes render. Two\n * dispatch paths feed lanes keyed by dispatch id:\n *\n * - top-level `task` tool calls, read from the call's own tool-call part\n * ({@link taskSubagentsOfTurn}): the part's result and `isPreliminary` say\n * where the lane is, and its `messages` (the nested thread\n * `createSubagentTranscriptConversionCache` converts) are the transcript;\n * - in-eval `task()` dispatches ({@link deriveEvalSubagents}), whose only\n * signals are the live `ptc_subagents` state channel and the summaries a\n * finished `eval` ToolMessage persists in `artifact.ptc_subagents`.\n */\nimport {\n getExternalStoreMessages,\n type ThreadMessage,\n type ToolCallMessagePart,\n} from '@assistant-ui/core';\nimport type { LangChainMessage, LangChainToolCall } from '@assistant-ui/react-langgraph';\nimport { useAuiState } from '@assistant-ui/store';\nimport { useMemo } from 'react';\nimport {\n DEEP_AGENT_LANE_USAGE_KEY,\n DEEP_AGENT_TRUNCATED_LANE_KEY,\n} from './generated/runconfig-contract';\nimport { getMessageText } from './message-text';\nimport { convertSubagentTranscript, withRepeatedResult } from './subagent-transcripts';\nimport { EVAL_TOOL_NAME, TASK_TOOL_NAME } from './tool-names';\nimport type { PtcSubagentEntry, Todo } from './types';\n\n/**\n * Where a subagent lane is:\n *\n * - `queued` — the dispatch has not started: a `task` call with no result yet\n * (waiting for a dispatch slot or an approval; the backend shows the running\n * card once the dispatch holds its slot), or an in-eval dispatch waiting for\n * one of the bridge's concurrency slots.\n * - `running` — a `task` call's result is still the backend's running\n * placeholder (its part is `isPreliminary`), and the nested transcript fills\n * in live; or an in-eval dispatch's lifecycle says it runs.\n * - `complete` / `error` — the real result replaced the placeholder; `error`\n * when it is an error result.\n */\nexport type SubagentStatus = 'queued' | 'running' | 'complete' | 'error';\n\n/** True for the settled lifecycle states (`complete` / `error`). */\nexport function isTerminalSubagentStatus(status: SubagentStatus): boolean {\n return status === 'complete' || status === 'error';\n}\n\n/** Aggregate lane lifecycle counts for one fan-out (orchestration strip + header chip). */\nexport interface SubagentStatusCounts {\n total: number;\n queued: number;\n running: number;\n complete: number;\n failed: number;\n /** complete + failed — the settled count progress displays use. */\n terminal: number;\n}\n\nexport function countSubagentStatuses(\n snapshots: readonly SubagentDiscoverySnapshot[]\n): SubagentStatusCounts {\n const counts: SubagentStatusCounts = {\n total: snapshots.length,\n queued: 0,\n running: 0,\n complete: 0,\n failed: 0,\n terminal: 0,\n };\n for (const snapshot of snapshots) {\n if (snapshot.status === 'queued') counts.queued += 1;\n else if (snapshot.status === 'running') counts.running += 1;\n else if (snapshot.status === 'complete') counts.complete += 1;\n else counts.failed += 1;\n }\n counts.terminal = counts.complete + counts.failed;\n return counts;\n}\n\n/**\n * Discovery snapshot for one subagent invocation. Mirrors LangChain's\n * `SubagentDiscoverySnapshot`: `id` is the `task` tool-call id that spawned the\n * subagent (the dispatch id for an in-eval dispatch), so cards nest under the\n * coordinator turn that delegated the work.\n */\nexport interface SubagentDiscoverySnapshot {\n /** The `task` tool-call id that spawned the subagent. */\n id: string;\n /** Subagent type/name, from the `task` call's `subagent_type` arg. */\n name: string;\n /** The one-line task brief from the `task` call's `description` arg. */\n description: string;\n /** Lifecycle state — see {@link SubagentStatus}. */\n status: SubagentStatus;\n /** The call's result text (empty while it is the running placeholder). */\n output?: string;\n /** Number of nested tool calls the subagent made. */\n toolCallCount: number;\n /**\n * The subagent's transcript as a nested thread: a `task` part's native\n * `messages`, or an in-eval dispatch's live transcript converted the same way.\n */\n messages: readonly ThreadMessage[];\n /** Messages in the transcript as the wire carries them, before conversion joins a turn's steps. */\n messageCount: number;\n /**\n * Nested messages the wire left off: a cut card carries its newest steps\n * ({@link readTruncatedLane}) — a running card always, a finished one on a\n * version-2 view — and the rest pages in through `history/lane`; an in-eval\n * dispatch's streamed transcript is cut the same way, running or finished.\n * Absent when the transcript rides whole.\n */\n omittedMessageCount?: number;\n /**\n * Where the lane's steps ride, what `history/lane` pages the rest of the lane\n * under (`useDeepAgentLaneHistory`): a `task` lane's card, an in-eval lane's\n * registry entry while it streams its steps, or, once they no longer ride,\n * its subagent checkpoint (`checkpointed`), when agora recorded where that is\n * (`ns`). Absent for any other in-eval lane with no streamed steps (a summary\n * written before agora recorded the namespace, an older host).\n */\n source?: SubagentLaneSource;\n /** The subagent's own plan, nested by the backend on the task artifact (`subgraph_state.todos`). */\n todos?: Todo[];\n /** The newest tool call in the transcript — the card's \"last action\" ticker. */\n lastToolCall?: LangChainToolCall;\n /** The newest assistant text in the transcript — the card's thought preview. */\n currentText: string;\n /**\n * The `eval` tool-call id that dispatched this subagent, when it was spawned\n * from INSIDE the code interpreter (`task()` in the REPL) rather than by a\n * top-level `task` tool call. The eval card uses it to render lanes for its\n * own dispatches.\n */\n evalId?: string;\n /**\n * Backend-reported runtime for a finished in-eval dispatch (from the terminal\n * lifecycle event). Authoritative over client-side timing — it survives a page\n * refresh, where local first-seen timestamps are gone.\n */\n durationMs?: number;\n /** The model that produced the transcript, from its newest assistant turn's model stamp. */\n model?: string;\n /**\n * The lane's token use: the whole lane's as the host counts it\n * (`DEEP_AGENT_LANE_USAGE_KEY`), else the sum of the native step usage\n * (`metadata.steps[].usage`) of the steps the transcript holds. Absent while\n * no step reports any.\n */\n usage?: SubagentTokenUsage;\n}\n\n/** A subagent lane's token use. */\nexport interface SubagentTokenUsage {\n /** Input tokens, the prompt cache's reads and writes included. */\n readonly inputTokens: number;\n readonly outputTokens: number;\n /**\n * Less than the lane will have used: the lane still runs (its newest step may\n * not have reported yet), or no host total arrived and the sum covers only\n * the steps held of a lane cut to its newest ones.\n */\n readonly partial: boolean;\n}\n\n/** Input and output tokens of some model calls. */\nexport interface TokenCounts {\n readonly inputTokens: number;\n readonly outputTokens: number;\n}\n\nfunction subagentNameFromArgs(args: Readonly<Record<string, unknown>> | undefined): string {\n if (!args) return 'subagent';\n return String(args.subagent_type ?? args.subagentType ?? args.subagent ?? 'subagent');\n}\n\n/**\n * The subagent's streamed transcript as the wire carries it, read from a task\n * ToolMessage's `artifact.subgraph_state.messages` (the shape the backend nests\n * it under — see the route's `_subagent_subgraph_state`).\n */\nexport function nestedMessagesFromArtifact(artifact: unknown): LangChainMessage[] {\n const a = artifact as { subgraph_state?: { messages?: LangChainMessage[] } } | undefined;\n return a?.subgraph_state?.messages ?? [];\n}\n\n/** What the wire left off a cut `task` card's nested transcript. */\nexport interface TruncatedLane {\n /** Nested messages the host holds for the lane. */\n messages: number;\n /** Tool calls across all of them. */\n toolCalls: number;\n /**\n * The card is a finished lane's, cut for a version-2 view. Only a host that\n * serves `history/lane` cuts a finished card.\n */\n finished: boolean;\n}\n\n/**\n * Where a lane's steps ride, and what `history/lane` pages the rest of them\n * under: a `task` lane's card, by its message id, or an in-eval dispatch's\n * `ptc_subagents` registry entry, by its dispatch id.\n */\nexport type SubagentLaneSource = {\n /** The steps as the wire carries them (a card's report restored, {@link withRepeatedResult}). */\n readonly transcript: readonly LangChainMessage[];\n /** The cut marker; absent while every step rides. */\n readonly truncated?: TruncatedLane;\n /**\n * No steps ride, and `history/lane {lane}` pages the subagent's own steps\n * from its checkpoint: an in-eval lane a later run in this activation left\n * only its summary and `ns`, or a reopened session's lane (its registry gone,\n * the summary its eval persisted records `ns`).\n */\n readonly checkpointed?: true;\n} & (\n | {\n /** The card's message id: the running placeholder's, then the result's. */\n readonly messageId: string;\n readonly lane?: undefined;\n }\n | {\n /** The dispatch id: the in-eval lane's registry key. */\n readonly lane: string;\n readonly messageId?: undefined;\n }\n);\n\nconst isCount = (value: unknown): value is number =>\n typeof value === 'number' && Number.isInteger(value) && value >= 0;\n\n/**\n * The cut marker off a `task` card's raw wire message: the host carries only\n * the lane's newest nested steps and names the whole transcript here\n * (`DEEP_AGENT_TRUNCATED_LANE_KEY`), on a running card and, for a version-2\n * view, on a finished one. `null` when the transcript rides whole.\n */\nexport function readTruncatedLane(toolMessage: unknown): TruncatedLane | null {\n if (typeof toolMessage !== 'object' || toolMessage === null) return null;\n const marker = (toolMessage as Record<string, unknown>)[DEEP_AGENT_TRUNCATED_LANE_KEY];\n if (typeof marker !== 'object' || marker === null) return null;\n const { messages, tool_calls: toolCalls, finished } = marker as Record<string, unknown>;\n return isCount(messages) && isCount(toolCalls)\n ? { messages, toolCalls, finished: finished === true }\n : null;\n}\n\n/**\n * The whole lane's token use the host carries on a `task` card's raw wire\n * message or an in-eval lane's `ptc_subagents` entry\n * (`DEEP_AGENT_LANE_USAGE_KEY`), however much of the lane the wire carries.\n * `null` when it carries none (an older host, or no step reported usage).\n */\nexport function readLaneUsage(wire: unknown): TokenCounts | null {\n if (typeof wire !== 'object' || wire === null) return null;\n const usage = (wire as Record<string, unknown>)[DEEP_AGENT_LANE_USAGE_KEY];\n if (typeof usage !== 'object' || usage === null) return null;\n const { input_tokens: inputTokens, output_tokens: outputTokens } = usage as Record<\n string,\n unknown\n >;\n return isCount(inputTokens) && isCount(outputTokens) ? { inputTokens, outputTokens } : null;\n}\n\n/**\n * A lane's token use: the host's total when it sent one, else what the native\n * steps of the transcript held add up to, partial while the lane runs or when\n * that transcript is cut. `undefined` while neither counts anything.\n */\nfunction laneTokenUsage(\n wire: unknown,\n steps: TokenCounts | undefined,\n status: SubagentStatus,\n cut: boolean\n): SubagentTokenUsage | undefined {\n const settled = isTerminalSubagentStatus(status);\n const whole = readLaneUsage(wire);\n if (whole !== null) return { ...whole, partial: !settled };\n return steps === undefined ? undefined : { ...steps, partial: !settled || cut };\n}\n\nconst transcriptStepUsageCache = new WeakMap<readonly ThreadMessage[], TokenCounts | null>();\n\n/**\n * What the model calls of a converted transcript used, from assistant-ui's\n * native step usage (`metadata.steps[].usage`, one step per model call a turn\n * joined). `undefined` when no step reports usage. Memoized per transcript\n * array, which the conversion caches keep while the transcript is unchanged.\n */\nexport function transcriptStepUsage(messages: readonly ThreadMessage[]): TokenCounts | undefined {\n const cached = transcriptStepUsageCache.get(messages);\n if (cached !== undefined) return cached ?? undefined;\n let inputTokens = 0;\n let outputTokens = 0;\n let counted = false;\n for (const message of messages) {\n for (const step of message.metadata.steps ?? []) {\n if (step.usage === undefined) continue;\n inputTokens += step.usage.inputTokens;\n outputTokens += step.usage.outputTokens;\n counted = true;\n }\n }\n const usage = counted ? { inputTokens, outputTokens } : null;\n transcriptStepUsageCache.set(messages, usage);\n return usage ?? undefined;\n}\n\n/**\n * The subagent's own plan, read from a task ToolMessage's\n * `artifact.subgraph_state.todos` (the backend mirrors the subagent's isolated\n * `todos` state channel there — see the route's `_forward_subagent_todos`).\n * `undefined` (not `[]`) when the subagent never wrote a plan, so the UI can\n * distinguish \"no plan\" from \"plan with zero items\".\n */\nexport function nestedTodosFromArtifact(artifact: unknown): Todo[] | undefined {\n const a = artifact as { subgraph_state?: { todos?: unknown } } | undefined;\n const todos = a?.subgraph_state?.todos;\n return Array.isArray(todos) ? (todos as Todo[]) : undefined;\n}\n\n/**\n * The persisted in-eval dispatch summaries from an `eval` ToolMessage's\n * `artifact.ptc_subagents` (written by the backend when the eval ends). Unlike\n * the live `ptc_subagents` state channel — which dies with the stream — these\n * survive checkpoint reload, so reopened sessions can still render each\n * dispatch's terminal status, duration, output, and error.\n */\nexport function ptcSubagentsFromArtifact(artifact: unknown): PtcSubagentEntry[] {\n const a = artifact as { ptc_subagents?: unknown } | undefined;\n const entries = a?.ptc_subagents;\n if (!Array.isArray(entries)) return [];\n return entries.filter(\n (entry): entry is PtcSubagentEntry =>\n !!entry &&\n typeof entry === 'object' &&\n typeof (entry as { id?: unknown }).id === 'string' &&\n !!(entry as { id?: string }).id\n );\n}\n\n/**\n * What one transcript contributes to a lane: the newest assistant text\n * (thought preview), the newest tool call and the count (\"last action\"\n * ticker), the producing model, and the plan recovered from the newest\n * `write_todos` call — the fallback for in-eval lanes, whose isolated `todos`\n * state channel never reaches the wire (the task path nests todos on the\n * artifact instead); the call args carry the same list, so the progress ring\n * can still fill. A pure function of the transcript array.\n */\ninterface TranscriptDerivation {\n currentText: string;\n model: string | undefined;\n lastToolCall: LangChainToolCall | undefined;\n toolCallCount: number;\n todos: Todo[] | undefined;\n}\n\nconst EMPTY_TRANSCRIPT_DERIVATION: TranscriptDerivation = {\n currentText: '',\n model: undefined,\n lastToolCall: undefined,\n toolCallCount: 0,\n todos: undefined,\n};\n\n/**\n * Per-transcript cache for {@link deriveTranscript}: a lane's converted\n * transcript keeps its array while the lane does not change (the conversion\n * caches hand back the previous array), so only lanes still streaming are\n * read again.\n */\nconst transcriptDerivationCache = new WeakMap<readonly ThreadMessage[], TranscriptDerivation>();\n\nfunction deriveTranscript(transcript: readonly ThreadMessage[]): TranscriptDerivation {\n if (transcript.length === 0) return EMPTY_TRANSCRIPT_DERIVATION;\n const cached = transcriptDerivationCache.get(transcript);\n if (cached !== undefined) return cached;\n let currentText = '';\n let model: string | undefined;\n let lastToolCall: LangChainToolCall | undefined;\n let toolCallCount = 0;\n let todos: Todo[] | undefined;\n for (const message of transcript) {\n if (message.role !== 'assistant') continue;\n // A joined turn's `metadata.custom` merges its steps' stamps, the later\n // step's winning (`joinExternalMessages`), so this is the newest stamp.\n const turnModel: unknown = message.metadata?.custom?.model;\n if (typeof turnModel === 'string' && turnModel) model = turnModel;\n for (const part of message.content) {\n if (part.type === 'text') {\n if (part.text) currentText = part.text;\n continue;\n }\n if (part.type !== 'tool-call') continue;\n toolCallCount += 1;\n lastToolCall = { id: part.toolCallId, name: part.toolName, args: part.args };\n if (part.toolName !== 'write_todos') continue;\n const list: unknown = part.args.todos;\n if (Array.isArray(list)) todos = list as Todo[];\n }\n }\n const derivation: TranscriptDerivation = {\n currentText,\n model,\n lastToolCall,\n toolCallCount,\n todos,\n };\n transcriptDerivationCache.set(transcript, derivation);\n return derivation;\n}\n\nconst NO_TRANSCRIPT: readonly ThreadMessage[] = [];\n\n/**\n * The lane of one `task` tool-call part. `toolMessage` is the raw ToolMessage\n * answering it, which carries the wire's cut marker for a running lane.\n */\nfunction taskSubagent(\n part: ToolCallMessagePart,\n toolMessage: LangChainMessage | undefined\n): SubagentDiscoverySnapshot {\n const args: Readonly<Record<string, unknown>> = part.args;\n const transcript = part.messages ?? NO_TRANSCRIPT;\n const derived = deriveTranscript(transcript);\n const messageCount = nestedMessagesFromArtifact(part.artifact).length;\n const lane = readTruncatedLane(toolMessage);\n const todos = nestedTodosFromArtifact(part.artifact);\n const status: SubagentStatus =\n part.result === undefined\n ? 'queued'\n : part.isPreliminary === true\n ? 'running'\n : part.isError === true\n ? 'error'\n : 'complete';\n const usage = laneTokenUsage(\n toolMessage,\n transcriptStepUsage(transcript),\n status,\n lane !== null && lane.messages > messageCount\n );\n return {\n id: part.toolCallId,\n name: subagentNameFromArgs(args),\n description: typeof args.description === 'string' ? args.description : '',\n status,\n ...(part.result !== undefined && { output: getMessageText({ content: part.result }) }),\n toolCallCount: Math.max(derived.toolCallCount, lane?.toolCalls ?? 0),\n messages: transcript,\n messageCount,\n ...(lane !== null && { omittedMessageCount: Math.max(0, lane.messages - messageCount) }),\n ...(typeof toolMessage?.id === 'string' && {\n source: {\n messageId: toolMessage.id,\n transcript: withRepeatedResult(nestedMessagesFromArtifact(part.artifact), part.result),\n ...(lane !== null && { truncated: lane }),\n },\n }),\n ...(todos !== undefined && { todos }),\n ...(derived.lastToolCall !== undefined && { lastToolCall: derived.lastToolCall }),\n currentText: derived.currentText,\n ...(derived.model !== undefined && { model: derived.model }),\n ...(usage !== undefined && { usage }),\n };\n}\n\n/** The raw ToolMessage answering each tool call of a converted turn, from the sources bound to it. */\nfunction toolMessagesOfTurn(message: ThreadMessage): Map<string, LangChainMessage> {\n const byCall = new Map<string, LangChainMessage>();\n for (const source of getExternalStoreMessages<LangChainMessage>(message)) {\n if (source.type === 'tool') byCall.set(source.tool_call_id, source);\n }\n return byCall;\n}\n\n/**\n * Per-part lane cache: a re-converted turn keeps the part object of every call\n * whose ToolMessage did not change (the conversion cache's `keepUnchangedParts`),\n * so a streaming lane re-derives only itself.\n */\nconst taskSubagentByPart = new WeakMap<ToolCallMessagePart, SubagentDiscoverySnapshot>();\nconst taskSubagentsByTurn = new WeakMap<ThreadMessage, ReadonlyMap<string, SubagentDiscoverySnapshot>>();\n\n/**\n * The lane of every `task` call in one converted turn (a `ThreadMessage`, or the\n * message state assistant-ui publishes for it), keyed by tool-call id in call\n * order. Memoized per turn and per part.\n */\nexport function taskSubagentsOfTurn(\n message: ThreadMessage\n): ReadonlyMap<string, SubagentDiscoverySnapshot> {\n const cached = taskSubagentsByTurn.get(message);\n if (cached !== undefined) return cached;\n const lanes = new Map<string, SubagentDiscoverySnapshot>();\n if (message.role === 'assistant') {\n let toolMessages: Map<string, LangChainMessage> | null = null;\n for (const part of message.content) {\n if (part.type !== 'tool-call' || part.toolName !== TASK_TOOL_NAME) continue;\n let lane = taskSubagentByPart.get(part);\n if (lane === undefined) {\n toolMessages ??= toolMessagesOfTurn(message);\n lane = taskSubagent(part, toolMessages.get(part.toolCallId));\n taskSubagentByPart.set(part, lane);\n }\n lanes.set(part.toolCallId, lane);\n }\n }\n taskSubagentsByTurn.set(message, lanes);\n return lanes;\n}\n\n/** The lane of every `task` call in a converted thread, in transcript order. */\nexport function taskSubagentsOfThread(\n messages: readonly ThreadMessage[]\n): SubagentDiscoverySnapshot[] {\n return messages.flatMap((message) => [...taskSubagentsOfTurn(message).values()]);\n}\n\n/**\n * Point a lane at an in-eval dispatch's live transcript, converted into a nested\n * thread, with the live fields it derives. Never regresses a known tool-call\n * count: a countless later event must not reset a lane to \"0 tool calls\".\n */\nfunction applyLaneTranscript(\n snap: SubagentDiscoverySnapshot,\n transcript: readonly LangChainMessage[]\n): void {\n snap.messages = convertSubagentTranscript(transcript, snap.status === 'running');\n snap.messageCount = transcript.length;\n const derived = deriveTranscript(snap.messages);\n if (derived.currentText) snap.currentText = derived.currentText;\n if (derived.model) snap.model = derived.model;\n if (derived.lastToolCall) snap.lastToolCall = derived.lastToolCall;\n snap.toolCallCount = Math.max(snap.toolCallCount, derived.toolCallCount);\n // An in-eval lane has no artifact todos channel: recover the plan from its\n // `write_todos` calls.\n snap.todos = snap.todos ?? derived.todos;\n}\n\n/**\n * The lanes of in-eval dispatches, from two sources: the *persisted* summaries\n * each finished `eval` ToolMessage carries in `artifact.ptc_subagents`\n * (terminal truth; the only source after a session reopen), then the *live*\n * `ptc_subagents` state channel (`ptcSubagents`) for dispatches still\n * streaming. A live entry never downgrades a terminal snapshot back to\n * `running` — a stale lifecycle entry whose terminal event was lost must not\n * resurrect a perpetually-running lane the persisted summary already settled.\n * A lane whose steps no longer ride but whose subagent checkpoint namespace is\n * recorded (`ns`) is `checkpointed`, and `history/lane {lane}` pages its\n * steps: a live entry a later run stripped to its summary, or a persisted\n * summary with no live entry (the registry died with the activation that\n * streamed it). A live entry speaks for its lane over the summary.\n */\nexport function deriveEvalSubagents(\n messages: readonly LangChainMessage[],\n ptcSubagents?: Record<string, PtcSubagentEntry>\n): Map<string, SubagentDiscoverySnapshot> {\n const byDispatchId = new Map<string, SubagentDiscoverySnapshot>();\n // Persisted in-eval dispatch summaries (terminal truth; survives reopen).\n for (const m of messages) {\n if (m.type !== 'tool' || m.name !== EVAL_TOOL_NAME) continue;\n for (const entry of ptcSubagentsFromArtifact(m.artifact)) {\n mergePtcSubagentEntry(byDispatchId, entry, {\n // The eval ended when these summaries were written, so any lane the\n // backend could not settle is a cancelled dispatch, never \"running\".\n status: entry.status === 'complete' ? 'complete' : 'error',\n fallbackEvalId: m.tool_call_id,\n });\n noteCheckpointedLane(byDispatchId.get(entry.id), entry);\n }\n }\n // Live lifecycle entries (the only signal while an eval is still streaming).\n if (ptcSubagents) {\n for (const entry of Object.values(ptcSubagents)) {\n if (!entry || typeof entry !== 'object' || typeof entry.id !== 'string' || !entry.id) {\n continue;\n }\n // This activation's registry speaks for the lane: the steps it streams,\n // else its own namespace, else nothing to page.\n const existing = byDispatchId.get(entry.id);\n if (existing?.source?.checkpointed === true) existing.source = undefined;\n mergePtcSubagentEntry(byDispatchId, entry, {\n status:\n entry.status === 'complete'\n ? 'complete'\n : entry.status === 'error'\n ? 'error'\n : entry.status === 'queued'\n ? 'queued'\n : 'running',\n });\n noteCheckpointedLane(byDispatchId.get(entry.id), entry);\n }\n }\n return byDispatchId;\n}\n\n/** Lifecycle progression order — a merge may only move a lane forward. */\nfunction subagentStatusRank(status: SubagentStatus): number {\n if (status === 'queued') return 0;\n if (status === 'running') return 1;\n return 2;\n}\n\nfunction mergePtcSubagentEntry(\n byDispatchId: Map<string, SubagentDiscoverySnapshot>,\n entry: PtcSubagentEntry,\n options: { status: SubagentStatus; fallbackEvalId?: string }\n): void {\n const { status, fallbackEvalId } = options;\n const existing = byDispatchId.get(entry.id);\n if (existing) {\n // A lane only ever moves FORWARD (queued → running → terminal): a stale\n // entry whose later event was lost must not resurrect a running lane to\n // queued or a finished lane to running — and a settled terminal outcome\n // never flips to the other terminal (first settled source wins).\n if (\n status === existing.status ||\n subagentStatusRank(status) > subagentStatusRank(existing.status)\n ) {\n existing.status = status;\n }\n const evalId = entry.eval_id ?? fallbackEvalId;\n if (evalId) existing.evalId = evalId;\n if (typeof entry.duration_ms === 'number') existing.durationMs = entry.duration_ms;\n // A count only arrives on terminal events; never let a countless later\n // event (or an older backend) regress a known count.\n if (typeof entry.tool_call_count === 'number') {\n existing.toolCallCount = Math.max(existing.toolCallCount, entry.tool_call_count);\n }\n if (Array.isArray(entry.messages) && entry.messages.length > 0) {\n applyLaneTranscript(existing, entry.messages);\n }\n applyLaneCut(existing, entry);\n applyLaneUsage(existing, entry);\n // Prefer the real output (Athena's in-eval output bridge); fall back to the\n // error string only when no (non-empty) output was captured. Same\n // empty-string/nullish rule as the create branch below.\n if (entry.output) existing.output = entry.output;\n else if (entry.error && !existing.output) existing.output = entry.error;\n return;\n }\n // `||` (not `??`) so an empty-string output falls back to the error, matching\n // the merge branch's truthy check above.\n const initialOutput = entry.output || entry.error;\n const evalId = entry.eval_id ?? fallbackEvalId;\n const created: SubagentDiscoverySnapshot = {\n id: entry.id,\n name: String(entry.subagent_type ?? 'subagent'),\n description: entry.label ?? entry.description ?? '',\n status,\n toolCallCount: typeof entry.tool_call_count === 'number' ? entry.tool_call_count : 0,\n messages: NO_TRANSCRIPT,\n messageCount: 0,\n currentText: '',\n ...(evalId ? { evalId } : {}),\n ...(typeof entry.duration_ms === 'number' ? { durationMs: entry.duration_ms } : {}),\n ...(initialOutput ? { output: initialOutput } : {}),\n };\n if (Array.isArray(entry.messages) && entry.messages.length > 0) {\n applyLaneTranscript(created, entry.messages);\n }\n applyLaneCut(created, entry);\n applyLaneUsage(created, entry);\n byDispatchId.set(entry.id, created);\n}\n\n/**\n * Where an in-eval dispatch's streamed steps ride, and what the wire left off\n * them, read off its entry's cut marker (`DEEP_AGENT_TRUNCATED_LANE_KEY`) as a\n * `task` card's is: the steps left off, and the whole lane's tool calls.\n */\nfunction applyLaneCut(snap: SubagentDiscoverySnapshot, entry: PtcSubagentEntry): void {\n const lane = readTruncatedLane(entry);\n if (Array.isArray(entry.messages) && entry.messages.length > 0) {\n snap.source = {\n lane: entry.id,\n transcript: entry.messages,\n ...(lane !== null && { truncated: lane }),\n };\n }\n if (lane === null) return;\n snap.omittedMessageCount = Math.max(0, lane.messages - snap.messageCount);\n snap.toolCallCount = Math.max(snap.toolCallCount, lane.toolCalls);\n}\n\nconst NO_LANE_STEPS: readonly LangChainMessage[] = [];\n\n/**\n * An entry that recorded its subagent's checkpoint namespace (`ns`, a registry\n * entry or the summary an eval persisted, since agora writes it) pages its\n * lane from that checkpoint when no streamed steps carry it.\n */\nfunction noteCheckpointedLane(\n snap: SubagentDiscoverySnapshot | undefined,\n entry: PtcSubagentEntry\n): void {\n if (snap === undefined || snap.source !== undefined) return;\n if (typeof entry.ns !== 'string' || !entry.ns) return;\n snap.source = { lane: entry.id, transcript: NO_LANE_STEPS, checkpointed: true };\n}\n\n/**\n * An in-eval lane's token use, from its entry's host total or the native steps\n * of its live transcript. A merge that brings neither keeps what the lane has.\n */\nfunction applyLaneUsage(snap: SubagentDiscoverySnapshot, entry: PtcSubagentEntry): void {\n const usage = laneTokenUsage(\n entry,\n transcriptStepUsage(snap.messages),\n snap.status,\n (snap.omittedMessageCount ?? 0) > 0\n );\n if (usage !== undefined) snap.usage = usage;\n}\n\n/**\n * The first call of a nested thread with one of `toolCallIds`: the calls a\n * subagent made are the tool-call parts of its transcript, ids included.\n */\nfunction findToolCall({\n messages,\n toolCallIds,\n}: {\n messages: readonly ThreadMessage[] | undefined;\n toolCallIds: ReadonlySet<string>;\n}): ToolCallMessagePart | undefined {\n if (messages === undefined) return undefined;\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n for (const part of message.content) {\n if (part.type === 'tool-call' && toolCallIds.has(part.toolCallId)) return part;\n }\n }\n return undefined;\n}\n\n/**\n * Whether a subagent lane waits on a person's approval, given the gated calls\n * still waiting on one (`toolCallIdsAwaitingApproval`): its own dispatch is the\n * gated call (a per-dispatch `task` gate), or a call it made is (a gated tool\n * raised inside the delegated subagent). The approval names the gated call's\n * `tool_call_id` and never the lane, and a lane's transcript carries the calls\n * it made with their ids, so the call id is the join. A settled lane waits on\n * nobody.\n */\nexport function subagentAwaitingApproval({\n lane,\n toolCallIds,\n}: {\n lane: Pick<SubagentDiscoverySnapshot, 'id' | 'status' | 'messages'>;\n /** The gated calls still waiting on a decision (`toolCallIdsAwaitingApproval`). */\n toolCallIds: ReadonlySet<string>;\n}): boolean {\n if (toolCallIds.size === 0 || isTerminalSubagentStatus(lane.status)) return false;\n return (\n toolCallIds.has(lane.id) ||\n findToolCall({ messages: lane.messages, toolCallIds }) !== undefined\n );\n}\n\n/**\n * The call a subagent made that waits on a person's approval (a gated tool\n * raised inside the delegated subagent), read off its transcript — what the\n * lane card names while it waits. `undefined` when the lane made none, which\n * includes a lane whose own dispatch is the gated call.\n */\nexport function subagentToolCallAwaitingApproval({\n lane,\n toolCallIds,\n}: {\n lane: Pick<SubagentDiscoverySnapshot, 'status' | 'messages'>;\n /** The gated calls still waiting on a decision (`toolCallIdsAwaitingApproval`). */\n toolCallIds: ReadonlySet<string>;\n}): LangChainToolCall | undefined {\n if (toolCallIds.size === 0 || isTerminalSubagentStatus(lane.status)) return undefined;\n const part = findToolCall({ messages: lane.messages, toolCallIds });\n return part === undefined\n ? undefined\n : { id: part.toolCallId, name: part.toolName, args: part.args };\n}\n\n/**\n * The calls of one converted turn that wait on a person's approval, in turn\n * order: a gated call of the turn itself, or a `task` call not yet settled\n * (no result, or the running placeholder) whose lane holds a gated call — the\n * steps the turn's step list reads as waiting rather than running or done.\n */\nexport function turnToolCallsAwaitingApproval({\n message,\n toolCallIds,\n}: {\n message: ThreadMessage;\n /** The gated calls still waiting on a decision (`toolCallIdsAwaitingApproval`). */\n toolCallIds: ReadonlySet<string>;\n}): string[] {\n if (toolCallIds.size === 0 || message.role !== 'assistant') return [];\n const ids: string[] = [];\n for (const part of message.content) {\n if (part.type !== 'tool-call') continue;\n if (toolCallIds.has(part.toolCallId)) {\n ids.push(part.toolCallId);\n continue;\n }\n if (part.toolName !== TASK_TOOL_NAME) continue;\n const settled = part.result !== undefined && part.isPreliminary !== true;\n if (!settled && findToolCall({ messages: part.messages, toolCallIds }) !== undefined) {\n ids.push(part.toolCallId);\n }\n }\n return ids;\n}\n\nconst NO_WAITING_TOOL_CALLS: ReadonlySet<string> = new Set();\n/** Joins call ids into one selector value; an id never holds it. */\nconst TOOL_CALL_ID_SEPARATOR = '\\n';\n\n/**\n * {@link turnToolCallsAwaitingApproval} for the message in scope: what a\n * turn's step list takes as `waitingToolCallIds`, given the run's waiting\n * calls (`toolCallIdsAwaitingApproval`). Selected as a joined string, so a\n * streamed token re-renders the caller only when the waiting steps change, and\n * the set keeps its identity while they do not. Olympus's activity card and\n * the SDK chat's turns both read it.\n */\nexport function useTurnToolCallsAwaitingApproval(\n toolCallIds: ReadonlySet<string>\n): ReadonlySet<string> {\n const key = useAuiState((s) =>\n toolCallIds.size === 0\n ? ''\n : turnToolCallsAwaitingApproval({ message: s.message, toolCallIds }).join(\n TOOL_CALL_ID_SEPARATOR\n )\n );\n return useMemo(\n () => (key === '' ? NO_WAITING_TOOL_CALLS : new Set(key.split(TOOL_CALL_ID_SEPARATOR))),\n [key]\n );\n}\n\n/** Result text shown for a dispatch whose owning run ended before it finished. */\nexport const ORPHANED_SUBAGENT_OUTPUT =\n 'Interrupted — the run that dispatched this subagent ended before it finished.';\n\n/**\n * Settle snapshots orphaned by their dispatching context: once the owner (e.g.\n * the `eval` tool call whose in-eval `task()` issued them) is itself terminal,\n * nothing can ever deliver a `complete`/`error` lifecycle event for a lane still\n * `queued`/`running` — the dispatch coroutines were cancelled with the eval. Those\n * lanes are coerced to `error` with an interruption message so the UI can't show\n * perpetual \"Running · no activity\" ghosts. Returns the input array unchanged\n * (same reference) when there is nothing to settle.\n */\nexport function finalizeOrphanedSubagents(\n snapshots: readonly SubagentDiscoverySnapshot[],\n ownerTerminal: boolean\n): readonly SubagentDiscoverySnapshot[] {\n if (!ownerTerminal || snapshots.every((s) => isTerminalSubagentStatus(s.status))) {\n return snapshots;\n }\n return snapshots.map((s) =>\n isTerminalSubagentStatus(s.status)\n ? s\n : { ...s, status: 'error', output: s.output || ORPHANED_SUBAGENT_OUTPUT }\n );\n}\n\n/**\n * The `task` tool calls sharing `toolCallId`'s parent AI message — the parallel\n * fan-out siblings, in declaration order. Parallel `task` calls always live on ONE\n * AI message's `tool_calls`, so \"same parent message\" IS the parallelism boundary;\n * sequential delegations sit on separate AI messages and form singleton groups.\n * The FIRST sibling is the group's `anchorId`: its tool-part render draws the whole\n * side-by-side group and the other siblings render nothing, keeping the layout\n * change fully inside the `task` tool UI. Falls back to a singleton group when the\n * parent AI message isn't among `messages` (a turn's bound sources, or a raw\n * transcript).\n */\nexport interface TaskSiblingGroup {\n /** Sibling `task` tool-call ids in declaration order. */\n ids: string[];\n /** The first sibling — the one tool-part render that owns the group's UI. */\n anchorId: string;\n}\n\nexport function taskSiblingGroup(\n messages: readonly LangChainMessage[],\n toolCallId: string\n): TaskSiblingGroup {\n for (const m of messages) {\n if (m.type !== 'ai' || !m.tool_calls) continue;\n if (!m.tool_calls.some((tc) => tc.id === toolCallId)) continue;\n const ids = m.tool_calls\n .filter((tc) => tc.name === TASK_TOOL_NAME && tc.id)\n .map((tc) => tc.id as string);\n if (ids.length > 0) return { ids, anchorId: ids[0] ?? toolCallId };\n break;\n }\n return { ids: [toolCallId], anchorId: toolCallId };\n}\n"],"names":["DEEP_AGENT_TRUNCATED_LANE_KEY","DEEP_AGENT_LANE_USAGE_KEY","getMessageText","withRepeatedResult","getExternalStoreMessages","TASK_TOOL_NAME","useAuiState","useMemo"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"subagents.cjs","sources":["../../../../agent-runtime/src/subagents.ts"],"sourcesContent":["/**\n * Subagent discovery: every subagent lane a deep-agent thread has spawned, as\n * the card view model the surfaces that draw subagent lanes render. Two\n * dispatch paths feed lanes keyed by dispatch id:\n *\n * - top-level `task` tool calls, read from the call's own tool-call part\n * ({@link taskSubagentsOfTurn}): the part's result and `isPreliminary` say\n * where the lane is, and its `messages` (the nested thread\n * `createSubagentTranscriptConversionCache` converts) are the transcript;\n * - in-eval `task()` dispatches ({@link deriveEvalSubagents}), whose only\n * signals are the live `ptc_subagents` state channel and the summaries a\n * finished `eval` ToolMessage persists in `artifact.ptc_subagents`.\n */\nimport {\n getExternalStoreMessages,\n type ThreadMessage,\n type ToolCallMessagePart,\n} from '@assistant-ui/core';\nimport type { LangChainMessage, LangChainToolCall } from '@assistant-ui/react-langgraph';\nimport { useAuiState } from '@assistant-ui/store';\nimport { useMemo } from 'react';\nimport {\n DEEP_AGENT_LANE_USAGE_KEY,\n DEEP_AGENT_TRUNCATED_LANE_KEY,\n} from './generated/runconfig-contract';\nimport { getMessageText } from './message-text';\nimport { convertSubagentTranscript, withRepeatedResult } from './subagent-transcripts';\nimport { EVAL_TOOL_NAME, TASK_TOOL_NAME } from './tool-names';\nimport type { PtcSubagentEntry, Todo } from './types';\n\n/**\n * Where a subagent lane is:\n *\n * - `queued` — the dispatch has not started: a `task` call with no result yet\n * (waiting for a dispatch slot or an approval; the backend shows the running\n * card once the dispatch holds its slot), or an in-eval dispatch waiting for\n * one of the bridge's concurrency slots.\n * - `running` — a `task` call's result is still the backend's running\n * placeholder (its part is `isPreliminary`), and the nested transcript fills\n * in live; or an in-eval dispatch's lifecycle says it runs.\n * - `complete` / `error` — the real result replaced the placeholder; `error`\n * when it is an error result.\n */\nexport type SubagentStatus = 'queued' | 'running' | 'complete' | 'error';\n\n/** True for the settled lifecycle states (`complete` / `error`). */\nexport function isTerminalSubagentStatus(status: SubagentStatus): boolean {\n return status === 'complete' || status === 'error';\n}\n\n/** Aggregate lane lifecycle counts for one fan-out (orchestration strip + header chip). */\nexport interface SubagentStatusCounts {\n total: number;\n queued: number;\n running: number;\n complete: number;\n failed: number;\n /** complete + failed — the settled count progress displays use. */\n terminal: number;\n}\n\nexport function countSubagentStatuses(\n snapshots: readonly SubagentDiscoverySnapshot[]\n): SubagentStatusCounts {\n const counts: SubagentStatusCounts = {\n total: snapshots.length,\n queued: 0,\n running: 0,\n complete: 0,\n failed: 0,\n terminal: 0,\n };\n for (const snapshot of snapshots) {\n if (snapshot.status === 'queued') counts.queued += 1;\n else if (snapshot.status === 'running') counts.running += 1;\n else if (snapshot.status === 'complete') counts.complete += 1;\n else counts.failed += 1;\n }\n counts.terminal = counts.complete + counts.failed;\n return counts;\n}\n\n/**\n * Discovery snapshot for one subagent invocation. Mirrors LangChain's\n * `SubagentDiscoverySnapshot`: `id` is the `task` tool-call id that spawned the\n * subagent (the dispatch id for an in-eval dispatch), so cards nest under the\n * coordinator turn that delegated the work.\n */\nexport interface SubagentDiscoverySnapshot {\n /** The `task` tool-call id that spawned the subagent. */\n id: string;\n /** Subagent type/name, from the `task` call's `subagent_type` arg. */\n name: string;\n /** The one-line task brief from the `task` call's `description` arg. */\n description: string;\n /** Lifecycle state — see {@link SubagentStatus}. */\n status: SubagentStatus;\n /** The call's result text (empty while it is the running placeholder). */\n output?: string;\n /** Number of nested tool calls the subagent made. */\n toolCallCount: number;\n /**\n * The subagent's transcript as a nested thread: a `task` part's native\n * `messages`, or an in-eval dispatch's live transcript converted the same way.\n */\n messages: readonly ThreadMessage[];\n /** Messages in the transcript as the wire carries them, before conversion joins a turn's steps. */\n messageCount: number;\n /**\n * Nested messages the wire left off: a cut card carries its newest steps\n * ({@link readTruncatedLane}) — a running card always, a finished one on a\n * version-2 view — and the rest pages in through `history/lane`; an in-eval\n * dispatch's streamed transcript is cut the same way, running or finished.\n * Absent when the transcript rides whole.\n */\n omittedMessageCount?: number;\n /**\n * Where the lane's steps ride, what `history/lane` pages the rest of the lane\n * under (`useDeepAgentLaneHistory`): a `task` lane's card, an in-eval lane's\n * registry entry while it streams its steps, or, once they no longer ride,\n * its subagent checkpoint (`checkpointed`), when agora recorded where that is\n * (`ns`). Absent for any other in-eval lane with no streamed steps (a summary\n * written before agora recorded the namespace, an older host).\n */\n source?: SubagentLaneSource;\n /** The subagent's own plan, nested by the backend on the task artifact (`subgraph_state.todos`). */\n todos?: Todo[];\n /** The newest tool call in the transcript — the card's \"last action\" ticker. */\n lastToolCall?: LangChainToolCall;\n /** The newest assistant text in the transcript — the card's thought preview. */\n currentText: string;\n /**\n * The `eval` tool-call id that dispatched this subagent, when it was spawned\n * from INSIDE the code interpreter (`task()` in the REPL) rather than by a\n * top-level `task` tool call. The eval card uses it to render lanes for its\n * own dispatches.\n */\n evalId?: string;\n /**\n * Backend-reported runtime for a finished in-eval dispatch (from the terminal\n * lifecycle event). Authoritative over client-side timing — it survives a page\n * refresh, where local first-seen timestamps are gone.\n */\n durationMs?: number;\n /** The model that produced the transcript, from its newest assistant turn's model stamp. */\n model?: string;\n /**\n * The lane's token use: the whole lane's as the host counts it\n * (`DEEP_AGENT_LANE_USAGE_KEY`), else the sum of the native step usage\n * (`metadata.steps[].usage`) of the steps the transcript holds. Absent while\n * no step reports any.\n */\n usage?: SubagentTokenUsage;\n}\n\n/** A subagent lane's token use. */\nexport interface SubagentTokenUsage {\n /** Input tokens, the prompt cache's reads and writes included. */\n readonly inputTokens: number;\n readonly outputTokens: number;\n /**\n * Less than the lane will have used: the lane still runs (its newest step may\n * not have reported yet), or no host total arrived and the sum covers only\n * the steps held of a lane cut to its newest ones.\n */\n readonly partial: boolean;\n}\n\n/** Input and output tokens of some model calls. */\nexport interface TokenCounts {\n readonly inputTokens: number;\n readonly outputTokens: number;\n}\n\nfunction subagentNameFromArgs(args: Readonly<Record<string, unknown>> | undefined): string {\n if (!args) return 'subagent';\n return String(args.subagent_type ?? args.subagentType ?? args.subagent ?? 'subagent');\n}\n\n/**\n * The subagent's streamed transcript as the wire carries it, read from a task\n * ToolMessage's `artifact.subgraph_state.messages` (the shape the backend nests\n * it under — see the route's `_subagent_subgraph_state`).\n */\nexport function nestedMessagesFromArtifact(artifact: unknown): LangChainMessage[] {\n const a = artifact as { subgraph_state?: { messages?: LangChainMessage[] } } | undefined;\n return a?.subgraph_state?.messages ?? [];\n}\n\n/** What the wire left off a cut `task` card's nested transcript. */\nexport interface TruncatedLane {\n /** Nested messages the host holds for the lane. */\n messages: number;\n /** Tool calls across all of them. */\n toolCalls: number;\n /**\n * The card is a finished lane's, cut for a version-2 view. Only a host that\n * serves `history/lane` cuts a finished card.\n */\n finished: boolean;\n}\n\n/**\n * Where a lane's steps ride, and what `history/lane` pages the rest of them\n * under: a `task` lane's card, by its message id, or an in-eval dispatch's\n * `ptc_subagents` registry entry, by its dispatch id.\n */\nexport type SubagentLaneSource = {\n /** The steps as the wire carries them (a card's report restored, {@link withRepeatedResult}). */\n readonly transcript: readonly LangChainMessage[];\n /** The cut marker; absent while every step rides. */\n readonly truncated?: TruncatedLane;\n /**\n * No steps ride, and `history/lane {lane}` pages the subagent's own steps\n * from its checkpoint: an in-eval lane a later run in this activation left\n * only its summary and `ns`, or a reopened session's lane (its registry gone,\n * the summary its eval persisted records `ns`).\n */\n readonly checkpointed?: true;\n} & (\n | {\n /** The card's message id: the running placeholder's, then the result's. */\n readonly messageId: string;\n readonly lane?: undefined;\n }\n | {\n /** The dispatch id: the in-eval lane's registry key. */\n readonly lane: string;\n readonly messageId?: undefined;\n }\n);\n\nconst isCount = (value: unknown): value is number =>\n typeof value === 'number' && Number.isInteger(value) && value >= 0;\n\n/**\n * The cut marker off a `task` card's raw wire message: the host carries only\n * the lane's newest nested steps and names the whole transcript here\n * (`DEEP_AGENT_TRUNCATED_LANE_KEY`), on a running card and, for a version-2\n * view, on a finished one. `null` when the transcript rides whole.\n */\nexport function readTruncatedLane(toolMessage: unknown): TruncatedLane | null {\n if (typeof toolMessage !== 'object' || toolMessage === null) return null;\n const marker = (toolMessage as Record<string, unknown>)[DEEP_AGENT_TRUNCATED_LANE_KEY];\n if (typeof marker !== 'object' || marker === null) return null;\n const { messages, tool_calls: toolCalls, finished } = marker as Record<string, unknown>;\n return isCount(messages) && isCount(toolCalls)\n ? { messages, toolCalls, finished: finished === true }\n : null;\n}\n\n/**\n * The whole lane's token use the host carries on a `task` card's raw wire\n * message or an in-eval lane's `ptc_subagents` entry\n * (`DEEP_AGENT_LANE_USAGE_KEY`), however much of the lane the wire carries.\n * `null` when it carries none (an older host, or no step reported usage).\n */\nexport function readLaneUsage(wire: unknown): TokenCounts | null {\n if (typeof wire !== 'object' || wire === null) return null;\n const usage = (wire as Record<string, unknown>)[DEEP_AGENT_LANE_USAGE_KEY];\n if (typeof usage !== 'object' || usage === null) return null;\n const { input_tokens: inputTokens, output_tokens: outputTokens } = usage as Record<\n string,\n unknown\n >;\n return isCount(inputTokens) && isCount(outputTokens) ? { inputTokens, outputTokens } : null;\n}\n\n/**\n * A lane's token use: the host's total when it sent one, else what the native\n * steps of the transcript held add up to, partial while the lane runs or when\n * that transcript is cut. `undefined` while neither counts anything.\n */\nfunction laneTokenUsage(\n wire: unknown,\n steps: TokenCounts | undefined,\n status: SubagentStatus,\n cut: boolean\n): SubagentTokenUsage | undefined {\n const settled = isTerminalSubagentStatus(status);\n const whole = readLaneUsage(wire);\n if (whole !== null) return { ...whole, partial: !settled };\n return steps === undefined ? undefined : { ...steps, partial: !settled || cut };\n}\n\nconst transcriptStepUsageCache = new WeakMap<readonly ThreadMessage[], TokenCounts | null>();\n\n/**\n * What the model calls of a converted transcript used, from assistant-ui's\n * native step usage (`metadata.steps[].usage`, one step per model call a turn\n * joined). `undefined` when no step reports usage. Memoized per transcript\n * array, which the conversion caches keep while the transcript is unchanged.\n */\nexport function transcriptStepUsage(messages: readonly ThreadMessage[]): TokenCounts | undefined {\n const cached = transcriptStepUsageCache.get(messages);\n if (cached !== undefined) return cached ?? undefined;\n let inputTokens = 0;\n let outputTokens = 0;\n let counted = false;\n for (const message of messages) {\n for (const step of message.metadata.steps ?? []) {\n if (step.usage === undefined) continue;\n inputTokens += step.usage.inputTokens;\n outputTokens += step.usage.outputTokens;\n counted = true;\n }\n }\n const usage = counted ? { inputTokens, outputTokens } : null;\n transcriptStepUsageCache.set(messages, usage);\n return usage ?? undefined;\n}\n\n/**\n * The subagent's own plan, read from a task ToolMessage's\n * `artifact.subgraph_state.todos` (the backend mirrors the subagent's isolated\n * `todos` state channel there — see the route's `_forward_subagent_todos`).\n * `undefined` (not `[]`) when the subagent never wrote a plan, so the UI can\n * distinguish \"no plan\" from \"plan with zero items\".\n */\nexport function nestedTodosFromArtifact(artifact: unknown): Todo[] | undefined {\n const a = artifact as { subgraph_state?: { todos?: unknown } } | undefined;\n const todos = a?.subgraph_state?.todos;\n return Array.isArray(todos) ? (todos as Todo[]) : undefined;\n}\n\n/**\n * The persisted in-eval dispatch summaries from an `eval` ToolMessage's\n * `artifact.ptc_subagents` (written by the backend when the eval ends). Unlike\n * the live `ptc_subagents` state channel — which dies with the stream — these\n * survive checkpoint reload, so reopened sessions can still render each\n * dispatch's terminal status, duration, output, and error.\n */\nexport function ptcSubagentsFromArtifact(artifact: unknown): PtcSubagentEntry[] {\n const a = artifact as { ptc_subagents?: unknown } | undefined;\n const entries = a?.ptc_subagents;\n if (!Array.isArray(entries)) return [];\n return entries.filter(\n (entry): entry is PtcSubagentEntry =>\n !!entry &&\n typeof entry === 'object' &&\n typeof (entry as { id?: unknown }).id === 'string' &&\n !!(entry as { id?: string }).id\n );\n}\n\nconst inEvalDispatchCounts = new WeakMap<object, number>();\n\n/**\n * How many subagents an `eval` call delegated to from inside the interpreter\n * (its `task()` dispatches), read off the call's own artifact: the persisted\n * dispatch summaries (`artifact.ptc_subagents`, one per dispatch id), else the\n * `task` sub-calls its PTC log records (a running call's placeholder, or a\n * backend that persists no summaries). Counted once per artifact object, so a\n * settled call's count costs nothing when its turn is read again.\n */\nexport function countInEvalDispatches(artifact: unknown): number {\n if (typeof artifact !== 'object' || artifact === null) return 0;\n const cached = inEvalDispatchCounts.get(artifact);\n if (cached !== undefined) return cached;\n const summaries = new Set(ptcSubagentsFromArtifact(artifact).map((entry) => entry.id));\n let count = summaries.size;\n if (count === 0) {\n const dispatches = new Set<string>();\n for (const message of nestedMessagesFromArtifact(artifact)) {\n if (message.type !== 'ai' || !message.tool_calls) continue;\n for (const call of message.tool_calls) {\n if (call.name === TASK_TOOL_NAME && call.id) dispatches.add(call.id);\n }\n }\n count = dispatches.size;\n }\n inEvalDispatchCounts.set(artifact, count);\n return count;\n}\n\n/**\n * What one transcript contributes to a lane: the newest assistant text\n * (thought preview), the newest tool call and the count (\"last action\"\n * ticker), the producing model, and the plan recovered from the newest\n * `write_todos` call — the fallback for in-eval lanes, whose isolated `todos`\n * state channel never reaches the wire (the task path nests todos on the\n * artifact instead); the call args carry the same list, so the progress ring\n * can still fill. A pure function of the transcript array.\n */\ninterface TranscriptDerivation {\n currentText: string;\n model: string | undefined;\n lastToolCall: LangChainToolCall | undefined;\n toolCallCount: number;\n todos: Todo[] | undefined;\n}\n\nconst EMPTY_TRANSCRIPT_DERIVATION: TranscriptDerivation = {\n currentText: '',\n model: undefined,\n lastToolCall: undefined,\n toolCallCount: 0,\n todos: undefined,\n};\n\n/**\n * Per-transcript cache for {@link deriveTranscript}: a lane's converted\n * transcript keeps its array while the lane does not change (the conversion\n * caches hand back the previous array), so only lanes still streaming are\n * read again.\n */\nconst transcriptDerivationCache = new WeakMap<readonly ThreadMessage[], TranscriptDerivation>();\n\nfunction deriveTranscript(transcript: readonly ThreadMessage[]): TranscriptDerivation {\n if (transcript.length === 0) return EMPTY_TRANSCRIPT_DERIVATION;\n const cached = transcriptDerivationCache.get(transcript);\n if (cached !== undefined) return cached;\n let currentText = '';\n let model: string | undefined;\n let lastToolCall: LangChainToolCall | undefined;\n let toolCallCount = 0;\n let todos: Todo[] | undefined;\n for (const message of transcript) {\n if (message.role !== 'assistant') continue;\n // A joined turn's `metadata.custom` merges its steps' stamps, the later\n // step's winning (`joinExternalMessages`), so this is the newest stamp.\n const turnModel: unknown = message.metadata?.custom?.model;\n if (typeof turnModel === 'string' && turnModel) model = turnModel;\n for (const part of message.content) {\n if (part.type === 'text') {\n if (part.text) currentText = part.text;\n continue;\n }\n if (part.type !== 'tool-call') continue;\n toolCallCount += 1;\n lastToolCall = { id: part.toolCallId, name: part.toolName, args: part.args };\n if (part.toolName !== 'write_todos') continue;\n const list: unknown = part.args.todos;\n if (Array.isArray(list)) todos = list as Todo[];\n }\n }\n const derivation: TranscriptDerivation = {\n currentText,\n model,\n lastToolCall,\n toolCallCount,\n todos,\n };\n transcriptDerivationCache.set(transcript, derivation);\n return derivation;\n}\n\nconst NO_TRANSCRIPT: readonly ThreadMessage[] = [];\n\n/**\n * The lane of one `task` tool-call part. `toolMessage` is the raw ToolMessage\n * answering it, which carries the wire's cut marker for a running lane.\n */\nfunction taskSubagent(\n part: ToolCallMessagePart,\n toolMessage: LangChainMessage | undefined\n): SubagentDiscoverySnapshot {\n const args: Readonly<Record<string, unknown>> = part.args;\n const transcript = part.messages ?? NO_TRANSCRIPT;\n const derived = deriveTranscript(transcript);\n const messageCount = nestedMessagesFromArtifact(part.artifact).length;\n const lane = readTruncatedLane(toolMessage);\n const todos = nestedTodosFromArtifact(part.artifact);\n const status: SubagentStatus =\n part.result === undefined\n ? 'queued'\n : part.isPreliminary === true\n ? 'running'\n : part.isError === true\n ? 'error'\n : 'complete';\n const usage = laneTokenUsage(\n toolMessage,\n transcriptStepUsage(transcript),\n status,\n lane !== null && lane.messages > messageCount\n );\n return {\n id: part.toolCallId,\n name: subagentNameFromArgs(args),\n description: typeof args.description === 'string' ? args.description : '',\n status,\n ...(part.result !== undefined && { output: getMessageText({ content: part.result }) }),\n toolCallCount: Math.max(derived.toolCallCount, lane?.toolCalls ?? 0),\n messages: transcript,\n messageCount,\n ...(lane !== null && { omittedMessageCount: Math.max(0, lane.messages - messageCount) }),\n ...(typeof toolMessage?.id === 'string' && {\n source: {\n messageId: toolMessage.id,\n transcript: withRepeatedResult(nestedMessagesFromArtifact(part.artifact), part.result),\n ...(lane !== null && { truncated: lane }),\n },\n }),\n ...(todos !== undefined && { todos }),\n ...(derived.lastToolCall !== undefined && { lastToolCall: derived.lastToolCall }),\n currentText: derived.currentText,\n ...(derived.model !== undefined && { model: derived.model }),\n ...(usage !== undefined && { usage }),\n };\n}\n\n/** The raw ToolMessage answering each tool call of a converted turn, from the sources bound to it. */\nfunction toolMessagesOfTurn(message: ThreadMessage): Map<string, LangChainMessage> {\n const byCall = new Map<string, LangChainMessage>();\n for (const source of getExternalStoreMessages<LangChainMessage>(message)) {\n if (source.type === 'tool') byCall.set(source.tool_call_id, source);\n }\n return byCall;\n}\n\n/**\n * Per-part lane cache: a re-converted turn keeps the part object of every call\n * whose ToolMessage did not change (the conversion cache's `keepUnchangedParts`),\n * so a streaming lane re-derives only itself.\n */\nconst taskSubagentByPart = new WeakMap<ToolCallMessagePart, SubagentDiscoverySnapshot>();\nconst taskSubagentsByTurn = new WeakMap<ThreadMessage, ReadonlyMap<string, SubagentDiscoverySnapshot>>();\n\n/**\n * The lane of every `task` call in one converted turn (a `ThreadMessage`, or the\n * message state assistant-ui publishes for it), keyed by tool-call id in call\n * order. Memoized per turn and per part.\n */\nexport function taskSubagentsOfTurn(\n message: ThreadMessage\n): ReadonlyMap<string, SubagentDiscoverySnapshot> {\n const cached = taskSubagentsByTurn.get(message);\n if (cached !== undefined) return cached;\n const lanes = new Map<string, SubagentDiscoverySnapshot>();\n if (message.role === 'assistant') {\n let toolMessages: Map<string, LangChainMessage> | null = null;\n for (const part of message.content) {\n if (part.type !== 'tool-call' || part.toolName !== TASK_TOOL_NAME) continue;\n let lane = taskSubagentByPart.get(part);\n if (lane === undefined) {\n toolMessages ??= toolMessagesOfTurn(message);\n lane = taskSubagent(part, toolMessages.get(part.toolCallId));\n taskSubagentByPart.set(part, lane);\n }\n lanes.set(part.toolCallId, lane);\n }\n }\n taskSubagentsByTurn.set(message, lanes);\n return lanes;\n}\n\n/** The lane of every `task` call in a converted thread, in transcript order. */\nexport function taskSubagentsOfThread(\n messages: readonly ThreadMessage[]\n): SubagentDiscoverySnapshot[] {\n return messages.flatMap((message) => [...taskSubagentsOfTurn(message).values()]);\n}\n\n/**\n * Point a lane at an in-eval dispatch's live transcript, converted into a nested\n * thread, with the live fields it derives. Never regresses a known tool-call\n * count: a countless later event must not reset a lane to \"0 tool calls\".\n */\nfunction applyLaneTranscript(\n snap: SubagentDiscoverySnapshot,\n transcript: readonly LangChainMessage[]\n): void {\n snap.messages = convertSubagentTranscript(transcript, snap.status === 'running');\n snap.messageCount = transcript.length;\n const derived = deriveTranscript(snap.messages);\n if (derived.currentText) snap.currentText = derived.currentText;\n if (derived.model) snap.model = derived.model;\n if (derived.lastToolCall) snap.lastToolCall = derived.lastToolCall;\n snap.toolCallCount = Math.max(snap.toolCallCount, derived.toolCallCount);\n // An in-eval lane has no artifact todos channel: recover the plan from its\n // `write_todos` calls.\n snap.todos = snap.todos ?? derived.todos;\n}\n\n/**\n * The lanes of in-eval dispatches, from two sources: the *persisted* summaries\n * each finished `eval` ToolMessage carries in `artifact.ptc_subagents`\n * (terminal truth; the only source after a session reopen), then the *live*\n * `ptc_subagents` state channel (`ptcSubagents`) for dispatches still\n * streaming. A live entry never downgrades a terminal snapshot back to\n * `running` — a stale lifecycle entry whose terminal event was lost must not\n * resurrect a perpetually-running lane the persisted summary already settled.\n * A lane whose steps no longer ride but whose subagent checkpoint namespace is\n * recorded (`ns`) is `checkpointed`, and `history/lane {lane}` pages its\n * steps: a live entry a later run stripped to its summary, or a persisted\n * summary with no live entry (the registry died with the activation that\n * streamed it). A live entry speaks for its lane over the summary.\n */\nexport function deriveEvalSubagents(\n messages: readonly LangChainMessage[],\n ptcSubagents?: Record<string, PtcSubagentEntry>\n): Map<string, SubagentDiscoverySnapshot> {\n const byDispatchId = new Map<string, SubagentDiscoverySnapshot>();\n // Persisted in-eval dispatch summaries (terminal truth; survives reopen).\n for (const m of messages) {\n if (m.type !== 'tool' || m.name !== EVAL_TOOL_NAME) continue;\n for (const entry of ptcSubagentsFromArtifact(m.artifact)) {\n mergePtcSubagentEntry(byDispatchId, entry, {\n // The eval ended when these summaries were written, so any lane the\n // backend could not settle is a cancelled dispatch, never \"running\".\n status: entry.status === 'complete' ? 'complete' : 'error',\n fallbackEvalId: m.tool_call_id,\n });\n noteCheckpointedLane(byDispatchId.get(entry.id), entry);\n }\n }\n // Live lifecycle entries (the only signal while an eval is still streaming).\n if (ptcSubagents) {\n for (const entry of Object.values(ptcSubagents)) {\n if (!entry || typeof entry !== 'object' || typeof entry.id !== 'string' || !entry.id) {\n continue;\n }\n // This activation's registry speaks for the lane: the steps it streams,\n // else its own namespace, else nothing to page.\n const existing = byDispatchId.get(entry.id);\n if (existing?.source?.checkpointed === true) existing.source = undefined;\n mergePtcSubagentEntry(byDispatchId, entry, {\n status:\n entry.status === 'complete'\n ? 'complete'\n : entry.status === 'error'\n ? 'error'\n : entry.status === 'queued'\n ? 'queued'\n : 'running',\n });\n noteCheckpointedLane(byDispatchId.get(entry.id), entry);\n }\n }\n return byDispatchId;\n}\n\n/** Lifecycle progression order — a merge may only move a lane forward. */\nfunction subagentStatusRank(status: SubagentStatus): number {\n if (status === 'queued') return 0;\n if (status === 'running') return 1;\n return 2;\n}\n\nfunction mergePtcSubagentEntry(\n byDispatchId: Map<string, SubagentDiscoverySnapshot>,\n entry: PtcSubagentEntry,\n options: { status: SubagentStatus; fallbackEvalId?: string }\n): void {\n const { status, fallbackEvalId } = options;\n const existing = byDispatchId.get(entry.id);\n if (existing) {\n // A lane only ever moves FORWARD (queued → running → terminal): a stale\n // entry whose later event was lost must not resurrect a running lane to\n // queued or a finished lane to running — and a settled terminal outcome\n // never flips to the other terminal (first settled source wins).\n if (\n status === existing.status ||\n subagentStatusRank(status) > subagentStatusRank(existing.status)\n ) {\n existing.status = status;\n }\n const evalId = entry.eval_id ?? fallbackEvalId;\n if (evalId) existing.evalId = evalId;\n if (typeof entry.duration_ms === 'number') existing.durationMs = entry.duration_ms;\n // A count only arrives on terminal events; never let a countless later\n // event (or an older backend) regress a known count.\n if (typeof entry.tool_call_count === 'number') {\n existing.toolCallCount = Math.max(existing.toolCallCount, entry.tool_call_count);\n }\n if (Array.isArray(entry.messages) && entry.messages.length > 0) {\n applyLaneTranscript(existing, entry.messages);\n }\n applyLaneCut(existing, entry);\n applyLaneUsage(existing, entry);\n // Prefer the real output (Athena's in-eval output bridge); fall back to the\n // error string only when no (non-empty) output was captured. Same\n // empty-string/nullish rule as the create branch below.\n if (entry.output) existing.output = entry.output;\n else if (entry.error && !existing.output) existing.output = entry.error;\n return;\n }\n // `||` (not `??`) so an empty-string output falls back to the error, matching\n // the merge branch's truthy check above.\n const initialOutput = entry.output || entry.error;\n const evalId = entry.eval_id ?? fallbackEvalId;\n const created: SubagentDiscoverySnapshot = {\n id: entry.id,\n name: String(entry.subagent_type ?? 'subagent'),\n description: entry.label ?? entry.description ?? '',\n status,\n toolCallCount: typeof entry.tool_call_count === 'number' ? entry.tool_call_count : 0,\n messages: NO_TRANSCRIPT,\n messageCount: 0,\n currentText: '',\n ...(evalId ? { evalId } : {}),\n ...(typeof entry.duration_ms === 'number' ? { durationMs: entry.duration_ms } : {}),\n ...(initialOutput ? { output: initialOutput } : {}),\n };\n if (Array.isArray(entry.messages) && entry.messages.length > 0) {\n applyLaneTranscript(created, entry.messages);\n }\n applyLaneCut(created, entry);\n applyLaneUsage(created, entry);\n byDispatchId.set(entry.id, created);\n}\n\n/**\n * Where an in-eval dispatch's streamed steps ride, and what the wire left off\n * them, read off its entry's cut marker (`DEEP_AGENT_TRUNCATED_LANE_KEY`) as a\n * `task` card's is: the steps left off, and the whole lane's tool calls.\n */\nfunction applyLaneCut(snap: SubagentDiscoverySnapshot, entry: PtcSubagentEntry): void {\n const lane = readTruncatedLane(entry);\n if (Array.isArray(entry.messages) && entry.messages.length > 0) {\n snap.source = {\n lane: entry.id,\n transcript: entry.messages,\n ...(lane !== null && { truncated: lane }),\n };\n }\n if (lane === null) return;\n snap.omittedMessageCount = Math.max(0, lane.messages - snap.messageCount);\n snap.toolCallCount = Math.max(snap.toolCallCount, lane.toolCalls);\n}\n\nconst NO_LANE_STEPS: readonly LangChainMessage[] = [];\n\n/**\n * An entry that recorded its subagent's checkpoint namespace (`ns`, a registry\n * entry or the summary an eval persisted, since agora writes it) pages its\n * lane from that checkpoint when no streamed steps carry it.\n */\nfunction noteCheckpointedLane(\n snap: SubagentDiscoverySnapshot | undefined,\n entry: PtcSubagentEntry\n): void {\n if (snap === undefined || snap.source !== undefined) return;\n if (typeof entry.ns !== 'string' || !entry.ns) return;\n snap.source = { lane: entry.id, transcript: NO_LANE_STEPS, checkpointed: true };\n}\n\n/**\n * An in-eval lane's token use, from its entry's host total or the native steps\n * of its live transcript. A merge that brings neither keeps what the lane has.\n */\nfunction applyLaneUsage(snap: SubagentDiscoverySnapshot, entry: PtcSubagentEntry): void {\n const usage = laneTokenUsage(\n entry,\n transcriptStepUsage(snap.messages),\n snap.status,\n (snap.omittedMessageCount ?? 0) > 0\n );\n if (usage !== undefined) snap.usage = usage;\n}\n\n/**\n * The first call of a nested thread with one of `toolCallIds`: the calls a\n * subagent made are the tool-call parts of its transcript, ids included.\n */\nfunction findToolCall({\n messages,\n toolCallIds,\n}: {\n messages: readonly ThreadMessage[] | undefined;\n toolCallIds: ReadonlySet<string>;\n}): ToolCallMessagePart | undefined {\n if (messages === undefined) return undefined;\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n for (const part of message.content) {\n if (part.type === 'tool-call' && toolCallIds.has(part.toolCallId)) return part;\n }\n }\n return undefined;\n}\n\n/**\n * Whether a subagent lane waits on a person's approval, given the gated calls\n * still waiting on one (`toolCallIdsAwaitingApproval`): its own dispatch is the\n * gated call (a per-dispatch `task` gate), or a call it made is (a gated tool\n * raised inside the delegated subagent). The approval names the gated call's\n * `tool_call_id` and never the lane, and a lane's transcript carries the calls\n * it made with their ids, so the call id is the join. A settled lane waits on\n * nobody.\n */\nexport function subagentAwaitingApproval({\n lane,\n toolCallIds,\n}: {\n lane: Pick<SubagentDiscoverySnapshot, 'id' | 'status' | 'messages'>;\n /** The gated calls still waiting on a decision (`toolCallIdsAwaitingApproval`). */\n toolCallIds: ReadonlySet<string>;\n}): boolean {\n if (toolCallIds.size === 0 || isTerminalSubagentStatus(lane.status)) return false;\n return (\n toolCallIds.has(lane.id) ||\n findToolCall({ messages: lane.messages, toolCallIds }) !== undefined\n );\n}\n\n/**\n * The call a subagent made that waits on a person's approval (a gated tool\n * raised inside the delegated subagent), read off its transcript — what the\n * lane card names while it waits. `undefined` when the lane made none, which\n * includes a lane whose own dispatch is the gated call.\n */\nexport function subagentToolCallAwaitingApproval({\n lane,\n toolCallIds,\n}: {\n lane: Pick<SubagentDiscoverySnapshot, 'status' | 'messages'>;\n /** The gated calls still waiting on a decision (`toolCallIdsAwaitingApproval`). */\n toolCallIds: ReadonlySet<string>;\n}): LangChainToolCall | undefined {\n if (toolCallIds.size === 0 || isTerminalSubagentStatus(lane.status)) return undefined;\n const part = findToolCall({ messages: lane.messages, toolCallIds });\n return part === undefined\n ? undefined\n : { id: part.toolCallId, name: part.toolName, args: part.args };\n}\n\n/**\n * The calls of one converted turn that wait on a person's approval, in turn\n * order: a gated call of the turn itself, or a `task` call not yet settled\n * (no result, or the running placeholder) whose lane holds a gated call — the\n * steps the turn's step list reads as waiting rather than running or done.\n */\nexport function turnToolCallsAwaitingApproval({\n message,\n toolCallIds,\n}: {\n message: ThreadMessage;\n /** The gated calls still waiting on a decision (`toolCallIdsAwaitingApproval`). */\n toolCallIds: ReadonlySet<string>;\n}): string[] {\n if (toolCallIds.size === 0 || message.role !== 'assistant') return [];\n const ids: string[] = [];\n for (const part of message.content) {\n if (part.type !== 'tool-call') continue;\n if (toolCallIds.has(part.toolCallId)) {\n ids.push(part.toolCallId);\n continue;\n }\n if (part.toolName !== TASK_TOOL_NAME) continue;\n const settled = part.result !== undefined && part.isPreliminary !== true;\n if (!settled && findToolCall({ messages: part.messages, toolCallIds }) !== undefined) {\n ids.push(part.toolCallId);\n }\n }\n return ids;\n}\n\nconst NO_WAITING_TOOL_CALLS: ReadonlySet<string> = new Set();\n/** Joins call ids into one selector value; an id never holds it. */\nconst TOOL_CALL_ID_SEPARATOR = '\\n';\n\n/**\n * {@link turnToolCallsAwaitingApproval} for the message in scope: what a\n * turn's step list takes as `waitingToolCallIds`, given the run's waiting\n * calls (`toolCallIdsAwaitingApproval`). Selected as a joined string, so a\n * streamed token re-renders the caller only when the waiting steps change, and\n * the set keeps its identity while they do not. Olympus's activity card and\n * the SDK chat's turns both read it.\n */\nexport function useTurnToolCallsAwaitingApproval(\n toolCallIds: ReadonlySet<string>\n): ReadonlySet<string> {\n const key = useAuiState((s) =>\n toolCallIds.size === 0\n ? ''\n : turnToolCallsAwaitingApproval({ message: s.message, toolCallIds }).join(\n TOOL_CALL_ID_SEPARATOR\n )\n );\n return useMemo(\n () => (key === '' ? NO_WAITING_TOOL_CALLS : new Set(key.split(TOOL_CALL_ID_SEPARATOR))),\n [key]\n );\n}\n\n/** Result text shown for a dispatch whose owning run ended before it finished. */\nexport const ORPHANED_SUBAGENT_OUTPUT =\n 'Interrupted — the run that dispatched this subagent ended before it finished.';\n\n/**\n * Settle snapshots orphaned by their dispatching context: once the owner (e.g.\n * the `eval` tool call whose in-eval `task()` issued them) is itself terminal,\n * nothing can ever deliver a `complete`/`error` lifecycle event for a lane still\n * `queued`/`running` — the dispatch coroutines were cancelled with the eval. Those\n * lanes are coerced to `error` with an interruption message so the UI can't show\n * perpetual \"Running · no activity\" ghosts. Returns the input array unchanged\n * (same reference) when there is nothing to settle.\n */\nexport function finalizeOrphanedSubagents(\n snapshots: readonly SubagentDiscoverySnapshot[],\n ownerTerminal: boolean\n): readonly SubagentDiscoverySnapshot[] {\n if (!ownerTerminal || snapshots.every((s) => isTerminalSubagentStatus(s.status))) {\n return snapshots;\n }\n return snapshots.map((s) =>\n isTerminalSubagentStatus(s.status)\n ? s\n : { ...s, status: 'error', output: s.output || ORPHANED_SUBAGENT_OUTPUT }\n );\n}\n\n/**\n * The `task` tool calls sharing `toolCallId`'s parent AI message — the parallel\n * fan-out siblings, in declaration order. Parallel `task` calls always live on ONE\n * AI message's `tool_calls`, so \"same parent message\" IS the parallelism boundary;\n * sequential delegations sit on separate AI messages and form singleton groups.\n * The FIRST sibling is the group's `anchorId`: its tool-part render draws the whole\n * side-by-side group and the other siblings render nothing, keeping the layout\n * change fully inside the `task` tool UI. Falls back to a singleton group when the\n * parent AI message isn't among `messages` (a turn's bound sources, or a raw\n * transcript).\n */\nexport interface TaskSiblingGroup {\n /** Sibling `task` tool-call ids in declaration order. */\n ids: string[];\n /** The first sibling — the one tool-part render that owns the group's UI. */\n anchorId: string;\n}\n\nexport function taskSiblingGroup(\n messages: readonly LangChainMessage[],\n toolCallId: string\n): TaskSiblingGroup {\n for (const m of messages) {\n if (m.type !== 'ai' || !m.tool_calls) continue;\n if (!m.tool_calls.some((tc) => tc.id === toolCallId)) continue;\n const ids = m.tool_calls\n .filter((tc) => tc.name === TASK_TOOL_NAME && tc.id)\n .map((tc) => tc.id as string);\n if (ids.length > 0) return { ids, anchorId: ids[0] ?? toolCallId };\n break;\n }\n return { ids: [toolCallId], anchorId: toolCallId };\n}\n"],"names":["DEEP_AGENT_TRUNCATED_LANE_KEY","DEEP_AGENT_LANE_USAGE_KEY","TASK_TOOL_NAME","getMessageText","withRepeatedResult","getExternalStoreMessages","useAuiState","useMemo"],"mappings":"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"}
|
|
@@ -211,6 +211,15 @@ export declare function nestedTodosFromArtifact(artifact: unknown): Todo[] | und
|
|
|
211
211
|
* dispatch's terminal status, duration, output, and error.
|
|
212
212
|
*/
|
|
213
213
|
export declare function ptcSubagentsFromArtifact(artifact: unknown): PtcSubagentEntry[];
|
|
214
|
+
/**
|
|
215
|
+
* How many subagents an `eval` call delegated to from inside the interpreter
|
|
216
|
+
* (its `task()` dispatches), read off the call's own artifact: the persisted
|
|
217
|
+
* dispatch summaries (`artifact.ptc_subagents`, one per dispatch id), else the
|
|
218
|
+
* `task` sub-calls its PTC log records (a running call's placeholder, or a
|
|
219
|
+
* backend that persists no summaries). Counted once per artifact object, so a
|
|
220
|
+
* settled call's count costs nothing when its turn is read again.
|
|
221
|
+
*/
|
|
222
|
+
export declare function countInEvalDispatches(artifact: unknown): number;
|
|
214
223
|
/**
|
|
215
224
|
* The lane of every `task` call in one converted turn (a `ThreadMessage`, or the
|
|
216
225
|
* message state assistant-ui publishes for it), keyed by tool-call id in call
|
|
@@ -63,6 +63,34 @@ function nestedTodosFromArtifact(artifact) {
|
|
|
63
63
|
const todos = (_a = a == null ? void 0 : a.subgraph_state) == null ? void 0 : _a.todos;
|
|
64
64
|
return Array.isArray(todos) ? todos : void 0;
|
|
65
65
|
}
|
|
66
|
+
function ptcSubagentsFromArtifact(artifact) {
|
|
67
|
+
const a = artifact;
|
|
68
|
+
const entries = a == null ? void 0 : a.ptc_subagents;
|
|
69
|
+
if (!Array.isArray(entries)) return [];
|
|
70
|
+
return entries.filter(
|
|
71
|
+
(entry) => !!entry && typeof entry === "object" && typeof entry.id === "string" && !!entry.id
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
const inEvalDispatchCounts = /* @__PURE__ */ new WeakMap();
|
|
75
|
+
function countInEvalDispatches(artifact) {
|
|
76
|
+
if (typeof artifact !== "object" || artifact === null) return 0;
|
|
77
|
+
const cached = inEvalDispatchCounts.get(artifact);
|
|
78
|
+
if (cached !== void 0) return cached;
|
|
79
|
+
const summaries = new Set(ptcSubagentsFromArtifact(artifact).map((entry) => entry.id));
|
|
80
|
+
let count = summaries.size;
|
|
81
|
+
if (count === 0) {
|
|
82
|
+
const dispatches = /* @__PURE__ */ new Set();
|
|
83
|
+
for (const message of nestedMessagesFromArtifact(artifact)) {
|
|
84
|
+
if (message.type !== "ai" || !message.tool_calls) continue;
|
|
85
|
+
for (const call of message.tool_calls) {
|
|
86
|
+
if (call.name === TASK_TOOL_NAME && call.id) dispatches.add(call.id);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
count = dispatches.size;
|
|
90
|
+
}
|
|
91
|
+
inEvalDispatchCounts.set(artifact, count);
|
|
92
|
+
return count;
|
|
93
|
+
}
|
|
66
94
|
const EMPTY_TRANSCRIPT_DERIVATION = {
|
|
67
95
|
currentText: "",
|
|
68
96
|
model: void 0,
|
|
@@ -238,9 +266,11 @@ function useTurnToolCallsAwaitingApproval(toolCallIds) {
|
|
|
238
266
|
);
|
|
239
267
|
}
|
|
240
268
|
export {
|
|
269
|
+
countInEvalDispatches,
|
|
241
270
|
isTerminalSubagentStatus,
|
|
242
271
|
nestedMessagesFromArtifact,
|
|
243
272
|
nestedTodosFromArtifact,
|
|
273
|
+
ptcSubagentsFromArtifact,
|
|
244
274
|
readLaneUsage,
|
|
245
275
|
readTruncatedLane,
|
|
246
276
|
subagentAwaitingApproval,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagents.js","sources":["../../../../agent-runtime/src/subagents.ts"],"sourcesContent":["/**\n * Subagent discovery: every subagent lane a deep-agent thread has spawned, as\n * the card view model the surfaces that draw subagent lanes render. Two\n * dispatch paths feed lanes keyed by dispatch id:\n *\n * - top-level `task` tool calls, read from the call's own tool-call part\n * ({@link taskSubagentsOfTurn}): the part's result and `isPreliminary` say\n * where the lane is, and its `messages` (the nested thread\n * `createSubagentTranscriptConversionCache` converts) are the transcript;\n * - in-eval `task()` dispatches ({@link deriveEvalSubagents}), whose only\n * signals are the live `ptc_subagents` state channel and the summaries a\n * finished `eval` ToolMessage persists in `artifact.ptc_subagents`.\n */\nimport {\n getExternalStoreMessages,\n type ThreadMessage,\n type ToolCallMessagePart,\n} from '@assistant-ui/core';\nimport type { LangChainMessage, LangChainToolCall } from '@assistant-ui/react-langgraph';\nimport { useAuiState } from '@assistant-ui/store';\nimport { useMemo } from 'react';\nimport {\n DEEP_AGENT_LANE_USAGE_KEY,\n DEEP_AGENT_TRUNCATED_LANE_KEY,\n} from './generated/runconfig-contract';\nimport { getMessageText } from './message-text';\nimport { convertSubagentTranscript, withRepeatedResult } from './subagent-transcripts';\nimport { EVAL_TOOL_NAME, TASK_TOOL_NAME } from './tool-names';\nimport type { PtcSubagentEntry, Todo } from './types';\n\n/**\n * Where a subagent lane is:\n *\n * - `queued` — the dispatch has not started: a `task` call with no result yet\n * (waiting for a dispatch slot or an approval; the backend shows the running\n * card once the dispatch holds its slot), or an in-eval dispatch waiting for\n * one of the bridge's concurrency slots.\n * - `running` — a `task` call's result is still the backend's running\n * placeholder (its part is `isPreliminary`), and the nested transcript fills\n * in live; or an in-eval dispatch's lifecycle says it runs.\n * - `complete` / `error` — the real result replaced the placeholder; `error`\n * when it is an error result.\n */\nexport type SubagentStatus = 'queued' | 'running' | 'complete' | 'error';\n\n/** True for the settled lifecycle states (`complete` / `error`). */\nexport function isTerminalSubagentStatus(status: SubagentStatus): boolean {\n return status === 'complete' || status === 'error';\n}\n\n/** Aggregate lane lifecycle counts for one fan-out (orchestration strip + header chip). */\nexport interface SubagentStatusCounts {\n total: number;\n queued: number;\n running: number;\n complete: number;\n failed: number;\n /** complete + failed — the settled count progress displays use. */\n terminal: number;\n}\n\nexport function countSubagentStatuses(\n snapshots: readonly SubagentDiscoverySnapshot[]\n): SubagentStatusCounts {\n const counts: SubagentStatusCounts = {\n total: snapshots.length,\n queued: 0,\n running: 0,\n complete: 0,\n failed: 0,\n terminal: 0,\n };\n for (const snapshot of snapshots) {\n if (snapshot.status === 'queued') counts.queued += 1;\n else if (snapshot.status === 'running') counts.running += 1;\n else if (snapshot.status === 'complete') counts.complete += 1;\n else counts.failed += 1;\n }\n counts.terminal = counts.complete + counts.failed;\n return counts;\n}\n\n/**\n * Discovery snapshot for one subagent invocation. Mirrors LangChain's\n * `SubagentDiscoverySnapshot`: `id` is the `task` tool-call id that spawned the\n * subagent (the dispatch id for an in-eval dispatch), so cards nest under the\n * coordinator turn that delegated the work.\n */\nexport interface SubagentDiscoverySnapshot {\n /** The `task` tool-call id that spawned the subagent. */\n id: string;\n /** Subagent type/name, from the `task` call's `subagent_type` arg. */\n name: string;\n /** The one-line task brief from the `task` call's `description` arg. */\n description: string;\n /** Lifecycle state — see {@link SubagentStatus}. */\n status: SubagentStatus;\n /** The call's result text (empty while it is the running placeholder). */\n output?: string;\n /** Number of nested tool calls the subagent made. */\n toolCallCount: number;\n /**\n * The subagent's transcript as a nested thread: a `task` part's native\n * `messages`, or an in-eval dispatch's live transcript converted the same way.\n */\n messages: readonly ThreadMessage[];\n /** Messages in the transcript as the wire carries them, before conversion joins a turn's steps. */\n messageCount: number;\n /**\n * Nested messages the wire left off: a cut card carries its newest steps\n * ({@link readTruncatedLane}) — a running card always, a finished one on a\n * version-2 view — and the rest pages in through `history/lane`; an in-eval\n * dispatch's streamed transcript is cut the same way, running or finished.\n * Absent when the transcript rides whole.\n */\n omittedMessageCount?: number;\n /**\n * Where the lane's steps ride, what `history/lane` pages the rest of the lane\n * under (`useDeepAgentLaneHistory`): a `task` lane's card, an in-eval lane's\n * registry entry while it streams its steps, or, once they no longer ride,\n * its subagent checkpoint (`checkpointed`), when agora recorded where that is\n * (`ns`). Absent for any other in-eval lane with no streamed steps (a summary\n * written before agora recorded the namespace, an older host).\n */\n source?: SubagentLaneSource;\n /** The subagent's own plan, nested by the backend on the task artifact (`subgraph_state.todos`). */\n todos?: Todo[];\n /** The newest tool call in the transcript — the card's \"last action\" ticker. */\n lastToolCall?: LangChainToolCall;\n /** The newest assistant text in the transcript — the card's thought preview. */\n currentText: string;\n /**\n * The `eval` tool-call id that dispatched this subagent, when it was spawned\n * from INSIDE the code interpreter (`task()` in the REPL) rather than by a\n * top-level `task` tool call. The eval card uses it to render lanes for its\n * own dispatches.\n */\n evalId?: string;\n /**\n * Backend-reported runtime for a finished in-eval dispatch (from the terminal\n * lifecycle event). Authoritative over client-side timing — it survives a page\n * refresh, where local first-seen timestamps are gone.\n */\n durationMs?: number;\n /** The model that produced the transcript, from its newest assistant turn's model stamp. */\n model?: string;\n /**\n * The lane's token use: the whole lane's as the host counts it\n * (`DEEP_AGENT_LANE_USAGE_KEY`), else the sum of the native step usage\n * (`metadata.steps[].usage`) of the steps the transcript holds. Absent while\n * no step reports any.\n */\n usage?: SubagentTokenUsage;\n}\n\n/** A subagent lane's token use. */\nexport interface SubagentTokenUsage {\n /** Input tokens, the prompt cache's reads and writes included. */\n readonly inputTokens: number;\n readonly outputTokens: number;\n /**\n * Less than the lane will have used: the lane still runs (its newest step may\n * not have reported yet), or no host total arrived and the sum covers only\n * the steps held of a lane cut to its newest ones.\n */\n readonly partial: boolean;\n}\n\n/** Input and output tokens of some model calls. */\nexport interface TokenCounts {\n readonly inputTokens: number;\n readonly outputTokens: number;\n}\n\nfunction subagentNameFromArgs(args: Readonly<Record<string, unknown>> | undefined): string {\n if (!args) return 'subagent';\n return String(args.subagent_type ?? args.subagentType ?? args.subagent ?? 'subagent');\n}\n\n/**\n * The subagent's streamed transcript as the wire carries it, read from a task\n * ToolMessage's `artifact.subgraph_state.messages` (the shape the backend nests\n * it under — see the route's `_subagent_subgraph_state`).\n */\nexport function nestedMessagesFromArtifact(artifact: unknown): LangChainMessage[] {\n const a = artifact as { subgraph_state?: { messages?: LangChainMessage[] } } | undefined;\n return a?.subgraph_state?.messages ?? [];\n}\n\n/** What the wire left off a cut `task` card's nested transcript. */\nexport interface TruncatedLane {\n /** Nested messages the host holds for the lane. */\n messages: number;\n /** Tool calls across all of them. */\n toolCalls: number;\n /**\n * The card is a finished lane's, cut for a version-2 view. Only a host that\n * serves `history/lane` cuts a finished card.\n */\n finished: boolean;\n}\n\n/**\n * Where a lane's steps ride, and what `history/lane` pages the rest of them\n * under: a `task` lane's card, by its message id, or an in-eval dispatch's\n * `ptc_subagents` registry entry, by its dispatch id.\n */\nexport type SubagentLaneSource = {\n /** The steps as the wire carries them (a card's report restored, {@link withRepeatedResult}). */\n readonly transcript: readonly LangChainMessage[];\n /** The cut marker; absent while every step rides. */\n readonly truncated?: TruncatedLane;\n /**\n * No steps ride, and `history/lane {lane}` pages the subagent's own steps\n * from its checkpoint: an in-eval lane a later run in this activation left\n * only its summary and `ns`, or a reopened session's lane (its registry gone,\n * the summary its eval persisted records `ns`).\n */\n readonly checkpointed?: true;\n} & (\n | {\n /** The card's message id: the running placeholder's, then the result's. */\n readonly messageId: string;\n readonly lane?: undefined;\n }\n | {\n /** The dispatch id: the in-eval lane's registry key. */\n readonly lane: string;\n readonly messageId?: undefined;\n }\n);\n\nconst isCount = (value: unknown): value is number =>\n typeof value === 'number' && Number.isInteger(value) && value >= 0;\n\n/**\n * The cut marker off a `task` card's raw wire message: the host carries only\n * the lane's newest nested steps and names the whole transcript here\n * (`DEEP_AGENT_TRUNCATED_LANE_KEY`), on a running card and, for a version-2\n * view, on a finished one. `null` when the transcript rides whole.\n */\nexport function readTruncatedLane(toolMessage: unknown): TruncatedLane | null {\n if (typeof toolMessage !== 'object' || toolMessage === null) return null;\n const marker = (toolMessage as Record<string, unknown>)[DEEP_AGENT_TRUNCATED_LANE_KEY];\n if (typeof marker !== 'object' || marker === null) return null;\n const { messages, tool_calls: toolCalls, finished } = marker as Record<string, unknown>;\n return isCount(messages) && isCount(toolCalls)\n ? { messages, toolCalls, finished: finished === true }\n : null;\n}\n\n/**\n * The whole lane's token use the host carries on a `task` card's raw wire\n * message or an in-eval lane's `ptc_subagents` entry\n * (`DEEP_AGENT_LANE_USAGE_KEY`), however much of the lane the wire carries.\n * `null` when it carries none (an older host, or no step reported usage).\n */\nexport function readLaneUsage(wire: unknown): TokenCounts | null {\n if (typeof wire !== 'object' || wire === null) return null;\n const usage = (wire as Record<string, unknown>)[DEEP_AGENT_LANE_USAGE_KEY];\n if (typeof usage !== 'object' || usage === null) return null;\n const { input_tokens: inputTokens, output_tokens: outputTokens } = usage as Record<\n string,\n unknown\n >;\n return isCount(inputTokens) && isCount(outputTokens) ? { inputTokens, outputTokens } : null;\n}\n\n/**\n * A lane's token use: the host's total when it sent one, else what the native\n * steps of the transcript held add up to, partial while the lane runs or when\n * that transcript is cut. `undefined` while neither counts anything.\n */\nfunction laneTokenUsage(\n wire: unknown,\n steps: TokenCounts | undefined,\n status: SubagentStatus,\n cut: boolean\n): SubagentTokenUsage | undefined {\n const settled = isTerminalSubagentStatus(status);\n const whole = readLaneUsage(wire);\n if (whole !== null) return { ...whole, partial: !settled };\n return steps === undefined ? undefined : { ...steps, partial: !settled || cut };\n}\n\nconst transcriptStepUsageCache = new WeakMap<readonly ThreadMessage[], TokenCounts | null>();\n\n/**\n * What the model calls of a converted transcript used, from assistant-ui's\n * native step usage (`metadata.steps[].usage`, one step per model call a turn\n * joined). `undefined` when no step reports usage. Memoized per transcript\n * array, which the conversion caches keep while the transcript is unchanged.\n */\nexport function transcriptStepUsage(messages: readonly ThreadMessage[]): TokenCounts | undefined {\n const cached = transcriptStepUsageCache.get(messages);\n if (cached !== undefined) return cached ?? undefined;\n let inputTokens = 0;\n let outputTokens = 0;\n let counted = false;\n for (const message of messages) {\n for (const step of message.metadata.steps ?? []) {\n if (step.usage === undefined) continue;\n inputTokens += step.usage.inputTokens;\n outputTokens += step.usage.outputTokens;\n counted = true;\n }\n }\n const usage = counted ? { inputTokens, outputTokens } : null;\n transcriptStepUsageCache.set(messages, usage);\n return usage ?? undefined;\n}\n\n/**\n * The subagent's own plan, read from a task ToolMessage's\n * `artifact.subgraph_state.todos` (the backend mirrors the subagent's isolated\n * `todos` state channel there — see the route's `_forward_subagent_todos`).\n * `undefined` (not `[]`) when the subagent never wrote a plan, so the UI can\n * distinguish \"no plan\" from \"plan with zero items\".\n */\nexport function nestedTodosFromArtifact(artifact: unknown): Todo[] | undefined {\n const a = artifact as { subgraph_state?: { todos?: unknown } } | undefined;\n const todos = a?.subgraph_state?.todos;\n return Array.isArray(todos) ? (todos as Todo[]) : undefined;\n}\n\n/**\n * The persisted in-eval dispatch summaries from an `eval` ToolMessage's\n * `artifact.ptc_subagents` (written by the backend when the eval ends). Unlike\n * the live `ptc_subagents` state channel — which dies with the stream — these\n * survive checkpoint reload, so reopened sessions can still render each\n * dispatch's terminal status, duration, output, and error.\n */\nexport function ptcSubagentsFromArtifact(artifact: unknown): PtcSubagentEntry[] {\n const a = artifact as { ptc_subagents?: unknown } | undefined;\n const entries = a?.ptc_subagents;\n if (!Array.isArray(entries)) return [];\n return entries.filter(\n (entry): entry is PtcSubagentEntry =>\n !!entry &&\n typeof entry === 'object' &&\n typeof (entry as { id?: unknown }).id === 'string' &&\n !!(entry as { id?: string }).id\n );\n}\n\n/**\n * What one transcript contributes to a lane: the newest assistant text\n * (thought preview), the newest tool call and the count (\"last action\"\n * ticker), the producing model, and the plan recovered from the newest\n * `write_todos` call — the fallback for in-eval lanes, whose isolated `todos`\n * state channel never reaches the wire (the task path nests todos on the\n * artifact instead); the call args carry the same list, so the progress ring\n * can still fill. A pure function of the transcript array.\n */\ninterface TranscriptDerivation {\n currentText: string;\n model: string | undefined;\n lastToolCall: LangChainToolCall | undefined;\n toolCallCount: number;\n todos: Todo[] | undefined;\n}\n\nconst EMPTY_TRANSCRIPT_DERIVATION: TranscriptDerivation = {\n currentText: '',\n model: undefined,\n lastToolCall: undefined,\n toolCallCount: 0,\n todos: undefined,\n};\n\n/**\n * Per-transcript cache for {@link deriveTranscript}: a lane's converted\n * transcript keeps its array while the lane does not change (the conversion\n * caches hand back the previous array), so only lanes still streaming are\n * read again.\n */\nconst transcriptDerivationCache = new WeakMap<readonly ThreadMessage[], TranscriptDerivation>();\n\nfunction deriveTranscript(transcript: readonly ThreadMessage[]): TranscriptDerivation {\n if (transcript.length === 0) return EMPTY_TRANSCRIPT_DERIVATION;\n const cached = transcriptDerivationCache.get(transcript);\n if (cached !== undefined) return cached;\n let currentText = '';\n let model: string | undefined;\n let lastToolCall: LangChainToolCall | undefined;\n let toolCallCount = 0;\n let todos: Todo[] | undefined;\n for (const message of transcript) {\n if (message.role !== 'assistant') continue;\n // A joined turn's `metadata.custom` merges its steps' stamps, the later\n // step's winning (`joinExternalMessages`), so this is the newest stamp.\n const turnModel: unknown = message.metadata?.custom?.model;\n if (typeof turnModel === 'string' && turnModel) model = turnModel;\n for (const part of message.content) {\n if (part.type === 'text') {\n if (part.text) currentText = part.text;\n continue;\n }\n if (part.type !== 'tool-call') continue;\n toolCallCount += 1;\n lastToolCall = { id: part.toolCallId, name: part.toolName, args: part.args };\n if (part.toolName !== 'write_todos') continue;\n const list: unknown = part.args.todos;\n if (Array.isArray(list)) todos = list as Todo[];\n }\n }\n const derivation: TranscriptDerivation = {\n currentText,\n model,\n lastToolCall,\n toolCallCount,\n todos,\n };\n transcriptDerivationCache.set(transcript, derivation);\n return derivation;\n}\n\nconst NO_TRANSCRIPT: readonly ThreadMessage[] = [];\n\n/**\n * The lane of one `task` tool-call part. `toolMessage` is the raw ToolMessage\n * answering it, which carries the wire's cut marker for a running lane.\n */\nfunction taskSubagent(\n part: ToolCallMessagePart,\n toolMessage: LangChainMessage | undefined\n): SubagentDiscoverySnapshot {\n const args: Readonly<Record<string, unknown>> = part.args;\n const transcript = part.messages ?? NO_TRANSCRIPT;\n const derived = deriveTranscript(transcript);\n const messageCount = nestedMessagesFromArtifact(part.artifact).length;\n const lane = readTruncatedLane(toolMessage);\n const todos = nestedTodosFromArtifact(part.artifact);\n const status: SubagentStatus =\n part.result === undefined\n ? 'queued'\n : part.isPreliminary === true\n ? 'running'\n : part.isError === true\n ? 'error'\n : 'complete';\n const usage = laneTokenUsage(\n toolMessage,\n transcriptStepUsage(transcript),\n status,\n lane !== null && lane.messages > messageCount\n );\n return {\n id: part.toolCallId,\n name: subagentNameFromArgs(args),\n description: typeof args.description === 'string' ? args.description : '',\n status,\n ...(part.result !== undefined && { output: getMessageText({ content: part.result }) }),\n toolCallCount: Math.max(derived.toolCallCount, lane?.toolCalls ?? 0),\n messages: transcript,\n messageCount,\n ...(lane !== null && { omittedMessageCount: Math.max(0, lane.messages - messageCount) }),\n ...(typeof toolMessage?.id === 'string' && {\n source: {\n messageId: toolMessage.id,\n transcript: withRepeatedResult(nestedMessagesFromArtifact(part.artifact), part.result),\n ...(lane !== null && { truncated: lane }),\n },\n }),\n ...(todos !== undefined && { todos }),\n ...(derived.lastToolCall !== undefined && { lastToolCall: derived.lastToolCall }),\n currentText: derived.currentText,\n ...(derived.model !== undefined && { model: derived.model }),\n ...(usage !== undefined && { usage }),\n };\n}\n\n/** The raw ToolMessage answering each tool call of a converted turn, from the sources bound to it. */\nfunction toolMessagesOfTurn(message: ThreadMessage): Map<string, LangChainMessage> {\n const byCall = new Map<string, LangChainMessage>();\n for (const source of getExternalStoreMessages<LangChainMessage>(message)) {\n if (source.type === 'tool') byCall.set(source.tool_call_id, source);\n }\n return byCall;\n}\n\n/**\n * Per-part lane cache: a re-converted turn keeps the part object of every call\n * whose ToolMessage did not change (the conversion cache's `keepUnchangedParts`),\n * so a streaming lane re-derives only itself.\n */\nconst taskSubagentByPart = new WeakMap<ToolCallMessagePart, SubagentDiscoverySnapshot>();\nconst taskSubagentsByTurn = new WeakMap<ThreadMessage, ReadonlyMap<string, SubagentDiscoverySnapshot>>();\n\n/**\n * The lane of every `task` call in one converted turn (a `ThreadMessage`, or the\n * message state assistant-ui publishes for it), keyed by tool-call id in call\n * order. Memoized per turn and per part.\n */\nexport function taskSubagentsOfTurn(\n message: ThreadMessage\n): ReadonlyMap<string, SubagentDiscoverySnapshot> {\n const cached = taskSubagentsByTurn.get(message);\n if (cached !== undefined) return cached;\n const lanes = new Map<string, SubagentDiscoverySnapshot>();\n if (message.role === 'assistant') {\n let toolMessages: Map<string, LangChainMessage> | null = null;\n for (const part of message.content) {\n if (part.type !== 'tool-call' || part.toolName !== TASK_TOOL_NAME) continue;\n let lane = taskSubagentByPart.get(part);\n if (lane === undefined) {\n toolMessages ??= toolMessagesOfTurn(message);\n lane = taskSubagent(part, toolMessages.get(part.toolCallId));\n taskSubagentByPart.set(part, lane);\n }\n lanes.set(part.toolCallId, lane);\n }\n }\n taskSubagentsByTurn.set(message, lanes);\n return lanes;\n}\n\n/** The lane of every `task` call in a converted thread, in transcript order. */\nexport function taskSubagentsOfThread(\n messages: readonly ThreadMessage[]\n): SubagentDiscoverySnapshot[] {\n return messages.flatMap((message) => [...taskSubagentsOfTurn(message).values()]);\n}\n\n/**\n * Point a lane at an in-eval dispatch's live transcript, converted into a nested\n * thread, with the live fields it derives. Never regresses a known tool-call\n * count: a countless later event must not reset a lane to \"0 tool calls\".\n */\nfunction applyLaneTranscript(\n snap: SubagentDiscoverySnapshot,\n transcript: readonly LangChainMessage[]\n): void {\n snap.messages = convertSubagentTranscript(transcript, snap.status === 'running');\n snap.messageCount = transcript.length;\n const derived = deriveTranscript(snap.messages);\n if (derived.currentText) snap.currentText = derived.currentText;\n if (derived.model) snap.model = derived.model;\n if (derived.lastToolCall) snap.lastToolCall = derived.lastToolCall;\n snap.toolCallCount = Math.max(snap.toolCallCount, derived.toolCallCount);\n // An in-eval lane has no artifact todos channel: recover the plan from its\n // `write_todos` calls.\n snap.todos = snap.todos ?? derived.todos;\n}\n\n/**\n * The lanes of in-eval dispatches, from two sources: the *persisted* summaries\n * each finished `eval` ToolMessage carries in `artifact.ptc_subagents`\n * (terminal truth; the only source after a session reopen), then the *live*\n * `ptc_subagents` state channel (`ptcSubagents`) for dispatches still\n * streaming. A live entry never downgrades a terminal snapshot back to\n * `running` — a stale lifecycle entry whose terminal event was lost must not\n * resurrect a perpetually-running lane the persisted summary already settled.\n * A lane whose steps no longer ride but whose subagent checkpoint namespace is\n * recorded (`ns`) is `checkpointed`, and `history/lane {lane}` pages its\n * steps: a live entry a later run stripped to its summary, or a persisted\n * summary with no live entry (the registry died with the activation that\n * streamed it). A live entry speaks for its lane over the summary.\n */\nexport function deriveEvalSubagents(\n messages: readonly LangChainMessage[],\n ptcSubagents?: Record<string, PtcSubagentEntry>\n): Map<string, SubagentDiscoverySnapshot> {\n const byDispatchId = new Map<string, SubagentDiscoverySnapshot>();\n // Persisted in-eval dispatch summaries (terminal truth; survives reopen).\n for (const m of messages) {\n if (m.type !== 'tool' || m.name !== EVAL_TOOL_NAME) continue;\n for (const entry of ptcSubagentsFromArtifact(m.artifact)) {\n mergePtcSubagentEntry(byDispatchId, entry, {\n // The eval ended when these summaries were written, so any lane the\n // backend could not settle is a cancelled dispatch, never \"running\".\n status: entry.status === 'complete' ? 'complete' : 'error',\n fallbackEvalId: m.tool_call_id,\n });\n noteCheckpointedLane(byDispatchId.get(entry.id), entry);\n }\n }\n // Live lifecycle entries (the only signal while an eval is still streaming).\n if (ptcSubagents) {\n for (const entry of Object.values(ptcSubagents)) {\n if (!entry || typeof entry !== 'object' || typeof entry.id !== 'string' || !entry.id) {\n continue;\n }\n // This activation's registry speaks for the lane: the steps it streams,\n // else its own namespace, else nothing to page.\n const existing = byDispatchId.get(entry.id);\n if (existing?.source?.checkpointed === true) existing.source = undefined;\n mergePtcSubagentEntry(byDispatchId, entry, {\n status:\n entry.status === 'complete'\n ? 'complete'\n : entry.status === 'error'\n ? 'error'\n : entry.status === 'queued'\n ? 'queued'\n : 'running',\n });\n noteCheckpointedLane(byDispatchId.get(entry.id), entry);\n }\n }\n return byDispatchId;\n}\n\n/** Lifecycle progression order — a merge may only move a lane forward. */\nfunction subagentStatusRank(status: SubagentStatus): number {\n if (status === 'queued') return 0;\n if (status === 'running') return 1;\n return 2;\n}\n\nfunction mergePtcSubagentEntry(\n byDispatchId: Map<string, SubagentDiscoverySnapshot>,\n entry: PtcSubagentEntry,\n options: { status: SubagentStatus; fallbackEvalId?: string }\n): void {\n const { status, fallbackEvalId } = options;\n const existing = byDispatchId.get(entry.id);\n if (existing) {\n // A lane only ever moves FORWARD (queued → running → terminal): a stale\n // entry whose later event was lost must not resurrect a running lane to\n // queued or a finished lane to running — and a settled terminal outcome\n // never flips to the other terminal (first settled source wins).\n if (\n status === existing.status ||\n subagentStatusRank(status) > subagentStatusRank(existing.status)\n ) {\n existing.status = status;\n }\n const evalId = entry.eval_id ?? fallbackEvalId;\n if (evalId) existing.evalId = evalId;\n if (typeof entry.duration_ms === 'number') existing.durationMs = entry.duration_ms;\n // A count only arrives on terminal events; never let a countless later\n // event (or an older backend) regress a known count.\n if (typeof entry.tool_call_count === 'number') {\n existing.toolCallCount = Math.max(existing.toolCallCount, entry.tool_call_count);\n }\n if (Array.isArray(entry.messages) && entry.messages.length > 0) {\n applyLaneTranscript(existing, entry.messages);\n }\n applyLaneCut(existing, entry);\n applyLaneUsage(existing, entry);\n // Prefer the real output (Athena's in-eval output bridge); fall back to the\n // error string only when no (non-empty) output was captured. Same\n // empty-string/nullish rule as the create branch below.\n if (entry.output) existing.output = entry.output;\n else if (entry.error && !existing.output) existing.output = entry.error;\n return;\n }\n // `||` (not `??`) so an empty-string output falls back to the error, matching\n // the merge branch's truthy check above.\n const initialOutput = entry.output || entry.error;\n const evalId = entry.eval_id ?? fallbackEvalId;\n const created: SubagentDiscoverySnapshot = {\n id: entry.id,\n name: String(entry.subagent_type ?? 'subagent'),\n description: entry.label ?? entry.description ?? '',\n status,\n toolCallCount: typeof entry.tool_call_count === 'number' ? entry.tool_call_count : 0,\n messages: NO_TRANSCRIPT,\n messageCount: 0,\n currentText: '',\n ...(evalId ? { evalId } : {}),\n ...(typeof entry.duration_ms === 'number' ? { durationMs: entry.duration_ms } : {}),\n ...(initialOutput ? { output: initialOutput } : {}),\n };\n if (Array.isArray(entry.messages) && entry.messages.length > 0) {\n applyLaneTranscript(created, entry.messages);\n }\n applyLaneCut(created, entry);\n applyLaneUsage(created, entry);\n byDispatchId.set(entry.id, created);\n}\n\n/**\n * Where an in-eval dispatch's streamed steps ride, and what the wire left off\n * them, read off its entry's cut marker (`DEEP_AGENT_TRUNCATED_LANE_KEY`) as a\n * `task` card's is: the steps left off, and the whole lane's tool calls.\n */\nfunction applyLaneCut(snap: SubagentDiscoverySnapshot, entry: PtcSubagentEntry): void {\n const lane = readTruncatedLane(entry);\n if (Array.isArray(entry.messages) && entry.messages.length > 0) {\n snap.source = {\n lane: entry.id,\n transcript: entry.messages,\n ...(lane !== null && { truncated: lane }),\n };\n }\n if (lane === null) return;\n snap.omittedMessageCount = Math.max(0, lane.messages - snap.messageCount);\n snap.toolCallCount = Math.max(snap.toolCallCount, lane.toolCalls);\n}\n\nconst NO_LANE_STEPS: readonly LangChainMessage[] = [];\n\n/**\n * An entry that recorded its subagent's checkpoint namespace (`ns`, a registry\n * entry or the summary an eval persisted, since agora writes it) pages its\n * lane from that checkpoint when no streamed steps carry it.\n */\nfunction noteCheckpointedLane(\n snap: SubagentDiscoverySnapshot | undefined,\n entry: PtcSubagentEntry\n): void {\n if (snap === undefined || snap.source !== undefined) return;\n if (typeof entry.ns !== 'string' || !entry.ns) return;\n snap.source = { lane: entry.id, transcript: NO_LANE_STEPS, checkpointed: true };\n}\n\n/**\n * An in-eval lane's token use, from its entry's host total or the native steps\n * of its live transcript. A merge that brings neither keeps what the lane has.\n */\nfunction applyLaneUsage(snap: SubagentDiscoverySnapshot, entry: PtcSubagentEntry): void {\n const usage = laneTokenUsage(\n entry,\n transcriptStepUsage(snap.messages),\n snap.status,\n (snap.omittedMessageCount ?? 0) > 0\n );\n if (usage !== undefined) snap.usage = usage;\n}\n\n/**\n * The first call of a nested thread with one of `toolCallIds`: the calls a\n * subagent made are the tool-call parts of its transcript, ids included.\n */\nfunction findToolCall({\n messages,\n toolCallIds,\n}: {\n messages: readonly ThreadMessage[] | undefined;\n toolCallIds: ReadonlySet<string>;\n}): ToolCallMessagePart | undefined {\n if (messages === undefined) return undefined;\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n for (const part of message.content) {\n if (part.type === 'tool-call' && toolCallIds.has(part.toolCallId)) return part;\n }\n }\n return undefined;\n}\n\n/**\n * Whether a subagent lane waits on a person's approval, given the gated calls\n * still waiting on one (`toolCallIdsAwaitingApproval`): its own dispatch is the\n * gated call (a per-dispatch `task` gate), or a call it made is (a gated tool\n * raised inside the delegated subagent). The approval names the gated call's\n * `tool_call_id` and never the lane, and a lane's transcript carries the calls\n * it made with their ids, so the call id is the join. A settled lane waits on\n * nobody.\n */\nexport function subagentAwaitingApproval({\n lane,\n toolCallIds,\n}: {\n lane: Pick<SubagentDiscoverySnapshot, 'id' | 'status' | 'messages'>;\n /** The gated calls still waiting on a decision (`toolCallIdsAwaitingApproval`). */\n toolCallIds: ReadonlySet<string>;\n}): boolean {\n if (toolCallIds.size === 0 || isTerminalSubagentStatus(lane.status)) return false;\n return (\n toolCallIds.has(lane.id) ||\n findToolCall({ messages: lane.messages, toolCallIds }) !== undefined\n );\n}\n\n/**\n * The call a subagent made that waits on a person's approval (a gated tool\n * raised inside the delegated subagent), read off its transcript — what the\n * lane card names while it waits. `undefined` when the lane made none, which\n * includes a lane whose own dispatch is the gated call.\n */\nexport function subagentToolCallAwaitingApproval({\n lane,\n toolCallIds,\n}: {\n lane: Pick<SubagentDiscoverySnapshot, 'status' | 'messages'>;\n /** The gated calls still waiting on a decision (`toolCallIdsAwaitingApproval`). */\n toolCallIds: ReadonlySet<string>;\n}): LangChainToolCall | undefined {\n if (toolCallIds.size === 0 || isTerminalSubagentStatus(lane.status)) return undefined;\n const part = findToolCall({ messages: lane.messages, toolCallIds });\n return part === undefined\n ? undefined\n : { id: part.toolCallId, name: part.toolName, args: part.args };\n}\n\n/**\n * The calls of one converted turn that wait on a person's approval, in turn\n * order: a gated call of the turn itself, or a `task` call not yet settled\n * (no result, or the running placeholder) whose lane holds a gated call — the\n * steps the turn's step list reads as waiting rather than running or done.\n */\nexport function turnToolCallsAwaitingApproval({\n message,\n toolCallIds,\n}: {\n message: ThreadMessage;\n /** The gated calls still waiting on a decision (`toolCallIdsAwaitingApproval`). */\n toolCallIds: ReadonlySet<string>;\n}): string[] {\n if (toolCallIds.size === 0 || message.role !== 'assistant') return [];\n const ids: string[] = [];\n for (const part of message.content) {\n if (part.type !== 'tool-call') continue;\n if (toolCallIds.has(part.toolCallId)) {\n ids.push(part.toolCallId);\n continue;\n }\n if (part.toolName !== TASK_TOOL_NAME) continue;\n const settled = part.result !== undefined && part.isPreliminary !== true;\n if (!settled && findToolCall({ messages: part.messages, toolCallIds }) !== undefined) {\n ids.push(part.toolCallId);\n }\n }\n return ids;\n}\n\nconst NO_WAITING_TOOL_CALLS: ReadonlySet<string> = new Set();\n/** Joins call ids into one selector value; an id never holds it. */\nconst TOOL_CALL_ID_SEPARATOR = '\\n';\n\n/**\n * {@link turnToolCallsAwaitingApproval} for the message in scope: what a\n * turn's step list takes as `waitingToolCallIds`, given the run's waiting\n * calls (`toolCallIdsAwaitingApproval`). Selected as a joined string, so a\n * streamed token re-renders the caller only when the waiting steps change, and\n * the set keeps its identity while they do not. Olympus's activity card and\n * the SDK chat's turns both read it.\n */\nexport function useTurnToolCallsAwaitingApproval(\n toolCallIds: ReadonlySet<string>\n): ReadonlySet<string> {\n const key = useAuiState((s) =>\n toolCallIds.size === 0\n ? ''\n : turnToolCallsAwaitingApproval({ message: s.message, toolCallIds }).join(\n TOOL_CALL_ID_SEPARATOR\n )\n );\n return useMemo(\n () => (key === '' ? NO_WAITING_TOOL_CALLS : new Set(key.split(TOOL_CALL_ID_SEPARATOR))),\n [key]\n );\n}\n\n/** Result text shown for a dispatch whose owning run ended before it finished. */\nexport const ORPHANED_SUBAGENT_OUTPUT =\n 'Interrupted — the run that dispatched this subagent ended before it finished.';\n\n/**\n * Settle snapshots orphaned by their dispatching context: once the owner (e.g.\n * the `eval` tool call whose in-eval `task()` issued them) is itself terminal,\n * nothing can ever deliver a `complete`/`error` lifecycle event for a lane still\n * `queued`/`running` — the dispatch coroutines were cancelled with the eval. Those\n * lanes are coerced to `error` with an interruption message so the UI can't show\n * perpetual \"Running · no activity\" ghosts. Returns the input array unchanged\n * (same reference) when there is nothing to settle.\n */\nexport function finalizeOrphanedSubagents(\n snapshots: readonly SubagentDiscoverySnapshot[],\n ownerTerminal: boolean\n): readonly SubagentDiscoverySnapshot[] {\n if (!ownerTerminal || snapshots.every((s) => isTerminalSubagentStatus(s.status))) {\n return snapshots;\n }\n return snapshots.map((s) =>\n isTerminalSubagentStatus(s.status)\n ? s\n : { ...s, status: 'error', output: s.output || ORPHANED_SUBAGENT_OUTPUT }\n );\n}\n\n/**\n * The `task` tool calls sharing `toolCallId`'s parent AI message — the parallel\n * fan-out siblings, in declaration order. Parallel `task` calls always live on ONE\n * AI message's `tool_calls`, so \"same parent message\" IS the parallelism boundary;\n * sequential delegations sit on separate AI messages and form singleton groups.\n * The FIRST sibling is the group's `anchorId`: its tool-part render draws the whole\n * side-by-side group and the other siblings render nothing, keeping the layout\n * change fully inside the `task` tool UI. Falls back to a singleton group when the\n * parent AI message isn't among `messages` (a turn's bound sources, or a raw\n * transcript).\n */\nexport interface TaskSiblingGroup {\n /** Sibling `task` tool-call ids in declaration order. */\n ids: string[];\n /** The first sibling — the one tool-part render that owns the group's UI. */\n anchorId: string;\n}\n\nexport function taskSiblingGroup(\n messages: readonly LangChainMessage[],\n toolCallId: string\n): TaskSiblingGroup {\n for (const m of messages) {\n if (m.type !== 'ai' || !m.tool_calls) continue;\n if (!m.tool_calls.some((tc) => tc.id === toolCallId)) continue;\n const ids = m.tool_calls\n .filter((tc) => tc.name === TASK_TOOL_NAME && tc.id)\n .map((tc) => tc.id as string);\n if (ids.length > 0) return { ids, anchorId: ids[0] ?? toolCallId };\n break;\n }\n return { ids: [toolCallId], anchorId: toolCallId };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"subagents.js","sources":["../../../../agent-runtime/src/subagents.ts"],"sourcesContent":["/**\n * Subagent discovery: every subagent lane a deep-agent thread has spawned, as\n * the card view model the surfaces that draw subagent lanes render. Two\n * dispatch paths feed lanes keyed by dispatch id:\n *\n * - top-level `task` tool calls, read from the call's own tool-call part\n * ({@link taskSubagentsOfTurn}): the part's result and `isPreliminary` say\n * where the lane is, and its `messages` (the nested thread\n * `createSubagentTranscriptConversionCache` converts) are the transcript;\n * - in-eval `task()` dispatches ({@link deriveEvalSubagents}), whose only\n * signals are the live `ptc_subagents` state channel and the summaries a\n * finished `eval` ToolMessage persists in `artifact.ptc_subagents`.\n */\nimport {\n getExternalStoreMessages,\n type ThreadMessage,\n type ToolCallMessagePart,\n} from '@assistant-ui/core';\nimport type { LangChainMessage, LangChainToolCall } from '@assistant-ui/react-langgraph';\nimport { useAuiState } from '@assistant-ui/store';\nimport { useMemo } from 'react';\nimport {\n DEEP_AGENT_LANE_USAGE_KEY,\n DEEP_AGENT_TRUNCATED_LANE_KEY,\n} from './generated/runconfig-contract';\nimport { getMessageText } from './message-text';\nimport { convertSubagentTranscript, withRepeatedResult } from './subagent-transcripts';\nimport { EVAL_TOOL_NAME, TASK_TOOL_NAME } from './tool-names';\nimport type { PtcSubagentEntry, Todo } from './types';\n\n/**\n * Where a subagent lane is:\n *\n * - `queued` — the dispatch has not started: a `task` call with no result yet\n * (waiting for a dispatch slot or an approval; the backend shows the running\n * card once the dispatch holds its slot), or an in-eval dispatch waiting for\n * one of the bridge's concurrency slots.\n * - `running` — a `task` call's result is still the backend's running\n * placeholder (its part is `isPreliminary`), and the nested transcript fills\n * in live; or an in-eval dispatch's lifecycle says it runs.\n * - `complete` / `error` — the real result replaced the placeholder; `error`\n * when it is an error result.\n */\nexport type SubagentStatus = 'queued' | 'running' | 'complete' | 'error';\n\n/** True for the settled lifecycle states (`complete` / `error`). */\nexport function isTerminalSubagentStatus(status: SubagentStatus): boolean {\n return status === 'complete' || status === 'error';\n}\n\n/** Aggregate lane lifecycle counts for one fan-out (orchestration strip + header chip). */\nexport interface SubagentStatusCounts {\n total: number;\n queued: number;\n running: number;\n complete: number;\n failed: number;\n /** complete + failed — the settled count progress displays use. */\n terminal: number;\n}\n\nexport function countSubagentStatuses(\n snapshots: readonly SubagentDiscoverySnapshot[]\n): SubagentStatusCounts {\n const counts: SubagentStatusCounts = {\n total: snapshots.length,\n queued: 0,\n running: 0,\n complete: 0,\n failed: 0,\n terminal: 0,\n };\n for (const snapshot of snapshots) {\n if (snapshot.status === 'queued') counts.queued += 1;\n else if (snapshot.status === 'running') counts.running += 1;\n else if (snapshot.status === 'complete') counts.complete += 1;\n else counts.failed += 1;\n }\n counts.terminal = counts.complete + counts.failed;\n return counts;\n}\n\n/**\n * Discovery snapshot for one subagent invocation. Mirrors LangChain's\n * `SubagentDiscoverySnapshot`: `id` is the `task` tool-call id that spawned the\n * subagent (the dispatch id for an in-eval dispatch), so cards nest under the\n * coordinator turn that delegated the work.\n */\nexport interface SubagentDiscoverySnapshot {\n /** The `task` tool-call id that spawned the subagent. */\n id: string;\n /** Subagent type/name, from the `task` call's `subagent_type` arg. */\n name: string;\n /** The one-line task brief from the `task` call's `description` arg. */\n description: string;\n /** Lifecycle state — see {@link SubagentStatus}. */\n status: SubagentStatus;\n /** The call's result text (empty while it is the running placeholder). */\n output?: string;\n /** Number of nested tool calls the subagent made. */\n toolCallCount: number;\n /**\n * The subagent's transcript as a nested thread: a `task` part's native\n * `messages`, or an in-eval dispatch's live transcript converted the same way.\n */\n messages: readonly ThreadMessage[];\n /** Messages in the transcript as the wire carries them, before conversion joins a turn's steps. */\n messageCount: number;\n /**\n * Nested messages the wire left off: a cut card carries its newest steps\n * ({@link readTruncatedLane}) — a running card always, a finished one on a\n * version-2 view — and the rest pages in through `history/lane`; an in-eval\n * dispatch's streamed transcript is cut the same way, running or finished.\n * Absent when the transcript rides whole.\n */\n omittedMessageCount?: number;\n /**\n * Where the lane's steps ride, what `history/lane` pages the rest of the lane\n * under (`useDeepAgentLaneHistory`): a `task` lane's card, an in-eval lane's\n * registry entry while it streams its steps, or, once they no longer ride,\n * its subagent checkpoint (`checkpointed`), when agora recorded where that is\n * (`ns`). Absent for any other in-eval lane with no streamed steps (a summary\n * written before agora recorded the namespace, an older host).\n */\n source?: SubagentLaneSource;\n /** The subagent's own plan, nested by the backend on the task artifact (`subgraph_state.todos`). */\n todos?: Todo[];\n /** The newest tool call in the transcript — the card's \"last action\" ticker. */\n lastToolCall?: LangChainToolCall;\n /** The newest assistant text in the transcript — the card's thought preview. */\n currentText: string;\n /**\n * The `eval` tool-call id that dispatched this subagent, when it was spawned\n * from INSIDE the code interpreter (`task()` in the REPL) rather than by a\n * top-level `task` tool call. The eval card uses it to render lanes for its\n * own dispatches.\n */\n evalId?: string;\n /**\n * Backend-reported runtime for a finished in-eval dispatch (from the terminal\n * lifecycle event). Authoritative over client-side timing — it survives a page\n * refresh, where local first-seen timestamps are gone.\n */\n durationMs?: number;\n /** The model that produced the transcript, from its newest assistant turn's model stamp. */\n model?: string;\n /**\n * The lane's token use: the whole lane's as the host counts it\n * (`DEEP_AGENT_LANE_USAGE_KEY`), else the sum of the native step usage\n * (`metadata.steps[].usage`) of the steps the transcript holds. Absent while\n * no step reports any.\n */\n usage?: SubagentTokenUsage;\n}\n\n/** A subagent lane's token use. */\nexport interface SubagentTokenUsage {\n /** Input tokens, the prompt cache's reads and writes included. */\n readonly inputTokens: number;\n readonly outputTokens: number;\n /**\n * Less than the lane will have used: the lane still runs (its newest step may\n * not have reported yet), or no host total arrived and the sum covers only\n * the steps held of a lane cut to its newest ones.\n */\n readonly partial: boolean;\n}\n\n/** Input and output tokens of some model calls. */\nexport interface TokenCounts {\n readonly inputTokens: number;\n readonly outputTokens: number;\n}\n\nfunction subagentNameFromArgs(args: Readonly<Record<string, unknown>> | undefined): string {\n if (!args) return 'subagent';\n return String(args.subagent_type ?? args.subagentType ?? args.subagent ?? 'subagent');\n}\n\n/**\n * The subagent's streamed transcript as the wire carries it, read from a task\n * ToolMessage's `artifact.subgraph_state.messages` (the shape the backend nests\n * it under — see the route's `_subagent_subgraph_state`).\n */\nexport function nestedMessagesFromArtifact(artifact: unknown): LangChainMessage[] {\n const a = artifact as { subgraph_state?: { messages?: LangChainMessage[] } } | undefined;\n return a?.subgraph_state?.messages ?? [];\n}\n\n/** What the wire left off a cut `task` card's nested transcript. */\nexport interface TruncatedLane {\n /** Nested messages the host holds for the lane. */\n messages: number;\n /** Tool calls across all of them. */\n toolCalls: number;\n /**\n * The card is a finished lane's, cut for a version-2 view. Only a host that\n * serves `history/lane` cuts a finished card.\n */\n finished: boolean;\n}\n\n/**\n * Where a lane's steps ride, and what `history/lane` pages the rest of them\n * under: a `task` lane's card, by its message id, or an in-eval dispatch's\n * `ptc_subagents` registry entry, by its dispatch id.\n */\nexport type SubagentLaneSource = {\n /** The steps as the wire carries them (a card's report restored, {@link withRepeatedResult}). */\n readonly transcript: readonly LangChainMessage[];\n /** The cut marker; absent while every step rides. */\n readonly truncated?: TruncatedLane;\n /**\n * No steps ride, and `history/lane {lane}` pages the subagent's own steps\n * from its checkpoint: an in-eval lane a later run in this activation left\n * only its summary and `ns`, or a reopened session's lane (its registry gone,\n * the summary its eval persisted records `ns`).\n */\n readonly checkpointed?: true;\n} & (\n | {\n /** The card's message id: the running placeholder's, then the result's. */\n readonly messageId: string;\n readonly lane?: undefined;\n }\n | {\n /** The dispatch id: the in-eval lane's registry key. */\n readonly lane: string;\n readonly messageId?: undefined;\n }\n);\n\nconst isCount = (value: unknown): value is number =>\n typeof value === 'number' && Number.isInteger(value) && value >= 0;\n\n/**\n * The cut marker off a `task` card's raw wire message: the host carries only\n * the lane's newest nested steps and names the whole transcript here\n * (`DEEP_AGENT_TRUNCATED_LANE_KEY`), on a running card and, for a version-2\n * view, on a finished one. `null` when the transcript rides whole.\n */\nexport function readTruncatedLane(toolMessage: unknown): TruncatedLane | null {\n if (typeof toolMessage !== 'object' || toolMessage === null) return null;\n const marker = (toolMessage as Record<string, unknown>)[DEEP_AGENT_TRUNCATED_LANE_KEY];\n if (typeof marker !== 'object' || marker === null) return null;\n const { messages, tool_calls: toolCalls, finished } = marker as Record<string, unknown>;\n return isCount(messages) && isCount(toolCalls)\n ? { messages, toolCalls, finished: finished === true }\n : null;\n}\n\n/**\n * The whole lane's token use the host carries on a `task` card's raw wire\n * message or an in-eval lane's `ptc_subagents` entry\n * (`DEEP_AGENT_LANE_USAGE_KEY`), however much of the lane the wire carries.\n * `null` when it carries none (an older host, or no step reported usage).\n */\nexport function readLaneUsage(wire: unknown): TokenCounts | null {\n if (typeof wire !== 'object' || wire === null) return null;\n const usage = (wire as Record<string, unknown>)[DEEP_AGENT_LANE_USAGE_KEY];\n if (typeof usage !== 'object' || usage === null) return null;\n const { input_tokens: inputTokens, output_tokens: outputTokens } = usage as Record<\n string,\n unknown\n >;\n return isCount(inputTokens) && isCount(outputTokens) ? { inputTokens, outputTokens } : null;\n}\n\n/**\n * A lane's token use: the host's total when it sent one, else what the native\n * steps of the transcript held add up to, partial while the lane runs or when\n * that transcript is cut. `undefined` while neither counts anything.\n */\nfunction laneTokenUsage(\n wire: unknown,\n steps: TokenCounts | undefined,\n status: SubagentStatus,\n cut: boolean\n): SubagentTokenUsage | undefined {\n const settled = isTerminalSubagentStatus(status);\n const whole = readLaneUsage(wire);\n if (whole !== null) return { ...whole, partial: !settled };\n return steps === undefined ? undefined : { ...steps, partial: !settled || cut };\n}\n\nconst transcriptStepUsageCache = new WeakMap<readonly ThreadMessage[], TokenCounts | null>();\n\n/**\n * What the model calls of a converted transcript used, from assistant-ui's\n * native step usage (`metadata.steps[].usage`, one step per model call a turn\n * joined). `undefined` when no step reports usage. Memoized per transcript\n * array, which the conversion caches keep while the transcript is unchanged.\n */\nexport function transcriptStepUsage(messages: readonly ThreadMessage[]): TokenCounts | undefined {\n const cached = transcriptStepUsageCache.get(messages);\n if (cached !== undefined) return cached ?? undefined;\n let inputTokens = 0;\n let outputTokens = 0;\n let counted = false;\n for (const message of messages) {\n for (const step of message.metadata.steps ?? []) {\n if (step.usage === undefined) continue;\n inputTokens += step.usage.inputTokens;\n outputTokens += step.usage.outputTokens;\n counted = true;\n }\n }\n const usage = counted ? { inputTokens, outputTokens } : null;\n transcriptStepUsageCache.set(messages, usage);\n return usage ?? undefined;\n}\n\n/**\n * The subagent's own plan, read from a task ToolMessage's\n * `artifact.subgraph_state.todos` (the backend mirrors the subagent's isolated\n * `todos` state channel there — see the route's `_forward_subagent_todos`).\n * `undefined` (not `[]`) when the subagent never wrote a plan, so the UI can\n * distinguish \"no plan\" from \"plan with zero items\".\n */\nexport function nestedTodosFromArtifact(artifact: unknown): Todo[] | undefined {\n const a = artifact as { subgraph_state?: { todos?: unknown } } | undefined;\n const todos = a?.subgraph_state?.todos;\n return Array.isArray(todos) ? (todos as Todo[]) : undefined;\n}\n\n/**\n * The persisted in-eval dispatch summaries from an `eval` ToolMessage's\n * `artifact.ptc_subagents` (written by the backend when the eval ends). Unlike\n * the live `ptc_subagents` state channel — which dies with the stream — these\n * survive checkpoint reload, so reopened sessions can still render each\n * dispatch's terminal status, duration, output, and error.\n */\nexport function ptcSubagentsFromArtifact(artifact: unknown): PtcSubagentEntry[] {\n const a = artifact as { ptc_subagents?: unknown } | undefined;\n const entries = a?.ptc_subagents;\n if (!Array.isArray(entries)) return [];\n return entries.filter(\n (entry): entry is PtcSubagentEntry =>\n !!entry &&\n typeof entry === 'object' &&\n typeof (entry as { id?: unknown }).id === 'string' &&\n !!(entry as { id?: string }).id\n );\n}\n\nconst inEvalDispatchCounts = new WeakMap<object, number>();\n\n/**\n * How many subagents an `eval` call delegated to from inside the interpreter\n * (its `task()` dispatches), read off the call's own artifact: the persisted\n * dispatch summaries (`artifact.ptc_subagents`, one per dispatch id), else the\n * `task` sub-calls its PTC log records (a running call's placeholder, or a\n * backend that persists no summaries). Counted once per artifact object, so a\n * settled call's count costs nothing when its turn is read again.\n */\nexport function countInEvalDispatches(artifact: unknown): number {\n if (typeof artifact !== 'object' || artifact === null) return 0;\n const cached = inEvalDispatchCounts.get(artifact);\n if (cached !== undefined) return cached;\n const summaries = new Set(ptcSubagentsFromArtifact(artifact).map((entry) => entry.id));\n let count = summaries.size;\n if (count === 0) {\n const dispatches = new Set<string>();\n for (const message of nestedMessagesFromArtifact(artifact)) {\n if (message.type !== 'ai' || !message.tool_calls) continue;\n for (const call of message.tool_calls) {\n if (call.name === TASK_TOOL_NAME && call.id) dispatches.add(call.id);\n }\n }\n count = dispatches.size;\n }\n inEvalDispatchCounts.set(artifact, count);\n return count;\n}\n\n/**\n * What one transcript contributes to a lane: the newest assistant text\n * (thought preview), the newest tool call and the count (\"last action\"\n * ticker), the producing model, and the plan recovered from the newest\n * `write_todos` call — the fallback for in-eval lanes, whose isolated `todos`\n * state channel never reaches the wire (the task path nests todos on the\n * artifact instead); the call args carry the same list, so the progress ring\n * can still fill. A pure function of the transcript array.\n */\ninterface TranscriptDerivation {\n currentText: string;\n model: string | undefined;\n lastToolCall: LangChainToolCall | undefined;\n toolCallCount: number;\n todos: Todo[] | undefined;\n}\n\nconst EMPTY_TRANSCRIPT_DERIVATION: TranscriptDerivation = {\n currentText: '',\n model: undefined,\n lastToolCall: undefined,\n toolCallCount: 0,\n todos: undefined,\n};\n\n/**\n * Per-transcript cache for {@link deriveTranscript}: a lane's converted\n * transcript keeps its array while the lane does not change (the conversion\n * caches hand back the previous array), so only lanes still streaming are\n * read again.\n */\nconst transcriptDerivationCache = new WeakMap<readonly ThreadMessage[], TranscriptDerivation>();\n\nfunction deriveTranscript(transcript: readonly ThreadMessage[]): TranscriptDerivation {\n if (transcript.length === 0) return EMPTY_TRANSCRIPT_DERIVATION;\n const cached = transcriptDerivationCache.get(transcript);\n if (cached !== undefined) return cached;\n let currentText = '';\n let model: string | undefined;\n let lastToolCall: LangChainToolCall | undefined;\n let toolCallCount = 0;\n let todos: Todo[] | undefined;\n for (const message of transcript) {\n if (message.role !== 'assistant') continue;\n // A joined turn's `metadata.custom` merges its steps' stamps, the later\n // step's winning (`joinExternalMessages`), so this is the newest stamp.\n const turnModel: unknown = message.metadata?.custom?.model;\n if (typeof turnModel === 'string' && turnModel) model = turnModel;\n for (const part of message.content) {\n if (part.type === 'text') {\n if (part.text) currentText = part.text;\n continue;\n }\n if (part.type !== 'tool-call') continue;\n toolCallCount += 1;\n lastToolCall = { id: part.toolCallId, name: part.toolName, args: part.args };\n if (part.toolName !== 'write_todos') continue;\n const list: unknown = part.args.todos;\n if (Array.isArray(list)) todos = list as Todo[];\n }\n }\n const derivation: TranscriptDerivation = {\n currentText,\n model,\n lastToolCall,\n toolCallCount,\n todos,\n };\n transcriptDerivationCache.set(transcript, derivation);\n return derivation;\n}\n\nconst NO_TRANSCRIPT: readonly ThreadMessage[] = [];\n\n/**\n * The lane of one `task` tool-call part. `toolMessage` is the raw ToolMessage\n * answering it, which carries the wire's cut marker for a running lane.\n */\nfunction taskSubagent(\n part: ToolCallMessagePart,\n toolMessage: LangChainMessage | undefined\n): SubagentDiscoverySnapshot {\n const args: Readonly<Record<string, unknown>> = part.args;\n const transcript = part.messages ?? NO_TRANSCRIPT;\n const derived = deriveTranscript(transcript);\n const messageCount = nestedMessagesFromArtifact(part.artifact).length;\n const lane = readTruncatedLane(toolMessage);\n const todos = nestedTodosFromArtifact(part.artifact);\n const status: SubagentStatus =\n part.result === undefined\n ? 'queued'\n : part.isPreliminary === true\n ? 'running'\n : part.isError === true\n ? 'error'\n : 'complete';\n const usage = laneTokenUsage(\n toolMessage,\n transcriptStepUsage(transcript),\n status,\n lane !== null && lane.messages > messageCount\n );\n return {\n id: part.toolCallId,\n name: subagentNameFromArgs(args),\n description: typeof args.description === 'string' ? args.description : '',\n status,\n ...(part.result !== undefined && { output: getMessageText({ content: part.result }) }),\n toolCallCount: Math.max(derived.toolCallCount, lane?.toolCalls ?? 0),\n messages: transcript,\n messageCount,\n ...(lane !== null && { omittedMessageCount: Math.max(0, lane.messages - messageCount) }),\n ...(typeof toolMessage?.id === 'string' && {\n source: {\n messageId: toolMessage.id,\n transcript: withRepeatedResult(nestedMessagesFromArtifact(part.artifact), part.result),\n ...(lane !== null && { truncated: lane }),\n },\n }),\n ...(todos !== undefined && { todos }),\n ...(derived.lastToolCall !== undefined && { lastToolCall: derived.lastToolCall }),\n currentText: derived.currentText,\n ...(derived.model !== undefined && { model: derived.model }),\n ...(usage !== undefined && { usage }),\n };\n}\n\n/** The raw ToolMessage answering each tool call of a converted turn, from the sources bound to it. */\nfunction toolMessagesOfTurn(message: ThreadMessage): Map<string, LangChainMessage> {\n const byCall = new Map<string, LangChainMessage>();\n for (const source of getExternalStoreMessages<LangChainMessage>(message)) {\n if (source.type === 'tool') byCall.set(source.tool_call_id, source);\n }\n return byCall;\n}\n\n/**\n * Per-part lane cache: a re-converted turn keeps the part object of every call\n * whose ToolMessage did not change (the conversion cache's `keepUnchangedParts`),\n * so a streaming lane re-derives only itself.\n */\nconst taskSubagentByPart = new WeakMap<ToolCallMessagePart, SubagentDiscoverySnapshot>();\nconst taskSubagentsByTurn = new WeakMap<ThreadMessage, ReadonlyMap<string, SubagentDiscoverySnapshot>>();\n\n/**\n * The lane of every `task` call in one converted turn (a `ThreadMessage`, or the\n * message state assistant-ui publishes for it), keyed by tool-call id in call\n * order. Memoized per turn and per part.\n */\nexport function taskSubagentsOfTurn(\n message: ThreadMessage\n): ReadonlyMap<string, SubagentDiscoverySnapshot> {\n const cached = taskSubagentsByTurn.get(message);\n if (cached !== undefined) return cached;\n const lanes = new Map<string, SubagentDiscoverySnapshot>();\n if (message.role === 'assistant') {\n let toolMessages: Map<string, LangChainMessage> | null = null;\n for (const part of message.content) {\n if (part.type !== 'tool-call' || part.toolName !== TASK_TOOL_NAME) continue;\n let lane = taskSubagentByPart.get(part);\n if (lane === undefined) {\n toolMessages ??= toolMessagesOfTurn(message);\n lane = taskSubagent(part, toolMessages.get(part.toolCallId));\n taskSubagentByPart.set(part, lane);\n }\n lanes.set(part.toolCallId, lane);\n }\n }\n taskSubagentsByTurn.set(message, lanes);\n return lanes;\n}\n\n/** The lane of every `task` call in a converted thread, in transcript order. */\nexport function taskSubagentsOfThread(\n messages: readonly ThreadMessage[]\n): SubagentDiscoverySnapshot[] {\n return messages.flatMap((message) => [...taskSubagentsOfTurn(message).values()]);\n}\n\n/**\n * Point a lane at an in-eval dispatch's live transcript, converted into a nested\n * thread, with the live fields it derives. Never regresses a known tool-call\n * count: a countless later event must not reset a lane to \"0 tool calls\".\n */\nfunction applyLaneTranscript(\n snap: SubagentDiscoverySnapshot,\n transcript: readonly LangChainMessage[]\n): void {\n snap.messages = convertSubagentTranscript(transcript, snap.status === 'running');\n snap.messageCount = transcript.length;\n const derived = deriveTranscript(snap.messages);\n if (derived.currentText) snap.currentText = derived.currentText;\n if (derived.model) snap.model = derived.model;\n if (derived.lastToolCall) snap.lastToolCall = derived.lastToolCall;\n snap.toolCallCount = Math.max(snap.toolCallCount, derived.toolCallCount);\n // An in-eval lane has no artifact todos channel: recover the plan from its\n // `write_todos` calls.\n snap.todos = snap.todos ?? derived.todos;\n}\n\n/**\n * The lanes of in-eval dispatches, from two sources: the *persisted* summaries\n * each finished `eval` ToolMessage carries in `artifact.ptc_subagents`\n * (terminal truth; the only source after a session reopen), then the *live*\n * `ptc_subagents` state channel (`ptcSubagents`) for dispatches still\n * streaming. A live entry never downgrades a terminal snapshot back to\n * `running` — a stale lifecycle entry whose terminal event was lost must not\n * resurrect a perpetually-running lane the persisted summary already settled.\n * A lane whose steps no longer ride but whose subagent checkpoint namespace is\n * recorded (`ns`) is `checkpointed`, and `history/lane {lane}` pages its\n * steps: a live entry a later run stripped to its summary, or a persisted\n * summary with no live entry (the registry died with the activation that\n * streamed it). A live entry speaks for its lane over the summary.\n */\nexport function deriveEvalSubagents(\n messages: readonly LangChainMessage[],\n ptcSubagents?: Record<string, PtcSubagentEntry>\n): Map<string, SubagentDiscoverySnapshot> {\n const byDispatchId = new Map<string, SubagentDiscoverySnapshot>();\n // Persisted in-eval dispatch summaries (terminal truth; survives reopen).\n for (const m of messages) {\n if (m.type !== 'tool' || m.name !== EVAL_TOOL_NAME) continue;\n for (const entry of ptcSubagentsFromArtifact(m.artifact)) {\n mergePtcSubagentEntry(byDispatchId, entry, {\n // The eval ended when these summaries were written, so any lane the\n // backend could not settle is a cancelled dispatch, never \"running\".\n status: entry.status === 'complete' ? 'complete' : 'error',\n fallbackEvalId: m.tool_call_id,\n });\n noteCheckpointedLane(byDispatchId.get(entry.id), entry);\n }\n }\n // Live lifecycle entries (the only signal while an eval is still streaming).\n if (ptcSubagents) {\n for (const entry of Object.values(ptcSubagents)) {\n if (!entry || typeof entry !== 'object' || typeof entry.id !== 'string' || !entry.id) {\n continue;\n }\n // This activation's registry speaks for the lane: the steps it streams,\n // else its own namespace, else nothing to page.\n const existing = byDispatchId.get(entry.id);\n if (existing?.source?.checkpointed === true) existing.source = undefined;\n mergePtcSubagentEntry(byDispatchId, entry, {\n status:\n entry.status === 'complete'\n ? 'complete'\n : entry.status === 'error'\n ? 'error'\n : entry.status === 'queued'\n ? 'queued'\n : 'running',\n });\n noteCheckpointedLane(byDispatchId.get(entry.id), entry);\n }\n }\n return byDispatchId;\n}\n\n/** Lifecycle progression order — a merge may only move a lane forward. */\nfunction subagentStatusRank(status: SubagentStatus): number {\n if (status === 'queued') return 0;\n if (status === 'running') return 1;\n return 2;\n}\n\nfunction mergePtcSubagentEntry(\n byDispatchId: Map<string, SubagentDiscoverySnapshot>,\n entry: PtcSubagentEntry,\n options: { status: SubagentStatus; fallbackEvalId?: string }\n): void {\n const { status, fallbackEvalId } = options;\n const existing = byDispatchId.get(entry.id);\n if (existing) {\n // A lane only ever moves FORWARD (queued → running → terminal): a stale\n // entry whose later event was lost must not resurrect a running lane to\n // queued or a finished lane to running — and a settled terminal outcome\n // never flips to the other terminal (first settled source wins).\n if (\n status === existing.status ||\n subagentStatusRank(status) > subagentStatusRank(existing.status)\n ) {\n existing.status = status;\n }\n const evalId = entry.eval_id ?? fallbackEvalId;\n if (evalId) existing.evalId = evalId;\n if (typeof entry.duration_ms === 'number') existing.durationMs = entry.duration_ms;\n // A count only arrives on terminal events; never let a countless later\n // event (or an older backend) regress a known count.\n if (typeof entry.tool_call_count === 'number') {\n existing.toolCallCount = Math.max(existing.toolCallCount, entry.tool_call_count);\n }\n if (Array.isArray(entry.messages) && entry.messages.length > 0) {\n applyLaneTranscript(existing, entry.messages);\n }\n applyLaneCut(existing, entry);\n applyLaneUsage(existing, entry);\n // Prefer the real output (Athena's in-eval output bridge); fall back to the\n // error string only when no (non-empty) output was captured. Same\n // empty-string/nullish rule as the create branch below.\n if (entry.output) existing.output = entry.output;\n else if (entry.error && !existing.output) existing.output = entry.error;\n return;\n }\n // `||` (not `??`) so an empty-string output falls back to the error, matching\n // the merge branch's truthy check above.\n const initialOutput = entry.output || entry.error;\n const evalId = entry.eval_id ?? fallbackEvalId;\n const created: SubagentDiscoverySnapshot = {\n id: entry.id,\n name: String(entry.subagent_type ?? 'subagent'),\n description: entry.label ?? entry.description ?? '',\n status,\n toolCallCount: typeof entry.tool_call_count === 'number' ? entry.tool_call_count : 0,\n messages: NO_TRANSCRIPT,\n messageCount: 0,\n currentText: '',\n ...(evalId ? { evalId } : {}),\n ...(typeof entry.duration_ms === 'number' ? { durationMs: entry.duration_ms } : {}),\n ...(initialOutput ? { output: initialOutput } : {}),\n };\n if (Array.isArray(entry.messages) && entry.messages.length > 0) {\n applyLaneTranscript(created, entry.messages);\n }\n applyLaneCut(created, entry);\n applyLaneUsage(created, entry);\n byDispatchId.set(entry.id, created);\n}\n\n/**\n * Where an in-eval dispatch's streamed steps ride, and what the wire left off\n * them, read off its entry's cut marker (`DEEP_AGENT_TRUNCATED_LANE_KEY`) as a\n * `task` card's is: the steps left off, and the whole lane's tool calls.\n */\nfunction applyLaneCut(snap: SubagentDiscoverySnapshot, entry: PtcSubagentEntry): void {\n const lane = readTruncatedLane(entry);\n if (Array.isArray(entry.messages) && entry.messages.length > 0) {\n snap.source = {\n lane: entry.id,\n transcript: entry.messages,\n ...(lane !== null && { truncated: lane }),\n };\n }\n if (lane === null) return;\n snap.omittedMessageCount = Math.max(0, lane.messages - snap.messageCount);\n snap.toolCallCount = Math.max(snap.toolCallCount, lane.toolCalls);\n}\n\nconst NO_LANE_STEPS: readonly LangChainMessage[] = [];\n\n/**\n * An entry that recorded its subagent's checkpoint namespace (`ns`, a registry\n * entry or the summary an eval persisted, since agora writes it) pages its\n * lane from that checkpoint when no streamed steps carry it.\n */\nfunction noteCheckpointedLane(\n snap: SubagentDiscoverySnapshot | undefined,\n entry: PtcSubagentEntry\n): void {\n if (snap === undefined || snap.source !== undefined) return;\n if (typeof entry.ns !== 'string' || !entry.ns) return;\n snap.source = { lane: entry.id, transcript: NO_LANE_STEPS, checkpointed: true };\n}\n\n/**\n * An in-eval lane's token use, from its entry's host total or the native steps\n * of its live transcript. A merge that brings neither keeps what the lane has.\n */\nfunction applyLaneUsage(snap: SubagentDiscoverySnapshot, entry: PtcSubagentEntry): void {\n const usage = laneTokenUsage(\n entry,\n transcriptStepUsage(snap.messages),\n snap.status,\n (snap.omittedMessageCount ?? 0) > 0\n );\n if (usage !== undefined) snap.usage = usage;\n}\n\n/**\n * The first call of a nested thread with one of `toolCallIds`: the calls a\n * subagent made are the tool-call parts of its transcript, ids included.\n */\nfunction findToolCall({\n messages,\n toolCallIds,\n}: {\n messages: readonly ThreadMessage[] | undefined;\n toolCallIds: ReadonlySet<string>;\n}): ToolCallMessagePart | undefined {\n if (messages === undefined) return undefined;\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n for (const part of message.content) {\n if (part.type === 'tool-call' && toolCallIds.has(part.toolCallId)) return part;\n }\n }\n return undefined;\n}\n\n/**\n * Whether a subagent lane waits on a person's approval, given the gated calls\n * still waiting on one (`toolCallIdsAwaitingApproval`): its own dispatch is the\n * gated call (a per-dispatch `task` gate), or a call it made is (a gated tool\n * raised inside the delegated subagent). The approval names the gated call's\n * `tool_call_id` and never the lane, and a lane's transcript carries the calls\n * it made with their ids, so the call id is the join. A settled lane waits on\n * nobody.\n */\nexport function subagentAwaitingApproval({\n lane,\n toolCallIds,\n}: {\n lane: Pick<SubagentDiscoverySnapshot, 'id' | 'status' | 'messages'>;\n /** The gated calls still waiting on a decision (`toolCallIdsAwaitingApproval`). */\n toolCallIds: ReadonlySet<string>;\n}): boolean {\n if (toolCallIds.size === 0 || isTerminalSubagentStatus(lane.status)) return false;\n return (\n toolCallIds.has(lane.id) ||\n findToolCall({ messages: lane.messages, toolCallIds }) !== undefined\n );\n}\n\n/**\n * The call a subagent made that waits on a person's approval (a gated tool\n * raised inside the delegated subagent), read off its transcript — what the\n * lane card names while it waits. `undefined` when the lane made none, which\n * includes a lane whose own dispatch is the gated call.\n */\nexport function subagentToolCallAwaitingApproval({\n lane,\n toolCallIds,\n}: {\n lane: Pick<SubagentDiscoverySnapshot, 'status' | 'messages'>;\n /** The gated calls still waiting on a decision (`toolCallIdsAwaitingApproval`). */\n toolCallIds: ReadonlySet<string>;\n}): LangChainToolCall | undefined {\n if (toolCallIds.size === 0 || isTerminalSubagentStatus(lane.status)) return undefined;\n const part = findToolCall({ messages: lane.messages, toolCallIds });\n return part === undefined\n ? undefined\n : { id: part.toolCallId, name: part.toolName, args: part.args };\n}\n\n/**\n * The calls of one converted turn that wait on a person's approval, in turn\n * order: a gated call of the turn itself, or a `task` call not yet settled\n * (no result, or the running placeholder) whose lane holds a gated call — the\n * steps the turn's step list reads as waiting rather than running or done.\n */\nexport function turnToolCallsAwaitingApproval({\n message,\n toolCallIds,\n}: {\n message: ThreadMessage;\n /** The gated calls still waiting on a decision (`toolCallIdsAwaitingApproval`). */\n toolCallIds: ReadonlySet<string>;\n}): string[] {\n if (toolCallIds.size === 0 || message.role !== 'assistant') return [];\n const ids: string[] = [];\n for (const part of message.content) {\n if (part.type !== 'tool-call') continue;\n if (toolCallIds.has(part.toolCallId)) {\n ids.push(part.toolCallId);\n continue;\n }\n if (part.toolName !== TASK_TOOL_NAME) continue;\n const settled = part.result !== undefined && part.isPreliminary !== true;\n if (!settled && findToolCall({ messages: part.messages, toolCallIds }) !== undefined) {\n ids.push(part.toolCallId);\n }\n }\n return ids;\n}\n\nconst NO_WAITING_TOOL_CALLS: ReadonlySet<string> = new Set();\n/** Joins call ids into one selector value; an id never holds it. */\nconst TOOL_CALL_ID_SEPARATOR = '\\n';\n\n/**\n * {@link turnToolCallsAwaitingApproval} for the message in scope: what a\n * turn's step list takes as `waitingToolCallIds`, given the run's waiting\n * calls (`toolCallIdsAwaitingApproval`). Selected as a joined string, so a\n * streamed token re-renders the caller only when the waiting steps change, and\n * the set keeps its identity while they do not. Olympus's activity card and\n * the SDK chat's turns both read it.\n */\nexport function useTurnToolCallsAwaitingApproval(\n toolCallIds: ReadonlySet<string>\n): ReadonlySet<string> {\n const key = useAuiState((s) =>\n toolCallIds.size === 0\n ? ''\n : turnToolCallsAwaitingApproval({ message: s.message, toolCallIds }).join(\n TOOL_CALL_ID_SEPARATOR\n )\n );\n return useMemo(\n () => (key === '' ? NO_WAITING_TOOL_CALLS : new Set(key.split(TOOL_CALL_ID_SEPARATOR))),\n [key]\n );\n}\n\n/** Result text shown for a dispatch whose owning run ended before it finished. */\nexport const ORPHANED_SUBAGENT_OUTPUT =\n 'Interrupted — the run that dispatched this subagent ended before it finished.';\n\n/**\n * Settle snapshots orphaned by their dispatching context: once the owner (e.g.\n * the `eval` tool call whose in-eval `task()` issued them) is itself terminal,\n * nothing can ever deliver a `complete`/`error` lifecycle event for a lane still\n * `queued`/`running` — the dispatch coroutines were cancelled with the eval. Those\n * lanes are coerced to `error` with an interruption message so the UI can't show\n * perpetual \"Running · no activity\" ghosts. Returns the input array unchanged\n * (same reference) when there is nothing to settle.\n */\nexport function finalizeOrphanedSubagents(\n snapshots: readonly SubagentDiscoverySnapshot[],\n ownerTerminal: boolean\n): readonly SubagentDiscoverySnapshot[] {\n if (!ownerTerminal || snapshots.every((s) => isTerminalSubagentStatus(s.status))) {\n return snapshots;\n }\n return snapshots.map((s) =>\n isTerminalSubagentStatus(s.status)\n ? s\n : { ...s, status: 'error', output: s.output || ORPHANED_SUBAGENT_OUTPUT }\n );\n}\n\n/**\n * The `task` tool calls sharing `toolCallId`'s parent AI message — the parallel\n * fan-out siblings, in declaration order. Parallel `task` calls always live on ONE\n * AI message's `tool_calls`, so \"same parent message\" IS the parallelism boundary;\n * sequential delegations sit on separate AI messages and form singleton groups.\n * The FIRST sibling is the group's `anchorId`: its tool-part render draws the whole\n * side-by-side group and the other siblings render nothing, keeping the layout\n * change fully inside the `task` tool UI. Falls back to a singleton group when the\n * parent AI message isn't among `messages` (a turn's bound sources, or a raw\n * transcript).\n */\nexport interface TaskSiblingGroup {\n /** Sibling `task` tool-call ids in declaration order. */\n ids: string[];\n /** The first sibling — the one tool-part render that owns the group's UI. */\n anchorId: string;\n}\n\nexport function taskSiblingGroup(\n messages: readonly LangChainMessage[],\n toolCallId: string\n): TaskSiblingGroup {\n for (const m of messages) {\n if (m.type !== 'ai' || !m.tool_calls) continue;\n if (!m.tool_calls.some((tc) => tc.id === toolCallId)) continue;\n const ids = m.tool_calls\n .filter((tc) => tc.name === TASK_TOOL_NAME && tc.id)\n .map((tc) => tc.id as string);\n if (ids.length > 0) return { ids, anchorId: ids[0] ?? toolCallId };\n break;\n }\n return { ids: [toolCallId], anchorId: toolCallId };\n}\n"],"names":[],"mappings":"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"}
|