@oh-my-pi/pi-catalog 16.1.13 → 16.1.15

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 CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.1.14] - 2026-06-22
6
+
7
+ ### Added
8
+
9
+ - Added Sakana AI provider support with Fugu model integration
10
+ - Added Sakana AI/Fugu provider catalog entries with Fugu model discovery and Responses API metadata
11
+ - Added support for "xhigh" reasoning tier across model configurations
12
+ - Added configuration for new models GCP-5.4 Mini, GPT-5.5, and variants
13
+ - Added `devin` variant collapse table to streamline model tiering
14
+
15
+ ### Changed
16
+
17
+ - Updated reasoning label pattern to include "minimal" and "max" efforts
18
+ - Simplified model identification logic for Devin-powered reasoning models
19
+ - Refactored variant routing to consolidate and standardize tier definitions
20
+
5
21
  ## [16.1.13] - 2026-06-22
6
22
 
7
23
  ### Added
@@ -0,0 +1,9 @@
1
+ import type { ModelSpec, ResolvedDevinCompat } from "../types";
2
+ /**
3
+ * Resolve devin-agent (Codeium Cascade) compat. Cascade has no wire
4
+ * reasoning/effort field — effort is selected by routing to a sibling model id
5
+ * (the `thinking.effortRouting` baked by variant-collapse). So the thinking
6
+ * deriver must never fabricate an effort ladder from identity for these models;
7
+ * only explicit routed metadata counts.
8
+ */
9
+ export declare function buildDevinCompat(_spec: ModelSpec<"devin-agent">): ResolvedDevinCompat;
@@ -266,6 +266,15 @@ export declare const CATALOG_PROVIDERS: readonly [{
266
266
  readonly label: "Qwen Portal";
267
267
  readonly oauthProvider: "qwen-portal";
268
268
  };
269
+ }, {
270
+ readonly id: "sakana";
271
+ readonly defaultModel: "fugu";
272
+ readonly envVars: readonly ["SAKANA_API_KEY", "FUGU_API_KEY"];
273
+ readonly createModelManagerOptions: (config: ModelManagerConfig) => import("..").ModelManagerOptions<"openai-responses", unknown>;
274
+ readonly dynamicModelsAuthoritative: true;
275
+ readonly catalogDiscovery: {
276
+ readonly label: "Sakana AI";
277
+ };
269
278
  }, {
270
279
  readonly id: "synthetic";
271
280
  readonly defaultModel: "hf:zai-org/GLM-5.1";
@@ -313,6 +313,13 @@ export interface MoonshotModelManagerConfig {
313
313
  fetch?: FetchImpl;
314
314
  }
315
315
  export declare function moonshotModelManagerOptions(config?: MoonshotModelManagerConfig): ModelManagerOptions<"openai-completions">;
316
+ export declare const SAKANA_FUGU_STATIC_MODELS: readonly ModelSpec<"openai-responses">[];
317
+ export interface SakanaModelManagerConfig {
318
+ apiKey?: string;
319
+ baseUrl?: string;
320
+ fetch?: FetchImpl;
321
+ }
322
+ export declare function sakanaModelManagerOptions(config?: SakanaModelManagerConfig): ModelManagerOptions<"openai-responses">;
316
323
  export interface QwenPortalModelManagerConfig {
317
324
  apiKey?: string;
318
325
  baseUrl?: string;
@@ -439,6 +439,7 @@ export interface ResolvedOpenAIResponsesCompat extends ResolvedOpenAISharedCompa
439
439
  supportsImageDetailOriginal: boolean;
440
440
  requiresJuiceZeroHack: boolean;
441
441
  supportsObfuscationOptOut: boolean;
442
+ streamIdleTimeoutMs?: number;
442
443
  }
443
444
  /**
444
445
  * OpenRouter is a pseudo API: runtime dispatch can use either Responses
@@ -456,10 +457,28 @@ export type ResolvedAnthropicCompat = Required<AnthropicCompat> & {
456
457
  */
457
458
  officialEndpoint: boolean;
458
459
  };
460
+ /**
461
+ * Compatibility settings for the devin-agent (Codeium Cascade) API. Cascade
462
+ * selects reasoning effort only by routing to a sibling model id (the
463
+ * `thinking.effortRouting` baked by variant-collapse), never by a wire
464
+ * reasoning/effort field, so the model-thinking deriver must not invent an
465
+ * effort ladder from identity for these models.
466
+ */
467
+ export interface DevinCompat {
468
+ /**
469
+ * Trust only explicit `thinking` metadata; never derive a thinking surface
470
+ * from model identity. A reasoning model with no explicit routed thinking
471
+ * resolves to `thinking: undefined` (`reasoning: true`, no controllable
472
+ * effort) instead of a fabricated minimal/low/medium/high ladder.
473
+ */
474
+ trustExplicitThinkingOnly?: boolean;
475
+ }
476
+ /** Fully-resolved devin-agent compat view. */
477
+ export type ResolvedDevinCompat = Required<DevinCompat>;
459
478
  /** Sparse, user-authored compat overrides for a given API (models.json / config vocabulary). */
460
- export type CompatConfigOf<TApi extends Api> = TApi extends "openai-completions" | "openrouter" | "openai-responses" | "azure-openai-responses" | "openai-codex-responses" ? OpenAICompat : TApi extends "anthropic-messages" ? AnthropicCompat : undefined;
479
+ export type CompatConfigOf<TApi extends Api> = TApi extends "openai-completions" | "openrouter" | "openai-responses" | "azure-openai-responses" | "openai-codex-responses" ? OpenAICompat : TApi extends "anthropic-messages" ? AnthropicCompat : TApi extends "devin-agent" ? DevinCompat : undefined;
461
480
  /** Resolved compat for a given API: complete record, materialized once by `buildModel`. */
462
- export type CompatOf<TApi extends Api> = TApi extends "openrouter" ? ResolvedOpenRouterCompat : TApi extends "openai-completions" ? ResolvedOpenAICompat : TApi extends "openai-responses" | "azure-openai-responses" | "openai-codex-responses" ? ResolvedOpenAIResponsesCompat : TApi extends "anthropic-messages" ? ResolvedAnthropicCompat : undefined;
481
+ export type CompatOf<TApi extends Api> = TApi extends "openrouter" ? ResolvedOpenRouterCompat : TApi extends "openai-completions" ? ResolvedOpenAICompat : TApi extends "openai-responses" | "azure-openai-responses" | "openai-codex-responses" ? ResolvedOpenAIResponsesCompat : TApi extends "anthropic-messages" ? ResolvedAnthropicCompat : TApi extends "devin-agent" ? ResolvedDevinCompat : undefined;
463
482
  export interface Model<TApi extends Api = Api> {
464
483
  id: string;
465
484
  /**
@@ -57,6 +57,7 @@ export interface VariantCollapseTable {
57
57
  export declare const ANTIGRAVITY_VARIANT_COLLAPSE_TABLE: VariantCollapseTable;
58
58
  /** `google-gemini-cli` (cloudcode-pa): Gemini 3.x on the level transport (official CLI parity). */
59
59
  export declare const GEMINI_CLI_VARIANT_COLLAPSE_TABLE: VariantCollapseTable;
60
+ export declare const DEVIN_VARIANT_COLLAPSE_TABLE: VariantCollapseTable;
60
61
  /** Provider id → hand collapse table. The CCA providers diverge on thinking transport. */
61
62
  export declare const VARIANT_COLLAPSE_TABLES: Readonly<Record<string, VariantCollapseTable>>;
62
63
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-catalog",
4
- "version": "16.1.13",
4
+ "version": "16.1.15",
5
5
  "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -34,12 +34,12 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@bufbuild/protobuf": "^2.12.0",
37
- "@oh-my-pi/pi-utils": "16.1.13",
37
+ "@oh-my-pi/pi-utils": "16.1.15",
38
38
  "arktype": "^2.2.0",
39
39
  "zod": "^4"
40
40
  },
41
41
  "devDependencies": {
42
- "@oh-my-pi/pi-ai": "16.1.13",
42
+ "@oh-my-pi/pi-ai": "16.1.15",
43
43
  "@types/bun": "^1.3.14"
44
44
  },
45
45
  "engines": {
package/src/build.ts CHANGED
@@ -10,6 +10,7 @@
10
10
  * compat per request.
11
11
  */
12
12
  import { buildAnthropicCompat } from "./compat/anthropic";
13
+ import { buildDevinCompat } from "./compat/devin";
13
14
  import { buildOpenAICompat, buildOpenAIResponsesCompat, buildOpenRouterCompat } from "./compat/openai";
14
15
  import { resolveModelThinking } from "./model-thinking";
15
16
  import type { Api, CompatOf, Model, ModelSpec } from "./types";
@@ -38,6 +39,8 @@ export function buildCompat(spec: ModelSpec<Api>): CompatOf<Api> {
38
39
  return buildOpenAIResponsesCompat(spec as ModelSpec<"openai-responses">);
39
40
  case "anthropic-messages":
40
41
  return buildAnthropicCompat(spec as ModelSpec<"anthropic-messages">);
42
+ case "devin-agent":
43
+ return buildDevinCompat(spec as ModelSpec<"devin-agent">);
41
44
  default:
42
45
  return undefined;
43
46
  }
@@ -0,0 +1,12 @@
1
+ import type { ModelSpec, ResolvedDevinCompat } from "../types";
2
+
3
+ /**
4
+ * Resolve devin-agent (Codeium Cascade) compat. Cascade has no wire
5
+ * reasoning/effort field — effort is selected by routing to a sibling model id
6
+ * (the `thinking.effortRouting` baked by variant-collapse). So the thinking
7
+ * deriver must never fabricate an effort ladder from identity for these models;
8
+ * only explicit routed metadata counts.
9
+ */
10
+ export function buildDevinCompat(_spec: ModelSpec<"devin-agent">): ResolvedDevinCompat {
11
+ return { trustExplicitThinkingOnly: true };
12
+ }
@@ -535,6 +535,7 @@ export function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): Resol
535
535
  emptyLengthFinishIsContextError: spec.provider === "ollama",
536
536
  usesOpenAIToolCallIdLimit: spec.provider === "openai",
537
537
  promptCacheSessionHeader: spec.provider === "xai-oauth" ? "x-grok-conv-id" : undefined,
538
+ streamIdleTimeoutMs: spec.compat?.streamIdleTimeoutMs,
538
539
  };
539
540
  applyCompatOverrides(compat, spec.compat);
540
541
  if (spec.compat?.reasoningDisableMode === undefined) {
@@ -17,9 +17,8 @@ const DEFAULT_CONTEXT_WINDOW = 200_000;
17
17
  const DEFAULT_MAX_TOKENS = 64_000;
18
18
 
19
19
  /** Best-effort match for labels whose wording implies a thinking / reasoning-effort variant. */
20
- const REASONING_LABEL_PATTERN = /think|thinking|high|medium|low|xhigh|reasoning/i;
20
+ const REASONING_LABEL_PATTERN = /think|thinking|minimal|high|medium|low|xhigh|max|reasoning/i;
21
21
  const NO_REASONING_LABEL_PATTERN = /\bno thinking\b/i;
22
-
23
22
  function supportsDevinThinking(config: ClientModelConfig): boolean {
24
23
  if (NO_REASONING_LABEL_PATTERN.test(config.label)) return false;
25
24
  return config.modelInfo?.modelFeatures?.supportsThinking === true || REASONING_LABEL_PATTERN.test(config.label);
@@ -35,6 +35,7 @@ import type {
35
35
  CompatOf,
36
36
  Model,
37
37
  ModelSpec,
38
+ ResolvedDevinCompat,
38
39
  ResolvedOpenAICompat,
39
40
  ResolvedOpenAIResponsesCompat,
40
41
  ThinkingConfig,
@@ -61,6 +62,10 @@ const GPT_5_1_CODEX_MINI_EFFORTS: readonly Effort[] = [Effort.Medium, Effort.Hig
61
62
  const LOW_MEDIUM_HIGH_REASONING_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High];
62
63
  const GLM_52_HIGH_MAX_REASONING_EFFORTS: readonly Effort[] = [Effort.High, Effort.XHigh];
63
64
 
65
+ const FUGU_REASONING_EFFORTS: readonly Effort[] = [Effort.High, Effort.XHigh];
66
+ const FUGU_REASONING_EFFORT_MAP: Readonly<EffortMap> = {
67
+ [Effort.XHigh]: "max",
68
+ };
64
69
  type EffortMap = Partial<Record<Effort, string>>;
65
70
 
66
71
  const GROQ_QWEN3_32B_REASONING_EFFORT_MAP: Readonly<EffortMap> = {
@@ -153,6 +158,10 @@ export function resolveModelThinking<TApi extends Api>(
153
158
  if (spec.thinking && Array.isArray(spec.thinking.efforts) && spec.thinking.efforts.length > 0) {
154
159
  return fillThinkingWireDefaults(spec, compat, spec.thinking);
155
160
  }
161
+ // Cascade selects effort only by routing to a sibling model id, so a Devin
162
+ // model with no explicit routed thinking has no controllable surface —
163
+ // never fabricate an effort ladder from identity.
164
+ if ((compat as ResolvedDevinCompat | undefined)?.trustExplicitThinkingOnly === true) return undefined;
156
165
  // Empty/malformed explicit metadata is treated as absent — infer instead.
157
166
  return deriveThinking(spec, compat);
158
167
  }
@@ -301,6 +310,9 @@ function getModelDefinedEfforts<TApi extends Api>(
301
310
  return GLM_52_HIGH_MAX_REASONING_EFFORTS;
302
311
  }
303
312
  }
313
+ if (isSakanaFuguReasoningModel(spec)) {
314
+ return FUGU_REASONING_EFFORTS;
315
+ }
304
316
  return isOpenAICompatReasoningApi(spec.api) &&
305
317
  (isMinimaxM2FamilyModelId(spec.id) ||
306
318
  isOpenAIGptOssModelId(spec.id) ||
@@ -377,6 +389,9 @@ function inferDetectedEffortMap<TApi extends Api>(
377
389
  if (isOllamaCloudGlm52ReasoningEffortModel(spec)) {
378
390
  return GLM_52_XHIGH_MAX_EFFORT_MAP;
379
391
  }
392
+ if (isSakanaFuguReasoningModel(spec)) {
393
+ return FUGU_REASONING_EFFORT_MAP;
394
+ }
380
395
  if (!isOpenAICompatReasoningApi(spec.api)) {
381
396
  return undefined;
382
397
  }
@@ -400,6 +415,10 @@ function inferDetectedEffortMap<TApi extends Api>(
400
415
  return map;
401
416
  }
402
417
 
418
+ function isSakanaFuguReasoningModel<TApi extends Api>(spec: ModelSpec<TApi>): boolean {
419
+ return spec.provider === "sakana" && /^fugu(?:$|-)/i.test(spec.id);
420
+ }
421
+
403
422
  function isDeepseekReasoningModel<TApi extends Api>(spec: ModelSpec<TApi>): boolean {
404
423
  if (!spec.reasoning) return false;
405
424
  const lowerId = spec.id.toLowerCase();