Files
oh-my-openagent/src/plugin/event-compaction-agent.test.ts
Ravi Tharuma a77a16c494 feat(config): support object-style fallback_models with per-model settings
Add support for object-style entries in fallback_models arrays, enabling
per-model configuration of variant, reasoningEffort, temperature, top_p,
maxTokens, and thinking settings.

- Zod schema for FallbackModelObject with full validation
- normalizeFallbackModels() and flattenToFallbackModelStrings() utilities
- Provider-agnostic model resolution pipeline with fallback chain
- Session prompt params state management
- Fallback chain construction with prefix-match lookup
- Integration across delegate-task, background-agent, and plugin layers
2026-03-25 11:04:49 +01:00

121 lines
4.0 KiB
TypeScript

import { afterEach, describe, expect, it } from "bun:test"
import { _resetForTesting, getSessionAgent, updateSessionAgent } from "../features/claude-code-session-state"
import { clearSessionModel, getSessionModel, setSessionModel } from "../shared/session-model-state"
import { clearSessionPromptParams } from "../shared/session-prompt-params-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()
clearSessionModel("ses_compaction_poisoning")
clearSessionModel("ses_compaction_model_poisoning")
clearSessionPromptParams("ses_compaction_poisoning")
clearSessionPromptParams("ses_compaction_model_poisoning")
})
it("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<ReturnType<typeof createEventHandler>>[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")
})
it("does not overwrite the stored session model with compaction", async () => {
// given
const sessionID = "ses_compaction_model_poisoning"
setSessionModel(sessionID, { providerID: "openai", modelID: "gpt-5" })
const eventHandler = createMinimalEventHandler()
const input: Parameters<ReturnType<typeof createEventHandler>>[0] = {
event: {
type: "message.updated",
properties: {
info: {
id: "msg-compaction-model",
sessionID,
role: "user",
agent: "compaction",
providerID: "anthropic",
modelID: "claude-opus-4-1",
time: { created: Date.now() },
},
},
},
}
// when
await eventHandler(input)
// then
expect(getSessionModel(sessionID)).toEqual({
providerID: "openai",
modelID: "gpt-5",
})
})
})