fix(app): stop calling new agent work reopened (#4068)

Task snapshots reuse identities after completed work, so backward status transitions do not prove that an old task resumed. Report active work as started and keep pending work in the current task snapshot instead of inventing a reopened event.
This commit is contained in:
Mohamed Boudra
2026-08-30 10:55:19 +02:00
committed by GitHub
parent 8cf5942a5f
commit 6688c92bc6
14 changed files with 26 additions and 17 deletions
-3
View File
@@ -42,7 +42,6 @@ import {
CircleDot,
Copy,
Plus,
RotateCcw,
TriangleAlertIcon,
Scissors,
MicVocal,
@@ -2290,8 +2289,6 @@ function taskActivityIcon(activity: TaskActivity) {
return CircleDot;
case "completed":
return Check;
case "reopened":
return RotateCcw;
default:
return CheckSquare;
}
-1
View File
@@ -422,7 +422,6 @@ describe("translation resources", () => {
added: "Added",
started: "Started",
completed: "Completed",
reopened: "Reopened",
});
});
-1
View File
@@ -345,7 +345,6 @@ export const ar: TranslationResources = {
added: "أُضيفت",
started: "بدأت",
completed: "اكتملت",
reopened: "أُعيد فتحها",
},
},
compaction: {
-1
View File
@@ -343,7 +343,6 @@ export const en = {
added: "Added",
started: "Started",
completed: "Completed",
reopened: "Reopened",
},
},
compaction: {
-1
View File
@@ -348,7 +348,6 @@ export const es: TranslationResources = {
added: "Añadida",
started: "Iniciada",
completed: "Completada",
reopened: "Reabierta",
},
},
compaction: {
-1
View File
@@ -349,7 +349,6 @@ export const fr: TranslationResources = {
added: "Ajoutée",
started: "Commencée",
completed: "Terminée",
reopened: "Rouverte",
},
},
compaction: {
-1
View File
@@ -348,7 +348,6 @@ export const ja: TranslationResources = {
added: "追加",
started: "開始",
completed: "完了",
reopened: "再開",
},
},
compaction: {
-1
View File
@@ -346,7 +346,6 @@ export const ko: TranslationResources = {
added: "추가됨",
started: "시작됨",
completed: "완료됨",
reopened: "다시 열림",
},
},
compaction: {
-1
View File
@@ -348,7 +348,6 @@ export const ptBR: TranslationResources = {
added: "Adicionada",
started: "Iniciada",
completed: "Concluída",
reopened: "Reaberta",
},
},
compaction: {
-1
View File
@@ -347,7 +347,6 @@ export const ru: TranslationResources = {
added: "Добавлена",
started: "Начата",
completed: "Завершена",
reopened: "Возобновлена",
},
},
compaction: {
-1
View File
@@ -345,7 +345,6 @@ export const zhCN: TranslationResources = {
added: "已添加",
started: "已开始",
completed: "已完成",
reopened: "已重新打开",
},
},
compaction: {
@@ -69,7 +69,7 @@ const TodoEntrySchema = z.strictObject({
const TaskActivitySchema = z.discriminatedUnion("type", [
z.strictObject({ type: z.literal("created"), count: z.number().int().nonnegative() }),
z.strictObject({
type: z.enum(["added", "started", "completed", "reopened"]),
type: z.enum(["added", "started", "completed"]),
task: z.string(),
}),
]);
+24
View File
@@ -1094,6 +1094,30 @@ describe("stream reducer canonical tool calls", () => {
]);
});
it("reports new work after completed tasks without reopening anything", () => {
const state = hydrateStreamState([
{
event: todoTimeline([
{ id: "0", text: "Finish old work", completed: true, status: "completed" },
{ id: "1", text: "Verify old work", completed: true, status: "completed" },
]),
timestamp: new Date("2025-01-01T10:50:00Z"),
},
{
event: todoTimeline([
{ id: "0", text: "Investigate unrelated bug", completed: false, status: "in_progress" },
{ id: "1", text: "Write unrelated test", completed: false, status: "pending" },
]),
timestamp: new Date("2025-01-01T10:51:00Z"),
},
]);
expect(state.flatMap((item) => (item.kind === "todo_list" ? [item.activity] : []))).toEqual([
{ type: "created", count: 2 },
{ type: "started", task: "Investigate unrelated bug" },
]);
});
it("groups consecutive initial Claude TaskCreate snapshots", () => {
const state = hydrateStreamState([
{
+1 -3
View File
@@ -799,7 +799,7 @@ export interface TodoEntry {
export type TaskActivity =
| { type: "created"; count: number }
| { type: "added" | "started" | "completed" | "reopened"; task: string };
| { type: "added" | "started" | "completed"; task: string };
export interface TodoListItem {
kind: "todo_list";
@@ -1307,8 +1307,6 @@ function deriveTaskActivities(
if (before === after) continue;
if (after === "completed") {
activities.push({ type: "completed", task: task.text });
} else if (before === "completed") {
activities.push({ type: "reopened", task: task.text });
} else if (after === "in_progress") {
activities.push({ type: "started", task: task.text });
}