feat(vtuber): add OpenAI-compatible adapter#1234
Conversation
Expose POST /v1/chat/completions (SSE) backed by the OAB agent, so any OpenAI-compatible character skin (AniCompanion, Open-LLM-VTuber, …) gets a real agent with zero client changes. messages[] is flattened into the agent prompt; the agent's streamed reply is re-emitted as OpenAI chat.completion.chunk deltas via a per-request channel.id registry drained by the /ws recv loop. Inline [emotion] tags pass through untouched. Tier 1 of RFC openabdev#1233. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NXngQyvmJwQPNYsiRUNU2m
Additional: Frontend WebSocket Client DemoAdded examples/vtuber-demo/index.html — a minimal WebSocket client reference implementation for VTuber skins. What it does:Connects to OAB Gateway via raw WebSocket (ws://host:8080/ws?token=) Usage:Open index.html in browser, configure WS URL and token, connect and chat. Note:Currently the gateway's handle_oab_connection does not forward GatewayEvents from WS clients to OAB core — backend update needed for full functionality. Code: |
Tier-1 complete ✅All validation items checked:
CI: all checks and smoke tests passing. Next: Tier-2Tier-2 RFC opened as #1235 — WebSocket side-channel ( |
This comment has been minimized.
This comment has been minimized.
Tier-2 adds GET /v1/vtuber/ws — a persistent WebSocket that pushes agent_state, emotion, and notification events derived from GatewayReply commands. VTuber skins connect once and receive real-time state updates (thinking/working/idle, tool usage, emotion tags) without polling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NXngQyvmJwQPNYsiRUNU2m
|
Tier-2 WebSocket event stream pushed (acd3e38). Pending: e2e testing with a live VTuber skin. |
This comment has been minimized.
This comment has been minimized.
Replace Vec<WsClient> with HashMap<u64, WsClient> and an AtomicU64 counter. The old Vec+index scheme broke when broadcast() called swap_remove on dead clients — surviving clients' stored indices became stale, routing subscribe/pong to the wrong connection. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NXngQyvmJwQPNYsiRUNU2m
This comment has been minimized.
This comment has been minimized.
F2: Cap in-flight /v1/chat/completions at 32 by checking vtuber_pending size before accepting — returns 429 when full. F3: Emit SSE comment `: waiting for agent` after 10s of silence, giving clients an early signal before the 180s hard timeout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NXngQyvmJwQPNYsiRUNU2m
|
Review findings addressed:
|
This comment has been minimized.
This comment has been minimized.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NXngQyvmJwQPNYsiRUNU2m
|
All findings resolved, clippy CI fixed in c1b9495. Ready for merge — pending e2e testing with a live VTuber skin. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Rebased persistent channel session reuse on Can's cleaned-up feat/vtuber-adapter (Tier-1 HTTP SSE only, no WS side-channel). Changes retained from original PR: - Fixed channel_id "vtb_persistent" for OAB session pool reuse - try_lock + 429 + Retry-After:3 for serialised access - Persistent channel kept in registry after reply - Improved timeout warning message Dropped from original (Can's base already removed these): - vtuber_ws_clients (Tier-2 WS, deferred upstream) - vtuber_persistent_channel field (dead code, already removed) Co-authored-by: smallgun01 <smallgun01@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
bf3b0a5 to
9919c10
Compare
This comment has been minimized.
This comment has been minimized.
|
Latest head looks good from my pass. I rechecked the final diff after Tier-2 was deferred: this is now scoped to the OpenAI-compatible SSE adapter, persistent VTuber session reuse, serialized turns with 429/Retry-After, constant-time bearer auth comparison, and the docs/config reference updates. No blocking issues found. CI and Docker smoke are green now: 34 pass, 2 skipped, 0 pending/failing. Ball back to reviewer/maintainer for final approval/merge. |
|
LGTM ✅ — Well-structured OpenAI-compatible adapter that follows existing conventions. What This PR DoesAdds a VTuber platform adapter so character skins (AniCompanion, Open-LLM-VTuber, ChatVRM) that speak OpenAI chat completions can connect directly to OpenAB and get full agent capabilities (tool use, MCP, memory) without code changes on the skin side. How It WorksThe adapter exposes Findings
Finding Details🟢 F1: Constant-time auth comparisonUses 🟢 F2: Feature-flag disciplineEvery vtuber integration point is gated behind 🟢 F3: Complete documentation
🟢 F4: Good test coverageTests validate: auth key constant-time comparison, non-streaming rejection, in-flight cap enforcement, request serialization for stream lifetime, message flattening, persistent session prompt extraction, and reply stream idle close. 🟢 F5: Dual-path integrationReply routing is wired in both the WebSocket handler ( Baseline Check
What's Good (🟢)
|
What problem does this solve?
Desktop character apps such as AniCompanion, Open-LLM-VTuber, and ChatVRM already speak OpenAI chat completions, but they usually connect to a raw LLM. This PR lets those skins point at OpenAB instead, so the same UI gets ACP-backed tool use, code editing, memory, MCP, and existing OpenAB steering.
Closes #1233
Discord Discussion URL: https://discord.com/channels/1491295327620169908/1520790210320011274
Architecture
The VTuber adapter now runs inside the unified OpenAB binary:
No separate gateway process or adapter config block is required for VTuber in unified mode. Set
VTUBER_ENABLED=trueon the OpenAB process, and the unified HTTP listener exposes the OpenAI-compatible endpoint.Proposed Solution
OpenAI-Compatible SSE
POST /v1/chat/completionsstreams OpenAI-compatiblechat.completion.chunkevents.[emotion]tags pass through for skins that already parse and strip them before TTS.vtb_persistentchannel reuses one warm ACP session for VTuber traffic, avoiding per-turn cold starts.429withRetry-After: 3.messages[]; the adapter forwards system/developer instructions plus the latest user turn so assistant history is not duplicated inside the persistent ACP session.Why this approach?
Validation
cargo test -p openab-gateway vtuber— 7 VTuber tests passedcargo test -p openab has_unified_platform_env_checks --features unifiedcargo check -p openab --features unifiedcargo clippy -- -D warningscargo testNotes
docs/vtuber.mddocuments unified-mode setup only.docs/config-reference.mdlists the VTuber unified environment variables.