mixdog 1.2.2 → 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/provider-pingpong-live.mjs +509 -0
- package/src/agents/advisor/AGENT.md +1 -1
- package/src/agents/advisor/agent.json +1 -1
- package/src/defaults/shipped-history.json +5 -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/rules/agent/AGENT.md +5 -5
- package/src/rules/lead/LEAD.md +5 -5
- 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/providers/anthropic-api-request.mjs +48 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +24 -17
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +7 -6
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +29 -10
- 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 +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +58 -7
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +29 -10
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +12 -6
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +114 -72
- package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +37 -5
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +9 -2
- 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 +3 -1
- package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +25 -8
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +87 -5
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +13 -13
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +355 -37
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +93 -47
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +55 -10
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +26 -8
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +1 -0
- 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/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/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 +121 -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 +5 -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-error-contract.mjs +1 -1
- 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 +42 -24
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +63 -25
- 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.mjs +53 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +103 -26
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +23 -4
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +11 -6
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +15 -23
- 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 +25 -4
- 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 +4 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +71 -24
- 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-ws-delta.mjs +7 -16
- 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-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.mjs +11 -3
- 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 +147 -8
- package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +5 -0
- 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/deferred-tool-availability.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
- 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 +3 -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 +63 -20
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +2 -1
- 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 +4 -1
- 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 +16 -0
- 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/prompt-utils.mjs +208 -14
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +15 -3
- 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.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 +13 -0
- 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/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-summary-archived-agent.mjs +34 -15
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +10 -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/tools/bash-policy-scan.mjs +8 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
- 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 +31 -26
- package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +108 -3
- 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 +1 -1
- 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/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 +6 -0
- 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-effort.mjs +6 -0
- 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/loopback-listener.mjs +9 -0
- package/src/runtime/shared/provider-api-key.mjs +2 -0
- package/src/runtime/shared/review-diff.mjs +52 -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-segments.mjs +28 -4
- 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 +268 -100
- package/src/runtime/shared/turn-review-reply.mjs +8 -39
- package/src/runtime/shared/turn-snapshot-store.mjs +19 -108
- package/src/runtime/shared/turn-snapshot.mjs +857 -683
- package/src/runtime/shared/turn-worktree-snapshot.mjs +183 -255
- 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 -0
- 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/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 +13 -5
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/infrastructure.mjs +6 -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 +12 -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 +72 -7
- package/src/session-runtime/lifecycle-api.mjs +1 -0
- package/src/session-runtime/mcp-glue/connect.mjs +17 -5
- package/src/session-runtime/model-route/set-route.mjs +2 -2
- 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/resource-scope-decorate.mjs +10 -3
- package/src/session-runtime/runtime-review-api.mjs +8 -2
- package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
- 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/tag-registry.mjs +15 -1
- 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.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/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-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 +19 -0
- package/src/standalone/daemon.mjs +61 -1
- 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 +7 -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/session-calls/session-action.mjs +18 -3
- package/src/standalone/session-service-api.mjs +6 -1
- 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/btw-controller.mjs +118 -0
- package/src/tui/app/create-app-pickers.mjs +2 -0
- 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 +13 -3
- 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/question-panel-model.mjs +156 -0
- package/src/tui/dist/index.mjs +2413 -1465
- package/src/tui/session/context-state.mjs +4 -2
- package/src/tui/session/session-api/commands.mjs +10 -0
- package/src/tui/session/session-api/controls.mjs +2 -2
- package/src/tui/session/session-api/integrations.mjs +9 -2
- package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
- package/src/tui/session/session-api/lifecycle.mjs +2 -1
- package/src/tui/session/session-api/settings.mjs +6 -0
- package/src/tui/session/session-api.mjs +1 -0
- 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 +12 -5
- package/src/workflows/default/WORKFLOW.md +3 -1
|
@@ -3,26 +3,35 @@
|
|
|
3
3
|
import { statSync } from 'node:fs';
|
|
4
4
|
import { resolve } from 'node:path';
|
|
5
5
|
import { listProjects } from '../../runtime/shared/projects.mjs';
|
|
6
|
+
import { applySessionSidebarChange } from '../../runtime/shared/session-sidebar-host.mjs';
|
|
6
7
|
import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
7
8
|
|
|
9
|
+
const USER_TITLE_ERROR = 'session: the user already titled this session; the title was not changed';
|
|
10
|
+
|
|
8
11
|
export function createWorkspaceToolHandlers({
|
|
9
12
|
rt,
|
|
10
13
|
goalRuntime,
|
|
11
14
|
agentTool,
|
|
12
15
|
notifyFnForSession,
|
|
13
|
-
applyResolvedCwd,
|
|
14
16
|
getWorkspaceApi = () => null,
|
|
17
|
+
getSessionManager = () => null,
|
|
18
|
+
getLifecycleApi = () => null,
|
|
15
19
|
}) {
|
|
16
20
|
// The Lead's own worktree, on the user's request: the same authority the
|
|
17
21
|
// branch chip menu drives, tolerating the calling turn but nothing else
|
|
18
22
|
// running (workers, background shells).
|
|
19
|
-
const
|
|
20
|
-
const workspace = getWorkspaceApi();
|
|
21
|
-
if (!workspace) throw new Error(`cwd: ${action} is unavailable in this runtime`);
|
|
23
|
+
const assertLead = (action, callerCtx) => {
|
|
22
24
|
const callerSessionId = callerCtx?.callerSessionId || rt.session?.id || null;
|
|
23
25
|
if (!rt.session?.id || callerSessionId !== rt.session.id) {
|
|
24
|
-
throw new Error(`
|
|
26
|
+
throw new Error(`session: ${action} belongs to the Lead session`);
|
|
25
27
|
}
|
|
28
|
+
return rt.session.id;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const worktreeAction = async (action, args, callerCtx) => {
|
|
32
|
+
const workspace = getWorkspaceApi();
|
|
33
|
+
if (!workspace) throw new Error(`session: ${action} is unavailable in this runtime`);
|
|
34
|
+
assertLead(action, callerCtx);
|
|
26
35
|
const result =
|
|
27
36
|
action === 'merge-worktree'
|
|
28
37
|
? await workspace.mergeWorkspace({ confirmed: true }, { ownTurn: true })
|
|
@@ -35,12 +44,95 @@ export function createWorkspaceToolHandlers({
|
|
|
35
44
|
};
|
|
36
45
|
|
|
37
46
|
const WORKTREE_ACTIONS = new Set(['merge-worktree', 'remove-worktree', 'list-worktrees', 'prune-worktrees']);
|
|
47
|
+
const SIDEBAR_ACTIONS = new Set(['favorite', 'archive']);
|
|
38
48
|
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
// Sidebar flags only (the desktop's favorite/archive metadata).
|
|
50
|
+
const sidebarAction = async (action, args, callerCtx) => {
|
|
51
|
+
const sessionId = assertLead(action, callerCtx);
|
|
52
|
+
if (typeof args?.value !== 'boolean') throw new Error(`session: value (boolean) is required for action=${action}`);
|
|
53
|
+
const change = action === 'favorite' ? { favorite: args.value } : { archived: args.value };
|
|
54
|
+
try {
|
|
55
|
+
await applySessionSidebarChange(sessionId, change);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
throw new Error(`session: ${action} failed (${error?.message || error})`);
|
|
58
|
+
}
|
|
59
|
+
return JSON.stringify({ action, sessionId, ...change }, null, 2);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const session = async (args, { callerCtx, callerCwd }) => {
|
|
63
|
+
const action = clean(args?.action || (args?.path ? 'set-project' : 'status')).toLowerCase();
|
|
41
64
|
if (WORKTREE_ACTIONS.has(action)) return worktreeAction(action, args, callerCtx);
|
|
65
|
+
if (SIDEBAR_ACTIONS.has(action)) return sidebarAction(action, args, callerCtx);
|
|
42
66
|
let currentCwd = callerCwd;
|
|
43
|
-
if (action === 'list')
|
|
67
|
+
if (action === 'status' || action === 'list-projects' || action === 'set-project') assertLead(action, callerCtx);
|
|
68
|
+
if (action === 'rename') {
|
|
69
|
+
const sessionId = assertLead(action, callerCtx);
|
|
70
|
+
if (rt.config?.aiSessionTitles === false) throw new Error('session: AI session titles are disabled in settings');
|
|
71
|
+
const title = clean(args?.title);
|
|
72
|
+
if (!title) throw new Error('session: title is required for action=rename');
|
|
73
|
+
const result = await getSessionManager()?.updateSessionAiTitle(sessionId, title);
|
|
74
|
+
if (!result?.ok) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
result?.reason === 'user-title'
|
|
77
|
+
? USER_TITLE_ERROR
|
|
78
|
+
: `session: rename failed (${result?.reason || 'unavailable'})`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
// Mirror the store's truth onto the live session, never the AI title
|
|
82
|
+
// itself: a manual rename that landed while the save was awaited wins.
|
|
83
|
+
const stored = getSessionManager()?.getSession?.(sessionId);
|
|
84
|
+
if (stored && rt.session?.id === sessionId && stored !== rt.session) {
|
|
85
|
+
rt.session.title = stored.title;
|
|
86
|
+
rt.session.titleLocked = stored.titleLocked;
|
|
87
|
+
rt.session.titleSource = stored.titleSource;
|
|
88
|
+
rt.session.titleUpdatedAt = stored.titleUpdatedAt;
|
|
89
|
+
}
|
|
90
|
+
if (stored && stored.titleSource === 'user') throw new Error(USER_TITLE_ERROR);
|
|
91
|
+
return JSON.stringify({ action, sessionId, title: result.title }, null, 2);
|
|
92
|
+
}
|
|
93
|
+
if (action === 'compact') {
|
|
94
|
+
const sessionId = assertLead(action, callerCtx);
|
|
95
|
+
rt.pendingCompactSessionIds ??= new Set();
|
|
96
|
+
rt.pendingCompactSessionIds.add(sessionId);
|
|
97
|
+
return JSON.stringify(
|
|
98
|
+
{ action, sessionId, scheduled: true, note: 'Compaction runs right after the current turn finishes.' },
|
|
99
|
+
null,
|
|
100
|
+
2
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
if (action === 'fork') {
|
|
104
|
+
const sessionId = assertLead(action, callerCtx);
|
|
105
|
+
const lifecycle = getLifecycleApi();
|
|
106
|
+
if (typeof lifecycle?.inheritToNewSession !== 'function') {
|
|
107
|
+
throw new Error('session: fork is unavailable in this runtime');
|
|
108
|
+
}
|
|
109
|
+
const result = await lifecycle.inheritToNewSession(sessionId, {
|
|
110
|
+
compact: args?.compact === true,
|
|
111
|
+
titleSuffix: ' (Fork)',
|
|
112
|
+
});
|
|
113
|
+
return JSON.stringify(
|
|
114
|
+
{ action, sourceSessionId: sessionId, sessionId: result.sessionId, compacted: result.compacted === true },
|
|
115
|
+
null,
|
|
116
|
+
2
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
if (action === 'status') {
|
|
120
|
+
const current = rt.session;
|
|
121
|
+
return JSON.stringify(
|
|
122
|
+
{
|
|
123
|
+
sessionId: callerCtx?.callerSessionId || current?.id || null,
|
|
124
|
+
title: current?.title || null,
|
|
125
|
+
titleSource: current?.titleSource || null,
|
|
126
|
+
cwd: currentCwd,
|
|
127
|
+
project: current?.workspace?.projectPath || current?.desktopSession?.projectPath || currentCwd,
|
|
128
|
+
provider: current?.provider || null,
|
|
129
|
+
model: current?.model || null,
|
|
130
|
+
},
|
|
131
|
+
null,
|
|
132
|
+
2
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
if (action === 'list-projects') {
|
|
44
136
|
return JSON.stringify(
|
|
45
137
|
{
|
|
46
138
|
cwd: currentCwd,
|
|
@@ -50,18 +142,23 @@ export function createWorkspaceToolHandlers({
|
|
|
50
142
|
2
|
|
51
143
|
);
|
|
52
144
|
}
|
|
53
|
-
if (action === 'set') {
|
|
145
|
+
if (action === 'set-project') {
|
|
54
146
|
const rawPath = clean(args?.path);
|
|
55
|
-
if (!rawPath) throw new Error('
|
|
147
|
+
if (!rawPath) throw new Error('session: path is required for action=set-project');
|
|
56
148
|
const nextCwd = resolve(callerCwd || process.cwd(), rawPath);
|
|
57
149
|
const stat = statSync(nextCwd);
|
|
58
|
-
if (!stat.isDirectory()) throw new Error(`
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
150
|
+
if (!stat.isDirectory()) throw new Error(`session: not a directory: ${nextCwd}`);
|
|
151
|
+
// The Lead's own call: the runtime's Project switch authority admits it
|
|
152
|
+
// during the calling turn and refuses inside a managed worktree.
|
|
153
|
+
if (typeof callerCtx?.setCallerCwd === 'function') {
|
|
154
|
+
currentCwd = clean(await callerCtx.setCallerCwd(nextCwd)) || nextCwd;
|
|
155
|
+
} else {
|
|
156
|
+
const workspace = getWorkspaceApi();
|
|
157
|
+
if (!workspace) throw new Error('session: set-project is unavailable in this runtime');
|
|
158
|
+
currentCwd = await workspace.switchProject(nextCwd, { ownTurn: true });
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
throw new Error(`session: unknown action "${action}"`);
|
|
65
162
|
}
|
|
66
163
|
return JSON.stringify(
|
|
67
164
|
{
|
|
@@ -74,7 +171,7 @@ export function createWorkspaceToolHandlers({
|
|
|
74
171
|
};
|
|
75
172
|
|
|
76
173
|
return {
|
|
77
|
-
|
|
174
|
+
session,
|
|
78
175
|
goal: async (args, { name, callerCtx }) =>
|
|
79
176
|
await goalRuntime.executeTool(name, args || {}, {
|
|
80
177
|
callerSessionId: callerCtx?.callerSessionId || rt.session?.id || rt.reservedSessionId || null,
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* to channel tools.
|
|
7
7
|
*/
|
|
8
8
|
import { clean } from '../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
9
|
+
import { createAskUserToolHandlers } from './internal-tool-executor/ask-user-tool.mjs';
|
|
9
10
|
import { createBridgeToolHandlers } from './internal-tool-executor/bridge-tools.mjs';
|
|
10
11
|
import { createFeatureToolHandlers } from './internal-tool-executor/feature-tools.mjs';
|
|
11
12
|
import { createKnowledgeToolHandlers } from './internal-tool-executor/knowledge-tools.mjs';
|
|
@@ -29,12 +30,14 @@ export function createInternalToolExecutor({
|
|
|
29
30
|
runNativeWebSearch,
|
|
30
31
|
activeToolSurface,
|
|
31
32
|
mcpStatus,
|
|
32
|
-
applyResolvedCwd,
|
|
33
33
|
skillToolContent,
|
|
34
34
|
getWorkspaceApi,
|
|
35
|
+
getSessionManager,
|
|
36
|
+
getLifecycleApi,
|
|
35
37
|
}) {
|
|
36
38
|
const handlers = {
|
|
37
39
|
...createBridgeToolHandlers({ rt }),
|
|
40
|
+
...createAskUserToolHandlers({ rt }),
|
|
38
41
|
...createFeatureToolHandlers({ rt, setupTool, officeToolsEnabled, mediaToolEnabled, tidyToolEnabled }),
|
|
39
42
|
...createKnowledgeToolHandlers({
|
|
40
43
|
rt,
|
|
@@ -52,8 +55,9 @@ export function createInternalToolExecutor({
|
|
|
52
55
|
goalRuntime,
|
|
53
56
|
agentTool,
|
|
54
57
|
notifyFnForSession,
|
|
55
|
-
applyResolvedCwd,
|
|
56
58
|
getWorkspaceApi,
|
|
59
|
+
getSessionManager,
|
|
60
|
+
getLifecycleApi,
|
|
57
61
|
}),
|
|
58
62
|
};
|
|
59
63
|
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/session-runtime/lifecycle/cold-heir.mjs - the record of a heir that is
|
|
3
|
+
* NOT opened: a sibling of the source session on the same route, cwd and
|
|
4
|
+
* Project, persisted to the store and left cold for a later resume.
|
|
5
|
+
*
|
|
6
|
+
* The heir starts from the source's own record (same provider/model, tool
|
|
7
|
+
* surface, system layer, desktop classification) the way /clear's cold fork
|
|
8
|
+
* does, minus everything that belongs to the source alone: its conversation,
|
|
9
|
+
* in-flight turn, provider continuation, usage readings, title, worktree and
|
|
10
|
+
* ownership/lineage links — the heir is a root Lead of its own, linked to the
|
|
11
|
+
* source only through `inheritedFromSessionId`.
|
|
12
|
+
*/
|
|
13
|
+
import {
|
|
14
|
+
ensureCodexWireSessionId,
|
|
15
|
+
mintSessionId,
|
|
16
|
+
} from '../../runtime/agent/orchestrator/session/manager/session-id.mjs';
|
|
17
|
+
import {
|
|
18
|
+
refreshSessionWorkspaceContext,
|
|
19
|
+
resetSessionBp3Environment,
|
|
20
|
+
} from '../../runtime/agent/orchestrator/session/manager/prompt-utils.mjs';
|
|
21
|
+
import { buildWorkspacePromptContext } from '../../runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs';
|
|
22
|
+
import {
|
|
23
|
+
invalidateContextUsageSnapshot,
|
|
24
|
+
invalidateProviderContextBaseline,
|
|
25
|
+
} from '../../runtime/agent/orchestrator/session/loop/compact-policy.mjs';
|
|
26
|
+
import { deleteSession, evictLiveSession, saveSessionAsync } from '../../runtime/agent/orchestrator/session/store.mjs';
|
|
27
|
+
import { projectWorkspace } from '../../runtime/shared/worktrees/contract.mjs';
|
|
28
|
+
import { writeStderrBestEffort } from '../../runtime/shared/best-effort-stderr.mjs';
|
|
29
|
+
import { replacementSessionCwd } from '../workspace/workspace-state.mjs';
|
|
30
|
+
|
|
31
|
+
// Per-turn and per-process state of the source: the in-flight turn, its
|
|
32
|
+
// transient serializer-stripped aliases, and one-shot pending work.
|
|
33
|
+
const SOURCE_RUNTIME_FIELDS = [
|
|
34
|
+
'liveTurnMessages',
|
|
35
|
+
'toolApprovalHook',
|
|
36
|
+
'_providerPrefixGuardState',
|
|
37
|
+
'activeTurnCheckpoint',
|
|
38
|
+
'remoteAttached',
|
|
39
|
+
'deferredInitialRefreshPending',
|
|
40
|
+
'pendingGoalReminder',
|
|
41
|
+
'goalReminderRevision',
|
|
42
|
+
'pendingCacheBreakIntent',
|
|
43
|
+
'contextPressureUnanchoredAfterRestart',
|
|
44
|
+
'contextPressureUnanchoredReason',
|
|
45
|
+
// Store read-back projections of the SOURCE file.
|
|
46
|
+
'storageMtimeMs',
|
|
47
|
+
'storageSize',
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
// Identity the source owns: its title (the carry decides the heir's), import
|
|
51
|
+
// provenance (a dedupe key), its own inheritance link (the carry sets the
|
|
52
|
+
// heir's), Codex wire identity, lifecycle provenance (a 'cli-resume' detach
|
|
53
|
+
// hides a row from Recent), and every ownership / lineage / visibility link —
|
|
54
|
+
// a self-link copied from a recovered root Lead would point at the source and
|
|
55
|
+
// classify the heir as an agent-only child.
|
|
56
|
+
const SOURCE_IDENTITY_FIELDS = [
|
|
57
|
+
'title',
|
|
58
|
+
'titleLocked',
|
|
59
|
+
'titleSource',
|
|
60
|
+
'titleUpdatedAt',
|
|
61
|
+
'importOrigin',
|
|
62
|
+
'inheritedFromSessionId',
|
|
63
|
+
'codexWireSessionId',
|
|
64
|
+
'detachedReason',
|
|
65
|
+
'sessionVisibility',
|
|
66
|
+
'task_id',
|
|
67
|
+
'taskId',
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
// The heir is an ordinary, user-visible root Lead owned by nobody but itself,
|
|
71
|
+
// whatever the source's ownership history (same identity a new Lead session
|
|
72
|
+
// or an imported conversation gets).
|
|
73
|
+
const ROOT_LEAD_IDENTITY = Object.freeze({
|
|
74
|
+
owner: 'cli',
|
|
75
|
+
agent: 'lead',
|
|
76
|
+
lane: 'cli',
|
|
77
|
+
sourceType: 'lead',
|
|
78
|
+
sourceName: 'main',
|
|
79
|
+
parentSessionId: null,
|
|
80
|
+
ownerSessionId: null,
|
|
81
|
+
visibility: null,
|
|
82
|
+
agentTag: null,
|
|
83
|
+
taskType: null,
|
|
84
|
+
permissionMode: null,
|
|
85
|
+
scopeKey: null,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The source as of its last committed turn. Mid-turn, `messages` already
|
|
90
|
+
* holds the in-flight user prompt (pre-committed before the provider call)
|
|
91
|
+
* while `liveTurnMessages` holds the turn's working transcript; the prompt is
|
|
92
|
+
* not part of the conversation yet, so it does not travel. Never mutates.
|
|
93
|
+
*/
|
|
94
|
+
export function committedSource(source) {
|
|
95
|
+
const messages = Array.isArray(source?.messages) ? source.messages : [];
|
|
96
|
+
const live = source?.liveTurnMessages;
|
|
97
|
+
if (!Array.isArray(live) || live === messages || messages.at(-1)?.role !== 'user') return source;
|
|
98
|
+
return { ...source, messages: messages.slice(0, -1) };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** A fresh, empty heir record of `source` — system layer only, nothing saved. */
|
|
102
|
+
export function buildColdHeir(source, now = Date.now()) {
|
|
103
|
+
const heir = {
|
|
104
|
+
...source,
|
|
105
|
+
id: mintSessionId(),
|
|
106
|
+
// The heir runs on the very route that built these blocks; copies, so
|
|
107
|
+
// the heir never shares a message object with the source.
|
|
108
|
+
messages: structuredClone((source.messages || []).filter((message) => message?.role === 'system')),
|
|
109
|
+
closed: false,
|
|
110
|
+
status: 'idle',
|
|
111
|
+
generation: 0,
|
|
112
|
+
createdAt: now,
|
|
113
|
+
updatedAt: now,
|
|
114
|
+
lastUsedAt: now,
|
|
115
|
+
lastHeartbeatAt: null,
|
|
116
|
+
mcpPid: process.pid,
|
|
117
|
+
clientHostPid: null,
|
|
118
|
+
providerState: undefined,
|
|
119
|
+
totalInputTokens: 0,
|
|
120
|
+
totalOutputTokens: 0,
|
|
121
|
+
totalToolCalls: 0,
|
|
122
|
+
reasoningUsage: null,
|
|
123
|
+
totalCachedReadTokens: 0,
|
|
124
|
+
totalCacheWriteTokens: 0,
|
|
125
|
+
tokensCumulative: 0,
|
|
126
|
+
lastInputTokens: 0,
|
|
127
|
+
lastOutputTokens: 0,
|
|
128
|
+
lastCachedReadTokens: 0,
|
|
129
|
+
lastCacheWriteTokens: 0,
|
|
130
|
+
lastContextTokens: 0,
|
|
131
|
+
lastContextTokensUpdatedAt: now,
|
|
132
|
+
lastContextTokensStaleAfterCompact: false,
|
|
133
|
+
...ROOT_LEAD_IDENTITY,
|
|
134
|
+
};
|
|
135
|
+
for (const key of [...SOURCE_RUNTIME_FIELDS, ...SOURCE_IDENTITY_FIELDS]) delete heir[key];
|
|
136
|
+
ensureCodexWireSessionId(heir);
|
|
137
|
+
// The compaction archive sidecar is keyed by the source id.
|
|
138
|
+
if (heir.compaction?.archive) {
|
|
139
|
+
heir.compaction = { ...heir.compaction };
|
|
140
|
+
delete heir.compaction.archive;
|
|
141
|
+
}
|
|
142
|
+
// A worktree belongs to the session that created it: like /new, the heir
|
|
143
|
+
// starts in the Project folder instead of sharing (and on delete, removing)
|
|
144
|
+
// the source's worktree.
|
|
145
|
+
const projectFolder = replacementSessionCwd(source);
|
|
146
|
+
if (projectFolder) {
|
|
147
|
+
heir.cwd = projectFolder;
|
|
148
|
+
heir.workspace = projectWorkspace({ projectPath: projectFolder });
|
|
149
|
+
}
|
|
150
|
+
// The source's staged working-folder change (its prompt still rooted at an
|
|
151
|
+
// earlier folder) is the source's own: the heir's prompt is built for the
|
|
152
|
+
// folder it actually starts in. Project memory follows the Project, which a
|
|
153
|
+
// worktree shares, so the source's current memory slice carries over.
|
|
154
|
+
const pending = source.workspaceReroot;
|
|
155
|
+
delete heir.workspaceReroot;
|
|
156
|
+
if ((projectFolder || pending) && heir.cwd) {
|
|
157
|
+
refreshSessionWorkspaceContext(heir, {
|
|
158
|
+
cwd: heir.cwd,
|
|
159
|
+
...buildWorkspacePromptContext(heir, heir.cwd),
|
|
160
|
+
coreMemoryContext: pending?.target?.coreMemoryContext,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
invalidateContextUsageSnapshot(heir);
|
|
164
|
+
invalidateProviderContextBaseline(heir);
|
|
165
|
+
// The `# Session` block names the session it was stamped for; the heir's
|
|
166
|
+
// first turn stamps its own.
|
|
167
|
+
resetSessionBp3Environment(heir);
|
|
168
|
+
return heir;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Persist the heir durably, then drop it from the same-process live cache:
|
|
173
|
+
* it is a cold session until someone resumes it. A failed save removes the
|
|
174
|
+
* half-made record and rejects.
|
|
175
|
+
*/
|
|
176
|
+
export async function persistColdHeir(heir) {
|
|
177
|
+
try {
|
|
178
|
+
await saveSessionAsync(heir);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
try {
|
|
181
|
+
deleteSession(heir.id);
|
|
182
|
+
} catch (cleanupError) {
|
|
183
|
+
writeStderrBestEffort(`[inherit] cleanup of ${heir.id} failed: ${cleanupError?.message || cleanupError}\n`);
|
|
184
|
+
}
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
evictLiveSession(heir.id);
|
|
188
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* src/session-runtime/lifecycle/inheritance.mjs - session inheritance
|
|
3
3
|
* (/inherit): fit preflight and the carry of another session's conversation
|
|
4
|
-
* into the freshly created heir
|
|
4
|
+
* into the freshly created heir — the live one (inheritFrom) or a cold sibling
|
|
5
|
+
* persisted without switching (inheritToNewSession), through one carry core.
|
|
5
6
|
*/
|
|
6
7
|
import { hasUserConversationMessage } from '../../runtime/agent/orchestrator/session/manager/prompt-utils.mjs';
|
|
7
8
|
import { stripEffortConfiguration } from '../../runtime/agent/orchestrator/providers/effort-configuration.mjs';
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
inheritanceRouteTarget,
|
|
15
16
|
} from '../inheritance-fit.mjs';
|
|
16
17
|
import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
18
|
+
import { buildColdHeir, committedSource, persistColdHeir } from './cold-heir.mjs';
|
|
17
19
|
|
|
18
20
|
export function createInheritance(deps, { compactConversation, saveSession }) {
|
|
19
21
|
const { getSession, getRoute, mgr, createCurrentSession, invalidateContextStatusCache, getReservedSessionId } = deps;
|
|
@@ -143,6 +145,44 @@ export function createInheritance(deps, { compactConversation, saveSession }) {
|
|
|
143
145
|
};
|
|
144
146
|
}
|
|
145
147
|
|
|
148
|
+
/**
|
|
149
|
+
* The ONE carry every inheritance path shares: measure the source's
|
|
150
|
+
* conversation on the heir's scale, compact it for the heir when asked to
|
|
151
|
+
* or when it cannot fit, and append it to the (empty) heir with its
|
|
152
|
+
* inheritance boundary. Refusals throw before the heir is touched; the
|
|
153
|
+
* source is never mutated.
|
|
154
|
+
*/
|
|
155
|
+
async function carryConversation(source, target, { compact = false } = {}) {
|
|
156
|
+
// System blocks belong to the session that BUILT them: the target's own
|
|
157
|
+
// prompt was composed for the current model, tool surface, and workflow.
|
|
158
|
+
// Only the conversation itself travels.
|
|
159
|
+
let carried = inheritableMessages(source.messages);
|
|
160
|
+
if (!hasUserConversationMessage(carried)) {
|
|
161
|
+
throw new Error('inheritFrom: the source session has no conversation to carry');
|
|
162
|
+
}
|
|
163
|
+
// Decide BEFORE anything moves, on the heir's own scale. This is the
|
|
164
|
+
// same function inheritancePreflight() answers with, so the surface that
|
|
165
|
+
// offered the carry and the runtime that performs it cannot disagree —
|
|
166
|
+
// and a refusal no longer has to unwind a half-filled transcript.
|
|
167
|
+
const fit = inheritanceFit(carried, target);
|
|
168
|
+
let compacted = false;
|
|
169
|
+
// compact:true summarizes even a conversation that fits; otherwise only
|
|
170
|
+
// one that cannot fit is compacted.
|
|
171
|
+
if (compact || (fit.known && !fit.fits)) {
|
|
172
|
+
const next = await fitConversationForHeir(source, target, carried, fit, { required: compact });
|
|
173
|
+
compacted = next !== carried;
|
|
174
|
+
carried = next;
|
|
175
|
+
}
|
|
176
|
+
target.messages.push(
|
|
177
|
+
...stripEffortConfiguration(inheritedCompatReplayMessages(structuredClone(carried), source.provider))
|
|
178
|
+
);
|
|
179
|
+
target.inheritedFromSessionId = source.id;
|
|
180
|
+
target.updatedAt = Date.now();
|
|
181
|
+
recordInheritanceBoundary(target, source);
|
|
182
|
+
if (!clean(target.title) && clean(source.title)) target.title = source.title;
|
|
183
|
+
return { messages: carried.length, compacted };
|
|
184
|
+
}
|
|
185
|
+
|
|
146
186
|
/**
|
|
147
187
|
* Session inheritance (/inherit): carry another session's conversation
|
|
148
188
|
* into THIS freshly created session, so the transcript continues under a
|
|
@@ -174,41 +214,45 @@ export function createInheritance(deps, { compactConversation, saveSession }) {
|
|
|
174
214
|
}
|
|
175
215
|
const source = mgr.getSession(id);
|
|
176
216
|
if (!source) throw new Error(`inheritFrom: session ${id} was not found`);
|
|
177
|
-
|
|
178
|
-
// prompt was composed for the current model, tool surface, and workflow.
|
|
179
|
-
// Only the conversation itself travels.
|
|
180
|
-
let carried = inheritableMessages(source.messages);
|
|
181
|
-
if (!hasUserConversationMessage(carried)) {
|
|
182
|
-
throw new Error('inheritFrom: the source session has no conversation to carry');
|
|
183
|
-
}
|
|
184
|
-
// Decide BEFORE anything moves, on the heir's own scale. This is the
|
|
185
|
-
// same function inheritancePreflight() answers with, so the surface that
|
|
186
|
-
// offered the carry and the runtime that performs it cannot disagree —
|
|
187
|
-
// and a refusal no longer has to unwind a half-filled transcript.
|
|
188
|
-
const fit = inheritanceFit(carried, target);
|
|
189
|
-
// compact:true summarizes even a conversation that fits; otherwise only
|
|
190
|
-
// one that cannot fit is compacted.
|
|
191
|
-
if (compact || (fit.known && !fit.fits)) {
|
|
192
|
-
carried = await fitConversationForHeir(source, target, carried, fit, { required: compact });
|
|
193
|
-
}
|
|
194
|
-
target.messages.push(
|
|
195
|
-
...stripEffortConfiguration(inheritedCompatReplayMessages(structuredClone(carried), source.provider))
|
|
196
|
-
);
|
|
217
|
+
const { messages } = await carryConversation(source, target, { compact });
|
|
197
218
|
invalidateContextStatusCache();
|
|
198
|
-
target.inheritedFromSessionId = source.id;
|
|
199
|
-
target.updatedAt = Date.now();
|
|
200
|
-
recordInheritanceBoundary(target, source);
|
|
201
|
-
if (!clean(target.title) && clean(source.title)) target.title = source.title;
|
|
202
219
|
saveSession(target, { immediate: true });
|
|
203
220
|
invalidateContextStatusCache();
|
|
204
221
|
return {
|
|
205
222
|
sessionId: target.id,
|
|
206
223
|
sourceSessionId: source.id,
|
|
207
|
-
messages
|
|
224
|
+
messages,
|
|
208
225
|
provider: target.provider,
|
|
209
226
|
model: target.model,
|
|
210
227
|
};
|
|
211
228
|
}
|
|
212
229
|
|
|
213
|
-
|
|
230
|
+
/**
|
|
231
|
+
* Inheritance WITHOUT switching: carry a session's conversation (normally
|
|
232
|
+
* the live one, possibly mid-turn) into a NEW session on the same route,
|
|
233
|
+
* cwd and Project, persisted cold for a later resume. The live session
|
|
234
|
+
* stays the current one and is never mutated; only its committed turns
|
|
235
|
+
* travel. Same carry, compaction and refusals as inheritFrom().
|
|
236
|
+
*/
|
|
237
|
+
async function inheritToNewSession(sourceSessionId, { compact = false, titleSuffix = '' } = {}) {
|
|
238
|
+
const live = getSession();
|
|
239
|
+
const id = clean(sourceSessionId) || clean(live?.id);
|
|
240
|
+
if (!id) throw new TypeError('inheritToNewSession: source session id is required');
|
|
241
|
+
const stored = id === clean(live?.id) ? live : mgr.getSession(id);
|
|
242
|
+
if (!stored) throw new Error(`inheritFrom: session ${id} was not found`);
|
|
243
|
+
const source = committedSource(stored);
|
|
244
|
+
const heir = buildColdHeir(source);
|
|
245
|
+
const { messages, compacted } = await carryConversation(source, heir, { compact: compact === true });
|
|
246
|
+
// A suffixed title ("… (Fork)") tells the copy apart in session lists;
|
|
247
|
+
// locked as a model title so auto-titling keeps it, renames still win.
|
|
248
|
+
if (titleSuffix && clean(heir.title)) {
|
|
249
|
+
heir.title = `${clean(heir.title)}${titleSuffix}`;
|
|
250
|
+
heir.titleLocked = true;
|
|
251
|
+
heir.titleSource = 'ai';
|
|
252
|
+
}
|
|
253
|
+
await persistColdHeir(heir);
|
|
254
|
+
return { sessionId: heir.id, messages, compacted };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return { inheritancePreflight, inheritFrom, inheritToNewSession };
|
|
214
258
|
}
|
|
@@ -15,6 +15,9 @@ import {
|
|
|
15
15
|
clean,
|
|
16
16
|
} from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
17
17
|
|
|
18
|
+
import { isRealTurnMessage } from '../../runtime/agent/orchestrator/session/compact/user-message-kind.mjs';
|
|
19
|
+
import { realTurnCount as realTurnCountOf } from '../../runtime/agent/orchestrator/session/store-summary-fields.mjs';
|
|
20
|
+
|
|
18
21
|
const VISIBLE_OWNERS = ['cli', 'user', 'mixdog'];
|
|
19
22
|
|
|
20
23
|
function isLeadShaped(s, owner, sourceType) {
|
|
@@ -39,7 +42,9 @@ function previewOf(s) {
|
|
|
39
42
|
const rawPreview = s.preview || '';
|
|
40
43
|
let preview = isSessionPreviewNoise(rawPreview) ? '' : cleanSessionPreview(rawPreview);
|
|
41
44
|
let messageCount = Math.max(0, Number(s.messageCount) || 0);
|
|
45
|
+
let realTurnCount = realTurnCountOf(s);
|
|
42
46
|
if (!preview && Array.isArray(s.messages)) {
|
|
47
|
+
realTurnCount = s.messages.filter(isRealTurnMessage).length;
|
|
43
48
|
const msgs = s.messages;
|
|
44
49
|
const userPreviews = msgs
|
|
45
50
|
.filter((m) => m && m.role === 'user')
|
|
@@ -50,10 +55,10 @@ function previewOf(s) {
|
|
|
50
55
|
preview = userPreviews[0] || '';
|
|
51
56
|
messageCount = msgs.filter((m) => m && (m.role === 'user' || m.role === 'assistant')).length;
|
|
52
57
|
}
|
|
53
|
-
return { preview, messageCount };
|
|
58
|
+
return { preview, messageCount, realTurnCount };
|
|
54
59
|
}
|
|
55
60
|
|
|
56
|
-
function leadSessionRow(s, heartbeatMtimes) {
|
|
61
|
+
export function leadSessionRow(s, heartbeatMtimes) {
|
|
57
62
|
// Durable visibility is the catalog boundary. Apply it before the legacy
|
|
58
63
|
// lead-shape heuristics so an explicitly agent-only child cannot leak just
|
|
59
64
|
// because its owner field looks ordinary.
|
|
@@ -66,10 +71,14 @@ function leadSessionRow(s, heartbeatMtimes) {
|
|
|
66
71
|
// One-shot `mixdog exec` runs are never resumable conversations.
|
|
67
72
|
if (sourceType === 'exec') return null;
|
|
68
73
|
if (!isLeadShaped(s, owner, sourceType)) return null;
|
|
69
|
-
const { preview, messageCount } = previewOf(s);
|
|
74
|
+
const { preview, messageCount, realTurnCount } = previewOf(s);
|
|
70
75
|
if (!preview && messageCount === 0) return null;
|
|
71
76
|
return {
|
|
72
77
|
id: s.id,
|
|
78
|
+
// Durable provenance the desktop uses to tell a real conversation from
|
|
79
|
+
// resume scratch or synthetic-only rows when no title source survives.
|
|
80
|
+
...(realTurnCount === null ? {} : { realTurnCount }),
|
|
81
|
+
...(s.detachedReason ? { detachedReason: s.detachedReason } : {}),
|
|
73
82
|
updatedAt: s.updatedAt,
|
|
74
83
|
// Conversation-activity timestamp for Recent ordering. Without this the
|
|
75
84
|
// desktop falls back to updatedAt, which detach/resume bookkeeping
|
|
@@ -13,6 +13,8 @@ import { isScratchConversation } from '../shared.mjs';
|
|
|
13
13
|
import { compactionArchiveRange } from '../../../runtime/agent/orchestrator/session/compaction-archive.mjs';
|
|
14
14
|
import { stampCompactionMessageIds } from '../../../runtime/agent/orchestrator/session/compaction-archive-capture.mjs';
|
|
15
15
|
import { boundWorkspaceCwd, restoreWorkspaceAfterResume } from '../../workspace/workspace-state.mjs';
|
|
16
|
+
import { toolExposureMigrationNeeded } from '../../../runtime/agent/orchestrator/runtime-core/tool-exposure.mjs';
|
|
17
|
+
import { markToolSurfaceMigrated } from '../../../runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs';
|
|
16
18
|
|
|
17
19
|
export function resolveResumeCwd(session, currentCwd) {
|
|
18
20
|
// A worktree-bound Lead resumes in its worktree whatever its desktop class;
|
|
@@ -61,10 +63,14 @@ export function createSessionResume(deps, { ingestSessionIntoMemory, closeSurfac
|
|
|
61
63
|
} = deps;
|
|
62
64
|
|
|
63
65
|
function restoreResumedToolSurface(target, targetRoute) {
|
|
66
|
+
// A surface persisted with another tool exposure (e.g. a pre-bridge
|
|
67
|
+
// fixed canonical surface) migrates here; legacy selections never widen it.
|
|
68
|
+
const migrating = toolExposureMigrationNeeded(target, targetRoute.provider);
|
|
64
69
|
applyDeferredToolSurface(target, deferredSurfaceModeForLead(getMode()), getStandaloneTools(), {
|
|
65
70
|
provider: targetRoute.provider,
|
|
66
71
|
model: targetRoute.model,
|
|
67
72
|
});
|
|
73
|
+
if (migrating) markToolSurfaceMigrated(target);
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
// The resumed session's OWN effort wins. resolveRoute always returns an
|