ask: multi-select answers with "Other" text drop the checked options #216

Closed
opened 2026-11-03 11:59:54 +01:00 by omp-deck · 0 comments
Collaborator

Problem

In an ask question with multi: true, if the user checks several options and also types custom text into "Other (type your own)", the agent receives only the custom text and acts as if nothing else was selected.

Root cause (verified): the web dialog sends everything correctly. apps/web/src/components/chat/AskDialog.tsx submitAll sends values = [...checked, otherText]. createDeckAskTool in apps/server/src/bridge/deck-tools.ts also splits that correctly into selectedOptions + customInput. But the LLM-facing responseText uses customInput ? \Custom: ${customInput}` : selectedOptions.join(", ")in both the multi-question branch (~L287) and the single-question branch (~L292–294). That ternary discardsselectedOptionswhenever custom text exists.details keeps both, so the tool card (apps/web/src/components/tools/Ask.tsx`) displays correctly and hides the bug.

Plan

Context

Make the agent-facing ask result include both the checked options and the custom text. The format is selected: A, B; custom: <text>. An empty part is left out.

Approach

  1. In apps/server/src/bridge/deck-tools.ts, add an exported pure function above createDeckAskTool:
    export function formatAskAnswer(selectedOptions: string[], customInput: string | undefined): string
    
    • parts = []; if selectedOptions.length > 0 push `selected: ${selectedOptions.join(", ")}`; if customInput (non-empty after trim) push `custom: ${customInput}`; return parts.join("; ").
    • If both are empty, return "". This cannot happen for answered dialogs, because the dialog refuses to submit an empty answer, so no special handling is needed.
    • Add a doc comment stating the contract: both parts are kept, and an empty part is omitted.
  2. In createDeckAskTool.execute, replace both ternaries:
    • multi-question: `${r.question}: ${formatAskAnswer(r.selectedOptions, r.customInput)}`
    • single-question: `${details.question}: ${formatAskAnswer(details.selectedOptions ?? [], details.customInput)}`
      Leave buildResult, details, and the web UI unchanged.

Critical files & anchors

  • apps/server/src/bridge/deck-tools.ts: createDeckAskTool, response-text block (~L282–296).

Verification

  • Add apps/server/src/bridge/deck-tools.test.ts (bun:test, same style as other *.test.ts in apps/server/src/bridge/) with cases for formatAskAnswer:
    • (["A","B"], "foo") → "selected: A, B; custom: foo"
    • (["A"], undefined) → "selected: A"
    • ([], "foo") → "custom: foo"
  • Run bun test apps/server/src/bridge/deck-tools.test.ts from the repo root, then the typecheck the repo already uses.
  • Manual check: in a deck session, have the agent call ask with multi: true, check two options, and type text in Other. The tool result text should read <question>: selected: X, Y; custom: <text>.
## Problem In an `ask` question with `multi: true`, if the user checks several options and also types custom text into "Other (type your own)", the agent receives only the custom text and acts as if nothing else was selected. Root cause (verified): the web dialog sends everything correctly. `apps/web/src/components/chat/AskDialog.tsx` `submitAll` sends `values = [...checked, otherText]`. `createDeckAskTool` in `apps/server/src/bridge/deck-tools.ts` also splits that correctly into `selectedOptions` + `customInput`. But the LLM-facing `responseText` uses `customInput ? \`Custom: ${customInput}\` : selectedOptions.join(", ")` in both the multi-question branch (~L287) and the single-question branch (~L292–294). That ternary discards `selectedOptions` whenever custom text exists. `details` keeps both, so the tool card (`apps/web/src/components/tools/Ask.tsx`) displays correctly and hides the bug. ## Plan ### Context Make the agent-facing ask result include both the checked options and the custom text. The format is `selected: A, B; custom: <text>`. An empty part is left out. ### Approach 1. In `apps/server/src/bridge/deck-tools.ts`, add an exported pure function above `createDeckAskTool`: ```ts export function formatAskAnswer(selectedOptions: string[], customInput: string | undefined): string ``` - parts = []; if `selectedOptions.length > 0` push `` `selected: ${selectedOptions.join(", ")}` ``; if `customInput` (non-empty after trim) push `` `custom: ${customInput}` ``; return `parts.join("; ")`. - If both are empty, return `""`. This cannot happen for answered dialogs, because the dialog refuses to submit an empty answer, so no special handling is needed. - Add a doc comment stating the contract: both parts are kept, and an empty part is omitted. 2. In `createDeckAskTool.execute`, replace both ternaries: - multi-question: `` `${r.question}: ${formatAskAnswer(r.selectedOptions, r.customInput)}` `` - single-question: `` `${details.question}: ${formatAskAnswer(details.selectedOptions ?? [], details.customInput)}` `` Leave `buildResult`, `details`, and the web UI unchanged. ### Critical files & anchors - `apps/server/src/bridge/deck-tools.ts`: `createDeckAskTool`, response-text block (~L282–296). ### Verification - Add `apps/server/src/bridge/deck-tools.test.ts` (bun:test, same style as other `*.test.ts` in `apps/server/src/bridge/`) with cases for `formatAskAnswer`: - `(["A","B"], "foo")` → `"selected: A, B; custom: foo"` - `(["A"], undefined)` → `"selected: A"` - `([], "foo")` → `"custom: foo"` - Run `bun test apps/server/src/bridge/deck-tools.test.ts` from the repo root, then the typecheck the repo already uses. - Manual check: in a deck session, have the agent call `ask` with `multi: true`, check two options, and type text in Other. The tool result text should read `<question>: selected: X, Y; custom: <text>`.
lucas closed this issue 2026-11-03 12:03:29 +01:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
lucas/omp-deck#216
No description provided.