@ziro-agent/openai 0.1.0

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 ADDED
@@ -0,0 +1,368 @@
1
+ 'use strict';
2
+
3
+ var core = require('@ziro-agent/core');
4
+
5
+ // src/openai-chat-model.ts
6
+
7
+ // src/util/sse.ts
8
+ async function* parseSSE(body) {
9
+ const reader = body.getReader();
10
+ const decoder = new TextDecoder("utf-8");
11
+ let buffer = "";
12
+ try {
13
+ while (true) {
14
+ const { done, value } = await reader.read();
15
+ if (done) {
16
+ if (buffer.length > 0) {
17
+ const event = extractEvent(buffer);
18
+ if (event !== null) yield event;
19
+ }
20
+ return;
21
+ }
22
+ buffer += decoder.decode(value, { stream: true });
23
+ while (true) {
24
+ const sepIdx = findEventBoundary(buffer);
25
+ if (sepIdx === -1) break;
26
+ const block = buffer.slice(0, sepIdx);
27
+ buffer = buffer.slice(sepIdx).replace(/^(\r?\n){2}/, "");
28
+ const event = extractEvent(block);
29
+ if (event !== null) yield event;
30
+ }
31
+ }
32
+ } finally {
33
+ reader.releaseLock();
34
+ }
35
+ }
36
+ function findEventBoundary(s) {
37
+ const i1 = s.indexOf("\n\n");
38
+ const i2 = s.indexOf("\r\n\r\n");
39
+ if (i1 === -1) return i2;
40
+ if (i2 === -1) return i1;
41
+ return Math.min(i1, i2);
42
+ }
43
+ function extractEvent(block) {
44
+ const lines = block.split(/\r?\n/);
45
+ const data = [];
46
+ for (const line of lines) {
47
+ if (line.startsWith("data:")) {
48
+ data.push(line.slice(5).replace(/^ /, ""));
49
+ }
50
+ }
51
+ if (data.length === 0) return null;
52
+ return data.join("\n");
53
+ }
54
+
55
+ // src/openai-chat-model.ts
56
+ var OpenAIChatModel = class {
57
+ provider = "openai";
58
+ modelId;
59
+ config;
60
+ constructor(config) {
61
+ this.modelId = config.modelId;
62
+ this.config = config;
63
+ }
64
+ async generate(options) {
65
+ const body = this.buildBody(options, false);
66
+ const res = await this.fetch("/chat/completions", body, options);
67
+ const json = await res.json();
68
+ const choice = json.choices?.[0];
69
+ if (!choice) {
70
+ throw new core.APICallError({
71
+ message: "OpenAI response contained no choices.",
72
+ url: `${this.config.baseURL}/chat/completions`,
73
+ statusCode: res.status,
74
+ responseBody: JSON.stringify(json)
75
+ });
76
+ }
77
+ const text = choice.message?.content ?? "";
78
+ const toolCalls = choice.message?.tool_calls?.map((tc) => ({
79
+ type: "tool-call",
80
+ toolCallId: tc.id,
81
+ toolName: tc.function.name,
82
+ args: safeParseJSON(tc.function.arguments)
83
+ })) ?? [];
84
+ return {
85
+ text,
86
+ content: [
87
+ ...text.length > 0 ? [{ type: "text", text }] : [],
88
+ ...toolCalls
89
+ ],
90
+ toolCalls,
91
+ finishReason: mapFinishReason(choice.finish_reason),
92
+ usage: mapUsage(json.usage),
93
+ rawResponse: json
94
+ };
95
+ }
96
+ async stream(options) {
97
+ const body = this.buildBody(options, true);
98
+ const res = await this.fetch("/chat/completions", body, options);
99
+ if (!res.body) {
100
+ throw new core.APICallError({
101
+ message: "OpenAI streaming response has no body.",
102
+ statusCode: res.status
103
+ });
104
+ }
105
+ const sse = parseSSE(res.body);
106
+ return new ReadableStream({
107
+ async start(controller) {
108
+ const toolCallsByIndex = /* @__PURE__ */ new Map();
109
+ let usage;
110
+ let finish = "unknown";
111
+ try {
112
+ for await (const event of sse) {
113
+ if (event === "[DONE]") break;
114
+ const chunk = JSON.parse(event);
115
+ const choice = chunk.choices?.[0];
116
+ if (!choice) {
117
+ if (chunk.usage) usage = mapUsage(chunk.usage);
118
+ continue;
119
+ }
120
+ const delta = choice.delta;
121
+ if (delta?.content) {
122
+ controller.enqueue({ type: "text-delta", textDelta: delta.content });
123
+ }
124
+ if (delta?.tool_calls) {
125
+ for (const tc of delta.tool_calls) {
126
+ const idx = tc.index;
127
+ let entry = toolCallsByIndex.get(idx);
128
+ if (!entry) {
129
+ entry = {
130
+ id: tc.id ?? `call_${idx}`,
131
+ name: tc.function?.name ?? "",
132
+ argsBuffer: ""
133
+ };
134
+ toolCallsByIndex.set(idx, entry);
135
+ }
136
+ if (tc.id && !entry.id) entry.id = tc.id;
137
+ if (tc.function?.name) entry.name = tc.function.name;
138
+ if (tc.function?.arguments) {
139
+ entry.argsBuffer += tc.function.arguments;
140
+ controller.enqueue({
141
+ type: "tool-call-delta",
142
+ toolCallId: entry.id,
143
+ toolName: entry.name,
144
+ argsDelta: tc.function.arguments
145
+ });
146
+ }
147
+ }
148
+ }
149
+ if (choice.finish_reason) {
150
+ finish = mapFinishReason(choice.finish_reason);
151
+ }
152
+ if (chunk.usage) usage = mapUsage(chunk.usage);
153
+ }
154
+ for (const entry of toolCallsByIndex.values()) {
155
+ controller.enqueue({
156
+ type: "tool-call",
157
+ toolCallId: entry.id,
158
+ toolName: entry.name,
159
+ args: safeParseJSON(entry.argsBuffer)
160
+ });
161
+ }
162
+ controller.enqueue({
163
+ type: "finish",
164
+ finishReason: finish,
165
+ usage: usage ?? {}
166
+ });
167
+ controller.close();
168
+ } catch (err) {
169
+ controller.enqueue({ type: "error", error: err });
170
+ controller.close();
171
+ }
172
+ }
173
+ });
174
+ }
175
+ buildBody(options, stream) {
176
+ const body = {
177
+ model: this.modelId,
178
+ messages: options.messages.map(toOpenAIMessage)
179
+ };
180
+ if (stream) {
181
+ body["stream"] = true;
182
+ body["stream_options"] = { include_usage: true };
183
+ }
184
+ if (options.tools?.length) {
185
+ body["tools"] = options.tools.map((t) => ({
186
+ type: "function",
187
+ function: {
188
+ name: t.name,
189
+ ...t.description !== void 0 ? { description: t.description } : {},
190
+ parameters: t.parameters
191
+ }
192
+ }));
193
+ }
194
+ if (options.toolChoice !== void 0) {
195
+ if (typeof options.toolChoice === "string") {
196
+ body["tool_choice"] = options.toolChoice;
197
+ } else {
198
+ body["tool_choice"] = {
199
+ type: "function",
200
+ function: { name: options.toolChoice.toolName }
201
+ };
202
+ }
203
+ }
204
+ if (options.temperature !== void 0) body["temperature"] = options.temperature;
205
+ if (options.topP !== void 0) body["top_p"] = options.topP;
206
+ if (options.maxTokens !== void 0) body["max_tokens"] = options.maxTokens;
207
+ if (options.stopSequences !== void 0) body["stop"] = options.stopSequences;
208
+ if (options.seed !== void 0) body["seed"] = options.seed;
209
+ if (options.providerOptions) Object.assign(body, options.providerOptions);
210
+ return body;
211
+ }
212
+ async fetch(path, body, options) {
213
+ const url = `${this.config.baseURL}${path}`;
214
+ const headers = { ...this.config.headers, ...options.headers };
215
+ const init = {
216
+ method: "POST",
217
+ headers,
218
+ body: JSON.stringify(body)
219
+ };
220
+ if (options.abortSignal) init.signal = options.abortSignal;
221
+ const res = await this.config.fetcher(url, init);
222
+ if (!res.ok) {
223
+ const text = await res.text().catch(() => "");
224
+ throw new core.APICallError({
225
+ message: `OpenAI API error: ${res.status} ${res.statusText}`,
226
+ url,
227
+ statusCode: res.status,
228
+ responseBody: text
229
+ });
230
+ }
231
+ return res;
232
+ }
233
+ };
234
+ function toOpenAIMessage(m) {
235
+ switch (m.role) {
236
+ case "system": {
237
+ const text = m.content.filter((p) => p.type === "text").map((p) => p.text).join("");
238
+ return { role: "system", content: text };
239
+ }
240
+ case "user": {
241
+ const allText = m.content.every((p) => p.type === "text");
242
+ if (allText) {
243
+ return {
244
+ role: "user",
245
+ content: m.content.map((p) => p.text).join("")
246
+ };
247
+ }
248
+ return {
249
+ role: "user",
250
+ content: m.content.map((p) => {
251
+ if (p.type === "text") return { type: "text", text: p.text };
252
+ if (p.type === "image") {
253
+ const url = typeof p.image === "string" ? p.image : p.image instanceof URL ? p.image.toString() : `data:${p.mimeType ?? "image/png"};base64,${uint8ToBase64(p.image)}`;
254
+ return { type: "image_url", image_url: { url } };
255
+ }
256
+ return p;
257
+ })
258
+ };
259
+ }
260
+ case "assistant": {
261
+ const toolCalls = m.content.filter((p) => p.type === "tool-call");
262
+ const text = m.content.filter((p) => p.type === "text").map((p) => p.text).join("");
263
+ const out = { role: "assistant", content: text || null };
264
+ if (toolCalls.length > 0) {
265
+ out["tool_calls"] = toolCalls.map((tc) => ({
266
+ id: tc.toolCallId,
267
+ type: "function",
268
+ function: {
269
+ name: tc.toolName,
270
+ arguments: JSON.stringify(tc.args ?? {})
271
+ }
272
+ }));
273
+ }
274
+ return out;
275
+ }
276
+ case "tool": {
277
+ const first = m.content[0];
278
+ if (!first || first.type !== "tool-result") {
279
+ return { role: "tool", content: "", tool_call_id: "" };
280
+ }
281
+ return {
282
+ role: "tool",
283
+ content: typeof first.result === "string" ? first.result : JSON.stringify(first.result),
284
+ tool_call_id: first.toolCallId
285
+ };
286
+ }
287
+ }
288
+ }
289
+ function uint8ToBase64(arr) {
290
+ let s = "";
291
+ for (let i = 0; i < arr.byteLength; i++) s += String.fromCharCode(arr[i]);
292
+ return typeof btoa !== "undefined" ? btoa(s) : Buffer.from(s, "binary").toString("base64");
293
+ }
294
+ function safeParseJSON(text) {
295
+ if (!text) return {};
296
+ try {
297
+ return JSON.parse(text);
298
+ } catch {
299
+ return text;
300
+ }
301
+ }
302
+ function mapFinishReason(reason) {
303
+ switch (reason) {
304
+ case "stop":
305
+ return "stop";
306
+ case "length":
307
+ return "length";
308
+ case "tool_calls":
309
+ case "function_call":
310
+ return "tool-calls";
311
+ case "content_filter":
312
+ return "content-filter";
313
+ case null:
314
+ case void 0:
315
+ return "unknown";
316
+ default:
317
+ return "other";
318
+ }
319
+ }
320
+ function mapUsage(u) {
321
+ if (!u) return {};
322
+ const out = {};
323
+ if (u.prompt_tokens !== void 0) out.promptTokens = u.prompt_tokens;
324
+ if (u.completion_tokens !== void 0) out.completionTokens = u.completion_tokens;
325
+ if (u.total_tokens !== void 0) out.totalTokens = u.total_tokens;
326
+ if (u.prompt_tokens_details?.cached_tokens !== void 0) {
327
+ out.cachedPromptTokens = u.prompt_tokens_details.cached_tokens;
328
+ }
329
+ if (u.completion_tokens_details?.reasoning_tokens !== void 0) {
330
+ out.reasoningTokens = u.completion_tokens_details.reasoning_tokens;
331
+ }
332
+ return out;
333
+ }
334
+
335
+ // src/openai-provider.ts
336
+ function createOpenAI(options = {}) {
337
+ const apiKey = options.apiKey ?? loadEnv("OPENAI_API_KEY");
338
+ const baseURL = options.baseURL ?? "https://api.openai.com/v1";
339
+ const fetcher = options.fetch ?? globalThis.fetch;
340
+ const headers = {
341
+ "Content-Type": "application/json",
342
+ ...options.headers
343
+ };
344
+ if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
345
+ if (options.organization) headers["OpenAI-Organization"] = options.organization;
346
+ if (options.project) headers["OpenAI-Project"] = options.project;
347
+ const make = (modelId) => new OpenAIChatModel({
348
+ modelId,
349
+ baseURL,
350
+ headers,
351
+ fetcher
352
+ });
353
+ const provider = ((modelId) => make(modelId));
354
+ provider.chat = make;
355
+ return provider;
356
+ }
357
+ var openai = createOpenAI();
358
+ function loadEnv(name) {
359
+ if (typeof process !== "undefined" && process.env) {
360
+ return process.env[name];
361
+ }
362
+ return void 0;
363
+ }
364
+
365
+ exports.createOpenAI = createOpenAI;
366
+ exports.openai = openai;
367
+ //# sourceMappingURL=index.cjs.map
368
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/util/sse.ts","../src/openai-chat-model.ts","../src/openai-provider.ts"],"names":["APICallError"],"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 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 { 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 | 'gpt-4o'\n | 'gpt-4o-mini'\n | 'gpt-4.1'\n | 'gpt-4.1-mini'\n | 'gpt-4.1-nano'\n | 'gpt-4-turbo'\n | 'gpt-3.5-turbo'\n | 'o1'\n | 'o1-mini'\n | 'o3'\n | 'o3-mini'\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: [\n ...(text.length > 0 ? [{ type: 'text' as const, text }] : []),\n ...toolCalls,\n ],\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 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(\n path: string,\n body: unknown,\n options: ModelCallOptions,\n ): 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:\n typeof first.result === 'string' ? first.result : JSON.stringify(first.result),\n tool_call_id: first.toolCallId,\n };\n }\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'\n ? btoa(s)\n : 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"]}
@@ -0,0 +1,32 @@
1
+ import { LanguageModel } from '@ziro-agent/core';
2
+
3
+ /**
4
+ * The set of OpenAI chat model ids we explicitly know about. Other strings are
5
+ * still allowed via the `(string & {})` trick — we don't want to lock users out
6
+ * when OpenAI ships a new model before we update the SDK.
7
+ */
8
+ type OpenAIChatModelId = 'gpt-4o' | 'gpt-4o-mini' | 'gpt-4.1' | 'gpt-4.1-mini' | 'gpt-4.1-nano' | 'gpt-4-turbo' | 'gpt-3.5-turbo' | 'o1' | 'o1-mini' | 'o3' | 'o3-mini' | (string & {});
9
+
10
+ interface OpenAIProviderOptions {
11
+ /** Defaults to `process.env.OPENAI_API_KEY`. */
12
+ apiKey?: string;
13
+ /** Override the base URL (useful for proxies / Azure / OpenRouter). */
14
+ baseURL?: string;
15
+ /** Optional organization id (`OpenAI-Organization` header). */
16
+ organization?: string;
17
+ /** Optional project id (`OpenAI-Project` header). */
18
+ project?: string;
19
+ /** Extra default headers attached to every request. */
20
+ headers?: Record<string, string>;
21
+ /** Custom `fetch`. Defaults to `globalThis.fetch`. */
22
+ fetch?: typeof fetch;
23
+ }
24
+ interface OpenAIProvider {
25
+ (modelId: OpenAIChatModelId): LanguageModel;
26
+ chat(modelId: OpenAIChatModelId): LanguageModel;
27
+ }
28
+ declare function createOpenAI(options?: OpenAIProviderOptions): OpenAIProvider;
29
+ /** Default singleton provider — reads `OPENAI_API_KEY` from env. */
30
+ declare const openai: OpenAIProvider;
31
+
32
+ export { type OpenAIChatModelId, type OpenAIProviderOptions, createOpenAI, openai };
@@ -0,0 +1,32 @@
1
+ import { LanguageModel } from '@ziro-agent/core';
2
+
3
+ /**
4
+ * The set of OpenAI chat model ids we explicitly know about. Other strings are
5
+ * still allowed via the `(string & {})` trick — we don't want to lock users out
6
+ * when OpenAI ships a new model before we update the SDK.
7
+ */
8
+ type OpenAIChatModelId = 'gpt-4o' | 'gpt-4o-mini' | 'gpt-4.1' | 'gpt-4.1-mini' | 'gpt-4.1-nano' | 'gpt-4-turbo' | 'gpt-3.5-turbo' | 'o1' | 'o1-mini' | 'o3' | 'o3-mini' | (string & {});
9
+
10
+ interface OpenAIProviderOptions {
11
+ /** Defaults to `process.env.OPENAI_API_KEY`. */
12
+ apiKey?: string;
13
+ /** Override the base URL (useful for proxies / Azure / OpenRouter). */
14
+ baseURL?: string;
15
+ /** Optional organization id (`OpenAI-Organization` header). */
16
+ organization?: string;
17
+ /** Optional project id (`OpenAI-Project` header). */
18
+ project?: string;
19
+ /** Extra default headers attached to every request. */
20
+ headers?: Record<string, string>;
21
+ /** Custom `fetch`. Defaults to `globalThis.fetch`. */
22
+ fetch?: typeof fetch;
23
+ }
24
+ interface OpenAIProvider {
25
+ (modelId: OpenAIChatModelId): LanguageModel;
26
+ chat(modelId: OpenAIChatModelId): LanguageModel;
27
+ }
28
+ declare function createOpenAI(options?: OpenAIProviderOptions): OpenAIProvider;
29
+ /** Default singleton provider — reads `OPENAI_API_KEY` from env. */
30
+ declare const openai: OpenAIProvider;
31
+
32
+ export { type OpenAIChatModelId, type OpenAIProviderOptions, createOpenAI, openai };
package/dist/index.js ADDED
@@ -0,0 +1,365 @@
1
+ import { APICallError } from '@ziro-agent/core';
2
+
3
+ // src/openai-chat-model.ts
4
+
5
+ // src/util/sse.ts
6
+ async function* parseSSE(body) {
7
+ const reader = body.getReader();
8
+ const decoder = new TextDecoder("utf-8");
9
+ let buffer = "";
10
+ try {
11
+ while (true) {
12
+ const { done, value } = await reader.read();
13
+ if (done) {
14
+ if (buffer.length > 0) {
15
+ const event = extractEvent(buffer);
16
+ if (event !== null) yield event;
17
+ }
18
+ return;
19
+ }
20
+ buffer += decoder.decode(value, { stream: true });
21
+ while (true) {
22
+ const sepIdx = findEventBoundary(buffer);
23
+ if (sepIdx === -1) break;
24
+ const block = buffer.slice(0, sepIdx);
25
+ buffer = buffer.slice(sepIdx).replace(/^(\r?\n){2}/, "");
26
+ const event = extractEvent(block);
27
+ if (event !== null) yield event;
28
+ }
29
+ }
30
+ } finally {
31
+ reader.releaseLock();
32
+ }
33
+ }
34
+ function findEventBoundary(s) {
35
+ const i1 = s.indexOf("\n\n");
36
+ const i2 = s.indexOf("\r\n\r\n");
37
+ if (i1 === -1) return i2;
38
+ if (i2 === -1) return i1;
39
+ return Math.min(i1, i2);
40
+ }
41
+ function extractEvent(block) {
42
+ const lines = block.split(/\r?\n/);
43
+ const data = [];
44
+ for (const line of lines) {
45
+ if (line.startsWith("data:")) {
46
+ data.push(line.slice(5).replace(/^ /, ""));
47
+ }
48
+ }
49
+ if (data.length === 0) return null;
50
+ return data.join("\n");
51
+ }
52
+
53
+ // src/openai-chat-model.ts
54
+ var OpenAIChatModel = class {
55
+ provider = "openai";
56
+ modelId;
57
+ config;
58
+ constructor(config) {
59
+ this.modelId = config.modelId;
60
+ this.config = config;
61
+ }
62
+ async generate(options) {
63
+ const body = this.buildBody(options, false);
64
+ const res = await this.fetch("/chat/completions", body, options);
65
+ const json = await res.json();
66
+ const choice = json.choices?.[0];
67
+ if (!choice) {
68
+ throw new APICallError({
69
+ message: "OpenAI response contained no choices.",
70
+ url: `${this.config.baseURL}/chat/completions`,
71
+ statusCode: res.status,
72
+ responseBody: JSON.stringify(json)
73
+ });
74
+ }
75
+ const text = choice.message?.content ?? "";
76
+ const toolCalls = choice.message?.tool_calls?.map((tc) => ({
77
+ type: "tool-call",
78
+ toolCallId: tc.id,
79
+ toolName: tc.function.name,
80
+ args: safeParseJSON(tc.function.arguments)
81
+ })) ?? [];
82
+ return {
83
+ text,
84
+ content: [
85
+ ...text.length > 0 ? [{ type: "text", text }] : [],
86
+ ...toolCalls
87
+ ],
88
+ toolCalls,
89
+ finishReason: mapFinishReason(choice.finish_reason),
90
+ usage: mapUsage(json.usage),
91
+ rawResponse: json
92
+ };
93
+ }
94
+ async stream(options) {
95
+ const body = this.buildBody(options, true);
96
+ const res = await this.fetch("/chat/completions", body, options);
97
+ if (!res.body) {
98
+ throw new APICallError({
99
+ message: "OpenAI streaming response has no body.",
100
+ statusCode: res.status
101
+ });
102
+ }
103
+ const sse = parseSSE(res.body);
104
+ return new ReadableStream({
105
+ async start(controller) {
106
+ const toolCallsByIndex = /* @__PURE__ */ new Map();
107
+ let usage;
108
+ let finish = "unknown";
109
+ try {
110
+ for await (const event of sse) {
111
+ if (event === "[DONE]") break;
112
+ const chunk = JSON.parse(event);
113
+ const choice = chunk.choices?.[0];
114
+ if (!choice) {
115
+ if (chunk.usage) usage = mapUsage(chunk.usage);
116
+ continue;
117
+ }
118
+ const delta = choice.delta;
119
+ if (delta?.content) {
120
+ controller.enqueue({ type: "text-delta", textDelta: delta.content });
121
+ }
122
+ if (delta?.tool_calls) {
123
+ for (const tc of delta.tool_calls) {
124
+ const idx = tc.index;
125
+ let entry = toolCallsByIndex.get(idx);
126
+ if (!entry) {
127
+ entry = {
128
+ id: tc.id ?? `call_${idx}`,
129
+ name: tc.function?.name ?? "",
130
+ argsBuffer: ""
131
+ };
132
+ toolCallsByIndex.set(idx, entry);
133
+ }
134
+ if (tc.id && !entry.id) entry.id = tc.id;
135
+ if (tc.function?.name) entry.name = tc.function.name;
136
+ if (tc.function?.arguments) {
137
+ entry.argsBuffer += tc.function.arguments;
138
+ controller.enqueue({
139
+ type: "tool-call-delta",
140
+ toolCallId: entry.id,
141
+ toolName: entry.name,
142
+ argsDelta: tc.function.arguments
143
+ });
144
+ }
145
+ }
146
+ }
147
+ if (choice.finish_reason) {
148
+ finish = mapFinishReason(choice.finish_reason);
149
+ }
150
+ if (chunk.usage) usage = mapUsage(chunk.usage);
151
+ }
152
+ for (const entry of toolCallsByIndex.values()) {
153
+ controller.enqueue({
154
+ type: "tool-call",
155
+ toolCallId: entry.id,
156
+ toolName: entry.name,
157
+ args: safeParseJSON(entry.argsBuffer)
158
+ });
159
+ }
160
+ controller.enqueue({
161
+ type: "finish",
162
+ finishReason: finish,
163
+ usage: usage ?? {}
164
+ });
165
+ controller.close();
166
+ } catch (err) {
167
+ controller.enqueue({ type: "error", error: err });
168
+ controller.close();
169
+ }
170
+ }
171
+ });
172
+ }
173
+ buildBody(options, stream) {
174
+ const body = {
175
+ model: this.modelId,
176
+ messages: options.messages.map(toOpenAIMessage)
177
+ };
178
+ if (stream) {
179
+ body["stream"] = true;
180
+ body["stream_options"] = { include_usage: true };
181
+ }
182
+ if (options.tools?.length) {
183
+ body["tools"] = options.tools.map((t) => ({
184
+ type: "function",
185
+ function: {
186
+ name: t.name,
187
+ ...t.description !== void 0 ? { description: t.description } : {},
188
+ parameters: t.parameters
189
+ }
190
+ }));
191
+ }
192
+ if (options.toolChoice !== void 0) {
193
+ if (typeof options.toolChoice === "string") {
194
+ body["tool_choice"] = options.toolChoice;
195
+ } else {
196
+ body["tool_choice"] = {
197
+ type: "function",
198
+ function: { name: options.toolChoice.toolName }
199
+ };
200
+ }
201
+ }
202
+ if (options.temperature !== void 0) body["temperature"] = options.temperature;
203
+ if (options.topP !== void 0) body["top_p"] = options.topP;
204
+ if (options.maxTokens !== void 0) body["max_tokens"] = options.maxTokens;
205
+ if (options.stopSequences !== void 0) body["stop"] = options.stopSequences;
206
+ if (options.seed !== void 0) body["seed"] = options.seed;
207
+ if (options.providerOptions) Object.assign(body, options.providerOptions);
208
+ return body;
209
+ }
210
+ async fetch(path, body, options) {
211
+ const url = `${this.config.baseURL}${path}`;
212
+ const headers = { ...this.config.headers, ...options.headers };
213
+ const init = {
214
+ method: "POST",
215
+ headers,
216
+ body: JSON.stringify(body)
217
+ };
218
+ if (options.abortSignal) init.signal = options.abortSignal;
219
+ const res = await this.config.fetcher(url, init);
220
+ if (!res.ok) {
221
+ const text = await res.text().catch(() => "");
222
+ throw new APICallError({
223
+ message: `OpenAI API error: ${res.status} ${res.statusText}`,
224
+ url,
225
+ statusCode: res.status,
226
+ responseBody: text
227
+ });
228
+ }
229
+ return res;
230
+ }
231
+ };
232
+ function toOpenAIMessage(m) {
233
+ switch (m.role) {
234
+ case "system": {
235
+ const text = m.content.filter((p) => p.type === "text").map((p) => p.text).join("");
236
+ return { role: "system", content: text };
237
+ }
238
+ case "user": {
239
+ const allText = m.content.every((p) => p.type === "text");
240
+ if (allText) {
241
+ return {
242
+ role: "user",
243
+ content: m.content.map((p) => p.text).join("")
244
+ };
245
+ }
246
+ return {
247
+ role: "user",
248
+ content: m.content.map((p) => {
249
+ if (p.type === "text") return { type: "text", text: p.text };
250
+ if (p.type === "image") {
251
+ const url = typeof p.image === "string" ? p.image : p.image instanceof URL ? p.image.toString() : `data:${p.mimeType ?? "image/png"};base64,${uint8ToBase64(p.image)}`;
252
+ return { type: "image_url", image_url: { url } };
253
+ }
254
+ return p;
255
+ })
256
+ };
257
+ }
258
+ case "assistant": {
259
+ const toolCalls = m.content.filter((p) => p.type === "tool-call");
260
+ const text = m.content.filter((p) => p.type === "text").map((p) => p.text).join("");
261
+ const out = { role: "assistant", content: text || null };
262
+ if (toolCalls.length > 0) {
263
+ out["tool_calls"] = toolCalls.map((tc) => ({
264
+ id: tc.toolCallId,
265
+ type: "function",
266
+ function: {
267
+ name: tc.toolName,
268
+ arguments: JSON.stringify(tc.args ?? {})
269
+ }
270
+ }));
271
+ }
272
+ return out;
273
+ }
274
+ case "tool": {
275
+ const first = m.content[0];
276
+ if (!first || first.type !== "tool-result") {
277
+ return { role: "tool", content: "", tool_call_id: "" };
278
+ }
279
+ return {
280
+ role: "tool",
281
+ content: typeof first.result === "string" ? first.result : JSON.stringify(first.result),
282
+ tool_call_id: first.toolCallId
283
+ };
284
+ }
285
+ }
286
+ }
287
+ function uint8ToBase64(arr) {
288
+ let s = "";
289
+ for (let i = 0; i < arr.byteLength; i++) s += String.fromCharCode(arr[i]);
290
+ return typeof btoa !== "undefined" ? btoa(s) : Buffer.from(s, "binary").toString("base64");
291
+ }
292
+ function safeParseJSON(text) {
293
+ if (!text) return {};
294
+ try {
295
+ return JSON.parse(text);
296
+ } catch {
297
+ return text;
298
+ }
299
+ }
300
+ function mapFinishReason(reason) {
301
+ switch (reason) {
302
+ case "stop":
303
+ return "stop";
304
+ case "length":
305
+ return "length";
306
+ case "tool_calls":
307
+ case "function_call":
308
+ return "tool-calls";
309
+ case "content_filter":
310
+ return "content-filter";
311
+ case null:
312
+ case void 0:
313
+ return "unknown";
314
+ default:
315
+ return "other";
316
+ }
317
+ }
318
+ function mapUsage(u) {
319
+ if (!u) return {};
320
+ const out = {};
321
+ if (u.prompt_tokens !== void 0) out.promptTokens = u.prompt_tokens;
322
+ if (u.completion_tokens !== void 0) out.completionTokens = u.completion_tokens;
323
+ if (u.total_tokens !== void 0) out.totalTokens = u.total_tokens;
324
+ if (u.prompt_tokens_details?.cached_tokens !== void 0) {
325
+ out.cachedPromptTokens = u.prompt_tokens_details.cached_tokens;
326
+ }
327
+ if (u.completion_tokens_details?.reasoning_tokens !== void 0) {
328
+ out.reasoningTokens = u.completion_tokens_details.reasoning_tokens;
329
+ }
330
+ return out;
331
+ }
332
+
333
+ // src/openai-provider.ts
334
+ function createOpenAI(options = {}) {
335
+ const apiKey = options.apiKey ?? loadEnv("OPENAI_API_KEY");
336
+ const baseURL = options.baseURL ?? "https://api.openai.com/v1";
337
+ const fetcher = options.fetch ?? globalThis.fetch;
338
+ const headers = {
339
+ "Content-Type": "application/json",
340
+ ...options.headers
341
+ };
342
+ if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
343
+ if (options.organization) headers["OpenAI-Organization"] = options.organization;
344
+ if (options.project) headers["OpenAI-Project"] = options.project;
345
+ const make = (modelId) => new OpenAIChatModel({
346
+ modelId,
347
+ baseURL,
348
+ headers,
349
+ fetcher
350
+ });
351
+ const provider = ((modelId) => make(modelId));
352
+ provider.chat = make;
353
+ return provider;
354
+ }
355
+ var openai = createOpenAI();
356
+ function loadEnv(name) {
357
+ if (typeof process !== "undefined" && process.env) {
358
+ return process.env[name];
359
+ }
360
+ return void 0;
361
+ }
362
+
363
+ export { createOpenAI, openai };
364
+ //# sourceMappingURL=index.js.map
365
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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 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 { 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 | 'gpt-4o'\n | 'gpt-4o-mini'\n | 'gpt-4.1'\n | 'gpt-4.1-mini'\n | 'gpt-4.1-nano'\n | 'gpt-4-turbo'\n | 'gpt-3.5-turbo'\n | 'o1'\n | 'o1-mini'\n | 'o3'\n | 'o3-mini'\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: [\n ...(text.length > 0 ? [{ type: 'text' as const, text }] : []),\n ...toolCalls,\n ],\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 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(\n path: string,\n body: unknown,\n options: ModelCallOptions,\n ): 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:\n typeof first.result === 'string' ? first.result : JSON.stringify(first.result),\n tool_call_id: first.toolCallId,\n };\n }\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'\n ? btoa(s)\n : 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"]}
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@ziro-agent/openai",
3
+ "version": "0.1.0",
4
+ "description": "OpenAI provider for ZiroAgent SDK.",
5
+ "license": "Apache-2.0",
6
+ "homepage": "https://github.com/ziroagent/sdk-typescript/tree/main/packages/providers-openai",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/ziroagent/sdk-typescript.git",
10
+ "directory": "packages/providers-openai"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/ziroagent/sdk-typescript/issues"
14
+ },
15
+ "keywords": [
16
+ "ai",
17
+ "llm",
18
+ "openai",
19
+ "ziroagent",
20
+ "gpt"
21
+ ],
22
+ "type": "module",
23
+ "sideEffects": false,
24
+ "main": "./dist/index.cjs",
25
+ "module": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.js",
31
+ "require": "./dist/index.cjs"
32
+ },
33
+ "./package.json": "./package.json"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "scripts": {
41
+ "build": "tsup",
42
+ "dev": "tsup --watch",
43
+ "test": "vitest run",
44
+ "test:watch": "vitest",
45
+ "typecheck": "tsc --noEmit",
46
+ "clean": "rm -rf dist .turbo *.tsbuildinfo",
47
+ "publint": "publint",
48
+ "attw": "attw --pack ."
49
+ },
50
+ "dependencies": {
51
+ "@ziro-agent/core": "workspace:*"
52
+ },
53
+ "devDependencies": {
54
+ "@arethetypeswrong/cli": "^0.18.2",
55
+ "msw": "^2.11.7",
56
+ "publint": "^0.3.18",
57
+ "tsup": "^8.5.1",
58
+ "typescript": "^5.9.3",
59
+ "vitest": "^4.1.4"
60
+ },
61
+ "engines": {
62
+ "node": ">=20.10.0"
63
+ },
64
+ "publishConfig": {
65
+ "access": "public"
66
+ }
67
+ }