@bastani/pi-ai 0.9.43 → 0.9.44-alpha.2
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 +23 -0
- package/dist/api/anthropic-messages.d.ts.map +1 -1
- package/dist/api/anthropic-messages.js +45 -58
- package/dist/api/anthropic-messages.js.map +1 -1
- package/dist/api/azure-openai-responses.d.ts.map +1 -1
- package/dist/api/azure-openai-responses.js +0 -6
- 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 +71 -78
- package/dist/api/bedrock-converse-stream.js.map +1 -1
- package/dist/api/constrained-sampling.d.ts +11 -1
- package/dist/api/constrained-sampling.d.ts.map +1 -1
- package/dist/api/constrained-sampling.js +33 -18
- package/dist/api/constrained-sampling.js.map +1 -1
- package/dist/api/google-generative-ai.d.ts.map +1 -1
- package/dist/api/google-generative-ai.js +0 -6
- package/dist/api/google-generative-ai.js.map +1 -1
- package/dist/api/google-shared.d.ts +2 -1
- package/dist/api/google-shared.d.ts.map +1 -1
- package/dist/api/google-shared.js +57 -2
- package/dist/api/google-shared.js.map +1 -1
- package/dist/api/google-vertex.d.ts.map +1 -1
- package/dist/api/google-vertex.js +0 -6
- 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 +17 -44
- 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 +0 -5
- package/dist/api/openai-codex-responses.js.map +1 -1
- package/dist/api/openai-completions.d.ts.map +1 -1
- package/dist/api/openai-completions.js +34 -53
- package/dist/api/openai-completions.js.map +1 -1
- package/dist/api/openai-responses-shared.d.ts.map +1 -1
- package/dist/api/openai-responses-shared.js +58 -57
- package/dist/api/openai-responses-shared.js.map +1 -1
- package/dist/api/openai-responses.d.ts.map +1 -1
- package/dist/api/openai-responses.js +0 -6
- package/dist/api/openai-responses.js.map +1 -1
- package/dist/api/pi-messages.d.ts +2 -0
- package/dist/api/pi-messages.d.ts.map +1 -1
- package/dist/api/pi-messages.js +15 -9
- package/dist/api/pi-messages.js.map +1 -1
- package/dist/index.d.ts +1 -0
- 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/kimi-coding.json +1 -1
- package/dist/providers/data/moonshotai-cn.json +1 -1
- package/dist/providers/data/moonshotai.json +1 -1
- package/dist/providers/data/opencode-go.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/providers/faux.d.ts.map +1 -1
- package/dist/providers/faux.js +7 -2
- package/dist/providers/faux.js.map +1 -1
- package/dist/providers/radius-config.d.ts.map +1 -1
- package/dist/providers/radius-config.js +2 -1
- package/dist/providers/radius-config.js.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/error-body.d.ts.map +1 -1
- package/dist/utils/error-body.js +2 -1
- package/dist/utils/error-body.js.map +1 -1
- package/dist/utils/streaming-json.d.ts +84 -0
- package/dist/utils/streaming-json.d.ts.map +1 -0
- package/dist/utils/streaming-json.js +513 -0
- package/dist/utils/streaming-json.js.map +1 -0
- package/dist/utils/text.d.ts +7 -0
- package/dist/utils/text.d.ts.map +1 -1
- package/dist/utils/text.js +9 -0
- package/dist/utils/text.js.map +1 -1
- package/dist/utils/version.d.ts +1 -1
- package/dist/utils/version.d.ts.map +1 -1
- package/dist/utils/version.js +1 -1
- package/dist/utils/version.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,29 @@ 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.44-alpha.1] - 2026-10-24
|
|
8
|
+
|
|
9
|
+
### Breaking Changes
|
|
10
|
+
|
|
11
|
+
- `appendGrammarToolInputJsonDelta()` (`api/constrained-sampling`) takes the input delta instead of the whole input so far and no longer closes the input; close it with the new `closeGrammarToolInputJson()` ([pi #9265](https://github.com/earendil-works/pi/issues/9265))
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Assistant messages from the `pi-messages` API now carry `responseModel`, the concrete model the server reports on its terminal `done` or `error` event, so clients of virtual models can see which model answered ([pi #11265](https://github.com/earendil-works/pi/pull/11265))
|
|
16
|
+
- Added `StreamingJsonParser`, an incremental, tolerant parser for JSON text that arrives in pieces (each piece is read once; snapshots of the partial value never change once returned), and `ToolCallArgumentsStream`, which every provider now uses for streamed tool-call arguments; `StreamingJsonParser.append()` also returns the changes each piece made (`JsonChange`), for writers that keep their own copy ([pi #9265](https://github.com/earendil-works/pi/issues/9265))
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- The faux provider streams partial tool-call arguments, so `toolcall_delta` partials show growing arguments as real providers do ([pi #9265](https://github.com/earendil-works/pi/issues/9265))
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Claude models with mid-conversation effort no longer fail with `Invalid effort level` on accounts whose organization caps effort below `high`, even at `low` or `medium` thinking: the fixed top-level effort is now `low`, and the per-message effort markers still set the level for each reply ([pi #10063](https://github.com/earendil-works/pi/issues/10063))
|
|
25
|
+
- The faux provider no longer counts newly cached prompt tokens both as `input` and as `cacheWrite` when it simulates prompt caching for a `sessionId`. Every prompt token now goes to either `cacheRead` or `cacheWrite`, and `input` is 0 ([pi f3fa8bd9](https://github.com/earendil-works/pi/commit/f3fa8bd92430a2bf443681027a01c58586f35464))
|
|
26
|
+
- Gemini tool schemas sent through `parametersJsonSchema` now express string and number `const` values as single-value `enum`s, which Gemini honors (it ignores `const`). Only schema-bearing keywords are rewritten, so literal data under `default`, `examples`, `enum`, `const` and custom keywords, and property names such as `__proto__`, are sent unchanged ([pi 7314819f](https://github.com/earendil-works/pi/commit/7314819f0fe30fa616f32fa3a1fc8d1a856a1446), [pi #11308](https://github.com/earendil-works/pi/issues/11308))
|
|
27
|
+
- Kimi K3.1 Pro and K3.1 Pro Highspeed on Kimi Coding, Moonshot, and OpenCode Go no longer use Kimi K2 request settings. They now send `reasoning_effort` (low/high/max), return earlier reasoning, accept tools added mid-conversation, and report Moonshot rates on Kimi Coding; OpenRouter and Vercel AI Gateway clamp their output limit like Kimi K3. Kimi Coding `k3-256k` now reports Kimi K3 rates ([pi 1de2d7ad](https://github.com/earendil-works/pi/commit/1de2d7adeacfd1b065d9df091997d44c43120ade))
|
|
28
|
+
- Streamed tool-call arguments are no longer re-parsed in full on every delta, which made CPU time and memory grow quadratically with the size of a tool call (a 90 KB `write` on Anthropic peaked at about 140 MB of heap; a 500 KB one took minutes). Every provider and the pi-messages client now read each delta once, and keep their stream state (`partialJson`, `partialArgs`, `index`, `customInput`, `streamIndex`, Bedrock's encrypted reasoning bytes) off the content blocks, so it no longer reaches partial messages or transcripts of failed streams. Grammar (custom) tool input streaming no longer copies the whole input on every delta, and truncated provider error bodies and pi-messages diagnostics no longer keep the whole text they were cut from alive ([pi #9265](https://github.com/earendil-works/pi/issues/9265))
|
|
29
|
+
|
|
7
30
|
## [0.9.42] - 2026-10-23
|
|
8
31
|
|
|
9
32
|
### Added
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../src/api/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,SAAkD,MAAM,mBAAmB,CAAC;AAiBnF,OAAO,KAAK,EASX,mBAAmB,EAEnB,cAAc,EACd,aAAa,
|
|
1
|
+
{"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../src/api/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,SAAkD,MAAM,mBAAmB,CAAC;AAiBnF,OAAO,KAAK,EASX,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAKb,MAAM,aAAa,CAAC;AA+KrB,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,wBAAwB,GAAG,YAAY,GAAG,SAAS,CAAC;AAqPhE,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;AAsTD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,gBAAgB,CAgZzE,CAAC;AA4BF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CAgDlF,CAAC"}
|
|
@@ -7,13 +7,14 @@ import { assertSupportedDocumentMimeType } from "../utils/document-input.js";
|
|
|
7
7
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
8
8
|
import { headersToRecord } from "../utils/headers.js";
|
|
9
9
|
import { getIdentityHeaders } from "../utils/identity.js";
|
|
10
|
-
import { parseJsonWithRepair
|
|
10
|
+
import { parseJsonWithRepair } from "../utils/json-parse.js";
|
|
11
11
|
import { applyOpenRouterReportedCost, isOpenRouterModel, } from "../utils/openrouter-cost.js";
|
|
12
12
|
import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
13
13
|
import { retryProviderRequest } from "../utils/provider-retry.js";
|
|
14
14
|
import { getFetchAdmission } from "../utils/request-admission.js";
|
|
15
15
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
16
16
|
import { createStreamDeadline, withStreamDeadline } from "../utils/stream-deadline.js";
|
|
17
|
+
import { ToolCallArgumentsStream } from "../utils/streaming-json.js";
|
|
17
18
|
import { getSystemMessageText, renderSystemMessageUpdate } from "../utils/text.js";
|
|
18
19
|
import { getCurrentTools, getInitialSystemMessage, resolveTranscript, } from "../utils/transcript.js";
|
|
19
20
|
import { ANTHROPIC_STRICT_JSON_SCHEMA_PROFILE, getJsonSchemaToolParameters, resolveJsonSchemaStrictSampling, } from "./constrained-sampling.js";
|
|
@@ -685,7 +686,12 @@ export const stream = (model, context, options) => {
|
|
|
685
686
|
}
|
|
686
687
|
await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);
|
|
687
688
|
stream.push({ type: "start", partial: output });
|
|
688
|
-
|
|
689
|
+
// Stream state per Anthropic block index, kept off the content blocks so it never reaches partials.
|
|
690
|
+
const openBlocks = new Map();
|
|
691
|
+
const openBlock = (anthropicIndex) => {
|
|
692
|
+
const open = openBlocks.get(anthropicIndex);
|
|
693
|
+
return open === undefined ? undefined : { ...open, block: output.content[open.contentIndex] };
|
|
694
|
+
};
|
|
689
695
|
for await (const event of withStreamDeadline(iterateAnthropicEvents(response, streamDeadline.signal), streamDeadline.deadlineMs, streamDeadline.abort)) {
|
|
690
696
|
await options?.onProviderStreamEvent?.(event, model);
|
|
691
697
|
if (event.type === "message_start") {
|
|
@@ -715,47 +721,42 @@ export const stream = (model, context, options) => {
|
|
|
715
721
|
}
|
|
716
722
|
else if (event.type === "content_block_start") {
|
|
717
723
|
if (event.content_block.type === "text") {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
text: event.content_block.text ?? "",
|
|
721
|
-
index: event.index,
|
|
722
|
-
};
|
|
723
|
-
output.content.push(block);
|
|
724
|
+
output.content.push({ type: "text", text: event.content_block.text ?? "" });
|
|
725
|
+
openBlocks.set(event.index, { contentIndex: output.content.length - 1 });
|
|
724
726
|
stream.push({ type: "text_start", contentIndex: output.content.length - 1, partial: output });
|
|
725
727
|
}
|
|
726
728
|
else if (event.content_block.type === "thinking") {
|
|
727
|
-
|
|
729
|
+
output.content.push({
|
|
728
730
|
type: "thinking",
|
|
729
731
|
thinking: event.content_block.thinking ?? "",
|
|
730
732
|
thinkingSignature: event.content_block.signature ?? "",
|
|
731
|
-
|
|
732
|
-
};
|
|
733
|
-
output.content.push(block);
|
|
733
|
+
});
|
|
734
|
+
openBlocks.set(event.index, { contentIndex: output.content.length - 1 });
|
|
734
735
|
stream.push({ type: "thinking_start", contentIndex: output.content.length - 1, partial: output });
|
|
735
736
|
}
|
|
736
737
|
else if (event.content_block.type === "redacted_thinking") {
|
|
737
|
-
|
|
738
|
+
output.content.push({
|
|
738
739
|
type: "thinking",
|
|
739
740
|
thinking: "[Reasoning redacted]",
|
|
740
741
|
thinkingSignature: event.content_block.data,
|
|
741
742
|
redacted: true,
|
|
742
|
-
|
|
743
|
-
};
|
|
744
|
-
output.content.push(block);
|
|
743
|
+
});
|
|
744
|
+
openBlocks.set(event.index, { contentIndex: output.content.length - 1 });
|
|
745
745
|
stream.push({ type: "thinking_start", contentIndex: output.content.length - 1, partial: output });
|
|
746
746
|
}
|
|
747
747
|
else if (event.content_block.type === "tool_use") {
|
|
748
|
-
|
|
748
|
+
output.content.push({
|
|
749
749
|
type: "toolCall",
|
|
750
750
|
id: event.content_block.id,
|
|
751
751
|
name: isOAuth
|
|
752
752
|
? fromClaudeCodeName(event.content_block.name, currentTools)
|
|
753
753
|
: event.content_block.name,
|
|
754
754
|
arguments: event.content_block.input ?? {},
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
755
|
+
});
|
|
756
|
+
openBlocks.set(event.index, {
|
|
757
|
+
contentIndex: output.content.length - 1,
|
|
758
|
+
arguments: new ToolCallArgumentsStream(),
|
|
759
|
+
});
|
|
759
760
|
stream.push({ type: "toolcall_start", contentIndex: output.content.length - 1, partial: output });
|
|
760
761
|
}
|
|
761
762
|
else if (event.content_block.type === "fallback") {
|
|
@@ -785,60 +786,52 @@ export const stream = (model, context, options) => {
|
|
|
785
786
|
}
|
|
786
787
|
}
|
|
787
788
|
else if (event.type === "content_block_delta") {
|
|
789
|
+
const open = openBlock(event.index);
|
|
788
790
|
if (event.delta.type === "text_delta") {
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
if (block && block.type === "text") {
|
|
792
|
-
block.text += event.delta.text;
|
|
791
|
+
if (open?.block.type === "text") {
|
|
792
|
+
open.block.text += event.delta.text;
|
|
793
793
|
stream.push({
|
|
794
794
|
type: "text_delta",
|
|
795
|
-
contentIndex:
|
|
795
|
+
contentIndex: open.contentIndex,
|
|
796
796
|
delta: event.delta.text,
|
|
797
797
|
partial: output,
|
|
798
798
|
});
|
|
799
799
|
}
|
|
800
800
|
}
|
|
801
801
|
else if (event.delta.type === "thinking_delta") {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
if (block && block.type === "thinking") {
|
|
805
|
-
block.thinking += event.delta.thinking;
|
|
802
|
+
if (open?.block.type === "thinking") {
|
|
803
|
+
open.block.thinking += event.delta.thinking;
|
|
806
804
|
stream.push({
|
|
807
805
|
type: "thinking_delta",
|
|
808
|
-
contentIndex:
|
|
806
|
+
contentIndex: open.contentIndex,
|
|
809
807
|
delta: event.delta.thinking,
|
|
810
808
|
partial: output,
|
|
811
809
|
});
|
|
812
810
|
}
|
|
813
811
|
}
|
|
814
812
|
else if (event.delta.type === "input_json_delta") {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
if (block && block.type === "toolCall") {
|
|
818
|
-
block.partialJson += event.delta.partial_json;
|
|
819
|
-
block.arguments = parseStreamingJson(block.partialJson);
|
|
813
|
+
if (open?.block.type === "toolCall" && open.arguments !== undefined) {
|
|
814
|
+
open.block.arguments = open.arguments.append(event.delta.partial_json);
|
|
820
815
|
stream.push({
|
|
821
816
|
type: "toolcall_delta",
|
|
822
|
-
contentIndex:
|
|
817
|
+
contentIndex: open.contentIndex,
|
|
823
818
|
delta: event.delta.partial_json,
|
|
824
819
|
partial: output,
|
|
825
820
|
});
|
|
826
821
|
}
|
|
827
822
|
}
|
|
828
823
|
else if (event.delta.type === "signature_delta") {
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
block.thinkingSignature = block.thinkingSignature || "";
|
|
833
|
-
block.thinkingSignature += event.delta.signature;
|
|
824
|
+
if (open?.block.type === "thinking") {
|
|
825
|
+
open.block.thinkingSignature = open.block.thinkingSignature || "";
|
|
826
|
+
open.block.thinkingSignature += event.delta.signature;
|
|
834
827
|
}
|
|
835
828
|
}
|
|
836
829
|
}
|
|
837
830
|
else if (event.type === "content_block_stop") {
|
|
838
|
-
const
|
|
839
|
-
|
|
840
|
-
if (
|
|
841
|
-
|
|
831
|
+
const open = openBlock(event.index);
|
|
832
|
+
openBlocks.delete(event.index);
|
|
833
|
+
if (open) {
|
|
834
|
+
const { block, contentIndex: index } = open;
|
|
842
835
|
if (block.type === "text") {
|
|
843
836
|
stream.push({
|
|
844
837
|
type: "text_end",
|
|
@@ -855,11 +848,8 @@ export const stream = (model, context, options) => {
|
|
|
855
848
|
partial: output,
|
|
856
849
|
});
|
|
857
850
|
}
|
|
858
|
-
else if (block.type === "toolCall") {
|
|
859
|
-
Object.assign(block,
|
|
860
|
-
// Finalize in-place and strip the scratch buffer so replay only
|
|
861
|
-
// carries parsed arguments.
|
|
862
|
-
delete block.partialJson;
|
|
851
|
+
else if (block.type === "toolCall" && open.arguments !== undefined) {
|
|
852
|
+
Object.assign(block, open.arguments.finish());
|
|
863
853
|
stream.push({
|
|
864
854
|
type: "toolcall_end",
|
|
865
855
|
contentIndex: index,
|
|
@@ -948,11 +938,6 @@ export const stream = (model, context, options) => {
|
|
|
948
938
|
!output.diagnostics?.some((diagnostic) => diagnostic.type === "anthropic_input_transformations")) {
|
|
949
939
|
recordInputTransformations(output, inputTransformations);
|
|
950
940
|
}
|
|
951
|
-
for (const block of output.content) {
|
|
952
|
-
delete block.index;
|
|
953
|
-
// partialJson is only a streaming scratch buffer; never persist it.
|
|
954
|
-
delete block.partialJson;
|
|
955
|
-
}
|
|
956
941
|
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
957
942
|
output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
|
958
943
|
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
@@ -1241,14 +1226,16 @@ function buildParams(model, context, isOAuthToken, options, disablePreferredStri
|
|
|
1241
1226
|
}
|
|
1242
1227
|
}
|
|
1243
1228
|
// Managed effort models always use adaptive thinking. Their per-turn markers
|
|
1244
|
-
// carry the actual effort
|
|
1229
|
+
// carry the actual effort for every reply.
|
|
1245
1230
|
if (effortMessages) {
|
|
1246
1231
|
params.thinking = {
|
|
1247
1232
|
type: "adaptive",
|
|
1248
1233
|
display: options?.thinkingDisplay ?? "summarized",
|
|
1249
1234
|
block_binding: { prefix_mismatch_behavior: "drop_block" },
|
|
1250
1235
|
};
|
|
1251
|
-
|
|
1236
|
+
// The top-level effort is part of the cached prompt, so it stays fixed. It is "low" because
|
|
1237
|
+
// organizations can cap effort and reject requests containing any level above the cap.
|
|
1238
|
+
params.output_config = { effort: "low" };
|
|
1252
1239
|
}
|
|
1253
1240
|
else if (model.reasoning) {
|
|
1254
1241
|
if (options?.thinkingEnabled) {
|