machinaos 0.0.13 → 0.0.17
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.
- package/README.md +4 -4
- package/bin/cli.js +5 -0
- package/client/package.json +1 -1
- package/client/src/components/AIAgentNode.tsx +65 -30
- package/client/src/components/CredentialsModal.tsx +162 -6
- package/client/src/components/ParameterRenderer.tsx +41 -0
- package/client/src/components/parameterPanel/InputSection.tsx +3 -2
- package/client/src/components/parameterPanel/MasterSkillEditor.tsx +575 -66
- package/client/src/components/parameterPanel/MiddleSection.tsx +213 -3
- package/client/src/components/ui/QRCodeDisplay.tsx +1 -1
- package/client/src/components/ui/SettingsPanel.tsx +29 -0
- package/client/src/contexts/WebSocketContext.tsx +2 -0
- package/client/src/factories/baseChatModelFactory.ts +2 -2
- package/client/src/hooks/useApiKeys.ts +60 -0
- package/client/src/nodeDefinitions/aiAgentNodes.ts +80 -9
- package/client/src/nodeDefinitions/skillNodes.ts +5 -208
- package/client/src/nodeDefinitions/specializedAgentNodes.ts +35 -4
- package/package.json +2 -1
- package/scripts/build.js +29 -38
- package/scripts/install.js +8 -1
- package/scripts/start.js +4 -6
- package/server/constants.py +4 -9
- package/server/core/config.py +4 -0
- package/server/core/container.py +24 -3
- package/server/core/database.py +312 -2
- package/server/main.py +20 -4
- package/server/models/database.py +97 -1
- package/server/pyproject.toml +4 -3
- package/server/requirements.txt +1 -0
- package/server/routers/websocket.py +78 -17
- package/server/services/ai.py +235 -18
- package/server/services/android/client.py +2 -2
- package/server/services/compaction.py +217 -0
- package/server/services/handlers/ai.py +8 -2
- package/server/services/handlers/tools.py +2 -2
- package/server/services/node_executor.py +2 -0
- package/server/services/skill_loader.py +17 -12
- package/server/services/temporal/__init__.py +13 -3
- package/server/skills/assistant/compaction-skill/SKILL.md +157 -0
- package/server/skills/assistant/humanify-skill/SKILL.md +210 -0
- package/server/skills/autonomous/agentic-loop-skill/SKILL.md +228 -0
- package/server/skills/autonomous/code-mode-skill/SKILL.md +226 -0
- package/server/skills/autonomous/error-recovery-skill/SKILL.md +394 -0
- package/server/skills/autonomous/multi-tool-orchestration-skill/SKILL.md +457 -0
- package/server/skills/autonomous/progressive-discovery-skill/SKILL.md +223 -0
package/README.md
CHANGED
|
@@ -57,11 +57,11 @@ npm run docker:up
|
|
|
57
57
|
|
|
58
58
|
| Provider | Models | Features |
|
|
59
59
|
|----------|--------|----------|
|
|
60
|
-
| **OpenAI** | GPT-
|
|
61
|
-
| **Anthropic** | Claude
|
|
62
|
-
| **Google** | Gemini
|
|
60
|
+
| **OpenAI** | GPT-5, GPT-4o, o1, o3, o4 | 128K output, reasoning effort |
|
|
61
|
+
| **Anthropic** | Claude Opus 4.6, Sonnet 4.5 | 128K output, extended thinking |
|
|
62
|
+
| **Google** | Gemini 3.0, 2.5 Pro/Flash | 65K output, 1M context |
|
|
63
63
|
| **OpenRouter** | 200+ models | Unified API for all providers |
|
|
64
|
-
| **Groq** | Llama,
|
|
64
|
+
| **Groq** | Llama, Qwen | Ultra-fast inference |
|
|
65
65
|
| **Cerebras** | Llama, Qwen | Ultra-fast on custom hardware |
|
|
66
66
|
|
|
67
67
|
### AI Agents & Skills
|
package/bin/cli.js
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
import { spawn, execSync } from 'child_process';
|
|
4
4
|
import { dirname, resolve } from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
|
+
import { readFileSync } from 'fs';
|
|
6
7
|
|
|
7
8
|
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
9
|
+
const PKG = JSON.parse(readFileSync(resolve(ROOT, 'package.json'), 'utf-8'));
|
|
8
10
|
|
|
9
11
|
const COMMANDS = {
|
|
10
12
|
start: 'Start the development server',
|
|
@@ -16,6 +18,7 @@ const COMMANDS = {
|
|
|
16
18
|
'docker:build': 'Build Docker images',
|
|
17
19
|
'docker:logs': 'View Docker logs',
|
|
18
20
|
help: 'Show this help message',
|
|
21
|
+
version: 'Show version number',
|
|
19
22
|
};
|
|
20
23
|
|
|
21
24
|
function printHelp() {
|
|
@@ -114,6 +117,8 @@ const cmd = process.argv[2] || 'help';
|
|
|
114
117
|
|
|
115
118
|
if (cmd === 'help' || cmd === '--help' || cmd === '-h') {
|
|
116
119
|
printHelp();
|
|
120
|
+
} else if (cmd === 'version' || cmd === '--version' || cmd === '-v') {
|
|
121
|
+
console.log(`machinaos v${PKG.version}`);
|
|
117
122
|
} else if (cmd === 'start' || cmd === 'build') {
|
|
118
123
|
checkDeps();
|
|
119
124
|
run(cmd);
|
package/client/package.json
CHANGED
|
@@ -66,28 +66,29 @@ const AGENT_CONFIGS: Record<string, AgentConfig> = {
|
|
|
66
66
|
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
67
67
|
],
|
|
68
68
|
leftHandles: [
|
|
69
|
-
{ id: 'input-memory', label: 'Memory', position: '
|
|
69
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
70
70
|
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
71
71
|
],
|
|
72
72
|
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
73
73
|
width: 260,
|
|
74
|
-
height:
|
|
74
|
+
height: 200,
|
|
75
75
|
},
|
|
76
76
|
chatAgent: {
|
|
77
77
|
icon: <span style={{ fontSize: '28px' }}>🧞</span>,
|
|
78
78
|
title: 'Zeenie',
|
|
79
|
-
subtitle: '
|
|
79
|
+
subtitle: 'Personal Assistant',
|
|
80
80
|
themeColorKey: 'cyan',
|
|
81
81
|
bottomHandles: [
|
|
82
82
|
{ id: 'input-skill', label: 'Skill', position: '25%' },
|
|
83
83
|
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
84
84
|
],
|
|
85
85
|
leftHandles: [
|
|
86
|
-
{ id: 'input-memory', label: 'Memory', position: '
|
|
86
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
87
87
|
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
88
88
|
],
|
|
89
|
+
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
89
90
|
width: 260,
|
|
90
|
-
height:
|
|
91
|
+
height: 200,
|
|
91
92
|
},
|
|
92
93
|
socialReceive: {
|
|
93
94
|
icon: <SocialReceiveIcon />,
|
|
@@ -122,7 +123,7 @@ const AGENT_CONFIGS: Record<string, AgentConfig> = {
|
|
|
122
123
|
},
|
|
123
124
|
android_agent: {
|
|
124
125
|
icon: <span style={{ fontSize: '28px' }}>📱</span>,
|
|
125
|
-
title: 'Android
|
|
126
|
+
title: 'Android Agent',
|
|
126
127
|
subtitle: 'Device Control',
|
|
127
128
|
themeColorKey: 'green',
|
|
128
129
|
bottomHandles: [
|
|
@@ -130,12 +131,12 @@ const AGENT_CONFIGS: Record<string, AgentConfig> = {
|
|
|
130
131
|
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
131
132
|
],
|
|
132
133
|
leftHandles: [
|
|
133
|
-
{ id: 'input-memory', label: 'Memory', position: '
|
|
134
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
134
135
|
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
135
136
|
],
|
|
136
137
|
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
137
138
|
width: 260,
|
|
138
|
-
height:
|
|
139
|
+
height: 200,
|
|
139
140
|
},
|
|
140
141
|
coding_agent: {
|
|
141
142
|
icon: <span style={{ fontSize: '28px' }}>💻</span>,
|
|
@@ -147,16 +148,16 @@ const AGENT_CONFIGS: Record<string, AgentConfig> = {
|
|
|
147
148
|
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
148
149
|
],
|
|
149
150
|
leftHandles: [
|
|
150
|
-
{ id: 'input-memory', label: 'Memory', position: '
|
|
151
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
151
152
|
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
152
153
|
],
|
|
153
154
|
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
154
155
|
width: 260,
|
|
155
|
-
height:
|
|
156
|
+
height: 200,
|
|
156
157
|
},
|
|
157
158
|
web_agent: {
|
|
158
159
|
icon: <span style={{ fontSize: '28px' }}>🌐</span>,
|
|
159
|
-
title: 'Web
|
|
160
|
+
title: 'Web Agent',
|
|
160
161
|
subtitle: 'Browser Automation',
|
|
161
162
|
themeColorKey: 'pink',
|
|
162
163
|
bottomHandles: [
|
|
@@ -164,16 +165,16 @@ const AGENT_CONFIGS: Record<string, AgentConfig> = {
|
|
|
164
165
|
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
165
166
|
],
|
|
166
167
|
leftHandles: [
|
|
167
|
-
{ id: 'input-memory', label: 'Memory', position: '
|
|
168
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
168
169
|
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
169
170
|
],
|
|
170
171
|
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
171
172
|
width: 260,
|
|
172
|
-
height:
|
|
173
|
+
height: 200,
|
|
173
174
|
},
|
|
174
175
|
task_agent: {
|
|
175
176
|
icon: <span style={{ fontSize: '28px' }}>📋</span>,
|
|
176
|
-
title: 'Task
|
|
177
|
+
title: 'Task Agent',
|
|
177
178
|
subtitle: 'Task Automation',
|
|
178
179
|
themeColorKey: 'purple',
|
|
179
180
|
bottomHandles: [
|
|
@@ -181,16 +182,16 @@ const AGENT_CONFIGS: Record<string, AgentConfig> = {
|
|
|
181
182
|
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
182
183
|
],
|
|
183
184
|
leftHandles: [
|
|
184
|
-
{ id: 'input-memory', label: 'Memory', position: '
|
|
185
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
185
186
|
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
186
187
|
],
|
|
187
188
|
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
188
189
|
width: 260,
|
|
189
|
-
height:
|
|
190
|
+
height: 200,
|
|
190
191
|
},
|
|
191
192
|
social_agent: {
|
|
192
193
|
icon: <span style={{ fontSize: '28px' }}>📱</span>,
|
|
193
|
-
title: 'Social
|
|
194
|
+
title: 'Social Agent',
|
|
194
195
|
subtitle: 'Social Messaging',
|
|
195
196
|
themeColorKey: 'green',
|
|
196
197
|
bottomHandles: [
|
|
@@ -198,12 +199,12 @@ const AGENT_CONFIGS: Record<string, AgentConfig> = {
|
|
|
198
199
|
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
199
200
|
],
|
|
200
201
|
leftHandles: [
|
|
201
|
-
{ id: 'input-memory', label: 'Memory', position: '
|
|
202
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
202
203
|
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
203
204
|
],
|
|
204
205
|
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
205
206
|
width: 260,
|
|
206
|
-
height:
|
|
207
|
+
height: 200,
|
|
207
208
|
},
|
|
208
209
|
travel_agent: {
|
|
209
210
|
icon: <span style={{ fontSize: '28px' }}>✈️</span>,
|
|
@@ -215,12 +216,12 @@ const AGENT_CONFIGS: Record<string, AgentConfig> = {
|
|
|
215
216
|
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
216
217
|
],
|
|
217
218
|
leftHandles: [
|
|
218
|
-
{ id: 'input-memory', label: 'Memory', position: '
|
|
219
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
219
220
|
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
220
221
|
],
|
|
221
222
|
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
222
223
|
width: 260,
|
|
223
|
-
height:
|
|
224
|
+
height: 200,
|
|
224
225
|
},
|
|
225
226
|
tool_agent: {
|
|
226
227
|
icon: <span style={{ fontSize: '28px' }}>🔧</span>,
|
|
@@ -232,29 +233,29 @@ const AGENT_CONFIGS: Record<string, AgentConfig> = {
|
|
|
232
233
|
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
233
234
|
],
|
|
234
235
|
leftHandles: [
|
|
235
|
-
{ id: 'input-memory', label: 'Memory', position: '
|
|
236
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
236
237
|
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
237
238
|
],
|
|
238
239
|
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
239
240
|
width: 260,
|
|
240
|
-
height:
|
|
241
|
+
height: 200,
|
|
241
242
|
},
|
|
242
243
|
productivity_agent: {
|
|
243
244
|
icon: <span style={{ fontSize: '28px' }}>⏰</span>,
|
|
244
245
|
title: 'Productivity Agent',
|
|
245
|
-
subtitle: '
|
|
246
|
+
subtitle: 'Workflows',
|
|
246
247
|
themeColorKey: 'cyan',
|
|
247
248
|
bottomHandles: [
|
|
248
249
|
{ id: 'input-skill', label: 'Skill', position: '25%' },
|
|
249
250
|
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
250
251
|
],
|
|
251
252
|
leftHandles: [
|
|
252
|
-
{ id: 'input-memory', label: 'Memory', position: '
|
|
253
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
253
254
|
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
254
255
|
],
|
|
255
256
|
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
256
257
|
width: 260,
|
|
257
|
-
height:
|
|
258
|
+
height: 200,
|
|
258
259
|
},
|
|
259
260
|
payments_agent: {
|
|
260
261
|
icon: <span style={{ fontSize: '28px' }}>💳</span>,
|
|
@@ -266,12 +267,12 @@ const AGENT_CONFIGS: Record<string, AgentConfig> = {
|
|
|
266
267
|
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
267
268
|
],
|
|
268
269
|
leftHandles: [
|
|
269
|
-
{ id: 'input-memory', label: 'Memory', position: '
|
|
270
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
270
271
|
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
271
272
|
],
|
|
272
273
|
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
273
274
|
width: 260,
|
|
274
|
-
height:
|
|
275
|
+
height: 200,
|
|
275
276
|
},
|
|
276
277
|
consumer_agent: {
|
|
277
278
|
icon: <span style={{ fontSize: '28px' }}>🛒</span>,
|
|
@@ -283,12 +284,46 @@ const AGENT_CONFIGS: Record<string, AgentConfig> = {
|
|
|
283
284
|
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
284
285
|
],
|
|
285
286
|
leftHandles: [
|
|
286
|
-
{ id: 'input-memory', label: 'Memory', position: '
|
|
287
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
287
288
|
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
288
289
|
],
|
|
289
290
|
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
290
291
|
width: 260,
|
|
291
|
-
height:
|
|
292
|
+
height: 200,
|
|
293
|
+
},
|
|
294
|
+
autonomous_agent: {
|
|
295
|
+
icon: <span style={{ fontSize: '28px' }}>🎯</span>,
|
|
296
|
+
title: 'Autonomous Agent',
|
|
297
|
+
subtitle: 'Autonomous Ops',
|
|
298
|
+
themeColorKey: 'purple',
|
|
299
|
+
bottomHandles: [
|
|
300
|
+
{ id: 'input-skill', label: 'Skill', position: '25%' },
|
|
301
|
+
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
302
|
+
],
|
|
303
|
+
leftHandles: [
|
|
304
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
305
|
+
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
306
|
+
],
|
|
307
|
+
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
308
|
+
width: 260,
|
|
309
|
+
height: 200,
|
|
310
|
+
},
|
|
311
|
+
orchestrator_agent: {
|
|
312
|
+
icon: <span style={{ fontSize: '28px' }}>🎼</span>,
|
|
313
|
+
title: 'Orchestrator Agent',
|
|
314
|
+
subtitle: 'Agent Coordination',
|
|
315
|
+
themeColorKey: 'cyan',
|
|
316
|
+
bottomHandles: [
|
|
317
|
+
{ id: 'input-skill', label: 'Skill', position: '25%' },
|
|
318
|
+
{ id: 'input-tools', label: 'Tool', position: '75%' },
|
|
319
|
+
],
|
|
320
|
+
leftHandles: [
|
|
321
|
+
{ id: 'input-memory', label: 'Memory', position: '65%' },
|
|
322
|
+
{ id: 'input-task', label: 'Task', position: '85%' },
|
|
323
|
+
],
|
|
324
|
+
topOutputHandle: { id: 'output-top', label: 'Output' },
|
|
325
|
+
width: 260,
|
|
326
|
+
height: 200,
|
|
292
327
|
},
|
|
293
328
|
};
|
|
294
329
|
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import Modal from './ui/Modal';
|
|
14
14
|
import QRCodeDisplay from './ui/QRCodeDisplay';
|
|
15
15
|
import ApiKeyInput from './ui/ApiKeyInput';
|
|
16
|
-
import { useApiKeys } from '../hooks/useApiKeys';
|
|
16
|
+
import { useApiKeys, ProviderDefaults } from '../hooks/useApiKeys';
|
|
17
17
|
import { useAppTheme } from '../hooks/useAppTheme';
|
|
18
18
|
import { useWhatsAppStatus, useAndroidStatus, useWebSocket, RateLimitConfig, RateLimitStats } from '../contexts/WebSocketContext';
|
|
19
19
|
import { useWhatsApp } from '../hooks/useWhatsApp';
|
|
@@ -114,7 +114,7 @@ interface Props {
|
|
|
114
114
|
|
|
115
115
|
const CredentialsModal: React.FC<Props> = ({ visible, onClose }) => {
|
|
116
116
|
const theme = useAppTheme();
|
|
117
|
-
const { validateApiKey, saveApiKey, getStoredApiKey, hasStoredKey, removeApiKey, validateGoogleMapsKey, isConnected } = useApiKeys();
|
|
117
|
+
const { validateApiKey, saveApiKey, getStoredApiKey, hasStoredKey, removeApiKey, validateGoogleMapsKey, getProviderDefaults, saveProviderDefaults, isConnected } = useApiKeys();
|
|
118
118
|
const whatsappStatus = useWhatsAppStatus();
|
|
119
119
|
const androidStatus = useAndroidStatus();
|
|
120
120
|
|
|
@@ -138,6 +138,11 @@ const CredentialsModal: React.FC<Props> = ({ visible, onClose }) => {
|
|
|
138
138
|
const [proxyUrls, setProxyUrls] = useState<Record<string, string>>({});
|
|
139
139
|
const [selectedItem, setSelectedItem] = useState<CredentialItem | null>(null);
|
|
140
140
|
|
|
141
|
+
// Provider defaults state
|
|
142
|
+
const [providerDefaults, setProviderDefaults] = useState<Record<string, ProviderDefaults>>({});
|
|
143
|
+
const [defaultsLoading, setDefaultsLoading] = useState<Record<string, boolean>>({});
|
|
144
|
+
const [defaultsDirty, setDefaultsDirty] = useState<Record<string, boolean>>({});
|
|
145
|
+
|
|
141
146
|
// Load stored keys and proxy URLs
|
|
142
147
|
const loadKeys = useCallback(async () => {
|
|
143
148
|
const allItems = CATEGORIES.flatMap(c => c.items);
|
|
@@ -177,6 +182,42 @@ const CredentialsModal: React.FC<Props> = ({ visible, onClose }) => {
|
|
|
177
182
|
}
|
|
178
183
|
}, [visible, isConnected, loadKeys]);
|
|
179
184
|
|
|
185
|
+
// Load provider defaults when AI provider is selected
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
const isAIProvider = CATEGORIES.find(c => c.key === 'ai')?.items.some(i => i.id === selectedItem?.id);
|
|
188
|
+
if (selectedItem && !selectedItem.isSpecial && isAIProvider && isConnected) {
|
|
189
|
+
// Only load if we don't already have defaults for this provider
|
|
190
|
+
if (!providerDefaults[selectedItem.id]) {
|
|
191
|
+
const loadDefaults = async () => {
|
|
192
|
+
setDefaultsLoading(l => ({ ...l, [selectedItem.id]: true }));
|
|
193
|
+
const defaults = await getProviderDefaults(selectedItem.id);
|
|
194
|
+
setProviderDefaults(p => ({ ...p, [selectedItem.id]: defaults }));
|
|
195
|
+
setDefaultsLoading(l => ({ ...l, [selectedItem.id]: false }));
|
|
196
|
+
};
|
|
197
|
+
loadDefaults();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}, [selectedItem, isConnected, getProviderDefaults, providerDefaults]);
|
|
201
|
+
|
|
202
|
+
// Handler to update a single default value
|
|
203
|
+
const updateProviderDefault = (provider: string, key: keyof ProviderDefaults, value: number | boolean | string) => {
|
|
204
|
+
setProviderDefaults(p => ({
|
|
205
|
+
...p,
|
|
206
|
+
[provider]: { ...(p[provider] || {}), [key]: value } as ProviderDefaults
|
|
207
|
+
}));
|
|
208
|
+
setDefaultsDirty(d => ({ ...d, [provider]: true }));
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
// Handler to save provider defaults
|
|
212
|
+
const handleSaveProviderDefaults = async (provider: string) => {
|
|
213
|
+
setDefaultsLoading(l => ({ ...l, [provider]: true }));
|
|
214
|
+
const success = await saveProviderDefaults(provider, providerDefaults[provider]);
|
|
215
|
+
if (success) {
|
|
216
|
+
setDefaultsDirty(d => ({ ...d, [provider]: false }));
|
|
217
|
+
}
|
|
218
|
+
setDefaultsLoading(l => ({ ...l, [provider]: false }));
|
|
219
|
+
};
|
|
220
|
+
|
|
180
221
|
const handleValidate = async (id: string) => {
|
|
181
222
|
const key = keys[id];
|
|
182
223
|
if (!key?.trim()) return;
|
|
@@ -323,7 +364,7 @@ const CredentialsModal: React.FC<Props> = ({ visible, onClose }) => {
|
|
|
323
364
|
|
|
324
365
|
// WhatsApp actions
|
|
325
366
|
const { getStatus: getWhatsAppStatus, startConnection, restartConnection } = useWhatsApp();
|
|
326
|
-
const { sendRequest, getWhatsAppRateLimitConfig, setWhatsAppRateLimitConfig, unpauseWhatsAppRateLimit } = useWebSocket();
|
|
367
|
+
const { sendRequest, setAndroidStatus, getWhatsAppRateLimitConfig, setWhatsAppRateLimitConfig, unpauseWhatsAppRateLimit } = useWebSocket();
|
|
327
368
|
|
|
328
369
|
// Android state
|
|
329
370
|
const [androidApiKey, setAndroidApiKey] = useState('');
|
|
@@ -381,8 +422,19 @@ const CredentialsModal: React.FC<Props> = ({ visible, onClose }) => {
|
|
|
381
422
|
url: import.meta.env.VITE_ANDROID_RELAY_URL || '',
|
|
382
423
|
api_key: key,
|
|
383
424
|
});
|
|
425
|
+
console.log('[Android] Connect response:', response);
|
|
384
426
|
if (!response.success) {
|
|
385
427
|
setAndroidError(response.error || 'Failed to connect');
|
|
428
|
+
} else if (response.qr_data) {
|
|
429
|
+
console.log('[Android] Setting QR data from response');
|
|
430
|
+
// Use response data directly - don't rely on broadcast timing
|
|
431
|
+
setAndroidStatus(prev => ({
|
|
432
|
+
...prev,
|
|
433
|
+
connected: true,
|
|
434
|
+
paired: false,
|
|
435
|
+
qr_data: response.qr_data,
|
|
436
|
+
session_token: response.session_token || prev.session_token,
|
|
437
|
+
}));
|
|
386
438
|
}
|
|
387
439
|
} catch (err: any) {
|
|
388
440
|
setAndroidError(err.message || 'Failed to connect');
|
|
@@ -592,7 +644,7 @@ const CredentialsModal: React.FC<Props> = ({ visible, onClose }) => {
|
|
|
592
644
|
<QRCodeDisplay
|
|
593
645
|
value={whatsappStatus.qr}
|
|
594
646
|
isConnected={whatsappStatus.connected}
|
|
595
|
-
size={
|
|
647
|
+
size={280}
|
|
596
648
|
connectedTitle="Already Connected!"
|
|
597
649
|
connectedSubtitle="No QR code needed"
|
|
598
650
|
loading={whatsappStatus.running && !whatsappStatus.qr && !whatsappStatus.connected}
|
|
@@ -916,12 +968,12 @@ const CredentialsModal: React.FC<Props> = ({ visible, onClose }) => {
|
|
|
916
968
|
backgroundColor: theme.colors.backgroundAlt,
|
|
917
969
|
borderRadius: theme.borderRadius.lg,
|
|
918
970
|
marginBottom: theme.spacing.xl,
|
|
919
|
-
minHeight:
|
|
971
|
+
minHeight: 300,
|
|
920
972
|
}}>
|
|
921
973
|
<QRCodeDisplay
|
|
922
974
|
value={androidStatus.qr_data}
|
|
923
975
|
isConnected={androidStatus.paired}
|
|
924
|
-
size={
|
|
976
|
+
size={280}
|
|
925
977
|
connectedTitle="Device Paired!"
|
|
926
978
|
connectedSubtitle={androidStatus.device_name || androidStatus.device_id || 'Android Device'}
|
|
927
979
|
loading={androidStatus.connected && !androidStatus.qr_data && !androidStatus.paired}
|
|
@@ -1213,6 +1265,110 @@ const CredentialsModal: React.FC<Props> = ({ visible, onClose }) => {
|
|
|
1213
1265
|
</div>
|
|
1214
1266
|
)}
|
|
1215
1267
|
|
|
1268
|
+
{/* Default Parameters Section - Only for AI providers */}
|
|
1269
|
+
{CATEGORIES.find(c => c.key === 'ai')?.items.some(i => i.id === item.id) && (
|
|
1270
|
+
<div style={{ marginBottom: theme.spacing.xl }}>
|
|
1271
|
+
<label style={{
|
|
1272
|
+
display: 'block',
|
|
1273
|
+
fontSize: theme.fontSize.sm,
|
|
1274
|
+
fontWeight: theme.fontWeight.medium,
|
|
1275
|
+
color: theme.colors.text,
|
|
1276
|
+
marginBottom: theme.spacing.md,
|
|
1277
|
+
}}>
|
|
1278
|
+
Default Parameters
|
|
1279
|
+
</label>
|
|
1280
|
+
|
|
1281
|
+
<div style={{
|
|
1282
|
+
padding: theme.spacing.lg,
|
|
1283
|
+
backgroundColor: theme.colors.backgroundAlt,
|
|
1284
|
+
borderRadius: theme.borderRadius.md,
|
|
1285
|
+
border: `1px solid ${theme.colors.border}`,
|
|
1286
|
+
opacity: defaultsLoading[item.id] ? 0.6 : 1,
|
|
1287
|
+
}}>
|
|
1288
|
+
{/* Temperature */}
|
|
1289
|
+
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: theme.spacing.md }}>
|
|
1290
|
+
<div>
|
|
1291
|
+
<div style={{ fontSize: theme.fontSize.sm, fontWeight: theme.fontWeight.medium, color: theme.colors.text }}>Temperature</div>
|
|
1292
|
+
<div style={{ fontSize: theme.fontSize.xs, color: theme.colors.textSecondary }}>Controls randomness (0-2)</div>
|
|
1293
|
+
</div>
|
|
1294
|
+
<InputNumber
|
|
1295
|
+
size="small"
|
|
1296
|
+
value={providerDefaults[item.id]?.temperature ?? 0.7}
|
|
1297
|
+
onChange={(v) => updateProviderDefault(item.id, 'temperature', v ?? 0.7)}
|
|
1298
|
+
min={0}
|
|
1299
|
+
max={2}
|
|
1300
|
+
step={0.1}
|
|
1301
|
+
style={{ width: 80 }}
|
|
1302
|
+
/>
|
|
1303
|
+
</div>
|
|
1304
|
+
|
|
1305
|
+
{/* Max Tokens */}
|
|
1306
|
+
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: theme.spacing.md }}>
|
|
1307
|
+
<div>
|
|
1308
|
+
<div style={{ fontSize: theme.fontSize.sm, fontWeight: theme.fontWeight.medium, color: theme.colors.text }}>Max Tokens</div>
|
|
1309
|
+
<div style={{ fontSize: theme.fontSize.xs, color: theme.colors.textSecondary }}>Maximum response length</div>
|
|
1310
|
+
</div>
|
|
1311
|
+
<InputNumber
|
|
1312
|
+
size="small"
|
|
1313
|
+
value={providerDefaults[item.id]?.max_tokens ?? 4096}
|
|
1314
|
+
onChange={(v) => updateProviderDefault(item.id, 'max_tokens', v ?? 4096)}
|
|
1315
|
+
min={1}
|
|
1316
|
+
max={128000}
|
|
1317
|
+
style={{ width: 100 }}
|
|
1318
|
+
/>
|
|
1319
|
+
</div>
|
|
1320
|
+
|
|
1321
|
+
{/* Thinking/Reasoning Toggle */}
|
|
1322
|
+
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: theme.spacing.md }}>
|
|
1323
|
+
<div>
|
|
1324
|
+
<div style={{ fontSize: theme.fontSize.sm, fontWeight: theme.fontWeight.medium, color: theme.colors.text }}>Thinking/Reasoning</div>
|
|
1325
|
+
<div style={{ fontSize: theme.fontSize.xs, color: theme.colors.textSecondary }}>Extended thinking for supported models</div>
|
|
1326
|
+
</div>
|
|
1327
|
+
<Switch
|
|
1328
|
+
size="small"
|
|
1329
|
+
checked={providerDefaults[item.id]?.thinking_enabled ?? false}
|
|
1330
|
+
onChange={(v) => updateProviderDefault(item.id, 'thinking_enabled', v)}
|
|
1331
|
+
/>
|
|
1332
|
+
</div>
|
|
1333
|
+
|
|
1334
|
+
{/* Thinking Budget - conditional */}
|
|
1335
|
+
{providerDefaults[item.id]?.thinking_enabled && (
|
|
1336
|
+
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: theme.spacing.md }}>
|
|
1337
|
+
<div>
|
|
1338
|
+
<div style={{ fontSize: theme.fontSize.sm, fontWeight: theme.fontWeight.medium, color: theme.colors.text }}>Thinking Budget</div>
|
|
1339
|
+
<div style={{ fontSize: theme.fontSize.xs, color: theme.colors.textSecondary }}>Token budget (1024-16000)</div>
|
|
1340
|
+
</div>
|
|
1341
|
+
<InputNumber
|
|
1342
|
+
size="small"
|
|
1343
|
+
value={providerDefaults[item.id]?.thinking_budget ?? 2048}
|
|
1344
|
+
onChange={(v) => updateProviderDefault(item.id, 'thinking_budget', v ?? 2048)}
|
|
1345
|
+
min={1024}
|
|
1346
|
+
max={16000}
|
|
1347
|
+
style={{ width: 80 }}
|
|
1348
|
+
/>
|
|
1349
|
+
</div>
|
|
1350
|
+
)}
|
|
1351
|
+
|
|
1352
|
+
{/* Save Button */}
|
|
1353
|
+
<Button
|
|
1354
|
+
size="small"
|
|
1355
|
+
onClick={() => handleSaveProviderDefaults(item.id)}
|
|
1356
|
+
loading={defaultsLoading[item.id]}
|
|
1357
|
+
disabled={!defaultsDirty[item.id]}
|
|
1358
|
+
block
|
|
1359
|
+
style={{
|
|
1360
|
+
marginTop: theme.spacing.sm,
|
|
1361
|
+
backgroundColor: defaultsDirty[item.id] ? `${theme.dracula.green}25` : undefined,
|
|
1362
|
+
borderColor: defaultsDirty[item.id] ? `${theme.dracula.green}60` : undefined,
|
|
1363
|
+
color: defaultsDirty[item.id] ? theme.dracula.green : undefined,
|
|
1364
|
+
}}
|
|
1365
|
+
>
|
|
1366
|
+
Save Defaults
|
|
1367
|
+
</Button>
|
|
1368
|
+
</div>
|
|
1369
|
+
</div>
|
|
1370
|
+
)}
|
|
1371
|
+
|
|
1216
1372
|
{/* Models list */}
|
|
1217
1373
|
{models[item.id]?.length > 0 && (
|
|
1218
1374
|
<div style={{ marginBottom: theme.spacing.xl }}>
|
|
@@ -768,6 +768,8 @@ interface ParameterRendererProps {
|
|
|
768
768
|
onParameterChange?: (paramName: string, value: any) => void;
|
|
769
769
|
onClosePanel?: () => void;
|
|
770
770
|
isLoadingParameters?: boolean;
|
|
771
|
+
/** For memory nodes: the connected agent's node ID for auto-session display */
|
|
772
|
+
connectedAgentId?: string | null;
|
|
771
773
|
}
|
|
772
774
|
|
|
773
775
|
// Type guard to check if parameter is INodeProperties
|
|
@@ -782,6 +784,7 @@ const ParameterRenderer: React.FC<ParameterRendererProps> = ({
|
|
|
782
784
|
allParameters,
|
|
783
785
|
onParameterChange,
|
|
784
786
|
isLoadingParameters = false,
|
|
787
|
+
connectedAgentId,
|
|
785
788
|
}) => {
|
|
786
789
|
const theme = useAppTheme();
|
|
787
790
|
// Don't use default while loading - wait for actual saved value to load
|
|
@@ -1380,6 +1383,44 @@ const ParameterRenderer: React.FC<ParameterRendererProps> = ({
|
|
|
1380
1383
|
);
|
|
1381
1384
|
}
|
|
1382
1385
|
|
|
1386
|
+
// Special case for sessionId parameter - show auto-derived session ID in placeholder
|
|
1387
|
+
if (parameter.name === 'sessionId' && connectedAgentId) {
|
|
1388
|
+
const effectivePlaceholder = connectedAgentId;
|
|
1389
|
+
|
|
1390
|
+
return (
|
|
1391
|
+
<input
|
|
1392
|
+
type="text"
|
|
1393
|
+
value={currentValue || ''}
|
|
1394
|
+
onChange={(e) => onChange(e.target.value)}
|
|
1395
|
+
placeholder={effectivePlaceholder}
|
|
1396
|
+
onDragOver={handleDragOver}
|
|
1397
|
+
onDragLeave={handleDragLeave}
|
|
1398
|
+
onDrop={handleDrop}
|
|
1399
|
+
style={{
|
|
1400
|
+
width: '100%',
|
|
1401
|
+
padding: '10px 12px',
|
|
1402
|
+
border: isDragOver ? `2px solid ${theme.accent.cyan}` : `1px solid ${theme.colors.border}`,
|
|
1403
|
+
borderRadius: '6px',
|
|
1404
|
+
fontSize: '14px',
|
|
1405
|
+
backgroundColor: isDragOver ? `${theme.accent.cyan}10` : theme.colors.backgroundAlt,
|
|
1406
|
+
color: currentValue && currentValue.includes('{{') ? theme.accent.yellow : theme.colors.text,
|
|
1407
|
+
outline: 'none',
|
|
1408
|
+
transition: 'all 0.2s ease',
|
|
1409
|
+
fontFamily: currentValue && currentValue.includes('{{') ? 'monospace' : 'system-ui, sans-serif',
|
|
1410
|
+
boxShadow: 'inset 0 1px 2px rgba(0,0,0,0.05)'
|
|
1411
|
+
}}
|
|
1412
|
+
onFocus={(e) => {
|
|
1413
|
+
e.target.style.borderColor = theme.accent.cyan;
|
|
1414
|
+
e.target.style.boxShadow = `0 0 0 3px ${theme.accent.cyan}20, inset 0 1px 2px rgba(0,0,0,0.05)`;
|
|
1415
|
+
}}
|
|
1416
|
+
onBlur={(e) => {
|
|
1417
|
+
e.target.style.borderColor = theme.colors.border;
|
|
1418
|
+
e.target.style.boxShadow = 'inset 0 1px 2px rgba(0,0,0,0.05)';
|
|
1419
|
+
}}
|
|
1420
|
+
/>
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1383
1424
|
return (
|
|
1384
1425
|
<input
|
|
1385
1426
|
type={isPassword ? "password" : "text"}
|
|
@@ -88,7 +88,8 @@ const InputSection: React.FC<InputSectionProps> = ({ nodeId, visible = true }) =
|
|
|
88
88
|
const AGENT_WITH_SKILLS_TYPES = [
|
|
89
89
|
'aiAgent', 'chatAgent', 'android_agent', 'coding_agent',
|
|
90
90
|
'web_agent', 'task_agent', 'social_agent', 'travel_agent',
|
|
91
|
-
'tool_agent', 'productivity_agent', 'payments_agent', 'consumer_agent'
|
|
91
|
+
'tool_agent', 'productivity_agent', 'payments_agent', 'consumer_agent',
|
|
92
|
+
'autonomous_agent', 'orchestrator_agent'
|
|
92
93
|
];
|
|
93
94
|
// Check if current node is an agent that shows skills in Middle Section
|
|
94
95
|
const isAgentWithSkills = AGENT_WITH_SKILLS_TYPES.includes(currentNodeType || '');
|
|
@@ -486,7 +487,7 @@ const InputSection: React.FC<InputSectionProps> = ({ nodeId, visible = true }) =
|
|
|
486
487
|
const isMemory = nodeType === 'simpleMemory';
|
|
487
488
|
const nodeTypeLower = nodeType.toLowerCase();
|
|
488
489
|
// AI agent types that use the AI output schema
|
|
489
|
-
const aiAgentTypes = ['aiAgent', 'chatAgent', 'android_agent', 'coding_agent', 'web_agent', 'task_agent', 'social_agent', 'travel_agent', 'tool_agent', 'productivity_agent', 'payments_agent', 'consumer_agent'];
|
|
490
|
+
const aiAgentTypes = ['aiAgent', 'chatAgent', 'android_agent', 'coding_agent', 'web_agent', 'task_agent', 'social_agent', 'travel_agent', 'tool_agent', 'productivity_agent', 'payments_agent', 'consumer_agent', 'autonomous_agent', 'orchestrator_agent'];
|
|
490
491
|
const isAI = !isMemory && (nodeTypeLower.includes('chatmodel') || aiAgentTypes.includes(nodeType));
|
|
491
492
|
const isFile = nodeType.includes('file');
|
|
492
493
|
const isWhatsAppDb = nodeType === 'whatsappDb';
|