@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/google/provider.ts
4
233
  var GOOGLE_MODELS = {
5
234
  // Gemini 2.5 (Experimental)
@@ -119,7 +348,8 @@ function google(modelId, options = {}) {
119
348
  messages,
120
349
  tools: params.tools,
121
350
  temperature: params.temperature,
122
- max_tokens: params.maxTokens
351
+ max_tokens: params.maxTokens,
352
+ response_format: toOpenAIResponseFormat(params.responseFormat)
123
353
  });
124
354
  const choice = response.choices[0];
125
355
  const message = choice.message;
@@ -151,6 +381,7 @@ function google(modelId, options = {}) {
151
381
  tools: params.tools,
152
382
  temperature: params.temperature,
153
383
  max_tokens: params.maxTokens,
384
+ response_format: toOpenAIResponseFormat(params.responseFormat),
154
385
  stream: true
155
386
  });
156
387
  let currentToolCall = null;
@@ -296,204 +527,6 @@ function generateToolCallId() {
296
527
  return generateId("call");
297
528
  }
298
529
 
299
- // src/adapters/base.ts
300
- function stringifyForDebug(value) {
301
- return JSON.stringify(
302
- value,
303
- (_key, currentValue) => {
304
- if (typeof currentValue === "bigint") {
305
- return currentValue.toString();
306
- }
307
- if (currentValue instanceof Error) {
308
- return {
309
- name: currentValue.name,
310
- message: currentValue.message,
311
- stack: currentValue.stack
312
- };
313
- }
314
- return currentValue;
315
- },
316
- 2
317
- );
318
- }
319
- function logProviderPayload(provider, label, payload, enabled) {
320
- if (!enabled) {
321
- return;
322
- }
323
- if (label.toLowerCase().includes("stream ")) {
324
- return;
325
- }
326
- try {
327
- console.log(
328
- `[llm-sdk:${provider}] ${label}
329
- ${stringifyForDebug(payload)}`
330
- );
331
- } catch (error) {
332
- console.log(
333
- `[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
334
- error
335
- );
336
- }
337
- }
338
- function parameterToJsonSchema(param) {
339
- const schema = {
340
- type: param.type
341
- };
342
- if (param.description) {
343
- schema.description = param.description;
344
- }
345
- if (param.enum) {
346
- schema.enum = param.enum;
347
- }
348
- if (param.type === "array" && param.items) {
349
- schema.items = parameterToJsonSchema(
350
- param.items
351
- );
352
- }
353
- if (param.type === "object" && param.properties) {
354
- schema.properties = Object.fromEntries(
355
- Object.entries(param.properties).map(([key, prop]) => [
356
- key,
357
- parameterToJsonSchema(
358
- prop
359
- )
360
- ])
361
- );
362
- schema.additionalProperties = false;
363
- }
364
- return schema;
365
- }
366
- function normalizeObjectJsonSchema(schema) {
367
- if (!schema || typeof schema !== "object") {
368
- return {
369
- type: "object",
370
- properties: {},
371
- required: [],
372
- additionalProperties: false
373
- };
374
- }
375
- const normalized = { ...schema };
376
- const type = normalized.type;
377
- if (type === "object") {
378
- const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
379
- normalized.properties = Object.fromEntries(
380
- Object.entries(properties).map(([key, value]) => [
381
- key,
382
- normalizeObjectJsonSchema(value)
383
- ])
384
- );
385
- const propertyKeys = Object.keys(properties);
386
- const required = Array.isArray(normalized.required) ? normalized.required.filter(
387
- (value) => typeof value === "string"
388
- ) : [];
389
- normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
390
- if (normalized.additionalProperties === void 0) {
391
- normalized.additionalProperties = false;
392
- }
393
- } else if (type === "array" && normalized.items && typeof normalized.items === "object") {
394
- normalized.items = normalizeObjectJsonSchema(
395
- normalized.items
396
- );
397
- }
398
- return normalized;
399
- }
400
- function formatTools(actions) {
401
- return actions.map((action) => ({
402
- type: "function",
403
- function: {
404
- name: action.name,
405
- description: action.description,
406
- parameters: {
407
- type: "object",
408
- properties: action.parameters ? Object.fromEntries(
409
- Object.entries(action.parameters).map(([key, param]) => [
410
- key,
411
- parameterToJsonSchema(param)
412
- ])
413
- ) : {},
414
- required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
415
- additionalProperties: false
416
- }
417
- }
418
- }));
419
- }
420
- function hasImageAttachments(message) {
421
- const attachments = message.metadata?.attachments;
422
- return attachments?.some((a) => a.type === "image") ?? false;
423
- }
424
- function attachmentToOpenAIImage(attachment) {
425
- if (attachment.type !== "image") return null;
426
- let imageUrl;
427
- if (attachment.url) {
428
- imageUrl = attachment.url;
429
- } else if (attachment.data) {
430
- imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
431
- } else {
432
- return null;
433
- }
434
- return {
435
- type: "image_url",
436
- image_url: {
437
- url: imageUrl,
438
- detail: "auto"
439
- }
440
- };
441
- }
442
- function messageToOpenAIContent(message) {
443
- const attachments = message.metadata?.attachments;
444
- const content = message.content ?? "";
445
- if (!hasImageAttachments(message)) {
446
- return content;
447
- }
448
- const blocks = [];
449
- if (content) {
450
- blocks.push({ type: "text", text: content });
451
- }
452
- if (attachments) {
453
- for (const attachment of attachments) {
454
- const imageBlock = attachmentToOpenAIImage(attachment);
455
- if (imageBlock) {
456
- blocks.push(imageBlock);
457
- }
458
- }
459
- }
460
- return blocks;
461
- }
462
- function formatMessagesForOpenAI(messages, systemPrompt) {
463
- const formatted = [];
464
- if (systemPrompt) {
465
- formatted.push({ role: "system", content: systemPrompt });
466
- }
467
- for (const msg of messages) {
468
- if (msg.role === "system") {
469
- formatted.push({ role: "system", content: msg.content ?? "" });
470
- } else if (msg.role === "user") {
471
- formatted.push({
472
- role: "user",
473
- content: messageToOpenAIContent(msg)
474
- });
475
- } else if (msg.role === "assistant") {
476
- const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
477
- const assistantMsg = {
478
- role: "assistant",
479
- // Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
480
- content: hasToolCalls ? msg.content || null : msg.content
481
- };
482
- if (hasToolCalls) {
483
- assistantMsg.tool_calls = msg.tool_calls;
484
- }
485
- formatted.push(assistantMsg);
486
- } else if (msg.role === "tool" && msg.tool_call_id) {
487
- formatted.push({
488
- role: "tool",
489
- content: msg.content ?? "",
490
- tool_call_id: msg.tool_call_id
491
- });
492
- }
493
- }
494
- return formatted;
495
- }
496
-
497
530
  // src/adapters/openai.ts
498
531
  var OpenAIAdapter = class _OpenAIAdapter {
499
532
  constructor(config) {
@@ -506,7 +539,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
506
539
  if (baseUrl.includes("generativelanguage.googleapis.com")) return "google";
507
540
  if (baseUrl.includes("x.ai")) return "xai";
508
541
  if (baseUrl.includes("azure")) return "azure";
509
- if (baseUrl.includes("openrouter.ai")) return "openrouter";
510
542
  return "openai";
511
543
  }
512
544
  async getClient() {
@@ -606,259 +638,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
606
638
  rawResponse: response
607
639
  };
608
640
  }
609
- /**
610
- * OpenAI reasoning models on OpenRouter (o1/o3/o4/gpt-5 family) hide their
611
- * reasoning content on the chat-completions endpoint. To surface reasoning
612
- * SUMMARIES (not raw CoT, which OpenAI never exposes) we have to use the
613
- * Responses API, which streams `response.reasoning_summary_text.delta` events.
614
- *
615
- * Match by prefix on the OpenRouter model id. Excludes openai/gpt-4o,
616
- * openai/gpt-4.1, openai/chatgpt-* — those continue on chat-completions.
617
- */
618
- isOpenAIReasoningModelOnOpenRouter(activeModel) {
619
- if (this.provider !== "openrouter") return false;
620
- return activeModel.startsWith("openai/o1") || activeModel.startsWith("openai/o3") || activeModel.startsWith("openai/o4") || activeModel.startsWith("openai/gpt-5");
621
- }
622
- /**
623
- * Convert ActionDefinition[] (the chat-completions tool shape used by the
624
- * adapter) to the Responses API tool shape.
625
- */
626
- buildResponsesToolsFromActions(actions) {
627
- if (!actions || actions.length === 0) return void 0;
628
- const formatted = formatTools(actions);
629
- return formatted.map((t) => ({
630
- type: "function",
631
- name: t.function.name,
632
- description: t.function.description,
633
- parameters: t.function.parameters
634
- }));
635
- }
636
- /**
637
- * Streaming Responses API path for OpenAI reasoning models on OpenRouter.
638
- *
639
- * Maps Responses API SSE events back to the same StreamEvent shapes the
640
- * chat-completions path emits, so downstream consumers (processChunk.ts,
641
- * frontend tool handlers, plan approval, specialist delegations) see
642
- * identical events regardless of which path produced them.
643
- *
644
- * response.reasoning_summary_text.delta → thinking:start (once) + thinking:delta
645
- * response.output_text.delta → message:delta
646
- * response.output_item.added (function_call) → action:start (queued buffer)
647
- * response.function_call_arguments.delta → action:args (progressive)
648
- * response.output_item.done (function_call) → final action:args + action:end
649
- * response.completed → message:end + done(usage)
650
- * response.error → error
651
- */
652
- async *streamWithResponsesAPI(request, activeModel, messageId) {
653
- const client = await this.getClient();
654
- const maxTokensValue = request.config?.maxTokens ?? this.config.maxTokens;
655
- const payload = {
656
- model: activeModel,
657
- input: this.buildResponsesInput(request),
658
- stream: true,
659
- reasoning: {
660
- effort: request.config?.reasoningEffort ?? "medium",
661
- summary: "auto"
662
- }
663
- };
664
- if (request.systemPrompt) payload.instructions = request.systemPrompt;
665
- if (typeof maxTokensValue === "number")
666
- payload.max_output_tokens = maxTokensValue;
667
- const tools = this.buildResponsesToolsFromActions(request.actions);
668
- if (tools && tools.length > 0) payload.tools = tools;
669
- logProviderPayload(
670
- "openai",
671
- "responses-api request payload",
672
- payload,
673
- request.debug
674
- );
675
- let stream;
676
- try {
677
- stream = await client.responses.create(payload);
678
- } catch (error) {
679
- yield {
680
- type: "error",
681
- message: error instanceof Error ? error.message : "Unknown error",
682
- code: "OPENAI_RESPONSES_ERROR"
683
- };
684
- return;
685
- }
686
- const toolBuffers = /* @__PURE__ */ new Map();
687
- const itemIdToCallId = /* @__PURE__ */ new Map();
688
- let usage;
689
- let reasoningStarted = false;
690
- let textStarted = false;
691
- let finishEmitted = false;
692
- const resolveCallId = (evt) => {
693
- if (evt?.call_id) return evt.call_id;
694
- if (evt?.item_id) return itemIdToCallId.get(evt.item_id) ?? evt.item_id;
695
- if (evt?.item?.call_id) return evt.item.call_id;
696
- if (evt?.item?.id) return evt.item.id;
697
- return "";
698
- };
699
- try {
700
- for await (const evt of stream) {
701
- logProviderPayload(
702
- "openai",
703
- "responses-api stream chunk",
704
- evt,
705
- request.debug
706
- );
707
- if (request.signal?.aborted) break;
708
- const t = evt?.type ?? "";
709
- if (t === "response.reasoning_summary_text.delta") {
710
- const delta = evt.delta ?? "";
711
- if (!delta) continue;
712
- if (!reasoningStarted) {
713
- yield { type: "thinking:start" };
714
- reasoningStarted = true;
715
- }
716
- yield { type: "thinking:delta", content: delta };
717
- continue;
718
- }
719
- if (t === "response.reasoning_summary_text.done" || t === "response.reasoning.done") {
720
- continue;
721
- }
722
- if (t === "response.output_text.delta") {
723
- const text = evt.delta ?? "";
724
- if (!text) continue;
725
- if (reasoningStarted && !textStarted) {
726
- yield { type: "thinking:end" };
727
- textStarted = true;
728
- }
729
- yield { type: "message:delta", content: text };
730
- continue;
731
- }
732
- if (t === "response.output_item.added") {
733
- const item = evt.item;
734
- if (item?.type === "function_call") {
735
- const callId = item.call_id ?? item.id ?? "";
736
- const itemId = item.id ?? callId;
737
- if (callId) {
738
- if (itemId && itemId !== callId) {
739
- itemIdToCallId.set(itemId, callId);
740
- }
741
- if (!toolBuffers.has(callId)) {
742
- toolBuffers.set(callId, {
743
- id: callId,
744
- name: item.name ?? "",
745
- arguments: item.arguments ?? "",
746
- emittedStart: false
747
- });
748
- }
749
- const buf = toolBuffers.get(callId);
750
- if (buf.name && !buf.emittedStart) {
751
- yield { type: "action:start", id: buf.id, name: buf.name };
752
- buf.emittedStart = true;
753
- }
754
- }
755
- }
756
- continue;
757
- }
758
- if (t === "response.function_call_arguments.delta") {
759
- const callId = resolveCallId(evt);
760
- const delta = evt.delta ?? "";
761
- if (!callId || !delta) continue;
762
- let buf = toolBuffers.get(callId);
763
- if (!buf) {
764
- buf = { id: callId, name: "", arguments: "", emittedStart: false };
765
- toolBuffers.set(callId, buf);
766
- }
767
- buf.arguments += delta;
768
- if (buf.emittedStart) {
769
- yield {
770
- type: "action:args",
771
- id: buf.id,
772
- args: buf.arguments
773
- };
774
- }
775
- continue;
776
- }
777
- if (t === "response.output_item.done") {
778
- const item = evt.item;
779
- if (item?.type === "function_call") {
780
- const callId = item.call_id ?? item.id ?? "";
781
- const buf = toolBuffers.get(callId);
782
- const name = buf?.name || item.name || "";
783
- const argsStr = buf?.arguments || item.arguments || "{}";
784
- if (callId && name) {
785
- if (!buf?.emittedStart) {
786
- yield { type: "action:start", id: callId, name };
787
- }
788
- yield {
789
- type: "action:args",
790
- id: callId,
791
- args: argsStr
792
- };
793
- yield {
794
- type: "action:end",
795
- id: callId,
796
- name
797
- };
798
- }
799
- toolBuffers.delete(callId);
800
- }
801
- continue;
802
- }
803
- if (t === "response.completed") {
804
- const u = evt.response?.usage;
805
- if (u) {
806
- usage = {
807
- prompt_tokens: u.input_tokens ?? 0,
808
- completion_tokens: u.output_tokens ?? 0,
809
- total_tokens: u.total_tokens ?? (u.input_tokens ?? 0) + (u.output_tokens ?? 0)
810
- };
811
- }
812
- for (const buf of toolBuffers.values()) {
813
- if (!buf.id || !buf.name) continue;
814
- if (!buf.emittedStart) {
815
- yield { type: "action:start", id: buf.id, name: buf.name };
816
- }
817
- yield {
818
- type: "action:args",
819
- id: buf.id,
820
- args: buf.arguments || "{}"
821
- };
822
- yield { type: "action:end", id: buf.id, name: buf.name };
823
- }
824
- toolBuffers.clear();
825
- if (reasoningStarted && !textStarted) {
826
- yield { type: "thinking:end" };
827
- }
828
- yield { type: "message:end" };
829
- yield { type: "done", usage };
830
- finishEmitted = true;
831
- continue;
832
- }
833
- if (t === "response.error" || t === "error") {
834
- const msg = evt.error?.message || evt.message || "Responses API error";
835
- yield {
836
- type: "error",
837
- message: msg,
838
- code: "OPENAI_RESPONSES_ERROR"
839
- };
840
- return;
841
- }
842
- }
843
- } catch (error) {
844
- yield {
845
- type: "error",
846
- message: error instanceof Error ? error.message : "Unknown error",
847
- code: "OPENAI_RESPONSES_ERROR"
848
- };
849
- return;
850
- }
851
- if (!finishEmitted) {
852
- if (reasoningStarted && !textStarted) {
853
- yield { type: "thinking:end" };
854
- }
855
- yield { type: "message:end" };
856
- yield { type: "done", usage };
857
- }
858
- }
859
641
  async completeWithResponses(request) {
860
642
  const client = await this.getClient();
861
643
  const openaiToolOptions = request.providerToolOptions?.openai;
644
+ const responsesTextFormat = toOpenAIResponsesTextFormat(
645
+ request.config?.responseFormat
646
+ );
862
647
  const payload = {
863
648
  model: request.config?.model || this.model,
864
649
  instructions: request.systemPrompt,
@@ -868,6 +653,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
868
653
  parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
869
654
  temperature: request.config?.temperature ?? this.config.temperature,
870
655
  max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
656
+ ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
871
657
  stream: false
872
658
  };
873
659
  logProviderPayload("openai", "request payload", payload, request.debug);
@@ -989,37 +775,21 @@ var OpenAIAdapter = class _OpenAIAdapter {
989
775
  name: openaiToolOptions.toolChoice.name
990
776
  }
991
777
  } : openaiToolOptions?.toolChoice;
992
- const isOpenRouter = this.provider === "openrouter";
993
- const activeModel = request.config?.model || this.model;
994
- const modelSlug = activeModel.replace("openai/", "");
995
- const isOSeries = /^o[1-9]/.test(modelSlug);
996
- const isOpenAIOnOpenRouter = isOpenRouter && activeModel.startsWith("openai/");
997
- if (!this.config.disableThinking && this.isOpenAIReasoningModelOnOpenRouter(activeModel)) {
998
- yield* this.streamWithResponsesAPI(request, activeModel, messageId);
999
- return;
1000
- }
1001
- const maxTokensValue = request.config?.maxTokens ?? this.config.maxTokens;
778
+ const modelIdForPayload = request.config?.model || this.model;
1002
779
  const payload = {
1003
- model: activeModel,
780
+ model: modelIdForPayload,
1004
781
  messages,
1005
782
  tools: tools.length > 0 ? tools : void 0,
1006
783
  tool_choice: tools.length > 0 ? toolChoice : void 0,
1007
784
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
785
+ ...buildOpenAITokenParams(
786
+ modelIdForPayload,
787
+ request.config?.maxTokens ?? this.config.maxTokens,
788
+ request.config?.temperature ?? this.config.temperature
789
+ ),
790
+ response_format: toOpenAIResponseFormat(request.config?.responseFormat),
1008
791
  stream: true,
1009
- stream_options: { include_usage: true },
1010
- // o-series: use max_completion_tokens + reasoning_effort, no temperature
1011
- // regular models: use max_tokens + temperature
1012
- ...isOSeries ? {
1013
- max_completion_tokens: maxTokensValue,
1014
- reasoning_effort: request.config?.reasoningEffort ?? "medium"
1015
- } : {
1016
- temperature: request.config?.temperature ?? this.config.temperature,
1017
- max_tokens: maxTokensValue
1018
- },
1019
- // Non-OpenAI OpenRouter models support OR's reasoning/include_reasoning params.
1020
- // When disableThinking=true we must explicitly send include_reasoning:false because
1021
- // models like Qwen3 and DeepSeek-R1 reason by default even without the reasoning param.
1022
- ...isOpenRouter && !isOpenAIOnOpenRouter ? this.config.disableThinking ? { include_reasoning: false } : { reasoning: { max_tokens: 8e3 }, include_reasoning: true } : {}
792
+ stream_options: { include_usage: true }
1023
793
  };
1024
794
  logProviderPayload("openai", "request payload", payload, request.debug);
1025
795
  const stream = await client.chat.completions.create(payload);
@@ -1027,7 +797,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
1027
797
  const collectedCitations = [];
1028
798
  let citationIndex = 0;
1029
799
  let usage;
1030
- let adapterReasoningStarted = false;
1031
800
  for await (const chunk of stream) {
1032
801
  logProviderPayload("openai", "stream chunk", chunk, request.debug);
1033
802
  if (request.signal?.aborted) {
@@ -1038,22 +807,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
1038
807
  if (delta?.content) {
1039
808
  yield { type: "message:delta", content: delta.content };
1040
809
  }
1041
- if (isOpenRouter) {
1042
- const rc = delta?.reasoning_content ?? delta?.reasoning ?? null;
1043
- if (rc) {
1044
- const rcText = typeof rc === "string" ? rc : Array.isArray(rc) && rc[0]?.text ? rc[0].text : "";
1045
- if (rcText) {
1046
- if (!adapterReasoningStarted) {
1047
- yield { type: "thinking:start" };
1048
- adapterReasoningStarted = true;
1049
- }
1050
- yield { type: "thinking:delta", content: rcText };
1051
- }
1052
- } else if (adapterReasoningStarted && (delta?.content || choice?.finish_reason)) {
1053
- yield { type: "thinking:end" };
1054
- adapterReasoningStarted = false;
1055
- }
1056
- }
1057
810
  const annotations = delta?.annotations;
1058
811
  if (annotations && annotations.length > 0) {
1059
812
  for (const annotation of annotations) {
@@ -1101,11 +854,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
1101
854
  };
1102
855
  } else if (currentToolCall && toolCall.function?.arguments) {
1103
856
  currentToolCall.arguments += toolCall.function.arguments;
1104
- yield {
1105
- type: "action:args",
1106
- id: currentToolCall.id,
1107
- args: currentToolCall.arguments
1108
- };
1109
857
  }
1110
858
  }
1111
859
  }
@@ -1181,24 +929,20 @@ var OpenAIAdapter = class _OpenAIAdapter {
1181
929
  name: openaiToolOptions.toolChoice.name
1182
930
  }
1183
931
  } : openaiToolOptions?.toolChoice;
1184
- const activeModel2 = request.config?.model || this.model;
1185
- const modelSlug2 = activeModel2.replace("openai/", "");
1186
- const isOSeries2 = /^o[1-9]/.test(modelSlug2);
1187
- const maxTokensValue2 = request.config?.maxTokens ?? this.config.maxTokens;
932
+ const modelIdForCompletePayload = request.config?.model || this.model;
1188
933
  const payload = {
1189
- model: activeModel2,
934
+ model: modelIdForCompletePayload,
1190
935
  messages,
1191
936
  tools: tools.length > 0 ? tools : void 0,
1192
937
  tool_choice: tools.length > 0 ? toolChoice : void 0,
1193
938
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
1194
- stream: false,
1195
- ...isOSeries2 ? {
1196
- max_completion_tokens: maxTokensValue2,
1197
- reasoning_effort: request.config?.reasoningEffort ?? "medium"
1198
- } : {
1199
- temperature: request.config?.temperature ?? this.config.temperature,
1200
- max_tokens: maxTokensValue2
1201
- }
939
+ ...buildOpenAITokenParams(
940
+ modelIdForCompletePayload,
941
+ request.config?.maxTokens ?? this.config.maxTokens,
942
+ request.config?.temperature ?? this.config.temperature
943
+ ),
944
+ response_format: toOpenAIResponseFormat(request.config?.responseFormat),
945
+ stream: false
1202
946
  };
1203
947
  logProviderPayload("openai", "request payload", payload, request.debug);
1204
948
  const response = await client.chat.completions.create(payload);