Skip to content

Conversation

@Pwuts
Copy link
Member

@Pwuts Pwuts commented Dec 16, 2025

OPEN-2743: Ability to Update Sub-Agents in Graph (Without Re-Adding)

Updating sub-graphs is a cumbersome experience at the moment, this should help. :)

Demo in Builder v2:

2026-01-02.15.03.vivaldi.mp4
2026-01-02.17.00.vivaldi.mp4

Changes 🏗️

  • Add sub-graph update banner with I/O incompatibility notification and resolution mode
    • Builder v1: Add CustomNode > IncompatibilityDialog + SubAgentUpdateBar sub-components
    • Builder v2: Add SubAgentUpdateFeature + ResolutionModeBar + IncompatibleUpdateDialog + useSubAgentUpdateState sub-components
    • Add useSubAgentUpdate hook
  • Related fixes in Builder v1:
    • Fix static edges not rendering as such
    • Fix edge styling not applying
  • Related fixes in Builder v2:
    • Fix excess spacing for nested node input fields

Checklist 📋

For code changes:

  • I have clearly listed my changes in the PR description
  • I have made a test plan
  • I have tested my changes according to the test plan:
    • CI for existing frontend UX flows
    • Updating to a new sub-agent version with compatibility issues: UX flow works
    • Updating to a new sub-agent version with no compatibility issues: works
    • Designer approves of the look

Summary by CodeRabbit

  • New Features

    • Sub-agent update detection with compatibility checks, update UI, and confirmation dialogs
    • Resolution mode workflow to stage and apply incompatible updates, auto-apply after fixes
    • Visual resolution aids: update bars, incompatibility tooltips/dialogs, and broken-output indicators
  • Bug Fixes

    • Retry now triggers a full page reload for non-login errors
  • Refactor

    • Standardized edge ID shape and node/edge state for resolution flows
    • Simplified form rendering and expanded schema types for inputs/outputs
  • Style

    • Updated debug panel label and added clearer red/amber visuals for broken/incompatible states

✏️ Tip: You can customize this high-level summary in your review settings.

@netlify
Copy link

netlify bot commented Dec 16, 2025

Deploy Preview for auto-gpt-docs-dev canceled.

Name Link
🔨 Latest commit c55121c
🔍 Latest deploy log https://app.netlify.com/projects/auto-gpt-docs-dev/deploys/6942f8b9b316610008aa7c82

@coderabbitai
Copy link

coderabbitai bot commented Dec 16, 2025

Walkthrough

Implements in-graph sub-agent updates with a resolution mode: detects compatible vs incompatible updates, stages incompatible updates, tracks and visually flags broken connections, and applies pending updates once broken edges are resolved.

Changes

Cohort / File(s) Summary
Sub-Agent Update UI & Components
.../FlowEditor/nodes/CustomNode/components/SubAgentUpdate/*, .../legacy-builder/CustomNode/SubAgentUpdateBar.tsx, .../legacy-builder/CustomNode/IncompatibilityDialog.tsx
New components (SubAgentUpdateFeature, SubAgentUpdateBar, Incompatible/Incompatibility dialogs, ResolutionModeBar) for displaying update availability, incompatibilities, and resolution UI.
Sub-Agent Update Logic & Hooks
.../build/hooks/useSubAgentUpdate/*
New hook useSubAgentUpdate, helpers, and types to detect updates, compute incompatibilities, and expose update metadata (SubAgentUpdateInfo, IncompatibilityInfo, GraphMetaLike).
Resolution Mode State & Store APIs
.../build/stores/nodeStore.ts, .../build/stores/graphStore.ts, .../legacy-builder/Flow/Flow.tsx
Adds per-node resolution state (nodesInResolutionMode, nodeResolutionData, brokenEdgeIDs) and graphStore.availableSubGraphs plus public setters and Flow-level enter/exit/applyResolution APIs.
Editor Integration & Auto-apply Flow
.../FlowEditor/Flow/useFlow.ts, .../legacy-builder/BuildActionBar.tsx, .../legacy-builder/Flow/Flow.tsx
Fetches available graphs, syncs to graphStore, wires resolutionMode into builder context, shows banner when resolution is active, and auto-applies pending updates when broken edges cleared.
Node / Edge Visuals & Interactivity
.../FlowEditor/edges/CustomEdge.tsx, .../legacy-builder/CustomEdge/CustomEdge.tsx, .../FlowEditor/handlers/NodeHandle.tsx, .../legacy-builder/NodeHandle.tsx, .../FlowEditor/nodes/OutputHandler.tsx, .../FlowEditor/nodes/useBrokenOutputs.ts
Adds isBroken propagation to edges/handles/outputs, visual indicators (red/dashed/thicker strokes, strikethrough labels), and disables interactions for broken handles.
Node Components & Resolution Merging
.../FlowEditor/nodes/CustomNode/CustomNode.tsx, .../legacy-builder/CustomNode/CustomNode.tsx, .../FlowEditor/nodes/CustomNode/helpers.ts
Integrates resolution-mode logic into node rendering, adds mergeSchemaForResolution to combine current and pending schemas preserving compatible props.
Form Renderer / Layout Refactor
.../nodes/FormCreator.tsx, .../BuilderActions/components/RunInputDialog/RunInputDialog.tsx, components/renderers/input-renderer/FormRenderer.tsx
Remove wrapper divs and pass className directly to FormRenderer; FormCreator now has explicit props/interface and displayName.
Input Renderers: Broken / Type Mismatch UI
components/.../AnyOfField.tsx, .../templates/FieldTemplate.tsx, .../widgets/ObjectEditorWidget/ObjectEditorWidget.tsx
Integrates nodeStore checks into field templates/widgets to show broken inputs, type mismatches, and passes isBroken to NodeHandle.
Edge/Connection Shape Migration
.../legacy-builder/CustomNode/CustomNode.tsx, .../legacy-builder/NodeInputs.tsx, .../legacy-builder/NodeTableInput.tsx, .../legacy-builder/useCopyPaste.ts, .../hooks/useAgentGraph.tsx
Migrates edge identifier from edge_idid, introduces ConnectedEdge shape and updates copy/paste and graph loader mappings.
Types & Utils
src/lib/autogpt-server-api/types.ts, src/lib/utils.ts, .../build/hooks/useSubAgentUpdate/types.ts
Adds GraphInputSchema/GraphOutputSchema types, updates GraphMeta usages, adds getEffectiveType utility and other schema/type helpers.
Misc & Small UI/Behavior Changes
.../RightSidebar.tsx, error.tsx, legacy-builder/BlocksControl.tsx
Changes debug panel label to "Graph Debug Panel", retry now reloads document, broadens _Block input/output schema unions.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as SubAgentUpdateBar / Node UI
    participant Hook as useSubAgentUpdate
    participant Store as nodeStore / graphStore
    participant Flow as FlowEditor / Flow

    User->>UI: Click "Update"
    UI->>Hook: Request update check (availableGraphs, schemas, connections)
    Hook->>Hook: Compare versions & compute incompatibilities
    alt Compatible
        Hook-->>UI: isCompatible = true
        UI->>Flow: applyUpdate(nodeID, newHardcodedValues)
        Flow->>Store: updateNodeData(nodeID, values)
        Store-->>UI: Node updated
    else Incompatible
        Hook-->>UI: isCompatible = false + incompatibilities
        UI->>UI: Open IncompatibilityDialog / show ResolutionModeBar
        User->>UI: Confirm "Update Anyway"
        UI->>Flow: enterResolutionMode(nodeID, incompatibilities, brokenEdgeIds, pendingUpdate)
        Flow->>Store: setNodeResolutionMode & setBrokenEdgeIDs
        Store-->>UI: Render broken visuals (red/dashed edges, disabled handles)
        loop User fixes connections
            User->>UI: Remove/adjust broken edges
            UI->>Store: edge state updated
        end
        alt all broken edges cleared
            Store->>Flow: notify cleared
            Flow->>Flow: applyPendingUpdate(nodeID)
            Flow->>Store: clearResolutionState(nodeID)
            Store-->>UI: Exit resolution mode
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested labels

Review effort 4/5

Suggested reviewers

  • Swiftyos
  • Bentlybro
  • 0ubbe

Poem

🐰 I nibble through schema vines and threads,
I patch the agents, lift their heads,
When red lines shout and edges fall,
I tidy paths and mend them all,
Hop—update done, the graph leaps ahead!

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.62% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive The PR implements Milestone 1 (in-place updates preserving connections) and partially addresses Milestone 2 (version visibility). However, Milestone 3 (hierarchy-aware updates) is incomplete, and testing for compatibility-free updates remains unchecked per reviewer comments. Complete remaining test cases (updating without compatibility issues) and designer approval, then update the PR checklist. Milestone 3 (hierarchy update flow) should be addressed in a follow-up if not in scope for this PR.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(frontend/builder): Add sub-graph update UX' accurately describes the main change—adding UI for updating sub-agents. It is specific, concise, and aligns with the primary objective of implementing in-place sub-graph updates.
Out of Scope Changes check ✅ Passed All changes directly support sub-agent update functionality, including resolution mode, incompatibility detection, edge styling, and schema merging. Minor fixes (e.g., spacing, error page retry) are incidental but aligned with the primary feature.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 61f2e03 and 81622ac.

📒 Files selected for processing (1)
  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
🧰 Additional context used
📓 Path-based instructions (8)
autogpt_platform/frontend/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/frontend/**/*.{ts,tsx}: Always run pnpm install before frontend development, then use pnpm dev to start development server on port 3000
For frontend code formatting and linting, always run pnpm format

If adding protected frontend routes, update frontend/lib/supabase/middleware.ts

autogpt_platform/frontend/**/*.{ts,tsx}: Use generated API hooks from @/app/api/__generated__/endpoints/ for data fetching in frontend
Use function declarations (not arrow functions) for components and handlers in frontend
Only use Phosphor Icons in frontend; never use other icon libraries
Never use src/components/__legacy__/* or deprecated BackendAPI in frontend

Files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
autogpt_platform/frontend/**/*.{ts,tsx,json}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use Node.js 21+ with pnpm package manager for frontend development

Files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
autogpt_platform/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

autogpt_platform/frontend/src/**/*.{ts,tsx}: Use generated API hooks from @/app/api/generated/endpoints/ (generated via Orval from backend OpenAPI spec). Pattern: use{Method}{Version}{OperationName} (e.g., useGetV2ListLibraryAgents). Regenerate with: pnpm generate:api. Never use deprecated BackendAPI or src/lib/autogpt-server-api/*
Use function declarations for components and handlers (not arrow functions). Only arrow functions for small inline lambdas (map, filter, etc.)
Use PascalCase for components, camelCase with use prefix for hooks
No barrel files or index.ts re-exports in frontend
For frontend render errors, use component. For mutation errors, display with toast notifications. For manual exceptions, use Sentry.captureException()
Default to client components (use client). Use server components only for SEO or extreme TTFB needs. Use React Query for server state via generated hooks. Co-locate UI state in components/hooks

Files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
autogpt_platform/frontend/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Format frontend code using pnpm format

Files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
autogpt_platform/frontend/**

📄 CodeRabbit inference engine (autogpt_platform/CLAUDE.md)

autogpt_platform/frontend/**: Install frontend dependencies using pnpm i instead of npm
Generate API client from OpenAPI spec using pnpm generate:api
Regenerate API client hooks using pnpm generate:api when OpenAPI spec changes

Files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
autogpt_platform/frontend/src/**/*.tsx

📄 CodeRabbit inference engine (autogpt_platform/CLAUDE.md)

Use design system components from src/components/ (atoms, molecules, organisms) in frontend

Files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
autogpt_platform/frontend/src/app/**/*.tsx

📄 CodeRabbit inference engine (autogpt_platform/CLAUDE.md)

Create frontend pages in src/app/(platform)/feature-name/page.tsx with corresponding usePageName.ts hook and local components/ subfolder

Files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
autogpt_platform/frontend/**/*.{ts,tsx,css}

📄 CodeRabbit inference engine (autogpt_platform/CLAUDE.md)

Use only Tailwind CSS for styling in frontend, with design tokens and Phosphor Icons

Files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
🧠 Learnings (8)
📚 Learning: 2025-11-25T08:48:33.246Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-25T08:48:33.246Z
Learning: Applies to autogpt_platform/frontend/src/components/**/*.tsx : Only use Phosphor Icons (phosphor-icons/react) for icon components in frontend

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
📚 Learning: 2025-11-25T08:49:03.583Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/CLAUDE.md:0-0
Timestamp: 2025-11-25T08:49:03.583Z
Learning: Applies to autogpt_platform/frontend/**/*.{ts,tsx} : Never use `src/components/__legacy__/*` or deprecated `BackendAPI` in frontend

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
📚 Learning: 2025-11-25T08:49:03.583Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/CLAUDE.md:0-0
Timestamp: 2025-11-25T08:49:03.583Z
Learning: Applies to autogpt_platform/frontend/**/*.{ts,tsx} : Only use Phosphor Icons in frontend; never use other icon libraries

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
📚 Learning: 2025-11-25T08:48:33.246Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-25T08:48:33.246Z
Learning: Applies to autogpt_platform/frontend/src/**/*.{ts,tsx} : No barrel files or index.ts re-exports in frontend

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
📚 Learning: 2025-11-25T08:49:03.583Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/CLAUDE.md:0-0
Timestamp: 2025-11-25T08:49:03.583Z
Learning: Applies to autogpt_platform/frontend/**/*.{ts,tsx,css} : Use only Tailwind CSS for styling in frontend, with design tokens and Phosphor Icons

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
📚 Learning: 2025-11-25T08:48:33.246Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-25T08:48:33.246Z
Learning: Applies to autogpt_platform/frontend/src/components/**/*.tsx : Prefer design tokens over hardcoded values in frontend styling

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
📚 Learning: 2025-11-25T08:48:33.246Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-25T08:48:33.246Z
Learning: Applies to autogpt_platform/frontend/src/components/**/*.tsx : Use Tailwind CSS utilities only for styling in frontend. Use design system components from src/components/ (atoms, molecules, organisms). Never use src/components/__legacy__/*

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
📚 Learning: 2025-11-25T08:49:03.583Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: autogpt_platform/CLAUDE.md:0-0
Timestamp: 2025-11-25T08:49:03.583Z
Learning: Applies to autogpt_platform/frontend/src/**/*.tsx : Use design system components from `src/components/` (atoms, molecules, organisms) in frontend

Applied to files:

  • autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx
🧬 Code graph analysis (1)
autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx (1)
autogpt_platform/frontend/src/lib/utils.ts (1)
  • cn (15-17)
⏰ 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: Seer Code Review
  • GitHub Check: Seer Code Review
🔇 Additional comments (1)
autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx (1)

5-5: LGTM! Well-implemented resolution mode feature.

The resolution mode implementation is clean and follows all coding guidelines:

  • ✅ Correctly uses WarningIcon from Phosphor Icons (line 5)
  • ✅ Prop signature is properly typed with optional resolutionModeActive (line 16)
  • ✅ Early return pattern improves readability (lines 32-49)
  • ✅ Semantic amber styling appropriately conveys warning state
  • ✅ Dark mode support is consistent with the design system
  • ✅ Clear, actionable message guides users to resolve incompatibilities

The feature integrates smoothly with the existing component structure.

Also applies to: 16-16, 27-27, 32-49


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@netlify
Copy link

netlify bot commented Dec 16, 2025

Deploy Preview for auto-gpt-docs canceled.

Name Link
🔨 Latest commit c55121c
🔍 Latest deploy log https://app.netlify.com/projects/auto-gpt-docs/deploys/6942f8b91f22610008e5537a

@github-actions github-actions bot added the platform/frontend AutoGPT Platform - Front end label Dec 16, 2025
@deepsource-io
Copy link

deepsource-io bot commented Dec 16, 2025

Here's the code health analysis summary for commits cc91791..c55121c. View details on DeepSource ↗.

Analysis Summary

AnalyzerStatusSummaryLink
DeepSource JavaScript LogoJavaScript✅ Success
❗ 15 occurences introduced
🎯 2 occurences resolved
View Check ↗
DeepSource Python LogoPython✅ SuccessView Check ↗

💡 If you’re a repository administrator, you can configure the quality gates from the settings.

@AutoGPT-Agent
Copy link

Thanks for implementing this sub-graph update feature! This will definitely improve the user experience when working with sub-agents in the graph editor.

The code looks good with well-structured components for handling updates, incompatibility detection, and resolution mode. I particularly like the clear visual indicators for broken connections and the detailed incompatibility dialog.

Before merging

You need to complete your test plan by verifying all the test scenarios you've outlined:

  • Updating to a new sub-agent version with compatibility issues: UX flow works
  • Updating to a new sub-agent version with no compatibility issues: works
  • Designer approves of the look

Once you've completed all the tests and received design approval, please update the checklist to reflect this.

Minor notes

  • The approach with resolution mode and visual indicators for broken connections is excellent for guiding users through the process
  • Great work on the IncompatibilityDialog component that clearly explains what's changed between versions
  • The edge rendering fixes are a nice bonus improvement

Please let us know when you've completed the remaining tests so we can merge this improvement.

@AutoGPT-Agent
Copy link

Thank you for this PR that addresses the sub-graph update UX! The implementation looks thorough and well-designed.

Looking Good

  • Clear description linking to the issue
  • Well-organized code with good component structure
  • Comprehensive handling of compatibility issues between versions
  • Nice UI features with appropriate warnings and visual indicators

Before Merging

Your test plan needs completion:

  • You've marked that you tested updating with compatibility issues
  • The following items remain untested or unchecked:
    • Updating to a new sub-agent version with no compatibility issues
    • Designer approves of the look

Please complete the remaining test plan items to ensure this feature works as expected in all scenarios. Once those are checked off, this should be ready to merge.

Is there anything you need help with to finish testing these scenarios?

@Pwuts Pwuts marked this pull request as ready for review December 19, 2025 22:03
@Pwuts Pwuts requested a review from a team as a code owner December 19, 2025 22:03
@Pwuts Pwuts requested review from Bentlybro and Swiftyos and removed request for a team December 19, 2025 22:03
@AutoGPT-Agent
Copy link

Thanks for working on improving the sub-graph update experience! This is a valuable enhancement that will make the builder UX much better.

Feedback

Your implementation looks well thought out, with good separation of concerns between the UI components and the core logic in the useSubAgentUpdate hook. I particularly like how you've handled the resolution mode to guide users through fixing incompatible connections.

However, before we can merge this PR:

  1. Complete the test plan: You've marked that you haven't fully tested the "Updating to a new sub-agent version with no compatibility issues" scenario yet. Please complete this test to ensure all flows work correctly.

  2. Designer approval: The checklist indicates designer approval is needed but this item isn't checked off. Please get confirmation from a designer that the new UI elements meet our design standards.

Once these two items are addressed, the PR should be ready for merging. The code implementation itself looks solid and well-structured.

@AutoGPT-Agent
Copy link

Thanks for your PR implementing the sub-graph update UX! This is a valuable improvement that will make updating sub-agents much more user-friendly.

The implementation looks thorough - I like how you've added comprehensive UI elements for detecting updates and handling incompatibilities, particularly the resolution mode that highlights broken connections.

Before this can be approved, please complete the remaining test item in your checklist:

  • Updating to a new sub-agent version with no compatibility issues: works

Once you've tested this scenario and checked it off, this PR should be ready for approval. The implementation itself looks solid, with good separation of concerns between the detection logic and UI components.

@AutoGPT-Agent
Copy link

Thanks for this well-structured PR implementing the sub-graph update UX! The feature looks comprehensive, with support for both builder versions and thorough handling of compatibility issues.

The code changes look good, but I noticed that your checklist has one uncompleted item: "Designer approves of the look". Since this involves significant UI changes with new dialogs, banners, and resolution workflows, design approval appears to be required by your team's process.

Before this can be merged, please ensure you've received design approval for the UI elements, and check that item off in the PR description.

@Pwuts Pwuts requested review from 0ubbe and Abhi1992002 January 2, 2026 16:17
@Pwuts Pwuts enabled auto-merge January 2, 2026 16:17
Comment on lines 345 to 386
nodesInResolutionMode: new Set<string>(),
brokenEdgeIDs: new Set<string>(),
nodeResolutionData: new Map<string, NodeResolutionData>(),

setNodeResolutionMode: (
nodeID: string,
inResolution: boolean,
resolutionData?: NodeResolutionData,
) => {
set((state) => {
const newNodesSet = new Set(state.nodesInResolutionMode);
const newResolutionDataMap = new Map(state.nodeResolutionData);

if (inResolution) {
newNodesSet.add(nodeID);
if (resolutionData) {
newResolutionDataMap.set(nodeID, resolutionData);
}
} else {
newNodesSet.delete(nodeID);
newResolutionDataMap.delete(nodeID);
}

return {
nodesInResolutionMode: newNodesSet,
nodeResolutionData: newResolutionDataMap,
};
});
},

isNodeInResolutionMode: (nodeId: string) => {
return get().nodesInResolutionMode.has(nodeId);
},

getNodeResolutionData: (nodeId: string) => {
return get().nodeResolutionData.get(nodeId);
},

setBrokenEdgeIDs: (edgeIds: string[]) => {
set({ brokenEdgeIDs: new Set(edgeIds) });
},

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical: Global brokenEdgeIDs causes conflicts with per-node resolution mode

The brokenEdgeIDs is stored as a single global Set<string> (line 346), but resolution mode is tracked per-node via nodesInResolutionMode: Set<string> (line 345). This creates a critical bug:

  1. If two nodes enter resolution mode simultaneously, their broken edge IDs will be mixed in the same global set
  2. When one node completes resolution and calls setBrokenEdgeIds([]), it clears ALL broken edges, breaking the other node's resolution state
  3. The setNodeResolutionMode function (lines 349-373) doesn't clear brokenEdgeIDs when exiting resolution mode, leaving stale data

Fix: Change the data structure to track broken edges per node:

brokenEdgeIDs: Map<string, Set<string>>, // nodeId -> Set of broken edge IDs

setBrokenEdgeIDs: (nodeId: string, edgeIds: string[]) => {
  set((state) => {
    const newMap = new Map(state.brokenEdgeIDs);
    newMap.set(nodeId, new Set(edgeIds));
    return { brokenEdgeIDs: newMap };
  });
},

removeBrokenEdgeID: (nodeId: string, edgeId: string) => {
  set((state) => {
    const newMap = new Map(state.brokenEdgeIDs);
    const nodeSet = new Set(newMap.get(nodeId));
    nodeSet.delete(edgeId);
    newMap.set(nodeId, nodeSet);
    return { brokenEdgeIDs: newMap };
  });
},

Also update setNodeResolutionMode to clean up node-specific broken edges when exiting resolution mode.

Suggested change
nodesInResolutionMode: new Set<string>(),
brokenEdgeIDs: new Set<string>(),
nodeResolutionData: new Map<string, NodeResolutionData>(),
setNodeResolutionMode: (
nodeID: string,
inResolution: boolean,
resolutionData?: NodeResolutionData,
) => {
set((state) => {
const newNodesSet = new Set(state.nodesInResolutionMode);
const newResolutionDataMap = new Map(state.nodeResolutionData);
if (inResolution) {
newNodesSet.add(nodeID);
if (resolutionData) {
newResolutionDataMap.set(nodeID, resolutionData);
}
} else {
newNodesSet.delete(nodeID);
newResolutionDataMap.delete(nodeID);
}
return {
nodesInResolutionMode: newNodesSet,
nodeResolutionData: newResolutionDataMap,
};
});
},
isNodeInResolutionMode: (nodeId: string) => {
return get().nodesInResolutionMode.has(nodeId);
},
getNodeResolutionData: (nodeId: string) => {
return get().nodeResolutionData.get(nodeId);
},
setBrokenEdgeIDs: (edgeIds: string[]) => {
set({ brokenEdgeIDs: new Set(edgeIds) });
},
nodesInResolutionMode: new Set<string>(),
brokenEdgeIDs: new Map<string, Set<string>>(),
nodeResolutionData: new Map<string, NodeResolutionData>(),
setNodeResolutionMode: (
nodeID: string,
inResolution: boolean,
resolutionData?: NodeResolutionData,
) => {
set((state) => {
const newNodesSet = new Set(state.nodesInResolutionMode);
const newResolutionDataMap = new Map(state.nodeResolutionData);
const newBrokenEdgeIDs = new Map(state.brokenEdgeIDs);
if (inResolution) {
newNodesSet.add(nodeID);
if (resolutionData) {
newResolutionDataMap.set(nodeID, resolutionData);
}
} else {
newNodesSet.delete(nodeID);
newResolutionDataMap.delete(nodeID);
newBrokenEdgeIDs.delete(nodeID); // Clean up broken edges when exiting resolution mode
}
return {
nodesInResolutionMode: newNodesSet,
nodeResolutionData: newResolutionDataMap,
brokenEdgeIDs: newBrokenEdgeIDs,
};
});
},
isNodeInResolutionMode: (nodeId: string) => {
return get().nodesInResolutionMode.has(nodeId);
},
getNodeResolutionData: (nodeId: string) => {
return get().nodeResolutionData.get(nodeId);
},
setBrokenEdgeIDs: (nodeId: string, edgeIds: string[]) => {
set((state) => {
const newMap = new Map(state.brokenEdgeIDs);
newMap.set(nodeId, new Set(edgeIds));
return { brokenEdgeIDs: newMap };
});
},
removeBrokenEdgeID: (nodeId: string, edgeId: string) => {
set((state) => {
const newMap = new Map(state.brokenEdgeIDs);
const nodeSet = new Set(newMap.get(nodeId) || []);
nodeSet.delete(edgeId);
newMap.set(nodeId, nodeSet);
return { brokenEdgeIDs: newMap };
});
},

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Copy link
Contributor

@Abhi1992002 Abhi1992002 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 🙌

I’ve added a review for the new builder (haven’t checked the old one).

Comment on lines +69 to +73
// Fetch all available graphs for sub-agent update detection
const { data: availableGraphs } = useGetV1ListUserGraphs({
query: { select: okData },
});

Copy link
Contributor

@Abhi1992002 Abhi1992002 Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if a user has access to 100's of graphs but is using only 2–3 subgraphs in the current agent. Don’t you think fetching all available graphs will increase backend load (and cost) and also hurt frontend performance?

Instead, could we create a new endpoint that returns only the user’s graphs based on a list of graph_ids? We could first fetch the details of the current graph, extract all the agent blocks, and then use their graph_ids to fetch only the required graphs.

I know this approach would lose some parallelism—we’d need to wait for the main graph to load before checking compatibility—but it should improve overall performance. We could show a loader on the agent node saying “checking compatibility.” WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s totally fine if you want to handle this in follow-up PRs, since this one is already quite large. [I’m also planning a few changes to reduce loading and saving time, since I’m currently using some brute-force logic in a few places]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can create IncompatibleUpdateDialog folder - and put IncompatibleUpdateDialog.tsx inisde it, as well as types.ts and also a folder named components with 2 files TwoColumnSection.tsx and SingleColumnSection

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that would hurt rather than help DX. I know it would for me. These are (right now) components that will always be used together, and they are designed to work together.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, in many places we’re not using the Text atom. Can we use it instead of normal elements? It would be good for design consistency.

https://www.chromatic.com/component?appId=670f94474adee5e32c896b98&csfId=atoms-text&buildNumber=3354&k=69592f95d1f7307f8f33abba-1200px-interactive-true&h=11&b=-1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't the default global font suffice for standard body text?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think this component now have enough states —maybe we can create a useFormCreator hook.

@github-project-automation github-project-automation bot moved this from 🆕 Needs initial review to 🚧 Needs work in AutoGPT development kanban Jan 4, 2026
@github-actions github-actions bot added the conflicts Automatically applied to PRs with merge conflicts label Jan 7, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

This pull request has conflicts with the base branch, please resolve those so we can evaluate the pull request.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In
@autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/BuildActionBar.tsx:
- Line 4: In BuildActionBar replace lucide-react icons with Phosphor
equivalents: change the import statement that currently imports AlertTriangle
and LogOut from "lucide-react" to import Warning and SignOut (or SignOutSimple
if used elsewhere) from "phosphor-react", then update JSX usages in the
BuildActionBar component to render <Warning .../> instead of <AlertTriangle
.../> and <SignOut .../> instead of <LogOut .../> so only Phosphor Icons are
used.

In
@autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/CustomNode/IncompatibilityDialog.tsx:
- Around line 2-10: This file imports legacy UI components (Dialog,
DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle,
Button); replace those legacy imports with the design-system Dialog and Button
components (use the project’s Dialog molecule and Button atom equivalents) and
update any prop names/usage to match the design-system API; use the
IncompatibleUpdateDialog.tsx implementation as the reference for import names
and prop usage to ensure compatibility, then run the frontend build/tests to
verify no API mismatches remain.

In @autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts:
- Around line 248-249: The change touches deprecated backend API types in
types.ts (the lines with "type?: never;" and "const?: never;"); do not edit this
legacy file—revert any modifications and instead migrate the consumer code to
use the generated API hooks under "@/app/api/__generated__/endpoints/"
(regenerate with "pnpm generate:api" if needed) so the schema change is applied
via the generated client rather than the deprecated src/lib/autogpt-server-api
layer.
🧹 Nitpick comments (17)
autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/CustomNode/CustomNode.tsx (2)

139-143: Throwing during render may cause issues.

Throwing an error during the render phase when builderContext is missing can cause React error boundaries to trigger and may result in a poor developer experience. Consider using a more graceful fallback or moving this check.

♻️ Suggested alternative
-    if (!builderContext) {
-      throw new Error(
-        "BuilderContext consumer must be inside FlowEditor component",
-      );
-    }
+    // Early return with null or a fallback if context is missing
+    // This shouldn't happen in practice, but provides a safer fallback
+    if (!builderContext) {
+      console.error("BuilderContext consumer must be inside FlowEditor component");
+      return null;
+    }

Alternatively, keep the throw but move it to an effect or use a custom hook that handles the context check.


204-215: Direct mutation of data prop during render.

The code directly assigns to data.inputSchema and data.outputSchema, which are properties of the data prop. While this creates new objects for the properties, mutating props during render is an anti-pattern in React and can lead to subtle bugs or unexpected behavior.

Consider computing the merged schemas as local variables and using them in the render without mutating the prop object.

♻️ Suggested refactor
+      // Compute merged schemas without mutating data
+      const mergedInputSchema = {
+        ...newInputSchema,
+        properties: mergedInputProps,
+      };
+      const mergedOutputSchema = {
+        ...newOutputSchema,
+        properties: mergedOutputProps,
+      };
-        data.inputSchema = {
-          ...newInputSchema,
-          properties: mergedInputProps,
-        };
-        data.outputSchema = {
-          ...newOutputSchema,
-          properties: mergedOutputProps,
-        };
+      // Then use mergedInputSchema and mergedOutputSchema in render

You would need to track these as local variables and use them instead of data.inputSchema/data.outputSchema throughout the component.

autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/useCopyPaste.ts (1)

115-123: Non-null assertions on handle properties.

The non-null assertions (!) on sourceHandle and targetHandle assume these properties are always defined. While this is typically true for edges in the builder context, it could cause runtime errors if an edge somehow lacks these properties.

Consider adding a defensive filter or defaulting to empty strings:

♻️ Suggested safer approach
                  .map(
                    (edge: Edge): ConnectedEdge => ({
                      id: edge.id,
                      source: edge.source,
                      target: edge.target,
-                      sourceHandle: edge.sourceHandle!,
-                      targetHandle: edge.targetHandle!,
+                      sourceHandle: edge.sourceHandle ?? "",
+                      targetHandle: edge.targetHandle ?? "",
                    }),
                  );

Or filter out edges without handles before mapping:

+                  .filter(
+                    (edge: Edge) => edge.sourceHandle != null && edge.targetHandle != null,
+                  )
                  .map(
                    (edge: Edge): ConnectedEdge => ({
                      id: edge.id,
                      source: edge.source,
                      target: edge.target,
-                      sourceHandle: edge.sourceHandle!,
-                      targetHandle: edge.targetHandle!,
+                      sourceHandle: edge.sourceHandle!,
+                      targetHandle: edge.targetHandle!,
                    }),
                  );
autogpt_platform/frontend/src/app/(platform)/build/hooks/useSubAgentUpdate/helpers.ts (1)

64-104: Potential duplicate edge IDs in result.

The function checks for missing inputs (lines 76-82) and type mismatches (lines 85-91) separately. If an input name appears in both missingInputs and inputTypeMismatches, the same edge ID would be pushed twice.

While this is unlikely in practice (a missing input shouldn't have a type mismatch), consider using a Set for brokenEdgeIDs or checking for existence before pushing:

♻️ Suggested fix using Set
 export function getBrokenEdgeIDs(
   connections: EdgeLike[],
   incompatibilities: IncompatibilityInfo,
   nodeID: string,
 ): string[] {
-  const brokenEdgeIDs: string[] = [];
+  const brokenEdgeIDs = new Set<string>();
   const typeMismatchInputNames = new Set(
     incompatibilities.inputTypeMismatches.map((m) => m.name),
   );

   connections.forEach((conn) => {
     // Check if this connection uses a missing input (node is target)
     if (
       conn.target === nodeID &&
       conn.targetHandle &&
       incompatibilities.missingInputs.includes(conn.targetHandle)
     ) {
-      brokenEdgeIDs.push(conn.id);
+      brokenEdgeIDs.add(conn.id);
     }

     // Check if this connection uses an input with a type mismatch (node is target)
     if (
       conn.target === nodeID &&
       conn.targetHandle &&
       typeMismatchInputNames.has(conn.targetHandle)
     ) {
-      brokenEdgeIDs.push(conn.id);
+      brokenEdgeIDs.add(conn.id);
     }

     // Check if this connection uses a missing output (node is source)
     if (
       conn.source === nodeID &&
       conn.sourceHandle &&
       incompatibilities.missingOutputs.includes(conn.sourceHandle)
     ) {
-      brokenEdgeIDs.push(conn.id);
+      brokenEdgeIDs.add(conn.id);
     }
   });

-  return brokenEdgeIDs;
+  return Array.from(brokenEdgeIDs);
 }
autogpt_platform/frontend/src/app/(platform)/build/hooks/useSubAgentUpdate/index.ts (1)

1-2: Barrel file violates coding guidelines.

As per coding guidelines: "No barrel files or index.ts re-exports in frontend". This index.ts file serves purely as a re-export barrel.

Consider removing this file and having consumers import directly from the specific modules:

  • import { useSubAgentUpdate } from "./useSubAgentUpdate";
  • import { createUpdatedAgentNodeInputs, getBrokenEdgeIDs } from "./helpers";
♻️ Suggested approach

Delete this barrel file and update import paths in consuming files to import directly from the source modules.

For example, in SubAgentUpdateFeature.tsx or other consumers:

// Instead of:
import { useSubAgentUpdate } from "@/app/(platform)/build/hooks/useSubAgentUpdate";

// Use:
import { useSubAgentUpdate } from "@/app/(platform)/build/hooks/useSubAgentUpdate/useSubAgentUpdate";
autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/SubAgentUpdate/components/ResolutionModeBar.tsx (1)

17-80: Consider extracting renderIncompatibilities outside the component.

The inner function is recreated on every render. Since it only depends on incompatibilities prop, extracting it as a separate function or using useCallback would improve performance, though the impact is minimal given the component's usage context.

♻️ Optional: Extract as standalone function
+function renderIncompatibilities(incompatibilities: IncompatibilityInfo | null) {
+  if (!incompatibilities) return <span>No incompatibilities</span>;
+  // ... rest of the logic
+}

 export function ResolutionModeBar({
   incompatibilities,
 }: ResolutionModeBarProps): React.ReactElement {
-  const renderIncompatibilities = () => {
-    // ...
-  };
autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/handlers/NodeHandle.tsx (2)

12-41: Consider using function declaration for component.

Per coding guidelines, components should use function declarations rather than arrow functions. While this is a small component, consistency with the codebase convention would be beneficial.

♻️ Suggested refactor to function declaration
-const NodeHandle = ({
+function NodeHandle({
   handleId,
   isConnected,
   side,
   isBroken = false,
-}: NodeHandleProps) => {
+}: NodeHandleProps) {
   return (
     // ... rest of component
   );
-};
+}

Based on coding guidelines, function declarations are preferred for components.


33-36: Minor: Redundant opacity-100 class.

The opacity-100 class has no effect since it's the default opacity. It can be safely removed.

♻️ Suggested cleanup
           className={cn(
-            "opacity-100",
             isBroken ? "text-red-500" : "text-gray-400",
           )}
autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/CustomNode/IncompatibilityDialog.tsx (1)

118-124: Button variant and custom styling conflict.

The button uses variant="destructive" but overrides the colors with bg-amber-600 hover:bg-amber-700. This is a semantic mismatch—destructive typically implies red/danger. Consider using variant="primary" or a custom variant if amber is the intended warning color.

♻️ Suggested fix
           <Button
-            variant="destructive"
+            variant="default"
             onClick={onConfirm}
-            className="bg-amber-600 hover:bg-amber-700"
+            className="border-amber-700 bg-amber-600 hover:bg-amber-700"
           >
autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/FormCreator.tsx (1)

24-38: Consider memoizing handleChange with useCallback.

The handleChange function is recreated on every render, which could cause unnecessary re-renders of the FormRenderer. Since this is a memoized component, stabilizing the callback would improve the memoization benefit.

♻️ Suggested improvement
+import React, { useCallback } from "react";
 // ...
 
-    const handleChange = ({ formData }: any) => {
+    const handleChange = useCallback(({ formData }: any) => {
       if ("credentials" in formData && !formData.credentials?.id) {
         delete formData.credentials;
       }
 
       const updatedValues =
         uiType === BlockUIType.AGENT
           ? {
               ...getHardCodedValues(nodeId),
               inputs: formData,
             }
           : formData;
 
       updateNodeData(nodeId, { hardcodedValues: updatedValues });
-    };
+    }, [uiType, nodeId, getHardCodedValues, updateNodeData]);
autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/SubAgentUpdate/useSubAgentUpdateState.ts (3)

33-52: Remove unnecessary useShallow wrappers for single primitive/function selectors.

useShallow is designed for shallow comparison of objects/arrays to prevent unnecessary re-renders. When selecting a single function reference (like updateNodeData, setNodeResolutionMode, etc.), useShallow adds overhead without benefit since function references from Zustand are already stable.

Suggested simplification
-  const updateNodeData = useNodeStore(
-    useShallow((state) => state.updateNodeData),
-  );
-  const setNodeResolutionMode = useNodeStore(
-    useShallow((state) => state.setNodeResolutionMode),
-  );
-  const isNodeInResolutionMode = useNodeStore(
-    useShallow((state) => state.isNodeInResolutionMode),
-  );
-  const setBrokenEdgeIDs = useNodeStore(
-    useShallow((state) => state.setBrokenEdgeIDs),
-  );
+  const updateNodeData = useNodeStore((state) => state.updateNodeData);
+  const setNodeResolutionMode = useNodeStore((state) => state.setNodeResolutionMode);
+  const isNodeInResolutionMode = useNodeStore((state) => state.isNodeInResolutionMode);
+  const setBrokenEdgeIDs = useNodeStore((state) => state.setBrokenEdgeIDs);
   // ... same for getNodeResolutionData

110-153: Consider wrapping handleConfirmIncompatibleUpdate in useCallback.

This function is returned from the hook and may be passed as a prop to child components. Without useCallback, a new function reference is created on every render, potentially causing unnecessary re-renders in consuming components.

Suggested fix
-  function handleConfirmIncompatibleUpdate() {
+  const handleConfirmIncompatibleUpdate = useCallback(() => {
     if (!updateInfo.latestGraph || !updateInfo.incompatibilities) return;
     // ... rest of implementation
     setShowIncompatibilityDialog(false);
-  }
+  }, [
+    updateInfo.latestGraph,
+    updateInfo.incompatibilities,
+    nodeData.hardcodedValues,
+    connectedEdges,
+    currentInputSchema,
+    currentOutputSchema,
+    setBrokenEdgeIDs,
+    setNodeResolutionMode,
+    nodeID,
+  ]);

177-183: Stable functions can be removed from the dependency array.

As noted in previous review feedback, setNodeResolutionMode and updateNodeData are stable store functions that won't change between renders. Including them doesn't cause bugs but adds unnecessary noise to the dependency array.

autogpt_platform/frontend/src/app/(platform)/build/hooks/useSubAgentUpdate/useSubAgentUpdate.ts (1)

30-33: Potential issue with non-null assertion on latestGraph.version.

The non-null assertion latestGraph.version! assumes version is always defined when latestGraph exists. If version could be undefined or null, this comparison would behave unexpectedly (comparing undefined > number returns false in JavaScript, which happens to be safe here, but the assertion is misleading).

Consider adding explicit handling:

Safer version check
   const hasUpdate = useMemo(() => {
-    if (!latestGraph || graphVersion === undefined) return false;
-    return latestGraph.version! > graphVersion;
+    if (!latestGraph || graphVersion === undefined || latestGraph.version === undefined) return false;
+    return latestGraph.version > graphVersion;
   }, [latestGraph, graphVersion]);
autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/CustomNode/SubAgentUpdateBar.tsx (2)

21-27: Arrow function components instead of function declarations.

Per coding guidelines: "Use function declarations for components and handlers (not arrow functions)."

Function declaration style
-export const SubAgentUpdateBar: React.FC<SubAgentUpdateBarProps> = ({
-  currentVersion,
-  // ...
-}) => {
+export function SubAgentUpdateBar({
+  currentVersion,
+  // ...
+}: SubAgentUpdateBarProps) {

-const ResolutionModeBar: React.FC<ResolutionModeBarProps> = ({
-  incompatibilities,
-}) => {
+function ResolutionModeBar({
+  incompatibilities,
+}: ResolutionModeBarProps) {

Also applies to: 73-75


73-128: ResolutionModeBar duplicates logic from the v2 implementation.

There's a similar ResolutionModeBar component in the v2 builder (autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/SubAgentUpdate/components/ResolutionModeBar.tsx). Consider extracting this into a shared component to avoid duplication and ensure consistent behavior across both builders.

autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/Flow/Flow.tsx (1)

77-83: Consider co-locating ResolutionModeState type with the new builder's types.

The ResolutionModeState type defined here duplicates the concept from the new builder's NodeResolutionData in nodeStore. While the legacy builder needs its own state management, having similar but different types could lead to drift. Consider documenting the relationship or extracting shared types.

Comment on lines +2 to +10
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/__legacy__/ui/dialog";
import { Button } from "@/components/__legacy__/ui/button";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Using legacy components violates coding guidelines.

This file imports from @/components/__legacy__/ui/dialog and @/components/__legacy__/ui/button. Per coding guidelines, legacy components should never be used in frontend code. Use the design system components from src/components/ (atoms, molecules, organisms) instead.

Consider using:

  • @/components/molecules/Dialog/Dialog instead of legacy dialog
  • @/components/atoms/Button/Button instead of legacy button

The newer IncompatibleUpdateDialog.tsx in the FlowEditor path already uses the correct design system components and could serve as a reference.

🤖 Prompt for AI Agents
In
@autogpt_platform/frontend/src/app/(platform)/build/components/legacy-builder/CustomNode/IncompatibilityDialog.tsx
around lines 2 - 10, This file imports legacy UI components (Dialog,
DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle,
Button); replace those legacy imports with the design-system Dialog and Button
components (use the project’s Dialog molecule and Button atom equivalents) and
update any prop names/usage to match the design-system API; use the
IncompatibleUpdateDialog.tsx implementation as the reference for import names
and prop usage to ensure compatibility, then run the frontend build/tests to
verify no API mismatches remain.

DialogTitle,
} from "@/components/__legacy__/ui/dialog";
import { Button } from "@/components/__legacy__/ui/button";
import { AlertTriangle, XCircle, PlusCircle } from "lucide-react";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use Phosphor Icons instead of lucide-react.

Per coding guidelines, only Phosphor Icons (@phosphor-icons/react) should be used in the frontend. Replace lucide-react icons with their Phosphor equivalents.

♻️ Suggested icon replacements
-import { AlertTriangle, XCircle, PlusCircle } from "lucide-react";
+import { WarningIcon, XCircleIcon, PlusCircleIcon } from "@phosphor-icons/react";

Then update usages to use weight="fill" prop for filled appearance:

<WarningIcon className="h-5 w-5 text-amber-500" weight="fill" />
<XCircleIcon className="h-4 w-4 text-red-500" weight="fill" />
<PlusCircleIcon className="h-4 w-4 text-green-500" weight="fill" />

Based on coding guidelines, only Phosphor Icons should be used.

Committable suggestion skipped: line range outside the PR's diff.

@Pwuts Pwuts requested a review from Abhi1992002 January 7, 2026 19:17
Comment on lines 128 to 138

// Update available sub-graphs in store for sub-agent update detection
useEffect(() => {
if (availableGraphs) {
setAvailableSubGraphs(availableGraphs);
}
}, [availableGraphs, setAvailableSubGraphs]);

// adding nodes
useEffect(() => {
if (customNodes.length > 0) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Global resolution state is not cleared when switching between flows, causing nodes in the new flow to incorrectly inherit stale resolution mode from the previous flow.
Severity: HIGH | Confidence: High

🔍 Detailed Analysis

The resolution state, managed in the nodeStore, is not reset when a user navigates between different flows. While setNodes([]) is called to clear the current nodes, the associated resolution data (nodesInResolutionMode, brokenEdgeIDs, etc.) persists. If a newly loaded flow contains a node with an ID that was previously in resolution mode, that node will incorrectly render with stale "broken connection" indicators and incompatibility data from the old flow. This happens because the cleanup function clearResolutionState() exists but is never invoked on flow change or component unmount.

💡 Suggested Fix

Call the existing clearResolutionState() function from the nodeStore within the cleanup effect in useFlow.ts. This will ensure that all resolution-related state is properly reset when the user switches between flows, preventing stale data from affecting the new flow's state.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location:
autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/useFlow.ts#L126-L138

Potential issue: The resolution state, managed in the `nodeStore`, is not reset when a
user navigates between different flows. While `setNodes([])` is called to clear the
current nodes, the associated resolution data (`nodesInResolutionMode`, `brokenEdgeIDs`,
etc.) persists. If a newly loaded flow contains a node with an ID that was previously in
resolution mode, that node will incorrectly render with stale "broken connection"
indicators and incompatibility data from the old flow. This happens because the cleanup
function `clearResolutionState()` exists but is never invoked on flow change or
component unmount.

Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 8298818

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflicts Automatically applied to PRs with merge conflicts platform/frontend AutoGPT Platform - Front end size/xl

Projects

Status: 🚧 Needs work
Status: No status

Development

Successfully merging this pull request may close these issues.

5 participants