diff options
| author | t <t@tjp.lol> | 2026-06-13 23:45:59 -0600 |
|---|---|---|
| committer | t <t@tjp.lol> | 2026-06-15 15:08:32 -0600 |
| commit | 02b4c7a35ac0b714bc045d54fb4bb45d1ce4e490 (patch) | |
| tree | 134196a82dd6fdd55b735be4c0cf38428c85038d /src/luarocks_runtime.zig | |
| parent | 71643a5d69ffc40882c9fcde3cc8a3bcf02d7396 (diff) | |
Add Codex Responses support and session debugging
Teach provider config and auth resolution about the Codex Responses
dialect, including user-facing `style = "openai_responses"` with
`dialect = "codex"`. Serialize and parse Responses traffic with
provider-specific reasoning replay, assistant phase metadata, and robust
function-call assembly keyed by `output_index` so streamed tool inputs
survive proxy quirks and empty terminal payloads.
Also persist thinking origins and message metadata across sessions, add
the Anthropic interleaved-thinking header switch, write per-session
debug logs, and improve the TUI and scripts for inspecting tool output
and session costs.
Diffstat (limited to 'src/luarocks_runtime.zig')
| -rw-r--r-- | src/luarocks_runtime.zig | 103 |
1 files changed, 98 insertions, 5 deletions
diff --git a/src/luarocks_runtime.zig b/src/luarocks_runtime.zig index f76a60e..7f2e161 100644 --- a/src/luarocks_runtime.zig +++ b/src/luarocks_runtime.zig @@ -29,6 +29,7 @@ //! `<panto-binary> lua` (with the absolute path of the running `panto` //! binary) into the luarocks config as `variables.LUA`. +const builtin = @import("builtin"); const std = @import("std"); const Allocator = std.mem.Allocator; const Io = std.Io; @@ -70,6 +71,7 @@ pub const BootstrapError = error{ LuarocksInjectionFailed, LuarocksInstallFailed, LuarocksSearcherInstallFailed, + PantoModuleSigningFailed, PathConfigFailed, PantoExecutablePathUnknown, } || Allocator.Error; @@ -229,6 +231,98 @@ fn stagePantoModule( var dir = try Io.Dir.cwd().openDir(io, layout.lib_lua_dir, .{}); defer dir.close(io); try writeIfDifferent(allocator, io, dir, "panto.so", embedded_panto_so.bytes); + try ensurePantoModuleSignature(allocator, layout); +} + +/// Ad-hoc re-sign the staged `panto.so` so macOS will `dlopen` it. +/// +/// We deliberately spawn `codesign` via `posix_spawn` rather than +/// `std.process.run`. `std.process.run` (via `Io.Threaded`) implements +/// spawning as a raw `fork()` + `execve()`. On macOS a `fork()` from a +/// process that has *any* live secondary thread runs the registered +/// `pthread_atfork` child handlers in the forked child; system-framework +/// handlers can dereference per-thread state that no longer exists in the +/// child and fault (`EXC_BAD_ACCESS`). In a normal `panto` run bootstrap +/// is still single-threaded here so the fork is safe, but under the +/// multithreaded Zig test runner (whose pool already has worker threads, +/// and which installs a debug `SIGSEGV` handler that turns that fault into +/// an `abort()`) the spawned child dies with `SIGABRT` before `codesign` +/// ever execs. `posix_spawn` is a single Darwin primitive that does *not* +/// run userspace `pthread_atfork` handlers — Apple's recommended way to +/// spawn from a multithreaded process — so it sidesteps the hazard +/// entirely while behaving identically to the caller. The child's stdio is +/// redirected to /dev/null (see below); failures surface via the exit +/// status, which we translate into `error.PantoModuleSigningFailed`. +fn ensurePantoModuleSignature( + allocator: Allocator, + layout: panto_home.Layout, +) !void { + if (builtin.os.tag != .macos) return; + + const module_path = try std.fs.path.joinZ(allocator, &.{ layout.lib_lua_dir, "panto.so" }); + defer allocator.free(module_path); + + const argv = [_:null]?[*:0]const u8{ + "/usr/bin/codesign", + "--force", + "--sign", + "-", + module_path.ptr, + null, + }; + + // Redirect the child's stdio to /dev/null: `codesign` is silent on + // success and writes progress/errors to stderr, which we don't want + // leaking into panto's own output (and, under the test runner, racing + // with the build-server IPC). Failures are surfaced via the exit + // status and our own `std.log.err` below. + var actions: std.c.posix_spawn_file_actions_t = undefined; + if (std.c.posix_spawn_file_actions_init(&actions) != 0) { + return error.PantoModuleSigningFailed; + } + defer _ = std.c.posix_spawn_file_actions_destroy(&actions); + const rdonly: c_int = @bitCast(std.c.O{ .ACCMODE = .RDONLY }); + const wronly: c_int = @bitCast(std.c.O{ .ACCMODE = .WRONLY }); + _ = std.c.posix_spawn_file_actions_addopen(&actions, std.c.STDIN_FILENO, "/dev/null", rdonly, 0); + _ = std.c.posix_spawn_file_actions_addopen(&actions, std.c.STDOUT_FILENO, "/dev/null", wronly, 0); + _ = std.c.posix_spawn_file_actions_addopen(&actions, std.c.STDERR_FILENO, "/dev/null", wronly, 0); + + var pid: std.c.pid_t = undefined; + const spawn_rc = std.c.posix_spawn( + &pid, + "/usr/bin/codesign", + &actions, + null, + &argv, + @ptrCast(std.c.environ), + ); + if (spawn_rc != 0) { + std.log.err( + "failed to spawn codesign for staged panto module at {s}: posix_spawn errno={d}", + .{ module_path, spawn_rc }, + ); + return error.PantoModuleSigningFailed; + } + + const status = blk: while (true) { + var status: c_int = undefined; + const rc = std.c.waitpid(pid, &status, 0); + if (rc == -1) { + const err = std.posix.errno(rc); + if (err == .INTR) continue; + std.log.err("failed to wait for codesign: errno={t}", .{err}); + return error.PantoModuleSigningFailed; + } + break :blk @as(u32, @bitCast(status)); + }; + + if (std.c.W.IFEXITED(status) and std.c.W.EXITSTATUS(status) == 0) return; + + std.log.err( + "codesign failed for staged panto module at {s}: status=0x{x}", + .{ module_path, status }, + ); + return error.PantoModuleSigningFailed; } // --------------------------------------------------------------------------- @@ -338,14 +432,13 @@ const default_base_config = \\# exchange_expires_path = "expires_at" \\# exchange_base_url_path = "endpoints.api" \\ - \\# OpenAI Codex via a ChatGPT subscription (device login). Codex speaks the - \\# OpenAI Responses API, not Chat Completions, so style = "openai_responses". - \\# NOTE: this path is implemented but not yet verified against a live - \\# ChatGPT plan — see docs/oauth-provider-auth.md. + \\# OpenAI Codex via a ChatGPT subscription (device login). Codex uses the + \\# Responses protocol with a stricter ChatGPT-subscription dialect. \\# \\# [providers.codex] \\# style = "openai_responses" - \\# base_url = "https://chatgpt.com/backend-api/codex" + \\# dialect = "codex" + \\# base_url = "https://chatgpt.com/backend-api" \\# auth = "openai_codex" \\# \\# [providers.codex.extra_headers] |
