Skip to content

Commit 45dc93b

Browse files
committed
test(opencode): cover the notify-path fallback when a task error is blank
1 parent 1e997a7 commit 45dc93b

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

packages/opencode/test/tool/task.test.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,91 @@ describe("tool.task", () => {
840840
}),
841841
)
842842

843+
background.instance("notifies the parent with a fallback when a background task error is blank", () =>
844+
Effect.gen(function* () {
845+
const { chat, assistant } = yield* seed()
846+
const injected = yield* Deferred.make<SessionPrompt.PromptInput>()
847+
let error = ""
848+
const fakeBackground: BackgroundJob.Interface = {
849+
list: () => Effect.succeed([]),
850+
get: () => Effect.succeed(undefined),
851+
start: (input) =>
852+
Effect.succeed({
853+
id: input.id ?? "task",
854+
type: input.type,
855+
title: input.title,
856+
status: "running",
857+
started_at: 0,
858+
metadata: input.metadata,
859+
}),
860+
extend: () => Effect.succeed(false),
861+
wait: () => Effect.succeed({ timedOut: false, info: { id: "task", type: "task", status: "error", started_at: 0, error } }),
862+
waitForPromotion: () => Effect.never,
863+
promote: () => Effect.succeed(undefined),
864+
cancel: () => Effect.succeed(undefined),
865+
}
866+
const task = yield* TaskTool.pipe(Effect.provideService(BackgroundJob.Service, fakeBackground))
867+
const def = yield* task.init()
868+
const promptOps: TaskPromptOps = {
869+
cancel: () => Effect.void,
870+
resolvePromptParts: (template) => Effect.succeed([{ type: "text" as const, text: template }]),
871+
prompt: (input) => {
872+
if (input.sessionID === chat.id) return Deferred.succeed(injected, input).pipe(Effect.as(reply(input, "injected")))
873+
return Effect.succeed(reply(input, "done"))
874+
},
875+
}
876+
const execute = () =>
877+
def.execute(
878+
{
879+
description: "inspect bug",
880+
prompt: "look into the cache key path",
881+
subagent_type: "general",
882+
background: true,
883+
},
884+
{
885+
sessionID: chat.id,
886+
messageID: assistant.id,
887+
agent: "build",
888+
abort: new AbortController().signal,
889+
extra: { promptOps },
890+
messages: [],
891+
metadata: () => Effect.void,
892+
ask: () => Effect.void,
893+
},
894+
)
895+
896+
yield* execute()
897+
const blank = yield* Deferred.await(injected)
898+
expect(blank.parts[0]?.type).toBe("text")
899+
if (blank.parts[0]?.type === "text") expect(blank.parts[0].text).toContain("Task failed")
900+
901+
error = "real task error"
902+
const injectedReal = yield* Deferred.make<SessionPrompt.PromptInput>()
903+
const realPromptOps = { ...promptOps, prompt: (input: SessionPrompt.PromptInput) => Deferred.succeed(injectedReal, input).pipe(Effect.as(reply(input, "injected"))) }
904+
yield* def.execute(
905+
{
906+
description: "inspect bug",
907+
prompt: "look into the cache key path",
908+
subagent_type: "general",
909+
background: true,
910+
},
911+
{
912+
sessionID: chat.id,
913+
messageID: assistant.id,
914+
agent: "build",
915+
abort: new AbortController().signal,
916+
extra: { promptOps: realPromptOps },
917+
messages: [],
918+
metadata: () => Effect.void,
919+
ask: () => Effect.void,
920+
},
921+
)
922+
const real = yield* Deferred.await(injectedReal)
923+
expect(real.parts[0]?.type).toBe("text")
924+
if (real.parts[0]?.type === "text") expect(real.parts[0].text).toContain("real task error")
925+
}),
926+
)
927+
843928
background.instance("background task completion does not wait for the parent async prompt", () =>
844929
Effect.gen(function* () {
845930
const jobs = yield* BackgroundJob.Service

0 commit comments

Comments
 (0)