/** * The write the assistant is asking permission for — read from the request * itself, not from the model's description of it. * * ★ WHY THIS EXISTS. In "Take action" mode the in-sandbox helper refuses every * mutation on its first attempt and returns a `CONFIRMATION_REQUIRED` tool * result naming the operation and the exact values it was about to send. The * model is then instructed to describe that change in prose and ask the user. * * So today the user approves a PARAGRAPH. The paragraph is generated by the same * model that wants the write to go through, and nothing checks it against the * payload — a field can be omitted, rounded, or described as something milder * than it is, and the approval still counts. * * The refusal itself is already in the message parts the panel receives, and the * panel throws it away (`getToolProgress` reduces a tool part to * "Completed: "). Reading it back means the confirmation card can show the * operation and values that will actually be sent. * * ★ WHAT THIS IS NOT. It does not make the UI the authorization boundary. The * approval still travels back through the model, which holds the single-use * token and could in principle retry without asking — see the module docstring * in `ai-assistant/src/write-confirmation.ts`, which names the remaining gap and * the fix ("the UI holding the approval"). This narrows what the user can be * misled about; it does not close that. */ export interface PendingWriteValue { key: string; /** Already stringified for display; objects and arrays are JSON. */ value: string; } export interface PendingWrite { /** GraphQL operation name, e.g. `createCrop`. */ operation: string; /** * The variables, flattened for display. `null` when the refusal reported no * variables or the block could not be parsed — the card then falls back to * naming the operation alone rather than implying there is nothing to send. */ values: PendingWriteValue[] | null; /** * The pending change's public reference, when the sandbox emitted one. * * ★★ NOT a token, and the distinction is the whole design. The reference * NAMES the pending write so the panel can approve that exact one; it * authorises nothing on its own. The token never leaves the sandbox — being * shown it is what used to let the model approve itself. * * `null` on a sandbox running an image from before the approval endpoint * existed, in which case the card has nothing to approve WITH and correctly * falls back to asking the user to reply in prose. */ reference: string | null; } /** * A tool part as the transport delivers it. Deliberately loose: `state.output` * is typed `unknown` upstream and different agent versions have wrapped the text * differently, so this accepts anything and proves the shape at runtime. */ interface ToolPartLike { type?: string; state?: { output?: unknown; [key: string]: unknown; } | undefined; } /** * Parse one refusal. * * ★ The single-use token is deliberately NOT extracted. It is a capability: the * write goes through if it is echoed back, so putting it on screen would invite * a user — or anything reading the page — to replay it, and would turn a * confirmation card into a bypass. The card needs the operation and the values; * it never needs the token. */ export declare function parseConfirmationRefusal(text: string): PendingWrite | null; /** * The pending write in a set of message parts, if the agent refused one. * * Takes the LAST match: within a turn the model may be told to stop after the * first refusal, but a turn that somehow produced two is asking about the most * recent one. */ export declare function findPendingWrite(parts: readonly ToolPartLike[] | undefined): PendingWrite | null; export {}; //# sourceMappingURL=pendingWrite.d.ts.map