Skip to content

Commit bc2d501

Browse files
samzongsteipete
authored andcommitted
fix(gateway): preserve lifecycle cleanup
Signed-off-by: samzong <samzong.lu@gmail.com>
1 parent 9d56f4a commit bc2d501

2 files changed

Lines changed: 61 additions & 1 deletion

File tree

src/gateway/server-chat.agent-events.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2050,6 +2050,20 @@ describe("agent event handler", () => {
20502050
expect(fallbackPayload.runId).toBe("run-fallback-client");
20512051
expect(fallbackPayload.data?.phase).toBe("fallback");
20522052

2053+
vi.advanceTimersByTime(100);
2054+
2055+
expect(chatRunState.registry.peek("run-fallback-retry")).toEqual({
2056+
sessionKey: "session-fallback",
2057+
clientRunId: "run-fallback-client",
2058+
});
2059+
expect(
2060+
chatBroadcastCalls(broadcast).some(
2061+
([, payload]) => (payload as { state?: string }).state === "error",
2062+
),
2063+
).toBe(false);
2064+
expect(clearAgentRunContext).not.toHaveBeenCalled();
2065+
expect(agentRunSeq.get("run-fallback-retry")).toBe(3);
2066+
20532067
emitLifecycleEnd(handler, "run-fallback-retry", 4);
20542068

20552069
expect(
@@ -2172,6 +2186,52 @@ describe("agent event handler", () => {
21722186
).toBe(true);
21732187
});
21742188

2189+
it("keeps deferred lifecycle-error cleanup across phase-less lifecycle events", () => {
2190+
vi.useFakeTimers();
2191+
const { broadcast, clearAgentRunContext, agentRunSeq, handler } = createHarness({
2192+
resolveSessionKeyForRun: () => "session-terminal-error",
2193+
lifecycleErrorRetryGraceMs: 100,
2194+
});
2195+
registerAgentRunContext("run-terminal-late-lifecycle", {
2196+
sessionKey: "session-terminal-error",
2197+
});
2198+
2199+
handler({
2200+
runId: "run-terminal-late-lifecycle",
2201+
seq: 1,
2202+
stream: "lifecycle",
2203+
ts: Date.now(),
2204+
data: { phase: "start" },
2205+
});
2206+
handler({
2207+
runId: "run-terminal-late-lifecycle",
2208+
seq: 2,
2209+
stream: "lifecycle",
2210+
ts: Date.now(),
2211+
data: { phase: "error", error: "request timed out" },
2212+
});
2213+
handler({
2214+
runId: "run-terminal-late-lifecycle",
2215+
seq: 3,
2216+
stream: "lifecycle",
2217+
ts: Date.now(),
2218+
data: { msg: "status update" },
2219+
});
2220+
2221+
vi.advanceTimersByTime(100);
2222+
2223+
const finalPayload = chatBroadcastCalls(broadcast).at(-1)?.[1] as {
2224+
state?: string;
2225+
runId?: string;
2226+
errorMessage?: string;
2227+
};
2228+
expect(finalPayload.state).toBe("error");
2229+
expect(finalPayload.runId).toBe("run-terminal-late-lifecycle");
2230+
expect(finalPayload.errorMessage).toContain("request timed out");
2231+
expect(clearAgentRunContext).toHaveBeenCalledWith("run-terminal-late-lifecycle");
2232+
expect(agentRunSeq.has("run-terminal-late-lifecycle")).toBe(false);
2233+
});
2234+
21752235
it("cancels deferred lifecycle-error cleanup when the run restarts", () => {
21762236
vi.useFakeTimers();
21772237
const { broadcast, clearAgentRunContext, agentRunSeq, handler } = createHarness({

src/gateway/server-chat.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,7 @@ export function createAgentEventHandler({
814814
return (evt: AgentEventPayload) => {
815815
const lifecyclePhase =
816816
evt.stream === "lifecycle" && typeof evt.data?.phase === "string" ? evt.data.phase : null;
817-
if (lifecyclePhase === "start") {
817+
if (lifecyclePhase !== null && lifecyclePhase !== "error") {
818818
clearPendingTerminalLifecycleError(evt.runId);
819819
}
820820

0 commit comments

Comments
 (0)