Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/agentflow/examples/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/**
* Application configuration from environment variables
*/
export const apiBaseUrl = import.meta.env.VITE_INSTANCE_URL || 'http://localhost:3000'
// When VITE_INSTANCE_URL is set, use it directly (cross-origin with API key).
// Otherwise use the dev server origin so Vite's proxy routes /api/* to the backend (no CORS, cookies work).
export const apiBaseUrl = import.meta.env.VITE_INSTANCE_URL || window.location.origin
export const token = import.meta.env.VITE_API_TOKEN || undefined
export const agentflowId = import.meta.env.VITE_FLOW_ID || undefined
1 change: 1 addition & 0 deletions packages/agentflow/examples/src/demos/E2eExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ export function E2eExample() {
apiBaseUrl={apiBaseUrl}
token={token ?? undefined}
initialFlow={loadedFlow}
flowId={activeChatflowId}
onFlowChange={handleFlowChange}
onSave={handleSave}
canvasActions={canvasActions}
Expand Down
47 changes: 27 additions & 20 deletions packages/agentflow/examples/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
import { defineConfig } from 'vite'
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'

export default defineConfig({
plugins: [react()],
root: __dirname,
resolve: {
alias: {
// Use the source files directly for development
'@flowiseai/agentflow': path.resolve(__dirname, '../src'),
'@': path.resolve(__dirname, '../src')
}
},
server: {
port: 5174,
// Watch the parent src directory for changes
watch: {
// Include the agentflow source directory
ignored: ['!**/packages/agentflow/src/**']
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, __dirname, '')
// VITE_INSTANCE_URL points at a remote instance; BACKEND_URL overrides the local dev server port.
const backendUrl = env.VITE_INSTANCE_URL || 'http://localhost:3000'

return {
plugins: [react()],
root: __dirname,
resolve: {
alias: {
// Use the source files directly for development
'@flowiseai/agentflow': path.resolve(__dirname, '../src'),
'@': path.resolve(__dirname, '../src')
}
},
server: {
port: 5174,
proxy: {
'/api': backendUrl
},
watch: {
ignored: ['!**/packages/agentflow/src/**']
}
},
optimizeDeps: {
include: ['react', 'react-dom', '@mui/material', 'reactflow']
}
},
optimizeDeps: {
include: ['react', 'react-dom', '@mui/material', 'reactflow']
}
})
6 changes: 6 additions & 0 deletions packages/agentflow/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@ const baseConfig = {
moduleNameMapper: {
'\\.(css|less|scss|sass)$': '<rootDir>/src/__mocks__/styleMock.js',
'\\.svg$': '<rootDir>/src/__mocks__/styleMock.js',
'\\.(png|jpg|jpeg|gif|webp|ico)$': '<rootDir>/src/__mocks__/fileMock.js',
'^@/(.*)$': '<rootDir>/src/$1',
'^@test-utils/(.*)$': '<rootDir>/src/__test_utils__/$1',
// TipTap + lowlight ship ESM-only — Jest (CJS) cannot import them,
// so we redirect to lightweight CJS stubs under src/__mocks__/.
'^@tiptap/(.+)$': '<rootDir>/src/__mocks__/@tiptap/$1.ts',
'^lowlight$': '<rootDir>/src/__mocks__/lowlight.ts',
'^tippy\\.js$': '<rootDir>/src/__mocks__/tippy.js.ts',
// uuid ships ESM-only in browser context — redirect to deterministic CJS stub
'^uuid$': '<rootDir>/src/__mocks__/uuid.ts',
// react-markdown and remark-gfm ship ESM-only — redirect to lightweight CJS stubs
'^react-markdown$': '<rootDir>/src/__mocks__/react-markdown.tsx',
'^remark-gfm$': '<rootDir>/src/__mocks__/remark-gfm.ts',
// Bypass React.lazy wrappers — resolve Foo.lazy → Foo so tests render synchronously
'(.*)\\.lazy$': '$1'
}
Expand Down
3 changes: 3 additions & 0 deletions packages/agentflow/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@
"@uiw/codemirror-theme-sublime": "^4.21.0",
"@uiw/codemirror-theme-vscode": "^4.21.0",
"@uiw/react-codemirror": "^4.21.0",
"@microsoft/fetch-event-source": "^2.0.1",
"axios": "1.15.0",
"react-markdown": "^9.1.0",
"remark-gfm": "^4.0.1",
"dompurify": "^3.2.6",
"flowise-react-json-view": "^1.21.7",
"html-react-parser": "^3.0.16",
Expand Down
34 changes: 25 additions & 9 deletions packages/agentflow/src/Agentflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import ReactFlow, { Background, Controls, MiniMap, ReactFlowProvider, useEdgesSt
import { Alert, Snackbar } from '@mui/material'
import { IconSparkles } from '@tabler/icons-react'

import { StyledFab } from '@/atoms'

import { tokens } from './core/theme'
import type { AgentFlowInstance, AgentflowProps, FlowData, FlowDataCallback, FlowEdge, FlowNode } from './core/types'
import { initNode, resolveNodeType } from './core/utils'
Expand All @@ -22,7 +24,7 @@ import {
import { ValidationFeedback } from './features/canvas/components'
import { GenerateFlowDialog } from './features/generator'
import { EditNodeDialog } from './features/node-editor'
import { AddNodesDrawer, StyledFab } from './features/node-palette'
import { AddNodesDrawer } from './features/node-palette'
import { useAgentflowContext, useConfigContext } from './infrastructure/store'
import { AgentflowProvider } from './AgentflowProvider'
import { useAgentflow } from './useAgentflow'
Expand All @@ -35,6 +37,7 @@ import './features/canvas/canvas.css'
*/
function AgentflowCanvas({
initialFlow,
flowId,
readOnly,
onFlowChange,
onSave,
Expand All @@ -47,6 +50,7 @@ function AgentflowCanvas({
renderNodePalette
}: {
initialFlow?: FlowData
flowId?: string
readOnly?: boolean
onFlowChange?: FlowDataCallback
onSave?: FlowDataCallback
Expand All @@ -63,6 +67,7 @@ function AgentflowCanvas({
syncNodesFromReactFlow,
syncEdgesFromReactFlow,
setDirty,
setChatflow,
setReactFlowInstance,
closeEditDialog,
registerLocalStateSetters,
Expand All @@ -89,6 +94,7 @@ function AgentflowCanvas({
const [nodes, setLocalNodes, onNodesChange] = useNodesState(safeInitialNodes)
const [edges, setLocalEdges, onEdgesChange] = useEdgesState(safeInitialEdges)
const [showGenerateDialog, setShowGenerateDialog] = useState(false)
const [isChatOpen, setIsChatOpen] = useState(false)

// Constraint violation snackbar state
const [snackbar, setSnackbar] = useState<{ open: boolean; message: string }>({ open: false, message: '' })
Expand Down Expand Up @@ -139,6 +145,11 @@ function AgentflowCanvas({
return () => registerOnFlowChange(undefined)
}, [registerOnFlowChange, onFlowChange])

// Sync flowId into context so features like TestFlowButton can read state.chatflow.id
useEffect(() => {
setChatflow(flowId ? { id: flowId } : null)
}, [flowId, setChatflow])

// Sync local ReactFlow state to context (when user interacts with canvas)
useEffect(() => {
syncNodesFromReactFlow(nodes as FlowNode[])
Expand Down Expand Up @@ -287,14 +298,16 @@ function AgentflowCanvas({
gap: 8
}}
>
<TestFlowButton />
<ValidationFeedback
nodes={nodes as FlowNode[]}
edges={edges as FlowEdge[]}
availableNodes={availableNodes}
setNodes={setLocalNodes as React.Dispatch<React.SetStateAction<FlowNode[]>>}
/>
{canvasActions}
<TestFlowButton onOpenChange={setIsChatOpen} />
{!isChatOpen && (
<ValidationFeedback
nodes={nodes as FlowNode[]}
edges={edges as FlowEdge[]}
availableNodes={availableNodes}
setNodes={setLocalNodes as React.Dispatch<React.SetStateAction<FlowNode[]>>}
/>
)}
{!isChatOpen && canvasActions}
</div>
)}

Expand Down Expand Up @@ -374,6 +387,7 @@ export const Agentflow = forwardRef<AgentFlowInstance, AgentflowProps>(function
token,
requestInterceptor,
initialFlow,
flowId,
components,
onFlowChange,
onSave,
Expand Down Expand Up @@ -402,6 +416,7 @@ export const Agentflow = forwardRef<AgentFlowInstance, AgentflowProps>(function
<AgentflowCanvasWithRef
ref={ref}
initialFlow={initialFlow}
flowId={flowId}
readOnly={readOnly}
onFlowChange={onFlowChange}
onSave={onSave}
Expand All @@ -425,6 +440,7 @@ const AgentflowCanvasWithRef = forwardRef<
AgentFlowInstance,
{
initialFlow?: FlowData
flowId?: string
readOnly?: boolean
onFlowChange?: FlowDataCallback
onSave?: FlowDataCallback
Expand Down
1 change: 1 addition & 0 deletions packages/agentflow/src/__mocks__/fileMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = 'test-file-stub'
4 changes: 4 additions & 0 deletions packages/agentflow/src/__mocks__/react-markdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import React from 'react'

const ReactMarkdown = ({ children }: { children?: React.ReactNode }) => <span>{children}</span>
export default ReactMarkdown
2 changes: 2 additions & 0 deletions packages/agentflow/src/__mocks__/remark-gfm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const remarkGfm = () => {}
export default remarkGfm
7 changes: 7 additions & 0 deletions packages/agentflow/src/__mocks__/uuid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
let _counter = 0

export const v4 = (): string => `test-uuid-${++_counter}`

export const reset = (): void => {
_counter = 0
}
Binary file added packages/agentflow/src/assets/images/account.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/agentflow/src/assets/images/robot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export interface StyledFabProps extends FabProps {
}

/**
* Styled floating action button with hover effects
* Supports gradient background for special actions like Generate
* Styled floating action button with hover effects.
* Supports gradient background for special actions like Generate.
*/
export const StyledFab: ComponentType<StyledFabProps> = styled(Fab, {
shouldForwardProp: (prop) => prop !== 'gradient'
Expand Down
1 change: 1 addition & 0 deletions packages/agentflow/src/atoms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export { RichTextEditor } from './RichTextEditor.lazy'
export { ScenariosInput, type ScenariosInputProps } from './ScenariosInput'
export { StateKeyValueInput, type StateKeyValueInputProps } from './StateKeyValueInput'
export { StructuredOutputBuilder, type StructuredOutputBuilderProps, type StructuredOutputEntry } from './StructuredOutputBuilder'
export { StyledFab, type StyledFabProps } from './StyledFab'
export { SuggestionDropdown, type SuggestionDropdownProps, type SuggestionDropdownRef, type SuggestionItem } from './SuggestionDropdown'
export { SwitchInput, type SwitchInputProps } from './SwitchInput'
export { TooltipWithParser, type TooltipWithParserProps } from './TooltipWithParser'
Expand Down

This file was deleted.

1 change: 0 additions & 1 deletion packages/agentflow/src/features/canvas/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,4 @@ export { NodeModelConfigs } from './NodeModelConfigs'
export { getMinimumNodeHeight, NodeOutputHandles } from './NodeOutputHandles'
export { NodeStatusIndicator, NodeWarningIndicator } from './NodeStatusIndicator'
export { NodeToolbarActions } from './NodeToolbarActions'
export { TestFlowButton } from './TestFlowButton'
export { ValidationFeedback } from './ValidationFeedback'
Loading