@linxiraos/pi-catalog 1.1.26 → 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.
- package/CHANGELOG.md +4 -6
- package/dist/types/compat/auth-ids.d.ts +2 -2
- package/dist/types/compat/collapse.d.ts +7 -0
- package/dist/types/compat/image-tokenization.d.ts +52 -0
- package/dist/types/compat/judgment-questions.d.ts +7 -0
- package/dist/types/compat/prompt-cache-lookback.d.ts +7 -0
- package/dist/types/compat/provider-ids.d.ts +1 -1
- package/dist/types/compat/reasoning-carry.d.ts +21 -0
- package/dist/types/compat/request-size.d.ts +7 -0
- package/dist/types/compat/taxonomy.d.ts +0 -10
- package/dist/types/compat/types.d.ts +4 -0
- package/dist/types/discovery/antigravity.d.ts +13 -3
- package/dist/types/hosts.d.ts +4 -0
- package/dist/types/model-cache.d.ts +6 -0
- package/dist/types/model-manager.d.ts +16 -0
- package/dist/types/provider-models/account-access.d.ts +11 -0
- package/dist/types/provider-models/google.d.ts +23 -1
- package/dist/types/provider-models/openai-compat.d.ts +19 -1
- package/dist/types/provider-models/special.d.ts +8 -0
- package/dist/types/types.d.ts +134 -23
- package/dist/types/wire/cloudflare-ai-gateway.d.ts +0 -10
- package/dist/types/wire/cloudflare.d.ts +10 -0
- package/dist/types/wire/factory-droid.d.ts +1 -1
- package/dist/types/wire/gemini-headers.d.ts +6 -3
- package/package.json +4 -4
- package/src/build.ts +39 -35
- package/src/compat/auth-ids.ts +6 -0
- package/src/compat/axes.ts +43 -5
- package/src/compat/cascade.ts +6 -1
- package/src/compat/collapse.d.ts +7 -0
- package/src/compat/collapse.ts +11 -0
- package/src/compat/image-tokenization.ts +166 -0
- package/src/compat/judgment-questions.ts +12 -0
- package/src/compat/prompt-cache-lookback.ts +23 -0
- package/src/compat/provider-ids.d.ts +1 -1
- package/src/compat/provider-ids.ts +3 -0
- package/src/compat/reasoning-carry.ts +64 -0
- package/src/compat/request-size.ts +25 -0
- package/src/compat/resolve.ts +36 -25
- package/src/compat/rules/README.md +13 -3
- package/src/compat/rules/auth/_order.kdl +2 -2
- package/src/compat/rules/auth/cloudflare-workers-ai.kdl +9 -0
- package/src/compat/rules/auth/coralbricks.kdl +13 -0
- package/src/compat/rules/auth/minimax-code-cn.kdl +1 -1
- package/src/compat/rules/auth/minimax-code.kdl +1 -1
- package/src/compat/rules/auth/openai-codex.kdl +1 -1
- package/src/compat/rules/auth/snowflake.kdl +11 -0
- package/src/compat/rules/auth/stencil.kdl +1 -1
- package/src/compat/rules/classes/anthropic.kdl +188 -7
- package/src/compat/rules/classes/deepseek.kdl +11 -3
- package/src/compat/rules/classes/gemini.kdl +12 -0
- package/src/compat/rules/classes/glm.kdl +17 -8
- package/src/compat/rules/classes/kimi.kdl +15 -0
- package/src/compat/rules/classes/meta.kdl +4 -4
- package/src/compat/rules/classes/minimax.kdl +31 -1
- package/src/compat/rules/classes/openai.kdl +114 -4
- package/src/compat/rules/classes/qwen.kdl +2 -1
- package/src/compat/rules/providers/abliteration.kdl +7 -0
- package/src/compat/rules/providers/amazon-bedrock.kdl +0 -7
- package/src/compat/rules/providers/anthropic.kdl +13 -0
- package/src/compat/rules/providers/apple.kdl +1 -0
- package/src/compat/rules/providers/cloudflare-workers-ai.kdl +34 -0
- package/src/compat/rules/providers/coralbricks.kdl +62 -0
- package/src/compat/rules/providers/cursor.kdl +28 -8
- package/src/compat/rules/providers/devin.kdl +2 -2
- package/src/compat/rules/providers/factory-droid.kdl +77 -13
- package/src/compat/rules/providers/github-copilot.kdl +29 -0
- package/src/compat/rules/providers/google-antigravity.kdl +8 -1
- package/src/compat/rules/providers/groq.kdl +21 -0
- package/src/compat/rules/providers/image-tokenization.kdl +42 -0
- package/src/compat/rules/providers/judgment-questions.kdl +53 -0
- package/src/compat/rules/providers/litellm.kdl +4 -1
- package/src/compat/rules/providers/meta.kdl +3 -3
- package/src/compat/rules/providers/minimax-code-cn.kdl +10 -5
- package/src/compat/rules/providers/minimax-code.kdl +10 -5
- package/src/compat/rules/providers/mistral.kdl +25 -1
- package/src/compat/rules/providers/moonshot.kdl +11 -0
- package/src/compat/rules/providers/muse-code.kdl +7 -0
- package/src/compat/rules/providers/ollama.kdl +3 -0
- package/src/compat/rules/providers/openai-codex.kdl +18 -13
- package/src/compat/rules/providers/openai.kdl +22 -0
- package/src/compat/rules/providers/opencode-go.kdl +11 -0
- package/src/compat/rules/providers/opencode-zen.kdl +20 -0
- package/src/compat/rules/providers/openrouter.kdl +6 -0
- package/src/compat/rules/providers/snowflake.kdl +135 -0
- package/src/compat/rules/providers/tool-result-images.kdl +16 -0
- package/src/compat/rules/providers/zhipu-coding-plan.kdl +10 -0
- package/src/compat/rules/runtime/behavior.kdl +8 -5
- package/src/compat/rules/taxonomy/_collapse.kdl +52 -2
- package/src/compat/rules/taxonomy/deepseek.kdl +4 -0
- package/src/compat/rules/taxonomy/kimi.kdl +5 -0
- package/src/compat/rules.json +1 -1
- package/src/compat/taxonomy.d.ts +0 -10
- package/src/compat/taxonomy.ts +3 -3
- package/src/compat/types.d.ts +4 -0
- package/src/compat/types.ts +4 -0
- package/src/discovery/antigravity.d.ts +13 -3
- package/src/discovery/antigravity.ts +33 -17
- package/src/discovery/cursor.ts +28 -4
- package/src/discovery/devin.ts +20 -2
- package/src/hosts.d.ts +4 -0
- package/src/hosts.ts +2 -0
- package/src/model-cache.d.ts +6 -0
- package/src/model-cache.ts +123 -47
- package/src/model-manager.d.ts +16 -0
- package/src/model-manager.ts +107 -41
- package/src/model-tokenizer.ts +3 -0
- package/src/models.json +1 -1
- package/src/provider-models/account-access.d.ts +11 -0
- package/src/provider-models/account-access.ts +30 -0
- package/src/provider-models/cache-provider-id.ts +13 -6
- package/src/provider-models/cline-pass.ts +33 -0
- package/src/provider-models/descriptors.ts +4 -0
- package/src/provider-models/google.d.ts +23 -1
- package/src/provider-models/google.ts +72 -14
- package/src/provider-models/openai-compat.d.ts +19 -1
- package/src/provider-models/openai-compat.ts +281 -42
- package/src/provider-models/special.d.ts +8 -0
- package/src/provider-models/special.ts +26 -22
- package/src/types.d.ts +134 -23
- package/src/types.ts +183 -20
- package/src/wire/cloudflare-ai-gateway.d.ts +0 -10
- package/src/wire/cloudflare-ai-gateway.ts +0 -36
- package/src/wire/cloudflare.ts +40 -0
- package/src/wire/factory-droid.d.ts +1 -1
- package/src/wire/factory-droid.ts +1 -1
- package/src/wire/gemini-headers.d.ts +6 -3
- package/src/wire/gemini-headers.ts +39 -21
package/src/compat/taxonomy.d.ts
CHANGED
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime model-identity taxonomy: classifies wire model ids into
|
|
3
|
-
* `(class, family, revision)` ranks, applies reviewed identity overrides, and
|
|
4
|
-
* exposes the collapse/discovery vocabularies.
|
|
5
|
-
*
|
|
6
|
-
* Faithful port of the o2 reference (`taxonomy.rs` / `classify.rs`):
|
|
7
|
-
* matchers rank `exact(4) > bounded(3) > namespace(2) > prefix(1) > glob(0)`
|
|
8
|
-
* with token byte length as tiebreak; equal cross-class or cross-family ranks
|
|
9
|
-
* throw unless classification is `lenient` (discovery normalization).
|
|
10
|
-
*/
|
|
11
1
|
import type { Effort } from "../effort";
|
|
12
2
|
import type { ModelIdentity } from "./types";
|
|
13
3
|
/** Two classes, families, or reviewed override patterns tie for one model id. */
|
package/src/compat/taxonomy.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* with token byte length as tiebreak; equal cross-class or cross-family ranks
|
|
9
9
|
* throw unless classification is `lenient` (discovery normalization).
|
|
10
10
|
*/
|
|
11
|
+
import { LRUCache } from "@linxiraos/pi-utils/lru";
|
|
11
12
|
import type { Effort } from "../effort";
|
|
12
13
|
import { globMatch } from "./cascade";
|
|
13
14
|
import { formatRevision, parseRevisionPrefix } from "./revision";
|
|
@@ -433,8 +434,8 @@ export function stripThinkingVariantSuffix(model: string): string | undefined {
|
|
|
433
434
|
* @throws AmbiguousIdentityError on equal-rank cross-class, cross-family, or
|
|
434
435
|
* reviewed-pattern matches unless `opts.lenient`.
|
|
435
436
|
*/
|
|
436
|
-
|
|
437
|
-
const
|
|
437
|
+
// LRU sized above the bundled catalog so catalog-wide passes stay hot (a full `clear()` thrashed them).
|
|
438
|
+
const classifyMemo = new LRUCache<string, ModelIdentity>({ max: 16384 });
|
|
438
439
|
|
|
439
440
|
function classifyMemoKey(provider: string, modelId: string, lenient: boolean): string {
|
|
440
441
|
return `${provider.length}:${provider}${modelId.length}:${modelId}${lenient ? 1 : 0}`;
|
|
@@ -446,7 +447,6 @@ export function classifyModel(provider: string, modelId: string, opts?: Classify
|
|
|
446
447
|
const cached = classifyMemo.get(key);
|
|
447
448
|
if (cached !== undefined) return { ...cached };
|
|
448
449
|
const identity = classifyModelUncached(provider, modelId, opts);
|
|
449
|
-
if (classifyMemo.size >= CLASSIFY_MEMO_MAX) classifyMemo.clear();
|
|
450
450
|
classifyMemo.set(key, Object.freeze(identity));
|
|
451
451
|
return { ...identity };
|
|
452
452
|
}
|
package/src/compat/types.d.ts
CHANGED
|
@@ -593,6 +593,8 @@ export interface CompiledSeedModel {
|
|
|
593
593
|
baseUrl: string;
|
|
594
594
|
reasoning: boolean;
|
|
595
595
|
input: ("text" | "image")[];
|
|
596
|
+
/** Wire model id sent upstream when it differs from the row id (`request-model-id`). */
|
|
597
|
+
requestModelId?: string;
|
|
596
598
|
supportsTools?: boolean;
|
|
597
599
|
cost: TokenCost;
|
|
598
600
|
contextWindow: number | null;
|
|
@@ -622,6 +624,8 @@ export interface CompiledProvider {
|
|
|
622
624
|
id: string;
|
|
623
625
|
/** Preferred model id when no explicit selection is made. */
|
|
624
626
|
defaultModel: string;
|
|
627
|
+
/** Whether the provider participates in automatic default selection (defaults to true). */
|
|
628
|
+
automaticDefault?: boolean;
|
|
625
629
|
/** Env vars consulted, in order, for the runtime API-key fallback. */
|
|
626
630
|
envVars?: string[];
|
|
627
631
|
/** The runtime creates a model manager even without a valid API key. */
|
package/src/compat/types.ts
CHANGED
|
@@ -625,6 +625,8 @@ export interface CompiledSeedModel {
|
|
|
625
625
|
baseUrl: string;
|
|
626
626
|
reasoning: boolean;
|
|
627
627
|
input: ("text" | "image")[];
|
|
628
|
+
/** Wire model id sent upstream when it differs from the row id (`request-model-id`). */
|
|
629
|
+
requestModelId?: string;
|
|
628
630
|
supportsTools?: boolean;
|
|
629
631
|
cost: TokenCost;
|
|
630
632
|
contextWindow: number | null;
|
|
@@ -656,6 +658,8 @@ export interface CompiledProvider {
|
|
|
656
658
|
id: string;
|
|
657
659
|
/** Preferred model id when no explicit selection is made. */
|
|
658
660
|
defaultModel: string;
|
|
661
|
+
/** Whether the provider participates in automatic default selection (defaults to true). */
|
|
662
|
+
automaticDefault?: boolean;
|
|
659
663
|
/** Env vars consulted, in order, for the runtime API-key fallback. */
|
|
660
664
|
envVars?: string[];
|
|
661
665
|
/** The runtime creates a model manager even without a valid API key. */
|
|
@@ -63,13 +63,23 @@ export interface FetchAntigravityDiscoveryModelsOptions {
|
|
|
63
63
|
*/
|
|
64
64
|
collapseTable?: VariantCollapseTable;
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* A complete account roster, or a definitive 401/403 credential rejection.
|
|
68
|
+
* `null` from {@link fetchAntigravityDiscoveryModels} instead means a transient
|
|
69
|
+
* failure or invalid response, which must not replace an authoritative catalog.
|
|
70
|
+
*/
|
|
71
|
+
export interface AntigravityModelDiscoveryResult {
|
|
72
|
+
models: ModelSpec<"google-gemini-cli">[];
|
|
73
|
+
rejectedStatus?: 401 | 403;
|
|
74
|
+
}
|
|
66
75
|
/**
|
|
67
76
|
* Fetches discoverable Antigravity models and normalizes them into canonical model entries.
|
|
68
77
|
*
|
|
69
|
-
* Returns `null` on network
|
|
70
|
-
*
|
|
78
|
+
* Returns `null` on network, server, or payload failures; a 401/403 is reported
|
|
79
|
+
* separately so multi-account discovery can skip a rejected credential.
|
|
80
|
+
* A successful empty roster has `models: []` without `rejectedStatus`.
|
|
71
81
|
*/
|
|
72
|
-
export declare function fetchAntigravityDiscoveryModels(options: FetchAntigravityDiscoveryModelsOptions): Promise<
|
|
82
|
+
export declare function fetchAntigravityDiscoveryModels(options: FetchAntigravityDiscoveryModelsOptions): Promise<AntigravityModelDiscoveryResult | null>;
|
|
73
83
|
/** Advertised image model and serving endpoint for one Antigravity account. */
|
|
74
84
|
export interface AntigravityImageModel {
|
|
75
85
|
id: string;
|
|
@@ -153,19 +153,29 @@ export interface FetchAntigravityDiscoveryModelsOptions {
|
|
|
153
153
|
collapseTable?: VariantCollapseTable;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
/**
|
|
157
|
+
* A complete account roster, or a definitive 401/403 credential rejection.
|
|
158
|
+
* `null` from {@link fetchAntigravityDiscoveryModels} instead means a transient
|
|
159
|
+
* failure or invalid response, which must not replace an authoritative catalog.
|
|
160
|
+
*/
|
|
161
|
+
export interface AntigravityModelDiscoveryResult {
|
|
162
|
+
models: ModelSpec<"google-gemini-cli">[];
|
|
163
|
+
rejectedStatus?: 401 | 403;
|
|
164
|
+
}
|
|
165
|
+
|
|
156
166
|
/**
|
|
157
167
|
* Fetches discoverable Antigravity models and normalizes them into canonical model entries.
|
|
158
168
|
*
|
|
159
|
-
* Returns `null` on network
|
|
160
|
-
*
|
|
169
|
+
* Returns `null` on network, server, or payload failures; a 401/403 is reported
|
|
170
|
+
* separately so multi-account discovery can skip a rejected credential.
|
|
171
|
+
* A successful empty roster has `models: []` without `rejectedStatus`.
|
|
161
172
|
*/
|
|
162
173
|
export async function fetchAntigravityDiscoveryModels(
|
|
163
174
|
options: FetchAntigravityDiscoveryModelsOptions,
|
|
164
|
-
): Promise<
|
|
175
|
+
): Promise<AntigravityModelDiscoveryResult | null> {
|
|
165
176
|
const discovered = await fetchAntigravityDiscoveryResponse(options);
|
|
166
|
-
if (!discovered)
|
|
167
|
-
|
|
168
|
-
}
|
|
177
|
+
if (!discovered) return null;
|
|
178
|
+
if ("rejectedStatus" in discovered) return { models: [], rejectedStatus: discovered.rejectedStatus };
|
|
169
179
|
|
|
170
180
|
const models: ModelSpec<"google-gemini-cli">[] = [];
|
|
171
181
|
const apiModels = discovered.payload.models;
|
|
@@ -208,7 +218,7 @@ export async function fetchAntigravityDiscoveryModels(
|
|
|
208
218
|
options.collapseTable === undefined ? undefined : { table: options.collapseTable },
|
|
209
219
|
);
|
|
210
220
|
collapsed.sort((a, b) => a.name.localeCompare(b.name) || a.id.localeCompare(b.id));
|
|
211
|
-
return collapsed;
|
|
221
|
+
return { models: collapsed };
|
|
212
222
|
}
|
|
213
223
|
|
|
214
224
|
/** Advertised image model and serving endpoint for one Antigravity account. */
|
|
@@ -222,14 +232,14 @@ export async function fetchAntigravityImageModel(
|
|
|
222
232
|
options: FetchAntigravityDiscoveryModelsOptions,
|
|
223
233
|
): Promise<AntigravityImageModel | null> {
|
|
224
234
|
const discovered = await fetchAntigravityDiscoveryResponse(options);
|
|
225
|
-
|
|
226
|
-
|
|
235
|
+
if (!discovered || "rejectedStatus" in discovered) return null;
|
|
236
|
+
const id = discovered.payload.imageGenerationModelIds?.find(modelId => modelId.length > 0);
|
|
237
|
+
return id ? { id, endpoint: discovered.endpoint } : null;
|
|
227
238
|
}
|
|
228
239
|
|
|
229
|
-
|
|
230
|
-
payload: AntigravityDiscoveryApiResponse;
|
|
231
|
-
|
|
232
|
-
}
|
|
240
|
+
type AntigravityDiscoveryResponse =
|
|
241
|
+
| { payload: AntigravityDiscoveryApiResponse; endpoint: string }
|
|
242
|
+
| { rejectedStatus: 401 | 403 };
|
|
233
243
|
|
|
234
244
|
async function fetchAntigravityDiscoveryResponse(
|
|
235
245
|
options: FetchAntigravityDiscoveryModelsOptions,
|
|
@@ -243,6 +253,8 @@ async function fetchAntigravityDiscoveryResponse(
|
|
|
243
253
|
? [trimTrailingSlashes(options.endpoint)]
|
|
244
254
|
: DEFAULT_ANTIGRAVITY_DISCOVERY_ENDPOINTS.map(trimTrailingSlashes);
|
|
245
255
|
|
|
256
|
+
let rejectedStatus: 401 | 403 | undefined;
|
|
257
|
+
let transientFailure = false;
|
|
246
258
|
for (const endpoint of endpoints) {
|
|
247
259
|
let response: Response;
|
|
248
260
|
try {
|
|
@@ -257,10 +269,14 @@ async function fetchAntigravityDiscoveryResponse(
|
|
|
257
269
|
signal: options.signal,
|
|
258
270
|
});
|
|
259
271
|
} catch {
|
|
272
|
+
transientFailure = true;
|
|
260
273
|
continue;
|
|
261
274
|
}
|
|
262
275
|
|
|
263
276
|
if (!response.ok) {
|
|
277
|
+
if (response.status === 401) rejectedStatus = 401;
|
|
278
|
+
else if (response.status === 403) rejectedStatus = 403;
|
|
279
|
+
else transientFailure = true;
|
|
264
280
|
continue;
|
|
265
281
|
}
|
|
266
282
|
|
|
@@ -268,16 +284,16 @@ async function fetchAntigravityDiscoveryResponse(
|
|
|
268
284
|
try {
|
|
269
285
|
payload = await response.json();
|
|
270
286
|
} catch {
|
|
287
|
+
transientFailure = true;
|
|
271
288
|
continue;
|
|
272
289
|
}
|
|
273
290
|
|
|
274
291
|
const parsed = parseAntigravityDiscoveryResponse(payload);
|
|
275
|
-
if (parsed) {
|
|
276
|
-
|
|
277
|
-
}
|
|
292
|
+
if (parsed) return { payload: parsed, endpoint };
|
|
293
|
+
transientFailure = true;
|
|
278
294
|
}
|
|
279
295
|
|
|
280
|
-
return null;
|
|
296
|
+
return rejectedStatus !== undefined && !transientFailure ? { rejectedStatus } : null;
|
|
281
297
|
}
|
|
282
298
|
|
|
283
299
|
function parseAntigravityDiscoveryResponse(value: unknown): AntigravityDiscoveryApiResponse | null {
|
package/src/discovery/cursor.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as http2 from "node:http2";
|
|
2
2
|
import { type } from "@linxiraos/pi-omptype";
|
|
3
|
-
import { collapseVariants, type EffortVariantFamily } from "../compat/collapse";
|
|
3
|
+
import { collapseVariants, type EffortVariantFamily, reviewedVariantFamilyId } from "../compat/collapse";
|
|
4
4
|
import { compareRevision, parseRevision } from "../compat/revision";
|
|
5
5
|
import { resolveCatalogAxes, resolveModelPolicy } from "../compat/resolve";
|
|
6
6
|
import { classifyModel } from "../compat/taxonomy";
|
|
@@ -577,14 +577,15 @@ function normalizeRichCursorModels(
|
|
|
577
577
|
const first = entries[0];
|
|
578
578
|
if (!first) continue;
|
|
579
579
|
const dimensions = cursorLaneParameters(first.parameters);
|
|
580
|
-
const
|
|
580
|
+
const richLaneId = cursorLaneId(
|
|
581
581
|
baseId,
|
|
582
582
|
dimensions,
|
|
583
583
|
parameterDefaults,
|
|
584
584
|
first.variant?.isMaxMode === true,
|
|
585
585
|
claimedLaneIds,
|
|
586
586
|
);
|
|
587
|
-
const laneName = cursorLaneName(details,
|
|
587
|
+
const laneName = cursorLaneName(details, richLaneId, baseId);
|
|
588
|
+
const laneId = reviewedCursorLaneId(entries, claimedLaneIds) ?? richLaneId;
|
|
588
589
|
normalized.push(
|
|
589
590
|
...buildRichCursorLane(
|
|
590
591
|
details,
|
|
@@ -706,6 +707,28 @@ function cursorLaneId(
|
|
|
706
707
|
return candidate;
|
|
707
708
|
}
|
|
708
709
|
|
|
710
|
+
/**
|
|
711
|
+
* The reviewed collapse family owning a lane's legacy slugs, when exactly one
|
|
712
|
+
* family claims any of them (slugs no family lists, e.g. a newly added tier,
|
|
713
|
+
* stay in the lane). `AvailableModels` names Grok 4.5/4.6 `grok-4.6` while its
|
|
714
|
+
* slugs are `cursor-grok-4.6-*`; reusing the family id keeps the lane id equal
|
|
715
|
+
* to the `GetUsableModels`-only fallback and the bundled catalog, so a selector
|
|
716
|
+
* survives whichever RPC answered.
|
|
717
|
+
*/
|
|
718
|
+
function reviewedCursorLaneId(entries: readonly NormalizedRichVariant[], claimed: Set<string>): string | undefined {
|
|
719
|
+
let familyId: string | undefined;
|
|
720
|
+
for (const entry of entries) {
|
|
721
|
+
const slug = entry.variant?.legacySlug?.trim();
|
|
722
|
+
const owner = slug ? reviewedVariantFamilyId("cursor", slug) : undefined;
|
|
723
|
+
if (owner === undefined) continue;
|
|
724
|
+
if (familyId !== undefined && owner !== familyId) return undefined;
|
|
725
|
+
familyId = owner;
|
|
726
|
+
}
|
|
727
|
+
if (familyId === undefined || claimed.has(familyId)) return undefined;
|
|
728
|
+
claimed.add(familyId);
|
|
729
|
+
return familyId;
|
|
730
|
+
}
|
|
731
|
+
|
|
709
732
|
function sanitizeCursorLanePart(value: string): string {
|
|
710
733
|
return value
|
|
711
734
|
.toLowerCase()
|
|
@@ -859,7 +882,8 @@ function buildRichCursorLane(
|
|
|
859
882
|
cursorRequiresDataRetention: details.requiresDataRetention,
|
|
860
883
|
cursorSupportsAgent: details.supportsAgent,
|
|
861
884
|
cursorSupportsSandboxing: details.supportsSandboxing,
|
|
862
|
-
isProviderDefault,
|
|
885
|
+
// Not marked `isProviderDefault`: Cursor keeps its bundled startup default, so
|
|
886
|
+
// the account default only picks the lane's default wire id and the badge.
|
|
863
887
|
isRecommended: isProviderDefault || details.defaultOn,
|
|
864
888
|
description:
|
|
865
889
|
variant?.tagline ??
|
package/src/discovery/devin.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
type ClientModelConfig,
|
|
10
10
|
DisplayOption,
|
|
11
11
|
GetCliModelConfigsRequestSchema,
|
|
12
|
+
type GetCliModelConfigsResponse,
|
|
12
13
|
GetCliModelConfigsResponseSchema,
|
|
13
14
|
type Metadata,
|
|
14
15
|
MetadataSchema,
|
|
@@ -346,7 +347,7 @@ export async function fetchDevinModels(
|
|
|
346
347
|
GetCliModelConfigsResponseSchema,
|
|
347
348
|
new Uint8Array(await response.arrayBuffer()),
|
|
348
349
|
);
|
|
349
|
-
return decoded ? normalizeDevinModels(decoded
|
|
350
|
+
return decoded ? normalizeDevinModels(decoded, options.baseUrl) : null;
|
|
350
351
|
} catch {
|
|
351
352
|
return null;
|
|
352
353
|
}
|
|
@@ -497,9 +498,12 @@ function routeDevinFusionLead(spec: ModelSpec<"devin-agent">, lead: ModelSpec<"d
|
|
|
497
498
|
}
|
|
498
499
|
|
|
499
500
|
function normalizeDevinModels(
|
|
500
|
-
|
|
501
|
+
response: GetCliModelConfigsResponse,
|
|
501
502
|
baseUrlOverride: string | undefined,
|
|
502
503
|
): ModelSpec<"devin-agent">[] {
|
|
504
|
+
const configs = response.clientModelConfigs;
|
|
505
|
+
// The model the native client starts this account on (plan-dependent).
|
|
506
|
+
const accountDefaultUid = response.defaultOverrideModelConfig?.modelUid.trim();
|
|
503
507
|
const baseUrl = baseUrlOverride ?? DEVIN_DEFAULT_BASE_URL;
|
|
504
508
|
const specs: ModelSpec<"devin-agent">[] = [];
|
|
505
509
|
const seen = new Set<string>();
|
|
@@ -539,6 +543,7 @@ function normalizeDevinModels(
|
|
|
539
543
|
if (lead === null) continue;
|
|
540
544
|
const spec = devinModelSpec(config, uid, baseUrl, isAssignModelRouter);
|
|
541
545
|
if (lead !== undefined) routeDevinFusionLead(spec, devinModelSpec(liveConfigs.get(lead)!, lead, baseUrl, false));
|
|
546
|
+
if (uid === accountDefaultUid) spec.isProviderDefault = true;
|
|
542
547
|
specs.push(spec);
|
|
543
548
|
// A router is a server-side dispatcher, not an effort tier: it stays a
|
|
544
549
|
// standalone model even when upstream files it under a family.
|
|
@@ -554,5 +559,18 @@ function normalizeDevinModels(
|
|
|
554
559
|
const families = devinDynamicFamilies(lanes.values());
|
|
555
560
|
const dynamic = families.length > 0 ? collapseVariants(specs, { table: { families } }) : specs;
|
|
556
561
|
const collapsed = collapseVariants(dynamic);
|
|
562
|
+
// The account default outranks its family's own default lane when an effort
|
|
563
|
+
// routes to it, from server metadata or the static table: the family starts
|
|
564
|
+
// on that wire uid and effort. Other lanes (a no-thinking `off` default) keep
|
|
565
|
+
// the family's own default.
|
|
566
|
+
const accountFamily = collapsed.find(spec => spec.isProviderDefault && spec.thinking?.effortRouting);
|
|
567
|
+
const accountEffort = THINKING_EFFORTS.find(
|
|
568
|
+
effort => accountFamily?.thinking?.effortRouting?.[effort] === accountDefaultUid,
|
|
569
|
+
);
|
|
570
|
+
if (accountFamily?.thinking && accountEffort !== undefined) {
|
|
571
|
+
accountFamily.thinking = { ...accountFamily.thinking, defaultLevel: accountEffort };
|
|
572
|
+
if (accountFamily.id === accountDefaultUid) delete accountFamily.requestModelId;
|
|
573
|
+
else accountFamily.requestModelId = accountDefaultUid;
|
|
574
|
+
}
|
|
557
575
|
return collapsed.sort((a, b) => a.id.localeCompare(b.id));
|
|
558
576
|
}
|
package/src/hosts.d.ts
CHANGED
|
@@ -15,6 +15,10 @@ export declare const KNOWN_HOSTS: {
|
|
|
15
15
|
readonly providers: readonly ["openai"];
|
|
16
16
|
readonly urlMarkers: readonly ["api.openai.com"];
|
|
17
17
|
};
|
|
18
|
+
/** URL-only: a Codex provider rerouted through a proxy does not imply the subscription backend's capabilities. */
|
|
19
|
+
readonly openaiCodex: {
|
|
20
|
+
readonly urlMarkers: readonly ["chatgpt.com/backend-api", "chat.openai.com/backend-api"];
|
|
21
|
+
};
|
|
18
22
|
readonly azureOpenAI: {
|
|
19
23
|
readonly providers: readonly ["azure"];
|
|
20
24
|
readonly urlMarkers: readonly [".openai.azure.com", "azure.com/openai", "models.inference.ai.azure.com"];
|
package/src/hosts.ts
CHANGED
|
@@ -25,6 +25,8 @@ interface HostClassSpec {
|
|
|
25
25
|
|
|
26
26
|
export const KNOWN_HOSTS = {
|
|
27
27
|
openai: { providers: ["openai"], urlMarkers: ["api.openai.com"] },
|
|
28
|
+
/** URL-only: a Codex provider rerouted through a proxy does not imply the subscription backend's capabilities. */
|
|
29
|
+
openaiCodex: { urlMarkers: ["chatgpt.com/backend-api", "chat.openai.com/backend-api"] },
|
|
28
30
|
azureOpenAI: {
|
|
29
31
|
providers: ["azure"],
|
|
30
32
|
urlMarkers: [".openai.azure.com", "azure.com/openai", "models.inference.ai.azure.com"],
|
package/src/model-cache.d.ts
CHANGED
|
@@ -35,6 +35,12 @@ export interface CacheEntry<TApi extends Api = Api> {
|
|
|
35
35
|
*/
|
|
36
36
|
staticFingerprint: string;
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Closes the shared handle to the default `<agent-dir>/models.db`; the next
|
|
40
|
+
* default-path access reopens it. Call before deleting an agent directory the
|
|
41
|
+
* cache was opened under — Windows cannot remove a database that is still open.
|
|
42
|
+
*/
|
|
43
|
+
export declare function closeModelCache(): void;
|
|
38
44
|
export declare function readModelCache<TApi extends Api>(providerId: string, ttlMs: number, now: () => number, dbPath?: string): CacheEntry<TApi> | null;
|
|
39
45
|
/**
|
|
40
46
|
* Persist a provider snapshot.
|