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:
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user