Repository navigation
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds per-tool-call timing: records startedAt/completedAt during tool execution, stores timings in AI state and restores them from persisted assistant message metadata, injects timings into message metadata on persist/error, and surfaces formatted elapsed durations in the UI via a new hook and utilities. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as Client/UI
participant Transport as chatTransport
participant Store as AI Store (ai.toolTimings)
participant Tool as Tool Executor
participant Hook as useElapsedTime
UI->>Transport: initiate tool call
Transport->>Store: setToolTiming(toolCallId, { startedAt })
Transport->>Tool: tool.execute(...)
Tool-->>Transport: result / error
Transport->>Store: setToolTiming(toolCallId, { startedAt, completedAt })
Store->>Hook: ai.toolTimings read
Hook->>UI: formatted elapsed text (updates while running)
UI->>Transport: persist session
Transport->>Store: getToolTimings()
Transport->>Transport: writeToolTimingsToMetadata(messages, toolTimings)
Transport->>Persist: save messages with metadata
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/ai-core/src/chatTransport.ts (2)
303-364:⚠️ Potential issue | 🟠 MajorRecord
completedAtfor failed tool executions too.The new timing flow only writes
completedAtafter a successfultool.execute. Iftool.executethrows, the entry stays as{startedAt}even though the UI part becomesoutput-error, which makes elapsed time render-time dependent instead of execution-time dependent and persists incomplete timing data. StampcompletedAtin the catch path before emitting the error result.Suggested fix
}: { sessionId: string; toolCall: ToolCall; addToolResult?: AddToolResult; }) => { const {input, toolCallId, toolName} = toolCall; + let startedAt: number | undefined; try { const state = store.getState(); const session = getSessionById(store, sessionId); state.ai.setToolCallSession(toolCallId, sessionId); @@ const tool = state.ai.tools[toolName]; if (tool?.execute) { const sessionMessages = (session?.uiMessages ?? []) as UIMessage[]; - const startedAt = Date.now(); + startedAt = Date.now(); state.ai.setToolTiming(toolCallId, {startedAt}); @@ } catch (error) { + if (startedAt != null) { + store.getState().ai.setToolTiming(toolCallId, { + startedAt, + completedAt: Date.now(), + }); + } const isAbortError = error instanceof ToolAbortError;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ai-core/src/chatTransport.ts` around lines 303 - 364, The timing entry only sets completedAt on success; update the catch block to also record completedAt by calling state.ai.setToolTiming(toolCallId, {startedAt: existingStartedAt?, completedAt: Date.now()}) before emitting the error result so failed executions have finished timestamps; locate the try/catch around tool.execute in chatTransport.ts (references: tool.execute, state.ai.setToolTiming, addToolResult, ToolAbortError, TOOL_CALL_CANCELLED, getErrorMessageForDisplay, and store.getState().ai.setToolCallSession) and ensure completedAt is stamped prior to calling addToolResult and rethrowing the error.
380-447:⚠️ Potential issue | 🟠 MajorPersist timings when the run ends in
onChatErroras well.
writeToolTimingsToMetadata(...)is only invoked fromonChatFinish. When the transport falls throughonChatErrorafter one or more tool calls have already run,targetSession.uiMessagesgets stored withoutmetadata.toolTimings, andpackages/ai-core/src/AiSlice.tshas nothing to rehydrate from on reload. Please run the same enrichment step before writing messages in the error handler.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ai-core/src/chatTransport.ts` around lines 380 - 447, When handling the aborted/error path in onChatError (the branch that builds completedMessages from sessionMessages and calls state.ai.setSessionUiMessages), run the same enrichment step as onChatFinish: call fixIncompleteToolCalls to produce completedMessages (already present) and then call writeToolTimingsToMetadata(completedMessages, state.ai.getToolTimings()) before state.ai.setSessionUiMessages(sessionId, completedMessages); this ensures metadata.toolTimings is persisted for rehydration. Use the existing helpers fixIncompleteToolCalls and writeToolTimingsToMetadata and keep the rest of the abort/error handling (setIsRunning, setAbortController, and the produce(...) update) unchanged.
🧹 Nitpick comments (1)
packages/ai-core/src/components/ToolCallInfo.tsx (1)
62-80: Give the disclosure trigger explicit button semantics.Line 62 toggles a collapsible region, but the trigger still lacks
type="button"and doesn't expose its open state. Addingtype="button"plusaria-expanded(and ideallyaria-controls) makes this safe inside forms and announces the expand/collapse state to assistive tech.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ai-core/src/components/ToolCallInfo.tsx` around lines 62 - 80, The disclosure button in ToolCallInfo (the <button> that calls toggle and renders ChevronDownIcon/ChevronRightIcon using isExpanded, toolName, showElapsed, elapsedText) needs explicit button semantics: add type="button" to prevent accidental form submissions, add aria-expanded={isExpanded} to expose open state, and add aria-controls pointing to the collapsible region's id (create or reuse a stable id for the content panel) so assistive tech can associate the trigger with the controlled region.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/ai-core/src/components/ToolPartRenderer.tsx`:
- Around line 109-121: The timer badge in ToolPartRenderer currently calculates
elapsed inline and won't auto-update for pending tool calls; extract the badge
into a new child component (or reuse the pattern from ToolCallInfo) that accepts
toolCall.startedAt and toolCall.completedAt and uses the existing useElapsedTime
hook to drive re-renders, then render formatted output via
formatShortDuration(elapsed). Specifically, replace the inline IIFE that
computes elapsed with a component (e.g., ToolPartElapsedBadge) which imports
useElapsedTime, computes elapsed = useElapsedTime(startedAt, completedAt),
decides visibility with completedAt != null || elapsed >= 1000, and returns the
same <span className="ml-1 text-[0.85em]
text-gray-400">{formatShortDuration(elapsed)}</span> so pending tool calls
update live.
---
Outside diff comments:
In `@packages/ai-core/src/chatTransport.ts`:
- Around line 303-364: The timing entry only sets completedAt on success; update
the catch block to also record completedAt by calling
state.ai.setToolTiming(toolCallId, {startedAt: existingStartedAt?, completedAt:
Date.now()}) before emitting the error result so failed executions have finished
timestamps; locate the try/catch around tool.execute in chatTransport.ts
(references: tool.execute, state.ai.setToolTiming, addToolResult,
ToolAbortError, TOOL_CALL_CANCELLED, getErrorMessageForDisplay, and
store.getState().ai.setToolCallSession) and ensure completedAt is stamped prior
to calling addToolResult and rethrowing the error.
- Around line 380-447: When handling the aborted/error path in onChatError (the
branch that builds completedMessages from sessionMessages and calls
state.ai.setSessionUiMessages), run the same enrichment step as onChatFinish:
call fixIncompleteToolCalls to produce completedMessages (already present) and
then call writeToolTimingsToMetadata(completedMessages,
state.ai.getToolTimings()) before state.ai.setSessionUiMessages(sessionId,
completedMessages); this ensures metadata.toolTimings is persisted for
rehydration. Use the existing helpers fixIncompleteToolCalls and
writeToolTimingsToMetadata and keep the rest of the abort/error handling
(setIsRunning, setAbortController, and the produce(...) update) unchanged.
---
Nitpick comments:
In `@packages/ai-core/src/components/ToolCallInfo.tsx`:
- Around line 62-80: The disclosure button in ToolCallInfo (the <button> that
calls toggle and renders ChevronDownIcon/ChevronRightIcon using isExpanded,
toolName, showElapsed, elapsedText) needs explicit button semantics: add
type="button" to prevent accidental form submissions, add
aria-expanded={isExpanded} to expose open state, and add aria-controls pointing
to the collapsible region's id (create or reuse a stable id for the content
panel) so assistive tech can associate the trigger with the controlled region.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b59b295b-33ea-4ab4-b1e2-28618916c283
📒 Files selected for processing (12)
packages/ai-core/src/AiSlice.tspackages/ai-core/src/agents/AgentUtils.tspackages/ai-core/src/chatTransport.tspackages/ai-core/src/components/GroupedMessageParts.tsxpackages/ai-core/src/components/ReasoningBox.tsxpackages/ai-core/src/components/ToolCallInfo.tsxpackages/ai-core/src/components/ToolPartRenderer.tsxpackages/ai-core/src/hooks/useElapsedTime.tspackages/ai-core/src/hooks/useToolGrouping.tsxpackages/ai-core/src/types.tspackages/utils/src/helpers.tspackages/utils/src/index.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/ai-core/src/AiSlice.ts`:
- Around line 490-497: setConfig currently replaces draft.ai.toolTimings with
collectToolTimingsFromConfig(config), which discards any in-flight timings
(entries with startedAt and no completedAt) if called mid-execution; instead,
merge restoredToolTimings with the existing state to preserve in-flight entries:
inside setConfig’s produce callback (where you set draft.ai.config and
draft.ai.toolTimings), compute a merged list by taking restoredToolTimings and
then re-attaching any timings from the prior state.toolTimings that have
startedAt && !completedAt (matching by a unique id or name if available) so
in-flight timings are not lost when setConfig runs. Ensure you reference
setConfig, collectToolTimingsFromConfig, draft.ai.config and
draft.ai.toolTimings when making the change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2a3330e7-ed9c-4437-8c06-8158fc6cef29
📒 Files selected for processing (3)
packages/ai-core/src/AiSlice.tspackages/ai-core/src/chatTransport.tspackages/ai-core/src/components/ToolPartRenderer.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/ai-core/src/chatTransport.ts
| isRunning = false, | ||
| toolCallIds, | ||
| }) => { | ||
| const displayTitle = title ?? 'Thought'; |
There was a problem hiding this comment.
For the generic label I would suggest to use "Worked for 4m 18s" instead of just "Thought".
Ideally, if we could ask AI to generate a short phrase explaining what's happening, like "Finding datasets", "Analyzing data", "Creating a map", that would be fantastic.
See also this.
There was a problem hiding this comment.
Sounds good! Can I address this in a new PR and land this PR for now? THanks!
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
packages/ai-core/src/hooks/useToolGrouping.tsx (1)
34-35: Avoid a fresh{}default fortoolDisplayNames.Because
AnalysisResultforwards this prop asundefinedwhen it is omitted, the default object here is recreated on every render. That makes theuseMemodependency change every time, so regrouping reruns unconditionally.♻️ Proposed fix
+const EMPTY_TOOL_DISPLAY_NAMES: Record<string, string> = {}; + export function useToolGrouping( uiMessageParts: UIMessagePart[], containerWidth: number = 0, exclude: string[] = [], - toolDisplayNames: Record<string, string> = {}, + toolDisplayNames: Record<string, string> = EMPTY_TOOL_DISPLAY_NAMES, ): ToolGroup[] {Also applies to: 199-199
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ai-core/src/hooks/useToolGrouping.tsx` around lines 34 - 35, The default parameter toolDisplayNames: Record<string,string> = {} in useToolGrouping creates a new object each render; change the signature to accept toolDisplayNames?: Record<string,string> (or default to a module‑level constant) and introduce a single stable EMPTY_TOOL_DISPLAY_NAMES = Object.freeze({}) at top scope, then use that constant inside useToolGrouping (referencing toolDisplayNames ?? EMPTY_TOOL_DISPLAY_NAMES) so the memo deps are stable; make the same change for the other occurrence that uses the same default for toolDisplayNames.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/ai-core/src/hooks/useToolGrouping.tsx`:
- Around line 173-179: The header should only show "Running ..." when this
group's parts are actually still pending, so change the running-condition logic
to require both that at least one tool part is not in an output state and that
the group's overall isRunning flag remains true; specifically, use the existing
toolParts check (groupIsRunning = toolParts.some(p => !((p as any).state ===
'output-available' || (p as any).state === 'output-error'))) AND combine it with
the group's isRunning/hasMoreToolsAfter-derived flag when deciding the
header/display; apply the same fix to the other occurrences noted (around lines
189-190 and 319-329) so finished groups (all parts in output-*) never render the
"Running ${toolLabel}..." header even if hasMoreToolsAfter is true.
- Around line 273-287: The code currently deduplicates by raw tool name (using
toolNamesList) which can produce duplicate headers when different names map to
the same display label and can produce an empty title if all names become
'unknown'; change the logic in the block that builds uniqueDisplayNames (working
with actualToolParts, getToolName, toolDisplayNames, formatToolNameFallback) to
compute the final label first (const label = toolDisplayNames[name] ??
formatToolNameFallback(name)), then deduplicate based on that label (use
seen.has(label)), pushing the label into uniqueDisplayNames only if not seen,
and ensure you supply a generic fallback label (e.g., 'Tool') when the computed
label is empty so downstream titles are never empty.
---
Nitpick comments:
In `@packages/ai-core/src/hooks/useToolGrouping.tsx`:
- Around line 34-35: The default parameter toolDisplayNames:
Record<string,string> = {} in useToolGrouping creates a new object each render;
change the signature to accept toolDisplayNames?: Record<string,string> (or
default to a module‑level constant) and introduce a single stable
EMPTY_TOOL_DISPLAY_NAMES = Object.freeze({}) at top scope, then use that
constant inside useToolGrouping (referencing toolDisplayNames ??
EMPTY_TOOL_DISPLAY_NAMES) so the memo deps are stable; make the same change for
the other occurrence that uses the same default for toolDisplayNames.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5120388f-cf85-41ea-aad1-12bbd3f17837
📒 Files selected for processing (4)
packages/ai-core/src/components/AnalysisResult.tsxpackages/ai-core/src/components/AnalysisResultsContainer.tsxpackages/ai-core/src/components/ReasoningBox.tsxpackages/ai-core/src/hooks/useToolGrouping.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/ai-core/src/components/ReasoningBox.tsx
|
Update the reasoning box wording: Screen.Recording.2026-03-31.at.10.45.06.AM.mp4 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/ai-core/src/chatTransport.ts (1)
39-78: Consider documenting the mutation expectation or returning a new array.This function mutates
msg.metadatain-place. It works correctly because all call sites pass the result offixIncompleteToolCalls(), which returns cloned message objects. However, this implicit contract could be fragile if a future caller passes the original messages array.Consider either:
- Adding a JSDoc note that the function mutates messages and expects cloned input, or
- Returning a new array with updated metadata (more defensive but adds allocation overhead)
The current implementation is functional—this is just a suggestion for maintainability.
📝 Option 1: Add documentation
/** * Write tool timings from the store into assistant message metadata so they * survive serialization. + * + * **Note:** This function mutates `messages` in place. Callers should pass + * cloned messages (e.g., from `fixIncompleteToolCalls`). */ function writeToolTimingsToMetadata(🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ai-core/src/chatTransport.ts` around lines 39 - 78, The function writeToolTimingsToMetadata mutates each UIMessage's msg.metadata in-place and relies on callers (currently fixIncompleteToolCalls) to supply cloned messages; add a clear JSDoc above writeToolTimingsToMetadata stating that it mutates the messages array and expects cloned UIMessage objects (reference UIMessage, AssistantMessageMetadata, and fixIncompleteToolCalls) so callers know not to pass original arrays, or alternatively refactor writeToolTimingsToMetadata to be pure by returning a new UIMessage[] with updated metadata (update call sites accordingly) if you prefer the defensive non-mutating approach.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/ai-core/src/chatTransport.ts`:
- Around line 39-78: The function writeToolTimingsToMetadata mutates each
UIMessage's msg.metadata in-place and relies on callers (currently
fixIncompleteToolCalls) to supply cloned messages; add a clear JSDoc above
writeToolTimingsToMetadata stating that it mutates the messages array and
expects cloned UIMessage objects (reference UIMessage, AssistantMessageMetadata,
and fixIncompleteToolCalls) so callers know not to pass original arrays, or
alternatively refactor writeToolTimingsToMetadata to be pure by returning a new
UIMessage[] with updated metadata (update call sites accordingly) if you prefer
the defensive non-mutating approach.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7d61ef17-a7f1-45c5-af37-e0c50ffcb145
📒 Files selected for processing (2)
packages/ai-core/src/chatTransport.tspackages/ai-core/src/hooks/useToolGrouping.tsx
There was a problem hiding this comment.
🧹 Nitpick comments (4)
packages/ai-core/src/components/ReasoningBox.tsx (2)
69-94: Agent name formatting is duplicated.The name formatting logic (lines 80-83) is identical to
ReasoningBox.tsxlines 80-83. Consider extracting to a shared utility:♻️ Extract shared formatter
// In a shared utils file export function formatAgentName(toolName: string): string { return toolName .replace(/-/g, ' ') .replace(/([a-z])([A-Z])/g, '$1 $2') .replace(/\b\w/g, (c) => c.toUpperCase()); }This is the same pattern as
formatToolNameFallbackinuseToolGrouping.tsx(lines 220-225), so you could potentially reuse that function.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ai-core/src/components/ReasoningBox.tsx` around lines 69 - 94, Extract the duplicated agent name formatting from latestSubReasoning into a shared utility (e.g., formatAgentName) and replace the inline logic inside latestSubReasoning with a call to that utility; update any other places using the same pattern (refer to formatToolNameFallback in useToolGrouping.tsx) to reuse the new function, ensuring latestSubReasoning still calls truncateToFit(reasoning, containerWidth, prefix.length) with prefix = `${formatAgentName(tc.toolName)}: ` and that agentProgress and containerWidth remain in the useMemo dependency array.
39-43: Selecting entiretoolTimingsobject may cause excess re-renders.Line 39 selects the entire
s.ai.toolTimingsrecord. Any timing update to any tool call will trigger a re-render of this component, even if none of thetoolCallIdsfor this box changed. Consider selecting only the relevant entries:♻️ Scoped timing selection
- const toolTimings = useStoreWithAi((s) => s.ai.toolTimings); + const relevantTimings = useStoreWithAi((s) => { + if (!toolCallIds?.length) return undefined; + const result: Record<string, { startedAt: number; completedAt?: number }> = {}; + for (const id of toolCallIds) { + const t = s.ai.toolTimings[id]; + if (t) result[id] = t; + } + return result; + });Then update the
useMemoto userelevantTimingsinstead oftoolTimings. Note: The selector now derives an object, so you should use a shallow-equality check or move the derivation touseMemowith raw IDs as dependency. A cleaner approach per coding guidelines:+ // Select raw timing entries individually to avoid selector-derived objects + const timingEntries = useMemo(() => { + if (!toolCallIds?.length) return []; + return toolCallIds.map((id) => toolTimings[id]).filter(Boolean); + }, [toolCallIds, toolTimings]);This keeps the selector simple while the derivation happens in React.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ai-core/src/components/ReasoningBox.tsx` around lines 39 - 43, The component currently selects the entire s.ai.toolTimings via useStoreWithAi which causes unnecessary re-renders; change the selector to only read the raw tool call IDs needed (e.g., select s.ai.toolTimings keys or the array of toolCallIds) and move the derivation of relevantTimings into a useMemo that depends on those raw IDs and the full toolTimings accessor, or alternatively adjust the selector to return only the specific entries for this box; update the useMemo that currently uses toolTimings to use relevantTimings (or the memoized subset) and ensure any selector returning derived objects uses shallow equality to avoid re-renders (refer to useStoreWithAi, toolTimings, agentToolCallId, and the existing useMemo that computes relevantTimings).packages/ai-core/src/components/ToolPartRenderer.tsx (2)
128-138: Consider extracting the reasoning type guard.The inline type checking for
toolCall.input.reasoningis repeated here and inToolPartRenderer(lines 301-304) andReasoningBox.tsx. A shared helper likegetToolCallReasoning(input: unknown): string | undefinedwould reduce duplication.♻️ Optional helper extraction
// In a shared utils file export function getToolCallReasoning(input: unknown): string | undefined { if ( input instanceof Object && 'reasoning' in input && typeof (input as Record<string, unknown>).reasoning === 'string' ) { return (input as Record<string, unknown>).reasoning as string; } return undefined; }Then usage becomes:
- {toolCall.input instanceof Object && - 'reasoning' in toolCall.input && - typeof (toolCall.input as Record<string, unknown>).reasoning === - 'string' ? ( - <div className="mb-1 text-sm text-gray-500"> - { - (toolCall.input as Record<string, unknown>) - .reasoning as string - } - </div> - ) : null} + {getToolCallReasoning(toolCall.input) && ( + <div className="mb-1 text-sm text-gray-500"> + {getToolCallReasoning(toolCall.input)} + </div> + )}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ai-core/src/components/ToolPartRenderer.tsx` around lines 128 - 138, Extract the repeated inline type-guard into a shared helper named getToolCallReasoning(input: unknown): string | undefined and replace the duplicated checks in ToolPartRenderer (the JSX block rendering toolCall.input.reasoning) and ReasoningBox.tsx with calls to this helper; specifically, implement getToolCallReasoning to return the reasoning string when input is an Object with a string "reasoning" property and undefined otherwise, then import and use getToolCallReasoning(toolCall.input) in the conditional render and any other locations instead of repeating the instanceof/'reasoning'/'typeof' checks.
214-217: Passing emptyagentToolCallswhenliveProgressis used is confusing.When
liveProgressexists, the component passesagentToolCalls={[]}butAgentProgressRendererignores it viadisplayCalls = liveProgress ?? agentToolCalls. This works but obscures the data flow. Consider passingliveProgressdirectly:♻️ Clearer prop passing
if (liveProgress && liveProgress.length > 0) { return ( - <AgentProgressRenderer toolCallId={toolCallId} agentToolCalls={[]} /> + <AgentProgressRenderer toolCallId={toolCallId} agentToolCalls={liveProgress} /> ); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ai-core/src/components/ToolPartRenderer.tsx` around lines 214 - 217, ToolPartRenderer currently passes agentToolCalls={[]} when liveProgress exists, which obscures data flow; change the call in ToolPartRenderer to pass the actual liveProgress (e.g., AgentProgressRenderer toolCallId={toolCallId} agentToolCalls={liveProgress}) so AgentProgressRenderer's internal displayCalls = liveProgress ?? agentToolCalls receives the data directly and avoids the confusing empty-array override.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/ai-core/src/components/ReasoningBox.tsx`:
- Around line 69-94: Extract the duplicated agent name formatting from
latestSubReasoning into a shared utility (e.g., formatAgentName) and replace the
inline logic inside latestSubReasoning with a call to that utility; update any
other places using the same pattern (refer to formatToolNameFallback in
useToolGrouping.tsx) to reuse the new function, ensuring latestSubReasoning
still calls truncateToFit(reasoning, containerWidth, prefix.length) with prefix
= `${formatAgentName(tc.toolName)}: ` and that agentProgress and containerWidth
remain in the useMemo dependency array.
- Around line 39-43: The component currently selects the entire s.ai.toolTimings
via useStoreWithAi which causes unnecessary re-renders; change the selector to
only read the raw tool call IDs needed (e.g., select s.ai.toolTimings keys or
the array of toolCallIds) and move the derivation of relevantTimings into a
useMemo that depends on those raw IDs and the full toolTimings accessor, or
alternatively adjust the selector to return only the specific entries for this
box; update the useMemo that currently uses toolTimings to use relevantTimings
(or the memoized subset) and ensure any selector returning derived objects uses
shallow equality to avoid re-renders (refer to useStoreWithAi, toolTimings,
agentToolCallId, and the existing useMemo that computes relevantTimings).
In `@packages/ai-core/src/components/ToolPartRenderer.tsx`:
- Around line 128-138: Extract the repeated inline type-guard into a shared
helper named getToolCallReasoning(input: unknown): string | undefined and
replace the duplicated checks in ToolPartRenderer (the JSX block rendering
toolCall.input.reasoning) and ReasoningBox.tsx with calls to this helper;
specifically, implement getToolCallReasoning to return the reasoning string when
input is an Object with a string "reasoning" property and undefined otherwise,
then import and use getToolCallReasoning(toolCall.input) in the conditional
render and any other locations instead of repeating the
instanceof/'reasoning'/'typeof' checks.
- Around line 214-217: ToolPartRenderer currently passes agentToolCalls={[]}
when liveProgress exists, which obscures data flow; change the call in
ToolPartRenderer to pass the actual liveProgress (e.g., AgentProgressRenderer
toolCallId={toolCallId} agentToolCalls={liveProgress}) so
AgentProgressRenderer's internal displayCalls = liveProgress ?? agentToolCalls
receives the data directly and avoids the confusing empty-array override.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7272c98b-91da-44b2-80b6-ea412b9e7871
📒 Files selected for processing (6)
packages/ai-core/src/agents/AgentUtils.tspackages/ai-core/src/components/AnalysisResult.tsxpackages/ai-core/src/components/GroupedMessageParts.tsxpackages/ai-core/src/components/ReasoningBox.tsxpackages/ai-core/src/components/ToolPartRenderer.tsxpackages/ai-core/src/hooks/useToolGrouping.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/ai-core/src/components/GroupedMessageParts.tsx
- packages/ai-core/src/components/AnalysisResult.tsx
- packages/ai-core/src/agents/AgentUtils.ts
|
Since we are going to migrate to AI SDK V6 which has different implementation of agent (with its own loop executiono f sub-tools), we can implement elapsed time in #497 directly. |
Summary by CodeRabbit