feat(ultrawork): implement per-message model override with deferred DB retry strategy

- Add per-message ultrawork mode detection via keyword matching
- Implement deferred DB override strategy using microtask retry loop
- Fall back to setTimeout after 10 microtask retries for robustness
- Update agent configuration schema with ultrawork model/variant fields
- Integrate with chat.message hook to apply overrides on detection
- Add comprehensive tests for all override scenarios
- Generated schema includes ultrawork configuration

🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode)
This commit is contained in:
YeonGyu-Kim 2026-02-19 15:20:53 +09:00
parent 50de1a18f2
commit 64b2d69036
9 changed files with 1112 additions and 22 deletions

View File

@ -101,7 +101,8 @@
"tasks-todowrite-disabler",
"write-existing-file-guard",
"anthropic-effort",
"hashline-read-enhancer"
"hashline-read-enhancer",
"hashline-edit-diff-enhancer"
]
}
},
@ -165,6 +166,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -210,6 +214,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -297,7 +304,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -338,6 +360,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -383,6 +408,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -470,7 +498,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -511,6 +554,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -556,6 +602,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -643,7 +692,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -684,6 +748,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -729,6 +796,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -816,7 +886,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -857,6 +942,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -902,6 +990,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -989,7 +1080,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -1030,6 +1136,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -1075,6 +1184,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -1162,7 +1274,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -1203,6 +1330,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -1248,6 +1378,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -1335,7 +1468,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -1376,6 +1524,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -1421,6 +1572,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -1508,7 +1662,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -1549,6 +1718,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -1594,6 +1766,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -1681,7 +1856,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -1722,6 +1912,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -1767,6 +1960,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -1854,7 +2050,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -1895,6 +2106,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -1940,6 +2154,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -2027,7 +2244,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -2068,6 +2300,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -2113,6 +2348,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -2200,7 +2438,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -2241,6 +2494,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -2286,6 +2542,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -2373,7 +2632,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -2414,6 +2688,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -2459,6 +2736,9 @@
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string",
"enum": [
@ -2546,7 +2826,22 @@
},
"providerOptions": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"ultrawork": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"variant": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
@ -2556,6 +2851,9 @@
},
"categories": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "object",
"properties": {
@ -2619,6 +2917,9 @@
},
"tools": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -2659,6 +2960,9 @@
},
"plugins_override": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "boolean"
}
@ -2932,6 +3236,9 @@
},
"metadata": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"allowed-tools": {
@ -2983,6 +3290,9 @@
},
"providerConcurrency": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "number",
"minimum": 0
@ -2990,6 +3300,9 @@
},
"modelConcurrency": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "number",
"minimum": 0
@ -3162,4 +3475,4 @@
}
},
"additionalProperties": false
}
}

View File

@ -38,6 +38,13 @@ export const AgentOverrideConfigSchema = z.object({
textVerbosity: z.enum(["low", "medium", "high"]).optional(),
/** Provider-specific options. Passed directly to OpenCode SDK. */
providerOptions: z.record(z.string(), z.unknown()).optional(),
/** Per-message ultrawork override model/variant when ultrawork keyword is detected. */
ultrawork: z
.object({
model: z.string().optional(),
variant: z.string().optional(),
})
.optional(),
})
export const AgentOverridesSchema = z.object({

View File

@ -10,6 +10,7 @@ import { hasConnectedProvidersCache } from "../shared"
import {
setSessionAgent,
} from "../features/claude-code-session-state"
import { applyUltraworkModelOverrideOnMessage } from "./ultrawork-model-override"
import type { CreatedHooks } from "../create-hooks"
@ -138,5 +139,7 @@ export function createChatMessageHandler(args: {
hooks.ralphLoop.cancelLoop(input.sessionID)
}
}
applyUltraworkModelOverrideOnMessage(pluginConfig, input.agent, output, ctx.client.tui)
}
}

View File

@ -0,0 +1,180 @@
import { describe, expect, test, beforeEach, afterEach, spyOn } from "bun:test"
import { Database } from "bun:sqlite"
import { mkdtempSync, mkdirSync, rmSync } from "node:fs"
import { join } from "node:path"
import { tmpdir } from "node:os"
import * as dataPathModule from "../shared/data-path"
import * as sharedModule from "../shared"
function flushMicrotasks(depth: number): Promise<void> {
return new Promise<void>((resolve) => {
let remaining = depth
function step() {
if (remaining <= 0) { resolve(); return }
remaining--
queueMicrotask(step)
}
queueMicrotask(step)
})
}
function flushWithTimeout(): Promise<void> {
return new Promise<void>((resolve) => setTimeout(resolve, 10))
}
describe("scheduleDeferredModelOverride", () => {
let tempDir: string
let dbPath: string
let logSpy: ReturnType<typeof spyOn>
let getDataDirSpy: ReturnType<typeof spyOn>
beforeEach(() => {
tempDir = mkdtempSync(join(tmpdir(), "ultrawork-db-test-"))
const opencodePath = join(tempDir, "opencode")
mkdirSync(opencodePath, { recursive: true })
dbPath = join(opencodePath, "opencode.db")
const db = new Database(dbPath)
db.run(`
CREATE TABLE IF NOT EXISTS message (
id TEXT PRIMARY KEY,
session_id TEXT NOT NULL,
time_created TEXT NOT NULL DEFAULT (datetime('now')),
time_updated TEXT NOT NULL DEFAULT (datetime('now')),
data TEXT NOT NULL DEFAULT '{}'
)
`)
db.close()
getDataDirSpy = spyOn(dataPathModule, "getDataDir").mockReturnValue(tempDir)
logSpy = spyOn(sharedModule, "log").mockImplementation(() => {})
})
afterEach(() => {
getDataDirSpy?.mockRestore()
logSpy?.mockRestore()
rmSync(tempDir, { recursive: true, force: true })
})
function insertMessage(id: string, model: { providerID: string; modelID: string }) {
const db = new Database(dbPath)
db.run(
`INSERT INTO message (id, session_id, data) VALUES (?, ?, ?)`,
id,
"ses_test",
JSON.stringify({ model }),
)
db.close()
}
function readMessageModel(id: string): { providerID: string; modelID: string } | null {
const db = new Database(dbPath)
const row = db.query(`SELECT data FROM message WHERE id = ?`).get(id) as
| { data: string }
| null
db.close()
if (!row) return null
const parsed = JSON.parse(row.data)
return parsed.model ?? null
}
function readMessageField(id: string, field: string): unknown {
const db = new Database(dbPath)
const row = db.query(`SELECT data FROM message WHERE id = ?`).get(id) as
| { data: string }
| null
db.close()
if (!row) return null
return JSON.parse(row.data)[field] ?? null
}
test("should update model in DB after microtask flushes", async () => {
//#given
insertMessage("msg_001", { providerID: "anthropic", modelID: "claude-sonnet-4-6" })
//#when
const { scheduleDeferredModelOverride } = await import("./ultrawork-db-model-override")
scheduleDeferredModelOverride(
"msg_001",
{ providerID: "anthropic", modelID: "claude-opus-4-6" },
)
await flushMicrotasks(5)
//#then
const model = readMessageModel("msg_001")
expect(model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" })
})
test("should update variant and thinking fields when variant provided", async () => {
//#given
insertMessage("msg_002", { providerID: "anthropic", modelID: "claude-sonnet-4-6" })
//#when
const { scheduleDeferredModelOverride } = await import("./ultrawork-db-model-override")
scheduleDeferredModelOverride(
"msg_002",
{ providerID: "anthropic", modelID: "claude-opus-4-6" },
"max",
)
await flushMicrotasks(5)
//#then
expect(readMessageField("msg_002", "variant")).toBe("max")
expect(readMessageField("msg_002", "thinking")).toBe("max")
})
test("should fall back to setTimeout when message never appears", async () => {
//#given — no message inserted
//#when
const { scheduleDeferredModelOverride } = await import("./ultrawork-db-model-override")
scheduleDeferredModelOverride(
"msg_nonexistent",
{ providerID: "anthropic", modelID: "claude-opus-4-6" },
)
await flushWithTimeout()
//#then
expect(logSpy).toHaveBeenCalledWith(
expect.stringContaining("setTimeout fallback failed"),
expect.objectContaining({ messageId: "msg_nonexistent" }),
)
})
test("should not update variant fields when variant is undefined", async () => {
//#given
insertMessage("msg_003", { providerID: "anthropic", modelID: "claude-sonnet-4-6" })
//#when
const { scheduleDeferredModelOverride } = await import("./ultrawork-db-model-override")
scheduleDeferredModelOverride(
"msg_003",
{ providerID: "anthropic", modelID: "claude-opus-4-6" },
)
await flushMicrotasks(5)
//#then
const model = readMessageModel("msg_003")
expect(model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" })
expect(readMessageField("msg_003", "variant")).toBeNull()
expect(readMessageField("msg_003", "thinking")).toBeNull()
})
test("should not crash when DB path does not exist", async () => {
//#given
getDataDirSpy.mockReturnValue("/nonexistent/path/that/does/not/exist")
//#when
const { scheduleDeferredModelOverride } = await import("./ultrawork-db-model-override")
scheduleDeferredModelOverride(
"msg_004",
{ providerID: "anthropic", modelID: "claude-opus-4-6" },
)
await flushMicrotasks(5)
//#then
expect(logSpy).toHaveBeenCalledWith(
expect.stringContaining("DB not found"),
)
})
})

View File

@ -0,0 +1,95 @@
import { Database } from "bun:sqlite"
import { join } from "node:path"
import { existsSync } from "node:fs"
import { getDataDir } from "../shared/data-path"
import { log } from "../shared"
function getDbPath(): string {
return join(getDataDir(), "opencode", "opencode.db")
}
const MAX_MICROTASK_RETRIES = 10
function tryUpdateMessageModel(
db: InstanceType<typeof Database>,
messageId: string,
targetModel: { providerID: string; modelID: string },
variant?: string,
): boolean {
const stmt = db.prepare(
`UPDATE message SET data = json_set(data, '$.model.providerID', ?, '$.model.modelID', ?) WHERE id = ?`,
)
const result = stmt.run(targetModel.providerID, targetModel.modelID, messageId)
if (result.changes === 0) return false
if (variant) {
db.prepare(
`UPDATE message SET data = json_set(data, '$.variant', ?, '$.thinking', ?) WHERE id = ?`,
).run(variant, variant, messageId)
}
return true
}
function retryViaMicrotask(
db: InstanceType<typeof Database>,
messageId: string,
targetModel: { providerID: string; modelID: string },
variant: string | undefined,
attempt: number,
): void {
if (attempt >= MAX_MICROTASK_RETRIES) {
log("[ultrawork-db-override] Exhausted microtask retries, falling back to setTimeout", {
messageId,
attempt,
})
setTimeout(() => {
if (tryUpdateMessageModel(db, messageId, targetModel, variant)) {
log(`[ultrawork-db-override] setTimeout fallback succeeded: ${targetModel.providerID}/${targetModel.modelID}`, { messageId })
} else {
log("[ultrawork-db-override] setTimeout fallback failed - message not found", { messageId })
}
db.close()
}, 0)
return
}
queueMicrotask(() => {
if (tryUpdateMessageModel(db, messageId, targetModel, variant)) {
log(`[ultrawork-db-override] Deferred DB update (attempt ${attempt}): ${targetModel.providerID}/${targetModel.modelID}`, { messageId })
db.close()
return
}
retryViaMicrotask(db, messageId, targetModel, variant, attempt + 1)
})
}
/**
* Schedules a deferred SQLite update to change the message model in the DB
* WITHOUT triggering a Bus event. Uses microtask retry loop to wait for
* Session.updateMessage() to save the message first, then overwrites the model.
*
* Falls back to setTimeout(fn, 0) after 10 microtask attempts.
*/
export function scheduleDeferredModelOverride(
messageId: string,
targetModel: { providerID: string; modelID: string },
variant?: string,
): void {
queueMicrotask(() => {
const dbPath = getDbPath()
if (!existsSync(dbPath)) {
log("[ultrawork-db-override] DB not found, skipping deferred override")
return
}
const db = new Database(dbPath)
try {
retryViaMicrotask(db, messageId, targetModel, variant, 0)
} catch (error) {
log("[ultrawork-db-override] Failed to apply deferred model override", {
error: String(error),
})
db.close()
}
})
}

View File

@ -0,0 +1,365 @@
import { describe, expect, test, beforeEach, afterEach, spyOn, mock } from "bun:test"
import {
applyUltraworkModelOverrideOnMessage,
resolveUltraworkOverride,
detectUltrawork,
} from "./ultrawork-model-override"
import * as sharedModule from "../shared"
import * as dbOverrideModule from "./ultrawork-db-model-override"
describe("detectUltrawork", () => {
test("should detect ultrawork keyword", () => {
expect(detectUltrawork("ultrawork do something")).toBe(true)
})
test("should detect ulw keyword", () => {
expect(detectUltrawork("ulw fix the bug")).toBe(true)
})
test("should be case insensitive", () => {
expect(detectUltrawork("ULTRAWORK do something")).toBe(true)
})
test("should not detect in code blocks", () => {
const textWithCodeBlock = [
"check this:",
"```",
"ultrawork mode",
"```",
].join("\n")
expect(detectUltrawork(textWithCodeBlock)).toBe(false)
})
test("should not detect in inline code", () => {
expect(detectUltrawork("the `ultrawork` mode is cool")).toBe(false)
})
test("should not detect when keyword absent", () => {
expect(detectUltrawork("just do something normal")).toBe(false)
})
})
describe("resolveUltraworkOverride", () => {
function createOutput(text: string, agentName?: string) {
return {
message: {
...(agentName ? { agent: agentName } : {}),
} as Record<string, unknown>,
parts: [{ type: "text", text }],
}
}
function createConfig(agentName: string, ultrawork: { model?: string; variant?: string }) {
return {
agents: {
[agentName]: { ultrawork },
},
} as unknown as Parameters<typeof resolveUltraworkOverride>[0]
}
test("should resolve override when ultrawork keyword detected", () => {
//#given
const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" })
const output = createOutput("ultrawork do something")
//#when
const result = resolveUltraworkOverride(config, "sisyphus", output)
//#then
expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: "max" })
})
test("should return null when no keyword detected", () => {
//#given
const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" })
const output = createOutput("just do something normal")
//#when
const result = resolveUltraworkOverride(config, "sisyphus", output)
//#then
expect(result).toBeNull()
})
test("should return null when agent name is undefined", () => {
//#given
const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" })
const output = createOutput("ultrawork do something")
//#when
const result = resolveUltraworkOverride(config, undefined, output)
//#then
expect(result).toBeNull()
})
test("should use message.agent when input agent is undefined", () => {
//#given
const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" })
const output = createOutput("ultrawork do something", "sisyphus")
//#when
const result = resolveUltraworkOverride(config, undefined, output)
//#then
expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: undefined })
})
test("should return null when agents config is missing", () => {
//#given
const config = {} as Parameters<typeof resolveUltraworkOverride>[0]
const output = createOutput("ultrawork do something")
//#when
const result = resolveUltraworkOverride(config, "sisyphus", output)
//#then
expect(result).toBeNull()
})
test("should return null when agent has no ultrawork config", () => {
//#given
const config = {
agents: { sisyphus: { model: "anthropic/claude-sonnet-4-6" } },
} as unknown as Parameters<typeof resolveUltraworkOverride>[0]
const output = createOutput("ultrawork do something")
//#when
const result = resolveUltraworkOverride(config, "sisyphus", output)
//#then
expect(result).toBeNull()
})
test("should return null when ultrawork.model is not set", () => {
//#given
const config = createConfig("sisyphus", { variant: "max" })
const output = createOutput("ultrawork do something")
//#when
const result = resolveUltraworkOverride(config, "sisyphus", output)
//#then
expect(result).toBeNull()
})
test("should handle model string with multiple slashes", () => {
//#given
const config = createConfig("sisyphus", { model: "openai/gpt-5.3/codex" })
const output = createOutput("ultrawork do something")
//#when
const result = resolveUltraworkOverride(config, "sisyphus", output)
//#then
expect(result).toEqual({ providerID: "openai", modelID: "gpt-5.3/codex", variant: undefined })
})
test("should return null when model string has no slash", () => {
//#given
const config = createConfig("sisyphus", { model: "just-a-model" })
const output = createOutput("ultrawork do something")
//#when
const result = resolveUltraworkOverride(config, "sisyphus", output)
//#then
expect(result).toBeNull()
})
test("should resolve display name to config key", () => {
//#given
const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" })
const output = createOutput("ulw do something")
//#when
const result = resolveUltraworkOverride(config, "Sisyphus (Ultraworker)", output)
//#then
expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: "max" })
})
test("should handle multiple text parts by joining them", () => {
//#given
const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" })
const output = {
message: {} as Record<string, unknown>,
parts: [
{ type: "text", text: "hello " },
{ type: "image", text: undefined },
{ type: "text", text: "ultrawork now" },
],
}
//#when
const result = resolveUltraworkOverride(config, "sisyphus", output)
//#then
expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: undefined })
})
})
describe("applyUltraworkModelOverrideOnMessage", () => {
let logSpy: ReturnType<typeof spyOn>
let dbOverrideSpy: ReturnType<typeof spyOn>
beforeEach(() => {
logSpy = spyOn(sharedModule, "log").mockImplementation(() => {})
dbOverrideSpy = spyOn(dbOverrideModule, "scheduleDeferredModelOverride").mockImplementation(() => {})
})
afterEach(() => {
logSpy?.mockRestore()
dbOverrideSpy?.mockRestore()
})
function createMockTui() {
return {
showToast: async () => {},
}
}
function createOutput(
text: string,
options?: {
existingModel?: { providerID: string; modelID: string }
agentName?: string
messageId?: string
},
) {
return {
message: {
...(options?.existingModel ? { model: options.existingModel } : {}),
...(options?.agentName ? { agent: options.agentName } : {}),
...(options?.messageId ? { id: options.messageId } : {}),
} as Record<string, unknown>,
parts: [{ type: "text", text }],
}
}
function createConfig(agentName: string, ultrawork: { model?: string; variant?: string }) {
return {
agents: {
[agentName]: { ultrawork },
},
} as unknown as Parameters<typeof applyUltraworkModelOverrideOnMessage>[0]
}
test("should schedule deferred DB override when message ID present", () => {
//#given
const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" })
const output = createOutput("ultrawork do something", { messageId: "msg_123" })
const tui = createMockTui()
//#when
applyUltraworkModelOverrideOnMessage(config, "sisyphus", output, tui)
//#then
expect(dbOverrideSpy).toHaveBeenCalledWith(
"msg_123",
{ providerID: "anthropic", modelID: "claude-opus-4-6" },
"max",
)
})
test("should NOT mutate output.message.model when message ID present", () => {
//#given
const sonnetModel = { providerID: "anthropic", modelID: "claude-sonnet-4-6" }
const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" })
const output = createOutput("ultrawork do something", {
existingModel: sonnetModel,
messageId: "msg_123",
})
const tui = createMockTui()
//#when
applyUltraworkModelOverrideOnMessage(config, "sisyphus", output, tui)
//#then
expect(output.message.model).toEqual(sonnetModel)
})
test("should fall back to direct mutation when no message ID", () => {
//#given
const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" })
const output = createOutput("ultrawork do something")
const tui = createMockTui()
//#when
applyUltraworkModelOverrideOnMessage(config, "sisyphus", output, tui)
//#then
expect(output.message.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" })
expect(output.message["variant"]).toBe("max")
expect(output.message["thinking"]).toBe("max")
expect(dbOverrideSpy).not.toHaveBeenCalled()
})
test("should not apply override when no keyword detected", () => {
//#given
const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" })
const output = createOutput("just do something normal", { messageId: "msg_123" })
const tui = createMockTui()
//#when
applyUltraworkModelOverrideOnMessage(config, "sisyphus", output, tui)
//#then
expect(dbOverrideSpy).not.toHaveBeenCalled()
})
test("should log the model transition with deferred DB tag", () => {
//#given
const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" })
const existingModel = { providerID: "anthropic", modelID: "claude-sonnet-4-6" }
const output = createOutput("ultrawork do something", {
existingModel,
messageId: "msg_123",
})
const tui = createMockTui()
//#when
applyUltraworkModelOverrideOnMessage(config, "sisyphus", output, tui)
//#then
expect(logSpy).toHaveBeenCalledWith(
expect.stringContaining("deferred DB"),
expect.objectContaining({ agent: "sisyphus" }),
)
})
test("should call showToast on override", () => {
//#given
const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" })
const output = createOutput("ultrawork do something", { messageId: "msg_123" })
let toastCalled = false
const tui = {
showToast: async () => {
toastCalled = true
},
}
//#when
applyUltraworkModelOverrideOnMessage(config, "sisyphus", output, tui)
//#then
expect(toastCalled).toBe(true)
})
test("should resolve display name to config key with deferred path", () => {
//#given
const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" })
const output = createOutput("ulw do something", { messageId: "msg_123" })
const tui = createMockTui()
//#when
applyUltraworkModelOverrideOnMessage(config, "Sisyphus (Ultraworker)", output, tui)
//#then
expect(dbOverrideSpy).toHaveBeenCalledWith(
"msg_123",
{ providerID: "anthropic", modelID: "claude-opus-4-6" },
"max",
)
})
})

View File

@ -0,0 +1,127 @@
import type { OhMyOpenCodeConfig } from "../config"
import type { AgentOverrides } from "../config/schema/agent-overrides"
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
}
/**
* 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 }>
},
): 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 rawAgentName = inputAgentName ?? messageAgentName
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) return null
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,
): void {
const override = resolveUltraworkOverride(pluginConfig, inputAgentName, output)
if (!override) 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 = { providerID: override.providerID, modelID: override.modelID }
if (override.variant) {
output.message["variant"] = override.variant
output.message["thinking"] = 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,
{ providerID: override.providerID, modelID: override.modelID },
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.`,
)
}

View File

@ -64,7 +64,7 @@ describe("AGENT_MODEL_REQUIREMENTS", () => {
const explore = AGENT_MODEL_REQUIREMENTS["explore"]
// when - accessing explore requirement
// then - fallbackChain exists with grok-code-fast-1 as first entry, minimax-m2.5-free as second
// then - fallbackChain: grok → minimax-free → haiku → nano
expect(explore).toBeDefined()
expect(explore.fallbackChain).toBeArray()
expect(explore.fallbackChain).toHaveLength(4)

View File

@ -16,10 +16,10 @@ export const AGENT_MODEL_REQUIREMENTS: Record<string, ModelRequirement> = {
sisyphus: {
fallbackChain: [
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
{ providers: ["kimi-for-coding", "friendli"], model: "k2p5" },
{ providers: ["opencode", "opencode-zen-abuse"], model: "kimi-k2.5-free" },
{ providers: ["kimi-for-coding"], model: "k2p5" },
{ providers: ["opencode"], model: "kimi-k2.5-free" },
{ providers: ["zai-coding-plan", "opencode"], model: "glm-5" },
{ providers: ["opencode", "opencode-zen-abuse"], model: "big-pickle" },
{ providers: ["opencode"], model: "big-pickle" },
],
requiresAnyModel: true,
},
@ -38,23 +38,23 @@ export const AGENT_MODEL_REQUIREMENTS: Record<string, ModelRequirement> = {
},
librarian: {
fallbackChain: [
{ providers: ["opencode", "opencode-zen-abuse"], model: "minimax-m2.5-free" },
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
{ providers: ["opencode", "opencode-zen-abuse"], model: "big-pickle" },
{ providers: ["opencode"], model: "minimax-m2.5-free" },
{ providers: ["opencode"], model: "big-pickle" },
],
},
explore: {
fallbackChain: [
{ providers: ["github-copilot", "venice"], model: "grok-code-fast-1" },
{ providers: ["opencode", "opencode-zen-abuse"], model: "minimax-m2.5-free" },
{ providers: ["github-copilot"], model: "grok-code-fast-1" },
{ providers: ["opencode"], model: "minimax-m2.5-free" },
{ providers: ["anthropic", "opencode"], model: "claude-haiku-4-5" },
{ providers: ["opencode", "opencode-zen-abuse"], model: "gpt-5-nano" },
{ providers: ["opencode"], model: "gpt-5-nano" },
],
},
"multimodal-looker": {
fallbackChain: [
{ providers: ["kimi-for-coding", "friendli"], model: "k2p5" },
{ providers: ["opencode", "opencode-zen-abuse"], model: "kimi-k2.5-free" },
{ providers: ["kimi-for-coding"], model: "k2p5" },
{ providers: ["opencode"], model: "kimi-k2.5-free" },
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
{ providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" },
{ providers: ["zai-coding-plan"], model: "glm-4.6v" },
@ -64,16 +64,16 @@ export const AGENT_MODEL_REQUIREMENTS: Record<string, ModelRequirement> = {
fallbackChain: [
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
{ providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
{ providers: ["kimi-for-coding", "friendli"], model: "k2p5" },
{ providers: ["opencode", "opencode-zen-abuse"], model: "kimi-k2.5-free" },
{ providers: ["kimi-for-coding"], model: "k2p5" },
{ providers: ["opencode"], model: "kimi-k2.5-free" },
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" },
],
},
metis: {
fallbackChain: [
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
{ providers: ["kimi-for-coding", "friendli"], model: "k2p5" },
{ providers: ["opencode", "opencode-zen-abuse"], model: "kimi-k2.5-free" },
{ providers: ["kimi-for-coding"], model: "k2p5" },
{ providers: ["opencode"], model: "kimi-k2.5-free" },
{ providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
],
@ -87,8 +87,8 @@ export const AGENT_MODEL_REQUIREMENTS: Record<string, ModelRequirement> = {
},
atlas: {
fallbackChain: [
{ providers: ["kimi-for-coding", "friendli"], model: "k2p5" },
{ providers: ["opencode", "opencode-zen-abuse"], model: "kimi-k2.5-free" },
{ providers: ["kimi-for-coding"], model: "k2p5" },
{ providers: ["opencode"], model: "kimi-k2.5-free" },
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-6" },
{ providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" },
],
@ -101,7 +101,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record<string, ModelRequirement> = {
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
{ providers: ["zai-coding-plan", "opencode"], model: "glm-5" },
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
{ providers: ["kimi-for-coding", "friendli"], model: "k2p5" },
{ providers: ["kimi-for-coding"], model: "k2p5" },
],
},
ultrabrain: {
@ -131,7 +131,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record<string, ModelRequirement> = {
fallbackChain: [
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-haiku-4-5" },
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
{ providers: ["opencode", "opencode-zen-abuse"], model: "gpt-5-nano" },
{ providers: ["opencode"], model: "gpt-5-nano" },
],
},
"unspecified-low": {
@ -150,7 +150,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record<string, ModelRequirement> = {
},
writing: {
fallbackChain: [
{ providers: ["kimi-for-coding", "friendli"], model: "k2p5" },
{ providers: ["kimi-for-coding"], model: "k2p5" },
{ providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-6" },
],