test(tools): remove unsafe test assertions

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-05-12 14:23:05 +09:00
parent 8b093a1115
commit fb135d047c
24 changed files with 199 additions and 156 deletions
@@ -18,7 +18,7 @@ describe("createBackgroundTask metadata", () => {
// #given
clearPendingStore()
const manager = {
const manager = testCoerce<BackgroundManager>({
launch: mock(() => Promise.resolve({
id: "task-1",
sessionID: null,
@@ -27,12 +27,12 @@ describe("createBackgroundTask metadata", () => {
status: "pending",
})),
getTask: mock(() => undefined),
} as unknown as BackgroundManager
const client = {
})
const client = testCoerce<PluginInput["client"]>({
session: {
messages: mock(() => Promise.resolve({ data: [] })),
},
} as unknown as PluginInput["client"]
})
let capturedMetadata: { title?: string; metadata?: Record<string, unknown> } | undefined
const tool = createBackgroundTask(manager, client)
@@ -21,16 +21,16 @@ describe("createBackgroundTask", () => {
}))
const getTaskMock = mock()
const mockManager = {
const mockManager = testCoerce<BackgroundManager>({
launch: launchMock,
getTask: getTaskMock,
} as unknown as BackgroundManager
})
const mockClient = {
const mockClient = testCoerce<PluginInput["client"]>({
session: {
messages: mock(() => Promise.resolve({ data: [] })),
},
} as unknown as PluginInput["client"]
})
const tool = createBackgroundTask(mockManager, mockClient)
+14 -14
View File
@@ -66,10 +66,10 @@ describe("background_output full_session", () => {
const manager = createMockManager(task)
const client = createMockClient({})
const tool = createBackgroundOutput(manager, client)
const ctxWithCallId = {
const ctxWithCallId = testCoerce<ToolContext>({
...mockContext,
callID: "call-1",
} as unknown as ToolContext
})
// #when
await tool.execute({ task_id: "task-1" }, ctxWithCallId)
@@ -93,10 +93,10 @@ describe("background_output full_session", () => {
const manager = createMockManager(task)
const client = createMockClient({})
const tool = createBackgroundOutput(manager, client)
const ctxWithCallId = {
const ctxWithCallId = testCoerce<ToolContext>({
...mockContext,
callID: "call-1",
} as unknown as ToolContext
})
// #when
await tool.execute({ task_id: "task-1" }, ctxWithCallId)
@@ -387,7 +387,7 @@ describe("background_cancel", () => {
// #given
const task = createTask({ status: "running" })
const cancelled: string[] = []
const manager = {
const manager = testCoerce<BackgroundManager>({
getTask: (id: string) => (id === task.id ? task : undefined),
getAllDescendantTasks: () => [task],
cancelTask: async (taskId: string) => {
@@ -395,7 +395,7 @@ describe("background_cancel", () => {
task.status = "cancelled"
return true
},
} as unknown as BackgroundManager
})
const client = { session: { abort: async () => ({}) } } as BackgroundCancelClient
const tool = createBackgroundCancel(manager, client)
@@ -412,7 +412,7 @@ describe("background_cancel", () => {
const taskA = createTask({ id: "task-a", status: "running" })
const taskB = createTask({ id: "task-b", status: "pending" })
const cancelled: string[] = []
const manager = {
const manager = testCoerce<BackgroundManager>({
getTask: () => undefined,
getAllDescendantTasks: () => [taskA, taskB],
cancelTask: async (taskId: string) => {
@@ -421,7 +421,7 @@ describe("background_cancel", () => {
task.status = "cancelled"
return true
},
} as unknown as BackgroundManager
})
const client = { session: { abort: async () => ({}) } } as BackgroundCancelClient
const tool = createBackgroundCancel(manager, client)
@@ -437,7 +437,7 @@ describe("background_cancel", () => {
// #given
const taskA = createTask({ id: "task-a", status: "running", sessionId: "ses-a", description: "running task" })
const taskB = createTask({ id: "task-b", status: "pending", sessionId: undefined, description: "pending task" })
const manager = {
const manager = testCoerce<BackgroundManager>({
getTask: () => undefined,
getAllDescendantTasks: () => [taskA, taskB],
cancelTask: async (taskId: string) => {
@@ -445,7 +445,7 @@ describe("background_cancel", () => {
task.status = "cancelled"
return true
},
} as unknown as BackgroundManager
})
const client = { session: { abort: async () => ({}) } } as BackgroundCancelClient
const tool = createBackgroundCancel(manager, client)
@@ -461,7 +461,7 @@ describe("background_cancel", () => {
// #given
const task = createTask({ id: "task-1", status: "running" })
const cancelOptions: Array<{ taskId: string; options: unknown }> = []
const manager = {
const manager = testCoerce<BackgroundManager>({
getTask: (id: string) => (id === task.id ? task : undefined),
getAllDescendantTasks: () => [task],
cancelTask: async (taskId: string, options?: unknown) => {
@@ -469,7 +469,7 @@ describe("background_cancel", () => {
task.status = "cancelled"
return true
},
} as unknown as BackgroundManager
})
const client = { session: { abort: async () => ({}) } } as BackgroundCancelClient
const tool = createBackgroundCancel(manager, client)
@@ -487,7 +487,7 @@ describe("background_cancel", () => {
// #given
const task = createTask({ id: "task-1", status: "running" })
const cancelOptions: Array<{ taskId: string; options: unknown }> = []
const manager = {
const manager = testCoerce<BackgroundManager>({
getTask: (id: string) => (id === task.id ? task : undefined),
getAllDescendantTasks: () => [task],
cancelTask: async (taskId: string, options?: unknown) => {
@@ -495,7 +495,7 @@ describe("background_cancel", () => {
task.status = "cancelled"
return true
},
} as unknown as BackgroundManager
})
const client = { session: { abort: async () => ({}) } } as BackgroundCancelClient
const tool = createBackgroundCancel(manager, client)
@@ -2,7 +2,7 @@ const { describe, test, expect, mock, beforeEach } = require("bun:test")
const { resolveCallableAgents, clearCallableAgentsCache } = require("./agent-resolver")
const { ALLOWED_AGENTS } = require("./constants")
function createMockClient(agents = []) {
function createMockClient(agents: Array<Record<string, string>> = []) {
return {
app: {
agents: mock(() => Promise.resolve({ data: agents })),
@@ -37,12 +37,12 @@ describe("call-omo-agent createOrGetSession", () => {
}
// when
const result = await createOrGetSession(args as any, toolContext as any, ctx as any)
const result = await createOrGetSession(testCoerce(args), testCoerce(toolContext), testCoerce(ctx))
// then
expect(result).toEqual({ sessionID: "ses_child", isNew: true })
expect(createCalls).toHaveLength(1)
const createBody = (createCalls[0] as any)?.body
const createBody = (testCoerce(createCalls[0]))?.body
expect(createBody?.parentID).toBe("ses_parent")
expect(createBody?.permission).toBeUndefined()
expect(subagentSessions.has("ses_child")).toBe(true)
@@ -19,7 +19,7 @@ describe("call-omo-agent resolveOrCreateSessionId", () => {
const { parentDirectory, contextDirectory } = options
const parentSessionData = parentDirectory ? { data: { directory: parentDirectory } } : { data: {} }
const ctx = {
const ctx = testCoerce<Parameters<typeof resolveOrCreateSessionId>[0]>({
directory: contextDirectory,
client: {
session: {
@@ -31,7 +31,7 @@ describe("call-omo-agent resolveOrCreateSessionId", () => {
},
},
},
} as unknown as Parameters<typeof resolveOrCreateSessionId>[0]
})
const args = {
description: "sync test",
@@ -389,7 +389,7 @@ describe("executeSync", () => {
}
//#when
await executeSync(args, toolContext, ctx as any, deps, undefined, spawnReservation)
await executeSync(args, toolContext, testCoerce(ctx), deps, undefined, spawnReservation)
//#then
expect(spawnReservation.commit).toHaveBeenCalledTimes(1)
+9 -1
View File
@@ -14,6 +14,10 @@ type SessionWithPromptAsync = {
promptAsync: (opts: { path: { id: string }; body: Record<string, unknown> }) => Promise<unknown>
}
function hasPromptAsync(session: PluginInput["client"]["session"]): session is PluginInput["client"]["session"] & SessionWithPromptAsync {
return "promptAsync" in session && typeof session.promptAsync === "function"
}
type ExecuteSyncDeps = {
createOrGetSession: typeof createOrGetSession
waitForCompletion: typeof waitForCompletion
@@ -102,7 +106,11 @@ export async function executeSync(
const normalizedSubagentType = stripAgentListSortPrefix(args.subagent_type)
try {
await (ctx.client.session as unknown as SessionWithPromptAsync).promptAsync({
if (!hasPromptAsync(ctx.client.session)) {
return `Error: Failed to send prompt: promptAsync is not available on this OpenCode client.\n\n<task_metadata>\nsession_id: ${sessionID}\n</task_metadata>`
}
await ctx.client.session.promptAsync({
path: { id: sessionID },
body: {
agent: normalizedSubagentType,
+21 -10
View File
@@ -1,7 +1,25 @@
import type { OpencodeClient } from "./types"
import { log } from "../../shared/logger"
import { isRecord } from "../../shared/record-type-guard"
import { readConnectedProvidersCache, readProviderModelsCache } from "../../shared/connected-providers-cache"
type ModelListClient = OpencodeClient & {
model: { list: () => Promise<unknown> }
}
function hasModelList(client: OpencodeClient): client is ModelListClient {
return "model" in client && isRecord(client.model) && typeof client.model.list === "function"
}
function isModelRow(value: unknown): value is { provider: string; id: string } {
return isRecord(value) && typeof value.provider === "string" && typeof value.id === "string"
}
function extractModelRows(result: unknown): Array<{ provider: string; id: string }> {
const rows = Array.isArray(result) ? result : isRecord(result) && Array.isArray(result.data) ? result.data : []
return rows.filter(isModelRow)
}
function addFromProviderModels(
out: Set<string>,
providerID: string,
@@ -35,24 +53,17 @@ export async function getAvailableModelsForDelegateTask(client: OpencodeClient):
return new Set()
}
const modelList = (client as unknown as { model?: { list?: () => Promise<unknown> } })
?.model
?.list
if (!modelList) {
if (!hasModelList(client)) {
return new Set()
}
try {
const result = await modelList()
const rows = Array.isArray(result)
? result
: ((result as { data?: unknown }).data as Array<{ provider?: string; id?: string }> | undefined) ?? []
const result = await client.model.list()
const rows = extractModelRows(result)
const connected = new Set(connectedProviders)
const out = new Set<string>()
for (const row of rows) {
if (!row?.provider || !row?.id) continue
if (!connected.has(row.provider)) continue
out.add(`${row.provider}/${row.id}`)
}
@@ -26,8 +26,8 @@ describe("resolveCategoryExecution", () => {
})
const createMockExecutorContext = (): ExecutorContext => ({
client: {} as any,
manager: {} as any,
client: testCoerce({}),
manager: testCoerce({}),
directory: "/tmp/test",
userCategories: {},
sisyphusJuniorModel: undefined,
@@ -28,7 +28,7 @@ describe("task tool metadata awaiting", () => {
subagent_type: "explore",
}
const executorCtx = {
const executorCtx = testCoerce({
manager: {
launch: async () => ({
id: "task_1",
@@ -40,7 +40,7 @@ describe("task tool metadata awaiting", () => {
}),
getTask: () => undefined,
},
} as any
})
const parentContext = {
sessionID: "ses_parent",
@@ -63,7 +63,7 @@ describe("metadata model unification", () => {
load_skills: [], run_in_background: true, subagent_type: "explore",
}
await executeBackgroundTask(args, ctx, {
await executeBackgroundTask(args, ctx, testCoerce({
manager: {
launch: async () => ({
id: "bg_1", description: "test", agent: "explore",
@@ -71,7 +71,7 @@ describe("metadata model unification", () => {
}),
getTask: () => undefined,
},
} as any, parentContext, "explore", MODEL, undefined)
}), parentContext, "explore", MODEL, undefined)
const meta = ctx.captured.find((m: any) => m.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -92,7 +92,7 @@ describe("metadata model unification", () => {
}
await executeUnstableAgentTask(
args, ctx,
{
testCoerce({
manager: {
launch: async () => launchedTask,
getTask: () => launchedTask,
@@ -109,7 +109,7 @@ describe("metadata model unification", () => {
},
},
syncPollTimeoutMs: 100,
} as any,
}),
parentContext, "explore", MODEL, undefined, "anthropic/claude-sonnet-4-6",
)
@@ -126,14 +126,14 @@ describe("metadata model unification", () => {
load_skills: [], run_in_background: true, task_id: "ses_resumed",
}
await executeBackgroundContinuation(args, ctx, {
await executeBackgroundContinuation(args, ctx, testCoerce({
manager: {
resume: async () => ({
id: "bg_2", description: "continue", agent: "explore",
status: "running", sessionId: "ses_resumed", model: MODEL,
}),
},
} as any, parentContext)
}), parentContext)
const meta = ctx.captured.find((m: any) => m.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -153,7 +153,7 @@ describe("metadata model unification", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, {
await executeSyncContinuation(args, ctx, testCoerce({
client: {
session: {
messages: async () => ({
@@ -162,7 +162,7 @@ describe("metadata model unification", () => {
prompt: async () => ({}),
},
},
} as any, parentContext, deps)
}), parentContext, deps)
const meta = ctx.captured.find((m: any) => m.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -206,7 +206,7 @@ describe("metadata model unification", () => {
load_skills: [], run_in_background: true, subagent_type: "explore",
}
await executeBackgroundTask(args, ctx, {
await executeBackgroundTask(args, ctx, testCoerce({
manager: {
launch: async () => ({
id: "bg_1", description: "test", agent: "explore",
@@ -214,7 +214,7 @@ describe("metadata model unification", () => {
}),
getTask: () => undefined,
},
} as any, parentContext, "explore", undefined, undefined)
}), parentContext, "explore", undefined, undefined)
const meta = ctx.captured.find((m: any) => m.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -236,7 +236,7 @@ describe("metadata model unification", () => {
await executeUnstableAgentTask(
args, ctx,
{
testCoerce({
manager: {
launch: async () => launchedTask,
getTask: () => launchedTask,
@@ -253,7 +253,7 @@ describe("metadata model unification", () => {
},
},
syncPollTimeoutMs: 100,
} as any,
}),
parentContext, "explore", undefined, undefined, "anthropic/claude-sonnet-4-6",
)
@@ -270,14 +270,14 @@ describe("metadata model unification", () => {
load_skills: [], run_in_background: true, task_id: "ses_resumed",
}
await executeBackgroundContinuation(args, ctx, {
await executeBackgroundContinuation(args, ctx, testCoerce({
manager: {
resume: async () => ({
id: "bg_2", description: "continue", agent: "explore",
status: "running", sessionId: "ses_resumed",
}),
},
} as any, parentContext)
}), parentContext)
const meta = ctx.captured.find((m: any) => m.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -297,14 +297,14 @@ describe("metadata model unification", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, {
await executeSyncContinuation(args, ctx, testCoerce({
client: {
session: {
messages: async () => ({ data: [] }),
prompt: async () => ({}),
},
},
} as any, parentContext, deps)
}), parentContext, deps)
const meta = ctx.captured.find((m: any) => m.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -381,7 +381,7 @@ describe("metadata model unification", () => {
category: "visual-engineering", load_skills: [], run_in_background: true, subagent_type: "explore",
}
await executeBackgroundTask(args, ctx, {
await executeBackgroundTask(args, ctx, testCoerce({
manager: {
launch: async () => ({
id: "bg_variant", description: "test", agent: "explore",
@@ -389,7 +389,7 @@ describe("metadata model unification", () => {
}),
getTask: () => undefined,
},
} as any, parentContext, "explore", MODEL_WITH_VARIANT, undefined)
}), parentContext, "explore", MODEL_WITH_VARIANT, undefined)
const meta = ctx.captured.find((metadataEvent: any) => metadataEvent.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -411,7 +411,7 @@ describe("metadata model unification", () => {
await executeUnstableAgentTask(
args, ctx,
{
testCoerce({
manager: {
launch: async () => launchedTask,
getTask: () => launchedTask,
@@ -428,7 +428,7 @@ describe("metadata model unification", () => {
},
},
syncPollTimeoutMs: 100,
} as any,
}),
parentContext, "explore", MODEL_WITH_VARIANT, undefined, "google/gemini-3.1-pro high",
)
@@ -445,14 +445,14 @@ describe("metadata model unification", () => {
load_skills: [], run_in_background: true, task_id: "ses_resumed_variant",
}
await executeBackgroundContinuation(args, ctx, {
await executeBackgroundContinuation(args, ctx, testCoerce({
manager: {
resume: async () => ({
id: "bg_resume_variant", description: "continue", agent: "explore",
status: "running", sessionId: "ses_resumed_variant", model: MODEL_WITH_VARIANT,
}),
},
} as any, parentContext)
}), parentContext)
const meta = ctx.captured.find((metadataEvent: any) => metadataEvent.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -472,7 +472,7 @@ describe("metadata model unification", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, {
await executeSyncContinuation(args, ctx, testCoerce({
client: {
session: {
messages: async () => ({
@@ -481,7 +481,7 @@ describe("metadata model unification", () => {
prompt: async () => ({}),
},
},
} as any, parentContext, deps)
}), parentContext, deps)
const meta = ctx.captured.find((metadataEvent: any) => metadataEvent.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -64,7 +64,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
load_skills: [], run_in_background: true, subagent_type: "explore",
}
await executeBackgroundTask(args, ctx, {
await executeBackgroundTask(args, ctx, testCoerce({
manager: {
launch: async () => ({
id: "bg_abc123", description: "test", agent: "explore",
@@ -72,7 +72,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
}),
getTask: () => undefined,
},
} as any, parentContext, "explore", MODEL, undefined)
}), parentContext, "explore", MODEL, undefined)
const meta = ctx.captured.find((m: any) => m.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -98,7 +98,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
await executeUnstableAgentTask(
args, ctx,
{
testCoerce({
manager: {
launch: async () => launchedTask,
getTask: () => launchedTask,
@@ -115,7 +115,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
},
},
syncPollTimeoutMs: 100,
} as any,
}),
parentContext, "explore", MODEL, undefined, "anthropic/claude-sonnet-4-6",
)
@@ -136,14 +136,14 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
load_skills: [], run_in_background: true, task_id: "ses_resumed_x",
}
await executeBackgroundContinuation(args, ctx, {
await executeBackgroundContinuation(args, ctx, testCoerce({
manager: {
resume: async () => ({
id: "bg_resumed_y", description: "continue", agent: "explore",
status: "running", sessionId: "ses_resumed_x", model: MODEL,
}),
},
} as any, parentContext)
}), parentContext)
const meta = ctx.captured.find((m: any) => m.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -160,14 +160,14 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
load_skills: [], run_in_background: true, task_id: "ses_resumed_x",
}
await executeBackgroundContinuation(args, ctx, {
await executeBackgroundContinuation(args, ctx, testCoerce({
manager: {
resume: async () => ({
id: "bg_resumed_y", description: "continue", agent: "explore",
status: "running", sessionId: "ses_resumed_x", model: MODEL, category: "deep",
}),
},
} as any, parentContext)
}), parentContext)
const meta = ctx.captured.find((item: any) => item.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -187,14 +187,14 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
task_id: "ses_resumed_x",
}
await executeBackgroundContinuation(args, ctx, {
await executeBackgroundContinuation(args, ctx, testCoerce({
manager: {
resume: async () => ({
id: "bg_resumed_y", description: "continue", agent: "explore",
status: "running", sessionId: "ses_resumed_x", model: MODEL,
}),
},
} as any, parentContext)
}), parentContext)
const meta = ctx.captured.find((item: any) => item.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -216,7 +216,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, {
await executeSyncContinuation(args, ctx, testCoerce({
client: {
session: {
messages: async () => ({
@@ -225,7 +225,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
prompt: async () => ({}),
},
},
} as any, parentContext, deps)
}), parentContext, deps)
const meta = ctx.captured.find((m: any) => m.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -246,7 +246,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, {
await executeSyncContinuation(args, ctx, testCoerce({
client: {
session: {
messages: async () => ({
@@ -255,7 +255,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
prompt: async () => ({}),
},
},
} as any, parentContext, deps)
}), parentContext, deps)
const meta = ctx.captured.find((item: any) => item.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -275,7 +275,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, {
await executeSyncContinuation(args, ctx, testCoerce({
client: {
session: {
messages: async () => ({
@@ -284,7 +284,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
prompt: async () => ({}),
},
},
} as any, parentContext, deps)
}), parentContext, deps)
const meta = ctx.captured.find((item: any) => item.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -309,7 +309,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
}
await executeSyncContinuation(args, ctx, {
await executeSyncContinuation(args, ctx, testCoerce({
client: {
session: {
messages: async () => ({
@@ -318,7 +318,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
prompt: async () => ({}),
},
},
} as any, parentContext, deps)
}), parentContext, deps)
const meta = ctx.captured.find((item: any) => item.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -368,7 +368,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
run_in_background: true,
}
await executeBackgroundTask(args, ctx, {
await executeBackgroundTask(args, ctx, testCoerce({
manager: {
launch: async () => ({
id: "bg_abc123", description: "test", agent: "Sisyphus-Junior",
@@ -376,7 +376,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
}),
getTask: () => undefined,
},
} as any, parentContext, "Sisyphus-Junior", MODEL, undefined)
}), parentContext, "Sisyphus-Junior", MODEL, undefined)
const meta = ctx.captured.find((item: any) => item.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -402,7 +402,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
await executeUnstableAgentTask(
args, ctx,
{
testCoerce({
manager: {
launch: async () => launchedTask,
getTask: () => launchedTask,
@@ -419,7 +419,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
},
},
syncPollTimeoutMs: 100,
} as any,
}),
parentContext, "Sisyphus-Junior", MODEL, undefined, "anthropic/claude-sonnet-4-6",
)
@@ -438,14 +438,14 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
load_skills: [], run_in_background: true, task_id: "ses_resume_title",
}
await executeBackgroundContinuation(args, ctx, {
await executeBackgroundContinuation(args, ctx, testCoerce({
manager: {
resume: async () => ({
id: "bg_resume_title", description: "continue work", agent: "explore",
status: "running", sessionId: "ses_resume_title", model: MODEL,
}),
},
} as any, parentContext)
}), parentContext)
const meta = ctx.captured.find((item: any) => item.metadata?.sessionId)
expect(meta).toBeDefined()
@@ -460,7 +460,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
load_skills: [], run_in_background: false, task_id: "ses_sync_title",
}
await executeSyncContinuation(args, ctx, {
await executeSyncContinuation(args, ctx, testCoerce({
client: {
session: {
messages: async () => ({
@@ -469,7 +469,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
prompt: async () => ({}),
},
},
} as any, parentContext, {
}), parentContext, {
pollSyncSession: async () => null,
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
})
@@ -500,8 +500,8 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
},
}
const bgOutput = createBackgroundOutput(manager as any, client as any)
await bgOutput.execute({ task_id: "bg_output_xyz" } as any, ctx as any)
const bgOutput = createBackgroundOutput(testCoerce(manager), testCoerce(client))
await bgOutput.execute(testCoerce({ task_id: "bg_output_xyz" }), testCoerce(ctx))
const meta = ctx.captured.find((m: any) => m.metadata?.backgroundTaskId)
expect(meta).toBeDefined()
+2 -2
View File
@@ -18,14 +18,14 @@ function createDelegateTask(...args: Parameters<typeof import("./tools").createD
const toolDefinition = createDelegateTask({ manager: {} as never, client: {} as never, directory: "/tmp/test" })
//#when
const categorySchema = toolDefinition.args.category as unknown as {
const categorySchema = testCoerce<{
def: {
type: string
innerType: {
def: { type: string }
}
}
}
}>(toolDefinition.args.category)
//#then
expect(categorySchema.def.type).toBe("optional")
@@ -33,7 +33,7 @@ describe("executeUnstableAgentTask session permission", () => {
metadata: () => {},
abort: new AbortController().signal,
} satisfies Parameters<typeof executeUnstableAgentTask>[1]
const executorContext = {
const executorContext = testCoerce<Parameters<typeof executeUnstableAgentTask>[2]>({
manager: mockManager,
client: {
session: {
@@ -41,7 +41,7 @@ describe("executeUnstableAgentTask session permission", () => {
messages: async () => ({ data: [] }),
},
},
} as unknown as Parameters<typeof executeUnstableAgentTask>[2]
})
const parentContext = {
sessionID: "parent-session",
messageID: "msg_parent",
@@ -51,9 +51,9 @@ describe("normalizeHashlineEdits", () => {
it("rejects legacy payload without op", () => {
//#given
const input = [{ type: "set_line", line: "2#VK", text: "updated" }] as unknown as Parameters<
const input = testCoerce<Parameters<
typeof normalizeHashlineEdits
>[0]
>[0]>([{ type: "set_line", line: "2#VK", text: "updated" }])
//#when / #then
expect(() => normalizeHashlineEdits(input)).toThrow(/legacy format was removed/i)
+2 -2
View File
@@ -8,14 +8,14 @@ import * as os from "node:os"
import * as path from "node:path"
function createMockContext(): ToolContext {
return {
return testCoerce<ToolContext>({
sessionID: "test",
messageID: "test",
agent: "test",
abort: new AbortController().signal,
metadata: mock(() => {}),
ask: async () => {},
} as unknown as ToolContext
})
}
describe("createHashlineEditTool", () => {
@@ -32,8 +32,8 @@ describe("resolveMultimodalLookerAgentMetadata", () => {
afterEach(() => {
clearVisionCapableModelsCache()
;(modelAvailability.fetchAvailableModels as unknown as { mockRestore?: () => void }).mockRestore?.()
;(connectedProvidersCache.readConnectedProvidersCache as unknown as { mockRestore?: () => void }).mockRestore?.()
;(testCoerce<{ mockRestore?: () => void }>(modelAvailability.fetchAvailableModels)).mockRestore?.()
;(testCoerce<{ mockRestore?: () => void }>(connectedProvidersCache.readConnectedProvidersCache)).mockRestore?.()
})
test("returns configured multimodal-looker model when it already matches a vision-capable override", async () => {
+6 -6
View File
@@ -30,7 +30,7 @@ describe("pollSessionUntilIdle", () => {
{ data: { ses_test: { type: "idle" } } },
])
await pollSessionUntilIdle(client as any, "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
await pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
expect(client.session.status).toHaveBeenCalledTimes(3)
})
@@ -43,7 +43,7 @@ describe("pollSessionUntilIdle", () => {
{ data: {} },
])
await pollSessionUntilIdle(client as any, "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
await pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
expect(client.session.status).toHaveBeenCalledTimes(1)
})
@@ -57,7 +57,7 @@ describe("pollSessionUntilIdle", () => {
])
await expect(
pollSessionUntilIdle(client as any, "ses_test", { pollIntervalMs: 10, timeoutMs: 50 })
pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 50 })
).rejects.toThrow("timed out")
})
@@ -69,7 +69,7 @@ describe("pollSessionUntilIdle", () => {
{ error: new Error("API error") },
])
await pollSessionUntilIdle(client as any, "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
await pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
expect(client.session.status).toHaveBeenCalledTimes(1)
})
@@ -85,7 +85,7 @@ describe("pollSessionUntilIdle", () => {
{ data: {} },
])
await pollSessionUntilIdle(client as any, "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
await pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
expect(client.session.status).toHaveBeenCalledTimes(4)
})
@@ -98,7 +98,7 @@ describe("pollSessionUntilIdle", () => {
{ data: {} },
])
await pollSessionUntilIdle(client as any, "ses_test")
await pollSessionUntilIdle(testCoerce(client), "ses_test")
expect(client.session.status).toHaveBeenCalledTimes(1)
})
+35 -35
View File
@@ -14,7 +14,7 @@ describe("look-at tool", () => {
// then should normalize to file_path
test("normalizes path to file_path for LLM compatibility", () => {
const args = { path: "/some/file.png", goal: "analyze" }
const normalized = normalizeArgs(args as any)
const normalized = normalizeArgs(testCoerce(args))
expect(normalized.file_path).toBe("/some/file.png")
expect(normalized.goal).toBe("analyze")
})
@@ -33,7 +33,7 @@ describe("look-at tool", () => {
// then prefer file_path
test("prefers file_path over path when both provided", () => {
const args = { file_path: "/preferred.png", path: "/fallback.png", goal: "test" }
const normalized = normalizeArgs(args as any)
const normalized = normalizeArgs(testCoerce(args))
expect(normalized.file_path).toBe("/preferred.png")
})
@@ -42,7 +42,7 @@ describe("look-at tool", () => {
// then preserve image_data in normalized args
test("preserves image_data when provided", () => {
const args = { image_data: "data:image/png;base64,iVBORw0KGgo=", goal: "analyze" }
const normalized = normalizeArgs(args as any)
const normalized = normalizeArgs(testCoerce(args))
expect(normalized.image_data).toBe("data:image/png;base64,iVBORw0KGgo=")
expect(normalized.file_path).toBeUndefined()
})
@@ -69,7 +69,7 @@ describe("look-at tool", () => {
// when validated
// then clear error message
test("returns error when neither file_path nor image_data provided", () => {
const args = { goal: "analyze" } as any
const args = testCoerce({ goal: "analyze" })
const error = validateArgs(args)
expect(error).toContain("file_path")
expect(error).toContain("image_data")
@@ -88,7 +88,7 @@ describe("look-at tool", () => {
// when validated
// then clear error message
test("returns error when goal is missing", () => {
const args = { file_path: "/some/path.png" } as any
const args = testCoerce({ file_path: "/some/path.png" })
const error = validateArgs(args)
expect(error).toContain("goal")
expect(error).toContain("required")
@@ -156,10 +156,10 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
const toolContext: ToolContext = {
sessionID: "parent-session",
@@ -193,10 +193,10 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
const toolContext: ToolContext = {
sessionID: "parent-session",
@@ -230,10 +230,10 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
const toolContext: ToolContext = {
sessionID: "parent-session",
@@ -291,10 +291,10 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
const toolContext: ToolContext = {
sessionID: "parent-session",
@@ -346,10 +346,10 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
const toolContext: ToolContext = {
sessionID: "parent-session",
@@ -395,10 +395,10 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
const toolContext: ToolContext = {
sessionID: "parent-session",
@@ -437,10 +437,10 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
const toolContext: ToolContext = {
sessionID: "parent-session",
@@ -486,10 +486,10 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
const result = await tool.execute(
{ file_path: "/test/file.png", goal: "analyze" },
@@ -515,10 +515,10 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
const result = await tool.execute(
{ file_path: "/test/file.png", goal: "analyze" },
@@ -539,10 +539,10 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
const result = await tool.execute(
{ file_path: "/test/file.png", goal: "analyze" },
@@ -579,10 +579,10 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
const toolContext: ToolContext = {
sessionID: "parent-session",
@@ -632,10 +632,10 @@ describe("look-at tool", () => {
},
}
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
const toolContext: ToolContext = {
sessionID: "parent-session",
@@ -701,10 +701,10 @@ describe("look-at tool", () => {
test("instructs agent to analyze attached file when Read is disabled (file_path mode)", async () => {
const { mockClient, captured } = captureLastPromptBody()
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
await tool.execute(
{ file_path: "/test/file.png", goal: "describe contents" },
@@ -726,10 +726,10 @@ describe("look-at tool", () => {
test("instructs agent to analyze attached image when image_data is provided", async () => {
const { mockClient, captured } = captureLastPromptBody()
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
await tool.execute(
{ image_data: "data:image/png;base64,iVBORw0KGgo=", goal: "describe image" },
@@ -751,10 +751,10 @@ describe("look-at tool", () => {
test("explicitly warns the agent not to attempt Read when Read is disabled", async () => {
const { mockClient, captured } = captureLastPromptBody()
const tool = createLookAt({
const tool = createLookAt(testCoerce({
client: mockClient,
directory: "/project",
} as any)
}))
await tool.execute(
{ file_path: "/test/file.pdf", goal: "extract text" },
+2 -2
View File
@@ -36,7 +36,7 @@ describe("LSPClient", () => {
const originalSetTimeout = globalThis.setTimeout
globalThis.setTimeout = ((fn: (...args: unknown[]) => void, _ms?: number) => {
fn()
return 0 as unknown as ReturnType<typeof setTimeout>
return testCoerce<ReturnType<typeof setTimeout>>(0)
}) as typeof setTimeout
const server: ResolvedServer = {
@@ -50,7 +50,7 @@ describe("LSPClient", () => {
// Stub protocol output: we only want to assert notifications.
const sendNotificationSpy = spyOn(
client as unknown as { sendNotification: (m: string, p?: unknown) => void },
testCoerce<{ sendNotification: (m: string, p?: unknown) => void }>(client),
"sendNotification"
)
+26 -2
View File
@@ -1,4 +1,4 @@
import { spawn as bunSpawn } from "../../shared/bun-spawn-shim"
import { spawn as bunSpawn, type SpawnedProcess } from "../../shared/bun-spawn-shim"
import { spawn as nodeSpawn, type ChildProcess } from "node:child_process"
import { existsSync, statSync } from "fs"
import { log } from "../../shared/logger"
@@ -127,6 +127,30 @@ function wrapNodeProcess(proc: ChildProcess): UnifiedProcess {
},
}
}
function wrapBunProcess(proc: SpawnedProcess): UnifiedProcess {
return {
stdin: {
write(chunk: Uint8Array | string) {
proc.stdin.write(chunk)
},
},
stdout: {
getReader: () => proc.stdout.getReader(),
},
stderr: {
getReader: () => proc.stderr.getReader(),
},
get exitCode() {
return proc.exitCode
},
exited: proc.exited,
kill(signal?: string) {
proc.kill(signal === "SIGKILL" ? "SIGKILL" : undefined)
},
}
}
export function spawnProcess(
command: string[],
options: { cwd: string; env: Record<string, string | undefined> }
@@ -154,5 +178,5 @@ export function spawnProcess(
cwd: options.cwd,
env: options.env,
})
return proc as unknown as UnifiedProcess
return wrapBunProcess(proc)
}
+5 -5
View File
@@ -448,7 +448,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
// Re-import to get fresh module with mocked isSqliteBackend
const { setStorageClient, getMainSessions } = await import("./storage")
setStorageClient(mockClient as unknown as Parameters<typeof setStorageClient>[0])
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
// when
const sessions = await getMainSessions({ directory: "/test" })
@@ -473,7 +473,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
}))
const { setStorageClient, getAllSessions } = await import("./storage")
setStorageClient(mockClient as unknown as Parameters<typeof setStorageClient>[0])
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
// when
const sessionIDs = await getAllSessions()
@@ -503,7 +503,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
}))
const { setStorageClient, readSessionMessages } = await import("./storage")
setStorageClient(mockClient as unknown as Parameters<typeof setStorageClient>[0])
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
// when
const messages = await readSessionMessages("ses_test")
@@ -531,7 +531,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
}))
const { setStorageClient, readSessionTodos } = await import("./storage")
setStorageClient(mockClient as unknown as Parameters<typeof setStorageClient>[0])
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
// when
const todos = await readSessionTodos("ses_test")
@@ -555,7 +555,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
}))
const { setStorageClient, readSessionMessages } = await import("./storage")
setStorageClient(mockClient as unknown as Parameters<typeof setStorageClient>[0])
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
await expect(readSessionMessages("ses_test")).rejects.toThrow("API error")
})
@@ -205,7 +205,7 @@ describe("skill tool - agent restriction", () => {
// given
const loadedSkills = [createMockSkill("sisyphus-only-skill", { agent: "sisyphus" })]
const tool = createSkillTool({ skills: loadedSkills })
const contextWithoutAgent = { ...mockContext, agent: undefined as unknown as string }
const contextWithoutAgent = { ...mockContext, agent: testCoerce<string>(undefined) }
// when / #then
return expect(tool.execute({ name: "sisyphus-only-skill" }, contextWithoutAgent)).rejects.toThrow(