@oh-my-pi/pi-catalog 18.2.5 → 18.2.7

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 (56) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/THIRD-PARTY-NOTICES.txt +0 -37
  3. package/dist/types/build.d.ts +7 -1
  4. package/dist/types/compat/auth-ids.d.ts +1 -1
  5. package/dist/types/compat/axes.d.ts +1 -1
  6. package/dist/types/compat/cascade.d.ts +3 -2
  7. package/dist/types/compat/provider-ids.d.ts +1 -1
  8. package/dist/types/compat/resolve.d.ts +2 -0
  9. package/dist/types/compat/taxonomy.d.ts +2 -2
  10. package/dist/types/compat/types.d.ts +18 -7
  11. package/dist/types/discovery/index.d.ts +1 -0
  12. package/dist/types/discovery/openai-compatible.d.ts +2 -0
  13. package/dist/types/discovery/typesafe.d.ts +26 -0
  14. package/dist/types/model-manager.d.ts +1 -1
  15. package/dist/types/provider-models/openai-compat.d.ts +6 -4
  16. package/dist/types/provider-models/special.d.ts +10 -0
  17. package/dist/types/types.d.ts +20 -0
  18. package/package.json +4 -4
  19. package/src/build.ts +27 -5
  20. package/src/compat/auth-ids.ts +2 -0
  21. package/src/compat/axes.ts +9 -1
  22. package/src/compat/cascade.ts +45 -23
  23. package/src/compat/provider-ids.ts +3 -0
  24. package/src/compat/resolve.ts +24 -14
  25. package/src/compat/rules/README.md +5 -3
  26. package/src/compat/rules/auth/local.kdl +4 -0
  27. package/src/compat/rules/auth/typesafe.kdl +3 -6
  28. package/src/compat/rules/auth/web.kdl +4 -0
  29. package/src/compat/rules/classes/qwen.kdl +6 -5
  30. package/src/compat/rules/providers/anthropic.kdl +1 -0
  31. package/src/compat/rules/providers/deepinfra.kdl +28 -0
  32. package/src/compat/rules/providers/google-antigravity.kdl +17 -0
  33. package/src/compat/rules/providers/google.kdl +9 -0
  34. package/src/compat/rules/providers/llama.cpp.kdl +23 -0
  35. package/src/compat/rules/providers/local.kdl +110 -0
  36. package/src/compat/rules/providers/openai-codex.kdl +18 -0
  37. package/src/compat/rules/providers/openai.kdl +3 -0
  38. package/src/compat/rules/providers/openrouter.kdl +24 -0
  39. package/src/compat/rules/providers/typesafe.kdl +21 -0
  40. package/src/compat/rules/providers/web.kdl +153 -0
  41. package/src/compat/rules/providers/xai-oauth.kdl +26 -0
  42. package/src/compat/rules/providers/xai.kdl +22 -0
  43. package/src/compat/rules/runtime/behavior.kdl +2 -1
  44. package/src/compat/rules/taxonomy/qwen.kdl +2 -0
  45. package/src/compat/rules.json +1 -1
  46. package/src/compat/taxonomy.ts +92 -31
  47. package/src/compat/types.ts +22 -7
  48. package/src/discovery/index.ts +1 -0
  49. package/src/discovery/openai-compatible.ts +4 -1
  50. package/src/discovery/typesafe.ts +118 -0
  51. package/src/model-manager.ts +44 -15
  52. package/src/models.json +1 -1
  53. package/src/provider-models/descriptors.ts +6 -0
  54. package/src/provider-models/openai-compat.ts +246 -79
  55. package/src/provider-models/special.ts +53 -0
  56. package/src/types.ts +33 -0
@@ -311,6 +311,7 @@ function detectOpenAI(
311
311
  reasoningCapable: boolean,
312
312
  ): OpenAIDetection {
313
313
  const provider = spec.provider;
314
+ const backendProvider = spec.providerType ?? provider;
314
315
  const baseUrl = spec.baseUrl;
315
316
  const hostModel = { provider, baseUrl };
316
317
  const isZai = modelMatchesHost(hostModel, "zai");
@@ -321,8 +322,8 @@ function detectOpenAI(
321
322
  const isDeepseekFamily = modelMatchesHost(hostModel, "deepseekFamily") || facts.is("deepseek");
322
323
  const isDeepseekReasoning = isDeepseekFamily && reasoningCapable;
323
324
  const isLocalOpenAICompatBackend =
324
- PROXY_OPENAI_COMPAT_PROVIDERS[provider] !== true &&
325
- (LOCAL_OPENAI_COMPAT_PROVIDERS[provider] === true || hasLocalLoopbackBaseUrl(baseUrl));
325
+ PROXY_OPENAI_COMPAT_PROVIDERS[backendProvider] !== true &&
326
+ (LOCAL_OPENAI_COMPAT_PROVIDERS[backendProvider] === true || hasLocalLoopbackBaseUrl(baseUrl));
326
327
  return {
327
328
  facts,
328
329
  isClinePass: provider === "cline-pass",
@@ -521,12 +522,8 @@ function detectOpenAICompat(
521
522
  replayReasoningContent: d.isLocalOpenAICompatBackend,
522
523
  qwenPreserveThinking:
523
524
  (thinkingFormat === "qwen" || thinkingFormat === "qwen-chat-template") && d.isLocalOpenAICompatBackend,
524
- qwenTemplateReasoningEffort:
525
- (thinkingFormat === "qwen" || thinkingFormat === "qwen-chat-template") &&
526
- d.isLocalOpenAICompatBackend &&
527
- provider !== "ollama" &&
528
- isQwen &&
529
- facts.revGte("3.8"),
525
+ // Template effort support is a reviewed backend × model contract in KDL.
526
+ qwenTemplateReasoningEffort: false,
530
527
  requiresAssistantContentForToolCalls: facts.is("kimi") || d.isDirectDeepseekReasoning,
531
528
  cacheControlFormat:
532
529
  (d.isClinePass && (isQwen || isAnthropicModel)) || (d.isOpenRouter && isAnthropicModel)
@@ -692,6 +689,7 @@ function resolveOpenAIResponsesPolicy(
692
689
  ): ResolvedOpenAIResponsesCompat {
693
690
  const baseUrl = spec.baseUrl ?? "";
694
691
  const provider = spec.provider;
692
+ const backendProvider = spec.providerType ?? provider;
695
693
  const hostModel = { provider, baseUrl };
696
694
  const isAzure = modelMatchesHost(hostModel, "azureOpenAI");
697
695
  const isOpenRouter = modelMatchesHost(hostModel, "openrouter");
@@ -703,7 +701,8 @@ function resolveOpenAIResponsesPolicy(
703
701
  const thinkingFormat: ResolvedOpenAISharedCompat["thinkingFormat"] = isOpenRouter ? "openrouter" : "openai";
704
702
  const reasoningCapable = compatReasoning(spec, axes);
705
703
  const isLocalServingBackend =
706
- (PROXY_OPENAI_COMPAT_PROVIDERS[provider] !== true && LOCAL_OPENAI_COMPAT_PROVIDERS[provider] === true) ||
704
+ (PROXY_OPENAI_COMPAT_PROVIDERS[backendProvider] !== true &&
705
+ LOCAL_OPENAI_COMPAT_PROVIDERS[backendProvider] === true) ||
707
706
  hasLocalLoopbackBaseUrl(baseUrl);
708
707
  const isAnthropicModel = facts.is("anthropic");
709
708
  const isDeepseekFamily = facts.is("deepseek");
@@ -1063,8 +1062,8 @@ function readRuleThinking(axes: ResolvedAxes): RuleThinking {
1063
1062
 
1064
1063
  /**
1065
1064
  * Compat-time reasoning capability. `axes.reasoning` also promotes targets on
1066
- * any exact `thinking-efforts` rule (the cascade's thinking-axis gate), but
1067
- * compat may only be repaired where the provider contract opted in with
1065
+ * reviewed effort corrections (the cascade's thinking-axis gate), but compat
1066
+ * may only be repaired where the matching contract opted in with
1068
1067
  * `thinking-upgrade-neutral`; everywhere else a spec that reports no reasoning
1069
1068
  * stays the authoritative capability surface.
1070
1069
  */
@@ -1104,7 +1103,7 @@ function resolveThinkingPolicy<TApi extends Api>(
1104
1103
  // reasoning (e.g. Synthetic's `none`-only off-switch): reviewed KDL must
1105
1104
  // not re-expand it into an unadvertised ladder. Absent metadata is
1106
1105
  // repaired only where KDL opts in with `thinking-upgrade-neutral`
1107
- // alongside an exact `thinking-efforts` ladder (the cascade upgrade for
1106
+ // alongside a reviewed `thinking-efforts` ladder (the cascade upgrade for
1108
1107
  // stale source capability data); otherwise the neutral default holds.
1109
1108
  if (!spec.reasoning && (explicitThinking !== undefined || rule.upgradeNeutral !== true)) return undefined;
1110
1109
  if (
@@ -1210,9 +1209,13 @@ function fillExplicitThinking<TApi extends Api>(
1210
1209
  // Entry
1211
1210
  // ---------------------------------------------------------------------------
1212
1211
 
1213
- function buildResolveTarget<TApi extends Api>(spec: ModelSpec<TApi>, identity: ModelIdentity): ResolveTarget {
1212
+ function buildResolveTarget<TApi extends Api>(
1213
+ spec: ModelSpec<TApi>,
1214
+ identity: ModelIdentity,
1215
+ providerType = spec.providerType ?? spec.provider,
1216
+ ): ResolveTarget {
1214
1217
  const target: ResolveTarget = {
1215
- provider: spec.provider,
1218
+ provider: providerType,
1216
1219
  api: spec.api,
1217
1220
  class: identity.class,
1218
1221
  model: spec.id,
@@ -1227,6 +1230,13 @@ function specUsesApi<TApi extends Api>(spec: ModelSpec<Api>, api: TApi): spec is
1227
1230
  return spec.api === api;
1228
1231
  }
1229
1232
 
1233
+ /** Resolve the request adapter assigned to a discovery backend before materialization. */
1234
+ export function resolveDiscoveryApi(spec: ModelSpec<Api>, providerType: string): Api {
1235
+ const identity = resolveIdentity(spec);
1236
+ const discoveryApi = resolveCascade(buildResolveTarget(spec, identity, providerType)).catalog.discoveryApi;
1237
+ return typeof discoveryApi === "string" ? discoveryApi : spec.api;
1238
+ }
1239
+
1230
1240
  /**
1231
1241
  * Resolves the full policy surface for one model spec: structured identity,
1232
1242
  * complete compat record, thinking metadata, and catalog-data corrections.
@@ -89,7 +89,7 @@ revision skip-bare "o1" "o3" "o4"
89
89
 
90
90
  ### Reviewed identity overrides
91
91
 
92
- `override` has properties only and no child block. Required string properties are `id` (stable, globally unique review ID), `model` (exact bare model identifier, compared case-insensitively), `rationale`, and `provenance`.
92
+ `override` has properties only and no child block. Required string properties are `id` (stable, globally unique review ID), `rationale`, and `provenance`, plus exactly one selector: `model` (exact bare identifier) or `glob` (anchored `*` wildcard over the bare identifier). Both selectors compare case-insensitively; namespace prefixes before the final `/` are ignored.
93
93
 
94
94
  Optional properties are:
95
95
 
@@ -104,7 +104,7 @@ Optional properties are:
104
104
  | `thinking-variant` | Boolean marker for a separately exposed thinking sibling. |
105
105
  | `expires-at-ms` | Non-negative Unix time in milliseconds. The override is inactive when the observation time is at or after this value. |
106
106
 
107
- The pair `(provider, model)` must also be unique, including provider-agnostic pairs. When no observation time is supplied, an expiring override remains active.
107
+ The tuple `(provider, selector-kind, selector)` must also be unique, including provider-agnostic selectors. Active exact overrides take precedence over every glob. Within each selector kind, provider-scoped overrides precede provider-agnostic ones; matching globs rank by non-wildcard byte count. Equal-ranked globs are an ambiguity error, never resolved by declaration order. When no observation time is supplied, an expiring override remains active.
108
108
 
109
109
  ### Suffix collapse
110
110
 
@@ -194,6 +194,8 @@ A `models` string without `*` is an exact, case-sensitive match against the prov
194
194
 
195
195
  `priority=N` is an optional signed integer property on the block that owns axis assignments. Its default is zero. Use it only to resolve an intentional equal-specificity overlap; do not use it to encode declaration order.
196
196
 
197
+ `buildDiscoveredModel(spec, providerType)` resolves the catalog `discovery-api` axis before materializing compatibility. It preserves the credential-bearing provider ID and records `providerType` as the backend used for provider selectors on subsequent rebuilds. Ordinary `buildModel` preserves its input API. This lets custom-named llama.cpp deployments reuse the same rules without model-specific discovery code.
198
+
197
199
  ### Axis vocabulary and value shapes
198
200
 
199
201
  The directive vocabulary is closed and lives in **`src/compat/axes.ts`** — one table mapping each kebab-case directive to its resolved camelCase field, namespace (`wire` / `thinking` / `catalog`), value shape, applicable compat records, and (for enums) accepted values. The compiler rejects unknown directives and out-of-vocabulary values against that table; consult it rather than a duplicated table here.
@@ -262,7 +264,7 @@ The highest-ranked matching assignment wins for that axis. Two distinct rules th
262
264
 
263
265
  ### Capability gating
264
266
 
265
- Wire axes are considered for every matching target. Thinking axes are considered only when the structured resolve target sets `reasoning` — except that an exact model selector declaring `thinking-efforts` upgrades the target (a reviewed correction to stale source capability metadata). Family and revision selectors never match targets missing that rank. An unmatched target resolves to empty maps; the cascade does not infer negative capabilities from absence.
267
+ Wire axes are considered for every matching target. Thinking axes require `reasoning`, except that an exact model selector declaring `thinking-efforts` opens the gate for reviewed corrections. A winning `thinking-upgrade-neutral #true` scoped to a recognized class, family, revision, or model selector also opens it when a matching effort ladder exists; provider-wide opt-in alone does not. Materializing a neutral spec as reasoning-capable requires that opt-in and no explicit thinking vocabulary. Family and revision selectors never match targets missing that rank. An unmatched target resolves to empty maps; the cascade does not infer negative capabilities from absence.
266
268
 
267
269
  ## Runtime behavior grammar
268
270
 
@@ -0,0 +1,4 @@
1
+ auth "local" {
2
+ name "Local models"
3
+ allows-missing-api-key #true
4
+ }
@@ -1,9 +1,6 @@
1
- // TypeSafe (System One judgments) is not a chat-model provider: it answers
2
- // typed questions (choice / yes-no / score) over JSON state via
3
- // `POST /v1/systemone`, consumed through `@oh-my-pi/pi-ai`'s `TypeSafeJudge`.
4
- // No `providers/typesafe.kdl` entry exists on purpose — it has no chat models,
5
- // so it never appears in the model picker; the credential alone is what the
6
- // judgment resolver checks.
1
+ // TypeSafe (System One judgments) answers typed questions over JSON state via
2
+ // `POST /v1/systemone`. Its judgment models are catalogued under the `judge`
3
+ // kind; this auth entry supplies both live `/v1/models` discovery and requests.
7
4
  auth "typesafe" {
8
5
  name "TypeSafe"
9
6
  env "TYPESAFE_API_KEY"
@@ -0,0 +1,4 @@
1
+ auth "web" {
2
+ name "Web search engines"
3
+ allows-missing-api-key #true
4
+ }
@@ -33,11 +33,12 @@ class "qwen" {
33
33
  }
34
34
  // Qwen 3.8+ open-weight chat templates steer thinking depth through the
35
35
  // `reasoning_effort` template kwarg (wire-exact low/medium/xhigh, template
36
- // default xhigh) and raise on `enable_thinking: false`, so local
37
- // llama.cpp-style hosts route the selected effort onto the template instead
38
- // of always reasoning at xhigh. vLLM ignores top-level
39
- // `enable_thinking`, so it rides the chat-template-kwargs dialect.
40
- on "llama.cpp" "lm-studio" {
36
+ // default xhigh) and raise on `enable_thinking: false`. LM Studio routes
37
+ // the selected effort onto the template instead of always reasoning at
38
+ // xhigh; llama.cpp owns its equivalent policy in the provider rule. vLLM
39
+ // ignores top-level `enable_thinking`, so it rides the
40
+ // chat-template-kwargs dialect.
41
+ on "lm-studio" {
41
42
  revision ">=3.8" {
42
43
  supports-reasoning-effort #true
43
44
  template-reasoning-effort #true
@@ -4,6 +4,7 @@ provider "anthropic" {
4
4
  default-model "claude-opus-4-8"
5
5
  env "ANTHROPIC_API_KEY"
6
6
  discovery label="Anthropic"
7
+ web-search "anthropic"
7
8
 
8
9
  // Curated Anthropic models that are live or limited-availability on the
9
10
  // first-party `/v1/models` endpoint but that stencil.so has not catalogued
@@ -5,4 +5,32 @@ provider "deepinfra" {
5
5
  env "DEEPINFRA_API_KEY"
6
6
  dynamic-models-authoritative #true
7
7
  discovery label="DeepInfra" allow-unauthenticated=#true
8
+ kind-apis {
9
+ image "openai-images"
10
+ tts "openai-speech"
11
+ }
12
+
13
+ seed base-url="https://api.deepinfra.com/v1/openai" bundle="always" {
14
+ model "black-forest-labs/FLUX-2-pro" name="FLUX.2 Pro" api="openai-images" {
15
+ reasoning #false
16
+ input "text" "image"
17
+ cost input=0 output=0 cache-read=0 cache-write=0
18
+ limits
19
+ supports-tools #false
20
+ }
21
+ model "hexgrad/Kokoro-82M" name="Kokoro-82M" api="openai-speech" {
22
+ reasoning #false
23
+ input "text"
24
+ cost input=0 output=0 cache-read=0 cache-write=0
25
+ limits
26
+ supports-tools #false
27
+ }
28
+ }
29
+
30
+ models "black-forest-labs/FLUX-2-pro" {
31
+ kind "image"
32
+ }
33
+ models "hexgrad/Kokoro-82M" {
34
+ kind "tts"
35
+ }
8
36
  }
@@ -2,6 +2,20 @@
2
2
 
3
3
  provider "google-antigravity" {
4
4
  default-model "gemini-3.1-pro"
5
+ kind-apis {
6
+ image "google-gemini-cli"
7
+ }
8
+ web-search "gemini"
9
+
10
+ seed api="google-gemini-cli" base-url="https://daily-cloudcode-pa.googleapis.com" bundle="always" {
11
+ model "gemini-3-pro-image" name="Gemini 3 Pro Image" {
12
+ reasoning #false
13
+ input "text" "image"
14
+ cost input=0 output=0 cache-read=0 cache-write=0
15
+ limits
16
+ supports-tools #false
17
+ }
18
+ }
5
19
 
6
20
  class "anthropic" {
7
21
  family "opus" {
@@ -45,6 +59,9 @@ provider "google-antigravity" {
45
59
  models "gemini-3-pro" {
46
60
  thinking-mode "google-level"
47
61
  }
62
+ models "gemini-3-pro-image" {
63
+ kind "image"
64
+ }
48
65
  // residue: taxonomy ranks and exact globs do not isolate these models.
49
66
  models "gemini-3.1-flash-lite" {
50
67
  thinking-mode "google-level"
@@ -3,6 +3,10 @@
3
3
  provider "google" {
4
4
  default-model "gemini-3.1-pro-preview"
5
5
  env "GEMINI_API_KEY"
6
+ kind-apis {
7
+ image "google-generative-ai"
8
+ }
9
+ web-search "gemini"
6
10
 
7
11
  class "unknown" {
8
12
  thinking-efforts "minimal" "low" "medium" "high"
@@ -17,4 +21,9 @@ provider "google" {
17
21
  models "gemini-2.5-computer-use-preview-10-2025" "gemini-robotics-er-1.6-preview" {
18
22
  thinking-efforts "minimal" "low" "medium" "high"
19
23
  }
24
+ // The proxy conservatively classifies tool-capable text+image output as chat;
25
+ // this SKU is a native image generator on the Gemini image transport.
26
+ models "gemini-3.1-flash-lite-image" {
27
+ kind "image"
28
+ }
20
29
  }
@@ -1,6 +1,29 @@
1
1
  // Provider-wire compat for "llama.cpp".
2
2
 
3
3
  provider "llama.cpp" {
4
+ supports-store #false
5
+ supports-developer-role #false
6
+ supports-reasoning-effort #false
4
7
  // Replaces the string-only named-tool-choice provider table.
5
8
  supports-named-tool-choice #false
9
+
10
+ class "qwen" {
11
+ // Responses cannot encode the template's thinking controls.
12
+ discovery-api "openai-completions"
13
+ // llama-server exposes the model's bundled chat template. Qwen templates
14
+ // preserve prior reasoning and accept the chat-template thinking controls.
15
+ thinking-upgrade-neutral #true
16
+ thinking-mode "effort"
17
+ thinking-efforts "low" "medium" "high" "max"
18
+ thinking-format "qwen"
19
+ reasoning-disable-mode "qwen-enable-thinking-false"
20
+ qwen-preserve-thinking #true
21
+
22
+ revision ">=3.8" {
23
+ supports-reasoning-effort #true
24
+ template-reasoning-effort #true
25
+ thinking-efforts "low" "medium" "xhigh"
26
+ thinking-requires-effort #true
27
+ }
28
+ }
6
29
  }
@@ -0,0 +1,110 @@
1
+ // On-device inference workers exposed as catalog models.
2
+
3
+ provider "local" {
4
+ default-model "lfm2.5-230m"
5
+ allow-unauthenticated #true
6
+
7
+ seed api="local-inference" base-url="local://inference" bundle="always" {
8
+ model "kokoro" name="Kokoro-82M" {
9
+ reasoning #false
10
+ input "text"
11
+ cost input=0 output=0 cache-read=0 cache-write=0
12
+ limits
13
+ supports-tools #false
14
+ }
15
+ model "parakeet-tdt-0.6b-v3" name="Parakeet TDT 0.6B v3" {
16
+ reasoning #false
17
+ input "text"
18
+ cost input=0 output=0 cache-read=0 cache-write=0
19
+ limits
20
+ supports-tools #false
21
+ }
22
+ model "whisper-base" name="Whisper Base" {
23
+ reasoning #false
24
+ input "text"
25
+ cost input=0 output=0 cache-read=0 cache-write=0
26
+ limits
27
+ supports-tools #false
28
+ }
29
+ model "whisper-small" name="Whisper Small" {
30
+ reasoning #false
31
+ input "text"
32
+ cost input=0 output=0 cache-read=0 cache-write=0
33
+ limits
34
+ supports-tools #false
35
+ }
36
+ model "whisper-large-v3-turbo" name="Whisper Large v3 Turbo" {
37
+ reasoning #false
38
+ input "text"
39
+ cost input=0 output=0 cache-read=0 cache-write=0
40
+ limits
41
+ supports-tools #false
42
+ }
43
+ model "lfm2.5-230m" name="LFM2.5 230M" {
44
+ reasoning #false
45
+ input "text"
46
+ cost input=0 output=0 cache-read=0 cache-write=0
47
+ limits
48
+ supports-tools #false
49
+ }
50
+ model "lfm2.5-350m" name="LFM2.5 350M" {
51
+ reasoning #false
52
+ input "text"
53
+ cost input=0 output=0 cache-read=0 cache-write=0
54
+ limits
55
+ supports-tools #false
56
+ }
57
+ model "falcon-h1-90m" name="Falcon H1 Tiny 90M" {
58
+ reasoning #false
59
+ input "text"
60
+ cost input=0 output=0 cache-read=0 cache-write=0
61
+ limits
62
+ supports-tools #false
63
+ }
64
+ model "qwen3-1.7b" name="Qwen3 1.7B" {
65
+ reasoning #true
66
+ input "text"
67
+ cost input=0 output=0 cache-read=0 cache-write=0
68
+ limits
69
+ supports-tools #false
70
+ }
71
+ model "llama3.2:3b" name="Llama 3.2 3B" {
72
+ reasoning #false
73
+ input "text"
74
+ cost input=0 output=0 cache-read=0 cache-write=0
75
+ limits
76
+ supports-tools #false
77
+ }
78
+ model "gemma-3-1b" name="Gemma 3 1B" {
79
+ reasoning #false
80
+ input "text"
81
+ cost input=0 output=0 cache-read=0 cache-write=0
82
+ limits
83
+ supports-tools #false
84
+ }
85
+ model "qwen2.5-1.5b" name="Qwen2.5 1.5B" {
86
+ reasoning #false
87
+ input "text"
88
+ cost input=0 output=0 cache-read=0 cache-write=0
89
+ limits
90
+ supports-tools #false
91
+ }
92
+ model "lfm2-1.2b" name="LFM2 1.2B" {
93
+ reasoning #false
94
+ input "text"
95
+ cost input=0 output=0 cache-read=0 cache-write=0
96
+ limits
97
+ supports-tools #false
98
+ }
99
+ }
100
+
101
+ models "kokoro" {
102
+ kind "tts"
103
+ }
104
+ models "parakeet-tdt-0.6b-v3" "whisper-*" {
105
+ kind "stt"
106
+ }
107
+ models "lfm*" "falcon-*" "qwen*" "llama3.2:3b" "gemma-3-1b" {
108
+ kind "tiny"
109
+ }
110
+ }
@@ -3,6 +3,24 @@
3
3
  provider "openai-codex" {
4
4
  default-model "gpt-5.5"
5
5
  env "OPENAI_CODEX_OAUTH_TOKEN"
6
+ kind-apis {
7
+ image "openai-codex-responses"
8
+ }
9
+ web-search "codex"
10
+
11
+ seed api="openai-codex-responses" base-url="https://chatgpt.com/backend-api" bundle="always" {
12
+ model "gpt-image-1" name="GPT Image 1" {
13
+ reasoning #false
14
+ input "text" "image"
15
+ cost input=0 output=0 cache-read=0 cache-write=0
16
+ limits
17
+ supports-tools #false
18
+ }
19
+ }
20
+
21
+ models "gpt-image-1" {
22
+ kind "image"
23
+ }
6
24
 
7
25
  // Replaces the Codex provider's handwritten flex/priority pricing fallback.
8
26
  service-tier-cost {
@@ -3,6 +3,9 @@
3
3
  provider "openai" {
4
4
  default-model "gpt-5.5"
5
5
  env "OPENAI_API_KEY"
6
+ kind-apis {
7
+ image "openai-responses"
8
+ }
6
9
 
7
10
  // Daybreak models are approval-gated first-party Responses models that are
8
11
  // not yet present in stencil.so. Seed the documented aliases and current
@@ -4,6 +4,25 @@ provider "openrouter" {
4
4
  default-model "openai/gpt-5.5"
5
5
  env "OPENROUTER_API_KEY"
6
6
  discovery label="OpenRouter" allow-unauthenticated=#true
7
+ kind-apis {
8
+ image "openrouter-images"
9
+ }
10
+ web-search "openrouter"
11
+
12
+ // TypeSafe's Jev answers only through the Decisions API (`/api/alpha/decisions`,
13
+ // System One wire shape); the default `/models` roster omits `text->decisions`
14
+ // rows, so the alias is authored here and discovery refreshes the family.
15
+ seed api="openrouter-decisions" base-url="https://openrouter.ai/api/alpha" bundle="always" {
16
+ model "~typesafe/jev-latest" name="TypeSafe: Jev Latest" {
17
+ reasoning #false
18
+ input "text"
19
+ cost input=0.042 output=0 cache-read=0 cache-write=0
20
+ limits context=32000 max-tokens=28800
21
+ }
22
+ }
23
+ models "~typesafe/*" "typesafe/*" {
24
+ kind "judge"
25
+ }
7
26
 
8
27
  // Replaces the OpenRouter provider wire-model-id dispatch branch.
9
28
  wire-model-id-mode "openrouter"
@@ -59,6 +78,11 @@ provider "openrouter" {
59
78
  thinking-efforts "minimal" "low" "medium" "high"
60
79
  thinking-requires-effort #true
61
80
  }
81
+ // The proxy conservatively classifies this tool-capable text+image output row
82
+ // as chat; OpenRouter's dedicated image roster confirms the image transport.
83
+ models "google/gemini-3-pro-image" {
84
+ kind "image"
85
+ }
62
86
  // residue: taxonomy ranks and exact globs do not isolate these models.
63
87
  models "qwen/qwen3-coder" {
64
88
  thinking-format "openrouter"
@@ -0,0 +1,21 @@
1
+ // TypeSafe System One judgment models.
2
+
3
+ provider "typesafe" {
4
+ default-model "jev-latest"
5
+ env "TYPESAFE_API_KEY"
6
+
7
+ seed api="typesafe" base-url="https://api.typesafe.ai" bundle="always" {
8
+ model "jev-latest" name="TypeSafe jev" {
9
+ reasoning #false
10
+ input "text"
11
+ // Jev bills input only; matches the OpenRouter route seed.
12
+ cost input=0.042 output=0 cache-read=0 cache-write=0
13
+ limits
14
+ supports-tools #false
15
+ }
16
+ }
17
+
18
+ models "*" {
19
+ kind "judge"
20
+ }
21
+ }
@@ -0,0 +1,153 @@
1
+ // Pure search engines exposed through the web-search runner.
2
+
3
+ provider "web" {
4
+ default-model "public"
5
+ allow-unauthenticated #true
6
+
7
+ seed api="web-search" base-url="web://search" bundle="always" {
8
+ model "parallel" name="Parallel" {
9
+ reasoning #false
10
+ input "text"
11
+ cost input=0 output=0 cache-read=0 cache-write=0
12
+ limits
13
+ supports-tools #false
14
+ }
15
+ model "perplexity" name="Perplexity" {
16
+ reasoning #false
17
+ input "text"
18
+ cost input=0 output=0 cache-read=0 cache-write=0
19
+ limits
20
+ supports-tools #false
21
+ }
22
+ model "zai" name="Z.AI" {
23
+ reasoning #false
24
+ input "text"
25
+ cost input=0 output=0 cache-read=0 cache-write=0
26
+ limits
27
+ supports-tools #false
28
+ }
29
+ model "exa" name="Exa" {
30
+ reasoning #false
31
+ input "text"
32
+ cost input=0 output=0 cache-read=0 cache-write=0
33
+ limits
34
+ supports-tools #false
35
+ }
36
+ model "tinyfish" name="TinyFish" {
37
+ reasoning #false
38
+ input "text"
39
+ cost input=0 output=0 cache-read=0 cache-write=0
40
+ limits
41
+ supports-tools #false
42
+ }
43
+ model "jina" name="Jina" {
44
+ reasoning #false
45
+ input "text"
46
+ cost input=0 output=0 cache-read=0 cache-write=0
47
+ limits
48
+ supports-tools #false
49
+ }
50
+ model "kagi" name="Kagi" {
51
+ reasoning #false
52
+ input "text"
53
+ cost input=0 output=0 cache-read=0 cache-write=0
54
+ limits
55
+ supports-tools #false
56
+ }
57
+ model "tavily" name="Tavily" {
58
+ reasoning #false
59
+ input "text"
60
+ cost input=0 output=0 cache-read=0 cache-write=0
61
+ limits
62
+ supports-tools #false
63
+ }
64
+ model "firecrawl" name="Firecrawl" {
65
+ reasoning #false
66
+ input "text"
67
+ cost input=0 output=0 cache-read=0 cache-write=0
68
+ limits
69
+ supports-tools #false
70
+ }
71
+ model "brave" name="Brave" {
72
+ reasoning #false
73
+ input "text"
74
+ cost input=0 output=0 cache-read=0 cache-write=0
75
+ limits
76
+ supports-tools #false
77
+ }
78
+ model "kimi" name="Kimi" {
79
+ reasoning #false
80
+ input "text"
81
+ cost input=0 output=0 cache-read=0 cache-write=0
82
+ limits
83
+ supports-tools #false
84
+ }
85
+ model "synthetic" name="Synthetic" {
86
+ reasoning #false
87
+ input "text"
88
+ cost input=0 output=0 cache-read=0 cache-write=0
89
+ limits
90
+ supports-tools #false
91
+ }
92
+ model "ollama" name="Ollama" {
93
+ reasoning #false
94
+ input "text"
95
+ cost input=0 output=0 cache-read=0 cache-write=0
96
+ limits
97
+ supports-tools #false
98
+ }
99
+ model "searxng" name="SearXNG" {
100
+ reasoning #false
101
+ input "text"
102
+ cost input=0 output=0 cache-read=0 cache-write=0
103
+ limits
104
+ supports-tools #false
105
+ }
106
+ model "startpage" name="Startpage" {
107
+ reasoning #false
108
+ input "text"
109
+ cost input=0 output=0 cache-read=0 cache-write=0
110
+ limits
111
+ supports-tools #false
112
+ }
113
+ model "duckduckgo" name="DuckDuckGo" {
114
+ reasoning #false
115
+ input "text"
116
+ cost input=0 output=0 cache-read=0 cache-write=0
117
+ limits
118
+ supports-tools #false
119
+ }
120
+ model "ecosia" name="Ecosia" {
121
+ reasoning #false
122
+ input "text"
123
+ cost input=0 output=0 cache-read=0 cache-write=0
124
+ limits
125
+ supports-tools #false
126
+ }
127
+ model "google" name="Google" {
128
+ reasoning #false
129
+ input "text"
130
+ cost input=0 output=0 cache-read=0 cache-write=0
131
+ limits
132
+ supports-tools #false
133
+ }
134
+ model "mojeek" name="Mojeek" {
135
+ reasoning #false
136
+ input "text"
137
+ cost input=0 output=0 cache-read=0 cache-write=0
138
+ limits
139
+ supports-tools #false
140
+ }
141
+ model "public" name="Public Web" {
142
+ reasoning #false
143
+ input "text"
144
+ cost input=0 output=0 cache-read=0 cache-write=0
145
+ limits
146
+ supports-tools #false
147
+ }
148
+ }
149
+
150
+ models "*" {
151
+ kind "search"
152
+ }
153
+ }