Skip to content

Commit 739f877

Browse files
authored
Merge branch 'main' into flowise-305
2 parents 86a36e6 + 7dc48ad commit 739f877

139 files changed

Lines changed: 9131 additions & 860 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CONTRIBUTING.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,48 @@ Flowise has 3 different modules in a single mono repository.
116116

117117
11. Commit code and submit Pull Request from forked branch pointing to [Flowise main](https://github.com/FlowiseAI/Flowise/tree/main).
118118

119+
### Testing
120+
121+
- Unit tests are **co-located** with their source files — a test for `Foo.ts` lives in `Foo.test.ts` in the same directory. This is the standard used across all packages in this repo.
122+
123+
- Run tests per package:
124+
125+
```bash
126+
cd packages/server && pnpm test
127+
cd packages/components && pnpm test
128+
cd packages/agentflow && pnpm test
129+
```
130+
131+
Or from the repo root using `--filter`:
132+
133+
```bash
134+
pnpm --filter flowise-components test
135+
pnpm --filter @flowiseai/agentflow test
136+
pnpm --filter "./packages/server" test # root and server share the same package name.
137+
```
138+
139+
- Or run all tests from the repo root:
140+
141+
```bash
142+
pnpm test
143+
```
144+
145+
- When adding new functionality, place your test file next to the source file it tests:
146+
147+
```
148+
packages/components/nodes/tools/MyTool/
149+
├── MyTool.ts
150+
└── MyTool.test.ts ← co-located test
151+
```
152+
119153
## 🌱 Env Variables
120154

121155
Flowise support different environment variables to configure your instance. You can specify the following variables in the `.env` file inside `packages/server` folder. Read [more](https://docs.flowiseai.com/environment-variables)
122156

123157
| Variable | Description | Type | Default |
124158
| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------- |
125159
| PORT | The HTTP port Flowise runs on | Number | 3000 |
160+
| CORS_ALLOW_CREDENTIALS | Enables CORS `Access-Control-Allow-Credentials` when `true` | Boolean | false |
126161
| CORS_ORIGINS | The allowed origins for all cross-origin HTTP calls | String | |
127162
| IFRAME_ORIGINS | The allowed origins for iframe src embedding | String | |
128163
| FLOWISE_FILE_SIZE_LIMIT | Upload File Size Limit | String | 50mb |

docker/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ PORT=3000
7474
############################################################################################################
7575

7676
# NUMBER_OF_PROXIES= 1
77+
# CORS_ALLOW_CREDENTIALS=false
7778
# CORS_ORIGINS=*
7879
# IFRAME_ORIGINS=*
7980
# FLOWISE_FILE_SIZE_LIMIT=50mb

docker/worker/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ WORKER_PORT=5566
7474
############################################################################################################
7575

7676
# NUMBER_OF_PROXIES= 1
77+
# CORS_ALLOW_CREDENTIALS=false
7778
# CORS_ORIGINS=*
7879
# IFRAME_ORIGINS=*
7980
# FLOWISE_FILE_SIZE_LIMIT=50mb

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "flowise",
3-
"version": "3.1.0",
3+
"version": "3.1.1",
44
"private": true,
55
"homepage": "https://flowiseai.com",
66
"workspaces": [

packages/agentflow/.eslintrc.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ module.exports = {
8181
'import/first': 'error',
8282
'import/newline-after-import': 'error',
8383
'import/no-duplicates': 'error',
84+
// Allow autoFocus on custom components (e.g. RichTextEditor in dialogs) — they manage
85+
// focus programmatically per WAI-ARIA dialog patterns. Native elements are still flagged.
86+
'jsx-a11y/no-autofocus': ['error', { ignoreNonDOM: true }],
8487
'prettier/prettier': 'error',
8588
// Ban @/features alias — features use relative imports internally, and no other
8689
// layer should import from features (enforced by import/no-restricted-paths below).
@@ -116,8 +119,8 @@ module.exports = {
116119
{
117120
target: './src/atoms',
118121
from: './src/core',
119-
except: ['./types'],
120-
message: 'Atoms can only import types from core/types, not utilities or business logic.'
122+
except: ['./types', './theme', './primitives'],
123+
message: 'Atoms can only import from core/types, core/theme, and core/primitives.'
121124
},
122125
// core/ cannot import from anything (leaf node)
123126
{

packages/agentflow/ARCHITECTURE.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ atoms/
4242
- No API calls
4343
- Stateless or minimal local state
4444
- Imported by features, never the reverse
45-
- **Forbidden**: Importing from `features/` or `infrastructure/` (except types from `core/types` for prop definitions)
45+
- **Forbidden**: Importing from `features/` or `infrastructure/` (except types from `core/types` for prop definitions, design tokens from `core/theme`, and primitives from `core/primitives`)
4646

4747
**Goal:** 100% visual consistency.
4848

@@ -110,6 +110,9 @@ features/
110110
core/
111111
├── types/ # Global interfaces (Node, Edge, Flow)
112112
│ └── index.ts
113+
├── primitives/ # Domain-free utilities (safe for atoms)
114+
│ ├── inputDefaults.ts # getDefaultValueForType
115+
│ └── index.ts
113116
├── node-config/ # Node configuration (icons, colors, default types)
114117
│ ├── nodeIcons.ts # AGENTFLOW_ICONS, DEFAULT_AGENTFLOW_NODES
115118
│ └── ...
@@ -124,7 +127,7 @@ core/
124127
│ ├── flowValidation.ts # validateFlow, validateNode
125128
│ ├── connectionValidation.ts # isValidConnectionAgentflowV2
126129
│ └── ...
127-
├── utils/ # Generic utilities
130+
├── utils/ # Domain-aware utilities (NOT importable by atoms)
128131
│ ├── nodeFactory.ts # initNode, getUniqueNodeId
129132
│ └── ...
130133
└── index.ts # Barrel export (use sparingly)
@@ -138,6 +141,15 @@ core/
138141
- Pure functions where possible
139142
- Can be tested in isolation
140143

144+
#### `core/primitives/` vs `core/utils/`
145+
146+
`core/` contains two utility directories with different import permissions:
147+
148+
- **`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 from `atoms/`.**
149+
- **`utils/`** — Domain-aware utilities that understand node structures, flow data, or validation logic (e.g., `initNode`, `buildDynamicOutputAnchors`). **Only importable by `features/` and `infrastructure/`.**
150+
151+
When adding a new utility, ask: _"Does this function need to know what a Node or Flow is?"_ If no → `primitives/`. If yes → `utils/`.
152+
141153
**Goal:** To be the framework-agnostic source of truth.
142154

143155
---
@@ -210,7 +222,7 @@ infrastructure/
210222

211223
- `features``atoms`, `infrastructure`, `core`
212224
- `infrastructure``core`
213-
- `atoms``core/types` only (for type definitions)
225+
- `atoms``core/types`, `core/theme`, and `core/primitives` only
214226
- `core` → nothing (leaf node) ✅
215227
- **Atoms and Core are "leaf" nodes** - they cannot import from `features/` or `infrastructure/`
216228

packages/agentflow/README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,22 @@
2121

2222
`@flowiseai/agentflow` is a React-based flow editor for creating AI agent workflows. It provides a visual canvas built on ReactFlow for connecting AI agents, LLMs, tools, and logic nodes.
2323

24+
## Features
25+
26+
- **Visual Canvas** — Drag-and-drop flow editor built on ReactFlow with zoom, pan, minimap, and fit-to-view controls
27+
- **15 Built-in Node Types** — Start, Agent, LLM, Condition, Condition Agent, Human Input, Loop, Direct Reply, Custom Function, Tool, Retriever, Sticky Note, HTTP, Iteration, and Execute Flow
28+
- **Node Editor Dialog** — Modal for editing node parameters with dynamic input types (text, number, boolean, dropdown, arrays, async options)
29+
- **Rich Text Editor** — TipTap-based editor with syntax highlighting for JavaScript, TypeScript, Python, and JSON (lazy-loaded)
30+
- **Specialized Input Components** — Condition builder, messages input (role + content), and structured output schema builder
31+
- **AI Flow Generator** — Generate flows from natural language descriptions with model selection
32+
- **Flow Validation** — Detects empty flows, missing start nodes, disconnected nodes, cycles, hanging edges, and per-node input errors with visual feedback
33+
- **Dark Mode** — Full light/dark theme support via design tokens and CSS variables
34+
- **Read-Only Mode** — Disable editing for view-only embedding
35+
- **Custom Rendering** — Replace the default header and node palette with your own components via render props
36+
- **Imperative API** — Programmatic control via ref (`getFlow`, `validate`, `fitView`, `clear`, `addNode`, `toJSON`)
37+
- **Request Interceptor** — Customize outgoing API requests (headers, credentials) via an Axios interceptor callback
38+
- **Keyboard Shortcuts** — Cmd/Ctrl+S to save
39+
2440
## Installation
2541

2642
```bash
@@ -139,10 +155,48 @@ The `requestInterceptor` callback runs inside the Axios request pipeline and has
139155
- Follow the **principle of least privilege** — only read or modify the specific config properties you need (e.g., `withCredentials`, custom headers).
140156
- If the interceptor throws, the error is caught, logged, and the **original unmodified config** is used so the request still proceeds safely.
141157

158+
### Node Types
159+
160+
The following node types are available in the palette by default. Use the `components` prop to restrict which types are shown.
161+
162+
<!-- prettier-ignore -->
163+
| Node Type | Description |
164+
| -------------------------- | ------------------------------------ |
165+
| `startAgentflow` | Entry point (required, always shown) |
166+
| `agentAgentflow` | AI agent execution |
167+
| `llmAgentflow` | LLM / language model call |
168+
| `conditionAgentflow` | Conditional branching |
169+
| `conditionAgentAgentflow` | Agent-level conditional branching |
170+
| `humanInputAgentflow` | Wait for user input |
171+
| `loopAgentflow` | Loop / iteration |
172+
| `directReplyAgentflow` | Direct response to user |
173+
| `customFunctionAgentflow` | Custom JavaScript function |
174+
| `toolAgentflow` | Tool integration |
175+
| `retrieverAgentflow` | Data retrieval |
176+
| `stickyNoteAgentflow` | Canvas annotation (not connectable) |
177+
| `httpAgentflow` | HTTP request |
178+
| `iterationAgentflow` | Iteration / map-reduce container |
179+
| `executeFlowAgentflow` | Execute a sub-flow |
180+
142181
### Design Note
143182

144183
`<Agentflow>` is an **uncontrolled component**. The `initialFlow` prop seeds the canvas state on mount, but the component owns its own state afterward. Use the `ref` for imperative access and `onFlowChange` to observe changes.
145184

185+
## Exports
186+
187+
Beyond the main `<Agentflow>` component, the package exports utilities for advanced usage:
188+
189+
```ts
190+
// Main component and provider
191+
// Types
192+
193+
// Hooks
194+
// Validation
195+
// Node utilities
196+
197+
// Field visibility helpers
198+
```
199+
146200
## Development
147201

148202
```bash

packages/agentflow/examples/src/demos/BasicExample.tsx

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { useCallback, useRef, useState } from 'react'
99

1010
import type { AgentFlowInstance, FlowData, ValidationResult } from '@flowiseai/agentflow'
1111
import { Agentflow } from '@flowiseai/agentflow'
12+
import { InternalAxiosRequestConfig } from 'axios'
1213

1314
import { apiBaseUrl, token } from '../config'
1415
import { FlowStatePanel } from '../FlowStatePanel'
@@ -28,9 +29,31 @@ const initialFlow: FlowData = {
2829
hideInput: true,
2930
outputAnchors: [{ id: 'startAgentflow_0-output-0', name: 'start', label: 'Start', type: 'start' }]
3031
}
32+
},
33+
{
34+
id: 'agentAgentflow_0',
35+
type: 'agentflowNode',
36+
position: { x: 250, y: 100 },
37+
data: {
38+
id: 'agentAgentflow_0',
39+
name: 'agentAgentflow',
40+
label: 'Agent',
41+
color: '#4DD0E1',
42+
outputAnchors: [{ id: 'agentAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }]
43+
}
44+
}
45+
],
46+
edges: [
47+
{
48+
id: 'edge-1',
49+
source: 'startAgentflow_0',
50+
sourceHandle: 'startAgentflow_0-output-0',
51+
target: 'agentAgentflow_0',
52+
targetHandle: 'agentAgentflow_0',
53+
type: 'agentflowEdge',
54+
data: { sourceColor: '#7EE787', targetColor: '#4DD0E1' }
3155
}
3256
],
33-
edges: [],
3457
viewport: { x: 0, y: 0, zoom: 1 }
3558
}
3659

@@ -115,6 +138,13 @@ export function BasicExample() {
115138
onFlowChange={handleFlowChange}
116139
onSave={handleSave}
117140
showDefaultHeader={true}
141+
requestInterceptor={(config: InternalAxiosRequestConfig) => {
142+
// pass cookies if no token is provided
143+
if (!token) {
144+
config.withCredentials = true
145+
}
146+
return config
147+
}}
118148
/>
119149
</div>
120150
<FlowStatePanel currentFlow={currentFlow} savedFlow={savedFlow} changeCount={changeCount} />
@@ -129,5 +159,6 @@ export const BasicExampleProps = {
129159
initialFlow: 'FlowData',
130160
onFlowChange: '(flow: FlowData) => void',
131161
onSave: '(flow: FlowData) => void',
132-
showDefaultHeader: true
162+
showDefaultHeader: true,
163+
requestInterceptor: '(config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig'
133164
}

packages/agentflow/jest.config.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,16 @@ const baseConfig = {
1212
},
1313
testPathIgnorePatterns: ['/node_modules/', '/dist/'],
1414
moduleNameMapper: {
15-
'^@test-utils/(.*)$': '<rootDir>/src/__test_utils__/$1',
15+
'\\.(css|less|scss|sass)$': '<rootDir>/src/__mocks__/styleMock.js',
1616
'\\.svg$': '<rootDir>/src/__mocks__/styleMock.js',
1717
'^@/(.*)$': '<rootDir>/src/$1',
18-
'\\.(css|less|scss|sass)$': '<rootDir>/src/__mocks__/styleMock.js'
18+
'^@test-utils/(.*)$': '<rootDir>/src/__test_utils__/$1',
19+
// TipTap + lowlight ship ESM-only — Jest (CJS) cannot import them,
20+
// so we redirect to lightweight CJS stubs under src/__mocks__/.
21+
'^@tiptap/(.+)$': '<rootDir>/src/__mocks__/@tiptap/$1.ts',
22+
'^lowlight$': '<rootDir>/src/__mocks__/lowlight.ts',
23+
// Bypass React.lazy wrappers — resolve Foo.lazy → Foo so tests render synchronously
24+
'(.*)\\.lazy$': '$1'
1925
}
2026
}
2127

@@ -39,10 +45,16 @@ module.exports = {
3945
'./src/*.ts': { branches: 80, functions: 80, lines: 80, statements: 80 },
4046
'./src/Agentflow.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 },
4147
'./src/atoms/ArrayInput.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 },
48+
'./src/atoms/ExpandTextDialog.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 },
49+
'./src/atoms/MessagesInput.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 },
50+
'./src/atoms/ScenariosInput.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 },
51+
// Tier 3 UI atom — only the onChange/disabled/sync logic is tested, not styled internals
52+
'./src/atoms/RichTextEditor.tsx': { branches: 30, functions: 50, lines: 50, statements: 50 },
4253
'./src/core/': { branches: 80, functions: 80, lines: 80, statements: 80 },
4354
'./src/features/canvas/components/ConnectionLine.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 },
4455
// Only getMinimumNodeHeight() is tested; the component is Tier 3 UI with no business logic
4556
'./src/features/canvas/components/NodeOutputHandles.tsx': { branches: 0, functions: 10, lines: 30, statements: 30 },
57+
'./src/features/canvas/containers/NodeInfoDialog.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 },
4658
'./src/features/canvas/hooks/': { branches: 80, functions: 80, lines: 80, statements: 80 },
4759
'./src/features/generator/GenerateFlowDialog.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 },
4860
'./src/features/node-editor/': { branches: 80, functions: 80, lines: 80, statements: 80 },

packages/agentflow/package.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@flowiseai/agentflow",
3-
"version": "0.0.0-dev.3",
3+
"version": "0.0.0-dev.6",
44
"description": "Embeddable React component for building and visualizing AI agent workflows",
55
"license": "Apache-2.0",
66
"repository": {
@@ -68,9 +68,23 @@
6868
"reactflow": "^11.5.0"
6969
},
7070
"dependencies": {
71+
"@codemirror/lang-javascript": "^6.2.0",
72+
"@codemirror/lang-json": "^6.0.0",
73+
"@codemirror/lang-python": "^6.1.0",
7174
"@tabler/icons-react": "^3.7.0",
75+
"@tiptap/extension-code-block-lowlight": "^3.4.3",
76+
"@tiptap/extension-placeholder": "^2.11.5",
77+
"@tiptap/react": "^2.11.5",
78+
"@tiptap/starter-kit": "^2.11.5",
79+
"@uiw/codemirror-theme-sublime": "^4.21.0",
80+
"@uiw/codemirror-theme-vscode": "^4.21.0",
81+
"@uiw/react-codemirror": "^4.21.0",
7282
"axios": "^1.7.2",
83+
"dompurify": "^3.2.6",
84+
"flowise-react-json-view": "^1.21.7",
85+
"html-react-parser": "^3.0.16",
7386
"lodash": "^4.17.21",
87+
"lowlight": "^3.3.0",
7488
"uuid": "^10.0.0"
7589
},
7690
"devDependencies": {

0 commit comments

Comments
 (0)