@iislee/opencodex 2.11.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/LICENSE +21 -0
- package/README.md +225 -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 +451 -0
- package/bin/package-main.mjs +9 -0
- package/gui/dist/assets/index-DTpMHS4F.js +67 -0
- package/gui/dist/assets/index-ZNVDE3C7.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/antigravity.svg +1 -0
- package/gui/dist/provider-icons/claude-color.svg +1 -0
- package/gui/dist/provider-icons/claude.svg +1 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -0
- package/gui/dist/provider-icons/copilot.svg +1 -0
- package/gui/dist/provider-icons/cursor-color.svg +2 -0
- package/gui/dist/provider-icons/cursor.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/gemini.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-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/kiro.svg +14 -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 +1 -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 +102 -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.ts +1003 -0
- package/src/adapters/azure.ts +36 -0
- package/src/adapters/base.ts +72 -0
- package/src/adapters/client-fingerprint.ts +59 -0
- package/src/adapters/cursor/arg-codec.ts +38 -0
- package/src/adapters/cursor/arg-normalize.ts +104 -0
- package/src/adapters/cursor/cursor-errors.ts +165 -0
- package/src/adapters/cursor/discovery.ts +276 -0
- package/src/adapters/cursor/effort-map.ts +127 -0
- package/src/adapters/cursor/exec-policy.ts +88 -0
- package/src/adapters/cursor/framing.ts +211 -0
- package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
- package/src/adapters/cursor/kv-store.ts +52 -0
- package/src/adapters/cursor/live-models.ts +153 -0
- package/src/adapters/cursor/live-smoke-gate.ts +41 -0
- package/src/adapters/cursor/live-transport.ts +1214 -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 +55 -0
- package/src/adapters/cursor/native-exec-desktop.ts +184 -0
- package/src/adapters/cursor/native-exec-fs.ts +329 -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 +548 -0
- package/src/adapters/cursor/native-exec-tools.ts +118 -0
- package/src/adapters/cursor/native-exec.ts +576 -0
- package/src/adapters/cursor/protobuf-events.ts +563 -0
- package/src/adapters/cursor/protobuf-request.ts +714 -0
- package/src/adapters/cursor/request-builder.ts +255 -0
- package/src/adapters/cursor/thread-continuity.ts +67 -0
- package/src/adapters/cursor/tool-definitions.ts +505 -0
- package/src/adapters/cursor/transport-retry.ts +132 -0
- package/src/adapters/cursor/transport.ts +57 -0
- package/src/adapters/cursor/types.ts +52 -0
- package/src/adapters/cursor.ts +196 -0
- package/src/adapters/google-antigravity-replay.ts +303 -0
- package/src/adapters/google-antigravity-wire.ts +108 -0
- package/src/adapters/google-errors.ts +85 -0
- package/src/adapters/google-http.ts +100 -0
- package/src/adapters/google-tool-schema.ts +173 -0
- package/src/adapters/google-truncation.ts +13 -0
- package/src/adapters/google-wire-compiler.ts +232 -0
- package/src/adapters/google.ts +758 -0
- package/src/adapters/identity.ts +44 -0
- package/src/adapters/image.ts +23 -0
- package/src/adapters/kiro-constants.ts +16 -0
- package/src/adapters/kiro-errors.ts +197 -0
- package/src/adapters/kiro-events.ts +179 -0
- package/src/adapters/kiro-images.ts +129 -0
- package/src/adapters/kiro-retry.ts +312 -0
- package/src/adapters/kiro-thinking.ts +96 -0
- package/src/adapters/kiro-tool-fallback.ts +36 -0
- package/src/adapters/kiro-tools.ts +215 -0
- package/src/adapters/kiro-truncation.ts +33 -0
- package/src/adapters/kiro-wire.ts +129 -0
- package/src/adapters/kiro.ts +1898 -0
- package/src/adapters/mimo-free.ts +263 -0
- package/src/adapters/openai-chat.ts +1005 -0
- package/src/adapters/openai-responses.ts +1137 -0
- package/src/adapters/run-turn-queue.ts +114 -0
- package/src/adapters/tool-catalog-nudge.ts +71 -0
- package/src/adapters/upstream-http-error.ts +48 -0
- package/src/bridge.ts +1619 -0
- package/src/chat/inbound.ts +295 -0
- package/src/chat/outbound.ts +765 -0
- package/src/claude/agents-inject.ts +243 -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 +189 -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 +381 -0
- package/src/claude/desktop-health.ts +26 -0
- package/src/claude/desktop-profile.ts +263 -0
- package/src/claude/gateway-cache.ts +70 -0
- package/src/claude/inbound-debug.ts +163 -0
- package/src/claude/inbound.ts +509 -0
- package/src/claude/model-info.ts +151 -0
- package/src/claude/outbound.ts +872 -0
- package/src/cli/access.ts +108 -0
- package/src/cli/account-api.ts +268 -0
- package/src/cli/account-auth.ts +223 -0
- package/src/cli/account-extended.ts +350 -0
- package/src/cli/account.ts +275 -0
- package/src/cli/agent-driven.ts +70 -0
- package/src/cli/agent.ts +184 -0
- package/src/cli/catalog-prewarm.ts +27 -0
- package/src/cli/claude-desktop.ts +188 -0
- package/src/cli/claude.ts +286 -0
- package/src/cli/codex-shim-autorestore.ts +45 -0
- package/src/cli/combo.ts +119 -0
- package/src/cli/config-command.ts +145 -0
- package/src/cli/debug.ts +228 -0
- package/src/cli/doctor.ts +930 -0
- package/src/cli/export-command.ts +187 -0
- package/src/cli/help.ts +354 -0
- package/src/cli/index.ts +1113 -0
- package/src/cli/init.ts +224 -0
- package/src/cli/integrations.ts +142 -0
- package/src/cli/interactive-confirm.ts +133 -0
- package/src/cli/internal-dispatch.ts +20 -0
- package/src/cli/models-runtime.ts +212 -0
- package/src/cli/models.ts +336 -0
- package/src/cli/observe.ts +117 -0
- package/src/cli/opencode.ts +586 -0
- package/src/cli/pi.ts +188 -0
- package/src/cli/provider-runtime.ts +162 -0
- package/src/cli/provider.ts +463 -0
- package/src/cli/runtime-api.ts +325 -0
- package/src/cli/star-prompt.ts +155 -0
- package/src/cli/status-oauth.ts +78 -0
- package/src/cli/status.ts +321 -0
- package/src/cli/sync-cloud.ts +283 -0
- package/src/cli/system-command.ts +112 -0
- package/src/cli/tray-proxy.ts +52 -0
- package/src/cli/v2.ts +173 -0
- package/src/cli.ts +10 -0
- package/src/clients/config-export.ts +377 -0
- package/src/clients/effective-status.ts +385 -0
- package/src/clients/probes/agy.ts +55 -0
- package/src/clients/probes/cc-switch.ts +110 -0
- package/src/clients/probes/claude.ts +90 -0
- package/src/clients/probes/codex.ts +125 -0
- package/src/clients/probes/grok.ts +29 -0
- package/src/clients/probes/opencode.ts +109 -0
- package/src/clients/probes/paseo.ts +55 -0
- package/src/clients/probes/pi.ts +55 -0
- package/src/cloud/onedrive-auth.ts +666 -0
- package/src/cloud/onedrive-graph.ts +108 -0
- package/src/cloud/settings.ts +75 -0
- package/src/cloud/sync.ts +212 -0
- package/src/cloud/types.ts +56 -0
- package/src/cloud/vault.ts +89 -0
- package/src/codex/account-id.ts +34 -0
- package/src/codex/account-label.ts +34 -0
- package/src/codex/account-lifecycle.ts +55 -0
- package/src/codex/account-namespace-match.ts +63 -0
- package/src/codex/account-namespaces.ts +149 -0
- package/src/codex/account-pause.ts +20 -0
- package/src/codex/account-runtime-state.ts +31 -0
- package/src/codex/account-store.ts +517 -0
- package/src/codex/account-usability.ts +20 -0
- package/src/codex/app-server-processes.ts +756 -0
- package/src/codex/auth-api.ts +1540 -0
- package/src/codex/auth-collision.ts +107 -0
- package/src/codex/auth-context.ts +352 -0
- package/src/codex/autostart-health.ts +149 -0
- package/src/codex/catalog/aggregation.ts +378 -0
- package/src/codex/catalog/bundled.ts +251 -0
- package/src/codex/catalog/effort.ts +355 -0
- package/src/codex/catalog/metadata.ts +180 -0
- package/src/codex/catalog/parsing.ts +456 -0
- package/src/codex/catalog/provider-fetch.ts +902 -0
- package/src/codex/catalog/sync.ts +620 -0
- package/src/codex/catalog.ts +12 -0
- package/src/codex/data/upstream-models.json +830 -0
- package/src/codex/exec-invocation.ts +22 -0
- package/src/codex/features.ts +969 -0
- package/src/codex/history-migration-guardian.ts +102 -0
- package/src/codex/history-provider.ts +776 -0
- package/src/codex/home.ts +206 -0
- package/src/codex/inject.ts +799 -0
- package/src/codex/injected-marker.ts +72 -0
- package/src/codex/journal.ts +163 -0
- package/src/codex/main-account-cache.ts +32 -0
- package/src/codex/main-account.ts +40 -0
- package/src/codex/model-cache.ts +227 -0
- package/src/codex/paths.ts +65 -0
- package/src/codex/plugins-doctor.ts +242 -0
- package/src/codex/pool-rotation.ts +225 -0
- package/src/codex/project-config-warnings.ts +411 -0
- package/src/codex/quota.ts +411 -0
- package/src/codex/refresh.ts +53 -0
- package/src/codex/routing.ts +1477 -0
- package/src/codex/runtime.ts +538 -0
- package/src/codex/shim.ts +1189 -0
- package/src/codex/subagent-defaults.ts +550 -0
- package/src/codex/subagent-model-fallback.ts +469 -0
- package/src/codex/sync.ts +130 -0
- package/src/codex/warmup.ts +192 -0
- package/src/codex/websocket-registry.ts +100 -0
- package/src/combos/failover.ts +140 -0
- package/src/combos/index.ts +41 -0
- package/src/combos/request.ts +62 -0
- package/src/combos/resolve.ts +232 -0
- package/src/combos/types.ts +326 -0
- package/src/config.ts +2356 -0
- package/src/generated/jawcode-model-metadata.ts +104 -0
- package/src/github/star-state.ts +203 -0
- package/src/grok/inject.ts +545 -0
- package/src/grok/status.ts +121 -0
- package/src/grok/sync.ts +103 -0
- package/src/grok/usage-hook/report.mjs +348 -0
- package/src/grok/usage-hook.ts +278 -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 +829 -0
- package/src/images/plan.ts +133 -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/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 +173 -0
- package/src/lib/app-owned-memory.ts +265 -0
- package/src/lib/bounded-body.ts +202 -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 +71 -0
- package/src/lib/bun-stream-caps.ts +126 -0
- package/src/lib/config-ownership.ts +360 -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 +316 -0
- package/src/lib/errors.ts +364 -0
- package/src/lib/eventstream-decoder.ts +253 -0
- package/src/lib/gcp-adc.ts +341 -0
- package/src/lib/injection-debug-log.ts +58 -0
- package/src/lib/open-url.ts +25 -0
- package/src/lib/pinned-http.ts +151 -0
- package/src/lib/privacy.ts +20 -0
- package/src/lib/process-control.ts +165 -0
- package/src/lib/provider-outbound.ts +170 -0
- package/src/lib/provider-url.ts +14 -0
- package/src/lib/proxy-env.ts +18 -0
- package/src/lib/redact.ts +105 -0
- package/src/lib/retry-after.ts +55 -0
- package/src/lib/service-secrets.ts +25 -0
- package/src/lib/shadow-call.ts +30 -0
- package/src/lib/sidecar-tracker.ts +52 -0
- package/src/lib/sse-decoder.ts +323 -0
- package/src/lib/state-store-registrations.ts +109 -0
- package/src/lib/state-store-sweeper.ts +184 -0
- package/src/lib/test-home-guard.ts +90 -0
- package/src/lib/token-estimate.ts +69 -0
- package/src/lib/translator-budget.ts +356 -0
- package/src/lib/upstream-retry.ts +239 -0
- package/src/lib/win-exec.ts +115 -0
- package/src/lib/win-paths.ts +68 -0
- package/src/lib/windows-elevation.ts +705 -0
- package/src/lib/windows-secret-acl.ts +514 -0
- package/src/lib/winsw.ts +375 -0
- package/src/oauth/anthropic-routing.ts +594 -0
- package/src/oauth/anthropic.ts +177 -0
- package/src/oauth/callback-server.ts +294 -0
- package/src/oauth/chatgpt.ts +150 -0
- package/src/oauth/cursor.ts +211 -0
- package/src/oauth/github-copilot.ts +428 -0
- package/src/oauth/google-antigravity.ts +230 -0
- package/src/oauth/health.ts +399 -0
- package/src/oauth/index.ts +1174 -0
- package/src/oauth/key-providers.ts +108 -0
- package/src/oauth/kimi.ts +213 -0
- package/src/oauth/kiro-credentials.ts +726 -0
- package/src/oauth/kiro.ts +577 -0
- package/src/oauth/local-token-detect.ts +121 -0
- package/src/oauth/log.ts +48 -0
- package/src/oauth/login-cli.ts +163 -0
- package/src/oauth/pkce.ts +15 -0
- package/src/oauth/store.ts +630 -0
- package/src/oauth/token-guardian.ts +303 -0
- package/src/oauth/types.ts +62 -0
- package/src/oauth/xai.ts +241 -0
- package/src/pi/extensions.ts +72 -0
- package/src/pi/home.ts +42 -0
- package/src/pi/index.ts +40 -0
- package/src/pi/models.ts +278 -0
- package/src/pi/packages.ts +219 -0
- package/src/pi/settings.ts +365 -0
- package/src/pi/status.ts +68 -0
- package/src/pi/sync.ts +75 -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 +205 -0
- package/src/providers/api-keys.ts +140 -0
- package/src/providers/base-url-choices.ts +64 -0
- package/src/providers/context-cap.ts +65 -0
- package/src/providers/derive.ts +339 -0
- package/src/providers/free-directory.ts +184 -0
- package/src/providers/github-copilot-transport.ts +56 -0
- package/src/providers/key-failover.ts +203 -0
- package/src/providers/kiro-models.ts +67 -0
- package/src/providers/label.ts +19 -0
- package/src/providers/model-discovery.ts +356 -0
- package/src/providers/openai-sidecar.ts +175 -0
- package/src/providers/openai-tier-startup.ts +27 -0
- package/src/providers/openai-tiers.ts +301 -0
- package/src/providers/openai-virtual-models.ts +82 -0
- package/src/providers/openrouter-routing.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +150 -0
- package/src/providers/quota.ts +1260 -0
- package/src/providers/registry.ts +1600 -0
- package/src/providers/slug-codec.ts +67 -0
- package/src/providers/xai-transport.ts +141 -0
- package/src/reasoning-effort.ts +135 -0
- package/src/responses/compaction.ts +117 -0
- package/src/responses/parser.ts +656 -0
- package/src/responses/reasoning-envelope.ts +52 -0
- package/src/responses/schema.ts +159 -0
- package/src/responses/spill-store.ts +394 -0
- package/src/responses/state.ts +895 -0
- package/src/responses/tool-groups.ts +19 -0
- package/src/router.ts +425 -0
- package/src/server/adapter-resolve.ts +80 -0
- package/src/server/auth-cors.ts +530 -0
- package/src/server/chat-completions.ts +368 -0
- package/src/server/claude-messages.ts +914 -0
- package/src/server/effort-policy.ts +172 -0
- package/src/server/gui-static.ts +123 -0
- package/src/server/image-retry.ts +42 -0
- package/src/server/images.ts +476 -0
- package/src/server/index.ts +1126 -0
- package/src/server/lifecycle.ts +227 -0
- package/src/server/live.ts +598 -0
- package/src/server/management/agent-settings-routes.ts +1169 -0
- package/src/server/management/api-access.ts +141 -0
- package/src/server/management/api-key-usage.ts +167 -0
- package/src/server/management/body.ts +35 -0
- package/src/server/management/clients-routes.ts +63 -0
- package/src/server/management/cloud-sync-routes.ts +266 -0
- package/src/server/management/combo-routes.ts +220 -0
- package/src/server/management/config-routes.ts +422 -0
- package/src/server/management/context.ts +31 -0
- package/src/server/management/logs-usage-routes.ts +707 -0
- package/src/server/management/model-routes.ts +525 -0
- package/src/server/management/oauth-account-routes.ts +563 -0
- package/src/server/management/provider-routes.ts +556 -0
- package/src/server/management/shared.ts +277 -0
- package/src/server/management/sidebar-routes.ts +90 -0
- package/src/server/management/system-restart.ts +179 -0
- package/src/server/management/system-routes.ts +117 -0
- package/src/server/management/usage-summary-cache.ts +86 -0
- package/src/server/management-api.ts +215 -0
- package/src/server/management-auth.ts +267 -0
- package/src/server/memory-watchdog.ts +156 -0
- package/src/server/port-reclaim.ts +307 -0
- package/src/server/ports.ts +116 -0
- package/src/server/proxy-liveness.ts +201 -0
- package/src/server/relay-eager.ts +313 -0
- package/src/server/relay.ts +1049 -0
- package/src/server/request-decompress.ts +132 -0
- package/src/server/request-log-conversation.ts +168 -0
- package/src/server/request-log.ts +1046 -0
- package/src/server/responses/collaboration.ts +354 -0
- package/src/server/responses/compact.ts +384 -0
- package/src/server/responses/core.ts +2758 -0
- package/src/server/responses/encrypted-payload.ts +308 -0
- package/src/server/responses/fetch-helpers.ts +157 -0
- package/src/server/responses/passthrough-error.ts +78 -0
- package/src/server/responses/terminal-guard.ts +230 -0
- package/src/server/responses/upstream-error.ts +48 -0
- package/src/server/responses-image-gen-repair.ts +132 -0
- package/src/server/responses-item-id-repair.ts +224 -0
- package/src/server/responses.ts +9 -0
- package/src/server/search.ts +136 -0
- package/src/server/sse-payload-rewrite.ts +175 -0
- package/src/server/startup-action-control.ts +308 -0
- package/src/server/startup-health-cache.ts +113 -0
- package/src/server/system-env.ts +413 -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 +471 -0
- package/src/service.ts +2554 -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 +290 -0
- package/src/tray/windows.ts +730 -0
- package/src/types.ts +1237 -0
- package/src/update/badge.ts +72 -0
- package/src/update/index.ts +407 -0
- package/src/update/job.ts +1520 -0
- package/src/update/notify.ts +257 -0
- package/src/update/npm-invocation.d.mts +23 -0
- package/src/update/npm-invocation.mjs +94 -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 +0 -0
- package/src/usage/debug.ts +97 -0
- package/src/usage/expected-prices.ts +164 -0
- package/src/usage/log.ts +658 -0
- package/src/usage/summary.ts +585 -0
- package/src/usage/totals.ts +14 -0
- package/src/vision/anthropic-describe.ts +185 -0
- package/src/vision/describe.ts +125 -0
- package/src/vision/index.ts +467 -0
- package/src/web-search/anthropic-executor.ts +189 -0
- package/src/web-search/executor.ts +105 -0
- package/src/web-search/format-result.ts +89 -0
- package/src/web-search/index.ts +196 -0
- package/src/web-search/loop.ts +664 -0
- package/src/web-search/parse.ts +220 -0
- package/src/web-search/progress-stream.ts +342 -0
- package/src/web-search/synthetic-tool.ts +47 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, realpathSync } from "node:fs";
|
|
4
|
+
import { delimiter, dirname, join, resolve } from "node:path";
|
|
5
|
+
import { atomicWriteFile, expandUserPath, getConfigDir, websocketsEnabled } from "../../config";
|
|
6
|
+
import { CODEX_CONFIG_PATH, CODEX_MODELS_CACHE_PATH, DEFAULT_CATALOG_PATH, readRootTomlString, resolveCodexConfigPath } from "../paths";
|
|
7
|
+
import { clearModelCache, DEFAULT_MODEL_CACHE_TTL_MS, getFreshCached, getStaleCached, isModelsFetchCoolingDown, markModelsFetchFailure, setCached } from "../model-cache";
|
|
8
|
+
import { buildModelsRequest, resolveModelsAuthToken } from "../../oauth";
|
|
9
|
+
import type { OcxConfig, OcxProviderConfig } from "../../types";
|
|
10
|
+
import { modelInList } from "../../types";
|
|
11
|
+
import { CODEX_REASONING_LEVELS, codexEffortRank, configuredReasoningEfforts, modelRecordValue, sanitizeCodexReasoningEfforts } from "../../reasoning-effort";
|
|
12
|
+
import { getJawcodeModelMetadata, getJawcodeModelMetadataCaseInsensitive, listJawcodeModelMetadata, resolveJawcodeProvider } from "../../generated/jawcode-model-metadata";
|
|
13
|
+
import { enrichProviderFromRegistry, shouldCaseFoldMetadataModelId } from "../../providers/derive";
|
|
14
|
+
import { getProviderRegistryEntry } from "../../providers/registry";
|
|
15
|
+
import { applyProviderContextCap, providerContextCap } from "../../providers/context-cap";
|
|
16
|
+
import { encodeRoutedModelId, routedSlug, slugEquals, slugsEquivalent } from "../../providers/slug-codec";
|
|
17
|
+
import { CODEX_GPT5_IDENTITY_LINE } from "../../adapters/identity";
|
|
18
|
+
import { filterCursorConfiguredModelsByLiveDiscovery } from "../../adapters/cursor/discovery";
|
|
19
|
+
import { fetchCursorUsableModels } from "../../adapters/cursor/live-models";
|
|
20
|
+
import { isCanonicalOpenAiForwardProvider, OPENAI_API_PROVIDER_ID, OPENAI_CODEX_PROVIDER_ID } from "../../providers/openai-tiers";
|
|
21
|
+
import {
|
|
22
|
+
COMBO_NAMESPACE,
|
|
23
|
+
comboModelId,
|
|
24
|
+
getCombo,
|
|
25
|
+
listComboIds,
|
|
26
|
+
targetKey,
|
|
27
|
+
} from "../../combos";
|
|
28
|
+
import type { NormalizedComboConfig } from "../../combos/types";
|
|
29
|
+
import { providerDestinationResolvedError } from "../../lib/destination-policy";
|
|
30
|
+
import { redactSecretString } from "../../lib/redact";
|
|
31
|
+
import upstreamModelsSnapshot from "../data/upstream-models.json";
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
import { NATIVE_OPENAI_CONTEXT_OVERRIDES, SUPPORTED_NATIVE_OPENAI_SLUGS, UPSTREAM_NATIVE_ENTRIES } from "./metadata";
|
|
35
|
+
|
|
36
|
+
export function legacyCatalogBackupPath(): string {
|
|
37
|
+
return join(getConfigDir(), "catalog-backup.json");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function catalogBackupPathFor(catalogPath: string): string {
|
|
41
|
+
const normalized = process.platform === "win32" ? resolve(catalogPath).toLowerCase() : resolve(catalogPath);
|
|
42
|
+
const id = createHash("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
43
|
+
return join(getConfigDir(), `catalog-backup-${id}.json`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function samePath(a: string, b: string): boolean {
|
|
47
|
+
const left = resolve(a);
|
|
48
|
+
const right = resolve(b);
|
|
49
|
+
return process.platform === "win32" ? left.toLowerCase() === right.toLowerCase() : left === right;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function activeCodexHome(): string | null {
|
|
53
|
+
const raw = process.env.CODEX_HOME?.trim();
|
|
54
|
+
if (!raw) return null;
|
|
55
|
+
const path = resolve(expandUserPath(raw));
|
|
56
|
+
try {
|
|
57
|
+
return realpathSync.native(path);
|
|
58
|
+
} catch {
|
|
59
|
+
return path;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function activeCodexConfigPath(): string {
|
|
64
|
+
const home = activeCodexHome();
|
|
65
|
+
return home ? join(home, "config.toml") : CODEX_CONFIG_PATH;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function activeDefaultCatalogPath(): string {
|
|
69
|
+
const home = activeCodexHome();
|
|
70
|
+
return home ? join(home, "opencodex-catalog.json") : DEFAULT_CATALOG_PATH;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function activeCodexModelsCachePath(): string {
|
|
74
|
+
const home = activeCodexHome();
|
|
75
|
+
return home ? join(home, "models_cache.json") : CODEX_MODELS_CACHE_PATH;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function resolveActiveCodexConfigPath(path: string): string {
|
|
79
|
+
const home = activeCodexHome();
|
|
80
|
+
return home ? resolve(home, path) : resolveCodexConfigPath(path);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function isDefaultCatalogPath(path: string): boolean {
|
|
84
|
+
return samePath(path, activeDefaultCatalogPath());
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface CatalogModel {
|
|
88
|
+
id: string;
|
|
89
|
+
provider: string;
|
|
90
|
+
/** Public Codex-facing slug override (used by combo aliases). */
|
|
91
|
+
alias?: string;
|
|
92
|
+
/**
|
|
93
|
+
* Display-only Codex catalog `display_name` override. Relabels the picker row ONLY — it never
|
|
94
|
+
* affects the routing slug, alias-collision order, native marketing-name precedence, or provider
|
|
95
|
+
* behavior. When unset, the entry falls back to its Codex-facing slug (the historical behavior).
|
|
96
|
+
* Native upstream entries (e.g. gpt-5.6-sol → "GPT-5.6-Sol") come from the pinned snapshot path
|
|
97
|
+
* which carries no CatalogModel, so a configured displayName can never override a native name.
|
|
98
|
+
*/
|
|
99
|
+
displayName?: string;
|
|
100
|
+
owned_by?: string;
|
|
101
|
+
reasoningEfforts?: string[];
|
|
102
|
+
defaultReasoningEffort?: string;
|
|
103
|
+
contextWindow?: number;
|
|
104
|
+
maxInputTokens?: number;
|
|
105
|
+
contextCap?: number;
|
|
106
|
+
contextCapped?: boolean;
|
|
107
|
+
inputModalities?: string[];
|
|
108
|
+
/** Provider opted into parallel tool calls (OcxProviderConfig.parallelToolCalls). */
|
|
109
|
+
parallelToolCalls?: boolean;
|
|
110
|
+
/** Whether Codex may send Responses text.verbosity for this routed model. */
|
|
111
|
+
supportsVerbosity?: boolean;
|
|
112
|
+
supportsReasoningSummaries?: boolean;
|
|
113
|
+
/** Normalized upstream capability names retained for management/API consumers (#485 follow-up). */
|
|
114
|
+
capabilities?: string[];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export type RawEntry = Record<string, unknown>;
|
|
118
|
+
|
|
119
|
+
export type RawCatalog = { models?: RawEntry[]; [k: string]: unknown };
|
|
120
|
+
|
|
121
|
+
export const JAWCODE_CATALOG_AUGMENT_PROVIDERS = new Set(["opencode-go"]);
|
|
122
|
+
|
|
123
|
+
export const ROUTED_MODEL_COMPATIBILITY_EXCLUSIONS = new Set([
|
|
124
|
+
// Issue #82: Zen Go /models advertises HY3, but Console Go rejects it as outside the lite list.
|
|
125
|
+
"opencode-go/hy3-preview",
|
|
126
|
+
]);
|
|
127
|
+
|
|
128
|
+
export function isRoutedModelCompatibilityExcluded(slug: string): boolean {
|
|
129
|
+
return ROUTED_MODEL_COMPATIBILITY_EXCLUSIONS.has(slug);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export const MEDIA_GEN_FAMILIES = [
|
|
133
|
+
"dall-e", "dalle", "imagen", "sora", "veo", "flux", "kling",
|
|
134
|
+
"seedance", "hailuo", "stable-diffusion", "sdxl", "midjourney",
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
export const MEDIA_GEN_ID_RE = new RegExp(
|
|
138
|
+
`(?:^|[/_-])(?:image|video)(?:[/_-]|$)|(?:^|[/_-])(?:${MEDIA_GEN_FAMILIES.join("|")})(?:[/_-]|$|\\d)`,
|
|
139
|
+
"i",
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
export function isMediaGenerationModelId(id: string): boolean {
|
|
143
|
+
return MEDIA_GEN_ID_RE.test(id);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Gemini image-capable chat models produce inline images within text responses
|
|
148
|
+
* via the Responses API. Explicit allowlist only — a broad `/gemini/ && /image/`
|
|
149
|
+
* heuristic resurrects standalone media-gen IDs (e.g. gemini-3-pro-image).
|
|
150
|
+
*/
|
|
151
|
+
const GEMINI_IMAGE_CHAT_MODEL_IDS = new Set([
|
|
152
|
+
"gemini-3.1-flash-image",
|
|
153
|
+
"gemini-2.0-flash-preview-image-generation",
|
|
154
|
+
"gemini-3-pro-image-preview",
|
|
155
|
+
]);
|
|
156
|
+
|
|
157
|
+
function isGeminiImageChatModel(id: string): boolean {
|
|
158
|
+
return GEMINI_IMAGE_CHAT_MODEL_IDS.has(id);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function shouldExposeRoutedModel(model: CatalogModel): boolean {
|
|
162
|
+
if (isRoutedModelCompatibilityExcluded(`${model.provider}/${model.id}`)) return false;
|
|
163
|
+
if (isGeminiImageChatModel(model.id)) return true;
|
|
164
|
+
return !isMediaGenerationModelId(model.id);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function readCodexCatalogPath(): string {
|
|
168
|
+
try {
|
|
169
|
+
const configPath = activeCodexConfigPath();
|
|
170
|
+
if (existsSync(configPath)) {
|
|
171
|
+
const toml = readFileSync(configPath, "utf-8");
|
|
172
|
+
const path = readRootTomlString(toml, "model_catalog_json");
|
|
173
|
+
if (path) return resolveActiveCodexConfigPath(path);
|
|
174
|
+
}
|
|
175
|
+
} catch { /* ignore */ }
|
|
176
|
+
return activeDefaultCatalogPath();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function parseCatalogJson(raw: string): RawCatalog | null {
|
|
180
|
+
try {
|
|
181
|
+
const cat = JSON.parse(raw);
|
|
182
|
+
return (cat && Array.isArray(cat.models)) ? cat : null;
|
|
183
|
+
} catch { return null; }
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function readCatalog(path: string): RawCatalog | null {
|
|
187
|
+
try {
|
|
188
|
+
if (!existsSync(path)) return null;
|
|
189
|
+
return parseCatalogJson(readFileSync(path, "utf-8"));
|
|
190
|
+
} catch { return null; }
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function findNativeTemplate(catalog: RawCatalog | null): RawEntry | null {
|
|
194
|
+
return catalog?.models?.find(
|
|
195
|
+
m => typeof m.slug === "string" && !m.slug.includes("/") && "base_instructions" in m,
|
|
196
|
+
) ?? null;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Native OpenAI slugs that do NOT support the Fast (priority) service tier.
|
|
201
|
+
* Upstream may advertise service_tiers for these models, but the tier is not
|
|
202
|
+
* actually available — strip it so the Codex UI does not offer a dead toggle.
|
|
203
|
+
*/
|
|
204
|
+
const NO_FAST_TIER_NATIVE_SLUGS = new Set([
|
|
205
|
+
"gpt-5.3-codex-spark",
|
|
206
|
+
]);
|
|
207
|
+
|
|
208
|
+
export function normalizeServiceTiers(entry: RawEntry): RawEntry {
|
|
209
|
+
// Strip service tiers for models that do not actually support the Fast tier.
|
|
210
|
+
if (typeof entry.slug === "string" && NO_FAST_TIER_NATIVE_SLUGS.has(entry.slug)) {
|
|
211
|
+
delete entry.service_tier;
|
|
212
|
+
delete entry.service_tiers;
|
|
213
|
+
delete entry.default_service_tier;
|
|
214
|
+
delete entry.additional_speed_tiers;
|
|
215
|
+
return entry;
|
|
216
|
+
}
|
|
217
|
+
// Codex stores the user-facing config spelling as "fast", but the catalog/request
|
|
218
|
+
// service tier id is "priority" in current codex-rs. Keep legacy catalogs working.
|
|
219
|
+
if (entry.service_tier === "fast") entry.service_tier = "priority";
|
|
220
|
+
if (Array.isArray(entry.service_tiers)) {
|
|
221
|
+
entry.service_tiers = entry.service_tiers.map(tier => {
|
|
222
|
+
if (tier && typeof tier === "object" && "id" in tier && tier.id === "fast") {
|
|
223
|
+
return { ...tier, id: "priority" };
|
|
224
|
+
}
|
|
225
|
+
return tier;
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
return entry;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function ensureAutoCompactTokenLimit(entry: RawEntry): RawEntry {
|
|
232
|
+
if (
|
|
233
|
+
typeof entry.context_window === "number"
|
|
234
|
+
&& entry.context_window > 0
|
|
235
|
+
&& typeof entry.auto_compact_token_limit !== "number"
|
|
236
|
+
) {
|
|
237
|
+
entry.auto_compact_token_limit = Math.floor(entry.context_window * 0.9);
|
|
238
|
+
}
|
|
239
|
+
return entry;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export function isNativeOpenAiEntry(entry: RawEntry): boolean {
|
|
243
|
+
return typeof entry.slug === "string" && !entry.slug.includes("/");
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function applyNativeOpenAiContextOverride(entry: RawEntry): void {
|
|
247
|
+
if (!isNativeOpenAiEntry(entry)) return;
|
|
248
|
+
const override = NATIVE_OPENAI_CONTEXT_OVERRIDES[entry.slug as string];
|
|
249
|
+
if (!override) return;
|
|
250
|
+
if (typeof override.contextWindow === "number") {
|
|
251
|
+
entry.context_window = override.contextWindow;
|
|
252
|
+
entry.auto_compact_token_limit = Math.floor(override.contextWindow * 0.9);
|
|
253
|
+
}
|
|
254
|
+
if (typeof override.maxContextWindow === "number") {
|
|
255
|
+
entry.max_context_window = override.maxContextWindow;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export function ensureStrictCatalogFields(
|
|
260
|
+
entry: RawEntry,
|
|
261
|
+
options: { preserveExactInputModalities?: boolean; isRouted?: boolean } = {},
|
|
262
|
+
): RawEntry {
|
|
263
|
+
if (typeof entry.supports_reasoning_summaries !== "boolean") entry.supports_reasoning_summaries = false;
|
|
264
|
+
if (typeof entry.default_reasoning_summary !== "string") entry.default_reasoning_summary = "none";
|
|
265
|
+
if (typeof entry.support_verbosity !== "boolean") entry.support_verbosity = true;
|
|
266
|
+
if (typeof entry.default_verbosity !== "string") entry.default_verbosity = "low";
|
|
267
|
+
if (typeof entry.apply_patch_tool_type !== "string") entry.apply_patch_tool_type = "freeform";
|
|
268
|
+
if (!entry.truncation_policy || typeof entry.truncation_policy !== "object" || Array.isArray(entry.truncation_policy)) {
|
|
269
|
+
entry.truncation_policy = { mode: "tokens", limit: 10000 };
|
|
270
|
+
}
|
|
271
|
+
if (typeof entry.supports_parallel_tool_calls !== "boolean") entry.supports_parallel_tool_calls = true;
|
|
272
|
+
if (typeof entry.supports_image_detail_original !== "boolean") entry.supports_image_detail_original = false;
|
|
273
|
+
if (!Array.isArray(entry.experimental_supported_tools)) entry.experimental_supported_tools = [];
|
|
274
|
+
if (!Array.isArray(entry.input_modalities) && !options.preserveExactInputModalities) {
|
|
275
|
+
entry.input_modalities = ["text"];
|
|
276
|
+
}
|
|
277
|
+
// Codex parses `input_modalities` as a closed enum. One out-of-enum value (zenmux advertises
|
|
278
|
+
// "video") makes its config loader reject the entire catalog, which takes down plugins, apps and
|
|
279
|
+
// MCP servers — not just that model. Normalize at the single point every entry passes through,
|
|
280
|
+
// because provider metadata, jawcode metadata and effort sync each write this field.
|
|
281
|
+
if (Array.isArray(entry.input_modalities)) {
|
|
282
|
+
const accepted = entry.input_modalities.filter(value =>
|
|
283
|
+
value === "text" || value === "image" || value === "audio");
|
|
284
|
+
// Never leave it empty: an entry with no modality at all is worse than a text-only one.
|
|
285
|
+
entry.input_modalities = accepted.length > 0 ? accepted : ["text"];
|
|
286
|
+
}
|
|
287
|
+
const contextWindow = typeof entry.context_window === "number" && entry.context_window > 0 ? entry.context_window : 128000;
|
|
288
|
+
entry.context_window = contextWindow;
|
|
289
|
+
if (
|
|
290
|
+
typeof entry.max_context_window !== "number"
|
|
291
|
+
|| entry.max_context_window <= 0
|
|
292
|
+
|| ((options.isRouted === true || !isNativeOpenAiEntry(entry)) && entry.max_context_window > contextWindow)
|
|
293
|
+
) {
|
|
294
|
+
entry.max_context_window = contextWindow;
|
|
295
|
+
}
|
|
296
|
+
if (typeof entry.effective_context_window_percent !== "number") entry.effective_context_window_percent = 95;
|
|
297
|
+
if (typeof entry.comp_hash !== "string") entry.comp_hash = "opencodex";
|
|
298
|
+
return ensureAutoCompactTokenLimit(entry);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export type MultiAgentMode = "v1" | "default" | "v2";
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* @param v2FeatureEnabled When the native multi_agent_v2 feature is on, "default"
|
|
305
|
+
* mode stamps unpinned entries as "v2" instead of deleting the key. The native
|
|
306
|
+
* binary validates spawn_agent models against THIS catalog with its own
|
|
307
|
+
* `multi_agent_version == Some(V2)` test (codex-rs multi_agents_common.rs), so an
|
|
308
|
+
* absent pin means a clean refusal at spawn time — exactly the cross-provider
|
|
309
|
+
* spawns opencodex exists to enable (option B, devlog
|
|
310
|
+
* 260730_codex_rs_upstream_v2_live_handoff/060). Upstream pins are always
|
|
311
|
+
* preserved: a genuine "v1" pin is a real capability statement and stays excluded.
|
|
312
|
+
* With the feature off the output is byte-identical to the historical behavior.
|
|
313
|
+
*/
|
|
314
|
+
export function applyMultiAgentMode(entries: RawEntry[], mode: MultiAgentMode, v2FeatureEnabled = false): RawEntry[] {
|
|
315
|
+
if (mode === "default") {
|
|
316
|
+
// Restore upstream defaults: clear any stale forced multi_agent_version and
|
|
317
|
+
// re-apply upstream pins from the snapshot for native entries that have one.
|
|
318
|
+
for (const entry of entries) {
|
|
319
|
+
const slug = typeof entry.slug === "string" ? entry.slug : "";
|
|
320
|
+
const upstream = UPSTREAM_NATIVE_ENTRIES.get(slug);
|
|
321
|
+
const upstreamPin = upstream?.multi_agent_version;
|
|
322
|
+
if (typeof upstreamPin === "string") {
|
|
323
|
+
entry.multi_agent_version = upstreamPin;
|
|
324
|
+
} else if (v2FeatureEnabled) {
|
|
325
|
+
entry.multi_agent_version = "v2";
|
|
326
|
+
} else {
|
|
327
|
+
delete entry.multi_agent_version;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return entries;
|
|
331
|
+
}
|
|
332
|
+
for (const entry of entries) {
|
|
333
|
+
entry.multi_agent_version = mode;
|
|
334
|
+
}
|
|
335
|
+
return entries;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export function normalizeRoutedCatalogEntry(entry: RawEntry, parallelToolCalls = false): RawEntry {
|
|
339
|
+
delete entry.model_messages;
|
|
340
|
+
delete entry.tool_mode;
|
|
341
|
+
delete entry.multi_agent_version;
|
|
342
|
+
delete entry.use_responses_lite;
|
|
343
|
+
delete entry.supports_websockets;
|
|
344
|
+
delete entry.additional_speed_tiers;
|
|
345
|
+
delete entry.service_tier;
|
|
346
|
+
delete entry.service_tiers;
|
|
347
|
+
delete entry.default_service_tier;
|
|
348
|
+
// Routed rows cloned from native templates must not inherit OpenAI-only summary delivery.
|
|
349
|
+
// Per-model routed opt-ins can be added once provider metadata exposes this capability.
|
|
350
|
+
delete entry.supports_reasoning_summaries;
|
|
351
|
+
const isCursorEntry = typeof entry.slug === "string" && entry.slug.startsWith("cursor/");
|
|
352
|
+
// Routed providers use opencodex sidecars and client-executed tool discovery. The sidecar
|
|
353
|
+
// runs through native gpt-5.4-mini, so image search is available and verbalized for text-only
|
|
354
|
+
// models. EXCEPT cursor: its runTurn transport bypasses the web-search plan entirely and
|
|
355
|
+
// rejects server search queries — advertising the tool would make models call into a void.
|
|
356
|
+
if (isCursorEntry) {
|
|
357
|
+
delete entry.web_search_tool_type;
|
|
358
|
+
entry.supports_search_tool = false;
|
|
359
|
+
} else {
|
|
360
|
+
entry.web_search_tool_type = "text_and_image";
|
|
361
|
+
entry.supports_search_tool = true;
|
|
362
|
+
}
|
|
363
|
+
// Cursor's transport already serializes overlapping tool calls into atomic Responses tool events.
|
|
364
|
+
// Advertising parallel calls lets Codex send the same native capability bit it sends for OpenAI.
|
|
365
|
+
// Opt-in providers (OcxProviderConfig.parallelToolCalls, e.g. xAI) advertise it too: the
|
|
366
|
+
// openai-chat adapter stops forcing parallel_tool_calls:false and the buffered stream parser
|
|
367
|
+
// assembles multi-call turns (devlog/_plan/260709_parallel_tool_calls).
|
|
368
|
+
entry.supports_parallel_tool_calls = isCursorEntry || parallelToolCalls === true;
|
|
369
|
+
return ensureStrictCatalogFields(entry, { isRouted: true });
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Resolve reasoning-summary support from the active Codex catalog for wire sanitization. */
|
|
373
|
+
export function catalogModelSupportsReasoningSummaries(modelId: string): boolean | undefined {
|
|
374
|
+
if (typeof modelId !== "string" || modelId.length === 0) return undefined;
|
|
375
|
+
const catalog = readCatalog(readCodexCatalogPath()) ?? readCatalog(activeCodexModelsCachePath());
|
|
376
|
+
const models = catalog?.models ?? [];
|
|
377
|
+
const exact = models.find(entry => entry.slug === modelId || entry.id === modelId);
|
|
378
|
+
if (typeof exact?.supports_reasoning_summaries === "boolean") {
|
|
379
|
+
return exact.supports_reasoning_summaries;
|
|
380
|
+
}
|
|
381
|
+
const encodedModelId = encodeRoutedModelId(modelId);
|
|
382
|
+
const matches = models.filter(entry => (
|
|
383
|
+
typeof entry.slug === "string"
|
|
384
|
+
&& entry.slug.includes("/")
|
|
385
|
+
&& entry.slug.slice(entry.slug.indexOf("/") + 1) === encodedModelId
|
|
386
|
+
&& typeof entry.supports_reasoning_summaries === "boolean"
|
|
387
|
+
));
|
|
388
|
+
const values = new Set(matches.map(entry => entry.supports_reasoning_summaries as boolean));
|
|
389
|
+
return values.size === 1 ? values.values().next().value : undefined;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
export function applyJawcodeCatalogMetadata(entry: RawEntry, provider: string, modelId: string, contextCap?: number): void {
|
|
393
|
+
const jawcodeProvider = resolveJawcodeProvider(provider);
|
|
394
|
+
if (!jawcodeProvider) return;
|
|
395
|
+
const meta = getJawcodeModelMetadata(jawcodeProvider, modelId)
|
|
396
|
+
?? (shouldCaseFoldMetadataModelId(provider) ? getJawcodeModelMetadataCaseInsensitive(jawcodeProvider, modelId) : undefined);
|
|
397
|
+
if (!meta) return;
|
|
398
|
+
if (typeof meta.contextWindow === "number" && meta.contextWindow > 0) {
|
|
399
|
+
const contextWindow = applyProviderContextCap(meta.contextWindow, contextCap) ?? meta.contextWindow;
|
|
400
|
+
entry.context_window = contextWindow;
|
|
401
|
+
entry.max_context_window = contextWindow;
|
|
402
|
+
entry.auto_compact_token_limit = Math.floor(contextWindow * 0.9);
|
|
403
|
+
}
|
|
404
|
+
if (Array.isArray(meta.input) && meta.input.length > 0) {
|
|
405
|
+
entry.input_modalities = meta.input;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export function catalogModelSlug(model: CatalogModel): string {
|
|
410
|
+
return model.alias ?? routedSlug(model.provider, model.id);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export function filterSupportedNativeSlugs(models: RawEntry[]): string[] {
|
|
414
|
+
return models
|
|
415
|
+
.filter(m => typeof m.slug === "string" && !(m.slug as string).includes("/") && m.visibility === "list" && SUPPORTED_NATIVE_OPENAI_SLUGS.has(m.slug as string))
|
|
416
|
+
.map(m => m.slug as string);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export function readCatalogBackup(catalogPath: string): RawCatalog | null {
|
|
420
|
+
return readCatalog(catalogBackupPathFor(catalogPath))
|
|
421
|
+
?? (isDefaultCatalogPath(catalogPath) ? readCatalog(legacyCatalogBackupPath()) : null);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export function catalogHasRoutedEntries(catalog: RawCatalog | null): boolean {
|
|
425
|
+
return (catalog?.models ?? []).some(m => typeof m.slug === "string" && m.slug.includes("/"));
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
export function writePristineCatalogBackup(backupPath: string, catalogPath: string, catalog: RawCatalog): void {
|
|
429
|
+
if (existsSync(backupPath)) return;
|
|
430
|
+
const onDisk = readCatalog(catalogPath);
|
|
431
|
+
if (onDisk && !catalogHasRoutedEntries(onDisk)) {
|
|
432
|
+
copyFileSync(catalogPath, backupPath);
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
if (!catalogHasRoutedEntries(catalog)) {
|
|
436
|
+
atomicWriteFile(backupPath, JSON.stringify(catalog, null, 2) + "\n");
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export function ensureCatalogBackup(catalogPath: string, catalog: RawCatalog): void {
|
|
441
|
+
const dir = getConfigDir();
|
|
442
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
443
|
+
writePristineCatalogBackup(catalogBackupPathFor(catalogPath), catalogPath, catalog);
|
|
444
|
+
if (isDefaultCatalogPath(catalogPath)) writePristineCatalogBackup(legacyCatalogBackupPath(), catalogPath, catalog);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
export function readNativeBaseline(catalogPath: string): Map<string, number> {
|
|
448
|
+
const backup = readCatalogBackup(catalogPath);
|
|
449
|
+
const out = new Map<string, number>();
|
|
450
|
+
for (const e of backup?.models ?? []) {
|
|
451
|
+
if (typeof e.slug === "string" && !e.slug.includes("/") && typeof e.priority === "number") {
|
|
452
|
+
out.set(e.slug, e.priority);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return out;
|
|
456
|
+
}
|