@oh-my-pi/pi-catalog 18.11.2 → 18.12.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/CHANGELOG.md +30 -0
- package/dist/types/compat/behavior.d.ts +5 -0
- package/dist/types/compat/catalog-endpoint.d.ts +8 -0
- package/dist/types/compat/judgment-images.d.ts +25 -0
- package/dist/types/compat/request-compression.d.ts +21 -0
- package/dist/types/compat/request-size.d.ts +2 -1
- package/dist/types/compat/types.d.ts +2 -0
- package/dist/types/model-cache.d.ts +7 -0
- package/dist/types/provider-models/openai-compat.d.ts +0 -46
- package/dist/types/types.d.ts +14 -1
- package/package.json +4 -4
- package/src/build.ts +13 -0
- package/src/compat/axes.ts +51 -1
- package/src/compat/behavior.ts +9 -1
- package/src/compat/catalog-endpoint.ts +43 -0
- package/src/compat/judgment-images.ts +83 -0
- package/src/compat/request-compression.ts +41 -0
- package/src/compat/request-size.ts +3 -1
- package/src/compat/resolve.ts +34 -49
- package/src/compat/rules/README.md +17 -1
- package/src/compat/rules/auth/google-antigravity.kdl +1 -1
- package/src/compat/rules/classes/anthropic.kdl +2 -3
- package/src/compat/rules/classes/deepseek.kdl +4 -0
- package/src/compat/rules/classes/minimax.kdl +10 -0
- package/src/compat/rules/classes/openai.kdl +8 -0
- package/src/compat/rules/providers/anthropic.kdl +4 -0
- package/src/compat/rules/providers/azure.kdl +2 -0
- package/src/compat/rules/providers/cerebras.kdl +3 -0
- package/src/compat/rules/providers/cline-pass.kdl +16 -0
- package/src/compat/rules/providers/commandcode.kdl +10 -0
- package/src/compat/rules/providers/deepinfra.kdl +3 -1
- package/src/compat/rules/providers/devin.kdl +7 -1
- package/src/compat/rules/providers/factory-droid.kdl +6 -0
- package/src/compat/rules/providers/firepass.kdl +15 -0
- package/src/compat/rules/providers/fireworks.kdl +26 -0
- package/src/compat/rules/providers/github-copilot.kdl +24 -0
- package/src/compat/rules/providers/google-antigravity.kdl +11 -0
- package/src/compat/rules/providers/moonshot.kdl +2 -0
- package/src/compat/rules/providers/ollama-cloud.kdl +3 -0
- package/src/compat/rules/providers/openai-codex.kdl +9 -0
- package/src/compat/rules/providers/opencode-go.kdl +4 -0
- package/src/compat/rules/providers/opencode-zen.kdl +4 -0
- package/src/compat/rules/providers/openrouter.kdl +15 -0
- package/src/compat/rules/providers/tool-call-names.kdl +37 -0
- package/src/compat/rules/providers/typesafe.kdl +8 -0
- package/src/compat/rules/providers/umans.kdl +6 -0
- package/src/compat/rules/providers/venice.kdl +7 -0
- package/src/compat/rules/providers/xai-oauth.kdl +4 -0
- package/src/compat/rules/providers/zai.kdl +5 -0
- package/src/compat/rules/runtime/behavior.kdl +115 -4
- package/src/compat/rules.json +1 -1
- package/src/compat/types.ts +2 -0
- package/src/model-cache.ts +8 -0
- package/src/model-manager.ts +29 -20
- package/src/models.json +1 -1
- package/src/provider-models/openai-compat.ts +8 -90
- package/src/types.ts +14 -0
package/src/compat/resolve.ts
CHANGED
|
@@ -330,7 +330,6 @@ function isOfficialOpenAIEndpoint(provider: string, baseUrl: string): boolean {
|
|
|
330
330
|
|
|
331
331
|
interface OpenAIDetection {
|
|
332
332
|
facts: IdentityFacts;
|
|
333
|
-
isClinePass: boolean;
|
|
334
333
|
isZai: boolean;
|
|
335
334
|
isZhipu: boolean;
|
|
336
335
|
isMoonshotNative: boolean;
|
|
@@ -368,7 +367,6 @@ function detectOpenAI(
|
|
|
368
367
|
(LOCAL_OPENAI_COMPAT_PROVIDERS[backendProvider] === true || hasLocalLoopbackBaseUrl(baseUrl));
|
|
369
368
|
return {
|
|
370
369
|
facts,
|
|
371
|
-
isClinePass: provider === "cline-pass",
|
|
372
370
|
isZai,
|
|
373
371
|
isZhipu,
|
|
374
372
|
isMoonshotNative,
|
|
@@ -474,7 +472,9 @@ function detectOpenAICompat(
|
|
|
474
472
|
provider === "github-copilot" ||
|
|
475
473
|
provider === "zenmux");
|
|
476
474
|
|
|
477
|
-
//
|
|
475
|
+
// URL-keyed watchdogs: they also cover custom provider ids pointed at these
|
|
476
|
+
// hosts, which provider-keyed rules (`stream-idle-timeout-ms` in
|
|
477
|
+
// classes/{glm,kimi,mimo}.kdl) cannot match. KDL rules override them.
|
|
478
478
|
const streamIdleTimeoutMs =
|
|
479
479
|
facts.is("glm") &&
|
|
480
480
|
facts.revGte("5") &&
|
|
@@ -521,21 +521,17 @@ function detectOpenAICompat(
|
|
|
521
521
|
supportsMultipleSystemMessages: supportsMultipleSystemMessagesDefault,
|
|
522
522
|
supportsReasoningEffort: !isGrok && !d.isXiaomiMimo && (!(d.isZai || d.isZhipu) || supportsZaiReasoningEffort),
|
|
523
523
|
trustExplicitThinkingOnly: undefined,
|
|
524
|
-
|
|
525
|
-
// provider rule without changing Copilot Responses rows.
|
|
526
|
-
supportsReasoningParams: provider !== "github-copilot",
|
|
524
|
+
supportsReasoningParams: true,
|
|
527
525
|
supportsSamplingParams: true,
|
|
528
526
|
supportsPenaltyAndStopParams: !(isGrok && reasoningCapable),
|
|
529
527
|
reasoningEffortMap: {},
|
|
530
528
|
supportsUsageInStreaming: !isCerebrasHost,
|
|
531
529
|
alwaysSendMaxTokens: facts.is("kimi"),
|
|
532
|
-
disableReasoningOnForcedToolChoice:
|
|
533
|
-
|
|
534
|
-
disableReasoningOnToolChoice: !d.isClinePass && isDeepseekFamily && reasoningCapable && !d.isOpenRouter,
|
|
530
|
+
disableReasoningOnForcedToolChoice: (facts.is("kimi") && !isMoonshotKimiK3) || isAnthropicModel,
|
|
531
|
+
disableReasoningOnToolChoice: isDeepseekFamily && reasoningCapable && !d.isOpenRouter,
|
|
535
532
|
disableReasoningWithTools: false,
|
|
536
|
-
supportsToolChoice:
|
|
537
|
-
supportsForcedToolChoice:
|
|
538
|
-
!d.requiresEnabledThinking && !(d.isOpenCodeHost && d.isDeepseekReasoning) && !(d.isClinePass && isQwen),
|
|
533
|
+
supportsToolChoice: !d.isDirectDeepseekReasoning,
|
|
534
|
+
supportsForcedToolChoice: !d.requiresEnabledThinking && !(d.isOpenCodeHost && d.isDeepseekReasoning),
|
|
539
535
|
supportsNamedToolChoice: true,
|
|
540
536
|
maxTokensField: useMaxTokens ? "max_tokens" : "max_completion_tokens",
|
|
541
537
|
requiresToolResultName: isMistral,
|
|
@@ -544,16 +540,12 @@ function detectOpenAICompat(
|
|
|
544
540
|
requiresMistralToolIds: isMistral,
|
|
545
541
|
thinkingFormat,
|
|
546
542
|
kimiApiFormat: undefined,
|
|
547
|
-
reasoningDisableMode: d.
|
|
548
|
-
? "cline-enabled-false"
|
|
549
|
-
: d.isVenice
|
|
550
|
-
? "venice-disable-thinking"
|
|
551
|
-
: resolveReasoningDisableMode(thinkingFormat),
|
|
543
|
+
reasoningDisableMode: d.isVenice ? "venice-disable-thinking" : resolveReasoningDisableMode(thinkingFormat),
|
|
552
544
|
omitReasoningEffort: false,
|
|
553
545
|
includeEncryptedReasoning: true,
|
|
554
546
|
filterReasoningHistory: d.isOpenRouter && isAnthropicModel,
|
|
555
547
|
thinkingKeep: usesMoonshotKimiPreservedThinking ? "all" : undefined,
|
|
556
|
-
reasoningContentField:
|
|
548
|
+
reasoningContentField: "reasoning_content",
|
|
557
549
|
mistralReasoningContentParts: undefined,
|
|
558
550
|
requiresReasoningContentForToolCalls:
|
|
559
551
|
(facts.is("kimi") && !d.isOpenCodeProvider) ||
|
|
@@ -571,10 +563,7 @@ function detectOpenAICompat(
|
|
|
571
563
|
// Template effort support is a reviewed backend × model contract in KDL.
|
|
572
564
|
qwenTemplateReasoningEffort: false,
|
|
573
565
|
requiresAssistantContentForToolCalls: facts.is("kimi") || d.isDirectDeepseekReasoning,
|
|
574
|
-
cacheControlFormat:
|
|
575
|
-
(d.isClinePass && (isQwen || isAnthropicModel)) || (d.isOpenRouter && isAnthropicModel)
|
|
576
|
-
? "anthropic"
|
|
577
|
-
: undefined,
|
|
566
|
+
cacheControlFormat: d.isOpenRouter && isAnthropicModel ? "anthropic" : undefined,
|
|
578
567
|
supportsPromptCacheBreakpoints,
|
|
579
568
|
promptCacheBreakpointTtl: supportsPromptCacheBreakpoints ? "30m" : undefined,
|
|
580
569
|
openRouterRouting: undefined,
|
|
@@ -599,7 +588,11 @@ function detectOpenAICompat(
|
|
|
599
588
|
: undefined,
|
|
600
589
|
streamFirstEventTimeoutMs: d.isLocalServingBackend ? 0 : undefined,
|
|
601
590
|
streamIdleTimeoutMs,
|
|
602
|
-
stripDeepseekSpecialTokens:
|
|
591
|
+
stripDeepseekSpecialTokens: false,
|
|
592
|
+
// Present as a key so models.yml `compat` can set it; unset unless a rule assigns it.
|
|
593
|
+
stripThinkingHistory: undefined,
|
|
594
|
+
// URL-derived like the Responses field; unset off the official OpenAI API.
|
|
595
|
+
officialEndpoint: isOfficialOpenAIEndpoint(spec.provider, baseUrl) || undefined,
|
|
603
596
|
streamMarkupHealingPattern: detectStreamMarkupHealing(spec.provider, facts, baseUrl),
|
|
604
597
|
reasoningDeltasMayBeCumulative: false,
|
|
605
598
|
emptyLengthFinishIsContextError: false,
|
|
@@ -657,15 +650,13 @@ function fixupOpenAICompat(
|
|
|
657
650
|
compat.extraBody = Object.keys(extraBody).length > 0 ? extraBody : undefined;
|
|
658
651
|
}
|
|
659
652
|
if (spec.compat?.reasoningDisableMode === undefined && !("reasoningDisableMode" in axes.wire)) {
|
|
660
|
-
compat.reasoningDisableMode = d.
|
|
661
|
-
? "
|
|
662
|
-
: d.
|
|
663
|
-
? "
|
|
664
|
-
: d.
|
|
665
|
-
? "
|
|
666
|
-
:
|
|
667
|
-
? "venice-disable-thinking"
|
|
668
|
-
: resolveReasoningDisableMode(compat.thinkingFormat);
|
|
653
|
+
compat.reasoningDisableMode = d.requiresEnabledThinking
|
|
654
|
+
? "omit"
|
|
655
|
+
: d.isDirectDeepseekReasoning
|
|
656
|
+
? "zai-thinking-disabled"
|
|
657
|
+
: d.isVenice
|
|
658
|
+
? "venice-disable-thinking"
|
|
659
|
+
: resolveReasoningDisableMode(compat.thinkingFormat);
|
|
669
660
|
}
|
|
670
661
|
if (
|
|
671
662
|
spec.compat?.omitReasoningEffort === undefined &&
|
|
@@ -754,7 +745,8 @@ function resolveOpenAIResponsesPolicy(
|
|
|
754
745
|
supportsLongPromptCacheRetention: isOpenAIUrl,
|
|
755
746
|
supportsPromptCacheBreakpoints,
|
|
756
747
|
promptCacheBreakpointTtl: supportsPromptCacheBreakpoints ? "30m" : undefined,
|
|
757
|
-
|
|
748
|
+
// Provider ids are rule-owned; the URL arm keeps custom Azure endpoints paired.
|
|
749
|
+
strictResponsesPairing: hostMatchesUrl(baseUrl, "azureOpenAI"),
|
|
758
750
|
// Azure's provider id alone only implies support while its endpoint is
|
|
759
751
|
// resolved at runtime; an explicit non-Azure baseUrl is a proxy, like Codex.
|
|
760
752
|
supportsImageDetailOriginal:
|
|
@@ -783,7 +775,7 @@ function resolveOpenAIResponsesPolicy(
|
|
|
783
775
|
disableReasoningOnToolChoice: isDeepseekFamily && reasoningCapable && !isOpenRouter,
|
|
784
776
|
disableReasoningWithTools: false,
|
|
785
777
|
supportsToolChoice: true,
|
|
786
|
-
supportsForcedToolChoice:
|
|
778
|
+
supportsForcedToolChoice: true,
|
|
787
779
|
supportsNamedToolChoice: true,
|
|
788
780
|
reasoningContentField: "reasoning_content",
|
|
789
781
|
requiresReasoningContentForToolCalls:
|
|
@@ -822,7 +814,7 @@ function resolveOpenAIResponsesPolicy(
|
|
|
822
814
|
rejectRootObjectUnion: false,
|
|
823
815
|
retryWithoutStrictOnGrammarError: false,
|
|
824
816
|
cacheControlFormat: isOpenRouter && isAnthropicModel ? "anthropic" : undefined,
|
|
825
|
-
stripDeepseekSpecialTokens:
|
|
817
|
+
stripDeepseekSpecialTokens: false,
|
|
826
818
|
streamMarkupHealingPattern: detectStreamMarkupHealing(provider, facts, baseUrl),
|
|
827
819
|
reasoningDeltasMayBeCumulative: false,
|
|
828
820
|
emptyLengthFinishIsContextError: false,
|
|
@@ -984,7 +976,8 @@ function resolveOllamaPolicy(spec: ModelSpec<"ollama-chat">, axes: ResolvedAxes)
|
|
|
984
976
|
|
|
985
977
|
function resolveDevinPolicy(spec: ModelSpec<"devin-agent">, axes: ResolvedAxes): ResolvedDevinCompat {
|
|
986
978
|
const compat: ResolvedDevinCompat = {
|
|
987
|
-
|
|
979
|
+
// Rule-owned: `on-api "devin-agent"` in providers/devin.kdl opts in.
|
|
980
|
+
trustExplicitThinkingOnly: false,
|
|
988
981
|
modelRouter: false,
|
|
989
982
|
supportsParallelToolCalls: false,
|
|
990
983
|
};
|
|
@@ -1037,7 +1030,11 @@ function readCompatEffortMap(compat: CompatOf<Api>): Partial<Record<Effort, stri
|
|
|
1037
1030
|
const map = compat.reasoningEffortMap;
|
|
1038
1031
|
return map && Object.keys(map).length > 0 ? map : undefined;
|
|
1039
1032
|
}
|
|
1040
|
-
/**
|
|
1033
|
+
/**
|
|
1034
|
+
* URL-keyed Fireworks effort remap: covers custom provider ids pointed at the
|
|
1035
|
+
* Fireworks host, which the `fireworks`/`firepass` `thinking-effort-map`
|
|
1036
|
+
* rules cannot match. Rule and configured maps override it.
|
|
1037
|
+
*/
|
|
1041
1038
|
const FIREWORKS_THINKING_EFFORT_MAP: Readonly<Partial<Record<Effort, string>>> = {
|
|
1042
1039
|
[Effort.Minimal]: "none",
|
|
1043
1040
|
};
|
|
@@ -1051,10 +1048,6 @@ function defaultThinkingMode<TApi extends Api>(spec: ModelSpec<TApi>, facts: Ide
|
|
|
1051
1048
|
// Gemini 3+ `google-level` is a `thinking-mode` rule in classes/gemini.kdl.
|
|
1052
1049
|
return "budget";
|
|
1053
1050
|
case "anthropic-messages":
|
|
1054
|
-
if (facts.is("minimax") && facts.family("m2", "m3")) return "anthropic-adaptive";
|
|
1055
|
-
if (facts.is("glm") && facts.revGte("5.2") && (spec.provider === "umans" || spec.provider === "zai")) {
|
|
1056
|
-
return "anthropic-budget-effort";
|
|
1057
|
-
}
|
|
1058
1051
|
if (facts.is("anthropic")) {
|
|
1059
1052
|
// Haiku stays on budget thinking until 5.5, its first adaptive generation.
|
|
1060
1053
|
if (facts.revGte(facts.family("haiku") ? "5.5" : "4.6")) return "anthropic-adaptive";
|
|
@@ -1201,14 +1194,6 @@ function resolveThinkingPolicy<TApi extends Api>(
|
|
|
1201
1194
|
) {
|
|
1202
1195
|
return undefined;
|
|
1203
1196
|
}
|
|
1204
|
-
if (
|
|
1205
|
-
spec.provider === "cline-pass" &&
|
|
1206
|
-
compat !== undefined &&
|
|
1207
|
-
"supportsReasoningEffort" in compat &&
|
|
1208
|
-
compat.supportsReasoningEffort === false
|
|
1209
|
-
) {
|
|
1210
|
-
return undefined;
|
|
1211
|
-
}
|
|
1212
1197
|
if (omitsWireReasoningEffort(spec.api, compat)) return undefined;
|
|
1213
1198
|
if (explicitThinking !== undefined) {
|
|
1214
1199
|
return fillExplicitThinking(spec, facts, compat, explicitThinking, rule);
|
|
@@ -221,19 +221,29 @@ One object axis carries a computed form: `long-context-cost` accepts either the
|
|
|
221
221
|
|
|
222
222
|
`context-window-authoritative #true` preserves a host's supplied context window through runtime model selection instead of applying inferred expansion or reference-price-tier caps. Explicit user context overrides still apply afterward. It applies to rows materialized through `buildModel` (discovery and regenerated bundles). See [`providers/factory-droid.kdl`](providers/factory-droid.kdl).
|
|
223
223
|
|
|
224
|
+
`long-context-window-uncapped #true` keeps a model's `long-context-cost` tier from capping its runtime context window while extended context is off: the coding agent normally lowers the window to the tier's input threshold so compaction fires before a request crosses into premium pricing. Use it where the tier is an API-equivalent estimate on a subscription host (`xai-oauth`) or where the model is served at its full window regardless (GPT-5.4, except on GitHub Copilot). `buildModel` materializes it as `Model.longContextWindowUncapped`; explicit user context overrides still apply.
|
|
225
|
+
|
|
226
|
+
`max-tokens-fallback` seeds `maxTokens` only when the row reports none, and `max-tokens-ceiling` lowers a larger reported `maxTokens` to the host's output cap (an unknown budget stays unknown unless a fallback seeded it). Both apply in `buildModel` after `limits-patch`, so discovery mappers pass upstream output budgets through verbatim. See the Kimi rules in [`providers/fireworks.kdl`](providers/fireworks.kdl).
|
|
227
|
+
|
|
224
228
|
`inline-image-byte-budget` caps retained base64 image characters for a deployment's request body. It leaves room for tool schemas and text beneath the provider's body-size limit; the coding agent reads it through `resolveInlineImageByteBudget` before sending live history, and snapcompact gives its archive frames half of it (`frameDataBytesBudget`). The budget applies only while the request reaches the official endpoint (the Anthropic API, first-party OpenAI, or the Codex backend at its default URL), which callers decide with pi-ai's `reachesOfficialEndpoint`: `compat.officialEndpoint` for the configured `baseUrl`, and for first-party Anthropic models also the `ANTHROPIC_BASE_URL` or Foundry `FOUNDRY_BASE_URL` reroute applied at request time. A custom or rerouted endpoint imposes its own body limit.
|
|
225
229
|
|
|
226
230
|
`image-count-budget` is the most images one request may carry, archive frames, screenshots and imaged tool results combined. The coding agent reads it through `resolveImageCountBudget`, drops the oldest images past it, and caps snapcompact frames at it; unassigned hosts get a floor of 5. `official-image-count-budget` replaces it while the request reaches the official endpoint (same gate as `inline-image-byte-budget`), for limits established on the host's own endpoint (Anthropic: 600, 100 on 200k-window models; Codex: 2,000); a custom or rerouted endpoint keeps `image-count-budget` (Anthropic 90, Codex 200).
|
|
227
231
|
|
|
232
|
+
`endpoint-hosts` lists the HTTPS hostnames a provider serves besides its bundled base URL's host, such as Copilot's per-plan `api.<plan>.githubcopilot.com` hosts. That host plus these define the provider's own endpoint (`isCatalogEndpointUrl`), which separates first-party traffic from a custom model or provider override that keeps a catalog provider id but points `baseUrl` at a gateway, proxy, or local server. Connection prewarming and request compression act only on the provider's own endpoint.
|
|
233
|
+
|
|
234
|
+
`request-encodings` lists the `Content-Encoding`s (`zstd`, `gzip`) a provider's own endpoint decodes on request bodies, most preferred first; pi-ai's `wrapFetchForRequestCompression` reads them through `resolveRequestCompression` and compresses bodies of 1 KiB or more. A proxy, relay, or `ANTHROPIC_BASE_URL` reroute never receives bytes it cannot read. `request-encoding-rejection` is a regular expression for the 400/415 error body the host returns when it cannot decode the body; unassigned, every 400/415 is re-checked with an uncompressed resend. A rejected encoding is dropped for that host only after the uncompressed resend succeeds. Assign them only from a live probe of every endpoint host: a compressed body, the same plain JSON mislabeled as compressed (a decoding host must reject it), and a real request.
|
|
235
|
+
|
|
228
236
|
`judgment-questions-max` is the most questions one System One judgment request may carry (razorback16/openjev: 256; Cloudflare Clef on Workers AI and through OpenRouter Decisions: 64; unidentified `*openjev*` deployments: 16). The coding agent reads it through `resolveJudgmentQuestionsMax` and `NativeJudge` splits larger requests into parallel chunks; unassigned means the endpoint takes any batch size. [`providers/judgment-questions.kdl`](providers/judgment-questions.kdl) lists the servers verified uncapped or not isolatable.
|
|
229
237
|
|
|
238
|
+
`judgment-image-input` assigns model-specific native judgment image bounds, read through `resolveJudgmentImageInput`. Its object accepts `mime-types` as a comma-separated lowercase MIME list and positive integer `max-count`, `max-bytes`, `max-total-bytes`, `min-pixels`, `max-pixels`, `min-side`, and `max-side`; byte limits count decoded data. `NativeJudge` enforces these alongside its wire's encoding constraints without resizing, and candidate filtering skips models whose bounds reject the images. Unassigned adds no model-specific bounds. The Jev selectors in [`providers/typesafe.kdl`](providers/typesafe.kdl) and [`providers/openrouter.kdl`](providers/openrouter.kdl) own Jev's limits rather than imposing them on every model using those APIs.
|
|
239
|
+
|
|
230
240
|
`prompt-cache-lookback` is how many block positions back from a cache breakpoint the model's prompt cache looks for an earlier request's entry (Claude: 20, counting the breakpoint; a run of consecutive `tool_use` or `tool_result` blocks is one position). The coding agent reads it through `resolvePromptCacheLookback` and keeps warm-cache tool-result pruning inside the window; unassigned means no known bound.
|
|
231
241
|
|
|
232
242
|
`task-sibling-prompt-cache #true` lets Task children use an automatically derived sibling cache key on the matching request model. Missing or `#false` keeps the provider's per-child default; explicit cache keys still win. The session resolves this catalog policy against the actual model for primary turns, handoff, and ephemeral requests that reuse the live context, including model changes, without sharing conversation IDs or response state. The automatic candidate is persisted separately from explicit keys and survives full forks, `/tan`, and session reopening; new and partial sessions discard it. A fork carrying an automatic candidate uses its own conversation ID on unsupported models, and re-enables the candidate when returning to an eligible model. Ordinary forks without an automatic candidate keep their existing inherited cache routing. Conventional compaction keeps its existing cache routing because its serialized summary prompt differs from the primary context. The opt-in covers Muse Code's `muse-spark-1.3`, `muse-spark-1.3-contributor`, `muse-wonder-1.0`, `muse-wonder-1.0-contributor`, `muse-wonder-full-1.0`, and `muse-wonder-full-1.0-contributor` over `openai-responses`. Meta documents shared-prefix `prompt_cache_key` routing for Responses. Warmed sibling cache reuse was measured on Spark 1.3 Contributor; the standard Spark variant shares this scope following maintainer guidance. A bounded synthetic probe observed cache reuse on all four Wonder variants; it does not establish production or latency benefits. Auxiliary-request latency has not been measured. Provider selectors also match custom providers that declare the same `providerType`; no benefit is established for custom endpoints.
|
|
233
243
|
|
|
234
244
|
`image-max-edge` is the longest image edge, in pixels, a host passes to the model; it downscales larger images to fit first (Cursor: 1024 for Claude and GPT). Snapcompact reads it through `resolveImageMaxEdge` and renders frames no wider, so their glyphs reach the model at the size they were drawn; unassigned means the host keeps the image's size.
|
|
235
245
|
|
|
236
|
-
`snapcompact-image-reads #true` opts a reader in to getting a fresh `read` result as snapcompact frames when `snapcompact.toolResults` is on. Frames
|
|
246
|
+
`snapcompact-image-reads #true` opts a reader in to getting a fresh `read` result as snapcompact frames when `snapcompact.toolResults` is on. Frames collapse whitespace, so snapcompact draws each row's leading indentation as a count bracket (`[»2]`, `[·4]`) and keeps the `[path#TAG]` header as text beside them. On 3–4 frame reads Opus 5.5 then made exact first edits from frames within one of text (38 vs 39 of 40), so Opus 5.5+ opts in ([`classes/anthropic.kdl`](classes/anthropic.kdl)); Sonnet 5.5 (37 vs 40) and Haiku 5.5 (35 vs 40) still miscounted deep tab indents. Unassigned: `read` results stay text; other tools' results are imaged either way.
|
|
237
247
|
|
|
238
248
|
The routed-subscription registry axes (`upstream-rotation`, `region-upstreams-global|us|eu`, `region-limits-eu`, `credit-rates`, `list-price-from`, `routing-family`, `policy-aliases`, `entitlement`, `default-reasoning-off`) describe a gateway whose proxy fans one model out to several upstreams. They are read through `src/compat/factory-droid.ts` by Factory Droid discovery and its request provider, not materialized by `buildModel`. A provider-wide `region-upstreams-*` rule is the upstream serving table and a model rule replaces it for that region. `list-price-from "<provider>" ["<id>"]` shows a bundled row's list price beside the subscription's own billing; unlike seed values it is resolved at runtime and degrades to the seed's zero cost when the row is gone. See [`providers/factory-droid.kdl`](providers/factory-droid.kdl), whose wire and billing pool per model are `api-routes` and `quota-tiers` rules in `runtime/behavior.kdl`.
|
|
239
249
|
|
|
@@ -325,11 +335,17 @@ behavior {
|
|
|
325
335
|
pricing-peer provider="google-antigravity" peers="google" "google-vertex" {
|
|
326
336
|
alias "gemini-3-pro" peer-id="gemini-3-pro-preview"
|
|
327
337
|
}
|
|
338
|
+
role-defaults "smol" {
|
|
339
|
+
model "claude-haiku-5-5"
|
|
340
|
+
model "openai-codex/gpt-5.3-codex-spark"
|
|
341
|
+
}
|
|
328
342
|
}
|
|
329
343
|
```
|
|
330
344
|
|
|
331
345
|
`exclude-discovery-modes` takes one or more exact, case-sensitive upstream mode strings plus `provider=`; discovery mappers preserve missing, malformed, and unknown modes unless the provider policy explicitly lists them. Matcher properties on `route` / `exclude-models` / `tier` nodes are `exact=` / `prefix=` / `substring=` / `glob=`, repeatable. `strip-prefix=#true` on a prefix route strips the matched prefix off the wire id. Values are copied verbatim from the TS constants they replaced; runtime accessors live in `src/compat/behavior.ts`.
|
|
332
346
|
|
|
347
|
+
`role-defaults "<role>"` declares one agent role's built-in default model selector chain, one `model "<selector>"` child per entry, most preferred first. Selectors are copied verbatim (`provider/id`, bare ids, fuzzy fragments such as `-mini`, and `@role` references); duplicates within a role and repeated roles are compile errors. `roleDefaultModels()` returns every chain keyed by role in declaration order.
|
|
348
|
+
|
|
333
349
|
## Auth grammar
|
|
334
350
|
|
|
335
351
|
Every provider has exactly one `auth "<id>" { … }` node under `auth/`; `auth/_order.kdl` holds a single `login-order "id" …` node pinning the `/login` roster order (every provider with a `login` and `show-in-login-list` unset/true must appear; providers without a login sort alphabetically after it). Runtime accessors live in `src/compat/auth.ts`; the id unions in the generated `src/compat/auth-ids.ts`. Every provider in `provider-models/descriptors.ts` needs an auth node (`@oh-my-pi/pi-ai` type-checks this).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
auth "google-antigravity" {
|
|
2
|
-
name "Antigravity (Gemini
|
|
2
|
+
name "Google Antigravity (Gemini, Claude, GPT-OSS)"
|
|
3
3
|
login "oauth-code" {
|
|
4
4
|
// Antigravity uses different Google OAuth credentials for its additional models.
|
|
5
5
|
client-id "MTA3MTAwNjA2MDU5MS10bWhzc2luMmgyMWxjcmUyMzV2dG9sb2poNGc0MDNlcC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbQ==" encoding="base64"
|
|
@@ -120,9 +120,8 @@ class "anthropic" {
|
|
|
120
120
|
supports-sampling-params #false
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
|
-
// Opus 5.5
|
|
124
|
-
//
|
|
125
|
-
// (22/54), so other lines keep `read` as text until measured.
|
|
123
|
+
// Opus 5.5 edits from imaged `read` results within one miss of text; Sonnet
|
|
124
|
+
// and Haiku 5.5 miscount deep tab indents (measurements: rules/README.md).
|
|
126
125
|
family "opus" {
|
|
127
126
|
revision ">=5.5 <10" {
|
|
128
127
|
snapcompact-image-reads #true
|
|
@@ -59,6 +59,10 @@ class "deepseek" {
|
|
|
59
59
|
on "alibaba-token-plan" "deepseek" {
|
|
60
60
|
supports-developer-role #false
|
|
61
61
|
}
|
|
62
|
+
// Replaces the provider-keyed leaked chat-template special-token strip.
|
|
63
|
+
on "nvidia" "deepseek" {
|
|
64
|
+
strip-deepseek-special-tokens #true
|
|
65
|
+
}
|
|
62
66
|
on "deepseek" "opencode-go" {
|
|
63
67
|
family "pro" {
|
|
64
68
|
max-tokens-field "max_tokens"
|
|
@@ -7,6 +7,16 @@ class "minimax" {
|
|
|
7
7
|
}
|
|
8
8
|
// Replaces the MiniMax lineage branch in both OpenAI baselines.
|
|
9
9
|
reasoning-deltas-may-be-cumulative #true
|
|
10
|
+
// Replaces the identity default: M2/M3 thinking rides Anthropic adaptive
|
|
11
|
+
// thinking on every Messages route, custom provider ids included.
|
|
12
|
+
on-api "anthropic-messages" {
|
|
13
|
+
family "m2" {
|
|
14
|
+
thinking-mode "anthropic-adaptive"
|
|
15
|
+
}
|
|
16
|
+
family "m3" {
|
|
17
|
+
thinking-mode "anthropic-adaptive"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
10
20
|
on "aimlapi" "coreweave" "fireworks" "huggingface" "kilo" "nanogpt" "novita" "nvidia" \
|
|
11
21
|
"opencode-go" "opencode-zen" "together" "venice" "wafer-serverless" "zenmux" {
|
|
12
22
|
family "m3" {
|
|
@@ -11,6 +11,14 @@ class "openai" {
|
|
|
11
11
|
revision ">=5" {
|
|
12
12
|
supports-sampling-params #false
|
|
13
13
|
}
|
|
14
|
+
// GPT-5.4 serves its 1M window, and its long-context price tier does not
|
|
15
|
+
// cap that window. GitHub Copilot keeps its own cap (github-copilot.kdl).
|
|
16
|
+
models "gpt-5.4" {
|
|
17
|
+
limits-patch {
|
|
18
|
+
context-window 1000000
|
|
19
|
+
}
|
|
20
|
+
long-context-window-uncapped #true
|
|
21
|
+
}
|
|
14
22
|
// GPT wire ladders are model generations, not host contracts: <5.2 keeps
|
|
15
23
|
// the classic four-tier scale, 5.2+ drops minimal for xhigh, and 5.6+
|
|
16
24
|
// exposes the wire-exact five-tier low..max scale.
|
|
@@ -92,6 +92,10 @@ provider "anthropic" {
|
|
|
92
92
|
// https://platform.claude.com/docs/en/build-with-claude/vision
|
|
93
93
|
image-count-budget 90
|
|
94
94
|
official-image-count-budget 600
|
|
95
|
+
// The Messages API decodes gzip request bodies and rejects zstd and br
|
|
96
|
+
// with a 400 (`request_body_encoding_invalid`).
|
|
97
|
+
request-encodings "gzip"
|
|
98
|
+
request-encoding-rejection "request_body_encoding_invalid|Unsupported Content-Encoding"
|
|
95
99
|
class "anthropic" {
|
|
96
100
|
revision "<4.6" {
|
|
97
101
|
official-image-count-budget 100
|
|
@@ -10,6 +10,9 @@ provider "cerebras" {
|
|
|
10
10
|
// Replaces the Cerebras provider branches in the completions baseline.
|
|
11
11
|
supports-usage-in-streaming #false
|
|
12
12
|
tool-strict-mode "all_strict"
|
|
13
|
+
// Replaces the provider check in agent-loop history normalization: replayed
|
|
14
|
+
// assistant history drops its thinking blocks.
|
|
15
|
+
strip-thinking-history #true
|
|
13
16
|
// Prompt caching carries no discount: cached input tokens bill at the
|
|
14
17
|
// standard input rate (https://inference-docs.cerebras.ai/capabilities/prompt-caching).
|
|
15
18
|
cache-read-at-input-rate #true
|
|
@@ -10,4 +10,20 @@ provider "cline-pass" {
|
|
|
10
10
|
wire-model-id-mode "cline-pass"
|
|
11
11
|
// Replaces the Cline Pass thinking-format branch.
|
|
12
12
|
thinking-format "openai"
|
|
13
|
+
// Replaces the Cline Pass completions baseline branches: the reasoning
|
|
14
|
+
// field, the disable shape, and reasoning kept on under tool choice.
|
|
15
|
+
reasoning-content-field "reasoning"
|
|
16
|
+
reasoning-disable-mode "cline-enabled-false"
|
|
17
|
+
disable-reasoning-on-forced-tool-choice #false
|
|
18
|
+
disable-reasoning-on-tool-choice #false
|
|
19
|
+
// Discovery reports each row's thinking ladder; a row without one
|
|
20
|
+
// (`supportsReasoningEffort: false`) has no reasoning control at all.
|
|
21
|
+
trust-explicit-thinking-only #true
|
|
22
|
+
class "qwen" {
|
|
23
|
+
supports-forced-tool-choice #false
|
|
24
|
+
cache-control-format "anthropic"
|
|
25
|
+
}
|
|
26
|
+
class "anthropic" {
|
|
27
|
+
cache-control-format "anthropic"
|
|
28
|
+
}
|
|
13
29
|
}
|
|
@@ -337,6 +337,16 @@ provider "commandcode" {
|
|
|
337
337
|
cache-write 0.0
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
|
+
// Restate the 64K provider output cap beside the openai class's GPT-5.4
|
|
341
|
+
// window patch, or the class rule wins the whole limits axis.
|
|
342
|
+
class "openai" {
|
|
343
|
+
models "gpt-5.4" {
|
|
344
|
+
limits-patch {
|
|
345
|
+
context-window 1000000
|
|
346
|
+
max-tokens 65536
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
340
350
|
models "gpt-5.3-codex" {
|
|
341
351
|
cost-patch {
|
|
342
352
|
input 2.0
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Catalog entry for "deepinfra"
|
|
1
|
+
// Catalog entry for "deepinfra".
|
|
2
2
|
|
|
3
3
|
provider "deepinfra" {
|
|
4
4
|
default-model "deepseek-ai/DeepSeek-V4-Flash-0731"
|
|
@@ -9,6 +9,8 @@ provider "deepinfra" {
|
|
|
9
9
|
image "openai-images"
|
|
10
10
|
tts "openai-speech"
|
|
11
11
|
}
|
|
12
|
+
// Same-provider image-generation swap target for chat models.
|
|
13
|
+
image-model "black-forest-labs/FLUX-2-pro"
|
|
12
14
|
|
|
13
15
|
seed base-url="https://api.deepinfra.com/v1/openai" bundle="always" {
|
|
14
16
|
model "black-forest-labs/FLUX-2-pro" name="FLUX.2 Pro" api="openai-images" {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Catalog entry for "devin"
|
|
1
|
+
// Catalog entry and deployment contract for "devin".
|
|
2
2
|
|
|
3
3
|
provider "devin" {
|
|
4
4
|
default-model "swe-1-6"
|
|
@@ -191,3 +191,9 @@ provider "devin" {
|
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
|
+
|
|
195
|
+
// Devin's Cascade catalog reports each model's thinking surface; a row
|
|
196
|
+
// without one carries no reasoning ladder.
|
|
197
|
+
on-api "devin-agent" {
|
|
198
|
+
trust-explicit-thinking-only #true
|
|
199
|
+
}
|
|
@@ -691,6 +691,12 @@ provider "factory-droid" {
|
|
|
691
691
|
thinking-requires-effort #true
|
|
692
692
|
thinking-default-level "medium"
|
|
693
693
|
}
|
|
694
|
+
// The native 922K window is authoritative; the class-wide gpt-5.4 1M patch does not apply.
|
|
695
|
+
class "openai" {
|
|
696
|
+
models "gpt-5.4" {
|
|
697
|
+
limits-patch {}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
694
700
|
models "gpt-5.4-fast" {
|
|
695
701
|
routing-family "openai"
|
|
696
702
|
upstream-rotation "openai" "azure_openai"
|
|
@@ -38,4 +38,19 @@ provider "firepass" {
|
|
|
38
38
|
thinking-mode "effort"
|
|
39
39
|
thinking-efforts "low" "high" "max"
|
|
40
40
|
}
|
|
41
|
+
// The Fire Pass router shares Fireworks' 32,768 Kimi K2 output cap (#1849).
|
|
42
|
+
class "kimi" {
|
|
43
|
+
family "k2" {
|
|
44
|
+
max-tokens-ceiling 32768
|
|
45
|
+
}
|
|
46
|
+
family "k2.5" {
|
|
47
|
+
max-tokens-ceiling 32768
|
|
48
|
+
}
|
|
49
|
+
family "k2.6" {
|
|
50
|
+
max-tokens-ceiling 32768
|
|
51
|
+
}
|
|
52
|
+
family "k2-thinking" {
|
|
53
|
+
max-tokens-ceiling 32768
|
|
54
|
+
}
|
|
55
|
+
}
|
|
41
56
|
}
|
|
@@ -24,6 +24,32 @@ provider "fireworks" priority=-1 {
|
|
|
24
24
|
class "unknown" {
|
|
25
25
|
thinking-efforts "minimal" "low" "medium" "high" "xhigh"
|
|
26
26
|
}
|
|
27
|
+
// Replaces the Fireworks Kimi output caps in provider-models/openai-compat.ts
|
|
28
|
+
// (#1849). The K2 family ships long reasoning traces Fireworks bounds at
|
|
29
|
+
// 32,768 output tokens; the control plane reports no output budget, so the
|
|
30
|
+
// cap is also the fallback. K2.7-Code serves its full 65,536 (verified with
|
|
31
|
+
// a 58,971-token completion), which seeds rows that report none.
|
|
32
|
+
class "kimi" {
|
|
33
|
+
family "k2" {
|
|
34
|
+
max-tokens-fallback 32768
|
|
35
|
+
max-tokens-ceiling 32768
|
|
36
|
+
}
|
|
37
|
+
family "k2.5" {
|
|
38
|
+
max-tokens-fallback 32768
|
|
39
|
+
max-tokens-ceiling 32768
|
|
40
|
+
}
|
|
41
|
+
family "k2.6" {
|
|
42
|
+
max-tokens-fallback 32768
|
|
43
|
+
max-tokens-ceiling 32768
|
|
44
|
+
}
|
|
45
|
+
family "k2-thinking" {
|
|
46
|
+
max-tokens-fallback 32768
|
|
47
|
+
max-tokens-ceiling 32768
|
|
48
|
+
}
|
|
49
|
+
family "k2.7-code" {
|
|
50
|
+
max-tokens-fallback 65536
|
|
51
|
+
}
|
|
52
|
+
}
|
|
27
53
|
// residue: taxonomy ranks and exact globs do not isolate these models.
|
|
28
54
|
models "deepseek-v4-flash" {
|
|
29
55
|
requires-reasoning-content-for-all-assistant-turns #true
|
|
@@ -14,6 +14,30 @@ provider "github-copilot" {
|
|
|
14
14
|
// not belong to this connection`: a resumed session rebuilds prior turns
|
|
15
15
|
// until its first response.
|
|
16
16
|
connection-bound-native-history #true
|
|
17
|
+
// Per-plan API hosts the Copilot token resolves to; the bundled base URL
|
|
18
|
+
// is `api.githubcopilot.com`.
|
|
19
|
+
endpoint-hosts "api.individual.githubcopilot.com" "api.business.githubcopilot.com" \
|
|
20
|
+
"api.enterprise.githubcopilot.com"
|
|
21
|
+
// `/chat/completions`, `/responses` and `/v1/messages` decode zstd, br and
|
|
22
|
+
// gzip request bodies (deflate is rejected), probed live 2026-10. GHE.com
|
|
23
|
+
// tenants (`copilot-api.<tenant>.ghe.com`) are unverified and stay plain.
|
|
24
|
+
request-encodings "zstd" "gzip"
|
|
25
|
+
request-encoding-rejection "invalid_request_body|[Ff]ailed to (?:parse|read) request"
|
|
26
|
+
// Replaces the provider-keyed strict Responses tool-call/result pairing.
|
|
27
|
+
strict-responses-pairing #true
|
|
28
|
+
// Replaces the provider check that disabled reasoning params on chat completions.
|
|
29
|
+
on-api "openai-completions" {
|
|
30
|
+
supports-reasoning-params #false
|
|
31
|
+
}
|
|
32
|
+
// Copilot caps GPT-5.4 below the lineage's 1M window (model-limits in
|
|
33
|
+
// runtime/behavior.kdl), so the class-wide window patch and uncapped
|
|
34
|
+
// window do not apply here.
|
|
35
|
+
class "openai" {
|
|
36
|
+
models "gpt-5.4" {
|
|
37
|
+
limits-patch {}
|
|
38
|
+
long-context-window-uncapped #false
|
|
39
|
+
}
|
|
40
|
+
}
|
|
17
41
|
class "anthropic" {
|
|
18
42
|
revision ">=4 <4.6" {
|
|
19
43
|
thinking-efforts "minimal" "low" "medium" "high" "xhigh"
|
|
@@ -41,6 +41,17 @@ provider "google-antigravity" {
|
|
|
41
41
|
// any image edge over 3,000 px. The clamp above caps each image; with no
|
|
42
42
|
// byte budget on this wire, the count bounds the body.
|
|
43
43
|
image-count-budget 20
|
|
44
|
+
// Cache-warmer lifetime. Claude here is Vertex Anthropic, whose prompt
|
|
45
|
+
// cache has a five-minute default TTL refreshed on every hit; this wire
|
|
46
|
+
// sends no `cache_control`, so the 1h tier is never requested.
|
|
47
|
+
// https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/partner-models/claude/prompt-caching
|
|
48
|
+
// Gemini declares none: its implicit cache keeps entries for a
|
|
49
|
+
// load-dependent time ("caches always deleted within 24 hours"), so no
|
|
50
|
+
// fixed lifetime exists to warm against.
|
|
51
|
+
// https://cloud.google.com/blog/products/ai-machine-learning/vertex-ai-context-caching
|
|
52
|
+
prompt-cache {
|
|
53
|
+
short 300
|
|
54
|
+
}
|
|
44
55
|
family "opus" {
|
|
45
56
|
thinking-mode "budget"
|
|
46
57
|
}
|
|
@@ -6,6 +6,8 @@ provider "moonshot" {
|
|
|
6
6
|
// as a fallback so China users need not learn MOONSHOT_API_KEY. (#2883)
|
|
7
7
|
env "MOONSHOT_API_KEY" "KIMI_API_KEY"
|
|
8
8
|
discovery label="Moonshot"
|
|
9
|
+
// Moonshot's China platform, selected with MOONSHOT_BASE_URL (#2883).
|
|
10
|
+
endpoint-hosts "api.moonshot.cn"
|
|
9
11
|
|
|
10
12
|
class "kimi" {
|
|
11
13
|
// Replaces the Moonshot Kimi thinking-format branch.
|
|
@@ -10,6 +10,9 @@ provider "ollama-cloud" {
|
|
|
10
10
|
thinking-mode "effort"
|
|
11
11
|
// Same runtime as local Ollama: a trailing assistant turn is continued verbatim.
|
|
12
12
|
supports-assistant-prefill #true
|
|
13
|
+
// Replaces the provider checks in model-registry.ts and the generator:
|
|
14
|
+
// never send a caller output limit.
|
|
15
|
+
omit-max-output-tokens #true
|
|
13
16
|
class "unknown" {
|
|
14
17
|
thinking-efforts "minimal" "low" "medium" "high"
|
|
15
18
|
}
|
|
@@ -21,6 +21,9 @@ provider "openai-codex" {
|
|
|
21
21
|
inline-image-byte-budget 24000000
|
|
22
22
|
image-count-budget 200
|
|
23
23
|
official-image-count-budget 2000
|
|
24
|
+
// The backend decodes zstd request bodies, as the official client sends.
|
|
25
|
+
// Its rejection body is undocumented, so any 400/415 re-checks uncompressed.
|
|
26
|
+
request-encodings "zstd"
|
|
24
27
|
|
|
25
28
|
seed api="openai-codex-responses" base-url="https://chatgpt.com/backend-api" bundle="always" {
|
|
26
29
|
// Label only: the Codex backend ignores `tool.model` and runs gpt-image-2-codex.
|
|
@@ -224,3 +227,9 @@ provider "openai-codex" {
|
|
|
224
227
|
context-window-floor 1000000
|
|
225
228
|
}
|
|
226
229
|
}
|
|
230
|
+
|
|
231
|
+
// The Codex backend rejects every sampling control (`temperature`, `top_p`,
|
|
232
|
+
// penalties, stop sequences), whichever model it serves (#3117).
|
|
233
|
+
on-api "openai-codex-responses" {
|
|
234
|
+
supports-sampling-params #false
|
|
235
|
+
}
|
|
@@ -4,6 +4,10 @@ provider "opencode-go" {
|
|
|
4
4
|
default-model "kimi-k2.7-code"
|
|
5
5
|
env "OPENCODE_API_KEY"
|
|
6
6
|
dynamic-models-authoritative #true
|
|
7
|
+
// Replaces the provider check that disabled forced tool choice on Responses.
|
|
8
|
+
on-api "openai-responses" {
|
|
9
|
+
supports-forced-tool-choice #false
|
|
10
|
+
}
|
|
7
11
|
|
|
8
12
|
// The Flash lanes accept images despite their IDs lacking a vision suffix;
|
|
9
13
|
// verified against the gateway (unguessable pixel-rendered text read back
|
|
@@ -4,6 +4,10 @@ provider "opencode-zen" {
|
|
|
4
4
|
default-model "claude-opus-5"
|
|
5
5
|
env "OPENCODE_API_KEY"
|
|
6
6
|
dynamic-models-authoritative #true
|
|
7
|
+
// Replaces the provider check that disabled forced tool choice on Responses.
|
|
8
|
+
on-api "openai-responses" {
|
|
9
|
+
supports-forced-tool-choice #false
|
|
10
|
+
}
|
|
7
11
|
|
|
8
12
|
// Replaces the OpenCode reasoning-model whenThinking fallback object.
|
|
9
13
|
// Applies to every completions-routed reasoning model, discovered ids
|