@aigne/afs-ai-gateway 1.12.0-beta.5

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.
Files changed (42) hide show
  1. package/LICENSE.md +26 -0
  2. package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
  4. package/dist/_virtual/rolldown_runtime.cjs +29 -0
  5. package/dist/ai-gateway.cjs +1083 -0
  6. package/dist/ai-gateway.d.cts +124 -0
  7. package/dist/ai-gateway.d.cts.map +1 -0
  8. package/dist/ai-gateway.d.mts +124 -0
  9. package/dist/ai-gateway.d.mts.map +1 -0
  10. package/dist/ai-gateway.mjs +1083 -0
  11. package/dist/ai-gateway.mjs.map +1 -0
  12. package/dist/index.cjs +14 -0
  13. package/dist/index.d.cts +5 -0
  14. package/dist/index.d.mts +5 -0
  15. package/dist/index.mjs +6 -0
  16. package/dist/models.cjs +155 -0
  17. package/dist/models.d.cts +8 -0
  18. package/dist/models.d.cts.map +1 -0
  19. package/dist/models.d.mts +8 -0
  20. package/dist/models.d.mts.map +1 -0
  21. package/dist/models.mjs +150 -0
  22. package/dist/models.mjs.map +1 -0
  23. package/dist/models2.cjs +97 -0
  24. package/dist/models2.mjs +96 -0
  25. package/dist/models2.mjs.map +1 -0
  26. package/dist/normalize.cjs +49 -0
  27. package/dist/normalize.d.cts +10 -0
  28. package/dist/normalize.d.cts.map +1 -0
  29. package/dist/normalize.d.mts +10 -0
  30. package/dist/normalize.d.mts.map +1 -0
  31. package/dist/normalize.mjs +47 -0
  32. package/dist/normalize.mjs.map +1 -0
  33. package/dist/types.cjs +80 -0
  34. package/dist/types.d.cts +104 -0
  35. package/dist/types.d.cts.map +1 -0
  36. package/dist/types.d.mts +104 -0
  37. package/dist/types.d.mts.map +1 -0
  38. package/dist/types.mjs +77 -0
  39. package/dist/types.mjs.map +1 -0
  40. package/manifest.json +40 -0
  41. package/models.json +145 -0
  42. package/package.json +61 -0
@@ -0,0 +1,96 @@
1
+ import models_default from "./models.mjs";
2
+ import { modelCatalogSchema } from "./types.mjs";
3
+
4
+ //#region src/models.ts
5
+ /**
6
+ * Model catalog loader.
7
+ *
8
+ * The bundled `models.json` is the offline default — curated entries we've
9
+ * validated through CF AI Gateway's compat endpoint. Validated at import time
10
+ * so any malformed entry fails startup loudly instead of silently mis-routing.
11
+ *
12
+ * `loadModels()` accepts any unknown value and validates it against the same
13
+ * schema — use it for user-supplied `models` option.
14
+ *
15
+ * `fetchModelsFromEndpoint()` hits the OpenAI-compat `GET /v1/models` route
16
+ * and maps the response into our schema. Right for local runtimes (Ollama /
17
+ * LM Studio / LiteLLM) whose `/v1/models` reflects live-loaded models.
18
+ */
19
+ function loadModels(source) {
20
+ return modelCatalogSchema.parse(source);
21
+ }
22
+ const DEFAULT_MODELS = loadModels(models_default);
23
+ /**
24
+ * Type inference from model id.
25
+ *
26
+ * Looks at the id casefolded. Keep the rule list small and documented — a model
27
+ * id whose shape doesn't hint its type defaults to `chat` (the safe fallback).
28
+ */
29
+ function inferTypeFromId(id) {
30
+ const s = id.toLowerCase();
31
+ if (s.includes("embedding") || s.includes("-embed") || /\bembed\b/.test(s)) return "embed";
32
+ if (s.includes("image") || s.includes("dall-e") || s.includes("imagen") || /\bsdxl\b/.test(s) || s.includes("flux") || s.includes("stable-diffusion")) return "image";
33
+ if (s.includes("sora") || s.includes("veo") || s.includes("video")) return "video";
34
+ return "chat";
35
+ }
36
+ /** Best-effort vendor inference from common id prefixes used by Ollama/LM Studio. */
37
+ function inferVendorFromId(id) {
38
+ const s = id.toLowerCase();
39
+ if (s.startsWith("llama") || s.startsWith("meta-llama")) return "meta";
40
+ if (s.startsWith("qwen")) return "alibaba";
41
+ if (s.startsWith("gemma") || s.startsWith("gemini")) return "google";
42
+ if (s.startsWith("mistral") || s.startsWith("mixtral") || s.startsWith("codestral")) return "mistral";
43
+ if (s.startsWith("deepseek")) return "deepseek";
44
+ if (s.startsWith("phi")) return "microsoft";
45
+ if (s.startsWith("claude")) return "anthropic";
46
+ if (s.startsWith("gpt")) return "openai";
47
+ if (s.startsWith("grok")) return "xai";
48
+ if (s.startsWith("command") || s.startsWith("c4ai")) return "cohere";
49
+ if (s.startsWith("nomic")) return "nomic";
50
+ return null;
51
+ }
52
+ /**
53
+ * Call `GET {baseURL}/models` and map into our `ModelCatalog` schema.
54
+ *
55
+ * The response is validated loosely — we need `data[].id` as a non-empty
56
+ * string; everything else is best-effort inference.
57
+ */
58
+ async function fetchModelsFromEndpoint(baseURL, apiKey, options = {}) {
59
+ const fetchImpl = options.fetchImpl ?? fetch;
60
+ const timeoutMs = options.timeoutMs ?? 5e3;
61
+ const defaultVendor = options.defaultVendor ?? "local";
62
+ const controller = new AbortController();
63
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
64
+ const url = baseURL.endsWith("/") ? `${baseURL}models` : `${baseURL}/models`;
65
+ let raw;
66
+ try {
67
+ const response = await fetchImpl(url, {
68
+ signal: controller.signal,
69
+ headers: {
70
+ Authorization: `Bearer ${apiKey}`,
71
+ "Content-Type": "application/json"
72
+ }
73
+ });
74
+ if (!response.ok) throw new Error(`GET ${url} → HTTP ${response.status} ${response.statusText}`);
75
+ raw = await response.json();
76
+ } finally {
77
+ clearTimeout(timer);
78
+ }
79
+ const parsed = raw;
80
+ if (!parsed || !Array.isArray(parsed.data)) throw new Error(`Unexpected response from ${url}: missing .data[]`);
81
+ const entries = [];
82
+ for (const item of parsed.data) {
83
+ if (!item || typeof item.id !== "string" || item.id.length === 0) continue;
84
+ entries.push({
85
+ model: item.id,
86
+ nativeModelId: item.id,
87
+ vendor: inferVendorFromId(item.id) ?? defaultVendor,
88
+ type: inferTypeFromId(item.id)
89
+ });
90
+ }
91
+ return modelCatalogSchema.parse(entries);
92
+ }
93
+
94
+ //#endregion
95
+ export { DEFAULT_MODELS, fetchModelsFromEndpoint, loadModels };
96
+ //# sourceMappingURL=models2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models2.mjs","names":["bundled"],"sources":["../src/models.ts"],"sourcesContent":["/**\n * Model catalog loader.\n *\n * The bundled `models.json` is the offline default — curated entries we've\n * validated through CF AI Gateway's compat endpoint. Validated at import time\n * so any malformed entry fails startup loudly instead of silently mis-routing.\n *\n * `loadModels()` accepts any unknown value and validates it against the same\n * schema — use it for user-supplied `models` option.\n *\n * `fetchModelsFromEndpoint()` hits the OpenAI-compat `GET /v1/models` route\n * and maps the response into our schema. Right for local runtimes (Ollama /\n * LM Studio / LiteLLM) whose `/v1/models` reflects live-loaded models.\n */\n\nimport bundled from \"../models.json\" with { type: \"json\" };\nimport { type ModelCatalog, type ModelEntry, type ModelType, modelCatalogSchema } from \"./types.js\";\n\nexport function loadModels(source: unknown): ModelCatalog {\n return modelCatalogSchema.parse(source);\n}\n\nexport const DEFAULT_MODELS: ModelCatalog = loadModels(bundled);\n\n// ─── /v1/models fetcher ────────────────────────────────────────────────────\n\nexport interface FetchModelsOptions {\n /** Applied to entries whose vendor can't be inferred from the id. */\n defaultVendor?: string;\n /** Fetch timeout in ms — default 5000. */\n timeoutMs?: number;\n /** Dependency injection for tests. */\n fetchImpl?: typeof fetch;\n}\n\n/**\n * Type inference from model id.\n *\n * Looks at the id casefolded. Keep the rule list small and documented — a model\n * id whose shape doesn't hint its type defaults to `chat` (the safe fallback).\n */\nexport function inferTypeFromId(id: string): ModelType {\n const s = id.toLowerCase();\n if (s.includes(\"embedding\") || s.includes(\"-embed\") || /\\bembed\\b/.test(s)) return \"embed\";\n if (\n s.includes(\"image\") ||\n s.includes(\"dall-e\") ||\n s.includes(\"imagen\") ||\n /\\bsdxl\\b/.test(s) ||\n s.includes(\"flux\") ||\n s.includes(\"stable-diffusion\")\n )\n return \"image\";\n if (s.includes(\"sora\") || s.includes(\"veo\") || s.includes(\"video\")) return \"video\";\n return \"chat\";\n}\n\n/** Best-effort vendor inference from common id prefixes used by Ollama/LM Studio. */\nexport function inferVendorFromId(id: string): string | null {\n const s = id.toLowerCase();\n if (s.startsWith(\"llama\") || s.startsWith(\"meta-llama\")) return \"meta\";\n if (s.startsWith(\"qwen\")) return \"alibaba\";\n if (s.startsWith(\"gemma\") || s.startsWith(\"gemini\")) return \"google\";\n if (s.startsWith(\"mistral\") || s.startsWith(\"mixtral\") || s.startsWith(\"codestral\"))\n return \"mistral\";\n if (s.startsWith(\"deepseek\")) return \"deepseek\";\n if (s.startsWith(\"phi\")) return \"microsoft\";\n if (s.startsWith(\"claude\")) return \"anthropic\";\n if (s.startsWith(\"gpt\")) return \"openai\";\n if (s.startsWith(\"grok\")) return \"xai\";\n if (s.startsWith(\"command\") || s.startsWith(\"c4ai\")) return \"cohere\";\n if (s.startsWith(\"nomic\")) return \"nomic\";\n return null;\n}\n\ninterface OpenAIModelListItem {\n id?: string;\n object?: string;\n owned_by?: string;\n}\n\ninterface OpenAIModelListResponse {\n data?: OpenAIModelListItem[];\n}\n\n/**\n * Call `GET {baseURL}/models` and map into our `ModelCatalog` schema.\n *\n * The response is validated loosely — we need `data[].id` as a non-empty\n * string; everything else is best-effort inference.\n */\nexport async function fetchModelsFromEndpoint(\n baseURL: string,\n apiKey: string,\n options: FetchModelsOptions = {},\n): Promise<ModelCatalog> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const timeoutMs = options.timeoutMs ?? 5000;\n const defaultVendor = options.defaultVendor ?? \"local\";\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n const url = baseURL.endsWith(\"/\") ? `${baseURL}models` : `${baseURL}/models`;\n let raw: unknown;\n try {\n const response = await fetchImpl(url, {\n signal: controller.signal,\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n });\n if (!response.ok) {\n throw new Error(`GET ${url} → HTTP ${response.status} ${response.statusText}`);\n }\n raw = await response.json();\n } finally {\n clearTimeout(timer);\n }\n\n const parsed = raw as OpenAIModelListResponse;\n if (!parsed || !Array.isArray(parsed.data)) {\n throw new Error(`Unexpected response from ${url}: missing .data[]`);\n }\n\n const entries: ModelEntry[] = [];\n for (const item of parsed.data) {\n if (!item || typeof item.id !== \"string\" || item.id.length === 0) continue;\n entries.push({\n model: item.id,\n nativeModelId: item.id,\n vendor: inferVendorFromId(item.id) ?? defaultVendor,\n type: inferTypeFromId(item.id),\n });\n }\n // Re-validate to catch any schema drift.\n return modelCatalogSchema.parse(entries);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,SAAgB,WAAW,QAA+B;AACxD,QAAO,mBAAmB,MAAM,OAAO;;AAGzC,MAAa,iBAA+B,WAAWA,eAAQ;;;;;;;AAmB/D,SAAgB,gBAAgB,IAAuB;CACrD,MAAM,IAAI,GAAG,aAAa;AAC1B,KAAI,EAAE,SAAS,YAAY,IAAI,EAAE,SAAS,SAAS,IAAI,YAAY,KAAK,EAAE,CAAE,QAAO;AACnF,KACE,EAAE,SAAS,QAAQ,IACnB,EAAE,SAAS,SAAS,IACpB,EAAE,SAAS,SAAS,IACpB,WAAW,KAAK,EAAE,IAClB,EAAE,SAAS,OAAO,IAClB,EAAE,SAAS,mBAAmB,CAE9B,QAAO;AACT,KAAI,EAAE,SAAS,OAAO,IAAI,EAAE,SAAS,MAAM,IAAI,EAAE,SAAS,QAAQ,CAAE,QAAO;AAC3E,QAAO;;;AAIT,SAAgB,kBAAkB,IAA2B;CAC3D,MAAM,IAAI,GAAG,aAAa;AAC1B,KAAI,EAAE,WAAW,QAAQ,IAAI,EAAE,WAAW,aAAa,CAAE,QAAO;AAChE,KAAI,EAAE,WAAW,OAAO,CAAE,QAAO;AACjC,KAAI,EAAE,WAAW,QAAQ,IAAI,EAAE,WAAW,SAAS,CAAE,QAAO;AAC5D,KAAI,EAAE,WAAW,UAAU,IAAI,EAAE,WAAW,UAAU,IAAI,EAAE,WAAW,YAAY,CACjF,QAAO;AACT,KAAI,EAAE,WAAW,WAAW,CAAE,QAAO;AACrC,KAAI,EAAE,WAAW,MAAM,CAAE,QAAO;AAChC,KAAI,EAAE,WAAW,SAAS,CAAE,QAAO;AACnC,KAAI,EAAE,WAAW,MAAM,CAAE,QAAO;AAChC,KAAI,EAAE,WAAW,OAAO,CAAE,QAAO;AACjC,KAAI,EAAE,WAAW,UAAU,IAAI,EAAE,WAAW,OAAO,CAAE,QAAO;AAC5D,KAAI,EAAE,WAAW,QAAQ,CAAE,QAAO;AAClC,QAAO;;;;;;;;AAmBT,eAAsB,wBACpB,SACA,QACA,UAA8B,EAAE,EACT;CACvB,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,gBAAgB,QAAQ,iBAAiB;CAE/C,MAAM,aAAa,IAAI,iBAAiB;CACxC,MAAM,QAAQ,iBAAiB,WAAW,OAAO,EAAE,UAAU;CAC7D,MAAM,MAAM,QAAQ,SAAS,IAAI,GAAG,GAAG,QAAQ,UAAU,GAAG,QAAQ;CACpE,IAAI;AACJ,KAAI;EACF,MAAM,WAAW,MAAM,UAAU,KAAK;GACpC,QAAQ,WAAW;GACnB,SAAS;IACP,eAAe,UAAU;IACzB,gBAAgB;IACjB;GACF,CAAC;AACF,MAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,OAAO,IAAI,UAAU,SAAS,OAAO,GAAG,SAAS,aAAa;AAEhF,QAAM,MAAM,SAAS,MAAM;WACnB;AACR,eAAa,MAAM;;CAGrB,MAAM,SAAS;AACf,KAAI,CAAC,UAAU,CAAC,MAAM,QAAQ,OAAO,KAAK,CACxC,OAAM,IAAI,MAAM,4BAA4B,IAAI,mBAAmB;CAGrE,MAAM,UAAwB,EAAE;AAChC,MAAK,MAAM,QAAQ,OAAO,MAAM;AAC9B,MAAI,CAAC,QAAQ,OAAO,KAAK,OAAO,YAAY,KAAK,GAAG,WAAW,EAAG;AAClE,UAAQ,KAAK;GACX,OAAO,KAAK;GACZ,eAAe,KAAK;GACpB,QAAQ,kBAAkB,KAAK,GAAG,IAAI;GACtC,MAAM,gBAAgB,KAAK,GAAG;GAC/B,CAAC;;AAGJ,QAAO,mBAAmB,MAAM,QAAQ"}
@@ -0,0 +1,49 @@
1
+ const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
+ let _aigne_afs_ai_device = require("@aigne/afs-ai-device");
3
+ let _aigne_afs_ai_device_catalog_json = require("@aigne/afs-ai-device/catalog.json");
4
+ _aigne_afs_ai_device_catalog_json = require_rolldown_runtime.__toESM(_aigne_afs_ai_device_catalog_json);
5
+
6
+ //#region src/normalize.ts
7
+ /**
8
+ * Canonical ↔ native model-id resolution for the gateway provider.
9
+ *
10
+ * The `/models/{id}` tree and `.actions/listModels` speak in canonical
11
+ * ids (matching the AI Device catalog). The OpenAI SDK's `model` field
12
+ * speaks in native ids (`{vendor}/{canonical}` for CF compat). This
13
+ * helper resolves requested canonical ids against the configured model
14
+ * list, using both exact matches and catalog alias lookups.
15
+ *
16
+ * Unknown ids pass through untouched so custom gateway deployments can
17
+ * still invoke models the bundled catalog has no entry for — upstream
18
+ * surfaces the error if the native id really doesn't exist.
19
+ */
20
+ let sharedCatalog = null;
21
+ function getCatalog() {
22
+ if (sharedCatalog) return sharedCatalog;
23
+ sharedCatalog = (0, _aigne_afs_ai_device.buildCatalog)(_aigne_afs_ai_device_catalog_json.default);
24
+ return sharedCatalog;
25
+ }
26
+ function lastSegment(id) {
27
+ const idx = id.lastIndexOf("/");
28
+ return idx >= 0 ? id.slice(idx + 1) : id;
29
+ }
30
+ /** Normalize a requested id to the canonical catalog id, or pass through. */
31
+ function toCanonicalModel(id) {
32
+ if (!id) return id;
33
+ return getCatalog().resolveCanonicalModel(id) ?? id;
34
+ }
35
+ /** Find the model entry matching a requested canonical id (or alias). */
36
+ function findModelEntry(requestedId, models) {
37
+ if (!requestedId) return void 0;
38
+ const canonical = toCanonicalModel(requestedId);
39
+ for (const m of models) if (m.model === canonical) return m;
40
+ for (const m of models) {
41
+ if (m.aliases?.includes(canonical) || m.aliases?.includes(requestedId)) return m;
42
+ if (lastSegment(m.nativeModelId) === canonical) return m;
43
+ if (toCanonicalModel(m.model) === canonical) return m;
44
+ }
45
+ }
46
+
47
+ //#endregion
48
+ exports.findModelEntry = findModelEntry;
49
+ exports.toCanonicalModel = toCanonicalModel;
@@ -0,0 +1,10 @@
1
+ import { ModelEntry } from "./types.cjs";
2
+
3
+ //#region src/normalize.d.ts
4
+ /** Normalize a requested id to the canonical catalog id, or pass through. */
5
+ declare function toCanonicalModel(id: string): string;
6
+ /** Find the model entry matching a requested canonical id (or alias). */
7
+ declare function findModelEntry(requestedId: string, models: readonly ModelEntry[]): ModelEntry | undefined;
8
+ //#endregion
9
+ export { findModelEntry, toCanonicalModel };
10
+ //# sourceMappingURL=normalize.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.cts","names":[],"sources":["../src/normalize.ts"],"mappings":";;;;iBAgCgB,gBAAA,CAAiB,EAAA;;iBAMjB,cAAA,CACd,WAAA,UACA,MAAA,WAAiB,UAAA,KAChB,UAAA"}
@@ -0,0 +1,10 @@
1
+ import { ModelEntry } from "./types.mjs";
2
+
3
+ //#region src/normalize.d.ts
4
+ /** Normalize a requested id to the canonical catalog id, or pass through. */
5
+ declare function toCanonicalModel(id: string): string;
6
+ /** Find the model entry matching a requested canonical id (or alias). */
7
+ declare function findModelEntry(requestedId: string, models: readonly ModelEntry[]): ModelEntry | undefined;
8
+ //#endregion
9
+ export { findModelEntry, toCanonicalModel };
10
+ //# sourceMappingURL=normalize.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.mts","names":[],"sources":["../src/normalize.ts"],"mappings":";;;;iBAgCgB,gBAAA,CAAiB,EAAA;;iBAMjB,cAAA,CACd,WAAA,UACA,MAAA,WAAiB,UAAA,KAChB,UAAA"}
@@ -0,0 +1,47 @@
1
+ import { buildCatalog } from "@aigne/afs-ai-device";
2
+ import catalogJson from "@aigne/afs-ai-device/catalog.json" with { type: "json" };
3
+
4
+ //#region src/normalize.ts
5
+ /**
6
+ * Canonical ↔ native model-id resolution for the gateway provider.
7
+ *
8
+ * The `/models/{id}` tree and `.actions/listModels` speak in canonical
9
+ * ids (matching the AI Device catalog). The OpenAI SDK's `model` field
10
+ * speaks in native ids (`{vendor}/{canonical}` for CF compat). This
11
+ * helper resolves requested canonical ids against the configured model
12
+ * list, using both exact matches and catalog alias lookups.
13
+ *
14
+ * Unknown ids pass through untouched so custom gateway deployments can
15
+ * still invoke models the bundled catalog has no entry for — upstream
16
+ * surfaces the error if the native id really doesn't exist.
17
+ */
18
+ let sharedCatalog = null;
19
+ function getCatalog() {
20
+ if (sharedCatalog) return sharedCatalog;
21
+ sharedCatalog = buildCatalog(catalogJson);
22
+ return sharedCatalog;
23
+ }
24
+ function lastSegment(id) {
25
+ const idx = id.lastIndexOf("/");
26
+ return idx >= 0 ? id.slice(idx + 1) : id;
27
+ }
28
+ /** Normalize a requested id to the canonical catalog id, or pass through. */
29
+ function toCanonicalModel(id) {
30
+ if (!id) return id;
31
+ return getCatalog().resolveCanonicalModel(id) ?? id;
32
+ }
33
+ /** Find the model entry matching a requested canonical id (or alias). */
34
+ function findModelEntry(requestedId, models) {
35
+ if (!requestedId) return void 0;
36
+ const canonical = toCanonicalModel(requestedId);
37
+ for (const m of models) if (m.model === canonical) return m;
38
+ for (const m of models) {
39
+ if (m.aliases?.includes(canonical) || m.aliases?.includes(requestedId)) return m;
40
+ if (lastSegment(m.nativeModelId) === canonical) return m;
41
+ if (toCanonicalModel(m.model) === canonical) return m;
42
+ }
43
+ }
44
+
45
+ //#endregion
46
+ export { findModelEntry, toCanonicalModel };
47
+ //# sourceMappingURL=normalize.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.mjs","names":[],"sources":["../src/normalize.ts"],"sourcesContent":["/**\n * Canonical ↔ native model-id resolution for the gateway provider.\n *\n * The `/models/{id}` tree and `.actions/listModels` speak in canonical\n * ids (matching the AI Device catalog). The OpenAI SDK's `model` field\n * speaks in native ids (`{vendor}/{canonical}` for CF compat). This\n * helper resolves requested canonical ids against the configured model\n * list, using both exact matches and catalog alias lookups.\n *\n * Unknown ids pass through untouched so custom gateway deployments can\n * still invoke models the bundled catalog has no entry for — upstream\n * surfaces the error if the native id really doesn't exist.\n */\n\nimport { buildCatalog, type LoadedCatalog } from \"@aigne/afs-ai-device\";\nimport catalogJson from \"@aigne/afs-ai-device/catalog.json\" with { type: \"json\" };\nimport type { ModelEntry } from \"./types.js\";\n\nlet sharedCatalog: LoadedCatalog | null = null;\n\nfunction getCatalog(): LoadedCatalog {\n if (sharedCatalog) return sharedCatalog;\n sharedCatalog = buildCatalog(catalogJson as readonly unknown[]);\n return sharedCatalog;\n}\n\nfunction lastSegment(id: string): string {\n const idx = id.lastIndexOf(\"/\");\n return idx >= 0 ? id.slice(idx + 1) : id;\n}\n\n/** Normalize a requested id to the canonical catalog id, or pass through. */\nexport function toCanonicalModel(id: string): string {\n if (!id) return id;\n return getCatalog().resolveCanonicalModel(id) ?? id;\n}\n\n/** Find the model entry matching a requested canonical id (or alias). */\nexport function findModelEntry(\n requestedId: string,\n models: readonly ModelEntry[],\n): ModelEntry | undefined {\n if (!requestedId) return undefined;\n const canonical = toCanonicalModel(requestedId);\n\n // Fast path: exact canonical match.\n for (const m of models) {\n if (m.model === canonical) return m;\n }\n\n // Secondary: alias list, vendor-stripped, or last path segment.\n for (const m of models) {\n if (m.aliases?.includes(canonical) || m.aliases?.includes(requestedId)) return m;\n if (lastSegment(m.nativeModelId) === canonical) return m;\n const modelCanonical = toCanonicalModel(m.model);\n if (modelCanonical === canonical) return m;\n }\n return undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAkBA,IAAI,gBAAsC;AAE1C,SAAS,aAA4B;AACnC,KAAI,cAAe,QAAO;AAC1B,iBAAgB,aAAa,YAAkC;AAC/D,QAAO;;AAGT,SAAS,YAAY,IAAoB;CACvC,MAAM,MAAM,GAAG,YAAY,IAAI;AAC/B,QAAO,OAAO,IAAI,GAAG,MAAM,MAAM,EAAE,GAAG;;;AAIxC,SAAgB,iBAAiB,IAAoB;AACnD,KAAI,CAAC,GAAI,QAAO;AAChB,QAAO,YAAY,CAAC,sBAAsB,GAAG,IAAI;;;AAInD,SAAgB,eACd,aACA,QACwB;AACxB,KAAI,CAAC,YAAa,QAAO;CACzB,MAAM,YAAY,iBAAiB,YAAY;AAG/C,MAAK,MAAM,KAAK,OACd,KAAI,EAAE,UAAU,UAAW,QAAO;AAIpC,MAAK,MAAM,KAAK,QAAQ;AACtB,MAAI,EAAE,SAAS,SAAS,UAAU,IAAI,EAAE,SAAS,SAAS,YAAY,CAAE,QAAO;AAC/E,MAAI,YAAY,EAAE,cAAc,KAAK,UAAW,QAAO;AAEvD,MADuB,iBAAiB,EAAE,MAAM,KACzB,UAAW,QAAO"}
package/dist/types.cjs ADDED
@@ -0,0 +1,80 @@
1
+ const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
+ let zod = require("zod");
3
+
4
+ //#region src/types.ts
5
+ /** Shared vocabulary: the four AI Device capacity types. */
6
+ const modelTypeSchema = zod.z.enum([
7
+ "chat",
8
+ "embed",
9
+ "image",
10
+ "video"
11
+ ]);
12
+ /**
13
+ * One entry in the bundled / user-supplied / remote model list.
14
+ *
15
+ * - `model` — canonical id the AI Device catalog uses (e.g. "claude-haiku-4-5")
16
+ * - `nativeModelId` — id fed to the underlying OpenAI SDK (e.g. "anthropic/claude-haiku-4-5")
17
+ * - `vendor` — vendor slug (openai / anthropic / google / …)
18
+ * - `type` — capacity type
19
+ * - `aliases` — extra ids users may reference
20
+ * - `available` — optional availability flag (default true)
21
+ */
22
+ const modelEntrySchema = zod.z.object({
23
+ model: zod.z.string().min(1),
24
+ nativeModelId: zod.z.string().min(1),
25
+ vendor: zod.z.string().min(1),
26
+ type: modelTypeSchema,
27
+ aliases: zod.z.array(zod.z.string()).optional(),
28
+ available: zod.z.boolean().optional()
29
+ });
30
+ /** A catalog of models — same schema whether from bundled JSON or remote fetch. */
31
+ const modelCatalogSchema = zod.z.array(modelEntrySchema);
32
+ /**
33
+ * Source of truth for the model list.
34
+ *
35
+ * - `"bundled"` (default): use the package's `models.json` + any user `models` override.
36
+ * Zero network dependency at startup. Right for remote gateways (CF Gateway,
37
+ * OpenRouter) where the operator has curated the allowlist.
38
+ *
39
+ * - `"endpoint"`: lazily `GET {baseURL}/models` and derive the list from the
40
+ * response. Right for **local runtimes** (Ollama, LM Studio, LiteLLM) where
41
+ * the runtime's own `/v1/models` already reflects exactly what's loaded.
42
+ * Falls back to bundled + user override if the endpoint fails.
43
+ */
44
+ const listStrategySchema = zod.z.enum(["bundled", "endpoint"]);
45
+ /**
46
+ * Provider options — the `baseURL` must point at an OpenAI-compatible
47
+ * chat/completions root (i.e. POST {baseURL}/chat/completions works).
48
+ *
49
+ * Example baseURLs:
50
+ * - https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/compat
51
+ * - https://openrouter.ai/api/v1
52
+ * - https://api.openai.com/v1
53
+ * - http://localhost:4000/v1 (LiteLLM proxy)
54
+ * - http://localhost:11434/v1 (Ollama)
55
+ * - http://localhost:1234/v1 (LM Studio)
56
+ */
57
+ const afsAIGatewayOptionsSchema = zod.z.object({
58
+ name: zod.z.string().default("ai-gateway"),
59
+ description: zod.z.string().default("AI Gateway provider — OpenAI-compatible backend surfaced as an AI Device hub. Execute inference via .actions/chat, .actions/embed, .actions/generateImage, .actions/generateVideo on any model node."),
60
+ baseURL: zod.z.string().meta({
61
+ env: ["AI_GATEWAY_BASE_URL"],
62
+ description: "OpenAI-compatible base URL (chat/completions will be appended by the SDK)."
63
+ }),
64
+ apiKey: zod.z.string().meta({
65
+ sensitive: true,
66
+ env: ["AI_GATEWAY_API_KEY"],
67
+ description: "Bearer token sent as Authorization header."
68
+ }),
69
+ listStrategy: listStrategySchema.default("bundled").describe("How to populate the model list — 'bundled' (static) or 'endpoint' (fetch /v1/models)."),
70
+ vendor: zod.z.string().optional().describe("Default vendor slug applied to entries discovered via listStrategy:endpoint (when no better guess from the id)."),
71
+ models: modelCatalogSchema.optional().describe("Bundled/override catalog. Used as the primary source for listStrategy:bundled, and as fallback for listStrategy:endpoint when the /v1/models call fails."),
72
+ extraHeaders: zod.z.record(zod.z.string(), zod.z.string()).optional().describe("Extra HTTP headers forwarded on every request — e.g. cf-aig-cache-ttl for Cloudflare AI Gateway."),
73
+ endpointTimeoutMs: zod.z.number().positive().optional().describe("Timeout (ms) for the /v1/models fetch when listStrategy:endpoint. Default 5000.")
74
+ });
75
+
76
+ //#endregion
77
+ exports.afsAIGatewayOptionsSchema = afsAIGatewayOptionsSchema;
78
+ exports.modelCatalogSchema = modelCatalogSchema;
79
+ exports.modelEntrySchema = modelEntrySchema;
80
+ exports.modelTypeSchema = modelTypeSchema;
@@ -0,0 +1,104 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/types.d.ts
4
+ /** Shared vocabulary: the four AI Device capacity types. */
5
+ declare const modelTypeSchema: z.ZodEnum<{
6
+ chat: "chat";
7
+ embed: "embed";
8
+ image: "image";
9
+ video: "video";
10
+ }>;
11
+ type ModelType = z.infer<typeof modelTypeSchema>;
12
+ /**
13
+ * One entry in the bundled / user-supplied / remote model list.
14
+ *
15
+ * - `model` — canonical id the AI Device catalog uses (e.g. "claude-haiku-4-5")
16
+ * - `nativeModelId` — id fed to the underlying OpenAI SDK (e.g. "anthropic/claude-haiku-4-5")
17
+ * - `vendor` — vendor slug (openai / anthropic / google / …)
18
+ * - `type` — capacity type
19
+ * - `aliases` — extra ids users may reference
20
+ * - `available` — optional availability flag (default true)
21
+ */
22
+ declare const modelEntrySchema: z.ZodObject<{
23
+ model: z.ZodString;
24
+ nativeModelId: z.ZodString;
25
+ vendor: z.ZodString;
26
+ type: z.ZodEnum<{
27
+ chat: "chat";
28
+ embed: "embed";
29
+ image: "image";
30
+ video: "video";
31
+ }>;
32
+ aliases: z.ZodOptional<z.ZodArray<z.ZodString>>;
33
+ available: z.ZodOptional<z.ZodBoolean>;
34
+ }, z.core.$strip>;
35
+ type ModelEntry = z.infer<typeof modelEntrySchema>;
36
+ /** A catalog of models — same schema whether from bundled JSON or remote fetch. */
37
+ declare const modelCatalogSchema: z.ZodArray<z.ZodObject<{
38
+ model: z.ZodString;
39
+ nativeModelId: z.ZodString;
40
+ vendor: z.ZodString;
41
+ type: z.ZodEnum<{
42
+ chat: "chat";
43
+ embed: "embed";
44
+ image: "image";
45
+ video: "video";
46
+ }>;
47
+ aliases: z.ZodOptional<z.ZodArray<z.ZodString>>;
48
+ available: z.ZodOptional<z.ZodBoolean>;
49
+ }, z.core.$strip>>;
50
+ type ModelCatalog = z.infer<typeof modelCatalogSchema>;
51
+ /**
52
+ * Provider options — the `baseURL` must point at an OpenAI-compatible
53
+ * chat/completions root (i.e. POST {baseURL}/chat/completions works).
54
+ *
55
+ * Example baseURLs:
56
+ * - https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/compat
57
+ * - https://openrouter.ai/api/v1
58
+ * - https://api.openai.com/v1
59
+ * - http://localhost:4000/v1 (LiteLLM proxy)
60
+ * - http://localhost:11434/v1 (Ollama)
61
+ * - http://localhost:1234/v1 (LM Studio)
62
+ */
63
+ declare const afsAIGatewayOptionsSchema: z.ZodObject<{
64
+ name: z.ZodDefault<z.ZodString>;
65
+ description: z.ZodDefault<z.ZodString>;
66
+ baseURL: z.ZodString;
67
+ apiKey: z.ZodString;
68
+ listStrategy: z.ZodDefault<z.ZodEnum<{
69
+ bundled: "bundled";
70
+ endpoint: "endpoint";
71
+ }>>;
72
+ vendor: z.ZodOptional<z.ZodString>;
73
+ models: z.ZodOptional<z.ZodArray<z.ZodObject<{
74
+ model: z.ZodString;
75
+ nativeModelId: z.ZodString;
76
+ vendor: z.ZodString;
77
+ type: z.ZodEnum<{
78
+ chat: "chat";
79
+ embed: "embed";
80
+ image: "image";
81
+ video: "video";
82
+ }>;
83
+ aliases: z.ZodOptional<z.ZodArray<z.ZodString>>;
84
+ available: z.ZodOptional<z.ZodBoolean>;
85
+ }, z.core.$strip>>>;
86
+ extraHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
87
+ endpointTimeoutMs: z.ZodOptional<z.ZodNumber>;
88
+ }, z.core.$strip>;
89
+ type AFSAIGatewayOptions = z.infer<typeof afsAIGatewayOptionsSchema>;
90
+ type AFSAIGatewayOptionsInput = z.input<typeof afsAIGatewayOptionsSchema>;
91
+ /** Response shape returned by `.actions/listModels`. */
92
+ interface ListModelsResponse {
93
+ entries: ListModelsEntry[];
94
+ }
95
+ interface ListModelsEntry {
96
+ model: string;
97
+ nativeModelId: string;
98
+ type: ModelType;
99
+ vendor: string;
100
+ available: boolean;
101
+ }
102
+ //#endregion
103
+ export { AFSAIGatewayOptions, AFSAIGatewayOptionsInput, ListModelsEntry, ListModelsResponse, ModelCatalog, ModelEntry, ModelType, afsAIGatewayOptionsSchema, modelCatalogSchema, modelEntrySchema, modelTypeSchema };
104
+ //# sourceMappingURL=types.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"mappings":";;;;cAGa,eAAA,EAAe,CAAA,CAAA,OAAA;;;;;;KAChB,SAAA,GAAY,CAAA,CAAE,KAAA,QAAa,eAAA;;;;;;;AAAvC;;;;cAYa,gBAAA,EAAgB,CAAA,CAAA,SAAA;;;;;;;;;;;;;KAQjB,UAAA,GAAa,CAAA,CAAE,KAAA,QAAa,gBAAA;;cAG3B,kBAAA,EAAkB,CAAA,CAAA,QAAA,CAAA,CAAA,CAAA,SAAA;;;;;;;;;;;;;KACnB,YAAA,GAAe,CAAA,CAAE,KAAA,QAAa,kBAAA;;;;;;;;;;;AAJ1C;;cAiCa,yBAAA,EAAyB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;KA6C1B,mBAAA,GAAsB,CAAA,CAAE,KAAA,QAAa,yBAAA;AAAA,KACrC,wBAAA,GAA2B,CAAA,CAAE,KAAA,QAAa,yBAAA;;UAGrC,kBAAA;EACf,OAAA,EAAS,eAAA;AAAA;AAAA,UAGM,eAAA;EACf,KAAA;EACA,aAAA;EACA,IAAA,EAAM,SAAA;EACN,MAAA;EACA,SAAA;AAAA"}
@@ -0,0 +1,104 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/types.d.ts
4
+ /** Shared vocabulary: the four AI Device capacity types. */
5
+ declare const modelTypeSchema: z.ZodEnum<{
6
+ chat: "chat";
7
+ embed: "embed";
8
+ image: "image";
9
+ video: "video";
10
+ }>;
11
+ type ModelType = z.infer<typeof modelTypeSchema>;
12
+ /**
13
+ * One entry in the bundled / user-supplied / remote model list.
14
+ *
15
+ * - `model` — canonical id the AI Device catalog uses (e.g. "claude-haiku-4-5")
16
+ * - `nativeModelId` — id fed to the underlying OpenAI SDK (e.g. "anthropic/claude-haiku-4-5")
17
+ * - `vendor` — vendor slug (openai / anthropic / google / …)
18
+ * - `type` — capacity type
19
+ * - `aliases` — extra ids users may reference
20
+ * - `available` — optional availability flag (default true)
21
+ */
22
+ declare const modelEntrySchema: z.ZodObject<{
23
+ model: z.ZodString;
24
+ nativeModelId: z.ZodString;
25
+ vendor: z.ZodString;
26
+ type: z.ZodEnum<{
27
+ chat: "chat";
28
+ embed: "embed";
29
+ image: "image";
30
+ video: "video";
31
+ }>;
32
+ aliases: z.ZodOptional<z.ZodArray<z.ZodString>>;
33
+ available: z.ZodOptional<z.ZodBoolean>;
34
+ }, z.core.$strip>;
35
+ type ModelEntry = z.infer<typeof modelEntrySchema>;
36
+ /** A catalog of models — same schema whether from bundled JSON or remote fetch. */
37
+ declare const modelCatalogSchema: z.ZodArray<z.ZodObject<{
38
+ model: z.ZodString;
39
+ nativeModelId: z.ZodString;
40
+ vendor: z.ZodString;
41
+ type: z.ZodEnum<{
42
+ chat: "chat";
43
+ embed: "embed";
44
+ image: "image";
45
+ video: "video";
46
+ }>;
47
+ aliases: z.ZodOptional<z.ZodArray<z.ZodString>>;
48
+ available: z.ZodOptional<z.ZodBoolean>;
49
+ }, z.core.$strip>>;
50
+ type ModelCatalog = z.infer<typeof modelCatalogSchema>;
51
+ /**
52
+ * Provider options — the `baseURL` must point at an OpenAI-compatible
53
+ * chat/completions root (i.e. POST {baseURL}/chat/completions works).
54
+ *
55
+ * Example baseURLs:
56
+ * - https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/compat
57
+ * - https://openrouter.ai/api/v1
58
+ * - https://api.openai.com/v1
59
+ * - http://localhost:4000/v1 (LiteLLM proxy)
60
+ * - http://localhost:11434/v1 (Ollama)
61
+ * - http://localhost:1234/v1 (LM Studio)
62
+ */
63
+ declare const afsAIGatewayOptionsSchema: z.ZodObject<{
64
+ name: z.ZodDefault<z.ZodString>;
65
+ description: z.ZodDefault<z.ZodString>;
66
+ baseURL: z.ZodString;
67
+ apiKey: z.ZodString;
68
+ listStrategy: z.ZodDefault<z.ZodEnum<{
69
+ bundled: "bundled";
70
+ endpoint: "endpoint";
71
+ }>>;
72
+ vendor: z.ZodOptional<z.ZodString>;
73
+ models: z.ZodOptional<z.ZodArray<z.ZodObject<{
74
+ model: z.ZodString;
75
+ nativeModelId: z.ZodString;
76
+ vendor: z.ZodString;
77
+ type: z.ZodEnum<{
78
+ chat: "chat";
79
+ embed: "embed";
80
+ image: "image";
81
+ video: "video";
82
+ }>;
83
+ aliases: z.ZodOptional<z.ZodArray<z.ZodString>>;
84
+ available: z.ZodOptional<z.ZodBoolean>;
85
+ }, z.core.$strip>>>;
86
+ extraHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
87
+ endpointTimeoutMs: z.ZodOptional<z.ZodNumber>;
88
+ }, z.core.$strip>;
89
+ type AFSAIGatewayOptions = z.infer<typeof afsAIGatewayOptionsSchema>;
90
+ type AFSAIGatewayOptionsInput = z.input<typeof afsAIGatewayOptionsSchema>;
91
+ /** Response shape returned by `.actions/listModels`. */
92
+ interface ListModelsResponse {
93
+ entries: ListModelsEntry[];
94
+ }
95
+ interface ListModelsEntry {
96
+ model: string;
97
+ nativeModelId: string;
98
+ type: ModelType;
99
+ vendor: string;
100
+ available: boolean;
101
+ }
102
+ //#endregion
103
+ export { AFSAIGatewayOptions, AFSAIGatewayOptionsInput, ListModelsEntry, ListModelsResponse, ModelCatalog, ModelEntry, ModelType, afsAIGatewayOptionsSchema, modelCatalogSchema, modelEntrySchema, modelTypeSchema };
104
+ //# sourceMappingURL=types.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;cAGa,eAAA,EAAe,CAAA,CAAA,OAAA;;;;;;KAChB,SAAA,GAAY,CAAA,CAAE,KAAA,QAAa,eAAA;;;;;;;AAAvC;;;;cAYa,gBAAA,EAAgB,CAAA,CAAA,SAAA;;;;;;;;;;;;;KAQjB,UAAA,GAAa,CAAA,CAAE,KAAA,QAAa,gBAAA;;cAG3B,kBAAA,EAAkB,CAAA,CAAA,QAAA,CAAA,CAAA,CAAA,SAAA;;;;;;;;;;;;;KACnB,YAAA,GAAe,CAAA,CAAE,KAAA,QAAa,kBAAA;;;;;;;;;;;AAJ1C;;cAiCa,yBAAA,EAAyB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;KA6C1B,mBAAA,GAAsB,CAAA,CAAE,KAAA,QAAa,yBAAA;AAAA,KACrC,wBAAA,GAA2B,CAAA,CAAE,KAAA,QAAa,yBAAA;;UAGrC,kBAAA;EACf,OAAA,EAAS,eAAA;AAAA;AAAA,UAGM,eAAA;EACf,KAAA;EACA,aAAA;EACA,IAAA,EAAM,SAAA;EACN,MAAA;EACA,SAAA;AAAA"}
package/dist/types.mjs ADDED
@@ -0,0 +1,77 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/types.ts
4
+ /** Shared vocabulary: the four AI Device capacity types. */
5
+ const modelTypeSchema = z.enum([
6
+ "chat",
7
+ "embed",
8
+ "image",
9
+ "video"
10
+ ]);
11
+ /**
12
+ * One entry in the bundled / user-supplied / remote model list.
13
+ *
14
+ * - `model` — canonical id the AI Device catalog uses (e.g. "claude-haiku-4-5")
15
+ * - `nativeModelId` — id fed to the underlying OpenAI SDK (e.g. "anthropic/claude-haiku-4-5")
16
+ * - `vendor` — vendor slug (openai / anthropic / google / …)
17
+ * - `type` — capacity type
18
+ * - `aliases` — extra ids users may reference
19
+ * - `available` — optional availability flag (default true)
20
+ */
21
+ const modelEntrySchema = z.object({
22
+ model: z.string().min(1),
23
+ nativeModelId: z.string().min(1),
24
+ vendor: z.string().min(1),
25
+ type: modelTypeSchema,
26
+ aliases: z.array(z.string()).optional(),
27
+ available: z.boolean().optional()
28
+ });
29
+ /** A catalog of models — same schema whether from bundled JSON or remote fetch. */
30
+ const modelCatalogSchema = z.array(modelEntrySchema);
31
+ /**
32
+ * Source of truth for the model list.
33
+ *
34
+ * - `"bundled"` (default): use the package's `models.json` + any user `models` override.
35
+ * Zero network dependency at startup. Right for remote gateways (CF Gateway,
36
+ * OpenRouter) where the operator has curated the allowlist.
37
+ *
38
+ * - `"endpoint"`: lazily `GET {baseURL}/models` and derive the list from the
39
+ * response. Right for **local runtimes** (Ollama, LM Studio, LiteLLM) where
40
+ * the runtime's own `/v1/models` already reflects exactly what's loaded.
41
+ * Falls back to bundled + user override if the endpoint fails.
42
+ */
43
+ const listStrategySchema = z.enum(["bundled", "endpoint"]);
44
+ /**
45
+ * Provider options — the `baseURL` must point at an OpenAI-compatible
46
+ * chat/completions root (i.e. POST {baseURL}/chat/completions works).
47
+ *
48
+ * Example baseURLs:
49
+ * - https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/compat
50
+ * - https://openrouter.ai/api/v1
51
+ * - https://api.openai.com/v1
52
+ * - http://localhost:4000/v1 (LiteLLM proxy)
53
+ * - http://localhost:11434/v1 (Ollama)
54
+ * - http://localhost:1234/v1 (LM Studio)
55
+ */
56
+ const afsAIGatewayOptionsSchema = z.object({
57
+ name: z.string().default("ai-gateway"),
58
+ description: z.string().default("AI Gateway provider — OpenAI-compatible backend surfaced as an AI Device hub. Execute inference via .actions/chat, .actions/embed, .actions/generateImage, .actions/generateVideo on any model node."),
59
+ baseURL: z.string().meta({
60
+ env: ["AI_GATEWAY_BASE_URL"],
61
+ description: "OpenAI-compatible base URL (chat/completions will be appended by the SDK)."
62
+ }),
63
+ apiKey: z.string().meta({
64
+ sensitive: true,
65
+ env: ["AI_GATEWAY_API_KEY"],
66
+ description: "Bearer token sent as Authorization header."
67
+ }),
68
+ listStrategy: listStrategySchema.default("bundled").describe("How to populate the model list — 'bundled' (static) or 'endpoint' (fetch /v1/models)."),
69
+ vendor: z.string().optional().describe("Default vendor slug applied to entries discovered via listStrategy:endpoint (when no better guess from the id)."),
70
+ models: modelCatalogSchema.optional().describe("Bundled/override catalog. Used as the primary source for listStrategy:bundled, and as fallback for listStrategy:endpoint when the /v1/models call fails."),
71
+ extraHeaders: z.record(z.string(), z.string()).optional().describe("Extra HTTP headers forwarded on every request — e.g. cf-aig-cache-ttl for Cloudflare AI Gateway."),
72
+ endpointTimeoutMs: z.number().positive().optional().describe("Timeout (ms) for the /v1/models fetch when listStrategy:endpoint. Default 5000.")
73
+ });
74
+
75
+ //#endregion
76
+ export { afsAIGatewayOptionsSchema, modelCatalogSchema, modelEntrySchema, modelTypeSchema };
77
+ //# sourceMappingURL=types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.mjs","names":[],"sources":["../src/types.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/** Shared vocabulary: the four AI Device capacity types. */\nexport const modelTypeSchema = z.enum([\"chat\", \"embed\", \"image\", \"video\"]);\nexport type ModelType = z.infer<typeof modelTypeSchema>;\n\n/**\n * One entry in the bundled / user-supplied / remote model list.\n *\n * - `model` — canonical id the AI Device catalog uses (e.g. \"claude-haiku-4-5\")\n * - `nativeModelId` — id fed to the underlying OpenAI SDK (e.g. \"anthropic/claude-haiku-4-5\")\n * - `vendor` — vendor slug (openai / anthropic / google / …)\n * - `type` — capacity type\n * - `aliases` — extra ids users may reference\n * - `available` — optional availability flag (default true)\n */\nexport const modelEntrySchema = z.object({\n model: z.string().min(1),\n nativeModelId: z.string().min(1),\n vendor: z.string().min(1),\n type: modelTypeSchema,\n aliases: z.array(z.string()).optional(),\n available: z.boolean().optional(),\n});\nexport type ModelEntry = z.infer<typeof modelEntrySchema>;\n\n/** A catalog of models — same schema whether from bundled JSON or remote fetch. */\nexport const modelCatalogSchema = z.array(modelEntrySchema);\nexport type ModelCatalog = z.infer<typeof modelCatalogSchema>;\n\n/**\n * Source of truth for the model list.\n *\n * - `\"bundled\"` (default): use the package's `models.json` + any user `models` override.\n * Zero network dependency at startup. Right for remote gateways (CF Gateway,\n * OpenRouter) where the operator has curated the allowlist.\n *\n * - `\"endpoint\"`: lazily `GET {baseURL}/models` and derive the list from the\n * response. Right for **local runtimes** (Ollama, LM Studio, LiteLLM) where\n * the runtime's own `/v1/models` already reflects exactly what's loaded.\n * Falls back to bundled + user override if the endpoint fails.\n */\nexport const listStrategySchema = z.enum([\"bundled\", \"endpoint\"]);\nexport type ListStrategy = z.infer<typeof listStrategySchema>;\n\n/**\n * Provider options — the `baseURL` must point at an OpenAI-compatible\n * chat/completions root (i.e. POST {baseURL}/chat/completions works).\n *\n * Example baseURLs:\n * - https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/compat\n * - https://openrouter.ai/api/v1\n * - https://api.openai.com/v1\n * - http://localhost:4000/v1 (LiteLLM proxy)\n * - http://localhost:11434/v1 (Ollama)\n * - http://localhost:1234/v1 (LM Studio)\n */\nexport const afsAIGatewayOptionsSchema = z.object({\n name: z.string().default(\"ai-gateway\"),\n description: z\n .string()\n .default(\n \"AI Gateway provider — OpenAI-compatible backend surfaced as an AI Device hub. Execute inference via .actions/chat, .actions/embed, .actions/generateImage, .actions/generateVideo on any model node.\",\n ),\n baseURL: z.string().meta({\n env: [\"AI_GATEWAY_BASE_URL\"],\n description: \"OpenAI-compatible base URL (chat/completions will be appended by the SDK).\",\n }),\n apiKey: z.string().meta({\n sensitive: true,\n env: [\"AI_GATEWAY_API_KEY\"],\n description: \"Bearer token sent as Authorization header.\",\n }),\n listStrategy: listStrategySchema\n .default(\"bundled\")\n .describe(\n \"How to populate the model list — 'bundled' (static) or 'endpoint' (fetch /v1/models).\",\n ),\n vendor: z\n .string()\n .optional()\n .describe(\n \"Default vendor slug applied to entries discovered via listStrategy:endpoint (when no better guess from the id).\",\n ),\n models: modelCatalogSchema\n .optional()\n .describe(\n \"Bundled/override catalog. Used as the primary source for listStrategy:bundled, and as fallback for listStrategy:endpoint when the /v1/models call fails.\",\n ),\n extraHeaders: z\n .record(z.string(), z.string())\n .optional()\n .describe(\n \"Extra HTTP headers forwarded on every request — e.g. cf-aig-cache-ttl for Cloudflare AI Gateway.\",\n ),\n endpointTimeoutMs: z\n .number()\n .positive()\n .optional()\n .describe(\"Timeout (ms) for the /v1/models fetch when listStrategy:endpoint. Default 5000.\"),\n});\n\nexport type AFSAIGatewayOptions = z.infer<typeof afsAIGatewayOptionsSchema>;\nexport type AFSAIGatewayOptionsInput = z.input<typeof afsAIGatewayOptionsSchema>;\n\n/** Response shape returned by `.actions/listModels`. */\nexport interface ListModelsResponse {\n entries: ListModelsEntry[];\n}\n\nexport interface ListModelsEntry {\n model: string;\n nativeModelId: string;\n type: ModelType;\n vendor: string;\n available: boolean;\n}\n"],"mappings":";;;;AAGA,MAAa,kBAAkB,EAAE,KAAK;CAAC;CAAQ;CAAS;CAAS;CAAQ,CAAC;;;;;;;;;;;AAa1E,MAAa,mBAAmB,EAAE,OAAO;CACvC,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE;CACxB,eAAe,EAAE,QAAQ,CAAC,IAAI,EAAE;CAChC,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE;CACzB,MAAM;CACN,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;CACvC,WAAW,EAAE,SAAS,CAAC,UAAU;CAClC,CAAC;;AAIF,MAAa,qBAAqB,EAAE,MAAM,iBAAiB;;;;;;;;;;;;;AAe3D,MAAa,qBAAqB,EAAE,KAAK,CAAC,WAAW,WAAW,CAAC;;;;;;;;;;;;;AAejE,MAAa,4BAA4B,EAAE,OAAO;CAChD,MAAM,EAAE,QAAQ,CAAC,QAAQ,aAAa;CACtC,aAAa,EACV,QAAQ,CACR,QACC,uMACD;CACH,SAAS,EAAE,QAAQ,CAAC,KAAK;EACvB,KAAK,CAAC,sBAAsB;EAC5B,aAAa;EACd,CAAC;CACF,QAAQ,EAAE,QAAQ,CAAC,KAAK;EACtB,WAAW;EACX,KAAK,CAAC,qBAAqB;EAC3B,aAAa;EACd,CAAC;CACF,cAAc,mBACX,QAAQ,UAAU,CAClB,SACC,wFACD;CACH,QAAQ,EACL,QAAQ,CACR,UAAU,CACV,SACC,kHACD;CACH,QAAQ,mBACL,UAAU,CACV,SACC,2JACD;CACH,cAAc,EACX,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC,CAC9B,UAAU,CACV,SACC,mGACD;CACH,mBAAmB,EAChB,QAAQ,CACR,UAAU,CACV,UAAU,CACV,SAAS,kFAAkF;CAC/F,CAAC"}