225 lines
6.3 KiB
JavaScript
225 lines
6.3 KiB
JavaScript
|
|
// 消息发送工具
|
|||
|
|
// 文件位置: D:\openclaw-multi-agent\scripts\send-message.js
|
|||
|
|
// 功能: 发送消息到消息路由系统
|
|||
|
|
|
|||
|
|
const fs = require('fs');
|
|||
|
|
const path = require('path');
|
|||
|
|
const { exec } = require('child_process');
|
|||
|
|
const { promisify } = require('util');
|
|||
|
|
|
|||
|
|
const execAsync = promisify(exec);
|
|||
|
|
|
|||
|
|
class MessageSender {
|
|||
|
|
constructor() {
|
|||
|
|
this.basePath = 'D:\\openclaw-multi-agent';
|
|||
|
|
this.notificationsPath = path.join(this.basePath, 'shared', 'notifications', 'incoming');
|
|||
|
|
|
|||
|
|
// 确保目录存在
|
|||
|
|
if (!fs.existsSync(this.notificationsPath)) {
|
|||
|
|
fs.mkdirSync(this.notificationsPath, { recursive: true });
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成消息ID
|
|||
|
|
generateMessageId() {
|
|||
|
|
const timestamp = Date.now();
|
|||
|
|
const random = Math.floor(Math.random() * 1000);
|
|||
|
|
return `msg-${timestamp}-${random}`;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 直接发送消息到Agent(绕过路由系统)
|
|||
|
|
async sendDirect(agent, message) {
|
|||
|
|
try {
|
|||
|
|
// 转义消息中的特殊字符
|
|||
|
|
const escapedMessage = message.replace(/"/g, '\\"');
|
|||
|
|
const command = `openclaw agent --agent ${agent} --message "${escapedMessage}"`;
|
|||
|
|
|
|||
|
|
console.log(`Sending direct to ${agent}: ${message}`);
|
|||
|
|
|
|||
|
|
const { stdout, stderr } = await execAsync(command, {
|
|||
|
|
cwd: this.basePath,
|
|||
|
|
timeout: 30000
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (stderr && !stderr.includes('feishu_doc')) {
|
|||
|
|
console.warn(`Agent ${agent} stderr: ${stderr}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
success: true,
|
|||
|
|
agent,
|
|||
|
|
output: stdout
|
|||
|
|
};
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error(`Failed to send to agent ${agent}:`, error.message);
|
|||
|
|
return {
|
|||
|
|
success: false,
|
|||
|
|
agent,
|
|||
|
|
error: error.message
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 通过文件系统发送消息(使用路由系统)
|
|||
|
|
async sendViaFileSystem(prefix, message) {
|
|||
|
|
try {
|
|||
|
|
const fullMessage = `[${prefix}] ${message}`;
|
|||
|
|
const messageId = this.generateMessageId();
|
|||
|
|
|
|||
|
|
const messageFile = {
|
|||
|
|
id: messageId,
|
|||
|
|
timestamp: new Date().toISOString(),
|
|||
|
|
prefix,
|
|||
|
|
message,
|
|||
|
|
fullMessage,
|
|||
|
|
status: 'pending',
|
|||
|
|
source: 'cli'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const filePath = path.join(this.notificationsPath, `${messageId}.json`);
|
|||
|
|
|
|||
|
|
await fs.promises.writeFile(
|
|||
|
|
filePath,
|
|||
|
|
JSON.stringify(messageFile, null, 2),
|
|||
|
|
'utf8'
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
console.log(`Message saved to file system: ${filePath}`);
|
|||
|
|
console.log(`Message: ${fullMessage}`);
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
success: true,
|
|||
|
|
messageId,
|
|||
|
|
filePath,
|
|||
|
|
message: fullMessage
|
|||
|
|
};
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('Error sending via file system:', error);
|
|||
|
|
return {
|
|||
|
|
success: false,
|
|||
|
|
error: error.message
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 批量发送消息
|
|||
|
|
async sendBatch(messages) {
|
|||
|
|
const results = [];
|
|||
|
|
|
|||
|
|
for (const msg of messages) {
|
|||
|
|
const { prefix, message, method = 'direct' } = msg;
|
|||
|
|
|
|||
|
|
let result;
|
|||
|
|
if (method === 'direct') {
|
|||
|
|
// 需要将前缀映射到agent
|
|||
|
|
const agentMap = {
|
|||
|
|
'PM': 'pm',
|
|||
|
|
'BE': 'backend',
|
|||
|
|
'FE': 'frontend',
|
|||
|
|
'QA': 'qa'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const agent = agentMap[prefix] || 'pm';
|
|||
|
|
result = await this.sendDirect(agent, `[${prefix}] ${message}`);
|
|||
|
|
} else {
|
|||
|
|
result = await this.sendViaFileSystem(prefix, message);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
results.push({
|
|||
|
|
...msg,
|
|||
|
|
result
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 延迟一下,避免太快
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return results;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 命令行接口
|
|||
|
|
if (require.main === module) {
|
|||
|
|
const sender = new MessageSender();
|
|||
|
|
|
|||
|
|
const command = process.argv[2];
|
|||
|
|
|
|||
|
|
async function main() {
|
|||
|
|
switch (command) {
|
|||
|
|
case 'direct':
|
|||
|
|
const agent = process.argv[3];
|
|||
|
|
const message = process.argv.slice(4).join(' ');
|
|||
|
|
|
|||
|
|
if (!agent || !message) {
|
|||
|
|
console.error('Usage: node send-message.js direct <agent> <message>');
|
|||
|
|
console.error('Example: node send-message.js direct pm "[PM] 查看任务"');
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const result = await sender.sendDirect(agent, message);
|
|||
|
|
console.log(JSON.stringify(result, null, 2));
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'file':
|
|||
|
|
const prefix = process.argv[3];
|
|||
|
|
const msg = process.argv.slice(4).join(' ');
|
|||
|
|
|
|||
|
|
if (!prefix || !msg) {
|
|||
|
|
console.error('Usage: node send-message.js file <prefix> <message>');
|
|||
|
|
console.error('Example: node send-message.js file PM "查看任务"');
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const fileResult = await sender.sendViaFileSystem(prefix, msg);
|
|||
|
|
console.log(JSON.stringify(fileResult, null, 2));
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'test':
|
|||
|
|
// 测试消息
|
|||
|
|
const testMessages = [
|
|||
|
|
{ prefix: 'PM', message: '查看当前任务状态', method: 'direct' },
|
|||
|
|
{ prefix: 'BE', message: '查看分配的任务', method: 'direct' },
|
|||
|
|
{ prefix: 'FE', message: '查看设计稿', method: 'direct' },
|
|||
|
|
{ prefix: 'QA', message: '查看测试报告', method: 'direct' }
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
console.log('Sending test messages...');
|
|||
|
|
const batchResults = await sender.sendBatch(testMessages);
|
|||
|
|
|
|||
|
|
console.log('\n=== Test Results ===');
|
|||
|
|
batchResults.forEach((item, index) => {
|
|||
|
|
console.log(`\n${index + 1}. [${item.prefix}] ${item.message}`);
|
|||
|
|
console.log(` Success: ${item.result.success}`);
|
|||
|
|
if (item.result.error) {
|
|||
|
|
console.log(` Error: ${item.result.error}`);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 'help':
|
|||
|
|
default:
|
|||
|
|
console.log(`
|
|||
|
|
Message Sender Tool - Usage:
|
|||
|
|
node send-message.js direct <agent> <message> # 直接发送到Agent
|
|||
|
|
node send-message.js file <prefix> <message> # 通过文件系统发送
|
|||
|
|
node send-message.js test # 发送测试消息
|
|||
|
|
node send-message.js help # 显示帮助
|
|||
|
|
|
|||
|
|
Examples:
|
|||
|
|
node send-message.js direct pm "[PM] 查看任务"
|
|||
|
|
node send-message.js file PM "查看任务"
|
|||
|
|
node send-message.js test
|
|||
|
|
|
|||
|
|
Available agents: pm, backend, frontend, qa
|
|||
|
|
`);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
main().catch(error => {
|
|||
|
|
console.error('Fatal error:', error);
|
|||
|
|
process.exit(1);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
module.exports = MessageSender;
|