feat: beaver first commit
This commit is contained in:
@ -4,7 +4,7 @@ import asyncio
|
||||
from collections.abc import Sequence
|
||||
from typing import Any
|
||||
|
||||
from custom.beaver_terminal_client import BeaverTerminalClient
|
||||
from beaver_terminal_client import BeaverTerminalClient
|
||||
from livekit.agents import llm
|
||||
from livekit.agents.types import (
|
||||
DEFAULT_API_CONNECT_OPTIONS,
|
||||
@ -14,7 +14,6 @@ from livekit.agents.types import (
|
||||
)
|
||||
from livekit.agents.utils import shortuuid
|
||||
|
||||
|
||||
def latest_user_text(chat_ctx: llm.ChatContext) -> str:
|
||||
for message in reversed(chat_ctx.messages()):
|
||||
if message.role != "user":
|
||||
|
||||
@ -686,18 +686,16 @@ async def entrypoint(ctx: JobContext) -> None:
|
||||
stt_stream = stt.StreamAdapter(stt=blackbox_stt, vad=ctx.proc.userdata["vad"])
|
||||
|
||||
if LLM_PROVIDER == "beaver":
|
||||
beaver_url = os.getenv("CUSTOM_BEAVER_WS_URL") or os.getenv("BEAVER_WS_URL", "").strip()
|
||||
beaver_url = _first_env("CUSTOM_BEAVER_WS_URL", "BEAVER_WS_URL")
|
||||
if not beaver_url:
|
||||
raise RuntimeError(f"CUSTOM_BEAVER_WS_URL or BEAVER_WS_URL is not set in {CUSTOM_ENV_PATH}")
|
||||
|
||||
beaver_peer_id = (
|
||||
os.getenv("CUSTOM_BEAVER_PEER_ID")
|
||||
or os.getenv("BEAVER_PEER_ID")
|
||||
_first_env("CUSTOM_BEAVER_PEER_ID", "BEAVER_PEER_ID", "TERMINAL_PEER_ID")
|
||||
or f"livekit-{ctx.room.name}"
|
||||
)
|
||||
beaver_device_name = (
|
||||
os.getenv("CUSTOM_BEAVER_DEVICE_NAME")
|
||||
or os.getenv("BEAVER_DEVICE_NAME")
|
||||
_first_env("CUSTOM_BEAVER_DEVICE_NAME", "BEAVER_DEVICE_NAME", "TERMINAL_DEVICE_NAME")
|
||||
or "livekit-custom-agent"
|
||||
)
|
||||
base_llm = BeaverLLM(
|
||||
@ -709,10 +707,11 @@ async def entrypoint(ctx: JobContext) -> None:
|
||||
text_llm = base_llm
|
||||
vision_llm = base_llm
|
||||
logger.info(
|
||||
"Using Beaver gateway url=%s peer_id=%s device_name=%s",
|
||||
"Using Beaver gateway url=%s peer_id=%s device_name=%s room=%s",
|
||||
beaver_url,
|
||||
beaver_peer_id,
|
||||
beaver_device_name,
|
||||
ctx.room.name,
|
||||
)
|
||||
elif LLM_PROVIDER in {"hermes", "hermes_gateway", "openclaw"}:
|
||||
gateway_url = os.getenv("CUSTOM_HERMES_GATEWAY_URL", "").strip()
|
||||
@ -1000,6 +999,14 @@ def _env_bool(name: str, default: bool) -> bool:
|
||||
return default
|
||||
|
||||
|
||||
def _first_env(*names: str) -> str | None:
|
||||
for name in names:
|
||||
value = os.getenv(name)
|
||||
if value and value.strip():
|
||||
return value.strip()
|
||||
return None
|
||||
|
||||
|
||||
def _recording_options_from_env() -> RecordingOptions:
|
||||
return RecordingOptions(
|
||||
audio=_env_bool("CUSTOM_RECORD_AUDIO", False),
|
||||
|
||||
@ -3,7 +3,10 @@ import json
|
||||
import aiohttp
|
||||
from aiohttp import web
|
||||
|
||||
from custom.beaver_llm import BeaverLLM, latest_user_text
|
||||
try:
|
||||
from custom.beaver_llm import BeaverLLM, latest_user_text
|
||||
except ModuleNotFoundError:
|
||||
from beaver_llm import BeaverLLM, latest_user_text
|
||||
from livekit.agents import ChatContext
|
||||
|
||||
|
||||
@ -83,16 +86,13 @@ async def test_beaver_llm_sends_latest_user_text_and_returns_reply(
|
||||
await runner.cleanup()
|
||||
|
||||
assert collected.text == "beaver reply"
|
||||
assert received == [
|
||||
{
|
||||
"type": "connect",
|
||||
"peer_id": "livekit-room",
|
||||
"device_name": "livekit-custom-agent",
|
||||
"capabilities": ["text"],
|
||||
},
|
||||
{
|
||||
"type": "message",
|
||||
"message_id": "livekit-room-000001",
|
||||
"text": "hello beaver",
|
||||
},
|
||||
]
|
||||
assert received[0] == {
|
||||
"type": "connect",
|
||||
"peer_id": "livekit-room",
|
||||
"device_name": "livekit-custom-agent",
|
||||
"capabilities": ["text"],
|
||||
}
|
||||
assert received[1]["type"] == "message"
|
||||
assert received[1]["message_id"].startswith("livekit-room-")
|
||||
assert received[1]["message_id"].endswith("-000001")
|
||||
assert received[1]["text"] == "hello beaver"
|
||||
|
||||
@ -58,6 +58,13 @@ def test_message_id_generator_uses_monotonic_peer_counter() -> None:
|
||||
assert generator.counter == 9
|
||||
|
||||
|
||||
def test_message_id_generator_can_include_nonce() -> None:
|
||||
generator = MessageIdGenerator(peer_id="device-001", nonce="run12345")
|
||||
|
||||
assert generator.next_id() == "device-001-run12345-000001"
|
||||
assert generator.next_id() == "device-001-run12345-000002"
|
||||
|
||||
|
||||
async def test_client_connects_sends_text_and_returns_assistant_reply(
|
||||
unused_tcp_port: int,
|
||||
) -> None:
|
||||
@ -113,6 +120,7 @@ async def test_client_connects_sends_text_and_returns_assistant_reply(
|
||||
url=f"http://127.0.0.1:{unused_tcp_port}/api/channels/terminal-dev/ws",
|
||||
peer_id="device-001",
|
||||
device_name="desk-terminal",
|
||||
message_ids=MessageIdGenerator(peer_id="device-001"),
|
||||
)
|
||||
|
||||
try:
|
||||
@ -180,6 +188,7 @@ async def test_client_returns_cached_duplicate_reply(unused_tcp_port: int) -> No
|
||||
url=f"http://127.0.0.1:{unused_tcp_port}/api/channels/terminal-dev/ws",
|
||||
peer_id="device-001",
|
||||
device_name="desk-terminal",
|
||||
message_ids=MessageIdGenerator(peer_id="device-001"),
|
||||
)
|
||||
|
||||
try:
|
||||
@ -223,6 +232,7 @@ async def test_client_raises_on_error_frames(unused_tcp_port: int) -> None:
|
||||
url=f"http://127.0.0.1:{unused_tcp_port}/api/channels/terminal-dev/ws",
|
||||
peer_id="device-001",
|
||||
device_name="desk-terminal",
|
||||
message_ids=MessageIdGenerator(peer_id="device-001"),
|
||||
)
|
||||
|
||||
try:
|
||||
@ -284,6 +294,7 @@ async def test_client_treats_assistant_finish_reason_error_as_failed_turn(
|
||||
url=f"http://127.0.0.1:{unused_tcp_port}/api/channels/terminal-dev/ws",
|
||||
peer_id="device-001",
|
||||
device_name="desk-terminal",
|
||||
message_ids=MessageIdGenerator(peer_id="device-001"),
|
||||
)
|
||||
|
||||
try:
|
||||
@ -326,6 +337,7 @@ async def test_client_ping_sends_ping_and_waits_for_pong(unused_tcp_port: int) -
|
||||
url=f"http://127.0.0.1:{unused_tcp_port}/api/channels/terminal-dev/ws",
|
||||
peer_id="device-001",
|
||||
device_name="desk-terminal",
|
||||
message_ids=MessageIdGenerator(peer_id="device-001"),
|
||||
)
|
||||
|
||||
try:
|
||||
@ -398,6 +410,7 @@ async def test_client_reconnects_with_same_peer_id_when_socket_closes_before_sen
|
||||
url=f"http://127.0.0.1:{unused_tcp_port}/api/channels/terminal-dev/ws",
|
||||
peer_id="device-001",
|
||||
device_name="desk-terminal",
|
||||
message_ids=MessageIdGenerator(peer_id="device-001"),
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user