feat(interactions): generic agent interaction-request bridge (Claude + Codex permission capture) - #112
Conversation
Introduce a pure, in-memory InteractionRegistry and request model (permission/exit_plan/question/input) with register/resolve/cancel/wait (timeout + abort). Extend AgentAttentionState with needs_response and AlertKind with interaction_request plus an actionable `interaction` payload on AlertEvent. No server/hook wiring yet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add register/wait(long-poll)/respond/pending HTTP endpoints under /agents/interaction/*, an actionable interaction_request alert (forwarded through publishAlert), and pendingInteractions on /desktop-state. The registry is a per-server instance. Validate object payload/response and only clear attention when still needs_response. Covered by HTTP integration tests (register -> wait -> respond, pending, timeout, 400/409). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…equest hook
Inject a PermissionRequest hook (120s) that routes "ask"-gated permission
prompts through the interaction registry: the claude-hook permission-request
action registers + long-polls POST /agents/interaction/request and prints the
allow/deny decision Claude honors, or {} to defer to the native tmux prompt.
Watcher-gating: a GET /agents/interaction/stream SSE endpoint tracks connected
interaction clients; /request blocks only when a watcher is present, otherwise
returns watching:false so the hook defers instantly (no ~110s block in the
default no-client case). Clear lingering needs_response on non-resolved settle.
Verified end-to-end with the built CLI: no-watcher defers in ~200ms; a watched
request blocks and resolves to behavior:allow on approve.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ude) Port the codex hook subsystem onto this branch and add PermissionRequest capture. codex-hooks.ts writes a merge-preserving ~/.codex/hooks.json (only replaces aimux-owned entries, so it coexists with cmux) and enables hooks per-launch via -c features.hooks=true --dangerously-bypass-hook-trust (no config.toml mutation). The codex-hook command's permission-request action and the claude one now share resolvePermissionRequestOutput, routing both through POST /agents/interaction/request. session-launch wires installCodexHooks + launch args + AIMUX_SESSION_ID/AIMUX_PROJECT_ROOT env for codex. Verified end-to-end with the built CLI: codex-hook defers in ~200ms with no watcher and resolves to behavior:allow when a watcher approves. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
More reviews will be available in 10 minutes and 46 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (12)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
…growth, watcher safety) - /request: reset needs_response on client disconnect, not only on the normal-return path, so a killed hook doesn't strand the attention state. - /respond: clear attention via listPending (handles concurrent interactions) instead of a stale loadMetadataState disk read. - InteractionRegistry: prune settled entries past a TTL on register so the registry can't grow unbounded; constructor-configurable for tests. - /agents/interaction/stream: wrap setup so a send failure runs cleanup and never strands the watcher counter. - Truncate overlong permission detail before it enters the alert/notification. - Document the codex hook trust-bypass scope. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sub-agent review (CodeRabbit was rate-limited this round)CodeRabbit couldn't review (PR-review rate limit). A sub-agent review ran instead; findings + resolutions, fixed in 1577a4b:
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
What
Builds the aimux side of the cmux⇄aimux bridge: a generic, first-party agent interaction-request primitive (approvals being the first type), with Claude and Codex
PermissionRequestcapture routed through it. External clients (cmux today; the aimuxapp/later) consume one HTTP API to see and resolve "ask"-gated prompts. Design spec:~/cs/docs/aimux-cmux-bridge.md.How it fits together
src/interaction-requests.ts: an in-memoryInteractionRegistryof{id, sessionId, type, payload, status, response}wheretype ∈ {permission, exit_plan, question, input}, with register/resolve/cancel/wait (timeout + abort).permissionis implemented; the others drop into the same shape.POST /agents/interaction/{register,respond,request},GET /agents/interaction/{wait,pending,stream}; an actionableinteraction_requestalert (carries{id,type,summary});pendingInteractionson/desktop-state. New attention stateneeds_response.PermissionRequesthook (120s) injected via the existing--settingspath; theclaude-hook permission-requestaction registers + long-polls/agents/interaction/requestand prints the allow/deny decision Claude honors, or{}to defer.PermissionRequest; writes a merge-preserving~/.codex/hooks.json(only replaces aimux-owned entries, so it coexists with cmux) and enables hooks per-launch via-c features.hooks=true --dangerously-bypass-hook-trust(noconfig.tomlmutation). Shares oneresolvePermissionRequestOutputhelper with Claude.No default-path regression (watcher-gating)
The
PermissionRequesthook is blocking. To avoid every gated prompt hanging ~110s when no approval client is running,/agents/interaction/requestblocks only while a client is connected to/agents/interaction/stream; otherwise it returns instantly and the hook defers to the native tmux prompt. Any error/timeout also degrades to{}(native prompt) — nothing regresses when no client is watching.Tests / verification
/request, watcher gate, timeout, 400/409); codex-hooks tests (merge preserves foreign entries, PermissionRequest@120s).behavior:allowon approve.yarn typecheck,yarn lint,yarn build, full suite (1094) all green.Out of scope (follow-ups)
/agents/interaction/*(poll/stream → Feed, reply, Deny/Once/Always).app/consumption + updating theapp/TS mirrors ofAlertKind/DesktopState.exit_plan/question/input) — structurally ready, not yet wired.🤖 Generated with Claude Code