Skip to content

feat(docs): HUMAN IN THE LOOP - User consent for some tools execution - #109

Merged
murdore merged 1 commit into
juspay:releasefrom
yugesh-ganipudi:BZ-7308188-Doc-for-Human-In-The-Loop-UserConsent-For-Tool-Execution
Aug 19, 2025
Merged

murdore merged 1 commit into
juspay:releasefrom
yugesh-ganipudi:BZ-7308188-Doc-for-Human-In-The-Loop-UserConsent-For-Tool-Execution

Conversation

@yugesh-ganipudi

@yugesh-ganipudi yugesh-ganipudi commented Aug 19, 2025 •

Copy link
Copy Markdown
Contributor

Pull Request

Description

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🧹 Code refactoring (no functional changes)
  • ⚡ Performance improvement
  • 🧪 Test coverage improvement
  • 🔧 Build/CI configuration change

Related Issues

  • Fixes #
  • Related to #

Changes Made

  • Added doc for HUMAN IN THE LOOP - Adding user consent for some tools execution

AI Provider Impact

  • OpenAI
  • Anthropic
  • Google AI/Vertex
  • AWS Bedrock
  • Azure OpenAI
  • Hugging Face
  • Ollama
  • Mistral
  • All providers
  • No provider-specific changes

Component Impact

  • CLI
  • SDK
  • MCP Integration
  • Streaming
  • Tool Calling
  • Configuration
  • Documentation
  • Tests

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • E2E tests added/updated
  • Manual testing performed
  • All existing tests pass

Test Environment

  • OS:
  • Node.js version:
  • Package manager:

Performance Impact

  • No performance impact
  • Performance improvement
  • Minor performance impact (acceptable)
  • Significant performance impact (needs discussion)

Breaking Changes

Screenshots/Demo

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

Additional Notes

Summary by CodeRabbit

  • Documentation
    • Added a comprehensive Human-in-the-Loop (HITL) guide for secure AI tool execution.
    • Explains two-step permission flow, risky tools, core components, and init/execution workflows.
    • Includes quick-start examples, diagrams, best practices, FAQs, benefits, and getting-started steps.
    • Highlights security features: one-time permissions, no reuse, audit trails, fail-safe defaults.
    • Documentation-only change; no code or API modifications.

@coderabbitai

coderabbitai Bot commented Aug 19, 2025 •

Copy link
Copy Markdown

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Added a new documentation file describing a Human-in-the-Loop pattern for secure AI tool execution, including definitions, two-step permission flow, components, technical workflow, TypeScript quick-start snippets, diagrams, security features, risk criteria, best practices, FAQs, and getting-started steps. No source code or public APIs were changed.

Changes

Cohort / File(s) Summary
Documentation: HITL pattern
docs/HUMAN-IN-THE-LOOP.md
New doc outlining HITL tool execution pattern, concepts, two-phase workflow, TypeScript examples, Mermaid diagrams, security practices, and FAQs; documentation-only with no code or API changes.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~2 minutes

Poem

A whisk of ears, I read the lore,
Two steps to knock on the tooling door.
Ask, then act—one hop, then halt,
Trails to audit, safe by default.
With charts and code, I thump in cheer—
HITL secured, the path is clear! 🐇✨

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (8)
docs/HUMAN-IN-THE-LOOP.md (8)

159-165: Enrich tool metadata with identity and risk rationale.

Add a stable toolId and rationale to help registries, policy engines, and audits.

Apply this diff:

-// Mark a tool as requiring confirmation
-const deleteFileTool = {
-  name: "deleteFile",
-  description: "Deletes a file from the filesystem",
-  requiresConfirmation: true, // ← This makes it safe!
-};
+// Mark a tool as requiring confirmation (with identity and rationale)
+const deleteFileTool = {
+  toolId: "file.delete",               // stable identifier
+  name: "deleteFile",
+  description: "Deletes a file from the filesystem",
+  requiresConfirmation: true,          // policy gate
+  riskRationale: [
+    "Irreversible deletion",
+    "Potential data loss",
+  ],
+};

65-77: Use consistent naming (camelCase) and avoid global, mutable flags in diagrams.

Mixing confirmation_received (snake_case) with requiresConfirmation (camelCase) is inconsistent, and the notion of a global flag is risky. Prefer confirmationReceived or, better, a “grant” concept.

Apply this diff for naming consistency in the sequence diagram:

-    Note right of Tool Executor: Tool requires confirmation<br/>and confirmation_received is false.
+    Note right of Tool Executor: Tool requires confirmation<br/>and confirmationReceived is false.
@@
-        Note right of Tool Executor: confirmation_received is now true.<br>Reset it to false and execute the tool.
+        Note right of Tool Executor: A valid one-time grant is present.<br>Consume it atomically and execute the tool.

Follow-up: elsewhere replace confirmation_received with a one-time grant model.


134-139: Replace confirmation_received checks with “has valid one-time grant?” and adjust UI step.

Aligns terminology and security model in the flowchart.

Apply this diff:

-        C -- Yes --> E{"Is confirmation_received?"};
+        C -- Yes --> E{"Valid one-time grant for this request?"};
-        E -- No --> F["Return 'Confirmation Required' to LLM"];
+        E -- No --> F["Return USER_CONFIRMATION_REQUIRED"];
@@
-        H -- Yes --> I["UI sets confirmation_received = true"];
+        H -- Yes --> I["UI requests/receives a signed grant from backend"];

93-98: Tighten risk criteria wording and include network/internal access.

“Change databases” is vague; add internal network access as risky.

Apply this diff:

-- **Change databases** (data modifications)
+- **Modify databases** (writes, schema changes, bulk updates)
@@
 - **Access sensitive data** (privacy concerns)
+- **Access internal networks/services** (lateral movement, data exfiltration)

151-153: Clarify audit logging to avoid sensitive-data leakage.

Recommend logging digests/summaries rather than raw params and define retention.

Apply this diff:

-- **Clear audit trail** - Everything is logged for accountability
+- **Privacy-respecting audit trail** - Log toolId, requestId, params digests (not raw data), userId, timestamps; define retention and access controls

193-207: Add developer best practices: idempotency, dry-run/preview, RBAC, rate limits, and server-side enforcement.

These guardrails materially improve safety in production.

Apply this diff:

 - **Test the flow** - Ensure confirmations work smoothly in your UI
 - **Log everything** - Keep records of what users approved
+- **Prefer dry-run/preview** - Provide diffs or impact summaries before execution
+- **Enforce server-side** - Executor must validate/consume grants; never trust client or LLM text
+- **Ensure idempotency** - Use idempotency keys to prevent duplicate side effects on retries
+- **Apply RBAC/ABAC** - Restrict who can approve which tools/scopes
+- **Rate limit & budget guardrails** - Cap frequency/cost for risky tools
+- **Handle concurrency** - Support multiple pending confirmations keyed by requestId

15-18: Minor wording tighten-up.

Eliminate “by mistake” duplication and use more direct phrasing.

Apply this diff:

-- Modify important data by mistake
+- Accidentally modify important data

224-231: Optional: add a row about auditability and replay protection.

Helps readers understand the token/consumption benefits.

Apply this diff:

 | ❌ No audit trail            | ✅ Clear accountability     |
+| ❌ Flags can be replayed     | ✅ One-time, scope-bound grants |
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a15d975 and 85ff454.

📒 Files selected for processing (1)
  • docs/HUMAN-IN-THE-LOOP.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
docs/HUMAN-IN-THE-LOOP.md

[style] ~16-~16: ‘by mistake’ might be wordy. Consider a shorter alternative.
Context: ...the wrong files - Modify important data by mistake - Trigger costly operations you didn't ...

(EN_WORDINESS_PREMIUM_BY_MISTAKE)


[grammar] ~24-~24: There might be a mistake here.
Context: ...ou time to review what's about to happen - ✅ Putting you in control - You decid...

(QB_NEW_EN)


[style] ~38-~38: You have already used this phrasing in nearby sentences. Consider replacing it to add variety to your writing.
Context: ...ou first 2. It explains exactly what it wants to do 3. It waits for your response ### S...

(REP_WANT_TO_VB)


[grammar] ~93-~93: There might be a mistake here.
Context: ...lete or modify files** (file operations) - Change databases (data modifications) ...

(QB_NEW_EN)


[grammar] ~94-~94: There might be a mistake here.
Context: ...Change databases* (data modifications) - Cost money (paid API calls) - **Can't ...

(QB_NEW_EN)


[grammar] ~95-~95: There might be a mistake here.
Context: ...tions) - Cost money (paid API calls) - Can't be undone (irreversible actions)...

(QB_NEW_EN)


[grammar] ~96-~96: There might be a mistake here.
Context: ...Can't be undone** (irreversible actions) - Access sensitive data (privacy concern...

(QB_NEW_EN)


[grammar] ~213-~213: There might be a mistake here.
Context: ...n off confirmations for tools I trust?** A: Yes, developers can adjust which tool...

(QB_NEW_EN)


[grammar] ~216-~216: There might be a mistake here.
Context: ...happens if I accidentally click "yes"?** A: The permission is only used once, so ...

(QB_NEW_EN)


[grammar] ~219-~219: There might be a mistake here.
Context: ...Q: Can the AI remember my preferences?** A: Not automatically - each risky action...

(QB_NEW_EN)


[grammar] ~224-~224: There might be a mistake here.
Context: ... | With HITL | | ---------------------------- | -------...

(QB_NEW_EN)


[grammar] ~225-~225: There might be a mistake here.
Context: ...-------- | --------------------------- | | ❌ AI acts immediately | ✅ AI ask...

(QB_NEW_EN)


[grammar] ~226-~226: There might be a mistake here.
Context: ...ely | ✅ AI asks permission first | | ❌ Mistakes can be costly | ✅ Mistak...

(QB_NEW_EN)


[grammar] ~227-~227: There might be a mistake here.
Context: ...costly | ✅ Mistakes are prevented | | ❌ User feels out of control | ✅ User s...

(QB_NEW_EN)


[grammar] ~228-~228: There might be a mistake here.
Context: ...f control | ✅ User stays in control | | ❌ Trust issues | ✅ Trust ...

(QB_NEW_EN)


[grammar] ~229-~229: There might be a mistake here.
Context: ... | ✅ Trust is built | | ❌ No audit trail | ✅ Clear ...

(QB_NEW_EN)


[grammar] ~234-~234: There might be a mistake here.
Context: ...s** - What actions could cause problems? 2. Implement confirmation flow - Add the ...

(QB_NEW_EN)

Comment thread docs/HUMAN-IN-THE-LOOP.md
Comment on lines +69 to +71
LLM->>Application UI: 3. "I need to delete /tmp/log.txt. Is it okay?"

alt User Confirms

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Do not trust LLM text for permission gating; the executor/UI must enforce policy.

Clarify that the UI prompt is triggered by the executor’s policy decision and metadata, not because “the LLM asked.” This mitigates prompt-injection and social engineering.

Apply this diff:

-    LLM->>Application UI: 3. "I need to delete /tmp/log.txt. Is it okay?"
+    LLM->>Application UI: 3. Request indicates deletion of /tmp/log.txt
+    Note over Application UI: The confirmation prompt is driven by the executor's policy & metadata, not by LLM text.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
LLM->>Application UI: 3. "I need to delete /tmp/log.txt. Is it okay?"
alt User Confirms
LLM->>Application UI: 3. Request indicates deletion of /tmp/log.txt
Note over Application UI: The confirmation prompt is driven by the executor's policy & metadata, not by LLM text.
alt User Confirms

Comment thread docs/HUMAN-IN-THE-LOOP.md
Comment on lines +103 to +107
1. **Confirmation Flag** - Tools are marked as `requiresConfirmation: true`
2. **Smart Registry** - System tracks which tools need approval
3. **Execution Wrapper** - Intercepts risky tool calls
4. **Permission State** - Remembers your "yes" for exactly one operation

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Reframe “Permission State” as a one-time permission grant (token) with scope and TTL.

A mutable “state/flag” invites replay and cross-request reuse. Define it as a verifiable, consumable grant bound to the exact action.

Apply this diff:

-4. **Permission State** - Remembers your "yes" for exactly one operation
+4. **One-time Permission Grant (token)** - A verifiable, single-use grant bound to {requestId, toolId, paramsDigest} with a short TTL; validated and consumed atomically by the executor
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
1. **Confirmation Flag** - Tools are marked as `requiresConfirmation: true`
2. **Smart Registry** - System tracks which tools need approval
3. **Execution Wrapper** - Intercepts risky tool calls
4. **Permission State** - Remembers your "yes" for exactly one operation
1. **Confirmation Flag** - Tools are marked as `requiresConfirmation: true`
2. **Smart Registry** - System tracks which tools need approval
3. **Execution Wrapper** - Intercepts risky tool calls
4. **One-time Permission Grant (token)** - A verifiable, single-use grant bound to {requestId, toolId, paramsDigest} with a short TTL; validated and consumed atomically by the executor
🤖 Prompt for AI Agents
In docs/HUMAN-IN-THE-LOOP.md around lines 103 to 107, replace the mutable
"Permission State" bullet with a description that it's a one-time permission
grant (token) with explicit scope and TTL: explain that the grant must be
cryptographically verifiable and consumable, bound to the exact action
(action-id and user-id), include an expiration (TTL) and allowed scope, and must
be marked consumed on first use to prevent replay; describe acceptable
implementation patterns (signed short-lived token or server-side single-use
entry keyed by nonce) and note that mutable flags must be replaced by verifiable
single-use tokens that are invalidated after consumption.

Comment thread docs/HUMAN-IN-THE-LOOP.md
Comment on lines +129 to +145
flowchart TD
subgraph "Execution: The Confirmation Checkpoint"
A["LLM requests to execute a tool"] --> B["Call executeTool"];
B --> C{"Is tool in confirmation list?"};
C -- No --> D["Execute tool directly"];
C -- Yes --> E{"Is confirmation_received?"};
E -- No --> F["Return 'Confirmation Required' to LLM"];
E -- Yes --> G["Reset flag & Execute tool"];
F --> H{"User is prompted"};
H -- Yes --> I["UI sets confirmation_received = true"];
H -- No --> L["Terminate & Inform LLM"];
I --> B;
D --> K["Return final result"];
G --> K;
L --> K;
end
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Update flowchart to validate a scoped grant instead of a global confirmation flag.

The decision point should verify a valid, single-use grant bound to requestId/tool/params, not a shared flag. This eliminates TOCTOU and concurrent-call hazards.

Apply this diff in the Mermaid block:

-        C -- Yes --> E{"Is confirmation_received?"};
-        E -- No --> F["Return 'Confirmation Required' to LLM"];
-        E -- Yes --> G["Reset flag & Execute tool"];
+        C -- Yes --> E{"Valid one-time grant for {requestId, toolId, paramsDigest}?"};
+        E -- No --> F["Return USER_CONFIRMATION_REQUIRED with {requestId, toolId, paramsDigest}"];
+        E -- Yes --> G["Consume grant atomically & Execute tool"];
-        H -- Yes --> I["UI sets confirmation_received = true"];
-        H -- No --> L["Terminate & Inform LLM"];
+        H -- Yes --> I["UI requests a signed one-time grant from backend"];
+        H -- No --> L["Terminate & Inform LLM"];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
flowchart TD
subgraph "Execution: The Confirmation Checkpoint"
A["LLM requests to execute a tool"] --> B["Call executeTool"];
B --> C{"Is tool in confirmation list?"};
C -- No --> D["Execute tool directly"];
C -- Yes --> E{"Is confirmation_received?"};
E -- No --> F["Return 'Confirmation Required' to LLM"];
E -- Yes --> G["Reset flag & Execute tool"];
F --> H{"User is prompted"};
H -- Yes --> I["UI sets confirmation_received = true"];
H -- No --> L["Terminate & Inform LLM"];
I --> B;
D --> K["Return final result"];
G --> K;
L --> K;
end
```
flowchart TD
subgraph "Execution: The Confirmation Checkpoint"
A["LLM requests to execute a tool"] --> B["Call executeTool"];
B --> C{"Is tool in confirmation list?"};
C -- No --> D["Execute tool directly"];
C -- Yes --> E{"Valid one-time grant for {requestId, toolId, paramsDigest}?"};
E -- No --> F["Return USER_CONFIRMATION_REQUIRED with {requestId, toolId, paramsDigest}"];
E -- Yes --> G["Consume grant atomically & Execute tool"];
F --> H{"User is prompted"};
H -- Yes --> I["UI requests a signed one-time grant from backend"];
H -- No --> L["Terminate & Inform LLM"];
I --> B;
D --> K["Return final result"];
G --> K;
L --> K;
end
🤖 Prompt for AI Agents
In docs/HUMAN-IN-THE-LOOP.md around lines 129 to 145, the flowchart currently
checks a shared confirmation_received flag; replace that decision with a
validation of a single-use, scoped grant bound to requestId/tool/params (e.g.,
"Is valid grant for requestId/tool/params?"), branch No to return "Confirmation
Required" or reject, branch Yes to invalidate the grant and execute the tool,
and add an explicit transition for grant invalidation/reset after use to prevent
TOCTOU and concurrent-call hazards while keeping the rest of the flow intact.

Comment thread docs/HUMAN-IN-THE-LOOP.md
Comment on lines +170 to +180
// When AI requests risky action
if (toolRequiresConfirmation && !userHasConfirmed) {
// Show user a confirmation dialog
showConfirmationDialog({
action: "Delete file",
details: "This will permanently delete 'important.txt'",
onConfirm: () => executeToolSafely(),
onCancel: () => tellAIUserSaidNo(),
});
}
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Bind UI confirmation to a specific request and include a preview/impact summary.

Tie the prompt to requestId and a params digest; capture cost/time estimates and show a diff/preview if available. The UI should request a signed grant from backend rather than toggling state locally.

Apply this diff:

-// When AI requests risky action
-if (toolRequiresConfirmation && !userHasConfirmed) {
-  // Show user a confirmation dialog
-  showConfirmationDialog({
-    action: "Delete file",
-    details: "This will permanently delete 'important.txt'",
-    onConfirm: () => executeToolSafely(),
-    onCancel: () => tellAIUserSaidNo(),
-  });
-}
+// When AI requests risky action
+if (toolRequiresConfirmation && !hasValidGrant(requestId)) {
+  // Show user a confirmation dialog (scoped to this requestId)
+  showConfirmationDialog({
+    action: "Delete file",
+    details: "This will permanently delete 'important.txt'",
+    paramsDigest,          // display canonicalized params summary
+    costEstimate,          // optional: estimated cost/time/affected records
+    preview: changePreview, // optional: dry-run/diff if tool supports it
+    onConfirm: async () => {
+      const grant = await requestPermissionGrant({ requestId, toolId, paramsDigest });
+      await executeToolSafely(grant);
+    },
+    onCancel: () => tellAIUserSaidNo({ requestId }),
+  });
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// When AI requests risky action
if (toolRequiresConfirmation && !userHasConfirmed) {
// Show user a confirmation dialog
showConfirmationDialog({
action: "Delete file",
details: "This will permanently delete 'important.txt'",
onConfirm: () => executeToolSafely(),
onCancel: () => tellAIUserSaidNo(),
});
}
```
// When AI requests risky action
if (toolRequiresConfirmation && !hasValidGrant(requestId)) {
// Show user a confirmation dialog (scoped to this requestId)
showConfirmationDialog({
action: "Delete file",
details: "This will permanently delete 'important.txt'",
paramsDigest, // display canonicalized params summary
costEstimate, // optional: estimated cost/time/affected records
preview: changePreview, // optional: dry-run/diff if tool supports it
onConfirm: async () => {
const grant = await requestPermissionGrant({ requestId, toolId, paramsDigest });
await executeToolSafely(grant);
},
onCancel: () => tellAIUserSaidNo({ requestId }),
});
}

Comment thread docs/HUMAN-IN-THE-LOOP.md
Comment on lines +185 to +191
// Only execute after user confirms
function executeToolSafely() {
setUserConfirmation(true); // Grant permission
executeTool(); // Run the tool
setUserConfirmation(false); // Reset permission immediately
}
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace boolean toggle with one-time, scope-bound permission grant to avoid race/replay.

The boolean setUserConfirmation(true/false) is unsafe in concurrent/async contexts. It can be reused by another in-flight tool call (race), replayed later, or flipped by compromised UI. Use a one-time permission token bound to requestId + toolId + params digest with a short TTL, and consume it atomically on the server-side executor.

Apply this diff to the snippet:

-// Only execute after user confirms
-function executeToolSafely() {
-  setUserConfirmation(true); // Grant permission
-  executeTool(); // Run the tool
-  setUserConfirmation(false); // Reset permission immediately
-}
+// Only execute after user confirms — use a one-time, scope-bound grant
+async function executeToolSafely(grant: { requestId: string; token: string }) {
+  // The executor must validate and CONSUME the grant atomically server-side.
+  await executeTool({ requestId: grant.requestId, permissionToken: grant.token });
+}

Support code to add outside this snippet (for clarity):

// Executor-side (authoritative):
// - Verifies token signature
// - Ensures token matches {requestId, toolId, paramsDigest}
// - Checks TTL and nonces
// - Consumes/invalidates the token atomically before executing
type PermissionGrant = {
  requestId: string;
  toolId: string;
  paramsDigest: string; // e.g., SHA-256 of canonicalized params
  exp: number;          // unix epoch ms
  jti: string;          // unique nonce (prevent replay)
  sig: string;          // signature (HMAC/JWT/etc.)
};
🤖 Prompt for AI Agents
In docs/HUMAN-IN-THE-LOOP.md around lines 185 to 191, replace the unsafe boolean
toggle pattern with a one-time, scope-bound permission token: stop calling
setUserConfirmation(true/false); instead generate/obtain a PermissionGrant token
tied to {requestId, toolId, paramsDigest} with exp and jti, pass that token into
the executor call, and have the executor verify signature, TTL,
request/tool/params match and atomically consume/invalidate the token before
executing the tool; update the snippet to accept and forward the token rather
than toggling shared state and remove any immediate boolean resets.

@murdore
murdore force-pushed the BZ-7308188-Doc-for-Human-In-The-Loop-UserConsent-For-Tool-Execution branch from 85ff454 to ed549c7 Compare August 19, 2025 15:14
@murdore
murdore merged commit 3f8db51 into juspay:release Aug 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants