oh-my-opencode/src/plugin/ultrawork-model-override.ts
YeonGyu-Kim 0c59d2dbe7 refactor(ultrawork): remove thinking config injection from model override
Delegate thinking config control to the provider layer rather than
injecting it manually in ultrawork model override.

🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
2026-02-26 20:08:44 +09:00

162 lines
5.2 KiB
TypeScript

import type { OhMyOpenCodeConfig } from "../config"
import type { AgentOverrides } from "../config/schema/agent-overrides"
import { getSessionAgent } from "../features/claude-code-session-state"
import { log } from "../shared"
import { getAgentConfigKey } from "../shared/agent-display-names"
import { scheduleDeferredModelOverride } from "./ultrawork-db-model-override"
const CODE_BLOCK = /```[\s\S]*?```/g
const INLINE_CODE = /`[^`]+`/g
const ULTRAWORK_PATTERN = /\b(ultrawork|ulw)\b/i
export function detectUltrawork(text: string): boolean {
const clean = text.replace(CODE_BLOCK, "").replace(INLINE_CODE, "")
return ULTRAWORK_PATTERN.test(clean)
}
function extractPromptText(parts: Array<{ type: string; text?: string }>): string {
return parts.filter((p) => p.type === "text").map((p) => p.text || "").join("")
}
type ToastFn = {
showToast: (o: { body: Record<string, unknown> }) => Promise<unknown>
}
function showToast(tui: unknown, title: string, message: string): void {
const toastFn = tui as Partial<ToastFn>
if (typeof toastFn.showToast !== "function") return
toastFn.showToast({
body: { title, message, variant: "warning" as const, duration: 3000 },
}).catch(() => {})
}
export type UltraworkOverrideResult = {
providerID?: string
modelID?: string
variant?: string
}
function isSameModel(
current: unknown,
target: { providerID: string; modelID: string },
): boolean {
if (typeof current !== "object" || current === null) return false
const currentRecord = current as Record<string, unknown>
return (
currentRecord["providerID"] === target.providerID
&& currentRecord["modelID"] === target.modelID
)
}
/**
* Resolves the ultrawork model override config for the given agent and prompt text.
* Returns null if no override should be applied.
*/
export function resolveUltraworkOverride(
pluginConfig: OhMyOpenCodeConfig,
inputAgentName: string | undefined,
output: {
message: Record<string, unknown>
parts: Array<{ type: string; text?: string; [key: string]: unknown }>
},
sessionID?: string,
): UltraworkOverrideResult | null {
const promptText = extractPromptText(output.parts)
if (!detectUltrawork(promptText)) return null
const messageAgentName =
typeof output.message["agent"] === "string" ? (output.message["agent"] as string) : undefined
const sessionAgentName = sessionID ? getSessionAgent(sessionID) : undefined
const rawAgentName = inputAgentName ?? messageAgentName ?? sessionAgentName
if (!rawAgentName || !pluginConfig.agents) return null
const agentConfigKey = getAgentConfigKey(rawAgentName)
const agentConfig = pluginConfig.agents[agentConfigKey as keyof AgentOverrides]
const ultraworkConfig = agentConfig?.ultrawork
if (!ultraworkConfig?.model && !ultraworkConfig?.variant) return null
if (!ultraworkConfig.model) {
return {
variant: ultraworkConfig.variant,
}
}
const modelParts = ultraworkConfig.model.split("/")
if (modelParts.length < 2) return null
return {
providerID: modelParts[0],
modelID: modelParts.slice(1).join("/"),
variant: ultraworkConfig.variant,
}
}
/**
* Applies ultrawork model override using a deferred DB update strategy.
*
* Instead of directly mutating output.message.model (which would cause the TUI
* bottom bar to show the override model), this schedules a queueMicrotask that
* updates the message model directly in SQLite AFTER Session.updateMessage()
* saves the original model, but BEFORE loop() reads it for the API call.
*
* Result: API call uses opus, TUI bottom bar stays on sonnet.
*/
export function applyUltraworkModelOverrideOnMessage(
pluginConfig: OhMyOpenCodeConfig,
inputAgentName: string | undefined,
output: {
message: Record<string, unknown>
parts: Array<{ type: string; text?: string; [key: string]: unknown }>
},
tui: unknown,
sessionID?: string,
): void {
const override = resolveUltraworkOverride(pluginConfig, inputAgentName, output, sessionID)
if (!override) return
if (!override.providerID || !override.modelID) {
if (override.variant) {
output.message["variant"] = override.variant
}
return
}
const targetModel = { providerID: override.providerID, modelID: override.modelID }
if (isSameModel(output.message.model, targetModel)) {
log(`[ultrawork-model-override] Skip override; target model already active: ${override.modelID}`)
return
}
const messageId = output.message["id"] as string | undefined
if (!messageId) {
log("[ultrawork-model-override] No message ID found, falling back to direct mutation")
output.message.model = targetModel
if (override.variant) {
output.message["variant"] = override.variant
}
return
}
const fromModel = (output.message.model as { modelID?: string } | undefined)?.modelID ?? "unknown"
const agentConfigKey = getAgentConfigKey(
inputAgentName ??
(typeof output.message["agent"] === "string" ? (output.message["agent"] as string) : "unknown"),
)
scheduleDeferredModelOverride(
messageId,
targetModel,
override.variant,
)
log(`[ultrawork-model-override] ${fromModel} -> ${override.modelID} (deferred DB)`, {
agent: agentConfigKey,
})
showToast(
tui,
"Ultrawork Model Override",
`${fromModel} \u2192 ${override.modelID}. Maximum precision engaged.`,
)
}