@mariozechner/pi-ai 0.13.2 → 0.14.1

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/README.md CHANGED
@@ -194,8 +194,8 @@ const response = await complete(model, context);
194
194
  // Check for tool calls in the response
195
195
  for (const block of response.content) {
196
196
  if (block.type === 'toolCall') {
197
- // Arguments are automatically validated against the TypeBox schema using AJV
198
- // If validation fails, an error event is emitted
197
+ // Execute your tool with the arguments
198
+ // See "Validating Tool Arguments" section for validation
199
199
  const result = await executeWeatherApi(block.arguments);
200
200
 
201
201
  // Add tool result with text content
@@ -253,7 +253,7 @@ for await (const event of s) {
253
253
  }
254
254
 
255
255
  if (event.type === 'toolcall_end') {
256
- // Here toolCall.arguments is complete and validated
256
+ // Here toolCall.arguments is complete (but not yet validated)
257
257
  const toolCall = event.toolCall;
258
258
  console.log(`Tool completed: ${toolCall.name}`, toolCall.arguments);
259
259
  }
@@ -267,9 +267,44 @@ for await (const event of s) {
267
267
  - Arrays may be incomplete
268
268
  - Nested objects may be partially populated
269
269
  - At minimum, `arguments` will be an empty object `{}`, never `undefined`
270
- - Full validation only occurs at `toolcall_end` when arguments are complete
271
270
  - The Google provider does not support function call streaming. Instead, you will receive a single `toolcall_delta` event with the full arguments.
272
271
 
272
+ ### Validating Tool Arguments
273
+
274
+ When using `agentLoop`, tool arguments are automatically validated against your TypeBox schemas before execution. If validation fails, the error is returned to the model as a tool result, allowing it to retry.
275
+
276
+ When implementing your own tool execution loop with `stream()` or `complete()`, use `validateToolCall` to validate arguments before passing them to your tools:
277
+
278
+ ```typescript
279
+ import { stream, validateToolCall, Tool } from '@mariozechner/pi-ai';
280
+
281
+ const tools: Tool[] = [weatherTool, calculatorTool];
282
+ const s = stream(model, { messages, tools });
283
+
284
+ for await (const event of s) {
285
+ if (event.type === 'toolcall_end') {
286
+ const toolCall = event.toolCall;
287
+
288
+ try {
289
+ // Validate arguments against the tool's schema (throws on invalid args)
290
+ const validatedArgs = validateToolCall(tools, toolCall);
291
+ const result = await executeMyTool(toolCall.name, validatedArgs);
292
+ // ... add tool result to context
293
+ } catch (error) {
294
+ // Validation failed - return error as tool result so model can retry
295
+ context.messages.push({
296
+ role: 'toolResult',
297
+ toolCallId: toolCall.id,
298
+ toolName: toolCall.name,
299
+ content: [{ type: 'text', text: error.message }],
300
+ isError: true,
301
+ timestamp: Date.now()
302
+ });
303
+ }
304
+ }
305
+ }
306
+ ```
307
+
273
308
  ### Complete Event Reference
274
309
 
275
310
  All streaming events emitted during assistant message generation:
@@ -352,7 +387,7 @@ if (model.reasoning) {
352
387
  const response = await completeSimple(model, {
353
388
  messages: [{ role: 'user', content: 'Solve: 2x + 5 = 13' }]
354
389
  }, {
355
- reasoning: 'medium' // 'minimal' | 'low' | 'medium' | 'high'
390
+ reasoning: 'medium' // 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' (xhigh maps to high on non-OpenAI providers)
356
391
  });
357
392
 
358
393
  // Access thinking and text blocks
@@ -576,6 +611,23 @@ const ollamaModel: Model<'openai-completions'> = {
576
611
  maxTokens: 32000
577
612
  };
578
613
 
614
+ // Example: LiteLLM proxy with explicit compat settings
615
+ const litellmModel: Model<'openai-completions'> = {
616
+ id: 'gpt-4o',
617
+ name: 'GPT-4o (via LiteLLM)',
618
+ api: 'openai-completions',
619
+ provider: 'litellm',
620
+ baseUrl: 'http://localhost:4000/v1',
621
+ reasoning: false,
622
+ input: ['text', 'image'],
623
+ cost: { input: 2.5, output: 10, cacheRead: 0, cacheWrite: 0 },
624
+ contextWindow: 128000,
625
+ maxTokens: 16384,
626
+ compat: {
627
+ supportsStore: false, // LiteLLM doesn't support the store field
628
+ }
629
+ };
630
+
579
631
  // Example: Custom endpoint with headers (bypassing Cloudflare bot detection)
580
632
  const proxyModel: Model<'anthropic-messages'> = {
581
633
  id: 'claude-sonnet-4',
@@ -600,6 +652,25 @@ const response = await stream(ollamaModel, context, {
600
652
  });
601
653
  ```
602
654
 
655
+ ### OpenAI Compatibility Settings
656
+
657
+ The `openai-completions` API is implemented by many providers with minor differences. By default, the library auto-detects compatibility settings based on `baseUrl` for known providers (Cerebras, xAI, Mistral, Chutes, etc.). For custom proxies or unknown endpoints, you can override these settings via the `compat` field:
658
+
659
+ ```typescript
660
+ interface OpenAICompat {
661
+ supportsStore?: boolean; // Whether provider supports the `store` field (default: true)
662
+ supportsDeveloperRole?: boolean; // Whether provider supports `developer` role vs `system` (default: true)
663
+ supportsReasoningEffort?: boolean; // Whether provider supports `reasoning_effort` (default: true)
664
+ maxTokensField?: 'max_completion_tokens' | 'max_tokens'; // Which field name to use (default: max_completion_tokens)
665
+ }
666
+ ```
667
+
668
+ If `compat` is not set, the library falls back to URL-based detection. If `compat` is partially set, unspecified fields use the detected defaults. This is useful for:
669
+
670
+ - **LiteLLM proxies**: May not support `store` field
671
+ - **Custom inference servers**: May use non-standard field names
672
+ - **Self-hosted endpoints**: May have different feature support
673
+
603
674
  ### Type Safety
604
675
 
605
676
  Models are typed by their API, ensuring type-safe options:
package/dist/index.d.ts CHANGED
@@ -8,4 +8,5 @@ export * from "./stream.js";
8
8
  export * from "./types.js";
9
9
  export * from "./utils/overflow.js";
10
10
  export * from "./utils/typebox-helpers.js";
11
+ export * from "./utils/validation.js";
11
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC","sourcesContent":["export * from \"./agent/index.js\";\nexport * from \"./models.js\";\nexport * from \"./providers/anthropic.js\";\nexport * from \"./providers/google.js\";\nexport * from \"./providers/openai-completions.js\";\nexport * from \"./providers/openai-responses.js\";\nexport * from \"./stream.js\";\nexport * from \"./types.js\";\nexport * from \"./utils/overflow.js\";\nexport * from \"./utils/typebox-helpers.js\";\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC","sourcesContent":["export * from \"./agent/index.js\";\nexport * from \"./models.js\";\nexport * from \"./providers/anthropic.js\";\nexport * from \"./providers/google.js\";\nexport * from \"./providers/openai-completions.js\";\nexport * from \"./providers/openai-responses.js\";\nexport * from \"./stream.js\";\nexport * from \"./types.js\";\nexport * from \"./utils/overflow.js\";\nexport * from \"./utils/typebox-helpers.js\";\nexport * from \"./utils/validation.js\";\n"]}
package/dist/index.js CHANGED
@@ -8,4 +8,5 @@ export * from "./stream.js";
8
8
  export * from "./types.js";
9
9
  export * from "./utils/overflow.js";
10
10
  export * from "./utils/typebox-helpers.js";
11
+ export * from "./utils/validation.js";
11
12
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC","sourcesContent":["export * from \"./agent/index.js\";\nexport * from \"./models.js\";\nexport * from \"./providers/anthropic.js\";\nexport * from \"./providers/google.js\";\nexport * from \"./providers/openai-completions.js\";\nexport * from \"./providers/openai-responses.js\";\nexport * from \"./stream.js\";\nexport * from \"./types.js\";\nexport * from \"./utils/overflow.js\";\nexport * from \"./utils/typebox-helpers.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC","sourcesContent":["export * from \"./agent/index.js\";\nexport * from \"./models.js\";\nexport * from \"./providers/anthropic.js\";\nexport * from \"./providers/google.js\";\nexport * from \"./providers/openai-completions.js\";\nexport * from \"./providers/openai-responses.js\";\nexport * from \"./stream.js\";\nexport * from \"./types.js\";\nexport * from \"./utils/overflow.js\";\nexport * from \"./utils/typebox-helpers.js\";\nexport * from \"./utils/validation.js\";\n"]}
@@ -1986,6 +1986,23 @@ export declare const MODELS: {
1986
1986
  };
1987
1987
  };
1988
1988
  readonly openrouter: {
1989
+ readonly "relace/relace-search": {
1990
+ id: string;
1991
+ name: string;
1992
+ api: "openai-completions";
1993
+ provider: string;
1994
+ baseUrl: string;
1995
+ reasoning: false;
1996
+ input: "text"[];
1997
+ cost: {
1998
+ input: number;
1999
+ output: number;
2000
+ cacheRead: number;
2001
+ cacheWrite: number;
2002
+ };
2003
+ contextWindow: number;
2004
+ maxTokens: number;
2005
+ };
1989
2006
  readonly "openai/gpt-5.1-codex-max": {
1990
2007
  id: string;
1991
2008
  name: string;
@@ -3958,23 +3975,6 @@ export declare const MODELS: {
3958
3975
  contextWindow: number;
3959
3976
  maxTokens: number;
3960
3977
  };
3961
- readonly "mistralai/magistral-medium-2506:thinking": {
3962
- id: string;
3963
- name: string;
3964
- api: "openai-completions";
3965
- provider: string;
3966
- baseUrl: string;
3967
- reasoning: true;
3968
- input: "text"[];
3969
- cost: {
3970
- input: number;
3971
- output: number;
3972
- cacheRead: number;
3973
- cacheWrite: number;
3974
- };
3975
- contextWindow: number;
3976
- maxTokens: number;
3977
- };
3978
3978
  readonly "google/gemini-2.5-pro-preview": {
3979
3979
  id: string;
3980
3980
  name: string;
@@ -5148,7 +5148,7 @@ export declare const MODELS: {
5148
5148
  contextWindow: number;
5149
5149
  maxTokens: number;
5150
5150
  };
5151
- readonly "cohere/command-r-plus-08-2024": {
5151
+ readonly "cohere/command-r-08-2024": {
5152
5152
  id: string;
5153
5153
  name: string;
5154
5154
  api: "openai-completions";
@@ -5165,7 +5165,7 @@ export declare const MODELS: {
5165
5165
  contextWindow: number;
5166
5166
  maxTokens: number;
5167
5167
  };
5168
- readonly "cohere/command-r-08-2024": {
5168
+ readonly "cohere/command-r-plus-08-2024": {
5169
5169
  id: string;
5170
5170
  name: string;
5171
5171
  api: "openai-completions";
@@ -5250,7 +5250,7 @@ export declare const MODELS: {
5250
5250
  contextWindow: number;
5251
5251
  maxTokens: number;
5252
5252
  };
5253
- readonly "meta-llama/llama-3.1-70b-instruct": {
5253
+ readonly "meta-llama/llama-3.1-405b-instruct": {
5254
5254
  id: string;
5255
5255
  name: string;
5256
5256
  api: "openai-completions";
@@ -5267,7 +5267,7 @@ export declare const MODELS: {
5267
5267
  contextWindow: number;
5268
5268
  maxTokens: number;
5269
5269
  };
5270
- readonly "meta-llama/llama-3.1-405b-instruct": {
5270
+ readonly "meta-llama/llama-3.1-70b-instruct": {
5271
5271
  id: string;
5272
5272
  name: string;
5273
5273
  api: "openai-completions";
@@ -5301,7 +5301,7 @@ export declare const MODELS: {
5301
5301
  contextWindow: number;
5302
5302
  maxTokens: number;
5303
5303
  };
5304
- readonly "openai/gpt-4o-mini": {
5304
+ readonly "openai/gpt-4o-mini-2024-07-18": {
5305
5305
  id: string;
5306
5306
  name: string;
5307
5307
  api: "openai-completions";
@@ -5318,7 +5318,7 @@ export declare const MODELS: {
5318
5318
  contextWindow: number;
5319
5319
  maxTokens: number;
5320
5320
  };
5321
- readonly "openai/gpt-4o-mini-2024-07-18": {
5321
+ readonly "openai/gpt-4o-mini": {
5322
5322
  id: string;
5323
5323
  name: string;
5324
5324
  api: "openai-completions";
@@ -5420,7 +5420,7 @@ export declare const MODELS: {
5420
5420
  contextWindow: number;
5421
5421
  maxTokens: number;
5422
5422
  };
5423
- readonly "openai/gpt-4o": {
5423
+ readonly "openai/gpt-4o-2024-05-13": {
5424
5424
  id: string;
5425
5425
  name: string;
5426
5426
  api: "openai-completions";
@@ -5437,7 +5437,7 @@ export declare const MODELS: {
5437
5437
  contextWindow: number;
5438
5438
  maxTokens: number;
5439
5439
  };
5440
- readonly "openai/gpt-4o:extended": {
5440
+ readonly "openai/gpt-4o": {
5441
5441
  id: string;
5442
5442
  name: string;
5443
5443
  api: "openai-completions";
@@ -5454,7 +5454,7 @@ export declare const MODELS: {
5454
5454
  contextWindow: number;
5455
5455
  maxTokens: number;
5456
5456
  };
5457
- readonly "openai/gpt-4o-2024-05-13": {
5457
+ readonly "openai/gpt-4o:extended": {
5458
5458
  id: string;
5459
5459
  name: string;
5460
5460
  api: "openai-completions";
@@ -5471,7 +5471,7 @@ export declare const MODELS: {
5471
5471
  contextWindow: number;
5472
5472
  maxTokens: number;
5473
5473
  };
5474
- readonly "meta-llama/llama-3-8b-instruct": {
5474
+ readonly "meta-llama/llama-3-70b-instruct": {
5475
5475
  id: string;
5476
5476
  name: string;
5477
5477
  api: "openai-completions";
@@ -5488,7 +5488,7 @@ export declare const MODELS: {
5488
5488
  contextWindow: number;
5489
5489
  maxTokens: number;
5490
5490
  };
5491
- readonly "meta-llama/llama-3-70b-instruct": {
5491
+ readonly "meta-llama/llama-3-8b-instruct": {
5492
5492
  id: string;
5493
5493
  name: string;
5494
5494
  api: "openai-completions";
@@ -5590,7 +5590,7 @@ export declare const MODELS: {
5590
5590
  contextWindow: number;
5591
5591
  maxTokens: number;
5592
5592
  };
5593
- readonly "openai/gpt-4-turbo-preview": {
5593
+ readonly "openai/gpt-3.5-turbo-0613": {
5594
5594
  id: string;
5595
5595
  name: string;
5596
5596
  api: "openai-completions";
@@ -5607,7 +5607,7 @@ export declare const MODELS: {
5607
5607
  contextWindow: number;
5608
5608
  maxTokens: number;
5609
5609
  };
5610
- readonly "openai/gpt-3.5-turbo-0613": {
5610
+ readonly "openai/gpt-4-turbo-preview": {
5611
5611
  id: string;
5612
5612
  name: string;
5613
5613
  api: "openai-completions";