@absolutejs/ai 0.0.56 → 0.0.57

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.
@@ -1,6 +1,286 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
+ // src/ai/inputCapacity.ts
5
+ class AIInputError extends Error {
6
+ code;
7
+ constructor(code, message) {
8
+ super(message);
9
+ this.code = code;
10
+ this.name = "AIInputError";
11
+ }
12
+ }
13
+ var positiveTokenLimit = (value) => {
14
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0)
15
+ throw new AIInputError("capacity_unavailable", "The provider did not supply a valid model limit.");
16
+ return value;
17
+ };
18
+ var inputTokenCount = (value) => {
19
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
20
+ throw new AIInputError("capacity_unavailable", "The provider did not supply a valid token count.");
21
+ return value;
22
+ };
23
+ var inspectAIInput = async (provider, params) => {
24
+ params.signal?.throwIfAborted();
25
+ if (!provider.inputCapacity)
26
+ throw new AIInputError("capacity_unavailable", "This provider does not expose model capacity and token counting.");
27
+ const [limits, tokens] = await Promise.all([
28
+ provider.inputCapacity.getLimits(params),
29
+ provider.inputCapacity.countTokens(params)
30
+ ]);
31
+ const inputTokens = inputTokenCount(tokens);
32
+ const outputTokens = positiveTokenLimit(provider.inputCapacity.outputTokens?.(params) ?? params.maxTokens ?? limits.maxOutputTokens);
33
+ const maxInputTokens = positiveTokenLimit(limits.maxInputTokens);
34
+ const maxOutputTokens = positiveTokenLimit(limits.maxOutputTokens);
35
+ const availableInputTokens = Math.max(0, Math.min(maxInputTokens, limits.contextWindowTokens === undefined ? maxInputTokens : positiveTokenLimit(limits.contextWindowTokens) - outputTokens));
36
+ return {
37
+ limits,
38
+ inputTokens,
39
+ outputTokens,
40
+ availableInputTokens,
41
+ fits: outputTokens <= maxOutputTokens && inputTokens <= availableInputTokens
42
+ };
43
+ };
44
+ var cacheModelLimits = (load, ttlMs = 300000) => {
45
+ const cache = new Map;
46
+ return async (params) => {
47
+ const entry = cache.get(params.model);
48
+ if (entry && Date.now() - entry.at < ttlMs)
49
+ return entry.limits;
50
+ const limits = await load(params);
51
+ positiveTokenLimit(limits.maxInputTokens);
52
+ positiveTokenLimit(limits.maxOutputTokens);
53
+ if (cache.size >= 100)
54
+ cache.clear();
55
+ cache.set(params.model, { at: Date.now(), limits });
56
+ return limits;
57
+ };
58
+ };
59
+ var capacityJson = async (response) => {
60
+ if (!response.ok)
61
+ throw new AIInputError("capacity_unavailable", `Model capacity request failed (${response.status}).`);
62
+ const value = await response.json();
63
+ if (!value || typeof value !== "object" || Array.isArray(value))
64
+ throw new AIInputError("capacity_unavailable", "Model capacity response was invalid.");
65
+ return value;
66
+ };
67
+
68
+ // src/ai/providers/openaiCapacity.ts
69
+ var LIMITS = {
70
+ "gpt-4.1": {
71
+ maxInputTokens: 1047576,
72
+ contextWindowTokens: 1047576,
73
+ maxOutputTokens: 32768
74
+ },
75
+ "gpt-4.1-2025-04-14": {
76
+ maxInputTokens: 1047576,
77
+ contextWindowTokens: 1047576,
78
+ maxOutputTokens: 32768
79
+ },
80
+ "gpt-4.1-mini": {
81
+ maxInputTokens: 1047576,
82
+ contextWindowTokens: 1047576,
83
+ maxOutputTokens: 32768
84
+ },
85
+ "gpt-4.1-mini-2025-04-14": {
86
+ maxInputTokens: 1047576,
87
+ contextWindowTokens: 1047576,
88
+ maxOutputTokens: 32768
89
+ },
90
+ "gpt-4.1-nano": {
91
+ maxInputTokens: 1047576,
92
+ contextWindowTokens: 1047576,
93
+ maxOutputTokens: 32768
94
+ },
95
+ "gpt-4.1-nano-2025-04-14": {
96
+ maxInputTokens: 1047576,
97
+ contextWindowTokens: 1047576,
98
+ maxOutputTokens: 32768
99
+ },
100
+ "gpt-4o": {
101
+ maxInputTokens: 128000,
102
+ contextWindowTokens: 128000,
103
+ maxOutputTokens: 16384
104
+ },
105
+ "gpt-4o-mini": {
106
+ maxInputTokens: 128000,
107
+ contextWindowTokens: 128000,
108
+ maxOutputTokens: 16384
109
+ },
110
+ "gpt-4o-mini-2024-07-18": {
111
+ maxInputTokens: 128000,
112
+ contextWindowTokens: 128000,
113
+ maxOutputTokens: 16384
114
+ },
115
+ "gpt-5": {
116
+ maxInputTokens: 272000,
117
+ contextWindowTokens: 400000,
118
+ maxOutputTokens: 128000
119
+ },
120
+ "gpt-5-mini": {
121
+ maxInputTokens: 272000,
122
+ contextWindowTokens: 400000,
123
+ maxOutputTokens: 128000
124
+ },
125
+ "gpt-5-mini-2025-08-07": {
126
+ maxInputTokens: 272000,
127
+ contextWindowTokens: 400000,
128
+ maxOutputTokens: 128000
129
+ },
130
+ "gpt-5-nano": {
131
+ maxInputTokens: 272000,
132
+ contextWindowTokens: 400000,
133
+ maxOutputTokens: 128000
134
+ },
135
+ "gpt-5-nano-2025-08-07": {
136
+ maxInputTokens: 272000,
137
+ contextWindowTokens: 400000,
138
+ maxOutputTokens: 128000
139
+ },
140
+ "gpt-5.4-mini": {
141
+ maxInputTokens: 272000,
142
+ contextWindowTokens: 400000,
143
+ maxOutputTokens: 128000
144
+ },
145
+ "gpt-5.4-nano": {
146
+ maxInputTokens: 272000,
147
+ contextWindowTokens: 400000,
148
+ maxOutputTokens: 128000
149
+ },
150
+ "gpt-5.1": {
151
+ maxInputTokens: 400000,
152
+ contextWindowTokens: 400000,
153
+ maxOutputTokens: 128000
154
+ },
155
+ "gpt-5.1-2025-11-13": {
156
+ maxInputTokens: 400000,
157
+ contextWindowTokens: 400000,
158
+ maxOutputTokens: 128000
159
+ },
160
+ "gpt-5.2": {
161
+ maxInputTokens: 400000,
162
+ contextWindowTokens: 400000,
163
+ maxOutputTokens: 128000
164
+ },
165
+ "gpt-5.2-2025-12-11": {
166
+ maxInputTokens: 400000,
167
+ contextWindowTokens: 400000,
168
+ maxOutputTokens: 128000
169
+ },
170
+ "gpt-5.4": {
171
+ maxInputTokens: 1050000,
172
+ contextWindowTokens: 1050000,
173
+ maxOutputTokens: 128000
174
+ },
175
+ "gpt-5.4-2026-03-05": {
176
+ maxInputTokens: 1050000,
177
+ contextWindowTokens: 1050000,
178
+ maxOutputTokens: 128000
179
+ },
180
+ "gpt-5.5": {
181
+ maxInputTokens: 1050000,
182
+ contextWindowTokens: 1050000,
183
+ maxOutputTokens: 128000
184
+ },
185
+ "gpt-6-astra": {
186
+ maxInputTokens: 922000,
187
+ contextWindowTokens: 1050000,
188
+ maxOutputTokens: 128000
189
+ },
190
+ "gpt-5.6-sol": {
191
+ maxInputTokens: 922000,
192
+ contextWindowTokens: 1050000,
193
+ maxOutputTokens: 128000
194
+ },
195
+ "gpt-5.6-terra": {
196
+ maxInputTokens: 922000,
197
+ contextWindowTokens: 1050000,
198
+ maxOutputTokens: 128000
199
+ },
200
+ "gpt-5.6-luna": {
201
+ maxInputTokens: 922000,
202
+ contextWindowTokens: 1050000,
203
+ maxOutputTokens: 128000
204
+ },
205
+ o3: {
206
+ maxInputTokens: 200000,
207
+ contextWindowTokens: 200000,
208
+ maxOutputTokens: 1e5
209
+ },
210
+ "o3-2025-04-16": {
211
+ maxInputTokens: 200000,
212
+ contextWindowTokens: 200000,
213
+ maxOutputTokens: 1e5
214
+ },
215
+ "o4-mini": {
216
+ maxInputTokens: 200000,
217
+ contextWindowTokens: 200000,
218
+ maxOutputTokens: 1e5
219
+ },
220
+ "o4-mini-2025-04-16": {
221
+ maxInputTokens: 200000,
222
+ contextWindowTokens: 200000,
223
+ maxOutputTokens: 1e5
224
+ },
225
+ "gpt-5-chat-latest": {
226
+ maxInputTokens: 128000,
227
+ contextWindowTokens: 128000,
228
+ maxOutputTokens: 16384
229
+ },
230
+ "gpt-5.1-chat-latest": {
231
+ maxInputTokens: 128000,
232
+ contextWindowTokens: 128000,
233
+ maxOutputTokens: 16384
234
+ },
235
+ "gpt-5.2-chat-latest": {
236
+ maxInputTokens: 128000,
237
+ contextWindowTokens: 128000,
238
+ maxOutputTokens: 16384
239
+ }
240
+ };
241
+ var openaiInputCapacity = (config) => ({
242
+ outputTokens: (params) => {
243
+ const value = config.body(params).max_output_tokens;
244
+ return value === undefined ? undefined : positiveTokenLimit(value);
245
+ },
246
+ getLimits: async (params) => {
247
+ if (config.modelLimits)
248
+ return config.modelLimits(params);
249
+ if (new URL(config.baseUrl).origin !== "https://api.openai.com")
250
+ throw new AIInputError("capacity_unavailable", "This compatible endpoint must expose its own model capacity.");
251
+ const limits = LIMITS[params.model];
252
+ if (!limits)
253
+ throw new AIInputError("capacity_unavailable", `Model limits are unavailable for ${params.model}; no character limit has been substituted.`);
254
+ return { ...limits };
255
+ },
256
+ countTokens: async (params) => {
257
+ const headers = new Headers(await config.headers(params));
258
+ headers.set("Authorization", `Bearer ${await config.key()}`);
259
+ headers.set("Content-Type", "application/json");
260
+ const body = config.body(params);
261
+ const counted = {};
262
+ for (const key of [
263
+ "model",
264
+ "input",
265
+ "instructions",
266
+ "tools",
267
+ "tool_choice",
268
+ "reasoning",
269
+ "text",
270
+ "parallel_tool_calls"
271
+ ])
272
+ if (body[key] !== undefined)
273
+ counted[key] = body[key];
274
+ const response = await config.fetch(`${config.baseUrl}/v1/responses/input_tokens`, {
275
+ method: "POST",
276
+ headers,
277
+ body: JSON.stringify(counted),
278
+ signal: params.signal ? AbortSignal.any([params.signal, AbortSignal.timeout(15000)]) : AbortSignal.timeout(15000)
279
+ });
280
+ return inputTokenCount((await capacityJson(response)).input_tokens);
281
+ }
282
+ });
283
+
4
284
  // src/ai/errors/providerError.ts
5
285
  var PROVIDER_STATUS_PAGES = {
6
286
  anthropic: "https://status.claude.com",
@@ -231,6 +511,7 @@ var withResilience = (provider, providerName = "unknown") => {
231
511
  }
232
512
  };
233
513
  return {
514
+ ...provider,
234
515
  stream: (params) => {
235
516
  const tripped = circuitOpen(providerName);
236
517
  if (tripped) {
@@ -247,6 +528,7 @@ var withResilience = (provider, providerName = "unknown") => {
247
528
  var instrumentAIProvider = (provider, providerName) => {
248
529
  const resilient = withResilience(provider, providerName);
249
530
  return {
531
+ ...provider,
250
532
  stream: (params) => {
251
533
  if (!params.onUsage && !params.onSpan) {
252
534
  return resilient.stream(params);
@@ -388,81 +670,23 @@ var openaiEffortValue = (model, reasoning) => {
388
670
  return clampEffort(requested, allowed);
389
671
  };
390
672
 
391
- // src/ai/providers/openai.ts
673
+ // src/ai/providers/openaiResponses.ts
392
674
  var h2IfHttps = (url) => url.startsWith("https://") ? { protocol: "http2" } : {};
393
675
  var DEFAULT_BASE_URL = "https://api.openai.com";
394
- var SSE_DATA_PREFIX_LENGTH = 6;
395
- var DONE_SENTINEL = "[DONE]";
396
- var NOT_FOUND = -1;
676
+ var EVENT_PREFIX_LENGTH = 7;
677
+ var DATA_PREFIX_LENGTH = 6;
397
678
  var isRecord = (value) => typeof value === "object" && value !== null;
398
679
  var isRecordArray = (value) => Array.isArray(value) && value.length > 0 && isRecord(value[0]);
399
- var hasArrayContent = (msg) => typeof msg.content !== "string" && Array.isArray(msg.content);
400
- var buildToolMessages = (blocks) => {
401
- const toolUseBlocks = blocks.filter((block) => block.type === "tool_use");
402
- const toolResultBlocks = blocks.filter((block) => block.type === "tool_result");
403
- const messages = [];
404
- if (toolUseBlocks.length > 0) {
405
- messages.push({
406
- content: null,
407
- role: "assistant",
408
- tool_calls: toolUseBlocks.map((block) => ({
409
- function: {
410
- arguments: typeof block.input === "string" ? block.input : JSON.stringify(block.input),
411
- name: block.name
412
- },
413
- id: block.id,
414
- type: "function"
415
- }))
416
- });
417
- }
418
- for (const result of toolResultBlocks) {
419
- messages.push({
420
- content: typeof result.content === "string" ? result.content : "",
421
- role: "tool",
422
- tool_call_id: result.tool_use_id
423
- });
424
- }
425
- return messages;
426
- };
427
- var processMessageAtIndex = (result, msg, idx) => {
428
- if (!hasArrayContent(msg)) {
429
- return;
430
- }
431
- const hasToolBlocks = msg.content.some((block) => block.type === "tool_use" || block.type === "tool_result");
432
- if (!hasToolBlocks) {
433
- return;
434
- }
435
- const toolMessages = buildToolMessages(msg.content);
436
- result.splice(idx, 1, ...toolMessages);
437
- };
438
- var convertSingleMessage = (result, msg, idx) => {
439
- if (!msg) {
440
- return;
441
- }
442
- processMessageAtIndex(result, msg, idx);
443
- };
444
- var convertToolResultMessages = (messages, params) => {
445
- const result = [...messages];
446
- for (let idx = 0;idx < params.messages.length; idx++) {
447
- convertSingleMessage(result, params.messages[idx], idx);
680
+ var mapBlockToResponsesFormat = (block) => {
681
+ if (block.type === "text") {
682
+ return { text: block.content, type: "input_text" };
448
683
  }
449
- return result;
450
- };
451
- var mapToolDefinitions = (tools) => tools.map((tool) => ({
452
- function: {
453
- description: tool.description,
454
- name: tool.name,
455
- parameters: tool.input_schema
456
- },
457
- type: "function"
458
- }));
459
- var mapContentBlockToOpenAI = (block) => {
460
684
  if (block.type === "image") {
461
685
  return {
462
686
  image_url: {
463
687
  url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
464
688
  },
465
- type: "image_url"
689
+ type: "input_image"
466
690
  };
467
691
  }
468
692
  if (block.type === "document") {
@@ -471,7 +695,7 @@ var mapContentBlockToOpenAI = (block) => {
471
695
  file_data: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`,
472
696
  filename: block.name ?? "document.pdf"
473
697
  },
474
- type: "file"
698
+ type: "input_file"
475
699
  };
476
700
  }
477
701
  if (block.type === "audio") {
@@ -482,48 +706,95 @@ var mapContentBlockToOpenAI = (block) => {
482
706
  }
483
707
  if (block.type === "video") {
484
708
  return {
485
- type: "video_url",
486
- video_url: {
487
- url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
488
- }
709
+ type: "input_video",
710
+ video_url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
489
711
  };
490
712
  }
491
- if (block.type === "text") {
492
- return { text: block.content, type: "text" };
713
+ return null;
714
+ };
715
+ var mapContentToResponsesFormat = (content) => {
716
+ if (typeof content === "string") {
717
+ return content;
718
+ }
719
+ const parts = content.map(mapBlockToResponsesFormat).filter((mapped) => mapped !== null);
720
+ return parts.length > 0 ? parts : "";
721
+ };
722
+ var hasToolBlocks = (content) => content.some((block) => block.type === "tool_use" || block.type === "tool_result");
723
+ var convertToolBlock = (block) => {
724
+ if (block.type === "provider_data" && block.provider === "openrouter") {
725
+ return { ...block.data };
726
+ }
727
+ if (block.type === "tool_use") {
728
+ if (block.providerData)
729
+ return { ...block.providerData };
730
+ return {
731
+ arguments: typeof block.input === "string" ? block.input : JSON.stringify(block.input),
732
+ call_id: block.id,
733
+ name: block.name,
734
+ type: "function_call"
735
+ };
736
+ }
737
+ if (block.type === "tool_result") {
738
+ return {
739
+ call_id: block.tool_use_id,
740
+ output: typeof block.content === "string" ? block.content : "",
741
+ type: "function_call_output"
742
+ };
493
743
  }
494
744
  return null;
495
745
  };
496
- var mapOpenAIContent = (msg) => {
497
- if (typeof msg.content === "string") {
498
- return msg.content;
746
+ var convertToolBlocks = (content) => content.map(convertToolBlock).filter((converted) => converted !== null);
747
+ var convertMessage = (msg) => {
748
+ if (typeof msg.content !== "string" && Array.isArray(msg.content) && hasToolBlocks(msg.content)) {
749
+ return convertToolBlocks(msg.content);
499
750
  }
500
- const hasMedia = msg.content.some((block) => block.type === "image" || block.type === "document" || block.type === "audio" || block.type === "video");
501
- if (!hasMedia) {
502
- return null;
751
+ const content = mapContentToResponsesFormat(msg.content);
752
+ return [
753
+ {
754
+ content,
755
+ role: msg.role === "system" ? "developer" : msg.role,
756
+ type: "message"
757
+ }
758
+ ];
759
+ };
760
+ var buildInput = (messages) => {
761
+ const input = [];
762
+ for (const msg of messages) {
763
+ input.push(...convertMessage(msg));
503
764
  }
504
- return msg.content.map(mapContentBlockToOpenAI).filter((mapped) => mapped !== null);
765
+ return input;
505
766
  };
506
- var buildRequestBody = (params, capabilityModel = params.model) => {
507
- const messages = convertToolResultMessages(params.messages.map((msg) => ({
508
- content: mapOpenAIContent(msg),
509
- role: msg.role
510
- })), params);
511
- if (params.systemPrompt) {
512
- messages.unshift({ content: params.systemPrompt, role: "system" });
767
+ var mapToolDefinition = (tool) => ({
768
+ description: tool.description,
769
+ name: tool.name,
770
+ parameters: tool.input_schema,
771
+ type: "function"
772
+ });
773
+ var buildTools = (tools, isImageModel) => {
774
+ const mapped = tools ? tools.map(mapToolDefinition) : [];
775
+ const result = [...mapped];
776
+ if (isImageModel) {
777
+ result.push({ type: "image_generation" });
513
778
  }
779
+ return result.length > 0 ? result : undefined;
780
+ };
781
+ var buildResponsesRequestBody = (params, isImageModel, capabilityModel = params.model) => {
514
782
  const body = {
515
- messages,
783
+ input: buildInput(params.messages),
516
784
  model: params.model,
517
- stream: true,
518
- stream_options: { include_usage: true }
785
+ stream: true
519
786
  };
520
- if (params.tools && params.tools.length > 0) {
521
- body.tools = mapToolDefinitions(params.tools);
787
+ if (params.systemPrompt) {
788
+ body.instructions = params.systemPrompt;
789
+ }
790
+ const tools = buildTools(params.tools, isImageModel);
791
+ if (tools) {
792
+ body.tools = tools;
522
793
  if (params.toolChoice === "auto" || params.toolChoice === "none" || params.toolChoice === "required") {
523
794
  body.tool_choice = params.toolChoice;
524
795
  } else if (params.toolChoice && typeof params.toolChoice === "object") {
525
796
  body.tool_choice = {
526
- function: { name: params.toolChoice.name },
797
+ name: params.toolChoice.name,
527
798
  type: "function"
528
799
  };
529
800
  }
@@ -531,24 +802,12 @@ var buildRequestBody = (params, capabilityModel = params.model) => {
531
802
  body.parallel_tool_calls = params.parallelToolCalls;
532
803
  }
533
804
  }
534
- if (isOpenAIReasoningModel(capabilityModel)) {
535
- if (typeof params.maxTokens === "number") {
536
- body.max_completion_tokens = params.maxTokens;
537
- }
538
- if (params.reasoning) {
539
- const effort = openaiEffortValue(capabilityModel, params.reasoning);
540
- if (effort)
541
- body.reasoning_effort = effort;
542
- }
543
- } else {
544
- if (typeof params.temperature === "number") {
545
- body.temperature = params.temperature;
546
- }
547
- if (typeof params.topP === "number")
548
- body.top_p = params.topP;
549
- if (typeof params.maxTokens === "number")
550
- body.max_tokens = params.maxTokens;
551
- }
805
+ if (typeof params.temperature === "number")
806
+ body.temperature = params.temperature;
807
+ if (typeof params.topP === "number")
808
+ body.top_p = params.topP;
809
+ if (typeof params.maxTokens === "number")
810
+ body.max_output_tokens = params.maxTokens;
552
811
  if (params.stopSequences && params.stopSequences.length > 0)
553
812
  body.stop = params.stopSequences;
554
813
  if (typeof params.seed === "number")
@@ -559,20 +818,36 @@ var buildRequestBody = (params, capabilityModel = params.model) => {
559
818
  body.presence_penalty = params.presencePenalty;
560
819
  if (params.responseFormat) {
561
820
  if (params.responseFormat.type === "text" || params.responseFormat.type === "json_object") {
562
- body.response_format = { type: params.responseFormat.type };
821
+ body.text = { format: { type: params.responseFormat.type } };
563
822
  } else if (params.responseFormat.type === "json_schema") {
564
- body.response_format = {
565
- json_schema: {
823
+ body.text = {
824
+ format: {
566
825
  name: params.responseFormat.name,
567
826
  schema: params.responseFormat.schema,
568
- strict: params.responseFormat.strict ?? true
569
- },
570
- type: "json_schema"
571
- };
572
- }
827
+ strict: params.responseFormat.strict ?? true,
828
+ type: "json_schema"
829
+ }
830
+ };
831
+ }
832
+ }
833
+ if (params.reasoning && isOpenAIReasoningModel(capabilityModel)) {
834
+ const effort = openaiEffortValue(capabilityModel, params.reasoning);
835
+ if (effort) {
836
+ body.reasoning = {
837
+ effort,
838
+ summary: "auto"
839
+ };
840
+ }
573
841
  }
574
842
  return body;
575
843
  };
844
+ var parseJSON = (data) => {
845
+ try {
846
+ return JSON.parse(data);
847
+ } catch {
848
+ return null;
849
+ }
850
+ };
576
851
  var parseToolInput = (rawArguments) => {
577
852
  try {
578
853
  return JSON.parse(rawArguments);
@@ -580,284 +855,297 @@ var parseToolInput = (rawArguments) => {
580
855
  return rawArguments;
581
856
  }
582
857
  };
583
- var flushPendingToolCalls = function* (pendingToolCalls) {
584
- for (const [, tool] of pendingToolCalls) {
585
- const input = parseToolInput(tool.arguments);
586
- yield {
587
- id: tool.id,
588
- input,
589
- name: tool.name,
590
- type: "tool_use"
591
- };
858
+ var extractUsage = (response) => {
859
+ if (!isRecord(response.usage)) {
860
+ return;
592
861
  }
593
- pendingToolCalls.clear();
594
- };
595
- var extractUsage = (parsedUsage) => {
596
- const prompt = parsedUsage.prompt_tokens ?? 0;
597
- const cached = parsedUsage.cached_tokens ?? 0;
598
- return {
862
+ const { usage } = response;
863
+ const input = typeof usage.input_tokens === "number" ? usage.input_tokens : 0;
864
+ const cached = isRecord(usage.input_tokens_details) && typeof usage.input_tokens_details.cached_tokens === "number" ? usage.input_tokens_details.cached_tokens : 0;
865
+ const outputDetails = isRecord(usage.output_tokens_details) ? usage.output_tokens_details : undefined;
866
+ const inputDetails = isRecord(usage.input_tokens_details) ? usage.input_tokens_details : undefined;
867
+ const costDetails = isRecord(usage.cost_details) ? usage.cost_details : undefined;
868
+ const normalized = {
599
869
  cacheReadInputTokens: cached,
600
- cacheWriteInputTokens: parsedUsage.cache_write_tokens || undefined,
601
- costCredits: parsedUsage.cost,
602
- inputTokens: Math.max(0, prompt - cached),
603
- outputTokens: parsedUsage.completion_tokens ?? 0,
604
- reasoningTokens: parsedUsage.reasoning_tokens || undefined,
605
- upstreamInferenceCostCredits: parsedUsage.upstream_inference_cost || undefined
870
+ cacheWriteInputTokens: inputDetails && typeof inputDetails.cache_write_tokens === "number" ? inputDetails.cache_write_tokens : undefined,
871
+ costCredits: typeof usage.cost === "number" ? usage.cost : undefined,
872
+ inputTokens: Math.max(0, input - cached),
873
+ outputTokens: typeof usage.output_tokens === "number" ? usage.output_tokens : 0,
874
+ reasoningTokens: outputDetails && typeof outputDetails.reasoning_tokens === "number" ? outputDetails.reasoning_tokens : undefined,
875
+ upstreamInferenceCostCredits: costDetails && typeof costDetails.upstream_inference_cost === "number" ? costDetails.upstream_inference_cost : undefined
606
876
  };
877
+ if (isRecord(usage.server_tool_use)) {
878
+ normalized.serverToolUse = Object.fromEntries(Object.entries(usage.server_tool_use).filter((entry) => typeof entry[1] === "number"));
879
+ }
880
+ return normalized;
607
881
  };
608
- var resolveToolCallIndex = (toolCall) => {
609
- const raw = typeof toolCall.index === "number" ? toolCall.index : NOT_FOUND;
610
- return raw < 0 ? undefined : raw;
611
- };
612
- var initPendingToolCall = (toolCall, func, index, pendingToolCalls) => {
613
- if (pendingToolCalls.has(index)) {
882
+ var extractResponseMetadata = (response) => {
883
+ const providerMetadata = isRecord(response.openrouter_metadata) ? response.openrouter_metadata : undefined;
884
+ const generationId = typeof response.id === "string" ? response.id : undefined;
885
+ const model = typeof response.model === "string" ? response.model : undefined;
886
+ const provider = typeof response.provider === "string" ? response.provider : undefined;
887
+ const serviceTier = typeof response.service_tier === "string" ? response.service_tier : undefined;
888
+ if (!providerMetadata && !generationId && !model && !provider && !serviceTier)
614
889
  return;
890
+ return { generationId, model, provider, providerMetadata, serviceTier };
891
+ };
892
+ var extractMimeFormat = (mimeType) => {
893
+ if (typeof mimeType !== "string") {
894
+ return "png";
615
895
  }
616
- const toolId = typeof toolCall.id === "string" ? toolCall.id : "";
617
- const toolName = func && typeof func.name === "string" ? func.name : "";
618
- pendingToolCalls.set(index, {
619
- arguments: "",
620
- id: toolId,
621
- name: toolName
622
- });
896
+ if (mimeType.includes("jpeg"))
897
+ return "jpeg";
898
+ if (mimeType.includes("webp"))
899
+ return "webp";
900
+ return "png";
623
901
  };
624
- var updatePendingToolCall = (toolCall, func, pending) => {
625
- if (typeof toolCall.id === "string") {
626
- pending.id = toolCall.id;
902
+ var processTextDelta = function* (parsed) {
903
+ if (typeof parsed.delta === "string") {
904
+ yield { content: parsed.delta, type: "text" };
627
905
  }
628
- if (func && typeof func.name === "string") {
629
- pending.name = func.name;
906
+ };
907
+ var processPartialImage = function* (parsed) {
908
+ const itemId = typeof parsed.item_id === "string" ? parsed.item_id : undefined;
909
+ const b64 = typeof parsed.partial_image_b64 === "string" ? parsed.partial_image_b64 : undefined;
910
+ if (b64) {
911
+ yield {
912
+ data: b64,
913
+ format: "png",
914
+ imageId: itemId,
915
+ isPartial: true,
916
+ type: "image"
917
+ };
630
918
  }
631
- if (func && typeof func.arguments === "string") {
632
- pending.arguments += func.arguments;
919
+ };
920
+ var processFunctionCallArgumentsDelta = (parsed, pendingCalls) => {
921
+ const itemId = typeof parsed.item_id === "string" ? parsed.item_id : "";
922
+ const callId = typeof parsed.call_id === "string" ? parsed.call_id : "";
923
+ const delta = typeof parsed.arguments_delta === "string" ? parsed.arguments_delta : "";
924
+ const existing = pendingCalls.get(itemId);
925
+ if (existing) {
926
+ existing.arguments += delta;
927
+ } else {
928
+ pendingCalls.set(itemId, {
929
+ arguments: delta,
930
+ callId,
931
+ name: ""
932
+ });
633
933
  }
634
934
  };
635
- var processToolCallDelta = (toolCall, pendingToolCalls) => {
636
- const index = resolveToolCallIndex(toolCall);
637
- if (index === undefined) {
935
+ var processFunctionCallArgumentsDone = function* (parsed, pendingCalls) {
936
+ const itemId = typeof parsed.item_id === "string" ? parsed.item_id : "";
937
+ const callId = typeof parsed.call_id === "string" ? parsed.call_id : "";
938
+ const fullArgs = typeof parsed.arguments === "string" ? parsed.arguments : "";
939
+ const pending = pendingCalls.get(itemId);
940
+ const name = pending?.name ?? "";
941
+ const args = fullArgs || pending?.arguments || "";
942
+ pendingCalls.delete(itemId);
943
+ yield {
944
+ id: callId || pending?.callId || itemId,
945
+ input: parseToolInput(args),
946
+ name,
947
+ providerData: pending?.providerData ? { ...pending.providerData, arguments: args } : undefined,
948
+ type: "tool_use"
949
+ };
950
+ };
951
+ var processOutputItemAdded = (parsed, pendingCalls) => {
952
+ if (!isRecord(parsed.item)) {
638
953
  return;
639
954
  }
640
- const func = isRecord(toolCall.function) ? toolCall.function : null;
641
- initPendingToolCall(toolCall, func, index, pendingToolCalls);
642
- const pending = pendingToolCalls.get(index);
643
- if (!pending) {
955
+ const { item } = parsed;
956
+ const itemId = typeof item.id === "string" ? item.id : "";
957
+ const itemType = typeof item.type === "string" ? item.type : "";
958
+ if (itemType !== "function_call") {
644
959
  return;
645
960
  }
646
- updatePendingToolCall(toolCall, func, pending);
961
+ const callId = typeof item.call_id === "string" ? item.call_id : "";
962
+ const name = typeof item.name === "string" ? item.name : "";
963
+ pendingCalls.set(itemId, {
964
+ arguments: "",
965
+ callId,
966
+ name,
967
+ providerData: { ...item }
968
+ });
647
969
  };
648
- var processToolCallDeltas = (toolCalls, pendingToolCalls) => {
649
- for (const toolCall of toolCalls) {
650
- processToolCallDelta(toolCall, pendingToolCalls);
651
- }
970
+ var processOutputItemDone = function* (parsed) {
971
+ if (!isRecord(parsed.item) || typeof parsed.item.type !== "string")
972
+ return;
973
+ if (!parsed.item.type.startsWith("openrouter:"))
974
+ return;
975
+ yield {
976
+ data: { ...parsed.item },
977
+ provider: "openrouter",
978
+ type: "provider_event"
979
+ };
652
980
  };
653
- var processDelta = function* (delta, pendingToolCalls) {
654
- if (typeof delta.content === "string") {
655
- yield { content: delta.content, type: "text" };
656
- }
657
- if (isRecord(delta.audio)) {
658
- const audio = delta.audio;
659
- if (typeof audio.data === "string" || typeof audio.transcript === "string") {
660
- yield {
661
- audioId: typeof audio.id === "string" ? audio.id : undefined,
662
- data: typeof audio.data === "string" ? audio.data : "",
663
- format: typeof audio.format === "string" ? audio.format : "pcm16",
664
- transcript: typeof audio.transcript === "string" ? audio.transcript : undefined,
665
- type: "audio"
666
- };
667
- }
668
- }
669
- if (isRecordArray(delta.tool_calls)) {
670
- processToolCallDeltas(delta.tool_calls, pendingToolCalls);
981
+ var isCompletedImageGeneration = (item) => item.type === "image_generation_call" && item.status === "completed" && typeof item.result === "string" && item.result !== "";
982
+ var buildImageChunk = (item) => ({
983
+ data: typeof item.result === "string" ? item.result : "",
984
+ format: extractMimeFormat(item.output_format),
985
+ imageId: typeof item.id === "string" ? item.id : undefined,
986
+ isPartial: false,
987
+ revisedPrompt: typeof item.revised_prompt === "string" ? item.revised_prompt : undefined,
988
+ type: "image"
989
+ });
990
+ var extractImageFromOutput = function* (output) {
991
+ const completedImages = output.filter(isCompletedImageGeneration);
992
+ for (const item of completedImages) {
993
+ yield buildImageChunk(item);
671
994
  }
672
- if (Array.isArray(delta.annotations)) {
673
- for (const annotation of delta.annotations) {
674
- if (!isRecord(annotation) || annotation.type !== "url_citation")
675
- continue;
676
- const citation = isRecord(annotation.url_citation) ? annotation.url_citation : annotation;
677
- if (typeof citation.url !== "string")
995
+ };
996
+ var extractCitationsFromOutput = function* (output) {
997
+ for (const item of output) {
998
+ if (!isRecordArray(item.content))
999
+ continue;
1000
+ for (const content of item.content) {
1001
+ if (!Array.isArray(content.annotations))
678
1002
  continue;
679
- yield {
680
- content: typeof citation.content === "string" ? citation.content : undefined,
681
- endIndex: typeof citation.end_index === "number" ? citation.end_index : undefined,
682
- startIndex: typeof citation.start_index === "number" ? citation.start_index : undefined,
683
- title: typeof citation.title === "string" ? citation.title : undefined,
684
- type: "citation",
685
- url: citation.url
686
- };
1003
+ for (const annotation of content.annotations) {
1004
+ if (!isRecord(annotation) || annotation.type !== "url_citation")
1005
+ continue;
1006
+ if (typeof annotation.url !== "string")
1007
+ continue;
1008
+ yield {
1009
+ content: typeof annotation.content === "string" ? annotation.content : undefined,
1010
+ endIndex: typeof annotation.end_index === "number" ? annotation.end_index : undefined,
1011
+ startIndex: typeof annotation.start_index === "number" ? annotation.start_index : undefined,
1012
+ title: typeof annotation.title === "string" ? annotation.title : undefined,
1013
+ type: "citation",
1014
+ url: annotation.url
1015
+ };
1016
+ }
687
1017
  }
688
1018
  }
689
1019
  };
690
- var narrowResponseMetadata = (parsed) => {
691
- const providerMetadata = isRecord(parsed.openrouter_metadata) ? parsed.openrouter_metadata : undefined;
692
- const generationId = typeof parsed.id === "string" ? parsed.id : undefined;
693
- const model = typeof parsed.model === "string" ? parsed.model : undefined;
694
- const serviceTier = typeof parsed.service_tier === "string" ? parsed.service_tier : undefined;
695
- const selected = providerMetadata && isRecord(providerMetadata.endpoints) ? providerMetadata.endpoints.available : undefined;
696
- const selectedEndpoint = Array.isArray(selected) ? selected.find((entry) => isRecord(entry) && entry.selected === true) : undefined;
697
- const provider = isRecord(selectedEndpoint) && typeof selectedEndpoint.provider === "string" ? selectedEndpoint.provider : undefined;
698
- if (!providerMetadata && !generationId && !model && !serviceTier)
1020
+ var processCompleted = function* (parsed) {
1021
+ if (!isRecord(parsed.response)) {
1022
+ yield { type: "done", usage: undefined };
699
1023
  return;
700
- return { generationId, model, provider, providerMetadata, serviceTier };
701
- };
702
- var processChoice = function* (choice, pendingToolCalls) {
703
- const delta = isRecord(choice.delta) ? choice.delta : null;
704
- if (delta) {
705
- yield* processDelta(delta, pendingToolCalls);
706
1024
  }
707
- if (choice.finish_reason === "tool_calls") {
708
- yield* flushPendingToolCalls(pendingToolCalls);
1025
+ const { response } = parsed;
1026
+ const usage = extractUsage(response);
1027
+ const metadata = extractResponseMetadata(response);
1028
+ if (isRecordArray(response.output)) {
1029
+ yield* extractCitationsFromOutput(response.output);
1030
+ yield* extractImageFromOutput(response.output);
709
1031
  }
1032
+ yield { metadata, type: "done", usage };
710
1033
  };
711
- var narrowUsageRecord = (parsed) => {
712
- if (!isRecord(parsed.usage)) {
713
- return;
714
- }
715
- const { usage } = parsed;
716
- const promptTokens = typeof usage.prompt_tokens === "number" ? usage.prompt_tokens : 0;
717
- const completionTokens = typeof usage.completion_tokens === "number" ? usage.completion_tokens : 0;
718
- const cachedTokens = isRecord(usage.prompt_tokens_details) && typeof usage.prompt_tokens_details.cached_tokens === "number" ? usage.prompt_tokens_details.cached_tokens : 0;
719
- const cacheWriteTokens = isRecord(usage.prompt_tokens_details) && typeof usage.prompt_tokens_details.cache_write_tokens === "number" ? usage.prompt_tokens_details.cache_write_tokens : 0;
720
- const reasoningTokens = isRecord(usage.completion_tokens_details) && typeof usage.completion_tokens_details.reasoning_tokens === "number" ? usage.completion_tokens_details.reasoning_tokens : 0;
721
- const cost = typeof usage.cost === "number" ? usage.cost : undefined;
722
- const upstreamInferenceCost = isRecord(usage.cost_details) && typeof usage.cost_details.upstream_inference_cost === "number" ? usage.cost_details.upstream_inference_cost : undefined;
723
- const normalized = extractUsage({
724
- cache_write_tokens: cacheWriteTokens,
725
- cached_tokens: cachedTokens,
726
- completion_tokens: completionTokens,
727
- cost,
728
- prompt_tokens: promptTokens,
729
- reasoning_tokens: reasoningTokens,
730
- upstream_inference_cost: upstreamInferenceCost
1034
+ var responseFailure = (eventType, parsed, providerName) => {
1035
+ const response = isRecord(parsed.response) ? parsed.response : parsed;
1036
+ const error = isRecord(response.error) ? response.error : undefined;
1037
+ const type = typeof response.error_type === "string" ? response.error_type : error && typeof error.code === "string" ? error.code : eventType;
1038
+ return new ProviderError({
1039
+ message: error && typeof error.message === "string" ? error.message : `OpenRouter Responses API: ${eventType}`,
1040
+ metadata: response,
1041
+ provider: providerName,
1042
+ retryable: type === "rate_limit_exceeded" || type === "provider_overloaded" || type === "provider_unavailable" || type === "server",
1043
+ type
731
1044
  });
732
- if (isRecord(usage.server_tool_use)) {
733
- normalized.serverToolUse = Object.fromEntries(Object.entries(usage.server_tool_use).filter((entry) => typeof entry[1] === "number"));
734
- }
735
- return normalized;
736
1045
  };
737
- var processSSELine = function* (line, pendingToolCalls, providerName) {
738
- const trimmed = line.trim();
739
- if (!trimmed || !trimmed.startsWith("data: ")) {
740
- return;
741
- }
742
- const data = trimmed.slice(SSE_DATA_PREFIX_LENGTH);
743
- if (data === DONE_SENTINEL) {
744
- yield* flushPendingToolCalls(pendingToolCalls);
745
- return;
746
- }
747
- let parsed;
748
- try {
749
- parsed = JSON.parse(data);
750
- } catch {
751
- return;
752
- }
753
- if (isRecord(parsed.error)) {
754
- const error = parsed.error;
755
- const metadata2 = isRecord(error.metadata) ? error.metadata : undefined;
756
- const status = typeof error.code === "number" ? error.code : null;
757
- const type = metadata2 && typeof metadata2.error_type === "string" ? metadata2.error_type : typeof error.error_type === "string" ? error.error_type : null;
758
- throw new ProviderError({
759
- message: typeof error.message === "string" ? error.message : "OpenRouter stream failed",
760
- metadata: metadata2,
761
- provider: providerName,
762
- retryable: status === 408 || status === 409 || status === 425 || status === 429 || status !== null && status >= 500,
763
- status,
764
- type
765
- });
766
- }
767
- const usageUpdate = narrowUsageRecord(parsed);
768
- if (usageUpdate) {
769
- yield { type: "usage_update", usage: usageUpdate };
770
- }
771
- const metadata = narrowResponseMetadata(parsed);
772
- if (metadata) {
773
- yield { metadata, type: "response_metadata" };
774
- }
775
- const { choices } = parsed;
776
- if (!isRecordArray(choices)) {
777
- return;
1046
+ var processSSEEvent = function* (eventType, parsed, pendingCalls, providerName) {
1047
+ switch (eventType) {
1048
+ case "response.reasoning_summary_text.delta": {
1049
+ const delta = typeof parsed.delta === "string" ? parsed.delta : "";
1050
+ if (!delta)
1051
+ break;
1052
+ yield {
1053
+ content: delta,
1054
+ type: "thinking"
1055
+ };
1056
+ break;
1057
+ }
1058
+ case "response.output_text.delta":
1059
+ yield* processTextDelta(parsed);
1060
+ break;
1061
+ case "response.image_generation_call.partial_image":
1062
+ yield* processPartialImage(parsed);
1063
+ break;
1064
+ case "response.output_item.added":
1065
+ processOutputItemAdded(parsed, pendingCalls);
1066
+ break;
1067
+ case "response.output_item.done":
1068
+ yield* processOutputItemDone(parsed);
1069
+ break;
1070
+ case "response.function_call_arguments.delta":
1071
+ processFunctionCallArgumentsDelta(parsed, pendingCalls);
1072
+ break;
1073
+ case "response.function_call_arguments.done":
1074
+ yield* processFunctionCallArgumentsDone(parsed, pendingCalls);
1075
+ break;
1076
+ case "response.completed":
1077
+ yield* processCompleted(parsed);
1078
+ break;
1079
+ case "response.failed":
1080
+ case "response.incomplete":
1081
+ case "response.error":
1082
+ case "error":
1083
+ throw responseFailure(eventType, parsed, providerName);
778
1084
  }
779
- const [firstChoice] = choices;
780
- if (!firstChoice) {
1085
+ };
1086
+ var flushSSEBuffer = function* (state) {
1087
+ if (!state.currentEvent || !state.buffer) {
781
1088
  return;
782
1089
  }
783
- if (isRecord(firstChoice.error)) {
784
- const error = firstChoice.error;
785
- const metadata2 = isRecord(error.metadata) ? error.metadata : undefined;
786
- const status = typeof error.code === "number" ? error.code : null;
787
- throw new ProviderError({
788
- message: typeof error.message === "string" ? error.message : "OpenRouter stream failed",
789
- metadata: metadata2,
790
- provider: providerName,
791
- retryable: status === 429 || status !== null && status >= 500,
792
- status,
793
- type: metadata2 && typeof metadata2.error_type === "string" ? metadata2.error_type : null
794
- });
1090
+ const parsed = parseJSON(state.buffer);
1091
+ if (parsed) {
1092
+ yield* processSSEEvent(state.currentEvent, parsed, state.pendingCalls, state.providerName);
795
1093
  }
796
- yield* processChoice(firstChoice, pendingToolCalls);
1094
+ state.currentEvent = "";
1095
+ state.buffer = "";
797
1096
  };
798
- var isUsageUpdate = (chunk) => chunk.type === "usage_update";
799
- var collectYieldableChunks = (line, pendingToolCalls, usageRef, metadataRef, providerName) => {
800
- const allChunks = Array.from(processSSELine(line, pendingToolCalls, providerName));
801
- const usageChunks = allChunks.filter(isUsageUpdate);
802
- const lastUsage = usageChunks.at(NOT_FOUND);
803
- if (lastUsage) {
804
- usageRef.current = lastUsage.usage;
805
- }
806
- const metadataChunks = allChunks.filter((chunk) => chunk.type === "response_metadata");
807
- const lastMetadata = metadataChunks.at(NOT_FOUND);
808
- if (lastMetadata && "metadata" in lastMetadata) {
809
- metadataRef.current = {
810
- ...metadataRef.current,
811
- ...lastMetadata.metadata,
812
- providerMetadata: {
813
- ...metadataRef.current?.providerMetadata,
814
- ...lastMetadata.metadata.providerMetadata
815
- }
816
- };
1097
+ var parseSSELine = (trimmed, state) => {
1098
+ if (trimmed.startsWith("event: ")) {
1099
+ state.currentEvent = trimmed.slice(EVENT_PREFIX_LENGTH);
1100
+ } else if (trimmed.startsWith("data: ")) {
1101
+ state.buffer = trimmed.slice(DATA_PREFIX_LENGTH);
817
1102
  }
818
- return allChunks.filter((chunk) => !isUsageUpdate(chunk) && chunk.type !== "response_metadata");
819
1103
  };
820
- var processSSELines = function* (lines, pendingToolCalls, usageRef, metadataRef, providerName) {
821
- for (const line of lines) {
822
- yield* collectYieldableChunks(line, pendingToolCalls, usageRef, metadataRef, providerName);
1104
+ var processSSELine = function* (line, state) {
1105
+ const trimmed = line.trim();
1106
+ if (trimmed) {
1107
+ parseSSELine(trimmed, state);
1108
+ return;
823
1109
  }
1110
+ yield* flushSSEBuffer(state);
824
1111
  };
825
- var processStreamValue = (value, decoder, state) => {
826
- state.buffer += decoder.decode(value, { stream: true });
827
- const lines = state.buffer.split(`
828
- `);
829
- state.buffer = lines.pop() ?? "";
830
- return lines;
1112
+ var processSSELines = function* (lines, state) {
1113
+ for (const line of lines) {
1114
+ yield* processSSELine(line, state);
1115
+ }
831
1116
  };
832
1117
  var drainReader = async function* (reader, decoder, state, signal) {
1118
+ let textBuffer = "";
833
1119
  for (let result = await reader.read();!result.done && !signal?.aborted; result = await reader.read()) {
834
- const lines = processStreamValue(result.value, decoder, state);
835
- yield* processSSELines(lines, state.pendingToolCalls, state.usageRef, state.metadataRef, state.providerName);
1120
+ textBuffer += decoder.decode(result.value, { stream: true });
1121
+ const lines = textBuffer.split(`
1122
+ `);
1123
+ textBuffer = lines.pop() ?? "";
1124
+ yield* processSSELines(lines, state);
1125
+ }
1126
+ if (textBuffer.trim()) {
1127
+ yield* processSSELines([textBuffer, ""], state);
836
1128
  }
837
1129
  };
838
- var parseSSEStream = async function* (body, initialMetadata, providerName = "openai", signal) {
1130
+ var parseSSEStream = async function* (body, providerName, signal) {
839
1131
  const reader = body.getReader();
840
1132
  const decoder = new TextDecoder;
841
1133
  const state = {
842
1134
  buffer: "",
843
- metadataRef: { current: initialMetadata },
844
- pendingToolCalls: new Map,
845
- providerName,
846
- usageRef: { current: undefined }
1135
+ currentEvent: "",
1136
+ pendingCalls: new Map,
1137
+ usage: undefined,
1138
+ providerName
847
1139
  };
848
1140
  try {
849
1141
  yield* drainReader(reader, decoder, state, signal);
850
- yield {
851
- metadata: state.metadataRef.current,
852
- type: "done",
853
- usage: state.usageRef.current
854
- };
1142
+ yield* flushSSEBuffer(state);
855
1143
  } finally {
856
1144
  reader.releaseLock();
857
1145
  }
858
1146
  };
859
- var fetchOpenAIStream = async function* (baseUrl, apiKey, body, fetchImpl, headers, providerName, signal) {
860
- const target = `${baseUrl}/v1/chat/completions`;
1147
+ var fetchResponsesStream = async function* (baseUrl, apiKey, body, fetchImpl, headers, providerName, signal) {
1148
+ const target = `${baseUrl}/v1/responses`;
861
1149
  const requestHeaders = new Headers(headers);
862
1150
  requestHeaders.set("Authorization", `Bearer ${apiKey}`);
863
1151
  requestHeaders.set("Content-Type", "application/json");
@@ -874,67 +1162,133 @@ var fetchOpenAIStream = async function* (baseUrl, apiKey, body, fetchImpl, heade
874
1162
  }
875
1163
  if (!response.body) {
876
1164
  throw new ProviderError({
877
- message: `${providerName} API returned no response body`,
1165
+ message: `${providerName} Responses API returned no response body`,
878
1166
  provider: providerName,
879
1167
  retryable: true
880
1168
  });
881
1169
  }
882
- yield* parseSSEStream(response.body, {
883
- generationId: response.headers.get("X-Generation-Id") ?? undefined,
884
- providerMetadata: {
885
- cacheAge: response.headers.get("X-OpenRouter-Cache-Age") ?? undefined,
886
- cacheSourceId: response.headers.get("X-OpenRouter-Cache-Source-Id") ?? undefined,
887
- cacheStatus: response.headers.get("X-OpenRouter-Cache-Status") ?? undefined,
888
- cacheTtl: response.headers.get("X-OpenRouter-Cache-TTL") ?? undefined
889
- }
890
- }, providerName, signal);
1170
+ yield* parseSSEStream(response.body, providerName, signal);
891
1171
  };
892
- var openai = (config2) => {
1172
+ var resolveImageModels = (imageModels) => {
1173
+ if (!imageModels) {
1174
+ return new Set;
1175
+ }
1176
+ if (imageModels instanceof Set) {
1177
+ return imageModels;
1178
+ }
1179
+ return new Set(imageModels);
1180
+ };
1181
+ var openaiResponses = (config2) => {
1182
+ if (!config2.apiKey && !config2.tokenSource)
1183
+ throw new Error("openaiResponses() requires either apiKey or tokenSource");
893
1184
  const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL;
894
1185
  const fetchImpl = config2.fetch ?? globalThis.fetch;
895
- const providerName = config2.providerName ?? "openai";
896
- if (!config2.apiKey && !config2.tokenSource) {
897
- throw new Error("openai() requires either apiKey or tokenSource");
898
- }
899
- const resolveKey = async () => {
900
- if (config2.tokenSource) {
901
- return await Promise.resolve(config2.tokenSource());
902
- }
903
- return config2.apiKey;
904
- };
1186
+ const imageModels = resolveImageModels(config2.imageModels);
1187
+ const providerName = config2.providerName ?? "openai-responses";
1188
+ const resolveKey = async () => config2.tokenSource ? await Promise.resolve(config2.tokenSource()) : config2.apiKey;
905
1189
  const resolveHeaders = async (params) => typeof config2.headers === "function" ? await config2.headers(params) : config2.headers ?? {};
906
1190
  return instrumentAIProvider({
1191
+ inputCapacity: openaiInputCapacity({
1192
+ baseUrl,
1193
+ fetch: fetchImpl,
1194
+ key: resolveKey,
1195
+ headers: resolveHeaders,
1196
+ modelLimits: config2.modelLimits,
1197
+ body: (params) => {
1198
+ const built = buildResponsesRequestBody(params, imageModels.has(params.model), config2.modelForCapabilities?.(params.model) ?? params.model);
1199
+ return config2.transformRequestBody ? config2.transformRequestBody(built, params) : built;
1200
+ }
1201
+ }),
907
1202
  stream: (params) => {
908
- const openaiBody = buildRequestBody(params, config2.modelForCapabilities?.(params.model) ?? params.model);
909
- const body = config2.transformRequestBody ? config2.transformRequestBody(openaiBody, params) : openaiBody;
1203
+ const isImageModel = imageModels.has(params.model);
1204
+ const builtBody = buildResponsesRequestBody(params, isImageModel, config2.modelForCapabilities?.(params.model) ?? params.model);
1205
+ const body = config2.transformRequestBody ? config2.transformRequestBody(builtBody, params) : builtBody;
910
1206
  return async function* () {
911
1207
  const [apiKey, headers] = await Promise.all([
912
1208
  resolveKey(),
913
1209
  resolveHeaders(params)
914
1210
  ]);
915
- yield* fetchOpenAIStream(baseUrl, apiKey, body, fetchImpl, headers, providerName, params.signal);
1211
+ yield* fetchResponsesStream(baseUrl, apiKey, body, fetchImpl, headers, providerName, params.signal);
916
1212
  }();
917
1213
  }
918
1214
  }, providerName);
919
1215
  };
920
1216
 
921
- // src/ai/providers/openaiResponses.ts
1217
+ // src/ai/providers/openai.ts
922
1218
  var h2IfHttps2 = (url) => url.startsWith("https://") ? { protocol: "http2" } : {};
923
1219
  var DEFAULT_BASE_URL2 = "https://api.openai.com";
924
- var EVENT_PREFIX_LENGTH = 7;
925
- var DATA_PREFIX_LENGTH = 6;
1220
+ var SSE_DATA_PREFIX_LENGTH = 6;
1221
+ var DONE_SENTINEL = "[DONE]";
1222
+ var NOT_FOUND = -1;
926
1223
  var isRecord2 = (value) => typeof value === "object" && value !== null;
927
1224
  var isRecordArray2 = (value) => Array.isArray(value) && value.length > 0 && isRecord2(value[0]);
928
- var mapBlockToResponsesFormat = (block) => {
929
- if (block.type === "text") {
930
- return { text: block.content, type: "input_text" };
1225
+ var hasArrayContent = (msg) => typeof msg.content !== "string" && Array.isArray(msg.content);
1226
+ var buildToolMessages = (blocks) => {
1227
+ const toolUseBlocks = blocks.filter((block) => block.type === "tool_use");
1228
+ const toolResultBlocks = blocks.filter((block) => block.type === "tool_result");
1229
+ const messages = [];
1230
+ if (toolUseBlocks.length > 0) {
1231
+ messages.push({
1232
+ content: null,
1233
+ role: "assistant",
1234
+ tool_calls: toolUseBlocks.map((block) => ({
1235
+ function: {
1236
+ arguments: typeof block.input === "string" ? block.input : JSON.stringify(block.input),
1237
+ name: block.name
1238
+ },
1239
+ id: block.id,
1240
+ type: "function"
1241
+ }))
1242
+ });
1243
+ }
1244
+ for (const result of toolResultBlocks) {
1245
+ messages.push({
1246
+ content: typeof result.content === "string" ? result.content : "",
1247
+ role: "tool",
1248
+ tool_call_id: result.tool_use_id
1249
+ });
1250
+ }
1251
+ return messages;
1252
+ };
1253
+ var processMessageAtIndex = (result, msg, idx) => {
1254
+ if (!hasArrayContent(msg)) {
1255
+ return;
1256
+ }
1257
+ const hasToolBlocks2 = msg.content.some((block) => block.type === "tool_use" || block.type === "tool_result");
1258
+ if (!hasToolBlocks2) {
1259
+ return;
1260
+ }
1261
+ const toolMessages = buildToolMessages(msg.content);
1262
+ result.splice(idx, 1, ...toolMessages);
1263
+ };
1264
+ var convertSingleMessage = (result, msg, idx) => {
1265
+ if (!msg) {
1266
+ return;
931
1267
  }
1268
+ processMessageAtIndex(result, msg, idx);
1269
+ };
1270
+ var convertToolResultMessages = (messages, params) => {
1271
+ const result = [...messages];
1272
+ for (let idx = 0;idx < params.messages.length; idx++) {
1273
+ convertSingleMessage(result, params.messages[idx], idx);
1274
+ }
1275
+ return result;
1276
+ };
1277
+ var mapToolDefinitions = (tools) => tools.map((tool) => ({
1278
+ function: {
1279
+ description: tool.description,
1280
+ name: tool.name,
1281
+ parameters: tool.input_schema
1282
+ },
1283
+ type: "function"
1284
+ }));
1285
+ var mapContentBlockToOpenAI = (block) => {
932
1286
  if (block.type === "image") {
933
1287
  return {
934
1288
  image_url: {
935
1289
  url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
936
1290
  },
937
- type: "input_image"
1291
+ type: "image_url"
938
1292
  };
939
1293
  }
940
1294
  if (block.type === "document") {
@@ -943,7 +1297,7 @@ var mapBlockToResponsesFormat = (block) => {
943
1297
  file_data: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`,
944
1298
  filename: block.name ?? "document.pdf"
945
1299
  },
946
- type: "input_file"
1300
+ type: "file"
947
1301
  };
948
1302
  }
949
1303
  if (block.type === "audio") {
@@ -954,95 +1308,48 @@ var mapBlockToResponsesFormat = (block) => {
954
1308
  }
955
1309
  if (block.type === "video") {
956
1310
  return {
957
- type: "input_video",
958
- video_url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
959
- };
960
- }
961
- return null;
962
- };
963
- var mapContentToResponsesFormat = (content) => {
964
- if (typeof content === "string") {
965
- return content;
966
- }
967
- const parts = content.map(mapBlockToResponsesFormat).filter((mapped) => mapped !== null);
968
- return parts.length > 0 ? parts : "";
969
- };
970
- var hasToolBlocks = (content) => content.some((block) => block.type === "tool_use" || block.type === "tool_result");
971
- var convertToolBlock = (block) => {
972
- if (block.type === "provider_data" && block.provider === "openrouter") {
973
- return { ...block.data };
974
- }
975
- if (block.type === "tool_use") {
976
- if (block.providerData)
977
- return { ...block.providerData };
978
- return {
979
- arguments: typeof block.input === "string" ? block.input : JSON.stringify(block.input),
980
- call_id: block.id,
981
- name: block.name,
982
- type: "function_call"
1311
+ type: "video_url",
1312
+ video_url: {
1313
+ url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
1314
+ }
983
1315
  };
984
1316
  }
985
- if (block.type === "tool_result") {
986
- return {
987
- call_id: block.tool_use_id,
988
- output: typeof block.content === "string" ? block.content : "",
989
- type: "function_call_output"
990
- };
1317
+ if (block.type === "text") {
1318
+ return { text: block.content, type: "text" };
991
1319
  }
992
1320
  return null;
993
1321
  };
994
- var convertToolBlocks = (content) => content.map(convertToolBlock).filter((converted) => converted !== null);
995
- var convertMessage = (msg) => {
996
- if (typeof msg.content !== "string" && Array.isArray(msg.content) && hasToolBlocks(msg.content)) {
997
- return convertToolBlocks(msg.content);
1322
+ var mapOpenAIContent = (msg) => {
1323
+ if (typeof msg.content === "string") {
1324
+ return msg.content;
998
1325
  }
999
- const content = mapContentToResponsesFormat(msg.content);
1000
- return [
1001
- {
1002
- content,
1003
- role: msg.role === "system" ? "developer" : msg.role,
1004
- type: "message"
1005
- }
1006
- ];
1007
- };
1008
- var buildInput = (messages) => {
1009
- const input = [];
1010
- for (const msg of messages) {
1011
- input.push(...convertMessage(msg));
1326
+ const hasMedia = msg.content.some((block) => block.type === "image" || block.type === "document" || block.type === "audio" || block.type === "video");
1327
+ if (!hasMedia) {
1328
+ return null;
1012
1329
  }
1013
- return input;
1330
+ return msg.content.map(mapContentBlockToOpenAI).filter((mapped) => mapped !== null);
1014
1331
  };
1015
- var mapToolDefinition = (tool) => ({
1016
- description: tool.description,
1017
- name: tool.name,
1018
- parameters: tool.input_schema,
1019
- type: "function"
1020
- });
1021
- var buildTools = (tools, isImageModel) => {
1022
- const mapped = tools ? tools.map(mapToolDefinition) : [];
1023
- const result = [...mapped];
1024
- if (isImageModel) {
1025
- result.push({ type: "image_generation" });
1332
+ var buildRequestBody = (params, capabilityModel = params.model) => {
1333
+ const messages = convertToolResultMessages(params.messages.map((msg) => ({
1334
+ content: mapOpenAIContent(msg),
1335
+ role: msg.role
1336
+ })), params);
1337
+ if (params.systemPrompt) {
1338
+ messages.unshift({ content: params.systemPrompt, role: "system" });
1026
1339
  }
1027
- return result.length > 0 ? result : undefined;
1028
- };
1029
- var buildRequestBody2 = (params, isImageModel, capabilityModel = params.model) => {
1030
1340
  const body = {
1031
- input: buildInput(params.messages),
1341
+ messages,
1032
1342
  model: params.model,
1033
- stream: true
1343
+ stream: true,
1344
+ stream_options: { include_usage: true }
1034
1345
  };
1035
- if (params.systemPrompt) {
1036
- body.instructions = params.systemPrompt;
1037
- }
1038
- const tools = buildTools(params.tools, isImageModel);
1039
- if (tools) {
1040
- body.tools = tools;
1346
+ if (params.tools && params.tools.length > 0) {
1347
+ body.tools = mapToolDefinitions(params.tools);
1041
1348
  if (params.toolChoice === "auto" || params.toolChoice === "none" || params.toolChoice === "required") {
1042
1349
  body.tool_choice = params.toolChoice;
1043
1350
  } else if (params.toolChoice && typeof params.toolChoice === "object") {
1044
1351
  body.tool_choice = {
1045
- name: params.toolChoice.name,
1352
+ function: { name: params.toolChoice.name },
1046
1353
  type: "function"
1047
1354
  };
1048
1355
  }
@@ -1050,12 +1357,24 @@ var buildRequestBody2 = (params, isImageModel, capabilityModel = params.model) =
1050
1357
  body.parallel_tool_calls = params.parallelToolCalls;
1051
1358
  }
1052
1359
  }
1053
- if (typeof params.temperature === "number")
1054
- body.temperature = params.temperature;
1055
- if (typeof params.topP === "number")
1056
- body.top_p = params.topP;
1057
- if (typeof params.maxTokens === "number")
1058
- body.max_output_tokens = params.maxTokens;
1360
+ if (isOpenAIReasoningModel(capabilityModel)) {
1361
+ if (typeof params.maxTokens === "number") {
1362
+ body.max_completion_tokens = params.maxTokens;
1363
+ }
1364
+ if (params.reasoning) {
1365
+ const effort = openaiEffortValue(capabilityModel, params.reasoning);
1366
+ if (effort)
1367
+ body.reasoning_effort = effort;
1368
+ }
1369
+ } else {
1370
+ if (typeof params.temperature === "number") {
1371
+ body.temperature = params.temperature;
1372
+ }
1373
+ if (typeof params.topP === "number")
1374
+ body.top_p = params.topP;
1375
+ if (typeof params.maxTokens === "number")
1376
+ body.max_tokens = params.maxTokens;
1377
+ }
1059
1378
  if (params.stopSequences && params.stopSequences.length > 0)
1060
1379
  body.stop = params.stopSequences;
1061
1380
  if (typeof params.seed === "number")
@@ -1066,36 +1385,20 @@ var buildRequestBody2 = (params, isImageModel, capabilityModel = params.model) =
1066
1385
  body.presence_penalty = params.presencePenalty;
1067
1386
  if (params.responseFormat) {
1068
1387
  if (params.responseFormat.type === "text" || params.responseFormat.type === "json_object") {
1069
- body.text = { format: { type: params.responseFormat.type } };
1388
+ body.response_format = { type: params.responseFormat.type };
1070
1389
  } else if (params.responseFormat.type === "json_schema") {
1071
- body.text = {
1072
- format: {
1390
+ body.response_format = {
1391
+ json_schema: {
1073
1392
  name: params.responseFormat.name,
1074
1393
  schema: params.responseFormat.schema,
1075
- strict: params.responseFormat.strict ?? true,
1076
- type: "json_schema"
1077
- }
1078
- };
1079
- }
1080
- }
1081
- if (params.reasoning && isOpenAIReasoningModel(capabilityModel)) {
1082
- const effort = openaiEffortValue(capabilityModel, params.reasoning);
1083
- if (effort) {
1084
- body.reasoning = {
1085
- effort,
1086
- summary: "auto"
1394
+ strict: params.responseFormat.strict ?? true
1395
+ },
1396
+ type: "json_schema"
1087
1397
  };
1088
1398
  }
1089
1399
  }
1090
1400
  return body;
1091
1401
  };
1092
- var parseJSON = (data) => {
1093
- try {
1094
- return JSON.parse(data);
1095
- } catch {
1096
- return null;
1097
- }
1098
- };
1099
1402
  var parseToolInput2 = (rawArguments) => {
1100
1403
  try {
1101
1404
  return JSON.parse(rawArguments);
@@ -1103,297 +1406,284 @@ var parseToolInput2 = (rawArguments) => {
1103
1406
  return rawArguments;
1104
1407
  }
1105
1408
  };
1106
- var extractUsage2 = (response) => {
1107
- if (!isRecord2(response.usage)) {
1108
- return;
1409
+ var flushPendingToolCalls = function* (pendingToolCalls) {
1410
+ for (const [, tool] of pendingToolCalls) {
1411
+ const input = parseToolInput2(tool.arguments);
1412
+ yield {
1413
+ id: tool.id,
1414
+ input,
1415
+ name: tool.name,
1416
+ type: "tool_use"
1417
+ };
1109
1418
  }
1110
- const { usage } = response;
1111
- const input = typeof usage.input_tokens === "number" ? usage.input_tokens : 0;
1112
- const cached = isRecord2(usage.input_tokens_details) && typeof usage.input_tokens_details.cached_tokens === "number" ? usage.input_tokens_details.cached_tokens : 0;
1113
- const outputDetails = isRecord2(usage.output_tokens_details) ? usage.output_tokens_details : undefined;
1114
- const inputDetails = isRecord2(usage.input_tokens_details) ? usage.input_tokens_details : undefined;
1115
- const costDetails = isRecord2(usage.cost_details) ? usage.cost_details : undefined;
1116
- const normalized = {
1419
+ pendingToolCalls.clear();
1420
+ };
1421
+ var extractUsage2 = (parsedUsage) => {
1422
+ const prompt = parsedUsage.prompt_tokens ?? 0;
1423
+ const cached = parsedUsage.cached_tokens ?? 0;
1424
+ return {
1117
1425
  cacheReadInputTokens: cached,
1118
- cacheWriteInputTokens: inputDetails && typeof inputDetails.cache_write_tokens === "number" ? inputDetails.cache_write_tokens : undefined,
1119
- costCredits: typeof usage.cost === "number" ? usage.cost : undefined,
1120
- inputTokens: Math.max(0, input - cached),
1121
- outputTokens: typeof usage.output_tokens === "number" ? usage.output_tokens : 0,
1122
- reasoningTokens: outputDetails && typeof outputDetails.reasoning_tokens === "number" ? outputDetails.reasoning_tokens : undefined,
1123
- upstreamInferenceCostCredits: costDetails && typeof costDetails.upstream_inference_cost === "number" ? costDetails.upstream_inference_cost : undefined
1426
+ cacheWriteInputTokens: parsedUsage.cache_write_tokens || undefined,
1427
+ costCredits: parsedUsage.cost,
1428
+ inputTokens: Math.max(0, prompt - cached),
1429
+ outputTokens: parsedUsage.completion_tokens ?? 0,
1430
+ reasoningTokens: parsedUsage.reasoning_tokens || undefined,
1431
+ upstreamInferenceCostCredits: parsedUsage.upstream_inference_cost || undefined
1124
1432
  };
1125
- if (isRecord2(usage.server_tool_use)) {
1126
- normalized.serverToolUse = Object.fromEntries(Object.entries(usage.server_tool_use).filter((entry) => typeof entry[1] === "number"));
1127
- }
1128
- return normalized;
1129
1433
  };
1130
- var extractResponseMetadata = (response) => {
1131
- const providerMetadata = isRecord2(response.openrouter_metadata) ? response.openrouter_metadata : undefined;
1132
- const generationId = typeof response.id === "string" ? response.id : undefined;
1133
- const model = typeof response.model === "string" ? response.model : undefined;
1134
- const provider = typeof response.provider === "string" ? response.provider : undefined;
1135
- const serviceTier = typeof response.service_tier === "string" ? response.service_tier : undefined;
1136
- if (!providerMetadata && !generationId && !model && !provider && !serviceTier)
1137
- return;
1138
- return { generationId, model, provider, providerMetadata, serviceTier };
1434
+ var resolveToolCallIndex = (toolCall) => {
1435
+ const raw = typeof toolCall.index === "number" ? toolCall.index : NOT_FOUND;
1436
+ return raw < 0 ? undefined : raw;
1139
1437
  };
1140
- var extractMimeFormat = (mimeType) => {
1141
- if (typeof mimeType !== "string") {
1142
- return "png";
1438
+ var initPendingToolCall = (toolCall, func, index, pendingToolCalls) => {
1439
+ if (pendingToolCalls.has(index)) {
1440
+ return;
1143
1441
  }
1144
- if (mimeType.includes("jpeg"))
1145
- return "jpeg";
1146
- if (mimeType.includes("webp"))
1147
- return "webp";
1148
- return "png";
1442
+ const toolId = typeof toolCall.id === "string" ? toolCall.id : "";
1443
+ const toolName = func && typeof func.name === "string" ? func.name : "";
1444
+ pendingToolCalls.set(index, {
1445
+ arguments: "",
1446
+ id: toolId,
1447
+ name: toolName
1448
+ });
1149
1449
  };
1150
- var processTextDelta = function* (parsed) {
1151
- if (typeof parsed.delta === "string") {
1152
- yield { content: parsed.delta, type: "text" };
1450
+ var updatePendingToolCall = (toolCall, func, pending) => {
1451
+ if (typeof toolCall.id === "string") {
1452
+ pending.id = toolCall.id;
1153
1453
  }
1154
- };
1155
- var processPartialImage = function* (parsed) {
1156
- const itemId = typeof parsed.item_id === "string" ? parsed.item_id : undefined;
1157
- const b64 = typeof parsed.partial_image_b64 === "string" ? parsed.partial_image_b64 : undefined;
1158
- if (b64) {
1159
- yield {
1160
- data: b64,
1161
- format: "png",
1162
- imageId: itemId,
1163
- isPartial: true,
1164
- type: "image"
1165
- };
1454
+ if (func && typeof func.name === "string") {
1455
+ pending.name = func.name;
1166
1456
  }
1167
- };
1168
- var processFunctionCallArgumentsDelta = (parsed, pendingCalls) => {
1169
- const itemId = typeof parsed.item_id === "string" ? parsed.item_id : "";
1170
- const callId = typeof parsed.call_id === "string" ? parsed.call_id : "";
1171
- const delta = typeof parsed.arguments_delta === "string" ? parsed.arguments_delta : "";
1172
- const existing = pendingCalls.get(itemId);
1173
- if (existing) {
1174
- existing.arguments += delta;
1175
- } else {
1176
- pendingCalls.set(itemId, {
1177
- arguments: delta,
1178
- callId,
1179
- name: ""
1180
- });
1457
+ if (func && typeof func.arguments === "string") {
1458
+ pending.arguments += func.arguments;
1181
1459
  }
1182
1460
  };
1183
- var processFunctionCallArgumentsDone = function* (parsed, pendingCalls) {
1184
- const itemId = typeof parsed.item_id === "string" ? parsed.item_id : "";
1185
- const callId = typeof parsed.call_id === "string" ? parsed.call_id : "";
1186
- const fullArgs = typeof parsed.arguments === "string" ? parsed.arguments : "";
1187
- const pending = pendingCalls.get(itemId);
1188
- const name = pending?.name ?? "";
1189
- const args = fullArgs || pending?.arguments || "";
1190
- pendingCalls.delete(itemId);
1191
- yield {
1192
- id: callId || pending?.callId || itemId,
1193
- input: parseToolInput2(args),
1194
- name,
1195
- providerData: pending?.providerData ? { ...pending.providerData, arguments: args } : undefined,
1196
- type: "tool_use"
1197
- };
1198
- };
1199
- var processOutputItemAdded = (parsed, pendingCalls) => {
1200
- if (!isRecord2(parsed.item)) {
1461
+ var processToolCallDelta = (toolCall, pendingToolCalls) => {
1462
+ const index = resolveToolCallIndex(toolCall);
1463
+ if (index === undefined) {
1201
1464
  return;
1202
1465
  }
1203
- const { item } = parsed;
1204
- const itemId = typeof item.id === "string" ? item.id : "";
1205
- const itemType = typeof item.type === "string" ? item.type : "";
1206
- if (itemType !== "function_call") {
1466
+ const func = isRecord2(toolCall.function) ? toolCall.function : null;
1467
+ initPendingToolCall(toolCall, func, index, pendingToolCalls);
1468
+ const pending = pendingToolCalls.get(index);
1469
+ if (!pending) {
1207
1470
  return;
1208
1471
  }
1209
- const callId = typeof item.call_id === "string" ? item.call_id : "";
1210
- const name = typeof item.name === "string" ? item.name : "";
1211
- pendingCalls.set(itemId, {
1212
- arguments: "",
1213
- callId,
1214
- name,
1215
- providerData: { ...item }
1216
- });
1217
- };
1218
- var processOutputItemDone = function* (parsed) {
1219
- if (!isRecord2(parsed.item) || typeof parsed.item.type !== "string")
1220
- return;
1221
- if (!parsed.item.type.startsWith("openrouter:"))
1222
- return;
1223
- yield {
1224
- data: { ...parsed.item },
1225
- provider: "openrouter",
1226
- type: "provider_event"
1227
- };
1472
+ updatePendingToolCall(toolCall, func, pending);
1228
1473
  };
1229
- var isCompletedImageGeneration = (item) => item.type === "image_generation_call" && item.status === "completed" && typeof item.result === "string" && item.result !== "";
1230
- var buildImageChunk = (item) => ({
1231
- data: typeof item.result === "string" ? item.result : "",
1232
- format: extractMimeFormat(item.output_format),
1233
- imageId: typeof item.id === "string" ? item.id : undefined,
1234
- isPartial: false,
1235
- revisedPrompt: typeof item.revised_prompt === "string" ? item.revised_prompt : undefined,
1236
- type: "image"
1237
- });
1238
- var extractImageFromOutput = function* (output) {
1239
- const completedImages = output.filter(isCompletedImageGeneration);
1240
- for (const item of completedImages) {
1241
- yield buildImageChunk(item);
1474
+ var processToolCallDeltas = (toolCalls, pendingToolCalls) => {
1475
+ for (const toolCall of toolCalls) {
1476
+ processToolCallDelta(toolCall, pendingToolCalls);
1242
1477
  }
1243
1478
  };
1244
- var extractCitationsFromOutput = function* (output) {
1245
- for (const item of output) {
1246
- if (!isRecordArray2(item.content))
1247
- continue;
1248
- for (const content of item.content) {
1249
- if (!Array.isArray(content.annotations))
1479
+ var processDelta = function* (delta, pendingToolCalls) {
1480
+ if (typeof delta.content === "string") {
1481
+ yield { content: delta.content, type: "text" };
1482
+ }
1483
+ if (isRecord2(delta.audio)) {
1484
+ const audio = delta.audio;
1485
+ if (typeof audio.data === "string" || typeof audio.transcript === "string") {
1486
+ yield {
1487
+ audioId: typeof audio.id === "string" ? audio.id : undefined,
1488
+ data: typeof audio.data === "string" ? audio.data : "",
1489
+ format: typeof audio.format === "string" ? audio.format : "pcm16",
1490
+ transcript: typeof audio.transcript === "string" ? audio.transcript : undefined,
1491
+ type: "audio"
1492
+ };
1493
+ }
1494
+ }
1495
+ if (isRecordArray2(delta.tool_calls)) {
1496
+ processToolCallDeltas(delta.tool_calls, pendingToolCalls);
1497
+ }
1498
+ if (Array.isArray(delta.annotations)) {
1499
+ for (const annotation of delta.annotations) {
1500
+ if (!isRecord2(annotation) || annotation.type !== "url_citation")
1250
1501
  continue;
1251
- for (const annotation of content.annotations) {
1252
- if (!isRecord2(annotation) || annotation.type !== "url_citation")
1253
- continue;
1254
- if (typeof annotation.url !== "string")
1255
- continue;
1256
- yield {
1257
- content: typeof annotation.content === "string" ? annotation.content : undefined,
1258
- endIndex: typeof annotation.end_index === "number" ? annotation.end_index : undefined,
1259
- startIndex: typeof annotation.start_index === "number" ? annotation.start_index : undefined,
1260
- title: typeof annotation.title === "string" ? annotation.title : undefined,
1261
- type: "citation",
1262
- url: annotation.url
1263
- };
1264
- }
1502
+ const citation = isRecord2(annotation.url_citation) ? annotation.url_citation : annotation;
1503
+ if (typeof citation.url !== "string")
1504
+ continue;
1505
+ yield {
1506
+ content: typeof citation.content === "string" ? citation.content : undefined,
1507
+ endIndex: typeof citation.end_index === "number" ? citation.end_index : undefined,
1508
+ startIndex: typeof citation.start_index === "number" ? citation.start_index : undefined,
1509
+ title: typeof citation.title === "string" ? citation.title : undefined,
1510
+ type: "citation",
1511
+ url: citation.url
1512
+ };
1265
1513
  }
1266
1514
  }
1267
1515
  };
1268
- var processCompleted = function* (parsed) {
1269
- if (!isRecord2(parsed.response)) {
1270
- yield { type: "done", usage: undefined };
1516
+ var narrowResponseMetadata = (parsed) => {
1517
+ const providerMetadata = isRecord2(parsed.openrouter_metadata) ? parsed.openrouter_metadata : undefined;
1518
+ const generationId = typeof parsed.id === "string" ? parsed.id : undefined;
1519
+ const model = typeof parsed.model === "string" ? parsed.model : undefined;
1520
+ const serviceTier = typeof parsed.service_tier === "string" ? parsed.service_tier : undefined;
1521
+ const selected = providerMetadata && isRecord2(providerMetadata.endpoints) ? providerMetadata.endpoints.available : undefined;
1522
+ const selectedEndpoint = Array.isArray(selected) ? selected.find((entry) => isRecord2(entry) && entry.selected === true) : undefined;
1523
+ const provider = isRecord2(selectedEndpoint) && typeof selectedEndpoint.provider === "string" ? selectedEndpoint.provider : undefined;
1524
+ if (!providerMetadata && !generationId && !model && !serviceTier)
1271
1525
  return;
1526
+ return { generationId, model, provider, providerMetadata, serviceTier };
1527
+ };
1528
+ var processChoice = function* (choice, pendingToolCalls) {
1529
+ const delta = isRecord2(choice.delta) ? choice.delta : null;
1530
+ if (delta) {
1531
+ yield* processDelta(delta, pendingToolCalls);
1272
1532
  }
1273
- const { response } = parsed;
1274
- const usage = extractUsage2(response);
1275
- const metadata = extractResponseMetadata(response);
1276
- if (isRecordArray2(response.output)) {
1277
- yield* extractCitationsFromOutput(response.output);
1278
- yield* extractImageFromOutput(response.output);
1533
+ if (choice.finish_reason === "tool_calls") {
1534
+ yield* flushPendingToolCalls(pendingToolCalls);
1279
1535
  }
1280
- yield { metadata, type: "done", usage };
1281
1536
  };
1282
- var responseFailure = (eventType, parsed, providerName) => {
1283
- const response = isRecord2(parsed.response) ? parsed.response : parsed;
1284
- const error = isRecord2(response.error) ? response.error : undefined;
1285
- const type = typeof response.error_type === "string" ? response.error_type : error && typeof error.code === "string" ? error.code : eventType;
1286
- return new ProviderError({
1287
- message: error && typeof error.message === "string" ? error.message : `OpenRouter Responses API: ${eventType}`,
1288
- metadata: response,
1289
- provider: providerName,
1290
- retryable: type === "rate_limit_exceeded" || type === "provider_overloaded" || type === "provider_unavailable" || type === "server",
1291
- type
1537
+ var narrowUsageRecord = (parsed) => {
1538
+ if (!isRecord2(parsed.usage)) {
1539
+ return;
1540
+ }
1541
+ const { usage } = parsed;
1542
+ const promptTokens = typeof usage.prompt_tokens === "number" ? usage.prompt_tokens : 0;
1543
+ const completionTokens = typeof usage.completion_tokens === "number" ? usage.completion_tokens : 0;
1544
+ const cachedTokens = isRecord2(usage.prompt_tokens_details) && typeof usage.prompt_tokens_details.cached_tokens === "number" ? usage.prompt_tokens_details.cached_tokens : 0;
1545
+ const cacheWriteTokens = isRecord2(usage.prompt_tokens_details) && typeof usage.prompt_tokens_details.cache_write_tokens === "number" ? usage.prompt_tokens_details.cache_write_tokens : 0;
1546
+ const reasoningTokens = isRecord2(usage.completion_tokens_details) && typeof usage.completion_tokens_details.reasoning_tokens === "number" ? usage.completion_tokens_details.reasoning_tokens : 0;
1547
+ const cost = typeof usage.cost === "number" ? usage.cost : undefined;
1548
+ const upstreamInferenceCost = isRecord2(usage.cost_details) && typeof usage.cost_details.upstream_inference_cost === "number" ? usage.cost_details.upstream_inference_cost : undefined;
1549
+ const normalized = extractUsage2({
1550
+ cache_write_tokens: cacheWriteTokens,
1551
+ cached_tokens: cachedTokens,
1552
+ completion_tokens: completionTokens,
1553
+ cost,
1554
+ prompt_tokens: promptTokens,
1555
+ reasoning_tokens: reasoningTokens,
1556
+ upstream_inference_cost: upstreamInferenceCost
1292
1557
  });
1293
- };
1294
- var processSSEEvent = function* (eventType, parsed, pendingCalls, providerName) {
1295
- switch (eventType) {
1296
- case "response.reasoning_summary_text.delta": {
1297
- const delta = typeof parsed.delta === "string" ? parsed.delta : "";
1298
- if (!delta)
1299
- break;
1300
- yield {
1301
- content: delta,
1302
- type: "thinking"
1303
- };
1304
- break;
1305
- }
1306
- case "response.output_text.delta":
1307
- yield* processTextDelta(parsed);
1308
- break;
1309
- case "response.image_generation_call.partial_image":
1310
- yield* processPartialImage(parsed);
1311
- break;
1312
- case "response.output_item.added":
1313
- processOutputItemAdded(parsed, pendingCalls);
1314
- break;
1315
- case "response.output_item.done":
1316
- yield* processOutputItemDone(parsed);
1317
- break;
1318
- case "response.function_call_arguments.delta":
1319
- processFunctionCallArgumentsDelta(parsed, pendingCalls);
1320
- break;
1321
- case "response.function_call_arguments.done":
1322
- yield* processFunctionCallArgumentsDone(parsed, pendingCalls);
1323
- break;
1324
- case "response.completed":
1325
- yield* processCompleted(parsed);
1326
- break;
1327
- case "response.failed":
1328
- case "response.incomplete":
1329
- case "response.error":
1330
- case "error":
1331
- throw responseFailure(eventType, parsed, providerName);
1558
+ if (isRecord2(usage.server_tool_use)) {
1559
+ normalized.serverToolUse = Object.fromEntries(Object.entries(usage.server_tool_use).filter((entry) => typeof entry[1] === "number"));
1332
1560
  }
1561
+ return normalized;
1333
1562
  };
1334
- var flushSSEBuffer = function* (state) {
1335
- if (!state.currentEvent || !state.buffer) {
1563
+ var processSSELine2 = function* (line, pendingToolCalls, providerName) {
1564
+ const trimmed = line.trim();
1565
+ if (!trimmed || !trimmed.startsWith("data: ")) {
1336
1566
  return;
1337
1567
  }
1338
- const parsed = parseJSON(state.buffer);
1339
- if (parsed) {
1340
- yield* processSSEEvent(state.currentEvent, parsed, state.pendingCalls, state.providerName);
1568
+ const data = trimmed.slice(SSE_DATA_PREFIX_LENGTH);
1569
+ if (data === DONE_SENTINEL) {
1570
+ yield* flushPendingToolCalls(pendingToolCalls);
1571
+ return;
1341
1572
  }
1342
- state.currentEvent = "";
1343
- state.buffer = "";
1344
- };
1345
- var parseSSELine = (trimmed, state) => {
1346
- if (trimmed.startsWith("event: ")) {
1347
- state.currentEvent = trimmed.slice(EVENT_PREFIX_LENGTH);
1348
- } else if (trimmed.startsWith("data: ")) {
1349
- state.buffer = trimmed.slice(DATA_PREFIX_LENGTH);
1573
+ let parsed;
1574
+ try {
1575
+ parsed = JSON.parse(data);
1576
+ } catch {
1577
+ return;
1350
1578
  }
1351
- };
1352
- var processSSELine2 = function* (line, state) {
1353
- const trimmed = line.trim();
1354
- if (trimmed) {
1355
- parseSSELine(trimmed, state);
1579
+ if (isRecord2(parsed.error)) {
1580
+ const error = parsed.error;
1581
+ const metadata2 = isRecord2(error.metadata) ? error.metadata : undefined;
1582
+ const status = typeof error.code === "number" ? error.code : null;
1583
+ const type = metadata2 && typeof metadata2.error_type === "string" ? metadata2.error_type : typeof error.error_type === "string" ? error.error_type : null;
1584
+ throw new ProviderError({
1585
+ message: typeof error.message === "string" ? error.message : "OpenRouter stream failed",
1586
+ metadata: metadata2,
1587
+ provider: providerName,
1588
+ retryable: status === 408 || status === 409 || status === 425 || status === 429 || status !== null && status >= 500,
1589
+ status,
1590
+ type
1591
+ });
1592
+ }
1593
+ const usageUpdate = narrowUsageRecord(parsed);
1594
+ if (usageUpdate) {
1595
+ yield { type: "usage_update", usage: usageUpdate };
1596
+ }
1597
+ const metadata = narrowResponseMetadata(parsed);
1598
+ if (metadata) {
1599
+ yield { metadata, type: "response_metadata" };
1600
+ }
1601
+ const { choices } = parsed;
1602
+ if (!isRecordArray2(choices)) {
1356
1603
  return;
1357
1604
  }
1358
- yield* flushSSEBuffer(state);
1605
+ const [firstChoice] = choices;
1606
+ if (!firstChoice) {
1607
+ return;
1608
+ }
1609
+ if (isRecord2(firstChoice.error)) {
1610
+ const error = firstChoice.error;
1611
+ const metadata2 = isRecord2(error.metadata) ? error.metadata : undefined;
1612
+ const status = typeof error.code === "number" ? error.code : null;
1613
+ throw new ProviderError({
1614
+ message: typeof error.message === "string" ? error.message : "OpenRouter stream failed",
1615
+ metadata: metadata2,
1616
+ provider: providerName,
1617
+ retryable: status === 429 || status !== null && status >= 500,
1618
+ status,
1619
+ type: metadata2 && typeof metadata2.error_type === "string" ? metadata2.error_type : null
1620
+ });
1621
+ }
1622
+ yield* processChoice(firstChoice, pendingToolCalls);
1623
+ };
1624
+ var isUsageUpdate = (chunk) => chunk.type === "usage_update";
1625
+ var collectYieldableChunks = (line, pendingToolCalls, usageRef, metadataRef, providerName) => {
1626
+ const allChunks = Array.from(processSSELine2(line, pendingToolCalls, providerName));
1627
+ const usageChunks = allChunks.filter(isUsageUpdate);
1628
+ const lastUsage = usageChunks.at(NOT_FOUND);
1629
+ if (lastUsage) {
1630
+ usageRef.current = lastUsage.usage;
1631
+ }
1632
+ const metadataChunks = allChunks.filter((chunk) => chunk.type === "response_metadata");
1633
+ const lastMetadata = metadataChunks.at(NOT_FOUND);
1634
+ if (lastMetadata && "metadata" in lastMetadata) {
1635
+ metadataRef.current = {
1636
+ ...metadataRef.current,
1637
+ ...lastMetadata.metadata,
1638
+ providerMetadata: {
1639
+ ...metadataRef.current?.providerMetadata,
1640
+ ...lastMetadata.metadata.providerMetadata
1641
+ }
1642
+ };
1643
+ }
1644
+ return allChunks.filter((chunk) => !isUsageUpdate(chunk) && chunk.type !== "response_metadata");
1359
1645
  };
1360
- var processSSELines2 = function* (lines, state) {
1646
+ var processSSELines2 = function* (lines, pendingToolCalls, usageRef, metadataRef, providerName) {
1361
1647
  for (const line of lines) {
1362
- yield* processSSELine2(line, state);
1648
+ yield* collectYieldableChunks(line, pendingToolCalls, usageRef, metadataRef, providerName);
1363
1649
  }
1364
1650
  };
1651
+ var processStreamValue = (value, decoder, state) => {
1652
+ state.buffer += decoder.decode(value, { stream: true });
1653
+ const lines = state.buffer.split(`
1654
+ `);
1655
+ state.buffer = lines.pop() ?? "";
1656
+ return lines;
1657
+ };
1365
1658
  var drainReader2 = async function* (reader, decoder, state, signal) {
1366
- let textBuffer = "";
1367
1659
  for (let result = await reader.read();!result.done && !signal?.aborted; result = await reader.read()) {
1368
- textBuffer += decoder.decode(result.value, { stream: true });
1369
- const lines = textBuffer.split(`
1370
- `);
1371
- textBuffer = lines.pop() ?? "";
1372
- yield* processSSELines2(lines, state);
1373
- }
1374
- if (textBuffer.trim()) {
1375
- yield* processSSELines2([textBuffer, ""], state);
1660
+ const lines = processStreamValue(result.value, decoder, state);
1661
+ yield* processSSELines2(lines, state.pendingToolCalls, state.usageRef, state.metadataRef, state.providerName);
1376
1662
  }
1377
1663
  };
1378
- var parseSSEStream2 = async function* (body, providerName, signal) {
1664
+ var parseSSEStream2 = async function* (body, initialMetadata, providerName = "openai", signal) {
1379
1665
  const reader = body.getReader();
1380
1666
  const decoder = new TextDecoder;
1381
1667
  const state = {
1382
1668
  buffer: "",
1383
- currentEvent: "",
1384
- pendingCalls: new Map,
1385
- usage: undefined,
1386
- providerName
1669
+ metadataRef: { current: initialMetadata },
1670
+ pendingToolCalls: new Map,
1671
+ providerName,
1672
+ usageRef: { current: undefined }
1387
1673
  };
1388
1674
  try {
1389
1675
  yield* drainReader2(reader, decoder, state, signal);
1390
- yield* flushSSEBuffer(state);
1676
+ yield {
1677
+ metadata: state.metadataRef.current,
1678
+ type: "done",
1679
+ usage: state.usageRef.current
1680
+ };
1391
1681
  } finally {
1392
1682
  reader.releaseLock();
1393
1683
  }
1394
1684
  };
1395
- var fetchResponsesStream = async function* (baseUrl, apiKey, body, fetchImpl, headers, providerName, signal) {
1396
- const target = `${baseUrl}/v1/responses`;
1685
+ var fetchOpenAIStream = async function* (baseUrl, apiKey, body, fetchImpl, headers, providerName, signal) {
1686
+ const target = `${baseUrl}/v1/chat/completions`;
1397
1687
  const requestHeaders = new Headers(headers);
1398
1688
  requestHeaders.set("Authorization", `Bearer ${apiKey}`);
1399
1689
  requestHeaders.set("Content-Type", "application/json");
@@ -1410,42 +1700,53 @@ var fetchResponsesStream = async function* (baseUrl, apiKey, body, fetchImpl, he
1410
1700
  }
1411
1701
  if (!response.body) {
1412
1702
  throw new ProviderError({
1413
- message: `${providerName} Responses API returned no response body`,
1703
+ message: `${providerName} API returned no response body`,
1414
1704
  provider: providerName,
1415
1705
  retryable: true
1416
1706
  });
1417
1707
  }
1418
- yield* parseSSEStream2(response.body, providerName, signal);
1419
- };
1420
- var resolveImageModels = (imageModels) => {
1421
- if (!imageModels) {
1422
- return new Set;
1423
- }
1424
- if (imageModels instanceof Set) {
1425
- return imageModels;
1426
- }
1427
- return new Set(imageModels);
1708
+ yield* parseSSEStream2(response.body, {
1709
+ generationId: response.headers.get("X-Generation-Id") ?? undefined,
1710
+ providerMetadata: {
1711
+ cacheAge: response.headers.get("X-OpenRouter-Cache-Age") ?? undefined,
1712
+ cacheSourceId: response.headers.get("X-OpenRouter-Cache-Source-Id") ?? undefined,
1713
+ cacheStatus: response.headers.get("X-OpenRouter-Cache-Status") ?? undefined,
1714
+ cacheTtl: response.headers.get("X-OpenRouter-Cache-TTL") ?? undefined
1715
+ }
1716
+ }, providerName, signal);
1428
1717
  };
1429
- var openaiResponses = (config2) => {
1430
- if (!config2.apiKey && !config2.tokenSource)
1431
- throw new Error("openaiResponses() requires either apiKey or tokenSource");
1718
+ var openai = (config2) => {
1432
1719
  const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL2;
1433
1720
  const fetchImpl = config2.fetch ?? globalThis.fetch;
1434
- const imageModels = resolveImageModels(config2.imageModels);
1435
- const providerName = config2.providerName ?? "openai-responses";
1436
- const resolveKey = async () => config2.tokenSource ? await Promise.resolve(config2.tokenSource()) : config2.apiKey;
1721
+ const providerName = config2.providerName ?? "openai";
1722
+ if (!config2.apiKey && !config2.tokenSource) {
1723
+ throw new Error("openai() requires either apiKey or tokenSource");
1724
+ }
1725
+ const resolveKey = async () => {
1726
+ if (config2.tokenSource) {
1727
+ return await Promise.resolve(config2.tokenSource());
1728
+ }
1729
+ return config2.apiKey;
1730
+ };
1437
1731
  const resolveHeaders = async (params) => typeof config2.headers === "function" ? await config2.headers(params) : config2.headers ?? {};
1438
1732
  return instrumentAIProvider({
1733
+ inputCapacity: config2.transformRequestBody ? undefined : openaiInputCapacity({
1734
+ baseUrl,
1735
+ fetch: fetchImpl,
1736
+ key: resolveKey,
1737
+ headers: resolveHeaders,
1738
+ modelLimits: config2.modelLimits,
1739
+ body: (params) => buildResponsesRequestBody(params, false, config2.modelForCapabilities?.(params.model) ?? params.model)
1740
+ }),
1439
1741
  stream: (params) => {
1440
- const isImageModel = imageModels.has(params.model);
1441
- const builtBody = buildRequestBody2(params, isImageModel, config2.modelForCapabilities?.(params.model) ?? params.model);
1442
- const body = config2.transformRequestBody ? config2.transformRequestBody(builtBody, params) : builtBody;
1742
+ const openaiBody = buildRequestBody(params, config2.modelForCapabilities?.(params.model) ?? params.model);
1743
+ const body = config2.transformRequestBody ? config2.transformRequestBody(openaiBody, params) : openaiBody;
1443
1744
  return async function* () {
1444
1745
  const [apiKey, headers] = await Promise.all([
1445
1746
  resolveKey(),
1446
1747
  resolveHeaders(params)
1447
1748
  ]);
1448
- yield* fetchResponsesStream(baseUrl, apiKey, body, fetchImpl, headers, providerName, params.signal);
1749
+ yield* fetchOpenAIStream(baseUrl, apiKey, body, fetchImpl, headers, providerName, params.signal);
1449
1750
  }();
1450
1751
  }
1451
1752
  }, providerName);
@@ -1588,7 +1889,7 @@ var cacheLastContentBlock = (msg) => {
1588
1889
  };
1589
1890
  return { content: blocks, role: msg.role };
1590
1891
  };
1591
- var buildRequestBody3 = (params, configuredMax, configCaching) => {
1892
+ var buildRequestBody2 = (params, configuredMax, configCaching) => {
1592
1893
  const caching = params.promptCaching ?? configCaching;
1593
1894
  const cacheSystem = params.cacheSystemPrompt ?? caching;
1594
1895
  const options = requestOptionsFor(params);
@@ -2014,7 +2315,7 @@ async function* parseSSEStream3(body, providerName, signal) {
2014
2315
  }
2015
2316
  }
2016
2317
  var fetchAndStream = async function* (baseUrl, config2, params, configuredMax, promptCaching, providerName) {
2017
- const builtBody = buildRequestBody3(params, configuredMax, promptCaching);
2318
+ const builtBody = buildRequestBody2(params, configuredMax, promptCaching);
2018
2319
  const body = config2.transformRequestBody ? config2.transformRequestBody(builtBody, params) : builtBody;
2019
2320
  const target = `${baseUrl}/v1/messages`;
2020
2321
  const fetchImpl = config2.fetch ?? fetch;
@@ -2055,7 +2356,57 @@ var anthropic = (config2) => {
2055
2356
  const configuredMax = config2.maxTokens ?? DEFAULT_MAX_TOKENS;
2056
2357
  const promptCaching = config2.promptCaching ?? true;
2057
2358
  const providerName = config2.providerName ?? "anthropic";
2359
+ const capacityRequest = async (params, path, body) => {
2360
+ const token = config2.tokenSource ? await config2.tokenSource() : config2.apiKey;
2361
+ const headers = new Headers(typeof config2.headers === "function" ? await config2.headers(params) : config2.headers);
2362
+ headers.set("Content-Type", "application/json");
2363
+ if (config2.authStyle === "bearer")
2364
+ headers.set("Authorization", `Bearer ${token}`);
2365
+ else {
2366
+ headers.set("anthropic-version", API_VERSION);
2367
+ headers.set("x-api-key", token);
2368
+ }
2369
+ return capacityJson(await (config2.fetch ?? fetch)(`${baseUrl}${path}`, {
2370
+ method: body ? "POST" : "GET",
2371
+ headers,
2372
+ body: body ? JSON.stringify(body) : undefined,
2373
+ signal: params.signal ? AbortSignal.any([params.signal, AbortSignal.timeout(15000)]) : AbortSignal.timeout(15000)
2374
+ }));
2375
+ };
2376
+ const inputCapacity = {
2377
+ outputTokens: (params) => {
2378
+ const built = buildRequestBody2(params, configuredMax, promptCaching);
2379
+ const body = config2.transformRequestBody ? config2.transformRequestBody(built, params) : built;
2380
+ return positiveTokenLimit(body.max_tokens);
2381
+ },
2382
+ getLimits: cacheModelLimits(async (params) => {
2383
+ const data = await capacityRequest(params, `/v1/models/${encodeURIComponent(params.model)}`);
2384
+ const context = positiveTokenLimit(data.max_input_tokens);
2385
+ return {
2386
+ maxInputTokens: context,
2387
+ contextWindowTokens: context,
2388
+ maxOutputTokens: positiveTokenLimit(data.max_tokens)
2389
+ };
2390
+ }, config2.tokenSource || typeof config2.headers === "function" ? 0 : 300000),
2391
+ countTokens: async (params) => {
2392
+ const built = buildRequestBody2(params, configuredMax, promptCaching);
2393
+ const body = config2.transformRequestBody ? config2.transformRequestBody(built, params) : built;
2394
+ const counted = {};
2395
+ for (const key of [
2396
+ "model",
2397
+ "messages",
2398
+ "system",
2399
+ "tools",
2400
+ "tool_choice",
2401
+ "thinking"
2402
+ ])
2403
+ if (body[key] !== undefined)
2404
+ counted[key] = body[key];
2405
+ return inputTokenCount((await capacityRequest(params, "/v1/messages/count_tokens", counted)).input_tokens);
2406
+ }
2407
+ };
2058
2408
  return instrumentAIProvider({
2409
+ inputCapacity,
2059
2410
  stream: (params) => fetchAndStream(baseUrl, config2, params, configuredMax, promptCaching, providerName)
2060
2411
  }, providerName);
2061
2412
  };
@@ -2978,5 +3329,5 @@ export {
2978
3329
  verifyOpenRouterWebhookSignature
2979
3330
  };
2980
3331
 
2981
- //# debugId=35809F9761B2091A64756E2164756E21
3332
+ //# debugId=97E7A9DE2EC4EDCB64756E2164756E21
2982
3333
  //# sourceMappingURL=openrouter.js.map