Skip to content

refactor: ai assistant revamp#547

Open
emrberk wants to merge 29 commits intomainfrom
refactor/ai-assistant-mechanics
Open

refactor: ai assistant revamp#547
emrberk wants to merge 29 commits intomainfrom
refactor/ai-assistant-mechanics

Conversation

@emrberk
Copy link
Copy Markdown
Collaborator

@emrberk emrberk commented Mar 31, 2026

  • Replaces JSON structured output with plain text responses + suggest_query tool for SQL suggestions
  • Adds thinking/reasoning content display for reasoning models
  • Removes all JSON response format schemas, custom provider JSON parsing/repair logic, and extractPartialExplanation
  • Removes responseStart, explanation, and contentFragments fields from conversation messages
  • Adds full tool call and result history to conversations, giving the model context of prior tool interactions across
    turns
  • Adds turn-based grouping of assistant responses with their tool calls in the UI
  • Raises max response token limit to 64,000 for Anthropic models
  • Switches summary generation for context compaction to streaming
  • Fixes issues about not being able to run query from chat window when editor is unmounted
  • Fixes issues about query key mismatches between query runs from chat and editor
  • Prevents unnecessary rerenders and fixes layout issues
  • Adds cancellation/abort handling for the queries ran from AI Chat Window

@emrberk emrberk marked this pull request as ready for review April 6, 2026 07:41
@emrberk emrberk requested a review from bluestreak01 April 8, 2026 11:42
@emrberk emrberk changed the title refactor: use chronological view in the assistant response, render thinking blocks refactor: ai assistant revamp Apr 8, 2026
@bluestreak01
Copy link
Copy Markdown
Member

@emrberk — code review of this PR. Findings verified by reading the actual code, false positives removed.


High

Streaming retry corrupts conversation state

src/utils/executeAIFlow.ts:481-484, src/utils/aiAssistant.ts:357

The streaming accumulators (accumulatedText, accumulatedReasoning, accumulatedToolCalls) are declared once at the top of executeAIFlow(). tryWithRetries wraps the entire executeFlow call, so on a retry after a mid-stream failure, chunks append to already-populated accumulators. onResponseStart resets them — but only within tool-call loops, not at the start of a fresh executeFlow invocation.

Suggested fix: Reset all streaming accumulators at the beginning of each executeFlow attempt, or move the retry boundary below the streaming layer.


Medium

Memo comparator too aggressive on AssistantMessageContent

src/scenes/Editor/AIChatWindow/AssistantMessageContent.tsx:262-269

The custom React.memo comparator only checks turnMessages[last] reference and isMessageStreaming. It ignores anchorMessage (which holds operationHistory) and status. In multi-message turns (tool calls), the anchor is not the last turn message, so operationHistory/status updates are missed until text streaming begins on the last message.

Suggested fix: Add prev.anchorMessage === next.anchorMessage and prev.status === next.status to the comparator.

Thinking content not rendered in AssistantModes.tsx

src/components/AIStatusIndicator/AssistantModes.tsx:375-528

getIsExpandableSection marks Thinking as expandable, but the expanded content block has no rendering branch for it — only Processing, InvestigatingTable, and InvestigatingDocs. Expanding a Thinking section renders an empty <ReasoningThread>. The compact variant (AssistantModesCompact.tsx:417-425) handles this correctly.

setIsStreaming(false) skipped if persistMessages throws

src/utils/executeAIFlow.ts:720-721

In the finally block, await callbacks.persistMessages(conversationId) precedes callbacks.setIsStreaming(false). If persistence throws, the UI stays stuck in streaming state.

Suggested fix: Wrap persistMessages in try/catch, or move setIsStreaming(false) before the await.

openChatWindow — no post-await staleness guard

src/providers/AIConversationProvider/index.tsx:599-603

After await aiConversationStore.getMessages(conversationId), there's no check that conversationId is still the active conversation before calling setActiveConversationMessages(msgs). If the user rapidly switches conversations, messages from a previous load can overwrite the current conversation's state.

closeChatWindow makes irreversible decision on potentially stale data

src/providers/AIConversationProvider/index.tsx:629-639

activeConversationMessages.length === 0 is read from the closure to decide whether to delete the conversation. If a message was added between the last memoization and the click, the stale snapshot could still show length 0, deleting a conversation that has messages.

Suggested fix: Use activeConversationMessagesRef.current.length instead.

Unbounded tool-call recursion/iteration

src/utils/ai/anthropicProvider.ts:284-426 (recursive, stack overflow risk), src/utils/ai/openaiProvider.ts:368-461, src/utils/ai/openaiChatCompletionsProvider.ts:452-529 (iterative, token burn risk)

None of the three providers have a max-iterations guard on the tool-call loop. A misbehaving model that always returns tool_use will burn tokens unboundedly (or blow the stack in the Anthropic case).

Suggested fix: Add a MAX_TOOL_CALL_ROUNDS constant (e.g., 10-20) and bail with an error.

generateSummary ignores abort signal

src/utils/ai/anthropicProvider.ts:582-598, src/utils/ai/openaiProvider.ts:504-518, src/utils/ai/openaiChatCompletionsProvider.ts:564-581

All three providers' generateSummary implementations create streaming requests with no abort signal. If the user cancels during compaction, the summary stream runs to completion in the background, wasting tokens.


Low

AIStatusProvider context value not memoized

src/providers/AIStatusProvider/index.tsx:254-284

The context value object is created inline every render without useMemo. When the parent re-renders for unrelated reasons, all consumers re-render even if no context value changed.

currentSQL memo has overly broad dependency

src/scenes/Editor/AIChatWindow/index.tsx:264-266

currentSQL depends on the entire conversation object instead of conversation?.currentSQL. Should be [conversation?.currentSQL].

Compaction fast-path compares characters against token threshold

src/utils/contextCompaction.ts:152-158

totalChars (characters) is compared against compactionThreshold (tokens). Since chars outnumber tokens ~3-4x, this fast-path almost never short-circuits, defeating the intended optimization of skipping the expensive countTokens call.

replaceConversationMessages has latent duplication bug

src/providers/AIConversationProvider/index.tsx:495-499

The unconditional splice of the last newMessage works correctly for the current sole call site (compaction, where the last message always has a new UUID). But if any future caller passes messages where the last one's ID already exists in the array, it will be present both at its original position (replaced) and inserted again.

O(n²) array copies in OpenAI tool loops

src/utils/ai/openaiProvider.ts:353, 407, 448

input = [...input, ...items] on each iteration creates a full copy. input.push(...items) would be O(n) total.

emrberk and others added 15 commits April 14, 2026 01:36
- cancel active query on script-confirm so chat/editor queries don't
  orphan on the server when the "Run script" dialog is confirmed
- add onStop hook to markActive so confirmPending unblocks when the
  active execution is a multi-query selection script
- release _active when the script loop breaks via scriptStopRef
- drain pending microtasks before the script loop starts so iteration
  zero's "Running..." notification and glyph spinner aren't clobbered
  by a pending chat-abort addNotification
- chat completions provider: drop tools from last-round follow-up so
  MAX_TOOL_CALL_ROUNDS actually terminates the loop

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

2 participants