@kjerneverk/execution-openai 1.0.11 → 1.0.12
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/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -255,6 +255,18 @@ class OpenAIProvider {
|
|
|
255
255
|
}
|
|
256
256
|
};
|
|
257
257
|
}
|
|
258
|
+
if (tc.function?.name) {
|
|
259
|
+
const existing = toolCallsInProgress.get(index);
|
|
260
|
+
if (existing) {
|
|
261
|
+
existing.name = tc.function.name;
|
|
262
|
+
} else {
|
|
263
|
+
toolCallsInProgress.set(index, {
|
|
264
|
+
id: tc.id || "",
|
|
265
|
+
name: tc.function.name,
|
|
266
|
+
arguments: ""
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
258
270
|
if (tc.function?.arguments) {
|
|
259
271
|
const toolCall = toolCallsInProgress.get(index);
|
|
260
272
|
if (toolCall) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/proxy.ts","../src/index.ts"],"sourcesContent":["/**\n * Proxy support for OpenAI API requests.\n *\n * When proxy environment variables are set, routes requests through the proxy\n * using undici's ProxyAgent. Respects NO_PROXY/no_proxy for bypass lists and\n * NODE_TLS_REJECT_UNAUTHORIZED for TLS verification.\n */\n\nimport { ProxyAgent, fetch as undiciFetch } from 'undici';\n\n/**\n * Get the proxy URL from environment variables.\n * Checks HTTPS_PROXY, https_proxy, HTTP_PROXY, http_proxy.\n */\nexport function getProxyUrl(): string | undefined {\n return (\n process.env.HTTPS_PROXY ||\n process.env.https_proxy ||\n process.env.HTTP_PROXY ||\n process.env.http_proxy ||\n undefined\n );\n}\n\n/**\n * Read TLS strict mode. Returns false only when NODE_TLS_REJECT_UNAUTHORIZED\n * is explicitly set to '0'.\n */\nexport function getStrictSSL(): boolean {\n return process.env.NODE_TLS_REJECT_UNAUTHORIZED !== '0';\n}\n\n/**\n * Check whether a target URL should bypass the proxy based on NO_PROXY / no_proxy.\n */\nexport function isProxyBypassed(targetUrl: string): boolean {\n const noProxy = process.env.NO_PROXY || process.env.no_proxy;\n if (!noProxy) {\n return false;\n }\n\n let hostname: string;\n try {\n hostname = new URL(targetUrl).hostname.toLowerCase();\n } catch {\n return false;\n }\n\n const entries = noProxy.split(',').map((e) => e.trim().toLowerCase());\n for (const entry of entries) {\n if (!entry) {\n continue;\n }\n if (entry === '*') {\n return true;\n }\n if (hostname === entry) {\n return true;\n }\n const suffix = entry.startsWith('.') ? entry : `.${entry}`;\n if (hostname.endsWith(suffix)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Create a fetch implementation that routes requests through an HTTP(S) proxy.\n * Respects TLS verification settings and NO_PROXY bypass lists.\n *\n * @param proxyUrl - The proxy URL (e.g. https://proxy.example.com:8080)\n * @returns A fetch function that uses ProxyAgent as the dispatcher\n */\nexport function createProxyFetch(proxyUrl: string): typeof fetch {\n const proxyAgent = new ProxyAgent({\n uri: proxyUrl,\n requestTls: { rejectUnauthorized: getStrictSSL() },\n });\n return ((input: any, init?: any) => {\n const targetUrl = typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.toString()\n : input.url;\n if (isProxyBypassed(targetUrl)) {\n return undiciFetch(input, init);\n }\n return undiciFetch(input, { ...init, dispatcher: proxyAgent });\n }) as any;\n}\n","/**\n * Execution OpenAI Package\n *\n * OpenAI provider implementation for LLM execution.\n *\n * @packageDocumentation\n */\n\nimport OpenAI from 'openai';\nimport { getRedactor } from '@utilarium/offrecord';\nimport { getProxyUrl, createProxyFetch } from './proxy.js';\nimport { \n createSafeError, \n configureErrorSanitizer,\n configureSecretGuard,\n} from '@utilarium/spotclean';\n\n// Register OpenAI API key patterns on module load\nconst redactor = getRedactor();\nredactor.register({\n name: 'openai',\n patterns: [\n /sk-[a-zA-Z0-9]{20,}/g,\n /sk-proj-[a-zA-Z0-9_-]+/g,\n ],\n validator: (key: string) => /^sk-(proj-)?[a-zA-Z0-9_-]{20,}$/.test(key),\n envVar: 'OPENAI_API_KEY',\n description: 'OpenAI API keys',\n});\n\n// Configure spotclean for error sanitization\nconfigureErrorSanitizer({\n enabled: true,\n environment: process.env.NODE_ENV === 'production' ? 'production' : 'development',\n includeCorrelationId: true,\n sanitizeStackTraces: process.env.NODE_ENV === 'production',\n maxMessageLength: 500,\n});\n\nconfigureSecretGuard({\n enabled: true,\n redactionText: '[REDACTED]',\n preservePartial: false,\n preserveLength: 0,\n customPatterns: [\n { name: 'openai', pattern: /sk-[a-zA-Z0-9]{20,}/g, description: 'OpenAI API key' },\n { name: 'openai-proj', pattern: /sk-proj-[a-zA-Z0-9_-]+/g, description: 'OpenAI project key' },\n ],\n});\n\n// ===== INLINE TYPES (from 'execution' package) =====\n// These types are duplicated here for build independence.\n// When 'execution' is published, these can be imported from there.\n\nexport type Model = string;\n\nexport interface Message {\n role: 'user' | 'assistant' | 'system' | 'developer' | 'tool';\n content: string | string[] | null;\n name?: string;\n}\n\nexport interface ToolParameterSchema {\n type: 'object';\n properties: Record<string, {\n type: string;\n description?: string;\n enum?: string[];\n items?: { type: string };\n default?: any;\n }>;\n required?: string[];\n additionalProperties?: boolean;\n}\n\nexport interface ToolDefinition {\n name: string;\n description: string;\n parameters: ToolParameterSchema;\n}\n\nexport type StreamChunkType = 'text' | 'tool_call_start' | 'tool_call_delta' | 'tool_call_end' | 'usage' | 'done';\n\nexport interface StreamChunk {\n type: StreamChunkType;\n text?: string;\n toolCall?: {\n id?: string;\n index?: number;\n name?: string;\n argumentsDelta?: string;\n };\n usage?: {\n inputTokens: number;\n outputTokens: number;\n };\n}\n\nexport interface Request {\n messages: Message[];\n model: Model;\n responseFormat?: any;\n validator?: any;\n tools?: ToolDefinition[];\n addMessage(message: Message): void;\n}\n\nexport interface ProviderResponse {\n content: string;\n model: string;\n usage?: {\n inputTokens: number;\n outputTokens: number;\n };\n toolCalls?: Array<{\n id: string;\n type: 'function';\n function: {\n name: string;\n arguments: string;\n };\n }>;\n}\n\nexport interface ExecutionOptions {\n apiKey?: string;\n model?: string;\n temperature?: number;\n maxTokens?: number;\n timeout?: number;\n retries?: number;\n}\n\nexport interface Provider {\n readonly name: string;\n execute(request: Request, options?: ExecutionOptions): Promise<ProviderResponse>;\n executeStream?(request: Request, options?: ExecutionOptions): AsyncIterable<StreamChunk>;\n supportsModel?(model: Model): boolean;\n}\n\n/**\n * OpenAI Provider implementation\n */\nexport class OpenAIProvider implements Provider {\n readonly name = 'openai';\n\n /**\n * Check if this provider supports a given model\n */\n supportsModel(model: Model): boolean {\n if (!model) return true; // Default to OpenAI\n return (\n model.startsWith('gpt') ||\n model.startsWith('o1') ||\n model.startsWith('o3') ||\n model.startsWith('o4')\n );\n }\n\n /**\n * Execute a request against OpenAI\n */\n async execute(\n request: Request,\n options: ExecutionOptions = {}\n ): Promise<ProviderResponse> {\n const apiKey = options.apiKey || process.env.OPENAI_API_KEY;\n \n if (!apiKey) {\n throw new Error('OpenAI API key is required. Set OPENAI_API_KEY environment variable.');\n }\n\n // Validate key format\n const validation = redactor.validateKey(apiKey, 'openai');\n if (!validation.valid) {\n throw new Error('Invalid OpenAI API key format');\n }\n\n try {\n const clientOptions: ConstructorParameters<typeof OpenAI>[0] = { apiKey };\n const proxyUrl = getProxyUrl();\n if (proxyUrl) {\n clientOptions.fetch = createProxyFetch(proxyUrl);\n }\n const client = new OpenAI(clientOptions);\n\n const model = options.model || request.model || 'gpt-4';\n\n // Convert messages to OpenAI format\n const messages = request.messages.map((msg) => {\n if (msg.role === 'tool') {\n // Tool result message\n return {\n role: 'tool',\n content: typeof msg.content === 'string'\n ? msg.content\n : JSON.stringify(msg.content),\n tool_call_id: (msg as any).tool_call_id || '',\n };\n } else if (msg.role === 'assistant' && (msg as any).tool_calls) {\n // Assistant message with tool calls\n return {\n role: 'assistant',\n content: msg.content,\n tool_calls: (msg as any).tool_calls,\n };\n } else {\n const role = msg.role === 'developer' ? 'system' : msg.role;\n return {\n role: role,\n content:\n typeof msg.content === 'string'\n ? msg.content\n : JSON.stringify(msg.content),\n name: msg.name,\n };\n }\n }) as any[];\n\n // Build tools array for OpenAI format\n let openaiTools: OpenAI.ChatCompletionTool[] | undefined;\n if (request.tools && request.tools.length > 0) {\n openaiTools = request.tools.map((tool) => ({\n type: 'function' as const,\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters as unknown as OpenAI.FunctionParameters,\n },\n }));\n }\n\n const response = await client.chat.completions.create({\n model: model,\n messages: messages,\n temperature: options.temperature,\n max_tokens: options.maxTokens,\n response_format: request.responseFormat,\n ...(openaiTools ? { tools: openaiTools } : {}),\n });\n\n const choice = response.choices[0];\n\n return {\n content: choice.message.content || '',\n model: response.model,\n usage: response.usage\n ? {\n inputTokens: response.usage.prompt_tokens,\n outputTokens: response.usage.completion_tokens,\n }\n : undefined,\n toolCalls: choice.message.tool_calls\n ?.filter((tc) => tc.type === 'function')\n .map((tc) => ({\n id: tc.id,\n type: 'function' as const,\n function: {\n name: (tc as any).function.name,\n arguments: (tc as any).function.arguments,\n },\n })),\n };\n } catch (error) {\n // Sanitize error to remove any API keys from error messages\n // Use spotclean for comprehensive error sanitization\n throw createSafeError(error as Error, { provider: 'openai' });\n }\n }\n\n /**\n * Execute a request with streaming response\n */\n async *executeStream(\n request: Request,\n options: ExecutionOptions = {}\n ): AsyncIterable<StreamChunk> {\n const apiKey = options.apiKey || process.env.OPENAI_API_KEY;\n \n if (!apiKey) {\n throw new Error('OpenAI API key is required. Set OPENAI_API_KEY environment variable.');\n }\n\n // Validate key format\n const validation = redactor.validateKey(apiKey, 'openai');\n if (!validation.valid) {\n throw new Error('Invalid OpenAI API key format');\n }\n\n try {\n const clientOptions: ConstructorParameters<typeof OpenAI>[0] = { apiKey };\n const proxyUrl = getProxyUrl();\n if (proxyUrl) {\n clientOptions.fetch = createProxyFetch(proxyUrl);\n }\n const client = new OpenAI(clientOptions);\n\n const model = options.model || request.model || 'gpt-4';\n\n // Convert messages to OpenAI format\n const messages = request.messages.map((msg) => {\n if (msg.role === 'tool') {\n return {\n role: 'tool',\n content: typeof msg.content === 'string'\n ? msg.content\n : JSON.stringify(msg.content),\n tool_call_id: (msg as any).tool_call_id || '',\n };\n } else if (msg.role === 'assistant' && (msg as any).tool_calls) {\n return {\n role: 'assistant',\n content: msg.content,\n tool_calls: (msg as any).tool_calls,\n };\n } else {\n const role = msg.role === 'developer' ? 'system' : msg.role;\n return {\n role: role,\n content:\n typeof msg.content === 'string'\n ? msg.content\n : JSON.stringify(msg.content),\n name: msg.name,\n };\n }\n }) as any[];\n\n // Build tools array\n let openaiTools: OpenAI.ChatCompletionTool[] | undefined;\n if (request.tools && request.tools.length > 0) {\n openaiTools = request.tools.map((tool) => ({\n type: 'function' as const,\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters as unknown as OpenAI.FunctionParameters,\n },\n }));\n }\n\n const stream = await client.chat.completions.create({\n model: model,\n messages: messages,\n temperature: options.temperature,\n max_tokens: options.maxTokens,\n stream: true,\n stream_options: { include_usage: true },\n ...(openaiTools ? { tools: openaiTools } : {}),\n });\n\n // Track tool calls being built\n const toolCallsInProgress: Map<number, { id: string; name: string; arguments: string }> = new Map();\n\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta;\n \n if (delta?.content) {\n yield { type: 'text', text: delta.content };\n }\n\n if (delta?.tool_calls) {\n for (const tc of delta.tool_calls) {\n const index = tc.index;\n \n if (tc.id) {\n // New tool call starting\n toolCallsInProgress.set(index, {\n id: tc.id,\n name: tc.function?.name || '',\n arguments: '',\n });\n yield {\n type: 'tool_call_start',\n toolCall: {\n id: tc.id,\n index,\n name: tc.function?.name,\n },\n };\n }\n \n if (tc.function?.arguments) {\n const toolCall = toolCallsInProgress.get(index);\n if (toolCall) {\n toolCall.arguments += tc.function.arguments;\n yield {\n type: 'tool_call_delta',\n toolCall: {\n index,\n argumentsDelta: tc.function.arguments,\n },\n };\n }\n }\n }\n }\n\n // Check for finish reason to emit tool_call_end\n if (chunk.choices[0]?.finish_reason === 'tool_calls') {\n for (const [index, toolCall] of toolCallsInProgress) {\n yield {\n type: 'tool_call_end',\n toolCall: {\n id: toolCall.id,\n index,\n name: toolCall.name,\n },\n };\n }\n }\n\n // Usage comes at the end\n if (chunk.usage) {\n yield {\n type: 'usage',\n usage: {\n inputTokens: chunk.usage.prompt_tokens,\n outputTokens: chunk.usage.completion_tokens,\n },\n };\n }\n }\n\n yield { type: 'done' };\n } catch (error) {\n throw createSafeError(error as Error, { provider: 'openai' });\n }\n }\n}\n\n/**\n * Create a new OpenAI provider instance\n */\nexport function createOpenAIProvider(): OpenAIProvider {\n return new OpenAIProvider();\n}\n\n/**\n * Package version\n */\nexport const VERSION = '0.0.1';\n\nexport default OpenAIProvider;\n"],"names":["undiciFetch"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/proxy.ts","../src/index.ts"],"sourcesContent":["/**\n * Proxy support for OpenAI API requests.\n *\n * When proxy environment variables are set, routes requests through the proxy\n * using undici's ProxyAgent. Respects NO_PROXY/no_proxy for bypass lists and\n * NODE_TLS_REJECT_UNAUTHORIZED for TLS verification.\n */\n\nimport { ProxyAgent, fetch as undiciFetch } from 'undici';\n\n/**\n * Get the proxy URL from environment variables.\n * Checks HTTPS_PROXY, https_proxy, HTTP_PROXY, http_proxy.\n */\nexport function getProxyUrl(): string | undefined {\n return (\n process.env.HTTPS_PROXY ||\n process.env.https_proxy ||\n process.env.HTTP_PROXY ||\n process.env.http_proxy ||\n undefined\n );\n}\n\n/**\n * Read TLS strict mode. Returns false only when NODE_TLS_REJECT_UNAUTHORIZED\n * is explicitly set to '0'.\n */\nexport function getStrictSSL(): boolean {\n return process.env.NODE_TLS_REJECT_UNAUTHORIZED !== '0';\n}\n\n/**\n * Check whether a target URL should bypass the proxy based on NO_PROXY / no_proxy.\n */\nexport function isProxyBypassed(targetUrl: string): boolean {\n const noProxy = process.env.NO_PROXY || process.env.no_proxy;\n if (!noProxy) {\n return false;\n }\n\n let hostname: string;\n try {\n hostname = new URL(targetUrl).hostname.toLowerCase();\n } catch {\n return false;\n }\n\n const entries = noProxy.split(',').map((e) => e.trim().toLowerCase());\n for (const entry of entries) {\n if (!entry) {\n continue;\n }\n if (entry === '*') {\n return true;\n }\n if (hostname === entry) {\n return true;\n }\n const suffix = entry.startsWith('.') ? entry : `.${entry}`;\n if (hostname.endsWith(suffix)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Create a fetch implementation that routes requests through an HTTP(S) proxy.\n * Respects TLS verification settings and NO_PROXY bypass lists.\n *\n * @param proxyUrl - The proxy URL (e.g. https://proxy.example.com:8080)\n * @returns A fetch function that uses ProxyAgent as the dispatcher\n */\nexport function createProxyFetch(proxyUrl: string): typeof fetch {\n const proxyAgent = new ProxyAgent({\n uri: proxyUrl,\n requestTls: { rejectUnauthorized: getStrictSSL() },\n });\n return ((input: any, init?: any) => {\n const targetUrl = typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.toString()\n : input.url;\n if (isProxyBypassed(targetUrl)) {\n return undiciFetch(input, init);\n }\n return undiciFetch(input, { ...init, dispatcher: proxyAgent });\n }) as any;\n}\n","/**\n * Execution OpenAI Package\n *\n * OpenAI provider implementation for LLM execution.\n *\n * @packageDocumentation\n */\n\nimport OpenAI from 'openai';\nimport { getRedactor } from '@utilarium/offrecord';\nimport { getProxyUrl, createProxyFetch } from './proxy.js';\nimport { \n createSafeError, \n configureErrorSanitizer,\n configureSecretGuard,\n} from '@utilarium/spotclean';\n\n// Register OpenAI API key patterns on module load\nconst redactor = getRedactor();\nredactor.register({\n name: 'openai',\n patterns: [\n /sk-[a-zA-Z0-9]{20,}/g,\n /sk-proj-[a-zA-Z0-9_-]+/g,\n ],\n validator: (key: string) => /^sk-(proj-)?[a-zA-Z0-9_-]{20,}$/.test(key),\n envVar: 'OPENAI_API_KEY',\n description: 'OpenAI API keys',\n});\n\n// Configure spotclean for error sanitization\nconfigureErrorSanitizer({\n enabled: true,\n environment: process.env.NODE_ENV === 'production' ? 'production' : 'development',\n includeCorrelationId: true,\n sanitizeStackTraces: process.env.NODE_ENV === 'production',\n maxMessageLength: 500,\n});\n\nconfigureSecretGuard({\n enabled: true,\n redactionText: '[REDACTED]',\n preservePartial: false,\n preserveLength: 0,\n customPatterns: [\n { name: 'openai', pattern: /sk-[a-zA-Z0-9]{20,}/g, description: 'OpenAI API key' },\n { name: 'openai-proj', pattern: /sk-proj-[a-zA-Z0-9_-]+/g, description: 'OpenAI project key' },\n ],\n});\n\n// ===== INLINE TYPES (from 'execution' package) =====\n// These types are duplicated here for build independence.\n// When 'execution' is published, these can be imported from there.\n\nexport type Model = string;\n\nexport interface Message {\n role: 'user' | 'assistant' | 'system' | 'developer' | 'tool';\n content: string | string[] | null;\n name?: string;\n}\n\nexport interface ToolParameterSchema {\n type: 'object';\n properties: Record<string, {\n type: string;\n description?: string;\n enum?: string[];\n items?: { type: string };\n default?: any;\n }>;\n required?: string[];\n additionalProperties?: boolean;\n}\n\nexport interface ToolDefinition {\n name: string;\n description: string;\n parameters: ToolParameterSchema;\n}\n\nexport type StreamChunkType = 'text' | 'tool_call_start' | 'tool_call_delta' | 'tool_call_end' | 'usage' | 'done';\n\nexport interface StreamChunk {\n type: StreamChunkType;\n text?: string;\n toolCall?: {\n id?: string;\n index?: number;\n name?: string;\n argumentsDelta?: string;\n };\n usage?: {\n inputTokens: number;\n outputTokens: number;\n };\n}\n\nexport interface Request {\n messages: Message[];\n model: Model;\n responseFormat?: any;\n validator?: any;\n tools?: ToolDefinition[];\n addMessage(message: Message): void;\n}\n\nexport interface ProviderResponse {\n content: string;\n model: string;\n usage?: {\n inputTokens: number;\n outputTokens: number;\n };\n toolCalls?: Array<{\n id: string;\n type: 'function';\n function: {\n name: string;\n arguments: string;\n };\n }>;\n}\n\nexport interface ExecutionOptions {\n apiKey?: string;\n model?: string;\n temperature?: number;\n maxTokens?: number;\n timeout?: number;\n retries?: number;\n}\n\nexport interface Provider {\n readonly name: string;\n execute(request: Request, options?: ExecutionOptions): Promise<ProviderResponse>;\n executeStream?(request: Request, options?: ExecutionOptions): AsyncIterable<StreamChunk>;\n supportsModel?(model: Model): boolean;\n}\n\n/**\n * OpenAI Provider implementation\n */\nexport class OpenAIProvider implements Provider {\n readonly name = 'openai';\n\n /**\n * Check if this provider supports a given model\n */\n supportsModel(model: Model): boolean {\n if (!model) return true; // Default to OpenAI\n return (\n model.startsWith('gpt') ||\n model.startsWith('o1') ||\n model.startsWith('o3') ||\n model.startsWith('o4')\n );\n }\n\n /**\n * Execute a request against OpenAI\n */\n async execute(\n request: Request,\n options: ExecutionOptions = {}\n ): Promise<ProviderResponse> {\n const apiKey = options.apiKey || process.env.OPENAI_API_KEY;\n \n if (!apiKey) {\n throw new Error('OpenAI API key is required. Set OPENAI_API_KEY environment variable.');\n }\n\n // Validate key format\n const validation = redactor.validateKey(apiKey, 'openai');\n if (!validation.valid) {\n throw new Error('Invalid OpenAI API key format');\n }\n\n try {\n const clientOptions: ConstructorParameters<typeof OpenAI>[0] = { apiKey };\n const proxyUrl = getProxyUrl();\n if (proxyUrl) {\n clientOptions.fetch = createProxyFetch(proxyUrl);\n }\n const client = new OpenAI(clientOptions);\n\n const model = options.model || request.model || 'gpt-4';\n\n // Convert messages to OpenAI format\n const messages = request.messages.map((msg) => {\n if (msg.role === 'tool') {\n // Tool result message\n return {\n role: 'tool',\n content: typeof msg.content === 'string'\n ? msg.content\n : JSON.stringify(msg.content),\n tool_call_id: (msg as any).tool_call_id || '',\n };\n } else if (msg.role === 'assistant' && (msg as any).tool_calls) {\n // Assistant message with tool calls\n return {\n role: 'assistant',\n content: msg.content,\n tool_calls: (msg as any).tool_calls,\n };\n } else {\n const role = msg.role === 'developer' ? 'system' : msg.role;\n return {\n role: role,\n content:\n typeof msg.content === 'string'\n ? msg.content\n : JSON.stringify(msg.content),\n name: msg.name,\n };\n }\n }) as any[];\n\n // Build tools array for OpenAI format\n let openaiTools: OpenAI.ChatCompletionTool[] | undefined;\n if (request.tools && request.tools.length > 0) {\n openaiTools = request.tools.map((tool) => ({\n type: 'function' as const,\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters as unknown as OpenAI.FunctionParameters,\n },\n }));\n }\n\n const response = await client.chat.completions.create({\n model: model,\n messages: messages,\n temperature: options.temperature,\n max_tokens: options.maxTokens,\n response_format: request.responseFormat,\n ...(openaiTools ? { tools: openaiTools } : {}),\n });\n\n const choice = response.choices[0];\n\n return {\n content: choice.message.content || '',\n model: response.model,\n usage: response.usage\n ? {\n inputTokens: response.usage.prompt_tokens,\n outputTokens: response.usage.completion_tokens,\n }\n : undefined,\n toolCalls: choice.message.tool_calls\n ?.filter((tc) => tc.type === 'function')\n .map((tc) => ({\n id: tc.id,\n type: 'function' as const,\n function: {\n name: (tc as any).function.name,\n arguments: (tc as any).function.arguments,\n },\n })),\n };\n } catch (error) {\n // Sanitize error to remove any API keys from error messages\n // Use spotclean for comprehensive error sanitization\n throw createSafeError(error as Error, { provider: 'openai' });\n }\n }\n\n /**\n * Execute a request with streaming response\n */\n async *executeStream(\n request: Request,\n options: ExecutionOptions = {}\n ): AsyncIterable<StreamChunk> {\n const apiKey = options.apiKey || process.env.OPENAI_API_KEY;\n \n if (!apiKey) {\n throw new Error('OpenAI API key is required. Set OPENAI_API_KEY environment variable.');\n }\n\n // Validate key format\n const validation = redactor.validateKey(apiKey, 'openai');\n if (!validation.valid) {\n throw new Error('Invalid OpenAI API key format');\n }\n\n try {\n const clientOptions: ConstructorParameters<typeof OpenAI>[0] = { apiKey };\n const proxyUrl = getProxyUrl();\n if (proxyUrl) {\n clientOptions.fetch = createProxyFetch(proxyUrl);\n }\n const client = new OpenAI(clientOptions);\n\n const model = options.model || request.model || 'gpt-4';\n\n // Convert messages to OpenAI format\n const messages = request.messages.map((msg) => {\n if (msg.role === 'tool') {\n return {\n role: 'tool',\n content: typeof msg.content === 'string'\n ? msg.content\n : JSON.stringify(msg.content),\n tool_call_id: (msg as any).tool_call_id || '',\n };\n } else if (msg.role === 'assistant' && (msg as any).tool_calls) {\n return {\n role: 'assistant',\n content: msg.content,\n tool_calls: (msg as any).tool_calls,\n };\n } else {\n const role = msg.role === 'developer' ? 'system' : msg.role;\n return {\n role: role,\n content:\n typeof msg.content === 'string'\n ? msg.content\n : JSON.stringify(msg.content),\n name: msg.name,\n };\n }\n }) as any[];\n\n // Build tools array\n let openaiTools: OpenAI.ChatCompletionTool[] | undefined;\n if (request.tools && request.tools.length > 0) {\n openaiTools = request.tools.map((tool) => ({\n type: 'function' as const,\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters as unknown as OpenAI.FunctionParameters,\n },\n }));\n }\n\n const stream = await client.chat.completions.create({\n model: model,\n messages: messages,\n temperature: options.temperature,\n max_tokens: options.maxTokens,\n stream: true,\n stream_options: { include_usage: true },\n ...(openaiTools ? { tools: openaiTools } : {}),\n });\n\n // Track tool calls being built\n const toolCallsInProgress: Map<number, { id: string; name: string; arguments: string }> = new Map();\n\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta;\n \n if (delta?.content) {\n yield { type: 'text', text: delta.content };\n }\n\n if (delta?.tool_calls) {\n for (const tc of delta.tool_calls) {\n const index = tc.index;\n \n if (tc.id) {\n // New tool call starting\n toolCallsInProgress.set(index, {\n id: tc.id,\n name: tc.function?.name || '',\n arguments: '',\n });\n yield {\n type: 'tool_call_start',\n toolCall: {\n id: tc.id,\n index,\n name: tc.function?.name,\n },\n };\n }\n\n if (tc.function?.name) {\n const existing = toolCallsInProgress.get(index);\n if (existing) {\n existing.name = tc.function.name;\n } else {\n toolCallsInProgress.set(index, {\n id: tc.id || '',\n name: tc.function.name,\n arguments: '',\n });\n }\n }\n \n if (tc.function?.arguments) {\n const toolCall = toolCallsInProgress.get(index);\n if (toolCall) {\n toolCall.arguments += tc.function.arguments;\n yield {\n type: 'tool_call_delta',\n toolCall: {\n index,\n argumentsDelta: tc.function.arguments,\n },\n };\n }\n }\n }\n }\n\n // Check for finish reason to emit tool_call_end\n if (chunk.choices[0]?.finish_reason === 'tool_calls') {\n for (const [index, toolCall] of toolCallsInProgress) {\n yield {\n type: 'tool_call_end',\n toolCall: {\n id: toolCall.id,\n index,\n name: toolCall.name,\n },\n };\n }\n }\n\n // Usage comes at the end\n if (chunk.usage) {\n yield {\n type: 'usage',\n usage: {\n inputTokens: chunk.usage.prompt_tokens,\n outputTokens: chunk.usage.completion_tokens,\n },\n };\n }\n }\n\n yield { type: 'done' };\n } catch (error) {\n throw createSafeError(error as Error, { provider: 'openai' });\n }\n }\n}\n\n/**\n * Create a new OpenAI provider instance\n */\nexport function createOpenAIProvider(): OpenAIProvider {\n return new OpenAIProvider();\n}\n\n/**\n * Package version\n */\nexport const VERSION = '0.0.1';\n\nexport default OpenAIProvider;\n"],"names":["undiciFetch"],"mappings":"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"}
|