@f2a/openclaw-adapter 0.1.0 → 0.2.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 (61) hide show
  1. package/dist/announcement-queue.d.ts +72 -1
  2. package/dist/announcement-queue.d.ts.map +1 -1
  3. package/dist/announcement-queue.js +145 -20
  4. package/dist/announcement-queue.js.map +1 -1
  5. package/dist/claim-handlers.d.ts +75 -0
  6. package/dist/claim-handlers.d.ts.map +1 -0
  7. package/dist/claim-handlers.js +368 -0
  8. package/dist/claim-handlers.js.map +1 -0
  9. package/dist/connector.d.ts +46 -18
  10. package/dist/connector.d.ts.map +1 -1
  11. package/dist/connector.js +319 -592
  12. package/dist/connector.js.map +1 -1
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +2 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/logger.d.ts +28 -0
  18. package/dist/logger.d.ts.map +1 -0
  19. package/dist/logger.js +44 -0
  20. package/dist/logger.js.map +1 -0
  21. package/dist/network-client.d.ts +17 -1
  22. package/dist/network-client.d.ts.map +1 -1
  23. package/dist/network-client.js +119 -23
  24. package/dist/network-client.js.map +1 -1
  25. package/dist/node-manager.d.ts +20 -0
  26. package/dist/node-manager.d.ts.map +1 -1
  27. package/dist/node-manager.js +194 -18
  28. package/dist/node-manager.js.map +1 -1
  29. package/dist/plugin.d.ts +1 -1
  30. package/dist/plugin.d.ts.map +1 -1
  31. package/dist/plugin.js +4 -5
  32. package/dist/plugin.js.map +1 -1
  33. package/dist/reputation.d.ts +85 -1
  34. package/dist/reputation.d.ts.map +1 -1
  35. package/dist/reputation.js +222 -9
  36. package/dist/reputation.js.map +1 -1
  37. package/dist/task-guard.d.ts +82 -0
  38. package/dist/task-guard.d.ts.map +1 -1
  39. package/dist/task-guard.js +449 -16
  40. package/dist/task-guard.js.map +1 -1
  41. package/dist/task-queue.d.ts +55 -7
  42. package/dist/task-queue.d.ts.map +1 -1
  43. package/dist/task-queue.js +477 -12
  44. package/dist/task-queue.js.map +1 -1
  45. package/dist/tool-handlers.d.ts +158 -0
  46. package/dist/tool-handlers.d.ts.map +1 -0
  47. package/dist/tool-handlers.js +724 -0
  48. package/dist/tool-handlers.js.map +1 -0
  49. package/dist/types.d.ts +112 -15
  50. package/dist/types.d.ts.map +1 -1
  51. package/dist/types.js +23 -0
  52. package/dist/types.js.map +1 -1
  53. package/dist/webhook-pusher.d.ts +71 -0
  54. package/dist/webhook-pusher.d.ts.map +1 -0
  55. package/dist/webhook-pusher.js +174 -0
  56. package/dist/webhook-pusher.js.map +1 -0
  57. package/dist/webhook-server.d.ts +8 -1
  58. package/dist/webhook-server.d.ts.map +1 -1
  59. package/dist/webhook-server.js +65 -7
  60. package/dist/webhook-server.js.map +1 -1
  61. package/package.json +21 -8
@@ -0,0 +1,724 @@
1
+ "use strict";
2
+ /**
3
+ * F2A OpenClaw Connector - Tool Handlers
4
+ * 工具处理器模块 - 处理 f2a_discover, f2a_delegate 等工具
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ToolHandlers = void 0;
8
+ const logger_js_1 = require("./logger.js");
9
+ /**
10
+ * 工具处理器类
11
+ * 包含所有核心工具的处理逻辑
12
+ */
13
+ class ToolHandlers {
14
+ adapter;
15
+ constructor(adapter) {
16
+ this.adapter = adapter;
17
+ }
18
+ /**
19
+ * 处理 f2a_discover 工具
20
+ * 发现 F2A 网络中的 Agents
21
+ */
22
+ async handleDiscover(params, context) {
23
+ const networkClient = this.adapter.networkClient;
24
+ const reputationSystem = this.adapter.reputationSystem;
25
+ const result = await networkClient.discoverAgents(params.capability);
26
+ if (!result.success) {
27
+ return { content: `发现失败: ${result.error}` };
28
+ }
29
+ let agents = result.data || [];
30
+ // 过滤信誉
31
+ if (params.min_reputation !== undefined) {
32
+ agents = agents.filter((a) => {
33
+ const rep = reputationSystem.getReputation(a.peerId);
34
+ return rep.score >= params.min_reputation;
35
+ });
36
+ }
37
+ if (agents.length === 0) {
38
+ return { content: '🔍 未发现符合条件的 Agents' };
39
+ }
40
+ const content = `
41
+ 🔍 发现 ${agents.length} 个 Agents:
42
+
43
+ ${agents.map((a, i) => {
44
+ const rep = reputationSystem.getReputation(a.peerId);
45
+ return `${i + 1}. ${a.displayName} (信誉: ${rep.score})
46
+ ID: ${a.peerId.slice(0, 20)}...
47
+ 能力: ${a.capabilities?.map(c => c.name).join(', ') || '无'}`;
48
+ }).join('\n\n')}
49
+
50
+ 💡 使用方式:
51
+ - 委托任务: 让 ${agents[0]?.displayName} 帮我写代码
52
+ - 指定ID: 委托给 #1 分析数据
53
+ `.trim();
54
+ return {
55
+ content,
56
+ data: { agents, count: agents.length }
57
+ };
58
+ }
59
+ /**
60
+ * 处理 f2a_delegate 工具
61
+ * 委托任务给特定 Agent
62
+ */
63
+ async handleDelegate(params, context) {
64
+ // 输入验证
65
+ if (!params.agent || typeof params.agent !== 'string' || params.agent.trim() === '') {
66
+ return { content: '❌ 请提供有效的 agent 参数(Agent ID、名称或 #索引)' };
67
+ }
68
+ if (!params.task || typeof params.task !== 'string' || params.task.trim() === '') {
69
+ return { content: '❌ 请提供有效的 task 参数(任务描述)' };
70
+ }
71
+ const networkClient = this.adapter.networkClient;
72
+ const reputationSystem = this.adapter.reputationSystem;
73
+ // 解析 Agent 引用
74
+ const targetAgent = await this.resolveAgent(params.agent);
75
+ if (!targetAgent) {
76
+ return { content: `❌ 找不到 Agent: ${params.agent}` };
77
+ }
78
+ // 检查信誉
79
+ if (!reputationSystem.isAllowed(targetAgent.peerId)) {
80
+ return {
81
+ content: `⚠️ ${targetAgent.displayName} 信誉过低 (${reputationSystem.getReputation(targetAgent.peerId).score}),建议谨慎委托`
82
+ };
83
+ }
84
+ logger_js_1.pluginLogger.info(`委托任务给 ${targetAgent.displayName}...`);
85
+ const result = await networkClient.delegateTask({
86
+ peerId: targetAgent.peerId,
87
+ taskType: 'openclaw-task',
88
+ description: params.task,
89
+ parameters: {
90
+ context: params.context,
91
+ sessionContext: context.toJSON()
92
+ },
93
+ timeout: params.timeout || 60000
94
+ });
95
+ if (!result.success) {
96
+ // 记录失败
97
+ reputationSystem.recordFailure(targetAgent.peerId, 'unknown', result.error.message);
98
+ return { content: `❌ 委托失败: ${result.error.message}` };
99
+ }
100
+ return {
101
+ content: `✅ ${targetAgent.displayName} 已完成任务:\n\n${JSON.stringify(result.data, null, 2)}`,
102
+ data: result.data
103
+ };
104
+ }
105
+ /**
106
+ * 处理 f2a_broadcast 工具
107
+ * 广播任务给所有具备某能力的 Agents
108
+ */
109
+ async handleBroadcast(params, context) {
110
+ // 输入验证
111
+ if (!params.capability || typeof params.capability !== 'string' || params.capability.trim() === '') {
112
+ return { content: '❌ 请提供有效的 capability 参数(所需能力)' };
113
+ }
114
+ if (!params.task || typeof params.task !== 'string' || params.task.trim() === '') {
115
+ return { content: '❌ 请提供有效的 task 参数(任务描述)' };
116
+ }
117
+ const networkClient = this.adapter.networkClient;
118
+ const discoverResult = await networkClient.discoverAgents(params.capability);
119
+ if (!discoverResult.success || !discoverResult.data?.length) {
120
+ return { content: `❌ 未发现具备 "${params.capability}" 能力的 Agents` };
121
+ }
122
+ const agents = discoverResult.data;
123
+ logger_js_1.pluginLogger.info(`广播任务给 ${agents.length} 个 Agents...`);
124
+ // 并行委托
125
+ const promises = agents.map(async (agent) => {
126
+ const start = Date.now();
127
+ const result = await networkClient.delegateTask({
128
+ peerId: agent.peerId,
129
+ taskType: 'openclaw-task',
130
+ description: params.task,
131
+ parameters: { sessionContext: context.toJSON() },
132
+ timeout: 60000
133
+ });
134
+ const latency = Date.now() - start;
135
+ return {
136
+ agent: agent.displayName,
137
+ peerId: agent.peerId,
138
+ success: result.success,
139
+ result: result.data,
140
+ error: result.success ? undefined : (result.error?.message || 'Unknown error'),
141
+ latency
142
+ };
143
+ });
144
+ const results = await Promise.allSettled(promises);
145
+ const settled = results.map((r, i) => r.status === 'fulfilled' ? r.value : {
146
+ agent: agents[i].displayName,
147
+ success: false,
148
+ error: String(r.reason)
149
+ });
150
+ const successful = settled.filter(r => r.success);
151
+ const minResponses = params.min_responses || 1;
152
+ if (successful.length < minResponses) {
153
+ return {
154
+ content: `⚠️ 仅 ${successful.length} 个成功响应(需要 ${minResponses})\n\n${this.formatBroadcastResults(settled)}`
155
+ };
156
+ }
157
+ return {
158
+ content: `✅ 收到 ${successful.length}/${settled.length} 个成功响应:\n\n${this.formatBroadcastResults(settled)}`,
159
+ data: { results: settled }
160
+ };
161
+ }
162
+ /**
163
+ * 处理 f2a_status 工具
164
+ * 查看网络状态
165
+ */
166
+ async handleStatus(params, context) {
167
+ const nodeManager = this.adapter.nodeManager;
168
+ const networkClient = this.adapter.networkClient;
169
+ const taskQueue = this.adapter.taskQueue;
170
+ const reputationSystem = this.adapter.reputationSystem;
171
+ const [nodeStatus, peersResult] = await Promise.all([
172
+ nodeManager.getStatus(),
173
+ networkClient.getConnectedPeers()
174
+ ]);
175
+ if (!nodeStatus.success) {
176
+ return { content: `❌ 获取状态失败: ${nodeStatus.error}` };
177
+ }
178
+ const peers = peersResult.success ? (peersResult.data || []) : [];
179
+ const taskStats = taskQueue.getStats();
180
+ const content = `
181
+ 🟢 F2A 状态: ${nodeStatus.data?.running ? '运行中' : '已停止'}
182
+ 📡 本机 PeerID: ${nodeStatus.data?.peerId || 'N/A'}
183
+ ⏱️ 运行时间: ${nodeStatus.data?.uptime ? Math.floor(nodeStatus.data.uptime / 60) + ' 分钟' : 'N/A'}
184
+ 🔗 已连接 Peers: ${peers.length}
185
+ 📋 任务队列: ${taskStats.pending} 待处理, ${taskStats.processing} 处理中, ${taskStats.completed} 已完成
186
+
187
+ ${peers.map((p) => {
188
+ const rep = reputationSystem.getReputation(p.peerId);
189
+ return ` • ${p.agentInfo?.displayName || 'Unknown'} (信誉: ${rep.score})\n ID: ${p.peerId.slice(0, 20)}...`;
190
+ }).join('\n')}
191
+ `.trim();
192
+ return { content, data: { status: nodeStatus.data, peers, taskStats } };
193
+ }
194
+ /**
195
+ * 处理 f2a_reputation 工具
196
+ * 查看或管理 Peer 信誉
197
+ */
198
+ async handleReputation(params, context) {
199
+ // 输入验证
200
+ if (!params.action || !['list', 'view', 'block', 'unblock'].includes(params.action)) {
201
+ return { content: '❌ action 参数必须是 list, view, block 或 unblock' };
202
+ }
203
+ if ((params.action === 'view' || params.action === 'block' || params.action === 'unblock') &&
204
+ (!params.peer_id || typeof params.peer_id !== 'string' || params.peer_id.trim() === '')) {
205
+ return { content: '❌ view/block/unblock 操作需要提供 peer_id 参数' };
206
+ }
207
+ const reputationSystem = this.adapter.reputationSystem;
208
+ const config = this.adapter.config;
209
+ switch (params.action) {
210
+ case 'list': {
211
+ const reps = reputationSystem.getAllReputations();
212
+ return {
213
+ content: `📊 信誉记录 (${reps.length} 条):\n\n${reps.map((r) => ` ${r.peerId.slice(0, 20)}...: ${r.score} (成功: ${r.successfulTasks}, 失败: ${r.failedTasks})`).join('\n')}`
214
+ };
215
+ }
216
+ case 'view': {
217
+ if (!params.peer_id) {
218
+ return { content: '❌ 请提供 peer_id' };
219
+ }
220
+ const rep = reputationSystem.getReputation(params.peer_id);
221
+ return {
222
+ content: `📊 Peer ${params.peer_id.slice(0, 20)}...:\n` +
223
+ ` 信誉分: ${rep.score}\n` +
224
+ ` 成功任务: ${rep.successfulTasks}\n` +
225
+ ` 失败任务: ${rep.failedTasks}\n` +
226
+ ` 平均响应: ${rep.avgResponseTime.toFixed(0)}ms\n` +
227
+ ` 最后交互: ${new Date(rep.lastInteraction).toLocaleString()}`
228
+ };
229
+ }
230
+ case 'block': {
231
+ if (!params.peer_id) {
232
+ return { content: '❌ 请提供 peer_id' };
233
+ }
234
+ if (!config.security) {
235
+ config.security = { requireConfirmation: false, whitelist: [], blacklist: [], maxTasksPerMinute: 10 };
236
+ }
237
+ config.security.blacklist.push(params.peer_id);
238
+ return { content: `🚫 已屏蔽 ${params.peer_id.slice(0, 20)}...` };
239
+ }
240
+ case 'unblock': {
241
+ if (!params.peer_id) {
242
+ return { content: '❌ 请提供 peer_id' };
243
+ }
244
+ if (!config.security) {
245
+ config.security = { requireConfirmation: false, whitelist: [], blacklist: [], maxTasksPerMinute: 10 };
246
+ }
247
+ config.security.blacklist = config.security.blacklist.filter((id) => id !== params.peer_id);
248
+ return { content: `✅ 已解除屏蔽 ${params.peer_id.slice(0, 20)}...` };
249
+ }
250
+ default:
251
+ return { content: `❌ 未知操作: ${params.action}` };
252
+ }
253
+ }
254
+ /**
255
+ * 处理 f2a_poll_tasks 工具
256
+ * 查询任务队列
257
+ */
258
+ async handlePollTasks(params, context) {
259
+ // 输入验证
260
+ if (params.limit !== undefined && (typeof params.limit !== 'number' || params.limit < 1 || params.limit > 100)) {
261
+ return { content: '❌ limit 参数必须是 1-100 之间的数字' };
262
+ }
263
+ if (params.status !== undefined && !['pending', 'processing', 'completed', 'failed'].includes(params.status)) {
264
+ return { content: '❌ status 参数必须是 pending, processing, completed 或 failed' };
265
+ }
266
+ const taskQueue = this.adapter.taskQueue;
267
+ let tasks;
268
+ if (params.status) {
269
+ // 按状态过滤时不改变任务状态(只是查看)
270
+ tasks = taskQueue.getAll().filter((t) => t.status === params.status);
271
+ }
272
+ else {
273
+ // 默认返回待处理任务,并标记为 processing(防止重复执行)
274
+ tasks = taskQueue.getPending(params.limit || 10);
275
+ // 将返回的任务标记为 processing,防止重复获取
276
+ for (const task of tasks) {
277
+ taskQueue.markProcessing(task.taskId);
278
+ }
279
+ if (tasks.length > 0) {
280
+ logger_js_1.pluginLogger.info(`已将 ${tasks.length} 个任务标记为 processing`);
281
+ }
282
+ }
283
+ if (tasks.length === 0) {
284
+ return { content: '📭 没有符合条件的任务' };
285
+ }
286
+ const content = `
287
+ 📋 任务列表 (${tasks.length} 个):
288
+
289
+ ${tasks.map(t => {
290
+ const statusIcon = {
291
+ pending: '⏳',
292
+ processing: '🔄',
293
+ completed: '✅',
294
+ failed: '❌'
295
+ }[t.status];
296
+ return `${statusIcon} [${t.taskId.slice(0, 8)}...] ${t.description.slice(0, 50)}${t.description.length > 50 ? '...' : ''}
297
+ 来自: ${t.from.slice(0, 16)}...
298
+ 类型: ${t.taskType} | 状态: ${t.status} | 创建: ${new Date(t.createdAt).toLocaleTimeString()}`;
299
+ }).join('\n\n')}
300
+
301
+ 💡 使用方式:
302
+ - 查看详情: 使用 task_id 查询
303
+ - 提交结果: f2a_submit_result 工具
304
+ `.trim();
305
+ return {
306
+ content,
307
+ data: {
308
+ count: tasks.length,
309
+ tasks: tasks.map(t => ({
310
+ taskId: t.taskId,
311
+ from: t.from,
312
+ description: t.description,
313
+ taskType: t.taskType,
314
+ parameters: t.parameters,
315
+ status: t.status,
316
+ createdAt: t.createdAt,
317
+ timeout: t.timeout
318
+ }))
319
+ }
320
+ };
321
+ }
322
+ /**
323
+ * 处理 f2a_submit_result 工具
324
+ * 提交任务结果
325
+ */
326
+ async handleSubmitResult(params, context) {
327
+ // 输入验证
328
+ if (!params.task_id || typeof params.task_id !== 'string' || params.task_id.trim() === '') {
329
+ return { content: '❌ 请提供有效的 task_id 参数' };
330
+ }
331
+ if (!params.result || typeof params.result !== 'string') {
332
+ return { content: '❌ 请提供有效的 result 参数' };
333
+ }
334
+ if (params.status !== 'success' && params.status !== 'error') {
335
+ return { content: '❌ status 参数必须是 success 或 error' };
336
+ }
337
+ const taskQueue = this.adapter.taskQueue;
338
+ const networkClient = this.adapter.networkClient;
339
+ const reputationSystem = this.adapter.reputationSystem;
340
+ // 查找任务
341
+ const task = taskQueue.get(params.task_id);
342
+ if (!task) {
343
+ return { content: `❌ 找不到任务: ${params.task_id}` };
344
+ }
345
+ // 更新任务状态
346
+ const response = {
347
+ taskId: params.task_id,
348
+ status: params.status,
349
+ result: params.status === 'success' ? params.result : undefined,
350
+ error: params.status === 'error' ? params.result : undefined,
351
+ latency: Date.now() - task.createdAt
352
+ };
353
+ taskQueue.complete(params.task_id, response);
354
+ // 发送响应给原节点
355
+ const sendResult = await networkClient.sendTaskResponse(task.from, response);
356
+ if (!sendResult.success) {
357
+ return {
358
+ content: `⚠️ 结果已记录,但发送给原节点失败: ${sendResult.error}`,
359
+ data: { taskId: params.task_id, sent: false }
360
+ };
361
+ }
362
+ // 更新信誉
363
+ if (params.status === 'success') {
364
+ reputationSystem.recordSuccess(task.from, params.task_id, response.latency);
365
+ }
366
+ else {
367
+ reputationSystem.recordFailure(task.from, params.task_id, params.result);
368
+ }
369
+ return {
370
+ content: `✅ 任务结果已提交并发送给原节点\n 任务ID: ${params.task_id.slice(0, 16)}...\n 状态: ${params.status}\n 响应时间: ${response.latency}ms`,
371
+ data: { taskId: params.task_id, sent: true, latency: response.latency }
372
+ };
373
+ }
374
+ /**
375
+ * 处理 f2a_task_stats 工具
376
+ * 查看任务队列统计
377
+ */
378
+ async handleTaskStats(params, context) {
379
+ const taskQueue = this.adapter.taskQueue;
380
+ const stats = taskQueue.getStats();
381
+ const content = `
382
+ 📊 任务队列统计:
383
+
384
+ ⏳ 待处理: ${stats.pending}
385
+ 🔄 处理中: ${stats.processing}
386
+ ✅ 已完成: ${stats.completed}
387
+ ❌ 失败: ${stats.failed}
388
+ 📦 总计: ${stats.total}
389
+
390
+ 💡 使用 f2a_poll_tasks 查看详细任务列表
391
+ `.trim();
392
+ return { content, data: stats };
393
+ }
394
+ // ========== Helper Methods ==========
395
+ /**
396
+ * 解析 Agent 引用
397
+ */
398
+ async resolveAgent(agentRef) {
399
+ const networkClient = this.adapter.networkClient;
400
+ const result = await networkClient.discoverAgents();
401
+ if (!result.success)
402
+ return null;
403
+ const agents = result.data || [];
404
+ // #索引格式
405
+ if (agentRef.startsWith('#')) {
406
+ const index = parseInt(agentRef.slice(1)) - 1;
407
+ return agents[index] || null;
408
+ }
409
+ // 精确匹配
410
+ const exact = agents.find((a) => a.peerId === agentRef ||
411
+ a.displayName === agentRef);
412
+ if (exact)
413
+ return exact;
414
+ // 模糊匹配
415
+ const fuzzy = agents.find((a) => a.peerId.startsWith(agentRef) ||
416
+ a.displayName.toLowerCase().includes(agentRef.toLowerCase()));
417
+ return fuzzy || null;
418
+ }
419
+ /**
420
+ * 格式化广播结果
421
+ */
422
+ formatBroadcastResults(results) {
423
+ return results.map(r => {
424
+ const icon = r.success ? '✅' : '❌';
425
+ const latency = r.latency ? ` (${r.latency}ms)` : '';
426
+ return `${icon} ${r.agent}${latency}\n ${r.success ? '完成' : `失败: ${r.error}`}`;
427
+ }).join('\n\n');
428
+ }
429
+ // ========== 任务评估相关工具 ==========
430
+ /**
431
+ * 处理 f2a_estimate_task 工具
432
+ * 评估任务成本
433
+ */
434
+ async handleEstimateTask(params, context) {
435
+ // 输入验证
436
+ if (!params.task_type || typeof params.task_type !== 'string' || params.task_type.trim() === '') {
437
+ return { content: '❌ 请提供有效的 task_type 参数(任务类型)' };
438
+ }
439
+ if (!params.description || typeof params.description !== 'string' || params.description.trim() === '') {
440
+ return { content: '❌ 请提供有效的 description 参数(任务描述)' };
441
+ }
442
+ // 基于任务类型和描述估算工作量
443
+ const estimation = this.estimateTaskComplexity(params.task_type, params.description, params.required_capabilities || []);
444
+ const content = `
445
+ 📊 任务评估结果:
446
+
447
+ 🏷️ 任务类型: ${params.task_type}
448
+ 📝 描述: ${params.description.slice(0, 100)}${params.description.length > 100 ? '...' : ''}
449
+ 🔧 所需能力: ${params.required_capabilities?.join(', ') || '无特定要求'}
450
+
451
+ 📈 评估指标:
452
+ • 工作量: ${estimation.workload}/100
453
+ • 复杂度: ${estimation.complexity}/10
454
+ • 预估时间: ${this.formatDuration(estimation.estimated_time_ms)}
455
+ • 置信度: ${(estimation.confidence * 100).toFixed(0)}%
456
+ `.trim();
457
+ return {
458
+ content,
459
+ data: estimation
460
+ };
461
+ }
462
+ /**
463
+ * 处理 f2a_review_task 工具
464
+ * 作为评审者评审任务
465
+ */
466
+ async handleReviewTask(params, context) {
467
+ // 输入验证
468
+ if (!params.task_id || typeof params.task_id !== 'string' || params.task_id.trim() === '') {
469
+ return { content: '❌ 请提供有效的 task_id 参数' };
470
+ }
471
+ if (typeof params.workload !== 'number' || params.workload < 0 || params.workload > 100) {
472
+ return { content: '❌ workload 参数必须是 0-100 之间的数字' };
473
+ }
474
+ if (typeof params.value !== 'number' || params.value < -100 || params.value > 100) {
475
+ return { content: '❌ value 参数必须是 -100 到 100 之间的数字' };
476
+ }
477
+ const reviewCommittee = this.adapter.reviewCommittee;
478
+ const reputationSystem = this.adapter.reputationSystem;
479
+ if (!reviewCommittee) {
480
+ return { content: '❌ 评审系统未初始化' };
481
+ }
482
+ // 获取评审者 ID(从 context 或使用默认)
483
+ const reviewerId = context.sessionId || 'anonymous-reviewer';
484
+ // 检查评审者资格
485
+ if (!reputationSystem.hasPermission(reviewerId, 'review')) {
486
+ return { content: '❌ 您的信誉等级不足以进行评审' };
487
+ }
488
+ // 提交评审
489
+ const result = reviewCommittee.submitReview({
490
+ taskId: params.task_id,
491
+ reviewerId,
492
+ dimensions: {
493
+ workload: params.workload,
494
+ value: params.value
495
+ },
496
+ riskFlags: params.risk_flags,
497
+ comment: params.comment,
498
+ timestamp: Date.now()
499
+ });
500
+ if (!result.success) {
501
+ return { content: `❌ 评审提交失败: ${result.message}` };
502
+ }
503
+ // 检查评审是否完成
504
+ const isComplete = reviewCommittee.isReviewComplete(params.task_id);
505
+ const content = `
506
+ ✅ 评审已提交
507
+
508
+ 📋 任务ID: ${params.task_id.slice(0, 16)}...
509
+ 📊 您的评审:
510
+ • 工作量: ${params.workload}/100
511
+ • 价值分: ${params.value}
512
+ ${params.risk_flags?.length ? `• 风险标记: ${params.risk_flags.join(', ')}` : ''}
513
+ ${params.comment ? `• 评论: ${params.comment}` : ''}
514
+
515
+ ${isComplete ? '🎉 评审已完成,可以使用 f2a_get_reviews 查看最终结果' : '⏳ 等待其他评审者...'}
516
+ `.trim();
517
+ return {
518
+ content,
519
+ data: {
520
+ taskId: params.task_id,
521
+ submitted: true,
522
+ reviewComplete: isComplete
523
+ }
524
+ };
525
+ }
526
+ /**
527
+ * 处理 f2a_get_reviews 工具
528
+ * 获取任务的评审结果
529
+ */
530
+ async handleGetReviews(params, context) {
531
+ // 输入验证
532
+ if (!params.task_id || typeof params.task_id !== 'string' || params.task_id.trim() === '') {
533
+ return { content: '❌ 请提供有效的 task_id 参数' };
534
+ }
535
+ const reviewCommittee = this.adapter.reviewCommittee;
536
+ if (!reviewCommittee) {
537
+ return { content: '❌ 评审系统未初始化' };
538
+ }
539
+ // 获取评审状态
540
+ const pendingReview = reviewCommittee.getReviewStatus(params.task_id);
541
+ if (!pendingReview) {
542
+ // 尝试获取已完成的评审结果(如果存储了的话)
543
+ return { content: `❌ 找不到任务 ${params.task_id.slice(0, 16)}... 的评审记录` };
544
+ }
545
+ // 检查是否完成
546
+ if (pendingReview.reviews.length < pendingReview.requiredReviewers) {
547
+ const content = `
548
+ ⏳ 评审进行中
549
+
550
+ 📋 任务ID: ${params.task_id.slice(0, 16)}...
551
+ 📝 任务描述: ${pendingReview.taskDescription.slice(0, 100)}...
552
+ 📊 进度: ${pendingReview.reviews.length}/${pendingReview.requiredReviewers}
553
+
554
+ 已收到的评审:
555
+ ${pendingReview.reviews.map((r, i) => ` ${i + 1}. 工作量: ${r.dimensions.workload}, 价值: ${r.dimensions.value}`).join('\n')}
556
+ `.trim();
557
+ return {
558
+ content,
559
+ data: {
560
+ taskId: params.task_id,
561
+ status: 'in_progress',
562
+ current: pendingReview.reviews.length,
563
+ required: pendingReview.requiredReviewers,
564
+ reviews: pendingReview.reviews.map(r => ({
565
+ reviewerId: r.reviewerId.slice(0, 16) + '...',
566
+ workload: r.dimensions.workload,
567
+ value: r.dimensions.value,
568
+ riskFlags: r.riskFlags,
569
+ comment: r.comment
570
+ }))
571
+ }
572
+ };
573
+ }
574
+ // 评审已完成,结算结果
575
+ const result = reviewCommittee.finalizeReview(params.task_id);
576
+ if (!result) {
577
+ return { content: '❌ 无法结算评审结果' };
578
+ }
579
+ const content = `
580
+ 🎉 评审完成
581
+
582
+ 📋 任务ID: ${params.task_id.slice(0, 16)}...
583
+ 📊 最终评估:
584
+ • 最终工作量: ${result.finalWorkload.toFixed(1)}/100
585
+ • 最终价值分: ${result.finalValue.toFixed(1)}
586
+ • 评审人数: ${result.reviews.length}
587
+ ${result.outliers.length > 0 ? `• 偏离评审: ${result.outliers.length} 个` : ''}
588
+
589
+ 详细评审:
590
+ ${result.reviews.map((r, i) => {
591
+ const isOutlier = result.outliers.includes(r);
592
+ const outlierMark = isOutlier ? ' ⚠️ (偏离)' : '';
593
+ return ` ${i + 1}. 工作量: ${r.dimensions.workload}, 价值: ${r.dimensions.value}${outlierMark}`;
594
+ }).join('\n')}
595
+ `.trim();
596
+ return {
597
+ content,
598
+ data: {
599
+ taskId: params.task_id,
600
+ status: 'completed',
601
+ finalWorkload: result.finalWorkload,
602
+ finalValue: result.finalValue,
603
+ reviewerCount: result.reviews.length,
604
+ outlierCount: result.outliers.length
605
+ }
606
+ };
607
+ }
608
+ /**
609
+ * 处理 f2a_get_capabilities 工具
610
+ * 获取指定 Agent 的能力列表
611
+ */
612
+ async handleGetCapabilities(params, context) {
613
+ // 需要提供 peer_id 或 agent_name 其中之一
614
+ if (!params.peer_id && !params.agent_name) {
615
+ return { content: '❌ 请提供 peer_id 或 agent_name 参数' };
616
+ }
617
+ const networkClient = this.adapter.networkClient;
618
+ // 发现所有 agents
619
+ const result = await networkClient.discoverAgents();
620
+ if (!result.success) {
621
+ return { content: `❌ 查询失败: ${result.error.message}` };
622
+ }
623
+ const agents = result.data || [];
624
+ // 根据 peer_id 或 agent_name 查找
625
+ let targetAgent;
626
+ if (params.peer_id) {
627
+ // 精确匹配或前缀匹配
628
+ targetAgent = agents.find((a) => a.peerId === params.peer_id ||
629
+ a.peerId.startsWith(params.peer_id));
630
+ }
631
+ else if (params.agent_name) {
632
+ // 精确匹配或模糊匹配
633
+ targetAgent = agents.find((a) => a.displayName === params.agent_name ||
634
+ a.displayName.toLowerCase().includes(params.agent_name.toLowerCase()));
635
+ }
636
+ if (!targetAgent) {
637
+ const searchBy = params.peer_id ? `peer_id=${params.peer_id}` : `agent_name=${params.agent_name}`;
638
+ return { content: `❌ 找不到 Agent: ${searchBy}` };
639
+ }
640
+ const capabilities = targetAgent.capabilities || [];
641
+ const content = `
642
+ 🔧 Agent 能力列表
643
+
644
+ 📋 Agent: ${targetAgent.displayName}
645
+ 🆔 Peer ID: ${targetAgent.peerId.slice(0, 24)}...
646
+
647
+ 能力 (${capabilities.length} 个):
648
+ ${capabilities.length > 0
649
+ ? capabilities.map((cap, i) => ` ${i + 1}. ${cap.name}
650
+ ${cap.description}
651
+ ${cap.tools?.length ? `工具: ${cap.tools.join(', ')}` : ''}`).join('\n')
652
+ : ' 暂无能力信息'}
653
+ `.trim();
654
+ return {
655
+ content,
656
+ data: {
657
+ peerId: targetAgent.peerId,
658
+ displayName: targetAgent.displayName,
659
+ capabilities
660
+ }
661
+ };
662
+ }
663
+ // ========== 任务评估辅助方法 ==========
664
+ /**
665
+ * 估算任务复杂度
666
+ * 基于任务类型、描述和所需能力进行估算
667
+ */
668
+ estimateTaskComplexity(taskType, description, requiredCapabilities) {
669
+ // 基础复杂度(根据任务类型)
670
+ const typeComplexityMap = {
671
+ 'code-generation': 5,
672
+ 'code-review': 3,
673
+ 'file-operation': 2,
674
+ 'data-analysis': 6,
675
+ 'web-search': 2,
676
+ 'api-call': 3,
677
+ 'testing': 4,
678
+ 'documentation': 3,
679
+ 'debugging': 7,
680
+ 'refactoring': 6,
681
+ 'deployment': 5,
682
+ 'security-audit': 8
683
+ };
684
+ const baseComplexity = typeComplexityMap[taskType.toLowerCase()] || 4;
685
+ // 描述长度影响复杂度
686
+ const descLength = description.length;
687
+ const descComplexityBonus = descLength > 500 ? 2 : descLength > 200 ? 1 : 0;
688
+ // 所需能力数量影响复杂度
689
+ const capComplexityBonus = requiredCapabilities.length > 3 ? 2 : requiredCapabilities.length > 1 ? 1 : 0;
690
+ // 计算最终复杂度 (1-10)
691
+ const complexity = Math.min(10, Math.max(1, baseComplexity + descComplexityBonus + capComplexityBonus));
692
+ // 工作量估算 (0-100)
693
+ // 基于复杂度和描述长度
694
+ const workload = Math.min(100, Math.max(0, complexity * 8 + Math.min(descLength / 20, 20)));
695
+ // 预估时间(毫秒)
696
+ // 复杂度越高,时间越长
697
+ const baseTime = 60000; // 1分钟基础
698
+ const estimatedTimeMs = baseTime * complexity * (1 + requiredCapabilities.length * 0.3);
699
+ // 置信度 (0-1)
700
+ // 熟悉的任务类型置信度更高
701
+ const isKnownType = taskType.toLowerCase() in typeComplexityMap;
702
+ const confidence = isKnownType ? 0.8 : 0.5;
703
+ return {
704
+ workload: Math.round(workload),
705
+ complexity,
706
+ estimated_time_ms: Math.round(estimatedTimeMs),
707
+ confidence
708
+ };
709
+ }
710
+ /**
711
+ * 格式化持续时间
712
+ */
713
+ formatDuration(ms) {
714
+ if (ms < 1000)
715
+ return `${ms}ms`;
716
+ if (ms < 60000)
717
+ return `${(ms / 1000).toFixed(1)}s`;
718
+ if (ms < 3600000)
719
+ return `${(ms / 60000).toFixed(1)}min`;
720
+ return `${(ms / 3600000).toFixed(1)}h`;
721
+ }
722
+ }
723
+ exports.ToolHandlers = ToolHandlers;
724
+ //# sourceMappingURL=tool-handlers.js.map