fix(coding-agent/session): prevented truncation of signed thinking and redacted reasoning blocks

- Excluded signed `thinking` blocks and `redactedThinking` blobs from size-based persistence truncation.
- Preserved signature-bound reasoning verbatim to prevent provider validation failures on session replay.
- Maintained normal truncation behavior for unsigned thinking and standard text blocks.
This commit is contained in:
can1357
2026-07-02 03:39:59 +02:00
parent 21f5728ef8
commit af748c3e90
3 changed files with 99 additions and 0 deletions
@@ -76,6 +76,21 @@ function truncateForPersistence(obj: unknown, blobStore: BlobStore, key?: string
if (shouldExternalizeImagePayload(obj, key)) {
return { ...obj, data: externalizeImageDataSync(blobStore, obj.data, obj.mimeType) };
}
// Signed/encrypted reasoning is bound to its exact bytes: a truncated `thinking`
// no longer matches its signature and a truncated `redacted_thinking` blob is
// undecryptable, so the provider 400s the replay. Persist these verbatim — never
// truncate, externalize, or descend. Unsigned thinking (e.g. an interrupted
// stream) has no such binding and stays truncatable for size control.
if (typeof obj === "object" && "type" in obj) {
const signedThinking =
obj.type === "thinking" &&
"thinkingSignature" in obj &&
typeof obj.thinkingSignature === "string" &&
obj.thinkingSignature.length > 0;
const redacted =
obj.type === "redactedThinking" && "data" in obj && typeof obj.data === "string" && obj.data.length > 0;
if (signedThinking || redacted) return obj;
}
if (typeof obj === "string") {
if (key === "image_url" && isImageDataUrl(obj)) {