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
|
@@ -5,6 +5,7 @@ import { formatLocalAndUtcTimestamp } from '../../../../shared/time-format.mjs';
|
|
|
5
5
|
import { SUMMARY_PREFIX } from '../compact.mjs';
|
|
6
6
|
import { isProtectedContextUserMessage } from '../compact/messages.mjs';
|
|
7
7
|
import { attachmentTextForPart, isAttachmentReference } from '../../../../attachments/store.mjs';
|
|
8
|
+
import { samePath } from '../../../../shared/worktrees/paths.mjs';
|
|
8
9
|
|
|
9
10
|
export function promptContentText(content) {
|
|
10
11
|
if (typeof content === 'string') return content;
|
|
@@ -144,7 +145,11 @@ function replaceSystemMessageContent(session, target, content) {
|
|
|
144
145
|
return true;
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
export function refreshSessionBp3Environment(session,
|
|
148
|
+
export function refreshSessionBp3Environment(session, requestedCwd) {
|
|
149
|
+
// A staged workspace change (see stageWorkspaceReroot) keeps the system
|
|
150
|
+
// prompt rooted where it was until the next re-root: the `# Session` Cwd
|
|
151
|
+
// stays the rooted one, the change reaches the model as a tail notice.
|
|
152
|
+
const cwd = session?.workspaceReroot?.rootCwd || requestedCwd;
|
|
148
153
|
// Split layout (bp3EnvSplit): the volatile environment lives in its own
|
|
149
154
|
// UNMARKED cacheTier:'env' system block; the tier3 core block is never
|
|
150
155
|
// rewritten, so the refresh cannot invalidate the BP3 cache write.
|
|
@@ -242,20 +247,12 @@ export function replaceWorkspaceEnvironment(environmentTail, environmentContext)
|
|
|
242
247
|
}
|
|
243
248
|
|
|
244
249
|
/**
|
|
245
|
-
* Re-root
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* a full snapshot.
|
|
250
|
-
* @param {object} session
|
|
251
|
-
* @param {{ cwd: string, environmentContext?: string, coreMemoryContext?: string, instructionFilesContext?: string }} context
|
|
252
|
-
* @returns {boolean}
|
|
250
|
+
* Re-root a session's prompt at a workspace in place: environment facts,
|
|
251
|
+
* project memory and instruction files are replaced (never appended), then
|
|
252
|
+
* the `# Session` block is rebuilt for `cwd`. Messages are replaced, not
|
|
253
|
+
* mutated, so delta saves write a full snapshot.
|
|
253
254
|
*/
|
|
254
|
-
|
|
255
|
-
session,
|
|
256
|
-
{ cwd, environmentContext, coreMemoryContext, instructionFilesContext } = {}
|
|
257
|
-
) {
|
|
258
|
-
if (!session) return false;
|
|
255
|
+
function rerootSessionWorkspace(session, { cwd, environmentContext, coreMemoryContext, instructionFilesContext }) {
|
|
259
256
|
if (typeof session.bp3EnvironmentContext === 'string') {
|
|
260
257
|
session.bp3EnvironmentContext = replaceWorkspaceEnvironment(session.bp3EnvironmentContext, environmentContext);
|
|
261
258
|
}
|
|
@@ -275,7 +272,204 @@ export function refreshSessionWorkspaceContext(
|
|
|
275
272
|
return refreshSessionBp3Environment(session, cwd);
|
|
276
273
|
}
|
|
277
274
|
|
|
275
|
+
const SESSION_BLOCK_CWD_RE = /(?:^|\n)# Session\nCwd: ([^\n]+)/;
|
|
276
|
+
const WORKER_ENV_CWD_RE = /(?:^|\n)- Cwd: ([^\n]+?) — the active Project root/;
|
|
277
|
+
|
|
278
|
+
function textOf(message) {
|
|
279
|
+
return typeof message?.content === 'string' ? message.content : '';
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* The workspace the session's system prompt currently presents: its Cwd and
|
|
284
|
+
* the environment facts, project memory and instruction-files slices, read
|
|
285
|
+
* back from the blocks refreshSessionBp3Environment/composeSystemPrompt wrote.
|
|
286
|
+
*/
|
|
287
|
+
function presentedWorkspace(session) {
|
|
288
|
+
const core = session.bp3EnvSplit === true ? textOf(bp3SystemMessage(session)) : String(session.bp3CoreContext || '');
|
|
289
|
+
const instructionAt = bp3SliceAt(core, INSTRUCTION_FILES_HEADING);
|
|
290
|
+
const head = instructionAt ? core.slice(0, instructionAt.cut) : core;
|
|
291
|
+
const memory = (head ? head.split(BP3_PART_SEPARATOR) : []).find((part) => part.startsWith(CORE_MEMORY_HEADING));
|
|
292
|
+
const tail = typeof session.bp3EnvironmentContext === 'string' ? session.bp3EnvironmentContext : '';
|
|
293
|
+
const facts = tail.split(BP3_PART_SEPARATOR)[0] || '';
|
|
294
|
+
const promptText = [textOf(bpEnvSystemMessage(session)), textOf(bp3SystemMessage(session))].join('\n');
|
|
295
|
+
const cwd = promptText.match(SESSION_BLOCK_CWD_RE)?.[1] || facts.match(WORKER_ENV_CWD_RE)?.[1] || null;
|
|
296
|
+
return {
|
|
297
|
+
cwd: cwd ? cwd.trim() : null,
|
|
298
|
+
environmentContext: facts.startsWith('- ') ? facts.trim() : '',
|
|
299
|
+
coreMemoryContext: memory ? memory.slice(CORE_MEMORY_HEADING.length).trim() : '',
|
|
300
|
+
instructionFilesContext: instructionAt ? core.slice(instructionAt.start).trim() : '',
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const WORKSPACE_SLICES = ['environmentContext', 'coreMemoryContext', 'instructionFilesContext'];
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* A workspace change of a session that already has a conversation: the
|
|
308
|
+
* system prompt stays byte-identical (provider prompt cache intact) and the
|
|
309
|
+
* change is staged on `session.workspaceReroot`:
|
|
310
|
+
* rootCwd — the Cwd the system prompt stays rooted at;
|
|
311
|
+
* seen — what the model has been told (the prompt, then acknowledged notices);
|
|
312
|
+
* target — the current workspace, applied to the prompt at the next re-root
|
|
313
|
+
* (compaction, a route change, a cleared conversation).
|
|
314
|
+
* `undefined` slices keep what is there. The state object is replaced, never
|
|
315
|
+
* mutated, so a transaction snapshot of the field restores it exactly.
|
|
316
|
+
*/
|
|
317
|
+
function stageWorkspaceReroot(session, context) {
|
|
318
|
+
const prior = session.workspaceReroot;
|
|
319
|
+
const seen = prior ? prior.seen : presentedWorkspace(session);
|
|
320
|
+
const target = { ...(prior ? prior.target : {}), cwd: String(context.cwd || '').trim() };
|
|
321
|
+
for (const slice of WORKSPACE_SLICES) {
|
|
322
|
+
if (context[slice] !== undefined) target[slice] = trimmedSlice(context[slice]);
|
|
323
|
+
}
|
|
324
|
+
// The move into a worktree belongs to this change only; a later one drops it.
|
|
325
|
+
delete target.move;
|
|
326
|
+
const from = String(context.move?.from || '').trim();
|
|
327
|
+
if (from) target.move = { from, changes: context.move.changes ?? null };
|
|
328
|
+
session.workspaceReroot = {
|
|
329
|
+
version: 1,
|
|
330
|
+
revision: (Number(prior?.revision) || 0) + 1,
|
|
331
|
+
rootCwd: prior ? prior.rootCwd : seen.cwd,
|
|
332
|
+
seen,
|
|
333
|
+
target,
|
|
334
|
+
};
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Re-root an existing session's prompt at a new workspace. A session without
|
|
340
|
+
* a conversation is re-rooted in place (no cache to keep); one with a
|
|
341
|
+
* conversation keeps its system messages untouched and stages the change
|
|
342
|
+
* (stageWorkspaceReroot): the model learns it from the tail notice of its
|
|
343
|
+
* next user turn (snapshotPendingWorkspaceNotice), and the next re-root
|
|
344
|
+
* (applyPendingWorkspaceReroot) rewrites the prompt.
|
|
345
|
+
* `move` ({ from, changes: 'carried'|'left'|null }: the session left the
|
|
346
|
+
* project folder `from` for a worktree) adds to the notice what happened to
|
|
347
|
+
* the uncommitted changes and that paths under `from` now resolve under `cwd`.
|
|
348
|
+
* @param {object} session
|
|
349
|
+
* @param {{ cwd: string, environmentContext?: string, coreMemoryContext?: string, instructionFilesContext?: string, move?: { from: string, changes?: 'carried'|'left'|null } }} context
|
|
350
|
+
* @returns {boolean}
|
|
351
|
+
*/
|
|
352
|
+
export function refreshSessionWorkspaceContext(session, context = {}) {
|
|
353
|
+
if (!session) return false;
|
|
354
|
+
if (hasUserConversationMessage(session.messages)) return stageWorkspaceReroot(session, context);
|
|
355
|
+
applyPendingWorkspaceReroot(session);
|
|
356
|
+
return rerootSessionWorkspace(session, context);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Give `stored` (the canonical transcript) the system prefix of `messages`
|
|
361
|
+
* (a running turn's working array built on it), message objects included.
|
|
362
|
+
*/
|
|
363
|
+
export function syncSystemPrefix(stored, messages) {
|
|
364
|
+
const systemCount = (list) => {
|
|
365
|
+
let count = 0;
|
|
366
|
+
while (count < list.length && list[count]?.role === 'system') count += 1;
|
|
367
|
+
return count;
|
|
368
|
+
};
|
|
369
|
+
stored.splice(0, systemCount(stored), ...messages.slice(0, systemCount(messages)));
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Apply a staged workspace change to the system prompt (the session's own
|
|
374
|
+
* messages, plus `messages` when a running turn works on another array whose
|
|
375
|
+
* system prefix is the session's) and drop the staged state: the prompt now
|
|
376
|
+
* presents the current workspace, so no notice is due any more.
|
|
377
|
+
* @returns {boolean} whether a staged change was applied
|
|
378
|
+
*/
|
|
379
|
+
export function applyPendingWorkspaceReroot(session, messages = session?.messages) {
|
|
380
|
+
const pending = session?.workspaceReroot;
|
|
381
|
+
if (!pending) return false;
|
|
382
|
+
delete session.workspaceReroot;
|
|
383
|
+
const stored = session.messages;
|
|
384
|
+
const other = Array.isArray(messages) && messages !== stored;
|
|
385
|
+
if (other) session.messages = messages;
|
|
386
|
+
try {
|
|
387
|
+
rerootSessionWorkspace(session, pending.target);
|
|
388
|
+
} finally {
|
|
389
|
+
if (other) session.messages = stored;
|
|
390
|
+
}
|
|
391
|
+
if (other && Array.isArray(stored)) syncSystemPrefix(stored, messages);
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function sameWorkspacePath(left, right) {
|
|
396
|
+
return !!left && !!right && samePath(left, right);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/** The lines a move from the project folder into a worktree adds to the notice. */
|
|
400
|
+
function workspaceMoveLines(move, cwd) {
|
|
401
|
+
if (!move?.from || sameWorkspacePath(move.from, cwd)) return [];
|
|
402
|
+
const changes =
|
|
403
|
+
move.changes === 'carried'
|
|
404
|
+
? 'Uncommitted changes were moved into the worktree; ignored files (dependencies, build output, env files) were not.'
|
|
405
|
+
: move.changes === 'left'
|
|
406
|
+
? `Uncommitted changes were left in ${move.from}; they are not present here.`
|
|
407
|
+
: '';
|
|
408
|
+
return [
|
|
409
|
+
changes,
|
|
410
|
+
`For continued work, substitute ${cwd} for the project root ${move.from} in paths mentioned earlier; absolute paths are not remapped automatically. Re-read affected files before editing them.`,
|
|
411
|
+
].filter(Boolean);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function workspaceNoticeContent({ seen, target }) {
|
|
415
|
+
if (!target?.cwd || sameWorkspacePath(seen?.cwd, target.cwd)) return '';
|
|
416
|
+
const changed = (slice) => target[slice] !== undefined && target[slice] !== (seen?.[slice] || '');
|
|
417
|
+
const sections = [
|
|
418
|
+
[
|
|
419
|
+
'# Working Folder Changed',
|
|
420
|
+
`The working folder is now ${target.cwd}. This replaces the Cwd and environment facts given earlier in this conversation; relative paths and shell commands resolve here.`,
|
|
421
|
+
...workspaceMoveLines(target.move, target.cwd),
|
|
422
|
+
changed('environmentContext') ? target.environmentContext : '',
|
|
423
|
+
]
|
|
424
|
+
.filter(Boolean)
|
|
425
|
+
.join('\n'),
|
|
426
|
+
];
|
|
427
|
+
if (changed('instructionFilesContext')) {
|
|
428
|
+
sections.push(
|
|
429
|
+
target.instructionFilesContext
|
|
430
|
+
? `The instruction files below replace all previously provided instruction files.\n\n${target.instructionFilesContext}`
|
|
431
|
+
: 'The new working folder has no instruction files: the previously provided instruction files no longer apply.'
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
if (changed('coreMemoryContext')) {
|
|
435
|
+
sections.push(
|
|
436
|
+
target.coreMemoryContext
|
|
437
|
+
? `The core memory below replaces all previously provided core memory.\n\n${CORE_MEMORY_HEADING}${target.coreMemoryContext}`
|
|
438
|
+
: 'The new working folder has no core memory: the previously provided core memory no longer applies.'
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
return `<system-reminder>\n${sections.join('\n\n')}\n</system-reminder>`;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* The workspace notice the next user turn carries, or null: nothing when the
|
|
446
|
+
* folder did not change from what the model was told, and only the slices
|
|
447
|
+
* that changed. Lifecycle mirrors deferred-tool-delta.mjs (snapshot → acknowledge
|
|
448
|
+
* when the provider accepted the turn), so a failed turn re-sends it.
|
|
449
|
+
* @returns {{ revision: number, content: string } | null}
|
|
450
|
+
*/
|
|
451
|
+
export function snapshotPendingWorkspaceNotice(session) {
|
|
452
|
+
const pending = session?.workspaceReroot;
|
|
453
|
+
if (!pending) return null;
|
|
454
|
+
const content = workspaceNoticeContent(pending);
|
|
455
|
+
return content ? { revision: pending.revision, content } : null;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/** The notice of `revision` reached the model: what it was told is now the target. */
|
|
459
|
+
export function acknowledgePendingWorkspaceNotice(session, revision) {
|
|
460
|
+
const pending = session?.workspaceReroot;
|
|
461
|
+
if (!pending || pending.revision !== Number(revision)) return false;
|
|
462
|
+
const seen = { ...pending.seen, cwd: pending.target.cwd };
|
|
463
|
+
for (const slice of WORKSPACE_SLICES) {
|
|
464
|
+
if (pending.target[slice] !== undefined) seen[slice] = pending.target[slice];
|
|
465
|
+
}
|
|
466
|
+
session.workspaceReroot = { ...pending, seen };
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
|
|
278
470
|
export function resetSessionBp3Environment(session) {
|
|
471
|
+
// A cleared conversation has no cache to keep: the prompt re-roots now.
|
|
472
|
+
applyPendingWorkspaceReroot(session);
|
|
279
473
|
if (session?.bp3EnvSplit === true) {
|
|
280
474
|
const target = bpEnvSystemMessage(session);
|
|
281
475
|
if (!target || typeof session?.bp3EnvironmentContext !== 'string') return false;
|
|
@@ -18,6 +18,7 @@ import { forgetSessionSaveBaseline } from '../store/save-worker.mjs';
|
|
|
18
18
|
import { forgetSessionLoadCache } from '../store/load-cache.mjs';
|
|
19
19
|
import { releaseReadSnapshotScope } from '../../tools/builtin/snapshot-store.mjs';
|
|
20
20
|
import { cancelNativeTasks } from '../../tools/lib/native-spawn-client.mjs';
|
|
21
|
+
import { forgetSideQuestion } from '../side-question-store.mjs';
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Close a session. Plants a `closed=true` tombstone on disk with a bumped
|
|
@@ -66,7 +67,10 @@ export function closeSession(id, reason = 'manual', opts = {}) {
|
|
|
66
67
|
// it once disk generation moves past that. Without this bump the late
|
|
67
68
|
// write could silently overwrite the session after the user resumes
|
|
68
69
|
// it back (BL: burned-session late-save clobber).
|
|
69
|
-
const
|
|
70
|
+
const outcome = { absent: false };
|
|
71
|
+
const newGen = tombstone
|
|
72
|
+
? markSessionClosed(id, reason, { outcome })
|
|
73
|
+
: bumpSessionGeneration(id, reason, { outcome });
|
|
70
74
|
// Durable lifecycle barrier check. ANY nonnumeric result means the barrier
|
|
71
75
|
// is not on disk — a write failure, a liveness/ownership veto, a contended
|
|
72
76
|
// commit lock, or a missing record. Only a failed write publishes a
|
|
@@ -76,7 +80,13 @@ export function closeSession(id, reason = 'manual', opts = {}) {
|
|
|
76
80
|
// crash checkpoint while the session stays open and resumable on disk — the
|
|
77
81
|
// way a failed close silently destroys a turn. Leave every runtime
|
|
78
82
|
// structure intact, surface the cause, and report failure to the caller.
|
|
79
|
-
|
|
83
|
+
//
|
|
84
|
+
// The one exception is a record that was legitimately already gone (never
|
|
85
|
+
// saved, or deleted): the barrier cancelled its pending writes under the
|
|
86
|
+
// commit lock and found no copy on disk or in memory, so there is nothing
|
|
87
|
+
// a late save could clobber and nothing left open to resume. That close
|
|
88
|
+
// succeeds and tears the runtime down normally.
|
|
89
|
+
if (typeof newGen !== 'number' && outcome.absent !== true) {
|
|
80
90
|
reportCloseBarrierFailure({ id, reason, tombstone, entry });
|
|
81
91
|
return false;
|
|
82
92
|
}
|
|
@@ -95,7 +105,7 @@ export function closeSession(id, reason = 'manual', opts = {}) {
|
|
|
95
105
|
*/
|
|
96
106
|
function reportCloseBarrierFailure({ id, reason, tombstone, entry }) {
|
|
97
107
|
const commitError = getSessionLifecycleCommitError(id);
|
|
98
|
-
let detail = 'no durable barrier written (veto
|
|
108
|
+
let detail = 'no durable barrier written (veto or contended commit)';
|
|
99
109
|
if (commitError) {
|
|
100
110
|
const code = commitError.code ? ` (${commitError.code})` : '';
|
|
101
111
|
detail = `${commitError.message}${code}`;
|
|
@@ -163,6 +173,7 @@ function teardownSessionRuntime({ id, entry, reason, tombstone, newGen }) {
|
|
|
163
173
|
/* ignore */
|
|
164
174
|
}
|
|
165
175
|
}
|
|
176
|
+
forgetSideQuestion(id, { cancel: true });
|
|
166
177
|
closeProviderConnections(id, `session-close:${reason}`);
|
|
167
178
|
// Diagnostic: one-line stderr so operators can distinguish the four close
|
|
168
179
|
// pathways (request-abort / manual / idle-sweep / runner-crash). iterCount
|
|
@@ -216,7 +227,7 @@ function releaseSessionReadCaches(id) {
|
|
|
216
227
|
/* ignore */
|
|
217
228
|
}
|
|
218
229
|
try {
|
|
219
|
-
forgetSessionSaveBaseline(id);
|
|
230
|
+
forgetSessionSaveBaseline(id, { releaseWriteControl: true });
|
|
220
231
|
} catch {
|
|
221
232
|
/* ignore */
|
|
222
233
|
}
|
|
@@ -288,6 +299,7 @@ export function unloadSessionRuntime(id, reason = 'runtime-unload') {
|
|
|
288
299
|
if (IN_FLIGHT_STAGES.has(entry.stage)) return false;
|
|
289
300
|
}
|
|
290
301
|
_stopToolActivityHeartbeat(id);
|
|
302
|
+
forgetSideQuestion(id, { cancel: true });
|
|
291
303
|
closeProviderConnections(id, `runtime-unload:${reason}`);
|
|
292
304
|
releaseSessionReadCaches(id);
|
|
293
305
|
_clearSessionRuntime(id);
|
|
@@ -27,6 +27,7 @@ import { isSessionCompactionBlocked, getSessionAbortSignal, _runtimeEntries } fr
|
|
|
27
27
|
import { mintSessionId } from './session-id.mjs';
|
|
28
28
|
import { hideCompactionArchive } from '../compaction-archive-capture.mjs';
|
|
29
29
|
import { writeStderrBestEffort } from '../../../../shared/best-effort-stderr.mjs';
|
|
30
|
+
import { forgetSideQuestion } from '../side-question-store.mjs';
|
|
30
31
|
|
|
31
32
|
/** Force-flush session metrics to disk. Used by watchdog terminal-reap (fix B). */
|
|
32
33
|
export async function flushSessionMetrics(sessionId) {
|
|
@@ -91,13 +92,30 @@ export async function updateSessionManualTitle(id, title) {
|
|
|
91
92
|
if (!session || session.closed === true) return false;
|
|
92
93
|
const normalized = normalizeSessionTitle(title);
|
|
93
94
|
if (!normalized) return false;
|
|
94
|
-
if (session.title === normalized && session.titleLocked === true) return false;
|
|
95
|
+
if (session.title === normalized && session.titleLocked === true && session.titleSource === 'user') return false;
|
|
95
96
|
session.title = normalized;
|
|
96
97
|
session.titleLocked = true;
|
|
98
|
+
session.titleSource = 'user';
|
|
97
99
|
session.titleUpdatedAt = Date.now();
|
|
98
100
|
await saveSessionAsync(session, { expectedGeneration: session.generation });
|
|
99
101
|
return true;
|
|
100
102
|
}
|
|
103
|
+
// A title the model chose (session tool). Never overwrites a user title; a
|
|
104
|
+
// legacy locked session without titleSource counts as user-titled. It locks
|
|
105
|
+
// the title against auto-generated ones but stays replaceable by the model.
|
|
106
|
+
export async function updateSessionAiTitle(id, title) {
|
|
107
|
+
const session = loadSession(id);
|
|
108
|
+
if (!session || session.closed === true) return { ok: false, reason: 'not-found' };
|
|
109
|
+
const normalized = normalizeSessionTitle(title);
|
|
110
|
+
if (!normalized) return { ok: false, reason: 'empty-title' };
|
|
111
|
+
if (session.titleLocked === true && session.titleSource !== 'ai') return { ok: false, reason: 'user-title' };
|
|
112
|
+
session.title = normalized;
|
|
113
|
+
session.titleLocked = true;
|
|
114
|
+
session.titleSource = 'ai';
|
|
115
|
+
session.titleUpdatedAt = Date.now();
|
|
116
|
+
await saveSessionAsync(session, { expectedGeneration: session.generation });
|
|
117
|
+
return { ok: true, title: normalized };
|
|
118
|
+
}
|
|
101
119
|
// --- Clear messages (keep system prompt + provider/model/cwd) ---
|
|
102
120
|
// Token/provider accounting a cleared transcript starts from; shared by the
|
|
103
121
|
// live session and the cold fork of its outgoing transcript.
|
|
@@ -262,8 +280,10 @@ export async function clearSessionMessages(sessionId, options = {}) {
|
|
|
262
280
|
|
|
263
281
|
session.messages = keep;
|
|
264
282
|
// Clear truncates the transcript wholesale; drop the provider prefix
|
|
265
|
-
// snapshot so the next send re-baselines instead of history_shrink
|
|
283
|
+
// snapshot so the next send re-baselines instead of history_shrink, and
|
|
284
|
+
// the request a /btw side question would fork.
|
|
266
285
|
delete session._providerPrefixGuardState;
|
|
286
|
+
forgetSideQuestion(sessionId);
|
|
267
287
|
resetSessionBp3Environment(session);
|
|
268
288
|
Object.assign(session, clearedTokenAccounting(now));
|
|
269
289
|
session.compaction = {
|
|
@@ -372,9 +392,11 @@ export async function rewindSessionMessagesTo(sessionId, options = {}) {
|
|
|
372
392
|
const removed = messages.length - start;
|
|
373
393
|
session.messages = messages.slice(0, start);
|
|
374
394
|
// The provider cache is keyed on the exact prefix we just truncated;
|
|
375
|
-
// the prefix-guard snapshot
|
|
395
|
+
// the prefix-guard snapshot and the /btw fork request describe it too and
|
|
396
|
+
// must go with it.
|
|
376
397
|
session.providerState = undefined;
|
|
377
398
|
delete session._providerPrefixGuardState;
|
|
399
|
+
forgetSideQuestion(sessionId);
|
|
378
400
|
session.updatedAt = Date.now();
|
|
379
401
|
session.lastUsedAt = Date.now();
|
|
380
402
|
await saveSessionAsync(session, { expectedGeneration: session.generation });
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// manager/session-fallback-title.mjs
|
|
2
|
+
// Durable, transcript-independent fallback title: the first usable
|
|
3
|
+
// user-authored prompt, stored on `session.title` so the conversation keeps a
|
|
4
|
+
// name after compaction replaces the transcript. Leaf module (no session-crud
|
|
5
|
+
// import) so ask-turn-execute, compaction-runner and pre-send-compact can share it.
|
|
6
|
+
import { compactSessionTitle } from '../../runtime-core/session-title.mjs';
|
|
7
|
+
import { cleanSessionPreview, isSessionPreviewNoise, sessionMessageText } from '../../runtime-core/session-text.mjs';
|
|
8
|
+
import { IMPORTED_MESSAGE_SOURCE } from '../imported-message.mjs';
|
|
9
|
+
import { isActualUserInstructionMessage } from '../compact/messages.mjs';
|
|
10
|
+
|
|
11
|
+
const UNTITLED_PLACEHOLDER = /^untitled(?:\s+session)?$/i;
|
|
12
|
+
const MEDIA_PLACEHOLDER = /^\[(?:image|video|file)\]$/i;
|
|
13
|
+
// Attachment envelopes carry payloads, not prose: closed blocks, then a block
|
|
14
|
+
// that lost its closing tag (the rest of the text is payload), then bare
|
|
15
|
+
// self-closing tags. Stripped before truncation so a large payload cannot
|
|
16
|
+
// crowd the prompt out of the bounded source.
|
|
17
|
+
const ATTACHMENT_TAGS = 'file|attachment|document|image|video|pdf';
|
|
18
|
+
const ATTACHMENT_BLOCK = new RegExp(`<(${ATTACHMENT_TAGS})\\b[^>]*>[\\s\\S]*?<\\/\\1\\s*>`, 'gi');
|
|
19
|
+
const ATTACHMENT_UNTERMINATED = new RegExp(`<(?:${ATTACHMENT_TAGS})\\b[^>]*>[\\s\\S]*$`, 'i');
|
|
20
|
+
const ATTACHMENT_SELF_CLOSING = new RegExp(`<(?:${ATTACHMENT_TAGS})\\b[^>]*\\/>`, 'gi');
|
|
21
|
+
const MEDIA_MARKER = /\[(?:Image|Video|File)(?:\s*#?\d+)?(?::[^\]\r\n]*)?\]/gi;
|
|
22
|
+
|
|
23
|
+
function stripAttachmentEnvelopes(text) {
|
|
24
|
+
return text
|
|
25
|
+
.replace(ATTACHMENT_BLOCK, ' ')
|
|
26
|
+
.replace(ATTACHMENT_SELF_CLOSING, ' ')
|
|
27
|
+
.replace(ATTACHMENT_UNTERMINATED, ' ')
|
|
28
|
+
.replace(MEDIA_MARKER, ' ');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function isUsableTitle(title) {
|
|
32
|
+
const text = String(title || '').trim();
|
|
33
|
+
return !!text && !UNTITLED_PLACEHOLDER.test(text);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Bounded single-line title from user-authored text; '' when nothing usable. */
|
|
37
|
+
export function fallbackTitleFromText(content) {
|
|
38
|
+
const raw = sessionMessageText(content);
|
|
39
|
+
if (!raw || /^\s*reference files:/i.test(raw)) return '';
|
|
40
|
+
const prose = stripAttachmentEnvelopes(raw);
|
|
41
|
+
if (isSessionPreviewNoise(prose)) return '';
|
|
42
|
+
const title = compactSessionTitle(cleanSessionPreview(prose, 4_000));
|
|
43
|
+
return isUsableTitle(title) && !MEDIA_PLACEHOLDER.test(title) ? title : '';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** A turn the human typed: provenance lives in `meta` (`source` of an injected
|
|
47
|
+
* goal/notification/compaction turn, `synthetic`), never on the message root. */
|
|
48
|
+
function isHumanAuthoredTurn(message) {
|
|
49
|
+
if (message?.role !== 'user' || message.internal === true || message.synthetic === true) return false;
|
|
50
|
+
const meta = message.meta;
|
|
51
|
+
if (meta && typeof meta === 'object') {
|
|
52
|
+
if (meta.synthetic === true) return false;
|
|
53
|
+
if (meta.source && meta.source !== IMPORTED_MESSAGE_SOURCE) return false;
|
|
54
|
+
}
|
|
55
|
+
return isActualUserInstructionMessage(message);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Title from the first usable human user message of a transcript. */
|
|
59
|
+
export function fallbackTitleFromMessages(messages) {
|
|
60
|
+
for (const message of Array.isArray(messages) ? messages : []) {
|
|
61
|
+
if (!isHumanAuthoredTurn(message)) continue;
|
|
62
|
+
const title = fallbackTitleFromText(message.content);
|
|
63
|
+
if (title) return title;
|
|
64
|
+
}
|
|
65
|
+
return '';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Fills `session.title` only when missing. Never touches a locked (manual/AI)
|
|
69
|
+
* or generated title, and leaves generatedTitleStage unset so
|
|
70
|
+
* updateSessionGeneratedTitle can still upgrade it. The caller persists. */
|
|
71
|
+
export function applyFallbackSessionTitle(session, title) {
|
|
72
|
+
if (!session || !isUsableTitle(title) || isUsableTitle(session.title)) return false;
|
|
73
|
+
if (session.titleLocked === true || session.generatedTitleStage) return false;
|
|
74
|
+
session.title = title;
|
|
75
|
+
session.titleUpdatedAt = Date.now();
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function backfillFallbackSessionTitle(session, messages) {
|
|
80
|
+
if (!session || isUsableTitle(session.title)) return false;
|
|
81
|
+
return applyFallbackSessionTitle(session, fallbackTitleFromMessages(messages));
|
|
82
|
+
}
|
|
@@ -37,8 +37,9 @@ import { getAgentRuntimeSync, warnAgentRuntimeResolveFailureOnce } from './agent
|
|
|
37
37
|
import { ensureCodexWireSessionId, mintSessionId } from './session-id.mjs';
|
|
38
38
|
import { providerCacheKey } from './provider-cache-key.mjs';
|
|
39
39
|
import { buildSessionRecord, normalizeDesktopSessionMetadata, sessionOriginFields } from './session-record.mjs';
|
|
40
|
-
import { refreshSessionBp3Environment } from './prompt-utils.mjs';
|
|
40
|
+
import { applyPendingWorkspaceReroot, refreshSessionBp3Environment } from './prompt-utils.mjs';
|
|
41
41
|
import { isWorktreeBound } from '../../../../shared/worktrees/contract.mjs';
|
|
42
|
+
import { applyAgentToolExposure } from '../loop/tool-exposure-migration.mjs';
|
|
42
43
|
|
|
43
44
|
// Owner liveness (attach-on-resume guard) and the durable turn-checkpoint
|
|
44
45
|
// recovery it gates; re-exported so prior importers of this module stay
|
|
@@ -243,6 +244,8 @@ export function createSession(opts) {
|
|
|
243
244
|
origin: sessionOriginFields(opts, { profile, presetObj, providerCacheOpts, surface }),
|
|
244
245
|
});
|
|
245
246
|
session.providerCacheOptsOverride = Boolean(resolved.providerCacheOpts);
|
|
247
|
+
// A non-native agent sends core + bridge, built from its filtered tools.
|
|
248
|
+
applyAgentToolExposure(session);
|
|
246
249
|
refreshSessionBp3Environment(session, opts.cwd);
|
|
247
250
|
// In-process registry + async debounced save: same-process create → load
|
|
248
251
|
// reads live memory; disk flush is for cross-process / restart durability.
|
|
@@ -367,6 +370,11 @@ function resetSessionForRouteChange(id, session, previousModel, previousProvider
|
|
|
367
370
|
session.lastContextTokensUpdatedAt = Date.now();
|
|
368
371
|
session.lastContextTokensStaleAfterCompact = false;
|
|
369
372
|
session.providerState = undefined;
|
|
373
|
+
// The previous route's prefix snapshot measured another prompt (model line,
|
|
374
|
+
// stripped replay); the new chain baselines on its first send.
|
|
375
|
+
delete session._providerPrefixGuardState;
|
|
376
|
+
// The new route resolves its own wire before its first request.
|
|
377
|
+
session.wireRoute = null;
|
|
370
378
|
const prepared = _prepareResumeTools(session, session.preset || 'full');
|
|
371
379
|
session.tools = prepared.tools;
|
|
372
380
|
session.toolSpec = prepared.toolSpec;
|
|
@@ -384,6 +392,7 @@ function resetSessionForRouteChange(id, session, previousModel, previousProvider
|
|
|
384
392
|
]) {
|
|
385
393
|
if (Array.isArray(session[key])) session[key] = filterModelEditToolNames(session[key], session.model);
|
|
386
394
|
}
|
|
395
|
+
applyAgentToolExposure(session, { existing: true });
|
|
387
396
|
_refreshSessionRuleVariantsForModel(session, previousModel, previousProvider);
|
|
388
397
|
_forgetPreparedResume(id);
|
|
389
398
|
}
|
|
@@ -436,6 +445,9 @@ export function updateSessionRoute(id, route = {}, options = {}) {
|
|
|
436
445
|
// route and set sessionStartMetaInjected, so the ask-time refresh guard
|
|
437
446
|
// skips it and an empty-session route change would otherwise keep the old
|
|
438
447
|
// model line in the system prompt (model self-identity confusion).
|
|
448
|
+
// A new route starts a cold cache: a staged working-folder change re-roots
|
|
449
|
+
// the prompt now instead of riding a notice.
|
|
450
|
+
if (routeChanged) applyPendingWorkspaceReroot(session);
|
|
439
451
|
refreshSessionBp3Environment(session, session.cwd);
|
|
440
452
|
session.updatedAt = Date.now();
|
|
441
453
|
setLiveSession(session);
|
|
@@ -513,7 +525,12 @@ function _refreshResumedTools(session, sessionId, preset) {
|
|
|
513
525
|
// Keep the persisted tool mode in sync on resume (see createSession note).
|
|
514
526
|
session.toolSpec = prepared.toolSpec;
|
|
515
527
|
session.tools = prepared.tools;
|
|
516
|
-
|
|
528
|
+
applyAgentToolExposure(session, { existing: true });
|
|
529
|
+
// A bridge surface keeps the rest of its tools in the catalog.
|
|
530
|
+
const available = new Set(
|
|
531
|
+
[...session.tools, ...(session.deferredToolCatalog || [])].map((tool) => tool?.name).filter(Boolean)
|
|
532
|
+
);
|
|
533
|
+
const missing = oldTools.filter((t) => !available.has(t.name));
|
|
517
534
|
if (missing.length) {
|
|
518
535
|
process.stderr.write(
|
|
519
536
|
`[session] Warning: ${missing.length} tools no longer available: ${missing.map((t) => t.name).join(', ')}\n`
|
|
@@ -109,6 +109,9 @@ export function buildSessionRecord({ opts, route, presetObj, surface, prompt, me
|
|
|
109
109
|
codexWireSessionId: providerName === 'openai-oauth' ? mintUuidV7() : null,
|
|
110
110
|
provider: providerName,
|
|
111
111
|
model: modelName,
|
|
112
|
+
// Resolved and pinned before the first request (wire-route.mjs). null —
|
|
113
|
+
// not absent — marks a session created under the per-model wire table.
|
|
114
|
+
wireRoute: null,
|
|
112
115
|
messages,
|
|
113
116
|
contextWindow: contextMeta.contextWindow,
|
|
114
117
|
rawContextWindow: contextMeta.rawContextWindow,
|
|
@@ -48,6 +48,9 @@ const SESSION_ROUTE_TOOL_RANK = new Map(
|
|
|
48
48
|
const FILESYSTEM_TOOL_NAMES = new Set(['code_graph', 'find', 'glob', 'list', 'grep', 'read', 'edit', 'apply_patch']);
|
|
49
49
|
const READONLY_FS_TOOL_NAMES = new Set(['code_graph', 'find', 'glob', 'list', 'grep', 'read']);
|
|
50
50
|
|
|
51
|
+
// Lead-only control tools: never part of a worker/sub-agent session surface.
|
|
52
|
+
export const AGENT_WORKER_DENIED_TOOLS = Object.freeze(new Set(['agent', 'ask_user', 'session']));
|
|
53
|
+
|
|
51
54
|
export function finalizeSessionToolList(
|
|
52
55
|
tools,
|
|
53
56
|
{ schemaAllowedTools = null, disallowedTools = null, ownerIsAgent = false } = {}
|
|
@@ -64,7 +67,7 @@ export function finalizeSessionToolList(
|
|
|
64
67
|
out = out.filter((t) => !denySet.has(String(t?.name || '').toLowerCase()));
|
|
65
68
|
}
|
|
66
69
|
if (ownerIsAgent) {
|
|
67
|
-
out = out.filter((t) => String(t?.name || '').toLowerCase()
|
|
70
|
+
out = out.filter((t) => !AGENT_WORKER_DENIED_TOOLS.has(String(t?.name || '').toLowerCase()));
|
|
68
71
|
out = orderSessionTools(out);
|
|
69
72
|
}
|
|
70
73
|
return out;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { sanitizeToolPairs } from '../context-utils.mjs';
|
|
2
2
|
import { collectAssistantToolCallIds as assistantToolCallIds } from '../context-tool-pairs.mjs';
|
|
3
|
-
import {
|
|
3
|
+
import { promptContentText } from './prompt-utils.mjs';
|
|
4
4
|
import { filterModelVisibleSessionMessages } from './message-sanitize.mjs';
|
|
5
5
|
import { journalDelta } from './turn-interruption-journal.mjs';
|
|
6
6
|
|
|
@@ -72,8 +72,11 @@ function finalizeInterruptedTurn({
|
|
|
72
72
|
const index = provisionalUserTurnIndex(messages, currentUserContent);
|
|
73
73
|
return index >= 0 && index < messages.length - 1;
|
|
74
74
|
})();
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
// A turn woken by a task notification is preserved by the same rule as a
|
|
76
|
+
// user prompt: once it produced output its notification is consumed (the
|
|
77
|
+
// host commits it and never requeues it), so rewinding it would erase the
|
|
78
|
+
// turn and its side effects from history.
|
|
79
|
+
const preserveResponse = responseStarted && (producedOutput || !userCancelled);
|
|
77
80
|
if (!preserveResponse) {
|
|
78
81
|
if (!userCancelled) {
|
|
79
82
|
return {
|
|
@@ -198,8 +201,11 @@ export function createTurnInterruptionTracker() {
|
|
|
198
201
|
// copies of the same first sentence). Reference agents never
|
|
199
202
|
// commit a replayed attempt's discarded stream at all; the
|
|
200
203
|
// tombstone exists only for the window between a retraction and
|
|
201
|
-
// its replacement.
|
|
202
|
-
|
|
204
|
+
// its replacement. Whitespace is not a replacement: it is not output
|
|
205
|
+
// (finalizeInterruptedTurn trims, and the host commits the prompt only
|
|
206
|
+
// on non-blank text), so until real text arrives the retracted bytes
|
|
207
|
+
// remain the only output the user saw.
|
|
208
|
+
if (state.tombstonedAssistantContent && value.trim()) {
|
|
203
209
|
state.tombstonedAssistantContent = '';
|
|
204
210
|
state.tombEpoch += 1;
|
|
205
211
|
}
|
|
@@ -212,8 +218,13 @@ export function createTurnInterruptionTracker() {
|
|
|
212
218
|
// REPLACE, never accumulate: consecutive retractions belong to
|
|
213
219
|
// successive attempts at the SAME answer, so keeping the earlier
|
|
214
220
|
// tombstone alongside the newer one is what multiplied the visible
|
|
215
|
-
// text across retries.
|
|
216
|
-
|
|
221
|
+
// text across retries. A whitespace-only retraction is not a newer
|
|
222
|
+
// attempt at the answer (recordTextDelta never let it supersede the
|
|
223
|
+
// draft), so it never replaces a meaningful tombstone.
|
|
224
|
+
const retracted = state.partialAssistantContent.slice(cutAt);
|
|
225
|
+
if (retracted.trim() || !state.tombstonedAssistantContent.trim()) {
|
|
226
|
+
state.tombstonedAssistantContent = retracted;
|
|
227
|
+
}
|
|
217
228
|
state.partialAssistantContent = state.partialAssistantContent.slice(0, cutAt);
|
|
218
229
|
state.textEpoch += 1;
|
|
219
230
|
state.tombEpoch += 1;
|
|
@@ -123,9 +123,10 @@ export {
|
|
|
123
123
|
updateSessionStatus,
|
|
124
124
|
updateSessionGeneratedTitle,
|
|
125
125
|
updateSessionManualTitle,
|
|
126
|
+
updateSessionAiTitle,
|
|
126
127
|
flushSessionMetrics,
|
|
127
128
|
} from './manager/session-crud.mjs';
|
|
128
|
-
export { deleteSession, listOwnedAgentSessionIds } from './store.mjs';
|
|
129
|
+
export { deleteSession, listOwnedAgentSessionIds, fenceSessionWrites } from './store.mjs';
|
|
129
130
|
// Read-only parsed-session access (desktop pane peek): no resume, no
|
|
130
131
|
// ownership, no liveness side effects.
|
|
131
132
|
export { loadSession } from './store.mjs';
|
|
@@ -31,6 +31,8 @@ import { bumpUsageMetricsEpoch } from './manager/usage-metrics.mjs';
|
|
|
31
31
|
import { resetReadStateAfterCompaction } from './read-dedup.mjs';
|
|
32
32
|
import { scheduleCompactionArchive, stampCompactionMessageIds } from './compaction-archive-capture.mjs';
|
|
33
33
|
import { writeStderrBestEffort } from '../../../shared/best-effort-stderr.mjs';
|
|
34
|
+
import { applyPendingWorkspaceReroot } from './manager/prompt-utils.mjs';
|
|
35
|
+
import { backfillFallbackSessionTitle } from './manager/session-fallback-title.mjs';
|
|
34
36
|
import {
|
|
35
37
|
acknowledgePendingGoalReminder,
|
|
36
38
|
markPendingGoalReminder,
|
|
@@ -378,6 +380,7 @@ function adoptCompactedTranscript(ctx, run) {
|
|
|
378
380
|
const { state } = ctx;
|
|
379
381
|
const { messages, sessionRef, sessionId, opts } = state;
|
|
380
382
|
const replaced = messages.slice();
|
|
383
|
+
if (sessionRef) backfillFallbackSessionTitle(sessionRef, replaced);
|
|
381
384
|
messages.length = 0;
|
|
382
385
|
messages.push(...run.compacted);
|
|
383
386
|
// Display-only archive of the dropped conversation; the projection and the
|
|
@@ -388,6 +391,9 @@ function adoptCompactedTranscript(ctx, run) {
|
|
|
388
391
|
ctx.droppedMessages = archived?.dropped ?? 0;
|
|
389
392
|
ctx.droppedIdentities = archived?.identities ?? null;
|
|
390
393
|
acknowledgeGoalReminder(sessionRef, run);
|
|
394
|
+
// The compacted transcript breaks the cache anyway: a staged working-folder
|
|
395
|
+
// change re-roots the system prompt now and needs no notice any more.
|
|
396
|
+
if (sessionRef) applyPendingWorkspaceReroot(sessionRef, messages);
|
|
391
397
|
resetReadStateAfterCompaction(sessionId);
|
|
392
398
|
// Cross-turn receipts reference tool results that compaction just removed
|
|
393
399
|
// from context; a stub for them would point at nothing. Clear in place so
|