fix: address 8-domain Oracle review findings (C1, C2, M1-M4)

- C1: thinking-prepend unique part IDs per message (global PK collision)
- C2: recover-thinking-disabled-violation try/catch guard on SDK call
- M1: remove non-schema truncated/originalSize fields from SDK interfaces
- M2: messageHasContentFromSDK treats thinking-only messages as non-empty
- M3: syncAllTasksToTodos persists finalTodos + no-id rename dedup guard
- M4: AbortSignal.timeout(30s) on HTTP fetch calls in opencode-http-api

All 2739 tests pass, typecheck clean.
This commit is contained in:
YeonGyu-Kim
2026-02-16 15:23:45 +09:00
parent 106cd5c8b1
commit c2012c6027
10 changed files with 148 additions and 46 deletions
@@ -4,6 +4,7 @@ import { findMessagesWithThinkingBlocks, stripThinkingParts } from "./storage"
import { isSqliteBackend } from "../../shared/opencode-storage-detection"
import { stripThinkingPartsAsync } from "./storage/thinking-strip"
import { THINKING_TYPES } from "./constants"
import { log } from "../../shared/logger"
type Client = ReturnType<typeof createOpencodeClient>
@@ -35,31 +36,39 @@ async function recoverThinkingDisabledViolationFromSDK(
client: Client,
sessionID: string
): Promise<boolean> {
const response = await client.session.messages({ path: { id: sessionID } })
const messages = (response.data ?? []) as MessageData[]
try {
const response = await client.session.messages({ path: { id: sessionID } })
const messages = (response.data ?? []) as MessageData[]
const messageIDsWithThinking: string[] = []
for (const msg of messages) {
if (msg.info?.role !== "assistant") continue
if (!msg.info?.id) continue
if (!msg.parts) continue
const messageIDsWithThinking: string[] = []
for (const msg of messages) {
if (msg.info?.role !== "assistant") continue
if (!msg.info?.id) continue
if (!msg.parts) continue
const hasThinking = msg.parts.some((part) => THINKING_TYPES.has(part.type))
if (hasThinking) {
messageIDsWithThinking.push(msg.info.id)
const hasThinking = msg.parts.some((part) => THINKING_TYPES.has(part.type))
if (hasThinking) {
messageIDsWithThinking.push(msg.info.id)
}
}
}
if (messageIDsWithThinking.length === 0) {
if (messageIDsWithThinking.length === 0) {
return false
}
let anySuccess = false
for (const messageID of messageIDsWithThinking) {
if (await stripThinkingPartsAsync(client, sessionID, messageID)) {
anySuccess = true
}
}
return anySuccess
} catch (error) {
log("[session-recovery] recoverThinkingDisabledViolationFromSDK failed", {
sessionID,
error: String(error),
})
return false
}
let anySuccess = false
for (const messageID of messageIDsWithThinking) {
if (await stripThinkingPartsAsync(client, sessionID, messageID)) {
anySuccess = true
}
}
return anySuccess
}
@@ -49,7 +49,7 @@ export function prependThinkingPart(sessionID: string, messageID: string): boole
const previousThinking = findLastThinkingContent(sessionID, messageID)
const partId = "prt_0000000000_thinking"
const partId = `prt_0000000000_${messageID}_thinking`
const part = {
id: partId,
sessionID,
@@ -104,7 +104,7 @@ export async function prependThinkingPartAsync(
): Promise<boolean> {
const previousThinking = await findLastThinkingContentFromSDK(client, sessionID, messageID)
const partId = "prt_0000000000_thinking"
const partId = `prt_0000000000_${messageID}_thinking`
const part: Record<string, unknown> = {
id: partId,
sessionID,