@yansigit/opencodex 2.31.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/AGENTS_INSTALL.md +109 -0
- package/LICENSE +21 -0
- package/README.md +303 -0
- package/assets/architecture.png +0 -0
- package/assets/banner.png +0 -0
- package/assets/claude-code-models.gif +0 -0
- package/assets/codex-app-picker.png +0 -0
- package/bin/ocx.mjs +587 -0
- package/bin/package-main.mjs +9 -0
- package/gui/dist/assets/index-BNJ7r4Gd.js +102 -0
- package/gui/dist/assets/index-CGoDO3uO.css +1 -0
- package/gui/dist/favicon.png +0 -0
- package/gui/dist/icons.svg +24 -0
- package/gui/dist/index.html +25 -0
- package/gui/dist/logo.png +0 -0
- package/gui/dist/provider-icons/alibaba-color.svg +1 -0
- package/gui/dist/provider-icons/antigravity-color.svg +1 -0
- package/gui/dist/provider-icons/claude-color.svg +1 -0
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -0
- package/gui/dist/provider-icons/cursor-color.svg +2 -0
- package/gui/dist/provider-icons/deepseek-color.svg +1 -0
- package/gui/dist/provider-icons/discord.svg +1 -0
- package/gui/dist/provider-icons/firepass-color.svg +1 -0
- package/gui/dist/provider-icons/fireworks-color.svg +1 -0
- package/gui/dist/provider-icons/gemini-color.svg +1 -0
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
- package/gui/dist/provider-icons/grok.svg +1 -0
- package/gui/dist/provider-icons/groq-color.svg +1 -0
- package/gui/dist/provider-icons/huggingface-color.svg +1 -0
- package/gui/dist/provider-icons/kimi-color.svg +1 -0
- package/gui/dist/provider-icons/kiro-color.svg +15 -0
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
- package/gui/dist/provider-icons/mistral-color.svg +1 -0
- package/gui/dist/provider-icons/moonshot-color.svg +1 -0
- package/gui/dist/provider-icons/nvidia-color.svg +1 -0
- package/gui/dist/provider-icons/ollama-color.svg +1 -0
- package/gui/dist/provider-icons/openai.svg +1 -0
- package/gui/dist/provider-icons/opencode.svg +2 -0
- package/gui/dist/provider-icons/openrouter-color.svg +1 -0
- package/gui/dist/provider-icons/pi.svg +21 -0
- package/gui/dist/provider-icons/qianfan-color.svg +1 -0
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
- package/gui/dist/provider-icons/telegram.svg +1 -0
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/vllm-color.svg +1 -0
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
- package/package.json +108 -0
- package/src/AGENTS.md +28 -0
- package/src/adapters/anthropic-image-guard.ts +251 -0
- package/src/adapters/anthropic-image-normalize.ts +518 -0
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +1327 -0
- package/src/adapters/azure.ts +36 -0
- package/src/adapters/base.ts +121 -0
- package/src/adapters/client-fingerprint.ts +65 -0
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/arg-codec.ts +38 -0
- package/src/adapters/cursor/arg-normalize.ts +104 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +288 -0
- package/src/adapters/cursor/discovery.ts +333 -0
- package/src/adapters/cursor/effort-map.ts +151 -0
- package/src/adapters/cursor/exec-policy.ts +88 -0
- package/src/adapters/cursor/framing.ts +250 -0
- package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/kv-store.ts +52 -0
- package/src/adapters/cursor/live-models.ts +269 -0
- package/src/adapters/cursor/live-smoke-gate.ts +41 -0
- package/src/adapters/cursor/live-transport.ts +1653 -0
- package/src/adapters/cursor/mcp-config.ts +42 -0
- package/src/adapters/cursor/mcp-manager.ts +333 -0
- package/src/adapters/cursor/message-mapper.ts +49 -0
- package/src/adapters/cursor/native-exec-common.ts +76 -0
- package/src/adapters/cursor/native-exec-desktop.ts +184 -0
- package/src/adapters/cursor/native-exec-fs.ts +332 -0
- package/src/adapters/cursor/native-exec-mcp.ts +153 -0
- package/src/adapters/cursor/native-exec-network.ts +43 -0
- package/src/adapters/cursor/native-exec-shell.ts +547 -0
- package/src/adapters/cursor/native-exec-tools.ts +118 -0
- package/src/adapters/cursor/native-exec.ts +663 -0
- package/src/adapters/cursor/protobuf-events.ts +1381 -0
- package/src/adapters/cursor/protobuf-request.ts +1032 -0
- package/src/adapters/cursor/request-builder.ts +461 -0
- package/src/adapters/cursor/thread-continuity.ts +67 -0
- package/src/adapters/cursor/tool-definitions.ts +735 -0
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport-retry.ts +132 -0
- package/src/adapters/cursor/transport.ts +79 -0
- package/src/adapters/cursor/types.ts +79 -0
- package/src/adapters/cursor.ts +322 -0
- package/src/adapters/google-antigravity-hosts.ts +48 -0
- package/src/adapters/google-antigravity-replay.ts +827 -0
- package/src/adapters/google-antigravity-tools.ts +105 -0
- package/src/adapters/google-antigravity-wire.ts +141 -0
- package/src/adapters/google-errors.ts +92 -0
- package/src/adapters/google-http.ts +460 -0
- package/src/adapters/google-tool-schema.ts +238 -0
- package/src/adapters/google-truncation.ts +24 -0
- package/src/adapters/google-wire-compiler.ts +232 -0
- package/src/adapters/google.ts +1377 -0
- package/src/adapters/identity.ts +77 -0
- package/src/adapters/image.ts +23 -0
- package/src/adapters/kiro-constants.ts +16 -0
- package/src/adapters/kiro-errors.ts +208 -0
- package/src/adapters/kiro-events.ts +197 -0
- package/src/adapters/kiro-images.ts +129 -0
- package/src/adapters/kiro-retry.ts +312 -0
- package/src/adapters/kiro-thinking.ts +112 -0
- package/src/adapters/kiro-tool-fallback.ts +36 -0
- package/src/adapters/kiro-tools.ts +224 -0
- package/src/adapters/kiro-truncation.ts +33 -0
- package/src/adapters/kiro-wire.ts +129 -0
- package/src/adapters/kiro.ts +1936 -0
- package/src/adapters/mimo-free.ts +280 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1980 -0
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +1911 -0
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/run-turn-queue.ts +114 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +154 -0
- package/src/adapters/upstream-http-error.ts +48 -0
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +1986 -0
- package/src/chat/inbound.ts +319 -0
- package/src/chat/outbound.ts +821 -0
- package/src/claude/agents-inject.ts +266 -0
- package/src/claude/alias.ts +149 -0
- package/src/claude/auth-detect.ts +229 -0
- package/src/claude/auth-mode-migration.ts +32 -0
- package/src/claude/auth-mode.ts +62 -0
- package/src/claude/context-windows.ts +205 -0
- package/src/claude/desktop-3p-guard.ts +35 -0
- package/src/claude/desktop-3p-paths.ts +84 -0
- package/src/claude/desktop-3p.ts +615 -0
- package/src/claude/desktop-health.ts +26 -0
- package/src/claude/desktop-profile.ts +263 -0
- package/src/claude/gateway-cache.ts +107 -0
- package/src/claude/inbound-debug.ts +163 -0
- package/src/claude/inbound.ts +578 -0
- package/src/claude/model-info.ts +174 -0
- package/src/claude/outbound.ts +926 -0
- package/src/cli/access.ts +108 -0
- package/src/cli/account-api.ts +302 -0
- package/src/cli/account-auth.ts +250 -0
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +737 -0
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +299 -0
- package/src/cli/agent-driven.ts +70 -0
- package/src/cli/agent.ts +290 -0
- package/src/cli/catalog-prewarm.ts +27 -0
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +213 -0
- package/src/cli/claude.ts +355 -0
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +47 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +127 -0
- package/src/cli/config-command.ts +209 -0
- package/src/cli/debug.ts +228 -0
- package/src/cli/dispatch.ts +585 -0
- package/src/cli/doctor.ts +1202 -0
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +213 -0
- package/src/cli/help.ts +101 -0
- package/src/cli/index.ts +973 -0
- package/src/cli/init.ts +211 -0
- package/src/cli/integrations.ts +260 -0
- package/src/cli/interactive-confirm.ts +133 -0
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +245 -0
- package/src/cli/models.ts +422 -0
- package/src/cli/observe.ts +206 -0
- package/src/cli/opencode.ts +588 -0
- package/src/cli/provider-replit.ts +232 -0
- package/src/cli/provider-runtime.ts +179 -0
- package/src/cli/provider.ts +492 -0
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +422 -0
- package/src/cli/replit-gateway-key-input.ts +138 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +328 -0
- package/src/cli/star-prompt.ts +211 -0
- package/src/cli/status-oauth.ts +78 -0
- package/src/cli/status.ts +328 -0
- package/src/cli/system-command.ts +112 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +199 -0
- package/src/cli/v2.ts +268 -0
- package/src/cli.ts +10 -0
- package/src/clients/config-export.ts +1704 -0
- package/src/codex/account-id.ts +34 -0
- package/src/codex/account-label.ts +47 -0
- package/src/codex/account-lifecycle.ts +172 -0
- package/src/codex/account-namespace-match.ts +63 -0
- package/src/codex/account-namespaces.ts +195 -0
- package/src/codex/account-pause.ts +20 -0
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-runtime-state.ts +31 -0
- package/src/codex/account-store.ts +544 -0
- package/src/codex/account-usability.ts +43 -0
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/agent-roles-sync.ts +225 -0
- package/src/codex/agent-roles.ts +238 -0
- package/src/codex/app-server-processes.ts +1143 -0
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +2147 -0
- package/src/codex/auth-collision.ts +109 -0
- package/src/codex/auth-context.ts +665 -0
- package/src/codex/autostart-health.ts +156 -0
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +436 -0
- package/src/codex/catalog/bundled.ts +549 -0
- package/src/codex/catalog/effort.ts +446 -0
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +664 -0
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +650 -0
- package/src/codex/catalog/provider-fetch.ts +2064 -0
- package/src/codex/catalog/sync.ts +1883 -0
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +14 -0
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +651 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/data/upstream-models.json +830 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/exec-invocation.ts +22 -0
- package/src/codex/features.ts +1566 -0
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +407 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +108 -0
- package/src/codex/history-provider.ts +979 -0
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/home.ts +206 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1733 -0
- package/src/codex/injected-marker.ts +106 -0
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +225 -0
- package/src/codex/log-guard/inspect.ts +506 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +56 -0
- package/src/codex/main-account.ts +68 -0
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +273 -0
- package/src/codex/model-entitlements.ts +353 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +492 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +682 -0
- package/src/codex/paths.ts +144 -0
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +242 -0
- package/src/codex/pool-rotation.ts +295 -0
- package/src/codex/project-config-warnings.ts +425 -0
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +573 -0
- package/src/codex/refresh.ts +62 -0
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +1888 -0
- package/src/codex/runtime.ts +659 -0
- package/src/codex/shim.ts +2170 -0
- package/src/codex/subagent-defaults.ts +550 -0
- package/src/codex/subagent-model-fallback.ts +784 -0
- package/src/codex/sync.ts +319 -0
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +298 -0
- package/src/codex/websocket-registry.ts +100 -0
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +160 -0
- package/src/combos/index.ts +45 -0
- package/src/combos/request.ts +94 -0
- package/src/combos/resolve.ts +232 -0
- package/src/combos/types.ts +398 -0
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +4041 -0
- package/src/fork/register.ts +3 -0
- package/src/generated/compatibility-version.json +3116 -0
- package/src/generated/model-metadata.ts +106 -0
- package/src/github/star-state.ts +203 -0
- package/src/grok/inject.ts +530 -0
- package/src/grok/inspect.ts +45 -0
- package/src/grok/status.ts +121 -0
- package/src/grok/sync.ts +66 -0
- package/src/images/artifacts.ts +516 -0
- package/src/images/fulfill-video.ts +163 -0
- package/src/images/fulfill.ts +149 -0
- package/src/images/index.ts +4 -0
- package/src/images/loop.ts +955 -0
- package/src/images/plan.ts +143 -0
- package/src/images/synthetic-tool.ts +133 -0
- package/src/images/types.ts +41 -0
- package/src/images/xai-client.ts +141 -0
- package/src/images/xai-video-client.ts +163 -0
- package/src/index.ts +22 -0
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +159 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +361 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +691 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/abort.ts +146 -0
- package/src/lib/admin-secrets.ts +25 -0
- package/src/lib/admission.ts +83 -0
- package/src/lib/app-owned-memory-stores.ts +195 -0
- package/src/lib/app-owned-memory.ts +265 -0
- package/src/lib/bounded-body.ts +346 -0
- package/src/lib/bun-binary-validator.d.mts +3 -0
- package/src/lib/bun-binary-validator.mjs +18 -0
- package/src/lib/bun-runtime.ts +184 -0
- package/src/lib/bun-stream-caps.ts +130 -0
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +364 -0
- package/src/lib/crash-guard.ts +344 -0
- package/src/lib/debug-log-buffer.ts +83 -0
- package/src/lib/debug-settings.ts +108 -0
- package/src/lib/debug.ts +31 -0
- package/src/lib/destination-policy.ts +380 -0
- package/src/lib/errors.ts +406 -0
- package/src/lib/eventstream-decoder.ts +253 -0
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/gcp-adc.ts +341 -0
- package/src/lib/injection-debug-log.ts +58 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/open-url.ts +25 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +270 -0
- package/src/lib/privacy.ts +20 -0
- package/src/lib/process-control.ts +168 -0
- package/src/lib/provider-outbound.ts +210 -0
- package/src/lib/provider-url.ts +14 -0
- package/src/lib/proxy-env.ts +18 -0
- package/src/lib/redact.ts +521 -0
- package/src/lib/retry-after.ts +55 -0
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/service-secrets.ts +25 -0
- package/src/lib/shadow-call.ts +61 -0
- package/src/lib/sidecar-tracker.ts +52 -0
- package/src/lib/sse-decoder.ts +364 -0
- package/src/lib/state-store-registrations.ts +119 -0
- package/src/lib/state-store-sweeper.ts +184 -0
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/test-home-guard.ts +90 -0
- package/src/lib/token-estimate.ts +86 -0
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +400 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +392 -0
- package/src/lib/win-exec.ts +115 -0
- package/src/lib/win-paths.ts +68 -0
- package/src/lib/windows-atomic-replace.ts +156 -0
- package/src/lib/windows-elevation.ts +773 -0
- package/src/lib/windows-secret-acl.ts +854 -0
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +403 -0
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic-routing.ts +594 -0
- package/src/oauth/anthropic.ts +188 -0
- package/src/oauth/antigravity-routing.ts +151 -0
- package/src/oauth/callback-server.ts +300 -0
- package/src/oauth/chatgpt.ts +161 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +252 -0
- package/src/oauth/github-copilot.ts +428 -0
- package/src/oauth/google-antigravity.ts +262 -0
- package/src/oauth/health.ts +407 -0
- package/src/oauth/index.ts +1504 -0
- package/src/oauth/key-providers.ts +124 -0
- package/src/oauth/kimi.ts +227 -0
- package/src/oauth/kiro-credentials.ts +726 -0
- package/src/oauth/kiro.ts +621 -0
- package/src/oauth/local-token-detect.ts +130 -0
- package/src/oauth/log.ts +50 -0
- package/src/oauth/login-cli.ts +223 -0
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/pkce.ts +15 -0
- package/src/oauth/store.ts +728 -0
- package/src/oauth/token-guardian.ts +309 -0
- package/src/oauth/types.ts +62 -0
- package/src/oauth/xai.ts +241 -0
- package/src/providers/alibaba-region-backup.ts +75 -0
- package/src/providers/alibaba-region-migration.ts +156 -0
- package/src/providers/alibaba-region-startup.ts +36 -0
- package/src/providers/antigravity-models.ts +695 -0
- package/src/providers/antigravity-quota.ts +216 -0
- package/src/providers/api-keys.ts +140 -0
- package/src/providers/base-url-choices.ts +74 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +82 -0
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +586 -0
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +187 -0
- package/src/providers/github-copilot-transport.ts +56 -0
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +271 -0
- package/src/providers/kiro-models.ts +67 -0
- package/src/providers/label.ts +19 -0
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +449 -0
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +243 -0
- package/src/providers/openai-tier-startup.ts +56 -0
- package/src/providers/openai-tiers.ts +423 -0
- package/src/providers/openai-virtual-models.ts +83 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/openrouter-routing.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +185 -0
- package/src/providers/quota.ts +2345 -0
- package/src/providers/registry.ts +2918 -0
- package/src/providers/replit/constants.ts +27 -0
- package/src/providers/replit/derive.ts +85 -0
- package/src/providers/replit/headers.ts +28 -0
- package/src/providers/replit/origin.ts +55 -0
- package/src/providers/replit/pair-install-response.ts +72 -0
- package/src/providers/replit/probe.ts +199 -0
- package/src/providers/replit/setup.ts +350 -0
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +103 -0
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +148 -0
- package/src/reasoning-effort.ts +183 -0
- package/src/responses/compaction.ts +142 -0
- package/src/responses/custom-tool-compat.ts +266 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +355 -0
- package/src/responses/parser.ts +838 -0
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +60 -0
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +165 -0
- package/src/responses/spill-store.ts +459 -0
- package/src/responses/state.ts +1433 -0
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-groups.ts +19 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +761 -0
- package/src/routing/analytics.ts +378 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +53 -0
- package/src/server/auth-cors.ts +751 -0
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +442 -0
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +1030 -0
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +190 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +152 -0
- package/src/server/image-retry.ts +42 -0
- package/src/server/images.ts +568 -0
- package/src/server/index.ts +1813 -0
- package/src/server/lifecycle.ts +498 -0
- package/src/server/live.ts +717 -0
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +1433 -0
- package/src/server/management/api-access.ts +141 -0
- package/src/server/management/api-key-usage.ts +193 -0
- package/src/server/management/body.ts +41 -0
- package/src/server/management/combo-routes.ts +263 -0
- package/src/server/management/config-routes.ts +835 -0
- package/src/server/management/context.ts +113 -0
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +586 -0
- package/src/server/management/model-routes.ts +560 -0
- package/src/server/management/model-rows.ts +163 -0
- package/src/server/management/native-integration-routes.ts +769 -0
- package/src/server/management/oauth-account-routes.ts +637 -0
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +1033 -0
- package/src/server/management/replit-provider-routes.ts +86 -0
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +385 -0
- package/src/server/management/shared.ts +286 -0
- package/src/server/management/sidebar-routes.ts +106 -0
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +435 -0
- package/src/server/management/system-routes.ts +194 -0
- package/src/server/management/usage-summary-cache.ts +94 -0
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +314 -0
- package/src/server/management-auth.ts +482 -0
- package/src/server/memory-watchdog.ts +156 -0
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/port-reclaim.ts +307 -0
- package/src/server/ports.ts +156 -0
- package/src/server/proxy-liveness.ts +328 -0
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +353 -0
- package/src/server/relay.ts +1209 -0
- package/src/server/request-decompress.ts +239 -0
- package/src/server/request-log-conversation.ts +168 -0
- package/src/server/request-log.ts +1259 -0
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/collaboration.ts +551 -0
- package/src/server/responses/compact.ts +771 -0
- package/src/server/responses/core.ts +5389 -0
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +331 -0
- package/src/server/responses/fetch-helpers.ts +232 -0
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/passthrough-error.ts +78 -0
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +251 -0
- package/src/server/responses/terminal-guard.ts +251 -0
- package/src/server/responses/upstream-error.ts +53 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-image-gen-repair.ts +132 -0
- package/src/server/responses-item-id-repair.ts +272 -0
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +153 -0
- package/src/server/responses.ts +25 -0
- package/src/server/search.ts +201 -0
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +263 -0
- package/src/server/startup-action-control.ts +315 -0
- package/src/server/startup-health-cache.ts +131 -0
- package/src/server/system-env.ts +484 -0
- package/src/server/windows-tcp-drop.ts +184 -0
- package/src/server/windows-tray-control.ts +41 -0
- package/src/server/ws-bridge.ts +472 -0
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +3575 -0
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/stall-timeout.ts +20 -0
- package/src/storage/cleanup-job.ts +57 -0
- package/src/storage/cleanup.ts +3085 -0
- package/src/storage/policy-job.ts +457 -0
- package/src/storage/policy-scheduler.ts +40 -0
- package/src/storage/policy-worker.ts +59 -0
- package/src/storage/policy.ts +527 -0
- package/src/storage/restore-job.ts +299 -0
- package/src/storage/restore-worker.ts +58 -0
- package/src/storage/scanner.ts +238 -0
- package/src/storage/storage-mutation-coordinator.ts +139 -0
- package/src/storage/worker-lifecycle.ts +215 -0
- package/src/tray/assets/opencodex-tray-offline.ico +0 -0
- package/src/tray/assets/opencodex-tray-online.ico +0 -0
- package/src/tray/assets/opencodex-tray-warning.ico +0 -0
- package/src/tray/assets/opencodex-tray.png +0 -0
- package/src/tray/windows-tray.ps1 +364 -0
- package/src/tray/windows.ts +757 -0
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +876 -0
- package/src/types/provider.ts +545 -0
- package/src/types/request.ts +384 -0
- package/src/types/tools.ts +131 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +106 -0
- package/src/update/badge.ts +72 -0
- package/src/update/index.ts +415 -0
- package/src/update/job.ts +1887 -0
- package/src/update/notify.ts +263 -0
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/npm-invocation.d.mts +23 -0
- package/src/update/npm-invocation.mjs +94 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/update/tray-update-plan.d.mts +18 -0
- package/src/update/tray-update-plan.mjs +38 -0
- package/src/usage/cost.ts +625 -0
- package/src/usage/debug.ts +97 -0
- package/src/usage/expected-prices.ts +416 -0
- package/src/usage/log.ts +1223 -0
- package/src/usage/summary.ts +753 -0
- package/src/usage/totals.ts +14 -0
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +189 -0
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +131 -0
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +681 -0
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +195 -0
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +113 -0
- package/src/web-search/format-result.ts +89 -0
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +331 -0
- package/src/web-search/loop.ts +896 -0
- package/src/web-search/parse.ts +315 -0
- package/src/web-search/progress-stream.ts +342 -0
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/synthetic-tool.ts +47 -0
- package/src/web-search/xai-executor.ts +219 -0
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /v1/images/{generations,edits} relay (issue #83).
|
|
3
|
+
*
|
|
4
|
+
* codex-rs's standalone image_gen extension executes CLIENT-SIDE: it POSTs
|
|
5
|
+
* `{base_url}/images/generations` (edits when reference images are attached) with the same
|
|
6
|
+
* ChatGPT bearer auth it uses for chat. Under Design B injection base_url IS this proxy, so
|
|
7
|
+
* without a route the tool died on the /v1/* JSON-404 guard. Only an OpenAI-family upstream
|
|
8
|
+
* can serve these endpoints — routed providers (Cursor, Kiro, Gemini, …) have no image
|
|
9
|
+
* generation surface — so the handler relays the body verbatim to the ChatGPT forward
|
|
10
|
+
* provider, an OpenAI API-key provider, or an explicitly selected compatible custom provider and
|
|
11
|
+
* passes the response through untouched:
|
|
12
|
+
* codex's images client parses `{created, data:[{b64_json}]}` strictly and Debug-prints
|
|
13
|
+
* error bodies into the model-visible failure, so upstream errors must stay legible.
|
|
14
|
+
*/
|
|
15
|
+
import { formatErrorResponse } from "../bridge";
|
|
16
|
+
import {
|
|
17
|
+
CodexAccountCooldownError,
|
|
18
|
+
codexMainProfileDrainingResponse,
|
|
19
|
+
cooldownErrorResponse,
|
|
20
|
+
CodexAuthContextError,
|
|
21
|
+
CodexMainProfileDrainingError,
|
|
22
|
+
CodexPoolAuthenticationError,
|
|
23
|
+
CodexThreadAffinityExpiredError,
|
|
24
|
+
} from "../codex/auth-context";
|
|
25
|
+
import { formatCodexProviderForLog } from "../codex/routing";
|
|
26
|
+
import { signalWithTimeout } from "../lib/abort";
|
|
27
|
+
import { readBoundedResponseBytes, type BoundedBytesResult } from "../lib/bounded-body";
|
|
28
|
+
import { sidecarEnter } from "../lib/sidecar-tracker";
|
|
29
|
+
import type { OcxConfig } from "../types";
|
|
30
|
+
import { resolveFirstUsableOpenAiSidecar, selectImagesProvider } from "../providers/openai-sidecar";
|
|
31
|
+
import { getProviderRegistryEntry } from "../providers/registry";
|
|
32
|
+
import { readJsonRequestBody } from "./request-decompress";
|
|
33
|
+
import { ForwardAdmissionCredentialError, validateForwardAdmissionCredential } from "./auth-cors";
|
|
34
|
+
import type { RequestLogContext } from "./request-log";
|
|
35
|
+
import { codexLogAccountId, decodeRequestErrorResponse } from "./responses";
|
|
36
|
+
import { getValidAccessToken, getOAuthCredentialProjectId } from "../oauth/index";
|
|
37
|
+
import { safeAntigravityHttpErrorMessage } from "../adapters/google-errors";
|
|
38
|
+
import { sanitizeUpstreamErrorText } from "../adapters/upstream-http-error";
|
|
39
|
+
import { ANTIGRAVITY_REQUEST_UA } from "../adapters/google-antigravity-wire";
|
|
40
|
+
import { decodeValidatedImageBase64, MAX_ENCODED_BYTES_PER_IMAGE } from "../images/artifacts";
|
|
41
|
+
import type { AdmissionLease } from "../lib/admission";
|
|
42
|
+
import { codexAccountSelectionForTurn } from "./lifecycle";
|
|
43
|
+
|
|
44
|
+
export type ImagesEndpoint = "generations" | "edits";
|
|
45
|
+
|
|
46
|
+
/** Image generation is slow (tens of seconds); bound a hung upstream, not a working one. */
|
|
47
|
+
const IMAGES_UPSTREAM_TIMEOUT_MS = 300_000;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Cap for the buffered upstream response body (100 MiB). Images responses are JSON documents
|
|
51
|
+
* containing base64-encoded images — typically a few MB. This prevents an oversized or malicious
|
|
52
|
+
* response from exhausting process memory.
|
|
53
|
+
*/
|
|
54
|
+
export const IMAGES_RESPONSE_MAX_BYTES = 100 * 1024 * 1024;
|
|
55
|
+
|
|
56
|
+
interface ImageResponseBytesOptions {
|
|
57
|
+
signal?: AbortSignal;
|
|
58
|
+
/** Smaller values are used only by focused reader tests. */
|
|
59
|
+
maxBytes?: number;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function cancelUnlockedResponseBody(response: Response | undefined, reason?: unknown): void {
|
|
63
|
+
const body = response?.body;
|
|
64
|
+
if (!body || body.locked) return;
|
|
65
|
+
try {
|
|
66
|
+
void body.cancel(reason).catch(() => undefined);
|
|
67
|
+
} catch {
|
|
68
|
+
// A broken stream can throw synchronously from cancel().
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Read one image relay response as exact raw bytes under the same cap used by
|
|
74
|
+
* the public handler. A trustworthy Content-Length can reject obvious excess
|
|
75
|
+
* before attaching a reader; the streaming reader remains authoritative when
|
|
76
|
+
* the header is absent or understated.
|
|
77
|
+
*/
|
|
78
|
+
export async function readImageResponseBytes(
|
|
79
|
+
response: Response,
|
|
80
|
+
options: ImageResponseBytesOptions = {},
|
|
81
|
+
): Promise<BoundedBytesResult> {
|
|
82
|
+
const signal = options.signal;
|
|
83
|
+
if (signal?.aborted) {
|
|
84
|
+
cancelUnlockedResponseBody(response, signal.reason);
|
|
85
|
+
throw signal.reason;
|
|
86
|
+
}
|
|
87
|
+
if (response.body === null) {
|
|
88
|
+
return { bytes: new Uint8Array(0), oversized: false };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const maxBytes = options.maxBytes ?? IMAGES_RESPONSE_MAX_BYTES;
|
|
92
|
+
const contentLength = response.headers.get("content-length");
|
|
93
|
+
const declaredBytes = contentLength === null ? Number.NaN : Number(contentLength);
|
|
94
|
+
if (Number.isSafeInteger(declaredBytes) && declaredBytes > maxBytes) {
|
|
95
|
+
cancelUnlockedResponseBody(
|
|
96
|
+
response,
|
|
97
|
+
new DOMException("Response body size limit reached", "QuotaExceededError"),
|
|
98
|
+
);
|
|
99
|
+
return { bytes: new Uint8Array(0), oversized: true };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return readBoundedResponseBytes(response, { maxBytes, signal });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const CCA_IMAGE_MODEL = "gemini-3.1-flash-image";
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Google Gemini finishReasons that indicate a permanent content/safety block.
|
|
109
|
+
* When any of these is present, the same prompt will always fail — retrying
|
|
110
|
+
* wastes paid quota. The response is surfaced as 400 (non-retryable) instead
|
|
111
|
+
* of 502 (which codex retries up to 5 times).
|
|
112
|
+
*/
|
|
113
|
+
const CCA_BLOCKING_FINISH_REASONS: ReadonlySet<string> = new Set([
|
|
114
|
+
"SAFETY",
|
|
115
|
+
"BLOCKLIST",
|
|
116
|
+
"PROHIBITED_CONTENT",
|
|
117
|
+
"SPII",
|
|
118
|
+
"RECITATION",
|
|
119
|
+
]);
|
|
120
|
+
|
|
121
|
+
function ccaAmbiguousImageTransportError(detail: string): Response {
|
|
122
|
+
return formatErrorResponse(
|
|
123
|
+
400,
|
|
124
|
+
"invalid_request_error",
|
|
125
|
+
`CCA image generation may have started and must not be blindly retried: ${detail}`,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Race a promise against an abort signal. If the signal aborts first, reject
|
|
131
|
+
* immediately — our code stops awaiting the underlying operation even though
|
|
132
|
+
* the HTTP request behind it may still complete. Used to make the non-cancellable
|
|
133
|
+
* OAuth refresh chain responsive to client cancellation and deadline expiry.
|
|
134
|
+
*/
|
|
135
|
+
function abortableRace<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {
|
|
136
|
+
if (signal.aborted) {
|
|
137
|
+
return Promise.reject(signal.reason ?? new DOMException("The operation was aborted.", "AbortError"));
|
|
138
|
+
}
|
|
139
|
+
return new Promise<T>((resolve, reject) => {
|
|
140
|
+
const onAbort = () => reject(signal.reason ?? new DOMException("The operation was aborted.", "AbortError"));
|
|
141
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
142
|
+
promise.then(
|
|
143
|
+
(val) => { signal.removeEventListener("abort", onAbort); resolve(val); },
|
|
144
|
+
(err) => { signal.removeEventListener("abort", onAbort); reject(err); },
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function tryCcaImageGeneration(
|
|
150
|
+
body: unknown,
|
|
151
|
+
config: OcxConfig,
|
|
152
|
+
logCtx: RequestLogContext,
|
|
153
|
+
signal: AbortSignal,
|
|
154
|
+
endpoint: ImagesEndpoint,
|
|
155
|
+
): Promise<Response | undefined> {
|
|
156
|
+
if (endpoint !== "generations") return undefined;
|
|
157
|
+
const provider = config.providers?.["google-antigravity"];
|
|
158
|
+
if (!provider || provider.disabled) return undefined;
|
|
159
|
+
|
|
160
|
+
const prompt = (body as { prompt?: unknown })?.prompt;
|
|
161
|
+
if (typeof prompt !== "string" || !prompt.trim()) {
|
|
162
|
+
return formatErrorResponse(400, "invalid_request_error", "prompt is required and must not be empty");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const nRaw = (body as { n?: unknown })?.n;
|
|
166
|
+
if (nRaw !== undefined && nRaw !== null) {
|
|
167
|
+
const n = typeof nRaw === "number" ? nRaw : Number(nRaw);
|
|
168
|
+
if (!Number.isInteger(n) || n !== 1) {
|
|
169
|
+
return formatErrorResponse(400, "invalid_request_error", "CCA image generation supports n=1 only");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Create the deadline before credential resolution so the timeout covers
|
|
174
|
+
// OAuth token refresh and project discovery, not just the upstream fetch.
|
|
175
|
+
const timeoutMs = config.images?.timeoutMs ?? IMAGES_UPSTREAM_TIMEOUT_MS;
|
|
176
|
+
const linkedSignal = signalWithTimeout(timeoutMs, signal);
|
|
177
|
+
let token: string;
|
|
178
|
+
try {
|
|
179
|
+
// Race the OAuth refresh against the deadline signal. getValidAccessToken
|
|
180
|
+
// chains through 4 layers (resolveAccessSnapshotForAccount →
|
|
181
|
+
// refreshAndPersistAccessToken → refreshGenericAccountWithLock →
|
|
182
|
+
// def.refresh()) that do HTTP calls without accepting a signal. Rather than
|
|
183
|
+
// threading signal through the entire chain, race the whole call against
|
|
184
|
+
// linkedSignal: when the signal aborts we stop awaiting and surface the
|
|
185
|
+
// cancellation immediately instead of hanging on the refresh HTTP call.
|
|
186
|
+
token = await abortableRace(getValidAccessToken("google-antigravity"), linkedSignal.signal);
|
|
187
|
+
} catch (err) {
|
|
188
|
+
linkedSignal.cleanup();
|
|
189
|
+
// abortableRace rejects immediately when the signal fires, so client
|
|
190
|
+
// cancellation and deadline expiry surface here. Parent abort propagates
|
|
191
|
+
// into the linked signal, so check parent first (499) before the linked
|
|
192
|
+
// signal (504).
|
|
193
|
+
if (signal.aborted) {
|
|
194
|
+
return formatErrorResponse(499, "client_closed_request", "CCA image request canceled by client");
|
|
195
|
+
}
|
|
196
|
+
if (linkedSignal.signal.aborted) {
|
|
197
|
+
return formatErrorResponse(504, "upstream_error", "CCA image generation timed out during authentication");
|
|
198
|
+
}
|
|
199
|
+
// Missing/revoked credential → 401 (re-login required); transient refresh/network → 502.
|
|
200
|
+
const errName = err instanceof Error ? err.name : "";
|
|
201
|
+
if (errName === "OAuthLoginRequiredError") {
|
|
202
|
+
return formatErrorResponse(401, "invalid_request_error", "Google Antigravity login required: run 'ocx login google-antigravity'");
|
|
203
|
+
}
|
|
204
|
+
return formatErrorResponse(502, "upstream_error", "CCA image generation failed: OAuth token refresh failed");
|
|
205
|
+
}
|
|
206
|
+
const project = getOAuthCredentialProjectId("google-antigravity");
|
|
207
|
+
if (!project) {
|
|
208
|
+
linkedSignal.cleanup();
|
|
209
|
+
return formatErrorResponse(
|
|
210
|
+
400,
|
|
211
|
+
"invalid_request_error",
|
|
212
|
+
"Antigravity requires a discovered Cloud Code Assist project id (re-run `ocx login google-antigravity`).",
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
logCtx.provider = "google-antigravity";
|
|
217
|
+
logCtx.model = CCA_IMAGE_MODEL;
|
|
218
|
+
|
|
219
|
+
// Pin to the registry endpoint — never use a config-level baseUrl override for OAuth token transmission.
|
|
220
|
+
const registryEntry = getProviderRegistryEntry("google-antigravity");
|
|
221
|
+
const baseUrl = registryEntry?.baseUrl ?? "https://daily-cloudcode-pa.googleapis.com";
|
|
222
|
+
const envelope = {
|
|
223
|
+
model: CCA_IMAGE_MODEL,
|
|
224
|
+
userAgent: "antigravity",
|
|
225
|
+
requestType: "agent",
|
|
226
|
+
project,
|
|
227
|
+
requestId: `agent-${crypto.randomUUID()}`,
|
|
228
|
+
request: {
|
|
229
|
+
contents: [{ role: "user", parts: [{ text: prompt }] }],
|
|
230
|
+
generationConfig: { responseModalities: ["TEXT", "IMAGE"] },
|
|
231
|
+
sessionId: `ocx-img-${crypto.randomUUID().slice(0, 8)}`,
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
let upstream: Response | undefined;
|
|
235
|
+
try {
|
|
236
|
+
try {
|
|
237
|
+
// Image generation is a paid, non-idempotent POST. A transport failure is
|
|
238
|
+
// ambiguous: the upstream may have accepted the request before the
|
|
239
|
+
// connection failed, so never replay it on a peer host.
|
|
240
|
+
upstream = await fetch(`${baseUrl}/v1internal:generateContent`, {
|
|
241
|
+
method: "POST",
|
|
242
|
+
headers: {
|
|
243
|
+
"Content-Type": "application/json",
|
|
244
|
+
"Authorization": `Bearer ${token}`,
|
|
245
|
+
"User-Agent": ANTIGRAVITY_REQUEST_UA,
|
|
246
|
+
},
|
|
247
|
+
body: JSON.stringify(envelope),
|
|
248
|
+
signal: linkedSignal.signal,
|
|
249
|
+
});
|
|
250
|
+
} catch (err) {
|
|
251
|
+
if (signal.aborted) return formatErrorResponse(499, "client_closed_request", "CCA image request canceled by client");
|
|
252
|
+
if (err instanceof Error && err.name === "TimeoutError") {
|
|
253
|
+
return ccaAmbiguousImageTransportError("upstream request timed out");
|
|
254
|
+
}
|
|
255
|
+
// Network/DNS/runtime errors may embed the request URL or headers verbatim
|
|
256
|
+
// (e.g. "fetch failed: https://…/v1internal:generateContent"). The token
|
|
257
|
+
// lives in an Authorization header, not in the URL, but sanitize defensively
|
|
258
|
+
// so no upstream-rejected credential or query param can reach the client,
|
|
259
|
+
// and strip the internal base URL host from the surfaced message.
|
|
260
|
+
// 400, not 5xx: the POST is paid and non-idempotent. Codex retries every
|
|
261
|
+
// 5xx up to 5 attempts, which would duplicate generation after an ambiguous
|
|
262
|
+
// transport failure (the upstream may already have accepted the request).
|
|
263
|
+
const rawMsg = err instanceof Error ? err.message : String(err);
|
|
264
|
+
const safeMsg = sanitizeUpstreamErrorText(rawMsg).replace(
|
|
265
|
+
/https?:\/\/[^\s"'<>]+/gi,
|
|
266
|
+
"[upstream-url]",
|
|
267
|
+
);
|
|
268
|
+
return ccaAmbiguousImageTransportError(safeMsg);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Stream the upstream body with a bounded reader so an oversized or malicious
|
|
272
|
+
// response is rejected mid-stream rather than after a full arrayBuffer() allocation.
|
|
273
|
+
let payload: Uint8Array;
|
|
274
|
+
try {
|
|
275
|
+
const reader = upstream.body?.getReader();
|
|
276
|
+
if (!reader) {
|
|
277
|
+
return ccaAmbiguousImageTransportError("upstream response had no body");
|
|
278
|
+
}
|
|
279
|
+
const chunks: Uint8Array[] = [];
|
|
280
|
+
let total = 0;
|
|
281
|
+
try {
|
|
282
|
+
for (;;) {
|
|
283
|
+
const { done, value } = await reader.read();
|
|
284
|
+
if (done) break;
|
|
285
|
+
total += value.byteLength;
|
|
286
|
+
if (total > IMAGES_RESPONSE_MAX_BYTES) {
|
|
287
|
+
await reader.cancel().catch(() => {});
|
|
288
|
+
return formatErrorResponse(502, "upstream_error", `CCA image response too large (exceeded ${IMAGES_RESPONSE_MAX_BYTES} bytes)`);
|
|
289
|
+
}
|
|
290
|
+
chunks.push(value);
|
|
291
|
+
}
|
|
292
|
+
} finally {
|
|
293
|
+
try { await reader.cancel(); } catch { /* ignore */ }
|
|
294
|
+
reader.releaseLock();
|
|
295
|
+
}
|
|
296
|
+
payload = new Uint8Array(total);
|
|
297
|
+
let offset = 0;
|
|
298
|
+
for (const chunk of chunks) {
|
|
299
|
+
payload.set(chunk, offset);
|
|
300
|
+
offset += chunk.byteLength;
|
|
301
|
+
}
|
|
302
|
+
} catch (err) {
|
|
303
|
+
// Body-read timeout/abort: when CCA returns headers then stalls or the
|
|
304
|
+
// connection fails, the paid POST may already have started. Parent abort
|
|
305
|
+
// remains 499; every other ambiguous transport failure is non-retryable.
|
|
306
|
+
if (signal.aborted) {
|
|
307
|
+
return formatErrorResponse(499, "client_closed_request", "CCA image request canceled by client");
|
|
308
|
+
}
|
|
309
|
+
const rawMsg = err instanceof Error ? err.message : String(err);
|
|
310
|
+
const safeMsg = sanitizeUpstreamErrorText(rawMsg).replace(/https?:\/\/[^\s"'<>]+/gi, "[upstream-url]");
|
|
311
|
+
return ccaAmbiguousImageTransportError(
|
|
312
|
+
linkedSignal.signal.aborted ? "upstream response timed out during body read" : safeMsg,
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (!upstream.ok) {
|
|
317
|
+
// Preserve auth/rate-limit and other permanent 4xx signals so callers can
|
|
318
|
+
// distinguish retryable from permanent failures. Remaining 5xx collapse to 502.
|
|
319
|
+
const text = new TextDecoder().decode(payload);
|
|
320
|
+
const safeMsg = safeAntigravityHttpErrorMessage(upstream.status, text);
|
|
321
|
+
if (upstream.status >= 400 && upstream.status < 500) {
|
|
322
|
+
return formatErrorResponse(upstream.status, "upstream_error", safeMsg);
|
|
323
|
+
}
|
|
324
|
+
return formatErrorResponse(502, "upstream_error", safeMsg);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
let json: Record<string, unknown>;
|
|
328
|
+
try {
|
|
329
|
+
json = JSON.parse(new TextDecoder().decode(payload)) as Record<string, unknown>;
|
|
330
|
+
} catch {
|
|
331
|
+
return formatErrorResponse(502, "upstream_error", "CCA image response was not valid JSON");
|
|
332
|
+
}
|
|
333
|
+
const resp = (json.response ?? json) as {
|
|
334
|
+
candidates?: { content?: { parts?: { inlineData?: { mimeType?: string; data?: string }; text?: string }[] }; finishReason?: string }[];
|
|
335
|
+
promptFeedback?: { blockReason?: string };
|
|
336
|
+
};
|
|
337
|
+
// Safety blocks are permanent for the same prompt — return 400 (non-retryable)
|
|
338
|
+
// instead of 502 (which codex retries up to 5 times, wasting paid quota on a
|
|
339
|
+
// prompt that will never succeed). Two blocking signals exist in the Gemini
|
|
340
|
+
// API: promptFeedback.blockReason (prompt rejected before generation) and
|
|
341
|
+
// candidate.finishReason (generation cut off by a content filter).
|
|
342
|
+
const blockReason = resp.promptFeedback?.blockReason;
|
|
343
|
+
if (typeof blockReason === "string" && blockReason.trim()) {
|
|
344
|
+
return formatErrorResponse(400, "invalid_request_error", `CCA image generation blocked by safety filter (promptFeedback.blockReason: ${blockReason})`);
|
|
345
|
+
}
|
|
346
|
+
const candidate = resp.candidates?.[0];
|
|
347
|
+
const finishReason = candidate?.finishReason;
|
|
348
|
+
if (typeof finishReason === "string" && CCA_BLOCKING_FINISH_REASONS.has(finishReason)) {
|
|
349
|
+
return formatErrorResponse(400, "invalid_request_error", `CCA image generation blocked by safety filter (finishReason: ${finishReason})`);
|
|
350
|
+
}
|
|
351
|
+
const parts = candidate?.content?.parts;
|
|
352
|
+
if (!Array.isArray(parts)) {
|
|
353
|
+
return formatErrorResponse(502, "upstream_error", "CCA image response had no valid parts array");
|
|
354
|
+
}
|
|
355
|
+
const images: { b64_json: string }[] = [];
|
|
356
|
+
for (const part of parts) {
|
|
357
|
+
if (!part || typeof part !== "object") continue;
|
|
358
|
+
const data = part.inlineData?.data;
|
|
359
|
+
if (typeof data !== "string" || data.length === 0) continue;
|
|
360
|
+
if (data.length > MAX_ENCODED_BYTES_PER_IMAGE) {
|
|
361
|
+
return formatErrorResponse(502, "upstream_error", "CCA image payload exceeds per-image size cap");
|
|
362
|
+
}
|
|
363
|
+
try {
|
|
364
|
+
decodeValidatedImageBase64(data);
|
|
365
|
+
} catch {
|
|
366
|
+
return formatErrorResponse(502, "upstream_error", "CCA image payload failed base64/magic validation");
|
|
367
|
+
}
|
|
368
|
+
images.push({ b64_json: data });
|
|
369
|
+
}
|
|
370
|
+
if (images.length === 0) {
|
|
371
|
+
return formatErrorResponse(502, "upstream_error", "CCA image model returned no image data");
|
|
372
|
+
}
|
|
373
|
+
// Only `{created, data:[{b64_json}]}` is returned — no token, projectId, or
|
|
374
|
+
// upstream metadata leak through. The Authorization header is consumed by the
|
|
375
|
+
// fetch above and never copied onto this Response.
|
|
376
|
+
return new Response(JSON.stringify({ created: Math.floor(Date.now() / 1000), data: images }), {
|
|
377
|
+
status: 200,
|
|
378
|
+
headers: { "content-type": "application/json" },
|
|
379
|
+
});
|
|
380
|
+
} finally {
|
|
381
|
+
linkedSignal.cleanup();
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export async function handleImages(
|
|
386
|
+
req: Request,
|
|
387
|
+
config: OcxConfig,
|
|
388
|
+
endpoint: ImagesEndpoint,
|
|
389
|
+
logCtx: RequestLogContext,
|
|
390
|
+
turnAdmissionLease?: AdmissionLease,
|
|
391
|
+
): Promise<Response> {
|
|
392
|
+
const candidates = selectImagesProvider(config);
|
|
393
|
+
if (candidates.error) {
|
|
394
|
+
return formatErrorResponse(400, "invalid_request_error", candidates.error);
|
|
395
|
+
}
|
|
396
|
+
const explicitKeyedProvider = config.images?.provider !== undefined && candidates.keyed !== undefined;
|
|
397
|
+
// Admission bearer is valid proxy auth (requireApiAuth already passed) but must never be
|
|
398
|
+
// forwarded as OpenAI ChatGPT credentials. When the caller sent it, skip OpenAI forward
|
|
399
|
+
// and allow CCA / keyed paths instead of rejecting the whole request.
|
|
400
|
+
let skipOpenAiForwardForAdmissionBearer = false;
|
|
401
|
+
if (!explicitKeyedProvider) {
|
|
402
|
+
try { validateForwardAdmissionCredential(req.headers, config); }
|
|
403
|
+
catch (err) {
|
|
404
|
+
if (err instanceof ForwardAdmissionCredentialError) {
|
|
405
|
+
skipOpenAiForwardForAdmissionBearer = true;
|
|
406
|
+
} else {
|
|
407
|
+
throw err;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
let body: unknown;
|
|
412
|
+
try {
|
|
413
|
+
body = await readJsonRequestBody(req);
|
|
414
|
+
} catch (err) {
|
|
415
|
+
return decodeRequestErrorResponse(err, "images");
|
|
416
|
+
}
|
|
417
|
+
const model = (body as { model?: unknown } | null)?.model;
|
|
418
|
+
if (typeof model === "string" && model) logCtx.model = model;
|
|
419
|
+
|
|
420
|
+
const canUseOpenAiForward = !skipOpenAiForwardForAdmissionBearer && candidates.forwardCandidates.length > 0;
|
|
421
|
+
|
|
422
|
+
if (!canUseOpenAiForward && !candidates.keyed) {
|
|
423
|
+
const ccaResponse = await tryCcaImageGeneration(body, config, logCtx, req.signal, endpoint);
|
|
424
|
+
if (ccaResponse) return ccaResponse;
|
|
425
|
+
// 400, not 5xx: codex retries every 5xx up to 5 total attempts, and this is a permanent
|
|
426
|
+
// configuration state that must surface on the first attempt.
|
|
427
|
+
return formatErrorResponse(
|
|
428
|
+
400,
|
|
429
|
+
"invalid_request_error",
|
|
430
|
+
"Built-in image generation needs an OpenAI upstream (ChatGPT login or an OpenAI API-key provider) "
|
|
431
|
+
+ "or a logged-in Google Antigravity (Cloud Code Assist) provider, "
|
|
432
|
+
+ "but none is configured in opencodex. Add a provider or disable the tool with `codex features disable image_generation`.",
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Resolve forward auth first; failures are captured, not returned, so a configured keyed
|
|
437
|
+
// provider can still serve the request (e.g. every pool account cooling down must not
|
|
438
|
+
// 429 image_gen while api.openai.com sits idle).
|
|
439
|
+
let forward: Awaited<ReturnType<typeof resolveFirstUsableOpenAiSidecar>>;
|
|
440
|
+
let forwardAuthError: Response | undefined;
|
|
441
|
+
if (canUseOpenAiForward) {
|
|
442
|
+
try {
|
|
443
|
+
forward = await resolveFirstUsableOpenAiSidecar(candidates.forwardCandidates, req.headers, config, {
|
|
444
|
+
beginCodexAccountSelection: codexAccountSelectionForTurn(turnAdmissionLease),
|
|
445
|
+
});
|
|
446
|
+
if (forward) logCtx.provider = formatCodexProviderForLog(forward.providerName, codexLogAccountId(forward.authContext), config);
|
|
447
|
+
} catch (err) {
|
|
448
|
+
if (err instanceof CodexAccountCooldownError) {
|
|
449
|
+
forwardAuthError = cooldownErrorResponse(err);
|
|
450
|
+
} else if (err instanceof CodexMainProfileDrainingError) {
|
|
451
|
+
forwardAuthError = codexMainProfileDrainingResponse();
|
|
452
|
+
} else if (err instanceof CodexThreadAffinityExpiredError) {
|
|
453
|
+
forwardAuthError = formatErrorResponse(409, "invalid_request_error", "Codex thread account affinity expired; start a new session");
|
|
454
|
+
} else if (err instanceof CodexAuthContextError) {
|
|
455
|
+
const safeAccountLabel = formatCodexProviderForLog("openai", err.accountId, config);
|
|
456
|
+
console.error(`[images] Pool account ${safeAccountLabel} token failed; reauthentication required`);
|
|
457
|
+
forwardAuthError = formatErrorResponse(401, "authentication_error", "Selected Codex account needs reauthentication");
|
|
458
|
+
} else if (err instanceof CodexPoolAuthenticationError) {
|
|
459
|
+
forwardAuthError = formatErrorResponse(401, "authentication_error", err.message);
|
|
460
|
+
} else {
|
|
461
|
+
throw err;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const headers: Record<string, string> = { "content-type": "application/json" };
|
|
467
|
+
let url: string;
|
|
468
|
+
if (forward) {
|
|
469
|
+
const { provider } = forward;
|
|
470
|
+
if (provider.headers) Object.assign(headers, provider.headers);
|
|
471
|
+
for (const [name, value] of forward.headers) headers[name] = value;
|
|
472
|
+
// The ChatGPT codex backend takes bare paths (matches the adapter's `${baseUrl}/responses`).
|
|
473
|
+
url = `${provider.baseUrl}/images/${endpoint}`;
|
|
474
|
+
} else if (forwardAuthError) {
|
|
475
|
+
// Before surfacing the OpenAI auth failure, try CCA — the user may have a
|
|
476
|
+
// valid Google Antigravity login even though their OpenAI pool is broken.
|
|
477
|
+
const ccaResponse = await tryCcaImageGeneration(body, config, logCtx, req.signal, endpoint);
|
|
478
|
+
if (ccaResponse) return ccaResponse;
|
|
479
|
+
// No CCA either: a configured OpenAI pool mode owns its authentication failure.
|
|
480
|
+
// Do not hide a broken/expired pool behind separately billed API-key image generation.
|
|
481
|
+
return forwardAuthError;
|
|
482
|
+
} else if (candidates.keyed) {
|
|
483
|
+
const { provider, apiKey, providerName } = candidates.keyed;
|
|
484
|
+
if (provider.headers) Object.assign(headers, provider.headers);
|
|
485
|
+
headers["authorization"] = `Bearer ${apiKey}`;
|
|
486
|
+
logCtx.provider = providerName;
|
|
487
|
+
// Keyed providers tolerate baseUrl with or without /v1 (mirrors openai-responses.ts).
|
|
488
|
+
url = `${provider.baseUrl.replace(/\/v1\/?$/, "")}/v1/images/${endpoint}`;
|
|
489
|
+
} else {
|
|
490
|
+
// No usable OpenAI credential — try CCA before giving up.
|
|
491
|
+
const ccaResponse = await tryCcaImageGeneration(body, config, logCtx, req.signal, endpoint);
|
|
492
|
+
if (ccaResponse) return ccaResponse;
|
|
493
|
+
return formatErrorResponse(
|
|
494
|
+
401,
|
|
495
|
+
"authentication_error",
|
|
496
|
+
"image generation relay needs ChatGPT auth (Authorization header) or an OpenAI API-key provider",
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const timeoutMs = config.images?.timeoutMs ?? IMAGES_UPSTREAM_TIMEOUT_MS;
|
|
501
|
+
const linkedSignal = signalWithTimeout(timeoutMs, req.signal);
|
|
502
|
+
const sidecarExit = sidecarEnter("images");
|
|
503
|
+
let upstreamResponse: Response | undefined;
|
|
504
|
+
try {
|
|
505
|
+
// Images POSTs create paid, non-idempotent work. One fetch only: no reset retry without a
|
|
506
|
+
// source-proven idempotency contract.
|
|
507
|
+
upstreamResponse = await fetch(url, {
|
|
508
|
+
method: "POST",
|
|
509
|
+
headers,
|
|
510
|
+
body: JSON.stringify(body),
|
|
511
|
+
signal: linkedSignal.signal,
|
|
512
|
+
// Do not follow a cross-origin 3xx while carrying Codex credentials. Bun strips
|
|
513
|
+
// `Authorization` across origins but forwards nonstandard headers, so
|
|
514
|
+
// `chatgpt-account-id`, `session_id`, and `x-codex-turn-metadata` would reach the
|
|
515
|
+
// redirect target. Verified with a two-server probe. The Responses path and native
|
|
516
|
+
// compact already set this; the credential-bearing sidecars did not.
|
|
517
|
+
redirect: "manual",
|
|
518
|
+
});
|
|
519
|
+
const observed = await readImageResponseBytes(upstreamResponse, {
|
|
520
|
+
maxBytes: IMAGES_RESPONSE_MAX_BYTES,
|
|
521
|
+
signal: linkedSignal.signal,
|
|
522
|
+
});
|
|
523
|
+
if (observed.oversized) {
|
|
524
|
+
forward?.recordOutcome?.(upstreamResponse.status);
|
|
525
|
+
return formatErrorResponse(
|
|
526
|
+
502,
|
|
527
|
+
"upstream_error",
|
|
528
|
+
`image ${endpoint} response too large (exceeded ${IMAGES_RESPONSE_MAX_BYTES} bytes)`,
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
const relayHeaders: Record<string, string> = {};
|
|
532
|
+
const contentType = upstreamResponse.headers.get("content-type");
|
|
533
|
+
if (contentType) relayHeaders["content-type"] = contentType;
|
|
534
|
+
// Fetch represents 204/205/304 responses with a null body. Preserve that
|
|
535
|
+
// invariant: constructing those statuses with even an empty Uint8Array throws.
|
|
536
|
+
const relayBody = upstreamResponse.body === null ? null : observed.bytes;
|
|
537
|
+
const relayResponse = new Response(relayBody, {
|
|
538
|
+
status: upstreamResponse.status,
|
|
539
|
+
headers: relayHeaders,
|
|
540
|
+
});
|
|
541
|
+
forward?.recordOutcome?.(upstreamResponse.status);
|
|
542
|
+
return relayResponse;
|
|
543
|
+
} catch (err) {
|
|
544
|
+
// Client cancel first: it aborts the linked signal too, and must not be logged as an
|
|
545
|
+
// upstream failure (499 maps to client_closed_request in the request log).
|
|
546
|
+
if (req.signal.aborted) {
|
|
547
|
+
return formatErrorResponse(499, "client_closed_request", `image ${endpoint} request canceled by client`);
|
|
548
|
+
}
|
|
549
|
+
if (linkedSignal.signal.aborted || (err instanceof Error && err.name === "TimeoutError")) {
|
|
550
|
+
forward?.recordOutcome?.("timeout");
|
|
551
|
+
// codex retries 5xx up to 4 more times; a retried 504 is acceptable for a transient hang.
|
|
552
|
+
return formatErrorResponse(504, "upstream_error", `image ${endpoint} upstream timed out`);
|
|
553
|
+
}
|
|
554
|
+
forward?.recordOutcome?.("connect_error");
|
|
555
|
+
return formatErrorResponse(
|
|
556
|
+
502,
|
|
557
|
+
"upstream_error",
|
|
558
|
+
`image ${endpoint} relay failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
559
|
+
);
|
|
560
|
+
} finally {
|
|
561
|
+
sidecarExit();
|
|
562
|
+
linkedSignal.cleanup();
|
|
563
|
+
// If cancellation won before readImageResponseBytes attached its reader, the
|
|
564
|
+
// response still owns an upstream body/socket. Consumed or locked bodies are
|
|
565
|
+
// already owned by the reader and need no second cancellation.
|
|
566
|
+
cancelUnlockedResponseBody(upstreamResponse);
|
|
567
|
+
}
|
|
568
|
+
}
|