fix: add bounded AgentRun task input drill-down
This commit is contained in:
@@ -1335,12 +1335,13 @@ export function renderTaskDescription(task: Record<string, unknown>, options: Ag
|
||||
"Next:",
|
||||
];
|
||||
const next = [
|
||||
`bun scripts/cli.ts agentrun describe task/${taskId} --input -o json`,
|
||||
runId === null ? null : `bun scripts/cli.ts agentrun events run/${runId} --after-seq 0 --limit 100`,
|
||||
sessionId === null ? null : `bun scripts/cli.ts agentrun logs session/${sessionId} --tail 100`,
|
||||
runId === null || commandId === null ? null : `bun scripts/cli.ts agentrun result run/${runId} --command ${commandId}`,
|
||||
`bun scripts/cli.ts agentrun ack task/${taskId}`,
|
||||
options.full ? null : `bun scripts/cli.ts agentrun describe task/${taskId} --full`,
|
||||
].filter((item): item is string => item !== null).slice(0, 5);
|
||||
].filter((item): item is string => item !== null).slice(0, 6);
|
||||
lines.push(...next.map((item) => ` ${item}`));
|
||||
return lines.join("\n");
|
||||
}
|
||||
@@ -1379,12 +1380,147 @@ export function compactTaskDescriptionPayload(ref: AgentRunResourceRef, task: Re
|
||||
logs: sessionId === null ? null : `bun scripts/cli.ts agentrun logs session/${sessionId} --tail 100`,
|
||||
result: runId === null || commandId === null ? null : `bun scripts/cli.ts agentrun result run/${runId} --command ${commandId}`,
|
||||
ack: `bun scripts/cli.ts agentrun ack task/${taskId}`,
|
||||
input: `bun scripts/cli.ts agentrun describe task/${taskId} --input -o json`,
|
||||
full: `bun scripts/cli.ts agentrun describe task/${taskId} --full -o json`,
|
||||
},
|
||||
valuesPrinted: false,
|
||||
};
|
||||
}
|
||||
|
||||
export function taskInputDescriptionPayload(ref: AgentRunResourceRef, task: Record<string, unknown>): Record<string, unknown> {
|
||||
const metadata = taskInputMetadata(task.metadata);
|
||||
const aipodImageRef = taskInputImageRef(metadata.aipodImageRef);
|
||||
if (aipodImageRef !== null) metadata.aipodImageRef = aipodImageRef;
|
||||
const spec = pickCompact(task, [
|
||||
"tenantId",
|
||||
"projectId",
|
||||
"queue",
|
||||
"lane",
|
||||
"title",
|
||||
"priority",
|
||||
"backendProfile",
|
||||
"providerId",
|
||||
"payload",
|
||||
"references",
|
||||
"idempotencyKey",
|
||||
]);
|
||||
spec.workspaceRef = taskInputWorkspaceRef(task.workspaceRef);
|
||||
spec.sessionRef = taskInputSessionRef(task.sessionRef);
|
||||
spec.executionPolicy = taskInputExecutionPolicy(task.executionPolicy);
|
||||
spec.resourceBundleRef = taskInputResourceBundleRef(task.resourceBundleRef);
|
||||
spec.metadata = metadata;
|
||||
return {
|
||||
kind: "TaskInput",
|
||||
name: ref.name,
|
||||
spec,
|
||||
aipodSpec: {
|
||||
name: metadata.aipod ?? null,
|
||||
specHash: metadata.aipodSpecHash ?? null,
|
||||
imageRef: aipodImageRef,
|
||||
valuesPrinted: false,
|
||||
},
|
||||
provenance: {
|
||||
sourceTaskId: stringOrNull(task.id) ?? ref.name,
|
||||
source: metadata.source ?? null,
|
||||
payloadHash: task.payloadHash ?? null,
|
||||
valuesPrinted: false,
|
||||
},
|
||||
redaction: {
|
||||
credentialValues: "omitted",
|
||||
secretRefsOnly: true,
|
||||
valuesPrinted: false,
|
||||
},
|
||||
valuesPrinted: false,
|
||||
};
|
||||
}
|
||||
|
||||
function taskInputExecutionPolicy(value: unknown): Record<string, unknown> | null {
|
||||
if (!isRecord(value)) return null;
|
||||
const policy = pickCompact(value, ["sandbox", "approval", "timeoutMs", "network"]);
|
||||
const secretScope = record(value.secretScope);
|
||||
policy.secretScope = {
|
||||
allowCredentialEcho: false,
|
||||
providerCredentials: arrayRecords(secretScope.providerCredentials).map((credential) => ({
|
||||
...pickCompact(credential, ["profile"]),
|
||||
secretRef: taskInputSecretRef(credential.secretRef),
|
||||
valuesPrinted: false,
|
||||
})),
|
||||
toolCredentials: arrayRecords(secretScope.toolCredentials).map((credential) => ({
|
||||
...pickCompact(credential, ["tool", "purpose"]),
|
||||
secretRef: taskInputSecretRef(credential.secretRef),
|
||||
projection: pickCompact(record(credential.projection), ["kind", "envName", "secretKey", "mountPath"]),
|
||||
valuesPrinted: false,
|
||||
})),
|
||||
valuesPrinted: false,
|
||||
};
|
||||
return policy;
|
||||
}
|
||||
|
||||
function taskInputSecretRef(value: unknown): Record<string, unknown> | null {
|
||||
if (!isRecord(value)) return null;
|
||||
return {
|
||||
...pickCompact(value, ["namespace", "name", "keys", "mountPath"]),
|
||||
valuesPrinted: false,
|
||||
};
|
||||
}
|
||||
|
||||
function taskInputResourceBundleRef(value: unknown): Record<string, unknown> | null {
|
||||
if (!isRecord(value)) return null;
|
||||
const result = pickCompact(value, ["kind", "commitId", "ref", "submodules", "lfs"]);
|
||||
result.repoUrl = taskInputRepoUrl(value.repoUrl);
|
||||
result.bundles = arrayRecords(value.bundles).map((bundle) => ({
|
||||
...pickCompact(bundle, ["name", "commitId", "ref", "subpath", "targetPath"]),
|
||||
...(bundle.repoUrl === undefined ? {} : { repoUrl: taskInputRepoUrl(bundle.repoUrl) }),
|
||||
}));
|
||||
if (Array.isArray(value.promptRefs)) {
|
||||
result.promptRefs = arrayRecords(value.promptRefs).map((item) => pickCompact(item, ["name", "path", "inject", "required"]));
|
||||
}
|
||||
if (Array.isArray(value.requiredSkills)) {
|
||||
result.requiredSkills = arrayRecords(value.requiredSkills).map((item) => pickCompact(item, ["name"]));
|
||||
}
|
||||
if (value.credentialRef !== undefined) result.credentialRef = taskInputSecretRef(value.credentialRef);
|
||||
result.valuesPrinted = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
function taskInputWorkspaceRef(value: unknown): Record<string, unknown> | null {
|
||||
if (!isRecord(value)) return null;
|
||||
const result = pickCompact(value, ["kind", "path", "branch"]);
|
||||
if (value.repo !== undefined) result.repo = taskInputRepoUrl(value.repo);
|
||||
return result;
|
||||
}
|
||||
|
||||
function taskInputSessionRef(value: unknown): Record<string, unknown> | null {
|
||||
if (!isRecord(value)) return null;
|
||||
return pickCompact(value, ["sessionId", "conversationId", "threadId", "expiresAt"]);
|
||||
}
|
||||
|
||||
function taskInputMetadata(value: unknown): Record<string, unknown> {
|
||||
if (!isRecord(value)) return {};
|
||||
return pickCompact(value, ["aipod", "source", "aipodSpecHash", "aipodImageRef"]);
|
||||
}
|
||||
|
||||
function taskInputImageRef(value: unknown): Record<string, unknown> | null {
|
||||
if (!isRecord(value)) return null;
|
||||
const result = pickCompact(value, ["kind", "commitId", "dockerfilePath", "sourceIdentity"]);
|
||||
if (value.repoUrl !== undefined) result.repoUrl = taskInputRepoUrl(value.repoUrl);
|
||||
result.valuesPrinted = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
function taskInputRepoUrl(value: unknown): unknown {
|
||||
if (typeof value !== "string") return value ?? null;
|
||||
if (!value.includes("://")) return value;
|
||||
try {
|
||||
const parsed = new URL(value);
|
||||
parsed.username = "";
|
||||
parsed.password = "";
|
||||
return parsed.toString();
|
||||
} catch {
|
||||
return "<invalid-or-redacted-url>";
|
||||
}
|
||||
}
|
||||
|
||||
export function unwrapTaskDetail(data: Record<string, unknown>): Record<string, unknown> {
|
||||
const task = record(data.task);
|
||||
if (Object.keys(task).length > 0) return task;
|
||||
|
||||
Reference in New Issue
Block a user