@oh-my-pi/pi-catalog 18.13.2 → 18.14.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 +40 -0
- package/README.md +3 -3
- package/dist/types/build.d.ts +12 -4
- package/dist/types/compat/types.d.ts +3 -1
- package/dist/types/discovery/codex.d.ts +4 -5
- package/dist/types/model-cache.d.ts +8 -0
- package/dist/types/model-catalog-format.d.ts +37 -0
- package/dist/types/models.d.ts +6 -3
- package/package.json +5 -10
- package/src/build.ts +50 -3
- package/src/compat/axes.ts +6 -0
- package/src/compat/rules/README.md +11 -11
- package/src/compat/rules/auth/typesafe.kdl +2 -1
- package/src/compat/rules/classes/deepseek.kdl +2 -1
- package/src/compat/rules/classes/openai.kdl +2 -2
- package/src/compat/rules/providers/factory-droid.kdl +24 -0
- package/src/compat/rules/providers/google-vertex.kdl +3 -0
- package/src/compat/rules/providers/kimi-code.kdl +6 -0
- package/src/compat/rules/providers/mistral.kdl +8 -0
- package/src/compat/rules/runtime/behavior.kdl +9 -6
- package/src/compat/rules.json +1 -1
- package/src/compat/types.ts +3 -1
- package/src/discovery/codex.ts +5 -6
- package/src/model-cache.ts +51 -3
- package/src/model-catalog-format.ts +299 -0
- package/src/models.json +1 -1
- package/src/models.ts +16 -10
- package/src/provider-models/cache-provider-id.ts +23 -6
- package/src/provider-models/openai-compat.ts +83 -23
- package/src/provider-models/special.ts +5 -6
- package/THIRD-PARTY-NOTICES.txt +0 -22901
- package/src/models.json.d.ts +0 -9
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.14.0] - 2026-10-29
|
|
6
|
+
|
|
7
|
+
### Breaking Changes
|
|
8
|
+
|
|
9
|
+
- Removed the raw `@oh-my-pi/pi-catalog/models.json` export; use the bundled model registry APIs instead.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added `nextBuildPriceChange(cost, now)` to identify when a model's dated pricing card may change, allowing callers to safely reuse earlier builds until that time.
|
|
14
|
+
- Added the `selector-revision-suffix` catalog axis for Google Vertex, so `google-vertex/claude-opus-4-8` resolves exactly to `claude-opus-4-8@default`.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Reduced the bundled model catalog size and loading overhead.
|
|
19
|
+
- Updated role defaults so Factory Droid image models are preferred for the `image` role, allowing `generate_image` to work with only a Factory login.
|
|
20
|
+
- Updated `smol` and `slow` role defaults to use the currently bundled Cerebras and OpenAI Codex model identifiers.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Fixed Mistral reasoning models so streamed thinking appears in the transcript and is preserved for subsequent turns.
|
|
25
|
+
- Fixed later-turn HTTP 422 errors in Mistral-hosted DeepSeek conversations when assistant reasoning history is included.
|
|
26
|
+
- Fixed DeepSeek V4.1 Flash image attachments being dropped for publisher-namespaced model IDs such as `ds/deepseek-flash`.
|
|
27
|
+
|
|
28
|
+
## [18.13.3] - 2026-10-28
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Added DeepSeek V4.1 Flash 1017 to the Factory Droid provider for accounts with Factory's 1017 flag; turning thinking off on its Baseten route disables reasoning instead of falling back to low effort ([#17234](https://github.com/can1357/oh-my-pi/pull/17234) by [@skipper019](https://github.com/skipper019))
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- Made Kimi Code model discovery authoritative and cached per credential, added K3.1 Pro and K3.1 Pro Highspeed to the bundled Kimi Code catalog, and preserved live thinking metadata there ([#17224](https://github.com/can1357/oh-my-pi/pull/17224) by [@trukhinyuri](https://github.com/trukhinyuri))
|
|
37
|
+
- Updated Bun engine requirement to ≥1.4.4
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- Codex model refresh now lists models available to an entitled account even when other saved accounts return HTTP 402 ([#17198](https://github.com/can1357/oh-my-pi/issues/17198)).
|
|
42
|
+
- LiteLLM discovery now reads every `/v2/model/info` page before selecting the proxy's model roster, rather than caching only the first 50 entries; malformed or incomplete pagination falls back without caching a partial page ([#17237](https://github.com/can1357/oh-my-pi/pull/17237) by [@maykonmichel](https://github.com/maykonmichel)).
|
|
43
|
+
- Fixed hosted web search on OpenAI Responses and Codex Responses selecting GPT-5.6 Luna instead of GPT-6 Luna ([#17202](https://github.com/can1357/oh-my-pi/pull/17202) by [@mateo-bolanos](https://github.com/mateo-bolanos)).
|
|
44
|
+
|
|
5
45
|
## [18.13.2] - 2026-10-27
|
|
6
46
|
|
|
7
47
|
### Added
|
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ Import from subpaths (`@oh-my-pi/pi-catalog/<module>`) or the root barrel.
|
|
|
21
21
|
|
|
22
22
|
## models.json and rules.json are generated
|
|
23
23
|
|
|
24
|
-
Never edit `src/models.json` or `src/compat/rules.json` by hand. `models.json` is produced from upstream sources (stencil.so, provider catalog discovery, OpenCode docs) by `scripts/generate-models.ts`; `rules.json` is compiled from the KDL tree in `src/compat/rules/`. Regenerate with:
|
|
24
|
+
Never edit `src/models.json` or `src/compat/rules.json` by hand. `models.json` is a compact generated catalog; use `getBundledProviders()` and `getBundledModels()` instead of reading its internal format. It is produced from upstream sources (stencil.so, provider catalog discovery, OpenCode docs) by `scripts/generate-models.ts`; `rules.json` is compiled from the KDL tree in `src/compat/rules/`. Regenerate with:
|
|
25
25
|
|
|
26
26
|
```sh
|
|
27
27
|
bun run gen:compat # src/compat/rules/**/*.kdl -> src/compat/rules.json
|
|
@@ -36,7 +36,7 @@ Model- or provider-conditional policy (identity, effort ladders, wire quirks, mo
|
|
|
36
36
|
bun add @oh-my-pi/pi-catalog
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Ships TypeScript source directly (no build step); requires Bun ≥ 1.
|
|
39
|
+
Ships TypeScript source directly (no build step); requires Bun ≥ 1.4.4.
|
|
40
40
|
|
|
41
41
|
## Cost calculation
|
|
42
42
|
|
|
@@ -47,7 +47,7 @@ The `models` subpath (also exported from the root) provides timestamp-aware pric
|
|
|
47
47
|
| `calculateCost(model, usage, timestamp?)` | Updates and returns `usage.cost` using `model.cost`. |
|
|
48
48
|
| `calculateUsageCost(cost, usage, timestamp?)` | Updates and returns `usage.cost` using a `ModelCost`. |
|
|
49
49
|
| `calculateUncachedInputCost(cost, promptInputTokens, timestamp?)` | Returns the cost of a fully uncached prompt. |
|
|
50
|
-
| `getEffectiveTokenCost(cost, timestamp?)` | Returns the base card in force: the latest due effective rate, else the row's own legs.
|
|
50
|
+
| `getEffectiveTokenCost(cost, timestamp?)` | Returns the base card in force: the latest due effective rate, else the row's own legs. |
|
|
51
51
|
| `getTimeBasedPricingPeriod(cost, timestamp?)` | Returns `"peak"`, `"off-peak"`, or `undefined` without a recurring tariff. |
|
|
52
52
|
| `hasRecurringTariff(schedule)` | Whether a `TimeBasedCost` carries a peak/off-peak tariff rather than only dated rate cards. |
|
|
53
53
|
| `getNextTimeBasedPricingTransition(cost, timestamp?)` | Returns the next actual peak/off-peak change strictly after the timestamp, or `undefined` if none exists. |
|
package/dist/types/build.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Request handlers read fields — they never detect, parse ids, or allocate
|
|
7
7
|
* compat per request.
|
|
8
8
|
*/
|
|
9
|
-
import { type Api, type Model, type ModelSpec } from "./types.js";
|
|
9
|
+
import { type Api, type Model, type ModelCost, type ModelSpec } from "./types.js";
|
|
10
10
|
/**
|
|
11
11
|
* Applies reviewed catalog-data value corrections (`cost-patch`,
|
|
12
12
|
* `cache-read-at-input-rate`, `cache-write-rate`, `limits-patch`,
|
|
@@ -24,8 +24,16 @@ export declare function applyCatalogCorrections(model: Pick<ModelSpec<Api>, "cos
|
|
|
24
24
|
*/
|
|
25
25
|
export declare function buildDiscoveredModel(spec: ModelSpec<Api>, providerType: string): Model<Api>;
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
27
|
+
* The first instant after `now` at which {@link buildModel} could select a
|
|
28
|
+
* different dated price card for a spec carrying `cost`: the next
|
|
29
|
+
* `effectiveFrom` of the spec's own rate schedule or of any dated card in the
|
|
30
|
+
* compiled rules. A build of an unchanged spec made at or after `now` is
|
|
31
|
+
* identical to a fresh one until then. `Infinity` when no change is pending.
|
|
32
|
+
*/
|
|
33
|
+
export declare function nextBuildPriceChange(cost: ModelCost, now: number): number;
|
|
34
|
+
/**
|
|
35
|
+
* Build one model from an authored spec. Bundled models are prebuilt by the
|
|
36
|
+
* generator and decoded by `models.ts`, so this only runs for discovered,
|
|
37
|
+
* custom, and override specs.
|
|
30
38
|
*/
|
|
31
39
|
export declare function buildModel<TApi extends Api>(spec: ModelSpec<TApi>): Model<TApi>;
|
|
@@ -369,8 +369,10 @@ export type CompiledAuthValidation = {
|
|
|
369
369
|
kind: "models-endpoint";
|
|
370
370
|
label?: string;
|
|
371
371
|
url: string;
|
|
372
|
-
/** Env var holding an alternate base URL;
|
|
372
|
+
/** Env var holding an alternate base URL; `baseUrlPath` is appended to it. */
|
|
373
373
|
baseUrlEnv?: string;
|
|
374
|
+
/** Path appended to the `baseUrlEnv` value (default `/models`), for bases that exclude the API version. */
|
|
375
|
+
baseUrlPath?: string;
|
|
374
376
|
/** Hook returning extra request headers (may throw a configuration error). */
|
|
375
377
|
headersHook?: string;
|
|
376
378
|
optional?: boolean;
|
|
@@ -27,12 +27,11 @@ export interface CodexModelDiscoveryResult {
|
|
|
27
27
|
models: ModelSpec<"openai-codex-responses">[];
|
|
28
28
|
etag?: string;
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* discovery can skip the account instead of aborting.
|
|
30
|
+
* A definitive per-account denial (401/403 auth, 402 payment). `models` is
|
|
31
|
+
* empty; unlike transport/parse failures, sibling accounts can still supply
|
|
32
|
+
* an authoritative catalog.
|
|
34
33
|
*/
|
|
35
|
-
rejectedStatus?: 401 | 403;
|
|
34
|
+
rejectedStatus?: 401 | 402 | 403;
|
|
36
35
|
}
|
|
37
36
|
/**
|
|
38
37
|
* Fetches model metadata from Codex backend and normalizes it for pi model management.
|
|
@@ -48,6 +48,14 @@ export interface CacheEntry<TApi extends Api = Api> {
|
|
|
48
48
|
* cache was opened under — Windows cannot remove a database that is still open.
|
|
49
49
|
*/
|
|
50
50
|
export declare function closeModelCache(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Keeps one connection to a non-default cache path open until the returned
|
|
53
|
+
* handle is disposed. The default `models.db` already shares a long-lived
|
|
54
|
+
* connection; other paths otherwise open, initialize and close the database on
|
|
55
|
+
* every read and write, which a refresh pass repeats once per provider.
|
|
56
|
+
* Retains nest: the connection closes when the last one is disposed.
|
|
57
|
+
*/
|
|
58
|
+
export declare function retainModelCacheConnection(dbPath: string | undefined): Disposable;
|
|
51
59
|
export declare function readModelCache<TApi extends Api>(providerId: string, ttlMs: number, now: () => number, dbPath?: string): CacheEntry<TApi> | null;
|
|
52
60
|
/**
|
|
53
61
|
* Persist a provider snapshot.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Api, Model } from "./types.js";
|
|
2
|
+
type EncodedValue = string | number | boolean | null | [number];
|
|
3
|
+
type ObjectNode = [0, EncodedValue[], number, number[]];
|
|
4
|
+
type ArrayNode = [1, EncodedValue[]];
|
|
5
|
+
type Node = ObjectNode | ArrayNode;
|
|
6
|
+
type CompatDelta = [number[], EncodedValue];
|
|
7
|
+
type ModelRow = [string, EncodedValue, CompatDelta?];
|
|
8
|
+
type ProviderRow = [string, EncodedValue, ModelRow[]];
|
|
9
|
+
interface CatalogData {
|
|
10
|
+
version: 1;
|
|
11
|
+
keys: string[];
|
|
12
|
+
booleanShapes: number[][];
|
|
13
|
+
nodes: Node[];
|
|
14
|
+
compat: [string, EncodedValue][];
|
|
15
|
+
providers: ProviderRow[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Parsed compact catalog. Decoded nested objects and arrays can be shared by
|
|
19
|
+
* multiple models; callers must treat those values as immutable.
|
|
20
|
+
*/
|
|
21
|
+
export interface ModelCatalog {
|
|
22
|
+
readonly data: CatalogData;
|
|
23
|
+
readonly values: unknown[];
|
|
24
|
+
readonly decoded: boolean[];
|
|
25
|
+
readonly providers: Map<string, Record<string, Model<Api>>>;
|
|
26
|
+
readonly compatBases: Map<string, EncodedValue>;
|
|
27
|
+
readonly compatValues: Map<string, Map<number, Map<string, Record<string, unknown>>>>;
|
|
28
|
+
}
|
|
29
|
+
/** Encode a model catalog into a deterministic, compact JSON representation. */
|
|
30
|
+
export declare function encodeModelCatalog(models: Record<string, Record<string, Model<Api>>>): string;
|
|
31
|
+
/** Open a parsed catalog without materializing its provider models. */
|
|
32
|
+
export declare function openModelCatalog(value: unknown): ModelCatalog;
|
|
33
|
+
/** List catalog provider keys in deterministic order. */
|
|
34
|
+
export declare function getCatalogProviders(catalog: ModelCatalog): string[];
|
|
35
|
+
/** Materialize and cache one provider, or return undefined if it is absent. */
|
|
36
|
+
export declare function getCatalogProvider(catalog: ModelCatalog, provider: string): Record<string, Model<Api>> | undefined;
|
|
37
|
+
export {};
|
package/dist/types/models.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import MODELS from "./models.json";
|
|
2
1
|
import type { Api, KnownProvider, Model, ModelCost, ModelPricingStatus, TimeBasedCost, TokenCost, Usage } from "./types.js";
|
|
3
|
-
|
|
2
|
+
/** Provider identifier accepted by the bundled model registry. */
|
|
3
|
+
export type GeneratedProvider = string;
|
|
4
4
|
/** Whether `provider` has bundled rows in models.json (e.g. a provider id authored in KDL). */
|
|
5
5
|
export declare function isGeneratedProvider(provider: string): provider is GeneratedProvider;
|
|
6
|
+
/** Look up a bundled model; nested catalog values are shared and must not be mutated. */
|
|
6
7
|
export declare function getBundledModel<TApi extends Api = Api>(provider: GeneratedProvider, modelId: string): Model<TApi>;
|
|
7
|
-
|
|
8
|
+
/** List providers with bundled rows; the array is shared and frozen. */
|
|
9
|
+
export declare function getBundledProviders(): readonly KnownProvider[];
|
|
10
|
+
/** List a provider's bundled models; nested catalog values are shared and must not be mutated. */
|
|
8
11
|
export declare function getBundledModels(provider: GeneratedProvider): Model<Api>[];
|
|
9
12
|
/** Resolve display semantics without mistaking an absent rate card for a free model. */
|
|
10
13
|
export declare function getModelPricingStatus(model: Pick<Model<Api>, "cost" | "pricingStatus">): ModelPricingStatus;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-catalog",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.14.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",
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
"README.md",
|
|
29
29
|
"CHANGELOG.md",
|
|
30
30
|
"LICENSE",
|
|
31
|
-
"THIRD-PARTY-NOTICES.txt",
|
|
32
31
|
"dist/types"
|
|
33
32
|
],
|
|
34
33
|
"type": "module",
|
|
@@ -39,10 +38,6 @@
|
|
|
39
38
|
"types": "./dist/types/index.d.ts",
|
|
40
39
|
"import": "./src/index.ts"
|
|
41
40
|
},
|
|
42
|
-
"./models.json": {
|
|
43
|
-
"types": "./dist/types/models.json.d.d.ts",
|
|
44
|
-
"import": "./src/models.json"
|
|
45
|
-
},
|
|
46
41
|
"./provider-models": {
|
|
47
42
|
"types": "./dist/types/provider-models/index.d.ts",
|
|
48
43
|
"import": "./src/provider-models/index.ts"
|
|
@@ -93,15 +88,15 @@
|
|
|
93
88
|
"gen:proto": "bun scripts/generate-protocols.ts"
|
|
94
89
|
},
|
|
95
90
|
"dependencies": {
|
|
96
|
-
"@oh-my-pi/omptype": "18.
|
|
97
|
-
"@oh-my-pi/pi-utils": "18.
|
|
91
|
+
"@oh-my-pi/omptype": "18.14.0",
|
|
92
|
+
"@oh-my-pi/pi-utils": "18.14.0"
|
|
98
93
|
},
|
|
99
94
|
"devDependencies": {
|
|
100
95
|
"@bgotink/kdl": "0.4.0",
|
|
101
|
-
"@oh-my-pi/pi-ai": "18.
|
|
96
|
+
"@oh-my-pi/pi-ai": "18.14.0",
|
|
102
97
|
"@types/bun": "^1.3.14"
|
|
103
98
|
},
|
|
104
99
|
"engines": {
|
|
105
|
-
"bun": ">=1.
|
|
100
|
+
"bun": ">=1.4.4"
|
|
106
101
|
}
|
|
107
102
|
}
|
package/src/build.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* compat per request.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import RULES from "./compat/rules.json" with { type: "json" };
|
|
10
11
|
import { resolveDiscoveryApi, resolveModelPolicy } from "./compat/resolve";
|
|
11
12
|
import type { ModelIdentity } from "./compat/types";
|
|
12
13
|
import { resolveModelTokenizer } from "./model-tokenizer";
|
|
@@ -463,10 +464,56 @@ export function buildDiscoveredModel(spec: ModelSpec<Api>, providerType: string)
|
|
|
463
464
|
return buildModel({ ...spec, api, providerType });
|
|
464
465
|
}
|
|
465
466
|
|
|
467
|
+
/** Every dated card instant in the compiled rules, ascending; collected on first use. */
|
|
468
|
+
let ruleCardInstants: number[] | undefined;
|
|
469
|
+
|
|
470
|
+
function collectRuleCardInstants(value: unknown, out: number[]): void {
|
|
471
|
+
if (Array.isArray(value)) {
|
|
472
|
+
for (const item of value) collectRuleCardInstants(item, out);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
if (typeof value !== "object" || value === null) return;
|
|
476
|
+
for (const key in value) {
|
|
477
|
+
const child: unknown = Reflect.get(value, key);
|
|
478
|
+
if (key === "effectiveFrom" && typeof child === "string") {
|
|
479
|
+
const instant = Date.parse(child);
|
|
480
|
+
if (Number.isFinite(instant)) out.push(instant);
|
|
481
|
+
} else {
|
|
482
|
+
collectRuleCardInstants(child, out);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* The first instant after `now` at which {@link buildModel} could select a
|
|
489
|
+
* different dated price card for a spec carrying `cost`: the next
|
|
490
|
+
* `effectiveFrom` of the spec's own rate schedule or of any dated card in the
|
|
491
|
+
* compiled rules. A build of an unchanged spec made at or after `now` is
|
|
492
|
+
* identical to a fresh one until then. `Infinity` when no change is pending.
|
|
493
|
+
*/
|
|
494
|
+
export function nextBuildPriceChange(cost: ModelCost, now: number): number {
|
|
495
|
+
if (ruleCardInstants === undefined) {
|
|
496
|
+
const instants: number[] = [];
|
|
497
|
+
collectRuleCardInstants(RULES, instants);
|
|
498
|
+
ruleCardInstants = instants.sort((a, b) => a - b);
|
|
499
|
+
}
|
|
500
|
+
let next = Number.POSITIVE_INFINITY;
|
|
501
|
+
for (const instant of ruleCardInstants) {
|
|
502
|
+
if (instant > now) {
|
|
503
|
+
next = instant;
|
|
504
|
+
break;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
for (const rate of cost.timeBased?.effectiveRates ?? []) {
|
|
508
|
+
if (rate.effectiveFrom > now && rate.effectiveFrom < next) next = rate.effectiveFrom;
|
|
509
|
+
}
|
|
510
|
+
return next;
|
|
511
|
+
}
|
|
512
|
+
|
|
466
513
|
/**
|
|
467
|
-
* Build one model from an authored spec. Bundled models
|
|
468
|
-
*
|
|
469
|
-
*
|
|
514
|
+
* Build one model from an authored spec. Bundled models are prebuilt by the
|
|
515
|
+
* generator and decoded by `models.ts`, so this only runs for discovered,
|
|
516
|
+
* custom, and override specs.
|
|
470
517
|
*/
|
|
471
518
|
export function buildModel<TApi extends Api>(spec: ModelSpec<TApi>): Model<TApi> {
|
|
472
519
|
const policy = resolveModelPolicy(spec);
|
package/src/compat/axes.ts
CHANGED
|
@@ -469,6 +469,12 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
|
|
|
469
469
|
values: ["gemini", "anthropic", "codex", "xai", "openrouter", "openai"],
|
|
470
470
|
},
|
|
471
471
|
"web-search-model": { key: "webSearchModel", set: "catalog", shape: "scalar" },
|
|
472
|
+
/**
|
|
473
|
+
* Revision suffix the host appends to the model's id (Vertex `@default`): a
|
|
474
|
+
* `provider/id` selector written without it names this model exactly.
|
|
475
|
+
* Unassigned: the id has no implied revision and must be written in full.
|
|
476
|
+
*/
|
|
477
|
+
"selector-revision-suffix": { key: "selectorRevisionSuffix", set: "catalog", shape: "scalar" },
|
|
472
478
|
"hosted-image": { key: "hostedImage", set: "catalog", shape: "scalar", values: [true, false] },
|
|
473
479
|
/** How the model line bills an input image; shape and formulas in `./image-tokenization`. */
|
|
474
480
|
"image-tokenization": { key: "imageTokenization", set: "catalog", shape: "object" },
|
|
@@ -179,16 +179,16 @@ provider "openrouter" {
|
|
|
179
179
|
|
|
180
180
|
### Selectors and nesting
|
|
181
181
|
|
|
182
|
-
| Selector
|
|
183
|
-
|
|
|
184
|
-
| `class`
|
|
185
|
-
| `provider`
|
|
186
|
-
| `on`
|
|
187
|
-
| `on-api`
|
|
188
|
-
| `family`
|
|
189
|
-
| `revision`
|
|
190
|
-
| `models`
|
|
191
|
-
| `on-upstream` | `on-upstream "a" "b" { ... }`
|
|
182
|
+
| Selector | Form | Matching semantics |
|
|
183
|
+
| ------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
184
|
+
| `class` | `class "id" { ... }` | Exact class ID. At document root it may contain `on`, `on-api`, `family`, `revision`, and `models`. Under `provider` it may contain `family`, `revision`, and `models`. |
|
|
185
|
+
| `provider` | `provider "id" { ... }` | Exact provider ID. It is root-only and may contain `class`, `on-api`, and `models`. |
|
|
186
|
+
| `on` | `on "provider-a" "provider-b" { ... }` | One or more provider IDs, combined as OR. It is allowed under a root `class`, and may contain `on-api` to conjoin an API scope plus `family`, `revision`, and `models`. |
|
|
187
|
+
| `on-api` | `on-api "adapter-a" "adapter-b" { ... }` | One or more request adapter IDs, combined as OR. At document root it may contain `class` and `models`; under a root `class` (directly or nested inside `on`) or `provider` it may contain `family`, `revision`, and `models`. |
|
|
188
|
+
| `family` | `family "id" { ... }` | Exact classified family ID. It may contain `revision` and `models`. A target with no family does not match. |
|
|
189
|
+
| `revision` | `revision ">=2.5 <4" { ... }` | A non-empty, whitespace-separated conjunction of comparisons. It may contain `models`. A target with no revision does not match. |
|
|
190
|
+
| `models` | `models "id" "vendor/*" { ... }` | One or more alternatives, combined as OR. It may contain only `on-upstream`. `token="name"` matches an ASCII-case-insensitive token bounded by non-alphanumerics. |
|
|
191
|
+
| `on-upstream` | `on-upstream "a" "b" { ... }` | Exact selected upstream IDs, combined as OR. Allowed inside any selector scope once; preserves the containing scope's other permitted children. Absent upstream never matches. |
|
|
192
192
|
|
|
193
193
|
Every selector scope may additionally contain `on-upstream`; it cannot replace an already constrained upstream. Class, provider/`on`, `on-api`, `on-upstream`, and family values are compared exactly and case-sensitively to the structured resolve target. Revision operators are `>=`, `>`, `<=`, `<`, and `=`; operands have one to three dot-separated unsigned 8-bit components, omitted components zero.
|
|
194
194
|
|
|
@@ -415,7 +415,7 @@ auth "anthropic" {
|
|
|
415
415
|
|
|
416
416
|
Login kinds:
|
|
417
417
|
|
|
418
|
-
- `login "api-key" { auth-url "…"; instructions "…"; prompt "…" placeholder="…"; empty-fallback "…"; normalize "strip-bearer"; validate … }` — `validate "chat-completions" base-url= model= tolerate-model-denied= max-tokens-field= max-tokens=`, `validate "anthropic-messages" base-url= model=`, or `validate "models-endpoint" url= base-url-env= headers-hook
|
|
418
|
+
- `login "api-key" { auth-url "…"; instructions "…"; prompt "…" placeholder="…"; empty-fallback "…"; normalize "strip-bearer"; validate … }` — `validate "chat-completions" base-url= model= tolerate-model-denied= max-tokens-field= max-tokens=`, `validate "anthropic-messages" base-url= model=`, or `validate "models-endpoint" url= base-url-env= base-url-path= headers-hook=` (`base-url-path`, default `/models`, is appended to the `base-url-env` value and needs it); all accept `label=` (error-message label, defaults to `name`), `optional=#true` (only auth failures reject), and `trust-forbidden=#true` (requires `optional=#true`; a 403 no longer rejects, so only a 401 does).
|
|
419
419
|
- `login "oauth-code" { … }` as above; `token`/`refresh` `params` values may use `{code}`, `{state}`, `{redirect_uri}`, `{code_verifier}`, `{client_id}`, `{client_secret}`, `{refresh_token}`, `{scope}`; the standard grant parameters are sent unless `standard=#false`.
|
|
420
420
|
- `login "device-code" { client-id …; base-url "…"; scopes …; headers-hook "…"; device url="{base}/…" body="form" { params {…} headers {…} }; token url="…" url-hook="…"; response user-code= device-code= verification-uri= verification-uri-complete= interval= expires-in=; instructions "Enter code: {user_code}"; credential {…}; userinfo …; after-exchange hook=… }`.
|
|
421
421
|
- `login "custom" hook="name"` — the whole flow is a named `@oh-my-pi/pi-ai` hook (`src/registry/hooks/custom.ts`).
|
|
@@ -8,6 +8,7 @@ auth "typesafe" {
|
|
|
8
8
|
auth-url "https://console.typesafe.ai/"
|
|
9
9
|
instructions "Create or copy your API key from the TypeSafe console."
|
|
10
10
|
prompt "Paste your TypeSafe API key" placeholder="API key"
|
|
11
|
-
|
|
11
|
+
// TYPESAFE_BASE_URL is an origin without `/v1` (the SDK appends `/v1/systemone`).
|
|
12
|
+
validate "models-endpoint" label="TypeSafe" url="https://api.typesafe.ai/v1/models" base-url-env="TYPESAFE_BASE_URL" base-url-path="/v1/models"
|
|
12
13
|
}
|
|
13
14
|
}
|
|
@@ -90,10 +90,11 @@ class "deepseek" {
|
|
|
90
90
|
}
|
|
91
91
|
// V4.1 Flash is natively multimodal (vision encoder + projector, image-text
|
|
92
92
|
// pre-training) but its release id carries no `vision` token to key on.
|
|
93
|
+
// The leading glob also covers publisher-namespaced ids (`ds/deepseek-flash`).
|
|
93
94
|
// Same priority as the V4.1 Flash carve-out: the OpenCode Go provider rule
|
|
94
95
|
// declares the same value for its `deepseek-flash` lane and would otherwise
|
|
95
96
|
// tie at equal rank.
|
|
96
|
-
models "deepseek-flash" priority=10 {
|
|
97
|
+
models "*deepseek-flash" priority=10 {
|
|
97
98
|
strip-image-input #false
|
|
98
99
|
}
|
|
99
100
|
// DSML is the model's own tool-call grammar, not a host quirk: any server
|
|
@@ -84,14 +84,14 @@ class "openai" {
|
|
|
84
84
|
on-api "openai-responses" {
|
|
85
85
|
revision ">=5" {
|
|
86
86
|
web-search "openai"
|
|
87
|
-
web-search-model "gpt-
|
|
87
|
+
web-search-model "gpt-6-luna"
|
|
88
88
|
hosted-image #true
|
|
89
89
|
image-model "gpt-image-2"
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
on-api "openai-codex-responses" {
|
|
93
93
|
revision ">=5" {
|
|
94
|
-
web-search-model "gpt-
|
|
94
|
+
web-search-model "gpt-6-luna"
|
|
95
95
|
hosted-image #true
|
|
96
96
|
image-model "gpt-image-2"
|
|
97
97
|
}
|
|
@@ -345,6 +345,12 @@ provider "factory-droid" {
|
|
|
345
345
|
cost input=0 output=0 cache-read=0 cache-write=0
|
|
346
346
|
limits context=136464 max-tokens=65536
|
|
347
347
|
}
|
|
348
|
+
model "deepseek-v4.1-flash-1017" name="DeepSeek V4.1 Flash 1017" {
|
|
349
|
+
reasoning #true
|
|
350
|
+
input "text" "image"
|
|
351
|
+
cost input=0 output=0 cache-read=0 cache-write=0
|
|
352
|
+
limits context=908928 max-tokens=131072
|
|
353
|
+
}
|
|
348
354
|
model "deepseek-v4.1-flash" name="DeepSeek V4.1 Flash" {
|
|
349
355
|
reasoning #true
|
|
350
356
|
input "text" "image"
|
|
@@ -975,6 +981,17 @@ provider "factory-droid" {
|
|
|
975
981
|
thinking-requires-effort #false
|
|
976
982
|
thinking-default-level "high"
|
|
977
983
|
}
|
|
984
|
+
models "deepseek-v4.1-flash-1017" {
|
|
985
|
+
routing-family "factory"
|
|
986
|
+
upstream-rotation "fireworks" "baseten" "databricks"
|
|
987
|
+
credit-rates { input 0.12; output 4; cache-read 0.024 }
|
|
988
|
+
// No bundled Fireworks row for the 1017 slug; Fireworks prices it like V4.1 Flash.
|
|
989
|
+
list-price-from "fireworks" "deepseek-v4.1-flash"
|
|
990
|
+
thinking-efforts "low" "high" "max"
|
|
991
|
+
thinking-requires-effort #false
|
|
992
|
+
thinking-default-level "high"
|
|
993
|
+
entitlement { feature-flag "deepseek_v4_1_flash_1017" }
|
|
994
|
+
}
|
|
978
995
|
models "deepseek-v4.1-flash" {
|
|
979
996
|
routing-family "factory"
|
|
980
997
|
upstream-rotation "fireworks" "baseten" "databricks"
|
|
@@ -1131,6 +1148,13 @@ provider "factory-droid" {
|
|
|
1131
1148
|
synthetic-reasoning-content-fallback " "
|
|
1132
1149
|
}
|
|
1133
1150
|
}
|
|
1151
|
+
// Droid 0.250.0 configures the 1017 checkpoint's Baseten route with
|
|
1152
|
+
// thinkingMode "reasoning-effort": thinking off is sent as `none`.
|
|
1153
|
+
models "deepseek-v4.1-flash-1017" {
|
|
1154
|
+
on-upstream "baseten" {
|
|
1155
|
+
completions-reasoning-mode "effort"
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1134
1158
|
// The replay codec follows the selected route, including EU GLM routes.
|
|
1135
1159
|
on-upstream "mistral" {
|
|
1136
1160
|
models "glm-*" "mistral-medium-3.5" "mistral-large-4" {
|
|
@@ -4,6 +4,9 @@ provider "google-vertex" {
|
|
|
4
4
|
default-model "gemini-3.1-pro-preview"
|
|
5
5
|
allow-unauthenticated #true
|
|
6
6
|
image-count-budget 200
|
|
7
|
+
// Vertex publishes Anthropic ids pinned to a revision (`claude-opus-4-8@default`);
|
|
8
|
+
// `google-vertex/claude-opus-4-8` names that model exactly.
|
|
9
|
+
selector-revision-suffix "@default"
|
|
7
10
|
|
|
8
11
|
// Replaces google-shared.ts stripping functionCall/functionResponse ids for Vertex.
|
|
9
12
|
supports-function-part-id #false
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
provider "kimi-code" {
|
|
4
4
|
default-model "kimi-for-coding"
|
|
5
|
+
dynamic-models-authoritative #true
|
|
5
6
|
discovery label="Kimi Code" {
|
|
6
7
|
env "KIMI_API_KEY"
|
|
7
8
|
}
|
|
@@ -39,6 +40,11 @@ provider "kimi-code" {
|
|
|
39
40
|
thinking-efforts "minimal" "low" "medium" "high"
|
|
40
41
|
thinking-format "zai"
|
|
41
42
|
}
|
|
43
|
+
// K2.7 Code Highspeed always thinks (`supports_thinking_type: "only"`) but
|
|
44
|
+
// exposes no adjustable effort ladder (`think_efforts` is omitted).
|
|
45
|
+
models "kimi-for-coding-highspeed" {
|
|
46
|
+
thinking-efforts
|
|
47
|
+
}
|
|
42
48
|
|
|
43
49
|
// /coding/v1/models carries no pricing. `cost-fallback` seeds the public
|
|
44
50
|
// Moonshot list price only when discovery reports $0, so a future priced
|
|
@@ -29,6 +29,14 @@ provider "mistral" {
|
|
|
29
29
|
// without it, requests only hit replica-local implicit cache. Same shape as
|
|
30
30
|
// the kimi-code rule (#6049).
|
|
31
31
|
supports-prompt-cache-key #true
|
|
32
|
+
// The gateway accepts assistant reasoning as text, not DeepSeek's native
|
|
33
|
+
// reasoning_content field, even when it serves DeepSeek-family models.
|
|
34
|
+
requires-reasoning-content-for-tool-calls #false
|
|
35
|
+
requires-reasoning-content-for-all-assistant-turns #false
|
|
36
|
+
// Reasoning streams and replays as typed `thinking` content parts
|
|
37
|
+
// (https://docs.mistral.ai/studio/conversations/reasoning) for every
|
|
38
|
+
// reasoning model the host serves, including GLM and DeepSeek (#17375).
|
|
39
|
+
mistral-reasoning-content-parts #true
|
|
32
40
|
class "unknown" {
|
|
33
41
|
thinking-efforts "minimal" "low" "medium" "high" "xhigh"
|
|
34
42
|
}
|
|
@@ -100,8 +100,8 @@ behavior {
|
|
|
100
100
|
// (flat rate) or Standard Credits. Unknown ids have no inferred entitlement.
|
|
101
101
|
quota-tiers provider="factory-droid" {
|
|
102
102
|
tier "core" "inkling" "mistral-large-4" "mistral-medium-3.5" "glm-5.3-flash" "glm-5.3" "glm-5.2" "glm-5.2-fast" \
|
|
103
|
-
"kimi-k3" "qwen3.8-max" "nemotron-3-ultra" "deepseek-v4.1-flash" "deepseek-v4-flash-
|
|
104
|
-
"deepseek-v4-pro" "minimax-m3" "minimax-m2.7"
|
|
103
|
+
"kimi-k3" "qwen3.8-max" "nemotron-3-ultra" "deepseek-v4.1-flash" "deepseek-v4.1-flash-1017" \
|
|
104
|
+
"deepseek-v4-flash-0731" "deepseek-v4-pro" "minimax-m3" "minimax-m2.7"
|
|
105
105
|
tier "standard" "claude-fable-5.1" "claude-fable-5" "claude-opus-5-5" "claude-opus-5-5-fast" \
|
|
106
106
|
"claude-opus-5" "claude-opus-5-fast" "claude-opus-4-8" "claude-opus-4-8-fast" "claude-opus-4-7" \
|
|
107
107
|
"claude-opus-4-6" "claude-opus-4-5-20251101" "claude-sonnet-5-5" "claude-sonnet-5" \
|
|
@@ -315,8 +315,8 @@ behavior {
|
|
|
315
315
|
exact="gemini-3-flash-preview" exact="gemini-3-pro-image-preview"
|
|
316
316
|
route "openai-completions" exact="inkling" exact="mistral-large-4" exact="mistral-medium-3.5" exact="glm-5.3-flash" \
|
|
317
317
|
exact="glm-5.3" exact="glm-5.2" exact="glm-5.2-fast" exact="kimi-k3" exact="qwen3.8-max" \
|
|
318
|
-
exact="nemotron-3-ultra" exact="deepseek-v4.1-flash" exact="deepseek-v4-flash-
|
|
319
|
-
exact="deepseek-v4-pro" exact="minimax-m3"
|
|
318
|
+
exact="nemotron-3-ultra" exact="deepseek-v4.1-flash" exact="deepseek-v4.1-flash-1017" \
|
|
319
|
+
exact="deepseek-v4-flash-0731" exact="deepseek-v4-pro" exact="minimax-m3"
|
|
320
320
|
}
|
|
321
321
|
|
|
322
322
|
// Copilot serves these models with tighter effective limits than its
|
|
@@ -428,7 +428,6 @@ behavior {
|
|
|
428
428
|
model "oss-120b"
|
|
429
429
|
model "cerebras/zai-glm-4.7"
|
|
430
430
|
model "cerebras/zai-glm-4.6"
|
|
431
|
-
model "cerebras/zai-glm"
|
|
432
431
|
model "claude-haiku-4-5"
|
|
433
432
|
model "claude-haiku-4.5"
|
|
434
433
|
model "haiku-4-5"
|
|
@@ -463,7 +462,6 @@ behavior {
|
|
|
463
462
|
model "anthropic/claude-opus-5"
|
|
464
463
|
model "claude-opus-5"
|
|
465
464
|
model "opus-5"
|
|
466
|
-
model "openai-codex/gpt-5.5"
|
|
467
465
|
model "gpt-5.5"
|
|
468
466
|
model "claude-opus-4-8"
|
|
469
467
|
model "claude-opus-4.8"
|
|
@@ -479,6 +477,11 @@ behavior {
|
|
|
479
477
|
model "openrouter/google/gemini-3-pro-image"
|
|
480
478
|
model "google/gemini-3-pro-image"
|
|
481
479
|
model "deepinfra/black-forest-labs/FLUX-2-pro"
|
|
480
|
+
// Factory Droid last, in the CLI's own preference order: a Factory
|
|
481
|
+
// login alone can generate, and no other provider's turn moves.
|
|
482
|
+
model "factory-droid/gpt-image-2.5-sunburst"
|
|
483
|
+
model "factory-droid/gpt-image-2.5-flare"
|
|
484
|
+
model "factory-droid/gemini-3-pro-image-preview"
|
|
482
485
|
}
|
|
483
486
|
role-defaults "web" {
|
|
484
487
|
model "web/parallel"
|