@deepseek-harness-tui/dsh-tui 0.13.0 → 0.14.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 +85 -5
- package/assets/claude-girl/claude-girl-happy.png +0 -0
- package/assets/claude-girl/claude-girl.png +0 -0
- package/assets/codex-girl/codex-girl-happy.png +0 -0
- package/assets/codex-girl/codex-girl.png +0 -0
- package/bin/dsh-tui.js +104 -18
- package/cordis.patch.yml +2 -0
- package/cordis.yml +2 -0
- package/guide/dsh-tui-guide/SKILL.md +4 -2
- package/guide/dsh-tui-guide/claude-backend.en.md +203 -0
- package/guide/dsh-tui-guide/claude-backend.md +161 -0
- package/guide/dsh-tui-guide/codex-backend.en.md +297 -0
- package/guide/dsh-tui-guide/codex-backend.md +257 -0
- package/guide/dsh-tui-guide/configuration.en.md +9 -2
- package/guide/dsh-tui-guide/configuration.md +9 -2
- package/guide/dsh-tui-guide/interaction.en.md +169 -27
- package/guide/dsh-tui-guide/interaction.md +115 -17
- package/guide/dsh-tui-guide/themes.en.md +24 -2
- package/guide/dsh-tui-guide/themes.md +21 -2
- package/guide/dsh-tui-guide/user-guide.en.md +38 -23
- package/guide/dsh-tui-guide/user-guide.md +22 -11
- package/guide/dsh-tui-guide/vscode.en.md +1 -0
- package/guide/dsh-tui-guide/vscode.md +1 -0
- package/lib/settings.json +139 -6
- package/lib/types/adapter/channel/state.d.ts.map +1 -1
- package/lib/types/adapter/channel/state.js +1 -0
- package/lib/types/adapter/channel/ui-policy.d.ts +17 -2
- package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
- package/lib/types/adapter/channel/ui-policy.js +29 -0
- package/lib/types/adapter/channel/ui.d.ts.map +1 -1
- package/lib/types/adapter/channel/ui.js +45 -5
- package/lib/types/adapter/ports/channel-catalog.d.ts +7 -0
- package/lib/types/adapter/ports/channel-catalog.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-display.d.ts +7 -1
- package/lib/types/adapter/ports/channel-display.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-session.d.ts +5 -0
- package/lib/types/adapter/ports/channel-session.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-settings.d.ts +20 -0
- package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-ui.d.ts +183 -6
- package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-view.d.ts +477 -13
- package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
- package/lib/types/agent/backend.d.ts +168 -0
- package/lib/types/agent/backend.d.ts.map +1 -0
- package/lib/types/agent/backend.js +1 -0
- package/lib/types/agent/capabilities.d.ts +461 -0
- package/lib/types/agent/capabilities.d.ts.map +1 -0
- package/lib/types/agent/capabilities.js +1 -0
- package/lib/types/agent/events.d.ts +733 -0
- package/lib/types/agent/events.d.ts.map +1 -0
- package/lib/types/agent/events.js +2 -0
- package/lib/types/agent/index.d.ts +8 -0
- package/lib/types/agent/index.d.ts.map +1 -0
- package/lib/types/agent/index.js +7 -0
- package/lib/types/agent/messages.d.ts +52 -0
- package/lib/types/agent/messages.d.ts.map +1 -0
- package/lib/types/agent/messages.js +91 -0
- package/lib/types/agent/presentation.d.ts +29 -0
- package/lib/types/agent/presentation.d.ts.map +1 -0
- package/lib/types/agent/presentation.js +4 -0
- package/lib/types/agent/refs.d.ts +30 -0
- package/lib/types/agent/refs.d.ts.map +1 -0
- package/lib/types/agent/refs.js +39 -0
- package/lib/types/agent/session.d.ts +78 -0
- package/lib/types/agent/session.d.ts.map +1 -0
- package/lib/types/agent/session.js +1 -0
- package/lib/types/backends/claude/activity.d.ts +53 -0
- package/lib/types/backends/claude/activity.d.ts.map +1 -0
- package/lib/types/backends/claude/activity.js +103 -0
- package/lib/types/backends/claude/auth.d.ts +245 -0
- package/lib/types/backends/claude/auth.d.ts.map +1 -0
- package/lib/types/backends/claude/auth.js +503 -0
- package/lib/types/backends/claude/backend.d.ts +32 -0
- package/lib/types/backends/claude/backend.d.ts.map +1 -0
- package/lib/types/backends/claude/backend.js +296 -0
- package/lib/types/backends/claude/catalog.d.ts +17 -0
- package/lib/types/backends/claude/catalog.d.ts.map +1 -0
- package/lib/types/backends/claude/catalog.js +94 -0
- package/lib/types/backends/claude/channels.d.ts +63 -0
- package/lib/types/backends/claude/channels.d.ts.map +1 -0
- package/lib/types/backends/claude/channels.js +275 -0
- package/lib/types/backends/claude/contract.d.ts +37 -0
- package/lib/types/backends/claude/contract.d.ts.map +1 -0
- package/lib/types/backends/claude/contract.js +46 -0
- package/lib/types/backends/claude/controls.d.ts +134 -0
- package/lib/types/backends/claude/controls.d.ts.map +1 -0
- package/lib/types/backends/claude/controls.js +425 -0
- package/lib/types/backends/claude/dialogs.d.ts +62 -0
- package/lib/types/backends/claude/dialogs.d.ts.map +1 -0
- package/lib/types/backends/claude/dialogs.js +253 -0
- package/lib/types/backends/claude/flag-settings.d.ts +12 -0
- package/lib/types/backends/claude/flag-settings.d.ts.map +1 -0
- package/lib/types/backends/claude/flag-settings.js +49 -0
- package/lib/types/backends/claude/images.d.ts +49 -0
- package/lib/types/backends/claude/images.d.ts.map +1 -0
- package/lib/types/backends/claude/images.js +94 -0
- package/lib/types/backends/claude/index.d.ts +5 -0
- package/lib/types/backends/claude/index.d.ts.map +1 -0
- package/lib/types/backends/claude/index.js +4 -0
- package/lib/types/backends/claude/install.d.ts +15 -0
- package/lib/types/backends/claude/install.d.ts.map +1 -0
- package/lib/types/backends/claude/install.js +91 -0
- package/lib/types/backends/claude/modelEnv.d.ts +64 -0
- package/lib/types/backends/claude/modelEnv.d.ts.map +1 -0
- package/lib/types/backends/claude/modelEnv.js +199 -0
- package/lib/types/backends/claude/narrow.d.ts +10 -0
- package/lib/types/backends/claude/narrow.d.ts.map +1 -0
- package/lib/types/backends/claude/narrow.js +8 -0
- package/lib/types/backends/claude/older-history.d.ts +16 -0
- package/lib/types/backends/claude/older-history.d.ts.map +1 -0
- package/lib/types/backends/claude/older-history.js +101 -0
- package/lib/types/backends/claude/options.d.ts +181 -0
- package/lib/types/backends/claude/options.d.ts.map +1 -0
- package/lib/types/backends/claude/options.js +208 -0
- package/lib/types/backends/claude/permissions.d.ts +83 -0
- package/lib/types/backends/claude/permissions.d.ts.map +1 -0
- package/lib/types/backends/claude/permissions.js +331 -0
- package/lib/types/backends/claude/prefs.d.ts +55 -0
- package/lib/types/backends/claude/prefs.d.ts.map +1 -0
- package/lib/types/backends/claude/prefs.js +150 -0
- package/lib/types/backends/claude/process.d.ts +19 -0
- package/lib/types/backends/claude/process.d.ts.map +1 -0
- package/lib/types/backends/claude/process.js +156 -0
- package/lib/types/backends/claude/replay.d.ts +129 -0
- package/lib/types/backends/claude/replay.d.ts.map +1 -0
- package/lib/types/backends/claude/replay.js +505 -0
- package/lib/types/backends/claude/sdk-warnings.d.ts +23 -0
- package/lib/types/backends/claude/sdk-warnings.d.ts.map +1 -0
- package/lib/types/backends/claude/sdk-warnings.js +55 -0
- package/lib/types/backends/claude/sdk.d.ts +12 -0
- package/lib/types/backends/claude/sdk.d.ts.map +1 -0
- package/lib/types/backends/claude/sdk.js +34 -0
- package/lib/types/backends/claude/send-message.d.ts +54 -0
- package/lib/types/backends/claude/send-message.d.ts.map +1 -0
- package/lib/types/backends/claude/send-message.js +65 -0
- package/lib/types/backends/claude/session/auth.d.ts +47 -0
- package/lib/types/backends/claude/session/auth.d.ts.map +1 -0
- package/lib/types/backends/claude/session/auth.js +226 -0
- package/lib/types/backends/claude/session/channels.d.ts +82 -0
- package/lib/types/backends/claude/session/channels.d.ts.map +1 -0
- package/lib/types/backends/claude/session/channels.js +45 -0
- package/lib/types/backends/claude/session/input.d.ts +16 -0
- package/lib/types/backends/claude/session/input.d.ts.map +1 -0
- package/lib/types/backends/claude/session/input.js +64 -0
- package/lib/types/backends/claude/session/lifecycle.d.ts +6 -0
- package/lib/types/backends/claude/session/lifecycle.d.ts.map +1 -0
- package/lib/types/backends/claude/session/lifecycle.js +852 -0
- package/lib/types/backends/claude/session/store.d.ts +17 -0
- package/lib/types/backends/claude/session/store.d.ts.map +1 -0
- package/lib/types/backends/claude/session/store.js +122 -0
- package/lib/types/backends/claude/session/subagents.d.ts +13 -0
- package/lib/types/backends/claude/session/subagents.d.ts.map +1 -0
- package/lib/types/backends/claude/session/subagents.js +77 -0
- package/lib/types/backends/claude/session/types.d.ts +89 -0
- package/lib/types/backends/claude/session/types.d.ts.map +1 -0
- package/lib/types/backends/claude/session/types.js +1 -0
- package/lib/types/backends/claude/session.d.ts +4 -0
- package/lib/types/backends/claude/session.d.ts.map +1 -0
- package/lib/types/backends/claude/session.js +2 -0
- package/lib/types/backends/claude/side-query.d.ts +34 -0
- package/lib/types/backends/claude/side-query.d.ts.map +1 -0
- package/lib/types/backends/claude/side-query.js +116 -0
- package/lib/types/backends/claude/task-output.d.ts +13 -0
- package/lib/types/backends/claude/task-output.d.ts.map +1 -0
- package/lib/types/backends/claude/task-output.js +101 -0
- package/lib/types/backends/claude/tools.d.ts +45 -0
- package/lib/types/backends/claude/tools.d.ts.map +1 -0
- package/lib/types/backends/claude/tools.js +231 -0
- package/lib/types/backends/claude/transcript-file.d.ts +41 -0
- package/lib/types/backends/claude/transcript-file.d.ts.map +1 -0
- package/lib/types/backends/claude/transcript-file.js +195 -0
- package/lib/types/backends/claude/translate/attempts.d.ts +33 -0
- package/lib/types/backends/claude/translate/attempts.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/attempts.js +243 -0
- package/lib/types/backends/claude/translate/content.d.ts +33 -0
- package/lib/types/backends/claude/translate/content.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/content.js +91 -0
- package/lib/types/backends/claude/translate/core.d.ts +76 -0
- package/lib/types/backends/claude/translate/core.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/core.js +447 -0
- package/lib/types/backends/claude/translate/events.d.ts +9 -0
- package/lib/types/backends/claude/translate/events.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/events.js +77 -0
- package/lib/types/backends/claude/translate/lanes.d.ts +31 -0
- package/lib/types/backends/claude/translate/lanes.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/lanes.js +177 -0
- package/lib/types/backends/claude/translate/messages.d.ts +36 -0
- package/lib/types/backends/claude/translate/messages.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/messages.js +202 -0
- package/lib/types/backends/claude/translate/system.d.ts +40 -0
- package/lib/types/backends/claude/translate/system.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/system.js +399 -0
- package/lib/types/backends/claude/translate/tasks.d.ts +19 -0
- package/lib/types/backends/claude/translate/tasks.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/tasks.js +159 -0
- package/lib/types/backends/claude/translate/types.d.ts +114 -0
- package/lib/types/backends/claude/translate/types.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/types.js +1 -0
- package/lib/types/backends/claude/translate.d.ts +9 -0
- package/lib/types/backends/claude/translate.d.ts.map +1 -0
- package/lib/types/backends/claude/translate.js +6 -0
- package/lib/types/backends/codex/auth/external-tokens.d.ts +66 -0
- package/lib/types/backends/codex/auth/external-tokens.d.ts.map +1 -0
- package/lib/types/backends/codex/auth/external-tokens.js +325 -0
- package/lib/types/backends/codex/auth/route.d.ts +14 -0
- package/lib/types/backends/codex/auth/route.d.ts.map +1 -0
- package/lib/types/backends/codex/auth/route.js +52 -0
- package/lib/types/backends/codex/auth/status.d.ts +16 -0
- package/lib/types/backends/codex/auth/status.d.ts.map +1 -0
- package/lib/types/backends/codex/auth/status.js +115 -0
- package/lib/types/backends/codex/backend.d.ts +58 -0
- package/lib/types/backends/codex/backend.d.ts.map +1 -0
- package/lib/types/backends/codex/backend.js +201 -0
- package/lib/types/backends/codex/catalog.d.ts +17 -0
- package/lib/types/backends/codex/catalog.d.ts.map +1 -0
- package/lib/types/backends/codex/catalog.js +128 -0
- package/lib/types/backends/codex/channels.d.ts +59 -0
- package/lib/types/backends/codex/channels.d.ts.map +1 -0
- package/lib/types/backends/codex/channels.js +274 -0
- package/lib/types/backends/codex/contract.d.ts +46 -0
- package/lib/types/backends/codex/contract.d.ts.map +1 -0
- package/lib/types/backends/codex/contract.js +80 -0
- package/lib/types/backends/codex/detect.d.ts +14 -0
- package/lib/types/backends/codex/detect.d.ts.map +1 -0
- package/lib/types/backends/codex/detect.js +90 -0
- package/lib/types/backends/codex/index.d.ts +6 -0
- package/lib/types/backends/codex/index.d.ts.map +1 -0
- package/lib/types/backends/codex/index.js +5 -0
- package/lib/types/backends/codex/modes.d.ts +16 -0
- package/lib/types/backends/codex/modes.d.ts.map +1 -0
- package/lib/types/backends/codex/modes.js +49 -0
- package/lib/types/backends/codex/narrow.d.ts +20 -0
- package/lib/types/backends/codex/narrow.d.ts.map +1 -0
- package/lib/types/backends/codex/narrow.js +18 -0
- package/lib/types/backends/codex/prefs.d.ts +42 -0
- package/lib/types/backends/codex/prefs.d.ts.map +1 -0
- package/lib/types/backends/codex/prefs.js +124 -0
- package/lib/types/backends/codex/protocol/index.d.ts +149 -0
- package/lib/types/backends/codex/protocol/index.d.ts.map +1 -0
- package/lib/types/backends/codex/protocol/index.js +130 -0
- package/lib/types/backends/codex/rpc/binary.d.ts +35 -0
- package/lib/types/backends/codex/rpc/binary.d.ts.map +1 -0
- package/lib/types/backends/codex/rpc/binary.js +174 -0
- package/lib/types/backends/codex/rpc/client.d.ts +72 -0
- package/lib/types/backends/codex/rpc/client.d.ts.map +1 -0
- package/lib/types/backends/codex/rpc/client.js +214 -0
- package/lib/types/backends/codex/rpc/hub.d.ts +105 -0
- package/lib/types/backends/codex/rpc/hub.d.ts.map +1 -0
- package/lib/types/backends/codex/rpc/hub.js +532 -0
- package/lib/types/backends/codex/rpc/transport.d.ts +39 -0
- package/lib/types/backends/codex/rpc/transport.d.ts.map +1 -0
- package/lib/types/backends/codex/rpc/transport.js +212 -0
- package/lib/types/backends/codex/session/activity.d.ts +18 -0
- package/lib/types/backends/codex/session/activity.d.ts.map +1 -0
- package/lib/types/backends/codex/session/activity.js +108 -0
- package/lib/types/backends/codex/session/approvals.d.ts +39 -0
- package/lib/types/backends/codex/session/approvals.d.ts.map +1 -0
- package/lib/types/backends/codex/session/approvals.js +477 -0
- package/lib/types/backends/codex/session/commands.d.ts +37 -0
- package/lib/types/backends/codex/session/commands.d.ts.map +1 -0
- package/lib/types/backends/codex/session/commands.js +141 -0
- package/lib/types/backends/codex/session/controls.d.ts +37 -0
- package/lib/types/backends/codex/session/controls.d.ts.map +1 -0
- package/lib/types/backends/codex/session/controls.js +303 -0
- package/lib/types/backends/codex/session/goals.d.ts +25 -0
- package/lib/types/backends/codex/session/goals.d.ts.map +1 -0
- package/lib/types/backends/codex/session/goals.js +97 -0
- package/lib/types/backends/codex/session/history.d.ts +52 -0
- package/lib/types/backends/codex/session/history.d.ts.map +1 -0
- package/lib/types/backends/codex/session/history.js +196 -0
- package/lib/types/backends/codex/session/images.d.ts +17 -0
- package/lib/types/backends/codex/session/images.d.ts.map +1 -0
- package/lib/types/backends/codex/session/images.js +138 -0
- package/lib/types/backends/codex/session/input.d.ts +75 -0
- package/lib/types/backends/codex/session/input.d.ts.map +1 -0
- package/lib/types/backends/codex/session/input.js +294 -0
- package/lib/types/backends/codex/session/plan-review.d.ts +19 -0
- package/lib/types/backends/codex/session/plan-review.d.ts.map +1 -0
- package/lib/types/backends/codex/session/plan-review.js +48 -0
- package/lib/types/backends/codex/session/prompts.d.ts +7 -0
- package/lib/types/backends/codex/session/prompts.d.ts.map +1 -0
- package/lib/types/backends/codex/session/prompts.js +47 -0
- package/lib/types/backends/codex/session/session.d.ts +12 -0
- package/lib/types/backends/codex/session/session.d.ts.map +1 -0
- package/lib/types/backends/codex/session/session.js +871 -0
- package/lib/types/backends/codex/session/side-query.d.ts +25 -0
- package/lib/types/backends/codex/session/side-query.d.ts.map +1 -0
- package/lib/types/backends/codex/session/side-query.js +121 -0
- package/lib/types/backends/codex/session/state.d.ts +57 -0
- package/lib/types/backends/codex/session/state.d.ts.map +1 -0
- package/lib/types/backends/codex/session/state.js +1 -0
- package/lib/types/backends/codex/session/subagents.d.ts +28 -0
- package/lib/types/backends/codex/session/subagents.d.ts.map +1 -0
- package/lib/types/backends/codex/session/subagents.js +286 -0
- package/lib/types/backends/codex/session/tasks.d.ts +25 -0
- package/lib/types/backends/codex/session/tasks.d.ts.map +1 -0
- package/lib/types/backends/codex/session/tasks.js +207 -0
- package/lib/types/backends/codex/session/tool-output.d.ts +9 -0
- package/lib/types/backends/codex/session/tool-output.d.ts.map +1 -0
- package/lib/types/backends/codex/session/tool-output.js +29 -0
- package/lib/types/backends/codex/translate/commands.d.ts +30 -0
- package/lib/types/backends/codex/translate/commands.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/commands.js +103 -0
- package/lib/types/backends/codex/translate/events.d.ts +9 -0
- package/lib/types/backends/codex/translate/events.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/events.js +71 -0
- package/lib/types/backends/codex/translate/items.d.ts +112 -0
- package/lib/types/backends/codex/translate/items.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/items.js +375 -0
- package/lib/types/backends/codex/translate/live.d.ts +39 -0
- package/lib/types/backends/codex/translate/live.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/live.js +315 -0
- package/lib/types/backends/codex/translate/notices.d.ts +27 -0
- package/lib/types/backends/codex/translate/notices.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/notices.js +99 -0
- package/lib/types/backends/codex/translate/presentation.d.ts +49 -0
- package/lib/types/backends/codex/translate/presentation.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/presentation.js +237 -0
- package/lib/types/backends/codex/translate/replay.d.ts +18 -0
- package/lib/types/backends/codex/translate/replay.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/replay.js +33 -0
- package/lib/types/backends/codex/translate/usage.d.ts +29 -0
- package/lib/types/backends/codex/translate/usage.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/usage.js +65 -0
- package/lib/types/backends/shared/atomic-file.d.ts +4 -0
- package/lib/types/backends/shared/atomic-file.d.ts.map +1 -0
- package/lib/types/backends/shared/atomic-file.js +52 -0
- package/lib/types/backends/shared/channel-tokens.d.ts +29 -0
- package/lib/types/backends/shared/channel-tokens.d.ts.map +1 -0
- package/lib/types/backends/shared/channel-tokens.js +161 -0
- package/lib/types/backends/shared/display-path.d.ts +3 -0
- package/lib/types/backends/shared/display-path.d.ts.map +1 -0
- package/lib/types/backends/shared/display-path.js +12 -0
- package/lib/types/branding.d.ts +92 -0
- package/lib/types/branding.d.ts.map +1 -0
- package/lib/types/branding.js +117 -0
- package/lib/types/channel/activity.d.ts +53 -0
- package/lib/types/channel/activity.d.ts.map +1 -0
- package/lib/types/channel/activity.js +955 -0
- package/lib/types/channel/capabilities.d.ts +24 -0
- package/lib/types/channel/capabilities.d.ts.map +1 -0
- package/lib/types/channel/capabilities.js +57 -0
- package/lib/types/channel/channel-slug.d.ts +9 -0
- package/lib/types/channel/channel-slug.d.ts.map +1 -0
- package/lib/types/channel/channel-slug.js +15 -0
- package/lib/types/channel/channel-wizard.d.ts +30 -0
- package/lib/types/channel/channel-wizard.d.ts.map +1 -0
- package/lib/types/channel/channel-wizard.js +226 -0
- package/lib/types/channel/elicitation.d.ts +135 -0
- package/lib/types/channel/elicitation.d.ts.map +1 -0
- package/lib/types/channel/elicitation.js +360 -0
- package/lib/types/channel/goal-command.d.ts +49 -0
- package/lib/types/channel/goal-command.d.ts.map +1 -0
- package/lib/types/channel/goal-command.js +72 -0
- package/lib/types/channel/history-restore.d.ts +16 -0
- package/lib/types/channel/history-restore.d.ts.map +1 -0
- package/lib/types/channel/history-restore.js +214 -0
- package/lib/types/channel/interaction.d.ts +38 -0
- package/lib/types/channel/interaction.d.ts.map +1 -0
- package/lib/types/channel/interaction.js +110 -0
- package/lib/types/channel/job-format.d.ts +6 -0
- package/lib/types/channel/job-format.d.ts.map +1 -0
- package/lib/types/channel/job-format.js +12 -0
- package/lib/types/channel/live-output.d.ts +35 -0
- package/lib/types/channel/live-output.d.ts.map +1 -0
- package/lib/types/channel/live-output.js +74 -0
- package/lib/types/channel/model-capabilities.d.ts +10 -0
- package/lib/types/channel/model-capabilities.d.ts.map +1 -0
- package/lib/types/channel/model-capabilities.js +51 -0
- package/lib/types/channel/permissions.d.ts +155 -0
- package/lib/types/channel/permissions.d.ts.map +1 -0
- package/lib/types/channel/permissions.js +188 -0
- package/lib/types/channel/projection.d.ts +110 -0
- package/lib/types/channel/projection.d.ts.map +1 -0
- package/lib/types/channel/projection.js +1521 -0
- package/lib/types/channel/question-record.d.ts +76 -0
- package/lib/types/channel/question-record.d.ts.map +1 -0
- package/lib/types/channel/question-record.js +109 -0
- package/lib/types/channel/questions.d.ts +204 -0
- package/lib/types/channel/questions.d.ts.map +1 -0
- package/lib/types/channel/questions.js +286 -0
- package/lib/types/channel/sanitize.d.ts +49 -0
- package/lib/types/channel/sanitize.d.ts.map +1 -0
- package/lib/types/channel/sanitize.js +88 -0
- package/lib/types/channel/selection-record.d.ts +18 -0
- package/lib/types/channel/selection-record.d.ts.map +1 -0
- package/lib/types/channel/selection-record.js +45 -0
- package/lib/types/channel/side-prompts.d.ts +59 -0
- package/lib/types/channel/side-prompts.d.ts.map +1 -0
- package/lib/types/channel/side-prompts.js +127 -0
- package/lib/types/channel/transcript.d.ts +17 -0
- package/lib/types/channel/transcript.d.ts.map +1 -0
- package/lib/types/channel/transcript.js +19 -0
- package/lib/types/channel/usage.d.ts +48 -0
- package/lib/types/channel/usage.d.ts.map +1 -0
- package/lib/types/channel/usage.js +143 -0
- package/lib/types/commands.d.ts +147 -0
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +196 -2
- package/lib/types/components/AgentMessageComposer.d.ts +50 -0
- package/lib/types/components/AgentMessageComposer.d.ts.map +1 -0
- package/lib/types/components/AgentMessageComposer.js +159 -0
- package/lib/types/components/BtwPanel.d.ts +13 -12
- package/lib/types/components/BtwPanel.d.ts.map +1 -1
- package/lib/types/components/BtwPanel.js +35 -24
- package/lib/types/components/ChannelPicker.d.ts +40 -0
- package/lib/types/components/ChannelPicker.d.ts.map +1 -0
- package/lib/types/components/ChannelPicker.js +26 -0
- package/lib/types/components/Chat/JobCard.d.ts +29 -31
- package/lib/types/components/Chat/JobCard.d.ts.map +1 -1
- package/lib/types/components/Chat/JobCard.js +31 -112
- package/lib/types/components/Chat/SubagentMessage.d.ts +4 -1
- package/lib/types/components/Chat/SubagentMessage.d.ts.map +1 -1
- package/lib/types/components/Chat/SubagentMessage.js +10 -3
- package/lib/types/components/ClaudeGirl.d.ts +27 -0
- package/lib/types/components/ClaudeGirl.d.ts.map +1 -0
- package/lib/types/components/ClaudeGirl.js +30 -0
- package/lib/types/components/CodeBlockFrame.d.ts +19 -0
- package/lib/types/components/CodeBlockFrame.d.ts.map +1 -0
- package/lib/types/components/CodeBlockFrame.js +138 -0
- package/lib/types/components/CommandSuggestions.d.ts +10 -1
- package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
- package/lib/types/components/CommandSuggestions.js +20 -3
- package/lib/types/components/ContextBarView.d.ts +2 -2
- package/lib/types/components/ContextBarView.d.ts.map +1 -1
- package/lib/types/components/ContextBarView.js +18 -8
- package/lib/types/components/EffortChargeGlyph.d.ts +1 -1
- package/lib/types/components/EffortChargeGlyph.d.ts.map +1 -1
- package/lib/types/components/EffortChargeGlyph.js +3 -4
- package/lib/types/components/EffortInputBorder.d.ts +1 -2
- package/lib/types/components/EffortInputBorder.d.ts.map +1 -1
- package/lib/types/components/EffortInputBorder.js +7 -4
- package/lib/types/components/EffortSlider.d.ts +5 -1
- package/lib/types/components/EffortSlider.d.ts.map +1 -1
- package/lib/types/components/EffortSlider.js +2 -2
- package/lib/types/components/EffortTierBadge.d.ts +1 -2
- package/lib/types/components/EffortTierBadge.d.ts.map +1 -1
- package/lib/types/components/EffortTierBadge.js +8 -5
- package/lib/types/components/GoalTodoPanel.d.ts +2 -1
- package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
- package/lib/types/components/GoalTodoPanel.js +11 -5
- package/lib/types/components/InlineMathParagraph.js +1 -1
- package/lib/types/components/JobsPanel.d.ts +8 -9
- package/lib/types/components/JobsPanel.d.ts.map +1 -1
- package/lib/types/components/JobsPanel.js +72 -13
- package/lib/types/components/KernelPicker.d.ts +28 -0
- package/lib/types/components/KernelPicker.d.ts.map +1 -0
- package/lib/types/components/KernelPicker.js +37 -0
- package/lib/types/components/LogoV2.d.ts +7 -1
- package/lib/types/components/LogoV2.d.ts.map +1 -1
- package/lib/types/components/LogoV2.js +120 -24
- package/lib/types/components/Markdown.d.ts +2 -1
- package/lib/types/components/Markdown.d.ts.map +1 -1
- package/lib/types/components/Markdown.js +37 -8
- package/lib/types/components/MathBlock.d.ts.map +1 -1
- package/lib/types/components/MathBlock.js +3 -1
- package/lib/types/components/MermaidDiagram.d.ts.map +1 -1
- package/lib/types/components/MermaidDiagram.js +7 -5
- package/lib/types/components/MessageList.d.ts +21 -3
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +62 -42
- package/lib/types/components/ModePicker.d.ts +20 -0
- package/lib/types/components/ModePicker.d.ts.map +1 -0
- package/lib/types/components/ModePicker.js +17 -0
- package/lib/types/components/PromptInput.d.ts +2 -2
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +308 -55
- package/lib/types/components/SdkInstallWizard.d.ts +44 -0
- package/lib/types/components/SdkInstallWizard.d.ts.map +1 -0
- package/lib/types/components/SdkInstallWizard.js +18 -0
- package/lib/types/components/SearchBox.d.ts +7 -8
- package/lib/types/components/SearchBox.d.ts.map +1 -1
- package/lib/types/components/SearchBox.js +18 -9
- package/lib/types/components/SplitDiffView.d.ts.map +1 -1
- package/lib/types/components/SplitDiffView.js +113 -6
- package/lib/types/components/StarPrompt.d.ts.map +1 -1
- package/lib/types/components/StarPrompt.js +5 -3
- package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
- package/lib/types/components/StreamingMarkdown.js +6 -4
- package/lib/types/components/SubagentCard.d.ts +2 -1
- package/lib/types/components/SubagentCard.d.ts.map +1 -1
- package/lib/types/components/SubagentCard.js +25 -18
- package/lib/types/components/SubagentDashboard.d.ts +10 -6
- package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
- package/lib/types/components/SubagentDashboard.js +32 -21
- package/lib/types/components/SubagentDetailScene.d.ts +16 -1
- package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
- package/lib/types/components/SubagentDetailScene.js +196 -45
- package/lib/types/components/SyntaxText.d.ts.map +1 -1
- package/lib/types/components/SyntaxText.js +4 -1
- package/lib/types/components/TurnInterruptedRow.d.ts +3 -1
- package/lib/types/components/TurnInterruptedRow.d.ts.map +1 -1
- package/lib/types/components/TurnInterruptedRow.js +6 -3
- package/lib/types/components/TurnUsageRow.d.ts +24 -0
- package/lib/types/components/TurnUsageRow.d.ts.map +1 -0
- package/lib/types/components/TurnUsageRow.js +46 -0
- package/lib/types/components/WorkingSpinner.d.ts +2 -1
- package/lib/types/components/WorkingSpinner.d.ts.map +1 -1
- package/lib/types/components/WorkingSpinner.js +21 -4
- package/lib/types/components/approvals/ApprovalPanel.d.ts +36 -13
- package/lib/types/components/approvals/ApprovalPanel.d.ts.map +1 -1
- package/lib/types/components/approvals/ApprovalPanel.js +173 -25
- package/lib/types/components/claudeGirlSprite.d.ts +18 -0
- package/lib/types/components/claudeGirlSprite.d.ts.map +1 -0
- package/lib/types/components/claudeGirlSprite.js +48 -0
- package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
- package/lib/types/components/design-system/ThemeProvider.js +46 -13
- package/lib/types/components/design-system/ThemedText.d.ts +3 -1
- package/lib/types/components/design-system/ThemedText.d.ts.map +1 -1
- package/lib/types/components/design-system/ThemedText.js +2 -2
- package/lib/types/components/diffPatch.d.ts +55 -0
- package/lib/types/components/diffPatch.d.ts.map +1 -0
- package/lib/types/components/diffPatch.js +142 -0
- package/lib/types/components/kernelCatalog.d.ts +48 -0
- package/lib/types/components/kernelCatalog.d.ts.map +1 -0
- package/lib/types/components/kernelCatalog.js +53 -0
- package/lib/types/components/launchpadActions.d.ts +13 -6
- package/lib/types/components/launchpadActions.d.ts.map +1 -1
- package/lib/types/components/launchpadActions.js +26 -4
- package/lib/types/components/launchpadParams.d.ts +101 -0
- package/lib/types/components/launchpadParams.d.ts.map +1 -0
- package/lib/types/components/launchpadParams.js +171 -0
- package/lib/types/components/maidPortrait.d.ts +37 -5
- package/lib/types/components/maidPortrait.d.ts.map +1 -1
- package/lib/types/components/maidPortrait.js +73 -54
- package/lib/types/components/messages/AgentMessageFlow.d.ts +20 -0
- package/lib/types/components/messages/AgentMessageFlow.d.ts.map +1 -0
- package/lib/types/components/messages/AgentMessageFlow.js +37 -0
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts +6 -1
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantThinkingMessage.js +29 -5
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts +11 -2
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +289 -36
- package/lib/types/components/messages/TranscriptLeaves.d.ts +85 -0
- package/lib/types/components/messages/TranscriptLeaves.d.ts.map +1 -0
- package/lib/types/components/messages/TranscriptLeaves.js +74 -0
- package/lib/types/components/messages/agentTeam.d.ts +69 -0
- package/lib/types/components/messages/agentTeam.d.ts.map +1 -0
- package/lib/types/components/messages/agentTeam.js +53 -0
- package/lib/types/components/messages/liveOutputLines.d.ts +33 -0
- package/lib/types/components/messages/liveOutputLines.d.ts.map +1 -0
- package/lib/types/components/messages/liveOutputLines.js +100 -0
- package/lib/types/components/messages/subagentTranscript.d.ts +146 -0
- package/lib/types/components/messages/subagentTranscript.d.ts.map +1 -0
- package/lib/types/components/messages/subagentTranscript.js +304 -0
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts +16 -1
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
- package/lib/types/components/questions/AskUserQuestionPanel.js +76 -6
- package/lib/types/components/questions/PlanReviewPanel.d.ts +8 -3
- package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
- package/lib/types/components/questions/PlanReviewPanel.js +11 -6
- package/lib/types/components/questions/ProviderModelEditor.d.ts +12 -0
- package/lib/types/components/questions/ProviderModelEditor.d.ts.map +1 -0
- package/lib/types/components/questions/ProviderModelEditor.js +266 -0
- package/lib/types/components/shimmer.d.ts +26 -0
- package/lib/types/components/shimmer.d.ts.map +1 -1
- package/lib/types/components/shimmer.js +26 -0
- package/lib/types/components/sidePanel/InfoPanel.d.ts.map +1 -1
- package/lib/types/components/sidePanel/InfoPanel.js +13 -8
- package/lib/types/components/sidePanel/PanelBar.d.ts +0 -24
- package/lib/types/components/sidePanel/PanelBar.d.ts.map +1 -1
- package/lib/types/components/sidePanel/PanelBar.js +55 -77
- package/lib/types/components/sidePanel/PanelStore.d.ts +3 -1
- package/lib/types/components/sidePanel/PanelStore.d.ts.map +1 -1
- package/lib/types/components/sidePanel/PanelStore.js +8 -4
- package/lib/types/components/sidePanel/SidePanelColumn.d.ts +3 -10
- package/lib/types/components/sidePanel/SidePanelColumn.d.ts.map +1 -1
- package/lib/types/components/sidePanel/SidePanelColumn.js +9 -12
- package/lib/types/components/sidePanel/TrajectoryPanel.d.ts.map +1 -1
- package/lib/types/components/sidePanel/TrajectoryPanel.js +78 -14
- package/lib/types/components/sidePanel/agentViewStore.d.ts +20 -0
- package/lib/types/components/sidePanel/agentViewStore.d.ts.map +1 -0
- package/lib/types/components/sidePanel/agentViewStore.js +26 -0
- package/lib/types/components/sidePanel/btw/BtwComposer.d.ts +50 -0
- package/lib/types/components/sidePanel/btw/BtwComposer.d.ts.map +1 -0
- package/lib/types/components/sidePanel/btw/BtwComposer.js +45 -0
- package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts +13 -0
- package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts.map +1 -0
- package/lib/types/components/sidePanel/btw/BtwPanelAdapter.js +147 -0
- package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts +14 -0
- package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts.map +1 -0
- package/lib/types/components/sidePanel/btw/BtwThreadScene.js +131 -0
- package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts +30 -0
- package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts.map +1 -0
- package/lib/types/components/sidePanel/btw/BtwThreadView.js +87 -0
- package/lib/types/components/sidePanel/btw/threads.d.ts +111 -0
- package/lib/types/components/sidePanel/btw/threads.d.ts.map +1 -0
- package/lib/types/components/sidePanel/btw/threads.js +302 -0
- package/lib/types/components/sidePanel/builtinPanels.d.ts.map +1 -1
- package/lib/types/components/sidePanel/builtinPanels.js +70 -30
- package/lib/types/components/sidePanel/companion/CompanionPanel.d.ts +4 -46
- package/lib/types/components/sidePanel/companion/CompanionPanel.d.ts.map +1 -1
- package/lib/types/components/sidePanel/companion/CompanionPanel.js +19 -55
- package/lib/types/components/sidePanel/companion/mood.d.ts +32 -0
- package/lib/types/components/sidePanel/companion/mood.d.ts.map +1 -1
- package/lib/types/components/sidePanel/companion/mood.js +44 -0
- package/lib/types/components/sidePanel/companion/skins.d.ts +34 -0
- package/lib/types/components/sidePanel/companion/skins.d.ts.map +1 -1
- package/lib/types/components/sidePanel/companion/skins.js +203 -29
- package/lib/types/components/splashFonts.d.ts +17 -9
- package/lib/types/components/splashFonts.d.ts.map +1 -1
- package/lib/types/components/splashFonts.js +119 -15
- package/lib/types/components/splashLayout.d.ts.map +1 -1
- package/lib/types/components/splashLayout.js +3 -1
- package/lib/types/components/subagentDetailMemory.d.ts +17 -0
- package/lib/types/components/subagentDetailMemory.d.ts.map +1 -0
- package/lib/types/components/subagentDetailMemory.js +28 -0
- package/lib/types/components/trajectory/Inspector.d.ts.map +1 -1
- package/lib/types/components/trajectory/Inspector.js +9 -0
- package/lib/types/components/trajectory/Ledger.d.ts.map +1 -1
- package/lib/types/components/trajectory/Ledger.js +7 -1
- package/lib/types/components/trajectory/scope.d.ts +64 -0
- package/lib/types/components/trajectory/scope.d.ts.map +1 -0
- package/lib/types/components/trajectory/scope.js +88 -0
- package/lib/types/components/trajectory/useTrajectoryScope.d.ts +42 -0
- package/lib/types/components/trajectory/useTrajectoryScope.d.ts.map +1 -0
- package/lib/types/components/trajectory/useTrajectoryScope.js +86 -0
- package/lib/types/customTheme.d.ts +4 -6
- package/lib/types/customTheme.d.ts.map +1 -1
- package/lib/types/customTheme.js +6 -8
- package/lib/types/dsh-adapter/approvals.d.ts +18 -5
- package/lib/types/dsh-adapter/approvals.d.ts.map +1 -1
- package/lib/types/dsh-adapter/approvals.js +17 -4
- package/lib/types/dsh-adapter/backend/session.d.ts +64 -0
- package/lib/types/dsh-adapter/backend/session.d.ts.map +1 -0
- package/lib/types/dsh-adapter/backend/session.js +291 -0
- package/lib/types/dsh-adapter/backend/translate.d.ts +58 -0
- package/lib/types/dsh-adapter/backend/translate.d.ts.map +1 -0
- package/lib/types/dsh-adapter/backend/translate.js +467 -0
- package/lib/types/dsh-adapter/backends.d.ts +49 -0
- package/lib/types/dsh-adapter/backends.d.ts.map +1 -0
- package/lib/types/dsh-adapter/backends.js +124 -0
- package/lib/types/dsh-adapter/channel/action-readiness.d.ts +16 -0
- package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/action-readiness.js +109 -0
- package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts +2 -2
- package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/background-action.d.ts +2 -2
- package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/background-action.js +7 -5
- package/lib/types/dsh-adapter/channel/binding-events.d.ts +19 -9
- package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/binding-events.js +58 -135
- package/lib/types/dsh-adapter/channel/binding.d.ts +61 -14
- package/lib/types/dsh-adapter/channel/binding.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/binding.js +102 -35
- package/lib/types/dsh-adapter/channel/command-completions.d.ts +3 -0
- package/lib/types/dsh-adapter/channel/command-completions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/command-completions.js +33 -4
- package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/compaction.js +3 -2
- package/lib/types/dsh-adapter/channel/composer-images.d.ts +5 -0
- package/lib/types/dsh-adapter/channel/composer-images.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/composer-images.js +4 -3
- package/lib/types/dsh-adapter/channel/core/actions.d.ts +39 -0
- package/lib/types/dsh-adapter/channel/core/actions.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/actions.js +152 -0
- package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts +145 -0
- package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/binding-feed.js +289 -0
- package/lib/types/dsh-adapter/channel/core/compose.d.ts +217 -0
- package/lib/types/dsh-adapter/channel/core/compose.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/compose.js +938 -0
- package/lib/types/dsh-adapter/channel/core/files.d.ts +57 -0
- package/lib/types/dsh-adapter/channel/core/files.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/files.js +45 -0
- package/lib/types/dsh-adapter/channel/core/host.d.ts +55 -0
- package/lib/types/dsh-adapter/channel/core/host.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/host.js +116 -0
- package/lib/types/dsh-adapter/channel/core/local-actions.d.ts +46 -0
- package/lib/types/dsh-adapter/channel/core/local-actions.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/local-actions.js +117 -0
- package/lib/types/dsh-adapter/channel/core/local-images.d.ts +20 -0
- package/lib/types/dsh-adapter/channel/core/local-images.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/local-images.js +147 -0
- package/lib/types/dsh-adapter/channel/core/reports.d.ts +12 -0
- package/lib/types/dsh-adapter/channel/core/reports.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/reports.js +77 -0
- package/lib/types/dsh-adapter/channel/core/session-controls.d.ts +39 -0
- package/lib/types/dsh-adapter/channel/core/session-controls.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/session-controls.js +219 -0
- package/lib/types/dsh-adapter/channel/core/session-switch.d.ts +174 -0
- package/lib/types/dsh-adapter/channel/core/session-switch.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/session-switch.js +390 -0
- package/lib/types/dsh-adapter/channel/core/sessions.d.ts +40 -0
- package/lib/types/dsh-adapter/channel/core/sessions.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/sessions.js +268 -0
- package/lib/types/dsh-adapter/channel/decisions.d.ts +4 -3
- package/lib/types/dsh-adapter/channel/decisions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/decisions.js +4 -4
- package/lib/types/dsh-adapter/channel/emitter.d.ts +15 -2
- package/lib/types/dsh-adapter/channel/emitter.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/emitter.js +5 -3
- package/lib/types/dsh-adapter/channel/extensions.d.ts +36 -0
- package/lib/types/dsh-adapter/channel/extensions.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/extensions.js +714 -0
- package/lib/types/dsh-adapter/channel/ide-selection.d.ts +1 -10
- package/lib/types/dsh-adapter/channel/ide-selection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/ide-selection.js +4 -46
- package/lib/types/dsh-adapter/channel/input-actions.d.ts +27 -4
- package/lib/types/dsh-adapter/channel/input-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/input-actions.js +240 -21
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts +21 -5
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/input-delivery.js +65 -27
- package/lib/types/dsh-adapter/channel/local-actions.d.ts +10 -32
- package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/local-actions.js +10 -78
- package/lib/types/dsh-adapter/channel/local-fs.d.ts +3 -0
- package/lib/types/dsh-adapter/channel/local-fs.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/local-fs.js +46 -0
- package/lib/types/dsh-adapter/channel/mode-actions.d.ts +3 -3
- package/lib/types/dsh-adapter/channel/mode-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts +2 -2
- package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-actions.d.ts +3 -3
- package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-actions.js +38 -5
- package/lib/types/dsh-adapter/channel/model-switch.d.ts +2 -2
- package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-switch.js +9 -6
- package/lib/types/dsh-adapter/channel/preferences.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/preferences.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/preferences.js +16 -0
- package/lib/types/dsh-adapter/channel/projection.d.ts +16 -13
- package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/projection.js +38 -1143
- package/lib/types/dsh-adapter/channel/question-record.d.ts +3 -75
- package/lib/types/dsh-adapter/channel/question-record.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/question-record.js +3 -107
- package/lib/types/dsh-adapter/channel/session-activity.d.ts +9 -0
- package/lib/types/dsh-adapter/channel/session-activity.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/session-activity.js +42 -0
- package/lib/types/dsh-adapter/channel/session-adoption.d.ts +4 -4
- package/lib/types/dsh-adapter/channel/session-adoption.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-adoption.js +3 -1
- package/lib/types/dsh-adapter/channel/session-fork.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-fork.js +2 -1
- package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts +7 -3
- package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-live-adoption.js +1 -1
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts +2 -9
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-reset.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/session-reset.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-reset.js +4 -0
- package/lib/types/dsh-adapter/channel/session-resume.d.ts +5 -10
- package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-resume.js +74 -113
- package/lib/types/dsh-adapter/channel/session-rewind.d.ts +4 -4
- package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-rewind.js +7 -6
- package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts +4 -4
- package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-tree-actions.js +8 -7
- package/lib/types/dsh-adapter/channel/settings-host.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/settings-host.js +8 -0
- package/lib/types/dsh-adapter/channel/skill-catalog.d.ts +5 -1
- package/lib/types/dsh-adapter/channel/skill-catalog.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/skill-catalog.js +2 -2
- package/lib/types/dsh-adapter/channel/state.d.ts +72 -1
- package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/state.js +7 -3
- package/lib/types/dsh-adapter/channel/subagent-projection.d.ts +58 -3
- package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.js +153 -9
- package/lib/types/dsh-adapter/channel/subagent-transcript.d.ts +114 -0
- package/lib/types/dsh-adapter/channel/subagent-transcript.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/subagent-transcript.js +279 -0
- package/lib/types/dsh-adapter/channel/transcript.d.ts +7 -15
- package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/transcript.js +17 -21
- package/lib/types/dsh-adapter/channel/types.d.ts +16 -7
- package/lib/types/dsh-adapter/channel/types.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/usage.d.ts +3 -23
- package/lib/types/dsh-adapter/channel/usage.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/usage.js +5 -111
- package/lib/types/dsh-adapter/channel/workspace-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/workspace-actions.js +2 -1
- package/lib/types/dsh-adapter/channel.d.ts +17 -8
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +24 -1059
- package/lib/types/dsh-adapter/context-occupancy.d.ts +6 -1
- package/lib/types/dsh-adapter/context-occupancy.d.ts.map +1 -1
- package/lib/types/dsh-adapter/context-occupancy.js +6 -1
- package/lib/types/dsh-adapter/decision-guard.d.ts +24 -0
- package/lib/types/dsh-adapter/decision-guard.d.ts.map +1 -1
- package/lib/types/dsh-adapter/decision-guard.js +44 -0
- package/lib/types/dsh-adapter/extension-events.d.ts +4 -1
- package/lib/types/dsh-adapter/extension-events.d.ts.map +1 -1
- package/lib/types/dsh-adapter/extension-events.js +22 -10
- package/lib/types/dsh-adapter/index.d.ts +41 -3
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +28 -1
- package/lib/types/dsh-adapter/jobs.d.ts +5 -3
- package/lib/types/dsh-adapter/jobs.d.ts.map +1 -1
- package/lib/types/dsh-adapter/jobs.js +53 -14
- package/lib/types/dsh-adapter/migrate/parse/jsonl.d.ts +1 -16
- package/lib/types/dsh-adapter/migrate/parse/jsonl.d.ts.map +1 -1
- package/lib/types/dsh-adapter/migrate/parse/jsonl.js +3 -29
- package/lib/types/dsh-adapter/oauth-credential-source.d.ts +34 -0
- package/lib/types/dsh-adapter/oauth-credential-source.d.ts.map +1 -0
- package/lib/types/dsh-adapter/oauth-credential-source.js +66 -0
- package/lib/types/dsh-adapter/plugin.d.ts +38 -2
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +546 -110
- package/lib/types/dsh-adapter/provider-model-capabilities.d.ts +10 -0
- package/lib/types/dsh-adapter/provider-model-capabilities.d.ts.map +1 -0
- package/lib/types/dsh-adapter/provider-model-capabilities.js +80 -0
- package/lib/types/dsh-adapter/providerWizard.d.ts +8 -2
- package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
- package/lib/types/dsh-adapter/providerWizard.js +118 -52
- package/lib/types/dsh-adapter/questions.d.ts +29 -124
- package/lib/types/dsh-adapter/questions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/questions.js +33 -267
- package/lib/types/dsh-adapter/recap.d.ts +3 -15
- package/lib/types/dsh-adapter/recap.d.ts.map +1 -1
- package/lib/types/dsh-adapter/recap.js +3 -46
- package/lib/types/dsh-adapter/sanitize.d.ts +4 -44
- package/lib/types/dsh-adapter/sanitize.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sanitize.js +4 -84
- package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts +3 -1
- package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts.map +1 -1
- package/lib/types/dsh-adapter/session-mount-heartbeat.js +4 -2
- package/lib/types/dsh-adapter/sessions/digest.d.ts +18 -3
- package/lib/types/dsh-adapter/sessions/digest.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/digest.js +60 -27
- package/lib/types/dsh-adapter/sessions/list.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/list.js +6 -4
- package/lib/types/dsh-adapter/sessions/recovery.d.ts +2 -2
- package/lib/types/dsh-adapter/sessions/recovery.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/recovery.js +23 -14
- package/lib/types/dsh-adapter/sessions/store.d.ts +2 -0
- package/lib/types/dsh-adapter/sessions/store.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/store.js +1 -0
- package/lib/types/dsh-adapter/sessions/types.d.ts +2 -0
- package/lib/types/dsh-adapter/sessions/types.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sideQuestion.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sideQuestion.js +3 -13
- package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
- package/lib/types/dsh-adapter/subagents.js +7 -0
- package/lib/types/dsh-adapter/themes.d.ts +1 -1
- package/lib/types/dsh-adapter/themes.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/agent-source.d.ts +84 -0
- package/lib/types/dsh-adapter/trajectory/agent-source.d.ts.map +1 -0
- package/lib/types/dsh-adapter/trajectory/agent-source.js +601 -0
- package/lib/types/dsh-adapter/trajectory/guards.d.ts +31 -1
- package/lib/types/dsh-adapter/trajectory/guards.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/guards.js +28 -0
- package/lib/types/dsh-adapter/trajectory/index.d.ts +3 -1
- package/lib/types/dsh-adapter/trajectory/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/index.js +1 -0
- package/lib/types/dsh-adapter/trajectory/inspect.d.ts +7 -0
- package/lib/types/dsh-adapter/trajectory/inspect.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/inspect.js +70 -2
- package/lib/types/dsh-adapter/trajectory/projection.d.ts +4 -0
- package/lib/types/dsh-adapter/trajectory/projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/projection.js +36 -0
- package/lib/types/dsh-adapter/trajectory/types.d.ts +13 -0
- package/lib/types/dsh-adapter/trajectory/types.d.ts.map +1 -1
- package/lib/types/effortPrefs.d.ts +7 -0
- package/lib/types/effortPrefs.d.ts.map +1 -1
- package/lib/types/effortPrefs.js +11 -2
- package/lib/types/handoffAck.d.ts +57 -0
- package/lib/types/handoffAck.d.ts.map +1 -0
- package/lib/types/handoffAck.js +154 -0
- package/lib/types/handoffEvents.d.ts +52 -0
- package/lib/types/handoffEvents.d.ts.map +1 -0
- package/lib/types/handoffEvents.js +128 -0
- package/lib/types/i18n.d.ts +3189 -68
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +855 -9
- package/lib/types/ink/colorize.d.ts.map +1 -1
- package/lib/types/ink/colorize.js +8 -2
- package/lib/types/ink/components/AlternateScreen.d.ts +12 -1
- package/lib/types/ink/components/AlternateScreen.d.ts.map +1 -1
- package/lib/types/ink/components/AlternateScreen.js +25 -4
- package/lib/types/ink/components/App.d.ts +5 -1
- package/lib/types/ink/components/App.d.ts.map +1 -1
- package/lib/types/ink/components/App.js +52 -5
- package/lib/types/ink/components/Image.d.ts +8 -1
- package/lib/types/ink/components/Image.d.ts.map +1 -1
- package/lib/types/ink/components/Image.js +2 -2
- package/lib/types/ink/components/Text.d.ts +8 -1
- package/lib/types/ink/components/Text.d.ts.map +1 -1
- package/lib/types/ink/components/Text.js +11 -1
- package/lib/types/ink/dom.d.ts.map +1 -1
- package/lib/types/ink/dom.js +75 -3
- package/lib/types/ink/hooks/use-input.d.ts.map +1 -1
- package/lib/types/ink/hooks/use-input.js +9 -4
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +8 -2
- package/lib/types/ink/kitty-graphics.d.ts +7 -2
- package/lib/types/ink/kitty-graphics.d.ts.map +1 -1
- package/lib/types/ink/kitty-graphics.js +15 -7
- package/lib/types/ink/node-cache.d.ts +15 -1
- package/lib/types/ink/node-cache.d.ts.map +1 -1
- package/lib/types/ink/node-cache.js +4 -1
- package/lib/types/ink/output.d.ts.map +1 -1
- package/lib/types/ink/output.js +2 -0
- package/lib/types/ink/parse-keypress.d.ts +13 -0
- package/lib/types/ink/parse-keypress.d.ts.map +1 -1
- package/lib/types/ink/parse-keypress.js +438 -19
- package/lib/types/ink/reconciler.d.ts.map +1 -1
- package/lib/types/ink/reconciler.js +9 -0
- package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
- package/lib/types/ink/render-node-to-output.js +200 -4
- package/lib/types/ink/render-stats.d.ts +35 -0
- package/lib/types/ink/render-stats.d.ts.map +1 -0
- package/lib/types/ink/render-stats.js +53 -0
- package/lib/types/ink/sixel-codec.d.ts +11 -1
- package/lib/types/ink/sixel-codec.d.ts.map +1 -1
- package/lib/types/ink/sixel-codec.js +10 -3
- package/lib/types/ink/sixel-graphics.js +2 -2
- package/lib/types/ink/styles.d.ts +46 -0
- package/lib/types/ink/styles.d.ts.map +1 -1
- package/lib/types/ink/terminal-image.d.ts +7 -0
- package/lib/types/ink/terminal-image.d.ts.map +1 -1
- package/lib/types/ink/terminal-querier.d.ts +1 -1
- package/lib/types/ink/terminal-querier.js +4 -4
- package/lib/types/ink/text-decoration.d.ts +49 -0
- package/lib/types/ink/text-decoration.d.ts.map +1 -0
- package/lib/types/ink/text-decoration.js +235 -0
- package/lib/types/ink/update-overflow-guard.d.ts +9 -0
- package/lib/types/ink/update-overflow-guard.d.ts.map +1 -1
- package/lib/types/ink/update-overflow-guard.js +41 -0
- package/lib/types/ink/wrap-text.d.ts.map +1 -1
- package/lib/types/ink/wrap-text.js +5 -1
- package/lib/types/kernelPrefs.d.ts +51 -0
- package/lib/types/kernelPrefs.d.ts.map +1 -0
- package/lib/types/kernelPrefs.js +126 -0
- package/lib/types/modelRecents.d.ts +10 -2
- package/lib/types/modelRecents.d.ts.map +1 -1
- package/lib/types/modelRecents.js +20 -7
- package/lib/types/screens/AgentTranscriptScene.d.ts +42 -0
- package/lib/types/screens/AgentTranscriptScene.d.ts.map +1 -0
- package/lib/types/screens/AgentTranscriptScene.js +269 -0
- package/lib/types/screens/Chat.d.ts +45 -7
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +625 -113
- package/lib/types/screens/Launchpad.d.ts +24 -7
- package/lib/types/screens/Launchpad.d.ts.map +1 -1
- package/lib/types/screens/Launchpad.js +147 -28
- package/lib/types/screens/SessionSupervisor.d.ts +3 -3
- package/lib/types/screens/SessionSupervisor.d.ts.map +1 -1
- package/lib/types/screens/SessionSupervisor.js +69 -5
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +211 -7
- package/lib/types/screens/StatusLine.d.ts +40 -1
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +131 -19
- package/lib/types/screens/StatusMetrics.d.ts +53 -17
- package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
- package/lib/types/screens/StatusMetrics.js +141 -30
- package/lib/types/screens/TrajectoryScene.d.ts.map +1 -1
- package/lib/types/screens/TrajectoryScene.js +74 -12
- package/lib/types/screens/chat/backendCommands.d.ts +37 -0
- package/lib/types/screens/chat/backendCommands.d.ts.map +1 -0
- package/lib/types/screens/chat/backendCommands.js +51 -0
- package/lib/types/screens/chat/useBackendChannels.d.ts +20 -0
- package/lib/types/screens/chat/useBackendChannels.d.ts.map +1 -0
- package/lib/types/screens/chat/useBackendChannels.js +117 -0
- package/lib/types/screens/chat/useKernelPicker.d.ts +23 -0
- package/lib/types/screens/chat/useKernelPicker.d.ts.map +1 -0
- package/lib/types/screens/chat/useKernelPicker.js +72 -0
- package/lib/types/screens/chatOverlay.d.ts +32 -2
- package/lib/types/screens/chatOverlay.d.ts.map +1 -1
- package/lib/types/screens/chatOverlay.js +9 -0
- package/lib/types/screens/sessionSupervisor/useForeignSessions.d.ts.map +1 -1
- package/lib/types/screens/sessionSupervisor/useForeignSessions.js +5 -1
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +14 -0
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -1
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +97 -22
- package/lib/types/sessionHistory.d.ts +18 -1
- package/lib/types/sessionHistory.d.ts.map +1 -1
- package/lib/types/sessionHistory.js +46 -4
- package/lib/types/sessionPins.d.ts +7 -0
- package/lib/types/sessionPins.d.ts.map +1 -1
- package/lib/types/sessionPins.js +9 -0
- package/lib/types/sessions/resumeFailure.d.ts.map +1 -1
- package/lib/types/sessions/resumeFailure.js +2 -1
- package/lib/types/settings/definitions.d.ts +74 -0
- package/lib/types/settings/definitions.d.ts.map +1 -1
- package/lib/types/settings/definitions.js +50 -4
- package/lib/types/terminal-utils/hyperlink.d.ts +2 -2
- package/lib/types/terminal-utils/hyperlink.d.ts.map +1 -1
- package/lib/types/terminal-utils/hyperlink.js +21 -4
- package/lib/types/terminal-utils/markdown.d.ts +34 -6
- package/lib/types/terminal-utils/markdown.d.ts.map +1 -1
- package/lib/types/terminal-utils/markdown.js +257 -66
- package/lib/types/theme.d.ts +49 -8
- package/lib/types/theme.d.ts.map +1 -1
- package/lib/types/theme.js +514 -18
- package/lib/types/tips.js +2 -2
- package/lib/types/trajectory/effortIgnition.d.ts +25 -7
- package/lib/types/trajectory/effortIgnition.d.ts.map +1 -1
- package/lib/types/trajectory/effortIgnition.js +106 -34
- package/lib/types/trajectory/window.d.ts +26 -0
- package/lib/types/trajectory/window.d.ts.map +1 -0
- package/lib/types/trajectory/window.js +27 -0
- package/lib/types/tuiDisplayPrefs.d.ts +38 -1
- package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
- package/lib/types/tuiDisplayPrefs.js +45 -1
- package/lib/types/update.d.ts +88 -3
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +285 -18
- package/lib/types/utils/crashDetail.d.ts +56 -0
- package/lib/types/utils/crashDetail.d.ts.map +1 -0
- package/lib/types/utils/crashDetail.js +175 -0
- package/lib/types/utils/imageResize.d.ts +9 -23
- package/lib/types/utils/imageResize.d.ts.map +1 -1
- package/lib/types/utils/imageResize.js +24 -20
- package/lib/types/utils/inputPaste.d.ts +9 -8
- package/lib/types/utils/inputPaste.d.ts.map +1 -1
- package/lib/types/utils/inputPaste.js +53 -16
- package/lib/types/utils/jsonl.d.ts +24 -0
- package/lib/types/utils/jsonl.d.ts.map +1 -0
- package/lib/types/utils/jsonl.js +36 -0
- package/package.json +18 -2
|
@@ -0,0 +1,1521 @@
|
|
|
1
|
+
import { markChannelReadDirty } from '../adapter/channel/read-view.js';
|
|
2
|
+
import { t } from '../i18n.js';
|
|
3
|
+
import { logForDebugging } from '../utils/debug.js';
|
|
4
|
+
import { laneOf } from './activity.js';
|
|
5
|
+
import { buildQuestionRecord, parseQuestionRecordAnswers, parseQuestionRecordQuestions } from './question-record.js';
|
|
6
|
+
import { cleanRenderText, NOTICE_CELLS } from './sanitize.js';
|
|
7
|
+
import { appendLiveOutput } from './live-output.js';
|
|
8
|
+
import { replaySelectionAttachment } from './selection-record.js';
|
|
9
|
+
import { ARGS_PREVIEW_LIMIT, LOCAL_OUTPUT_LIMIT, preview, RESULT_PREVIEW_LIMIT } from './transcript.js';
|
|
10
|
+
import { addUsageToBucket, emptyCostBuckets, estimateTokens, estimateTokensFraction, usageOutputTokens } from './usage.js';
|
|
11
|
+
/** Notice keys whose live toast is tracked (a repeat replaces it). */
|
|
12
|
+
const MAX_KEYED_TOASTS = 32;
|
|
13
|
+
const NO_IMAGES = [];
|
|
14
|
+
/** Joined, trimmed text of every `text` block (what a bubble or card body shows). */
|
|
15
|
+
export function textOfBlocks(blocks) {
|
|
16
|
+
// Unknown block kinds are skipped, never fatal (v1 renders text blocks only).
|
|
17
|
+
return (blocks ?? []).map(block => (block.type === 'text' ? block.text : '')).join('').trim();
|
|
18
|
+
}
|
|
19
|
+
/** Create the shared projector over one channel state. */
|
|
20
|
+
export function createChannelProjection(state, deps) {
|
|
21
|
+
/** The in-progress assistant text row; `undefined` when no step is streaming. */
|
|
22
|
+
let streaming;
|
|
23
|
+
/** The in-progress reasoning row; `undefined` when no reasoning is streaming. */
|
|
24
|
+
let reasoning;
|
|
25
|
+
/** Reasoning rows sealed this turn. Full mode keeps them expanded until
|
|
26
|
+
* turn end without leaving their streaming spinner active. */
|
|
27
|
+
const sealedReasoning = [];
|
|
28
|
+
/** Wall-clock start of the current reasoning row (durationMs on settle). */
|
|
29
|
+
let reasoningStart = 0;
|
|
30
|
+
/** Decode-throughput fold for the current turn. One step is one model call
|
|
31
|
+
* plus its tools; summing only first-token → message spans excludes tool
|
|
32
|
+
* execution and per-request TTFT from generation speed. */
|
|
33
|
+
let tpsTurn;
|
|
34
|
+
let tpsBeforeTurn;
|
|
35
|
+
let tpsTurnDecodeMs = 0;
|
|
36
|
+
let tpsTurnDecodeTokens = 0;
|
|
37
|
+
let tpsTurnSampled = false;
|
|
38
|
+
let tpsStep;
|
|
39
|
+
/** The open turn's per-step token contributions (real or estimated): a
|
|
40
|
+
* late real usage report naming the same (turn, step) swaps the estimate
|
|
41
|
+
* in place (Codex meters after the reply settles). */
|
|
42
|
+
let tpsTurnSteps;
|
|
43
|
+
/** The LAST ended turn's fold, kept so a straggler usage arriving after
|
|
44
|
+
* turn.end still corrects the tps readout and the pushed sample. */
|
|
45
|
+
let tpsClosedTurn;
|
|
46
|
+
/** Per-turn usage ledger: reset at turn.start, summed from each assistant
|
|
47
|
+
* message's own request usage (messages report per-request increments, so
|
|
48
|
+
* a turn-level backend report must never be added on top), rendered as
|
|
49
|
+
* the turn-summary row at turn.end and kept on `state.turnUsage` for the
|
|
50
|
+
* footer readouts. */
|
|
51
|
+
const turnLedger = {
|
|
52
|
+
input: 0,
|
|
53
|
+
output: 0,
|
|
54
|
+
cacheRead: 0,
|
|
55
|
+
cacheWrite: 0,
|
|
56
|
+
cacheKnown: false,
|
|
57
|
+
usageSeen: false,
|
|
58
|
+
startedAt: 0,
|
|
59
|
+
model: undefined,
|
|
60
|
+
};
|
|
61
|
+
/** Attempt ids that failed and were superseded within the current turn
|
|
62
|
+
* (API retries): a set, because the same failure can be observed from
|
|
63
|
+
* both the superseding attempt.start and the positioned attempt.end. */
|
|
64
|
+
const turnFailedAttempts = new Set();
|
|
65
|
+
/** Model of the last emitted turn ledger: the row names the model only
|
|
66
|
+
* when it changed (or on the first turn that has one), since repeating an
|
|
67
|
+
* unchanged id every turn is noise. Commands read `model` regardless. */
|
|
68
|
+
let lastNotedTurnModel;
|
|
69
|
+
/** Tool cards by callId, so the result can settle the running card. */
|
|
70
|
+
const toolCards = new Map();
|
|
71
|
+
/** The live-output tail of each running card that printed (`tool.output`),
|
|
72
|
+
* by callId: at most one per running card, dropped with its result. */
|
|
73
|
+
const liveTails = new Map();
|
|
74
|
+
/**
|
|
75
|
+
* Question-presented calls by callId, holding their raw arguments. The ask
|
|
76
|
+
* renders as the interactive panel rather than a tool card, so its result
|
|
77
|
+
* has no card to settle, but the answered record still belongs in the
|
|
78
|
+
* transcript and must come from the durable log (issue #1009), never from
|
|
79
|
+
* the view. Remembering the call lets the result derive that record on the
|
|
80
|
+
* live stream and on every replay (`/resume`, rewind, model switch).
|
|
81
|
+
*/
|
|
82
|
+
const askCalls = new Map();
|
|
83
|
+
/** Todo-panel calls by callId (cards suppressed: the panel shows the
|
|
84
|
+
* list). Their arguments are remembered so a failed result can still
|
|
85
|
+
* render its error card. Otherwise a rejected TaskUpdate would vanish
|
|
86
|
+
* silently: the panel rolls back its optimistic change, and the user
|
|
87
|
+
* needs to see that the task change never happened. */
|
|
88
|
+
const todoCalls = new Map();
|
|
89
|
+
/** callId of the result that just settled an ok card: task feeds a
|
|
90
|
+
* translator derives from a result only reach the job registry when that
|
|
91
|
+
* result actually settled a card here. */
|
|
92
|
+
let settledCardCallId;
|
|
93
|
+
/**
|
|
94
|
+
* Session events are delivered live and can also be replayed around a
|
|
95
|
+
* reconnect. A repeated sealed message must not create a second assistant
|
|
96
|
+
* row for the same durable sequence number.
|
|
97
|
+
*/
|
|
98
|
+
const handledAssistantMessages = new Set();
|
|
99
|
+
const handledUsage = new Set();
|
|
100
|
+
const handledAssistantChunks = new Set();
|
|
101
|
+
/** One agent runs one request at a time. Durable step boundaries also let
|
|
102
|
+
* a freshly attached projector accept deltas whose attempt start it missed. */
|
|
103
|
+
let openStep;
|
|
104
|
+
let activeAttempt;
|
|
105
|
+
/** 最近一次 request.header 的模型,durable usage 按它归属模型。replay
|
|
106
|
+
* 会按历史请求逐个还原,因此 /model 切换(reset + replay 整个 seed)
|
|
107
|
+
* 不会把换模型前的用量重估到新模型;旧日志没有 header 时回退
|
|
108
|
+
* 事件发生时的 state.model。 */
|
|
109
|
+
let eventModel;
|
|
110
|
+
/** Backend occupancy is independent of the last request's billed usage. */
|
|
111
|
+
let contextUsage;
|
|
112
|
+
const assistantRowsByStep = new Map();
|
|
113
|
+
/**
|
|
114
|
+
* Assistant rows by the seq they carry: a reconnect can replay a delta or
|
|
115
|
+
* settlement of a row already on screen, which must reuse that row. Live
|
|
116
|
+
* events only see rows this projector opened or settled since the last
|
|
117
|
+
* replay; rows prepended by "load earlier" come from a separate projection
|
|
118
|
+
* whose seqs may overlap live ones and are never matched.
|
|
119
|
+
*/
|
|
120
|
+
const assistantRowsBySeq = new Map();
|
|
121
|
+
const lastTextDelta = new Map();
|
|
122
|
+
const stepKey = (turn, step) => `${turn}:${step}`;
|
|
123
|
+
const touchRow = (row) => { markChannelReadDirty(row); markChannelReadDirty(state.rows); };
|
|
124
|
+
/** The last keyed notice row (updated in place while it stays last). */
|
|
125
|
+
let keyedNoticeRow;
|
|
126
|
+
/** The live toast of each notice key (a repeat replaces it). */
|
|
127
|
+
const keyedToasts = new Map();
|
|
128
|
+
const appendRow = (row) => { state.rows.push(row); markChannelReadDirty(state.rows); };
|
|
129
|
+
const removeRow = (row) => {
|
|
130
|
+
const index = state.rows.indexOf(row);
|
|
131
|
+
if (index !== -1) {
|
|
132
|
+
state.rows.splice(index, 1);
|
|
133
|
+
markChannelReadDirty(state.rows);
|
|
134
|
+
}
|
|
135
|
+
if (streaming === row)
|
|
136
|
+
streaming = undefined;
|
|
137
|
+
if (reasoning === row)
|
|
138
|
+
reasoning = undefined;
|
|
139
|
+
if (lastReasoningRow?.row === row)
|
|
140
|
+
lastReasoningRow = undefined;
|
|
141
|
+
const sealedIndex = sealedReasoning.indexOf(row);
|
|
142
|
+
if (sealedIndex !== -1)
|
|
143
|
+
sealedReasoning.splice(sealedIndex, 1);
|
|
144
|
+
lastTextDelta.delete(row);
|
|
145
|
+
if (row.seq !== undefined && assistantRowsBySeq.get(row.seq) === row)
|
|
146
|
+
assistantRowsBySeq.delete(row.seq);
|
|
147
|
+
};
|
|
148
|
+
const discardAttempt = (turn, step) => {
|
|
149
|
+
const key = stepKey(turn, step);
|
|
150
|
+
const row = assistantRowsByStep.get(key);
|
|
151
|
+
if (row !== undefined && row.seq === undefined) {
|
|
152
|
+
state.responseChars = Math.max(0, state.responseChars - row.text.length);
|
|
153
|
+
removeRow(row);
|
|
154
|
+
assistantRowsByStep.delete(key);
|
|
155
|
+
}
|
|
156
|
+
if (lastReasoningRow !== undefined && lastReasoningRow.turn === turn && lastReasoningRow.step === step && lastReasoningRow.row.seq === undefined) {
|
|
157
|
+
removeRow(lastReasoningRow.row);
|
|
158
|
+
}
|
|
159
|
+
if (activeAttempt !== undefined && activeAttempt.turn === turn && activeAttempt.step === step)
|
|
160
|
+
activeAttempt = undefined;
|
|
161
|
+
if (tpsStep !== undefined && tpsStep.turn === turn && tpsStep.step === step) {
|
|
162
|
+
tpsStep.firstTokenTime = undefined;
|
|
163
|
+
tpsStep.outputEstimate = 0;
|
|
164
|
+
}
|
|
165
|
+
updateSpinnerMode();
|
|
166
|
+
};
|
|
167
|
+
/** Live deltas are ordered by the backend's stream fence and must stay
|
|
168
|
+
* byte-exact. Positioned (legacy durable) deltas may instead repeat a
|
|
169
|
+
* cumulative prefix after a reconnect/proxy replay. */
|
|
170
|
+
const appendTextDelta = (row, delta, legacy) => {
|
|
171
|
+
if (delta === '')
|
|
172
|
+
return;
|
|
173
|
+
if (!legacy) {
|
|
174
|
+
row.text += delta;
|
|
175
|
+
touchRow(row);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (lastTextDelta.get(row) === delta)
|
|
179
|
+
return;
|
|
180
|
+
lastTextDelta.set(row, delta);
|
|
181
|
+
if (delta.startsWith(row.text)) {
|
|
182
|
+
row.text = delta;
|
|
183
|
+
touchRow(row);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const maxOverlap = Math.min(row.text.length, delta.length, 4096);
|
|
187
|
+
for (let size = maxOverlap; size > 0; size--) {
|
|
188
|
+
if (row.text.endsWith(delta.slice(0, size))) {
|
|
189
|
+
row.text += delta.slice(size);
|
|
190
|
+
touchRow(row);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
row.text += delta;
|
|
195
|
+
touchRow(row);
|
|
196
|
+
};
|
|
197
|
+
const indexAssistantRow = (row) => {
|
|
198
|
+
if (row.seq !== undefined)
|
|
199
|
+
assistantRowsBySeq.set(row.seq, row);
|
|
200
|
+
};
|
|
201
|
+
const openStreaming = (seq) => {
|
|
202
|
+
streaming = { id: deps.rowIds.value, kind: 'assistant', text: '', streaming: true, fresh: true, ...seq !== undefined ? { seq } : {} };
|
|
203
|
+
deps.rowIds.value += 1;
|
|
204
|
+
appendRow(streaming);
|
|
205
|
+
indexAssistantRow(streaming);
|
|
206
|
+
return streaming;
|
|
207
|
+
};
|
|
208
|
+
const ensureStreaming = (seq) => {
|
|
209
|
+
if (streaming !== undefined)
|
|
210
|
+
return streaming;
|
|
211
|
+
// A reconnect can replay the first delta after the sealed message was
|
|
212
|
+
// already observed. Reuse that durable row instead of opening a second
|
|
213
|
+
// assistant bubble for the same event sequence.
|
|
214
|
+
const existing = seq === undefined ? undefined : assistantRowsBySeq.get(seq);
|
|
215
|
+
if (existing !== undefined) {
|
|
216
|
+
existing.streaming = true;
|
|
217
|
+
touchRow(existing);
|
|
218
|
+
streaming = existing;
|
|
219
|
+
return existing;
|
|
220
|
+
}
|
|
221
|
+
return openStreaming(seq);
|
|
222
|
+
};
|
|
223
|
+
/** Latest reasoning row keyed by its (turn, step), so a resumed mid-step
|
|
224
|
+
* stream revives the row the replay sealed (crash-orphan tail: replay
|
|
225
|
+
* folds the partial row, and live continuation deltas would otherwise
|
|
226
|
+
* open a second row for the same step, splitting one thinking block in
|
|
227
|
+
* two). */
|
|
228
|
+
let lastReasoningRow;
|
|
229
|
+
const ensureReasoning = (seq, turn, step) => {
|
|
230
|
+
if (reasoning === undefined) {
|
|
231
|
+
// Same-step revive: the sealed row is this step's thinking — continue
|
|
232
|
+
// it (durationMs carried over via reasoningStart back-dating).
|
|
233
|
+
if (lastReasoningRow !== undefined &&
|
|
234
|
+
turn !== undefined &&
|
|
235
|
+
lastReasoningRow.turn === turn &&
|
|
236
|
+
lastReasoningRow.step === step) {
|
|
237
|
+
reasoning = lastReasoningRow.row;
|
|
238
|
+
reasoning.streaming = true;
|
|
239
|
+
reasoning.thinkingOpen = false;
|
|
240
|
+
touchRow(reasoning);
|
|
241
|
+
const sealedIdx = sealedReasoning.indexOf(reasoning);
|
|
242
|
+
if (sealedIdx !== -1)
|
|
243
|
+
sealedReasoning.splice(sealedIdx, 1);
|
|
244
|
+
reasoningStart = Date.now() - (reasoning.durationMs ?? 0);
|
|
245
|
+
logForDebugging('thinking: revived sealed reasoning row for same step');
|
|
246
|
+
return reasoning;
|
|
247
|
+
}
|
|
248
|
+
reasoningStart = Date.now();
|
|
249
|
+
reasoning = { id: deps.rowIds.value, kind: 'reasoning', text: '', streaming: true, ...seq !== undefined ? { seq } : {} };
|
|
250
|
+
deps.rowIds.value += 1;
|
|
251
|
+
appendRow(reasoning);
|
|
252
|
+
logForDebugging('thinking: reasoning row open (expanded)');
|
|
253
|
+
}
|
|
254
|
+
if (turn !== undefined && step !== undefined) {
|
|
255
|
+
lastReasoningRow = { row: reasoning, turn, step };
|
|
256
|
+
}
|
|
257
|
+
return reasoning;
|
|
258
|
+
};
|
|
259
|
+
/** Settle live reasoning the moment the model moves past thinking (the
|
|
260
|
+
* answer's first text token or a tool call), not at the settled message
|
|
261
|
+
* (end of step). A long reply pushes the thinking block into terminal
|
|
262
|
+
* scrollback long before the message seals, and scrollback rows cannot be
|
|
263
|
+
* repainted (the cursor cannot reach them), so a late fold leaves a stale
|
|
264
|
+
* unfolded preview above the window. Folding while the block still sits
|
|
265
|
+
* in the live window keeps the shrink inside the diff engine's reachable
|
|
266
|
+
* region. Full mode keeps the settled block open separately, so its
|
|
267
|
+
* spinner can stop immediately. */
|
|
268
|
+
const settleLiveReasoning = (where) => {
|
|
269
|
+
if (reasoning === undefined)
|
|
270
|
+
return;
|
|
271
|
+
const duration = Math.max(0, Date.now() - reasoningStart);
|
|
272
|
+
reasoning.durationMs = duration;
|
|
273
|
+
reasoning.streaming = false;
|
|
274
|
+
reasoning.thinkingOpen = state.thinkingFold === 'full';
|
|
275
|
+
touchRow(reasoning);
|
|
276
|
+
sealedReasoning.push(reasoning);
|
|
277
|
+
reasoning = undefined;
|
|
278
|
+
logForDebugging(`thinking: folded at ${where} (${duration}ms)`);
|
|
279
|
+
};
|
|
280
|
+
const settleStreaming = () => {
|
|
281
|
+
if (streaming !== undefined) {
|
|
282
|
+
streaming.streaming = false;
|
|
283
|
+
touchRow(streaming);
|
|
284
|
+
}
|
|
285
|
+
streaming = undefined;
|
|
286
|
+
const folded = sealedReasoning.length + (reasoning !== undefined ? 1 : 0);
|
|
287
|
+
for (const row of sealedReasoning) {
|
|
288
|
+
row.streaming = false;
|
|
289
|
+
row.thinkingOpen = false;
|
|
290
|
+
touchRow(row);
|
|
291
|
+
}
|
|
292
|
+
sealedReasoning.length = 0;
|
|
293
|
+
if (reasoning !== undefined) {
|
|
294
|
+
reasoning.streaming = false;
|
|
295
|
+
reasoning.thinkingOpen = false;
|
|
296
|
+
reasoning.durationMs = Math.max(0, Date.now() - reasoningStart);
|
|
297
|
+
touchRow(reasoning);
|
|
298
|
+
}
|
|
299
|
+
reasoning = undefined;
|
|
300
|
+
if (folded > 0)
|
|
301
|
+
logForDebugging(`thinking: folded ${folded} reasoning row(s) at turn settle`);
|
|
302
|
+
};
|
|
303
|
+
/**
|
|
304
|
+
* Project one answered question-presented result into the transcript.
|
|
305
|
+
*
|
|
306
|
+
* The row shape reuses what `pushLocal` emits (`local` title + one
|
|
307
|
+
* `local-output` per line), so rendering, preview clipping and the local
|
|
308
|
+
* rows' fold exemption all keep their existing behavior. A failed ask
|
|
309
|
+
* renders the log's own error text — never a fabricated answer (the ask
|
|
310
|
+
* was cancelled/aborted, so no human ever chose anything).
|
|
311
|
+
*/
|
|
312
|
+
const projectAskResult = (event, rawArguments) => {
|
|
313
|
+
const append = (record) => {
|
|
314
|
+
appendRow({ id: deps.rowIds.value, kind: 'local', text: record.title, seq: event.seq });
|
|
315
|
+
deps.rowIds.value += 1;
|
|
316
|
+
for (const line of record.lines) {
|
|
317
|
+
appendRow({
|
|
318
|
+
id: deps.rowIds.value,
|
|
319
|
+
kind: 'local-output',
|
|
320
|
+
text: preview(line, LOCAL_OUTPUT_LIMIT),
|
|
321
|
+
seq: event.seq,
|
|
322
|
+
});
|
|
323
|
+
deps.rowIds.value += 1;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
if (event.isError) {
|
|
327
|
+
append({ title: event.errorText ?? '', lines: [] });
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const answers = parseQuestionRecordAnswers(event.text);
|
|
331
|
+
// No parseable answers (unparseable durable payload, or an older host):
|
|
332
|
+
// `answers: []` still yields the title, so the transcript shows that a
|
|
333
|
+
// questionnaire happened instead of dropping the fact silently.
|
|
334
|
+
append(buildQuestionRecord(parseQuestionRecordQuestions(rawArguments), answers ?? []));
|
|
335
|
+
};
|
|
336
|
+
/** Recompute the spinner phase from live row/tool state. */
|
|
337
|
+
const updateSpinnerMode = () => {
|
|
338
|
+
if (state.activeToolCount > 0) {
|
|
339
|
+
state.spinnerMode = 'tool-use';
|
|
340
|
+
}
|
|
341
|
+
else if (reasoning !== undefined) {
|
|
342
|
+
// Only live reasoning counts: sealed rows stay streaming=true for
|
|
343
|
+
// transcript expansion until turn end but the model is past thinking.
|
|
344
|
+
state.spinnerMode = 'thinking';
|
|
345
|
+
}
|
|
346
|
+
else if (streaming !== undefined) {
|
|
347
|
+
state.spinnerMode = 'responding';
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
state.spinnerMode = 'requesting';
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
/** Fold one goal mutation into the channel's goal projection. */
|
|
354
|
+
const applyGoalChange = (operation, goal, roundsStarted) => {
|
|
355
|
+
if (operation === 'clear') {
|
|
356
|
+
state.goal = undefined;
|
|
357
|
+
}
|
|
358
|
+
else if (goal !== undefined) {
|
|
359
|
+
state.goal = {
|
|
360
|
+
...goal,
|
|
361
|
+
roundsStarted: roundsStarted ?? state.goal?.roundsStarted ?? 0,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
/** Replay paints settled history without the live smooth-reveal animation. */
|
|
366
|
+
let replaying = false;
|
|
367
|
+
/** Whether one delta advances the first-token/decode boundary. */
|
|
368
|
+
const isTokenDelta = (delta) => {
|
|
369
|
+
switch (delta.kind) {
|
|
370
|
+
case 'text':
|
|
371
|
+
case 'reasoning':
|
|
372
|
+
return delta.text !== '';
|
|
373
|
+
case 'tool-args':
|
|
374
|
+
return delta.partialJson !== '' || delta.name !== undefined;
|
|
375
|
+
default:
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
/** Fractional token estimate of one token-bearing delta for the live fold
|
|
380
|
+
* (script-weighted, see estimateTokensFraction): the old raw char count fed
|
|
381
|
+
* a chars/4 conversion that under-counted CJK output ~3x. */
|
|
382
|
+
const tokenDeltaEstimate = (delta) => {
|
|
383
|
+
switch (delta.kind) {
|
|
384
|
+
case 'text':
|
|
385
|
+
case 'reasoning':
|
|
386
|
+
return estimateTokensFraction(delta.text);
|
|
387
|
+
case 'tool-args':
|
|
388
|
+
return (delta.name === undefined ? 0 : estimateTokensFraction(delta.name)) + estimateTokensFraction(delta.partialJson);
|
|
389
|
+
default:
|
|
390
|
+
return 0;
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
/**
|
|
394
|
+
* One stream delta at a resolved (turn, step). `seq` exists only on
|
|
395
|
+
* positioned (legacy durable) deltas, which use the overlap-tolerant merge.
|
|
396
|
+
*/
|
|
397
|
+
const renderStreamDelta = (turn, step, delta, time, seq) => {
|
|
398
|
+
if (delta.kind === 'text') {
|
|
399
|
+
if (delta.text) {
|
|
400
|
+
// Fold the thinking preview while it is still in the live window
|
|
401
|
+
// (see settleLiveReasoning) — before this text grows the transcript
|
|
402
|
+
// and pushes the block into scrollback.
|
|
403
|
+
settleLiveReasoning('first text token');
|
|
404
|
+
const key = stepKey(turn, step);
|
|
405
|
+
const row = assistantRowsByStep.get(key) ?? ensureStreaming(seq);
|
|
406
|
+
assistantRowsByStep.set(key, row);
|
|
407
|
+
streaming = row;
|
|
408
|
+
row.streaming = true;
|
|
409
|
+
touchRow(row);
|
|
410
|
+
const before = row.text.length;
|
|
411
|
+
appendTextDelta(row, delta.text, seq !== undefined);
|
|
412
|
+
state.responseChars += Math.max(0, row.text.length - before);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
else if (delta.kind === 'reasoning') {
|
|
416
|
+
if (delta.text) {
|
|
417
|
+
const row = ensureReasoning(seq, turn, step);
|
|
418
|
+
appendTextDelta(row, delta.text, seq !== undefined);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
else if (delta.kind === 'reasoning-tokens') {
|
|
422
|
+
// Thinking reported only as an estimated token count:
|
|
423
|
+
// the reasoning row opens with no text and shows the live count; text
|
|
424
|
+
// that arrives later still wins in the view.
|
|
425
|
+
const row = ensureReasoning(seq, turn, step);
|
|
426
|
+
if (row.reasoningTokens !== delta.estimated) {
|
|
427
|
+
row.reasoningTokens = delta.estimated;
|
|
428
|
+
touchRow(row);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
const tps = tpsStep;
|
|
432
|
+
if (tps !== undefined &&
|
|
433
|
+
tps.turn === turn &&
|
|
434
|
+
tps.step === step &&
|
|
435
|
+
isTokenDelta(delta)) {
|
|
436
|
+
tps.firstTokenTime ??= time;
|
|
437
|
+
tps.outputEstimate += tokenDeltaEstimate(delta);
|
|
438
|
+
const elapsedMs = Math.max(0, time - tps.firstTokenTime);
|
|
439
|
+
if (elapsedMs > 500) {
|
|
440
|
+
const decodeMs = tpsTurnDecodeMs + elapsedMs;
|
|
441
|
+
const outputTokens = tpsTurnDecodeTokens + Math.ceil(tps.outputEstimate);
|
|
442
|
+
state.tps = outputTokens / (decodeMs / 1000);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
updateSpinnerMode();
|
|
446
|
+
};
|
|
447
|
+
/**
|
|
448
|
+
* Book one model call's usage: session totals, the cost buckets, the
|
|
449
|
+
* context sample and the open turn's ledger. Shared by settled messages
|
|
450
|
+
* and the separate usage reports a backend sends after a reply settled.
|
|
451
|
+
*/
|
|
452
|
+
const bookUsage = (usage, event) => {
|
|
453
|
+
state.tokens.input += usage.input ?? 0;
|
|
454
|
+
state.tokens.output += usage.output ?? 0;
|
|
455
|
+
// Cache split totals feed the session cost estimate (hit-priced input
|
|
456
|
+
// vs. uncached input) — the durable replay may lack them.
|
|
457
|
+
state.tokens.cacheRead += usage.cacheRead ?? 0;
|
|
458
|
+
state.tokens.cacheWrite += usage.cacheWrite ?? 0;
|
|
459
|
+
// Rate-window bucketing by the request's own time (the durable replay
|
|
460
|
+
// replays historical events, so a resumed session prices each request
|
|
461
|
+
// at the rate window it actually ran in — the session cost estimate
|
|
462
|
+
// never prices the whole session at the current window).
|
|
463
|
+
const peak = (deps.pricingWindow?.(event.time) ?? 'idle') === 'peak';
|
|
464
|
+
addUsageToBucket(peak ? state.tokens.peak : state.tokens.idle, usage);
|
|
465
|
+
// 主会话费用分桶:计数方式与 tokens 相同,但按事件发生时的模型
|
|
466
|
+
// 归属。replay 用 request.header 还原历史请求模型,旧日志回退
|
|
467
|
+
// channel 模型;换模型不会把历史 token 重估到新模型。
|
|
468
|
+
if ((usage.input ?? 0) !== 0 || (usage.output ?? 0) !== 0 || (usage.cacheRead ?? 0) !== 0 || (usage.cacheWrite ?? 0) !== 0) {
|
|
469
|
+
const model = eventModel ?? event.model ?? state.model;
|
|
470
|
+
const cost = state.mainCost[model] ?? emptyCostBuckets();
|
|
471
|
+
addUsageToBucket(peak ? cost.peak : cost.idle, usage);
|
|
472
|
+
state.mainCost[model] = cost;
|
|
473
|
+
}
|
|
474
|
+
// The most recent request's usage describes the current context:
|
|
475
|
+
// input (uncached) + cache hits all occupy the window. Cache hits
|
|
476
|
+
// also drive the status-line `cache N` readout.
|
|
477
|
+
state.lastUsage = {
|
|
478
|
+
input: usage.input ?? 0,
|
|
479
|
+
output: usage.output ?? 0,
|
|
480
|
+
cacheRead: usage.cacheRead ?? 0,
|
|
481
|
+
cacheWrite: usage.cacheWrite ?? 0,
|
|
482
|
+
at: event.time,
|
|
483
|
+
};
|
|
484
|
+
// Turn ledger: each message reports its own request's increment, so
|
|
485
|
+
// the sum is the turn total. Cache fields absent on the wire stay
|
|
486
|
+
// absent (cacheKnown distinguishes zero from unreported).
|
|
487
|
+
turnLedger.input += usage.input ?? 0;
|
|
488
|
+
turnLedger.output += usage.output ?? 0;
|
|
489
|
+
turnLedger.cacheRead += usage.cacheRead ?? 0;
|
|
490
|
+
turnLedger.cacheWrite += usage.cacheWrite ?? 0;
|
|
491
|
+
if (usage.cacheRead !== undefined || usage.cacheWrite !== undefined)
|
|
492
|
+
turnLedger.cacheKnown = true;
|
|
493
|
+
turnLedger.usageSeen = true;
|
|
494
|
+
if (event.model !== undefined && event.model !== '')
|
|
495
|
+
turnLedger.model = event.model;
|
|
496
|
+
};
|
|
497
|
+
const applyAssistantMessage = (event) => {
|
|
498
|
+
if (handledAssistantMessages.has(event.seq))
|
|
499
|
+
return;
|
|
500
|
+
handledAssistantMessages.add(event.seq);
|
|
501
|
+
// A canonical settlement embeds its complete attempt; older settlements
|
|
502
|
+
// may omit reasoning that is still durably recorded in legacy deltas.
|
|
503
|
+
const canonical = event.canonical;
|
|
504
|
+
const text = textOfBlocks(event.blocks);
|
|
505
|
+
const images = event.images ?? NO_IMAGES;
|
|
506
|
+
const reasoningText = event.blocks
|
|
507
|
+
.map(block => (block.type === 'reasoning' ? block.text : ''))
|
|
508
|
+
.join('');
|
|
509
|
+
// A backend's own message anchor beyond the seq (DSH anchors are the
|
|
510
|
+
// seq, so DSH rows carry none) is how "load earlier" finds the durable
|
|
511
|
+
// message a folded row came from.
|
|
512
|
+
const anchor = event.anchor === '' || event.anchor === String(event.seq) ? undefined : event.anchor;
|
|
513
|
+
const settledReasoning = lastReasoningRow !== undefined && lastReasoningRow.turn === event.turn && lastReasoningRow.step === event.step
|
|
514
|
+
? lastReasoningRow.row : reasoning;
|
|
515
|
+
if (settledReasoning !== undefined) {
|
|
516
|
+
if (reasoningText === '') {
|
|
517
|
+
// A count-only thinking row (no text was ever recorded) settles as
|
|
518
|
+
// its one-line summary instead of vanishing with the empty block.
|
|
519
|
+
if (canonical && settledReasoning.reasoningTokens === undefined)
|
|
520
|
+
removeRow(settledReasoning);
|
|
521
|
+
else if (anchor !== undefined && settledReasoning.anchor === undefined)
|
|
522
|
+
settledReasoning.anchor = anchor;
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
settledReasoning.text = reasoningText;
|
|
526
|
+
settledReasoning.seq ??= event.seq;
|
|
527
|
+
if (anchor !== undefined)
|
|
528
|
+
settledReasoning.anchor ??= anchor;
|
|
529
|
+
touchRow(settledReasoning);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
else if (reasoningText !== '') {
|
|
533
|
+
// Replays and reattachments may not have seen any reasoning delta.
|
|
534
|
+
// Insert before a live text row to preserve message block order.
|
|
535
|
+
const rebuilt = {
|
|
536
|
+
id: deps.rowIds.value,
|
|
537
|
+
kind: 'reasoning',
|
|
538
|
+
text: reasoningText,
|
|
539
|
+
seq: event.seq,
|
|
540
|
+
...(anchor === undefined ? {} : { anchor }),
|
|
541
|
+
};
|
|
542
|
+
deps.rowIds.value += 1;
|
|
543
|
+
const textRow = assistantRowsByStep.get(stepKey(event.turn, event.step));
|
|
544
|
+
const textIndex = textRow === undefined ? -1 : state.rows.indexOf(textRow);
|
|
545
|
+
if (textIndex === -1)
|
|
546
|
+
appendRow(rebuilt);
|
|
547
|
+
else {
|
|
548
|
+
state.rows.splice(textIndex, 0, rebuilt);
|
|
549
|
+
markChannelReadDirty(state.rows);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
// Reasoning/tool-only steps emit no text: creating an assistant row
|
|
553
|
+
// anyway leaves an empty `●` bullet in the transcript. A pre-existing
|
|
554
|
+
// streaming row always has text (ensureStreaming is only reached on
|
|
555
|
+
// non-empty text deltas), so only create one when text arrives.
|
|
556
|
+
// Key the step→row ledger only when the event carries a durable
|
|
557
|
+
// turn/step; a message without them must never collide onto a
|
|
558
|
+
// previous step's row (a bare `undefined:undefined` key would make
|
|
559
|
+
// every turn/step-less message reuse the FIRST one's assistant row).
|
|
560
|
+
const msgTurn = event.turn;
|
|
561
|
+
const msgStep = event.step;
|
|
562
|
+
const msgKey = msgTurn !== undefined && msgStep !== undefined
|
|
563
|
+
? stepKey(msgTurn, msgStep)
|
|
564
|
+
: undefined;
|
|
565
|
+
const row = (msgKey !== undefined ? assistantRowsByStep.get(msgKey) : undefined) ?? streaming ??
|
|
566
|
+
(text || images.length > 0 ? assistantRowsBySeq.get(event.seq) ?? openStreaming(event.seq) : undefined);
|
|
567
|
+
if (row !== undefined && canonical && !text && images.length === 0) {
|
|
568
|
+
removeRow(row);
|
|
569
|
+
if (msgKey !== undefined)
|
|
570
|
+
assistantRowsByStep.delete(msgKey);
|
|
571
|
+
}
|
|
572
|
+
else if (row !== undefined) {
|
|
573
|
+
if (msgKey !== undefined)
|
|
574
|
+
assistantRowsByStep.set(msgKey, row);
|
|
575
|
+
row.seq ??= event.seq;
|
|
576
|
+
indexAssistantRow(row);
|
|
577
|
+
if (anchor !== undefined)
|
|
578
|
+
row.anchor ??= anchor;
|
|
579
|
+
row.time = event.time;
|
|
580
|
+
if (text || canonical)
|
|
581
|
+
row.text = text;
|
|
582
|
+
row.images = images.length === 0 ? undefined : images;
|
|
583
|
+
row.streaming = false;
|
|
584
|
+
// Live settles keep the smooth-reveal cursor alive (a one-shot
|
|
585
|
+
// non-streaming delivery still paints as a flow); replayed settles
|
|
586
|
+
// must not, or the transcript would typewrite on open.
|
|
587
|
+
if (!replaying && text)
|
|
588
|
+
row.fresh = true;
|
|
589
|
+
touchRow(row);
|
|
590
|
+
}
|
|
591
|
+
streaming = undefined;
|
|
592
|
+
if (reasoning !== undefined) {
|
|
593
|
+
// Backstop fold: reasoning whose step ended with no text token and no
|
|
594
|
+
// tool call (settleLiveReasoning handles those earlier, while the block
|
|
595
|
+
// is still in the repaintable live window; here a long reply may
|
|
596
|
+
// already have pushed it into scrollback, where the shrink cannot be
|
|
597
|
+
// repainted). `full` mode (/settings opt-in) keeps the block expanded
|
|
598
|
+
// until turn settle; settleStreaming folds the sealed rows then.
|
|
599
|
+
reasoning.durationMs = Math.max(0, Date.now() - reasoningStart);
|
|
600
|
+
reasoning.streaming = false;
|
|
601
|
+
reasoning.thinkingOpen = state.thinkingFold === 'full';
|
|
602
|
+
touchRow(reasoning);
|
|
603
|
+
sealedReasoning.push(reasoning);
|
|
604
|
+
logForDebugging(`thinking: step sealed (${reasoning.durationMs}ms), expanded until turn/end`);
|
|
605
|
+
}
|
|
606
|
+
reasoning = undefined;
|
|
607
|
+
if (activeAttempt !== undefined && activeAttempt.turn === event.turn && activeAttempt.step === event.step)
|
|
608
|
+
activeAttempt = undefined;
|
|
609
|
+
updateSpinnerMode();
|
|
610
|
+
const usage = event.usage;
|
|
611
|
+
if (usage !== undefined)
|
|
612
|
+
bookUsage(usage, event);
|
|
613
|
+
const tpsMessageStep = tpsStep;
|
|
614
|
+
// Same-timestamp delivery has no measurable decode span; its tokens
|
|
615
|
+
// must not inflate the rate of another step in this turn.
|
|
616
|
+
if (tpsTurn === event.turn &&
|
|
617
|
+
tpsMessageStep !== undefined &&
|
|
618
|
+
tpsMessageStep.turn === event.turn &&
|
|
619
|
+
tpsMessageStep.step === event.step &&
|
|
620
|
+
tpsMessageStep.firstTokenTime !== undefined &&
|
|
621
|
+
event.time > tpsMessageStep.firstTokenTime) {
|
|
622
|
+
const reported = usageOutputTokens(usage);
|
|
623
|
+
const outputTokens = reported
|
|
624
|
+
?? (tpsMessageStep.outputEstimate > 0
|
|
625
|
+
? Math.ceil(tpsMessageStep.outputEstimate)
|
|
626
|
+
: undefined);
|
|
627
|
+
const decodeMs = Math.max(0, event.time - tpsMessageStep.firstTokenTime);
|
|
628
|
+
tpsTurnDecodeMs += decodeMs;
|
|
629
|
+
if (outputTokens !== undefined) {
|
|
630
|
+
tpsTurnDecodeTokens += outputTokens;
|
|
631
|
+
tpsTurnSampled = true;
|
|
632
|
+
if (tpsTurnDecodeMs > 0) {
|
|
633
|
+
state.tps = tpsTurnDecodeTokens / (tpsTurnDecodeMs / 1000);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
// A backend can signal hidden generation without any content delta.
|
|
637
|
+
// Keep its timed span for later usage, without sampling a zero rate.
|
|
638
|
+
tpsTurnSteps = [...tpsTurnSteps.filter(step => step.step !== event.step), { step: event.step, tokens: outputTokens ?? 0, estimated: reported === undefined }];
|
|
639
|
+
}
|
|
640
|
+
if (tpsMessageStep !== undefined &&
|
|
641
|
+
tpsMessageStep.turn === event.turn &&
|
|
642
|
+
tpsMessageStep.step === event.step) {
|
|
643
|
+
tpsStep = undefined;
|
|
644
|
+
}
|
|
645
|
+
// Context-bar segmentation (pi-nano-context style): assistant text and
|
|
646
|
+
// tool calls in the assistant segment, thinking separately.
|
|
647
|
+
for (const block of event.blocks) {
|
|
648
|
+
if (block.type === 'text' && block.text) {
|
|
649
|
+
state.contextSegments.assistant += estimateTokens(block.text);
|
|
650
|
+
}
|
|
651
|
+
else if (block.type === 'reasoning' && block.text) {
|
|
652
|
+
state.contextSegments.thinking += estimateTokens(block.text);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
const applyUserMessage = (event) => {
|
|
657
|
+
// A compaction checkpoint renders as a folded summary rather than
|
|
658
|
+
// disappearing with the other injected context.
|
|
659
|
+
if (event.source === 'compaction') {
|
|
660
|
+
const summary = event.text;
|
|
661
|
+
appendRow({ id: deps.rowIds.value, kind: 'notice', text: t('compact-done') });
|
|
662
|
+
deps.rowIds.value += 1;
|
|
663
|
+
if (summary) {
|
|
664
|
+
appendRow({ id: deps.rowIds.value, kind: 'compact', text: summary });
|
|
665
|
+
deps.rowIds.value += 1;
|
|
666
|
+
}
|
|
667
|
+
// The checkpoint replaces the whole pre-compact surface. Occupancy
|
|
668
|
+
// needs no chars/4 rewrite here: a DSH host's token meter folds this
|
|
669
|
+
// same event and reprices the surface by its logged shadow price (the
|
|
670
|
+
// channel's `contextOccupancy` drops the moment the checkpoint lands),
|
|
671
|
+
// and a backend that measures the compacted window reports it on
|
|
672
|
+
// `compaction.end` (`postTokens`, below). `tokens.*` are cumulative
|
|
673
|
+
// session counters and are never rewritten by a compaction.
|
|
674
|
+
//
|
|
675
|
+
// The segmented bar keeps its own heuristic composition (system + the
|
|
676
|
+
// summary prompt): it describes what the surface is made of, never the
|
|
677
|
+
// occupancy total.
|
|
678
|
+
state.contextSegments = {
|
|
679
|
+
system: state.contextSegments.system,
|
|
680
|
+
prompt: estimateTokens(summary),
|
|
681
|
+
assistant: 0,
|
|
682
|
+
thinking: 0,
|
|
683
|
+
tools: 0,
|
|
684
|
+
};
|
|
685
|
+
// The latch must release: compaction is the remediation for a low
|
|
686
|
+
// context, so the warning has to be able to fire again afterwards.
|
|
687
|
+
deps.resetContextWarning();
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
// Command output a backend recorded as an input (Claude: `!!` output
|
|
691
|
+
// sent on to the model): live, the channel already showed the command
|
|
692
|
+
// and its output; a replay restores the output row.
|
|
693
|
+
if (event.source === 'command-output') {
|
|
694
|
+
if (replaying && event.text !== '') {
|
|
695
|
+
appendRow({ id: deps.rowIds.value, kind: 'local-output', text: preview(event.text, LOCAL_OUTPUT_LIMIT), seq: event.seq });
|
|
696
|
+
deps.rowIds.value += 1;
|
|
697
|
+
}
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
// Injected context (plugin/skill/goal source) is not a human bubble;
|
|
701
|
+
// v1 renders direct human prompts only.
|
|
702
|
+
if (event.source !== 'user')
|
|
703
|
+
return;
|
|
704
|
+
const text = event.text;
|
|
705
|
+
const images = event.images ?? NO_IMAGES;
|
|
706
|
+
if (text || images.length > 0) {
|
|
707
|
+
// IDE selection indicator: the delivery path remembered what this
|
|
708
|
+
// message attached; the durable event carries the same message id.
|
|
709
|
+
// On replay (session resumed in a new process) the in-memory map
|
|
710
|
+
// starts empty, so the indicator falls back to the durable content
|
|
711
|
+
// itself: the `<attached-file … selection>` block is part of the
|
|
712
|
+
// persisted message, so the indicator survives a restart.
|
|
713
|
+
const selectionAttached = deps.selectionAttached(event.id)
|
|
714
|
+
?? replaySelectionAttachment(event.blocks);
|
|
715
|
+
appendRow({
|
|
716
|
+
id: deps.rowIds.value,
|
|
717
|
+
kind: 'user',
|
|
718
|
+
text,
|
|
719
|
+
...(images.length === 0 ? {} : { images }),
|
|
720
|
+
...(selectionAttached === undefined ? {} : { selectionAttached }),
|
|
721
|
+
seq: event.seq,
|
|
722
|
+
// A native anchor beyond the seq (DSH anchors are the seq, so DSH
|
|
723
|
+
// rows carry none) is what a backend rewind needs.
|
|
724
|
+
...(event.anchor === '' || event.anchor === String(event.seq) ? {} : { anchor: event.anchor }),
|
|
725
|
+
});
|
|
726
|
+
state.lastUserText = text || t('transcript-image-message', { count: images.length });
|
|
727
|
+
// The context estimate counts everything sent to the model: typed
|
|
728
|
+
// text and the `@`-mention attachment blocks.
|
|
729
|
+
state.contextSegments.prompt += estimateTokens(textOfBlocks(event.blocks));
|
|
730
|
+
deps.rowIds.value += 1;
|
|
731
|
+
}
|
|
732
|
+
};
|
|
733
|
+
const applyToolCall = (event) => {
|
|
734
|
+
const presentation = event.presentation;
|
|
735
|
+
// A question-presented call renders as the interactive questionnaire
|
|
736
|
+
// panel, not as a tool card: the model is parked waiting for the human,
|
|
737
|
+
// so no running card, no active-tool spinner, no args noise in the
|
|
738
|
+
// transcript. Only the arguments are remembered: the paired result
|
|
739
|
+
// projects the answered record from them (issue #1009), so `/resume`,
|
|
740
|
+
// rewind and replay rebuild it from the persisted log like every other
|
|
741
|
+
// transcript row.
|
|
742
|
+
if (presentation?.card === 'question') {
|
|
743
|
+
askCalls.set(event.callId, event.argsJson);
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
// A subagent delegation renders as the live subagent card (Kimi Code
|
|
747
|
+
// semantics), so the raw args/result card would only duplicate it. The
|
|
748
|
+
// call still runs; only its transcript rendering is suppressed. The
|
|
749
|
+
// subagent reducer owns pending descriptions, including delegations made
|
|
750
|
+
// while this transcript is parked.
|
|
751
|
+
if (presentation?.card === 'subagent')
|
|
752
|
+
return;
|
|
753
|
+
// A todo-list write renders in the todo panel (the backend emits
|
|
754
|
+
// `todo.write` with it); a card would repeat the list. The call is
|
|
755
|
+
// remembered so its result can still surface a failure card.
|
|
756
|
+
if (presentation?.card === 'todo') {
|
|
757
|
+
todoCalls.set(event.callId, { name: event.name, argsJson: event.argsJson, seq: event.seq, time: event.time });
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
// Reasoning that led to a tool call is done thinking: fold the preview
|
|
761
|
+
// now, before the tool card grows the transcript past it (see
|
|
762
|
+
// settleLiveReasoning).
|
|
763
|
+
settleLiveReasoning('tool call');
|
|
764
|
+
const card = {
|
|
765
|
+
id: deps.rowIds.value,
|
|
766
|
+
kind: 'tool',
|
|
767
|
+
text: '',
|
|
768
|
+
seq: event.seq,
|
|
769
|
+
// Smooth-reveal participation flag: live cards animate their body in;
|
|
770
|
+
// replayed cards (resume/rewind) paint complete.
|
|
771
|
+
fresh: !replaying,
|
|
772
|
+
tool: {
|
|
773
|
+
callId: event.callId,
|
|
774
|
+
name: event.name,
|
|
775
|
+
argsText: preview(event.argsJson, ARGS_PREVIEW_LIMIT),
|
|
776
|
+
argsFull: event.argsJson,
|
|
777
|
+
status: 'running',
|
|
778
|
+
callView: presentation,
|
|
779
|
+
startedAt: Date.now(),
|
|
780
|
+
},
|
|
781
|
+
};
|
|
782
|
+
deps.rowIds.value += 1;
|
|
783
|
+
toolCards.set(event.callId, card);
|
|
784
|
+
appendRow(card);
|
|
785
|
+
state.activeToolCount += 1;
|
|
786
|
+
state.contextSegments.assistant += estimateTokens(`${event.name}${event.argsJson}`);
|
|
787
|
+
updateSpinnerMode();
|
|
788
|
+
};
|
|
789
|
+
const applyToolResult = (event) => {
|
|
790
|
+
const callId = event.callId;
|
|
791
|
+
const card = toolCards.get(callId);
|
|
792
|
+
const askArguments = askCalls.get(callId);
|
|
793
|
+
// A call with no card is usually a question-presented one (above). Its
|
|
794
|
+
// interaction lives in the panel, but its outcome still belongs in the
|
|
795
|
+
// transcript, projected from the durable log here: consumed before the
|
|
796
|
+
// card branch so the two can never both fire, and deleted so a repeated
|
|
797
|
+
// replay of the same result cannot double the record.
|
|
798
|
+
if (card === undefined && askArguments !== undefined) {
|
|
799
|
+
projectAskResult(event, askArguments);
|
|
800
|
+
askCalls.delete(callId);
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
const suppressedTodo = todoCalls.get(callId);
|
|
804
|
+
if (suppressedTodo !== undefined) {
|
|
805
|
+
todoCalls.delete(callId);
|
|
806
|
+
// Success stays in the panel; only a failure needs a visible card.
|
|
807
|
+
if (event.isError) {
|
|
808
|
+
settleLiveReasoning('tool call');
|
|
809
|
+
const errorCard = {
|
|
810
|
+
id: deps.rowIds.value,
|
|
811
|
+
kind: 'tool',
|
|
812
|
+
text: '',
|
|
813
|
+
seq: suppressedTodo.seq,
|
|
814
|
+
fresh: !replaying,
|
|
815
|
+
tool: {
|
|
816
|
+
callId,
|
|
817
|
+
name: suppressedTodo.name,
|
|
818
|
+
argsText: preview(suppressedTodo.argsJson, ARGS_PREVIEW_LIMIT),
|
|
819
|
+
argsFull: suppressedTodo.argsJson,
|
|
820
|
+
status: 'error',
|
|
821
|
+
callView: undefined,
|
|
822
|
+
startedAt: suppressedTodo.time,
|
|
823
|
+
errorText: event.errorText ?? '',
|
|
824
|
+
},
|
|
825
|
+
};
|
|
826
|
+
deps.rowIds.value += 1;
|
|
827
|
+
appendRow(errorCard);
|
|
828
|
+
state.contextSegments.tools += estimateTokens(event.errorText ?? '');
|
|
829
|
+
}
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
if (card === undefined || card.tool === undefined)
|
|
833
|
+
return;
|
|
834
|
+
// The result carries the output of record: the live tail goes (deleted,
|
|
835
|
+
// not set undefined, so a card that never printed keeps its shape).
|
|
836
|
+
if (liveTails.delete(callId)) {
|
|
837
|
+
delete card.tool.liveOutput;
|
|
838
|
+
delete card.tool.liveOutputDropped;
|
|
839
|
+
}
|
|
840
|
+
const images = event.images ?? NO_IMAGES;
|
|
841
|
+
card.images = images.length === 0 ? undefined : images;
|
|
842
|
+
card.tool.durationMs = Math.max(0, Date.now() - card.tool.startedAt);
|
|
843
|
+
if (event.isError) {
|
|
844
|
+
card.tool.status = 'error';
|
|
845
|
+
const errorText = event.errorText ?? '';
|
|
846
|
+
card.tool.errorText = errorText;
|
|
847
|
+
state.contextSegments.tools += estimateTokens(errorText);
|
|
848
|
+
}
|
|
849
|
+
else {
|
|
850
|
+
card.tool.status = 'ok';
|
|
851
|
+
const result = event.text;
|
|
852
|
+
card.tool.resultText = result ? preview(result, RESULT_PREVIEW_LIMIT) : undefined;
|
|
853
|
+
// A card the window cap already folded while it ran keeps only its
|
|
854
|
+
// preview: foldRows drops the full payload and the presentation views
|
|
855
|
+
// by design (the durable record re-derives them on loadOlder), so a
|
|
856
|
+
// late result must not re-attach them past the fold line.
|
|
857
|
+
if (card.folded !== true) {
|
|
858
|
+
card.tool.resultFull = result || undefined;
|
|
859
|
+
// The tool's own settled-state view (applied diff, terminal output,
|
|
860
|
+
// read content…) wins over the raw text body.
|
|
861
|
+
card.tool.resultView = event.presentation;
|
|
862
|
+
}
|
|
863
|
+
state.contextSegments.tools += estimateTokens(result);
|
|
864
|
+
settledCardCallId = callId;
|
|
865
|
+
}
|
|
866
|
+
state.activeToolCount = Math.max(0, state.activeToolCount - 1);
|
|
867
|
+
// The card is settled: no later event looks it up by callId, so drop the
|
|
868
|
+
// index entry. The card itself stays in state.rows (bounded by MAX_ROWS +
|
|
869
|
+
// foldRows, which also drops the full args/result payloads of folded
|
|
870
|
+
// cards).
|
|
871
|
+
toolCards.delete(callId);
|
|
872
|
+
touchRow(card);
|
|
873
|
+
updateSpinnerMode();
|
|
874
|
+
};
|
|
875
|
+
/**
|
|
876
|
+
* One live-output chunk of a running card: appended to its bounded tail
|
|
877
|
+
* (`./live-output.ts`) and published on the row. Only that row changes
|
|
878
|
+
* (the read view marks it dirty), so only the running card re-renders. A
|
|
879
|
+
* chunk for a call with no running card here (unknown, settled, folded
|
|
880
|
+
* by the window cap, or a suppressed question/todo/subagent call) is
|
|
881
|
+
* ignored.
|
|
882
|
+
*/
|
|
883
|
+
const applyToolOutput = (event) => {
|
|
884
|
+
const card = toolCards.get(event.callId);
|
|
885
|
+
if (card?.tool === undefined || card.tool.status !== 'running' || card.folded === true || event.text === '')
|
|
886
|
+
return;
|
|
887
|
+
const tail = appendLiveOutput(liveTails.get(event.callId), event.text);
|
|
888
|
+
liveTails.set(event.callId, tail);
|
|
889
|
+
card.tool.liveOutput = tail.text;
|
|
890
|
+
if (tail.dropped > 0)
|
|
891
|
+
card.tool.liveOutputDropped = tail.dropped;
|
|
892
|
+
touchRow(card);
|
|
893
|
+
};
|
|
894
|
+
/** A task feed derived from one tool result reaches the job registry only
|
|
895
|
+
* when that result settled an ok card here (see settledCardCallId). */
|
|
896
|
+
const taskFeedAdmitted = (callId) => callId === undefined || callId === settledCardCallId;
|
|
897
|
+
const applyTurnEnd = (event) => {
|
|
898
|
+
// A backend-reported session cost (cumulative, e.g. Claude
|
|
899
|
+
// `total_cost_usd`) replaces the previous report; DSH reports none.
|
|
900
|
+
if (event.cost !== undefined)
|
|
901
|
+
state.costReport = event.cost;
|
|
902
|
+
if (activeAttempt !== undefined)
|
|
903
|
+
discardAttempt(activeAttempt.turn, activeAttempt.step);
|
|
904
|
+
openStep = undefined;
|
|
905
|
+
deps.inputConvergence.cancelInFlight = false;
|
|
906
|
+
state.cancelPending = false;
|
|
907
|
+
settleStreaming();
|
|
908
|
+
state.working = false;
|
|
909
|
+
state.activeToolCount = 0;
|
|
910
|
+
if (tpsTurn !== undefined && tpsTurn === event.turn) {
|
|
911
|
+
let sample;
|
|
912
|
+
if (tpsTurnSampled && tpsTurnDecodeMs > 0) {
|
|
913
|
+
const turnTps = tpsTurnDecodeTokens / (tpsTurnDecodeMs / 1000);
|
|
914
|
+
state.tps = turnTps;
|
|
915
|
+
sample = { tps: turnTps, at: event.time };
|
|
916
|
+
state.tpsSamples.push(sample);
|
|
917
|
+
if (state.tpsSamples.length > 500)
|
|
918
|
+
state.tpsSamples.shift();
|
|
919
|
+
}
|
|
920
|
+
else {
|
|
921
|
+
// Do not leave a chars/4 live estimate behind when no completed
|
|
922
|
+
// decode sample exists for this turn.
|
|
923
|
+
state.tps = tpsBeforeTurn;
|
|
924
|
+
}
|
|
925
|
+
// Keep the ended turn's fold ONE turn longer: a straggler usage report
|
|
926
|
+
// (Codex may deliver the final metering after turn/completed) still
|
|
927
|
+
// corrects the tps readout and the just-pushed sample through it.
|
|
928
|
+
tpsClosedTurn = tpsTurnSteps.length > 0 ? { turn: event.turn, decodeMs: tpsTurnDecodeMs, steps: tpsTurnSteps, endAt: event.time, sample } : undefined;
|
|
929
|
+
tpsTurn = undefined;
|
|
930
|
+
tpsStep = undefined;
|
|
931
|
+
tpsTurnSteps = [];
|
|
932
|
+
tpsTurnDecodeMs = 0;
|
|
933
|
+
tpsTurnDecodeTokens = 0;
|
|
934
|
+
tpsTurnSampled = false;
|
|
935
|
+
}
|
|
936
|
+
// Occupancy is evaluated on every turn end, not only a completed one:
|
|
937
|
+
// the request that overflowed the window is exactly the one whose turn
|
|
938
|
+
// ends as an error (it writes no successful usage sample at all), and an
|
|
939
|
+
// aborted turn has still grown the surface. Replay drains a resumed
|
|
940
|
+
// session's history through the projector; its totals describe the past,
|
|
941
|
+
// not a live context-low state.
|
|
942
|
+
if (!replaying)
|
|
943
|
+
deps.checkContextWarning();
|
|
944
|
+
const reason = event.reason;
|
|
945
|
+
// Turn ledger → summary row + footer snapshot. Rendered as the turn's
|
|
946
|
+
// last row (after the interrupt/notice that closes it), so the ledger
|
|
947
|
+
// reads as the account of what just happened. A turn with no
|
|
948
|
+
// usage-bearing message emits nothing (nothing was measured), and a
|
|
949
|
+
// fully successful zero-usage turn stays quiet too.
|
|
950
|
+
const outcome = reason.kind === 'completed' ? 'completed'
|
|
951
|
+
: reason.kind === 'aborted' || reason.kind === 'interrupted' ? 'interrupted'
|
|
952
|
+
: 'error';
|
|
953
|
+
const emitTurnSummary = () => {
|
|
954
|
+
if (!turnLedger.usageSeen)
|
|
955
|
+
return;
|
|
956
|
+
const total = turnLedger.input + turnLedger.output + turnLedger.cacheRead + turnLedger.cacheWrite;
|
|
957
|
+
if (outcome === 'completed' && total === 0 && turnFailedAttempts.size === 0)
|
|
958
|
+
return;
|
|
959
|
+
const summary = {
|
|
960
|
+
input: turnLedger.input,
|
|
961
|
+
output: turnLedger.output,
|
|
962
|
+
cacheRead: turnLedger.cacheRead,
|
|
963
|
+
cacheWrite: turnLedger.cacheWrite,
|
|
964
|
+
cacheKnown: turnLedger.cacheKnown,
|
|
965
|
+
retries: turnFailedAttempts.size,
|
|
966
|
+
durationMs: Math.max(0, event.time - turnLedger.startedAt),
|
|
967
|
+
...(turnLedger.model === undefined ? {} : { model: turnLedger.model }),
|
|
968
|
+
...(turnLedger.model === undefined || turnLedger.model === lastNotedTurnModel ? {} : { noteModel: true }),
|
|
969
|
+
...(state.reasoningEffort === undefined ? {} : { effort: state.reasoningEffort }),
|
|
970
|
+
outcome,
|
|
971
|
+
};
|
|
972
|
+
if (turnLedger.model !== undefined)
|
|
973
|
+
lastNotedTurnModel = turnLedger.model;
|
|
974
|
+
state.turnUsage = summary;
|
|
975
|
+
appendRow({ id: deps.rowIds.value, kind: 'turn-summary', text: '', turnUsage: summary });
|
|
976
|
+
deps.rowIds.value += 1;
|
|
977
|
+
};
|
|
978
|
+
if (reason.kind === 'completed') {
|
|
979
|
+
emitTurnSummary();
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
if (reason.kind === 'aborted' || reason.kind === 'interrupted') {
|
|
983
|
+
// A user cancel closes the turn as `aborted`; `interrupted` only
|
|
984
|
+
// appears for crash-orphaned turns. Both user-interruption paths
|
|
985
|
+
// render as a distinct dim row.
|
|
986
|
+
const backend = deps.backendLabel?.();
|
|
987
|
+
appendRow({
|
|
988
|
+
id: deps.rowIds.value,
|
|
989
|
+
kind: 'interrupt',
|
|
990
|
+
...(backend ? { interruptBackend: backend } : {}),
|
|
991
|
+
text: t('interrupted-by-user') + (backend
|
|
992
|
+
? t('interrupted-ask-backend', { name: backend })
|
|
993
|
+
: t('interrupted-ask-next')),
|
|
994
|
+
});
|
|
995
|
+
deps.rowIds.value += 1;
|
|
996
|
+
emitTurnSummary();
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
// The notice renders as a single-line Divider title: the error message
|
|
1000
|
+
// can carry newlines/control chars, and an embedded \n splits the rule
|
|
1001
|
+
// across rows. cleanRenderText is the render-path single-line contract
|
|
1002
|
+
// (sessionTree's preview() folds likewise for the tree).
|
|
1003
|
+
const label = reason.kind === 'other' ? reason.label : reason.kind;
|
|
1004
|
+
const detail = reason.kind === 'error' ? cleanRenderText(reason.message, NOTICE_CELLS) : '';
|
|
1005
|
+
appendRow({ id: deps.rowIds.value, kind: 'notice', text: `turn ${label}${detail ? ` · ${detail}` : ''}` });
|
|
1006
|
+
deps.rowIds.value += 1;
|
|
1007
|
+
emitTurnSummary();
|
|
1008
|
+
// Historical failure notices belong to the transcript row above;
|
|
1009
|
+
// re-raising them as a live toast on every /resume re-alarms the user
|
|
1010
|
+
// over a turn that already ended.
|
|
1011
|
+
if (!replaying)
|
|
1012
|
+
deps.notify(t('turn-failed', { detail: detail ? ` · ${detail}` : '' }), { color: 'error', timeoutMs: 8000 });
|
|
1013
|
+
};
|
|
1014
|
+
const applyEvent = (event) => {
|
|
1015
|
+
// The trajectory fold sees every event before the lane split: a child's
|
|
1016
|
+
// lifecycle row belongs to the parent's ledger even though its
|
|
1017
|
+
// assistant/tool traffic is skipped inside the fold (child lane).
|
|
1018
|
+
deps.trajectory?.observe(event, replaying);
|
|
1019
|
+
// A subagent's own lane (its assistant and tool traffic) belongs to its
|
|
1020
|
+
// card and panels, never to the main transcript.
|
|
1021
|
+
if (laneOf(event) !== undefined) {
|
|
1022
|
+
deps.activity?.apply(event, replaying);
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
switch (event.type) {
|
|
1026
|
+
case 'goal.change':
|
|
1027
|
+
if (event.operation === 'round') {
|
|
1028
|
+
// Admitted continuation round — the snapshot itself is unchanged.
|
|
1029
|
+
if (state.goal !== undefined && event.round !== undefined) {
|
|
1030
|
+
state.goal = {
|
|
1031
|
+
...state.goal,
|
|
1032
|
+
roundsStarted: Math.max(state.goal.roundsStarted, event.round),
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
applyGoalChange(event.operation, event.goal, event.roundsStarted);
|
|
1038
|
+
return;
|
|
1039
|
+
case 'user.message':
|
|
1040
|
+
applyUserMessage(event);
|
|
1041
|
+
return;
|
|
1042
|
+
case 'step.start':
|
|
1043
|
+
openStep = { turn: event.turn, step: event.step };
|
|
1044
|
+
if (tpsTurn === event.turn) {
|
|
1045
|
+
tpsStep = {
|
|
1046
|
+
turn: event.turn,
|
|
1047
|
+
step: event.step,
|
|
1048
|
+
firstTokenTime: undefined,
|
|
1049
|
+
outputEstimate: 0,
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
return;
|
|
1053
|
+
case 'step.end':
|
|
1054
|
+
if (openStep !== undefined && openStep.turn === event.turn && openStep.step === event.step)
|
|
1055
|
+
openStep = undefined;
|
|
1056
|
+
if (tpsStep !== undefined &&
|
|
1057
|
+
tpsStep.turn === event.turn &&
|
|
1058
|
+
tpsStep.step === event.step) {
|
|
1059
|
+
tpsStep = undefined;
|
|
1060
|
+
}
|
|
1061
|
+
return;
|
|
1062
|
+
case 'assistant.attempt.start':
|
|
1063
|
+
// Start owns the attempt's (turn, step); a superseded attempt that
|
|
1064
|
+
// never settled loses its provisional rows.
|
|
1065
|
+
if (activeAttempt !== undefined) {
|
|
1066
|
+
// Capture before discardAttempt: clearing the superseded attempt's
|
|
1067
|
+
// rows also clears the `activeAttempt` ref itself (its last line).
|
|
1068
|
+
const superseded = activeAttempt.attemptId;
|
|
1069
|
+
discardAttempt(activeAttempt.turn, activeAttempt.step);
|
|
1070
|
+
// The superseded attempt failed mid-flight (an API retry opens the
|
|
1071
|
+
// replacement): it counts toward the turn's retry tally.
|
|
1072
|
+
turnFailedAttempts.add(superseded);
|
|
1073
|
+
}
|
|
1074
|
+
activeAttempt = { attemptId: event.attemptId, turn: event.turn, step: event.step };
|
|
1075
|
+
// A backend's output-start signal includes generation hidden from
|
|
1076
|
+
// text deltas. Replay has no reliable per-item decode timing.
|
|
1077
|
+
if (!replaying && event.firstTokenTime !== undefined && tpsStep?.turn === event.turn && tpsStep.step === event.step) {
|
|
1078
|
+
tpsStep.firstTokenTime ??= event.firstTokenTime;
|
|
1079
|
+
}
|
|
1080
|
+
return;
|
|
1081
|
+
case 'assistant.attempt.end':
|
|
1082
|
+
// A positioned end is a durable record of a failed attempt: drop that
|
|
1083
|
+
// step's provisional rows whether or not a live attempt matched.
|
|
1084
|
+
if (event.turn !== undefined && event.step !== undefined) {
|
|
1085
|
+
if (event.outcome !== 'committed')
|
|
1086
|
+
turnFailedAttempts.add(event.attemptId);
|
|
1087
|
+
discardAttempt(event.turn, event.step);
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
// Settlement owns the text; an abandoned end must discard provisional
|
|
1091
|
+
// rows even when no durable event was written.
|
|
1092
|
+
if (activeAttempt?.attemptId !== event.attemptId)
|
|
1093
|
+
return;
|
|
1094
|
+
if (event.outcome !== 'committed') {
|
|
1095
|
+
turnFailedAttempts.add(activeAttempt.attemptId);
|
|
1096
|
+
discardAttempt(activeAttempt.turn, activeAttempt.step);
|
|
1097
|
+
}
|
|
1098
|
+
activeAttempt = undefined;
|
|
1099
|
+
return;
|
|
1100
|
+
case 'assistant.delta':
|
|
1101
|
+
if (event.seq !== undefined) {
|
|
1102
|
+
// Positioned legacy delta: its own durable (turn, step), deduplicated
|
|
1103
|
+
// by seq (a reconnect may replay the same durable chunk).
|
|
1104
|
+
if (handledAssistantChunks.has(event.seq))
|
|
1105
|
+
return;
|
|
1106
|
+
handledAssistantChunks.add(event.seq);
|
|
1107
|
+
renderStreamDelta(event.turn, event.step, event.delta, event.time, event.seq);
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
// A reattach rebuilds the attempt's (turn, step) from the open
|
|
1111
|
+
// durable step when its start was missed.
|
|
1112
|
+
if (activeAttempt === undefined && openStep !== undefined) {
|
|
1113
|
+
activeAttempt = { attemptId: event.attemptId, ...openStep };
|
|
1114
|
+
}
|
|
1115
|
+
if (activeAttempt?.attemptId !== event.attemptId)
|
|
1116
|
+
return;
|
|
1117
|
+
renderStreamDelta(activeAttempt.turn, activeAttempt.step, event.delta, event.time);
|
|
1118
|
+
return;
|
|
1119
|
+
case 'assistant.message':
|
|
1120
|
+
applyAssistantMessage(event);
|
|
1121
|
+
return;
|
|
1122
|
+
case 'usage':
|
|
1123
|
+
if (handledUsage.has(event.seq))
|
|
1124
|
+
return;
|
|
1125
|
+
handledUsage.add(event.seq);
|
|
1126
|
+
bookUsage(event.usage, event);
|
|
1127
|
+
// A late real report (Codex meters after the reply settles) names the
|
|
1128
|
+
// step it describes: replace that step's estimate in the turn fold so
|
|
1129
|
+
// the live tps and the turn-end sample read real tokens, not a guess.
|
|
1130
|
+
// The same swap also serves the LAST ended turn (a straggler after
|
|
1131
|
+
// turn.end corrects the readout and the pushed sample in place).
|
|
1132
|
+
const real = usageOutputTokens(event.usage);
|
|
1133
|
+
const swap = (steps, decodeMs) => {
|
|
1134
|
+
const target = steps.find(step => step.step === event.step && step.estimated);
|
|
1135
|
+
if (target === undefined || real === undefined)
|
|
1136
|
+
return undefined;
|
|
1137
|
+
target.tokens = real;
|
|
1138
|
+
target.estimated = false;
|
|
1139
|
+
return steps.reduce((sum, step) => sum + step.tokens, 0);
|
|
1140
|
+
};
|
|
1141
|
+
if (real !== undefined && tpsTurn === event.turn) {
|
|
1142
|
+
const total = swap(tpsTurnSteps, tpsTurnDecodeMs);
|
|
1143
|
+
if (total !== undefined) {
|
|
1144
|
+
tpsTurnDecodeTokens = total;
|
|
1145
|
+
tpsTurnSampled = true;
|
|
1146
|
+
if (tpsTurnDecodeMs > 0)
|
|
1147
|
+
state.tps = total / (tpsTurnDecodeMs / 1000);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
else if (real !== undefined && tpsClosedTurn?.turn === event.turn) {
|
|
1151
|
+
const total = swap(tpsClosedTurn.steps, tpsClosedTurn.decodeMs);
|
|
1152
|
+
if (total !== undefined && tpsClosedTurn.decodeMs > 0) {
|
|
1153
|
+
state.tps = total / (tpsClosedTurn.decodeMs / 1000);
|
|
1154
|
+
if (tpsClosedTurn.sample === undefined) {
|
|
1155
|
+
tpsClosedTurn.sample = { tps: state.tps, at: tpsClosedTurn.endAt };
|
|
1156
|
+
state.tpsSamples.push(tpsClosedTurn.sample);
|
|
1157
|
+
if (state.tpsSamples.length > 500)
|
|
1158
|
+
state.tpsSamples.shift();
|
|
1159
|
+
}
|
|
1160
|
+
else {
|
|
1161
|
+
tpsClosedTurn.sample.tps = state.tps;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
return;
|
|
1166
|
+
case 'tool.call':
|
|
1167
|
+
applyToolCall(event);
|
|
1168
|
+
return;
|
|
1169
|
+
case 'tool.result':
|
|
1170
|
+
applyToolResult(event);
|
|
1171
|
+
return;
|
|
1172
|
+
case 'tool.output':
|
|
1173
|
+
applyToolOutput(event);
|
|
1174
|
+
return;
|
|
1175
|
+
case 'task.output':
|
|
1176
|
+
// A `job_output`-style read doubles as the job card's output feed:
|
|
1177
|
+
// the registry's read is consuming and reserved for the owning
|
|
1178
|
+
// agent, so the UI mirrors the tail that already streams through
|
|
1179
|
+
// the transcript instead of polling the job itself.
|
|
1180
|
+
// oxlint-disable-next-line typescript/no-unnecessary-condition -- durable replay data may lack a time
|
|
1181
|
+
if (taskFeedAdmitted(event.callId))
|
|
1182
|
+
deps.jobs.onOutputSeen(event.taskId, event.text, event.time ?? Date.now());
|
|
1183
|
+
deps.activity?.apply(event, replaying);
|
|
1184
|
+
return;
|
|
1185
|
+
case 'task.start':
|
|
1186
|
+
// A background-start ack pairs the job with its tool call and gives
|
|
1187
|
+
// the full command (the registry label is the friendly description).
|
|
1188
|
+
if (event.command !== undefined && taskFeedAdmitted(event.callId))
|
|
1189
|
+
deps.jobs.onStarted(event.taskId, event.command);
|
|
1190
|
+
deps.activity?.apply(event, replaying);
|
|
1191
|
+
return;
|
|
1192
|
+
case 'subagent.start':
|
|
1193
|
+
case 'subagent.progress':
|
|
1194
|
+
case 'subagent.end':
|
|
1195
|
+
case 'task.update':
|
|
1196
|
+
case 'task.end':
|
|
1197
|
+
case 'tasks.snapshot':
|
|
1198
|
+
deps.activity?.apply(event, replaying);
|
|
1199
|
+
return;
|
|
1200
|
+
case 'turn.start':
|
|
1201
|
+
deps.inputConvergence.cancelInFlight = false;
|
|
1202
|
+
state.cancelPending = false;
|
|
1203
|
+
state.working = true;
|
|
1204
|
+
state.turnStart = Date.now();
|
|
1205
|
+
state.responseChars = 0;
|
|
1206
|
+
state.spinnerMode = 'requesting';
|
|
1207
|
+
// Fresh turn ledger: the previous turn's summary stays on
|
|
1208
|
+
// `state.turnUsage` (the footer reads it) while this one accrues.
|
|
1209
|
+
turnLedger.input = 0;
|
|
1210
|
+
turnLedger.output = 0;
|
|
1211
|
+
turnLedger.cacheRead = 0;
|
|
1212
|
+
turnLedger.cacheWrite = 0;
|
|
1213
|
+
turnLedger.cacheKnown = false;
|
|
1214
|
+
turnLedger.usageSeen = false;
|
|
1215
|
+
turnLedger.startedAt = event.time;
|
|
1216
|
+
turnLedger.model = undefined;
|
|
1217
|
+
turnFailedAttempts.clear();
|
|
1218
|
+
// Keep the prior turn visible until this turn produces a measurable
|
|
1219
|
+
// decode span, while starting a fresh weighted step fold.
|
|
1220
|
+
tpsBeforeTurn = state.tps;
|
|
1221
|
+
tpsTurn = event.turn;
|
|
1222
|
+
tpsTurnDecodeMs = 0;
|
|
1223
|
+
tpsTurnDecodeTokens = 0;
|
|
1224
|
+
tpsTurnSampled = false;
|
|
1225
|
+
tpsStep = undefined;
|
|
1226
|
+
tpsTurnSteps = [];
|
|
1227
|
+
tpsClosedTurn = undefined;
|
|
1228
|
+
return;
|
|
1229
|
+
case 'turn.end':
|
|
1230
|
+
applyTurnEnd(event);
|
|
1231
|
+
// A foreground subagent cannot outlive its turn (./activity.ts).
|
|
1232
|
+
deps.activity?.apply(event, replaying);
|
|
1233
|
+
return;
|
|
1234
|
+
case 'context.usage':
|
|
1235
|
+
contextUsage = event;
|
|
1236
|
+
if (!replaying)
|
|
1237
|
+
deps.checkContextWarning();
|
|
1238
|
+
return;
|
|
1239
|
+
case 'context.capacity':
|
|
1240
|
+
// Backend-advertised context capacity; drives the context-low warning.
|
|
1241
|
+
state.contextWindow = event.contextWindow;
|
|
1242
|
+
return;
|
|
1243
|
+
case 'session.ready':
|
|
1244
|
+
// The backend's own account of the session it opened: the model it
|
|
1245
|
+
// actually runs (status line) and its context window when known.
|
|
1246
|
+
if (event.model !== '')
|
|
1247
|
+
state.model = event.model;
|
|
1248
|
+
if (event.contextWindow !== undefined)
|
|
1249
|
+
state.contextWindow = event.contextWindow;
|
|
1250
|
+
return;
|
|
1251
|
+
case 'model.changed':
|
|
1252
|
+
if (event.model !== '')
|
|
1253
|
+
state.model = event.model;
|
|
1254
|
+
return;
|
|
1255
|
+
case 'effort.changed':
|
|
1256
|
+
// Backend-set effort (`/effort` on the Claude backend; DSH arrives
|
|
1257
|
+
// per request via `request.header` instead). `null` = cleared back
|
|
1258
|
+
// to the backend default.
|
|
1259
|
+
state.reasoningEffort = event.effort ?? undefined;
|
|
1260
|
+
return;
|
|
1261
|
+
case 'system.prompt':
|
|
1262
|
+
// The latest system prompt holds the active instructions (an empty
|
|
1263
|
+
// render clears them); the context bar's system segment tracks it.
|
|
1264
|
+
state.contextSegments.system = estimateTokens(event.text);
|
|
1265
|
+
return;
|
|
1266
|
+
case 'request.header':
|
|
1267
|
+
// Reasoning effort readout (status line) from the call config.
|
|
1268
|
+
if (event.effort !== undefined)
|
|
1269
|
+
state.reasoningEffort = event.effort;
|
|
1270
|
+
// 该请求的 usage 按这里的 model 计价(replay 时逐请求还原;live 时
|
|
1271
|
+
// 与 state.model 同步更新)。header 缺/空 model 时也要清掉上一条
|
|
1272
|
+
// header 的值,否则后续 usage 会沿用旧模型进错桶;归属时再回退
|
|
1273
|
+
// state.model(旧日志没有 header 时就是这样)。
|
|
1274
|
+
eventModel = event.model;
|
|
1275
|
+
return;
|
|
1276
|
+
case 'session.title':
|
|
1277
|
+
state.sessionTitle = event.title;
|
|
1278
|
+
return;
|
|
1279
|
+
case 'session.color':
|
|
1280
|
+
// `/color` accent, replayed on resume/rewind like the title: last
|
|
1281
|
+
// write wins, '' clears to the default.
|
|
1282
|
+
state.sessionColor = event.color;
|
|
1283
|
+
return;
|
|
1284
|
+
case 'todo.write':
|
|
1285
|
+
// The snapshot array is adopted as-is (the durable record owns it).
|
|
1286
|
+
state.todos = event.items;
|
|
1287
|
+
return;
|
|
1288
|
+
case 'preset.selected': {
|
|
1289
|
+
// A transcript marker so a replayed log shows which composition
|
|
1290
|
+
// produced the turns after it. A recording under an alias of the
|
|
1291
|
+
// current preset shows the current spelling.
|
|
1292
|
+
const current = state.agentPreset;
|
|
1293
|
+
// `aliases` crosses a backend boundary: only a real array is trusted
|
|
1294
|
+
// (a translator bug must not turn a marker into a projector throw).
|
|
1295
|
+
const aliases = event.aliases;
|
|
1296
|
+
const preset = current !== undefined && Array.isArray(aliases) && aliases.includes(current) ? current : event.preset;
|
|
1297
|
+
appendRow({
|
|
1298
|
+
id: deps.rowIds.value,
|
|
1299
|
+
kind: 'notice',
|
|
1300
|
+
text: t('agent-preset-switched', { preset }),
|
|
1301
|
+
});
|
|
1302
|
+
deps.rowIds.value += 1;
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
case 'compaction.start':
|
|
1306
|
+
// Opening the bracket here rather than in the manual path is what
|
|
1307
|
+
// makes an automatic pressure compaction visible too. A manual
|
|
1308
|
+
// request already installed its own cancellable row, so this only
|
|
1309
|
+
// fills the gap for one this process did not start. Replay is settled
|
|
1310
|
+
// history, and a process killed between start and end leaves an
|
|
1311
|
+
// unmatched start in the log: painting a row for it would show a
|
|
1312
|
+
// compaction that nothing will ever clear.
|
|
1313
|
+
if (!replaying && state.compaction === undefined) {
|
|
1314
|
+
state.compaction = {
|
|
1315
|
+
// oxlint-disable-next-line typescript/no-unnecessary-condition -- durable replay data may lack a time
|
|
1316
|
+
startedAt: typeof event.time === 'number' ? event.time : Date.now(),
|
|
1317
|
+
phase: 'prefill',
|
|
1318
|
+
outputChars: 0,
|
|
1319
|
+
cancellable: event.cancellable,
|
|
1320
|
+
};
|
|
1321
|
+
}
|
|
1322
|
+
return;
|
|
1323
|
+
case 'compaction.progress': {
|
|
1324
|
+
const compaction = state.compaction;
|
|
1325
|
+
if (compaction !== undefined) {
|
|
1326
|
+
state.compaction = {
|
|
1327
|
+
...compaction,
|
|
1328
|
+
phase: 'summary',
|
|
1329
|
+
outputChars: compaction.outputChars + event.outputChars,
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
case 'compaction.end':
|
|
1335
|
+
state.compaction = undefined;
|
|
1336
|
+
// A confirmed replacement without a checkpoint (Codex) invalidates
|
|
1337
|
+
// the old composition. Hosts that only bracket the attempt omit this
|
|
1338
|
+
// signal; their recorded checkpoint owns the reset.
|
|
1339
|
+
if (event.ok && event.contextReplaced === true) {
|
|
1340
|
+
state.contextSegments = {
|
|
1341
|
+
system: state.contextSegments.system,
|
|
1342
|
+
prompt: estimateTokens(event.summary ?? ''),
|
|
1343
|
+
assistant: 0,
|
|
1344
|
+
thinking: 0,
|
|
1345
|
+
tools: 0,
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
// A backend that measured the compacted window (Claude
|
|
1349
|
+
// `compact_boundary.post_tokens`) re-seeds the occupancy sample with
|
|
1350
|
+
// it: a compaction turn makes no request, so without this the
|
|
1351
|
+
// fallback reading would keep the pre-compact size until the next
|
|
1352
|
+
// turn. DSH reports no `postTokens` (its token meter owns occupancy).
|
|
1353
|
+
if (event.ok && event.postTokens !== undefined) {
|
|
1354
|
+
state.lastUsage = { input: event.postTokens, output: 0, cacheRead: 0, cacheWrite: 0, at: event.time };
|
|
1355
|
+
}
|
|
1356
|
+
return;
|
|
1357
|
+
case 'custom': {
|
|
1358
|
+
// Custom plugin events (tuiRenderers seam): a registered renderer maps
|
|
1359
|
+
// the payload to text rows: title as a local row, body as
|
|
1360
|
+
// preview-clipped local-output rows, same shape pushLocal uses. Runs
|
|
1361
|
+
// on the live stream and on replay (resume/rewind), so the projection
|
|
1362
|
+
// must stay total; the runtime isolates renderer crashes per type.
|
|
1363
|
+
if (deps.renderer === undefined)
|
|
1364
|
+
return;
|
|
1365
|
+
const rendered = deps.renderer.render(event.nativeType, event.data);
|
|
1366
|
+
if (rendered === undefined)
|
|
1367
|
+
return;
|
|
1368
|
+
if (rendered.title !== undefined && rendered.title !== '') {
|
|
1369
|
+
appendRow({ id: deps.rowIds.value, kind: 'local', text: rendered.title });
|
|
1370
|
+
deps.rowIds.value += 1;
|
|
1371
|
+
}
|
|
1372
|
+
for (const line of rendered.lines) {
|
|
1373
|
+
appendRow({
|
|
1374
|
+
id: deps.rowIds.value,
|
|
1375
|
+
kind: 'local-output',
|
|
1376
|
+
text: preview(String(line), LOCAL_OUTPUT_LIMIT),
|
|
1377
|
+
});
|
|
1378
|
+
deps.rowIds.value += 1;
|
|
1379
|
+
}
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
case 'notice': {
|
|
1383
|
+
// A backend notice: `info` is a transcript fact (a dim notice row);
|
|
1384
|
+
// `notice` is a passing toast; `warning`/`error` are both: the row
|
|
1385
|
+
// keeps the explanation next to the work it concerns, the toast makes
|
|
1386
|
+
// sure it is seen. Replay repaints rows only, never toasts.
|
|
1387
|
+
//
|
|
1388
|
+
// A `key` dedupes repeats of one condition (an API retry counting
|
|
1389
|
+
// up, a limit warning): its toast replaces the key's previous toast,
|
|
1390
|
+
// and its row is updated in place while that row is still the last
|
|
1391
|
+
// one (once other rows follow, a new row keeps the history in order).
|
|
1392
|
+
const text = cleanRenderText(event.text, NOTICE_CELLS);
|
|
1393
|
+
if (text === '')
|
|
1394
|
+
return;
|
|
1395
|
+
if (event.level !== 'notice') {
|
|
1396
|
+
const last = state.rows.at(-1);
|
|
1397
|
+
if (event.key !== undefined && keyedNoticeRow?.key === event.key && last !== undefined && last === keyedNoticeRow.row) {
|
|
1398
|
+
last.text = text;
|
|
1399
|
+
touchRow(last);
|
|
1400
|
+
}
|
|
1401
|
+
else {
|
|
1402
|
+
const row = { id: deps.rowIds.value, kind: 'notice', text };
|
|
1403
|
+
appendRow(row);
|
|
1404
|
+
deps.rowIds.value += 1;
|
|
1405
|
+
keyedNoticeRow = event.key === undefined ? undefined : { key: event.key, row };
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
if (!replaying && event.level !== 'info') {
|
|
1409
|
+
if (event.key !== undefined)
|
|
1410
|
+
keyedToasts.get(event.key)?.();
|
|
1411
|
+
const dismiss = deps.notify(text, event.level === 'notice' ? { timeoutMs: 4000 } : { color: event.level, timeoutMs: 8000 });
|
|
1412
|
+
if (event.key !== undefined) {
|
|
1413
|
+
keyedToasts.delete(event.key);
|
|
1414
|
+
keyedToasts.set(event.key, dismiss);
|
|
1415
|
+
// Bounded: keys are per condition (a call, a tool use).
|
|
1416
|
+
for (const stale of keyedToasts.keys()) {
|
|
1417
|
+
if (keyedToasts.size <= MAX_KEYED_TOASTS)
|
|
1418
|
+
break;
|
|
1419
|
+
keyedToasts.delete(stale);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
return;
|
|
1424
|
+
}
|
|
1425
|
+
// Owned outside the transcript reducer: session status and pending
|
|
1426
|
+
// inputs by the channel binding, permissions/questions by their stores,
|
|
1427
|
+
// and agent-message observations by the activity projection.
|
|
1428
|
+
case 'agent.message':
|
|
1429
|
+
deps.activity?.apply(event, replaying);
|
|
1430
|
+
return;
|
|
1431
|
+
case 'session.reset':
|
|
1432
|
+
case 'session.status':
|
|
1433
|
+
case 'pending.changed':
|
|
1434
|
+
case 'tool.progress':
|
|
1435
|
+
case 'permission.request':
|
|
1436
|
+
case 'permission.settled':
|
|
1437
|
+
case 'question.request':
|
|
1438
|
+
case 'question.settled':
|
|
1439
|
+
case 'effort.changed':
|
|
1440
|
+
case 'mode.changed':
|
|
1441
|
+
case 'commands.changed':
|
|
1442
|
+
case 'rate-limit':
|
|
1443
|
+
return;
|
|
1444
|
+
default: {
|
|
1445
|
+
// Exhaustiveness: a new AgentEvent variant must be handled above.
|
|
1446
|
+
const unhandled = event;
|
|
1447
|
+
void unhandled;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
};
|
|
1451
|
+
/**
|
|
1452
|
+
* Fold one batch. A `replay` batch is one complete history pass: sequence
|
|
1453
|
+
* numbers restart with a replacement session, so the idempotency ledgers
|
|
1454
|
+
* and step/attempt bindings reset before it (an old session must not
|
|
1455
|
+
* suppress a legitimate message in the new transcript), and it paints
|
|
1456
|
+
* settled history (no live toasts, no smooth reveal, no unmatched
|
|
1457
|
+
* compaction row).
|
|
1458
|
+
*/
|
|
1459
|
+
const apply = (events, meta) => {
|
|
1460
|
+
if (!meta.replay) {
|
|
1461
|
+
for (const event of events)
|
|
1462
|
+
applyEvent(event);
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1465
|
+
handledAssistantMessages.clear();
|
|
1466
|
+
handledUsage.clear();
|
|
1467
|
+
contextUsage = undefined;
|
|
1468
|
+
handledAssistantChunks.clear();
|
|
1469
|
+
openStep = undefined;
|
|
1470
|
+
activeAttempt = undefined;
|
|
1471
|
+
eventModel = undefined;
|
|
1472
|
+
assistantRowsByStep.clear();
|
|
1473
|
+
lastTextDelta.clear();
|
|
1474
|
+
// Rows still on screen when a replay starts keep matching by seq, so a
|
|
1475
|
+
// replay over painted history reuses them instead of duplicating them.
|
|
1476
|
+
assistantRowsBySeq.clear();
|
|
1477
|
+
for (const row of state.rows)
|
|
1478
|
+
if (row.kind === 'assistant')
|
|
1479
|
+
indexAssistantRow(row);
|
|
1480
|
+
replaying = true;
|
|
1481
|
+
try {
|
|
1482
|
+
for (const event of events)
|
|
1483
|
+
applyEvent(event);
|
|
1484
|
+
}
|
|
1485
|
+
finally {
|
|
1486
|
+
replaying = false;
|
|
1487
|
+
}
|
|
1488
|
+
};
|
|
1489
|
+
/** Forget every per-session projection ledger (adoption, `/clear`). */
|
|
1490
|
+
function reset() {
|
|
1491
|
+
keyedNoticeRow = undefined;
|
|
1492
|
+
streaming = undefined;
|
|
1493
|
+
reasoning = undefined;
|
|
1494
|
+
sealedReasoning.length = 0;
|
|
1495
|
+
lastReasoningRow = undefined;
|
|
1496
|
+
toolCards.clear();
|
|
1497
|
+
liveTails.clear();
|
|
1498
|
+
askCalls.clear();
|
|
1499
|
+
todoCalls.clear();
|
|
1500
|
+
settledCardCallId = undefined;
|
|
1501
|
+
handledAssistantMessages.clear();
|
|
1502
|
+
handledUsage.clear();
|
|
1503
|
+
contextUsage = undefined;
|
|
1504
|
+
handledAssistantChunks.clear();
|
|
1505
|
+
openStep = undefined;
|
|
1506
|
+
activeAttempt = undefined;
|
|
1507
|
+
eventModel = undefined;
|
|
1508
|
+
assistantRowsByStep.clear();
|
|
1509
|
+
assistantRowsBySeq.clear();
|
|
1510
|
+
lastTextDelta.clear();
|
|
1511
|
+
lastNotedTurnModel = undefined;
|
|
1512
|
+
tpsTurn = undefined;
|
|
1513
|
+
tpsStep = undefined;
|
|
1514
|
+
tpsTurnSteps = [];
|
|
1515
|
+
tpsClosedTurn = undefined;
|
|
1516
|
+
tpsTurnDecodeMs = 0;
|
|
1517
|
+
tpsTurnDecodeTokens = 0;
|
|
1518
|
+
tpsTurnSampled = false;
|
|
1519
|
+
}
|
|
1520
|
+
return { apply, reset, settleStreaming, updateSpinnerMode, contextUsage: () => contextUsage };
|
|
1521
|
+
}
|