Skip to content

Commit 82b8a93

Browse files
authored
fix(orchestration): do not revive idle tasks from status-free progress (#7172)
1 parent cebac35 commit 82b8a93

2 files changed

Lines changed: 39 additions & 0 deletions

File tree

apps/server/src/orchestration/ThreadBackgroundLiveness.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,32 @@ import { describe, expect, it } from "vite-plus/test";
22
import * as ThreadBackgroundLiveness from "./ThreadBackgroundLiveness.ts";
33

44
describe("ThreadBackgroundLiveness", () => {
5+
it("does not let status-free progress restart an idle task", () => {
6+
const liveness = ThreadBackgroundLiveness.make();
7+
liveness.recordTaskLiveness({
8+
threadId: "thread",
9+
taskId: "task",
10+
taskType: undefined,
11+
status: undefined,
12+
kind: "started",
13+
});
14+
liveness.recordTaskLiveness({
15+
threadId: "thread",
16+
taskId: "task",
17+
taskType: undefined,
18+
status: "idle",
19+
kind: "updated",
20+
});
21+
liveness.recordTaskLiveness({
22+
threadId: "thread",
23+
taskId: "task",
24+
taskType: undefined,
25+
status: undefined,
26+
kind: "progress",
27+
});
28+
expect(liveness.getThreadBackgroundLiveness("thread")).toBeNull();
29+
});
30+
531
it("agents present as working; monitors as monitoring; agents win", () => {
632
const liveness = ThreadBackgroundLiveness.make();
733
const threadId = "t-live-1";

apps/server/src/orchestration/ThreadBackgroundLiveness.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,19 @@ export function make(): ThreadBackgroundLivenessService["Service"] {
130130
return;
131131
}
132132

133+
// Status-free progress is a description tick, not a restart. A delayed
134+
// progress event after idle must not put the task back in the live set
135+
// (#7128).
136+
if (input.kind === "progress" && input.status === undefined) {
137+
const existing = stateByThreadId.get(input.threadId);
138+
const stillLive =
139+
existing !== undefined &&
140+
(existing.agents.has(input.taskId) || existing.monitors.has(input.taskId));
141+
if (!stillLive) {
142+
return;
143+
}
144+
}
145+
133146
drop(input.threadId, input.taskId);
134147
const state = stateFor(input.threadId);
135148
const bucket =

0 commit comments

Comments
 (0)