@oh-my-pi/pi-ai 14.4.0 → 14.4.3

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,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-ai",
4
- "version": "14.4.0",
4
+ "version": "14.4.3",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://github.com/can1357/oh-my-pi",
7
7
  "author": "Can Boluk",
@@ -46,8 +46,8 @@
46
46
  "@aws-sdk/credential-provider-node": "^3.972.36",
47
47
  "@bufbuild/protobuf": "^2.12.0",
48
48
  "@google/genai": "^1.50.1",
49
- "@oh-my-pi/pi-natives": "14.4.0",
50
- "@oh-my-pi/pi-utils": "14.4.0",
49
+ "@oh-my-pi/pi-natives": "14.4.3",
50
+ "@oh-my-pi/pi-utils": "14.4.3",
51
51
  "@sinclair/typebox": "^0.34.49",
52
52
  "@smithy/node-http-handler": "^4.6.1",
53
53
  "ajv": "^8.20.0",
@@ -84,7 +84,6 @@ export function buildBetaHeader(baseBetas: string[], extraBetas: string[]): stri
84
84
  const claudeCodeBetaDefaults = [
85
85
  "claude-code-20250219",
86
86
  "oauth-2025-04-20",
87
- "interleaved-thinking-2025-05-14",
88
87
  "context-management-2025-06-27",
89
88
  "prompt-caching-scope-2026-01-05",
90
89
  ];
@@ -1160,6 +1159,7 @@ export function buildAnthropicClientOptions(args: AnthropicClientOptionsArgs): A
1160
1159
  dynamicHeaders,
1161
1160
  isOAuth,
1162
1161
  } = args;
1162
+ const needsInterleavedBeta = interleavedThinking && !supportsAdaptiveThinkingDisplay(model.id);
1163
1163
  const oauthToken = isOAuth ?? isAnthropicOAuthToken(apiKey);
1164
1164
  const baseUrl = resolveAnthropicBaseUrl(model, apiKey);
1165
1165
  const foundryCustomHeaders = resolveAnthropicCustomHeaders(model);
@@ -1193,7 +1193,7 @@ export function buildAnthropicClientOptions(args: AnthropicClientOptionsArgs): A
1193
1193
  }
1194
1194
 
1195
1195
  const betaFeatures = [...extraBetas];
1196
- if (interleavedThinking) {
1196
+ if (needsInterleavedBeta) {
1197
1197
  betaFeatures.push("interleaved-thinking-2025-05-14");
1198
1198
  }
1199
1199
 
@@ -1498,9 +1498,6 @@ function buildParams(
1498
1498
  stream: true,
1499
1499
  };
1500
1500
 
1501
- if (options?.temperature !== undefined) {
1502
- params.temperature = options.temperature;
1503
- }
1504
1501
  if (options?.topP !== undefined) {
1505
1502
  params.top_p = options.topP;
1506
1503
  }
@@ -1510,13 +1507,16 @@ function buildParams(
1510
1507
 
1511
1508
  // Opus 4.7+ rejects non-default sampling parameters with 400 error.
1512
1509
  if (hasOpus47ApiRestrictions(model.id)) {
1513
- delete params.temperature;
1514
- delete (params as AnthropicSamplingParams).top_p;
1515
- delete (params as AnthropicSamplingParams).top_k;
1510
+ delete params.top_p;
1511
+ delete params.top_k;
1516
1512
  }
1517
1513
 
1518
1514
  if (context.tools) {
1519
- params.tools = convertTools(context.tools, isOAuthToken, disableStrictTools);
1515
+ params.tools = convertTools(
1516
+ context.tools,
1517
+ isOAuthToken,
1518
+ disableStrictTools || model.provider === "github-copilot",
1519
+ );
1520
1520
  }
1521
1521
 
1522
1522
  if (options?.thinkingEnabled && model.reasoning && model.provider !== "github-copilot") {
@@ -10,11 +10,11 @@ import {
10
10
  type Api,
11
11
  type AssistantMessage,
12
12
  type Context,
13
- isSpecialServiceTier,
14
13
  type Model,
15
14
  type ServiceTier,
16
15
  type StreamFunction,
17
16
  type StreamOptions,
17
+ shouldSendServiceTier,
18
18
  type Tool,
19
19
  type ToolChoice,
20
20
  } from "../types";
@@ -298,7 +298,7 @@ function buildParams(
298
298
  if (options?.repetitionPenalty !== undefined) {
299
299
  params.repetition_penalty = options.repetitionPenalty;
300
300
  }
301
- if (isSpecialServiceTier(options?.serviceTier)) {
301
+ if (shouldSendServiceTier(options?.serviceTier, model.provider)) {
302
302
  params.service_tier = options.serviceTier;
303
303
  }
304
304
 
@@ -19,12 +19,12 @@ import {
19
19
  type Api,
20
20
  type AssistantMessage,
21
21
  type Context,
22
- isSpecialServiceTier,
23
22
  type Model,
24
23
  type ProviderSessionState,
25
24
  type ServiceTier,
26
25
  type StreamFunction,
27
26
  type StreamOptions,
27
+ shouldSendServiceTier,
28
28
  type TextContent,
29
29
  type ThinkingContent,
30
30
  type Tool,
@@ -493,7 +493,7 @@ async function buildTransformedCodexRequestBody(
493
493
  if (options?.repetitionPenalty !== undefined) {
494
494
  params.repetition_penalty = options.repetitionPenalty;
495
495
  }
496
- if (isSpecialServiceTier(options?.serviceTier)) {
496
+ if (shouldSendServiceTier(options?.serviceTier, model.provider)) {
497
497
  params.service_tier = options.serviceTier;
498
498
  }
499
499
  if (context.tools && context.tools.length > 0) {
@@ -14,7 +14,6 @@ import { getEnvApiKey } from "../stream";
14
14
  import {
15
15
  type AssistantMessage,
16
16
  type Context,
17
- isSpecialServiceTier,
18
17
  type Message,
19
18
  type MessageAttribution,
20
19
  type Model,
@@ -23,6 +22,7 @@ import {
23
22
  type StopReason,
24
23
  type StreamFunction,
25
24
  type StreamOptions,
25
+ shouldSendServiceTier,
26
26
  type TextContent,
27
27
  type ThinkingContent,
28
28
  type Tool,
@@ -811,7 +811,7 @@ function buildParams(
811
811
  if (options?.repetitionPenalty !== undefined) {
812
812
  params.repetition_penalty = options.repetitionPenalty;
813
813
  }
814
- if (isSpecialServiceTier(options?.serviceTier)) {
814
+ if (shouldSendServiceTier(options?.serviceTier, model.provider)) {
815
815
  params.service_tier = options.serviceTier;
816
816
  }
817
817
 
@@ -11,13 +11,13 @@ import {
11
11
  type AssistantMessage,
12
12
  type CacheRetention,
13
13
  type Context,
14
- isSpecialServiceTier,
15
14
  type MessageAttribution,
16
15
  type Model,
17
16
  type ProviderSessionState,
18
17
  type ServiceTier,
19
18
  type StreamFunction,
20
19
  type StreamOptions,
20
+ shouldSendServiceTier,
21
21
  type Tool,
22
22
  type ToolChoice,
23
23
  } from "../types";
@@ -384,7 +384,7 @@ function buildParams(
384
384
  if (options?.repetitionPenalty !== undefined) {
385
385
  params.repetition_penalty = options.repetitionPenalty;
386
386
  }
387
- if (isSpecialServiceTier(options?.serviceTier)) {
387
+ if (shouldSendServiceTier(options?.serviceTier, model.provider)) {
388
388
  params.service_tier = options.serviceTier;
389
389
  }
390
390
 
package/src/types.ts CHANGED
@@ -152,7 +152,13 @@ export type CacheRetention = "none" | "short" | "long";
152
152
  /** OpenAI service tier for processing priority. Only applies to OpenAI-compatible APIs. */
153
153
  export type ServiceTier = "auto" | "default" | "flex" | "scale" | "priority";
154
154
 
155
- export function isSpecialServiceTier(serviceTier?: ServiceTier | null): serviceTier is "flex" | "scale" | "priority" {
155
+ export function shouldSendServiceTier(
156
+ serviceTier?: ServiceTier | null,
157
+ provider?: Provider,
158
+ ): serviceTier is "flex" | "scale" | "priority" {
159
+ if (provider !== "openai" && provider !== "openai-codex") {
160
+ return false;
161
+ }
156
162
  return serviceTier === "flex" || serviceTier === "scale" || serviceTier === "priority";
157
163
  }
158
164
 
@@ -585,6 +585,26 @@ function normalizeOptionalNullsForSchema(schema: unknown, value: unknown): { val
585
585
  nextValue[key] = normalized.value;
586
586
  }
587
587
 
588
+ // Strip unknown keys with null/"null" values when the schema forbids extras.
589
+ // LLMs sometimes hallucinate verbs alongside valid ones (e.g. `split: null`,
590
+ // `original: null`). Rejecting the entire tool call wastes a turn; treating
591
+ // these the same as null on known optional fields is a safer fallback. Keys
592
+ // with non-null unknown values are left intact so genuine schema mistakes
593
+ // still surface as validation errors.
594
+ if (schemaObject.additionalProperties === false) {
595
+ const knownKeys = new Set(Object.keys(properties));
596
+ for (const key of Object.keys(nextValue)) {
597
+ if (knownKeys.has(key)) continue;
598
+ const v = nextValue[key];
599
+ if (v !== null && v !== "null") continue;
600
+ if (!changed) {
601
+ nextValue = { ...nextValue };
602
+ changed = true;
603
+ }
604
+ delete nextValue[key];
605
+ }
606
+ }
607
+
588
608
  return { value: changed ? nextValue : value, changed };
589
609
  }
590
610