@swarmclawai/swarmclaw 0.6.7 → 0.7.0

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 (203) hide show
  1. package/README.md +82 -39
  2. package/next.config.ts +31 -6
  3. package/package.json +3 -2
  4. package/src/app/api/agents/[id]/thread/route.ts +1 -0
  5. package/src/app/api/agents/route.ts +19 -5
  6. package/src/app/api/approvals/route.ts +22 -0
  7. package/src/app/api/chatrooms/[id]/chat/route.ts +4 -0
  8. package/src/app/api/clawhub/install/route.ts +2 -2
  9. package/src/app/api/eval/run/route.ts +37 -0
  10. package/src/app/api/eval/scenarios/route.ts +24 -0
  11. package/src/app/api/eval/suite/route.ts +29 -0
  12. package/src/app/api/mcp-servers/[id]/conformance/route.ts +26 -0
  13. package/src/app/api/mcp-servers/[id]/invoke/route.ts +81 -0
  14. package/src/app/api/memory/graph/route.ts +46 -0
  15. package/src/app/api/memory/route.ts +36 -5
  16. package/src/app/api/notifications/route.ts +3 -0
  17. package/src/app/api/plugins/install/route.ts +57 -5
  18. package/src/app/api/plugins/marketplace/route.ts +73 -22
  19. package/src/app/api/plugins/route.ts +61 -1
  20. package/src/app/api/plugins/ui/route.ts +34 -0
  21. package/src/app/api/sessions/[id]/checkpoints/route.ts +31 -0
  22. package/src/app/api/sessions/[id]/restore/route.ts +36 -0
  23. package/src/app/api/settings/route.ts +62 -0
  24. package/src/app/api/setup/doctor/route.ts +22 -5
  25. package/src/app/api/souls/[id]/route.ts +65 -0
  26. package/src/app/api/souls/route.ts +70 -0
  27. package/src/app/api/tasks/[id]/approve/route.ts +4 -3
  28. package/src/app/api/tasks/[id]/route.ts +16 -3
  29. package/src/app/api/tasks/route.ts +10 -2
  30. package/src/app/api/usage/route.ts +9 -2
  31. package/src/app/globals.css +27 -0
  32. package/src/app/page.tsx +10 -5
  33. package/src/cli/index.js +37 -0
  34. package/src/components/activity/activity-feed.tsx +9 -2
  35. package/src/components/agents/agent-avatar.tsx +5 -1
  36. package/src/components/agents/agent-card.tsx +55 -9
  37. package/src/components/agents/agent-sheet.tsx +112 -34
  38. package/src/components/agents/inspector-panel.tsx +1 -1
  39. package/src/components/agents/soul-library-picker.tsx +84 -13
  40. package/src/components/auth/access-key-gate.tsx +63 -54
  41. package/src/components/auth/user-picker.tsx +37 -32
  42. package/src/components/chat/activity-moment.tsx +2 -0
  43. package/src/components/chat/chat-area.tsx +11 -0
  44. package/src/components/chat/chat-header.tsx +69 -25
  45. package/src/components/chat/chat-tool-toggles.tsx +2 -2
  46. package/src/components/chat/checkpoint-timeline.tsx +112 -0
  47. package/src/components/chat/code-block.tsx +3 -1
  48. package/src/components/chat/exec-approval-card.tsx +8 -1
  49. package/src/components/chat/message-bubble.tsx +164 -4
  50. package/src/components/chat/message-list.tsx +46 -4
  51. package/src/components/chat/session-approval-card.tsx +80 -0
  52. package/src/components/chat/session-debug-panel.tsx +106 -84
  53. package/src/components/chat/streaming-bubble.tsx +6 -5
  54. package/src/components/chat/task-approval-card.tsx +78 -0
  55. package/src/components/chat/thinking-indicator.tsx +48 -12
  56. package/src/components/chat/tool-call-bubble.tsx +3 -0
  57. package/src/components/chat/tool-request-banner.tsx +39 -20
  58. package/src/components/chatrooms/chatroom-list.tsx +11 -4
  59. package/src/components/chatrooms/chatroom-sheet.tsx +7 -2
  60. package/src/components/connectors/connector-list.tsx +33 -11
  61. package/src/components/connectors/connector-sheet.tsx +37 -7
  62. package/src/components/home/home-view.tsx +54 -24
  63. package/src/components/input/chat-input.tsx +22 -1
  64. package/src/components/knowledge/knowledge-list.tsx +17 -18
  65. package/src/components/knowledge/knowledge-sheet.tsx +9 -5
  66. package/src/components/layout/app-layout.tsx +87 -19
  67. package/src/components/mcp-servers/mcp-server-list.tsx +352 -50
  68. package/src/components/mcp-servers/mcp-server-sheet.tsx +25 -9
  69. package/src/components/memory/memory-browser.tsx +73 -45
  70. package/src/components/memory/memory-graph-view.tsx +203 -0
  71. package/src/components/memory/memory-list.tsx +20 -13
  72. package/src/components/plugins/plugin-list.tsx +214 -60
  73. package/src/components/plugins/plugin-sheet.tsx +119 -24
  74. package/src/components/projects/project-list.tsx +17 -9
  75. package/src/components/providers/provider-list.tsx +21 -6
  76. package/src/components/providers/provider-sheet.tsx +42 -25
  77. package/src/components/runs/run-list.tsx +17 -13
  78. package/src/components/schedules/schedule-card.tsx +10 -3
  79. package/src/components/schedules/schedule-list.tsx +2 -2
  80. package/src/components/schedules/schedule-sheet.tsx +28 -9
  81. package/src/components/secrets/secret-sheet.tsx +7 -2
  82. package/src/components/secrets/secrets-list.tsx +18 -5
  83. package/src/components/sessions/new-session-sheet.tsx +183 -376
  84. package/src/components/sessions/session-card.tsx +10 -2
  85. package/src/components/settings/gateway-connection-panel.tsx +9 -8
  86. package/src/components/shared/command-palette.tsx +13 -5
  87. package/src/components/shared/empty-state.tsx +20 -8
  88. package/src/components/shared/hint-tip.tsx +31 -0
  89. package/src/components/shared/notification-center.tsx +134 -86
  90. package/src/components/shared/profile-sheet.tsx +4 -0
  91. package/src/components/shared/settings/plugin-manager.tsx +360 -135
  92. package/src/components/shared/settings/section-capability-policy.tsx +3 -3
  93. package/src/components/shared/settings/section-runtime-loop.tsx +149 -4
  94. package/src/components/skills/clawhub-browser.tsx +1 -0
  95. package/src/components/skills/skill-list.tsx +31 -12
  96. package/src/components/skills/skill-sheet.tsx +20 -7
  97. package/src/components/tasks/approvals-panel.tsx +224 -0
  98. package/src/components/tasks/task-board.tsx +20 -12
  99. package/src/components/tasks/task-card.tsx +21 -7
  100. package/src/components/tasks/task-column.tsx +4 -3
  101. package/src/components/tasks/task-list.tsx +1 -1
  102. package/src/components/tasks/task-sheet.tsx +130 -1
  103. package/src/components/ui/dialog.tsx +1 -0
  104. package/src/components/ui/sheet.tsx +1 -0
  105. package/src/components/usage/metrics-dashboard.tsx +72 -48
  106. package/src/components/wallets/wallet-panel.tsx +65 -41
  107. package/src/components/wallets/wallet-section.tsx +9 -3
  108. package/src/components/webhooks/webhook-list.tsx +21 -12
  109. package/src/components/webhooks/webhook-sheet.tsx +13 -3
  110. package/src/lib/approval-display.test.ts +45 -0
  111. package/src/lib/approval-display.ts +62 -0
  112. package/src/lib/clipboard.ts +38 -0
  113. package/src/lib/memory.ts +8 -0
  114. package/src/lib/providers/claude-cli.ts +5 -3
  115. package/src/lib/providers/index.ts +67 -21
  116. package/src/lib/runtime-loop.ts +3 -2
  117. package/src/lib/server/approvals.ts +150 -0
  118. package/src/lib/server/chat-execution.ts +319 -74
  119. package/src/lib/server/chatroom-helpers.ts +63 -5
  120. package/src/lib/server/chatroom-orchestration.ts +74 -0
  121. package/src/lib/server/clawhub-client.ts +82 -6
  122. package/src/lib/server/connectors/manager.ts +27 -1
  123. package/src/lib/server/context-manager.ts +132 -50
  124. package/src/lib/server/cost.test.ts +73 -0
  125. package/src/lib/server/cost.ts +165 -34
  126. package/src/lib/server/daemon-state.ts +112 -1
  127. package/src/lib/server/data-dir.ts +18 -1
  128. package/src/lib/server/eval/runner.ts +126 -0
  129. package/src/lib/server/eval/scenarios.ts +218 -0
  130. package/src/lib/server/eval/scorer.ts +96 -0
  131. package/src/lib/server/eval/store.ts +37 -0
  132. package/src/lib/server/eval/types.ts +48 -0
  133. package/src/lib/server/execution-log.ts +12 -8
  134. package/src/lib/server/guardian.ts +34 -0
  135. package/src/lib/server/heartbeat-service.ts +53 -1
  136. package/src/lib/server/integrity-monitor.ts +208 -0
  137. package/src/lib/server/langgraph-checkpoint.ts +10 -0
  138. package/src/lib/server/link-understanding.ts +55 -0
  139. package/src/lib/server/llm-response-cache.test.ts +102 -0
  140. package/src/lib/server/llm-response-cache.ts +227 -0
  141. package/src/lib/server/main-agent-loop.ts +115 -16
  142. package/src/lib/server/main-session.ts +6 -3
  143. package/src/lib/server/mcp-conformance.test.ts +18 -0
  144. package/src/lib/server/mcp-conformance.ts +233 -0
  145. package/src/lib/server/memory-db.ts +193 -19
  146. package/src/lib/server/memory-retrieval.test.ts +56 -0
  147. package/src/lib/server/mmr.ts +73 -0
  148. package/src/lib/server/orchestrator-lg.ts +7 -1
  149. package/src/lib/server/orchestrator.ts +4 -3
  150. package/src/lib/server/plugins.ts +662 -132
  151. package/src/lib/server/process-manager.ts +18 -0
  152. package/src/lib/server/query-expansion.ts +57 -0
  153. package/src/lib/server/queue.ts +280 -11
  154. package/src/lib/server/runtime-settings.ts +9 -0
  155. package/src/lib/server/session-run-manager.test.ts +23 -0
  156. package/src/lib/server/session-run-manager.ts +32 -2
  157. package/src/lib/server/session-tools/canvas.ts +85 -50
  158. package/src/lib/server/session-tools/chatroom.ts +130 -127
  159. package/src/lib/server/session-tools/connector.ts +233 -454
  160. package/src/lib/server/session-tools/context-mgmt.ts +87 -105
  161. package/src/lib/server/session-tools/crud.ts +84 -7
  162. package/src/lib/server/session-tools/delegate.ts +351 -752
  163. package/src/lib/server/session-tools/discovery.ts +198 -0
  164. package/src/lib/server/session-tools/edit_file.ts +82 -0
  165. package/src/lib/server/session-tools/file-send.test.ts +39 -0
  166. package/src/lib/server/session-tools/file.ts +257 -425
  167. package/src/lib/server/session-tools/git.ts +87 -47
  168. package/src/lib/server/session-tools/http.ts +95 -33
  169. package/src/lib/server/session-tools/index.ts +217 -138
  170. package/src/lib/server/session-tools/memory.ts +154 -239
  171. package/src/lib/server/session-tools/monitor.ts +126 -0
  172. package/src/lib/server/session-tools/normalize-tool-args.test.ts +61 -0
  173. package/src/lib/server/session-tools/normalize-tool-args.ts +48 -0
  174. package/src/lib/server/session-tools/openclaw-nodes.ts +82 -99
  175. package/src/lib/server/session-tools/openclaw-workspace.ts +103 -93
  176. package/src/lib/server/session-tools/platform.ts +86 -0
  177. package/src/lib/server/session-tools/plugin-creator.ts +239 -0
  178. package/src/lib/server/session-tools/sample-ui.ts +97 -0
  179. package/src/lib/server/session-tools/sandbox.ts +175 -148
  180. package/src/lib/server/session-tools/schedule.ts +78 -0
  181. package/src/lib/server/session-tools/session-info.ts +104 -410
  182. package/src/lib/server/session-tools/shell-normalize.test.ts +43 -0
  183. package/src/lib/server/session-tools/shell.ts +171 -143
  184. package/src/lib/server/session-tools/subagent.ts +77 -77
  185. package/src/lib/server/session-tools/wallet.ts +182 -106
  186. package/src/lib/server/session-tools/web.ts +181 -327
  187. package/src/lib/server/storage.ts +36 -0
  188. package/src/lib/server/stream-agent-chat.ts +348 -242
  189. package/src/lib/server/task-quality-gate.test.ts +44 -0
  190. package/src/lib/server/task-quality-gate.ts +67 -0
  191. package/src/lib/server/task-validation.test.ts +78 -0
  192. package/src/lib/server/task-validation.ts +67 -2
  193. package/src/lib/server/tool-aliases.ts +68 -0
  194. package/src/lib/server/tool-capability-policy.ts +24 -5
  195. package/src/lib/server/tool-retry.ts +62 -0
  196. package/src/lib/server/transcript-repair.ts +72 -0
  197. package/src/lib/setup-defaults.ts +1 -0
  198. package/src/lib/tasks.ts +7 -1
  199. package/src/lib/tool-definitions.ts +24 -23
  200. package/src/lib/validation/schemas.ts +13 -0
  201. package/src/lib/view-routes.ts +2 -23
  202. package/src/stores/use-app-store.ts +23 -1
  203. package/src/types/index.ts +155 -10
@@ -1,21 +1,21 @@
1
1
  import { z } from 'zod'
2
2
  import { tool, type StructuredToolInterface } from '@langchain/core/tools'
3
+ import type { Session } from '@/types'
3
4
  import { loadSettings, loadSessions, saveSessions, loadMcpServers } from '../storage'
4
5
  import { loadRuntimeSettings } from '../runtime-settings'
5
6
  import { log } from '../logger'
6
7
  import { resolveSessionToolPolicy } from '../tool-capability-policy'
8
+ import { expandToolIds } from '../tool-aliases'
7
9
  import type { ToolContext, SessionToolsResult, ToolBuildContext } from './context'
10
+
11
+ // Import all tool modules to trigger their builtin registration
8
12
  import { buildShellTools } from './shell'
9
13
  import { buildFileTools } from './file'
14
+ import { buildEditFileTools } from './edit_file'
10
15
  import { buildDelegateTools } from './delegate'
11
16
  import { buildWebTools, sweepOrphanedBrowsers, cleanupSessionBrowser, getActiveBrowserCount, hasActiveBrowser } from './web'
12
17
  import { buildMemoryTools } from './memory'
13
- import { buildCrudTools } from './crud'
14
- import { buildSessionInfoTools } from './session-info'
15
- import { buildConnectorTools } from './connector'
16
- import { buildContextTools } from './context-mgmt'
17
18
  import { buildSandboxTools } from './sandbox'
18
- import { buildOpenClawNodeTools } from './openclaw-nodes'
19
19
  import { buildChatroomTools } from './chatroom'
20
20
  import { buildSubagentTools } from './subagent'
21
21
  import { buildCanvasTools } from './canvas'
@@ -23,6 +23,20 @@ import { buildHttpTools } from './http'
23
23
  import { buildGitTools } from './git'
24
24
  import { buildWalletTools } from './wallet'
25
25
  import { buildOpenClawWorkspaceTools } from './openclaw-workspace'
26
+ import { buildScheduleTools } from './schedule'
27
+ import { buildPlatformTools } from './platform'
28
+ import { buildSessionInfoTools } from './session-info'
29
+ import { buildOpenClawNodeTools } from './openclaw-nodes'
30
+ import { buildContextTools } from './context-mgmt'
31
+ import { buildConnectorTools } from './connector'
32
+ import { buildDiscoveryTools } from './discovery'
33
+ import { buildMonitorTools } from './monitor'
34
+ import { buildSampleUITools } from './sample-ui'
35
+ import { buildPluginCreatorTools } from './plugin-creator'
36
+ import { normalizeToolInputArgs } from './normalize-tool-args'
37
+
38
+ import { getPluginManager } from '../plugins'
39
+ import { jsonSchemaToZod } from '../mcp-client'
26
40
 
27
41
  export type { ToolContext, SessionToolsResult }
28
42
  export { sweepOrphanedBrowsers, cleanupSessionBrowser, getActiveBrowserCount, hasActiveBrowser }
@@ -30,155 +44,220 @@ export { sweepOrphanedBrowsers, cleanupSessionBrowser, getActiveBrowserCount, ha
30
44
  export async function buildSessionTools(cwd: string, enabledTools: string[], ctx?: ToolContext): Promise<SessionToolsResult> {
31
45
  const tools: StructuredToolInterface[] = []
32
46
  const cleanupFns: (() => Promise<void>)[] = []
33
- const runtime = loadRuntimeSettings()
34
- const commandTimeoutMs = runtime.shellCommandTimeoutMs
35
- const claudeTimeoutMs = runtime.claudeCodeTimeoutMs
36
- const cliProcessTimeoutMs = runtime.cliProcessTimeoutMs
37
- const appSettings = loadSettings()
38
- const toolPolicy = resolveSessionToolPolicy(enabledTools, appSettings)
39
- const activeTools = toolPolicy.enabledTools.includes('shell') && !toolPolicy.enabledTools.includes('process')
40
- ? [...toolPolicy.enabledTools, 'process']
41
- : toolPolicy.enabledTools
42
- const hasTool = (toolName: string) => activeTools.includes(toolName)
47
+
48
+ try {
49
+ const runtime = loadRuntimeSettings()
50
+ const commandTimeoutMs = runtime.shellCommandTimeoutMs
51
+ const claudeTimeoutMs = runtime.claudeCodeTimeoutMs
52
+ const cliProcessTimeoutMs = runtime.cliProcessTimeoutMs
53
+ const appSettings = loadSettings()
54
+ const toolPolicy = resolveSessionToolPolicy(enabledTools, appSettings)
55
+ const expandedEnabledTools = expandToolIds(toolPolicy.enabledTools)
56
+ const expandedBlockedTools = expandToolIds(toolPolicy.blockedTools.map((entry) => entry.tool))
57
+ const blockedToolSet = new Set(expandedBlockedTools)
58
+ const filteredEnabledTools = expandedEnabledTools.filter((toolId) => !blockedToolSet.has(toolId))
59
+ const activeTools = filteredEnabledTools.includes('shell')
60
+ && !filteredEnabledTools.includes('process')
61
+ && !blockedToolSet.has('process')
62
+ ? [...filteredEnabledTools, 'process']
63
+ : filteredEnabledTools
64
+ const activeToolSet = new Set(activeTools)
65
+ const hasTool = (toolName: string) => activeToolSet.has(toolName)
43
66
 
44
- if (toolPolicy.blockedTools.length > 0) {
45
- log.info('session-tools', 'Capability policy blocked tool families', {
46
- sessionId: ctx?.sessionId || null,
47
- agentId: ctx?.agentId || null,
48
- blockedTools: toolPolicy.blockedTools.map((entry) => `${entry.tool}:${entry.reason}`),
49
- })
50
- }
67
+ if (toolPolicy.blockedTools.length > 0) {
68
+ log.info('session-tools', 'Capability policy blocked tool families', {
69
+ sessionId: ctx?.sessionId || null,
70
+ agentId: ctx?.agentId || null,
71
+ blockedTools: toolPolicy.blockedTools.map((entry) => `${entry.tool}:${entry.reason}`),
72
+ })
73
+ }
51
74
 
52
- const resolveCurrentSession = (): any | null => {
53
- if (!ctx?.sessionId) return null
54
- const sessions = loadSessions()
55
- return sessions[ctx.sessionId] || null
56
- }
75
+ const resolveCurrentSession = (): Session | null => {
76
+ if (!ctx?.sessionId) return null
77
+ const sessions = loadSessions()
78
+ return sessions[ctx.sessionId] || null
79
+ }
57
80
 
58
- const readStoredDelegateResumeId = (key: 'claudeCode' | 'codex' | 'opencode'): string | null => {
59
- const session = resolveCurrentSession()
60
- if (!session?.delegateResumeIds || typeof session.delegateResumeIds !== 'object') return null
61
- const raw = session.delegateResumeIds[key]
62
- return typeof raw === 'string' && raw.trim() ? raw.trim() : null
63
- }
81
+ const readStoredDelegateResumeId = (key: 'claudeCode' | 'codex' | 'opencode'): string | null => {
82
+ const session = resolveCurrentSession()
83
+ if (!session?.delegateResumeIds || typeof session.delegateResumeIds !== 'object') return null
84
+ const raw = session.delegateResumeIds[key]
85
+ return typeof raw === 'string' && raw.trim() ? raw.trim() : null
86
+ }
64
87
 
65
- const persistDelegateResumeId = (key: 'claudeCode' | 'codex' | 'opencode', resumeId: string | null | undefined): void => {
66
- const normalized = typeof resumeId === 'string' ? resumeId.trim() : ''
67
- if (!normalized || !ctx?.sessionId) return
68
- const sessions = loadSessions()
69
- const target = sessions[ctx.sessionId]
70
- if (!target) return
71
- const current = (target.delegateResumeIds && typeof target.delegateResumeIds === 'object')
72
- ? target.delegateResumeIds
73
- : {}
74
- target.delegateResumeIds = {
75
- ...current,
76
- [key]: normalized,
88
+ const persistDelegateResumeId = (key: 'claudeCode' | 'codex' | 'opencode', resumeId: string | null | undefined): void => {
89
+ const normalized = typeof resumeId === 'string' ? resumeId.trim() : ''
90
+ if (!normalized || !ctx?.sessionId) return
91
+ const sessions = loadSessions()
92
+ const target = sessions[ctx.sessionId]
93
+ if (!target) return
94
+ const current = (target.delegateResumeIds && typeof target.delegateResumeIds === 'object')
95
+ ? target.delegateResumeIds
96
+ : {}
97
+ target.delegateResumeIds = {
98
+ ...current,
99
+ [key]: normalized,
100
+ }
101
+ target.updatedAt = Date.now()
102
+ sessions[ctx.sessionId] = target
103
+ saveSessions(sessions)
77
104
  }
78
- target.updatedAt = Date.now()
79
- sessions[ctx.sessionId] = target
80
- saveSessions(sessions)
81
- }
82
105
 
83
- const bctx: ToolBuildContext = {
84
- cwd,
85
- ctx,
86
- hasTool,
87
- cleanupFns,
88
- commandTimeoutMs,
89
- claudeTimeoutMs,
90
- cliProcessTimeoutMs,
91
- persistDelegateResumeId,
92
- readStoredDelegateResumeId,
93
- resolveCurrentSession,
94
- activeTools,
95
- }
106
+ const bctx: ToolBuildContext = {
107
+ cwd,
108
+ ctx,
109
+ hasTool,
110
+ cleanupFns,
111
+ commandTimeoutMs,
112
+ claudeTimeoutMs,
113
+ cliProcessTimeoutMs,
114
+ persistDelegateResumeId,
115
+ readStoredDelegateResumeId,
116
+ resolveCurrentSession,
117
+ activeTools,
118
+ }
96
119
 
97
- tools.push(
98
- ...buildShellTools(bctx),
99
- ...buildFileTools(bctx),
100
- ...buildDelegateTools(bctx),
101
- ...buildWebTools(bctx),
102
- ...buildMemoryTools(bctx),
103
- ...buildCrudTools(bctx),
104
- ...buildSessionInfoTools(bctx),
105
- ...buildConnectorTools(bctx),
106
- ...buildContextTools(bctx),
107
- ...buildSandboxTools(bctx),
108
- ...buildOpenClawNodeTools(bctx),
109
- ...buildChatroomTools(bctx),
110
- ...buildSubagentTools(bctx),
111
- ...buildCanvasTools(bctx),
112
- ...buildHttpTools(bctx),
113
- ...buildGitTools(bctx),
114
- ...buildWalletTools(bctx),
115
- ...buildOpenClawWorkspaceTools(bctx),
116
- )
120
+ // 1. Build Native Bridge Tools (Legacy enablement)
121
+ tools.push(
122
+ ...buildShellTools(bctx),
123
+ ...buildFileTools(bctx),
124
+ ...buildEditFileTools(bctx),
125
+ ...buildDelegateTools(bctx),
126
+ ...buildWebTools(bctx),
127
+ ...buildMemoryTools(bctx),
128
+ ...buildPlatformTools(bctx),
129
+ ...buildSandboxTools(bctx),
130
+ ...buildChatroomTools(bctx),
131
+ ...buildSubagentTools(bctx),
132
+ ...buildCanvasTools(bctx),
133
+ ...buildHttpTools(bctx),
134
+ ...buildGitTools(bctx),
135
+ ...buildWalletTools(bctx),
136
+ ...buildOpenClawWorkspaceTools(bctx),
137
+ ...buildScheduleTools(bctx),
138
+ ...buildSessionInfoTools(bctx),
139
+ ...buildOpenClawNodeTools(bctx),
140
+ ...buildContextTools(bctx),
141
+ ...buildConnectorTools(bctx),
142
+ ...buildDiscoveryTools(bctx),
143
+ ...buildMonitorTools(bctx),
144
+ ...buildSampleUITools(bctx),
145
+ ...buildPluginCreatorTools(bctx),
146
+ )
117
147
 
118
- // ---------------------------------------------------------------------------
119
- // MCP server tools — first-class injection (each MCP tool becomes its own LangChain tool)
120
- // ---------------------------------------------------------------------------
121
- const disabledMcpToolNames = new Set<string>(ctx?.mcpDisabledTools ?? [])
148
+ // 2. Build Plugin Tools (Built-in + External)
149
+ try {
150
+ const pluginManager = getPluginManager()
151
+ const pluginTools = pluginManager.getTools(activeTools)
152
+ const existingNames = new Set(tools.map((t) => t.name))
153
+
154
+ for (const entry of pluginTools) {
155
+ const pt = entry.tool
156
+ if (existingNames.has(pt.name)) {
157
+ log.warn('session-tools', 'Skipping plugin tool due to duplicate name', {
158
+ toolName: pt.name,
159
+ pluginId: entry.pluginId,
160
+ })
161
+ continue
162
+ }
163
+ existingNames.add(pt.name)
122
164
 
123
- if (ctx?.mcpServerIds?.length) {
124
- const mcpConnections: Array<{ client: any; transport: any }> = []
125
- const allMcpServers = loadMcpServers()
165
+ tools.push(
166
+ tool(
167
+ async (args) => {
168
+ if (!pluginManager.isEnabled(entry.pluginId)) {
169
+ throw new Error(`Plugin "${entry.pluginId}" is disabled`)
170
+ }
171
+ try {
172
+ const normalizedArgs = normalizeToolInputArgs((args ?? {}) as Record<string, unknown>)
173
+ const res = await pt.execute(normalizedArgs, {
174
+ session: { ...ctx, cwd } as any,
175
+ message: '',
176
+ })
177
+ pluginManager.recordExternalToolSuccess(entry.pluginId)
178
+ return typeof res === 'string' ? res : JSON.stringify(res)
179
+ } catch (err: unknown) {
180
+ pluginManager.recordExternalToolFailure(entry.pluginId, pt.name, err)
181
+ throw err
182
+ }
183
+ },
184
+ {
185
+ name: pt.name,
186
+ description: pt.description,
187
+ schema: jsonSchemaToZod(pt.parameters),
188
+ }
189
+ )
190
+ )
191
+ }
192
+ } catch (err: unknown) {
193
+ log.error('session-tools', 'Failed to load plugin tools', { error: err instanceof Error ? err.message : String(err) })
194
+ }
126
195
 
127
- for (const serverId of ctx.mcpServerIds) {
128
- const config = allMcpServers[serverId]
129
- if (!config) continue
130
- try {
131
- const { connectMcpServer, mcpToolsToLangChain } = await import('../mcp-client')
132
- const conn = await connectMcpServer(config)
133
- mcpConnections.push(conn)
134
- const mcpLcTools = await mcpToolsToLangChain(conn.client, config.name)
135
- for (const t of mcpLcTools) {
136
- if (!disabledMcpToolNames.has(t.name)) {
137
- tools.push(t)
196
+ // 3. MCP server tools
197
+ const disabledMcpToolNames = new Set<string>(ctx?.mcpDisabledTools ?? [])
198
+ if (ctx?.mcpServerIds?.length) {
199
+ const mcpConnections: Array<{ client: any; transport: any }> = []
200
+ const allMcpServers = loadMcpServers()
201
+ for (const serverId of ctx.mcpServerIds) {
202
+ const config = allMcpServers[serverId]
203
+ if (!config) continue
204
+ try {
205
+ const { connectMcpServer, mcpToolsToLangChain } = await import('../mcp-client')
206
+ const conn = await connectMcpServer(config)
207
+ mcpConnections.push(conn)
208
+ const mcpLcTools = await mcpToolsToLangChain(conn.client, config.name)
209
+ for (const t of mcpLcTools) {
210
+ if (!disabledMcpToolNames.has(t.name)) {
211
+ tools.push(t)
212
+ }
138
213
  }
214
+ } catch (err: any) {
215
+ log.warn('session-tools', `Failed to connect MCP server "${config.name}"`, { serverId, error: err.message })
139
216
  }
140
- } catch (err: any) {
141
- log.warn('session-tools', `Failed to connect MCP server "${config.name}"`, { serverId, error: err.message })
142
217
  }
218
+ cleanupFns.push(async () => {
219
+ const { disconnectMcpServer } = await import('../mcp-client')
220
+ for (const conn of mcpConnections) {
221
+ await disconnectMcpServer(conn.client, conn.transport)
222
+ }
223
+ })
143
224
  }
144
225
 
145
- // Register cleanup for all MCP connections
146
- cleanupFns.push(async () => {
147
- const { disconnectMcpServer } = await import('../mcp-client')
148
- for (const conn of mcpConnections) {
149
- await disconnectMcpServer(conn.client, conn.transport)
150
- }
151
- })
152
- }
226
+ // 4. Always available: request_tool_access
227
+ tools.push(
228
+ tool(
229
+ async (args) => {
230
+ const normalized = normalizeToolInputArgs((args ?? {}) as Record<string, unknown>)
231
+ const toolId = normalized.toolId as string | undefined
232
+ const reason = normalized.reason as string | undefined
233
+ return JSON.stringify({
234
+ type: 'tool_request',
235
+ toolId,
236
+ reason,
237
+ message: `Tool access request sent to user for "${toolId}". The user will be prompted to grant access — once granted, a follow-up message will arrive and you should immediately proceed with the original task using the newly available tool.`,
238
+ })
239
+ },
240
+ {
241
+ name: 'request_tool_access',
242
+ description: 'Ask the user for access to a plugin I don\'t currently have.',
243
+ schema: z.object({
244
+ toolId: z.string().describe('The plugin ID to request access for'),
245
+ reason: z.string().describe('Brief explanation of why you need this plugin'),
246
+ }),
247
+ },
248
+ ),
249
+ )
153
250
 
154
- // request_tool_access: always available
155
- tools.push(
156
- tool(
157
- async ({ toolId, reason }) => {
158
- return JSON.stringify({
159
- type: 'tool_request',
160
- toolId,
161
- reason,
162
- message: `Tool access request sent to user for "${toolId}". The user will be prompted to grant access — once granted, a follow-up message will arrive and you should immediately proceed with the original task using the newly available tool.`,
163
- })
164
- },
165
- {
166
- name: 'request_tool_access',
167
- description: 'Ask the user for access to a tool I don\'t currently have. They\'ll get a prompt to grant it, and once they do, I\'ll automatically continue where I left off. I should end my current response after calling this — no need to ask the user to confirm, it happens on its own.',
168
- schema: z.object({
169
- toolId: z.string().describe('The tool ID to request access for (e.g. manage_tasks, shell, claude_code)'),
170
- reason: z.string().describe('Brief explanation of why you need this tool'),
171
- }),
251
+ return {
252
+ tools,
253
+ cleanup: async () => {
254
+ for (const fn of cleanupFns) {
255
+ try { await fn() } catch { /* ignore */ }
256
+ }
172
257
  },
173
- ),
174
- )
175
-
176
- return {
177
- tools,
178
- cleanup: async () => {
179
- for (const fn of cleanupFns) {
180
- try { await fn() } catch { /* ignore */ }
181
- }
182
- },
258
+ }
259
+ } catch (err: any) {
260
+ console.error('[session-tools] buildSessionTools critical failure:', err.message)
261
+ throw err
183
262
  }
184
263
  }