From b56f57bf7fe08870907c2820a69873983aaa0d30 Mon Sep 17 00:00:00 2001 From: opencode controller Date: Tue, 30 Jun 2026 20:26:06 -0400 Subject: [PATCH] =?UTF-8?q?feat(slice-3):=20+rutster-brain-realtime=20crat?= =?UTF-8?q?e=20skeleton=20+=20async-trait=20dep=20(spec=20=C2=A71.1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Workspace member 8 of 8. Library + binary; mirrored slice-2's rutster-tap-echo shape. Three stub modules (api_key, translator, openai_client) filled in by Tasks 3-5. No behavioral code yet — this task only locks the crate boundary + the new async-trait dep (the Tool trait in Task 6 needs it for async-fns-in-trait-objects). --- Cargo.lock | 17 +++++++++++ Cargo.toml | 3 ++ crates/rutster-brain-realtime/Cargo.toml | 27 ++++++++++++++++++ crates/rutster-brain-realtime/src/api_key.rs | 2 ++ crates/rutster-brain-realtime/src/lib.rs | 28 +++++++++++++++++++ .../src/openai_client.rs | 1 + .../rutster-brain-realtime/src/translator.rs | 1 + 7 files changed, 79 insertions(+) create mode 100644 crates/rutster-brain-realtime/Cargo.toml create mode 100644 crates/rutster-brain-realtime/src/api_key.rs create mode 100644 crates/rutster-brain-realtime/src/lib.rs create mode 100644 crates/rutster-brain-realtime/src/openai_client.rs create mode 100644 crates/rutster-brain-realtime/src/translator.rs diff --git a/Cargo.lock b/Cargo.lock index f1b3428..62054df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1182,6 +1182,23 @@ dependencies = [ "uuid", ] +[[package]] +name = "rutster-brain-realtime" +version = "0.1.0" +dependencies = [ + "async-trait", + "base64", + "futures-util", + "rutster-tap", + "serde", + "serde_json", + "tokio", + "tokio-tungstenite", + "tracing", + "tracing-subscriber", + "url", +] + [[package]] name = "rutster-call-model" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index 1efc567..c048b1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "crates/rutster-trunk", "crates/rutster-tap", "crates/rutster-tap-echo", + "crates/rutster-brain-realtime", "crates/rutster-spend", ] @@ -51,3 +52,5 @@ futures-util = "0.3" url = "2" # base64 0.22: PCM <-> base64 codec for the v1 wire format (spec §3). base64 = "0.22" +# async-trait 0.1: async fns in trait objects (Tool trait, slice-3 spec §6.1). +async-trait = "0.1" diff --git a/crates/rutster-brain-realtime/Cargo.toml b/crates/rutster-brain-realtime/Cargo.toml new file mode 100644 index 0000000..5d0a0c2 --- /dev/null +++ b/crates/rutster-brain-realtime/Cargo.toml @@ -0,0 +1,27 @@ +# crates/rutster-brain-realtime/Cargo.toml +[package] +name = "rutster-brain-realtime" +version = "0.1.0" +license.workspace = true +edition.workspace = true +repository.workspace = true +description = "OpenAI Realtime speech-to-speech brain — translates slice-2's tap protocol to OpenAI Realtime's event schema (green-zone per ADR-0008; slice-3 spec §1.1, §4)." + +[dependencies] +rutster-tap = { path = "../rutster-tap" } +tokio = { workspace = true, features = ["full"] } +tokio-tungstenite = { workspace = true, features = ["connect"] } +futures-util = { workspace = true } +serde_json = { workspace = true } +serde = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +url = { workspace = true } +async-trait = { workspace = true } +base64 = { workspace = true } + +[features] +default = [] +# Mock mode: in-process fake OpenAI Realtime WS server (no real API calls). +# Used by the integration test + the offline dev loop (spec §7.3). +mock = [] diff --git a/crates/rutster-brain-realtime/src/api_key.rs b/crates/rutster-brain-realtime/src/api_key.rs new file mode 100644 index 0000000..f67ea6f --- /dev/null +++ b/crates/rutster-brain-realtime/src/api_key.rs @@ -0,0 +1,2 @@ +//! API-key loader (spec §5.3) — implements the env-var + file-path posture. +//! Filled in by Task 3. diff --git a/crates/rutster-brain-realtime/src/lib.rs b/crates/rutster-brain-realtime/src/lib.rs new file mode 100644 index 0000000..08d54d4 --- /dev/null +++ b/crates/rutster-brain-realtime/src/lib.rs @@ -0,0 +1,28 @@ +//! # rutster-brain-realtime +//! +//! **Slice-3 brain:** translates slice-2's tap protocol (the green-zone side of +//! the seam — core-as-client dials this brain's WS server; ADR-0008 classifies +//! the brain as green-zone) to OpenAI Realtime's event schema. The brain +//! process is a WS *server* (core-as-client dials it, unchanged from slice-2) +//! AND a WS *client* to `wss://api.openai.com/v1/realtime` (OpenAI is server +//! on *its* leg). +//! +//! See `docs/superpowers/specs/2026-06-30-slice-3-realtime-brain-design.md` for +//! the full design. +//! +//! ## Modules +//! +//! - [`api_key`] — load API key from env var or file (spec §5.3). +//! - [`translator`] — pure-function event translation (tap ⇄ OpenAI). +//! - [`openai_client`] — wss:// client to api.openai.com/v1/realtime. +//! +//! ## Dev mode (`--features=mock`) +//! +//! When built with `mock`, the binary uses in-process `MockRealtimeBrain` +//! (defined in `lib.rs`'s test-support module) instead of dialing OpenAI. +//! No API key required, no real OpenAI calls. Used by the integration test + +//! the offline dev loop (spec §7.3). + +pub mod api_key; +pub mod openai_client; +pub mod translator; diff --git a/crates/rutster-brain-realtime/src/openai_client.rs b/crates/rutster-brain-realtime/src/openai_client.rs new file mode 100644 index 0000000..76a7072 --- /dev/null +++ b/crates/rutster-brain-realtime/src/openai_client.rs @@ -0,0 +1 @@ +//! wss://api.openai.com/v1/realtime client (spec §4). Filled in by Task 5. diff --git a/crates/rutster-brain-realtime/src/translator.rs b/crates/rutster-brain-realtime/src/translator.rs new file mode 100644 index 0000000..4413ae4 --- /dev/null +++ b/crates/rutster-brain-realtime/src/translator.rs @@ -0,0 +1 @@ +//! Tap ⇄ OpenAI Realtime event translation (spec §4). Filled in by Task 4.