Skip to content

fix(daemon): let a Codex turn ask a structured question - #1824

Merged
spacedragon merged 1 commit into
mainfrom
fix/codex-request-user-input
Sep 7, 2026
Merged

fix(daemon): let a Codex turn ask a structured question#1824
spacedragon merged 1 commit into
mainfrom
fix/codex-request-user-input

Conversation

@spacedragon

@spacedragon spacedragon commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

What

A codex-acp session could never reach AgentConnect's ACP form elicitation. Everything
between the two ends was already wired — the daemon advertises
elicitation: { form: {}, url: {} } (acp-host.ts), and codex-acp implements
item/tool/requestUserInputelicitation/create — but Codex itself offers the
request_user_input tool in Default mode only behind the default_mode_request_user_input
feature, which is off by default.

So the model had no such tool. Observed on a real session: it searched its MCP resource
templates, then rg'd the daemon and Codex state directories for a form schema, found
nothing, and answered in prose that interactive forms are unavailable — advising the user
to "switch to Plan mode", which codex-acp does not expose (AgentMode.all() is
read-only / agent / agent-full-access). That advice comes from Codex's own
<collaboration_mode> prompt, which names Default and Plan and says to use the tool
"only when it is listed in the available tools for this turn".

How

  • codexConfigWithUserInputTool() in runtimes/codex-config.ts merges the feature into
    CODEX_CONFIG.features one level deep, so it cannot clobber the apps: false /
    memories: false switches other seams set there.
  • AcpHost.start() applies it after all caller env is merged, for a Codex runtime, gated on
    opts.onElicit being present — i.e. exactly when this host services session elicitations.
    That gate is host-level, so it excludes an AcpHost built without an answerer (the runtime
    prober, the chat CLI) but NOT the daemon's own background passes, which share an agent's
    host: a distillation / dream / commit-message pass can see the tool, and the coordinator
    declines its request because the pass has no pending turn. Malformed inherited
    CODEX_CONFIG warns and leaves the tool off rather than blocking startup, matching the
    account-app isolation seam above it.
  • isCodexRuntimeDef is exported from runtime-defs/executable-hints.ts rather than a
    second copy of the predicate.

Verification

  • Driven end to end against a real codex-acp + a minimal ACP client advertising
    elicitation.form, two runs per arm:
    • with the feature → elicitation/create arrives with the full form schema (one field
      per question plus the per-question __other field the console already folds in fix(console): fold a question's own "Other" box into that question #1817).
    • without it → no elicitation; the model emits a markdown pseudo-form.
    • [tools] experimental_request_user_input = { enabled = true } alone → no elicitation.
      That knob is inert in the Codex build bundled with codex-acp@1.10.0 (and is a struct,
      not a bool, so a bare true fails Codex's config parse).
  • New tests: three pure-function cases for the merge (including the features-table merge and
    malformed-input rejection) and two AcpHost cases through the env-echo fixture — the tool
    on for an elicitation-servicing host, off for a headless one.
  • test/codex-config.test.ts, test/acp-host.test.ts, test/account-apps.test.ts,
    test/elicit-decline-notice.test.ts: 112 passed. Every test file referencing
    CODEX_CONFIG: 182 passed. typecheck / eslint / prettier clean.

Not covered: the webchat card rendering of a Codex-authored form was not exercised against a
live daemon — only the ACP payload was.

A codex-acp session could never reach our ACP form elicitation: Codex offers
`request_user_input` in Default mode only behind the `default_mode_request_user_input`
feature, so the model found no such tool, searched for one, and answered in prose that
it cannot ask — advising a Plan mode codex-acp does not expose. AcpHost now merges that
feature into CODEX_CONFIG for a Codex runtime, gated on the host actually servicing
session elicitations so a headless pass never gains a question it would decline.

The `[tools] experimental_request_user_input` knob is inert here (verified against the
codex build bundled with codex-acp@1.10.0); the feature flag is the real gate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@agentconnect-md-test agentconnect-md-test Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No blocking regressions found at 65417351. The feature merge preserves existing config and feature switches, and runs after caller-env assembly and account-app isolation.

Non-blocking clarification: onElicit is a host-level gate, so it does not exclude all background passes as the PR description claims. buildAcpHost() also installs that callback for dream hosts and hosts used by distillation/commit-message passes. Those passes can gain the tool, though the existing missing-pending-turn check safely declines their requests. Narrow the stated headless guarantee accordingly.

Validation: all 112 tests across codex-config, acp-host, account-apps, and elicit-decline-notice passed; daemon typecheck, changed-file ESLint/Prettier, and git diff --check passed. Live webchat rendering was not exercised.

sent by review-bot (Codex · gpt-6-astra) · open in session

@spacedragon

Copy link
Copy Markdown
Contributor Author

Fair correction on the headless guarantee — buildAcpHost() does install onElicit for an agent's host, and the background passes share it, so the gate excludes only an AcpHost built without an answerer (prober, chat CLI). PR description narrowed to say exactly that, and to credit the missing-pending-turn check as what actually declines a pass's request. No code change; the comment at the call site already claims only the host-level condition.

@spacedragon
spacedragon merged commit 69ac1b7 into main Sep 7, 2026
14 checks passed
@spacedragon
spacedragon deleted the fix/codex-request-user-input branch September 7, 2026 07:03
@agentconnect-md-test

Copy link
Copy Markdown
Contributor

That addresses the background-pass clarification. One wording detail: probeCallbacks also supplies a declining onElicit, so the prober isn’t an example of an excluded host.

This remains non-blocking; my approval stands.

sent by review-bot (Codex · gpt-6-astra) · open in session

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