feat(frontend): Show thinking indicator between CoPilot tool calls - #12203
feat(frontend): Show thinking indicator between CoPilot tool calls#12203Otto-AGPT wants to merge 3 commits into
Conversation
When CoPilot executes multiple tool calls in sequence, the UI now shows the thinking indicator (e.g. 'Reasoning...', 'On it...') between completed tool calls while the LLM processes the result. Previously, the indicator only appeared before the first response. Detects when the last message part is a completed tool call (state=result) and re-shows the shimmer indicator with a fresh random phrase. Fixes SECRT-2035
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
🔍 PR Overlap DetectionThis check compares your PR against all other open PRs targeting the same branch to detect potential merge conflicts early. 🔴 Merge Conflicts DetectedThe following PRs have been tested and will have merge conflicts if merged after this PR. Consider coordinating with the authors.
Summary: 1 conflict(s), 0 medium risk, 0 low risk (out of 1 PRs with file overlap) Auto-generated on push. Ignores: |
WalkthroughDetects and handle a "thinking after tool call" state inside ChatMessagesContainer by tracking the last assistant/tool output with a ref, updating the thinking phrase on transitions, and extending rendering conditions for the thinking indicator. No public API changes. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 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 |
| const lastPart = lastMessage.parts[lastMessage.parts.length - 1]; | ||
| return ( | ||
| lastPart.type.startsWith("tool-") && | ||
| (lastPart as ToolUIPart).state === "result" |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx (1)
123-129: Pre-existing: component is an arrow function, not a function declaration.The coding guidelines require function declarations for components. This is pre-existing and out of scope for this PR, but worth noting for a future cleanup.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx around lines 123 - 129, The component ChatMessagesContainer is currently defined as an arrow function; update it to a standard function declaration to follow the project coding guidelines by refactoring the export const ChatMessagesContainer = (...) => { ... } into export function ChatMessagesContainer(...) { ... } (preserving the same props type ChatMessagesContainerProps, parameter names messages/status/error/isLoading/headerSlot, and all existing implementation and exports).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx:
- Around line 142-153: The isThinkingAfterToolCall expression uses an IIFE and
checks (lastPart as ToolUIPart).state === "result", which is invalid; change the
check to use the correct state "output-available" and simplify the IIFE into a
plain local variable for readability: extract const lastPart =
lastMessage.parts[lastMessage.parts.length - 1] before the return and compare
(lastPart as ToolUIPart).state === "output-available" inside
isThinkingAfterToolCall; keep the surrounding status and role checks as-is to
preserve behavior.
---
Nitpick comments:
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx:
- Around line 123-129: The component ChatMessagesContainer is currently defined
as an arrow function; update it to a standard function declaration to follow the
project coding guidelines by refactoring the export const ChatMessagesContainer
= (...) => { ... } into export function ChatMessagesContainer(...) { ... }
(preserving the same props type ChatMessagesContainerProps, parameter names
messages/status/error/isLoading/headerSlot, and all existing implementation and
exports).
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: types
- GitHub Check: Check PR Status
🧰 Additional context used
📓 Path-based instructions (10)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}: Use Node.js 21+ with pnpm package manager for frontend development
Always run 'pnpm format' for formatting and linting code in frontend development
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/frontend/**/*.{tsx,ts}: Use function declarations for components and handlers (not arrow functions) in React components
Only use arrow functions for small inline lambdas (map, filter, etc.) in React components
Use PascalCase for component names and camelCase with 'use' prefix for hook names in React
Use Tailwind CSS utilities only for styling in frontend components
Use design system components from 'src/components/' (atoms, molecules, organisms) in frontend development
Never use 'src/components/legacy/' in frontend code
Only use Phosphor Icons (@phosphor-icons/react) for icons in frontend components
Use generated API hooks from '@/app/api/generated/endpoints/' instead of deprecated 'BackendAPI' or 'src/lib/autogpt-server-api/'
Use React Query for server state (via generated hooks) in frontend development
Default to client components ('use client') in Next.js; only use server components for SEO or extreme TTFB needs
Use '' component for rendering errors in frontend UI; use toast notifications for mutation errors; use 'Sentry.captureException()' for manual exceptions
Separate render logic from data/behavior in React components; keep comments minimal (code should be self-documenting)
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/frontend/**/*.{ts,tsx}: No barrel files or 'index.ts' re-exports in frontend code
Regenerate API hooks with 'pnpm generate:api' after backend OpenAPI spec changes in frontend development
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/CLAUDE.md)
autogpt_platform/frontend/src/**/*.{ts,tsx}: Fully capitalize acronyms in symbols, e.g.graphID,useBackendAPI
Use function declarations (not arrow functions) for components and handlers
Separate render logic (.tsx) from business logic (use*.tshooks)
Use shadcn/ui (Radix UI primitives) with Tailwind CSS styling for UI components
Use Phosphor Icons only for icons
Use ErrorCard for render errors, toast for mutations, and Sentry for exceptions
Use design system components fromsrc/components/(atoms, molecules, organisms)
Never usesrc/components/__legacy__/*components
Use generated API hooks from@/app/api/__generated__/endpoints/with patternuse{Method}{Version}{OperationName}
Use Tailwind CSS only for styling, with design tokens
Do not useuseCallbackoruseMemounless asked to optimize a given function
Never type withanyunless a variable/attribute can ACTUALLY be of any type
autogpt_platform/frontend/src/**/*.{ts,tsx}: Structure components asComponentName/ComponentName.tsx+useComponentName.ts+helpers.tsand use design system components fromsrc/components/(atoms, molecules, organisms)
Use generated API hooks from@/app/api/__generated__/endpoints/with patternuse{Method}{Version}{OperationName}and regenerate withpnpm generate:api
Use function declarations (not arrow functions) for components and handlers
Separate render logic from business logic with component.tsx + useComponent.ts + helpers.ts structure
Colocate state when possible, avoid creating large components, use sub-components in local/componentsfolder
Avoid large hooks, abstract logic intohelpers.tsfiles when sensible
Use arrow functions only for callbacks, not for component declarations
Avoid comments at all times unless the code is very complex
Do not useuseCallbackoruseMemounless asked to optimize a given function
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/app/(platform)/**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/CLAUDE.md)
Put sub-components in local
components/folder within feature directories
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/**/*.tsx
📄 CodeRabbit inference engine (autogpt_platform/frontend/CLAUDE.md)
Component props should be
type Props = { ... }(not exported) unless it needs to be used outside the componentComponent props should be
interface Props { ... }(not exported) unless the interface needs to be used outside the component
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}: Format frontend code usingpnpm format
Never use components fromsrc/components/__legacy__/*
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use Tailwind CSS only for styling, use design tokens, and use Phosphor Icons only
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Never type with
any, if no types available useunknown
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/app/(platform)/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
If adding protected frontend routes, update
frontend/lib/supabase/middleware.ts
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
🪛 GitHub Actions: AutoGPT Platform - Frontend CI
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
[error] 151-151: Type error: This comparison appears to be unintentional because the types '"input-streaming" | "input-available" | "approval-requested" | "approval-responded" | "output-available" | "output-error" | "output-denied"' and '"result"' have no overlap.
[error] 151-151: Next.js build failed. Command 'pnpm build' exited with code 1 due to TypeScript type incompatibility at the comparison above.
🔇 Additional comments (2)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx (2)
160-172: Effect logic for refreshing thinking phrases looks correct.The two effects have distinct triggers — one for
status === "submitted"and one for the rising edge ofisThinkingAfterToolCallvia the ref guard — so they won't interfere with each other and each picks a fresh random phrase at the right moment.One minor note: if
isThinkingAfterToolCallis fixed (per the build error above), the second effect will correctly fire only when entering the "thinking after tool call" state and not on every render while in that state, thanks to thewasThinkingAfterToolref.
303-305: Rendering condition correctly extends the thinking indicator for tool-call gaps.The condition
(!messageHasVisibleContent || isThinkingAfterToolCall)ensures the indicator appears both when the assistant message has no visible content yet and after a tool call completes with visible tool results already present. This is the right approach — the indicator will disappear once a new text part starts streaming.
…cator Change ToolUIPart.state check from "result" (invalid) to "output-available" (the actual AI SDK state for a completed tool call). This fixes the build and makes the thinking-between-tool-calls feature functional. Also simplifies the IIFE into a plain local variable for readability. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx (1)
160-160: Remove inline section comments — code is self-documenting here.
isThinkingAfterToolCalland theuseEffectdependency on it are self-describing; the comments add no information beyond what the identifiers already convey. Per coding guidelines, comments should be omitted unless the code is genuinely complex.♻️ Suggested cleanup
- // Detect when the LLM is thinking after a completed tool call const lastPart =- // Pick a new phrase when entering "thinking after tool call" state useEffect(() => {Based on learnings: "Applies to
autogpt_platform/frontend/**/*.{tsx,ts}: Separate render logic from data/behavior in React components; keep comments minimal (code should be self-documenting)."Also applies to: 183-184
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx at line 160, Remove the inline section comment "// Detect when the LLM is thinking after a completed tool call" and similar self-describing comments around the isThinkingAfterToolCall variable and the useEffect that depends on it in ChatMessagesContainer (the comment at the start of the isThinkingAfterToolCall section and at 183-184); leave the variable name isThinkingAfterToolCall and the useEffect intact so behavior is unchanged, only delete the redundant comment to comply with the guideline of omitting self-documenting comments.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@autogpt_platform/frontend/src/app/`(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx:
- Line 160: Remove the inline section comment "// Detect when the LLM is
thinking after a completed tool call" and similar self-describing comments
around the isThinkingAfterToolCall variable and the useEffect that depends on it
in ChatMessagesContainer (the comment at the start of the
isThinkingAfterToolCall section and at 183-184); leave the variable name
isThinkingAfterToolCall and the useEffect intact so behavior is unchanged, only
delete the redundant comment to comply with the guideline of omitting
self-documenting comments.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Seer Code Review
- GitHub Check: types
- GitHub Check: Analyze (python)
- GitHub Check: end-to-end tests
- GitHub Check: Check PR Status
🧰 Additional context used
📓 Path-based instructions (10)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/frontend/**/*.{ts,tsx,js,jsx}: Use Node.js 21+ with pnpm package manager for frontend development
Always run 'pnpm format' for formatting and linting code in frontend development
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/frontend/**/*.{tsx,ts}: Use function declarations for components and handlers (not arrow functions) in React components
Only use arrow functions for small inline lambdas (map, filter, etc.) in React components
Use PascalCase for component names and camelCase with 'use' prefix for hook names in React
Use Tailwind CSS utilities only for styling in frontend components
Use design system components from 'src/components/' (atoms, molecules, organisms) in frontend development
Never use 'src/components/legacy/' in frontend code
Only use Phosphor Icons (@phosphor-icons/react) for icons in frontend components
Use generated API hooks from '@/app/api/generated/endpoints/' instead of deprecated 'BackendAPI' or 'src/lib/autogpt-server-api/'
Use React Query for server state (via generated hooks) in frontend development
Default to client components ('use client') in Next.js; only use server components for SEO or extreme TTFB needs
Use '' component for rendering errors in frontend UI; use toast notifications for mutation errors; use 'Sentry.captureException()' for manual exceptions
Separate render logic from data/behavior in React components; keep comments minimal (code should be self-documenting)
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/frontend/**/*.{ts,tsx}: No barrel files or 'index.ts' re-exports in frontend code
Regenerate API hooks with 'pnpm generate:api' after backend OpenAPI spec changes in frontend development
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/CLAUDE.md)
autogpt_platform/frontend/src/**/*.{ts,tsx}: Fully capitalize acronyms in symbols, e.g.graphID,useBackendAPI
Use function declarations (not arrow functions) for components and handlers
Separate render logic (.tsx) from business logic (use*.tshooks)
Use shadcn/ui (Radix UI primitives) with Tailwind CSS styling for UI components
Use Phosphor Icons only for icons
Use ErrorCard for render errors, toast for mutations, and Sentry for exceptions
Use design system components fromsrc/components/(atoms, molecules, organisms)
Never usesrc/components/__legacy__/*components
Use generated API hooks from@/app/api/__generated__/endpoints/with patternuse{Method}{Version}{OperationName}
Use Tailwind CSS only for styling, with design tokens
Do not useuseCallbackoruseMemounless asked to optimize a given function
Never type withanyunless a variable/attribute can ACTUALLY be of any type
autogpt_platform/frontend/src/**/*.{ts,tsx}: Structure components asComponentName/ComponentName.tsx+useComponentName.ts+helpers.tsand use design system components fromsrc/components/(atoms, molecules, organisms)
Use generated API hooks from@/app/api/__generated__/endpoints/with patternuse{Method}{Version}{OperationName}and regenerate withpnpm generate:api
Use function declarations (not arrow functions) for components and handlers
Separate render logic from business logic with component.tsx + useComponent.ts + helpers.ts structure
Colocate state when possible, avoid creating large components, use sub-components in local/componentsfolder
Avoid large hooks, abstract logic intohelpers.tsfiles when sensible
Use arrow functions only for callbacks, not for component declarations
Avoid comments at all times unless the code is very complex
Do not useuseCallbackoruseMemounless asked to optimize a given function
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/app/(platform)/**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (autogpt_platform/frontend/CLAUDE.md)
Put sub-components in local
components/folder within feature directories
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/**/*.tsx
📄 CodeRabbit inference engine (autogpt_platform/frontend/CLAUDE.md)
Component props should be
type Props = { ... }(not exported) unless it needs to be used outside the componentComponent props should be
interface Props { ... }(not exported) unless the interface needs to be used outside the component
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx}: Format frontend code usingpnpm format
Never use components fromsrc/components/__legacy__/*
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/**/*.{js,jsx,ts,tsx,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use Tailwind CSS only for styling, use design tokens, and use Phosphor Icons only
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Never type with
any, if no types available useunknown
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
autogpt_platform/frontend/src/app/(platform)/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
If adding protected frontend routes, update
frontend/lib/supabase/middleware.ts
Files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
🧠 Learnings (2)
📚 Learning: 2026-02-04T16:49:42.490Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.490Z
Learning: Applies to autogpt_platform/frontend/**/*.{tsx,ts} : Separate render logic from data/behavior in React components; keep comments minimal (code should be self-documenting)
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
📚 Learning: 2026-02-04T16:50:33.615Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/frontend/CLAUDE.md:0-0
Timestamp: 2026-02-04T16:50:33.615Z
Learning: Applies to autogpt_platform/frontend/src/**/*.tsx : Component props should be `type Props = { ... }` (not exported) unless it needs to be used outside the component
Applied to files:
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx
🔇 Additional comments (2)
autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/ChatMessagesContainer.tsx (2)
149-189: New thinking-after-tool-call logic is correct and well-structured.
- The
wasThinkingAfterToolref correctly gatessetThinkingPhraseto fire only on the false→true transition, preventing repeated phrase churn on consecutive re-renders while the tool output remainsoutput-available.isThinkingAfterToolCallcorrectly requiresstatus === "streaming"+ a terminal tool-part state (output-available), and the"result"→"output-available"fix from the previous review cycle is in place.- The two
useEffects have non-overlapping triggers (status === "submitted"vs.isThinkingAfterToolCall), so no double-update race exists.
320-326: Render condition correctly gates inline thinking indicator.
(!messageHasVisibleContent || isThinkingAfterToolCall)ensures the shimmer renders inside the existing assistant bubble after tool parts rather than spawning a duplicate bubble (which is handled by thelastMessage?.role !== "assistant"guard at line 331). No issues.
autogpt-reviewer
left a comment
There was a problem hiding this comment.
PR #12203 — feat(frontend): Show thinking indicator between CoPilot tool calls
Author: Otto-AGPT | Requested by: majdyz | Files: ChatMessagesContainer.tsx (+32/-10)
🎯 Verdict: APPROVE
What This PR Does
When CoPilot executes multiple tool calls in sequence, the UI previously showed no feedback between completed tool calls — users saw a "dead pause" with no indication the LLM was processing the tool output. This PR re-shows the thinking indicator ("Reasoning...", "On it...") after each tool call completes while the LLM processes the result. The indicator disappears as soon as new text starts streaming. Single-file change, no backend modifications, no new dependencies. Fixes SECRT-2035.
Specialist Findings
🛡️ Security ✅ — No security concerns. thinkingPhrase renders hardcoded static strings via React JSX (auto-escaped). The as ToolUIPart cast is guarded by the startsWith("tool-") discriminator check. No dangerouslySetInnerHTML, no new external data consumed, no new attack surface. Purely cosmetic UI change.
🏗️ Architecture ✅ — Clean design. useRef(false) for edge detection (wasThinkingAfterTool) is the correct React pattern — avoids unnecessary re-renders that useState would cause. isThinkingAfterToolCall is derived state (not stored), following single-source-of-truth. No new coupling — component already imports ToolUIPart and inspects part.type. Props interface unchanged.
useThinkingState hook.
⚡ Performance ✅ — Negligible overhead. ~5 boolean checks + 1 O(1) array index access per render. useState(getRandomPhrase) correctly uses lazy initializer. wasThinkingAfterTool ref prevents render loops — setThinkingPhrase fires exactly once per false→true transition. No risk of oscillation.
🧪 Testing ChatMessagesContainer has zero existing tests, and the entire copilot directory has no test files. Frontend has only 2 unit test files total. Given this near-zero baseline, this is a nice-to-have rather than a blocker. Notable untested edge case: output-error/output-denied tool states don't trigger the indicator (arguably correct UX — errors should surface differently).
📖 Quality ✅ — Readability grade A. Code is clean and focused. as ToolUIPart cast pattern is consistent with lines 248–310 in the same file. Two minor nits: (1) wasThinkingAfterTool ref drops "Call" vs isThinkingAfterToolCall — rename to wasThinkingAfterToolCall for symmetry; (2) two redundant inline comments (lines 167, 186) that project "minimal comments" guidelines would trim.
📦 Product ✅ — Solves the real "dead pause" UX gap. Flicker risk eliminated by ref-based edge detection. Random phrase rotation makes multi-tool sequences feel alive. Indicator placement (after tool parts, within same bubble) provides natural reading flow. Accessible — shimmer text is real text for screen readers.
📬 Discussion ✅ — All CodeRabbit findings addressed. Critical build-breaking bug ("result" → "output-available") caught by CodeRabbit + CI + Sentry, fixed in commit 592e967. IIFE simplified to plain variable. Only unaddressed item is cosmetic (redundant comments). CI: 17/17 green. Zero human reviewers so far.
🔎 QA
ThinkingPhrases flip animation produces ~100+ motion.dev warnings per phrase change (animate filter from "blur(NaNpx)", animate rotateX from "NaNdeg"). Pre-existing animation issue, not introduced by this PR, but now triggered more frequently due to additional phrase changes. Does not crash or affect visual behavior.
Evidence:
Blockers
None.
Should Fix (Follow-up OK)
ChatMessagesContainer.tsx:149— RenamewasThinkingAfterTool→wasThinkingAfterToolCallfor naming consistency withisThinkingAfterToolCallChatMessagesContainer.tsx:167,186— Remove redundant inline comments per project "minimal comments" conventionThinkingPhrasescomponent — Fix animation NaN warnings (blur(NaNpx),rotateX(NaNdeg)) inAnimatePresencetransitions (pre-existing, not introduced by this PR, but now more visible)- Consider merging the two
useEffecthooks forthinkingPhraseinto one for clarity
Risk Assessment
Merge risk: LOW | Rollback: EASY (single file, no API changes, no backend changes)
@ntindle Clean, minimal change that solves a real user-facing UX gap. All 8 specialists approve or have non-blocking concerns only. CI green, feature confirmed working in live QA with video evidence. Ship it.
|
This pull request has conflicts with the base branch, please resolve those so we can evaluate the pull request. |




Requested by @majdyz
When CoPilot executes multiple tool calls in sequence, the UI previously showed no feedback between completed tool calls — users saw a pause with no indication that the LLM was processing. Now the thinking indicator (e.g. "Reasoning...", "On it...") re-appears after each tool call completes while the LLM processes the result.
Changes
ToolUIPart.state === "result") and re-show the shimmer indicatorHow it works
The existing
showThinkinglogic only triggered before the first response. A newisThinkingAfterToolCallcheck looks at the last part of the assistant message — if it's a tool part withstate === "result"and the stream is still active, we know the LLM is processing the tool output and show the indicator.The indicator disappears as soon as new text starts streaming (because the last part is no longer a completed tool call).
Single file change
ChatMessagesContainer.tsx— no backend changes, no new dependencies.Fixes SECRT-2035