fix(agentrun): 添加队列任务重试资源命令

This commit is contained in:
Codex
2026-07-12 02:47:00 +02:00
parent db75577b8f
commit 9276e751f5
6 changed files with 373 additions and 11 deletions
+11 -4
View File
@@ -49,7 +49,7 @@ import { cleanupLocalPostgres, cleanupReleasedPvs, cleanupRunners, cleanupRuns,
export function agentRunHelp(): unknown {
return {
command: "agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|send|explain",
command: "agentrun get|describe|events|logs|result|ack|cancel|retry|dispatch|create|apply|send|explain",
output: "human by default; use -o json|yaml or --raw for machine/debug output",
usage: [
"bun scripts/cli.ts agentrun get tasks --queue commander --limit 20",
@@ -62,6 +62,8 @@ export function agentRunHelp(): unknown {
"bun scripts/cli.ts agentrun result run/<runId> --command <commandId>",
"bun scripts/cli.ts agentrun ack task/<taskId> --reader-id cli",
"bun scripts/cli.ts agentrun cancel task/<taskId> --reason <text> --dry-run",
"bun scripts/cli.ts agentrun retry task/<taskId> --idempotency-key <key> --reason <text> --dry-run",
"bun scripts/cli.ts agentrun get attempts --task <taskId> --limit 20",
"bun scripts/cli.ts agentrun dispatch task/<taskId>",
"bun scripts/cli.ts agentrun create task --aipod Artificer --prompt-stdin --idempotency-key <key>",
"bun scripts/cli.ts agentrun apply -f - --dry-run",
@@ -93,9 +95,9 @@ export function agentRunHelp(): unknown {
"bun scripts/cli.ts agentrun git-mirror status --full",
"bun scripts/cli.ts agentrun git-mirror legacy-ops --help",
],
resources: ["task/qt", "run", "command/cmd", "runnerjob/rjob", "session/ses", "aipodspec/aps"],
resources: ["task/qt", "attempt", "run", "command/cmd", "runnerjob/rjob", "session/ses", "aipodspec/aps"],
description: "Operate AgentRun through Kubernetes-style resource verbs. Human output is compact by default; -o json|yaml returns the UniDesk render-only client schema, --raw exposes the REST envelope, and --node/--lane targets a YAML-declared runtime lane.",
legacyCompatibility: "queue/runs/commands/runner/sessions/aipod-specs remain as compatibility groups backed by direct HTTP; new commander work should use get/describe/events/logs/result/ack/cancel/dispatch/create/apply/send. sessions turn/steer are removed; use send only.",
legacyCompatibility: "queue/runs/commands/runner/sessions/aipod-specs remain as compatibility groups backed by direct HTTP; new commander work should use get/describe/events/logs/result/ack/cancel/retry/dispatch/create/apply/send. sessions turn/steer are removed; use send only.",
cicdBoundary: "NC01 PaC consumer 仅由 GitHub PR merge 自动触发;默认帮助只给 status/history。legacy 与平台维护写入口只在显式 scoped help 中展示。",
};
}
@@ -238,6 +240,7 @@ export function isResourceVerb(value: string | undefined): value is AgentRunReso
|| value === "result"
|| value === "ack"
|| value === "cancel"
|| value === "retry"
|| value === "dispatch"
|| value === "create"
|| value === "apply"
@@ -257,11 +260,12 @@ export function agentRunHelpText(args: string[]): string {
return [
"Usage: bun scripts/cli.ts agentrun get <resource> [options]",
"",
"Resources: tasks|sessions|runs|commands|runnerjobs|aipodspecs",
"Resources: tasks|attempts|sessions|runs|commands|runnerjobs|aipodspecs",
"Output: table by default; use -o wide|name|json|yaml.",
"",
"Examples:",
" bun scripts/cli.ts agentrun get tasks --queue commander --limit 20",
" bun scripts/cli.ts agentrun get attempts --task <taskId> --limit 20",
" bun scripts/cli.ts agentrun get sessions --limit 20",
" bun scripts/cli.ts agentrun get tasks -o json",
].join("\n");
@@ -293,6 +297,9 @@ export function agentRunHelpText(args: string[]): string {
if (verb === "cancel") {
return "Usage: bun scripts/cli.ts agentrun cancel task/<taskId>|session/<sessionId>|run/<runId>|command/<commandId> --reason <text> [--run <runId>] [--dry-run]";
}
if (verb === "retry") {
return "Usage: bun scripts/cli.ts agentrun retry task/<taskId> --idempotency-key <key> --reason <text> [--dry-run] [--full] [-o json|yaml] [--raw]";
}
if (verb === "dispatch") {
return "Usage: bun scripts/cli.ts agentrun dispatch task/<taskId>";
}
+160
View File
@@ -146,6 +146,125 @@ export function renderResourceResult(command: string, raw: Record<string, unknow
return renderedCliResult(raw.ok !== false, command, renderResourceTable(items, options.output === "wide"));
}
export function renderQueueAttemptList(command: string, raw: Record<string, unknown>, options: AgentRunResourceOptions, requestedTaskId: string, items: Record<string, unknown>[]): RenderedCliResult {
if (options.raw) return renderMachine(command, raw, "json", raw.ok !== false);
const data = record(innerData(raw));
const taskId = stringOrNull(data.taskId) ?? requestedTaskId;
const cursor = typeof data.cursor === "number" ? String(data.cursor) : stringOrNull(data.cursor);
const rawItems = arrayRecords(data.items);
if (options.full) {
return renderMachine(command, {
kind: "AttemptList",
taskId,
count: data.count ?? rawItems.length,
cursor,
items: rawItems,
}, options.output === "yaml" ? "yaml" : "json", raw.ok !== false);
}
const payload = { kind: "AttemptList", taskId, count: items.length, cursor, items };
if (options.output === "json" || options.output === "yaml") return renderMachine(command, payload, options.output, raw.ok !== false);
if (options.output === "name") return renderedCliResult(raw.ok !== false, command, items.map((item) => `attempt/${String(item.name ?? "")}`).join("\n"));
if (items.length === 0) return renderedCliResult(raw.ok !== false, command, `No attempt resources found for task/${taskId}.`);
const lines = [
`Attempts for task/${taskId}`,
renderTable(["NAME", "INDEX", "STATE", "PREVIOUS", "RUN", "CMD", "RJOB", "AGE", "FAILURE", "REASON"], items.map((item) => [
resourceName(item),
displayValue(item.retryIndex),
displayValue(item.state),
shortId(stringOrDash(item.previousAttemptId)),
shortId(stringOrDash(item.runId)),
shortId(stringOrDash(item.commandId)),
shortId(stringOrDash(item.runnerJobId)),
displayValue(item.age),
queueAttemptFailureSummary(item),
truncateOneLine(displayValue(item.reason), 48),
])),
];
if (cursor !== null) lines.push(`Next: ${nextQueueAttemptPageCommand(command, cursor, options.limit)}`);
return renderedCliResult(raw.ok !== false, command, lines.join("\n"));
}
export function renderQueueRetrySummary(command: string, raw: Record<string, unknown>, options: AgentRunResourceOptions, requestedTaskId: string): RenderedCliResult {
if (options.raw) return renderMachine(command, raw, "json", raw.ok !== false);
const data = record(innerData(raw));
const task = record(data.task);
const attempt = record(data.attempt);
const previousAttempt = record(data.previousAttempt);
const allowedTransition = record(data.allowedTransition);
const taskId = stringOrNull(task.id) ?? requestedTaskId;
if (options.full) {
return renderMachine(command, { kind: "TaskRetry", taskId, ...data }, options.output === "yaml" ? "yaml" : "json", raw.ok !== false);
}
const normalizedAttempt = compactQueueRetryAttempt(attempt);
const normalizedPreviousAttempt = compactQueueRetryAttempt(previousAttempt);
const run = record(data.run);
const runId = stringOrNull(run.id) ?? stringOrNull(attempt.runId);
const commandResource = record(data.command);
const commandId = stringOrNull(commandResource.id) ?? stringOrNull(attempt.commandId);
const runnerJob = record(data.runnerJob);
const runnerJobId = stringOrNull(runnerJob.id) ?? stringOrNull(attempt.runnerJobId);
const payload = {
kind: "TaskRetry",
taskId,
dryRun: options.dryRun,
mutation: data.mutation === true,
idempotentReplay: data.idempotentReplay === true,
task: pickCompact(task, ["id", "state", "queue", "lane", "payloadHash", "updatedAt"]),
attempt: normalizedAttempt,
previousAttempt: normalizedPreviousAttempt,
allowedTransition,
run: compactQueueRetryIdentity(run, ["id", "status", "terminalStatus", "createdAt", "updatedAt"]),
command: compactQueueRetryIdentity(commandResource, ["id", "type", "state", "terminalStatus", "createdAt", "updatedAt"]),
runnerJob: compactQueueRetryIdentity(runnerJob, ["id", "state", "phase", "terminalStatus", "attemptId", "createdAt", "updatedAt"]),
};
if (options.output === "json" || options.output === "yaml") return renderMachine(command, payload, options.output, raw.ok !== false);
const retryIndex = attempt.retryIndex ?? allowedTransition.retryIndex;
const attemptId = stringOrNull(attempt.attemptId);
const previousAttemptId = stringOrNull(previousAttempt.attemptId) ?? stringOrNull(allowedTransition.previousAttemptId);
const lines = [
`${options.dryRun ? "Task retry validated" : "Task retry submitted"}: task/${taskId}`,
`OK: ${String(raw.ok !== false)}`,
`DryRun: ${String(options.dryRun)}`,
`Mutation: ${String(data.mutation === true)}`,
`IdempotentReplay: ${String(data.idempotentReplay === true)}`,
`Transition: ${displayValue(allowedTransition.from)} -> ${displayValue(allowedTransition.to)} retryIndex=${displayValue(retryIndex)}`,
`Attempt: ${attemptId === null ? "planned" : `attempt/${shortId(attemptId)}`} state=${displayValue(attempt.state ?? allowedTransition.to)}`,
`PreviousAttempt: ${previousAttemptId === null ? "-" : `attempt/${shortId(previousAttemptId)}`}`,
];
if (runId !== null) lines.push(`Run: run/${shortId(runId)}`);
if (commandId !== null) lines.push(`Command: command/${shortId(commandId)}`);
if (runnerJobId !== null) lines.push(`RunnerJob: runnerjob/${shortId(runnerJobId)}`);
const next = [
`bun scripts/cli.ts agentrun get attempts --task ${taskId}`,
`bun scripts/cli.ts agentrun describe task/${taskId}`,
runId === null ? null : `bun scripts/cli.ts agentrun events run/${runId} --after-seq 0 --limit 100`,
runId === null || commandId === null ? null : `bun scripts/cli.ts agentrun describe command/${commandId} --run ${runId}`,
].filter((value): value is string => value !== null);
lines.push("", "Next:", ...next.map((value) => ` ${value}`));
return renderedCliResult(raw.ok !== false, command, lines.join("\n"));
}
function compactQueueRetryAttempt(value: Record<string, unknown>): Record<string, unknown> | null {
if (Object.keys(value).length === 0) return null;
const attempt = pickCompact(value, ["attemptId", "taskId", "retryIndex", "state", "idempotencyKey", "reason", "payloadHash", "previousAttemptId", "runId", "commandId", "runnerJobId", "sessionId", "sessionPath", "failureKind", "failureMessage", "createdAt", "updatedAt", "activatedAt", "terminalAt"]);
attempt.reason = boundedQueueAttemptText(attempt.reason, 240);
attempt.failureMessage = boundedQueueAttemptText(attempt.failureMessage, 320);
attempt.sessionPath = boundedQueueAttemptText(attempt.sessionPath, 240);
return attempt;
}
function compactQueueRetryIdentity(value: Record<string, unknown>, keys: string[]): Record<string, unknown> | null {
return Object.keys(value).length === 0 ? null : pickCompact(value, keys);
}
function nextQueueAttemptPageCommand(command: string, cursor: string, limit: number): string {
const base = command
.replace(/\s+--cursor(?:=|\s+)\S+/gu, "")
.replace(/\s+--limit(?:=|\s+)\S+/gu, "")
.trim();
return `bun scripts/cli.ts ${base} --cursor ${cursor} --limit ${limit}`;
}
export function renderDescribe(command: string, raw: Record<string, unknown>, options: AgentRunResourceOptions, ref: AgentRunResourceRef, text: string): RenderedCliResult {
if (options.raw) return renderMachine(command, raw, "json", raw.ok !== false);
if (options.output === "json" || options.output === "yaml") {
@@ -355,6 +474,7 @@ export function parseResourceKind(raw: string | undefined): AgentRunResourceKind
if (raw === undefined) return null;
const value = raw.toLowerCase().replace(/s$/u, "");
if (value === "task" || value === "qt" || value === "queue" || value === "queuetask") return "task";
if (value === "attempt") return "attempt";
if (value === "run") return "run";
if (value === "command" || value === "cmd") return "command";
if (value === "runnerjob" || value === "runner-job" || value === "rjob" || value === "job") return "runnerjob";
@@ -432,6 +552,46 @@ export function normalizeTaskItems(data: unknown, options: AgentRunResourceOptio
});
}
export function normalizeQueueAttemptItems(data: unknown): Record<string, unknown>[] {
const items = arrayRecords(record(data).items ?? data);
return items.map((item) => ({
kind: "attempt",
name: item.attemptId,
attemptId: item.attemptId,
taskId: item.taskId,
retryIndex: item.retryIndex,
state: item.state,
idempotencyKey: item.idempotencyKey,
reason: boundedQueueAttemptText(item.reason, 240),
payloadHash: item.payloadHash,
previousAttemptId: item.previousAttemptId,
runId: item.runId,
commandId: item.commandId,
runnerJobId: item.runnerJobId,
sessionId: item.sessionId,
sessionPath: boundedQueueAttemptText(item.sessionPath, 240),
failureKind: item.failureKind,
failureMessage: boundedQueueAttemptText(item.failureMessage, 320),
createdAt: item.createdAt,
updatedAt: item.updatedAt,
activatedAt: item.activatedAt,
terminalAt: item.terminalAt,
age: relativeAge(stringOrNull(item.updatedAt) ?? stringOrNull(item.createdAt)),
}));
}
function boundedQueueAttemptText(value: unknown, maxChars: number): string | null {
const text = stringOrNull(value);
return text === null ? null : truncateOneLine(text, maxChars);
}
function queueAttemptFailureSummary(item: Record<string, unknown>): string {
const kind = stringOrNull(item.failureKind);
const message = stringOrNull(item.failureMessage);
if (kind === null && message === null) return "-";
return truncateOneLine(kind === null ? message ?? "-" : message === null ? kind : `${kind}: ${message}`, 72);
}
export function taskListState(options: AgentRunResourceOptions): string {
const requested = options.state?.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
return requested?.[0] ?? "running";
+35 -4
View File
@@ -37,7 +37,7 @@ import type { AgentRunResourceOptions, AgentRunResourceRef, AgentRunResourceVerb
import { agentRunDryRunPlan } from "./config";
import { isHelpArg, renderAgentRunHelp } from "./entry";
import { agentRunExplain, arrayRecords, shortId } from "./options";
import { agentRunCancelAuthorityDisclosure, agentRunCancelCascadeScope, agentRunCancelFencingDisclosure, agentRunCancelRunnerAbortDisclosure, compactTaskDescriptionPayload, innerData, normalizeAipodSpecItems, normalizeAttemptResources, normalizeEventItems, normalizeLogItems, normalizeRunnerJobItems, normalizeSessionItems, normalizeSingleCommand, normalizeTaskItems, parseResourceKind, parseResourceRef, renderDescribe, renderEventLike, renderGenericDescription, renderMachine, renderMutationSummary, renderResourceResult, renderResultSummary, renderTaskDescription, renderedCliResult, requiredContext, rerunWithoutDryRun, resolveAgentRunCancelPolicyTarget, resourceApply, resourceCreate, resourceDispatch, resourceSessionPromptCommand, taskListState, unwrapTaskDetail } from "./render";
import { agentRunCancelAuthorityDisclosure, agentRunCancelCascadeScope, agentRunCancelFencingDisclosure, agentRunCancelRunnerAbortDisclosure, compactTaskDescriptionPayload, innerData, normalizeAipodSpecItems, normalizeAttemptResources, normalizeEventItems, normalizeLogItems, normalizeQueueAttemptItems, normalizeRunnerJobItems, normalizeSessionItems, normalizeSingleCommand, normalizeTaskItems, parseResourceKind, parseResourceRef, renderDescribe, renderEventLike, renderGenericDescription, renderMachine, renderMutationSummary, renderQueueAttemptList, renderQueueRetrySummary, renderResourceResult, renderResultSummary, renderTaskDescription, renderedCliResult, requiredContext, rerunWithoutDryRun, resolveAgentRunCancelPolicyTarget, resourceApply, resourceCreate, resourceDispatch, resourceSessionPromptCommand, taskListState, unwrapTaskDetail } from "./render";
import { AgentRunRestError, renderAgentRunRestError, resolveAgentRunRestTarget, runAgentRunRestCommand, withAgentRunRestTarget } from "./rest-bridge";
import { runnerJobObservationScript, type RunnerJobObservationIdentity } from "./runner-observation";
import { capture, captureJsonPayload, compactCapture, nonNegativeIntegerOrNull, record, stringOrNull } from "./utils";
@@ -45,12 +45,13 @@ import { capture, captureJsonPayload, compactCapture, nonNegativeIntegerOrNull,
export function agentRunGetKindHelp(kindRaw: string): string {
const kind = parseResourceKind(kindRaw);
if (kind === "task") return "Usage: bun scripts/cli.ts agentrun get tasks [--queue commander] [--state running,pending,completed,failed] [--unread] [--limit 20] [-o wide|name|json|yaml]";
if (kind === "attempt") return "Usage: bun scripts/cli.ts agentrun get attempts --task <taskId> [--cursor <retry-index>] [--limit 20] [--full] [-o json|yaml] [--raw]";
if (kind === "session") return "Usage: bun scripts/cli.ts agentrun get sessions [--limit 20] [-o wide|name|json|yaml]";
if (kind === "run") return "Usage: bun scripts/cli.ts agentrun get runs --task <taskId> [--limit 20] [-o wide|name|json|yaml]";
if (kind === "command") return "Usage: bun scripts/cli.ts agentrun get commands --run <runId> [--command <commandId>] [-o wide|name|json|yaml]";
if (kind === "runnerjob") return "Usage: bun scripts/cli.ts agentrun get runnerjobs --run <runId> --command <commandId> [-o wide|name|json|yaml]";
if (kind === "aipodspec") return "Usage: bun scripts/cli.ts agentrun get aipodspecs [-o wide|name|json|yaml]";
return "Unknown resource. Supported: tasks, sessions, runs, commands, runnerjobs, aipodspecs.";
return "Unknown resource. Supported: tasks, attempts, sessions, runs, commands, runnerjobs, aipodspecs.";
}
export async function runAgentRunResourceCommand(config: UniDeskConfig | null, verb: AgentRunResourceVerb, action: string | undefined, actionArgs: string[], canonicalArgs: string[]): Promise<RenderedCliResult> {
@@ -69,6 +70,7 @@ export async function runAgentRunResourceCommand(config: UniDeskConfig | null, v
if (verb === "result") return await resourceResult(config, command, action, bridgeActionArgs, options);
if (verb === "ack") return await resourceAck(config, command, action, bridgeActionArgs, options);
if (verb === "cancel") return await resourceCancel(config, command, action, bridgeActionArgs, options);
if (verb === "retry") return await resourceRetry(config, command, action, bridgeActionArgs, options);
if (verb === "dispatch") return await resourceDispatch(config, command, action, bridgeActionArgs, options);
if (verb === "create") return await resourceCreate(config, command, action, bridgeActionArgs, options);
if (verb === "apply") return await resourceApply(config, command, bridgeActionArgs, options);
@@ -109,6 +111,7 @@ export function parseResourceOptions(args: string[]): AgentRunResourceOptions {
raw: false,
debug: false,
limit: 20,
cursor: null,
queue: null,
state: null,
unread: false,
@@ -130,7 +133,7 @@ export function parseResourceOptions(args: string[]): AgentRunResourceOptions {
lane: null,
passthroughArgs: [],
};
const valueFlags = new Set(["-o", "--output", "--limit", "--queue", "--state", "--reader-id", "--task", "--task-id", "--run", "--run-id", "--command", "--command-id", "--session", "--session-id", "--after-seq", "--tail", "--reason", "-f", "--file", "--filename", "--aipod", "--idempotency-key", "--node", "--lane"]);
const valueFlags = new Set(["-o", "--output", "--limit", "--cursor", "--queue", "--state", "--reader-id", "--task", "--task-id", "--run", "--run-id", "--command", "--command-id", "--session", "--session-id", "--after-seq", "--tail", "--reason", "-f", "--file", "--filename", "--aipod", "--idempotency-key", "--node", "--lane"]);
const booleanFlags = new Set(["--full", "--raw", "--debug", "--unread", "--dry-run", "--full-text", "--prompt-stdin", "--stdin"]);
for (let index = 0; index < args.length; index += 1) {
const arg = args[index] ?? "";
@@ -169,6 +172,7 @@ export function applyResourceOption(options: AgentRunResourceOptions, flag: stri
else if (flag === "--full-text") options.fullText = true;
else if (flag === "--prompt-stdin" || flag === "--stdin") options.promptStdin = true;
else if (flag === "--limit") options.limit = parseNonNegativeInt(value, "--limit", 20, 500);
else if (flag === "--cursor") options.cursor = parseNonNegativeInt(value, "--cursor", 0, Number.MAX_SAFE_INTEGER);
else if (flag === "--queue") options.queue = requiredValue(value, flag);
else if (flag === "--state") options.state = requiredValue(value, flag);
else if (flag === "--reader-id") options.readerId = requiredValue(value, flag);
@@ -200,7 +204,7 @@ export function requiredValue(value: string | null, flag: string): string {
export async function resourceGet(config: UniDeskConfig | null, command: string, action: string | undefined, args: string[], options: AgentRunResourceOptions): Promise<RenderedCliResult> {
const kind = parseResourceKind(action);
if (kind === null) throw new Error("get requires a resource: tasks|sessions|runs|commands|runnerjobs|aipodspecs");
if (kind === null) throw new Error("get requires a resource: tasks|attempts|sessions|runs|commands|runnerjobs|aipodspecs");
let result: Record<string, unknown>;
if (kind === "task") {
const taskListArgs = options.unread
@@ -220,6 +224,16 @@ export async function resourceGet(config: UniDeskConfig | null, command: string,
result = await runAgentRunRestCommand(config, "sessions", ["ps", "--limit", String(options.limit)]);
return renderResourceResult(command, result, options, "Session", normalizeSessionItems(innerData(result)).slice(0, options.limit));
}
if (kind === "attempt" && options.taskId !== null) {
result = await runAgentRunRestCommand(config, "queue", [
"attempts",
options.taskId,
...(options.cursor === null ? [] : ["--cursor", String(options.cursor)]),
"--limit",
String(options.limit),
]);
return renderQueueAttemptList(command, result, options, options.taskId, normalizeQueueAttemptItems(innerData(result)).slice(0, options.limit));
}
if (kind === "aipodspec") {
result = await runAgentRunRestCommand(config, "aipod-specs", ["list"]);
return renderResourceResult(command, result, options, "AipodSpec", normalizeAipodSpecItems(innerData(result)).slice(0, options.limit));
@@ -240,6 +254,23 @@ export async function resourceGet(config: UniDeskConfig | null, command: string,
throw new Error(`get ${kind}s requires more context; use --task, --run/--command, or describe <kind>/<id>`);
}
export async function resourceRetry(config: UniDeskConfig | null, command: string, action: string | undefined, args: string[], options: AgentRunResourceOptions): Promise<RenderedCliResult> {
const ref = parseResourceRef(action, args, "task");
if (ref.kind !== "task") throw new Error("retry supports task/<taskId>");
const idempotencyKey = options.idempotencyKey ?? requiredContext("retry", "--idempotency-key <key>");
const reason = options.reason ?? requiredContext("retry", "--reason <text>");
const result = await runAgentRunRestCommand(config, "queue", [
"retry",
ref.name,
"--idempotency-key",
idempotencyKey,
"--reason",
reason,
...(options.dryRun ? ["--dry-run"] : []),
]);
return renderQueueRetrySummary(command, result, options, ref.name);
}
export async function resourceDescribe(config: UniDeskConfig | null, command: string, action: string | undefined, args: string[], options: AgentRunResourceOptions): Promise<RenderedCliResult> {
const ref = parseResourceRef(action, args);
if (ref.kind === "task") {
+12
View File
@@ -482,9 +482,11 @@ export async function runAgentRunQueueRest(action: string | undefined, id: strin
if (action === "list") return await agentRunRestRequest("agentrun queue list", "GET", `/api/v1/queue/tasks${agentRunQuery(args, ["queue", "state", "cursor", "limit", "updated-after"])}`);
if (action === "commander") return await agentRunRestRequest("agentrun queue commander", "GET", `/api/v1/queue/commander${agentRunQuery(args, ["queue", "reader-id"])}`);
if (action === "stats") return await agentRunRestRequest("agentrun queue stats", "GET", `/api/v1/queue/stats${agentRunQuery(args, ["queue"])}`);
if (action === "attempts" && id) return await agentRunRestRequest("agentrun queue attempts", "GET", `/api/v1/queue/tasks/${encodeURIComponent(id)}/attempts${agentRunQuery(args, ["cursor", "limit"])}`);
if (action === "show" && id) return await agentRunRestRequest("agentrun queue show", "GET", `/api/v1/queue/tasks/${encodeURIComponent(id)}`);
if (action === "submit") return await submitQueueTaskRest(args);
if (action === "dispatch" && id) return await mutateQueueTaskRest("queue-dispatch", id, "dispatch", queueDispatchBodyFromArgs(args), args);
if (action === "retry" && id) return await retryQueueTaskRest(id, args);
if (action === "read" && id) return await mutateQueueTaskRest("queue-read", id, "read", { readerId: agentRunOption(args, "reader-id") ?? "cli" }, args);
if (action === "cancel" && id) return await mutateQueueTaskRest("queue-cancel", id, "cancel", cancelBodyFromArgs(args), args);
if (action === "refresh" && id) return await mutateQueueTaskRest("queue-refresh", id, "refresh", {}, args);
@@ -603,6 +605,16 @@ export async function mutateQueueTaskRest(action: string, taskId: string, suffix
return await agentRunRestRequest(`agentrun queue ${suffix}`, "POST", pathValue, body);
}
export async function retryQueueTaskRest(taskId: string, args: string[]): Promise<Record<string, unknown>> {
const idempotencyKey = requiredAgentRunOption(args, ["idempotency-key"], "queue retry requires --idempotency-key");
const reason = requiredAgentRunOption(args, ["reason"], "queue retry requires --reason");
return await agentRunRestRequest("agentrun queue retry", "POST", `/api/v1/queue/tasks/${encodeURIComponent(taskId)}/retry`, {
idempotencyKey,
reason,
dryRun: agentRunHasFlag(args, "dry-run"),
});
}
export async function sessionSendRest(sessionId: string, args: string[]): Promise<Record<string, unknown>> {
const aipod = agentRunOption(args, "aipod") ?? agentRunOption(args, "aipod-spec");
if (aipod) return await sessionSendWithAipodRest(sessionId, aipod, args);
+3 -2
View File
@@ -48,9 +48,9 @@ export type AgentRunFailureKind = "auth-missing" | "auth-failed" | "agentrun-con
export type AgentRunRestCompatGroup = "queue" | "sessions" | "aipod-specs" | "aipods" | "runs" | "commands" | "runner";
export type AgentRunResourceVerb = "get" | "describe" | "events" | "logs" | "result" | "ack" | "cancel" | "dispatch" | "create" | "apply" | "send" | "explain";
export type AgentRunResourceVerb = "get" | "describe" | "events" | "logs" | "result" | "ack" | "cancel" | "retry" | "dispatch" | "create" | "apply" | "send" | "explain";
export type AgentRunResourceKind = "task" | "run" | "command" | "runnerjob" | "session" | "aipodspec";
export type AgentRunResourceKind = "task" | "attempt" | "run" | "command" | "runnerjob" | "session" | "aipodspec";
export type AgentRunOutputMode = "human" | "wide" | "name" | "json" | "yaml";
@@ -65,6 +65,7 @@ export interface AgentRunResourceOptions {
raw: boolean;
debug: boolean;
limit: number;
cursor: number | null;
queue: string | null;
state: string | null;
unread: boolean;