@sayknow-cli/ai 0.5.11 → 0.5.13

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,7 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
- ## [0.5.11] - 2026-09-10
5
+ ## [0.5.13] - 2026-09-15
6
+
7
+ ## [0.5.12] - 2026-09-15
8
+ ### Added
9
+
10
+ - `detectDiscoveredApiFamily` infers Anthropic Messages vs OpenAI Completions for mixed OpenAI-compatible `/v1/models` catalogs from `owned_by` then the model id (ported from upstream #5187).
6
11
 
7
12
  ## [0.5.10] - 2026-09-10
8
13
 
@@ -1,4 +1,23 @@
1
1
  import type { Api, FetchImpl, Model, Provider } from "../../types";
2
+ /**
3
+ * The two wire families a mixed OpenAI-compatible gateway (e.g. CLIProxyAPI)
4
+ * can front. A gateway exposes an OpenAI-shaped `/v1/models` catalog but may
5
+ * proxy Anthropic models that must be driven through the Anthropic Messages
6
+ * transport rather than OpenAI Chat Completions.
7
+ */
8
+ export type DiscoveredApiFamily = "anthropic-messages" | "openai-completions";
9
+ /**
10
+ * Infer the wire API family for one discovered model on a mixed
11
+ * OpenAI-compatible gateway.
12
+ *
13
+ * Uses the `owned_by` owner string first, then falls back to the model id.
14
+ * Returns `undefined` when neither signal is conclusive so the caller can keep
15
+ * the provider-level default instead of guessing.
16
+ */
17
+ export declare function detectDiscoveredApiFamily(entry: {
18
+ id?: unknown;
19
+ owned_by?: unknown;
20
+ }): DiscoveredApiFamily | undefined;
2
21
  /**
3
22
  * Minimal OpenAI-style model entry shape consumed by discovery.
4
23
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@sayknow-cli/ai",
4
- "version": "0.5.11",
4
+ "version": "0.5.13",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://sayknow-cli.com",
7
7
  "author": "jaybeyond",
@@ -43,7 +43,7 @@
43
43
  "dependencies": {
44
44
  "@anthropic-ai/sdk": "^0.94.0",
45
45
  "@bufbuild/protobuf": "^2.12.0",
46
- "@sayknow-cli/utils": "0.5.11",
46
+ "@sayknow-cli/utils": "0.5.13",
47
47
  "openai": "^6.36.0",
48
48
  "partial-json": "^0.1.7",
49
49
  "zod": "4.4.3"
@@ -39,6 +39,40 @@ function isLoopbackHost(hostname: string): boolean {
39
39
  return isIpv6Loopback || isIpv4MappedLoopback;
40
40
  }
41
41
 
42
+ /**
43
+ * The two wire families a mixed OpenAI-compatible gateway (e.g. CLIProxyAPI)
44
+ * can front. A gateway exposes an OpenAI-shaped `/v1/models` catalog but may
45
+ * proxy Anthropic models that must be driven through the Anthropic Messages
46
+ * transport rather than OpenAI Chat Completions.
47
+ */
48
+ export type DiscoveredApiFamily = "anthropic-messages" | "openai-completions";
49
+
50
+ const ANTHROPIC_OWNER_PATTERN = /\banthropic\b/i;
51
+ const OPENAI_OWNER_PATTERN = /\b(openai|open-ai)\b/i;
52
+ const ANTHROPIC_MODEL_ID_PATTERN = /(^|[/:])claude[-.]/i;
53
+ const OPENAI_MODEL_ID_PATTERN = /(^|[/:])(gpt[-.]?|o[1-9]|codex|text-|chatgpt|davinci|dall-e|gpt-image|whisper|tts-)/i;
54
+
55
+ /**
56
+ * Infer the wire API family for one discovered model on a mixed
57
+ * OpenAI-compatible gateway.
58
+ *
59
+ * Uses the `owned_by` owner string first, then falls back to the model id.
60
+ * Returns `undefined` when neither signal is conclusive so the caller can keep
61
+ * the provider-level default instead of guessing.
62
+ */
63
+ export function detectDiscoveredApiFamily(entry: {
64
+ id?: unknown;
65
+ owned_by?: unknown;
66
+ }): DiscoveredApiFamily | undefined {
67
+ const owner = typeof entry.owned_by === "string" ? entry.owned_by : "";
68
+ if (ANTHROPIC_OWNER_PATTERN.test(owner)) return "anthropic-messages";
69
+ if (OPENAI_OWNER_PATTERN.test(owner)) return "openai-completions";
70
+ const id = typeof entry.id === "string" ? entry.id : "";
71
+ if (ANTHROPIC_MODEL_ID_PATTERN.test(id)) return "anthropic-messages";
72
+ if (OPENAI_MODEL_ID_PATTERN.test(id)) return "openai-completions";
73
+ return undefined;
74
+ }
75
+
42
76
  /**
43
77
  * Minimal OpenAI-style model entry shape consumed by discovery.
44
78
  *