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. |
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.