Checkpoint: Phase 7 complete: Orchestrator Agent добавлен в /agents с меткой CROWN/SYSTEM, кнопками Configure и Open Chat. /chat читает конфиг оркестратора из БД (модель, промпт, инструменты). AgentDetailModal поддерживает isOrchestrator. 24 теста пройдены.

This commit is contained in:
Manus
2026-03-20 17:48:21 -04:00
parent c2fdfdbf72
commit 7aa8eee2ca
11 changed files with 1339 additions and 128 deletions

View File

@@ -1,6 +1,7 @@
/**
* Seed script — creates 3 specialized agents in the database
* Seed script — creates Orchestrator + 3 specialized agents in the database
* Run: node scripts/seed-agents.mjs
* Run with --force to re-seed existing agents
*/
import mysql from "mysql2/promise";
import * as dotenv from "dotenv";
@@ -13,7 +14,6 @@ if (!DATABASE_URL) {
process.exit(1);
}
// Parse mysql2 connection string
function parseDbUrl(url) {
const u = new URL(url);
return {
@@ -26,7 +26,78 @@ function parseDbUrl(url) {
};
}
const AGENTS = [
const ORCHESTRATOR = {
name: "Orchestrator",
description:
"Main system agent that powers the /chat interface. Has full access to all system resources: shell commands, file system, Docker management, HTTP requests, and can delegate tasks to any other agent. Configure its model, system prompt, and tools here.",
role: "orchestrator",
model: "qwen2.5:7b",
provider: "ollama",
temperature: "0.5",
maxTokens: 8192,
topP: "0.9",
frequencyPenalty: "0.0",
presencePenalty: "0.0",
systemPrompt: `You are the GoClaw Orchestrator — the central AI agent of the GoClaw Control Center system.
You have FULL access to the system and can:
- Execute shell commands on the host system
- Read and write files anywhere on the filesystem
- Manage Docker containers and services
- Make HTTP requests to any URL
- Delegate tasks to specialized agents (Browser Agent, Tool Builder, Agent Compiler)
- List and manage all agents in the system
- Install and manage skills
- Access and modify the GoClaw codebase
When given a task:
1. Analyze what needs to be done
2. Choose the right approach: direct execution or delegation to a specialist agent
3. Use tools step by step, showing your reasoning
4. Report results clearly
Available specialized agents you can delegate to:
- Browser Agent: web browsing, scraping, research
- Tool Builder: create new tools from descriptions
- Agent Compiler: compile new agents from specifications (ТЗ)
System access tools: shell_exec, file_read, file_write, http_request, docker_ps, docker_restart
Agent management: delegate_to_agent, list_agents, list_skills, install_skill
Always be transparent about what you're doing and why.
Respond in the same language as the user's message.`,
allowedTools: JSON.stringify([
"shell_exec",
"file_read",
"file_write",
"http_request",
"docker_ps",
"docker_restart",
"delegate_to_agent",
"list_agents",
"list_skills",
"install_skill",
"read_logs",
"manage_agents",
]),
allowedDomains: JSON.stringify(["*"]),
maxRequestsPerHour: 1000,
isActive: 1,
isPublic: 0,
isSystem: 1,
isOrchestrator: 1,
tags: JSON.stringify(["orchestrator", "system", "core", "privileged"]),
metadata: JSON.stringify({
agentType: "orchestrator",
icon: "Crown",
color: "#FFD700",
seeded: true,
systemAgent: true,
privileged: true,
}),
};
const SPECIALIZED_AGENTS = [
{
name: "Browser Agent",
description:
@@ -62,6 +133,8 @@ Respond in the same language as the user's message.`,
maxRequestsPerHour: 100,
isActive: 1,
isPublic: 1,
isSystem: 1,
isOrchestrator: 0,
tags: JSON.stringify(["browser", "web", "scraping", "research"]),
metadata: JSON.stringify({
agentType: "browser",
@@ -111,6 +184,8 @@ Respond in the same language as the user's message.`,
maxRequestsPerHour: 50,
isActive: 1,
isPublic: 1,
isSystem: 1,
isOrchestrator: 0,
tags: JSON.stringify(["tools", "code", "builder", "automation"]),
metadata: JSON.stringify({
agentType: "tool_builder",
@@ -164,6 +239,8 @@ Respond in the same language as the user's message.`,
maxRequestsPerHour: 30,
isActive: 1,
isPublic: 1,
isSystem: 1,
isOrchestrator: 0,
tags: JSON.stringify(["compiler", "meta", "agent-factory", "automation"]),
metadata: JSON.stringify({
agentType: "agent_compiler",
@@ -174,41 +251,42 @@ Respond in the same language as the user's message.`,
},
];
const ALL_AGENTS = [ORCHESTRATOR, ...SPECIALIZED_AGENTS];
async function seed() {
const conn = await mysql.createConnection(parseDbUrl(DATABASE_URL));
console.log("Connected to DB");
try {
// Check if agents already seeded
// Check existing seeded agents
const [existing] = await conn.execute(
"SELECT id, name FROM agents WHERE JSON_CONTAINS(metadata, '\"seeded\"', '$.seeded') OR name IN (?, ?, ?)",
["Browser Agent", "Tool Builder", "Agent Compiler"]
"SELECT id, name FROM agents WHERE name IN (?, ?, ?, ?)",
["Orchestrator", "Browser Agent", "Tool Builder", "Agent Compiler"]
);
if (existing.length > 0) {
console.log("Agents already seeded:");
existing.forEach((a) => console.log(` - [${a.id}] ${a.name}`));
console.log("Skipping seed. Use --force to re-seed.");
if (!process.argv.includes("--force")) {
console.log("Skipping seed. Use --force to re-seed.");
await conn.end();
return;
}
// Delete existing seeded agents
const ids = existing.map((a) => a.id);
await conn.execute(`DELETE FROM agents WHERE id IN (${ids.join(",")})`);
console.log("Deleted existing seeded agents");
}
// Insert agents
for (const agent of AGENTS) {
// Insert all agents
for (const agent of ALL_AGENTS) {
const [result] = await conn.execute(
`INSERT INTO agents
(userId, name, description, role, model, provider, temperature, maxTokens, topP,
frequencyPenalty, presencePenalty, systemPrompt, allowedTools, allowedDomains,
maxRequestsPerHour, isActive, isPublic, tags, metadata, createdAt, updatedAt)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`,
maxRequestsPerHour, isActive, isPublic, isSystem, isOrchestrator, tags, metadata, createdAt, updatedAt)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`,
[
1, // SYSTEM_USER_ID
1,
agent.name,
agent.description,
agent.role,
@@ -225,21 +303,25 @@ async function seed() {
agent.maxRequestsPerHour,
agent.isActive,
agent.isPublic,
agent.isSystem,
agent.isOrchestrator,
agent.tags,
agent.metadata,
]
);
console.log(`✓ Created agent: ${agent.name} (id: ${result.insertId})`);
const badge = agent.isOrchestrator ? " [ORCHESTRATOR]" : agent.isSystem ? " [SYSTEM]" : "";
console.log(`✓ Created agent: ${agent.name}${badge} (id: ${result.insertId})`);
}
// Verify
const [agents] = await conn.execute(
"SELECT id, name, role, model, isActive FROM agents ORDER BY id"
"SELECT id, name, role, model, isSystem, isOrchestrator FROM agents ORDER BY id"
);
console.log("\nAll agents in DB:");
agents.forEach((a) =>
console.log(` [${a.id}] ${a.name} | role: ${a.role} | model: ${a.model} | active: ${a.isActive}`)
);
agents.forEach((a) => {
const flags = [a.isOrchestrator ? "ORCH" : "", a.isSystem ? "SYS" : ""].filter(Boolean).join(",");
console.log(` [${a.id}] ${a.name} | role: ${a.role} | model: ${a.model}${flags ? ` | ${flags}` : ""}`);
});
} finally {
await conn.end();
}