@bastani/pi-ai 0.9.20-alpha.5 → 0.9.20-alpha.7

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 (107) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +4 -2
  3. package/dist/api/anthropic-messages.d.ts.map +1 -1
  4. package/dist/api/anthropic-messages.js +81 -11
  5. package/dist/api/anthropic-messages.js.map +1 -1
  6. package/dist/api/openai-completions.d.ts.map +1 -1
  7. package/dist/api/openai-completions.js +5 -2
  8. package/dist/api/openai-completions.js.map +1 -1
  9. package/dist/api/openai-responses-shared.d.ts +3 -0
  10. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  11. package/dist/api/openai-responses-shared.js +8 -2
  12. package/dist/api/openai-responses-shared.js.map +1 -1
  13. package/dist/auth/oauth/load.d.ts +2 -0
  14. package/dist/auth/oauth/load.d.ts.map +1 -1
  15. package/dist/auth/oauth/load.js +5 -0
  16. package/dist/auth/oauth/load.js.map +1 -1
  17. package/dist/auth/oauth/meta.d.ts +17 -0
  18. package/dist/auth/oauth/meta.d.ts.map +1 -0
  19. package/dist/auth/oauth/meta.js +190 -0
  20. package/dist/auth/oauth/meta.js.map +1 -0
  21. package/dist/bun-oauth.d.ts.map +1 -1
  22. package/dist/bun-oauth.js +2 -0
  23. package/dist/bun-oauth.js.map +1 -1
  24. package/dist/decision-models.d.ts +21 -0
  25. package/dist/decision-models.d.ts.map +1 -0
  26. package/dist/decision-models.generated.d.ts +3 -0
  27. package/dist/decision-models.generated.d.ts.map +1 -0
  28. package/dist/decision-models.generated.js +47 -0
  29. package/dist/decision-models.generated.js.map +1 -0
  30. package/dist/decision-models.js +8 -0
  31. package/dist/decision-models.js.map +1 -0
  32. package/dist/env-api-keys.d.ts.map +1 -1
  33. package/dist/env-api-keys.js +1 -0
  34. package/dist/env-api-keys.js.map +1 -1
  35. package/dist/image-models.generated.d.ts +15 -0
  36. package/dist/image-models.generated.d.ts.map +1 -1
  37. package/dist/image-models.generated.js +15 -0
  38. package/dist/image-models.generated.js.map +1 -1
  39. package/dist/index.d.ts +1 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +1 -0
  42. package/dist/index.js.map +1 -1
  43. package/dist/models.generated.d.ts +2 -0
  44. package/dist/models.generated.d.ts.map +1 -1
  45. package/dist/models.generated.js +2 -0
  46. package/dist/models.generated.js.map +1 -1
  47. package/dist/providers/all.d.ts.map +1 -1
  48. package/dist/providers/all.js +2 -0
  49. package/dist/providers/all.js.map +1 -1
  50. package/dist/providers/data/.manifest.json +1 -1
  51. package/dist/providers/data/amazon-bedrock.json +1 -1
  52. package/dist/providers/data/ant-ling.json +1 -1
  53. package/dist/providers/data/anthropic.json +1 -1
  54. package/dist/providers/data/azure-openai-responses.json +1 -1
  55. package/dist/providers/data/baseten.json +1 -1
  56. package/dist/providers/data/cerebras.json +1 -1
  57. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  58. package/dist/providers/data/cloudflare-workers-ai.json +1 -1
  59. package/dist/providers/data/deepseek.json +1 -1
  60. package/dist/providers/data/fireworks.json +1 -1
  61. package/dist/providers/data/github-copilot.json +1 -1
  62. package/dist/providers/data/google-vertex.json +1 -1
  63. package/dist/providers/data/google.json +1 -1
  64. package/dist/providers/data/groq.json +1 -1
  65. package/dist/providers/data/huggingface.json +1 -1
  66. package/dist/providers/data/kimi-coding.json +1 -1
  67. package/dist/providers/data/meta.json +1 -0
  68. package/dist/providers/data/minimax-cn.json +1 -1
  69. package/dist/providers/data/minimax.json +1 -1
  70. package/dist/providers/data/mistral.json +1 -1
  71. package/dist/providers/data/moonshotai-cn.json +1 -1
  72. package/dist/providers/data/moonshotai.json +1 -1
  73. package/dist/providers/data/nvidia.json +1 -1
  74. package/dist/providers/data/openai-codex.json +1 -1
  75. package/dist/providers/data/openai.json +1 -1
  76. package/dist/providers/data/opencode-go.json +1 -1
  77. package/dist/providers/data/opencode.json +1 -1
  78. package/dist/providers/data/openrouter.json +1 -1
  79. package/dist/providers/data/qwen-token-plan-cn.json +1 -1
  80. package/dist/providers/data/qwen-token-plan-individual.json +1 -1
  81. package/dist/providers/data/qwen-token-plan.json +1 -1
  82. package/dist/providers/data/radius.json +1 -1
  83. package/dist/providers/data/together.json +1 -1
  84. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  85. package/dist/providers/data/xai.json +1 -1
  86. package/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  87. package/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  88. package/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  89. package/dist/providers/data/xiaomi.json +1 -1
  90. package/dist/providers/data/zai-coding-cn.json +1 -1
  91. package/dist/providers/data/zai.json +1 -1
  92. package/dist/providers/faux.d.ts +1 -0
  93. package/dist/providers/faux.d.ts.map +1 -1
  94. package/dist/providers/faux.js +1 -0
  95. package/dist/providers/faux.js.map +1 -1
  96. package/dist/providers/meta.d.ts +3 -0
  97. package/dist/providers/meta.d.ts.map +1 -0
  98. package/dist/providers/meta.js +24 -0
  99. package/dist/providers/meta.js.map +1 -0
  100. package/dist/providers/meta.models.d.ts +3 -0
  101. package/dist/providers/meta.models.d.ts.map +1 -0
  102. package/dist/providers/meta.models.js +6 -0
  103. package/dist/providers/meta.models.js.map +1 -0
  104. package/dist/types.d.ts +26 -2
  105. package/dist/types.d.ts.map +1 -1
  106. package/dist/types.js.map +1 -1
  107. package/package.json +3 -2
@@ -43,13 +43,13 @@ function getCacheControl(model, cacheRetention, env) {
43
43
  // Stealth mode: Mimic Claude Code's tool naming exactly
44
44
  //
45
45
  // Anthropic gates newer models on the `claude-cli/<version>` user agent alone and rejects an
46
- // older one with `claude_code_version_too_old`. `claude-fable-5-1` requires >= 2.1.251, bisected
47
- // against the live API: 2.1.250 -> 400, 2.1.251 -> 200. This is pinned to that exact published
48
- // minimum rather than the newest release, and it is a strict superset of the previous 2.1.75 --
49
- // every model this provider ships answers 200 at 2.1.251. Raise it only when a model rejects
50
- // this value; a caller can override it for one client through the `headers` option, whose
51
- // lowercase `user-agent` key is merged last.
52
- const claudeCodeVersion = "2.1.251";
46
+ // older one with `claude_code_version_too_old`. `claude-fable-5-1` requires >= 2.1.251 (bisected
47
+ // against the live API: 2.1.250 -> 400, 2.1.251 -> 200) and Claude Opus 5.5 requires >= 2.1.280,
48
+ // the floor the API names in its rejection. This is pinned to the highest published minimum
49
+ // among shipped models rather than the newest release; every model this provider ships answers
50
+ // 200 at 2.1.280. Raise it only when a model rejects this value; a caller can override it for
51
+ // one client through the `headers` option, whose lowercase `user-agent` key is merged last.
52
+ const claudeCodeVersion = "2.1.280";
53
53
  // Claude Code 2.x tool names (canonical casing)
54
54
  // Source: https://cchistory.mariozechner.at/data/prompts-2.1.11.md
55
55
  // To update: https://github.com/badlogic/cchistory
@@ -129,6 +129,61 @@ const SERVER_SIDE_FALLBACK_BETA = "server-side-fallback-2026-07-01";
129
129
  const THINKING_BINDING_CONTROLS_BETA = "thinking-binding-controls-2026-08-01";
130
130
  const MID_CONVERSATION_OUTPUT_CONFIG_BETA = "mid-conversation-output-config-2026-07-01";
131
131
  const MID_CONVERSATION_TOOL_CHANGES_BETA = "mid-conversation-tool-changes-2026-07-01";
132
+ const FAST_MODE_BETA = "fast-mode-2026-02-01";
133
+ /**
134
+ * Fast mode bills every token category at twice the standard rate for each supported model, across
135
+ * the full context window, and prompt-caching multipliers stack on top.
136
+ * https://platform.claude.com/docs/en/build-with-claude/fast-mode#pricing
137
+ */
138
+ const FAST_MODE_PRICE_MULTIPLIER = 2;
139
+ function requestedSpeed(model) {
140
+ return model.fastRoute?.speed;
141
+ }
142
+ function upstreamModelId(model) {
143
+ return model.fastRoute?.upstreamModelId ?? model.id;
144
+ }
145
+ function reportedSpeed(usage) {
146
+ const speed = usage?.speed;
147
+ return speed === "fast" || speed === "standard" ? speed : undefined;
148
+ }
149
+ function applyFastModePricing(usage) {
150
+ usage.cost.input *= FAST_MODE_PRICE_MULTIPLIER;
151
+ usage.cost.output *= FAST_MODE_PRICE_MULTIPLIER;
152
+ usage.cost.cacheRead *= FAST_MODE_PRICE_MULTIPLIER;
153
+ usage.cost.cacheWrite *= FAST_MODE_PRICE_MULTIPLIER;
154
+ usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
155
+ }
156
+ /**
157
+ * Reject a payload hook that rewrote a field the model's fast route owns.
158
+ *
159
+ * A fast variant is recorded, persisted, and billed under its own `-fast` identity, so a hook that
160
+ * changes the upstream model or drops `speed: "fast"` would send a different request under that
161
+ * identity. Refusing loudly surfaces the misconfigured hook instead of silently restoring the route.
162
+ */
163
+ function assertPayloadPreservesFastRoute(model, payload) {
164
+ const fastRoute = model.fastRoute;
165
+ if (fastRoute?.speed === undefined)
166
+ return;
167
+ const remedy = `A fast model variant must send its route's upstream model and speed, because it is recorded, persisted, ` +
168
+ `and billed under its own identity. Select the normal model "${model.provider}/${fastRoute.baseModelId}" ` +
169
+ `if the request needs different routing`;
170
+ if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
171
+ throw new Error(`A request hook changed payload for fast model "${model.provider}/${model.id}" to a value that cannot carry ` +
172
+ `the route's upstream model and speed. ${remedy}, or return an object that preserves those fields.`);
173
+ }
174
+ const record = payload;
175
+ const conflicts = [];
176
+ if (record.model !== fastRoute.upstreamModelId) {
177
+ conflicts.push(`model (expected "${fastRoute.upstreamModelId}", got ${JSON.stringify(record.model)})`);
178
+ }
179
+ if (record.speed !== fastRoute.speed) {
180
+ conflicts.push(`speed (expected ${JSON.stringify(fastRoute.speed)}, got ${JSON.stringify(record.speed)})`);
181
+ }
182
+ if (conflicts.length === 0)
183
+ return;
184
+ throw new Error(`A request hook changed ${conflicts.join(" and ")} for fast model "${model.provider}/${model.id}". ` +
185
+ `${remedy}, or stop rewriting those fields.`);
186
+ }
132
187
  /**
133
188
  * Stable deferred tool declared whenever native tool changes are in use. Anthropic adds
134
189
  * hidden prompt scaffolding as soon as any tool has `defer_loading`; declaring this
@@ -220,7 +275,7 @@ function addEarlierAttemptCosts(output, model, servingModel, event) {
220
275
  if (!iteration.output_tokens)
221
276
  continue;
222
277
  // Price at the rates of the model that ran the attempt, which is not the serving model.
223
- const attemptCost = iteration.model === model.id
278
+ const attemptCost = iteration.model === upstreamModelId(model)
224
279
  ? model.cost
225
280
  : iteration.model === servingModel.id
226
281
  ? servingModel.cost
@@ -485,6 +540,7 @@ export const stream = (model, context, options) => {
485
540
  let client;
486
541
  let isOAuth;
487
542
  let usageModel = model;
543
+ let servedSpeed = requestedSpeed(model);
488
544
  if (options?.client) {
489
545
  client = options.client;
490
546
  isOAuth = false;
@@ -515,6 +571,7 @@ export const stream = (model, context, options) => {
515
571
  if (nextParams !== undefined) {
516
572
  params = nextParams;
517
573
  }
574
+ assertPayloadPreservesFastRoute(model, params);
518
575
  const requestOptions = {
519
576
  ...(streamDeadline.signal ? { signal: streamDeadline.signal } : {}),
520
577
  ...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),
@@ -532,9 +589,9 @@ export const stream = (model, context, options) => {
532
589
  if (event.type === "message_start") {
533
590
  output.responseId = event.message.id;
534
591
  const responseModel = event.message.model;
535
- if (responseModel !== model.id)
592
+ if (responseModel !== upstreamModelId(model))
536
593
  output.responseModel = responseModel;
537
- const fallbackCost = responseModel === model.id
594
+ const fallbackCost = responseModel === upstreamModelId(model)
538
595
  ? undefined
539
596
  : model.compat?.allowedFallbackModels?.find((fallback) => fallback.provider === model.provider && fallback.model === responseModel)?.cost;
540
597
  usageModel = fallbackCost ? { ...model, id: responseModel, cost: fallbackCost } : model;
@@ -549,6 +606,9 @@ export const stream = (model, context, options) => {
549
606
  output.usage.totalTokens =
550
607
  output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
551
608
  calculateCost(usageModel, output.usage);
609
+ servedSpeed = reportedSpeed(event.message.usage) ?? servedSpeed;
610
+ if (servedSpeed === "fast")
611
+ applyFastModePricing(output.usage);
552
612
  inputTransformations = getInputTransformations(event.message) ?? inputTransformations;
553
613
  }
554
614
  else if (event.type === "content_block_start") {
@@ -744,6 +804,9 @@ export const stream = (model, context, options) => {
744
804
  output.usage.totalTokens =
745
805
  output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
746
806
  calculateCost(usageModel, output.usage);
807
+ servedSpeed = reportedSpeed(event.usage) ?? servedSpeed;
808
+ if (servedSpeed === "fast")
809
+ applyFastModePricing(output.usage);
747
810
  // A non-empty final fallback report supersedes the request-start report with
748
811
  // the serving model's transformations. An empty report must not erase drops
749
812
  // already reported at message_start.
@@ -868,6 +931,8 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
868
931
  }
869
932
  if (useNativeToolChanges)
870
933
  betaFeatures.push(MID_CONVERSATION_TOOL_CHANGES_BETA);
934
+ if (requestedSpeed(model) === "fast")
935
+ betaFeatures.push(FAST_MODE_BETA);
871
936
  const uniqueBetaFeatures = [...new Set(betaFeatures)];
872
937
  // Copilot: Bearer auth, selective betas.
873
938
  if (model.provider === "github-copilot") {
@@ -959,6 +1024,8 @@ function getNativeToolChangeBetas(model, context, isOAuth, options) {
959
1024
  features.push(THINKING_BINDING_CONTROLS_BETA);
960
1025
  if (supportsMidConvoEffort(model))
961
1026
  features.push(MID_CONVERSATION_OUTPUT_CONFIG_BETA, THINKING_BINDING_CONTROLS_BETA);
1027
+ if (requestedSpeed(model) === "fast")
1028
+ features.push(FAST_MODE_BETA);
962
1029
  return [...new Set(features)];
963
1030
  }
964
1031
  function buildParams(model, context, isOAuthToken, options) {
@@ -979,7 +1046,7 @@ function buildParams(model, context, isOAuthToken, options) {
979
1046
  const converted = convertMessages(conversationMessages, isOAuthToken, cacheControl, compat.allowEmptySignature, supportsMidConvoEffort(model) ? model.provider : undefined, nativeToolChanges);
980
1047
  const activeEffort = options?.effort ?? "high";
981
1048
  const params = {
982
- model: model.id,
1049
+ model: upstreamModelId(model),
983
1050
  messages: (supportsMidConvoEffort(model)
984
1051
  ? insertThinkingLevelMessages(converted, activeEffort)
985
1052
  : converted.messages),
@@ -988,6 +1055,9 @@ function buildParams(model, context, isOAuthToken, options) {
988
1055
  };
989
1056
  if (nativeToolChanges)
990
1057
  params.betas = getNativeToolChangeBetas(model, context, isOAuthToken, options);
1058
+ const speed = requestedSpeed(model);
1059
+ if (speed !== undefined)
1060
+ params.speed = speed;
991
1061
  // For OAuth tokens, we MUST include Claude Code identity
992
1062
  if (isOAuthToken) {
993
1063
  params.system = [