Files
BaiLongma/orchestrator-v2/role-router.js
chengjiaxi 664ffb3834 小白龙 Bailongma - 初始提交
自主操作员与思考搭档系统。
包含 orchestrator-v2 多Agent编排层、后台意识引擎、记忆系统、ACUI 组件。
2026-05-22 19:22:06 +08:00

118 lines
3.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const RoleTemplates = require('./role-templates.js');
class RoleRouter {
constructor() {
this.templates = new RoleTemplates();
this.initialized = false;
}
async init() {
if (this.initialized) return;
await this.templates.init();
this.initialized = true;
}
// Generate n-grams from Chinese text for matching
_ngrams(text, minN = 2, maxN = 4) {
const chars = text.replace(/[\s,,、。.;;:!?()\[\]【】{}《》""''"'"\/\\\-_+*=#@&^%$§~`·…—\d]+/g, '');
const grams = new Set();
for (let n = minN; n <= maxN; n++) {
for (let i = 0; i <= chars.length - n; i++) {
grams.add(chars.slice(i, i + n));
}
}
return grams;
}
// Auto-select the best role for a given task description
selectRole(taskDescription, preferredRoles = []) {
// 1. If preferred roles specified, use them
if (preferredRoles.length > 0) {
const roles = preferredRoles.map(id => this.templates.getTemplate(id)).filter(Boolean);
if (roles.length > 0) return roles;
}
const q = taskDescription.toLowerCase();
// 2. Generate n-grams from the task query
const queryGrams = this._ngrams(q, 2, 4);
// Also extract English terms and standalone keywords
const terms = q.split(/[\s,,、。.;;:!?()\[\]【】{}《》""''"'"\/\\\-_+*=#@&^%$§~`·…—]+/)
.filter(t => t.length > 1);
// 3. Score each role
const scores = new Map();
for (const [id, role] of this.templates.roles) {
const searchSpace = (role.name + ' ' + role.description + ' ' + role.id + ' ' + role.category).toLowerCase();
let score = 0;
// Score by n-gram overlap (for Chinese)
const roleGrams = this._ngrams(searchSpace, 2, 4);
let overlap = 0;
for (const gram of queryGrams) {
if (roleGrams.has(gram)) overlap++;
}
if (queryGrams.size > 0) {
score += (overlap / queryGrams.size) * 100;
}
// Score by term matching (for English/mixed)
for (const term of terms) {
if (searchSpace.includes(term)) {
score += term.length * 3;
// Extra for name/id match
if (role.name.toLowerCase().includes(term)) score += term.length * 2;
if (role.id.toLowerCase().includes(term)) score += term.length;
}
}
// Boost for full name match
if (searchSpace.includes(q) && q.length > 4) {
score += q.length * 5;
}
if (score > 0) scores.set(id, Math.round(score));
}
// 4. Return top matches (up to 5)
const ranked = [...scores.entries()]
.sort((a, b) => b[1] - a[1])
.slice(0, 5)
.map(([id]) => this.templates.getTemplate(id));
return ranked;
}
// Decompose a complex task and assign roles to each sub-task
async decomposeWithRoles(mainTask) {
const lines = mainTask.split('\n').filter(l => l.trim());
if (lines.length <= 1) {
const roles = this.selectRole(mainTask);
return [{
id: 'sub_1',
name: mainTask.slice(0, 60),
target: mainTask,
priority: 1,
roles: roles
}];
}
return lines.map((line, i) => {
const trimmed = line.trim();
const roles = this.selectRole(trimmed);
return {
id: 'sub_' + (i + 1),
name: trimmed.slice(0, 60),
target: trimmed,
priority: i + 1,
roles: roles
};
});
}
getTemplates() { return this.templates; }
}
module.exports = RoleRouter;