feat(editor): Add response grouping and thinking UI for instance AI (no-changelog)#28236
feat(editor): Add response grouping and thinking UI for instance AI (no-changelog)#28236
Conversation
Bundle ReportChanges will decrease total bundle size by 45.61MB (-100.0%) ⬇️. This is within the configured threshold ✅ Detailed changes
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Performance ComparisonComparing current → latest master → 14-day baseline Idle baseline with Instance AI module loaded
docker-stats
Memory consumption baseline with starter plan resources
How to read this table
|
…ents Remove header icon, task count, status badges, kind icons/badges, accordion behavior, and divider lines. Use N8nText, N8nInput components instead of raw HTML elements. Shorten approve button label to "Approve". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… mode contrast Restyle AnsweredQuestions to match user message alignment and appearance (right-aligned grey bubble). Use neutral design token for ConfirmationPreview background in dark mode for better contrast. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…section Extract communication style rules (conciseness, no emojis, always end with text) into a dedicated section, keeping Safety focused on actual safety concerns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ArtifactCard: replace hoverable prop with standard box-shadow hover - CredentialSetup & WorkflowSetup: remove green success border on completed/confirm cards, keep regular border Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…st spacing Use consistent medium-size buttons across all instance AI confirmation components, add background to gateway resource decision panel, and reduce thread item height to 32px with proper padding. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use design system N8nHeading for artifacts/tasks panel titles, increase pagination button sizes, use ghost variant for credential nav buttons, and lighten question list hover states. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove accidentally committed debug mock messages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tance AI Add ResponseGroup component and useTimelineGrouping composable for better organization of agent activity. Update agent-run-reducer schema, stream mapping, and timeline components to support grouped responses. Fix invalid CSS variable --text-color--subtler in AgentActivityTree and ArtifactCard.
…ponseId patch, keep intermediate text in groups - Extract HIDDEN_TOOLS to shared agentTimeline.utils - Preserve responseId when patching streaming timeline entries - Keep text inside groups when it shares the same API response as tool calls - Only render text inline when it comes from a standalone response
…s are always visible
…count, prevent premature collapse - Remove isCompleted gate — grouping applies as soon as responseId data exists - Last response group stays flat while agent is still active (prevents collapsing during streaming) - Groups with loading tool calls or active children don't collapse - Track and display answered questions count in group summaries
… inherit for agent-spawned - Capture responseId from step-start before the trace hooks branch (was skipped when hooks active) - Inherit responseId from parent timeline for agent-spawned events (emitted from tool code, not stream) - Remove temporary debug logging
…tant for sidebar width key
- Lazy-mount CollapsibleContent in ResponseGroup and AgentSection (v-if="isOpen" + force-mount) so reka-ui RAF loops and keyboard handlers are not registered for collapsed items - Fix InstanceAiMarkdown listener leak: clean up click handlers on onUpdated and onBeforeUnmount instead of accumulating them - Mutate workflowExecutions Map in-place with triggerRef instead of cloning on every SSE event in useExecutionPushEvents - Narrow useEventRelay watch to only track active workflow status and log length instead of the entire Map reference
Keep the readable original watch shape while adding a prevLogLength guard to skip redundant relay calls when the event log hasn't grown.
- Create AnimatedCollapsibleContent wrapper component with slideDown/ slideUp keyframes using reka-ui's --reka-collapsible-content-height - Replace raw CollapsibleContent in all 8 instance AI components - Make PlanReviewPanel header a collapsible trigger so the body collapses after approval - Add i18n key for changesRequested
…nal patterns Revert the triggerRef/in-place mutation optimization in useExecutionPushEvents and the prevLogLength guard in useEventRelay. The in-place mutation + triggerRef approach doesn't propagate correctly through Vue's watch equality check, causing test failures. The perf wins are maintained by the other fixes (InstanceAiMarkdown listener cleanup, AnimatedCollapsibleContent).
… counter Bring back in-place Map mutation in useExecutionPushEvents (avoids cloning the entire Map on every SSE event). Use a monotonic version counter ref instead of triggerRef so Vue's watch equality check properly detects changes. Update useEventRelay to watch the version counter, and update tests to bump version alongside mutations.
Replace version counter approach with shallowRef + triggerRef. This is the standard Vue pattern for in-place mutations on non-primitive refs: shallowRef skips deep reactivity wrapping so triggerRef properly notifies watchers. Avoids cloning the entire Map on every SSE event.
…tions Remove shallowRef/triggerRef/version-counter optimizations from useExecutionPushEvents and useEventRelay. Profiling showed these changes had no measurable impact on listener count or heap usage — the listener reduction attributed to them was actually caused by the relay watch silently breaking (never firing). Restore original patterns from master for correctness and simplicity.
Cadiac
left a comment
There was a problem hiding this comment.
👍 nice, pretty clean looking changes
There was a problem hiding this comment.
6 issues found across 37 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiMarkdown.vue">
<violation number="1" location="packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiMarkdown.vue:216">
P1: The new update cycle removes link click handlers but does not reattach them for already-enhanced links, which can break resource preview clicks after updates.</violation>
</file>
<file name="packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiConfirmationPanel.vue">
<violation number="1" location="packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiConfirmationPanel.vue:504">
P3: This change introduces a legacy background token (`--color--background--light-3`) in modified styles. Use the semantic token (`--color-background-xlight`) for new/updated code to align with design-system migration rules.</violation>
</file>
<file name="packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiThreadList.vue">
<violation number="1" location="packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiThreadList.vue:225">
P3: This token substitution changes thread list spacing (`--spacing--4xs` → `--spacing--2xs`). Please confirm this is an intentional visual adjustment and not an accidental regression.</violation>
<violation number="2" location="packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiThreadList.vue:245">
P2: Replace the hard-coded `32px` height with a design-system token (for example `var(--height--md)`) to keep sizing consistent and themeable.
(Based on your team's feedback about using design-system tokens for visual values when a matching token exists.) [FEEDBACK_USED]</violation>
</file>
<file name="packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiQuestions.vue">
<violation number="1" location="packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiQuestions.vue:619">
P3: This changes the hover background token from neutral-200 to neutral-100. Per the design-system style rules, token substitutions should be confirmed as intentional to avoid accidental visual regressions.</violation>
</file>
<file name="packages/frontend/editor-ui/src/features/ai/instanceAi/components/PlanReviewPanel.vue">
<violation number="1" location="packages/frontend/editor-ui/src/features/ai/instanceAi/components/PlanReviewPanel.vue:45">
P2: `isExpanded` is not kept in sync with `readOnly`, so the panel can stay open after approval/resolution instead of collapsing with the new read-only state.</violation>
</file>
Architecture diagram
sequenceDiagram
participant LLM as Anthropic / LLM
participant Exec as ResumableStreamExecutor (Backend)
participant Reducer as Agent Run Reducer
participant Store as InstanceAiStore (Frontend)
participant Grouping as useTimelineGrouping (Composable)
participant Tree as AgentActivityTree (UI)
participant Group as ResponseGroup (UI)
participant MD as InstanceAiMarkdown (UI)
Note over LLM, MD: Runtime Streaming & Grouping Flow
LLM->>Exec: SSE Chunk (step-start)
Exec->>Exec: NEW: Extract responseId (messageId)
LLM->>Exec: SSE Chunk (text-delta / tool-call)
Exec->>Reducer: NEW: Emit event with responseId
Reducer->>Reducer: CHANGED: Append to timeline<br/>(Merge text if responseId matches last)
Reducer-->>Store: Update Agent State
Store->>Grouping: Trigger reactivity (agentNode change)
Note over Grouping: Logic: Groups entries by responseId.<br/>Extracts trailing text as "conclusions".
Grouping-->>Tree: Return TimelineSegments[]
alt If Agent is Active (Streaming)
Tree->>Tree: Render AgentTimeline (Flat view)
else If Agent is Complete
Tree->>Group: NEW: Render ResponseGroup (Collapsible)
Group->>Group: NEW: Calculate summary<br/>(tool/message/question counts)
Group->>MD: Render trailing text (conclusion)
end
Note over MD: Performance & Resource Management
MD->>MD: CHANGED: enhanceResourceLinks()
MD->>MD: NEW: Track link click handlers in WeakMap
opt On Component Update / Unmount
MD->>MD: NEW: cleanupLinkHandlers() (Prevents memory leaks)
end
Note over Tree,Group: Animation Control
Group->>Group: NEW: AnimatedCollapsibleContent<br/>(Slide down/up animations)
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
| onMounted(enhanceResourceLinks); | ||
| onUpdated(enhanceResourceLinks); | ||
| onUpdated(() => { | ||
| cleanupLinkHandlers(); |
There was a problem hiding this comment.
P1: The new update cycle removes link click handlers but does not reattach them for already-enhanced links, which can break resource preview clicks after updates.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiMarkdown.vue, line 216:
<comment>The new update cycle removes link click handlers but does not reattach them for already-enhanced links, which can break resource preview clicks after updates.</comment>
<file context>
@@ -193,8 +198,25 @@ function enhanceResourceLinks(): void {
onMounted(enhanceResourceLinks);
-onUpdated(enhanceResourceLinks);
+onUpdated(() => {
+ cleanupLinkHandlers();
+ enhanceResourceLinks();
+});
</file context>
| .threadItem { | ||
| display: flex; | ||
| align-items: center; | ||
| height: 32px; |
There was a problem hiding this comment.
P2: Replace the hard-coded 32px height with a design-system token (for example var(--height--md)) to keep sizing consistent and themeable.
(Based on your team's feedback about using design-system tokens for visual values when a matching token exists.)
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiThreadList.vue, line 245:
<comment>Replace the hard-coded `32px` height with a design-system token (for example `var(--height--md)`) to keep sizing consistent and themeable.
(Based on your team's feedback about using design-system tokens for visual values when a matching token exists.) </comment>
<file context>
@@ -242,6 +242,7 @@ function handleThreadAction(action: string, threadId: string) {
.threadItem {
display: flex;
align-items: center;
+ height: 32px;
border-radius: var(--radius);
transition: background-color 0.1s ease;
</file context>
| height: 32px; | |
| height: var(--height--md); |
| expandedIds.value.delete(id); | ||
| } else { | ||
| expandedIds.value.add(id); | ||
| const isExpanded = ref(!props.readOnly); |
There was a problem hiding this comment.
P2: isExpanded is not kept in sync with readOnly, so the panel can stay open after approval/resolution instead of collapsing with the new read-only state.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/frontend/editor-ui/src/features/ai/instanceAi/components/PlanReviewPanel.vue, line 45:
<comment>`isExpanded` is not kept in sync with `readOnly`, so the panel can stay open after approval/resolution instead of collapsing with the new read-only state.</comment>
<file context>
@@ -35,38 +37,23 @@ const emit = defineEmits<{
- expandedIds.value.delete(id);
- } else {
- expandedIds.value.add(id);
+const isExpanded = ref(!props.readOnly);
+
+function getDescription(task: PlannedTaskArg): string {
</file context>
| .root { | ||
| border: var(--border); | ||
| border-radius: var(--radius--lg); | ||
| background-color: var(--color--background--light-3); |
There was a problem hiding this comment.
P3: This change introduces a legacy background token (--color--background--light-3) in modified styles. Use the semantic token (--color-background-xlight) for new/updated code to align with design-system migration rules.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiConfirmationPanel.vue, line 504:
<comment>This change introduces a legacy background token (`--color--background--light-3`) in modified styles. Use the semantic token (`--color-background-xlight`) for new/updated code to align with design-system migration rules.</comment>
<file context>
@@ -501,6 +501,7 @@ function isAllGenericApproval(items: PendingConfirmationItem[]): boolean {
.root {
border: var(--border);
border-radius: var(--radius--lg);
+ background-color: var(--color--background--light-3);
}
</file context>
| background-color: var(--color--background--light-3); | |
| background-color: var(--color-background-xlight); |
| flex: 1; | ||
| overflow-y: auto; | ||
| padding: var(--spacing--4xs); | ||
| padding: var(--spacing--2xs); |
There was a problem hiding this comment.
P3: This token substitution changes thread list spacing (--spacing--4xs → --spacing--2xs). Please confirm this is an intentional visual adjustment and not an accidental regression.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiThreadList.vue, line 225:
<comment>This token substitution changes thread list spacing (`--spacing--4xs` → `--spacing--2xs`). Please confirm this is an intentional visual adjustment and not an accidental regression.</comment>
<file context>
@@ -222,7 +222,7 @@ function handleThreadAction(action: string, threadId: string) {
flex: 1;
overflow-y: auto;
- padding: var(--spacing--4xs);
+ padding: var(--spacing--2xs);
}
</file context>
| &:hover, | ||
| &.highlighted { | ||
| background-color: light-dark(var(--color--neutral-200), var(--color--neutral-800)); | ||
| background-color: light-dark(var(--color--neutral-100), var(--color--neutral-800)); |
There was a problem hiding this comment.
P3: This changes the hover background token from neutral-200 to neutral-100. Per the design-system style rules, token substitutions should be confirmed as intentional to avoid accidental visual regressions.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiQuestions.vue, line 619:
<comment>This changes the hover background token from neutral-200 to neutral-100. Per the design-system style rules, token substitutions should be confirmed as intentional to avoid accidental visual regressions.</comment>
<file context>
@@ -619,7 +616,7 @@ function onOptionMouseEnter(idx: number) {
&:hover,
&.highlighted {
- background-color: light-dark(var(--color--neutral-200), var(--color--neutral-800));
+ background-color: light-dark(var(--color--neutral-100), var(--color--neutral-800));
}
</file context>
|
Got released with |
…no-changelog) (n8n-io#28236) Co-authored-by: Tuukka Kantola <tuukka@n8n.io> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
responseIdthrough stream chunks and agent-spawned tool calls for accurate groupingAnimatedCollapsibleContentcomponent with slide animations for all collapsible sectionsPlanReviewPanelheader a collapsible trigger so the body collapses after approvalInstanceAiMarkdownevent listener leak (clean up handlers on update/unmount)Related Linear tickets, Github issues, and Community forum posts
Builds on #28155
Review / Merge checklist
Test plan