fix(agentrun): 完善重试命令发现与错误输出

This commit is contained in:
Codex
2026-07-12 02:55:57 +02:00
parent 9276e751f5
commit c4f3724430
4 changed files with 219 additions and 17 deletions
+4 -2
View File
@@ -385,8 +385,8 @@ export function agentRunHelpText(args: string[]): string {
return [
"Usage: bun scripts/cli.ts agentrun <verb> <resource> [options]",
"",
"Verbs: get, describe, events, logs, result, ack, cancel, dispatch, create, apply, send, explain",
"Resources: task/qt, run, command/cmd, runnerjob/rjob, session/ses, aipodspec/aps",
"Verbs: get, describe, events, logs, result, ack, cancel, retry, dispatch, create, apply, send, explain",
"Resources: task/qt, attempt, run, command/cmd, runnerjob/rjob, session/ses, aipodspec/aps",
"",
"Common:",
" bun scripts/cli.ts agentrun get tasks --queue commander --limit 20",
@@ -394,6 +394,8 @@ export function agentRunHelpText(args: string[]): string {
" bun scripts/cli.ts agentrun describe run/<runId> --node NC01 --lane nc01-v02",
" bun scripts/cli.ts agentrun events run/<runId> --after-seq 0 --limit 100",
" bun scripts/cli.ts agentrun logs session/<sessionId> --tail 100",
" 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 create task --aipod Artificer --prompt-stdin",
"",
"Machine/debug output:",
+39 -9
View File
@@ -57,9 +57,17 @@ export function agentRunGetKindHelp(kindRaw: string): string {
export async function runAgentRunResourceCommand(config: UniDeskConfig | null, verb: AgentRunResourceVerb, action: string | undefined, actionArgs: string[], canonicalArgs: string[]): Promise<RenderedCliResult> {
if (isHelpArg(action) || actionArgs.some(isHelpArg)) return renderAgentRunHelp(canonicalArgs);
const resourceArgs = action === undefined ? actionArgs : [action, ...actionArgs];
const options = parseResourceOptions(resourceArgs);
const bridgeActionArgs = stripAgentRunResourceWrapperArgs(actionArgs);
const command = `agentrun ${canonicalArgs.join(" ")}`.trim();
let options: AgentRunResourceOptions;
try {
options = parseResourceOptions(resourceArgs);
} catch (error) {
const validationError = error instanceof AgentRunRestError
? error
: new AgentRunRestError("validation-failed", error instanceof Error ? error.message : String(error));
return renderAgentRunRestError(command, validationError, resourceErrorOutputOptions(resourceArgs));
}
const bridgeActionArgs = stripAgentRunResourceWrapperArgs(actionArgs);
try {
return await withAgentRunRestTarget(resolveAgentRunRestTarget(config, options), async () => {
if (verb === "explain") return renderedCliResult(true, command, agentRunExplain(action ?? "task", resourceArgs, options));
@@ -84,6 +92,21 @@ export async function runAgentRunResourceCommand(config: UniDeskConfig | null, v
return renderedCliResult(false, command, `Unsupported AgentRun resource command. Try: bun scripts/cli.ts agentrun --help`);
}
function resourceErrorOutputOptions(args: string[]): AgentRunResourceOptions {
const options = parseResourceOptions([]);
options.raw = args.includes("--raw");
for (let index = 0; index < args.length; index += 1) {
const arg = args[index] ?? "";
const value = arg === "-o" || arg === "--output"
? args[index + 1]
: arg.startsWith("--output=") || arg.startsWith("-o=")
? arg.slice(arg.indexOf("=") + 1)
: null;
if (value === "json" || value === "yaml") options.output = value;
}
return options;
}
export function stripAgentRunResourceWrapperArgs(args: string[]): string[] {
const result: string[] = [];
for (let index = 0; index < args.length; index += 1) {
@@ -224,7 +247,8 @@ 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) {
if (kind === "attempt") {
if (options.taskId === null) throw new AgentRunRestError("validation-failed", "get attempts requires --task <taskId>");
result = await runAgentRunRestCommand(config, "queue", [
"attempts",
options.taskId,
@@ -255,17 +279,23 @@ export async function resourceGet(config: UniDeskConfig | null, command: string,
}
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>");
if (action === undefined || action.startsWith("-")) throw new AgentRunRestError("validation-failed", "retry requires task/<taskId>");
let ref: AgentRunResourceRef;
try {
ref = parseResourceRef(action, args, "task");
} catch {
throw new AgentRunRestError("validation-failed", "retry requires task/<taskId>");
}
if (ref.kind !== "task") throw new AgentRunRestError("validation-failed", "retry supports task/<taskId>");
if (options.idempotencyKey === null) throw new AgentRunRestError("validation-failed", "retry requires --idempotency-key <key>");
if (options.reason === null) throw new AgentRunRestError("validation-failed", "retry requires --reason <text>");
const result = await runAgentRunRestCommand(config, "queue", [
"retry",
ref.name,
"--idempotency-key",
idempotencyKey,
options.idempotencyKey,
"--reason",
reason,
options.reason,
...(options.dryRun ? ["--dry-run"] : []),
]);
return renderQueueRetrySummary(command, result, options, ref.name);
+31 -6
View File
@@ -1059,8 +1059,10 @@ export async function withAgentRunRestTarget<T>(target: AgentRunRestTarget | nul
}
export function renderAgentRunRestError(command: string, error: AgentRunRestError, options: AgentRunResourceOptions): RenderedCliResult {
const payload = error.toPayload(command);
if (options.raw || options.output === "json" || options.output === "yaml") return renderMachine(command, payload, options.output === "yaml" ? "yaml" : "json", false);
const rawPayload = error.toPayload(command);
if (options.raw) return renderMachine(command, rawPayload, "json", false);
const payload = boundedAgentRunRestErrorPayload(rawPayload);
if (options.output === "json" || options.output === "yaml") return renderMachine(command, payload, options.output === "yaml" ? "yaml" : "json", false);
const laneHint = record(record(payload.agentrun).laneAwareLookup);
const currentEndpoint = record(laneHint.currentEndpoint);
const nextCommands = Array.isArray(laneHint.nextCommands)
@@ -1075,12 +1077,18 @@ export function renderAgentRunRestError(command: string, error: AgentRunRestErro
` Config: ${String(currentEndpoint.configPath ?? "(unknown)")}`,
` ${String(laneHint.summary ?? "The resource was not found on the currently configured AgentRun manager endpoint.")}`,
];
const validationHelp = `bun scripts/cli.ts agentrun ${command.split(/\s+/u)[1] ?? "--help"} --help`;
const nextLines = nextCommands.length > 0
? nextCommands
: [
"Check config/agentrun.yaml manager.baseUrl and the AgentRun API route.",
"Verify HWLAB_API_KEY is present in env or in the configured auth.file without printing the key.",
];
: error.failureKind === "validation-failed"
? [
"Review the AgentRun validation message and correct the request; do not bypass the formal resource API.",
validationHelp,
]
: [
"Check config/agentrun.yaml manager.baseUrl and the AgentRun API route.",
"Verify HWLAB_API_KEY is present in env or in the configured auth.file without printing the key.",
];
return renderedCliResult(false, command, [
`Error: ${payload.failureKind}`,
String(payload.message ?? ""),
@@ -1091,6 +1099,23 @@ export function renderAgentRunRestError(command: string, error: AgentRunRestErro
].join("\n"));
}
export function boundedAgentRunRestErrorPayload(payload: Record<string, unknown>): Record<string, unknown> {
return boundedAgentRunRestErrorValue(payload, 0) as Record<string, unknown>;
}
function boundedAgentRunRestErrorValue(value: unknown, depth: number): unknown {
if (typeof value === "string") return truncateOneLine(value, 400);
if (value === null || typeof value === "number" || typeof value === "boolean") return value;
if (Array.isArray(value)) return value.slice(0, 12).map((item) => boundedAgentRunRestErrorValue(item, depth + 1));
if (typeof value !== "object") return String(value);
if (depth >= 5) return "[nested details omitted]";
const entries = Object.entries(value as Record<string, unknown>);
const result: Record<string, unknown> = {};
for (const [key, item] of entries.slice(0, 20)) result[key] = boundedAgentRunRestErrorValue(item, depth + 1);
if (entries.length > 20) result.omittedFieldCount = entries.length - 20;
return result;
}
export class AgentRunRestError extends Error {
readonly failureKind: AgentRunFailureKind;
readonly bridge: Record<string, unknown> | null;