1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
| import { ApiClient, type ApiClientConfig } from "./api-client"; import { AgentLoop, type AgentConfig } from "./agent-loop"; import { ToolRouter, type ToolDescriptor } from "./tools/router"; import { ParallelScheduler } from "./tools/scheduler"; import { SubAgentSpawner } from "./subagent/spawner"; import { SkillLoader, SkillInjector } from "./skills"; import { ConfigLoader, type AgentConfig as AppConfig } from "./config"; import { McpClient } from "./mcp/client";
export class AgentFramework { readonly config: AppConfig; readonly client: ApiClient; readonly router: ToolRouter; readonly scheduler: ParallelScheduler; readonly skills: { loader: SkillLoader; injector: SkillInjector }; readonly subAgents: SubAgentSpawner;
private mcpClients = new Map<string, McpClient>();
constructor(config: AppConfig) { this.config = config;
this.client = new ApiClient({ apiKey: config.apiKey!, baseUrl: config.baseUrl, });
this.router = new ToolRouter();
this.scheduler = new ParallelScheduler(this.router);
this.skills = { loader: new SkillLoader(), injector: new SkillInjector(new SkillLoader()), };
this.subAgents = new SubAgentSpawner(this.client); }
async initialize(): Promise<void> { await this.skills.loader.loadFromDirectory("./skills");
if (this.config.mcpServers) { for (const [name, serverConfig] of Object.entries(this.config.mcpServers)) { if (serverConfig.type === "stdio") { const mcpClient = new McpClient(serverConfig.command!, serverConfig.args!); await mcpClient.initialize(); await mcpClient.listTools(); this.router.registerMcp(mcpClient); this.mcpClients.set(name, mcpClient); } } } }
createAgent(options?: { systemPrompt?: string; tools?: ToolDescriptor[]; skills?: string[]; model?: string; }): AgentLoop { if (options?.tools) { for (const tool of options.tools) { this.router.register(tool); } }
let systemPrompt = options?.systemPrompt ?? ""; if (options?.skills) { const skillDefs = options.skills .map(name => this.skills.loader.get(name)) .filter(Boolean) as SkillDefinition[]; systemPrompt = this.skills.injector.buildSystemPrompt( systemPrompt, skillDefs ); }
return new AgentLoop( this.client, this.router, { model: options?.model ?? this.config.model, maxTokens: this.config.maxTokens ?? 4096, maxIterations: this.config.maxIterations ?? 25, maxContextTokens: 180_000, tools: this.router.getToolDefinitions(), systemPrompt, outputConfig: { effort: this.config.effort ?? "high" }, } ); }
registerTool(descriptor: ToolDescriptor): void { this.router.register(descriptor); }
registerMcpServer(name: string, config: McpServerConfig): void { this.config.mcpServers ??= {}; this.config.mcpServers[name] = config; }
async shutdown(): Promise<void> { for (const [name, mcpClient] of this.mcpClients) { mcpClient.close(); } this.mcpClients.clear(); } }
|