Files
oh-my-opencode/src/hooks/keyword-detector/index.ts
T
justsisyphus 5ee8996a39 fix(keyword-detector): use session state for agent-specific ultrawork templates
Bug: When switching from Prometheus to Sisyphus, the Prometheus ultrawork
template was still injected because:
1. setSessionAgent() only sets on first call, ignoring subsequent updates
2. keyword-detector relied solely on input.agent which could be stale

Fix:
- Use updateSessionAgent() instead of setSessionAgent() in index.ts
- keyword-detector now uses getSessionAgent() as primary source, fallback to input.agent
- Added tests for agent switch scenario
2026-01-16 19:06:00 +09:00

94 lines
3.1 KiB
TypeScript

import type { PluginInput } from "@opencode-ai/plugin"
import { detectKeywordsWithType, extractPromptText, removeCodeBlocks } from "./detector"
import { log } from "../../shared"
import { isSystemDirective } from "../../shared/system-directive"
import { getMainSessionID, getSessionAgent } from "../../features/claude-code-session-state"
import type { ContextCollector } from "../../features/context-injector"
export * from "./detector"
export * from "./constants"
export * from "./types"
export function createKeywordDetectorHook(ctx: PluginInput, collector?: ContextCollector) {
return {
"chat.message": async (
input: {
sessionID: string
agent?: string
model?: { providerID: string; modelID: string }
messageID?: string
},
output: {
message: Record<string, unknown>
parts: Array<{ type: string; text?: string; [key: string]: unknown }>
}
): Promise<void> => {
const promptText = extractPromptText(output.parts)
if (isSystemDirective(promptText)) {
log(`[keyword-detector] Skipping system directive message`, { sessionID: input.sessionID })
return
}
const currentAgent = getSessionAgent(input.sessionID) ?? input.agent
let detectedKeywords = detectKeywordsWithType(removeCodeBlocks(promptText), currentAgent)
if (detectedKeywords.length === 0) {
return
}
const mainSessionID = getMainSessionID()
const isNonMainSession = mainSessionID && input.sessionID !== mainSessionID
if (isNonMainSession) {
detectedKeywords = detectedKeywords.filter((k) => k.type === "ultrawork")
if (detectedKeywords.length === 0) {
log(`[keyword-detector] Skipping non-ultrawork keywords in non-main session`, {
sessionID: input.sessionID,
mainSessionID,
})
return
}
}
const hasUltrawork = detectedKeywords.some((k) => k.type === "ultrawork")
if (hasUltrawork) {
log(`[keyword-detector] Ultrawork mode activated`, { sessionID: input.sessionID })
if (output.message.variant === undefined) {
output.message.variant = "max"
}
ctx.client.tui
.showToast({
body: {
title: "Ultrawork Mode Activated",
message: "Maximum precision engaged. All agents at your disposal.",
variant: "success" as const,
duration: 3000,
},
})
.catch((err) =>
log(`[keyword-detector] Failed to show toast`, { error: err, sessionID: input.sessionID })
)
}
if (collector) {
for (const keyword of detectedKeywords) {
collector.register(input.sessionID, {
id: `keyword-${keyword.type}`,
source: "keyword-detector",
content: keyword.message,
priority: keyword.type === "ultrawork" ? "critical" : "high",
})
}
}
log(`[keyword-detector] Detected ${detectedKeywords.length} keywords`, {
sessionID: input.sessionID,
types: detectedKeywords.map((k) => k.type),
})
},
}
}