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
|
@@ -194,38 +194,63 @@ async function archiveIndexFor(path, handle) {
|
|
|
194
194
|
return entries;
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
/**
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
|
|
197
|
+
/** Runs `use(entries, load)` over a session's archive sidecar: its segment
|
|
198
|
+
* index and a loader of one segment's items. The open handle pins the file
|
|
199
|
+
* a concurrent atomic replace may swap out, so the index and the segment
|
|
200
|
+
* reads describe the same bytes. `fallback` when the archive is absent or
|
|
201
|
+
* unreadable (display-only history: it shows nothing then). */
|
|
202
|
+
async function withArchive(storeDir, sessionId, fallback, use) {
|
|
201
203
|
const path = compactionArchivePath(storeDir, sessionId);
|
|
202
|
-
if (!path) return
|
|
204
|
+
if (!path) return fallback;
|
|
203
205
|
let handle;
|
|
204
206
|
try {
|
|
205
207
|
handle = await open(path, 'r');
|
|
206
208
|
} catch {
|
|
207
|
-
// Display-only history: an absent or unreadable archive shows nothing.
|
|
208
209
|
archiveIndexes.delete(path);
|
|
209
|
-
return
|
|
210
|
+
return fallback;
|
|
210
211
|
}
|
|
211
212
|
try {
|
|
212
213
|
const entries = await archiveIndexFor(path, handle);
|
|
213
|
-
return await
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
return segmentItems(buffer.toString('utf8'));
|
|
219
|
-
},
|
|
220
|
-
range
|
|
221
|
-
);
|
|
214
|
+
return await use(entries, async (entry) => {
|
|
215
|
+
const buffer = Buffer.alloc(entry.length);
|
|
216
|
+
await handle.read(buffer, 0, entry.length, entry.start);
|
|
217
|
+
return segmentItems(buffer.toString('utf8'));
|
|
218
|
+
});
|
|
222
219
|
} catch {
|
|
223
|
-
return
|
|
220
|
+
return fallback;
|
|
224
221
|
} finally {
|
|
225
222
|
await handle.close().catch(() => {});
|
|
226
223
|
}
|
|
227
224
|
}
|
|
228
225
|
|
|
226
|
+
/** One page of a session's archive sidecar (see pageFromSegments). */
|
|
227
|
+
export function readCompactionArchivePage(storeDir, sessionId, range = {}) {
|
|
228
|
+
return withArchive(storeDir, sessionId, { items: [], hasOlder: false }, (entries, load) =>
|
|
229
|
+
pageFromSegments(entries, load, range)
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Hands every visible segment of the archive (numbered in (after, before),
|
|
234
|
+
* oldest first) to `visit` as its items, one segment at a time, so a whole
|
|
235
|
+
* walk never holds more than one segment. True when the walk completed;
|
|
236
|
+
* false when the archive was absent or unreadable (the visits made so far
|
|
237
|
+
* are then incomplete). */
|
|
238
|
+
export function visitCompactionArchive(
|
|
239
|
+
storeDir,
|
|
240
|
+
sessionId,
|
|
241
|
+
{ after = 0, before = Number.POSITIVE_INFINITY } = {},
|
|
242
|
+
visit
|
|
243
|
+
) {
|
|
244
|
+
return withArchive(storeDir, sessionId, false, async (entries, load) => {
|
|
245
|
+
for (const entry of entries) {
|
|
246
|
+
const { seq, count } = entry.head;
|
|
247
|
+
if (seq <= after || seq >= before || count < 1) continue;
|
|
248
|
+
visit(await load(entry));
|
|
249
|
+
}
|
|
250
|
+
return true;
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
229
254
|
// Delete fence: every deletion bumps the session's epoch. A writer captures
|
|
230
255
|
// the epoch before it starts and publishes only if it is unchanged at the
|
|
231
256
|
// (synchronous) rename, so a delete that lands while a segment is being
|
|
@@ -24,6 +24,7 @@ export function createEagerDispatcher({
|
|
|
24
24
|
getIterations,
|
|
25
25
|
getNextIteration,
|
|
26
26
|
repeatFailLimit,
|
|
27
|
+
isTurnLimitNoticed = () => false,
|
|
27
28
|
executeToolFn = executeTool,
|
|
28
29
|
}) {
|
|
29
30
|
const pending = new Map();
|
|
@@ -56,7 +57,9 @@ export function createEagerDispatcher({
|
|
|
56
57
|
const startEagerTool = (wireCall) => {
|
|
57
58
|
// Streamed call_tool requests are admitted, ordered and executed as their
|
|
58
59
|
// targets; a projection error is answered by the serial batch instead.
|
|
59
|
-
|
|
60
|
+
// Once the turn was told to reply (any limit), no call runs: the batch
|
|
61
|
+
// refuses them, so none may start while the wrap-up response streams.
|
|
62
|
+
if (capped || isTurnLimitNoticed()) return null;
|
|
60
63
|
const call = resolveExecutionToolCall(wireCall, sessionRef);
|
|
61
64
|
if (!call?.id || pending.has(call.id) || !isParallelDispatchable(call.name)) return null;
|
|
62
65
|
const admitted = admission.admit(call);
|
|
@@ -98,7 +98,8 @@ const LEAD_NAME = 'Lead';
|
|
|
98
98
|
* bot-created task session, a bot's home chat or room member session) and
|
|
99
99
|
* the names from there down to the asker ("Lead › Reviewer", "사무관 ›
|
|
100
100
|
* Worker"). Only where the card shows: no bot identity, grant or remember
|
|
101
|
-
* scope follows from it. Null for a top-level session
|
|
101
|
+
* scope follows from it. Null for a top-level session (whose requests show
|
|
102
|
+
* in the chats handing it work instead: tui/session/tool-approval.mjs). */
|
|
102
103
|
export function approvalSurface(sessionId) {
|
|
103
104
|
const delegation = delegationOf(sessionId);
|
|
104
105
|
if (delegation.state !== 'resolved') return null;
|
|
@@ -156,7 +157,13 @@ async function describeEmails(call, outbound, ctx) {
|
|
|
156
157
|
const { executeMcpTool } = await import('../../mcp/client.mjs');
|
|
157
158
|
const ids = outbound.category === 'trash' && Array.isArray(call.args?.ids) ? call.args.ids.map(String) : [];
|
|
158
159
|
const shown = ids.slice(0, PREVIEW_MESSAGES);
|
|
159
|
-
|
|
160
|
+
// The account the call acts as (one server holds every Gmail account).
|
|
161
|
+
const chosen = typeof call.args?.account === 'string' ? call.args.account.trim() : '';
|
|
162
|
+
const raw = await executeMcpTool(
|
|
163
|
+
name,
|
|
164
|
+
{ ids: shown, ...(chosen ? { account: chosen } : {}) },
|
|
165
|
+
{ scopeId: ctx.mcpScopeId }
|
|
166
|
+
);
|
|
160
167
|
const { account, emails } = JSON.parse(raw);
|
|
161
168
|
const messages = (Array.isArray(emails) ? emails : []).map((mail) =>
|
|
162
169
|
[mail.from, mail.subject, String(mail.date || '').slice(0, 10)].filter(Boolean).join(' · ')
|
|
@@ -231,10 +238,9 @@ export async function humanGateDecision(call, decision, ctx = {}) {
|
|
|
231
238
|
editable: outbound.editable,
|
|
232
239
|
details: outbound.details,
|
|
233
240
|
},
|
|
234
|
-
|
|
241
|
+
// "Don't ask again" is the bot's permission.
|
|
242
|
+
remember: outboundRemember(outbound.category),
|
|
235
243
|
};
|
|
236
|
-
// "Don't ask again" is the bot's permission.
|
|
237
|
-
request.remember = outboundRemember(outbound.category);
|
|
238
244
|
const store = ctx.store || (await humanGateStore());
|
|
239
245
|
const mode = await store.modeFor({ agentId, action: outbound.category });
|
|
240
246
|
const base = decision && typeof decision === 'object' ? decision : {};
|
|
@@ -74,8 +74,6 @@ const MCP_OUTBOUND = new Map([
|
|
|
74
74
|
'slack_post_message',
|
|
75
75
|
'slack_reply_to_thread',
|
|
76
76
|
'chat_post_message',
|
|
77
|
-
'discord_send_message',
|
|
78
|
-
'telegram_send_message',
|
|
79
77
|
].map((name) => [name, 'message']),
|
|
80
78
|
...['create_post', 'publish_post', 'create_tweet', 'post_tweet', 'send_tweet'].map((name) => [name, 'publish']),
|
|
81
79
|
['submit_form', 'form'],
|
|
@@ -12,10 +12,23 @@
|
|
|
12
12
|
// the scopes it allows and can leave out `always`. Nothing here ever carries a
|
|
13
13
|
// secret value: a decision that names one is stripped to its verdict.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const HUMAN_REQUEST_KINDS = Object.freeze(['approval', 'outbound', 'secret', 'takeover', 'permission']);
|
|
16
|
+
const HUMAN_RESPONSES = Object.freeze(['approve', 'deny', 'edit-and-approve', 'provide-secret', 'skip', 'done']);
|
|
17
|
+
const REMEMBER_SCOPES = Object.freeze(['once', 'agent', 'always']);
|
|
18
18
|
export const SECRET_REQUEST_TIMEOUT_MS = 120_000;
|
|
19
|
+
/** What a secret's bound field is: a sign-in form (아이디 + 비밀번호), a lone
|
|
20
|
+
* password, a new password, or a one-time code; '' when unknown (computer). */
|
|
21
|
+
export const SECRET_FORMS = Object.freeze(['login', 'password', 'new-password', 'otp']);
|
|
22
|
+
/** Every result a secret handoff (and a declined or expired takeover) gives
|
|
23
|
+
* the agent: facts, never a verdict about the site. */
|
|
24
|
+
export const HANDOFF_OUTCOMES = Object.freeze([
|
|
25
|
+
'entered',
|
|
26
|
+
'user_skipped',
|
|
27
|
+
'no_field',
|
|
28
|
+
'page_changed',
|
|
29
|
+
'blocked',
|
|
30
|
+
'expired',
|
|
31
|
+
]);
|
|
19
32
|
|
|
20
33
|
const RESPONSES_BY_KIND = Object.freeze({
|
|
21
34
|
approval: ['approve', 'deny'],
|
|
@@ -49,7 +62,7 @@ const text = (value, limit = TEXT_LIMIT) => (typeof value === 'string' ? value.t
|
|
|
49
62
|
|
|
50
63
|
/** The human kind of a request; anything else (ask_user's 'question', a
|
|
51
64
|
* hook's bare ask) is an ordinary approval for responses. */
|
|
52
|
-
|
|
65
|
+
function humanRequestKind(request) {
|
|
53
66
|
return HUMAN_REQUEST_KINDS.includes(request?.kind) ? request.kind : 'approval';
|
|
54
67
|
}
|
|
55
68
|
|
|
@@ -103,11 +116,21 @@ export function humanRequestFields(input = {}) {
|
|
|
103
116
|
}
|
|
104
117
|
if (kind === 'secret') {
|
|
105
118
|
const secret = isRecord(input.secret) ? input.secret : {};
|
|
119
|
+
// The bound page's origin and what its field is (the desktop read it at
|
|
120
|
+
// request time, ask-user-tool.mjs): the card's title and inputs; no value.
|
|
121
|
+
const origin = loginPageUrl(secret.origin)?.origin || '';
|
|
122
|
+
const form = SECRET_FORMS.includes(secret.form) ? secret.form : '';
|
|
123
|
+
// A code's length is the bound field's own (credential-autofill.ts
|
|
124
|
+
// codeLength); absent, it stays unspecified.
|
|
125
|
+
const length = Number.isInteger(secret.length) && secret.length > 0 ? secret.length : 0;
|
|
106
126
|
fields.secret = {
|
|
107
127
|
requestId: text(secret.requestId),
|
|
108
128
|
surface: secret.surface === 'computer' ? 'computer' : 'browser',
|
|
109
129
|
target: text(secret.target),
|
|
110
130
|
field: text(secret.field),
|
|
131
|
+
...(origin ? { origin } : {}),
|
|
132
|
+
...(form ? { form } : {}),
|
|
133
|
+
...(form === 'otp' && length ? { length } : {}),
|
|
111
134
|
};
|
|
112
135
|
fields.args = { surface: fields.secret.surface, target: fields.secret.target, field: fields.secret.field };
|
|
113
136
|
fields.remember = ['once'];
|
|
@@ -132,12 +155,21 @@ export function humanRequestFields(input = {}) {
|
|
|
132
155
|
// A login takeover (purpose 'login') opens the desktop's sign-in window on
|
|
133
156
|
// its validated page instead of handing over the side panel.
|
|
134
157
|
const login = surface === 'browser' && takeover.purpose === 'login' ? loginPageUrl(takeover.url) : null;
|
|
158
|
+
// The saved logins of the sign-in page's origin: opaque ids and masked
|
|
159
|
+
// labels only (profile-import.ts credentialSuggestions), never a password.
|
|
160
|
+
const accounts = (login && Array.isArray(takeover.accounts) ? takeover.accounts : [])
|
|
161
|
+
.filter((account) => isRecord(account) && token(account.id, 128) && text(account.label, 120))
|
|
162
|
+
.map((account) => ({ id: token(account.id, 128), label: text(account.label, 120) }));
|
|
163
|
+
// The page those logins may be filled into, bound by the desktop at
|
|
164
|
+
// request time (ask-user-tool.mjs fillId): without it none is offered.
|
|
165
|
+
const fillId = /^secret_[A-Za-z0-9-]{8,80}$/.test(text(takeover.fillId, 100)) ? text(takeover.fillId, 100) : '';
|
|
135
166
|
fields.takeover = {
|
|
136
167
|
surface,
|
|
137
168
|
instructions: text(takeover.instructions, 2_000),
|
|
138
169
|
...(text(takeover.target) ? { target: text(takeover.target) } : {}),
|
|
139
170
|
...identity,
|
|
140
171
|
...(login ? { purpose: 'login', url: login.url, origin: login.origin } : {}),
|
|
172
|
+
...(accounts.length && fillId ? { accounts, fillId } : {}),
|
|
141
173
|
};
|
|
142
174
|
fields.remember = ['once'];
|
|
143
175
|
}
|
|
@@ -17,7 +17,7 @@ import { ACTION_KINDS, isRememberableAction } from './outbound-policy.mjs';
|
|
|
17
17
|
const ANY_AGENT = '*';
|
|
18
18
|
const FIELD_LIMIT = 200;
|
|
19
19
|
const AUDIT_KEYS = ['agentId', 'kind', 'action', 'tool', 'target', 'decision', 'device'];
|
|
20
|
-
const PERMISSION_MODES = Object.freeze(['ask', 'allow', 'block']);
|
|
20
|
+
export const PERMISSION_MODES = Object.freeze(['ask', 'allow', 'block']);
|
|
21
21
|
|
|
22
22
|
const field = (value) => String(value ?? '').slice(0, FIELD_LIMIT);
|
|
23
23
|
const grantId = (agentId, action) =>
|
|
@@ -21,6 +21,7 @@ import { isAgentModeSession } from '../agent-mode.mjs';
|
|
|
21
21
|
import { providerInputExcludesCache, providerNativePdf } from '../../providers/registry.mjs';
|
|
22
22
|
import { contentMediaBytes, contentMediaCount } from '../../providers/media-normalization.mjs';
|
|
23
23
|
import { splitProtectedContext } from '../compact/messages.mjs';
|
|
24
|
+
import { withLiveCompactionConfig } from '../../runtime-core/compaction-config-keys.mjs';
|
|
24
25
|
|
|
25
26
|
// Unified context-share rule (compact/constants.mjs CONTEXT_SHARE_RATIO): the
|
|
26
27
|
// post-compaction target is 25% of the boundary/context window. One
|
|
@@ -394,13 +395,6 @@ export function invalidateProviderContextBaseline(sessionRef) {
|
|
|
394
395
|
delete sessionRef.contextPressureUnanchoredReason;
|
|
395
396
|
}
|
|
396
397
|
|
|
397
|
-
// A baseline is refreshed on every provider_send/turn-end. When the transcript
|
|
398
|
-
// has grown but no fresh recording landed for this long, recording is failing
|
|
399
|
-
// (zero/absent usage keeps the OLD baseline because record() only returns
|
|
400
|
-
// false) — distrust it and fall back to the estimate. An idle session whose
|
|
401
|
-
// transcript did NOT grow keeps its baseline regardless of age.
|
|
402
|
-
const BASELINE_MAX_STALE_GROWTH_MS = 30 * 60 * 1000;
|
|
403
|
-
|
|
404
398
|
/**
|
|
405
399
|
* Does this anchor still describe this message prefix?
|
|
406
400
|
*
|
|
@@ -480,17 +474,19 @@ function providerBaselinePressureTokens(messages, sessionRef, policy, { includeC
|
|
|
480
474
|
? Math.max(0, tokens - Math.round(storedRequestReserve) + currentRequestReserve)
|
|
481
475
|
: tokens + currentRequestReserve;
|
|
482
476
|
}
|
|
483
|
-
// Staleness means
|
|
484
|
-
//
|
|
485
|
-
//
|
|
486
|
-
//
|
|
487
|
-
//
|
|
488
|
-
//
|
|
489
|
-
//
|
|
490
|
-
//
|
|
491
|
-
//
|
|
492
|
-
|
|
493
|
-
|
|
477
|
+
// Staleness means usage recording is failing: a provider request completed
|
|
478
|
+
// AFTER this reading without replacing it (every send records its usage
|
|
479
|
+
// after it starts, so a working recorder always leaves the reading newer
|
|
480
|
+
// than the last send) — zero/absent usage keeps the OLD baseline because
|
|
481
|
+
// record() only returns false. Never age on a clock: measured against `now`
|
|
482
|
+
// it discarded the reading of every session that sat unopened for a while
|
|
483
|
+
// (88 of 983 stored sessions), and measured against the session's last
|
|
484
|
+
// activity it discarded it whenever anything was appended more than half an
|
|
485
|
+
// hour after the last request — a user back from a break, an agent's result
|
|
486
|
+
// posted to a waiting Lead — so the next send compacted on the
|
|
487
|
+
// whole-transcript estimate, far above the provider's own count.
|
|
488
|
+
const lastSendAt = Number(sessionRef.lastProviderSendAt) || 0;
|
|
489
|
+
if (messages.length > count && baselineAt > 0 && lastSendAt > baselineAt) return null;
|
|
494
490
|
try {
|
|
495
491
|
// Baseline tokens are authoritative provider billing; only the growth
|
|
496
492
|
// after the baseline is a local estimate and needs billing calibration.
|
|
@@ -795,9 +791,9 @@ function compactionTelemetryRecord(sessionRef, policy, meta, prev) {
|
|
|
795
791
|
if (terminalSuccess) return null;
|
|
796
792
|
return present ? (next ?? null) : (previous ?? null);
|
|
797
793
|
};
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
794
|
+
// Config-owned fields stay the live ones (withLiveCompactionConfig): `policy`
|
|
795
|
+
// was resolved before a compaction that a reload may have outlived.
|
|
796
|
+
return withLiveCompactionConfig(prev, {
|
|
801
797
|
requestReserveTokens: policy.requestReserveTokens || 0,
|
|
802
798
|
reserveTokens: policy.reserveTokens || 0,
|
|
803
799
|
boundaryTokens: policy.boundaryTokens || null,
|
|
@@ -848,7 +844,7 @@ function compactionTelemetryRecord(sessionRef, policy, meta, prev) {
|
|
|
848
844
|
compactCount: (prev.compactCount || 0) + (changed ? 1 : 0),
|
|
849
845
|
singleShotConsumed:
|
|
850
846
|
policy.singleShot === true && meta.stage === 'compacting' ? true : prev.singleShotConsumed === true,
|
|
851
|
-
};
|
|
847
|
+
});
|
|
852
848
|
}
|
|
853
849
|
|
|
854
850
|
// Postmortem ring buffer: the per-check telemetry record is overwritten on
|
|
@@ -18,6 +18,9 @@ import { summarizeOnSharedPrefix } from '../compact/forked-summary.mjs';
|
|
|
18
18
|
import { normalizeCompactionSummaryMode } from '../compact/summary-mode.mjs';
|
|
19
19
|
import { compactionCacheWarm, lighterSubscriptionModel } from '../compact/summary-route.mjs';
|
|
20
20
|
import { retireCompactionFork } from '../side-question-store.mjs';
|
|
21
|
+
import { buildSkillToolEnvelope, collectSkillsCached, currentSkillDelivery } from '../../context/collect.mjs';
|
|
22
|
+
import { loadSkillToolDependencies } from '../../runtime-core/skill-tool-loading.mjs';
|
|
23
|
+
import { parseNativeToolSearchPayload } from './tool-helpers.mjs';
|
|
21
24
|
|
|
22
25
|
// Conversation summarization triggers independently of the post-compact target:
|
|
23
26
|
// at 5% of the window, capped so a large window does not carry tens of
|
|
@@ -262,11 +265,37 @@ function freshContextBudget({ compactPolicy, sessionRef, provider, compactBudget
|
|
|
262
265
|
return { contextWindow, hardBudget, conversationInput, conversationTokens, conversationThresholdTokens };
|
|
263
266
|
}
|
|
264
267
|
|
|
268
|
+
// Compact restores each active skill from its current source, as the Skill
|
|
269
|
+
// tool would deliver it in this session now (null: it no longer loads). The
|
|
270
|
+
// real pass also re-arms the skill's current tool dependencies on the session
|
|
271
|
+
// surface and answers the native tool-search payload they produce (or, with
|
|
272
|
+
// none, the Skill result summary); a preview never touches the surface and
|
|
273
|
+
// keeps the transcript's loader pairs.
|
|
274
|
+
function currentSkillResolver(sessionRef, { preview = false } = {}) {
|
|
275
|
+
const cwd = sessionRef?.cwd || null;
|
|
276
|
+
const config = loadConfig({ secrets: false });
|
|
277
|
+
const skills = collectSkillsCached(cwd);
|
|
278
|
+
return (name) => {
|
|
279
|
+
const delivery = currentSkillDelivery(name, cwd, config, skills);
|
|
280
|
+
if (!delivery) return null;
|
|
281
|
+
if (preview) return { body: delivery.body, native: undefined };
|
|
282
|
+
const { resource } = delivery;
|
|
283
|
+
const envelope = loadSkillToolDependencies(
|
|
284
|
+
buildSkillToolEnvelope(name, resource.content, resource.dir, resource),
|
|
285
|
+
sessionRef
|
|
286
|
+
);
|
|
287
|
+
const native = parseNativeToolSearchPayload('Skill', envelope.result);
|
|
288
|
+
return { body: delivery.body, native, summary: native?.summary ?? envelope.result };
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
265
292
|
function freshContextBuildOptions(
|
|
266
|
-
{ compactPolicy = {}, sessionId, goalReminderText, activeTurn, referenceLatestAttachments },
|
|
293
|
+
{ sessionRef, compactPolicy = {}, sessionId, goalReminderText, activeTurn, referenceLatestAttachments, preview },
|
|
267
294
|
budget
|
|
268
295
|
) {
|
|
269
296
|
return {
|
|
297
|
+
// A sessionless call (no session gates to apply) keeps the transcript copies.
|
|
298
|
+
currentSkill: sessionRef ? currentSkillResolver(sessionRef, { preview }) : null,
|
|
270
299
|
reserveTokens: compactPolicy.reserveTokens,
|
|
271
300
|
maxBudgetTokens: budget.hardBudget,
|
|
272
301
|
force: true,
|
|
@@ -287,7 +316,7 @@ export function previewFreshContextCompaction(input) {
|
|
|
287
316
|
const budget = freshContextBudget(input);
|
|
288
317
|
const summaryTriggered = budget.conversationTokens >= budget.conversationThresholdTokens;
|
|
289
318
|
const result = freshContextCompactMessages(input.messages, input.compactBudgetTokens, {
|
|
290
|
-
...freshContextBuildOptions(input, budget),
|
|
319
|
+
...freshContextBuildOptions({ ...input, preview: true }, budget),
|
|
291
320
|
preview: true,
|
|
292
321
|
previewSummary: summaryTriggered,
|
|
293
322
|
});
|
|
@@ -346,7 +375,7 @@ export async function runFreshContextCompact({
|
|
|
346
375
|
});
|
|
347
376
|
const summaryTriggered = conversationTokens >= conversationThresholdTokens;
|
|
348
377
|
const buildOptions = freshContextBuildOptions(
|
|
349
|
-
{ compactPolicy, sessionId, goalReminderText, activeTurn, referenceLatestAttachments },
|
|
378
|
+
{ sessionRef, compactPolicy, sessionId, goalReminderText, activeTurn, referenceLatestAttachments },
|
|
350
379
|
{ contextWindow, hardBudget }
|
|
351
380
|
);
|
|
352
381
|
const build = (handoffText) =>
|
|
@@ -120,7 +120,9 @@ export function createLoopState({ provider, messages, model, tools, cwd, sendOpt
|
|
|
120
120
|
messages.push(message);
|
|
121
121
|
try {
|
|
122
122
|
opts.onToolResult?.(message);
|
|
123
|
-
} catch {
|
|
123
|
+
} catch {
|
|
124
|
+
// the tool-result observer is advisory
|
|
125
|
+
}
|
|
124
126
|
};
|
|
125
127
|
state.drainSteering = createSteeringDrain({
|
|
126
128
|
messages,
|
|
@@ -44,7 +44,7 @@ export function createNoToolTurnResolver({
|
|
|
44
44
|
// whether it answered that input.
|
|
45
45
|
reactions: [],
|
|
46
46
|
// Structured provider continuation signals honored this turn. Diagnostic
|
|
47
|
-
// only:
|
|
47
|
+
// only: this count bounds nothing. A
|
|
48
48
|
// text-only continuation runaway is bounded by continuationsSinceToolBatch
|
|
49
49
|
// below; continuations interleaved with tool batches are not limited.
|
|
50
50
|
providerContinuationCount: 0,
|
|
@@ -6,6 +6,12 @@ import { getProvider, initProviders } from '../../providers/registry.mjs';
|
|
|
6
6
|
import { loadConfig } from '../../config.mjs';
|
|
7
7
|
import { ensureProviderEnabled } from '../../runtime-core/config-helpers.mjs';
|
|
8
8
|
import { updateSessionRoute } from '../manager/session-lifecycle.mjs';
|
|
9
|
+
import {
|
|
10
|
+
liveRouteFallbacks,
|
|
11
|
+
nextRouteFallbackIndex,
|
|
12
|
+
routeFallbackHopped,
|
|
13
|
+
routeLeaf,
|
|
14
|
+
} from '../manager/route-fallback-chain.mjs';
|
|
9
15
|
import { pinSessionWireRoute } from '../../providers/wire-route.mjs';
|
|
10
16
|
import { buildRequestSendOptions } from '../manager/ask-turn-loop-options.mjs';
|
|
11
17
|
import { prepareTurnEffortConfiguration } from '../../providers/effort-configuration.mjs';
|
|
@@ -78,9 +84,13 @@ async function nextContextGrows(state, next) {
|
|
|
78
84
|
|
|
79
85
|
export async function advanceAgentRoute(state, error) {
|
|
80
86
|
const session = state.sessionRef;
|
|
81
|
-
if (!session?.agent
|
|
82
|
-
|
|
83
|
-
|
|
87
|
+
if (!session?.agent) return false;
|
|
88
|
+
// Read from the session's settings at this hop: a chain edited while it runs
|
|
89
|
+
// applies now, and one cleared to [] leaves the provider's own error.
|
|
90
|
+
const { chain } = liveRouteFallbacks(session, loadConfig({ secrets: false }));
|
|
91
|
+
if (!chain.length) return false;
|
|
92
|
+
const index = nextRouteFallbackIndex(session, chain);
|
|
93
|
+
const next = chain[index];
|
|
84
94
|
// Only THIS request must have produced nothing (its stream outcome says so):
|
|
85
95
|
// earlier requests of the turn may have run tools. Their calls and results
|
|
86
96
|
// are already in the live turn, which the next model continues from, so no
|
|
@@ -97,6 +107,8 @@ export async function advanceAgentRoute(state, error) {
|
|
|
97
107
|
const provider = getProvider(next.provider);
|
|
98
108
|
if (!provider) throw new Error(`Provider "${next.provider}" not available`);
|
|
99
109
|
const failed = routeFailure(session, error);
|
|
110
|
+
// The route a reset returns to (setup reset_route_fallback), kept from the first hop.
|
|
111
|
+
const primary = routeFallbackHopped(session) ? session.routeFallbackPrimary : routeLeaf(session);
|
|
100
112
|
// The left model's share of the turn ends here: the running total at the
|
|
101
113
|
// switch bounds it, so each model's tokens are booked at its own rates.
|
|
102
114
|
state.routeUsageHops = [
|
|
@@ -131,6 +143,8 @@ export async function advanceAgentRoute(state, error) {
|
|
|
131
143
|
{ crossProvider: true, session }
|
|
132
144
|
);
|
|
133
145
|
if (!updated) throw new Error('agent session closed during model fallback');
|
|
146
|
+
updated.routeFallbacks = chain;
|
|
147
|
+
if (primary) updated.routeFallbackPrimary = primary;
|
|
134
148
|
updated.routeFallbackIndex = index + 1;
|
|
135
149
|
updated.routeFallbackFailures = [...(session.routeFallbackFailures || []), failed];
|
|
136
150
|
await pinSessionWireRoute(updated, provider);
|
|
@@ -126,13 +126,16 @@ export async function beginIteration(state) {
|
|
|
126
126
|
getIterations: () => state.iterations,
|
|
127
127
|
getNextIteration: () => nextIteration,
|
|
128
128
|
repeatFailLimit: REPEAT_FAIL_LIMIT,
|
|
129
|
+
isTurnLimitNoticed: () => state.turnLimitNoticed === true,
|
|
129
130
|
});
|
|
130
131
|
const resolveToolCallId = createToolCallIdResolver(messages);
|
|
131
132
|
opts.onToolCall = (call) => {
|
|
132
133
|
resolveToolCallId(call);
|
|
133
134
|
try {
|
|
134
135
|
opts.onAssistantToolCallObserved?.(call, { eagerStarted: false });
|
|
135
|
-
} catch {
|
|
136
|
+
} catch {
|
|
137
|
+
// the tool-call observer is advisory
|
|
138
|
+
}
|
|
136
139
|
return eager.onToolCall(call);
|
|
137
140
|
};
|
|
138
141
|
return {
|
|
@@ -173,7 +176,9 @@ export async function sendProviderRequest(state, round) {
|
|
|
173
176
|
});
|
|
174
177
|
try {
|
|
175
178
|
opts.onProviderSendStarted?.();
|
|
176
|
-
} catch {
|
|
179
|
+
} catch {
|
|
180
|
+
// the send-started observer is advisory
|
|
181
|
+
}
|
|
177
182
|
// The request a /btw side question forks: kept while it is in flight, with
|
|
178
183
|
// its reply once it proceeds, and dropped again if it fails.
|
|
179
184
|
const sideQuestion = captureSideQuestionRequest({
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { normalizeToolEnvelope, makeToolEnvelope } from '../../tool-envelope.mjs';
|
|
6
6
|
import { resolveToolResultAfterHook } from '../tool-helpers.mjs';
|
|
7
|
+
import { effectiveToolCwd } from '../../../tools/builtin/bash-tool/shell-cwd.mjs';
|
|
7
8
|
|
|
8
9
|
export async function applyAfterToolHook(result, afterToolHook, { name, args, cwd, callerSessionId, toolCallId }) {
|
|
9
10
|
if (typeof afterToolHook !== 'function') return result;
|
|
@@ -15,7 +16,7 @@ export async function applyAfterToolHook(result, afterToolHook, { name, args, cw
|
|
|
15
16
|
const hookResult = await afterToolHook({
|
|
16
17
|
name,
|
|
17
18
|
args,
|
|
18
|
-
cwd,
|
|
19
|
+
cwd: effectiveToolCwd(name, args, cwd),
|
|
19
20
|
sessionId: callerSessionId,
|
|
20
21
|
toolCallId,
|
|
21
22
|
result: visible,
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
recordHumanDecision,
|
|
16
16
|
} from '../../human-gate/gate.mjs';
|
|
17
17
|
import { applyEditedArgs } from '../../human-gate/requests.mjs';
|
|
18
|
+
import { effectiveToolCwd } from '../../../tools/builtin/bash-tool/shell-cwd.mjs';
|
|
18
19
|
|
|
19
20
|
const isArgsObject = (value) => value && typeof value === 'object' && !Array.isArray(value);
|
|
20
21
|
|
|
@@ -31,7 +32,7 @@ async function askApproval(
|
|
|
31
32
|
resolvePreToolAskApproval({
|
|
32
33
|
toolName: call.name,
|
|
33
34
|
args: call.args,
|
|
34
|
-
cwd: call.cwd,
|
|
35
|
+
cwd: effectiveToolCwd(call.name, call.args, call.cwd),
|
|
35
36
|
sessionId: callerSessionId,
|
|
36
37
|
toolCallId: executeOpts.toolCallId || null,
|
|
37
38
|
askReason,
|
|
@@ -140,7 +141,7 @@ export async function applyBeforeToolHook({
|
|
|
140
141
|
{
|
|
141
142
|
name,
|
|
142
143
|
args,
|
|
143
|
-
cwd,
|
|
144
|
+
cwd: effectiveToolCwd(name, args, cwd),
|
|
144
145
|
sessionId: callerSessionId,
|
|
145
146
|
toolCallId: executeOpts.toolCallId || null,
|
|
146
147
|
},
|
|
@@ -3,7 +3,14 @@
|
|
|
3
3
|
* MCP, code graph, internal tools, shell, apply_patch, built-ins and foreign
|
|
4
4
|
* CLI adapters.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
executeMcpTool,
|
|
8
|
+
isBuiltinMailRead,
|
|
9
|
+
isMcpTool,
|
|
10
|
+
isRegisteredMcpTool,
|
|
11
|
+
mcpToolHasField,
|
|
12
|
+
} from '../../../mcp/client.mjs';
|
|
13
|
+
import { recordMailLinks } from '../../../../../browser-bridge/mail-links.mjs';
|
|
7
14
|
import {
|
|
8
15
|
executeBuiltinTool,
|
|
9
16
|
formatUnknownBuiltinToolMessage,
|
|
@@ -56,11 +63,18 @@ function dispatchMcp(name, args, { cwd, callerSessionId, sessionRef, executeOpts
|
|
|
56
63
|
// an unknown argument.
|
|
57
64
|
const needsCwdInjection = cwd && mcpToolHasField(name, 'cwd', mcpScopeId) && (args == null || args.cwd == null);
|
|
58
65
|
const finalArgs = needsCwdInjection ? { ...(args || {}), cwd } : args;
|
|
59
|
-
|
|
66
|
+
const call = executeMcpTool(name, finalArgs, {
|
|
60
67
|
signal: executeOpts.signal || null,
|
|
61
68
|
ownerKey: callerSessionId,
|
|
62
69
|
scopeId: mcpScopeId,
|
|
63
70
|
});
|
|
71
|
+
if (!isBuiltinMailRead(name, mcpScopeId)) return call;
|
|
72
|
+
// The runtime's own record of the links in a mail it read for this session:
|
|
73
|
+
// the only way Browser Use may open a link carrying a token.
|
|
74
|
+
return call.then((result) => {
|
|
75
|
+
recordMailLinks(callerSessionId, result);
|
|
76
|
+
return result;
|
|
77
|
+
});
|
|
64
78
|
}
|
|
65
79
|
|
|
66
80
|
function dispatchInternal(
|
|
@@ -19,6 +19,7 @@ import { applyBeforeToolHook, applyConnectorApproval, applyShellElevationGate }
|
|
|
19
19
|
import { dispatchToolCall } from './tool-exec/dispatch.mjs';
|
|
20
20
|
import { applyAfterToolHook } from './tool-exec/after-hook.mjs';
|
|
21
21
|
import { runReadOnlyIoWithDeadline } from './tool-exec/read-only-deadline.mjs';
|
|
22
|
+
import { guardShellCall, requestedShellType } from '../../tools/builtin/bash-tool/misuse-guard.mjs';
|
|
22
23
|
|
|
23
24
|
export { runReadOnlyIoWithDeadline as _runReadOnlyIoWithDeadlineForTest };
|
|
24
25
|
export {
|
|
@@ -43,9 +44,23 @@ async function executeToolOwned(name, args, cwd, callerSessionId, sessionRef, ex
|
|
|
43
44
|
const prepared = prepareToolCall(name, args, cwd, callerSessionId, sessionRef, executeOpts);
|
|
44
45
|
const { toolOpts, notifyFn, completionToolOpts } = prepared;
|
|
45
46
|
const toolApprovalHook = hookFrom(executeOpts, sessionRef, 'toolApprovalHook');
|
|
47
|
+
// Shell misuse is judged before any hook or approval sees the call, so they
|
|
48
|
+
// read the command that will run and the directory it runs in.
|
|
49
|
+
let callArgs = prepared.args;
|
|
50
|
+
if (name === 'shell') {
|
|
51
|
+
const guarded = guardShellCall(callArgs, {
|
|
52
|
+
shellType: requestedShellType(callArgs),
|
|
53
|
+
agent: sessionRef?.agent || null,
|
|
54
|
+
sessionId: callerSessionId,
|
|
55
|
+
telemetry: executeOpts.resultTelemetry,
|
|
56
|
+
});
|
|
57
|
+
if (guarded.failure) return guarded.failure;
|
|
58
|
+
callArgs = guarded.args;
|
|
59
|
+
completionToolOpts.shellGuardNotes = guarded.notes;
|
|
60
|
+
}
|
|
46
61
|
const hooked = await applyBeforeToolHook({
|
|
47
62
|
name,
|
|
48
|
-
args:
|
|
63
|
+
args: callArgs,
|
|
49
64
|
cwd: prepared.cwd,
|
|
50
65
|
callerSessionId,
|
|
51
66
|
executeOpts,
|
|
@@ -18,6 +18,7 @@ import { isAgentOwner } from '../../agent-owner.mjs';
|
|
|
18
18
|
import { honoredSchemaAllowlist } from '../manager/session-tool-surface.mjs';
|
|
19
19
|
import { syncSystemPrefix } from '../manager/prompt-utils.mjs';
|
|
20
20
|
import { invalidateProviderContextBaseline } from './compact-policy.mjs';
|
|
21
|
+
import { rebindToChangedPrefix } from '../thinking-binding.mjs';
|
|
21
22
|
|
|
22
23
|
/** Drop everything measured against the previous tool surface. */
|
|
23
24
|
function invalidateForToolSurfaceMigration(session) {
|
|
@@ -34,6 +35,14 @@ function invalidateForToolSurfaceMigration(session) {
|
|
|
34
35
|
*/
|
|
35
36
|
export function markToolSurfaceMigrated(session, intent = TOOL_SURFACE_MIGRATION_INTENT) {
|
|
36
37
|
invalidateForToolSurfaceMigration(session);
|
|
38
|
+
// The stored thinking was bound to the previous prefix and can never be
|
|
39
|
+
// replayed again (../thinking-binding.mjs); an open tool round a stopped
|
|
40
|
+
// turn left behind is ended first. Outside a turn only: a running turn sends
|
|
41
|
+
// from its own working transcript, whose latest tool round must keep its
|
|
42
|
+
// thinking.
|
|
43
|
+
if (Array.isArray(session.messages) && !Array.isArray(session.liveTurnMessages)) {
|
|
44
|
+
session.messages = rebindToChangedPrefix(session.messages);
|
|
45
|
+
}
|
|
37
46
|
session.pendingCacheBreakIntent = intent;
|
|
38
47
|
}
|
|
39
48
|
|
|
@@ -105,6 +114,7 @@ const AGENT_BRIDGE_FIELDS = [
|
|
|
105
114
|
'deferredToolDeltaRevision',
|
|
106
115
|
'nativeDeferredDiscovery',
|
|
107
116
|
'mcpServerInstructions',
|
|
117
|
+
'mcpInstructionsAnnounced',
|
|
108
118
|
];
|
|
109
119
|
|
|
110
120
|
/**
|