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