Skip to content

fix(web,myra): chat shows pending approvals inline; a parked approval no longer aborts Myra's run (CL-8493) - #896

Merged
TheGreatAxios merged 2 commits into
mainfrom
cl-8492-chat-approvals
Sep 18, 2026
Merged

TheGreatAxios merged 2 commits into
mainfrom
cl-8492-chat-approvals

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Contributor

What

Chat page answers approvals. ApprovalRow moved out of workbench-room-page.tsx into apps/web/src/chat/approval-row.tsx; the room page imports it unchanged. chat-thread-page.tsx's transcript now calls usePendingApprovals(tenantId) and renders the asks raised by this chat's agent — filtered on agentAddress === chat.agent.liveAddress — inline above the composer. PendingApproval carries agentAddress (already on the stock ApprovalResponse) so the filter needs no extra read. The existing SSE inbox subscription now invalidates tenantKeys.pendingApprovals alongside the chat scope, and approve/deny already invalidate it in onSuccess.

Myra's run survives a parked approval. Her step no longer sets a timeout; buildMyraWorkflow's MyraWorkflowInput drops turnTimeoutMs and its positive-integer guard, and ASSISTANT_TURN_TIMEOUT_MS is gone from myra-deploy.ts (both the JSON projection and the bundle build input).

Why

A step's timeout is an execution budget that stays armed across an approval park. vendor/intx/workflow/src/runtime/run.ts (~1491) is explicit: "Each input park below disarms it before waiting and re-arms a fresh budget on resume; the approval park stays armed." So the 2-minute budget kept counting while the run_shell ask sat pending, stepAbort.abort() fired, and the step failed with {"message":"aborted"}, failing the run and releasing the deployment. The approval itself never expires on its own — the stock row had timeoutAt: null, the documented hold-indefinitely case — so the step timer was the only clock.

timeout is optional on StepPrimitive (definition/primitives.ts:84) and armStepTimer installs no timer when it is undefined, so omitting it is the supported unbounded shape rather than a large magic number. That matches upstream's own long-lived warm agent: ~/abklabs/interchange/tests/workflow-deploy/fixtures/single-step-mail-inbox-agent.ts builds the triggers: "unbounded" mail-triggered step as a bare step({ agent }) with no timeout, and single-step-mail-interactive-turns.test.ts services multiple turns on that one run. The old "a wedged inference call would hang a run forever" rationale is not worth aborting every human-in-the-loop turn; an outer cancellation still aborts the step independently of the timer.

What a decision returns to the agent: a resolve is a control signal, not a step outcome. hub-api/src/routes/approvals.ts enqueues a signal keyed on the approval's correlationId, and workflow-host/src/adapters/step-invoker.ts (buildSendMessage, ~719) delivers approve and reject back to the parked reactor as a correlated InboundMessage. So a denial resumes the same turn as tool-level feedback — the reject route's optional message is described upstream as "feedback to the agent" — it is not a step failure. A timeout/expired approval status would likewise come back through the gate; with timeoutAt: null no such deadline is set today.

Verified

bunx tsc -p apps/web --noEmit, bun run typecheck, bun run lint, bun run fmt, apps/web bun run build + bun test ./src (582 pass), agents/myra bun run build + bun test ./src (3 pass).

agents/myra/src/definition.test.ts swapped its timeout pin for the inverse assertion — the step must carry no timeout. Genuine red/green: it fails against the old definition and is the regression guard for this fix.

Not verified

No live run: the dev stack was not started, so the parked-approval-then-approve path was not exercised end to end against a real sidecar, and the chat approval card was not seen rendered in a browser. The reasoning above is read off the vendored runtime and upstream's fixtures.

@linear-code

linear-code Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

CL-8493

CL-8492

@TheGreatAxios
TheGreatAxios merged commit d6e8333 into main Sep 18, 2026
4 checks passed
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.

1 participant