@oh-my-pi/pi-catalog 18.2.11 → 18.3.1
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 +21 -0
- package/README.md +1 -1
- package/THIRD-PARTY-NOTICES.txt +3 -3
- package/dist/types/compat/auth-ids.d.ts +1 -1
- package/dist/types/compat/fallback-credit.d.ts +7 -0
- package/dist/types/compat/output-limits.d.ts +5 -0
- package/dist/types/compat/provider-ids.d.ts +1 -1
- package/dist/types/compat/server-side-fallback.d.ts +7 -0
- package/dist/types/compat/types.d.ts +4 -0
- package/dist/types/discovery/cursor-proto.d.ts +1 -1
- package/dist/types/discovery/devin-proto.d.ts +1 -1
- package/dist/types/types.d.ts +37 -7
- package/package.json +8 -5
- package/src/compat/auth-ids.ts +1 -0
- package/src/compat/axes.ts +25 -0
- package/src/compat/fallback-credit.ts +13 -0
- package/src/compat/output-limits.ts +8 -0
- package/src/compat/provider-ids.ts +1 -0
- package/src/compat/resolve.ts +2 -0
- package/src/compat/rules/README.md +4 -0
- package/src/compat/rules/auth/anthropic.kdl +1 -0
- package/src/compat/rules/auth/apple.kdl +4 -0
- package/src/compat/rules/auth/openai-codex.kdl +1 -0
- package/src/compat/rules/auth/xai-oauth.kdl +1 -0
- package/src/compat/rules/classes/anthropic.kdl +46 -16
- package/src/compat/rules/classes/openai.kdl +3 -0
- package/src/compat/rules/providers/anthropic.kdl +15 -0
- package/src/compat/rules/providers/apple.kdl +8 -0
- package/src/compat/rules/providers/yolo-auto.kdl +8 -2
- package/src/compat/rules.json +1 -1
- package/src/compat/server-side-fallback.ts +13 -0
- package/src/compat/types.ts +4 -0
- package/src/discovery/codex.ts +29 -4
- package/src/discovery/cursor-proto.ts +1 -1
- package/src/discovery/devin-proto.ts +1 -1
- package/src/discovery/devin.ts +60 -1
- package/src/models.json +1 -1
- package/src/provider-models/cache-provider-id.ts +5 -0
- package/src/provider-models/openai-compat.ts +30 -7
- package/src/provider-models/special.ts +12 -2
- package/src/types.ts +39 -6
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Model } from "../types";
|
|
2
|
+
import { resolveCatalogPolicy } from "./catalog-policy";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Ordered model ids for Anthropic's server-side refusal `fallbacks` chain,
|
|
6
|
+
* authored on the `server-side-fallback-models` catalog axis. Empty when no
|
|
7
|
+
* rule assigns a chain (the model or host does not support the feature).
|
|
8
|
+
*/
|
|
9
|
+
export function serverSideFallbackModels(model: Model): readonly string[] {
|
|
10
|
+
const value = resolveCatalogPolicy(model).serverSideFallbackModels;
|
|
11
|
+
if (!Array.isArray(value)) return [];
|
|
12
|
+
return value.filter((entry): entry is string => typeof entry === "string");
|
|
13
|
+
}
|
package/src/compat/types.ts
CHANGED
|
@@ -552,6 +552,10 @@ export interface CompiledAuthProvider {
|
|
|
552
552
|
name: string;
|
|
553
553
|
env?: { vars: string[] } | { hook: string };
|
|
554
554
|
allowsMissingApiKey?: boolean;
|
|
555
|
+
/** Qualify credential and usage-report identity by org when an email may have multiple subscriptions. */
|
|
556
|
+
orgScopedIdentity?: boolean;
|
|
557
|
+
/** Environment variables carrying this provider's own OAuth bearer, excluding borrowed API-key aliases. */
|
|
558
|
+
oauthTokenEnv?: string[];
|
|
555
559
|
/** APIs whose provider transport resolves credentials without a stored account. */
|
|
556
560
|
nativeAuthApis?: string[];
|
|
557
561
|
available?: boolean;
|
package/src/discovery/codex.ts
CHANGED
|
@@ -70,6 +70,7 @@ const codexModelEntrySchema = type({
|
|
|
70
70
|
"prefer_websockets?": "unknown",
|
|
71
71
|
"use_responses_lite?": "unknown",
|
|
72
72
|
"tool_mode?": "unknown",
|
|
73
|
+
"available_access_programs?": "unknown",
|
|
73
74
|
});
|
|
74
75
|
|
|
75
76
|
const codexModelsResponseSchema = type({
|
|
@@ -161,7 +162,7 @@ export async function fetchCodexModels(options: CodexModelDiscoveryOptions): Pro
|
|
|
161
162
|
continue;
|
|
162
163
|
}
|
|
163
164
|
|
|
164
|
-
const models = normalizeCodexModels(payload, baseUrl);
|
|
165
|
+
const models = normalizeCodexModels(payload, baseUrl, options.accountId);
|
|
165
166
|
if (models === null) {
|
|
166
167
|
continue;
|
|
167
168
|
}
|
|
@@ -223,7 +224,11 @@ function normalizeClientVersion(value: unknown): string | undefined {
|
|
|
223
224
|
return trimmed;
|
|
224
225
|
}
|
|
225
226
|
|
|
226
|
-
function normalizeCodexModels(
|
|
227
|
+
function normalizeCodexModels(
|
|
228
|
+
payload: unknown,
|
|
229
|
+
baseUrl: string,
|
|
230
|
+
accountId: string | undefined,
|
|
231
|
+
): ModelSpec<"openai-codex-responses">[] | null {
|
|
227
232
|
const parsedResponse = codexModelsResponseSchema(payload);
|
|
228
233
|
if (parsedResponse instanceof type.errors) {
|
|
229
234
|
return null;
|
|
@@ -250,10 +255,10 @@ function normalizeCodexModels(payload: unknown, baseUrl: string): ModelSpec<"ope
|
|
|
250
255
|
const normalized: NormalizedCodexModel[] = [];
|
|
251
256
|
for (const parsed of parsedEntries) {
|
|
252
257
|
const canonicalSlug = plainCounterpartForWorkerSlug(parsed.slug, bundledCodexModelIds) ?? parsed.slug;
|
|
253
|
-
normalized.push(buildNormalizedCodexModel(parsed, parsed.slug, canonicalSlug, baseUrl));
|
|
258
|
+
normalized.push(buildNormalizedCodexModel(parsed, parsed.slug, canonicalSlug, baseUrl, accountId));
|
|
254
259
|
const plainSlug = canonicalSlug !== parsed.slug ? canonicalSlug : null;
|
|
255
260
|
if (plainSlug && !advertisedSlugs.has(plainSlug)) {
|
|
256
|
-
normalized.push(buildNormalizedCodexModel(parsed, plainSlug, canonicalSlug, baseUrl));
|
|
261
|
+
normalized.push(buildNormalizedCodexModel(parsed, plainSlug, canonicalSlug, baseUrl, accountId));
|
|
257
262
|
}
|
|
258
263
|
}
|
|
259
264
|
|
|
@@ -288,6 +293,7 @@ function plainCounterpartForWorkerSlug(slug: string, bundledCodexModelIds: Reado
|
|
|
288
293
|
|
|
289
294
|
interface ParsedCodexModelEntry {
|
|
290
295
|
slug: string;
|
|
296
|
+
cyberPrograms: string[] | undefined;
|
|
291
297
|
name: string;
|
|
292
298
|
contextWindow: number | null;
|
|
293
299
|
maxContextWindow: number | null;
|
|
@@ -316,8 +322,19 @@ function parseCodexModelEntry(entry: unknown): ParsedCodexModelEntry | null {
|
|
|
316
322
|
return null;
|
|
317
323
|
}
|
|
318
324
|
|
|
325
|
+
const programs = payload.available_access_programs;
|
|
326
|
+
let cyberPrograms: string[] | undefined;
|
|
327
|
+
if (programs !== null && typeof programs === "object" && "cyber" in programs && Array.isArray(programs.cyber)) {
|
|
328
|
+
cyberPrograms = [];
|
|
329
|
+
for (const program of programs.cyber) {
|
|
330
|
+
const name = toNonEmptyString(program);
|
|
331
|
+
if (name) cyberPrograms.push(name);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
319
335
|
return {
|
|
320
336
|
slug,
|
|
337
|
+
cyberPrograms,
|
|
321
338
|
name: toNonEmptyString(payload.display_name) ?? slug,
|
|
322
339
|
contextWindow: toPositiveInt(payload.context_window),
|
|
323
340
|
maxContextWindow: toPositiveInt(payload.max_context_window),
|
|
@@ -342,6 +359,7 @@ function buildNormalizedCodexModel(
|
|
|
342
359
|
slug: string,
|
|
343
360
|
canonicalSlug: string,
|
|
344
361
|
baseUrl: string,
|
|
362
|
+
accountId: string | undefined,
|
|
345
363
|
): NormalizedCodexModel {
|
|
346
364
|
// Codex discovery historically omitted `context_window` for GPT-5.6-family
|
|
347
365
|
// SKUs (#5705); luna/sol/terra additionally floor the reported value because
|
|
@@ -371,6 +389,13 @@ function buildNormalizedCodexModel(
|
|
|
371
389
|
api: "openai-codex-responses",
|
|
372
390
|
provider: "openai-codex",
|
|
373
391
|
baseUrl,
|
|
392
|
+
...(accountId && accountId.trim().length > 0
|
|
393
|
+
? {
|
|
394
|
+
accountAccess: {
|
|
395
|
+
[accountId]: parsed.cyberPrograms === undefined ? {} : { cyberPrograms: parsed.cyberPrograms },
|
|
396
|
+
},
|
|
397
|
+
}
|
|
398
|
+
: {}),
|
|
374
399
|
reasoning: parsed.reasoning,
|
|
375
400
|
input: parsed.input,
|
|
376
401
|
// Codex discovery omits pricing; documented subscription credit-equivalent
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @generated by packages/catalog/scripts/proto-parser.ts - DO NOT EDIT
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Cursor agent protocol declarations used by
|
|
4
|
+
* Cursor agent protocol declarations used by omp.
|
|
5
5
|
*
|
|
6
6
|
* Each declaration retains only fields consumed by the client or its protocol tests.
|
|
7
7
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @generated by packages/catalog/scripts/proto-parser.ts - DO NOT EDIT
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Devin protocol declarations used by
|
|
4
|
+
* Devin protocol declarations used by omp.
|
|
5
5
|
*
|
|
6
6
|
* Each declaration retains only fields consumed by the client or its protocol tests.
|
|
7
7
|
*/
|
package/src/discovery/devin.ts
CHANGED
|
@@ -453,6 +453,51 @@ function devinModelSpec(
|
|
|
453
453
|
return spec;
|
|
454
454
|
}
|
|
455
455
|
|
|
456
|
+
/**
|
|
457
|
+
* Lead chat uid of a Fusion pairing `fusion-<lead>[-fast]-sidekick-<sidekick>`.
|
|
458
|
+
* An exact live lead uid wins, so leads whose own uid ends in `-fast`
|
|
459
|
+
* (`swe-1-6-fast`) route as written. Otherwise `-fast` selects the lead's
|
|
460
|
+
* priority lane when the server lists one, then the standard lane.
|
|
461
|
+
*
|
|
462
|
+
* Returns `undefined` for uids that are not pairings and `null` for pairings
|
|
463
|
+
* whose lead is not live: the composite uid itself is never servable.
|
|
464
|
+
*/
|
|
465
|
+
function devinFusionLeadUid(uid: string, liveUids: ReadonlyMap<string, unknown>): string | null | undefined {
|
|
466
|
+
if (!uid.startsWith("fusion-")) return undefined;
|
|
467
|
+
const cut = uid.indexOf("-sidekick-");
|
|
468
|
+
if (cut <= "fusion-".length) return undefined;
|
|
469
|
+
const lead = uid.slice("fusion-".length, cut);
|
|
470
|
+
if (liveUids.has(lead)) return lead;
|
|
471
|
+
if (lead.endsWith("-fast")) {
|
|
472
|
+
const base = lead.slice(0, -"-fast".length);
|
|
473
|
+
if (liveUids.has(`${base}-priority`)) return `${base}-priority`;
|
|
474
|
+
if (liveUids.has(base)) return base;
|
|
475
|
+
}
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Point a Fusion pairing at its lead. omp runs only the lead (the sidekick is
|
|
481
|
+
* paired by the native client), so the limits and pricing a caller budgets
|
|
482
|
+
* against are the lead's, not the composite card's.
|
|
483
|
+
*/
|
|
484
|
+
function routeDevinFusionLead(spec: ModelSpec<"devin-agent">, lead: ModelSpec<"devin-agent">): void {
|
|
485
|
+
spec.requestModelId = lead.id;
|
|
486
|
+
spec.reasoning = lead.reasoning;
|
|
487
|
+
spec.input = lead.input;
|
|
488
|
+
spec.supportsTools = lead.supportsTools;
|
|
489
|
+
spec.cost = lead.cost;
|
|
490
|
+
spec.contextWindow = lead.contextWindow;
|
|
491
|
+
spec.maxTokens = lead.maxTokens;
|
|
492
|
+
if (lead.compat?.supportsParallelToolCalls) {
|
|
493
|
+
spec.compat = { ...spec.compat, supportsParallelToolCalls: true };
|
|
494
|
+
} else if (spec.compat?.supportsParallelToolCalls) {
|
|
495
|
+
const { supportsParallelToolCalls: _, ...rest } = spec.compat;
|
|
496
|
+
if (Object.keys(rest).length > 0) spec.compat = rest;
|
|
497
|
+
else delete spec.compat;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
456
501
|
function normalizeDevinModels(
|
|
457
502
|
configs: readonly ClientModelConfig[],
|
|
458
503
|
baseUrlOverride: string | undefined,
|
|
@@ -461,6 +506,11 @@ function normalizeDevinModels(
|
|
|
461
506
|
const specs: ModelSpec<"devin-agent">[] = [];
|
|
462
507
|
const seen = new Set<string>();
|
|
463
508
|
const lanes = new Map<string, DevinFamilyLane>();
|
|
509
|
+
const liveConfigs = new Map<string, ClientModelConfig>();
|
|
510
|
+
for (const config of configs) {
|
|
511
|
+
const uid = config.modelUid.trim();
|
|
512
|
+
if (!config.disabled && uid && !liveConfigs.has(uid)) liveConfigs.set(uid, config);
|
|
513
|
+
}
|
|
464
514
|
|
|
465
515
|
for (const config of configs) {
|
|
466
516
|
if (config.disabled) {
|
|
@@ -482,7 +532,16 @@ function normalizeDevinModels(
|
|
|
482
532
|
// `fusion-sidekick-*`) that are themselves valid chat uids. Only the
|
|
483
533
|
// former take the `AssignModel` path — sending a composite uid there 404s.
|
|
484
534
|
const isAssignModelRouter = isRouter && (config.modelInfo?.harnessUids.length ?? 0) === 0;
|
|
485
|
-
|
|
535
|
+
// Fusion pairings are orchestrated by the native client: it runs the lead
|
|
536
|
+
// model as an ordinary chat uid and pairs a sidekick locally. The server
|
|
537
|
+
// has no provider for the composite uid itself (`permission_denied: no API
|
|
538
|
+
// providers are available`), so the chat request carries the lead uid and
|
|
539
|
+
// a pairing without a live lead is not listed.
|
|
540
|
+
const lead = devinFusionLeadUid(uid, liveConfigs);
|
|
541
|
+
if (lead === null) continue;
|
|
542
|
+
const spec = devinModelSpec(config, uid, baseUrl, isAssignModelRouter);
|
|
543
|
+
if (lead !== undefined) routeDevinFusionLead(spec, devinModelSpec(liveConfigs.get(lead)!, lead, baseUrl, false));
|
|
544
|
+
specs.push(spec);
|
|
486
545
|
// A router is a server-side dispatcher, not an effort tier: it stays a
|
|
487
546
|
// standalone model even when upstream files it under a family.
|
|
488
547
|
if (!isRouter) {
|