5a6a9e9800
- Replace all response.data ?? [] with (response.data ?? response) pattern across 14 files to handle SDK array-shaped responses - Normalize SDK parts in parts-reader.ts by injecting sessionID/ messageID before validation (P1: SDK parts lack these fields) - Treat unknown part types as having content in recover-empty-content-message-sdk.ts to prevent false placeholder injection on image/file parts - Replace local isRecord with shared import in parts-reader.ts
75 lines
2.1 KiB
TypeScript
75 lines
2.1 KiB
TypeScript
import type { createOpencodeClient } from "@opencode-ai/sdk"
|
|
import type { MessageData } from "./types"
|
|
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>
|
|
|
|
export async function recoverThinkingDisabledViolation(
|
|
client: Client,
|
|
sessionID: string,
|
|
_failedAssistantMsg: MessageData
|
|
): Promise<boolean> {
|
|
if (isSqliteBackend()) {
|
|
return recoverThinkingDisabledViolationFromSDK(client, sessionID)
|
|
}
|
|
|
|
const messagesWithThinking = findMessagesWithThinkingBlocks(sessionID)
|
|
if (messagesWithThinking.length === 0) {
|
|
return false
|
|
}
|
|
|
|
let anySuccess = false
|
|
for (const messageID of messagesWithThinking) {
|
|
if (stripThinkingParts(messageID)) {
|
|
anySuccess = true
|
|
}
|
|
}
|
|
|
|
return anySuccess
|
|
}
|
|
|
|
async function recoverThinkingDisabledViolationFromSDK(
|
|
client: Client,
|
|
sessionID: string
|
|
): Promise<boolean> {
|
|
try {
|
|
const response = await client.session.messages({ path: { id: sessionID } })
|
|
const messages = ((response.data ?? response) as unknown 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 hasThinking = msg.parts.some((part) => THINKING_TYPES.has(part.type))
|
|
if (hasThinking) {
|
|
messageIDsWithThinking.push(msg.info.id)
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|