@wrongstack/providers 0.1.9 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -37,6 +37,8 @@ async function aggregateStream(stream, onEvent) {
37
37
  const textBuffers = [];
38
38
  let currentTextIndex = -1;
39
39
  const toolBuffers = /* @__PURE__ */ new Map();
40
+ const thinkingBuffers = [];
41
+ let currentThinkingIndex = -1;
40
42
  const blockOrder = [];
41
43
  for await (const ev of stream) {
42
44
  if (onEvent) onEvent(ev);
@@ -74,10 +76,45 @@ async function aggregateStream(stream, onEvent) {
74
76
  } else {
75
77
  b.input = { __raw: ev.input };
76
78
  }
79
+ if (ev.providerMeta) b.providerMeta = ev.providerMeta;
77
80
  }
78
81
  currentTextIndex = -1;
79
82
  break;
80
83
  }
84
+ case "thinking_start": {
85
+ currentTextIndex = -1;
86
+ currentThinkingIndex = thinkingBuffers.length;
87
+ thinkingBuffers.push({
88
+ textBuf: "",
89
+ ...ev.providerMeta ? { providerMeta: ev.providerMeta } : {}
90
+ });
91
+ blockOrder.push({ kind: "thinking", idx: currentThinkingIndex });
92
+ break;
93
+ }
94
+ case "thinking_delta": {
95
+ if (currentThinkingIndex === -1) {
96
+ currentThinkingIndex = thinkingBuffers.length;
97
+ thinkingBuffers.push({ textBuf: "" });
98
+ blockOrder.push({ kind: "thinking", idx: currentThinkingIndex });
99
+ }
100
+ const t = thinkingBuffers[currentThinkingIndex];
101
+ if (t) t.textBuf += ev.text;
102
+ break;
103
+ }
104
+ case "thinking_signature": {
105
+ if (currentThinkingIndex === -1) {
106
+ currentThinkingIndex = thinkingBuffers.length;
107
+ thinkingBuffers.push({ textBuf: "" });
108
+ blockOrder.push({ kind: "thinking", idx: currentThinkingIndex });
109
+ }
110
+ const t = thinkingBuffers[currentThinkingIndex];
111
+ if (t) t.signature = ev.signature;
112
+ break;
113
+ }
114
+ case "thinking_stop": {
115
+ currentThinkingIndex = -1;
116
+ break;
117
+ }
81
118
  case "message_stop":
82
119
  stopReason = ev.stopReason;
83
120
  usage = ev.usage;
@@ -89,15 +126,28 @@ async function aggregateStream(stream, onEvent) {
89
126
  if (b.kind === "text") {
90
127
  const text = textBuffers[b.idx] ?? "";
91
128
  if (text) content.push({ type: "text", text });
129
+ } else if (b.kind === "thinking") {
130
+ const t = thinkingBuffers[b.idx];
131
+ if (!t || !t.textBuf && !t.signature) continue;
132
+ const block = { type: "thinking", thinking: t.textBuf };
133
+ if (t.signature) block.signature = t.signature;
134
+ if (t.providerMeta && Object.keys(t.providerMeta).length > 0) {
135
+ block.providerMeta = t.providerMeta;
136
+ }
137
+ content.push(block);
92
138
  } else {
93
139
  const tb = toolBuffers.get(b.id);
94
140
  if (tb) {
95
- content.push({
141
+ const block = {
96
142
  type: "tool_use",
97
143
  id: b.id,
98
144
  name: tb.name,
99
145
  input: tb.input && typeof tb.input === "object" && !Array.isArray(tb.input) ? tb.input : {}
100
- });
146
+ };
147
+ if (tb.providerMeta && Object.keys(tb.providerMeta).length > 0) {
148
+ block.providerMeta = tb.providerMeta;
149
+ }
150
+ content.push(block);
101
151
  }
102
152
  }
103
153
  }
@@ -109,6 +159,9 @@ var init_aggregate = __esm({
109
159
  init_tool_input();
110
160
  }
111
161
  });
162
+
163
+ // src/anthropic.ts
164
+ init_tool_input();
112
165
  function parseProviderHttpError(providerId, status, rawText) {
113
166
  const body = parseBody(rawText);
114
167
  const retryable = isRetryable(status, body.type);
@@ -162,71 +215,69 @@ function stringOf(v) {
162
215
  return typeof v === "string" && v.length > 0 ? v : void 0;
163
216
  }
164
217
 
165
- // src/anthropic.ts
166
- init_tool_input();
167
-
168
- // src/tool-format/to-anthropic.ts
169
- function toolsToAnthropic(tools) {
170
- return tools.map((t) => ({
171
- name: t.name,
172
- description: t.description,
173
- input_schema: t.inputSchema ?? {
174
- type: "object",
175
- properties: {}
176
- }
177
- }));
178
- }
179
-
180
- // src/stop-reason.ts
181
- function normalizeAnthropic(stop) {
182
- switch (stop) {
183
- case "end_turn":
184
- return "end_turn";
185
- case "tool_use":
186
- return "tool_use";
187
- case "max_tokens":
188
- return "max_tokens";
189
- case "stop_sequence":
190
- return "stop_sequence";
191
- case "refusal":
192
- return "refusal";
193
- default:
194
- return "end_turn";
195
- }
196
- }
197
- function normalizeOpenAI(stop) {
198
- switch (stop) {
199
- case "stop":
200
- return "end_turn";
201
- case "tool_calls":
202
- case "function_call":
203
- return "tool_use";
204
- case "length":
205
- return "max_tokens";
206
- case "content_filter":
207
- return "refusal";
208
- default:
209
- return "end_turn";
210
- }
211
- }
212
- function normalizeGemini(stop) {
213
- switch (stop) {
214
- case "SAFETY":
215
- case "RECITATION":
216
- case "hallucination":
217
- return "refusal";
218
- case "stop":
219
- case "STOP":
220
- return "end_turn";
221
- case "max_tokens":
222
- case "MAX_TOKENS":
223
- return "max_tokens";
224
- case "tool_use":
225
- case "TOOL_USE":
226
- return "tool_use";
227
- default:
228
- return "end_turn";
218
+ // src/family-capabilities.ts
219
+ var CAPABILITIES_BY_FAMILY = {
220
+ anthropic: {
221
+ tools: true,
222
+ parallelTools: true,
223
+ vision: true,
224
+ streaming: true,
225
+ promptCache: true,
226
+ systemPrompt: true,
227
+ jsonMode: false,
228
+ maxContext: 2e5,
229
+ cacheControl: "native"
230
+ },
231
+ openai: {
232
+ tools: true,
233
+ parallelTools: true,
234
+ vision: true,
235
+ streaming: true,
236
+ promptCache: false,
237
+ systemPrompt: true,
238
+ jsonMode: true,
239
+ maxContext: 128e3,
240
+ cacheControl: "auto"
241
+ },
242
+ "openai-compatible": {
243
+ tools: true,
244
+ parallelTools: true,
245
+ vision: false,
246
+ streaming: true,
247
+ promptCache: false,
248
+ systemPrompt: true,
249
+ jsonMode: false,
250
+ maxContext: 32e3,
251
+ cacheControl: "none"
252
+ },
253
+ google: {
254
+ tools: true,
255
+ parallelTools: true,
256
+ vision: true,
257
+ streaming: true,
258
+ promptCache: false,
259
+ systemPrompt: true,
260
+ jsonMode: true,
261
+ maxContext: 1e6,
262
+ cacheControl: "none"
263
+ },
264
+ unsupported: {
265
+ tools: false,
266
+ parallelTools: false,
267
+ vision: false,
268
+ streaming: false,
269
+ promptCache: false,
270
+ systemPrompt: false,
271
+ jsonMode: false,
272
+ maxContext: 0,
273
+ cacheControl: "none"
229
274
  }
275
+ };
276
+ function capabilitiesForFamily(family, overrides = {}) {
277
+ return {
278
+ ...CAPABILITIES_BY_FAMILY[family] ?? CAPABILITIES_BY_FAMILY.unsupported,
279
+ ...overrides
280
+ };
230
281
  }
231
282
 
232
283
  // src/sse.ts
@@ -318,6 +369,70 @@ function splitBuffer(buf) {
318
369
  function isNodeReadable(b) {
319
370
  return !!b && typeof b === "object" && typeof b.pipe === "function" && typeof b.on === "function";
320
371
  }
372
+
373
+ // src/stop-reason.ts
374
+ function normalizeAnthropic(stop) {
375
+ switch (stop) {
376
+ case "end_turn":
377
+ return "end_turn";
378
+ case "tool_use":
379
+ return "tool_use";
380
+ case "max_tokens":
381
+ return "max_tokens";
382
+ case "stop_sequence":
383
+ return "stop_sequence";
384
+ case "refusal":
385
+ return "refusal";
386
+ default:
387
+ return "end_turn";
388
+ }
389
+ }
390
+ function normalizeOpenAI(stop) {
391
+ switch (stop) {
392
+ case "stop":
393
+ return "end_turn";
394
+ case "tool_calls":
395
+ case "function_call":
396
+ return "tool_use";
397
+ case "length":
398
+ return "max_tokens";
399
+ case "content_filter":
400
+ return "refusal";
401
+ default:
402
+ return "end_turn";
403
+ }
404
+ }
405
+ function normalizeGemini(stop) {
406
+ switch (stop) {
407
+ case "SAFETY":
408
+ case "RECITATION":
409
+ case "hallucination":
410
+ return "refusal";
411
+ case "stop":
412
+ case "STOP":
413
+ return "end_turn";
414
+ case "max_tokens":
415
+ case "MAX_TOKENS":
416
+ return "max_tokens";
417
+ case "tool_use":
418
+ case "TOOL_USE":
419
+ return "tool_use";
420
+ default:
421
+ return "end_turn";
422
+ }
423
+ }
424
+
425
+ // src/tool-format/to-anthropic.ts
426
+ function toolsToAnthropic(tools) {
427
+ return tools.map((t) => ({
428
+ name: t.name,
429
+ description: t.description,
430
+ input_schema: t.inputSchema ?? {
431
+ type: "object",
432
+ properties: {}
433
+ }
434
+ }));
435
+ }
321
436
  async function safeText(res) {
322
437
  try {
323
438
  return await res.text();
@@ -353,13 +468,10 @@ var WireAdapter = class {
353
468
  });
354
469
  } catch (err) {
355
470
  if (opts.signal.aborted) throw err;
356
- throw new ProviderError(
357
- err instanceof Error ? err.message : String(err),
358
- 0,
359
- true,
360
- this.id,
361
- { cause: err, body: { message: err instanceof Error ? err.message : String(err) } }
362
- );
471
+ throw new ProviderError(err instanceof Error ? err.message : String(err), 0, true, this.id, {
472
+ cause: err,
473
+ body: { message: err instanceof Error ? err.message : String(err) }
474
+ });
363
475
  }
364
476
  if (!httpRes.ok) {
365
477
  const text = await safeText(httpRes);
@@ -380,71 +492,6 @@ var WireAdapter = class {
380
492
  }
381
493
  };
382
494
 
383
- // src/family-capabilities.ts
384
- var CAPABILITIES_BY_FAMILY = {
385
- anthropic: {
386
- tools: true,
387
- parallelTools: true,
388
- vision: true,
389
- streaming: true,
390
- promptCache: true,
391
- systemPrompt: true,
392
- jsonMode: false,
393
- maxContext: 2e5,
394
- cacheControl: "native"
395
- },
396
- openai: {
397
- tools: true,
398
- parallelTools: true,
399
- vision: true,
400
- streaming: true,
401
- promptCache: false,
402
- systemPrompt: true,
403
- jsonMode: true,
404
- maxContext: 128e3,
405
- cacheControl: "auto"
406
- },
407
- "openai-compatible": {
408
- tools: true,
409
- parallelTools: true,
410
- vision: false,
411
- streaming: true,
412
- promptCache: false,
413
- systemPrompt: true,
414
- jsonMode: false,
415
- maxContext: 32e3,
416
- cacheControl: "none"
417
- },
418
- google: {
419
- tools: true,
420
- parallelTools: true,
421
- vision: true,
422
- streaming: true,
423
- promptCache: false,
424
- systemPrompt: true,
425
- jsonMode: true,
426
- maxContext: 1e6,
427
- cacheControl: "none"
428
- },
429
- unsupported: {
430
- tools: false,
431
- parallelTools: false,
432
- vision: false,
433
- streaming: false,
434
- promptCache: false,
435
- systemPrompt: false,
436
- jsonMode: false,
437
- maxContext: 0,
438
- cacheControl: "none"
439
- }
440
- };
441
- function capabilitiesForFamily(family, overrides = {}) {
442
- return {
443
- ...CAPABILITIES_BY_FAMILY[family] ?? CAPABILITIES_BY_FAMILY.unsupported,
444
- ...overrides
445
- };
446
- }
447
-
448
495
  // src/anthropic.ts
449
496
  var DEFAULT_BASE = "https://api.anthropic.com";
450
497
  var DEFAULT_VERSION = "2023-06-01";
@@ -539,6 +586,9 @@ async function* parseAnthropicStream(body, fallbackModel) {
539
586
  }
540
587
  } else if (cb?.type === "text") {
541
588
  blocks.set(index, { kind: "text", partial: "" });
589
+ } else if (cb?.type === "thinking" || cb?.type === "redacted_thinking") {
590
+ blocks.set(index, { kind: "thinking", partial: "" });
591
+ yield { type: "thinking_start" };
542
592
  } else {
543
593
  blocks.set(index, { kind: "unknown", partial: "" });
544
594
  }
@@ -556,6 +606,10 @@ async function* parseAnthropicStream(body, fallbackModel) {
556
606
  block.partial += delta.partial_json;
557
607
  yield { type: "tool_use_input_delta", id: block.id, partial: delta.partial_json };
558
608
  }
609
+ } else if (delta.type === "thinking_delta" && typeof delta.thinking === "string") {
610
+ yield { type: "thinking_delta", text: delta.thinking };
611
+ } else if (delta.type === "signature_delta" && typeof delta.signature === "string") {
612
+ yield { type: "thinking_signature", signature: delta.signature };
559
613
  }
560
614
  break;
561
615
  }
@@ -565,6 +619,8 @@ async function* parseAnthropicStream(body, fallbackModel) {
565
619
  if (block?.kind === "tool_use" && block.id) {
566
620
  const input = parseToolInput(block.partial);
567
621
  yield { type: "tool_use_stop", id: block.id, input };
622
+ } else if (block?.kind === "thinking") {
623
+ yield { type: "thinking_stop" };
568
624
  }
569
625
  break;
570
626
  }
@@ -582,20 +638,237 @@ async function* parseAnthropicStream(body, fallbackModel) {
582
638
  break;
583
639
  case "error": {
584
640
  const err = ev["error"];
585
- throw new ProviderError(
586
- err?.message ?? "Anthropic stream error",
587
- 0,
588
- false,
589
- "anthropic",
590
- { body: { type: err?.type, message: err?.message } }
591
- );
641
+ throw new ProviderError(err?.message ?? "Anthropic stream error", 0, false, "anthropic", {
642
+ body: { type: err?.type, message: err?.message }
643
+ });
644
+ }
645
+ }
646
+ }
647
+ if (started) {
648
+ yield { type: "message_stop", stopReason, usage };
649
+ }
650
+ }
651
+ var DEFAULT_BASE2 = "https://generativelanguage.googleapis.com/v1beta";
652
+ var GoogleProvider = class extends WireAdapter {
653
+ id;
654
+ capabilities;
655
+ opts;
656
+ constructor(opts) {
657
+ super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE2, opts.fetchImpl);
658
+ this.opts = opts;
659
+ this.id = opts.id ?? "google";
660
+ this.capabilities = capabilitiesForFamily("google", {
661
+ ...opts.capabilities
662
+ });
663
+ }
664
+ buildUrl(req) {
665
+ return `${this.baseUrl}/models/${encodeURIComponent(req.model)}:streamGenerateContent?alt=sse`;
666
+ }
667
+ buildHeaders(req) {
668
+ return {
669
+ ...super.buildHeaders(req),
670
+ "x-goog-api-key": this.apiKey
671
+ };
672
+ }
673
+ buildBody(req) {
674
+ const body = {
675
+ contents: messagesToGemini(req.messages),
676
+ generationConfig: this.buildGenConfig(req)
677
+ };
678
+ if (req.system && req.system.length > 0) {
679
+ body["systemInstruction"] = {
680
+ parts: req.system.map((b) => ({ text: b.text }))
681
+ };
682
+ }
683
+ if (req.tools && req.tools.length > 0) {
684
+ body["tools"] = [{ functionDeclarations: toolsToGemini(req.tools) }];
685
+ }
686
+ return body;
687
+ }
688
+ parseStream(body, fallbackModel) {
689
+ return parseGoogleStream(body, fallbackModel);
690
+ }
691
+ translateError(status, text) {
692
+ return parseProviderHttpError(this.id, status, text);
693
+ }
694
+ buildGenConfig(req) {
695
+ const cfg = { maxOutputTokens: req.maxTokens };
696
+ if (req.temperature !== void 0) cfg["temperature"] = req.temperature;
697
+ if (req.topP !== void 0) cfg["topP"] = req.topP;
698
+ if (req.stopSequences) cfg["stopSequences"] = req.stopSequences;
699
+ return cfg;
700
+ }
701
+ };
702
+ function toolsToGemini(tools) {
703
+ return tools.map((t) => ({
704
+ name: t.name,
705
+ description: t.description,
706
+ parameters: sanitizeSchemaForGemini(t.inputSchema) ?? {
707
+ type: "object",
708
+ properties: {}
709
+ }
710
+ }));
711
+ }
712
+ var GEMINI_ALLOWED_KEYS = /* @__PURE__ */ new Set([
713
+ "type",
714
+ "format",
715
+ "description",
716
+ "nullable",
717
+ "enum",
718
+ "items",
719
+ "properties",
720
+ "required",
721
+ "anyOf",
722
+ "minLength",
723
+ "maxLength",
724
+ "pattern",
725
+ "minimum",
726
+ "maximum",
727
+ "minItems",
728
+ "maxItems",
729
+ "minProperties",
730
+ "maxProperties",
731
+ "propertyOrdering",
732
+ "title"
733
+ ]);
734
+ function sanitizeSchemaForGemini(node) {
735
+ if (node === null || node === void 0) return void 0;
736
+ if (Array.isArray(node)) {
737
+ return void 0;
738
+ }
739
+ if (typeof node !== "object") return void 0;
740
+ const src = node;
741
+ const out = {};
742
+ for (const [k, v] of Object.entries(src)) {
743
+ if (!GEMINI_ALLOWED_KEYS.has(k)) continue;
744
+ if (k === "properties" && v && typeof v === "object") {
745
+ const props = {};
746
+ for (const [pname, pschema] of Object.entries(v)) {
747
+ const cleaned = sanitizeSchemaForGemini(pschema);
748
+ if (cleaned) props[pname] = cleaned;
749
+ }
750
+ out["properties"] = props;
751
+ } else if (k === "items") {
752
+ const cleaned = sanitizeSchemaForGemini(v);
753
+ if (cleaned) out["items"] = cleaned;
754
+ } else if (k === "anyOf" && Array.isArray(v)) {
755
+ const cleaned = v.map((s) => sanitizeSchemaForGemini(s)).filter((s) => s !== void 0);
756
+ if (cleaned.length > 0) out["anyOf"] = cleaned;
757
+ } else if (k === "required" && Array.isArray(v)) {
758
+ out["required"] = v.filter((s) => typeof s === "string");
759
+ } else if (k === "enum" && Array.isArray(v)) {
760
+ out["enum"] = v;
761
+ } else {
762
+ out[k] = v;
763
+ }
764
+ }
765
+ return out;
766
+ }
767
+ function messagesToGemini(messages) {
768
+ const out = [];
769
+ for (const m of messages) {
770
+ if (m.role === "system") continue;
771
+ const blocks = typeof m.content === "string" ? [{ type: "text", text: m.content }] : m.content;
772
+ if (m.role === "assistant") {
773
+ const parts = [];
774
+ for (const b of blocks) {
775
+ if (b.type === "text" && b.text) parts.push({ text: b.text });
776
+ else if (b.type === "tool_use") {
777
+ const part = {
778
+ functionCall: { name: b.name, args: b.input }
779
+ };
780
+ const sig = b.providerMeta?.["google.thoughtSignature"];
781
+ if (typeof sig === "string" && sig.length > 0) {
782
+ part.thoughtSignature = sig;
783
+ }
784
+ parts.push(part);
785
+ }
786
+ }
787
+ if (parts.length > 0) out.push({ role: "model", parts });
788
+ continue;
789
+ }
790
+ const textParts = [];
791
+ const functionParts = [];
792
+ for (const b of blocks) {
793
+ if (b.type === "text" && b.text) textParts.push({ text: b.text });
794
+ else if (b.type === "tool_result") {
795
+ const responseText = typeof b.content === "string" ? b.content : JSON.stringify(b.content);
796
+ const fnName = b.name ?? b.tool_use_id;
797
+ functionParts.push({
798
+ functionResponse: {
799
+ name: fnName,
800
+ response: { content: responseText }
801
+ }
802
+ });
803
+ } else if (b.type === "image" && b.source.type === "base64") {
804
+ textParts.push({
805
+ inlineData: {
806
+ mimeType: b.source.media_type ?? "image/png",
807
+ data: b.source.data ?? ""
808
+ }
809
+ });
810
+ }
811
+ }
812
+ const userParts = [...textParts];
813
+ if (functionParts.length > 0) userParts.push(...functionParts);
814
+ if (userParts.length > 0) out.push({ role: "user", parts: userParts });
815
+ }
816
+ return out;
817
+ }
818
+ async function* parseGoogleStream(body, fallbackModel) {
819
+ let model = fallbackModel;
820
+ let usage = { input: 0, output: 0 };
821
+ let stopReason = "end_turn";
822
+ let started = false;
823
+ let sawFunctionCall = false;
824
+ for await (const msg of parseSSE(body)) {
825
+ if (!msg.data || msg.data === "[DONE]") continue;
826
+ const parsed = safeParse(msg.data);
827
+ if (!parsed.ok || !parsed.value) continue;
828
+ const obj = parsed.value;
829
+ if (obj.modelVersion) model = obj.modelVersion;
830
+ if (!started) {
831
+ started = true;
832
+ yield { type: "message_start", model };
833
+ }
834
+ const candidate = obj.candidates?.[0];
835
+ for (const part of candidate?.content?.parts ?? []) {
836
+ if (typeof part.text === "string" && part.text.length > 0) {
837
+ yield { type: "text_delta", text: part.text };
838
+ } else if (part.functionCall) {
839
+ sawFunctionCall = true;
840
+ const id = randomUUID();
841
+ yield { type: "tool_use_start", id, name: part.functionCall.name };
842
+ const providerMeta = typeof part.thoughtSignature === "string" ? { "google.thoughtSignature": part.thoughtSignature } : void 0;
843
+ yield {
844
+ type: "tool_use_stop",
845
+ id,
846
+ input: part.functionCall.args ?? {},
847
+ ...providerMeta ? { providerMeta } : {}
848
+ };
592
849
  }
593
850
  }
851
+ if (candidate?.finishReason) {
852
+ stopReason = normalizeGemini(candidate.finishReason);
853
+ }
854
+ const u = obj.usageMetadata;
855
+ if (u) {
856
+ const cached = u.cachedContentTokenCount ?? 0;
857
+ const promptTotal = u.promptTokenCount ?? usage.input + cached;
858
+ usage = {
859
+ input: Math.max(0, promptTotal - cached),
860
+ output: u.candidatesTokenCount ?? usage.output,
861
+ cacheRead: cached || usage.cacheRead
862
+ };
863
+ }
594
864
  }
595
865
  if (started) {
596
- yield { type: "message_stop", stopReason, usage };
866
+ const finalStop = sawFunctionCall ? "tool_use" : stopReason;
867
+ yield { type: "message_stop", stopReason: finalStop, usage };
597
868
  }
598
869
  }
870
+
871
+ // src/openai.ts
599
872
  init_tool_input();
600
873
 
601
874
  // src/tool-format/to-openai.ts
@@ -645,7 +918,9 @@ function messagesToOpenAI(system, messages, opts = {}) {
645
918
  const blocks = normalizeContent(msg.content);
646
919
  const textBlocks = blocks.filter((b) => b.type === "text");
647
920
  const toolUses = blocks.filter((b) => b.type === "tool_use");
921
+ const thinkingBlocks = blocks.filter((b) => b.type === "thinking");
648
922
  const text = textBlocks.map((b) => b.text).join("");
923
+ const reasoning = thinkingBlocks.map((b) => b.thinking).filter((t) => t && t.length > 0).join("");
649
924
  const toolCalls = toolUses.map((u) => ({
650
925
  id: u.id,
651
926
  type: "function",
@@ -662,6 +937,9 @@ function messagesToOpenAI(system, messages, opts = {}) {
662
937
  } else {
663
938
  message.content = text;
664
939
  }
940
+ if (reasoning.length > 0) {
941
+ message.reasoning_content = reasoning;
942
+ }
665
943
  out.push(message);
666
944
  }
667
945
  }
@@ -693,13 +971,13 @@ function blocksToContentArray(blocks) {
693
971
  }
694
972
 
695
973
  // src/openai.ts
696
- var DEFAULT_BASE2 = "https://api.openai.com/v1";
974
+ var DEFAULT_BASE3 = "https://api.openai.com/v1";
697
975
  var OpenAIProvider = class extends WireAdapter {
698
976
  id;
699
977
  capabilities;
700
978
  opts;
701
979
  constructor(opts) {
702
- super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE2, opts.fetchImpl);
980
+ super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE3, opts.fetchImpl);
703
981
  this.opts = opts;
704
982
  this.id = opts.id ?? "openai";
705
983
  this.capabilities = capabilitiesForFamily("openai", {
@@ -771,6 +1049,7 @@ async function* parseOpenAIStream(body, fallbackModel) {
771
1049
  let usage = { input: 0, output: 0 };
772
1050
  let stopReason = "end_turn";
773
1051
  let started = false;
1052
+ let thinkingOpen = false;
774
1053
  const toolByIndex = /* @__PURE__ */ new Map();
775
1054
  for await (const msg of parseSSE(body)) {
776
1055
  if (!msg.data || msg.data === "[DONE]") continue;
@@ -784,10 +1063,26 @@ async function* parseOpenAIStream(body, fallbackModel) {
784
1063
  }
785
1064
  const choices = obj["choices"];
786
1065
  const choice = choices?.[0];
1066
+ const reasoningDelta = typeof choice?.delta?.reasoning_content === "string" ? choice.delta.reasoning_content : typeof choice?.delta?.reasoning === "string" ? choice.delta.reasoning : void 0;
1067
+ if (reasoningDelta && reasoningDelta.length > 0) {
1068
+ if (!thinkingOpen) {
1069
+ thinkingOpen = true;
1070
+ yield { type: "thinking_start" };
1071
+ }
1072
+ yield { type: "thinking_delta", text: reasoningDelta };
1073
+ }
787
1074
  if (choice?.delta?.content) {
1075
+ if (thinkingOpen) {
1076
+ thinkingOpen = false;
1077
+ yield { type: "thinking_stop" };
1078
+ }
788
1079
  yield { type: "text_delta", text: choice.delta.content };
789
1080
  }
790
1081
  if (choice?.delta?.tool_calls) {
1082
+ if (thinkingOpen) {
1083
+ thinkingOpen = false;
1084
+ yield { type: "thinking_stop" };
1085
+ }
791
1086
  for (const tc of choice.delta.tool_calls) {
792
1087
  const idx = tc.index ?? 0;
793
1088
  let entry = toolByIndex.get(idx);
@@ -811,13 +1106,18 @@ async function* parseOpenAIStream(body, fallbackModel) {
811
1106
  }
812
1107
  const u = obj["usage"];
813
1108
  if (u) {
1109
+ const cached = u.prompt_tokens_details?.cached_tokens ?? 0;
1110
+ const promptTotal = u.prompt_tokens ?? usage.input + cached;
814
1111
  usage = {
815
- input: u.prompt_tokens ?? usage.input,
1112
+ input: Math.max(0, promptTotal - cached),
816
1113
  output: u.completion_tokens ?? usage.output,
817
- cacheRead: u.prompt_tokens_details?.cached_tokens ?? usage.cacheRead
1114
+ cacheRead: cached || usage.cacheRead
818
1115
  };
819
1116
  }
820
1117
  }
1118
+ if (thinkingOpen) {
1119
+ yield { type: "thinking_stop" };
1120
+ }
821
1121
  for (const entry of toolByIndex.values()) {
822
1122
  const input = parseToolInput(entry.argBuf);
823
1123
  yield { type: "tool_use_stop", id: entry.id, input };
@@ -860,220 +1160,6 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
860
1160
  };
861
1161
  }
862
1162
  };
863
- var DEFAULT_BASE3 = "https://generativelanguage.googleapis.com/v1beta";
864
- var GoogleProvider = class extends WireAdapter {
865
- id;
866
- capabilities;
867
- opts;
868
- constructor(opts) {
869
- super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE3, opts.fetchImpl);
870
- this.opts = opts;
871
- this.id = opts.id ?? "google";
872
- this.capabilities = capabilitiesForFamily("google", {
873
- ...opts.capabilities
874
- });
875
- }
876
- buildUrl(req) {
877
- return `${this.baseUrl}/models/${encodeURIComponent(req.model)}:streamGenerateContent?alt=sse`;
878
- }
879
- buildHeaders(req) {
880
- return {
881
- ...super.buildHeaders(req),
882
- "x-goog-api-key": this.apiKey
883
- };
884
- }
885
- buildBody(req) {
886
- const body = {
887
- contents: messagesToGemini(req.messages),
888
- generationConfig: this.buildGenConfig(req)
889
- };
890
- if (req.system && req.system.length > 0) {
891
- body["systemInstruction"] = {
892
- parts: req.system.map((b) => ({ text: b.text }))
893
- };
894
- }
895
- if (req.tools && req.tools.length > 0) {
896
- body["tools"] = [{ functionDeclarations: toolsToGemini(req.tools) }];
897
- }
898
- return body;
899
- }
900
- parseStream(body, fallbackModel) {
901
- return parseGoogleStream(body, fallbackModel);
902
- }
903
- translateError(status, text) {
904
- return parseProviderHttpError(this.id, status, text);
905
- }
906
- buildGenConfig(req) {
907
- const cfg = { maxOutputTokens: req.maxTokens };
908
- if (req.temperature !== void 0) cfg["temperature"] = req.temperature;
909
- if (req.topP !== void 0) cfg["topP"] = req.topP;
910
- if (req.stopSequences) cfg["stopSequences"] = req.stopSequences;
911
- return cfg;
912
- }
913
- };
914
- function toolsToGemini(tools) {
915
- return tools.map((t) => ({
916
- name: t.name,
917
- description: t.description,
918
- parameters: sanitizeSchemaForGemini(t.inputSchema) ?? { type: "object", properties: {} }
919
- }));
920
- }
921
- var GEMINI_ALLOWED_KEYS = /* @__PURE__ */ new Set([
922
- "type",
923
- "format",
924
- "description",
925
- "nullable",
926
- "enum",
927
- "items",
928
- "properties",
929
- "required",
930
- "anyOf",
931
- "minLength",
932
- "maxLength",
933
- "pattern",
934
- "minimum",
935
- "maximum",
936
- "minItems",
937
- "maxItems",
938
- "minProperties",
939
- "maxProperties",
940
- "propertyOrdering",
941
- "title"
942
- ]);
943
- function sanitizeSchemaForGemini(node) {
944
- if (node === null || node === void 0) return void 0;
945
- if (Array.isArray(node)) {
946
- return void 0;
947
- }
948
- if (typeof node !== "object") return void 0;
949
- const src = node;
950
- const out = {};
951
- for (const [k, v] of Object.entries(src)) {
952
- if (!GEMINI_ALLOWED_KEYS.has(k)) continue;
953
- if (k === "properties" && v && typeof v === "object") {
954
- const props = {};
955
- for (const [pname, pschema] of Object.entries(v)) {
956
- const cleaned = sanitizeSchemaForGemini(pschema);
957
- if (cleaned) props[pname] = cleaned;
958
- }
959
- out["properties"] = props;
960
- } else if (k === "items") {
961
- const cleaned = sanitizeSchemaForGemini(v);
962
- if (cleaned) out["items"] = cleaned;
963
- } else if (k === "anyOf" && Array.isArray(v)) {
964
- const cleaned = v.map((s) => sanitizeSchemaForGemini(s)).filter((s) => s !== void 0);
965
- if (cleaned.length > 0) out["anyOf"] = cleaned;
966
- } else if (k === "required" && Array.isArray(v)) {
967
- out["required"] = v.filter((s) => typeof s === "string");
968
- } else if (k === "enum" && Array.isArray(v)) {
969
- out["enum"] = v;
970
- } else {
971
- out[k] = v;
972
- }
973
- }
974
- return out;
975
- }
976
- function messagesToGemini(messages) {
977
- const out = [];
978
- for (const m of messages) {
979
- if (m.role === "system") continue;
980
- const blocks = typeof m.content === "string" ? [{ type: "text", text: m.content }] : m.content;
981
- if (m.role === "assistant") {
982
- const parts = [];
983
- for (const b of blocks) {
984
- if (b.type === "text" && b.text) parts.push({ text: b.text });
985
- else if (b.type === "tool_use") {
986
- const part = {
987
- functionCall: { name: b.name, args: b.input }
988
- };
989
- const sig = b.providerMeta?.["google.thoughtSignature"];
990
- if (typeof sig === "string" && sig.length > 0) {
991
- part.thoughtSignature = sig;
992
- }
993
- parts.push(part);
994
- }
995
- }
996
- if (parts.length > 0) out.push({ role: "model", parts });
997
- continue;
998
- }
999
- const textParts = [];
1000
- const functionParts = [];
1001
- for (const b of blocks) {
1002
- if (b.type === "text" && b.text) textParts.push({ text: b.text });
1003
- else if (b.type === "tool_result") {
1004
- const responseText = typeof b.content === "string" ? b.content : JSON.stringify(b.content);
1005
- const fnName = b.name ?? b.tool_use_id;
1006
- functionParts.push({
1007
- functionResponse: {
1008
- name: fnName,
1009
- response: { content: responseText }
1010
- }
1011
- });
1012
- } else if (b.type === "image" && b.source.type === "base64") {
1013
- textParts.push({
1014
- inlineData: {
1015
- mimeType: b.source.media_type ?? "image/png",
1016
- data: b.source.data ?? ""
1017
- }
1018
- });
1019
- }
1020
- }
1021
- const userParts = [...textParts];
1022
- if (functionParts.length > 0) userParts.push(...functionParts);
1023
- if (userParts.length > 0) out.push({ role: "user", parts: userParts });
1024
- }
1025
- return out;
1026
- }
1027
- async function* parseGoogleStream(body, fallbackModel) {
1028
- let model = fallbackModel;
1029
- let usage = { input: 0, output: 0 };
1030
- let stopReason = "end_turn";
1031
- let started = false;
1032
- let sawFunctionCall = false;
1033
- for await (const msg of parseSSE(body)) {
1034
- if (!msg.data || msg.data === "[DONE]") continue;
1035
- const parsed = safeParse(msg.data);
1036
- if (!parsed.ok || !parsed.value) continue;
1037
- const obj = parsed.value;
1038
- if (obj.modelVersion) model = obj.modelVersion;
1039
- if (!started) {
1040
- started = true;
1041
- yield { type: "message_start", model };
1042
- }
1043
- const candidate = obj.candidates?.[0];
1044
- for (const part of candidate?.content?.parts ?? []) {
1045
- if (typeof part.text === "string" && part.text.length > 0) {
1046
- yield { type: "text_delta", text: part.text };
1047
- } else if (part.functionCall) {
1048
- sawFunctionCall = true;
1049
- const id = randomUUID();
1050
- yield { type: "tool_use_start", id, name: part.functionCall.name };
1051
- const providerMeta = typeof part.thoughtSignature === "string" ? { "google.thoughtSignature": part.thoughtSignature } : void 0;
1052
- yield {
1053
- type: "tool_use_stop",
1054
- id,
1055
- input: part.functionCall.args ?? {},
1056
- ...providerMeta ? { providerMeta } : {}
1057
- };
1058
- }
1059
- }
1060
- if (candidate?.finishReason) {
1061
- stopReason = normalizeGemini(candidate.finishReason);
1062
- }
1063
- const u = obj.usageMetadata;
1064
- if (u) {
1065
- usage = {
1066
- input: u.promptTokenCount ?? usage.input,
1067
- output: u.candidatesTokenCount ?? usage.output,
1068
- cacheRead: u.cachedContentTokenCount ?? usage.cacheRead
1069
- };
1070
- }
1071
- }
1072
- if (started) {
1073
- const finalStop = sawFunctionCall ? "tool_use" : stopReason;
1074
- yield { type: "message_stop", stopReason: finalStop, usage };
1075
- }
1076
- }
1077
1163
 
1078
1164
  // src/wire-format.ts
1079
1165
  var WireFormatProvider = class extends WireAdapter {
@@ -1356,13 +1442,9 @@ var anthropicWireFormat = defineWireFormat({
1356
1442
  break;
1357
1443
  case "error": {
1358
1444
  const err = ev["error"];
1359
- throw new ProviderError(
1360
- err?.message ?? "Anthropic stream error",
1361
- 0,
1362
- false,
1363
- "anthropic",
1364
- { body: { type: err?.type, message: err?.message } }
1365
- );
1445
+ throw new ProviderError(err?.message ?? "Anthropic stream error", 0, false, "anthropic", {
1446
+ body: { type: err?.type, message: err?.message }
1447
+ });
1366
1448
  }
1367
1449
  }
1368
1450
  return out;
@@ -1421,6 +1503,7 @@ var openaiWireFormat = defineWireFormat({
1421
1503
  stopReason: "end_turn",
1422
1504
  started: false,
1423
1505
  textOpen: false,
1506
+ thinkingOpen: false,
1424
1507
  toolByIndex: /* @__PURE__ */ new Map(),
1425
1508
  finalEmitted: false
1426
1509
  }),
@@ -1437,11 +1520,27 @@ var openaiWireFormat = defineWireFormat({
1437
1520
  }
1438
1521
  const choices = obj["choices"];
1439
1522
  const choice = choices?.[0];
1523
+ const reasoningDelta = typeof choice?.delta?.reasoning_content === "string" ? choice.delta.reasoning_content : typeof choice?.delta?.reasoning === "string" ? choice.delta.reasoning : void 0;
1524
+ if (reasoningDelta && reasoningDelta.length > 0) {
1525
+ if (!state.thinkingOpen) {
1526
+ state.thinkingOpen = true;
1527
+ out.push({ type: "thinking_start" });
1528
+ }
1529
+ out.push({ type: "thinking_delta", text: reasoningDelta });
1530
+ }
1440
1531
  if (choice?.delta?.content) {
1532
+ if (state.thinkingOpen) {
1533
+ state.thinkingOpen = false;
1534
+ out.push({ type: "thinking_stop" });
1535
+ }
1441
1536
  if (!state.textOpen) state.textOpen = true;
1442
1537
  out.push({ type: "text_delta", text: choice.delta.content });
1443
1538
  }
1444
1539
  if (choice?.delta?.tool_calls) {
1540
+ if (state.thinkingOpen) {
1541
+ state.thinkingOpen = false;
1542
+ out.push({ type: "thinking_stop" });
1543
+ }
1445
1544
  for (const tc of choice.delta.tool_calls) {
1446
1545
  const idx = tc.index ?? 0;
1447
1546
  let entry = state.toolByIndex.get(idx);
@@ -1466,10 +1565,12 @@ var openaiWireFormat = defineWireFormat({
1466
1565
  }
1467
1566
  const u = obj["usage"];
1468
1567
  if (u) {
1568
+ const cached = u.prompt_tokens_details?.cached_tokens ?? 0;
1569
+ const promptTotal = u.prompt_tokens ?? state.usage.input + cached;
1469
1570
  state.usage = {
1470
- input: u.prompt_tokens ?? state.usage.input,
1571
+ input: Math.max(0, promptTotal - cached),
1471
1572
  output: u.completion_tokens ?? state.usage.output,
1472
- cacheRead: u.prompt_tokens_details?.cached_tokens ?? state.usage.cacheRead
1573
+ cacheRead: cached || state.usage.cacheRead
1473
1574
  };
1474
1575
  }
1475
1576
  return out;
@@ -1478,6 +1579,10 @@ var openaiWireFormat = defineWireFormat({
1478
1579
  if (state.finalEmitted) return [];
1479
1580
  state.finalEmitted = true;
1480
1581
  const out = [];
1582
+ if (state.thinkingOpen) {
1583
+ state.thinkingOpen = false;
1584
+ out.push({ type: "thinking_stop" });
1585
+ }
1481
1586
  for (const entry of state.toolByIndex.values()) {
1482
1587
  const input = parseToolInput(entry.argBuf);
1483
1588
  out.push({ type: "tool_use_stop", id: entry.id, input });
@@ -1542,7 +1647,7 @@ var googleWireFormat = defineWireFormat({
1542
1647
  out.push({ type: "text_delta", text: part.text });
1543
1648
  } else if (part.functionCall) {
1544
1649
  state.sawFunctionCall = true;
1545
- const id = `${part.functionCall.name}_${Math.random().toString(36).slice(2, 10)}`;
1650
+ const id = `${part.functionCall.name}_${randomUUID().slice(0, 8)}`;
1546
1651
  out.push({ type: "tool_use_start", id, name: part.functionCall.name });
1547
1652
  const providerMeta = typeof part.thoughtSignature === "string" ? { "google.thoughtSignature": part.thoughtSignature } : void 0;
1548
1653
  out.push({
@@ -1558,10 +1663,12 @@ var googleWireFormat = defineWireFormat({
1558
1663
  }
1559
1664
  const u = obj.usageMetadata;
1560
1665
  if (u) {
1666
+ const cached = u.cachedContentTokenCount ?? 0;
1667
+ const promptTotal = u.promptTokenCount ?? state.usage.input + cached;
1561
1668
  state.usage = {
1562
- input: u.promptTokenCount ?? state.usage.input,
1669
+ input: Math.max(0, promptTotal - cached),
1563
1670
  output: u.candidatesTokenCount ?? state.usage.output,
1564
- cacheRead: u.cachedContentTokenCount ?? state.usage.cacheRead
1671
+ cacheRead: cached || state.usage.cacheRead
1565
1672
  };
1566
1673
  }
1567
1674
  return out;
@@ -1725,6 +1832,12 @@ function contentFromAnthropic(blocks, opts = {}) {
1725
1832
  content: normalizeToolResultContent(b.content, opts),
1726
1833
  is_error: b.is_error
1727
1834
  });
1835
+ } else if (b.type === "thinking" && typeof b.thinking === "string") {
1836
+ out.push({
1837
+ type: "thinking",
1838
+ thinking: b.thinking,
1839
+ ...b.signature ? { signature: b.signature } : {}
1840
+ });
1728
1841
  } else if (b.type === "image" && b.source) {
1729
1842
  const src = b.source;
1730
1843
  const kind = src.type === "url" ? "url" : "base64";