principles-disciple 1.6.0 → 1.7.1
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/dist/commands/context.js +7 -3
- package/dist/commands/evolution-status.d.ts +4 -0
- package/dist/commands/evolution-status.js +134 -0
- package/dist/commands/export.d.ts +2 -0
- package/dist/commands/export.js +45 -0
- package/dist/commands/focus.js +9 -6
- package/dist/commands/pain.js +8 -0
- package/dist/commands/principle-rollback.d.ts +4 -0
- package/dist/commands/principle-rollback.js +22 -0
- package/dist/commands/rollback.js +9 -3
- package/dist/commands/samples.d.ts +2 -0
- package/dist/commands/samples.js +55 -0
- package/dist/commands/trust.js +64 -81
- package/dist/core/config.d.ts +5 -0
- package/dist/core/control-ui-db.d.ts +68 -0
- package/dist/core/control-ui-db.js +274 -0
- package/dist/core/detection-funnel.d.ts +1 -1
- package/dist/core/detection-funnel.js +4 -0
- package/dist/core/dictionary.d.ts +2 -0
- package/dist/core/dictionary.js +13 -0
- package/dist/core/event-log.d.ts +7 -1
- package/dist/core/event-log.js +10 -0
- package/dist/core/evolution-engine.d.ts +5 -5
- package/dist/core/evolution-engine.js +18 -18
- package/dist/core/evolution-migration.d.ts +5 -0
- package/dist/core/evolution-migration.js +65 -0
- package/dist/core/evolution-reducer.d.ts +69 -0
- package/dist/core/evolution-reducer.js +369 -0
- package/dist/core/evolution-types.d.ts +103 -0
- package/dist/core/path-resolver.js +75 -36
- package/dist/core/paths.d.ts +7 -8
- package/dist/core/paths.js +48 -40
- package/dist/core/profile.js +1 -1
- package/dist/core/session-tracker.d.ts +14 -2
- package/dist/core/session-tracker.js +75 -9
- package/dist/core/thinking-models.d.ts +38 -0
- package/dist/core/thinking-models.js +170 -0
- package/dist/core/trajectory.d.ts +184 -0
- package/dist/core/trajectory.js +817 -0
- package/dist/core/trust-engine.d.ts +6 -0
- package/dist/core/trust-engine.js +50 -29
- package/dist/core/workspace-context.d.ts +13 -0
- package/dist/core/workspace-context.js +50 -7
- package/dist/hooks/gate.js +171 -87
- package/dist/hooks/llm.js +119 -71
- package/dist/hooks/pain.js +105 -5
- package/dist/hooks/prompt.d.ts +11 -14
- package/dist/hooks/prompt.js +283 -57
- package/dist/hooks/subagent.js +69 -28
- package/dist/hooks/trajectory-collector.d.ts +32 -0
- package/dist/hooks/trajectory-collector.js +256 -0
- package/dist/http/principles-console-route.d.ts +2 -0
- package/dist/http/principles-console-route.js +257 -0
- package/dist/i18n/commands.js +16 -0
- package/dist/index.js +105 -4
- package/dist/service/control-ui-query-service.d.ts +217 -0
- package/dist/service/control-ui-query-service.js +537 -0
- package/dist/service/empathy-observer-manager.d.ts +2 -0
- package/dist/service/empathy-observer-manager.js +43 -1
- package/dist/service/evolution-worker.d.ts +27 -0
- package/dist/service/evolution-worker.js +256 -41
- package/dist/service/runtime-summary-service.d.ts +79 -0
- package/dist/service/runtime-summary-service.js +319 -0
- package/dist/service/trajectory-service.d.ts +2 -0
- package/dist/service/trajectory-service.js +15 -0
- package/dist/tools/agent-spawn.d.ts +27 -6
- package/dist/tools/agent-spawn.js +339 -87
- package/dist/tools/deep-reflect.d.ts +27 -7
- package/dist/tools/deep-reflect.js +210 -121
- package/dist/types/event-types.d.ts +10 -2
- package/dist/types.d.ts +10 -0
- package/dist/types.js +5 -0
- package/openclaw.plugin.json +43 -11
- package/package.json +14 -4
- package/templates/langs/zh/skills/pd-daily/SKILL.md +97 -13
|
@@ -49,110 +49,359 @@ function buildSubagentSystemPrompt(agentDef, _task) {
|
|
|
49
49
|
// It will be appended to OpenClaw's minimal subagent prompt
|
|
50
50
|
return agentDef.systemPrompt;
|
|
51
51
|
}
|
|
52
|
+
const INTERNAL_AGENT_USAGE_GUIDANCE = 'pd_run_worker is only for Principles Disciple internal workers. ' +
|
|
53
|
+
'Use agents_list / sessions_list / sessions_spawn / sessions_send for peer agents or cross-session communication.';
|
|
54
|
+
function buildInternalAgentUsageMessage(availableAgents) {
|
|
55
|
+
return [
|
|
56
|
+
'pd_run_worker is reserved for Principles Disciple internal workers.',
|
|
57
|
+
`Allowed internal roles: ${availableAgents.join(', ')}`,
|
|
58
|
+
'Use `agents_list` to discover peer agent ids.',
|
|
59
|
+
'Use `sessions_spawn` to create or orchestrate another session.',
|
|
60
|
+
'Use `sessions_list` to inspect running sessions.',
|
|
61
|
+
'Use `sessions_send` to talk to another existing session.',
|
|
62
|
+
].join('\n');
|
|
63
|
+
}
|
|
64
|
+
function looksLikeSessionOrPeerCoordinationTask(task) {
|
|
65
|
+
const normalized = task.trim().toLowerCase();
|
|
66
|
+
if (!normalized)
|
|
67
|
+
return false;
|
|
68
|
+
const explicitMarkers = [
|
|
69
|
+
'sessions_send',
|
|
70
|
+
'sessions_spawn',
|
|
71
|
+
'sessions_list',
|
|
72
|
+
'agents_list',
|
|
73
|
+
'sessionkey',
|
|
74
|
+
'session key',
|
|
75
|
+
'sessionid',
|
|
76
|
+
'session id',
|
|
77
|
+
'agentid',
|
|
78
|
+
'agent id',
|
|
79
|
+
'other session',
|
|
80
|
+
'another session',
|
|
81
|
+
'peer agent',
|
|
82
|
+
'other agent',
|
|
83
|
+
'another agent',
|
|
84
|
+
'same-level agent',
|
|
85
|
+
'same level agent',
|
|
86
|
+
'cross-session',
|
|
87
|
+
'cross session',
|
|
88
|
+
'send a message to',
|
|
89
|
+
'message another session',
|
|
90
|
+
'talk to another session',
|
|
91
|
+
'同级智能体',
|
|
92
|
+
'另一个智能体',
|
|
93
|
+
'其他智能体',
|
|
94
|
+
'另一个会话',
|
|
95
|
+
'其他会话',
|
|
96
|
+
'跨会话',
|
|
97
|
+
'给另一个会话发消息',
|
|
98
|
+
];
|
|
99
|
+
return explicitMarkers.some((marker) => normalized.includes(marker));
|
|
100
|
+
}
|
|
52
101
|
/**
|
|
53
|
-
*
|
|
102
|
+
* Sanitize params for debug logging (remove sensitive values)
|
|
54
103
|
*/
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
104
|
+
function sanitizeParamsForLogging(params) {
|
|
105
|
+
const SENSITIVE_PATTERNS = /password|token|api[_-]?key|secret|credential|authorization|cookie|session/i;
|
|
106
|
+
const sanitized = {};
|
|
107
|
+
for (const [key, value] of Object.entries(params)) {
|
|
108
|
+
if (SENSITIVE_PATTERNS.test(key)) {
|
|
109
|
+
sanitized[key] = '[REDACTED]';
|
|
110
|
+
}
|
|
111
|
+
else if (typeof value === 'string' && value.length > 200) {
|
|
112
|
+
sanitized[key] = value.slice(0, 200) + '...[truncated]';
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
sanitized[key] = value;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return sanitized;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Helper to read string parameter from rawParams
|
|
122
|
+
* Supports both camelCase and snake_case parameter names
|
|
123
|
+
*/
|
|
124
|
+
function readStringParam(rawParams, key) {
|
|
125
|
+
const value = rawParams[key];
|
|
126
|
+
if (typeof value === 'string')
|
|
127
|
+
return value.trim() || undefined;
|
|
128
|
+
// Try snake_case alias
|
|
129
|
+
const snakeKey = key.replace(/([A-Z])/g, '_$1').toLowerCase();
|
|
130
|
+
const snakeValue = rawParams[snakeKey];
|
|
131
|
+
if (typeof snakeValue === 'string')
|
|
132
|
+
return snakeValue.trim() || undefined;
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Helper to read boolean parameter from rawParams
|
|
137
|
+
* Supports both camelCase and snake_case parameter names
|
|
138
|
+
*/
|
|
139
|
+
function readBooleanParam(rawParams, key) {
|
|
140
|
+
const value = rawParams[key];
|
|
141
|
+
if (typeof value === 'boolean')
|
|
142
|
+
return value;
|
|
143
|
+
// Try snake_case alias
|
|
144
|
+
const snakeKey = key.replace(/([A-Z])/g, '_$1').toLowerCase();
|
|
145
|
+
const snakeValue = rawParams[snakeKey];
|
|
146
|
+
if (typeof snakeValue === 'boolean')
|
|
147
|
+
return snakeValue;
|
|
148
|
+
// Backward compatibility for legacy prompt guidance / callers.
|
|
149
|
+
if (key === 'runInBackground' && typeof rawParams.async === 'boolean') {
|
|
150
|
+
return rawParams.async;
|
|
151
|
+
}
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Create Agent Spawn Tool
|
|
156
|
+
*
|
|
157
|
+
* Uses factory pattern to capture `api` in closure, following OpenClaw plugin SDK conventions.
|
|
158
|
+
* The execute signature must be: async (_toolCallId: string, rawParams: Record<string, unknown>)
|
|
159
|
+
*/
|
|
160
|
+
export function createAgentSpawnTool(api) {
|
|
161
|
+
return {
|
|
162
|
+
name: 'pd_run_worker',
|
|
163
|
+
description: `启动指定类型的子智能体执行任务。
|
|
58
164
|
|
|
59
165
|
可用的智能体类型:
|
|
60
166
|
- explorer: 快速收集证据(文件、日志、复现步骤)
|
|
61
167
|
- diagnostician: 根因分析(verb/adjective + 5Whys)
|
|
62
|
-
- auditor:
|
|
168
|
+
- auditor: 演演审计(axiom/system/via-negativa)
|
|
63
169
|
- planner: 制定电影剧本计划
|
|
64
170
|
- implementer: 按计划执行代码修改
|
|
65
171
|
- reviewer: 代码审查(正确性、安全性、可维护性)
|
|
66
|
-
- reporter:
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
172
|
+
- reporter: 最终汇报(技术细节转管理报告)
|
|
173
|
+
|
|
174
|
+
示例调用: pd_run_worker(agentType="diagnostician", task="分析 Pain 7386ccfb 的根因")`,
|
|
175
|
+
parameters: Type.Object({
|
|
176
|
+
agentType: Type.String({
|
|
177
|
+
description: '【必填】智能体类型,必须是以下之一: explorer, diagnostician, auditor, planner, implementer, reviewer, reporter',
|
|
178
|
+
}),
|
|
179
|
+
task: Type.String({
|
|
180
|
+
description: '【必填】任务描述,告诉智能体要做什么',
|
|
181
|
+
}),
|
|
182
|
+
runInBackground: Type.Optional(Type.Boolean({
|
|
183
|
+
description: '【可选】是否后台运行。true=立即返回不等待结果,false=等待执行完成。默认 false',
|
|
184
|
+
})),
|
|
73
185
|
}),
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Execution logic for the agent spawn tool
|
|
188
|
+
*
|
|
189
|
+
* OpenClaw tool execute signature:
|
|
190
|
+
* - First parameter: _toolCallId (string) - the tool call ID
|
|
191
|
+
* - Second parameter: rawParams (Record<string, unknown>) - the actual parameters
|
|
192
|
+
* - Third parameter (optional): signal (AbortSignal) - for cancellation
|
|
193
|
+
*/
|
|
194
|
+
async execute(_toolCallId, rawParams) {
|
|
195
|
+
const agentType = readStringParam(rawParams, 'agentType') || '';
|
|
196
|
+
const task = readStringParam(rawParams, 'task') || '';
|
|
197
|
+
const runAsync = readBooleanParam(rawParams, 'runInBackground') === true;
|
|
198
|
+
const availableInternalAgents = listAvailableAgents();
|
|
199
|
+
// Log summary at info level, full params at debug level
|
|
200
|
+
api.logger?.info?.(`[PD:AgentSpawn] toolCallId=${_toolCallId}, agentType=${agentType || 'MISSING'}, hasTask=${!!task}, taskLength=${task.length}, runInBackground=${runAsync}`);
|
|
201
|
+
api.logger?.debug?.(`[PD:AgentSpawn] Full rawParams: ${JSON.stringify(sanitizeParamsForLogging(rawParams))}`);
|
|
202
|
+
if (!agentType) {
|
|
203
|
+
api.logger?.warn?.(`[PD:AgentSpawn] Missing agentType, hasTask=${!!task}`);
|
|
204
|
+
return {
|
|
205
|
+
content: [{
|
|
206
|
+
type: 'text',
|
|
207
|
+
text: `❌ 缺少 agentType 参数。请按以下格式调用:
|
|
84
208
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
if (!agentDef) {
|
|
90
|
-
return `❌ 无法加载智能体定义: ${agentType}`;
|
|
91
|
-
}
|
|
92
|
-
// 3. Check subagent runtime availability
|
|
93
|
-
const subagentRuntime = api.runtime?.subagent;
|
|
94
|
-
if (!subagentRuntime) {
|
|
95
|
-
return `❌ Subagent runtime 不可用。请确保 OpenClaw Gateway 正在运行。`;
|
|
96
|
-
}
|
|
97
|
-
// 4. Build session key
|
|
98
|
-
const sessionKey = `agent:${agentType}:${randomUUID()}`;
|
|
99
|
-
// 5. Build system prompt
|
|
100
|
-
const extraSystemPrompt = buildSubagentSystemPrompt(agentDef, task);
|
|
101
|
-
const startTime = Date.now();
|
|
102
|
-
try {
|
|
103
|
-
// 6. Run subagent
|
|
104
|
-
await subagentRuntime.run({
|
|
105
|
-
sessionKey,
|
|
106
|
-
message: task,
|
|
107
|
-
extraSystemPrompt,
|
|
108
|
-
lane: 'subagent',
|
|
109
|
-
deliver: false, // Critical: don't send directly to external channels
|
|
110
|
-
idempotencyKey: randomUUID(),
|
|
111
|
-
});
|
|
112
|
-
// 7. Wait for completion
|
|
113
|
-
const result = await subagentRuntime.waitForRun({
|
|
114
|
-
runId: sessionKey,
|
|
115
|
-
});
|
|
116
|
-
const duration = Date.now() - startTime;
|
|
117
|
-
// 8. Handle timeout
|
|
118
|
-
if (result.status === 'timeout') {
|
|
119
|
-
return `⚠️ 智能体 **${agentDef.name}** 执行超时 (${(duration / 1000).toFixed(1)}s)。
|
|
209
|
+
pd_run_worker(
|
|
210
|
+
agentType="diagnostician", // 必填: explorer, diagnostician, auditor, planner, implementer, reviewer, reporter
|
|
211
|
+
task="分析问题的根因" // 必填: 任务描述
|
|
212
|
+
)
|
|
120
213
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
- 检查任务是否需要更多上下文`;
|
|
214
|
+
可用的智能体类型: ${availableInternalAgents.join(', ')}`
|
|
215
|
+
}]
|
|
216
|
+
};
|
|
125
217
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return
|
|
218
|
+
if (!task) {
|
|
219
|
+
api.logger?.warn?.(`[PD:AgentSpawn] Missing task for agentType=${agentType}`);
|
|
220
|
+
return {
|
|
221
|
+
content: [{
|
|
222
|
+
type: 'text',
|
|
223
|
+
text: `❌ 缺少 task 参数。请提供任务描述,例如:
|
|
224
|
+
|
|
225
|
+
pd_run_worker(
|
|
226
|
+
agentType="${agentType || 'diagnostician'}",
|
|
227
|
+
task="分析 Pain xxx 的根因"
|
|
228
|
+
)`
|
|
229
|
+
}]
|
|
230
|
+
};
|
|
129
231
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
232
|
+
if (looksLikeSessionOrPeerCoordinationTask(task)) {
|
|
233
|
+
api.logger?.warn?.(`[PD:AgentSpawn] Rejected likely peer/session misuse for task: ${task}`);
|
|
234
|
+
return {
|
|
235
|
+
content: [{
|
|
236
|
+
type: 'text',
|
|
237
|
+
text: buildInternalAgentUsageMessage(availableInternalAgents)
|
|
238
|
+
}]
|
|
239
|
+
};
|
|
135
240
|
}
|
|
136
|
-
|
|
137
|
-
|
|
241
|
+
if (!availableInternalAgents.includes(agentType)) {
|
|
242
|
+
return {
|
|
243
|
+
content: [{
|
|
244
|
+
type: 'text',
|
|
245
|
+
text: `❌ 未知的智能体类型: "${agentType}"
|
|
138
246
|
|
|
139
|
-
|
|
247
|
+
可用的智能体类型: ${availableInternalAgents.join(', ')}
|
|
140
248
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
249
|
+
示例: pd_run_worker(agentType="diagnostician", task="分析问题根因")`
|
|
250
|
+
}]
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
// Load agent definition
|
|
254
|
+
const agentDef = loadAgentDefinition(agentType);
|
|
255
|
+
if (!agentDef) {
|
|
256
|
+
return {
|
|
257
|
+
content: [{
|
|
258
|
+
type: 'text',
|
|
259
|
+
text: `❌ 无法加载智能体定义: ${agentType}`
|
|
260
|
+
}]
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
// Check subagent runtime availability
|
|
264
|
+
const subagentRuntime = api.runtime?.subagent;
|
|
265
|
+
if (!subagentRuntime) {
|
|
266
|
+
return {
|
|
267
|
+
content: [{
|
|
268
|
+
type: 'text',
|
|
269
|
+
text: `❌ Subagent runtime 不可用。请确保 OpenClaw Gateway 正在运行。`
|
|
270
|
+
}]
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
// Build session key
|
|
274
|
+
const sessionKey = `agent:${agentType}:${randomUUID()}`;
|
|
275
|
+
// Build system prompt
|
|
276
|
+
const extraSystemPrompt = buildSubagentSystemPrompt(agentDef, task);
|
|
277
|
+
const startTime = Date.now();
|
|
149
278
|
try {
|
|
150
|
-
|
|
279
|
+
// Run subagent
|
|
280
|
+
await subagentRuntime.run({
|
|
281
|
+
sessionKey,
|
|
282
|
+
message: task,
|
|
283
|
+
extraSystemPrompt,
|
|
284
|
+
lane: 'subagent',
|
|
285
|
+
deliver: false, // Critical: don't send directly to external channels
|
|
286
|
+
idempotencyKey: randomUUID(),
|
|
287
|
+
});
|
|
288
|
+
if (runAsync) {
|
|
289
|
+
const duration = Date.now() - startTime;
|
|
290
|
+
return {
|
|
291
|
+
content: [{
|
|
292
|
+
type: 'text',
|
|
293
|
+
text: `✅ 已在后台启动 **${agentDef.name}** (${(duration / 1000).toFixed(1)}s)。它不会阻塞当前对话。`
|
|
294
|
+
}]
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
// Wait for completion (with configurable timeout to prevent indefinite block)
|
|
298
|
+
const timeoutMs = api.config?.get?.('intervals.task_timeout_ms') || (30 * 60 * 1000);
|
|
299
|
+
const result = await subagentRuntime.waitForRun({
|
|
300
|
+
runId: sessionKey,
|
|
301
|
+
timeoutMs,
|
|
302
|
+
});
|
|
303
|
+
const duration = Date.now() - startTime;
|
|
304
|
+
// Handle timeout
|
|
305
|
+
if (result.status === 'timeout') {
|
|
306
|
+
return {
|
|
307
|
+
content: [{
|
|
308
|
+
type: 'text',
|
|
309
|
+
text: `⚠️ 智能体 **${agentDef.name}** 执行超时 (${(duration / 1000).toFixed(1)}s)。
|
|
310
|
+
|
|
311
|
+
建议:
|
|
312
|
+
- 简化任务描述
|
|
313
|
+
- 分解为多个子任务
|
|
314
|
+
- 检查任务是否需要更多上下文`
|
|
315
|
+
}]
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
// Handle error
|
|
319
|
+
if (result.status === 'error') {
|
|
320
|
+
return {
|
|
321
|
+
content: [{
|
|
322
|
+
type: 'text',
|
|
323
|
+
text: `❌ 智能体 **${agentDef.name}** 执行失败: ${result.error || '未知错误'}`
|
|
324
|
+
}]
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
// Get results
|
|
328
|
+
const messages = await subagentRuntime.getSessionMessages({ sessionKey });
|
|
329
|
+
const output = extractAssistantText(messages);
|
|
330
|
+
if (!output || output.trim() === '') {
|
|
331
|
+
return {
|
|
332
|
+
content: [{
|
|
333
|
+
type: 'text',
|
|
334
|
+
text: `⚠️ 智能体 **${agentDef.name}** 执行完成,但没有返回输出。`
|
|
335
|
+
}]
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
// Return formatted result
|
|
339
|
+
return {
|
|
340
|
+
content: [{
|
|
341
|
+
type: 'text',
|
|
342
|
+
text: `✅ **${agentDef.name}** 执行完成 (${(duration / 1000).toFixed(1)}s)
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
${output}`
|
|
347
|
+
}]
|
|
348
|
+
};
|
|
151
349
|
}
|
|
152
|
-
catch {
|
|
153
|
-
|
|
350
|
+
catch (err) {
|
|
351
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
352
|
+
return {
|
|
353
|
+
content: [{
|
|
354
|
+
type: 'text',
|
|
355
|
+
text: `❌ 智能体 **${agentDef.name}** 执行异常: ${errorMsg}`
|
|
356
|
+
}]
|
|
357
|
+
};
|
|
154
358
|
}
|
|
155
|
-
|
|
359
|
+
finally {
|
|
360
|
+
// Cleanup session (P1 fix: log failures instead of silent swallow)
|
|
361
|
+
if (!runAsync) {
|
|
362
|
+
try {
|
|
363
|
+
await subagentRuntime.deleteSession({ sessionKey });
|
|
364
|
+
}
|
|
365
|
+
catch (cleanupErr) {
|
|
366
|
+
const cleanupErrMsg = cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr);
|
|
367
|
+
api.logger?.error?.(`[PD:AgentSpawn] Failed to cleanup session ${sessionKey}: ${cleanupErrMsg}`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
// Legacy export for backward compatibility with internal code
|
|
375
|
+
// This is the "unconfigured" tool that needs to be created via createAgentSpawnTool()
|
|
376
|
+
export const agentSpawnTool = {
|
|
377
|
+
name: 'pd_run_worker',
|
|
378
|
+
description: `启动指定类型的子智能体执行任务。
|
|
379
|
+
|
|
380
|
+
可用的智能体类型:
|
|
381
|
+
- explorer: 快速收集证据(文件、日志、复现步骤)
|
|
382
|
+
- diagnostician: 根因分析(verb/adjective + 5Whys)
|
|
383
|
+
- auditor: 演演审计(axiom/system/via-negativa)
|
|
384
|
+
- planner: 制定电影剧本计划
|
|
385
|
+
- implementer: 按计划执行代码修改
|
|
386
|
+
- reviewer: 代码审查(正确性、安全性、可维护性)
|
|
387
|
+
- reporter: 最终汇报(技术细节转管理报告)
|
|
388
|
+
|
|
389
|
+
示例调用: pd_run_worker(agentType="diagnostician", task="分析 Pain 7386ccfb 的根因")`,
|
|
390
|
+
parameters: Type.Object({
|
|
391
|
+
agentType: Type.String({
|
|
392
|
+
description: '【必填】智能体类型,必须是以下之一: explorer, diagnostician, auditor, planner, implementer, reviewer, reporter',
|
|
393
|
+
}),
|
|
394
|
+
task: Type.String({
|
|
395
|
+
description: '【必填】任务描述,告诉智能体要做什么',
|
|
396
|
+
}),
|
|
397
|
+
runInBackground: Type.Optional(Type.Boolean({
|
|
398
|
+
description: '【可选】是否后台运行。true=立即返回不等待结果,false=等待执行完成。默认 false',
|
|
399
|
+
})),
|
|
400
|
+
}),
|
|
401
|
+
// This execute method throws to prevent accidental usage of the unconfigured tool
|
|
402
|
+
execute: () => {
|
|
403
|
+
throw new Error('agentSpawnTool is a metadata-only export. ' +
|
|
404
|
+
'Use createAgentSpawnTool(api) to get an executable instance.');
|
|
156
405
|
},
|
|
157
406
|
};
|
|
158
407
|
/**
|
|
@@ -161,10 +410,13 @@ ${output}`;
|
|
|
161
410
|
*/
|
|
162
411
|
export async function spawnAgentSequence(agents, api, onProgress) {
|
|
163
412
|
const results = new Map();
|
|
413
|
+
const tool = createAgentSpawnTool(api);
|
|
164
414
|
for (const { type, task } of agents) {
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
415
|
+
const toolCallId = `spawn-sequence-${type}-${randomUUID()}`;
|
|
416
|
+
const result = await tool.execute(toolCallId, { agentType: type, task });
|
|
417
|
+
const text = result.content[0]?.text || '';
|
|
418
|
+
results.set(type, text);
|
|
419
|
+
onProgress?.(type, text);
|
|
168
420
|
}
|
|
169
421
|
return results;
|
|
170
422
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { OpenClawPluginApi } from '../openclaw-sdk.js';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Create Deep Reflect Tool
|
|
4
|
+
*
|
|
5
|
+
* Uses factory pattern to capture `api` in closure, following OpenClaw plugin SDK conventions.
|
|
6
|
+
* The execute signature must be: async (_toolCallId: string, rawParams: Record<string, unknown>)
|
|
7
|
+
*/
|
|
8
|
+
export declare function createDeepReflectTool(api: OpenClawPluginApi): {
|
|
3
9
|
name: string;
|
|
4
10
|
description: string;
|
|
5
11
|
parameters: import("@sinclair/typebox").TObject<{
|
|
@@ -9,11 +15,25 @@ export declare const deepReflectTool: {
|
|
|
9
15
|
}>;
|
|
10
16
|
/**
|
|
11
17
|
* Tool execution logic
|
|
12
|
-
*
|
|
18
|
+
*
|
|
19
|
+
* OpenClaw tool execute signature:
|
|
20
|
+
* - First parameter: _toolCallId (string) - the tool call ID
|
|
21
|
+
* - Second parameter: rawParams (Record<string, unknown>) - the actual parameters
|
|
22
|
+
* - Third parameter (optional): signal (AbortSignal) - for cancellation
|
|
13
23
|
*/
|
|
14
|
-
execute(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
execute(_toolCallId: string, rawParams: Record<string, unknown>): Promise<{
|
|
25
|
+
content: Array<{
|
|
26
|
+
type: string;
|
|
27
|
+
text: string;
|
|
28
|
+
}>;
|
|
29
|
+
}>;
|
|
30
|
+
};
|
|
31
|
+
export declare const deepReflectTool: {
|
|
32
|
+
name: string;
|
|
33
|
+
description: string;
|
|
34
|
+
parameters: import("@sinclair/typebox").TObject<{
|
|
35
|
+
context: import("@sinclair/typebox").TString;
|
|
36
|
+
depth: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
37
|
+
model_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
38
|
+
}>;
|
|
19
39
|
};
|