machinaos 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/.env.template +71 -0
  2. package/LICENSE +21 -0
  3. package/README.md +87 -0
  4. package/bin/cli.js +159 -0
  5. package/client/.dockerignore +45 -0
  6. package/client/Dockerfile +68 -0
  7. package/client/eslint.config.js +29 -0
  8. package/client/index.html +13 -0
  9. package/client/nginx.conf +66 -0
  10. package/client/package.json +48 -0
  11. package/client/src/App.tsx +27 -0
  12. package/client/src/Dashboard.tsx +1173 -0
  13. package/client/src/ParameterPanel.tsx +301 -0
  14. package/client/src/components/AIAgentNode.tsx +321 -0
  15. package/client/src/components/APIKeyValidator.tsx +118 -0
  16. package/client/src/components/ClaudeChatModelNode.tsx +18 -0
  17. package/client/src/components/ConditionalEdge.tsx +189 -0
  18. package/client/src/components/CredentialsModal.tsx +306 -0
  19. package/client/src/components/EdgeConditionEditor.tsx +443 -0
  20. package/client/src/components/GeminiChatModelNode.tsx +18 -0
  21. package/client/src/components/GenericNode.tsx +357 -0
  22. package/client/src/components/LocationParameterPanel.tsx +154 -0
  23. package/client/src/components/ModelNode.tsx +286 -0
  24. package/client/src/components/OpenAIChatModelNode.tsx +18 -0
  25. package/client/src/components/OutputPanel.tsx +471 -0
  26. package/client/src/components/ParameterRenderer.tsx +1874 -0
  27. package/client/src/components/SkillEditorModal.tsx +417 -0
  28. package/client/src/components/SquareNode.tsx +797 -0
  29. package/client/src/components/StartNode.tsx +250 -0
  30. package/client/src/components/ToolkitNode.tsx +365 -0
  31. package/client/src/components/TriggerNode.tsx +463 -0
  32. package/client/src/components/auth/LoginPage.tsx +247 -0
  33. package/client/src/components/auth/ProtectedRoute.tsx +59 -0
  34. package/client/src/components/base/BaseChatModelNode.tsx +271 -0
  35. package/client/src/components/icons/AIProviderIcons.tsx +50 -0
  36. package/client/src/components/maps/GoogleMapsPicker.tsx +137 -0
  37. package/client/src/components/maps/MapsPreviewPanel.tsx +110 -0
  38. package/client/src/components/maps/index.ts +26 -0
  39. package/client/src/components/parameterPanel/InputSection.tsx +1094 -0
  40. package/client/src/components/parameterPanel/LocationPanelLayout.tsx +65 -0
  41. package/client/src/components/parameterPanel/MapsSection.tsx +92 -0
  42. package/client/src/components/parameterPanel/MiddleSection.tsx +571 -0
  43. package/client/src/components/parameterPanel/OutputSection.tsx +81 -0
  44. package/client/src/components/parameterPanel/ParameterPanelLayout.tsx +82 -0
  45. package/client/src/components/parameterPanel/ToolSchemaEditor.tsx +436 -0
  46. package/client/src/components/parameterPanel/index.ts +42 -0
  47. package/client/src/components/shared/DataPanel.tsx +142 -0
  48. package/client/src/components/shared/JSONTreeRenderer.tsx +106 -0
  49. package/client/src/components/ui/AIResultModal.tsx +204 -0
  50. package/client/src/components/ui/AndroidSettingsPanel.tsx +401 -0
  51. package/client/src/components/ui/CodeEditor.tsx +81 -0
  52. package/client/src/components/ui/CollapsibleSection.tsx +88 -0
  53. package/client/src/components/ui/ComponentItem.tsx +154 -0
  54. package/client/src/components/ui/ComponentPalette.tsx +321 -0
  55. package/client/src/components/ui/ConsolePanel.tsx +1074 -0
  56. package/client/src/components/ui/ErrorBoundary.tsx +196 -0
  57. package/client/src/components/ui/InputNodesPanel.tsx +204 -0
  58. package/client/src/components/ui/MapSelector.tsx +314 -0
  59. package/client/src/components/ui/Modal.tsx +149 -0
  60. package/client/src/components/ui/NodeContextMenu.tsx +192 -0
  61. package/client/src/components/ui/NodeOutputPanel.tsx +1150 -0
  62. package/client/src/components/ui/OutputDisplayPanel.tsx +381 -0
  63. package/client/src/components/ui/SettingsPanel.tsx +243 -0
  64. package/client/src/components/ui/TopToolbar.tsx +736 -0
  65. package/client/src/components/ui/WhatsAppSettingsPanel.tsx +345 -0
  66. package/client/src/components/ui/WorkflowSidebar.tsx +294 -0
  67. package/client/src/config/antdTheme.ts +186 -0
  68. package/client/src/config/api.ts +54 -0
  69. package/client/src/contexts/AuthContext.tsx +221 -0
  70. package/client/src/contexts/ThemeContext.tsx +42 -0
  71. package/client/src/contexts/WebSocketContext.tsx +1971 -0
  72. package/client/src/factories/baseChatModelFactory.ts +256 -0
  73. package/client/src/hooks/useAndroidOperations.ts +164 -0
  74. package/client/src/hooks/useApiKeyValidation.ts +107 -0
  75. package/client/src/hooks/useApiKeys.ts +238 -0
  76. package/client/src/hooks/useAppTheme.ts +17 -0
  77. package/client/src/hooks/useComponentPalette.ts +51 -0
  78. package/client/src/hooks/useCopyPaste.ts +155 -0
  79. package/client/src/hooks/useDragAndDrop.ts +124 -0
  80. package/client/src/hooks/useDragVariable.ts +88 -0
  81. package/client/src/hooks/useExecution.ts +313 -0
  82. package/client/src/hooks/useParameterPanel.ts +176 -0
  83. package/client/src/hooks/useReactFlowNodes.ts +189 -0
  84. package/client/src/hooks/useToolSchema.ts +209 -0
  85. package/client/src/hooks/useWhatsApp.ts +196 -0
  86. package/client/src/hooks/useWorkflowManagement.ts +46 -0
  87. package/client/src/index.css +315 -0
  88. package/client/src/main.tsx +19 -0
  89. package/client/src/nodeDefinitions/aiAgentNodes.ts +336 -0
  90. package/client/src/nodeDefinitions/aiModelNodes.ts +340 -0
  91. package/client/src/nodeDefinitions/androidDeviceNodes.ts +140 -0
  92. package/client/src/nodeDefinitions/androidServiceNodes.ts +383 -0
  93. package/client/src/nodeDefinitions/chatNodes.ts +135 -0
  94. package/client/src/nodeDefinitions/codeNodes.ts +54 -0
  95. package/client/src/nodeDefinitions/documentNodes.ts +379 -0
  96. package/client/src/nodeDefinitions/index.ts +15 -0
  97. package/client/src/nodeDefinitions/locationNodes.ts +463 -0
  98. package/client/src/nodeDefinitions/schedulerNodes.ts +220 -0
  99. package/client/src/nodeDefinitions/skillNodes.ts +211 -0
  100. package/client/src/nodeDefinitions/toolNodes.ts +198 -0
  101. package/client/src/nodeDefinitions/utilityNodes.ts +284 -0
  102. package/client/src/nodeDefinitions/whatsappNodes.ts +865 -0
  103. package/client/src/nodeDefinitions/workflowNodes.ts +41 -0
  104. package/client/src/nodeDefinitions.ts +104 -0
  105. package/client/src/schemas/workflowSchema.ts +264 -0
  106. package/client/src/services/dynamicParameterService.ts +96 -0
  107. package/client/src/services/execution/aiAgentExecutionService.ts +35 -0
  108. package/client/src/services/executionService.ts +232 -0
  109. package/client/src/services/workflowApi.ts +91 -0
  110. package/client/src/store/useAppStore.ts +582 -0
  111. package/client/src/styles/theme.ts +508 -0
  112. package/client/src/styles/zIndex.ts +17 -0
  113. package/client/src/types/ComponentTypes.ts +39 -0
  114. package/client/src/types/EdgeCondition.ts +231 -0
  115. package/client/src/types/INodeProperties.ts +288 -0
  116. package/client/src/types/NodeTypes.ts +28 -0
  117. package/client/src/utils/formatters.ts +33 -0
  118. package/client/src/utils/googleMapsLoader.ts +140 -0
  119. package/client/src/utils/locationUtils.ts +85 -0
  120. package/client/src/utils/nodeUtils.ts +31 -0
  121. package/client/src/utils/workflow.ts +30 -0
  122. package/client/src/utils/workflowExport.ts +120 -0
  123. package/client/src/vite-env.d.ts +12 -0
  124. package/client/tailwind.config.js +60 -0
  125. package/client/tsconfig.json +25 -0
  126. package/client/tsconfig.node.json +11 -0
  127. package/client/vite.config.js +35 -0
  128. package/docker-compose.prod.yml +107 -0
  129. package/docker-compose.yml +104 -0
  130. package/docs-MachinaOs/README.md +85 -0
  131. package/docs-MachinaOs/deployment/docker.mdx +228 -0
  132. package/docs-MachinaOs/deployment/production.mdx +345 -0
  133. package/docs-MachinaOs/docs.json +75 -0
  134. package/docs-MachinaOs/faq.mdx +309 -0
  135. package/docs-MachinaOs/favicon.svg +5 -0
  136. package/docs-MachinaOs/installation.mdx +160 -0
  137. package/docs-MachinaOs/introduction.mdx +114 -0
  138. package/docs-MachinaOs/logo/dark.svg +6 -0
  139. package/docs-MachinaOs/logo/light.svg +6 -0
  140. package/docs-MachinaOs/nodes/ai-agent.mdx +216 -0
  141. package/docs-MachinaOs/nodes/ai-models.mdx +240 -0
  142. package/docs-MachinaOs/nodes/android.mdx +411 -0
  143. package/docs-MachinaOs/nodes/overview.mdx +181 -0
  144. package/docs-MachinaOs/nodes/schedulers.mdx +316 -0
  145. package/docs-MachinaOs/nodes/webhooks.mdx +330 -0
  146. package/docs-MachinaOs/nodes/whatsapp.mdx +305 -0
  147. package/docs-MachinaOs/quickstart.mdx +119 -0
  148. package/docs-MachinaOs/tutorials/ai-agent-workflow.mdx +177 -0
  149. package/docs-MachinaOs/tutorials/android-automation.mdx +242 -0
  150. package/docs-MachinaOs/tutorials/first-workflow.mdx +134 -0
  151. package/docs-MachinaOs/tutorials/whatsapp-automation.mdx +185 -0
  152. package/nul +0 -0
  153. package/package.json +70 -0
  154. package/scripts/build.js +158 -0
  155. package/scripts/check-ports.ps1 +33 -0
  156. package/scripts/clean.js +40 -0
  157. package/scripts/docker.js +93 -0
  158. package/scripts/kill-port.ps1 +154 -0
  159. package/scripts/start.js +210 -0
  160. package/scripts/stop.js +325 -0
  161. package/server/.dockerignore +44 -0
  162. package/server/Dockerfile +45 -0
  163. package/server/constants.py +249 -0
  164. package/server/core/__init__.py +1 -0
  165. package/server/core/cache.py +461 -0
  166. package/server/core/config.py +128 -0
  167. package/server/core/container.py +99 -0
  168. package/server/core/database.py +1211 -0
  169. package/server/core/logging.py +314 -0
  170. package/server/main.py +289 -0
  171. package/server/middleware/__init__.py +5 -0
  172. package/server/middleware/auth.py +89 -0
  173. package/server/models/__init__.py +1 -0
  174. package/server/models/auth.py +52 -0
  175. package/server/models/cache.py +24 -0
  176. package/server/models/database.py +211 -0
  177. package/server/models/nodes.py +455 -0
  178. package/server/package.json +9 -0
  179. package/server/pyproject.toml +72 -0
  180. package/server/requirements.txt +83 -0
  181. package/server/routers/__init__.py +1 -0
  182. package/server/routers/android.py +294 -0
  183. package/server/routers/auth.py +203 -0
  184. package/server/routers/database.py +151 -0
  185. package/server/routers/maps.py +142 -0
  186. package/server/routers/nodejs_compat.py +289 -0
  187. package/server/routers/webhook.py +90 -0
  188. package/server/routers/websocket.py +2127 -0
  189. package/server/routers/whatsapp.py +761 -0
  190. package/server/routers/workflow.py +200 -0
  191. package/server/services/__init__.py +1 -0
  192. package/server/services/ai.py +2415 -0
  193. package/server/services/android/__init__.py +27 -0
  194. package/server/services/android/broadcaster.py +114 -0
  195. package/server/services/android/client.py +608 -0
  196. package/server/services/android/manager.py +78 -0
  197. package/server/services/android/protocol.py +165 -0
  198. package/server/services/android_service.py +588 -0
  199. package/server/services/auth.py +131 -0
  200. package/server/services/chat_client.py +160 -0
  201. package/server/services/deployment/__init__.py +12 -0
  202. package/server/services/deployment/manager.py +706 -0
  203. package/server/services/deployment/state.py +47 -0
  204. package/server/services/deployment/triggers.py +275 -0
  205. package/server/services/event_waiter.py +785 -0
  206. package/server/services/execution/__init__.py +77 -0
  207. package/server/services/execution/cache.py +769 -0
  208. package/server/services/execution/conditions.py +373 -0
  209. package/server/services/execution/dlq.py +132 -0
  210. package/server/services/execution/executor.py +1351 -0
  211. package/server/services/execution/models.py +531 -0
  212. package/server/services/execution/recovery.py +235 -0
  213. package/server/services/handlers/__init__.py +126 -0
  214. package/server/services/handlers/ai.py +355 -0
  215. package/server/services/handlers/android.py +260 -0
  216. package/server/services/handlers/code.py +278 -0
  217. package/server/services/handlers/document.py +598 -0
  218. package/server/services/handlers/http.py +193 -0
  219. package/server/services/handlers/polyglot.py +105 -0
  220. package/server/services/handlers/tools.py +845 -0
  221. package/server/services/handlers/triggers.py +107 -0
  222. package/server/services/handlers/utility.py +822 -0
  223. package/server/services/handlers/whatsapp.py +476 -0
  224. package/server/services/maps.py +289 -0
  225. package/server/services/memory_store.py +103 -0
  226. package/server/services/node_executor.py +375 -0
  227. package/server/services/parameter_resolver.py +218 -0
  228. package/server/services/polyglot_client.py +169 -0
  229. package/server/services/scheduler.py +155 -0
  230. package/server/services/skill_loader.py +417 -0
  231. package/server/services/status_broadcaster.py +826 -0
  232. package/server/services/temporal/__init__.py +23 -0
  233. package/server/services/temporal/activities.py +344 -0
  234. package/server/services/temporal/client.py +76 -0
  235. package/server/services/temporal/executor.py +147 -0
  236. package/server/services/temporal/worker.py +251 -0
  237. package/server/services/temporal/workflow.py +355 -0
  238. package/server/services/temporal/ws_client.py +236 -0
  239. package/server/services/text.py +111 -0
  240. package/server/services/user_auth.py +172 -0
  241. package/server/services/websocket_client.py +29 -0
  242. package/server/services/workflow.py +597 -0
  243. package/server/skills/android-skill/SKILL.md +82 -0
  244. package/server/skills/assistant-personality/SKILL.md +45 -0
  245. package/server/skills/code-skill/SKILL.md +140 -0
  246. package/server/skills/http-skill/SKILL.md +161 -0
  247. package/server/skills/maps-skill/SKILL.md +170 -0
  248. package/server/skills/memory-skill/SKILL.md +154 -0
  249. package/server/skills/scheduler-skill/SKILL.md +84 -0
  250. package/server/skills/whatsapp-skill/SKILL.md +283 -0
  251. package/server/uv.lock +2916 -0
  252. package/server/whatsapp-rpc/.dockerignore +30 -0
  253. package/server/whatsapp-rpc/Dockerfile +44 -0
  254. package/server/whatsapp-rpc/Dockerfile.web +17 -0
  255. package/server/whatsapp-rpc/README.md +139 -0
  256. package/server/whatsapp-rpc/cli.js +95 -0
  257. package/server/whatsapp-rpc/configs/config.yaml +7 -0
  258. package/server/whatsapp-rpc/docker-compose.yml +35 -0
  259. package/server/whatsapp-rpc/docs/API.md +410 -0
  260. package/server/whatsapp-rpc/go.mod +67 -0
  261. package/server/whatsapp-rpc/go.sum +203 -0
  262. package/server/whatsapp-rpc/package.json +30 -0
  263. package/server/whatsapp-rpc/schema.json +1294 -0
  264. package/server/whatsapp-rpc/scripts/clean.cjs +66 -0
  265. package/server/whatsapp-rpc/scripts/cli.js +162 -0
  266. package/server/whatsapp-rpc/src/go/cmd/server/main.go +91 -0
  267. package/server/whatsapp-rpc/src/go/config/config.go +49 -0
  268. package/server/whatsapp-rpc/src/go/rpc/rpc.go +446 -0
  269. package/server/whatsapp-rpc/src/go/rpc/server.go +112 -0
  270. package/server/whatsapp-rpc/src/go/whatsapp/history.go +166 -0
  271. package/server/whatsapp-rpc/src/go/whatsapp/messages.go +390 -0
  272. package/server/whatsapp-rpc/src/go/whatsapp/service.go +2130 -0
  273. package/server/whatsapp-rpc/src/go/whatsapp/types.go +261 -0
  274. package/server/whatsapp-rpc/src/python/pyproject.toml +15 -0
  275. package/server/whatsapp-rpc/src/python/whatsapp_rpc/__init__.py +4 -0
  276. package/server/whatsapp-rpc/src/python/whatsapp_rpc/client.py +427 -0
  277. package/server/whatsapp-rpc/web/app.py +609 -0
  278. package/server/whatsapp-rpc/web/requirements.txt +6 -0
  279. package/server/whatsapp-rpc/web/rpc_client.py +427 -0
  280. package/server/whatsapp-rpc/web/static/openapi.yaml +59 -0
  281. package/server/whatsapp-rpc/web/templates/base.html +150 -0
  282. package/server/whatsapp-rpc/web/templates/contacts.html +240 -0
  283. package/server/whatsapp-rpc/web/templates/dashboard.html +320 -0
  284. package/server/whatsapp-rpc/web/templates/groups.html +328 -0
  285. package/server/whatsapp-rpc/web/templates/messages.html +465 -0
  286. package/server/whatsapp-rpc/web/templates/messaging.html +681 -0
  287. package/server/whatsapp-rpc/web/templates/send.html +259 -0
  288. package/server/whatsapp-rpc/web/templates/settings.html +459 -0
@@ -0,0 +1,301 @@
1
+ import React from 'react';
2
+ import Modal from './components/ui/Modal';
3
+ import ParameterPanelLayout from './components/parameterPanel/ParameterPanelLayout';
4
+ import { useParameterPanel } from './hooks/useParameterPanel';
5
+ import { useAppStore } from './store/useAppStore';
6
+ import { useWebSocket } from './contexts/WebSocketContext';
7
+ import { ExecutionService, ExecutionResult } from './services/executionService';
8
+ import { useAppTheme } from './hooks/useAppTheme';
9
+ import { ScheduleOutlined, PlayCircleFilled } from '@ant-design/icons';
10
+
11
+ const ParameterPanel: React.FC = () => {
12
+ const theme = useAppTheme();
13
+ const {
14
+ selectedNode,
15
+ nodeDefinition,
16
+ parameters,
17
+ hasUnsavedChanges,
18
+ handleParameterChange,
19
+ handleSave,
20
+ handleCancel,
21
+ isLoading,
22
+ } = useParameterPanel();
23
+
24
+ const { currentWorkflow } = useAppStore();
25
+ const { executeNode, getNodeParameters, clearNodeStatus, cancelEventWait, getNodeStatus } = useWebSocket();
26
+
27
+ // Get current node status to check if waiting
28
+ const nodeStatus = selectedNode ? getNodeStatus(selectedNode.id) : null;
29
+ const isWaiting = nodeStatus?.status === 'waiting';
30
+
31
+ // Execution state
32
+ const [isExecuting, setIsExecuting] = React.useState(false);
33
+ const [executionResults, setExecutionResults] = React.useState<ExecutionResult[]>([]);
34
+
35
+
36
+ const handleModalClose = () => {
37
+ handleCancel();
38
+ };
39
+
40
+ // Execute the current node
41
+ const handleRun = async () => {
42
+ if (!selectedNode || !nodeDefinition) return;
43
+
44
+ // Save parameters first if there are unsaved changes
45
+ if (hasUnsavedChanges) {
46
+ await handleSave();
47
+ }
48
+
49
+ setIsExecuting(true);
50
+
51
+ try {
52
+
53
+ // Get current workflow nodes and edges from app store
54
+ const nodes = currentWorkflow?.nodes || [];
55
+ const edges = currentWorkflow?.edges || [];
56
+
57
+ // Execute node via WebSocket
58
+ const result: ExecutionResult = await ExecutionService.executeNodeViaWebSocket(
59
+ selectedNode.id,
60
+ nodeDefinition.name,
61
+ executeNode,
62
+ getNodeParameters,
63
+ nodes,
64
+ edges
65
+ );
66
+
67
+ // Debug logging
68
+ console.log('[ParameterPanel] Execution result:', result);
69
+ console.log('[ParameterPanel] Result nodeId:', result.nodeId);
70
+ console.log('[ParameterPanel] Result outputs:', result.outputs);
71
+ console.log('[ParameterPanel] Selected node id:', selectedNode.id);
72
+
73
+ // Add result to the beginning of the array (newest first)
74
+ setExecutionResults(prev => [result, ...prev]);
75
+
76
+ } catch (error: any) {
77
+ console.error('Execution failed:', error);
78
+
79
+ // Add error result
80
+ const errorResult: ExecutionResult = {
81
+ success: false,
82
+ nodeId: selectedNode.id,
83
+ nodeType: nodeDefinition.name,
84
+ nodeName: nodeDefinition.displayName,
85
+ timestamp: new Date().toISOString(),
86
+ executionTime: 0,
87
+ error: error.message || 'Unknown execution error',
88
+ nodeData: [[{
89
+ json: {
90
+ error: error.message || 'Unknown execution error',
91
+ nodeId: selectedNode.id,
92
+ success: false,
93
+ timestamp: new Date().toISOString()
94
+ }
95
+ }]]
96
+ };
97
+
98
+ setExecutionResults(prev => [errorResult, ...prev]);
99
+ } finally {
100
+ setIsExecuting(false);
101
+ }
102
+ };
103
+
104
+ // Clear execution results (both local state and WebSocket nodeStatuses)
105
+ const handleClearResults = () => {
106
+ setExecutionResults([]);
107
+ // Also clear the node status from WebSocket context
108
+ if (selectedNode) {
109
+ clearNodeStatus(selectedNode.id);
110
+ }
111
+ };
112
+
113
+
114
+ // Check if node can be executed
115
+ const canExecute = selectedNode && nodeDefinition &&
116
+ ExecutionService.isNodeTypeSupported(nodeDefinition.name);
117
+
118
+ // Check if this is a Start node (only show middle section)
119
+ const isStartNode = nodeDefinition?.name === 'start';
120
+
121
+ if (!selectedNode || !nodeDefinition) {
122
+ return null;
123
+ }
124
+
125
+
126
+
127
+ // Helper to render icon (handles image URLs, Ant Design icons, and emoji/text)
128
+ const renderIcon = (icon: string) => {
129
+ // Handle Ant Design icon names
130
+ if (icon === 'schedule') {
131
+ return <ScheduleOutlined style={{ fontSize: 20, color: theme.colors.actionDeploy }} />;
132
+ }
133
+ if (icon === 'play' || nodeDefinition?.name === 'start') {
134
+ return <PlayCircleFilled style={{ fontSize: 20, color: theme.dracula.cyan }} />;
135
+ }
136
+ // Handle image URLs
137
+ if (icon.startsWith('data:') || icon.startsWith('http') || icon.startsWith('/')) {
138
+ return (
139
+ <img
140
+ src={icon}
141
+ alt="icon"
142
+ style={{ width: 20, height: 20, objectFit: 'contain' }}
143
+ />
144
+ );
145
+ }
146
+ return <span>{icon}</span>;
147
+ };
148
+
149
+ // Action button style helper - Dracula theme for visibility
150
+ const actionButtonStyle = (color: string, isDisabled = false): React.CSSProperties => ({
151
+ height: '32px',
152
+ padding: '0 14px',
153
+ display: 'flex',
154
+ alignItems: 'center',
155
+ gap: '6px',
156
+ backgroundColor: isDisabled ? `${theme.colors.primary}15` : `${color}25`,
157
+ color: isDisabled ? theme.colors.primary : color,
158
+ border: `1px solid ${isDisabled ? `${theme.colors.primary}40` : `${color}60`}`,
159
+ borderRadius: theme.borderRadius.sm,
160
+ fontSize: '13px',
161
+ fontWeight: 600,
162
+ cursor: isDisabled ? 'not-allowed' : 'pointer',
163
+ transition: `all ${theme.transitions.fast}`,
164
+ fontFamily: 'system-ui, sans-serif',
165
+ });
166
+
167
+ // Header actions with node name and buttons in middle area
168
+ const headerActions = (
169
+ <div style={{
170
+ display: 'flex',
171
+ gap: '16px',
172
+ alignItems: 'center'
173
+ }}>
174
+ {/* Node Name */}
175
+ <div style={{
176
+ display: 'flex',
177
+ alignItems: 'center',
178
+ gap: '8px',
179
+ fontSize: '15px',
180
+ fontWeight: 600,
181
+ color: theme.colors.text,
182
+ fontFamily: 'system-ui, sans-serif'
183
+ }}>
184
+ {renderIcon(nodeDefinition.icon)}
185
+ <span>{nodeDefinition.displayName}</span>
186
+ {hasUnsavedChanges && <span style={{ color: theme.accent.orange }}>*</span>}
187
+ </div>
188
+
189
+ {/* Buttons: Run, Save, Cancel */}
190
+ <div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
191
+ {/* Run Button */}
192
+ {canExecute && (
193
+ <button
194
+ style={actionButtonStyle(theme.dracula.green, isExecuting)}
195
+ onClick={handleRun}
196
+ disabled={isExecuting}
197
+ title={isExecuting ? 'Execution in progress...' : 'Execute this node'}
198
+ onMouseEnter={(e) => {
199
+ if (!isExecuting) {
200
+ e.currentTarget.style.backgroundColor = `${theme.dracula.green}40`;
201
+ }
202
+ }}
203
+ onMouseLeave={(e) => {
204
+ if (!isExecuting) {
205
+ e.currentTarget.style.backgroundColor = `${theme.dracula.green}25`;
206
+ }
207
+ }}
208
+ >
209
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">
210
+ <path d="M8 5v14l11-7z"/>
211
+ </svg>
212
+ {isExecuting ? 'Running...' : 'Run'}
213
+ </button>
214
+ )}
215
+
216
+ {/* Save Button */}
217
+ <button
218
+ style={actionButtonStyle(theme.dracula.purple, !hasUnsavedChanges)}
219
+ onClick={handleSave}
220
+ disabled={!hasUnsavedChanges}
221
+ onMouseEnter={(e) => {
222
+ if (hasUnsavedChanges) {
223
+ e.currentTarget.style.backgroundColor = `${theme.dracula.purple}40`;
224
+ }
225
+ }}
226
+ onMouseLeave={(e) => {
227
+ if (hasUnsavedChanges) {
228
+ e.currentTarget.style.backgroundColor = `${theme.dracula.purple}25`;
229
+ }
230
+ }}
231
+ >
232
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
233
+ <path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
234
+ <polyline points="17 21 17 13 7 13 7 21"/>
235
+ <polyline points="7 3 7 8 15 8"/>
236
+ </svg>
237
+ Save
238
+ </button>
239
+
240
+ {/* Cancel/Stop Button */}
241
+ <button
242
+ style={actionButtonStyle(theme.dracula.pink, false)}
243
+ onClick={async () => {
244
+ if (isWaiting && selectedNode) {
245
+ // Cancel the event wait for trigger nodes - don't close modal, let execution complete
246
+ console.log('[ParameterPanel] Cancelling event wait:', {
247
+ nodeId: selectedNode.id,
248
+ waiterId: nodeStatus?.data?.waiter_id,
249
+ nodeStatus
250
+ });
251
+ const result = await cancelEventWait(selectedNode.id, nodeStatus?.data?.waiter_id);
252
+ console.log('[ParameterPanel] Cancel result:', result);
253
+ // Don't call handleCancel() - let the execution complete with cancelled state
254
+ return;
255
+ }
256
+ handleCancel();
257
+ }}
258
+ onMouseEnter={(e) => {
259
+ e.currentTarget.style.backgroundColor = `${theme.dracula.pink}40`;
260
+ }}
261
+ onMouseLeave={(e) => {
262
+ e.currentTarget.style.backgroundColor = `${theme.dracula.pink}25`;
263
+ }}
264
+ >
265
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
266
+ <line x1="18" y1="6" x2="6" y2="18"/>
267
+ <line x1="6" y1="6" x2="18" y2="18"/>
268
+ </svg>
269
+ {isWaiting ? 'Stop' : 'Cancel'}
270
+ </button>
271
+ </div>
272
+ </div>
273
+ );
274
+
275
+ return (
276
+ <Modal
277
+ isOpen={!!selectedNode}
278
+ onClose={handleModalClose}
279
+ title="Node Configuration"
280
+ maxWidth="95vw"
281
+ maxHeight="95vh"
282
+ headerActions={headerActions}
283
+ >
284
+ {/* Modular Three Panel Layout */}
285
+ <ParameterPanelLayout
286
+ selectedNode={selectedNode}
287
+ nodeDefinition={nodeDefinition}
288
+ parameters={parameters}
289
+ hasUnsavedChanges={hasUnsavedChanges}
290
+ onParameterChange={handleParameterChange}
291
+ executionResults={executionResults}
292
+ onClearResults={handleClearResults}
293
+ showInputSection={!isStartNode}
294
+ showOutputSection={!isStartNode}
295
+ isLoadingParameters={isLoading}
296
+ />
297
+ </Modal>
298
+ );
299
+ };
300
+
301
+ export default ParameterPanel;
@@ -0,0 +1,321 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Handle, Position, NodeProps } from 'reactflow';
3
+ import { NodeData } from '../types/NodeTypes';
4
+ import { useAppStore } from '../store/useAppStore';
5
+ import AIAgentExecutionService from '../services/execution/aiAgentExecutionService';
6
+ import { useAppTheme } from '../hooks/useAppTheme';
7
+ import { useNodeStatus } from '../contexts/WebSocketContext';
8
+
9
+ // LangGraph phase icons and labels
10
+ const PHASE_CONFIG: Record<string, { icon: string; label: string; color: string }> = {
11
+ initializing: { icon: '⚡', label: 'Initializing', color: '#8be9fd' },
12
+ loading_memory: { icon: '💾', label: 'Loading Memory', color: '#bd93f9' },
13
+ memory_loaded: { icon: '✓', label: 'Memory Ready', color: '#50fa7b' },
14
+ building_tools: { icon: '🔧', label: 'Building Tools', color: '#ffb86c' },
15
+ building_graph: { icon: '🔗', label: 'Building Graph', color: '#ffb86c' },
16
+ invoking_llm: { icon: '🧠', label: 'Thinking...', color: '#ff79c6' },
17
+ executing_tool: { icon: '⚡', label: 'Using Tool', color: '#ff79c6' },
18
+ tool_completed: { icon: '✓', label: 'Tool Done', color: '#50fa7b' },
19
+ saving_memory: { icon: '💾', label: 'Saving Memory', color: '#bd93f9' },
20
+ };
21
+
22
+ // Configuration for different agent types
23
+ interface AgentConfig {
24
+ icon: React.ReactNode;
25
+ title: string;
26
+ subtitle: string;
27
+ accentColor: string;
28
+ bottomHandles: Array<{ id: string; label: string; position: string }>;
29
+ }
30
+
31
+ // Lucide-style SVG icons
32
+ const RobotIcon = ({ size = 32, color = 'currentColor' }: { size?: number; color?: string }) => (
33
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
34
+ <rect x="3" y="11" width="18" height="10" rx="2" />
35
+ <circle cx="12" cy="5" r="2" />
36
+ <path d="M12 7v4" />
37
+ <line x1="8" y1="16" x2="8" y2="16" />
38
+ <line x1="16" y1="16" x2="16" y2="16" />
39
+ <circle cx="8" cy="16" r="1" fill={color} />
40
+ <circle cx="16" cy="16" r="1" fill={color} />
41
+ </svg>
42
+ );
43
+
44
+ // Lucide MessageSquare icon - clean chat bubble
45
+ const ChatAgentIcon = ({ size = 32, color = 'currentColor' }: { size?: number; color?: string }) => (
46
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
47
+ <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
48
+ </svg>
49
+ );
50
+
51
+ const AGENT_CONFIGS: Record<string, AgentConfig> = {
52
+ aiAgent: {
53
+ icon: <RobotIcon />,
54
+ title: 'AI Agent',
55
+ subtitle: 'LangGraph Agent',
56
+ accentColor: '#9333EA',
57
+ bottomHandles: [
58
+ { id: 'input-memory', label: 'Memory', position: '35%' },
59
+ { id: 'input-tools', label: 'Tool', position: '65%' },
60
+ ],
61
+ },
62
+ chatAgent: {
63
+ icon: <ChatAgentIcon />,
64
+ title: 'Chat Agent',
65
+ subtitle: 'Skill-based Agent',
66
+ accentColor: '#3B82F6',
67
+ bottomHandles: [
68
+ { id: 'input-memory', label: 'Memory', position: '25%' },
69
+ { id: 'input-skill', label: 'Skill', position: '50%' },
70
+ { id: 'input-tools', label: 'Tool', position: '75%' },
71
+ ],
72
+ },
73
+ };
74
+
75
+ const AIAgentNode: React.FC<NodeProps<NodeData>> = ({ id, type, data, isConnectable, selected }) => {
76
+ const theme = useAppTheme();
77
+ const { setSelectedNode } = useAppStore();
78
+ const [_configValid, setConfigValid] = useState(true);
79
+ const [_configErrors, setConfigErrors] = useState<string[]>([]);
80
+
81
+ // Get config based on node type
82
+ const config = AGENT_CONFIGS[type || 'aiAgent'] || AGENT_CONFIGS.aiAgent;
83
+
84
+ // Get real-time node status from WebSocket
85
+ const nodeStatus = useNodeStatus(id);
86
+ const isExecuting = nodeStatus?.status === 'executing';
87
+ const currentPhase = nodeStatus?.data?.phase as string | undefined;
88
+ const phaseConfig = currentPhase ? PHASE_CONFIG[currentPhase] : null;
89
+
90
+ // Validate configuration whenever data changes
91
+ useEffect(() => {
92
+ try {
93
+ const validation = AIAgentExecutionService.validateConfiguration(data || {});
94
+ setConfigValid(validation.valid);
95
+ setConfigErrors(validation.errors);
96
+
97
+ if (!validation.valid) {
98
+ console.warn(`${config.title} ${id} configuration issues:`, validation.errors);
99
+ }
100
+ } catch (error) {
101
+ console.error('Configuration validation error:', error);
102
+ setConfigValid(false);
103
+ setConfigErrors(['Configuration validation failed']);
104
+ }
105
+ }, [data, id, config.title]);
106
+
107
+ const handleParametersClick = (e: React.MouseEvent) => {
108
+ e.stopPropagation();
109
+ setSelectedNode({ id, type, data, position: { x: 0, y: 0 } });
110
+ };
111
+
112
+ const getBorderColor = () => {
113
+ if (isExecuting) {
114
+ if (theme.isDarkMode && phaseConfig) return phaseConfig.color;
115
+ return config.accentColor;
116
+ }
117
+ if (selected) return theme.colors.focus;
118
+ return theme.colors.border;
119
+ };
120
+
121
+ const getBoxShadow = () => {
122
+ if (isExecuting) {
123
+ if (theme.isDarkMode && phaseConfig) {
124
+ return `0 0 20px ${phaseConfig.color}80, 0 0 40px ${phaseConfig.color}40`;
125
+ }
126
+ return `0 0 0 3px ${config.accentColor}80, 0 4px 16px ${config.accentColor}60`;
127
+ }
128
+ if (selected) {
129
+ return `0 4px 12px ${theme.colors.focusRing}, 0 0 0 1px ${theme.colors.focusRing}`;
130
+ }
131
+ return `0 2px 4px ${theme.colors.shadow}`;
132
+ };
133
+
134
+ return (
135
+ <div
136
+ style={{
137
+ position: 'relative',
138
+ padding: theme.spacing.lg,
139
+ minWidth: '180px',
140
+ minHeight: '120px',
141
+ borderRadius: theme.borderRadius.lg,
142
+ background: theme.colors.background,
143
+ border: `2px solid ${getBorderColor()}`,
144
+ color: theme.colors.text,
145
+ fontSize: theme.fontSize.sm,
146
+ fontWeight: theme.fontWeight.medium,
147
+ textAlign: 'center',
148
+ cursor: 'pointer',
149
+ transition: 'all 0.3s ease',
150
+ boxShadow: getBoxShadow(),
151
+ overflow: 'visible',
152
+ display: 'flex',
153
+ flexDirection: 'column',
154
+ alignItems: 'center',
155
+ justifyContent: 'center',
156
+ gap: theme.spacing.sm,
157
+ animation: isExecuting ? 'pulse 1.5s ease-in-out infinite' : 'none'
158
+ }}
159
+ >
160
+ {/* Input Handle */}
161
+ <Handle
162
+ id="input-main"
163
+ type="target"
164
+ position={Position.Left}
165
+ isConnectable={isConnectable}
166
+ style={{
167
+ position: 'absolute',
168
+ left: '-6px',
169
+ top: '50%',
170
+ transform: 'translateY(-50%)',
171
+ width: theme.nodeSize.handle,
172
+ height: theme.nodeSize.handle,
173
+ backgroundColor: theme.colors.background,
174
+ border: `2px solid ${theme.colors.textSecondary}`,
175
+ borderRadius: '50%'
176
+ }}
177
+ title="Main Input"
178
+ />
179
+
180
+ {/* Parameters Button */}
181
+ <button
182
+ onClick={handleParametersClick}
183
+ style={{
184
+ position: 'absolute',
185
+ top: theme.spacing.xs,
186
+ right: theme.spacing.xs,
187
+ width: theme.nodeSize.paramButton,
188
+ height: theme.nodeSize.paramButton,
189
+ borderRadius: theme.borderRadius.sm,
190
+ backgroundColor: theme.colors.backgroundAlt,
191
+ border: `1px solid ${theme.colors.border}`,
192
+ cursor: 'pointer',
193
+ display: 'flex',
194
+ alignItems: 'center',
195
+ justifyContent: 'center',
196
+ fontSize: theme.fontSize.xs,
197
+ color: theme.colors.textSecondary,
198
+ fontWeight: theme.fontWeight.normal,
199
+ transition: theme.transitions.fast,
200
+ zIndex: 20
201
+ }}
202
+ title="Edit Parameters"
203
+ >
204
+ ⚙️
205
+ </button>
206
+
207
+ {/* Status Indicator */}
208
+ <div
209
+ style={{
210
+ position: 'absolute',
211
+ top: theme.spacing.xs,
212
+ left: theme.spacing.xs,
213
+ width: '10px',
214
+ height: '10px',
215
+ borderRadius: '50%',
216
+ backgroundColor: isExecuting
217
+ ? (theme.isDarkMode ? (phaseConfig?.color || theme.dracula.cyan) : theme.dracula.cyan)
218
+ : (nodeStatus?.status === 'success' ? theme.dracula.green
219
+ : nodeStatus?.status === 'error' ? theme.dracula.red
220
+ : theme.colors.textSecondary),
221
+ boxShadow: isExecuting
222
+ ? (theme.isDarkMode
223
+ ? `0 0 8px ${phaseConfig?.color || theme.dracula.cyan}`
224
+ : `0 0 4px ${config.accentColor}80`)
225
+ : 'none',
226
+ animation: isExecuting ? 'pulse 1s ease-in-out infinite' : 'none',
227
+ zIndex: 20
228
+ }}
229
+ title={isExecuting ? (phaseConfig?.label || 'Executing') : (nodeStatus?.status || 'Idle')}
230
+ />
231
+
232
+ {/* Icon */}
233
+ <div style={{ lineHeight: '1', marginBottom: theme.spacing.xs, color: config.accentColor }}>
234
+ {config.icon}
235
+ </div>
236
+
237
+ {/* Title */}
238
+ <div style={{
239
+ fontSize: theme.fontSize.base,
240
+ fontWeight: theme.fontWeight.semibold,
241
+ color: theme.colors.text,
242
+ lineHeight: '1.2',
243
+ marginBottom: theme.spacing.xs
244
+ }}>
245
+ {config.title}
246
+ </div>
247
+
248
+ {/* Subtitle */}
249
+ <div style={{
250
+ fontSize: theme.fontSize.xs,
251
+ fontWeight: theme.fontWeight.normal,
252
+ color: isExecuting && phaseConfig ? phaseConfig.color : theme.colors.focus,
253
+ lineHeight: '1.2',
254
+ marginBottom: theme.spacing.lg,
255
+ transition: 'color 0.3s ease'
256
+ }}>
257
+ {isExecuting && phaseConfig ? phaseConfig.label : config.subtitle}
258
+ </div>
259
+
260
+ {/* Bottom Handle Labels */}
261
+ <div style={{
262
+ position: 'absolute',
263
+ bottom: theme.spacing.lg,
264
+ left: '0',
265
+ right: '0',
266
+ display: 'flex',
267
+ justifyContent: 'space-around',
268
+ fontSize: theme.fontSize.xs,
269
+ color: theme.colors.textSecondary,
270
+ fontWeight: theme.fontWeight.normal
271
+ }}>
272
+ {config.bottomHandles.map(h => <span key={h.id}>{h.label}</span>)}
273
+ </div>
274
+
275
+ {/* Bottom Handles */}
276
+ {config.bottomHandles.map(h => (
277
+ <Handle
278
+ key={h.id}
279
+ id={h.id}
280
+ type="target"
281
+ position={Position.Bottom}
282
+ isConnectable={isConnectable}
283
+ style={{
284
+ position: 'absolute',
285
+ bottom: '-6px',
286
+ left: h.position,
287
+ width: theme.nodeSize.handle,
288
+ height: theme.nodeSize.handle,
289
+ backgroundColor: theme.colors.background,
290
+ border: `2px solid ${theme.colors.textSecondary}`,
291
+ borderRadius: '0',
292
+ transform: 'translateX(-50%) rotate(45deg)'
293
+ }}
294
+ title={h.label}
295
+ />
296
+ ))}
297
+
298
+ {/* Output Handle */}
299
+ <Handle
300
+ id="output-main"
301
+ type="source"
302
+ position={Position.Right}
303
+ isConnectable={isConnectable}
304
+ style={{
305
+ position: 'absolute',
306
+ right: '-6px',
307
+ top: '50%',
308
+ transform: 'translateY(-50%)',
309
+ width: theme.nodeSize.handle,
310
+ height: theme.nodeSize.handle,
311
+ backgroundColor: theme.colors.background,
312
+ border: `2px solid ${theme.colors.textSecondary}`,
313
+ borderRadius: '50%'
314
+ }}
315
+ title="Main Output"
316
+ />
317
+ </div>
318
+ );
319
+ };
320
+
321
+ export default AIAgentNode;