@linxiraos/pi-catalog 1.1.27 → 1.2.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.
Files changed (100) hide show
  1. package/CHANGELOG.md +4 -17
  2. package/dist/types/compat/auth-ids.d.ts +2 -2
  3. package/dist/types/compat/judgment-questions.d.ts +7 -0
  4. package/dist/types/compat/prompt-cache-lookback.d.ts +7 -0
  5. package/dist/types/compat/provider-ids.d.ts +1 -1
  6. package/dist/types/compat/reasoning-carry.d.ts +21 -0
  7. package/dist/types/compat/request-size.d.ts +7 -0
  8. package/dist/types/compat/taxonomy.d.ts +0 -10
  9. package/dist/types/compat/types.d.ts +4 -0
  10. package/dist/types/discovery/antigravity.d.ts +13 -3
  11. package/dist/types/model-manager.d.ts +16 -0
  12. package/dist/types/provider-models/account-access.d.ts +11 -0
  13. package/dist/types/provider-models/google.d.ts +23 -1
  14. package/dist/types/provider-models/openai-compat.d.ts +19 -1
  15. package/dist/types/provider-models/special.d.ts +2 -0
  16. package/dist/types/types.d.ts +106 -20
  17. package/dist/types/wire/cloudflare-ai-gateway.d.ts +0 -10
  18. package/dist/types/wire/cloudflare.d.ts +10 -0
  19. package/dist/types/wire/factory-droid.d.ts +1 -1
  20. package/package.json +4 -4
  21. package/src/build.ts +39 -35
  22. package/src/compat/auth-ids.ts +4 -0
  23. package/src/compat/axes.ts +37 -3
  24. package/src/compat/cascade.ts +6 -1
  25. package/src/compat/judgment-questions.ts +12 -0
  26. package/src/compat/prompt-cache-lookback.ts +23 -0
  27. package/src/compat/provider-ids.d.ts +1 -1
  28. package/src/compat/provider-ids.ts +2 -0
  29. package/src/compat/reasoning-carry.ts +64 -0
  30. package/src/compat/request-size.ts +25 -0
  31. package/src/compat/resolve.ts +16 -2
  32. package/src/compat/rules/README.md +12 -2
  33. package/src/compat/rules/auth/_order.kdl +2 -2
  34. package/src/compat/rules/auth/cloudflare-workers-ai.kdl +9 -0
  35. package/src/compat/rules/auth/coralbricks.kdl +13 -0
  36. package/src/compat/rules/auth/minimax-code-cn.kdl +1 -1
  37. package/src/compat/rules/auth/minimax-code.kdl +1 -1
  38. package/src/compat/rules/auth/openai-codex.kdl +1 -1
  39. package/src/compat/rules/auth/stencil.kdl +1 -1
  40. package/src/compat/rules/classes/anthropic.kdl +87 -1
  41. package/src/compat/rules/classes/deepseek.kdl +6 -0
  42. package/src/compat/rules/classes/glm.kdl +16 -7
  43. package/src/compat/rules/classes/kimi.kdl +8 -0
  44. package/src/compat/rules/classes/minimax.kdl +31 -1
  45. package/src/compat/rules/classes/openai.kdl +5 -3
  46. package/src/compat/rules/classes/qwen.kdl +2 -1
  47. package/src/compat/rules/providers/abliteration.kdl +7 -0
  48. package/src/compat/rules/providers/anthropic.kdl +13 -0
  49. package/src/compat/rules/providers/apple.kdl +1 -0
  50. package/src/compat/rules/providers/cloudflare-workers-ai.kdl +34 -0
  51. package/src/compat/rules/providers/coralbricks.kdl +62 -0
  52. package/src/compat/rules/providers/cursor.kdl +22 -0
  53. package/src/compat/rules/providers/devin.kdl +2 -2
  54. package/src/compat/rules/providers/factory-droid.kdl +77 -13
  55. package/src/compat/rules/providers/github-copilot.kdl +29 -0
  56. package/src/compat/rules/providers/groq.kdl +21 -0
  57. package/src/compat/rules/providers/judgment-questions.kdl +53 -0
  58. package/src/compat/rules/providers/litellm.kdl +4 -1
  59. package/src/compat/rules/providers/minimax-code-cn.kdl +10 -5
  60. package/src/compat/rules/providers/minimax-code.kdl +10 -5
  61. package/src/compat/rules/providers/mistral.kdl +25 -1
  62. package/src/compat/rules/providers/moonshot.kdl +11 -0
  63. package/src/compat/rules/providers/openai-codex.kdl +17 -13
  64. package/src/compat/rules/providers/openai.kdl +22 -0
  65. package/src/compat/rules/providers/opencode-zen.kdl +20 -0
  66. package/src/compat/rules/providers/openrouter.kdl +6 -0
  67. package/src/compat/rules/providers/zhipu-coding-plan.kdl +10 -0
  68. package/src/compat/rules/runtime/behavior.kdl +7 -4
  69. package/src/compat/rules/taxonomy/_collapse.kdl +18 -0
  70. package/src/compat/rules.json +1 -1
  71. package/src/compat/taxonomy.d.ts +0 -10
  72. package/src/compat/taxonomy.ts +3 -3
  73. package/src/compat/types.d.ts +4 -0
  74. package/src/compat/types.ts +4 -0
  75. package/src/discovery/antigravity.d.ts +13 -3
  76. package/src/discovery/antigravity.ts +33 -17
  77. package/src/discovery/cursor.ts +2 -1
  78. package/src/discovery/devin.ts +20 -2
  79. package/src/model-cache.ts +113 -47
  80. package/src/model-manager.d.ts +16 -0
  81. package/src/model-manager.ts +107 -41
  82. package/src/model-tokenizer.ts +3 -0
  83. package/src/models.json +1 -1
  84. package/src/provider-models/account-access.d.ts +11 -0
  85. package/src/provider-models/account-access.ts +30 -0
  86. package/src/provider-models/cache-provider-id.ts +3 -2
  87. package/src/provider-models/descriptors.ts +4 -0
  88. package/src/provider-models/google.d.ts +23 -1
  89. package/src/provider-models/google.ts +70 -14
  90. package/src/provider-models/openai-compat.d.ts +19 -1
  91. package/src/provider-models/openai-compat.ts +215 -31
  92. package/src/provider-models/special.d.ts +2 -0
  93. package/src/provider-models/special.ts +15 -18
  94. package/src/types.d.ts +106 -20
  95. package/src/types.ts +149 -17
  96. package/src/wire/cloudflare-ai-gateway.d.ts +0 -10
  97. package/src/wire/cloudflare-ai-gateway.ts +0 -36
  98. package/src/wire/cloudflare.ts +40 -0
  99. package/src/wire/factory-droid.d.ts +1 -1
  100. package/src/wire/factory-droid.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linxiraos/pi-catalog",
3
- "version": "1.1.27",
3
+ "version": "1.2.0",
4
4
  "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
5
5
  "keywords": [
6
6
  "ai",
@@ -90,12 +90,12 @@
90
90
  "gen:proto": "bun scripts/generate-protocols.ts"
91
91
  },
92
92
  "dependencies": {
93
- "@linxiraos/pi-omptype": "1.1.27",
94
- "@linxiraos/pi-utils": "1.1.27"
93
+ "@linxiraos/pi-omptype": "1.2.0",
94
+ "@linxiraos/pi-utils": "1.2.0"
95
95
  },
96
96
  "devDependencies": {
97
97
  "@bgotink/kdl": "0.4.0",
98
- "@linxiraos/pi-ai": "1.1.27",
98
+ "@linxiraos/pi-ai": "1.2.0",
99
99
  "@types/bun": "^1.3.14"
100
100
  },
101
101
  "engines": {
package/src/build.ts CHANGED
@@ -101,9 +101,11 @@ function applyCatalogAssignments<TApi extends Api>(model: Model<TApi>, catalog:
101
101
  if (serviceTierCost !== undefined) {
102
102
  const flex = numberField(serviceTierCost, "flex");
103
103
  const priorityTier = numberField(serviceTierCost, "priority");
104
+ const ultrafast = numberField(serviceTierCost, "ultrafast");
104
105
  model.serviceTierCost = {
105
106
  ...(flex !== undefined && { flex }),
106
107
  ...(priorityTier !== undefined && { priority: priorityTier }),
108
+ ...(ultrafast !== undefined && { ultrafast }),
107
109
  };
108
110
  }
109
111
  const priority = catalog.priority;
@@ -174,40 +176,6 @@ export function applyCatalogCorrections(
174
176
  model: Pick<ModelSpec<Api>, "cost" | "contextWindow" | "maxTokens" | "input">,
175
177
  catalog: Record<string, unknown>,
176
178
  ): void {
177
- const longContext = objectPayload(catalog.longContext);
178
- if (longContext !== undefined) {
179
- const inputThreshold = numberField(longContext, "inputThreshold");
180
- const inclusive = Reflect.get(longContext, "inputThresholdInclusive") === true;
181
- const multiplier = numberField(longContext, "multiplier");
182
- const input = numberField(longContext, "input");
183
- const output = numberField(longContext, "output");
184
- const cacheRead = numberField(longContext, "cacheRead");
185
- const cacheWrite = numberField(longContext, "cacheWrite");
186
- const base = model.cost;
187
- const hasTokenPrice = base.input !== 0 || base.output !== 0 || base.cacheRead !== 0 || base.cacheWrite !== 0;
188
- if (inputThreshold !== undefined && multiplier !== undefined && hasTokenPrice) {
189
- // Multiplier form: tier rates derive from the row's live list price.
190
- model.cost = {
191
- ...base,
192
- longContext: {
193
- inputThreshold,
194
- ...(inclusive && { inputThresholdInclusive: true }),
195
- input: base.input * multiplier,
196
- output: base.output * multiplier,
197
- cacheRead: base.cacheRead * multiplier,
198
- cacheWrite: base.cacheWrite * multiplier,
199
- },
200
- };
201
- } else if (
202
- inputThreshold !== undefined &&
203
- input !== undefined &&
204
- output !== undefined &&
205
- cacheRead !== undefined &&
206
- cacheWrite !== undefined
207
- ) {
208
- model.cost = { ...model.cost, longContext: { inputThreshold, input, output, cacheRead, cacheWrite } };
209
- }
210
- }
211
179
  const patch = objectPayload(catalog.costPatch);
212
180
  if (patch !== undefined) {
213
181
  model.cost = { ...model.cost };
@@ -244,6 +212,41 @@ export function applyCatalogCorrections(
244
212
  applyEffectiveFallbackRates(model.cost, Reflect.get(fallback, "effectiveRates"));
245
213
  }
246
214
  }
215
+ const longContext = objectPayload(catalog.longContext);
216
+ if (longContext !== undefined) {
217
+ const inputThreshold = numberField(longContext, "inputThreshold");
218
+ const inclusive = Reflect.get(longContext, "inputThresholdInclusive") === true;
219
+ const multiplier = numberField(longContext, "multiplier");
220
+ const input = numberField(longContext, "input");
221
+ const output = numberField(longContext, "output");
222
+ const cacheRead = numberField(longContext, "cacheRead");
223
+ const cacheWrite = numberField(longContext, "cacheWrite");
224
+ const base = model.cost;
225
+ const hasTokenPrice = base.input !== 0 || base.output !== 0 || base.cacheRead !== 0 || base.cacheWrite !== 0;
226
+ if (inputThreshold !== undefined && multiplier !== undefined && hasTokenPrice) {
227
+ // Multiplier form: tier rates derive from the row's final base card,
228
+ // after `cost-patch`/`cost-fallback` corrected the live list price.
229
+ model.cost = {
230
+ ...base,
231
+ longContext: {
232
+ inputThreshold,
233
+ ...(inclusive && { inputThresholdInclusive: true }),
234
+ input: base.input * multiplier,
235
+ output: base.output * multiplier,
236
+ cacheRead: base.cacheRead * multiplier,
237
+ cacheWrite: base.cacheWrite * multiplier,
238
+ },
239
+ };
240
+ } else if (
241
+ inputThreshold !== undefined &&
242
+ input !== undefined &&
243
+ output !== undefined &&
244
+ cacheRead !== undefined &&
245
+ cacheWrite !== undefined
246
+ ) {
247
+ model.cost = { ...model.cost, longContext: { inputThreshold, input, output, cacheRead, cacheWrite } };
248
+ }
249
+ }
247
250
  if (catalog.cacheReadAtInputRate === true) {
248
251
  const { longContext } = model.cost;
249
252
  model.cost = {
@@ -363,7 +366,8 @@ export function buildModel<TApi extends Api>(spec: ModelSpec<TApi>): Model<TApi>
363
366
  };
364
367
  applyCatalogAssignments(model, policy.catalog);
365
368
  applyCatalogCorrections(model, policy.catalog);
366
- // Configured lifetimes replace catalog lifetimes rather than merging with them.
369
+ // Configured kinds and lifetimes replace catalog values rather than merging with them.
370
+ if (spec.kindConfig !== undefined) model.kind = spec.kindConfig;
367
371
  if (spec.promptCacheConfig !== undefined) model.promptCache = { ...spec.promptCacheConfig };
368
372
  return model;
369
373
  }
@@ -17,7 +17,9 @@ export type AuthProviderId =
17
17
  | "charm-hyper"
18
18
  | "cline-pass"
19
19
  | "cloudflare-ai-gateway"
20
+ | "cloudflare-workers-ai"
20
21
  | "commandcode"
22
+ | "coralbricks"
21
23
  | "coreweave"
22
24
  | "cursor"
23
25
  | "deepinfra"
@@ -109,7 +111,9 @@ export type LoginProviderId =
109
111
  | "charm-hyper"
110
112
  | "cline-pass"
111
113
  | "cloudflare-ai-gateway"
114
+ | "cloudflare-workers-ai"
112
115
  | "commandcode"
116
+ | "coralbricks"
113
117
  | "coreweave"
114
118
  | "cursor"
115
119
  | "deepinfra"
@@ -140,6 +140,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
140
140
  "qwen-preserve-thinking": wire("qwenPreserveThinking", ["openai"]),
141
141
  "reject-root-object-union": wire("rejectRootObjectUnion", OAI),
142
142
  "retry-without-strict-on-grammar-error": wire("retryWithoutStrictOnGrammarError", OAI),
143
+ "session-header": wire("sessionHeader", OAI, "scalar", ["x-litellm-session-id"]),
143
144
  "reasoning-content-field": wire("reasoningContentField", OAI, "scalar", [
144
145
  "reasoning_content",
145
146
  "reasoning",
@@ -169,6 +170,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
169
170
  "requires-thinking-as-text": wire("requiresThinkingAsText", ["openai"]),
170
171
  "requires-tool-result-name": wire("requiresToolResultName", ["openai"]),
171
172
  "strict-responses-pairing": wire("strictResponsesPairing", ["openai-responses"]),
173
+ "connection-bound-native-history": wire("connectionBoundNativeHistory", ["openai-responses"]),
172
174
  "stateful-responses": wire("statefulResponses", ["openai-responses"]),
173
175
  "requires-reasoning-off-juice-instruction": wire("requiresReasoningOffJuiceInstruction", ["openai-responses"]),
174
176
  "supports-all-turns-reasoning-context": wire("supportsAllTurnsReasoningContext", ["openai-responses"]),
@@ -229,12 +231,20 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
229
231
  "allow-anthropic-header-overrides": wire("allowAnthropicHeaderOverrides", ["anthropic"]),
230
232
  "disable-adaptive-thinking": wire("disableAdaptiveThinking", ["anthropic"]),
231
233
  "disable-strict-tools": wire("disableStrictTools", ["anthropic"]),
232
- "disabled-thinking": wire("disabledThinking", ["anthropic"], "scalar", ["omit", "disabled", "adaptive"]),
234
+ "between-tools-effort": wire("betweenToolsEffort", ["anthropic"], "scalar", ["low", "medium", "high"]),
235
+ "disabled-thinking": wire("disabledThinking", ["anthropic", "bedrock"], "scalar", [
236
+ "omit",
237
+ "disabled",
238
+ "adaptive",
239
+ "between-tools",
240
+ ]),
233
241
  "effort-beta": wire("effortBeta", ["anthropic"]),
234
242
  "escape-builtin-tool-names": wire("escapeBuiltinToolNames", ["anthropic"]),
235
243
  "fast-mode": wire("fastMode", ["anthropic"]),
236
244
  "first-party-provider": wire("firstPartyProvider", ["anthropic"]),
237
245
  "inject-claude-code-instruction": wire("injectClaudeCodeInstruction", ["anthropic"]),
246
+ "max-image-dimension": wire("maxImageDimension", ["anthropic"]),
247
+ "max-image-payload-bytes": wire("maxImagePayloadBytes", ["anthropic"]),
238
248
  "official-endpoint": wire("officialEndpoint", ["anthropic", "openai-responses"]),
239
249
  "replay-unsigned-thinking": wire("replayUnsignedThinking", ["anthropic"]),
240
250
  "requires-thinking-enabled": wire("requiresThinkingEnabled", ["anthropic"]),
@@ -250,7 +260,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
250
260
  "supports-per-message-effort": wire("supportsPerMessageEffort", ["anthropic"]),
251
261
  "supports-server-compaction": wire("supportsServerCompaction", ["anthropic"]),
252
262
  "supports-between-tools-thinking": wire("supportsBetweenToolsThinking", ["anthropic"]),
253
- "supports-thinking-binding-controls": wire("supportsThinkingBindingControls", ["anthropic"]),
263
+ "supports-thinking-binding-controls": wire("supportsThinkingBindingControls", ["anthropic", "bedrock"]),
254
264
  "supports-turn-scoped-system": wire("supportsTurnScopedSystem", ["anthropic"]),
255
265
 
256
266
  // ── wire: bedrock-converse-stream ──
@@ -261,7 +271,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
261
271
  // ── wire: devin-agent ──
262
272
  "model-router": wire("modelRouter", ["devin"]),
263
273
  "supports-parallel-tool-calls": wire("supportsParallelToolCalls", ["devin"]),
264
- "trust-explicit-thinking-only": wire("trustExplicitThinkingOnly", ["devin"]),
274
+ "trust-explicit-thinking-only": wire("trustExplicitThinkingOnly", [...OAI, "devin"]),
265
275
 
266
276
  // ── wire: google APIs ──
267
277
  "antigravity-claude-tool-mode": wire("antigravityClaudeToolMode", ["google"]),
@@ -395,11 +405,35 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
395
405
  /** How the model line bills an input image; shape and formulas in `./image-tokenization`. */
396
406
  "image-tokenization": { key: "imageTokenization", set: "catalog", shape: "object" },
397
407
  "image-model": { key: "imageModel", set: "catalog", shape: "scalar" },
408
+ "inline-image-byte-budget": { key: "inlineImageByteBudget", set: "catalog", shape: "scalar" },
409
+ /**
410
+ * Most questions one System One judgment request may carry; the judge
411
+ * splits larger requests. Unassigned: the endpoint takes any batch size.
412
+ */
413
+ "judgment-questions-max": { key: "judgmentQuestionsMax", set: "catalog", shape: "scalar" },
398
414
  "limits-patch": { key: "limitsPatch", set: "catalog", shape: "object" },
399
415
  "long-context-cost": { key: "longContext", set: "catalog", shape: "object" },
400
416
  "prompt-cache": { key: "promptCache", set: "catalog", shape: "object" },
417
+ /**
418
+ * Prompt-cache lookback in block positions: how far back from a cache
419
+ * breakpoint the provider looks for an earlier request's cache entry.
420
+ * Unassigned: no known lookback bound.
421
+ */
422
+ "prompt-cache-lookback": { key: "promptCacheLookback", set: "catalog", shape: "scalar" },
401
423
  "long-usage-limit-fallback": { key: "longUsageLimitFallback", set: "catalog", shape: "scalar" },
402
424
  "max-context-window": { key: "maxContextWindow", set: "catalog", shape: "scalar" },
425
+ /**
426
+ * Every host of the model returns its full plaintext trace wherever the
427
+ * wire does not mark reasoning as a summary (`ThinkingContent.summary ===
428
+ * false` vouches for nothing more), and its identity (class + family +
429
+ * revision) pins one set of weights, so a turn's reasoning may replay
430
+ * natively on another host serving the same model. Marked summaries never
431
+ * carry; do not declare it where a host serves summaries unmarked.
432
+ * Declared per family in `classes/*.kdl`; a host whose reasoning must not be
433
+ * carried in or out sets `#false` in its `providers/*.kdl`. Read through
434
+ * `compat/reasoning-carry.ts`.
435
+ */
436
+ "portable-reasoning": { key: "portableReasoning", set: "catalog", shape: "scalar", values: [true, false] },
403
437
  "pricing-status": {
404
438
  key: "pricingStatus",
405
439
  set: "catalog",
@@ -288,7 +288,12 @@ function collect(winners: WinnerTable, pick: (rule: CompiledRule) => Record<stri
288
288
  return out;
289
289
  }
290
290
 
291
- const resolveCache = new LRUCache<string, ResolvedAxes>({ max: 512 });
291
+ /**
292
+ * Sized above the bundled catalog (~5.6k targets) plus discovered rows so a
293
+ * catalog-wide buildModel pass (discovery, then merge rebuilding the same ids)
294
+ * hits instead of thrashing. Entries share rule values: a few hundred bytes each.
295
+ */
296
+ const resolveCache = new LRUCache<string, ResolvedAxes>({ max: 16384 });
292
297
 
293
298
  function keyPart(value: string | undefined): string {
294
299
  return value === undefined ? "-1:" : `${value.length}:${value}`;
@@ -0,0 +1,12 @@
1
+ import type { Model } from "../types";
2
+ import { resolveCatalogPolicy } from "./catalog-policy";
3
+
4
+ /**
5
+ * Most questions one System One judgment request to this model may carry
6
+ * (`judgment-questions-max` axis), or `undefined` when the endpoint takes any
7
+ * batch size.
8
+ */
9
+ export function resolveJudgmentQuestionsMax(model: Model): number | undefined {
10
+ const value = resolveCatalogPolicy(model).judgmentQuestionsMax;
11
+ return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : undefined;
12
+ }
@@ -0,0 +1,23 @@
1
+ import { toModelSpec } from "../provider-models/bundled-references";
2
+ import type { Model } from "../types";
3
+ import { resolveCatalogAxes } from "./resolve";
4
+
5
+ const lookbackCache = new Map<string, number | null>();
6
+ const LOOKBACK_CACHE_MAX = 8192;
7
+
8
+ /**
9
+ * Block positions the provider's prompt cache checks back from a breakpoint for
10
+ * an earlier request's entry (`prompt-cache-lookback` axis), or `undefined` when
11
+ * the model has no known lookback bound.
12
+ */
13
+ export function resolvePromptCacheLookback(model: Model): number | undefined {
14
+ const key = `${model.provider} ${model.id} ${model.api}`;
15
+ let lookback = lookbackCache.get(key);
16
+ if (lookback === undefined) {
17
+ const value = resolveCatalogAxes(toModelSpec(model)).promptCacheLookback;
18
+ lookback = typeof value === "number" && Number.isInteger(value) && value > 0 ? value : null;
19
+ if (lookbackCache.size >= LOOKBACK_CACHE_MAX) lookbackCache.clear();
20
+ lookbackCache.set(key, lookback);
21
+ }
22
+ return lookback ?? undefined;
23
+ }
@@ -1,2 +1,2 @@
1
1
  /** Every chat-model provider with a catalog entry (`default-model` in its provider rules). */
2
- export type KnownProvider = "abliteration" | "aiand" | "aimlapi" | "alibaba-coding-plan" | "alibaba-token-plan" | "amazon-bedrock" | "anthropic" | "apple" | "azure" | "baseten" | "bedrock-mantle" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "commandcode" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google" | "google-antigravity" | "google-gemini-cli" | "google-vertex" | "groq" | "helmcode" | "huggingface" | "kilo" | "kimi-code" | "litellm" | "lm-studio" | "local" | "meta" | "minimax" | "minimax-code" | "minimax-code-cn" | "mistral" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai" | "openai-codex" | "opencode-go" | "opencode-zen" | "openrouter" | "qianfan" | "qwen-portal" | "sakana" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stepfun" | "synthetic" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "web" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zenmux" | "zhipu-coding-plan";
2
+ export type KnownProvider = "abliteration" | "aiand" | "aimlapi" | "alibaba-coding-plan" | "alibaba-token-plan" | "amazon-bedrock" | "anthropic" | "apple" | "azure" | "baseten" | "bedrock-mantle" | "cerebras" | "charm-hyper" | "cline-pass" | "cloudflare-ai-gateway" | "cloudflare-workers-ai" | "commandcode" | "coralbricks" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "factory-droid" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google" | "google-antigravity" | "google-gemini-cli" | "google-vertex" | "groq" | "helmcode" | "huggingface" | "kilo" | "kimi-code" | "litellm" | "lm-studio" | "local" | "meta" | "minimax" | "minimax-code" | "minimax-code-cn" | "mistral" | "moonshot" | "muse-code" | "nanogpt" | "novita" | "nvidia" | "ollama" | "ollama-cloud" | "openai" | "openai-codex" | "opencode-go" | "opencode-zen" | "openrouter" | "qianfan" | "qwen-portal" | "sakana" | "siliconflow" | "siliconflow-cn" | "singularityapi-dev" | "singularityapi-tech" | "snowflake" | "stepfun" | "synthetic" | "together" | "typesafe" | "umans" | "venice" | "vercel-ai-gateway" | "vllm" | "wafer-serverless" | "web" | "xai" | "xai-oauth" | "xiaomi" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-sgp" | "yolo-auto" | "zai" | "zenmux" | "zhipu-coding-plan";
@@ -17,7 +17,9 @@ export type KnownProvider =
17
17
  | "charm-hyper"
18
18
  | "cline-pass"
19
19
  | "cloudflare-ai-gateway"
20
+ | "cloudflare-workers-ai"
20
21
  | "commandcode"
22
+ | "coralbricks"
21
23
  | "coreweave"
22
24
  | "cursor"
23
25
  | "deepinfra"
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Reasoning carry: whether reasoning a model produced on one host may replay
3
+ * natively on another host serving the same model.
4
+ *
5
+ * The model-side half is declared with the `portable-reasoning` catalog axis
6
+ * per family in `rules/classes/*.kdl`: the family's stored reasoning is its own
7
+ * full plaintext trace, and its identity pins one set of weights. A host whose
8
+ * reasoning must neither be carried in nor out overrides it to `#false` in its
9
+ * `rules/providers/*.kdl`. Whether the target host has a native slot for
10
+ * earlier reasoning is derived by the request encoders in `@linxiraos/pi-ai`,
11
+ * not declared here.
12
+ *
13
+ * Resolved through the cascade on demand (like delegation bias) because
14
+ * bundled rows are frozen by the generator; results are memoized per
15
+ * deployment.
16
+ */
17
+ import { resolveCascade } from "./cascade";
18
+ import { classifyModel } from "./taxonomy";
19
+ import type { ModelIdentity } from "./types";
20
+
21
+ /** `null` records a deployment that does not carry reasoning. */
22
+ const portableIdentityMemo = new Map<string, ModelIdentity | null>();
23
+
24
+ /**
25
+ * The identity a deployment's reasoning is carried under, or `undefined` when
26
+ * the deployment's model family is not declared portable there. Class-only
27
+ * identities never qualify: they name a lineage, not a set of weights.
28
+ */
29
+ export function portableReasoningIdentity(provider: string, api: string, modelId: string): ModelIdentity | undefined {
30
+ const key = `${provider}\0${api}\0${modelId}`;
31
+ const memo = portableIdentityMemo.get(key);
32
+ if (memo !== undefined) return memo ?? undefined;
33
+ const identity = classifyModel(provider, modelId, { lenient: true });
34
+ let portable: ModelIdentity | null = null;
35
+ if (identity.family !== undefined || identity.revision !== undefined) {
36
+ const declared = resolveCascade({
37
+ provider,
38
+ api,
39
+ class: identity.class,
40
+ model: modelId,
41
+ reasoning: true,
42
+ ...(identity.family !== undefined && { family: identity.family }),
43
+ ...(identity.revision !== undefined && { revision: identity.revision }),
44
+ }).catalog.portableReasoning;
45
+ if (declared === true) portable = identity;
46
+ }
47
+ portableIdentityMemo.set(key, portable);
48
+ return portable ?? undefined;
49
+ }
50
+
51
+ /**
52
+ * Whether reasoning recorded on `source` may replay natively on `target`:
53
+ * both deployments declare the family portable and classify to the same
54
+ * class, family, and revision.
55
+ */
56
+ export function carriesReasoning(
57
+ source: { provider: string; api: string; model: string },
58
+ target: { provider: string; api: string; id: string },
59
+ ): boolean {
60
+ const to = portableReasoningIdentity(target.provider, target.api, target.id);
61
+ if (!to) return false;
62
+ const from = portableReasoningIdentity(source.provider, source.api, source.model);
63
+ return from !== undefined && from.class === to.class && from.family === to.family && from.revision === to.revision;
64
+ }
@@ -0,0 +1,25 @@
1
+ import { toModelSpec } from "../provider-models/bundled-references";
2
+ import type { Model } from "../types";
3
+ import { resolveCatalogAxes } from "./resolve";
4
+
5
+ const imageBudgetCache = new Map<string, number | null>();
6
+ const IMAGE_BUDGET_CACHE_MAX = 8192;
7
+
8
+ /**
9
+ * Maximum encoded inline-image bytes retained per request for a deployment with a documented body-size limit.
10
+ * The axis is a host contract: a rerouted `baseUrl` (proxy, gateway) imposes its own limit, so the budget
11
+ * applies only while the model targets its official endpoint.
12
+ */
13
+ export function resolveInlineImageByteBudget(model: Model): number | undefined {
14
+ const compat = model.compat;
15
+ if (!compat || !("officialEndpoint" in compat) || !compat.officialEndpoint) return undefined;
16
+ const key = `${model.provider} ${model.id} ${model.api}`;
17
+ let budget = imageBudgetCache.get(key);
18
+ if (budget === undefined) {
19
+ const value = resolveCatalogAxes(toModelSpec(model)).inlineImageByteBudget;
20
+ budget = typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
21
+ if (imageBudgetCache.size >= IMAGE_BUDGET_CACHE_MAX) imageBudgetCache.clear();
22
+ imageBudgetCache.set(key, budget);
23
+ }
24
+ return budget ?? undefined;
25
+ }
@@ -107,11 +107,12 @@ class IdentityFacts {
107
107
  return this.is("kimi") && this.family("k2.7-code", "k3");
108
108
  }
109
109
 
110
- /** Adaptive-thinking Claude generation floor (Opus ≥ min; Sonnet/Fable/Mythos ≥ 5). */
110
+ /** Adaptive-thinking Claude generation floor (Opus ≥ min; Sonnet/Fable/Mythos ≥ 5; Haiku ≥ 5.5). */
111
111
  anthropicAdaptiveGenAtLeast(opusMin: string): boolean {
112
112
  if (!this.is("anthropic")) return false;
113
113
  if (this.family("opus")) return this.revGte(opusMin);
114
114
  if (this.family("sonnet", "fable", "mythos")) return this.revGte("5");
115
+ if (this.family("haiku")) return this.revGte("5.5");
115
116
  return false;
116
117
  }
117
118
  }
@@ -502,6 +503,7 @@ function detectOpenAICompat(
502
503
  supportsDeveloperRole: isOpenAIHost || isAzureHost,
503
504
  supportsMultipleSystemMessages: supportsMultipleSystemMessagesDefault,
504
505
  supportsReasoningEffort: !isGrok && !d.isXiaomiMimo && (!(d.isZai || d.isZhipu) || supportsZaiReasoningEffort),
506
+ trustExplicitThinkingOnly: undefined,
505
507
  // API-conditional: this completions-only Copilot exclusion cannot be a
506
508
  // provider rule without changing Copilot Responses rows.
507
509
  supportsReasoningParams: provider !== "github-copilot",
@@ -731,6 +733,7 @@ function resolveOpenAIResponsesPolicy(
731
733
  hostMatchesUrl(baseUrl, "openrouter") ||
732
734
  hostMatchesUrl(baseUrl, "deepseekFamily"),
733
735
  supportsReasoningEffort: !isXaiHost,
736
+ trustExplicitThinkingOnly: undefined,
734
737
  supportsLongPromptCacheRetention: isOpenAIUrl,
735
738
  supportsPromptCacheBreakpoints,
736
739
  promptCacheBreakpointTtl: supportsPromptCacheBreakpoints ? "30m" : undefined,
@@ -792,6 +795,7 @@ function resolveOpenAIResponsesPolicy(
792
795
  (LOCAL_OPENAI_COMPAT_PROVIDERS[backendProvider] === true || hasLocalLoopbackBaseUrl(baseUrl)),
793
796
  supportsObfuscationOptOut: isOpenAIUrl || provider === "openai",
794
797
  storeResponses: false,
798
+ connectionBoundNativeHistory: false,
795
799
  officialEndpoint: isOfficialOpenAIEndpoint(provider, baseUrl),
796
800
  harmonyLeakMitigation: false,
797
801
  rejectRootObjectUnion: false,
@@ -854,6 +858,7 @@ function pickResponsesOnly(compat: ResolvedOpenAIResponsesCompat): ResponsesOnly
854
858
  supportsImageDetailOriginal: compat.supportsImageDetailOriginal,
855
859
  supportsObfuscationOptOut: compat.supportsObfuscationOptOut,
856
860
  storeResponses: compat.storeResponses,
861
+ connectionBoundNativeHistory: compat.connectionBoundNativeHistory,
857
862
  supportsAllTurnsReasoningContext: compat.supportsAllTurnsReasoningContext,
858
863
  supportsConfigurationUpdate: compat.supportsConfigurationUpdate,
859
864
  supportsSteering: compat.supportsSteering,
@@ -910,6 +915,11 @@ function resolveAnthropicPolicy(
910
915
  escapeBuiltinToolNames: false,
911
916
  injectClaudeCodeInstruction: true,
912
917
  stripImageInput: false,
918
+ // Unset means "canonical Anthropic image contract"; the request builder
919
+ // owns those numbers. The keys must exist for a KDL rule or a
920
+ // user-authored `compat` block to override them.
921
+ maxImageDimension: undefined,
922
+ maxImagePayloadBytes: undefined,
913
923
  thinkingLoopGuard: undefined,
914
924
  // Present as keys so models.yml `compat` can set them; unset unless a rule assigns them.
915
925
  stripThinkingHistory: undefined,
@@ -932,6 +942,9 @@ function resolveBedrockPolicy(spec: ModelSpec<"bedrock-converse-stream">, axes:
932
942
  promptCacheMinimumTokens: 0,
933
943
  promptCacheMaximumCheckpoints: 0,
934
944
  supportsForcedToolChoice: true,
945
+ // Opt-out: every prefix-bound Claude line on Converse takes the controls,
946
+ // including custom Bedrock-wire providers; KDL or models.yml sets `false`.
947
+ supportsThinkingBindingControls: true,
935
948
  };
936
949
  // Reasoning capability is a mechanism gate; adaptive-lineage duration is rule-owned.
937
950
  compat.streamIdleTimeoutMs = compatReasoning(spec, axes) ? BEDROCK_REASONING_STREAM_IDLE_TIMEOUT_MS : undefined;
@@ -1009,7 +1022,8 @@ function defaultThinkingMode<TApi extends Api>(spec: ModelSpec<TApi>, facts: Ide
1009
1022
  return "anthropic-budget-effort";
1010
1023
  }
1011
1024
  if (facts.is("anthropic")) {
1012
- if (facts.revGte("4.6") && !facts.family("haiku")) return "anthropic-adaptive";
1025
+ // Haiku stays on budget thinking until 5.5, its first adaptive generation.
1026
+ if (facts.revGte(facts.family("haiku") ? "5.5" : "4.6")) return "anthropic-adaptive";
1013
1027
  if (facts.family("opus") && facts.revGte("4.5")) return "anthropic-budget-effort";
1014
1028
  }
1015
1029
  return "budget";
@@ -213,10 +213,16 @@ The three value shapes are:
213
213
  - **Object**: no arguments and a child block, including an empty block. Child names are kebab-case: an axis-directive spelling compiles to its resolved axis key (`template-reasoning-effort` → `qwenTemplateReasoningEffort`), anything else converts mechanically (`input-threshold` → `inputThreshold`); camelCase names are a compile error. `extra-body` payloads (top-level or nested) are the exception — their child names are literal wire JSON keys copied verbatim (`enable_thinking`). Each child is either one scalar or another object; arrays are not representable inside an object payload.
214
214
 
215
215
  A rule cannot assign the same resolved axis twice in one block.
216
- One object axis carries a computed form: `long-context-cost` accepts either the absolute rates (`input-threshold` + `input`/`output`/`cache-read`/`cache-write`) or `input-threshold` + `multiplier` (with optional `input-threshold-inclusive`), which derives the tier from the row's live base price at build time so the rule tracks upstream list-price updates (xAI's SuperGrok 200K tier). Rows without a token price carry no tier.
216
+ One object axis carries a computed form: `long-context-cost` accepts either the absolute rates (`input-threshold` + `input`/`output`/`cache-read`/`cache-write`) or `input-threshold` + `multiplier` (with optional `input-threshold-inclusive`), which derives the tier from the row's base price at build time, after `cost-patch` and `cost-fallback`, so the rule tracks upstream list-price updates (xAI's SuperGrok 200K tier). Rows without a token price carry no tier. An empty `long-context-cost {}` adds no tier; a more specific rule uses it to opt a host out of a broader rule's band (GitHub Copilot's Haiku 5.5 rows, whose long tier is the `-1m` sibling).
217
217
 
218
218
  `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).
219
219
 
220
+ `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. The budget applies only while `compat.officialEndpoint` holds: a custom `baseUrl` imposes its own body limit.
221
+
222
+ `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.
223
+
224
+ `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.
225
+
220
226
  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`.
221
227
 
222
228
  ### Time-based pricing
@@ -468,11 +474,15 @@ provider "muse-code" {
468
474
 
469
475
  Only `discovery` enrolls a provider in `generate-models.ts`; providers without it are never fetched at generation time (see the `charm-hyper` entry for why a live gateway deliberately omits it).
470
476
 
477
+ `automatic-default #false` keeps a provider available for explicit selection but excludes it from startup fallback and automatic model presets. The default is `#true`; `apple` opts out because its on-device context cannot accommodate the standard coding-agent prompt in many projects.
478
+
479
+ `kind-apis { <kind> "<api>" }` maps each non-chat kind (`image`, `tts`, `stt`, `embedding`, `rerank`, `video`) to the API discovery assigns rows of that kind. A runner API must sit under the kind it serves (`RUNNER_API_KINDS` in `src/types.ts`); chat APIs, which serve hosted image generation, and multi-kind `local-inference` may back any kind.
480
+
471
481
  ### Seed rows
472
482
 
473
483
  A `seed` _defines_ bundled rows for providers whose catalog cannot be discovered at generation time — credential-scoped rosters, unauthenticated regens, or models ahead of upstream catalogs. Every other stratum patches rows; this one authors them. Runtime model managers hand the rows to `staticModels` through `seedModels(provider)`; the generator bundles them per the seed's `bundle` policy. Values are literal — a seed never derives from another provider's row, and pricing is never borrowed.
474
484
 
475
- `seed` properties: `api` and `base-url` are per-row defaults (a `model` may override either with the same property names); `bundle` defaults to `always`; `precedence="seed"` is optional. `model` takes the wire id positionally, requires `name=`, and its body MUST declare `reasoning`, `input` (`"text"` and/or `"image"`), `cost` (all four per-million rates), and `limits` (`context=` / `max-tokens=`, an omitted limit is `null`); `supports-tools #true` is optional. Any other directive is an axis from the cascade vocabulary: thinking axes become the row's explicit `thinking` (then `thinking-mode` and `thinking-efforts` are both required), wire axes become its explicit `compat` and must apply to the row's API, and catalog axes are rejected because they stay rule-owned in the cascade block. Explicit `thinking`/`compat` on a seed row win over the cascade exactly as they do for any authored spec.
485
+ `seed` properties: `api` and `base-url` are per-row defaults (a `model` may override either with the same property names); `bundle` defaults to `always`; `precedence="seed"` is optional. `model` takes the row id positionally, requires `name=`, and its body MUST declare `reasoning`, `input` (`"text"` and/or `"image"`), `cost` (all four per-million rates), and `limits` (`context=` / `max-tokens=`, an omitted limit is `null`); `supports-tools #true` is optional, and `request-model-id "<wire id>"` sets the row's `requestModelId` when the upstream id differs from the row id (an OpenAI Decisions judge row beside the same-id chat model). Any other directive is an axis from the cascade vocabulary: thinking axes become the row's explicit `thinking` (then `thinking-mode` and `thinking-efforts` are both required), wire axes become its explicit `compat` and must apply to the row's API, and catalog axes are rejected because they stay rule-owned in the cascade block. Explicit `thinking`/`compat` on a seed row win over the cascade exactly as they do for any authored spec.
476
486
 
477
487
  `bundle` decides when the generator includes the rows:
478
488
 
@@ -8,6 +8,6 @@ login-order "openai-codex" "anthropic" "zai" "zai-coding-plan" "kimi-code" "open
8
8
  "xiaomi-token-plan-ams" "xiaomi-token-plan-cn" "firepass" "cline-pass" "factory-droid" "commandcode" "charm-hyper" "deepseek" "stepfun" "muse-code" "meta" "moonshot" \
9
9
  "cerebras" "baseten" "helmcode" "fireworks" "together" "nvidia" "novita" "deepinfra" "huggingface" "perplexity" \
10
10
  "qianfan" "venice" "siliconflow" "siliconflow-cn" "synthetic" "nanogpt" "wafer-serverless" "coreweave" \
11
- "vercel-ai-gateway" "cloudflare-ai-gateway" "snowflake" "litellm" "kilo" "zenmux" "opencode-zen" "opencode-go" \
11
+ "vercel-ai-gateway" "cloudflare-ai-gateway" "cloudflare-workers-ai" "snowflake" "litellm" "kilo" "zenmux" "opencode-zen" "opencode-go" \
12
12
  "yolo-auto" "tavily" "kagi" "exa" "parallel" "typesafe" "ollama" "ollama-cloud" "lm-studio" "llama.cpp" "vllm" \
13
- "gmi-cloud" "stencil" "singularityapi-dev" "singularityapi-tech"
13
+ "gmi-cloud" "stencil" "singularityapi-dev" "singularityapi-tech" "coralbricks"
@@ -0,0 +1,9 @@
1
+ // Cloudflare Workers AI runs the Clef decision models under
2
+ // `/client/v4/accounts/{account_id}/ai/run`. Login stores the API token with
3
+ // the account id (the shared Cloudflare credential); an env-supplied token
4
+ // takes its account from `CLOUDFLARE_ACCOUNT_ID`.
5
+ auth "cloudflare-workers-ai" {
6
+ name "Cloudflare Workers AI"
7
+ env "CLOUDFLARE_API_TOKEN" "CLOUDFLARE_AUTH_TOKEN"
8
+ login "custom" hook="cloudflare-workers-ai"
9
+ }
@@ -0,0 +1,13 @@
1
+ // `/v1/models` is key-protected — it answers `401 missing_api_key` without a
2
+ // bearer key and `401 invalid_api_key` to a rejected one (verified
3
+ // 2026-10-02) — so login validates the pasted key there. The probe bills
4
+ // nothing, unlike a chat-completions ping against a prepaid balance.
5
+ auth "coralbricks" {
6
+ name "CoralBricks"
7
+ login "api-key" {
8
+ auth-url "https://www.coralbricks.ai/api-keys"
9
+ instructions "Create or copy your API key from the CoralBricks dashboard (keys look like cb_...)"
10
+ prompt "Paste your CoralBricks API key" placeholder="cb_..."
11
+ validate "models-endpoint" label="CoralBricks" url="https://inference.coralbricks.ai/v1/models"
12
+ }
13
+ }
@@ -4,6 +4,6 @@ auth "minimax-code-cn" {
4
4
  auth-url "https://platform.minimaxi.com/subscribe/token-plan"
5
5
  instructions "Subscribe to Token Plan and copy your API key"
6
6
  prompt "Paste your MiniMax Token Plan API key" placeholder="sk-..."
7
- validate "chat-completions" base-url="https://api.minimaxi.com/v1" model="MiniMax-M3"
7
+ validate "anthropic-messages" base-url="https://api.minimaxi.com/anthropic" model="MiniMax-M3"
8
8
  }
9
9
  }
@@ -4,6 +4,6 @@ auth "minimax-code" {
4
4
  auth-url "https://platform.minimax.io/subscribe/token-plan"
5
5
  instructions "Subscribe to Token Plan and copy your API key"
6
6
  prompt "Paste your MiniMax Token Plan API key" placeholder="sk-..."
7
- validate "chat-completions" label="MiniMax Token Plan" base-url="https://api.minimax.io/v1" model="MiniMax-M3"
7
+ validate "anthropic-messages" label="MiniMax Token Plan" base-url="https://api.minimax.io/anthropic" model="MiniMax-M3"
8
8
  }
9
9
  }
@@ -9,7 +9,7 @@ auth "openai-codex" {
9
9
  authorize-params {
10
10
  id_token_add_organizations "true"
11
11
  codex_cli_simplified_flow "true"
12
- originator "omp"
12
+ originator "zeta"
13
13
  }
14
14
  instructions "A browser window should open. Complete login to finish."
15
15
  // OpenAI only allowlists this exact URI; a busy port must fail rather than fall back.
@@ -1,5 +1,5 @@
1
1
  // stencil.so account. Not a model provider: the credential authorizes
2
- // omp-hosted Stencil services such as `omp stream` (live.omp.sh).
2
+ // Zeta-hosted Stencil services such as `zetacode stream` (live.omp.sh).
3
3
  //
4
4
  // Two hosts: the Stencil API at api.stencil.so (`{base}`, STENCIL_BASE_URL)
5
5
  // and the OIDC issuer at auth.stencil.so (`{auth}`, STENCIL_AUTH_URL) which