@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.
- package/README.md +82 -39
- 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 +19 -5
- package/src/app/api/approvals/route.ts +22 -0
- package/src/app/api/chatrooms/[id]/chat/route.ts +4 -0
- package/src/app/api/clawhub/install/route.ts +2 -2
- package/src/app/api/eval/run/route.ts +37 -0
- package/src/app/api/eval/scenarios/route.ts +24 -0
- package/src/app/api/eval/suite/route.ts +29 -0
- 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/graph/route.ts +46 -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/sessions/[id]/checkpoints/route.ts +31 -0
- package/src/app/api/sessions/[id]/restore/route.ts +36 -0
- package/src/app/api/settings/route.ts +62 -0
- package/src/app/api/setup/doctor/route.ts +22 -5
- package/src/app/api/souls/[id]/route.ts +65 -0
- package/src/app/api/souls/route.ts +70 -0
- package/src/app/api/tasks/[id]/approve/route.ts +4 -3
- package/src/app/api/tasks/[id]/route.ts +16 -3
- package/src/app/api/tasks/route.ts +10 -2
- package/src/app/api/usage/route.ts +9 -2
- package/src/app/globals.css +27 -0
- package/src/app/page.tsx +10 -5
- package/src/cli/index.js +37 -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 +112 -34
- package/src/components/agents/inspector-panel.tsx +1 -1
- package/src/components/agents/soul-library-picker.tsx +84 -13
- package/src/components/auth/access-key-gate.tsx +63 -54
- package/src/components/auth/user-picker.tsx +37 -32
- package/src/components/chat/activity-moment.tsx +2 -0
- 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/checkpoint-timeline.tsx +112 -0
- 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 +46 -4
- package/src/components/chat/session-approval-card.tsx +80 -0
- package/src/components/chat/session-debug-panel.tsx +106 -84
- package/src/components/chat/streaming-bubble.tsx +6 -5
- package/src/components/chat/task-approval-card.tsx +78 -0
- package/src/components/chat/thinking-indicator.tsx +48 -12
- package/src/components/chat/tool-call-bubble.tsx +3 -0
- 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 +37 -7
- package/src/components/home/home-view.tsx +54 -24
- 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 +87 -19
- 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-browser.tsx +73 -45
- package/src/components/memory/memory-graph-view.tsx +203 -0
- package/src/components/memory/memory-list.tsx +20 -13
- package/src/components/plugins/plugin-list.tsx +214 -60
- 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 +28 -9
- 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/hint-tip.tsx +31 -0
- 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 +149 -4
- 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 +224 -0
- 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 +72 -48
- 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 +319 -74
- package/src/lib/server/chatroom-helpers.ts +63 -5
- package/src/lib/server/chatroom-orchestration.ts +74 -0
- package/src/lib/server/clawhub-client.ts +82 -6
- package/src/lib/server/connectors/manager.ts +27 -1
- package/src/lib/server/context-manager.ts +132 -50
- package/src/lib/server/cost.test.ts +73 -0
- package/src/lib/server/cost.ts +165 -34
- package/src/lib/server/daemon-state.ts +112 -1
- package/src/lib/server/data-dir.ts +18 -1
- package/src/lib/server/eval/runner.ts +126 -0
- package/src/lib/server/eval/scenarios.ts +218 -0
- package/src/lib/server/eval/scorer.ts +96 -0
- package/src/lib/server/eval/store.ts +37 -0
- package/src/lib/server/eval/types.ts +48 -0
- package/src/lib/server/execution-log.ts +12 -8
- package/src/lib/server/guardian.ts +34 -0
- package/src/lib/server/heartbeat-service.ts +53 -1
- package/src/lib/server/integrity-monitor.ts +208 -0
- package/src/lib/server/langgraph-checkpoint.ts +10 -0
- package/src/lib/server/link-understanding.ts +55 -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 +115 -16
- 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 +193 -19
- package/src/lib/server/memory-retrieval.test.ts +56 -0
- package/src/lib/server/mmr.ts +73 -0
- package/src/lib/server/orchestrator-lg.ts +7 -1
- package/src/lib/server/orchestrator.ts +4 -3
- package/src/lib/server/plugins.ts +662 -132
- package/src/lib/server/process-manager.ts +18 -0
- package/src/lib/server/query-expansion.ts +57 -0
- package/src/lib/server/queue.ts +280 -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 +32 -2
- 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 +95 -33
- package/src/lib/server/session-tools/index.ts +217 -138
- package/src/lib/server/session-tools/memory.ts +154 -239
- 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 +78 -0
- 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 +181 -327
- package/src/lib/server/storage.ts +36 -0
- package/src/lib/server/stream-agent-chat.ts +348 -242
- 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 +24 -5
- package/src/lib/server/tool-retry.ts +62 -0
- package/src/lib/server/transcript-repair.ts +72 -0
- package/src/lib/setup-defaults.ts +1 -0
- package/src/lib/tasks.ts +7 -1
- package/src/lib/tool-definitions.ts +24 -23
- package/src/lib/validation/schemas.ts +13 -0
- package/src/lib/view-routes.ts +2 -23
- package/src/stores/use-app-store.ts +23 -1
- package/src/types/index.ts +155 -10
|
@@ -1,121 +1,103 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import { tool, type StructuredToolInterface } from '@langchain/core/tools'
|
|
3
3
|
import { HumanMessage } from '@langchain/core/messages'
|
|
4
|
-
import { loadSessions, saveSessions
|
|
4
|
+
import { loadSessions, saveSessions } from '../storage'
|
|
5
5
|
import { buildChatModel } from '../build-llm'
|
|
6
|
-
import { getProvider } from '@/lib/providers'
|
|
7
6
|
import type { ToolBuildContext } from './context'
|
|
7
|
+
import type { Plugin, PluginHooks, Session } from '@/types'
|
|
8
|
+
import { getPluginManager } from '../plugins'
|
|
9
|
+
import { normalizeToolInputArgs } from './normalize-tool-args'
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
interface ContextToolContext {
|
|
12
|
+
ctx?: { agentId?: string | null; sessionId?: string | null }
|
|
13
|
+
resolveCurrentSession?: () => Session | null
|
|
14
|
+
}
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
} catch (err: unknown) {
|
|
26
|
-
return `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: 'context_status',
|
|
31
|
-
description: 'Check how much of my context window I\'ve used. Returns my token usage, the model\'s limit, percentage used, and whether I should compact.',
|
|
32
|
-
schema: z.object({}),
|
|
33
|
-
},
|
|
34
|
-
),
|
|
35
|
-
)
|
|
16
|
+
/**
|
|
17
|
+
* Core Context Management Execution Logic
|
|
18
|
+
*/
|
|
19
|
+
async function executeContextStatus(bctx: ContextToolContext) {
|
|
20
|
+
try {
|
|
21
|
+
const { getContextStatus } = await import('../context-manager')
|
|
22
|
+
const session = bctx.resolveCurrentSession?.()
|
|
23
|
+
if (!session) return 'Error: no current session context.'
|
|
24
|
+
const status = getContextStatus(session.messages || [], 2000, session.provider as string, session.model as string)
|
|
25
|
+
return JSON.stringify(status)
|
|
26
|
+
} catch (err: unknown) { return `Error: ${err instanceof Error ? err.message : String(err)}` }
|
|
27
|
+
}
|
|
36
28
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
29
|
+
async function executeContextSummarize(args: { keepLastN?: number }, bctx: ContextToolContext) {
|
|
30
|
+
try {
|
|
31
|
+
const normalized = normalizeToolInputArgs((args ?? {}) as Record<string, unknown>)
|
|
32
|
+
const { summarizeAndCompact } = await import('../context-manager')
|
|
33
|
+
const session = bctx.resolveCurrentSession?.()
|
|
34
|
+
if (!session || !bctx.ctx?.sessionId) return 'Error: no session context.'
|
|
35
|
+
|
|
36
|
+
const messages = session.messages || []
|
|
37
|
+
const keepLastN = normalized.keepLastN as number | undefined
|
|
38
|
+
const keep = Math.max(2, Math.min(keepLastN || 10, messages.length))
|
|
39
|
+
if (messages.length <= keep) return JSON.stringify({ status: 'no_action' })
|
|
47
40
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
41
|
+
const generateSummary = async (prompt: string): Promise<string> => {
|
|
42
|
+
const llm = buildChatModel({ provider: session.provider, model: session.model, apiKey: null })
|
|
43
|
+
const res = await llm.invoke([new HumanMessage(prompt)])
|
|
44
|
+
return typeof res.content === 'string' ? res.content : ''
|
|
45
|
+
}
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
try {
|
|
57
|
-
const creds = loadCredentials()
|
|
58
|
-
const cred = creds[session.credentialId]
|
|
59
|
-
if (cred) apiKey = decryptKey(cred.encryptedKey)
|
|
60
|
-
} catch { /* continue without key */ }
|
|
61
|
-
}
|
|
47
|
+
const result = await summarizeAndCompact({
|
|
48
|
+
messages, keepLastN: keep, agentId: bctx.ctx.agentId ?? null, sessionId: bctx.ctx.sessionId ?? '',
|
|
49
|
+
provider: session.provider, model: session.model, generateSummary
|
|
50
|
+
})
|
|
62
51
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const response = await llm.invoke([new HumanMessage(prompt)])
|
|
72
|
-
if (typeof response.content === 'string') return response.content
|
|
73
|
-
if (Array.isArray(response.content)) {
|
|
74
|
-
return response.content
|
|
75
|
-
.map((b: Record<string, unknown>) => (typeof b.text === 'string' ? b.text : ''))
|
|
76
|
-
.join('')
|
|
77
|
-
}
|
|
78
|
-
return ''
|
|
79
|
-
}
|
|
52
|
+
const sessions = loadSessions()
|
|
53
|
+
if (sessions[bctx.ctx.sessionId]) {
|
|
54
|
+
sessions[bctx.ctx.sessionId].messages = result.messages
|
|
55
|
+
saveSessions(sessions)
|
|
56
|
+
}
|
|
57
|
+
return JSON.stringify({ status: 'compacted', remaining: result.messages.length })
|
|
58
|
+
} catch (err: unknown) { return `Error: ${err instanceof Error ? err.message : String(err)}` }
|
|
59
|
+
}
|
|
80
60
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Register as a Built-in Plugin
|
|
63
|
+
*/
|
|
64
|
+
const ContextPlugin: Plugin = {
|
|
65
|
+
name: 'Core Context',
|
|
66
|
+
description: 'Manage and optimize the agent conversation context window.',
|
|
67
|
+
hooks: {} as PluginHooks,
|
|
68
|
+
tools: [
|
|
69
|
+
{
|
|
70
|
+
name: 'context_status',
|
|
71
|
+
description: 'Check token usage and context window limits.',
|
|
72
|
+
parameters: { type: 'object', properties: {} },
|
|
73
|
+
execute: async (_args, context) => executeContextStatus({ resolveCurrentSession: () => context.session as unknown as Session })
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'context_summarize',
|
|
77
|
+
description: 'Compact conversation history to free up space.',
|
|
78
|
+
parameters: {
|
|
79
|
+
type: 'object',
|
|
80
|
+
properties: { keepLastN: { type: 'number' } }
|
|
81
|
+
},
|
|
82
|
+
execute: async (args, context) => executeContextSummarize(args as { keepLastN?: number }, { ctx: { sessionId: context.session.id, agentId: context.session.agentId ?? null }, resolveCurrentSession: () => context.session as unknown as Session })
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
90
86
|
|
|
91
|
-
|
|
92
|
-
const target = sessions[ctx.sessionId]
|
|
93
|
-
if (target) {
|
|
94
|
-
target.messages = result.messages
|
|
95
|
-
saveSessions(sessions)
|
|
96
|
-
}
|
|
87
|
+
getPluginManager().registerBuiltin('context_mgmt', ContextPlugin)
|
|
97
88
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
name: 'context_summarize',
|
|
111
|
-
description: 'Compact my conversation history to free up context space. I\'ll save important decisions, facts, and results to memory, then replace older messages with a summary. I should check context_status first to see if this is needed.',
|
|
112
|
-
schema: z.object({
|
|
113
|
-
keepLastN: z.number().optional().describe('Number of recent messages to keep (default 10, min 2).'),
|
|
114
|
-
}),
|
|
115
|
-
},
|
|
116
|
-
),
|
|
89
|
+
/**
|
|
90
|
+
* Legacy Bridge
|
|
91
|
+
*/
|
|
92
|
+
export function buildContextTools(bctx: ToolBuildContext): StructuredToolInterface[] {
|
|
93
|
+
return [
|
|
94
|
+
tool(
|
|
95
|
+
async () => executeContextStatus(bctx),
|
|
96
|
+
{ name: 'context_status', description: ContextPlugin.tools![0].description, schema: z.object({}).passthrough() }
|
|
97
|
+
),
|
|
98
|
+
tool(
|
|
99
|
+
async (args) => executeContextSummarize(args as { keepLastN?: number }, bctx),
|
|
100
|
+
{ name: 'context_summarize', description: ContextPlugin.tools![1].description, schema: z.object({}).passthrough() }
|
|
117
101
|
)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return tools
|
|
102
|
+
]
|
|
121
103
|
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
loadWebhooks, saveWebhooks,
|
|
16
16
|
loadSecrets, saveSecrets,
|
|
17
17
|
loadSessions, saveSessions,
|
|
18
|
+
loadSettings,
|
|
18
19
|
encryptKey,
|
|
19
20
|
decryptKey,
|
|
20
21
|
} from '../storage'
|
|
@@ -22,8 +23,10 @@ import { resolveScheduleName } from '@/lib/schedule-name'
|
|
|
22
23
|
import { findDuplicateSchedule, type ScheduleLike } from '@/lib/schedule-dedupe'
|
|
23
24
|
import { computeTaskFingerprint, findDuplicateTask } from '@/lib/task-dedupe'
|
|
24
25
|
import { resolveTaskAgentFromDescription } from '@/lib/server/task-mention'
|
|
26
|
+
import { normalizeTaskQualityGate } from '@/lib/server/task-quality-gate'
|
|
25
27
|
import type { ToolBuildContext } from './context'
|
|
26
28
|
import { safePath, findBinaryOnPath } from './context'
|
|
29
|
+
import { normalizeToolInputArgs } from './normalize-tool-args'
|
|
27
30
|
|
|
28
31
|
// ---------------------------------------------------------------------------
|
|
29
32
|
// Document helpers
|
|
@@ -87,6 +90,41 @@ function trimDocumentContent(text: string): string {
|
|
|
87
90
|
return normalized.slice(0, MAX_DOCUMENT_TEXT_CHARS)
|
|
88
91
|
}
|
|
89
92
|
|
|
93
|
+
function deriveTaskTitle(input: { title?: unknown; description?: unknown }): string {
|
|
94
|
+
const explicit = typeof input.title === 'string' ? input.title.replace(/\s+/g, ' ').trim() : ''
|
|
95
|
+
if (explicit && !/^untitled task$/i.test(explicit)) return explicit.slice(0, 120)
|
|
96
|
+
|
|
97
|
+
const description = typeof input.description === 'string'
|
|
98
|
+
? input.description.replace(/\s+/g, ' ').trim()
|
|
99
|
+
: ''
|
|
100
|
+
if (!description) return ''
|
|
101
|
+
|
|
102
|
+
const firstSentence = description.split(/[.!?]\s+/)[0] || description
|
|
103
|
+
const compact = firstSentence
|
|
104
|
+
.replace(/^please\s+/i, '')
|
|
105
|
+
.replace(/^(create|make|build|implement|write)\s+/i, '')
|
|
106
|
+
.trim()
|
|
107
|
+
if (!compact) return ''
|
|
108
|
+
return compact.slice(0, 120)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const TASK_STATUS_VALUES = new Set([
|
|
112
|
+
'backlog',
|
|
113
|
+
'queued',
|
|
114
|
+
'running',
|
|
115
|
+
'completed',
|
|
116
|
+
'failed',
|
|
117
|
+
'archived',
|
|
118
|
+
])
|
|
119
|
+
|
|
120
|
+
function normalizeTaskStatusInput(status: unknown, prevStatus?: string): string | null {
|
|
121
|
+
if (typeof status !== 'string') return null
|
|
122
|
+
const normalized = status.trim().toLowerCase()
|
|
123
|
+
if (!TASK_STATUS_VALUES.has(normalized)) return null
|
|
124
|
+
if (normalized === 'running' && prevStatus !== 'running') return 'queued'
|
|
125
|
+
return normalized
|
|
126
|
+
}
|
|
127
|
+
|
|
90
128
|
// ---------------------------------------------------------------------------
|
|
91
129
|
// RESOURCE_DEFAULTS
|
|
92
130
|
// ---------------------------------------------------------------------------
|
|
@@ -107,7 +145,7 @@ const RESOURCE_DEFAULTS: Record<string, (parsed: any) => any> = {
|
|
|
107
145
|
...p,
|
|
108
146
|
}),
|
|
109
147
|
manage_tasks: (p) => ({
|
|
110
|
-
title: p
|
|
148
|
+
title: deriveTaskTitle(p) || 'Untitled Task',
|
|
111
149
|
description: p.description || '',
|
|
112
150
|
status: p.status || 'backlog',
|
|
113
151
|
agentId: p.agentId || null,
|
|
@@ -218,9 +256,9 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
218
256
|
let description = `Manage SwarmClaw ${res.label}. ${res.readOnly ? 'List and get only.' : 'List, get, create, update, or delete.'} Returns JSON.`
|
|
219
257
|
if (toolKey === 'manage_tasks') {
|
|
220
258
|
if (assignScope === 'self') {
|
|
221
|
-
description += `\n\nSet "agentId" to assign a task to yourself ("${ctx?.agentId || 'unknown'}") or leave it null. You can only assign tasks to yourself. Valid statuses: backlog, queued,
|
|
259
|
+
description += `\n\nSet "agentId" to assign a task to yourself ("${ctx?.agentId || 'unknown'}") or leave it null. You can only assign tasks to yourself. Valid manual statuses: backlog, queued, completed, failed, archived. "running" is runtime-only and set automatically when execution starts.`
|
|
222
260
|
} else {
|
|
223
|
-
description += `\n\nSet "agentId" to assign a task to an agent (including yourself: "${ctx?.agentId || 'unknown'}"). Valid statuses: backlog, queued,
|
|
261
|
+
description += `\n\nSet "agentId" to assign a task to an agent (including yourself: "${ctx?.agentId || 'unknown'}"). Valid manual statuses: backlog, queued, completed, failed, archived. "running" is runtime-only and set automatically when execution starts.` + agentSummary
|
|
224
262
|
}
|
|
225
263
|
} else if (toolKey === 'manage_agents') {
|
|
226
264
|
description += `\n\nAgents may self-edit their own soul. To update your soul, use action="update", id="${ctx?.agentId || 'your-agent-id'}", and include data with the "soul" field.`
|
|
@@ -236,7 +274,11 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
236
274
|
|
|
237
275
|
tools.push(
|
|
238
276
|
tool(
|
|
239
|
-
async (
|
|
277
|
+
async (rawArgs) => {
|
|
278
|
+
const normalized = normalizeToolInputArgs((rawArgs ?? {}) as Record<string, unknown>)
|
|
279
|
+
const action = normalized.action as string | undefined
|
|
280
|
+
const id = normalized.id as string | undefined
|
|
281
|
+
const data = normalized.data as string | undefined
|
|
240
282
|
const canAccessSecret = (secret: any): boolean => {
|
|
241
283
|
if (!secret) return false
|
|
242
284
|
if (secret.scope !== 'agent') return true
|
|
@@ -354,6 +396,20 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
354
396
|
agents,
|
|
355
397
|
)
|
|
356
398
|
}
|
|
399
|
+
if (toolKey === 'manage_tasks') {
|
|
400
|
+
parsed.title = deriveTaskTitle(parsed)
|
|
401
|
+
if (!parsed.title || /^untitled task$/i.test(parsed.title)) {
|
|
402
|
+
return 'Error: manage_tasks create requires a specific title or a meaningful description.'
|
|
403
|
+
}
|
|
404
|
+
parsed.status = normalizeTaskStatusInput(parsed.status) || 'backlog'
|
|
405
|
+
if (!parsed.cwd && cwd) parsed.cwd = cwd
|
|
406
|
+
if (Object.prototype.hasOwnProperty.call(parsed, 'qualityGate')) {
|
|
407
|
+
const settings = loadSettings()
|
|
408
|
+
parsed.qualityGate = parsed.qualityGate
|
|
409
|
+
? normalizeTaskQualityGate(parsed.qualityGate, settings)
|
|
410
|
+
: null
|
|
411
|
+
}
|
|
412
|
+
}
|
|
357
413
|
// Task dedup
|
|
358
414
|
if (toolKey === 'manage_tasks') {
|
|
359
415
|
const fp = computeTaskFingerprint(parsed.title || 'Untitled Task', parsed.agentId || ctx?.agentId || '')
|
|
@@ -400,9 +456,10 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
400
456
|
if (toolKey === 'manage_tasks' && entry.status === 'completed') {
|
|
401
457
|
const { formatValidationFailure, validateTaskCompletion } = await import('../task-validation')
|
|
402
458
|
const { ensureTaskCompletionReport } = await import('../task-reports')
|
|
459
|
+
const settings = loadSettings()
|
|
403
460
|
const report = ensureTaskCompletionReport(entry as any)
|
|
404
461
|
if (report?.relativePath) (entry as any).completionReportPath = report.relativePath
|
|
405
|
-
const validation = validateTaskCompletion(entry as any, { report })
|
|
462
|
+
const validation = validateTaskCompletion(entry as any, { report, settings })
|
|
406
463
|
;(entry as any).validation = validation
|
|
407
464
|
if (!validation.ok) {
|
|
408
465
|
entry.status = 'failed'
|
|
@@ -431,6 +488,17 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
431
488
|
if (!all[id]) return `Not found: ${res.label} "${id}"`
|
|
432
489
|
const parsed = data ? JSON.parse(data) : {}
|
|
433
490
|
const prevStatus = all[id]?.status
|
|
491
|
+
if (toolKey === 'manage_tasks' && Object.prototype.hasOwnProperty.call(parsed, 'status')) {
|
|
492
|
+
const normalized = normalizeTaskStatusInput(parsed.status, prevStatus)
|
|
493
|
+
if (normalized) parsed.status = normalized
|
|
494
|
+
else delete parsed.status
|
|
495
|
+
}
|
|
496
|
+
if (toolKey === 'manage_tasks' && Object.prototype.hasOwnProperty.call(parsed, 'qualityGate')) {
|
|
497
|
+
const settings = loadSettings()
|
|
498
|
+
parsed.qualityGate = parsed.qualityGate
|
|
499
|
+
? normalizeTaskQualityGate(parsed.qualityGate, settings)
|
|
500
|
+
: null
|
|
501
|
+
}
|
|
434
502
|
// Enforce assignment scope for tasks and schedules
|
|
435
503
|
if (assignScope === 'self' && (toolKey === 'manage_tasks' || toolKey === 'manage_schedules')) {
|
|
436
504
|
if (parsed.agentId && parsed.agentId !== ctx?.agentId) {
|
|
@@ -468,9 +536,10 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
468
536
|
if (toolKey === 'manage_tasks' && all[id].status === 'completed') {
|
|
469
537
|
const { formatValidationFailure, validateTaskCompletion } = await import('../task-validation')
|
|
470
538
|
const { ensureTaskCompletionReport } = await import('../task-reports')
|
|
539
|
+
const settings = loadSettings()
|
|
471
540
|
const report = ensureTaskCompletionReport(all[id] as any)
|
|
472
541
|
if (report?.relativePath) (all[id] as any).completionReportPath = report.relativePath
|
|
473
|
-
const validation = validateTaskCompletion(all[id] as any, { report })
|
|
542
|
+
const validation = validateTaskCompletion(all[id] as any, { report, settings })
|
|
474
543
|
;(all[id] as any).validation = validation
|
|
475
544
|
if (!validation.ok) {
|
|
476
545
|
all[id].status = 'failed'
|
|
@@ -532,7 +601,15 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
532
601
|
if (hasTool('manage_documents')) {
|
|
533
602
|
tools.push(
|
|
534
603
|
tool(
|
|
535
|
-
async (
|
|
604
|
+
async (rawArgs) => {
|
|
605
|
+
const normalized = normalizeToolInputArgs((rawArgs ?? {}) as Record<string, unknown>)
|
|
606
|
+
const action = normalized.action as string | undefined
|
|
607
|
+
const id = normalized.id as string | undefined
|
|
608
|
+
const filePath = (normalized.filePath ?? normalized.path) as string | undefined
|
|
609
|
+
const query = normalized.query as string | undefined
|
|
610
|
+
const limit = normalized.limit as number | undefined
|
|
611
|
+
const metadata = normalized.metadata as string | undefined
|
|
612
|
+
const title = normalized.title as string | undefined
|
|
536
613
|
try {
|
|
537
614
|
const documents = loadDocuments()
|
|
538
615
|
|