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
|
@@ -30,6 +30,13 @@ export { cleanupStaleTranscriptSpillDirs };
|
|
|
30
30
|
|
|
31
31
|
let staleSpillSweepDone = false;
|
|
32
32
|
|
|
33
|
+
/** One sweep per process: it lists the whole temp directory synchronously. */
|
|
34
|
+
export function sweepStaleTranscriptSpillDirsOnce() {
|
|
35
|
+
if (staleSpillSweepDone) return;
|
|
36
|
+
staleSpillSweepDone = true;
|
|
37
|
+
cleanupStaleTranscriptSpillDirs();
|
|
38
|
+
}
|
|
39
|
+
|
|
33
40
|
// Serialized pages deliberately release the old item object graph while
|
|
34
41
|
// keeping every byte restorable. Only `items` is render-live and walkable.
|
|
35
42
|
// This buffer owns the page list, the reading cursor and snapshots; the spill
|
|
@@ -47,12 +54,9 @@ export function createTranscriptSpillBuffer({
|
|
|
47
54
|
try {
|
|
48
55
|
writeOwnerRegistry();
|
|
49
56
|
} catch {}
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
staleSpillSweepDone = true;
|
|
54
|
-
cleanupStaleTranscriptSpillDirs();
|
|
55
|
-
}
|
|
57
|
+
// A buffer is created per session; the sweep runs once per process (the
|
|
58
|
+
// daemon runs it in its post-ready warm-up).
|
|
59
|
+
sweepStaleTranscriptSpillDirsOnce();
|
|
56
60
|
const pages = [];
|
|
57
61
|
let cursor = null;
|
|
58
62
|
let spillDir = null;
|
|
@@ -228,13 +232,16 @@ export function reindexItems(itemIndexById, items) {
|
|
|
228
232
|
export function replaceSessionItemsState({ state, items, itemIndexById, preserveStreamingTail = false, extra = {} }) {
|
|
229
233
|
const nextItems = Array.isArray(items) ? items : [];
|
|
230
234
|
reindexItems(itemIndexById, nextItems);
|
|
231
|
-
|
|
235
|
+
const next = {
|
|
232
236
|
...state,
|
|
233
237
|
...extra,
|
|
234
238
|
items: nextItems,
|
|
235
239
|
structureRevision: (Number(state.structureRevision) || 0) + 1,
|
|
236
240
|
streamingTail: preserveStreamingTail ? state.streamingTail : null,
|
|
237
241
|
};
|
|
242
|
+
// The desktop's partial line belongs to the live row it continues.
|
|
243
|
+
if (!preserveStreamingTail && next.streamingPartial) next.streamingPartial = null;
|
|
244
|
+
return next;
|
|
238
245
|
}
|
|
239
246
|
|
|
240
247
|
// Shared by the live session runtime and focused transcript tests so revision/tail
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Per-turn streaming state for the lead TUI turn: the assistant text
|
|
2
2
|
// segments, the thinking (reasoning) timer, and the frame-batched flush that
|
|
3
|
-
// publishes completed visible lines and thinking transitions to the store
|
|
3
|
+
// publishes completed visible lines and thinking transitions to the store,
|
|
4
|
+
// plus the desktop-only unfinished line (`streamingPartial`, see partialNow).
|
|
4
5
|
// `createTurnStream` returns one explicit state object (deps + mutable
|
|
5
6
|
// scalars); every function here takes it as its first argument.
|
|
6
7
|
import { TUI_FRAME_MS, yieldToRenderer } from './render-timing.mjs';
|
|
@@ -11,6 +12,10 @@ import { newTranscriptMessageId } from '../../runtime/shared/transcript-metadata
|
|
|
11
12
|
// 16ms timer left every other terminal frame idle, so completed script lines
|
|
12
13
|
// accumulated and then climbed into view in coarse two-step chunks.
|
|
13
14
|
const STREAM_BATCH_INTERVAL_MS = TUI_FRAME_MS;
|
|
15
|
+
// The desktop's unfinished-line channel (see partialNow): at most one
|
|
16
|
+
// publication per interval, the first chunk after an idle gap on the next
|
|
17
|
+
// frame. Forced flushes (tool calls, notices, finalization) publish at once.
|
|
18
|
+
const PARTIAL_INTERVAL_MS = 40;
|
|
14
19
|
|
|
15
20
|
// deps: getState, set, nextId, updateStreamingTail, settleStreamingTail,
|
|
16
21
|
// clearStreamingTail, isCurrentTurn, transcriptMeta, routeMeta, sealToolBlock.
|
|
@@ -53,42 +58,59 @@ export function createTurnStream(deps) {
|
|
|
53
58
|
publishedThinkingActive: false,
|
|
54
59
|
// Live countdown of a reconnect wait (see startReconnectCountdown).
|
|
55
60
|
reconnectTimer: null,
|
|
61
|
+
// The row identity (id, time, message id) claimed before the row exists,
|
|
62
|
+
// while only the desktop's partial line shows it; the row takes it over.
|
|
63
|
+
assistantIdentity: null,
|
|
64
|
+
// Desktop partial-line publication timer and last publish time.
|
|
65
|
+
partialTimer: null,
|
|
66
|
+
partialPublishedAt: 0,
|
|
67
|
+
// This segment's partial is on screen / was cleared by a transcript
|
|
68
|
+
// replacement (and must not come back).
|
|
69
|
+
partialShown: false,
|
|
70
|
+
partialDropped: false,
|
|
56
71
|
};
|
|
57
72
|
}
|
|
58
73
|
|
|
74
|
+
function claimAssistantIdentity(stream) {
|
|
75
|
+
if (stream.assistantIdentity) return stream.assistantIdentity;
|
|
76
|
+
const id = stream.nextId();
|
|
77
|
+
const meta = stream.transcriptMeta;
|
|
78
|
+
// A non-streaming continuation was persisted before its text reached this
|
|
79
|
+
// row: the runtime left that message's id and time (ask-session
|
|
80
|
+
// takeAssistant), and the row carries them instead of minting new ones.
|
|
81
|
+
const persisted = stream.claimPersistedAssistant ? meta.persistedAssistant : null;
|
|
82
|
+
if (persisted) meta.persistedAssistant = null;
|
|
83
|
+
let assistantAt = persisted?.at;
|
|
84
|
+
let messageId = persisted?.messageId;
|
|
85
|
+
if (!persisted) {
|
|
86
|
+
assistantAt =
|
|
87
|
+
Number.isFinite(Number(meta.assistantAt)) && Number(meta.assistantAt) > 0 ? Number(meta.assistantAt) : Date.now();
|
|
88
|
+
meta.assistantAt = assistantAt;
|
|
89
|
+
// The reply this segment becomes is persisted with this stable id (the
|
|
90
|
+
// runtime takes it with assistantAt), so a compaction that drops the
|
|
91
|
+
// reply greys this row.
|
|
92
|
+
if (!(typeof meta.assistantMessageId === 'string' && meta.assistantMessageId)) {
|
|
93
|
+
meta.assistantMessageId = newTranscriptMessageId();
|
|
94
|
+
}
|
|
95
|
+
messageId = meta.assistantMessageId;
|
|
96
|
+
}
|
|
97
|
+
stream.assistantIdentity = { id, at: assistantAt, messageId };
|
|
98
|
+
return stream.assistantIdentity;
|
|
99
|
+
}
|
|
100
|
+
|
|
59
101
|
function ensureAssistant(stream, initialText = '') {
|
|
60
102
|
if (!stream.currentAssistantId) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// row: the runtime left that message's id and time (ask-session
|
|
65
|
-
// takeAssistant), and the row carries them instead of minting new ones.
|
|
66
|
-
const persisted = stream.claimPersistedAssistant ? meta.persistedAssistant : null;
|
|
67
|
-
if (persisted) meta.persistedAssistant = null;
|
|
68
|
-
let assistantAt = persisted?.at;
|
|
69
|
-
let messageId = persisted?.messageId;
|
|
70
|
-
if (!persisted) {
|
|
71
|
-
assistantAt =
|
|
72
|
-
Number.isFinite(Number(meta.assistantAt)) && Number(meta.assistantAt) > 0
|
|
73
|
-
? Number(meta.assistantAt)
|
|
74
|
-
: Date.now();
|
|
75
|
-
meta.assistantAt = assistantAt;
|
|
76
|
-
// The reply this segment becomes is persisted with this stable id (the
|
|
77
|
-
// runtime takes it with assistantAt), so a compaction that drops the
|
|
78
|
-
// reply greys this row.
|
|
79
|
-
if (!(typeof meta.assistantMessageId === 'string' && meta.assistantMessageId)) {
|
|
80
|
-
meta.assistantMessageId = newTranscriptMessageId();
|
|
81
|
-
}
|
|
82
|
-
messageId = meta.assistantMessageId;
|
|
83
|
-
}
|
|
103
|
+
const { id, at, messageId } = claimAssistantIdentity(stream);
|
|
104
|
+
stream.assistantIdentity = null;
|
|
105
|
+
stream.currentAssistantId = id;
|
|
84
106
|
// Do NOT reset currentAssistantText here: the first onTextDelta has
|
|
85
107
|
// already accumulated the opening chunk before this batched flush runs.
|
|
86
108
|
// Segment resets are owned by closeAssistantSegment(). Seed the new row
|
|
87
109
|
// with the already-visible text so the ● gutter and the first body line
|
|
88
110
|
// appear in the SAME set()/emit() — no empty "●-only" row.
|
|
89
|
-
stream.updateStreamingTail(
|
|
111
|
+
stream.updateStreamingTail(id, {
|
|
90
112
|
text: String(initialText || ''),
|
|
91
|
-
at
|
|
113
|
+
at,
|
|
92
114
|
messageId,
|
|
93
115
|
...stream.routeMeta,
|
|
94
116
|
});
|
|
@@ -96,6 +118,85 @@ function ensureAssistant(stream, initialText = '') {
|
|
|
96
118
|
return stream.currentAssistantId;
|
|
97
119
|
}
|
|
98
120
|
|
|
121
|
+
// The desktop paints streamed text before its line completes; the terminal
|
|
122
|
+
// keeps the line-gated tail below. `streamingPartial` is the unfinished line
|
|
123
|
+
// beyond the published tail text (`from` is that text's length), cut from the
|
|
124
|
+
// same leak-guarded text the tail is, never raw provider output. Before the
|
|
125
|
+
// row's first completed line there is no tail: the partial then carries all
|
|
126
|
+
// visible text so far plus the row identity (`tail`) the row will take over.
|
|
127
|
+
// Terminal projections drop the field (session-proxy/projection.mjs).
|
|
128
|
+
function partialNow(stream) {
|
|
129
|
+
const text = stream.currentAssistantText;
|
|
130
|
+
const id = stream.currentAssistantId;
|
|
131
|
+
if (id != null) {
|
|
132
|
+
const tail = stream.getState().streamingTail;
|
|
133
|
+
if (!tail || tail.id !== id) return null;
|
|
134
|
+
const shown = typeof tail.text === 'string' ? tail.text : '';
|
|
135
|
+
if (text.length <= shown.length || !text.startsWith(shown)) return null;
|
|
136
|
+
return { id, from: shown.length, text: text.slice(shown.length) };
|
|
137
|
+
}
|
|
138
|
+
// Same rule as the row itself: nothing appears before visible content.
|
|
139
|
+
if (!text.trim()) return null;
|
|
140
|
+
const identity = claimAssistantIdentity(stream);
|
|
141
|
+
return {
|
|
142
|
+
id: identity.id,
|
|
143
|
+
from: 0,
|
|
144
|
+
text,
|
|
145
|
+
tail: {
|
|
146
|
+
kind: 'assistant',
|
|
147
|
+
id: identity.id,
|
|
148
|
+
streaming: true,
|
|
149
|
+
at: identity.at,
|
|
150
|
+
messageId: identity.messageId,
|
|
151
|
+
...stream.routeMeta,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function samePartial(left, right) {
|
|
157
|
+
if (left === right) return true;
|
|
158
|
+
if (!left || !right) return false;
|
|
159
|
+
return left.id === right.id && left.from === right.from && left.text === right.text && !left.tail === !right.tail;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function clearPartialTimer(stream) {
|
|
163
|
+
if (stream.partialTimer === null) return;
|
|
164
|
+
clearTimeout(stream.partialTimer);
|
|
165
|
+
stream.partialTimer = null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function publishPartial(stream) {
|
|
169
|
+
clearPartialTimer(stream);
|
|
170
|
+
if (!stream.isCurrentTurn()) return;
|
|
171
|
+
const current = stream.getState().streamingPartial ?? null;
|
|
172
|
+
// A transcript replacement cleared the partial this segment showed: the
|
|
173
|
+
// segment stays gone, like a tail the replacement dropped.
|
|
174
|
+
if (stream.partialShown && current === null) stream.partialDropped = true;
|
|
175
|
+
if (stream.partialDropped) return;
|
|
176
|
+
const next = partialNow(stream);
|
|
177
|
+
stream.partialShown = next !== null;
|
|
178
|
+
if (samePartial(current, next)) return;
|
|
179
|
+
stream.partialPublishedAt = Date.now();
|
|
180
|
+
stream.set({ streamingPartial: next });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function schedulePartial(stream) {
|
|
184
|
+
if (stream.partialTimer !== null) return;
|
|
185
|
+
const wait = Math.max(STREAM_BATCH_INTERVAL_MS, PARTIAL_INTERVAL_MS - (Date.now() - stream.partialPublishedAt));
|
|
186
|
+
stream.partialTimer = setTimeout(() => {
|
|
187
|
+
stream.partialTimer = null;
|
|
188
|
+
flushStreamBatch(stream);
|
|
189
|
+
}, wait);
|
|
190
|
+
stream.partialTimer?.unref?.();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// The segment's text settled (or was dropped): no partial line outlives it.
|
|
194
|
+
function clearPartial(stream) {
|
|
195
|
+
clearPartialTimer(stream);
|
|
196
|
+
stream.partialShown = false;
|
|
197
|
+
if (stream.getState().streamingPartial != null && stream.isCurrentTurn()) stream.set({ streamingPartial: null });
|
|
198
|
+
}
|
|
199
|
+
|
|
99
200
|
function resetLineScan(stream) {
|
|
100
201
|
stream.scanLen = 0;
|
|
101
202
|
stream.lastNewlineIdx = -1;
|
|
@@ -107,7 +208,10 @@ function closeAssistantSegment(stream) {
|
|
|
107
208
|
stream.currentAssistantId = null;
|
|
108
209
|
stream.currentAssistantText = '';
|
|
109
210
|
stream.claimPersistedAssistant = false;
|
|
211
|
+
stream.assistantIdentity = null;
|
|
110
212
|
resetLineScan(stream);
|
|
213
|
+
clearPartial(stream);
|
|
214
|
+
stream.partialDropped = false;
|
|
111
215
|
}
|
|
112
216
|
|
|
113
217
|
export function commitAssistantSegment(stream, { sealToolBlock = false } = {}) {
|
|
@@ -173,12 +277,14 @@ function flushTextBatch(stream) {
|
|
|
173
277
|
const { getState, set } = stream;
|
|
174
278
|
const visibleText = streamingVisibleTextNow(stream);
|
|
175
279
|
const patch = {};
|
|
280
|
+
let rowCreated = false;
|
|
176
281
|
// Do NOT create the assistant row (and scroll the transcript) before there
|
|
177
282
|
// is a completed line with VISIBLE content: the row appears together with
|
|
178
283
|
// its first visible line. `.trim()` also guards a response that opens with
|
|
179
284
|
// leading newlines, whose blank first line would reserve rows and scroll
|
|
180
285
|
// onto an empty band until a non-blank line lands.
|
|
181
286
|
if (stream.currentAssistantId || visibleText.trim()) {
|
|
287
|
+
rowCreated = !stream.currentAssistantId;
|
|
182
288
|
const id = ensureAssistant(stream, visibleText);
|
|
183
289
|
const current = getState().streamingTail;
|
|
184
290
|
if (!current || current.id !== id || !Object.is(current.text, visibleText)) {
|
|
@@ -214,6 +320,9 @@ function flushTextBatch(stream) {
|
|
|
214
320
|
set(patch);
|
|
215
321
|
}
|
|
216
322
|
stream.pendingThinkingLastEndedAt = 0;
|
|
323
|
+
// A completed line created or moved the tail: the partial line restarts
|
|
324
|
+
// after it in the same frame, so the two never disagree on screen.
|
|
325
|
+
if (rowCreated || patch.streamingTail) publishPartial(stream);
|
|
217
326
|
}
|
|
218
327
|
|
|
219
328
|
function thinkingSpinnerPatch(stream, thinkingElapsedMs) {
|
|
@@ -256,7 +365,7 @@ function flushThinkBatch(stream) {
|
|
|
256
365
|
stream.publishedThinkingActive = nextThinkingActive;
|
|
257
366
|
}
|
|
258
367
|
|
|
259
|
-
|
|
368
|
+
function flushPendingBatches(stream) {
|
|
260
369
|
if (stream.batchTimer !== null) {
|
|
261
370
|
clearTimeout(stream.batchTimer);
|
|
262
371
|
stream.batchTimer = null;
|
|
@@ -265,6 +374,7 @@ export function flushStreamBatch(stream) {
|
|
|
265
374
|
stream.pendingTextFlush = false;
|
|
266
375
|
stream.pendingThinkFlush = false;
|
|
267
376
|
stream.pendingThinkingLastEndedAt = 0;
|
|
377
|
+
clearPartialTimer(stream);
|
|
268
378
|
return;
|
|
269
379
|
}
|
|
270
380
|
if (stream.pendingTextFlush) {
|
|
@@ -277,9 +387,17 @@ export function flushStreamBatch(stream) {
|
|
|
277
387
|
}
|
|
278
388
|
}
|
|
279
389
|
|
|
390
|
+
// A forced flush is a boundary (tool call, notice, finalization, error, or
|
|
391
|
+
// the partial-line tick): the line-gated batch lands, and so does the
|
|
392
|
+
// desktop's unfinished line.
|
|
393
|
+
export function flushStreamBatch(stream) {
|
|
394
|
+
flushPendingBatches(stream);
|
|
395
|
+
publishPartial(stream);
|
|
396
|
+
}
|
|
397
|
+
|
|
280
398
|
function scheduleStreamFlush(stream) {
|
|
281
399
|
if (stream.batchTimer !== null) return; // already scheduled; do not re-arm
|
|
282
|
-
stream.batchTimer = setTimeout(() =>
|
|
400
|
+
stream.batchTimer = setTimeout(() => flushPendingBatches(stream), STREAM_BATCH_INTERVAL_MS);
|
|
283
401
|
stream.batchTimer?.unref?.(); // don't prevent process exit
|
|
284
402
|
}
|
|
285
403
|
|
|
@@ -306,6 +424,7 @@ export function appendTextDelta(stream, textChunk) {
|
|
|
306
424
|
stream.pendingTextFlush = true;
|
|
307
425
|
if (thinkingLastEndedAt) stream.pendingThinkingLastEndedAt = thinkingLastEndedAt;
|
|
308
426
|
scheduleStreamFlush(stream);
|
|
427
|
+
schedulePartial(stream);
|
|
309
428
|
}
|
|
310
429
|
|
|
311
430
|
// Mid-turn assistant text that precedes a tool call from a provider that only
|
|
@@ -320,6 +439,9 @@ export function appendAssistantText(stream, full, { committed = false } = {}) {
|
|
|
320
439
|
// id. Any other text (a tool preamble published before its message commits)
|
|
321
440
|
// leaves an earlier recorded id unclaimed, so drop it.
|
|
322
441
|
stream.claimPersistedAssistant = committed;
|
|
442
|
+
// A committed message's row takes its persisted identity, never one claimed
|
|
443
|
+
// earlier for partial text that has since been retracted.
|
|
444
|
+
if (committed && !stream.currentAssistantId) stream.assistantIdentity = null;
|
|
323
445
|
if (!committed && stream.transcriptMeta && typeof stream.transcriptMeta === 'object') {
|
|
324
446
|
stream.transcriptMeta.persistedAssistant = null;
|
|
325
447
|
}
|
|
@@ -364,6 +486,8 @@ export function resetStreamedText(stream, { chars, reasoning } = {}) {
|
|
|
364
486
|
stream.currentAssistantId = null;
|
|
365
487
|
}
|
|
366
488
|
}
|
|
489
|
+
// The retraction applies to the desktop's partial line in the same frame.
|
|
490
|
+
publishPartial(stream);
|
|
367
491
|
return true;
|
|
368
492
|
}
|
|
369
493
|
|
|
@@ -508,18 +632,37 @@ export function settleFinalText(stream, finalText) {
|
|
|
508
632
|
text: stream.currentAssistantText || stream.assistantText,
|
|
509
633
|
});
|
|
510
634
|
}
|
|
635
|
+
clearPartial(stream);
|
|
511
636
|
}
|
|
512
637
|
|
|
513
638
|
// On abort, preserve only the still-open segment: tool boundaries already
|
|
514
639
|
// sealed prior progress segments into their own rows, and replaying the
|
|
515
640
|
// turn-global text would create one giant duplicate after the cancelled card.
|
|
516
641
|
export function settleOpenSegmentOnCancel(stream) {
|
|
517
|
-
if (
|
|
518
|
-
|
|
519
|
-
|
|
642
|
+
if (stream.currentAssistantText.trim()) {
|
|
643
|
+
const id = stream.currentAssistantId || ensureAssistant(stream, stream.currentAssistantText);
|
|
644
|
+
stream.settleStreamingTail(id, { text: stream.currentAssistantText });
|
|
645
|
+
}
|
|
646
|
+
clearPartial(stream);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// A segment that never completed a line has no tail, only the partial row the
|
|
650
|
+
// desktop shows. A turn that ends without finalizing it (provider error,
|
|
651
|
+
// aborted tool loop) keeps that text as its row, like cancellation does. A
|
|
652
|
+
// transcript replacement cleared the partial, and then the text stays gone.
|
|
653
|
+
function settlePartialOnlySegment(stream) {
|
|
654
|
+
const identity = stream.assistantIdentity;
|
|
655
|
+
const open = stream.getState().streamingPartial;
|
|
656
|
+
if (stream.currentAssistantId || stream.partialDropped || !identity || open?.id !== identity.id) return;
|
|
657
|
+
if (!stream.isCurrentTurn()) return;
|
|
658
|
+
const text = stream.currentAssistantText;
|
|
659
|
+
if (!text.trim()) return;
|
|
660
|
+
stream.settleStreamingTail(ensureAssistant(stream, text), { text });
|
|
520
661
|
}
|
|
521
662
|
|
|
522
663
|
export function settleStreamingTailAtClose(stream) {
|
|
664
|
+
settlePartialOnlySegment(stream);
|
|
665
|
+
clearPartial(stream);
|
|
523
666
|
const id = stream.currentAssistantId;
|
|
524
667
|
if (!id || stream.getState().streamingTail?.id !== id) return;
|
|
525
668
|
if (stream.currentAssistantText.trim()) stream.settleStreamingTail(id, { text: stream.currentAssistantText });
|
package/src/tui/session/turn.mjs
CHANGED
|
@@ -15,6 +15,7 @@ import { preserveGoalStateAfterTurn } from './goal-turn-state.mjs';
|
|
|
15
15
|
export { preserveGoalStateAfterTurn } from './goal-turn-state.mjs';
|
|
16
16
|
export { transcriptToolCallDisplayMode } from './turn-tool-cards.mjs';
|
|
17
17
|
import { isRejected429, safeErrorDetails } from '../../runtime/shared/error-presentation.mjs';
|
|
18
|
+
import { QUOTA_KINDS, providerErrorKind } from '../../runtime/agent/orchestrator/providers/provider-error-kind.mjs';
|
|
18
19
|
import { registerTaskWaitSteeringCheck } from '../../runtime/agent/orchestrator/session/task-wait-control.mjs';
|
|
19
20
|
import { promptDisplayText, STEERING_SUPPRESSED_DISPLAY } from './queue-helpers.mjs';
|
|
20
21
|
import { yieldToRenderer } from './render-timing.mjs';
|
|
@@ -47,14 +48,11 @@ import {
|
|
|
47
48
|
startLiveTail,
|
|
48
49
|
} from './turn-tool-cards.mjs';
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
// A usage limit is exactly a spent quota, a plan-gated feature or a billing
|
|
52
|
+
// refusal; overloads, rate limits and server faults recover by waiting.
|
|
53
|
+
function isUsageLimitError(error, kind = providerErrorKind(error)) {
|
|
51
54
|
if (!error || isRejected429(error)) return false;
|
|
52
|
-
|
|
53
|
-
if (error?.providerQuota === true || error?.quotaExceeded === true || status === 429) return true;
|
|
54
|
-
const text = String(error?.message || error);
|
|
55
|
-
return /\brate[_ -]?limit\b|\bquota\b|too many requests|resource exhausted|insufficient_quota|quota_exceeded/i.test(
|
|
56
|
-
text
|
|
57
|
-
);
|
|
55
|
+
return QUOTA_KINDS.has(kind.kind);
|
|
58
56
|
}
|
|
59
57
|
|
|
60
58
|
function turnOutcome(cancelled, failed) {
|
|
@@ -165,7 +163,7 @@ function promptRestoreFor(displayText, options, submittedIds, content = null) {
|
|
|
165
163
|
};
|
|
166
164
|
}
|
|
167
165
|
|
|
168
|
-
function commitPromptRestore(flags, turn) {
|
|
166
|
+
export function commitPromptRestore(flags, turn) {
|
|
169
167
|
const restore = flags.activePromptRestore;
|
|
170
168
|
if (!restore) return;
|
|
171
169
|
if (!turn.promptCommitted && typeof restore.onCommitted === 'function') {
|
|
@@ -389,16 +387,27 @@ function toolHandlers(ctx) {
|
|
|
389
387
|
};
|
|
390
388
|
}
|
|
391
389
|
|
|
392
|
-
function streamHandlers(ctx) {
|
|
390
|
+
export function streamHandlers(ctx) {
|
|
393
391
|
const { isCurrentTurn, stream } = ctx;
|
|
394
392
|
return {
|
|
395
393
|
onStageChange: async (stage, detail = null) => {
|
|
396
|
-
if (isCurrentTurn())
|
|
394
|
+
if (!isCurrentTurn()) return;
|
|
395
|
+
// A runtime notice (e.g. a tool the provider left out of the request)
|
|
396
|
+
// becomes a transcript notice the TUI and desktop render.
|
|
397
|
+
if (stage === 'notice') {
|
|
398
|
+
flushStreamBatch(stream);
|
|
399
|
+
ctx.pushNotice(detail?.message, detail?.tone === 'warn' ? 'warn' : 'info', { transcript: true });
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
await applyStageChange(stream, stage, detail);
|
|
397
403
|
},
|
|
398
404
|
onTextDelta: (chunk) => {
|
|
399
405
|
const textChunk = String(chunk ?? '');
|
|
400
406
|
if (!textChunk || !isCurrentTurn()) return;
|
|
401
|
-
|
|
407
|
+
// Same verdict as the runtime's interruption check (finalizeInterruptedTurn
|
|
408
|
+
// trims): whitespace-only text is not output, so it must not commit the
|
|
409
|
+
// prompt — the runtime would rewind it while the host skipped the requeue.
|
|
410
|
+
if (textChunk.trim()) ctx.markPromptCommitted();
|
|
402
411
|
appendTextDelta(stream, textChunk);
|
|
403
412
|
},
|
|
404
413
|
onTextReset: (reset = {}) => (isCurrentTurn() ? resetStreamedText(stream, reset) : false),
|
|
@@ -448,13 +457,30 @@ export function failTurn(ctx, error) {
|
|
|
448
457
|
}
|
|
449
458
|
turn.failed = true;
|
|
450
459
|
cards.aggregates.finalizeToolHeaders();
|
|
451
|
-
|
|
460
|
+
// Presentation only: legacy untyped failure text may still name a usage limit.
|
|
461
|
+
const errorKind = providerErrorKind(error, { legacyQuotaWording: true });
|
|
462
|
+
// The UI reads this descriptor instead of re-parsing the error text.
|
|
463
|
+
turn.errorKind = {
|
|
464
|
+
kind: errorKind.kind,
|
|
465
|
+
code: errorKind.code,
|
|
466
|
+
status: errorKind.status,
|
|
467
|
+
retryAfterMs: errorKind.retryAfterMs,
|
|
468
|
+
resetAt: errorKind.resetAt,
|
|
469
|
+
};
|
|
470
|
+
turn.usageLimited = isUsageLimitError(error, errorKind);
|
|
452
471
|
const exhausted = error?.quotaExhausted;
|
|
453
|
-
|
|
472
|
+
// Quota metadata: the pool's validated exhaustion, or a spent quota whose
|
|
473
|
+
// provider named the real reset time.
|
|
474
|
+
const resetKnown = errorKind.kind === 'quota_exhausted' && Number.isFinite(errorKind.resetAt);
|
|
475
|
+
if ((exhausted && typeof exhausted === 'object') || resetKnown) {
|
|
476
|
+
const source = exhausted && typeof exhausted === 'object' ? exhausted : {};
|
|
477
|
+
let resetAt = null;
|
|
478
|
+
if (Number.isFinite(source.resetAt)) resetAt = source.resetAt;
|
|
479
|
+
else if (Number.isFinite(errorKind.resetAt)) resetAt = errorKind.resetAt;
|
|
454
480
|
turn.quota = {
|
|
455
|
-
provider: String(
|
|
456
|
-
model: String(
|
|
457
|
-
resetAt
|
|
481
|
+
provider: String(source.provider || turn.routeMeta?.provider || ''),
|
|
482
|
+
model: String(source.model || turn.routeMeta?.model || ''),
|
|
483
|
+
resetAt,
|
|
458
484
|
};
|
|
459
485
|
}
|
|
460
486
|
turn.failureDetail = toolErrorDisplay(error, 'turn').replace(/^Error:\s*/i, '');
|
|
@@ -485,6 +511,7 @@ export function turnDoneItem({ turn, stream, cards, getState, nextId }) {
|
|
|
485
511
|
...(turn.failureDiagnostic ? { errorDetails: turn.failureDiagnostic } : {}),
|
|
486
512
|
...turn.routeMeta,
|
|
487
513
|
...(turn.failed && turn.quota ? { quota: turn.quota } : {}),
|
|
514
|
+
...(turn.failed && turn.errorKind ? { errorKind: turn.errorKind } : {}),
|
|
488
515
|
};
|
|
489
516
|
}
|
|
490
517
|
|
|
@@ -564,6 +591,7 @@ async function settleTurn(ctx) {
|
|
|
564
591
|
result: turn.askResult,
|
|
565
592
|
session: runtime.session || null,
|
|
566
593
|
error: turn.failureDetail || null,
|
|
594
|
+
errorKind: turn.failed ? turn.errorKind || null : null,
|
|
567
595
|
};
|
|
568
596
|
// Publish termination before optional Goal work can delay the caller.
|
|
569
597
|
bag.settleSteeredSubmissions?.(turn.epoch, detail);
|
|
@@ -626,6 +654,8 @@ export function createRunTurn(bag) {
|
|
|
626
654
|
set({
|
|
627
655
|
busy: true,
|
|
628
656
|
lastTurn: null,
|
|
657
|
+
// A turn that unwound stale never cleared its desktop partial line.
|
|
658
|
+
...(getState().streamingPartial ? { streamingPartial: null } : {}),
|
|
629
659
|
spinner: {
|
|
630
660
|
active: true,
|
|
631
661
|
verb: pickVerb(turn.index),
|
|
@@ -65,7 +65,7 @@ export function statuslineFooterIdentityChanged(args, lastArgs) {
|
|
|
65
65
|
if (!lastArgs) return true;
|
|
66
66
|
if (args.sessionId !== lastArgs.sessionId) return true;
|
|
67
67
|
if (args.provider !== lastArgs.provider || args.model !== lastArgs.model) return true;
|
|
68
|
-
if (args.effort !== lastArgs.effort || args.fast !== lastArgs.fast) return true;
|
|
68
|
+
if (args.effort !== lastArgs.effort || args.fast !== lastArgs.fast || args.ultra !== lastArgs.ultra) return true;
|
|
69
69
|
if (args.contextWindow !== lastArgs.contextWindow || args.rawContextWindow !== lastArgs.rawContextWindow) return true;
|
|
70
70
|
if (args.displayContextWindow !== lastArgs.displayContextWindow) return true;
|
|
71
71
|
if (args.compactBoundaryTokens !== lastArgs.compactBoundaryTokens) return true;
|
|
@@ -25,8 +25,7 @@ let _hiddenStatuslineAgents = null;
|
|
|
25
25
|
function normalizeAgentWorkerForStatusline(worker = {}) {
|
|
26
26
|
const tag = String(worker.tag || worker.agent || worker.name || '').trim();
|
|
27
27
|
if (!tag) return null;
|
|
28
|
-
const
|
|
29
|
-
const status = isActiveAgentEntry(statuses) ? 'running' : 'idle';
|
|
28
|
+
const status = isActiveAgentEntry(lifecycleStatuses(worker)) ? 'running' : 'idle';
|
|
30
29
|
return {
|
|
31
30
|
tag,
|
|
32
31
|
status,
|
|
@@ -63,11 +62,12 @@ function normalizeAgentJobForStatusline(job = {}) {
|
|
|
63
62
|
model: job.model || null,
|
|
64
63
|
};
|
|
65
64
|
}
|
|
66
|
-
|
|
65
|
+
const lifecycle = lifecycleStatuses(job);
|
|
66
|
+
if (!isActiveAgentEntry(lifecycle)) return null;
|
|
67
67
|
return {
|
|
68
68
|
tag,
|
|
69
69
|
taskId,
|
|
70
|
-
status: isQueuedAgentEntry(
|
|
70
|
+
status: isQueuedAgentEntry(lifecycle) ? 'queued' : 'running',
|
|
71
71
|
startedAtMs,
|
|
72
72
|
agent: job.agent || null,
|
|
73
73
|
stage: job.stage || job.workerStatus || job.status || null,
|
|
@@ -214,6 +214,17 @@ function agentStatusValues(value = {}) {
|
|
|
214
214
|
.filter((status, index, values) => Boolean(status) && values.indexOf(status) === index);
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
/** The statuses that decide whether an entry is working. `status` is the
|
|
218
|
+
* lifecycle; `stage` is the runtime phase copied in beside it, which can read
|
|
219
|
+
* idle/done/error mid-work, so it decides only for an entry with no status. A
|
|
220
|
+
* cancel in either field still counts (it keeps both in play). */
|
|
221
|
+
function lifecycleStatuses(value = {}) {
|
|
222
|
+
const statuses = agentStatusValues(value);
|
|
223
|
+
if (statuses.some((status) => /cancel|killed/i.test(status))) return statuses;
|
|
224
|
+
const status = String(value.status || '').trim();
|
|
225
|
+
return status ? [status] : statuses;
|
|
226
|
+
}
|
|
227
|
+
|
|
217
228
|
function isTerminalAgentEntry(statuses = []) {
|
|
218
229
|
return statuses.some((status) => TERMINAL_AGENT_STATUS.test(String(status || '')));
|
|
219
230
|
}
|
package/src/ui/statusline.mjs
CHANGED
|
@@ -197,6 +197,7 @@ export async function renderStatusline({
|
|
|
197
197
|
model = '',
|
|
198
198
|
effort = '',
|
|
199
199
|
fast = false,
|
|
200
|
+
ultra = false,
|
|
200
201
|
cwd = '',
|
|
201
202
|
stats,
|
|
202
203
|
sessionId,
|
|
@@ -223,6 +224,7 @@ export async function renderStatusline({
|
|
|
223
224
|
model,
|
|
224
225
|
effort,
|
|
225
226
|
fast,
|
|
227
|
+
ultra,
|
|
226
228
|
cwd,
|
|
227
229
|
stats,
|
|
228
230
|
sessionId,
|
|
@@ -233,7 +235,7 @@ export async function renderStatusline({
|
|
|
233
235
|
...displayArgs,
|
|
234
236
|
});
|
|
235
237
|
} catch {
|
|
236
|
-
return fallbackLine({ provider, model, effort, fast, cwd, stats, ...displayArgs });
|
|
238
|
+
return fallbackLine({ provider, model, effort, fast, ultra, cwd, stats, ...displayArgs });
|
|
237
239
|
}
|
|
238
240
|
}
|
|
239
241
|
|
|
@@ -244,6 +246,7 @@ function renderNativeStatusline({
|
|
|
244
246
|
model = '',
|
|
245
247
|
effort = '',
|
|
246
248
|
fast = false,
|
|
249
|
+
ultra = false,
|
|
247
250
|
stats,
|
|
248
251
|
sessionId,
|
|
249
252
|
contextWindow = 0,
|
|
@@ -275,7 +278,7 @@ function renderNativeStatusline({
|
|
|
275
278
|
|
|
276
279
|
const sep = ` ${D}│${R} `;
|
|
277
280
|
const l1Parts = [
|
|
278
|
-
formatModelSegment({ provider, model, effort, fast, cols }),
|
|
281
|
+
formatModelSegment({ provider, model, effort, fast, ultra, cols }),
|
|
279
282
|
formatContextSegment(ctxPct, cols, s.currentContextSource),
|
|
280
283
|
...quotaSegmentsFor({ provider, model, effort, fast, sessionId, clientHostPid, gatewayStatus, cols }),
|
|
281
284
|
].filter(Boolean);
|
|
@@ -664,6 +667,7 @@ function fallbackLine({
|
|
|
664
667
|
model = '',
|
|
665
668
|
effort = '',
|
|
666
669
|
fast = false,
|
|
670
|
+
ultra = false,
|
|
667
671
|
cwd: _cwd = '',
|
|
668
672
|
stats,
|
|
669
673
|
contextWindow = 0,
|
|
@@ -687,7 +691,7 @@ function fallbackLine({
|
|
|
687
691
|
});
|
|
688
692
|
const sep = ` ${D}│${R} `;
|
|
689
693
|
const parts = [
|
|
690
|
-
formatModelSegment({ provider, model, effort, fast, cols }),
|
|
694
|
+
formatModelSegment({ provider, model, effort, fast, ultra, cols }),
|
|
691
695
|
formatContextSegment(ctxPct, cols, s.currentContextSource),
|
|
692
696
|
].filter(Boolean);
|
|
693
697
|
if (!parts.length) return statusSubtle('> mixdog');
|
|
@@ -213,12 +213,43 @@ function healIncompleteLink(text, isPendingLocalPath) {
|
|
|
213
213
|
return `${prefix}[${closeEmphasis(caption)}${']'.repeat(Math.max(0, depth - 1))}]()`;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
const PIPE_ROW = /^ {0,3}\|/;
|
|
217
|
+
const DELIMITER_ROW = /^ {0,3}\|?\s*:?-+:?\s*(?:\|\s*:?-+:?\s*)*\|?\s*$/;
|
|
218
|
+
const PARTIAL_DELIMITER_ROW = /^ {0,3}\|?[\s:|-]*$/;
|
|
219
|
+
|
|
220
|
+
function tableCells(line) {
|
|
221
|
+
const cells = line.trim().split(/(?<!\\)\|/);
|
|
222
|
+
if (cells[0].trim() === '') cells.shift();
|
|
223
|
+
if (cells.length && cells[cells.length - 1].trim() === '') cells.pop();
|
|
224
|
+
return cells.length;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// A table streams in as its header row, then its delimiter row a token at a
|
|
228
|
+
// time. Until the delimiter is complete (and has the header's cell count) the
|
|
229
|
+
// rows are a paragraph of raw pipes, which then re-laid out as a table of a
|
|
230
|
+
// different height — the reply grew and shrank under a followed transcript.
|
|
231
|
+
// Hold both rows back until the table can form in one step.
|
|
232
|
+
function trimPendingTableHead(text) {
|
|
233
|
+
let offset = 0;
|
|
234
|
+
for (const blank of text.matchAll(/\n[ \t]*\r?\n/g)) offset = blank.index + blank[0].length;
|
|
235
|
+
const block = text.slice(offset);
|
|
236
|
+
const lines = block.split('\n').map((line) => line.replace(/\r$/, ''));
|
|
237
|
+
if (lines.length === 0 || lines.length > 2 || !PIPE_ROW.test(lines[0])) return text;
|
|
238
|
+
if (lines.length === 2) {
|
|
239
|
+
const delimiter = lines[1];
|
|
240
|
+
if (!PARTIAL_DELIMITER_ROW.test(delimiter)) return text;
|
|
241
|
+
if (DELIMITER_ROW.test(delimiter) && tableCells(delimiter) === tableCells(lines[0])) return text;
|
|
242
|
+
}
|
|
243
|
+
return text.slice(0, offset);
|
|
244
|
+
}
|
|
245
|
+
|
|
216
246
|
export function healStreamingMarkdownTail(text, isPendingLocalPath) {
|
|
217
|
-
const
|
|
247
|
+
const source = String(text ?? '');
|
|
248
|
+
const fence = source.includes('`') || source.includes('~') ? openFence(source) : null;
|
|
249
|
+
if (fence) return trimPartialClosingFence(source, fence);
|
|
250
|
+
const value = source.includes('|') ? trimPendingTableHead(source) : source;
|
|
218
251
|
const hasSyntax = HEALABLE_MARKDOWN_SYNTAX.test(value);
|
|
219
252
|
if (!value || (!hasSyntax && !isPendingLocalPath)) return value;
|
|
220
|
-
const fence = openFence(value);
|
|
221
|
-
if (fence) return trimPartialClosingFence(value, fence);
|
|
222
253
|
const healed = hasSyntax
|
|
223
254
|
? closeEmphasis(healIncompleteLink(closeInlineCode(value, isPendingLocalPath), isPendingLocalPath))
|
|
224
255
|
: value;
|