-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Open
Description
문제 설명
세션 복구 기능이 특정 상황에서 실패하여 다음과 같은 에러가 반복 발생합니다:
1. tool_result_missing 에러
messages.141: `tool_use` ids were found without `tool_result` blocks immediately after: toolu_01MiWair1KGbNe4CPdq8fmnT. Each `tool_use` block must have a corresponding `tool_result` block in the next message.
2. thinking_block_order 에러
messages.57.content.0: If an assistant message contains any thinking blocks, the first block must be `thinking` or `redacted_thinking`. Found `text`.
원인 분석
tool_result_missing
recoverToolResultMissing() 함수에서:
failedAssistantMsg.parts에서 tool_use ID 추출 시도- parts가 비어있으면 스토리지에서 읽기 시도
- 둘 다 실패하면
toolUseIds가 빈 배열 →return false→ 복구 실패
하지만 에러 메시지 자체에 tool_use ID가 포함되어 있음 (toolu_01MiWair1KGbNe4CPdq8fmnT)
thinking_block_order
findMessageByIndexNeedingThinking() 함수에서:
- API에서 반환하는 메시지 인덱스와 스토리지 인덱스가 다를 수 있음 (시스템 메시지 등으로 인해)
- 정확한 인덱스만 시도하므로 메시지를 찾지 못함
failedAssistantMsg.info.id를 직접 사용하는 fallback이 없음
제안하는 수정
1. index.ts - recoverToolResultMissing
async function recoverToolResultMissing(
client: Client,
sessionID: string,
failedAssistantMsg: MessageData,
error?: unknown // 에러 파라미터 추가
): Promise<boolean> {
// ... 기존 parts 추출 로직 ...
let toolUseIds = extractToolUseIds(parts)
// Fallback: 에러 메시지에서 직접 tool_use ID 추출
if (toolUseIds.length === 0 && error) {
toolUseIds = extractToolUseIdsFromError(error)
}
if (toolUseIds.length === 0) {
return false
}
// ...
}그리고 호출부에서 info.error 전달:
if (errorType === "tool_result_missing") {
success = await recoverToolResultMissing(ctx.client, sessionID, failedMsg, info.error)
}2. storage.ts - findMessageByIndexNeedingThinking
export function findMessageByIndexNeedingThinking(sessionID: string, targetIndex: number): string | null {
const messages = readMessages(sessionID)
// API 인덱스와 스토리지 인덱스 차이를 고려하여 여러 오프셋 시도
const indicesToTry = [
targetIndex,
targetIndex - 1,
targetIndex + 1,
targetIndex - 2,
targetIndex + 2,
targetIndex - 3,
targetIndex - 4,
targetIndex - 5,
]
for (const idx of indicesToTry) {
if (idx < 0 || idx >= messages.length) continue
// ... 기존 로직 ...
}
return null
}3. index.ts - recoverThinkingBlockOrder
async function recoverThinkingBlockOrder(
_client: Client,
sessionID: string,
failedAssistantMsg: MessageData, // _failedAssistantMsg → failedAssistantMsg (사용)
_directory: string,
error: unknown
): Promise<boolean> {
// ... 기존 인덱스 기반 복구 시도 ...
// Fallback: failedAssistantMsg ID 직접 사용
const failedMsgId = failedAssistantMsg.info?.id
if (failedMsgId) {
if (prependThinkingPart(sessionID, failedMsgId)) {
return true
}
}
// ... orphanMessages fallback ...
}환경
- OpenCode 버전: 최신
- oh-my-opencode 버전: 2.12.2
- 모델: claude-opus-4-5
추가 정보
이 수정으로 세션이 중단되지 않고 자동으로 복구되어 작업을 이어갈 수 있습니다.
Metadata
Metadata
Assignees
Labels
No labels