|
| 1 | +const std = @import("std"); |
| 2 | +const moe = @import("moe_router.zig"); |
| 3 | +const dao = @import("dao_integration.zig"); |
| 4 | + |
| 5 | +// ============================================================================ |
| 6 | +// TRINITY: AGENT LOOP (PHASE 17) - ReAct Pattern with MoE Routing |
| 7 | +// Thought → Action → Observation → Repeat |
| 8 | +// ============================================================================ |
| 9 | + |
| 10 | +/// Agent execution state |
| 11 | +pub const AgentState = enum { |
| 12 | + Idle, |
| 13 | + Thinking, |
| 14 | + Planning, |
| 15 | + Acting, |
| 16 | + Observing, |
| 17 | + Done, |
| 18 | + Error, |
| 19 | + |
| 20 | + pub fn getIcon(self: AgentState) []const u8 { |
| 21 | + return switch (self) { |
| 22 | + .Idle => "💤", |
| 23 | + .Thinking => "🤔", |
| 24 | + .Planning => "📋", |
| 25 | + .Acting => "⚡", |
| 26 | + .Observing => "👁️", |
| 27 | + .Done => "✅", |
| 28 | + .Error => "❌", |
| 29 | + }; |
| 30 | + } |
| 31 | +}; |
| 32 | + |
| 33 | +/// Tool types available to the agent |
| 34 | +pub const Tool = enum { |
| 35 | + Infer, // Run inference on a model |
| 36 | + Convert, // Convert model formats |
| 37 | + Stake, // Stake TRI tokens |
| 38 | + Vote, // Vote on DAO proposals |
| 39 | + WebSearch, // External: web search (mock) |
| 40 | + CodeExec, // External: code execution (mock) |
| 41 | + FindJobs, // Find jobs in Trinity L2 |
| 42 | + |
| 43 | + pub fn getName(self: Tool) []const u8 { |
| 44 | + return switch (self) { |
| 45 | + .Infer => "infer", |
| 46 | + .Convert => "convert", |
| 47 | + .Stake => "stake", |
| 48 | + .Vote => "vote", |
| 49 | + .WebSearch => "web_search", |
| 50 | + .CodeExec => "code_exec", |
| 51 | + .FindJobs => "find_jobs", |
| 52 | + }; |
| 53 | + } |
| 54 | + |
| 55 | + pub fn getDescription(self: Tool) []const u8 { |
| 56 | + return switch (self) { |
| 57 | + .Infer => "Run inference on ternary models (Mistral-7B.tri, Qwen2.5-Coder-7B.tri)", |
| 58 | + .Convert => "Convert models to ternary format", |
| 59 | + .Stake => "Stake $TRI tokens with tier (bronze/silver/gold)", |
| 60 | + .Vote => "Vote on DAO proposals (yes/no)", |
| 61 | + .WebSearch => "Search the web for information", |
| 62 | + .CodeExec => "Execute generated code", |
| 63 | + .FindJobs => "Find available jobs in Trinity L2 network", |
| 64 | + }; |
| 65 | + } |
| 66 | +}; |
| 67 | + |
| 68 | +/// Action to be executed |
| 69 | +pub const Action = struct { |
| 70 | + tool: Tool, |
| 71 | + args: []const []const u8, |
| 72 | + confidence: f32 = 1.0, |
| 73 | +}; |
| 74 | + |
| 75 | +/// Single step in agent history |
| 76 | +pub const Step = struct { |
| 77 | + thought: []const u8, |
| 78 | + action: ?Action, |
| 79 | + observation: []const u8, |
| 80 | + state: AgentState, |
| 81 | + expert_used: moe.Expert, |
| 82 | +}; |
| 83 | + |
| 84 | +/// Thought result from reasoning |
| 85 | +pub const ThoughtResult = struct { |
| 86 | + thought: []const u8, |
| 87 | + suggested_tool: ?Tool, |
| 88 | + suggested_args: []const []const u8, |
| 89 | + confidence: f32, |
| 90 | + should_finish: bool, |
| 91 | +}; |
| 92 | + |
| 93 | +/// Observation result from action |
| 94 | +pub const ObservationResult = struct { |
| 95 | + success: bool, |
| 96 | + output: []const u8, |
| 97 | + error_msg: ?[]const u8 = null, |
| 98 | + reward: f32 = 0.0, // Mock TRI reward |
| 99 | +}; |
| 100 | + |
| 101 | +/// Agent configuration |
| 102 | +pub const AgentConfig = struct { |
| 103 | + max_steps: usize = 10, |
| 104 | + verbose: bool = true, |
| 105 | + self_healing: bool = true, |
| 106 | + streaming: bool = true, |
| 107 | +}; |
| 108 | + |
| 109 | +/// Main Agent Loop implementation |
| 110 | +pub const AgentLoop = struct { |
| 111 | + allocator: std.mem.Allocator, |
| 112 | + router: *moe.MoERouter, |
| 113 | + dao_manager: dao.DAOManager, |
| 114 | + config: AgentConfig, |
| 115 | + state: AgentState = .Idle, |
| 116 | + history: std.ArrayListUnmanaged(Step), |
| 117 | + current_task: []const u8 = "", |
| 118 | + total_reward: f32 = 0.0, |
| 119 | + error_count: u32 = 0, |
| 120 | + |
| 121 | + const Self = @This(); |
| 122 | + |
| 123 | + pub fn init(allocator: std.mem.Allocator, router: *moe.MoERouter, config: AgentConfig) !*Self { |
| 124 | + const self = try allocator.create(Self); |
| 125 | + self.* = .{ |
| 126 | + .allocator = allocator, |
| 127 | + .router = router, |
| 128 | + .dao_manager = dao.DAOManager.init(allocator), |
| 129 | + .config = config, |
| 130 | + .history = .{}, |
| 131 | + }; |
| 132 | + return self; |
| 133 | + } |
| 134 | + |
| 135 | + pub fn deinit(self: *Self) void { |
| 136 | + self.history.deinit(self.allocator); |
| 137 | + self.dao_manager.deinit(); |
| 138 | + self.allocator.destroy(self); |
| 139 | + } |
| 140 | + |
| 141 | + /// Main agent execution loop |
| 142 | + pub fn run(self: *Self, task: []const u8) !void { |
| 143 | + self.current_task = task; |
| 144 | + self.state = .Thinking; |
| 145 | + self.error_count = 0; |
| 146 | + |
| 147 | + if (self.config.verbose) { |
| 148 | + std.debug.print("\n🚀 [Agent] Starting task: \"{s}\"\n", .{task}); |
| 149 | + std.debug.print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", .{}); |
| 150 | + } |
| 151 | + |
| 152 | + // Route to experts |
| 153 | + const route_result = self.router.route(task); |
| 154 | + if (self.config.verbose) { |
| 155 | + moe.MoERouter.printRoute(route_result); |
| 156 | + } |
| 157 | + |
| 158 | + // ReAct loop |
| 159 | + var step_count: usize = 0; |
| 160 | + while (step_count < self.config.max_steps and self.state != .Done and self.state != .Error) : (step_count += 1) { |
| 161 | + if (self.config.verbose) { |
| 162 | + std.debug.print("\n── Step {d} ──\n", .{step_count + 1}); |
| 163 | + } |
| 164 | + |
| 165 | + // THINK |
| 166 | + self.state = .Thinking; |
| 167 | + const thought = self.think(route_result.selected[0]); |
| 168 | + |
| 169 | + if (self.config.streaming) { |
| 170 | + std.debug.print("💭 Thought: {s}\n", .{thought.thought}); |
| 171 | + } |
| 172 | + |
| 173 | + if (thought.should_finish) { |
| 174 | + self.state = .Done; |
| 175 | + break; |
| 176 | + } |
| 177 | + |
| 178 | + // PLAN (if needed) |
| 179 | + if (thought.suggested_tool == null) { |
| 180 | + self.state = .Planning; |
| 181 | + if (self.config.streaming) { |
| 182 | + std.debug.print("📋 Plan: Analyzing task requirements...\n", .{}); |
| 183 | + } |
| 184 | + continue; |
| 185 | + } |
| 186 | + |
| 187 | + // ACT |
| 188 | + self.state = .Acting; |
| 189 | + const action = Action{ |
| 190 | + .tool = thought.suggested_tool.?, |
| 191 | + .args = thought.suggested_args, |
| 192 | + .confidence = thought.confidence, |
| 193 | + }; |
| 194 | + |
| 195 | + if (self.config.streaming) { |
| 196 | + std.debug.print("⚡ Action: {s}(", .{action.tool.getName()}); |
| 197 | + for (action.args, 0..) |arg, i| { |
| 198 | + if (i > 0) std.debug.print(", ", .{}); |
| 199 | + std.debug.print("\"{s}\"", .{arg}); |
| 200 | + } |
| 201 | + std.debug.print(")\n", .{}); |
| 202 | + } |
| 203 | + |
| 204 | + const observation = self.act(action) catch |err| { |
| 205 | + if (self.config.self_healing) { |
| 206 | + self.selfHeal(err, route_result); |
| 207 | + continue; |
| 208 | + } |
| 209 | + self.state = .Error; |
| 210 | + break; |
| 211 | + }; |
| 212 | + |
| 213 | + // OBSERVE |
| 214 | + self.state = .Observing; |
| 215 | + if (self.config.streaming) { |
| 216 | + std.debug.print("👁️ Observation: {s}\n", .{observation.output}); |
| 217 | + if (observation.reward > 0) { |
| 218 | + std.debug.print("💰 Reward: +{d:.2} $TRI\n", .{observation.reward}); |
| 219 | + } |
| 220 | + } |
| 221 | + |
| 222 | + self.total_reward += observation.reward; |
| 223 | + |
| 224 | + // Record step in history |
| 225 | + try self.history.append(self.allocator, .{ |
| 226 | + .thought = thought.thought, |
| 227 | + .action = action, |
| 228 | + .observation = observation.output, |
| 229 | + .state = self.state, |
| 230 | + .expert_used = route_result.selected[0], |
| 231 | + }); |
| 232 | + |
| 233 | + // Check if task is complete |
| 234 | + if (self.isTaskComplete(observation)) { |
| 235 | + self.state = .Done; |
| 236 | + } |
| 237 | + } |
| 238 | + |
| 239 | + // Final summary |
| 240 | + if (self.config.verbose) { |
| 241 | + std.debug.print("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", .{}); |
| 242 | + std.debug.print("{s} [Agent] Task completed in {d} steps\n", .{ self.state.getIcon(), step_count }); |
| 243 | + std.debug.print("💰 Total rewards: {d:.2} $TRI\n", .{self.total_reward}); |
| 244 | + } |
| 245 | + } |
| 246 | + |
| 247 | + /// Thinking phase - analyze task and decide next action |
| 248 | + fn think(self: *Self, expert: moe.Expert) ThoughtResult { |
| 249 | + _ = self; |
| 250 | + // Mock reasoning based on expert type |
| 251 | + return switch (expert) { |
| 252 | + .Inference => .{ |
| 253 | + .thought = "Need to run inference on ternary model", |
| 254 | + .suggested_tool = .Infer, |
| 255 | + .suggested_args = &[_][]const u8{ "mistral-7b.tri", "--turbo" }, |
| 256 | + .confidence = 0.9, |
| 257 | + .should_finish = false, |
| 258 | + }, |
| 259 | + .Network => .{ |
| 260 | + .thought = "Network operation required - checking staking/voting", |
| 261 | + .suggested_tool = .Stake, |
| 262 | + .suggested_args = &[_][]const u8{ "10000", "--tier", "gold" }, |
| 263 | + .confidence = 0.85, |
| 264 | + .should_finish = false, |
| 265 | + }, |
| 266 | + .CodeGen => .{ |
| 267 | + .thought = "Code generation task detected", |
| 268 | + .suggested_tool = .CodeExec, |
| 269 | + .suggested_args = &[_][]const u8{"generate_optimization"}, |
| 270 | + .confidence = 0.8, |
| 271 | + .should_finish = false, |
| 272 | + }, |
| 273 | + .Planning => .{ |
| 274 | + .thought = "Multi-step task - need to create execution plan", |
| 275 | + .suggested_tool = null, |
| 276 | + .suggested_args = &[_][]const u8{}, |
| 277 | + .confidence = 0.7, |
| 278 | + .should_finish = false, |
| 279 | + }, |
| 280 | + }; |
| 281 | + } |
| 282 | + |
| 283 | + /// Action execution phase |
| 284 | + fn act(self: *Self, action: Action) !ObservationResult { |
| 285 | + return switch (action.tool) { |
| 286 | + .Infer => .{ |
| 287 | + .success = true, |
| 288 | + .output = "Inference complete: Mistral-7B.tri loaded, 42 tokens generated", |
| 289 | + .reward = 1.0, |
| 290 | + }, |
| 291 | + .Stake => blk: { |
| 292 | + const amount = std.fmt.parseFloat(f64, action.args[0]) catch 1000.0; |
| 293 | + try self.dao_manager.stake(amount, .GOLD); |
| 294 | + break :blk .{ |
| 295 | + .success = true, |
| 296 | + .output = "Staked successfully in GOLD tier", |
| 297 | + .reward = @floatCast(amount * 0.001), |
| 298 | + }; |
| 299 | + }, |
| 300 | + .Vote => blk: { |
| 301 | + try self.dao_manager.vote("proposal_42", true); |
| 302 | + break :blk .{ |
| 303 | + .success = true, |
| 304 | + .output = "Vote cast: YES on proposal_42", |
| 305 | + .reward = 0.5, |
| 306 | + }; |
| 307 | + }, |
| 308 | + .FindJobs => .{ |
| 309 | + .success = true, |
| 310 | + .output = "Found 3 jobs in Trinity L2: [inference_task_1, staking_reward_2, code_review_3]", |
| 311 | + .reward = 0.1, |
| 312 | + }, |
| 313 | + .WebSearch => .{ |
| 314 | + .success = true, |
| 315 | + .output = "[Mock] Web search results: Found relevant documentation", |
| 316 | + .reward = 0.0, |
| 317 | + }, |
| 318 | + .CodeExec => .{ |
| 319 | + .success = true, |
| 320 | + .output = "[Mock] Code executed successfully: optimization applied", |
| 321 | + .reward = 2.0, |
| 322 | + }, |
| 323 | + .Convert => .{ |
| 324 | + .success = true, |
| 325 | + .output = "Model converted to ternary format", |
| 326 | + .reward = 0.5, |
| 327 | + }, |
| 328 | + }; |
| 329 | + } |
| 330 | + |
| 331 | + /// Self-healing: switch experts or mutate strategy on error |
| 332 | + fn selfHeal(self: *Self, err: anyerror, route_result: moe.RouteResult) void { |
| 333 | + self.error_count += 1; |
| 334 | + if (self.config.verbose) { |
| 335 | + std.debug.print("🩹 [Self-Healing] Error: {s}, switching to backup expert\n", .{@errorName(err)}); |
| 336 | + } |
| 337 | + |
| 338 | + // Switch to second expert if available |
| 339 | + if (route_result.selected_count > 1) { |
| 340 | + std.debug.print("🔄 Switching from {s} to {s}\n", .{ |
| 341 | + route_result.selected[0].getName(), |
| 342 | + route_result.selected[1].getName(), |
| 343 | + }); |
| 344 | + } |
| 345 | + |
| 346 | + // Reset state to thinking |
| 347 | + self.state = .Thinking; |
| 348 | + } |
| 349 | + |
| 350 | + /// Check if task is complete |
| 351 | + fn isTaskComplete(self: *Self, observation: ObservationResult) bool { |
| 352 | + _ = self; |
| 353 | + return observation.success and observation.reward > 0; |
| 354 | + } |
| 355 | + |
| 356 | + /// Get agent history |
| 357 | + pub fn getHistory(self: *Self) []const Step { |
| 358 | + return self.history.items; |
| 359 | + } |
| 360 | +}; |
| 361 | + |
| 362 | +// ============================================================================ |
| 363 | +// CLI INTERFACE |
| 364 | +// ============================================================================ |
| 365 | + |
| 366 | +pub fn main() !void { |
| 367 | + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; |
| 368 | + defer _ = gpa.deinit(); |
| 369 | + const allocator = gpa.allocator(); |
| 370 | + |
| 371 | + std.debug.print("\n🌟 TRINITY AGENT LOOP - PHASE 17\n", .{}); |
| 372 | + std.debug.print(" ReAct Pattern with MoE Routing\n\n", .{}); |
| 373 | + |
| 374 | + // Initialize MoE router |
| 375 | + var router = try moe.MoERouter.init(allocator, .{}); |
| 376 | + defer router.deinit(); |
| 377 | + |
| 378 | + // Initialize agent |
| 379 | + var agent = try AgentLoop.init(allocator, router, .{ |
| 380 | + .verbose = true, |
| 381 | + .streaming = true, |
| 382 | + .self_healing = true, |
| 383 | + .max_steps = 5, |
| 384 | + }); |
| 385 | + defer agent.deinit(); |
| 386 | + |
| 387 | + // Demo tasks |
| 388 | + const demo_tasks = [_][]const u8{ |
| 389 | + "Запусти инференс на Mistral-7B и застейкай 10000 TRI", |
| 390 | + "Максимизируй earnings на моём node в Ko Samui", |
| 391 | + }; |
| 392 | + |
| 393 | + for (demo_tasks) |task| { |
| 394 | + try agent.run(task); |
| 395 | + std.debug.print("\n", .{}); |
| 396 | + } |
| 397 | + |
| 398 | + std.debug.print("✅ Agent Loop Phase 17 Complete!\n", .{}); |
| 399 | +} |
0 commit comments