|
13 | 13 | * OpenCode's reasoning-clearing replay was added to fix. |
14 | 14 | * |
15 | 15 | * Behavior: |
16 | | - * - On execute passes (cache-busting): walk Pi assistant messages |
| 16 | + * - On execute passes (cache-busting): walk Pi assistant messages |
17 | 17 | * whose tag number is older than `clear_reasoning_age` from the |
18 | 18 | * newest tag, EMPTY each `PiThinkingContent.thinking` (and drop its |
19 | 19 | * stale signature), persist watermark = max-tag-cleared in |
@@ -153,6 +153,14 @@ export function clearOldReasoningPi(args: { |
153 | 153 | (part as { type?: unknown }).type === "thinking" |
154 | 154 | ) { |
155 | 155 | const tp = part as PiThinkingContent; |
| 156 | + // Leave REDACTED thinking blocks untouched. Unlike normal thinking, |
| 157 | + // redacted blocks bypass the empty-drop in Pi's serializers |
| 158 | + // (transform-messages.ts and anthropic.ts serialize `redacted` |
| 159 | + // before the empty-thinking check), so emptying one + dropping its |
| 160 | + // signature would leave a malformed redacted block (no data, no sig) |
| 161 | + // on the wire. A redacted block carries no plaintext to save anyway; |
| 162 | + // keeping it verbatim is both safe and byte-stable across passes. |
| 163 | + if (tp.redacted) continue; |
156 | 164 | // Empty the thinking AND drop its now-stale signature (a signature |
157 | 165 | // over the original text would mismatch the emptied content). The |
158 | 166 | // empty block is dropped by every Pi serializer, so neither reaches |
@@ -271,6 +279,10 @@ export function replayClearedReasoningPi(args: { |
271 | 279 | (part as { type?: unknown }).type === "thinking" |
272 | 280 | ) { |
273 | 281 | const tp = part as PiThinkingContent; |
| 282 | + // Mirror clearOldReasoningPi exactly: redacted blocks are left |
| 283 | + // untouched (they bypass the serializers' empty-drop, so emptying |
| 284 | + // one would put a malformed redacted block on the wire). |
| 285 | + if (tp.redacted) continue; |
274 | 286 | // Replay the exact clear shape from clearOldReasoningPi: empty |
275 | 287 | // thinking + dropped signature, so defer passes are byte-identical |
276 | 288 | // to the cache-busting pass that set the watermark. |
|
0 commit comments