diff --git a/src/rlm.ts b/src/rlm.ts index 9e49dc0..51867c6 100644 --- a/src/rlm.ts +++ b/src/rlm.ts @@ -705,7 +705,8 @@ export async function press(query: string, context: Record | un })(); pendingRlmCalls.add(promise); - promise.finally(() => pendingRlmCalls.delete(promise)); + const removeFromPending = () => pendingRlmCalls.delete(promise); + promise.then(removeFromPending, removeFromPending); return promise; }; diff --git a/test/rlm.test.ts b/test/rlm.test.ts index f241fcc..7d11cc4 100644 --- a/test/rlm.test.ts +++ b/test/rlm.test.ts @@ -547,6 +547,33 @@ describe("press", () => { expect(toolResult!.content).toContain("other-component"); }); + it("caught delegation failure does not surface as a phantom error", async () => { + const events: Array<{ type: string; invocationId?: string; error?: string | null }> = []; + const callLLM = mockToolCallLLM([ + tc(`try { await press("child task", undefined, { model: "failer" }) } catch (e) { console.log("caught:", e.message) }`, "t1"), + tc('return "ok"', "t2"), + ]); + + const result = await press("parent task", undefined, { + callLLM, + maxDepth: 3, + models: { + failer: { + callLLM: async () => { + throw new Error("child boom"); + }, + }, + }, + observer: { emit: (event) => events.push(event as { type: string; invocationId?: string; error?: string | null }) }, + }); + + expect(result.answer).toBe("ok"); + const rootIterationEnds = events.filter((e) => e.type === "iteration:end" && e.invocationId === "root"); + for (const event of rootIterationEnds) { + expect(event.error).toBeNull(); + } + }); + it("use + systemPrompt concatenated", async () => { const systemPrompts: string[] = []; const callLLM: CallLLM = async (messages, systemPrompt) => {