Skip to content

feat(acp): ACP elicitation loop (ZOD078) - #101

Merged
benocodes merged 1 commit into
mainfrom
feat/zod078-elicitation
Sep 30, 2026
Merged

benocodes merged 1 commit into
mainfrom
feat/zod078-elicitation

Conversation

@benocodes

@benocodes benocodes commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Agents can now ask humans a form question during an ACP turn and resume the same tool call after an eligible room member answers. Implements the live-loop cycle in ZOD078 PLAN.md.

Adds conditional ACP form capability on SDK 1.5, typed request cancellation, daemon schema validation, a pending-input correlator, and the four Matrix elicitation events. Responses bypass the turn FIFO, match the room/thread/published request, check current membership, and atomically accept the first valid response. Invalid answers receive field errors; interrupt, clear, task closure, and process exit cancel pending questions. Publication retries use stable transaction IDs, including answers arriving before a retried publication acknowledgement.

Accepted resolution events carry the confirmed values so other viewers and reloads can display the answer. Includes package changesets. The existing permission callback and session lifecycle facade remain covered by the previous tests.

Validation:

  • All daemon package suites passed: 1,339 assertions, 7 existing skips. ACP includes real SDK subprocess request/cancellation tests; Matrix includes local Tuwunel integration tests.
  • All package typechecks and builds passed.
  • Tests ran with bounded worker concurrency. Earlier parallel runs timed out CLI help subprocesses; the CLI rerun passed all 333 tests with a 30-second Docker teardown hook allowance.

Paired web PR: zooid-ai/clients#46. Per the plan, review and merge the daemon first, then the web client. Live Claude smoke is reserved for Ori after merge. Restart journaling/reconciliation and the architect's retrospective are follow-on work, as specified by the cycle.

@zooidbot zooidbot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Architect review against the ZOD078 PLAN. Verdict: matches the plan, no blockers. CI is green.

What I checked and found correct

  • The SDK 1.5 client() app is used so ctx.signal reaches the handler. The capability is advertised only when onElicitationRequest is set, and only the Matrix transport sets it (decisions 1 and 5).
  • AcpClient.onElicitation: when the upstream signal aborts, the handler throws, so the SDK answers -32800. A local abort (interrupt) answers {action:'cancel'}. Idle reaping is held via setHumanRequestPending.
  • ElicitationCorrelator: transitions out of pending are atomic and happen once. Terminal records are kept (bounded) so late answers get stale feedback. fail emits nothing, so no orphan resolved is published. It is the ZOD072 PendingInputRegistry through opts.pendingInput ?? opts.elicitations, and start-daemon doesn't pass a competing pendingInput. Good: there is no second pending-input concept.
  • Response path: responses bypass enqueueTurn. The handler rejects agent/bot senders and checks room, thread and request_event_id before membership (getJoinedMembers). It validates only while the request is pending and uses settle for first-wins. Forbidden responses are dropped with no feedback (decision 3).
  • Publication: it's chained on the send queue so prose lands above the card. The send queue waits on the card, not on the answer. Stable txnIds, 3 tries, and resolved waits for the publish, so it can't race the card.
  • The typing refresh skips sessions with an open question, and typing comes back on the answer (decision 7).
  • /clear cancels only sessions with an open question (decision 4). Keep it that way. Widening ZOD039 to cancel every live turn on /clear is a separate decision and shouldn't ride on this PR.

Non-blocking, for the follow-on journal cycle (don't fix here)

  1. If elicitation_resolved fails all 3 tries, the agent carries on, but the card stays interactive and the web "awaiting your input" indicator stays up for good. Today that's only a log line. It's the same class as the restart orphan the follow-on journal cycle already owns, so I'll make sure that cycle covers "resolved not delivered" too.
  2. handleElicitationResponse is awaited inside AS transaction processing and can wait out the publish retries (up to ~1.5 s plus the send-queue tail) before it acks the txn. That's fine at current volumes. Just note it if txn latency ever shows up.

Merge order per the plan: this first, then zooid-ai/clients#46.

@benocodes
benocodes merged commit 0198f5f into main Sep 30, 2026
1 check passed
@zooidbot
zooidbot deleted the feat/zod078-elicitation branch October 1, 2026 06:09
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