@happyvertical/ai 0.96.0 → 0.96.1
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/README.md +6 -0
- package/dist/chunks/{bifrost-D1io0ttr.js → bifrost-DzT2J0Lq.js} +2 -2
- package/dist/chunks/{bifrost-D1io0ttr.js.map → bifrost-DzT2J0Lq.js.map} +1 -1
- package/dist/chunks/{litellm-xv_7hqm_.js → litellm-xCO8QlGI.js} +2 -2
- package/dist/chunks/{litellm-xv_7hqm_.js.map → litellm-xCO8QlGI.js.map} +1 -1
- package/dist/chunks/{src-DOm4LN_h.js → src-BUQUZK2M.js} +4 -4
- package/dist/chunks/{src-DOm4LN_h.js.map → src-BUQUZK2M.js.map} +1 -1
- package/dist/chunks/{typesafe-qpVPDkOR.js → typesafe-B0gPZQJg.js} +9 -3
- package/dist/chunks/typesafe-B0gPZQJg.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/node.js +2 -2
- package/dist/shared/providers/typesafe.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/chunks/typesafe-qpVPDkOR.js.map +0 -1
package/README.md
CHANGED
|
@@ -156,6 +156,12 @@ Probabilities are provider output and are not calibrated for comparison with
|
|
|
156
156
|
another provider. The optional capability and method preserve compatibility
|
|
157
157
|
with existing provider implementations.
|
|
158
158
|
|
|
159
|
+
TypeSafe documents normalized choice and score distributions. For measured
|
|
160
|
+
wire responses that are demonstrably rounded to hundredths, the adapter also
|
|
161
|
+
accepts a positive distribution within one percentage point of unit mass and
|
|
162
|
+
normalizes it by its actual sum. It continues to reject non-finite,
|
|
163
|
+
out-of-range, missing, extra, all-zero, and non-hundredth distributions.
|
|
164
|
+
|
|
159
165
|
## Video Generation
|
|
160
166
|
|
|
161
167
|
Video generation is asynchronous: `submitVideoGenerationJob` returns a JSON-serializable
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as OpenAIProvider } from "./src-
|
|
1
|
+
import { d as OpenAIProvider } from "./src-BUQUZK2M.js";
|
|
2
2
|
import { o as normalizeChatOptions, s as normalizeImageGenerationOptions } from "./safety-BKswBoqy.js";
|
|
3
3
|
import { i as resolveGatewayAdminBaseUrl, r as normalizeGatewayBaseUrl, t as BifrostAdmin } from "./gateway-admin-04mvbDHC.js";
|
|
4
4
|
import { ValidationError } from "@happyvertical/utils";
|
|
@@ -196,4 +196,4 @@ var BifrostProvider = class extends OpenAIProvider {
|
|
|
196
196
|
//#endregion
|
|
197
197
|
export { BifrostProvider };
|
|
198
198
|
|
|
199
|
-
//# sourceMappingURL=bifrost-
|
|
199
|
+
//# sourceMappingURL=bifrost-DzT2J0Lq.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bifrost-D1io0ttr.js","names":[],"sources":["../../src/shared/providers/bifrost.ts"],"sourcesContent":["import { ValidationError } from '@happyvertical/utils';\n\nimport {\n normalizeChatOptions,\n normalizeImageGenerationOptions,\n} from '../safety';\nimport type {\n AICapabilities,\n AIMessage,\n AIModel,\n AIResponse,\n BifrostOptions,\n ChatOptions,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n} from '../types';\nimport {\n BifrostAdmin,\n normalizeGatewayBaseUrl,\n resolveGatewayAdminBaseUrl,\n} from './gateway-admin';\nimport { type OpenAICompatibleProfile, OpenAIProvider } from './openai';\n\nconst BIFROST_CAPABILITIES: AICapabilities = {\n chat: true,\n completion: true,\n embeddings: true,\n streaming: true,\n functions: true,\n vision: true,\n fineTuning: false,\n imageEmbeddings: true,\n imageGeneration: true,\n videoGeneration: false,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 128000,\n supportedOperations: [\n 'chat',\n 'completion',\n 'embedding',\n 'streaming',\n 'functions',\n 'vision',\n 'image_embedding',\n 'image_generation',\n ],\n};\n\nfunction isEmbeddingModel(modelId: string): boolean {\n return /embed/i.test(modelId);\n}\n\nfunction isImageEmbeddingModel(modelId: string): boolean {\n return /titan-embed-image|multimodalembedding|image[-_]?embed|clip/i.test(\n modelId,\n );\n}\n\nfunction isImageGenerationModel(modelId: string): boolean {\n return /gpt-image|dall-e|imagen|stable[-_ ]diffusion|sdxl|flux|titan-image|image-generator/i.test(\n modelId,\n );\n}\n\nfunction isFilteredBifrostModel(modelId: string): boolean {\n return /moderation|transcrib|whisper|speech|tts|rerank/i.test(modelId);\n}\n\nfunction inferBifrostContextLength(modelId: string): number {\n if (isEmbeddingModel(modelId)) return 8192;\n if (/gemini-1\\.5|gemini-2\\.0|gemini-2\\.5|gemini-3/i.test(modelId)) {\n return 1000000;\n }\n if (/claude/i.test(modelId)) return 200000;\n if (/gpt-4o|gpt-4\\.1|o1|o3|o4|llama|mistral|qwen|deepseek/i.test(modelId)) {\n return 128000;\n }\n return 32768;\n}\n\nfunction inferBifrostFunctions(modelId: string): boolean {\n if (isEmbeddingModel(modelId)) return false;\n return /gpt|claude|gemini|command|llama|mistral|qwen|deepseek|o1|o3|o4/i.test(\n modelId,\n );\n}\n\nfunction inferBifrostVision(modelId: string): boolean {\n return /gpt-4o|gpt-4\\.1|vision|claude-3|gemini|pixtral|llava|qwen.*vl|vl-/i.test(\n modelId,\n );\n}\n\nfunction inferBifrostCapabilities(modelId: string): string[] {\n if (isImageGenerationModel(modelId)) {\n return ['image_generation'];\n }\n\n if (isImageEmbeddingModel(modelId)) {\n return ['embeddings', 'image_embedding'];\n }\n\n if (isEmbeddingModel(modelId)) {\n return ['embeddings'];\n }\n\n const capabilities = ['text', 'chat'];\n\n if (inferBifrostFunctions(modelId)) {\n capabilities.push('functions');\n }\n\n if (inferBifrostVision(modelId)) {\n capabilities.push('vision');\n }\n\n return capabilities;\n}\n\nfunction ensureBifrostOptions(options: BifrostOptions): BifrostOptions {\n if (!options.baseUrl?.trim()) {\n throw new ValidationError('Bifrost baseUrl is required', {\n provider: 'bifrost',\n hint: 'Pass baseUrl like http://localhost:8080, http://localhost:8080/openai, or http://localhost:8080/v1 and optionally adminBaseUrl for governance endpoints',\n });\n }\n\n const baseUrl = normalizeGatewayBaseUrl(options.baseUrl);\n const inferenceBaseUrl = /\\/(?:openai|v1|pydanticai\\/v1)$/.test(baseUrl)\n ? baseUrl\n : `${baseUrl}/openai`;\n const headers = options.apiKey\n ? {\n ...options.headers,\n 'x-bf-vk': options.apiKey,\n 'x-api-key': options.apiKey,\n }\n : options.headers;\n\n return {\n ...options,\n baseUrl: inferenceBaseUrl,\n headers,\n };\n}\n\nconst BIFROST_PROFILE: OpenAICompatibleProfile = {\n providerLabel: 'Bifrost',\n providerName: 'bifrost',\n defaultModel: 'openai/gpt-4o-mini',\n capabilities: BIFROST_CAPABILITIES,\n describeModel: (modelId) => `Bifrost model: ${modelId}`,\n getContextLength: inferBifrostContextLength,\n getModelCapabilities: inferBifrostCapabilities,\n shouldIncludeModel: (modelId) => !isFilteredBifrostModel(modelId),\n supportsFunctions: inferBifrostFunctions,\n supportsVision: inferBifrostVision,\n};\n\ntype BifrostResolvedCapability =\n | 'chat'\n | 'vision'\n | 'embeddings'\n | 'image_generation';\n\nfunction supportsCapability(\n model: AIModel,\n capability: BifrostResolvedCapability,\n): boolean {\n if (capability === 'vision') {\n return (\n model.capabilities.includes('vision') || model.supportsVision === true\n );\n }\n\n if (capability === 'embeddings') {\n return model.capabilities.includes('embeddings');\n }\n\n if (capability === 'image_generation') {\n return model.capabilities.includes('image_generation');\n }\n\n return model.capabilities.includes('chat');\n}\n\n/**\n * Bifrost provider implementation.\n *\n * Bifrost exposes OpenAI-compatible inference and governance admin APIs. This\n * provider reuses the OpenAI-compatible transport for inference and exposes\n * `admin` for tenant project and virtual-key provisioning.\n */\nexport class BifrostProvider extends OpenAIProvider {\n readonly admin: BifrostAdmin;\n private readonly configuredDefaultModel?: string;\n private readonly resolvedModelCache = new Map<\n BifrostResolvedCapability,\n Promise<string>\n >();\n\n constructor(options: BifrostOptions) {\n const normalized = ensureBifrostOptions(options);\n super(normalized, BIFROST_PROFILE);\n const adminKey = normalized.adminApiKey || normalized.apiKey;\n const adminUsername = normalized.adminUser || normalized.adminUsername;\n this.admin = new BifrostAdmin({\n provider: 'bifrost',\n baseUrl: resolveGatewayAdminBaseUrl(\n normalized.baseUrl,\n normalized.adminUrl || normalized.adminBaseUrl,\n 'bifrost',\n ),\n apiKey: adminKey,\n username: adminUsername,\n password: normalized.adminPassword,\n headers:\n adminKey && !(adminUsername && normalized.adminPassword)\n ? {\n ...normalized.adminHeaders,\n 'x-bf-vk': adminKey,\n 'x-api-key': adminKey,\n }\n : normalized.adminHeaders,\n timeout: normalized.timeout,\n });\n this.configuredDefaultModel = normalized.defaultModel;\n }\n\n private async resolveModel(\n capability: BifrostResolvedCapability,\n explicitModel?: string,\n ): Promise<string> {\n if (explicitModel) {\n return explicitModel;\n }\n\n if (\n this.configuredDefaultModel &&\n (capability === 'chat' || capability === 'vision')\n ) {\n return this.configuredDefaultModel;\n }\n\n const cached = this.resolvedModelCache.get(capability);\n if (cached) {\n return cached;\n }\n\n const pending = this.selectModel(capability).catch((error) => {\n this.resolvedModelCache.delete(capability);\n throw error;\n });\n this.resolvedModelCache.set(capability, pending);\n return pending;\n }\n\n private async selectModel(\n capability: BifrostResolvedCapability,\n ): Promise<string> {\n const models = await super.getModels();\n const model = models.find((candidate) =>\n supportsCapability(candidate, capability),\n );\n\n if (!model) {\n throw new ValidationError(\n `No ${capability} model is available from the Bifrost gateway`,\n {\n provider: 'bifrost',\n capability,\n hint: 'Pass defaultModel explicitly or ensure the gateway returns a compatible model for this key',\n },\n );\n }\n\n return model.id;\n }\n\n async chat(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): Promise<AIResponse> {\n const safe = normalizeChatOptions(\n this.options,\n options,\n 'bifrost',\n options.model || this.options.defaultModel,\n );\n return super.chat(messages, {\n ...safe,\n model: await this.resolveModel('chat', safe.model),\n });\n }\n\n async *stream(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): AsyncIterable<string> {\n const safe = normalizeChatOptions(\n this.options,\n options,\n 'bifrost',\n options.model || this.options.defaultModel,\n );\n yield* super.stream(messages, {\n ...safe,\n model: await this.resolveModel('chat', safe.model),\n });\n }\n\n async describeImage(\n image: string | Buffer,\n prompt?: string,\n options: ImageDescriptionOptions = {},\n ): Promise<string> {\n const safe = normalizeChatOptions(\n this.options,\n options,\n 'bifrost',\n options.model || this.options.defaultModel,\n );\n return super.describeImage(image, prompt, {\n ...safe,\n model: await this.resolveModel('vision', safe.model),\n });\n }\n\n async embed(\n text: string | string[],\n options: EmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n return super.embed(text, {\n ...options,\n model: await this.resolveModel('embeddings', options.model),\n });\n }\n\n async embedImage(\n image: string | Buffer,\n options: ImageEmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n return super.embedImage(image, {\n ...options,\n model: await this.resolveModel('embeddings', options.model),\n });\n }\n\n async generateImage(\n prompt: string,\n options: ImageGenerationOptions = {},\n ): Promise<ImageGenerationResponse> {\n const safe = normalizeImageGenerationOptions(\n this.options,\n options,\n 'bifrost',\n options.model,\n );\n return super.generateImage(prompt, {\n ...safe,\n model: await this.resolveModel('image_generation', safe.model),\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bifrost-DzT2J0Lq.js","names":[],"sources":["../../src/shared/providers/bifrost.ts"],"sourcesContent":["import { ValidationError } from '@happyvertical/utils';\n\nimport {\n normalizeChatOptions,\n normalizeImageGenerationOptions,\n} from '../safety';\nimport type {\n AICapabilities,\n AIMessage,\n AIModel,\n AIResponse,\n BifrostOptions,\n ChatOptions,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n} from '../types';\nimport {\n BifrostAdmin,\n normalizeGatewayBaseUrl,\n resolveGatewayAdminBaseUrl,\n} from './gateway-admin';\nimport { type OpenAICompatibleProfile, OpenAIProvider } from './openai';\n\nconst BIFROST_CAPABILITIES: AICapabilities = {\n chat: true,\n completion: true,\n embeddings: true,\n streaming: true,\n functions: true,\n vision: true,\n fineTuning: false,\n imageEmbeddings: true,\n imageGeneration: true,\n videoGeneration: false,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 128000,\n supportedOperations: [\n 'chat',\n 'completion',\n 'embedding',\n 'streaming',\n 'functions',\n 'vision',\n 'image_embedding',\n 'image_generation',\n ],\n};\n\nfunction isEmbeddingModel(modelId: string): boolean {\n return /embed/i.test(modelId);\n}\n\nfunction isImageEmbeddingModel(modelId: string): boolean {\n return /titan-embed-image|multimodalembedding|image[-_]?embed|clip/i.test(\n modelId,\n );\n}\n\nfunction isImageGenerationModel(modelId: string): boolean {\n return /gpt-image|dall-e|imagen|stable[-_ ]diffusion|sdxl|flux|titan-image|image-generator/i.test(\n modelId,\n );\n}\n\nfunction isFilteredBifrostModel(modelId: string): boolean {\n return /moderation|transcrib|whisper|speech|tts|rerank/i.test(modelId);\n}\n\nfunction inferBifrostContextLength(modelId: string): number {\n if (isEmbeddingModel(modelId)) return 8192;\n if (/gemini-1\\.5|gemini-2\\.0|gemini-2\\.5|gemini-3/i.test(modelId)) {\n return 1000000;\n }\n if (/claude/i.test(modelId)) return 200000;\n if (/gpt-4o|gpt-4\\.1|o1|o3|o4|llama|mistral|qwen|deepseek/i.test(modelId)) {\n return 128000;\n }\n return 32768;\n}\n\nfunction inferBifrostFunctions(modelId: string): boolean {\n if (isEmbeddingModel(modelId)) return false;\n return /gpt|claude|gemini|command|llama|mistral|qwen|deepseek|o1|o3|o4/i.test(\n modelId,\n );\n}\n\nfunction inferBifrostVision(modelId: string): boolean {\n return /gpt-4o|gpt-4\\.1|vision|claude-3|gemini|pixtral|llava|qwen.*vl|vl-/i.test(\n modelId,\n );\n}\n\nfunction inferBifrostCapabilities(modelId: string): string[] {\n if (isImageGenerationModel(modelId)) {\n return ['image_generation'];\n }\n\n if (isImageEmbeddingModel(modelId)) {\n return ['embeddings', 'image_embedding'];\n }\n\n if (isEmbeddingModel(modelId)) {\n return ['embeddings'];\n }\n\n const capabilities = ['text', 'chat'];\n\n if (inferBifrostFunctions(modelId)) {\n capabilities.push('functions');\n }\n\n if (inferBifrostVision(modelId)) {\n capabilities.push('vision');\n }\n\n return capabilities;\n}\n\nfunction ensureBifrostOptions(options: BifrostOptions): BifrostOptions {\n if (!options.baseUrl?.trim()) {\n throw new ValidationError('Bifrost baseUrl is required', {\n provider: 'bifrost',\n hint: 'Pass baseUrl like http://localhost:8080, http://localhost:8080/openai, or http://localhost:8080/v1 and optionally adminBaseUrl for governance endpoints',\n });\n }\n\n const baseUrl = normalizeGatewayBaseUrl(options.baseUrl);\n const inferenceBaseUrl = /\\/(?:openai|v1|pydanticai\\/v1)$/.test(baseUrl)\n ? baseUrl\n : `${baseUrl}/openai`;\n const headers = options.apiKey\n ? {\n ...options.headers,\n 'x-bf-vk': options.apiKey,\n 'x-api-key': options.apiKey,\n }\n : options.headers;\n\n return {\n ...options,\n baseUrl: inferenceBaseUrl,\n headers,\n };\n}\n\nconst BIFROST_PROFILE: OpenAICompatibleProfile = {\n providerLabel: 'Bifrost',\n providerName: 'bifrost',\n defaultModel: 'openai/gpt-4o-mini',\n capabilities: BIFROST_CAPABILITIES,\n describeModel: (modelId) => `Bifrost model: ${modelId}`,\n getContextLength: inferBifrostContextLength,\n getModelCapabilities: inferBifrostCapabilities,\n shouldIncludeModel: (modelId) => !isFilteredBifrostModel(modelId),\n supportsFunctions: inferBifrostFunctions,\n supportsVision: inferBifrostVision,\n};\n\ntype BifrostResolvedCapability =\n | 'chat'\n | 'vision'\n | 'embeddings'\n | 'image_generation';\n\nfunction supportsCapability(\n model: AIModel,\n capability: BifrostResolvedCapability,\n): boolean {\n if (capability === 'vision') {\n return (\n model.capabilities.includes('vision') || model.supportsVision === true\n );\n }\n\n if (capability === 'embeddings') {\n return model.capabilities.includes('embeddings');\n }\n\n if (capability === 'image_generation') {\n return model.capabilities.includes('image_generation');\n }\n\n return model.capabilities.includes('chat');\n}\n\n/**\n * Bifrost provider implementation.\n *\n * Bifrost exposes OpenAI-compatible inference and governance admin APIs. This\n * provider reuses the OpenAI-compatible transport for inference and exposes\n * `admin` for tenant project and virtual-key provisioning.\n */\nexport class BifrostProvider extends OpenAIProvider {\n readonly admin: BifrostAdmin;\n private readonly configuredDefaultModel?: string;\n private readonly resolvedModelCache = new Map<\n BifrostResolvedCapability,\n Promise<string>\n >();\n\n constructor(options: BifrostOptions) {\n const normalized = ensureBifrostOptions(options);\n super(normalized, BIFROST_PROFILE);\n const adminKey = normalized.adminApiKey || normalized.apiKey;\n const adminUsername = normalized.adminUser || normalized.adminUsername;\n this.admin = new BifrostAdmin({\n provider: 'bifrost',\n baseUrl: resolveGatewayAdminBaseUrl(\n normalized.baseUrl,\n normalized.adminUrl || normalized.adminBaseUrl,\n 'bifrost',\n ),\n apiKey: adminKey,\n username: adminUsername,\n password: normalized.adminPassword,\n headers:\n adminKey && !(adminUsername && normalized.adminPassword)\n ? {\n ...normalized.adminHeaders,\n 'x-bf-vk': adminKey,\n 'x-api-key': adminKey,\n }\n : normalized.adminHeaders,\n timeout: normalized.timeout,\n });\n this.configuredDefaultModel = normalized.defaultModel;\n }\n\n private async resolveModel(\n capability: BifrostResolvedCapability,\n explicitModel?: string,\n ): Promise<string> {\n if (explicitModel) {\n return explicitModel;\n }\n\n if (\n this.configuredDefaultModel &&\n (capability === 'chat' || capability === 'vision')\n ) {\n return this.configuredDefaultModel;\n }\n\n const cached = this.resolvedModelCache.get(capability);\n if (cached) {\n return cached;\n }\n\n const pending = this.selectModel(capability).catch((error) => {\n this.resolvedModelCache.delete(capability);\n throw error;\n });\n this.resolvedModelCache.set(capability, pending);\n return pending;\n }\n\n private async selectModel(\n capability: BifrostResolvedCapability,\n ): Promise<string> {\n const models = await super.getModels();\n const model = models.find((candidate) =>\n supportsCapability(candidate, capability),\n );\n\n if (!model) {\n throw new ValidationError(\n `No ${capability} model is available from the Bifrost gateway`,\n {\n provider: 'bifrost',\n capability,\n hint: 'Pass defaultModel explicitly or ensure the gateway returns a compatible model for this key',\n },\n );\n }\n\n return model.id;\n }\n\n async chat(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): Promise<AIResponse> {\n const safe = normalizeChatOptions(\n this.options,\n options,\n 'bifrost',\n options.model || this.options.defaultModel,\n );\n return super.chat(messages, {\n ...safe,\n model: await this.resolveModel('chat', safe.model),\n });\n }\n\n async *stream(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): AsyncIterable<string> {\n const safe = normalizeChatOptions(\n this.options,\n options,\n 'bifrost',\n options.model || this.options.defaultModel,\n );\n yield* super.stream(messages, {\n ...safe,\n model: await this.resolveModel('chat', safe.model),\n });\n }\n\n async describeImage(\n image: string | Buffer,\n prompt?: string,\n options: ImageDescriptionOptions = {},\n ): Promise<string> {\n const safe = normalizeChatOptions(\n this.options,\n options,\n 'bifrost',\n options.model || this.options.defaultModel,\n );\n return super.describeImage(image, prompt, {\n ...safe,\n model: await this.resolveModel('vision', safe.model),\n });\n }\n\n async embed(\n text: string | string[],\n options: EmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n return super.embed(text, {\n ...options,\n model: await this.resolveModel('embeddings', options.model),\n });\n }\n\n async embedImage(\n image: string | Buffer,\n options: ImageEmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n return super.embedImage(image, {\n ...options,\n model: await this.resolveModel('embeddings', options.model),\n });\n }\n\n async generateImage(\n prompt: string,\n options: ImageGenerationOptions = {},\n ): Promise<ImageGenerationResponse> {\n const safe = normalizeImageGenerationOptions(\n this.options,\n options,\n 'bifrost',\n options.model,\n );\n return super.generateImage(prompt, {\n ...safe,\n model: await this.resolveModel('image_generation', safe.model),\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as OpenAIProvider } from "./src-
|
|
1
|
+
import { d as OpenAIProvider } from "./src-BUQUZK2M.js";
|
|
2
2
|
import { o as normalizeChatOptions, s as normalizeImageGenerationOptions } from "./safety-BKswBoqy.js";
|
|
3
3
|
import { i as resolveGatewayAdminBaseUrl, n as LiteLLMAdmin } from "./gateway-admin-04mvbDHC.js";
|
|
4
4
|
import { ValidationError } from "@happyvertical/utils";
|
|
@@ -183,4 +183,4 @@ var LiteLLMProvider = class extends OpenAIProvider {
|
|
|
183
183
|
//#endregion
|
|
184
184
|
export { LiteLLMProvider };
|
|
185
185
|
|
|
186
|
-
//# sourceMappingURL=litellm-
|
|
186
|
+
//# sourceMappingURL=litellm-xCO8QlGI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"litellm-xv_7hqm_.js","names":[],"sources":["../../src/shared/providers/litellm.ts"],"sourcesContent":["import { ValidationError } from '@happyvertical/utils';\n\nimport {\n normalizeChatOptions,\n normalizeImageGenerationOptions,\n} from '../safety';\nimport type {\n AICapabilities,\n AIMessage,\n AIModel,\n AIResponse,\n ChatOptions,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n LiteLLMOptions,\n} from '../types';\nimport { LiteLLMAdmin, resolveGatewayAdminBaseUrl } from './gateway-admin';\nimport { type OpenAICompatibleProfile, OpenAIProvider } from './openai';\n\nconst LITELLM_CAPABILITIES: AICapabilities = {\n chat: true,\n completion: true,\n embeddings: true,\n streaming: true,\n functions: true,\n vision: true,\n fineTuning: false,\n imageEmbeddings: true,\n imageGeneration: true,\n videoGeneration: false,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 128000,\n supportedOperations: [\n 'chat',\n 'completion',\n 'embedding',\n 'streaming',\n 'functions',\n 'vision',\n 'image_embedding',\n 'image_generation',\n ],\n};\n\nfunction isEmbeddingModel(modelId: string): boolean {\n return /embed/i.test(modelId);\n}\n\nfunction isImageEmbeddingModel(modelId: string): boolean {\n return /titan-embed-image|multimodalembedding|image[-_]?embed|clip/i.test(\n modelId,\n );\n}\n\nfunction isImageGenerationModel(modelId: string): boolean {\n return /gpt-image|dall-e|imagen|stable[-_ ]diffusion|sdxl|flux|titan-image|image-generator/i.test(\n modelId,\n );\n}\n\nfunction isFilteredLiteLLMModel(modelId: string): boolean {\n return /moderation|transcrib|whisper|speech|tts|rerank/i.test(modelId);\n}\n\nfunction inferLiteLLMContextLength(modelId: string): number {\n if (isEmbeddingModel(modelId)) return 8192;\n if (/gemini-1\\.5|gemini-2\\.0|gemini-2\\.5|gemini-3/i.test(modelId)) {\n return 1000000;\n }\n if (/claude/i.test(modelId)) return 200000;\n if (/gpt-4o|gpt-4\\.1|o1|o3|o4|llama|mistral|qwen|deepseek/i.test(modelId)) {\n return 128000;\n }\n return 32768;\n}\n\nfunction inferLiteLLMFunctions(modelId: string): boolean {\n if (isEmbeddingModel(modelId)) return false;\n return /gpt|claude|gemini|command|llama|mistral|qwen|deepseek|o1|o3|o4/i.test(\n modelId,\n );\n}\n\nfunction inferLiteLLMVision(modelId: string): boolean {\n return /gpt-4o|gpt-4\\.1|vision|claude-3|gemini|pixtral|llava|qwen.*vl|vl-/i.test(\n modelId,\n );\n}\n\nfunction inferLiteLLMCapabilities(modelId: string): string[] {\n if (isImageGenerationModel(modelId)) {\n return ['image_generation'];\n }\n\n if (isImageEmbeddingModel(modelId)) {\n return ['embeddings', 'image_embedding'];\n }\n\n if (isEmbeddingModel(modelId)) {\n return ['embeddings'];\n }\n\n const capabilities = ['text', 'chat'];\n\n if (inferLiteLLMFunctions(modelId)) {\n capabilities.push('functions');\n }\n\n if (inferLiteLLMVision(modelId)) {\n capabilities.push('vision');\n }\n\n return capabilities;\n}\n\nfunction normalizeBaseUrl(baseUrl: string): string {\n return baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n}\n\nfunction ensureLiteLLMOptions(options: LiteLLMOptions): LiteLLMOptions {\n if (!options.baseUrl?.trim()) {\n throw new ValidationError('LiteLLM baseUrl is required', {\n provider: 'litellm',\n hint: 'Pass baseUrl like https://llm.happyvertical.com/v1 or set HAVE_AI_BASE_URL / LITELLM_BASE_URL',\n });\n }\n\n return {\n ...options,\n baseUrl: normalizeBaseUrl(options.baseUrl.trim()),\n };\n}\n\nconst LITELLM_PROFILE: OpenAICompatibleProfile = {\n providerLabel: 'LiteLLM',\n providerName: 'litellm',\n defaultModel: 'gpt-4',\n capabilities: LITELLM_CAPABILITIES,\n describeModel: (modelId) => `LiteLLM model: ${modelId}`,\n getContextLength: inferLiteLLMContextLength,\n getModelCapabilities: inferLiteLLMCapabilities,\n shouldIncludeModel: (modelId) => !isFilteredLiteLLMModel(modelId),\n supportsFunctions: inferLiteLLMFunctions,\n supportsVision: inferLiteLLMVision,\n};\n\ntype LiteLLMResolvedCapability =\n | 'chat'\n | 'vision'\n | 'embeddings'\n | 'image_generation';\n\nfunction supportsCapability(\n model: AIModel,\n capability: LiteLLMResolvedCapability,\n): boolean {\n if (capability === 'vision') {\n return (\n model.capabilities.includes('vision') || model.supportsVision === true\n );\n }\n\n if (capability === 'embeddings') {\n return model.capabilities.includes('embeddings');\n }\n\n if (capability === 'image_generation') {\n return model.capabilities.includes('image_generation');\n }\n\n return model.capabilities.includes('chat');\n}\n\n/**\n * LiteLLM provider implementation.\n *\n * LiteLLM exposes an OpenAI-compatible API surface, so this provider reuses the\n * OpenAI transport while customizing provider identity, model discovery, and\n * capability heuristics for gateway-backed deployments.\n */\nexport class LiteLLMProvider extends OpenAIProvider {\n readonly admin: LiteLLMAdmin;\n private readonly configuredDefaultModel?: string;\n private readonly resolvedModelCache = new Map<\n LiteLLMResolvedCapability,\n Promise<string>\n >();\n\n constructor(options: LiteLLMOptions) {\n const normalized = ensureLiteLLMOptions(options);\n super(normalized, LITELLM_PROFILE);\n this.admin = new LiteLLMAdmin({\n provider: 'litellm',\n baseUrl: resolveGatewayAdminBaseUrl(\n normalized.baseUrl,\n normalized.adminUrl || normalized.adminBaseUrl,\n 'litellm',\n ),\n apiKey: normalized.adminApiKey || normalized.apiKey,\n headers: normalized.adminHeaders,\n timeout: normalized.timeout,\n });\n this.configuredDefaultModel = normalized.defaultModel;\n }\n\n private async resolveModel(\n capability: LiteLLMResolvedCapability,\n explicitModel?: string,\n ): Promise<string> {\n if (explicitModel) {\n return explicitModel;\n }\n\n if (\n this.configuredDefaultModel &&\n (capability === 'chat' || capability === 'vision')\n ) {\n return this.configuredDefaultModel;\n }\n\n const cached = this.resolvedModelCache.get(capability);\n if (cached) {\n return cached;\n }\n\n const pending = this.selectModel(capability).catch((error) => {\n this.resolvedModelCache.delete(capability);\n throw error;\n });\n this.resolvedModelCache.set(capability, pending);\n return pending;\n }\n\n private async selectModel(\n capability: LiteLLMResolvedCapability,\n ): Promise<string> {\n const models = await super.getModels();\n const model = models.find((candidate) =>\n supportsCapability(candidate, capability),\n );\n\n if (!model) {\n throw new ValidationError(\n `No ${capability} model is available from the LiteLLM gateway`,\n {\n provider: 'litellm',\n capability,\n hint: 'Pass defaultModel explicitly or ensure /models returns a compatible model for this key',\n },\n );\n }\n\n return model.id;\n }\n\n async chat(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): Promise<AIResponse> {\n const safe = normalizeChatOptions(\n this.options,\n options,\n 'litellm',\n options.model || this.options.defaultModel,\n );\n return super.chat(messages, {\n ...safe,\n model: await this.resolveModel('chat', safe.model),\n });\n }\n\n async *stream(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): AsyncIterable<string> {\n const safe = normalizeChatOptions(\n this.options,\n options,\n 'litellm',\n options.model || this.options.defaultModel,\n );\n yield* super.stream(messages, {\n ...safe,\n model: await this.resolveModel('chat', safe.model),\n });\n }\n\n async describeImage(\n image: string | Buffer,\n prompt?: string,\n options: ImageDescriptionOptions = {},\n ): Promise<string> {\n const safe = normalizeChatOptions(\n this.options,\n options,\n 'litellm',\n options.model || this.options.defaultModel,\n );\n return super.describeImage(image, prompt, {\n ...safe,\n model: await this.resolveModel('vision', safe.model),\n });\n }\n\n async embed(\n text: string | string[],\n options: EmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n return super.embed(text, {\n ...options,\n model: await this.resolveModel('embeddings', options.model),\n });\n }\n\n async embedImage(\n image: string | Buffer,\n options: ImageEmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n return super.embedImage(image, {\n ...options,\n model: await this.resolveModel('embeddings', options.model),\n });\n }\n\n async generateImage(\n prompt: string,\n options: ImageGenerationOptions = {},\n ): Promise<ImageGenerationResponse> {\n const safe = normalizeImageGenerationOptions(\n this.options,\n options,\n 'litellm',\n options.model,\n );\n return super.generateImage(prompt, {\n ...safe,\n model: await this.resolveModel('image_generation', safe.model),\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"litellm-xCO8QlGI.js","names":[],"sources":["../../src/shared/providers/litellm.ts"],"sourcesContent":["import { ValidationError } from '@happyvertical/utils';\n\nimport {\n normalizeChatOptions,\n normalizeImageGenerationOptions,\n} from '../safety';\nimport type {\n AICapabilities,\n AIMessage,\n AIModel,\n AIResponse,\n ChatOptions,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n LiteLLMOptions,\n} from '../types';\nimport { LiteLLMAdmin, resolveGatewayAdminBaseUrl } from './gateway-admin';\nimport { type OpenAICompatibleProfile, OpenAIProvider } from './openai';\n\nconst LITELLM_CAPABILITIES: AICapabilities = {\n chat: true,\n completion: true,\n embeddings: true,\n streaming: true,\n functions: true,\n vision: true,\n fineTuning: false,\n imageEmbeddings: true,\n imageGeneration: true,\n videoGeneration: false,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 128000,\n supportedOperations: [\n 'chat',\n 'completion',\n 'embedding',\n 'streaming',\n 'functions',\n 'vision',\n 'image_embedding',\n 'image_generation',\n ],\n};\n\nfunction isEmbeddingModel(modelId: string): boolean {\n return /embed/i.test(modelId);\n}\n\nfunction isImageEmbeddingModel(modelId: string): boolean {\n return /titan-embed-image|multimodalembedding|image[-_]?embed|clip/i.test(\n modelId,\n );\n}\n\nfunction isImageGenerationModel(modelId: string): boolean {\n return /gpt-image|dall-e|imagen|stable[-_ ]diffusion|sdxl|flux|titan-image|image-generator/i.test(\n modelId,\n );\n}\n\nfunction isFilteredLiteLLMModel(modelId: string): boolean {\n return /moderation|transcrib|whisper|speech|tts|rerank/i.test(modelId);\n}\n\nfunction inferLiteLLMContextLength(modelId: string): number {\n if (isEmbeddingModel(modelId)) return 8192;\n if (/gemini-1\\.5|gemini-2\\.0|gemini-2\\.5|gemini-3/i.test(modelId)) {\n return 1000000;\n }\n if (/claude/i.test(modelId)) return 200000;\n if (/gpt-4o|gpt-4\\.1|o1|o3|o4|llama|mistral|qwen|deepseek/i.test(modelId)) {\n return 128000;\n }\n return 32768;\n}\n\nfunction inferLiteLLMFunctions(modelId: string): boolean {\n if (isEmbeddingModel(modelId)) return false;\n return /gpt|claude|gemini|command|llama|mistral|qwen|deepseek|o1|o3|o4/i.test(\n modelId,\n );\n}\n\nfunction inferLiteLLMVision(modelId: string): boolean {\n return /gpt-4o|gpt-4\\.1|vision|claude-3|gemini|pixtral|llava|qwen.*vl|vl-/i.test(\n modelId,\n );\n}\n\nfunction inferLiteLLMCapabilities(modelId: string): string[] {\n if (isImageGenerationModel(modelId)) {\n return ['image_generation'];\n }\n\n if (isImageEmbeddingModel(modelId)) {\n return ['embeddings', 'image_embedding'];\n }\n\n if (isEmbeddingModel(modelId)) {\n return ['embeddings'];\n }\n\n const capabilities = ['text', 'chat'];\n\n if (inferLiteLLMFunctions(modelId)) {\n capabilities.push('functions');\n }\n\n if (inferLiteLLMVision(modelId)) {\n capabilities.push('vision');\n }\n\n return capabilities;\n}\n\nfunction normalizeBaseUrl(baseUrl: string): string {\n return baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n}\n\nfunction ensureLiteLLMOptions(options: LiteLLMOptions): LiteLLMOptions {\n if (!options.baseUrl?.trim()) {\n throw new ValidationError('LiteLLM baseUrl is required', {\n provider: 'litellm',\n hint: 'Pass baseUrl like https://llm.happyvertical.com/v1 or set HAVE_AI_BASE_URL / LITELLM_BASE_URL',\n });\n }\n\n return {\n ...options,\n baseUrl: normalizeBaseUrl(options.baseUrl.trim()),\n };\n}\n\nconst LITELLM_PROFILE: OpenAICompatibleProfile = {\n providerLabel: 'LiteLLM',\n providerName: 'litellm',\n defaultModel: 'gpt-4',\n capabilities: LITELLM_CAPABILITIES,\n describeModel: (modelId) => `LiteLLM model: ${modelId}`,\n getContextLength: inferLiteLLMContextLength,\n getModelCapabilities: inferLiteLLMCapabilities,\n shouldIncludeModel: (modelId) => !isFilteredLiteLLMModel(modelId),\n supportsFunctions: inferLiteLLMFunctions,\n supportsVision: inferLiteLLMVision,\n};\n\ntype LiteLLMResolvedCapability =\n | 'chat'\n | 'vision'\n | 'embeddings'\n | 'image_generation';\n\nfunction supportsCapability(\n model: AIModel,\n capability: LiteLLMResolvedCapability,\n): boolean {\n if (capability === 'vision') {\n return (\n model.capabilities.includes('vision') || model.supportsVision === true\n );\n }\n\n if (capability === 'embeddings') {\n return model.capabilities.includes('embeddings');\n }\n\n if (capability === 'image_generation') {\n return model.capabilities.includes('image_generation');\n }\n\n return model.capabilities.includes('chat');\n}\n\n/**\n * LiteLLM provider implementation.\n *\n * LiteLLM exposes an OpenAI-compatible API surface, so this provider reuses the\n * OpenAI transport while customizing provider identity, model discovery, and\n * capability heuristics for gateway-backed deployments.\n */\nexport class LiteLLMProvider extends OpenAIProvider {\n readonly admin: LiteLLMAdmin;\n private readonly configuredDefaultModel?: string;\n private readonly resolvedModelCache = new Map<\n LiteLLMResolvedCapability,\n Promise<string>\n >();\n\n constructor(options: LiteLLMOptions) {\n const normalized = ensureLiteLLMOptions(options);\n super(normalized, LITELLM_PROFILE);\n this.admin = new LiteLLMAdmin({\n provider: 'litellm',\n baseUrl: resolveGatewayAdminBaseUrl(\n normalized.baseUrl,\n normalized.adminUrl || normalized.adminBaseUrl,\n 'litellm',\n ),\n apiKey: normalized.adminApiKey || normalized.apiKey,\n headers: normalized.adminHeaders,\n timeout: normalized.timeout,\n });\n this.configuredDefaultModel = normalized.defaultModel;\n }\n\n private async resolveModel(\n capability: LiteLLMResolvedCapability,\n explicitModel?: string,\n ): Promise<string> {\n if (explicitModel) {\n return explicitModel;\n }\n\n if (\n this.configuredDefaultModel &&\n (capability === 'chat' || capability === 'vision')\n ) {\n return this.configuredDefaultModel;\n }\n\n const cached = this.resolvedModelCache.get(capability);\n if (cached) {\n return cached;\n }\n\n const pending = this.selectModel(capability).catch((error) => {\n this.resolvedModelCache.delete(capability);\n throw error;\n });\n this.resolvedModelCache.set(capability, pending);\n return pending;\n }\n\n private async selectModel(\n capability: LiteLLMResolvedCapability,\n ): Promise<string> {\n const models = await super.getModels();\n const model = models.find((candidate) =>\n supportsCapability(candidate, capability),\n );\n\n if (!model) {\n throw new ValidationError(\n `No ${capability} model is available from the LiteLLM gateway`,\n {\n provider: 'litellm',\n capability,\n hint: 'Pass defaultModel explicitly or ensure /models returns a compatible model for this key',\n },\n );\n }\n\n return model.id;\n }\n\n async chat(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): Promise<AIResponse> {\n const safe = normalizeChatOptions(\n this.options,\n options,\n 'litellm',\n options.model || this.options.defaultModel,\n );\n return super.chat(messages, {\n ...safe,\n model: await this.resolveModel('chat', safe.model),\n });\n }\n\n async *stream(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): AsyncIterable<string> {\n const safe = normalizeChatOptions(\n this.options,\n options,\n 'litellm',\n options.model || this.options.defaultModel,\n );\n yield* super.stream(messages, {\n ...safe,\n model: await this.resolveModel('chat', safe.model),\n });\n }\n\n async describeImage(\n image: string | Buffer,\n prompt?: string,\n options: ImageDescriptionOptions = {},\n ): Promise<string> {\n const safe = normalizeChatOptions(\n this.options,\n options,\n 'litellm',\n options.model || this.options.defaultModel,\n );\n return super.describeImage(image, prompt, {\n ...safe,\n model: await this.resolveModel('vision', safe.model),\n });\n }\n\n async embed(\n text: string | string[],\n options: EmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n return super.embed(text, {\n ...options,\n model: await this.resolveModel('embeddings', options.model),\n });\n }\n\n async embedImage(\n image: string | Buffer,\n options: ImageEmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n return super.embedImage(image, {\n ...options,\n model: await this.resolveModel('embeddings', options.model),\n });\n }\n\n async generateImage(\n prompt: string,\n options: ImageGenerationOptions = {},\n ): Promise<ImageGenerationResponse> {\n const safe = normalizeImageGenerationOptions(\n this.options,\n options,\n 'litellm',\n options.model,\n );\n return super.generateImage(prompt, {\n ...safe,\n model: await this.resolveModel('image_generation', safe.model),\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1202,10 +1202,10 @@ async function getAI(options = {}) {
|
|
|
1202
1202
|
const { OpenAIProvider } = await Promise.resolve().then(() => openai_exports);
|
|
1203
1203
|
client = new OpenAIProvider(options);
|
|
1204
1204
|
} else if (isLiteLLMOptions(options)) {
|
|
1205
|
-
const { LiteLLMProvider } = await import("./litellm-
|
|
1205
|
+
const { LiteLLMProvider } = await import("./litellm-xCO8QlGI.js");
|
|
1206
1206
|
client = new LiteLLMProvider(options);
|
|
1207
1207
|
} else if (isBifrostOptions(options)) {
|
|
1208
|
-
const { BifrostProvider } = await import("./bifrost-
|
|
1208
|
+
const { BifrostProvider } = await import("./bifrost-DzT2J0Lq.js");
|
|
1209
1209
|
client = new BifrostProvider(options);
|
|
1210
1210
|
} else if (isOllamaOptions(options)) {
|
|
1211
1211
|
const { OllamaProvider } = await import("./ollama-Bedt8Agy.js");
|
|
@@ -1238,7 +1238,7 @@ async function getAI(options = {}) {
|
|
|
1238
1238
|
const { SeevioProvider } = await import("./seevio-BJRiguLc.js");
|
|
1239
1239
|
client = new SeevioProvider(options);
|
|
1240
1240
|
} else if (isTypeSafeOptions(options)) {
|
|
1241
|
-
const { TypeSafeProvider } = await import("./typesafe-
|
|
1241
|
+
const { TypeSafeProvider } = await import("./typesafe-B0gPZQJg.js");
|
|
1242
1242
|
client = new TypeSafeProvider(options);
|
|
1243
1243
|
} else throw new ValidationError("Unsupported AI provider type", {
|
|
1244
1244
|
supportedTypes: [...AI_PROVIDER_TYPES],
|
|
@@ -1512,4 +1512,4 @@ var PACKAGE_VERSION_INITIALIZED = true;
|
|
|
1512
1512
|
//#endregion
|
|
1513
1513
|
export { getAI as a, OpenAIClient as c, OpenAIProvider as d, factory_exports as i, getAIClient as l, AIThread as n, getAIAuto as o, AIMessage as r, AIClient as s, PACKAGE_VERSION_INITIALIZED as t, getOpenAI as u };
|
|
1514
1514
|
|
|
1515
|
-
//# sourceMappingURL=src-
|
|
1515
|
+
//# sourceMappingURL=src-BUQUZK2M.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src-DOm4LN_h.js","names":[],"sources":["../../src/shared/providers/openai.ts","../../src/shared/client.ts","../../src/shared/factory.ts","../../src/shared/message.ts","../../src/shared/thread.ts","../../src/index.ts"],"sourcesContent":["/**\n * OpenAI provider implementation\n *\n * Provides a standardized interface for interacting with OpenAI's GPT models,\n * including chat completions, text completions, embeddings, and streaming responses.\n * Supports all major OpenAI features including function calling, vision models,\n * and custom fine-tuned models.\n */\n\nimport OpenAI from 'openai';\nimport { extractRetryAfterSeconds } from '../rate-limit';\nimport {\n normalizeBaseAIOptions,\n normalizeChatOptions,\n normalizeImageGenerationOptions,\n type PreparedRequestControls,\n prepareRequestControls,\n} from '../safety';\nimport type {\n AICapabilities,\n AIInterface,\n AIMessage,\n AIModel,\n AIResponse,\n BaseAIOptions,\n ChatOptions,\n CompletionOptions,\n ContentPart,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n MessageOptions,\n TokenUsage,\n TTSOptions,\n TTSResponse,\n VideoGenerationJob,\n VideoGenerationOptions,\n VideoGenerationResult,\n VideoGenerationStatusResult,\n Voice,\n VoiceCloneOptions,\n VoiceDesignOptions,\n VoiceListOptions,\n} from '../types';\nimport {\n AIError,\n AuthenticationError,\n ContentFilterError,\n ContextLengthError,\n ModelNotFoundError,\n RateLimitError,\n} from '../types';\nimport { emitUsage } from './usage';\n\n/**\n * Determines whether a model uses OpenAI's newer reasoning-model request\n * shape: `max_completion_tokens` in place of `max_tokens`, and no\n * `temperature` parameter at all (a non-default `temperature` is rejected\n * with a 400 error).\n *\n * This applies to the `gpt-5` family (`gpt-5`, `gpt-5-mini`, `gpt-5-nano`,\n * and future `gpt-5*` variants) and the `o`-series reasoning models (`o1`,\n * `o3`, `o4`, and their variants such as `o1-mini`, `o3-mini`, `o4-mini`).\n * See OpenAI's reasoning models guide and the Chat Completions API\n * reference for `max_completion_tokens`:\n * https://platform.openai.com/docs/guides/reasoning\n * https://platform.openai.com/docs/api-reference/chat/create\n *\n * The match is a conservative prefix/family check so future `gpt-5*` and\n * `o1`/`o3`/`o4` variants are covered without needing an allowlist update.\n * Models outside these families (`gpt-4.x`, `gpt-3.5`, etc.) are unaffected\n * and keep sending `max_tokens` and `temperature` as before.\n *\n * Gateway providers (`BifrostProvider`, some `LiteLLMProvider` deployments)\n * route with a vendor-prefixed model id, e.g. `openai/gpt-5-mini` — see\n * `BifrostProvider`'s own `defaultModel: 'openai/gpt-4o-mini'` convention in\n * `bifrost.ts`. Only the final path segment is matched against the family\n * checks so those gateway-routed ids are recognized the same as a bare\n * `gpt-5-mini`.\n *\n * Internal request-shaping helper: exported at module level only so it can\n * be unit-tested directly. It is not re-exported from the package entry\n * point (`src/index.ts`) and is not part of the package's public API.\n *\n * @param model - The model identifier (e.g. `gpt-5-mini`, `openai/gpt-5-mini`, `gpt-4.1-mini`)\n * @returns `true` when the model requires `max_completion_tokens` and rejects `temperature`\n */\nexport function usesCompletionTokenLimit(model: string | undefined): boolean {\n if (!model) return false;\n const normalized = model.toLowerCase();\n const lastSegment = normalized.slice(normalized.lastIndexOf('/') + 1);\n return lastSegment.startsWith('gpt-5') || /^o[134](-|$)/.test(lastSegment);\n}\n\n/**\n * Builds the output-token-limit and temperature fields for a chat/completion\n * request body, shaped for the given model per {@link usesCompletionTokenLimit}.\n *\n * For models that require it: sends `max_completion_tokens` and omits\n * `max_tokens`, and omits `temperature` entirely (never sends a default\n * value in its place). For all other models: sends `max_tokens` and\n * `temperature` unchanged. Fields whose source value is `undefined` are\n * omitted rather than included as `undefined` keys.\n *\n * Internal request-shaping helper: exported at module level only so it can\n * be unit-tested directly. It is not re-exported from the package entry\n * point (`src/index.ts`) and is not part of the package's public API.\n */\nexport function buildTokenLimitRequestFields(\n model: string,\n maxTokens: number | undefined,\n temperature: number | undefined,\n): {\n max_tokens?: number;\n max_completion_tokens?: number;\n temperature?: number;\n} {\n if (usesCompletionTokenLimit(model)) {\n return maxTokens === undefined ? {} : { max_completion_tokens: maxTokens };\n }\n return {\n ...(maxTokens === undefined ? {} : { max_tokens: maxTokens }),\n ...(temperature === undefined ? {} : { temperature }),\n };\n}\n\n/**\n * Shared profile for OpenAI-compatible providers\n */\nexport interface OpenAICompatibleProfile {\n providerLabel: string;\n providerName: string;\n defaultModel: string;\n capabilities: AICapabilities;\n describeModel(modelId: string): string;\n getContextLength(modelId: string): number;\n getModelCapabilities(modelId: string): string[];\n shouldIncludeModel(modelId: string): boolean;\n supportsFunctions(modelId: string): boolean;\n supportsVision(modelId: string): boolean;\n}\n\nconst OPENAI_PROFILE: OpenAICompatibleProfile = {\n providerLabel: 'OpenAI',\n providerName: 'openai',\n defaultModel: 'gpt-4o',\n capabilities: {\n chat: true,\n completion: true,\n embeddings: true,\n streaming: true,\n functions: true,\n vision: true,\n fineTuning: true,\n imageEmbeddings: true,\n imageGeneration: true,\n videoGeneration: false,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 128000,\n supportedOperations: [\n 'chat',\n 'completion',\n 'embedding',\n 'streaming',\n 'functions',\n 'vision',\n 'image_embedding',\n 'image_generation',\n ],\n },\n describeModel: (modelId) => `OpenAI model: ${modelId}`,\n getContextLength(modelId) {\n if (modelId.includes('gpt-4o')) return 128000;\n if (modelId.includes('gpt-4.1')) return 128000;\n if (modelId.includes('gpt-4-turbo')) return 128000;\n if (modelId.includes('gpt-4')) return 8192;\n if (modelId.includes('gpt-3.5-turbo')) return 16385;\n if (modelId.includes('text-embedding')) return 8192;\n return 4096;\n },\n getModelCapabilities(modelId) {\n const capabilities = ['text'];\n if (modelId.includes('gpt')) {\n capabilities.push('chat', 'functions');\n }\n if (\n modelId.includes('vision') ||\n modelId === 'gpt-4o' ||\n modelId.includes('gpt-4.1')\n ) {\n capabilities.push('vision');\n }\n if (modelId.includes('embedding')) {\n capabilities.push('embeddings');\n }\n return capabilities;\n },\n shouldIncludeModel(modelId) {\n return modelId.includes('gpt') || modelId.includes('text-embedding');\n },\n supportsFunctions(modelId) {\n return modelId.includes('gpt-4') || modelId.includes('gpt-3.5');\n },\n supportsVision(modelId) {\n return (\n modelId.includes('vision') ||\n modelId === 'gpt-4o' ||\n modelId.includes('gpt-4.1')\n );\n },\n};\n\nexport interface OpenAICompatibleOptions extends BaseAIOptions {\n type?: string;\n apiKey?: string;\n baseUrl?: string;\n organization?: string;\n}\n\n/**\n * OpenAI provider implementation that handles all interactions with OpenAI's API.\n * Supports GPT models, embeddings, function calling, streaming, and vision capabilities.\n */\nexport class OpenAIProvider implements AIInterface {\n private client: OpenAI;\n protected options: OpenAICompatibleOptions;\n protected readonly profile: OpenAICompatibleProfile;\n\n /**\n * Creates a new OpenAI provider instance\n * @param options - Configuration options for the OpenAI provider\n */\n constructor(\n options: OpenAICompatibleOptions,\n profile: OpenAICompatibleProfile = OPENAI_PROFILE,\n ) {\n this.profile = profile;\n this.options = normalizeBaseAIOptions({\n defaultModel: this.profile.defaultModel,\n ...options,\n });\n\n this.client = new OpenAI({\n apiKey: this.options.apiKey,\n baseURL: this.options.baseUrl,\n organization: this.options.organization,\n timeout: this.options.timeout,\n maxRetries: this.options.maxRetries,\n defaultHeaders: this.options.headers,\n });\n }\n\n /**\n * Generate a chat completion using OpenAI's chat models\n * @param messages - Array of conversation messages\n * @param options - Optional configuration for the chat completion\n * @returns Promise resolving to the AI response with content and metadata\n * @throws {AIError} When the API request fails or returns invalid data\n *\n * @example\n * ```typescript\n * const response = await provider.chat([\n * { role: 'system', content: 'You are a helpful assistant.' },\n * { role: 'user', content: 'What is the capital of France?' }\n * ], {\n * model: 'gpt-4o',\n * temperature: 0.7,\n * maxTokens: 150\n * });\n * console.log(response.content); // \"Paris is the capital of France.\"\n * ```\n */\n async chat(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): Promise<AIResponse> {\n const startTime = Date.now();\n let controls: PreparedRequestControls | undefined;\n try {\n const model =\n options.model || this.options.defaultModel || this.profile.defaultModel;\n options = normalizeChatOptions(\n this.options,\n options,\n this.profile.providerName,\n model,\n );\n controls = prepareRequestControls(this.options, options);\n const request = {\n model,\n messages: this.mapMessagesToOpenAI(messages),\n ...buildTokenLimitRequestFields(\n model,\n options.maxTokens,\n options.temperature,\n ),\n top_p: options.topP,\n n: options.n,\n stop: options.stop,\n frequency_penalty: options.frequencyPenalty,\n presence_penalty: options.presencePenalty,\n user: options.user,\n tools: options.tools?.map((tool) => ({\n type: 'function' as const,\n function: {\n name: tool.function.name,\n description: tool.function.description,\n parameters: tool.function.parameters,\n },\n })),\n tool_choice: this.mapToolChoice(options.toolChoice),\n response_format: options.responseFormat,\n seed: options.seed,\n stream: false,\n } as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming & {\n reasoning?: {\n effort?: string;\n max_tokens?: number;\n include_thoughts?: boolean;\n };\n };\n if (\n (this.profile.providerName === 'bifrost' ||\n this.profile.providerName === 'litellm') &&\n (options.reasoning?.maxTokens || 0) > 0\n ) {\n request.reasoning = {\n effort: options.reasoning?.effort,\n max_tokens: options.reasoning?.maxTokens,\n include_thoughts: options.reasoning?.includeThoughts,\n };\n }\n const response = await this.client.chat.completions.create(request, {\n signal: controls.signal,\n timeout: controls.timeout,\n });\n\n const choice = response.choices[0];\n if (!choice) {\n throw new AIError(\n `No choices returned from ${this.profile.providerLabel}`,\n 'NO_CHOICES',\n this.profile.providerName,\n );\n }\n\n const usage = this.mapUsage(response.usage);\n emitUsage(\n this.options,\n this.profile.providerName,\n 'chat',\n response.model || model,\n usage,\n startTime,\n options.usageTags,\n );\n\n return {\n content: choice.message.content || '',\n usage,\n model: response.model,\n finishReason: this.mapFinishReason(choice.finish_reason),\n toolCalls: choice.message.tool_calls\n ?.filter((call) => call.type === 'function')\n .map((call) => ({\n id: call.id,\n type: 'function' as const,\n function: {\n name: call.function.name,\n arguments: call.function.arguments,\n },\n })),\n };\n } catch (error) {\n if (controls?.didTimeout()) {\n throw new AIError(\n `AI request timed out after ${controls.timeout}ms`,\n 'AI_TIMEOUT',\n this.profile.providerName,\n options.model,\n );\n }\n if (options.signal?.aborted) {\n throw new AIError(\n 'AI request aborted by caller',\n 'AI_ABORTED',\n this.profile.providerName,\n options.model,\n );\n }\n throw this.mapError(error);\n } finally {\n controls?.cleanup();\n }\n }\n\n /**\n * Generate a text completion for a given prompt\n * @param prompt - The text prompt to complete\n * @param options - Optional configuration for the completion\n * @returns Promise resolving to the AI response\n * @throws {AIError} When the API request fails\n *\n * @example\n * ```typescript\n * const response = await provider.complete('The weather today is', {\n * model: 'gpt-4o',\n * maxTokens: 50,\n * temperature: 0.5\n * });\n * ```\n */\n async complete(\n prompt: string,\n options: CompletionOptions = {},\n ): Promise<AIResponse> {\n return this.chat([{ role: 'user', content: prompt }], {\n model: options.model,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n topP: options.topP,\n n: options.n,\n stop: options.stop,\n stream: options.stream,\n onProgress: options.onProgress,\n signal: options.signal,\n timeout: options.timeout,\n reasoning: options.reasoning,\n usageTags: options.usageTags,\n });\n }\n\n /**\n * Simple message interface for single-turn interactions with optional history\n *\n * @param text - The message text to send\n * @param options - Configuration options including history, model, etc.\n * @returns Promise resolving to the response content string\n *\n * @example\n * ```typescript\n * // Simple usage\n * const response = await provider.message('Hello!');\n *\n * // With options\n * const response = await provider.message('Analyze this', {\n * model: 'gpt-4o',\n * responseFormat: { type: 'json_object' }\n * });\n *\n * // With history\n * const response = await provider.message('What was my question?', {\n * history: [\n * { role: 'user', content: 'What is 2+2?' },\n * { role: 'assistant', content: '4' }\n * ]\n * });\n * ```\n */\n async message(text: string, options: MessageOptions = {}): Promise<string> {\n // Build messages array from history + current message\n const messages: AIMessage[] = [\n ...(options.history || []),\n { role: options.role || 'user', content: text },\n ];\n\n const response = await this.chat(messages, {\n model: options.model,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n topP: options.topP,\n stop: options.stop,\n stream: options.stream,\n frequencyPenalty: options.frequencyPenalty,\n presencePenalty: options.presencePenalty,\n responseFormat: options.responseFormat,\n seed: options.seed,\n tools: options.tools,\n toolChoice: options.toolChoice,\n onProgress: options.onProgress,\n signal: options.signal,\n timeout: options.timeout,\n reasoning: options.reasoning,\n usageTags: options.usageTags,\n });\n\n return response.content;\n }\n\n /**\n * Generate embeddings for the given text(s)\n * @param text - Single text string or array of texts to embed\n * @param options - Optional configuration for embeddings\n * @returns Promise resolving to embeddings response with vector arrays\n * @throws {AIError} When the API request fails\n *\n * @example\n * ```typescript\n * // Single text embedding\n * const response1 = await provider.embed('Hello world');\n * console.log(response1.embeddings[0]); // Array of numbers\n *\n * // Multiple text embeddings\n * const response2 = await provider.embed(['Text 1', 'Text 2']);\n * console.log(response2.embeddings.length); // 2\n * ```\n */\n async embed(\n text: string | string[],\n options: EmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n const startTime = Date.now();\n try {\n const model = options.model || 'text-embedding-3-small';\n const input = Array.isArray(text) ? text : [text];\n const response = await this.client.embeddings.create({\n model,\n input,\n encoding_format: options.encodingFormat,\n dimensions: options.dimensions,\n user: options.user,\n });\n\n const usage = this.mapUsage(response.usage);\n emitUsage(\n this.options,\n this.profile.providerName,\n 'embed',\n response.model || model,\n usage,\n startTime,\n options.usageTags,\n );\n\n return {\n embeddings: response.data.map((item) => item.embedding),\n usage,\n model: response.model,\n };\n } catch (error) {\n throw this.mapError(error);\n }\n }\n\n /**\n * Convert an image to a base64 data URL\n * @param image - Image as URL, base64 data URL, or Buffer\n * @returns base64 data URL string\n * @private\n */\n private async imageToBase64(\n image: string | Buffer,\n signal?: AbortSignal,\n ): Promise<string> {\n if (Buffer.isBuffer(image)) {\n return `data:image/png;base64,${image.toString('base64')}`;\n }\n if (image.startsWith('data:')) {\n return image; // Already base64 data URL\n }\n // It's a URL - fetch and convert\n const response = await fetch(image, { signal });\n if (!response.ok) {\n throw new AIError(\n `Failed to fetch image: ${response.status} ${response.statusText}`,\n 'IMAGE_FETCH_ERROR',\n this.profile.providerName,\n );\n }\n const arrayBuffer = await response.arrayBuffer();\n const buffer = Buffer.from(arrayBuffer);\n const contentType = response.headers.get('content-type') || 'image/png';\n return `data:${contentType};base64,${buffer.toString('base64')}`;\n }\n\n /**\n * Generate a text description of an image\n * @param image - Image as URL, base64 data URL, or Buffer\n * @param prompt - Custom prompt for description (optional)\n * @param options - Optional configuration\n * @returns Promise resolving to the description string\n *\n * @example\n * ```typescript\n * const description = await provider.describeImage('https://example.com/image.jpg');\n * ```\n */\n async describeImage(\n image: string | Buffer,\n prompt?: string,\n options: ImageDescriptionOptions = {},\n ): Promise<string> {\n let controls: PreparedRequestControls | undefined;\n try {\n const defaultPrompt =\n 'Describe this image for a search index. Include objects, mood, lighting, and any visible text.';\n\n controls = prepareRequestControls(this.options, options);\n const imageUrl = await this.imageToBase64(image, controls.signal);\n\n const response = await this.chat(\n [\n {\n role: 'user',\n content: [\n { type: 'text', text: prompt || defaultPrompt },\n {\n type: 'image_url',\n image_url: {\n url: imageUrl,\n detail: options.detail || 'auto',\n },\n },\n ],\n },\n ],\n {\n model:\n options.model ||\n this.options.defaultModel ||\n this.profile.defaultModel,\n maxTokens: options.maxTokens ?? 500,\n signal: controls.signal,\n timeout: controls.timeout,\n reasoning: options.reasoning,\n usageTags: options.usageTags,\n },\n );\n\n return response.content;\n } catch (error) {\n if (controls?.didTimeout()) {\n throw new AIError(\n `AI request timed out after ${controls.timeout}ms`,\n 'AI_TIMEOUT',\n this.profile.providerName,\n options.model,\n );\n }\n if (options.signal?.aborted) {\n throw new AIError(\n 'AI request aborted by caller',\n 'AI_ABORTED',\n this.profile.providerName,\n options.model,\n );\n }\n throw this.mapError(error);\n } finally {\n controls?.cleanup();\n }\n }\n\n /**\n * Generate embeddings for an image using describe-then-embed pattern\n * @param image - Image as URL, base64 data URL, or Buffer\n * @param options - Optional configuration for image embeddings\n * @returns Promise resolving to embeddings response\n *\n * @example\n * ```typescript\n * const embedding = await provider.embedImage('https://example.com/image.jpg');\n * ```\n */\n async embedImage(\n image: string | Buffer,\n options: ImageEmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n try {\n // OpenAI doesn't have native image embeddings - use describe-then-embed\n const description = await this.describeImage(\n image,\n 'Describe this image in detail for semantic embedding. Include all visible objects, colors, textures, composition, text, people, actions, and overall scene context.',\n );\n\n return this.embed(description, {\n model: options.model || 'text-embedding-3-small',\n dimensions: options.dimensions,\n user: options.user,\n });\n } catch (error) {\n throw this.mapError(error);\n }\n }\n\n /**\n * Generate an image from a text prompt using DALL-E\n * @param prompt - Text description of the image to generate\n * @param options - Optional configuration for image generation\n * @returns Promise resolving to generated image(s)\n *\n * @example\n * ```typescript\n * const result = await provider.generateImage('A sunset over mountains');\n * fs.writeFileSync('image.png', result.images[0].data);\n * ```\n */\n async generateImage(\n prompt: string,\n options: ImageGenerationOptions = {},\n ): Promise<ImageGenerationResponse> {\n let controls: PreparedRequestControls | undefined;\n try {\n const model = options.model || 'dall-e-3';\n options = normalizeImageGenerationOptions(\n this.options,\n options,\n this.profile.providerName,\n model,\n );\n controls = prepareRequestControls(this.options, options);\n\n const requestParams: OpenAI.Images.ImageGenerateParams = {\n model,\n prompt,\n n: model === 'dall-e-3' ? 1 : options.n,\n size:\n (options.size as OpenAI.Images.ImageGenerateParams['size']) ||\n '1024x1024',\n response_format: options.outputFormat === 'url' ? 'url' : 'b64_json',\n };\n\n if (model === 'dall-e-3') {\n if (options.style) {\n requestParams.style = options.style;\n }\n if (options.quality) {\n requestParams.quality =\n options.quality as OpenAI.Images.ImageGenerateParams['quality'];\n }\n }\n\n const response = await this.client.images.generate(requestParams, {\n signal: controls.signal,\n timeout: controls.timeout,\n });\n\n const images = (response.data || []).map((item) => {\n let data: Buffer | string;\n const mimeType = 'image/png';\n\n if (options.outputFormat === 'url') {\n data = item.url || '';\n } else if (options.outputFormat === 'base64') {\n data = item.b64_json || '';\n } else {\n // Default: buffer\n data = Buffer.from(item.b64_json || '', 'base64');\n }\n\n return {\n data,\n mimeType,\n revisedPrompt: item.revised_prompt,\n };\n });\n\n return {\n images,\n model,\n };\n } catch (error) {\n if (controls?.didTimeout()) {\n throw new AIError(\n `AI request timed out after ${controls.timeout}ms`,\n 'AI_TIMEOUT',\n this.profile.providerName,\n options.model,\n );\n }\n if (options.signal?.aborted) {\n throw new AIError(\n 'AI request aborted by caller',\n 'AI_ABORTED',\n this.profile.providerName,\n options.model,\n );\n }\n throw this.mapError(error);\n } finally {\n controls?.cleanup();\n }\n }\n\n // ============================================================================\n // Video Generation Methods (Not supported - use gemini, byteplus-modelark,\n // or openai-compat-video provider)\n // ============================================================================\n\n async submitVideoGenerationJob(\n _options: VideoGenerationOptions,\n ): Promise<VideoGenerationJob> {\n throw new AIError(\n `Video generation is not supported by ${this.profile.providerLabel} provider. Use gemini, byteplus-modelark, or openai-compat-video provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n async getVideoGenerationJob(\n _handle: VideoGenerationJob,\n ): Promise<VideoGenerationStatusResult> {\n throw new AIError(\n `Video generation is not supported by ${this.profile.providerLabel} provider. Use gemini, byteplus-modelark, or openai-compat-video provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n async fetchVideoGenerationResult(\n _handle: VideoGenerationJob,\n ): Promise<VideoGenerationResult> {\n throw new AIError(\n `Video generation is not supported by ${this.profile.providerLabel} provider. Use gemini, byteplus-modelark, or openai-compat-video provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n async cancelVideoGenerationJob(_handle: VideoGenerationJob): Promise<void> {\n throw new AIError(\n `Video generation is not supported by ${this.profile.providerLabel} provider. Use gemini, byteplus-modelark, or openai-compat-video provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n async validateVideoGenerationAccess(): Promise<boolean> {\n throw new AIError(\n `Video generation is not supported by ${this.profile.providerLabel} provider. Use gemini, byteplus-modelark, or openai-compat-video provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n /**\n * Stream a chat completion response in real-time\n * @param messages - Array of conversation messages\n * @param options - Optional configuration for the chat completion\n * @yields Individual content chunks as they arrive\n * @throws {AIError} When the streaming request fails\n *\n * @example\n * ```typescript\n * for await (const chunk of provider.stream([\n * { role: 'user', content: 'Write a story about AI' }\n * ])) {\n * process.stdout.write(chunk);\n * }\n * ```\n */\n async *stream(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): AsyncIterable<string> {\n const startTime = Date.now();\n let controls: PreparedRequestControls | undefined;\n try {\n const model =\n options.model || this.options.defaultModel || this.profile.defaultModel;\n options = normalizeChatOptions(\n this.options,\n options,\n this.profile.providerName,\n model,\n );\n controls = prepareRequestControls(this.options, options);\n const request = {\n model,\n messages: this.mapMessagesToOpenAI(messages),\n ...buildTokenLimitRequestFields(\n model,\n options.maxTokens,\n options.temperature,\n ),\n top_p: options.topP,\n stop: options.stop,\n frequency_penalty: options.frequencyPenalty,\n presence_penalty: options.presencePenalty,\n user: options.user,\n stream: true,\n } as OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming & {\n reasoning?: {\n effort?: string;\n max_tokens?: number;\n include_thoughts?: boolean;\n };\n };\n if (\n (this.profile.providerName === 'bifrost' ||\n this.profile.providerName === 'litellm') &&\n (options.reasoning?.maxTokens || 0) > 0\n ) {\n request.reasoning = {\n effort: options.reasoning?.effort,\n max_tokens: options.reasoning?.maxTokens,\n include_thoughts: options.reasoning?.includeThoughts,\n };\n }\n const stream = await this.client.chat.completions.create(request, {\n signal: controls.signal,\n timeout: controls.timeout,\n });\n\n for await (const chunk of stream) {\n const content = chunk.choices[0]?.delta?.content;\n if (content) {\n if (options.onProgress) {\n options.onProgress(content);\n }\n yield content;\n }\n }\n\n emitUsage(\n this.options,\n this.profile.providerName,\n 'stream',\n model,\n undefined,\n startTime,\n options.usageTags,\n );\n } catch (error) {\n if (controls?.didTimeout()) {\n throw new AIError(\n `AI request timed out after ${controls.timeout}ms`,\n 'AI_TIMEOUT',\n this.profile.providerName,\n options.model,\n );\n }\n if (options.signal?.aborted) {\n throw new AIError(\n 'AI request aborted by caller',\n 'AI_ABORTED',\n this.profile.providerName,\n options.model,\n );\n }\n throw this.mapError(error);\n } finally {\n controls?.cleanup();\n }\n }\n\n /**\n * Count the number of tokens in the given text\n * @param text - The text to count tokens for\n * @returns Promise resolving to the estimated token count\n *\n * @remarks\n * OpenAI doesn't provide a direct token counting API, so this is an approximation\n * based on the general rule of ~4 characters per token. For precise counting,\n * consider using a dedicated tokenizer library.\n *\n * @example\n * ```typescript\n * const count = await provider.countTokens('Hello, world!');\n * console.log(count); // Approximately 4 tokens\n * ```\n */\n async countTokens(text: string): Promise<number> {\n // OpenAI doesn't provide a direct token counting API\n // This is an approximation based on the general rule of ~4 characters per token\n return Math.ceil(text.length / 4);\n }\n\n /**\n * Get a list of available OpenAI models\n * @returns Promise resolving to an array of model information\n * @throws {AIError} When the API request fails\n *\n * @example\n * ```typescript\n * const models = await provider.getModels();\n * const gptModels = models.filter(m => m.id.includes('gpt'));\n * ```\n */\n async getModels(): Promise<AIModel[]> {\n try {\n const response = await this.client.models.list();\n return response.data\n .filter((model) => this.profile.shouldIncludeModel(model.id))\n .map((model) => ({\n id: model.id,\n name: model.id,\n description: this.profile.describeModel(model.id),\n contextLength: this.profile.getContextLength(model.id),\n capabilities: this.profile.getModelCapabilities(model.id),\n supportsFunctions: this.profile.supportsFunctions(model.id),\n supportsVision: this.profile.supportsVision(model.id),\n }));\n } catch (error) {\n throw this.mapError(error);\n }\n }\n\n /**\n * Get the capabilities supported by this OpenAI provider\n * @returns Promise resolving to provider capabilities\n *\n * @example\n * ```typescript\n * const caps = await provider.getCapabilities();\n * if (caps.functions) {\n * // Provider supports function calling\n * }\n * ```\n */\n async getCapabilities(): Promise<AICapabilities> {\n return { ...this.profile.capabilities };\n }\n\n // ============================================================================\n // TTS Methods (Not supported - use Qwen3-TTS provider)\n // ============================================================================\n\n async synthesizeSpeech(\n _text: string,\n _options?: TTSOptions,\n ): Promise<TTSResponse> {\n throw new AIError(\n `TTS is not supported by ${this.profile.providerLabel} provider. Use Qwen3-TTS provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n streamSpeech(_text: string, _options?: TTSOptions): AsyncIterable<Buffer> {\n const error = new AIError(\n `TTS streaming is not supported by ${this.profile.providerLabel} provider. Use Qwen3-TTS provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n return {\n [Symbol.asyncIterator]: () => ({\n next: () => Promise.reject(error),\n }),\n };\n }\n\n async cloneVoice(_options: VoiceCloneOptions): Promise<Voice> {\n throw new AIError(\n `Voice cloning is not supported by ${this.profile.providerLabel} provider. Use Qwen3-TTS provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n async designVoice(_options: VoiceDesignOptions): Promise<Voice> {\n throw new AIError(\n `Voice design is not supported by ${this.profile.providerLabel} provider. Use Qwen3-TTS provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n async getVoices(_options?: VoiceListOptions): Promise<Voice[]> {\n throw new AIError(\n `Voice listing is not supported by ${this.profile.providerLabel} provider. Use Qwen3-TTS provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n /**\n * Maps internal AI messages to OpenAI's message format\n * @param messages - Array of internal AI messages\n * @returns Array of OpenAI-compatible message parameters\n * @private\n */\n private mapMessagesToOpenAI(\n messages: AIMessage[],\n ): OpenAI.Chat.ChatCompletionMessageParam[] {\n return messages.map((message) => {\n // Handle content that can be string or ContentPart[]\n let content: string | OpenAI.Chat.ChatCompletionContentPart[];\n\n if (typeof message.content === 'string') {\n content = message.content;\n } else {\n // Array of content parts - map to OpenAI format\n content = message.content.map((part: ContentPart) => {\n if (part.type === 'text') {\n return { type: 'text' as const, text: part.text };\n }\n // Image content part\n return {\n type: 'image_url' as const,\n image_url: {\n url: part.image_url.url,\n detail: part.image_url.detail,\n },\n };\n });\n }\n\n // Build message based on role and content\n const baseMessage = {\n role: message.role as OpenAI.Chat.ChatCompletionRole,\n content,\n };\n\n // Add optional fields based on role and availability\n if (\n message.name &&\n (message.role === 'system' ||\n message.role === 'user' ||\n message.role === 'function')\n ) {\n (baseMessage as any).name = message.name;\n }\n\n if (message.tool_calls && message.role === 'assistant') {\n (baseMessage as any).tool_calls = message.tool_calls;\n }\n\n return baseMessage as OpenAI.Chat.ChatCompletionMessageParam;\n });\n }\n\n /**\n * Maps internal tool choice format to OpenAI's tool choice format\n * @param toolChoice - Internal tool choice specification\n * @returns OpenAI-compatible tool choice option or undefined\n * @private\n */\n private mapToolChoice(\n toolChoice?:\n | 'auto'\n | 'none'\n | { type: 'function'; function: { name: string } },\n ): OpenAI.Chat.ChatCompletionToolChoiceOption | undefined {\n if (!toolChoice) return undefined;\n if (typeof toolChoice === 'string') return toolChoice;\n return {\n type: 'function',\n function: { name: toolChoice.function.name },\n };\n }\n\n /**\n * Maps OpenAI usage information to internal token usage format\n * @param usage - OpenAI usage object from API response\n * @returns Internal token usage object or undefined\n * @private\n */\n private mapUsage(\n usage?:\n | OpenAI.CompletionUsage\n | OpenAI.Completions.CompletionUsage\n | OpenAI.Embeddings.CreateEmbeddingResponse.Usage,\n ): TokenUsage | undefined {\n if (!usage) return undefined;\n return {\n promptTokens: usage.prompt_tokens || 0,\n completionTokens: (usage as any).completion_tokens || 0,\n totalTokens: usage.total_tokens || 0,\n };\n }\n\n /**\n * Maps OpenAI finish reason to internal finish reason format\n * @param reason - OpenAI finish reason from API response\n * @returns Internal finish reason\n * @private\n */\n private mapFinishReason(reason: string | null): AIResponse['finishReason'] {\n switch (reason) {\n case 'stop':\n return 'stop';\n case 'length':\n return 'length';\n case 'tool_calls':\n return 'tool_calls';\n case 'content_filter':\n return 'content_filter';\n default:\n return 'stop';\n }\n }\n\n /**\n * Gets the context length for a given OpenAI model\n * @param modelId - The OpenAI model identifier\n * @returns Maximum context length in tokens\n * @private\n */\n /**\n * Maps OpenAI API errors to internal AI error types\n * @param error - The error object from OpenAI API\n * @returns Appropriate internal AI error instance\n * @private\n */\n\n private mapError(error: unknown): AIError {\n if (error instanceof OpenAI.APIError) {\n switch (error.status) {\n case 401:\n return new AuthenticationError(this.profile.providerName);\n case 429: {\n return new RateLimitError(\n this.profile.providerName,\n extractRetryAfterSeconds(error),\n );\n }\n case 404:\n return new ModelNotFoundError(\n error.message,\n this.profile.providerName,\n );\n case 413:\n return new ContextLengthError(this.profile.providerName);\n default:\n if (error.message.includes('content_filter')) {\n return new ContentFilterError(this.profile.providerName);\n }\n return new AIError(\n error.message,\n 'API_ERROR',\n this.profile.providerName,\n );\n }\n }\n\n if (error instanceof AIError) {\n return error;\n }\n\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error occurred';\n return new AIError(\n errorMessage,\n 'UNKNOWN_ERROR',\n this.profile.providerName,\n );\n }\n}\n","import { ApiError, ValidationError } from '@happyvertical/utils';\nimport OpenAI from 'openai';\n\nimport type { AIMessageOptions } from './message';\nimport { buildTokenLimitRequestFields } from './providers/openai';\nimport type { AIProviderType, AIRateLimitOptions } from './types';\nimport { AI_PROVIDER_TYPES } from './types';\n\n/**\n * Common options for AI client configuration\n */\nexport interface AIClientOptions {\n /**\n * Type of AI client (e.g., 'openai')\n */\n type?: AIProviderType | string;\n\n /**\n * Response format for AI completions\n */\n responseFormat?: string;\n\n /**\n * API key for authentication\n */\n apiKey?: string;\n\n /**\n * Base URL for API requests\n */\n baseUrl?: string;\n\n /**\n * Admin API key for gateway providers that support provisioning.\n */\n adminApiKey?: string;\n\n /**\n * Admin base URL for gateway providers when it differs from `baseUrl`.\n */\n adminBaseUrl?: string;\n\n /**\n * Alias for adminBaseUrl.\n */\n adminUrl?: string;\n\n /**\n * Admin username for providers that use HTTP Basic auth.\n */\n adminUser?: string;\n\n /**\n * Admin username for providers that use HTTP Basic auth.\n */\n adminUsername?: string;\n\n /**\n * Admin password for providers that use HTTP Basic auth.\n */\n adminPassword?: string;\n\n /**\n * Custom admin headers for gateway providers.\n */\n adminHeaders?: Record<string, string>;\n\n /**\n * Optional shared pacing / retry configuration for getAI().\n */\n rateLimit?: AIRateLimitOptions;\n}\n\n/**\n * Interface defining required methods for AI clients\n */\nexport interface AIClientInterface {\n /**\n * Configuration options for this client\n */\n options: AIClientOptions;\n\n /**\n * Sends a message to the AI and gets a response\n *\n * @param text - Message text\n * @param options - Message options\n * @returns Promise resolving to the AI response\n */\n message(text: string, options: AIMessageOptions): Promise<unknown>;\n\n /**\n * Gets a text completion from the AI\n *\n * @param text - Input text for completion\n * @param options - Completion options\n * @returns Promise resolving to the completion result\n */\n textCompletion(text: string, options: AIMessageOptions): Promise<unknown>;\n}\n\n/**\n * Type guard to check if options are for OpenAI client\n *\n * @param options - Options to check\n * @returns True if options are valid for OpenAI client\n */\nfunction isOpenAIClientOptions(\n options: AIClientOptions,\n): options is OpenAIClientOptions {\n return options.type === 'openai' && 'apiKey' in options && !!options.apiKey;\n}\n\n/**\n * Type guard to check if value is an AI client instance\n *\n * @param value - Value to check\n * @returns True if value is an AI client instance\n */\nfunction isAIClientInstance(value: any): value is AIClient {\n return value instanceof AIClient;\n}\n\n/**\n * Options for AI text completion requests\n */\nexport interface AITextCompletionOptions {\n /**\n * Model identifier to use\n */\n model?: string;\n\n /**\n * Timeout in milliseconds\n */\n timeout?: number;\n\n /**\n * Role of the message sender\n */\n role?: OpenAI.Chat.ChatCompletionRole;\n\n /**\n * Previous messages in the conversation\n */\n history?: OpenAI.Chat.ChatCompletionMessageParam[];\n\n /**\n * Name of the message sender\n */\n name?: string;\n\n /**\n * Penalty for token frequency\n */\n frequencyPenalty?: number;\n\n /**\n * Token bias adjustments\n */\n logitBias?: Record<string, number>;\n\n /**\n * Whether to return log probabilities\n */\n logprobs?: boolean;\n\n /**\n * Number of top log probabilities to return\n */\n topLogprobs?: number;\n\n /**\n * Maximum tokens to generate\n */\n maxTokens?: number;\n\n /**\n * Number of completions to generate\n */\n n?: number;\n\n /**\n * Penalty for token presence\n */\n presencePenalty?: number;\n\n /**\n * Format for the response\n */\n responseFormat?: { type: 'text' | 'json_object' };\n\n /**\n * Random seed for deterministic results\n */\n seed?: number;\n\n /**\n * Sequences that stop generation\n */\n stop?: string | Array<string>;\n\n /**\n * Whether to stream responses\n */\n stream?: boolean;\n\n /**\n * Sampling temperature\n */\n temperature?: number;\n\n /**\n * Top-p sampling parameter\n */\n topProbability?: number;\n\n /**\n * Available tools for the model\n */\n tools?: Array<any>; // todo: figure out generic solution - Array<OpenAI.Chat.ChatCompletionTool>;\n\n /**\n * Tool selection behavior\n */\n toolChoice?:\n | 'none'\n | 'auto'\n | { type: 'function'; function: { name: string } };\n\n /**\n * User identifier\n */\n user?: string;\n\n /**\n * Callback for handling streaming responses\n */\n onProgress?: (partialMessage: string) => void;\n}\n\n/**\n * Base class for AI clients\n * Provides a common interface for different AI service providers\n */\nexport class AIClient {\n /**\n * Configuration options for this client\n */\n public options: AIClientOptions;\n\n /**\n * Creates a new AIClient\n *\n * @param options - Client configuration options\n */\n constructor(options: AIClientOptions) {\n this.options = options;\n }\n\n /**\n * Sends a message to the AI\n * Base implementation returns a placeholder response\n *\n * @param text - Message text\n * @param options - Message options\n * @returns Promise resolving to a placeholder response\n */\n public async message(\n _text: string,\n _options: AITextCompletionOptions = { role: 'user' },\n ) {\n return 'not a real ai message, this is the base class!';\n }\n\n /**\n * Factory method to create appropriate AI client based on options\n *\n * @param options - Client configuration options\n * @returns Promise resolving to an initialized AI client\n * @throws Error if client type is invalid\n */\n public static async create(\n options: AIClientOptions | AIClient,\n ): Promise<AIClient | OpenAIClient> {\n // If an AI client instance is passed, return it directly\n if (isAIClientInstance(options)) {\n return options;\n }\n\n // Cast to options since we know it's not an instance\n const clientOptions = options as AIClientOptions;\n\n if (isOpenAIClientOptions(clientOptions)) {\n return OpenAIClient.create(clientOptions);\n }\n\n // Delegate to modern factory for non-OpenAI providers\n const providedType = (clientOptions as any).type;\n if (providedType && providedType !== 'openai') {\n const { getAI } = await import('./factory.js');\n return (await getAI(clientOptions as any)) as any;\n }\n\n // Provide specific error messages for common issues\n if (providedType === 'openai') {\n throw new ValidationError(\n 'OpenAI API key is required but missing or empty',\n {\n supportedTypes: [...AI_PROVIDER_TYPES],\n providedType,\n hint: 'Set OPENAI_API_KEY environment variable or pass apiKey in options',\n },\n );\n }\n\n throw new ValidationError('Invalid client type specified', {\n supportedTypes: [...AI_PROVIDER_TYPES],\n providedType,\n });\n }\n\n /**\n * Gets a text completion from the AI\n * In base class, delegates to message method\n *\n * @param text - Input text for completion\n * @param options - Completion options\n * @returns Promise resolving to the completion result\n */\n public textCompletion(\n text: string,\n options: AITextCompletionOptions = {\n role: 'user',\n },\n ) {\n return this.message(text, options);\n }\n}\n\n/**\n * Creates an OpenAI client instance\n *\n * @param options - OpenAI configuration options\n * @returns Promise resolving to an OpenAI client\n */\nexport async function getOpenAI(options: {\n apiKey?: string;\n baseUrl?: string;\n}) {\n return new OpenAI({\n apiKey: options.apiKey,\n baseURL: options.baseUrl,\n });\n}\n\n/**\n * Options specific to OpenAI text completion requests\n */\nexport interface OpenAITextCompletionOptions {\n /**\n * Model identifier to use\n */\n model?: string;\n\n /**\n * Timeout in milliseconds\n */\n timeout?: number;\n\n /**\n * Role of the message sender\n */\n role?: OpenAI.Chat.ChatCompletionRole;\n\n /**\n * Previous messages in the conversation\n */\n history?: Array<OpenAI.Chat.ChatCompletionMessageParam>;\n\n /**\n * Name of the message sender\n */\n name?: string;\n\n /**\n * Penalty for token frequency\n */\n frequencyPenalty?: number;\n\n /**\n * Token bias adjustments\n */\n logitBias?: Record<string, number>;\n\n /**\n * Whether to return log probabilities\n */\n logprobs?: boolean;\n\n /**\n * Number of top log probabilities to return\n */\n topLogprobs?: number;\n\n /**\n * Maximum tokens to generate\n */\n maxTokens?: number;\n\n /**\n * Number of completions to generate\n */\n n?: number;\n\n /**\n * Penalty for token presence\n */\n presencePenalty?: number;\n\n /**\n * Format for the response\n */\n responseFormat?: { type: 'text' | 'json_object' };\n\n /**\n * Random seed for deterministic results\n */\n seed?: number;\n\n /**\n * Sequences that stop generation\n */\n stop?: string | Array<string>;\n\n /**\n * Whether to stream responses\n */\n stream?: boolean;\n\n /**\n * Sampling temperature\n */\n temperature?: number;\n\n /**\n * Top-p sampling parameter\n */\n topProbability?: number;\n\n /**\n * Available tools for the model\n */\n tools?: Array<OpenAI.Chat.ChatCompletionTool>;\n\n /**\n * Tool selection behavior\n */\n toolChoice?:\n | 'none'\n | 'auto'\n | { type: 'function'; function: { name: string } };\n\n /**\n * User identifier\n */\n user?: string;\n\n /**\n * Callback for handling streaming responses\n */\n onProgress?: (partialMessage: string) => void;\n}\n\n/**\n * Configuration options specific to OpenAI client\n */\nexport interface OpenAIClientOptions extends AIClientOptions {\n /**\n * OpenAI API key\n */\n apiKey?: string;\n\n /**\n * OpenAI API base URL\n */\n baseUrl?: string;\n}\n\n/**\n * Client implementation for the OpenAI API\n */\nexport class OpenAIClient extends AIClient {\n /**\n * OpenAI client instance\n */\n protected openai!: OpenAI;\n\n /**\n * Configuration options for this client\n */\n public options: OpenAIClientOptions;\n\n /**\n * Creates a new OpenAIClient\n *\n * @param options - OpenAI client configuration options\n */\n constructor(options: OpenAIClientOptions) {\n super(options);\n this.options = options;\n }\n\n /**\n * Sends a message to OpenAI\n *\n * @param text - Message text\n * @param options - Message options\n * @returns Promise resolving to the OpenAI response\n */\n public async message(\n text: string,\n options: AIMessageOptions = { role: 'user' },\n ) {\n const response = await this.textCompletion(text, options);\n return response;\n }\n\n /**\n * Factory method to create and initialize an OpenAIClient\n *\n * @param options - OpenAI client configuration options\n * @returns Promise resolving to an initialized OpenAIClient\n */\n public static async create(\n options: OpenAIClientOptions,\n ): Promise<OpenAIClient> {\n const client = new OpenAIClient(options);\n await client.initialize();\n return client;\n }\n\n /**\n * Initializes the OpenAI client\n */\n protected async initialize() {\n this.openai = new OpenAI({\n apiKey: this.options.apiKey,\n baseURL: this.options.baseUrl,\n });\n }\n\n /**\n * Sends a text completion request to the OpenAI API\n *\n * @param message - The message to send\n * @param options - Configuration options for the completion request\n * @returns Promise resolving to the completion text\n * @throws Error if the OpenAI API response is invalid\n */\n public async textCompletion(\n message: string,\n options: OpenAITextCompletionOptions = {},\n ): Promise<string> {\n const {\n model = 'gpt-4o',\n role = 'user',\n history = [],\n name: _name,\n frequencyPenalty = 0,\n logitBias,\n logprobs = false,\n topLogprobs,\n maxTokens,\n n = 1,\n presencePenalty = 0,\n responseFormat,\n seed,\n stop,\n stream: _stream = false,\n temperature = 1,\n topProbability: topP = 1,\n tools,\n toolChoice,\n user,\n onProgress,\n } = options;\n\n const messages = [\n ...history,\n {\n role: role as OpenAI.Chat.ChatCompletionRole,\n content: message,\n } as OpenAI.Chat.ChatCompletionSystemMessageParam,\n ];\n\n if (onProgress) {\n const stream = await this.openai.chat.completions.create({\n model,\n messages,\n stream: true,\n frequency_penalty: frequencyPenalty,\n logit_bias: logitBias,\n logprobs,\n top_logprobs: topLogprobs,\n ...buildTokenLimitRequestFields(model, maxTokens, temperature),\n n,\n presence_penalty: presencePenalty,\n response_format: responseFormat,\n seed,\n stop,\n top_p: topP,\n tools,\n tool_choice: toolChoice,\n user,\n });\n\n let fullContent = '';\n for await (const chunk of stream) {\n const content = chunk.choices[0]?.delta?.content || '';\n fullContent += content;\n onProgress(content);\n }\n\n return fullContent;\n }\n const response = await this.openai.chat.completions.create({\n model,\n messages,\n frequency_penalty: frequencyPenalty,\n logit_bias: logitBias,\n logprobs,\n top_logprobs: topLogprobs,\n ...buildTokenLimitRequestFields(model, maxTokens, temperature),\n n,\n presence_penalty: presencePenalty,\n response_format: responseFormat,\n seed,\n stop,\n stream: false,\n top_p: topP,\n tools,\n tool_choice: toolChoice,\n user,\n });\n\n const choice = response.choices[0];\n if (!choice || !choice.message || !choice.message.content) {\n throw new ApiError('Invalid response from OpenAI API: Missing content', {\n model,\n responseId: response.id,\n choices: response.choices?.length || 0,\n hasChoice: !!choice,\n hasMessage: !!choice?.message,\n hasContent: !!choice?.message?.content,\n });\n }\n return choice.message.content;\n }\n}\n\n/**\n * Options for getting an AI client with type information\n */\ntype GetAIClientOptions = AIClientOptions & {\n type?: AIProviderType;\n};\n\n/**\n * Factory function to create and initialize an appropriate AI client\n * Delegates to the modern getAI() factory for all provider types\n *\n * @param options - Client configuration options\n * @returns Promise resolving to an initialized AI client\n * @throws Error if client type is invalid\n */\nexport async function getAIClient(\n options: GetAIClientOptions,\n): Promise<AIClient> {\n // Delegate to modern factory for all providers\n const { getAI } = await import('./factory.js');\n return (await getAI(options as any)) as any;\n}\n","/**\n * Universal factory functions for creating AI provider instances\n * Works in both browser and Node.js environments\n */\n\nimport { loadEnvConfig, ValidationError } from '@happyvertical/utils';\n\nimport type { AIClientOptions } from './client';\nimport { createRateLimitedAI } from './rate-limit';\nimport { createObservedAI, normalizeBaseAIOptions } from './safety';\nimport type {\n AIInterface,\n AIProviderType,\n AnthropicOptions,\n BedrockOptions,\n BifrostOptions,\n ByteplusModelArkOptions,\n ClaudeCliOptions,\n GeminiOptions,\n GetAIOptions,\n HuggingFaceOptions,\n LiteLLMOptions,\n OllamaOptions,\n OpenAICompatVideoOptions,\n OpenAIOptions,\n Qwen3TTSOptions,\n SeevioOptions,\n TypeSafeOptions,\n} from './types';\nimport { AI_PROVIDER_TYPES } from './types';\n\n/**\n * Type guards for provider options\n */\n\n/**\n * Checks if the options are for OpenAI provider\n * @param options - The AI provider options to check\n * @returns True if options are for OpenAI provider (including default case)\n */\nfunction isOpenAIOptions(\n options: GetAIOptions | AIClientOptions,\n): options is OpenAIOptions {\n return !options.type || options.type === 'openai';\n}\n\n/**\n * Checks if the options are for LiteLLM provider\n * @param options - The AI provider options to check\n * @returns True if options are for LiteLLM provider\n */\nfunction isLiteLLMOptions(\n options: GetAIOptions | AIClientOptions,\n): options is LiteLLMOptions {\n return options.type === 'litellm';\n}\n\n/**\n * Checks if the options are for Bifrost provider\n * @param options - The AI provider options to check\n * @returns True if options are for Bifrost provider\n */\nfunction isBifrostOptions(\n options: GetAIOptions | AIClientOptions,\n): options is BifrostOptions {\n return options.type === 'bifrost';\n}\n\n/**\n * Checks if the options are for Ollama provider\n * @param options - The AI provider options to check\n * @returns True if options are for Ollama provider\n */\nfunction isOllamaOptions(\n options: GetAIOptions | AIClientOptions,\n): options is OllamaOptions {\n return options.type === 'ollama';\n}\n\n/**\n * Checks if the options are for Google Gemini provider\n * @param options - The AI provider options to check\n * @returns True if options are for Gemini provider\n */\nfunction isGeminiOptions(\n options: GetAIOptions | AIClientOptions,\n): options is GeminiOptions {\n return options.type === 'gemini';\n}\n\n/**\n * Checks if the options are for Anthropic Claude provider\n * @param options - The AI provider options to check\n * @returns True if options are for Anthropic provider\n */\nfunction isAnthropicOptions(\n options: GetAIOptions | AIClientOptions,\n): options is AnthropicOptions {\n return options.type === 'anthropic';\n}\n\n/**\n * Checks if the options are for Hugging Face provider\n * @param options - The AI provider options to check\n * @returns True if options are for Hugging Face provider\n */\nfunction isHuggingFaceOptions(\n options: GetAIOptions | AIClientOptions,\n): options is HuggingFaceOptions {\n return options.type === 'huggingface';\n}\n\n/**\n * Checks if the options are for AWS Bedrock provider\n * @param options - The AI provider options to check\n * @returns True if options are for Bedrock provider\n */\nfunction isBedrockOptions(\n options: GetAIOptions | AIClientOptions,\n): options is BedrockOptions {\n return options.type === 'bedrock';\n}\n\n/**\n * Checks if the options are for Claude CLI provider\n * @param options - The AI provider options to check\n * @returns True if options are for Claude CLI provider\n */\nfunction isClaudeCliOptions(\n options: GetAIOptions | AIClientOptions,\n): options is ClaudeCliOptions {\n return options.type === 'claude-cli';\n}\n\n/**\n * Checks if the options are for Qwen3-TTS provider\n * @param options - The AI provider options to check\n * @returns True if options are for Qwen3-TTS provider\n */\nfunction isQwen3TTSOptions(\n options: GetAIOptions | AIClientOptions,\n): options is Qwen3TTSOptions {\n return options.type === 'qwen3-tts';\n}\n\n/**\n * Checks if the options are for the OpenAI-compatible video-generation provider\n * @param options - The AI provider options to check\n * @returns True if options are for the openai-compat-video provider\n */\nfunction isOpenAICompatVideoOptions(\n options: GetAIOptions | AIClientOptions,\n): options is OpenAICompatVideoOptions {\n return options.type === 'openai-compat-video';\n}\n\n/**\n * Checks if the options are for the BytePlus ModelArk (Seedance) provider\n * @param options - The AI provider options to check\n * @returns True if options are for the byteplus-modelark provider\n */\nfunction isByteplusModelArkOptions(\n options: GetAIOptions | AIClientOptions,\n): options is ByteplusModelArkOptions {\n return options.type === 'byteplus-modelark';\n}\n\n/** Checks if options select Seevio's native Seedance task API. */\nfunction isSeevioOptions(\n options: GetAIOptions | AIClientOptions,\n): options is SeevioOptions {\n return options.type === 'seevio';\n}\n\n/** Checks if options select TypeSafe's System One decision API. */\nfunction isTypeSafeOptions(\n options: GetAIOptions | AIClientOptions,\n): options is TypeSafeOptions {\n return options.type === 'typesafe';\n}\n\n/**\n * Creates an AI provider instance based on the provided options.\n * Universal version that works in both browser and Node.js environments.\n *\n * Supports environment variable configuration using the pattern:\n * - HAVE_AI_PROVIDER → provider type (string)\n * - HAVE_AI_MODEL → defaultModel (string)\n * - HAVE_AI_TIMEOUT → timeout (number)\n * - HAVE_AI_MAX_RETRIES → maxRetries (number)\n * - HAVE_AI_API_KEY → apiKey (string) - fallback if provider-specific key not set\n * - HAVE_AI_BASE_URL → baseUrl (string)\n *\n * User-provided options always take precedence over environment variables.\n *\n * Accepts both GetAIOptions (provider-specific options with literal types)\n * and AIClientOptions (legacy interface with generic string type) for\n * backward compatibility with existing code.\n *\n * @param options - Configuration options for the AI provider. Can be GetAIOptions or AIClientOptions.\n * @returns Promise resolving to an AI provider instance that implements the AIInterface\n * @throws {ValidationError} When the provider type is unsupported or invalid\n *\n * @example\n * ```typescript\n * // Create OpenAI client with explicit options\n * const openai = await getAI({\n * type: 'openai',\n * apiKey: process.env.OPENAI_API_KEY!,\n * defaultModel: 'gpt-4o'\n * });\n *\n * // Or use environment variables (HAVE_AI_PROVIDER=openai, HAVE_AI_API_KEY=sk-...)\n * const client = await getAI({});\n *\n * // Create Anthropic client\n * const anthropic = await getAI({\n * type: 'anthropic',\n * apiKey: process.env.ANTHROPIC_API_KEY!,\n * defaultModel: 'claude-3-5-sonnet-20241022'\n * });\n *\n * // Works with AIClientOptions (legacy interface)\n * const clientOptions: AIClientOptions = { type: 'openai', apiKey: '...' };\n * const legacy = await getAI(clientOptions);\n * ```\n */\nexport async function getAI(\n options: GetAIOptions | AIClientOptions = {},\n): Promise<AIInterface> {\n // Load environment variables with user options taking precedence\n options = loadEnvConfig(options as Record<string, any>, {\n packageName: 'ai',\n schema: {\n provider: 'string',\n type: 'string', // Alias for provider\n model: 'string',\n defaultModel: 'string',\n timeout: 'number',\n maxRetries: 'number',\n apiKey: 'string',\n baseUrl: 'string',\n adminApiKey: 'string',\n adminBaseUrl: 'string',\n adminUrl: 'string',\n adminUser: 'string',\n adminUsername: 'string',\n adminPassword: 'string',\n },\n }) as GetAIOptions;\n\n // Normalize 'provider' field to 'type' for consistency\n if ('provider' in options && !options.type) {\n (options as any).type = (options as any).provider;\n }\n\n // Normalize 'model' field to 'defaultModel' for consistency\n if ('model' in options && !options.defaultModel) {\n (options as any).defaultModel = (options as any).model;\n }\n\n options = normalizeBaseAIOptions(options as GetAIOptions);\n\n let client: AIInterface;\n\n if (isOpenAIOptions(options)) {\n const { OpenAIProvider } = await import('./providers/openai.js');\n client = new OpenAIProvider(options);\n } else if (isLiteLLMOptions(options)) {\n const { LiteLLMProvider } = await import('./providers/litellm.js');\n client = new LiteLLMProvider(options);\n } else if (isBifrostOptions(options)) {\n const { BifrostProvider } = await import('./providers/bifrost.js');\n client = new BifrostProvider(options);\n } else if (isOllamaOptions(options)) {\n const { OllamaProvider } = await import('./providers/ollama.js');\n client = new OllamaProvider(options);\n } else if (isGeminiOptions(options)) {\n const { GeminiProvider } = await import('./providers/gemini.js');\n client = new GeminiProvider(options);\n } else if (isAnthropicOptions(options)) {\n const { AnthropicProvider } = await import('./providers/anthropic.js');\n client = new AnthropicProvider(options);\n } else if (isHuggingFaceOptions(options)) {\n const { HuggingFaceProvider } = await import('./providers/huggingface.js');\n client = new HuggingFaceProvider(options);\n } else if (isBedrockOptions(options)) {\n const { BedrockProvider } = await import('./providers/bedrock.js');\n client = new BedrockProvider(options);\n } else if (isClaudeCliOptions(options)) {\n const { ClaudeCliProvider } = await import('./providers/claude-cli.js');\n client = new ClaudeCliProvider(options);\n } else if (isQwen3TTSOptions(options)) {\n const { Qwen3TTSProvider } = await import('./providers/qwen-tts.js');\n client = new Qwen3TTSProvider(options);\n } else if (isOpenAICompatVideoOptions(options)) {\n const { OpenAICompatVideoProvider } = await import(\n './providers/openai-compat-video.js'\n );\n client = new OpenAICompatVideoProvider(options);\n } else if (isByteplusModelArkOptions(options)) {\n const { ByteplusModelArkProvider } = await import(\n './providers/byteplus-modelark.js'\n );\n client = new ByteplusModelArkProvider(options);\n } else if (isSeevioOptions(options)) {\n const { SeevioProvider } = await import('./providers/seevio.js');\n client = new SeevioProvider(options);\n } else if (isTypeSafeOptions(options)) {\n const { TypeSafeProvider } = await import('./providers/typesafe.js');\n client = new TypeSafeProvider(options);\n } else {\n throw new ValidationError('Unsupported AI provider type', {\n supportedTypes: [...AI_PROVIDER_TYPES],\n providedType: (options as any).type,\n });\n }\n\n return createObservedAI(createRateLimitedAI(client, options), options);\n}\n\n/**\n * Browser-compatible auto-detection of AI provider based on available credentials.\n * Does not rely on process.env, making it suitable for browser environments.\n *\n * @param options - Configuration options that may contain provider-specific credentials\n * @returns Promise resolving to an AI provider instance based on detected credentials\n * @throws {ValidationError} When no provider can be detected from the provided options\n *\n * @example\n * ```typescript\n * // Auto-detect OpenAI from apiKey\n * const client1 = await getAIAuto({\n * apiKey: 'sk-...', // Detected as OpenAI\n * defaultModel: 'gpt-4o'\n * });\n *\n * // Auto-detect Hugging Face from apiToken\n * const client2 = await getAIAuto({\n * apiToken: 'hf_...', // Detected as Hugging Face\n * model: 'microsoft/DialoGPT-medium'\n * });\n *\n * // Auto-detect AWS Bedrock from region and credentials\n * const client3 = await getAIAuto({\n * region: 'us-east-1',\n * credentials: {\n * accessKeyId: 'AKIA...',\n * secretAccessKey: 'xxx'\n * }\n * });\n * ```\n */\nexport async function getAIAuto(\n options: Record<string, any>,\n): Promise<AIInterface> {\n const baseUrl = String((options as any).baseUrl || '');\n const hasKeepAliveOption =\n 'keepAlive' in options && (options as any).keepAlive !== undefined;\n\n // Auto-detect provider based on available credentials\n if (\n /((?:localhost|127\\.0\\.0\\.1)(?::11434)?(?:\\/(?:api|v1))?|ollama(?:\\.com)?(?:\\/(?:api|v1))?)\\/?$/i.test(\n baseUrl,\n ) ||\n hasKeepAliveOption\n ) {\n return getAI({ ...options, type: 'ollama' } as OllamaOptions);\n }\n\n if (options.apiKey && !options.type) {\n // Default to OpenAI if apiKey is provided without explicit type\n return getAI({ ...options, type: 'openai' } as OpenAIOptions);\n }\n\n if (options.apiToken) {\n // Hugging Face uses apiToken\n return getAI({ ...options, type: 'huggingface' } as HuggingFaceOptions);\n }\n\n if (options.region && options.credentials) {\n // AWS Bedrock uses region and explicit credentials\n return getAI({ ...options, type: 'bedrock' } as BedrockOptions);\n }\n\n if (options.projectId || options.anthropicVersion) {\n // Try to detect based on provider-specific options\n if (options.anthropicVersion) {\n return getAI({ ...options, type: 'anthropic' } as AnthropicOptions);\n }\n if (options.projectId) {\n return getAI({ ...options, type: 'gemini' } as GeminiOptions);\n }\n }\n\n throw new ValidationError('Could not auto-detect AI provider from options', {\n hint: 'Please specify a \"type\" field in options or provide provider-specific credentials',\n supportedTypes: [...AI_PROVIDER_TYPES] as AIProviderType[],\n providedOptions: Object.keys(options),\n });\n}\n","import type { AIThread } from './thread';\n\n/**\n * Options for creating AI messages\n */\nexport interface AIMessageOptions {\n /**\n * Role of the message sender\n */\n role?: 'user' | 'assistant' | 'system';\n\n /**\n * Format for the AI response\n */\n responseFormat?: { type: 'text' | 'json_object' };\n}\n\n/**\n * Represents a message in an AI conversation\n */\nexport class AIMessage {\n /**\n * Original options used to create this message\n */\n protected options;\n\n /**\n * Name of the message sender\n */\n public name: string;\n\n /**\n * Content of the message\n */\n public content: string;\n\n /**\n * Role of the message sender in the conversation\n */\n public role: 'user' | 'assistant' | 'system';\n\n /**\n * Creates a new AI message\n *\n * @param options - Message configuration\n * @param options.role - Role of the message sender\n * @param options.content - Content of the message\n * @param options.name - Name of the message sender\n */\n constructor(options: {\n role: 'user' | 'assistant' | 'system';\n content: string;\n name: string;\n }) {\n this.options = options;\n this.role = options.role;\n this.content = options.content;\n this.name = options.name;\n }\n\n /**\n * Factory method to create a new AI message\n *\n * @param options - Message configuration\n * @param options.thread - Thread this message belongs to\n * @param options.role - Role of the message sender\n * @param options.content - Content of the message\n * @param options.name - Name of the message sender\n * @returns Promise resolving to a new AIMessage instance\n */\n static async create(options: {\n thread: AIThread;\n role: 'user' | 'assistant' | 'system';\n content: string;\n name: string;\n }) {\n return new AIMessage(options);\n }\n}\n","import type OpenAI from 'openai';\nimport { AIClient, type AIClientOptions } from './client';\nimport { AIMessage } from './message';\n\n/**\n * Options for creating an AI conversation thread\n */\nexport interface AIThreadOptions {\n /**\n * Options for the AI client to use in this thread\n */\n ai: AIClientOptions;\n}\n\n/**\n * Represents a conversation thread with an AI model\n * Manages messages, references, and conversation state\n */\nexport class AIThread {\n /**\n * AI client instance for this thread\n */\n protected ai!: AIClient;\n\n /**\n * Options used to configure this thread\n */\n protected options: AIThreadOptions;\n\n /**\n * Messages in this conversation thread\n */\n private messages: AIMessage[] = [];\n\n /**\n * Reference materials to include in the conversation context\n */\n private references: { [name: string]: string } = {};\n\n /**\n * Creates a new AI thread\n *\n * @param options - Thread configuration options\n */\n constructor(options: AIThreadOptions) {\n this.options = options;\n }\n\n /**\n * Factory method to create and initialize a new AI thread\n *\n * @param options - Thread configuration options\n * @returns Promise resolving to an initialized AIThread\n */\n static async create(options: AIThreadOptions) {\n const thread = new AIThread(options);\n await thread.initialize();\n return thread; // No need to add system message here, do it in addSystem\n }\n\n /**\n * Initializes the AI client for this thread\n */\n public async initialize() {\n this.ai = await AIClient.create(this.options.ai);\n }\n\n /**\n * Adds a system message to the conversation\n *\n * @param prompt - System message content\n * @returns Promise resolving to the created AIMessage\n */\n public async addSystem(prompt: string) {\n const message = await AIMessage.create({\n thread: this,\n role: 'system',\n name: 'system',\n content: prompt,\n });\n\n this.messages.push(message);\n return message;\n }\n\n /**\n * Adds a message to the conversation\n *\n * @param options - Message options\n * @param options.role - Role of the message sender\n * @param options.name - Optional name of the message sender\n * @param options.content - Content of the message\n * @returns Promise resolving to the created AIMessage\n */\n public async add(options: {\n role: 'user' | 'assistant' | 'system';\n name?: string;\n content: string;\n }) {\n const message = await AIMessage.create({\n thread: this,\n role: options.role,\n name: options.name || options.role, // Default name to role if not provided\n content: options.content,\n });\n\n this.messages.push(message);\n return message;\n }\n\n /**\n * Gets all messages in this thread\n *\n * @returns Array of AIMessage objects\n */\n public get(): AIMessage[] {\n return this.messages;\n }\n\n /**\n * Adds a reference to be included in the conversation context\n *\n * @param name - Name of the reference\n * @param body - Content of the reference\n */\n public addReference(name: string, body: string): void {\n this.references[name] = body;\n }\n\n /**\n * Assembles the conversation history for sending to the AI\n * Properly orders system message, references, and conversation messages\n *\n * @returns Array of message parameters formatted for the OpenAI API\n */\n public assembleHistory(): OpenAI.Chat.ChatCompletionMessageParam[] {\n const history: OpenAI.Chat.ChatCompletionMessageParam[] = [];\n\n // Add system message first\n const systemMessage = this.messages.find((m) => m.role === 'system');\n if (systemMessage) {\n history.push({\n role: systemMessage.role,\n content: systemMessage.content,\n });\n }\n\n // Add references as user messages (before other user/assistant messages)\n for (const name in this.references) {\n history.push({\n role: 'user',\n content: `Reference - ${name}:\\n${this.references[name]}`,\n });\n }\n\n // Add other messages\n this.messages\n .filter((m) => m.role !== 'system')\n .forEach((message) => {\n history.push({ role: message.role, content: message.content });\n });\n\n return history;\n }\n\n /**\n * Sends a prompt to the AI and gets a response\n *\n * @param prompt - Prompt message to send\n * @param options - Options for the AI response\n * @param options.responseFormat - Format for the AI to respond with\n * @returns Promise resolving to the AI response\n */\n public async do(\n prompt: string,\n options: {\n responseFormat?: 'html' | 'text' | 'json';\n } = {\n responseFormat: 'text',\n },\n ) {\n const { responseFormat } = options;\n const history = this.assembleHistory();\n\n // Get completion from AI with assembled history\n const response = await this.ai.textCompletion(prompt, {\n history,\n responseFormat: {\n type: responseFormat === 'json' ? 'json_object' : 'text',\n },\n });\n return response;\n }\n}\n","/**\n * @happyvertical/ai - A standardized interface for AI model interactions\n *\n * This package provides a unified interface for interacting with various AI models.\n * Supports multiple providers: OpenAI, LiteLLM, Ollama, Gemini, Anthropic,\n * Hugging Face, AWS Bedrock, Claude CLI, and Qwen3-TTS.\n *\n * Key components:\n * - getAI() - Factory function for creating AI provider instances\n * - AIInterface - Standardized interface for all AI providers\n * - Provider-specific implementations for each supported service\n */\n\n// Legacy exports for backward compatibility\nexport * from './shared/client';\nexport * from './shared/factory';\nexport { AIMessage as AIMessageClass } from './shared/message';\nexport {\n DEFAULT_AI_GENERATION_LIMITS,\n DEFAULT_AI_MAX_RETRIES,\n DEFAULT_AI_TIMEOUT_MS,\n} from './shared/safety';\nexport * from './shared/thread';\nexport * from './shared/types';\n\n/** @internal */\nexport const PACKAGE_VERSION_INITIALIZED = true;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"src-BUQUZK2M.js","names":[],"sources":["../../src/shared/providers/openai.ts","../../src/shared/client.ts","../../src/shared/factory.ts","../../src/shared/message.ts","../../src/shared/thread.ts","../../src/index.ts"],"sourcesContent":["/**\n * OpenAI provider implementation\n *\n * Provides a standardized interface for interacting with OpenAI's GPT models,\n * including chat completions, text completions, embeddings, and streaming responses.\n * Supports all major OpenAI features including function calling, vision models,\n * and custom fine-tuned models.\n */\n\nimport OpenAI from 'openai';\nimport { extractRetryAfterSeconds } from '../rate-limit';\nimport {\n normalizeBaseAIOptions,\n normalizeChatOptions,\n normalizeImageGenerationOptions,\n type PreparedRequestControls,\n prepareRequestControls,\n} from '../safety';\nimport type {\n AICapabilities,\n AIInterface,\n AIMessage,\n AIModel,\n AIResponse,\n BaseAIOptions,\n ChatOptions,\n CompletionOptions,\n ContentPart,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n MessageOptions,\n TokenUsage,\n TTSOptions,\n TTSResponse,\n VideoGenerationJob,\n VideoGenerationOptions,\n VideoGenerationResult,\n VideoGenerationStatusResult,\n Voice,\n VoiceCloneOptions,\n VoiceDesignOptions,\n VoiceListOptions,\n} from '../types';\nimport {\n AIError,\n AuthenticationError,\n ContentFilterError,\n ContextLengthError,\n ModelNotFoundError,\n RateLimitError,\n} from '../types';\nimport { emitUsage } from './usage';\n\n/**\n * Determines whether a model uses OpenAI's newer reasoning-model request\n * shape: `max_completion_tokens` in place of `max_tokens`, and no\n * `temperature` parameter at all (a non-default `temperature` is rejected\n * with a 400 error).\n *\n * This applies to the `gpt-5` family (`gpt-5`, `gpt-5-mini`, `gpt-5-nano`,\n * and future `gpt-5*` variants) and the `o`-series reasoning models (`o1`,\n * `o3`, `o4`, and their variants such as `o1-mini`, `o3-mini`, `o4-mini`).\n * See OpenAI's reasoning models guide and the Chat Completions API\n * reference for `max_completion_tokens`:\n * https://platform.openai.com/docs/guides/reasoning\n * https://platform.openai.com/docs/api-reference/chat/create\n *\n * The match is a conservative prefix/family check so future `gpt-5*` and\n * `o1`/`o3`/`o4` variants are covered without needing an allowlist update.\n * Models outside these families (`gpt-4.x`, `gpt-3.5`, etc.) are unaffected\n * and keep sending `max_tokens` and `temperature` as before.\n *\n * Gateway providers (`BifrostProvider`, some `LiteLLMProvider` deployments)\n * route with a vendor-prefixed model id, e.g. `openai/gpt-5-mini` — see\n * `BifrostProvider`'s own `defaultModel: 'openai/gpt-4o-mini'` convention in\n * `bifrost.ts`. Only the final path segment is matched against the family\n * checks so those gateway-routed ids are recognized the same as a bare\n * `gpt-5-mini`.\n *\n * Internal request-shaping helper: exported at module level only so it can\n * be unit-tested directly. It is not re-exported from the package entry\n * point (`src/index.ts`) and is not part of the package's public API.\n *\n * @param model - The model identifier (e.g. `gpt-5-mini`, `openai/gpt-5-mini`, `gpt-4.1-mini`)\n * @returns `true` when the model requires `max_completion_tokens` and rejects `temperature`\n */\nexport function usesCompletionTokenLimit(model: string | undefined): boolean {\n if (!model) return false;\n const normalized = model.toLowerCase();\n const lastSegment = normalized.slice(normalized.lastIndexOf('/') + 1);\n return lastSegment.startsWith('gpt-5') || /^o[134](-|$)/.test(lastSegment);\n}\n\n/**\n * Builds the output-token-limit and temperature fields for a chat/completion\n * request body, shaped for the given model per {@link usesCompletionTokenLimit}.\n *\n * For models that require it: sends `max_completion_tokens` and omits\n * `max_tokens`, and omits `temperature` entirely (never sends a default\n * value in its place). For all other models: sends `max_tokens` and\n * `temperature` unchanged. Fields whose source value is `undefined` are\n * omitted rather than included as `undefined` keys.\n *\n * Internal request-shaping helper: exported at module level only so it can\n * be unit-tested directly. It is not re-exported from the package entry\n * point (`src/index.ts`) and is not part of the package's public API.\n */\nexport function buildTokenLimitRequestFields(\n model: string,\n maxTokens: number | undefined,\n temperature: number | undefined,\n): {\n max_tokens?: number;\n max_completion_tokens?: number;\n temperature?: number;\n} {\n if (usesCompletionTokenLimit(model)) {\n return maxTokens === undefined ? {} : { max_completion_tokens: maxTokens };\n }\n return {\n ...(maxTokens === undefined ? {} : { max_tokens: maxTokens }),\n ...(temperature === undefined ? {} : { temperature }),\n };\n}\n\n/**\n * Shared profile for OpenAI-compatible providers\n */\nexport interface OpenAICompatibleProfile {\n providerLabel: string;\n providerName: string;\n defaultModel: string;\n capabilities: AICapabilities;\n describeModel(modelId: string): string;\n getContextLength(modelId: string): number;\n getModelCapabilities(modelId: string): string[];\n shouldIncludeModel(modelId: string): boolean;\n supportsFunctions(modelId: string): boolean;\n supportsVision(modelId: string): boolean;\n}\n\nconst OPENAI_PROFILE: OpenAICompatibleProfile = {\n providerLabel: 'OpenAI',\n providerName: 'openai',\n defaultModel: 'gpt-4o',\n capabilities: {\n chat: true,\n completion: true,\n embeddings: true,\n streaming: true,\n functions: true,\n vision: true,\n fineTuning: true,\n imageEmbeddings: true,\n imageGeneration: true,\n videoGeneration: false,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 128000,\n supportedOperations: [\n 'chat',\n 'completion',\n 'embedding',\n 'streaming',\n 'functions',\n 'vision',\n 'image_embedding',\n 'image_generation',\n ],\n },\n describeModel: (modelId) => `OpenAI model: ${modelId}`,\n getContextLength(modelId) {\n if (modelId.includes('gpt-4o')) return 128000;\n if (modelId.includes('gpt-4.1')) return 128000;\n if (modelId.includes('gpt-4-turbo')) return 128000;\n if (modelId.includes('gpt-4')) return 8192;\n if (modelId.includes('gpt-3.5-turbo')) return 16385;\n if (modelId.includes('text-embedding')) return 8192;\n return 4096;\n },\n getModelCapabilities(modelId) {\n const capabilities = ['text'];\n if (modelId.includes('gpt')) {\n capabilities.push('chat', 'functions');\n }\n if (\n modelId.includes('vision') ||\n modelId === 'gpt-4o' ||\n modelId.includes('gpt-4.1')\n ) {\n capabilities.push('vision');\n }\n if (modelId.includes('embedding')) {\n capabilities.push('embeddings');\n }\n return capabilities;\n },\n shouldIncludeModel(modelId) {\n return modelId.includes('gpt') || modelId.includes('text-embedding');\n },\n supportsFunctions(modelId) {\n return modelId.includes('gpt-4') || modelId.includes('gpt-3.5');\n },\n supportsVision(modelId) {\n return (\n modelId.includes('vision') ||\n modelId === 'gpt-4o' ||\n modelId.includes('gpt-4.1')\n );\n },\n};\n\nexport interface OpenAICompatibleOptions extends BaseAIOptions {\n type?: string;\n apiKey?: string;\n baseUrl?: string;\n organization?: string;\n}\n\n/**\n * OpenAI provider implementation that handles all interactions with OpenAI's API.\n * Supports GPT models, embeddings, function calling, streaming, and vision capabilities.\n */\nexport class OpenAIProvider implements AIInterface {\n private client: OpenAI;\n protected options: OpenAICompatibleOptions;\n protected readonly profile: OpenAICompatibleProfile;\n\n /**\n * Creates a new OpenAI provider instance\n * @param options - Configuration options for the OpenAI provider\n */\n constructor(\n options: OpenAICompatibleOptions,\n profile: OpenAICompatibleProfile = OPENAI_PROFILE,\n ) {\n this.profile = profile;\n this.options = normalizeBaseAIOptions({\n defaultModel: this.profile.defaultModel,\n ...options,\n });\n\n this.client = new OpenAI({\n apiKey: this.options.apiKey,\n baseURL: this.options.baseUrl,\n organization: this.options.organization,\n timeout: this.options.timeout,\n maxRetries: this.options.maxRetries,\n defaultHeaders: this.options.headers,\n });\n }\n\n /**\n * Generate a chat completion using OpenAI's chat models\n * @param messages - Array of conversation messages\n * @param options - Optional configuration for the chat completion\n * @returns Promise resolving to the AI response with content and metadata\n * @throws {AIError} When the API request fails or returns invalid data\n *\n * @example\n * ```typescript\n * const response = await provider.chat([\n * { role: 'system', content: 'You are a helpful assistant.' },\n * { role: 'user', content: 'What is the capital of France?' }\n * ], {\n * model: 'gpt-4o',\n * temperature: 0.7,\n * maxTokens: 150\n * });\n * console.log(response.content); // \"Paris is the capital of France.\"\n * ```\n */\n async chat(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): Promise<AIResponse> {\n const startTime = Date.now();\n let controls: PreparedRequestControls | undefined;\n try {\n const model =\n options.model || this.options.defaultModel || this.profile.defaultModel;\n options = normalizeChatOptions(\n this.options,\n options,\n this.profile.providerName,\n model,\n );\n controls = prepareRequestControls(this.options, options);\n const request = {\n model,\n messages: this.mapMessagesToOpenAI(messages),\n ...buildTokenLimitRequestFields(\n model,\n options.maxTokens,\n options.temperature,\n ),\n top_p: options.topP,\n n: options.n,\n stop: options.stop,\n frequency_penalty: options.frequencyPenalty,\n presence_penalty: options.presencePenalty,\n user: options.user,\n tools: options.tools?.map((tool) => ({\n type: 'function' as const,\n function: {\n name: tool.function.name,\n description: tool.function.description,\n parameters: tool.function.parameters,\n },\n })),\n tool_choice: this.mapToolChoice(options.toolChoice),\n response_format: options.responseFormat,\n seed: options.seed,\n stream: false,\n } as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming & {\n reasoning?: {\n effort?: string;\n max_tokens?: number;\n include_thoughts?: boolean;\n };\n };\n if (\n (this.profile.providerName === 'bifrost' ||\n this.profile.providerName === 'litellm') &&\n (options.reasoning?.maxTokens || 0) > 0\n ) {\n request.reasoning = {\n effort: options.reasoning?.effort,\n max_tokens: options.reasoning?.maxTokens,\n include_thoughts: options.reasoning?.includeThoughts,\n };\n }\n const response = await this.client.chat.completions.create(request, {\n signal: controls.signal,\n timeout: controls.timeout,\n });\n\n const choice = response.choices[0];\n if (!choice) {\n throw new AIError(\n `No choices returned from ${this.profile.providerLabel}`,\n 'NO_CHOICES',\n this.profile.providerName,\n );\n }\n\n const usage = this.mapUsage(response.usage);\n emitUsage(\n this.options,\n this.profile.providerName,\n 'chat',\n response.model || model,\n usage,\n startTime,\n options.usageTags,\n );\n\n return {\n content: choice.message.content || '',\n usage,\n model: response.model,\n finishReason: this.mapFinishReason(choice.finish_reason),\n toolCalls: choice.message.tool_calls\n ?.filter((call) => call.type === 'function')\n .map((call) => ({\n id: call.id,\n type: 'function' as const,\n function: {\n name: call.function.name,\n arguments: call.function.arguments,\n },\n })),\n };\n } catch (error) {\n if (controls?.didTimeout()) {\n throw new AIError(\n `AI request timed out after ${controls.timeout}ms`,\n 'AI_TIMEOUT',\n this.profile.providerName,\n options.model,\n );\n }\n if (options.signal?.aborted) {\n throw new AIError(\n 'AI request aborted by caller',\n 'AI_ABORTED',\n this.profile.providerName,\n options.model,\n );\n }\n throw this.mapError(error);\n } finally {\n controls?.cleanup();\n }\n }\n\n /**\n * Generate a text completion for a given prompt\n * @param prompt - The text prompt to complete\n * @param options - Optional configuration for the completion\n * @returns Promise resolving to the AI response\n * @throws {AIError} When the API request fails\n *\n * @example\n * ```typescript\n * const response = await provider.complete('The weather today is', {\n * model: 'gpt-4o',\n * maxTokens: 50,\n * temperature: 0.5\n * });\n * ```\n */\n async complete(\n prompt: string,\n options: CompletionOptions = {},\n ): Promise<AIResponse> {\n return this.chat([{ role: 'user', content: prompt }], {\n model: options.model,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n topP: options.topP,\n n: options.n,\n stop: options.stop,\n stream: options.stream,\n onProgress: options.onProgress,\n signal: options.signal,\n timeout: options.timeout,\n reasoning: options.reasoning,\n usageTags: options.usageTags,\n });\n }\n\n /**\n * Simple message interface for single-turn interactions with optional history\n *\n * @param text - The message text to send\n * @param options - Configuration options including history, model, etc.\n * @returns Promise resolving to the response content string\n *\n * @example\n * ```typescript\n * // Simple usage\n * const response = await provider.message('Hello!');\n *\n * // With options\n * const response = await provider.message('Analyze this', {\n * model: 'gpt-4o',\n * responseFormat: { type: 'json_object' }\n * });\n *\n * // With history\n * const response = await provider.message('What was my question?', {\n * history: [\n * { role: 'user', content: 'What is 2+2?' },\n * { role: 'assistant', content: '4' }\n * ]\n * });\n * ```\n */\n async message(text: string, options: MessageOptions = {}): Promise<string> {\n // Build messages array from history + current message\n const messages: AIMessage[] = [\n ...(options.history || []),\n { role: options.role || 'user', content: text },\n ];\n\n const response = await this.chat(messages, {\n model: options.model,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n topP: options.topP,\n stop: options.stop,\n stream: options.stream,\n frequencyPenalty: options.frequencyPenalty,\n presencePenalty: options.presencePenalty,\n responseFormat: options.responseFormat,\n seed: options.seed,\n tools: options.tools,\n toolChoice: options.toolChoice,\n onProgress: options.onProgress,\n signal: options.signal,\n timeout: options.timeout,\n reasoning: options.reasoning,\n usageTags: options.usageTags,\n });\n\n return response.content;\n }\n\n /**\n * Generate embeddings for the given text(s)\n * @param text - Single text string or array of texts to embed\n * @param options - Optional configuration for embeddings\n * @returns Promise resolving to embeddings response with vector arrays\n * @throws {AIError} When the API request fails\n *\n * @example\n * ```typescript\n * // Single text embedding\n * const response1 = await provider.embed('Hello world');\n * console.log(response1.embeddings[0]); // Array of numbers\n *\n * // Multiple text embeddings\n * const response2 = await provider.embed(['Text 1', 'Text 2']);\n * console.log(response2.embeddings.length); // 2\n * ```\n */\n async embed(\n text: string | string[],\n options: EmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n const startTime = Date.now();\n try {\n const model = options.model || 'text-embedding-3-small';\n const input = Array.isArray(text) ? text : [text];\n const response = await this.client.embeddings.create({\n model,\n input,\n encoding_format: options.encodingFormat,\n dimensions: options.dimensions,\n user: options.user,\n });\n\n const usage = this.mapUsage(response.usage);\n emitUsage(\n this.options,\n this.profile.providerName,\n 'embed',\n response.model || model,\n usage,\n startTime,\n options.usageTags,\n );\n\n return {\n embeddings: response.data.map((item) => item.embedding),\n usage,\n model: response.model,\n };\n } catch (error) {\n throw this.mapError(error);\n }\n }\n\n /**\n * Convert an image to a base64 data URL\n * @param image - Image as URL, base64 data URL, or Buffer\n * @returns base64 data URL string\n * @private\n */\n private async imageToBase64(\n image: string | Buffer,\n signal?: AbortSignal,\n ): Promise<string> {\n if (Buffer.isBuffer(image)) {\n return `data:image/png;base64,${image.toString('base64')}`;\n }\n if (image.startsWith('data:')) {\n return image; // Already base64 data URL\n }\n // It's a URL - fetch and convert\n const response = await fetch(image, { signal });\n if (!response.ok) {\n throw new AIError(\n `Failed to fetch image: ${response.status} ${response.statusText}`,\n 'IMAGE_FETCH_ERROR',\n this.profile.providerName,\n );\n }\n const arrayBuffer = await response.arrayBuffer();\n const buffer = Buffer.from(arrayBuffer);\n const contentType = response.headers.get('content-type') || 'image/png';\n return `data:${contentType};base64,${buffer.toString('base64')}`;\n }\n\n /**\n * Generate a text description of an image\n * @param image - Image as URL, base64 data URL, or Buffer\n * @param prompt - Custom prompt for description (optional)\n * @param options - Optional configuration\n * @returns Promise resolving to the description string\n *\n * @example\n * ```typescript\n * const description = await provider.describeImage('https://example.com/image.jpg');\n * ```\n */\n async describeImage(\n image: string | Buffer,\n prompt?: string,\n options: ImageDescriptionOptions = {},\n ): Promise<string> {\n let controls: PreparedRequestControls | undefined;\n try {\n const defaultPrompt =\n 'Describe this image for a search index. Include objects, mood, lighting, and any visible text.';\n\n controls = prepareRequestControls(this.options, options);\n const imageUrl = await this.imageToBase64(image, controls.signal);\n\n const response = await this.chat(\n [\n {\n role: 'user',\n content: [\n { type: 'text', text: prompt || defaultPrompt },\n {\n type: 'image_url',\n image_url: {\n url: imageUrl,\n detail: options.detail || 'auto',\n },\n },\n ],\n },\n ],\n {\n model:\n options.model ||\n this.options.defaultModel ||\n this.profile.defaultModel,\n maxTokens: options.maxTokens ?? 500,\n signal: controls.signal,\n timeout: controls.timeout,\n reasoning: options.reasoning,\n usageTags: options.usageTags,\n },\n );\n\n return response.content;\n } catch (error) {\n if (controls?.didTimeout()) {\n throw new AIError(\n `AI request timed out after ${controls.timeout}ms`,\n 'AI_TIMEOUT',\n this.profile.providerName,\n options.model,\n );\n }\n if (options.signal?.aborted) {\n throw new AIError(\n 'AI request aborted by caller',\n 'AI_ABORTED',\n this.profile.providerName,\n options.model,\n );\n }\n throw this.mapError(error);\n } finally {\n controls?.cleanup();\n }\n }\n\n /**\n * Generate embeddings for an image using describe-then-embed pattern\n * @param image - Image as URL, base64 data URL, or Buffer\n * @param options - Optional configuration for image embeddings\n * @returns Promise resolving to embeddings response\n *\n * @example\n * ```typescript\n * const embedding = await provider.embedImage('https://example.com/image.jpg');\n * ```\n */\n async embedImage(\n image: string | Buffer,\n options: ImageEmbeddingOptions = {},\n ): Promise<EmbeddingResponse> {\n try {\n // OpenAI doesn't have native image embeddings - use describe-then-embed\n const description = await this.describeImage(\n image,\n 'Describe this image in detail for semantic embedding. Include all visible objects, colors, textures, composition, text, people, actions, and overall scene context.',\n );\n\n return this.embed(description, {\n model: options.model || 'text-embedding-3-small',\n dimensions: options.dimensions,\n user: options.user,\n });\n } catch (error) {\n throw this.mapError(error);\n }\n }\n\n /**\n * Generate an image from a text prompt using DALL-E\n * @param prompt - Text description of the image to generate\n * @param options - Optional configuration for image generation\n * @returns Promise resolving to generated image(s)\n *\n * @example\n * ```typescript\n * const result = await provider.generateImage('A sunset over mountains');\n * fs.writeFileSync('image.png', result.images[0].data);\n * ```\n */\n async generateImage(\n prompt: string,\n options: ImageGenerationOptions = {},\n ): Promise<ImageGenerationResponse> {\n let controls: PreparedRequestControls | undefined;\n try {\n const model = options.model || 'dall-e-3';\n options = normalizeImageGenerationOptions(\n this.options,\n options,\n this.profile.providerName,\n model,\n );\n controls = prepareRequestControls(this.options, options);\n\n const requestParams: OpenAI.Images.ImageGenerateParams = {\n model,\n prompt,\n n: model === 'dall-e-3' ? 1 : options.n,\n size:\n (options.size as OpenAI.Images.ImageGenerateParams['size']) ||\n '1024x1024',\n response_format: options.outputFormat === 'url' ? 'url' : 'b64_json',\n };\n\n if (model === 'dall-e-3') {\n if (options.style) {\n requestParams.style = options.style;\n }\n if (options.quality) {\n requestParams.quality =\n options.quality as OpenAI.Images.ImageGenerateParams['quality'];\n }\n }\n\n const response = await this.client.images.generate(requestParams, {\n signal: controls.signal,\n timeout: controls.timeout,\n });\n\n const images = (response.data || []).map((item) => {\n let data: Buffer | string;\n const mimeType = 'image/png';\n\n if (options.outputFormat === 'url') {\n data = item.url || '';\n } else if (options.outputFormat === 'base64') {\n data = item.b64_json || '';\n } else {\n // Default: buffer\n data = Buffer.from(item.b64_json || '', 'base64');\n }\n\n return {\n data,\n mimeType,\n revisedPrompt: item.revised_prompt,\n };\n });\n\n return {\n images,\n model,\n };\n } catch (error) {\n if (controls?.didTimeout()) {\n throw new AIError(\n `AI request timed out after ${controls.timeout}ms`,\n 'AI_TIMEOUT',\n this.profile.providerName,\n options.model,\n );\n }\n if (options.signal?.aborted) {\n throw new AIError(\n 'AI request aborted by caller',\n 'AI_ABORTED',\n this.profile.providerName,\n options.model,\n );\n }\n throw this.mapError(error);\n } finally {\n controls?.cleanup();\n }\n }\n\n // ============================================================================\n // Video Generation Methods (Not supported - use gemini, byteplus-modelark,\n // or openai-compat-video provider)\n // ============================================================================\n\n async submitVideoGenerationJob(\n _options: VideoGenerationOptions,\n ): Promise<VideoGenerationJob> {\n throw new AIError(\n `Video generation is not supported by ${this.profile.providerLabel} provider. Use gemini, byteplus-modelark, or openai-compat-video provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n async getVideoGenerationJob(\n _handle: VideoGenerationJob,\n ): Promise<VideoGenerationStatusResult> {\n throw new AIError(\n `Video generation is not supported by ${this.profile.providerLabel} provider. Use gemini, byteplus-modelark, or openai-compat-video provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n async fetchVideoGenerationResult(\n _handle: VideoGenerationJob,\n ): Promise<VideoGenerationResult> {\n throw new AIError(\n `Video generation is not supported by ${this.profile.providerLabel} provider. Use gemini, byteplus-modelark, or openai-compat-video provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n async cancelVideoGenerationJob(_handle: VideoGenerationJob): Promise<void> {\n throw new AIError(\n `Video generation is not supported by ${this.profile.providerLabel} provider. Use gemini, byteplus-modelark, or openai-compat-video provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n async validateVideoGenerationAccess(): Promise<boolean> {\n throw new AIError(\n `Video generation is not supported by ${this.profile.providerLabel} provider. Use gemini, byteplus-modelark, or openai-compat-video provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n /**\n * Stream a chat completion response in real-time\n * @param messages - Array of conversation messages\n * @param options - Optional configuration for the chat completion\n * @yields Individual content chunks as they arrive\n * @throws {AIError} When the streaming request fails\n *\n * @example\n * ```typescript\n * for await (const chunk of provider.stream([\n * { role: 'user', content: 'Write a story about AI' }\n * ])) {\n * process.stdout.write(chunk);\n * }\n * ```\n */\n async *stream(\n messages: AIMessage[],\n options: ChatOptions = {},\n ): AsyncIterable<string> {\n const startTime = Date.now();\n let controls: PreparedRequestControls | undefined;\n try {\n const model =\n options.model || this.options.defaultModel || this.profile.defaultModel;\n options = normalizeChatOptions(\n this.options,\n options,\n this.profile.providerName,\n model,\n );\n controls = prepareRequestControls(this.options, options);\n const request = {\n model,\n messages: this.mapMessagesToOpenAI(messages),\n ...buildTokenLimitRequestFields(\n model,\n options.maxTokens,\n options.temperature,\n ),\n top_p: options.topP,\n stop: options.stop,\n frequency_penalty: options.frequencyPenalty,\n presence_penalty: options.presencePenalty,\n user: options.user,\n stream: true,\n } as OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming & {\n reasoning?: {\n effort?: string;\n max_tokens?: number;\n include_thoughts?: boolean;\n };\n };\n if (\n (this.profile.providerName === 'bifrost' ||\n this.profile.providerName === 'litellm') &&\n (options.reasoning?.maxTokens || 0) > 0\n ) {\n request.reasoning = {\n effort: options.reasoning?.effort,\n max_tokens: options.reasoning?.maxTokens,\n include_thoughts: options.reasoning?.includeThoughts,\n };\n }\n const stream = await this.client.chat.completions.create(request, {\n signal: controls.signal,\n timeout: controls.timeout,\n });\n\n for await (const chunk of stream) {\n const content = chunk.choices[0]?.delta?.content;\n if (content) {\n if (options.onProgress) {\n options.onProgress(content);\n }\n yield content;\n }\n }\n\n emitUsage(\n this.options,\n this.profile.providerName,\n 'stream',\n model,\n undefined,\n startTime,\n options.usageTags,\n );\n } catch (error) {\n if (controls?.didTimeout()) {\n throw new AIError(\n `AI request timed out after ${controls.timeout}ms`,\n 'AI_TIMEOUT',\n this.profile.providerName,\n options.model,\n );\n }\n if (options.signal?.aborted) {\n throw new AIError(\n 'AI request aborted by caller',\n 'AI_ABORTED',\n this.profile.providerName,\n options.model,\n );\n }\n throw this.mapError(error);\n } finally {\n controls?.cleanup();\n }\n }\n\n /**\n * Count the number of tokens in the given text\n * @param text - The text to count tokens for\n * @returns Promise resolving to the estimated token count\n *\n * @remarks\n * OpenAI doesn't provide a direct token counting API, so this is an approximation\n * based on the general rule of ~4 characters per token. For precise counting,\n * consider using a dedicated tokenizer library.\n *\n * @example\n * ```typescript\n * const count = await provider.countTokens('Hello, world!');\n * console.log(count); // Approximately 4 tokens\n * ```\n */\n async countTokens(text: string): Promise<number> {\n // OpenAI doesn't provide a direct token counting API\n // This is an approximation based on the general rule of ~4 characters per token\n return Math.ceil(text.length / 4);\n }\n\n /**\n * Get a list of available OpenAI models\n * @returns Promise resolving to an array of model information\n * @throws {AIError} When the API request fails\n *\n * @example\n * ```typescript\n * const models = await provider.getModels();\n * const gptModels = models.filter(m => m.id.includes('gpt'));\n * ```\n */\n async getModels(): Promise<AIModel[]> {\n try {\n const response = await this.client.models.list();\n return response.data\n .filter((model) => this.profile.shouldIncludeModel(model.id))\n .map((model) => ({\n id: model.id,\n name: model.id,\n description: this.profile.describeModel(model.id),\n contextLength: this.profile.getContextLength(model.id),\n capabilities: this.profile.getModelCapabilities(model.id),\n supportsFunctions: this.profile.supportsFunctions(model.id),\n supportsVision: this.profile.supportsVision(model.id),\n }));\n } catch (error) {\n throw this.mapError(error);\n }\n }\n\n /**\n * Get the capabilities supported by this OpenAI provider\n * @returns Promise resolving to provider capabilities\n *\n * @example\n * ```typescript\n * const caps = await provider.getCapabilities();\n * if (caps.functions) {\n * // Provider supports function calling\n * }\n * ```\n */\n async getCapabilities(): Promise<AICapabilities> {\n return { ...this.profile.capabilities };\n }\n\n // ============================================================================\n // TTS Methods (Not supported - use Qwen3-TTS provider)\n // ============================================================================\n\n async synthesizeSpeech(\n _text: string,\n _options?: TTSOptions,\n ): Promise<TTSResponse> {\n throw new AIError(\n `TTS is not supported by ${this.profile.providerLabel} provider. Use Qwen3-TTS provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n streamSpeech(_text: string, _options?: TTSOptions): AsyncIterable<Buffer> {\n const error = new AIError(\n `TTS streaming is not supported by ${this.profile.providerLabel} provider. Use Qwen3-TTS provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n return {\n [Symbol.asyncIterator]: () => ({\n next: () => Promise.reject(error),\n }),\n };\n }\n\n async cloneVoice(_options: VoiceCloneOptions): Promise<Voice> {\n throw new AIError(\n `Voice cloning is not supported by ${this.profile.providerLabel} provider. Use Qwen3-TTS provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n async designVoice(_options: VoiceDesignOptions): Promise<Voice> {\n throw new AIError(\n `Voice design is not supported by ${this.profile.providerLabel} provider. Use Qwen3-TTS provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n async getVoices(_options?: VoiceListOptions): Promise<Voice[]> {\n throw new AIError(\n `Voice listing is not supported by ${this.profile.providerLabel} provider. Use Qwen3-TTS provider.`,\n 'NOT_IMPLEMENTED',\n this.profile.providerName,\n );\n }\n\n /**\n * Maps internal AI messages to OpenAI's message format\n * @param messages - Array of internal AI messages\n * @returns Array of OpenAI-compatible message parameters\n * @private\n */\n private mapMessagesToOpenAI(\n messages: AIMessage[],\n ): OpenAI.Chat.ChatCompletionMessageParam[] {\n return messages.map((message) => {\n // Handle content that can be string or ContentPart[]\n let content: string | OpenAI.Chat.ChatCompletionContentPart[];\n\n if (typeof message.content === 'string') {\n content = message.content;\n } else {\n // Array of content parts - map to OpenAI format\n content = message.content.map((part: ContentPart) => {\n if (part.type === 'text') {\n return { type: 'text' as const, text: part.text };\n }\n // Image content part\n return {\n type: 'image_url' as const,\n image_url: {\n url: part.image_url.url,\n detail: part.image_url.detail,\n },\n };\n });\n }\n\n // Build message based on role and content\n const baseMessage = {\n role: message.role as OpenAI.Chat.ChatCompletionRole,\n content,\n };\n\n // Add optional fields based on role and availability\n if (\n message.name &&\n (message.role === 'system' ||\n message.role === 'user' ||\n message.role === 'function')\n ) {\n (baseMessage as any).name = message.name;\n }\n\n if (message.tool_calls && message.role === 'assistant') {\n (baseMessage as any).tool_calls = message.tool_calls;\n }\n\n return baseMessage as OpenAI.Chat.ChatCompletionMessageParam;\n });\n }\n\n /**\n * Maps internal tool choice format to OpenAI's tool choice format\n * @param toolChoice - Internal tool choice specification\n * @returns OpenAI-compatible tool choice option or undefined\n * @private\n */\n private mapToolChoice(\n toolChoice?:\n | 'auto'\n | 'none'\n | { type: 'function'; function: { name: string } },\n ): OpenAI.Chat.ChatCompletionToolChoiceOption | undefined {\n if (!toolChoice) return undefined;\n if (typeof toolChoice === 'string') return toolChoice;\n return {\n type: 'function',\n function: { name: toolChoice.function.name },\n };\n }\n\n /**\n * Maps OpenAI usage information to internal token usage format\n * @param usage - OpenAI usage object from API response\n * @returns Internal token usage object or undefined\n * @private\n */\n private mapUsage(\n usage?:\n | OpenAI.CompletionUsage\n | OpenAI.Completions.CompletionUsage\n | OpenAI.Embeddings.CreateEmbeddingResponse.Usage,\n ): TokenUsage | undefined {\n if (!usage) return undefined;\n return {\n promptTokens: usage.prompt_tokens || 0,\n completionTokens: (usage as any).completion_tokens || 0,\n totalTokens: usage.total_tokens || 0,\n };\n }\n\n /**\n * Maps OpenAI finish reason to internal finish reason format\n * @param reason - OpenAI finish reason from API response\n * @returns Internal finish reason\n * @private\n */\n private mapFinishReason(reason: string | null): AIResponse['finishReason'] {\n switch (reason) {\n case 'stop':\n return 'stop';\n case 'length':\n return 'length';\n case 'tool_calls':\n return 'tool_calls';\n case 'content_filter':\n return 'content_filter';\n default:\n return 'stop';\n }\n }\n\n /**\n * Gets the context length for a given OpenAI model\n * @param modelId - The OpenAI model identifier\n * @returns Maximum context length in tokens\n * @private\n */\n /**\n * Maps OpenAI API errors to internal AI error types\n * @param error - The error object from OpenAI API\n * @returns Appropriate internal AI error instance\n * @private\n */\n\n private mapError(error: unknown): AIError {\n if (error instanceof OpenAI.APIError) {\n switch (error.status) {\n case 401:\n return new AuthenticationError(this.profile.providerName);\n case 429: {\n return new RateLimitError(\n this.profile.providerName,\n extractRetryAfterSeconds(error),\n );\n }\n case 404:\n return new ModelNotFoundError(\n error.message,\n this.profile.providerName,\n );\n case 413:\n return new ContextLengthError(this.profile.providerName);\n default:\n if (error.message.includes('content_filter')) {\n return new ContentFilterError(this.profile.providerName);\n }\n return new AIError(\n error.message,\n 'API_ERROR',\n this.profile.providerName,\n );\n }\n }\n\n if (error instanceof AIError) {\n return error;\n }\n\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error occurred';\n return new AIError(\n errorMessage,\n 'UNKNOWN_ERROR',\n this.profile.providerName,\n );\n }\n}\n","import { ApiError, ValidationError } from '@happyvertical/utils';\nimport OpenAI from 'openai';\n\nimport type { AIMessageOptions } from './message';\nimport { buildTokenLimitRequestFields } from './providers/openai';\nimport type { AIProviderType, AIRateLimitOptions } from './types';\nimport { AI_PROVIDER_TYPES } from './types';\n\n/**\n * Common options for AI client configuration\n */\nexport interface AIClientOptions {\n /**\n * Type of AI client (e.g., 'openai')\n */\n type?: AIProviderType | string;\n\n /**\n * Response format for AI completions\n */\n responseFormat?: string;\n\n /**\n * API key for authentication\n */\n apiKey?: string;\n\n /**\n * Base URL for API requests\n */\n baseUrl?: string;\n\n /**\n * Admin API key for gateway providers that support provisioning.\n */\n adminApiKey?: string;\n\n /**\n * Admin base URL for gateway providers when it differs from `baseUrl`.\n */\n adminBaseUrl?: string;\n\n /**\n * Alias for adminBaseUrl.\n */\n adminUrl?: string;\n\n /**\n * Admin username for providers that use HTTP Basic auth.\n */\n adminUser?: string;\n\n /**\n * Admin username for providers that use HTTP Basic auth.\n */\n adminUsername?: string;\n\n /**\n * Admin password for providers that use HTTP Basic auth.\n */\n adminPassword?: string;\n\n /**\n * Custom admin headers for gateway providers.\n */\n adminHeaders?: Record<string, string>;\n\n /**\n * Optional shared pacing / retry configuration for getAI().\n */\n rateLimit?: AIRateLimitOptions;\n}\n\n/**\n * Interface defining required methods for AI clients\n */\nexport interface AIClientInterface {\n /**\n * Configuration options for this client\n */\n options: AIClientOptions;\n\n /**\n * Sends a message to the AI and gets a response\n *\n * @param text - Message text\n * @param options - Message options\n * @returns Promise resolving to the AI response\n */\n message(text: string, options: AIMessageOptions): Promise<unknown>;\n\n /**\n * Gets a text completion from the AI\n *\n * @param text - Input text for completion\n * @param options - Completion options\n * @returns Promise resolving to the completion result\n */\n textCompletion(text: string, options: AIMessageOptions): Promise<unknown>;\n}\n\n/**\n * Type guard to check if options are for OpenAI client\n *\n * @param options - Options to check\n * @returns True if options are valid for OpenAI client\n */\nfunction isOpenAIClientOptions(\n options: AIClientOptions,\n): options is OpenAIClientOptions {\n return options.type === 'openai' && 'apiKey' in options && !!options.apiKey;\n}\n\n/**\n * Type guard to check if value is an AI client instance\n *\n * @param value - Value to check\n * @returns True if value is an AI client instance\n */\nfunction isAIClientInstance(value: any): value is AIClient {\n return value instanceof AIClient;\n}\n\n/**\n * Options for AI text completion requests\n */\nexport interface AITextCompletionOptions {\n /**\n * Model identifier to use\n */\n model?: string;\n\n /**\n * Timeout in milliseconds\n */\n timeout?: number;\n\n /**\n * Role of the message sender\n */\n role?: OpenAI.Chat.ChatCompletionRole;\n\n /**\n * Previous messages in the conversation\n */\n history?: OpenAI.Chat.ChatCompletionMessageParam[];\n\n /**\n * Name of the message sender\n */\n name?: string;\n\n /**\n * Penalty for token frequency\n */\n frequencyPenalty?: number;\n\n /**\n * Token bias adjustments\n */\n logitBias?: Record<string, number>;\n\n /**\n * Whether to return log probabilities\n */\n logprobs?: boolean;\n\n /**\n * Number of top log probabilities to return\n */\n topLogprobs?: number;\n\n /**\n * Maximum tokens to generate\n */\n maxTokens?: number;\n\n /**\n * Number of completions to generate\n */\n n?: number;\n\n /**\n * Penalty for token presence\n */\n presencePenalty?: number;\n\n /**\n * Format for the response\n */\n responseFormat?: { type: 'text' | 'json_object' };\n\n /**\n * Random seed for deterministic results\n */\n seed?: number;\n\n /**\n * Sequences that stop generation\n */\n stop?: string | Array<string>;\n\n /**\n * Whether to stream responses\n */\n stream?: boolean;\n\n /**\n * Sampling temperature\n */\n temperature?: number;\n\n /**\n * Top-p sampling parameter\n */\n topProbability?: number;\n\n /**\n * Available tools for the model\n */\n tools?: Array<any>; // todo: figure out generic solution - Array<OpenAI.Chat.ChatCompletionTool>;\n\n /**\n * Tool selection behavior\n */\n toolChoice?:\n | 'none'\n | 'auto'\n | { type: 'function'; function: { name: string } };\n\n /**\n * User identifier\n */\n user?: string;\n\n /**\n * Callback for handling streaming responses\n */\n onProgress?: (partialMessage: string) => void;\n}\n\n/**\n * Base class for AI clients\n * Provides a common interface for different AI service providers\n */\nexport class AIClient {\n /**\n * Configuration options for this client\n */\n public options: AIClientOptions;\n\n /**\n * Creates a new AIClient\n *\n * @param options - Client configuration options\n */\n constructor(options: AIClientOptions) {\n this.options = options;\n }\n\n /**\n * Sends a message to the AI\n * Base implementation returns a placeholder response\n *\n * @param text - Message text\n * @param options - Message options\n * @returns Promise resolving to a placeholder response\n */\n public async message(\n _text: string,\n _options: AITextCompletionOptions = { role: 'user' },\n ) {\n return 'not a real ai message, this is the base class!';\n }\n\n /**\n * Factory method to create appropriate AI client based on options\n *\n * @param options - Client configuration options\n * @returns Promise resolving to an initialized AI client\n * @throws Error if client type is invalid\n */\n public static async create(\n options: AIClientOptions | AIClient,\n ): Promise<AIClient | OpenAIClient> {\n // If an AI client instance is passed, return it directly\n if (isAIClientInstance(options)) {\n return options;\n }\n\n // Cast to options since we know it's not an instance\n const clientOptions = options as AIClientOptions;\n\n if (isOpenAIClientOptions(clientOptions)) {\n return OpenAIClient.create(clientOptions);\n }\n\n // Delegate to modern factory for non-OpenAI providers\n const providedType = (clientOptions as any).type;\n if (providedType && providedType !== 'openai') {\n const { getAI } = await import('./factory.js');\n return (await getAI(clientOptions as any)) as any;\n }\n\n // Provide specific error messages for common issues\n if (providedType === 'openai') {\n throw new ValidationError(\n 'OpenAI API key is required but missing or empty',\n {\n supportedTypes: [...AI_PROVIDER_TYPES],\n providedType,\n hint: 'Set OPENAI_API_KEY environment variable or pass apiKey in options',\n },\n );\n }\n\n throw new ValidationError('Invalid client type specified', {\n supportedTypes: [...AI_PROVIDER_TYPES],\n providedType,\n });\n }\n\n /**\n * Gets a text completion from the AI\n * In base class, delegates to message method\n *\n * @param text - Input text for completion\n * @param options - Completion options\n * @returns Promise resolving to the completion result\n */\n public textCompletion(\n text: string,\n options: AITextCompletionOptions = {\n role: 'user',\n },\n ) {\n return this.message(text, options);\n }\n}\n\n/**\n * Creates an OpenAI client instance\n *\n * @param options - OpenAI configuration options\n * @returns Promise resolving to an OpenAI client\n */\nexport async function getOpenAI(options: {\n apiKey?: string;\n baseUrl?: string;\n}) {\n return new OpenAI({\n apiKey: options.apiKey,\n baseURL: options.baseUrl,\n });\n}\n\n/**\n * Options specific to OpenAI text completion requests\n */\nexport interface OpenAITextCompletionOptions {\n /**\n * Model identifier to use\n */\n model?: string;\n\n /**\n * Timeout in milliseconds\n */\n timeout?: number;\n\n /**\n * Role of the message sender\n */\n role?: OpenAI.Chat.ChatCompletionRole;\n\n /**\n * Previous messages in the conversation\n */\n history?: Array<OpenAI.Chat.ChatCompletionMessageParam>;\n\n /**\n * Name of the message sender\n */\n name?: string;\n\n /**\n * Penalty for token frequency\n */\n frequencyPenalty?: number;\n\n /**\n * Token bias adjustments\n */\n logitBias?: Record<string, number>;\n\n /**\n * Whether to return log probabilities\n */\n logprobs?: boolean;\n\n /**\n * Number of top log probabilities to return\n */\n topLogprobs?: number;\n\n /**\n * Maximum tokens to generate\n */\n maxTokens?: number;\n\n /**\n * Number of completions to generate\n */\n n?: number;\n\n /**\n * Penalty for token presence\n */\n presencePenalty?: number;\n\n /**\n * Format for the response\n */\n responseFormat?: { type: 'text' | 'json_object' };\n\n /**\n * Random seed for deterministic results\n */\n seed?: number;\n\n /**\n * Sequences that stop generation\n */\n stop?: string | Array<string>;\n\n /**\n * Whether to stream responses\n */\n stream?: boolean;\n\n /**\n * Sampling temperature\n */\n temperature?: number;\n\n /**\n * Top-p sampling parameter\n */\n topProbability?: number;\n\n /**\n * Available tools for the model\n */\n tools?: Array<OpenAI.Chat.ChatCompletionTool>;\n\n /**\n * Tool selection behavior\n */\n toolChoice?:\n | 'none'\n | 'auto'\n | { type: 'function'; function: { name: string } };\n\n /**\n * User identifier\n */\n user?: string;\n\n /**\n * Callback for handling streaming responses\n */\n onProgress?: (partialMessage: string) => void;\n}\n\n/**\n * Configuration options specific to OpenAI client\n */\nexport interface OpenAIClientOptions extends AIClientOptions {\n /**\n * OpenAI API key\n */\n apiKey?: string;\n\n /**\n * OpenAI API base URL\n */\n baseUrl?: string;\n}\n\n/**\n * Client implementation for the OpenAI API\n */\nexport class OpenAIClient extends AIClient {\n /**\n * OpenAI client instance\n */\n protected openai!: OpenAI;\n\n /**\n * Configuration options for this client\n */\n public options: OpenAIClientOptions;\n\n /**\n * Creates a new OpenAIClient\n *\n * @param options - OpenAI client configuration options\n */\n constructor(options: OpenAIClientOptions) {\n super(options);\n this.options = options;\n }\n\n /**\n * Sends a message to OpenAI\n *\n * @param text - Message text\n * @param options - Message options\n * @returns Promise resolving to the OpenAI response\n */\n public async message(\n text: string,\n options: AIMessageOptions = { role: 'user' },\n ) {\n const response = await this.textCompletion(text, options);\n return response;\n }\n\n /**\n * Factory method to create and initialize an OpenAIClient\n *\n * @param options - OpenAI client configuration options\n * @returns Promise resolving to an initialized OpenAIClient\n */\n public static async create(\n options: OpenAIClientOptions,\n ): Promise<OpenAIClient> {\n const client = new OpenAIClient(options);\n await client.initialize();\n return client;\n }\n\n /**\n * Initializes the OpenAI client\n */\n protected async initialize() {\n this.openai = new OpenAI({\n apiKey: this.options.apiKey,\n baseURL: this.options.baseUrl,\n });\n }\n\n /**\n * Sends a text completion request to the OpenAI API\n *\n * @param message - The message to send\n * @param options - Configuration options for the completion request\n * @returns Promise resolving to the completion text\n * @throws Error if the OpenAI API response is invalid\n */\n public async textCompletion(\n message: string,\n options: OpenAITextCompletionOptions = {},\n ): Promise<string> {\n const {\n model = 'gpt-4o',\n role = 'user',\n history = [],\n name: _name,\n frequencyPenalty = 0,\n logitBias,\n logprobs = false,\n topLogprobs,\n maxTokens,\n n = 1,\n presencePenalty = 0,\n responseFormat,\n seed,\n stop,\n stream: _stream = false,\n temperature = 1,\n topProbability: topP = 1,\n tools,\n toolChoice,\n user,\n onProgress,\n } = options;\n\n const messages = [\n ...history,\n {\n role: role as OpenAI.Chat.ChatCompletionRole,\n content: message,\n } as OpenAI.Chat.ChatCompletionSystemMessageParam,\n ];\n\n if (onProgress) {\n const stream = await this.openai.chat.completions.create({\n model,\n messages,\n stream: true,\n frequency_penalty: frequencyPenalty,\n logit_bias: logitBias,\n logprobs,\n top_logprobs: topLogprobs,\n ...buildTokenLimitRequestFields(model, maxTokens, temperature),\n n,\n presence_penalty: presencePenalty,\n response_format: responseFormat,\n seed,\n stop,\n top_p: topP,\n tools,\n tool_choice: toolChoice,\n user,\n });\n\n let fullContent = '';\n for await (const chunk of stream) {\n const content = chunk.choices[0]?.delta?.content || '';\n fullContent += content;\n onProgress(content);\n }\n\n return fullContent;\n }\n const response = await this.openai.chat.completions.create({\n model,\n messages,\n frequency_penalty: frequencyPenalty,\n logit_bias: logitBias,\n logprobs,\n top_logprobs: topLogprobs,\n ...buildTokenLimitRequestFields(model, maxTokens, temperature),\n n,\n presence_penalty: presencePenalty,\n response_format: responseFormat,\n seed,\n stop,\n stream: false,\n top_p: topP,\n tools,\n tool_choice: toolChoice,\n user,\n });\n\n const choice = response.choices[0];\n if (!choice || !choice.message || !choice.message.content) {\n throw new ApiError('Invalid response from OpenAI API: Missing content', {\n model,\n responseId: response.id,\n choices: response.choices?.length || 0,\n hasChoice: !!choice,\n hasMessage: !!choice?.message,\n hasContent: !!choice?.message?.content,\n });\n }\n return choice.message.content;\n }\n}\n\n/**\n * Options for getting an AI client with type information\n */\ntype GetAIClientOptions = AIClientOptions & {\n type?: AIProviderType;\n};\n\n/**\n * Factory function to create and initialize an appropriate AI client\n * Delegates to the modern getAI() factory for all provider types\n *\n * @param options - Client configuration options\n * @returns Promise resolving to an initialized AI client\n * @throws Error if client type is invalid\n */\nexport async function getAIClient(\n options: GetAIClientOptions,\n): Promise<AIClient> {\n // Delegate to modern factory for all providers\n const { getAI } = await import('./factory.js');\n return (await getAI(options as any)) as any;\n}\n","/**\n * Universal factory functions for creating AI provider instances\n * Works in both browser and Node.js environments\n */\n\nimport { loadEnvConfig, ValidationError } from '@happyvertical/utils';\n\nimport type { AIClientOptions } from './client';\nimport { createRateLimitedAI } from './rate-limit';\nimport { createObservedAI, normalizeBaseAIOptions } from './safety';\nimport type {\n AIInterface,\n AIProviderType,\n AnthropicOptions,\n BedrockOptions,\n BifrostOptions,\n ByteplusModelArkOptions,\n ClaudeCliOptions,\n GeminiOptions,\n GetAIOptions,\n HuggingFaceOptions,\n LiteLLMOptions,\n OllamaOptions,\n OpenAICompatVideoOptions,\n OpenAIOptions,\n Qwen3TTSOptions,\n SeevioOptions,\n TypeSafeOptions,\n} from './types';\nimport { AI_PROVIDER_TYPES } from './types';\n\n/**\n * Type guards for provider options\n */\n\n/**\n * Checks if the options are for OpenAI provider\n * @param options - The AI provider options to check\n * @returns True if options are for OpenAI provider (including default case)\n */\nfunction isOpenAIOptions(\n options: GetAIOptions | AIClientOptions,\n): options is OpenAIOptions {\n return !options.type || options.type === 'openai';\n}\n\n/**\n * Checks if the options are for LiteLLM provider\n * @param options - The AI provider options to check\n * @returns True if options are for LiteLLM provider\n */\nfunction isLiteLLMOptions(\n options: GetAIOptions | AIClientOptions,\n): options is LiteLLMOptions {\n return options.type === 'litellm';\n}\n\n/**\n * Checks if the options are for Bifrost provider\n * @param options - The AI provider options to check\n * @returns True if options are for Bifrost provider\n */\nfunction isBifrostOptions(\n options: GetAIOptions | AIClientOptions,\n): options is BifrostOptions {\n return options.type === 'bifrost';\n}\n\n/**\n * Checks if the options are for Ollama provider\n * @param options - The AI provider options to check\n * @returns True if options are for Ollama provider\n */\nfunction isOllamaOptions(\n options: GetAIOptions | AIClientOptions,\n): options is OllamaOptions {\n return options.type === 'ollama';\n}\n\n/**\n * Checks if the options are for Google Gemini provider\n * @param options - The AI provider options to check\n * @returns True if options are for Gemini provider\n */\nfunction isGeminiOptions(\n options: GetAIOptions | AIClientOptions,\n): options is GeminiOptions {\n return options.type === 'gemini';\n}\n\n/**\n * Checks if the options are for Anthropic Claude provider\n * @param options - The AI provider options to check\n * @returns True if options are for Anthropic provider\n */\nfunction isAnthropicOptions(\n options: GetAIOptions | AIClientOptions,\n): options is AnthropicOptions {\n return options.type === 'anthropic';\n}\n\n/**\n * Checks if the options are for Hugging Face provider\n * @param options - The AI provider options to check\n * @returns True if options are for Hugging Face provider\n */\nfunction isHuggingFaceOptions(\n options: GetAIOptions | AIClientOptions,\n): options is HuggingFaceOptions {\n return options.type === 'huggingface';\n}\n\n/**\n * Checks if the options are for AWS Bedrock provider\n * @param options - The AI provider options to check\n * @returns True if options are for Bedrock provider\n */\nfunction isBedrockOptions(\n options: GetAIOptions | AIClientOptions,\n): options is BedrockOptions {\n return options.type === 'bedrock';\n}\n\n/**\n * Checks if the options are for Claude CLI provider\n * @param options - The AI provider options to check\n * @returns True if options are for Claude CLI provider\n */\nfunction isClaudeCliOptions(\n options: GetAIOptions | AIClientOptions,\n): options is ClaudeCliOptions {\n return options.type === 'claude-cli';\n}\n\n/**\n * Checks if the options are for Qwen3-TTS provider\n * @param options - The AI provider options to check\n * @returns True if options are for Qwen3-TTS provider\n */\nfunction isQwen3TTSOptions(\n options: GetAIOptions | AIClientOptions,\n): options is Qwen3TTSOptions {\n return options.type === 'qwen3-tts';\n}\n\n/**\n * Checks if the options are for the OpenAI-compatible video-generation provider\n * @param options - The AI provider options to check\n * @returns True if options are for the openai-compat-video provider\n */\nfunction isOpenAICompatVideoOptions(\n options: GetAIOptions | AIClientOptions,\n): options is OpenAICompatVideoOptions {\n return options.type === 'openai-compat-video';\n}\n\n/**\n * Checks if the options are for the BytePlus ModelArk (Seedance) provider\n * @param options - The AI provider options to check\n * @returns True if options are for the byteplus-modelark provider\n */\nfunction isByteplusModelArkOptions(\n options: GetAIOptions | AIClientOptions,\n): options is ByteplusModelArkOptions {\n return options.type === 'byteplus-modelark';\n}\n\n/** Checks if options select Seevio's native Seedance task API. */\nfunction isSeevioOptions(\n options: GetAIOptions | AIClientOptions,\n): options is SeevioOptions {\n return options.type === 'seevio';\n}\n\n/** Checks if options select TypeSafe's System One decision API. */\nfunction isTypeSafeOptions(\n options: GetAIOptions | AIClientOptions,\n): options is TypeSafeOptions {\n return options.type === 'typesafe';\n}\n\n/**\n * Creates an AI provider instance based on the provided options.\n * Universal version that works in both browser and Node.js environments.\n *\n * Supports environment variable configuration using the pattern:\n * - HAVE_AI_PROVIDER → provider type (string)\n * - HAVE_AI_MODEL → defaultModel (string)\n * - HAVE_AI_TIMEOUT → timeout (number)\n * - HAVE_AI_MAX_RETRIES → maxRetries (number)\n * - HAVE_AI_API_KEY → apiKey (string) - fallback if provider-specific key not set\n * - HAVE_AI_BASE_URL → baseUrl (string)\n *\n * User-provided options always take precedence over environment variables.\n *\n * Accepts both GetAIOptions (provider-specific options with literal types)\n * and AIClientOptions (legacy interface with generic string type) for\n * backward compatibility with existing code.\n *\n * @param options - Configuration options for the AI provider. Can be GetAIOptions or AIClientOptions.\n * @returns Promise resolving to an AI provider instance that implements the AIInterface\n * @throws {ValidationError} When the provider type is unsupported or invalid\n *\n * @example\n * ```typescript\n * // Create OpenAI client with explicit options\n * const openai = await getAI({\n * type: 'openai',\n * apiKey: process.env.OPENAI_API_KEY!,\n * defaultModel: 'gpt-4o'\n * });\n *\n * // Or use environment variables (HAVE_AI_PROVIDER=openai, HAVE_AI_API_KEY=sk-...)\n * const client = await getAI({});\n *\n * // Create Anthropic client\n * const anthropic = await getAI({\n * type: 'anthropic',\n * apiKey: process.env.ANTHROPIC_API_KEY!,\n * defaultModel: 'claude-3-5-sonnet-20241022'\n * });\n *\n * // Works with AIClientOptions (legacy interface)\n * const clientOptions: AIClientOptions = { type: 'openai', apiKey: '...' };\n * const legacy = await getAI(clientOptions);\n * ```\n */\nexport async function getAI(\n options: GetAIOptions | AIClientOptions = {},\n): Promise<AIInterface> {\n // Load environment variables with user options taking precedence\n options = loadEnvConfig(options as Record<string, any>, {\n packageName: 'ai',\n schema: {\n provider: 'string',\n type: 'string', // Alias for provider\n model: 'string',\n defaultModel: 'string',\n timeout: 'number',\n maxRetries: 'number',\n apiKey: 'string',\n baseUrl: 'string',\n adminApiKey: 'string',\n adminBaseUrl: 'string',\n adminUrl: 'string',\n adminUser: 'string',\n adminUsername: 'string',\n adminPassword: 'string',\n },\n }) as GetAIOptions;\n\n // Normalize 'provider' field to 'type' for consistency\n if ('provider' in options && !options.type) {\n (options as any).type = (options as any).provider;\n }\n\n // Normalize 'model' field to 'defaultModel' for consistency\n if ('model' in options && !options.defaultModel) {\n (options as any).defaultModel = (options as any).model;\n }\n\n options = normalizeBaseAIOptions(options as GetAIOptions);\n\n let client: AIInterface;\n\n if (isOpenAIOptions(options)) {\n const { OpenAIProvider } = await import('./providers/openai.js');\n client = new OpenAIProvider(options);\n } else if (isLiteLLMOptions(options)) {\n const { LiteLLMProvider } = await import('./providers/litellm.js');\n client = new LiteLLMProvider(options);\n } else if (isBifrostOptions(options)) {\n const { BifrostProvider } = await import('./providers/bifrost.js');\n client = new BifrostProvider(options);\n } else if (isOllamaOptions(options)) {\n const { OllamaProvider } = await import('./providers/ollama.js');\n client = new OllamaProvider(options);\n } else if (isGeminiOptions(options)) {\n const { GeminiProvider } = await import('./providers/gemini.js');\n client = new GeminiProvider(options);\n } else if (isAnthropicOptions(options)) {\n const { AnthropicProvider } = await import('./providers/anthropic.js');\n client = new AnthropicProvider(options);\n } else if (isHuggingFaceOptions(options)) {\n const { HuggingFaceProvider } = await import('./providers/huggingface.js');\n client = new HuggingFaceProvider(options);\n } else if (isBedrockOptions(options)) {\n const { BedrockProvider } = await import('./providers/bedrock.js');\n client = new BedrockProvider(options);\n } else if (isClaudeCliOptions(options)) {\n const { ClaudeCliProvider } = await import('./providers/claude-cli.js');\n client = new ClaudeCliProvider(options);\n } else if (isQwen3TTSOptions(options)) {\n const { Qwen3TTSProvider } = await import('./providers/qwen-tts.js');\n client = new Qwen3TTSProvider(options);\n } else if (isOpenAICompatVideoOptions(options)) {\n const { OpenAICompatVideoProvider } = await import(\n './providers/openai-compat-video.js'\n );\n client = new OpenAICompatVideoProvider(options);\n } else if (isByteplusModelArkOptions(options)) {\n const { ByteplusModelArkProvider } = await import(\n './providers/byteplus-modelark.js'\n );\n client = new ByteplusModelArkProvider(options);\n } else if (isSeevioOptions(options)) {\n const { SeevioProvider } = await import('./providers/seevio.js');\n client = new SeevioProvider(options);\n } else if (isTypeSafeOptions(options)) {\n const { TypeSafeProvider } = await import('./providers/typesafe.js');\n client = new TypeSafeProvider(options);\n } else {\n throw new ValidationError('Unsupported AI provider type', {\n supportedTypes: [...AI_PROVIDER_TYPES],\n providedType: (options as any).type,\n });\n }\n\n return createObservedAI(createRateLimitedAI(client, options), options);\n}\n\n/**\n * Browser-compatible auto-detection of AI provider based on available credentials.\n * Does not rely on process.env, making it suitable for browser environments.\n *\n * @param options - Configuration options that may contain provider-specific credentials\n * @returns Promise resolving to an AI provider instance based on detected credentials\n * @throws {ValidationError} When no provider can be detected from the provided options\n *\n * @example\n * ```typescript\n * // Auto-detect OpenAI from apiKey\n * const client1 = await getAIAuto({\n * apiKey: 'sk-...', // Detected as OpenAI\n * defaultModel: 'gpt-4o'\n * });\n *\n * // Auto-detect Hugging Face from apiToken\n * const client2 = await getAIAuto({\n * apiToken: 'hf_...', // Detected as Hugging Face\n * model: 'microsoft/DialoGPT-medium'\n * });\n *\n * // Auto-detect AWS Bedrock from region and credentials\n * const client3 = await getAIAuto({\n * region: 'us-east-1',\n * credentials: {\n * accessKeyId: 'AKIA...',\n * secretAccessKey: 'xxx'\n * }\n * });\n * ```\n */\nexport async function getAIAuto(\n options: Record<string, any>,\n): Promise<AIInterface> {\n const baseUrl = String((options as any).baseUrl || '');\n const hasKeepAliveOption =\n 'keepAlive' in options && (options as any).keepAlive !== undefined;\n\n // Auto-detect provider based on available credentials\n if (\n /((?:localhost|127\\.0\\.0\\.1)(?::11434)?(?:\\/(?:api|v1))?|ollama(?:\\.com)?(?:\\/(?:api|v1))?)\\/?$/i.test(\n baseUrl,\n ) ||\n hasKeepAliveOption\n ) {\n return getAI({ ...options, type: 'ollama' } as OllamaOptions);\n }\n\n if (options.apiKey && !options.type) {\n // Default to OpenAI if apiKey is provided without explicit type\n return getAI({ ...options, type: 'openai' } as OpenAIOptions);\n }\n\n if (options.apiToken) {\n // Hugging Face uses apiToken\n return getAI({ ...options, type: 'huggingface' } as HuggingFaceOptions);\n }\n\n if (options.region && options.credentials) {\n // AWS Bedrock uses region and explicit credentials\n return getAI({ ...options, type: 'bedrock' } as BedrockOptions);\n }\n\n if (options.projectId || options.anthropicVersion) {\n // Try to detect based on provider-specific options\n if (options.anthropicVersion) {\n return getAI({ ...options, type: 'anthropic' } as AnthropicOptions);\n }\n if (options.projectId) {\n return getAI({ ...options, type: 'gemini' } as GeminiOptions);\n }\n }\n\n throw new ValidationError('Could not auto-detect AI provider from options', {\n hint: 'Please specify a \"type\" field in options or provide provider-specific credentials',\n supportedTypes: [...AI_PROVIDER_TYPES] as AIProviderType[],\n providedOptions: Object.keys(options),\n });\n}\n","import type { AIThread } from './thread';\n\n/**\n * Options for creating AI messages\n */\nexport interface AIMessageOptions {\n /**\n * Role of the message sender\n */\n role?: 'user' | 'assistant' | 'system';\n\n /**\n * Format for the AI response\n */\n responseFormat?: { type: 'text' | 'json_object' };\n}\n\n/**\n * Represents a message in an AI conversation\n */\nexport class AIMessage {\n /**\n * Original options used to create this message\n */\n protected options;\n\n /**\n * Name of the message sender\n */\n public name: string;\n\n /**\n * Content of the message\n */\n public content: string;\n\n /**\n * Role of the message sender in the conversation\n */\n public role: 'user' | 'assistant' | 'system';\n\n /**\n * Creates a new AI message\n *\n * @param options - Message configuration\n * @param options.role - Role of the message sender\n * @param options.content - Content of the message\n * @param options.name - Name of the message sender\n */\n constructor(options: {\n role: 'user' | 'assistant' | 'system';\n content: string;\n name: string;\n }) {\n this.options = options;\n this.role = options.role;\n this.content = options.content;\n this.name = options.name;\n }\n\n /**\n * Factory method to create a new AI message\n *\n * @param options - Message configuration\n * @param options.thread - Thread this message belongs to\n * @param options.role - Role of the message sender\n * @param options.content - Content of the message\n * @param options.name - Name of the message sender\n * @returns Promise resolving to a new AIMessage instance\n */\n static async create(options: {\n thread: AIThread;\n role: 'user' | 'assistant' | 'system';\n content: string;\n name: string;\n }) {\n return new AIMessage(options);\n }\n}\n","import type OpenAI from 'openai';\nimport { AIClient, type AIClientOptions } from './client';\nimport { AIMessage } from './message';\n\n/**\n * Options for creating an AI conversation thread\n */\nexport interface AIThreadOptions {\n /**\n * Options for the AI client to use in this thread\n */\n ai: AIClientOptions;\n}\n\n/**\n * Represents a conversation thread with an AI model\n * Manages messages, references, and conversation state\n */\nexport class AIThread {\n /**\n * AI client instance for this thread\n */\n protected ai!: AIClient;\n\n /**\n * Options used to configure this thread\n */\n protected options: AIThreadOptions;\n\n /**\n * Messages in this conversation thread\n */\n private messages: AIMessage[] = [];\n\n /**\n * Reference materials to include in the conversation context\n */\n private references: { [name: string]: string } = {};\n\n /**\n * Creates a new AI thread\n *\n * @param options - Thread configuration options\n */\n constructor(options: AIThreadOptions) {\n this.options = options;\n }\n\n /**\n * Factory method to create and initialize a new AI thread\n *\n * @param options - Thread configuration options\n * @returns Promise resolving to an initialized AIThread\n */\n static async create(options: AIThreadOptions) {\n const thread = new AIThread(options);\n await thread.initialize();\n return thread; // No need to add system message here, do it in addSystem\n }\n\n /**\n * Initializes the AI client for this thread\n */\n public async initialize() {\n this.ai = await AIClient.create(this.options.ai);\n }\n\n /**\n * Adds a system message to the conversation\n *\n * @param prompt - System message content\n * @returns Promise resolving to the created AIMessage\n */\n public async addSystem(prompt: string) {\n const message = await AIMessage.create({\n thread: this,\n role: 'system',\n name: 'system',\n content: prompt,\n });\n\n this.messages.push(message);\n return message;\n }\n\n /**\n * Adds a message to the conversation\n *\n * @param options - Message options\n * @param options.role - Role of the message sender\n * @param options.name - Optional name of the message sender\n * @param options.content - Content of the message\n * @returns Promise resolving to the created AIMessage\n */\n public async add(options: {\n role: 'user' | 'assistant' | 'system';\n name?: string;\n content: string;\n }) {\n const message = await AIMessage.create({\n thread: this,\n role: options.role,\n name: options.name || options.role, // Default name to role if not provided\n content: options.content,\n });\n\n this.messages.push(message);\n return message;\n }\n\n /**\n * Gets all messages in this thread\n *\n * @returns Array of AIMessage objects\n */\n public get(): AIMessage[] {\n return this.messages;\n }\n\n /**\n * Adds a reference to be included in the conversation context\n *\n * @param name - Name of the reference\n * @param body - Content of the reference\n */\n public addReference(name: string, body: string): void {\n this.references[name] = body;\n }\n\n /**\n * Assembles the conversation history for sending to the AI\n * Properly orders system message, references, and conversation messages\n *\n * @returns Array of message parameters formatted for the OpenAI API\n */\n public assembleHistory(): OpenAI.Chat.ChatCompletionMessageParam[] {\n const history: OpenAI.Chat.ChatCompletionMessageParam[] = [];\n\n // Add system message first\n const systemMessage = this.messages.find((m) => m.role === 'system');\n if (systemMessage) {\n history.push({\n role: systemMessage.role,\n content: systemMessage.content,\n });\n }\n\n // Add references as user messages (before other user/assistant messages)\n for (const name in this.references) {\n history.push({\n role: 'user',\n content: `Reference - ${name}:\\n${this.references[name]}`,\n });\n }\n\n // Add other messages\n this.messages\n .filter((m) => m.role !== 'system')\n .forEach((message) => {\n history.push({ role: message.role, content: message.content });\n });\n\n return history;\n }\n\n /**\n * Sends a prompt to the AI and gets a response\n *\n * @param prompt - Prompt message to send\n * @param options - Options for the AI response\n * @param options.responseFormat - Format for the AI to respond with\n * @returns Promise resolving to the AI response\n */\n public async do(\n prompt: string,\n options: {\n responseFormat?: 'html' | 'text' | 'json';\n } = {\n responseFormat: 'text',\n },\n ) {\n const { responseFormat } = options;\n const history = this.assembleHistory();\n\n // Get completion from AI with assembled history\n const response = await this.ai.textCompletion(prompt, {\n history,\n responseFormat: {\n type: responseFormat === 'json' ? 'json_object' : 'text',\n },\n });\n return response;\n }\n}\n","/**\n * @happyvertical/ai - A standardized interface for AI model interactions\n *\n * This package provides a unified interface for interacting with various AI models.\n * Supports multiple providers: OpenAI, LiteLLM, Ollama, Gemini, Anthropic,\n * Hugging Face, AWS Bedrock, Claude CLI, and Qwen3-TTS.\n *\n * Key components:\n * - getAI() - Factory function for creating AI provider instances\n * - AIInterface - Standardized interface for all AI providers\n * - Provider-specific implementations for each supported service\n */\n\n// Legacy exports for backward compatibility\nexport * from './shared/client';\nexport * from './shared/factory';\nexport { AIMessage as AIMessageClass } from './shared/message';\nexport {\n DEFAULT_AI_GENERATION_LIMITS,\n DEFAULT_AI_MAX_RETRIES,\n DEFAULT_AI_TIMEOUT_MS,\n} from './shared/safety';\nexport * from './shared/thread';\nexport * from './shared/types';\n\n/** @internal */\nexport const PACKAGE_VERSION_INITIALIZED = true;\n"],"mappings":"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"}
|
|
@@ -13,6 +13,9 @@ import { ValidationError } from "@happyvertical/utils";
|
|
|
13
13
|
var PROVIDER = "typesafe";
|
|
14
14
|
var DEFAULT_BASE_URL = "https://api.typesafe.ai/v1";
|
|
15
15
|
var DEFAULT_MODEL = "jev-latest";
|
|
16
|
+
var STRICT_DISTRIBUTION_EPSILON = 1e-6;
|
|
17
|
+
var HUNDREDTH_GRID_EPSILON = 1e-8;
|
|
18
|
+
var ROUNDED_DISTRIBUTION_MAX_ERROR = .01;
|
|
16
19
|
function isRecord(value) {
|
|
17
20
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
18
21
|
}
|
|
@@ -89,8 +92,11 @@ function distribution(value, expected, field) {
|
|
|
89
92
|
if (!isRecord(value) || Object.keys(value).length !== expected.length || expected.some((key) => !(key in value))) throw new AIError(`TypeSafe response ${field} must cover exactly the requested values`, "INVALID_RESPONSE", PROVIDER);
|
|
90
93
|
const result = Object.fromEntries(expected.map((key) => [key, probability(value[key], `${field}.${key}`)]));
|
|
91
94
|
const sum = Object.values(result).reduce((total, item) => total + item, 0);
|
|
92
|
-
if (Math.abs(sum - 1)
|
|
93
|
-
|
|
95
|
+
if (Math.abs(sum - 1) <= STRICT_DISTRIBUTION_EPSILON) return result;
|
|
96
|
+
const maximumRoundingError = Math.min(expected.length * .005, ROUNDED_DISTRIBUTION_MAX_ERROR);
|
|
97
|
+
const isHundredthRounded = Object.values(result).every((item) => Math.abs(item * 100 - Math.round(item * 100)) <= HUNDREDTH_GRID_EPSILON);
|
|
98
|
+
if (sum <= 0 || !isHundredthRounded || Math.abs(sum - 1) > maximumRoundingError + HUNDREDTH_GRID_EPSILON) throw new AIError(`TypeSafe response ${field} must sum to 1`, "INVALID_RESPONSE", PROVIDER);
|
|
99
|
+
return Object.fromEntries(Object.entries(result).map(([key, item]) => [key, item / sum]));
|
|
94
100
|
}
|
|
95
101
|
function answer(question, raw, id) {
|
|
96
102
|
if (!isRecord(raw)) throw new AIError(`TypeSafe response answers.${id} must be an object`, "INVALID_RESPONSE", PROVIDER);
|
|
@@ -303,4 +309,4 @@ var TypeSafeProvider = class {
|
|
|
303
309
|
//#endregion
|
|
304
310
|
export { TypeSafeProvider };
|
|
305
311
|
|
|
306
|
-
//# sourceMappingURL=typesafe-
|
|
312
|
+
//# sourceMappingURL=typesafe-B0gPZQJg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typesafe-B0gPZQJg.js","names":[],"sources":["../../src/shared/providers/typesafe.ts"],"sourcesContent":["/**\n * TypeSafe System One typed-decision provider.\n *\n * The public SDK contract deliberately calls TypeSafe's `noul` primitive a\n * `predicate`; vendor terminology stays confined to this wire translation.\n */\n\nimport { ValidationError } from '@happyvertical/utils';\n\nimport { extractRetryAfterSeconds } from '../rate-limit';\nimport { normalizeBaseAIOptions, prepareRequestControls } from '../safety';\nimport type {\n AICapabilities,\n AIInterface,\n AIMessage,\n AIModel,\n AIResponse,\n ChatOptions,\n ChoiceDecisionQuestion,\n CompletionOptions,\n DecisionAnswer,\n DecisionOptions,\n DecisionQuestion,\n DecisionRequest,\n DecisionResult,\n DecisionValue,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n MessageOptions,\n ScoreDecisionQuestion,\n TTSOptions,\n TTSResponse,\n TypeSafeOptions,\n VideoGenerationJob,\n VideoGenerationOptions,\n VideoGenerationResult,\n VideoGenerationStatusResult,\n Voice,\n VoiceCloneOptions,\n VoiceDesignOptions,\n VoiceListOptions,\n} from '../types';\nimport { AIError, AuthenticationError, RateLimitError } from '../types';\nimport { emitUsage } from './usage';\n\nconst PROVIDER = 'typesafe';\nconst DEFAULT_BASE_URL = 'https://api.typesafe.ai/v1';\nconst DEFAULT_MODEL = 'jev-latest';\nconst STRICT_DISTRIBUTION_EPSILON = 1e-6;\nconst HUNDREDTH_GRID_EPSILON = 1e-8;\nconst ROUNDED_DISTRIBUTION_MAX_ERROR = 0.01;\n\ntype WireQuestion =\n | {\n type: 'noul';\n instructions: DecisionValue;\n criteria?: Record<string, DecisionValue>;\n }\n | {\n type: 'choice';\n instructions: DecisionValue;\n criteria: Record<string, DecisionValue | null>;\n }\n | { type: 'score'; instructions: DecisionValue; criteria: DecisionValue[] };\n\ninterface WireResponse {\n model?: unknown;\n answers?: unknown;\n usage?: unknown;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction finite(value: unknown, field: string): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new AIError(\n `TypeSafe response ${field} must be finite`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n return value;\n}\n\nfunction probability(value: unknown, field: string): number {\n const result = finite(value, field);\n if (result < 0 || result > 1) {\n throw new AIError(\n `TypeSafe response ${field} must be between 0 and 1`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n return result;\n}\n\nfunction tokenCount(value: unknown, field: string): number {\n const result = finite(value, field);\n if (!Number.isSafeInteger(result) || result < 0) {\n throw new AIError(\n `TypeSafe response ${field} must be a non-negative integer`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n return result;\n}\n\nfunction sameDecisionValue(left: DecisionValue, right: unknown): boolean {\n if (left === right) return true;\n if (Array.isArray(left)) {\n return (\n Array.isArray(right) &&\n left.length === right.length &&\n left.every((value, index) => sameDecisionValue(value, right[index]))\n );\n }\n if (isRecord(left)) {\n return (\n isRecord(right) &&\n Object.keys(left).length === Object.keys(right).length &&\n Object.entries(left).every(\n ([key, value]) => key in right && sameDecisionValue(value, right[key]),\n )\n );\n }\n return false;\n}\n\nfunction validateValue(\n value: unknown,\n field: string,\n): asserts value is DecisionValue {\n if (value === null || typeof value === 'string' || typeof value === 'boolean')\n return;\n if (typeof value === 'number') {\n if (!Number.isFinite(value))\n throw new ValidationError(`${field} must contain finite numbers`, {\n provider: PROVIDER,\n });\n return;\n }\n if (Array.isArray(value)) {\n value.forEach((item, index) => {\n validateValue(item, `${field}[${index}]`);\n });\n return;\n }\n if (isRecord(value)) {\n Object.entries(value).forEach(([key, item]) => {\n validateValue(item, `${field}.${key}`);\n });\n return;\n }\n throw new ValidationError(`${field} must be JSON-compatible`, {\n provider: PROVIDER,\n });\n}\n\nfunction validateRequest(request: DecisionRequest): void {\n validateValue(request.state, 'state');\n const entries = Object.entries(request.questions || {});\n if (entries.length === 0)\n throw new ValidationError('questions must not be empty', {\n provider: PROVIDER,\n });\n for (const [id, question] of entries) {\n if (!id.trim())\n throw new ValidationError('question IDs must not be empty', {\n provider: PROVIDER,\n });\n validateValue(question.instructions, `questions.${id}.instructions`);\n if (question.type === 'predicate') {\n if (question.criteria) {\n for (const [key, value] of Object.entries(question.criteria))\n validateValue(value, `questions.${id}.criteria.${key}`);\n }\n } else if (question.type === 'choice') {\n const options = Object.keys(question.criteria || {});\n if (options.length === 0 || options.length > 255)\n throw new ValidationError(\n `questions.${id}.criteria must contain 1 to 255 options`,\n { provider: PROVIDER },\n );\n for (const [key, value] of Object.entries(question.criteria))\n if (value !== null)\n validateValue(value, `questions.${id}.criteria.${key}`);\n } else if (question.type === 'score') {\n if (question.criteria.length < 2 || question.criteria.length > 10)\n throw new ValidationError(\n `questions.${id}.criteria must contain 2 to 10 ordered levels`,\n { provider: PROVIDER },\n );\n question.criteria.forEach((value, index) => {\n validateValue(value, `questions.${id}.criteria[${index}]`);\n });\n } else {\n throw new ValidationError(`questions.${id}.type is unsupported`, {\n provider: PROVIDER,\n });\n }\n }\n}\n\nfunction wireQuestion(question: DecisionQuestion): WireQuestion {\n if (question.type === 'predicate')\n return {\n type: 'noul',\n instructions: question.instructions,\n ...(question.criteria ? { criteria: question.criteria } : {}),\n };\n return question;\n}\n\nfunction distribution(\n value: unknown,\n expected: string[],\n field: string,\n): Record<string, number> {\n if (\n !isRecord(value) ||\n Object.keys(value).length !== expected.length ||\n expected.some((key) => !(key in value))\n ) {\n throw new AIError(\n `TypeSafe response ${field} must cover exactly the requested values`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n const result = Object.fromEntries(\n expected.map((key) => [key, probability(value[key], `${field}.${key}`)]),\n );\n const sum = Object.values(result).reduce((total, item) => total + item, 0);\n if (Math.abs(sum - 1) <= STRICT_DISTRIBUTION_EPSILON) return result;\n\n // TypeSafe documents normalized distributions, but observed high-cardinality\n // wire responses use hundredth rounding. Accept only that measured form and\n // cap its total rounding error at one percentage point before normalizing.\n const maximumRoundingError = Math.min(\n expected.length * 0.005,\n ROUNDED_DISTRIBUTION_MAX_ERROR,\n );\n const isHundredthRounded = Object.values(result).every(\n (item) =>\n Math.abs(item * 100 - Math.round(item * 100)) <= HUNDREDTH_GRID_EPSILON,\n );\n if (\n sum <= 0 ||\n !isHundredthRounded ||\n Math.abs(sum - 1) > maximumRoundingError + HUNDREDTH_GRID_EPSILON\n )\n throw new AIError(\n `TypeSafe response ${field} must sum to 1`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return Object.fromEntries(\n Object.entries(result).map(([key, item]) => [key, item / sum]),\n );\n}\n\nfunction answer(\n question: DecisionQuestion,\n raw: unknown,\n id: string,\n): DecisionAnswer {\n if (!isRecord(raw))\n throw new AIError(\n `TypeSafe response answers.${id} must be an object`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n if (question.type === 'predicate') {\n if (raw.type !== 'noul')\n throw new AIError(\n `TypeSafe response answers.${id} type does not match predicate`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return {\n type: 'predicate',\n probability: probability(raw.noul, `answers.${id}.noul`),\n };\n }\n if (raw.type !== question.type)\n throw new AIError(\n `TypeSafe response answers.${id} type does not match request`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n if (question.type === 'choice') {\n const choices = Object.keys(question.criteria);\n if (typeof raw.choice !== 'string' || !choices.includes(raw.choice))\n throw new AIError(\n `TypeSafe response answers.${id}.choice is not a requested option`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return {\n type: 'choice',\n choice: raw.choice,\n probabilities: distribution(\n raw.probabilities,\n choices,\n `answers.${id}.probabilities`,\n ),\n confidence: probability(raw.confidence, `answers.${id}.confidence`),\n };\n }\n const scoreQuestion = question as ScoreDecisionQuestion;\n const levels = scoreQuestion.criteria;\n const levelKeys = levels.map((_, index) => String(index));\n const score = finite(raw.score, `answers.${id}.score`);\n if (score < 0 || score > levels.length - 1)\n throw new AIError(\n `TypeSafe response answers.${id}.score is outside the requested rubric`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n const legend = raw.legend;\n if (\n !isRecord(legend) ||\n levelKeys.some(\n (key, index) => !sameDecisionValue(levels[index], legend[key]),\n )\n )\n throw new AIError(\n `TypeSafe response answers.${id}.legend does not match the requested rubric`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return {\n type: 'score',\n score,\n probabilities: distribution(\n raw.probabilities,\n levelKeys,\n `answers.${id}.probabilities`,\n ),\n confidence: probability(raw.confidence, `answers.${id}.confidence`),\n levels,\n };\n}\n\n/** A decision-only adapter for TypeSafe's System One endpoint. */\nexport class TypeSafeProvider implements AIInterface {\n private readonly options: TypeSafeOptions;\n\n constructor(options: TypeSafeOptions) {\n this.options = normalizeBaseAIOptions({\n ...options,\n baseUrl: (options.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, ''),\n });\n }\n\n async decide(\n request: DecisionRequest,\n options: DecisionOptions = {},\n ): Promise<DecisionResult> {\n validateRequest(request);\n const apiKey = this.options.apiKey;\n if (!apiKey) throw new AuthenticationError(PROVIDER);\n const controls = prepareRequestControls(this.options, options);\n const startedAt = Date.now();\n const model = options.model || this.options.defaultModel || DEFAULT_MODEL;\n try {\n const response = await fetch(`${this.options.baseUrl}/systemone`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n ...this.options.headers,\n },\n body: JSON.stringify({\n state: request.state,\n model,\n questions: Object.fromEntries(\n Object.entries(request.questions).map(([id, question]) => [\n id,\n wireQuestion(question),\n ]),\n ),\n }),\n signal: controls.signal,\n });\n if (!response.ok) {\n if (response.status === 401) throw new AuthenticationError(PROVIDER);\n if (response.status === 429 || response.status === 529)\n throw new RateLimitError(\n PROVIDER,\n extractRetryAfterSeconds(response.headers),\n );\n const text = await response.text();\n throw new AIError(\n `TypeSafe request failed (${response.status}): ${text.slice(0, 500)}`,\n 'API_ERROR',\n PROVIDER,\n model,\n response.status >= 500,\n );\n }\n let body: WireResponse;\n try {\n body = (await response.json()) as WireResponse;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new AIError(\n 'TypeSafe response contained invalid JSON',\n 'INVALID_RESPONSE',\n PROVIDER,\n model,\n );\n }\n throw error;\n }\n if (!body || typeof body.model !== 'string' || !body.model)\n throw new AIError(\n 'TypeSafe response model is required',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n if (!isRecord(body.answers))\n throw new AIError(\n 'TypeSafe response answers is required',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n const responseAnswers = body.answers;\n const ids = Object.keys(request.questions);\n if (\n Object.keys(responseAnswers).length !== ids.length ||\n ids.some((id) => !(id in responseAnswers))\n )\n throw new AIError(\n 'TypeSafe response answers must match requested question IDs',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n const answers = Object.fromEntries(\n ids.map((id) => [\n id,\n answer(request.questions[id], responseAnswers[id], id),\n ]),\n );\n let usage:\n | {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n }\n | undefined;\n if (body.usage !== undefined) {\n if (\n !isRecord(body.usage) ||\n !('input_tokens' in body.usage) ||\n !('output_tokens' in body.usage)\n ) {\n throw new AIError(\n 'TypeSafe response usage must include input_tokens and output_tokens',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n const input = tokenCount(body.usage.input_tokens, 'usage.input_tokens');\n const output = tokenCount(\n body.usage.output_tokens,\n 'usage.output_tokens',\n );\n usage = {\n promptTokens: input,\n completionTokens: output,\n totalTokens: input + output,\n };\n }\n emitUsage(\n this.options,\n PROVIDER,\n 'decide',\n body.model,\n usage,\n startedAt,\n options.usageTags,\n );\n return {\n model: body.model,\n ...(usage ? { usage } : {}),\n provenance: { provider: PROVIDER, model: body.model },\n answers,\n };\n } catch (error) {\n if (controls.didTimeout())\n throw new AIError(\n `TypeSafe request timed out after ${controls.timeout}ms`,\n 'REQUEST_TIMEOUT',\n PROVIDER,\n model,\n true,\n );\n if (controls.signal.aborted && !(error instanceof AIError))\n throw new AIError(\n 'TypeSafe request was aborted',\n 'REQUEST_ABORTED',\n PROVIDER,\n model,\n );\n if (!(error instanceof AIError)) {\n throw new AIError(\n `Network error calling TypeSafe System One: ${\n error instanceof Error ? error.message : String(error)\n }`,\n 'NETWORK_ERROR',\n PROVIDER,\n model,\n true,\n );\n }\n throw error;\n } finally {\n controls.cleanup();\n }\n }\n\n async getModels(): Promise<AIModel[]> {\n return [\n {\n id: this.options.defaultModel || DEFAULT_MODEL,\n name: 'TypeSafe Jev',\n description: 'TypeSafe System One typed decisions',\n contextLength: 0,\n capabilities: ['decisions'],\n supportsFunctions: false,\n supportsVision: false,\n },\n ];\n }\n async getCapabilities(): Promise<AICapabilities> {\n return {\n decisions: true,\n chat: false,\n completion: false,\n embeddings: false,\n streaming: false,\n functions: false,\n vision: false,\n fineTuning: false,\n imageEmbeddings: false,\n imageGeneration: false,\n videoGeneration: false,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 0,\n supportedOperations: ['decide'],\n };\n }\n private unsupported(): never {\n throw new AIError(\n 'This operation is not supported by the TypeSafe decision-only provider.',\n 'NOT_IMPLEMENTED',\n PROVIDER,\n );\n }\n async chat(_a: AIMessage[], _b?: ChatOptions): Promise<AIResponse> {\n return this.unsupported();\n }\n async complete(_a: string, _b?: CompletionOptions): Promise<AIResponse> {\n return this.unsupported();\n }\n async message(_a: string, _b?: MessageOptions): Promise<string> {\n return this.unsupported();\n }\n async embed(\n _a: string | string[],\n _b?: EmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n async embedImage(\n _a: string | Buffer,\n _b?: ImageEmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n async describeImage(\n _a: string | Buffer,\n _b?: string,\n _c?: ImageDescriptionOptions,\n ): Promise<string> {\n return this.unsupported();\n }\n async generateImage(\n _a: string,\n _b?: ImageGenerationOptions,\n ): Promise<ImageGenerationResponse> {\n return this.unsupported();\n }\n stream(_a: AIMessage[], _b?: ChatOptions): AsyncIterable<string> {\n const error = new AIError(\n 'Chat streaming is not supported by the TypeSafe decision-only provider.',\n 'NOT_IMPLEMENTED',\n PROVIDER,\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n async countTokens(_a: string): Promise<number> {\n return this.unsupported();\n }\n async submitVideoGenerationJob(\n _a: VideoGenerationOptions,\n ): Promise<VideoGenerationJob> {\n return this.unsupported();\n }\n async getVideoGenerationJob(\n _a: VideoGenerationJob,\n ): Promise<VideoGenerationStatusResult> {\n return this.unsupported();\n }\n async fetchVideoGenerationResult(\n _a: VideoGenerationJob,\n ): Promise<VideoGenerationResult> {\n return this.unsupported();\n }\n async cancelVideoGenerationJob(_a: VideoGenerationJob): Promise<void> {\n return this.unsupported();\n }\n async validateVideoGenerationAccess(): Promise<boolean> {\n return this.unsupported();\n }\n async synthesizeSpeech(_a: string, _b?: TTSOptions): Promise<TTSResponse> {\n return this.unsupported();\n }\n streamSpeech(_a: string, _b?: TTSOptions): AsyncIterable<Buffer> {\n const error = new AIError(\n 'TTS streaming is not supported by the TypeSafe decision-only provider.',\n 'NOT_IMPLEMENTED',\n PROVIDER,\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n async cloneVoice(_a: VoiceCloneOptions): Promise<Voice> {\n return this.unsupported();\n }\n async designVoice(_a: VoiceDesignOptions): Promise<Voice> {\n return this.unsupported();\n }\n async getVoices(_a?: VoiceListOptions): Promise<Voice[]> {\n return this.unsupported();\n }\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as getAI, c as OpenAIClient, l as getAIClient, n as AIThread, o as getAIAuto, r as AIMessage, s as AIClient, t as PACKAGE_VERSION_INITIALIZED, u as getOpenAI } from "./chunks/src-
|
|
1
|
+
import { a as getAI, c as OpenAIClient, l as getAIClient, n as AIThread, o as getAIAuto, r as AIMessage, s as AIClient, t as PACKAGE_VERSION_INITIALIZED, u as getOpenAI } from "./chunks/src-BUQUZK2M.js";
|
|
2
2
|
import { a as ContextLengthError, c as extractTextContent, i as ContentFilterError, n as AI_PROVIDER_TYPES, o as ModelNotFoundError, r as AuthenticationError, s as RateLimitError, t as AIError } from "./chunks/types-BpnNcTU1.js";
|
|
3
3
|
import { n as DEFAULT_AI_MAX_RETRIES, r as DEFAULT_AI_TIMEOUT_MS, t as DEFAULT_AI_GENERATION_LIMITS } from "./chunks/safety-BKswBoqy.js";
|
|
4
4
|
export { AIClient, AIError, AIMessage as AIMessageClass, AIThread, AI_PROVIDER_TYPES, AuthenticationError, ContentFilterError, ContextLengthError, DEFAULT_AI_GENERATION_LIMITS, DEFAULT_AI_MAX_RETRIES, DEFAULT_AI_TIMEOUT_MS, ModelNotFoundError, OpenAIClient, PACKAGE_VERSION_INITIALIZED, RateLimitError, extractTextContent, getAI, getAIAuto, getAIClient, getOpenAI };
|
package/dist/node.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as getAI, c as OpenAIClient, l as getAIClient, n as AIThread, r as AIMessage, s as AIClient, t as PACKAGE_VERSION_INITIALIZED, u as getOpenAI } from "./chunks/src-
|
|
1
|
+
import { a as getAI, c as OpenAIClient, l as getAIClient, n as AIThread, r as AIMessage, s as AIClient, t as PACKAGE_VERSION_INITIALIZED, u as getOpenAI } from "./chunks/src-BUQUZK2M.js";
|
|
2
2
|
import { a as ContextLengthError, c as extractTextContent, i as ContentFilterError, n as AI_PROVIDER_TYPES, o as ModelNotFoundError, r as AuthenticationError, s as RateLimitError, t as AIError } from "./chunks/types-BpnNcTU1.js";
|
|
3
3
|
import { n as DEFAULT_AI_MAX_RETRIES, r as DEFAULT_AI_TIMEOUT_MS, t as DEFAULT_AI_GENERATION_LIMITS } from "./chunks/safety-BKswBoqy.js";
|
|
4
4
|
import { ValidationError, loadEnvConfig } from "@happyvertical/utils";
|
|
@@ -100,7 +100,7 @@ async function getAIAuto(options = {}) {
|
|
|
100
100
|
return getAI(config);
|
|
101
101
|
}
|
|
102
102
|
try {
|
|
103
|
-
return await import("./chunks/src-
|
|
103
|
+
return await import("./chunks/src-BUQUZK2M.js").then((n) => n.i).then((m) => m.getAIAuto(config));
|
|
104
104
|
} catch (_error) {}
|
|
105
105
|
const hasLiteLLMSignal = Boolean(process.env.LITELLM_BASE_URL || process.env.LITELLM_API_KEY);
|
|
106
106
|
if (Boolean(process.env.BIFROST_BASE_URL) && !config.type) return getAI({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typesafe.d.ts","sourceRoot":"","sources":["../../../src/shared/providers/typesafe.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,SAAS,EACT,OAAO,EACP,UAAU,EACV,WAAW,EAEX,iBAAiB,EAEjB,eAAe,EAEf,eAAe,EACf,cAAc,EAEd,gBAAgB,EAChB,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,cAAc,EAEd,UAAU,EACV,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,2BAA2B,EAC3B,KAAK,EACL,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"typesafe.d.ts","sourceRoot":"","sources":["../../../src/shared/providers/typesafe.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/ai",
|
|
3
|
-
"version": "0.96.
|
|
3
|
+
"version": "0.96.1",
|
|
4
4
|
"description": "Standardized AI interface supporting chat, embeddings, media, and TypeSafe/Jev typed decisions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@aws-sdk/client-bedrock-runtime": "3.1034.0",
|
|
45
45
|
"@google/genai": "1.50.1",
|
|
46
46
|
"openai": "6.34.0",
|
|
47
|
-
"@happyvertical/utils": "0.96.
|
|
47
|
+
"@happyvertical/utils": "0.96.1"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@types/node": "25.0.10",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"typesafe-qpVPDkOR.js","names":[],"sources":["../../src/shared/providers/typesafe.ts"],"sourcesContent":["/**\n * TypeSafe System One typed-decision provider.\n *\n * The public SDK contract deliberately calls TypeSafe's `noul` primitive a\n * `predicate`; vendor terminology stays confined to this wire translation.\n */\n\nimport { ValidationError } from '@happyvertical/utils';\n\nimport { extractRetryAfterSeconds } from '../rate-limit';\nimport { normalizeBaseAIOptions, prepareRequestControls } from '../safety';\nimport type {\n AICapabilities,\n AIInterface,\n AIMessage,\n AIModel,\n AIResponse,\n ChatOptions,\n ChoiceDecisionQuestion,\n CompletionOptions,\n DecisionAnswer,\n DecisionOptions,\n DecisionQuestion,\n DecisionRequest,\n DecisionResult,\n DecisionValue,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n MessageOptions,\n ScoreDecisionQuestion,\n TTSOptions,\n TTSResponse,\n TypeSafeOptions,\n VideoGenerationJob,\n VideoGenerationOptions,\n VideoGenerationResult,\n VideoGenerationStatusResult,\n Voice,\n VoiceCloneOptions,\n VoiceDesignOptions,\n VoiceListOptions,\n} from '../types';\nimport { AIError, AuthenticationError, RateLimitError } from '../types';\nimport { emitUsage } from './usage';\n\nconst PROVIDER = 'typesafe';\nconst DEFAULT_BASE_URL = 'https://api.typesafe.ai/v1';\nconst DEFAULT_MODEL = 'jev-latest';\n\ntype WireQuestion =\n | {\n type: 'noul';\n instructions: DecisionValue;\n criteria?: Record<string, DecisionValue>;\n }\n | {\n type: 'choice';\n instructions: DecisionValue;\n criteria: Record<string, DecisionValue | null>;\n }\n | { type: 'score'; instructions: DecisionValue; criteria: DecisionValue[] };\n\ninterface WireResponse {\n model?: unknown;\n answers?: unknown;\n usage?: unknown;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction finite(value: unknown, field: string): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new AIError(\n `TypeSafe response ${field} must be finite`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n return value;\n}\n\nfunction probability(value: unknown, field: string): number {\n const result = finite(value, field);\n if (result < 0 || result > 1) {\n throw new AIError(\n `TypeSafe response ${field} must be between 0 and 1`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n return result;\n}\n\nfunction tokenCount(value: unknown, field: string): number {\n const result = finite(value, field);\n if (!Number.isSafeInteger(result) || result < 0) {\n throw new AIError(\n `TypeSafe response ${field} must be a non-negative integer`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n return result;\n}\n\nfunction sameDecisionValue(left: DecisionValue, right: unknown): boolean {\n if (left === right) return true;\n if (Array.isArray(left)) {\n return (\n Array.isArray(right) &&\n left.length === right.length &&\n left.every((value, index) => sameDecisionValue(value, right[index]))\n );\n }\n if (isRecord(left)) {\n return (\n isRecord(right) &&\n Object.keys(left).length === Object.keys(right).length &&\n Object.entries(left).every(\n ([key, value]) => key in right && sameDecisionValue(value, right[key]),\n )\n );\n }\n return false;\n}\n\nfunction validateValue(\n value: unknown,\n field: string,\n): asserts value is DecisionValue {\n if (value === null || typeof value === 'string' || typeof value === 'boolean')\n return;\n if (typeof value === 'number') {\n if (!Number.isFinite(value))\n throw new ValidationError(`${field} must contain finite numbers`, {\n provider: PROVIDER,\n });\n return;\n }\n if (Array.isArray(value)) {\n value.forEach((item, index) => {\n validateValue(item, `${field}[${index}]`);\n });\n return;\n }\n if (isRecord(value)) {\n Object.entries(value).forEach(([key, item]) => {\n validateValue(item, `${field}.${key}`);\n });\n return;\n }\n throw new ValidationError(`${field} must be JSON-compatible`, {\n provider: PROVIDER,\n });\n}\n\nfunction validateRequest(request: DecisionRequest): void {\n validateValue(request.state, 'state');\n const entries = Object.entries(request.questions || {});\n if (entries.length === 0)\n throw new ValidationError('questions must not be empty', {\n provider: PROVIDER,\n });\n for (const [id, question] of entries) {\n if (!id.trim())\n throw new ValidationError('question IDs must not be empty', {\n provider: PROVIDER,\n });\n validateValue(question.instructions, `questions.${id}.instructions`);\n if (question.type === 'predicate') {\n if (question.criteria) {\n for (const [key, value] of Object.entries(question.criteria))\n validateValue(value, `questions.${id}.criteria.${key}`);\n }\n } else if (question.type === 'choice') {\n const options = Object.keys(question.criteria || {});\n if (options.length === 0 || options.length > 255)\n throw new ValidationError(\n `questions.${id}.criteria must contain 1 to 255 options`,\n { provider: PROVIDER },\n );\n for (const [key, value] of Object.entries(question.criteria))\n if (value !== null)\n validateValue(value, `questions.${id}.criteria.${key}`);\n } else if (question.type === 'score') {\n if (question.criteria.length < 2 || question.criteria.length > 10)\n throw new ValidationError(\n `questions.${id}.criteria must contain 2 to 10 ordered levels`,\n { provider: PROVIDER },\n );\n question.criteria.forEach((value, index) => {\n validateValue(value, `questions.${id}.criteria[${index}]`);\n });\n } else {\n throw new ValidationError(`questions.${id}.type is unsupported`, {\n provider: PROVIDER,\n });\n }\n }\n}\n\nfunction wireQuestion(question: DecisionQuestion): WireQuestion {\n if (question.type === 'predicate')\n return {\n type: 'noul',\n instructions: question.instructions,\n ...(question.criteria ? { criteria: question.criteria } : {}),\n };\n return question;\n}\n\nfunction distribution(\n value: unknown,\n expected: string[],\n field: string,\n): Record<string, number> {\n if (\n !isRecord(value) ||\n Object.keys(value).length !== expected.length ||\n expected.some((key) => !(key in value))\n ) {\n throw new AIError(\n `TypeSafe response ${field} must cover exactly the requested values`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n const result = Object.fromEntries(\n expected.map((key) => [key, probability(value[key], `${field}.${key}`)]),\n );\n const sum = Object.values(result).reduce((total, item) => total + item, 0);\n if (Math.abs(sum - 1) > 1e-6)\n throw new AIError(\n `TypeSafe response ${field} must sum to 1`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return result;\n}\n\nfunction answer(\n question: DecisionQuestion,\n raw: unknown,\n id: string,\n): DecisionAnswer {\n if (!isRecord(raw))\n throw new AIError(\n `TypeSafe response answers.${id} must be an object`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n if (question.type === 'predicate') {\n if (raw.type !== 'noul')\n throw new AIError(\n `TypeSafe response answers.${id} type does not match predicate`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return {\n type: 'predicate',\n probability: probability(raw.noul, `answers.${id}.noul`),\n };\n }\n if (raw.type !== question.type)\n throw new AIError(\n `TypeSafe response answers.${id} type does not match request`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n if (question.type === 'choice') {\n const choices = Object.keys(question.criteria);\n if (typeof raw.choice !== 'string' || !choices.includes(raw.choice))\n throw new AIError(\n `TypeSafe response answers.${id}.choice is not a requested option`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return {\n type: 'choice',\n choice: raw.choice,\n probabilities: distribution(\n raw.probabilities,\n choices,\n `answers.${id}.probabilities`,\n ),\n confidence: probability(raw.confidence, `answers.${id}.confidence`),\n };\n }\n const scoreQuestion = question as ScoreDecisionQuestion;\n const levels = scoreQuestion.criteria;\n const levelKeys = levels.map((_, index) => String(index));\n const score = finite(raw.score, `answers.${id}.score`);\n if (score < 0 || score > levels.length - 1)\n throw new AIError(\n `TypeSafe response answers.${id}.score is outside the requested rubric`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n const legend = raw.legend;\n if (\n !isRecord(legend) ||\n levelKeys.some(\n (key, index) => !sameDecisionValue(levels[index], legend[key]),\n )\n )\n throw new AIError(\n `TypeSafe response answers.${id}.legend does not match the requested rubric`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return {\n type: 'score',\n score,\n probabilities: distribution(\n raw.probabilities,\n levelKeys,\n `answers.${id}.probabilities`,\n ),\n confidence: probability(raw.confidence, `answers.${id}.confidence`),\n levels,\n };\n}\n\n/** A decision-only adapter for TypeSafe's System One endpoint. */\nexport class TypeSafeProvider implements AIInterface {\n private readonly options: TypeSafeOptions;\n\n constructor(options: TypeSafeOptions) {\n this.options = normalizeBaseAIOptions({\n ...options,\n baseUrl: (options.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, ''),\n });\n }\n\n async decide(\n request: DecisionRequest,\n options: DecisionOptions = {},\n ): Promise<DecisionResult> {\n validateRequest(request);\n const apiKey = this.options.apiKey;\n if (!apiKey) throw new AuthenticationError(PROVIDER);\n const controls = prepareRequestControls(this.options, options);\n const startedAt = Date.now();\n const model = options.model || this.options.defaultModel || DEFAULT_MODEL;\n try {\n const response = await fetch(`${this.options.baseUrl}/systemone`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n ...this.options.headers,\n },\n body: JSON.stringify({\n state: request.state,\n model,\n questions: Object.fromEntries(\n Object.entries(request.questions).map(([id, question]) => [\n id,\n wireQuestion(question),\n ]),\n ),\n }),\n signal: controls.signal,\n });\n if (!response.ok) {\n if (response.status === 401) throw new AuthenticationError(PROVIDER);\n if (response.status === 429 || response.status === 529)\n throw new RateLimitError(\n PROVIDER,\n extractRetryAfterSeconds(response.headers),\n );\n const text = await response.text();\n throw new AIError(\n `TypeSafe request failed (${response.status}): ${text.slice(0, 500)}`,\n 'API_ERROR',\n PROVIDER,\n model,\n response.status >= 500,\n );\n }\n let body: WireResponse;\n try {\n body = (await response.json()) as WireResponse;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new AIError(\n 'TypeSafe response contained invalid JSON',\n 'INVALID_RESPONSE',\n PROVIDER,\n model,\n );\n }\n throw error;\n }\n if (!body || typeof body.model !== 'string' || !body.model)\n throw new AIError(\n 'TypeSafe response model is required',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n if (!isRecord(body.answers))\n throw new AIError(\n 'TypeSafe response answers is required',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n const responseAnswers = body.answers;\n const ids = Object.keys(request.questions);\n if (\n Object.keys(responseAnswers).length !== ids.length ||\n ids.some((id) => !(id in responseAnswers))\n )\n throw new AIError(\n 'TypeSafe response answers must match requested question IDs',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n const answers = Object.fromEntries(\n ids.map((id) => [\n id,\n answer(request.questions[id], responseAnswers[id], id),\n ]),\n );\n let usage:\n | {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n }\n | undefined;\n if (body.usage !== undefined) {\n if (\n !isRecord(body.usage) ||\n !('input_tokens' in body.usage) ||\n !('output_tokens' in body.usage)\n ) {\n throw new AIError(\n 'TypeSafe response usage must include input_tokens and output_tokens',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n const input = tokenCount(body.usage.input_tokens, 'usage.input_tokens');\n const output = tokenCount(\n body.usage.output_tokens,\n 'usage.output_tokens',\n );\n usage = {\n promptTokens: input,\n completionTokens: output,\n totalTokens: input + output,\n };\n }\n emitUsage(\n this.options,\n PROVIDER,\n 'decide',\n body.model,\n usage,\n startedAt,\n options.usageTags,\n );\n return {\n model: body.model,\n ...(usage ? { usage } : {}),\n provenance: { provider: PROVIDER, model: body.model },\n answers,\n };\n } catch (error) {\n if (controls.didTimeout())\n throw new AIError(\n `TypeSafe request timed out after ${controls.timeout}ms`,\n 'REQUEST_TIMEOUT',\n PROVIDER,\n model,\n true,\n );\n if (controls.signal.aborted && !(error instanceof AIError))\n throw new AIError(\n 'TypeSafe request was aborted',\n 'REQUEST_ABORTED',\n PROVIDER,\n model,\n );\n if (!(error instanceof AIError)) {\n throw new AIError(\n `Network error calling TypeSafe System One: ${\n error instanceof Error ? error.message : String(error)\n }`,\n 'NETWORK_ERROR',\n PROVIDER,\n model,\n true,\n );\n }\n throw error;\n } finally {\n controls.cleanup();\n }\n }\n\n async getModels(): Promise<AIModel[]> {\n return [\n {\n id: this.options.defaultModel || DEFAULT_MODEL,\n name: 'TypeSafe Jev',\n description: 'TypeSafe System One typed decisions',\n contextLength: 0,\n capabilities: ['decisions'],\n supportsFunctions: false,\n supportsVision: false,\n },\n ];\n }\n async getCapabilities(): Promise<AICapabilities> {\n return {\n decisions: true,\n chat: false,\n completion: false,\n embeddings: false,\n streaming: false,\n functions: false,\n vision: false,\n fineTuning: false,\n imageEmbeddings: false,\n imageGeneration: false,\n videoGeneration: false,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 0,\n supportedOperations: ['decide'],\n };\n }\n private unsupported(): never {\n throw new AIError(\n 'This operation is not supported by the TypeSafe decision-only provider.',\n 'NOT_IMPLEMENTED',\n PROVIDER,\n );\n }\n async chat(_a: AIMessage[], _b?: ChatOptions): Promise<AIResponse> {\n return this.unsupported();\n }\n async complete(_a: string, _b?: CompletionOptions): Promise<AIResponse> {\n return this.unsupported();\n }\n async message(_a: string, _b?: MessageOptions): Promise<string> {\n return this.unsupported();\n }\n async embed(\n _a: string | string[],\n _b?: EmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n async embedImage(\n _a: string | Buffer,\n _b?: ImageEmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n async describeImage(\n _a: string | Buffer,\n _b?: string,\n _c?: ImageDescriptionOptions,\n ): Promise<string> {\n return this.unsupported();\n }\n async generateImage(\n _a: string,\n _b?: ImageGenerationOptions,\n ): Promise<ImageGenerationResponse> {\n return this.unsupported();\n }\n stream(_a: AIMessage[], _b?: ChatOptions): AsyncIterable<string> {\n const error = new AIError(\n 'Chat streaming is not supported by the TypeSafe decision-only provider.',\n 'NOT_IMPLEMENTED',\n PROVIDER,\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n async countTokens(_a: string): Promise<number> {\n return this.unsupported();\n }\n async submitVideoGenerationJob(\n _a: VideoGenerationOptions,\n ): Promise<VideoGenerationJob> {\n return this.unsupported();\n }\n async getVideoGenerationJob(\n _a: VideoGenerationJob,\n ): Promise<VideoGenerationStatusResult> {\n return this.unsupported();\n }\n async fetchVideoGenerationResult(\n _a: VideoGenerationJob,\n ): Promise<VideoGenerationResult> {\n return this.unsupported();\n }\n async cancelVideoGenerationJob(_a: VideoGenerationJob): Promise<void> {\n return this.unsupported();\n }\n async validateVideoGenerationAccess(): Promise<boolean> {\n return this.unsupported();\n }\n async synthesizeSpeech(_a: string, _b?: TTSOptions): Promise<TTSResponse> {\n return this.unsupported();\n }\n streamSpeech(_a: string, _b?: TTSOptions): AsyncIterable<Buffer> {\n const error = new AIError(\n 'TTS streaming is not supported by the TypeSafe decision-only provider.',\n 'NOT_IMPLEMENTED',\n PROVIDER,\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n async cloneVoice(_a: VoiceCloneOptions): Promise<Voice> {\n return this.unsupported();\n }\n async designVoice(_a: VoiceDesignOptions): Promise<Voice> {\n return this.unsupported();\n }\n async getVoices(_a?: VoiceListOptions): Promise<Voice[]> {\n return this.unsupported();\n }\n}\n"],"mappings":"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"}
|