Show live task progress while agents work (#3227)

* feat(agents): surface live task progress

Keep current task state above the composer and turn task snapshots into semantic timeline activity. Normalize provider task protocols while preserving genuine plan flows.

* fix(agents): admit tasks through stream sequencing

* test(agents): expect normalized task status
This commit is contained in:
Mohamed Boudra
2026-08-11 18:23:30 +02:00
committed by GitHub
parent b2ff359b60
commit db6520bf36
37 changed files with 1342 additions and 60 deletions
+9 -1
View File
@@ -339,12 +339,20 @@ export interface CompactionTimelineItem {
preTokens?: number;
}
export interface AgentTaskItem {
text: string;
completed: boolean;
id?: string;
status?: "pending" | "in_progress" | "completed";
activeForm?: string;
}
export type AgentTimelineItem =
| { type: "user_message"; text: string; messageId?: string; clientMessageId?: string }
| { type: "assistant_message"; text: string; messageId?: string }
| { type: "reasoning"; text: string }
| ToolCallTimelineItem
| { type: "todo"; items: { text: string; completed: boolean }[] }
| { type: "todo"; items: AgentTaskItem[] }
| { type: "error"; message: string }
| CompactionTimelineItem;
+3
View File
@@ -659,6 +659,9 @@ export const AgentTimelineItemPayloadSchema: z.ZodType<AgentTimelineItem, unknow
z.object({
text: z.string(),
completed: z.boolean(),
id: z.string().optional(),
status: z.enum(["pending", "in_progress", "completed"]).optional(),
activeForm: z.string().optional(),
}),
),
}),
@@ -117,6 +117,40 @@ describe("wire schema compatibility", () => {
});
});
test("task progress fields are optional on the wire", () => {
expect(
AgentTimelineItemPayloadSchema.parse({
type: "todo",
items: [{ text: "Legacy task", completed: false }],
}),
).toEqual({ type: "todo", items: [{ text: "Legacy task", completed: false }] });
expect(
AgentTimelineItemPayloadSchema.parse({
type: "todo",
items: [
{
id: "task-1",
text: "Current task",
activeForm: "Working on current task",
status: "in_progress",
completed: false,
},
],
}),
).toEqual({
type: "todo",
items: [
{
id: "task-1",
text: "Current task",
activeForm: "Working on current task",
status: "in_progress",
completed: false,
},
],
});
});
test("sub_agent tool-call payload still parses against the v0.1.65-beta.3 schema", () => {
const parsed = LegacySubAgentToolCallSchema.parse({
type: "tool_call",