From 538a5d926fa626a00cc3dc12c555f11f82867efd Mon Sep 17 00:00:00 2001 From: t Date: Mon, 22 Jun 2026 18:18:28 -0600 Subject: libpanto ponytail-audit simplifications --- libpanto/src/provider_anthropic_messages.zig | 68 +++------------------------- 1 file changed, 6 insertions(+), 62 deletions(-) (limited to 'libpanto/src/provider_anthropic_messages.zig') diff --git a/libpanto/src/provider_anthropic_messages.zig b/libpanto/src/provider_anthropic_messages.zig index 258ddbd..955991a 100644 --- a/libpanto/src/provider_anthropic_messages.zig +++ b/libpanto/src/provider_anthropic_messages.zig @@ -135,66 +135,18 @@ pub const AnthropicMessagesRequest = struct { ); defer self.allocator.free(extra_headers); - rr.req = try self.http_client.request(.POST, uri, .{ - .extra_headers = extra_headers, - // Disable compression: gzip buffers small SSE frames, defeating - // the streaming property we paid for `stream: true` to get. - .headers = .{ .accept_encoding = .{ .override = "identity" } }, - .keep_alive = false, - .redirect_behavior = .not_allowed, - }); + rr.response = try provider_mod.sendRequest(self.http_client, uri, extra_headers, body, &rr.req); rr.req_open = true; errdefer { rr.req.deinit(); rr.req_open = false; } - rr.req.transfer_encoding = .{ .content_length = body.len }; - - var send_buf: [4096]u8 = undefined; - var bw = try rr.req.sendBodyUnflushed(&send_buf); - try bw.writer.writeAll(body); - try bw.end(); - try rr.req.connection.?.flush(); - - var redirect_buf: [1024]u8 = undefined; - rr.response = try rr.req.receiveHead(&redirect_buf); - + // A >=400 status maps to a retryable/terminal provider error. Anthropic + // rejects oversized requests with HTTP 400 + "prompt is too long", + // which `classifyErrorResponse` maps to ContextOverflow (compact+retry). if (@intFromEnum(rr.response.head.status) >= 400) { - // `head.bytes` (which `iterateHeaders` walks) points into the - // connection read buffer and is invalidated the moment the body - // stream is initialized below. Capture Retry-After first. - const retry_after_ms = provider_mod.retryAfterFromHead(rr.response.head); - const body_reader = rr.response.reader(&rr.transfer_buf); - var err_buf: std.ArrayList(u8) = .empty; - defer err_buf.deinit(self.allocator); - var tmp: [1024]u8 = undefined; - while (true) { - const n = body_reader.readSliceShort(&tmp) catch break; - if (n == 0) break; - try err_buf.appendSlice(self.allocator, tmp[0..n]); - if (err_buf.items.len > 16 * 1024) break; - } - const status: u16 = @intFromEnum(rr.response.head.status); - // Anthropic rejects oversized requests with HTTP 400 and a - // "prompt is too long" message; `classifyHttpStatus` maps that to - // ContextOverflow so the caller can compact and retry. Other - // statuses map to retryable/terminal provider errors. - const classified = provider_mod.classifyHttpStatus(status, err_buf.items); - // 401/403 is routinely recovered by the turn-runner's forced token - // refresh + reopen; demote it to `.debug` (still in the debug log) - // so a transparent refresh doesn't surface a scary error line. The - // retry layer raises a hard error only if recovery ultimately fails. - if (classified == error.ProviderAuthFailed) { - std.log.debug("anthropic_messages HTTP {d} (recoverable auth): {s}", .{ status, err_buf.items }); - } else { - std.log.err("anthropic_messages HTTP {d}: {s}", .{ status, err_buf.items }); - } - if (self.diag) |d| { - d.status_code = status; - d.retry_after_ms = retry_after_ms; - } - return classified; + return provider_mod.classifyErrorResponse(self.allocator, &rr.response, &rr.transfer_buf, self.diag, "anthropic_messages"); } rr.body_reader = rr.response.reader(&rr.transfer_buf); @@ -498,15 +450,7 @@ const StreamState = struct { /// absent). Replaces any previous value. fn setStreamErrorMessage(self: *StreamState, kind: ?[]const u8, message: ?[]const u8) !void { if (self.stream_error_message) |old| self.allocator.free(old); - self.stream_error_message = null; - self.stream_error_message = if (kind != null and message != null) - try std.fmt.allocPrint(self.allocator, "{s}: {s}", .{ kind.?, message.? }) - else if (kind) |k| - try self.allocator.dupe(u8, k) - else if (message) |m| - try self.allocator.dupe(u8, m) - else - null; + self.stream_error_message = try provider_mod.formatStreamError(self.allocator, kind, message); } /// Close the active block: append it to `blocks` and emit block_complete. -- cgit v1.3