wait_for_user_ack
wait_for_user_ack
Waits for the user to confirm an out-of-band action (e.g. 'did you finish resetting your password in the browser?'). Emits a UserAckCard to the renderer with a prompt and clickable options; returns the chosen option id to the agent.
Metadata
Name
wait_for_user_ack
Updated
last month
Source
Risk
Low
Requires consent
false
Affected scope
user
Code
/**
* mcp/skills/waitForUserAck.ts — wait_for_user_ack synthetic tool
*
* This is NOT a normal tool. It is a registration shim for a first-class
* G4 gate — the "user-ack" gate — which is routed specially in
* electron/agent/guards/execution.ts:executeStep().
*
* Returns
* -------
* { choice: string }
*
*/
import { z } from "zod";
// -- Meta ---------------------------------------------------------------------
export const meta = {
name: "wait_for_user_ack",
description:
"Waits for the user to confirm an out-of-band action (e.g. 'did you " +
"finish resetting your password in the browser?'). Emits a UserAckCard " +
"to the renderer with a prompt and clickable options; returns the " +
"chosen option id to the agent.",
riskLevel: "low",
destructive: false,
requiresConsent: false,
supportsDryRun: false,
affectedScope: ["user"],
auditRequired: false,
isUserWaitGate: true,
schema: {
prompt: z
.string()
.min(1)
.describe(
"Short question to show the user in the UserAckCard " +
"(e.g. 'Did you complete the password reset in the browser?').",
),
options: z
.array(
z.object({
id: z
.string()
.min(1)
.describe(
"Stable identifier returned in the gate result — the agent " +
"branches on this value. Use 'done' for the happy-path continue " +
"option; 'failed', 'cancel', 'timeout' for the sad paths.",
),
label: z
.string()
.min(1)
.describe("Human-readable button text shown in the UserAckCard."),
kind: z
.enum(["primary", "secondary", "cancel"])
.optional()
.describe(
"Optional visual hint for the button (primary = green/emerald, " +
"secondary = neutral zinc, cancel = muted). Defaults to 'secondary'.",
),
}),
)
.min(1)
.max(4)
.describe(
"Ordered list of clickable options. Include one 'done' option on " +
"the happy path plus 1-3 sad-path options.",
),
},
} as const;
// -- Exported run function ----------------------------------------------------
/**
* Safety-net stub. The run() function is never invoked on the normal path —
* G4's executeStep() detects meta.isUserWaitGate and routes to runUserAckGate()
* before the tool-execution block. If this throws, the routing is broken.
*/
export async function run(): Promise<never> {
throw new Error(
"wait_for_user_ack.run() was invoked directly — this should never happen. " +
"G4 is expected to route steps whose tool.meta.isUserWaitGate is true " +
"through runUserAckGate() in electron/agent/guards/execution.ts, bypassing " +
"the normal tool-execution pipeline. Check G4's executeStep() routing.",
);
}