小白龙 Bailongma - 初始提交

自主操作员与思考搭档系统。
包含 orchestrator-v2 多Agent编排层、后台意识引擎、记忆系统、ACUI 组件。
This commit is contained in:
chengjiaxi
2026-05-22 19:22:06 +08:00
commit 664ffb3834
64 changed files with 111533 additions and 0 deletions

View 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;