diff --git a/build.zig.zon b/build.zig.zon index 2da214e3..c05b14bd 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -35,8 +35,8 @@ .hash = "sqlite3-3.51.0-DMxLWssOAABZ8cAvU_LfBIbp0kZjm824PU8sSLXpEDdr", }, .zenai = .{ - .url = "git+https://github.com/lightpanda-io/zenai.git#a84812e6d37beccdc43ee79f43b0af8c1ae2e5e8", - .hash = "zenai-0.0.0-iOY_VErUAwA06Ygd91R3fP6jmUhScXsvIfceno4lA9Po", + .url = "git+https://github.com/lightpanda-io/zenai.git#35bec07f40f1493362ba4b3dc3bb9b8e51a98fd0", + .hash = "zenai-0.0.0-iOY_VOvxAwDY9Gj7AsJhFb8CBf-QuQjJsJgUJb2mGjC_", }, .isocline = .{ .url = "git+https://github.com/arrufat/isocline#94433ba3afa8e1ebb0187af17838a8d853a3829c", diff --git a/src/agent/Agent.zig b/src/agent/Agent.zig index eb9d7ae8..1f9ec50c 100644 --- a/src/agent/Agent.zig +++ b/src/agent/Agent.zig @@ -113,6 +113,9 @@ script_file: ?[]const u8, one_shot_task: ?[]const u8, one_shot_attachments: ?[]const []const u8, cancel_requested: std.atomic.Value(bool) = .init(false), +/// Shuts down the in-flight LLM socket on Ctrl-C so an agent turn aborts +/// mid-request instead of blocking until the model's full response arrives. +http_interrupt: zenai.http.Interrupt = .{}, synthetic_tool_call_id: u32 = 0, /// Aggregate Anthropic/OpenAI/Gemini token usage across every model call /// this Agent has made. Printed as a structured `$usage ...` line on stderr @@ -249,6 +252,7 @@ pub fn init(allocator: std.mem.Allocator, app: *App, opts: Config.Agent) !*Agent self.ai_client = if (llm) |l| try zenai.provider.Client.init(allocator, l, .{ .base_url = opts.base_url, .retry_policy = .long_running }) else null; errdefer if (self.ai_client) |c| c.deinit(allocator); + if (self.ai_client) |c| c.setInterrupt(&self.http_interrupt); if (will_repl) { self.terminal.attachCompleter(); @@ -305,6 +309,7 @@ fn globalTools() []const ProviderTool { /// touches from this context. pub fn requestCancel(self: *Agent) void { self.cancel_requested.store(true, .release); + self.http_interrupt.fire(); { self.script_runtime_mutex.lock(); defer self.script_runtime_mutex.unlock(); @@ -671,6 +676,7 @@ fn setProvider(self: *Agent, credentials: Credentials) !void { const new_model = try self.allocator.dupe(u8, zenai.provider.defaultModel(credentials.provider)); if (self.ai_client) |client| client.deinit(self.allocator); + new_client.setInterrupt(&self.http_interrupt); self.ai_client = new_client; self.model_credentials = credentials; self.model_completions = null;