v1.11.5: ContextBar inline next to agent picker; remove ChatContextPopover

ContextBar relocated from a dedicated row above MessageList to inline with
the agent-picker row, filling the space to the right of the picker + plus
button. Always-visible (zero-state when no assistant message has run yet)
via chat.model_context_limit, which GET /api/sessions/:id/chats now
populates from a single getModelContext lookup per session.

ChatContextPopover above the input is removed entirely along with its
useChatContextStats hook (no remaining callers). Color tiers and the
auto-compaction threshold tooltip unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 20:11:49 +00:00
parent 3a5cf0c81a
commit 1ffcf67c47
8 changed files with 138 additions and 159 deletions

View File

@@ -3,11 +3,8 @@ import { ChevronDown, Square, X } from 'lucide-react';
import { toast } from 'sonner';
import { api } from '@/api/client';
import { useSessionStream } from '@/hooks/useSessionStream';
import { useChatContextStats } from '@/hooks/useChatContextStats';
import { MessageList } from '@/components/MessageList';
import { ChatInput } from '@/components/ChatInput';
import { ChatContextPopover } from '@/components/ChatContextPopover';
import { ContextBar } from '@/components/ContextBar';
import {
DropdownMenu,
DropdownMenuContent,
@@ -47,7 +44,11 @@ export function ChatPane({ sessionId, chatId, projectId, agentId, onAgentChange,
const chatMessages = stream.messages.filter((m) => m.chat_id === chatId);
const streaming = chatMessages.some((m) => m.status === 'streaming');
const contextStats = useChatContextStats(chatId, chatMessages);
// v1.11.5: per-chat model context limit comes from chat.model_context_limit
// populated by GET /api/sessions/:id/chats. Threaded into ChatInput so
// ContextBar can render a zero-state before the first assistant message.
const modelContextLimit =
sessionChats?.find((c) => c.id === chatId)?.model_context_limit ?? null;
// Auto-send next queued message when streaming completes
useEffect(() => {
@@ -126,10 +127,7 @@ export function ChatPane({ sessionId, chatId, projectId, agentId, onAgentChange,
return (
<div className="flex flex-col h-full min-h-0">
{/* v1.11.2: persistent context-usage indicator. Renders null when there
are no assistant messages yet (fresh chat). shrink-0 keeps it out of
the MessageList scroll region — bar stays pinned, list scrolls. */}
<ContextBar messages={chatMessages} />
{/* v1.11.5: ContextBar moved into ChatInput (above the agent picker). */}
<MessageList messages={chatMessages} sessionChats={sessionChats} />
{/* Queued messages */}
@@ -189,22 +187,23 @@ export function ChatPane({ sessionId, chatId, projectId, agentId, onAgentChange,
</div>
)}
<div className="relative">
<ChatContextPopover stats={contextStats} />
<ChatInput
disabled={false}
projectId={projectId}
sessionId={sessionId}
agentId={agentId}
onAgentChange={onAgentChange}
webSearchEnabled={webSearchEnabled}
onSend={handleSend}
onForceSend={streaming ? handleForceSend : undefined}
onSlashCommand={handleSlashCommand}
chatId={chatId}
chatLabel={sessionChats?.find((c) => c.id === chatId)?.name ?? 'Chat'}
/>
</div>
<ChatInput
disabled={false}
projectId={projectId}
sessionId={sessionId}
agentId={agentId}
onAgentChange={onAgentChange}
webSearchEnabled={webSearchEnabled}
onSend={handleSend}
onForceSend={streaming ? handleForceSend : undefined}
onSlashCommand={handleSlashCommand}
chatId={chatId}
chatLabel={sessionChats?.find((c) => c.id === chatId)?.name ?? 'Chat'}
// v1.11.5: feed ContextBar (mounted inside ChatInput). messages
// drives latest-pair walk; modelContextLimit powers the zero-state.
messages={chatMessages}
modelContextLimit={modelContextLimit}
/>
</div>
);
}