fix: unique room names per session, JT_ROOM dispatch, dispatch-first prompt
- token_server: generate voice-{uuid8} room name per request so each
browser session creates a fresh room and triggers agent dispatch
- token claim: add jobType JT_ROOM to roomConfig.agents
- livekit.yaml: revert empty_timeout to default (300s)
- agent.py: system prompt now mandates dispatch_task for all non-trivial
tasks (not just research); removed inline web_search instructions;
added tool_call logging in _ReasoningFallbackWrapper
This commit is contained in:
+24
-16
@@ -63,15 +63,6 @@ SYSTEM_PROMPT = textwrap.dedent("""\
|
||||
- Never write more than three sentences in a row.
|
||||
- Never read back URLs, file paths, or technical identifiers.
|
||||
|
||||
# Web access
|
||||
You have web_search and web_scrape tools. Use them when the user asks about
|
||||
current events, recent news, prices, sports scores, or anything
|
||||
that may have changed since your training data. Search first, then scrape
|
||||
a result only if you need more detail. Answer from what you find, in your
|
||||
normal conversational style — don't cite sources formally, just mention the
|
||||
source naturally ("according to..."). If a search comes up empty, say so
|
||||
briefly and move on.
|
||||
|
||||
# Weather & Time
|
||||
You can check the weather for any location. Use get_weather when the user
|
||||
asks about current conditions, temperature, or forecasts. It returns a
|
||||
@@ -79,6 +70,27 @@ SYSTEM_PROMPT = textwrap.dedent("""\
|
||||
Use get_time when the user asks what time or day it is. If they mention
|
||||
a city, pass it as the location argument.
|
||||
|
||||
# Background Tasks (dispatch_task) — USE FOR ALL NON-TRIVIAL TASKS
|
||||
For ANY task that is not a simple one-sentence answer from your own
|
||||
knowledge, you MUST call dispatch_task. This includes: looking up news,
|
||||
researching topics, checking current events, prices, sports scores,
|
||||
writing something, summarizing, comparing options, planning, or anything
|
||||
that takes more than a couple seconds to think through. Do NOT use
|
||||
web_search or web_scrape directly; always dispatch instead.
|
||||
The only things you answer inline are: weather (get_weather), time
|
||||
(get_time), memory operations, and trivial facts you already know.
|
||||
Examples:
|
||||
- User says "what's the latest news?" → CALL dispatch_task with
|
||||
description="Find the top 5 international news headlines today"
|
||||
- User says "look up the price of a PS5" → CALL dispatch_task with
|
||||
description="Find the current retail price of a PlayStation 5"
|
||||
- User says "plan a weekend trip to Denver" → CALL dispatch_task with
|
||||
description="Plan a two-day weekend trip to Denver including activities"
|
||||
After calling dispatch_task, tell the user "I'll get on that for you"
|
||||
and keep the conversation going. The result comes back automatically — when
|
||||
you receive it, share the findings naturally in your conversational style.
|
||||
You can have multiple tasks running at once.
|
||||
|
||||
# Memory (CRITICAL — always use these tools)
|
||||
You MUST call memory_save whenever the user tells you something to remember,
|
||||
shares a preference, or says "remember that...". Do NOT just say "okay I'll
|
||||
@@ -99,13 +111,6 @@ SYSTEM_PROMPT = textwrap.dedent("""\
|
||||
use skill_save to record it so you can follow it next time. Be selective: only
|
||||
save skills for repeatable tasks, not one-off facts (those go in memory).
|
||||
|
||||
# Background Tasks (dispatch_task)
|
||||
When the user asks you to research something, look up news, or do anything
|
||||
that will take more than a few seconds, CALL dispatch_task with a clear
|
||||
description of what to investigate. Tell the user "I'll take a look at that
|
||||
for you" and keep talking. The result comes back automatically — when you
|
||||
receive it, share the findings naturally. You can have multiple tasks running
|
||||
at once.
|
||||
""")
|
||||
|
||||
|
||||
@@ -165,6 +170,9 @@ class _ReasoningFallbackWrapper:
|
||||
self._last_reasoning = reasoning
|
||||
if chunk.has_response():
|
||||
self._has_content = True
|
||||
tc = getattr(delta, "tool_calls", None)
|
||||
if tc:
|
||||
logger.info("LLM tool_call: %s", [t.function.name for t in tc])
|
||||
return chunk
|
||||
|
||||
async def collect(self):
|
||||
|
||||
+2
-6
@@ -7,9 +7,5 @@ rtc:
|
||||
keys:
|
||||
devkey: devsecret
|
||||
|
||||
# Keep rooms alive for 24h — the agent stays resident so reconnections
|
||||
# don't require a fresh dispatch. Without this, LiveKit destroys the room
|
||||
# after empty_timeout (default 300s), kills the agent job, and the next
|
||||
# join finds no worker registered ("assistant not ready retry").
|
||||
room:
|
||||
empty_timeout: 86400
|
||||
# Rooms are short-lived: each browser session gets a unique room name, so
|
||||
# the agent is dispatched at room creation. Default 300s cleanup is fine.
|
||||
|
||||
+3
-2
@@ -47,7 +47,7 @@ def make_token(room_name: str, identity: str) -> str:
|
||||
"canPublishData": True,
|
||||
},
|
||||
"roomConfig": {
|
||||
"agents": [{"agentName": AGENT_NAME}],
|
||||
"agents": [{"agentName": AGENT_NAME, "jobType": "JT_ROOM"}],
|
||||
},
|
||||
}
|
||||
h = b64url(json.dumps(header).encode())
|
||||
@@ -66,7 +66,8 @@ class Handler(BaseHTTPRequestHandler):
|
||||
|
||||
length = int(self.headers.get("Content-Length", 0))
|
||||
body = json.loads(self.rfile.read(length) or b"{}")
|
||||
room_name = "voice-room"
|
||||
# Unique room per session so LiveKit dispatches the agent at creation.
|
||||
room_name = f"voice-{uuid.uuid4().hex[:8]}"
|
||||
identity = body.get("identity") or f"user-{uuid.uuid4().hex[:8]}"
|
||||
|
||||
token = make_token(room_name, identity)
|
||||
|
||||
Reference in New Issue
Block a user