From 0a90f5781adffefc744ef515e4b09c0b60d4a808 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 23 Dec 2025 02:33:31 +0900 Subject: [PATCH] Add fallback to use stored message model info when session.idle event lacks providerID/modelID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds getMessageDir() helper function and fallback logic in the session.idle event handler to retrieve stored model information (providerID/modelID) when the API response lacks these fields. This mirrors the approach used in todo-continuation-enforcer hook to ensure preemptive compaction can proceed even when model info is missing from the initial response. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) --- src/hooks/preemptive-compaction/index.ts | 35 ++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/hooks/preemptive-compaction/index.ts b/src/hooks/preemptive-compaction/index.ts index 3a8e010..657f2c8 100644 --- a/src/hooks/preemptive-compaction/index.ts +++ b/src/hooks/preemptive-compaction/index.ts @@ -1,3 +1,5 @@ +import { existsSync, readdirSync } from "node:fs" +import { join } from "node:path" import type { PluginInput } from "@opencode-ai/plugin" import type { ExperimentalConfig } from "../../config" import type { PreemptiveCompactionState, TokenInfo } from "./types" @@ -6,6 +8,10 @@ import { MIN_TOKENS_FOR_COMPACTION, COMPACTION_COOLDOWN_MS, } from "./constants" +import { + findNearestMessageWithFields, + MESSAGE_STORAGE, +} from "../../features/hook-message-injector" import { log } from "../../shared/logger" export interface SummarizeContext { @@ -48,6 +54,20 @@ function isSupportedModel(modelID: string): boolean { return CLAUDE_MODEL_PATTERN.test(modelID) } +function getMessageDir(sessionID: string): string | null { + if (!existsSync(MESSAGE_STORAGE)) return null + + const directPath = join(MESSAGE_STORAGE, sessionID) + if (existsSync(directPath)) return directPath + + for (const dir of readdirSync(MESSAGE_STORAGE)) { + const sessionPath = join(MESSAGE_STORAGE, dir, sessionID) + if (existsSync(sessionPath)) return sessionPath + } + + return null +} + function createState(): PreemptiveCompactionState { return { lastCompactionTime: new Map(), @@ -222,6 +242,21 @@ export function createPreemptiveCompactionHook( if (assistants.length === 0) return const lastAssistant = assistants[assistants.length - 1] + + if (!lastAssistant.providerID || !lastAssistant.modelID) { + const messageDir = getMessageDir(sessionID) + const storedMessage = messageDir ? findNearestMessageWithFields(messageDir) : null + if (storedMessage?.model?.providerID && storedMessage?.model?.modelID) { + lastAssistant.providerID = storedMessage.model.providerID + lastAssistant.modelID = storedMessage.model.modelID + log("[preemptive-compaction] using stored message model info", { + sessionID, + providerID: lastAssistant.providerID, + modelID: lastAssistant.modelID, + }) + } + } + await checkAndTriggerCompaction(sessionID, lastAssistant) } catch {} }