fix(nodes-tool): add exec approval flow for agent tool run action
The agent tool's run action was directly calling node.invoke with system.run without going through the exec approval flow. When the node requires approval (ask=on-miss and allowlist miss), it immediately denied the request with SYSTEM_RUN_DENIED. The CLI path (nodes run) already handled this correctly by calling exec.approval.request first, waiting for the user decision, then retrying with the approved flag. This commit adds the same flow to the agent tool: 1. Try system.run without approval flags 2. If denied with 'approval required', call exec.approval.request on the gateway to create a pending approval and wait for user 3. On approve, retry system.run with approved=true + approvalDecision 4. On deny/timeout, throw a clear error This fixes the approval UI not showing pending requests when the agent tool triggers a node run command.
This commit is contained in:
parent
da71eaebd2
commit
0564482aba
@ -423,17 +423,71 @@ export function createNodesTool(options?: {
|
||||
typeof params.needsScreenRecording === "boolean"
|
||||
? params.needsScreenRecording
|
||||
: undefined;
|
||||
const runParams = {
|
||||
command,
|
||||
cwd,
|
||||
env,
|
||||
timeoutMs: commandTimeoutMs,
|
||||
needsScreenRecording,
|
||||
agentId,
|
||||
sessionKey,
|
||||
};
|
||||
|
||||
// First attempt without approval flags.
|
||||
try {
|
||||
const raw = (await callGatewayTool("node.invoke", gatewayOpts, {
|
||||
nodeId,
|
||||
command: "system.run",
|
||||
params: runParams,
|
||||
timeoutMs: invokeTimeoutMs,
|
||||
idempotencyKey: crypto.randomUUID(),
|
||||
})) as { payload?: unknown };
|
||||
return jsonResult(raw?.payload ?? {});
|
||||
} catch (firstErr) {
|
||||
const msg = firstErr instanceof Error ? firstErr.message : String(firstErr);
|
||||
if (!msg.includes("SYSTEM_RUN_DENIED: approval required")) {
|
||||
throw firstErr;
|
||||
}
|
||||
}
|
||||
|
||||
// Node requires approval – create a pending approval request on
|
||||
// the gateway and wait for the user to approve/deny via the UI.
|
||||
const APPROVAL_TIMEOUT_MS = 120_000;
|
||||
const cmdText = command.join(" ");
|
||||
const approvalResult = (await callGatewayTool(
|
||||
"exec.approval.request",
|
||||
{ ...gatewayOpts, timeoutMs: APPROVAL_TIMEOUT_MS + 5_000 },
|
||||
{
|
||||
command: cmdText,
|
||||
cwd,
|
||||
host: "node",
|
||||
agentId,
|
||||
sessionKey,
|
||||
timeoutMs: APPROVAL_TIMEOUT_MS,
|
||||
},
|
||||
)) as { decision?: string; id?: string } | null;
|
||||
|
||||
const decision =
|
||||
approvalResult && typeof approvalResult === "object"
|
||||
? (approvalResult.decision ?? null)
|
||||
: null;
|
||||
|
||||
if (!decision || decision === "deny") {
|
||||
throw new Error(
|
||||
decision === "deny"
|
||||
? "exec denied: user denied"
|
||||
: "exec denied: approval timed out",
|
||||
);
|
||||
}
|
||||
|
||||
// Retry with the approval decision.
|
||||
const raw = (await callGatewayTool("node.invoke", gatewayOpts, {
|
||||
nodeId,
|
||||
command: "system.run",
|
||||
params: {
|
||||
command,
|
||||
cwd,
|
||||
env,
|
||||
timeoutMs: commandTimeoutMs,
|
||||
needsScreenRecording,
|
||||
agentId,
|
||||
sessionKey,
|
||||
...runParams,
|
||||
approved: true,
|
||||
approvalDecision: decision,
|
||||
},
|
||||
timeoutMs: invokeTimeoutMs,
|
||||
idempotencyKey: crypto.randomUUID(),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user