const std = @import("std"); const config = @import("../../config.zig"); const ws = @import("../../net/ws/client.zig"); const crypto = @import("../../utils/crypto.zig"); const protocol = @import("../../net/protocol.zig"); const history = @import("../../utils/history.zig"); /// Execute job on remote server pub fn execute( allocator: std.mem.Allocator, job_name: []const u8, priority: u8, options: anytype, args_str: []const u8, cfg: config.Config, ) !void { // Use queue command logic for remote execution std.log.info("Queueing job on remote server: {s}", .{job_name}); const ws_url = try cfg.getWebSocketUrl(allocator); defer allocator.free(ws_url); var client = try ws.Client.connect(allocator, ws_url, cfg.api_key); defer client.close(); const api_key_hash = try crypto.hashApiKey(allocator, cfg.api_key); defer allocator.free(api_key_hash); // Generate commit ID var commit_bytes: [20]u8 = undefined; std.crypto.random.bytes(&commit_bytes); // Build narrative JSON if provided const narrative_json = buildNarrativeJson(allocator, options) catch null; defer if (narrative_json) |j| allocator.free(j); // Send queue request try client.sendQueueJobWithArgsAndResources( job_name, &commit_bytes, priority, api_key_hash, args_str, false, // force options.cpu, options.memory, options.gpu, options.gpu_memory, ); // Receive response const message = try client.receiveMessage(allocator); defer allocator.free(message); const packet = protocol.ResponsePacket.deserialize(message, allocator) catch { std.debug.print("Server response: {s}\n", .{message}); return; }; defer packet.deinit(allocator); switch (packet.packet_type) { .success => { const commit_hex = try crypto.encodeHexLower(allocator, &commit_bytes); defer allocator.free(commit_hex); history.record(allocator, job_name, commit_hex) catch {}; std.debug.print("Job queued: {s} (commit: {s})\n", .{ job_name, commit_hex[0..8] }); }, .error_packet => { const err_msg = packet.error_message orelse "Unknown error"; std.debug.print("Error: {s}\n", .{err_msg}); return error.ServerError; }, else => { std.debug.print("Job queued: {s}\n", .{job_name}); }, } } fn buildNarrativeJson(allocator: std.mem.Allocator, options: anytype) !?[]const u8 { if (options.hypothesis == null and options.context == null and options.intent == null and options.expected_outcome == null) { return null; } var buf = try std.ArrayList(u8).initCapacity(allocator, 256); defer buf.deinit(allocator); const writer = buf.writer(allocator); try writer.writeAll("{"); var first = true; if (options.hypothesis) |h| { if (!first) try writer.writeAll(","); try writer.print("\"hypothesis\":\"{s}\"", .{h}); first = false; } if (options.context) |c| { if (!first) try writer.writeAll(","); try writer.print("\"context\":\"{s}\"", .{c}); first = false; } if (options.intent) |i| { if (!first) try writer.writeAll(","); try writer.print("\"intent\":\"{s}\"", .{i}); first = false; } if (options.expected_outcome) |eo| { if (!first) try writer.writeAll(","); try writer.print("\"expected_outcome\":\"{s}\"", .{eo}); first = false; } try writer.writeAll("}"); return try buf.toOwnedSlice(allocator); }