* Initial flow * Fix styling to look the same as v2 * Add new atoms - SwitxhInput, Dropdown and ToolTipWithParser similar to v2 * Add test cases for all changes * Refactor input default value handling and consolidate utility functions * Allow imports from utils for atoms * Fix gemini comments * Fixed buold issues * FIx styling and create credentiall behavior * Add support for edit credentials * Fix bug to display tool and vector embeddign parameters * Add CredentialTypeSelector for HTTP node * Fix to add falback icon in case of error * Move inputDefaults under core/primitives * Added fix to check if all mandatory fields have value before submittign a credential * Fix new credential not being selected on creating * Fixes made to address comments * Gemini comment fix * Fix test error by adding theme * Refactor getDefaultValueForType to remove null/undefined handling * Fixed getDefaultValueForType to be generic * Fixed getDefaultValueForType to take single destructured object parameter
14 KiB
@flowiseai/agentflow - Architecture
This document describes the internal architecture of the @flowiseai/agentflow package.
Overview
The package follows a Domain-Driven Modular Architecture with clear separation of concerns. The goal is to separate low-level UI primitives from high-level business logic to ensure high reusability and easy testing.
src/
├── index.ts # Public Package API ("Public Face")
├── Agentflow.tsx # Main component
├── AgentflowProvider.tsx # Root provider (composition)
├── useAgentflow.ts # Primary public hook
│
├── atoms/ # ⚛️ UI Primitives ("What it looks like" (Dumb))
├── features/ # 🧩 Domain Features ("What it does" (Smart))
├── core/ # 🧠 Business Logic ("Business Rules" (Types/Logic))
└── infrastructure/ # 🌐 External Services ("Outside World" (API/Storage))
Directory Structure
atoms/ - UI Primitives
"What it looks like." Tiny, irreducible UI components with no business logic. These are the building blocks used by features.
atoms/
├── MainCard.tsx # Styled card wrapper
├── NodeInputHandler.tsx # Form input for node properties
├── ... # Other UI primitives
└── index.ts # Central export
Rules:
- Must be "dumb" and stateless
- No business logic
- No API calls
- Stateless or minimal local state
- Imported by features, never the reverse
- Forbidden: Importing from
features/orinfrastructure/(except types fromcore/typesfor prop definitions, design tokens fromcore/theme, and primitives fromcore/primitives)
Goal: 100% visual consistency.
features/ - Domain Features
"What it does." Complex, self-contained domain modules (silos) that house the application's core functionality. Each feature owns its components, hooks, and utilities.
features/
├── canvas/ # Core ReactFlow canvas
│ ├── containers/ # Smart components with state/logic
│ │ ├── AgentFlowNode.tsx
│ │ ├── AgentFlowEdge.tsx
│ │ ├── ... # Other node containers
│ │ └── index.ts
│ ├── components/ # Presentational components
│ │ ├── ConnectionLine.tsx
│ │ ├── NodeOutputHandles.tsx
│ │ ├── ... # Other presentational components
│ │ └── index.ts
│ ├── hooks/ # Canvas-related hooks
│ │ ├── useFlowHandlers.ts
│ │ ├── useDragAndDrop.ts
│ │ ├── ... # Other canvas hooks
│ │ └── index.ts
│ ├── styled.ts # Styled components
│ └── index.ts # Public API
│
├── node-palette/ # Add nodes drawer
│ ├── AddNodesDrawer.tsx
│ ├── search.ts # Feature-specific utility (private)
│ ├── ...
│ └── index.ts
│
├── generator/ # AI flow generation
│ ├── GenerateFlowDialog.tsx
│ ├── ...
│ └── index.ts
│
└── node-editor/ # Node property editing
├── EditNodeDialog.tsx
└── index.ts
Rules:
- Each feature has an
index.tsgatekeeper - Features never import from other features directly - If
canvasneeds logic fromgenerator, move that logic tocore/ - Feature-specific utils stay in the feature folder
- Styles are co-located with their feature
- Use
containers/for smart components (with state, hooks, side effects) - Use
components/for presentational components (props in, JSX out)
Goal: High cohesion. Should be able to delete a feature folder without breaking others.
core/ - Business Logic
"The Brain." Framework-agnostic logic, types, and utilities. No React, no UI - pure TypeScript. Contains validation schemas, node registries, domain constants, and shared types.
core/
├── types/ # Global interfaces (Node, Edge, Flow)
│ └── index.ts
├── primitives/ # Domain-free utilities (safe for atoms)
│ ├── inputDefaults.ts # getDefaultValueForType
│ └── index.ts
├── node-config/ # Node configuration (icons, colors, default types)
│ ├── nodeIcons.ts # AGENTFLOW_ICONS, DEFAULT_AGENTFLOW_NODES
│ └── ...
├── node-catalog/ # Node catalog and filtering logic
│ ├── nodeFilters.ts # filterNodesByComponents, isAgentflowNode
│ └── ...
├── theme/ # Design tokens and MUI theming
│ ├── tokens.ts # Color palettes, spacing, shadows
│ ├── createAgentflowTheme.ts
│ └── ...
├── validation/ # Flow validation logic
│ ├── flowValidation.ts # validateFlow, validateNode
│ ├── connectionValidation.ts # isValidConnectionAgentflowV2
│ └── ...
├── utils/ # Domain-aware utilities (NOT importable by atoms)
│ ├── nodeFactory.ts # initNode, getUniqueNodeId
│ └── ...
└── index.ts # Barrel export (use sparingly)
Rules:
- No React components allowed - Pure TypeScript only
- No browser-specific APIs if possible
- No side effects
- Pure functions where possible
- Can be tested in isolation
core/primitives/ vs core/utils/
core/ contains two utility directories with different import permissions:
primitives/— Domain-free, general-purpose functions with no knowledge of nodes, flows, or any business concept. These are pure data transformations (e.g., computing a default value from a type string). Safe to import fromatoms/.utils/— Domain-aware utilities that understand node structures, flow data, or validation logic (e.g.,initNode,buildDynamicOutputAnchors). Only importable byfeatures/andinfrastructure/.
When adding a new utility, ask: "Does this function need to know what a Node or Flow is?" If no → primitives/. If yes → utils/.
Goal: To be the framework-agnostic source of truth.
infrastructure/ - External Services
"The Outside World." Handles communication with external systems: data persistence, network requests, and global state management.
infrastructure/
├── api/ # API client layer (network requests)
│ ├── client.ts # Axios factory
│ ├── ... # Endpoint modules (nodes, chatflows, etc.)
│ └── index.ts
│
└── store/ # State management
├── AgentflowContext.tsx # Flow state context
├── agentflowReducer.ts # Reducer for flow state actions
├── ... # Other contexts (ApiContext, ConfigContext)
└── index.ts
Rules:
- All external communication goes here
- Contexts are internal (composed in AgentflowProvider)
- API hooks live with their API modules
Goal: To wrap external dependencies so they can be easily swapped or mocked in tests.
Dependency Flow
Dependencies must only flow downwards.
┌─────────────────────────────────────────────────────────┐
│ Root Files (Public API) │
│ (index.ts, Agentflow.tsx, AgentflowProvider.tsx) │
│ "The Public Face" │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ features/ │
│ (canvas, node-palette, generator, node-editor) │
│ "What it does" │
└─────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌──────────────────┐ ┌────────────────────────┐
│ atoms/ │ │ infrastructure/ │
│ (UI primitives) │ │ (api, store) │
│ "What it looks │ │ "The Outside World" │
│ like" │ │ │
└──────────────────┘ └────────────────────────┘
│ │
└──────────────┬─────────────────────┘
▼
┌─────────────────────┐
│ core/ │
│ (types, constants, │
│ validation, etc.) │
│ "The Brain" │
└─────────────────────┘
Import Rules:
features→atoms,infrastructure,core✅infrastructure→core✅atoms→core/types,core/theme, andcore/primitivesonly ✅core→ nothing (leaf node) ✅- Atoms and Core are "leaf" nodes - they cannot import from
features/orinfrastructure/
Gatekeeper Pattern
Each module exposes only what's needed via its index.ts:
// features/canvas/index.ts
// ✅ Public API
export const nodeTypes = { ... }
export const edgeTypes = { ... }
export { ConnectionLine, AgentflowHeader, createHeaderProps }
export { useFlowNodes, useFlowHandlers, useDragAndDrop }
// Container components are re-exported for advanced usage
export { AgentFlowNode, AgentFlowEdge, StickyNote, IterationNode }
// ❌ Internal sub-components stay private within containers/components
This enables:
- Encapsulation: Internal refactoring doesn't break consumers
- Tree-shaking: Bundlers can eliminate unused code
- Clarity: Clear contract of what each module provides
Adding a New Feature
-
Create folder under
features/:features/my-feature/ ├── containers/ # Smart components (optional) │ └── MyContainer.tsx ├── components/ # Presentational components (optional) │ └── MyComponent.tsx ├── hooks/ # Feature-specific hooks (optional) │ └── useMyHook.ts ├── helper.ts # Feature-specific util └── index.ts # Public exports only -
Export only what's needed:
// index.ts export { MyContainer } from './containers' export { MyComponent } from './components' export { useMyHook } from './hooks' export type { MyComponentProps } from './components' -
Import from infrastructure/core, never from other features:
// ✅ Good import { useApiContext } from '../../infrastructure/store' import type { NodeData } from '../../core/types' // ❌ Bad - cross-feature import import { AgentFlowNode } from '../canvas/containers/AgentFlowNode'
Root Files (src/*.ts)
"The Public Face." The entry point of the package.
AgentflowProvider.tsx: Injects infrastructure (stores/api) into the appAgentflow.tsx: The primary component users will drop into their appsuseAgentflow.ts: Primary public hook for accessing flow state and actionsindex.ts: The "Barrel" that exports the public API for npm
Public API
The package exposes a minimal public API via src/index.ts:
// Components
export { Agentflow } from './Agentflow'
export { AgentflowProvider } from './AgentflowProvider'
// Hooks
export { useAgentflow } from './useAgentflow'
export { useApiContext, useConfigContext, useAgentflowContext } from './infrastructure/store'
// Types
export type { AgentflowProps, FlowData, NodeData, ... } from './core/types'
// Utilities (for advanced usage)
export { AGENTFLOW_ICONS, validateFlow, ... } from './core/...'
Everything else is internal implementation detail.
Development Principles
Barrel Exports
Every directory must have an index.ts that acts as a gatekeeper.
✅ Good:
import { Button } from '@atoms'
import { useFlowHandlers } from '@features/canvas'
❌ Bad:
// Never deep-link into files
import { Button } from '@atoms/Button/Button'
import { useFlowHandlers } from '@features/canvas/hooks/useFlowHandlers'
Prop Drilling vs. Context
- Atoms: Use props for all configuration
- Features: Use context/state for shared data
Naming Convention
| Type | Convention | Example |
|---|---|---|
| Component | PascalCase.tsx | AgentFlowNode.tsx |
| Hook | camelCase.ts (use prefix) | useFlowHandlers.ts |
| Logic/Types | camelCase.ts | flowValidation.ts, nodeFilters.ts |
| Styles | kebab-case (co-located) | canvas.css |