@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/xai/provider.ts
4
233
  var XAI_MODELS = {
5
234
  // Grok 4.1 Fast (Latest - December 2025)
@@ -53,8 +282,8 @@ function xai(modelId, options = {}) {
53
282
  supportsVision: modelConfig.vision,
54
283
  supportsTools: modelConfig.tools,
55
284
  supportsStreaming: true,
56
- supportsJsonMode: false,
57
- // xAI doesn't support JSON mode yet
285
+ supportsJsonMode: true,
286
+ // OpenAI-compatible `response_format`
58
287
  supportsThinking: false,
59
288
  supportsPDF: false,
60
289
  maxTokens: modelConfig.maxTokens,
@@ -68,7 +297,8 @@ function xai(modelId, options = {}) {
68
297
  messages,
69
298
  tools: params.tools,
70
299
  temperature: params.temperature,
71
- max_tokens: params.maxTokens
300
+ max_tokens: params.maxTokens,
301
+ response_format: toOpenAIResponseFormat(params.responseFormat)
72
302
  });
73
303
  const choice = response.choices[0];
74
304
  const message = choice.message;
@@ -100,6 +330,7 @@ function xai(modelId, options = {}) {
100
330
  tools: params.tools,
101
331
  temperature: params.temperature,
102
332
  max_tokens: params.maxTokens,
333
+ response_format: toOpenAIResponseFormat(params.responseFormat),
103
334
  stream: true
104
335
  });
105
336
  let currentToolCall = null;
@@ -245,204 +476,6 @@ function generateToolCallId() {
245
476
  return generateId("call");
246
477
  }
247
478
 
248
- // src/adapters/base.ts
249
- function stringifyForDebug(value) {
250
- return JSON.stringify(
251
- value,
252
- (_key, currentValue) => {
253
- if (typeof currentValue === "bigint") {
254
- return currentValue.toString();
255
- }
256
- if (currentValue instanceof Error) {
257
- return {
258
- name: currentValue.name,
259
- message: currentValue.message,
260
- stack: currentValue.stack
261
- };
262
- }
263
- return currentValue;
264
- },
265
- 2
266
- );
267
- }
268
- function logProviderPayload(provider, label, payload, enabled) {
269
- if (!enabled) {
270
- return;
271
- }
272
- if (label.toLowerCase().includes("stream ")) {
273
- return;
274
- }
275
- try {
276
- console.log(
277
- `[llm-sdk:${provider}] ${label}
278
- ${stringifyForDebug(payload)}`
279
- );
280
- } catch (error) {
281
- console.log(
282
- `[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
283
- error
284
- );
285
- }
286
- }
287
- function parameterToJsonSchema(param) {
288
- const schema = {
289
- type: param.type
290
- };
291
- if (param.description) {
292
- schema.description = param.description;
293
- }
294
- if (param.enum) {
295
- schema.enum = param.enum;
296
- }
297
- if (param.type === "array" && param.items) {
298
- schema.items = parameterToJsonSchema(
299
- param.items
300
- );
301
- }
302
- if (param.type === "object" && param.properties) {
303
- schema.properties = Object.fromEntries(
304
- Object.entries(param.properties).map(([key, prop]) => [
305
- key,
306
- parameterToJsonSchema(
307
- prop
308
- )
309
- ])
310
- );
311
- schema.additionalProperties = false;
312
- }
313
- return schema;
314
- }
315
- function normalizeObjectJsonSchema(schema) {
316
- if (!schema || typeof schema !== "object") {
317
- return {
318
- type: "object",
319
- properties: {},
320
- required: [],
321
- additionalProperties: false
322
- };
323
- }
324
- const normalized = { ...schema };
325
- const type = normalized.type;
326
- if (type === "object") {
327
- const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
328
- normalized.properties = Object.fromEntries(
329
- Object.entries(properties).map(([key, value]) => [
330
- key,
331
- normalizeObjectJsonSchema(value)
332
- ])
333
- );
334
- const propertyKeys = Object.keys(properties);
335
- const required = Array.isArray(normalized.required) ? normalized.required.filter(
336
- (value) => typeof value === "string"
337
- ) : [];
338
- normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
339
- if (normalized.additionalProperties === void 0) {
340
- normalized.additionalProperties = false;
341
- }
342
- } else if (type === "array" && normalized.items && typeof normalized.items === "object") {
343
- normalized.items = normalizeObjectJsonSchema(
344
- normalized.items
345
- );
346
- }
347
- return normalized;
348
- }
349
- function formatTools(actions) {
350
- return actions.map((action) => ({
351
- type: "function",
352
- function: {
353
- name: action.name,
354
- description: action.description,
355
- parameters: {
356
- type: "object",
357
- properties: action.parameters ? Object.fromEntries(
358
- Object.entries(action.parameters).map(([key, param]) => [
359
- key,
360
- parameterToJsonSchema(param)
361
- ])
362
- ) : {},
363
- required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
364
- additionalProperties: false
365
- }
366
- }
367
- }));
368
- }
369
- function hasImageAttachments(message) {
370
- const attachments = message.metadata?.attachments;
371
- return attachments?.some((a) => a.type === "image") ?? false;
372
- }
373
- function attachmentToOpenAIImage(attachment) {
374
- if (attachment.type !== "image") return null;
375
- let imageUrl;
376
- if (attachment.url) {
377
- imageUrl = attachment.url;
378
- } else if (attachment.data) {
379
- imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
380
- } else {
381
- return null;
382
- }
383
- return {
384
- type: "image_url",
385
- image_url: {
386
- url: imageUrl,
387
- detail: "auto"
388
- }
389
- };
390
- }
391
- function messageToOpenAIContent(message) {
392
- const attachments = message.metadata?.attachments;
393
- const content = message.content ?? "";
394
- if (!hasImageAttachments(message)) {
395
- return content;
396
- }
397
- const blocks = [];
398
- if (content) {
399
- blocks.push({ type: "text", text: content });
400
- }
401
- if (attachments) {
402
- for (const attachment of attachments) {
403
- const imageBlock = attachmentToOpenAIImage(attachment);
404
- if (imageBlock) {
405
- blocks.push(imageBlock);
406
- }
407
- }
408
- }
409
- return blocks;
410
- }
411
- function formatMessagesForOpenAI(messages, systemPrompt) {
412
- const formatted = [];
413
- if (systemPrompt) {
414
- formatted.push({ role: "system", content: systemPrompt });
415
- }
416
- for (const msg of messages) {
417
- if (msg.role === "system") {
418
- formatted.push({ role: "system", content: msg.content ?? "" });
419
- } else if (msg.role === "user") {
420
- formatted.push({
421
- role: "user",
422
- content: messageToOpenAIContent(msg)
423
- });
424
- } else if (msg.role === "assistant") {
425
- const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
426
- const assistantMsg = {
427
- role: "assistant",
428
- // Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
429
- content: hasToolCalls ? msg.content || null : msg.content
430
- };
431
- if (hasToolCalls) {
432
- assistantMsg.tool_calls = msg.tool_calls;
433
- }
434
- formatted.push(assistantMsg);
435
- } else if (msg.role === "tool" && msg.tool_call_id) {
436
- formatted.push({
437
- role: "tool",
438
- content: msg.content ?? "",
439
- tool_call_id: msg.tool_call_id
440
- });
441
- }
442
- }
443
- return formatted;
444
- }
445
-
446
479
  // src/adapters/openai.ts
447
480
  var OpenAIAdapter = class _OpenAIAdapter {
448
481
  constructor(config) {
@@ -455,7 +488,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
455
488
  if (baseUrl.includes("generativelanguage.googleapis.com")) return "google";
456
489
  if (baseUrl.includes("x.ai")) return "xai";
457
490
  if (baseUrl.includes("azure")) return "azure";
458
- if (baseUrl.includes("openrouter.ai")) return "openrouter";
459
491
  return "openai";
460
492
  }
461
493
  async getClient() {
@@ -555,259 +587,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
555
587
  rawResponse: response
556
588
  };
557
589
  }
558
- /**
559
- * OpenAI reasoning models on OpenRouter (o1/o3/o4/gpt-5 family) hide their
560
- * reasoning content on the chat-completions endpoint. To surface reasoning
561
- * SUMMARIES (not raw CoT, which OpenAI never exposes) we have to use the
562
- * Responses API, which streams `response.reasoning_summary_text.delta` events.
563
- *
564
- * Match by prefix on the OpenRouter model id. Excludes openai/gpt-4o,
565
- * openai/gpt-4.1, openai/chatgpt-* — those continue on chat-completions.
566
- */
567
- isOpenAIReasoningModelOnOpenRouter(activeModel) {
568
- if (this.provider !== "openrouter") return false;
569
- return activeModel.startsWith("openai/o1") || activeModel.startsWith("openai/o3") || activeModel.startsWith("openai/o4") || activeModel.startsWith("openai/gpt-5");
570
- }
571
- /**
572
- * Convert ActionDefinition[] (the chat-completions tool shape used by the
573
- * adapter) to the Responses API tool shape.
574
- */
575
- buildResponsesToolsFromActions(actions) {
576
- if (!actions || actions.length === 0) return void 0;
577
- const formatted = formatTools(actions);
578
- return formatted.map((t) => ({
579
- type: "function",
580
- name: t.function.name,
581
- description: t.function.description,
582
- parameters: t.function.parameters
583
- }));
584
- }
585
- /**
586
- * Streaming Responses API path for OpenAI reasoning models on OpenRouter.
587
- *
588
- * Maps Responses API SSE events back to the same StreamEvent shapes the
589
- * chat-completions path emits, so downstream consumers (processChunk.ts,
590
- * frontend tool handlers, plan approval, specialist delegations) see
591
- * identical events regardless of which path produced them.
592
- *
593
- * response.reasoning_summary_text.delta → thinking:start (once) + thinking:delta
594
- * response.output_text.delta → message:delta
595
- * response.output_item.added (function_call) → action:start (queued buffer)
596
- * response.function_call_arguments.delta → action:args (progressive)
597
- * response.output_item.done (function_call) → final action:args + action:end
598
- * response.completed → message:end + done(usage)
599
- * response.error → error
600
- */
601
- async *streamWithResponsesAPI(request, activeModel, messageId) {
602
- const client = await this.getClient();
603
- const maxTokensValue = request.config?.maxTokens ?? this.config.maxTokens;
604
- const payload = {
605
- model: activeModel,
606
- input: this.buildResponsesInput(request),
607
- stream: true,
608
- reasoning: {
609
- effort: request.config?.reasoningEffort ?? "medium",
610
- summary: "auto"
611
- }
612
- };
613
- if (request.systemPrompt) payload.instructions = request.systemPrompt;
614
- if (typeof maxTokensValue === "number")
615
- payload.max_output_tokens = maxTokensValue;
616
- const tools = this.buildResponsesToolsFromActions(request.actions);
617
- if (tools && tools.length > 0) payload.tools = tools;
618
- logProviderPayload(
619
- "openai",
620
- "responses-api request payload",
621
- payload,
622
- request.debug
623
- );
624
- let stream;
625
- try {
626
- stream = await client.responses.create(payload);
627
- } catch (error) {
628
- yield {
629
- type: "error",
630
- message: error instanceof Error ? error.message : "Unknown error",
631
- code: "OPENAI_RESPONSES_ERROR"
632
- };
633
- return;
634
- }
635
- const toolBuffers = /* @__PURE__ */ new Map();
636
- const itemIdToCallId = /* @__PURE__ */ new Map();
637
- let usage;
638
- let reasoningStarted = false;
639
- let textStarted = false;
640
- let finishEmitted = false;
641
- const resolveCallId = (evt) => {
642
- if (evt?.call_id) return evt.call_id;
643
- if (evt?.item_id) return itemIdToCallId.get(evt.item_id) ?? evt.item_id;
644
- if (evt?.item?.call_id) return evt.item.call_id;
645
- if (evt?.item?.id) return evt.item.id;
646
- return "";
647
- };
648
- try {
649
- for await (const evt of stream) {
650
- logProviderPayload(
651
- "openai",
652
- "responses-api stream chunk",
653
- evt,
654
- request.debug
655
- );
656
- if (request.signal?.aborted) break;
657
- const t = evt?.type ?? "";
658
- if (t === "response.reasoning_summary_text.delta") {
659
- const delta = evt.delta ?? "";
660
- if (!delta) continue;
661
- if (!reasoningStarted) {
662
- yield { type: "thinking:start" };
663
- reasoningStarted = true;
664
- }
665
- yield { type: "thinking:delta", content: delta };
666
- continue;
667
- }
668
- if (t === "response.reasoning_summary_text.done" || t === "response.reasoning.done") {
669
- continue;
670
- }
671
- if (t === "response.output_text.delta") {
672
- const text = evt.delta ?? "";
673
- if (!text) continue;
674
- if (reasoningStarted && !textStarted) {
675
- yield { type: "thinking:end" };
676
- textStarted = true;
677
- }
678
- yield { type: "message:delta", content: text };
679
- continue;
680
- }
681
- if (t === "response.output_item.added") {
682
- const item = evt.item;
683
- if (item?.type === "function_call") {
684
- const callId = item.call_id ?? item.id ?? "";
685
- const itemId = item.id ?? callId;
686
- if (callId) {
687
- if (itemId && itemId !== callId) {
688
- itemIdToCallId.set(itemId, callId);
689
- }
690
- if (!toolBuffers.has(callId)) {
691
- toolBuffers.set(callId, {
692
- id: callId,
693
- name: item.name ?? "",
694
- arguments: item.arguments ?? "",
695
- emittedStart: false
696
- });
697
- }
698
- const buf = toolBuffers.get(callId);
699
- if (buf.name && !buf.emittedStart) {
700
- yield { type: "action:start", id: buf.id, name: buf.name };
701
- buf.emittedStart = true;
702
- }
703
- }
704
- }
705
- continue;
706
- }
707
- if (t === "response.function_call_arguments.delta") {
708
- const callId = resolveCallId(evt);
709
- const delta = evt.delta ?? "";
710
- if (!callId || !delta) continue;
711
- let buf = toolBuffers.get(callId);
712
- if (!buf) {
713
- buf = { id: callId, name: "", arguments: "", emittedStart: false };
714
- toolBuffers.set(callId, buf);
715
- }
716
- buf.arguments += delta;
717
- if (buf.emittedStart) {
718
- yield {
719
- type: "action:args",
720
- id: buf.id,
721
- args: buf.arguments
722
- };
723
- }
724
- continue;
725
- }
726
- if (t === "response.output_item.done") {
727
- const item = evt.item;
728
- if (item?.type === "function_call") {
729
- const callId = item.call_id ?? item.id ?? "";
730
- const buf = toolBuffers.get(callId);
731
- const name = buf?.name || item.name || "";
732
- const argsStr = buf?.arguments || item.arguments || "{}";
733
- if (callId && name) {
734
- if (!buf?.emittedStart) {
735
- yield { type: "action:start", id: callId, name };
736
- }
737
- yield {
738
- type: "action:args",
739
- id: callId,
740
- args: argsStr
741
- };
742
- yield {
743
- type: "action:end",
744
- id: callId,
745
- name
746
- };
747
- }
748
- toolBuffers.delete(callId);
749
- }
750
- continue;
751
- }
752
- if (t === "response.completed") {
753
- const u = evt.response?.usage;
754
- if (u) {
755
- usage = {
756
- prompt_tokens: u.input_tokens ?? 0,
757
- completion_tokens: u.output_tokens ?? 0,
758
- total_tokens: u.total_tokens ?? (u.input_tokens ?? 0) + (u.output_tokens ?? 0)
759
- };
760
- }
761
- for (const buf of toolBuffers.values()) {
762
- if (!buf.id || !buf.name) continue;
763
- if (!buf.emittedStart) {
764
- yield { type: "action:start", id: buf.id, name: buf.name };
765
- }
766
- yield {
767
- type: "action:args",
768
- id: buf.id,
769
- args: buf.arguments || "{}"
770
- };
771
- yield { type: "action:end", id: buf.id, name: buf.name };
772
- }
773
- toolBuffers.clear();
774
- if (reasoningStarted && !textStarted) {
775
- yield { type: "thinking:end" };
776
- }
777
- yield { type: "message:end" };
778
- yield { type: "done", usage };
779
- finishEmitted = true;
780
- continue;
781
- }
782
- if (t === "response.error" || t === "error") {
783
- const msg = evt.error?.message || evt.message || "Responses API error";
784
- yield {
785
- type: "error",
786
- message: msg,
787
- code: "OPENAI_RESPONSES_ERROR"
788
- };
789
- return;
790
- }
791
- }
792
- } catch (error) {
793
- yield {
794
- type: "error",
795
- message: error instanceof Error ? error.message : "Unknown error",
796
- code: "OPENAI_RESPONSES_ERROR"
797
- };
798
- return;
799
- }
800
- if (!finishEmitted) {
801
- if (reasoningStarted && !textStarted) {
802
- yield { type: "thinking:end" };
803
- }
804
- yield { type: "message:end" };
805
- yield { type: "done", usage };
806
- }
807
- }
808
590
  async completeWithResponses(request) {
809
591
  const client = await this.getClient();
810
592
  const openaiToolOptions = request.providerToolOptions?.openai;
593
+ const responsesTextFormat = toOpenAIResponsesTextFormat(
594
+ request.config?.responseFormat
595
+ );
811
596
  const payload = {
812
597
  model: request.config?.model || this.model,
813
598
  instructions: request.systemPrompt,
@@ -817,6 +602,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
817
602
  parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
818
603
  temperature: request.config?.temperature ?? this.config.temperature,
819
604
  max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
605
+ ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
820
606
  stream: false
821
607
  };
822
608
  logProviderPayload("openai", "request payload", payload, request.debug);
@@ -938,37 +724,21 @@ var OpenAIAdapter = class _OpenAIAdapter {
938
724
  name: openaiToolOptions.toolChoice.name
939
725
  }
940
726
  } : openaiToolOptions?.toolChoice;
941
- const isOpenRouter = this.provider === "openrouter";
942
- const activeModel = request.config?.model || this.model;
943
- const modelSlug = activeModel.replace("openai/", "");
944
- const isOSeries = /^o[1-9]/.test(modelSlug);
945
- const isOpenAIOnOpenRouter = isOpenRouter && activeModel.startsWith("openai/");
946
- if (!this.config.disableThinking && this.isOpenAIReasoningModelOnOpenRouter(activeModel)) {
947
- yield* this.streamWithResponsesAPI(request, activeModel, messageId);
948
- return;
949
- }
950
- const maxTokensValue = request.config?.maxTokens ?? this.config.maxTokens;
727
+ const modelIdForPayload = request.config?.model || this.model;
951
728
  const payload = {
952
- model: activeModel,
729
+ model: modelIdForPayload,
953
730
  messages,
954
731
  tools: tools.length > 0 ? tools : void 0,
955
732
  tool_choice: tools.length > 0 ? toolChoice : void 0,
956
733
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
734
+ ...buildOpenAITokenParams(
735
+ modelIdForPayload,
736
+ request.config?.maxTokens ?? this.config.maxTokens,
737
+ request.config?.temperature ?? this.config.temperature
738
+ ),
739
+ response_format: toOpenAIResponseFormat(request.config?.responseFormat),
957
740
  stream: true,
958
- stream_options: { include_usage: true },
959
- // o-series: use max_completion_tokens + reasoning_effort, no temperature
960
- // regular models: use max_tokens + temperature
961
- ...isOSeries ? {
962
- max_completion_tokens: maxTokensValue,
963
- reasoning_effort: request.config?.reasoningEffort ?? "medium"
964
- } : {
965
- temperature: request.config?.temperature ?? this.config.temperature,
966
- max_tokens: maxTokensValue
967
- },
968
- // Non-OpenAI OpenRouter models support OR's reasoning/include_reasoning params.
969
- // When disableThinking=true we must explicitly send include_reasoning:false because
970
- // models like Qwen3 and DeepSeek-R1 reason by default even without the reasoning param.
971
- ...isOpenRouter && !isOpenAIOnOpenRouter ? this.config.disableThinking ? { include_reasoning: false } : { reasoning: { max_tokens: 8e3 }, include_reasoning: true } : {}
741
+ stream_options: { include_usage: true }
972
742
  };
973
743
  logProviderPayload("openai", "request payload", payload, request.debug);
974
744
  const stream = await client.chat.completions.create(payload);
@@ -976,7 +746,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
976
746
  const collectedCitations = [];
977
747
  let citationIndex = 0;
978
748
  let usage;
979
- let adapterReasoningStarted = false;
980
749
  for await (const chunk of stream) {
981
750
  logProviderPayload("openai", "stream chunk", chunk, request.debug);
982
751
  if (request.signal?.aborted) {
@@ -987,22 +756,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
987
756
  if (delta?.content) {
988
757
  yield { type: "message:delta", content: delta.content };
989
758
  }
990
- if (isOpenRouter) {
991
- const rc = delta?.reasoning_content ?? delta?.reasoning ?? null;
992
- if (rc) {
993
- const rcText = typeof rc === "string" ? rc : Array.isArray(rc) && rc[0]?.text ? rc[0].text : "";
994
- if (rcText) {
995
- if (!adapterReasoningStarted) {
996
- yield { type: "thinking:start" };
997
- adapterReasoningStarted = true;
998
- }
999
- yield { type: "thinking:delta", content: rcText };
1000
- }
1001
- } else if (adapterReasoningStarted && (delta?.content || choice?.finish_reason)) {
1002
- yield { type: "thinking:end" };
1003
- adapterReasoningStarted = false;
1004
- }
1005
- }
1006
759
  const annotations = delta?.annotations;
1007
760
  if (annotations && annotations.length > 0) {
1008
761
  for (const annotation of annotations) {
@@ -1050,11 +803,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
1050
803
  };
1051
804
  } else if (currentToolCall && toolCall.function?.arguments) {
1052
805
  currentToolCall.arguments += toolCall.function.arguments;
1053
- yield {
1054
- type: "action:args",
1055
- id: currentToolCall.id,
1056
- args: currentToolCall.arguments
1057
- };
1058
806
  }
1059
807
  }
1060
808
  }
@@ -1130,24 +878,20 @@ var OpenAIAdapter = class _OpenAIAdapter {
1130
878
  name: openaiToolOptions.toolChoice.name
1131
879
  }
1132
880
  } : openaiToolOptions?.toolChoice;
1133
- const activeModel2 = request.config?.model || this.model;
1134
- const modelSlug2 = activeModel2.replace("openai/", "");
1135
- const isOSeries2 = /^o[1-9]/.test(modelSlug2);
1136
- const maxTokensValue2 = request.config?.maxTokens ?? this.config.maxTokens;
881
+ const modelIdForCompletePayload = request.config?.model || this.model;
1137
882
  const payload = {
1138
- model: activeModel2,
883
+ model: modelIdForCompletePayload,
1139
884
  messages,
1140
885
  tools: tools.length > 0 ? tools : void 0,
1141
886
  tool_choice: tools.length > 0 ? toolChoice : void 0,
1142
887
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
1143
- stream: false,
1144
- ...isOSeries2 ? {
1145
- max_completion_tokens: maxTokensValue2,
1146
- reasoning_effort: request.config?.reasoningEffort ?? "medium"
1147
- } : {
1148
- temperature: request.config?.temperature ?? this.config.temperature,
1149
- max_tokens: maxTokensValue2
1150
- }
888
+ ...buildOpenAITokenParams(
889
+ modelIdForCompletePayload,
890
+ request.config?.maxTokens ?? this.config.maxTokens,
891
+ request.config?.temperature ?? this.config.temperature
892
+ ),
893
+ response_format: toOpenAIResponseFormat(request.config?.responseFormat),
894
+ stream: false
1151
895
  };
1152
896
  logProviderPayload("openai", "request payload", payload, request.debug);
1153
897
  const response = await client.chat.completions.create(payload);
@@ -1342,7 +1086,8 @@ function createXAI(config = {}) {
1342
1086
  supportsVideo: false,
1343
1087
  maxTokens: model.maxTokens,
1344
1088
  supportedImageTypes: model.vision ? ["image/png", "image/jpeg", "image/gif", "image/webp"] : [],
1345
- supportsJsonMode: false,
1089
+ // xAI accepts OpenAI-compatible `response_format` on grok-2-1212+.
1090
+ supportsJsonMode: true,
1346
1091
  supportsSystemMessages: true
1347
1092
  };
1348
1093
  };