fix: disable preemptive_generation for tool call compatibility; add get_time tool
- preemptive_generation was incompatible with MCP tool calls: it starts generating before the turn finalizes, breaking the tool execution loop (agent said 'let me check' then hung forever) - Add get_time(location?) to weather_mcp.py for date/time queries - Update system prompt with Weather & Time section
This commit is contained in:
+6
-3
@@ -70,10 +70,12 @@ SYSTEM_PROMPT = textwrap.dedent("""\
|
||||
source naturally ("according to..."). If a search comes up empty, say so
|
||||
briefly and move on.
|
||||
|
||||
# Weather
|
||||
# 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
|
||||
short summary — relay it naturally in your own words.
|
||||
Use get_time when the user asks what time or day it is. If they mention
|
||||
a city, pass it as the location argument.
|
||||
""")
|
||||
|
||||
|
||||
@@ -269,8 +271,9 @@ async def handle_job(ctx: JobContext) -> None:
|
||||
# VAD-based turn detection: agent waits for user to stop speaking.
|
||||
# ("adaptive" mode requires the LiveKit Cloud barge-in service.)
|
||||
interruption={"mode": "vad"},
|
||||
# Start generating the LLM response before the user fully stops
|
||||
preemptive_generation={"enabled": True},
|
||||
# Preemptive generation is incompatible with tool calls — it starts
|
||||
# generating before the turn finalizes, breaking the MCP execution loop.
|
||||
preemptive_generation={"enabled": False},
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ The tool returns a short, conversational summary suitable for speech
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import httpx
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
@@ -84,5 +85,43 @@ async def get_weather(location: str) -> str:
|
||||
return summary
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def get_time(location: str = "") -> str:
|
||||
"""Get the current date and time.
|
||||
|
||||
If a location is provided, returns the local time there (approximated
|
||||
via wttr.in's timezone data). Otherwise returns UTC time.
|
||||
Use this when the user asks what time or day it is.
|
||||
"""
|
||||
if not location:
|
||||
now = datetime.now(timezone.utc)
|
||||
return f"It's {now.strftime('%I:%M %p')} on {now.strftime('%A, %B %d')}, UTC."
|
||||
|
||||
try:
|
||||
async def _fetch():
|
||||
async with httpx.AsyncClient(timeout=15) as client:
|
||||
resp = await client.get(
|
||||
f"{WTTR_BASE}/{location}?format=j1",
|
||||
headers={"User-Agent": "curl/8.0"},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
import asyncio
|
||||
data = asyncio.get_event_loop().run_until_complete(_fetch())
|
||||
current = data.get("current_condition", [{}])[0] or {}
|
||||
tz_offset = current.get("localObsDateTime", "")
|
||||
area = data.get("nearest_area", [{}])[0] or {}
|
||||
city = (area.get("areaName", [{}])[0].get("value") or location).strip()
|
||||
|
||||
if tz_offset:
|
||||
return f"It's {tz_offset.split(' ')[1][:5]} on {tz_offset.split(' ')[0]} in {city}."
|
||||
except Exception: # noqa: BLE001
|
||||
pass
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
return f"It's {now.strftime('%I:%M %p')} on {now.strftime('%A, %B %d')}, UTC."
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mcp.run(transport="stdio")
|
||||
|
||||
Reference in New Issue
Block a user