@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.
- package/LICENSE.md +26 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
- package/dist/_virtual/rolldown_runtime.cjs +29 -0
- package/dist/ai-gateway.cjs +1083 -0
- package/dist/ai-gateway.d.cts +124 -0
- package/dist/ai-gateway.d.cts.map +1 -0
- package/dist/ai-gateway.d.mts +124 -0
- package/dist/ai-gateway.d.mts.map +1 -0
- package/dist/ai-gateway.mjs +1083 -0
- package/dist/ai-gateway.mjs.map +1 -0
- package/dist/index.cjs +14 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.mjs +6 -0
- package/dist/models.cjs +155 -0
- package/dist/models.d.cts +8 -0
- package/dist/models.d.cts.map +1 -0
- package/dist/models.d.mts +8 -0
- package/dist/models.d.mts.map +1 -0
- package/dist/models.mjs +150 -0
- package/dist/models.mjs.map +1 -0
- package/dist/models2.cjs +97 -0
- package/dist/models2.mjs +96 -0
- package/dist/models2.mjs.map +1 -0
- package/dist/normalize.cjs +49 -0
- package/dist/normalize.d.cts +10 -0
- package/dist/normalize.d.cts.map +1 -0
- package/dist/normalize.d.mts +10 -0
- package/dist/normalize.d.mts.map +1 -0
- package/dist/normalize.mjs +47 -0
- package/dist/normalize.mjs.map +1 -0
- package/dist/types.cjs +80 -0
- package/dist/types.d.cts +104 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +104 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +77 -0
- package/dist/types.mjs.map +1 -0
- package/manifest.json +40 -0
- package/models.json +145 -0
- package/package.json +61 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-gateway.mjs","names":[],"sources":["../src/ai-gateway.ts"],"sourcesContent":["import type {\n AFSEntry,\n AFSExecChunk,\n AFSExecOptions,\n AFSExecResult,\n AFSExplainResult,\n AFSStatResult,\n CapabilitiesManifest,\n JSONSchema7,\n ProviderManifest,\n ProviderTreeSchema,\n RouteContext,\n} from \"@aigne/afs\";\nimport {\n Actions,\n AFSBaseProvider,\n AFSNotFoundError,\n Explain,\n List,\n Meta,\n makeNsLog,\n Read,\n Stat,\n} from \"@aigne/afs\";\nimport { zodParse } from \"@aigne/afs/utils/zod\";\nimport type {\n ChatModelInputMessage,\n ChatModelOutput,\n ModelResponseChunk,\n ModelResponseStream,\n} from \"@aigne/model-base\";\nimport { mergeModelResponseChunk } from \"@aigne/model-base\";\nimport { OpenAIChatModel, OpenAIEmbeddingModel } from \"@aigne/openai\";\nimport { joinURL } from \"ufo\";\nimport { DEFAULT_MODELS, fetchModelsFromEndpoint } from \"./models.js\";\nimport { findModelEntry, toCanonicalModel } from \"./normalize.js\";\nimport {\n type AFSAIGatewayOptionsInput,\n afsAIGatewayOptionsSchema,\n type ListModelsEntry,\n type ListModelsResponse,\n type ListStrategy,\n type ModelCatalog,\n type ModelEntry,\n} from \"./types.js\";\n\nconst log = makeNsLog(\"provider:ai-gateway\");\n\nconst TYPES = [\"chat\", \"embed\", \"image\", \"video\"] as const;\ntype ModelType = (typeof TYPES)[number];\n\nconst TYPE_ACTION: Record<ModelType, string> = {\n chat: \"chat\",\n embed: \"embed\",\n image: \"generateImage\",\n video: \"generateVideo\",\n};\n\n// ─── JSON schemas for actions ──────────────────────────────────────────────\n\nconst CHAT_SCHEMA: JSONSchema7 = {\n type: \"object\",\n properties: {\n prompt: { type: \"string\" },\n messages: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n role: { type: \"string\" },\n content: {\n oneOf: [{ type: \"string\" }, { type: \"null\" }, { type: \"array\" }],\n },\n tool_calls: { type: \"array\" },\n tool_call_id: { type: \"string\" },\n },\n required: [\"role\"],\n },\n },\n temperature: { type: \"number\" },\n topP: { type: \"number\" },\n maxTokens: { type: \"number\" },\n responseFormat: { type: \"object\" },\n },\n};\n\nconst EMBED_SCHEMA: JSONSchema7 = {\n type: \"object\",\n properties: {\n input: {\n oneOf: [{ type: \"string\" }, { type: \"array\", items: { type: \"string\" } }],\n description: \"Text(s) to embed\",\n },\n text: { type: \"string\", description: \"Shorthand for single-text input\" },\n },\n};\n\nconst LIST_MODELS_SCHEMA: JSONSchema7 = {\n type: \"object\",\n properties: {\n type: { type: \"string\", enum: [\"chat\", \"embed\", \"image\", \"video\"] },\n },\n};\n\ninterface ActionDef {\n name: string;\n description: string;\n schema: JSONSchema7;\n}\n\nconst HUB_ACTIONS: ActionDef[] = [\n {\n name: \"listModels\",\n description:\n \"Return every model exposed by this hub as { entries: [{ model, nativeModelId, available, vendor, type }] }.\",\n schema: LIST_MODELS_SCHEMA,\n },\n {\n name: \"refresh\",\n description:\n \"Reset client caches (noop for static bundled lists; honored for contract parity).\",\n schema: { type: \"object\", properties: {} },\n },\n];\n\n// ─── Helpers ───────────────────────────────────────────────────────────────\n\n/**\n * Adapt a `response_format: { type: \"json_schema\", ... }` payload so it\n * passes Cloudflare AI Gateway's stricter validation than vanilla OpenAI:\n *\n * 1. `strict` defaults to `true` — CF rejects requests where the field\n * is omitted (`Field required`) and accepts only `true`\n * (`Input should be True`).\n * 2. Every nested object in the schema gets `additionalProperties: false`\n * and `required` listing all of its `properties` keys — OpenAI's\n * strict mode demands this. Without it CF returns 400 like\n * `For 'object' type, 'additionalProperties' must be explicitly set\n * to false`.\n *\n * Both transformations are no-ops on schemas that already comply, so\n * callers who write strict-correct schemas keep working unchanged. Without\n * this normaliser scan-spam (`SPAM_JUDGE_SCHEMA`) failed every request\n * with `LLM call failed after 3 attempts` and agent-run returned\n * `{ status: \"error\" }`, which scan-spam translated to\n * `reason: \"no result\"` for every message.\n */\nfunction normalizeResponseFormatForOpenAI(rf: unknown): unknown {\n if (!rf || typeof rf !== \"object\") return rf;\n const obj = rf as Record<string, unknown>;\n if (obj.type !== \"json_schema\") return rf;\n const js = obj.jsonSchema as Record<string, unknown> | undefined;\n if (!js || typeof js !== \"object\") return rf;\n const schema = js.schema as Record<string, unknown> | undefined;\n return {\n ...obj,\n jsonSchema: {\n ...js,\n strict: typeof js.strict === \"boolean\" ? js.strict : true,\n ...(schema ? { schema: enforceStrictSchema(schema) } : {}),\n },\n };\n}\n\n/**\n * Recursively patch a JSON schema for OpenAI strict mode:\n * - `additionalProperties: false` on every object node\n * - `required` listing every key in `properties`\n * - Strip keywords OpenAI strict rejects (`minimum`, `maximum`,\n * `minLength`, `maxLength`, `minItems`, `maxItems`, `pattern`,\n * `format`, `multipleOf`, `exclusiveMinimum`, `exclusiveMaximum`).\n * These are validation hints — losing them means the model's output\n * isn't bounds-checked server-side, but it's far better than the\n * alternative (request fails with 400, scan-spam sees \"no result\"\n * for every message). Caller-side schema validation can re-apply the\n * bounds afterward if needed.\n */\nconst STRICT_INCOMPATIBLE_KEYWORDS = [\n \"minimum\",\n \"maximum\",\n \"exclusiveMinimum\",\n \"exclusiveMaximum\",\n \"multipleOf\",\n \"minLength\",\n \"maxLength\",\n \"pattern\",\n \"format\",\n \"minItems\",\n \"maxItems\",\n \"uniqueItems\",\n \"minProperties\",\n \"maxProperties\",\n] as const;\n\nfunction enforceStrictSchema(node: unknown): unknown {\n if (!node || typeof node !== \"object\" || Array.isArray(node)) return node;\n const n = node as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(n)) {\n if ((STRICT_INCOMPATIBLE_KEYWORDS as readonly string[]).includes(k)) continue;\n out[k] = v;\n }\n\n if (n.type === \"object\" && n.properties && typeof n.properties === \"object\") {\n const props = n.properties as Record<string, unknown>;\n const patchedProps: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(props)) patchedProps[k] = enforceStrictSchema(v);\n out.properties = patchedProps;\n if (out.additionalProperties === undefined) out.additionalProperties = false;\n if (!Array.isArray(out.required)) out.required = Object.keys(patchedProps);\n }\n\n if (n.type === \"array\" && n.items) {\n out.items = Array.isArray(n.items)\n ? n.items.map((it) => enforceStrictSchema(it))\n : enforceStrictSchema(n.items);\n }\n\n for (const composer of [\"anyOf\", \"oneOf\", \"allOf\"] as const) {\n if (Array.isArray(n[composer])) {\n out[composer] = (n[composer] as unknown[]).map((x) => enforceStrictSchema(x));\n }\n }\n\n return out;\n}\n\nfunction inferenceError(modelName: string, err: unknown): AFSExecResult {\n const raw = err instanceof Error ? err.message : String(err);\n const isConnErr =\n raw.includes(\"fetch failed\") ||\n raw.includes(\"ECONNREFUSED\") ||\n raw.includes(\"ECONNRESET\") ||\n raw.includes(\"ETIMEDOUT\");\n return {\n success: false,\n error: {\n code: \"INFERENCE_ERROR\",\n message: isConnErr\n ? `Connection to gateway lost for ${modelName} (will retry with fresh connection)`\n : `Inference failed for ${modelName}: ${raw}`,\n },\n };\n}\n\ntype AIGNERole = ChatModelInputMessage[\"role\"];\nconst VALID_ROLES: ReadonlySet<AIGNERole> = new Set([\"system\", \"user\", \"agent\", \"tool\"]);\n\nfunction mapRole(role: unknown): AIGNERole {\n if (role === \"assistant\") return \"agent\";\n if (typeof role === \"string\" && VALID_ROLES.has(role as AIGNERole)) return role as AIGNERole;\n return \"user\";\n}\n\n// ─── Prompt-cache pass-through helpers ──────────────────────────────────────\n// OpenAIChatModel.contentsFromInputMessages strips all extra fields (including\n// cache_control) when serialising to the OpenAI wire format. For Anthropic\n// models we bypass the SDK and POST the JSON body ourselves so that\n// cache_control markers injected by ai-device's prompt-cache middleware reach\n// the Anthropic API (via the gateway's baseURL).\n\ntype RawBlock = Record<string, unknown>;\n\nfunction blockHasCacheMarker(b: unknown): boolean {\n const raw = b as RawBlock;\n return raw.cache_control !== undefined || raw.cacheControl !== undefined;\n}\n\nfunction messagesHaveCacheMarkers(messages: ChatModelInputMessage[]): boolean {\n return messages.some((m) => Array.isArray(m.content) && m.content.some(blockHasCacheMarker));\n}\n\n/** AIGNE role → OpenAI wire role. */\nfunction toOpenAIRole(role: AIGNERole): string {\n return role === \"agent\" ? \"assistant\" : role;\n}\n\n/** Serialise AIGNE messages to the OpenAI-compat JSON shape, forwarding cache_control. */\nfunction serializeMessagesForWire(messages: ChatModelInputMessage[]): unknown[] {\n return messages.map((m) => {\n const role = toOpenAIRole(m.role);\n const content =\n typeof m.content === \"string\"\n ? m.content\n : m.content?.map((b) => {\n const raw = b as RawBlock;\n if (raw.type === \"text\") {\n const cc = raw.cache_control ?? raw.cacheControl;\n return {\n type: \"text\",\n text: raw.text,\n ...(cc !== undefined ? { cache_control: cc } : {}),\n };\n }\n if (raw.type === \"url\") return { type: \"image_url\", image_url: { url: raw.url } };\n if (raw.type === \"file\")\n return {\n type: \"image_url\",\n image_url: { url: `data:${raw.mimeType || \"image/png\"};base64,${raw.data}` },\n };\n return raw;\n });\n const out: RawBlock = { role, content };\n if (m.toolCalls) {\n out.tool_calls = (m.toolCalls as RawBlock[]).map((tc) => ({\n ...tc,\n function: {\n ...(tc.function as object),\n arguments: JSON.stringify((tc.function as RawBlock)?.arguments),\n },\n }));\n }\n if (m.toolCallId) out.tool_call_id = m.toolCallId;\n if (m.name) out.name = m.name;\n return out;\n });\n}\n\n/** Parse an OpenAI-wire tool_calls array (string `function.arguments`) into\n * the AIGNE `toolCalls` shape (parsed-object `function.arguments`). */\nfunction parseWireToolCalls(raw: RawBlock[] | undefined): RawBlock[] | undefined {\n if (!Array.isArray(raw) || raw.length === 0) return undefined;\n return raw.map((tc) => {\n const fn = tc.function as RawBlock | undefined;\n const rawArgs = fn?.arguments;\n let args: unknown = rawArgs;\n if (typeof rawArgs === \"string\") {\n try {\n args = JSON.parse(rawArgs);\n } catch {\n args = rawArgs;\n }\n }\n return {\n id: tc.id,\n type: tc.type ?? \"function\",\n function: { name: fn?.name, arguments: args },\n };\n });\n}\n\n/** Convert a `normalizeResponseFormatForOpenAI`-normalized responseFormat\n * (AIGNE shape: `{ type: \"json_schema\", jsonSchema: {...} }`) into the\n * OpenAI wire shape (`{ type: \"json_schema\", json_schema: {...} }`) used by\n * the raw-fetch bypass body. Non-`json_schema` shapes (e.g. `json_object`)\n * pass through untouched — same convention as the SDK path. */\nfunction toWireResponseFormat(normalized: unknown): unknown {\n if (!normalized || typeof normalized !== \"object\") return normalized;\n const obj = normalized as RawBlock;\n if (obj.type !== \"json_schema\") return obj;\n return { type: \"json_schema\", json_schema: obj.jsonSchema };\n}\n\n/** Convert an OpenAI-compat chat-completion response to the AIGNE output shape. */\nfunction openAiRespToOutput(data: Record<string, unknown>): Record<string, unknown> {\n const choice = (data.choices as RawBlock[] | undefined)?.[0];\n const message = choice?.message as RawBlock | undefined;\n const text = (message?.content as string | null) ?? null;\n const u = data.usage as RawBlock | undefined;\n const out: Record<string, unknown> = { text };\n const toolCalls = parseWireToolCalls(message?.tool_calls as RawBlock[] | undefined);\n if (toolCalls) out.toolCalls = toolCalls;\n if (u) {\n out.usage = {\n inputTokens: (u.prompt_tokens as number) ?? 0,\n outputTokens: (u.completion_tokens as number) ?? 0,\n };\n }\n return out;\n}\n\n// ─── end prompt-cache helpers ────────────────────────────────────────────────\n\n/** OpenAI → AIGNE message shape (assistant → agent, snake_case → camelCase). */\nfunction normalizeMessage(msg: Record<string, unknown>): ChatModelInputMessage {\n const out: Partial<ChatModelInputMessage> & { role: AIGNERole } = {\n role: mapRole(msg.role),\n };\n if (msg.content !== undefined && msg.content !== null) {\n out.content = msg.content as ChatModelInputMessage[\"content\"];\n }\n const toolCalls = msg.toolCalls ?? msg.tool_calls;\n if (toolCalls !== undefined) out.toolCalls = toolCalls as ChatModelInputMessage[\"toolCalls\"];\n const toolCallId = msg.toolCallId ?? msg.tool_call_id;\n if (typeof toolCallId === \"string\") out.toolCallId = toolCallId;\n if (typeof msg.name === \"string\") out.name = msg.name;\n return out as ChatModelInputMessage;\n}\n\n// ─── Provider ──────────────────────────────────────────────────────────────\n\nexport class AFSAIGateway extends AFSBaseProvider {\n override readonly name: string;\n override readonly description?: string;\n override readonly accessMode = \"readwrite\" as const;\n\n private readonly apiKey: string;\n private readonly baseURL: string;\n private readonly extraHeaders: Record<string, string>;\n private readonly listStrategy: ListStrategy;\n private readonly defaultVendor: string | undefined;\n private readonly endpointTimeoutMs: number;\n\n /**\n * The fallback catalog used (a) directly in bundled mode and (b) when the\n * endpoint fetch fails in endpoint mode.\n */\n private readonly fallbackModels: ModelCatalog;\n\n /**\n * Current resolved catalog. For `bundled` this is just `fallbackModels`.\n * For `endpoint` this is `null` until the first fetch completes; subsequent\n * access goes through `ensureModelsLoaded()`.\n */\n private cachedModels: ModelCatalog | null;\n\n /** De-duplicate concurrent endpoint fetches. */\n private loadInflight: Promise<void> | null = null;\n\n private readonly chatCache = new Map<string, InstanceType<typeof OpenAIChatModel>>();\n private readonly embedCache = new Map<string, InstanceType<typeof OpenAIEmbeddingModel>>();\n\n constructor(options: AFSAIGatewayOptionsInput) {\n super();\n const parsed = zodParse(afsAIGatewayOptionsSchema, options);\n this.name = parsed.name;\n this.description = parsed.description;\n this.baseURL = parsed.baseURL;\n this.apiKey = parsed.apiKey;\n this.extraHeaders = parsed.extraHeaders ?? {};\n this.listStrategy = parsed.listStrategy;\n this.defaultVendor = parsed.vendor;\n this.endpointTimeoutMs = parsed.endpointTimeoutMs ?? 5000;\n // parsed.models is already zod-validated; empty arrays → bundled default.\n this.fallbackModels =\n parsed.models && parsed.models.length > 0 ? parsed.models : DEFAULT_MODELS;\n // Bundled mode: list is already final. Endpoint mode: wait for first fetch.\n this.cachedModels = this.listStrategy === \"bundled\" ? this.fallbackModels : null;\n }\n\n /** Getter for current models — lazy resolves endpoint strategy on first read. */\n private async ensureModelsLoaded(): Promise<ModelCatalog> {\n if (this.cachedModels) return this.cachedModels;\n if (!this.loadInflight) {\n this.loadInflight = this.loadFromEndpoint();\n }\n try {\n await this.loadInflight;\n } finally {\n this.loadInflight = null;\n }\n return this.cachedModels ?? this.fallbackModels;\n }\n\n private async loadFromEndpoint(): Promise<void> {\n try {\n const fetched = await fetchModelsFromEndpoint(this.baseURL, this.apiKey, {\n ...(this.defaultVendor ? { defaultVendor: this.defaultVendor } : {}),\n timeoutMs: this.endpointTimeoutMs,\n });\n this.cachedModels = fetched;\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n // Fall back to bundled so the provider still works partially while the\n // endpoint is down. The failure is surfaced in `.actions/refresh` below.\n log.warn(`[ai-gateway:${this.name}] /models fetch failed, using fallback catalog: ${detail}`);\n if (!this.cachedModels) this.cachedModels = this.fallbackModels;\n }\n }\n\n /** Synchronous read — for routes that need the list right now. */\n private get models(): ModelCatalog {\n return this.cachedModels ?? this.fallbackModels;\n }\n\n static manifest(): ProviderManifest {\n return {\n name: \"ai-gateway\",\n description:\n \"OpenAI-compatible AI gateway bridge (Cloudflare AI Gateway / OpenRouter / LiteLLM / OpenAI direct)\",\n uriTemplate: \"ai-gateway://{name?}\",\n category: \"ai\",\n schema: afsAIGatewayOptionsSchema,\n tags: [\"ai\", \"llm\", \"gateway\", \"openai-compatible\", \"ai:hub\"],\n capabilityTags: [\"auth:token\", \"remote\", \"http\", \"rate-limited\", \"streaming\"],\n security: {\n riskLevel: \"external\",\n resourceAccess: [\"internet\"],\n dataSensitivity: [\"credentials\"],\n notes: [\n \"Forwards prompts to a remote OpenAI-compatible gateway — API key authorizes usage and incurs cost.\",\n ],\n },\n capabilities: {\n network: { egress: true },\n secrets: [\"ai-gateway/api-key\"],\n },\n };\n }\n\n static treeSchema(): ProviderTreeSchema {\n return {\n operations: [\"list\", \"read\", \"exec\", \"stat\", \"explain\"],\n tree: {\n \"/\": {\n kind: \"ai-gateway:root\",\n operations: [\"list\", \"read\", \"exec\"],\n actions: [\"listModels\", \"refresh\"],\n },\n \"/models\": { kind: \"ai-gateway:directory\", operations: [\"list\", \"read\"] },\n \"/models/{model}\": {\n kind: \"ai-gateway:model\",\n operations: [\"read\", \"exec\"],\n actions: [\"chat\", \"embed\", \"generateImage\", \"generateVideo\"],\n },\n },\n auth: { type: \"token\", env: [\"AI_GATEWAY_API_KEY\"] },\n bestFor: [\"AI inference via OpenAI-compatible gateways\"],\n notFor: [\"data storage\", \"model training\"],\n };\n }\n\n // ─── internal helpers ────────────────────────────────────────────────────\n\n private findModel(canonical: string): ModelEntry {\n const hit = findModelEntry(canonical, this.models);\n if (!hit) {\n const avail = this.models.map((m) => m.model).slice(0, 10);\n throw new AFSNotFoundError(\n joinURL(\"/models\", canonical),\n `Model '${canonical}' not found. Available: ${avail.join(\", \")}${this.models.length > 10 ? \"…\" : \"\"}`,\n );\n }\n return hit;\n }\n\n private openAIClientOptions() {\n return Object.keys(this.extraHeaders).length > 0\n ? { defaultHeaders: this.extraHeaders }\n : undefined;\n }\n\n private getChatClient(nativeId: string): InstanceType<typeof OpenAIChatModel> {\n let m = this.chatCache.get(nativeId);\n if (!m) {\n const opts = this.openAIClientOptions();\n m = new OpenAIChatModel({\n baseURL: this.baseURL,\n apiKey: this.apiKey,\n model: nativeId,\n ...(opts ? { clientOptions: opts } : {}),\n });\n this.chatCache.set(nativeId, m);\n }\n return m;\n }\n\n private getEmbedClient(nativeId: string): InstanceType<typeof OpenAIEmbeddingModel> {\n let m = this.embedCache.get(nativeId);\n if (!m) {\n const opts = this.openAIClientOptions();\n m = new OpenAIEmbeddingModel({\n baseURL: this.baseURL,\n apiKey: this.apiKey,\n model: nativeId,\n ...(opts ? { clientOptions: opts } : {}),\n });\n this.embedCache.set(nativeId, m);\n }\n return m;\n }\n\n // ─── root ────────────────────────────────────────────────────────────────\n\n @List(\"/\")\n async listRoot(_ctx: RouteContext): Promise<{ data: AFSEntry[] }> {\n const models = await this.ensureModelsLoaded();\n return {\n data: [\n this.buildEntry(\"/models\", {\n meta: { childrenCount: models.length, kind: \"ai-gateway:directory\" },\n }),\n ],\n };\n }\n\n @Read(\"/\")\n async readRoot(_ctx: RouteContext): Promise<AFSEntry> {\n const models = await this.ensureModelsLoaded();\n return this.buildEntry(\"/\", {\n content: {\n provider: \"ai-gateway\",\n baseURL: this.baseURL,\n listStrategy: this.listStrategy,\n modelCount: models.length,\n },\n meta: { childrenCount: 1, kind: \"ai-gateway:root\" },\n });\n }\n\n @Meta(\"/\")\n async rootMeta(_ctx: RouteContext): Promise<AFSEntry> {\n const models = await this.ensureModelsLoaded();\n const byType: Record<string, number> = {};\n for (const m of models) byType[m.type] = (byType[m.type] ?? 0) + 1;\n return this.buildEntry(\"/.meta\", {\n content: {\n provider: \"ai-gateway\",\n baseURL: this.baseURL,\n description: this.description,\n listStrategy: this.listStrategy,\n modelCount: models.length,\n modelsByType: byType,\n },\n meta: { kind: \"ai-gateway:root\" },\n });\n }\n\n @Stat(\"/\")\n async statRoot(_ctx: RouteContext): Promise<AFSStatResult> {\n return {\n data: this.buildEntry(\"/\", {\n meta: { childrenCount: 1, kind: \"ai-gateway:root\" },\n }),\n };\n }\n\n @Read(\"/.meta/.capabilities\")\n async readCapabilities(_ctx: RouteContext): Promise<AFSEntry> {\n const operations = this.getOperationsDeclaration();\n const manifest: CapabilitiesManifest = {\n schemaVersion: 1,\n provider: this.name,\n description: this.description || \"AI Gateway provider\",\n tools: [],\n operations,\n actions: [\n {\n description: \"Hub-level actions\",\n catalog: [\n {\n name: \"listModels\",\n description: \"List every bundled model with vendor + type metadata\",\n inputSchema: LIST_MODELS_SCHEMA,\n },\n {\n name: \"refresh\",\n description: \"Clear per-model SDK caches\",\n inputSchema: { type: \"object\", properties: {} },\n },\n ],\n discovery: {\n pathTemplate: \"/.actions\",\n note: \"Hub-level actions: listModels, refresh\",\n },\n },\n {\n description: \"Model-level actions (varies by model type)\",\n catalog: [\n {\n name: \"chat\",\n description: \"Chat inference (chat models)\",\n inputSchema: CHAT_SCHEMA,\n },\n {\n name: \"embed\",\n description: \"Embeddings (embed models)\",\n inputSchema: EMBED_SCHEMA,\n },\n ],\n discovery: {\n pathTemplate: \"/models/:canonical/.actions\",\n note: \"Model-level actions depend on type. Chat models expose 'chat', embedding models expose 'embed'.\",\n },\n },\n ],\n };\n return this.buildEntry(\"/.meta/.capabilities\", {\n content: manifest,\n meta: { kind: \"afs:capabilities\", ...operations },\n });\n }\n\n @Explain(\"/\")\n async explainRoot(_ctx: RouteContext): Promise<AFSExplainResult> {\n const models = await this.ensureModelsLoaded();\n const typesWithEntries = TYPES.filter((t) => models.some((m) => m.type === t));\n const lines = [\n `# ${this.name}`,\n \"\",\n this.description ?? \"\",\n \"\",\n `- **baseURL**: \\`${this.baseURL}\\``,\n `- **listStrategy**: \\`${this.listStrategy}\\``,\n `- **models**: ${models.length} (${typesWithEntries.join(\", \")})`,\n \"\",\n \"## Hub Contract\",\n \"- `/.actions/listModels` → canonical model list\",\n \"- `/models/{canonical}/.actions/chat` (or `embed`, `generateImage`, `generateVideo`)\",\n ];\n return { format: \"markdown\", content: lines.join(\"\\n\") };\n }\n\n // ─── /.actions (hub-level) ────────────────────────────────────────────────\n\n @Actions(\"/\")\n async listRootActions(_ctx: RouteContext): Promise<{ data: AFSEntry[] }> {\n return {\n data: HUB_ACTIONS.map((a) =>\n this.buildEntry(joinURL(\"/.actions\", a.name), {\n content: { description: a.description, schema: a.schema },\n meta: { kind: \"afs:executable\" },\n }),\n ),\n };\n }\n\n @Actions.Exec(\"/\", \"listModels\", undefined, { effect: \"read\" })\n async execListModels(_ctx: RouteContext, args: Record<string, unknown>): Promise<AFSExecResult> {\n const models = await this.ensureModelsLoaded();\n const requested = typeof args.type === \"string\" ? (args.type as ModelType) : undefined;\n const entries: ListModelsEntry[] = [];\n for (const m of models) {\n if (requested && m.type !== requested) continue;\n entries.push({\n model: m.model,\n nativeModelId: m.nativeModelId,\n type: m.type,\n vendor: m.vendor,\n available: m.available ?? true,\n });\n }\n const response: ListModelsResponse = { entries };\n return { success: true, data: response as unknown as Record<string, unknown> };\n }\n\n @Actions.Exec(\"/\", \"refresh\", undefined, { effect: \"write\" })\n async execRefresh(): Promise<AFSExecResult> {\n this.chatCache.clear();\n this.embedCache.clear();\n // In endpoint mode, force a re-fetch so `ollama pull` / new LM Studio\n // models show up without restarting the daemon.\n let refetchError: string | null = null;\n if (this.listStrategy === \"endpoint\") {\n this.cachedModels = null;\n try {\n await this.ensureModelsLoaded();\n } catch (err) {\n refetchError = err instanceof Error ? err.message : String(err);\n }\n }\n return {\n success: true,\n data: {\n message: refetchError\n ? `Caches cleared; endpoint re-fetch failed (${refetchError})`\n : \"Gateway caches cleared.\",\n listStrategy: this.listStrategy,\n modelCount: this.models.length,\n },\n };\n }\n\n // ─── /models tree ─────────────────────────────────────────────────────────\n\n @List(\"/models\")\n async listModels(_ctx: RouteContext): Promise<{ data: AFSEntry[] }> {\n const models = await this.ensureModelsLoaded();\n return {\n data: models.map((m) =>\n this.buildEntry(joinURL(\"/models\", m.model), {\n content: {\n model: m.model,\n vendor: m.vendor,\n type: m.type,\n nativeModelId: m.nativeModelId,\n },\n meta: {\n childrenCount: 2,\n kind: \"ai-gateway:model\",\n vendor: m.vendor,\n capacity: { type: m.type },\n },\n }),\n ),\n };\n }\n\n @Read(\"/models\")\n async readModels(_ctx: RouteContext): Promise<AFSEntry> {\n const models = await this.ensureModelsLoaded();\n return this.buildEntry(\"/models\", {\n content: { count: models.length },\n meta: { childrenCount: models.length, kind: \"ai-gateway:directory\" },\n });\n }\n\n @Meta(\"/models\")\n async metaModels(_ctx: RouteContext): Promise<AFSEntry> {\n const models = await this.ensureModelsLoaded();\n return this.buildEntry(\"/models/.meta\", {\n content: { count: models.length },\n meta: { kind: \"ai-gateway:directory\" },\n });\n }\n\n @Stat(\"/models\")\n async statModels(_ctx: RouteContext): Promise<AFSStatResult> {\n const models = await this.ensureModelsLoaded();\n return {\n data: this.buildEntry(\"/models\", {\n meta: { childrenCount: models.length, kind: \"ai-gateway:directory\" },\n }),\n };\n }\n\n // ─── /models/:canonical ───────────────────────────────────────────────────\n\n @List(\"/models/:canonical\")\n async listModel(ctx: RouteContext<{ canonical: string }>): Promise<{ data: AFSEntry[] }> {\n await this.ensureModelsLoaded();\n const m = this.findModel(ctx.params.canonical);\n const base = joinURL(\"/models\", m.model);\n return {\n data: [this.buildEntry(joinURL(base, \".meta\"), { meta: { kind: \"ai-gateway:model-meta\" } })],\n };\n }\n\n @Read(\"/models/:canonical\")\n async readModel(ctx: RouteContext<{ canonical: string }>): Promise<AFSEntry> {\n await this.ensureModelsLoaded();\n const m = this.findModel(ctx.params.canonical);\n return this.buildEntry(joinURL(\"/models\", m.model), {\n content: {\n model: m.model,\n nativeModelId: m.nativeModelId,\n vendor: m.vendor,\n type: m.type,\n aliases: m.aliases ?? [],\n },\n meta: {\n childrenCount: 1,\n kind: \"ai-gateway:model\",\n vendor: m.vendor,\n capacity: { type: m.type },\n },\n });\n }\n\n @Meta(\"/models/:canonical\")\n async metaModel(ctx: RouteContext<{ canonical: string }>): Promise<AFSEntry> {\n await this.ensureModelsLoaded();\n const m = this.findModel(ctx.params.canonical);\n return this.buildEntry(joinURL(\"/models\", m.model, \".meta\"), {\n content: {\n model: m.model,\n nativeModelId: m.nativeModelId,\n vendor: m.vendor,\n capacity: { type: m.type },\n aliases: m.aliases ?? [],\n available: m.available ?? true,\n },\n meta: { kind: \"ai-gateway:model-meta\" },\n });\n }\n\n @Stat(\"/models/:canonical\")\n async statModel(ctx: RouteContext<{ canonical: string }>): Promise<AFSStatResult> {\n await this.ensureModelsLoaded();\n const m = this.findModel(ctx.params.canonical);\n return {\n data: this.buildEntry(joinURL(\"/models\", m.model), {\n meta: {\n childrenCount: 1,\n kind: \"ai-gateway:model\",\n vendor: m.vendor,\n capacity: { type: m.type },\n },\n }),\n };\n }\n\n @Explain(\"/models/:canonical\")\n async explainModel(ctx: RouteContext<{ canonical: string }>): Promise<AFSExplainResult> {\n await this.ensureModelsLoaded();\n const m = this.findModel(ctx.params.canonical);\n const action = TYPE_ACTION[m.type];\n const lines = [\n `# ${m.model}`,\n \"\",\n `Vendor: **${m.vendor}** · Type: **${m.type}**`,\n \"\",\n `Native id: \\`${m.nativeModelId}\\``,\n \"\",\n \"## Invoke\",\n `\\`exec ${joinURL(\"/models\", m.model, \".actions\", action)} { … }\\``,\n ];\n return { format: \"markdown\", content: lines.join(\"\\n\") };\n }\n\n @Actions(\"/models/:canonical\")\n async listModelActions(ctx: RouteContext<{ canonical: string }>): Promise<{ data: AFSEntry[] }> {\n await this.ensureModelsLoaded();\n const m = this.findModel(ctx.params.canonical);\n const base = joinURL(\"/models\", m.model, \".actions\");\n const action = TYPE_ACTION[m.type];\n const schema =\n m.type === \"chat\" ? CHAT_SCHEMA : m.type === \"embed\" ? EMBED_SCHEMA : { type: \"object\" };\n return {\n data: [\n this.buildEntry(joinURL(base, action), {\n content: {\n description: `${m.type} inference on ${m.model}`,\n schema,\n },\n meta: { kind: \"afs:executable\" },\n }),\n ],\n };\n }\n\n // ─── Model execution ──────────────────────────────────────────────────────\n\n @Actions.Exec(\"/models/:canonical\", \"chat\", undefined, { effect: \"read\", billable: true })\n async execChat(\n ctx: RouteContext<{ canonical: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n await this.ensureModelsLoaded();\n const m = this.findModel(ctx.params.canonical);\n if (m.type !== \"chat\") {\n return {\n success: false,\n error: {\n code: \"INVALID_ACTION\",\n message: `Model '${m.model}' is type '${m.type}', not 'chat'.`,\n },\n };\n }\n try {\n const messages = this.buildMessages(args);\n if (messages.length === 0) {\n return {\n success: false,\n error: { code: \"MISSING_PARAM\", message: \"'prompt' or 'messages' is required\" },\n };\n }\n // For Anthropic models with prompt-cache markers, bypass OpenAIChatModel —\n // its contentsFromInputMessages strips cache_control during serialisation.\n // Raw HTTP preserves the field so it reaches the Anthropic API end-to-end.\n if (m.vendor === \"anthropic\" && messagesHaveCacheMarkers(messages)) {\n return await this.rawChatFetch(m, messages, args, ctx);\n }\n\n const client = this.getChatClient(m.nativeModelId);\n const input: Record<string, unknown> = { messages };\n const modelOptions: Record<string, unknown> = {};\n if (typeof args.temperature === \"number\") modelOptions.temperature = args.temperature;\n if (typeof args.topP === \"number\") modelOptions.topP = args.topP;\n if (Object.keys(modelOptions).length > 0) input.modelOptions = modelOptions;\n if (args.responseFormat) {\n input.responseFormat = normalizeResponseFormatForOpenAI(args.responseFormat);\n }\n // Forward tool definitions + tool_choice to the model. Without this,\n // agent-run's `tools` array is silently dropped at the gateway, the\n // model has no idea any tools are available, and Claude in particular\n // falls back to emitting `<function_calls>...</function_calls>` XML\n // it learned during training — even hallucinating fake tool results\n // mid-response. agent-run then sees toolsUsed=[] and treats the run\n // as a tool-less reply. Same root cause as the vertex-claude bug\n // fixed in be8bac517, but on the OpenAI-compatible path.\n if (args.tools !== undefined) input.tools = args.tools;\n if (args.toolChoice !== undefined) input.toolChoice = args.toolChoice;\n\n // Streaming pass-through (native-ai-device): when the AFS caller attaches\n // an `onChunk` handler (forwarded all the way from `/api/afs/rpc`'s\n // NDJSON stream through the AI Device router), invoke the model in\n // streaming mode and relay each text/thoughts delta. The SDK\n // (`OpenAIChatModel`, base `Model.invoke(streaming:true)`) returns a\n // `ReadableStream<ModelResponseChunk>`; we consume it with `getReader()`\n // (NOT `for await`) so it works on BOTH Node and the Cloudflare workerd\n // isolate. `mergeModelResponseChunk` reassembles the SAME complete\n // `ChatModelOutput` the buffered path would produce, so the final `data`\n // is identical — only the delivery (incremental vs buffered) differs.\n const onChunk = (ctx.options as AFSExecOptions | undefined)?.onChunk;\n if (onChunk) {\n const output = await this.streamChat(\n client,\n input as Parameters<typeof client.invoke>[0],\n onChunk,\n );\n return { success: true, data: this.buildChatData(m, output) };\n }\n\n const result = await client.invoke(input as Parameters<typeof client.invoke>[0]);\n return { success: true, data: this.buildChatData(m, result as Record<string, unknown>) };\n } catch (err) {\n return inferenceError(m.model, err);\n }\n }\n\n /**\n * Drive a streaming chat completion, relaying text/thoughts deltas to\n * `onChunk`, and return the fully-merged `ChatModelOutput` (identical to the\n * buffered `invoke()` result). Runtime-agnostic: uses `getReader()` so it\n * runs on the Cloudflare workerd isolate as well as Node.\n */\n private async streamChat(\n client: InstanceType<typeof OpenAIChatModel>,\n input: Parameters<InstanceType<typeof OpenAIChatModel>[\"invoke\"]>[0],\n onChunk: (chunk: AFSExecChunk) => void,\n ): Promise<Record<string, unknown>> {\n const stream = (await client.invoke(input, {\n streaming: true,\n })) as ModelResponseStream<ChatModelOutput>;\n const reader = stream.getReader();\n let merged = {} as ChatModelOutput;\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = value as ModelResponseChunk<ChatModelOutput>;\n merged = mergeModelResponseChunk(merged, chunk);\n const textDelta = (chunk as { delta?: { text?: { text?: string; thoughts?: string } } })\n .delta?.text;\n if (textDelta?.text) onChunk({ text: textDelta.text });\n if (textDelta?.thoughts) onChunk({ thoughts: textDelta.thoughts });\n }\n } finally {\n reader.releaseLock();\n }\n return merged as Record<string, unknown>;\n }\n\n /**\n * Raw HTTP fetch path for Anthropic models that carry prompt-cache markers.\n * Bypasses OpenAIChatModel.contentsFromInputMessages so cache_control is not\n * stripped before it reaches the gateway / Anthropic API. Handles both\n * buffered and SSE-streaming modes.\n */\n private async rawChatFetch(\n m: ModelEntry,\n messages: ChatModelInputMessage[],\n args: Record<string, unknown>,\n ctx: RouteContext,\n ): Promise<AFSExecResult> {\n const onChunk = (ctx.options as AFSExecOptions | undefined)?.onChunk;\n const body: Record<string, unknown> = {\n model: m.nativeModelId,\n messages: serializeMessagesForWire(messages),\n };\n if (typeof args.temperature === \"number\") body.temperature = args.temperature;\n if (typeof args.topP === \"number\") body.top_p = args.topP;\n if (args.tools !== undefined) body.tools = args.tools;\n if (args.toolChoice !== undefined) body.tool_choice = args.toolChoice;\n if (args.responseFormat) {\n body.response_format = toWireResponseFormat(\n normalizeResponseFormatForOpenAI(args.responseFormat),\n );\n }\n if (onChunk) body.stream = true;\n\n let resp: Response;\n try {\n resp = await fetch(`${this.baseURL}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n ...this.extraHeaders,\n },\n body: JSON.stringify(body),\n });\n } catch (err) {\n return inferenceError(m.model, err);\n }\n\n if (!resp.ok) {\n const errText = await resp.text().catch(() => resp.statusText);\n return inferenceError(m.model, new Error(`HTTP ${resp.status}: ${errText}`));\n }\n\n if (onChunk) {\n return this.streamRawChat(m, resp, onChunk);\n }\n\n try {\n const data = (await resp.json()) as Record<string, unknown>;\n return { success: true, data: this.buildChatData(m, openAiRespToOutput(data)) };\n } catch (err) {\n return inferenceError(m.model, err);\n }\n }\n\n /** Consume an OpenAI-compat SSE stream, forwarding text deltas via onChunk. */\n private async streamRawChat(\n m: ModelEntry,\n resp: Response,\n onChunk: (chunk: AFSExecChunk) => void,\n ): Promise<AFSExecResult> {\n const reader = resp.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let fullText = \"\";\n let usage: { inputTokens: number; outputTokens: number } | undefined;\n // OpenAI-compat tool_calls stream as per-index deltas — id/name arrive\n // once, `arguments` arrives as concatenated string fragments across many\n // chunks. Accumulate by index, parse the joined JSON once the stream ends.\n const toolCallsByIndex = new Map<\n number,\n { id?: string; type?: string; name?: string; arguments: string }\n >();\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n const raw = line.slice(6).trim();\n if (raw === \"[DONE]\") continue;\n try {\n const chunk = JSON.parse(raw) as Record<string, unknown>;\n const delta = (chunk.choices as Array<Record<string, unknown>> | undefined)?.[0]\n ?.delta as Record<string, unknown> | undefined;\n const text = delta?.content as string | undefined;\n if (text) {\n fullText += text;\n onChunk({ text });\n }\n const deltaToolCalls = delta?.tool_calls as Array<Record<string, unknown>> | undefined;\n if (Array.isArray(deltaToolCalls)) {\n for (const tc of deltaToolCalls) {\n const index = typeof tc.index === \"number\" ? tc.index : 0;\n const fn = tc.function as Record<string, unknown> | undefined;\n const existing = toolCallsByIndex.get(index) ?? { arguments: \"\" };\n if (typeof tc.id === \"string\") existing.id = tc.id;\n if (typeof tc.type === \"string\") existing.type = tc.type;\n if (typeof fn?.name === \"string\") existing.name = fn.name;\n if (typeof fn?.arguments === \"string\") existing.arguments += fn.arguments;\n toolCallsByIndex.set(index, existing);\n }\n }\n if (chunk.usage) {\n const u = chunk.usage as Record<string, unknown>;\n usage = {\n inputTokens: (u.prompt_tokens as number) ?? 0,\n outputTokens: (u.completion_tokens as number) ?? 0,\n };\n }\n } catch {\n // skip malformed SSE lines\n }\n }\n }\n } catch (err) {\n return inferenceError(m.model, err);\n } finally {\n reader.releaseLock();\n }\n\n // Re-assemble into wire shape (string `arguments`, one entry per index) and\n // hand off to the SAME final-shape parser the buffered path uses — argument\n // JSON-parsing and id/type/function mapping live in exactly one place.\n const wireToolCalls =\n toolCallsByIndex.size > 0\n ? [...toolCallsByIndex.entries()]\n .sort(([a], [b]) => a - b)\n .map(([, tc]) => ({\n id: tc.id,\n type: tc.type ?? \"function\",\n function: { name: tc.name, arguments: tc.arguments },\n }))\n : undefined;\n const toolCalls = parseWireToolCalls(wireToolCalls);\n\n return {\n success: true,\n data: this.buildChatData(m, {\n text: fullText,\n ...(toolCalls ? { toolCalls } : {}),\n ...(usage ? { usage } : {}),\n }),\n };\n }\n\n /**\n * Build the `/.actions/chat` result `data` from a `ChatModelOutput`. Shared\n * by the buffered and streaming paths so they can never drift. Forwards\n * structured-output JSON + reasoning trace + tool calls + usage (without\n * this, callers using `responseFormat: { type: \"json_schema\" }` lose the\n * parsed object — caused scan-spam to log `\"reason\": \"no result\"`).\n */\n private buildChatData(m: ModelEntry, output: Record<string, unknown>): Record<string, unknown> {\n const data: Record<string, unknown> = { model: m.model, text: output.text ?? null };\n if (output.json !== undefined) data.json = output.json;\n if (output.thoughts !== undefined) data.thoughts = output.thoughts;\n if (output.toolCalls) data.toolCalls = output.toolCalls;\n if (output.usage) data.usage = output.usage;\n return data;\n }\n\n @Actions.Exec(\"/models/:canonical\", \"embed\", undefined, { effect: \"read\", billable: true })\n async execEmbed(\n ctx: RouteContext<{ canonical: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n await this.ensureModelsLoaded();\n const m = this.findModel(ctx.params.canonical);\n if (m.type !== \"embed\") {\n return {\n success: false,\n error: {\n code: \"INVALID_ACTION\",\n message: `Model '${m.model}' is type '${m.type}', not 'embed'.`,\n },\n };\n }\n const input = args.input ?? args.text;\n if (input === undefined) {\n return {\n success: false,\n error: { code: \"MISSING_PARAM\", message: \"'input' (or 'text') is required\" },\n };\n }\n try {\n const client = this.getEmbedClient(m.nativeModelId);\n const result = await client.invoke({ input: input as string | string[] });\n const output = result as Record<string, unknown>;\n return {\n success: true,\n data: {\n model: m.model,\n embeddings: output.embeddings,\n ...(output.usage ? { usage: output.usage } : {}),\n },\n };\n } catch (err) {\n return inferenceError(m.model, err);\n }\n }\n\n @Actions.Exec(\"/models/:canonical\", \"generateImage\", undefined, {\n effect: \"read\",\n billable: true,\n })\n async execGenerateImage(ctx: RouteContext<{ canonical: string }>): Promise<AFSExecResult> {\n await this.ensureModelsLoaded();\n const m = this.findModel(ctx.params.canonical);\n return {\n success: false,\n error: {\n code: \"NOT_IMPLEMENTED\",\n message: `generateImage for ${m.model} not supported by this provider yet.`,\n },\n };\n }\n\n @Actions.Exec(\"/models/:canonical\", \"generateVideo\", undefined, {\n effect: \"read\",\n billable: true,\n })\n async execGenerateVideo(ctx: RouteContext<{ canonical: string }>): Promise<AFSExecResult> {\n await this.ensureModelsLoaded();\n const m = this.findModel(ctx.params.canonical);\n return {\n success: false,\n error: {\n code: \"NOT_IMPLEMENTED\",\n message: `generateVideo for ${m.model} not supported by this provider yet.`,\n },\n };\n }\n\n // ─── message construction ────────────────────────────────────────────────\n\n private buildMessages(args: Record<string, unknown>): ChatModelInputMessage[] {\n const raw = args.messages;\n if (Array.isArray(raw)) {\n return raw.map((m) => normalizeMessage(m as Record<string, unknown>));\n }\n if (typeof args.prompt === \"string\" && args.prompt.length > 0) {\n return [{ role: \"user\", content: args.prompt }];\n }\n return [];\n }\n}\n\nexport { toCanonicalModel };\n"],"mappings":"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"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const require_types = require('./types.cjs');
|
|
2
|
+
const require_models = require('./models2.cjs');
|
|
3
|
+
const require_normalize = require('./normalize.cjs');
|
|
4
|
+
const require_ai_gateway = require('./ai-gateway.cjs');
|
|
5
|
+
|
|
6
|
+
exports.AFSAIGateway = require_ai_gateway.AFSAIGateway;
|
|
7
|
+
exports.DEFAULT_MODELS = require_models.DEFAULT_MODELS;
|
|
8
|
+
exports.afsAIGatewayOptionsSchema = require_types.afsAIGatewayOptionsSchema;
|
|
9
|
+
exports.findModelEntry = require_normalize.findModelEntry;
|
|
10
|
+
exports.loadModels = require_models.loadModels;
|
|
11
|
+
exports.modelCatalogSchema = require_types.modelCatalogSchema;
|
|
12
|
+
exports.modelEntrySchema = require_types.modelEntrySchema;
|
|
13
|
+
exports.modelTypeSchema = require_types.modelTypeSchema;
|
|
14
|
+
exports.toCanonicalModel = require_normalize.toCanonicalModel;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AFSAIGatewayOptions, AFSAIGatewayOptionsInput, ListModelsEntry, ListModelsResponse, ModelCatalog, ModelEntry, ModelType, afsAIGatewayOptionsSchema, modelCatalogSchema, modelEntrySchema, modelTypeSchema } from "./types.cjs";
|
|
2
|
+
import { findModelEntry, toCanonicalModel } from "./normalize.cjs";
|
|
3
|
+
import { AFSAIGateway } from "./ai-gateway.cjs";
|
|
4
|
+
import { DEFAULT_MODELS, loadModels } from "./models.cjs";
|
|
5
|
+
export { AFSAIGateway, type AFSAIGatewayOptions, type AFSAIGatewayOptionsInput, DEFAULT_MODELS, type ListModelsEntry, type ListModelsResponse, type ModelCatalog, type ModelEntry, type ModelType, afsAIGatewayOptionsSchema, findModelEntry, loadModels, modelCatalogSchema, modelEntrySchema, modelTypeSchema, toCanonicalModel };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AFSAIGatewayOptions, AFSAIGatewayOptionsInput, ListModelsEntry, ListModelsResponse, ModelCatalog, ModelEntry, ModelType, afsAIGatewayOptionsSchema, modelCatalogSchema, modelEntrySchema, modelTypeSchema } from "./types.mjs";
|
|
2
|
+
import { findModelEntry, toCanonicalModel } from "./normalize.mjs";
|
|
3
|
+
import { AFSAIGateway } from "./ai-gateway.mjs";
|
|
4
|
+
import { DEFAULT_MODELS, loadModels } from "./models.mjs";
|
|
5
|
+
export { AFSAIGateway, type AFSAIGatewayOptions, type AFSAIGatewayOptionsInput, DEFAULT_MODELS, type ListModelsEntry, type ListModelsResponse, type ModelCatalog, type ModelEntry, type ModelType, afsAIGatewayOptionsSchema, findModelEntry, loadModels, modelCatalogSchema, modelEntrySchema, modelTypeSchema, toCanonicalModel };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { afsAIGatewayOptionsSchema, modelCatalogSchema, modelEntrySchema, modelTypeSchema } from "./types.mjs";
|
|
2
|
+
import { DEFAULT_MODELS, loadModels } from "./models2.mjs";
|
|
3
|
+
import { findModelEntry, toCanonicalModel } from "./normalize.mjs";
|
|
4
|
+
import { AFSAIGateway } from "./ai-gateway.mjs";
|
|
5
|
+
|
|
6
|
+
export { AFSAIGateway, DEFAULT_MODELS, afsAIGatewayOptionsSchema, findModelEntry, loadModels, modelCatalogSchema, modelEntrySchema, modelTypeSchema, toCanonicalModel };
|
package/dist/models.cjs
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
|
|
2
|
+
//#region models.json
|
|
3
|
+
var models_default = [
|
|
4
|
+
{
|
|
5
|
+
"model": "claude-opus-4-7",
|
|
6
|
+
"nativeModelId": "anthropic/claude-opus-4-7",
|
|
7
|
+
"vendor": "anthropic",
|
|
8
|
+
"type": "chat",
|
|
9
|
+
"aliases": ["claude-opus-4-7-20260120", "claude-opus-4.7"]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"model": "claude-sonnet-4-6",
|
|
13
|
+
"nativeModelId": "anthropic/claude-sonnet-4-6",
|
|
14
|
+
"vendor": "anthropic",
|
|
15
|
+
"type": "chat",
|
|
16
|
+
"aliases": ["claude-sonnet-4-6-20260115", "claude-sonnet-4.6"]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"model": "claude-sonnet-4-5",
|
|
20
|
+
"nativeModelId": "anthropic/claude-sonnet-4-5",
|
|
21
|
+
"vendor": "anthropic",
|
|
22
|
+
"type": "chat",
|
|
23
|
+
"aliases": ["claude-sonnet-4-5-20250929", "claude-sonnet-4.5"]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"model": "claude-haiku-4-5",
|
|
27
|
+
"nativeModelId": "anthropic/claude-haiku-4-5",
|
|
28
|
+
"vendor": "anthropic",
|
|
29
|
+
"type": "chat",
|
|
30
|
+
"aliases": ["claude-haiku-4-5-20251001", "claude-haiku-4.5"]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"model": "gpt-5.4",
|
|
34
|
+
"nativeModelId": "openai/gpt-5.4",
|
|
35
|
+
"vendor": "openai",
|
|
36
|
+
"type": "chat"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"model": "gpt-5.4-mini",
|
|
40
|
+
"nativeModelId": "openai/gpt-5.4-mini",
|
|
41
|
+
"vendor": "openai",
|
|
42
|
+
"type": "chat"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"model": "gpt-5.4-nano",
|
|
46
|
+
"nativeModelId": "openai/gpt-5.4-nano",
|
|
47
|
+
"vendor": "openai",
|
|
48
|
+
"type": "chat"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"model": "gpt-5.4-codex",
|
|
52
|
+
"nativeModelId": "openai/gpt-5.4-codex",
|
|
53
|
+
"vendor": "openai",
|
|
54
|
+
"type": "chat"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"model": "gpt-5.2",
|
|
58
|
+
"nativeModelId": "openai/gpt-5.2",
|
|
59
|
+
"vendor": "openai",
|
|
60
|
+
"type": "chat"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"model": "gpt-5",
|
|
64
|
+
"nativeModelId": "openai/gpt-5",
|
|
65
|
+
"vendor": "openai",
|
|
66
|
+
"type": "chat"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"model": "gpt-4.1-mini",
|
|
70
|
+
"nativeModelId": "openai/gpt-4.1-mini",
|
|
71
|
+
"vendor": "openai",
|
|
72
|
+
"type": "chat",
|
|
73
|
+
"aliases": ["gpt-4.1-mini-2025-04-14"]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"model": "o3",
|
|
77
|
+
"nativeModelId": "openai/o3",
|
|
78
|
+
"vendor": "openai",
|
|
79
|
+
"type": "chat"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"model": "o4-mini",
|
|
83
|
+
"nativeModelId": "openai/o4-mini",
|
|
84
|
+
"vendor": "openai",
|
|
85
|
+
"type": "chat"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"model": "gemini-3-1-pro",
|
|
89
|
+
"nativeModelId": "google-ai-studio/gemini-3.1-pro-preview",
|
|
90
|
+
"vendor": "google",
|
|
91
|
+
"type": "chat",
|
|
92
|
+
"aliases": ["gemini-3.1-pro", "gemini-3-1-pro-preview"]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"model": "gemini-3-flash",
|
|
96
|
+
"nativeModelId": "google-ai-studio/gemini-3-flash-preview",
|
|
97
|
+
"vendor": "google",
|
|
98
|
+
"type": "chat",
|
|
99
|
+
"aliases": ["gemini-3-flash-preview"]
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"model": "gemini-3-1-flash-lite",
|
|
103
|
+
"nativeModelId": "google-ai-studio/gemini-3.1-flash-lite-preview",
|
|
104
|
+
"vendor": "google",
|
|
105
|
+
"type": "chat",
|
|
106
|
+
"aliases": ["gemini-3.1-flash-lite", "gemini-3-1-flash-lite-preview"]
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"model": "gemini-2-5-pro",
|
|
110
|
+
"nativeModelId": "google-ai-studio/gemini-2.5-pro",
|
|
111
|
+
"vendor": "google",
|
|
112
|
+
"type": "chat",
|
|
113
|
+
"aliases": ["gemini-2.5-pro"]
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"model": "gemini-2-5-flash",
|
|
117
|
+
"nativeModelId": "google-ai-studio/gemini-2.5-flash",
|
|
118
|
+
"vendor": "google",
|
|
119
|
+
"type": "chat",
|
|
120
|
+
"aliases": ["gemini-2.5-flash"]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"model": "gemini-2-5-flash-lite",
|
|
124
|
+
"nativeModelId": "google-ai-studio/gemini-2.5-flash-lite",
|
|
125
|
+
"vendor": "google",
|
|
126
|
+
"type": "chat",
|
|
127
|
+
"aliases": ["gemini-2.5-flash-lite"]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"model": "gemini-embedding-001",
|
|
131
|
+
"nativeModelId": "google-ai-studio/gemini-embedding-001",
|
|
132
|
+
"vendor": "google",
|
|
133
|
+
"type": "embed"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"model": "text-embedding-3-large",
|
|
137
|
+
"nativeModelId": "openai/text-embedding-3-large",
|
|
138
|
+
"vendor": "openai",
|
|
139
|
+
"type": "embed"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"model": "text-embedding-3-small",
|
|
143
|
+
"nativeModelId": "openai/text-embedding-3-small",
|
|
144
|
+
"vendor": "openai",
|
|
145
|
+
"type": "embed"
|
|
146
|
+
}
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
//#endregion
|
|
150
|
+
Object.defineProperty(exports, 'default', {
|
|
151
|
+
enumerable: true,
|
|
152
|
+
get: function () {
|
|
153
|
+
return models_default;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ModelCatalog } from "./types.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/models.d.ts
|
|
4
|
+
declare function loadModels(source: unknown): ModelCatalog;
|
|
5
|
+
declare const DEFAULT_MODELS: ModelCatalog;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { DEFAULT_MODELS, loadModels };
|
|
8
|
+
//# sourceMappingURL=models.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.d.cts","names":[],"sources":["../src/models.ts"],"mappings":";;;iBAkBgB,UAAA,CAAW,MAAA,YAAkB,YAAA;AAAA,cAIhC,cAAA,EAAgB,YAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ModelCatalog } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/models.d.ts
|
|
4
|
+
declare function loadModels(source: unknown): ModelCatalog;
|
|
5
|
+
declare const DEFAULT_MODELS: ModelCatalog;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { DEFAULT_MODELS, loadModels };
|
|
8
|
+
//# sourceMappingURL=models.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.d.mts","names":[],"sources":["../src/models.ts"],"mappings":";;;iBAkBgB,UAAA,CAAW,MAAA,YAAkB,YAAA;AAAA,cAIhC,cAAA,EAAgB,YAAA"}
|
package/dist/models.mjs
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
//#region models.json
|
|
2
|
+
var models_default = [
|
|
3
|
+
{
|
|
4
|
+
"model": "claude-opus-4-7",
|
|
5
|
+
"nativeModelId": "anthropic/claude-opus-4-7",
|
|
6
|
+
"vendor": "anthropic",
|
|
7
|
+
"type": "chat",
|
|
8
|
+
"aliases": ["claude-opus-4-7-20260120", "claude-opus-4.7"]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"model": "claude-sonnet-4-6",
|
|
12
|
+
"nativeModelId": "anthropic/claude-sonnet-4-6",
|
|
13
|
+
"vendor": "anthropic",
|
|
14
|
+
"type": "chat",
|
|
15
|
+
"aliases": ["claude-sonnet-4-6-20260115", "claude-sonnet-4.6"]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"model": "claude-sonnet-4-5",
|
|
19
|
+
"nativeModelId": "anthropic/claude-sonnet-4-5",
|
|
20
|
+
"vendor": "anthropic",
|
|
21
|
+
"type": "chat",
|
|
22
|
+
"aliases": ["claude-sonnet-4-5-20250929", "claude-sonnet-4.5"]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"model": "claude-haiku-4-5",
|
|
26
|
+
"nativeModelId": "anthropic/claude-haiku-4-5",
|
|
27
|
+
"vendor": "anthropic",
|
|
28
|
+
"type": "chat",
|
|
29
|
+
"aliases": ["claude-haiku-4-5-20251001", "claude-haiku-4.5"]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"model": "gpt-5.4",
|
|
33
|
+
"nativeModelId": "openai/gpt-5.4",
|
|
34
|
+
"vendor": "openai",
|
|
35
|
+
"type": "chat"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"model": "gpt-5.4-mini",
|
|
39
|
+
"nativeModelId": "openai/gpt-5.4-mini",
|
|
40
|
+
"vendor": "openai",
|
|
41
|
+
"type": "chat"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"model": "gpt-5.4-nano",
|
|
45
|
+
"nativeModelId": "openai/gpt-5.4-nano",
|
|
46
|
+
"vendor": "openai",
|
|
47
|
+
"type": "chat"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"model": "gpt-5.4-codex",
|
|
51
|
+
"nativeModelId": "openai/gpt-5.4-codex",
|
|
52
|
+
"vendor": "openai",
|
|
53
|
+
"type": "chat"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"model": "gpt-5.2",
|
|
57
|
+
"nativeModelId": "openai/gpt-5.2",
|
|
58
|
+
"vendor": "openai",
|
|
59
|
+
"type": "chat"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"model": "gpt-5",
|
|
63
|
+
"nativeModelId": "openai/gpt-5",
|
|
64
|
+
"vendor": "openai",
|
|
65
|
+
"type": "chat"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"model": "gpt-4.1-mini",
|
|
69
|
+
"nativeModelId": "openai/gpt-4.1-mini",
|
|
70
|
+
"vendor": "openai",
|
|
71
|
+
"type": "chat",
|
|
72
|
+
"aliases": ["gpt-4.1-mini-2025-04-14"]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"model": "o3",
|
|
76
|
+
"nativeModelId": "openai/o3",
|
|
77
|
+
"vendor": "openai",
|
|
78
|
+
"type": "chat"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"model": "o4-mini",
|
|
82
|
+
"nativeModelId": "openai/o4-mini",
|
|
83
|
+
"vendor": "openai",
|
|
84
|
+
"type": "chat"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"model": "gemini-3-1-pro",
|
|
88
|
+
"nativeModelId": "google-ai-studio/gemini-3.1-pro-preview",
|
|
89
|
+
"vendor": "google",
|
|
90
|
+
"type": "chat",
|
|
91
|
+
"aliases": ["gemini-3.1-pro", "gemini-3-1-pro-preview"]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"model": "gemini-3-flash",
|
|
95
|
+
"nativeModelId": "google-ai-studio/gemini-3-flash-preview",
|
|
96
|
+
"vendor": "google",
|
|
97
|
+
"type": "chat",
|
|
98
|
+
"aliases": ["gemini-3-flash-preview"]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"model": "gemini-3-1-flash-lite",
|
|
102
|
+
"nativeModelId": "google-ai-studio/gemini-3.1-flash-lite-preview",
|
|
103
|
+
"vendor": "google",
|
|
104
|
+
"type": "chat",
|
|
105
|
+
"aliases": ["gemini-3.1-flash-lite", "gemini-3-1-flash-lite-preview"]
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"model": "gemini-2-5-pro",
|
|
109
|
+
"nativeModelId": "google-ai-studio/gemini-2.5-pro",
|
|
110
|
+
"vendor": "google",
|
|
111
|
+
"type": "chat",
|
|
112
|
+
"aliases": ["gemini-2.5-pro"]
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"model": "gemini-2-5-flash",
|
|
116
|
+
"nativeModelId": "google-ai-studio/gemini-2.5-flash",
|
|
117
|
+
"vendor": "google",
|
|
118
|
+
"type": "chat",
|
|
119
|
+
"aliases": ["gemini-2.5-flash"]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"model": "gemini-2-5-flash-lite",
|
|
123
|
+
"nativeModelId": "google-ai-studio/gemini-2.5-flash-lite",
|
|
124
|
+
"vendor": "google",
|
|
125
|
+
"type": "chat",
|
|
126
|
+
"aliases": ["gemini-2.5-flash-lite"]
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"model": "gemini-embedding-001",
|
|
130
|
+
"nativeModelId": "google-ai-studio/gemini-embedding-001",
|
|
131
|
+
"vendor": "google",
|
|
132
|
+
"type": "embed"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"model": "text-embedding-3-large",
|
|
136
|
+
"nativeModelId": "openai/text-embedding-3-large",
|
|
137
|
+
"vendor": "openai",
|
|
138
|
+
"type": "embed"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"model": "text-embedding-3-small",
|
|
142
|
+
"nativeModelId": "openai/text-embedding-3-small",
|
|
143
|
+
"vendor": "openai",
|
|
144
|
+
"type": "embed"
|
|
145
|
+
}
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
//#endregion
|
|
149
|
+
export { models_default as default };
|
|
150
|
+
//# sourceMappingURL=models.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.mjs","names":[],"sources":["../models.json"],"sourcesContent":[""],"mappings":""}
|
package/dist/models2.cjs
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const require_models = require('./models.cjs');
|
|
2
|
+
const require_types = require('./types.cjs');
|
|
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 require_types.modelCatalogSchema.parse(source);
|
|
21
|
+
}
|
|
22
|
+
const DEFAULT_MODELS = loadModels(require_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 require_types.modelCatalogSchema.parse(entries);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
//#endregion
|
|
95
|
+
exports.DEFAULT_MODELS = DEFAULT_MODELS;
|
|
96
|
+
exports.fetchModelsFromEndpoint = fetchModelsFromEndpoint;
|
|
97
|
+
exports.loadModels = loadModels;
|