@yourgpt/llm-sdk 2.1.10-alpha.0 → 2.5.1-beta.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.
Files changed (59) hide show
  1. package/dist/adapters/index.d.mts +4 -38
  2. package/dist/adapters/index.d.ts +4 -38
  3. package/dist/adapters/index.js +158 -325
  4. package/dist/adapters/index.mjs +158 -325
  5. package/dist/base-C58Dsr9p.d.ts +259 -0
  6. package/dist/base-tNgbBaSo.d.mts +259 -0
  7. package/dist/fallback/index.d.mts +4 -4
  8. package/dist/fallback/index.d.ts +4 -4
  9. package/dist/index.d.mts +8 -7
  10. package/dist/index.d.ts +8 -7
  11. package/dist/index.js +35 -43
  12. package/dist/index.mjs +35 -43
  13. package/dist/providers/anthropic/index.d.mts +3 -3
  14. package/dist/providers/anthropic/index.d.ts +3 -3
  15. package/dist/providers/anthropic/index.js +271 -212
  16. package/dist/providers/anthropic/index.mjs +271 -212
  17. package/dist/providers/azure/index.d.mts +3 -3
  18. package/dist/providers/azure/index.d.ts +3 -3
  19. package/dist/providers/azure/index.js +49 -1
  20. package/dist/providers/azure/index.mjs +49 -1
  21. package/dist/providers/fireworks/index.d.mts +1 -1
  22. package/dist/providers/fireworks/index.d.ts +1 -1
  23. package/dist/providers/fireworks/index.js +56 -0
  24. package/dist/providers/fireworks/index.mjs +56 -0
  25. package/dist/providers/google/index.d.mts +3 -3
  26. package/dist/providers/google/index.d.ts +3 -3
  27. package/dist/providers/google/index.js +254 -510
  28. package/dist/providers/google/index.mjs +254 -510
  29. package/dist/providers/ollama/index.d.mts +4 -4
  30. package/dist/providers/ollama/index.d.ts +4 -4
  31. package/dist/providers/ollama/index.js +10 -2
  32. package/dist/providers/ollama/index.mjs +10 -2
  33. package/dist/providers/openai/index.d.mts +3 -3
  34. package/dist/providers/openai/index.d.ts +3 -3
  35. package/dist/providers/openai/index.js +269 -529
  36. package/dist/providers/openai/index.mjs +269 -529
  37. package/dist/providers/openrouter/index.d.mts +3 -7
  38. package/dist/providers/openrouter/index.d.ts +3 -7
  39. package/dist/providers/openrouter/index.js +365 -902
  40. package/dist/providers/openrouter/index.mjs +365 -902
  41. package/dist/providers/togetherai/index.d.mts +3 -3
  42. package/dist/providers/togetherai/index.d.ts +3 -3
  43. package/dist/providers/togetherai/index.js +259 -509
  44. package/dist/providers/togetherai/index.mjs +259 -509
  45. package/dist/providers/xai/index.d.mts +3 -3
  46. package/dist/providers/xai/index.d.ts +3 -3
  47. package/dist/providers/xai/index.js +258 -513
  48. package/dist/providers/xai/index.mjs +258 -513
  49. package/dist/{types-BNCmlJMs.d.mts → types-B6dhnguR.d.mts} +1 -1
  50. package/dist/{types-DhktekQ3.d.ts → types-BQ31QIsA.d.ts} +2 -1
  51. package/dist/{types-CMMQ8s2O.d.mts → types-BSSiJW2o.d.mts} +2 -1
  52. package/dist/{base-DN1EfKnE.d.mts → types-BkQCSiIt.d.mts} +388 -214
  53. package/dist/{base-DuUNxtVg.d.ts → types-BkQCSiIt.d.ts} +388 -214
  54. package/dist/{types-Pj-vpmoT.d.ts → types-CCxPmkmK.d.ts} +1 -1
  55. package/dist/yourgpt/index.d.mts +1 -1
  56. package/dist/yourgpt/index.d.ts +1 -1
  57. package/package.json +1 -1
  58. package/dist/types-CMvvDo-E.d.mts +0 -428
  59. package/dist/types-CMvvDo-E.d.ts +0 -428
@@ -1,5 +1,234 @@
1
1
  'use strict';
2
2
 
3
+ // src/adapters/base.ts
4
+ function stringifyForDebug(value) {
5
+ return JSON.stringify(
6
+ value,
7
+ (_key, currentValue) => {
8
+ if (typeof currentValue === "bigint") {
9
+ return currentValue.toString();
10
+ }
11
+ if (currentValue instanceof Error) {
12
+ return {
13
+ name: currentValue.name,
14
+ message: currentValue.message,
15
+ stack: currentValue.stack
16
+ };
17
+ }
18
+ return currentValue;
19
+ },
20
+ 2
21
+ );
22
+ }
23
+ function logProviderPayload(provider, label, payload, enabled) {
24
+ if (!enabled) {
25
+ return;
26
+ }
27
+ if (label.toLowerCase().includes("stream ")) {
28
+ return;
29
+ }
30
+ try {
31
+ console.log(
32
+ `[llm-sdk:${provider}] ${label}
33
+ ${stringifyForDebug(payload)}`
34
+ );
35
+ } catch (error) {
36
+ console.log(
37
+ `[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
38
+ error
39
+ );
40
+ }
41
+ }
42
+ function parameterToJsonSchema(param) {
43
+ const schema = {
44
+ type: param.type
45
+ };
46
+ if (param.description) {
47
+ schema.description = param.description;
48
+ }
49
+ if (param.enum) {
50
+ schema.enum = param.enum;
51
+ }
52
+ if (param.type === "array" && param.items) {
53
+ schema.items = parameterToJsonSchema(
54
+ param.items
55
+ );
56
+ }
57
+ if (param.type === "object" && param.properties) {
58
+ schema.properties = Object.fromEntries(
59
+ Object.entries(param.properties).map(([key, prop]) => [
60
+ key,
61
+ parameterToJsonSchema(
62
+ prop
63
+ )
64
+ ])
65
+ );
66
+ schema.additionalProperties = false;
67
+ }
68
+ return schema;
69
+ }
70
+ function normalizeObjectJsonSchema(schema) {
71
+ if (!schema || typeof schema !== "object") {
72
+ return {
73
+ type: "object",
74
+ properties: {},
75
+ required: [],
76
+ additionalProperties: false
77
+ };
78
+ }
79
+ const normalized = { ...schema };
80
+ const type = normalized.type;
81
+ if (type === "object") {
82
+ const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
83
+ normalized.properties = Object.fromEntries(
84
+ Object.entries(properties).map(([key, value]) => [
85
+ key,
86
+ normalizeObjectJsonSchema(value)
87
+ ])
88
+ );
89
+ const propertyKeys = Object.keys(properties);
90
+ const required = Array.isArray(normalized.required) ? normalized.required.filter(
91
+ (value) => typeof value === "string"
92
+ ) : [];
93
+ normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
94
+ if (normalized.additionalProperties === void 0) {
95
+ normalized.additionalProperties = false;
96
+ }
97
+ } else if (type === "array" && normalized.items && typeof normalized.items === "object") {
98
+ normalized.items = normalizeObjectJsonSchema(
99
+ normalized.items
100
+ );
101
+ }
102
+ return normalized;
103
+ }
104
+ function isOpenAIReasoningModel(modelId) {
105
+ if (!modelId) return false;
106
+ return /^(o1|o3|o4|gpt-5)/i.test(modelId);
107
+ }
108
+ function buildOpenAITokenParams(modelId, maxTokens, temperature) {
109
+ if (isOpenAIReasoningModel(modelId)) {
110
+ return { max_completion_tokens: maxTokens };
111
+ }
112
+ return { max_tokens: maxTokens, temperature };
113
+ }
114
+ function toOpenAIResponseFormat(rf) {
115
+ if (!rf) return void 0;
116
+ if (rf.type === "json_object") return { type: "json_object" };
117
+ return {
118
+ type: "json_schema",
119
+ json_schema: {
120
+ name: rf.json_schema.name,
121
+ schema: normalizeObjectJsonSchema(rf.json_schema.schema),
122
+ strict: rf.json_schema.strict ?? true
123
+ }
124
+ };
125
+ }
126
+ function toOpenAIResponsesTextFormat(rf) {
127
+ if (!rf || rf.type !== "json_schema") return void 0;
128
+ return {
129
+ type: "json_schema",
130
+ name: rf.json_schema.name,
131
+ schema: normalizeObjectJsonSchema(rf.json_schema.schema),
132
+ strict: rf.json_schema.strict ?? true
133
+ };
134
+ }
135
+ function formatTools(actions) {
136
+ return actions.map((action) => ({
137
+ type: "function",
138
+ function: {
139
+ name: action.name,
140
+ description: action.description,
141
+ parameters: {
142
+ type: "object",
143
+ properties: action.parameters ? Object.fromEntries(
144
+ Object.entries(action.parameters).map(([key, param]) => [
145
+ key,
146
+ parameterToJsonSchema(param)
147
+ ])
148
+ ) : {},
149
+ required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
150
+ additionalProperties: false
151
+ }
152
+ }
153
+ }));
154
+ }
155
+ function hasImageAttachments(message) {
156
+ const attachments = message.metadata?.attachments;
157
+ return attachments?.some((a) => a.type === "image") ?? false;
158
+ }
159
+ function attachmentToOpenAIImage(attachment) {
160
+ if (attachment.type !== "image") return null;
161
+ let imageUrl;
162
+ if (attachment.url) {
163
+ imageUrl = attachment.url;
164
+ } else if (attachment.data) {
165
+ imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
166
+ } else {
167
+ return null;
168
+ }
169
+ return {
170
+ type: "image_url",
171
+ image_url: {
172
+ url: imageUrl,
173
+ detail: "auto"
174
+ }
175
+ };
176
+ }
177
+ function messageToOpenAIContent(message) {
178
+ const attachments = message.metadata?.attachments;
179
+ const content = message.content ?? "";
180
+ if (!hasImageAttachments(message)) {
181
+ return content;
182
+ }
183
+ const blocks = [];
184
+ if (content) {
185
+ blocks.push({ type: "text", text: content });
186
+ }
187
+ if (attachments) {
188
+ for (const attachment of attachments) {
189
+ const imageBlock = attachmentToOpenAIImage(attachment);
190
+ if (imageBlock) {
191
+ blocks.push(imageBlock);
192
+ }
193
+ }
194
+ }
195
+ return blocks;
196
+ }
197
+ function formatMessagesForOpenAI(messages, systemPrompt) {
198
+ const formatted = [];
199
+ if (systemPrompt) {
200
+ formatted.push({ role: "system", content: systemPrompt });
201
+ }
202
+ for (const msg of messages) {
203
+ if (msg.role === "system") {
204
+ formatted.push({ role: "system", content: msg.content ?? "" });
205
+ } else if (msg.role === "user") {
206
+ formatted.push({
207
+ role: "user",
208
+ content: messageToOpenAIContent(msg)
209
+ });
210
+ } else if (msg.role === "assistant") {
211
+ const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
212
+ const assistantMsg = {
213
+ role: "assistant",
214
+ // Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
215
+ content: hasToolCalls ? msg.content || null : msg.content
216
+ };
217
+ if (hasToolCalls) {
218
+ assistantMsg.tool_calls = msg.tool_calls;
219
+ }
220
+ formatted.push(assistantMsg);
221
+ } else if (msg.role === "tool" && msg.tool_call_id) {
222
+ formatted.push({
223
+ role: "tool",
224
+ content: msg.content ?? "",
225
+ tool_call_id: msg.tool_call_id
226
+ });
227
+ }
228
+ }
229
+ return formatted;
230
+ }
231
+
3
232
  // src/providers/openrouter/provider.ts
4
233
  var DEFAULT_MODEL_CONFIG = {
5
234
  vision: true,
@@ -7,9 +236,6 @@ var DEFAULT_MODEL_CONFIG = {
7
236
  jsonMode: true,
8
237
  maxTokens: 128e3
9
238
  };
10
- function isOpenAIReasoningModel(modelId) {
11
- return modelId.startsWith("openai/o1") || modelId.startsWith("openai/o3") || modelId.startsWith("openai/o4") || modelId.startsWith("openai/gpt-5");
12
- }
13
239
  function openrouter(modelId, options = {}) {
14
240
  const apiKey = options.apiKey ?? process.env.OPENROUTER_API_KEY;
15
241
  const baseURL = options.baseURL ?? "https://openrouter.ai/api/v1";
@@ -41,7 +267,7 @@ function openrouter(modelId, options = {}) {
41
267
  supportsTools: modelConfig.tools,
42
268
  supportsStreaming: true,
43
269
  supportsJsonMode: modelConfig.jsonMode,
44
- supportsThinking: true,
270
+ supportsThinking: false,
45
271
  supportsPDF: false,
46
272
  maxTokens: modelConfig.maxTokens,
47
273
  supportedImageTypes: modelConfig.vision ? ["image/png", "image/jpeg", "image/gif", "image/webp"] : []
@@ -61,6 +287,10 @@ function openrouter(modelId, options = {}) {
61
287
  if (options.providerPreferences) {
62
288
  requestBody.provider = options.providerPreferences;
63
289
  }
290
+ const responseFormat = toOpenAIResponseFormat(params.responseFormat);
291
+ if (responseFormat) {
292
+ requestBody.response_format = responseFormat;
293
+ }
64
294
  const response = await client2.chat.completions.create(requestBody);
65
295
  const choice = response.choices[0];
66
296
  const message = choice.message;
@@ -84,11 +314,6 @@ function openrouter(modelId, options = {}) {
84
314
  };
85
315
  },
86
316
  async *doStream(params) {
87
- if (!options.disableThinking && isOpenAIReasoningModel(modelId)) {
88
- const client3 = await getClient();
89
- yield* doStreamResponsesAPI(client3, modelId, params);
90
- return;
91
- }
92
317
  const client2 = await getClient();
93
318
  const messages = formatMessagesForOpenRouter(params.messages);
94
319
  const requestBody = {
@@ -96,8 +321,7 @@ function openrouter(modelId, options = {}) {
96
321
  messages,
97
322
  temperature: params.temperature,
98
323
  max_tokens: params.maxTokens,
99
- stream: true,
100
- ...!options.disableThinking ? { reasoning: { max_tokens: 8e3 }, include_reasoning: true } : {}
324
+ stream: true
101
325
  };
102
326
  if (params.tools) {
103
327
  requestBody.tools = params.tools;
@@ -105,11 +329,14 @@ function openrouter(modelId, options = {}) {
105
329
  if (options.providerPreferences) {
106
330
  requestBody.provider = options.providerPreferences;
107
331
  }
332
+ const responseFormat = toOpenAIResponseFormat(params.responseFormat);
333
+ if (responseFormat) {
334
+ requestBody.response_format = responseFormat;
335
+ }
108
336
  const stream = await client2.chat.completions.create(requestBody);
109
337
  let currentToolCall = null;
110
338
  let totalPromptTokens = 0;
111
339
  let totalCompletionTokens = 0;
112
- let orReasoningStarted = false;
113
340
  for await (const chunk of stream) {
114
341
  if (params.signal?.aborted) {
115
342
  yield { type: "error", error: new Error("Aborted") };
@@ -120,20 +347,6 @@ function openrouter(modelId, options = {}) {
120
347
  if (delta?.content) {
121
348
  yield { type: "text-delta", text: delta.content };
122
349
  }
123
- const rc = delta?.reasoning_content ?? delta?.reasoning ?? null;
124
- if (rc) {
125
- const rcText = typeof rc === "string" ? rc : Array.isArray(rc) && rc[0]?.text ? rc[0].text : "";
126
- if (rcText) {
127
- if (!orReasoningStarted) {
128
- yield { type: "thinking:start" };
129
- orReasoningStarted = true;
130
- }
131
- yield { type: "thinking:delta", content: rcText };
132
- }
133
- } else if (orReasoningStarted && (delta?.content || choice?.finish_reason)) {
134
- yield { type: "thinking:end" };
135
- orReasoningStarted = false;
136
- }
137
350
  if (delta?.tool_calls) {
138
351
  for (const tc of delta.tool_calls) {
139
352
  if (tc.id) {
@@ -173,578 +386,118 @@ function openrouter(modelId, options = {}) {
173
386
  totalPromptTokens = chunk.usage.prompt_tokens;
174
387
  totalCompletionTokens = chunk.usage.completion_tokens;
175
388
  }
176
- yield {
177
- type: "finish",
178
- finishReason: mapFinishReason(choice.finish_reason),
179
- usage: {
180
- promptTokens: totalPromptTokens,
181
- completionTokens: totalCompletionTokens,
182
- totalTokens: totalPromptTokens + totalCompletionTokens
183
- }
184
- };
185
- }
186
- }
187
- }
188
- };
189
- }
190
- function mapFinishReason(reason) {
191
- switch (reason) {
192
- case "stop":
193
- return "stop";
194
- case "length":
195
- return "length";
196
- case "tool_calls":
197
- case "function_call":
198
- return "tool-calls";
199
- case "content_filter":
200
- return "content-filter";
201
- default:
202
- return "unknown";
203
- }
204
- }
205
- function formatMessagesForOpenRouter(messages) {
206
- return messages.map((msg) => {
207
- switch (msg.role) {
208
- case "system":
209
- return { role: "system", content: msg.content };
210
- case "user":
211
- if (typeof msg.content === "string") {
212
- return { role: "user", content: msg.content };
213
- }
214
- return {
215
- role: "user",
216
- content: msg.content.map((part) => {
217
- if (part.type === "text") {
218
- return { type: "text", text: part.text };
219
- }
220
- if (part.type === "image") {
221
- const imageData = typeof part.image === "string" ? part.image : Buffer.from(part.image).toString("base64");
222
- const url = imageData.startsWith("data:") ? imageData : `data:${part.mimeType ?? "image/png"};base64,${imageData}`;
223
- return { type: "image_url", image_url: { url, detail: "auto" } };
224
- }
225
- return { type: "text", text: "" };
226
- })
227
- };
228
- case "assistant":
229
- const assistantMsg = {
230
- role: "assistant",
231
- content: msg.content
232
- };
233
- if (msg.toolCalls && msg.toolCalls.length > 0) {
234
- assistantMsg.tool_calls = msg.toolCalls.map((tc) => ({
235
- id: tc.id,
236
- type: "function",
237
- function: {
238
- name: tc.name,
239
- arguments: JSON.stringify(tc.args)
240
- }
241
- }));
242
- }
243
- return assistantMsg;
244
- case "tool":
245
- return {
246
- role: "tool",
247
- tool_call_id: msg.toolCallId,
248
- content: msg.content
249
- };
250
- default:
251
- return msg;
252
- }
253
- });
254
- }
255
- function formatMessagesForResponsesAPI(messages) {
256
- const out = [];
257
- for (const msg of messages) {
258
- if (msg.role === "system") {
259
- out.push({
260
- type: "message",
261
- role: "system",
262
- content: [
263
- {
264
- type: "input_text",
265
- text: typeof msg.content === "string" ? msg.content : ""
266
- }
267
- ]
268
- });
269
- continue;
270
- }
271
- if (msg.role === "user") {
272
- const parts = [];
273
- if (typeof msg.content === "string") {
274
- parts.push({ type: "input_text", text: msg.content });
275
- } else {
276
- for (const part of msg.content) {
277
- if (part.type === "text") {
278
- parts.push({ type: "input_text", text: part.text });
279
- } else if (part.type === "image") {
280
- const imageData = typeof part.image === "string" ? part.image : Buffer.from(part.image).toString("base64");
281
- const url = imageData.startsWith("data:") ? imageData : `data:${part.mimeType ?? "image/png"};base64,${imageData}`;
282
- parts.push({ type: "input_image", image_url: url });
283
- }
284
- }
285
- }
286
- out.push({ type: "message", role: "user", content: parts });
287
- continue;
288
- }
289
- if (msg.role === "assistant") {
290
- if (msg.toolCalls && msg.toolCalls.length > 0) {
291
- for (const tc of msg.toolCalls) {
292
- out.push({
293
- type: "function_call",
294
- call_id: tc.id,
295
- name: tc.name,
296
- arguments: JSON.stringify(tc.args ?? {})
297
- });
298
- }
299
- if (typeof msg.content === "string" && msg.content.length > 0) {
300
- out.push({
301
- type: "message",
302
- role: "assistant",
303
- content: [{ type: "output_text", text: msg.content }]
304
- });
305
- }
306
- } else {
307
- const text = typeof msg.content === "string" ? msg.content : "";
308
- out.push({
309
- type: "message",
310
- role: "assistant",
311
- content: [{ type: "output_text", text }]
312
- });
313
- }
314
- continue;
315
- }
316
- if (msg.role === "tool") {
317
- out.push({
318
- type: "function_call_output",
319
- call_id: msg.toolCallId,
320
- output: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
321
- });
322
- continue;
323
- }
324
- }
325
- return out;
326
- }
327
- function formatToolsForResponsesAPI(tools) {
328
- if (!tools || tools.length === 0) return void 0;
329
- return tools.map((t) => {
330
- if (t?.name && t?.parameters && t?.type === "function") return t;
331
- const fn = t?.function ?? t;
332
- return {
333
- type: "function",
334
- name: fn.name,
335
- description: fn.description,
336
- parameters: fn.parameters ?? { type: "object", properties: {} }
337
- };
338
- });
339
- }
340
- async function* doStreamResponsesAPI(client, modelId, params) {
341
- const systemTexts = [];
342
- const nonSystem = [];
343
- for (const m of params.messages) {
344
- if (m.role === "system" && typeof m.content === "string") {
345
- systemTexts.push(m.content);
346
- } else {
347
- nonSystem.push(m);
348
- }
349
- }
350
- const instructions = systemTexts.join("\n\n") || void 0;
351
- const input = formatMessagesForResponsesAPI(nonSystem);
352
- const requestBody = {
353
- model: modelId,
354
- input,
355
- stream: true,
356
- reasoning: { effort: "medium", summary: "auto" }
357
- };
358
- if (instructions) requestBody.instructions = instructions;
359
- if (typeof params.maxTokens === "number")
360
- requestBody.max_output_tokens = params.maxTokens;
361
- if (typeof params.temperature === "number")
362
- requestBody.temperature = params.temperature;
363
- const tools = formatToolsForResponsesAPI(params.tools);
364
- if (tools) requestBody.tools = tools;
365
- let stream;
366
- try {
367
- stream = await client.responses.create(requestBody);
368
- } catch (err) {
369
- yield {
370
- type: "error",
371
- error: err instanceof Error ? err : new Error(String(err))
372
- };
373
- return;
374
- }
375
- const toolCalls = /* @__PURE__ */ new Map();
376
- let reasoningStarted = false;
377
- let textStarted = false;
378
- let totalPromptTokens = 0;
379
- let totalCompletionTokens = 0;
380
- let finishEmitted = false;
381
- for await (const evt of stream) {
382
- if (params.signal?.aborted) {
383
- yield { type: "error", error: new Error("Aborted") };
384
- return;
385
- }
386
- const t = evt?.type ?? "";
387
- if (t === "response.reasoning_summary_text.delta") {
388
- const delta = evt.delta ?? "";
389
- if (!delta) continue;
390
- if (!reasoningStarted) {
391
- yield { type: "thinking:start" };
392
- reasoningStarted = true;
393
- }
394
- yield { type: "thinking:delta", content: delta };
395
- continue;
396
- }
397
- if (t === "response.reasoning_summary_text.done" || t === "response.reasoning.done") {
398
- continue;
399
- }
400
- if (t === "response.output_text.delta") {
401
- const text = evt.delta ?? "";
402
- if (!text) continue;
403
- if (reasoningStarted && !textStarted) {
404
- yield { type: "thinking:end" };
405
- textStarted = true;
406
- }
407
- yield { type: "text-delta", text };
408
- continue;
409
- }
410
- if (t === "response.output_item.added") {
411
- const item = evt.item;
412
- if (item?.type === "function_call") {
413
- const id = item.call_id ?? item.id ?? "";
414
- if (id) {
415
- toolCalls.set(id, {
416
- id,
417
- name: item.name ?? "",
418
- arguments: item.arguments ?? ""
419
- });
420
- }
421
- }
422
- continue;
423
- }
424
- if (t === "response.function_call_arguments.delta") {
425
- const id = evt.call_id ?? evt.item_id ?? "";
426
- const delta = evt.delta ?? "";
427
- if (!id || !delta) continue;
428
- const existing = toolCalls.get(id);
429
- if (existing) {
430
- existing.arguments += delta;
431
- } else {
432
- toolCalls.set(id, { id, name: "", arguments: delta });
433
- }
434
- continue;
435
- }
436
- if (t === "response.output_item.done") {
437
- const item = evt.item;
438
- if (item?.type === "function_call") {
439
- const id = item.call_id ?? item.id ?? "";
440
- const tc = toolCalls.get(id);
441
- const name = tc?.name || item.name || "";
442
- const argsStr = tc?.arguments || item.arguments || "{}";
443
- let args = {};
444
- try {
445
- args = JSON.parse(argsStr || "{}");
446
- } catch {
447
- args = {};
448
- }
449
- if (id && name) {
450
- yield {
451
- type: "tool-call",
452
- toolCall: { id, name, args }
453
- };
454
- }
455
- toolCalls.delete(id);
456
- }
457
- continue;
458
- }
459
- if (t === "response.completed") {
460
- const usage = evt.response?.usage;
461
- if (usage) {
462
- totalPromptTokens = usage.input_tokens ?? 0;
463
- totalCompletionTokens = usage.output_tokens ?? 0;
464
- }
465
- for (const tc of toolCalls.values()) {
466
- let args = {};
467
- try {
468
- args = JSON.parse(tc.arguments || "{}");
469
- } catch {
470
- args = {};
471
- }
472
- if (tc.id && tc.name) {
473
- yield {
474
- type: "tool-call",
475
- toolCall: { id: tc.id, name: tc.name, args }
476
- };
477
- }
478
- }
479
- toolCalls.clear();
480
- if (reasoningStarted && !textStarted) {
481
- yield { type: "thinking:end" };
482
- }
483
- const finishReason = toolCalls.size > 0 ? "tool-calls" : "stop";
484
- yield {
485
- type: "finish",
486
- finishReason,
487
- usage: {
488
- promptTokens: totalPromptTokens,
489
- completionTokens: totalCompletionTokens,
490
- totalTokens: totalPromptTokens + totalCompletionTokens
491
- }
492
- };
493
- finishEmitted = true;
494
- continue;
495
- }
496
- if (t === "response.error" || t === "error") {
497
- const msg = evt.error?.message || evt.message || "Responses API error";
498
- yield { type: "error", error: new Error(msg) };
499
- return;
500
- }
501
- }
502
- if (!finishEmitted) {
503
- if (reasoningStarted && !textStarted) {
504
- yield { type: "thinking:end" };
505
- }
506
- yield {
507
- type: "finish",
508
- finishReason: "stop",
509
- usage: {
510
- promptTokens: totalPromptTokens,
511
- completionTokens: totalCompletionTokens,
512
- totalTokens: totalPromptTokens + totalCompletionTokens
513
- }
514
- };
515
- }
516
- }
517
- async function fetchOpenRouterModels(apiKey) {
518
- const headers = {
519
- "Content-Type": "application/json"
520
- };
521
- if (apiKey) {
522
- headers["Authorization"] = `Bearer ${apiKey}`;
523
- }
524
- const response = await fetch("https://openrouter.ai/api/v1/models", {
525
- headers
526
- });
527
- if (!response.ok) {
528
- throw new Error(`Failed to fetch models: ${response.statusText}`);
529
- }
530
- const data = await response.json();
531
- return data.data || [];
532
- }
533
- async function searchOpenRouterModels(query, apiKey) {
534
- const models = await fetchOpenRouterModels(apiKey);
535
- const lowerQuery = query.toLowerCase();
536
- return models.filter(
537
- (model) => model.id.toLowerCase().includes(lowerQuery) || model.name.toLowerCase().includes(lowerQuery)
538
- );
539
- }
540
-
541
- // src/core/utils.ts
542
- function generateId(prefix = "id") {
543
- return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
544
- }
545
- function generateMessageId() {
546
- return generateId("msg");
547
- }
548
- function generateToolCallId() {
549
- return generateId("call");
550
- }
551
-
552
- // src/adapters/base.ts
553
- function stringifyForDebug(value) {
554
- return JSON.stringify(
555
- value,
556
- (_key, currentValue) => {
557
- if (typeof currentValue === "bigint") {
558
- return currentValue.toString();
559
- }
560
- if (currentValue instanceof Error) {
561
- return {
562
- name: currentValue.name,
563
- message: currentValue.message,
564
- stack: currentValue.stack
565
- };
566
- }
567
- return currentValue;
568
- },
569
- 2
570
- );
571
- }
572
- function logProviderPayload(provider, label, payload, enabled) {
573
- if (!enabled) {
574
- return;
575
- }
576
- if (label.toLowerCase().includes("stream ")) {
577
- return;
578
- }
579
- try {
580
- console.log(
581
- `[llm-sdk:${provider}] ${label}
582
- ${stringifyForDebug(payload)}`
583
- );
584
- } catch (error) {
585
- console.log(
586
- `[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
587
- error
588
- );
589
- }
590
- }
591
- function parameterToJsonSchema(param) {
592
- const schema = {
593
- type: param.type
594
- };
595
- if (param.description) {
596
- schema.description = param.description;
597
- }
598
- if (param.enum) {
599
- schema.enum = param.enum;
600
- }
601
- if (param.type === "array" && param.items) {
602
- schema.items = parameterToJsonSchema(
603
- param.items
604
- );
605
- }
606
- if (param.type === "object" && param.properties) {
607
- schema.properties = Object.fromEntries(
608
- Object.entries(param.properties).map(([key, prop]) => [
609
- key,
610
- parameterToJsonSchema(
611
- prop
612
- )
613
- ])
614
- );
615
- schema.additionalProperties = false;
616
- }
617
- return schema;
618
- }
619
- function normalizeObjectJsonSchema(schema) {
620
- if (!schema || typeof schema !== "object") {
621
- return {
622
- type: "object",
623
- properties: {},
624
- required: [],
625
- additionalProperties: false
626
- };
627
- }
628
- const normalized = { ...schema };
629
- const type = normalized.type;
630
- if (type === "object") {
631
- const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
632
- normalized.properties = Object.fromEntries(
633
- Object.entries(properties).map(([key, value]) => [
634
- key,
635
- normalizeObjectJsonSchema(value)
636
- ])
637
- );
638
- const propertyKeys = Object.keys(properties);
639
- const required = Array.isArray(normalized.required) ? normalized.required.filter(
640
- (value) => typeof value === "string"
641
- ) : [];
642
- normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
643
- if (normalized.additionalProperties === void 0) {
644
- normalized.additionalProperties = false;
645
- }
646
- } else if (type === "array" && normalized.items && typeof normalized.items === "object") {
647
- normalized.items = normalizeObjectJsonSchema(
648
- normalized.items
649
- );
650
- }
651
- return normalized;
652
- }
653
- function formatTools(actions) {
654
- return actions.map((action) => ({
655
- type: "function",
656
- function: {
657
- name: action.name,
658
- description: action.description,
659
- parameters: {
660
- type: "object",
661
- properties: action.parameters ? Object.fromEntries(
662
- Object.entries(action.parameters).map(([key, param]) => [
663
- key,
664
- parameterToJsonSchema(param)
665
- ])
666
- ) : {},
667
- required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
668
- additionalProperties: false
389
+ yield {
390
+ type: "finish",
391
+ finishReason: mapFinishReason(choice.finish_reason),
392
+ usage: {
393
+ promptTokens: totalPromptTokens,
394
+ completionTokens: totalCompletionTokens,
395
+ totalTokens: totalPromptTokens + totalCompletionTokens
396
+ }
397
+ };
398
+ }
669
399
  }
670
400
  }
671
- }));
672
- }
673
- function hasImageAttachments(message) {
674
- const attachments = message.metadata?.attachments;
675
- return attachments?.some((a) => a.type === "image") ?? false;
676
- }
677
- function attachmentToOpenAIImage(attachment) {
678
- if (attachment.type !== "image") return null;
679
- let imageUrl;
680
- if (attachment.url) {
681
- imageUrl = attachment.url;
682
- } else if (attachment.data) {
683
- imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
684
- } else {
685
- return null;
686
- }
687
- return {
688
- type: "image_url",
689
- image_url: {
690
- url: imageUrl,
691
- detail: "auto"
692
- }
693
401
  };
694
402
  }
695
- function messageToOpenAIContent(message) {
696
- const attachments = message.metadata?.attachments;
697
- const content = message.content ?? "";
698
- if (!hasImageAttachments(message)) {
699
- return content;
700
- }
701
- const blocks = [];
702
- if (content) {
703
- blocks.push({ type: "text", text: content });
403
+ function mapFinishReason(reason) {
404
+ switch (reason) {
405
+ case "stop":
406
+ return "stop";
407
+ case "length":
408
+ return "length";
409
+ case "tool_calls":
410
+ case "function_call":
411
+ return "tool-calls";
412
+ case "content_filter":
413
+ return "content-filter";
414
+ default:
415
+ return "unknown";
704
416
  }
705
- if (attachments) {
706
- for (const attachment of attachments) {
707
- const imageBlock = attachmentToOpenAIImage(attachment);
708
- if (imageBlock) {
709
- blocks.push(imageBlock);
710
- }
417
+ }
418
+ function formatMessagesForOpenRouter(messages) {
419
+ return messages.map((msg) => {
420
+ switch (msg.role) {
421
+ case "system":
422
+ return { role: "system", content: msg.content };
423
+ case "user":
424
+ if (typeof msg.content === "string") {
425
+ return { role: "user", content: msg.content };
426
+ }
427
+ return {
428
+ role: "user",
429
+ content: msg.content.map((part) => {
430
+ if (part.type === "text") {
431
+ return { type: "text", text: part.text };
432
+ }
433
+ if (part.type === "image") {
434
+ const imageData = typeof part.image === "string" ? part.image : Buffer.from(part.image).toString("base64");
435
+ const url = imageData.startsWith("data:") ? imageData : `data:${part.mimeType ?? "image/png"};base64,${imageData}`;
436
+ return { type: "image_url", image_url: { url, detail: "auto" } };
437
+ }
438
+ return { type: "text", text: "" };
439
+ })
440
+ };
441
+ case "assistant":
442
+ const assistantMsg = {
443
+ role: "assistant",
444
+ content: msg.content
445
+ };
446
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
447
+ assistantMsg.tool_calls = msg.toolCalls.map((tc) => ({
448
+ id: tc.id,
449
+ type: "function",
450
+ function: {
451
+ name: tc.name,
452
+ arguments: JSON.stringify(tc.args)
453
+ }
454
+ }));
455
+ }
456
+ return assistantMsg;
457
+ case "tool":
458
+ return {
459
+ role: "tool",
460
+ tool_call_id: msg.toolCallId,
461
+ content: msg.content
462
+ };
463
+ default:
464
+ return msg;
711
465
  }
712
- }
713
- return blocks;
466
+ });
714
467
  }
715
- function formatMessagesForOpenAI(messages, systemPrompt) {
716
- const formatted = [];
717
- if (systemPrompt) {
718
- formatted.push({ role: "system", content: systemPrompt });
468
+ async function fetchOpenRouterModels(apiKey) {
469
+ const headers = {
470
+ "Content-Type": "application/json"
471
+ };
472
+ if (apiKey) {
473
+ headers["Authorization"] = `Bearer ${apiKey}`;
719
474
  }
720
- for (const msg of messages) {
721
- if (msg.role === "system") {
722
- formatted.push({ role: "system", content: msg.content ?? "" });
723
- } else if (msg.role === "user") {
724
- formatted.push({
725
- role: "user",
726
- content: messageToOpenAIContent(msg)
727
- });
728
- } else if (msg.role === "assistant") {
729
- const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
730
- const assistantMsg = {
731
- role: "assistant",
732
- // Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
733
- content: hasToolCalls ? msg.content || null : msg.content
734
- };
735
- if (hasToolCalls) {
736
- assistantMsg.tool_calls = msg.tool_calls;
737
- }
738
- formatted.push(assistantMsg);
739
- } else if (msg.role === "tool" && msg.tool_call_id) {
740
- formatted.push({
741
- role: "tool",
742
- content: msg.content ?? "",
743
- tool_call_id: msg.tool_call_id
744
- });
745
- }
475
+ const response = await fetch("https://openrouter.ai/api/v1/models", {
476
+ headers
477
+ });
478
+ if (!response.ok) {
479
+ throw new Error(`Failed to fetch models: ${response.statusText}`);
746
480
  }
747
- return formatted;
481
+ const data = await response.json();
482
+ return data.data || [];
483
+ }
484
+ async function searchOpenRouterModels(query, apiKey) {
485
+ const models = await fetchOpenRouterModels(apiKey);
486
+ const lowerQuery = query.toLowerCase();
487
+ return models.filter(
488
+ (model) => model.id.toLowerCase().includes(lowerQuery) || model.name.toLowerCase().includes(lowerQuery)
489
+ );
490
+ }
491
+
492
+ // src/core/utils.ts
493
+ function generateId(prefix = "id") {
494
+ return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
495
+ }
496
+ function generateMessageId() {
497
+ return generateId("msg");
498
+ }
499
+ function generateToolCallId() {
500
+ return generateId("call");
748
501
  }
749
502
 
750
503
  // src/adapters/openai.ts
@@ -759,7 +512,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
759
512
  if (baseUrl.includes("generativelanguage.googleapis.com")) return "google";
760
513
  if (baseUrl.includes("x.ai")) return "xai";
761
514
  if (baseUrl.includes("azure")) return "azure";
762
- if (baseUrl.includes("openrouter.ai")) return "openrouter";
763
515
  return "openai";
764
516
  }
765
517
  async getClient() {
@@ -859,259 +611,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
859
611
  rawResponse: response
860
612
  };
861
613
  }
862
- /**
863
- * OpenAI reasoning models on OpenRouter (o1/o3/o4/gpt-5 family) hide their
864
- * reasoning content on the chat-completions endpoint. To surface reasoning
865
- * SUMMARIES (not raw CoT, which OpenAI never exposes) we have to use the
866
- * Responses API, which streams `response.reasoning_summary_text.delta` events.
867
- *
868
- * Match by prefix on the OpenRouter model id. Excludes openai/gpt-4o,
869
- * openai/gpt-4.1, openai/chatgpt-* — those continue on chat-completions.
870
- */
871
- isOpenAIReasoningModelOnOpenRouter(activeModel) {
872
- if (this.provider !== "openrouter") return false;
873
- return activeModel.startsWith("openai/o1") || activeModel.startsWith("openai/o3") || activeModel.startsWith("openai/o4") || activeModel.startsWith("openai/gpt-5");
874
- }
875
- /**
876
- * Convert ActionDefinition[] (the chat-completions tool shape used by the
877
- * adapter) to the Responses API tool shape.
878
- */
879
- buildResponsesToolsFromActions(actions) {
880
- if (!actions || actions.length === 0) return void 0;
881
- const formatted = formatTools(actions);
882
- return formatted.map((t) => ({
883
- type: "function",
884
- name: t.function.name,
885
- description: t.function.description,
886
- parameters: t.function.parameters
887
- }));
888
- }
889
- /**
890
- * Streaming Responses API path for OpenAI reasoning models on OpenRouter.
891
- *
892
- * Maps Responses API SSE events back to the same StreamEvent shapes the
893
- * chat-completions path emits, so downstream consumers (processChunk.ts,
894
- * frontend tool handlers, plan approval, specialist delegations) see
895
- * identical events regardless of which path produced them.
896
- *
897
- * response.reasoning_summary_text.delta → thinking:start (once) + thinking:delta
898
- * response.output_text.delta → message:delta
899
- * response.output_item.added (function_call) → action:start (queued buffer)
900
- * response.function_call_arguments.delta → action:args (progressive)
901
- * response.output_item.done (function_call) → final action:args + action:end
902
- * response.completed → message:end + done(usage)
903
- * response.error → error
904
- */
905
- async *streamWithResponsesAPI(request, activeModel, messageId) {
906
- const client = await this.getClient();
907
- const maxTokensValue = request.config?.maxTokens ?? this.config.maxTokens;
908
- const payload = {
909
- model: activeModel,
910
- input: this.buildResponsesInput(request),
911
- stream: true,
912
- reasoning: {
913
- effort: request.config?.reasoningEffort ?? "medium",
914
- summary: "auto"
915
- }
916
- };
917
- if (request.systemPrompt) payload.instructions = request.systemPrompt;
918
- if (typeof maxTokensValue === "number")
919
- payload.max_output_tokens = maxTokensValue;
920
- const tools = this.buildResponsesToolsFromActions(request.actions);
921
- if (tools && tools.length > 0) payload.tools = tools;
922
- logProviderPayload(
923
- "openai",
924
- "responses-api request payload",
925
- payload,
926
- request.debug
927
- );
928
- let stream;
929
- try {
930
- stream = await client.responses.create(payload);
931
- } catch (error) {
932
- yield {
933
- type: "error",
934
- message: error instanceof Error ? error.message : "Unknown error",
935
- code: "OPENAI_RESPONSES_ERROR"
936
- };
937
- return;
938
- }
939
- const toolBuffers = /* @__PURE__ */ new Map();
940
- const itemIdToCallId = /* @__PURE__ */ new Map();
941
- let usage;
942
- let reasoningStarted = false;
943
- let textStarted = false;
944
- let finishEmitted = false;
945
- const resolveCallId = (evt) => {
946
- if (evt?.call_id) return evt.call_id;
947
- if (evt?.item_id) return itemIdToCallId.get(evt.item_id) ?? evt.item_id;
948
- if (evt?.item?.call_id) return evt.item.call_id;
949
- if (evt?.item?.id) return evt.item.id;
950
- return "";
951
- };
952
- try {
953
- for await (const evt of stream) {
954
- logProviderPayload(
955
- "openai",
956
- "responses-api stream chunk",
957
- evt,
958
- request.debug
959
- );
960
- if (request.signal?.aborted) break;
961
- const t = evt?.type ?? "";
962
- if (t === "response.reasoning_summary_text.delta") {
963
- const delta = evt.delta ?? "";
964
- if (!delta) continue;
965
- if (!reasoningStarted) {
966
- yield { type: "thinking:start" };
967
- reasoningStarted = true;
968
- }
969
- yield { type: "thinking:delta", content: delta };
970
- continue;
971
- }
972
- if (t === "response.reasoning_summary_text.done" || t === "response.reasoning.done") {
973
- continue;
974
- }
975
- if (t === "response.output_text.delta") {
976
- const text = evt.delta ?? "";
977
- if (!text) continue;
978
- if (reasoningStarted && !textStarted) {
979
- yield { type: "thinking:end" };
980
- textStarted = true;
981
- }
982
- yield { type: "message:delta", content: text };
983
- continue;
984
- }
985
- if (t === "response.output_item.added") {
986
- const item = evt.item;
987
- if (item?.type === "function_call") {
988
- const callId = item.call_id ?? item.id ?? "";
989
- const itemId = item.id ?? callId;
990
- if (callId) {
991
- if (itemId && itemId !== callId) {
992
- itemIdToCallId.set(itemId, callId);
993
- }
994
- if (!toolBuffers.has(callId)) {
995
- toolBuffers.set(callId, {
996
- id: callId,
997
- name: item.name ?? "",
998
- arguments: item.arguments ?? "",
999
- emittedStart: false
1000
- });
1001
- }
1002
- const buf = toolBuffers.get(callId);
1003
- if (buf.name && !buf.emittedStart) {
1004
- yield { type: "action:start", id: buf.id, name: buf.name };
1005
- buf.emittedStart = true;
1006
- }
1007
- }
1008
- }
1009
- continue;
1010
- }
1011
- if (t === "response.function_call_arguments.delta") {
1012
- const callId = resolveCallId(evt);
1013
- const delta = evt.delta ?? "";
1014
- if (!callId || !delta) continue;
1015
- let buf = toolBuffers.get(callId);
1016
- if (!buf) {
1017
- buf = { id: callId, name: "", arguments: "", emittedStart: false };
1018
- toolBuffers.set(callId, buf);
1019
- }
1020
- buf.arguments += delta;
1021
- if (buf.emittedStart) {
1022
- yield {
1023
- type: "action:args",
1024
- id: buf.id,
1025
- args: buf.arguments
1026
- };
1027
- }
1028
- continue;
1029
- }
1030
- if (t === "response.output_item.done") {
1031
- const item = evt.item;
1032
- if (item?.type === "function_call") {
1033
- const callId = item.call_id ?? item.id ?? "";
1034
- const buf = toolBuffers.get(callId);
1035
- const name = buf?.name || item.name || "";
1036
- const argsStr = buf?.arguments || item.arguments || "{}";
1037
- if (callId && name) {
1038
- if (!buf?.emittedStart) {
1039
- yield { type: "action:start", id: callId, name };
1040
- }
1041
- yield {
1042
- type: "action:args",
1043
- id: callId,
1044
- args: argsStr
1045
- };
1046
- yield {
1047
- type: "action:end",
1048
- id: callId,
1049
- name
1050
- };
1051
- }
1052
- toolBuffers.delete(callId);
1053
- }
1054
- continue;
1055
- }
1056
- if (t === "response.completed") {
1057
- const u = evt.response?.usage;
1058
- if (u) {
1059
- usage = {
1060
- prompt_tokens: u.input_tokens ?? 0,
1061
- completion_tokens: u.output_tokens ?? 0,
1062
- total_tokens: u.total_tokens ?? (u.input_tokens ?? 0) + (u.output_tokens ?? 0)
1063
- };
1064
- }
1065
- for (const buf of toolBuffers.values()) {
1066
- if (!buf.id || !buf.name) continue;
1067
- if (!buf.emittedStart) {
1068
- yield { type: "action:start", id: buf.id, name: buf.name };
1069
- }
1070
- yield {
1071
- type: "action:args",
1072
- id: buf.id,
1073
- args: buf.arguments || "{}"
1074
- };
1075
- yield { type: "action:end", id: buf.id, name: buf.name };
1076
- }
1077
- toolBuffers.clear();
1078
- if (reasoningStarted && !textStarted) {
1079
- yield { type: "thinking:end" };
1080
- }
1081
- yield { type: "message:end" };
1082
- yield { type: "done", usage };
1083
- finishEmitted = true;
1084
- continue;
1085
- }
1086
- if (t === "response.error" || t === "error") {
1087
- const msg = evt.error?.message || evt.message || "Responses API error";
1088
- yield {
1089
- type: "error",
1090
- message: msg,
1091
- code: "OPENAI_RESPONSES_ERROR"
1092
- };
1093
- return;
1094
- }
1095
- }
1096
- } catch (error) {
1097
- yield {
1098
- type: "error",
1099
- message: error instanceof Error ? error.message : "Unknown error",
1100
- code: "OPENAI_RESPONSES_ERROR"
1101
- };
1102
- return;
1103
- }
1104
- if (!finishEmitted) {
1105
- if (reasoningStarted && !textStarted) {
1106
- yield { type: "thinking:end" };
1107
- }
1108
- yield { type: "message:end" };
1109
- yield { type: "done", usage };
1110
- }
1111
- }
1112
614
  async completeWithResponses(request) {
1113
615
  const client = await this.getClient();
1114
616
  const openaiToolOptions = request.providerToolOptions?.openai;
617
+ const responsesTextFormat = toOpenAIResponsesTextFormat(
618
+ request.config?.responseFormat
619
+ );
1115
620
  const payload = {
1116
621
  model: request.config?.model || this.model,
1117
622
  instructions: request.systemPrompt,
@@ -1121,6 +626,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
1121
626
  parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
1122
627
  temperature: request.config?.temperature ?? this.config.temperature,
1123
628
  max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
629
+ ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
1124
630
  stream: false
1125
631
  };
1126
632
  logProviderPayload("openai", "request payload", payload, request.debug);
@@ -1242,37 +748,21 @@ var OpenAIAdapter = class _OpenAIAdapter {
1242
748
  name: openaiToolOptions.toolChoice.name
1243
749
  }
1244
750
  } : openaiToolOptions?.toolChoice;
1245
- const isOpenRouter = this.provider === "openrouter";
1246
- const activeModel = request.config?.model || this.model;
1247
- const modelSlug = activeModel.replace("openai/", "");
1248
- const isOSeries = /^o[1-9]/.test(modelSlug);
1249
- const isOpenAIOnOpenRouter = isOpenRouter && activeModel.startsWith("openai/");
1250
- if (!this.config.disableThinking && this.isOpenAIReasoningModelOnOpenRouter(activeModel)) {
1251
- yield* this.streamWithResponsesAPI(request, activeModel, messageId);
1252
- return;
1253
- }
1254
- const maxTokensValue = request.config?.maxTokens ?? this.config.maxTokens;
751
+ const modelIdForPayload = request.config?.model || this.model;
1255
752
  const payload = {
1256
- model: activeModel,
753
+ model: modelIdForPayload,
1257
754
  messages,
1258
755
  tools: tools.length > 0 ? tools : void 0,
1259
756
  tool_choice: tools.length > 0 ? toolChoice : void 0,
1260
757
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
758
+ ...buildOpenAITokenParams(
759
+ modelIdForPayload,
760
+ request.config?.maxTokens ?? this.config.maxTokens,
761
+ request.config?.temperature ?? this.config.temperature
762
+ ),
763
+ response_format: toOpenAIResponseFormat(request.config?.responseFormat),
1261
764
  stream: true,
1262
- stream_options: { include_usage: true },
1263
- // o-series: use max_completion_tokens + reasoning_effort, no temperature
1264
- // regular models: use max_tokens + temperature
1265
- ...isOSeries ? {
1266
- max_completion_tokens: maxTokensValue,
1267
- reasoning_effort: request.config?.reasoningEffort ?? "medium"
1268
- } : {
1269
- temperature: request.config?.temperature ?? this.config.temperature,
1270
- max_tokens: maxTokensValue
1271
- },
1272
- // Non-OpenAI OpenRouter models support OR's reasoning/include_reasoning params.
1273
- // When disableThinking=true we must explicitly send include_reasoning:false because
1274
- // models like Qwen3 and DeepSeek-R1 reason by default even without the reasoning param.
1275
- ...isOpenRouter && !isOpenAIOnOpenRouter ? this.config.disableThinking ? { include_reasoning: false } : { reasoning: { max_tokens: 8e3 }, include_reasoning: true } : {}
765
+ stream_options: { include_usage: true }
1276
766
  };
1277
767
  logProviderPayload("openai", "request payload", payload, request.debug);
1278
768
  const stream = await client.chat.completions.create(payload);
@@ -1280,7 +770,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
1280
770
  const collectedCitations = [];
1281
771
  let citationIndex = 0;
1282
772
  let usage;
1283
- let adapterReasoningStarted = false;
1284
773
  for await (const chunk of stream) {
1285
774
  logProviderPayload("openai", "stream chunk", chunk, request.debug);
1286
775
  if (request.signal?.aborted) {
@@ -1291,22 +780,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
1291
780
  if (delta?.content) {
1292
781
  yield { type: "message:delta", content: delta.content };
1293
782
  }
1294
- if (isOpenRouter) {
1295
- const rc = delta?.reasoning_content ?? delta?.reasoning ?? null;
1296
- if (rc) {
1297
- const rcText = typeof rc === "string" ? rc : Array.isArray(rc) && rc[0]?.text ? rc[0].text : "";
1298
- if (rcText) {
1299
- if (!adapterReasoningStarted) {
1300
- yield { type: "thinking:start" };
1301
- adapterReasoningStarted = true;
1302
- }
1303
- yield { type: "thinking:delta", content: rcText };
1304
- }
1305
- } else if (adapterReasoningStarted && (delta?.content || choice?.finish_reason)) {
1306
- yield { type: "thinking:end" };
1307
- adapterReasoningStarted = false;
1308
- }
1309
- }
1310
783
  const annotations = delta?.annotations;
1311
784
  if (annotations && annotations.length > 0) {
1312
785
  for (const annotation of annotations) {
@@ -1354,11 +827,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
1354
827
  };
1355
828
  } else if (currentToolCall && toolCall.function?.arguments) {
1356
829
  currentToolCall.arguments += toolCall.function.arguments;
1357
- yield {
1358
- type: "action:args",
1359
- id: currentToolCall.id,
1360
- args: currentToolCall.arguments
1361
- };
1362
830
  }
1363
831
  }
1364
832
  }
@@ -1434,24 +902,20 @@ var OpenAIAdapter = class _OpenAIAdapter {
1434
902
  name: openaiToolOptions.toolChoice.name
1435
903
  }
1436
904
  } : openaiToolOptions?.toolChoice;
1437
- const activeModel2 = request.config?.model || this.model;
1438
- const modelSlug2 = activeModel2.replace("openai/", "");
1439
- const isOSeries2 = /^o[1-9]/.test(modelSlug2);
1440
- const maxTokensValue2 = request.config?.maxTokens ?? this.config.maxTokens;
905
+ const modelIdForCompletePayload = request.config?.model || this.model;
1441
906
  const payload = {
1442
- model: activeModel2,
907
+ model: modelIdForCompletePayload,
1443
908
  messages,
1444
909
  tools: tools.length > 0 ? tools : void 0,
1445
910
  tool_choice: tools.length > 0 ? toolChoice : void 0,
1446
911
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
1447
- stream: false,
1448
- ...isOSeries2 ? {
1449
- max_completion_tokens: maxTokensValue2,
1450
- reasoning_effort: request.config?.reasoningEffort ?? "medium"
1451
- } : {
1452
- temperature: request.config?.temperature ?? this.config.temperature,
1453
- max_tokens: maxTokensValue2
1454
- }
912
+ ...buildOpenAITokenParams(
913
+ modelIdForCompletePayload,
914
+ request.config?.maxTokens ?? this.config.maxTokens,
915
+ request.config?.temperature ?? this.config.temperature
916
+ ),
917
+ response_format: toOpenAIResponseFormat(request.config?.responseFormat),
918
+ stream: false
1455
919
  };
1456
920
  logProviderPayload("openai", "request payload", payload, request.debug);
1457
921
  const response = await client.chat.completions.create(payload);
@@ -1534,8 +998,7 @@ function createOpenRouter(config = {}) {
1534
998
  return createOpenAIAdapter({
1535
999
  apiKey,
1536
1000
  model: modelId,
1537
- baseUrl,
1538
- disableThinking: config.disableThinking
1001
+ baseUrl
1539
1002
  });
1540
1003
  };
1541
1004
  const getCapabilities = (modelId) => {