feat: durable delegated tool approval flow#2966
Conversation
🦋 Changeset detectedLatest commit: f7312d1 The changes in this PR will be included in the next version bump. This PR includes changesets to release 10 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
TL;DR — Routes tool approval requests from delegated sub-agents through the durable workflow hook system (WDK) instead of the in-memory pub/sub bus, fixes a re-delegation loop where approving a delegated tool caused the parent to re-send the original user message instead of continuing with the tool result, and preserves tool denial context across durable workflow steps so the LLM can acknowledge user redirects. Key changes
Summary | 11 files | 6 commits | base: Parent-side detection of delegated approval artifacts
The raw artifact data is now cast through a
Post-approval continuation prompt with denial awareness
The flag is set after each approval round in
Delegated approval forwarding through A2A delegation metadata
The
|
There was a problem hiding this comment.
Solid approach — the artifact-based signaling pattern for durable delegated approvals is a clean replacement for the in-memory pub/sub, and the isPostApproval continuation prompt correctly breaks the re-delegation loop. Three issues to flag, one potentially breaking.
Claude Opus | 𝕏
Preview URLsUse these stable preview aliases for testing this PR:
These point to the same Vercel preview deployment as the bot comment, but they stay stable and easier to find. Raw Vercel deployment URLs
|
There was a problem hiding this comment.
PR Review Summary
(7) Total Issues | Risk: Medium
🟠⚠️ Major (3) 🟠⚠️
Inline Comments:
- 🟠 Major:
tool-wrapper.ts:231Unsafe type coercion of approval artifact fields without validation - 🟠 Major:
agentExecutionSteps.ts:555-576SSE streaming for delegated approvals lacks error handling - 🟠 Major:
agentExecution.ts:82-85Durable workflow hook awaits indefinitely without timeout
🟡 Minor (1) 🟡
Inline Comments:
- 🟡 Minor:
agentExecution.ts:82-86Improve logging for delegated approval debugging
🕐 Pending Recommendations (3)
From pullfrog's prior review (still applicable):
- 🟠
agentExecutionSteps.ts:123baseUrl now includes/run/agents— deviates from bare API root convention used elsewhere - 🟡
relationTools.ts:436Type casting delegationMeta to inject workflow metadata sidesteps type safety - 🟡
agentExecutionSteps.ts:507Continuation prompt dependency on conversation history needs documentation
🚫 REQUEST CHANGES
Summary: The artifact-based signaling pattern is a solid architectural choice for durable delegated approvals, and the isPostApproval continuation prompt correctly addresses the re-delegation loop. However, there are three major issues that should be addressed before merging:
-
Artifact validation — The
durable-approval-requiredartifact fields are used without validation, which could cause silent corruption or unhelpful runtime errors if a sub-agent returns malformed data. -
SSE error handling — The delegated approval SSE streaming block has no error handling. If writes fail, the workflow suspends awaiting approval but the client never receives the approval request UI — a particularly confusing failure mode.
-
Indefinite workflow suspension — Unlike the non-durable path (10-minute timeout), the durable workflow hook can suspend indefinitely. Consider either adding a timeout or documenting the expected cleanup strategy.
The pullfrog findings about baseUrl convention and type casting are worth addressing as follow-ups but are less critical.
Discarded (3)
| Location | Issue | Reason Discarded |
|---|---|---|
agentExecutionSteps.ts:155-167 |
Empty catch blocks in enhanceRelation | Pre-existing code not introduced by this PR |
tool-wrapper.ts:196 |
Nested artifact parsing without bounds | Low likelihood of malicious sub-agent responses in controlled environment |
agentExecutionSteps.ts:503 |
isPostApproval may not survive workflow replays | Workflow engine handles step replay correctly; flag is set consistently in workflow scope |
Reviewers (3)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
pr-review-errors |
4 | 0 | 0 | 0 | 2 | 0 | 2 |
pr-review-sre |
5 | 0 | 0 | 0 | 2 | 0 | 3 |
pr-review-standards |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Total | 9 | 0 | 0 | 0 | 4 | 0 | 5 |
Note: pr-review-standards found no issues — validated that baseUrl change is consistent with existing patterns in executionHandler.ts and data/agents.ts.
There was a problem hiding this comment.
PR Review Summary
(8) Total Issues | Risk: Medium | Review Scope: Delta (1 commit since last review)
This is a re-review scoped to changes in commit 5aea41ec7 ("fix: handle AI SDK stopWhen throw for durable approval detection").
🟠⚠️ Major (1) 🟠⚠️
Inline Comments:
- 🟠 Major:
agentExecutionSteps.ts:533-537Swallowing errors silently when pendingDurableApproval is set
🟡 Minor (1) 🟡
Inline Comments:
- 🟡 Minor:
generateTaskHandler.ts:585-588Catch block suppresses original error without logging
🕐 Pending Recommendations (6)
From prior automated review (claude):
- 🟠
tool-wrapper.ts:231Unsafe type coercion of approval artifact fields without validation - 🟠
agentExecutionSteps.ts:555-576SSE streaming for delegated approvals lacks error handling - 🟠
agentExecution.ts:82-85Durable workflow hook awaits indefinitely without timeout
From pullfrog's prior review:
- 🟠
agentExecutionSteps.ts:123baseUrl now includes/run/agents— deviates from bare API root convention - 🟡
relationTools.ts:436Type casting delegationMeta to inject workflow metadata sidesteps type safety - 🟡
agentExecutionSteps.ts:507Continuation prompt dependency on conversation history needs documentation
🚫 REQUEST CHANGES
Summary: The delta commit (5aea41ec7) correctly addresses the AI SDK stopWhen throw behavior by catching the error and extracting the pending approval state. However, silently discarding caught errors without logging creates a debugging blind spot. When errors are suppressed because pendingDurableApproval exists, engineers have no visibility into what actually failed. Add logging before suppressing these errors.
The 6 pending recommendations from the prior review remain unaddressed and should be considered alongside this delta feedback.
Discarded (1)
| Location | Issue | Reason Discarded |
|---|---|---|
agentExecutionSteps.ts:603-605 |
Error message lacks context | Low severity — the check is effectively dead code given the control flow (if catch re-throws, this line is unreachable) |
Reviewers (1)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
pr-review-errors |
3 | 0 | 0 | 0 | 2 | 0 | 1 |
| Total | 3 | 0 | 0 | 0 | 2 | 0 | 1 |
Note: Delta review — only dispatched error handling reviewer since the changes were focused on error/exception handling patterns.
5aea41e to
f6e94ae
Compare
There was a problem hiding this comment.
PR Review Summary
(0) Total Issues | Risk: Low
This is a re-review following prior feedback from pullfrog and two automated claude reviews. All previously identified issues have been addressed.
✅ Issues Resolved Since Prior Reviews
| Prior Issue | Resolution |
|---|---|
🟠 Unsafe type coercion of approval artifact fields (tool-wrapper.ts:232-245) |
Fixed — Added validation with typeof checks and error logging before using delegatedToolCallId and delegatedToolName |
🟠 SSE streaming for delegated approvals lacks error handling (agentExecutionSteps.ts:583-611) |
Fixed — Wrapped SSE writes in try-catch with error logging and re-throw |
🟠 Durable workflow hook awaits indefinitely (agentExecution.ts:98-101) |
Documented — Comment explains the design decision and cleanup strategy via external job |
🟡 Improve logging for delegated approval debugging (agentExecution.ts:88-96) |
Fixed — Added logger.info with hookToolCallId, parentToolCallId, isDelegated, and workflowRunId |
🟡 Swallowing errors silently when pendingDurableApproval is set (agentExecutionSteps.ts:545-553) |
Fixed — Added logger.info capturing error message, error name, requestId, and currentSubAgentId |
🟡 Catch block suppresses original error without logging (generateTaskHandler.ts:591-598) |
Fixed — Added logger.info with toolCallId, toolName, and error message |
🟡 baseUrl convention deviation (agentExecutionSteps.ts:117-121) |
Documented — Comment explains the intentional deviation for durable mode |
🟡 Type casting delegationMeta (relationTools.ts:434-452) |
Accepted — The spread pattern is safe here since we're adding fields, not removing them |
🟡 Continuation prompt dependency on conversation history (agentExecutionSteps.ts:507-510) |
Documented — Comment explains the dependency on skipHistoryStorage fix |
Architecture Assessment
The artifact-based signaling pattern for durable delegated approvals is well-designed:
- Artifact flow — Sub-agents return
durable-approval-requiredartifacts that the parent'stool-wrapperdetects and propagates throughpendingDurableApproval - Re-delegation loop prevention —
isPostApprovalflag switches to continuation prompt after approval rounds - Delegation metadata forwarding —
durableWorkflowRunIdandapprovedToolCallsflow through A2A metadata - SSE event streaming — Delegated approvals stream the correct
toolCallIdfrom the sub-agent
⚠️ Operational Note
The durable workflow hook (toolApprovalHook.create()) suspends indefinitely by design. The comment at lines 98-101 documents that stale suspended workflows should be cleaned up by an external job querying workflow_executions with status='suspended'. Ensure this cleanup mechanism exists or is planned.
Missing Changeset
The changeset-bot flagged that this PR has no changeset. Since this adds support for tool approvals in delegated sub-agents running in durable execution mode, consider adding:
pnpm bump patch --pkg agents-api "Add support for tool approvals in delegated sub-agents during durable execution"✅ APPROVE
Summary: All prior review feedback has been addressed. The implementation is solid — artifact-based signaling cleanly replaces the in-memory pub/sub for durable delegated approvals, error handling is comprehensive with logging, and the isPostApproval continuation prompt correctly breaks the re-delegation loop. Ship it! 🚀
Reviewers (0)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
| Total | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Note: This re-review validated that all prior findings have been addressed. No new reviewers were dispatched since the diff showed only fixes to previously identified issues.
f6e94ae to
e8954e7
Compare
There was a problem hiding this comment.
PR Review Summary
(0) Total Issues | Risk: Low
This is a re-review triggered by CI re-run. The code is unchanged from the prior APPROVE review — all previously identified issues remain resolved.
✅ Verified Fixes (from prior reviews)
| Prior Issue | Status |
|---|---|
| 🟠 Unsafe type coercion of approval artifact fields | ✅ Fixed — tool-wrapper.ts:232-245 has typeof validation |
| 🟠 SSE streaming lacks error handling | ✅ Fixed — agentExecutionSteps.ts:583-611 has try-catch with re-throw |
| 🟠 Durable workflow hook awaits indefinitely | ✅ Documented — agentExecution.ts:92-95 explains cleanup strategy |
| 🟡 Missing logging for delegated approval debugging | ✅ Fixed — agentExecution.ts:85-90 logs hook details |
| 🟡 Silent error swallowing when pendingDurableApproval set | ✅ Fixed — agentExecutionSteps.ts:545-553 logs caught errors |
| 🟡 Catch block suppresses original error | ✅ Fixed — generateTaskHandler.ts:591-598 logs error context |
| 🟡 baseUrl convention deviation | ✅ Documented — agentExecutionSteps.ts:117-121 explains intentional deviation |
| 🟡 Continuation prompt history dependency | ✅ Documented — agentExecutionSteps.ts:507-510 explains reliance on skipHistoryStorage |
Architecture Assessment
The artifact-based signaling pattern for durable delegated approvals is well-designed:
- Artifact flow — Sub-agents return
durable-approval-requiredartifacts that the parent'stool-wrapperdetects and propagates viapendingDurableApproval - Re-delegation loop prevention —
isPostApprovalflag switches to continuation prompt after approval rounds - Delegation metadata forwarding —
durableWorkflowRunIdandapprovedToolCallsflow through A2A metadata - SSE event streaming — Delegated approvals stream the correct
toolCallIdfrom the sub-agent
⚠️ CI Note
The "Auto Format" workflow failure is a CI infrastructure issue (pnpm setup step), not a code problem.
Missing Changeset
Consider adding a changeset for this feature:
pnpm bump patch --pkg agents-api "Add support for tool approvals in delegated sub-agents during durable execution"✅ APPROVE
Summary: All prior review feedback has been addressed. The implementation is solid — artifact-based signaling cleanly replaces the in-memory pub/sub for durable delegated approvals, error handling is comprehensive with logging, and the isPostApproval continuation prompt correctly breaks the re-delegation loop. Ship it! 🚀
Reviewers (0)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
| Total | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Note: Re-review — validated prior fixes are still present. No new reviewers dispatched.
Follow-up: Duplication beyond tool approval flowsLooking beyond the approval-specific duplication from my previous comment, there are additional sharing opportunities between 1. Task creation — ~60 lines identical in both engines (HIGH)Classic: Both do the exact same thing:
Proposal: Extract a shared 2. Stream/session registration — 3-line sequence repeated 3 times (LOW effort, HIGH clarity)The sequence: registerStreamHelper(requestId, sseHelper);
agentSessionManager.createSession(requestId, executionContext, conversationId);
if (emitOperations) agentSessionManager.enableEmitOperations(requestId);Appears in:
Proposal: 3. OTel baggage propagation — identical 5-line block within durable path (MEDIUM)const bag = (propagation.getBaggage(otelContext.active()) ?? propagation.createBaggage())
.setEntry('conversation.id', { value: conversationId })
.setEntry('tenant.id', { value: tenantId })
.setEntry('project.id', { value: projectId })
.setEntry('agent.id', { value: agentId });
const ctxWithBaggage = propagation.setBaggage(otelContext.active(), bag);Identical in Proposal: 4. Runtime context object — identical 8-line object within durable path (MEDIUM)const runtimeContext = {
contextId: conversationId,
metadata: {
conversationId, threadId: conversationId, taskId,
streamRequestId: requestId, apiKey: executionContext.apiKey,
},
};Identical in Proposal: Not duplication (structurally forced by durable architecture)
Combined extraction summary (both comments)
|
There was a problem hiding this comment.
PR Review Summary
(6) Total Issues | Risk: Medium | Review Scope: Delta + Human Feedback
This is a re-review incorporating the delta since the last automated review (46a02c31a → a74daba31) and addressing the human reviewer's (amikofalvy) outstanding feedback.
Delta Analysis
Commit a74daba31: "Fix tool denial context lost across durable workflow steps"
The delta adds preservation of tool denial context across durable workflow step boundaries:
tool-result-for-conversation-history.ts— Improved denied tool result formatting to include[DENIED BY USER]marker and show both input and denial reasonagentExecution.ts— AddeddenialRedirectsarray accumulator to preserve denials across workflow iterationsagentExecutionSteps.ts— AddedDenialRedirecttype,denialRedirectsparam, and post-approval prompt that acknowledges denials
Assessment: The delta changes are well-structured. The denial context flows correctly: executeToolStep returns denials → agentExecution accumulates them → callLlmStep uses them to construct an appropriate post-approval prompt. This correctly addresses the issue where tool denial context was lost.
🟡 Minor (4) 🟡
🟡 1) agentExecution.ts:90 Use logger utility instead of console.info
Issue: Uses console.info directly while the rest of the codebase uses structured logger.
Why: Bypasses structured logging, making production debugging harder.
Fix: Import and use logger utility.
Refs: Human review comment
🟡 2) agentExecutionSteps.ts:128 Default localhost URL should come from env.ts
Issue: Hardcoded 'http://localhost:3002' fallback appears in multiple places.
Why: Scattered defaults create inconsistency and maintenance burden.
Fix: Source the default from env.ts as the single source of truth.
Refs: Human review comment
🟡 3) tool-wrapper.ts:113 Extract delegate_to_ prefix to constant
Issue: String literal 'delegate_to_' is duplicated across multiple files.
Why: Creates maintenance burden and typo risk.
Fix: Define DELEGATE_TO_PREFIX constant in a shared location.
Refs: Human review comment
🟡 4) tool-wrapper.ts:232 Type validation is defensive but types are weak
Issue: Runtime typeof checks are needed because artifact parsing produces unknown types.
Why: The validation is necessary given the untyped artifact data, but the human reviewer is right that stronger types would be better.
Fix: Define a Zod schema for the durable-approval-required artifact shape and use safeParse for validation, which provides both type safety and runtime validation.
Refs: Human review comments
💭 Consider (1) 💭
💭 1) agent-types.ts:273-289 Extract shared approval types
Issue: The pendingDurableApproval.delegatedApproval shape and DelegatedApprovalContext in agentExecutionSteps.ts are duplicates.
Why: amikofalvy's analysis identified 5+ inline type re-declarations for approval-related shapes. Canonical types would reduce duplication.
Fix: Define and export DelegatedApprovalContext and ToolApprovalDecision types in agent-types.ts, import everywhere.
Refs: amikofalvy's duplication analysis
🕐 Pending Recommendations (6)
From amikofalvy's review (active, unaddressed):
- 🟡
agentExecution.ts:90Use logger util instead of console.info - 🟡
agentExecutionSteps.ts:128Remove hardcoded localhost:3002 default - 🟡
tool-wrapper.ts:113Extract delegate_to_ prefix to constant - 🟡
tool-wrapper.ts:232Enforce stronger types for approval data - 🟡
Agent.ts:165Needs better types for getPendingDurableApproval - 🟡
generateTaskHandler.ts:63Needs better types for buildDurableApprovalResult
✅ Resolved from Prior Automated Reviews
All technical issues from prior automated reviews have been addressed:
- ✅ Artifact validation with
typeofchecks — present attool-wrapper.ts:232-245 - ✅ SSE streaming error handling — present at
agentExecutionSteps.ts:647-655 - ✅ Durable hook timeout documented — present at
agentExecution.ts:97-100 - ✅ Error logging when suppressing — present at
agentExecutionSteps.ts:586-594 - ✅ baseUrl deviation documented — present at
agentExecutionSteps.ts:129-132
✅ Changeset Present
The PR now includes a changeset (tiny-eels-burn.md) for the fix.
💡 APPROVE WITH SUGGESTIONS
Summary: The delta correctly preserves tool denial context across durable workflow steps. The feature implementation is solid — artifact-based signaling cleanly replaces the in-memory pub/sub for durable delegated approvals, and the isPostApproval continuation prompt correctly handles both approvals and denials.
Outstanding items: amikofalvy's 6 active code comments should be addressed. These are reasonable code quality improvements:
- console.info → logger — Simple fix, ensures structured logging
- Hardcoded localhost:3002 — Should come from env.ts
- String literal duplication — Extract
delegate_to_to constant - Weak typing — Consider Zod schemas for approval artifact validation
None are blocking bugs, but resolving them before merge would improve maintainability.
Inline Comments:
- 🟡 Minor:
agentExecution.ts:90Use logger utility - 🟡 Minor:
agentExecutionSteps.ts:128Env.ts for default URL - 🟡 Minor:
tool-wrapper.ts:113Extract delegate prefix constant - 💭 Consider:
agent-types.ts:273-289Shared approval types
Discarded (2)
| Location | Issue | Reason Discarded |
|---|---|---|
agentExecutionSteps.ts:630 |
Inline for loop for chunking instead of chunkString helper |
Valid duplication concern raised by amikofalvy, but addressed as part of broader streamToolApprovalRequest extraction proposal — a follow-up refactor, not a blocking issue |
generateTaskHandler.ts:631 |
console.error instead of logger |
Pre-existing code not introduced by this PR |
Reviewers (2)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
orchestrator |
6 | 0 | 1 | 0 | 4 | 6 | 2 |
pr-review-consistency |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Total | 6 | 0 | 1 | 0 | 4 | 6 | 2 |
Note: This review focused on synthesizing the human reviewer's feedback and validating the delta changes. No sub-reviewers were dispatched since the primary work was addressing amikofalvy's outstanding comments.
…ve redundant localhost fallback
There was a problem hiding this comment.
PR Review Summary
(0) Total Issues | Risk: Low | Review Scope: Delta
This is a re-review scoped to the delta since the last automated review (a74daba31 → 35decfaf4).
Delta Analysis
Single commit: 35decfaf4 Address review: extract tool prefix constants, add shared types, remove redundant localhost fallback
This commit directly addresses amikofalvy's human review feedback:
| Review Comment | Resolution |
|---|---|
| Extract tool prefix to constant | ✅ Added DELEGATE_TOOL_PREFIX and TRANSFER_TOOL_PREFIX constants in tool-wrapper.ts:14-15 |
| Enforce stronger types for approval data | ✅ Added DurableApprovalData interface in tool-wrapper.ts:17-28 |
Better types in generateTaskHandler.ts |
✅ Now uses imported PendingDurableApproval type |
Better types in Agent.ts |
✅ getPendingDurableApproval() returns PendingDurableApproval type |
| Remove hardcoded localhost:3002 default | ✅ Removed fallback at agentExecutionSteps.ts:128 |
✅ All Human Review Comments Addressed (5/6)
The delta resolves 5 of 6 human review comments. The remaining item (console.info → logger at agentExecution.ts:90) is in a file that was not modified in this commit — it was part of the earlier feature implementation that prior automated reviews already covered and approved.
Architecture Assessment
The type improvements are well-structured:
PendingDurableApproval— Canonical shared type inagent-types.ts:225-235eliminates inline type re-declarationsDurableApprovalData— Provides type safety for artifact parsing intool-wrapper.ts- Constants —
DELEGATE_TOOL_PREFIX/TRANSFER_TOOL_PREFIXreduce string literal duplication
🕐 Pending Recommendations (1)
From amikofalvy's review (file not in delta):
- 🟡
agentExecution.ts:90Use logger util instead ofconsole.info
This was flagged in prior reviews and is still applicable, but the file wasn't touched in this commit. Consider addressing as a follow-up or in the same PR before merge.
✅ APPROVE
Summary: The delta commit successfully addresses the human reviewer's feedback — type safety improvements, constant extraction, and removal of the hardcoded localhost fallback. All prior technical issues from automated reviews remain resolved. The only outstanding item is the console.info → logger change at agentExecution.ts:90, which is a minor improvement that can be addressed before merge or as a follow-up. Ship it! 🚀
Reviewers (0)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
| Total | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Note: Delta review — no sub-reviewers dispatched since the changes were direct fixes to prior human review feedback. Verified all type improvements are correct and follow existing patterns.
|
@amikofalvy For this PR scope: the type extraction ( |
There was a problem hiding this comment.
PR Review Summary
(1) Total Issues | Risk: Low | Review Scope: Delta
This is a re-review scoped to the delta since the last automated review (a9be51148 → f7312d16a).
Delta Analysis
The delta consists of:
- Merge commit (
f7312d16a) — mergingmaininto the feature branch (23 commits from main) - Feature code unchanged — all 11 feature files have no modifications in this delta
The merged changes from main include unrelated work: feedback system, scheduled triggers, model resolver fixes, React compiler updates, project deletion improvements, etc. None of these interact with the durable delegated tool approval feature.
🟡 Minor (1) 🟡
Inline Comments:
- 🟡 Minor:
agentExecution.ts:90-95Use structured logger instead ofconsole.info
✅ Prior Issues Resolved
All issues from prior reviews have been addressed:
| Prior Issue | Status |
|---|---|
🟠 Type extraction (PendingDurableApproval) |
✅ Done in 35decfaf4 |
🟠 Artifact validation with typeof checks |
✅ Present at tool-wrapper.ts:250-262 |
| 🟠 SSE streaming error handling | ✅ Present at agentExecutionSteps.ts:647-655 |
| 🟠 Durable hook timeout documented | ✅ Present at agentExecution.ts:97-100 |
| 🟡 Hardcoded localhost:3002 removed | ✅ Done in 35decfaf4 |
| 🟡 Tool prefix constants extracted | ✅ DELEGATE_TOOL_PREFIX/TRANSFER_TOOL_PREFIX in tool-wrapper.ts:14-15 |
🟡 DurableApprovalData interface added |
✅ Present at tool-wrapper.ts:17-28 |
| 🟡 Error logging when suppressing | ✅ Present at agentExecutionSteps.ts:586-594 |
⚠️ Ito Test Failure Note
The Ito test report flagged that the reconnect endpoint (/run/api/executions/{executionId}/stream) misses post-approval continuation events. This is a valid finding but it's a pre-existing issue in executions.ts:344 that exists independently of this PR:
// executions.ts:344 — does NOT use namespace
const readable = run.getReadable({ startIndex });
// chatDataStream.ts:183-194 — DOES use namespace correctly
const namespace = (durableExecution.metadata as any)?.continuationStreamNamespace;
const readable = run.getReadable({ namespace });This PR correctly implements namespace handling in the /run/api/chat path but doesn't modify executions.ts. Consider filing a follow-up issue to align the reconnect endpoint behavior.
Architecture Assessment
The artifact-based signaling pattern for durable delegated approvals is well-designed:
- Artifact flow — Sub-agents return
durable-approval-requiredartifacts that the parent'stool-wrapperdetects and propagates throughpendingDurableApproval - Re-delegation loop prevention —
isPostApprovalflag switches to continuation prompt after approval rounds - Delegation metadata forwarding —
durableWorkflowRunIdandapproved_tool_callsflow through A2A metadata - SSE event streaming — Delegated approvals stream the correct
toolCallIdfrom the sub-agent - Denial context preservation —
DenialRedirecttype tracks denied tools across workflow steps
Human Reviewer Follow-up Items
amikofalvy's analysis identified duplication opportunities for follow-up (acknowledged by author as out of PR scope):
streamToolApprovalRequest()helper (4 copies of SSE approval sequence)createOrReuseTask()(60 lines × 2 engines)setupStreamSession()(3-line sequence × 3 locations)- Canonical types for approval shapes
✅ APPROVE
Summary: The delta contains only a merge from main — no modifications to the feature implementation. All prior review feedback has been addressed and verified. The one remaining minor issue (console.info → logger) is low-severity and doesn't block merge.
The implementation is solid: artifact-based signaling cleanly replaces the in-memory pub/sub for durable delegated approvals, comprehensive error handling with logging, and the isPostApproval continuation prompt correctly breaks the re-delegation loop. The Ito test failure is a pre-existing issue in a different file — recommend filing a follow-up issue. Ship it! 🚀
Discarded (1)
| Location | Issue | Reason Discarded |
|---|---|---|
executions.ts:344 |
Missing namespace in reconnect stream | Pre-existing issue not introduced by this PR — recommend follow-up issue |
Reviewers (0)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
| Total | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
Note: Delta review — no sub-reviewers dispatched since feature code is unchanged. Only verified prior fixes remain in place and analyzed the merge commit scope.
| parentToolCallId: toolCall.toolCallId, | ||
| isDelegated: !!llmResult.delegatedApproval, | ||
| workflowRunId, | ||
| }); |
There was a problem hiding this comment.
🟡 Minor: Use structured logger instead of console.info
Issue: Uses console.info directly while the rest of the codebase uses the structured logger utility.
Why: Using console.info bypasses structured logging, making production debugging harder. Log aggregation systems can't filter/search by logger name, and the output lacks the consistent formatting used elsewhere.
Fix:
import { getLogger } from '../../../../logger';
const logger = getLogger('agentExecution');
// Then at line 90:
logger.info({
hookToolCallId,
parentToolCallId: toolCall.toolCallId,
isDelegated: !!llmResult.delegatedApproval,
workflowRunId,
}, 'Creating tool approval hook');Refs:
Ito Test Report ✅15 test cases ran. 2 additional findings, 13 passed. Across 15 end-to-end and code-verified cases, 13 passed and core durable delegated-approval behavior was broadly validated: approval and denial continuations worked, denied-result formatting and history persistence guards were correct, endpoint-based resume by executionId/toolCallId succeeded, race/navigation/mobile UX scenarios were stable and idempotent, and stale approval replay plus guessed stream probing showed no data-leak side effects. The two key defects were a High-severity bug in POST /run/api/chat where batched approvals are incorrectly scoped to one latest conversation execution (dropping additional toolCallId decisions and leaving runs inconsistent) and a Medium-severity auth issue where unauthenticated /run/api requests in dev/test fall through to a fabricated default context and return 404 Project not found instead of 401/403. ✅ Passed (13)ℹ️ Additional Findings (2)
🟠 Unauthenticated run API requests return 404 via dev fallback instead of 401/403
Relevant code:
app.use('/run/tenants/*', runApiKeyAuthExcept(isWebhookRoute));
app.use('/run/agents/*', runApiKeyAuth());
app.use('/run/v1/*', runApiKeyAuth());
app.use('/run/api/*', runApiKeyAuth());
const isDev = process.env.ENVIRONMENT === 'development' || process.env.ENVIRONMENT === 'test';
// Development/test environment handling
if (isDev) {
logger.info({}, 'development environment');
const attempt = await authenticateRequest(reqData);
if (attempt.authResult) {
c.set('executionContext', buildExecutionContext(attempt.authResult, reqData));
} else {
logger.info(
{},
reqData.apiKey
? 'Development/test environment - fallback to default context due to invalid API key'
: 'Development/test environment - no API key provided, using default context'
);
c.set('executionContext', buildExecutionContext(createDevContext(reqData), reqData));
}
if (error.isNotFound) {
return c.json(
{
error: 'Project not found',
message: `Project ${projectId} not found for tenant ${tenantId}`,
},
404
);
}
|
Summary
Fixes PRD-6419