fix: preserve investigation execution history by round

This commit is contained in:
2026-10-30 17:07:53 +08:00
parent 1ee21d1c7f
commit 185bf31446
16 changed files with 830 additions and 32 deletions
@@ -28,6 +28,7 @@ const operationalTaskRunSchema = z.object({
status: z.enum(["queued", "claimed", "running", "succeeded", "failed", "timed_out", "cancelled"]),
revision: z.number().int().positive(),
agent_session_id: z.string().min(1).nullable(),
agent_instance_id: z.string().min(1).nullable().optional(),
lease_expires_at: workbenchDateTimeSchema.nullable(),
heartbeat_at: workbenchDateTimeSchema.nullable(),
started_at: workbenchDateTimeSchema.nullable(),
@@ -39,6 +40,10 @@ const operationalTaskRunSchema = z.object({
created_at: workbenchDateTimeSchema,
updated_at: workbenchDateTimeSchema
}).strict();
const operationalTaskRunPageSchema = z.object({
items: z.array(operationalTaskRunSchema),
next_cursor: z.string().min(1).nullable()
}).strict();
const taskSummarySchema = z.object({
project_id: z.string().uuid(),
task_id: z.string().uuid(),
@@ -359,6 +364,11 @@ const taskDataSnapshotSchema = z.object({
export type OperationalTaskSummary = z.infer<typeof taskSummarySchema>;
export type OperationalTask = z.infer<typeof operationalTaskSchema>;
export type OperationalTaskRun = z.infer<typeof operationalTaskRunSchema>;
export type TaskExecutionHistoryTarget = {
executionGeneration: number | null;
sessionId: string;
};
export type OperationalTaskPlan = z.infer<typeof planInputSchema>;
export type OperationalTaskAction = z.infer<typeof actionSchema>;
export type OperationalTaskAccessRequest = z.infer<typeof accessRequestSchema>;
@@ -423,6 +433,18 @@ export async function fetchOperationalTaskReports(taskId: string, offset: number
));
}
export async function fetchOperationalTaskRuns(taskId: string, getAccessToken?: WorkbenchAccess) {
const runs: OperationalTaskRun[] = [];
const limit = 100;
for (let offset = 0; ; offset += limit) {
const page = operationalTaskRunPageSchema.parse(await operationalTaskRequest(
`/operational-tasks/${encodeURIComponent(taskId)}/runs?limit=${limit}&offset=${offset}`, getAccessToken,
));
runs.push(...page.items);
if (page.items.length < limit) return runs;
}
}
export async function fetchOperationalTaskPresentationCursor(taskId: string, getAccessToken?: WorkbenchAccess, signal?: AbortSignal) {
return investigationPresentationCursorSchema.parse(await operationalTaskRequest(
`/operational-tasks/${encodeURIComponent(taskId)}/presentation-cursor`, getAccessToken, { signal }