@ziro-agent/openai 0.2.5 → 0.2.6

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.cjs CHANGED
@@ -257,6 +257,112 @@ var OpenAIChatModel = class {
257
257
  return res;
258
258
  }
259
259
  };
260
+ function uint8ToBase64(arr) {
261
+ let s = "";
262
+ for (let i = 0; i < arr.byteLength; i++) s += String.fromCharCode(arr[i]);
263
+ return typeof btoa !== "undefined" ? btoa(s) : Buffer.from(s, "binary").toString("base64");
264
+ }
265
+ function openAiAudioFormat(mime) {
266
+ const m = (mime ?? "").toLowerCase();
267
+ if (m.includes("wav")) return "wav";
268
+ if (m.includes("mp3") || m.includes("mpeg")) return "mp3";
269
+ return null;
270
+ }
271
+ function openAiGuessFilename(mime) {
272
+ const m = (mime ?? "").toLowerCase();
273
+ if (m.includes("pdf")) return "document.pdf";
274
+ if (m.includes("plain")) return "document.txt";
275
+ return "document.bin";
276
+ }
277
+ function openAiGuessVideoFilename(mime) {
278
+ const m = (mime ?? "").toLowerCase();
279
+ if (m.includes("webm")) return "clip.webm";
280
+ if (m.includes("quicktime")) return "clip.mov";
281
+ return "clip.mp4";
282
+ }
283
+ function mapOpenAiUserContentPart(p) {
284
+ if (p.type === "text") return { type: "text", text: p.text };
285
+ if (p.type === "image") {
286
+ const url = typeof p.image === "string" ? p.image : p.image instanceof URL ? p.image.toString() : `data:${p.mimeType ?? "image/png"};base64,${uint8ToBase64(p.image)}`;
287
+ return { type: "image_url", image_url: { url } };
288
+ }
289
+ if (p.type === "audio") {
290
+ const r = core.resolveMediaInput(p.audio);
291
+ if ("url" in r) {
292
+ throw new core.UnsupportedPartError({
293
+ partType: "audio",
294
+ provider: "openai",
295
+ message: "OpenAI `input_audio` requires inline WAV/MP3 as a Uint8Array or a `data:` URL. The SDK does not fetch remote URLs."
296
+ });
297
+ }
298
+ const fmt = openAiAudioFormat(r.mimeType ?? p.mimeType);
299
+ if (!fmt) {
300
+ throw new core.UnsupportedPartError({
301
+ partType: "audio",
302
+ provider: "openai",
303
+ message: `OpenAI supports input_audio with format "wav" or "mp3" only (got mime "${r.mimeType ?? p.mimeType ?? "unknown"}").`
304
+ });
305
+ }
306
+ return { type: "input_audio", input_audio: { data: r.base64, format: fmt } };
307
+ }
308
+ if (p.type === "file") {
309
+ if (typeof p.file === "string" && p.file.startsWith("file-")) {
310
+ return {
311
+ type: "file",
312
+ file: {
313
+ file_id: p.file,
314
+ ...p.filename !== void 0 ? { filename: p.filename } : {}
315
+ }
316
+ };
317
+ }
318
+ const r = core.resolveMediaInput(p.file);
319
+ if ("url" in r) {
320
+ throw new core.UnsupportedPartError({
321
+ partType: "file",
322
+ provider: "openai",
323
+ message: "OpenAI file parts need a Files API id (`file-\u2026`), or inline bytes / a base64 `data:` URL. The SDK does not fetch remote URLs."
324
+ });
325
+ }
326
+ return {
327
+ type: "file",
328
+ file: {
329
+ file_data: r.base64,
330
+ filename: p.filename ?? openAiGuessFilename(r.mimeType ?? p.mimeType)
331
+ }
332
+ };
333
+ }
334
+ if (p.type === "video") {
335
+ if (typeof p.video === "string" && p.video.startsWith("file-")) {
336
+ return {
337
+ type: "file",
338
+ file: {
339
+ file_id: p.video,
340
+ ...p.filename !== void 0 ? { filename: p.filename } : {}
341
+ }
342
+ };
343
+ }
344
+ const r = core.resolveMediaInput(p.video);
345
+ if ("url" in r) {
346
+ throw new core.UnsupportedPartError({
347
+ partType: "video",
348
+ provider: "openai",
349
+ message: "OpenAI video parts need a Files API id (`file-\u2026`), or inline bytes / a base64 `data:` URL. The SDK does not fetch remote URLs."
350
+ });
351
+ }
352
+ return {
353
+ type: "file",
354
+ file: {
355
+ file_data: r.base64,
356
+ filename: p.filename ?? openAiGuessVideoFilename(r.mimeType ?? p.mimeType)
357
+ }
358
+ };
359
+ }
360
+ throw new core.UnsupportedPartError({
361
+ partType: p.type ?? "unknown",
362
+ provider: "openai",
363
+ message: "Unexpected content part in user message."
364
+ });
365
+ }
260
366
  function toOpenAIMessage(m) {
261
367
  switch (m.role) {
262
368
  case "system": {
@@ -273,14 +379,7 @@ function toOpenAIMessage(m) {
273
379
  }
274
380
  return {
275
381
  role: "user",
276
- content: m.content.map((p) => {
277
- if (p.type === "text") return { type: "text", text: p.text };
278
- if (p.type === "image") {
279
- const url = typeof p.image === "string" ? p.image : p.image instanceof URL ? p.image.toString() : `data:${p.mimeType ?? "image/png"};base64,${uint8ToBase64(p.image)}`;
280
- return { type: "image_url", image_url: { url } };
281
- }
282
- return p;
283
- })
382
+ content: m.content.map((p) => mapOpenAiUserContentPart(p))
284
383
  };
285
384
  }
286
385
  case "assistant": {
@@ -320,11 +419,6 @@ function defaultOutputCap(modelId) {
320
419
  if (modelId.startsWith("gpt-5")) return 32768;
321
420
  return 16384;
322
421
  }
323
- function uint8ToBase64(arr) {
324
- let s = "";
325
- for (let i = 0; i < arr.byteLength; i++) s += String.fromCharCode(arr[i]);
326
- return typeof btoa !== "undefined" ? btoa(s) : Buffer.from(s, "binary").toString("base64");
327
- }
328
422
  function safeParseJSON(text) {
329
423
  if (!text) return {};
330
424
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/util/sse.ts","../src/openai-chat-model.ts","../src/openai-provider.ts"],"names":["APICallError","estimateTokensFromMessages","pricing","getPricing"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Parse a Server-Sent Events stream into a sequence of `data:` payloads\n * (the bit between `data: ` and the blank line). Comment lines, retries, and\n * other SSE features we don't need are ignored.\n */\nexport async function* parseSSE(body: ReadableStream<Uint8Array>): AsyncIterable<string> {\n const reader = body.getReader();\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n if (buffer.length > 0) {\n const event = extractEvent(buffer);\n if (event !== null) yield event;\n }\n return;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n while (true) {\n const sepIdx = findEventBoundary(buffer);\n if (sepIdx === -1) break;\n const block = buffer.slice(0, sepIdx);\n buffer = buffer.slice(sepIdx).replace(/^(\\r?\\n){2}/, '');\n const event = extractEvent(block);\n if (event !== null) yield event;\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction findEventBoundary(s: string): number {\n const i1 = s.indexOf('\\n\\n');\n const i2 = s.indexOf('\\r\\n\\r\\n');\n if (i1 === -1) return i2;\n if (i2 === -1) return i1;\n return Math.min(i1, i2);\n}\n\nfunction extractEvent(block: string): string | null {\n const lines = block.split(/\\r?\\n/);\n const data: string[] = [];\n for (const line of lines) {\n if (line.startsWith('data:')) {\n data.push(line.slice(5).replace(/^ /, ''));\n }\n }\n if (data.length === 0) return null;\n return data.join('\\n');\n}\n","import {\n APICallError,\n type CostEstimate,\n estimateTokensFromMessages,\n type FinishReason,\n type LanguageModel,\n type ModelCallOptions,\n type ModelGenerateResult,\n type ModelStreamPart,\n type NormalizedMessage,\n type TokenUsage,\n type ToolCallPart,\n} from '@ziro-agent/core';\nimport { getPricing } from '@ziro-agent/core/pricing';\nimport { parseSSE } from './util/sse.js';\n\n/**\n * The set of OpenAI chat model ids we explicitly know about. Other strings are\n * still allowed via the `(string & {})` trick — we don't want to lock users out\n * when OpenAI ships a new model before we update the SDK.\n */\nexport type OpenAIChatModelId =\n // Current flagships (verified against openai.com/api/pricing 2026-04-20).\n | 'gpt-5.4'\n | 'gpt-5.4-mini'\n | 'gpt-5.4-nano'\n // Legacy still served on the API.\n | 'gpt-4o'\n | 'gpt-4o-mini'\n // Open string for any model id we haven't enumerated — Budget Guard\n // pre-flight will return `pricingAvailable: false` for unknown ids and\n // fall back to post-call enforcement only.\n | (string & {});\n\ninterface OpenAIChatModelConfig {\n modelId: OpenAIChatModelId;\n baseURL: string;\n headers: Record<string, string>;\n fetcher: typeof fetch;\n}\n\nexport class OpenAIChatModel implements LanguageModel {\n readonly provider = 'openai';\n readonly modelId: string;\n private readonly config: OpenAIChatModelConfig;\n\n constructor(config: OpenAIChatModelConfig) {\n this.modelId = config.modelId;\n this.config = config;\n }\n\n async generate(options: ModelCallOptions): Promise<ModelGenerateResult> {\n const body = this.buildBody(options, false);\n const res = await this.fetch('/chat/completions', body, options);\n const json = (await res.json()) as OpenAIChatCompletion;\n\n const choice = json.choices?.[0];\n if (!choice) {\n throw new APICallError({\n message: 'OpenAI response contained no choices.',\n url: `${this.config.baseURL}/chat/completions`,\n statusCode: res.status,\n responseBody: JSON.stringify(json),\n });\n }\n\n const text = choice.message?.content ?? '';\n const toolCalls: ToolCallPart[] =\n choice.message?.tool_calls?.map((tc) => ({\n type: 'tool-call' as const,\n toolCallId: tc.id,\n toolName: tc.function.name,\n args: safeParseJSON(tc.function.arguments),\n })) ?? [];\n\n return {\n text,\n content: [...(text.length > 0 ? [{ type: 'text' as const, text }] : []), ...toolCalls],\n toolCalls,\n finishReason: mapFinishReason(choice.finish_reason),\n usage: mapUsage(json.usage),\n rawResponse: json,\n };\n }\n\n async stream(options: ModelCallOptions): Promise<ReadableStream<ModelStreamPart>> {\n const body = this.buildBody(options, true);\n const res = await this.fetch('/chat/completions', body, options);\n if (!res.body) {\n throw new APICallError({\n message: 'OpenAI streaming response has no body.',\n statusCode: res.status,\n });\n }\n\n const sse = parseSSE(res.body);\n\n return new ReadableStream<ModelStreamPart>({\n async start(controller) {\n const toolCallsByIndex = new Map<\n number,\n { id: string; name: string; argsBuffer: string }\n >();\n let usage: TokenUsage | undefined;\n let finish: FinishReason = 'unknown';\n\n try {\n for await (const event of sse) {\n if (event === '[DONE]') break;\n const chunk = JSON.parse(event) as OpenAIChatChunk;\n\n const choice = chunk.choices?.[0];\n if (!choice) {\n if (chunk.usage) usage = mapUsage(chunk.usage);\n continue;\n }\n\n const delta = choice.delta;\n if (delta?.content) {\n controller.enqueue({ type: 'text-delta', textDelta: delta.content });\n }\n\n if (delta?.tool_calls) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index;\n let entry = toolCallsByIndex.get(idx);\n if (!entry) {\n entry = {\n id: tc.id ?? `call_${idx}`,\n name: tc.function?.name ?? '',\n argsBuffer: '',\n };\n toolCallsByIndex.set(idx, entry);\n }\n if (tc.id && !entry.id) entry.id = tc.id;\n if (tc.function?.name) entry.name = tc.function.name;\n if (tc.function?.arguments) {\n entry.argsBuffer += tc.function.arguments;\n controller.enqueue({\n type: 'tool-call-delta',\n toolCallId: entry.id,\n toolName: entry.name,\n argsDelta: tc.function.arguments,\n });\n }\n }\n }\n\n if (choice.finish_reason) {\n finish = mapFinishReason(choice.finish_reason);\n }\n if (chunk.usage) usage = mapUsage(chunk.usage);\n }\n\n for (const entry of toolCallsByIndex.values()) {\n controller.enqueue({\n type: 'tool-call',\n toolCallId: entry.id,\n toolName: entry.name,\n args: safeParseJSON(entry.argsBuffer),\n });\n }\n\n controller.enqueue({\n type: 'finish',\n finishReason: finish,\n usage: usage ?? {},\n });\n controller.close();\n } catch (err) {\n controller.enqueue({ type: 'error', error: err });\n controller.close();\n }\n },\n });\n }\n\n /**\n * Pre-flight cost estimate. Conservative bounds: assumes the model fills\n * `maxTokens` for the upper bound, and emits ~16 tokens for the lower\n * bound. Returns `pricingAvailable: false` when the SDK has no row for\n * this model id — Budget Guard will then skip USD pre-flight enforcement.\n */\n estimateCost(options: ModelCallOptions): CostEstimate {\n const inputTokens = estimateTokensFromMessages(asChatMessages(options.messages));\n const maxOut = options.maxTokens ?? defaultOutputCap(this.modelId);\n const minOut = Math.min(16, maxOut);\n const pricing = getPricing(this.provider, this.modelId);\n if (!pricing) {\n return {\n minTokens: inputTokens + minOut,\n maxTokens: inputTokens + maxOut,\n minUsd: 0,\n maxUsd: 0,\n pricingAvailable: false,\n };\n }\n return {\n minTokens: inputTokens + minOut,\n maxTokens: inputTokens + maxOut,\n minUsd:\n (inputTokens * pricing.inputPer1M) / 1_000_000 + (minOut * pricing.outputPer1M) / 1_000_000,\n maxUsd:\n (inputTokens * pricing.inputPer1M) / 1_000_000 + (maxOut * pricing.outputPer1M) / 1_000_000,\n pricingAvailable: true,\n };\n }\n\n private buildBody(options: ModelCallOptions, stream: boolean): Record<string, unknown> {\n const body: Record<string, unknown> = {\n model: this.modelId,\n messages: options.messages.map(toOpenAIMessage),\n };\n if (stream) {\n body.stream = true;\n body.stream_options = { include_usage: true };\n }\n if (options.tools?.length) {\n body.tools = options.tools.map((t) => ({\n type: 'function',\n function: {\n name: t.name,\n ...(t.description !== undefined ? { description: t.description } : {}),\n parameters: t.parameters,\n },\n }));\n }\n if (options.toolChoice !== undefined) {\n if (typeof options.toolChoice === 'string') {\n body.tool_choice = options.toolChoice;\n } else {\n body.tool_choice = {\n type: 'function',\n function: { name: options.toolChoice.toolName },\n };\n }\n }\n if (options.temperature !== undefined) body.temperature = options.temperature;\n if (options.topP !== undefined) body.top_p = options.topP;\n if (options.maxTokens !== undefined) body.max_tokens = options.maxTokens;\n if (options.stopSequences !== undefined) body.stop = options.stopSequences;\n if (options.seed !== undefined) body.seed = options.seed;\n if (options.providerOptions) Object.assign(body, options.providerOptions);\n return body;\n }\n\n private async fetch(path: string, body: unknown, options: ModelCallOptions): Promise<Response> {\n const url = `${this.config.baseURL}${path}`;\n const headers = { ...this.config.headers, ...options.headers };\n const init: RequestInit = {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n };\n if (options.abortSignal) init.signal = options.abortSignal;\n\n const res = await this.config.fetcher(url, init);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new APICallError({\n message: `OpenAI API error: ${res.status} ${res.statusText}`,\n url,\n statusCode: res.status,\n responseBody: text,\n });\n }\n return res;\n }\n}\n\nfunction toOpenAIMessage(m: NormalizedMessage): unknown {\n switch (m.role) {\n case 'system': {\n const text = m.content\n .filter((p) => p.type === 'text')\n .map((p) => (p as { text: string }).text)\n .join('');\n return { role: 'system', content: text };\n }\n case 'user': {\n const allText = m.content.every((p) => p.type === 'text');\n if (allText) {\n return {\n role: 'user',\n content: m.content.map((p) => (p as { text: string }).text).join(''),\n };\n }\n return {\n role: 'user',\n content: m.content.map((p) => {\n if (p.type === 'text') return { type: 'text', text: p.text };\n if (p.type === 'image') {\n const url =\n typeof p.image === 'string'\n ? p.image\n : p.image instanceof URL\n ? p.image.toString()\n : `data:${p.mimeType ?? 'image/png'};base64,${uint8ToBase64(p.image)}`;\n return { type: 'image_url', image_url: { url } };\n }\n return p;\n }),\n };\n }\n case 'assistant': {\n const toolCalls = m.content.filter((p) => p.type === 'tool-call');\n const text = m.content\n .filter((p) => p.type === 'text')\n .map((p) => (p as { text: string }).text)\n .join('');\n const out: Record<string, unknown> = { role: 'assistant', content: text || null };\n if (toolCalls.length > 0) {\n out.tool_calls = toolCalls.map((tc) => ({\n id: (tc as ToolCallPart).toolCallId,\n type: 'function',\n function: {\n name: (tc as ToolCallPart).toolName,\n arguments: JSON.stringify((tc as ToolCallPart).args ?? {}),\n },\n }));\n }\n return out;\n }\n case 'tool': {\n // OpenAI requires one tool message per result.\n // The caller will need to flatten before passing. We pick the first.\n const first = m.content[0];\n if (!first || first.type !== 'tool-result') {\n return { role: 'tool', content: '', tool_call_id: '' };\n }\n return {\n role: 'tool',\n content: typeof first.result === 'string' ? first.result : JSON.stringify(first.result),\n tool_call_id: first.toolCallId,\n };\n }\n }\n}\n\n/**\n * Bridge `NormalizedMessage[]` (always `ContentPart[]`) to the public\n * `ChatMessage[]` shape `estimateTokensFromMessages` accepts. The estimator\n * only inspects `role` + `content`, so the structural cast is safe.\n */\nfunction asChatMessages(\n messages: NormalizedMessage[],\n): Parameters<typeof estimateTokensFromMessages>[0] {\n return messages as unknown as Parameters<typeof estimateTokensFromMessages>[0];\n}\n\n/**\n * Default output token cap when the caller didn't pass `maxTokens`. Mirrors\n * OpenAI's typical model defaults; intentionally generous so pre-flight\n * over- rather than underestimates.\n */\nfunction defaultOutputCap(modelId: string): number {\n if (modelId.startsWith('o1') || modelId.startsWith('o3')) return 100_000;\n if (modelId.startsWith('gpt-5')) return 32_768;\n return 16_384;\n}\n\nfunction uint8ToBase64(arr: Uint8Array): string {\n let s = '';\n for (let i = 0; i < arr.byteLength; i++) s += String.fromCharCode(arr[i] as number);\n return typeof btoa !== 'undefined' ? btoa(s) : Buffer.from(s, 'binary').toString('base64');\n}\n\nfunction safeParseJSON(text: string): unknown {\n if (!text) return {};\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction mapFinishReason(reason: string | null | undefined): FinishReason {\n switch (reason) {\n case 'stop':\n return 'stop';\n case 'length':\n return 'length';\n case 'tool_calls':\n case 'function_call':\n return 'tool-calls';\n case 'content_filter':\n return 'content-filter';\n case null:\n case undefined:\n return 'unknown';\n default:\n return 'other';\n }\n}\n\nfunction mapUsage(u: OpenAIUsage | undefined): TokenUsage {\n if (!u) return {};\n const out: TokenUsage = {};\n if (u.prompt_tokens !== undefined) out.promptTokens = u.prompt_tokens;\n if (u.completion_tokens !== undefined) out.completionTokens = u.completion_tokens;\n if (u.total_tokens !== undefined) out.totalTokens = u.total_tokens;\n if (u.prompt_tokens_details?.cached_tokens !== undefined) {\n out.cachedPromptTokens = u.prompt_tokens_details.cached_tokens;\n }\n if (u.completion_tokens_details?.reasoning_tokens !== undefined) {\n out.reasoningTokens = u.completion_tokens_details.reasoning_tokens;\n }\n return out;\n}\n\ninterface OpenAIUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n prompt_tokens_details?: { cached_tokens?: number };\n completion_tokens_details?: { reasoning_tokens?: number };\n}\n\ninterface OpenAIChatCompletion {\n choices?: Array<{\n message?: {\n content?: string;\n tool_calls?: Array<{\n id: string;\n function: { name: string; arguments: string };\n }>;\n };\n finish_reason?: string | null;\n }>;\n usage?: OpenAIUsage;\n}\n\ninterface OpenAIChatChunk {\n choices?: Array<{\n delta?: {\n content?: string;\n tool_calls?: Array<{\n index: number;\n id?: string;\n function?: { name?: string; arguments?: string };\n }>;\n };\n finish_reason?: string | null;\n }>;\n usage?: OpenAIUsage;\n}\n","import type { LanguageModel } from '@ziro-agent/core';\nimport { OpenAIChatModel, type OpenAIChatModelId } from './openai-chat-model.js';\n\nexport interface OpenAIProviderOptions {\n /** Defaults to `process.env.OPENAI_API_KEY`. */\n apiKey?: string;\n /** Override the base URL (useful for proxies / Azure / OpenRouter). */\n baseURL?: string;\n /** Optional organization id (`OpenAI-Organization` header). */\n organization?: string;\n /** Optional project id (`OpenAI-Project` header). */\n project?: string;\n /** Extra default headers attached to every request. */\n headers?: Record<string, string>;\n /** Custom `fetch`. Defaults to `globalThis.fetch`. */\n fetch?: typeof fetch;\n}\n\nexport interface OpenAIProvider {\n (modelId: OpenAIChatModelId): LanguageModel;\n chat(modelId: OpenAIChatModelId): LanguageModel;\n}\n\nexport function createOpenAI(options: OpenAIProviderOptions = {}): OpenAIProvider {\n const apiKey = options.apiKey ?? loadEnv('OPENAI_API_KEY');\n const baseURL = options.baseURL ?? 'https://api.openai.com/v1';\n const fetcher = options.fetch ?? globalThis.fetch;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n if (apiKey) headers.Authorization = `Bearer ${apiKey}`;\n if (options.organization) headers['OpenAI-Organization'] = options.organization;\n if (options.project) headers['OpenAI-Project'] = options.project;\n\n const make = (modelId: OpenAIChatModelId): LanguageModel =>\n new OpenAIChatModel({\n modelId,\n baseURL,\n headers,\n fetcher,\n });\n\n const provider = ((modelId: OpenAIChatModelId) => make(modelId)) as OpenAIProvider;\n provider.chat = make;\n return provider;\n}\n\n/** Default singleton provider — reads `OPENAI_API_KEY` from env. */\nexport const openai: OpenAIProvider = createOpenAI();\n\nfunction loadEnv(name: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n"]}
1
+ {"version":3,"sources":["../src/util/sse.ts","../src/openai-chat-model.ts","../src/openai-provider.ts"],"names":["APICallError","estimateTokensFromMessages","pricing","getPricing","resolveMediaInput","UnsupportedPartError"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Parse a Server-Sent Events stream into a sequence of `data:` payloads\n * (the bit between `data: ` and the blank line). Comment lines, retries, and\n * other SSE features we don't need are ignored.\n */\nexport async function* parseSSE(body: ReadableStream<Uint8Array>): AsyncIterable<string> {\n const reader = body.getReader();\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n if (buffer.length > 0) {\n const event = extractEvent(buffer);\n if (event !== null) yield event;\n }\n return;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n while (true) {\n const sepIdx = findEventBoundary(buffer);\n if (sepIdx === -1) break;\n const block = buffer.slice(0, sepIdx);\n buffer = buffer.slice(sepIdx).replace(/^(\\r?\\n){2}/, '');\n const event = extractEvent(block);\n if (event !== null) yield event;\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction findEventBoundary(s: string): number {\n const i1 = s.indexOf('\\n\\n');\n const i2 = s.indexOf('\\r\\n\\r\\n');\n if (i1 === -1) return i2;\n if (i2 === -1) return i1;\n return Math.min(i1, i2);\n}\n\nfunction extractEvent(block: string): string | null {\n const lines = block.split(/\\r?\\n/);\n const data: string[] = [];\n for (const line of lines) {\n if (line.startsWith('data:')) {\n data.push(line.slice(5).replace(/^ /, ''));\n }\n }\n if (data.length === 0) return null;\n return data.join('\\n');\n}\n","import type { ContentPart } from '@ziro-agent/core';\nimport {\n APICallError,\n type CostEstimate,\n estimateTokensFromMessages,\n type FinishReason,\n type LanguageModel,\n type ModelCallOptions,\n type ModelGenerateResult,\n type ModelStreamPart,\n type NormalizedMessage,\n resolveMediaInput,\n type TokenUsage,\n type ToolCallPart,\n UnsupportedPartError,\n} from '@ziro-agent/core';\nimport { getPricing } from '@ziro-agent/core/pricing';\nimport { parseSSE } from './util/sse.js';\n\n/**\n * The set of OpenAI chat model ids we explicitly know about. Other strings are\n * still allowed via the `(string & {})` trick — we don't want to lock users out\n * when OpenAI ships a new model before we update the SDK.\n */\nexport type OpenAIChatModelId =\n // Current flagships (verified against openai.com/api/pricing 2026-04-20).\n | 'gpt-5.4'\n | 'gpt-5.4-mini'\n | 'gpt-5.4-nano'\n // Legacy still served on the API.\n | 'gpt-4o'\n | 'gpt-4o-mini'\n // Open string for any model id we haven't enumerated — Budget Guard\n // pre-flight will return `pricingAvailable: false` for unknown ids and\n // fall back to post-call enforcement only.\n | (string & {});\n\ninterface OpenAIChatModelConfig {\n modelId: OpenAIChatModelId;\n baseURL: string;\n headers: Record<string, string>;\n fetcher: typeof fetch;\n}\n\nexport class OpenAIChatModel implements LanguageModel {\n readonly provider = 'openai';\n readonly modelId: string;\n private readonly config: OpenAIChatModelConfig;\n\n constructor(config: OpenAIChatModelConfig) {\n this.modelId = config.modelId;\n this.config = config;\n }\n\n async generate(options: ModelCallOptions): Promise<ModelGenerateResult> {\n const body = this.buildBody(options, false);\n const res = await this.fetch('/chat/completions', body, options);\n const json = (await res.json()) as OpenAIChatCompletion;\n\n const choice = json.choices?.[0];\n if (!choice) {\n throw new APICallError({\n message: 'OpenAI response contained no choices.',\n url: `${this.config.baseURL}/chat/completions`,\n statusCode: res.status,\n responseBody: JSON.stringify(json),\n });\n }\n\n const text = choice.message?.content ?? '';\n const toolCalls: ToolCallPart[] =\n choice.message?.tool_calls?.map((tc) => ({\n type: 'tool-call' as const,\n toolCallId: tc.id,\n toolName: tc.function.name,\n args: safeParseJSON(tc.function.arguments),\n })) ?? [];\n\n return {\n text,\n content: [...(text.length > 0 ? [{ type: 'text' as const, text }] : []), ...toolCalls],\n toolCalls,\n finishReason: mapFinishReason(choice.finish_reason),\n usage: mapUsage(json.usage),\n rawResponse: json,\n };\n }\n\n async stream(options: ModelCallOptions): Promise<ReadableStream<ModelStreamPart>> {\n const body = this.buildBody(options, true);\n const res = await this.fetch('/chat/completions', body, options);\n if (!res.body) {\n throw new APICallError({\n message: 'OpenAI streaming response has no body.',\n statusCode: res.status,\n });\n }\n\n const sse = parseSSE(res.body);\n\n return new ReadableStream<ModelStreamPart>({\n async start(controller) {\n const toolCallsByIndex = new Map<\n number,\n { id: string; name: string; argsBuffer: string }\n >();\n let usage: TokenUsage | undefined;\n let finish: FinishReason = 'unknown';\n\n try {\n for await (const event of sse) {\n if (event === '[DONE]') break;\n const chunk = JSON.parse(event) as OpenAIChatChunk;\n\n const choice = chunk.choices?.[0];\n if (!choice) {\n if (chunk.usage) usage = mapUsage(chunk.usage);\n continue;\n }\n\n const delta = choice.delta;\n if (delta?.content) {\n controller.enqueue({ type: 'text-delta', textDelta: delta.content });\n }\n\n if (delta?.tool_calls) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index;\n let entry = toolCallsByIndex.get(idx);\n if (!entry) {\n entry = {\n id: tc.id ?? `call_${idx}`,\n name: tc.function?.name ?? '',\n argsBuffer: '',\n };\n toolCallsByIndex.set(idx, entry);\n }\n if (tc.id && !entry.id) entry.id = tc.id;\n if (tc.function?.name) entry.name = tc.function.name;\n if (tc.function?.arguments) {\n entry.argsBuffer += tc.function.arguments;\n controller.enqueue({\n type: 'tool-call-delta',\n toolCallId: entry.id,\n toolName: entry.name,\n argsDelta: tc.function.arguments,\n });\n }\n }\n }\n\n if (choice.finish_reason) {\n finish = mapFinishReason(choice.finish_reason);\n }\n if (chunk.usage) usage = mapUsage(chunk.usage);\n }\n\n for (const entry of toolCallsByIndex.values()) {\n controller.enqueue({\n type: 'tool-call',\n toolCallId: entry.id,\n toolName: entry.name,\n args: safeParseJSON(entry.argsBuffer),\n });\n }\n\n controller.enqueue({\n type: 'finish',\n finishReason: finish,\n usage: usage ?? {},\n });\n controller.close();\n } catch (err) {\n controller.enqueue({ type: 'error', error: err });\n controller.close();\n }\n },\n });\n }\n\n /**\n * Pre-flight cost estimate. Conservative bounds: assumes the model fills\n * `maxTokens` for the upper bound, and emits ~16 tokens for the lower\n * bound. Returns `pricingAvailable: false` when the SDK has no row for\n * this model id — Budget Guard will then skip USD pre-flight enforcement.\n */\n estimateCost(options: ModelCallOptions): CostEstimate {\n const inputTokens = estimateTokensFromMessages(asChatMessages(options.messages));\n const maxOut = options.maxTokens ?? defaultOutputCap(this.modelId);\n const minOut = Math.min(16, maxOut);\n const pricing = getPricing(this.provider, this.modelId);\n if (!pricing) {\n return {\n minTokens: inputTokens + minOut,\n maxTokens: inputTokens + maxOut,\n minUsd: 0,\n maxUsd: 0,\n pricingAvailable: false,\n };\n }\n return {\n minTokens: inputTokens + minOut,\n maxTokens: inputTokens + maxOut,\n minUsd:\n (inputTokens * pricing.inputPer1M) / 1_000_000 + (minOut * pricing.outputPer1M) / 1_000_000,\n maxUsd:\n (inputTokens * pricing.inputPer1M) / 1_000_000 + (maxOut * pricing.outputPer1M) / 1_000_000,\n pricingAvailable: true,\n };\n }\n\n private buildBody(options: ModelCallOptions, stream: boolean): Record<string, unknown> {\n const body: Record<string, unknown> = {\n model: this.modelId,\n messages: options.messages.map(toOpenAIMessage),\n };\n if (stream) {\n body.stream = true;\n body.stream_options = { include_usage: true };\n }\n if (options.tools?.length) {\n body.tools = options.tools.map((t) => ({\n type: 'function',\n function: {\n name: t.name,\n ...(t.description !== undefined ? { description: t.description } : {}),\n parameters: t.parameters,\n },\n }));\n }\n if (options.toolChoice !== undefined) {\n if (typeof options.toolChoice === 'string') {\n body.tool_choice = options.toolChoice;\n } else {\n body.tool_choice = {\n type: 'function',\n function: { name: options.toolChoice.toolName },\n };\n }\n }\n if (options.temperature !== undefined) body.temperature = options.temperature;\n if (options.topP !== undefined) body.top_p = options.topP;\n if (options.maxTokens !== undefined) body.max_tokens = options.maxTokens;\n if (options.stopSequences !== undefined) body.stop = options.stopSequences;\n if (options.seed !== undefined) body.seed = options.seed;\n if (options.providerOptions) Object.assign(body, options.providerOptions);\n return body;\n }\n\n private async fetch(path: string, body: unknown, options: ModelCallOptions): Promise<Response> {\n const url = `${this.config.baseURL}${path}`;\n const headers = { ...this.config.headers, ...options.headers };\n const init: RequestInit = {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n };\n if (options.abortSignal) init.signal = options.abortSignal;\n\n const res = await this.config.fetcher(url, init);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new APICallError({\n message: `OpenAI API error: ${res.status} ${res.statusText}`,\n url,\n statusCode: res.status,\n responseBody: text,\n });\n }\n return res;\n }\n}\n\nfunction uint8ToBase64(arr: Uint8Array): string {\n let s = '';\n for (let i = 0; i < arr.byteLength; i++) s += String.fromCharCode(arr[i] as number);\n return typeof btoa !== 'undefined' ? btoa(s) : Buffer.from(s, 'binary').toString('base64');\n}\n\nfunction openAiAudioFormat(mime?: string): 'wav' | 'mp3' | null {\n const m = (mime ?? '').toLowerCase();\n if (m.includes('wav')) return 'wav';\n if (m.includes('mp3') || m.includes('mpeg')) return 'mp3';\n return null;\n}\n\nfunction openAiGuessFilename(mime?: string): string {\n const m = (mime ?? '').toLowerCase();\n if (m.includes('pdf')) return 'document.pdf';\n if (m.includes('plain')) return 'document.txt';\n return 'document.bin';\n}\n\nfunction openAiGuessVideoFilename(mime?: string): string {\n const m = (mime ?? '').toLowerCase();\n if (m.includes('webm')) return 'clip.webm';\n if (m.includes('quicktime')) return 'clip.mov';\n return 'clip.mp4';\n}\n\nfunction mapOpenAiUserContentPart(p: ContentPart): unknown {\n if (p.type === 'text') return { type: 'text', text: p.text };\n if (p.type === 'image') {\n const url =\n typeof p.image === 'string'\n ? p.image\n : p.image instanceof URL\n ? p.image.toString()\n : `data:${p.mimeType ?? 'image/png'};base64,${uint8ToBase64(p.image)}`;\n return { type: 'image_url', image_url: { url } };\n }\n if (p.type === 'audio') {\n const r = resolveMediaInput(p.audio);\n if ('url' in r) {\n throw new UnsupportedPartError({\n partType: 'audio',\n provider: 'openai',\n message:\n 'OpenAI `input_audio` requires inline WAV/MP3 as a Uint8Array or a `data:` URL. The SDK does not fetch remote URLs.',\n });\n }\n const fmt = openAiAudioFormat(r.mimeType ?? p.mimeType);\n if (!fmt) {\n throw new UnsupportedPartError({\n partType: 'audio',\n provider: 'openai',\n message: `OpenAI supports input_audio with format \"wav\" or \"mp3\" only (got mime \"${r.mimeType ?? p.mimeType ?? 'unknown'}\").`,\n });\n }\n return { type: 'input_audio', input_audio: { data: r.base64, format: fmt } };\n }\n if (p.type === 'file') {\n if (typeof p.file === 'string' && p.file.startsWith('file-')) {\n return {\n type: 'file',\n file: {\n file_id: p.file,\n ...(p.filename !== undefined ? { filename: p.filename } : {}),\n },\n };\n }\n const r = resolveMediaInput(p.file);\n if ('url' in r) {\n throw new UnsupportedPartError({\n partType: 'file',\n provider: 'openai',\n message:\n 'OpenAI file parts need a Files API id (`file-…`), or inline bytes / a base64 `data:` URL. The SDK does not fetch remote URLs.',\n });\n }\n return {\n type: 'file',\n file: {\n file_data: r.base64,\n filename: p.filename ?? openAiGuessFilename(r.mimeType ?? p.mimeType),\n },\n };\n }\n if (p.type === 'video') {\n if (typeof p.video === 'string' && p.video.startsWith('file-')) {\n return {\n type: 'file',\n file: {\n file_id: p.video,\n ...(p.filename !== undefined ? { filename: p.filename } : {}),\n },\n };\n }\n const r = resolveMediaInput(p.video);\n if ('url' in r) {\n throw new UnsupportedPartError({\n partType: 'video',\n provider: 'openai',\n message:\n 'OpenAI video parts need a Files API id (`file-…`), or inline bytes / a base64 `data:` URL. The SDK does not fetch remote URLs.',\n });\n }\n return {\n type: 'file',\n file: {\n file_data: r.base64,\n filename: p.filename ?? openAiGuessVideoFilename(r.mimeType ?? p.mimeType),\n },\n };\n }\n throw new UnsupportedPartError({\n partType: (p as { type?: string }).type ?? 'unknown',\n provider: 'openai',\n message: 'Unexpected content part in user message.',\n });\n}\n\nfunction toOpenAIMessage(m: NormalizedMessage): unknown {\n switch (m.role) {\n case 'system': {\n const text = m.content\n .filter((p) => p.type === 'text')\n .map((p) => (p as { text: string }).text)\n .join('');\n return { role: 'system', content: text };\n }\n case 'user': {\n const allText = m.content.every((p) => p.type === 'text');\n if (allText) {\n return {\n role: 'user',\n content: m.content.map((p) => (p as { text: string }).text).join(''),\n };\n }\n return {\n role: 'user',\n content: m.content.map((p) => mapOpenAiUserContentPart(p)),\n };\n }\n case 'assistant': {\n const toolCalls = m.content.filter((p) => p.type === 'tool-call');\n const text = m.content\n .filter((p) => p.type === 'text')\n .map((p) => (p as { text: string }).text)\n .join('');\n const out: Record<string, unknown> = { role: 'assistant', content: text || null };\n if (toolCalls.length > 0) {\n out.tool_calls = toolCalls.map((tc) => ({\n id: (tc as ToolCallPart).toolCallId,\n type: 'function',\n function: {\n name: (tc as ToolCallPart).toolName,\n arguments: JSON.stringify((tc as ToolCallPart).args ?? {}),\n },\n }));\n }\n return out;\n }\n case 'tool': {\n // OpenAI requires one tool message per result.\n // The caller will need to flatten before passing. We pick the first.\n const first = m.content[0];\n if (!first || first.type !== 'tool-result') {\n return { role: 'tool', content: '', tool_call_id: '' };\n }\n return {\n role: 'tool',\n content: typeof first.result === 'string' ? first.result : JSON.stringify(first.result),\n tool_call_id: first.toolCallId,\n };\n }\n }\n}\n\n/**\n * Bridge `NormalizedMessage[]` (always `ContentPart[]`) to the public\n * `ChatMessage[]` shape `estimateTokensFromMessages` accepts. The estimator\n * only inspects `role` + `content`, so the structural cast is safe.\n */\nfunction asChatMessages(\n messages: NormalizedMessage[],\n): Parameters<typeof estimateTokensFromMessages>[0] {\n return messages as unknown as Parameters<typeof estimateTokensFromMessages>[0];\n}\n\n/**\n * Default output token cap when the caller didn't pass `maxTokens`. Mirrors\n * OpenAI's typical model defaults; intentionally generous so pre-flight\n * over- rather than underestimates.\n */\nfunction defaultOutputCap(modelId: string): number {\n if (modelId.startsWith('o1') || modelId.startsWith('o3')) return 100_000;\n if (modelId.startsWith('gpt-5')) return 32_768;\n return 16_384;\n}\n\nfunction safeParseJSON(text: string): unknown {\n if (!text) return {};\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction mapFinishReason(reason: string | null | undefined): FinishReason {\n switch (reason) {\n case 'stop':\n return 'stop';\n case 'length':\n return 'length';\n case 'tool_calls':\n case 'function_call':\n return 'tool-calls';\n case 'content_filter':\n return 'content-filter';\n case null:\n case undefined:\n return 'unknown';\n default:\n return 'other';\n }\n}\n\nfunction mapUsage(u: OpenAIUsage | undefined): TokenUsage {\n if (!u) return {};\n const out: TokenUsage = {};\n if (u.prompt_tokens !== undefined) out.promptTokens = u.prompt_tokens;\n if (u.completion_tokens !== undefined) out.completionTokens = u.completion_tokens;\n if (u.total_tokens !== undefined) out.totalTokens = u.total_tokens;\n if (u.prompt_tokens_details?.cached_tokens !== undefined) {\n out.cachedPromptTokens = u.prompt_tokens_details.cached_tokens;\n }\n if (u.completion_tokens_details?.reasoning_tokens !== undefined) {\n out.reasoningTokens = u.completion_tokens_details.reasoning_tokens;\n }\n return out;\n}\n\ninterface OpenAIUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n prompt_tokens_details?: { cached_tokens?: number };\n completion_tokens_details?: { reasoning_tokens?: number };\n}\n\ninterface OpenAIChatCompletion {\n choices?: Array<{\n message?: {\n content?: string;\n tool_calls?: Array<{\n id: string;\n function: { name: string; arguments: string };\n }>;\n };\n finish_reason?: string | null;\n }>;\n usage?: OpenAIUsage;\n}\n\ninterface OpenAIChatChunk {\n choices?: Array<{\n delta?: {\n content?: string;\n tool_calls?: Array<{\n index: number;\n id?: string;\n function?: { name?: string; arguments?: string };\n }>;\n };\n finish_reason?: string | null;\n }>;\n usage?: OpenAIUsage;\n}\n","import type { LanguageModel } from '@ziro-agent/core';\nimport { OpenAIChatModel, type OpenAIChatModelId } from './openai-chat-model.js';\n\nexport interface OpenAIProviderOptions {\n /** Defaults to `process.env.OPENAI_API_KEY`. */\n apiKey?: string;\n /** Override the base URL (useful for proxies / Azure / OpenRouter). */\n baseURL?: string;\n /** Optional organization id (`OpenAI-Organization` header). */\n organization?: string;\n /** Optional project id (`OpenAI-Project` header). */\n project?: string;\n /** Extra default headers attached to every request. */\n headers?: Record<string, string>;\n /** Custom `fetch`. Defaults to `globalThis.fetch`. */\n fetch?: typeof fetch;\n}\n\nexport interface OpenAIProvider {\n (modelId: OpenAIChatModelId): LanguageModel;\n chat(modelId: OpenAIChatModelId): LanguageModel;\n}\n\nexport function createOpenAI(options: OpenAIProviderOptions = {}): OpenAIProvider {\n const apiKey = options.apiKey ?? loadEnv('OPENAI_API_KEY');\n const baseURL = options.baseURL ?? 'https://api.openai.com/v1';\n const fetcher = options.fetch ?? globalThis.fetch;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n if (apiKey) headers.Authorization = `Bearer ${apiKey}`;\n if (options.organization) headers['OpenAI-Organization'] = options.organization;\n if (options.project) headers['OpenAI-Project'] = options.project;\n\n const make = (modelId: OpenAIChatModelId): LanguageModel =>\n new OpenAIChatModel({\n modelId,\n baseURL,\n headers,\n fetcher,\n });\n\n const provider = ((modelId: OpenAIChatModelId) => make(modelId)) as OpenAIProvider;\n provider.chat = make;\n return provider;\n}\n\n/** Default singleton provider — reads `OPENAI_API_KEY` from env. */\nexport const openai: OpenAIProvider = createOpenAI();\n\nfunction loadEnv(name: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n"]}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { APICallError, estimateTokensFromMessages } from '@ziro-agent/core';
1
+ import { APICallError, estimateTokensFromMessages, resolveMediaInput, UnsupportedPartError } from '@ziro-agent/core';
2
2
  import { getPricing } from '@ziro-agent/core/pricing';
3
3
 
4
4
  // src/openai-chat-model.ts
@@ -255,6 +255,112 @@ var OpenAIChatModel = class {
255
255
  return res;
256
256
  }
257
257
  };
258
+ function uint8ToBase64(arr) {
259
+ let s = "";
260
+ for (let i = 0; i < arr.byteLength; i++) s += String.fromCharCode(arr[i]);
261
+ return typeof btoa !== "undefined" ? btoa(s) : Buffer.from(s, "binary").toString("base64");
262
+ }
263
+ function openAiAudioFormat(mime) {
264
+ const m = (mime ?? "").toLowerCase();
265
+ if (m.includes("wav")) return "wav";
266
+ if (m.includes("mp3") || m.includes("mpeg")) return "mp3";
267
+ return null;
268
+ }
269
+ function openAiGuessFilename(mime) {
270
+ const m = (mime ?? "").toLowerCase();
271
+ if (m.includes("pdf")) return "document.pdf";
272
+ if (m.includes("plain")) return "document.txt";
273
+ return "document.bin";
274
+ }
275
+ function openAiGuessVideoFilename(mime) {
276
+ const m = (mime ?? "").toLowerCase();
277
+ if (m.includes("webm")) return "clip.webm";
278
+ if (m.includes("quicktime")) return "clip.mov";
279
+ return "clip.mp4";
280
+ }
281
+ function mapOpenAiUserContentPart(p) {
282
+ if (p.type === "text") return { type: "text", text: p.text };
283
+ if (p.type === "image") {
284
+ const url = typeof p.image === "string" ? p.image : p.image instanceof URL ? p.image.toString() : `data:${p.mimeType ?? "image/png"};base64,${uint8ToBase64(p.image)}`;
285
+ return { type: "image_url", image_url: { url } };
286
+ }
287
+ if (p.type === "audio") {
288
+ const r = resolveMediaInput(p.audio);
289
+ if ("url" in r) {
290
+ throw new UnsupportedPartError({
291
+ partType: "audio",
292
+ provider: "openai",
293
+ message: "OpenAI `input_audio` requires inline WAV/MP3 as a Uint8Array or a `data:` URL. The SDK does not fetch remote URLs."
294
+ });
295
+ }
296
+ const fmt = openAiAudioFormat(r.mimeType ?? p.mimeType);
297
+ if (!fmt) {
298
+ throw new UnsupportedPartError({
299
+ partType: "audio",
300
+ provider: "openai",
301
+ message: `OpenAI supports input_audio with format "wav" or "mp3" only (got mime "${r.mimeType ?? p.mimeType ?? "unknown"}").`
302
+ });
303
+ }
304
+ return { type: "input_audio", input_audio: { data: r.base64, format: fmt } };
305
+ }
306
+ if (p.type === "file") {
307
+ if (typeof p.file === "string" && p.file.startsWith("file-")) {
308
+ return {
309
+ type: "file",
310
+ file: {
311
+ file_id: p.file,
312
+ ...p.filename !== void 0 ? { filename: p.filename } : {}
313
+ }
314
+ };
315
+ }
316
+ const r = resolveMediaInput(p.file);
317
+ if ("url" in r) {
318
+ throw new UnsupportedPartError({
319
+ partType: "file",
320
+ provider: "openai",
321
+ message: "OpenAI file parts need a Files API id (`file-\u2026`), or inline bytes / a base64 `data:` URL. The SDK does not fetch remote URLs."
322
+ });
323
+ }
324
+ return {
325
+ type: "file",
326
+ file: {
327
+ file_data: r.base64,
328
+ filename: p.filename ?? openAiGuessFilename(r.mimeType ?? p.mimeType)
329
+ }
330
+ };
331
+ }
332
+ if (p.type === "video") {
333
+ if (typeof p.video === "string" && p.video.startsWith("file-")) {
334
+ return {
335
+ type: "file",
336
+ file: {
337
+ file_id: p.video,
338
+ ...p.filename !== void 0 ? { filename: p.filename } : {}
339
+ }
340
+ };
341
+ }
342
+ const r = resolveMediaInput(p.video);
343
+ if ("url" in r) {
344
+ throw new UnsupportedPartError({
345
+ partType: "video",
346
+ provider: "openai",
347
+ message: "OpenAI video parts need a Files API id (`file-\u2026`), or inline bytes / a base64 `data:` URL. The SDK does not fetch remote URLs."
348
+ });
349
+ }
350
+ return {
351
+ type: "file",
352
+ file: {
353
+ file_data: r.base64,
354
+ filename: p.filename ?? openAiGuessVideoFilename(r.mimeType ?? p.mimeType)
355
+ }
356
+ };
357
+ }
358
+ throw new UnsupportedPartError({
359
+ partType: p.type ?? "unknown",
360
+ provider: "openai",
361
+ message: "Unexpected content part in user message."
362
+ });
363
+ }
258
364
  function toOpenAIMessage(m) {
259
365
  switch (m.role) {
260
366
  case "system": {
@@ -271,14 +377,7 @@ function toOpenAIMessage(m) {
271
377
  }
272
378
  return {
273
379
  role: "user",
274
- content: m.content.map((p) => {
275
- if (p.type === "text") return { type: "text", text: p.text };
276
- if (p.type === "image") {
277
- const url = typeof p.image === "string" ? p.image : p.image instanceof URL ? p.image.toString() : `data:${p.mimeType ?? "image/png"};base64,${uint8ToBase64(p.image)}`;
278
- return { type: "image_url", image_url: { url } };
279
- }
280
- return p;
281
- })
380
+ content: m.content.map((p) => mapOpenAiUserContentPart(p))
282
381
  };
283
382
  }
284
383
  case "assistant": {
@@ -318,11 +417,6 @@ function defaultOutputCap(modelId) {
318
417
  if (modelId.startsWith("gpt-5")) return 32768;
319
418
  return 16384;
320
419
  }
321
- function uint8ToBase64(arr) {
322
- let s = "";
323
- for (let i = 0; i < arr.byteLength; i++) s += String.fromCharCode(arr[i]);
324
- return typeof btoa !== "undefined" ? btoa(s) : Buffer.from(s, "binary").toString("base64");
325
- }
326
420
  function safeParseJSON(text) {
327
421
  if (!text) return {};
328
422
  try {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/util/sse.ts","../src/openai-chat-model.ts","../src/openai-provider.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Parse a Server-Sent Events stream into a sequence of `data:` payloads\n * (the bit between `data: ` and the blank line). Comment lines, retries, and\n * other SSE features we don't need are ignored.\n */\nexport async function* parseSSE(body: ReadableStream<Uint8Array>): AsyncIterable<string> {\n const reader = body.getReader();\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n if (buffer.length > 0) {\n const event = extractEvent(buffer);\n if (event !== null) yield event;\n }\n return;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n while (true) {\n const sepIdx = findEventBoundary(buffer);\n if (sepIdx === -1) break;\n const block = buffer.slice(0, sepIdx);\n buffer = buffer.slice(sepIdx).replace(/^(\\r?\\n){2}/, '');\n const event = extractEvent(block);\n if (event !== null) yield event;\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction findEventBoundary(s: string): number {\n const i1 = s.indexOf('\\n\\n');\n const i2 = s.indexOf('\\r\\n\\r\\n');\n if (i1 === -1) return i2;\n if (i2 === -1) return i1;\n return Math.min(i1, i2);\n}\n\nfunction extractEvent(block: string): string | null {\n const lines = block.split(/\\r?\\n/);\n const data: string[] = [];\n for (const line of lines) {\n if (line.startsWith('data:')) {\n data.push(line.slice(5).replace(/^ /, ''));\n }\n }\n if (data.length === 0) return null;\n return data.join('\\n');\n}\n","import {\n APICallError,\n type CostEstimate,\n estimateTokensFromMessages,\n type FinishReason,\n type LanguageModel,\n type ModelCallOptions,\n type ModelGenerateResult,\n type ModelStreamPart,\n type NormalizedMessage,\n type TokenUsage,\n type ToolCallPart,\n} from '@ziro-agent/core';\nimport { getPricing } from '@ziro-agent/core/pricing';\nimport { parseSSE } from './util/sse.js';\n\n/**\n * The set of OpenAI chat model ids we explicitly know about. Other strings are\n * still allowed via the `(string & {})` trick — we don't want to lock users out\n * when OpenAI ships a new model before we update the SDK.\n */\nexport type OpenAIChatModelId =\n // Current flagships (verified against openai.com/api/pricing 2026-04-20).\n | 'gpt-5.4'\n | 'gpt-5.4-mini'\n | 'gpt-5.4-nano'\n // Legacy still served on the API.\n | 'gpt-4o'\n | 'gpt-4o-mini'\n // Open string for any model id we haven't enumerated — Budget Guard\n // pre-flight will return `pricingAvailable: false` for unknown ids and\n // fall back to post-call enforcement only.\n | (string & {});\n\ninterface OpenAIChatModelConfig {\n modelId: OpenAIChatModelId;\n baseURL: string;\n headers: Record<string, string>;\n fetcher: typeof fetch;\n}\n\nexport class OpenAIChatModel implements LanguageModel {\n readonly provider = 'openai';\n readonly modelId: string;\n private readonly config: OpenAIChatModelConfig;\n\n constructor(config: OpenAIChatModelConfig) {\n this.modelId = config.modelId;\n this.config = config;\n }\n\n async generate(options: ModelCallOptions): Promise<ModelGenerateResult> {\n const body = this.buildBody(options, false);\n const res = await this.fetch('/chat/completions', body, options);\n const json = (await res.json()) as OpenAIChatCompletion;\n\n const choice = json.choices?.[0];\n if (!choice) {\n throw new APICallError({\n message: 'OpenAI response contained no choices.',\n url: `${this.config.baseURL}/chat/completions`,\n statusCode: res.status,\n responseBody: JSON.stringify(json),\n });\n }\n\n const text = choice.message?.content ?? '';\n const toolCalls: ToolCallPart[] =\n choice.message?.tool_calls?.map((tc) => ({\n type: 'tool-call' as const,\n toolCallId: tc.id,\n toolName: tc.function.name,\n args: safeParseJSON(tc.function.arguments),\n })) ?? [];\n\n return {\n text,\n content: [...(text.length > 0 ? [{ type: 'text' as const, text }] : []), ...toolCalls],\n toolCalls,\n finishReason: mapFinishReason(choice.finish_reason),\n usage: mapUsage(json.usage),\n rawResponse: json,\n };\n }\n\n async stream(options: ModelCallOptions): Promise<ReadableStream<ModelStreamPart>> {\n const body = this.buildBody(options, true);\n const res = await this.fetch('/chat/completions', body, options);\n if (!res.body) {\n throw new APICallError({\n message: 'OpenAI streaming response has no body.',\n statusCode: res.status,\n });\n }\n\n const sse = parseSSE(res.body);\n\n return new ReadableStream<ModelStreamPart>({\n async start(controller) {\n const toolCallsByIndex = new Map<\n number,\n { id: string; name: string; argsBuffer: string }\n >();\n let usage: TokenUsage | undefined;\n let finish: FinishReason = 'unknown';\n\n try {\n for await (const event of sse) {\n if (event === '[DONE]') break;\n const chunk = JSON.parse(event) as OpenAIChatChunk;\n\n const choice = chunk.choices?.[0];\n if (!choice) {\n if (chunk.usage) usage = mapUsage(chunk.usage);\n continue;\n }\n\n const delta = choice.delta;\n if (delta?.content) {\n controller.enqueue({ type: 'text-delta', textDelta: delta.content });\n }\n\n if (delta?.tool_calls) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index;\n let entry = toolCallsByIndex.get(idx);\n if (!entry) {\n entry = {\n id: tc.id ?? `call_${idx}`,\n name: tc.function?.name ?? '',\n argsBuffer: '',\n };\n toolCallsByIndex.set(idx, entry);\n }\n if (tc.id && !entry.id) entry.id = tc.id;\n if (tc.function?.name) entry.name = tc.function.name;\n if (tc.function?.arguments) {\n entry.argsBuffer += tc.function.arguments;\n controller.enqueue({\n type: 'tool-call-delta',\n toolCallId: entry.id,\n toolName: entry.name,\n argsDelta: tc.function.arguments,\n });\n }\n }\n }\n\n if (choice.finish_reason) {\n finish = mapFinishReason(choice.finish_reason);\n }\n if (chunk.usage) usage = mapUsage(chunk.usage);\n }\n\n for (const entry of toolCallsByIndex.values()) {\n controller.enqueue({\n type: 'tool-call',\n toolCallId: entry.id,\n toolName: entry.name,\n args: safeParseJSON(entry.argsBuffer),\n });\n }\n\n controller.enqueue({\n type: 'finish',\n finishReason: finish,\n usage: usage ?? {},\n });\n controller.close();\n } catch (err) {\n controller.enqueue({ type: 'error', error: err });\n controller.close();\n }\n },\n });\n }\n\n /**\n * Pre-flight cost estimate. Conservative bounds: assumes the model fills\n * `maxTokens` for the upper bound, and emits ~16 tokens for the lower\n * bound. Returns `pricingAvailable: false` when the SDK has no row for\n * this model id — Budget Guard will then skip USD pre-flight enforcement.\n */\n estimateCost(options: ModelCallOptions): CostEstimate {\n const inputTokens = estimateTokensFromMessages(asChatMessages(options.messages));\n const maxOut = options.maxTokens ?? defaultOutputCap(this.modelId);\n const minOut = Math.min(16, maxOut);\n const pricing = getPricing(this.provider, this.modelId);\n if (!pricing) {\n return {\n minTokens: inputTokens + minOut,\n maxTokens: inputTokens + maxOut,\n minUsd: 0,\n maxUsd: 0,\n pricingAvailable: false,\n };\n }\n return {\n minTokens: inputTokens + minOut,\n maxTokens: inputTokens + maxOut,\n minUsd:\n (inputTokens * pricing.inputPer1M) / 1_000_000 + (minOut * pricing.outputPer1M) / 1_000_000,\n maxUsd:\n (inputTokens * pricing.inputPer1M) / 1_000_000 + (maxOut * pricing.outputPer1M) / 1_000_000,\n pricingAvailable: true,\n };\n }\n\n private buildBody(options: ModelCallOptions, stream: boolean): Record<string, unknown> {\n const body: Record<string, unknown> = {\n model: this.modelId,\n messages: options.messages.map(toOpenAIMessage),\n };\n if (stream) {\n body.stream = true;\n body.stream_options = { include_usage: true };\n }\n if (options.tools?.length) {\n body.tools = options.tools.map((t) => ({\n type: 'function',\n function: {\n name: t.name,\n ...(t.description !== undefined ? { description: t.description } : {}),\n parameters: t.parameters,\n },\n }));\n }\n if (options.toolChoice !== undefined) {\n if (typeof options.toolChoice === 'string') {\n body.tool_choice = options.toolChoice;\n } else {\n body.tool_choice = {\n type: 'function',\n function: { name: options.toolChoice.toolName },\n };\n }\n }\n if (options.temperature !== undefined) body.temperature = options.temperature;\n if (options.topP !== undefined) body.top_p = options.topP;\n if (options.maxTokens !== undefined) body.max_tokens = options.maxTokens;\n if (options.stopSequences !== undefined) body.stop = options.stopSequences;\n if (options.seed !== undefined) body.seed = options.seed;\n if (options.providerOptions) Object.assign(body, options.providerOptions);\n return body;\n }\n\n private async fetch(path: string, body: unknown, options: ModelCallOptions): Promise<Response> {\n const url = `${this.config.baseURL}${path}`;\n const headers = { ...this.config.headers, ...options.headers };\n const init: RequestInit = {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n };\n if (options.abortSignal) init.signal = options.abortSignal;\n\n const res = await this.config.fetcher(url, init);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new APICallError({\n message: `OpenAI API error: ${res.status} ${res.statusText}`,\n url,\n statusCode: res.status,\n responseBody: text,\n });\n }\n return res;\n }\n}\n\nfunction toOpenAIMessage(m: NormalizedMessage): unknown {\n switch (m.role) {\n case 'system': {\n const text = m.content\n .filter((p) => p.type === 'text')\n .map((p) => (p as { text: string }).text)\n .join('');\n return { role: 'system', content: text };\n }\n case 'user': {\n const allText = m.content.every((p) => p.type === 'text');\n if (allText) {\n return {\n role: 'user',\n content: m.content.map((p) => (p as { text: string }).text).join(''),\n };\n }\n return {\n role: 'user',\n content: m.content.map((p) => {\n if (p.type === 'text') return { type: 'text', text: p.text };\n if (p.type === 'image') {\n const url =\n typeof p.image === 'string'\n ? p.image\n : p.image instanceof URL\n ? p.image.toString()\n : `data:${p.mimeType ?? 'image/png'};base64,${uint8ToBase64(p.image)}`;\n return { type: 'image_url', image_url: { url } };\n }\n return p;\n }),\n };\n }\n case 'assistant': {\n const toolCalls = m.content.filter((p) => p.type === 'tool-call');\n const text = m.content\n .filter((p) => p.type === 'text')\n .map((p) => (p as { text: string }).text)\n .join('');\n const out: Record<string, unknown> = { role: 'assistant', content: text || null };\n if (toolCalls.length > 0) {\n out.tool_calls = toolCalls.map((tc) => ({\n id: (tc as ToolCallPart).toolCallId,\n type: 'function',\n function: {\n name: (tc as ToolCallPart).toolName,\n arguments: JSON.stringify((tc as ToolCallPart).args ?? {}),\n },\n }));\n }\n return out;\n }\n case 'tool': {\n // OpenAI requires one tool message per result.\n // The caller will need to flatten before passing. We pick the first.\n const first = m.content[0];\n if (!first || first.type !== 'tool-result') {\n return { role: 'tool', content: '', tool_call_id: '' };\n }\n return {\n role: 'tool',\n content: typeof first.result === 'string' ? first.result : JSON.stringify(first.result),\n tool_call_id: first.toolCallId,\n };\n }\n }\n}\n\n/**\n * Bridge `NormalizedMessage[]` (always `ContentPart[]`) to the public\n * `ChatMessage[]` shape `estimateTokensFromMessages` accepts. The estimator\n * only inspects `role` + `content`, so the structural cast is safe.\n */\nfunction asChatMessages(\n messages: NormalizedMessage[],\n): Parameters<typeof estimateTokensFromMessages>[0] {\n return messages as unknown as Parameters<typeof estimateTokensFromMessages>[0];\n}\n\n/**\n * Default output token cap when the caller didn't pass `maxTokens`. Mirrors\n * OpenAI's typical model defaults; intentionally generous so pre-flight\n * over- rather than underestimates.\n */\nfunction defaultOutputCap(modelId: string): number {\n if (modelId.startsWith('o1') || modelId.startsWith('o3')) return 100_000;\n if (modelId.startsWith('gpt-5')) return 32_768;\n return 16_384;\n}\n\nfunction uint8ToBase64(arr: Uint8Array): string {\n let s = '';\n for (let i = 0; i < arr.byteLength; i++) s += String.fromCharCode(arr[i] as number);\n return typeof btoa !== 'undefined' ? btoa(s) : Buffer.from(s, 'binary').toString('base64');\n}\n\nfunction safeParseJSON(text: string): unknown {\n if (!text) return {};\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction mapFinishReason(reason: string | null | undefined): FinishReason {\n switch (reason) {\n case 'stop':\n return 'stop';\n case 'length':\n return 'length';\n case 'tool_calls':\n case 'function_call':\n return 'tool-calls';\n case 'content_filter':\n return 'content-filter';\n case null:\n case undefined:\n return 'unknown';\n default:\n return 'other';\n }\n}\n\nfunction mapUsage(u: OpenAIUsage | undefined): TokenUsage {\n if (!u) return {};\n const out: TokenUsage = {};\n if (u.prompt_tokens !== undefined) out.promptTokens = u.prompt_tokens;\n if (u.completion_tokens !== undefined) out.completionTokens = u.completion_tokens;\n if (u.total_tokens !== undefined) out.totalTokens = u.total_tokens;\n if (u.prompt_tokens_details?.cached_tokens !== undefined) {\n out.cachedPromptTokens = u.prompt_tokens_details.cached_tokens;\n }\n if (u.completion_tokens_details?.reasoning_tokens !== undefined) {\n out.reasoningTokens = u.completion_tokens_details.reasoning_tokens;\n }\n return out;\n}\n\ninterface OpenAIUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n prompt_tokens_details?: { cached_tokens?: number };\n completion_tokens_details?: { reasoning_tokens?: number };\n}\n\ninterface OpenAIChatCompletion {\n choices?: Array<{\n message?: {\n content?: string;\n tool_calls?: Array<{\n id: string;\n function: { name: string; arguments: string };\n }>;\n };\n finish_reason?: string | null;\n }>;\n usage?: OpenAIUsage;\n}\n\ninterface OpenAIChatChunk {\n choices?: Array<{\n delta?: {\n content?: string;\n tool_calls?: Array<{\n index: number;\n id?: string;\n function?: { name?: string; arguments?: string };\n }>;\n };\n finish_reason?: string | null;\n }>;\n usage?: OpenAIUsage;\n}\n","import type { LanguageModel } from '@ziro-agent/core';\nimport { OpenAIChatModel, type OpenAIChatModelId } from './openai-chat-model.js';\n\nexport interface OpenAIProviderOptions {\n /** Defaults to `process.env.OPENAI_API_KEY`. */\n apiKey?: string;\n /** Override the base URL (useful for proxies / Azure / OpenRouter). */\n baseURL?: string;\n /** Optional organization id (`OpenAI-Organization` header). */\n organization?: string;\n /** Optional project id (`OpenAI-Project` header). */\n project?: string;\n /** Extra default headers attached to every request. */\n headers?: Record<string, string>;\n /** Custom `fetch`. Defaults to `globalThis.fetch`. */\n fetch?: typeof fetch;\n}\n\nexport interface OpenAIProvider {\n (modelId: OpenAIChatModelId): LanguageModel;\n chat(modelId: OpenAIChatModelId): LanguageModel;\n}\n\nexport function createOpenAI(options: OpenAIProviderOptions = {}): OpenAIProvider {\n const apiKey = options.apiKey ?? loadEnv('OPENAI_API_KEY');\n const baseURL = options.baseURL ?? 'https://api.openai.com/v1';\n const fetcher = options.fetch ?? globalThis.fetch;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n if (apiKey) headers.Authorization = `Bearer ${apiKey}`;\n if (options.organization) headers['OpenAI-Organization'] = options.organization;\n if (options.project) headers['OpenAI-Project'] = options.project;\n\n const make = (modelId: OpenAIChatModelId): LanguageModel =>\n new OpenAIChatModel({\n modelId,\n baseURL,\n headers,\n fetcher,\n });\n\n const provider = ((modelId: OpenAIChatModelId) => make(modelId)) as OpenAIProvider;\n provider.chat = make;\n return provider;\n}\n\n/** Default singleton provider — reads `OPENAI_API_KEY` from env. */\nexport const openai: OpenAIProvider = createOpenAI();\n\nfunction loadEnv(name: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n"]}
1
+ {"version":3,"sources":["../src/util/sse.ts","../src/openai-chat-model.ts","../src/openai-provider.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Parse a Server-Sent Events stream into a sequence of `data:` payloads\n * (the bit between `data: ` and the blank line). Comment lines, retries, and\n * other SSE features we don't need are ignored.\n */\nexport async function* parseSSE(body: ReadableStream<Uint8Array>): AsyncIterable<string> {\n const reader = body.getReader();\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n if (buffer.length > 0) {\n const event = extractEvent(buffer);\n if (event !== null) yield event;\n }\n return;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n while (true) {\n const sepIdx = findEventBoundary(buffer);\n if (sepIdx === -1) break;\n const block = buffer.slice(0, sepIdx);\n buffer = buffer.slice(sepIdx).replace(/^(\\r?\\n){2}/, '');\n const event = extractEvent(block);\n if (event !== null) yield event;\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction findEventBoundary(s: string): number {\n const i1 = s.indexOf('\\n\\n');\n const i2 = s.indexOf('\\r\\n\\r\\n');\n if (i1 === -1) return i2;\n if (i2 === -1) return i1;\n return Math.min(i1, i2);\n}\n\nfunction extractEvent(block: string): string | null {\n const lines = block.split(/\\r?\\n/);\n const data: string[] = [];\n for (const line of lines) {\n if (line.startsWith('data:')) {\n data.push(line.slice(5).replace(/^ /, ''));\n }\n }\n if (data.length === 0) return null;\n return data.join('\\n');\n}\n","import type { ContentPart } from '@ziro-agent/core';\nimport {\n APICallError,\n type CostEstimate,\n estimateTokensFromMessages,\n type FinishReason,\n type LanguageModel,\n type ModelCallOptions,\n type ModelGenerateResult,\n type ModelStreamPart,\n type NormalizedMessage,\n resolveMediaInput,\n type TokenUsage,\n type ToolCallPart,\n UnsupportedPartError,\n} from '@ziro-agent/core';\nimport { getPricing } from '@ziro-agent/core/pricing';\nimport { parseSSE } from './util/sse.js';\n\n/**\n * The set of OpenAI chat model ids we explicitly know about. Other strings are\n * still allowed via the `(string & {})` trick — we don't want to lock users out\n * when OpenAI ships a new model before we update the SDK.\n */\nexport type OpenAIChatModelId =\n // Current flagships (verified against openai.com/api/pricing 2026-04-20).\n | 'gpt-5.4'\n | 'gpt-5.4-mini'\n | 'gpt-5.4-nano'\n // Legacy still served on the API.\n | 'gpt-4o'\n | 'gpt-4o-mini'\n // Open string for any model id we haven't enumerated — Budget Guard\n // pre-flight will return `pricingAvailable: false` for unknown ids and\n // fall back to post-call enforcement only.\n | (string & {});\n\ninterface OpenAIChatModelConfig {\n modelId: OpenAIChatModelId;\n baseURL: string;\n headers: Record<string, string>;\n fetcher: typeof fetch;\n}\n\nexport class OpenAIChatModel implements LanguageModel {\n readonly provider = 'openai';\n readonly modelId: string;\n private readonly config: OpenAIChatModelConfig;\n\n constructor(config: OpenAIChatModelConfig) {\n this.modelId = config.modelId;\n this.config = config;\n }\n\n async generate(options: ModelCallOptions): Promise<ModelGenerateResult> {\n const body = this.buildBody(options, false);\n const res = await this.fetch('/chat/completions', body, options);\n const json = (await res.json()) as OpenAIChatCompletion;\n\n const choice = json.choices?.[0];\n if (!choice) {\n throw new APICallError({\n message: 'OpenAI response contained no choices.',\n url: `${this.config.baseURL}/chat/completions`,\n statusCode: res.status,\n responseBody: JSON.stringify(json),\n });\n }\n\n const text = choice.message?.content ?? '';\n const toolCalls: ToolCallPart[] =\n choice.message?.tool_calls?.map((tc) => ({\n type: 'tool-call' as const,\n toolCallId: tc.id,\n toolName: tc.function.name,\n args: safeParseJSON(tc.function.arguments),\n })) ?? [];\n\n return {\n text,\n content: [...(text.length > 0 ? [{ type: 'text' as const, text }] : []), ...toolCalls],\n toolCalls,\n finishReason: mapFinishReason(choice.finish_reason),\n usage: mapUsage(json.usage),\n rawResponse: json,\n };\n }\n\n async stream(options: ModelCallOptions): Promise<ReadableStream<ModelStreamPart>> {\n const body = this.buildBody(options, true);\n const res = await this.fetch('/chat/completions', body, options);\n if (!res.body) {\n throw new APICallError({\n message: 'OpenAI streaming response has no body.',\n statusCode: res.status,\n });\n }\n\n const sse = parseSSE(res.body);\n\n return new ReadableStream<ModelStreamPart>({\n async start(controller) {\n const toolCallsByIndex = new Map<\n number,\n { id: string; name: string; argsBuffer: string }\n >();\n let usage: TokenUsage | undefined;\n let finish: FinishReason = 'unknown';\n\n try {\n for await (const event of sse) {\n if (event === '[DONE]') break;\n const chunk = JSON.parse(event) as OpenAIChatChunk;\n\n const choice = chunk.choices?.[0];\n if (!choice) {\n if (chunk.usage) usage = mapUsage(chunk.usage);\n continue;\n }\n\n const delta = choice.delta;\n if (delta?.content) {\n controller.enqueue({ type: 'text-delta', textDelta: delta.content });\n }\n\n if (delta?.tool_calls) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index;\n let entry = toolCallsByIndex.get(idx);\n if (!entry) {\n entry = {\n id: tc.id ?? `call_${idx}`,\n name: tc.function?.name ?? '',\n argsBuffer: '',\n };\n toolCallsByIndex.set(idx, entry);\n }\n if (tc.id && !entry.id) entry.id = tc.id;\n if (tc.function?.name) entry.name = tc.function.name;\n if (tc.function?.arguments) {\n entry.argsBuffer += tc.function.arguments;\n controller.enqueue({\n type: 'tool-call-delta',\n toolCallId: entry.id,\n toolName: entry.name,\n argsDelta: tc.function.arguments,\n });\n }\n }\n }\n\n if (choice.finish_reason) {\n finish = mapFinishReason(choice.finish_reason);\n }\n if (chunk.usage) usage = mapUsage(chunk.usage);\n }\n\n for (const entry of toolCallsByIndex.values()) {\n controller.enqueue({\n type: 'tool-call',\n toolCallId: entry.id,\n toolName: entry.name,\n args: safeParseJSON(entry.argsBuffer),\n });\n }\n\n controller.enqueue({\n type: 'finish',\n finishReason: finish,\n usage: usage ?? {},\n });\n controller.close();\n } catch (err) {\n controller.enqueue({ type: 'error', error: err });\n controller.close();\n }\n },\n });\n }\n\n /**\n * Pre-flight cost estimate. Conservative bounds: assumes the model fills\n * `maxTokens` for the upper bound, and emits ~16 tokens for the lower\n * bound. Returns `pricingAvailable: false` when the SDK has no row for\n * this model id — Budget Guard will then skip USD pre-flight enforcement.\n */\n estimateCost(options: ModelCallOptions): CostEstimate {\n const inputTokens = estimateTokensFromMessages(asChatMessages(options.messages));\n const maxOut = options.maxTokens ?? defaultOutputCap(this.modelId);\n const minOut = Math.min(16, maxOut);\n const pricing = getPricing(this.provider, this.modelId);\n if (!pricing) {\n return {\n minTokens: inputTokens + minOut,\n maxTokens: inputTokens + maxOut,\n minUsd: 0,\n maxUsd: 0,\n pricingAvailable: false,\n };\n }\n return {\n minTokens: inputTokens + minOut,\n maxTokens: inputTokens + maxOut,\n minUsd:\n (inputTokens * pricing.inputPer1M) / 1_000_000 + (minOut * pricing.outputPer1M) / 1_000_000,\n maxUsd:\n (inputTokens * pricing.inputPer1M) / 1_000_000 + (maxOut * pricing.outputPer1M) / 1_000_000,\n pricingAvailable: true,\n };\n }\n\n private buildBody(options: ModelCallOptions, stream: boolean): Record<string, unknown> {\n const body: Record<string, unknown> = {\n model: this.modelId,\n messages: options.messages.map(toOpenAIMessage),\n };\n if (stream) {\n body.stream = true;\n body.stream_options = { include_usage: true };\n }\n if (options.tools?.length) {\n body.tools = options.tools.map((t) => ({\n type: 'function',\n function: {\n name: t.name,\n ...(t.description !== undefined ? { description: t.description } : {}),\n parameters: t.parameters,\n },\n }));\n }\n if (options.toolChoice !== undefined) {\n if (typeof options.toolChoice === 'string') {\n body.tool_choice = options.toolChoice;\n } else {\n body.tool_choice = {\n type: 'function',\n function: { name: options.toolChoice.toolName },\n };\n }\n }\n if (options.temperature !== undefined) body.temperature = options.temperature;\n if (options.topP !== undefined) body.top_p = options.topP;\n if (options.maxTokens !== undefined) body.max_tokens = options.maxTokens;\n if (options.stopSequences !== undefined) body.stop = options.stopSequences;\n if (options.seed !== undefined) body.seed = options.seed;\n if (options.providerOptions) Object.assign(body, options.providerOptions);\n return body;\n }\n\n private async fetch(path: string, body: unknown, options: ModelCallOptions): Promise<Response> {\n const url = `${this.config.baseURL}${path}`;\n const headers = { ...this.config.headers, ...options.headers };\n const init: RequestInit = {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n };\n if (options.abortSignal) init.signal = options.abortSignal;\n\n const res = await this.config.fetcher(url, init);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new APICallError({\n message: `OpenAI API error: ${res.status} ${res.statusText}`,\n url,\n statusCode: res.status,\n responseBody: text,\n });\n }\n return res;\n }\n}\n\nfunction uint8ToBase64(arr: Uint8Array): string {\n let s = '';\n for (let i = 0; i < arr.byteLength; i++) s += String.fromCharCode(arr[i] as number);\n return typeof btoa !== 'undefined' ? btoa(s) : Buffer.from(s, 'binary').toString('base64');\n}\n\nfunction openAiAudioFormat(mime?: string): 'wav' | 'mp3' | null {\n const m = (mime ?? '').toLowerCase();\n if (m.includes('wav')) return 'wav';\n if (m.includes('mp3') || m.includes('mpeg')) return 'mp3';\n return null;\n}\n\nfunction openAiGuessFilename(mime?: string): string {\n const m = (mime ?? '').toLowerCase();\n if (m.includes('pdf')) return 'document.pdf';\n if (m.includes('plain')) return 'document.txt';\n return 'document.bin';\n}\n\nfunction openAiGuessVideoFilename(mime?: string): string {\n const m = (mime ?? '').toLowerCase();\n if (m.includes('webm')) return 'clip.webm';\n if (m.includes('quicktime')) return 'clip.mov';\n return 'clip.mp4';\n}\n\nfunction mapOpenAiUserContentPart(p: ContentPart): unknown {\n if (p.type === 'text') return { type: 'text', text: p.text };\n if (p.type === 'image') {\n const url =\n typeof p.image === 'string'\n ? p.image\n : p.image instanceof URL\n ? p.image.toString()\n : `data:${p.mimeType ?? 'image/png'};base64,${uint8ToBase64(p.image)}`;\n return { type: 'image_url', image_url: { url } };\n }\n if (p.type === 'audio') {\n const r = resolveMediaInput(p.audio);\n if ('url' in r) {\n throw new UnsupportedPartError({\n partType: 'audio',\n provider: 'openai',\n message:\n 'OpenAI `input_audio` requires inline WAV/MP3 as a Uint8Array or a `data:` URL. The SDK does not fetch remote URLs.',\n });\n }\n const fmt = openAiAudioFormat(r.mimeType ?? p.mimeType);\n if (!fmt) {\n throw new UnsupportedPartError({\n partType: 'audio',\n provider: 'openai',\n message: `OpenAI supports input_audio with format \"wav\" or \"mp3\" only (got mime \"${r.mimeType ?? p.mimeType ?? 'unknown'}\").`,\n });\n }\n return { type: 'input_audio', input_audio: { data: r.base64, format: fmt } };\n }\n if (p.type === 'file') {\n if (typeof p.file === 'string' && p.file.startsWith('file-')) {\n return {\n type: 'file',\n file: {\n file_id: p.file,\n ...(p.filename !== undefined ? { filename: p.filename } : {}),\n },\n };\n }\n const r = resolveMediaInput(p.file);\n if ('url' in r) {\n throw new UnsupportedPartError({\n partType: 'file',\n provider: 'openai',\n message:\n 'OpenAI file parts need a Files API id (`file-…`), or inline bytes / a base64 `data:` URL. The SDK does not fetch remote URLs.',\n });\n }\n return {\n type: 'file',\n file: {\n file_data: r.base64,\n filename: p.filename ?? openAiGuessFilename(r.mimeType ?? p.mimeType),\n },\n };\n }\n if (p.type === 'video') {\n if (typeof p.video === 'string' && p.video.startsWith('file-')) {\n return {\n type: 'file',\n file: {\n file_id: p.video,\n ...(p.filename !== undefined ? { filename: p.filename } : {}),\n },\n };\n }\n const r = resolveMediaInput(p.video);\n if ('url' in r) {\n throw new UnsupportedPartError({\n partType: 'video',\n provider: 'openai',\n message:\n 'OpenAI video parts need a Files API id (`file-…`), or inline bytes / a base64 `data:` URL. The SDK does not fetch remote URLs.',\n });\n }\n return {\n type: 'file',\n file: {\n file_data: r.base64,\n filename: p.filename ?? openAiGuessVideoFilename(r.mimeType ?? p.mimeType),\n },\n };\n }\n throw new UnsupportedPartError({\n partType: (p as { type?: string }).type ?? 'unknown',\n provider: 'openai',\n message: 'Unexpected content part in user message.',\n });\n}\n\nfunction toOpenAIMessage(m: NormalizedMessage): unknown {\n switch (m.role) {\n case 'system': {\n const text = m.content\n .filter((p) => p.type === 'text')\n .map((p) => (p as { text: string }).text)\n .join('');\n return { role: 'system', content: text };\n }\n case 'user': {\n const allText = m.content.every((p) => p.type === 'text');\n if (allText) {\n return {\n role: 'user',\n content: m.content.map((p) => (p as { text: string }).text).join(''),\n };\n }\n return {\n role: 'user',\n content: m.content.map((p) => mapOpenAiUserContentPart(p)),\n };\n }\n case 'assistant': {\n const toolCalls = m.content.filter((p) => p.type === 'tool-call');\n const text = m.content\n .filter((p) => p.type === 'text')\n .map((p) => (p as { text: string }).text)\n .join('');\n const out: Record<string, unknown> = { role: 'assistant', content: text || null };\n if (toolCalls.length > 0) {\n out.tool_calls = toolCalls.map((tc) => ({\n id: (tc as ToolCallPart).toolCallId,\n type: 'function',\n function: {\n name: (tc as ToolCallPart).toolName,\n arguments: JSON.stringify((tc as ToolCallPart).args ?? {}),\n },\n }));\n }\n return out;\n }\n case 'tool': {\n // OpenAI requires one tool message per result.\n // The caller will need to flatten before passing. We pick the first.\n const first = m.content[0];\n if (!first || first.type !== 'tool-result') {\n return { role: 'tool', content: '', tool_call_id: '' };\n }\n return {\n role: 'tool',\n content: typeof first.result === 'string' ? first.result : JSON.stringify(first.result),\n tool_call_id: first.toolCallId,\n };\n }\n }\n}\n\n/**\n * Bridge `NormalizedMessage[]` (always `ContentPart[]`) to the public\n * `ChatMessage[]` shape `estimateTokensFromMessages` accepts. The estimator\n * only inspects `role` + `content`, so the structural cast is safe.\n */\nfunction asChatMessages(\n messages: NormalizedMessage[],\n): Parameters<typeof estimateTokensFromMessages>[0] {\n return messages as unknown as Parameters<typeof estimateTokensFromMessages>[0];\n}\n\n/**\n * Default output token cap when the caller didn't pass `maxTokens`. Mirrors\n * OpenAI's typical model defaults; intentionally generous so pre-flight\n * over- rather than underestimates.\n */\nfunction defaultOutputCap(modelId: string): number {\n if (modelId.startsWith('o1') || modelId.startsWith('o3')) return 100_000;\n if (modelId.startsWith('gpt-5')) return 32_768;\n return 16_384;\n}\n\nfunction safeParseJSON(text: string): unknown {\n if (!text) return {};\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction mapFinishReason(reason: string | null | undefined): FinishReason {\n switch (reason) {\n case 'stop':\n return 'stop';\n case 'length':\n return 'length';\n case 'tool_calls':\n case 'function_call':\n return 'tool-calls';\n case 'content_filter':\n return 'content-filter';\n case null:\n case undefined:\n return 'unknown';\n default:\n return 'other';\n }\n}\n\nfunction mapUsage(u: OpenAIUsage | undefined): TokenUsage {\n if (!u) return {};\n const out: TokenUsage = {};\n if (u.prompt_tokens !== undefined) out.promptTokens = u.prompt_tokens;\n if (u.completion_tokens !== undefined) out.completionTokens = u.completion_tokens;\n if (u.total_tokens !== undefined) out.totalTokens = u.total_tokens;\n if (u.prompt_tokens_details?.cached_tokens !== undefined) {\n out.cachedPromptTokens = u.prompt_tokens_details.cached_tokens;\n }\n if (u.completion_tokens_details?.reasoning_tokens !== undefined) {\n out.reasoningTokens = u.completion_tokens_details.reasoning_tokens;\n }\n return out;\n}\n\ninterface OpenAIUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n prompt_tokens_details?: { cached_tokens?: number };\n completion_tokens_details?: { reasoning_tokens?: number };\n}\n\ninterface OpenAIChatCompletion {\n choices?: Array<{\n message?: {\n content?: string;\n tool_calls?: Array<{\n id: string;\n function: { name: string; arguments: string };\n }>;\n };\n finish_reason?: string | null;\n }>;\n usage?: OpenAIUsage;\n}\n\ninterface OpenAIChatChunk {\n choices?: Array<{\n delta?: {\n content?: string;\n tool_calls?: Array<{\n index: number;\n id?: string;\n function?: { name?: string; arguments?: string };\n }>;\n };\n finish_reason?: string | null;\n }>;\n usage?: OpenAIUsage;\n}\n","import type { LanguageModel } from '@ziro-agent/core';\nimport { OpenAIChatModel, type OpenAIChatModelId } from './openai-chat-model.js';\n\nexport interface OpenAIProviderOptions {\n /** Defaults to `process.env.OPENAI_API_KEY`. */\n apiKey?: string;\n /** Override the base URL (useful for proxies / Azure / OpenRouter). */\n baseURL?: string;\n /** Optional organization id (`OpenAI-Organization` header). */\n organization?: string;\n /** Optional project id (`OpenAI-Project` header). */\n project?: string;\n /** Extra default headers attached to every request. */\n headers?: Record<string, string>;\n /** Custom `fetch`. Defaults to `globalThis.fetch`. */\n fetch?: typeof fetch;\n}\n\nexport interface OpenAIProvider {\n (modelId: OpenAIChatModelId): LanguageModel;\n chat(modelId: OpenAIChatModelId): LanguageModel;\n}\n\nexport function createOpenAI(options: OpenAIProviderOptions = {}): OpenAIProvider {\n const apiKey = options.apiKey ?? loadEnv('OPENAI_API_KEY');\n const baseURL = options.baseURL ?? 'https://api.openai.com/v1';\n const fetcher = options.fetch ?? globalThis.fetch;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n if (apiKey) headers.Authorization = `Bearer ${apiKey}`;\n if (options.organization) headers['OpenAI-Organization'] = options.organization;\n if (options.project) headers['OpenAI-Project'] = options.project;\n\n const make = (modelId: OpenAIChatModelId): LanguageModel =>\n new OpenAIChatModel({\n modelId,\n baseURL,\n headers,\n fetcher,\n });\n\n const provider = ((modelId: OpenAIChatModelId) => make(modelId)) as OpenAIProvider;\n provider.chat = make;\n return provider;\n}\n\n/** Default singleton provider — reads `OPENAI_API_KEY` from env. */\nexport const openai: OpenAIProvider = createOpenAI();\n\nfunction loadEnv(name: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziro-agent/openai",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "OpenAI provider for ZiroAgent SDK.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://ziroagent.com",
@@ -43,7 +43,7 @@
43
43
  "LICENSE"
44
44
  ],
45
45
  "dependencies": {
46
- "@ziro-agent/core": "0.6.0"
46
+ "@ziro-agent/core": "0.7.0"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@arethetypeswrong/cli": "^0.18.2",