fix(core,web): retry transport and quota LLM errors, disable dead sessions on auth failure (#82)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c369e089a7
commit
3d3495528c
54 files changed
+2278
-161
No files matched your search
@@ -399,7 +399,7 @@ describe("context compaction", () => {
|
||||
environment: fakeEnvironment,
|
||||
compaction: settings(),
|
||||
createLLM: () => llm1,
|
||||
maxReconnects: 1,
|
||||
compactionMaxReconnects: 1,
|
||||
reconnectBackoffMs: 1,
|
||||
});
|
||||
|
||||
@@ -411,6 +411,52 @@ describe("context compaction", () => {
|
||||
expect(payloadTypes(llm1.calls[2]!)).toEqual(["text"]);
|
||||
});
|
||||
|
||||
it("the compaction loop uses its own cap, not the shared maxReconnects ladder", async () => {
|
||||
// Compaction failure has graceful semantics (the original context is kept, compaction
|
||||
// retries on the next trigger), so it fails fast: with compactionMaxReconnects=2, the
|
||||
// compaction request runs 1+2 attempts and gives up — even though maxReconnects is far
|
||||
// larger and would have kept the session stalled through the full exponential ladder.
|
||||
const llm1 = new ScriptedLLM(
|
||||
[
|
||||
{ messages: [assistantText("answer"), usage(150, 150)] },
|
||||
{ messages: [], outcome: { status: "timeout" } },
|
||||
{ messages: [], outcome: { status: "timeout" } },
|
||||
{ messages: [], outcome: { status: "timeout" } },
|
||||
// Never reached: the compaction cap stops at 3 compaction attempts in total.
|
||||
{ messages: [assistantText("[summary]late[/summary]")] },
|
||||
],
|
||||
"llm1",
|
||||
);
|
||||
const recorded: OmniMessage[] = [];
|
||||
const engine = new ContextEngine({
|
||||
llm: llm1,
|
||||
environment: fakeEnvironment,
|
||||
compaction: settings(),
|
||||
createLLM: () => llm1,
|
||||
maxReconnects: 8,
|
||||
compactionMaxReconnects: 2,
|
||||
reconnectBackoffMs: 1,
|
||||
trace: {
|
||||
write: async (m) => {
|
||||
recorded.push(m);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const out = await collect(engine.run([userText("go")], { approve: allowAll }));
|
||||
const events = compactionEvents(out);
|
||||
expect(events[1]).toMatchObject({ type: "compaction_end", status: "failed" });
|
||||
// 1 turn request + 3 compaction attempts (initial + compactionMaxReconnects retries).
|
||||
expect(llm1.calls).toHaveLength(4);
|
||||
// The Trace-written compaction request_ends announce the planned backoff under the
|
||||
// COMPACTION cap (base 1ms: 1, then 2), with none on the final failure — these events
|
||||
// are never streamed, so the value lands in the Trace record only.
|
||||
const retryPlans = recorded
|
||||
.filter((m) => (m.payload as { type?: string }).type === "request_end")
|
||||
.map((m) => (m.payload as { retry_in_ms?: number }).retry_in_ms);
|
||||
expect(retryPlans).toEqual([undefined, 1, 2, undefined]);
|
||||
});
|
||||
|
||||
it("session turns reaching (==) the threshold compact at task end — no waiting for the next task", async () => {
|
||||
const llm1 = new ScriptedLLM(
|
||||
[
|
||||
|
||||
Reference in new issue
Block a user