[Bug]: OMP questions show as two steps with no options, and the question text runs out of the card#23505

opened20d agobyIianneo97

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server (ACP elicitation mapping), plus apps/web (question card)

Steps to reproduce

  1. Add OMP (oh-my-pi 18.12.6) as an ACP registry provider.
  2. Have OMP call its ask tool with one single-select question that has a header, a long question and two options. The tool input from my thread, trimmed:
json
1{
2 "questions": [
3 {
4 "id": "booking_commit_guard",
5 "header": "Safety-hook false positive",
6 "question": "The safety hook mistakes the booking source file for a Telegram session file. Approve this exact code-only commit command so I can continue? No Telegram or Discord access is involved.",
7 "options": [
8 { "label": "Approve the exact command", "description": "Commit the verified booking fix and sync staging." },
9 { "label": "Hold the booking commit", "description": "Leave this fix uncommitted and continue the other ticket work." }
10 ],
11 "multi": false,
12 "recommended": 0
13 }
14 ]
15}
  1. Look at the question card above the composer.

Expected behavior

One question, so no "1/2". The card's top line shows "Safety-hook false positive". The body shows the full question, the two options, and the usual inline field for a custom answer.

Actual behavior

  • The card shows "1/2". Step 2 is OMP's "Other (type your own)" field, shown as a question of its own.
  • The long question sits on the header line. It doesn't wrap or truncate, so it runs under the "1/2" counter and the chevron, and past the right edge of the card.
  • The body shows "Safety-hook false positive" where the question should be.
  • No options are shown.

The user_input_request that T3 stored:

json
1[
2 {
3 "id": "q0",
4 "header": "The safety hook mistakes the booking source file for a Telegram session file. Approve this exact code-only commit command so I can continue? No Telegram or Discord access is involved.",
5 "question": "Safety-hook false positive",
6 "options": []
7 },
8 {
9 "id": "q0__other",
10 "header": "Other (type your own)",
11 "question": "The safety hook mistakes the booking source file for a Telegram session file. Approve this exact code-only commit command so I can continue? No Telegram or Discord access is involved.",
12 "options": []
13 }
14]

Impact

Major degradation or frequent failure

Version or commit

0.1.2-nightly.20261021.3499 (b5a226e49c52)

Environment

macOS 26.7, T3 Code Nightly desktop app, OMP 18.12.6 over ACP, model anthropic/claude-opus-5-5

Cause

OMP 18.12.6 builds its elicitation form like this (from its askDialog):

  • q{N}: title is the question, description is the header, choices are in oneOf: [{ const, title, description }] (items.anyOf for multi-select), and default is the recommended choice.
  • q{N}__other: { "type": "string", "title": "Other (type your own)" } for a custom answer.
  • When the answer comes back, OMP reads q{N} as one of the option labels and q{N}__other as the custom text.

The generic mapping in packages/provider-acp/src/server/adapter.ts (handleElicitation):

  • reads choices only from enum and boolean, so the oneOf choices are dropped.
  • turns every property into its own question, so q0__other becomes step 2.
  • maps title to the header and description to the question, which is the reverse of what OMP sends.

On the web side, the header span in apps/web/src/components/chat/ComposerPendingUserInputPanel.tsx is shrink-0 with no truncate or wrap, so any long header spills out of the card.

  • #21005 and #22479 report the same problems for Factory Droid. The fix in #20417 only covers Droid. droidAcp.ts matches Droid's <id>_other field and its const: "other" choice, so OMP's q{N}__other form still goes through the generic path.
  • The open PR #21770 reads oneOf and items.anyOf choices, which fixes the missing options. Its test input puts the short label in title and the question in description, and its expected output still keeps q0__other as a separate question. With OMP's real form, the card would still show "1/2" and the long question on the header line.

Suggested fix

  • Add an OMP form handler in provider-acp-registry through extractElicitationForm, the way droidAcp.ts handles Droid. It folds q{N}__other into its question, takes the question from title and the header from description, and replies with the chosen label(s) in q{N} and any typed text in q{N}__other.
  • In the question card, truncate or wrap the header so a long one stays inside the card.
Synced from GitHub

Is an OMP handler through extractElicitationForm still the plan here, or is #21770 meant to cover it? Still reproduces on 0.1.6 (2359643cffa6) with OMP 18.13.3: no options, and the full question sits in the header, which now truncates, so it's cut off. The Pi provider isn't a workaround either, since --mode is reserved and OMP only exposes ask under --mode rpc-ui.

Synced from GitHub

Still reproduces on 0.1.6 with OMP 18.17.0. With two questions it gets worse: four steps (q0, q0__other, q1, q1__other), all with options: []. With no field description, every step's question text is OMP's top-level message, "Answer 2 questions". The real question only shows in the header.

The user_input_request timeline item also shows the raw questions JSON, not the questions as text, so it can't be answered from there either.

#21770 would fix the options and the extra steps, but not the JSON in the timeline.

Synced from GitHub

I'm seeing the same problem with OMP connected through ACP in T3 Code. Adding another concrete example to this issue rather than opening a duplicate.

What the captured UI shows

  • OMP sends one question with two options and recommended: 0, but the question card displays 1/2.
  • The two options and their descriptions are not visible. The composer offers “Type your own answer, or leave this blank to use the selected option”, but there is no visible selected option to inspect.
  • The question appears in both the card header and body.
  • Above the card, the timeline displays a literal questions heading followed by the raw JSON array, including id, question, options, and recommended, rather than a readable question/choice presentation.

The composer shows model openai/gpt-6.1-sol, reasoning high. Exact T3 Code and OMP versions were not captured.

Payload structure

The example below preserves the structure visible in the screenshot, with the ID and wording generalized to omit unrelated task details. This generalized payload has not been independently run:

json
1{
2 "questions": [
3 {
4 "id": "publish_changes",
5 "question": "Should I publish the changes or keep them local?",
6 "options": [
7 {
8 "label": "Publish the changes",
9 "description": "Publish the completed work."
10 },
11 {
12 "label": "Keep the changes local",
13 "description": "Do not publish the changes."
14 }
15 ],
16 "recommended": 0
17 }
18 ]
19}

Expected: a single question step with both selectable options and their descriptions, a visible recommended/selected choice, and a custom-answer field associated with that same question. The timeline should present the question and choices readably instead of exposing the raw JSON as the user-facing prompt.

This corroborates both the missing-options/extra-step behavior in the original report and the raw-JSON timeline behavior noted in the November 6 comment. I have not verified whether typing a custom answer successfully resumes the agent.