@bastani/pi-ai 0.9.14 → 0.9.15
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/CHANGELOG.md +72 -0
- package/NOTICE.md +4 -5
- package/README.md +6 -4
- package/dist/api/anthropic-messages.d.ts.map +1 -1
- package/dist/api/anthropic-messages.js +55 -25
- package/dist/api/anthropic-messages.js.map +1 -1
- package/dist/api/azure-openai-responses.d.ts +2 -0
- package/dist/api/azure-openai-responses.d.ts.map +1 -1
- package/dist/api/azure-openai-responses.js +9 -2
- package/dist/api/azure-openai-responses.js.map +1 -1
- package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
- package/dist/api/bedrock-converse-stream.js +132 -8
- package/dist/api/bedrock-converse-stream.js.map +1 -1
- package/dist/api/github-copilot-headers.d.ts +22 -1
- package/dist/api/github-copilot-headers.d.ts.map +1 -1
- package/dist/api/github-copilot-headers.js +30 -0
- package/dist/api/github-copilot-headers.js.map +1 -1
- package/dist/api/google-generative-ai.d.ts +2 -2
- package/dist/api/google-generative-ai.d.ts.map +1 -1
- package/dist/api/google-generative-ai.js +28 -18
- package/dist/api/google-generative-ai.js.map +1 -1
- package/dist/api/google-shared.d.ts +5 -2
- package/dist/api/google-shared.d.ts.map +1 -1
- package/dist/api/google-shared.js +16 -0
- package/dist/api/google-shared.js.map +1 -1
- package/dist/api/google-vertex.d.ts +2 -2
- package/dist/api/google-vertex.d.ts.map +1 -1
- package/dist/api/google-vertex.js +15 -11
- package/dist/api/google-vertex.js.map +1 -1
- package/dist/api/mistral-conversations.d.ts.map +1 -1
- package/dist/api/mistral-conversations.js +15 -5
- package/dist/api/mistral-conversations.js.map +1 -1
- package/dist/api/openai-codex-responses.d.ts.map +1 -1
- package/dist/api/openai-codex-responses.js +15 -6
- package/dist/api/openai-codex-responses.js.map +1 -1
- package/dist/api/openai-completions.d.ts +3 -2
- package/dist/api/openai-completions.d.ts.map +1 -1
- package/dist/api/openai-completions.js +142 -94
- package/dist/api/openai-completions.js.map +1 -1
- package/dist/api/openai-responses.d.ts.map +1 -1
- package/dist/api/openai-responses.js +20 -10
- package/dist/api/openai-responses.js.map +1 -1
- package/dist/api/pi-messages.d.ts.map +1 -1
- package/dist/api/pi-messages.js +23 -5
- package/dist/api/pi-messages.js.map +1 -1
- package/dist/api/simple-options.d.ts +4 -0
- package/dist/api/simple-options.d.ts.map +1 -1
- package/dist/api/simple-options.js +18 -10
- package/dist/api/simple-options.js.map +1 -1
- package/dist/auth/oauth/device-code.d.ts +1 -0
- package/dist/auth/oauth/device-code.d.ts.map +1 -1
- package/dist/auth/oauth/device-code.js +1 -1
- package/dist/auth/oauth/device-code.js.map +1 -1
- package/dist/auth/oauth/github-copilot.d.ts.map +1 -1
- package/dist/auth/oauth/github-copilot.js +98 -34
- package/dist/auth/oauth/github-copilot.js.map +1 -1
- package/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
- package/dist/auth/oauth/kimi-coding.js +1 -14
- package/dist/auth/oauth/kimi-coding.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/amazon-bedrock.json +1 -1
- package/dist/providers/data/anthropic.json +1 -1
- package/dist/providers/data/baseten.json +1 -1
- package/dist/providers/data/cerebras.json +1 -1
- package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/dist/providers/data/cloudflare-workers-ai.json +1 -1
- package/dist/providers/data/github-copilot.json +1 -1
- package/dist/providers/data/google-vertex.json +1 -1
- package/dist/providers/data/google.json +1 -1
- package/dist/providers/data/huggingface.json +1 -1
- package/dist/providers/data/nvidia.json +1 -1
- package/dist/providers/data/opencode-go.json +1 -1
- package/dist/providers/data/opencode.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/qwen-token-plan-cn.json +1 -1
- package/dist/providers/data/qwen-token-plan-individual.json +1 -1
- package/dist/providers/data/qwen-token-plan.json +1 -1
- package/dist/providers/data/together.json +1 -1
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/providers/data/xai.json +1 -1
- package/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
- package/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
- package/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
- package/dist/providers/data/xiaomi.json +1 -1
- package/dist/providers/data/zai-coding-cn.json +1 -1
- package/dist/providers/data/zai.json +1 -1
- package/dist/providers/github-copilot-env.d.ts +36 -0
- package/dist/providers/github-copilot-env.d.ts.map +1 -0
- package/dist/providers/github-copilot-env.js +94 -0
- package/dist/providers/github-copilot-env.js.map +1 -0
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/xai.d.ts.map +1 -1
- package/dist/providers/xai.js +1 -5
- package/dist/providers/xai.js.map +1 -1
- package/dist/types.d.ts +43 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/retry.d.ts.map +1 -1
- package/dist/utils/retry.js +14 -0
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/sleep.d.ts +2 -0
- package/dist/utils/sleep.d.ts.map +1 -0
- package/dist/utils/sleep.js +15 -0
- package/dist/utils/sleep.js.map +1 -0
- package/dist/utils/stream-deadline.d.ts +74 -0
- package/dist/utils/stream-deadline.d.ts.map +1 -0
- package/dist/utils/stream-deadline.js +196 -0
- package/dist/utils/stream-deadline.js.map +1 -0
- package/package.json +118 -120
|
@@ -8,8 +8,9 @@ import { getPiUserAgent } from "../utils/pi-user-agent.js";
|
|
|
8
8
|
import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
9
9
|
import { retryProviderRequest } from "../utils/provider-retry.js";
|
|
10
10
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
11
|
+
import { createStreamDeadline, withStreamDeadline } from "../utils/stream-deadline.js";
|
|
11
12
|
import { getJsonSchemaToolParameters, resolveJsonSchemaStrictSampling } from "./constrained-sampling.js";
|
|
12
|
-
import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copilot-headers.js";
|
|
13
|
+
import { buildCopilotDynamicHeaders, hasCopilotVisionInput, preserveCopilotIntegrationHeader, } from "./github-copilot-headers.js";
|
|
13
14
|
import { adjustMaxTokensForThinking, buildBaseOptions, clampMaxTokensToContext } from "./simple-options.js";
|
|
14
15
|
import { transformMessages } from "./transform-messages.js";
|
|
15
16
|
/**
|
|
@@ -110,6 +111,10 @@ function convertContentBlocks(content) {
|
|
|
110
111
|
}
|
|
111
112
|
const FINE_GRAINED_TOOL_STREAMING_BETA = "fine-grained-tool-streaming-2025-05-14";
|
|
112
113
|
const INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
|
|
114
|
+
const SERVER_SIDE_FALLBACK_BETA = "server-side-fallback-2026-07-01";
|
|
115
|
+
function shouldUseServerSideFallbackBeta(model) {
|
|
116
|
+
return (model.compat?.allowedFallbackModels?.length ?? 0) > 0;
|
|
117
|
+
}
|
|
113
118
|
function getAnthropicCompat(model) {
|
|
114
119
|
return {
|
|
115
120
|
supportsEagerToolInputStreaming: model.compat?.supportsEagerToolInputStreaming ?? true,
|
|
@@ -146,16 +151,8 @@ function mergeHeaders(...headerSources) {
|
|
|
146
151
|
}
|
|
147
152
|
return merged;
|
|
148
153
|
}
|
|
149
|
-
function mergeClientHeaders(
|
|
150
|
-
|
|
151
|
-
if (model.provider === "kimi-coding") {
|
|
152
|
-
for (const name of Object.keys(merged)) {
|
|
153
|
-
if (name.toLowerCase() === "user-agent")
|
|
154
|
-
delete merged[name];
|
|
155
|
-
}
|
|
156
|
-
merged["User-Agent"] = getPiUserAgent();
|
|
157
|
-
}
|
|
158
|
-
return merged;
|
|
154
|
+
function mergeClientHeaders(...headerSources) {
|
|
155
|
+
return mergeHeaders({ "User-Agent": getPiUserAgent() }, ...headerSources);
|
|
159
156
|
}
|
|
160
157
|
function hasHeader(headers, name) {
|
|
161
158
|
if (!headers)
|
|
@@ -251,6 +248,10 @@ async function* iterateSseMessages(body, signal) {
|
|
|
251
248
|
const decoder = new TextDecoder();
|
|
252
249
|
const state = { event: null, data: [], raw: [] };
|
|
253
250
|
let buffer = "";
|
|
251
|
+
const onAbort = () => {
|
|
252
|
+
void reader.cancel().catch(() => { });
|
|
253
|
+
};
|
|
254
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
254
255
|
try {
|
|
255
256
|
while (true) {
|
|
256
257
|
if (signal?.aborted) {
|
|
@@ -293,6 +294,11 @@ async function* iterateSseMessages(body, signal) {
|
|
|
293
294
|
}
|
|
294
295
|
}
|
|
295
296
|
finally {
|
|
297
|
+
signal?.removeEventListener("abort", onAbort);
|
|
298
|
+
try {
|
|
299
|
+
await reader.cancel();
|
|
300
|
+
}
|
|
301
|
+
catch { }
|
|
296
302
|
reader.releaseLock();
|
|
297
303
|
}
|
|
298
304
|
}
|
|
@@ -348,9 +354,11 @@ export const stream = (model, context, options) => {
|
|
|
348
354
|
stopReason: "pending",
|
|
349
355
|
timestamp: Date.now(),
|
|
350
356
|
};
|
|
357
|
+
const streamDeadline = createStreamDeadline(options?.streamDeadlineMs, options?.signal);
|
|
351
358
|
try {
|
|
352
359
|
let client;
|
|
353
360
|
let isOAuth;
|
|
361
|
+
let usageModel = model;
|
|
354
362
|
if (options?.client) {
|
|
355
363
|
client = options.client;
|
|
356
364
|
isOAuth = false;
|
|
@@ -361,14 +369,15 @@ export const stream = (model, context, options) => {
|
|
|
361
369
|
let copilotDynamicHeaders;
|
|
362
370
|
if (model.provider === "github-copilot") {
|
|
363
371
|
const hasImages = hasCopilotVisionInput(context.messages);
|
|
364
|
-
copilotDynamicHeaders = buildCopilotDynamicHeaders({
|
|
372
|
+
copilotDynamicHeaders = preserveCopilotIntegrationHeader(model.headers, buildCopilotDynamicHeaders({
|
|
365
373
|
messages: context.messages,
|
|
366
374
|
hasImages,
|
|
367
|
-
|
|
375
|
+
apiKey,
|
|
376
|
+
}));
|
|
368
377
|
}
|
|
369
378
|
const cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);
|
|
370
379
|
const cacheSessionId = cacheRetention === "none" ? undefined : options?.sessionId;
|
|
371
|
-
const created = createClient(model, apiKey, options?.interleavedThinking ?? true, shouldUseFineGrainedToolStreamingBeta(model, context), options?.headers, options?.fetch, copilotDynamicHeaders, cacheSessionId);
|
|
380
|
+
const created = createClient(model, apiKey, options?.interleavedThinking ?? true, shouldUseFineGrainedToolStreamingBeta(model, context), shouldUseServerSideFallbackBeta(model), options?.headers, options?.fetch, copilotDynamicHeaders, cacheSessionId);
|
|
372
381
|
client = created.client;
|
|
373
382
|
isOAuth = created.isOAuthToken;
|
|
374
383
|
}
|
|
@@ -378,21 +387,26 @@ export const stream = (model, context, options) => {
|
|
|
378
387
|
params = nextParams;
|
|
379
388
|
}
|
|
380
389
|
const requestOptions = {
|
|
381
|
-
...(
|
|
390
|
+
...(streamDeadline.signal ? { signal: streamDeadline.signal } : {}),
|
|
382
391
|
...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),
|
|
383
392
|
maxRetries: 0,
|
|
384
393
|
};
|
|
385
394
|
const response = await retryProviderRequest(() => client.messages.create({ ...params, stream: true }, requestOptions).asResponse(), {
|
|
386
395
|
maxRetries: options?.maxRetries,
|
|
387
396
|
maxRetryDelayMs: options?.maxRetryDelayMs,
|
|
388
|
-
signal:
|
|
397
|
+
signal: streamDeadline.signal,
|
|
389
398
|
});
|
|
390
399
|
await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);
|
|
391
400
|
stream.push({ type: "start", partial: output });
|
|
392
401
|
const blocks = output.content;
|
|
393
|
-
for await (const event of iterateAnthropicEvents(response,
|
|
402
|
+
for await (const event of withStreamDeadline(iterateAnthropicEvents(response, streamDeadline.signal), streamDeadline.deadlineMs, streamDeadline.abort)) {
|
|
394
403
|
if (event.type === "message_start") {
|
|
395
404
|
output.responseId = event.message.id;
|
|
405
|
+
output.model = event.message.model;
|
|
406
|
+
const fallbackCost = output.model === model.id
|
|
407
|
+
? undefined
|
|
408
|
+
: model.compat?.allowedFallbackModels?.find((fallback) => fallback.provider === model.provider && fallback.model === output.model)?.cost;
|
|
409
|
+
usageModel = fallbackCost ? { ...model, id: output.model, cost: fallbackCost } : model;
|
|
396
410
|
// Capture initial token usage from message_start event
|
|
397
411
|
// This ensures we have input token counts even if the stream is aborted early
|
|
398
412
|
output.usage.input = event.message.usage.input_tokens || 0;
|
|
@@ -403,7 +417,7 @@ export const stream = (model, context, options) => {
|
|
|
403
417
|
// Anthropic doesn't provide total_tokens, compute from components
|
|
404
418
|
output.usage.totalTokens =
|
|
405
419
|
output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
406
|
-
calculateCost(
|
|
420
|
+
calculateCost(usageModel, output.usage);
|
|
407
421
|
}
|
|
408
422
|
else if (event.type === "content_block_start") {
|
|
409
423
|
if (event.content_block.type === "text") {
|
|
@@ -572,7 +586,7 @@ export const stream = (model, context, options) => {
|
|
|
572
586
|
// Anthropic doesn't provide total_tokens, compute from components
|
|
573
587
|
output.usage.totalTokens =
|
|
574
588
|
output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
575
|
-
calculateCost(
|
|
589
|
+
calculateCost(usageModel, output.usage);
|
|
576
590
|
}
|
|
577
591
|
}
|
|
578
592
|
if (options?.signal?.aborted) {
|
|
@@ -598,6 +612,9 @@ export const stream = (model, context, options) => {
|
|
|
598
612
|
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
599
613
|
stream.end();
|
|
600
614
|
}
|
|
615
|
+
finally {
|
|
616
|
+
streamDeadline.cleanup();
|
|
617
|
+
}
|
|
601
618
|
})();
|
|
602
619
|
return stream;
|
|
603
620
|
};
|
|
@@ -624,9 +641,15 @@ function mapThinkingLevelToEffort(model, level) {
|
|
|
624
641
|
}
|
|
625
642
|
export const streamSimple = (model, context, options) => {
|
|
626
643
|
assertRequestAuth(model.provider, options?.apiKey, options?.headers);
|
|
627
|
-
const base =
|
|
644
|
+
const base = {
|
|
645
|
+
...buildBaseOptions(model, context, options, options?.apiKey),
|
|
646
|
+
toolChoice: options?.toolChoice,
|
|
647
|
+
};
|
|
628
648
|
if (!options?.reasoning) {
|
|
629
|
-
return stream(model, context, {
|
|
649
|
+
return stream(model, context, {
|
|
650
|
+
...base,
|
|
651
|
+
thinkingEnabled: false,
|
|
652
|
+
});
|
|
630
653
|
}
|
|
631
654
|
// For models with adaptive thinking: use an effort level.
|
|
632
655
|
// For older models: use budget-based thinking.
|
|
@@ -652,7 +675,7 @@ export const streamSimple = (model, context, options) => {
|
|
|
652
675
|
function isOAuthToken(apiKey) {
|
|
653
676
|
return apiKey.includes("sk-ant-oat");
|
|
654
677
|
}
|
|
655
|
-
function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStreamingBeta, optionsHeaders, fetch, dynamicHeaders, sessionId) {
|
|
678
|
+
function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStreamingBeta, useServerSideFallbackBeta, optionsHeaders, fetch, dynamicHeaders, sessionId) {
|
|
656
679
|
// Adaptive thinking models have interleaved thinking built in, so skip the beta header.
|
|
657
680
|
const needsInterleavedBeta = interleavedThinking && model.compat?.forceAdaptiveThinking !== true;
|
|
658
681
|
const betaFeatures = [];
|
|
@@ -662,6 +685,9 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
662
685
|
if (needsInterleavedBeta) {
|
|
663
686
|
betaFeatures.push(INTERLEAVED_THINKING_BETA);
|
|
664
687
|
}
|
|
688
|
+
if (useServerSideFallbackBeta) {
|
|
689
|
+
betaFeatures.push(SERVER_SIDE_FALLBACK_BETA);
|
|
690
|
+
}
|
|
665
691
|
// Copilot: Bearer auth, selective betas.
|
|
666
692
|
if (model.provider === "github-copilot") {
|
|
667
693
|
const client = new Anthropic({
|
|
@@ -670,7 +696,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
670
696
|
baseURL: model.baseUrl,
|
|
671
697
|
dangerouslyAllowBrowser: true,
|
|
672
698
|
fetch,
|
|
673
|
-
defaultHeaders: mergeClientHeaders(
|
|
699
|
+
defaultHeaders: mergeClientHeaders({
|
|
674
700
|
accept: "application/json",
|
|
675
701
|
"anthropic-dangerous-direct-browser-access": "true",
|
|
676
702
|
...(betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}),
|
|
@@ -686,7 +712,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
686
712
|
baseURL: model.baseUrl,
|
|
687
713
|
dangerouslyAllowBrowser: true,
|
|
688
714
|
fetch,
|
|
689
|
-
defaultHeaders: mergeClientHeaders(
|
|
715
|
+
defaultHeaders: mergeClientHeaders({
|
|
690
716
|
accept: "application/json",
|
|
691
717
|
"anthropic-dangerous-direct-browser-access": "true",
|
|
692
718
|
"anthropic-beta": ["claude-code-20250219", "oauth-2025-04-20", ...betaFeatures].join(","),
|
|
@@ -698,7 +724,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
698
724
|
}
|
|
699
725
|
// API key or header-owned auth.
|
|
700
726
|
const sessionAffinityHeaders = sessionId && getAnthropicCompat(model).sendSessionAffinityHeaders ? { "x-session-affinity": sessionId } : {};
|
|
701
|
-
const defaultHeaders = mergeClientHeaders(
|
|
727
|
+
const defaultHeaders = mergeClientHeaders({
|
|
702
728
|
accept: "application/json",
|
|
703
729
|
"anthropic-dangerous-direct-browser-access": "true",
|
|
704
730
|
...(betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}),
|
|
@@ -813,6 +839,10 @@ function buildParams(model, context, isOAuthToken, options) {
|
|
|
813
839
|
params.tool_choice = options.toolChoice;
|
|
814
840
|
}
|
|
815
841
|
}
|
|
842
|
+
const allowedFallbackModels = model.compat?.allowedFallbackModels;
|
|
843
|
+
if (allowedFallbackModels && allowedFallbackModels.length > 0) {
|
|
844
|
+
params.fallbacks = allowedFallbackModels.map((fallback) => ({ model: fallback.model }));
|
|
845
|
+
}
|
|
816
846
|
return params;
|
|
817
847
|
}
|
|
818
848
|
// Normalize tool call IDs to match Anthropic's required pattern and length
|