@bitkyc08/opencodex 2.10.0 → 2.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_INSTALL.md +77 -0
- package/README.md +4 -10
- package/bin/ocx.mjs +71 -18
- package/gui/dist/assets/index-Cd6_PBKn.css +1 -0
- package/gui/dist/assets/index-ChZQsmBY.js +70 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +8 -4
- package/src/adapters/anthropic.ts +208 -14
- package/src/adapters/base.ts +16 -5
- package/src/adapters/cursor/effort-map.ts +3 -2
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/live-transport.ts +105 -95
- package/src/adapters/cursor/native-exec.ts +32 -6
- package/src/adapters/cursor/protobuf-request.ts +20 -15
- package/src/adapters/cursor/request-builder.ts +21 -7
- package/src/adapters/cursor/types.ts +7 -0
- package/src/adapters/google-antigravity-replay.ts +237 -21
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +50 -9
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +10 -2
- package/src/adapters/kiro-tools.ts +10 -1
- package/src/adapters/kiro.ts +37 -11
- package/src/adapters/openai-chat.ts +284 -83
- package/src/adapters/openai-responses.ts +182 -24
- package/src/bridge.ts +177 -7
- package/src/chat/outbound.ts +78 -23
- package/src/claude/agents-inject.ts +27 -5
- package/src/claude/inbound.ts +11 -1
- package/src/claude/model-info.ts +13 -10
- package/src/claude/outbound.ts +17 -0
- package/src/cli/account-api.ts +24 -0
- package/src/cli/account-auth.ts +31 -6
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +5 -0
- package/src/cli/claude.ts +2 -1
- package/src/cli/doctor.ts +93 -22
- package/src/cli/export-command.ts +26 -12
- package/src/cli/help.ts +8 -6
- package/src/cli/index.ts +56 -22
- package/src/cli/integrations.ts +84 -1
- package/src/cli/observe.ts +54 -1
- package/src/cli/opencode.ts +2 -1
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +1 -1
- package/src/cli/v2.ts +36 -9
- package/src/clients/config-export.ts +687 -10
- package/src/codex/account-lifecycle.ts +30 -5
- package/src/codex/account-usability.ts +22 -2
- package/src/codex/admission.ts +255 -0
- package/src/codex/auth-api.ts +427 -140
- package/src/codex/auth-context.ts +155 -30
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +62 -0
- package/src/codex/catalog/aggregation.ts +14 -1
- package/src/codex/catalog/bundled.ts +282 -32
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/metadata.ts +51 -6
- package/src/codex/catalog/parsing.ts +6 -3
- package/src/codex/catalog/provider-fetch.ts +576 -41
- package/src/codex/catalog/sync.ts +505 -66
- package/src/codex/catalog-admission.ts +197 -0
- package/src/codex/catalog-write-serialization.ts +241 -0
- package/src/codex/catalog.ts +2 -1
- package/src/codex/codex-write-lock.ts +372 -0
- package/src/codex/convergence-types.ts +593 -0
- package/src/codex/convergence.ts +441 -0
- package/src/codex/desired-state.ts +177 -0
- package/src/codex/features.ts +52 -8
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +257 -0
- package/src/codex/history-lock.ts +241 -0
- package/src/codex/history-migration-guardian.ts +18 -5
- package/src/codex/history-provider.ts +9 -2
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +176 -0
- package/src/codex/inject-coordination.ts +245 -0
- package/src/codex/inject.ts +605 -124
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +10 -1
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/management-convergence.ts +114 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +167 -0
- package/src/codex/native-main-lock-file.ts +158 -0
- package/src/codex/native-main-owner.ts +315 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1512 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +340 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +557 -0
- package/src/codex/project-config-warnings.ts +18 -4
- package/src/codex/prompt-journal.ts +311 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +224 -0
- package/src/codex/quota.ts +86 -3
- package/src/codex/routing.ts +299 -62
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +39 -13
- package/src/codex/subagent-model-fallback.ts +73 -12
- package/src/codex/transition-state.ts +604 -0
- package/src/codex/upstream-host-health.ts +70 -0
- package/src/codex/user-identity.ts +266 -0
- package/src/codex/write-coordination.ts +114 -0
- package/src/config.ts +562 -26
- package/src/generated/jawcode-model-metadata.ts +2 -2
- package/src/grok/inject.ts +15 -4
- package/src/grok/inspect.ts +45 -0
- package/src/images/loop.ts +113 -20
- package/src/integrations/config-io.ts +151 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/native/ownership-preflight.ts +165 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +101 -0
- package/src/integrations/serialize.ts +235 -0
- package/src/integrations/state.ts +290 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer.ts +492 -0
- package/src/lib/bounded-body.ts +46 -8
- package/src/lib/bun-runtime.ts +110 -1
- package/src/lib/bun-stream-caps.ts +2 -1
- package/src/lib/redact.ts +407 -2
- package/src/lib/shadow-call.ts +24 -0
- package/src/lib/translator-budget.ts +10 -0
- package/src/lib/upstream-reachability.ts +91 -0
- package/src/lib/upstream-retry.ts +154 -2
- package/src/lib/windows-secret-acl.ts +212 -11
- package/src/lib/winsw.ts +9 -3
- package/src/oauth/index.ts +61 -3
- package/src/oauth/key-providers.ts +4 -0
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/store.ts +31 -6
- package/src/oauth/token-guardian.ts +9 -3
- package/src/providers/codex-capacity.ts +288 -0
- package/src/providers/derive.ts +33 -1
- package/src/providers/free-directory.ts +3 -1
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/openai-sidecar.ts +64 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/quota.ts +334 -26
- package/src/providers/registry.ts +284 -16
- package/src/providers/xai-transport.ts +11 -4
- package/src/responses/compaction.ts +8 -1
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/parser.ts +44 -2
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +105 -0
- package/src/responses/spill-store.ts +45 -8
- package/src/responses/state.ts +161 -17
- package/src/router.ts +302 -16
- package/src/routing/analytics.ts +377 -0
- package/src/routing/capability.ts +204 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +444 -0
- package/src/routing/health.ts +401 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +590 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile.ts +423 -0
- package/src/routing/quota.ts +124 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +686 -0
- package/src/server/auth-cors.ts +46 -6
- package/src/server/chat-completions.ts +28 -13
- package/src/server/claude-messages.ts +23 -15
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +10 -1
- package/src/server/index.ts +238 -52
- package/src/server/lifecycle.ts +228 -9
- package/src/server/live.ts +14 -3
- package/src/server/management/agent-settings-routes.ts +64 -14
- package/src/server/management/combo-routes.ts +5 -5
- package/src/server/management/config-routes.ts +1 -1
- package/src/server/management/context.ts +42 -2
- package/src/server/management/integration-routes.ts +538 -0
- package/src/server/management/logs-usage-routes.ts +1 -1
- package/src/server/management/model-routes.ts +32 -113
- package/src/server/management/model-rows.ts +117 -0
- package/src/server/management/native-integration-routes.ts +587 -0
- package/src/server/management/oauth-account-routes.ts +1 -1
- package/src/server/management/provider-routes.ts +218 -117
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +177 -0
- package/src/server/management/shared.ts +2 -2
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +276 -24
- package/src/server/management/system-routes.ts +4 -0
- package/src/server/management-api.ts +84 -9
- package/src/server/management-auth.ts +43 -5
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +120 -6
- package/src/server/request-log.ts +26 -6
- package/src/server/responses/collaboration.ts +63 -8
- package/src/server/responses/compact.ts +272 -41
- package/src/server/responses/core.ts +730 -132
- package/src/server/responses/fetch-helpers.ts +15 -1
- package/src/server/responses-item-id-repair.ts +32 -3
- package/src/server/responses-json-events.ts +52 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/search.ts +51 -6
- package/src/server/sse-payload-rewrite.ts +89 -12
- package/src/server/startup-health-cache.ts +7 -1
- package/src/server/ws-bridge.ts +11 -17
- package/src/service-manager-probe.ts +297 -0
- package/src/service.ts +222 -32
- package/src/tray/windows-tray.ps1 +9 -0
- package/src/tray/windows.ts +15 -7
- package/src/types.ts +194 -14
- package/src/update/index.ts +13 -13
- package/src/update/job.ts +24 -21
- package/src/update/notify.ts +7 -3
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +129 -10
- package/src/usage/log.ts +50 -15
- package/src/usage/summary.ts +4 -4
- package/src/vision/index.ts +6 -1
- package/src/web-search/loop.ts +161 -34
- package/gui/dist/assets/index-OY43ubAq.css +0 -1
- package/gui/dist/assets/index-YwNnKZcL.js +0 -67
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
|
@@ -110,6 +110,11 @@ export interface ProviderRegistryEntry {
|
|
|
110
110
|
allowKeyAuthOverride?: boolean;
|
|
111
111
|
allowPrivateNetworkByDefault?: boolean;
|
|
112
112
|
keyOptional?: boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Registry-only key-login policy for public model catalogs that cannot authenticate a key.
|
|
115
|
+
* The dashboard flow then reports the key as unverifiable instead of a false positive.
|
|
116
|
+
*/
|
|
117
|
+
apiKeyValidation?: "unknown";
|
|
113
118
|
/**
|
|
114
119
|
* Free-tier pricing (no paid subscription required). Distinct from `keyOptional`:
|
|
115
120
|
* free tiers may still require an API key (e.g. NVIDIA NIM free credits).
|
|
@@ -148,6 +153,25 @@ export interface ProviderRegistryEntry {
|
|
|
148
153
|
* of paying a translation hop.
|
|
149
154
|
*/
|
|
150
155
|
modelWireDefaults?: Record<string, ModelWireDefault>;
|
|
156
|
+
/**
|
|
157
|
+
* Registry-only per-model override for the upstream request shape used behind a
|
|
158
|
+
* Codex Responses WebSocket turn. `false` keeps the client-facing WebSocket but
|
|
159
|
+
* asks the upstream Responses endpoint for bounded JSON, which the bridge then
|
|
160
|
+
* reframes as Responses events. Use only for upstreams whose streaming response
|
|
161
|
+
* can omit or indefinitely delay the terminal event.
|
|
162
|
+
*/
|
|
163
|
+
modelResponsesUpstreamStreaming?: Record<string, boolean>;
|
|
164
|
+
/**
|
|
165
|
+
* Registry-only client-facing item-id repair policy (#938), filled onto the
|
|
166
|
+
* runtime provider only when the user has no explicit policy (derive.ts);
|
|
167
|
+
* never seeded into saved config.
|
|
168
|
+
*/
|
|
169
|
+
responsesItemIdRepair?: {
|
|
170
|
+
message?: string[];
|
|
171
|
+
reasoning?: string[];
|
|
172
|
+
repairMissingTerminalIds?: boolean;
|
|
173
|
+
repairInvalidIds?: boolean;
|
|
174
|
+
};
|
|
151
175
|
/**
|
|
152
176
|
* Responses-API resource path for providers whose route is not `/v1/responses`.
|
|
153
177
|
* Unlike `modelWireDefaults` above, this IS seeded into saved config: it describes
|
|
@@ -161,6 +185,16 @@ export interface ProviderRegistryEntry {
|
|
|
161
185
|
* replay miss are repaired rather than forwarded.
|
|
162
186
|
*/
|
|
163
187
|
statelessResponses?: boolean;
|
|
188
|
+
/**
|
|
189
|
+
* Registry default for the provider's Responses `service_tier` support; see
|
|
190
|
+
* `OcxProviderConfig.supportsServiceTier`. Registry-only: backfilled (never
|
|
191
|
+
* overriding) at enrich/route time and deliberately NOT seeded into saved
|
|
192
|
+
* config, so an explicit user value stays distinguishable from the default
|
|
193
|
+
* (and the canonical openai seed comparison keeps its exact key set).
|
|
194
|
+
*/
|
|
195
|
+
supportsServiceTier?: boolean;
|
|
196
|
+
/** Registry default for plaintext reasoning replay; see `OcxProviderConfig.preserveResponsesReasoningContent`. Registry-only like `supportsServiceTier`. */
|
|
197
|
+
preserveResponsesReasoningContent?: boolean;
|
|
164
198
|
modelDiscovery?: ProviderModelDiscoverySpec;
|
|
165
199
|
contextWindow?: number;
|
|
166
200
|
modelContextWindows?: Record<string, number>;
|
|
@@ -172,6 +206,7 @@ export interface ProviderRegistryEntry {
|
|
|
172
206
|
modelDefaultReasoningEfforts?: Record<string, string>;
|
|
173
207
|
reasoningEffortMap?: Record<string, string>;
|
|
174
208
|
modelReasoningEffortMap?: Record<string, Record<string, string>>;
|
|
209
|
+
reasoningWireFormat?: OcxProviderConfig["reasoningWireFormat"];
|
|
175
210
|
noVisionModels?: string[];
|
|
176
211
|
noReasoningModels?: string[];
|
|
177
212
|
noTemperatureModels?: string[];
|
|
@@ -203,7 +238,7 @@ export type ProviderConfigSeed = Pick<
|
|
|
203
238
|
"adapter" | "baseUrl" | "apiKeyTransport" | "responsesPath" | "authMode" | "keyOptional" | "freeTier" | "modelSuffixBracketStrip" | "defaultModel" | "models"
|
|
204
239
|
| "liveModels" | "contextWindow" | "modelContextWindows" | "modelInputModalities"
|
|
205
240
|
| "modelMaxInputTokens" | "defaultMaxOutputTokens" | "modelMaxOutputTokens"
|
|
206
|
-
| "reasoningEfforts" | "modelReasoningEfforts" | "modelDefaultReasoningEfforts" | "reasoningEffortMap" | "modelReasoningEffortMap"
|
|
241
|
+
| "reasoningEfforts" | "modelReasoningEfforts" | "modelDefaultReasoningEfforts" | "reasoningEffortMap" | "modelReasoningEffortMap" | "reasoningWireFormat"
|
|
207
242
|
| "noVisionModels" | "noReasoningModels" | "noTemperatureModels" | "noTopPModels" | "noPenaltyModels"
|
|
208
243
|
| "autoToolChoiceOnlyModels" | "preserveReasoningContentModels" | "reasoningSplitModels" | "thinkingToggleModels" | "thinkingBudgetModels" | "escapeBuiltinToolNames"
|
|
209
244
|
| "googleMode" | "project" | "location" | "headers"
|
|
@@ -214,7 +249,7 @@ export type ProviderConfigSeed = Pick<
|
|
|
214
249
|
// 260710 context refresh: Tier-2 evidence in
|
|
215
250
|
// devlog/_plan/260710_provider_hardening/001_research_frontier.md.
|
|
216
251
|
const ANTHROPIC_MODELS = ["claude-fable-5", "claude-sonnet-5", "claude-opus-5", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5"];
|
|
217
|
-
const ANTHROPIC_MODEL_CONTEXT_WINDOWS: Record<string, number> = { "claude-sonnet-5": 1_000_000, "claude-fable-5": 1_000_000, "claude-opus-5": 1_000_000, "claude-opus-4-8": 1_000_000, "claude-haiku-4-5": 200_000 };
|
|
252
|
+
const ANTHROPIC_MODEL_CONTEXT_WINDOWS: Record<string, number> = { "claude-sonnet-5": 1_000_000, "claude-fable-5": 1_000_000, "claude-opus-5": 1_000_000, "claude-opus-4-8": 1_000_000, "claude-opus-4-7": 1_000_000, "claude-opus-4-6": 1_000_000, "claude-sonnet-4-6": 1_000_000, "claude-haiku-4-5": 200_000 };
|
|
218
253
|
|
|
219
254
|
const ZAI_GLM_52_MODELS = ["glm-5.2", "glm-5.2[1m]"];
|
|
220
255
|
const ZAI_GLM_52_REASONING_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
@@ -328,14 +363,14 @@ const DEEPSEEK_THINKING_REASONING_MAP: Record<string, string> = {
|
|
|
328
363
|
// Evidence: https://help.aliyun.com/en/model-studio/token-plan-personal-overview
|
|
329
364
|
// https://help.aliyun.com/en/model-studio/token-plan-quickstart
|
|
330
365
|
const ALIBABA_TOKEN_PLAN_MODELS = [
|
|
331
|
-
"qwen3.8-max
|
|
366
|
+
"qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash",
|
|
332
367
|
"glm-5.2", "deepseek-v4-pro",
|
|
333
368
|
];
|
|
334
369
|
const ALIBABA_TOKEN_PLAN_QWEN_MODELS = [
|
|
335
|
-
"qwen3.8-max
|
|
370
|
+
"qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash",
|
|
336
371
|
];
|
|
337
372
|
const ALIBABA_TOKEN_PLAN_INPUT_MODALITIES: Record<string, string[]> = {
|
|
338
|
-
"qwen3.8-max
|
|
373
|
+
"qwen3.8-max": ["text", "image"],
|
|
339
374
|
"qwen3.7-max": ["text", "image"],
|
|
340
375
|
"qwen3.7-plus": ["text", "image"],
|
|
341
376
|
"qwen3.6-flash": ["text", "image"],
|
|
@@ -348,14 +383,14 @@ const ALIBABA_TOKEN_PLAN_INPUT_MODALITIES: Record<string, string[]> = {
|
|
|
348
383
|
// Evidence: https://www.alibabacloud.com/help/en/model-studio/token-plan-overview
|
|
349
384
|
// https://qwencloud.com/pricing/token-plan (qwen3.8 metadata)
|
|
350
385
|
const ALIBABA_INTL_TOKEN_PLAN_MODELS = [
|
|
351
|
-
"qwen3.8-max
|
|
386
|
+
"qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.6-flash",
|
|
352
387
|
"deepseek-v4-pro", "deepseek-v4-flash", "deepseek-v3.2",
|
|
353
388
|
"kimi-k2.7-code", "kimi-k2.6", "kimi-k2.5",
|
|
354
389
|
"glm-5.2", "glm-5.1", "glm-5",
|
|
355
390
|
"MiniMax-M2.5",
|
|
356
391
|
];
|
|
357
392
|
const ALIBABA_INTL_TOKEN_PLAN_QWEN_MODELS = [
|
|
358
|
-
"qwen3.8-max
|
|
393
|
+
"qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.6-flash",
|
|
359
394
|
];
|
|
360
395
|
|
|
361
396
|
// 260722 Tencent Cloud Coding Plan. The plan's model set is explicitly dynamic; these are the
|
|
@@ -426,7 +461,7 @@ const VOLCENGINE_PLAN_TEXT_ONLY_MODELS = [
|
|
|
426
461
|
"doubao-seed-2.0-pro",
|
|
427
462
|
];
|
|
428
463
|
const ALIBABA_INTL_TOKEN_PLAN_INPUT_MODALITIES: Record<string, string[]> = {
|
|
429
|
-
"qwen3.8-max
|
|
464
|
+
"qwen3.8-max": ["text", "image"],
|
|
430
465
|
"qwen3.7-max": ["text", "image"],
|
|
431
466
|
"qwen3.7-plus": ["text", "image"],
|
|
432
467
|
"qwen3.6-plus": ["text", "image"],
|
|
@@ -496,6 +531,72 @@ const NVIDIA_NIM_KIMI_MODELS = [
|
|
|
496
531
|
...NVIDIA_NIM_KIMI_THINKING_MODELS,
|
|
497
532
|
"moonshotai/kimi-k2-instruct", "moonshotai/kimi-k2-instruct-0905",
|
|
498
533
|
];
|
|
534
|
+
/**
|
|
535
|
+
* 260804 issue #956: NIM publishes no input-modality metadata on `/v1/models`, so the
|
|
536
|
+
* registry is the only source of truth for which models can see images.
|
|
537
|
+
*
|
|
538
|
+
* Two lists, both verified per-model against NVIDIA documentation on 2026-08-04
|
|
539
|
+
* (build.nvidia.com model pages and docs.api.nvidia.com/nim/reference/*). Evidence and
|
|
540
|
+
* the per-id audit: devlog/_plan/260804_stack7_service_vision/011_nim_id_audit.md.
|
|
541
|
+
*
|
|
542
|
+
* Read `noVisionModels` carefully — it lists models that CANNOT see images, which is
|
|
543
|
+
* what routes them through the proxy's vision sidecar (src/vision/index.ts) and makes the
|
|
544
|
+
* catalog advertise image input for them. Membership is wrong in BOTH directions:
|
|
545
|
+
* - a text-only model missing from it keeps issue #956 (images blocked or rejected);
|
|
546
|
+
* - a vision model wrongly IN it gets its image silently replaced by another model's
|
|
547
|
+
* text description — no error, worse answers, extra cost.
|
|
548
|
+
*
|
|
549
|
+
* A new NIM id must be classified DELIBERATELY against its NVIDIA page, never assumed
|
|
550
|
+
* from its name: `google/gemma-4-31b-it` carries no vision marker yet accepts images,
|
|
551
|
+
* `-vl` also appears on embedding/reranking models, and `google/codegemma-7b` is
|
|
552
|
+
* text-only while `google/codegemma-1.1-7b` has no current page at all. An unclassified
|
|
553
|
+
* id is intentionally left alone rather than defaulted, because NIM serves non-chat
|
|
554
|
+
* endpoints (embeddings, rerankers, guards, OCR) that reach the same code path.
|
|
555
|
+
*/
|
|
556
|
+
const NVIDIA_NIM_VISION_MODELS = [
|
|
557
|
+
"meta/llama-3.2-11b-vision-instruct", "meta/llama-3.2-90b-vision-instruct",
|
|
558
|
+
"nvidia/llama-3.1-nemotron-nano-vl-8b-v1", "nvidia/nemotron-nano-12b-v2-vl",
|
|
559
|
+
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning", "nvidia/cosmos3-nano-reasoner",
|
|
560
|
+
"nvidia/ising-calibration-1.5-31b", "nvidia/ising-calibration-1-35b-a3b",
|
|
561
|
+
"google/gemma-4-31b-it", "google/diffusiongemma-26b-a4b-it",
|
|
562
|
+
"minimaxai/minimax-m3", "moonshotai/kimi-k2.6", "moonshotai/kimi-k2.5",
|
|
563
|
+
"stepfun-ai/step-3.7-flash", "thinkingmachines/inkling",
|
|
564
|
+
"mistralai/mistral-medium-3.5-128b",
|
|
565
|
+
];
|
|
566
|
+
/**
|
|
567
|
+
* The catalog advertises image input only for `noVisionModels` members, so a natively
|
|
568
|
+
* vision-capable model would otherwise be published as text-only and the Codex app would
|
|
569
|
+
* block attachments before the native path ever runs.
|
|
570
|
+
*/
|
|
571
|
+
const NVIDIA_NIM_VISION_INPUT_MODALITIES: Record<string, string[]> = Object.fromEntries(
|
|
572
|
+
NVIDIA_NIM_VISION_MODELS.map(id => [id, ["text", "image"]]),
|
|
573
|
+
);
|
|
574
|
+
/**
|
|
575
|
+
* Text-only NIM chat models — 26 ids, each carrying an explicit `Input Modalities: Text`
|
|
576
|
+
* (or equivalent) on its NVIDIA page. PR #964 proposed ~64; six of those are natively
|
|
577
|
+
* image-capable and live in NVIDIA_NIM_VISION_MODELS above, and 32 more had no current
|
|
578
|
+
* NVIDIA page and were dropped rather than assumed.
|
|
579
|
+
*
|
|
580
|
+
* kimi-k2-thinking and kimi-k2-instruct are text-only while k2.5/k2.6 are not — vision
|
|
581
|
+
* and reasoning are independent axes, so all four stay in NVIDIA_NIM_KIMI_MODELS for
|
|
582
|
+
* reasoning suppression regardless of which list they appear in here.
|
|
583
|
+
*/
|
|
584
|
+
const NVIDIA_NIM_NO_VISION_MODELS = [
|
|
585
|
+
"deepseek-ai/deepseek-v4-flash", "deepseek-ai/deepseek-v4-pro",
|
|
586
|
+
"google/codegemma-7b",
|
|
587
|
+
"meta/llama-3.1-70b-instruct", "meta/llama-3.1-8b-instruct",
|
|
588
|
+
"meta/llama-3.2-1b-instruct", "meta/llama-3.2-3b-instruct",
|
|
589
|
+
"meta/llama-3.3-70b-instruct", "meta/llama2-70b",
|
|
590
|
+
"mistralai/mistral-7b-instruct-v0.3", "mistralai/mistral-nemotron",
|
|
591
|
+
"moonshotai/kimi-k2-thinking", "moonshotai/kimi-k2-instruct",
|
|
592
|
+
"nvidia/llama-3.1-nemotron-nano-8b-v1", "nvidia/llama-3.1-nemotron-ultra-253b-v1",
|
|
593
|
+
"nvidia/llama-3.3-nemotron-super-49b-v1", "nvidia/llama-3.3-nemotron-super-49b-v1.5",
|
|
594
|
+
"nvidia/nemotron-3-nano-30b-a3b", "nvidia/nemotron-3-super-120b-a12b",
|
|
595
|
+
"nvidia/nemotron-3-ultra-550b-a55b", "nvidia/nemotron-mini-4b-instruct",
|
|
596
|
+
"nvidia/nvidia-nemotron-nano-9b-v2",
|
|
597
|
+
"openai/gpt-oss-120b", "openai/gpt-oss-20b",
|
|
598
|
+
"poolside/laguna-xs-2.1", "z-ai/glm-5.2",
|
|
599
|
+
];
|
|
499
600
|
const KIMI_CODING_MODEL_CONTEXT_WINDOWS: Record<string, number> = Object.fromEntries(
|
|
500
601
|
KIMI_CODING_MODELS.map(id => [id, id === "k3[1m]" ? KIMI_K3_1M_CONTEXT_WINDOW : KIMI_K3_STANDARD_CONTEXT_WINDOW]),
|
|
501
602
|
);
|
|
@@ -566,6 +667,44 @@ const UMANS_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
|
566
667
|
const UMANS_MODEL_INPUT_MODALITIES: Record<string, string[]> = Object.fromEntries(
|
|
567
668
|
UMANS_MODELS.map(id => [id, UMANS_TEXT_ONLY_MODELS.includes(id) ? ["text"] : ["text", "image"]]),
|
|
568
669
|
);
|
|
670
|
+
const CLINE_PASS_MODELS = [
|
|
671
|
+
"cline-pass/glm-5.2",
|
|
672
|
+
"cline-pass/kimi-k3",
|
|
673
|
+
"cline-pass/kimi-k2.7-code",
|
|
674
|
+
"cline-pass/kimi-k2.6",
|
|
675
|
+
"cline-pass/deepseek-v4-pro",
|
|
676
|
+
"cline-pass/deepseek-v4-flash",
|
|
677
|
+
"cline-pass/mimo-v2.5",
|
|
678
|
+
"cline-pass/mimo-v2.5-pro",
|
|
679
|
+
"cline-pass/minimax-m3",
|
|
680
|
+
"cline-pass/qwen3.7-max",
|
|
681
|
+
"cline-pass/qwen3.7-plus",
|
|
682
|
+
];
|
|
683
|
+
const CLINE_PASS_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
684
|
+
"cline-pass/glm-5.2": 1_048_576,
|
|
685
|
+
"cline-pass/kimi-k3": 1_048_576,
|
|
686
|
+
"cline-pass/kimi-k2.7-code": 262_144,
|
|
687
|
+
"cline-pass/kimi-k2.6": 262_144,
|
|
688
|
+
"cline-pass/deepseek-v4-pro": 1_048_576,
|
|
689
|
+
"cline-pass/deepseek-v4-flash": 1_048_576,
|
|
690
|
+
"cline-pass/mimo-v2.5": 1_050_000,
|
|
691
|
+
"cline-pass/mimo-v2.5-pro": 1_050_000,
|
|
692
|
+
"cline-pass/minimax-m3": 1_048_576,
|
|
693
|
+
"cline-pass/qwen3.7-max": 1_000_000,
|
|
694
|
+
"cline-pass/qwen3.7-plus": 1_000_000,
|
|
695
|
+
};
|
|
696
|
+
const CLINE_PASS_IMAGE_MODELS = new Set([
|
|
697
|
+
"cline-pass/kimi-k3",
|
|
698
|
+
"cline-pass/kimi-k2.7-code",
|
|
699
|
+
"cline-pass/kimi-k2.6",
|
|
700
|
+
"cline-pass/mimo-v2.5",
|
|
701
|
+
"cline-pass/minimax-m3",
|
|
702
|
+
"cline-pass/qwen3.7-plus",
|
|
703
|
+
]);
|
|
704
|
+
const CLINE_PASS_TEXT_ONLY_MODELS = CLINE_PASS_MODELS.filter(id => !CLINE_PASS_IMAGE_MODELS.has(id));
|
|
705
|
+
const CLINE_PASS_MODEL_INPUT_MODALITIES: Record<string, string[]> = Object.fromEntries(
|
|
706
|
+
CLINE_PASS_MODELS.map(id => [id, CLINE_PASS_IMAGE_MODELS.has(id) ? ["text", "image"] : ["text"]]),
|
|
707
|
+
);
|
|
569
708
|
|
|
570
709
|
export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
571
710
|
{
|
|
@@ -575,6 +714,7 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
575
714
|
baseUrl: "https://chatgpt.com/backend-api/codex",
|
|
576
715
|
authKind: "forward",
|
|
577
716
|
codexAccountMode: "pool",
|
|
717
|
+
supportsServiceTier: true,
|
|
578
718
|
featured: true,
|
|
579
719
|
note: "Codex login account pool (default) or Direct main-account mode via codexAccountMode",
|
|
580
720
|
},
|
|
@@ -745,6 +885,7 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
745
885
|
adapter: "openai-responses",
|
|
746
886
|
baseUrl: "https://api.openai.com/v1",
|
|
747
887
|
authKind: "key",
|
|
888
|
+
supportsServiceTier: true,
|
|
748
889
|
featured: true,
|
|
749
890
|
dashboardUrl: "https://platform.openai.com/api-keys",
|
|
750
891
|
defaultModel: "gpt-5.5",
|
|
@@ -869,6 +1010,56 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
869
1010
|
preserveReasoningContentModels: NEURALWATT_REASONING_HISTORY_MODELS,
|
|
870
1011
|
},
|
|
871
1012
|
{ id: "openrouter", label: "OpenRouter", adapter: "openai-chat", baseUrl: "https://openrouter.ai/api/v1", authKind: "key", featured: true, dashboardUrl: "https://openrouter.ai/keys", jawcodeBundle: "openrouter", models: ["anthropic/claude-sonnet-5", ...OPENROUTER_GPT56_MODELS], modelContextWindows: { "anthropic/claude-sonnet-5": 1_000_000, ...OPENROUTER_GPT56_CONTEXT_WINDOWS } },
|
|
1013
|
+
{
|
|
1014
|
+
// Primary sources checked 2026-08-02:
|
|
1015
|
+
// - docs.cline.bot/getting-started/clinepass publishes this exact catalog and explicitly
|
|
1016
|
+
// authorizes using the full slugs through Cline's external API.
|
|
1017
|
+
// - docs.cline.bot/api/chat-completions and /api/errors define the endpoint, reasoning delta,
|
|
1018
|
+
// and choice-scoped mid-stream error contract.
|
|
1019
|
+
// - Cline's official catalog source resolves per-model capabilities through OpenRouter data;
|
|
1020
|
+
// the static context/modality snapshot below was cross-checked against that catalog.
|
|
1021
|
+
// - cline.bot/tos identifies Cline Bot Inc. as the operator. Maintenance owner: @lidge-jun.
|
|
1022
|
+
id: "cline-pass",
|
|
1023
|
+
label: "ClinePass",
|
|
1024
|
+
adapter: "openai-chat",
|
|
1025
|
+
baseUrl: "https://api.cline.bot/api/v1",
|
|
1026
|
+
authKind: "key",
|
|
1027
|
+
dashboardUrl: "https://app.cline.bot",
|
|
1028
|
+
defaultModel: "cline-pass/kimi-k3",
|
|
1029
|
+
models: CLINE_PASS_MODELS,
|
|
1030
|
+
modelContextWindows: CLINE_PASS_MODEL_CONTEXT_WINDOWS,
|
|
1031
|
+
modelInputModalities: CLINE_PASS_MODEL_INPUT_MODALITIES,
|
|
1032
|
+
noVisionModels: CLINE_PASS_TEXT_ONLY_MODELS,
|
|
1033
|
+
// Only low and the `reasoning: { enabled, effort }` request shape have been accepted by a live
|
|
1034
|
+
// ClinePass request. Neither wire detail is currently documented, so clamp higher Codex
|
|
1035
|
+
// requests to the verified tier until the gateway documents or is live-probed more broadly.
|
|
1036
|
+
reasoningEfforts: ["low"],
|
|
1037
|
+
reasoningWireFormat: "gateway-object",
|
|
1038
|
+
preserveCustomDestination: true,
|
|
1039
|
+
note: "ClinePass subscription API. Uses a Cline API key and the full cline-pass/<model> upstream slug; quota is shared across the account's rolling 5-hour, weekly, and monthly limits.",
|
|
1040
|
+
},
|
|
1041
|
+
// Cline API (usage-billing): OpenAI-compatible Chat Completions. Model IDs follow the
|
|
1042
|
+
// OpenRouter-style `provider/model` convention. Live /models discovery is key-gated (401
|
|
1043
|
+
// without auth), so the static seed is the cold-start fallback. Evidence: docs.cline.bot/api/*.
|
|
1044
|
+
{
|
|
1045
|
+
id: "cline",
|
|
1046
|
+
label: "Cline",
|
|
1047
|
+
adapter: "openai-chat",
|
|
1048
|
+
baseUrl: "https://api.cline.bot/api/v1",
|
|
1049
|
+
authKind: "key",
|
|
1050
|
+
dashboardUrl: "https://app.cline.bot",
|
|
1051
|
+
liveModels: true,
|
|
1052
|
+
defaultModel: "anthropic/claude-sonnet-4-6",
|
|
1053
|
+
models: [
|
|
1054
|
+
"anthropic/claude-sonnet-4-6",
|
|
1055
|
+
"openai/gpt-4o",
|
|
1056
|
+
"google/gemini-2.5-pro",
|
|
1057
|
+
"deepseek/deepseek-chat",
|
|
1058
|
+
"minimax/minimax-m2.5",
|
|
1059
|
+
],
|
|
1060
|
+
preserveCustomDestination: true,
|
|
1061
|
+
note: "Cline usage-billing API: one key, 100+ models, OpenRouter-style ids. Promotional free models are IDE/CLI-only per Cline docs; minimax/minimax-m2.5 is the documented API free experimentation model.",
|
|
1062
|
+
},
|
|
872
1063
|
{
|
|
873
1064
|
// OrcaRouter: OpenAI-compatible adaptive router (api.orcarouter.ai). Model ids are
|
|
874
1065
|
// vendor-namespaced (`<vendor>/<model>`) and pass through to the upstream as-is.
|
|
@@ -960,11 +1151,29 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
960
1151
|
// for no gain.
|
|
961
1152
|
"deepseek-v4-flash": { wire: "openai-responses", inbound: ["responses"] },
|
|
962
1153
|
},
|
|
1154
|
+
// DeepSeek's Codex Responses stream can deliver output without closing on the
|
|
1155
|
+
// terminal event. Keep Codex on WebSocket, but use the provider's bounded JSON
|
|
1156
|
+
// response upstream so the bridge can synthesize a complete WS event sequence.
|
|
1157
|
+
modelResponsesUpstreamStreaming: { "deepseek-v4-flash": false },
|
|
1158
|
+
// DeepSeek's Responses route emits bare UUID item ids, which leave Codex
|
|
1159
|
+
// clients stuck on an uncommitted turn (#938). Client-facing only — raw
|
|
1160
|
+
// continuation snapshots keep the upstream ids.
|
|
1161
|
+
responsesItemIdRepair: { repairInvalidIds: true, repairMissingTerminalIds: true },
|
|
963
1162
|
// DeepSeek's Responses route is `POST /responses` with no `/v1` segment. Without
|
|
964
1163
|
// this the passthrough adapter falls back to its legacy `/v1/responses`
|
|
965
1164
|
// construction and the wire above can never route.
|
|
966
1165
|
// Evidence: https://api-docs.deepseek.com/api/create-response/
|
|
967
1166
|
responsesPath: "/responses",
|
|
1167
|
+
// DeepSeek's Responses reference does not list `service_tier`; unsupported
|
|
1168
|
+
// parameters are documented as silently ignored, but the fail-closed policy
|
|
1169
|
+
// strips the field rather than forwarding a knob the upstream never asked for.
|
|
1170
|
+
supportsServiceTier: false,
|
|
1171
|
+
// DeepSeek's Responses compatibility guide accepts plaintext reasoning items and
|
|
1172
|
+
// merges them into the adjacent assistant message, so replayed reasoning must
|
|
1173
|
+
// not be blanked the way the ChatGPT backend requires. (Whether the Responses
|
|
1174
|
+
// route REQUIRES replay on tool-call continuations is an inference from the
|
|
1175
|
+
// Chat Thinking-Mode docs, not a confirmed Responses contract.)
|
|
1176
|
+
preserveResponsesReasoningContent: true,
|
|
968
1177
|
// "The API is stateless: responses and conversations are not stored on the
|
|
969
1178
|
// server." https://api-docs.deepseek.com/api/create-response/
|
|
970
1179
|
statelessResponses: true,
|
|
@@ -1045,6 +1254,32 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
1045
1254
|
},
|
|
1046
1255
|
note: "Shared Model APIs only (personal API key, or team key with Call Model APIs access); dedicated Truss predict endpoints are outside this preset.",
|
|
1047
1256
|
},
|
|
1257
|
+
{
|
|
1258
|
+
id: "commandcode",
|
|
1259
|
+
label: "Command Code",
|
|
1260
|
+
adapter: "openai-chat",
|
|
1261
|
+
baseUrl: "https://api.commandcode.ai/provider/v1",
|
|
1262
|
+
authKind: "key",
|
|
1263
|
+
dashboardUrl: "https://commandcode.ai/studio/",
|
|
1264
|
+
liveModels: true,
|
|
1265
|
+
preserveCustomDestination: true,
|
|
1266
|
+
defaultModel: "deepseek/deepseek-v4-flash",
|
|
1267
|
+
// The default is also the cold-start seed: live discovery failure must not empty the catalog
|
|
1268
|
+
// for a freshly configured provider with no stale cache (issue #308 pattern).
|
|
1269
|
+
models: ["deepseek/deepseek-v4-flash"],
|
|
1270
|
+
// The public model catalog is unauthenticated, so a Bearer probe cannot prove key validity.
|
|
1271
|
+
apiKeyValidation: "unknown",
|
|
1272
|
+
// The public catalog reports ids/context windows only; no trustworthy reasoning contract.
|
|
1273
|
+
reasoningEfforts: [],
|
|
1274
|
+
modelDiscovery: {
|
|
1275
|
+
path: "models",
|
|
1276
|
+
maxResponseBytes: 256 * 1024,
|
|
1277
|
+
maxModels: 256,
|
|
1278
|
+
},
|
|
1279
|
+
// Verified 2026-08-03: public /provider/v1/models returns 51 rows; /chat/completions returns
|
|
1280
|
+
// 401 UNAUTHORIZED without a Bearer key. Primary source: https://commandcode.ai/docs/provider.
|
|
1281
|
+
note: "Command Code Provider API (OpenAI-compatible); API access requires the Provider plan. CLI auth bridging for Go/Pro subscriptions is not yet available. Docs: https://commandcode.ai/docs/provider.",
|
|
1282
|
+
},
|
|
1048
1283
|
// FREEZE 2026-07-10: exact serverless ids remain auth-gated/unverified. Evidence: devlog/_plan/260710_provider_hardening/003_research_aggregators.md.
|
|
1049
1284
|
{ id: "together", label: "Together", baseUrl: "https://api.together.xyz/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://api.together.xyz/settings/api-keys" },
|
|
1050
1285
|
{ id: "fireworks", label: "Fireworks", baseUrl: "https://api.fireworks.ai/inference/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://fireworks.ai/account/api-keys" },
|
|
@@ -1081,6 +1316,11 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
1081
1316
|
// Free pricing, but an API key is still required (free key from build.nvidia.com).
|
|
1082
1317
|
freeTier: true,
|
|
1083
1318
|
parallelToolCalls: false,
|
|
1319
|
+
// 260804 issue #956: NIM exposes no input modalities, so vision capability is
|
|
1320
|
+
// classified here. Both lists are verified per-model; unlisted ids stay unclassified
|
|
1321
|
+
// by design (see the comment on NVIDIA_NIM_VISION_MODELS).
|
|
1322
|
+
noVisionModels: NVIDIA_NIM_NO_VISION_MODELS,
|
|
1323
|
+
modelInputModalities: NVIDIA_NIM_VISION_INPUT_MODALITIES,
|
|
1084
1324
|
noReasoningModels: NVIDIA_NIM_KIMI_MODELS,
|
|
1085
1325
|
modelReasoningEfforts: Object.fromEntries(NVIDIA_NIM_KIMI_MODELS.map(id => [id, []])),
|
|
1086
1326
|
preserveReasoningContentModels: NVIDIA_NIM_KIMI_THINKING_MODELS,
|
|
@@ -1245,6 +1485,8 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
1245
1485
|
responsesPath: "/responses",
|
|
1246
1486
|
adapter: "openai-responses",
|
|
1247
1487
|
authKind: "key",
|
|
1488
|
+
// Ark's plan route does not document `service_tier`; fail closed like DeepSeek.
|
|
1489
|
+
supportsServiceTier: false,
|
|
1248
1490
|
preserveCustomDestination: true,
|
|
1249
1491
|
dashboardUrl: "https://console.volcengine.com/ark/region:ark+cn-beijing/overview",
|
|
1250
1492
|
defaultModel: "deepseek-v4-pro",
|
|
@@ -1265,13 +1507,13 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
1265
1507
|
adapter: "openai-chat",
|
|
1266
1508
|
authKind: "key",
|
|
1267
1509
|
dashboardUrl: "https://bailian.console.aliyun.com/cn-beijing?tab=plan",
|
|
1268
|
-
defaultModel: "qwen3.8-max
|
|
1510
|
+
defaultModel: "qwen3.8-max",
|
|
1269
1511
|
models: ALIBABA_TOKEN_PLAN_MODELS,
|
|
1270
1512
|
liveModels: false,
|
|
1271
1513
|
note: "Token Plan Personal Edition · China (Beijing)",
|
|
1272
1514
|
modelInputModalities: ALIBABA_TOKEN_PLAN_INPUT_MODALITIES,
|
|
1273
1515
|
modelContextWindows: {
|
|
1274
|
-
"qwen3.8-max
|
|
1516
|
+
"qwen3.8-max": 983_616, "qwen3.7-max": 1_000_000, "qwen3.7-plus": 1_000_000,
|
|
1275
1517
|
"qwen3.6-flash": 1_000_000, "glm-5.2": 1_000_000, "deepseek-v4-pro": 1_000_000,
|
|
1276
1518
|
},
|
|
1277
1519
|
modelReasoningEfforts: {
|
|
@@ -1281,7 +1523,7 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
1281
1523
|
},
|
|
1282
1524
|
modelReasoningEffortMap: { "deepseek-v4-pro": DEEPSEEK_THINKING_REASONING_MAP },
|
|
1283
1525
|
thinkingBudgetModels: ALIBABA_TOKEN_PLAN_QWEN_MODELS,
|
|
1284
|
-
preserveReasoningContentModels: ["glm-5.2", "deepseek-v4-pro", "qwen3.8-max
|
|
1526
|
+
preserveReasoningContentModels: ["glm-5.2", "deepseek-v4-pro", "qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash"],
|
|
1285
1527
|
noVisionModels: ["glm-5.2", "deepseek-v4-pro"],
|
|
1286
1528
|
},
|
|
1287
1529
|
{
|
|
@@ -1300,7 +1542,7 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
1300
1542
|
metadataModelIdNormalize: "case-insensitive",
|
|
1301
1543
|
modelInputModalities: ALIBABA_INTL_TOKEN_PLAN_INPUT_MODALITIES,
|
|
1302
1544
|
modelContextWindows: {
|
|
1303
|
-
"qwen3.8-max
|
|
1545
|
+
"qwen3.8-max": 983_616,
|
|
1304
1546
|
"qwen3.7-max": 1_000_000, "qwen3.7-plus": 1_000_000, "qwen3.6-plus": 1_000_000, "qwen3.6-flash": 1_000_000,
|
|
1305
1547
|
"deepseek-v4-pro": 1_000_000, "deepseek-v4-flash": 1_000_000, "deepseek-v3.2": 131_072,
|
|
1306
1548
|
"kimi-k2.7-code": 262_144, "kimi-k2.6": 262_144, "kimi-k2.5": 262_144,
|
|
@@ -1309,7 +1551,7 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
1309
1551
|
},
|
|
1310
1552
|
modelReasoningEfforts: {
|
|
1311
1553
|
...Object.fromEntries(ALIBABA_INTL_TOKEN_PLAN_QWEN_MODELS.map(id => [id, THINKING_BUDGET_EFFORTS])),
|
|
1312
|
-
"qwen3.8-max
|
|
1554
|
+
"qwen3.8-max": ["low", "high", "xhigh"],
|
|
1313
1555
|
"glm-5.2": ZAI_GLM_52_REASONING_EFFORTS,
|
|
1314
1556
|
"deepseek-v4-pro": DEEPSEEK_THINKING_EFFORTS,
|
|
1315
1557
|
"deepseek-v4-flash": DEEPSEEK_THINKING_EFFORTS,
|
|
@@ -1319,10 +1561,10 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
1319
1561
|
"deepseek-v4-flash": DEEPSEEK_THINKING_REASONING_MAP,
|
|
1320
1562
|
},
|
|
1321
1563
|
thinkingBudgetModels: ALIBABA_INTL_TOKEN_PLAN_QWEN_MODELS,
|
|
1322
|
-
preserveReasoningContentModels: ["glm-5.2", "deepseek-v4-pro", "deepseek-v4-flash", "qwen3.8-max
|
|
1564
|
+
preserveReasoningContentModels: ["glm-5.2", "deepseek-v4-pro", "deepseek-v4-flash", "qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.6-flash"],
|
|
1323
1565
|
noVisionModels: ["deepseek-v4-pro", "deepseek-v4-flash", "deepseek-v3.2", "glm-5.2", "glm-5.1", "glm-5", "MiniMax-M2.5"],
|
|
1324
1566
|
noReasoningModels: ["kimi-k2.7-code", "kimi-k2.6", "kimi-k2.5", "deepseek-v3.2", "glm-5.1", "glm-5", "MiniMax-M2.5"],
|
|
1325
|
-
modelDefaultReasoningEfforts: { "qwen3.8-max
|
|
1567
|
+
modelDefaultReasoningEfforts: { "qwen3.8-max": "xhigh" },
|
|
1326
1568
|
},
|
|
1327
1569
|
// NEEDS_HUMAN 2026-07-10: kept for config compatibility, but this is a dashboard URL,
|
|
1328
1570
|
// no /models endpoint is documented, and tools are silently ignored upstream per docs.parallel.ai.
|
|
@@ -1476,8 +1718,23 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
1476
1718
|
featured: false,
|
|
1477
1719
|
dashboardUrl: "https://github.com/settings/copilot",
|
|
1478
1720
|
liveModels: true,
|
|
1479
|
-
models: ["gpt-4o", "gpt-4.1", "gpt-4.1-mini", "claude-sonnet-4", "gemini-2.5-pro"],
|
|
1721
|
+
models: ["gpt-4o", "gpt-4.1", "gpt-4.1-mini", "claude-sonnet-4", "gemini-2.5-pro", "gpt-5-mini", "gpt-5.3-codex", "gpt-5.4", "gpt-5.4-mini", "gpt-5.5", "gpt-5.6-luna", "gpt-5.6-sol", "gpt-5.6-terra"],
|
|
1480
1722
|
defaultModel: "gpt-4o",
|
|
1723
|
+
// Copilot fronts a mixed-wire catalog: these models reject /chat/completions for
|
|
1724
|
+
// real Codex-agent traffic (function tools + reasoning), so every inbound wire
|
|
1725
|
+
// rides Responses. Evidence: issue #748 field runs, pi.dev/models/github-copilot/*
|
|
1726
|
+
// wire declarations, BerriAI/litellm#23332 (gpt-5.4), JetBrains LLM-29711
|
|
1727
|
+
// (gpt-5.6-sol). gpt-5.4-nano is deliberately absent — it has no field report; a
|
|
1728
|
+
// user can opt it in with an explicit modelAdapters entry, which always wins.
|
|
1729
|
+
modelWireDefaults: {
|
|
1730
|
+
"gpt-5.3-codex": "openai-responses",
|
|
1731
|
+
"gpt-5.4": "openai-responses",
|
|
1732
|
+
"gpt-5.4-mini": "openai-responses",
|
|
1733
|
+
"gpt-5.5": "openai-responses",
|
|
1734
|
+
"gpt-5.6-luna": "openai-responses",
|
|
1735
|
+
"gpt-5.6-sol": "openai-responses",
|
|
1736
|
+
"gpt-5.6-terra": "openai-responses",
|
|
1737
|
+
},
|
|
1481
1738
|
note: "Experimental unofficial Copilot bridge. Logs in via GitHub device flow using the public VS Code OAuth client id, then exchanges for a short-lived Copilot API token (copilot_internal). Requires an active Copilot subscription. GitHub may tighten or revoke this path; do not send confidential material you would not paste into Copilot Chat.",
|
|
1482
1739
|
},
|
|
1483
1740
|
// FREEZE 2026-07-10: no public OpenAI-compatible endpoint is documented. Evidence: devlog/_plan/260710_provider_hardening/003_research_aggregators.md.
|
|
@@ -1573,6 +1830,17 @@ export function providerModelWireDefault(
|
|
|
1573
1830
|
return wire !== undefined && allowedWires.has(wire) ? wire : undefined;
|
|
1574
1831
|
}
|
|
1575
1832
|
|
|
1833
|
+
/** Resolve a registry-only upstream-streaming compatibility hint for Responses turns. */
|
|
1834
|
+
export function providerModelResponsesUpstreamStreaming(
|
|
1835
|
+
id: string,
|
|
1836
|
+
provider: Pick<OcxProviderConfig, "baseUrl" | "adapter"> & Partial<Pick<OcxProviderConfig, "authMode">>,
|
|
1837
|
+
modelId: string,
|
|
1838
|
+
): boolean | undefined {
|
|
1839
|
+
const entry = getProviderRegistryEntry(id);
|
|
1840
|
+
if (!entry?.modelResponsesUpstreamStreaming || !providerMatchesRegistryTransport(id, provider)) return undefined;
|
|
1841
|
+
return entry.modelResponsesUpstreamStreaming[modelId.trim().toLowerCase()];
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1576
1844
|
/**
|
|
1577
1845
|
* Effective Codex account mode for a provider. For canonical `openai`, a valid persisted
|
|
1578
1846
|
* `codexAccountMode` on the provider config wins and a missing/invalid value defaults to
|
|
@@ -53,7 +53,7 @@ function withoutUserOverridden(
|
|
|
53
53
|
|
|
54
54
|
function withGeneratedRequestId(
|
|
55
55
|
init: RequestInit | undefined,
|
|
56
|
-
|
|
56
|
+
pinnedRequestId: string,
|
|
57
57
|
stableHeaders: Readonly<Record<string, string>>,
|
|
58
58
|
): RequestInit {
|
|
59
59
|
const headers = new Headers(init?.headers);
|
|
@@ -63,7 +63,7 @@ function withGeneratedRequestId(
|
|
|
63
63
|
if (!headers.has(XAI_GROK_COMPATIBILITY.headers.requestId)) {
|
|
64
64
|
headers.set(
|
|
65
65
|
XAI_GROK_COMPATIBILITY.headers.requestId,
|
|
66
|
-
|
|
66
|
+
pinnedRequestId,
|
|
67
67
|
);
|
|
68
68
|
}
|
|
69
69
|
return { ...init, headers };
|
|
@@ -83,7 +83,9 @@ export function deriveXaiConvId(promptCacheKey: string): string {
|
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* Resolve xAI's runtime transport without mutating persisted config. Conversation/session
|
|
86
|
-
* affinity is stable for this resolved transport; request identity is
|
|
86
|
+
* affinity is stable for this resolved transport; request identity is pinned per resolved
|
|
87
|
+
* transport (= per logical request until key rotation), so same-target replays and transient
|
|
88
|
+
* retries carry the same id while a rotated key gets a fresh one.
|
|
87
89
|
* Agent, deployment, model-override, turn, mode, and user identity headers are intentionally
|
|
88
90
|
* omitted because opencodex has no truthful values for the official fields.
|
|
89
91
|
*/
|
|
@@ -128,9 +130,14 @@ export function resolveProviderTransport(
|
|
|
128
130
|
provider.headers,
|
|
129
131
|
XAI_GROK_COMPATIBILITY.headers.requestId,
|
|
130
132
|
);
|
|
133
|
+
// Pin the request id per resolved transport (= per logical request until key rotation):
|
|
134
|
+
// same-target 429 replays must carry the SAME x-grok-req-id as the original dispatch, and
|
|
135
|
+
// transient retries reuse one id so the upstream can dedupe them. A rotated key resolves a
|
|
136
|
+
// fresh transport, which gets its own id.
|
|
137
|
+
const requestId = configuredRequestId ?? randomUUID();
|
|
131
138
|
const baseFetch = provider.fetch ?? globalThis.fetch;
|
|
132
139
|
const attemptFetch = ((input, init) =>
|
|
133
|
-
baseFetch(input, withGeneratedRequestId(init,
|
|
140
|
+
baseFetch(input, withGeneratedRequestId(init, requestId, stableHeaders))) as typeof globalThis.fetch;
|
|
134
141
|
|
|
135
142
|
return {
|
|
136
143
|
...provider,
|
|
@@ -105,7 +105,14 @@ export function buildCompactV1Output(userMessages: string[], summary: string): R
|
|
|
105
105
|
remaining -= msg.length;
|
|
106
106
|
} else {
|
|
107
107
|
// Budget partially covers this older message: keep its tail (most recent context) and stop.
|
|
108
|
-
|
|
108
|
+
let tailStart = msg.length - remaining;
|
|
109
|
+
// Never start the retained tail on a lone LOW surrogate: the pair's
|
|
110
|
+
// other half would be lost and encoding substitutes U+FFFD.
|
|
111
|
+
if (tailStart > 0 && tailStart < msg.length) {
|
|
112
|
+
const first = msg.charCodeAt(tailStart);
|
|
113
|
+
if (first >= 0xdc00 && first <= 0xdfff) tailStart += 1;
|
|
114
|
+
}
|
|
115
|
+
selected.push(msg.slice(tailStart));
|
|
109
116
|
break;
|
|
110
117
|
}
|
|
111
118
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Hosted tools rejected by specific native model slugs. */
|
|
2
|
+
const UNSUPPORTED_HOSTED_TOOLS: ReadonlyArray<{ match: (model: string) => boolean; tools: ReadonlySet<string> }> = [
|
|
3
|
+
{ match: model => model.includes("codex-spark"), tools: new Set(["image_generation", "tool_search"]) },
|
|
4
|
+
];
|
|
5
|
+
|
|
6
|
+
/** True when forwarding this hosted tool to the model would be rejected upstream. */
|
|
7
|
+
export function isHostedToolUnsupportedForModel(modelId: string, tool: string): boolean {
|
|
8
|
+
return UNSUPPORTED_HOSTED_TOOLS.some(entry => entry.match(modelId) && entry.tools.has(tool));
|
|
9
|
+
}
|
package/src/responses/parser.ts
CHANGED
|
@@ -263,6 +263,34 @@ function findToolById(messages: OcxMessage[], callId: string): { name: string; n
|
|
|
263
263
|
return { name: "" };
|
|
264
264
|
}
|
|
265
265
|
|
|
266
|
+
/**
|
|
267
|
+
* Attach pending reasoning to the assistant turn that owns the given call id.
|
|
268
|
+
* Reconstructed histories (resume/retry/synthetic) can order a `reasoning`
|
|
269
|
+
* item AFTER the `function_call` it belongs to; without this, the pending
|
|
270
|
+
* buffer is cleared at the tool output and the turn serializes without
|
|
271
|
+
* `reasoning_content`, which DeepSeek thinking mode rejects with HTTP 400
|
|
272
|
+
* (issue #950).
|
|
273
|
+
*/
|
|
274
|
+
function attachPendingReasoningToCallOwner(
|
|
275
|
+
messages: OcxMessage[],
|
|
276
|
+
callId: string,
|
|
277
|
+
pendingReasoning: Array<{ part: OcxThinkingContent; envelopeSigned: boolean }>,
|
|
278
|
+
): void {
|
|
279
|
+
if (pendingReasoning.length === 0 || !callId) return;
|
|
280
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
281
|
+
const m = messages[i];
|
|
282
|
+
if (m.role !== "assistant") continue;
|
|
283
|
+
for (const part of m.content) {
|
|
284
|
+
if (part.type === "toolCall" && part.id === callId) {
|
|
285
|
+
// Prepend so thinking still precedes tool_use for adapters that require
|
|
286
|
+
// that ordering (Anthropic-style replay).
|
|
287
|
+
m.content = [...pendingReasoning.map(entry => entry.part), ...m.content];
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
266
294
|
const REASONING_EFFORTS = new Set(["none", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
267
295
|
|
|
268
296
|
export function parseRequest(body: unknown): OcxParsedRequest {
|
|
@@ -416,6 +444,18 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
416
444
|
: null;
|
|
417
445
|
const thinkingText = envelope?.txt || text;
|
|
418
446
|
|
|
447
|
+
// Kiro reasoning round-trip: a krc-only item carries nothing renderable — it is provider
|
|
448
|
+
// state for the assistant turn that ALREADY closed, because Kiro emits its
|
|
449
|
+
// reasoningContentEvent at the END of a turn (after content AND tool calls, verified
|
|
450
|
+
// against kiro-cli 2.14.1/2.16.0). Folding it into the FOLLOWING turn like ordinary
|
|
451
|
+
// reasoning would attach turn N's blob to turn N+1, so attach it backwards instead. With
|
|
452
|
+
// no assistant turn to own it the blob is dropped rather than mis-paired.
|
|
453
|
+
if (envelope?.krc && thinkingText.length === 0) {
|
|
454
|
+
const previous = messages[messages.length - 1];
|
|
455
|
+
if (previous?.role === "assistant") previous.kiroRedactedReasoning = envelope.krc;
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
|
|
419
459
|
// Native/non-ocxr1 encrypted-only reasoning is opaque here. Do not create a detached
|
|
420
460
|
// assistant turn or invent replayable plaintext/signatures from the encrypted payload.
|
|
421
461
|
if (thinkingText.length > 0) {
|
|
@@ -545,8 +585,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
545
585
|
}
|
|
546
586
|
|
|
547
587
|
if (effectiveType === "function_call_output") {
|
|
548
|
-
pendingReasoning.length = 0;
|
|
549
588
|
const output = item as { call_id: string; output?: string | unknown[] };
|
|
589
|
+
attachPendingReasoningToCallOwner(messages, output.call_id, pendingReasoning);
|
|
590
|
+
pendingReasoning.length = 0;
|
|
550
591
|
const toolInfo = findToolById(messages, output.call_id);
|
|
551
592
|
messages.push({
|
|
552
593
|
role: "toolResult", toolCallId: output.call_id,
|
|
@@ -558,8 +599,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
558
599
|
}
|
|
559
600
|
|
|
560
601
|
if (effectiveType === "custom_tool_call_output") {
|
|
561
|
-
pendingReasoning.length = 0;
|
|
562
602
|
const output = item as { call_id: string; output: string | unknown[] };
|
|
603
|
+
attachPendingReasoningToCallOwner(messages, output.call_id, pendingReasoning);
|
|
604
|
+
pendingReasoning.length = 0;
|
|
563
605
|
const toolInfo = findToolById(messages, output.call_id);
|
|
564
606
|
messages.push({
|
|
565
607
|
role: "toolResult", toolCallId: output.call_id,
|