mixdog 1.2.2 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/package.json +2 -1
- package/scripts/provider-pingpong-live.mjs +509 -0
- package/src/agents/advisor/AGENT.md +1 -1
- package/src/agents/advisor/agent.json +1 -1
- package/src/defaults/shipped-history.json +5 -0
- package/src/defaults/skills/setup/SKILL.md +6 -1
- package/src/defaults/skills/setup/references/actions.md +44 -22
- package/src/defaults/skills/setup/references/surfaces.md +10 -8
- package/src/headless-exec.mjs +15 -8
- package/src/lib/keychain-cjs.cjs +7 -4
- package/src/output-styles/common.md +11 -10
- package/src/rules/agent/AGENT.md +5 -5
- package/src/rules/lead/LEAD.md +5 -5
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
- package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
- package/src/runtime/agent/orchestrator/config.mjs +5 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +24 -17
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +7 -6
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +29 -10
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +58 -7
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +29 -10
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +12 -6
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +114 -72
- package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +37 -5
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
- package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
- package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +25 -8
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +87 -5
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +13 -13
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +355 -37
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +93 -47
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +55 -10
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +26 -8
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
- package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
- package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
- package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
- package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +121 -61
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
- package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +42 -24
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +63 -25
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +53 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +103 -26
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +23 -4
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +11 -6
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +15 -23
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +25 -4
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +71 -24
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +11 -3
- package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
- package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +147 -8
- package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
- package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
- package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
- package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
- package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
- package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
- package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
- package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
- package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
- package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
- package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
- package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
- package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +63 -20
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +15 -3
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
- package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
- package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
- package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +10 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
- package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
- package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
- package/src/runtime/computer-bridge/action-schema.mjs +44 -21
- package/src/runtime/github/tool.mjs +92 -2
- package/src/runtime/memory/index.mjs +1 -0
- package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
- package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
- package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
- package/src/runtime/memory/lib/pg/process.mjs +31 -26
- package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +108 -3
- package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
- package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
- package/src/runtime/office/README.md +1 -1
- package/src/runtime/office/authoring/html-document-author.mjs +2 -0
- package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
- package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
- package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
- package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
- package/src/runtime/office/core/office-actions-read.mjs +3 -0
- package/src/runtime/office/core/office-render-preview.mjs +2 -0
- package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
- package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
- package/src/runtime/office/core/office-sessions.mjs +5 -0
- package/src/runtime/office/core/office-transactions.mjs +3 -0
- package/src/runtime/office/core/office-write-ledger.mjs +98 -0
- package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
- package/src/runtime/office/index.mjs +30 -0
- package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
- package/src/runtime/office/pdf/pdf-render.mjs +23 -7
- package/src/runtime/office/pdf/pdf-security.mjs +2 -0
- package/src/runtime/office/portable/portable-opc.mjs +4 -1
- package/src/runtime/office/quality/visual-diff.mjs +2 -0
- package/src/runtime/shared/bounded-file-read.mjs +13 -0
- package/src/runtime/shared/bounded-line-diff.mjs +182 -0
- package/src/runtime/shared/buffered-appender.mjs +18 -0
- package/src/runtime/shared/config.mjs +78 -18
- package/src/runtime/shared/err-text.mjs +6 -0
- package/src/runtime/shared/file-permissions.d.mts +6 -1
- package/src/runtime/shared/file-permissions.mjs +54 -6
- package/src/runtime/shared/llm/anthropic-effort.mjs +6 -0
- package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
- package/src/runtime/shared/loopback-listener.mjs +9 -0
- package/src/runtime/shared/provider-api-key.mjs +2 -0
- package/src/runtime/shared/review-diff.mjs +52 -0
- package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
- package/src/runtime/shared/session-sidebar-host.mjs +38 -0
- package/src/runtime/shared/slow-span.mjs +114 -0
- package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
- package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
- package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
- package/src/runtime/shared/tool-card-model.mjs +5 -2
- package/src/runtime/shared/tool-output-limit.mjs +4 -0
- package/src/runtime/shared/tool-primitives.mjs +13 -0
- package/src/runtime/shared/tool-result-summary.mjs +8 -1
- package/src/runtime/shared/tool-surface.mjs +18 -3
- package/src/runtime/shared/tool-work-units.mjs +40 -4
- package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
- package/src/runtime/shared/transcript-writer.mjs +10 -2
- package/src/runtime/shared/turn-changes.mjs +268 -100
- package/src/runtime/shared/turn-review-reply.mjs +8 -39
- package/src/runtime/shared/turn-snapshot-store.mjs +19 -108
- package/src/runtime/shared/turn-snapshot.mjs +857 -683
- package/src/runtime/shared/turn-worktree-snapshot.mjs +183 -255
- package/src/runtime/shared/user-data-guard.mjs +262 -49
- package/src/runtime/shared/worktrees/carry.mjs +531 -0
- package/src/runtime/shared/worktrees/contract.mjs +34 -0
- package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
- package/src/runtime/shared/worktrees/git-head.mjs +205 -0
- package/src/runtime/shared/worktrees/git.mjs +8 -3
- package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
- package/src/runtime/shared/worktrees/manager.mjs +156 -8
- package/src/runtime/shared/worktrees/merge.mjs +31 -21
- package/src/runtime/shared/worktrees/paths.d.mts +6 -0
- package/src/runtime/terminal-bridge/client.mjs +44 -11
- package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
- package/src/runtime/tidy/apply.mjs +47 -2
- package/src/runtime/tidy/run-engines.mjs +11 -5
- package/src/session-runtime/agent-tool-routing.mjs +19 -13
- package/src/session-runtime/boot/apis.mjs +13 -5
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/infrastructure.mjs +6 -1
- package/src/session-runtime/boot/session.mjs +0 -1
- package/src/session-runtime/boot/tools.mjs +4 -1
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
- package/src/session-runtime/internal-tool-executor.mjs +6 -2
- package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
- package/src/session-runtime/lifecycle/session-catalog.mjs +12 -3
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
- package/src/session-runtime/lifecycle/teardown.mjs +72 -7
- package/src/session-runtime/lifecycle-api.mjs +1 -0
- package/src/session-runtime/mcp-glue/connect.mjs +17 -5
- package/src/session-runtime/model-route/set-route.mjs +2 -2
- package/src/session-runtime/native-web-search-usage.mjs +51 -0
- package/src/session-runtime/native-web-search.mjs +10 -1
- package/src/session-runtime/new-session-config.mjs +4 -2
- package/src/session-runtime/provider-auth/login.mjs +4 -0
- package/src/session-runtime/resource-scope-decorate.mjs +10 -3
- package/src/session-runtime/runtime-review-api.mjs +8 -2
- package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
- package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
- package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
- package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
- package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
- package/src/session-runtime/services/agent-tool.mjs +3 -0
- package/src/session-runtime/services/channel-admin.mjs +19 -3
- package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
- package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
- package/src/session-runtime/services/provider-admin.mjs +81 -15
- package/src/session-runtime/session-transcript-purge.mjs +32 -0
- package/src/session-runtime/session-turn-api.mjs +14 -5
- package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
- package/src/session-runtime/setup-tool/executor.mjs +36 -6
- package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
- package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
- package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
- package/src/session-runtime/skills-api.mjs +3 -5
- package/src/session-runtime/tool-surface.mjs +5 -1
- package/src/session-runtime/turn/compaction-gate.mjs +25 -0
- package/src/session-runtime/turn/session-ops.mjs +7 -5
- package/src/session-runtime/turn/side-question-ops.mjs +22 -0
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
- package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +25 -9
- package/src/session-runtime/usage-stats-api.mjs +43 -11
- package/src/session-runtime/workspace/project-branches.mjs +7 -5
- package/src/session-runtime/workspace/transition-steps.mjs +129 -31
- package/src/session-runtime/workspace/transitions.mjs +190 -15
- package/src/standalone/daemon-agent-control.mjs +9 -1
- package/src/standalone/daemon-local-session-bridge.mjs +14 -1
- package/src/standalone/daemon-owner.mjs +17 -4
- package/src/standalone/daemon-pg-stop.mjs +51 -0
- package/src/standalone/daemon-stop-budget.d.mts +2 -0
- package/src/standalone/daemon-stop-budget.mjs +18 -0
- package/src/standalone/daemon-stored-session-views.mjs +2 -0
- package/src/standalone/daemon-telemetry.mjs +19 -0
- package/src/standalone/daemon.mjs +61 -1
- package/src/standalone/desktop-service-registry.mjs +5 -0
- package/src/standalone/local-session-runtime.mjs +70 -19
- package/src/standalone/session-client.mjs +42 -0
- package/src/standalone/session-protocol.mjs +7 -0
- package/src/standalone/session-proxy/projection.mjs +41 -4
- package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
- package/src/standalone/session-runtime-inline-host.mjs +1 -0
- package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
- package/src/standalone/session-service-api.mjs +6 -1
- package/src/standalone/session-state-patch.d.mts +2 -1
- package/src/standalone/session-state-patch.mjs +41 -1
- package/src/tui/App.jsx +25 -0
- package/src/tui/app/app-view/floating-panel.jsx +26 -1
- package/src/tui/app/btw-controller.mjs +118 -0
- package/src/tui/app/create-app-pickers.mjs +2 -0
- package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
- package/src/tui/app/shell-layout/surfaces.mjs +3 -1
- package/src/tui/app/slash-commands.mjs +13 -3
- package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
- package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
- package/src/tui/app/use-global-key-input.mjs +5 -12
- package/src/tui/app/use-prompt-handlers.mjs +11 -0
- package/src/tui/components/BtwPanel.jsx +53 -0
- package/src/tui/components/QuestionPanel.jsx +275 -0
- package/src/tui/components/question-panel-model.mjs +156 -0
- package/src/tui/dist/index.mjs +2413 -1465
- package/src/tui/session/context-state.mjs +4 -2
- package/src/tui/session/session-api/commands.mjs +10 -0
- package/src/tui/session/session-api/controls.mjs +2 -2
- package/src/tui/session/session-api/integrations.mjs +9 -2
- package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
- package/src/tui/session/session-api/lifecycle.mjs +2 -1
- package/src/tui/session/session-api/settings.mjs +6 -0
- package/src/tui/session/session-api.mjs +1 -0
- package/src/tui/session/tool-approval.mjs +10 -7
- package/src/tui/session/transcript-spill.mjs +14 -7
- package/src/tui/session/turn-stream.mjs +174 -31
- package/src/tui/session/turn.mjs +12 -5
- package/src/workflows/default/WORKFLOW.md +3 -1
|
@@ -46,6 +46,62 @@ export function agentContextOverflowError(
|
|
|
46
46
|
);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
export const TOOL_SURFACE_EXCEEDS_CONTEXT = 'TOOL_SURFACE_EXCEEDS_CONTEXT';
|
|
50
|
+
|
|
51
|
+
const tokens = (value) => `${Number(value || 0).toLocaleString('en-US')} tokens`;
|
|
52
|
+
|
|
53
|
+
// Distinct from AgentContextOverflowError: the request's FIXED overhead (tool
|
|
54
|
+
// definitions, protected system context, configured headroom) leaves no room
|
|
55
|
+
// for any history, so compacting the history cannot help and is not tried.
|
|
56
|
+
// The wording avoids provider context-overflow phrasing on purpose: this is
|
|
57
|
+
// not a "conversation too long" refusal and must not be routed as one.
|
|
58
|
+
export class ToolSurfaceExceedsContextError extends Error {
|
|
59
|
+
constructor({ sessionId, provider, model, overhead }) {
|
|
60
|
+
const target = [provider, model].filter(Boolean).join('/') || 'this model';
|
|
61
|
+
const reserve = overhead.kind === 'configured_reserve';
|
|
62
|
+
const headline = reserve
|
|
63
|
+
? 'The configured compaction headroom leaves no room for conversation history'
|
|
64
|
+
: 'Tool definitions and system context leave no room for conversation history';
|
|
65
|
+
const remedy = reserve
|
|
66
|
+
? 'Lower the configured headroom (compaction.reservedTokens or MIXDOG_AGENT_COMPACT_RESERVED_TOKENS), or use a model with a larger context window.'
|
|
67
|
+
: `Use a model with a larger context window, or send a smaller eager tool surface (disable MCP servers or custom tools this session does not need)${
|
|
68
|
+
overhead.configuredReserveTokens > 0 ? ', or configure fewer reserved tokens (compaction.reservedTokens)' : ''
|
|
69
|
+
}.`;
|
|
70
|
+
const largest = overhead.largestTools.map((tool) => `${tool.name} (${tokens(tool.tokens)})`).join(', ');
|
|
71
|
+
super(
|
|
72
|
+
[
|
|
73
|
+
`${headline} (${TOOL_SURFACE_EXCEEDS_CONTEXT}).`,
|
|
74
|
+
`${target}: context window ${tokens(overhead.contextWindowTokens)}, compaction boundary ${tokens(overhead.boundaryTokens)}.`,
|
|
75
|
+
`Fixed per-request overhead: tool definitions ${tokens(overhead.toolTokens)} (${overhead.toolCount} tools), ` +
|
|
76
|
+
`protected system context ${tokens(overhead.systemTokens)}, configured headroom ${tokens(overhead.configuredReserveTokens)}; ` +
|
|
77
|
+
'nothing remains for conversation history.',
|
|
78
|
+
...(overhead.measuredRequestTokens
|
|
79
|
+
? [`The provider measured the last request at ${tokens(overhead.measuredRequestTokens)}.`]
|
|
80
|
+
: []),
|
|
81
|
+
'Compacting the conversation history cannot reduce these.',
|
|
82
|
+
remedy,
|
|
83
|
+
...(largest ? [`Largest tool definitions: ${largest}.`] : []),
|
|
84
|
+
].join('\n')
|
|
85
|
+
);
|
|
86
|
+
this.name = 'ToolSurfaceExceedsContextError';
|
|
87
|
+
this.code = TOOL_SURFACE_EXCEEDS_CONTEXT;
|
|
88
|
+
this.sessionId = sessionId || null;
|
|
89
|
+
this.provider = provider || null;
|
|
90
|
+
this.model = model || null;
|
|
91
|
+
this.overheadKind = overhead.kind;
|
|
92
|
+
this.overhead = overhead;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function toolSurfaceExceedsContextError({ sessionId, sessionRef, model, overhead }) {
|
|
97
|
+
return new ToolSurfaceExceedsContextError({
|
|
98
|
+
sessionId,
|
|
99
|
+
provider: sessionRef?.provider || null,
|
|
100
|
+
model: sessionRef?.model || model || null,
|
|
101
|
+
overhead,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
49
105
|
// Distinct from AgentContextOverflowError: the compaction pipeline itself
|
|
50
106
|
// failed (handoff-summary error, dead Memory runtime,
|
|
51
107
|
// etc.). This is NOT "latest turn cannot fit the context budget" — masking it
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
// Deferred catalog call-through: inactive catalog tool_use → discovery bookkeeping
|
|
2
2
|
// then normal executeTool routing (runtime errors only; no pre-dispatch schema).
|
|
3
3
|
import { clean } from '../../runtime-core/session-text.mjs';
|
|
4
|
-
import {
|
|
5
|
-
deferredCatalogUnion,
|
|
6
|
-
isReadonlySelectable,
|
|
7
|
-
selectDeferredTools,
|
|
8
|
-
} from '../../runtime-core/tool-catalog.mjs';
|
|
4
|
+
import { deferredCatalogUnion, isReadonlySelectable, selectDeferredTools } from '../../runtime-core/tool-catalog.mjs';
|
|
9
5
|
import { isDeferredToolAvailable } from '../../runtime-core/deferred-tool-availability.mjs';
|
|
6
|
+
import { routeToolExclusionReason } from './provider-tool-exclusions.mjs';
|
|
7
|
+
import { isBridgeReadonlySession, isToolBridgeEnabled } from '../../runtime-core/tool-bridge.mjs';
|
|
10
8
|
|
|
11
9
|
/** Skill-list plumbing only; mutation/MCP/builtins must use the catalog+mode gate. */
|
|
12
10
|
const INACTIVE_INFRA_BYPASS = new Set(['skills_list', 'skill_view']);
|
|
@@ -41,7 +39,7 @@ function toolExecutesWhenInactive(name) {
|
|
|
41
39
|
return INACTIVE_INFRA_BYPASS.has(name);
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
function resolveDeferredSelectMode(session) {
|
|
42
|
+
export function resolveDeferredSelectMode(session) {
|
|
45
43
|
const spec = session?.toolSpec;
|
|
46
44
|
if (spec == null || spec === '') return null;
|
|
47
45
|
if (spec === 'readonly') return 'readonly';
|
|
@@ -89,20 +87,32 @@ export function prepareDeferredToolCallThrough(sessionRef, name) {
|
|
|
89
87
|
}
|
|
90
88
|
const tool = lookupDeferredCatalogTool(sessionRef, name);
|
|
91
89
|
if (!tool) return null;
|
|
90
|
+
const routeExclusion = isToolBridgeEnabled(sessionRef) ? null : routeToolExclusionReason(sessionRef, tool);
|
|
91
|
+
if (routeExclusion) return denyDeferredCallThrough(`Error: ${routeExclusion}`);
|
|
92
92
|
if (isActiveSessionTool(sessionRef, name)) return null;
|
|
93
93
|
if (toolExecutesWhenInactive(name)) return null;
|
|
94
94
|
|
|
95
95
|
const toolLabel = clean(tool.name) || clean(name) || 'tool';
|
|
96
|
+
const bridge = isToolBridgeEnabled(sessionRef);
|
|
96
97
|
const resolvedMode = resolveDeferredSelectMode(sessionRef);
|
|
98
|
+
// Whatever the exposure, a deferred mutating tool never runs without a
|
|
99
|
+
// resolved tool mode, and never in a read-only one.
|
|
97
100
|
if (resolvedMode === null) {
|
|
98
101
|
if (!isReadonlySelectable(tool)) {
|
|
102
|
+
const remedy = bridge ? 'no call was sent.' : `load it with load_tool names:["${toolLabel}"].`;
|
|
99
103
|
return denyDeferredCallThrough(
|
|
100
|
-
`Error: tool "${toolLabel}" is deferred and cannot be auto-loaded without a resolved tool mode;
|
|
104
|
+
`Error: tool "${toolLabel}" is deferred and cannot be auto-loaded without a resolved tool mode; ${remedy}`
|
|
101
105
|
);
|
|
102
106
|
}
|
|
103
|
-
} else if (
|
|
107
|
+
} else if (
|
|
108
|
+
(resolvedMode === 'readonly' || (bridge && isBridgeReadonlySession(sessionRef))) &&
|
|
109
|
+
!isReadonlySelectable(tool)
|
|
110
|
+
) {
|
|
104
111
|
return denyDeferredCallThrough(`Error: tool "${toolLabel}" is not available in readonly mode`);
|
|
105
112
|
}
|
|
113
|
+
// Bridge sessions reach deferred tools through call_tool: the fixed
|
|
114
|
+
// provider surface is never extended.
|
|
115
|
+
if (bridge) return null;
|
|
106
116
|
|
|
107
117
|
const selectMode = resolvedMode === null ? 'readonly' : resolvedMode;
|
|
108
118
|
selectDeferredTools(sessionRef, [toolLabel], selectMode);
|
|
@@ -114,6 +114,7 @@ export function createLoopState({ provider, messages, model, tools, cwd, sendOpt
|
|
|
114
114
|
// One-shot repair of an assistant turn whose stored reasoning replay the
|
|
115
115
|
// API refuses to take back (see thinking-replay-recovery.mjs).
|
|
116
116
|
thinkingReplayRepairUsed: false,
|
|
117
|
+
toolSchemaDropUsed: false,
|
|
117
118
|
// Pending image-strip retry: identities of the images every attempt leaves
|
|
118
119
|
// out until a send succeeds, and whether to heal them from history then.
|
|
119
120
|
imageStrip: null,
|
|
@@ -13,8 +13,12 @@
|
|
|
13
13
|
// registry knows its name.
|
|
14
14
|
import { isAgentOwner } from '../../agent-owner.mjs';
|
|
15
15
|
import { isOffReadonlySurface } from './deferred-call-through.mjs';
|
|
16
|
+
import { BRIDGE_CALL_TOOL_NAME, bridgeErrorText, isToolBridgeEnabled } from '../../runtime-core/tool-bridge.mjs';
|
|
17
|
+
import { sessionAllowlistExcludes, sessionDisallows } from '../../runtime-core/deferred-tool-availability.mjs';
|
|
18
|
+
import { providerToolExclusionReason } from './provider-tool-exclusions.mjs';
|
|
16
19
|
|
|
17
|
-
const WORKER_DENIED_TOOLS = new Set(['agent']);
|
|
20
|
+
const WORKER_DENIED_TOOLS = new Set(['agent', 'ask_user', 'session']);
|
|
21
|
+
const BRIDGE_DISCOVERY_TOOL_NAMES = new Set(['load_tool']);
|
|
18
22
|
|
|
19
23
|
const IMAGE_PATH_RE = /\.(?:png|jpe?g|gif|webp)(?:$|[?#])/i;
|
|
20
24
|
const COMPACTED_PATCH_LINE_RE = /^\s*\[mixdog compacted\b[^\]\n]*\]/;
|
|
@@ -95,17 +99,24 @@ export function routeWebFetchCall(call) {
|
|
|
95
99
|
export function preDispatchDenyForSession(sessionRef, call) {
|
|
96
100
|
const name = call?.name;
|
|
97
101
|
if (typeof name !== 'string' || !name) return null;
|
|
102
|
+
// A call_tool request that could not be projected onto its target answers
|
|
103
|
+
// its wire id with the projection error; call_tool itself never dispatches.
|
|
104
|
+
if (typeof call.bridgeError === 'string') return call.bridgeError;
|
|
105
|
+
if (name === BRIDGE_CALL_TOOL_NAME && isToolBridgeEnabled(sessionRef)) {
|
|
106
|
+
return bridgeErrorText('BRIDGE_RECURSION', 'call_tool runs one tool named in its arguments and cannot be dispatched itself.');
|
|
107
|
+
}
|
|
98
108
|
const schemaName = String(call?.schemaName || name);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
109
|
+
// A tool the provider left out of this request still exists in the session;
|
|
110
|
+
// a call to it is answered with why it is unavailable.
|
|
111
|
+
const excluded = providerToolExclusionReason(sessionRef, schemaName);
|
|
112
|
+
if (excluded) return `Error: ${excluded}`;
|
|
113
|
+
// The bridge's discovery tools grant no authority (every call_tool target
|
|
114
|
+
// is judged here under its own name), so an allowlist never strands them.
|
|
115
|
+
const bridgeDiscovery = isToolBridgeEnabled(sessionRef) && BRIDGE_DISCOVERY_TOOL_NAMES.has(schemaName);
|
|
116
|
+
if (!bridgeDiscovery && sessionAllowlistExcludes(sessionRef, schemaName)) {
|
|
117
|
+
return `Error: tool "${name}" is not available on this session's schema allowlist.`;
|
|
104
118
|
}
|
|
105
|
-
if (
|
|
106
|
-
Array.isArray(sessionRef?.disallowedTools) &&
|
|
107
|
-
sessionRef.disallowedTools.some((toolName) => String(toolName).toLowerCase() === schemaName.toLowerCase())
|
|
108
|
-
) {
|
|
119
|
+
if (sessionDisallows(sessionRef, schemaName)) {
|
|
109
120
|
return `Error: tool "${name}" is not available in this session.`;
|
|
110
121
|
}
|
|
111
122
|
if (isOffReadonlySurface(sessionRef, schemaName)) {
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// Tools a provider left out of a request because it cannot accept their input
|
|
2
|
+
// schema even after the wire's normalization (a schema with an unknown type
|
|
3
|
+
// name, an unresolvable $ref, a non-object root), or that the provider
|
|
4
|
+
// rejected with an HTTP 400 naming the schema (dropped for the session).
|
|
5
|
+
// The user is told once per session and tool on the turn's display-only stage
|
|
6
|
+
// channel (stage 'notice'); a call the model still makes to such a tool is
|
|
7
|
+
// answered with the reason instead of running it.
|
|
8
|
+
import { geminiToolExclusion } from '../../providers/gemini-schema.mjs';
|
|
9
|
+
import { isGeminiFamilyModel } from '../../providers/gemini-family.mjs';
|
|
10
|
+
import { anthropicToolExclusion } from '../../providers/lib/anthropic-request-utils.mjs';
|
|
11
|
+
import { claudeBridgeInputSchema, wireInputSchema } from '../../providers/lib/claude-bridge-schema.mjs';
|
|
12
|
+
import { actionInputUnionFor } from '../../providers/lib/action-input-contract.mjs';
|
|
13
|
+
import { isAntigravityClaude } from '../../providers/antigravity-request.mjs';
|
|
14
|
+
import { isResponsesFreeformTool } from '../../providers/custom-tool-wire.mjs';
|
|
15
|
+
import { ANTHROPIC_NATIVE_PROVIDERS } from '../../runtime-core/tool-catalog-schema.mjs';
|
|
16
|
+
import { finalizeProviderRequestTools, providerNativeToolPrefixCount } from '../../runtime-core/provider-request-tools.mjs';
|
|
17
|
+
|
|
18
|
+
const sessions = new WeakMap();
|
|
19
|
+
|
|
20
|
+
function exclusionsFor(sessionRef) {
|
|
21
|
+
let state = sessions.get(sessionRef);
|
|
22
|
+
if (!state) {
|
|
23
|
+
state = { noticed: new Set(), current: new Map(), dropped: new Map() };
|
|
24
|
+
sessions.set(sessionRef, state);
|
|
25
|
+
}
|
|
26
|
+
return state;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const isSessionRef = (value) => value !== null && typeof value === 'object';
|
|
30
|
+
|
|
31
|
+
/** A new provider request: exclusions describe the latest request only. */
|
|
32
|
+
export function beginProviderToolExclusions(sessionRef) {
|
|
33
|
+
if (isSessionRef(sessionRef)) sessions.get(sessionRef)?.current.clear();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function excludedToolNoticeText({ name, pointer, reason }) {
|
|
37
|
+
return `Tool "${name}" was excluded from this session's requests: its input schema is invalid at ${pointer || '/'} (${reason}). Fix the tool's schema or disable the tool.`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Record `exclusion` ({ name, pointer, reason }) for the session's current
|
|
41
|
+
* request and raise the user notice the first time this tool is excluded. */
|
|
42
|
+
export function recordProviderToolExclusion(sessionRef, exclusion, onStageChange) {
|
|
43
|
+
const name = String(exclusion?.name || '');
|
|
44
|
+
if (!name || !isSessionRef(sessionRef)) return;
|
|
45
|
+
const state = exclusionsFor(sessionRef);
|
|
46
|
+
state.current.set(name, exclusion);
|
|
47
|
+
if (state.noticed.has(name)) return;
|
|
48
|
+
state.noticed.add(name);
|
|
49
|
+
try {
|
|
50
|
+
onStageChange?.('notice', { tone: 'warn', message: excludedToolNoticeText(exclusion) });
|
|
51
|
+
} catch {
|
|
52
|
+
/* display-only */
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const unavailableText = (exclusion) =>
|
|
57
|
+
`tool "${exclusion.name}" is unavailable with the current model: the provider rejected its input schema at ${exclusion.pointer || '/'} (${exclusion.reason}), so it was left out of the request; no call was sent. Use another tool, or ask the user to fix the tool's schema or disable it.`;
|
|
58
|
+
|
|
59
|
+
/** Why `name` cannot be called in the session's current request, or null. */
|
|
60
|
+
export function providerToolExclusionReason(sessionRef, name) {
|
|
61
|
+
if (!isSessionRef(sessionRef)) return null;
|
|
62
|
+
const state = sessions.get(sessionRef);
|
|
63
|
+
const key = String(name || '');
|
|
64
|
+
const exclusion = state?.current.get(key) || state?.dropped.get(key);
|
|
65
|
+
return exclusion ? unavailableText(exclusion) : null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** The provider rejected `exclusion.name`'s schema with an HTTP 400: leave the
|
|
69
|
+
* tool out of every later request of the session and tell the user once. */
|
|
70
|
+
export function dropSessionTool(sessionRef, exclusion, onStageChange) {
|
|
71
|
+
if (!isSessionRef(sessionRef)) return;
|
|
72
|
+
exclusionsFor(sessionRef).dropped.set(exclusion.name, exclusion);
|
|
73
|
+
recordProviderToolExclusion(sessionRef, exclusion, onStageChange);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** The request's tool surface without the tools dropped for the session
|
|
77
|
+
* ({ sendTools, requestToolScope }, the same objects when none apply). */
|
|
78
|
+
export function withoutDroppedTools(sessionRef, { sendTools, requestToolScope }) {
|
|
79
|
+
const dropped = isSessionRef(sessionRef) ? sessions.get(sessionRef)?.dropped : null;
|
|
80
|
+
if (!dropped?.size) return { sendTools, requestToolScope };
|
|
81
|
+
const prefix = providerNativeToolPrefixCount(sendTools);
|
|
82
|
+
const kept = sendTools.filter((tool, index) => index < prefix || !dropped.has(tool?.name));
|
|
83
|
+
if (kept.length === sendTools.length) return { sendTools, requestToolScope };
|
|
84
|
+
const next = finalizeProviderRequestTools(kept, prefix);
|
|
85
|
+
return { sendTools: next, requestToolScope: { ...requestToolScope, requestTools: next } };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// The schema rule of the wire a session's requests use: 'gemini', 'anthropic'
|
|
89
|
+
// (Messages), 'antigravity-claude' (Anthropic bridge behind Antigravity) or
|
|
90
|
+
// 'openai' (Responses, Codex and every OpenAI-compatible chat route).
|
|
91
|
+
function routeSchemaFamily(session) {
|
|
92
|
+
const provider = String(session?.provider || '').toLowerCase();
|
|
93
|
+
const wire = session?.wireRoute?.wire;
|
|
94
|
+
if (provider === 'antigravity-oauth' && isAntigravityClaude(session?.model)) return 'antigravity-claude';
|
|
95
|
+
if (provider === 'gemini' || isGeminiFamilyModel(session?.model)) return 'gemini';
|
|
96
|
+
if (ANTHROPIC_NATIVE_PROVIDERS.has(provider) || wire === 'messages') return 'anthropic';
|
|
97
|
+
return 'openai';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function wireExclusion(tool, result) {
|
|
101
|
+
return result.schema ? null : { name: tool.name, pointer: result.pointer || '/', reason: result.reason };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// The same normalization + validation the wire applies to `tool`, as
|
|
105
|
+
// { name, pointer, reason } when the route leaves it out of its requests.
|
|
106
|
+
function schemaExclusion(session, family, tool) {
|
|
107
|
+
switch (family) {
|
|
108
|
+
case 'gemini':
|
|
109
|
+
return geminiToolExclusion(tool);
|
|
110
|
+
case 'anthropic':
|
|
111
|
+
return anthropicToolExclusion(tool, String(session?.provider || 'anthropic').toLowerCase());
|
|
112
|
+
case 'antigravity-claude':
|
|
113
|
+
return wireExclusion(tool, claudeBridgeInputSchema(actionInputUnionFor(tool.inputSchema)));
|
|
114
|
+
default:
|
|
115
|
+
if (tool.inputSchema == null) return null;
|
|
116
|
+
if (/^openai(-oauth)?$/.test(String(session?.provider || '')) && isResponsesFreeformTool(tool)) return null;
|
|
117
|
+
return wireExclusion(tool, wireInputSchema(tool.inputSchema, 'openai'));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Why `tool` is left out of every request on the session's route, or null.
|
|
122
|
+
* Validation is a pure function of the tool's schema and the route's wire, so
|
|
123
|
+
* this holds before the tool was ever sent and stays stable across turns; a
|
|
124
|
+
* tool the provider rejected with a 400 is dropped for the session. Built-in
|
|
125
|
+
* tools are never excluded by the schema rule. */
|
|
126
|
+
export function routeToolExclusionReason(session, tool) {
|
|
127
|
+
if (!tool) return null;
|
|
128
|
+
const dropped = isSessionRef(session) ? sessions.get(session)?.dropped.get(String(tool.name || '')) : null;
|
|
129
|
+
if (dropped) return unavailableText(dropped);
|
|
130
|
+
const exclusion = schemaExclusion(session, routeSchemaFamily(session), tool);
|
|
131
|
+
return exclusion ? unavailableText(exclusion) : null;
|
|
132
|
+
}
|
|
@@ -14,6 +14,10 @@ import {
|
|
|
14
14
|
providerNativeToolPrefixCount,
|
|
15
15
|
runWithProviderRequestToolsScope,
|
|
16
16
|
} from '../../runtime-core/provider-request-tools.mjs';
|
|
17
|
+
import { TOOL_SURFACE_MIGRATION_INTENT } from '../../runtime-core/tool-exposure.mjs';
|
|
18
|
+
import { migrateToolExposureAtBoundary } from './tool-exposure-migration.mjs';
|
|
19
|
+
import { fixedRequestOverhead, fixedRequestOverheadInputs, resolveWorkerCompactPolicy } from './compact-policy.mjs';
|
|
20
|
+
import { toolSurfaceExceedsContextError } from './context-overflow.mjs';
|
|
17
21
|
|
|
18
22
|
const isDynamicTool = (tool) =>
|
|
19
23
|
tool.deferLoading === true || tool.defer_loading === true || String(tool.name || '').startsWith('mcp__');
|
|
@@ -61,6 +65,18 @@ export async function prepareProviderRequest(state) {
|
|
|
61
65
|
let compactChanged;
|
|
62
66
|
let sendTools;
|
|
63
67
|
let requestToolScope;
|
|
68
|
+
// Fixed inputs of the last passing overhead verdict in this boundary.
|
|
69
|
+
let passedOverheadInputs;
|
|
70
|
+
// A session persisted with another tool exposure migrates here, once, at a
|
|
71
|
+
// boundary with no pending calls: new surface and fixed guidance, a fresh
|
|
72
|
+
// tool snapshot and provider state, and a tagged cache break.
|
|
73
|
+
if (migrateToolExposureAtBoundary(sessionRef, messages)) {
|
|
74
|
+
fixedProviderToolSurface = null;
|
|
75
|
+
providerState = undefined;
|
|
76
|
+
providerStateCleared = true;
|
|
77
|
+
delete sessionRef.pendingCacheBreakIntent;
|
|
78
|
+
opts.cacheBreakIntent = TOOL_SURFACE_MIGRATION_INTENT;
|
|
79
|
+
}
|
|
64
80
|
refreshDeferredMcpToolCatalog(sessionRef);
|
|
65
81
|
do {
|
|
66
82
|
// Provider-history normalization is part of the request boundary:
|
|
@@ -90,6 +106,20 @@ export async function prepareProviderRequest(state) {
|
|
|
90
106
|
requestTools: sendTools,
|
|
91
107
|
nativePrefixCount: providerNativeToolPrefixCount(sendTools),
|
|
92
108
|
};
|
|
109
|
+
// A request whose fixed overhead alone leaves no room for history fails
|
|
110
|
+
// here with an actionable error: no compaction could make it fit. A
|
|
111
|
+
// passing verdict holds while its fixed inputs (tool schemas, protected
|
|
112
|
+
// system context, headroom, boundary) are unchanged — a later pass whose
|
|
113
|
+
// compaction only removed history (and the provider reading with it) is
|
|
114
|
+
// not re-judged — but adopted MCP schema changes or a re-rooted system
|
|
115
|
+
// prompt are.
|
|
116
|
+
const overheadPolicy = resolveWorkerCompactPolicy(sessionRef, sendTools);
|
|
117
|
+
const overheadInputs = fixedRequestOverheadInputs(overheadPolicy, messages);
|
|
118
|
+
if (overheadInputs === null || overheadInputs !== passedOverheadInputs) {
|
|
119
|
+
const overhead = fixedRequestOverhead(overheadPolicy, messages, sendTools, sessionRef);
|
|
120
|
+
if (overhead) throw toolSurfaceExceedsContextError({ sessionId, sessionRef, model, overhead });
|
|
121
|
+
passedOverheadInputs = overheadInputs;
|
|
122
|
+
}
|
|
93
123
|
const pass = await runWithProviderRequestToolsScope(requestToolScope, () =>
|
|
94
124
|
runPreSendCompactPass({
|
|
95
125
|
provider,
|
|
@@ -17,6 +17,13 @@ import { stripInlineImages } from '../image-strip-recovery.mjs';
|
|
|
17
17
|
import { runWithProviderRequestToolsScope } from '../../runtime-core/provider-request-tools.mjs';
|
|
18
18
|
import { REPEAT_FAIL_LIMIT } from './loop-state.mjs';
|
|
19
19
|
import { createToolCallIdResolver } from './tool-call-ids.mjs';
|
|
20
|
+
import { captureSideQuestionRequest } from '../side-question-store.mjs';
|
|
21
|
+
import {
|
|
22
|
+
beginProviderToolExclusions,
|
|
23
|
+
dropSessionTool,
|
|
24
|
+
recordProviderToolExclusion,
|
|
25
|
+
withoutDroppedTools,
|
|
26
|
+
} from './provider-tool-exclusions.mjs';
|
|
20
27
|
|
|
21
28
|
/**
|
|
22
29
|
* Open an iteration: refresh the live cwd, drain queued steering after a
|
|
@@ -73,6 +80,8 @@ export async function beginIteration(state) {
|
|
|
73
80
|
loopUsageMetricsTurnId: state.usageMetricsTurnId,
|
|
74
81
|
loopUsageMetricsEpoch: state.usageMetricsEpoch,
|
|
75
82
|
});
|
|
83
|
+
// A tool the provider rejected with a schema 400 stays out of the session.
|
|
84
|
+
Object.assign(boundary, withoutDroppedTools(sessionRef, boundary));
|
|
76
85
|
state.iterations = boundary.iterations;
|
|
77
86
|
state.lastUsage = boundary.lastUsage;
|
|
78
87
|
state.firstTurnUsage = boundary.firstTurnUsage;
|
|
@@ -92,6 +101,10 @@ export async function beginIteration(state) {
|
|
|
92
101
|
// callers omit the flag and retain legacy live deferred resolution.
|
|
93
102
|
opts.providerToolSnapshotAuthoritative = true;
|
|
94
103
|
opts.providerNativeToolPrefixCount = boundary.requestToolScope.nativePrefixCount;
|
|
104
|
+
// A tool the provider leaves out of this request (a schema it cannot
|
|
105
|
+
// accept) is noticed once per session and refused if the model calls it.
|
|
106
|
+
beginProviderToolExclusions(sessionRef);
|
|
107
|
+
opts.onToolExcluded = (exclusion) => recordProviderToolExclusion(sessionRef, exclusion, opts.onStageChange);
|
|
95
108
|
state.lastSendTools = boundary.sendTools;
|
|
96
109
|
// Eager-dispatch queue (see ../eager-dispatch.mjs): read-only tools start
|
|
97
110
|
// the instant the provider streams a tool-call event; writes and unknown
|
|
@@ -156,26 +169,46 @@ export async function sendProviderRequest(state, round) {
|
|
|
156
169
|
try {
|
|
157
170
|
opts.onProviderSendStarted?.();
|
|
158
171
|
} catch {}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
172
|
+
// The request a /btw side question forks: kept while it is in flight, with
|
|
173
|
+
// its reply once it proceeds, and dropped again if it fails.
|
|
174
|
+
const sideQuestion = captureSideQuestionRequest({
|
|
175
|
+
sessionId,
|
|
176
|
+
sessionRef,
|
|
177
|
+
provider,
|
|
178
|
+
model,
|
|
179
|
+
messages: providerMessages,
|
|
180
|
+
tools: round.sendTools,
|
|
181
|
+
opts,
|
|
182
|
+
});
|
|
183
|
+
let result;
|
|
184
|
+
try {
|
|
185
|
+
result = await runWithProviderRequestToolsScope(round.requestToolScope, () =>
|
|
186
|
+
sendWithRecovery({
|
|
187
|
+
provider,
|
|
188
|
+
messages: providerMessages,
|
|
189
|
+
recoveryMessages: messageSource,
|
|
190
|
+
model,
|
|
191
|
+
sendTools: round.sendTools,
|
|
192
|
+
tools: round.sendTools,
|
|
193
|
+
opts,
|
|
194
|
+
sessionId,
|
|
195
|
+
sessionRef,
|
|
196
|
+
nextIteration: round.nextIteration,
|
|
197
|
+
contextOverflowRetryUsed: state.contextOverflowRetryUsed,
|
|
198
|
+
transportRetriesUsed: state.transportRetriesUsed,
|
|
199
|
+
transportRetryMax: state.transportRetryMax,
|
|
200
|
+
imageStripUsed: state.imageStripUsed,
|
|
201
|
+
thinkingReplayRepairUsed: state.thinkingReplayRepairUsed,
|
|
202
|
+
toolSchemaDropUsed: state.toolSchemaDropUsed,
|
|
203
|
+
signal: state.signal,
|
|
204
|
+
})
|
|
205
|
+
);
|
|
206
|
+
} catch (error) {
|
|
207
|
+
sideQuestion?.discard();
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
if (result.action === 'proceed') sideQuestion?.settle(result.response);
|
|
211
|
+
else sideQuestion?.discard();
|
|
179
212
|
return {
|
|
180
213
|
result,
|
|
181
214
|
providerMessages,
|
|
@@ -217,6 +250,16 @@ export function applyRetryAction(state, result) {
|
|
|
217
250
|
// transport budget is consumed: nothing was generated.
|
|
218
251
|
state.thinkingReplayRepairUsed = true;
|
|
219
252
|
return true;
|
|
253
|
+
case 'retry_tool_schema_drop':
|
|
254
|
+
// The provider named a tool whose schema it rejects: the session drops
|
|
255
|
+
// it (with the notice) and the turn is rebuilt without it, once. The
|
|
256
|
+
// frozen tool surface and provider state are rebuilt around the change.
|
|
257
|
+
state.toolSchemaDropUsed = true;
|
|
258
|
+
dropSessionTool(state.sessionRef, result.exclusion, state.opts.onStageChange);
|
|
259
|
+
state.fixedProviderToolSurface = null;
|
|
260
|
+
state.providerState = undefined;
|
|
261
|
+
state.providerStateUpdated = true;
|
|
262
|
+
return true;
|
|
220
263
|
case 'retry_image_strip':
|
|
221
264
|
state.transportRetriesUsed += 1;
|
|
222
265
|
state.imageStripUsed = true;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { resolveAutoEffort } from '../../providers/auto-effort.mjs';
|
|
17
17
|
import { isCustomProviderName, resolveCustomReasoning } from '../../providers/custom-reasoning.mjs';
|
|
18
18
|
import { autoEffortModel, stepEffortConfiguration } from '../../providers/effort-configuration.mjs';
|
|
19
|
-
import { effortOptionsFor } from '../../runtime-core/effort.mjs';
|
|
19
|
+
import { effortOptionsFor, warnEmptyAutoEffortLadder } from '../../runtime-core/effort.mjs';
|
|
20
20
|
import { judgeTurn, recordEffortDecision } from '../../../../effort-judge/judge-client.mjs';
|
|
21
21
|
import { stepResultWindow } from '../../../../effort-judge/judge-input.mjs';
|
|
22
22
|
|
|
@@ -174,6 +174,7 @@ function stepResult({ auto, snapshot, step, provider, model, providerClient, ses
|
|
|
174
174
|
ms: judged.ms,
|
|
175
175
|
probs: judged.probs.map((value) => Number(value.toFixed(3))),
|
|
176
176
|
});
|
|
177
|
+
if (!resolved) warnEmptyAutoEffortLadder(provider, model, auto.base);
|
|
177
178
|
if (isCustomProviderName(provider)) {
|
|
178
179
|
const level =
|
|
179
180
|
resolved &&
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Execution-call projection for the fixed tool bridge. A wire call
|
|
2
|
+
// `call_tool {name: T, arguments: A}` (id X) becomes the execution call
|
|
3
|
+
// `{ id: X, name: T, arguments: A, wireCall }` before eager admission and
|
|
4
|
+
// classification, so every policy, ordering, cache, hook, approval and audit
|
|
5
|
+
// layer sees the target itself. The tool result still answers wire id X and
|
|
6
|
+
// the transcript keeps the original wire call (`wireCall`, an immutable copy).
|
|
7
|
+
// Non-bridge sessions and every other call pass through unchanged.
|
|
8
|
+
import { formatInvalidToolArgsResult, isInvalidToolArgsMarker } from '../../providers/lib/openai-tool-args.mjs';
|
|
9
|
+
import {
|
|
10
|
+
BRIDGE_CALL_TOOL_NAME,
|
|
11
|
+
bridgeErrorText,
|
|
12
|
+
isToolBridgeEnabled,
|
|
13
|
+
resolveBridgeTarget,
|
|
14
|
+
} from '../../runtime-core/tool-bridge.mjs';
|
|
15
|
+
|
|
16
|
+
const CALL_TOOL_KEYS = new Set(['name', 'arguments']);
|
|
17
|
+
|
|
18
|
+
const isPlainObject = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
|
|
19
|
+
|
|
20
|
+
function deepFreeze(value) {
|
|
21
|
+
if (value && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
22
|
+
Object.freeze(value);
|
|
23
|
+
for (const key of Object.keys(value)) deepFreeze(value[key]);
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function projectionFailure(wireCall, wire, text) {
|
|
29
|
+
return { id: wireCall.id, name: wireCall.name, arguments: wireCall.arguments, wireCall: wire, bridgeError: text };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @returns the execution call for `wireCall`: the projected target call, a
|
|
34
|
+
* call carrying `bridgeError` (answered with that error, never executed),
|
|
35
|
+
* or `wireCall` itself when no projection applies. Idempotent.
|
|
36
|
+
*/
|
|
37
|
+
export function resolveExecutionToolCall(wireCall, session) {
|
|
38
|
+
if (!wireCall || wireCall.name !== BRIDGE_CALL_TOOL_NAME || wireCall.wireCall || !isToolBridgeEnabled(session)) {
|
|
39
|
+
return wireCall;
|
|
40
|
+
}
|
|
41
|
+
const wire = deepFreeze(structuredClone(wireCall));
|
|
42
|
+
const args = wireCall.arguments;
|
|
43
|
+
if (isInvalidToolArgsMarker(args)) return projectionFailure(wireCall, wire, formatInvalidToolArgsResult(wireCall));
|
|
44
|
+
if (!isPlainObject(args)) {
|
|
45
|
+
return projectionFailure(
|
|
46
|
+
wireCall,
|
|
47
|
+
wire,
|
|
48
|
+
bridgeErrorText('INVALID_ARGUMENTS', 'call_tool requires {name, arguments}.')
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
const extra = Object.keys(args).filter((key) => !CALL_TOOL_KEYS.has(key));
|
|
52
|
+
if (extra.length) {
|
|
53
|
+
return projectionFailure(
|
|
54
|
+
wireCall,
|
|
55
|
+
wire,
|
|
56
|
+
bridgeErrorText('INVALID_ARGUMENTS', `call_tool does not accept: ${extra.join(', ')}.`)
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
if (!isPlainObject(args.arguments)) {
|
|
60
|
+
return projectionFailure(
|
|
61
|
+
wireCall,
|
|
62
|
+
wire,
|
|
63
|
+
bridgeErrorText('INVALID_ARGUMENTS', 'call_tool arguments must be an object of the target tool arguments.')
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
const target = resolveBridgeTarget(session, args.name);
|
|
67
|
+
if (target.error) return projectionFailure(wireCall, wire, bridgeErrorText(target.error.code, target.error.message));
|
|
68
|
+
const call = { id: wireCall.id, name: target.name, arguments: structuredClone(args.arguments), wireCall: wire };
|
|
69
|
+
// The target definition drives read-only classification of the call; it is
|
|
70
|
+
// never serialized with the call.
|
|
71
|
+
Object.defineProperty(call, 'bridgeTool', { value: target.tool, enumerable: false });
|
|
72
|
+
return call;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function resolveExecutionToolCalls(calls, session) {
|
|
76
|
+
return Array.isArray(calls) ? calls.map((call) => resolveExecutionToolCall(call, session)) : calls;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The classification tool list for `calls`: `tools` plus the definitions of
|
|
81
|
+
* bridged targets that are not on it, so a bridged target is classified
|
|
82
|
+
* (read-only, dedup, stale-read invalidation) exactly like a direct call.
|
|
83
|
+
*/
|
|
84
|
+
export function bridgeClassificationTools(tools, calls) {
|
|
85
|
+
const base = Array.isArray(tools) ? tools : [];
|
|
86
|
+
const seen = new Set(base.map((tool) => tool?.name));
|
|
87
|
+
const extra = [];
|
|
88
|
+
for (const call of calls || []) {
|
|
89
|
+
const definition = call?.bridgeTool;
|
|
90
|
+
if (!definition || seen.has(definition.name)) continue;
|
|
91
|
+
seen.add(definition.name);
|
|
92
|
+
extra.push(definition);
|
|
93
|
+
}
|
|
94
|
+
return extra.length ? [...base, ...extra] : tools;
|
|
95
|
+
}
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { resolvePreToolAskApproval } from '../tool-helpers.mjs';
|
|
6
6
|
import { runAbortable, throwIfAborted } from '../../../../../shared/abort-race.mjs';
|
|
7
|
+
import { evaluateExecPolicy } from '../../../tools/bash-policy-scan.mjs';
|
|
7
8
|
import { beginSessionApprovalWait } from '../../manager/runtime-liveness.mjs';
|
|
8
9
|
|
|
9
10
|
const isArgsObject = (value) => value && typeof value === 'object' && !Array.isArray(value);
|
|
10
11
|
|
|
11
|
-
async function askApproval(call, { callerSessionId, executeOpts, toolApprovalHook, decision }) {
|
|
12
|
+
async function askApproval(call, { callerSessionId, executeOpts, toolApprovalHook, decision, keepArgs = false }) {
|
|
12
13
|
const askReason = String(decision?.reason || 'approval requested by hook').trim();
|
|
13
14
|
// While the user decides, the session is waiting on them, not working.
|
|
14
15
|
const releaseApprovalWait = beginSessionApprovalWait(callerSessionId);
|
|
@@ -30,10 +31,35 @@ async function askApproval(call, { callerSessionId, executeOpts, toolApprovalHoo
|
|
|
30
31
|
}
|
|
31
32
|
if (askOutcome.denial) return { denial: askOutcome.denial };
|
|
32
33
|
const approval = askOutcome.approval;
|
|
33
|
-
if (approval && typeof approval === 'object' && isArgsObject(approval.args)) call.args = approval.args;
|
|
34
|
+
if (!keepArgs && approval && typeof approval === 'object' && isArgsObject(approval.args)) call.args = approval.args;
|
|
34
35
|
return null;
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Approval gate for a shell call (or a terminal `run`) whose exec policy
|
|
40
|
+
* decision is 'ask' (elevated launch). Runs after the final call is known. The
|
|
41
|
+
* approval is granted for the exact command being asked about: an approval
|
|
42
|
+
* reply cannot rewrite the args.
|
|
43
|
+
* @returns {Promise<{ denial: string } | { elevationApproved: boolean }>}
|
|
44
|
+
*/
|
|
45
|
+
export async function applyShellElevationGate(call, { callerSessionId, executeOpts, toolApprovalHook }) {
|
|
46
|
+
const gated = call.name === 'shell' || (call.name === 'terminal' && call.args?.action === 'run');
|
|
47
|
+
if (!gated || !isArgsObject(call.args) || call.args.command == null) {
|
|
48
|
+
return { elevationApproved: false };
|
|
49
|
+
}
|
|
50
|
+
const decision = evaluateExecPolicy(String(call.args.command));
|
|
51
|
+
if (decision.decision !== 'ask') return { elevationApproved: false };
|
|
52
|
+
const denied = await askApproval(call, {
|
|
53
|
+
callerSessionId,
|
|
54
|
+
executeOpts,
|
|
55
|
+
toolApprovalHook,
|
|
56
|
+
decision,
|
|
57
|
+
keepArgs: true,
|
|
58
|
+
});
|
|
59
|
+
if (denied) return denied;
|
|
60
|
+
return { elevationApproved: true };
|
|
61
|
+
}
|
|
62
|
+
|
|
37
63
|
/**
|
|
38
64
|
* @returns {Promise<{ denial: string } | { name: string, args: any }>}
|
|
39
65
|
* the call as the hook left it, or the denial text to return instead
|
|
@@ -48,7 +74,8 @@ export async function applyBeforeToolHook({
|
|
|
48
74
|
toolApprovalHook,
|
|
49
75
|
}) {
|
|
50
76
|
const call = { name, args, cwd };
|
|
51
|
-
|
|
77
|
+
// ask_user is itself the user prompt; it never goes through the ordinary approval gate.
|
|
78
|
+
if (!beforeToolHook || name === 'ask_user') return call;
|
|
52
79
|
try {
|
|
53
80
|
const decision = await runAbortable(executeOpts.signal, () =>
|
|
54
81
|
beforeToolHook(
|