From 880b53c5114f3aade53c8d47afde9f5cfaa6d29e Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 16 Feb 2026 00:12:23 +0900 Subject: [PATCH] fix: address Cubic round-2 P2 issues - target-token-truncation: eliminate redundant SDK messages fetch by extracting tool results from already-fetched toolPartsByKey map - recover-thinking-block-order: wrap SDK message fetches in try/catch so recovery continues gracefully on API errors - thinking-strip: guard against missing part.id before calling deletePart to prevent invalid HTTP requests --- .../target-token-truncation.ts | 16 ++++++++++++++-- .../recover-thinking-block-order.ts | 18 ++++++++++++++---- .../session-recovery/storage/thinking-strip.ts | 2 +- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/hooks/anthropic-context-window-limit-recovery/target-token-truncation.ts b/src/hooks/anthropic-context-window-limit-recovery/target-token-truncation.ts index c743be7f..2907fa26 100644 --- a/src/hooks/anthropic-context-window-limit-recovery/target-token-truncation.ts +++ b/src/hooks/anthropic-context-window-limit-recovery/target-token-truncation.ts @@ -1,7 +1,7 @@ import type { PluginInput } from "@opencode-ai/plugin" import type { AggressiveTruncateResult } from "./tool-part-types" import { findToolResultsBySize, truncateToolResult } from "./tool-result-storage" -import { findToolResultsBySizeFromSDK, truncateToolResultAsync } from "./tool-result-storage-sdk" +import { truncateToolResultAsync } from "./tool-result-storage-sdk" import { isSqliteBackend } from "../../shared/opencode-storage-detection" type OpencodeClient = PluginInput["client"] @@ -79,7 +79,19 @@ export async function truncateUntilTargetTokens( toolPartsByKey = new Map() } - const results = await findToolResultsBySizeFromSDK(client, sessionID) + const results: import("./tool-part-types").ToolResultInfo[] = [] + for (const [key, part] of toolPartsByKey) { + if (part.type === "tool" && part.state?.output && !part.truncated && part.tool) { + results.push({ + partPath: "", + partId: part.id, + messageID: key.split(":")[0], + toolName: part.tool, + outputSize: part.state.output.length, + }) + } + } + results.sort((a, b) => b.outputSize - a.outputSize) if (results.length === 0) { return { diff --git a/src/hooks/session-recovery/recover-thinking-block-order.ts b/src/hooks/session-recovery/recover-thinking-block-order.ts index b07d1e9a..6e66fbf5 100644 --- a/src/hooks/session-recovery/recover-thinking-block-order.ts +++ b/src/hooks/session-recovery/recover-thinking-block-order.ts @@ -74,8 +74,13 @@ async function findMessagesWithOrphanThinkingFromSDK( client: Client, sessionID: string ): Promise { - const response = await client.session.messages({ path: { id: sessionID } }) - const messages = (response.data ?? []) as MessageData[] + let messages: MessageData[] + try { + const response = await client.session.messages({ path: { id: sessionID } }) + messages = (response.data ?? []) as MessageData[] + } catch { + return [] + } const result: string[] = [] for (const msg of messages) { @@ -103,8 +108,13 @@ async function findMessageByIndexNeedingThinkingFromSDK( sessionID: string, targetIndex: number ): Promise { - const response = await client.session.messages({ path: { id: sessionID } }) - const messages = (response.data ?? []) as MessageData[] + let messages: MessageData[] + try { + const response = await client.session.messages({ path: { id: sessionID } }) + messages = (response.data ?? []) as MessageData[] + } catch { + return null + } if (targetIndex < 0 || targetIndex >= messages.length) return null diff --git a/src/hooks/session-recovery/storage/thinking-strip.ts b/src/hooks/session-recovery/storage/thinking-strip.ts index 27295b18..c3a005f8 100644 --- a/src/hooks/session-recovery/storage/thinking-strip.ts +++ b/src/hooks/session-recovery/storage/thinking-strip.ts @@ -52,7 +52,7 @@ export async function stripThinkingPartsAsync( let anyRemoved = false for (const part of targetMsg.parts) { - if (THINKING_TYPES.has(part.type)) { + if (THINKING_TYPES.has(part.type) && part.id) { const deleted = await deletePart(client, sessionID, messageID, part.id) if (deleted) anyRemoved = true }