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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Deferred-pool and MCP-instruction manifests injected into BP2.
|
|
2
2
|
import { parseMcpToolName } from '../../../shared/tool-primitives.mjs';
|
|
3
|
+
import { isToolBridgeEnabled, TOOL_BRIDGE_GUIDANCE } from '../runtime-core/tool-exposure.mjs';
|
|
3
4
|
|
|
4
5
|
export function compactPromptManifestText(value, max = 250) {
|
|
5
6
|
const text = String(value || '')
|
|
@@ -13,7 +14,10 @@ export function compactPromptManifestText(value, max = 250) {
|
|
|
13
14
|
return `${cut.replace(/[\s,.;:!?/-]+$/, '')}...`;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
// The native deferred-pool manifest and the static bridge guidance occupy the
|
|
18
|
+
// same BP2 slot: one replaces the other when the exposure changes.
|
|
19
|
+
const DEFERRED_TOOLS_BLOCK_RE =
|
|
20
|
+
/(\n\n---\n*)?<(available-deferred-tools|tool-bridge)>[\s\S]*?<\/(?:available-deferred-tools|tool-bridge)>\s*/gi;
|
|
17
21
|
const MCP_INSTRUCTIONS_BLOCK_RE = /(\n\n---\n*)?<mcp-instructions>[\s\S]*?<\/mcp-instructions>\s*/gi;
|
|
18
22
|
// Tool and MCP server names enter the manifests only as plain identifiers
|
|
19
23
|
// (no markup can be smuggled into the prompt through a name).
|
|
@@ -47,6 +51,7 @@ function hasDeferredToolManifestBlock(text) {
|
|
|
47
51
|
const raw = String(text || '');
|
|
48
52
|
return (
|
|
49
53
|
/<available-deferred-tools>[\s\S]*?<\/available-deferred-tools>/i.test(raw) ||
|
|
54
|
+
/<tool-bridge>[\s\S]*?<\/tool-bridge>/i.test(raw) ||
|
|
50
55
|
/<mcp-instructions>[\s\S]*?<\/mcp-instructions>/i.test(raw)
|
|
51
56
|
);
|
|
52
57
|
}
|
|
@@ -173,11 +178,17 @@ function deferredManifestEntries(session, pool) {
|
|
|
173
178
|
}
|
|
174
179
|
|
|
175
180
|
function composeDeferredBp2Manifest(session, pool) {
|
|
181
|
+
// Bridge exposure gets the native roster and MCP instructions (the pool is
|
|
182
|
+
// already limited to what the session's policy lets it run), followed by
|
|
183
|
+
// the static bridge guidance. A tool-free bridge session gets nothing.
|
|
184
|
+
const bridge = isToolBridgeEnabled(session);
|
|
185
|
+
if (bridge && !(session.tools || []).some((tool) => tool?.name === 'call_tool')) return '';
|
|
176
186
|
const parts = [];
|
|
177
187
|
const deferredManifest = buildDeferredToolManifest(deferredManifestEntries(session, pool));
|
|
178
188
|
if (deferredManifest) parts.push(deferredManifest);
|
|
179
189
|
const mcpManifest = buildMcpInstructionsManifest(session.mcpServerInstructions, pool, session.deferredToolCatalog);
|
|
180
190
|
if (mcpManifest) parts.push(mcpManifest);
|
|
191
|
+
if (bridge) parts.push(TOOL_BRIDGE_GUIDANCE);
|
|
181
192
|
return parts.join('\n\n');
|
|
182
193
|
}
|
|
183
194
|
|
|
@@ -186,12 +197,20 @@ function markDeferredBp2Applied(session) {
|
|
|
186
197
|
delete session.deferredToolBp1Applied;
|
|
187
198
|
}
|
|
188
199
|
|
|
200
|
+
// Replace, never mutate: session-store delta saves treat stable message
|
|
201
|
+
// references as an unchanged prefix, so a rewritten prompt block must be a
|
|
202
|
+
// fresh object for the next save to persist it.
|
|
203
|
+
function setSystemContent(session, index, content) {
|
|
204
|
+
const message = session.messages[index];
|
|
205
|
+
if (message.content !== content) session.messages[index] = { ...message, content };
|
|
206
|
+
}
|
|
207
|
+
|
|
189
208
|
function clearDeferredManifestBlocks(session) {
|
|
190
|
-
|
|
209
|
+
session.messages.forEach((message, index) => {
|
|
191
210
|
if (message?.role === 'system' && typeof message.content === 'string') {
|
|
192
|
-
|
|
211
|
+
setSystemContent(session, index, stripDeferredToolManifestBlock(message.content));
|
|
193
212
|
}
|
|
194
|
-
}
|
|
213
|
+
});
|
|
195
214
|
session.messages = session.messages.filter(
|
|
196
215
|
(message) => message?.role !== 'system' || String(message.content || '').trim()
|
|
197
216
|
);
|
|
@@ -214,15 +233,15 @@ function writeDeferredManifestAt(session, idx, manifest, rebuild) {
|
|
|
214
233
|
for (let i = 0; i < session.messages.length; i++) {
|
|
215
234
|
if (i === idx || session.messages[i]?.role !== 'system' || typeof session.messages[i].content !== 'string')
|
|
216
235
|
continue;
|
|
217
|
-
session
|
|
236
|
+
setSystemContent(session, i, stripDeferredToolManifestBlock(session.messages[i].content));
|
|
218
237
|
}
|
|
219
238
|
const raw = typeof session.messages[idx].content === 'string' ? session.messages[idx].content : '';
|
|
220
239
|
if (rebuild && hasDeferredToolManifestBlock(raw)) {
|
|
221
|
-
session
|
|
240
|
+
setSystemContent(session, idx, rebuildDeferredToolManifestBlock(raw, manifest));
|
|
222
241
|
return;
|
|
223
242
|
}
|
|
224
243
|
const base = stripDeferredToolManifestBlock(raw);
|
|
225
|
-
session
|
|
244
|
+
setSystemContent(session, idx, base ? `${base}\n\n---\n\n${manifest}` : manifest);
|
|
226
245
|
}
|
|
227
246
|
|
|
228
247
|
/**
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// Skill discovery, cache, resource loading, envelopes, manifests, and the
|
|
2
2
|
// Skill meta-tool.
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
5
|
+
import { readFileSync, existsSync, readdirSync, statSync, watch as watch_ } from 'node:fs';
|
|
5
6
|
import { basename, dirname, join } from 'node:path';
|
|
6
|
-
import { maxMtimeRecursive, mtimeSignatureRecursive } from '../cache-mtime.mjs';
|
|
7
|
+
import { maxMtimeRecursive, mtimeSignatureRecursive, mtimeSignatureText } from '../cache-mtime.mjs';
|
|
7
8
|
import { mixdogHome, resolvePluginData, mixdogRoot } from '../../../shared/plugin-paths.mjs';
|
|
8
9
|
import { PLUGIN_MANIFEST_FILES, pluginSkillsRoots } from '../../../shared/plugin-manifest.mjs';
|
|
9
10
|
import {
|
|
@@ -257,6 +258,31 @@ export function isSkillDisabled(name, config = null, skills = null) {
|
|
|
257
258
|
return Boolean(skill && missingFeature(skill, featureConfig(config)));
|
|
258
259
|
}
|
|
259
260
|
|
|
261
|
+
/**
|
|
262
|
+
* `enabled` for every skill of one collectSkillsCached() snapshot, exactly as
|
|
263
|
+
* `!(isSkillDisabled(name, config, skills) || skillMissingFeature(name, config,
|
|
264
|
+
* skills))` per skill — but with ONE config read, one disabled-name set and one
|
|
265
|
+
* name index for the whole list instead of three config reads and a linear
|
|
266
|
+
* lookup per skill (the status listing blocked the event loop on them).
|
|
267
|
+
*/
|
|
268
|
+
export function skillEnabledFlags(skills, config = null) {
|
|
269
|
+
const list = Array.isArray(skills) ? skills : [];
|
|
270
|
+
const cfg = config || loadConfig({ secrets: false });
|
|
271
|
+
const disabled = getDisabledSkillNameSet(cfg);
|
|
272
|
+
const features = featureConfig(cfg);
|
|
273
|
+
const byKey = new Map();
|
|
274
|
+
for (const entry of list) {
|
|
275
|
+
const key = normalizeSkillNameKey(entry.name);
|
|
276
|
+
if (!byKey.has(key)) byKey.set(key, entry);
|
|
277
|
+
}
|
|
278
|
+
return list.map((entry) => {
|
|
279
|
+
const key = normalizeSkillNameKey(entry.name);
|
|
280
|
+
const skill = byKey.get(key);
|
|
281
|
+
if (key && !followsBuiltinFeature(skill) && disabled.has(key)) return false;
|
|
282
|
+
return !(skill && missingFeature(skill, features));
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
260
286
|
/** The built-in feature a skill needs that is not active, or null. */
|
|
261
287
|
export function skillMissingFeature(name, config = null, skills = null) {
|
|
262
288
|
const skill = findCachedSkillByKey(normalizeSkillNameKey(name), skills);
|
|
@@ -303,6 +329,81 @@ export function collectPromptSkillsCached(cwd, config = null) {
|
|
|
303
329
|
// --- Global skill cache (mtime-based) ---
|
|
304
330
|
const _skillsCache = new Map();
|
|
305
331
|
|
|
332
|
+
// Change watchers over the recursive skill roots. Re-walking every skill
|
|
333
|
+
// folder (one stat per entry) on every status/prompt read blocked the event
|
|
334
|
+
// loop for tens to hundreds of ms with a large skill set. A root whose
|
|
335
|
+
// recursive watcher has reported nothing since its last walk reuses that
|
|
336
|
+
// walk's signature text instead; any event, watcher error or explicit
|
|
337
|
+
// invalidation re-walks it. A watched root is trusted only once an event-loop
|
|
338
|
+
// turn has passed since its walk.
|
|
339
|
+
// Freshness contract: every write made through the app (addSkill, saveSkill,
|
|
340
|
+
// setDisabledSkills, reloadSkills, settings/plugin mutations, peer-runtime
|
|
341
|
+
// announcements) calls invalidateSkillsCache synchronously, which drops every
|
|
342
|
+
// watch, so the very next read re-walks and is exact. A passive edit made
|
|
343
|
+
// outside the app is eventually consistent: it is seen once the watcher
|
|
344
|
+
// delivers its event (watcher latency), or at the next explicit invalidation.
|
|
345
|
+
// Roots that cannot be watched (missing, or unsupported by the platform) and
|
|
346
|
+
// every plain-file gate path are stat'ed on every call as before.
|
|
347
|
+
const _ROOT_WATCH_LIMIT = 64;
|
|
348
|
+
const _rootWatches = new Map(); // root -> { watcher, dirty, text, settled }
|
|
349
|
+
|
|
350
|
+
function _closeRootWatch(root) {
|
|
351
|
+
const watch = _rootWatches.get(root);
|
|
352
|
+
if (!watch) return;
|
|
353
|
+
_rootWatches.delete(root);
|
|
354
|
+
try {
|
|
355
|
+
watch.watcher.close();
|
|
356
|
+
} catch {
|
|
357
|
+
/* already closed */
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function _closeAllRootWatches() {
|
|
362
|
+
for (const root of [..._rootWatches.keys()]) _closeRootWatch(root);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function _openRootWatch(root) {
|
|
366
|
+
let isDir = false;
|
|
367
|
+
try {
|
|
368
|
+
isDir = statSync(root).isDirectory();
|
|
369
|
+
} catch {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
if (!isDir) return null;
|
|
373
|
+
if (_rootWatches.size >= _ROOT_WATCH_LIMIT) _closeAllRootWatches();
|
|
374
|
+
const watch = { watcher: null, dirty: true, text: null, settled: false };
|
|
375
|
+
try {
|
|
376
|
+
// A change anywhere below drops the root's reused walk; the watcher is
|
|
377
|
+
// closed with it (a re-walk re-opens one), so a churning folder never
|
|
378
|
+
// keeps a handle on directories being deleted.
|
|
379
|
+
watch.watcher = watch_(root, { recursive: true, persistent: false }, () => _closeRootWatch(root));
|
|
380
|
+
watch.watcher.on('error', () => _closeRootWatch(root));
|
|
381
|
+
} catch {
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
_rootWatches.set(root, watch);
|
|
385
|
+
return watch;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** Signature text of one recursive gate root (see mtimeSignatureText). */
|
|
389
|
+
function _rootSignatureText(root) {
|
|
390
|
+
const current = _rootWatches.get(root);
|
|
391
|
+
if (current && !current.dirty && current.settled) return current.text;
|
|
392
|
+
// Open the watcher BEFORE the walk: a change racing the walk then either
|
|
393
|
+
// shows in it or arrives as an event that drops the reused text.
|
|
394
|
+
const watch = current || _openRootWatch(root);
|
|
395
|
+
const text = mtimeSignatureText([root]);
|
|
396
|
+
if (watch && _rootWatches.get(root) === watch) {
|
|
397
|
+
watch.text = text;
|
|
398
|
+
watch.dirty = false;
|
|
399
|
+
watch.settled = false;
|
|
400
|
+
setImmediate(() => {
|
|
401
|
+
if (_rootWatches.get(root) === watch && watch.text === text) watch.settled = true;
|
|
402
|
+
}).unref?.();
|
|
403
|
+
}
|
|
404
|
+
return text;
|
|
405
|
+
}
|
|
406
|
+
|
|
306
407
|
export function collectSkillsCached(cwd) {
|
|
307
408
|
if (skillsDisabled()) return [];
|
|
308
409
|
void cwd;
|
|
@@ -313,12 +414,15 @@ export function collectSkillsCached(cwd) {
|
|
|
313
414
|
skillsDirs.push(...pluginSkillDirs().map(({ dir }) => dir), ...builtinSkillDirs());
|
|
314
415
|
// registry.json itself gates plugin add/remove: removal deletes the
|
|
315
416
|
// plugin's skills dir (so no dir mtime advances), but saveRegistry()
|
|
316
|
-
// always rewrites this file.
|
|
417
|
+
// always rewrites this file. It is a plain file: stat'ed directly.
|
|
317
418
|
const registryPath = pluginRegistryPath();
|
|
318
|
-
|
|
319
|
-
//
|
|
320
|
-
// manifest edits and skill roots that do not
|
|
321
|
-
|
|
419
|
+
// Exact gate: unwatched roots and plain files are stat'ed every call; a
|
|
420
|
+
// watched root reuses its last walk only while its watcher stayed quiet.
|
|
421
|
+
// The shallow watch list covers manifest edits and skill roots that do not
|
|
422
|
+
// exist yet.
|
|
423
|
+
const rootTexts = skillsDirs.map((dir) => _rootSignatureText(dir));
|
|
424
|
+
if (registryPath) rootTexts.push(mtimeSignatureText([registryPath]));
|
|
425
|
+
const signature = `${createHash('sha1').update(rootTexts.join('\n')).digest('hex')}|${mtimeSignatureRecursive(pluginShallowWatchPaths(), 0)}`;
|
|
322
426
|
const entry = _skillsCache.get(key);
|
|
323
427
|
if (entry && entry.signature === signature) {
|
|
324
428
|
return entry.value;
|
|
@@ -331,6 +435,7 @@ export function collectSkillsCached(cwd) {
|
|
|
331
435
|
export function invalidateSkillsCache(cwd) {
|
|
332
436
|
void cwd;
|
|
333
437
|
_skillsCache.clear();
|
|
438
|
+
_closeAllRootWatches();
|
|
334
439
|
}
|
|
335
440
|
|
|
336
441
|
/**
|
|
@@ -16,10 +16,12 @@ import { fastModeAvailable } from './anthropic-fast-mode.mjs';
|
|
|
16
16
|
import { applyAnthropicEffortToBody, shouldIncludeEffortBeta } from './anthropic-effort.mjs';
|
|
17
17
|
import { isCustomProviderName, resolveCustomReasoning } from './custom-reasoning.mjs';
|
|
18
18
|
import {
|
|
19
|
+
anthropicThinkingActive,
|
|
19
20
|
applyAnthropicCacheMarkers,
|
|
20
21
|
clampAnthropicThinkingBudget as clampThinkingBudgetTokens,
|
|
21
22
|
resolveAnthropicCacheTtls as resolveCacheTtls,
|
|
22
23
|
resolveAnthropicMessageCacheSlots,
|
|
24
|
+
sharedCachePrefixBoundary,
|
|
23
25
|
toAnthropicToolChoice,
|
|
24
26
|
} from './lib/anthropic-request-utils.mjs';
|
|
25
27
|
import {
|
|
@@ -54,17 +56,21 @@ export async function buildAnthropicApiRequest({
|
|
|
54
56
|
opts,
|
|
55
57
|
fastModeLatched,
|
|
56
58
|
modelInfo = null,
|
|
59
|
+
// The Claude id a gateway slug stands for (OpenRouter `anthropic/claude-opus-4.8`
|
|
60
|
+
// → `claude-opus-4.8`): the output cap and the thinking/effort shape are read
|
|
61
|
+
// from it, while the wire still names `useModel`.
|
|
62
|
+
capabilityModel = useModel,
|
|
63
|
+
// A gateway-supplied output limit for the model; wins over the Anthropic catalog.
|
|
64
|
+
modelMaxOutputTokens = opts?.modelMaxOutputTokens ?? null,
|
|
57
65
|
}) {
|
|
58
66
|
// A user-defined provider's reasoning comes from its own model row only:
|
|
59
67
|
// the global by-model-id capability index and the Claude-id ladders are
|
|
60
68
|
// first-party knowledge and must not leak onto (or from) a custom endpoint.
|
|
61
69
|
const isCustom = isCustomProviderName(name);
|
|
62
|
-
const maxTokens = resolveMaxTokens(
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
disableBetaHeaders: config?.disableBetaHeaders,
|
|
67
|
-
});
|
|
70
|
+
const maxTokens = resolveMaxTokens(capabilityModel, { modelMaxOutputTokens });
|
|
71
|
+
const effortOptions = { ...config, ...opts, disableBetaHeaders: config?.disableBetaHeaders };
|
|
72
|
+
const gatewayEffort = typeof config?.messagesEffort === 'function' ? config.messagesEffort(opts) : null;
|
|
73
|
+
const effortProjection = projectEffortConfiguration(messages, name, useModel, effortOptions);
|
|
68
74
|
const ttls = resolveCacheTtls(opts);
|
|
69
75
|
|
|
70
76
|
const systemMsgs = messages.filter((m) => m.role === 'system');
|
|
@@ -73,20 +79,29 @@ export async function buildAnthropicApiRequest({
|
|
|
73
79
|
// (cacheTier:'tier3') at ttls.tier3 — each its own system content block.
|
|
74
80
|
const systemBlocks = buildSystemBlocks(systemMsgs, ttls.system, ttls.tier3);
|
|
75
81
|
|
|
76
|
-
// Message-tail cache budget (4-BP layout + ANTHROPIC_MSG_SLOTS) is
|
|
77
|
-
// shared with anthropic-oauth — see resolveAnthropicMessageCacheSlots.
|
|
78
|
-
const messageCacheSlots = resolveAnthropicMessageCacheSlots(systemBlocks, ttls);
|
|
79
82
|
// Tools are resolved BEFORE the messages: the lowering needs the final
|
|
80
83
|
// tool list to drop tool_reference blocks whose tool no longer ships
|
|
81
84
|
// in this request (otherwise the API rejects the whole turn).
|
|
82
|
-
const requestTools = requestAnthropicTools(tools, chatMsgs, opts);
|
|
85
|
+
const requestTools = requestAnthropicTools(tools, chatMsgs, opts, name);
|
|
86
|
+
// Message-tail cache budget (4-BP layout + ANTHROPIC_MSG_SLOTS) is
|
|
87
|
+
// shared with anthropic-oauth — see resolveAnthropicMessageCacheSlots.
|
|
88
|
+
const messageCacheSlots = resolveAnthropicMessageCacheSlots(systemBlocks, ttls, { tools: requestTools });
|
|
83
89
|
// Build → sanitize (once, inside toAnthropicMessages) → mark. Markers
|
|
84
90
|
// are applied to the FINAL sanitized array by invariant, so block
|
|
85
91
|
// drops / inserts / reorders performed by the sanitizer can never move
|
|
86
92
|
// or delete a marked block. NEVER sanitize again after this.
|
|
93
|
+
const lowerHistory = (history, projection) =>
|
|
94
|
+
lowerAnthropicEffortHistory(
|
|
95
|
+
history.filter((m) => m.role !== 'system'),
|
|
96
|
+
(segment) => toAnthropicMessages(segment, requestTools, name),
|
|
97
|
+
projection
|
|
98
|
+
);
|
|
87
99
|
const anthropicMessages = applyAnthropicCacheMarkers(
|
|
88
|
-
|
|
89
|
-
messageCacheSlots
|
|
100
|
+
lowerHistory(chatMsgs, effortProjection),
|
|
101
|
+
messageCacheSlots,
|
|
102
|
+
sharedCachePrefixBoundary(messages, opts, (prefix) =>
|
|
103
|
+
lowerHistory(prefix, projectEffortConfiguration(prefix, name, useModel, effortOptions))
|
|
104
|
+
)
|
|
90
105
|
);
|
|
91
106
|
|
|
92
107
|
const params = {
|
|
@@ -108,10 +123,9 @@ export async function buildAnthropicApiRequest({
|
|
|
108
123
|
// tool_choice only when tools are actually present (Anthropic rejects
|
|
109
124
|
// tool_choice without tools). 'none' rides the hard-cap final turn to
|
|
110
125
|
// forbid tool USE while keeping the tools prefix stable for cache reuse.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
126
|
+
// The key is reserved here (wire key order) and resolved once thinking is
|
|
127
|
+
// known: forced any/tool is invalid while thinking is enabled.
|
|
128
|
+
if (params.tools) params.tool_choice = undefined;
|
|
115
129
|
const hasDeferredTools = Array.isArray(params.tools) && params.tools.some((tool) => tool?.defer_loading === true);
|
|
116
130
|
// Known tool names for the shared parseSSEStream leaked-tool-call guard
|
|
117
131
|
// (same guard fixes both Anthropic providers). Recovered leaked calls
|
|
@@ -129,16 +143,30 @@ export async function buildAnthropicApiRequest({
|
|
|
129
143
|
});
|
|
130
144
|
if (fields.thinking) params.thinking = fields.thinking;
|
|
131
145
|
if (fields.output_config) params.output_config = { ...(params.output_config || {}), ...fields.output_config };
|
|
132
|
-
} else {
|
|
146
|
+
} else if (gatewayEffort !== 'none') {
|
|
147
|
+
// A gateway's own reasoning control (`messagesEffort`) replaces the turn
|
|
148
|
+
// effort; 'none' sends no thinking at all.
|
|
149
|
+
const turnOpts = effortProjection ? { ...opts, effort: effortProjection.initialEffort } : opts;
|
|
133
150
|
applyAnthropicEffortToBody(params, {
|
|
134
|
-
model:
|
|
135
|
-
opts:
|
|
151
|
+
model: capabilityModel,
|
|
152
|
+
opts: gatewayEffort ? { ...turnOpts, effort: gatewayEffort } : turnOpts,
|
|
136
153
|
maxTokens,
|
|
137
154
|
clampThinkingBudgetTokens,
|
|
138
155
|
logTag: name,
|
|
139
156
|
progressUpdates: config?.disableBetaHeaders !== true,
|
|
140
157
|
});
|
|
141
158
|
}
|
|
159
|
+
if (params.tools) {
|
|
160
|
+
const toolChoice = toAnthropicToolChoice(opts.toolChoice, {
|
|
161
|
+
thinking: anthropicThinkingActive(params),
|
|
162
|
+
disableParallelToolUse: opts.disableParallelToolUse === true,
|
|
163
|
+
// A gateway that cannot honour disable_parallel_tool_use declares so.
|
|
164
|
+
supportsDisableParallelToolUse: config?.supportsDisableParallelToolUse !== false,
|
|
165
|
+
onThinkingConflict: opts.toolChoiceThinkingConflict,
|
|
166
|
+
});
|
|
167
|
+
if (toolChoice) params.tool_choice = toolChoice;
|
|
168
|
+
else delete params.tool_choice;
|
|
169
|
+
}
|
|
142
170
|
// Fast mode → speed: "fast" on models Anthropic marks as speed-capable.
|
|
143
171
|
// Suppressed while the fast capacity pool is cooling down.
|
|
144
172
|
let fastLatched = fastModeLatched;
|
|
@@ -169,7 +197,7 @@ export async function buildAnthropicApiRequest({
|
|
|
169
197
|
fastMode: fastLatched,
|
|
170
198
|
toolSearch: hasDeferredTools,
|
|
171
199
|
// Custom: the beta follows the resolver's output, not the model id.
|
|
172
|
-
effort: isCustom ? Boolean(params.output_config?.effort) : shouldIncludeEffortBeta(
|
|
200
|
+
effort: isCustom ? Boolean(params.output_config?.effort) : shouldIncludeEffortBeta(capabilityModel, opts),
|
|
173
201
|
serverFallback: params.fallbacks === 'default',
|
|
174
202
|
thinkingDisplayUpdates: params.thinking?.display === 'updates',
|
|
175
203
|
}),
|
|
@@ -25,9 +25,11 @@ const STATUS_ERROR_TYPE = new Map([
|
|
|
25
25
|
[401, 'authentication_error'],
|
|
26
26
|
[403, 'permission_error'],
|
|
27
27
|
[404, 'not_found_error'],
|
|
28
|
+
[409, 'conflict_error'],
|
|
28
29
|
[413, REQUEST_TOO_LARGE],
|
|
29
30
|
[429, 'rate_limit_error'],
|
|
30
31
|
[500, 'api_error'],
|
|
32
|
+
[504, 'timeout_error'],
|
|
31
33
|
[529, 'overloaded_error'],
|
|
32
34
|
]);
|
|
33
35
|
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
//
|
|
5
5
|
// Resolution order:
|
|
6
6
|
// 1. MIXDOG_ANTHROPIC_MAX_OUTPUT_TOKENS env override, if set to a positive
|
|
7
|
-
// int, wins
|
|
7
|
+
// int, wins, capped by the known model maximum when there is one.
|
|
8
8
|
// 2. Catalog outputTokens for the model id (trusted over hardcoded
|
|
9
9
|
// heuristics when present — the API reports real per-model limits),
|
|
10
|
-
// clamped to
|
|
10
|
+
// clamped to safetyCap (never raised: a declared limit is a ceiling).
|
|
11
11
|
// 3. The shared model catalog's outputTokens for the model (cached roster /
|
|
12
12
|
// LiteLLM / models.dev), same clamp.
|
|
13
13
|
// 4. The pre-catalog family limits for a model no catalog describes, else
|
|
@@ -62,21 +62,28 @@ function sharedCatalogOutputTokens(model) {
|
|
|
62
62
|
// catalogLookup(model) -> number|null. Providers supply their own strategy
|
|
63
63
|
// for sourcing the catalog array (in-memory mirror + disk fallback for OAuth,
|
|
64
64
|
// plain disk read for the API-key twin — see anthropic.mjs).
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
//
|
|
66
|
+
// `modelMaxOutputTokens` (number|null): a gateway-supplied model limit. When
|
|
67
|
+
// positive it takes precedence over every catalog lookup. A declared model
|
|
68
|
+
// maximum is a ceiling: it is never raised to the floor, and the env override
|
|
69
|
+
// is capped by it.
|
|
70
|
+
export function resolveAnthropicMaxTokens(model, { catalogLookup, modelMaxOutputTokens = null } = {}) {
|
|
71
|
+
const isLimit = (value) => Number.isFinite(value) && value > 0;
|
|
72
|
+
let declared = Number(modelMaxOutputTokens);
|
|
73
|
+
if (!isLimit(declared)) {
|
|
74
|
+
declared = null;
|
|
75
|
+
if (typeof catalogLookup === 'function') {
|
|
76
|
+
try {
|
|
77
|
+
declared = catalogLookup(model);
|
|
78
|
+
} catch {
|
|
79
|
+
declared = null;
|
|
80
|
+
}
|
|
75
81
|
}
|
|
82
|
+
if (!isLimit(declared)) declared = sharedCatalogOutputTokens(model);
|
|
76
83
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return Math.min(fallbackAnthropicMaxTokens(model),
|
|
84
|
+
declared = isLimit(declared) ? Math.floor(declared) : null;
|
|
85
|
+
const envOverride = envAnthropicMaxOutputOverride();
|
|
86
|
+
if (envOverride != null) return declared == null ? envOverride : Math.min(envOverride, declared);
|
|
87
|
+
if (declared != null) return Math.min(declared, DEFAULT_SAFETY_CAP);
|
|
88
|
+
return Math.min(fallbackAnthropicMaxTokens(model), DEFAULT_SAFETY_CAP);
|
|
82
89
|
}
|
|
@@ -131,8 +131,8 @@ function _catalogOutputTokensFromSharedCache(model) {
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
export function resolveMaxTokens(model) {
|
|
135
|
-
return resolveAnthropicMaxTokens(model, { catalogLookup: _catalogOutputTokensFromSharedCache });
|
|
134
|
+
export function resolveMaxTokens(model, { modelMaxOutputTokens = null } = {}) {
|
|
135
|
+
return resolveAnthropicMaxTokens(model, { catalogLookup: _catalogOutputTokensFromSharedCache, modelMaxOutputTokens });
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
// Test-only escape hatch for the provider contract scripts
|
|
@@ -144,11 +144,12 @@ export const _test = {
|
|
|
144
144
|
sanitizeInputSchema: (schema, toolName) => sanitizeAnthropicInputSchema(schema, toolName, 'anthropic'),
|
|
145
145
|
};
|
|
146
146
|
|
|
147
|
-
function deferredAnthropicTools(activeTools, messages, opts) {
|
|
148
|
-
return sharedDeferredAnthropicTools(activeTools, messages, opts,
|
|
147
|
+
function deferredAnthropicTools(activeTools, messages, opts, provider = 'anthropic') {
|
|
148
|
+
return sharedDeferredAnthropicTools(activeTools, messages, opts, provider);
|
|
149
149
|
}
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
// `provider`: the engine's name (a gateway Messages engine runs under its gateway's).
|
|
151
|
+
export function requestAnthropicTools(tools, messages, opts, provider = 'anthropic') {
|
|
152
|
+
return sharedRequestAnthropicTools(tools, messages, opts, provider);
|
|
152
153
|
}
|
|
153
154
|
// Test-only: expose the lowering so the steering-provenance test can assert
|
|
154
155
|
// the API-key provider keeps steering-tagged user turns distinct (mirrors
|
|
@@ -10,7 +10,7 @@ import { createNpmVersionSource, maxSemver } from './npm-cli-version.mjs';
|
|
|
10
10
|
// source release just to advance the user-agent version.
|
|
11
11
|
// Claude Opus 5.5 requires 2.1.280 or newer. The release workflow raises this
|
|
12
12
|
// to the published CLI version (scripts/sync-client-version-floors.mjs).
|
|
13
|
-
export const DEFAULT_CLI_VERSION = '2.1.
|
|
13
|
+
export const DEFAULT_CLI_VERSION = '2.1.301';
|
|
14
14
|
export const CLAUDE_CLI_NPM_PACKAGE = '@anthropic-ai/claude-code';
|
|
15
15
|
|
|
16
16
|
const CACHE_SCHEMA_VERSION = 1;
|
|
@@ -55,6 +55,7 @@ import { applyAnthropicEffortToBody, shouldIncludeEffortBeta } from './anthropic
|
|
|
55
55
|
import { ANTHROPIC_EFFORT_LEVELS, withEffortRejectionFallback } from './effort-rejection.mjs';
|
|
56
56
|
import { getLlmDispatcher, preconnect } from '../../../shared/llm/http-agent.mjs';
|
|
57
57
|
import {
|
|
58
|
+
anthropicThinkingActive,
|
|
58
59
|
applyAnthropicCacheMarkers,
|
|
59
60
|
clampAnthropicThinkingBudget as clampThinkingBudgetTokens,
|
|
60
61
|
deferredAnthropicTools as sharedDeferredAnthropicTools,
|
|
@@ -62,6 +63,7 @@ import {
|
|
|
62
63
|
resolveAnthropicCacheTtls as resolveCacheTtls,
|
|
63
64
|
resolveAnthropicMessageCacheSlots,
|
|
64
65
|
sanitizeAnthropicInputSchema,
|
|
66
|
+
sharedCachePrefixBoundary,
|
|
65
67
|
toAnthropicMessages,
|
|
66
68
|
toAnthropicToolChoice,
|
|
67
69
|
} from './lib/anthropic-request-utils.mjs';
|
|
@@ -168,8 +170,8 @@ function buildSystemBlocks(systemMsgs, systemTtl, tier3Ttl) {
|
|
|
168
170
|
// clamped to [MAX_TOKENS_FLOOR, safetyCap].
|
|
169
171
|
// 3. Shared model catalog outputTokens, then the floor, when the live
|
|
170
172
|
// roster has no entry for this model.
|
|
171
|
-
function resolveMaxTokens(model) {
|
|
172
|
-
return resolveAnthropicMaxTokens(model, { catalogLookup: _catalogOutputTokens });
|
|
173
|
+
function resolveMaxTokens(model, { modelMaxOutputTokens = null } = {}) {
|
|
174
|
+
return resolveAnthropicMaxTokens(model, { catalogLookup: _catalogOutputTokens, modelMaxOutputTokens });
|
|
173
175
|
}
|
|
174
176
|
|
|
175
177
|
// --- Message conversion ---
|
|
@@ -191,8 +193,8 @@ function requestAnthropicTools(tools, messages, opts) {
|
|
|
191
193
|
function buildRequestBody(messages, model, tools, sendOpts) {
|
|
192
194
|
const systemMsgs = messages.filter((m) => m.role === 'system');
|
|
193
195
|
const chatMsgs = messages.filter((m) => m.role !== 'system');
|
|
194
|
-
const maxTokens = resolveMaxTokens(model);
|
|
195
196
|
const opts = sendOpts || {};
|
|
197
|
+
const maxTokens = resolveMaxTokens(model, { modelMaxOutputTokens: opts.modelMaxOutputTokens });
|
|
196
198
|
const effortProjection = projectEffortConfiguration(messages, 'anthropic-oauth', model, opts);
|
|
197
199
|
const ttls = resolveCacheTtls(opts);
|
|
198
200
|
// Each system message becomes its own Anthropic content block with its own
|
|
@@ -202,18 +204,27 @@ function buildRequestBody(messages, model, tools, sendOpts) {
|
|
|
202
204
|
|
|
203
205
|
// Message-tail cache budget (4-BP layout + ANTHROPIC_MSG_SLOTS) is shared
|
|
204
206
|
// with anthropic.mjs — see resolveAnthropicMessageCacheSlots.
|
|
205
|
-
const messageCacheSlots = resolveAnthropicMessageCacheSlots(systemBlocks, ttls);
|
|
206
207
|
// Tools are resolved BEFORE the messages: the lowering needs the final
|
|
207
208
|
// tool list to drop tool_reference blocks whose tool no longer ships in
|
|
208
209
|
// this request (otherwise the API rejects the whole turn).
|
|
209
210
|
const requestTools = requestAnthropicTools(tools, chatMsgs, opts);
|
|
211
|
+
const messageCacheSlots = resolveAnthropicMessageCacheSlots(systemBlocks, ttls, { tools: requestTools });
|
|
210
212
|
// Build → sanitize (once, inside toAnthropicMessages) → mark. Markers are
|
|
211
213
|
// applied to the FINAL sanitized array by invariant, so block drops /
|
|
212
214
|
// inserts / reorders performed by the sanitizer can never move or delete a
|
|
213
215
|
// marked block. NEVER sanitize again after this (see send path).
|
|
216
|
+
const lowerHistory = (history, projection) =>
|
|
217
|
+
lowerAnthropicEffortHistory(
|
|
218
|
+
history.filter((m) => m.role !== 'system'),
|
|
219
|
+
(segment) => toAnthropicMessages(segment, requestTools),
|
|
220
|
+
projection
|
|
221
|
+
);
|
|
214
222
|
const anthropicMessages = applyAnthropicCacheMarkers(
|
|
215
|
-
|
|
216
|
-
messageCacheSlots
|
|
223
|
+
lowerHistory(chatMsgs, effortProjection),
|
|
224
|
+
messageCacheSlots,
|
|
225
|
+
sharedCachePrefixBoundary(messages, opts, (prefix) =>
|
|
226
|
+
lowerHistory(prefix, projectEffortConfiguration(prefix, 'anthropic-oauth', model, opts))
|
|
227
|
+
)
|
|
217
228
|
);
|
|
218
229
|
|
|
219
230
|
const body = {
|
|
@@ -238,10 +249,8 @@ function buildRequestBody(messages, model, tools, sendOpts) {
|
|
|
238
249
|
// tool_choice only when tools are actually present (Anthropic rejects
|
|
239
250
|
// tool_choice without tools). 'none' rides the hard-cap final turn to
|
|
240
251
|
// forbid tool USE while keeping the tools prefix stable for cache reuse.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
if (toolChoice) body.tool_choice = toolChoice;
|
|
244
|
-
}
|
|
252
|
+
// Key reserved for wire order; resolved after thinking is applied.
|
|
253
|
+
if (body.tools) body.tool_choice = undefined;
|
|
245
254
|
|
|
246
255
|
applyAnthropicEffortToBody(body, {
|
|
247
256
|
model,
|
|
@@ -252,6 +261,16 @@ function buildRequestBody(messages, model, tools, sendOpts) {
|
|
|
252
261
|
progressUpdates: true,
|
|
253
262
|
});
|
|
254
263
|
|
|
264
|
+
if (body.tools) {
|
|
265
|
+
const toolChoice = toAnthropicToolChoice(opts.toolChoice, {
|
|
266
|
+
thinking: anthropicThinkingActive(body),
|
|
267
|
+
disableParallelToolUse: opts.disableParallelToolUse === true,
|
|
268
|
+
onThinkingConflict: opts.toolChoiceThinkingConflict,
|
|
269
|
+
});
|
|
270
|
+
if (toolChoice) body.tool_choice = toolChoice;
|
|
271
|
+
else delete body.tool_choice;
|
|
272
|
+
}
|
|
273
|
+
|
|
255
274
|
// Skipped while the fast capacity pool is in cooldown (or permanently
|
|
256
275
|
// unavailable) so a drained pool is not re-probed every turn.
|
|
257
276
|
if (opts.fast === true && supportsAnthropicFastMode(model) && fastModeAvailable()) {
|
|
@@ -36,6 +36,20 @@ export function createTurnBlocks() {
|
|
|
36
36
|
const appendText = (index, chunk) => {
|
|
37
37
|
text.set(index, (text.get(index) || '') + (chunk || ''));
|
|
38
38
|
};
|
|
39
|
+
// Per-index citations of a text block (content_block_start `citations` plus
|
|
40
|
+
// streamed citations_delta), replayed verbatim on the text block they cite.
|
|
41
|
+
const citations = new Map();
|
|
42
|
+
const appendCitation = (index, citation) => {
|
|
43
|
+
if (!citation || typeof citation !== 'object') return;
|
|
44
|
+
if (!text.has(index)) text.set(index, '');
|
|
45
|
+
let copy;
|
|
46
|
+
try {
|
|
47
|
+
copy = structuredClone(citation);
|
|
48
|
+
} catch {
|
|
49
|
+
copy = { ...citation };
|
|
50
|
+
}
|
|
51
|
+
citations.set(index, [...(citations.get(index) || []), copy]);
|
|
52
|
+
};
|
|
39
53
|
// Client tool_use blocks that were actually dispatched, kept for the same
|
|
40
54
|
// ordered replay list (deduped/skipped calls are intentionally absent).
|
|
41
55
|
const clientToolUse = new Map();
|
|
@@ -61,7 +75,11 @@ export function createTurnBlocks() {
|
|
|
61
75
|
...thinking.entries(),
|
|
62
76
|
...[...text.entries()].map(([index, value]) => [
|
|
63
77
|
index,
|
|
64
|
-
{
|
|
78
|
+
{
|
|
79
|
+
type: 'text',
|
|
80
|
+
text: typeof value === 'string' ? value : '',
|
|
81
|
+
...(citations.get(index)?.length ? { citations: citations.get(index) } : {}),
|
|
82
|
+
},
|
|
65
83
|
]),
|
|
66
84
|
...completedNativeBlocks(),
|
|
67
85
|
...clientToolUse.entries(),
|
|
@@ -105,6 +123,7 @@ export function createTurnBlocks() {
|
|
|
105
123
|
pendingToolInputs,
|
|
106
124
|
clientToolUse,
|
|
107
125
|
appendText,
|
|
126
|
+
appendCitation,
|
|
108
127
|
toolInputInFlight,
|
|
109
128
|
orderedThinkingBlocks,
|
|
110
129
|
orderedAssistantBlocks,
|
|
@@ -88,14 +88,27 @@ export function createContentBlockDelta({ turn, blocks, state, leak, relayText,
|
|
|
88
88
|
progress('tool');
|
|
89
89
|
};
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
const stampTtft = () => {
|
|
92
|
+
if (state && !state.ttftAt) state.ttftAt = Date.now();
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const onContentBlockDelta = (index, delta) => {
|
|
92
96
|
if (delta?.type) turn.contentBlockTypes.add(delta.type);
|
|
93
97
|
// Time-to-first-token: stamp the first content delta (text / thinking /
|
|
94
98
|
// tool input_json) exactly once so the SSE trace can separate first-byte
|
|
95
99
|
// latency from total stream/generation time.
|
|
96
|
-
|
|
100
|
+
stampTtft();
|
|
97
101
|
if (delta?.type === 'text_delta') onTextDelta(index, delta.text);
|
|
102
|
+
if (delta?.type === 'citations_delta') blocks.appendCitation(index, delta.citation);
|
|
98
103
|
if (delta?.type === 'thinking_delta' || delta?.type === 'signature_delta') onThinkingDelta(index, delta);
|
|
99
104
|
if (delta?.type === 'input_json_delta') onInputJsonDelta(index, delta.partial_json);
|
|
100
105
|
};
|
|
106
|
+
// A text block may open with non-empty `text` on content_block_start: it is
|
|
107
|
+
// model output and takes the same path as a text_delta (live relay, leak
|
|
108
|
+
// guard, returned content, ordered replay copy).
|
|
109
|
+
onContentBlockDelta.seedText = (index, initialText) => {
|
|
110
|
+
stampTtft();
|
|
111
|
+
onTextDelta(index, initialText);
|
|
112
|
+
};
|
|
113
|
+
return onContentBlockDelta;
|
|
101
114
|
}
|