feat: add openmax-bridge, a JSON-RPC over stdio front end#48
Merged
Conversation
A separate binary that exposes a running session over line-delimited JSON-RPC 2.0 on stdio, so any host that speaks JSON-RPC can drive openmax without handling its native JSONL envelope. It is a client of the pinned openmax-stdio contract, not a change to the harness core. - New crate crates/bridge (open-max-bridge, binary openmax-bridge). It spawns openmax --stdio (or $OPENMAX_BIN) and translates both directions. - Methods: initialize (answered from the child hello), prompt (streams update notifications and resolves with stop_reason at turn end), cancel, approve, shutdown. A prompt request stays open until the turn's done. - translate.rs is a pure mapping layer with no I/O, unit-tested across every method, child-line class, and JSON-RPC builder; main.rs is thin subprocess plumbing over two reader threads and one channel. - README documents the bridge methods and update stream.
|
| Filename | Overview |
|---|---|
| crates/bridge/src/main.rs | Adds subprocess management, request dispatch, prompt lifecycle tracking, and stdio event forwarding. |
| crates/bridge/src/translate.rs | Adds JSON-RPC parsing, child command translation, event classification, response builders, and unit tests. |
| crates/bridge/Cargo.toml | Defines the new bridge binary and its serde_json dependency. |
Reviews (2): Last reviewed commit: "fix: harden bridge request lifecycle and..." | Re-trigger Greptile
Address review findings on the JSON-RPC front end: - Track turn activity separately from the response id, so a notification prompt (no id) still blocks a concurrent prompt and cannot let one turn's done resolve another request. - Reject a malformed or non-2.0 envelope with -32600 before any method runs, so an unversioned or 1.0 message cannot reach prompt or shutdown. - Do not answer an initialize notification (no id); notifications get no response. - Fail initialize with -32002 when the child never handshook, instead of reporting a partial success without protocol_version or session_id. - forward now returns its write result; a failed prompt write is reported and the turn is not armed, and a child exit fails any pending request with -32001 rather than closing the transport on an unresolved call. - Unit-test envelope version validation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
--stdio(versioned and pinned in #46) is the contract external hosts build against, but every host still has to learn openmax's native JSONL envelope to use it. A host that already speaks JSON-RPC 2.0, the common line protocol for editor and tool integration, had no path in. This adds that path as a thin, separate front end so integration does not require touching the harness core.Summary
crates/bridge(open-max-bridge, binaryopenmax-bridge). It exposes a running session over line-delimited JSON-RPC 2.0 on stdio and is a client of theopenmax-stdio/1contract: it spawnsopenmax --stdio(or$OPENMAX_BIN) and translates both directions. The core is unchanged and gains no dependency.initialize(answered from the child hello: server, protocol_version, version, session_id),prompt { text }(streamsupdatenotifications, resolves with{ stop_reason }at the turn'sdone),cancel,approve { approval_id, approved },shutdown. A request carriesid; a notification omits it. A secondpromptwhile one is in flight is a JSON-RPC error.updatenotification, approval requests included; the host answers withapprove. Closing stdin drains the in-flight turn, mirroring the underlying protocol.translate.rsis a pure mapping layer with no I/O (parsing, request-to-command mapping, child-line classification, JSON-RPC builders), unit-tested exhaustively.main.rsis thin subprocess plumbing: two reader threads feeding one channel, hello read synchronously soinitializenever races the child's first write.updatestream.Test Plan
cargo test --workspace(6 bridge + 145 core + 59 tui)cargo clippy --all-targets --locked -- -D warningsinitializeextraction, and JSON-RPC builder shapeopenmax --stdio:initializeresolves withprotocol_versionandsession_id; apromptstreamsupdatenotifications and its request resolves atdonewith the turn'sstop_reason; stdin close drains and exits cleanly