@bitkyc08/opencodex 2.86.0 → 2.88.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/gui/dist/assets/App-CHC89EXQ.js +58 -0
- package/gui/dist/assets/App-wT3mXqFz.css +1 -0
- package/gui/dist/assets/{Tray-DyR9yBee.js → Tray-B5bC7AWL.js} +1 -1
- package/gui/dist/assets/index-B5bsvxor.js +94 -0
- package/gui/dist/assets/index-DPeB9HpV.css +1 -0
- package/gui/dist/assets/quota-summary-D8y2wTsB.js +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/adapters/anthropic/beta-allowlist.ts +9 -8
- package/src/adapters/anthropic/beta-body-pairs.ts +93 -0
- package/src/adapters/anthropic/passthrough.ts +7 -23
- package/src/adapters/anthropic-progress.ts +84 -0
- package/src/adapters/anthropic-rejection-memo.ts +71 -0
- package/src/adapters/anthropic-replay.ts +135 -0
- package/src/adapters/anthropic-tool-catalog.ts +11 -0
- package/src/adapters/anthropic.ts +151 -33
- package/src/adapters/base.ts +2 -0
- package/src/adapters/claude-cli/adapter.ts +111 -23
- package/src/adapters/claude-cli/profiles.ts +2 -1
- package/src/adapters/claude-cli/stable-replay.ts +108 -0
- package/src/adapters/claude-cli/usage-admission.ts +230 -0
- package/src/adapters/coding-agent/protocol.ts +1 -1
- package/src/adapters/coding-agent/turn.ts +18 -2
- package/src/adapters/dsh-account.ts +97 -0
- package/src/adapters/google-progress-history.ts +53 -0
- package/src/adapters/google.ts +52 -9
- package/src/adapters/openai-chat/messages.ts +4 -3
- package/src/adapters/openai-chat/passthrough.ts +8 -2
- package/src/adapters/openai-chat/reasoning-replay.ts +52 -0
- package/src/adapters/openai-responses/compaction-search-history.ts +14 -7
- package/src/adapters/openai-responses/passthrough.ts +57 -125
- package/src/adapters/openai-responses/request-strips.ts +25 -3
- package/src/adapters/openai-responses/transport.ts +81 -0
- package/src/adapters/qoder/adapter.ts +4 -2
- package/src/adapters/registry.ts +5 -0
- package/src/adapters/zed.ts +26 -1
- package/src/advisor/activity.ts +55 -0
- package/src/advisor/budget.ts +62 -0
- package/src/advisor/consult.ts +4 -1
- package/src/advisor/context.ts +16 -4
- package/src/advisor/evidence-tool.ts +21 -0
- package/src/advisor/evidence.ts +117 -0
- package/src/advisor/runtime.ts +79 -31
- package/src/advisor/settings.ts +11 -2
- package/src/bridge/errors.ts +19 -1
- package/src/bridge/internal.ts +7 -1
- package/src/bridge/response-json.ts +18 -3
- package/src/bridge/sse.ts +59 -8
- package/src/bridge/terminal-refusal.ts +59 -0
- package/src/claude/desktop-3p-library.ts +32 -7
- package/src/claude/desktop-3p.ts +55 -13
- package/src/claude/desktop-first-party.ts +1 -1
- package/src/claude/desktop-picker-platform.ts +4 -0
- package/src/claude/desktop-picker.ts +15 -8
- package/src/claude/desktop-system-proxy.ts +50 -4
- package/src/claude/inbound-content-options.ts +77 -0
- package/src/claude/inbound.ts +33 -0
- package/src/claude/intercept/picker-ca-startup.ts +2 -1
- package/src/claude/intercept/picker-runtime.ts +6 -5
- package/src/claude/intercept/picker-trust-windows.ts +338 -0
- package/src/claude/intercept/picker-trust.ts +19 -0
- package/src/claude/intercept/port-policy.ts +30 -0
- package/src/claude/intercept/runtime.ts +97 -94
- package/src/claude/outbound.ts +46 -13
- package/src/cli/account-api.ts +1 -0
- package/src/cli/account-policy-dto.ts +6 -0
- package/src/cli/account-policy.ts +34 -5
- package/src/cli/account-preservation.ts +44 -0
- package/src/cli/account.ts +8 -2
- package/src/cli/advisor.ts +17 -3
- package/src/cli/capabilities-accounts.ts +20 -1
- package/src/cli/capabilities-agents-routing.ts +5 -2
- package/src/cli/capabilities-base.ts +38 -10
- package/src/cli/capabilities-observe-system.ts +63 -3
- package/src/cli/capabilities-provider-models.ts +11 -0
- package/src/cli/codex-cli-update.ts +151 -41
- package/src/cli/codex-provider.ts +44 -0
- package/src/cli/combo-input.ts +10 -1
- package/src/cli/combo-result.ts +1 -1
- package/src/cli/combo.ts +2 -1
- package/src/cli/cross-home-owner.ts +33 -16
- package/src/cli/dispatch.ts +25 -4
- package/src/cli/doctor.ts +6 -1
- package/src/cli/ensure-desktop-cold-start.ts +60 -7
- package/src/cli/help.ts +3 -2
- package/src/cli/index.ts +1 -1
- package/src/cli/integration-plan-dto.ts +1 -0
- package/src/cli/log-history.ts +172 -0
- package/src/cli/loopback-family.ts +31 -0
- package/src/cli/models-runtime-subcommands.ts +1 -0
- package/src/cli/models-runtime.ts +72 -8
- package/src/cli/observe-stream.ts +2 -0
- package/src/cli/observe.ts +16 -4
- package/src/cli/provider.ts +27 -5
- package/src/cli/registry.ts +28 -8
- package/src/cli/runtime-api.ts +5 -3
- package/src/cli/system-command.ts +40 -8
- package/src/cli/uninstall-client-state.ts +32 -0
- package/src/cli/usage-compare.ts +309 -0
- package/src/cli/usage-model-search.ts +4 -4
- package/src/cli/usage-report.ts +2 -2
- package/src/cli/v2.ts +1 -1
- package/src/client/machine-listener.ts +1 -3
- package/src/client/runtime.ts +1 -0
- package/src/clients/client-path.ts +51 -0
- package/src/clients/config-export/contracts.ts +2 -1
- package/src/clients/config-export.ts +18 -44
- package/src/clients/gentle-shell-path.ts +87 -0
- package/src/codex/account-auto-switch.ts +2 -0
- package/src/codex/account-identity.ts +29 -0
- package/src/codex/account-label.ts +1 -1
- package/src/codex/account-lifecycle.ts +21 -5
- package/src/codex/account-preservation.ts +28 -0
- package/src/codex/account-use-remaining.ts +23 -0
- package/src/codex/app-server-processes.ts +97 -7
- package/src/codex/app-server-restart-service.ts +55 -4
- package/src/codex/auth-api/account-list.ts +4 -0
- package/src/codex/auth-api/account-pause-group.ts +6 -50
- package/src/codex/auth-api/account-preservation.ts +57 -0
- package/src/codex/auth-api/routes.ts +8 -0
- package/src/codex/auth-api/use-remaining-route.ts +36 -0
- package/src/codex/auth-api.ts +0 -1
- package/src/codex/auth-context.ts +2 -2
- package/src/codex/catalog/auto-review.ts +20 -3
- package/src/codex/catalog/build-entries.ts +9 -1
- package/src/codex/catalog/combo-member.ts +14 -5
- package/src/codex/catalog/configured-tiers.ts +1 -1
- package/src/codex/catalog/gather-capture.ts +2 -0
- package/src/codex/catalog/metadata.ts +11 -9
- package/src/codex/catalog/model-hints.ts +21 -16
- package/src/codex/catalog/model-visibility.ts +3 -1
- package/src/codex/catalog/parsing.ts +30 -86
- package/src/codex/catalog/provider-models.ts +36 -34
- package/src/codex/catalog/routed-gather.ts +14 -13
- package/src/codex/cli-install-provenance.ts +105 -17
- package/src/codex/cli-update-plan.ts +545 -0
- package/src/codex/config-write-lock.ts +23 -2
- package/src/codex/desktop-app/picker-freshness.ts +96 -0
- package/src/codex/desktop-app-restart.ts +21 -0
- package/src/codex/desktop-compatibility/installed-build.ts +24 -6
- package/src/codex/desktop-compatibility/routing-preflight.ts +1 -1
- package/src/codex/desktop-compatibility/runtime.ts +12 -3
- package/src/codex/desktop-compatibility/windows-key-protection.ts +115 -9
- package/src/codex/features.ts +85 -45
- package/src/codex/inject/history-failure.ts +27 -0
- package/src/codex/inject/restore.ts +24 -2
- package/src/codex/inject/routing-classify.ts +4 -3
- package/src/codex/inject.ts +18 -27
- package/src/codex/main-account-hard-lock.ts +30 -1
- package/src/codex/native-profile-startup.ts +1 -1
- package/src/codex/ocx-compaction-history.ts +12 -10
- package/src/codex/paths.ts +86 -1
- package/src/codex/provider-routing.ts +174 -0
- package/src/codex/refresh.ts +2 -2
- package/src/codex/routing/health-store.ts +1 -1
- package/src/codex/routing/selection.ts +4 -3
- package/src/codex/routing/thread-affinity.ts +1 -1
- package/src/codex/signed-in-identity.ts +43 -0
- package/src/codex/subagent-model-fallback.ts +1 -1
- package/src/codex/sync.ts +6 -1
- package/src/codex/user-identity.ts +16 -5
- package/src/codex/websocket-activity.ts +161 -0
- package/src/codex/websocket-registry.ts +25 -1
- package/src/codex/windows-local-appdata.ts +84 -0
- package/src/combos/failover.ts +6 -1
- package/src/combos/index.ts +1 -0
- package/src/combos/resolve.ts +46 -10
- package/src/combos/types.ts +15 -0
- package/src/config/diagnostics.ts +33 -6
- package/src/config/live-reconcile.ts +38 -2
- package/src/config/load-degrade.ts +17 -0
- package/src/config/opencode-wire-upgrade.ts +54 -0
- package/src/config/opencode-zen-upgrade.ts +53 -0
- package/src/config/owner-registry.ts +22 -17
- package/src/config/provider-validation.ts +45 -2
- package/src/config/schema/config-schema.ts +22 -0
- package/src/config/schema/leaf-validators.ts +38 -9
- package/src/config/schema/main-account-hard-lock-fallback.ts +26 -0
- package/src/config/schema/native-reasoning-retention.ts +26 -0
- package/src/config.ts +2 -0
- package/src/generated/compatibility-version.json +657 -297
- package/src/grok/sync.ts +1 -1
- package/src/images/loop.ts +116 -27
- package/src/integrations/catalog-refresh.ts +1 -1
- package/src/integrations/mutation-plan.ts +1 -0
- package/src/integrations/registry.ts +8 -0
- package/src/lib/codex-restart-contract.ts +15 -0
- package/src/lib/desktop-upstream-tunnel.ts +18 -53
- package/src/lib/empty-tool-catalog.ts +62 -0
- package/src/lib/errors.ts +19 -3
- package/src/lib/gcp-adc.ts +96 -9
- package/src/lib/gcp-credential-input.ts +12 -0
- package/src/lib/lab-live-route-production.ts +5 -0
- package/src/lib/opaque-proxy-tunnel.ts +217 -0
- package/src/lib/redact.ts +2 -2
- package/src/lib/request-failure-model.ts +2 -0
- package/src/oauth/account-quota-rank.ts +69 -2
- package/src/oauth/anthropic-account-refusal.ts +20 -2
- package/src/oauth/anthropic-oauth-definitions.ts +3 -1
- package/src/oauth/anthropic-routing.ts +1 -21
- package/src/oauth/anthropic.ts +38 -7
- package/src/oauth/callback-server.ts +27 -1
- package/src/oauth/chatgpt-device.ts +1 -1
- package/src/oauth/chatgpt-shared.ts +83 -0
- package/src/oauth/chatgpt.ts +8 -72
- package/src/oauth/dsh.ts +203 -0
- package/src/oauth/generic-account-failover.ts +40 -11
- package/src/oauth/generic-session-affinity.ts +125 -0
- package/src/oauth/index.ts +184 -109
- package/src/oauth/local-token-detect.ts +21 -1
- package/src/oauth/login-cli-errors.ts +44 -0
- package/src/oauth/login-cli.ts +69 -7
- package/src/oauth/login-flow-state.ts +371 -23
- package/src/oauth/meta-muse-errors.ts +41 -0
- package/src/oauth/meta-muse-keychain.ts +52 -0
- package/src/oauth/meta-muse.ts +51 -84
- package/src/oauth/model-discovery-auth.ts +3 -0
- package/src/oauth/pool-settings-capability.ts +4 -2
- package/src/oauth/refresh-flight-retirement.ts +48 -0
- package/src/oauth/session-affinity-key.ts +23 -0
- package/src/oauth/store-anthropic-instance.ts +9 -2
- package/src/oauth/store.ts +12 -5
- package/src/protocols/encoders/adapter-events.ts +6 -5
- package/src/protocols/encoders/messages.ts +9 -6
- package/src/protocols/provider-summary.ts +2 -1
- package/src/providers/api-key-cooldowns.ts +49 -0
- package/src/providers/api-key-resolve.ts +11 -6
- package/src/providers/api-key-response-ownership.ts +57 -0
- package/src/providers/api-key-selection.ts +31 -6
- package/src/providers/api-keys.ts +214 -3
- package/src/providers/claude-cli-usage.ts +96 -0
- package/src/providers/dsh-account-destination.ts +31 -0
- package/src/providers/dsh-account-models.ts +41 -0
- package/src/providers/gcp-credential-cleanup.ts +59 -0
- package/src/providers/key-failover.ts +54 -50
- package/src/providers/key-store.ts +7 -2
- package/src/providers/model-rename-fields.ts +3 -0
- package/src/providers/model-rename-migration.ts +2 -2
- package/src/providers/openai-tiers-destination.ts +11 -2
- package/src/providers/openai-tiers.ts +5 -12
- package/src/providers/opencode-go-transport.ts +3 -1
- package/src/providers/opencode-zen-rate-limit.ts +7 -2
- package/src/providers/quota/account-cache.ts +6 -5
- package/src/providers/quota/account-row.ts +34 -0
- package/src/providers/quota/antigravity.ts +28 -7
- package/src/providers/quota/dsh-account.ts +70 -0
- package/src/providers/quota/vendor-probes-oauth.ts +1 -93
- package/src/providers/quota-types.ts +2 -0
- package/src/providers/quota.ts +14 -20
- package/src/providers/registry/entries-core.ts +37 -8
- package/src/providers/registry/types.ts +1 -1
- package/src/providers/request-pacing.ts +77 -19
- package/src/providers/routed-config.ts +339 -0
- package/src/providers/service-tier.ts +2 -1
- package/src/quota/window-mapping.ts +5 -2
- package/src/responses/anthropic-progress.ts +34 -0
- package/src/responses/assistant-replay.ts +35 -0
- package/src/responses/compaction-history-framing.ts +65 -0
- package/src/responses/compaction.ts +6 -1
- package/src/responses/incomplete-reason.ts +31 -0
- package/src/responses/parser.ts +50 -5
- package/src/responses/reasoning-envelope.ts +4 -0
- package/src/responses/reasoning-replay-cache.ts +74 -6
- package/src/responses/reasoning-retention.ts +173 -0
- package/src/responses/retained-compaction.ts +46 -0
- package/src/responses/schema.ts +23 -0
- package/src/router.ts +8 -321
- package/src/routing/analytics.ts +7 -15
- package/src/routing/health.ts +37 -22
- package/src/routing/history/indexer.ts +6 -5
- package/src/routing/history/ingest.ts +6 -2
- package/src/routing/profile.ts +1 -1
- package/src/server/admission-model-scope.ts +17 -0
- package/src/server/auth-cors.ts +11 -0
- package/src/server/chat-completions.ts +7 -1
- package/src/server/chat-native-reasoning.ts +123 -0
- package/src/server/chat-native-sse.ts +110 -7
- package/src/server/chat-native.ts +76 -17
- package/src/server/claude-messages.ts +56 -414
- package/src/server/effort-policy.ts +1 -1
- package/src/server/images.ts +15 -2
- package/src/server/index/live-sideband.ts +3 -2
- package/src/server/index/model-alias-id.ts +36 -0
- package/src/server/index/optional-listeners.ts +2 -0
- package/src/server/index/serve-options.ts +20 -6
- package/src/server/index/startup-warnings.ts +2 -0
- package/src/server/index/websocket-handler.ts +18 -4
- package/src/server/index.ts +8 -8
- package/src/server/inference/advisor-diagnostics.ts +31 -0
- package/src/server/lifecycle.ts +13 -1
- package/src/server/management/advisor-routes.ts +15 -4
- package/src/server/management/claude-desktop-picker-routes.ts +1 -1
- package/src/server/management/combo-routes.ts +176 -50
- package/src/server/management/companion-routes.ts +1 -1
- package/src/server/management/config-routes.ts +75 -4
- package/src/server/management/cursor-integration-routes.ts +1 -1
- package/src/server/management/model-routes.ts +11 -6
- package/src/server/management/model-rows.ts +14 -0
- package/src/server/management/native-integration-routes.ts +2 -7
- package/src/server/management/native-reasoning-retention-routes.ts +41 -0
- package/src/server/management/oauth-account-routes.ts +87 -14
- package/src/server/management/provider-gcp-credential-routes.ts +29 -0
- package/src/server/management/provider-key-pacing-routes.ts +31 -0
- package/src/server/management/provider-overwrite-carry.ts +7 -0
- package/src/server/management/provider-routes.ts +25 -30
- package/src/server/management/route-registry.ts +10 -1
- package/src/server/management-api.ts +3 -1
- package/src/server/messages-native-tool-guard.ts +185 -0
- package/src/server/messages-native.ts +117 -24
- package/src/server/messages-shared.ts +431 -0
- package/src/server/relay.ts +1 -1
- package/src/server/request-log-terminal-status.ts +1 -1
- package/src/server/request-log.ts +6 -1
- package/src/server/responses/account-change-state.ts +8 -2
- package/src/server/responses/adapter-continuation.ts +47 -19
- package/src/server/responses/adapter-delivery.ts +72 -12
- package/src/server/responses/adapter-dispatch.ts +46 -3
- package/src/server/responses/advisor-retention.ts +117 -0
- package/src/server/responses/advisor-slot.ts +73 -41
- package/src/server/responses/anthropic-thinking-recovery.ts +153 -0
- package/src/server/responses/codex-ws-wire.ts +15 -8
- package/src/server/responses/combo-stream-preflight.ts +3 -2
- package/src/server/responses/compact.ts +303 -125
- package/src/server/responses/compaction-recovery.ts +20 -10
- package/src/server/responses/compaction-retention.ts +61 -0
- package/src/server/responses/context-overflow.ts +11 -6
- package/src/server/responses/core-auth.ts +6 -0
- package/src/server/responses/core-codex-account.ts +11 -1
- package/src/server/responses/core-combo-failure.ts +2 -0
- package/src/server/responses/core-combo.ts +121 -36
- package/src/server/responses/core-errors.ts +3 -3
- package/src/server/responses/core-lifetime.ts +8 -4
- package/src/server/responses/core-opaque-recovery.ts +35 -0
- package/src/server/responses/core-options.ts +7 -0
- package/src/server/responses/core-pipeline.ts +141 -0
- package/src/server/responses/core-replay.ts +23 -3
- package/src/server/responses/core.ts +2 -115
- package/src/server/responses/fetch-helpers.ts +73 -19
- package/src/server/responses/main-hard-lock-routing.ts +109 -0
- package/src/server/responses/native-response-control.ts +4 -2
- package/src/server/responses/passthrough-delivery.ts +3 -1
- package/src/server/responses/passthrough-dispatch.ts +15 -13
- package/src/server/responses/passthrough-execution.ts +3 -2
- package/src/server/responses/request-prepare.ts +77 -12
- package/src/server/responses/request-sidecar-auth.ts +2 -2
- package/src/server/responses/request-transport.ts +104 -27
- package/src/server/responses/response-effects.ts +2 -0
- package/src/server/responses/response-tool-ownership.ts +21 -0
- package/src/server/responses/run-turn-execution.ts +96 -30
- package/src/server/responses/sidecar-execution.ts +63 -9
- package/src/server/responses/sidecar-send-budget.ts +2 -2
- package/src/server/responses/terminal-guard.ts +2 -16
- package/src/server/responses-undeclared-tool-guard.ts +1 -1
- package/src/server/ws-bridge.ts +2 -0
- package/src/service/auth-preflight.ts +71 -0
- package/src/service/cli.ts +4 -2
- package/src/service/definition.ts +97 -0
- package/src/service/guards.ts +1 -61
- package/src/service/health-sentinel-linux.ts +112 -0
- package/src/service/health-sentinel-main.ts +76 -57
- package/src/service/health.ts +5 -89
- package/src/service/launchd.ts +27 -7
- package/src/service/logging.ts +72 -9
- package/src/service/repair.ts +2 -1
- package/src/service/state.ts +7 -8
- package/src/service/systemd.ts +1 -1
- package/src/service/windows-guarded-manager.ts +2 -1
- package/src/service/windows-ops.ts +1 -1
- package/src/service/windows-scheduler.ts +2 -7
- package/src/service/windows-taskxml.ts +2 -2
- package/src/service/windows-wscript.ts +14 -0
- package/src/service.ts +4 -2
- package/src/sidecar/auth.ts +2 -0
- package/src/types/config.ts +64 -3
- package/src/types/opencode-go.ts +61 -0
- package/src/types/opencode-zen.ts +35 -0
- package/src/types/provider.ts +32 -6
- package/src/types/request.ts +31 -2
- package/src/types/wire.ts +31 -37
- package/src/types.ts +2 -0
- package/src/update/npm-invocation.mjs +12 -2
- package/src/usage/cost.ts +48 -12
- package/src/usage/expected-prices.ts +3 -0
- package/src/usage/ledger-retention.ts +2 -1
- package/src/usage/ledger-scanner.ts +6 -5
- package/src/usage/log.ts +17 -8
- package/src/usage/summary.ts +30 -11
- package/src/usage/telemetry-contract.ts +1 -0
- package/src/usage/user-cost-overlays.ts +14 -19
- package/src/usage/user-cost-validation.ts +38 -0
- package/src/vision/eligibility.ts +13 -0
- package/src/web-search/anthropic-history.ts +59 -0
- package/src/web-search/loop.ts +236 -73
- package/src/web-search/progress-stream.ts +15 -2
- package/src/web-search/run-turn-loop.ts +9 -1
- package/gui/dist/assets/App-BjlttVLy.js +0 -58
- package/gui/dist/assets/App-CSJvmjNs.css +0 -1
- package/gui/dist/assets/index-BB6uK6tU.css +0 -1
- package/gui/dist/assets/index-BMssP4k3.js +0 -94
- package/gui/dist/assets/quota-summary-D8M1bc_R.js +0 -1
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { captureAnthropicRejectionPayloads, keepAnthropicReplayBlock } from "./anthropic-rejection-memo";
|
|
2
|
+
import { anthropicDeclaredTools } from "./anthropic-tool-catalog";
|
|
3
|
+
import { anthropicReplayContent, createAnthropicReplayCapture } from "./anthropic-replay";
|
|
4
|
+
import { withAnthropicProgressUpdates } from "./anthropic-progress";
|
|
1
5
|
import type { IncomingMeta, ProviderAdapter } from "./base";
|
|
2
6
|
import { createAdapterTierMetadata, type AdapterTierMetadata } from "../providers/fastwire";
|
|
3
7
|
import { ANTHROPIC_FAST_MODE_BETA, mergeAnthropicBetaHeader } from "../providers/anthropic-fast";
|
|
@@ -16,7 +20,7 @@ import type {
|
|
|
16
20
|
OcxToolResultMessage,
|
|
17
21
|
OcxUsage,
|
|
18
22
|
} from "../types";
|
|
19
|
-
import { isAllowedToolChoice, namespacedToolName, resolveToolChoiceWireName
|
|
23
|
+
import { isAllowedToolChoice, namespacedToolName, resolveToolChoiceWireName } from "../types";
|
|
20
24
|
import { ANTHROPIC_OAUTH_BETA, CLAUDE_CODE_SYSTEM_INSTRUCTION, applyClaudeToolPrefix, stripClaudeToolPrefix } from "../oauth/anthropic";
|
|
21
25
|
import { parseDataUrl } from "./image";
|
|
22
26
|
import { enforceAnthropicImageLimits } from "./anthropic-image-guard";
|
|
@@ -31,7 +35,7 @@ import { decodeServerSentEvents } from "../lib/sse-decoder";
|
|
|
31
35
|
import { isTranslatorBudgetExceededError, retainTranslatedEventBatch, type TranslatorBudget } from "../lib/translator-budget";
|
|
32
36
|
import { isReasoningEffortOmitted, modelRecordValue } from "../reasoning-effort";
|
|
33
37
|
import { applyAgentRouterLanguageFraming, isAgentRouterEndpoint } from "./agentrouter";
|
|
34
|
-
import { rejectsCombinedSampling, rejectsForcedToolChoice, rejectsSamplingParameters, supportsExplicitThinkingDisable, usesAdaptiveThinking, usesBetweenToolsFloor } from "./anthropic-model-contract";
|
|
38
|
+
import { claudeFamilyVersion, rejectsCombinedSampling, rejectsForcedToolChoice, rejectsSamplingParameters, supportsExplicitThinkingDisable, usesAdaptiveThinking, usesBetweenToolsFloor } from "./anthropic-model-contract";
|
|
35
39
|
|
|
36
40
|
/** Map a user content part to an Anthropic content block (text or image source). */
|
|
37
41
|
function toAnthropicContentPart(p: OcxContentPart): unknown {
|
|
@@ -282,7 +286,7 @@ function normalizeTtlOrdering(body: Record<string, unknown>): void {
|
|
|
282
286
|
}
|
|
283
287
|
}
|
|
284
288
|
|
|
285
|
-
function isLikelyRealAnthropicThinkingSignature(signature: string | undefined): signature is string {
|
|
289
|
+
export function isLikelyRealAnthropicThinkingSignature(signature: string | undefined): signature is string {
|
|
286
290
|
if (typeof signature !== "string" || signature.length < 16) return false;
|
|
287
291
|
if (/^(fc|call|msg|rs|resp|reasoning|item|ws|tool|func|function)[-_]/i.test(signature)) return false;
|
|
288
292
|
return /^[A-Za-z0-9+/_=-]+$/.test(signature);
|
|
@@ -312,11 +316,12 @@ function isAnthropicContentFilterStopReason(
|
|
|
312
316
|
}
|
|
313
317
|
|
|
314
318
|
/**
|
|
315
|
-
* Anthropic `refusal` / `content_filter` is a permanent sampling decision, not a disconnect
|
|
316
|
-
*
|
|
317
|
-
* `
|
|
318
|
-
*
|
|
319
|
-
* `
|
|
319
|
+
* Anthropic `refusal` / `content_filter` is a permanent sampling decision, not a disconnect
|
|
320
|
+
* (#4312). Codex does not read `incomplete_details.retryable`: it retries every
|
|
321
|
+
* `response.incomplete`. The explicit `retryable: false` verdict here is the marker the bridge
|
|
322
|
+
* uses to deliver the turn to a Responses client as a terminal `response.failed` instead
|
|
323
|
+
* (`src/bridge/terminal-refusal.ts`); a `done` with that stopReason carries no verdict and
|
|
324
|
+
* stays a plain incomplete. Usage is preserved: a filtered turn still consumed tokens.
|
|
320
325
|
* `max_tokens` stays a `done` so the client can continue from a legitimate truncation.
|
|
321
326
|
*/
|
|
322
327
|
function anthropicContentFilterIncomplete(
|
|
@@ -520,6 +525,16 @@ function streamedToolArgumentsParse(assembled: string): boolean {
|
|
|
520
525
|
}
|
|
521
526
|
}
|
|
522
527
|
|
|
528
|
+
/** A server tool's complete streamed input; undefined when it cannot be recovered. */
|
|
529
|
+
function serverToolInput(json: string): Record<string, unknown> | undefined {
|
|
530
|
+
try {
|
|
531
|
+
const input = JSON.parse(json) as unknown;
|
|
532
|
+
return isAnthropicRecord(input) ? input : undefined;
|
|
533
|
+
} catch {
|
|
534
|
+
return undefined;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
523
538
|
function anthropicKeyUsesBearer(provider: OcxProviderConfig): boolean {
|
|
524
539
|
return provider.apiKeyTransport === "bearer";
|
|
525
540
|
}
|
|
@@ -723,7 +738,16 @@ function orphanToolResultContent(msg: OcxToolResultMessage): string | unknown[]
|
|
|
723
738
|
function messagesToAnthropicFormat(
|
|
724
739
|
parsed: OcxParsedRequest,
|
|
725
740
|
toolNames: { toWire: (name: string) => string },
|
|
741
|
+
serverReplay?: ReadonlyMap<string, readonly Record<string, unknown>[]>,
|
|
726
742
|
): { system: string | undefined; messages: unknown[] } {
|
|
743
|
+
// The client's server-tool exchanges go back ahead of the block they preceded. Their anchors are
|
|
744
|
+
// unique in the caller's history (replayedAnthropicServerBlocks drops repeated ones); each is used once.
|
|
745
|
+
const pendingReplay = new Map(serverReplay);
|
|
746
|
+
const replayed = (anchor: string) => {
|
|
747
|
+
const blocks = pendingReplay.get(anchor) ?? [];
|
|
748
|
+
pendingReplay.delete(anchor);
|
|
749
|
+
return blocks;
|
|
750
|
+
};
|
|
727
751
|
// One allocator for the whole request: a tool_result must resolve to the SAME wire id its
|
|
728
752
|
// call got, and two distinct raw ids must never collapse into one. Conforming ids are claimed
|
|
729
753
|
// first so a rewritten id can never squat on an id another call legitimately owns.
|
|
@@ -738,8 +762,8 @@ function messagesToAnthropicFormat(
|
|
|
738
762
|
}
|
|
739
763
|
}
|
|
740
764
|
const toolCatalogNudge = buildNonOpenAIToolCatalogNudgeForTools(
|
|
741
|
-
parsed
|
|
742
|
-
|
|
765
|
+
anthropicDeclaredTools(parsed),
|
|
766
|
+
undefined,
|
|
743
767
|
tool => toolNames.toWire(namespacedToolName(tool.namespace, tool.name)),
|
|
744
768
|
);
|
|
745
769
|
const systemParts = [...(parsed.context.systemPrompt ?? []), ...(toolCatalogNudge ? [toolCatalogNudge] : [])];
|
|
@@ -769,27 +793,37 @@ function messagesToAnthropicFormat(
|
|
|
769
793
|
case "assistant": {
|
|
770
794
|
const aMsg = msg as OcxAssistantMessage;
|
|
771
795
|
const preface: unknown[] = [];
|
|
796
|
+
|
|
772
797
|
const toolUses: unknown[] = [];
|
|
798
|
+
const originalOrder: unknown[] = [];
|
|
799
|
+
const appendPreface = (block: unknown) => { preface.push(block); originalOrder.push(block); };
|
|
800
|
+
let signed = false;
|
|
773
801
|
const toolUseIds: string[] = [];
|
|
774
802
|
for (const part of aMsg.content) {
|
|
775
803
|
if (part.type === "text") {
|
|
776
804
|
const text = (part as OcxTextContent).text;
|
|
777
|
-
|
|
805
|
+
for (const b of replayed(`text:${text}`)) appendPreface(b);
|
|
806
|
+
if (text) appendPreface({ type: "text", text });
|
|
778
807
|
} else if (part.type === "thinking") {
|
|
779
808
|
const t = part as OcxThinkingContent;
|
|
809
|
+
// Server blocks that preceded this reasoning keep their place, even when it is dropped below.
|
|
810
|
+
for (const data of t.redacted ?? []) for (const b of replayed(`redacted:${data}`)) appendPreface(b);
|
|
811
|
+
for (const b of replayed(`thinking:${t.signature}`)) appendPreface(b);
|
|
780
812
|
// History minted under another serving identity (or already rejected as opaque) is not
|
|
781
813
|
// this destination's to verify: drop its opaque blocks, as the Responses passthrough does.
|
|
782
814
|
if (parsed._stripReasoningEncryptedContent === true) continue;
|
|
783
815
|
// Redacted blocks replay verbatim FIRST (they preceded the visible thinking block
|
|
784
816
|
// in the original stream order preserved by the bridge envelope).
|
|
785
817
|
for (const data of t.redacted ?? []) {
|
|
786
|
-
|
|
818
|
+
appendPreface({ type: "redacted_thinking", data });
|
|
787
819
|
}
|
|
788
820
|
if (isLikelyRealAnthropicThinkingSignature(t.signature)) {
|
|
789
|
-
|
|
821
|
+
signed = true;
|
|
822
|
+
appendPreface({ type: "thinking", thinking: t.thinking, signature: t.signature });
|
|
790
823
|
}
|
|
791
824
|
} else if (part.type === "toolCall") {
|
|
792
825
|
const tc = part as OcxToolCall;
|
|
826
|
+
for (const b of replayed(`call:${tc.id}`)) appendPreface(b);
|
|
793
827
|
const flatName = namespacedToolName(tc.namespace, tc.name);
|
|
794
828
|
// Normalized here, and identically for the matching tool_result above, so a history
|
|
795
829
|
// replayed from another provider path keeps its call/result pairing (#1767).
|
|
@@ -797,16 +831,26 @@ function messagesToAnthropicFormat(
|
|
|
797
831
|
// rejects. An unrepresentable call becomes text instead, and its result follows it there.
|
|
798
832
|
const wireCallId = callIds.allocate(tc.id);
|
|
799
833
|
if (wireCallId === undefined) {
|
|
800
|
-
|
|
834
|
+
appendPreface({ type: "text", text: unrepresentableToolCallText(tc, toolNames.toWire(flatName)) });
|
|
801
835
|
continue;
|
|
802
836
|
}
|
|
803
837
|
toolUseIds.push(wireCallId);
|
|
804
|
-
|
|
838
|
+
const block = { type: "tool_use", id: wireCallId, name: toolNames.toWire(flatName), input: tc.arguments };
|
|
839
|
+
toolUses.push(block);
|
|
840
|
+
originalOrder.push(block);
|
|
805
841
|
}
|
|
806
842
|
}
|
|
807
843
|
// Anthropic treats text/thinking after tool_use as ending the tool turn, which makes
|
|
808
844
|
// earlier tool_use ids look unpaired (#620 / common multi-step history shape).
|
|
809
|
-
const
|
|
845
|
+
const captured = anthropicReplayContent(aMsg);
|
|
846
|
+
if (captured) {
|
|
847
|
+
const expected = toolUses as Array<{ id: string; name: string }>;
|
|
848
|
+
const actual = captured.filter(block => block.type === "tool_use");
|
|
849
|
+
if (actual.length !== expected.length || actual.some((block, index) => block.id !== expected[index]?.id || block.name !== expected[index]?.name)) {
|
|
850
|
+
throw new Error("Anthropic search replay tool identity changed");
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
const content = (captured ?? (signed ? originalOrder : [...preface, ...toolUses])).filter(block => keepAnthropicReplayBlock(parsed, block as Record<string, unknown>));
|
|
810
854
|
if (content.length === 0) break;
|
|
811
855
|
messages.push({ role: "assistant", content });
|
|
812
856
|
if (toolUseIds.length > 0) {
|
|
@@ -869,9 +913,7 @@ function messagesToAnthropicFormat(
|
|
|
869
913
|
|
|
870
914
|
function toolsToAnthropicFormat(parsed: OcxParsedRequest, toolNames: { toWire: (name: string) => string }): unknown[] | undefined {
|
|
871
915
|
if (!parsed.context.tools || parsed.context.tools.length === 0) return undefined;
|
|
872
|
-
const tools =
|
|
873
|
-
? parsed.context.tools.filter(toolChoiceToolPredicate(parsed.options.toolChoice, parsed.context.tools))
|
|
874
|
-
: parsed.context.tools;
|
|
916
|
+
const tools = anthropicDeclaredTools(parsed);
|
|
875
917
|
if (tools.length === 0) return undefined;
|
|
876
918
|
const converted = tools.map(t => ({
|
|
877
919
|
name: toolNames.toWire(namespacedToolName(t.namespace, t.name)),
|
|
@@ -887,6 +929,18 @@ function toolsToAnthropicFormat(parsed: OcxParsedRequest, toolNames: { toWire: (
|
|
|
887
929
|
return converted;
|
|
888
930
|
}
|
|
889
931
|
|
|
932
|
+
/**
|
|
933
|
+
* Appends the Claude client's typed web tools (`parsed._anthropicServerTools`) so Anthropic runs
|
|
934
|
+
* them server-side. A same-named function tool wins: the web-search sidecar's `web_search` keeps
|
|
935
|
+
* priority, and Anthropic rejects duplicate tool names.
|
|
936
|
+
*/
|
|
937
|
+
function withAnthropicServerTools(tools: unknown[] | undefined, parsed: OcxParsedRequest): unknown[] | undefined {
|
|
938
|
+
const serverTools = parsed._anthropicServerTools?.filter(t => !parsed.context.tools?.some(f => f.name === t.name));
|
|
939
|
+
if (!serverTools?.length) return tools;
|
|
940
|
+
// The caller's breakpoints are dropped on this lane; applyPromptCaching places its own.
|
|
941
|
+
return [...(tools ?? []), ...serverTools.map(t => ({ ...t, cache_control: undefined }))];
|
|
942
|
+
}
|
|
943
|
+
|
|
890
944
|
function normalizeAnthropicInputSchema(schema: unknown): Record<string, unknown> {
|
|
891
945
|
const stripped = stripResponsesOnlyEncryptedMarker(schema);
|
|
892
946
|
const obj = stripped && typeof stripped === "object" && !Array.isArray(stripped)
|
|
@@ -952,7 +1006,8 @@ function normalizeAnthropicInputSchema(schema: unknown): Record<string, unknown>
|
|
|
952
1006
|
export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetention?: "none" | "short" | "long"): ProviderAdapter {
|
|
953
1007
|
const isOAuth = provider.authMode === "oauth";
|
|
954
1008
|
const toolNames = buildToolNameTransforms(provider);
|
|
955
|
-
|
|
1009
|
+
let progressUpdates = false;
|
|
1010
|
+
return withAnthropicProgressUpdates({
|
|
956
1011
|
name: "anthropic",
|
|
957
1012
|
|
|
958
1013
|
formatErrorBody: formatAnthropicErrorBody,
|
|
@@ -965,7 +1020,9 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
965
1020
|
throw new Error("anthropic provider requires a non-empty apiKey (authMode: key)");
|
|
966
1021
|
}
|
|
967
1022
|
|
|
968
|
-
|
|
1023
|
+
// Only api.anthropic.com runs Anthropic's server tools, so only it gets their history back.
|
|
1024
|
+
const { system, messages } = messagesToAnthropicFormat(parsed, toolNames,
|
|
1025
|
+
usesNativeAnthropicEndpoint(provider) ? parsed._anthropicServerReplay : undefined);
|
|
969
1026
|
// Before image normalization, so the framing block is present for every downstream pass.
|
|
970
1027
|
if (isAgentRouterEndpoint(provider.baseUrl)) applyAgentRouterLanguageFraming(messages);
|
|
971
1028
|
// Primary image layer: resize/re-encode to fit Anthropic limits without dropping
|
|
@@ -978,7 +1035,9 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
978
1035
|
// Anthropic rejects many-image requests (>20 images) carrying any image over
|
|
979
1036
|
// 2000px per side; see anthropic-image-guard.ts for the full limit policy.
|
|
980
1037
|
enforceAnthropicImageLimits(messages);
|
|
981
|
-
const
|
|
1038
|
+
const converted = toolsToAnthropicFormat(parsed, toolNames);
|
|
1039
|
+
// A third-party Anthropic-compatible endpoint may not implement Anthropic's server tools.
|
|
1040
|
+
const tools = usesNativeAnthropicEndpoint(provider) ? withAnthropicServerTools(converted, parsed) : converted;
|
|
982
1041
|
|
|
983
1042
|
// Codex never sends `max_output_tokens`, so the omitted-limit default decides how
|
|
984
1043
|
// long a Claude answer may run. Honor the provider's configured output budget
|
|
@@ -1017,6 +1076,8 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1017
1076
|
// anyway, and thinking shares the caller's `max_tokens` — which truncates a small-budget
|
|
1018
1077
|
// request before it can emit its stop sequence (#545). Say "disabled" out loud where the
|
|
1019
1078
|
// model both defaults to thinking and accepts being told not to.
|
|
1079
|
+
const family = claudeFamilyVersion(parsed.modelId);
|
|
1080
|
+
progressUpdates = usesNativeAnthropicEndpoint(provider) && family?.family === "opus" && family.major === 5 && family.minor === 5;
|
|
1020
1081
|
const effectiveReasoning = parsed.options.reasoning ?? defaultReasoningEffort(provider, parsed.modelId);
|
|
1021
1082
|
if (effectiveReasoning === "none" && supportsExplicitThinkingDisable(parsed.modelId)) {
|
|
1022
1083
|
body.thinking = { type: "disabled" };
|
|
@@ -1034,7 +1095,8 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1034
1095
|
// default 8192-token request can spend everything on thought and return empty text.
|
|
1035
1096
|
// Opus 4.7+ defaults `display` to "omitted": the stream then carries signature-only
|
|
1036
1097
|
// thinking blocks, so a Chat client sees minutes of heartbeats and no reasoning delta
|
|
1037
|
-
// during a long think (#5824).
|
|
1098
|
+
// during a long think (#5824). Opus 5.5 uses the documented updates discriminator;
|
|
1099
|
+
// other models request summarized thinking unless the caller hides it.
|
|
1038
1100
|
body.thinking = parsed.options.hideThinkingSummary
|
|
1039
1101
|
? { type: "adaptive" }
|
|
1040
1102
|
: { type: "adaptive", display: "summarized" };
|
|
@@ -1082,6 +1144,8 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1082
1144
|
delete body.top_p;
|
|
1083
1145
|
}
|
|
1084
1146
|
|
|
1147
|
+
if (progressUpdates) body.thinking = { type: "adaptive", display: "updates" };
|
|
1148
|
+
|
|
1085
1149
|
if (rejectsSamplingParameters(parsed.modelId)) {
|
|
1086
1150
|
// Opus 4.7+, Sonnet 5+, Haiku 5.5+ and Fable 400 on non-default sampling, with or without
|
|
1087
1151
|
// thinking (anthropic-model-contract.ts).
|
|
@@ -1155,7 +1219,7 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1155
1219
|
if (isOAuth) applyAnthropicOAuthAuth(headers, provider.apiKey);
|
|
1156
1220
|
else applyAnthropicKeyAuth(headers, provider);
|
|
1157
1221
|
if (provider.headers) Object.assign(headers, provider.headers);
|
|
1158
|
-
mergeAnthropicBetaHeader(headers, fastSpeed?.betas ?? []);
|
|
1222
|
+
mergeAnthropicBetaHeader(headers, [...(fastSpeed?.betas ?? []), ...(progressUpdates ? ["thinking-display-updates-2026-08-18"] : [])]);
|
|
1159
1223
|
|
|
1160
1224
|
// Prompt caching: native Anthropic supports top-level automatic caching, which
|
|
1161
1225
|
// follows the moving final block across turns. Keep one breakpoint slot free for it.
|
|
@@ -1170,7 +1234,7 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1170
1234
|
enforceCacheControlLimit(body, explicitLimit);
|
|
1171
1235
|
normalizeTtlOrdering(body);
|
|
1172
1236
|
|
|
1173
|
-
|
|
1237
|
+
const request = {
|
|
1174
1238
|
url,
|
|
1175
1239
|
method: "POST",
|
|
1176
1240
|
headers,
|
|
@@ -1184,6 +1248,8 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1184
1248
|
fastSpeed?.value ?? null,
|
|
1185
1249
|
),
|
|
1186
1250
|
};
|
|
1251
|
+
captureAnthropicRejectionPayloads(request, body, incoming?.translatorBudget);
|
|
1252
|
+
return request;
|
|
1187
1253
|
},
|
|
1188
1254
|
|
|
1189
1255
|
async *parseStream(
|
|
@@ -1196,6 +1262,7 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1196
1262
|
return;
|
|
1197
1263
|
}
|
|
1198
1264
|
|
|
1265
|
+
const replayCapture = createAnthropicReplayCapture(response, budget);
|
|
1199
1266
|
const budgetEncoder = new TextEncoder();
|
|
1200
1267
|
let currentBlockType = "";
|
|
1201
1268
|
let currentToolCallId = "";
|
|
@@ -1205,6 +1272,8 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1205
1272
|
let pendingStopReason: string | undefined;
|
|
1206
1273
|
let emittedDone = false;
|
|
1207
1274
|
let sawVisibleText = false;
|
|
1275
|
+
/** The open server-side web_search / web_fetch call, until its result block. */
|
|
1276
|
+
let serverSearch: { id: string; json: string; streaming: boolean } | undefined;
|
|
1208
1277
|
|
|
1209
1278
|
const emitDone = function* (): Generator<AdapterEvent> {
|
|
1210
1279
|
if (emittedDone) return;
|
|
@@ -1222,17 +1291,19 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1222
1291
|
return;
|
|
1223
1292
|
}
|
|
1224
1293
|
// Refusal / content_filter must not look like a dropped stream. `done` with that
|
|
1225
|
-
// stopReason
|
|
1226
|
-
// the same refusal
|
|
1294
|
+
// stopReason carries no verdict, so the bridge could not tell it from a retryable
|
|
1295
|
+
// incomplete and Codex would re-send the same refusal (#4312).
|
|
1227
1296
|
if (isAnthropicContentFilterStopReason(pendingStopReason)) {
|
|
1228
1297
|
yield anthropicContentFilterIncomplete(pendingStopReason, usageFromAnthropic(pendingUsage));
|
|
1229
1298
|
return;
|
|
1230
1299
|
}
|
|
1231
|
-
|
|
1300
|
+
const done: AdapterEvent = {
|
|
1232
1301
|
type: "done",
|
|
1233
1302
|
usage: usageFromAnthropic(pendingUsage),
|
|
1234
1303
|
...(pendingStopReason ? { stopReason: pendingStopReason } : {}),
|
|
1235
1304
|
};
|
|
1305
|
+
replayCapture?.finish(done);
|
|
1306
|
+
yield done;
|
|
1236
1307
|
};
|
|
1237
1308
|
|
|
1238
1309
|
try {
|
|
@@ -1252,6 +1323,7 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1252
1323
|
try {
|
|
1253
1324
|
parsed = JSON.parse(payload);
|
|
1254
1325
|
} catch {
|
|
1326
|
+
replayCapture?.invalidate();
|
|
1255
1327
|
debugDroppedFrame("anthropic", payload);
|
|
1256
1328
|
continue;
|
|
1257
1329
|
}
|
|
@@ -1259,10 +1331,12 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1259
1331
|
// it and the `data.type` read below crashed the stream. Drop a non-record frame the same
|
|
1260
1332
|
// way an unparseable one is dropped, so the message_stop check still governs the outcome.
|
|
1261
1333
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1334
|
+
replayCapture?.invalidate();
|
|
1262
1335
|
debugDroppedFrame("anthropic", payload);
|
|
1263
1336
|
continue;
|
|
1264
1337
|
}
|
|
1265
1338
|
const data = parsed as Record<string, unknown>;
|
|
1339
|
+
replayCapture?.accept({ ...data, type: record.event || data.type });
|
|
1266
1340
|
|
|
1267
1341
|
switch (record.event || data.type) {
|
|
1268
1342
|
case "message_start": {
|
|
@@ -1273,8 +1347,11 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1273
1347
|
break;
|
|
1274
1348
|
}
|
|
1275
1349
|
case "content_block_start": {
|
|
1276
|
-
const block = data.content_block as { type: string; id?: string; name?: unknown; data?: string; thinking?: string } | undefined;
|
|
1350
|
+
const block = data.content_block as { type: string; id?: string; name?: unknown; data?: string; thinking?: string; tool_use_id?: unknown; content?: unknown } | undefined;
|
|
1277
1351
|
if (!block) break;
|
|
1352
|
+
// Even an unmodeled server tool or empty block is semantic progress.
|
|
1353
|
+
// Fence replays before a later refusal; unknown blocks must not look like pings.
|
|
1354
|
+
yield { type: "heartbeat", replayUnsafe: true };
|
|
1278
1355
|
currentBlockType = block.type;
|
|
1279
1356
|
if (block.type === "thinking") {
|
|
1280
1357
|
// Preserve even a display:omitted block boundary. The bridge can then
|
|
@@ -1288,6 +1365,36 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1288
1365
|
budget.openCall(currentToolCallId);
|
|
1289
1366
|
yield { type: "tool_call_start", id: currentToolCallId, name: currentToolCallName };
|
|
1290
1367
|
}
|
|
1368
|
+
if (block.type === "server_tool_use" && (block.name === "web_search" || block.name === "web_fetch") && typeof block.id === "string") {
|
|
1369
|
+
// Only the input (query / url) is collected here (input_json_delta below). The cell
|
|
1370
|
+
// opens at its result: a call Anthropic defers beside a client tool_use has
|
|
1371
|
+
// no result in this response and must not surface as a completed search.
|
|
1372
|
+
serverSearch = { id: block.id, json: "", streaming: true };
|
|
1373
|
+
}
|
|
1374
|
+
if ((block.type === "web_search_tool_result" || block.type === "web_fetch_tool_result") && typeof block.tool_use_id === "string") {
|
|
1375
|
+
// The begin/end pair the sidecar emits, plus both blocks verbatim so the Claude client holds a
|
|
1376
|
+
// replayable copy. Without this response's matching call and complete input, drop the
|
|
1377
|
+
// exchange instead of inventing a call that could poison the client's next request.
|
|
1378
|
+
const fetch = block.type === "web_fetch_tool_result";
|
|
1379
|
+
const input = serverSearch?.id === block.tool_use_id ? serverToolInput(serverSearch.json) : undefined;
|
|
1380
|
+
if (!input) break;
|
|
1381
|
+
const hits = Array.isArray(block.content) ? block.content as Array<{ url?: unknown; title?: unknown }> : undefined;
|
|
1382
|
+
yield { type: "web_search_call_begin", id: block.tool_use_id };
|
|
1383
|
+
yield {
|
|
1384
|
+
type: "web_search_call_end",
|
|
1385
|
+
id: block.tool_use_id,
|
|
1386
|
+
queries: typeof input.query === "string" && input.query.length > 0 ? [input.query] : [],
|
|
1387
|
+
// A failed call carries one error object instead of the hit list / fetched page.
|
|
1388
|
+
status: (fetch ? (block.content as { type?: unknown } | undefined)?.type === "web_fetch_result" : hits) ? "completed" : "failed",
|
|
1389
|
+
sources: (hits ?? []).flatMap(h => typeof h.url === "string"
|
|
1390
|
+
? [{ url: h.url, ...(typeof h.title === "string" ? { title: h.title } : {}) }] : []),
|
|
1391
|
+
anthropic: {
|
|
1392
|
+
use: { type: "server_tool_use", id: block.tool_use_id, name: fetch ? "web_fetch" : "web_search", input },
|
|
1393
|
+
result: block as Record<string, unknown>,
|
|
1394
|
+
},
|
|
1395
|
+
};
|
|
1396
|
+
serverSearch = undefined;
|
|
1397
|
+
}
|
|
1291
1398
|
if (block.type === "redacted_thinking" && typeof block.data === "string") {
|
|
1292
1399
|
// Opaque redacted block: replay verbatim later or tool-use turns 400.
|
|
1293
1400
|
yield { type: "redacted_thinking", data: block.data };
|
|
@@ -1331,10 +1438,15 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1331
1438
|
throw error;
|
|
1332
1439
|
}
|
|
1333
1440
|
yield { type: "tool_call_delta", arguments: delta.partial_json };
|
|
1441
|
+
} else if (delta.type === "input_json_delta" && typeof delta.partial_json === "string" && serverSearch?.streaming
|
|
1442
|
+
&& serverSearch.json.length < 4096) {
|
|
1443
|
+
// Capped: input that cannot be recovered drops its exchange instead of inventing a call.
|
|
1444
|
+
serverSearch.json += delta.partial_json.slice(0, 4096 - serverSearch.json.length);
|
|
1334
1445
|
}
|
|
1335
1446
|
break;
|
|
1336
1447
|
}
|
|
1337
1448
|
case "content_block_stop": {
|
|
1449
|
+
if (serverSearch) serverSearch.streaming = false;
|
|
1338
1450
|
if (currentBlockType === "tool_use") {
|
|
1339
1451
|
// The non-stream path repairs an unparseable payload in toolUseArguments(); the
|
|
1340
1452
|
// stream cannot, because the fragments are already downstream. Fail the turn
|
|
@@ -1376,8 +1488,13 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1376
1488
|
break;
|
|
1377
1489
|
}
|
|
1378
1490
|
case "error": {
|
|
1379
|
-
const err = data.error as { message?:
|
|
1380
|
-
yield { type: "error", message: err?.message
|
|
1491
|
+
const err = data.error as { message?: unknown; type?: unknown; code?: unknown; status?: unknown } | undefined;
|
|
1492
|
+
yield { type: "error", message: typeof err?.message === "string" ? err.message : "Anthropic error",
|
|
1493
|
+
...(typeof err?.type === "string" ? { errorType: err.type } : {}),
|
|
1494
|
+
...(typeof err?.code === "string" ? { code: err.code } : {}),
|
|
1495
|
+
...(typeof err?.status === "number" && Number.isInteger(err.status) && err.status >= 400 && err.status <= 599
|
|
1496
|
+
? { status: err.status } : {}),
|
|
1497
|
+
};
|
|
1381
1498
|
return;
|
|
1382
1499
|
}
|
|
1383
1500
|
}
|
|
@@ -1396,6 +1513,7 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1396
1513
|
// one-terminal-event contract for consumers that keep draining the generator.
|
|
1397
1514
|
return;
|
|
1398
1515
|
} finally {
|
|
1516
|
+
replayCapture?.discard();
|
|
1399
1517
|
if (currentToolCallId) budget.closeCall(currentToolCallId);
|
|
1400
1518
|
}
|
|
1401
1519
|
if (!emittedDone) {
|
|
@@ -1418,7 +1536,7 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1418
1536
|
}
|
|
1419
1537
|
// Same rule as emitDone: refusal / content_filter is a permanent decision, not a
|
|
1420
1538
|
// disconnect. This branch bypasses emitDone, so the check has to be repeated here
|
|
1421
|
-
// or the EOF route
|
|
1539
|
+
// or the EOF route emits a verdict-less `done` the bridge cannot make terminal (#4312).
|
|
1422
1540
|
if (isAnthropicContentFilterStopReason(pendingStopReason)) {
|
|
1423
1541
|
emittedDone = true;
|
|
1424
1542
|
yield anthropicContentFilterIncomplete(pendingStopReason, usageFromAnthropic(pendingUsage));
|
|
@@ -1570,5 +1688,5 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti
|
|
|
1570
1688
|
}
|
|
1571
1689
|
},
|
|
1572
1690
|
|
|
1573
|
-
};
|
|
1691
|
+
}, () => progressUpdates);
|
|
1574
1692
|
}
|
package/src/adapters/base.ts
CHANGED
|
@@ -22,6 +22,8 @@ export interface IncomingMeta {
|
|
|
22
22
|
* the same pacing queue and custom provider fetch seam.
|
|
23
23
|
*/
|
|
24
24
|
providerFetch?: typeof globalThis.fetch;
|
|
25
|
+
/** Synchronous selection fence for adapter-owned sends; call after async setup, before dispatch. */
|
|
26
|
+
beforePhysicalSend?: () => void;
|
|
25
27
|
/**
|
|
26
28
|
* Image-normalization ladder bias for upstream-413 tightened retries: every image
|
|
27
29
|
* starts one tier lower (devlog/260714_image_normalization_pipeline/030). Consumed by
|