fix: return recovery action descriptors (#174)

Co-authored-by: AgentRun Codex <agentrun-codex@users.noreply.github.com>
This commit is contained in:
Lyon
2026-06-12 01:20:02 +08:00
committed by GitHub
parent 1a9b6debbb
commit 216209ca95
11 changed files with 298 additions and 74 deletions
+51 -10
View File
@@ -165,6 +165,7 @@ async function queueTaskSupervisor(store: AgentRunStore, task: JsonRecord): Prom
const lastActivity = asJsonRecord(liveness?.lastActivity ?? liveness?.lastCommandActivity);
const timeoutBudget = asJsonRecord(liveness?.timeoutBudget);
const terminalClassification = asJsonRecord(result.terminalClassification ?? liveness?.terminalClassification);
const lease = asJsonRecord(liveness?.lease);
return {
runId: stringJsonValue(result.runId),
commandId: stringJsonValue(result.commandId),
@@ -176,8 +177,13 @@ async function queueTaskSupervisor(store: AgentRunStore, task: JsonRecord): Prom
phase: stringJsonValue(liveness?.phase),
active: liveness?.active === true,
lastSeq: numberJsonValue(liveness?.lastSeq ?? result.lastSeq),
lastEventAt: stringJsonValue(liveness?.lastEventAt),
lastEventAgeMs: numberJsonValue(liveness?.lastEventAgeMs),
lastActivity: lastActivity ? compactActivity(lastActivity) : null,
timeoutBudget: timeoutBudget ? compactTimeoutBudget(timeoutBudget) : null,
lease: lease ? compactLease(lease) : null,
leaseRemainingMs: numberJsonValue(lease?.leaseRemainingMs),
leaseExpired: lease?.leaseExpired === true,
recoveryActions: compactRecoveryActions(liveness?.recoveryActions),
valuesPrinted: false,
};
@@ -220,6 +226,16 @@ function compactTimeoutBudget(budget: JsonRecord): JsonRecord {
};
}
function compactLease(lease: JsonRecord): JsonRecord {
return {
claimedBy: stringJsonValue(lease.claimedBy),
leaseExpiresAt: stringJsonValue(lease.leaseExpiresAt),
leaseExpired: lease.leaseExpired === true,
leaseRemainingMs: numberJsonValue(lease.leaseRemainingMs),
valuesPrinted: false,
};
}
function compactTerminalClassification(record: JsonRecord): JsonRecord {
return {
category: stringJsonValue(record.category),
@@ -248,13 +264,20 @@ function compactRecoveryActions(value: JsonValue | undefined): JsonValue[] {
if (!action) return { action: "unknown", valuesPrinted: false };
return {
action: stringJsonValue(action.action),
operation: stringJsonValue(action.operation),
resourceKind: stringJsonValue(action.resourceKind),
resourceName: stringJsonValue(action.resourceName),
reason: stringJsonValue(action.reason),
reasonHint: boundedJsonString(action.reasonHint, 220),
reasonRequired: action.reasonRequired === true,
inputKind: stringJsonValue(action.inputKind),
runId: stringJsonValue(action.runId),
commandId: stringJsonValue(action.commandId),
runnerJobId: stringJsonValue(action.runnerJobId),
sessionId: stringJsonValue(action.sessionId),
afterSeq: numberJsonValue(action.afterSeq),
command: boundedJsonString(action.command, 220),
hint: boundedJsonString(action.hint, 220),
limit: numberJsonValue(action.limit),
failureMessage: boundedJsonString(action.failureMessage, 220),
valuesPrinted: false,
};
});
@@ -710,7 +733,7 @@ function sessionSendPlan(sessionId: string, decision: "steer" | "turn", active:
activeBefore: active ? activeBeforeSummary(active) : null,
request,
...(runBody ? { run: { bodyBytes: jsonByteLength(runBody), sessionRef: summarizeSendSessionRef(runBody), valuesPrinted: false } } : {}),
next: { confirm: `./scripts/agentrun sessions send ${sessionId} --prompt-stdin`, note: "Remove --dry-run to perform the mutation. Manager will decide internal steer vs turn from durable session state." },
next: { confirm: managerActionDescriptor({ action: "send-session", operation: "send", resourceKind: "session", resourceName: sessionId, sessionId, inputKind: "prompt" }), note: "Remove --dry-run to perform the mutation. Manager will decide internal steer vs turn from durable session state." },
valuesPrinted: false,
};
}
@@ -727,13 +750,31 @@ function sessionSendResponse(input: { sessionId: string; decision: "steer" | "tu
command: input.command as unknown as JsonRecord,
runnerJob: input.runnerJob,
activeBefore: input.activeBefore ? activeBeforeSummary(input.activeBefore) : null,
pollCommands: {
show: `./scripts/agentrun sessions show ${input.sessionId} --reader-id cli`,
trace: `./scripts/agentrun sessions trace ${input.sessionId} --after-seq 0 --limit 100`,
output: `./scripts/agentrun sessions output ${input.sessionId} --after-seq 0 --limit 100`,
read: `./scripts/agentrun sessions read ${input.sessionId} --reader-id cli`,
cancel: `./scripts/agentrun sessions cancel ${input.sessionId}`,
},
pollActions: [
managerActionDescriptor({ action: "inspect-session", operation: "describe", resourceKind: "session", resourceName: input.sessionId, sessionId: input.sessionId, readerId: "cli" }),
managerActionDescriptor({ action: "poll-trace", operation: "events", resourceKind: "run", resourceName: input.run.id, runId: input.run.id, commandId: input.command.id, sessionId: input.sessionId, afterSeq: 0, limit: 100 }),
managerActionDescriptor({ action: "poll-output", operation: "logs", resourceKind: "session", resourceName: input.sessionId, runId: input.run.id, commandId: input.command.id, sessionId: input.sessionId, afterSeq: 0, limit: 100 }),
managerActionDescriptor({ action: "read-session", operation: "read", resourceKind: "session", resourceName: input.sessionId, sessionId: input.sessionId, readerId: "cli" }),
managerActionDescriptor({ action: "cancel-session", operation: "cancel", resourceKind: "session", resourceName: input.sessionId, sessionId: input.sessionId, reasonRequired: true }),
],
valuesPrinted: false,
};
}
function managerActionDescriptor(input: { action: string; operation: string; resourceKind: string; resourceName: string; runId?: string | null; commandId?: string | null; sessionId?: string | null; afterSeq?: number | null; limit?: number | null; readerId?: string | null; reasonRequired?: boolean; inputKind?: string | null }): JsonRecord {
return {
action: input.action,
operation: input.operation,
resourceKind: input.resourceKind,
resourceName: input.resourceName,
runId: input.runId ?? null,
commandId: input.commandId ?? null,
sessionId: input.sessionId ?? null,
...(input.afterSeq !== undefined ? { afterSeq: input.afterSeq } : {}),
...(input.limit !== undefined ? { limit: input.limit } : {}),
...(input.readerId ? { readerId: input.readerId } : {}),
...(input.reasonRequired === true ? { reasonRequired: true } : {}),
...(input.inputKind ? { inputKind: input.inputKind } : {}),
valuesPrinted: false,
};
}