@absolutejs/ai 0.3.4 → 0.4.1
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 +18 -0
- package/README.md +15 -0
- package/changelog.json +43 -0
- package/dist/ai/index.js +170 -60
- package/dist/ai/index.js.map +9 -9
- package/dist/ai/providers/anthropic.js +111 -51
- package/dist/ai/providers/anthropic.js.map +4 -4
- package/dist/ai/providers/gemini.js +2 -2
- package/dist/ai/providers/gemini.js.map +3 -3
- package/dist/ai/providers/ollama.js +2 -2
- package/dist/ai/providers/ollama.js.map +4 -4
- package/dist/ai/providers/openai.js +41 -7
- package/dist/ai/providers/openai.js.map +5 -5
- package/dist/ai/providers/openaiCompatible.js +41 -7
- package/dist/ai/providers/openaiCompatible.js.map +5 -5
- package/dist/ai/providers/openaiResponses.js +25 -3
- package/dist/ai/providers/openaiResponses.js.map +4 -4
- package/dist/ai/providers/openrouter.js +150 -56
- package/dist/ai/providers/openrouter.js.map +6 -6
- package/dist/angular/ai/index.js +9 -7
- package/dist/angular/ai/index.js.map +2 -2
- package/dist/src/ai/streamAIWithTools.d.ts +4 -0
- package/dist/types/ai.d.ts +26 -1
- package/dist/types/anthropic.d.ts +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,24 @@ This file is generated by `absolute-changelog` from the entries in
|
|
|
6
6
|
`changelog/`. Edit an entry, not this file — and add new ones under
|
|
7
7
|
`changelog/unreleased/`.
|
|
8
8
|
|
|
9
|
+
## 0.4.1 — 2026-10-17
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Preserve provider usage snapshots through stream interruptions, distinguish partial from final usage, and retain tool-input start events without application patches** (`AIUsageUpdateChunk`, `anthropic`, `openai`, `openaiResponses`, `AIChunk`, `StreamAIWithToolsEvent`, `AIToolInputStartChunk`)
|
|
14
|
+
|
|
15
|
+
## 0.4.0 — 2026-10-16
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **Report a tool call's input while it streams: a `tool_input` chunk, and a `preparing` tools event from streamAIToSSE** (`AIChunk`, `AIToolInputChunk`, `streamAIToSSE`)
|
|
20
|
+
A tool call with a long input, such as a whole file, takes the model a minute or more to write, and until now nothing arrived meanwhile. The Anthropic provider now yields a `tool_input` chunk when a tool call starts and every 2 KB of its input, with the tool name, the characters received and the top-level string fields already complete (a path, a name; at most 200 characters each, never read from inside other values). With structured events, streamAIToSSE turns it into a `tools` event with status `preparing`. Consumers that do not know the chunk can ignore it.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- **streamAIToSSE sends a turn's text back as one block, not one per streamed delta, so agent loops stop re-writing their prompt cache** (`streamAIToSSE`)
|
|
25
|
+
streamAIToSSE stored every streamed text delta as its own content block, so an agent loop sent each turn's text back as dozens of blocks. Anthropic looks back only 20 blocks for an earlier cache entry, and a turn with a few sentences of text pushed the previous request's entry out of reach: the next request re-wrote the whole history at the cache-write price. A run of text is now one block, as generateAI and streamAIWithTools already kept it.
|
|
26
|
+
|
|
9
27
|
## 0.3.4 — 2026-10-15
|
|
10
28
|
|
|
11
29
|
### Fixed
|
package/README.md
CHANGED
|
@@ -560,3 +560,18 @@ are documented provider limits, not a substitute for runtime token budgeting.
|
|
|
560
560
|
Regional features are omitted when they are not consistently supported.
|
|
561
561
|
|
|
562
562
|
`@absolutejs/ai/research` separates an injected `SearchProvider` from evidence-only synthesis. It returns sources, findings, searches, limitations and explicit availability, and excludes invented source references/quotes. Quotation checks establish provenance; they are not a substitute for claim entailment or entity review. Hosts can set `maxRetries: 0` on one-shot or stream requests when they own attempt accounting, and independently bound `maxRepairAttempts` and disable context recovery.
|
|
563
|
+
|
|
564
|
+
### Interrupted streams and usage
|
|
565
|
+
|
|
566
|
+
Provider streams can emit `usage_update` chunks before `done`. Each carries a
|
|
567
|
+
provider-reported cumulative snapshot: replace the previous snapshot for that
|
|
568
|
+
attempt; never sum snapshots. `final: true` means the provider reported complete
|
|
569
|
+
usage. An absent or false `final` means partial evidence, not a final bill.
|
|
570
|
+
Anthropic exposes message-start and message-delta usage; OpenAI Chat exposes its
|
|
571
|
+
usage chunk, and Responses preserves usage even on incomplete responses.
|
|
572
|
+
|
|
573
|
+
Persist snapshots while consuming the stream. Cancellation or transport failure
|
|
574
|
+
can prevent `done`, and no adapter can reconstruct usage the provider never sent.
|
|
575
|
+
`onUsage` still reports only complete usage, once per instrumented stream. Keep
|
|
576
|
+
credit reservations separate from charges and reconcile unknown outcomes in the
|
|
577
|
+
host application. The package does not invent token counts or decide billing policy.
|
package/changelog.json
CHANGED
|
@@ -2,6 +2,49 @@
|
|
|
2
2
|
"contract": 1,
|
|
3
3
|
"name": "@absolutejs/ai",
|
|
4
4
|
"releases": [
|
|
5
|
+
{
|
|
6
|
+
"changes": [
|
|
7
|
+
{
|
|
8
|
+
"kind": "fixed",
|
|
9
|
+
"summary": "Preserve provider usage snapshots through stream interruptions, distinguish partial from final usage, and retain tool-input start events without application patches",
|
|
10
|
+
"symbols": [
|
|
11
|
+
"AIUsageUpdateChunk",
|
|
12
|
+
"anthropic",
|
|
13
|
+
"openai",
|
|
14
|
+
"openaiResponses",
|
|
15
|
+
"AIChunk",
|
|
16
|
+
"StreamAIWithToolsEvent",
|
|
17
|
+
"AIToolInputStartChunk"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"date": "2026-10-17",
|
|
22
|
+
"version": "0.4.1"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"changes": [
|
|
26
|
+
{
|
|
27
|
+
"detail": "streamAIToSSE stored every streamed text delta as its own content block, so an agent loop sent each turn's text back as dozens of blocks. Anthropic looks back only 20 blocks for an earlier cache entry, and a turn with a few sentences of text pushed the previous request's entry out of reach: the next request re-wrote the whole history at the cache-write price. A run of text is now one block, as generateAI and streamAIWithTools already kept it.",
|
|
28
|
+
"kind": "fixed",
|
|
29
|
+
"summary": "streamAIToSSE sends a turn's text back as one block, not one per streamed delta, so agent loops stop re-writing their prompt cache",
|
|
30
|
+
"symbols": [
|
|
31
|
+
"streamAIToSSE"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"detail": "A tool call with a long input, such as a whole file, takes the model a minute or more to write, and until now nothing arrived meanwhile. The Anthropic provider now yields a `tool_input` chunk when a tool call starts and every 2 KB of its input, with the tool name, the characters received and the top-level string fields already complete (a path, a name; at most 200 characters each, never read from inside other values). With structured events, streamAIToSSE turns it into a `tools` event with status `preparing`. Consumers that do not know the chunk can ignore it.",
|
|
36
|
+
"kind": "added",
|
|
37
|
+
"summary": "Report a tool call's input while it streams: a `tool_input` chunk, and a `preparing` tools event from streamAIToSSE",
|
|
38
|
+
"symbols": [
|
|
39
|
+
"AIChunk",
|
|
40
|
+
"AIToolInputChunk",
|
|
41
|
+
"streamAIToSSE"
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"date": "2026-10-16",
|
|
46
|
+
"version": "0.4.0"
|
|
47
|
+
},
|
|
5
48
|
{
|
|
6
49
|
"changes": [
|
|
7
50
|
{
|
package/dist/ai/index.js
CHANGED
|
@@ -999,10 +999,11 @@ var maybeFlushThinking = (chunkState) => {
|
|
|
999
999
|
};
|
|
1000
1000
|
var processTextChunk = function* (content, chunkState, renderers, fullResponse, options) {
|
|
1001
1001
|
maybeFlushThinking(chunkState);
|
|
1002
|
-
chunkState.contentBlocks.
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1002
|
+
const last = chunkState.contentBlocks.at(-1);
|
|
1003
|
+
if (last?.type === "text")
|
|
1004
|
+
last.content += content;
|
|
1005
|
+
else
|
|
1006
|
+
chunkState.contentBlocks.push({ content, type: "text" });
|
|
1006
1007
|
yield contentEvent(options, renderers, content, fullResponse + content);
|
|
1007
1008
|
};
|
|
1008
1009
|
var processImageChunk = function* (chunk, renderers, options) {
|
|
@@ -1056,6 +1057,19 @@ var processChunk = function* (chunk, chunkState, renderers, options, fullRespons
|
|
|
1056
1057
|
case "tool_use":
|
|
1057
1058
|
processToolUseChunk(chunk, chunkState);
|
|
1058
1059
|
break;
|
|
1060
|
+
case "tool_input":
|
|
1061
|
+
if (options.structuredEvents)
|
|
1062
|
+
yield {
|
|
1063
|
+
data: JSON.stringify({
|
|
1064
|
+
fields: chunk.fields,
|
|
1065
|
+
id: chunk.id,
|
|
1066
|
+
name: chunk.name,
|
|
1067
|
+
receivedChars: chunk.receivedChars,
|
|
1068
|
+
status: "preparing"
|
|
1069
|
+
}),
|
|
1070
|
+
event: "tools"
|
|
1071
|
+
};
|
|
1072
|
+
break;
|
|
1059
1073
|
case "provider_event":
|
|
1060
1074
|
maybeFlushThinking(chunkState);
|
|
1061
1075
|
chunkState.contentBlocks.push({
|
|
@@ -2060,6 +2074,8 @@ var streamAIWithTools = async function* (options) {
|
|
|
2060
2074
|
transcript: chunk.transcript,
|
|
2061
2075
|
type: "audio"
|
|
2062
2076
|
};
|
|
2077
|
+
} else if (chunk.type === "tool_input_start") {
|
|
2078
|
+
yield chunk;
|
|
2063
2079
|
} else if (chunk.type === "tool_use") {
|
|
2064
2080
|
thinking = flushThinking3(blocks, thinking);
|
|
2065
2081
|
pending.push({ id: chunk.id, input: chunk.input, name: chunk.name });
|
|
@@ -4860,7 +4876,7 @@ async function* tapStream(source, params, providerName) {
|
|
|
4860
4876
|
let lastUsage;
|
|
4861
4877
|
try {
|
|
4862
4878
|
for await (const chunk of source) {
|
|
4863
|
-
if (chunk.type === "done" && chunk.usage) {
|
|
4879
|
+
if ((chunk.type === "done" || chunk.type === "usage_update" && chunk.final) && chunk.usage) {
|
|
4864
4880
|
lastUsage = chunk.usage;
|
|
4865
4881
|
}
|
|
4866
4882
|
yield chunk;
|
|
@@ -5473,6 +5489,8 @@ var processCompleted = function* (parsed) {
|
|
|
5473
5489
|
const { response } = parsed;
|
|
5474
5490
|
const usage = extractUsage(response);
|
|
5475
5491
|
const metadata = extractResponseMetadata(response);
|
|
5492
|
+
if (usage)
|
|
5493
|
+
yield { type: "usage_update", usage, metadata, final: true };
|
|
5476
5494
|
if (isRecordArray(response.output)) {
|
|
5477
5495
|
yield* extractCitationsFromOutput(response.output);
|
|
5478
5496
|
yield* extractImageFromOutput(response.output);
|
|
@@ -5511,6 +5529,15 @@ var processSSEEvent = function* (eventType, parsed, pendingCalls, providerName)
|
|
|
5511
5529
|
break;
|
|
5512
5530
|
case "response.output_item.added":
|
|
5513
5531
|
processOutputItemAdded(parsed, pendingCalls);
|
|
5532
|
+
if (isRecord2(parsed.item) && parsed.item.type === "function_call" && typeof parsed.item.name === "string") {
|
|
5533
|
+
const id = typeof parsed.item.call_id === "string" ? parsed.item.call_id : parsed.item.id;
|
|
5534
|
+
if (typeof id === "string")
|
|
5535
|
+
yield {
|
|
5536
|
+
type: "tool_input_start",
|
|
5537
|
+
id,
|
|
5538
|
+
name: parsed.item.name
|
|
5539
|
+
};
|
|
5540
|
+
}
|
|
5514
5541
|
break;
|
|
5515
5542
|
case "response.output_item.done":
|
|
5516
5543
|
yield* processOutputItemDone(parsed);
|
|
@@ -5527,8 +5554,19 @@ var processSSEEvent = function* (eventType, parsed, pendingCalls, providerName)
|
|
|
5527
5554
|
case "response.failed":
|
|
5528
5555
|
case "response.incomplete":
|
|
5529
5556
|
case "response.error":
|
|
5530
|
-
case "error":
|
|
5557
|
+
case "error": {
|
|
5558
|
+
if (isRecord2(parsed.response)) {
|
|
5559
|
+
const usage = extractUsage(parsed.response);
|
|
5560
|
+
if (usage)
|
|
5561
|
+
yield {
|
|
5562
|
+
type: "usage_update",
|
|
5563
|
+
usage,
|
|
5564
|
+
metadata: extractResponseMetadata(parsed.response),
|
|
5565
|
+
final: false
|
|
5566
|
+
};
|
|
5567
|
+
}
|
|
5531
5568
|
throw responseFailure(eventType, parsed, providerName);
|
|
5569
|
+
}
|
|
5532
5570
|
}
|
|
5533
5571
|
};
|
|
5534
5572
|
var flushSSEBuffer = function* (state) {
|
|
@@ -5950,6 +5988,14 @@ var processDelta = function* (delta, pendingToolCalls) {
|
|
|
5950
5988
|
}
|
|
5951
5989
|
if (isRecordArray2(delta.tool_calls)) {
|
|
5952
5990
|
processToolCallDeltas(delta.tool_calls, pendingToolCalls);
|
|
5991
|
+
for (const call of delta.tool_calls) {
|
|
5992
|
+
if (isRecord3(call.function) && typeof call.function.name === "string" && call.function.name)
|
|
5993
|
+
yield {
|
|
5994
|
+
type: "tool_input_start",
|
|
5995
|
+
id: typeof call.id === "string" ? call.id : String(call.index),
|
|
5996
|
+
name: call.function.name
|
|
5997
|
+
};
|
|
5998
|
+
}
|
|
5953
5999
|
}
|
|
5954
6000
|
if (Array.isArray(delta.annotations)) {
|
|
5955
6001
|
for (const annotation of delta.annotations) {
|
|
@@ -6048,7 +6094,12 @@ var processSSELine2 = function* (line, pendingToolCalls, providerName) {
|
|
|
6048
6094
|
}
|
|
6049
6095
|
const usageUpdate = narrowUsageRecord(parsed);
|
|
6050
6096
|
if (usageUpdate) {
|
|
6051
|
-
yield {
|
|
6097
|
+
yield {
|
|
6098
|
+
type: "usage_update",
|
|
6099
|
+
usage: usageUpdate,
|
|
6100
|
+
final: Array.isArray(parsed.choices) && parsed.choices.length === 0,
|
|
6101
|
+
metadata: narrowResponseMetadata(parsed)
|
|
6102
|
+
};
|
|
6052
6103
|
}
|
|
6053
6104
|
const metadata = narrowResponseMetadata(parsed);
|
|
6054
6105
|
if (metadata) {
|
|
@@ -6077,10 +6128,9 @@ var processSSELine2 = function* (line, pendingToolCalls, providerName) {
|
|
|
6077
6128
|
}
|
|
6078
6129
|
yield* processChoice(firstChoice, pendingToolCalls);
|
|
6079
6130
|
};
|
|
6080
|
-
var isUsageUpdate = (chunk) => chunk.type === "usage_update";
|
|
6081
6131
|
var collectYieldableChunks = (line, pendingToolCalls, usageRef, metadataRef, providerName) => {
|
|
6082
6132
|
const allChunks = Array.from(processSSELine2(line, pendingToolCalls, providerName));
|
|
6083
|
-
const usageChunks = allChunks.filter(
|
|
6133
|
+
const usageChunks = allChunks.filter((chunk) => chunk.type === "usage_update");
|
|
6084
6134
|
const lastUsage = usageChunks.at(NOT_FOUND4);
|
|
6085
6135
|
if (lastUsage) {
|
|
6086
6136
|
usageRef.current = lastUsage.usage;
|
|
@@ -6097,7 +6147,7 @@ var collectYieldableChunks = (line, pendingToolCalls, usageRef, metadataRef, pro
|
|
|
6097
6147
|
}
|
|
6098
6148
|
};
|
|
6099
6149
|
}
|
|
6100
|
-
return allChunks.filter((chunk) =>
|
|
6150
|
+
return allChunks.filter((chunk) => chunk.type !== "response_metadata").map((chunk) => chunk.type === "usage_update" ? { ...chunk, metadata: metadataRef.current } : chunk);
|
|
6101
6151
|
};
|
|
6102
6152
|
var processSSELines2 = function* (lines, pendingToolCalls, usageRef, metadataRef, providerName) {
|
|
6103
6153
|
for (const line of lines) {
|
|
@@ -6599,7 +6649,6 @@ var API_VERSION = "2023-06-01";
|
|
|
6599
6649
|
var DEFAULT_MAX_TOKENS = 32000;
|
|
6600
6650
|
var EVENT_PREFIX_LENGTH2 = 7;
|
|
6601
6651
|
var DATA_PREFIX_LENGTH2 = 6;
|
|
6602
|
-
var EMPTY_CHUNKS = [];
|
|
6603
6652
|
var isRecord5 = (val) => typeof val === "object" && val !== null;
|
|
6604
6653
|
var mapContentBlock2 = (block) => {
|
|
6605
6654
|
if (block.type === "thinking") {
|
|
@@ -6878,14 +6927,79 @@ var getNumber = (obj, key) => {
|
|
|
6878
6927
|
}
|
|
6879
6928
|
return 0;
|
|
6880
6929
|
};
|
|
6930
|
+
var TOOL_INPUT_PROGRESS_CHARS = 2048;
|
|
6931
|
+
var TOOL_INPUT_FIELD_MAX_CHARS = 200;
|
|
6932
|
+
var readJsonString = (json, start) => {
|
|
6933
|
+
for (let index = start + 1;index < json.length; index += 1) {
|
|
6934
|
+
if (json[index] === "\\")
|
|
6935
|
+
index += 1;
|
|
6936
|
+
else if (json[index] === '"')
|
|
6937
|
+
return { end: index + 1, raw: json.slice(start + 1, index) };
|
|
6938
|
+
}
|
|
6939
|
+
return;
|
|
6940
|
+
};
|
|
6941
|
+
var decodeJsonString = (raw) => {
|
|
6942
|
+
try {
|
|
6943
|
+
const value = JSON.parse(`"${raw}"`);
|
|
6944
|
+
return typeof value === "string" ? value : undefined;
|
|
6945
|
+
} catch {
|
|
6946
|
+
return;
|
|
6947
|
+
}
|
|
6948
|
+
};
|
|
6949
|
+
var completeStringFields = (partialJson) => {
|
|
6950
|
+
const fields = {};
|
|
6951
|
+
let depth = 0;
|
|
6952
|
+
let key;
|
|
6953
|
+
let index = 0;
|
|
6954
|
+
while (index < partialJson.length) {
|
|
6955
|
+
const character = partialJson[index];
|
|
6956
|
+
if (character === '"') {
|
|
6957
|
+
const text = readJsonString(partialJson, index);
|
|
6958
|
+
if (!text)
|
|
6959
|
+
break;
|
|
6960
|
+
if (depth === 1 && key === undefined) {
|
|
6961
|
+
const after = partialJson.slice(text.end).trimStart();
|
|
6962
|
+
if (after.startsWith(":"))
|
|
6963
|
+
key = text.raw;
|
|
6964
|
+
} else if (depth === 1 && key !== undefined) {
|
|
6965
|
+
const value = decodeJsonString(text.raw);
|
|
6966
|
+
if (value !== undefined && value.length <= TOOL_INPUT_FIELD_MAX_CHARS)
|
|
6967
|
+
fields[key] = value;
|
|
6968
|
+
key = undefined;
|
|
6969
|
+
}
|
|
6970
|
+
index = text.end;
|
|
6971
|
+
continue;
|
|
6972
|
+
}
|
|
6973
|
+
if (character === "{" || character === "[")
|
|
6974
|
+
depth += 1;
|
|
6975
|
+
else if (character === "}" || character === "]")
|
|
6976
|
+
depth -= 1;
|
|
6977
|
+
else if (character === "," && depth === 1)
|
|
6978
|
+
key = undefined;
|
|
6979
|
+
index += 1;
|
|
6980
|
+
}
|
|
6981
|
+
return fields;
|
|
6982
|
+
};
|
|
6983
|
+
var toolInputProgress = (state) => {
|
|
6984
|
+
state.toolInputReported = state.toolInputJson.length;
|
|
6985
|
+
return {
|
|
6986
|
+
fields: completeStringFields(state.toolInputJson),
|
|
6987
|
+
id: state.currentToolId,
|
|
6988
|
+
name: state.currentToolName,
|
|
6989
|
+
receivedChars: state.toolInputJson.length,
|
|
6990
|
+
type: "tool_input"
|
|
6991
|
+
};
|
|
6992
|
+
};
|
|
6881
6993
|
var handleContentBlockStart = (parsed, state) => {
|
|
6882
6994
|
const block = getRecord(parsed, "content_block");
|
|
6883
6995
|
if (block && block.type === "tool_use") {
|
|
6884
6996
|
state.currentToolId = getString(block, "id");
|
|
6885
6997
|
state.currentToolName = getString(block, "name");
|
|
6886
6998
|
state.toolInputJson = "";
|
|
6999
|
+
state.toolInputReported = 0;
|
|
6887
7000
|
state.isThinkingBlock = false;
|
|
6888
7001
|
state.currentProviderBlock = undefined;
|
|
7002
|
+
return toolInputProgress(state);
|
|
6889
7003
|
} else if (block && block.type === "thinking") {
|
|
6890
7004
|
state.isThinkingBlock = true;
|
|
6891
7005
|
state.thinkingSignature = "";
|
|
@@ -6895,6 +7009,7 @@ var handleContentBlockStart = (parsed, state) => {
|
|
|
6895
7009
|
state.currentProviderBlock = block && block.type !== "text" ? { ...block } : undefined;
|
|
6896
7010
|
state.providerBlockInputJson = "";
|
|
6897
7011
|
}
|
|
7012
|
+
return;
|
|
6898
7013
|
};
|
|
6899
7014
|
var handleContentBlockDelta = (parsed, state) => {
|
|
6900
7015
|
const delta = getRecord(parsed, "delta");
|
|
@@ -6929,6 +7044,8 @@ var handleContentBlockDelta = (parsed, state) => {
|
|
|
6929
7044
|
state.providerBlockInputJson += getString(delta, "partial_json");
|
|
6930
7045
|
} else {
|
|
6931
7046
|
state.toolInputJson += getString(delta, "partial_json");
|
|
7047
|
+
if (state.toolInputJson.length - state.toolInputReported >= TOOL_INPUT_PROGRESS_CHARS)
|
|
7048
|
+
return toolInputProgress(state);
|
|
6932
7049
|
}
|
|
6933
7050
|
}
|
|
6934
7051
|
if (delta.type === "signature_delta") {
|
|
@@ -7048,8 +7165,7 @@ var handleError = (parsed, state) => {
|
|
|
7048
7165
|
var processEvent = (eventType, parsed, state) => {
|
|
7049
7166
|
switch (eventType) {
|
|
7050
7167
|
case "content_block_start": {
|
|
7051
|
-
handleContentBlockStart(parsed, state);
|
|
7052
|
-
return;
|
|
7168
|
+
return handleContentBlockStart(parsed, state);
|
|
7053
7169
|
}
|
|
7054
7170
|
case "content_block_delta": {
|
|
7055
7171
|
return handleContentBlockDelta(parsed, state);
|
|
@@ -7060,11 +7176,21 @@ var processEvent = (eventType, parsed, state) => {
|
|
|
7060
7176
|
case "message_delta": {
|
|
7061
7177
|
handleMessageDelta(parsed, state);
|
|
7062
7178
|
mergeMetadata(parsed, state);
|
|
7063
|
-
return
|
|
7179
|
+
return state.usage ? {
|
|
7180
|
+
type: "usage_update",
|
|
7181
|
+
usage: state.usage,
|
|
7182
|
+
metadata: state.metadata,
|
|
7183
|
+
final: false
|
|
7184
|
+
} : undefined;
|
|
7064
7185
|
}
|
|
7065
7186
|
case "message_start": {
|
|
7066
7187
|
handleMessageStart(parsed, state);
|
|
7067
|
-
return
|
|
7188
|
+
return state.usage ? {
|
|
7189
|
+
type: "usage_update",
|
|
7190
|
+
usage: state.usage,
|
|
7191
|
+
metadata: state.metadata,
|
|
7192
|
+
final: false
|
|
7193
|
+
} : undefined;
|
|
7068
7194
|
}
|
|
7069
7195
|
case "message_stop": {
|
|
7070
7196
|
mergeMetadata(parsed, state);
|
|
@@ -7098,49 +7224,6 @@ var processSingleEvent = (event, state) => {
|
|
|
7098
7224
|
}
|
|
7099
7225
|
return processEvent(eventType, parsed, state);
|
|
7100
7226
|
};
|
|
7101
|
-
var collectChunk = (event, state) => {
|
|
7102
|
-
const chunk = processSingleEvent(event, state);
|
|
7103
|
-
return chunk ? [chunk] : [];
|
|
7104
|
-
};
|
|
7105
|
-
var processBufferedEvents = (eventsText, state) => {
|
|
7106
|
-
const events = eventsText.split(`
|
|
7107
|
-
|
|
7108
|
-
`);
|
|
7109
|
-
state.buffer = events.pop() ?? "";
|
|
7110
|
-
return events.flatMap((event) => collectChunk(event, state));
|
|
7111
|
-
};
|
|
7112
|
-
var readNextChunks = async (reader, decoder, state, signal) => {
|
|
7113
|
-
if (signal?.aborted) {
|
|
7114
|
-
return { chunks: EMPTY_CHUNKS, done: true };
|
|
7115
|
-
}
|
|
7116
|
-
const { done, value } = await reader.read();
|
|
7117
|
-
if (done) {
|
|
7118
|
-
return { chunks: EMPTY_CHUNKS, done: true };
|
|
7119
|
-
}
|
|
7120
|
-
const rawText = state.buffer + decoder.decode(value, { stream: true });
|
|
7121
|
-
const chunks = processBufferedEvents(rawText, state);
|
|
7122
|
-
return { chunks, done: false };
|
|
7123
|
-
};
|
|
7124
|
-
var findDoneChunk = (chunks) => chunks.findIndex((c) => c.type === "done");
|
|
7125
|
-
var sseStreamLoop = async (reader, decoder, state, signal) => {
|
|
7126
|
-
const result = await readNextChunks(reader, decoder, state, signal);
|
|
7127
|
-
if (result.done) {
|
|
7128
|
-
return { chunks: result.chunks, finished: true };
|
|
7129
|
-
}
|
|
7130
|
-
const doneIdx = findDoneChunk(result.chunks);
|
|
7131
|
-
if (doneIdx >= 0) {
|
|
7132
|
-
return { chunks: result.chunks.slice(0, doneIdx + 1), finished: true };
|
|
7133
|
-
}
|
|
7134
|
-
return { chunks: result.chunks, finished: false };
|
|
7135
|
-
};
|
|
7136
|
-
async function* streamChunks(reader, decoder, state, signal) {
|
|
7137
|
-
let finished = false;
|
|
7138
|
-
while (!finished) {
|
|
7139
|
-
const result = await sseStreamLoop(reader, decoder, state, signal);
|
|
7140
|
-
({ finished } = result);
|
|
7141
|
-
yield* result.chunks;
|
|
7142
|
-
}
|
|
7143
|
-
}
|
|
7144
7227
|
async function* parseSSEStream4(body, providerName, signal) {
|
|
7145
7228
|
const reader = body.getReader();
|
|
7146
7229
|
const decoder = new TextDecoder;
|
|
@@ -7152,13 +7235,40 @@ async function* parseSSEStream4(body, providerName, signal) {
|
|
|
7152
7235
|
stopReason: "",
|
|
7153
7236
|
thinkingSignature: "",
|
|
7154
7237
|
toolInputJson: "",
|
|
7238
|
+
toolInputReported: 0,
|
|
7155
7239
|
usage: undefined,
|
|
7156
7240
|
providerName,
|
|
7157
7241
|
providerBlockInputJson: ""
|
|
7158
7242
|
};
|
|
7159
7243
|
try {
|
|
7160
|
-
|
|
7244
|
+
while (true) {
|
|
7245
|
+
signal?.throwIfAborted();
|
|
7246
|
+
const { done, value } = await reader.read();
|
|
7247
|
+
if (done)
|
|
7248
|
+
return;
|
|
7249
|
+
const events = (state.buffer + decoder.decode(value, { stream: true })).split(`
|
|
7250
|
+
|
|
7251
|
+
`);
|
|
7252
|
+
state.buffer = events.pop() ?? "";
|
|
7253
|
+
for (const event of events) {
|
|
7254
|
+
const chunk = processSingleEvent(event, state);
|
|
7255
|
+
if (!chunk)
|
|
7256
|
+
continue;
|
|
7257
|
+
if (chunk.type === "tool_input" && chunk.receivedChars === 0)
|
|
7258
|
+
yield {
|
|
7259
|
+
type: "tool_input_start",
|
|
7260
|
+
id: chunk.id,
|
|
7261
|
+
name: chunk.name
|
|
7262
|
+
};
|
|
7263
|
+
yield chunk;
|
|
7264
|
+
if (chunk.type === "done")
|
|
7265
|
+
return;
|
|
7266
|
+
}
|
|
7267
|
+
}
|
|
7161
7268
|
} finally {
|
|
7269
|
+
await reader.cancel().catch(() => {
|
|
7270
|
+
return;
|
|
7271
|
+
});
|
|
7162
7272
|
reader.releaseLock();
|
|
7163
7273
|
}
|
|
7164
7274
|
}
|
|
@@ -9062,5 +9172,5 @@ export {
|
|
|
9062
9172
|
xai
|
|
9063
9173
|
};
|
|
9064
9174
|
|
|
9065
|
-
//# debugId=
|
|
9175
|
+
//# debugId=A58174807DA8A73664756E2164756E21
|
|
9066
9176
|
//# sourceMappingURL=index.js.map
|