@providerprotocol/ai 0.0.22 → 0.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +188 -6
  2. package/dist/anthropic/index.d.ts +1 -1
  3. package/dist/anthropic/index.js +95 -36
  4. package/dist/anthropic/index.js.map +1 -1
  5. package/dist/{chunk-7WYBJPJJ.js → chunk-55X3W2MN.js} +4 -3
  6. package/dist/chunk-55X3W2MN.js.map +1 -0
  7. package/dist/{chunk-M4BMM5IB.js → chunk-6AZVUI6H.js} +20 -4
  8. package/dist/chunk-6AZVUI6H.js.map +1 -0
  9. package/dist/chunk-73IIE3QT.js +120 -0
  10. package/dist/chunk-73IIE3QT.js.map +1 -0
  11. package/dist/{chunk-RFWLEFAB.js → chunk-QNJO7DSD.js} +61 -16
  12. package/dist/chunk-QNJO7DSD.js.map +1 -0
  13. package/dist/{chunk-RS7C25LS.js → chunk-SBCATNHA.js} +9 -5
  14. package/dist/chunk-SBCATNHA.js.map +1 -0
  15. package/dist/{chunk-NWS5IKNR.js → chunk-TOJCZMVU.js} +3 -12
  16. package/dist/chunk-TOJCZMVU.js.map +1 -0
  17. package/dist/{chunk-I2VHCGQE.js → chunk-Z6DKC37J.js} +6 -5
  18. package/dist/chunk-Z6DKC37J.js.map +1 -0
  19. package/dist/google/index.d.ts +36 -4
  20. package/dist/google/index.js +98 -53
  21. package/dist/google/index.js.map +1 -1
  22. package/dist/http/index.d.ts +2 -2
  23. package/dist/http/index.js +4 -4
  24. package/dist/index.d.ts +8 -6
  25. package/dist/index.js +92 -122
  26. package/dist/index.js.map +1 -1
  27. package/dist/ollama/index.d.ts +5 -2
  28. package/dist/ollama/index.js +47 -36
  29. package/dist/ollama/index.js.map +1 -1
  30. package/dist/openai/index.d.ts +1 -1
  31. package/dist/openai/index.js +117 -56
  32. package/dist/openai/index.js.map +1 -1
  33. package/dist/openrouter/index.d.ts +1 -1
  34. package/dist/openrouter/index.js +58 -53
  35. package/dist/openrouter/index.js.map +1 -1
  36. package/dist/{provider-DWEAzeM5.d.ts → provider-x4RocsnK.d.ts} +199 -54
  37. package/dist/proxy/index.d.ts +2 -2
  38. package/dist/proxy/index.js +11 -9
  39. package/dist/proxy/index.js.map +1 -1
  40. package/dist/{retry-DmPmqZL6.d.ts → retry-DTfjXXPh.d.ts} +1 -1
  41. package/dist/{stream-DbkLOIbJ.d.ts → stream-ITNFNnO4.d.ts} +95 -38
  42. package/dist/xai/index.d.ts +1 -1
  43. package/dist/xai/index.js +221 -97
  44. package/dist/xai/index.js.map +1 -1
  45. package/package.json +1 -1
  46. package/dist/chunk-7WYBJPJJ.js.map +0 -1
  47. package/dist/chunk-I2VHCGQE.js.map +0 -1
  48. package/dist/chunk-M4BMM5IB.js.map +0 -1
  49. package/dist/chunk-NWS5IKNR.js.map +0 -1
  50. package/dist/chunk-RFWLEFAB.js.map +0 -1
  51. package/dist/chunk-RS7C25LS.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { a as ProviderConfig, g as Provider } from '../provider-DWEAzeM5.js';
1
+ import { a as ProviderConfig, g as Provider } from '../provider-x4RocsnK.js';
2
2
 
3
3
  /**
4
4
  * Provider-specific parameters for Google Gemini API requests.
@@ -125,14 +125,37 @@ interface GoogleLLMParams {
125
125
  toolConfig?: GoogleToolConfig;
126
126
  }
127
127
  /**
128
- * Configuration for extended thinking/reasoning in Gemini 3+ models.
128
+ * Configuration for extended thinking/reasoning in Gemini 2.5+ and 3+ models.
129
129
  *
130
130
  * Enables models to spend additional compute on reasoning before
131
131
  * generating a response, improving quality for complex tasks.
132
+ *
133
+ * For Gemini 2.5 models: Use `thinkingBudget` to control token allocation.
134
+ * For Gemini 3+ models: Use `thinkingLevel` (recommended) to set reasoning depth.
135
+ *
136
+ * Set `includeThoughts: true` to receive thought/reasoning content in the response.
132
137
  */
133
138
  interface GoogleThinkingConfig {
134
- /** Token budget allocated for model thinking/reasoning before response generation. */
139
+ /**
140
+ * Token budget allocated for model thinking/reasoning (Gemini 2.5 models).
141
+ * - `-1`: Dynamic thinking (default)
142
+ * - `0`: Disable thinking (Flash models only)
143
+ * - `128-32768`: Specific token budget
144
+ */
135
145
  thinkingBudget?: number;
146
+ /**
147
+ * Thinking level for Gemini 3+ models (recommended over thinkingBudget).
148
+ * - `"minimal"`: Likely prevents thinking (Gemini 3 Flash only)
149
+ * - `"low"`: Minimizes latency and cost
150
+ * - `"medium"`: Balanced (Gemini 3 Flash only)
151
+ * - `"high"`: Maximizes reasoning depth (default for Gemini 3)
152
+ */
153
+ thinkingLevel?: 'minimal' | 'low' | 'medium' | 'high';
154
+ /**
155
+ * Whether to include thought summaries in the response.
156
+ * When true, response parts with `thought: true` contain reasoning content.
157
+ */
158
+ includeThoughts?: boolean;
136
159
  }
137
160
  /**
138
161
  * A single content turn in the Google conversation format.
@@ -160,6 +183,14 @@ type GooglePart = GoogleTextPart | GoogleImagePart | GoogleFunctionCallPart | Go
160
183
  interface GoogleTextPart {
161
184
  /** The text content. */
162
185
  text: string;
186
+ /** If true, this part contains thinking/reasoning content (Gemini 2.5+/3+). */
187
+ thought?: boolean;
188
+ /**
189
+ * Encrypted thought signature for Gemini 3+ models.
190
+ * Must be forwarded back in subsequent requests to maintain reasoning context.
191
+ * Required for Gemini 3 multi-turn conversations; recommended for Gemini 2.5.
192
+ */
193
+ thoughtSignature?: string;
163
194
  }
164
195
  /**
165
196
  * Inline image content part with base64-encoded data.
@@ -893,6 +924,7 @@ interface GoogleEmbedParams {
893
924
  * ```typescript
894
925
  * import { google } from './providers/google';
895
926
  * import { llm } from './core/llm';
927
+ * import { StreamEventType } from './types/stream';
896
928
  *
897
929
  * const gemini = llm({
898
930
  * model: google('gemini-1.5-pro'),
@@ -904,7 +936,7 @@ interface GoogleEmbedParams {
904
936
  *
905
937
  * const stream = gemini.stream('Tell me a story');
906
938
  * for await (const event of stream) {
907
- * if (event.type === 'text_delta') {
939
+ * if (event.type === StreamEventType.TextDelta) {
908
940
  * process.stdout.write(event.delta.text ?? '');
909
941
  * }
910
942
  * }
@@ -3,27 +3,32 @@ import {
3
3
  } from "../chunk-WAKD3OO5.js";
4
4
  import {
5
5
  parseJsonResponse
6
- } from "../chunk-I2VHCGQE.js";
6
+ } from "../chunk-Z6DKC37J.js";
7
+ import {
8
+ StreamEventType
9
+ } from "../chunk-73IIE3QT.js";
7
10
  import {
8
11
  AssistantMessage,
9
12
  createProvider,
10
13
  isAssistantMessage,
11
14
  isToolResultMessage,
12
15
  isUserMessage
13
- } from "../chunk-M4BMM5IB.js";
16
+ } from "../chunk-6AZVUI6H.js";
14
17
  import {
15
18
  parseSSEStream
16
- } from "../chunk-NWS5IKNR.js";
19
+ } from "../chunk-TOJCZMVU.js";
17
20
  import {
18
21
  resolveApiKey
19
- } from "../chunk-7WYBJPJJ.js";
22
+ } from "../chunk-55X3W2MN.js";
20
23
  import {
24
+ ErrorCode,
25
+ ModalityType,
21
26
  UPPError,
22
27
  doFetch,
23
28
  doStreamFetch,
24
29
  normalizeHttpError,
25
30
  toError
26
- } from "../chunk-RFWLEFAB.js";
31
+ } from "../chunk-QNJO7DSD.js";
27
32
 
28
33
  // src/providers/google/transform.ts
29
34
  function transformRequest(request, modelId) {
@@ -80,9 +85,9 @@ function normalizeSystem(system) {
80
85
  if (!Array.isArray(system)) {
81
86
  throw new UPPError(
82
87
  "System prompt must be a string or an array of text parts",
83
- "INVALID_REQUEST",
88
+ ErrorCode.InvalidRequest,
84
89
  "google",
85
- "llm"
90
+ ModalityType.LLM
86
91
  );
87
92
  }
88
93
  const parts = [];
@@ -90,18 +95,18 @@ function normalizeSystem(system) {
90
95
  if (!part || typeof part !== "object" || !("text" in part)) {
91
96
  throw new UPPError(
92
97
  "Google system prompt array must contain text parts",
93
- "INVALID_REQUEST",
98
+ ErrorCode.InvalidRequest,
94
99
  "google",
95
- "llm"
100
+ ModalityType.LLM
96
101
  );
97
102
  }
98
103
  const textValue = part.text;
99
104
  if (typeof textValue !== "string") {
100
105
  throw new UPPError(
101
106
  "Google system prompt text must be a string",
102
- "INVALID_REQUEST",
107
+ ErrorCode.InvalidRequest,
103
108
  "google",
104
- "llm"
109
+ ModalityType.LLM
105
110
  );
106
111
  }
107
112
  parts.push(part);
@@ -142,8 +147,18 @@ function transformMessages(messages) {
142
147
  });
143
148
  } else if (isAssistantMessage(msg)) {
144
149
  const validContent = filterValidContent(msg.content);
145
- const parts = validContent.map(transformContentBlock);
150
+ const nonReasoningContent = validContent.filter((c) => c.type !== "reasoning");
151
+ const parts = nonReasoningContent.map(transformContentBlock);
146
152
  const googleMeta = msg.metadata?.google;
153
+ if (googleMeta?.thoughtSignature) {
154
+ for (let i = parts.length - 1; i >= 0; i--) {
155
+ const part = parts[i];
156
+ if (part && "text" in part) {
157
+ part.thoughtSignature = googleMeta.thoughtSignature;
158
+ break;
159
+ }
160
+ }
161
+ }
147
162
  if (googleMeta?.functionCallParts && googleMeta.functionCallParts.length > 0) {
148
163
  for (const fc of googleMeta.functionCallParts) {
149
164
  const part = {
@@ -231,17 +246,26 @@ function transformResponse(data) {
231
246
  if (!candidate) {
232
247
  throw new Error("No candidates in Google response");
233
248
  }
234
- const textContent = [];
249
+ const content = [];
235
250
  const toolCalls = [];
236
251
  let structuredData;
252
+ let lastThoughtSignature;
237
253
  const functionCallParts = [];
238
254
  for (const part of candidate.content.parts) {
239
255
  if ("text" in part) {
240
- textContent.push({ type: "text", text: part.text });
241
- if (structuredData === void 0) {
242
- try {
243
- structuredData = JSON.parse(part.text);
244
- } catch {
256
+ const textPart = part;
257
+ if (textPart.thoughtSignature) {
258
+ lastThoughtSignature = textPart.thoughtSignature;
259
+ }
260
+ if (textPart.thought) {
261
+ content.push({ type: "reasoning", text: textPart.text });
262
+ } else {
263
+ content.push({ type: "text", text: textPart.text });
264
+ if (structuredData === void 0) {
265
+ try {
266
+ structuredData = JSON.parse(textPart.text);
267
+ } catch {
268
+ }
245
269
  }
246
270
  }
247
271
  } else if ("functionCall" in part) {
@@ -260,7 +284,7 @@ function transformResponse(data) {
260
284
  } else if ("codeExecutionResult" in part) {
261
285
  const codeResult = part;
262
286
  if (codeResult.codeExecutionResult.output) {
263
- textContent.push({ type: "text", text: `
287
+ content.push({ type: "text", text: `
264
288
  \`\`\`
265
289
  ${codeResult.codeExecutionResult.output}\`\`\`
266
290
  ` });
@@ -268,14 +292,16 @@ ${codeResult.codeExecutionResult.output}\`\`\`
268
292
  }
269
293
  }
270
294
  const message = new AssistantMessage(
271
- textContent,
295
+ content,
272
296
  toolCalls.length > 0 ? toolCalls : void 0,
273
297
  {
274
298
  metadata: {
275
299
  google: {
276
300
  finishReason: candidate.finishReason,
277
301
  safetyRatings: candidate.safetyRatings,
278
- functionCallParts: functionCallParts.length > 0 ? functionCallParts : void 0
302
+ functionCallParts: functionCallParts.length > 0 ? functionCallParts : void 0,
303
+ // Store thoughtSignature for multi-turn context preservation (Gemini 3+)
304
+ thoughtSignature: lastThoughtSignature
279
305
  }
280
306
  }
281
307
  }
@@ -297,6 +323,8 @@ ${codeResult.codeExecutionResult.output}\`\`\`
297
323
  function createStreamState() {
298
324
  return {
299
325
  content: "",
326
+ reasoning: "",
327
+ thoughtSignature: void 0,
300
328
  toolCalls: [],
301
329
  finishReason: null,
302
330
  inputTokens: 0,
@@ -308,7 +336,7 @@ function createStreamState() {
308
336
  function transformStreamChunk(chunk, state) {
309
337
  const events = [];
310
338
  if (state.isFirstChunk) {
311
- events.push({ type: "message_start", index: 0, delta: {} });
339
+ events.push({ type: StreamEventType.MessageStart, index: 0, delta: {} });
312
340
  state.isFirstChunk = false;
313
341
  }
314
342
  if (chunk.usageMetadata) {
@@ -322,12 +350,25 @@ function transformStreamChunk(chunk, state) {
322
350
  }
323
351
  for (const part of candidate.content?.parts ?? []) {
324
352
  if ("text" in part) {
325
- state.content += part.text;
326
- events.push({
327
- type: "text_delta",
328
- index: 0,
329
- delta: { text: part.text }
330
- });
353
+ const textPart = part;
354
+ if (textPart.thoughtSignature) {
355
+ state.thoughtSignature = textPart.thoughtSignature;
356
+ }
357
+ if (textPart.thought) {
358
+ state.reasoning += textPart.text;
359
+ events.push({
360
+ type: StreamEventType.ReasoningDelta,
361
+ index: 0,
362
+ delta: { text: textPart.text }
363
+ });
364
+ } else {
365
+ state.content += textPart.text;
366
+ events.push({
367
+ type: StreamEventType.TextDelta,
368
+ index: 0,
369
+ delta: { text: textPart.text }
370
+ });
371
+ }
331
372
  } else if ("functionCall" in part) {
332
373
  const fc = part;
333
374
  const toolCallId = createGoogleToolCallId(fc.functionCall.name, state.toolCalls.length);
@@ -338,7 +379,7 @@ function transformStreamChunk(chunk, state) {
338
379
  thoughtSignature: fc.thoughtSignature
339
380
  });
340
381
  events.push({
341
- type: "tool_call_delta",
382
+ type: StreamEventType.ToolCallDelta,
342
383
  index: state.toolCalls.length - 1,
343
384
  delta: {
344
385
  toolCallId,
@@ -355,7 +396,7 @@ ${codeResult.codeExecutionResult.output}\`\`\`
355
396
  `;
356
397
  state.content += outputText;
357
398
  events.push({
358
- type: "text_delta",
399
+ type: StreamEventType.TextDelta,
359
400
  index: 0,
360
401
  delta: { text: outputText }
361
402
  });
@@ -364,17 +405,20 @@ ${codeResult.codeExecutionResult.output}\`\`\`
364
405
  }
365
406
  if (candidate.finishReason) {
366
407
  state.finishReason = candidate.finishReason;
367
- events.push({ type: "message_stop", index: 0, delta: {} });
408
+ events.push({ type: StreamEventType.MessageStop, index: 0, delta: {} });
368
409
  }
369
410
  return events;
370
411
  }
371
412
  function buildResponseFromState(state) {
372
- const textContent = [];
413
+ const content = [];
373
414
  const toolCalls = [];
374
415
  let structuredData;
375
416
  const functionCallParts = [];
417
+ if (state.reasoning) {
418
+ content.push({ type: "reasoning", text: state.reasoning });
419
+ }
376
420
  if (state.content) {
377
- textContent.push({ type: "text", text: state.content });
421
+ content.push({ type: "text", text: state.content });
378
422
  try {
379
423
  structuredData = JSON.parse(state.content);
380
424
  } catch {
@@ -394,13 +438,14 @@ function buildResponseFromState(state) {
394
438
  });
395
439
  }
396
440
  const message = new AssistantMessage(
397
- textContent,
441
+ content,
398
442
  toolCalls.length > 0 ? toolCalls : void 0,
399
443
  {
400
444
  metadata: {
401
445
  google: {
402
446
  finishReason: state.finishReason,
403
- functionCallParts: functionCallParts.length > 0 ? functionCallParts : void 0
447
+ functionCallParts: functionCallParts.length > 0 ? functionCallParts : void 0,
448
+ thoughtSignature: state.thoughtSignature
404
449
  }
405
450
  }
406
451
  }
@@ -458,9 +503,9 @@ function createLLMHandler() {
458
503
  if (!providerRef) {
459
504
  throw new UPPError(
460
505
  "Provider reference not set. Handler must be used with createProvider().",
461
- "INVALID_REQUEST",
506
+ ErrorCode.InvalidRequest,
462
507
  "google",
463
- "llm"
508
+ ModalityType.LLM
464
509
  );
465
510
  }
466
511
  const model = {
@@ -554,9 +599,9 @@ function createLLMHandler() {
554
599
  if (!response.body) {
555
600
  const error = new UPPError(
556
601
  "No response body for streaming request",
557
- "PROVIDER_ERROR",
602
+ ErrorCode.ProviderError,
558
603
  "google",
559
- "llm"
604
+ ModalityType.LLM
560
605
  );
561
606
  responseReject(error);
562
607
  throw error;
@@ -567,9 +612,9 @@ function createLLMHandler() {
567
612
  if (chunk.error) {
568
613
  const error = new UPPError(
569
614
  chunk.error.message,
570
- "PROVIDER_ERROR",
615
+ ErrorCode.ProviderError,
571
616
  "google",
572
- "llm"
617
+ ModalityType.LLM
573
618
  );
574
619
  responseReject(error);
575
620
  throw error;
@@ -613,9 +658,9 @@ function createEmbeddingHandler() {
613
658
  if (!providerRef) {
614
659
  throw new UPPError(
615
660
  "Provider reference not set. Handler must be used with createProvider().",
616
- "INVALID_REQUEST",
661
+ ErrorCode.InvalidRequest,
617
662
  "google",
618
- "embedding"
663
+ ModalityType.Embedding
619
664
  );
620
665
  }
621
666
  const model = {
@@ -639,9 +684,9 @@ function createEmbeddingHandler() {
639
684
  if (!text) {
640
685
  throw new UPPError(
641
686
  "Google embeddings only support text input",
642
- "INVALID_REQUEST",
687
+ ErrorCode.InvalidRequest,
643
688
  "google",
644
- "embedding"
689
+ ModalityType.Embedding
645
690
  );
646
691
  }
647
692
  const embedRequest = {
@@ -713,9 +758,9 @@ function createImageHandler() {
713
758
  if (!providerRef) {
714
759
  throw new UPPError(
715
760
  "Provider reference not set. Handler must be used with createProvider().",
716
- "INVALID_REQUEST",
761
+ ErrorCode.InvalidRequest,
717
762
  "google",
718
- "image"
763
+ ModalityType.Image
719
764
  );
720
765
  }
721
766
  const capabilities = getCapabilities();
@@ -775,9 +820,9 @@ function transformResponse2(data) {
775
820
  if (!data.predictions || data.predictions.length === 0) {
776
821
  throw new UPPError(
777
822
  "No images in response",
778
- "PROVIDER_ERROR",
823
+ ErrorCode.ProviderError,
779
824
  "google",
780
- "image"
825
+ ModalityType.Image
781
826
  );
782
827
  }
783
828
  const images = data.predictions.map((prediction) => {
@@ -922,9 +967,9 @@ async function update(name, updateRequest, apiKey, config, signal) {
922
967
  if (updateRequest.expireTime && updateRequest.ttl) {
923
968
  throw new UPPError(
924
969
  "Provide either expireTime or ttl (not both)",
925
- "INVALID_REQUEST",
970
+ ErrorCode.InvalidRequest,
926
971
  "google",
927
- "llm"
972
+ ModalityType.LLM
928
973
  );
929
974
  }
930
975
  const updateMaskParts = [];
@@ -937,9 +982,9 @@ async function update(name, updateRequest, apiKey, config, signal) {
937
982
  if (updateMaskParts.length === 0) {
938
983
  throw new UPPError(
939
984
  "Update request must include expireTime or ttl",
940
- "INVALID_REQUEST",
985
+ ErrorCode.InvalidRequest,
941
986
  "google",
942
- "llm"
987
+ ModalityType.LLM
943
988
  );
944
989
  }
945
990
  const cacheName = name.startsWith("cachedContents/") ? name : `cachedContents/${name}`;