小白龙 Bailongma - 初始提交
自主操作员与思考搭档系统。 包含 orchestrator-v2 多Agent编排层、后台意识引擎、记忆系统、ACUI 组件。
This commit is contained in:
117
orchestrator-v2/role-router.js
Normal file
117
orchestrator-v2/role-router.js
Normal file
@@ -0,0 +1,117 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user