import test from "node:test"; import assert from "node:assert/strict"; import { KiroExecutor } from "../../open-sse/executors/kiro.ts"; import { hasStreamReadinessSignal } from "../../open-sse/utils/streamReadiness.ts"; const textEncoder = new TextEncoder(); function crc32(buf) { const table = new Uint32Array(256); for (let i = 0; i < 256; i++) { let c = i; for (let j = 0; j < 8; j++) { c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1; } table[i] = c >>> 0; } let crc = 0xffffffff; for (let i = 0; i < buf.length; i++) { crc = table[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8); } return (crc ^ 0xffffffff) >>> 0; } function concatArrays(...arrays) { const total = arrays.reduce((sum, array) => sum + array.length, 0); const result = new Uint8Array(total); let offset = 0; for (const array of arrays) { result.set(array, offset); offset += array.length; } return result; } function encodeHeader(name, value) { const nameBytes = textEncoder.encode(name); const valueBytes = textEncoder.encode(value); const header = new Uint8Array(1 + nameBytes.length + 1 + 2 + valueBytes.length); let offset = 0; header[offset++] = nameBytes.length; header.set(nameBytes, offset); offset += nameBytes.length; header[offset++] = 7; header[offset++] = (valueBytes.length >> 8) & 0xff; header[offset++] = valueBytes.length & 0xff; header.set(valueBytes, offset); return header; } function buildEventFrame(eventType, payload) { const headers = encodeHeader(":event-type", eventType); const payloadBytes = payload === null ? new Uint8Array() : typeof payload === "string" ? textEncoder.encode(payload) : textEncoder.encode(JSON.stringify(payload)); const totalLength = 12 + headers.length + payloadBytes.length + 4; const frame = new Uint8Array(totalLength); const view = new DataView(frame.buffer); view.setUint32(0, totalLength, false); view.setUint32(4, headers.length, false); view.setUint32(8, crc32(frame.slice(0, 8)), false); frame.set(headers, 12); frame.set(payloadBytes, 12 + headers.length); view.setUint32(totalLength - 4, crc32(frame.slice(0, totalLength - 4)), false); return frame; } function buildEventStreamResponse(frames) { return buildEventStreamResponseFromChunks(frames); } function buildEventStreamResponseFromChunks(chunks) { return new Response( new ReadableStream({ start(controller) { for (const chunk of chunks) { controller.enqueue(chunk); } controller.close(); }, }), { status: 200, headers: { "Content-Type": "application/vnd.amazon.eventstream" }, } ); } function parseSSEJsonChunks(text) { return text .split("\n") .filter((line) => line.startsWith("data: ")) .map((line) => line.slice(6).trim()) .filter((payload) => payload && payload !== "[DONE]") .map((payload) => JSON.parse(payload)); } test("KiroExecutor.transformEventStreamToSSE emits an early role-only start chunk that satisfies stream readiness", async () => { const executor = new KiroExecutor(); // A corrupted prelude frame must NOT trigger the start chunk; only the first // successfully-parsed frame should. Here the first valid frame is metadata-only // (contextUsageEvent emits no SSE of its own), proving the start chunk is driven // by frame parsing rather than by the first content token. const invalidPreludeFrame = buildEventFrame("assistantResponseEvent", { content: "skip me" }); invalidPreludeFrame[8] ^= 0xff; const response = buildEventStreamResponse([ invalidPreludeFrame, buildEventFrame("contextUsageEvent", { contextUsagePercentage: 5 }), buildEventFrame("assistantResponseEvent", { content: "Answer" }), buildEventFrame("messageStopEvent", {}), buildEventFrame("metricsEvent", { inputTokens: 3, outputTokens: 5 }), ]); const transformed = executor.transformEventStreamToSSE(response, "kiro-model"); const text = await transformed.text(); const chunks = parseSSEJsonChunks(text); // The very first emitted chunk is a role-only start frame (no content yet). assert.equal(chunks[0].object, "chat.completion.chunk"); assert.equal(chunks[0].choices[0].delta.role, "assistant"); assert.equal(chunks[0].choices[0].delta.content, undefined); // That first frame alone must release the backend stream-readiness gate so the // client is not held until the first content token (the slow-Kiro regression). const firstFrameText = `data: ${JSON.stringify(chunks[0])}\n\n`; assert.equal(hasStreamReadinessSignal(firstFrameText), true); // Content is still delivered, and role is not duplicated on the content delta. const contentChunk = chunks.find((chunk) => chunk.choices?.[0]?.delta?.content === "Answer"); assert.ok(contentChunk); assert.equal(contentChunk.choices[0].delta.role, undefined); assert.match(text, /\[DONE\]/); }); test("KiroExecutor.buildHeaders includes Kiro-specific auth and metadata", () => { const executor = new KiroExecutor(); const headers = executor.buildHeaders({ accessToken: "kiro-token" }, true); assert.equal(headers.Authorization, "Bearer kiro-token"); assert.equal(headers["anthropic-beta"], "prompt-caching-2024-07-31"); assert.equal(headers["x-amzn-bedrock-cache-control"], "enable"); assert.ok(headers["Amz-Sdk-Invocation-Id"]); }); test("KiroExecutor.transformRequest removes the top-level model field", () => { const executor = new KiroExecutor(); const body = { model: "kiro-model", conversationState: { currentMessage: { userInputMessage: { modelId: "kiro-model", }, }, }, }; const result = executor.transformRequest("kiro-model", body, true, {}); assert.equal("model" in result, false); const kiroResult = result as unknown as { conversationState: { currentMessage: { userInputMessage: { modelId: string } } }; }; assert.equal(kiroResult.conversationState.currentMessage.userInputMessage.modelId, "kiro-model"); }); test("KiroExecutor.transformRequest forwards additionalModelRequestFields (thinking) to AWS", () => { const executor = new KiroExecutor(); const body = { model: "kiro-model", conversationState: { currentMessage: { userInputMessage: { modelId: "kiro-model" } }, }, additionalModelRequestFields: { output_config: { effort: "high" }, thinking: { type: "adaptive", display: "summarized" }, max_tokens: 32000, }, }; const result = executor.transformRequest("kiro-model", body, true, {}) as unknown as Record< string, unknown >; // The thinking control must survive the strict allowlist — otherwise graded // reasoning never reaches CodeWhisperer (the field the openai-to-kiro // translator builds would be silently dropped). assert.deepEqual(result.additionalModelRequestFields, { output_config: { effort: "high" }, thinking: { type: "adaptive", display: "summarized" }, max_tokens: 32000, }); }); test("KiroExecutor.transformEventStreamToSSE converts text, tool calls, usage and DONE", async () => { const executor = new KiroExecutor(); const invalidPreludeFrame = buildEventFrame("assistantResponseEvent", { content: "skip me" }); invalidPreludeFrame[8] ^= 0xff; const response = buildEventStreamResponse([ invalidPreludeFrame, buildEventFrame("assistantResponseEvent", { content: "Hello " }), buildEventFrame("codeEvent", { content: "world" }), buildEventFrame("toolUseEvent", { toolUseId: "tool_1", name: "read_file", input: { path: "/tmp/a" }, }), buildEventFrame("metricsEvent", { inputTokens: 4, outputTokens: 6 }), buildEventFrame("contextUsageEvent", { contextUsagePercentage: 10 }), buildEventFrame("meteringEvent", {}), ]); const transformed = executor.transformEventStreamToSSE(response, "kiro-model"); const text = await transformed.text(); assert.equal(transformed.status, 200); assert.equal(transformed.headers.get("Content-Type"), "text/event-stream"); assert.match(text, /"content":"Hello "/); assert.match(text, /"content":"world"/); assert.match(text, /"name":"read_file"/); assert.match(text, /"arguments":"\{\\"path\\":\\"\/tmp\/a\\"\}"/); assert.match(text, /"prompt_tokens":4/); assert.match(text, /"completion_tokens":6/); assert.match(text, /"finish_reason":"tool_calls"/); assert.match(text, /\[DONE\]/); }); test("KiroExecutor.transformEventStreamToSSE surfaces native reasoning frames as reasoning_content", async () => { const executor = new KiroExecutor(); // Verified live wire format: Kiro streams adaptive-thinking reasoning as a // dedicated `reasoningContentEvent` frame carrying `{ text, signature }`. Also // cover the `reasoningText` object variant and a signature-only frame. const response = buildEventStreamResponse([ buildEventFrame("reasoningContentEvent", { text: "Let me think... " }), buildEventFrame("reasoningContentEvent", { text: "step two. " }), buildEventFrame("reasoningContentEvent", { signature: "sig-only-frame" }), buildEventFrame("assistantResponseEvent", { reasoningText: { text: "variant." } }), buildEventFrame("assistantResponseEvent", { content: "The answer is 42." }), buildEventFrame("metricsEvent", { inputTokens: 3, outputTokens: 5 }), ]); const transformed = executor.transformEventStreamToSSE(response, "kiro-model"); const chunks = parseSSEJsonChunks(await transformed.text()); const reasoning = chunks .map((c) => c.choices?.[0]?.delta?.reasoning_content) .filter(Boolean) .join(""); const content = chunks .map((c) => c.choices?.[0]?.delta?.content) .filter(Boolean) .join(""); assert.equal( reasoning, "Let me think... step two. variant.", "reasoningContentEvent frames + reasoningText variant must all surface" ); assert.match(content, /The answer is 42\./, "normal content must still flow"); }); test("KiroExecutor.transformEventStreamToSSE parses fragmented frames and waits for post-stop usage", async () => { const executor = new KiroExecutor(); const bytes = concatArrays( buildEventFrame("assistantResponseEvent", { content: "Hello fragmented" }), buildEventFrame("messageStopEvent", {}), buildEventFrame("metricsEvent", { inputTokens: 11, outputTokens: 13 }), buildEventFrame("contextUsageEvent", { contextUsagePercentage: 17 }), buildEventFrame("meteringEvent", {}) ); const response = buildEventStreamResponseFromChunks([ bytes.subarray(0, 2), bytes.subarray(2, 9), bytes.subarray(9, 37), bytes.subarray(37, 91), bytes.subarray(91), ]); const transformed = executor.transformEventStreamToSSE(response, "kiro-model"); const text = await transformed.text(); const chunks = parseSSEJsonChunks(text); const finishChunks = chunks.filter((chunk) => chunk.choices?.[0]?.finish_reason); assert.match(text, /"content":"Hello fragmented"/); assert.equal(finishChunks.length, 1); assert.equal(finishChunks[0].choices[0].finish_reason, "stop"); assert.deepEqual(finishChunks[0].usage, { prompt_tokens: 11, completion_tokens: 13, total_tokens: 24, }); assert.match(text, /\[DONE\]/); }); test("KiroExecutor.transformEventStreamToSSE deduplicates tool starts and handles malformed payload JSON", async () => { const executor = new KiroExecutor(); const response = buildEventStreamResponse([ buildEventFrame("toolUseEvent", { toolUseId: "tool_1", name: "read_file", input: { path: "/tmp/a" }, }), buildEventFrame("toolUseEvent", { toolUseId: "tool_1", name: "read_file", input: '{"path":"/tmp/a","followUp":true}', }), buildEventFrame("assistantResponseEvent", "{not-json"), buildEventFrame("messageStopEvent", {}), ]); const transformed = executor.transformEventStreamToSSE(response, "kiro-model"); const text = await transformed.text(); const startMatches = text.match(/"id":"tool_1"/g) || []; assert.equal(startMatches.length, 1); assert.match(text, /"finish_reason":"tool_calls"/); assert.match(text, /\[DONE\]/); }); test("KiroExecutor.execute returns upstream errors directly and transforms successful streams", async () => { const executor = new KiroExecutor(); const originalFetch = globalThis.fetch; const rawResponse = new Response("ok", { status: 200 }); let transformed = null; executor.transformEventStreamToSSE = (response, model) => { transformed = { response, model }; return new Response("data: [DONE]\n\n", { status: 200, headers: { "Content-Type": "text/event-stream" }, }); }; globalThis.fetch = async () => new Response("upstream error", { status: 429 }); try { const errorResult = await executor.execute({ model: "kiro-model", body: { conversationState: {} }, stream: true, credentials: { accessToken: "kiro-token" }, }); assert.equal(errorResult.response.status, 429); } finally { globalThis.fetch = originalFetch; } globalThis.fetch = async () => rawResponse; try { const successResult = await executor.execute({ model: "kiro-model", body: { conversationState: {} }, stream: true, credentials: { accessToken: "kiro-token" }, }); assert.equal(successResult.response.status, 200); assert.equal(transformed.response, rawResponse); assert.equal(transformed.model, "kiro-model"); } finally { globalThis.fetch = originalFetch; } }); test("KiroExecutor.refreshCredentials handles missing and AWS-style refresh tokens", async () => { const executor = new KiroExecutor(); const originalFetch = globalThis.fetch; globalThis.fetch = async (url) => { assert.match(String(url), /oidc\.us-east-1\.amazonaws\.com\/token$/); return new Response( JSON.stringify({ accessToken: "new-access-token", refreshToken: "new-refresh-token", expiresIn: 3600, }), { status: 200, headers: { "Content-Type": "application/json" } } ); }; try { assert.equal(await executor.refreshCredentials({}, null), null); const result = await executor.refreshCredentials( { refreshToken: "refresh", providerSpecificData: { clientId: "client", clientSecret: "secret" }, }, null ); assert.deepEqual(result, { accessToken: "new-access-token", refreshToken: "new-refresh-token", expiresIn: 3600, }); } finally { globalThis.fetch = originalFetch; } }); test("KiroExecutor.refreshCredentials returns null when the token refresh fails", async () => { const executor = new KiroExecutor(); const originalFetch = globalThis.fetch; globalThis.fetch = async () => { throw new Error("refresh failed"); }; try { const result = await executor.refreshCredentials( { refreshToken: "refresh", providerSpecificData: { clientId: "client", clientSecret: "secret" }, }, null ); assert.equal(result, null); } finally { globalThis.fetch = originalFetch; } });