fix: handle embedded agent overflow

This commit is contained in:
Peter Steinberger
2025-12-26 10:16:50 +01:00
parent 8059e83c49
commit d28265cfbe
5 changed files with 255 additions and 63 deletions

View File

@@ -101,6 +101,30 @@ describe("trigger handling", () => {
});
});
it("returns a context overflow fallback when the embedded agent throws", async () => {
await withTempHome(async (home) => {
vi.mocked(runEmbeddedPiAgent).mockRejectedValue(
new Error("Context window exceeded"),
);
const res = await getReplyFromConfig(
{
Body: "hello",
From: "+1002",
To: "+2000",
},
{},
makeCfg(home),
);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toBe(
"⚠️ Context overflow - conversation too long. Starting fresh might help!",
);
expect(runEmbeddedPiAgent).toHaveBeenCalledOnce();
});
});
it("uses heartbeat model override for heartbeat runs", async () => {
await withTempHome(async (home) => {
vi.mocked(runEmbeddedPiAgent).mockResolvedValue({

View File

@@ -996,44 +996,57 @@ export async function getReplyFromConfig(
await startTypingLoop();
}
const runId = crypto.randomUUID();
const runResult = await runEmbeddedPiAgent({
sessionId: sessionIdFinal,
sessionKey,
sessionFile,
workspaceDir,
config: cfg,
skillsSnapshot,
prompt: commandBody,
extraSystemPrompt: groupIntro || undefined,
ownerNumbers: ownerList.length > 0 ? ownerList : undefined,
enforceFinalTag:
provider === "lmstudio" || provider === "ollama" ? true : undefined,
provider,
model,
thinkLevel: resolvedThinkLevel,
verboseLevel: resolvedVerboseLevel,
timeoutMs,
runId,
onPartialReply: opts?.onPartialReply
? async (payload) => {
await startTypingOnText(payload.text);
await opts.onPartialReply?.({
text: payload.text,
mediaUrls: payload.mediaUrls,
});
}
: undefined,
shouldEmitToolResult,
onToolResult: opts?.onToolResult
? async (payload) => {
await startTypingOnText(payload.text);
await opts.onToolResult?.({
text: payload.text,
mediaUrls: payload.mediaUrls,
});
}
: undefined,
});
let runResult: Awaited<ReturnType<typeof runEmbeddedPiAgent>>;
try {
runResult = await runEmbeddedPiAgent({
sessionId: sessionIdFinal,
sessionKey,
sessionFile,
workspaceDir,
config: cfg,
skillsSnapshot,
prompt: commandBody,
extraSystemPrompt: groupIntro || undefined,
ownerNumbers: ownerList.length > 0 ? ownerList : undefined,
enforceFinalTag:
provider === "lmstudio" || provider === "ollama" ? true : undefined,
provider,
model,
thinkLevel: resolvedThinkLevel,
verboseLevel: resolvedVerboseLevel,
timeoutMs,
runId,
onPartialReply: opts?.onPartialReply
? async (payload) => {
await startTypingOnText(payload.text);
await opts.onPartialReply?.({
text: payload.text,
mediaUrls: payload.mediaUrls,
});
}
: undefined,
shouldEmitToolResult,
onToolResult: opts?.onToolResult
? async (payload) => {
await startTypingOnText(payload.text);
await opts.onToolResult?.({
text: payload.text,
mediaUrls: payload.mediaUrls,
});
}
: undefined,
});
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
const isContextOverflow =
/context.*overflow|too large|context window/i.test(message);
defaultRuntime.error(`Embedded agent failed before reply: ${message}`);
return {
text: isContextOverflow
? "⚠️ Context overflow - conversation too long. Starting fresh might help!"
: "⚠️ Agent failed. Check gateway logs.",
};
}
if (
shouldInjectGroupIntro &&