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
|
@@ -12,10 +12,7 @@ import {
|
|
|
12
12
|
loadSkillResource,
|
|
13
13
|
buildSkillToolEnvelope,
|
|
14
14
|
filterSkillsExcludingDisabled,
|
|
15
|
-
|
|
16
|
-
skillMissingFeature,
|
|
17
|
-
skillOutsideScope,
|
|
18
|
-
skillOutsideScopeError,
|
|
15
|
+
skillLoadRefusal,
|
|
19
16
|
} from '../../context/collect.mjs';
|
|
20
17
|
|
|
21
18
|
// Eager-dispatch: tools with readOnlyHint:true in their declaration are safe
|
|
@@ -95,12 +92,8 @@ export function buildSkillsListResponse(cwd) {
|
|
|
95
92
|
export function viewSkill(cwd, name, session = null) {
|
|
96
93
|
const skillName = String(name || '').trim();
|
|
97
94
|
if (!skillName) return 'Error: skill name is required';
|
|
98
|
-
const
|
|
99
|
-
if (
|
|
100
|
-
return `Error: skill "${skillName}" needs the ${missingFeature} built-in feature, which is not installed or is switched off in Extensions → Plugin → Built-in`;
|
|
101
|
-
}
|
|
102
|
-
if (isSkillDisabled(skillName)) return `Error: skill "${skillName}" is disabled`;
|
|
103
|
-
if (skillOutsideScope(skillName, cwd)) return skillOutsideScopeError(skillName);
|
|
95
|
+
const refusal = skillLoadRefusal(skillName, cwd);
|
|
96
|
+
if (refusal) return refusal;
|
|
104
97
|
const res = loadSkillResource(skillName, cwd);
|
|
105
98
|
if (!res) return `Error: skill "${skillName}" not found`;
|
|
106
99
|
// Return the general tool envelope: the model-visible tool_result is the
|
|
@@ -9,6 +9,7 @@ import { processToolBatch } from '../tool-batch.mjs';
|
|
|
9
9
|
import { CROSS_TURN_CAP, REPEAT_FAIL_LIMIT } from './loop-state.mjs';
|
|
10
10
|
import { markStepEffort } from './step-auto-effort.mjs';
|
|
11
11
|
import { resolveExecutionToolCalls } from './tool-call-resolution.mjs';
|
|
12
|
+
import { rememberSensitiveValues } from '../sensitive-values.mjs';
|
|
12
13
|
import { callsAllowed, settleTurnLimits, turnLimitsOf } from './turn-limits.mjs';
|
|
13
14
|
|
|
14
15
|
function isSleepLikeToolCall(call) {
|
|
@@ -41,13 +42,19 @@ export async function runToolPhase(state, round, sent, onToolCall) {
|
|
|
41
42
|
// derive the multi-tool adoption ratio without scanning message bodies.
|
|
42
43
|
// Audit records what runs: a bridged call_tool is recorded as its target.
|
|
43
44
|
// The wire calls stay the transcript identity (assistant turn below).
|
|
44
|
-
const
|
|
45
|
+
const executionCalls = resolveExecutionToolCalls(calls, sessionRef);
|
|
46
|
+
const toolBatchId = recordToolBatch(sessionId, executionCalls, state.iterations);
|
|
47
|
+
// A sensitive fill (a verification code): every stored copy of the
|
|
48
|
+
// transcript keeps a marker instead of the value; the call runs as is.
|
|
49
|
+
rememberSensitiveValues(sessionId, executionCalls);
|
|
45
50
|
await Promise.resolve(onToolCall?.(state.iterations, calls));
|
|
46
51
|
const assistantTurnMsg = buildToolCallAssistantMessage(response, { calls, opts });
|
|
47
52
|
commitAssistantMessage(messages, assistantTurnMsg, opts);
|
|
48
53
|
try {
|
|
49
54
|
opts.onToolPhaseStarted?.();
|
|
50
|
-
} catch {
|
|
55
|
+
} catch {
|
|
56
|
+
// the tool-phase-started observer is advisory
|
|
57
|
+
}
|
|
51
58
|
const toolsT0 = Date.now();
|
|
52
59
|
const resultsFrom = messages.length;
|
|
53
60
|
({ dedupStubTotal: state.dedupStubTotal, editCount: state.editCount } = await processToolBatch({
|
|
@@ -90,7 +97,9 @@ export async function runToolPhase(state, round, sent, onToolCall) {
|
|
|
90
97
|
calls: calls.length,
|
|
91
98
|
elapsedMs: toolsEndedAt - toolsT0,
|
|
92
99
|
});
|
|
93
|
-
} catch {
|
|
100
|
+
} catch {
|
|
101
|
+
// the tool-phase-completed observer is advisory
|
|
102
|
+
}
|
|
94
103
|
traceLoopPhaseTiming({
|
|
95
104
|
iteration: round.nextIteration,
|
|
96
105
|
preSendMs: sent.preSendMs,
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
drainPendingMessages,
|
|
10
10
|
releasePendingMessages,
|
|
11
11
|
} from './pending-messages.mjs';
|
|
12
|
+
import { promptOriginOf } from '../../../../shared/prompt-origin.mjs';
|
|
12
13
|
|
|
13
14
|
const SYNTHETIC_PROMPT_SOURCES = ['goal-continuation', 'goal-closeout'];
|
|
14
15
|
|
|
@@ -35,6 +36,7 @@ const tailTurnFor = (group) => ({
|
|
|
35
36
|
content: group.content,
|
|
36
37
|
entries: group.entries,
|
|
37
38
|
...(group.hop ? { hop: group.hop } : {}),
|
|
39
|
+
...(group.origin ? { origin: group.origin } : {}),
|
|
38
40
|
...(group.mode === PENDING_MODE_TASK_NOTIFICATION
|
|
39
41
|
? promptSourceFields(PENDING_MODE_TASK_NOTIFICATION, group.execution)
|
|
40
42
|
: {}),
|
|
@@ -49,13 +51,19 @@ const queuedTurnInput = (tailTurn) => ({
|
|
|
49
51
|
pendingEntries: tailTurn.entries,
|
|
50
52
|
...(tailTurn.hop ? { hop: tailTurn.hop } : {}),
|
|
51
53
|
promptSource: promptSourceFields(tailTurn.source, tailTurn.execution),
|
|
54
|
+
...(tailTurn.origin ? { promptOrigin: tailTurn.origin } : {}),
|
|
52
55
|
});
|
|
53
56
|
|
|
54
|
-
|
|
57
|
+
// The caller's provenance of its initial prompt, apart from its presentation
|
|
58
|
+
// source: an inbound channel message or an agent report (shared/prompt-origin.mjs).
|
|
59
|
+
const initialPromptOriginFor = (promptOrigin) => promptOriginOf(promptOrigin);
|
|
60
|
+
|
|
61
|
+
export function createAskPromptQueue({ sessionId, promptSource, promptOrigin }) {
|
|
55
62
|
// Local FIFO of follow-up prompts drained from the pending-message queue
|
|
56
63
|
// after each turn — keeps queued `agent type=send` messages in order.
|
|
57
64
|
const tail = [];
|
|
58
65
|
let initialPromptSource = initialPromptSourceFor(promptSource);
|
|
66
|
+
let initialPromptOrigin = initialPromptOriginFor(promptOrigin);
|
|
59
67
|
// Queue entries of the input nextTurn handed out that no turn owns yet.
|
|
60
68
|
// Once a turn starts, its failure path acks or releases them instead.
|
|
61
69
|
let unstartedEntries = [];
|
|
@@ -67,13 +75,15 @@ export function createAskPromptQueue({ sessionId, promptSource }) {
|
|
|
67
75
|
* and provenance — or null when nothing model-visible is left to run. */
|
|
68
76
|
const nextTurn = (original) => {
|
|
69
77
|
const source = initialPromptSource;
|
|
78
|
+
const origin = initialPromptOrigin;
|
|
70
79
|
initialPromptSource = null;
|
|
80
|
+
initialPromptOrigin = null;
|
|
71
81
|
let input;
|
|
72
82
|
if (tail.length > 0) {
|
|
73
83
|
// After the first turn, the next prompt comes from the drained queue.
|
|
74
84
|
input = queuedTurnInput(tail.shift());
|
|
75
85
|
} else if (hasModelVisiblePromptContent(original.prompt)) {
|
|
76
|
-
input = { ...original, pendingEntries: [], promptSource: source };
|
|
86
|
+
input = { ...original, pendingEntries: [], promptSource: source, ...(origin ? { promptOrigin: origin } : {}) };
|
|
77
87
|
} else {
|
|
78
88
|
// Idle resume: TUI kicks an empty ask() after execution completions
|
|
79
89
|
// mirror model-visible bodies into session pending. Drain that queue
|
|
@@ -19,6 +19,7 @@ import { armTurnDurability, claimTurnRuntime } from './ask-turn-open.mjs';
|
|
|
19
19
|
import { prepareAskTurn, runAskAgentLoop } from './ask-turn-execute.mjs';
|
|
20
20
|
import { commitAskTurn, publishAskTurn } from './ask-turn-settle.mjs';
|
|
21
21
|
import { finalizeAskTurnFailure } from './ask-turn-failure.mjs';
|
|
22
|
+
import { cacheWarmTurnKind, endCacheWarmTurn, failedTurnProvenance, noteCacheWarmTurn } from '../cache-warm.mjs';
|
|
22
23
|
|
|
23
24
|
export { _api_call_with_interrupt } from './ask-call-interrupt.mjs';
|
|
24
25
|
export {
|
|
@@ -168,7 +169,14 @@ export async function askSession(sessionId, prompt, context, onToolCall, cwdOver
|
|
|
168
169
|
// return value (the queued tail turns supersede the original prompt's
|
|
169
170
|
// result, mirroring how a live chat returns the latest turn).
|
|
170
171
|
let result;
|
|
171
|
-
const queue = createAskPromptQueue({
|
|
172
|
+
const queue = createAskPromptQueue({
|
|
173
|
+
sessionId,
|
|
174
|
+
promptSource: askOpts.promptSource,
|
|
175
|
+
promptOrigin: askOpts.promptOrigin,
|
|
176
|
+
});
|
|
177
|
+
// The turn the prompt-cache warmer is told about last; it forgets it when
|
|
178
|
+
// the turn ends (endCacheWarmTurn), whatever way the ask unwinds.
|
|
179
|
+
let warmTurn = null;
|
|
172
180
|
// Hoisted so the outer finally (which runs once after the whole turn loop)
|
|
173
181
|
// can compare against the last turn's generation.
|
|
174
182
|
let askGeneration = 0;
|
|
@@ -213,6 +221,12 @@ export async function askSession(sessionId, prompt, context, onToolCall, cwdOver
|
|
|
213
221
|
recoverCheckpoint: !crashRecoveryChecked,
|
|
214
222
|
emitStart: !sessionStartEmitted,
|
|
215
223
|
});
|
|
224
|
+
// The prompt-cache warmer learns idle gaps from real turns only; a
|
|
225
|
+
// retry is classified by the failed turn's stored provenance.
|
|
226
|
+
// The rebuilt retry message keeps that provenance (ask-turn-execute.mjs).
|
|
227
|
+
const retryProvenance = failedTurnProvenance(claimed.preSession?.messages, input);
|
|
228
|
+
if (retryProvenance) input.retryProvenance = retryProvenance;
|
|
229
|
+
warmTurn = noteCacheWarmTurn(sessionId, cacheWarmTurnKind(input, claimed.preSession?.messages));
|
|
216
230
|
crashRecoveryChecked = true;
|
|
217
231
|
sessionStartEmitted = true;
|
|
218
232
|
askGeneration = claimed.askGeneration;
|
|
@@ -234,6 +248,7 @@ export async function askSession(sessionId, prompt, context, onToolCall, cwdOver
|
|
|
234
248
|
askStartedAt,
|
|
235
249
|
});
|
|
236
250
|
result = turn.result;
|
|
251
|
+
endCacheWarmTurn(sessionId, warmTurn);
|
|
237
252
|
// Turn complete. Drain the pending-message queue: any `agent type=send`
|
|
238
253
|
// that arrived while this turn was in flight runs next, in order, as a
|
|
239
254
|
// follow-up user turn. The mutex is still held, so a send racing this
|
|
@@ -264,6 +279,9 @@ export async function askSession(sessionId, prompt, context, onToolCall, cwdOver
|
|
|
264
279
|
return result;
|
|
265
280
|
}
|
|
266
281
|
} finally {
|
|
282
|
+
// A failed/cancelled turn ends here too: its warmer turn entry goes (a
|
|
283
|
+
// later ask's own turn is never removed by this one).
|
|
284
|
+
endCacheWarmTurn(sessionId, warmTurn);
|
|
267
285
|
// A failed/cancelled turn ends the ask: the follow-up turns drained
|
|
268
286
|
// behind it never ran, so their entries go back to the pending queue.
|
|
269
287
|
queue.releaseUnstarted();
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { getProvider } from '../../providers/registry.mjs';
|
|
8
8
|
import { pinSessionWireRoute } from '../../providers/wire-route.mjs';
|
|
9
9
|
import { notifySkillsApplied, prepareExplicitSkills, recordAppliedSkills } from '../explicit-skills.mjs';
|
|
10
|
+
import { appendSkillUpdateNotices } from '../skill-update-notice.mjs';
|
|
10
11
|
import { prepareTurnEffortConfiguration } from '../../providers/effort-configuration.mjs';
|
|
11
12
|
import { resolveTurnAutoEffort, turnStepAutoEffort } from './ask-turn-auto-effort.mjs';
|
|
12
13
|
import { saveSessionAsync } from '../store.mjs';
|
|
@@ -22,6 +23,128 @@ import { _api_call_with_interrupt } from './ask-call-interrupt.mjs';
|
|
|
22
23
|
import { backfillFallbackSessionTitle } from './session-fallback-title.mjs';
|
|
23
24
|
import { stampTurnHop } from '../../../../shared/bot-hops.mjs';
|
|
24
25
|
|
|
26
|
+
function turnPromptSourceFor(input) {
|
|
27
|
+
if (!(input.promptOrigin || input.retryProvenance)) return input.promptSource;
|
|
28
|
+
return {
|
|
29
|
+
...(input.promptSource || {}),
|
|
30
|
+
...(input.promptOrigin ? { origin: input.promptOrigin } : {}),
|
|
31
|
+
...(input.retryProvenance ? { provenance: input.retryProvenance } : {}),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// A retried failed turn resubmits its retained user message over the history
|
|
36
|
+
// before it: the message keeps its input and records the failed completion.
|
|
37
|
+
function retainedUserTurn(session, retained, transcriptMeta, currentAgents) {
|
|
38
|
+
const historyMessages = filterModelVisibleSessionMessages(session.messages.slice(0, retained.index));
|
|
39
|
+
const { completion, ...previousTranscript } = retained.message.meta.transcript;
|
|
40
|
+
// The retained message keeps its input; agents enabled or switched
|
|
41
|
+
// off since it was built ride its runtime context.
|
|
42
|
+
const userTurnMessage = withAgentListingNotice(
|
|
43
|
+
session,
|
|
44
|
+
retained.index,
|
|
45
|
+
{
|
|
46
|
+
...retained.message,
|
|
47
|
+
meta: {
|
|
48
|
+
...retained.message.meta,
|
|
49
|
+
transcript: {
|
|
50
|
+
...previousTranscript,
|
|
51
|
+
...transcriptMeta,
|
|
52
|
+
messageId: previousTranscript.messageId,
|
|
53
|
+
previousCompletions: [
|
|
54
|
+
...(previousTranscript.previousCompletions || []),
|
|
55
|
+
{ ...completion, at: completion.at ?? previousTranscript.at },
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
currentAgents
|
|
61
|
+
);
|
|
62
|
+
return { historyMessages, userTurnMessage, outgoing: [...historyMessages, userTurnMessage] };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// The turn's user message: the retained one of a retried failed turn, or a
|
|
66
|
+
// newly built one (a promise).
|
|
67
|
+
function pendingUserTurn({ session, input, retained, turnSignal, transcriptMeta, currentAgents }) {
|
|
68
|
+
if (retained) return retainedUserTurn(session, retained, transcriptMeta, currentAgents);
|
|
69
|
+
return buildUserTurn({
|
|
70
|
+
session,
|
|
71
|
+
prompt: input.prompt,
|
|
72
|
+
context: input.context,
|
|
73
|
+
explicitPrefetch: input.explicitPrefetch,
|
|
74
|
+
turnSignal,
|
|
75
|
+
transcriptMeta,
|
|
76
|
+
// The stored message keeps an inbound channel's provenance and, for
|
|
77
|
+
// a rebuilt retry (the resubmitted prompt or a continuation prompt),
|
|
78
|
+
// the failed turn's, which a later retry reads back
|
|
79
|
+
// (cache-warm.mjs failedTurnProvenance).
|
|
80
|
+
turnPromptSource: turnPromptSourceFor(input),
|
|
81
|
+
effortConfiguration: null,
|
|
82
|
+
currentAgents,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Stamp the turn's effort on the user message (same meta order as when it
|
|
87
|
+
// was built with it: before the runtime-context provenance).
|
|
88
|
+
function stampTurnEffort(userTurnMessage, effortConfiguration) {
|
|
89
|
+
const { runtimeUserContext, ...meta } = userTurnMessage.meta || {};
|
|
90
|
+
userTurnMessage.meta = {
|
|
91
|
+
...meta,
|
|
92
|
+
effortConfiguration,
|
|
93
|
+
...(runtimeUserContext ? { runtimeUserContext } : {}),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Expose the in-flight working transcript so contextStatus() can
|
|
98
|
+
// estimate the LIVE context footprint mid-turn. agentLoop mutates
|
|
99
|
+
// `outgoing` in place (user turn + tool calls/results + compaction),
|
|
100
|
+
// so the statusline context gauge climbs as the turn accumulates
|
|
101
|
+
// tool output instead of freezing at the pre-turn snapshot. Cleared
|
|
102
|
+
// on turn commit and in the ask finally.
|
|
103
|
+
//
|
|
104
|
+
// Also commit the user turn to the live session BEFORE the provider
|
|
105
|
+
// call. Previously the prompt only reached session.messages after
|
|
106
|
+
// agentLoop returned. If a worker/lead session was closed or aborted
|
|
107
|
+
// before first response, closeSession() wrote a tombstone from the
|
|
108
|
+
// still-system-only session and the handoff brief vanished forever
|
|
109
|
+
// (agent row showed messages=2). Pre-committing makes cancellation,
|
|
110
|
+
// close, and post-mortem files retain the exact user task; completion
|
|
111
|
+
// overwrites this provisional transcript with the fully mutated
|
|
112
|
+
// outgoing history and appends the assistant result, so no duplicate
|
|
113
|
+
// user turn is introduced.
|
|
114
|
+
function precommitUserTurn(session, outgoing, historyMessages, input) {
|
|
115
|
+
session.messages = filterModelVisibleSessionMessages(outgoing);
|
|
116
|
+
session.liveTurnMessages = outgoing;
|
|
117
|
+
// Name a titleless session from its first human prompt before the first
|
|
118
|
+
// save, so the title outlives any later compaction of the transcript. The
|
|
119
|
+
// earliest human turn already in the history wins; this turn's prompt is the
|
|
120
|
+
// fallback (runtime-injected turns carrying a promptSource never name it).
|
|
121
|
+
backfillFallbackSessionTitle(session, [
|
|
122
|
+
...historyMessages,
|
|
123
|
+
...(input.promptSource ? [] : [{ role: 'user', content: input.prompt }]),
|
|
124
|
+
]);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Mark the turn active and persist the pre-committed session before the
|
|
128
|
+
// provider runs.
|
|
129
|
+
function persistTurnPreflight(session, { turnToken, startedAt, checkpoint, askGeneration }) {
|
|
130
|
+
session.activeTurnCheckpoint = {
|
|
131
|
+
version: 1,
|
|
132
|
+
turnToken,
|
|
133
|
+
startedAt,
|
|
134
|
+
};
|
|
135
|
+
// The sidecar lands synchronously before provider execution. Even
|
|
136
|
+
// if the async canonical-session preflight save has not reached its
|
|
137
|
+
// worker when the process is killed, recovery still has the prompt.
|
|
138
|
+
checkpoint.schedule(true);
|
|
139
|
+
saveSessionAsync(session, { expectedGeneration: askGeneration }).catch((err) => {
|
|
140
|
+
try {
|
|
141
|
+
process.stderr.write(`[session] preflight user-turn save failed: ${err?.message || err}\n`);
|
|
142
|
+
} catch {
|
|
143
|
+
// stderr may be closed; the save failure is only reported
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
25
148
|
/** Resolves the provider, builds the user turn and pre-commits it; returns
|
|
26
149
|
* what the loop and the commit need from this preparation. */
|
|
27
150
|
export async function prepareAskTurn({ sessionId, opened, input, cwdOverride, transcriptMeta, currentAgents }) {
|
|
@@ -68,45 +191,7 @@ export async function prepareAskTurn({ sessionId, opened, input, cwdOverride, tr
|
|
|
68
191
|
});
|
|
69
192
|
const [autoEffort, userTurn] = await Promise.all([
|
|
70
193
|
autoEffortPending,
|
|
71
|
-
retained
|
|
72
|
-
? (() => {
|
|
73
|
-
const historyMessages = filterModelVisibleSessionMessages(session.messages.slice(0, retained.index));
|
|
74
|
-
const { completion, ...previousTranscript } = retained.message.meta.transcript;
|
|
75
|
-
// The retained message keeps its input; agents enabled or switched
|
|
76
|
-
// off since it was built ride its runtime context.
|
|
77
|
-
const userTurnMessage = withAgentListingNotice(
|
|
78
|
-
session,
|
|
79
|
-
retained.index,
|
|
80
|
-
{
|
|
81
|
-
...retained.message,
|
|
82
|
-
meta: {
|
|
83
|
-
...retained.message.meta,
|
|
84
|
-
transcript: {
|
|
85
|
-
...previousTranscript,
|
|
86
|
-
...transcriptMeta,
|
|
87
|
-
messageId: previousTranscript.messageId,
|
|
88
|
-
previousCompletions: [
|
|
89
|
-
...(previousTranscript.previousCompletions || []),
|
|
90
|
-
{ ...completion, at: completion.at ?? previousTranscript.at },
|
|
91
|
-
],
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
currentAgents
|
|
96
|
-
);
|
|
97
|
-
return { historyMessages, userTurnMessage, outgoing: [...historyMessages, userTurnMessage] };
|
|
98
|
-
})()
|
|
99
|
-
: buildUserTurn({
|
|
100
|
-
session,
|
|
101
|
-
prompt: input.prompt,
|
|
102
|
-
context: input.context,
|
|
103
|
-
explicitPrefetch: input.explicitPrefetch,
|
|
104
|
-
turnSignal,
|
|
105
|
-
transcriptMeta,
|
|
106
|
-
turnPromptSource: input.promptSource,
|
|
107
|
-
effortConfiguration: null,
|
|
108
|
-
currentAgents,
|
|
109
|
-
}),
|
|
194
|
+
pendingUserTurn({ session, input, retained, turnSignal, transcriptMeta, currentAgents }),
|
|
110
195
|
wireRoutePending,
|
|
111
196
|
]);
|
|
112
197
|
const turnEffort = autoEffort?.applied ? autoEffort.effort : session.effort || null;
|
|
@@ -118,60 +203,12 @@ export async function prepareAskTurn({ sessionId, opened, input, cwdOverride, tr
|
|
|
118
203
|
// Auto effort also judges every tool-result step of the turn when the
|
|
119
204
|
// installed judge was trained on steps (session/loop/step-auto-effort.mjs).
|
|
120
205
|
const stepAutoEffort = turnStepAutoEffort(autoEffort, effortConfiguration);
|
|
121
|
-
if (effortConfiguration)
|
|
122
|
-
// Stamp the turn's effort on the user message (same meta order as when it
|
|
123
|
-
// was built with it: before the runtime-context provenance).
|
|
124
|
-
const { runtimeUserContext, ...meta } = userTurn.userTurnMessage.meta || {};
|
|
125
|
-
userTurn.userTurnMessage.meta = {
|
|
126
|
-
...meta,
|
|
127
|
-
effortConfiguration,
|
|
128
|
-
...(runtimeUserContext ? { runtimeUserContext } : {}),
|
|
129
|
-
};
|
|
130
|
-
}
|
|
206
|
+
if (effortConfiguration) stampTurnEffort(userTurn.userTurnMessage, effortConfiguration);
|
|
131
207
|
const { historyMessages, outgoing } = userTurn;
|
|
132
208
|
turn.userTurnContent = userTurn.userTurnMessage.content;
|
|
133
209
|
turn.outgoing = outgoing;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
// `outgoing` in place (user turn + tool calls/results + compaction),
|
|
137
|
-
// so the statusline context gauge climbs as the turn accumulates
|
|
138
|
-
// tool output instead of freezing at the pre-turn snapshot. Cleared
|
|
139
|
-
// on turn commit and in the ask finally.
|
|
140
|
-
//
|
|
141
|
-
// Also commit the user turn to the live session BEFORE the provider
|
|
142
|
-
// call. Previously the prompt only reached session.messages after
|
|
143
|
-
// agentLoop returned. If a worker/lead session was closed or aborted
|
|
144
|
-
// before first response, closeSession() wrote a tombstone from the
|
|
145
|
-
// still-system-only session and the handoff brief vanished forever
|
|
146
|
-
// (agent row showed messages=2). Pre-committing makes cancellation,
|
|
147
|
-
// close, and post-mortem files retain the exact user task; completion
|
|
148
|
-
// overwrites this provisional transcript with the fully mutated
|
|
149
|
-
// outgoing history and appends the assistant result, so no duplicate
|
|
150
|
-
// user turn is introduced.
|
|
151
|
-
session.messages = filterModelVisibleSessionMessages(outgoing);
|
|
152
|
-
session.liveTurnMessages = outgoing;
|
|
153
|
-
// Name a titleless session from its first human prompt before the first
|
|
154
|
-
// save, so the title outlives any later compaction of the transcript. The
|
|
155
|
-
// earliest human turn already in the history wins; this turn's prompt is the
|
|
156
|
-
// fallback (runtime-injected turns carrying a promptSource never name it).
|
|
157
|
-
backfillFallbackSessionTitle(session, [
|
|
158
|
-
...historyMessages,
|
|
159
|
-
...(input.promptSource ? [] : [{ role: 'user', content: input.prompt }]),
|
|
160
|
-
]);
|
|
161
|
-
session.activeTurnCheckpoint = {
|
|
162
|
-
version: 1,
|
|
163
|
-
turnToken,
|
|
164
|
-
startedAt,
|
|
165
|
-
};
|
|
166
|
-
// The sidecar lands synchronously before provider execution. Even
|
|
167
|
-
// if the async canonical-session preflight save has not reached its
|
|
168
|
-
// worker when the process is killed, recovery still has the prompt.
|
|
169
|
-
checkpoint.schedule(true);
|
|
170
|
-
saveSessionAsync(session, { expectedGeneration: askGeneration }).catch((err) => {
|
|
171
|
-
try {
|
|
172
|
-
process.stderr.write(`[session] preflight user-turn save failed: ${err?.message || err}\n`);
|
|
173
|
-
} catch {}
|
|
174
|
-
});
|
|
210
|
+
precommitUserTurn(session, outgoing, historyMessages, input);
|
|
211
|
+
persistTurnPreflight(session, { turnToken, startedAt, checkpoint, askGeneration });
|
|
175
212
|
traceTurnContext({
|
|
176
213
|
sessionId,
|
|
177
214
|
session,
|
|
@@ -237,6 +274,12 @@ export async function runAskAgentLoop({
|
|
|
237
274
|
checkpoint.schedule(true);
|
|
238
275
|
notifySkillsApplied(askOpts?.onSkillsApplied, applied, userMessage);
|
|
239
276
|
}
|
|
277
|
+
// Every turn (any session, any prompt source): a loaded skill that changed
|
|
278
|
+
// since it was loaded is announced once, after the history.
|
|
279
|
+
if (appendSkillUpdateNotices(outgoing, effectiveCwd).length) {
|
|
280
|
+
session.messages = filterModelVisibleSessionMessages(outgoing);
|
|
281
|
+
checkpoint.schedule(true);
|
|
282
|
+
}
|
|
240
283
|
return await _api_call_with_interrupt(sessionId, (signal) =>
|
|
241
284
|
agentLoop(
|
|
242
285
|
provider,
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
// canonicalizes the transcript when the turn is interrupted.
|
|
5
5
|
import { captureTurnCheckpointContextState, createTurnCheckpointRecorder } from './turn-checkpoint.mjs';
|
|
6
6
|
import { finalizeTurnInterruptionSnapshot } from './turn-interruption.mjs';
|
|
7
|
+
import { onSensitiveValuesMarked } from '../sensitive-values.mjs';
|
|
8
|
+
import { saveSessionAsync } from '../store.mjs';
|
|
9
|
+
import { ingestSessionTurn } from '../../../../session-search/session-search-ingest.mjs';
|
|
7
10
|
|
|
8
11
|
// Coalescing window for streaming-delta flushes. Each flush journals only the
|
|
9
12
|
// delta since the previous one, so the window just bounds syscalls.
|
|
@@ -50,11 +53,36 @@ export function createTurnCheckpointScheduler({ sessionId, generation, turnToken
|
|
|
50
53
|
warned = true;
|
|
51
54
|
try {
|
|
52
55
|
process.stderr.write(`[turn-checkpoint] write failed session=${sessionId}: ${error?.message || error}\n`);
|
|
53
|
-
} catch {
|
|
56
|
+
} catch {
|
|
57
|
+
// stderr may be closed; the checkpoint failure is only reported
|
|
58
|
+
}
|
|
54
59
|
}
|
|
55
60
|
return false;
|
|
56
61
|
}
|
|
57
62
|
};
|
|
63
|
+
const flushNow = () => {
|
|
64
|
+
if (timer) clearTimeout(timer);
|
|
65
|
+
timer = null;
|
|
66
|
+
flush();
|
|
67
|
+
};
|
|
68
|
+
// A value marked sensitive while the turn runs (sensitive-values.mjs) —
|
|
69
|
+
// before the call that carries it executes: every stored copy that may hold
|
|
70
|
+
// it is written again with it replaced. The checkpoint is rewritten in full
|
|
71
|
+
// now (the recorder sees the new version); the session file gets a full
|
|
72
|
+
// save (store/save-delta.mjs resyncs on the version) and the search rows a
|
|
73
|
+
// transactional replacement (session-search-ingest.mjs).
|
|
74
|
+
const stopMarks = onSensitiveValuesMarked(sessionId, () => {
|
|
75
|
+
if (stopped) return;
|
|
76
|
+
if (turn.outgoing) flushNow();
|
|
77
|
+
saveSessionAsync(turn.session, { expectedGeneration: generation }).catch((err) => {
|
|
78
|
+
try {
|
|
79
|
+
process.stderr.write(`[session] sensitive-value save failed session=${sessionId}: ${err?.message || err}\n`);
|
|
80
|
+
} catch {
|
|
81
|
+
// stderr may be closed; the save failure is only reported
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
ingestSessionTurn(turn.session);
|
|
85
|
+
});
|
|
58
86
|
return {
|
|
59
87
|
refreshContextState() {
|
|
60
88
|
contextState = captureTurnCheckpointContextState(turn.session, turn.outgoing, turn.userTurnContent);
|
|
@@ -62,9 +90,7 @@ export function createTurnCheckpointScheduler({ sessionId, generation, turnToken
|
|
|
62
90
|
schedule(immediate = false) {
|
|
63
91
|
if (stopped || !turn.outgoing) return;
|
|
64
92
|
if (immediate || Date.now() - lastAt >= TURN_CHECKPOINT_THROTTLE_MS) {
|
|
65
|
-
|
|
66
|
-
timer = null;
|
|
67
|
-
flush();
|
|
93
|
+
flushNow();
|
|
68
94
|
return;
|
|
69
95
|
}
|
|
70
96
|
if (timer) return;
|
|
@@ -77,6 +103,7 @@ export function createTurnCheckpointScheduler({ sessionId, generation, turnToken
|
|
|
77
103
|
},
|
|
78
104
|
stop() {
|
|
79
105
|
stopped = true;
|
|
106
|
+
stopMarks();
|
|
80
107
|
if (timer) clearTimeout(timer);
|
|
81
108
|
timer = null;
|
|
82
109
|
recorder.stop();
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from '../context-utils.mjs';
|
|
16
16
|
import { previewFreshContextCompaction, runFreshContextCompact } from '../loop/fresh-context.mjs';
|
|
17
17
|
import { positiveInt } from '../../../../shared/numbers.mjs';
|
|
18
|
+
import { withLiveCompactionConfig } from '../../runtime-core/compaction-config-keys.mjs';
|
|
18
19
|
import { writeStderrBestEffort } from '../../../../shared/best-effort-stderr.mjs';
|
|
19
20
|
import { traceAgentCompact, messagePrefixHash } from '../../agent-trace.mjs';
|
|
20
21
|
import { uncachedInputTokensForProvider } from './usage-metrics.mjs';
|
|
@@ -36,7 +37,7 @@ import {
|
|
|
36
37
|
shouldCompactForRequestMedia,
|
|
37
38
|
} from '../loop/compact-policy.mjs';
|
|
38
39
|
import { snapshotProviderRequestTools } from '../../runtime-core/tool-catalog.mjs';
|
|
39
|
-
import {
|
|
40
|
+
import { prepareCompactionArchive, stampCompactionMessageIds } from '../compaction-archive-capture.mjs';
|
|
40
41
|
|
|
41
42
|
// 'compacting' is a transient in-flight stage written just before Compact
|
|
42
43
|
// runs. If the process crashes or only partially
|
|
@@ -263,11 +264,12 @@ function compactionResult(plan, outcome, after, tail) {
|
|
|
263
264
|
};
|
|
264
265
|
}
|
|
265
266
|
|
|
267
|
+
// The commit writes only its own outcome telemetry; config-owned fields stay
|
|
268
|
+
// the live ones (withLiveCompactionConfig).
|
|
266
269
|
function compactionRecord(plan, { stage, after, now, reserve, outcome }) {
|
|
267
|
-
const { session
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
auto: mode === 'auto' ? true : session.compaction?.auto !== false,
|
|
270
|
+
const { session } = plan;
|
|
271
|
+
const live = withoutLegacyCompactFields(session.compaction);
|
|
272
|
+
return withLiveCompactionConfig(live, {
|
|
271
273
|
boundaryTokens: plan.boundary,
|
|
272
274
|
triggerTokens: plan.triggerTokens,
|
|
273
275
|
bufferTokens: plan.bufferTokens,
|
|
@@ -282,7 +284,7 @@ function compactionRecord(plan, { stage, after, now, reserve, outcome }) {
|
|
|
282
284
|
currentEstimatedTokens: after.tokens,
|
|
283
285
|
lastCheckedAt: now,
|
|
284
286
|
...outcome,
|
|
285
|
-
};
|
|
287
|
+
});
|
|
286
288
|
}
|
|
287
289
|
|
|
288
290
|
// compact_meta parity with the loop's pre-send pass: the out-of-loop
|
|
@@ -659,6 +661,26 @@ async function commitSessionCompaction(plan, run, compactStartedAt) {
|
|
|
659
661
|
// Older titleless sessions: keep a name before the transcript that carries
|
|
660
662
|
// the first prompt is replaced.
|
|
661
663
|
if (changed) backfillFallbackSessionTitle(session, messages);
|
|
664
|
+
// Write-ahead: what this compaction drops is durable (pending sidecar)
|
|
665
|
+
// before the shortened transcript is adopted, since any later save persists
|
|
666
|
+
// it. A sidecar that cannot be written keeps the old transcript.
|
|
667
|
+
let archive = null;
|
|
668
|
+
if (changed && plan.archive) {
|
|
669
|
+
try {
|
|
670
|
+
archive = prepareCompactionArchive({
|
|
671
|
+
session,
|
|
672
|
+
sessionId: resolvedSessionId,
|
|
673
|
+
before: messages,
|
|
674
|
+
after: transcript,
|
|
675
|
+
at: now,
|
|
676
|
+
});
|
|
677
|
+
} catch (archiveError) {
|
|
678
|
+
writeStderrBestEffort(
|
|
679
|
+
`[session] compaction not applied (sess=${resolvedSessionId || 'unknown'}): ${archiveError?.message || archiveError}\n`
|
|
680
|
+
);
|
|
681
|
+
return recordFailedCompaction(plan, { compactError: archiveError, freshContextError: null }, compactStartedAt);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
662
684
|
session.messages = transcript;
|
|
663
685
|
// The compacted transcript breaks the cache anyway: a staged working-folder
|
|
664
686
|
// change re-roots the system prompt now and needs no notice any more.
|
|
@@ -677,18 +699,8 @@ async function commitSessionCompaction(plan, run, compactStartedAt) {
|
|
|
677
699
|
outcome: compactionOutcome(session, freshContextResult, changed, now),
|
|
678
700
|
});
|
|
679
701
|
// Display-only: the dropped conversation stays readable above the divider.
|
|
680
|
-
//
|
|
681
|
-
|
|
682
|
-
const archived =
|
|
683
|
-
changed && plan.archive
|
|
684
|
-
? scheduleCompactionArchive({
|
|
685
|
-
session,
|
|
686
|
-
sessionId: resolvedSessionId,
|
|
687
|
-
before: messages,
|
|
688
|
-
after: transcript,
|
|
689
|
-
at: now,
|
|
690
|
-
})
|
|
691
|
-
: null;
|
|
702
|
+
// The publication runs later, off this commit.
|
|
703
|
+
const archived = archive ? { ...archive, written: archive.start() } : null;
|
|
692
704
|
if (changed) {
|
|
693
705
|
invalidateProviderContextBaseline(session);
|
|
694
706
|
if (postCompactPolicy) {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
// The chain applies only while the session runs on the owner's configured
|
|
9
9
|
// primary model. A session the user put on another model (composer picker,
|
|
10
10
|
// New Task) is a deliberate choice and gets none. Route changes recompute it
|
|
11
|
-
// (updateSessionRoute `routeFallbacks`); a fallback hop
|
|
11
|
+
// (updateSessionRoute `routeFallbacks`); a fallback hop reads it from the
|
|
12
|
+
// owner's route at that moment (route-fallback-chain.mjs).
|
|
12
13
|
import { loadConfig } from '../../config.mjs';
|
|
13
14
|
import { findPreset } from '../../runtime-core/config-helpers.mjs';
|
|
14
15
|
import { normalizeWorkflowRoute } from '../../runtime-core/workflow.mjs';
|
|
@@ -17,26 +18,35 @@ import { storedBotRoute } from '../../../../shared/agent-store.mjs';
|
|
|
17
18
|
import { configuredAgentRouteCandidates } from '../../../../shared/agent-route-config.mjs';
|
|
18
19
|
import { CODING_MODE } from '../agent-mode.mjs';
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
/** Whether two routes name the same model (provider aliases folded). */
|
|
22
|
+
export const sameRouteModel = (a, b) =>
|
|
23
|
+
Boolean(a?.provider && a?.model) &&
|
|
24
|
+
canonicalRouteProvider(a.provider) === canonicalRouteProvider(b?.provider) &&
|
|
25
|
+
String(a.model) === String(b?.model);
|
|
26
|
+
|
|
27
|
+
/** The owner's stored route (primary plus `fallbacks`), normalized; null when
|
|
28
|
+
* the owner has none or it cannot be read. */
|
|
29
|
+
export function ownerConfiguredRoute({ sessionMode, agentId, config = null }) {
|
|
30
|
+
if (!agentId) return null;
|
|
22
31
|
const cfg = () => config || loadConfig({ secrets: false });
|
|
23
32
|
let stored;
|
|
24
33
|
if (sessionMode === CODING_MODE) {
|
|
25
|
-
|
|
34
|
+
const loaded = cfg();
|
|
35
|
+
stored = findPreset(loaded, loaded?.default);
|
|
26
36
|
} else {
|
|
27
37
|
// Before the bot split a bot's route is still in the config (Mixy's never).
|
|
28
38
|
stored = storedBotRoute(agentId) || (agentId === 'lead' ? null : configuredAgentRouteCandidates(cfg(), agentId)[0]);
|
|
29
39
|
}
|
|
30
|
-
if (!stored
|
|
31
|
-
let route;
|
|
40
|
+
if (!stored) return null;
|
|
32
41
|
try {
|
|
33
|
-
|
|
42
|
+
return normalizeWorkflowRoute(stored) || null;
|
|
34
43
|
} catch {
|
|
35
|
-
return
|
|
44
|
+
return null;
|
|
36
45
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function ownerRouteFallbacks({ sessionMode, agentId, provider, model, config = null }) {
|
|
49
|
+
const route = ownerConfiguredRoute({ sessionMode, agentId, config });
|
|
50
|
+
if (!route?.fallbacks?.length) return [];
|
|
51
|
+
return sameRouteModel(route, { provider, model }) ? route.fallbacks : [];
|
|
42
52
|
}
|