@oh-my-pi/pi-catalog 16.4.2 → 16.4.3

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,13 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.4.3] - 2026-07-11
6
+
7
+ ### Fixed
8
+
9
+ - Fixed parsing of SAP AI Core Claude model IDs in version-first format (e.g., anthropic--claude-4.8-opus), restoring adaptive thinking metadata and capability gates.
10
+ - Fixed GitHub Copilot Business and Enterprise model discovery to correctly preserve vision capabilities instead of downgrading models to text-only.
11
+
5
12
  ## [16.4.2] - 2026-07-10
6
13
 
7
14
  ### Fixed
@@ -28,13 +28,7 @@ export type ParsedGitHubCopilotApiKey = {
28
28
  apiEndpoint?: string;
29
29
  };
30
30
  export declare function isPublicGitHubHost(host: string): boolean;
31
- /**
32
- * Canonical personal-Copilot API host. The business
33
- * (`api.business.githubcopilot.com`) and enterprise (`copilot-api.{domain}`)
34
- * endpoints respond with HTTP 400 "vision is not supported" on image inputs,
35
- * so catalog discovery and capability gates MUST honour the upstream's
36
- * `supports.vision` flag only for this exact base URL.
37
- */
31
+ /** Canonical personal-Copilot API host. */
38
32
  export declare const PERSONAL_GITHUB_COPILOT_BASE_URL: "https://api.githubcopilot.com";
39
33
  /** `true` when the resolved base URL is the canonical personal-Copilot host. */
40
34
  export declare function isPersonalGitHubCopilotBaseUrl(baseUrl: string | undefined): boolean;
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.4.2",
4
+ "version": "16.4.3",
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.4.2",
37
+ "@oh-my-pi/pi-utils": "16.4.3",
38
38
  "arktype": "2.2.2",
39
39
  "zod": "^4"
40
40
  },
41
41
  "devDependencies": {
42
- "@oh-my-pi/pi-ai": "16.4.2",
42
+ "@oh-my-pi/pi-ai": "16.4.3",
43
43
  "@types/bun": "^1.3.14"
44
44
  },
45
45
  "engines": {
@@ -106,15 +106,20 @@ export const parseGeminiModel = parser((modelId): GeminiModel | null => {
106
106
  });
107
107
 
108
108
  export const parseAnthropicModel = parser((modelId): AnthropicModel | null => {
109
- const match = /claude-(opus|sonnet|fable|mythos)-(\d{1,2}(?:[.-]\d{1,2}){0,2})\b/.exec(modelId);
110
- if (!match) {
109
+ const kindFirst = /claude-(opus|sonnet|fable|mythos)-(\d{1,2}(?:[.-]\d{1,2}){0,2})\b/.exec(modelId);
110
+ const versionFirst = kindFirst
111
+ ? null
112
+ : /claude-(\d{1,2}(?:[.-]\d{1,2}){0,2})-(opus|sonnet|fable|mythos)\b/.exec(modelId);
113
+ const kind = kindFirst?.[1] ?? versionFirst?.[2];
114
+ const versionInput = kindFirst?.[2] ?? versionFirst?.[1];
115
+ if (!kind || !versionInput) {
111
116
  return null;
112
117
  }
113
- const version = parseSemVer(match[2]);
118
+ const version = parseSemVer(versionInput);
114
119
  if (!version) {
115
120
  return null;
116
121
  }
117
- return { family: "anthropic", kind: match[1] as AnthropicKind, version };
122
+ return { family: "anthropic", kind: kind as AnthropicKind, version };
118
123
  });
119
124
 
120
125
  export const parseOpenAIModel = parser((modelId): OpenAIModel | null => {
@@ -351,11 +351,14 @@ function fingerprintStatic<TApi extends Api>(
351
351
  function mergeDynamicModel<TApi extends Api>(existingModel: Model<TApi>, dynamicModel: Model<TApi>): Model<TApi> {
352
352
  // When discovery resolves the same model id to a different endpoint (e.g.
353
353
  // a GitHub Copilot business/enterprise host), the bundled reference's
354
- // capabilities are pinned to the canonical host and no longer apply
355
- // honour the dynamic value alone. Same-endpoint merges still OR-upgrade so
356
- // a discovery that omits the capability flag doesn't drop bundled vision.
354
+ // capabilities are pinned to another endpoint and no longer apply. Copilot
355
+ // dynamic discovery also pre-applies the correct image fallback for omitted
356
+ // `supports.vision`, so its explicit `false` must not be OR-upgraded by the
357
+ // canonical bundled model.
357
358
  const endpointChanged = existingModel.baseUrl !== dynamicModel.baseUrl;
358
- const supportsImage = endpointChanged
359
+ const dynamicInputAuthoritative =
360
+ endpointChanged || (existingModel.provider === "github-copilot" && dynamicModel.provider === "github-copilot");
361
+ const supportsImage = dynamicInputAuthoritative
359
362
  ? dynamicModel.input.includes("image")
360
363
  : existingModel.input.includes("image") || dynamicModel.input.includes("image");
361
364
  // Re-build from spec stage: sparse compat comes from `compatConfig` (the
@@ -3924,16 +3924,13 @@ export function githubCopilotModelManagerOptions(config?: GithubCopilotModelMana
3924
3924
  ? entry.name
3925
3925
  : (reference?.name ?? defaults.name);
3926
3926
  const api = inferCopilotApi(defaults.id);
3927
- // `supports.vision` reports the model's intrinsic capability, but
3928
- // the business/enterprise endpoints respond `400 vision is not
3929
- // supported` on image inputs. Only honour the flag for the
3930
- // canonical personal-Copilot host.
3931
3927
  const supportsVision = extractCopilotSupportsVision(entry);
3932
- const input: ModelSpec<Api>["input"] = isPersonalGitHubCopilotBaseUrl(baseUrl)
3933
- ? supportsVision
3928
+ const input: ModelSpec<Api>["input"] =
3929
+ supportsVision === true
3934
3930
  ? ["text", "image"]
3935
- : (reference?.input ?? defaults.input)
3936
- : ["text"];
3931
+ : supportsVision === false || !isPersonalGitHubCopilotBaseUrl(baseUrl)
3932
+ ? ["text"]
3933
+ : (reference?.input ?? defaults.input);
3937
3934
  // With COPILOT_API_HEADERS the served window is the long-context
3938
3935
  // ceiling; the default tier ends at token_prices.default.context_max
3939
3936
  // prompt tokens. Cap the base entry to the default tier — the long
@@ -45,13 +45,7 @@ export function isPublicGitHubHost(host: string): boolean {
45
45
  return PUBLIC_GITHUB_HOSTS.has(host.trim().toLowerCase());
46
46
  }
47
47
 
48
- /**
49
- * Canonical personal-Copilot API host. The business
50
- * (`api.business.githubcopilot.com`) and enterprise (`copilot-api.{domain}`)
51
- * endpoints respond with HTTP 400 "vision is not supported" on image inputs,
52
- * so catalog discovery and capability gates MUST honour the upstream's
53
- * `supports.vision` flag only for this exact base URL.
54
- */
48
+ /** Canonical personal-Copilot API host. */
55
49
  export const PERSONAL_GITHUB_COPILOT_BASE_URL = "https://api.githubcopilot.com" as const;
56
50
 
57
51
  /** `true` when the resolved base URL is the canonical personal-Copilot host. */