fix(daemon): let a Codex turn ask a structured question - #1824
Conversation
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>
There was a problem hiding this comment.
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
|
Fair correction on the headless guarantee — |
|
That addresses the background-pass clarification. One wording detail: This remains non-blocking; my approval stands. sent by |
What
A
codex-acpsession could never reach AgentConnect's ACP form elicitation. Everythingbetween the two ends was already wired — the daemon advertises
elicitation: { form: {}, url: {} }(acp-host.ts), and codex-acp implementsitem/tool/requestUserInput→elicitation/create— but Codex itself offers therequest_user_inputtool in Default mode only behind thedefault_mode_request_user_inputfeature, 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, foundnothing, 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()isread-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()inruntimes/codex-config.tsmerges the feature intoCODEX_CONFIG.featuresone level deep, so it cannot clobber theapps: false/memories: falseswitches other seams set there.AcpHost.start()applies it after all caller env is merged, for a Codex runtime, gated onopts.onElicitbeing present — i.e. exactly when this host services session elicitations.That gate is host-level, so it excludes an
AcpHostbuilt without an answerer (the runtimeprober, 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_CONFIGwarns and leaves the tool off rather than blocking startup, matching theaccount-app isolation seam above it.
isCodexRuntimeDefis exported fromruntime-defs/executable-hints.tsrather than asecond copy of the predicate.
Verification
codex-acp+ a minimal ACP client advertisingelicitation.form, two runs per arm:elicitation/createarrives with the full form schema (one fieldper question plus the per-question
__otherfield the console already folds in fix(console): fold a question's own "Other" box into that question #1817).[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
truefails Codex's config parse).malformed-input rejection) and two
AcpHostcases through the env-echo fixture — the toolon 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 referencingCODEX_CONFIG: 182 passed.typecheck/eslint/prettierclean.Not covered: the webchat card rendering of a Codex-authored form was not exercised against a
live daemon — only the ACP payload was.