@happyvertical/ai 0.79.0 → 0.80.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.
Files changed (63) hide show
  1. package/AGENT.md +1 -1
  2. package/dist/chunks/anthropic-DA8sdt12.js +438 -0
  3. package/dist/chunks/anthropic-DA8sdt12.js.map +1 -0
  4. package/dist/chunks/bedrock-DDiYFUw0.js +699 -0
  5. package/dist/chunks/bedrock-DDiYFUw0.js.map +1 -0
  6. package/dist/chunks/bifrost-fM9FpW_w.js +198 -0
  7. package/dist/chunks/bifrost-fM9FpW_w.js.map +1 -0
  8. package/dist/chunks/claude-cli-CnJh5KQT.js +498 -0
  9. package/dist/chunks/claude-cli-CnJh5KQT.js.map +1 -0
  10. package/dist/chunks/gateway-admin-CiKvHst7.js +283 -0
  11. package/dist/chunks/gateway-admin-CiKvHst7.js.map +1 -0
  12. package/dist/chunks/gemini-Bu7Fke7c.js +593 -0
  13. package/dist/chunks/gemini-Bu7Fke7c.js.map +1 -0
  14. package/dist/chunks/huggingface-B07_6wHW.js +295 -0
  15. package/dist/chunks/huggingface-B07_6wHW.js.map +1 -0
  16. package/dist/chunks/litellm-D_Oo9OQ_.js +185 -0
  17. package/dist/chunks/litellm-D_Oo9OQ_.js.map +1 -0
  18. package/dist/chunks/ollama-D4ksOTO8.js +626 -0
  19. package/dist/chunks/ollama-D4ksOTO8.js.map +1 -0
  20. package/dist/chunks/openai--F38QHiJ.js +691 -0
  21. package/dist/chunks/openai--F38QHiJ.js.map +1 -0
  22. package/dist/chunks/qwen-tts-DRRbOrhA.js +333 -0
  23. package/dist/chunks/qwen-tts-DRRbOrhA.js.map +1 -0
  24. package/dist/chunks/rate-limit-BwyPGXFW.js +199 -0
  25. package/dist/chunks/rate-limit-BwyPGXFW.js.map +1 -0
  26. package/dist/chunks/safety-CEnoJS6X.js +260 -0
  27. package/dist/chunks/safety-CEnoJS6X.js.map +1 -0
  28. package/dist/chunks/types-FHs-KbGL.js +117 -0
  29. package/dist/chunks/types-FHs-KbGL.js.map +1 -0
  30. package/dist/chunks/usage-C1Y1Nlg4.js +35 -0
  31. package/dist/chunks/usage-C1Y1Nlg4.js.map +1 -0
  32. package/dist/cli/claude-context.js +17 -17
  33. package/dist/cli/claude-context.js.map +1 -1
  34. package/dist/index.js +717 -23
  35. package/dist/index.js.map +1 -1
  36. package/metadata.json +1 -1
  37. package/package.json +5 -5
  38. package/dist/chunks/anthropic-2z-82zgr.js +0 -530
  39. package/dist/chunks/anthropic-2z-82zgr.js.map +0 -1
  40. package/dist/chunks/bedrock-Dc2eVPUD.js +0 -920
  41. package/dist/chunks/bedrock-Dc2eVPUD.js.map +0 -1
  42. package/dist/chunks/bifrost-CEnCsciy.js +0 -258
  43. package/dist/chunks/bifrost-CEnCsciy.js.map +0 -1
  44. package/dist/chunks/claude-cli-X1ONjE8K.js +0 -603
  45. package/dist/chunks/claude-cli-X1ONjE8K.js.map +0 -1
  46. package/dist/chunks/gateway-admin-BUhBzXZb.js +0 -359
  47. package/dist/chunks/gateway-admin-BUhBzXZb.js.map +0 -1
  48. package/dist/chunks/gemini-CS56gY0D.js +0 -768
  49. package/dist/chunks/gemini-CS56gY0D.js.map +0 -1
  50. package/dist/chunks/huggingface-wQSfO5xA.js +0 -411
  51. package/dist/chunks/huggingface-wQSfO5xA.js.map +0 -1
  52. package/dist/chunks/index-DCXO0nZA.js +0 -1293
  53. package/dist/chunks/index-DCXO0nZA.js.map +0 -1
  54. package/dist/chunks/litellm-BMFTYbWc.js +0 -245
  55. package/dist/chunks/litellm-BMFTYbWc.js.map +0 -1
  56. package/dist/chunks/ollama-DsGDrA-c.js +0 -962
  57. package/dist/chunks/ollama-DsGDrA-c.js.map +0 -1
  58. package/dist/chunks/openai-CJEo69jb.js +0 -882
  59. package/dist/chunks/openai-CJEo69jb.js.map +0 -1
  60. package/dist/chunks/qwen-tts-BLYZ6d9s.js +0 -365
  61. package/dist/chunks/qwen-tts-BLYZ6d9s.js.map +0 -1
  62. package/dist/chunks/usage-DMWiJ2oB.js +0 -21
  63. package/dist/chunks/usage-DMWiJ2oB.js.map +0 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/shared/client.ts","../src/shared/factory.ts","../src/shared/message.ts","../src/shared/thread.ts","../src/index.ts"],"sourcesContent":["import { ApiError, ValidationError } from '@happyvertical/utils';\nimport OpenAI from 'openai';\n\nimport type { AIMessageOptions } from './message';\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 max_tokens: maxTokens,\n n,\n presence_penalty: presencePenalty,\n response_format: responseFormat,\n seed,\n stop,\n temperature,\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 max_tokens: maxTokens,\n n,\n presence_penalty: presencePenalty,\n response_format: responseFormat,\n seed,\n stop,\n stream: false,\n temperature,\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 ClaudeCliOptions,\n GeminiOptions,\n GetAIOptions,\n HuggingFaceOptions,\n LiteLLMOptions,\n OllamaOptions,\n OpenAIOptions,\n Qwen3TTSOptions,\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 * 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 {\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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"}
package/metadata.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "path": "packages/ai",
4
4
  "position": {
5
5
  "index": 2,
6
- "count": 31
6
+ "count": 32
7
7
  },
8
8
  "description": "Standardized AI interface supporting OpenAI, LiteLLM, Bifrost, Ollama, Anthropic, Gemini, Bedrock, Hugging Face, Claude CLI, and Qwen3-TTS",
9
9
  "provides": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/ai",
3
- "version": "0.79.0",
3
+ "version": "0.80.1",
4
4
  "description": "Standardized AI interface supporting OpenAI, LiteLLM, Bifrost, Ollama, Anthropic, Gemini, Bedrock, Hugging Face, Claude CLI, and Qwen3-TTS",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -40,14 +40,14 @@
40
40
  "@aws-sdk/client-bedrock-runtime": "3.1034.0",
41
41
  "@google/genai": "1.50.1",
42
42
  "openai": "6.34.0",
43
- "@happyvertical/utils": "0.79.0"
43
+ "@happyvertical/utils": "0.80.1"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/node": "25.0.10",
47
- "typescript": "^5.9.3",
48
- "vite": "7.3.2",
47
+ "typescript": "5.9.3",
48
+ "vite": "8.1.4",
49
49
  "vite-plugin-dts": "4.5.4",
50
- "vitest": "^4.1.5"
50
+ "vitest": "4.1.10"
51
51
  },
52
52
  "scripts": {
53
53
  "test": "vitest --config ../../vitest.package.config.ts run",
@@ -1,530 +0,0 @@
1
- import { b as normalizeBaseAIOptions, A as AIError, n as normalizeChatOptions, p as prepareRequestControls, f as extractTextContent, c as ContextLengthError, M as ModelNotFoundError, R as RateLimitError, e as extractRetryAfterSeconds, d as AuthenticationError } from "./index-DCXO0nZA.js";
2
- import { e as emitUsage } from "./usage-DMWiJ2oB.js";
3
- class AnthropicProvider {
4
- options;
5
- client;
6
- // Will be Anthropic instance from @anthropic-ai/sdk
7
- /**
8
- * Creates a new Anthropic provider instance
9
- * @param options - Configuration options for the Anthropic provider
10
- */
11
- constructor(options) {
12
- this.options = normalizeBaseAIOptions({
13
- defaultModel: "claude-3-5-sonnet-20241022",
14
- anthropicVersion: "2023-06-01",
15
- ...options
16
- });
17
- this.initializeClientSync();
18
- }
19
- initializeClientSync() {
20
- try {
21
- import("@anthropic-ai/sdk").then(({ Anthropic }) => {
22
- this.client = new Anthropic({
23
- apiKey: this.options.apiKey,
24
- baseURL: this.options.baseUrl,
25
- timeout: this.options.timeout,
26
- maxRetries: this.options.maxRetries,
27
- defaultHeaders: {
28
- "anthropic-version": this.options.anthropicVersion,
29
- ...this.options.headers
30
- }
31
- });
32
- }).catch(() => {
33
- });
34
- } catch (_error) {
35
- }
36
- }
37
- /**
38
- * Ensures the Anthropic client is initialized by dynamically importing the SDK
39
- * @throws {AIError} When the Anthropic SDK cannot be loaded
40
- * @private
41
- */
42
- async ensureClient() {
43
- if (!this.client) {
44
- try {
45
- const { Anthropic } = await import("@anthropic-ai/sdk");
46
- this.client = new Anthropic({
47
- apiKey: this.options.apiKey,
48
- baseURL: this.options.baseUrl,
49
- timeout: this.options.timeout,
50
- maxRetries: this.options.maxRetries,
51
- defaultHeaders: {
52
- "anthropic-version": this.options.anthropicVersion,
53
- ...this.options.headers
54
- }
55
- });
56
- } catch (_error) {
57
- throw new AIError(
58
- "Failed to initialize Anthropic client. Make sure @anthropic-ai/sdk is installed.",
59
- "INITIALIZATION_ERROR",
60
- "anthropic"
61
- );
62
- }
63
- }
64
- }
65
- /**
66
- * Generate a chat completion using Claude models
67
- * @param messages - Array of conversation messages
68
- * @param options - Optional configuration for the chat completion
69
- * @returns Promise resolving to the AI response with content and metadata
70
- * @throws {AIError} When the API request fails or SDK is not available
71
- *
72
- * @example
73
- * ```typescript
74
- * const response = await provider.chat([
75
- * { role: 'system', content: 'You are a helpful assistant.' },
76
- * { role: 'user', content: 'Explain quantum computing' }
77
- * ], {
78
- * model: 'claude-3-5-sonnet-20241022',
79
- * maxTokens: 1000
80
- * });
81
- * ```
82
- */
83
- async chat(messages, options = {}) {
84
- const startTime = Date.now();
85
- let controls;
86
- try {
87
- await this.ensureClient();
88
- const { system, anthropicMessages } = this.mapMessagesToAnthropic(messages);
89
- const model = options.model || this.options.defaultModel;
90
- options = normalizeChatOptions(this.options, options, "anthropic", model);
91
- controls = prepareRequestControls(this.options, options);
92
- const requestParams = {
93
- model,
94
- messages: anthropicMessages,
95
- max_tokens: options.maxTokens,
96
- temperature: options.temperature,
97
- top_p: options.topP,
98
- stop_sequences: Array.isArray(options.stop) ? options.stop : options.stop ? [options.stop] : void 0,
99
- system: system || void 0,
100
- tools: options.tools && options.tools.length > 0 ? options.tools.map((tool) => ({
101
- name: tool.function.name,
102
- description: tool.function.description || "",
103
- input_schema: tool.function.parameters || { type: "object" }
104
- })) : void 0,
105
- tool_choice: this.mapToolChoice(options.toolChoice),
106
- stream: false
107
- };
108
- if ((options.reasoning?.maxTokens || 0) > 0) {
109
- requestParams.thinking = {
110
- type: "enabled",
111
- budget_tokens: options.reasoning?.maxTokens
112
- };
113
- }
114
- if (options.responseFormat?.type === "json_object") {
115
- const jsonInstruction = "\n\nIMPORTANT: You must respond with valid JSON only. Do not include any explanatory text outside the JSON object.";
116
- requestParams.system = requestParams.system ? requestParams.system + jsonInstruction : jsonInstruction.trim();
117
- }
118
- const response = await this.client.messages.create(requestParams, {
119
- signal: controls.signal,
120
- timeout: controls.timeout
121
- });
122
- const textContent = response.content.filter((block) => block.type === "text").map((block) => block.text).join("");
123
- const toolCalls = response.content.filter((block) => block.type === "tool_use").map((block) => ({
124
- id: block.id,
125
- type: "function",
126
- function: {
127
- name: block.name,
128
- arguments: JSON.stringify(block.input)
129
- }
130
- }));
131
- const usage = {
132
- promptTokens: response.usage.input_tokens,
133
- completionTokens: response.usage.output_tokens,
134
- totalTokens: response.usage.input_tokens + response.usage.output_tokens
135
- };
136
- emitUsage(
137
- this.options,
138
- "anthropic",
139
- "chat",
140
- response.model || model,
141
- usage,
142
- startTime,
143
- options.usageTags
144
- );
145
- return {
146
- content: textContent,
147
- model: response.model,
148
- finishReason: this.mapFinishReason(response.stop_reason),
149
- usage,
150
- toolCalls: toolCalls.length > 0 ? toolCalls : void 0
151
- };
152
- } catch (error) {
153
- if (controls?.didTimeout()) {
154
- throw new AIError(
155
- `AI request timed out after ${controls.timeout}ms`,
156
- "AI_TIMEOUT",
157
- "anthropic",
158
- options.model
159
- );
160
- }
161
- if (options.signal?.aborted) {
162
- throw new AIError(
163
- "AI request aborted by caller",
164
- "AI_ABORTED",
165
- "anthropic",
166
- options.model
167
- );
168
- }
169
- throw this.mapError(error);
170
- } finally {
171
- controls?.cleanup();
172
- }
173
- }
174
- async complete(prompt, options = {}) {
175
- return this.chat([{ role: "user", content: prompt }], {
176
- model: options.model,
177
- maxTokens: options.maxTokens,
178
- temperature: options.temperature,
179
- topP: options.topP,
180
- n: options.n,
181
- stop: options.stop,
182
- stream: options.stream,
183
- onProgress: options.onProgress,
184
- signal: options.signal,
185
- timeout: options.timeout,
186
- reasoning: options.reasoning,
187
- usageTags: options.usageTags
188
- });
189
- }
190
- /**
191
- * Simple message interface for single-turn interactions with optional history
192
- *
193
- * @param text - The message text to send
194
- * @param options - Configuration options including history, model, etc.
195
- * @returns Promise resolving to the response content string
196
- *
197
- * @example
198
- * ```typescript
199
- * // Simple usage
200
- * const response = await provider.message('Hello!');
201
- *
202
- * // With history
203
- * const response = await provider.message('What was my question?', {
204
- * history: [
205
- * { role: 'user', content: 'What is 2+2?' },
206
- * { role: 'assistant', content: '4' }
207
- * ]
208
- * });
209
- * ```
210
- */
211
- async message(text, options = {}) {
212
- const messages = [
213
- ...options.history || [],
214
- { role: options.role || "user", content: text }
215
- ];
216
- const response = await this.chat(messages, {
217
- model: options.model,
218
- maxTokens: options.maxTokens,
219
- temperature: options.temperature,
220
- topP: options.topP,
221
- stop: options.stop,
222
- stream: options.stream,
223
- frequencyPenalty: options.frequencyPenalty,
224
- presencePenalty: options.presencePenalty,
225
- responseFormat: options.responseFormat,
226
- seed: options.seed,
227
- tools: options.tools,
228
- toolChoice: options.toolChoice,
229
- onProgress: options.onProgress,
230
- signal: options.signal,
231
- timeout: options.timeout,
232
- reasoning: options.reasoning,
233
- usageTags: options.usageTags
234
- });
235
- return response.content;
236
- }
237
- async embed(_text, _options = {}) {
238
- throw new AIError(
239
- "Anthropic Claude does not support embeddings. Use OpenAI or another provider for embeddings.",
240
- "NOT_SUPPORTED",
241
- "anthropic"
242
- );
243
- }
244
- async embedImage(_image, _options = {}) {
245
- throw new AIError(
246
- "Anthropic Claude does not support image embeddings. Use OpenAI or Gemini.",
247
- "NOT_SUPPORTED",
248
- "anthropic"
249
- );
250
- }
251
- async describeImage(_image, _prompt, _options = {}) {
252
- throw new AIError(
253
- "Image description is not yet implemented for Anthropic. Use OpenAI or Gemini.",
254
- "NOT_IMPLEMENTED",
255
- "anthropic"
256
- );
257
- }
258
- async generateImage(_prompt, _options = {}) {
259
- throw new AIError(
260
- "Anthropic Claude does not support image generation. Use OpenAI or Gemini.",
261
- "NOT_SUPPORTED",
262
- "anthropic"
263
- );
264
- }
265
- async *stream(messages, options = {}) {
266
- const startTime = Date.now();
267
- let controls;
268
- try {
269
- await this.ensureClient();
270
- const { system, anthropicMessages } = this.mapMessagesToAnthropic(messages);
271
- const model = options.model || this.options.defaultModel;
272
- options = normalizeChatOptions(this.options, options, "anthropic", model);
273
- controls = prepareRequestControls(this.options, options);
274
- const requestParams = {
275
- model,
276
- messages: anthropicMessages,
277
- max_tokens: options.maxTokens,
278
- temperature: options.temperature,
279
- top_p: options.topP,
280
- stop_sequences: Array.isArray(options.stop) ? options.stop : options.stop ? [options.stop] : void 0,
281
- system: system || void 0,
282
- stream: true
283
- };
284
- if ((options.reasoning?.maxTokens || 0) > 0) {
285
- requestParams.thinking = {
286
- type: "enabled",
287
- budget_tokens: options.reasoning?.maxTokens
288
- };
289
- }
290
- const stream = await this.client.messages.create(requestParams, {
291
- signal: controls.signal,
292
- timeout: controls.timeout
293
- });
294
- for await (const chunk of stream) {
295
- if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") {
296
- if (options.onProgress) {
297
- options.onProgress(chunk.delta.text);
298
- }
299
- yield chunk.delta.text;
300
- }
301
- }
302
- emitUsage(
303
- this.options,
304
- "anthropic",
305
- "stream",
306
- model,
307
- void 0,
308
- startTime,
309
- options.usageTags
310
- );
311
- } catch (error) {
312
- if (controls?.didTimeout()) {
313
- throw new AIError(
314
- `AI request timed out after ${controls.timeout}ms`,
315
- "AI_TIMEOUT",
316
- "anthropic",
317
- options.model
318
- );
319
- }
320
- if (options.signal?.aborted) {
321
- throw new AIError(
322
- "AI request aborted by caller",
323
- "AI_ABORTED",
324
- "anthropic",
325
- options.model
326
- );
327
- }
328
- throw this.mapError(error);
329
- } finally {
330
- controls?.cleanup();
331
- }
332
- }
333
- async countTokens(text) {
334
- return Math.ceil(text.length / 3.5);
335
- }
336
- async getModels() {
337
- return [
338
- {
339
- id: "claude-3-5-sonnet-20241022",
340
- name: "Claude 3.5 Sonnet",
341
- description: "Most intelligent Claude model with balanced performance",
342
- contextLength: 2e5,
343
- capabilities: ["text", "chat", "vision", "functions"],
344
- supportsFunctions: true,
345
- supportsVision: true
346
- },
347
- {
348
- id: "claude-3-5-haiku-20241022",
349
- name: "Claude 3.5 Haiku",
350
- description: "Fastest Claude model for simple tasks",
351
- contextLength: 2e5,
352
- capabilities: ["text", "chat", "vision"],
353
- supportsFunctions: true,
354
- supportsVision: true
355
- },
356
- {
357
- id: "claude-3-opus-20240229",
358
- name: "Claude 3 Opus",
359
- description: "Most powerful Claude model for complex tasks",
360
- contextLength: 2e5,
361
- capabilities: ["text", "chat", "vision", "functions"],
362
- supportsFunctions: true,
363
- supportsVision: true
364
- },
365
- {
366
- id: "claude-3-sonnet-20240229",
367
- name: "Claude 3 Sonnet",
368
- description: "Balanced Claude model for most tasks",
369
- contextLength: 2e5,
370
- capabilities: ["text", "chat", "vision"],
371
- supportsFunctions: true,
372
- supportsVision: true
373
- },
374
- {
375
- id: "claude-3-haiku-20240307",
376
- name: "Claude 3 Haiku",
377
- description: "Fast Claude model for simple tasks",
378
- contextLength: 2e5,
379
- capabilities: ["text", "chat", "vision"],
380
- supportsFunctions: false,
381
- supportsVision: true
382
- }
383
- ];
384
- }
385
- async getCapabilities() {
386
- return {
387
- chat: true,
388
- completion: true,
389
- embeddings: false,
390
- // Claude doesn't support embeddings
391
- streaming: true,
392
- functions: true,
393
- vision: true,
394
- fineTuning: false,
395
- imageEmbeddings: false,
396
- imageGeneration: false,
397
- tts: false,
398
- voiceCloning: false,
399
- voiceDesign: false,
400
- maxContextLength: 2e5,
401
- supportedOperations: [
402
- "chat",
403
- "completion",
404
- "streaming",
405
- "functions",
406
- "vision"
407
- ]
408
- };
409
- }
410
- // ============================================================================
411
- // TTS Methods (Not supported - use Qwen3-TTS provider)
412
- // ============================================================================
413
- async synthesizeSpeech(_text, _options) {
414
- throw new AIError(
415
- "TTS is not supported by Anthropic provider. Use Qwen3-TTS provider.",
416
- "NOT_IMPLEMENTED",
417
- "anthropic"
418
- );
419
- }
420
- streamSpeech(_text, _options) {
421
- const error = new AIError(
422
- "TTS streaming is not supported by Anthropic provider. Use Qwen3-TTS provider.",
423
- "NOT_IMPLEMENTED",
424
- "anthropic"
425
- );
426
- return {
427
- [Symbol.asyncIterator]: () => ({
428
- next: () => Promise.reject(error)
429
- })
430
- };
431
- }
432
- async cloneVoice(_options) {
433
- throw new AIError(
434
- "Voice cloning is not supported by Anthropic provider. Use Qwen3-TTS provider.",
435
- "NOT_IMPLEMENTED",
436
- "anthropic"
437
- );
438
- }
439
- async designVoice(_options) {
440
- throw new AIError(
441
- "Voice design is not supported by Anthropic provider. Use Qwen3-TTS provider.",
442
- "NOT_IMPLEMENTED",
443
- "anthropic"
444
- );
445
- }
446
- async getVoices(_options) {
447
- throw new AIError(
448
- "Voice listing is not supported by Anthropic provider. Use Qwen3-TTS provider.",
449
- "NOT_IMPLEMENTED",
450
- "anthropic"
451
- );
452
- }
453
- mapMessagesToAnthropic(messages) {
454
- let system;
455
- const anthropicMessages = [];
456
- for (const message of messages) {
457
- const textContent = extractTextContent(message.content);
458
- if (message.role === "system") {
459
- system = system ? `${system}
460
-
461
- ${textContent}` : textContent;
462
- } else {
463
- anthropicMessages.push({
464
- role: message.role === "assistant" ? "assistant" : "user",
465
- content: textContent
466
- });
467
- }
468
- }
469
- return { system, anthropicMessages };
470
- }
471
- mapToolChoice(toolChoice) {
472
- if (!toolChoice || toolChoice === "auto") {
473
- return { type: "auto" };
474
- }
475
- if (toolChoice === "none") {
476
- return void 0;
477
- }
478
- if (typeof toolChoice === "object" && toolChoice.type === "function") {
479
- return {
480
- type: "tool",
481
- name: toolChoice.function.name
482
- };
483
- }
484
- return { type: "auto" };
485
- }
486
- mapFinishReason(reason) {
487
- switch (reason) {
488
- case "end_turn":
489
- return "stop";
490
- case "max_tokens":
491
- return "length";
492
- case "stop_sequence":
493
- return "stop";
494
- case "tool_use":
495
- return "tool_calls";
496
- default:
497
- return "stop";
498
- }
499
- }
500
- mapError(error) {
501
- if (error instanceof AIError) {
502
- return error;
503
- }
504
- if (typeof error === "object" && error !== null && "status" in error) {
505
- const apiError = error;
506
- switch (apiError.status) {
507
- case 401:
508
- return new AuthenticationError("anthropic");
509
- case 429:
510
- return new RateLimitError(
511
- "anthropic",
512
- extractRetryAfterSeconds(error)
513
- );
514
- case 404:
515
- return new ModelNotFoundError(
516
- apiError.message || "Model not found",
517
- "anthropic"
518
- );
519
- case 413:
520
- return new ContextLengthError("anthropic");
521
- }
522
- }
523
- const errorMessage = error instanceof Error ? error.message : "Unknown Anthropic error occurred";
524
- return new AIError(errorMessage, "UNKNOWN_ERROR", "anthropic");
525
- }
526
- }
527
- export {
528
- AnthropicProvider
529
- };
530
- //# sourceMappingURL=anthropic-2z-82zgr.js.map