Skip to content

fix(runtime): reliable, correlation-safe, non-blocking elicitation delivery (#3584)#3587

Merged
dgageot merged 1 commit into
mainfrom
fix/a6-elicitation-concurrency
Jul 15, 2026
Merged

fix(runtime): reliable, correlation-safe, non-blocking elicitation delivery (#3584)#3587
dgageot merged 1 commit into
mainfrom
fix/a6-elicitation-concurrency

Conversation

@aheritier

@aheritier aheritier commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Previously this PR was the full A6 implementation; it has been split into a reviewable stack and now scopes to the runtime core only. Fixes the heart of #3584 — elicitation requests raised from concurrent background jobs were silently dropped and the requesting handler blocked forever.

#3584 stack

  1. fix(tui): queue pending attention events FIFO instead of a single slot (#3584) #3618 — fix(tui): FIFO pending-attention queue (merged)
  2. this PR (fix(runtime): reliable, correlation-safe, non-blocking elicitation delivery (#3584) #3587) — runtime core: correlation, delivery, API field
  3. feat(tui,app): surface & correlate background-job elicitations (#3584) #3624 — feat(tui,app): surface & correlate background-job elicitations
  4. feat(server): session-scoped elicitation sink for API/server runtimes (#3584) #3625 — feat(server): session-scoped elicitation sink

What changed

  • Per-request correlation: waiters keyed by an internal ID, registered before the request event is emitted (eliminates the TOCTOU branch).
  • Reliable delivery: the OnElicitationRequest sink is called synchronously; the best-effort bridge send is ctx-bounded on a detached goroutine and can never block delivery or response processing.
  • Atomic resolve-vs-cancel: a terminal-state guard ensures a delivered response is never discarded by a racing ctx.Done().
  • Backward-compatible API: ResumeElicitation's new elicitationID is variadic (pre-Concurrent background-job elicitations are silently dropped — nothing displayed to the user #3584 callers still compile); additive elicitation_id wire field; server pass-through wires it end-to-end.
  • Headless fast-decline with a model-readable note when no sink is registered.

The Runtime interface change and its repo-wide implementor/mock updates are one commit for Go compile atomicity.

Testing

  • pkg/runtime/elicitation_concurrency_test.go: duplicate wire IDs, cancel-vs-resolve race (300-iter -race), wedged bridge, real-handler TOCTOU, exactly-once delivery, concurrent background-job routing.
  • Full stack task dev + -race — green.

Bottom of the remaining stack (targets main now that #3618 is merged).


For advanced use (custom elicitation, raw event inspection), call `chat.Runtime()` to access the underlying `runtime.Runtime` directly.

> [!WARNING]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

can it impact AP @simonferquel ?

b.ch <- ev
return nil
select {
case b.ch <- ev:
// means the response will reach the caller, never a discarded one.
func (r *LocalRuntime) ResumeElicitation(ctx context.Context, action tools.ElicitationAction, content map[string]any, elicitationID ...string) error {
id := firstElicitationID(elicitationID)
slog.DebugContext(ctx, "Resuming runtime with elicitation response", "agent", r.currentAgentName(), "action", action, "elicitation_id", id)
ok = r.elicitationWaiters.resolveSingle(result)
}
if !ok {
slog.DebugContext(ctx, "No matching elicitation request in progress", "elicitation_id", id)
slog.DebugContext(ctx, "No matching elicitation request in progress", "elicitation_id", id)
return errNoSuchElicitation
}
slog.DebugContext(ctx, "Elicitation response sent successfully", "action", action)
func (r *RemoteRuntime) ResumeElicitation(ctx context.Context, action tools.ElicitationAction, content map[string]any) error {
slog.DebugContext(ctx, "Resuming remote runtime with elicitation response", "agent", r.currentAgent, "action", action, "session_id", r.sessionID)
func (r *RemoteRuntime) ResumeElicitation(ctx context.Context, action tools.ElicitationAction, content map[string]any, elicitationID ...string) error {
id := firstElicitationID(elicitationID)
slog.DebugContext(ctx, "Resuming remote runtime with elicitation response", "agent", r.currentAgent, "action", action, "session_id", r.sessionID)
func (r *RemoteRuntime) ResumeElicitation(ctx context.Context, action tools.ElicitationAction, content map[string]any, elicitationID ...string) error {
id := firstElicitationID(elicitationID)
slog.DebugContext(ctx, "Resuming remote runtime with elicitation response", "agent", r.currentAgent, "action", action, "session_id", r.sessionID, "elicitation_id", id)
@aheritier aheritier added area/api For features/issues/fixes related to the usage of the cagent API area/cli CLI commands, flags, output formatting area/docs Documentation changes area/runtime Runtime engine, agent loop execution, tool dispatch, loop detection area/tui For features/issues/fixes related to the TUI kind/fix PR fixes a bug (maps to fix:). Use on PRs only. labels Jul 11, 2026
@aheritier aheritier force-pushed the fix/a6-elicitation-concurrency branch 2 times, most recently from 06d22e7 to 5db8299 Compare July 13, 2026 14:37
@aheritier aheritier force-pushed the fix/a6-elicitation-concurrency branch from 5db8299 to 811d91d Compare July 13, 2026 14:40
@aheritier aheritier changed the title fix(runtime): reliably surface & correlate concurrent elicitation requests (#3584) fix(runtime): reliable, correlation-safe, non-blocking elicitation delivery (#3584) Jul 13, 2026
@aheritier aheritier marked this pull request as ready for review July 13, 2026 14:56
@aheritier aheritier requested a review from a team as a code owner July 13, 2026 14:56
@aheritier

Copy link
Copy Markdown
Contributor Author

/review

@github-actions

Copy link
Copy Markdown
Contributor

👋 Heads up: The /review command is deprecated. Please re-request a review from docker-agent in the PR sidebar instead.

@aheritier aheritier requested a review from docker-agent July 15, 2026 09:25
@dgageot dgageot merged commit 3556547 into main Jul 15, 2026
25 of 29 checks passed
@dgageot dgageot deleted the fix/a6-elicitation-concurrency branch July 15, 2026 14:42
aheritier added a commit that referenced this pull request Jul 15, 2026
…ibility (#3584)

Change NewElicitationDialog, NewURLElicitationDialog,
NewOAuthAuthorizationDialog, and App.ResumeElicitation to take the new
correlation-ID argument as a trailing variadic elicitationID ...string
instead of a required positional string, following #3587's precedent for
Runtime.ResumeElicitation.

This restores source compatibility for external callers and fixes the
compile break against 3-arg NewElicitationDialog call sites added on main
(bebfc22). Existing call sites in this branch that pass a real
elicitation ID are unchanged (still pass it as the variadic arg), so
response correlation is preserved.

NewOAuthAuthorizationDialog's parameter order also changes: appInstance now
comes before the new variadic elicitationID, so the trailing ID stays last
across all four signatures.
aheritier added a commit that referenced this pull request Jul 15, 2026
…ibility (#3584)

Change NewElicitationDialog, NewURLElicitationDialog,
NewOAuthAuthorizationDialog, and App.ResumeElicitation to take the new
correlation-ID argument as a trailing variadic elicitationID ...string
instead of a required positional string, following #3587's precedent for
Runtime.ResumeElicitation.

This restores source compatibility for external callers and fixes the
compile break against 3-arg NewElicitationDialog call sites added on main
(bebfc22). Existing call sites in this branch that pass a real
elicitation ID are unchanged (still pass it as the variadic arg), so
response correlation is preserved.

NewOAuthAuthorizationDialog's parameter order also changes: appInstance now
comes before the new variadic elicitationID, so the trailing ID stays last
across all four signatures.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api For features/issues/fixes related to the usage of the cagent API area/cli CLI commands, flags, output formatting area/docs Documentation changes area/runtime Runtime engine, agent loop execution, tool dispatch, loop detection area/tui For features/issues/fixes related to the TUI kind/fix PR fixes a bug (maps to fix:). Use on PRs only.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants