Strengthen sync executor test coverage

Cover metadata output and prompt failure branches so the sync executor is verified by its returned contract, not only tool flag plumbing.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-03-11 16:08:01 +09:00
parent 09a3c54f85
commit 339ece93f6

View File

@@ -1,137 +1,252 @@
const { describe, test, expect, mock } = require("bun:test")
describe("executeSync", () => {
test("passes question=false via tools parameter to block question tool", async () => {
//#given
const { executeSync } = require("./sync-executor")
type ExecuteSync = typeof import("./sync-executor").executeSync
const deps = {
createOrGetSession: mock(async () => ({ sessionID: "ses-test-123", isNew: true })),
waitForCompletion: mock(async () => {}),
processMessages: mock(async () => "agent response"),
setSessionFallbackChain: mock(() => {}),
type PromptAsyncInput = {
path: { id: string }
body: {
agent: string
tools: Record<string, boolean>
parts: Array<{ type: string; text: string }>
}
}
type ToolContext = {
sessionID: string
messageID: string
agent: string
abort: AbortSignal
metadata: ReturnType<typeof mock>
}
type Dependencies = {
createOrGetSession: ReturnType<typeof mock>
waitForCompletion: ReturnType<typeof mock>
processMessages: ReturnType<typeof mock>
setSessionFallbackChain: ReturnType<typeof mock>
}
async function importExecuteSync(): Promise<ExecuteSync> {
const module = await import("./sync-executor")
return module.executeSync
}
function createDependencies(overrides?: Partial<Dependencies>): Dependencies {
return {
createOrGetSession: mock(async () => ({ sessionID: "ses-test-123", isNew: true })),
waitForCompletion: mock(async () => {}),
processMessages: mock(async () => "agent response"),
setSessionFallbackChain: mock(() => {}),
...overrides,
}
}
function createPromptAsyncRecorder(implementation?: (input: PromptAsyncInput) => Promise<unknown>) {
let capturedInput: PromptAsyncInput | undefined
const promptAsync = mock(async (input: PromptAsyncInput) => {
capturedInput = input
if (implementation) {
return implementation(input)
}
let promptArgs: any
const promptAsync = mock(async (input: any) => {
promptArgs = input
return { data: {} }
})
return { data: {} }
})
return {
promptAsync,
getCapturedInput(): PromptAsyncInput | undefined {
return capturedInput
},
}
}
function createToolContext(): ToolContext {
return {
sessionID: "parent-session",
messageID: "msg-1",
agent: "sisyphus",
abort: new AbortController().signal,
metadata: mock(async () => {}),
}
}
function createContext(promptAsync: ReturnType<typeof mock>) {
return {
client: {
session: {
promptAsync,
},
},
}
}
describe("executeSync", () => {
test("sends sync prompt with question and task tools disabled", async () => {
//#given
const executeSync = await importExecuteSync()
const deps = createDependencies()
const toolContext = createToolContext()
const recorder = createPromptAsyncRecorder()
const args = {
subagent_type: "explore",
description: "test task",
prompt: "find something",
}
const toolContext = {
sessionID: "parent-session",
messageID: "msg-1",
agent: "sisyphus",
abort: new AbortController().signal,
metadata: mock(async () => {}),
}
const ctx = {
client: {
session: { promptAsync },
},
run_in_background: false,
}
//#when
await executeSync(args, toolContext, ctx as any, deps)
await executeSync(args, toolContext, createContext(recorder.promptAsync) as never, deps)
//#then
expect(promptAsync).toHaveBeenCalled()
expect(promptArgs.body.tools.question).toBe(false)
const promptInput = recorder.getCapturedInput()
expect(promptInput).toBeDefined()
expect(promptInput?.path.id).toBe("ses-test-123")
expect(promptInput?.body.agent).toBe("explore")
expect(promptInput?.body.tools.question).toBe(false)
expect(promptInput?.body.tools.task).toBe(false)
expect(promptInput?.body.parts).toEqual([{ type: "text", text: "find something" }])
})
test("passes task=false via tools parameter", async () => {
test("returns processed response with task metadata footer", async () => {
//#given
const { executeSync } = require("./sync-executor")
const deps = {
createOrGetSession: mock(async () => ({ sessionID: "ses-test-123", isNew: true })),
waitForCompletion: mock(async () => {}),
processMessages: mock(async () => "agent response"),
setSessionFallbackChain: mock(() => {}),
}
let promptArgs: any
const promptAsync = mock(async (input: any) => {
promptArgs = input
return { data: {} }
const executeSync = await importExecuteSync()
const deps = createDependencies({
createOrGetSession: mock(async () => ({ sessionID: "ses-test-456", isNew: true })),
processMessages: mock(async () => "final answer"),
})
const toolContext = createToolContext()
const recorder = createPromptAsyncRecorder()
const args = {
subagent_type: "librarian",
description: "search docs",
prompt: "find docs",
}
const toolContext = {
sessionID: "parent-session",
messageID: "msg-2",
agent: "sisyphus",
abort: new AbortController().signal,
metadata: mock(async () => {}),
}
const ctx = {
client: {
session: { promptAsync },
},
run_in_background: false,
}
//#when
await executeSync(args, toolContext, ctx as any, deps)
const result = await executeSync(args, toolContext, createContext(recorder.promptAsync) as never, deps)
//#then
expect(promptAsync).toHaveBeenCalled()
expect(promptArgs.body.tools.task).toBe(false)
expect(result).toContain("final answer")
expect(result).toContain("<task_metadata>")
expect(result).toContain("session_id: ses-test-456")
expect(result).toContain("</task_metadata>")
expect(deps.waitForCompletion).toHaveBeenCalledWith(
"ses-test-456",
toolContext,
expect.objectContaining({ client: expect.anything() })
)
})
test("applies fallbackChain to sync sessions", async () => {
test("records metadata with description and created session id", async () => {
//#given
const { executeSync } = require("./sync-executor")
const setSessionFallbackChain = mock(() => {})
const deps = {
createOrGetSession: mock(async () => ({ sessionID: "ses-test-456", isNew: true })),
waitForCompletion: mock(async () => {}),
processMessages: mock(async () => "agent response"),
setSessionFallbackChain,
const executeSync = await importExecuteSync()
const deps = createDependencies({
createOrGetSession: mock(async () => ({ sessionID: "ses-metadata", isNew: true })),
})
const toolContext = createToolContext()
const recorder = createPromptAsyncRecorder()
const args = {
subagent_type: "explore",
description: "metadata title",
prompt: "collect evidence",
run_in_background: false,
}
//#when
await executeSync(args, toolContext, createContext(recorder.promptAsync) as never, deps)
//#then
expect(toolContext.metadata).toHaveBeenCalledWith({
title: "metadata title",
metadata: { sessionId: "ses-metadata" },
})
})
test("applies fallback chain to sync sessions before completion polling", async () => {
//#given
const executeSync = await importExecuteSync()
const deps = createDependencies({
createOrGetSession: mock(async () => ({ sessionID: "ses-fallback", isNew: true })),
})
const toolContext = createToolContext()
const recorder = createPromptAsyncRecorder()
const args = {
subagent_type: "explore",
description: "test task",
prompt: "find something",
run_in_background: false,
}
const toolContext = {
sessionID: "parent-session",
messageID: "msg-3",
agent: "sisyphus",
abort: new AbortController().signal,
metadata: mock(async () => {}),
}
const ctx = {
client: {
session: { promptAsync: mock(async () => ({ data: {} })) },
},
}
const fallbackChain = [
{ providers: ["quotio"], model: "kimi-k2.5", variant: undefined },
{ providers: ["openai"], model: "gpt-5.2", variant: "high" },
]
//#when
await executeSync(args, toolContext, ctx as any, deps, fallbackChain)
await executeSync(
args,
toolContext,
createContext(recorder.promptAsync) as never,
deps,
fallbackChain
)
//#then
expect(setSessionFallbackChain).toHaveBeenCalledWith("ses-test-456", fallbackChain)
expect(deps.setSessionFallbackChain).toHaveBeenCalledWith("ses-fallback", fallbackChain)
})
test("returns dedicated agent-not-found error with task metadata", async () => {
//#given
const executeSync = await importExecuteSync()
const deps = createDependencies({
createOrGetSession: mock(async () => ({ sessionID: "ses-missing-agent", isNew: true })),
})
const toolContext = createToolContext()
const recorder = createPromptAsyncRecorder(async () => {
throw new Error("agent.name is undefined")
})
const args = {
subagent_type: "explore",
description: "missing agent",
prompt: "find something",
run_in_background: false,
}
//#when
const result = await executeSync(args, toolContext, createContext(recorder.promptAsync) as never, deps)
//#then
expect(result).toContain('Error: Agent "explore" not found')
expect(result).toContain("session_id: ses-missing-agent")
expect(deps.waitForCompletion).not.toHaveBeenCalled()
expect(deps.processMessages).not.toHaveBeenCalled()
})
test("returns generic prompt failure with task metadata", async () => {
//#given
const executeSync = await importExecuteSync()
const deps = createDependencies({
createOrGetSession: mock(async () => ({ sessionID: "ses-prompt-error", isNew: true })),
})
const toolContext = createToolContext()
const recorder = createPromptAsyncRecorder(async () => {
throw new Error("network exploded")
})
const args = {
subagent_type: "librarian",
description: "generic failure",
prompt: "find docs",
run_in_background: false,
}
//#when
const result = await executeSync(args, toolContext, createContext(recorder.promptAsync) as never, deps)
//#then
expect(result).toContain("Error: Failed to send prompt: network exploded")
expect(result).toContain("session_id: ses-prompt-error")
expect(deps.waitForCompletion).not.toHaveBeenCalled()
expect(deps.processMessages).not.toHaveBeenCalled()
})
})