docs: document exec approval followups

This commit is contained in:
Peter Steinberger
2026-06-04 06:07:16 -04:00
parent 11eb9ac1b9
commit e5f3bf99cc
3 changed files with 19 additions and 3 deletions

View File

@@ -1,3 +1,8 @@
/**
* Runtime handoff state for exec approval follow-up turns.
* Stores short-lived elevated defaults so an approved async exec can resume in
* the same session without persisting approval capabilities.
*/
import { randomUUID } from "node:crypto";
import {
isFutureDateTimestampMs,
@@ -6,13 +11,11 @@ import {
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
import type { ExecElevatedDefaults } from "./bash-tools.exec-types.js";
// Short-lived in-memory handoff state for exec approval follow-up turns. The
// handoff carries elevated defaults across the approval response without
// persisting operator approval state longer than the TTL.
const EXEC_APPROVAL_FOLLOWUP_IDEMPOTENCY_PREFIX = "exec-approval-followup:";
const EXEC_APPROVAL_FOLLOWUP_IDEMPOTENCY_NONCE_MARKER = ":nonce:";
const EXEC_APPROVAL_FOLLOWUP_RUNTIME_HANDOFF_TTL_MS = 5 * 60 * 1000;
/** Single-use capability payload consumed by a follow-up agent turn. */
export type ExecApprovalFollowupRuntimeHandoff = {
kind: "exec-approval-followup";
approvalId: string;
@@ -21,6 +24,7 @@ export type ExecApprovalFollowupRuntimeHandoff = {
bashElevated: ExecElevatedDefaults;
};
/** Registration handle returned to the gateway approval callback. */
export type ExecApprovalFollowupRuntimeHandoffRegistration = {
handoffId: string;
idempotencyKey: string;

View File

@@ -1,3 +1,8 @@
/**
* Exec approval follow-up delivery tests.
* Covers denied prompts, agent-session resume, wait handling, direct fallback,
* and elevated runtime handoff routing.
*/
import { afterEach, describe, expect, it, vi } from "vitest";
vi.mock("./tools/gateway.js", () => ({

View File

@@ -1,3 +1,8 @@
/**
* Delivery orchestration for async exec approval follow-ups.
* Resumes the originating agent session when possible and falls back to safe
* direct delivery only when session resume is unavailable.
*/
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalString,
@@ -61,6 +66,7 @@ function formatUnknownError(error: unknown): string {
}
}
/** Builds the prompt used to resume an agent after an approved async exec completes. */
export function buildExecApprovalFollowupPrompt(resultText: string): string {
const trimmed = resultText.trim();
if (isExecDeniedResultText(trimmed)) {
@@ -270,6 +276,7 @@ async function sendDirectFollowupFallback(params: {
return true;
}
/** Sends an exec approval follow-up via session resume or safe direct delivery. */
export async function sendExecApprovalFollowup(
params: ExecApprovalFollowupParams,
): Promise<boolean> {