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 {
|
try {
|
||||||
return await withAgentRunRestTarget(resolveAgentRunRestTarget(config, parseAgentRunRestTargetOptions(args)), async () => {
|
const raw = await withAgentRunRestTarget(resolveAgentRunRestTarget(config, options), async () => {
|
||||||
return await runAgentRunRestCommand(config, group, stripAgentRunLaneTargetArgs(args));
|
return await runAgentRunRestCommand(config, group, stripAgentRunResourceWrapperArgs(args));
|
||||||
});
|
});
|
||||||
|
return renderAgentRunRestCompatResult(command, group, stripAgentRunResourceWrapperArgs(args), raw, options);
|
||||||
} catch (error) {
|
} 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;
|
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>> {
|
async function runAgentRunRestCommand(config: UniDeskConfig | null, group: AgentRunRestCompatGroup, args: string[]): Promise<Record<string, unknown>> {
|
||||||
void config;
|
void config;
|
||||||
const compatGroup = group === "aipods" ? "aipod-specs" : group;
|
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}`);
|
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>> {
|
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 === "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 === "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;
|
lane: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AgentRunRestCompatOptions extends AgentRunRestTargetOptions {
|
||||||
|
output: AgentRunOutputMode;
|
||||||
|
full: boolean;
|
||||||
|
raw: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
interface AgentRunRestTarget {
|
interface AgentRunRestTarget {
|
||||||
config: UniDeskConfig;
|
config: UniDeskConfig;
|
||||||
configPath: string;
|
configPath: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user