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
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// Shared by openai-compat-responses-native.test.mjs and the one-off generator
|
|
2
|
+
// that produced openai-compat-responses-head-parity.json by running these same
|
|
3
|
+
// captures against the pre-change (HEAD) converters.
|
|
4
|
+
import { sendCompatResponses } from './openai-compat-responses.mjs';
|
|
5
|
+
import { OpenAICompatProvider } from './openai-compat.mjs';
|
|
6
|
+
import { buildRequestBody } from './openai-responses-payload.mjs';
|
|
7
|
+
import { createProviderReplay } from './lib/provider-replay.mjs';
|
|
8
|
+
|
|
9
|
+
export const SERVER_CALL = {
|
|
10
|
+
type: 'tool_search_call',
|
|
11
|
+
id: 'ts_srv',
|
|
12
|
+
call_id: null,
|
|
13
|
+
execution: 'server',
|
|
14
|
+
arguments: { query: 'q' },
|
|
15
|
+
};
|
|
16
|
+
export const SERVER_OUTPUT = { type: 'tool_search_output', id: 'tso_srv', call_id: null, execution: 'server', tools: [] };
|
|
17
|
+
export const REPLY = { type: 'message', role: 'assistant', content: [{ type: 'output_text', text: 'ok' }] };
|
|
18
|
+
|
|
19
|
+
export const ROUTES = [
|
|
20
|
+
['opencode-go', 'gpt-5.5'],
|
|
21
|
+
['muse-code', 'muse-spark'],
|
|
22
|
+
['command-code', 'gpt-5.5'],
|
|
23
|
+
['custom-cmd', 'openai/gpt-5.6-sol'],
|
|
24
|
+
['openrouter', 'openai/gpt-5.5'],
|
|
25
|
+
['xai', 'grok-4'],
|
|
26
|
+
['opencode-go', 'grok-4'],
|
|
27
|
+
];
|
|
28
|
+
export const FIRST_PARTY = [
|
|
29
|
+
['openai', 'gpt-5.5'],
|
|
30
|
+
['openai-oauth', 'gpt-5.5'],
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
export const replayOwner = (name) => `compat-responses:${name}`;
|
|
34
|
+
|
|
35
|
+
const search = (name) => ({
|
|
36
|
+
provider: name,
|
|
37
|
+
openaiTools: [{ type: 'function', name: 'x', description: 'd', parameters: { type: 'object', properties: {} } }],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export function nativeHistory() {
|
|
41
|
+
return [
|
|
42
|
+
{ role: 'user', content: 'go' },
|
|
43
|
+
{
|
|
44
|
+
role: 'assistant',
|
|
45
|
+
content: '',
|
|
46
|
+
toolCalls: [
|
|
47
|
+
{ id: 'ts1', name: 'load_tool', arguments: { names: ['x'] }, nativeType: 'tool_search_call' },
|
|
48
|
+
{ id: 'cu1', name: 'apply_patch', arguments: { patch: 'P' }, nativeType: 'custom_tool_call' },
|
|
49
|
+
{ id: 'fn1', name: 'Read', arguments: { path: 'a' } },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
{ role: 'tool', toolCallId: 'ts1', content: 'loaded' },
|
|
53
|
+
{ role: 'tool', toolCallId: 'cu1', content: 'patched' },
|
|
54
|
+
{ role: 'tool', toolCallId: 'fn1', content: 'file' },
|
|
55
|
+
{ role: 'user', content: 'next' },
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Left by a previous openai-oauth route: native search/custom calls, native
|
|
60
|
+
// search results carrying loaded tools, phase-tagged assistant turns, a Skill
|
|
61
|
+
// result with loadable tools, and a foreign openai-responses replay.
|
|
62
|
+
export function oauthHistory() {
|
|
63
|
+
return [
|
|
64
|
+
{ role: 'system', content: 'sys' },
|
|
65
|
+
{ role: 'user', content: 'go' },
|
|
66
|
+
{ role: 'assistant', content: 'working', phase: 'commentary', toolCalls: [] },
|
|
67
|
+
{
|
|
68
|
+
role: 'assistant',
|
|
69
|
+
content: 'looking',
|
|
70
|
+
phase: 'commentary',
|
|
71
|
+
reasoningItems: [{ id: 'rs', encrypted_content: 'ENC', summary: [] }],
|
|
72
|
+
toolCalls: [
|
|
73
|
+
{ id: 'ts1', name: 'load_tool', arguments: { names: ['x'] }, nativeType: 'tool_search_call' },
|
|
74
|
+
{ id: 'cu1', name: 'apply_patch', arguments: { patch: 'P' }, nativeType: 'custom_tool_call' },
|
|
75
|
+
{ id: 'sk1', name: 'Skill', arguments: { name: 's' } },
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
{ role: 'tool', toolCallId: 'ts1', content: 'loaded', nativeToolSearch: search('openai-oauth') },
|
|
79
|
+
{ role: 'tool', toolCallId: 'cu1', content: 'patched' },
|
|
80
|
+
{ role: 'tool', toolCallId: 'sk1', content: 'skill', nativeToolSearch: search('openai-oauth') },
|
|
81
|
+
{
|
|
82
|
+
role: 'assistant',
|
|
83
|
+
content: '',
|
|
84
|
+
toolCalls: [{ id: 'f2', name: 'Read', arguments: { path: 'a' } }],
|
|
85
|
+
providerReplay: createProviderReplay('openai-responses', [
|
|
86
|
+
{ type: 'tool_search_call', call_id: 'ts9', execution: 'client', arguments: {} },
|
|
87
|
+
]),
|
|
88
|
+
},
|
|
89
|
+
{ role: 'tool', toolCallId: 'f2', content: 'file' },
|
|
90
|
+
{ role: 'user', content: 'next' },
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Same-owner replay envelope holding a server-executed search pair.
|
|
95
|
+
export function serverSearchReplayHistory(owner) {
|
|
96
|
+
return [
|
|
97
|
+
{ role: 'user', content: 'find tools' },
|
|
98
|
+
{
|
|
99
|
+
role: 'assistant',
|
|
100
|
+
content: 'done',
|
|
101
|
+
providerReplay: createProviderReplay(owner, [
|
|
102
|
+
{ type: 'reasoning', id: 'rs_1', encrypted_content: 'ENC', summary: [] },
|
|
103
|
+
SERVER_CALL,
|
|
104
|
+
SERVER_OUTPUT,
|
|
105
|
+
{ type: 'function_call', call_id: 'c1', name: 'Read', arguments: '{}' },
|
|
106
|
+
]),
|
|
107
|
+
toolCalls: [{ id: 'c1', name: 'Read', arguments: {} }],
|
|
108
|
+
},
|
|
109
|
+
{ role: 'tool', toolCallId: 'c1', content: 'ok' },
|
|
110
|
+
{ role: 'user', content: 'next' },
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Pre-change flag-off cases: [label, history(name), providerState?]
|
|
115
|
+
export const COMPAT_CASES = [
|
|
116
|
+
['native', () => nativeHistory()],
|
|
117
|
+
['oauth', () => oauthHistory()],
|
|
118
|
+
['own-search-output', (name) => {
|
|
119
|
+
const h = nativeHistory();
|
|
120
|
+
h[2] = { ...h[2], nativeToolSearch: search(name) };
|
|
121
|
+
return h;
|
|
122
|
+
}],
|
|
123
|
+
['server-replay', (name, owner = replayOwner(name)) => serverSearchReplayHistory(owner)],
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
export function compatProvider(name, config = {}) {
|
|
127
|
+
const requests = [];
|
|
128
|
+
const provider = Object.assign(Object.create(OpenAICompatProvider.prototype), {
|
|
129
|
+
name,
|
|
130
|
+
config: { preconnect: false, ...config },
|
|
131
|
+
nativePdf: true,
|
|
132
|
+
client: {
|
|
133
|
+
responses: {
|
|
134
|
+
create: async (params) => {
|
|
135
|
+
requests.push(structuredClone(params));
|
|
136
|
+
return (async function* () {
|
|
137
|
+
yield {
|
|
138
|
+
type: 'response.completed',
|
|
139
|
+
response: { id: 'resp-1', model: params.model, status: 'completed', output: [REPLY] },
|
|
140
|
+
};
|
|
141
|
+
})();
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
return { provider, requests };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export async function captureCompat(name, model, history, opts = {}, config = {}) {
|
|
150
|
+
const { provider, requests } = compatProvider(name, config);
|
|
151
|
+
await sendCompatResponses(provider, history, model, [], { sessionId: 'sess-1', ...opts });
|
|
152
|
+
return requests[0];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function captureFirstParty(name, model, history) {
|
|
156
|
+
return JSON.parse(JSON.stringify(buildRequestBody(history, model, [], { promptCacheProvider: name, sessionId: 'sess-1' })));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export async function captureAll() {
|
|
160
|
+
const out = {};
|
|
161
|
+
for (const [name, model] of ROUTES) {
|
|
162
|
+
for (const [label, build] of COMPAT_CASES) {
|
|
163
|
+
out[`compat/${name}/${model}/${label}`] = await captureCompat(name, model, build(name));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
for (const [name, model] of FIRST_PARTY) {
|
|
167
|
+
for (const [label, build] of COMPAT_CASES) {
|
|
168
|
+
out[`first-party/${name}/${label}`] = captureFirstParty(name, model, build(name, 'openai-responses'));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return out;
|
|
172
|
+
}
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
toXaiResponsesInput,
|
|
23
23
|
xaiSystemInstructions,
|
|
24
24
|
} from './openai-compat-wire.mjs';
|
|
25
|
+
import { nativeDeferredFamilyForRoute } from './wire-route.mjs';
|
|
25
26
|
import { preparePdfTextForProvider } from './media-normalization.mjs';
|
|
26
27
|
import { normalizeOpencodeGoReasoningEffort } from './openai-compat-xai.mjs';
|
|
27
28
|
import { isCustomProviderName, resolveCustomReasoning } from './custom-reasoning.mjs';
|
|
@@ -87,15 +88,38 @@ function customEffortProjection(provider, useModel, messages, opts) {
|
|
|
87
88
|
return { ...projection, initialEffort, effort: current, updates };
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
// Whether the endpoint takes `prompt_cache_key`. An explicit
|
|
92
|
+
// `opts.responsesPromptCacheKey` / `config.responsesPromptCacheKey` boolean
|
|
93
|
+
// decides; otherwise only custom routes (which always had it) send it.
|
|
94
|
+
function supportsPromptCacheKey(provider, opts) {
|
|
95
|
+
const declared = opts.responsesPromptCacheKey ?? provider.config?.responsesPromptCacheKey;
|
|
96
|
+
return typeof declared === 'boolean' ? declared : isCustomProviderName(provider.name);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Native Responses items (tool_search_call/output, custom_tool_call/output) in
|
|
100
|
+
// replayed history are strictly opt-in: only a route that declares
|
|
101
|
+
// `responsesNativeItems: true` (opts or config) gets the first-party lowering.
|
|
102
|
+
// Every other route keeps the function-only lowering byte for byte.
|
|
103
|
+
function supportsNativeResponsesItems(provider, opts) {
|
|
104
|
+
return (opts.responsesNativeItems ?? provider.config?.responsesNativeItems) === true || hasNativeDeferredTools(provider, opts);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// A session whose pinned route verified native deferred tools on the Responses
|
|
108
|
+
// wire (flag off in every PROFILES entry today): tool_search is declared
|
|
109
|
+
// natively and loaded tools replay as tool_search_output.
|
|
110
|
+
function hasNativeDeferredTools(provider, opts) {
|
|
111
|
+
return nativeDeferredFamilyForRoute(provider.name, opts.wireRoute ?? opts.session?.wireRoute) === 'openai';
|
|
112
|
+
}
|
|
113
|
+
|
|
90
114
|
/**
|
|
91
|
-
* A
|
|
115
|
+
* A route's session identity: its prompt_cache_key and (custom routes) session
|
|
92
116
|
* headers, '' without a session. The session wins over the provider-scoped
|
|
93
117
|
* cache key, so parallel sessions never evict each other; a one-shot role
|
|
94
118
|
* ('shared' scope, a fresh session per call) keys on the provider key instead.
|
|
95
119
|
* Never the effort, so an effort change keeps the cache routing.
|
|
96
120
|
*/
|
|
97
121
|
function customSessionCacheKey(provider, opts) {
|
|
98
|
-
if (!
|
|
122
|
+
if (!supportsPromptCacheKey(provider, opts)) return '';
|
|
99
123
|
const explicit = opts.promptCacheKey || opts.providerCacheKey || opts.session?.promptCacheKey;
|
|
100
124
|
return normalizeCacheKey(
|
|
101
125
|
opts.promptCacheScope === 'shared' ? explicit || opts.sessionId : opts.sessionId || explicit
|
|
@@ -126,7 +150,11 @@ function buildCompatResponsesParams({
|
|
|
126
150
|
const maxOutputTokens = resolveCompatMaxOutputTokens(opts);
|
|
127
151
|
if (maxOutputTokens) params.max_output_tokens = maxOutputTokens;
|
|
128
152
|
if (tools?.length) {
|
|
129
|
-
params.tools = toResponsesTools(tools, {
|
|
153
|
+
params.tools = toResponsesTools(tools, {
|
|
154
|
+
provider: provider.name,
|
|
155
|
+
onToolExcluded: opts.onToolExcluded,
|
|
156
|
+
...(hasNativeDeferredTools(provider, opts) ? { nativeDeferredTools: true } : {}),
|
|
157
|
+
});
|
|
130
158
|
params.parallel_tool_calls = true;
|
|
131
159
|
}
|
|
132
160
|
applyCompatToolChoice(params, opts);
|
|
@@ -207,6 +235,22 @@ async function streamCompatResponses({ provider, params, label, signal, opts, he
|
|
|
207
235
|
}
|
|
208
236
|
}
|
|
209
237
|
|
|
238
|
+
// OpenRouter's Responses endpoint is stateless: it does not store responses or
|
|
239
|
+
// resolve `previous_response_id`. Imported server-side continuation state (a
|
|
240
|
+
// previous id, or a stored response) is rejected up front rather than sent.
|
|
241
|
+
function assertOpenRouterStateless(provider, opts) {
|
|
242
|
+
if (provider.name !== 'openrouter') return;
|
|
243
|
+
const imported = opts.providerState?.[COMPAT_RESPONSES_STATE_KEY];
|
|
244
|
+
const previous = typeof imported?.previousResponseId === 'string' && imported.previousResponseId !== '';
|
|
245
|
+
if (!previous && imported?.store !== true) return;
|
|
246
|
+
throw Object.assign(
|
|
247
|
+
new Error(
|
|
248
|
+
'openrouter Responses is stateless: imported previous_response_id / store:true continuation state is not supported'
|
|
249
|
+
),
|
|
250
|
+
{ code: 'OPENROUTER_RESPONSES_STATELESS_ONLY', provider: provider.name }
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
210
254
|
/**
|
|
211
255
|
* Send one turn over `POST {baseURL}/responses` (streaming) using the
|
|
212
256
|
* provider's existing OpenAI SDK client. Returns the same result shape as
|
|
@@ -229,6 +273,7 @@ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts
|
|
|
229
273
|
}
|
|
230
274
|
const label = `${provider.name}:responses`;
|
|
231
275
|
messages = await preparePdfTextForProvider(messages, provider);
|
|
276
|
+
assertOpenRouterStateless(provider, opts);
|
|
232
277
|
const effortProjection = customEffortProjection(provider, useModel, messages, opts);
|
|
233
278
|
const sessionCacheKey = customSessionCacheKey(provider, opts);
|
|
234
279
|
const { input, previousResponseId, continuationResetReason } = toXaiResponsesInput(messages, opts.providerState, {
|
|
@@ -237,6 +282,7 @@ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts
|
|
|
237
282
|
stateKey: COMPAT_RESPONSES_STATE_KEY,
|
|
238
283
|
replayProvider,
|
|
239
284
|
providerName: provider.name,
|
|
285
|
+
nativeLowering: supportsNativeResponsesItems(provider, opts),
|
|
240
286
|
nativePdf: provider.nativePdf,
|
|
241
287
|
// Opt-in: system prompts travel as top-level `instructions`, not input items.
|
|
242
288
|
includeSystem: provider.config?.responsesSystemAsInstructions !== true,
|
|
@@ -254,7 +300,7 @@ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts
|
|
|
254
300
|
sessionCacheKey,
|
|
255
301
|
});
|
|
256
302
|
// The session identity also travels as headers; caller headers win.
|
|
257
|
-
const headers = sessionCacheKey
|
|
303
|
+
const headers = sessionCacheKey && isCustomProviderName(provider.name)
|
|
258
304
|
? { 'session-id': sessionCacheKey, 'x-client-request-id': sessionCacheKey, ...opts.requestHeaders }
|
|
259
305
|
: opts.requestHeaders;
|
|
260
306
|
|
|
@@ -287,7 +333,7 @@ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts
|
|
|
287
333
|
const messageIndex = Array.isArray(messages) ? messages.length : 0;
|
|
288
334
|
const encryptedReasoningHistory = [
|
|
289
335
|
...(Array.isArray(priorState?.encryptedReasoningHistory) ? priorState.encryptedReasoningHistory : []),
|
|
290
|
-
...(reasoningItems.length ? [{ messageIndex, items: reasoningItems }] : []),
|
|
336
|
+
...(reasoningItems.length ? [{ messageIndex, items: reasoningItems, owner: replayProvider }] : []),
|
|
291
337
|
];
|
|
292
338
|
const searchSources = collectCompatResponseSearchSources(response);
|
|
293
339
|
const usageSummary = usage ? responsesUsage(usage) : undefined;
|
|
@@ -296,6 +342,7 @@ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts
|
|
|
296
342
|
model: response?.model || useModel,
|
|
297
343
|
toolCalls: streamed.toolCalls,
|
|
298
344
|
stopReason: streamed.stopReason || null,
|
|
345
|
+
...(streamed.refusal ? { refusal: streamed.refusal } : {}),
|
|
299
346
|
...(streamed.stopReason === 'length' && (streamed.content || '').length > 0 ? { truncated: true } : {}),
|
|
300
347
|
citations: searchSources.citations.length ? searchSources.citations : undefined,
|
|
301
348
|
webSearchCalls: searchSources.webSearchCalls.length ? searchSources.webSearchCalls : undefined,
|
|
@@ -306,6 +353,7 @@ async function sendCompatResponsesOnce(provider, messages, useModel, tools, opts
|
|
|
306
353
|
previousResponseId: null,
|
|
307
354
|
responseId: response?.id || null,
|
|
308
355
|
store: false,
|
|
356
|
+
owner: replayProvider,
|
|
309
357
|
encryptedReasoningItems: reasoningItems,
|
|
310
358
|
encryptedReasoningHistory,
|
|
311
359
|
seenMessageCount: messageIndex,
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
finalizeResponsesStream,
|
|
32
32
|
unresolvedSalvageError,
|
|
33
33
|
} from './openai-compat-responses-state.mjs';
|
|
34
|
+
import { createRefusals, refusalResultFields } from './openai-ws-response-state/refusals.mjs';
|
|
34
35
|
import { responsesUsage } from './openai-compat-response-normalization.mjs';
|
|
35
36
|
import { noteAbandonedUsage } from '../../../shared/llm/usage-context.mjs';
|
|
36
37
|
|
|
@@ -151,7 +152,12 @@ export async function consumeCompatResponsesStream(
|
|
|
151
152
|
throw stampOutcome(unresolved);
|
|
152
153
|
}
|
|
153
154
|
try {
|
|
154
|
-
|
|
155
|
+
const result = finalizeResponsesStream(state, { leakedCalls, parseResponsesToolCalls, responseOutputText, label });
|
|
156
|
+
// The terminal output bundle's refusal parts join the streamed ones (keyed
|
|
157
|
+
// by item id + content index, so copies of one part fold into one text).
|
|
158
|
+
state.refusals ||= createRefusals();
|
|
159
|
+
for (const item of result.response?.output || []) state.refusals.absorbMessage(item);
|
|
160
|
+
return { ...result, ...refusalResultFields(state.refusals, result.content) };
|
|
155
161
|
} catch (err) {
|
|
156
162
|
attachPartialState(err, state, leakedCalls);
|
|
157
163
|
throw stampOutcome(err);
|
|
@@ -37,6 +37,8 @@ export function extractCompatCachedTokens(usage) {
|
|
|
37
37
|
usage?.input_tokens_details?.cached_tokens,
|
|
38
38
|
usage?.prompt_cache_hit_tokens,
|
|
39
39
|
usage?.cached_prompt_text_tokens,
|
|
40
|
+
// Together reports it top-level; first-positive wins, so it never stacks on a nested count.
|
|
41
|
+
usage?.cached_tokens,
|
|
40
42
|
];
|
|
41
43
|
for (const v of candidates) {
|
|
42
44
|
const n = Number(v);
|
|
@@ -17,8 +17,11 @@ import {
|
|
|
17
17
|
} from './media-normalization.mjs';
|
|
18
18
|
import { customToolCallFromResponseItem, nativeToolSearchCallFromArguments } from './custom-tool-wire.mjs';
|
|
19
19
|
import { providerReplayItems } from './lib/provider-replay.mjs';
|
|
20
|
+
import { acceptedWireTools } from './lib/claude-bridge-schema.mjs';
|
|
20
21
|
import { ensureResponsesCallOutputs } from './lib/wire-pairing.mjs';
|
|
21
22
|
import { responsesEffortUpdates } from './effort-configuration.mjs';
|
|
23
|
+
import { convertMessagesToResponsesInput } from './openai-responses-input.mjs';
|
|
24
|
+
import { COMPAT_REASONING_METADATA_KEY, contentWithThinkingChunk } from './openai-compat-reasoning-field.mjs';
|
|
22
25
|
|
|
23
26
|
function positiveTokenInt(value) {
|
|
24
27
|
const n = Number(value);
|
|
@@ -39,19 +42,23 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
|
|
|
39
42
|
// strict providers (xai) reject unknown roles/types and would 400 the
|
|
40
43
|
// request. Documented in v0.1.160 (GPT reasoning replay).
|
|
41
44
|
//
|
|
42
|
-
// DeepSeek
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
// assistant reasoning_content is replayed; reasoning_effort itself remains
|
|
49
|
-
// caller/user-selected.
|
|
45
|
+
// DeepSeek thinking-mode models with tools REQUIRE the prior turn's
|
|
46
|
+
// `reasoning_content` echoed back (400 without it); without tools it is
|
|
47
|
+
// ignored, so the caller (options.replaysReasoningContent) always replays it.
|
|
48
|
+
// xAI reasoning models preserve their official multi-turn shape and cache
|
|
49
|
+
// prefix stability when prior assistant reasoning_content is replayed;
|
|
50
|
+
// reasoning_effort itself remains caller/user-selected.
|
|
50
51
|
//
|
|
51
52
|
// Custom providers pass options.customReplay (custom-reasoning.mjs replay
|
|
52
53
|
// eligibility). When it is a boolean it alone decides; a replaying custom
|
|
53
54
|
// endpoint also needs a non-empty reasoning_content on every assistant
|
|
54
55
|
// tool-call turn, so missing/empty reasoning there is padded with " ".
|
|
56
|
+
//
|
|
57
|
+
// options.reasoningShape (openai-compat-reasoning-field.mjs) names the
|
|
58
|
+
// endpoint families with their own reasoning fields; they decide the resend
|
|
59
|
+
// key and win over the flags above. options.developerRole keeps the
|
|
60
|
+
// `developer` role for endpoints that document it; every other chat endpoint
|
|
61
|
+
// only knows `system`, so developer instructions go out as system messages.
|
|
55
62
|
const customReplay = typeof options.customReplay === 'boolean' ? options.customReplay : null;
|
|
56
63
|
const replaysReasoningContent = customReplay ?? (options.replaysReasoningContent === true || providerName === 'xai');
|
|
57
64
|
const out = [];
|
|
@@ -62,8 +69,25 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
|
|
|
62
69
|
const details = metadata?.reasoning_details ?? metadata?.reasoningDetails;
|
|
63
70
|
return Array.isArray(details) && details.length ? details : null;
|
|
64
71
|
};
|
|
72
|
+
const shape = options.reasoningShape || null;
|
|
73
|
+
// Receive and resend fields differ per endpoint family: the key a reply's
|
|
74
|
+
// reasoning arrived on is recorded in providerMetadata at receive time.
|
|
75
|
+
const receivedField = (message) => message?.providerMetadata?.[COMPAT_REASONING_METADATA_KEY]?.reasoningField;
|
|
76
|
+
const attachShapeReasoning = (msg, message, stored) => {
|
|
77
|
+
if (!stored) return;
|
|
78
|
+
if (shape.resend === 'same_key') {
|
|
79
|
+
msg[receivedField(message) === 'reasoning' ? 'reasoning' : 'reasoning_content'] = stored;
|
|
80
|
+
} else if (shape.resend === 'reasoning') {
|
|
81
|
+
// OpenRouter: reasoning_details replace the text when present.
|
|
82
|
+
if (!openRouterReasoningDetails(message)) msg.reasoning = stored;
|
|
83
|
+
} else if (shape.resend === 'content_chunks' && receivedField(message) === 'content_chunks') {
|
|
84
|
+
msg.content = contentWithThinkingChunk(msg.content, stored);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
65
87
|
const attachAssistantReasoning = (msg, message) => {
|
|
66
|
-
if (
|
|
88
|
+
if (shape) {
|
|
89
|
+
attachShapeReasoning(msg, message, typeof message.reasoningContent === 'string' ? message.reasoningContent : '');
|
|
90
|
+
} else if (customReplay) {
|
|
67
91
|
const stored = typeof message.reasoningContent === 'string' ? message.reasoningContent : '';
|
|
68
92
|
if (stored) msg.reasoning_content = stored;
|
|
69
93
|
else if (Array.isArray(msg.tool_calls) && msg.tool_calls.length) msg.reasoning_content = ' ';
|
|
@@ -104,8 +128,12 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
|
|
|
104
128
|
continue;
|
|
105
129
|
}
|
|
106
130
|
const msg = {
|
|
107
|
-
role: m.role,
|
|
108
|
-
content: normalizeContentForOpenAIChat(m.content, {
|
|
131
|
+
role: m.role === 'developer' && options.developerRole !== true ? 'system' : m.role,
|
|
132
|
+
content: normalizeContentForOpenAIChat(m.content, {
|
|
133
|
+
role: m.role,
|
|
134
|
+
nativePdf: options.nativePdf,
|
|
135
|
+
cacheControl: options.cacheControl === true,
|
|
136
|
+
}),
|
|
109
137
|
};
|
|
110
138
|
out.push(m.role === 'assistant' ? attachAssistantReasoning(msg, m) : msg);
|
|
111
139
|
}
|
|
@@ -113,18 +141,6 @@ export function toOpenAIMessages(messages, providerName, options = {}) {
|
|
|
113
141
|
return out;
|
|
114
142
|
}
|
|
115
143
|
|
|
116
|
-
// deepseek-reasoner returns 400 when `reasoning_content` appears in the input
|
|
117
|
-
// messages; every other DeepSeek thinking model needs it back once tools are in
|
|
118
|
-
// play. Unknown DeepSeek ids default to replaying: a missing echo breaks the
|
|
119
|
-
// tool loop, while a stray field on a non-thinking model is ignored.
|
|
120
|
-
export function deepseekReplaysReasoningContent(model) {
|
|
121
|
-
return !/reasoner/.test(
|
|
122
|
-
String(model || '')
|
|
123
|
-
.trim()
|
|
124
|
-
.toLowerCase()
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
144
|
export function toOpenAITools(tools) {
|
|
129
145
|
return tools.map((t) => ({
|
|
130
146
|
type: 'function',
|
|
@@ -146,9 +162,42 @@ function functionToolFromSessionTool(t, name = t?.name) {
|
|
|
146
162
|
};
|
|
147
163
|
}
|
|
148
164
|
|
|
149
|
-
|
|
165
|
+
// xAI hosts tool search itself (docs.x.ai progressive tool disclosure): a
|
|
166
|
+
// `{type:'tool_search'}` server tool loads the definitions of function tools
|
|
167
|
+
// marked `defer_loading: true`, and the server returns the search as
|
|
168
|
+
// tool_search_call / tool_search_output items. The client loader (`load_tool`)
|
|
169
|
+
// is therefore replaced by that one server tool; with deferred tools but no
|
|
170
|
+
// loader the server tool is still added, or the deferred tools could never load.
|
|
171
|
+
function toServerToolSearchTools(tools) {
|
|
172
|
+
let hasSearch = false;
|
|
173
|
+
let hasDeferred = false;
|
|
174
|
+
const out = tools.map((t) => {
|
|
175
|
+
if (t?.name === 'load_tool' || t?.name === 'tool_search') {
|
|
176
|
+
if (hasSearch) return null;
|
|
177
|
+
hasSearch = true;
|
|
178
|
+
return { type: 'tool_search' };
|
|
179
|
+
}
|
|
180
|
+
if (t?.deferLoading === true || t?.defer_loading === true) {
|
|
181
|
+
hasDeferred = true;
|
|
182
|
+
return { ...functionToolFromSessionTool(t), defer_loading: true };
|
|
183
|
+
}
|
|
184
|
+
return functionToolFromSessionTool(t);
|
|
185
|
+
});
|
|
186
|
+
if (hasDeferred && !hasSearch) out.push({ type: 'tool_search' });
|
|
187
|
+
return out.filter(Boolean);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function toResponsesTools(allTools, options = {}) {
|
|
150
191
|
const provider = String(options?.provider || '').toLowerCase();
|
|
192
|
+
// A Responses endpoint rejects the whole request for one invalid
|
|
193
|
+
// `parameters`; a tool broken even after lowering is left out and reported.
|
|
194
|
+
const tools = acceptedWireTools(allTools, 'openai', options?.onToolExcluded, `[${provider || 'responses'}] tool`);
|
|
195
|
+
if (options?.serverToolSearch === true) return toServerToolSearchTools(tools);
|
|
196
|
+
// A route pinned with verified native deferred tools declares the native
|
|
197
|
+
// client tool_search tool and marks deferred definitions `defer_loading`.
|
|
198
|
+
const nativeDeferred = options?.nativeDeferredTools === true;
|
|
151
199
|
const allowNativeToolSearch =
|
|
200
|
+
nativeDeferred ||
|
|
152
201
|
options?.nativeToolSearch === true ||
|
|
153
202
|
(options?.nativeToolSearch !== false && (provider === 'openai' || provider === 'openai-oauth'));
|
|
154
203
|
return tools.map((t) => {
|
|
@@ -170,6 +219,9 @@ export function toResponsesTools(tools, options = {}) {
|
|
|
170
219
|
// tools (e.g. apply_patch) as ordinary function tools instead. Grammar
|
|
171
220
|
// tools may carry no usable inputSchema, so fall back to a permissive
|
|
172
221
|
// object schema so grok still registers a valid function tool.
|
|
222
|
+
if (nativeDeferred && (t?.deferLoading === true || t?.defer_loading === true)) {
|
|
223
|
+
return { ...functionToolFromSessionTool(t), defer_loading: true };
|
|
224
|
+
}
|
|
173
225
|
return functionToolFromSessionTool(t);
|
|
174
226
|
});
|
|
175
227
|
}
|
|
@@ -237,7 +289,7 @@ export function parseResponsesToolCalls(response, label) {
|
|
|
237
289
|
} else if (item?.type === 'custom_tool_call') {
|
|
238
290
|
const call = customToolCallFromResponseItem(item);
|
|
239
291
|
if (call) out.push(call);
|
|
240
|
-
} else if (item?.type === 'tool_search_call') {
|
|
292
|
+
} else if (item?.type === 'tool_search_call' && item.execution !== 'server') {
|
|
241
293
|
const searchArgs =
|
|
242
294
|
item.arguments && typeof item.arguments === 'object' && !Array.isArray(item.arguments)
|
|
243
295
|
? item.arguments
|
|
@@ -409,16 +461,41 @@ export function toXaiResponsesInput(messages, providerState, options = {}) {
|
|
|
409
461
|
let history = [];
|
|
410
462
|
if (Array.isArray(state?.encryptedReasoningHistory)) history = state.encryptedReasoningHistory;
|
|
411
463
|
else if (Array.isArray(state?.encryptedReasoningItems)) {
|
|
412
|
-
history = [{ messageIndex: seen, items: state.encryptedReasoningItems }];
|
|
464
|
+
history = [{ messageIndex: seen, items: state.encryptedReasoningItems, owner: state.owner }];
|
|
413
465
|
}
|
|
414
466
|
for (const entry of history) {
|
|
415
467
|
const index = Number(entry?.messageIndex);
|
|
416
468
|
if (!Number.isInteger(index) || index < 0 || !Array.isArray(entry?.items)) continue;
|
|
469
|
+
// Owner-tagged reasoning (compat routes) never replays under another
|
|
470
|
+
// owner, even when a caller passes provider state across providers.
|
|
471
|
+
if (entry.owner !== undefined && entry.owner !== replayProvider) continue;
|
|
417
472
|
const bucket = reasoningByMessageIndex.get(index) || [];
|
|
418
473
|
bucket.push(...entry.items.map((item) => ({ ...item })));
|
|
419
474
|
reasoningByMessageIndex.set(index, bucket);
|
|
420
475
|
}
|
|
421
476
|
}
|
|
477
|
+
if (options.nativeLowering === true) {
|
|
478
|
+
// Native-item-capable Responses routes share the first-party lowering:
|
|
479
|
+
// native tool_search / custom calls keep their own output type, and only
|
|
480
|
+
// this route's own replay tag and reasoning state are replayed.
|
|
481
|
+
return {
|
|
482
|
+
input: convertMessagesToResponsesInput(messages, {
|
|
483
|
+
startIndex,
|
|
484
|
+
includeSystem,
|
|
485
|
+
nativePdf: options.nativePdf,
|
|
486
|
+
replayProvider,
|
|
487
|
+
// Compat-owned tool_search payloads are tagged with the route name.
|
|
488
|
+
nativeToolSearchProvider: options.providerName,
|
|
489
|
+
replayOwnedReasoning: true,
|
|
490
|
+
reasoningByMessageIndex,
|
|
491
|
+
effortProjection: options.effortProjection,
|
|
492
|
+
splitToolContent: (content) => splitToolContentForXaiResponses(content, { nativePdf: options.nativePdf }),
|
|
493
|
+
}),
|
|
494
|
+
previousResponseId,
|
|
495
|
+
startIndex,
|
|
496
|
+
continuationResetReason: resetReason,
|
|
497
|
+
};
|
|
498
|
+
}
|
|
422
499
|
const pendingToolMedia = [];
|
|
423
500
|
const flushToolMedia = () => {
|
|
424
501
|
if (!pendingToolMedia.length) return;
|
|
@@ -5,6 +5,7 @@ import { consumeCompatResponsesStream } from './openai-compat-stream.mjs';
|
|
|
5
5
|
import { PROVIDER_FIRST_BYTE_TIMEOUT_MS, createPassthroughSignal } from '../stall-policy.mjs';
|
|
6
6
|
import {
|
|
7
7
|
nativeResponsesTools,
|
|
8
|
+
resolveCompatMaxOutputTokens,
|
|
8
9
|
toOpenAIMessages,
|
|
9
10
|
toResponsesTools,
|
|
10
11
|
toXaiResponsesInput,
|
|
@@ -26,17 +27,34 @@ import { applyCompatToolChoice, compatStreamRetryReporter } from './compat-reque
|
|
|
26
27
|
import { envFlag as _envFlag } from '../../../shared/env.mjs';
|
|
27
28
|
import { resolveResponsesTransportPolicy, RESPONSES_TRANSPORT_CAPABILITIES } from './openai-transport-policy.mjs';
|
|
28
29
|
|
|
30
|
+
// Server-side tool search is strictly opt-in, from the provider's own config
|
|
31
|
+
// (`xaiServerToolSearch`, shared by grok-oauth's inner xai provider) or the
|
|
32
|
+
// request opts. Unset, every xAI request body is unchanged: deferred tools go
|
|
33
|
+
// out as plain function tools and the client `load_tool` stays a function.
|
|
34
|
+
// Server-executed search items replay through the owner-tagged providerReplay
|
|
35
|
+
// envelope in either mode and are never dispatched locally.
|
|
36
|
+
function xaiServerToolSearchEnabled(provider, opts) {
|
|
37
|
+
return (opts.xaiServerToolSearch ?? provider.config?.xaiServerToolSearch) === true;
|
|
38
|
+
}
|
|
39
|
+
|
|
29
40
|
// Tool list, parallel tool calls, tool choice and reasoning effort shared by
|
|
30
41
|
// the HTTP/SSE and WebSocket Responses bodies.
|
|
31
42
|
function applyXaiResponsesToolsAndEffort(params, { provider, tools, opts, useModel }) {
|
|
32
43
|
const nativeTools = nativeResponsesTools(opts);
|
|
33
44
|
if (tools?.length || nativeTools.length) {
|
|
34
|
-
|
|
45
|
+
const toolOptions = xaiServerToolSearchEnabled(provider, opts)
|
|
46
|
+
? { provider: 'xai', serverToolSearch: true, onToolExcluded: opts.onToolExcluded }
|
|
47
|
+
: { provider: 'xai', onToolExcluded: opts.onToolExcluded };
|
|
48
|
+
params.tools = [...nativeTools, ...toResponsesTools(tools || [], toolOptions)];
|
|
35
49
|
}
|
|
36
50
|
// Explicit parallel tool calls, matching the OpenAI Responses
|
|
37
51
|
// reference shape. Probe-verified accepted by api.x.ai (HTTP 200,
|
|
38
|
-
// 2026-08-16); absent, the service default decides per turn.
|
|
39
|
-
|
|
52
|
+
// 2026-08-16); absent, the service default decides per turn. An explicit
|
|
53
|
+
// caller `parallelToolCalls:false` is honored (docs.x.ai function-calling).
|
|
54
|
+
if (params.tools?.length) params.parallel_tool_calls = opts.parallelToolCalls !== false;
|
|
55
|
+
// Caller output cap (docs.x.ai text best-practices): max_output_tokens.
|
|
56
|
+
const maxOutputTokens = resolveCompatMaxOutputTokens(opts);
|
|
57
|
+
if (maxOutputTokens) params.max_output_tokens = maxOutputTokens;
|
|
40
58
|
applyCompatToolChoice(params, opts);
|
|
41
59
|
const reasoningEffort = normalizeXaiReasoningEffort(
|
|
42
60
|
opts.xaiReasoningEffort ??
|
|
@@ -201,7 +219,8 @@ export async function sendXaiResponsesWebSocket(provider, messages, useModel, to
|
|
|
201
219
|
onTextDelta: typeof opts.onTextDelta === 'function' ? opts.onTextDelta : null,
|
|
202
220
|
onStageChange: typeof opts.onStageChange === 'function' ? opts.onStageChange : null,
|
|
203
221
|
externalSignal: signal,
|
|
204
|
-
|
|
222
|
+
// A forked request runs in its own transport scope (transport-scope.mjs).
|
|
223
|
+
poolKey: opts.transportScope || opts.sessionId || opts.session?.id || null,
|
|
205
224
|
cacheKey: cacheRouting.key,
|
|
206
225
|
iteration,
|
|
207
226
|
useModel,
|
|
@@ -235,13 +235,18 @@ export function useXaiResponsesApi(opts, config) {
|
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
export function useXaiResponsesWebSocket(opts, config) {
|
|
238
|
+
// A pinned route (grok-oauth's cli-chat-proxy) takes its transport from the
|
|
239
|
+
// config alone: the xAI WebSocket connector targets api.x.ai, so no request
|
|
240
|
+
// option or env override may carry the OAuth bearer there.
|
|
238
241
|
const raw =
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
242
|
+
config?.transportPinned === true
|
|
243
|
+
? config.responsesTransport
|
|
244
|
+
: (opts?.xaiResponsesTransport ??
|
|
245
|
+
opts?.xaiTransport ??
|
|
246
|
+
config?.responsesTransport ??
|
|
247
|
+
config?.transport ??
|
|
248
|
+
process.env.MIXDOG_XAI_RESPONSES_TRANSPORT ??
|
|
249
|
+
process.env.MIXDOG_XAI_TRANSPORT);
|
|
245
250
|
// Reference xAI/Grok parity is HTTP/SSE. WebSocket remains available only
|
|
246
251
|
// when a caller explicitly selects a WS transport.
|
|
247
252
|
if (raw == null || raw === '') return false;
|
|
@@ -78,6 +78,9 @@ export class OpenAICompatProvider {
|
|
|
78
78
|
this.config = config;
|
|
79
79
|
this.baseURL = baseURL;
|
|
80
80
|
this.apiKey = apiKey;
|
|
81
|
+
// Whether Chat content blocks keep their Anthropic-style `cache_control`
|
|
82
|
+
// (OpenRouter documents it); a gateway that does not ignores or rejects it.
|
|
83
|
+
this.chatCacheControl = (config.chatCacheControl ?? preset?.chatCacheControl) === true;
|
|
81
84
|
// Merge caller-supplied headers (config.extraHeaders) over the preset's.
|
|
82
85
|
// Used e.g. by grok-oauth to inject the Grok CLI client headers for the
|
|
83
86
|
// grok-build proxy. Backward-compatible: providers that pass no
|
|
@@ -256,7 +259,9 @@ export class OpenAICompatProvider {
|
|
|
256
259
|
return fetchCompatModelItems(this);
|
|
257
260
|
}
|
|
258
261
|
async listModels() {
|
|
259
|
-
|
|
262
|
+
// A failed /models request must surface; an empty list would be cached as
|
|
263
|
+
// a complete catalog by the shared catalog loader.
|
|
264
|
+
return listCompatModels(this, { throwOnError: true });
|
|
260
265
|
}
|
|
261
266
|
async isAvailable() {
|
|
262
267
|
return isCompatProviderAvailable(this);
|