@swarmclawai/swarmclaw 0.6.8 → 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.
- package/README.md +70 -45
- package/next.config.ts +31 -6
- package/package.json +3 -2
- package/src/app/api/agents/[id]/thread/route.ts +1 -0
- package/src/app/api/agents/route.ts +18 -5
- package/src/app/api/approvals/route.ts +22 -0
- package/src/app/api/clawhub/install/route.ts +2 -2
- package/src/app/api/mcp-servers/[id]/conformance/route.ts +26 -0
- package/src/app/api/mcp-servers/[id]/invoke/route.ts +81 -0
- package/src/app/api/memory/route.ts +36 -5
- package/src/app/api/notifications/route.ts +3 -0
- package/src/app/api/plugins/install/route.ts +57 -5
- package/src/app/api/plugins/marketplace/route.ts +73 -22
- package/src/app/api/plugins/route.ts +61 -1
- package/src/app/api/plugins/ui/route.ts +34 -0
- package/src/app/api/settings/route.ts +62 -0
- package/src/app/api/setup/doctor/route.ts +22 -5
- package/src/app/api/tasks/[id]/approve/route.ts +4 -3
- package/src/app/api/tasks/[id]/route.ts +11 -3
- package/src/app/api/tasks/route.ts +8 -2
- package/src/app/globals.css +27 -0
- package/src/app/page.tsx +10 -5
- package/src/cli/index.js +13 -0
- package/src/components/activity/activity-feed.tsx +9 -2
- package/src/components/agents/agent-avatar.tsx +5 -1
- package/src/components/agents/agent-card.tsx +55 -9
- package/src/components/agents/agent-sheet.tsx +86 -29
- package/src/components/agents/inspector-panel.tsx +1 -1
- package/src/components/auth/access-key-gate.tsx +63 -54
- package/src/components/auth/user-picker.tsx +37 -32
- package/src/components/chat/chat-area.tsx +11 -0
- package/src/components/chat/chat-header.tsx +69 -25
- package/src/components/chat/chat-tool-toggles.tsx +2 -2
- package/src/components/chat/code-block.tsx +3 -1
- package/src/components/chat/exec-approval-card.tsx +8 -1
- package/src/components/chat/message-bubble.tsx +164 -4
- package/src/components/chat/message-list.tsx +30 -4
- package/src/components/chat/session-approval-card.tsx +80 -0
- package/src/components/chat/streaming-bubble.tsx +6 -5
- package/src/components/chat/thinking-indicator.tsx +48 -12
- package/src/components/chat/tool-request-banner.tsx +39 -20
- package/src/components/chatrooms/chatroom-list.tsx +11 -4
- package/src/components/chatrooms/chatroom-sheet.tsx +7 -2
- package/src/components/connectors/connector-list.tsx +33 -11
- package/src/components/connectors/connector-sheet.tsx +29 -6
- package/src/components/home/home-view.tsx +20 -14
- package/src/components/input/chat-input.tsx +22 -1
- package/src/components/knowledge/knowledge-list.tsx +17 -18
- package/src/components/knowledge/knowledge-sheet.tsx +9 -5
- package/src/components/layout/app-layout.tsx +73 -21
- package/src/components/mcp-servers/mcp-server-list.tsx +352 -50
- package/src/components/mcp-servers/mcp-server-sheet.tsx +25 -9
- package/src/components/memory/memory-list.tsx +20 -13
- package/src/components/plugins/plugin-list.tsx +213 -59
- package/src/components/plugins/plugin-sheet.tsx +119 -24
- package/src/components/projects/project-list.tsx +17 -9
- package/src/components/providers/provider-list.tsx +21 -6
- package/src/components/providers/provider-sheet.tsx +42 -25
- package/src/components/runs/run-list.tsx +17 -13
- package/src/components/schedules/schedule-card.tsx +10 -3
- package/src/components/schedules/schedule-list.tsx +2 -2
- package/src/components/schedules/schedule-sheet.tsx +19 -7
- package/src/components/secrets/secret-sheet.tsx +7 -2
- package/src/components/secrets/secrets-list.tsx +18 -5
- package/src/components/sessions/new-session-sheet.tsx +183 -376
- package/src/components/sessions/session-card.tsx +10 -2
- package/src/components/settings/gateway-connection-panel.tsx +9 -8
- package/src/components/shared/command-palette.tsx +13 -5
- package/src/components/shared/empty-state.tsx +20 -8
- package/src/components/shared/notification-center.tsx +134 -86
- package/src/components/shared/profile-sheet.tsx +4 -0
- package/src/components/shared/settings/plugin-manager.tsx +360 -135
- package/src/components/shared/settings/section-capability-policy.tsx +3 -3
- package/src/components/shared/settings/section-runtime-loop.tsx +144 -0
- package/src/components/skills/clawhub-browser.tsx +1 -0
- package/src/components/skills/skill-list.tsx +31 -12
- package/src/components/skills/skill-sheet.tsx +20 -7
- package/src/components/tasks/approvals-panel.tsx +170 -66
- package/src/components/tasks/task-board.tsx +20 -12
- package/src/components/tasks/task-card.tsx +21 -7
- package/src/components/tasks/task-column.tsx +4 -3
- package/src/components/tasks/task-list.tsx +1 -1
- package/src/components/tasks/task-sheet.tsx +130 -1
- package/src/components/ui/dialog.tsx +1 -0
- package/src/components/ui/sheet.tsx +1 -0
- package/src/components/usage/metrics-dashboard.tsx +66 -64
- package/src/components/wallets/wallet-panel.tsx +65 -41
- package/src/components/wallets/wallet-section.tsx +9 -3
- package/src/components/webhooks/webhook-list.tsx +21 -12
- package/src/components/webhooks/webhook-sheet.tsx +13 -3
- package/src/lib/approval-display.test.ts +45 -0
- package/src/lib/approval-display.ts +62 -0
- package/src/lib/clipboard.ts +38 -0
- package/src/lib/memory.ts +8 -0
- package/src/lib/providers/claude-cli.ts +5 -3
- package/src/lib/providers/index.ts +67 -21
- package/src/lib/runtime-loop.ts +3 -2
- package/src/lib/server/approvals.ts +150 -0
- package/src/lib/server/chat-execution.ts +223 -62
- package/src/lib/server/clawhub-client.ts +82 -6
- package/src/lib/server/connectors/manager.ts +27 -1
- package/src/lib/server/cost.test.ts +73 -0
- package/src/lib/server/cost.ts +165 -34
- package/src/lib/server/daemon-state.ts +42 -0
- package/src/lib/server/data-dir.ts +18 -1
- package/src/lib/server/integrity-monitor.ts +208 -0
- package/src/lib/server/llm-response-cache.test.ts +102 -0
- package/src/lib/server/llm-response-cache.ts +227 -0
- package/src/lib/server/main-agent-loop.ts +1 -1
- package/src/lib/server/main-session.ts +6 -3
- package/src/lib/server/mcp-conformance.test.ts +18 -0
- package/src/lib/server/mcp-conformance.ts +233 -0
- package/src/lib/server/memory-db.ts +180 -17
- package/src/lib/server/memory-retrieval.test.ts +56 -0
- package/src/lib/server/orchestrator-lg.ts +4 -1
- package/src/lib/server/orchestrator.ts +4 -3
- package/src/lib/server/plugins.ts +650 -142
- package/src/lib/server/process-manager.ts +18 -0
- package/src/lib/server/queue.ts +253 -11
- package/src/lib/server/runtime-settings.ts +9 -0
- package/src/lib/server/session-run-manager.test.ts +23 -0
- package/src/lib/server/session-run-manager.ts +11 -1
- package/src/lib/server/session-tools/canvas.ts +85 -50
- package/src/lib/server/session-tools/chatroom.ts +130 -127
- package/src/lib/server/session-tools/connector.ts +233 -454
- package/src/lib/server/session-tools/context-mgmt.ts +87 -105
- package/src/lib/server/session-tools/crud.ts +84 -7
- package/src/lib/server/session-tools/delegate.ts +351 -752
- package/src/lib/server/session-tools/discovery.ts +198 -0
- package/src/lib/server/session-tools/edit_file.ts +82 -0
- package/src/lib/server/session-tools/file-send.test.ts +39 -0
- package/src/lib/server/session-tools/file.ts +257 -425
- package/src/lib/server/session-tools/git.ts +87 -47
- package/src/lib/server/session-tools/http.ts +85 -33
- package/src/lib/server/session-tools/index.ts +205 -160
- package/src/lib/server/session-tools/memory.ts +152 -265
- package/src/lib/server/session-tools/monitor.ts +126 -0
- package/src/lib/server/session-tools/normalize-tool-args.test.ts +61 -0
- package/src/lib/server/session-tools/normalize-tool-args.ts +48 -0
- package/src/lib/server/session-tools/openclaw-nodes.ts +82 -99
- package/src/lib/server/session-tools/openclaw-workspace.ts +103 -93
- package/src/lib/server/session-tools/platform.ts +86 -0
- package/src/lib/server/session-tools/plugin-creator.ts +239 -0
- package/src/lib/server/session-tools/sample-ui.ts +97 -0
- package/src/lib/server/session-tools/sandbox.ts +175 -148
- package/src/lib/server/session-tools/schedule.ts +66 -31
- package/src/lib/server/session-tools/session-info.ts +104 -410
- package/src/lib/server/session-tools/shell-normalize.test.ts +43 -0
- package/src/lib/server/session-tools/shell.ts +171 -143
- package/src/lib/server/session-tools/subagent.ts +77 -77
- package/src/lib/server/session-tools/wallet.ts +182 -106
- package/src/lib/server/session-tools/web.ts +179 -349
- package/src/lib/server/storage.ts +24 -0
- package/src/lib/server/stream-agent-chat.ts +301 -244
- package/src/lib/server/task-quality-gate.test.ts +44 -0
- package/src/lib/server/task-quality-gate.ts +67 -0
- package/src/lib/server/task-validation.test.ts +78 -0
- package/src/lib/server/task-validation.ts +67 -2
- package/src/lib/server/tool-aliases.ts +68 -0
- package/src/lib/server/tool-capability-policy.ts +23 -5
- package/src/lib/tasks.ts +7 -1
- package/src/lib/tool-definitions.ts +23 -23
- package/src/lib/validation/schemas.ts +12 -0
- package/src/lib/view-routes.ts +2 -24
- package/src/stores/use-app-store.ts +23 -1
- package/src/types/index.ts +121 -7
|
@@ -5,18 +5,17 @@ import { loadSettings, loadSessions, saveSessions, loadMcpServers } from '../sto
|
|
|
5
5
|
import { loadRuntimeSettings } from '../runtime-settings'
|
|
6
6
|
import { log } from '../logger'
|
|
7
7
|
import { resolveSessionToolPolicy } from '../tool-capability-policy'
|
|
8
|
+
import { expandToolIds } from '../tool-aliases'
|
|
8
9
|
import type { ToolContext, SessionToolsResult, ToolBuildContext } from './context'
|
|
10
|
+
|
|
11
|
+
// Import all tool modules to trigger their builtin registration
|
|
9
12
|
import { buildShellTools } from './shell'
|
|
10
13
|
import { buildFileTools } from './file'
|
|
14
|
+
import { buildEditFileTools } from './edit_file'
|
|
11
15
|
import { buildDelegateTools } from './delegate'
|
|
12
16
|
import { buildWebTools, sweepOrphanedBrowsers, cleanupSessionBrowser, getActiveBrowserCount, hasActiveBrowser } from './web'
|
|
13
17
|
import { buildMemoryTools } from './memory'
|
|
14
|
-
import { buildCrudTools } from './crud'
|
|
15
|
-
import { buildSessionInfoTools } from './session-info'
|
|
16
|
-
import { buildConnectorTools } from './connector'
|
|
17
|
-
import { buildContextTools } from './context-mgmt'
|
|
18
18
|
import { buildSandboxTools } from './sandbox'
|
|
19
|
-
import { buildOpenClawNodeTools } from './openclaw-nodes'
|
|
20
19
|
import { buildChatroomTools } from './chatroom'
|
|
21
20
|
import { buildSubagentTools } from './subagent'
|
|
22
21
|
import { buildCanvasTools } from './canvas'
|
|
@@ -25,6 +24,17 @@ import { buildGitTools } from './git'
|
|
|
25
24
|
import { buildWalletTools } from './wallet'
|
|
26
25
|
import { buildOpenClawWorkspaceTools } from './openclaw-workspace'
|
|
27
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
|
+
|
|
28
38
|
import { getPluginManager } from '../plugins'
|
|
29
39
|
import { jsonSchemaToZod } from '../mcp-client'
|
|
30
40
|
|
|
@@ -34,143 +44,142 @@ export { sweepOrphanedBrowsers, cleanupSessionBrowser, getActiveBrowserCount, ha
|
|
|
34
44
|
export async function buildSessionTools(cwd: string, enabledTools: string[], ctx?: ToolContext): Promise<SessionToolsResult> {
|
|
35
45
|
const tools: StructuredToolInterface[] = []
|
|
36
46
|
const cleanupFns: (() => Promise<void>)[] = []
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const resolveCurrentSession = (): any | null => {
|
|
57
|
-
if (!ctx?.sessionId) return null
|
|
58
|
-
const sessions = loadSessions()
|
|
59
|
-
return sessions[ctx.sessionId] || null
|
|
60
|
-
}
|
|
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)
|
|
61
66
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
+
}
|
|
68
74
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const target = sessions[ctx.sessionId]
|
|
74
|
-
if (!target) return
|
|
75
|
-
const current = (target.delegateResumeIds && typeof target.delegateResumeIds === 'object')
|
|
76
|
-
? target.delegateResumeIds
|
|
77
|
-
: {}
|
|
78
|
-
target.delegateResumeIds = {
|
|
79
|
-
...current,
|
|
80
|
-
[key]: normalized,
|
|
75
|
+
const resolveCurrentSession = (): Session | null => {
|
|
76
|
+
if (!ctx?.sessionId) return null
|
|
77
|
+
const sessions = loadSessions()
|
|
78
|
+
return sessions[ctx.sessionId] || null
|
|
81
79
|
}
|
|
82
|
-
target.updatedAt = Date.now()
|
|
83
|
-
sessions[ctx.sessionId] = target
|
|
84
|
-
saveSessions(sessions)
|
|
85
|
-
}
|
|
86
80
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
claudeTimeoutMs,
|
|
94
|
-
cliProcessTimeoutMs,
|
|
95
|
-
persistDelegateResumeId,
|
|
96
|
-
readStoredDelegateResumeId,
|
|
97
|
-
resolveCurrentSession,
|
|
98
|
-
activeTools,
|
|
99
|
-
}
|
|
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
|
+
}
|
|
100
87
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
...buildWalletTools(bctx),
|
|
119
|
-
...buildOpenClawWorkspaceTools(bctx),
|
|
120
|
-
...buildScheduleTools(bctx),
|
|
121
|
-
)
|
|
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)
|
|
104
|
+
}
|
|
122
105
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
+
}
|
|
127
119
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
+
)
|
|
131
147
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
|
144
162
|
}
|
|
145
|
-
|
|
146
|
-
log.warn('session-tools', `Failed to connect MCP server "${config.name}"`, { serverId, error: err.message })
|
|
147
|
-
}
|
|
148
|
-
}
|
|
163
|
+
existingNames.add(pt.name)
|
|
149
164
|
|
|
150
|
-
// Register cleanup for all MCP connections
|
|
151
|
-
cleanupFns.push(async () => {
|
|
152
|
-
const { disconnectMcpServer } = await import('../mcp-client')
|
|
153
|
-
for (const conn of mcpConnections) {
|
|
154
|
-
await disconnectMcpServer(conn.client, conn.transport)
|
|
155
|
-
}
|
|
156
|
-
})
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// ---------------------------------------------------------------------------
|
|
160
|
-
// Plugin tools — native tools provided by SwarmClaw plugins
|
|
161
|
-
// ---------------------------------------------------------------------------
|
|
162
|
-
try {
|
|
163
|
-
const pluginTools = getPluginManager().getPluginTools()
|
|
164
|
-
for (const pt of pluginTools) {
|
|
165
|
-
if (!disabledMcpToolNames.has(pt.name)) {
|
|
166
165
|
tools.push(
|
|
167
166
|
tool(
|
|
168
167
|
async (args) => {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
+
}
|
|
174
183
|
},
|
|
175
184
|
{
|
|
176
185
|
name: pt.name,
|
|
@@ -180,39 +189,75 @@ export async function buildSessionTools(cwd: string, enabledTools: string[], ctx
|
|
|
180
189
|
)
|
|
181
190
|
)
|
|
182
191
|
}
|
|
192
|
+
} catch (err: unknown) {
|
|
193
|
+
log.error('session-tools', 'Failed to load plugin tools', { error: err instanceof Error ? err.message : String(err) })
|
|
183
194
|
}
|
|
184
|
-
} catch (err: unknown) {
|
|
185
|
-
log.error('session-tools', 'Failed to load plugin tools', { error: err instanceof Error ? err.message : String(err) })
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// request_tool_access: always available
|
|
189
|
-
tools.push(
|
|
190
|
-
tool(
|
|
191
|
-
async ({ toolId, reason }) => {
|
|
192
|
-
return JSON.stringify({
|
|
193
|
-
type: 'tool_request',
|
|
194
|
-
toolId,
|
|
195
|
-
reason,
|
|
196
|
-
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.`,
|
|
197
|
-
})
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
name: 'request_tool_access',
|
|
201
|
-
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.',
|
|
202
|
-
schema: z.object({
|
|
203
|
-
toolId: z.string().describe('The tool ID to request access for (e.g. manage_tasks, shell, claude_code)'),
|
|
204
|
-
reason: z.string().describe('Brief explanation of why you need this tool'),
|
|
205
|
-
}),
|
|
206
|
-
},
|
|
207
|
-
),
|
|
208
|
-
)
|
|
209
195
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
+
}
|
|
213
|
+
}
|
|
214
|
+
} catch (err: any) {
|
|
215
|
+
log.warn('session-tools', `Failed to connect MCP server "${config.name}"`, { serverId, error: err.message })
|
|
216
|
+
}
|
|
215
217
|
}
|
|
216
|
-
|
|
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
|
+
})
|
|
224
|
+
}
|
|
225
|
+
|
|
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
|
+
)
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
tools,
|
|
253
|
+
cleanup: async () => {
|
|
254
|
+
for (const fn of cleanupFns) {
|
|
255
|
+
try { await fn() } catch { /* ignore */ }
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
}
|
|
259
|
+
} catch (err: any) {
|
|
260
|
+
console.error('[session-tools] buildSessionTools critical failure:', err.message)
|
|
261
|
+
throw err
|
|
217
262
|
}
|
|
218
263
|
}
|