feat(slice-3): +rutster-brain-realtime crate skeleton + async-trait dep (spec §1.1)

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).
This commit is contained in:
opencode controller
2026-06-30 20:26:06 -04:00
parent 68f097f9d9
commit b56f57bf7f
7 changed files with 79 additions and 0 deletions

17
Cargo.lock generated
View File

@@ -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"

View File

@@ -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"

View File

@@ -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 = []

View File

@@ -0,0 +1,2 @@
//! API-key loader (spec §5.3) — implements the env-var + file-path posture.
//! Filled in by Task 3.

View File

@@ -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;

View File

@@ -0,0 +1 @@
//! wss://api.openai.com/v1/realtime client (spec §4). Filled in by Task 5.

View File

@@ -0,0 +1 @@
//! Tap ⇄ OpenAI Realtime event translation (spec §4). Filled in by Task 4.