mixdog 1.2.1 → 1.2.3
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 +18 -0
- package/package.json +2 -1
- package/scripts/gate-local.mjs +19 -3
- package/scripts/model-catalog-audit.mjs +1 -15
- package/scripts/provider-pingpong-live.mjs +509 -0
- package/src/agents/advisor/AGENT.md +1 -1
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/reviewer/AGENT.md +3 -3
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +6 -0
- package/src/defaults/skills/setup/SKILL.md +6 -1
- package/src/defaults/skills/setup/references/actions.md +44 -22
- package/src/defaults/skills/setup/references/surfaces.md +10 -8
- package/src/headless-exec.mjs +15 -8
- package/src/lib/keychain-cjs.cjs +7 -4
- package/src/output-styles/common.md +11 -10
- package/src/repl/slash-commands.mjs +16 -1
- package/src/rules/agent/AGENT.md +5 -5
- package/src/rules/lead/LEAD.md +5 -5
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
- package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
- package/src/runtime/agent/orchestrator/config.mjs +5 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +36 -7
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +49 -10
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +40 -3
- package/src/runtime/agent/orchestrator/mcp/client.mjs +230 -96
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +188 -29
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +98 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +48 -37
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +10 -7
- package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +102 -45
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +40 -7
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +88 -21
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +30 -10
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +106 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +94 -15
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
- package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +75 -10
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +103 -23
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +32 -6
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +27 -3
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
- package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
- package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +80 -18
- package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +46 -8
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +273 -0
- package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +369 -112
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +140 -35
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +70 -24
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +80 -29
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +69 -19
- package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
- package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
- package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
- package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
- package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +123 -61
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +27 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +64 -23
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +79 -33
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +144 -15
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +109 -26
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +27 -6
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +34 -20
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +23 -4
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +37 -28
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +43 -15
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +7 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
- package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +37 -4
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +12 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +12 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +76 -33
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
- package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
- package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
- package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +41 -22
- package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
- package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +720 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +123 -219
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
- package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
- package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
- package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
- package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
- package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
- package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
- package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
- package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
- package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -97
- package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
- package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
- package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
- package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
- package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
- package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
- package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +104 -19
- package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +30 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +57 -21
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +5 -10
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +16 -4
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
- package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +168 -29
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
- package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
- package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
- package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
- package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +20 -1
- package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
- package/src/runtime/computer-bridge/action-schema.mjs +44 -21
- package/src/runtime/github/tool.mjs +92 -2
- package/src/runtime/memory/index.mjs +1 -0
- package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
- package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
- package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
- package/src/runtime/memory/lib/pg/process.mjs +65 -50
- package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +124 -16
- package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
- package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
- package/src/runtime/office/README.md +2 -2
- package/src/runtime/office/authoring/html-document-author.mjs +2 -0
- package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
- package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
- package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
- package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
- package/src/runtime/office/core/office-actions-read.mjs +3 -0
- package/src/runtime/office/core/office-render-preview.mjs +2 -0
- package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
- package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
- package/src/runtime/office/core/office-sessions.mjs +5 -0
- package/src/runtime/office/core/office-transactions.mjs +3 -0
- package/src/runtime/office/core/office-write-ledger.mjs +98 -0
- package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
- package/src/runtime/office/index.mjs +30 -0
- package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
- package/src/runtime/office/pdf/pdf-render.mjs +23 -7
- package/src/runtime/office/pdf/pdf-security.mjs +2 -0
- package/src/runtime/office/portable/portable-opc.mjs +4 -1
- package/src/runtime/office/quality/visual-diff.mjs +2 -0
- package/src/runtime/office/shared/values.mjs +0 -5
- package/src/runtime/shared/background-tasks.mjs +92 -14
- package/src/runtime/shared/bounded-file-read.mjs +13 -0
- package/src/runtime/shared/bounded-line-diff.mjs +182 -0
- package/src/runtime/shared/buffered-appender.mjs +18 -0
- package/src/runtime/shared/config.mjs +78 -18
- package/src/runtime/shared/err-text.mjs +31 -0
- package/src/runtime/shared/error-presentation.mjs +159 -19
- package/src/runtime/shared/file-permissions.d.mts +6 -1
- package/src/runtime/shared/file-permissions.mjs +54 -6
- package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
- package/src/runtime/shared/llm/anthropic-effort.mjs +129 -134
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
- package/src/runtime/shared/llm/model-catalog.mjs +53 -40
- package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +11 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
- package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
- package/src/runtime/shared/loopback-listener.mjs +9 -0
- package/src/runtime/shared/model-display.mjs +13 -0
- package/src/runtime/shared/provider-api-key.mjs +2 -0
- package/src/runtime/shared/quota-resume-store.mjs +11 -0
- package/src/runtime/shared/review-diff.mjs +52 -0
- package/src/runtime/shared/session-baseline-store.mjs +960 -0
- package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
- package/src/runtime/shared/session-sidebar-host.mjs +38 -0
- package/src/runtime/shared/slow-span.mjs +114 -0
- package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
- package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
- package/src/runtime/shared/task-notification-envelope.mjs +2 -2
- package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
- package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
- package/src/runtime/shared/tool-card-model.mjs +5 -2
- package/src/runtime/shared/tool-output-limit.mjs +4 -0
- package/src/runtime/shared/tool-primitives.mjs +13 -0
- package/src/runtime/shared/tool-result-summary.mjs +8 -1
- package/src/runtime/shared/tool-surface.mjs +18 -3
- package/src/runtime/shared/tool-work-units.mjs +40 -4
- package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
- package/src/runtime/shared/transcript-writer.mjs +10 -2
- package/src/runtime/shared/turn-changes.mjs +670 -274
- package/src/runtime/shared/turn-review-reply.mjs +8 -39
- package/src/runtime/shared/turn-snapshot-store.mjs +94 -2
- package/src/runtime/shared/turn-snapshot.mjs +986 -690
- package/src/runtime/shared/turn-worktree-snapshot.mjs +279 -262
- package/src/runtime/shared/user-data-guard.mjs +262 -49
- package/src/runtime/shared/worktrees/carry.mjs +531 -0
- package/src/runtime/shared/worktrees/contract.mjs +34 -24
- package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
- package/src/runtime/shared/worktrees/git-head.mjs +205 -0
- package/src/runtime/shared/worktrees/git.mjs +8 -3
- package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
- package/src/runtime/shared/worktrees/manager.mjs +156 -8
- package/src/runtime/shared/worktrees/merge.mjs +31 -21
- package/src/runtime/shared/worktrees/paths.d.mts +6 -0
- package/src/runtime/shared/worktrees/test-support.mjs +19 -4
- package/src/runtime/terminal-bridge/client.mjs +44 -11
- package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
- package/src/runtime/tidy/apply.mjs +47 -2
- package/src/runtime/tidy/run-engines.mjs +11 -5
- package/src/session-runtime/agent-tool-routing.mjs +19 -13
- package/src/session-runtime/boot/apis.mjs +19 -5
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/infrastructure.mjs +12 -1
- package/src/session-runtime/boot/session.mjs +0 -1
- package/src/session-runtime/boot/tools.mjs +4 -1
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
- package/src/session-runtime/internal-tool-executor.mjs +6 -2
- package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
- package/src/session-runtime/lifecycle/session-catalog.mjs +14 -3
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
- package/src/session-runtime/lifecycle/teardown.mjs +73 -8
- package/src/session-runtime/lifecycle-api.mjs +1 -0
- package/src/session-runtime/mcp-glue/connect.mjs +46 -14
- package/src/session-runtime/mcp-glue/server-catalog.mjs +20 -3
- package/src/session-runtime/mcp-glue.mjs +3 -0
- package/src/session-runtime/mcp-oauth-login.mjs +174 -0
- package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
- package/src/session-runtime/model-route/set-route.mjs +85 -17
- package/src/session-runtime/model-route/web-search-route.mjs +1 -1
- package/src/session-runtime/native-web-search/routes.mjs +22 -3
- package/src/session-runtime/native-web-search-usage.mjs +51 -0
- package/src/session-runtime/native-web-search.mjs +10 -1
- package/src/session-runtime/new-session-config.mjs +4 -2
- package/src/session-runtime/provider-auth/login.mjs +4 -0
- package/src/session-runtime/provider-models/model-meta.mjs +12 -3
- package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
- package/src/session-runtime/quick-web-search-models.mjs +13 -38
- package/src/session-runtime/resource-extension-sync.mjs +4 -0
- package/src/session-runtime/resource-mcp-api.mjs +98 -2
- package/src/session-runtime/resource-scope-decorate.mjs +10 -3
- package/src/session-runtime/runtime-review-api.mjs +21 -2
- package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
- package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
- package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
- package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
- package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
- package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
- package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
- package/src/session-runtime/services/agent-tool.mjs +3 -0
- package/src/session-runtime/services/channel-admin.mjs +19 -3
- package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
- package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
- package/src/session-runtime/services/provider-admin.mjs +81 -15
- package/src/session-runtime/session-transcript-purge.mjs +32 -0
- package/src/session-runtime/session-turn-api.mjs +14 -5
- package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
- package/src/session-runtime/settings-compaction-api.mjs +1 -0
- package/src/session-runtime/setup-tool/executor.mjs +36 -6
- package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
- package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
- package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
- package/src/session-runtime/skills-api.mjs +3 -5
- package/src/session-runtime/tool-surface.mjs +5 -1
- package/src/session-runtime/turn/compaction-gate.mjs +25 -0
- package/src/session-runtime/turn/session-ops.mjs +7 -5
- package/src/session-runtime/turn/side-question-ops.mjs +22 -0
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
- package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +25 -9
- package/src/session-runtime/usage-stats-api.mjs +43 -11
- package/src/session-runtime/workspace/project-branches.mjs +7 -5
- package/src/session-runtime/workspace/transition-steps.mjs +129 -31
- package/src/session-runtime/workspace/transitions.mjs +190 -15
- package/src/standalone/daemon-agent-control.mjs +9 -1
- package/src/standalone/daemon-drain-policy.mjs +8 -0
- package/src/standalone/daemon-local-session-bridge.mjs +14 -1
- package/src/standalone/daemon-owner.mjs +17 -4
- package/src/standalone/daemon-pg-stop.mjs +51 -0
- package/src/standalone/daemon-stop-budget.d.mts +2 -0
- package/src/standalone/daemon-stop-budget.mjs +18 -0
- package/src/standalone/daemon-stored-session-views.mjs +2 -0
- package/src/standalone/daemon-telemetry.mjs +74 -0
- package/src/standalone/daemon.mjs +64 -8
- package/src/standalone/desktop-service-registry.mjs +5 -0
- package/src/standalone/local-session-runtime.mjs +70 -19
- package/src/standalone/session-client.mjs +42 -0
- package/src/standalone/session-protocol.mjs +14 -0
- package/src/standalone/session-proxy/projection.mjs +41 -4
- package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
- package/src/standalone/session-runtime-inline-host.mjs +1 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
- package/src/standalone/session-service/agent-tree.mjs +12 -0
- package/src/standalone/session-service/quota-resume.mjs +8 -0
- package/src/standalone/session-service/retention/busy.mjs +15 -1
- package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
- package/src/standalone/session-service-api.mjs +11 -1
- package/src/standalone/session-service.mjs +1 -0
- package/src/standalone/session-state-patch.d.mts +2 -1
- package/src/standalone/session-state-patch.mjs +41 -1
- package/src/tui/App.jsx +25 -0
- package/src/tui/app/app-view/floating-panel.jsx +26 -1
- package/src/tui/app/app-view.jsx +1 -0
- package/src/tui/app/btw-controller.mjs +118 -0
- package/src/tui/app/create-app-pickers.mjs +6 -0
- package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
- package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
- package/src/tui/app/extension-pickers.mjs +2 -1
- package/src/tui/app/model-options.mjs +11 -16
- package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
- package/src/tui/app/shell-layout/surfaces.mjs +3 -1
- package/src/tui/app/slash-commands.mjs +20 -5
- package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
- package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
- package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
- package/src/tui/app/use-global-key-input.mjs +5 -12
- package/src/tui/app/use-prompt-handlers.mjs +11 -0
- package/src/tui/components/BtwPanel.jsx +53 -0
- package/src/tui/components/QuestionPanel.jsx +275 -0
- package/src/tui/components/StatusLine.jsx +2 -0
- package/src/tui/components/question-panel-model.mjs +156 -0
- package/src/tui/components/status-line/local-line.mjs +5 -2
- package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
- package/src/tui/dist/index.mjs +3221 -1500
- package/src/tui/session/context-state.mjs +4 -2
- package/src/tui/session/quota-resume.mjs +46 -14
- package/src/tui/session/session-api/commands.mjs +43 -24
- package/src/tui/session/session-api/controls.mjs +2 -2
- package/src/tui/session/session-api/extensions.mjs +22 -0
- package/src/tui/session/session-api/integrations.mjs +16 -2
- package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
- package/src/tui/session/session-api/lifecycle.mjs +7 -2
- package/src/tui/session/session-api/routes.mjs +71 -7
- package/src/tui/session/session-api/settings.mjs +11 -14
- package/src/tui/session/session-api.mjs +1 -0
- package/src/tui/session/session-flow/drain.mjs +7 -1
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
- package/src/tui/session/tool-approval.mjs +10 -7
- package/src/tui/session/transcript-spill.mjs +14 -7
- package/src/tui/session/turn-stream.mjs +174 -31
- package/src/tui/session/turn.mjs +46 -16
- package/src/tui/statusline-ansi-bridge.mjs +1 -1
- package/src/ui/statusline-agents.mjs +15 -4
- package/src/ui/statusline.mjs +7 -3
- package/src/ui/streaming-markdown-heal.mjs +34 -3
- package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
- package/src/workflows/default/WORKFLOW.md +3 -1
- package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
- package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
// agent-tree/agent-cancel.mjs
|
|
2
2
|
// Cancelling an agent subtree: descendants first, then a durable canonical
|
|
3
3
|
// close of the session itself. Concurrent cancels of one id share a run.
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
cancelBackgroundTask,
|
|
6
|
+
cancelBackgroundTasks,
|
|
7
|
+
listBackgroundTasks,
|
|
8
|
+
} from '../../../runtime/shared/background-tasks.mjs';
|
|
5
9
|
|
|
6
|
-
|
|
10
|
+
// Cancel the running Agent task(s) bound to this session itself (owned by its
|
|
11
|
+
// parent) BEFORE the session closes, so the owner hears `cancelled` with the
|
|
12
|
+
// turn's partial output instead of the closed turn failing the task.
|
|
13
|
+
function cancelOwnAgentTasks(sessionId, reason) {
|
|
14
|
+
for (const row of listBackgroundTasks({ surface: 'agent' })) {
|
|
15
|
+
if (row.status === 'running' && row.sessionId === sessionId) cancelBackgroundTask(row.task_id, reason);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function createAgentCancellation({
|
|
20
|
+
registry,
|
|
21
|
+
rehydrateAgentSessions,
|
|
22
|
+
sessionOwner,
|
|
23
|
+
entryForSession,
|
|
24
|
+
log,
|
|
25
|
+
rememberCancelTranscript,
|
|
26
|
+
}) {
|
|
7
27
|
const agentCancelRuns = new Map();
|
|
8
28
|
|
|
9
29
|
/** The runtime entry that can close this descriptor: the live owner, else a
|
|
@@ -39,6 +59,7 @@ export function createAgentCancellation({ registry, rehydrateAgentSessions, sess
|
|
|
39
59
|
});
|
|
40
60
|
const children = registry.childrenOf(id);
|
|
41
61
|
await Promise.all(children.map((childId) => cancelAgentTree(childId, reason)));
|
|
62
|
+
cancelOwnAgentTasks(id, reason);
|
|
42
63
|
const descriptor = registry.get(id);
|
|
43
64
|
if (!descriptor) return children.length > 0;
|
|
44
65
|
if (descriptor.closed) return true;
|
|
@@ -47,6 +68,16 @@ export function createAgentCancellation({ registry, rehydrateAgentSessions, sess
|
|
|
47
68
|
if (typeof closeCanonical !== 'function') {
|
|
48
69
|
throw new TypeError('session runtime must implement closeCanonicalSession');
|
|
49
70
|
}
|
|
71
|
+
// The close clears the transcript: capture a running turn's transcript
|
|
72
|
+
// first so the cancelled turn still hands off its partial output.
|
|
73
|
+
if (descriptor.status === 'running') {
|
|
74
|
+
try {
|
|
75
|
+
const { messages } = await entry.runtime.readModelMessages(0);
|
|
76
|
+
rememberCancelTranscript(id, messages);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
log(`agent cancel transcript read failed session=${id}: ${error?.message || error}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
50
81
|
const closed = await closeCanonical.call(entry.runtime, reason);
|
|
51
82
|
if (closed !== true) throw new Error(`agent session ${id} could not be durably closed`);
|
|
52
83
|
descriptor.closed = true;
|
|
@@ -12,16 +12,23 @@ export function createAgentTurns({
|
|
|
12
12
|
retainUnwatched,
|
|
13
13
|
createSession,
|
|
14
14
|
takeWatchdogStop,
|
|
15
|
+
takeCancelTranscript,
|
|
15
16
|
}) {
|
|
16
17
|
const createAgentChild = createAgentChildFactory({ registry, rehydrateAgentSessions, createSession });
|
|
17
18
|
|
|
18
|
-
// The progress watchdog
|
|
19
|
-
// the assistant text the turn produced, so the owner still gets a
|
|
20
|
-
// result.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
// The turn was stopped (progress watchdog or cancellation): rethrow its error
|
|
20
|
+
// carrying the assistant text the turn produced, so the owner still gets a
|
|
21
|
+
// partial result. A cancel that closed the session captured the transcript
|
|
22
|
+
// before the close cleared it.
|
|
23
|
+
async function withPartialHandoff(runtime, sessionId, error, messageStart) {
|
|
24
|
+
try {
|
|
25
|
+
const captured = takeCancelTranscript(sessionId);
|
|
26
|
+
const messages = captured
|
|
27
|
+
? captured.slice(messageStart)
|
|
28
|
+
: (await runtime.readModelMessages(messageStart)).messages;
|
|
29
|
+
const partial = partialHandoffTextFromSession({ messages });
|
|
30
|
+
if (partial) error.partialHandoff = partial;
|
|
31
|
+
} catch {}
|
|
25
32
|
return error;
|
|
26
33
|
}
|
|
27
34
|
|
|
@@ -44,6 +51,7 @@ export function createAgentTurns({
|
|
|
44
51
|
}
|
|
45
52
|
// A stop left over from an earlier turn must not relabel this one.
|
|
46
53
|
takeWatchdogStop(sessionId);
|
|
54
|
+
takeCancelTranscript(sessionId);
|
|
47
55
|
// Transcript length before this turn: where a watchdog stop's partial
|
|
48
56
|
// output starts.
|
|
49
57
|
const { messageCount: messageStart } = await entry.runtime.readModelMessages(Number.MAX_SAFE_INTEGER);
|
|
@@ -64,9 +72,16 @@ export function createAgentTurns({
|
|
|
64
72
|
throw new Error(String(detail.error || 'agent session turn failed'));
|
|
65
73
|
}
|
|
66
74
|
if (detail?.status === 'cancelled') {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
const stop = takeWatchdogStop(sessionId) || new Error('agent session turn cancelled');
|
|
76
|
+
throw await withPartialHandoff(entry.runtime, sessionId, stop, messageStart);
|
|
77
|
+
}
|
|
78
|
+
// Only a completed turn has a result; a rejected submission (session
|
|
79
|
+
// closing/terminal, steering persist failure) or any unknown status is a
|
|
80
|
+
// failure, never an empty completion.
|
|
81
|
+
if (detail?.status !== 'done' && detail?.status !== 'completed') {
|
|
82
|
+
const status = String(detail?.status || 'unknown');
|
|
83
|
+
const reason = String(detail?.reason || detail?.error || '').trim();
|
|
84
|
+
throw new Error(`agent turn ${status}${reason ? `: ${reason}` : ''}`);
|
|
70
85
|
}
|
|
71
86
|
const result = detail?.result || { content: '' };
|
|
72
87
|
descriptor.status = 'idle';
|
|
@@ -81,6 +96,7 @@ export function createAgentTurns({
|
|
|
81
96
|
descriptor.stage = descriptor.status;
|
|
82
97
|
throw error;
|
|
83
98
|
} finally {
|
|
99
|
+
takeCancelTranscript(sessionId);
|
|
84
100
|
descriptor.updatedAt = Date.now();
|
|
85
101
|
retainUnwatched(entry, 'agent child idle');
|
|
86
102
|
}
|
|
@@ -37,6 +37,16 @@ export function createAgentTree({
|
|
|
37
37
|
watchdogStops.delete(sessionId);
|
|
38
38
|
return error;
|
|
39
39
|
};
|
|
40
|
+
// Transcripts of running turns captured by a cancel just before it closes
|
|
41
|
+
// (and clears) the session, so the cancelled turn still reports the output
|
|
42
|
+
// it produced.
|
|
43
|
+
const cancelTranscripts = new Map();
|
|
44
|
+
const rememberCancelTranscript = (sessionId, messages) => cancelTranscripts.set(sessionId, messages);
|
|
45
|
+
const takeCancelTranscript = (sessionId) => {
|
|
46
|
+
const messages = cancelTranscripts.get(sessionId) || null;
|
|
47
|
+
cancelTranscripts.delete(sessionId);
|
|
48
|
+
return messages;
|
|
49
|
+
};
|
|
40
50
|
function getSessionProgressSnapshot(sessionId) {
|
|
41
51
|
const runtime = sessionOwner(sessionId)?.runtime;
|
|
42
52
|
if (typeof runtime?.getTurnLiveness !== 'function') return null;
|
|
@@ -58,6 +68,7 @@ export function createAgentTree({
|
|
|
58
68
|
retainUnwatched,
|
|
59
69
|
createSession,
|
|
60
70
|
takeWatchdogStop,
|
|
71
|
+
takeCancelTranscript,
|
|
61
72
|
});
|
|
62
73
|
const { cancelAgentTree, cancelAgentDescendants } = createAgentCancellation({
|
|
63
74
|
registry,
|
|
@@ -65,6 +76,7 @@ export function createAgentTree({
|
|
|
65
76
|
sessionOwner,
|
|
66
77
|
entryForSession,
|
|
67
78
|
log,
|
|
79
|
+
rememberCancelTranscript,
|
|
68
80
|
});
|
|
69
81
|
|
|
70
82
|
/** The descriptor as callers see it: status from the live runtime when one
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
// again, and the session's own lane runs the retry under the entry's
|
|
9
9
|
// generation. Overdue entries run as soon as the scheduler starts.
|
|
10
10
|
|
|
11
|
+
import { isAgentOnlySession } from '../../runtime/shared/quota-resume-store.mjs';
|
|
12
|
+
|
|
11
13
|
/** A still-exhausted reading is re-taken once, this much later. */
|
|
12
14
|
export const QUOTA_RESUME_RETRY_MS = 5 * 60_000;
|
|
13
15
|
/** A busy session is re-checked this much later, without spending an attempt. */
|
|
@@ -30,6 +32,12 @@ async function resumeDueEntry(entry, { store, materializeSession, readQuotaUsabl
|
|
|
30
32
|
return 'unavailable';
|
|
31
33
|
}
|
|
32
34
|
if (!isCurrent(store, entry)) return 'cancelled';
|
|
35
|
+
// A delegated agent child never owns a resume (the Lead decides retries), so
|
|
36
|
+
// an entry persisted for one never fires, whatever wrote it.
|
|
37
|
+
if (isAgentOnlySession({ id: sessionId, ...runtime?.session })) {
|
|
38
|
+
store.cancelQuotaResumeEntry(sessionId, { generation });
|
|
39
|
+
return 'agent-session';
|
|
40
|
+
}
|
|
33
41
|
let usable = false;
|
|
34
42
|
try {
|
|
35
43
|
usable = await readQuotaUsable(entry.provider, entry.model);
|
|
@@ -28,6 +28,12 @@ export function createBusyTracker({ sessions, currentSessionId }) {
|
|
|
28
28
|
// reaches a terminal state and its completion can be delivered back into
|
|
29
29
|
// this session.
|
|
30
30
|
if (sessionId && hasActiveBackgroundTasks({ callerSessionId: sessionId })) return true;
|
|
31
|
+
return sessionTurnBusy(entry);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// A turn is running (provider stream / tool call / queued input). Background
|
|
35
|
+
// tasks are deliberately not counted: they run outside the heap-churning turn.
|
|
36
|
+
function sessionTurnBusy(entry) {
|
|
31
37
|
if (typeof entry?.busy === 'boolean') return entry.busy;
|
|
32
38
|
try {
|
|
33
39
|
return updateEntryBusy(entry, entry.runtime.getState?.() || {});
|
|
@@ -46,5 +52,13 @@ export function createBusyTracker({ sessions, currentSessionId }) {
|
|
|
46
52
|
return count;
|
|
47
53
|
}
|
|
48
54
|
|
|
49
|
-
|
|
55
|
+
function liveTurnBusyCount() {
|
|
56
|
+
let count = 0;
|
|
57
|
+
for (const entry of sessions) {
|
|
58
|
+
if (sessionTurnBusy(entry)) count += 1;
|
|
59
|
+
}
|
|
60
|
+
return count;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return { stateBusy, updateEntryBusy, sessionBusy, liveBusyCount, liveTurnBusyCount };
|
|
50
64
|
}
|
|
@@ -2,10 +2,17 @@
|
|
|
2
2
|
// The generic runtime-action lane (read / configure allowlists) and the
|
|
3
3
|
// session catalog listing.
|
|
4
4
|
import { SESSION_CONFIGURE_ACTION_SET, SESSION_READ_ACTION_SET } from '../../session-protocol.mjs';
|
|
5
|
+
import { annotateSpan, markPhase } from '../../../runtime/shared/slow-span.mjs';
|
|
5
6
|
import { sanitizeForWire } from '../../session-wire-values.mjs';
|
|
6
7
|
|
|
7
8
|
/** Reads a session without a live runtime answers from disk (readStoredReview). */
|
|
8
|
-
const STORED_REVIEW_ACTIONS = new Set([
|
|
9
|
+
const STORED_REVIEW_ACTIONS = new Set([
|
|
10
|
+
'getTurnReviewDiff',
|
|
11
|
+
'getSessionReviewDiff',
|
|
12
|
+
'getTurnChanges',
|
|
13
|
+
'getSessionReviewFilePatch',
|
|
14
|
+
'getTurnReviewFilePatch',
|
|
15
|
+
]);
|
|
9
16
|
|
|
10
17
|
/** One compact description of an action result for the daemon log, never the payload itself. */
|
|
11
18
|
function resultSummary(value) {
|
|
@@ -44,7 +51,8 @@ export function createSessionActionCalls(ctx) {
|
|
|
44
51
|
assertAvailable();
|
|
45
52
|
if (value === null) throw new Error(`session ${id} is not available`);
|
|
46
53
|
log(`session action ${name} session=${id} result=${resultSummary(value)} (stored)`);
|
|
47
|
-
|
|
54
|
+
markPhase('load');
|
|
55
|
+
const result = {
|
|
48
56
|
value: sanitizeForWire(value) ?? null,
|
|
49
57
|
sessionId: id,
|
|
50
58
|
reservedOnly: false,
|
|
@@ -52,6 +60,8 @@ export function createSessionActionCalls(ctx) {
|
|
|
52
60
|
unchanged: true,
|
|
53
61
|
...(Number.isInteger(baseRevision) ? { revision: baseRevision } : {}),
|
|
54
62
|
};
|
|
63
|
+
markPhase('project');
|
|
64
|
+
return result;
|
|
55
65
|
}
|
|
56
66
|
|
|
57
67
|
async function runSessionAction(
|
|
@@ -62,6 +72,7 @@ export function createSessionActionCalls(ctx) {
|
|
|
62
72
|
const id = String(sessionId || '');
|
|
63
73
|
if (!id) throw new TypeError('sessionId is required');
|
|
64
74
|
const name = requireSessionAction(action, allowedActions);
|
|
75
|
+
annotateSpan(name);
|
|
65
76
|
// Opening an earlier session asks for its review right away; loading the
|
|
66
77
|
// whole runtime for that held the review bar (and the pane's reveal) for
|
|
67
78
|
// seconds.
|
|
@@ -72,7 +83,9 @@ export function createSessionActionCalls(ctx) {
|
|
|
72
83
|
assertAvailable(entry);
|
|
73
84
|
const target = entry.runtime[name];
|
|
74
85
|
if (typeof target !== 'function') throw new TypeError(`session action ${name} is unavailable`);
|
|
86
|
+
markPhase('load');
|
|
75
87
|
const value = await target.apply(entry.runtime, Array.isArray(args) ? args : []);
|
|
88
|
+
markPhase('action');
|
|
76
89
|
if (name === 'setCwd' && value) {
|
|
77
90
|
try {
|
|
78
91
|
const projects = await loadProjectStore();
|
|
@@ -89,11 +102,13 @@ export function createSessionActionCalls(ctx) {
|
|
|
89
102
|
// Still unwatched: keep it on the retention clock exactly like a runtime
|
|
90
103
|
// released by its view, so an untouched load cannot leak past the idle window.
|
|
91
104
|
retainUnwatched(entry);
|
|
92
|
-
|
|
105
|
+
const result = {
|
|
93
106
|
value: sanitizeForWire(value) ?? null,
|
|
94
107
|
sessionId: responseSessionId(entry, id),
|
|
95
108
|
...bodyForClient(step, Number.isInteger(baseRevision) ? baseRevision : null),
|
|
96
109
|
};
|
|
110
|
+
markPhase('project');
|
|
111
|
+
return result;
|
|
97
112
|
}
|
|
98
113
|
|
|
99
114
|
async function listSessionCatalog(options = {}) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { shortId, slowSpans } from '../runtime/shared/slow-span.mjs';
|
|
2
|
+
|
|
1
3
|
const sessionServiceRoutes = ({ desktop, project, session }) => ({
|
|
2
4
|
'desktop.init': (params, ctx) => desktop.init(params, ctx),
|
|
3
5
|
'desktop.invoke': (params, ctx) => desktop.invoke(params, ctx),
|
|
@@ -29,15 +31,19 @@ export function createSessionServiceApi({
|
|
|
29
31
|
methods,
|
|
30
32
|
getSize,
|
|
31
33
|
getBusyCount,
|
|
34
|
+
getTurnBusyCount,
|
|
32
35
|
getStatus,
|
|
33
36
|
getExternalClientCount,
|
|
37
|
+
spans = slowSpans,
|
|
34
38
|
}) {
|
|
35
39
|
const routes = sessionServiceRoutes({ desktop, project, session });
|
|
36
40
|
return {
|
|
37
41
|
async handleCall(name, args = {}, ctx = null) {
|
|
38
42
|
const route = routes[String(name || '')];
|
|
39
43
|
if (!route) throw new Error(`unknown session service call ${name}`);
|
|
40
|
-
|
|
44
|
+
const params = args || {};
|
|
45
|
+
const sid = shortId(params.sessionId);
|
|
46
|
+
return spans.trace(sid ? `${name}#${sid}` : String(name), () => route(params, ctx));
|
|
41
47
|
},
|
|
42
48
|
...methods,
|
|
43
49
|
get size() {
|
|
@@ -46,6 +52,10 @@ export function createSessionServiceApi({
|
|
|
46
52
|
get busyCount() {
|
|
47
53
|
return getBusyCount();
|
|
48
54
|
},
|
|
55
|
+
/** Sessions with a running turn; background-task-only sessions excluded. */
|
|
56
|
+
get turnBusyCount() {
|
|
57
|
+
return getTurnBusyCount();
|
|
58
|
+
},
|
|
49
59
|
get status() {
|
|
50
60
|
return getStatus();
|
|
51
61
|
},
|
|
@@ -296,6 +296,7 @@ export function createSessionService({
|
|
|
296
296
|
},
|
|
297
297
|
getSize: () => sessions.size,
|
|
298
298
|
getBusyCount: retention.liveBusyCount,
|
|
299
|
+
getTurnBusyCount: retention.liveTurnBusyCount,
|
|
299
300
|
getStatus,
|
|
300
301
|
getExternalClientCount: () => desktopServices.externalClientCount,
|
|
301
302
|
});
|
|
@@ -3,5 +3,6 @@ export function diffSessionState(
|
|
|
3
3
|
next: unknown,
|
|
4
4
|
options?: { prepend?: boolean }
|
|
5
5
|
): Record<string, unknown> | null;
|
|
6
|
-
export function
|
|
6
|
+
export function streamingPartialSuffix(before: unknown, after: unknown): string | null;
|
|
7
|
+
export function applySessionStatePatch(previous: unknown, patch: unknown): Record<string, unknown> | null;
|
|
7
8
|
export function transcriptItemsDigest(items: readonly unknown[]): string;
|
|
@@ -7,16 +7,51 @@
|
|
|
7
7
|
// `transcriptPrepend`) carries rows revealed ABOVE the previous list, an
|
|
8
8
|
// older-history page: the previous rows then start `values.length` rows in,
|
|
9
9
|
// and `itemsAppend.from` indexes the PREVIOUS list.
|
|
10
|
+
//
|
|
11
|
+
// `partialAppend` carries growth of the desktop-only `streamingPartial` (the
|
|
12
|
+
// unfinished streamed line) as just its new text: re-sending the whole line on
|
|
13
|
+
// every tick made a long unfinished line cost O(length²) on the wire. A
|
|
14
|
+
// decoder that predates it keeps its last partial, which the desktop join
|
|
15
|
+
// then ignores or shows behind — never wrong text.
|
|
10
16
|
import { createHash } from 'node:crypto';
|
|
11
17
|
|
|
18
|
+
/** The text `after` appends to `before` when both are the same unfinished
|
|
19
|
+
* line (same row, same offset, same row identity), else null: a retraction,
|
|
20
|
+
* another row or a new line travels as a full replacement. */
|
|
21
|
+
export function streamingPartialSuffix(before, after) {
|
|
22
|
+
if (!before || !after || typeof before !== 'object' || typeof after !== 'object') return null;
|
|
23
|
+
const { text: beforeText, ...beforeRest } = before;
|
|
24
|
+
const { text: afterText, ...afterRest } = after;
|
|
25
|
+
if (typeof beforeText !== 'string' || typeof afterText !== 'string') return null;
|
|
26
|
+
if (afterText.length <= beforeText.length || !afterText.startsWith(beforeText)) return null;
|
|
27
|
+
// id, from and the row identity: everything but the text stays put.
|
|
28
|
+
if (JSON.stringify(beforeRest) !== JSON.stringify(afterRest)) return null;
|
|
29
|
+
return afterText.slice(beforeText.length);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function appendStreamingPartial(state, suffix) {
|
|
33
|
+
const held = state.streamingPartial;
|
|
34
|
+
if (!held || typeof held !== 'object' || typeof held.text !== 'string' || typeof suffix !== 'string') return false;
|
|
35
|
+
state.streamingPartial = { ...held, text: held.text + suffix };
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
|
|
12
39
|
export function diffSessionState(previous, next, { prepend = false } = {}) {
|
|
13
40
|
if (!previous || !next || typeof previous !== 'object' || typeof next !== 'object') return null;
|
|
14
41
|
const set = {};
|
|
15
42
|
const remove = [];
|
|
16
43
|
let itemsAppend = null;
|
|
17
44
|
let itemsPrepend = null;
|
|
45
|
+
let partialAppend = null;
|
|
18
46
|
for (const [key, value] of Object.entries(next)) {
|
|
19
47
|
if (previous[key] === value) continue;
|
|
48
|
+
if (key === 'streamingPartial') {
|
|
49
|
+
const suffix = streamingPartialSuffix(previous[key], value);
|
|
50
|
+
if (suffix !== null) {
|
|
51
|
+
partialAppend = { text: suffix };
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
20
55
|
if (key === 'items' && Array.isArray(value) && Array.isArray(previous.items)) {
|
|
21
56
|
let head = 0;
|
|
22
57
|
if (prepend && previous.items.length > 0 && value[0] !== previous.items[0]) {
|
|
@@ -36,13 +71,18 @@ export function diffSessionState(previous, next, { prepend = false } = {}) {
|
|
|
36
71
|
for (const key of Object.keys(previous)) {
|
|
37
72
|
if (!(key in next)) remove.push(key);
|
|
38
73
|
}
|
|
39
|
-
|
|
74
|
+
const patch = itemsPrepend ? { set, remove, itemsAppend, itemsPrepend } : { set, remove, itemsAppend };
|
|
75
|
+
if (partialAppend) patch.partialAppend = partialAppend;
|
|
76
|
+
return patch;
|
|
40
77
|
}
|
|
41
78
|
|
|
79
|
+
/** The patched state, or null when a `partialAppend` has no held line to grow
|
|
80
|
+
* (a broken chain the caller answers with a full resync, never lost text). */
|
|
42
81
|
export function applySessionStatePatch(previous, patch) {
|
|
43
82
|
const base = previous && typeof previous === 'object' ? previous : {};
|
|
44
83
|
if (!patch || typeof patch !== 'object') return base;
|
|
45
84
|
const next = { ...base, ...(patch.set || {}) };
|
|
85
|
+
if (Object.hasOwn(patch, 'partialAppend') && !appendStreamingPartial(next, patch.partialAppend?.text)) return null;
|
|
46
86
|
if (patch.itemsAppend || patch.itemsPrepend) {
|
|
47
87
|
const items = Array.isArray(base.items) ? base.items : [];
|
|
48
88
|
const head = Array.isArray(patch.itemsPrepend?.values) ? patch.itemsPrepend.values : [];
|
package/src/tui/App.jsx
CHANGED
|
@@ -21,6 +21,7 @@ import { useApp, useStdin, useStdout } from 'ink';
|
|
|
21
21
|
import { useSession } from './hooks/useSession.mjs';
|
|
22
22
|
import { pickFolder } from '../standalone/folder-dialog.mjs';
|
|
23
23
|
import { deriveSlashPalette } from './app/slash-palette.mjs';
|
|
24
|
+
import { createBtwController } from './app/btw-controller.mjs';
|
|
24
25
|
import { skillMentionQuery, useSkillMentionSkills } from './app/skill-mention-palette.mjs';
|
|
25
26
|
import { shouldSupersedePanelEpoch, supersedePanelEpoch } from './app/panel-epoch.mjs';
|
|
26
27
|
import { createPanelSurface } from './app/panel-surface.mjs';
|
|
@@ -152,6 +153,24 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
152
153
|
livePickerRef.current = picker;
|
|
153
154
|
const [contextPanel, setContextPanel] = useState(null);
|
|
154
155
|
const [usagePanel, setUsagePanel] = useState(null);
|
|
156
|
+
const [btwPanel, setBtwPanel] = useState(null);
|
|
157
|
+
const btwRef = useRef(null);
|
|
158
|
+
const sessionIdRef = useRef('');
|
|
159
|
+
sessionIdRef.current = state.sessionId || '';
|
|
160
|
+
if (!btwRef.current) {
|
|
161
|
+
btwRef.current = createBtwController({
|
|
162
|
+
getStore: () => store,
|
|
163
|
+
setPanel: setBtwPanel,
|
|
164
|
+
getSessionId: () => sessionIdRef.current,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const btw = btwRef.current;
|
|
168
|
+
// A side answer belongs to the conversation it was asked in: drop it on a
|
|
169
|
+
// session change (new/resume/clear/switch) and cancel it on unmount.
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
btw.sync();
|
|
172
|
+
}, [btw, state.sessionId]);
|
|
173
|
+
useEffect(() => () => btw.dispose(), [btw]);
|
|
155
174
|
// OWNING LAYER (app/panel-surface.mjs): the three sinks above are handed over
|
|
156
175
|
// exactly once and never leave that module. Every panel factory below gets
|
|
157
176
|
// `surface` instead, so painting or delegating without a claim that proves
|
|
@@ -310,6 +329,7 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
310
329
|
setSettingsPrompt,
|
|
311
330
|
setOnboardingActive,
|
|
312
331
|
closeUsagePanel,
|
|
332
|
+
btw,
|
|
313
333
|
oauthSubmitRef,
|
|
314
334
|
clearModelCaches,
|
|
315
335
|
onboardingRef,
|
|
@@ -518,6 +538,8 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
518
538
|
usagePanel,
|
|
519
539
|
closeUsagePanel,
|
|
520
540
|
contextPanel,
|
|
541
|
+
btwPanel,
|
|
542
|
+
closeBtwPanel: btw.close,
|
|
521
543
|
installPastedImages,
|
|
522
544
|
clearPastedImagesSnapshot,
|
|
523
545
|
registerPastedImage,
|
|
@@ -650,6 +672,7 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
650
672
|
toolApproval: !!toolApproval,
|
|
651
673
|
contextPanel: !!contextPanel,
|
|
652
674
|
usagePanel: !!usagePanel,
|
|
675
|
+
btwPanel: !!btwPanel,
|
|
653
676
|
providerPrompt: !!providerPrompt,
|
|
654
677
|
settingsPrompt: !!settingsPrompt,
|
|
655
678
|
};
|
|
@@ -711,6 +734,7 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
711
734
|
picker,
|
|
712
735
|
contextPanel,
|
|
713
736
|
usagePanel,
|
|
737
|
+
btwPanel,
|
|
714
738
|
slashPaletteOpen,
|
|
715
739
|
tuiReady,
|
|
716
740
|
state,
|
|
@@ -822,6 +846,7 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
822
846
|
activeSlashQuery,
|
|
823
847
|
activeTools,
|
|
824
848
|
agentRevision,
|
|
849
|
+
btwPanel,
|
|
825
850
|
cancelProviderPrompt,
|
|
826
851
|
cancelSettingsPrompt,
|
|
827
852
|
cancelSlashPalette,
|
|
@@ -10,9 +10,12 @@
|
|
|
10
10
|
import { theme } from '../../theme.mjs';
|
|
11
11
|
import { toolApprovalDescription } from '../app-format.mjs';
|
|
12
12
|
import { Picker } from '../../components/Picker.jsx';
|
|
13
|
+
import { QuestionPanel } from '../../components/QuestionPanel.jsx';
|
|
14
|
+
import { questionsOf } from '../../components/question-panel-model.mjs';
|
|
13
15
|
import { SlashCommandPalette } from '../../components/SlashCommandPalette.jsx';
|
|
14
16
|
import { ContextPanel } from '../../components/ContextPanel.jsx';
|
|
15
17
|
import { UsagePanel } from '../../components/UsagePanel.jsx';
|
|
18
|
+
import { BtwPanel } from '../../components/BtwPanel.jsx';
|
|
16
19
|
import { TextEntryPanel } from '../../components/TextEntryPanel.jsx';
|
|
17
20
|
import { textEntryClearsByEmpty } from '../text-entry-policy.mjs';
|
|
18
21
|
import { withPickerEnterLatch } from '../picker-enter-latch.mjs';
|
|
@@ -24,7 +27,23 @@ const SKILL_PALETTE_TEXT = {
|
|
|
24
27
|
help: '↑/↓ select · Enter insert · Esc cancel',
|
|
25
28
|
};
|
|
26
29
|
|
|
27
|
-
function renderToolApproval({ toolApproval, store, frameColumns, expandedOptionPanel }) {
|
|
30
|
+
function renderToolApproval({ toolApproval, store, frameColumns, expandedOptionPanel, floatingPanelRows }) {
|
|
31
|
+
if (toolApproval.kind === 'question') {
|
|
32
|
+
return (
|
|
33
|
+
<QuestionPanel
|
|
34
|
+
key={toolApproval.id}
|
|
35
|
+
questions={questionsOf(toolApproval)}
|
|
36
|
+
columns={frameColumns}
|
|
37
|
+
rows={floatingPanelRows}
|
|
38
|
+
onSubmit={(answers) =>
|
|
39
|
+
store.resolveToolApproval?.(toolApproval.id, { approved: true, reason: 'answered by user', answers })
|
|
40
|
+
}
|
|
41
|
+
onDismiss={() =>
|
|
42
|
+
store.resolveToolApproval?.(toolApproval.id, { approved: false, reason: 'dismissed by user' })
|
|
43
|
+
}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
28
47
|
const resolve = (approved) => {
|
|
29
48
|
store.resolveToolApproval?.(toolApproval.id, {
|
|
30
49
|
approved,
|
|
@@ -144,6 +163,7 @@ export function renderFloatingPanel(ctx) {
|
|
|
144
163
|
slashPaletteOpen,
|
|
145
164
|
toolApproval,
|
|
146
165
|
usagePanel,
|
|
166
|
+
btwPanel,
|
|
147
167
|
} = ctx;
|
|
148
168
|
if (toolApproval) return renderToolApproval(ctx);
|
|
149
169
|
if (picker) return renderPicker(ctx);
|
|
@@ -227,5 +247,10 @@ export function renderFloatingPanel(ctx) {
|
|
|
227
247
|
/>
|
|
228
248
|
);
|
|
229
249
|
}
|
|
250
|
+
if (btwPanel) {
|
|
251
|
+
return (
|
|
252
|
+
<BtwPanel panel={btwPanel} columns={frameColumns} panelRows={floatingPanelRows} themeEpoch={ctx.state?.themeEpoch || 0} />
|
|
253
|
+
);
|
|
254
|
+
}
|
|
230
255
|
return null;
|
|
231
256
|
}
|
package/src/tui/app/app-view.jsx
CHANGED
|
@@ -235,6 +235,7 @@ export function renderAppView(ctx) {
|
|
|
235
235
|
model={state.model}
|
|
236
236
|
effort={state.effort}
|
|
237
237
|
fast={state.fast}
|
|
238
|
+
ultra={state.fast === true && state.modelParameters?.serviceTier === 'ultrafast'}
|
|
238
239
|
cwd={state.cwd}
|
|
239
240
|
stats={statuslineStats}
|
|
240
241
|
contextWindow={state.contextWindow}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* app/btw-controller.mjs — the transient `/btw` side-question panel.
|
|
3
|
+
*
|
|
4
|
+
* The answer lives only in this panel (never the transcript). `ask` replaces
|
|
5
|
+
* any existing panel, `close` (Esc) cancels a pending request, and a result
|
|
6
|
+
* that arrives after a replace/close is ignored via the request sequence.
|
|
7
|
+
*/
|
|
8
|
+
import { measureMarkdownRenderedRows } from '../markdown/measure-rendered-rows.mjs';
|
|
9
|
+
|
|
10
|
+
export const BTW_USAGE_HINT = 'usage: /btw <question>';
|
|
11
|
+
// Border (2) + header (1) + footer (1).
|
|
12
|
+
export const BTW_CHROME_ROWS = 4;
|
|
13
|
+
const BTW_MAX_BODY_ROWS = 10;
|
|
14
|
+
|
|
15
|
+
/** Rendered row count of the answer body (the scrollable content height). */
|
|
16
|
+
export function btwContentRows(panel, columns) {
|
|
17
|
+
const body =
|
|
18
|
+
panel.status === 'done'
|
|
19
|
+
? measureMarkdownRenderedRows(panel.text, Math.max(1, columns - 4))
|
|
20
|
+
: String(panel.text || '').split('\n').length;
|
|
21
|
+
return Math.max(1, body);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function btwPanelRows(panel, columns) {
|
|
25
|
+
if (!panel) return 0;
|
|
26
|
+
return BTW_CHROME_ROWS + Math.min(BTW_MAX_BODY_ROWS, btwContentRows(panel, columns));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Largest scroll offset for `total` content rows shown through `visible` rows. */
|
|
30
|
+
export function btwScrollMax(total, visible) {
|
|
31
|
+
return Math.max(0, total - Math.max(1, visible));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Next scroll offset for a PageUp/PageDown key (other keys leave it unchanged). */
|
|
35
|
+
export function btwScrollOffset(key, offset, visible, total) {
|
|
36
|
+
const max = btwScrollMax(total, visible);
|
|
37
|
+
const page = Math.max(1, visible - 1);
|
|
38
|
+
if (key.pageUp) return Math.max(0, Math.min(max, offset) - page);
|
|
39
|
+
if (key.pageDown) return Math.min(max, offset + page);
|
|
40
|
+
return Math.min(max, offset);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Each request is bound to the session it was asked in. A settlement whose
|
|
45
|
+
* session no longer matches is ignored; `sync` (session change) and `dispose`
|
|
46
|
+
* (unmount) cancel a pending request for its originating session.
|
|
47
|
+
*/
|
|
48
|
+
export function createBtwController({ getStore, setPanel, getSessionId = () => '' }) {
|
|
49
|
+
let seq = 0;
|
|
50
|
+
let pending = null; // { sessionId, dispatched } while a request is queued or in flight
|
|
51
|
+
let origin = null; // session the visible panel was asked in
|
|
52
|
+
|
|
53
|
+
const cancelPending = () => {
|
|
54
|
+
if (!pending) return;
|
|
55
|
+
const { sessionId, dispatched } = pending;
|
|
56
|
+
pending = null;
|
|
57
|
+
// Not dispatched yet: dropping `pending` stops the queued request, so
|
|
58
|
+
// there is nothing to cancel (a cancel sent first would not hit it).
|
|
59
|
+
if (!dispatched) return;
|
|
60
|
+
try {
|
|
61
|
+
const result = getStore().cancelSide?.(sessionId);
|
|
62
|
+
if (result?.catch) void result.catch(() => {});
|
|
63
|
+
} catch {
|
|
64
|
+
/* best-effort cancel */
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const ask = (question) => {
|
|
69
|
+
cancelPending();
|
|
70
|
+
const id = ++seq;
|
|
71
|
+
const sessionId = getSessionId();
|
|
72
|
+
const request = { sessionId, dispatched: false };
|
|
73
|
+
pending = request;
|
|
74
|
+
origin = sessionId;
|
|
75
|
+
setPanel({ question, status: 'pending', text: '' });
|
|
76
|
+
const settle = (next) => {
|
|
77
|
+
if (id !== seq || getSessionId() !== sessionId) return;
|
|
78
|
+
pending = null;
|
|
79
|
+
setPanel({ question, ...next });
|
|
80
|
+
};
|
|
81
|
+
Promise.resolve()
|
|
82
|
+
.then(() => {
|
|
83
|
+
// askSide runs against the store's current session, so only dispatch
|
|
84
|
+
// while this ask is still live and still in its origin session.
|
|
85
|
+
if (pending !== request || id !== seq || getSessionId() !== sessionId) {
|
|
86
|
+
if (pending === request) pending = null;
|
|
87
|
+
return undefined; // dropped, never sent; `settle` ignores it (stale id/session)
|
|
88
|
+
}
|
|
89
|
+
request.dispatched = true;
|
|
90
|
+
return getStore().askSide(question);
|
|
91
|
+
})
|
|
92
|
+
.then(
|
|
93
|
+
(result) => settle({ status: 'done', text: String(result?.text ?? '') }),
|
|
94
|
+
(error) => settle({ status: 'error', text: String(error?.message || error || 'side question failed') })
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const close = () => {
|
|
99
|
+
cancelPending();
|
|
100
|
+
seq += 1;
|
|
101
|
+
origin = null;
|
|
102
|
+
setPanel(null);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/** Session changed: a panel from another conversation is cancelled and cleared. */
|
|
106
|
+
const sync = () => {
|
|
107
|
+
if (origin !== null && getSessionId() !== origin) close();
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/** Unmount: cancel without touching React state. */
|
|
111
|
+
const dispose = () => {
|
|
112
|
+
cancelPending();
|
|
113
|
+
seq += 1;
|
|
114
|
+
origin = null;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
return { ask, close, sync, dispose };
|
|
118
|
+
}
|