Skip to content

feat(chat): question headers, multi-select, question tool replay, edit preview and run info - #1241

Merged
xiaozhou26 merged 2 commits into
mainfrom
feat/question-permission-followups
Nov 5, 2026
Merged

xiaozhou26 merged 2 commits into
mainfrom
feat/question-permission-followups

Conversation

@xiaozhou26

Copy link
Copy Markdown
Contributor

Linked issue

Closes #1240

Follows up on the question and permission data from Stack-Cairn/K-brain#162 and Stack-Cairn/K-brain#135 (both in K-brain v0.107.22).

Summary

  1. Question headers. Each question tab shows its header. When there is no header, the tab falls back to Q1, Q2, …
  2. Multi-select. A question with multiple: true uses checkboxes and a "Select all that apply" hint. The custom answer can be combined with the listed options. K-brain has no field for several labels yet, so when more than one option is picked, the answer is sent as the labels joined with , plus custom: true. A single picked option is sent as a normal answer. When the card is shown again from history, the joined text is split back into the listed options.
  3. History replay of the question tool. In history, K-brain's own question calls now render as the question card with the recorded answers, including custom text. A dismissed question shows as cancelled, and one with no answer shows as timed out. Both the single and the questions: [...] forms are handled. The original arguments are kept in a hidden __kbrainQuestionArguments field, so a transcript sent back to K-brain still uses the question name and its original arguments.
  4. Gateway direct link. crates/agent-gateway already passed multi-question question.requested events through. It now also handles the rest:
    • It renames and normalizes question calls, both live and in history.
    • It turns question results into card answers.
    • It accepts selectedLabels from the WebUI and sends them as joined text, with custom: true when there is more than one label.
    • It forwards permission.requested.preview to the approval card.
  5. Edit approval preview. When permission.requested.preview has a diff, the approval card renders K-brain's diff rows (<line> <mark> <text>), including the … +N more lines overflow note. new_file adds a "This creates a new file." line. truncated with an empty diff says the change is too large to preview. Without a preview, the card falls back to the old preview built from the tool arguments.
  6. Command run info. exit_code, timed_out and duration_ms from shell tools (Bash, bash, ManagedProcess, ProcessWait, ProcessStop) are read from tool.result events and from history tool_calls[]. They show in the Shell header, for example exit 1 · 2.3s or timed out · 30.0s. K-brain's native bash has no Shell display, so its result shows the same thing as one line.

K-brain protocol need

A selected_labels: []string answer field, validated against the options when multiple is set. Today a multi-select answer with more than one option has to be sent as joined labels with custom: true. That has two problems:

  • K-brain's AskUserQuestion result text presents the answer as something the user typed.
  • A label that contains , can't be split back reliably. LiveAgent splits on the longest listed label, which is a best effort.

Observation on K-brain's preview rows (no change needed here)

editDiffRows prints the trailing context row as the last line of the old text, o[len(o)-1]. It does not print the first line after the change. For a whole-file preview, that row is the file's last line. In the edit screenshot below the trailing row is 7 }, while the line right after the change is line 5. LiveAgent renders the rows exactly as K-brain sends them.

Change scope

  • Modules: agent-ui (question card, approval card, diff view, tool result display, shared helpers, i18n), agent-gui (K-brain turn, history and question adapters), agent-gateway (Go K-brain client and WebUI tests)
  • Key paths:
    • crates/agent-ui/src/components/chat/AskUserQuestionCard.tsx: header tabs and multi-select
    • crates/agent-ui/src/lib/chat/askUserQuestion.ts: question argument normalization, result parsing, multi-select answers
    • crates/agent-ui/src/lib/chat/toolApprovalArgs.ts: approvalPreviewFromKBrain()
    • crates/agent-ui/src/lib/chat/diffRows.ts (new), crates/agent-ui/src/components/chat/EditDiffView.tsx, crates/agent-ui/src/components/chat/ToolApprovalBar.tsx: preview rows, new file and too-large messages
    • crates/agent-ui/src/lib/chat/toolRunInfo.ts (new), crates/agent-ui/src/components/chat/assistant-bubble/ToolResultDisplay.tsx: run info
    • crates/agent-gui/src/lib/kbrain/{history,questions,turn,types}.ts, crates/agent-gui/src/pages/chat/turns/runKBrainConversationTurn.ts
    • crates/agent-gateway/internal/kbrain/question_tool.go (new), events.go, history.go, interactive.go, client.go

Screenshots / preview

All screenshots come from the real desktop debug app (macOS arm64). It was a cargo build of this branch with the Vite dev server from this worktree, and it ran the real K-brain v0.107.22 release binary through LIVEAGENT_KBRAIN_BINARY. HOME and LIVEAGENT_DEV_HOME pointed at temporary directories. The model was a local scripted OpenAI-compatible fixture. It picks the tool from the request's tool list and returns:

  • a question call with three questions (Format, Checks with multiple: true, Rollout)
  • an edit on an existing file
  • a write of a new file
  • a bash command that exits with status 3

K-brain produced everything else itself: the question.requested events, the permission requests with preview (in Always ask mode), the history, and the run info. The screenshots are only cropped (sidebar removed) and not otherwise edited.

Multi-question card with headers (live question.requested from the question tool):

Question card with header tabs

Multi-select question (two options checked):

Multi-select question

Edit approval rendered from permission.requested.preview:

Edit approval from preview

Write approval for a new file (new_file: true):

Write approval for a new file

History replay (after a reload): the question tool call from K-brain history shows as the settled card, and the joined multi-select answer is split back into its options:

Question card replayed from history

Run info on K-brain's native bash, read from history tool_calls[] (exit_code: 3, duration_ms: 16):

Run info on a bash result

The Gateway direct link was not run live in this pass. It is covered by the Go tests and the WebUI tests listed below.

Verification

  • pnpm typecheck:ui, pnpm typecheck:gui, pnpm typecheck:webui: pass
  • pnpm lint (biome): no errors
  • pnpm test:gui: 4122 pass, 12 skipped, 0 fail. The backend tests ran with LIVEAGENT_KBRAIN_BINARY set to the v0.107.22 release binary.
  • pnpm test:webui: 887 pass
  • cd crates/agent-gateway && go test ./...: pass (after pnpm --filter @liveagent/gateway-webui build)
  • New tests:
    • test/providers/kbrain-question-tool.test.mjs: normalization, result parsing, multi-select answers, history replay and the round trip back to K-brain, run info, and a live turn with the question tool and a Bash exit code
    • internal/kbrain/question_tool_test.go: the Gateway side of the same cases, plus the preview reaching the approval card
    • web/test/kbrain-question-preview.test.mjs
  • Extended tests: the question card (header tabs, multi-select, settled joined answers), the approval card (preview rows, new file, too large), the diff rows parser, a full turn where the permission preview reaches both the desktop and the WebUI, and run info on generic results.
  • The e2e run above also caught a bug that the unit tests missed: K-brain's native bash result showed the run info as raw JSON. It is fixed in the second commit and covered by a test.

…t preview and run info

The question card labels each question tab with its header (falling
back to Q1, Q2, ...) and supports multiple: true. Until K-brain has a
selected_labels field, a multi-select answer is sent as the joined
labels with custom: true.

History replay renders K-brain's question tool as the question card.
The original arguments are kept so the transcript is sent back to
K-brain with the original name. The Gateway direct link normalizes
question calls, results, history and multi-select answers the same
way, and it forwards the permission preview.

Edit approvals render permission.requested.preview diff rows. They
note new files and too-large previews, and keep the tool-arguments
preview as the fallback. Shell tool results show exit code, timeout
and duration.

Closes #1240
K-brain's native bash tool has no shell display, so its result fell
through to the raw details view and showed the kbrainRun object as
JSON. Show the exit code and duration as one line there, and leave
the run info out of the JSON dump of any other details.

Refs #1240
@xiaozhou26
xiaozhou26 merged commit a2e497b into main Nov 5, 2026
14 checks passed
@xiaozhou26
xiaozhou26 deleted the feat/question-permission-followups branch November 5, 2026 21:17
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.

Question and permission follow-ups: headers, multi-select, question tool replay, edit preview, run info

1 participant