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.
Files changed (45) hide show
  1. package/README.md +4 -4
  2. package/bin/cli.js +5 -0
  3. package/client/package.json +1 -1
  4. package/client/src/components/AIAgentNode.tsx +65 -30
  5. package/client/src/components/CredentialsModal.tsx +162 -6
  6. package/client/src/components/ParameterRenderer.tsx +41 -0
  7. package/client/src/components/parameterPanel/InputSection.tsx +3 -2
  8. package/client/src/components/parameterPanel/MasterSkillEditor.tsx +575 -66
  9. package/client/src/components/parameterPanel/MiddleSection.tsx +213 -3
  10. package/client/src/components/ui/QRCodeDisplay.tsx +1 -1
  11. package/client/src/components/ui/SettingsPanel.tsx +29 -0
  12. package/client/src/contexts/WebSocketContext.tsx +2 -0
  13. package/client/src/factories/baseChatModelFactory.ts +2 -2
  14. package/client/src/hooks/useApiKeys.ts +60 -0
  15. package/client/src/nodeDefinitions/aiAgentNodes.ts +80 -9
  16. package/client/src/nodeDefinitions/skillNodes.ts +5 -208
  17. package/client/src/nodeDefinitions/specializedAgentNodes.ts +35 -4
  18. package/package.json +2 -1
  19. package/scripts/build.js +29 -38
  20. package/scripts/install.js +8 -1
  21. package/scripts/start.js +4 -6
  22. package/server/constants.py +4 -9
  23. package/server/core/config.py +4 -0
  24. package/server/core/container.py +24 -3
  25. package/server/core/database.py +312 -2
  26. package/server/main.py +20 -4
  27. package/server/models/database.py +97 -1
  28. package/server/pyproject.toml +4 -3
  29. package/server/requirements.txt +1 -0
  30. package/server/routers/websocket.py +78 -17
  31. package/server/services/ai.py +235 -18
  32. package/server/services/android/client.py +2 -2
  33. package/server/services/compaction.py +217 -0
  34. package/server/services/handlers/ai.py +8 -2
  35. package/server/services/handlers/tools.py +2 -2
  36. package/server/services/node_executor.py +2 -0
  37. package/server/services/skill_loader.py +17 -12
  38. package/server/services/temporal/__init__.py +13 -3
  39. package/server/skills/assistant/compaction-skill/SKILL.md +157 -0
  40. package/server/skills/assistant/humanify-skill/SKILL.md +210 -0
  41. package/server/skills/autonomous/agentic-loop-skill/SKILL.md +228 -0
  42. package/server/skills/autonomous/code-mode-skill/SKILL.md +226 -0
  43. package/server/skills/autonomous/error-recovery-skill/SKILL.md +394 -0
  44. package/server/skills/autonomous/multi-tool-orchestration-skill/SKILL.md +457 -0
  45. 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-4o, GPT-4 Turbo, o1, o3, o4-mini | JSON mode, reasoning effort |
61
- | **Anthropic** | Claude 3.5 Sonnet, Claude 3 Opus, Claude 3 Haiku | Extended thinking |
62
- | **Google** | Gemini 2.5 Pro, Gemini 2.5 Flash, Gemini 2.0 Flash Thinking | Multimodal, 1M context |
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, Mixtral, Qwen | Ultra-fast inference |
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);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-flow-client",
3
3
  "private": true,
4
- "version": "0.0.13",
4
+ "version": "0.0.17",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "vite --host 0.0.0.0",
@@ -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: '55%' },
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: 160,
74
+ height: 200,
75
75
  },
76
76
  chatAgent: {
77
77
  icon: <span style={{ fontSize: '28px' }}>🧞</span>,
78
78
  title: 'Zeenie',
79
- subtitle: 'Your Personal Assistant',
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: '55%' },
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: 160,
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 Control Agent',
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: '55%' },
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: 160,
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: '55%' },
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: 160,
156
+ height: 200,
156
157
  },
157
158
  web_agent: {
158
159
  icon: <span style={{ fontSize: '28px' }}>🌐</span>,
159
- title: 'Web Control Agent',
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: '55%' },
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: 160,
173
+ height: 200,
173
174
  },
174
175
  task_agent: {
175
176
  icon: <span style={{ fontSize: '28px' }}>📋</span>,
176
- title: 'Task Management Agent',
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: '55%' },
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: 160,
190
+ height: 200,
190
191
  },
191
192
  social_agent: {
192
193
  icon: <span style={{ fontSize: '28px' }}>📱</span>,
193
- title: 'Social Media Agent',
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: '55%' },
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: 160,
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: '55%' },
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: 160,
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: '55%' },
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: 160,
241
+ height: 200,
241
242
  },
242
243
  productivity_agent: {
243
244
  icon: <span style={{ fontSize: '28px' }}>⏰</span>,
244
245
  title: 'Productivity Agent',
245
- subtitle: 'Productivity',
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: '55%' },
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: 160,
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: '55%' },
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: 160,
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: '55%' },
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: 160,
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={200}
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: 200,
971
+ minHeight: 300,
920
972
  }}>
921
973
  <QRCodeDisplay
922
974
  value={androidStatus.qr_data}
923
975
  isConnected={androidStatus.paired}
924
- size={260}
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';