fix: summarize aipod render output (#872)
Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
+183
-25
@@ -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<Record<string, unknown>> {
|
||||
async function runAgentRunRestCompatCommand(config: UniDeskConfig | null, group: AgentRunRestCompatGroup, args: string[], canonicalArgs: string[]): Promise<Record<string, unknown> | 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<string, unknown>, options: AgentRunRestCompatOptions): Record<string, unknown> | 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<string, unknown>, 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<string, unknown>, aipod: Record<string, unknown>): 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<string, unknown>, aipod: Record<string, unknown>): Array<{ tool: unknown; purpose: unknown; namespace: unknown; name: unknown; keys: string[]; projection: Record<string, unknown> }> {
|
||||
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, unknown>): 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<Record<string, unknown>> {
|
||||
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<Record<string, unknown>> {
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user