v1.6.0: Replace Rig with Agents Council + Keep FULL RAG

This commit is contained in:
admin
2026-02-26 17:53:41 +04:00
Unverified
parent 7255ca42aa
commit 1387a8b1c6
9 changed files with 1318 additions and 5 deletions

310
src/tools/agents-council.ts Normal file
View File

@@ -0,0 +1,310 @@
/**
* Agents Council Integration for QwenClaw
*
* Replaces Rig with Agents Council for multi-agent orchestration
* while maintaining FULL RAG capabilities
*/
import { spawn } from "child_process";
import { join } from "path";
import { existsSync, readFileSync, writeFile } from "fs";
const COUNCIL_DIR = join(process.env.HOME || process.env.USERPROFILE || "", ".agents-council");
const QWENCLAW_DIR = process.env.QWENCLAW_DIR || join(process.env.HOME || process.env.USERPROFILE || "", "qwenclaw");
const STATE_FILE = join(COUNCIL_DIR, "state.json");
export interface CouncilConfig {
autoStart: boolean;
desktopApp: boolean;
agents: Record<string, AgentConfig>;
rag: RAGConfig;
}
export interface AgentConfig {
enabled: boolean;
model: string;
autoSummon: boolean;
}
export interface RAGConfig {
enabled: boolean;
vectorStore: 'sqlite' | 'chroma' | 'pinecone';
shareAcrossAgents: boolean;
topK: number;
threshold: number;
}
const DEFAULT_CONFIG: CouncilConfig = {
autoStart: true,
desktopApp: true,
agents: {
qwen: { enabled: true, model: 'qwen-plus', autoSummon: true },
claude: { enabled: true, model: 'claude-sonnet-4-5-20250929', autoSummon: false },
codex: { enabled: true, model: 'codex-latest', autoSummon: false },
},
rag: {
enabled: true,
vectorStore: 'sqlite',
shareAcrossAgents: true,
topK: 5,
threshold: 0.7,
},
};
/**
* Agents Council Client
*/
export class AgentsCouncilClient {
private config: CouncilConfig;
private running: boolean = false;
constructor(config: Partial<CouncilConfig> = {}) {
this.config = { ...DEFAULT_CONFIG, ...config };
}
/**
* Start Agents Council MCP server
*/
async start(): Promise<void> {
if (this.running) {
console.log("[Council] Already running");
return;
}
console.log("[Council] Starting Agents Council...");
const councilProcess = spawn("npx", ["agents-council@latest", "mcp"], {
stdio: ["pipe", "pipe", "pipe"],
detached: false,
});
councilProcess.stdout?.on("data", (data) => {
console.log(`[Council] ${data.toString().trim()}`);
});
councilProcess.stderr?.on("data", (data) => {
console.error(`[Council Error] ${data.toString().trim()}`);
});
this.running = true;
// Wait for council to start
await new Promise((resolve) => setTimeout(resolve, 3000));
console.log("[Council] ✅ Started");
}
/**
* Stop council
*/
async stop(): Promise<void> {
this.running = false;
console.log("[Council] Stopped");
}
/**
* Summon agent to council
*/
async summon(agent: string): Promise<void> {
console.log(`[Council] Summoning ${agent}...`);
return new Promise((resolve, reject) => {
const proc = spawn("npx", ["agents-council@latest", "summon", agent], {
stdio: "inherit",
});
proc.on("close", (code) => {
if (code === 0) {
console.log(`[Council] ✅ ${agent} summoned`);
resolve();
} else {
reject(new Error(`Failed to summon ${agent}`));
}
});
});
}
/**
* Start multi-agent discussion
*/
async discuss(options: DiscussionOptions): Promise<DiscussionResult> {
console.log(`[Council] Starting discussion: ${options.topic}`);
const args = [
"agents-council@latest",
"discuss",
"--topic", options.topic,
"--agents", options.agents.join(","),
];
if (options.context) {
args.push("--context", options.context);
}
if (options.ragContext) {
args.push("--rag");
}
return new Promise((resolve, reject) => {
const proc = spawn("npx", args, {
stdio: ["pipe", "pipe", "pipe"],
});
let output = "";
proc.stdout?.on("data", (data) => {
output += data.toString();
});
proc.on("close", (code) => {
if (code === 0) {
resolve({
summary: output,
agents: options.agents,
topic: options.topic,
});
} else {
reject(new Error("Discussion failed"));
}
});
});
}
/**
* Get council status
*/
async getStatus(): Promise<CouncilStatus> {
if (!existsSync(STATE_FILE)) {
return { running: false, agents: [] };
}
try {
const state = JSON.parse(readFileSync(STATE_FILE, "utf-8"));
return {
running: this.running,
agents: state.agents || [],
discussions: state.discussions || 0,
};
} catch {
return { running: false, agents: [] };
}
}
/**
* Open Council Hall desktop app
*/
async monitor(): Promise<void> {
console.log("[Council] Opening Council Hall...");
spawn("npx", ["agents-council@latest", "desktop"], {
detached: true,
stdio: "ignore",
});
}
}
interface DiscussionOptions {
topic: string;
context?: string;
agents: string[];
roles?: Record<string, string>;
ragContext?: boolean | RAGOptions;
output?: 'markdown' | 'json';
timeout?: number;
}
interface RAGOptions {
searchQuery?: string;
documents?: string[];
topK?: number;
includeInContext?: boolean;
}
interface DiscussionResult {
summary: string;
agents: string[];
topic: string;
ragDocuments?: any[];
}
interface CouncilStatus {
running: boolean;
agents: string[];
discussions?: number;
}
/**
* Initialize Agents Council with RAG
*/
export async function initAgentsCouncil(): Promise<AgentsCouncilClient> {
const client = new AgentsCouncilClient();
// Auto-start if configured
if (client['config'].autoStart) {
await client.start();
}
// Summon auto-summon agents
for (const [agent, config] of Object.entries(client['config'].agents)) {
if (config.autoSummon) {
await client.summon(agent);
}
}
return client;
}
/**
* CLI command for council
*/
export async function councilCommand(args: string[]): Promise<void> {
console.log("🏛️ Agents Council for QwenClaw\n");
if (args.length === 0) {
console.log("Usage: qwenclaw council <command> [options]");
console.log("");
console.log("Commands:");
console.log(" start - Start council MCP server");
console.log(" status - Check council status");
console.log(" summon <agent> - Summon agent (claude/codex/qwen)");
console.log(" discuss - Start multi-agent discussion");
console.log(" monitor - Open Council Hall desktop");
console.log(" config - Edit configuration");
console.log("");
console.log("Examples:");
console.log(" qwenclaw council start");
console.log(" qwenclaw council summon claude");
console.log(" qwenclaw council discuss --topic 'Code Review'");
return;
}
const command = args[0];
const client = new AgentsCouncilClient();
switch (command) {
case "start":
await client.start();
break;
case "status":
const status = await client.getStatus();
console.log("Council Status:");
console.log(` Running: ${status.running ? '✅' : '❌'}`);
console.log(` Agents: ${status.agents.join(", ") || 'none'}`);
console.log(` Discussions: ${status.discussions || 0}`);
break;
case "summon":
if (!args[1]) {
console.log("[ERROR] Agent name required");
return;
}
await client.summon(args[1]);
break;
case "monitor":
await client.monitor();
break;
default:
console.log(`[ERROR] Unknown command: ${command}`);
}
}