ns-kiro-core 0.1.2 → 0.2.0
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/dist/cost.d.ts +6 -1
- package/dist/cost.js +9 -2
- package/dist/cost.js.map +1 -1
- package/dist/effort.js +10 -2
- package/dist/effort.js.map +1 -1
- package/dist/event-parser.d.ts +28 -4
- package/dist/event-parser.js +40 -1
- package/dist/event-parser.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kiro-cli.d.ts +17 -0
- package/dist/kiro-cli.js +47 -1
- package/dist/kiro-cli.js.map +1 -1
- package/dist/models.d.ts +10 -2
- package/dist/models.js +70 -4
- package/dist/models.js.map +1 -1
- package/dist/request-builder.d.ts +49 -0
- package/dist/request-builder.js +229 -0
- package/dist/request-builder.js.map +1 -0
- package/dist/response-assembler.d.ts +89 -0
- package/dist/response-assembler.js +330 -0
- package/dist/response-assembler.js.map +1 -0
- package/dist/response-stream.d.ts +39 -0
- package/dist/response-stream.js +123 -0
- package/dist/response-stream.js.map +1 -0
- package/dist/stream.js +72 -621
- package/dist/stream.js.map +1 -1
- package/dist/transport.d.ts +24 -0
- package/dist/transport.js +80 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +30 -0
- package/package.json +6 -1
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
// ABOUTME: Turns Kiro wire events into neutral content blocks and a stop reason.
|
|
2
|
+
// ABOUTME: Owns what the response says; the request loop owns whether to ask again.
|
|
3
|
+
import { KiroBlockBuffer } from "./blocks.js";
|
|
4
|
+
import { parseBracketToolCalls } from "./bracket-tool-parser.js";
|
|
5
|
+
import { calculateKiroCost } from "./cost.js";
|
|
6
|
+
import { debugEnabled, debugLog, formatSafeError, redactSensitiveText } from "./debug.js";
|
|
7
|
+
import { parseInvokeToolCalls } from "./invoke-tool-parser.js";
|
|
8
|
+
import { ThinkingTagParser } from "./thinking-parser.js";
|
|
9
|
+
import { countTokens } from "./tokenizer.js";
|
|
10
|
+
/** Text that is an artifact of history padding rather than an answer. */
|
|
11
|
+
const ECHO_NOISE_PATTERN = /^\s*(continue|\.+)\s*$/i;
|
|
12
|
+
/**
|
|
13
|
+
* Accumulates one response.
|
|
14
|
+
*
|
|
15
|
+
* Block indexes are monotonic across the whole call, including across an
|
|
16
|
+
* internal retry, so the buffer and the usage totals outlive a single attempt
|
|
17
|
+
* while everything else is reset by {@link beginAttempt}.
|
|
18
|
+
*/
|
|
19
|
+
export class KiroResponseAssembler {
|
|
20
|
+
model;
|
|
21
|
+
thinkingEnabled;
|
|
22
|
+
pending = [];
|
|
23
|
+
blocks = new KiroBlockBuffer((event) => this.pending.push(event));
|
|
24
|
+
usage = {
|
|
25
|
+
input: 0,
|
|
26
|
+
output: 0,
|
|
27
|
+
totalTokens: 0,
|
|
28
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
29
|
+
};
|
|
30
|
+
totalContent = "";
|
|
31
|
+
lastContentData = "";
|
|
32
|
+
usageEvent = null;
|
|
33
|
+
receivedContextUsage = false;
|
|
34
|
+
thinkingParser = null;
|
|
35
|
+
nativeThinkingBlockIndex = null;
|
|
36
|
+
nativeThinkingEnded = false;
|
|
37
|
+
textBlockIndex = null;
|
|
38
|
+
emittedToolCalls = 0;
|
|
39
|
+
sawAnyToolCalls = false;
|
|
40
|
+
currentToolCall = null;
|
|
41
|
+
constructor(model, thinkingEnabled) {
|
|
42
|
+
this.model = model;
|
|
43
|
+
this.thinkingEnabled = thinkingEnabled;
|
|
44
|
+
}
|
|
45
|
+
/** Clear per-attempt state. Block indexes and accumulated usage are kept. */
|
|
46
|
+
beginAttempt() {
|
|
47
|
+
this.totalContent = "";
|
|
48
|
+
this.lastContentData = "";
|
|
49
|
+
this.usageEvent = null;
|
|
50
|
+
this.receivedContextUsage = false;
|
|
51
|
+
this.thinkingParser = this.thinkingEnabled ? new ThinkingTagParser(this.blocks) : null;
|
|
52
|
+
this.nativeThinkingBlockIndex = null;
|
|
53
|
+
this.nativeThinkingEnded = false;
|
|
54
|
+
this.textBlockIndex = null;
|
|
55
|
+
this.emittedToolCalls = 0;
|
|
56
|
+
this.sawAnyToolCalls = false;
|
|
57
|
+
this.currentToolCall = null;
|
|
58
|
+
}
|
|
59
|
+
/** Hand over the events buffered so far. */
|
|
60
|
+
takeEvents() {
|
|
61
|
+
return this.pending.splice(0, this.pending.length);
|
|
62
|
+
}
|
|
63
|
+
/** Announce that a retry discarded everything emitted so far. */
|
|
64
|
+
discard() {
|
|
65
|
+
this.blocks.reset();
|
|
66
|
+
this.textBlockIndex = null;
|
|
67
|
+
}
|
|
68
|
+
handle(frame) {
|
|
69
|
+
const { event, payload } = frame;
|
|
70
|
+
switch (event.type) {
|
|
71
|
+
case "contextUsage": {
|
|
72
|
+
const pct = event.data.contextUsagePercentage;
|
|
73
|
+
this.usage.input = Math.round((pct / 100) * this.model.contextWindow);
|
|
74
|
+
this.usage.contextPercent = pct;
|
|
75
|
+
this.receivedContextUsage = true;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
case "thinkingText": {
|
|
79
|
+
if (!this.thinkingEnabled)
|
|
80
|
+
break;
|
|
81
|
+
this.blocks.appendThinking(this.ensureNativeThinkingBlock(), event.data);
|
|
82
|
+
this.totalContent += event.data;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case "thinkingSignature": {
|
|
86
|
+
if (!this.thinkingEnabled)
|
|
87
|
+
break;
|
|
88
|
+
this.ensureNativeThinkingBlock();
|
|
89
|
+
this.endNativeThinking(event.data);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case "content": {
|
|
93
|
+
this.endNativeThinking();
|
|
94
|
+
// Kiro repeats the last content frame on some turns; a repeat carries no
|
|
95
|
+
// new text and must not be appended twice.
|
|
96
|
+
if (event.data === this.lastContentData)
|
|
97
|
+
break;
|
|
98
|
+
this.lastContentData = event.data;
|
|
99
|
+
this.totalContent += event.data;
|
|
100
|
+
if (this.thinkingParser) {
|
|
101
|
+
this.thinkingParser.processChunk(event.data);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
if (this.textBlockIndex === null)
|
|
105
|
+
this.textBlockIndex = this.blocks.openText();
|
|
106
|
+
this.blocks.appendText(this.textBlockIndex, event.data);
|
|
107
|
+
}
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
case "toolUse": {
|
|
111
|
+
const tc = event.data;
|
|
112
|
+
this.sawAnyToolCalls = true;
|
|
113
|
+
if (!this.currentToolCall || this.currentToolCall.toolUseId !== tc.toolUseId) {
|
|
114
|
+
this.flushToolCall();
|
|
115
|
+
this.currentToolCall = { toolUseId: tc.toolUseId, name: tc.name, input: "" };
|
|
116
|
+
}
|
|
117
|
+
this.currentToolCall.input += tc.input || "";
|
|
118
|
+
if (tc.input)
|
|
119
|
+
this.totalContent += tc.input;
|
|
120
|
+
if (tc.stop)
|
|
121
|
+
this.flushToolCall();
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
case "toolUseInput": {
|
|
125
|
+
if (this.currentToolCall)
|
|
126
|
+
this.currentToolCall.input += event.data.input || "";
|
|
127
|
+
if (event.data.input)
|
|
128
|
+
this.totalContent += event.data.input;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
case "toolUseStop": {
|
|
132
|
+
if (event.data.stop)
|
|
133
|
+
this.flushToolCall();
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case "usage": {
|
|
137
|
+
this.usageEvent = event.data;
|
|
138
|
+
// The parsed event keeps only the fields this package understands.
|
|
139
|
+
// Log the frame verbatim so a field Kiro adds — cache counters above
|
|
140
|
+
// all — is visible without having to guess its name first.
|
|
141
|
+
if (debugEnabled())
|
|
142
|
+
debugLog("response.usageRaw", payload);
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
// followupPrompt events are intentionally ignored
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Close the turn: flush a trailing tool call, close thinking, and run the
|
|
150
|
+
* text-dialect recovery and echo-stripping passes.
|
|
151
|
+
*/
|
|
152
|
+
endTurn() {
|
|
153
|
+
if (this.currentToolCall && this.emitToolCall(this.currentToolCall))
|
|
154
|
+
this.emittedToolCalls++;
|
|
155
|
+
this.currentToolCall = null;
|
|
156
|
+
this.endNativeThinking();
|
|
157
|
+
if (this.thinkingParser) {
|
|
158
|
+
this.thinkingParser.finalize();
|
|
159
|
+
this.textBlockIndex = this.thinkingParser.getTextBlockIndex();
|
|
160
|
+
}
|
|
161
|
+
this.recoverTextToolCalls();
|
|
162
|
+
this.stripEchoNoise();
|
|
163
|
+
const responseText = this.textBlockIndex === null ? "" : this.blocks.getText(this.textBlockIndex);
|
|
164
|
+
const hasText = responseText.length > 0;
|
|
165
|
+
return {
|
|
166
|
+
responseText,
|
|
167
|
+
hasText,
|
|
168
|
+
sawAnyToolCalls: this.sawAnyToolCalls,
|
|
169
|
+
emittedToolCalls: this.emittedToolCalls,
|
|
170
|
+
isEchoLoop: hasText && !this.sawAnyToolCalls && ECHO_NOISE_PATTERN.test(responseText),
|
|
171
|
+
isEmpty: !hasText && !this.sawAnyToolCalls,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/** Drop an echo the caller decided not to retry, so it is not read as a continuation signal. */
|
|
175
|
+
stripEcho() {
|
|
176
|
+
if (this.textBlockIndex !== null)
|
|
177
|
+
this.blocks.setText(this.textBlockIndex, "");
|
|
178
|
+
}
|
|
179
|
+
/** Close the text block and settle usage and the stop reason. */
|
|
180
|
+
complete() {
|
|
181
|
+
if (this.textBlockIndex !== null)
|
|
182
|
+
this.blocks.endText(this.textBlockIndex);
|
|
183
|
+
// Kiro does not reliably emit per-response output token counts. When the
|
|
184
|
+
// `usage` event is missing or reports only `inputTokens`, fall back to a
|
|
185
|
+
// tiktoken estimate over everything the assistant emitted — text plus
|
|
186
|
+
// tool-call input JSON. Otherwise tool-call-only turns report 0 output
|
|
187
|
+
// tokens and break consumers that watch it.
|
|
188
|
+
if (this.usageEvent?.inputTokens !== undefined)
|
|
189
|
+
this.usage.input = this.usageEvent.inputTokens;
|
|
190
|
+
this.usage.output = this.usageEvent?.outputTokens ?? countTokens(this.totalContent);
|
|
191
|
+
this.usage.totalTokens = this.usage.input + this.usage.output;
|
|
192
|
+
// Only set when reported: leaving these absent is what tells a host that
|
|
193
|
+
// Kiro said nothing about caching, rather than that nothing was cached.
|
|
194
|
+
if (this.usageEvent?.cacheReadTokens !== undefined)
|
|
195
|
+
this.usage.cacheRead = this.usageEvent.cacheReadTokens;
|
|
196
|
+
if (this.usageEvent?.cacheWriteTokens !== undefined)
|
|
197
|
+
this.usage.cacheWrite = this.usageEvent.cacheWriteTokens;
|
|
198
|
+
if (this.usageEvent?.credits !== undefined)
|
|
199
|
+
this.usage.credits = this.usageEvent.credits;
|
|
200
|
+
if (this.usageEvent?.creditUnit !== undefined)
|
|
201
|
+
this.usage.creditUnit = this.usageEvent.creditUnit;
|
|
202
|
+
this.usage.cost = calculateKiroCost(this.model.cost, this.usage);
|
|
203
|
+
// Use `emittedToolCalls`, not the count seen on the wire: a turn whose calls
|
|
204
|
+
// were all dropped for unparseable input must not report `toolUse`, because
|
|
205
|
+
// an empty turn with a tool-use stop stalls an agent loop waiting for
|
|
206
|
+
// results that will never arrive.
|
|
207
|
+
//
|
|
208
|
+
// `length` is inferred, not reported: Kiro sends no stop reason, so a turn
|
|
209
|
+
// that produced no tool call and never carried a contextUsage frame is
|
|
210
|
+
// treated as cut short.
|
|
211
|
+
//
|
|
212
|
+
// That rests on contextUsage closing every complete response. Checked
|
|
213
|
+
// 2026-09-06 across a short reply, a ~5000-character one, a tool-call turn,
|
|
214
|
+
// a model with no effort schema (claude-haiku-4.5) and a non-Claude model
|
|
215
|
+
// (glm-5): the frame arrived in all five, so its absence really does mark an
|
|
216
|
+
// abnormal turn. `response.done` logs `receivedContextUsage` in case a later
|
|
217
|
+
// Kiro stops sending it — a false `length` is read by hosts as truncation
|
|
218
|
+
// and prepends TRUNCATION_NOTICE, asking the model to continue work it
|
|
219
|
+
// already finished.
|
|
220
|
+
const stopReason = !this.receivedContextUsage && this.emittedToolCalls === 0
|
|
221
|
+
? "length"
|
|
222
|
+
: this.emittedToolCalls > 0
|
|
223
|
+
? "toolUse"
|
|
224
|
+
: "stop";
|
|
225
|
+
debugLog("response.done", {
|
|
226
|
+
stopReason,
|
|
227
|
+
receivedContextUsage: this.receivedContextUsage,
|
|
228
|
+
emittedToolCalls: this.emittedToolCalls,
|
|
229
|
+
sawAnyToolCalls: this.sawAnyToolCalls,
|
|
230
|
+
textLen: this.textBlockIndex === null ? 0 : this.blocks.getText(this.textBlockIndex).length,
|
|
231
|
+
usage: this.usage,
|
|
232
|
+
});
|
|
233
|
+
return { stopReason, usage: this.usage };
|
|
234
|
+
}
|
|
235
|
+
ensureNativeThinkingBlock() {
|
|
236
|
+
if (this.nativeThinkingBlockIndex === null)
|
|
237
|
+
this.nativeThinkingBlockIndex = this.blocks.openThinking();
|
|
238
|
+
return this.nativeThinkingBlockIndex;
|
|
239
|
+
}
|
|
240
|
+
endNativeThinking(signature) {
|
|
241
|
+
if (this.nativeThinkingBlockIndex === null || this.nativeThinkingEnded)
|
|
242
|
+
return;
|
|
243
|
+
this.nativeThinkingEnded = true;
|
|
244
|
+
this.blocks.endThinking(this.nativeThinkingBlockIndex, signature);
|
|
245
|
+
}
|
|
246
|
+
emitToolCall(state) {
|
|
247
|
+
if (!state.input.trim()) {
|
|
248
|
+
// Kiro omits the input payload when the model calls a tool with no
|
|
249
|
+
// arguments (e.g. `mcp({})`). Treat empty input as an empty object
|
|
250
|
+
// rather than skipping — these are valid zero-arg calls, not truncations.
|
|
251
|
+
state.input = "{}";
|
|
252
|
+
}
|
|
253
|
+
let args;
|
|
254
|
+
try {
|
|
255
|
+
args = JSON.parse(state.input);
|
|
256
|
+
}
|
|
257
|
+
catch (e) {
|
|
258
|
+
console.warn(`[kiro-core] Failed to parse tool input for "${state.name}" (toolUseId: ${state.toolUseId}): ${formatSafeError(e)}. Raw input (${state.input.length} chars): ${redactSensitiveText(state.input.substring(0, 200))}`);
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
const index = this.blocks.reserve();
|
|
262
|
+
this.pending.push({ type: "tool_call_start", index, id: state.toolUseId, name: state.name });
|
|
263
|
+
this.pending.push({ type: "tool_call_delta", index, id: state.toolUseId, argumentsDelta: state.input });
|
|
264
|
+
this.pending.push({ type: "tool_call_end", index, id: state.toolUseId, name: state.name, arguments: args });
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
flushToolCall() {
|
|
268
|
+
if (!this.currentToolCall)
|
|
269
|
+
return;
|
|
270
|
+
if (this.emitToolCall(this.currentToolCall))
|
|
271
|
+
this.emittedToolCalls++;
|
|
272
|
+
this.currentToolCall = null;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Extract text-dialect tool calls from content when no native tool calls
|
|
276
|
+
* arrived. Two dialects are recovered at this seam:
|
|
277
|
+
* 1. Kiro's own `[Called name with args: {...}]` bracket form.
|
|
278
|
+
* 2. Anthropic's `<invoke name="..."><parameter .../></invoke>` XML form,
|
|
279
|
+
* which opus-class models emit as plain text at high context.
|
|
280
|
+
* Without this, the turn ends `stop` with zero tool calls — the agent loop
|
|
281
|
+
* sees a finished answer and an unattended session stalls with no error
|
|
282
|
+
* recorded anywhere.
|
|
283
|
+
*
|
|
284
|
+
* Models that emit native tool-use events opt out via
|
|
285
|
+
* `recoverTextToolCalls: false`. For them this pass has nothing to rescue
|
|
286
|
+
* and everything to break: prose that merely *quotes* the syntax — a model
|
|
287
|
+
* explaining how a tool is called — would be lifted into a real call the
|
|
288
|
+
* model never made. Absent means recover, so a model the catalog says
|
|
289
|
+
* nothing about keeps the fallback.
|
|
290
|
+
*/
|
|
291
|
+
recoverTextToolCalls() {
|
|
292
|
+
if (this.model.recoverTextToolCalls === false || this.sawAnyToolCalls || this.textBlockIndex === null)
|
|
293
|
+
return;
|
|
294
|
+
let text = this.blocks.getText(this.textBlockIndex);
|
|
295
|
+
const recovered = [];
|
|
296
|
+
const bracketResult = parseBracketToolCalls(text);
|
|
297
|
+
if (bracketResult.toolCalls.length > 0) {
|
|
298
|
+
text = bracketResult.cleanedText;
|
|
299
|
+
recovered.push(...bracketResult.toolCalls);
|
|
300
|
+
}
|
|
301
|
+
const invokeResult = parseInvokeToolCalls(text);
|
|
302
|
+
if (invokeResult.toolCalls.length > 0) {
|
|
303
|
+
text = invokeResult.cleanedText;
|
|
304
|
+
recovered.push(...invokeResult.toolCalls);
|
|
305
|
+
}
|
|
306
|
+
if (recovered.length === 0)
|
|
307
|
+
return;
|
|
308
|
+
this.blocks.setText(this.textBlockIndex, text);
|
|
309
|
+
this.sawAnyToolCalls = true;
|
|
310
|
+
for (const call of recovered) {
|
|
311
|
+
if (this.emitToolCall({ toolUseId: call.toolUseId, name: call.name, input: JSON.stringify(call.arguments) })) {
|
|
312
|
+
this.emittedToolCalls++;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Strip echo noise: when tool calls are present and the text content is just
|
|
318
|
+
* "." or a similar short echo from history padding, remove it. This prevents
|
|
319
|
+
* the echo from accumulating in conversation history and reinforcing the
|
|
320
|
+
* pattern in future turns.
|
|
321
|
+
*/
|
|
322
|
+
stripEchoNoise() {
|
|
323
|
+
if (this.emittedToolCalls === 0 || this.textBlockIndex === null)
|
|
324
|
+
return;
|
|
325
|
+
if (ECHO_NOISE_PATTERN.test(this.blocks.getText(this.textBlockIndex))) {
|
|
326
|
+
this.blocks.setText(this.textBlockIndex, "");
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=response-assembler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-assembler.js","sourceRoot":"","sources":["../src/response-assembler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type KiroWireEvent } from "./event-parser.js";
|
|
2
|
+
/** Longest gap between two frames before the response is treated as stalled. */
|
|
3
|
+
export declare const IDLE_TIMEOUT = 300000;
|
|
4
|
+
/**
|
|
5
|
+
* Why the stream stopped. Every field is a retryable condition; all false means
|
|
6
|
+
* the response ended normally.
|
|
7
|
+
*/
|
|
8
|
+
export interface KiroEventStreamOutcome {
|
|
9
|
+
firstTokenTimedOut: boolean;
|
|
10
|
+
idleTimedOut: boolean;
|
|
11
|
+
/** Message from a Smithy protocol error or a Kiro `error` frame. */
|
|
12
|
+
error: string | null;
|
|
13
|
+
}
|
|
14
|
+
export interface KiroWireEventFrame {
|
|
15
|
+
event: KiroWireEvent;
|
|
16
|
+
/** The frame verbatim, for logging fields this package does not model. */
|
|
17
|
+
payload: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface KiroEventStreamOptions {
|
|
20
|
+
firstTokenTimeoutMs: number;
|
|
21
|
+
idleTimeoutMs?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface KiroEventStreamReader {
|
|
24
|
+
frames: AsyncGenerator<KiroWireEventFrame>;
|
|
25
|
+
/** Populated by the time `frames` completes. */
|
|
26
|
+
outcome: KiroEventStreamOutcome;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Turn a Kiro response body into parsed wire events.
|
|
30
|
+
*
|
|
31
|
+
* Terminal conditions are reported through {@link KiroEventStreamOutcome}
|
|
32
|
+
* rather than thrown: the caller retries all three the same way, and a throw
|
|
33
|
+
* would force it to re-classify the cause it already knows.
|
|
34
|
+
*
|
|
35
|
+
* A Kiro `error` frame ends the stream and is not yielded — it carries no
|
|
36
|
+
* content, and every caller treats it as the same retryable failure as a
|
|
37
|
+
* protocol error.
|
|
38
|
+
*/
|
|
39
|
+
export declare function readKiroEventStream(body: ReadableStream<Uint8Array>, options: KiroEventStreamOptions): KiroEventStreamReader;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// ABOUTME: Reads Kiro's AWS event-stream response into parsed wire events.
|
|
2
|
+
// ABOUTME: Owns framing and the stall timeouts; block assembly lives elsewhere.
|
|
3
|
+
import { UniversalEventStreamMarshaller } from "@smithy/core/event-streams";
|
|
4
|
+
import { debugEnabled, debugLog } from "./debug.js";
|
|
5
|
+
import { parseKiroEvent } from "./event-parser.js";
|
|
6
|
+
/** Longest gap between two frames before the response is treated as stalled. */
|
|
7
|
+
export const IDLE_TIMEOUT = 300_000;
|
|
8
|
+
const eventStreamMarshaller = new UniversalEventStreamMarshaller({
|
|
9
|
+
utf8Encoder: (input) => new TextDecoder().decode(input),
|
|
10
|
+
utf8Decoder: (input) => new TextEncoder().encode(input),
|
|
11
|
+
});
|
|
12
|
+
/**
|
|
13
|
+
* Turn a Kiro response body into parsed wire events.
|
|
14
|
+
*
|
|
15
|
+
* Terminal conditions are reported through {@link KiroEventStreamOutcome}
|
|
16
|
+
* rather than thrown: the caller retries all three the same way, and a throw
|
|
17
|
+
* would force it to re-classify the cause it already knows.
|
|
18
|
+
*
|
|
19
|
+
* A Kiro `error` frame ends the stream and is not yielded — it carries no
|
|
20
|
+
* content, and every caller treats it as the same retryable failure as a
|
|
21
|
+
* protocol error.
|
|
22
|
+
*/
|
|
23
|
+
export function readKiroEventStream(body, options) {
|
|
24
|
+
const outcome = { firstTokenTimedOut: false, idleTimedOut: false, error: null };
|
|
25
|
+
const idleTimeoutMs = options.idleTimeoutMs ?? IDLE_TIMEOUT;
|
|
26
|
+
const bodyReader = body.getReader();
|
|
27
|
+
async function* frames() {
|
|
28
|
+
let idleTimer = null;
|
|
29
|
+
const resetIdle = () => {
|
|
30
|
+
if (idleTimer)
|
|
31
|
+
clearTimeout(idleTimer);
|
|
32
|
+
idleTimer = setTimeout(() => {
|
|
33
|
+
outcome.idleTimedOut = true;
|
|
34
|
+
void bodyReader.cancel().catch(() => { });
|
|
35
|
+
}, idleTimeoutMs);
|
|
36
|
+
};
|
|
37
|
+
// Smithy's marshaller handles chunk reassembly, CRC validation, protocol
|
|
38
|
+
// error/exception detection, and payload deserialization.
|
|
39
|
+
const bodyIterable = {
|
|
40
|
+
async *[Symbol.asyncIterator]() {
|
|
41
|
+
try {
|
|
42
|
+
while (true) {
|
|
43
|
+
const { done, value } = await bodyReader.read();
|
|
44
|
+
if (done)
|
|
45
|
+
return;
|
|
46
|
+
yield value;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
bodyReader.releaseLock();
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
const utf8Decoder = new TextDecoder();
|
|
55
|
+
const eventStream = eventStreamMarshaller.deserialize(bodyIterable, async (event) => {
|
|
56
|
+
const entry = Object.entries(event)[0];
|
|
57
|
+
if (!entry)
|
|
58
|
+
throw new Error("Received an empty event stream message");
|
|
59
|
+
const [key, msg] = entry;
|
|
60
|
+
const parsed = JSON.parse(utf8Decoder.decode(msg.body));
|
|
61
|
+
return { [key]: parsed };
|
|
62
|
+
});
|
|
63
|
+
const iterator = eventStream[Symbol.asyncIterator]();
|
|
64
|
+
let gotFirstToken = false;
|
|
65
|
+
const FIRST_TOKEN_SENTINEL = Symbol("firstTokenTimeout");
|
|
66
|
+
try {
|
|
67
|
+
while (true) {
|
|
68
|
+
let iterResult;
|
|
69
|
+
try {
|
|
70
|
+
if (!gotFirstToken) {
|
|
71
|
+
const readPromise = iterator.next();
|
|
72
|
+
const result = await Promise.race([
|
|
73
|
+
readPromise,
|
|
74
|
+
new Promise((resolve) => setTimeout(() => resolve(FIRST_TOKEN_SENTINEL), options.firstTokenTimeoutMs)),
|
|
75
|
+
]);
|
|
76
|
+
if (result === FIRST_TOKEN_SENTINEL) {
|
|
77
|
+
readPromise.catch(() => { }); // suppress dangling rejection
|
|
78
|
+
void bodyReader.cancel().catch(() => { });
|
|
79
|
+
outcome.firstTokenTimedOut = true;
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
iterResult = result;
|
|
83
|
+
gotFirstToken = true;
|
|
84
|
+
resetIdle();
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
iterResult = await iterator.next();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
// Smithy throws on `:message-type` error/exception headers.
|
|
92
|
+
outcome.error =
|
|
93
|
+
e instanceof Error
|
|
94
|
+
? e.message
|
|
95
|
+
: (typeof e === "object" && e !== null ? JSON.stringify(e) : String(e)) || "Unknown stream error";
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const { done, value } = iterResult;
|
|
99
|
+
if (done)
|
|
100
|
+
return;
|
|
101
|
+
resetIdle();
|
|
102
|
+
const payload = Object.values(value)[0];
|
|
103
|
+
const event = parseKiroEvent(payload);
|
|
104
|
+
if (!event)
|
|
105
|
+
continue;
|
|
106
|
+
if (debugEnabled())
|
|
107
|
+
debugLog("stream.events", [event]);
|
|
108
|
+
if (event.type === "error") {
|
|
109
|
+
outcome.error = event.data.message ? `${event.data.error}: ${event.data.message}` : event.data.error;
|
|
110
|
+
void bodyReader.cancel().catch(() => { });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
yield { event, payload };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
if (idleTimer)
|
|
118
|
+
clearTimeout(idleTimer);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return { frames: frames(), outcome };
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=response-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-stream.js","sourceRoot":"","sources":["../src/response-stream.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,gFAAgF;AAEhF,OAAO,EAAE,8BAA8B,EAAE,MAAM,4BAA4B,CAAC;AAE5E,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAsB,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEvE,gFAAgF;AAChF,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AAEpC,MAAM,qBAAqB,GAAG,IAAI,8BAA8B,CAAC;IAC/D,WAAW,EAAE,CAAC,KAAiB,EAAE,EAAE,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;IACnE,WAAW,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;CAChE,CAAC,CAAC;AA8BH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAgC,EAChC,OAA+B;IAE/B,MAAM,OAAO,GAA2B,EAAE,kBAAkB,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACxG,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,YAAY,CAAC;IAC5D,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IAEpC,KAAK,SAAS,CAAC,CAAC,MAAM;QACpB,IAAI,SAAS,GAAyC,IAAI,CAAC;QAC3D,MAAM,SAAS,GAAG,GAAG,EAAE;YACrB,IAAI,SAAS;gBAAE,YAAY,CAAC,SAAS,CAAC,CAAC;YACvC,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC1B,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;gBAC5B,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAC3C,CAAC,EAAE,aAAa,CAAC,CAAC;QACpB,CAAC,CAAC;QAEF,yEAAyE;QACzE,0DAA0D;QAC1D,MAAM,YAAY,GAA8B;YAC9C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC;gBAC3B,IAAI,CAAC;oBACH,OAAO,IAAI,EAAE,CAAC;wBACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC;wBAChD,IAAI,IAAI;4BAAE,OAAO;wBACjB,MAAM,KAAK,CAAC;oBACd,CAAC;gBACH,CAAC;wBAAS,CAAC;oBACT,UAAU,CAAC,WAAW,EAAE,CAAC;gBAC3B,CAAC;YACH,CAAC;SACF,CAAC;QACF,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;QACtC,MAAM,WAAW,GAAG,qBAAqB,CAAC,WAAW,CAAC,YAAY,EAAE,KAAK,EAAE,KAA8B,EAAE,EAAE;YAC3G,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACvC,IAAI,CAAC,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;YACtE,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC;YACzB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAA4B,CAAC;YACnF,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAA6B,CAAC;QACtD,CAAC,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,EAA4C,CAAC;QAE/F,IAAI,aAAa,GAAG,KAAK,CAAC;QAC1B,MAAM,oBAAoB,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;QAEzD,IAAI,CAAC;YACH,OAAO,IAAI,EAAE,CAAC;gBACZ,IAAI,UAAmD,CAAC;gBACxD,IAAI,CAAC;oBACH,IAAI,CAAC,aAAa,EAAE,CAAC;wBACnB,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;wBACpC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;4BAChC,WAAW;4BACX,IAAI,OAAO,CAA8B,CAAC,OAAO,EAAE,EAAE,CACnD,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAC7E;yBACF,CAAC,CAAC;wBACH,IAAI,MAAM,KAAK,oBAAoB,EAAE,CAAC;4BACpC,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,8BAA8B;4BAC3D,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;4BACzC,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;4BAClC,OAAO;wBACT,CAAC;wBACD,UAAU,GAAG,MAAiD,CAAC;wBAC/D,aAAa,GAAG,IAAI,CAAC;wBACrB,SAAS,EAAE,CAAC;oBACd,CAAC;yBAAM,CAAC;wBACN,UAAU,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;oBACrC,CAAC;gBACH,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,4DAA4D;oBAC5D,OAAO,CAAC,KAAK;wBACX,CAAC,YAAY,KAAK;4BAChB,CAAC,CAAC,CAAC,CAAC,OAAO;4BACX,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,sBAAsB,CAAC;oBACtG,OAAO;gBACT,CAAC;gBAED,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC;gBACnC,IAAI,IAAI;oBAAE,OAAO;gBACjB,SAAS,EAAE,CAAC;gBACZ,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,KAAgC,CAAC,CAAC,CAAC,CAA4B,CAAC;gBAC9F,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;gBACtC,IAAI,CAAC,KAAK;oBAAE,SAAS;gBACrB,IAAI,YAAY,EAAE;oBAAE,QAAQ,CAAC,eAAe,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;gBACvD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC3B,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;oBACrG,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBACzC,OAAO;gBACT,CAAC;gBACD,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,IAAI,SAAS;gBAAE,YAAY,CAAC,SAAS,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC;AACvC,CAAC"}
|