diff --git a/STRUCTURE.tree b/STRUCTURE.tree index fb0c992..d861dec 100644 --- a/STRUCTURE.tree +++ b/STRUCTURE.tree @@ -3,6 +3,8 @@ ├── buf.gen.yaml ├── buf.yaml ├── build.rs +├── .cargo +│   └── config.toml ├── Cargo.lock ├── Cargo.toml ├── CLAUDE.md @@ -10,6 +12,17 @@ ├── CONTRIBUTING.md ├── DEPLOYMENT_GUIDE.md ├── DESIGN_DECISIONS.md +├── docs +│   ├── specs +│   │   └── ecosystem +│   │   └── 2026-05-01-phase-1-integration.md +│   └── superpowers +│   ├── plans +│   │   ├── 2026-05-10-serde-registry-integration.md +│   │   └── 2026-05-15-brain-service-implementation.md +│   └── specs +│   ├── 2026-05-10-serde-registry-integration-design.md +│   └── 2026-05-15-brain-service-design.md ├── examples │   └── generate_golden.rs ├── FAQ.md @@ -18,13 +31,18 @@ │   ├── python │   │   └── vtuber │   │   └── v1 +│   │   ├── assets_pb2.py +│   │   ├── assets_pb2.pyi │   │   ├── conversation_pb2.py │   │   ├── conversation_pb2.pyi +│   │   ├── image_pb2.py +│   │   ├── image_pb2.pyi │   │   ├── persona_pb2.py │   │   ├── persona_pb2.pyi │   │   ├── __pycache__ │   │   │   ├── conversation_pb2.cpython-312.pyc │   │   │   ├── persona_pb2.cpython-312.pyc +│   │   │   ├── tool_call_pb2.cpython-312.pyc │   │   │   └── voice_profile_pb2.cpython-312.pyc │   │   ├── tool_call_pb2.py │   │   ├── tool_call_pb2.pyi @@ -37,7 +55,9 @@ │   │   └── timestamp.ts │   └── vtuber │   └── v1 +│   ├── assets.ts │   ├── conversation.ts +│   ├── image.ts │   ├── persona.ts │   ├── tool_call.ts │   └── voice_profile.ts @@ -45,11 +65,13 @@ │   ├── ISSUE_TEMPLATE │   │   ├── bug_report.yml │   │   └── feature_request.yml +│   ├── labeler.yml │   ├── PULL_REQUEST_TEMPLATE.md │   └── workflows │   ├── badges.yml │   ├── ci.yml │   ├── pr_automation.yml +│   ├── publish.yml │   └── security.yml ├── .gitignore ├── golden_directive.bin @@ -66,8 +88,10 @@ │   │   ├── test_golden_roundtrip.mojo │   │   └── test_roundtrip.mojo │   └── vtuber_contracts.mojo +├── .npmrc ├── package.json ├── PHILOSOPHY.md +├── pip.conf ├── .pixi │   ├── .condapackageignore │   ├── envs @@ -3011,6 +3035,7 @@ │   │   │   │   │   │   │   │   ├── message_factory.cpython-312.pyc │   │   │   │   │   │   │   │   ├── reflection.cpython-312.pyc │   │   │   │   │   │   │   │   ├── runtime_version.cpython-312.pyc +│   │   │   │   │   │   │   │   ├── struct_pb2.cpython-312.pyc │   │   │   │   │   │   │   │   ├── symbol_database.cpython-312.pyc │   │   │   │   │   │   │   │   ├── text_encoding.cpython-312.pyc │   │   │   │   │   │   │   │   ├── text_format.cpython-312.pyc @@ -4929,10 +4954,14 @@ │   │   │   │   │   └── mojo │   │   │   │   │   └── transform │   │   │   │   │   └── 1.0.0b1.dev2026042817a8e9fbebcd07fcee4a6fe028b12dff63-production +│   │   │   │   │   ├── MDZmYmE2MWRjNzViYWUyNmNhMjhmMzQ5ZWJlMmI0ZmM │   │   │   │   │   ├── Mzk3ZjcxZGY1NDM0ZDM1MDM4Mjk4N2I2Y2EwOTVjMmI │   │   │   │   │   ├── NTA2OTA1YmU3ODI1ODJhYzQ2NTBjZmYzOWQ2NmUyYTY │   │   │   │   │   ├── NTNmYzIyMjc0NGM4OTM2ODgxODEwOTgxZGQyMTAxMTM +│   │   │   │   │   ├── NWFiZmZjNTNjNDlhZjgwMDhjYTAyOGMyMjk0YTE1NjY │   │   │   │   │   ├── NzI5MmQ4YjVhYmQyNWYzNDYwZmQ2ODM0NjRhMmFhYWI +│   │   │   │   │   ├── ODdjY2I5NmY0N2Y5MGQyZDFkNTdjNzYyOWU0ZjE1Yzc +│   │   │   │   │   ├── OGRkZmFlZjRiODVkNjEwMzc4MmVhN2ZkNDAyZjFjMTE │   │   │   │   │   └── YmMwMTA3MDg1MTNhYjg4MTI4MTM1M2EzOWM4OTJiMjU │   │   │   │   ├── crashdb │   │   │   │   │   ├── attachments @@ -8537,6 +8566,7 @@ │   ├── .gitignore │   └── task-cache-v0 │   ├── default-check-d0a66a65c7528968.json +│   ├── default-generate-d0a66a65c7528968.json │   └── default-test-d0a66a65c7528968.json ├── pixi.lock ├── pixi.toml @@ -8545,6 +8575,8 @@ ├── proto │   └── vtuber │   └── v1 +│   ├── assets.proto +│   ├── brain.proto │   ├── conversation.proto │   ├── persona.proto │   ├── tool_call.proto @@ -8563,9 +8595,10 @@ ├── SUPPORT.md ├── tests │   ├── persona_yaml_roundtrip.rs -│   └── roundtrip.rs +│   ├── roundtrip.rs +│   └── serde_roundtrip.rs ├── TROUBLESHOOTING.md ├── tsconfig.json └── VISION.md -480 directories, 8089 files +487 directories, 8115 files diff --git a/build.rs b/build.rs index 6f9d9d3..0998052 100644 --- a/build.rs +++ b/build.rs @@ -10,6 +10,7 @@ fn main() -> Result<(), Box> { "proto/vtuber/v1/persona.proto", "proto/vtuber/v1/tool_call.proto", "proto/vtuber/v1/assets.proto", + "proto/vtuber/v1/brain.proto", ]; tonic_build::configure() diff --git a/docs/superpowers/plans/2026-05-15-brain-service-implementation.md b/docs/superpowers/plans/2026-05-15-brain-service-implementation.md new file mode 100644 index 0000000..4c51f1b --- /dev/null +++ b/docs/superpowers/plans/2026-05-15-brain-service-implementation.md @@ -0,0 +1,113 @@ +# BrainService Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Implement the `BrainService` gRPC interface in `vtuber.v1` and ensure it is serializable and integrated into the SDK. + +**Architecture:** Add a new proto file, update the build script for codegen/serde, and verify with unit tests. + +**Tech Stack:** Protobuf, Rust (tonic, pbjson). + +--- + +### Task 1: Define BrainService Proto + +**Files:** +- Create: `proto/vtuber/v1/brain.proto` + +- [ ] **Step 1: Create brain.proto** + +```proto +syntax = "proto3"; + +package vtuber.v1; + +service BrainService { + rpc PushContext (PushContextRequest) returns (PushContextResponse); +} + +message PushContextRequest { + string session_id = 1; + string user_id = 2; + string message = 3; + map metadata = 4; +} + +message PushContextResponse { + bool accepted = 1; + string request_id = 2; +} +``` + +- [ ] **Step 2: Lint the proto file** + +Run: `buf lint` +Expected: PASS + +### Task 2: Update Codegen & Serde Integration + +**Files:** +- Modify: `build.rs` + +- [ ] **Step 1: Add brain.proto to the list of protos in build.rs** + +```rust + let protos = &[ + // ... + "proto/vtuber/v1/brain.proto", + ]; +``` + +- [ ] **Step 2: Build the project to trigger codegen** + +Run: `cargo build` +Expected: SUCCESS + +### Task 3: Verify with Unit Tests + +**Files:** +- Modify: `tests/serde_roundtrip.rs` + +- [ ] **Step 1: Add test case for PushContextRequest** + +```rust +use vtuber_contracts::vtuber::v1::PushContextRequest; + +#[test] +fn test_push_context_request_serde() { + let mut metadata = std::collections::HashMap::new(); + metadata.insert("source".to_string(), "unit-test".to_string()); + + let request = PushContextRequest { + session_id: "session-456".to_string(), + user_id: "user-789".to_string(), + message: "Neural activation initiated".to_string(), + metadata, + }; + + let json = serde_json::to_string(&request).unwrap(); + let decoded: PushContextRequest = serde_json::from_str(&json).unwrap(); + + assert_eq!(request.session_id, decoded.session_id); + assert_eq!(request.metadata.get("source"), Some(&"unit-test".to_string())); +} +``` + +- [ ] **Step 2: Run tests** + +Run: `cargo test --test serde_roundtrip` +Expected: PASS + +### Task 4: Finalize and Cleanup + +- [ ] **Step 1: Update STRUCTURE.tree** + +Run: `tree -a -I 'node_modules|.git|target' > STRUCTURE.tree` + +- [ ] **Step 2: Commit and push** + +```bash +git add . +git commit -m "feat: add BrainService and PushContext definitions" +git push origin +``` diff --git a/docs/superpowers/specs/2026-05-15-brain-service-design.md b/docs/superpowers/specs/2026-05-15-brain-service-design.md new file mode 100644 index 0000000..1a2a72c --- /dev/null +++ b/docs/superpowers/specs/2026-05-15-brain-service-design.md @@ -0,0 +1,30 @@ +# Design Spec: BrainService & PushContext Definitions + +## 📝 Overview +This specification details the formalization of the `BrainService` gRPC interface. This service acts as a typed boundary for sending session context (messages, metadata) from upstream services (like `vtuber-api`) to the central `vtuber-brain` component. + +## 🔗 Related Issues +- Fixes #9 (Add BrainService and PushContext definitions) + +## 🏗️ Architectural Decisions + +### 1. Namespace & Package Consistency +- **Package Name:** `vtuber.v1` (aligned with existing contracts). +- **File Location:** `proto/vtuber/v1/brain.proto`. +- **Reasoning:** Maintains a flat and consistent API structure, making it easier for downstream consumers to discover and use types without nested namespaces. + +### 2. Service Definition +- **Service:** `BrainService` +- **RPC:** `PushContext(PushContextRequest) -> PushContextResponse` +- **Data Model:** + - `PushContextRequest`: Contains `session_id`, `user_id`, `message`, and a `metadata` map. + - `PushContextResponse`: Returns an `accepted` flag and a `request_id` for tracking. + +### 3. Integrated Tooling Support +- **Serde:** The new types will automatically support JSON/YAML serialization via the existing `pbjson` integration in `build.rs`. +- **Registry:** The updated crate including `BrainService` will be published to the internal Kellnr registry. + +## 🧪 Verification Plan +1. **Linting:** Run `buf lint` to ensure compliance with the Canonical Protobuf Standard. +2. **Codegen:** Run `cargo build` to verify Rust code generation. +3. **Round-trip Test:** Extend `tests/serde_roundtrip.rs` to include a verification for `PushContextRequest`. diff --git a/proto/vtuber/v1/brain.proto b/proto/vtuber/v1/brain.proto new file mode 100644 index 0000000..e7655ad --- /dev/null +++ b/proto/vtuber/v1/brain.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package vtuber.v1; + +// BrainService handles the pushing of session context to the central brain. +service BrainService { + // PushContext allows upstream services to send user messages and metadata. + rpc PushContext (PushContextRequest) returns (PushContextResponse); +} + +message PushContextRequest { + string session_id = 1; + string user_id = 2; + string message = 3; + // metadata for additional context-specific information. + map metadata = 4; +} + +message PushContextResponse { + bool accepted = 1; + string request_id = 2; +} diff --git a/tests/serde_roundtrip.rs b/tests/serde_roundtrip.rs index c6f16fb..6aada26 100644 --- a/tests/serde_roundtrip.rs +++ b/tests/serde_roundtrip.rs @@ -1,4 +1,4 @@ -use vtuber_contracts::vtuber::v1::ConversationDirective; +use vtuber_contracts::vtuber::v1::{ConversationDirective, PushContextRequest}; #[test] fn test_directive_serde_json() { @@ -18,3 +18,27 @@ fn test_directive_serde_json() { assert_eq!(directive.directive_id, decoded.directive_id); assert_eq!(directive.text_prompt, decoded.text_prompt); } + +#[test] +fn test_push_context_request_serde() { + let mut metadata = std::collections::HashMap::new(); + metadata.insert("source".to_string(), "unit-test".to_string()); + + let request = PushContextRequest { + session_id: "session-456".to_string(), + user_id: "user-789".to_string(), + message: "Neural activation initiated".to_string(), + metadata, + }; + + // Serialize to JSON + let json = serde_json::to_string(&request).expect("Failed to serialize"); + println!("Serialized PushContextRequest: {}", json); + + // Deserialize back to struct + let decoded: PushContextRequest = serde_json::from_str(&json).expect("Failed to deserialize"); + + assert_eq!(request.session_id, decoded.session_id); + assert_eq!(request.message, decoded.message); + assert_eq!(request.metadata.get("source"), Some(&"unit-test".to_string())); +}