1ea192b3f4
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
164 lines
4.3 KiB
TypeScript
164 lines
4.3 KiB
TypeScript
/// <reference types="bun-types" />
|
|
|
|
import { describe, expect, test } from "bun:test"
|
|
import type { ToolContext } from "@opencode-ai/plugin/tool"
|
|
import type { BackgroundTask } from "../../features/background-agent"
|
|
import type { BackgroundOutputClient, BackgroundOutputManager } from "./clients"
|
|
import { createBackgroundOutput } from "./create-background-output"
|
|
|
|
const projectDir = "/Users/yeongyu/local-workspaces/oh-my-opencode"
|
|
|
|
const mockContext = {
|
|
sessionID: "test-session",
|
|
messageID: "test-message",
|
|
agent: "test-agent",
|
|
directory: projectDir,
|
|
worktree: projectDir,
|
|
abort: new AbortController().signal,
|
|
metadata: () => {},
|
|
ask: async () => {},
|
|
$: () => {
|
|
const result = { stdout: Buffer.from(""), stderr: Buffer.from(""), exitCode: 0 }
|
|
const promise = Promise.resolve(result) as Promise<typeof result> & {
|
|
quiet: () => Promise<typeof result>
|
|
nothrow: () => typeof promise
|
|
}
|
|
promise.quiet = () => promise
|
|
promise.nothrow = () => promise
|
|
return promise
|
|
},
|
|
} as ToolContext
|
|
|
|
function createTask(overrides: Partial<BackgroundTask> = {}): BackgroundTask {
|
|
return {
|
|
id: "task-1",
|
|
sessionId: "ses-1",
|
|
parentSessionId: "main-1",
|
|
parentMessageId: "msg-1",
|
|
description: "background task",
|
|
prompt: "do work",
|
|
agent: "test-agent",
|
|
status: "running",
|
|
...overrides,
|
|
}
|
|
}
|
|
|
|
function createMockClient(): BackgroundOutputClient {
|
|
return {
|
|
session: {
|
|
messages: async () => ({ data: [] }),
|
|
},
|
|
}
|
|
}
|
|
|
|
describe("createBackgroundOutput block=true polling", () => {
|
|
test("retries a missing background task id before reporting not found", async () => {
|
|
// #given
|
|
let lookupCount = 0
|
|
const task = createTask({
|
|
id: "bg_retry_visible",
|
|
status: "completed",
|
|
sessionId: "ses-retry-visible",
|
|
})
|
|
const manager: BackgroundOutputManager = {
|
|
getTask: (id: string) => {
|
|
if (id !== task.id) return undefined
|
|
lookupCount += 1
|
|
return lookupCount === 1 ? undefined : task
|
|
},
|
|
}
|
|
const client: BackgroundOutputClient = {
|
|
session: {
|
|
messages: async () => ({
|
|
data: [
|
|
{
|
|
id: "m1",
|
|
info: { role: "assistant", time: "2026-01-01T00:00:00Z" },
|
|
parts: [{ type: "text", text: "visible result" }],
|
|
},
|
|
],
|
|
}),
|
|
},
|
|
}
|
|
|
|
const tool = createBackgroundOutput(manager, client)
|
|
|
|
// #when
|
|
const output = await tool.execute({ task_id: task.id }, mockContext)
|
|
|
|
// #then
|
|
expect(lookupCount).toBe(2)
|
|
expect(output).toContain("Task Result")
|
|
expect(output).toContain("visible result")
|
|
expect(output).not.toContain("Task not found")
|
|
})
|
|
|
|
test("returns terminal error output when task fails during blocking wait", async () => {
|
|
// #given
|
|
let pollCount = 0
|
|
const task = createTask({ status: "running" })
|
|
const manager: BackgroundOutputManager = {
|
|
getTask: (id: string) => {
|
|
if (id !== task.id) return undefined
|
|
|
|
pollCount += 1
|
|
if (pollCount >= 2) {
|
|
task.status = "error"
|
|
task.error = "task failed"
|
|
}
|
|
|
|
return task
|
|
},
|
|
}
|
|
|
|
const tool = createBackgroundOutput(manager, createMockClient())
|
|
|
|
// #when
|
|
const output = await tool.execute(
|
|
{
|
|
task_id: task.id,
|
|
block: true,
|
|
timeout: 3000,
|
|
full_session: false,
|
|
},
|
|
mockContext
|
|
)
|
|
|
|
// #then
|
|
expect(pollCount).toBeGreaterThanOrEqual(2)
|
|
expect(output).toContain("Status | **error**")
|
|
expect(output).not.toContain("Timed out waiting")
|
|
})
|
|
|
|
test("returns legacy status output with timeout note when task stays running", async () => {
|
|
// #given
|
|
let pollCount = 0
|
|
const task = createTask({ status: "running" })
|
|
const manager: BackgroundOutputManager = {
|
|
getTask: (id: string) => {
|
|
if (id !== task.id) return undefined
|
|
pollCount += 1
|
|
return task
|
|
},
|
|
}
|
|
|
|
const tool = createBackgroundOutput(manager, createMockClient())
|
|
|
|
// #when
|
|
const output = await tool.execute(
|
|
{
|
|
task_id: task.id,
|
|
block: true,
|
|
timeout: 10,
|
|
},
|
|
mockContext
|
|
)
|
|
|
|
// #then
|
|
expect(pollCount).toBeGreaterThanOrEqual(2)
|
|
expect(output).toContain("# Task Status")
|
|
expect(output).toContain("Timed out waiting")
|
|
expect(output).toContain("still running")
|
|
})
|
|
})
|