@swarmclawai/swarmclaw 0.7.1 → 0.7.3

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 (237) hide show
  1. package/README.md +155 -150
  2. package/package.json +1 -1
  3. package/src/app/api/agents/[id]/route.ts +26 -0
  4. package/src/app/api/agents/[id]/thread/route.ts +37 -9
  5. package/src/app/api/agents/route.ts +13 -2
  6. package/src/app/api/auth/route.ts +76 -7
  7. package/src/app/api/chatrooms/[id]/chat/route.ts +7 -2
  8. package/src/app/api/{sessions → chats}/[id]/browser/route.ts +5 -1
  9. package/src/app/api/{sessions → chats}/[id]/chat/route.ts +7 -3
  10. package/src/app/api/{sessions → chats}/[id]/checkpoints/route.ts +1 -1
  11. package/src/app/api/chats/[id]/main-loop/route.ts +13 -0
  12. package/src/app/api/{sessions → chats}/[id]/messages/route.ts +19 -13
  13. package/src/app/api/{sessions → chats}/[id]/restore/route.ts +1 -1
  14. package/src/app/api/{sessions → chats}/[id]/route.ts +22 -52
  15. package/src/app/api/{sessions → chats}/[id]/stop/route.ts +6 -1
  16. package/src/app/api/{sessions → chats}/route.ts +21 -7
  17. package/src/app/api/connectors/[id]/doctor/route.ts +26 -0
  18. package/src/app/api/connectors/doctor/route.ts +13 -0
  19. package/src/app/api/files/open/route.ts +16 -14
  20. package/src/app/api/memory/maintenance/route.ts +11 -1
  21. package/src/app/api/openclaw/agent-files/route.ts +27 -4
  22. package/src/app/api/openclaw/skills/route.ts +11 -3
  23. package/src/app/api/plugins/dependencies/route.ts +24 -0
  24. package/src/app/api/plugins/install/route.ts +15 -92
  25. package/src/app/api/plugins/route.ts +6 -26
  26. package/src/app/api/plugins/settings/route.ts +40 -0
  27. package/src/app/api/plugins/ui/route.ts +1 -0
  28. package/src/app/api/settings/route.ts +49 -7
  29. package/src/app/api/tasks/[id]/route.ts +15 -6
  30. package/src/app/api/tasks/bulk/route.ts +2 -2
  31. package/src/app/api/tasks/route.ts +9 -4
  32. package/src/app/api/usage/route.ts +30 -0
  33. package/src/app/api/webhooks/[id]/route.ts +8 -1
  34. package/src/app/page.tsx +9 -2
  35. package/src/cli/index.js +39 -33
  36. package/src/cli/index.ts +43 -49
  37. package/src/cli/spec.js +29 -27
  38. package/src/components/agents/agent-card.tsx +16 -13
  39. package/src/components/agents/agent-chat-list.tsx +104 -4
  40. package/src/components/agents/agent-list.tsx +54 -22
  41. package/src/components/agents/agent-sheet.tsx +209 -18
  42. package/src/components/agents/cron-job-form.tsx +3 -3
  43. package/src/components/agents/inspector-panel.tsx +110 -50
  44. package/src/components/auth/access-key-gate.tsx +36 -97
  45. package/src/components/auth/setup-wizard.tsx +5 -38
  46. package/src/components/chat/chat-area.tsx +39 -27
  47. package/src/components/{sessions/session-card.tsx → chat/chat-card.tsx} +7 -23
  48. package/src/components/chat/chat-header.tsx +299 -314
  49. package/src/components/{sessions/session-list.tsx → chat/chat-list.tsx} +11 -14
  50. package/src/components/chat/chat-tool-toggles.tsx +26 -17
  51. package/src/components/chat/checkpoint-timeline.tsx +4 -4
  52. package/src/components/chat/message-bubble.tsx +4 -1
  53. package/src/components/chat/message-list.tsx +5 -3
  54. package/src/components/chat/session-debug-panel.tsx +1 -1
  55. package/src/components/chat/tool-request-banner.tsx +3 -3
  56. package/src/components/chatrooms/agent-hover-card.tsx +3 -3
  57. package/src/components/chatrooms/chatroom-tool-request-banner.tsx +2 -2
  58. package/src/components/chatrooms/chatroom-view.tsx +347 -205
  59. package/src/components/connectors/connector-list.tsx +265 -127
  60. package/src/components/connectors/connector-sheet.tsx +218 -1
  61. package/src/components/home/home-view.tsx +129 -5
  62. package/src/components/layout/app-layout.tsx +392 -182
  63. package/src/components/layout/mobile-header.tsx +26 -8
  64. package/src/components/plugins/plugin-list.tsx +487 -254
  65. package/src/components/plugins/plugin-sheet.tsx +236 -13
  66. package/src/components/projects/project-detail.tsx +183 -0
  67. package/src/components/settings/gateway-connection-panel.tsx +1 -1
  68. package/src/components/shared/agent-picker-list.tsx +2 -2
  69. package/src/components/shared/command-palette.tsx +111 -25
  70. package/src/components/shared/settings/plugin-manager.tsx +20 -4
  71. package/src/components/shared/settings/section-capability-policy.tsx +105 -0
  72. package/src/components/shared/settings/section-heartbeat.tsx +78 -1
  73. package/src/components/shared/settings/section-orchestrator.tsx +3 -3
  74. package/src/components/shared/settings/section-providers.tsx +1 -1
  75. package/src/components/shared/settings/section-runtime-loop.tsx +5 -5
  76. package/src/components/shared/settings/section-secrets.tsx +6 -6
  77. package/src/components/shared/settings/section-user-preferences.tsx +1 -1
  78. package/src/components/shared/settings/section-voice.tsx +5 -1
  79. package/src/components/shared/settings/section-web-search.tsx +10 -2
  80. package/src/components/shared/settings/settings-page.tsx +244 -56
  81. package/src/components/tasks/approvals-panel.tsx +205 -18
  82. package/src/components/tasks/task-board.tsx +242 -46
  83. package/src/components/usage/metrics-dashboard.tsx +147 -1
  84. package/src/components/wallets/wallet-panel.tsx +17 -5
  85. package/src/components/webhooks/webhook-sheet.tsx +8 -8
  86. package/src/lib/auth.ts +17 -0
  87. package/src/lib/chat-streaming-state.test.ts +108 -0
  88. package/src/lib/chat-streaming-state.ts +108 -0
  89. package/src/lib/chat.ts +1 -1
  90. package/src/lib/{sessions.ts → chats.ts} +28 -18
  91. package/src/lib/openclaw-agent-id.test.ts +14 -0
  92. package/src/lib/openclaw-agent-id.ts +31 -0
  93. package/src/lib/providers/claude-cli.ts +1 -1
  94. package/src/lib/server/agent-assignment.test.ts +112 -0
  95. package/src/lib/server/agent-assignment.ts +169 -0
  96. package/src/lib/server/approval-connector-notify.test.ts +253 -0
  97. package/src/lib/server/approvals-auto-approve.test.ts +205 -0
  98. package/src/lib/server/approvals.ts +483 -75
  99. package/src/lib/server/autonomy-runtime.test.ts +341 -0
  100. package/src/lib/server/browser-state.test.ts +118 -0
  101. package/src/lib/server/browser-state.ts +123 -0
  102. package/src/lib/server/build-llm.test.ts +36 -0
  103. package/src/lib/server/build-llm.ts +11 -4
  104. package/src/lib/server/builtin-plugins.ts +34 -0
  105. package/src/lib/server/capability-router.ts +10 -8
  106. package/src/lib/server/chat-execution-heartbeat.test.ts +40 -0
  107. package/src/lib/server/chat-execution-tool-events.test.ts +134 -0
  108. package/src/lib/server/chat-execution.ts +285 -165
  109. package/src/lib/server/chatroom-health.test.ts +26 -0
  110. package/src/lib/server/chatroom-health.ts +2 -3
  111. package/src/lib/server/chatroom-helpers.test.ts +67 -2
  112. package/src/lib/server/chatroom-helpers.ts +48 -8
  113. package/src/lib/server/connectors/discord.ts +175 -11
  114. package/src/lib/server/connectors/doctor.test.ts +80 -0
  115. package/src/lib/server/connectors/doctor.ts +116 -0
  116. package/src/lib/server/connectors/manager.ts +948 -112
  117. package/src/lib/server/connectors/policy.test.ts +222 -0
  118. package/src/lib/server/connectors/policy.ts +452 -0
  119. package/src/lib/server/connectors/slack.ts +188 -9
  120. package/src/lib/server/connectors/telegram.ts +65 -15
  121. package/src/lib/server/connectors/thread-context.test.ts +44 -0
  122. package/src/lib/server/connectors/thread-context.ts +72 -0
  123. package/src/lib/server/connectors/types.ts +41 -11
  124. package/src/lib/server/cost.ts +34 -1
  125. package/src/lib/server/daemon-state.ts +61 -3
  126. package/src/lib/server/data-dir.ts +13 -0
  127. package/src/lib/server/delegation-jobs.test.ts +140 -0
  128. package/src/lib/server/delegation-jobs.ts +248 -0
  129. package/src/lib/server/document-utils.test.ts +47 -0
  130. package/src/lib/server/document-utils.ts +397 -0
  131. package/src/lib/server/heartbeat-service.ts +14 -40
  132. package/src/lib/server/heartbeat-source.test.ts +22 -0
  133. package/src/lib/server/heartbeat-source.ts +7 -0
  134. package/src/lib/server/identity-continuity.test.ts +77 -0
  135. package/src/lib/server/identity-continuity.ts +127 -0
  136. package/src/lib/server/mailbox-utils.ts +347 -0
  137. package/src/lib/server/main-agent-loop.ts +28 -1103
  138. package/src/lib/server/memory-db.ts +4 -6
  139. package/src/lib/server/memory-tiers.ts +40 -0
  140. package/src/lib/server/openclaw-agent-resolver.test.ts +70 -0
  141. package/src/lib/server/openclaw-agent-resolver.ts +128 -0
  142. package/src/lib/server/openclaw-exec-config.ts +5 -6
  143. package/src/lib/server/openclaw-skills-normalize.test.ts +56 -0
  144. package/src/lib/server/openclaw-skills-normalize.ts +136 -0
  145. package/src/lib/server/openclaw-sync.ts +3 -2
  146. package/src/lib/server/orchestrator-lg.ts +20 -9
  147. package/src/lib/server/orchestrator.ts +7 -7
  148. package/src/lib/server/playwright-proxy.mjs +27 -3
  149. package/src/lib/server/plugins.test.ts +207 -0
  150. package/src/lib/server/plugins.ts +927 -66
  151. package/src/lib/server/provider-health.ts +38 -6
  152. package/src/lib/server/queue.ts +13 -28
  153. package/src/lib/server/scheduler.ts +2 -0
  154. package/src/lib/server/session-archive-memory.test.ts +85 -0
  155. package/src/lib/server/session-archive-memory.ts +230 -0
  156. package/src/lib/server/session-mailbox.ts +8 -18
  157. package/src/lib/server/session-reset-policy.test.ts +99 -0
  158. package/src/lib/server/session-reset-policy.ts +311 -0
  159. package/src/lib/server/session-run-manager.ts +33 -82
  160. package/src/lib/server/session-tools/autonomy-tools.test.ts +105 -0
  161. package/src/lib/server/session-tools/calendar.ts +366 -0
  162. package/src/lib/server/session-tools/canvas.ts +1 -1
  163. package/src/lib/server/session-tools/chatroom.ts +4 -2
  164. package/src/lib/server/session-tools/connector.ts +114 -10
  165. package/src/lib/server/session-tools/context.ts +21 -5
  166. package/src/lib/server/session-tools/crawl.ts +447 -0
  167. package/src/lib/server/session-tools/crud.ts +74 -28
  168. package/src/lib/server/session-tools/delegate-fallback.test.ts +219 -0
  169. package/src/lib/server/session-tools/delegate.ts +497 -24
  170. package/src/lib/server/session-tools/discovery.ts +24 -6
  171. package/src/lib/server/session-tools/document.ts +283 -0
  172. package/src/lib/server/session-tools/edit_file.ts +4 -2
  173. package/src/lib/server/session-tools/email.ts +320 -0
  174. package/src/lib/server/session-tools/extract.ts +137 -0
  175. package/src/lib/server/session-tools/file-normalize.test.ts +93 -0
  176. package/src/lib/server/session-tools/file-send.test.ts +84 -1
  177. package/src/lib/server/session-tools/file.ts +241 -25
  178. package/src/lib/server/session-tools/git.ts +1 -1
  179. package/src/lib/server/session-tools/http.ts +1 -1
  180. package/src/lib/server/session-tools/human-loop.ts +227 -0
  181. package/src/lib/server/session-tools/image-gen.ts +380 -0
  182. package/src/lib/server/session-tools/index.ts +130 -50
  183. package/src/lib/server/session-tools/mailbox.ts +276 -0
  184. package/src/lib/server/session-tools/memory.ts +172 -3
  185. package/src/lib/server/session-tools/monitor.ts +151 -8
  186. package/src/lib/server/session-tools/normalize-tool-args.ts +17 -14
  187. package/src/lib/server/session-tools/openclaw-nodes.ts +1 -1
  188. package/src/lib/server/session-tools/openclaw-workspace.ts +1 -1
  189. package/src/lib/server/session-tools/platform-normalize.test.ts +142 -0
  190. package/src/lib/server/session-tools/platform.ts +148 -7
  191. package/src/lib/server/session-tools/plugin-creator.ts +89 -26
  192. package/src/lib/server/session-tools/primitive-tools.test.ts +257 -0
  193. package/src/lib/server/session-tools/replicate.ts +301 -0
  194. package/src/lib/server/session-tools/sample-ui.ts +1 -1
  195. package/src/lib/server/session-tools/sandbox.ts +4 -2
  196. package/src/lib/server/session-tools/schedule.ts +24 -12
  197. package/src/lib/server/session-tools/session-info.ts +43 -7
  198. package/src/lib/server/session-tools/session-tools-wiring.test.ts +31 -17
  199. package/src/lib/server/session-tools/shell.ts +5 -2
  200. package/src/lib/server/session-tools/subagent.ts +194 -28
  201. package/src/lib/server/session-tools/table.ts +587 -0
  202. package/src/lib/server/session-tools/wallet.ts +42 -12
  203. package/src/lib/server/session-tools/web-browser-config.test.ts +39 -0
  204. package/src/lib/server/session-tools/web.ts +926 -91
  205. package/src/lib/server/storage.ts +255 -16
  206. package/src/lib/server/stream-agent-chat.ts +116 -268
  207. package/src/lib/server/structured-extract.test.ts +72 -0
  208. package/src/lib/server/structured-extract.ts +373 -0
  209. package/src/lib/server/task-mention.test.ts +16 -2
  210. package/src/lib/server/task-mention.ts +61 -10
  211. package/src/lib/server/tool-aliases.ts +66 -18
  212. package/src/lib/server/tool-capability-policy.test.ts +9 -9
  213. package/src/lib/server/tool-capability-policy.ts +38 -27
  214. package/src/lib/server/tool-retry.ts +2 -0
  215. package/src/lib/server/watch-jobs.test.ts +173 -0
  216. package/src/lib/server/watch-jobs.ts +532 -0
  217. package/src/lib/server/ws-hub.ts +5 -3
  218. package/src/lib/tool-definitions.ts +4 -0
  219. package/src/lib/validation/schemas.test.ts +26 -0
  220. package/src/lib/validation/schemas.ts +10 -1
  221. package/src/lib/ws-client.ts +14 -12
  222. package/src/proxy.ts +5 -5
  223. package/src/stores/use-app-store.ts +5 -11
  224. package/src/stores/use-chat-store.ts +38 -9
  225. package/src/types/index.ts +352 -47
  226. package/src/app/api/sessions/[id]/main-loop/route.ts +0 -94
  227. package/src/components/sessions/new-session-sheet.tsx +0 -253
  228. package/src/lib/server/main-session.ts +0 -24
  229. package/src/lib/server/session-run-manager.test.ts +0 -23
  230. /package/src/app/api/{sessions → chats}/[id]/clear/route.ts +0 -0
  231. /package/src/app/api/{sessions → chats}/[id]/deploy/route.ts +0 -0
  232. /package/src/app/api/{sessions → chats}/[id]/devserver/route.ts +0 -0
  233. /package/src/app/api/{sessions → chats}/[id]/edit-resend/route.ts +0 -0
  234. /package/src/app/api/{sessions → chats}/[id]/fork/route.ts +0 -0
  235. /package/src/app/api/{sessions → chats}/[id]/mailbox/route.ts +0 -0
  236. /package/src/app/api/{sessions → chats}/[id]/retry/route.ts +0 -0
  237. /package/src/app/api/{sessions → chats}/heartbeat/route.ts +0 -0
@@ -6,8 +6,10 @@ import { useAppStore } from '@/stores/use-app-store'
6
6
  interface CommandItem {
7
7
  id: string
8
8
  label: string
9
- category: 'agent' | 'chat' | 'task' | 'nav'
10
- onSelect: () => void
9
+ description?: string
10
+ keywords?: string[]
11
+ category: 'agent' | 'chat' | 'task' | 'nav' | 'setting'
12
+ onSelect: () => void | Promise<void>
11
13
  }
12
14
 
13
15
  export function CommandPalette() {
@@ -20,13 +22,22 @@ export function CommandPalette() {
20
22
  const agents = useAppStore((s) => s.agents)
21
23
  const sessions = useAppStore((s) => s.sessions)
22
24
  const tasks = useAppStore((s) => s.tasks)
25
+ const setCurrentAgent = useAppStore((s) => s.setCurrentAgent)
23
26
  const setCurrentSession = useAppStore((s) => s.setCurrentSession)
24
27
  const setActiveView = useAppStore((s) => s.setActiveView)
25
- const setEditingAgentId = useAppStore((s) => s.setEditingAgentId)
26
- const setAgentSheetOpen = useAppStore((s) => s.setAgentSheetOpen)
27
28
  const setEditingTaskId = useAppStore((s) => s.setEditingTaskId)
28
29
  const setTaskSheetOpen = useAppStore((s) => s.setTaskSheetOpen)
29
30
 
31
+ const openSettingsSection = useCallback((tabId?: string, sectionId?: string) => {
32
+ setActiveView('settings')
33
+ setOpen(false)
34
+ window.setTimeout(() => {
35
+ window.dispatchEvent(new CustomEvent('swarmclaw:settings-focus', {
36
+ detail: { tabId, sectionId },
37
+ }))
38
+ }, 80)
39
+ }, [setActiveView])
40
+
30
41
  // Register keyboard shortcut
31
42
  useEffect(() => {
32
43
  const handler = (e: KeyboardEvent) => {
@@ -54,33 +65,89 @@ export function CommandPalette() {
54
65
  const items = useMemo<CommandItem[]>(() => {
55
66
  const result: CommandItem[] = []
56
67
 
57
- // Navigation items
58
- const views = ['agents', 'tasks', 'chatrooms', 'schedules', 'connectors', 'providers', 'secrets', 'settings', 'memory', 'skills'] as const
59
- for (const v of views) {
68
+ const views = [
69
+ { id: 'home', label: 'Home', description: 'Overview and triage', keywords: ['dashboard', 'overview', 'activity'] },
70
+ { id: 'agents', label: 'Agents', description: 'Agent chats and configuration', keywords: ['chat', 'assistant', 'default'] },
71
+ { id: 'tasks', label: 'Tasks', description: 'Task board and approvals', keywords: ['board', 'queue', 'backlog', 'approval'] },
72
+ { id: 'projects', label: 'Projects', description: 'Scoped workspaces for agents and tasks', keywords: ['workspace', 'scope'] },
73
+ { id: 'chatrooms', label: 'Chatrooms', description: 'Shared multi-agent conversations', keywords: ['group', 'room', 'mentions'] },
74
+ { id: 'schedules', label: 'Schedules', description: 'Recurring and timed automations', keywords: ['cron', 'automation', 'interval'] },
75
+ { id: 'connectors', label: 'Connectors', description: 'Bridges to Slack, Discord, Telegram, and more', keywords: ['discord', 'slack', 'telegram', 'whatsapp'] },
76
+ { id: 'memory', label: 'Memory', description: 'Stored agent memory and retrieval', keywords: ['knowledge', 'vector', 'retrieval'] },
77
+ { id: 'knowledge', label: 'Knowledge', description: 'Shared knowledge base', keywords: ['docs', 'entries', 'facts'] },
78
+ { id: 'providers', label: 'Providers', description: 'Model providers and endpoints', keywords: ['openai', 'anthropic', 'ollama', 'endpoint'] },
79
+ { id: 'secrets', label: 'Secrets', description: 'Credentials and encrypted secrets', keywords: ['api key', 'token', 'credential'] },
80
+ { id: 'settings', label: 'Settings', description: 'General app configuration', keywords: ['preferences', 'theme', 'heartbeat'] },
81
+ ] as const
82
+ for (const view of views) {
60
83
  result.push({
61
- id: `nav:${v}`,
62
- label: `Go to ${v}`,
84
+ id: `nav:${view.id}`,
85
+ label: `Go to ${view.label}`,
86
+ description: view.description,
87
+ keywords: [...view.keywords],
63
88
  category: 'nav',
64
- onSelect: () => { setActiveView(v); setOpen(false) },
89
+ onSelect: () => { setActiveView(view.id); setOpen(false) },
65
90
  })
66
91
  }
67
92
 
68
- // Agents
93
+ result.push(
94
+ {
95
+ id: 'setting:default-agent',
96
+ label: 'Default Agent Shortcut',
97
+ description: 'Choose which agent the sidebar shortcut opens',
98
+ keywords: ['main chat', 'default agent', 'shortcut'],
99
+ category: 'setting',
100
+ onSelect: () => openSettingsSection('general', 'user-preferences'),
101
+ },
102
+ {
103
+ id: 'setting:automation',
104
+ label: 'Automation Limits',
105
+ description: 'Heartbeat, autonomy, and delegation controls',
106
+ keywords: ['loops', 'coordination', 'delegation', 'heartbeat', 'automation'],
107
+ category: 'setting',
108
+ onSelect: () => openSettingsSection('agents', 'runtime-loop'),
109
+ },
110
+ {
111
+ id: 'setting:providers',
112
+ label: 'Provider Credentials',
113
+ description: 'Manage providers, endpoints, and secrets',
114
+ keywords: ['openai', 'anthropic', 'api keys', 'credentials', 'providers'],
115
+ category: 'setting',
116
+ onSelect: () => openSettingsSection('integrations', 'providers'),
117
+ },
118
+ {
119
+ id: 'setting:voice',
120
+ label: 'Voice & Search',
121
+ description: 'Voice output and web search defaults',
122
+ keywords: ['voice', 'tts', 'web search', 'search'],
123
+ category: 'setting',
124
+ onSelect: () => openSettingsSection('memory', 'voice'),
125
+ },
126
+ )
127
+
69
128
  for (const agent of Object.values(agents)) {
70
129
  result.push({
71
130
  id: `agent:${agent.id}`,
72
131
  label: agent.name,
132
+ description: `Open ${agent.name}'s chat`,
133
+ keywords: [agent.provider, agent.model, agent.description || ''].filter(Boolean),
73
134
  category: 'agent',
74
- onSelect: () => { setEditingAgentId(agent.id); setAgentSheetOpen(true); setOpen(false) },
135
+ onSelect: async () => {
136
+ await setCurrentAgent(agent.id)
137
+ setActiveView('agents')
138
+ setOpen(false)
139
+ },
75
140
  })
76
141
  }
77
142
 
78
143
  // Chats (sessions)
79
144
  for (const session of Object.values(sessions)) {
80
- if (session.name === '__main__') continue
145
+ const sessionAgent = session.agentId ? agents[session.agentId] : null
81
146
  result.push({
82
147
  id: `chat:${session.id}`,
83
148
  label: session.name || 'Untitled chat',
149
+ description: sessionAgent ? `Recent chat with ${sessionAgent.name}` : 'Direct model chat',
150
+ keywords: [session.provider, session.model, sessionAgent?.name || ''].filter(Boolean),
84
151
  category: 'chat',
85
152
  onSelect: () => { setCurrentSession(session.id); setActiveView('agents'); setOpen(false) },
86
153
  })
@@ -92,19 +159,25 @@ export function CommandPalette() {
92
159
  result.push({
93
160
  id: `task:${task.id}`,
94
161
  label: task.title,
162
+ description: `${task.status.charAt(0).toUpperCase() + task.status.slice(1)} task`,
163
+ keywords: [task.status, task.agentId || ''].filter(Boolean),
95
164
  category: 'task',
96
165
  onSelect: () => { setEditingTaskId(task.id); setTaskSheetOpen(true); setOpen(false) },
97
166
  })
98
167
  }
99
168
 
100
169
  return result
101
- }, [agents, sessions, tasks, setActiveView, setCurrentSession, setEditingAgentId, setAgentSheetOpen, setEditingTaskId, setTaskSheetOpen])
170
+ }, [agents, openSettingsSection, sessions, setActiveView, setCurrentAgent, setCurrentSession, setEditingTaskId, setTaskSheetOpen, tasks])
102
171
 
103
172
  const filtered = useMemo(() => {
104
173
  if (!query.trim()) return items.slice(0, 20)
105
174
  const q = query.toLowerCase()
106
175
  return items
107
- .filter((item) => item.label.toLowerCase().includes(q))
176
+ .filter((item) =>
177
+ item.label.toLowerCase().includes(q)
178
+ || item.description?.toLowerCase().includes(q)
179
+ || item.keywords?.some((keyword) => keyword.toLowerCase().includes(q)),
180
+ )
108
181
  .slice(0, 20)
109
182
  }, [items, query])
110
183
 
@@ -133,7 +206,7 @@ export function CommandPalette() {
133
206
 
134
207
  if (!open) return null
135
208
 
136
- const categoryLabel = { agent: 'Agents', chat: 'Chats', task: 'Tasks', nav: 'Navigation' } as const
209
+ const categoryLabel = { agent: 'Agents', chat: 'Chats', task: 'Tasks', nav: 'Navigation', setting: 'Settings' } as const
137
210
  const categoryIcon = {
138
211
  agent: (
139
212
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
@@ -155,6 +228,12 @@ export function CommandPalette() {
155
228
  <circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" />
156
229
  </svg>
157
230
  ),
231
+ setting: (
232
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
233
+ <circle cx="12" cy="12" r="3" />
234
+ <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
235
+ </svg>
236
+ ),
158
237
  }
159
238
 
160
239
  // Group by category
@@ -184,14 +263,14 @@ export function CommandPalette() {
184
263
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="text-text-3 shrink-0 relative z-10">
185
264
  <circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" />
186
265
  </svg>
187
- <input
188
- ref={inputRef}
189
- value={query}
190
- onChange={(e) => setQuery(e.target.value)}
191
- onKeyDown={handleKeyDown}
192
- placeholder="Search agents, chats, tasks..."
193
- className="flex-1 bg-transparent border-none outline-none text-[14px] text-text-1 placeholder:text-text-3/50"
194
- />
266
+ <input
267
+ ref={inputRef}
268
+ value={query}
269
+ onChange={(e) => setQuery(e.target.value)}
270
+ onKeyDown={handleKeyDown}
271
+ placeholder="Search chats, agents, tasks, settings..."
272
+ className="flex-1 bg-transparent border-none outline-none text-[14px] text-text-1 placeholder:text-text-3/50"
273
+ />
195
274
  <kbd className="hidden md:inline-flex items-center px-1.5 py-0.5 rounded-[6px] bg-white/[0.06] text-[11px] text-text-3 font-500">
196
275
  esc
197
276
  </kbd>
@@ -221,7 +300,14 @@ export function CommandPalette() {
221
300
  <div className="absolute left-0 top-1 bottom-1 w-1 rounded-r-full bg-accent-bright" style={{ animation: 'spring-in 0.3s var(--ease-spring)' }} />
222
301
  )}
223
302
  <span className="shrink-0 text-text-3">{categoryIcon[item.category as keyof typeof categoryIcon]}</span>
224
- <span className="text-[13px] font-500 truncate">{item.label}</span>
303
+ <div className="min-w-0 flex-1">
304
+ <div className="text-[13px] font-500 truncate">{item.label}</div>
305
+ {item.description && (
306
+ <div className={`text-[11px] truncate ${idx === selectedIndex ? 'text-accent-bright/75' : 'text-text-3/55'}`}>
307
+ {item.description}
308
+ </div>
309
+ )}
310
+ </div>
225
311
  </button>
226
312
  )
227
313
  })}
@@ -129,8 +129,8 @@ export function PluginManager() {
129
129
 
130
130
  const { corePlugins, installedPlugins } = useMemo(() => {
131
131
  return {
132
- corePlugins: plugins.filter(p => p.source === 'local'),
133
- installedPlugins: plugins.filter(p => p.source !== 'local')
132
+ corePlugins: plugins.filter(p => p.isBuiltin),
133
+ installedPlugins: plugins.filter(p => !p.isBuiltin)
134
134
  }
135
135
  }, [plugins])
136
136
 
@@ -155,6 +155,22 @@ export function PluginManager() {
155
155
  </div>
156
156
  <div className="text-[11px] font-mono text-text-3/40 truncate">{p.filename}</div>
157
157
  {p.description && <div className="text-[12px] text-text-3/70 mt-1 line-clamp-1">{p.description}</div>}
158
+ {p.hasDependencyManifest && (
159
+ <div className="mt-1.5 flex items-center gap-2 text-[10px] font-700 uppercase tracking-[0.08em]">
160
+ <span className="px-1.5 py-0.5 rounded bg-white/[0.04] text-text-3/70">
161
+ {p.dependencyCount ?? 0} deps
162
+ </span>
163
+ <span className={`px-1.5 py-0.5 rounded ${
164
+ p.dependencyInstallStatus === 'installed'
165
+ ? 'bg-emerald-500/10 text-emerald-400'
166
+ : p.dependencyInstallStatus === 'error'
167
+ ? 'bg-red-500/10 text-red-400'
168
+ : 'bg-amber-500/10 text-amber-400'
169
+ }`}>
170
+ {p.dependencyInstallStatus || 'ready'}
171
+ </span>
172
+ </div>
173
+ )}
158
174
  {p.autoDisabled && (
159
175
  <div className="text-[11px] text-amber-400/90 mt-1.5 p-2 rounded-[8px] bg-amber-500/[0.03] border border-amber-500/10">
160
176
  {p.lastFailureStage ? `Error at ${p.lastFailureStage}:` : 'Last error:'} {p.lastFailureError}
@@ -163,7 +179,7 @@ export function PluginManager() {
163
179
  </div>
164
180
 
165
181
  <div className="flex items-center gap-2">
166
- {p.source !== 'local' && (
182
+ {!p.isBuiltin && (
167
183
  <div className="flex items-center opacity-0 group-hover:opacity-100 transition-opacity">
168
184
  <button
169
185
  onClick={() => handleUpdateOne(p.filename)}
@@ -409,7 +425,7 @@ export function PluginManager() {
409
425
  </div>
410
426
  )}
411
427
  <p className="text-[11px] text-text-3/40 mt-6 leading-relaxed text-center italic">
412
- SwarmClaw supports standalone CommonJS plugins and OpenClaw activate/deactivate formats.
428
+ SwarmClaw supports `.js` / `.mjs` plugins, native SwarmClaw hooks/tools, and OpenClaw activate/register formats.
413
429
  </p>
414
430
  </div>
415
431
  )}
@@ -1,8 +1,20 @@
1
1
  'use client'
2
2
 
3
+ import type { ApprovalCategory } from '@/types'
3
4
  import type { SettingsSectionProps } from './types'
4
5
 
6
+ const APPROVAL_CATEGORY_OPTIONS: Array<{ id: ApprovalCategory; label: string; description: string }> = [
7
+ { id: 'tool_access', label: 'Plugin Access', description: 'Auto-enable requested plugins for a chat.' },
8
+ { id: 'plugin_scaffold', label: 'Plugin Scaffold', description: 'Auto-create plugin files requested by agents.' },
9
+ { id: 'plugin_install', label: 'Plugin Install', description: 'Auto-install plugins from approved URLs.' },
10
+ { id: 'human_loop', label: 'Human Approval Requests', description: 'Auto-approve ask-human approval prompts.' },
11
+ { id: 'wallet_transfer', label: 'Wallet Transfers', description: 'Auto-approve wallet send requests. High risk.' },
12
+ { id: 'task_tool', label: 'Task Tool Calls', description: 'Reserved for task-level approval flows.' },
13
+ ]
14
+
5
15
  export function CapabilityPolicySection({ appSettings, patchSettings, inputClass }: SettingsSectionProps) {
16
+ const autoApproved = new Set(appSettings.approvalAutoApproveCategories || [])
17
+
6
18
  return (
7
19
  <div className="mb-10">
8
20
  <h3 className="font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
@@ -34,6 +46,24 @@ export function CapabilityPolicySection({ appSettings, patchSettings, inputClass
34
46
  </div>
35
47
 
36
48
  <div className="grid grid-cols-1 gap-4">
49
+ <div className="rounded-[12px] border border-white/[0.06] bg-bg px-4 py-4">
50
+ <div className="flex items-center justify-between gap-4">
51
+ <div>
52
+ <div className="text-[12px] font-600 text-text-2">Platform Approvals</div>
53
+ <p className="text-[11px] text-text-3/60 mt-1 leading-relaxed">
54
+ Turn this off to auto-approve every approval request across the platform for maximum autonomy. Audit records are still kept.
55
+ </p>
56
+ </div>
57
+ <button
58
+ onClick={() => patchSettings({ approvalsEnabled: !(appSettings.approvalsEnabled ?? true) })}
59
+ className={`relative w-10 h-[22px] rounded-full transition-colors duration-200 cursor-pointer ${(appSettings.approvalsEnabled ?? true) ? 'bg-accent' : 'bg-white/[0.12]'}`}
60
+ aria-label="Toggle platform approvals"
61
+ >
62
+ <span className={`absolute top-[3px] left-[3px] w-4 h-4 rounded-full bg-white transition-transform duration-200 ${(appSettings.approvalsEnabled ?? true) ? 'translate-x-[18px]' : ''}`} />
63
+ </button>
64
+ </div>
65
+ </div>
66
+
37
67
  <div>
38
68
  <label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Blocked Categories</label>
39
69
  <input
@@ -86,6 +116,81 @@ export function CapabilityPolicySection({ appSettings, patchSettings, inputClass
86
116
  />
87
117
  <p className="text-[11px] text-text-3/60 mt-2">Use this to re-allow specific tool families when running in strict mode.</p>
88
118
  </div>
119
+
120
+ <div>
121
+ <label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Auto-Approve Workflow Requests</label>
122
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-2">
123
+ {APPROVAL_CATEGORY_OPTIONS.map((option) => {
124
+ const checked = autoApproved.has(option.id)
125
+ return (
126
+ <label
127
+ key={option.id}
128
+ className={`rounded-[12px] border px-3 py-3 cursor-pointer transition-all ${
129
+ checked
130
+ ? 'border-accent-bright/30 bg-accent-soft/60'
131
+ : 'border-white/[0.06] bg-bg hover:bg-surface-2'
132
+ }`}
133
+ >
134
+ <div className="flex items-start gap-3">
135
+ <input
136
+ type="checkbox"
137
+ checked={checked}
138
+ onChange={(e) => {
139
+ const next = new Set(appSettings.approvalAutoApproveCategories || [])
140
+ if (e.target.checked) next.add(option.id)
141
+ else next.delete(option.id)
142
+ patchSettings({ approvalAutoApproveCategories: [...next] })
143
+ }}
144
+ className="mt-0.5"
145
+ />
146
+ <div>
147
+ <div className="text-[12px] font-600 text-text-2">{option.label}</div>
148
+ <p className="text-[11px] text-text-3/60 mt-1 leading-relaxed">{option.description}</p>
149
+ </div>
150
+ </div>
151
+ </label>
152
+ )
153
+ })}
154
+ </div>
155
+ <p className="text-[11px] text-text-3/60 mt-2">
156
+ Auto-approved categories execute immediately instead of waiting in the Approvals queue. Leave high-risk categories off unless the user explicitly wants fully autonomous execution.
157
+ </p>
158
+ </div>
159
+
160
+ <div className="rounded-[12px] border border-white/[0.06] bg-bg px-4 py-4">
161
+ <div className="flex items-center justify-between gap-4">
162
+ <div>
163
+ <div className="text-[12px] font-600 text-text-2">Connector Approval Reminders</div>
164
+ <p className="text-[11px] text-text-3/60 mt-1 leading-relaxed">
165
+ If an approval sits too long, let the agent send a one-time reminder over an active connector conversation it already has access to.
166
+ </p>
167
+ </div>
168
+ <button
169
+ onClick={() => patchSettings({ approvalConnectorNotifyEnabled: !(appSettings.approvalConnectorNotifyEnabled ?? true) })}
170
+ className={`relative w-10 h-[22px] rounded-full transition-colors duration-200 cursor-pointer ${(appSettings.approvalConnectorNotifyEnabled ?? true) ? 'bg-accent' : 'bg-white/[0.12]'}`}
171
+ aria-label="Toggle connector approval reminders"
172
+ >
173
+ <span className={`absolute top-[3px] left-[3px] w-4 h-4 rounded-full bg-white transition-transform duration-200 ${(appSettings.approvalConnectorNotifyEnabled ?? true) ? 'translate-x-[18px]' : ''}`} />
174
+ </button>
175
+ </div>
176
+ <div className="mt-4 max-w-[220px]">
177
+ <label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Reminder Delay (Sec)</label>
178
+ <input
179
+ type="number"
180
+ min={30}
181
+ max={86400}
182
+ value={appSettings.approvalConnectorNotifyDelaySec ?? 300}
183
+ onChange={(e) => {
184
+ const next = Number.parseInt(e.target.value, 10)
185
+ patchSettings({
186
+ approvalConnectorNotifyDelaySec: Number.isFinite(next) ? Math.max(30, Math.min(86400, next)) : 300,
187
+ })
188
+ }}
189
+ className={inputClass}
190
+ style={{ fontFamily: 'inherit' }}
191
+ />
192
+ </div>
193
+ </div>
89
194
  </div>
90
195
  </div>
91
196
  </div>
@@ -3,12 +3,17 @@
3
3
  import { useState } from 'react'
4
4
  import { useAppStore } from '@/stores/use-app-store'
5
5
  import { api } from '@/lib/api-client'
6
+ import type { SessionResetMode } from '@/types'
6
7
  import type { SettingsSectionProps } from './types'
7
8
 
8
9
  export function HeartbeatSection({ appSettings, patchSettings, inputClass }: SettingsSectionProps) {
9
10
  const loadSessions = useAppStore((s) => s.loadSessions)
10
11
  const [disablingHeartbeats, setDisablingHeartbeats] = useState(false)
11
12
  const [heartbeatBulkNotice, setHeartbeatBulkNotice] = useState('')
13
+ const parseResetMode = (value: string): SessionResetMode | null => {
14
+ if (value === 'idle' || value === 'daily') return value
15
+ return null
16
+ }
12
17
 
13
18
  const handleDisableAllHeartbeats = async () => {
14
19
  if (disablingHeartbeats) return
@@ -20,7 +25,7 @@ export function HeartbeatSection({ appSettings, patchSettings, inputClass }: Set
20
25
  updatedSessions: number
21
26
  cancelledQueued: number
22
27
  abortedRunning: number
23
- }>('POST', '/sessions/heartbeat', { action: 'disable_all' })
28
+ }>('POST', '/chats/heartbeat', { action: 'disable_all' })
24
29
  await loadSessions()
25
30
  setHeartbeatBulkNotice(
26
31
  `Stopped heartbeat on ${result.updatedSessions} session(s); cancelled ${result.cancelledQueued} queued run(s), aborted ${result.abortedRunning} running run(s).`,
@@ -112,6 +117,78 @@ export function HeartbeatSection({ appSettings, patchSettings, inputClass }: Set
112
117
  </div>
113
118
  </div>
114
119
 
120
+ <div className="border-t border-white/[0.06] pt-5 mt-5">
121
+ <h4 className="font-display text-[11px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
122
+ Session Reset Defaults
123
+ </h4>
124
+ <p className="text-[11px] text-text-3/60 mb-4">
125
+ Freshness policy inherited by new sessions unless overridden on the agent or session itself.
126
+ </p>
127
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-3 mb-3">
128
+ <div>
129
+ <label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Reset Mode</label>
130
+ <select
131
+ value={appSettings.sessionResetMode || ''}
132
+ onChange={(e) => patchSettings({ sessionResetMode: parseResetMode(e.target.value) })}
133
+ className={inputClass}
134
+ style={{ fontFamily: 'inherit' }}
135
+ >
136
+ <option value="">Use built-in defaults</option>
137
+ <option value="idle">Idle</option>
138
+ <option value="daily">Daily</option>
139
+ </select>
140
+ </div>
141
+ <div>
142
+ <label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Idle Timeout (sec)</label>
143
+ <input
144
+ type="number"
145
+ min={0}
146
+ value={appSettings.sessionIdleTimeoutSec ?? ''}
147
+ onChange={(e) => patchSettings({ sessionIdleTimeoutSec: e.target.value ? Number.parseInt(e.target.value, 10) : null })}
148
+ placeholder="43200"
149
+ className={inputClass}
150
+ style={{ fontFamily: 'inherit' }}
151
+ />
152
+ </div>
153
+ </div>
154
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-3">
155
+ <div>
156
+ <label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Max Age (sec)</label>
157
+ <input
158
+ type="number"
159
+ min={0}
160
+ value={appSettings.sessionMaxAgeSec ?? ''}
161
+ onChange={(e) => patchSettings({ sessionMaxAgeSec: e.target.value ? Number.parseInt(e.target.value, 10) : null })}
162
+ placeholder="604800"
163
+ className={inputClass}
164
+ style={{ fontFamily: 'inherit' }}
165
+ />
166
+ </div>
167
+ <div>
168
+ <label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Daily Reset Time</label>
169
+ <input
170
+ type="text"
171
+ value={appSettings.sessionDailyResetAt || ''}
172
+ onChange={(e) => patchSettings({ sessionDailyResetAt: e.target.value || null })}
173
+ placeholder="04:00"
174
+ className={inputClass}
175
+ style={{ fontFamily: 'inherit' }}
176
+ />
177
+ </div>
178
+ <div>
179
+ <label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Reset Timezone</label>
180
+ <input
181
+ type="text"
182
+ value={appSettings.sessionResetTimezone || ''}
183
+ onChange={(e) => patchSettings({ sessionResetTimezone: e.target.value || null })}
184
+ placeholder="UTC"
185
+ className={inputClass}
186
+ style={{ fontFamily: 'inherit' }}
187
+ />
188
+ </div>
189
+ </div>
190
+ </div>
191
+
115
192
  <div>
116
193
  <div className="flex items-center gap-2.5">
117
194
  <button
@@ -27,10 +27,10 @@ export function OrchestratorSection({ appSettings, patchSettings, inputClass }:
27
27
  return (
28
28
  <div className="mb-10">
29
29
  <h3 className="font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
30
- Orchestrator Engine
30
+ Coordination Engine
31
31
  </h3>
32
32
  <p className="text-[12px] text-text-3 mb-5">
33
- The LLM provider used by orchestrators for tool calling, agent generation, and task delegation.
33
+ The LLM provider used when agents coordinate delegation, tool calling, and automation-heavy runs.
34
34
  </p>
35
35
 
36
36
  <div className="p-6 rounded-[18px] bg-surface border border-white/[0.06]">
@@ -53,7 +53,7 @@ export function OrchestratorSection({ appSettings, patchSettings, inputClass }:
53
53
  </div>
54
54
  {lgProviders.length === 0 && (
55
55
  <p className="text-[12px] text-text-3/60 mb-5">
56
- No orchestration-compatible providers available. Add an API provider in Providers.
56
+ No coordination-compatible providers available. Add an API provider in Providers.
57
57
  </p>
58
58
  )}
59
59
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { useState } from 'react'
4
4
  import { useAppStore } from '@/stores/use-app-store'
5
- import { createCredential, deleteCredential } from '@/lib/sessions'
5
+ import { createCredential, deleteCredential } from '@/lib/chats'
6
6
  import { toast } from 'sonner'
7
7
  import type { ProviderType } from '@/types'
8
8
  import type { SettingsSectionProps } from './types'
@@ -24,7 +24,7 @@ export function RuntimeLoopSection({ appSettings, patchSettings, inputClass }: S
24
24
  Runtime &amp; Loop Controls
25
25
  </h3>
26
26
  <p className="text-[12px] text-text-3 mb-5">
27
- Choose bounded or ongoing agent loops and set safety guards for task execution.
27
+ Control how far agents can run on their own and set safety guards for delegation and tool execution.
28
28
  </p>
29
29
  <div className="p-6 rounded-[18px] bg-surface border border-white/[0.06]">
30
30
  <label className="flex items-center gap-1.5 font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-3">Loop Mode <HintTip text="Bounded = fixed max steps. Ongoing = runs until the task completes (with a safety cap)" /></label>
@@ -64,8 +64,8 @@ export function RuntimeLoopSection({ appSettings, patchSettings, inputClass }: S
64
64
  style={{ fontFamily: 'inherit' }}
65
65
  />
66
66
  </div>
67
- <div>
68
- <label className="flex items-center gap-1.5 font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Orchestrator Steps <HintTip text="Maximum tool calls the orchestrator can make when coordinating multiple agents" /></label>
67
+ <div>
68
+ <label className="flex items-center gap-1.5 font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Coordination Steps <HintTip text="Maximum tool calls an agent can make while coordinating multiple delegated agents" /></label>
69
69
  <input
70
70
  type="number"
71
71
  min={1}
@@ -79,8 +79,8 @@ export function RuntimeLoopSection({ appSettings, patchSettings, inputClass }: S
79
79
  style={{ fontFamily: 'inherit' }}
80
80
  />
81
81
  </div>
82
- <div>
83
- <label className="flex items-center gap-1.5 font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Legacy Turns <HintTip text="Max conversation turns for older orchestration mode increase if agents get cut off mid-task" /></label>
82
+ <div>
83
+ <label className="flex items-center gap-1.5 font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Legacy Turns <HintTip text="Compatibility limit for older coordination flows that still rely on turn-based execution" /></label>
84
84
  <input
85
85
  type="number"
86
86
  min={1}
@@ -53,7 +53,7 @@ export function SecretsSection({ appSettings, inputClass }: SettingsSectionProps
53
53
  }
54
54
  }
55
55
 
56
- const orchestrators = Object.values(agents).filter((p) => p.isOrchestrator)
56
+ const selectableAgents = Object.values(agents)
57
57
  const secretList = Object.entries(secrets).map(([rowId, secret]) => ({ ...secret, rowId }))
58
58
 
59
59
  return (
@@ -62,7 +62,7 @@ export function SecretsSection({ appSettings, inputClass }: SettingsSectionProps
62
62
  Service Credentials
63
63
  </h3>
64
64
  <p className="text-[12px] text-text-3 mb-5">
65
- Credentials for external services (Gmail, APIs, etc.) that orchestrators can use during task execution.
65
+ Credentials for external services (Gmail, APIs, etc.) that agents can use during task execution.
66
66
  </p>
67
67
 
68
68
  {secretList.length > 0 && (
@@ -78,7 +78,7 @@ export function SecretsSection({ appSettings, inputClass }: SettingsSectionProps
78
78
  ? 'bg-emerald-500/10 text-emerald-400'
79
79
  : 'bg-amber-500/10 text-amber-400'
80
80
  }`}>
81
- {secret.scope === 'global' ? 'All orchestrators' : `${secret.agentIds.length} orchestrator(s)`}
81
+ {secret.scope === 'global' ? 'All eligible agents' : `${secret.agentIds.length} agent(s)`}
82
82
  </span>
83
83
  </div>
84
84
  </div>
@@ -106,14 +106,14 @@ export function SecretsSection({ appSettings, inputClass }: SettingsSectionProps
106
106
  <label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Scope</label>
107
107
  <div className="flex p-1 rounded-[12px] bg-bg border border-white/[0.06]">
108
108
  {(['global', 'agent'] as const).map((s) => (
109
- <button key={s} onClick={() => setSecretScope(s)} className={`flex-1 py-2.5 rounded-[10px] text-center cursor-pointer transition-all text-[13px] font-600 capitalize ${secretScope === s ? 'bg-accent-soft text-accent-bright' : 'bg-transparent text-text-3 hover:text-text-2'}`} style={{ fontFamily: 'inherit' }}>{s === 'global' ? 'All Orchestrators' : 'Specific'}</button>
109
+ <button key={s} onClick={() => setSecretScope(s)} className={`flex-1 py-2.5 rounded-[10px] text-center cursor-pointer transition-all text-[13px] font-600 capitalize ${secretScope === s ? 'bg-accent-soft text-accent-bright' : 'bg-transparent text-text-3 hover:text-text-2'}`} style={{ fontFamily: 'inherit' }}>{s === 'global' ? 'All Eligible Agents' : 'Specific Agents'}</button>
110
110
  ))}
111
111
  </div>
112
112
  </div>
113
113
 
114
- {secretScope === 'agent' && orchestrators.length > 0 && (
114
+ {secretScope === 'agent' && selectableAgents.length > 0 && (
115
115
  <div className="flex flex-wrap gap-2">
116
- {orchestrators.map((p) => (
116
+ {selectableAgents.map((p) => (
117
117
  <button key={p.id} onClick={() => setSecretAgentIds((prev) => prev.includes(p.id) ? prev.filter((x) => x !== p.id) : [...prev, p.id])} className={`px-3 py-2 rounded-[10px] text-[12px] font-600 cursor-pointer transition-all border ${secretAgentIds.includes(p.id) ? 'bg-accent-soft border-accent-bright/25 text-accent-bright' : 'bg-bg border-white/[0.06] text-text-3 hover:text-text-2'}`} style={{ fontFamily: 'inherit' }}>{p.name}</button>
118
118
  ))}
119
119
  </div>
@@ -47,7 +47,7 @@ export function UserPreferencesSection({ appSettings, patchSettings, inputClass
47
47
  <div className="mt-6">
48
48
  <label className="text-[12px] font-600 text-text-2 block mb-1.5">Default Agent</label>
49
49
  <p className="text-[11px] text-text-3/60 mb-2">
50
- The agent that opens automatically when you start the app or click Main Chat.
50
+ The agent that opens automatically when you start the app or use the default-agent shortcut.
51
51
  </p>
52
52
  <div className="flex flex-wrap gap-2">
53
53
  <button