fix: ChatContext is not a sequence — use .items for len/list; add test suite

Bug fix:
- GemmaLLM.chat(): len(chat_ctx) → len(chat_ctx.items)
- GemmaLLM._compact_context(): list(chat_ctx) → list(chat_ctx.items)
  ChatContext in livekit-agents 1.7 is not iterable or sized directly;
  it exposes an .items list. The TypeError was silently killing all LLM
  responses (agent heard user but never spoke back).

Test suite (tests/):
- test_web_ui.py: static assets, token endpoint, LiveKit WS proxy
- test_llm_api.py: completion, tool calling, thinking-disabled latency, streaming
- test_mcp_tools.py: weather (Fahrenheit), time, memory, skills — all via
  docker exec + in-container MCP client
- test_agent_integration.py: process alive, worker registered, supervisord,
  container health, LiveKit API
- test_compaction.py: size-triggered compaction, system prompt preservation,
  short-context no-op
- conftest.py: shared fixtures (HTTPS client, token, LLM, docker exec helpers)
- Run with: .venv-tests/bin/python -m pytest tests/ -v
This commit is contained in:
Shane
2026-08-22 17:09:29 -04:00
parent 938629df83
commit a1d59580f7
10 changed files with 658 additions and 4 deletions
+5 -4
View File
@@ -192,15 +192,16 @@ class GemmaLLM(openai.LLM):
# Compact if context is large, OR if we've been idle for 5+ minutes
# (user came back after a break — summarize the old conversation).
should_compact = len(chat_ctx) > self.COMPACTION_THRESHOLD
ctx_len = len(chat_ctx.items)
should_compact = ctx_len > self.COMPACTION_THRESHOLD
if not should_compact and idle_for > self.IDLE_COMPACTION_SECONDS:
should_compact = len(chat_ctx) > 6 # minimal context worth summarizing
should_compact = ctx_len > 6 # minimal context worth summarizing
if should_compact:
reason = "idle" if idle_for > self.IDLE_COMPACTION_SECONDS else "size"
logger.info(
"Compacting context (%s): %d items, idle %.0fs",
reason, len(chat_ctx), idle_for,
reason, ctx_len, idle_for,
)
chat_ctx = self._compact_context(chat_ctx, conn_options)
@@ -221,7 +222,7 @@ class GemmaLLM(openai.LLM):
"""
from livekit.agents import llm as lk_llm
items = list(chat_ctx)
items = list(chat_ctx.items)
# Identify the system/instruction message (first item usually)
sys_items = [it for it in items if getattr(it, "role", None) in ("system", "developer")]
non_sys = [it for it in items if getattr(it, "role", None) not in ("system", "developer")]