mixdog 1.3.5 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE.md +2 -2
- package/README.md +2 -2
- package/package.json +2 -11
- package/scripts/daemon-stub.mjs +1 -1
- package/scripts/gate-local.mjs +4 -2
- package/scripts/native-release-status.mjs +2 -2
- package/scripts/recall-history-cases.json +1 -1
- package/scripts/suite-health.mjs +10 -1
- package/scripts/test.mjs +7 -11
- package/src/agents/reviewer/AGENT.md +7 -11
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +17 -1
- package/src/defaults/skills/browser-use/SKILL.md +59 -11
- package/src/defaults/skills/code-tidy/SKILL.md +142 -270
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
- package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
- package/src/defaults/skills/computer-use/SKILL.md +33 -9
- package/src/defaults/skills/setup/SKILL.md +22 -0
- package/src/defaults/skills/setup/references/actions.md +39 -5
- package/src/defaults/skills/setup/references/surfaces.md +11 -2
- package/src/defaults/skills/visualize/SKILL.md +2 -1
- package/src/lib/rules-builder.cjs +10 -8
- package/src/rules/agent/AGENT.md +6 -6
- package/src/rules/lead/LEAD.md +18 -20
- package/src/rules/shared/05-tool-calls.md +5 -6
- package/src/rules/shared/10-tool-workflow.md +2 -0
- package/src/rules/shared/60-verification.md +7 -5
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
- package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
- package/src/runtime/agent/orchestrator/config.mjs +17 -1
- package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +72 -67
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +54 -1
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +176 -72
- package/src/runtime/agent/orchestrator/mcp/client.mjs +19 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +181 -133
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +42 -6
- package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +145 -66
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +64 -33
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +123 -102
- package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -13
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
- package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
- package/src/runtime/agent/orchestrator/providers/registry.mjs +26 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +12 -7
- package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +792 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +133 -22
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
- package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +0 -2
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +18 -22
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +32 -3
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +12 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +23 -13
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +129 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +20 -2
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +18 -5
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +19 -8
- package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +36 -9
- package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
- package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
- package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
- package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +8 -6
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -14
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +84 -3
- package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
- package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +18 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +65 -7
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
- package/src/runtime/browser-bridge/action-schema.mjs +13 -2
- package/src/runtime/browser-bridge/client.mjs +73 -8
- package/src/runtime/browser-bridge/input-fields.mjs +8 -9
- package/src/runtime/browser-bridge/mail-links.mjs +107 -0
- package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
- package/src/runtime/channels/lib/config.mjs +6 -61
- package/src/runtime/channels/lib/crash-log.mjs +1 -1
- package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
- package/src/runtime/channels/lib/event-queue.mjs +3 -18
- package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
- package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
- package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
- package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
- package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
- package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
- package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
- package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
- package/src/runtime/channels/lib/scheduler.mjs +33 -147
- package/src/runtime/channels/lib/schedules-db.mjs +34 -11
- package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/tool-dispatch.mjs +1 -2
- package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
- package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
- package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
- package/src/runtime/channels/lib/worker-main.mjs +10 -34
- package/src/runtime/computer-bridge/action-schema.mjs +42 -1
- package/src/runtime/computer-bridge/actions.mjs +9 -1
- package/src/runtime/computer-bridge/client.mjs +180 -8
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +27 -2
- package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
- package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
- package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
- package/src/runtime/connectors/gmail-app-password.mjs +172 -39
- package/src/runtime/connectors/google-mcp.mjs +10 -12
- package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
- package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
- package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
- package/src/runtime/session-search/session-search-db.mjs +73 -9
- package/src/runtime/session-search/session-search-ingest.mjs +110 -20
- package/src/runtime/shared/abort-race.mjs +89 -0
- package/src/runtime/shared/agent-avatar.d.mts +0 -1
- package/src/runtime/shared/agent-kind.mjs +4 -3
- package/src/runtime/shared/bounded-download.mjs +8 -3
- package/src/runtime/shared/config.mjs +2 -13
- package/src/runtime/shared/connector-accounts.mjs +20 -10
- package/src/runtime/shared/connector-catalog.d.mts +29 -0
- package/src/runtime/shared/connector-catalog.mjs +150 -0
- package/src/runtime/shared/connector-triggers.mjs +22 -19
- package/src/runtime/shared/defaults-separation.mjs +2 -14
- package/src/runtime/shared/delegated-approval-host.mjs +103 -11
- package/src/runtime/shared/err-text.mjs +24 -15
- package/src/runtime/shared/file-permissions.d.mts +0 -8
- package/src/runtime/shared/file-permissions.mjs +0 -11
- package/src/runtime/shared/git-direct.test-support.mjs +19 -0
- package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
- package/src/runtime/shared/heartbeat-interval.mjs +19 -0
- package/src/runtime/shared/idle-auto-clear-gate.mjs +104 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
- package/src/runtime/shared/mixy-presence.mjs +22 -0
- package/src/runtime/shared/orchestration.d.mts +2 -0
- package/src/runtime/shared/pg-schema-db.mjs +27 -16
- package/src/runtime/shared/profile-config.cjs +1 -1
- package/src/runtime/shared/prompt-origin.d.mts +4 -0
- package/src/runtime/shared/prompt-origin.mjs +21 -0
- package/src/runtime/shared/provider-accounts.mjs +7 -1
- package/src/runtime/shared/provider-display-name.mjs +29 -0
- package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
- package/src/runtime/shared/routine-trigger.d.mts +2 -0
- package/src/runtime/shared/routine-trigger.mjs +10 -0
- package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
- package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
- package/src/runtime/shared/session-activity-signal.mjs +34 -1
- package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
- package/src/runtime/shared/session-sidebar-host.mjs +7 -3
- package/src/runtime/shared/session-turn-prelude.mjs +18 -0
- package/src/runtime/shared/tool-result-summary.mjs +1 -14
- package/src/runtime/shared/worktrees/test-support.mjs +9 -4
- package/src/runtime/terminal-bridge/client.mjs +10 -1
- package/src/runtime/visualize-bridge/client.mjs +27 -8
- package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
- package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
- package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
- package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
- package/src/session-runtime/agent-home-delivery.mjs +448 -185
- package/src/session-runtime/agent-task-sessions.mjs +329 -180
- package/src/session-runtime/boot/apis.mjs +9 -0
- package/src/session-runtime/boot/infrastructure.mjs +4 -0
- package/src/session-runtime/boot/providers.mjs +3 -0
- package/src/session-runtime/boot/tools.mjs +6 -1
- package/src/session-runtime/config-lifecycle.mjs +6 -0
- package/src/session-runtime/connector-merge-migration.mjs +305 -0
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +132 -28
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +2 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
- package/src/session-runtime/lifecycle/session-catalog.mjs +3 -1
- package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
- package/src/session-runtime/lifecycle/teardown.mjs +23 -5
- package/src/session-runtime/mcp-glue/server-catalog.mjs +55 -3
- package/src/session-runtime/mcp-oauth-login.mjs +5 -3
- package/src/session-runtime/mixy-heartbeat.mjs +153 -33
- package/src/session-runtime/notification-bus.mjs +31 -117
- package/src/session-runtime/notification-completion-queue.mjs +54 -0
- package/src/session-runtime/notification-listeners.mjs +76 -0
- package/src/session-runtime/owned-automation-run.mjs +2 -1
- package/src/session-runtime/prewarm/channel-start.mjs +3 -7
- package/src/session-runtime/resource-mcp-api.mjs +143 -224
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
- package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
- package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
- package/src/session-runtime/resource-mcp-servers.mjs +78 -0
- package/src/session-runtime/resource-mcp-store.mjs +49 -0
- package/src/session-runtime/routine-owner.mjs +40 -9
- package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +7 -2
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
- package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
- package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
- package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
- package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
- package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
- package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
- package/src/session-runtime/services/channel-admin.mjs +7 -13
- package/src/session-runtime/services/channel-session-router.mjs +4 -2
- package/src/session-runtime/services/seeds.mjs +0 -28
- package/src/session-runtime/session-compaction-sync.mjs +27 -0
- package/src/session-runtime/session-create/session-options.mjs +1 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
- package/src/session-runtime/settings-compaction-api.mjs +2 -40
- package/src/session-runtime/settings-system-api.mjs +13 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
- package/src/session-runtime/setup-tool/executor.mjs +145 -22
- package/src/session-runtime/setup-tool/extended-actions.mjs +8 -3
- package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +4 -3
- package/src/session-runtime/setup-tool/tool-defs.mjs +64 -5
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
- package/src/session-runtime/tool-policy/policy-stage.mjs +16 -2
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
- package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
- package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
- package/src/standalone/channel-transport/client-registry.mjs +24 -163
- package/src/standalone/channel-transport.mjs +1 -1
- package/src/standalone/daemon-channels-loader.mjs +10 -8
- package/src/standalone/daemon-session-control/list-page.mjs +72 -0
- package/src/standalone/daemon-session-control/request.mjs +51 -0
- package/src/standalone/daemon-session-control/room-host.mjs +57 -0
- package/src/standalone/daemon-session-control/route-control.mjs +48 -0
- package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
- package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
- package/src/standalone/daemon-session-control.mjs +124 -188
- package/src/standalone/daemon.mjs +26 -3
- package/src/standalone/session-client.mjs +7 -3
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
- package/src/standalone/session-service/quota-resume.mjs +3 -0
- package/src/standalone/session-service/retention/busy.mjs +65 -1
- package/src/standalone/session-service/session-calls/session-action.mjs +23 -2
- package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
- package/src/standalone/session-tool-output.mjs +15 -7
- package/src/tui/app/model-options.mjs +3 -28
- package/src/tui/dist/index.mjs +58 -64
- package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
- package/src/tui/session/initial-state.mjs +3 -0
- package/src/tui/session/notice-surface.mjs +7 -1
- package/src/tui/session/queue-helpers.mjs +3 -42
- package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
- package/src/tui/session/session-api/routes-write.mjs +5 -1
- package/src/tui/session/session-api/routes.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +17 -1
- package/src/tui/session/session-flow/auto-clear.mjs +4 -33
- package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
- package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
- package/src/tui/session/session-flow/drain-retry.mjs +35 -0
- package/src/tui/session/session-flow/drain.mjs +118 -149
- package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
- package/src/tui/session/session-flow/queue/take-entries.mjs +5 -2
- package/src/tui/session/tool-approval-delegation.mjs +64 -0
- package/src/tui/session/tool-approval-request.mjs +39 -0
- package/src/tui/session/tool-approval-settle.mjs +62 -0
- package/src/tui/session/tool-approval.mjs +69 -115
- package/src/tui/session/tui-steering-persist.mjs +8 -1
- package/src/tui/session/turn-stream.mjs +19 -2
- package/src/tui/session/turn.mjs +1 -0
- package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
- package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
- package/scripts/code-graph-description-contract.mjs +0 -188
- package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
|
@@ -4,6 +4,7 @@ import { isDeliveredCompletion, logDuplicateSkip } from './delivered-completions
|
|
|
4
4
|
import { promptContentText } from './prompt-utils.mjs';
|
|
5
5
|
import { parseTaskNotification, taskNotificationId } from '../../../../shared/task-notification-envelope.mjs';
|
|
6
6
|
import { hopOf } from '../../../../shared/bot-hops.mjs';
|
|
7
|
+
import { PROMPT_ORIGIN_CHANNEL } from '../../../../shared/prompt-origin.mjs';
|
|
7
8
|
|
|
8
9
|
const STALE_USER_INJECTION_TTL_MS = 30 * 60 * 1000;
|
|
9
10
|
const PENDING_PROCESS_START_MS = Date.now();
|
|
@@ -12,6 +13,8 @@ const LIFECYCLE_TOKEN = Symbol('pendingLifecycleToken');
|
|
|
12
13
|
export const COMPLETION_NOTIFICATION_KIND = 'completion_notification';
|
|
13
14
|
export const PENDING_MODE_PROMPT = 'prompt';
|
|
14
15
|
export const PENDING_MODE_TASK_NOTIFICATION = 'task-notification';
|
|
16
|
+
// Prompt provenance apart from the presentation mode (shared/prompt-origin.mjs).
|
|
17
|
+
export { PROMPT_ORIGIN_AGENT_REPORT, PROMPT_ORIGIN_CHANNEL } from '../../../../shared/prompt-origin.mjs';
|
|
15
18
|
|
|
16
19
|
export function stampLifecycleToken(entry, token) {
|
|
17
20
|
if (!entry || typeof entry !== 'object' || !token) return entry;
|
|
@@ -169,9 +172,14 @@ export function lateDeliveryText(text, entry, now = Date.now()) {
|
|
|
169
172
|
// A non-completion entry may be queued explicitly as a task notification (a
|
|
170
173
|
// runtime/channel notice, never the user typing): the mode survives
|
|
171
174
|
// normalization and the durable spool so the drain stores it as one and it
|
|
172
|
-
// never drives explicit skill selection.
|
|
175
|
+
// never drives explicit skill selection. A channel's inbound message keeps
|
|
176
|
+
// its provenance beside the mode (PROMPT_ORIGIN_CHANNEL).
|
|
173
177
|
function explicitModeField(entry) {
|
|
174
|
-
|
|
178
|
+
if (entry?.mode !== PENDING_MODE_TASK_NOTIFICATION) return {};
|
|
179
|
+
return {
|
|
180
|
+
mode: PENDING_MODE_TASK_NOTIFICATION,
|
|
181
|
+
...(entry.origin === PROMPT_ORIGIN_CHANNEL ? { origin: PROMPT_ORIGIN_CHANNEL } : {}),
|
|
182
|
+
};
|
|
175
183
|
}
|
|
176
184
|
|
|
177
185
|
function normalizePendingMessageEntry(entry) {
|
|
@@ -343,6 +351,7 @@ export function _groupPendingMessageEntries(entries) {
|
|
|
343
351
|
mode: PENDING_MODE_TASK_NOTIFICATION,
|
|
344
352
|
...(normalized.execution ? { execution: normalized.execution } : {}),
|
|
345
353
|
...(normalized.hop ? { hop: normalized.hop } : {}),
|
|
354
|
+
...(normalized.origin ? { origin: normalized.origin } : {}),
|
|
346
355
|
ids: idsOf([entry]),
|
|
347
356
|
entries: [entry],
|
|
348
357
|
});
|
|
@@ -33,6 +33,19 @@ function plainToolCalls(toolCalls) {
|
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/** The provider-native replay state `message` carries — its replay fields'
|
|
37
|
+
* values and its tool calls' signatures — or null when it carries none. */
|
|
38
|
+
export function providerReplayState(message) {
|
|
39
|
+
if (!message || typeof message !== 'object') return null;
|
|
40
|
+
const state = PROVIDER_REPLAY_FIELDS.filter((field) => field in message).map((field) => message[field]);
|
|
41
|
+
for (const call of Array.isArray(message.toolCalls) ? message.toolCalls : []) {
|
|
42
|
+
if (call && typeof call === 'object') {
|
|
43
|
+
for (const field of TOOL_CALL_SIGNATURE_FIELDS) if (field in call) state.push(call[field]);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return state.length ? state : null;
|
|
47
|
+
}
|
|
48
|
+
|
|
36
49
|
/** `message` without provider-native replay state; the same object when it carries none. */
|
|
37
50
|
export function stripProviderReplayMessage(message) {
|
|
38
51
|
if (!message || typeof message !== 'object') return message;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// The fallback chain a running session follows, read from its settings when
|
|
2
|
+
// it is needed (a hop, a status read) instead of the copy taken at creation:
|
|
3
|
+
// an edit made while the session runs applies from its next model request,
|
|
4
|
+
// and a chain cleared to [] stops further hops at once.
|
|
5
|
+
// - A Lead-class session (coding Lead, a bot's chat, Mixy) follows its
|
|
6
|
+
// owner's stored route (owner-route-fallbacks.mjs);
|
|
7
|
+
// - a delegated agent follows the route it was spawned from
|
|
8
|
+
// (`routeFallbackSource`: its agent's route, else Main's, or a named preset).
|
|
9
|
+
// The stored chain applies only while the session's primary — the route it
|
|
10
|
+
// ran on before its first hop — is that stored route's model. A session
|
|
11
|
+
// whose source cannot be read (an older record, a direct route) keeps its own.
|
|
12
|
+
import { findPreset } from '../../runtime-core/config-helpers.mjs';
|
|
13
|
+
import { normalizeWorkflowRoute } from '../../runtime-core/workflow.mjs';
|
|
14
|
+
import { configuredAgentRouteCandidates } from '../../../../shared/agent-route-config.mjs';
|
|
15
|
+
import { CODING_MODE, resolveSessionMode } from '../agent-mode.mjs';
|
|
16
|
+
import { _liveSessions } from '../store/live-state.mjs';
|
|
17
|
+
import { ownerConfiguredRoute, sameRouteModel } from './owner-route-fallbacks.mjs';
|
|
18
|
+
|
|
19
|
+
const LEAF_FIELDS = ['effort', 'fast', 'autoEffort', 'modelParameters', 'contextPercent', 'contextTokens'];
|
|
20
|
+
|
|
21
|
+
/** The switchable fields of a route or session record (no chain). */
|
|
22
|
+
export function routeLeaf(route) {
|
|
23
|
+
const leaf = { provider: route?.provider || '', model: route?.model || '' };
|
|
24
|
+
for (const key of LEAF_FIELDS) if (route?.[key] !== undefined && route[key] !== null) leaf[key] = route[key];
|
|
25
|
+
return leaf;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The route the session ran on before its first fallback hop; its own route
|
|
29
|
+
* while it has not hopped. */
|
|
30
|
+
export function sessionRoutePrimary(session) {
|
|
31
|
+
if (session?.routeFallbackPrimary?.provider) return session.routeFallbackPrimary;
|
|
32
|
+
const first = session?.routeFallbackFailures?.[0];
|
|
33
|
+
if (first?.provider && first?.model) return { provider: first.provider, model: first.model };
|
|
34
|
+
return routeLeaf(session);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function normalizedOrNull(stored) {
|
|
38
|
+
if (!stored) return null;
|
|
39
|
+
try {
|
|
40
|
+
return normalizeWorkflowRoute(stored) || null;
|
|
41
|
+
} catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The stored route the session's chain comes from, read now; null when the
|
|
47
|
+
* session has no readable source (it then keeps its own chain). */
|
|
48
|
+
export function sessionChainSource(session, config) {
|
|
49
|
+
const { mode, agentId } = resolveSessionMode({ session });
|
|
50
|
+
if (agentId) return ownerConfiguredRoute({ sessionMode: mode, agentId, config });
|
|
51
|
+
const source = session?.routeFallbackSource;
|
|
52
|
+
if (source?.agent) {
|
|
53
|
+
// As the spawn resolved it: the agent's own route, else Main's.
|
|
54
|
+
const own = configuredAgentRouteCandidates(config, source.agent).map(normalizedOrNull).find(Boolean);
|
|
55
|
+
return own || normalizedOrNull(findPreset(config, config?.default));
|
|
56
|
+
}
|
|
57
|
+
if (source?.preset) return normalizedOrNull(findPreset(config, source.preset));
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** `{ chain, fromSettings }`: the fallback routes the session follows now. */
|
|
62
|
+
export function liveRouteFallbacks(session, config) {
|
|
63
|
+
const source = sessionChainSource(session, config);
|
|
64
|
+
if (!source)
|
|
65
|
+
return { chain: Array.isArray(session?.routeFallbacks) ? session.routeFallbacks : [], fromSettings: false };
|
|
66
|
+
const onSourcePrimary = sameRouteModel(source, sessionRoutePrimary(session));
|
|
67
|
+
return { chain: onSourcePrimary ? source.fallbacks || [] : [], fromSettings: true };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Index in `chain` of the next route to try: the first after the session's
|
|
71
|
+
* current model that this session has not already run (its primary and the
|
|
72
|
+
* models it already left); `chain.length` when none is left. */
|
|
73
|
+
export function nextRouteFallbackIndex(session, chain) {
|
|
74
|
+
const tried = [sessionRoutePrimary(session), ...(session?.routeFallbackFailures || []), session];
|
|
75
|
+
const at = chain.findIndex((entry) => sameRouteModel(entry, session));
|
|
76
|
+
for (let index = at + 1; index < chain.length; index += 1) {
|
|
77
|
+
if (!tried.some((route) => sameRouteModel(chain[index], route))) return index;
|
|
78
|
+
}
|
|
79
|
+
return chain.length;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const modelOf = (route) => ({ provider: route?.provider || '', model: route?.model || '' });
|
|
83
|
+
|
|
84
|
+
/** The public fallback position of one session: the route it is on against
|
|
85
|
+
* its primary, the hop index, the chain it follows now and why it left each model. */
|
|
86
|
+
export function routeFallbackPosition(session, config) {
|
|
87
|
+
const { chain, fromSettings } = liveRouteFallbacks(session, config);
|
|
88
|
+
const next = chain[nextRouteFallbackIndex(session, chain)] || null;
|
|
89
|
+
const primary = sessionRoutePrimary(session);
|
|
90
|
+
const { mode, agentId } = resolveSessionMode({ session });
|
|
91
|
+
let kind = 'agent';
|
|
92
|
+
if (agentId) kind = mode === CODING_MODE ? 'lead' : 'bot';
|
|
93
|
+
return {
|
|
94
|
+
sessionId: session.id,
|
|
95
|
+
kind,
|
|
96
|
+
agent: agentId || session.agent || null,
|
|
97
|
+
current: modelOf(session),
|
|
98
|
+
primary: modelOf(primary),
|
|
99
|
+
onPrimary: sameRouteModel(primary, session),
|
|
100
|
+
fallbackIndex: Number(session.routeFallbackIndex) || 0,
|
|
101
|
+
fallbacks: chain.map(modelOf),
|
|
102
|
+
chainFrom: fromSettings ? 'settings' : 'session',
|
|
103
|
+
next: next ? modelOf(next) : null,
|
|
104
|
+
failures: (session.routeFallbackFailures || []).map(({ provider, model, kind: errorKind, error }) => ({
|
|
105
|
+
provider,
|
|
106
|
+
model,
|
|
107
|
+
kind: errorKind,
|
|
108
|
+
error,
|
|
109
|
+
})),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Whether the session has left its primary for a fallback model. */
|
|
114
|
+
export const routeFallbackHopped = (session) =>
|
|
115
|
+
Number(session?.routeFallbackIndex) > 0 || Boolean(session?.routeFallbackFailures?.length);
|
|
116
|
+
|
|
117
|
+
/** Positions of the sessions held in this process that follow a chain or have
|
|
118
|
+
* hopped; `keep(position)` narrows them. */
|
|
119
|
+
export function liveRouteFallbackPositions(config, keep = () => true) {
|
|
120
|
+
const rows = [];
|
|
121
|
+
for (const session of _liveSessions.values()) {
|
|
122
|
+
// Only a session with an agent hops (advanceAgentRoute).
|
|
123
|
+
if (!session?.id || session.closed === true || !session.agent) continue;
|
|
124
|
+
const position = routeFallbackPosition(session, config);
|
|
125
|
+
if (!position.fallbacks.length && !routeFallbackHopped(session)) continue;
|
|
126
|
+
if (keep(position)) rows.push(position);
|
|
127
|
+
}
|
|
128
|
+
return rows;
|
|
129
|
+
}
|
|
@@ -23,10 +23,12 @@
|
|
|
23
23
|
// }
|
|
24
24
|
import { createAbortController } from '../../../../shared/abort-controller.mjs';
|
|
25
25
|
import { emitSessionApprovalWaitChange } from '../../../../shared/session-approval-wait.mjs';
|
|
26
|
-
import { emitSessionActivityChange } from '../../../../shared/session-activity-signal.mjs';
|
|
26
|
+
import { emitSessionActivityChange, emitSessionTurnStart } from '../../../../shared/session-activity-signal.mjs';
|
|
27
27
|
import { DEFAULT_ACTIVITY_HEARTBEAT_MS } from '../../stall-policy.mjs';
|
|
28
28
|
import { MODEL_THINKING_STAGE, awaitingModelResponse, lastProgressAt } from '../../../../shared/quiet-progress.mjs';
|
|
29
|
-
import { finishBrowserTurn } from '../../../../browser-bridge/client.mjs';
|
|
29
|
+
import { beginBrowserTurn, finishBrowserTurn, forgetBrowserSession } from '../../../../browser-bridge/client.mjs';
|
|
30
|
+
import { registerSessionPurgeHook } from '../store.mjs';
|
|
31
|
+
import { finishComputerTurn } from '../../../../computer-bridge/client.mjs';
|
|
30
32
|
import { configureUsageMetricsRuntime, dropMetricSeenState, bumpUsageMetricsTurnId } from './usage-metrics.mjs';
|
|
31
33
|
import { runtimeState as _runtimeState, isTurnInFlight } from './runtime-state.mjs';
|
|
32
34
|
|
|
@@ -48,11 +50,25 @@ const VALID_STAGES = new Set([
|
|
|
48
50
|
]);
|
|
49
51
|
const TERMINAL_STAGES = new Set(['done', 'error']);
|
|
50
52
|
|
|
53
|
+
function beginBrowserWork(id, entry) {
|
|
54
|
+
void beginBrowserTurn(id, entry.browserTurnId).catch((error) => {
|
|
55
|
+
process.stderr.write(`[browser] Task start failed: ${error?.message || error}\n`);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// A session deleted for good no longer has browser turns to report.
|
|
60
|
+
registerSessionPurgeHook(forgetBrowserSession);
|
|
61
|
+
|
|
51
62
|
function finishBrowserWork(id, entry, aborted = false) {
|
|
52
63
|
const turnId = Number(entry.browserTurnId ?? entry.session?.usageMetricsTurnId) || 0;
|
|
53
64
|
void finishBrowserTurn(id, turnId, { aborted }).catch((error) => {
|
|
54
65
|
process.stderr.write(`[browser] Task cleanup failed: ${error?.message || error}\n`);
|
|
55
66
|
});
|
|
67
|
+
// The same terminal state settles the turn's Computer Use saved-login fills
|
|
68
|
+
// (lead and sub-agent sessions alike).
|
|
69
|
+
void finishComputerTurn(id, turnId).catch((error) => {
|
|
70
|
+
process.stderr.write(`[computer] Turn settlement failed: ${error?.message || error}\n`);
|
|
71
|
+
});
|
|
56
72
|
}
|
|
57
73
|
|
|
58
74
|
// Injected deps that would otherwise pull manager.mjs's store/provider surface
|
|
@@ -149,6 +165,7 @@ export function markSessionAskStart(id) {
|
|
|
149
165
|
const sessionForTurn = entry.session ?? _deps.loadSession(id);
|
|
150
166
|
if (sessionForTurn) bumpUsageMetricsTurnId(sessionForTurn);
|
|
151
167
|
entry.browserTurnId = Number(sessionForTurn?.usageMetricsTurnId) || 0;
|
|
168
|
+
beginBrowserWork(id, entry);
|
|
152
169
|
entry.stage = 'connecting';
|
|
153
170
|
entry.lastStreamDeltaAt = null;
|
|
154
171
|
entry.lastTransportAt = null;
|
|
@@ -179,6 +196,7 @@ export function markSessionAskStart(id) {
|
|
|
179
196
|
entry.lastProgressAt = now;
|
|
180
197
|
entry.updatedAt = now;
|
|
181
198
|
entry.taskWaits = 0;
|
|
199
|
+
emitSessionTurnStart(id);
|
|
182
200
|
emitSessionActivityChange(id);
|
|
183
201
|
}
|
|
184
202
|
/** The provider put the request on the wire; its response headers are
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from './runtime-liveness.mjs';
|
|
25
25
|
import { clearTurnCheckpoint } from './turn-checkpoint.mjs';
|
|
26
26
|
import { forgetSessionSaveBaseline } from '../store/save-worker.mjs';
|
|
27
|
+
import { publishSessionPersistence } from '../store/session-persistence-events.mjs';
|
|
27
28
|
import { forgetSessionLoadCache } from '../store/load-cache.mjs';
|
|
28
29
|
import { releaseReadSnapshotScope } from '../../tools/builtin/snapshot-store.mjs';
|
|
29
30
|
import { cancelOwnedShellTrees } from '../../tools/lib/owned-shell-trees.mjs';
|
|
@@ -142,6 +143,7 @@ function finishClose({ id, reason, tombstone, entry, closeSnapshot, newGen, outc
|
|
|
142
143
|
// above; committing it stops the turn's checkpoint writer. Only now is it
|
|
143
144
|
// safe to remove the crash fallback.
|
|
144
145
|
closeSnapshot?.commit();
|
|
146
|
+
publishSessionPersistence(id, 'closed');
|
|
145
147
|
_stopToolActivityHeartbeat(id);
|
|
146
148
|
cancelOwnedShellProcesses({ id, reason, tombstone });
|
|
147
149
|
clearTurnCheckpoint(id);
|
|
@@ -288,6 +288,13 @@ export function createSession(createOpts) {
|
|
|
288
288
|
if (rulesRevision) session.rulesRevision = rulesRevision;
|
|
289
289
|
}
|
|
290
290
|
if (routeFallbacks?.length) session.routeFallbacks = routeFallbacks;
|
|
291
|
+
// Where an agent's chain is read from at each hop (route-fallback-chain.mjs).
|
|
292
|
+
const fallbackSource = Object.hasOwn(opts, 'routeFallbackSource')
|
|
293
|
+
? opts.routeFallbackSource
|
|
294
|
+
: presetObj?.fallbackSource;
|
|
295
|
+
if (!actingAgent && fallbackSource && typeof fallbackSource === 'object') {
|
|
296
|
+
session.routeFallbackSource = { ...fallbackSource };
|
|
297
|
+
}
|
|
291
298
|
// A non-native agent sends core + bridge, built from its filtered tools.
|
|
292
299
|
applyAgentToolExposure(session);
|
|
293
300
|
refreshSessionBp3Environment(session, opts.cwd);
|
|
@@ -364,6 +371,7 @@ function applyRouteFields(session, route) {
|
|
|
364
371
|
else delete session.routeFallbacks;
|
|
365
372
|
delete session.routeFallbackIndex;
|
|
366
373
|
delete session.routeFallbackFailures;
|
|
374
|
+
delete session.routeFallbackPrimary;
|
|
367
375
|
}
|
|
368
376
|
ensureCodexWireSessionId(session);
|
|
369
377
|
if (Object.hasOwn(route, 'modelParameters')) {
|
|
@@ -36,7 +36,7 @@ export function normalizeDesktopSessionMetadata(value, cwd = null) {
|
|
|
36
36
|
return null;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
function initialCompactionConfig(compaction = {}, contextMeta = {}) {
|
|
39
|
+
export function initialCompactionConfig(compaction = {}, contextMeta = {}) {
|
|
40
40
|
return {
|
|
41
41
|
auto: compaction?.auto !== false,
|
|
42
42
|
model: compaction?.model || null,
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import { compareCodePoints } from '../../../../shared/code-point-order.mjs';
|
|
4
4
|
import { getMcpTools } from '../../mcp/client.mjs';
|
|
5
5
|
import { getInternalTools } from '../../internal-tools.mjs';
|
|
6
|
-
import { BUILTIN_TOOLS } from '../../tools/builtin/builtin-tools.mjs';
|
|
6
|
+
import { BUILTIN_TOOLS, bindShellKind } from '../../tools/builtin/builtin-tools.mjs';
|
|
7
|
+
import { resolveShellFor } from '../../tools/builtin/shell-runtime.mjs';
|
|
7
8
|
import { PATCH_TOOL_DEFS } from '../../tools/patch-tool-defs.mjs';
|
|
8
9
|
import { CODE_GRAPH_TOOL_DEFS } from '../../tools/code-graph-tool-defs.mjs';
|
|
9
10
|
import { buildSkillToolDefs } from '../../context/collect.mjs';
|
|
@@ -101,7 +102,11 @@ export function resolveSessionTools(
|
|
|
101
102
|
// time (loop.mjs), so the schema bytes stay bit-identical across roles /
|
|
102
103
|
// cwds and the provider cache shard does not fragment.
|
|
103
104
|
const skillTools = buildSkillToolDefs(skills, { ownerIsAgentSession });
|
|
104
|
-
|
|
105
|
+
// The shell text follows the system shell the runtime actually resolves
|
|
106
|
+
// (Git Bash/WSL on Windows, pwsh on POSIX), before the edit-dialect rewrite.
|
|
107
|
+
const shellKind = resolveShellFor('default')?.shellType;
|
|
108
|
+
const base = _computeBaseTools(toolSpec, mcp, skillTools).map((tool) => bindShellKind(tool, shellKind));
|
|
109
|
+
return filterModelEditTools(base, modelName);
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
export function previewSessionTools(toolSpec, skills = [], options = {}) {
|
|
@@ -39,6 +39,8 @@ import { join } from 'node:path';
|
|
|
39
39
|
import { getPluginData } from '../../config.mjs';
|
|
40
40
|
import { writeFileAtomicSync } from '../../../../shared/atomic-file.mjs';
|
|
41
41
|
import { sanitizeContentForStoredHistory } from '../../providers/media-normalization.mjs';
|
|
42
|
+
import { redactSettledText, sensitiveValuesVersion } from '../sensitive-values.mjs';
|
|
43
|
+
import { redactSensitiveContent, redactSensitiveMessage, redactSensitiveToolCall } from '../sensitive-projection.mjs';
|
|
42
44
|
import { promptContentText } from './prompt-utils.mjs';
|
|
43
45
|
|
|
44
46
|
const TURN_CHECKPOINT_VERSION = 1;
|
|
@@ -96,7 +98,7 @@ export function checkpointMessage(message) {
|
|
|
96
98
|
return content === message.content ? message : { ...message, content };
|
|
97
99
|
}
|
|
98
100
|
|
|
99
|
-
|
|
101
|
+
function matchingUserMessage(message, currentUserContent) {
|
|
100
102
|
return (
|
|
101
103
|
message?.role === 'user' &&
|
|
102
104
|
(message.content === currentUserContent ||
|
|
@@ -131,16 +133,54 @@ export function emptyInterruptionSnapshot() {
|
|
|
131
133
|
};
|
|
132
134
|
}
|
|
133
135
|
|
|
134
|
-
//
|
|
136
|
+
// Observed tool calls ([id, { call, eagerStarted }]) and early tool results
|
|
137
|
+
// ([id, tool message]) as a checkpoint stores them (sensitive-projection.mjs).
|
|
138
|
+
const storedCallEntries = (sessionId, entries) =>
|
|
139
|
+
entries.map(([id, entry]) => {
|
|
140
|
+
const call = redactSensitiveToolCall(sessionId, entry?.call);
|
|
141
|
+
return [id, call === entry?.call ? entry : { ...entry, call }];
|
|
142
|
+
});
|
|
143
|
+
const storedResultEntries = (sessionId, entries) =>
|
|
144
|
+
entries.map(([id, message]) => [id, redactSensitiveMessage(sessionId, message)]);
|
|
145
|
+
|
|
146
|
+
/** Interruption snapshot `snapshot` as `sessionId`'s checkpoint stores it:
|
|
147
|
+
* sensitive values (sensitive-values.mjs) replaced, and of the partial text
|
|
148
|
+
* only what no value can still complete. */
|
|
149
|
+
function redactInterruptionSnapshot(sessionId, snapshot) {
|
|
150
|
+
const source = snapshot ?? emptyInterruptionSnapshot();
|
|
151
|
+
if (!sensitiveValuesVersion(sessionId)) return source;
|
|
152
|
+
return {
|
|
153
|
+
...source,
|
|
154
|
+
partialAssistantContent: redactSettledText(sessionId, String(source.partialAssistantContent || '')),
|
|
155
|
+
partialReasoningContent: redactSettledText(sessionId, String(source.partialReasoningContent || '')),
|
|
156
|
+
observedToolCalls: storedCallEntries(
|
|
157
|
+
sessionId,
|
|
158
|
+
Array.isArray(source.observedToolCalls) ? source.observedToolCalls : []
|
|
159
|
+
),
|
|
160
|
+
observedToolResults: storedResultEntries(
|
|
161
|
+
sessionId,
|
|
162
|
+
Array.isArray(source.observedToolResults) ? source.observedToolResults : []
|
|
163
|
+
),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ── Header (written once per turn, again when a sensitive value is marked) ──
|
|
135
168
|
|
|
136
169
|
export function writeCheckpointHeader(checkpoint) {
|
|
137
|
-
const
|
|
170
|
+
const { sessionId } = checkpoint;
|
|
171
|
+
const target = turnCheckpointPath(sessionId);
|
|
138
172
|
const payload = {
|
|
139
173
|
...checkpoint,
|
|
140
174
|
version: TURN_CHECKPOINT_VERSION,
|
|
141
|
-
currentUserContent:
|
|
142
|
-
|
|
143
|
-
|
|
175
|
+
currentUserContent: redactSensitiveContent(
|
|
176
|
+
sessionId,
|
|
177
|
+
sanitizeContentForStoredHistory(checkpoint.currentUserContent)
|
|
178
|
+
),
|
|
179
|
+
turnMessages: (Array.isArray(checkpoint.turnMessages) ? checkpoint.turnMessages : []).map((message) =>
|
|
180
|
+
redactSensitiveMessage(sessionId, checkpointMessage(message))
|
|
181
|
+
),
|
|
182
|
+
interruption: redactInterruptionSnapshot(sessionId, checkpoint.interruption),
|
|
183
|
+
// Counts, token readings and signatures only: no text.
|
|
144
184
|
contextState: checkpoint.contextState ?? null,
|
|
145
185
|
updatedAt: Date.now(),
|
|
146
186
|
};
|
|
@@ -488,7 +528,15 @@ export function replayTurnJournal(header) {
|
|
|
488
528
|
if (seq > expected) break;
|
|
489
529
|
expected = seq + 1;
|
|
490
530
|
if (!head) {
|
|
491
|
-
|
|
531
|
+
// A header rewritten for a newly marked sensitive value starts a new
|
|
532
|
+
// journal epoch; the journal it replaces never replays onto it.
|
|
533
|
+
if (
|
|
534
|
+
record.t !== 'h' ||
|
|
535
|
+
record.turnToken !== header.turnToken ||
|
|
536
|
+
(Number(record.e) || 0) !== (Number(header.journalEpoch) || 0)
|
|
537
|
+
) {
|
|
538
|
+
return header;
|
|
539
|
+
}
|
|
492
540
|
head = true;
|
|
493
541
|
continue;
|
|
494
542
|
}
|
|
@@ -529,7 +577,7 @@ export function replayTurnJournal(header) {
|
|
|
529
577
|
* turn-relative index) plus an opaque interruption cursor, so each encode()
|
|
530
578
|
* touches only what changed since the previous flush.
|
|
531
579
|
*/
|
|
532
|
-
export function createTurnJournalEncoder({ turnToken } = {}) {
|
|
580
|
+
export function createTurnJournalEncoder({ turnToken, sessionId = null } = {}) {
|
|
533
581
|
let journaled = [];
|
|
534
582
|
let fullTranscript = false;
|
|
535
583
|
let cursor = null;
|
|
@@ -537,27 +585,65 @@ export function createTurnJournalEncoder({ turnToken } = {}) {
|
|
|
537
585
|
// Per-turn record sequence. It is assigned where records are produced, so
|
|
538
586
|
// the number line is exactly the enqueue order the write lane preserves.
|
|
539
587
|
let seq = 0;
|
|
588
|
+
// Set while the session has sensitive values (sensitive-values.mjs): the
|
|
589
|
+
// tracker's state as its deltas build it (`raw`) and the state the journal
|
|
590
|
+
// replays to (`written`). Interruption deltas are then journaled as the
|
|
591
|
+
// difference of the redacted text, so a value that streams in across
|
|
592
|
+
// flushes never lands in pieces. A newly marked value reseeds the encoder
|
|
593
|
+
// (turn-checkpoint.mjs), so the session's values are known whenever this is null.
|
|
594
|
+
let mirror = null;
|
|
540
595
|
const line = (record) => {
|
|
541
596
|
const stamped = { ...record, s: seq };
|
|
542
597
|
seq += 1;
|
|
543
598
|
return `${JSON.stringify(stamped)}\n`;
|
|
544
599
|
};
|
|
600
|
+
const stored = (message) => redactSensitiveMessage(sessionId, checkpointMessage(message));
|
|
601
|
+
const interruptionRecord = (delta) => {
|
|
602
|
+
if (!mirror) return delta;
|
|
603
|
+
applyInterruptionDelta(mirror.raw, delta);
|
|
604
|
+
const out = {};
|
|
605
|
+
for (const key of ['rs', 'ph', 'cc', 'od']) if (Object.hasOwn(delta, key)) out[key] = delta[key];
|
|
606
|
+
for (const [field, setKey, appendKey] of [
|
|
607
|
+
['text', 'ts', 'ta'],
|
|
608
|
+
['reasoning', 'qs', 'qa'],
|
|
609
|
+
]) {
|
|
610
|
+
const settled = redactSettledText(sessionId, mirror.raw[field]);
|
|
611
|
+
const written = mirror.written[field];
|
|
612
|
+
if (settled === written) continue;
|
|
613
|
+
if (settled.startsWith(written)) out[appendKey] = settled.slice(written.length);
|
|
614
|
+
else out[setKey] = settled;
|
|
615
|
+
}
|
|
616
|
+
if (Object.hasOwn(delta, 'tb')) out.tb = redactSensitiveContent(sessionId, mirror.raw.tomb);
|
|
617
|
+
if (delta.cs) out.cs = storedCallEntries(sessionId, delta.cs);
|
|
618
|
+
if (delta.os) out.os = storedResultEntries(sessionId, delta.os);
|
|
619
|
+
applyInterruptionDelta(mirror.written, out);
|
|
620
|
+
return out;
|
|
621
|
+
};
|
|
545
622
|
return {
|
|
546
623
|
/** Seed from the turn's opening state; returns the header's messages
|
|
547
624
|
* and the journal's opening lines (head record, plus — defensively —
|
|
548
625
|
* the delta that makes the journal authoritative if the tracker already
|
|
549
|
-
* carried state at open time).
|
|
550
|
-
|
|
626
|
+
* carried state at open time). `snapshot` is the tracker snapshot the
|
|
627
|
+
* header stores; `epoch` names the journal a rewritten header starts. */
|
|
628
|
+
seed(turnOutgoing, currentUserContent, interruption, contextState = null, { snapshot = null, epoch = 0 } = {}) {
|
|
551
629
|
const source = Array.isArray(turnOutgoing) ? turnOutgoing : [];
|
|
552
630
|
const start = findTurnStart(source, currentUserContent);
|
|
553
631
|
fullTranscript = start < 0;
|
|
554
632
|
journaled = fullTranscript ? source.slice() : source.slice(start);
|
|
633
|
+
mirror = sensitiveValuesVersion(sessionId)
|
|
634
|
+
? {
|
|
635
|
+
raw: interruptionStateFromSnapshot(snapshot),
|
|
636
|
+
written: interruptionStateFromSnapshot(redactInterruptionSnapshot(sessionId, snapshot)),
|
|
637
|
+
}
|
|
638
|
+
: null;
|
|
555
639
|
const seeded = typeof interruption?.journalDelta === 'function' ? interruption.journalDelta(null) : null;
|
|
556
640
|
cursor = seeded ? seeded.cursor : null;
|
|
557
641
|
contextStateKey = contextState == null ? null : JSON.stringify(contextState);
|
|
558
642
|
seq = 0;
|
|
559
|
-
const openLines = [line({ t: 'h', turnToken, at: Date.now() })];
|
|
560
|
-
|
|
643
|
+
const openLines = [line({ t: 'h', turnToken, ...(epoch ? { e: epoch } : {}), at: Date.now() })];
|
|
644
|
+
const seededDelta = seeded?.changed ? interruptionRecord(seeded.delta) : null;
|
|
645
|
+
if (seededDelta && Object.keys(seededDelta).length)
|
|
646
|
+
openLines.push(line({ t: 'x', d: seededDelta, at: Date.now() }));
|
|
561
647
|
return {
|
|
562
648
|
turnMessages: journaled.map(checkpointMessage),
|
|
563
649
|
fullTranscript,
|
|
@@ -579,7 +665,7 @@ export function createTurnJournalEncoder({ turnToken } = {}) {
|
|
|
579
665
|
journaled = source.slice();
|
|
580
666
|
records.push({
|
|
581
667
|
t: 'full',
|
|
582
|
-
ms: journaled.map(
|
|
668
|
+
ms: journaled.map(stored),
|
|
583
669
|
});
|
|
584
670
|
} else {
|
|
585
671
|
const offset = fullTranscript ? 0 : start;
|
|
@@ -588,7 +674,7 @@ export function createTurnJournalEncoder({ turnToken } = {}) {
|
|
|
588
674
|
const raw = source[offset + index];
|
|
589
675
|
if (journaled[index] === raw) continue;
|
|
590
676
|
journaled[index] = raw;
|
|
591
|
-
records.push({ t: 'm', i: index, m:
|
|
677
|
+
records.push({ t: 'm', i: index, m: stored(raw) });
|
|
592
678
|
}
|
|
593
679
|
if (journaled.length > length) {
|
|
594
680
|
journaled.length = length;
|
|
@@ -598,7 +684,8 @@ export function createTurnJournalEncoder({ turnToken } = {}) {
|
|
|
598
684
|
if (typeof interruption?.journalDelta === 'function') {
|
|
599
685
|
const next = interruption.journalDelta(cursor);
|
|
600
686
|
cursor = next.cursor;
|
|
601
|
-
|
|
687
|
+
const delta = next.changed ? interruptionRecord(next.delta) : null;
|
|
688
|
+
if (delta && Object.keys(delta).length) records.push({ t: 'x', d: delta });
|
|
602
689
|
}
|
|
603
690
|
const nextContextStateKey = contextState == null ? null : JSON.stringify(contextState);
|
|
604
691
|
if (nextContextStateKey !== contextStateKey) {
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
} from './turn-checkpoint-journal.mjs';
|
|
20
20
|
import { captureTurnCheckpointContextState, restoreTurnCheckpointContextState } from './turn-checkpoint-context.mjs';
|
|
21
21
|
import { stripProviderReplayMessages } from './provider-replay.mjs';
|
|
22
|
+
import { sensitiveValuesVersion } from '../sensitive-values.mjs';
|
|
22
23
|
|
|
23
24
|
export { turnCheckpointPath, turnMessagesForCheckpoint };
|
|
24
25
|
export { captureTurnCheckpointContextState, restoreTurnCheckpointContextState };
|
|
@@ -67,9 +68,14 @@ export function projectTurnCheckpointMessages(session, checkpoint) {
|
|
|
67
68
|
// long tool-heavy turn no longer amplifies into the shared engine thread that
|
|
68
69
|
// every fanned-out agent session shares.
|
|
69
70
|
export function createTurnCheckpointRecorder({ sessionId, generation, turnToken, startedAt }) {
|
|
70
|
-
const encoder = createTurnJournalEncoder({ turnToken });
|
|
71
|
+
const encoder = createTurnJournalEncoder({ turnToken, sessionId });
|
|
71
72
|
let opened = false;
|
|
72
73
|
let stopped = false;
|
|
74
|
+
// The sensitive-values version (sensitive-values.mjs) the header and
|
|
75
|
+
// journal were written under. A newly marked value rewrites both from the
|
|
76
|
+
// turn's current state with the value replaced, under a new journal epoch,
|
|
77
|
+
// so no recovery record keeps it.
|
|
78
|
+
let openedVersion = 0;
|
|
73
79
|
return {
|
|
74
80
|
get opened() {
|
|
75
81
|
return opened;
|
|
@@ -77,8 +83,14 @@ export function createTurnCheckpointRecorder({ sessionId, generation, turnToken,
|
|
|
77
83
|
/** True when this call wrote or queued durable state. */
|
|
78
84
|
record({ currentUserContent, turnOutgoing, interruption, contextState = null }) {
|
|
79
85
|
if (stopped || !sessionId || !turnToken) return false;
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
const version = sensitiveValuesVersion(sessionId);
|
|
87
|
+
if (!opened || version !== openedVersion) {
|
|
88
|
+
const snapshot =
|
|
89
|
+
typeof interruption?.snapshot === 'function' ? interruption.snapshot() : emptyInterruptionSnapshot();
|
|
90
|
+
const seed = encoder.seed(turnOutgoing, currentUserContent, interruption, contextState, {
|
|
91
|
+
snapshot,
|
|
92
|
+
epoch: version,
|
|
93
|
+
});
|
|
82
94
|
writeCheckpointHeader({
|
|
83
95
|
sessionId,
|
|
84
96
|
generation,
|
|
@@ -87,10 +99,11 @@ export function createTurnCheckpointRecorder({ sessionId, generation, turnToken,
|
|
|
87
99
|
currentUserContent,
|
|
88
100
|
turnMessages: seed.turnMessages,
|
|
89
101
|
...(seed.fullTranscript ? { fullTranscript: true } : {}),
|
|
90
|
-
|
|
91
|
-
|
|
102
|
+
...(version ? { journalEpoch: version } : {}),
|
|
103
|
+
interruption: snapshot,
|
|
92
104
|
contextState: seed.contextState,
|
|
93
105
|
});
|
|
106
|
+
openedVersion = version;
|
|
94
107
|
// Opening the journal is part of the anchor: a leftover journal
|
|
95
108
|
// from an earlier turn of this session must never replay onto
|
|
96
109
|
// the new header. It lands synchronously when the lane is idle
|
|
@@ -30,7 +30,7 @@ import { traceAgentCompact, messagePrefixHash } from '../agent-trace.mjs';
|
|
|
30
30
|
import { invalidateProviderRequestToolsScope } from '../runtime-core/provider-request-tools.mjs';
|
|
31
31
|
import { bumpUsageMetricsEpoch } from './manager/usage-metrics.mjs';
|
|
32
32
|
import { resetReadStateAfterCompaction } from './read-dedup.mjs';
|
|
33
|
-
import {
|
|
33
|
+
import { prepareCompactionArchive, stampCompactionMessageIds } from './compaction-archive-capture.mjs';
|
|
34
34
|
import { writeStderrBestEffort } from '../../../shared/best-effort-stderr.mjs';
|
|
35
35
|
import { isAgentModeSession } from './agent-mode.mjs';
|
|
36
36
|
import { applyPendingWorkspaceReroot } from './manager/prompt-utils.mjs';
|
|
@@ -409,19 +409,31 @@ function adoptCompactedTranscript(ctx, run) {
|
|
|
409
409
|
const { messages, sessionRef, sessionId, opts } = state;
|
|
410
410
|
const replaced = messages.slice();
|
|
411
411
|
if (sessionRef) backfillFallbackSessionTitle(sessionRef, replaced);
|
|
412
|
+
// Display-only archive of the dropped conversation, made durable (pending
|
|
413
|
+
// sidecar) BEFORE the shortened transcript is adopted and can be saved; a
|
|
414
|
+
// sidecar that cannot be written keeps the old transcript and fails this
|
|
415
|
+
// compaction. The publication runs off this synchronous adoption.
|
|
416
|
+
let prepared = null;
|
|
417
|
+
if (sessionRef) {
|
|
418
|
+
try {
|
|
419
|
+
prepared = prepareCompactionArchive({ session: sessionRef, sessionId, before: replaced, after: run.compacted });
|
|
420
|
+
} catch (archiveError) {
|
|
421
|
+
throwCompactFailure(ctx, run, archiveError);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
412
424
|
messages.length = 0;
|
|
413
425
|
messages.push(...run.compacted);
|
|
414
|
-
|
|
415
|
-
// write run off this synchronous adoption.
|
|
416
|
-
const archived = sessionRef
|
|
417
|
-
? scheduleCompactionArchive({ session: sessionRef, sessionId, before: replaced, after: messages })
|
|
418
|
-
: null;
|
|
426
|
+
const archived = prepared ? { ...prepared, written: prepared.start() } : null;
|
|
419
427
|
ctx.droppedMessages = archived?.dropped ?? 0;
|
|
420
428
|
ctx.droppedIdentities = archived?.identities ?? null;
|
|
421
429
|
acknowledgeGoalReminder(sessionRef, run);
|
|
422
430
|
// The compacted transcript breaks the cache anyway: a staged working-folder
|
|
423
431
|
// change re-roots the system prompt now and needs no notice any more.
|
|
424
432
|
if (sessionRef) applyPendingWorkspaceReroot(sessionRef, messages);
|
|
433
|
+
// The system prompt is rebuilt from current sources outside a running turn
|
|
434
|
+
// (session-runtime agent-profile-fold.mjs): the next cold point folds it in
|
|
435
|
+
// instead of adding a break to the turn that is already warm again.
|
|
436
|
+
if (sessionRef) sessionRef.promptFoldPending = true;
|
|
425
437
|
resetReadStateAfterCompaction(sessionId);
|
|
426
438
|
// Cross-turn receipts reference tool results that compaction just removed
|
|
427
439
|
// from context; a stub for them would point at nothing. Clear in place so
|
|
@@ -444,8 +456,7 @@ function adoptCompactedTranscript(ctx, run) {
|
|
|
444
456
|
ctx.providerStateCleared = true;
|
|
445
457
|
// Compaction starts a new loop epoch: the iteration counter restarts at 0
|
|
446
458
|
// so iteration indices (traces, usage metrics, cross-turn dedup windows)
|
|
447
|
-
// count from the compacted transcript.
|
|
448
|
-
// loop has no iteration cap.
|
|
459
|
+
// count from the compacted transcript.
|
|
449
460
|
ctx.iterations = 0;
|
|
450
461
|
// New loop epoch so persistIterationMetrics idempotency keys do not
|
|
451
462
|
// collide when iteration indices restart at 1 (incl. iter 1 → iter 1).
|