Skip to content

UI/chat polish upstream#2281

Open
Feelings0220 wants to merge 3 commits into
kagent-dev:mainfrom
Feelings0220:ui/chat-polish-upstream
Open

UI/chat polish upstream#2281
Feelings0220 wants to merge 3 commits into
kagent-dev:mainfrom
Feelings0220:ui/chat-polish-upstream

Conversation

@Feelings0220

Copy link
Copy Markdown

Optimized the layout with a more compact chat interface, an adjustable sidebar, and other UI improvements.
对话框紧凑,侧边栏可调节等等agent对话布局的优化

claude added 2 commits July 17, 2026 09:10
- Auto-growing textarea (1 row min, ~8 rows max) replaces the fixed
  min-h-[100px] composer; send/voice/cancel buttons are inlined so the
  idle composer height drops from ~220px to ~60px
- Enter sends the message (Shift+Enter for newline), with an IME
  composition guard so CJK input confirmation doesn't trigger a send
- Status/token row only renders while active instead of permanently
- Messages column is centered at max-w-3xl; break-all -> break-words;
  reduced vertical padding
- Auto-scroll only follows when the user is near the bottom, with a
  floating 'Latest' button to jump back down; sending always re-engages
  follow scrolling

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016d9SxeefoRSLZmQ1oKo17j
…er, resizable sidebars

- ScrollArea switches to Radix type=scroll: the scrollbar overlays
  content, appears while scrolling, and fades out 600ms later; thinner
  thumb, no track border (applies to every ScrollArea in the app)
- Token counts render in k/M units via formatTokens (exact values stay
  in tooltips/titles)
- The composer usage row gains an approximate context-window meter:
  'ctx 12.3k/200k' with a progress bar (amber >80%, red >95%), sized
  from the latest turn's prompt tokens against a model-prefix window
  table (unknown models hide the meter). ChatAgentContext gains a
  modelInfo value (model/provider/ModelConfig ref) provided by
  ChatLayoutUI so chat components can read the active model.
- Chat scroll area top padding reduced (py-6 -> pt-2 pb-6)
- Both sidebars are now resizable: Sidebar gains a width override prop
  (set on the outer wrapper so the layout gap tracks the panel, with
  width transitions disabled while overridden), a pointer-capture drag
  handle on the inner edge, 200-480px clamp, per-side localStorage
  persistence, and double-click to reset

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016d9SxeefoRSLZmQ1oKo17j
@Feelings0220
Feelings0220 requested a review from peterj as a code owner July 17, 2026 15:57
Copilot AI review requested due to automatic review settings July 17, 2026 15:57

Copilot AI 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.

Pull request overview

This PR polishes the chat UI by introducing compact token usage formatting, adding independently resizable left/right sidebars with persistent width, and improving chat scrolling/composer ergonomics.

Changes:

  • Added token formatting + model context-window estimation utilities (with tests) and surfaced them in token usage UI.
  • Implemented persistent, draggable sidebar resizing for both sessions (left) and agent details (right) sidebars.
  • Improved chat interface ergonomics: “jump to latest”, smarter auto-scroll behavior, and auto-growing message composer.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
ui/src/lib/tokenUtils.ts Adds token formatting and model context-window lookup helpers.
ui/src/lib/tests/tokenUtils.test.ts Adds unit tests for the new token utilities.
ui/src/hooks/useSidebarWidth.ts New hook for persistent, clamped sidebar width via localStorage.
ui/src/components/ui/sidebar.tsx Adds per-sidebar width override and disables width transitions while dragging.
ui/src/components/ui/scroll-area.tsx Tweaks scroll behavior/appearance (overlay scrollbar behavior).
ui/src/components/sidebars/SidebarResizeHandle.tsx Adds pointer-driven resize handle used by sidebars.
ui/src/components/sidebars/SessionsSidebar.tsx Wires left sidebar to persistent width + resize handle.
ui/src/components/sidebars/AgentDetailsSidebar.tsx Wires right sidebar to persistent width + resize handle.
ui/src/components/chat/TokenStatsTooltip.tsx Displays compact token counts alongside raw counts in tooltip.
ui/src/components/chat/TokenStats.tsx Shows compact token counts and adds an approximate context usage meter.
ui/src/components/chat/ChatMessage.tsx Improves wrapping behavior for message content (break-words).
ui/src/components/chat/ChatLayoutUI.tsx Passes model/provider/config info into chat context.
ui/src/components/chat/ChatInterface.tsx Adds near-bottom tracking, “Latest” jump button, and auto-growing composer.
ui/src/components/chat/ChatAgentContext.tsx Extends chat context to include model info for token/context UI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ui/src/lib/tokenUtils.ts
Comment on lines +4 to +9
export function formatTokens(count: number): string {
if (!Number.isFinite(count) || count < 0) return "0";
if (count >= 1_000_000) return `${trimDecimal(count / 1_000_000)}M`;
if (count >= 1_000) return `${trimDecimal(count / 1_000)}k`;
return String(Math.round(count));
}
Comment on lines +12 to +13
export function useSidebarWidth(storageKey: string, defaultWidth: number) {
const [width, setWidthState] = useState<number>(defaultWidth);
Comment on lines +42 to +44
const reset = useCallback(() => {
setWidthState(defaultWidth);
try {
Comment on lines +24 to +35
const onMove = (event: PointerEvent) => {
const next = side === "left" ? event.clientX : window.innerWidth - event.clientX;
onResize(next);
};
const onUp = (event: PointerEvent) => {
target.releasePointerCapture(event.pointerId);
target.removeEventListener("pointermove", onMove);
target.removeEventListener("pointerup", onUp);
};
target.addEventListener("pointermove", onMove);
target.addEventListener("pointerup", onUp);
},
- formatTokens: 999950..999999 rounded up to '1000k'; roll to '1M'
  instead (with a regression test)
- useSidebarWidth: a missing localStorage key made Number(null)===0 fall
  through the range guard by luck; read the raw value and treat missing
  as NaN explicitly
- useSidebarWidth: clamp reset() to the min/max range in case a caller's
  default drifts outside it
- SidebarResizeHandle: also end the drag on pointercancel (touch scroll
  takeover, alt-tab) and guard releasePointerCapture so an already-
  released capture doesn't throw

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016d9SxeefoRSLZmQ1oKo17j
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.

3 participants