From d5d711a7b9897bb8eee8364a5d8765b55206bf6f Mon Sep 17 00:00:00 2001 From: luvs01 <27862058+luvs01@users.noreply.github.com> Date: Mon, 7 Sep 2026 10:23:03 +0900 Subject: [PATCH] fix(kiro): gate request diagnostics behind the debug check `debugProviderDiagnostic` already returns early when provider debug is off, but its argument object is built by the caller first. The Kiro request path therefore ran `new TextEncoder().encode(body).length` over the entire serialized request body on every request, including when diagnostics were disabled, and then discarded the result inside the callee. Wrap the diagnostic call in `isDebugEnabled()` so the details are only constructed when they can actually be emitted. `src/adapters/openai-chat.ts` already guards its diagnostics the same way. The regression asserts that building a request performs no `TextEncoder` encode over the serialized payload while diagnostics are off; it fails without the guard and passes with it. --- src/adapters/kiro.ts | 27 ++++++++++++++---------- tests/providers/kiro/kiro-stream.test.ts | 15 +++++++++++++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/adapters/kiro.ts b/src/adapters/kiro.ts index 200b1edb77..d24845be15 100644 --- a/src/adapters/kiro.ts +++ b/src/adapters/kiro.ts @@ -1,6 +1,7 @@ import { decodeEventStream } from "../lib/eventstream-decoder"; import { estimateTokens } from "../lib/token-estimate"; import { debugProviderDiagnostic } from "../lib/debug"; +import { isDebugEnabled } from "../lib/debug-settings"; import { resolveKiroApiRegion, resolveKiroRequestProfile } from "../oauth/kiro"; import { KIRO_MODEL_CONTEXT_WINDOWS, normalizeKiroModelId } from "../providers/kiro-models"; import { modelRecordValue } from "../reasoning-effort"; @@ -2114,17 +2115,21 @@ export function createKiroAdapter(provider: OcxProviderConfig): ProviderAdapter const rawContextInputEstimate = estimateKiroPayloadInputTokens(built.payload, parsed.modelId); const contextInputEstimate = calibrateKiroEstimate(built.conversationId, rawContextInputEstimate); const body = JSON.stringify(built.payload); - debugProviderDiagnostic("kiro", "request", { - region, - requestedModel: parsed.modelId, - completionMode: built.completionMode, - bodyBytes: new TextEncoder().encode(body).length, - messageCount: kiroPayloadMessages(parsed).length, - toolCount: parsed.context.tools?.length ?? 0, - hasProfileArn: Boolean(profileArn), - wireClient, - hasPreviousResponseId: Boolean(parsed.previousResponseId), - }); + // Every field below is evaluated before the call, so an unguarded call re-encodes the + // whole request body on each request even when provider debug is off. Gate the details. + if (isDebugEnabled()) { + debugProviderDiagnostic("kiro", "request", { + region, + requestedModel: parsed.modelId, + completionMode: built.completionMode, + bodyBytes: new TextEncoder().encode(body).length, + messageCount: kiroPayloadMessages(parsed).length, + toolCount: parsed.context.tools?.length ?? 0, + hasProfileArn: Boolean(profileArn), + wireClient, + hasPreviousResponseId: Boolean(parsed.previousResponseId), + }); + } return { request: { url: kiroRuntimeEndpoint(provider, region), diff --git a/tests/providers/kiro/kiro-stream.test.ts b/tests/providers/kiro/kiro-stream.test.ts index b85c698ae1..1a9b7a6e02 100644 --- a/tests/providers/kiro/kiro-stream.test.ts +++ b/tests/providers/kiro/kiro-stream.test.ts @@ -196,6 +196,21 @@ describe("kiro adapter — parseStream", () => { expect(providerState).toEqual({ kiro: { conversationId: "returned-conversation-1" } }); }); + test("request diagnostics do not re-encode the body when provider debug is off", async () => { + const encodeSpy = spyOn(TextEncoder.prototype, "encode"); + try { + const adapter = createKiroAdapter(provider); + const before = encodeSpy.mock.calls.length; + await adapter.buildRequest(parsedWith([{ role: "user", content: "hi" }])); + const during = encodeSpy.mock.calls.slice(before); + // The diagnostic argument list is evaluated eagerly, so an unguarded call encodes the + // full serialized request body on every request even with diagnostics disabled. + expect(during.some(([value]) => typeof value === "string" && value.includes("conversationState"))).toBe(false); + } finally { + encodeSpy.mockRestore(); + } + }); + test("invalid returned message metadata cannot poison continuation state", async () => { const adapter = createKiroAdapter(provider); const request = await adapter.buildRequest(parsedWith([{ role: "user", content: "hi" }]));