From bd349fbcf5db22bc7a49c0bcdfc99b024994b2fb Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Thu, 25 Jun 2026 12:21:06 +0800 Subject: [PATCH] fix: summarize aipod render output (#872) Co-authored-by: Codex --- scripts/src/agentrun.ts | 208 +++++++++++++++++++++++++++++++++++----- 1 file changed, 183 insertions(+), 25 deletions(-) diff --git a/scripts/src/agentrun.ts b/scripts/src/agentrun.ts index 9ecf91ca..b51856c9 100644 --- a/scripts/src/agentrun.ts +++ b/scripts/src/agentrun.ts @@ -6090,17 +6090,190 @@ function startAsyncAgentRunJob(name: string, command: string[], note: string): R }; } -async function runAgentRunRestCompatCommand(config: UniDeskConfig | null, group: AgentRunRestCompatGroup, args: string[], canonicalArgs: string[]): Promise> { +async function runAgentRunRestCompatCommand(config: UniDeskConfig | null, group: AgentRunRestCompatGroup, args: string[], canonicalArgs: string[]): Promise | RenderedCliResult> { + const options = parseAgentRunRestCompatOptions(args); + const command = `agentrun ${canonicalArgs.join(" ")}`.trim(); try { - return await withAgentRunRestTarget(resolveAgentRunRestTarget(config, parseAgentRunRestTargetOptions(args)), async () => { - return await runAgentRunRestCommand(config, group, stripAgentRunLaneTargetArgs(args)); + const raw = await withAgentRunRestTarget(resolveAgentRunRestTarget(config, options), async () => { + return await runAgentRunRestCommand(config, group, stripAgentRunResourceWrapperArgs(args)); }); + return renderAgentRunRestCompatResult(command, group, stripAgentRunResourceWrapperArgs(args), raw, options); } catch (error) { - if (error instanceof AgentRunRestError) return error.toPayload(`agentrun ${canonicalArgs.join(" ")}`.trim()); + if (error instanceof AgentRunRestError) { + if (options.raw || options.full || options.output === "json" || options.output === "yaml") { + return renderMachine(command, error.toPayload(command), options.output === "yaml" ? "yaml" : "json", false); + } + return error.toPayload(command); + } throw error; } } +function parseAgentRunRestCompatOptions(args: string[]): AgentRunRestCompatOptions { + const resourceOptions = parseResourceOptions(args); + return { + node: resourceOptions.node, + lane: resourceOptions.lane, + output: resourceOptions.output, + full: resourceOptions.full, + raw: resourceOptions.raw, + }; +} + +function renderAgentRunRestCompatResult(command: string, group: AgentRunRestCompatGroup, args: string[], raw: Record, options: AgentRunRestCompatOptions): Record | RenderedCliResult { + if (options.raw || options.full) return renderMachine(command, raw, "json", raw.ok !== false); + if (options.output === "json" || options.output === "yaml") return renderMachine(command, raw, options.output, raw.ok !== false); + const compatGroup = group === "aipods" ? "aipod-specs" : group; + const [action, id] = args; + if (compatGroup === "aipod-specs" && action === "render" && id !== undefined) return renderAgentRunAipodSpecRenderSummary(command, raw, id); + return raw; +} + +function renderAgentRunAipodSpecRenderSummary(command: string, raw: Record, requestedAipod: string): RenderedCliResult { + const data = record(innerData(raw)); + const aipod = record(data.aipod); + const task = record(data.queueTask); + const bridge = record(raw.bridge); + const executionPolicy = record(task.executionPolicy); + const secretScope = record(executionPolicy.secretScope); + const resourceBundle = record(task.resourceBundleRef ?? aipod.resourceBundleRef); + const dispatchDefaults = record(data.dispatchDefaults); + const runnerJobDefaults = record(dispatchDefaults.runnerJob); + const node = stringOrNull(bridge.node) ?? stringOrNull(task.providerId) ?? "-"; + const lane = stringOrNull(bridge.lane) ?? stringOrNull(task.lane) ?? "-"; + const namespace = stringOrNull(bridge.namespace) ?? stringOrNull(runnerJobDefaults.namespace) ?? "-"; + const providerCredentials = agentRunRenderedProviderCredentials(secretScope, aipod); + const toolCredentials = agentRunRenderedToolCredentials(secretScope, aipod); + const bundleNames = agentRunResourceBundleNames(resourceBundle.bundles, "name"); + const skillNames = agentRunResourceBundleNames(resourceBundle.requiredSkills, "name"); + const targetArgs = agentRunCompatTargetCliArgs(node, lane); + const lines = [ + "AIPODSPEC RENDER", + ` AipodSpec: ${displayValue(aipod.name ?? requestedAipod)} hash=${displayValue(aipod.specHash)}`, + ` Target: node=${displayValue(node)} lane=${displayValue(lane)} namespace=${displayValue(namespace)} bridge=${displayValue(bridge.mode)}`, + ` TaskPolicy: backendProfile=${displayValue(task.backendProfile)} providerId=${displayValue(task.providerId)} queue=${displayValue(task.queue)} lane=${displayValue(task.lane)}`, + ` WorkspaceRef: ${agentRunCompactJson(task.workspaceRef, 140)}`, + ` Execution: ${agentRunCompactJson(pickCompact(executionPolicy, ["sandbox", "approval", "timeoutMs", "network"]), 160)}`, + " Values: secret payloads are not printed; valuesPrinted=false", + "", + "PROVIDER CREDENTIAL SECRETREFS", + providerCredentials.length > 0 + ? renderTable(["PROFILE", "NAMESPACE", "SECRET", "KEYS", "VALUES"], providerCredentials.map((credential) => [ + displayValue(credential.profile), + displayValue(credential.namespace ?? namespace), + displayValue(credential.name), + agentRunJoinNames(credential.keys, 5), + "false", + ])) + : " (none)", + "", + "TOOL CREDENTIAL SECRETREFS", + toolCredentials.length > 0 + ? renderTable(["TOOL", "PURPOSE", "NAMESPACE", "SECRET", "KEYS", "PROJECTION", "VALUES"], toolCredentials.map((credential) => [ + displayValue(credential.tool), + displayValue(credential.purpose), + displayValue(credential.namespace ?? namespace), + displayValue(credential.name), + agentRunJoinNames(credential.keys, 5), + agentRunProjectionSummary(credential.projection), + "false", + ])) + : " (none)", + "", + "RESOURCE BUNDLE", + ` Kind: ${displayValue(resourceBundle.kind)} repo=${displayValue(resourceBundle.repoUrl)} ref=${displayValue(resourceBundle.ref)} commit=${displayValue(resourceBundle.commitId)}`, + ` Bundles: ${agentRunJoinNames(bundleNames, 6)}`, + ` RequiredSkills: ${agentRunJoinNames(skillNames, 8)}`, + ` RunnerJob: namespace=${displayValue(runnerJobDefaults.namespace)} image=${agentRunCompactJson(runnerJobDefaults.imageRef, 120)}`, + "", + "DRILL-DOWN", + ` bun scripts/cli.ts ${command} --full`, + ` bun scripts/cli.ts ${command} -o json`, + ` bun scripts/cli.ts agentrun create task --aipod ${requestedAipod}${targetArgs} --prompt-stdin`, + ]; + return renderedCliResult(raw.ok !== false, command, `${lines.join("\n")}\n`); +} + +function agentRunRenderedProviderCredentials(secretScope: Record, aipod: Record): Array<{ profile: unknown; namespace: unknown; name: unknown; keys: string[] }> { + const scoped = arrayRecords(secretScope.providerCredentials).map((credential) => { + const secretRef = record(credential.secretRef); + return { + profile: credential.profile, + namespace: secretRef.namespace, + name: secretRef.name, + keys: agentRunStringList(secretRef.keys), + }; + }); + if (scoped.length > 0) return scoped; + return arrayRecords(record(aipod.providerCredentials).items).map((credential) => ({ + profile: credential.profile, + namespace: credential.namespace, + name: credential.name, + keys: agentRunStringList(credential.keys), + })); +} + +function agentRunRenderedToolCredentials(secretScope: Record, aipod: Record): Array<{ tool: unknown; purpose: unknown; namespace: unknown; name: unknown; keys: string[]; projection: Record }> { + const scoped = arrayRecords(secretScope.toolCredentials).map((credential) => { + const secretRef = record(credential.secretRef); + return { + tool: credential.tool, + purpose: credential.purpose, + namespace: secretRef.namespace, + name: secretRef.name, + keys: agentRunStringList(secretRef.keys), + projection: record(credential.projection), + }; + }); + if (scoped.length > 0) return scoped; + return arrayRecords(record(aipod.toolCredentials).items).map((credential) => ({ + tool: credential.tool, + purpose: credential.purpose, + namespace: credential.namespace, + name: credential.name, + keys: agentRunStringList(credential.keys), + projection: record(credential.projection), + })); +} + +function agentRunResourceBundleNames(value: unknown, key: string): string[] { + const direct = agentRunStringList(record(value).names); + if (direct.length > 0) return direct; + return arrayRecords(value).map((item) => stringOrNull(item[key]) ?? "").filter((item) => item.length > 0); +} + +function agentRunStringList(value: unknown): string[] { + if (!Array.isArray(value)) return []; + return value.map((item) => String(item)).filter((item) => item.length > 0); +} + +function agentRunJoinNames(values: string[], maxItems: number): string { + if (values.length === 0) return "-"; + const visible = values.slice(0, maxItems); + const suffix = values.length > visible.length ? ` +${values.length - visible.length}` : ""; + return `${visible.join(", ")}${suffix}`; +} + +function agentRunProjectionSummary(value: Record): string { + const kind = stringOrNull(value.kind); + if (kind === "env") return `env:${displayValue(value.envName)}<-${displayValue(value.secretKey)}`; + if (kind === "volume") return `volume:${displayValue(value.mountPath)}`; + if (Object.keys(value).length === 0) return "-"; + return agentRunCompactJson(value, 80); +} + +function agentRunCompactJson(value: unknown, maxChars: number): string { + if (value === undefined || value === null) return "-"; + return truncateOneLine(JSON.stringify(value), maxChars); +} + +function agentRunCompatTargetCliArgs(node: string, lane: string): string { + const parts: string[] = []; + if (node !== "-") parts.push("--node", node); + if (lane !== "-") parts.push("--lane", lane); + return parts.length === 0 ? "" : ` ${parts.join(" ")}`; +} + async function runAgentRunRestCommand(config: UniDeskConfig | null, group: AgentRunRestCompatGroup, args: string[]): Promise> { void config; const compatGroup = group === "aipods" ? "aipod-specs" : group; @@ -6114,27 +6287,6 @@ async function runAgentRunRestCommand(config: UniDeskConfig | null, group: Agent throw new AgentRunRestError("unsupported-version", `unsupported AgentRun REST compatibility group: ${group}`); } -function parseAgentRunRestTargetOptions(args: string[]): AgentRunRestTargetOptions { - return { - node: agentRunOption(args, "node"), - lane: agentRunOption(args, "lane"), - }; -} - -function stripAgentRunLaneTargetArgs(args: string[]): string[] { - const result: string[] = []; - for (let index = 0; index < args.length; index += 1) { - const arg = args[index] ?? ""; - if (arg === "--node" || arg === "--lane") { - index += 1; - continue; - } - if (arg.startsWith("--node=") || arg.startsWith("--lane=")) continue; - result.push(arg); - } - return result; -} - async function runAgentRunQueueRest(action: string | undefined, id: string | undefined, args: string[]): Promise> { 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"])}`); @@ -7552,6 +7704,12 @@ interface AgentRunRestTargetOptions { lane: string | null; } +interface AgentRunRestCompatOptions extends AgentRunRestTargetOptions { + output: AgentRunOutputMode; + full: boolean; + raw: boolean; +} + interface AgentRunRestTarget { config: UniDeskConfig; configPath: string;