From e1930027753f63641e3a62df34f91b0a7f991c0a Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 7 Mar 2026 15:39:25 +0900 Subject: [PATCH] fix(plugin): ignore compaction session agent updates Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- src/plugin/event-compaction-agent.test.ts | 83 +++++++++++++++++++++++ src/plugin/event.ts | 7 +- 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 src/plugin/event-compaction-agent.test.ts diff --git a/src/plugin/event-compaction-agent.test.ts b/src/plugin/event-compaction-agent.test.ts new file mode 100644 index 000000000..d08f5e7ec --- /dev/null +++ b/src/plugin/event-compaction-agent.test.ts @@ -0,0 +1,83 @@ +declare const require: (name: string) => any +const { afterEach, describe, expect, test } = require("bun:test") + +import { _resetForTesting, getSessionAgent, updateSessionAgent } from "../features/claude-code-session-state" +import { createEventHandler } from "./event" + +function createMinimalEventHandler() { + return createEventHandler({ + ctx: {} as never, + pluginConfig: {} as never, + firstMessageVariantGate: { + markSessionCreated: () => {}, + clear: () => {}, + }, + managers: { + tmuxSessionManager: { + onSessionCreated: async () => {}, + onSessionDeleted: async () => {}, + }, + skillMcpManager: { + disconnectSession: async () => {}, + }, + } as never, + hooks: { + autoUpdateChecker: { event: async () => {} }, + claudeCodeHooks: { event: async () => {} }, + backgroundNotificationHook: { event: async () => {} }, + sessionNotification: async () => {}, + todoContinuationEnforcer: { handler: async () => {} }, + unstableAgentBabysitter: { event: async () => {} }, + contextWindowMonitor: { event: async () => {} }, + directoryAgentsInjector: { event: async () => {} }, + directoryReadmeInjector: { event: async () => {} }, + rulesInjector: { event: async () => {} }, + thinkMode: { event: async () => {} }, + anthropicContextWindowLimitRecovery: { event: async () => {} }, + runtimeFallback: undefined, + modelFallback: undefined, + agentUsageReminder: { event: async () => {} }, + categorySkillReminder: { event: async () => {} }, + interactiveBashSession: { event: async () => {} }, + ralphLoop: { event: async () => {} }, + stopContinuationGuard: { event: async () => {}, isStopped: () => false }, + compactionTodoPreserver: { event: async () => {} }, + writeExistingFileGuard: { event: async () => {} }, + atlasHook: { handler: async () => {} }, + } as never, + }) +} + +describe("createEventHandler compaction agent filtering", () => { + afterEach(() => { + _resetForTesting() + }) + + test("does not overwrite the stored session agent with compaction", async () => { + // given + const sessionID = "ses_compaction_poisoning" + updateSessionAgent(sessionID, "atlas") + const eventHandler = createMinimalEventHandler() + const input: Parameters>[0] = { + event: { + type: "message.updated", + properties: { + info: { + id: "msg-compaction", + sessionID, + role: "user", + agent: "compaction", + time: { created: Date.now() }, + model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + }, + }, + }, + } + + // when + await eventHandler(input) + + // then + expect(getSessionAgent(sessionID)).toBe("atlas") + }) +}) diff --git a/src/plugin/event.ts b/src/plugin/event.ts index b8f7910a8..1a9356194 100644 --- a/src/plugin/event.ts +++ b/src/plugin/event.ts @@ -97,6 +97,11 @@ function extractProviderModelFromErrorMessage(message: string): { providerID?: s return {}; } + +function isCompactionAgent(agent: string): boolean { + return agent.toLowerCase() === "compaction"; +} + type EventInput = Parameters["event"]>>[0]; export function createEventHandler(args: { ctx: PluginContext; @@ -261,7 +266,7 @@ export function createEventHandler(args: { const agent = info?.agent as string | undefined; const role = info?.role as string | undefined; if (sessionID && role === "user") { - if (agent) { + if (agent && !isCompactionAgent(agent)) { updateSessionAgent(sessionID, agent); } const providerID = info?.providerID as string | undefined;