diff --git a/src/features/background-agent/manager.ts b/src/features/background-agent/manager.ts index 7baca91e..e3c83384 100644 --- a/src/features/background-agent/manager.ts +++ b/src/features/background-agent/manager.ts @@ -875,7 +875,7 @@ export class BackgroundManager { path: { id: sessionID }, }) - const messages = response.data ?? [] + const messages = ((response.data ?? response) as unknown as Array<{ info?: { role?: string } }>) ?? [] // Check for at least one assistant or tool message const hasAssistantOrToolMessage = messages.some( diff --git a/src/hooks/anthropic-context-window-limit-recovery/message-builder.ts b/src/hooks/anthropic-context-window-limit-recovery/message-builder.ts index a62d655b..bcfe9434 100644 --- a/src/hooks/anthropic-context-window-limit-recovery/message-builder.ts +++ b/src/hooks/anthropic-context-window-limit-recovery/message-builder.ts @@ -64,7 +64,7 @@ async function findEmptyMessageIdsFromSDK( const response = (await client.session.messages({ path: { id: sessionID }, })) as { data?: SDKMessage[] } - const messages = response.data ?? [] + const messages = ((response.data ?? response) as unknown as SDKMessage[]) ?? [] const emptyIds: string[] = [] for (const message of messages) { diff --git a/src/hooks/anthropic-context-window-limit-recovery/message-storage-directory.ts b/src/hooks/anthropic-context-window-limit-recovery/message-storage-directory.ts index a72b3d8b..e8c5587b 100644 --- a/src/hooks/anthropic-context-window-limit-recovery/message-storage-directory.ts +++ b/src/hooks/anthropic-context-window-limit-recovery/message-storage-directory.ts @@ -17,7 +17,7 @@ export async function getMessageIdsFromSDK( ): Promise { try { const response = await client.session.messages({ path: { id: sessionID } }) - const messages = (response.data ?? []) as SDKMessage[] + const messages = ((response.data ?? response) as unknown as SDKMessage[]) ?? [] return messages.map(msg => msg.info.id) } catch { return [] diff --git a/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.ts b/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.ts index be141699..b44db121 100644 --- a/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.ts +++ b/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.ts @@ -72,7 +72,7 @@ function readMessages(sessionID: string): MessagePart[] { async function readMessagesFromSDK(client: OpencodeClient, sessionID: string): Promise { try { const response = await client.session.messages({ path: { id: sessionID } }) - const rawMessages = (response.data ?? []) as Array<{ parts?: ToolPart[] }> + const rawMessages = ((response.data ?? response) as unknown as Array<{ parts?: ToolPart[] }>) ?? [] return rawMessages.filter((m) => m.parts) as MessagePart[] } catch { return [] diff --git a/src/hooks/anthropic-context-window-limit-recovery/pruning-tool-output-truncation.ts b/src/hooks/anthropic-context-window-limit-recovery/pruning-tool-output-truncation.ts index 69c9ff7f..27dcc7f6 100644 --- a/src/hooks/anthropic-context-window-limit-recovery/pruning-tool-output-truncation.ts +++ b/src/hooks/anthropic-context-window-limit-recovery/pruning-tool-output-truncation.ts @@ -108,7 +108,7 @@ async function truncateToolOutputsByCallIdFromSDK( ): Promise<{ truncatedCount: number }> { try { const response = await client.session.messages({ path: { id: sessionID } }) - const messages = (response.data ?? []) as SDKMessage[] + const messages = ((response.data ?? response) as unknown as SDKMessage[]) ?? [] let truncatedCount = 0 for (const msg of messages) { 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 df60d35e..9da17f3a 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 @@ -66,7 +66,7 @@ export async function truncateUntilTargetTokens( const response = (await client.session.messages({ path: { id: sessionID }, })) as { data?: SDKMessage[] } - const messages = response.data ?? [] + const messages = (response.data ?? response) as SDKMessage[] toolPartsByKey = new Map() for (const message of messages) { diff --git a/src/hooks/anthropic-context-window-limit-recovery/tool-result-storage-sdk.ts b/src/hooks/anthropic-context-window-limit-recovery/tool-result-storage-sdk.ts index 31c721da..24df37d0 100644 --- a/src/hooks/anthropic-context-window-limit-recovery/tool-result-storage-sdk.ts +++ b/src/hooks/anthropic-context-window-limit-recovery/tool-result-storage-sdk.ts @@ -32,7 +32,7 @@ export async function findToolResultsBySizeFromSDK( ): Promise { try { const response = await client.session.messages({ path: { id: sessionID } }) - const messages = (response.data ?? []) as SDKMessage[] + const messages = ((response.data ?? response) as unknown as SDKMessage[]) ?? [] const results: ToolResultInfo[] = [] for (const msg of messages) { @@ -98,7 +98,7 @@ export async function countTruncatedResultsFromSDK( ): Promise { try { const response = await client.session.messages({ path: { id: sessionID } }) - const messages = (response.data ?? []) as SDKMessage[] + const messages = ((response.data ?? response) as unknown as SDKMessage[]) ?? [] let count = 0 for (const msg of messages) { diff --git a/src/hooks/session-recovery/recover-empty-content-message-sdk.ts b/src/hooks/session-recovery/recover-empty-content-message-sdk.ts index 10b96bb7..8766f0c7 100644 --- a/src/hooks/session-recovery/recover-empty-content-message-sdk.ts +++ b/src/hooks/session-recovery/recover-empty-content-message-sdk.ts @@ -126,7 +126,7 @@ function sdkPartHasContent(part: SdkPart): boolean { return true } - return false + return true } function sdkMessageHasContent(message: MessageData): boolean { @@ -136,7 +136,7 @@ function sdkMessageHasContent(message: MessageData): boolean { async function readMessagesFromSDK(client: Client, sessionID: string): Promise { try { const response = await client.session.messages({ path: { id: sessionID } }) - return (response.data ?? []) as MessageData[] + return ((response.data ?? response) as unknown as MessageData[]) ?? [] } catch { return [] } diff --git a/src/hooks/session-recovery/recover-thinking-block-order.ts b/src/hooks/session-recovery/recover-thinking-block-order.ts index 6e66fbf5..b8bbe04d 100644 --- a/src/hooks/session-recovery/recover-thinking-block-order.ts +++ b/src/hooks/session-recovery/recover-thinking-block-order.ts @@ -77,7 +77,7 @@ async function findMessagesWithOrphanThinkingFromSDK( let messages: MessageData[] try { const response = await client.session.messages({ path: { id: sessionID } }) - messages = (response.data ?? []) as MessageData[] + messages = ((response.data ?? response) as unknown as MessageData[]) ?? [] } catch { return [] } @@ -111,7 +111,7 @@ async function findMessageByIndexNeedingThinkingFromSDK( let messages: MessageData[] try { const response = await client.session.messages({ path: { id: sessionID } }) - messages = (response.data ?? []) as MessageData[] + messages = ((response.data ?? response) as unknown as MessageData[]) ?? [] } catch { return null } diff --git a/src/hooks/session-recovery/recover-thinking-disabled-violation.ts b/src/hooks/session-recovery/recover-thinking-disabled-violation.ts index cdb6556d..d569d37f 100644 --- a/src/hooks/session-recovery/recover-thinking-disabled-violation.ts +++ b/src/hooks/session-recovery/recover-thinking-disabled-violation.ts @@ -38,7 +38,7 @@ async function recoverThinkingDisabledViolationFromSDK( ): Promise { try { const response = await client.session.messages({ path: { id: sessionID } }) - const messages = (response.data ?? []) as MessageData[] + const messages = ((response.data ?? response) as unknown as MessageData[]) ?? [] const messageIDsWithThinking: string[] = [] for (const msg of messages) { diff --git a/src/hooks/session-recovery/recover-tool-result-missing.ts b/src/hooks/session-recovery/recover-tool-result-missing.ts index c266c24b..26e6724a 100644 --- a/src/hooks/session-recovery/recover-tool-result-missing.ts +++ b/src/hooks/session-recovery/recover-tool-result-missing.ts @@ -28,7 +28,7 @@ async function readPartsFromSDKFallback( ): Promise { try { const response = await client.session.messages({ path: { id: sessionID } }) - const messages = (response.data ?? []) as MessageData[] + const messages = ((response.data ?? response) as unknown as MessageData[]) ?? [] const target = messages.find((m) => m.info?.id === messageID) if (!target?.parts) return [] diff --git a/src/hooks/session-recovery/storage/empty-text.ts b/src/hooks/session-recovery/storage/empty-text.ts index 53bee36b..6ddd1fac 100644 --- a/src/hooks/session-recovery/storage/empty-text.ts +++ b/src/hooks/session-recovery/storage/empty-text.ts @@ -51,7 +51,7 @@ export async function replaceEmptyTextPartsAsync( ): Promise { try { const response = await client.session.messages({ path: { id: sessionID } }) - const messages = (response.data ?? []) as MessageData[] + const messages = ((response.data ?? response) as unknown as MessageData[]) ?? [] const targetMsg = messages.find((m) => m.info?.id === messageID) if (!targetMsg?.parts) return false @@ -101,7 +101,7 @@ export async function findMessagesWithEmptyTextPartsFromSDK( ): Promise { try { const response = await client.session.messages({ path: { id: sessionID } }) - const messages = (response.data ?? []) as MessageData[] + const messages = ((response.data ?? response) as unknown as MessageData[]) ?? [] const result: string[] = [] for (const msg of messages) { diff --git a/src/hooks/session-recovery/storage/parts-reader.ts b/src/hooks/session-recovery/storage/parts-reader.ts index 9aca63ad..287fd7b9 100644 --- a/src/hooks/session-recovery/storage/parts-reader.ts +++ b/src/hooks/session-recovery/storage/parts-reader.ts @@ -4,13 +4,10 @@ import type { PluginInput } from "@opencode-ai/plugin" import { PART_STORAGE } from "../constants" import type { StoredPart } from "../types" import { isSqliteBackend } from "../../../shared" +import { isRecord } from "../../../shared/record-type-guard" type OpencodeClient = PluginInput["client"] -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null -} - function isStoredPart(value: unknown): value is StoredPart { if (!isRecord(value)) return false return ( @@ -57,7 +54,12 @@ export async function readPartsFromSDK( const rawParts = data.parts if (!Array.isArray(rawParts)) return [] - return rawParts.filter(isStoredPart) + return rawParts + .map((part: unknown) => { + if (!isRecord(part) || typeof part.id !== "string" || typeof part.type !== "string") return null + return { ...part, sessionID, messageID } as StoredPart + }) + .filter((part): part is StoredPart => part !== null) } catch { return [] } diff --git a/src/hooks/session-recovery/storage/thinking-prepend.ts b/src/hooks/session-recovery/storage/thinking-prepend.ts index 476eadb4..13feabf7 100644 --- a/src/hooks/session-recovery/storage/thinking-prepend.ts +++ b/src/hooks/session-recovery/storage/thinking-prepend.ts @@ -74,7 +74,7 @@ async function findLastThinkingContentFromSDK( ): Promise { try { const response = await client.session.messages({ path: { id: sessionID } }) - const messages = (response.data ?? []) as MessageData[] + const messages = ((response.data ?? response) as unknown as MessageData[]) ?? [] const currentIndex = messages.findIndex((m) => m.info?.id === beforeMessageID) if (currentIndex === -1) return "" diff --git a/src/hooks/session-recovery/storage/thinking-strip.ts b/src/hooks/session-recovery/storage/thinking-strip.ts index c3a005f8..67c58da6 100644 --- a/src/hooks/session-recovery/storage/thinking-strip.ts +++ b/src/hooks/session-recovery/storage/thinking-strip.ts @@ -42,7 +42,7 @@ export async function stripThinkingPartsAsync( ): Promise { try { const response = await client.session.messages({ path: { id: sessionID } }) - const messages = (response.data ?? []) as Array<{ parts?: Array<{ type: string; id: string }> }> + const messages = ((response.data ?? response) as unknown as Array<{ parts?: Array<{ type: string; id: string }> }>) ?? [] const targetMsg = messages.find((m) => { const info = (m as Record)["info"] as Record | undefined