Skip to content

Commit 40db6a0

Browse files
Antigravity Agentclaude
andcommitted
fix(bridge): POST body for results, increase limit to 100KB
- bridge-agent.sh: send result as POST body instead of URL query param - perplexity_bridge.zig: read full POST body via Content-Length (up to 128KB) - Remove URL-encode/decode overhead for results - Increase MAX_RESULT from 50KB to 100KB Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d504207 commit 40db6a0

2 files changed

Lines changed: 47 additions & 18 deletions

File tree

deploy/tri-bridge-agent.sh

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ RAILWAY_URL="${RAILWAY_URL:-https://trinity-production-a1d4.up.railway.app}"
1818
TOKEN="${PX_BRIDGE_TOKEN:?ERROR: PX_BRIDGE_TOKEN not set}"
1919
POLL_INTERVAL="${PX_POLL_INTERVAL:-3}"
2020
REPO_DIR="${PX_REPO_DIR:-$(cd "$(dirname "$0")/.." && pwd)}"
21-
MAX_RESULT=50000 # 50KB max result size
21+
MAX_RESULT=100000 # 100KB max result size
2222

2323
# ─── Command Whitelist ───────────────────────────────────────
2424
# Only these command prefixes are allowed to execute.
@@ -94,10 +94,11 @@ while true; do
9494
EXIT_CODE=403
9595
fi
9696

97-
# URL-encode result and post back
98-
ENCODED_RESULT=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.stdin.read()))" <<< "$RESULT" 2>/dev/null || echo "encoding_error")
99-
100-
curl -sf "${RAILWAY_URL}/px/done?token=${TOKEN}&id=${JOB_ID}&exit=${EXIT_CODE}&result=${ENCODED_RESULT}" > /dev/null 2>&1 || \
97+
# POST result as body (id and exit in query params)
98+
curl -sf -X POST \
99+
-H "Content-Type: text/plain" \
100+
--data-binary "$RESULT" \
101+
"${RAILWAY_URL}/px/done?token=${TOKEN}&id=${JOB_ID}&exit=${EXIT_CODE}" > /dev/null 2>&1 || \
101102
echo "[bridge-agent] WARNING: failed to post result for $JOB_ID"
102103

103104
echo "[bridge-agent] $(date '+%H:%M:%S') done=$JOB_ID exit=$EXIT_CODE (${#RESULT} bytes)"

src/tri-api/perplexity_bridge.zig

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ pub const Bridge = struct {
6969
}
7070

7171
fn handleRequest(self: *Bridge, stream: std.net.Stream) !void {
72-
// Read HTTP request (up to 4KB header)
73-
var buf: [4096]u8 = undefined;
72+
// Read HTTP request headers (up to 8KB)
73+
var buf: [8192]u8 = undefined;
7474
const n = stream.read(&buf) catch return;
7575
if (n == 0) return;
7676
const request = buf[0..n];
@@ -105,13 +105,48 @@ pub const Bridge = struct {
105105

106106
std.debug.print("[px-bridge] {s} {s}\n", .{if (is_get) "GET" else "POST", path});
107107

108-
// Extract POST body if present
108+
// Extract POST body — read full body based on Content-Length
109109
var post_body: ?[]const u8 = null;
110+
var body_alloc: ?[]u8 = null;
111+
defer if (body_alloc) |b| self.allocator.free(b);
112+
110113
if (is_post) {
111-
// Find end of headers
112114
if (std.mem.indexOf(u8, request, "\r\n\r\n")) |hdr_end| {
113115
const body_start = hdr_end + 4;
114-
if (body_start < n) {
116+
const headers = request[0..hdr_end];
117+
118+
// Parse Content-Length
119+
var content_length: usize = 0;
120+
var hdr_iter = std.mem.splitSequence(u8, headers, "\r\n");
121+
while (hdr_iter.next()) |line| {
122+
if (std.ascii.startsWithIgnoreCase(line, "content-length:")) {
123+
const val = std.mem.trim(u8, line["content-length:".len..], &std.ascii.whitespace);
124+
content_length = std.fmt.parseInt(usize, val, 10) catch 0;
125+
break;
126+
}
127+
}
128+
129+
if (content_length > max_body) content_length = max_body;
130+
131+
if (content_length > 0) {
132+
// Allocate buffer for full body
133+
body_alloc = self.allocator.alloc(u8, content_length) catch null;
134+
if (body_alloc) |full_body| {
135+
// Copy what we already have
136+
const already_read = @min(n - body_start, content_length);
137+
@memcpy(full_body[0..already_read], request[body_start .. body_start + already_read]);
138+
139+
// Read remaining body from stream
140+
var total: usize = already_read;
141+
while (total < content_length) {
142+
const r = stream.read(full_body[total..content_length]) catch break;
143+
if (r == 0) break;
144+
total += r;
145+
}
146+
post_body = full_body[0..total];
147+
}
148+
} else if (body_start < n) {
149+
// No Content-Length, use what's in buffer
115150
post_body = request[body_start..n];
116151
}
117152
}
@@ -358,14 +393,7 @@ pub const Bridge = struct {
358393
}
359394

360395
fn handleDone(self: *Bridge, stream: std.net.Stream, id: []const u8, result: []const u8, exit_code: i32) !void {
361-
// URL-decode '+' as spaces in result
362-
const decoded_result = try self.allocator.alloc(u8, result.len);
363-
defer self.allocator.free(decoded_result);
364-
for (result, 0..) |c, i| {
365-
decoded_result[i] = if (c == '+') ' ' else c;
366-
}
367-
368-
self.updateJob(id, "done", decoded_result, exit_code) catch {
396+
self.updateJob(id, "done", result, exit_code) catch {
369397
try writeResponse(stream, "404", "{\"error\":\"job not found\"}");
370398
return;
371399
};

0 commit comments

Comments
 (0)