@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,156 @@
|
|
|
1
|
+
import { ALIBABA_INTL_BASE_URL_CHOICES } from "./base-url-choices";
|
|
2
|
+
import { providerConfigSeed } from "./derive";
|
|
3
|
+
import { rewriteProviderReferences } from "./provider-id-rewrite";
|
|
4
|
+
import { PROVIDER_REGISTRY } from "./registry";
|
|
5
|
+
import { codexAccountNamespaceProviderCollisionError } from "../codex/account-namespace-match";
|
|
6
|
+
import type { OcxConfig, OcxProviderConfig } from "../types";
|
|
7
|
+
|
|
8
|
+
const BEIJING_ID = "alibaba-token-plan";
|
|
9
|
+
const INTL_ID = "alibaba-token-plan-intl";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Credentials and switches the user owns directly. Everything else on the moved
|
|
13
|
+
* row is registry-derived Beijing metadata (`ocx provider add` and the GUI persist
|
|
14
|
+
* it, and registry enrichment only fills absent fields) and must NOT travel to the
|
|
15
|
+
* international id — carrying it would leave the intl provider serving Singapore
|
|
16
|
+
* while advertising the six-model Beijing Personal Edition catalog.
|
|
17
|
+
*
|
|
18
|
+
* `baseUrl` is carried deliberately: the migration only fires for a URL that
|
|
19
|
+
* `ALIBABA_INTL_BASE_URL_CHOICES` recognises, so it is nonblank and
|
|
20
|
+
* placeholder-free and satisfies the override guard in the router.
|
|
21
|
+
* `liveModels` is carried because it is directly user-editable, so resetting it
|
|
22
|
+
* to the seed's `false` would silently undo a deliberate choice.
|
|
23
|
+
* `authMode` is NOT carried — both entries are key-auth and the seed's value is
|
|
24
|
+
* the one matching the destination's registry contract.
|
|
25
|
+
* `defaultModel` and `note` are user-editable too and are handled below.
|
|
26
|
+
*/
|
|
27
|
+
const USER_OWNED_FIELDS = ["apiKey", "apiKeyPool", "disabled", "baseUrl", "allowPrivateNetwork", "liveModels"] as const;
|
|
28
|
+
|
|
29
|
+
export interface AlibabaRegionMigrationProjection {
|
|
30
|
+
config: OcxConfig;
|
|
31
|
+
changed: boolean;
|
|
32
|
+
warnings: string[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const normalize = (url: string): string => url.trim().replace(/\/+$/, "").toLowerCase();
|
|
36
|
+
|
|
37
|
+
/** True when the saved URL is one the international entry actually serves. */
|
|
38
|
+
function isInternationalEndpoint(baseUrl: string): boolean {
|
|
39
|
+
return ALIBABA_INTL_BASE_URL_CHOICES.some(
|
|
40
|
+
choice => choice.baseUrl && normalize(choice.baseUrl) === normalize(baseUrl),
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Seed the destination from the international registry entry, then overlay only
|
|
46
|
+
* what the user owns. `providerConfigSeed` is the same function `ocx provider add`
|
|
47
|
+
* uses, so the migrated row is indistinguishable from one the user had created
|
|
48
|
+
* against the international provider directly.
|
|
49
|
+
*/
|
|
50
|
+
function buildIntlRow(source: OcxProviderConfig): OcxProviderConfig {
|
|
51
|
+
const entry = PROVIDER_REGISTRY.find(e => e.id === INTL_ID);
|
|
52
|
+
// Fail fast rather than fabricate a row: a missing registry entry means the
|
|
53
|
+
// destination this migration targets no longer exists.
|
|
54
|
+
if (!entry) throw new Error(`registry entry "${INTL_ID}" not found; cannot migrate "${BEIJING_ID}"`);
|
|
55
|
+
const seeded = providerConfigSeed(entry);
|
|
56
|
+
const writable = seeded as unknown as Record<string, unknown>;
|
|
57
|
+
const readable = source as unknown as Record<string, unknown>;
|
|
58
|
+
for (const field of USER_OWNED_FIELDS) {
|
|
59
|
+
if (readable[field] !== undefined) writable[field] = readable[field];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const servable = new Set(entry.models ?? []);
|
|
63
|
+
// A user-chosen default survives only when the destination can actually serve
|
|
64
|
+
// it; otherwise the international default already on the seed stands.
|
|
65
|
+
if (source.defaultModel && servable.has(source.defaultModel)) seeded.defaultModel = source.defaultModel;
|
|
66
|
+
// Same rule for the allowlist, handled here where the destination catalog is
|
|
67
|
+
// known — never by the generic reference rewriter.
|
|
68
|
+
const selected = source.selectedModels?.filter(id => servable.has(id));
|
|
69
|
+
if (selected && selected.length > 0) seeded.selectedModels = selected;
|
|
70
|
+
else delete seeded.selectedModels;
|
|
71
|
+
|
|
72
|
+
// `providerConfigSeed` does not carry `note`, so seed the destination's registry
|
|
73
|
+
// note explicitly, then let a genuinely user-authored note win. Comparing
|
|
74
|
+
// against the SOURCE registry note is what distinguishes "the user typed this"
|
|
75
|
+
// from "the Beijing entry's stock note came along for the ride".
|
|
76
|
+
const beijingNote = PROVIDER_REGISTRY.find(e => e.id === BEIJING_ID)?.note;
|
|
77
|
+
if (entry.note) seeded.note = entry.note;
|
|
78
|
+
if (source.note && source.note !== beijingNote) seeded.note = source.note;
|
|
79
|
+
|
|
80
|
+
return seeded;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Repair a config whose `alibaba-token-plan` entry points at an international
|
|
85
|
+
* endpoint (issue #457). The Beijing entry is pinned to cn-beijing and does not
|
|
86
|
+
* take a baseUrl override by design, so such a config routes an international key
|
|
87
|
+
* to Beijing and fails with 401 on every request.
|
|
88
|
+
*
|
|
89
|
+
* The entry is MOVED to `alibaba-token-plan-intl` rather than the Beijing entry
|
|
90
|
+
* being taught to serve Singapore: the two ids carry different model lists,
|
|
91
|
+
* context windows, modality maps and dashboards, and a URL override cannot carry
|
|
92
|
+
* those contracts across. That override fix shipped once, was backed out twice,
|
|
93
|
+
* and was refused again when PR #459 closed.
|
|
94
|
+
*
|
|
95
|
+
* Refuses to act when the destination is reserved by an account namespace or
|
|
96
|
+
* already holds a value — a provider row or a key the reference rewrite would
|
|
97
|
+
* land on — because choosing which setting wins is a user decision, not a
|
|
98
|
+
* migration's.
|
|
99
|
+
*/
|
|
100
|
+
export function projectAlibabaRegionMigration(config: OcxConfig): AlibabaRegionMigrationProjection {
|
|
101
|
+
const beijing = config.providers[BEIJING_ID];
|
|
102
|
+
const savedBaseUrl = typeof beijing?.baseUrl === "string" ? beijing.baseUrl : "";
|
|
103
|
+
if (!beijing || !savedBaseUrl || !isInternationalEndpoint(savedBaseUrl)) {
|
|
104
|
+
return { config, changed: false, warnings: [] };
|
|
105
|
+
}
|
|
106
|
+
if (codexAccountNamespaceProviderCollisionError(config.codexAccountNamespaces, INTL_ID)) {
|
|
107
|
+
return {
|
|
108
|
+
config,
|
|
109
|
+
changed: false,
|
|
110
|
+
warnings: [
|
|
111
|
+
`provider "${BEIJING_ID}" needs to move to "${INTL_ID}", but that destination is reserved `
|
|
112
|
+
+ `by a configured Codex account namespace. Nothing was changed. Rename the account `
|
|
113
|
+
+ `selector or move the provider manually, then restart.`,
|
|
114
|
+
],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (config.providers[INTL_ID]) {
|
|
118
|
+
return {
|
|
119
|
+
config,
|
|
120
|
+
changed: false,
|
|
121
|
+
warnings: [
|
|
122
|
+
`provider "${BEIJING_ID}" is configured with an international endpoint, but "${INTL_ID}" `
|
|
123
|
+
+ `already exists. Both were left untouched: merging two credential sets is not a decision `
|
|
124
|
+
+ `this migration can make. Move the key to "${INTL_ID}" and delete the unused entry.`,
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const projected = structuredClone(config);
|
|
130
|
+
delete projected.providers[BEIJING_ID];
|
|
131
|
+
projected.providers[INTL_ID] = buildIntlRow(beijing);
|
|
132
|
+
const { changed: rewritten, collisions } = rewriteProviderReferences(projected, BEIJING_ID, INTL_ID);
|
|
133
|
+
// The rewriter is not transactional, so the clone is already partly rewritten
|
|
134
|
+
// here. Returning the ORIGINAL config discards it.
|
|
135
|
+
if (collisions.length > 0) {
|
|
136
|
+
return {
|
|
137
|
+
config,
|
|
138
|
+
changed: false,
|
|
139
|
+
warnings: [
|
|
140
|
+
`provider "${BEIJING_ID}" needs to move to "${INTL_ID}", but ${collisions.join(", ")} `
|
|
141
|
+
+ `already hold values for the destination. Nothing was changed: choosing which value `
|
|
142
|
+
+ `survives is not a decision this migration can make. Resolve those entries and restart.`,
|
|
143
|
+
],
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
config: projected,
|
|
149
|
+
changed: true,
|
|
150
|
+
warnings: [
|
|
151
|
+
`moved provider "${BEIJING_ID}" to "${INTL_ID}": its saved endpoint is the international one, `
|
|
152
|
+
+ `which the Beijing entry cannot serve. ${rewritten} reference(s) were re-pointed; the `
|
|
153
|
+
+ `international model catalog now applies.`,
|
|
154
|
+
],
|
|
155
|
+
};
|
|
156
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { saveConfig } from "../config";
|
|
2
|
+
import { backupConfigBeforeAlibabaRegionMigration } from "./alibaba-region-backup";
|
|
3
|
+
import { projectAlibabaRegionMigration } from "./alibaba-region-migration";
|
|
4
|
+
import type { OcxConfig } from "../types";
|
|
5
|
+
|
|
6
|
+
export interface AlibabaRegionStartupDeps {
|
|
7
|
+
project: typeof projectAlibabaRegionMigration;
|
|
8
|
+
backup: () => void;
|
|
9
|
+
save: (config: OcxConfig) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Run the #457 recovery migration at startup.
|
|
14
|
+
*
|
|
15
|
+
* Fail-closed: a backup failure throws, and nothing between here and
|
|
16
|
+
* `startServer` catches it, so the proxy does not start rather than rewriting
|
|
17
|
+
* credentials without a rollback point. That is the same posture the OpenAI tier
|
|
18
|
+
* migration takes.
|
|
19
|
+
*/
|
|
20
|
+
export function runAlibabaRegionStartupMigration(
|
|
21
|
+
config: OcxConfig,
|
|
22
|
+
deps: AlibabaRegionStartupDeps = {
|
|
23
|
+
project: projectAlibabaRegionMigration,
|
|
24
|
+
backup: () => { backupConfigBeforeAlibabaRegionMigration(); },
|
|
25
|
+
save: saveConfig,
|
|
26
|
+
},
|
|
27
|
+
): OcxConfig {
|
|
28
|
+
const projection = deps.project(config);
|
|
29
|
+
// Warnings are emitted even on a no-op: the collision case IS the warning.
|
|
30
|
+
for (const warning of projection.warnings) console.warn(`[alibaba-region-migration] ${warning}`);
|
|
31
|
+
if (!projection.changed) return projection.config;
|
|
32
|
+
// Strictly before the save: the snapshot must describe the config as it was.
|
|
33
|
+
deps.backup();
|
|
34
|
+
deps.save(projection.config);
|
|
35
|
+
return projection.config;
|
|
36
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
// Google Antigravity (Cloud Code Assist) bundled model list.
|
|
2
|
+
//
|
|
3
|
+
// Single source of truth: the Antigravity `:fetchAvailableModels` backend, the same one the `agy`
|
|
4
|
+
// CLI resolves labels against. The ids below separate CCA wire ids, collapsed picker entries,
|
|
5
|
+
// and hidden compatibility aliases for saved selections. The CCA envelope's `model` field must
|
|
6
|
+
// receive the wire id (for example "Gemini 3.1 Pro (High)" => gemini-pro-agent), while the
|
|
7
|
+
// picker exposes collapsed base models with reasoning-effort routing.
|
|
8
|
+
|
|
9
|
+
// ── Wire IDs (what CCA :fetchAvailableModels returns) ──
|
|
10
|
+
const ANTIGRAVITY_WIRE_MODELS = [
|
|
11
|
+
"gemini-3.6-flash-low",
|
|
12
|
+
"gemini-3.6-flash-medium",
|
|
13
|
+
"gemini-3.6-flash-high",
|
|
14
|
+
"gemini-3.1-pro-low",
|
|
15
|
+
"gemini-pro-agent",
|
|
16
|
+
"gemini-3.1-flash-image",
|
|
17
|
+
"claude-sonnet-4-6",
|
|
18
|
+
"claude-opus-4-6-thinking",
|
|
19
|
+
"gpt-oss-120b-medium",
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
// ── Effort ladders per collapsed base model ──
|
|
23
|
+
// Gemini models: effort → wire model suffix (official agy UI pattern).
|
|
24
|
+
// Claude Opus: effort → thinkingConfig.thinkingLevel (CLIProxyAPI proven pattern).
|
|
25
|
+
export const ANTIGRAVITY_MODEL_EFFORTS: Record<string, string[]> = {
|
|
26
|
+
"gemini-3.6-flash": ["low", "medium", "high"],
|
|
27
|
+
"gemini-3.1-pro": ["low", "high"],
|
|
28
|
+
"claude-sonnet-4-6": ["low", "medium", "high", "max"],
|
|
29
|
+
"claude-opus-4-6-thinking": ["low", "medium", "high", "max"],
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// ── Effort → wire model map for Gemini base models ──
|
|
33
|
+
const ANTIGRAVITY_EFFORT_WIRE_MAP: Record<string, Record<string, string>> = {
|
|
34
|
+
"gemini-3.6-flash": {
|
|
35
|
+
low: "gemini-3.6-flash-low",
|
|
36
|
+
medium: "gemini-3.6-flash-medium",
|
|
37
|
+
high: "gemini-3.6-flash-high",
|
|
38
|
+
},
|
|
39
|
+
"gemini-3.1-pro": {
|
|
40
|
+
low: "gemini-3.1-pro-low",
|
|
41
|
+
high: "gemini-pro-agent",
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// ── Default effort per Gemini base model ──
|
|
46
|
+
const ANTIGRAVITY_DEFAULT_EFFORT: Record<string, string> = {
|
|
47
|
+
"gemini-3.6-flash": "medium",
|
|
48
|
+
"gemini-3.1-pro": "high",
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const ANTIGRAVITY_THINKING_LEVELS = new Set(["minimal", "low", "medium", "high"]);
|
|
52
|
+
|
|
53
|
+
function resolveAntigravityThinkingLevel(effort: string): string | undefined {
|
|
54
|
+
if (effort === "xhigh" || effort === "max" || effort === "ultra") return "high";
|
|
55
|
+
return ANTIGRAVITY_THINKING_LEVELS.has(effort) ? effort : undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ── Visible client aliases (kept for saved-config compat, not picker-visible) ──
|
|
59
|
+
const ANTIGRAVITY_VISIBLE_MODEL_ALIASES: Record<string, string> = {
|
|
60
|
+
"gemini-3.1-pro-high": "gemini-pro-agent",
|
|
61
|
+
"gemini-3.1-pro-preview": "gemini-pro-agent",
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// ── Hidden compatibility aliases for saved selections ──
|
|
65
|
+
// Wire suffix IDs are identity aliases — they resolve to themselves so saved configs
|
|
66
|
+
// with explicit suffixes (e.g. gemini-3.6-flash-low) continue to work.
|
|
67
|
+
const ANTIGRAVITY_COMPATIBILITY_MODEL_ALIASES: Record<string, string> = {
|
|
68
|
+
"gemini-3.6-flash-low": "gemini-3.6-flash-low",
|
|
69
|
+
"gemini-3.6-flash-medium": "gemini-3.6-flash-medium",
|
|
70
|
+
"gemini-3.6-flash-high": "gemini-3.6-flash-high",
|
|
71
|
+
"gemini-3.1-pro-low": "gemini-3.1-pro-low",
|
|
72
|
+
"gemini-pro-agent": "gemini-pro-agent",
|
|
73
|
+
"gemini-3.5-flash-extra-low": "gemini-3.6-flash-low",
|
|
74
|
+
"gemini-3.5-flash-low": "gemini-3.6-flash-medium",
|
|
75
|
+
"gemini-3.5-flash-mid": "gemini-3.6-flash-medium",
|
|
76
|
+
"gemini-3.5-flash-high": "gemini-3.6-flash-high",
|
|
77
|
+
"gemini-3-flash-agent": "gemini-3.6-flash-high",
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const ANTIGRAVITY_MODEL_ALIASES: Record<string, string> = {
|
|
81
|
+
...ANTIGRAVITY_VISIBLE_MODEL_ALIASES,
|
|
82
|
+
...ANTIGRAVITY_COMPATIBILITY_MODEL_ALIASES,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Picker-visible: collapsed base models only.
|
|
86
|
+
export const ANTIGRAVITY_MODELS = [
|
|
87
|
+
"gemini-3.6-flash",
|
|
88
|
+
"gemini-3.1-pro",
|
|
89
|
+
"gemini-3.1-flash-image",
|
|
90
|
+
"claude-sonnet-4-6",
|
|
91
|
+
"claude-opus-4-6-thinking",
|
|
92
|
+
"gpt-oss-120b-medium",
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
// Context windows from the upstream `:fetchAvailableModels` maxTokens per model.
|
|
96
|
+
const ANTIGRAVITY_WIRE_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
97
|
+
"gemini-3.6-flash-low": 1_048_576,
|
|
98
|
+
"gemini-3.6-flash-medium": 1_048_576,
|
|
99
|
+
"gemini-3.6-flash-high": 1_048_576,
|
|
100
|
+
"gemini-3.1-pro-low": 1_048_576,
|
|
101
|
+
"gemini-pro-agent": 1_048_576,
|
|
102
|
+
"gemini-3.1-flash-image": 1_048_576,
|
|
103
|
+
"claude-sonnet-4-6": 200_000,
|
|
104
|
+
"claude-opus-4-6-thinking": 1_000_000,
|
|
105
|
+
"gpt-oss-120b-medium": 131_072,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export const ANTIGRAVITY_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
109
|
+
// Collapsed base IDs — explicit entries for the picker.
|
|
110
|
+
"gemini-3.6-flash": 1_048_576,
|
|
111
|
+
"gemini-3.1-pro": 1_048_576,
|
|
112
|
+
// Wire IDs and aliases via derivation.
|
|
113
|
+
...ANTIGRAVITY_WIRE_MODEL_CONTEXT_WINDOWS,
|
|
114
|
+
...Object.fromEntries(
|
|
115
|
+
Object.entries(ANTIGRAVITY_MODEL_ALIASES).map(([alias, wire]) => [
|
|
116
|
+
alias,
|
|
117
|
+
ANTIGRAVITY_WIRE_MODEL_CONTEXT_WINDOWS[wire],
|
|
118
|
+
]),
|
|
119
|
+
),
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export function resolveAntigravityWireModelId(modelId: string): string {
|
|
123
|
+
return ANTIGRAVITY_MODEL_ALIASES[modelId] ?? modelId;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Whether the given model ID is a suffix wire ID or compat alias that already encodes
|
|
128
|
+
* an effort level. For these IDs, the caller must NOT send thinkingConfig — the suffix
|
|
129
|
+
* IS the effort, and sending both creates a contradictory request.
|
|
130
|
+
*/
|
|
131
|
+
export function isAntigravitySuffixModelId(modelId: string): boolean {
|
|
132
|
+
return !(ANTIGRAVITY_MODELS as string[]).includes(modelId);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Resolve a picker-visible base model + optional reasoning effort to the CCA wire model ID.
|
|
137
|
+
*
|
|
138
|
+
* Precedence (evaluated in order):
|
|
139
|
+
* 1. Suffix wire ID or compat alias → resolve via `resolveAntigravityWireModelId`, no thinkingConfig.
|
|
140
|
+
* 2. Mapped Gemini base with effort → return mapped wire ID + thinkingLevel.
|
|
141
|
+
* 3. Mapped Gemini base without effort → return default-effort wire ID, no thinkingConfig.
|
|
142
|
+
* 4. Claude Opus with effort → return identity + thinkingLevel (no suffix variants exist).
|
|
143
|
+
* 5. All other IDs → return `resolveAntigravityWireModelId(modelId)`, no thinkingConfig.
|
|
144
|
+
*/
|
|
145
|
+
export function resolveAntigravityEffortWireModel(
|
|
146
|
+
modelId: string,
|
|
147
|
+
effort?: string,
|
|
148
|
+
): { wireModelId: string; thinkingLevel?: string } {
|
|
149
|
+
// Rule 1: suffix/compat alias — suffix IS the effort.
|
|
150
|
+
if (isAntigravitySuffixModelId(modelId)) {
|
|
151
|
+
return { wireModelId: resolveAntigravityWireModelId(modelId) };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Rule 2/3: mapped Gemini base model.
|
|
155
|
+
const effortMap = ANTIGRAVITY_EFFORT_WIRE_MAP[modelId];
|
|
156
|
+
if (effortMap) {
|
|
157
|
+
if (effort && effort in effortMap) {
|
|
158
|
+
return { wireModelId: effortMap[effort]!, thinkingLevel: effort };
|
|
159
|
+
}
|
|
160
|
+
const defaultEffort = ANTIGRAVITY_DEFAULT_EFFORT[modelId]!;
|
|
161
|
+
return { wireModelId: effortMap[defaultEffort]! };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Rule 4: Claude models — effort via thinkingConfig only (no suffix variants).
|
|
165
|
+
// CCA validates this field as Google's ThinkingLevel enum, whose highest value is `high`.
|
|
166
|
+
if (/^claude-/.test(modelId) && effort) {
|
|
167
|
+
return { wireModelId: modelId, thinkingLevel: resolveAntigravityThinkingLevel(effort) };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Rule 5: everything else.
|
|
171
|
+
return { wireModelId: resolveAntigravityWireModelId(modelId) };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
// ── Usage aggregation reverse map (picker/call base identity) ──
|
|
176
|
+
// Effort wire IDs and compatibility aliases must collapse to the same picker-visible
|
|
177
|
+
// base model that users invoke after effort routing. Historical logs store suffix IDs;
|
|
178
|
+
// summary aggregation consults this reverse map so one call model = one usage row.
|
|
179
|
+
const ANTIGRAVITY_USAGE_BASE_BY_ID: Record<string, string> = (() => {
|
|
180
|
+
const rev: Record<string, string> = {};
|
|
181
|
+
for (const base of ANTIGRAVITY_MODELS) rev[base] = base;
|
|
182
|
+
for (const [base, effortMap] of Object.entries(ANTIGRAVITY_EFFORT_WIRE_MAP)) {
|
|
183
|
+
rev[base] = base;
|
|
184
|
+
for (const wire of Object.values(effortMap)) rev[wire] = base;
|
|
185
|
+
}
|
|
186
|
+
for (const [alias, wire] of Object.entries(ANTIGRAVITY_MODEL_ALIASES)) {
|
|
187
|
+
const base = rev[wire] ?? rev[alias];
|
|
188
|
+
if (base) rev[alias] = base;
|
|
189
|
+
// If alias is itself a base/wire already mapped, keep that mapping.
|
|
190
|
+
else if (rev[wire]) rev[alias] = rev[wire]!;
|
|
191
|
+
}
|
|
192
|
+
// Visible aliases that only appear in ANTIGRAVITY_VISIBLE_MODEL_ALIASES are already
|
|
193
|
+
// included via ANTIGRAVITY_MODEL_ALIASES. Identity bases without effort maps remain.
|
|
194
|
+
return rev;
|
|
195
|
+
})();
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Canonical picker/call model id for usage aggregation.
|
|
199
|
+
* Unknown ids stay identity so future CCA models do not invent mappings.
|
|
200
|
+
*/
|
|
201
|
+
export function canonicalAntigravityUsageModel(modelId: string): string {
|
|
202
|
+
const id = modelId.trim();
|
|
203
|
+
if (!id) return modelId;
|
|
204
|
+
return ANTIGRAVITY_USAGE_BASE_BY_ID[id] ?? id;
|
|
205
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-key pool for key-auth providers (the API-key twin of OAuth multiauth).
|
|
3
|
+
*
|
|
4
|
+
* `provider.apiKey` stays the single source of truth for routing — it always mirrors the
|
|
5
|
+
* ACTIVE pool entry, so the router/adapters never learn about the pool. The pool itself
|
|
6
|
+
* lives in `provider.apiKeyPool` in config.json (same file that already holds apiKey).
|
|
7
|
+
* A provider with a legacy bare `apiKey` is seeded into a one-entry pool on first touch.
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from "node:crypto";
|
|
10
|
+
import { saveConfigPreservingClaudeCode } from "../config";
|
|
11
|
+
import type { OcxConfig, OcxProviderConfig } from "../types";
|
|
12
|
+
|
|
13
|
+
export interface ProviderApiKeyInfo {
|
|
14
|
+
id: string;
|
|
15
|
+
label?: string;
|
|
16
|
+
/** First/last 4 chars only; env references (`${VAR}`) are shown verbatim (not secrets). */
|
|
17
|
+
masked: string;
|
|
18
|
+
active: boolean;
|
|
19
|
+
addedAt?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isEnvReference(value: string): boolean {
|
|
23
|
+
return /^\$\{?\w+\}?$/.test(value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function maskApiKey(value: string): string {
|
|
27
|
+
if (isEnvReference(value)) return value;
|
|
28
|
+
if (value.length <= 8) return "****";
|
|
29
|
+
return `${value.slice(0, 4)}****${value.slice(-4)}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Content-derived id: re-adding the same key upserts instead of duplicating. */
|
|
33
|
+
export function apiKeyPoolEntryId(key: string): string {
|
|
34
|
+
return createHash("sha256").update(key).digest("hex").slice(0, 8);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** True for providers whose upstream auth is a configured API key (not oauth/forward). */
|
|
38
|
+
export function isKeyAuthProvider(provider: OcxProviderConfig): boolean {
|
|
39
|
+
return provider.authMode !== "oauth" && provider.authMode !== "forward";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Trim and reject blank / CRLF-bearing secrets. Shared by pool writes and OAuth upsert. */
|
|
43
|
+
export function sanitizeApiKeyValue(value: unknown): string | undefined {
|
|
44
|
+
if (typeof value !== "string") return undefined;
|
|
45
|
+
const trimmed = value.trim();
|
|
46
|
+
return trimmed && !/[\r\n]/.test(trimmed) ? trimmed : undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Seed the pool from a legacy bare `apiKey`, and keep `apiKey` mirrored to the active entry. */
|
|
50
|
+
function ensurePool(provider: OcxProviderConfig): NonNullable<OcxProviderConfig["apiKeyPool"]> {
|
|
51
|
+
if (!provider.apiKeyPool) provider.apiKeyPool = [];
|
|
52
|
+
if (provider.apiKeyPool.length === 0 && provider.apiKey) {
|
|
53
|
+
provider.apiKeyPool.push({ id: apiKeyPoolEntryId(provider.apiKey), key: provider.apiKey });
|
|
54
|
+
}
|
|
55
|
+
return provider.apiKeyPool;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function activeEntryId(provider: OcxProviderConfig): string | null {
|
|
59
|
+
const pool = provider.apiKeyPool ?? [];
|
|
60
|
+
if (pool.length === 0) return null;
|
|
61
|
+
return (pool.find(e => e.key === provider.apiKey) ?? pool[0]!).id;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function listProviderApiKeys(config: OcxConfig, name: string): { activeId: string | null; keys: ProviderApiKeyInfo[] } {
|
|
65
|
+
const provider = config.providers[name];
|
|
66
|
+
if (!provider || !isKeyAuthProvider(provider)) return { activeId: null, keys: [] };
|
|
67
|
+
const pool = ensurePool(provider);
|
|
68
|
+
const activeId = activeEntryId(provider);
|
|
69
|
+
return {
|
|
70
|
+
activeId,
|
|
71
|
+
keys: pool.map(entry => ({
|
|
72
|
+
id: entry.id,
|
|
73
|
+
...(entry.label ? { label: entry.label } : {}),
|
|
74
|
+
masked: maskApiKey(entry.key),
|
|
75
|
+
active: entry.id === activeId,
|
|
76
|
+
...(entry.addedAt !== undefined ? { addedAt: entry.addedAt } : {}),
|
|
77
|
+
})),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Add (or upsert) a key and make it ACTIVE. Persists config. */
|
|
82
|
+
export function addProviderApiKey(config: OcxConfig, name: string, key: string, label?: string): { id: string } | { error: string } {
|
|
83
|
+
const provider = config.providers[name];
|
|
84
|
+
if (!provider || !isKeyAuthProvider(provider)) return { error: "provider does not use API-key auth" };
|
|
85
|
+
if (typeof key !== "string" || !key.trim()) return { error: "key is required" };
|
|
86
|
+
const trimmed = sanitizeApiKeyValue(key);
|
|
87
|
+
if (!trimmed) return { error: "key must not include line breaks" };
|
|
88
|
+
const pool = ensurePool(provider);
|
|
89
|
+
const id = apiKeyPoolEntryId(trimmed);
|
|
90
|
+
const existing = pool.find(e => e.id === id);
|
|
91
|
+
if (existing) {
|
|
92
|
+
if (label?.trim()) existing.label = label.trim();
|
|
93
|
+
} else {
|
|
94
|
+
pool.push({ id, key: trimmed, ...(label?.trim() ? { label: label.trim() } : {}), addedAt: Date.now() });
|
|
95
|
+
}
|
|
96
|
+
provider.apiKey = trimmed;
|
|
97
|
+
saveConfigPreservingClaudeCode(config);
|
|
98
|
+
return { id };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Switch the ACTIVE key (mirrors into `provider.apiKey`). Persists config. */
|
|
102
|
+
export function setActiveProviderApiKey(config: OcxConfig, name: string, id: string): boolean {
|
|
103
|
+
const provider = config.providers[name];
|
|
104
|
+
if (!provider || !isKeyAuthProvider(provider)) return false;
|
|
105
|
+
const entry = ensurePool(provider).find(e => e.id === id);
|
|
106
|
+
if (!entry) return false;
|
|
107
|
+
provider.apiKey = entry.key;
|
|
108
|
+
saveConfigPreservingClaudeCode(config);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Rename a key slot without changing its id, secret, or active routing state. */
|
|
113
|
+
export function setProviderApiKeyLabel(config: OcxConfig, name: string, id: string, label: string | undefined): boolean {
|
|
114
|
+
const provider = config.providers[name];
|
|
115
|
+
if (!provider || !isKeyAuthProvider(provider)) return false;
|
|
116
|
+
const entry = ensurePool(provider).find(e => e.id === id);
|
|
117
|
+
if (!entry) return false;
|
|
118
|
+
if (label) entry.label = label;
|
|
119
|
+
else delete entry.label;
|
|
120
|
+
saveConfigPreservingClaudeCode(config);
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Remove one key; removing the active one promotes the first remaining. Persists config. */
|
|
125
|
+
export function removeProviderApiKey(config: OcxConfig, name: string, id: string): boolean {
|
|
126
|
+
const provider = config.providers[name];
|
|
127
|
+
if (!provider || !isKeyAuthProvider(provider)) return false;
|
|
128
|
+
const pool = ensurePool(provider);
|
|
129
|
+
const entry = pool.find(e => e.id === id);
|
|
130
|
+
if (!entry) return false;
|
|
131
|
+
provider.apiKeyPool = pool.filter(e => e.id !== id);
|
|
132
|
+
if (provider.apiKey === entry.key) {
|
|
133
|
+
const next = provider.apiKeyPool[0];
|
|
134
|
+
if (next) provider.apiKey = next.key;
|
|
135
|
+
else delete provider.apiKey;
|
|
136
|
+
}
|
|
137
|
+
if (provider.apiKeyPool.length === 0) delete provider.apiKeyPool;
|
|
138
|
+
saveConfigPreservingClaudeCode(config);
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qwen Cloud OpenAI-compatible endpoint presets.
|
|
3
|
+
* Token plan is the GUI default; pay-as-you-go and custom are selectable.
|
|
4
|
+
*/
|
|
5
|
+
export const QWEN_CLOUD_TOKEN_PLAN_BASE_URL =
|
|
6
|
+
"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1";
|
|
7
|
+
export const QWEN_CLOUD_PAYG_BASE_URL =
|
|
8
|
+
"https://dashscope.aliyuncs.com/compatible-mode/v1";
|
|
9
|
+
|
|
10
|
+
export type ProviderBaseUrlChoice = {
|
|
11
|
+
id: string;
|
|
12
|
+
/** English label projected to the GUI; GUI may i18n by `id`. */
|
|
13
|
+
label: string;
|
|
14
|
+
/** Omitted for `custom` — user supplies the URL. */
|
|
15
|
+
baseUrl?: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const QWEN_CLOUD_BASE_URL_CHOICES: readonly ProviderBaseUrlChoice[] = [
|
|
19
|
+
{ id: "token-plan", label: "Token plan", baseUrl: QWEN_CLOUD_TOKEN_PLAN_BASE_URL },
|
|
20
|
+
{ id: "payg", label: "Pay as you go", baseUrl: QWEN_CLOUD_PAYG_BASE_URL },
|
|
21
|
+
{ id: "custom", label: "Custom" },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Alibaba Token Plan International (ap-southeast-1) endpoint presets.
|
|
26
|
+
* Same product as the Beijing Token Plan but for international accounts.
|
|
27
|
+
* Note: ALIBABA_INTL_TOKEN_PLAN_BASE_URL intentionally duplicates
|
|
28
|
+
* QWEN_CLOUD_TOKEN_PLAN_BASE_URL — same host, different product branding
|
|
29
|
+
* and model lineup. Kept as a separate constant for clarity.
|
|
30
|
+
*/
|
|
31
|
+
export const ALIBABA_INTL_TOKEN_PLAN_BASE_URL =
|
|
32
|
+
"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1";
|
|
33
|
+
export const ALIBABA_INTL_PAYG_BASE_URL =
|
|
34
|
+
"https://dashscope-intl.aliyuncs.com/compatible-mode/v1";
|
|
35
|
+
|
|
36
|
+
export const ALIBABA_INTL_BASE_URL_CHOICES: readonly ProviderBaseUrlChoice[] = [
|
|
37
|
+
{ id: "token-plan", label: "Token plan", baseUrl: ALIBABA_INTL_TOKEN_PLAN_BASE_URL },
|
|
38
|
+
{ id: "payg", label: "Pay as you go", baseUrl: ALIBABA_INTL_PAYG_BASE_URL },
|
|
39
|
+
{ id: "custom", label: "Custom" },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
/** Alibaba Coding Plan endpoint presets (international default; China mainland selectable). */
|
|
43
|
+
export const ALIBABA_CODING_INTL_BASE_URL = "https://coding-intl.dashscope.aliyuncs.com/v1";
|
|
44
|
+
export const ALIBABA_CODING_CN_BASE_URL = "https://coding.dashscope.aliyuncs.com/v1";
|
|
45
|
+
|
|
46
|
+
export const ALIBABA_CODING_BASE_URL_CHOICES: readonly ProviderBaseUrlChoice[] = [
|
|
47
|
+
{ id: "intl", label: "International", baseUrl: ALIBABA_CODING_INTL_BASE_URL },
|
|
48
|
+
{ id: "china", label: "China", baseUrl: ALIBABA_CODING_CN_BASE_URL },
|
|
49
|
+
{ id: "custom", label: "Custom" },
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
/** Match a saved baseUrl to a known choice id (`custom` when it does not match). */
|
|
53
|
+
export function matchBaseUrlChoice(
|
|
54
|
+
choices: readonly ProviderBaseUrlChoice[],
|
|
55
|
+
baseUrl: string,
|
|
56
|
+
): string {
|
|
57
|
+
if (!choices.length) return "custom";
|
|
58
|
+
const normalized = baseUrl.trim().replace(/\/+$/, "");
|
|
59
|
+
for (const choice of choices) {
|
|
60
|
+
if (!choice.baseUrl) continue;
|
|
61
|
+
if (choice.baseUrl.trim().replace(/\/+$/, "") === normalized) return choice.id;
|
|
62
|
+
}
|
|
63
|
+
return choices.some(c => c.id === "custom") ? "custom" : choices[0]!.id;
|
|
64
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { OcxConfig } from "../types";
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_PROVIDER_CONTEXT_CAP = 350_000;
|
|
4
|
+
|
|
5
|
+
function isValidContextCap(value: unknown): value is number {
|
|
6
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function providerContextCap(config: Pick<OcxConfig, "providerContextCaps">, provider: string): number | undefined {
|
|
10
|
+
const value = config.providerContextCaps?.[provider];
|
|
11
|
+
return isValidContextCap(value) ? value : undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function providerContextCaps(config: Pick<OcxConfig, "providerContextCaps">): Record<string, number> {
|
|
15
|
+
const caps = config.providerContextCaps;
|
|
16
|
+
if (!caps || typeof caps !== "object" || Array.isArray(caps)) return {};
|
|
17
|
+
const out: Record<string, number> = {};
|
|
18
|
+
for (const [provider, value] of Object.entries(caps)) {
|
|
19
|
+
if (isValidContextCap(value)) out[provider] = value;
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function applyProviderContextCap(contextWindow: number | undefined, cap: number | undefined): number | undefined {
|
|
25
|
+
if (!isValidContextCap(cap)) return contextWindow;
|
|
26
|
+
if (!isValidContextCap(contextWindow)) return contextWindow;
|
|
27
|
+
return contextWindow > cap ? cap : contextWindow;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Effective global cap value: explicit config value, else the built-in default. */
|
|
31
|
+
export function globalContextCapValue(config: Pick<OcxConfig, "contextCapValue">): number {
|
|
32
|
+
const value = config.contextCapValue;
|
|
33
|
+
return isValidContextCap(value) ? Math.floor(value) : DEFAULT_PROVIDER_CONTEXT_CAP;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function setProviderContextCap(config: OcxConfig, provider: string, enabled: boolean): void {
|
|
37
|
+
const next = providerContextCaps(config);
|
|
38
|
+
if (enabled) next[provider] = globalContextCapValue(config);
|
|
39
|
+
else delete next[provider];
|
|
40
|
+
if (Object.keys(next).length > 0) config.providerContextCaps = next;
|
|
41
|
+
else delete config.providerContextCaps;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Set the global cap value and re-point every already-enabled provider to it. */
|
|
45
|
+
export function setGlobalContextCapValue(config: OcxConfig, value: number): void {
|
|
46
|
+
if (!isValidContextCap(value)) return;
|
|
47
|
+
const next = Math.floor(value);
|
|
48
|
+
config.contextCapValue = next;
|
|
49
|
+
const caps = providerContextCaps(config);
|
|
50
|
+
for (const provider of Object.keys(caps)) caps[provider] = next;
|
|
51
|
+
if (Object.keys(caps).length > 0) config.providerContextCaps = caps;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Enable the cap for every named provider at the current value, or clear all caps. */
|
|
55
|
+
export function setAllProviderContextCaps(config: OcxConfig, providerNames: string[], enabled: boolean): void {
|
|
56
|
+
if (!enabled) {
|
|
57
|
+
delete config.providerContextCaps;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const value = globalContextCapValue(config);
|
|
61
|
+
const next: Record<string, number> = {};
|
|
62
|
+
for (const name of providerNames) next[name] = value;
|
|
63
|
+
if (Object.keys(next).length > 0) config.providerContextCaps = next;
|
|
64
|
+
else delete config.providerContextCaps;
|
|
65
|
+
}
|