@bastani/pi-ai 0.9.26-alpha.2 → 0.9.26-alpha.4

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 (34) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/NOTICE.md +1 -1
  3. package/README.md +3 -1
  4. package/dist/api/anthropic-messages.d.ts.map +1 -1
  5. package/dist/api/anthropic-messages.js +20 -32
  6. package/dist/api/anthropic-messages.js.map +1 -1
  7. package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  8. package/dist/api/bedrock-converse-stream.js +25 -2
  9. package/dist/api/bedrock-converse-stream.js.map +1 -1
  10. package/dist/api/cloudflare-workers-ai-system-one.d.ts.map +1 -1
  11. package/dist/api/cloudflare-workers-ai-system-one.js +13 -8
  12. package/dist/api/cloudflare-workers-ai-system-one.js.map +1 -1
  13. package/dist/auth/oauth/openai-chatgpt.d.ts.map +1 -1
  14. package/dist/auth/oauth/openai-chatgpt.js +5 -0
  15. package/dist/auth/oauth/openai-chatgpt.js.map +1 -1
  16. package/dist/providers/data/.manifest.json +1 -1
  17. package/dist/providers/data/amazon-bedrock.json +1 -1
  18. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  19. package/dist/providers/data/cloudflare-workers-ai.json +1 -1
  20. package/dist/providers/data/opencode.json +1 -1
  21. package/dist/providers/data/openrouter.json +1 -1
  22. package/dist/providers/data/radius.json +1 -1
  23. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  24. package/dist/types.d.ts +1 -1
  25. package/dist/types.d.ts.map +1 -1
  26. package/dist/types.js.map +1 -1
  27. package/dist/utils/retry.d.ts.map +1 -1
  28. package/dist/utils/retry.js +1 -0
  29. package/dist/utils/retry.js.map +1 -1
  30. package/dist/utils/transcript.d.ts +5 -2
  31. package/dist/utils/transcript.d.ts.map +1 -1
  32. package/dist/utils/transcript.js +5 -2
  33. package/dist/utils/transcript.js.map +1 -1
  34. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -4,6 +4,24 @@ This package is a Bastani fork of `@earendil-works/pi-ai`. Upstream history at t
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.9.26-alpha.3] - 2026-10-03
8
+
9
+ ### Added
10
+
11
+ - Added Cloudflare's Clef and Clef Flash classifier models (`@cf/cloudflare/clef`, `@cf/cloudflare/clef-flash`) to the `cloudflare-workers-ai` provider ([#10316](https://github.com/earendil-works/pi/pull/10316) by [@ndisidore](https://github.com/ndisidore), [#10322](https://github.com/earendil-works/pi/pull/10322) by [@RealAlexandreAI](https://github.com/RealAlexandreAI)).
12
+
13
+ ### Changed
14
+
15
+ - Native Anthropic tool changes now define added and redefined tools inline, keeping the initial tool list stable for prompt caching. `hasToolRedefinitions()` is deprecated.
16
+
17
+ ### Fixed
18
+
19
+ - Provider errors containing "Selected model is at capacity" are now retried.
20
+ - Cloudflare AI Gateway now uses dashed Claude model IDs accepted by its Anthropic endpoint.
21
+ - Fixed Sign in with ChatGPT continuing when its callback port is taken by another login, which made the browser show "OAuth state mismatch"; it now fails with a port-in-use error before opening the browser ([#10265](https://github.com/earendil-works/pi/issues/10265)).
22
+ - Amazon Bedrock OpenAI models are no longer costed at the short-context rate above 272k input tokens; Bedrock models now include the pricing tiers listed on models.dev ([#10326](https://github.com/earendil-works/pi/issues/10326)).
23
+ - Amazon Bedrock Claude requests no longer fail with "Invalid `signature` in `thinking` block" after the system prompt or tools change; Claude Opus 4.7+, Sonnet 5+, and Fable 5 now drop stale thinking blocks like the Anthropic provider ([#10324](https://github.com/earendil-works/pi/issues/10324)).
24
+
7
25
  ## [0.9.26-alpha.2] - 2026-10-02
8
26
 
9
27
  ### Added
package/NOTICE.md CHANGED
@@ -6,7 +6,7 @@ monorepo at `packages/ai` and publishes at the same version as `@bastani/atomic`
6
6
 
7
7
  - Upstream package: [`@earendil-works/pi-ai`](https://www.npmjs.com/package/@earendil-works/pi-ai)
8
8
  - Original fork point: `v0.84.2` (`914cf1472e715297caa30db4b9535d534a9eb718`)
9
- - Applicable Pi AI fixes synced through audited upstream `main`: `earendil-works/pi@86dfceec402ad77e563bf4feab5f26c42d5f5db6`, with remaining registry Pi packages at `1.0.0`. Atomic retains its adaptations and does not enable upstream virtual models.
9
+ - Applicable Pi AI fixes synced through audited upstream `main`: `earendil-works/pi@c10bfb0d79dbbc998539a0a3e6c6a736a4e6db06`, with remaining registry Pi packages at `1.0.0`. Atomic retains its adaptations and does not enable upstream virtual models.
10
10
  - Catalog JSON under `src/providers/data/` is generated at build time from models.dev, matching upstream. It is not committed.
11
11
 
12
12
  Original work is Copyright (c) 2025 Mario Zechner and is licensed under the MIT License.
package/README.md CHANGED
@@ -879,7 +879,7 @@ Classifier models consume structured JSON state and answer one or more typed que
879
879
  | --- | --- | --- |
880
880
  | `typesafe` | `jev-latest` | `TYPESAFE_API_KEY` |
881
881
  | `openrouter` | `typesafe/jev-1.13`, `~typesafe/jev-latest` | `OPENROUTER_API_KEY` or OpenRouter OAuth |
882
- | `cloudflare-workers-ai` | `typesafe/jev` | `CLOUDFLARE_API_KEY` and `CLOUDFLARE_ACCOUNT_ID` |
882
+ | `cloudflare-workers-ai` | `typesafe/jev`, `@cf/cloudflare/clef`, `@cf/cloudflare/clef-flash` | `CLOUDFLARE_API_KEY` and `CLOUDFLARE_ACCOUNT_ID` |
883
883
  | `vercel-ai-gateway` | `typesafe-ai/jev` | `AI_GATEWAY_API_KEY` |
884
884
  | `opencode` | `jev-1.13`, `jev-1.13-free` | `OPENCODE_API_KEY` |
885
885
 
@@ -1561,6 +1561,8 @@ Later system messages append instructions, patch named sections (`null` removes
1561
1561
 
1562
1562
  Models with `supportsMidConvoSystemMessages` receive updates in place. Other models receive the replayed prompt and tools as a leading checkpoint. Anthropic's `supportsMidConvoToolChanges`, OpenAI Responses' `supportsAdditionalTools`/`supportsToolSearch`, and OpenAI Completions' `supportsMidConvoToolAdditions` enable native tool transitions where representable. Unsupported transitions fall back to the current top-level tool list and may invalidate the cached prefix.
1563
1563
 
1564
+ With Anthropic's `supportsMidConvoToolChanges`, the `inline-tools-2026-09-15` beta keeps the initial top-level tools and a deferred placeholder fixed. Later `tool_addition` blocks carry complete definitions, including replacements under an existing name; `tool_removal` blocks reference names. This preserves the cached prefix across tool changes. At least one initial tool is required; otherwise the current tool list is sent at the top level.
1565
+
1564
1566
  ## Context Serialization
1565
1567
 
1566
1568
  The `Context` object can be easily serialized and deserialized using standard JSON methods, making it simple to persist conversations, implement chat history, or transfer contexts between services:
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../src/api/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,SAAiC,MAAM,mBAAmB,CAAC;AAiBlE,OAAO,KAAK,EASX,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAOb,MAAM,aAAa,CAAC;AAsKrB,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,wBAAwB,GAAG,YAAY,GAAG,SAAS,CAAC;AAoPhE,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACtD;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;CACnB;AAgSD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,gBAAgB,CA6XzE,CAAC;AA4BF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CAgDlF,CAAC"}
1
+ {"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../src/api/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,SAAiC,MAAM,mBAAmB,CAAC;AAiBlE,OAAO,KAAK,EASX,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAOb,MAAM,aAAa,CAAC;AAoKrB,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,wBAAwB,GAAG,YAAY,GAAG,SAAS,CAAC;AAmPhE,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACtD;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;CACnB;AAgSD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,gBAAgB,CA4XzE,CAAC;AA4BF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CAgDlF,CAAC"}
@@ -12,7 +12,7 @@ import { retryProviderRequest } from "../utils/provider-retry.js";
12
12
  import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
13
13
  import { createStreamDeadline, withStreamDeadline } from "../utils/stream-deadline.js";
14
14
  import { getSystemMessageText, renderSystemMessageUpdate } from "../utils/text.js";
15
- import { getCurrentTools, getDeclaredTools, getInitialSystemMessage, hasToolRedefinitions, resolveTranscript, } from "../utils/transcript.js";
15
+ import { getCurrentTools, getInitialSystemMessage, resolveTranscript, } from "../utils/transcript.js";
16
16
  import { ANTHROPIC_STRICT_JSON_SCHEMA_PROFILE, getJsonSchemaToolParameters, resolveJsonSchemaStrictSampling, } from "./constrained-sampling.js";
17
17
  import { buildCopilotDynamicHeaders, hasCopilotVisionInput, preserveCopilotIntegrationHeader, } from "./github-copilot-headers.js";
18
18
  import { adjustMaxTokensForThinking, buildBaseOptions, clampMaxTokensToContext } from "./simple-options.js";
@@ -129,7 +129,7 @@ const INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
129
129
  const SERVER_SIDE_FALLBACK_BETA = "server-side-fallback-2026-07-01";
130
130
  const THINKING_BINDING_CONTROLS_BETA = "thinking-binding-controls-2026-08-01";
131
131
  const MID_CONVERSATION_OUTPUT_CONFIG_BETA = "mid-conversation-output-config-2026-07-01";
132
- const MID_CONVERSATION_TOOL_CHANGES_BETA = "mid-conversation-tool-changes-2026-07-01";
132
+ const INLINE_TOOLS_BETA = "inline-tools-2026-09-15";
133
133
  const FAST_MODE_BETA = "fast-mode-2026-02-01";
134
134
  /**
135
135
  * Fast mode bills every token category at twice the standard rate for each supported model, across
@@ -187,10 +187,9 @@ function assertPayloadPreservesFastRoute(model, payload) {
187
187
  }
188
188
  /**
189
189
  * Stable deferred tool declared whenever native tool changes are in use. Anthropic adds
190
- * hidden prompt scaffolding as soon as any tool has `defer_loading`; declaring this
191
- * placeholder from the first request keeps that scaffolding in the cached prefix, so the
192
- * first real late tool does not invalidate the cache (measured: full miss without it).
193
- * It is never activated and the model cannot see it.
190
+ * hidden prompt scaffolding for mid-conversation tool changes; declaring this placeholder
191
+ * from the first request keeps that scaffolding in the cached prefix. It is never activated
192
+ * and the model cannot see it.
194
193
  */
195
194
  const DEFERRED_TOOL_PLACEHOLDER = {
196
195
  name: "__pi_deferred_placeholder__",
@@ -606,8 +605,7 @@ export const stream = (model, context, options) => {
606
605
  const cacheSessionId = cacheRetention === "none" ? undefined : options?.sessionId;
607
606
  const created = createClient(model, apiKey, model.reasoning && options?.thinkingEnabled === true && (options.interleavedThinking ?? true), shouldUseFineGrainedToolStreamingBeta(model, context), shouldUseServerSideFallbackBeta(model), options?.headers, options?.fetch, copilotDynamicHeaders, cacheSessionId, getAnthropicCompat(model).supportsMidConvoToolChanges &&
608
607
  getAnthropicCompat(model).supportsMidConvoSystemMessages &&
609
- (getInitialSystemMessage(normalizedContext.messages)?.toolsAdded?.length ?? 0) > 0 &&
610
- !hasToolRedefinitions(normalizedContext.messages), federation);
608
+ (getInitialSystemMessage(normalizedContext.messages)?.toolsAdded?.length ?? 0) > 0, federation);
611
609
  client = created.client;
612
610
  isOAuth = created.isOAuthToken;
613
611
  }
@@ -983,7 +981,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
983
981
  betaFeatures.push(MID_CONVERSATION_OUTPUT_CONFIG_BETA, THINKING_BINDING_CONTROLS_BETA);
984
982
  }
985
983
  if (useNativeToolChanges)
986
- betaFeatures.push(MID_CONVERSATION_TOOL_CHANGES_BETA);
984
+ betaFeatures.push(INLINE_TOOLS_BETA);
987
985
  if (requestedSpeed(model) === "fast")
988
986
  betaFeatures.push(FAST_MODE_BETA);
989
987
  const uniqueBetaFeatures = [...new Set(betaFeatures)];
@@ -1075,7 +1073,7 @@ function getNativeToolChangeBetas(model, context, isOAuth, options) {
1075
1073
  .map((feature) => feature.trim())
1076
1074
  .filter(Boolean)),
1077
1075
  ];
1078
- const features = [MID_CONVERSATION_TOOL_CHANGES_BETA];
1076
+ const features = [INLINE_TOOLS_BETA];
1079
1077
  if (isOAuth)
1080
1078
  features.push("claude-code-20250219", "oauth-2025-04-20");
1081
1079
  if (shouldUseFineGrainedToolStreamingBeta(model, context))
@@ -1103,15 +1101,11 @@ function buildParams(model, context, isOAuthToken, options) {
1103
1101
  const initialSystemText = initialSystemMessage ? getSystemMessageText(initialSystemMessage) : "";
1104
1102
  const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);
1105
1103
  const conversationMessages = initialSystemMessage ? transformedMessages.slice(1) : transformedMessages;
1106
- // Native tool changes reference tools by name, so a redefined name cannot be expressed,
1107
- // and Anthropic rejects a tool list where every tool is deferred, so there must be an
1108
- // initial active tool to anchor the deferred ones. Otherwise the current tool list is sent.
1109
1104
  const initialTools = initialSystemMessage?.toolsAdded ?? [];
1110
- const nativeToolChanges = compat.supportsMidConvoSystemMessages &&
1111
- compat.supportsMidConvoToolChanges &&
1112
- initialTools.length > 0 &&
1113
- !hasToolRedefinitions(context.messages);
1114
- const converted = convertMessages(conversationMessages, isOAuthToken, cacheControl, compat.allowEmptySignature, supportsMidConvoEffort(model) ? model.provider : undefined, nativeToolChanges);
1105
+ const nativeToolChanges = compat.supportsMidConvoSystemMessages && compat.supportsMidConvoToolChanges && initialTools.length > 0;
1106
+ const converted = convertMessages(conversationMessages, isOAuthToken, cacheControl, compat.allowEmptySignature, supportsMidConvoEffort(model) ? model.provider : undefined, nativeToolChanges
1107
+ ? (tools) => convertTools(tools, isOAuthToken, compat.supportsEagerToolInputStreaming, compat.supportsStrictTools)
1108
+ : undefined);
1115
1109
  const activeEffort = options?.effort ?? "high";
1116
1110
  const params = {
1117
1111
  model: upstreamModelId(model),
@@ -1162,16 +1156,9 @@ function buildParams(model, context, isOAuthToken, options) {
1162
1156
  }
1163
1157
  const toolCacheControl = compat.supportsCacheControlOnTools ? cacheControl : undefined;
1164
1158
  if (nativeToolChanges) {
1165
- // Initial tools stay active with the cache breakpoint on the last one. Every later
1166
- // declaration is deferred and only surfaced by its `tool_addition` block; removed
1167
- // tools stay declared and are withdrawn by `tool_removal`. The request-level list
1168
- // therefore only grows, keeping the cached prefix intact across tool changes.
1169
- const initialNames = new Set(initialTools.map((tool) => tool.name));
1170
- const laterTools = getDeclaredTools(context.messages).filter((tool) => !initialNames.has(tool.name));
1171
1159
  params.tools = [
1172
1160
  ...convertTools(initialTools, isOAuthToken, compat.supportsEagerToolInputStreaming, compat.supportsStrictTools, toolCacheControl),
1173
1161
  DEFERRED_TOOL_PLACEHOLDER,
1174
- ...convertTools(laterTools, isOAuthToken, compat.supportsEagerToolInputStreaming, compat.supportsStrictTools).map((tool) => ({ ...tool, defer_loading: true })),
1175
1162
  ];
1176
1163
  }
1177
1164
  else {
@@ -1292,7 +1279,7 @@ function convertToolResult(msg) {
1292
1279
  is_error: msg.isError,
1293
1280
  };
1294
1281
  }
1295
- function convertMessages(transformedMessages, isOAuthToken, cacheControl, allowEmptySignature = false, managedProvider, nativeToolChanges = false) {
1282
+ function convertMessages(transformedMessages, isOAuthToken, cacheControl, allowEmptySignature = false, managedProvider, convertToolDefinitions) {
1296
1283
  const params = [];
1297
1284
  const assistantLevels = new Map();
1298
1285
  // Later system messages are held back and emitted directly before the next assistant
@@ -1314,18 +1301,19 @@ function convertMessages(transformedMessages, isOAuthToken, cacheControl, allowE
1314
1301
  const blocks = [];
1315
1302
  if (text.length > 0)
1316
1303
  blocks.push({ type: "text", text: sanitizeSurrogates(text) });
1317
- if (nativeToolChanges) {
1304
+ if (convertToolDefinitions) {
1305
+ const added = msg.toolsAdded ?? [];
1306
+ const redefined = new Set(added.map((tool) => tool.name));
1318
1307
  for (const tool of msg.toolsRemoved ?? []) {
1308
+ if (redefined.has(tool.name))
1309
+ continue;
1319
1310
  blocks.push({
1320
1311
  type: "tool_removal",
1321
1312
  tool: { type: "tool_reference", name: isOAuthToken ? toClaudeCodeName(tool.name) : tool.name },
1322
1313
  });
1323
1314
  }
1324
- for (const tool of msg.toolsAdded ?? []) {
1325
- blocks.push({
1326
- type: "tool_addition",
1327
- tool: { type: "tool_reference", name: isOAuthToken ? toClaudeCodeName(tool.name) : tool.name },
1328
- });
1315
+ for (const definition of convertToolDefinitions(added)) {
1316
+ blocks.push({ type: "tool_addition", tool: { type: "tool_definition", definition } });
1329
1317
  }
1330
1318
  }
1331
1319
  if (blocks.length > 0)