ui: Agentic Content UX improvements (#25450)
* feat: Add shimmer text animation for processing state indicators * feat: Redesign CollapsibleContentBlock component with improved UX * feat: Add conditional setting display support with dependsOn field * feat: Add showAgenticTurnStats setting for per-turn statistics * feat: Update ChatMessageAgenticContent with improved UI and new features * feat: Enhance file read tool UI/UX * feat: Refine styling of collapsible content and code preview blocks * feat: add terminal variant to CollapsibleContentBlock * feat: add built-in tools UI registry * feat: extract ChatMessageReasoningBlock and ChatMessageToolCallBlock * refactor: simplify ChatMessageAgenticContent to use extracted blocks * fix: correct markdown content block margin spacing * fix: reorganize SettingsChatFields layout and reset button positioning * fix: use direct map access in agentic store session methods * refactor: remove reasoning preview/throttle system from CollapsibleContentBlock * feat: add auto-scroll to reasoning block and remove showThoughtInProgress * feat: add ChatMessageToolCallDateTime component and support for new tool types * feat: improve auto-scroll reliability in reasoning block with RAF coalescing and MutationObserver * feat: show MCP server favicon for tools without a built-in icon * feat: add search-results parsing utilities and tests * feat: add ChatMessageToolCallSearchResults component * feat: integrate search results rendering into ChatMessageAgenticContent * feat: display tool call input alongside output in ChatMessageToolCallBlock * style: use muted foreground color in reasoning block content * chore: Format * feat: Refine reasoning block layout and make pending thoughts display configurable * feat: Stream tool call code blocks with auto-scroll and handle partial JSON * feat: add streaming permission gate infrastructure * feat: wire permission gate into the agentic loop * fix: bail out on abort and skip already-approved tool calls * fix: clear partial tool calls on abort and savePartialResponse * test: cover partial tool call cleanup end-to-end * refactor: Remove streaming permission gate logic * fix: Correct autoscroll and streaming gates for tool calls and reasoning blocks * refactor: Chat Message Assistant componentization * fix: Show health metadata for disabled MCP servers and promote connections on enable * fix: Inherit global enabled state for missing MCP per-chat overrides * refactor: Cleanup * refactor: Split ChatMessageToolCallBlock into dedicated components * feat: Add live streaming and auto-scroll for tool execution output * feat: Add line numbers and change markers to file edit diffs * chore: Formatting * feat: Add type definitions and utilities for recommended MCP servers * feat: Add recommended MCP servers configuration and storage key * feat: Add McpServerCardCompact component for recommended servers * feat: Add recommended servers section to Add New Server dialog * feat: Update McpServerForm to support authorization requirements * feat: Add select-none classes for text selection prevention * feat: Add recommended MCP server icon assets * refactor: Store dismissed MCP recommendations as a boolean flag * feat: Render tool results as JSON or Markdown based on detected content type * feat: UI improvement * feat: Render search block early and update heading to show execution state * fix: Prevent non-web-search tools from triggering the search UI block * refactor: Cleanup * refactor: Extract hardcoded icon size classes into shared constants * refactor: Extract hardcoded tool result separator into a shared constant * refactor: Tool Calls UI/logic * refactor: Cleanup * refactor: Cleanup * refactor: Cleanup
This commit is contained in:
@@ -562,8 +562,14 @@ class ChatStore {
|
||||
* Abort the current agentic flow signal without clearing loading state.
|
||||
* Used by "Send immediately" to force the agentic loop to exit so that
|
||||
* the pending steering message can be re-sent.
|
||||
*
|
||||
* Any tool calls captured mid-stream are dropped before the abort so the
|
||||
* pending message (or a manual follow-up) does not re-send a half-received
|
||||
* tool call with invalid JSON arguments to the server. Mirrors what the
|
||||
* Stop button already does through stopGenerationForChat.
|
||||
*/
|
||||
abortCurrentFlow(convId: string): void {
|
||||
async abortCurrentFlow(convId: string): Promise<void> {
|
||||
await this.savePartialResponseIfNeeded(convId);
|
||||
const c = this.abortControllers.get(convId);
|
||||
if (c) {
|
||||
c.abort();
|
||||
@@ -1255,6 +1261,28 @@ class ChatStore {
|
||||
lastCreatedInFlow = msg.id;
|
||||
return msg;
|
||||
},
|
||||
updateToolResultMessage: async (
|
||||
messageId: string,
|
||||
content: string,
|
||||
extras?: DatabaseMessageExtra[]
|
||||
) => {
|
||||
// Persist latest content + merged extras; mirror into the active
|
||||
// store so the chat view sees live updates for streaming tools
|
||||
// (e.g. exec_shell_command). The existing tool message node
|
||||
// pointer stays put - the renderer is already scoped to it.
|
||||
const updates: Partial<DatabaseMessage> = { content };
|
||||
if (extras) {
|
||||
const idx = conversationsStore.findMessageIndex(messageId);
|
||||
const existing = idx >= 0 ? (conversationsStore.activeMessages[idx]?.extra ?? []) : [];
|
||||
const merged = [...existing, ...extras];
|
||||
updates.extra = merged;
|
||||
}
|
||||
if (conversationsStore.activeConversation?.id === convId) {
|
||||
const idx = conversationsStore.findMessageIndex(messageId);
|
||||
if (idx >= 0) conversationsStore.updateMessageAtIndex(idx, updates);
|
||||
}
|
||||
await DatabaseService.updateMessage(messageId, updates);
|
||||
},
|
||||
createAssistantMessage: async () => {
|
||||
// Reset streaming state for new message
|
||||
streamedContent = '';
|
||||
@@ -1505,21 +1533,27 @@ class ChatStore {
|
||||
|
||||
const partialContent = streamingState.response;
|
||||
const partialReasoning = lastMessage.reasoningContent || '';
|
||||
// snapshot the streamed tool calls before clearing so we still know whether
|
||||
// anything was captured when deciding to skip the DB write below
|
||||
const hadPartialToolCalls = !!lastMessage.toolCalls?.trim();
|
||||
|
||||
// nothing to persist when both content and reasoning are empty (e.g. stop before any token)
|
||||
if (!partialContent.trim() && !partialReasoning.trim()) return;
|
||||
// nothing to persist when content, reasoning, and streamed tool calls are all empty
|
||||
// (e.g. stop before any token). otherwise drop the partial tool call and write whatever
|
||||
// was streamed: incomplete arguments (truncated JSON, missing closing quote) would
|
||||
// otherwise be re-sent to the server on the next turn and rejected.
|
||||
if (!partialContent.trim() && !partialReasoning.trim() && !hadPartialToolCalls) return;
|
||||
|
||||
try {
|
||||
const updateData: {
|
||||
content: string;
|
||||
content?: string;
|
||||
reasoningContent?: string;
|
||||
toolCalls?: string;
|
||||
timings?: ChatMessageTimings;
|
||||
} = {
|
||||
content: partialContent
|
||||
toolCalls: ''
|
||||
};
|
||||
if (partialReasoning) {
|
||||
updateData.reasoningContent = partialReasoning;
|
||||
}
|
||||
if (partialContent.trim()) updateData.content = partialContent;
|
||||
if (partialReasoning.trim()) updateData.reasoningContent = partialReasoning;
|
||||
const lastKnownState = this.getProcessingState(conversationId);
|
||||
if (lastKnownState) {
|
||||
updateData.timings = {
|
||||
@@ -1535,9 +1569,14 @@ class ChatStore {
|
||||
}
|
||||
await DatabaseService.updateMessage(lastMessage.id, updateData);
|
||||
lastMessage.content = partialContent;
|
||||
// mirror the drop into the in-memory message so the next request sent via
|
||||
// sendMessage (queued pending, Send immediately, or manual follow-up) reads
|
||||
// the cleared value, not whatever the streaming widget had been showing
|
||||
lastMessage.toolCalls = '';
|
||||
if (updateData.timings) lastMessage.timings = updateData.timings;
|
||||
} catch (error) {
|
||||
lastMessage.content = partialContent;
|
||||
lastMessage.toolCalls = '';
|
||||
console.error('Failed to save partial response:', error);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user