@oh-my-pi/pi-ai 9.4.0 → 9.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-ai",
3
- "version": "9.4.0",
3
+ "version": "9.6.0",
4
4
  "description": "Unified LLM API with automatic model discovery and provider configuration",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -63,7 +63,7 @@
63
63
  "@connectrpc/connect-node": "^2.1.1",
64
64
  "@google/genai": "^1.38.0",
65
65
  "@mistralai/mistralai": "^1.13.0",
66
- "@oh-my-pi/pi-utils": "9.4.0",
66
+ "@oh-my-pi/pi-utils": "9.6.0",
67
67
  "@sinclair/typebox": "^0.34.48",
68
68
  "@smithy/node-http-handler": "^4.4.8",
69
69
  "ajv": "^8.17.1",
@@ -208,7 +208,7 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
208
208
  type: "toolCall",
209
209
  id: event.content_block.id,
210
210
  name: isOAuthToken ? fromClaudeCodeName(event.content_block.name) : event.content_block.name,
211
- arguments: event.content_block.input as Record<string, any>,
211
+ arguments: (event.content_block.input as Record<string, any>) ?? {},
212
212
  partialJson: "",
213
213
  index: event.index,
214
214
  };
@@ -842,7 +842,7 @@ function convertMessages(
842
842
  type: "tool_use",
843
843
  id: sanitizeToolCallId(block.id),
844
844
  name: isOAuthToken ? toClaudeCodeName(block.name) : block.name,
845
- input: block.arguments,
845
+ input: block.arguments ?? {},
846
846
  });
847
847
  }
848
848
  }
@@ -53,8 +53,9 @@ function normalizeMistralToolId(id: string, isMistral: boolean): string {
53
53
  return normalized;
54
54
  }
55
55
 
56
- type ResolvedOpenAICompat = Required<Omit<OpenAICompat, "openRouterRouting">> & {
56
+ type ResolvedOpenAICompat = Required<Omit<OpenAICompat, "openRouterRouting" | "vercelGatewayRouting">> & {
57
57
  openRouterRouting?: OpenAICompat["openRouterRouting"];
58
+ vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"];
58
59
  };
59
60
 
60
61
  /**
@@ -454,6 +455,17 @@ function buildParams(model: Model<"openai-completions">, context: Context, optio
454
455
  (params as { provider?: unknown }).provider = compat.openRouterRouting;
455
456
  }
456
457
 
458
+ // Vercel AI Gateway provider routing preferences
459
+ if (model.baseUrl.includes("ai-gateway.vercel.sh") && model.compat?.vercelGatewayRouting) {
460
+ const routing = model.compat.vercelGatewayRouting;
461
+ if (routing.only || routing.order) {
462
+ const gatewayOptions: Record<string, string[]> = {};
463
+ if (routing.only) gatewayOptions.only = routing.only;
464
+ if (routing.order) gatewayOptions.order = routing.order;
465
+ (params as any).providerOptions = { gateway: gatewayOptions };
466
+ }
467
+ }
468
+
457
469
  return params;
458
470
  }
459
471
 
@@ -822,6 +834,7 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAICompat
822
834
  requiresReasoningContentForToolCalls: isOpenRouterKimi,
823
835
  requiresAssistantContentForToolCalls: isOpenRouterKimi,
824
836
  openRouterRouting: undefined,
837
+ vercelGatewayRouting: undefined,
825
838
  };
826
839
  }
827
840
 
@@ -852,5 +865,6 @@ function getCompat(model: Model<"openai-completions">): ResolvedOpenAICompat {
852
865
  requiresAssistantContentForToolCalls:
853
866
  model.compat.requiresAssistantContentForToolCalls ?? detected.requiresAssistantContentForToolCalls,
854
867
  openRouterRouting: model.compat.openRouterRouting ?? detected.openRouterRouting,
868
+ vercelGatewayRouting: model.compat.vercelGatewayRouting ?? detected.vercelGatewayRouting,
855
869
  };
856
870
  }
package/src/types.ts CHANGED
@@ -320,6 +320,8 @@ export interface OpenAICompat {
320
320
  supportsToolChoice?: boolean;
321
321
  /** OpenRouter-specific routing preferences. Only used when baseUrl points to OpenRouter. */
322
322
  openRouterRouting?: OpenRouterRouting;
323
+ /** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */
324
+ vercelGatewayRouting?: VercelGatewayRouting;
323
325
  }
324
326
 
325
327
  /**
@@ -334,6 +336,18 @@ export interface OpenRouterRouting {
334
336
  order?: string[];
335
337
  }
336
338
 
339
+ /**
340
+ * Vercel AI Gateway routing preferences.
341
+ * Controls which upstream providers the gateway routes requests to.
342
+ * @see https://vercel.com/docs/ai-gateway/models-and-providers/provider-options
343
+ */
344
+ export interface VercelGatewayRouting {
345
+ /** List of provider slugs to exclusively use for this request (e.g., ["bedrock", "anthropic"]). */
346
+ only?: string[];
347
+ /** List of provider slugs to try in order (e.g., ["anthropic", "openai"]). */
348
+ order?: string[];
349
+ }
350
+
337
351
  // Model interface for the unified model system
338
352
  export interface Model<TApi extends Api> {
339
353
  id: string;