11import asyncio
22import time
3+ from datetime import datetime
34from livekit .agents .voice import Agent
45from livekit import rtc
56from livekit .agents import ChatContext
67from siphon .config import get_logger , HangupCall , CallTranscription
7- from siphon .agent .internal_prompts import call_agent_prompt , proactive_agent_prompt , datetime_awareness_prompt
8+ from siphon .config .timezone_utils import get_timezone , get_timezone_name
9+ from siphon .agent .internal_prompts import call_agent_prompt
810import os
911
1012logger = get_logger ("calling-agent" )
1315from siphon .memory import MemoryService
1416
1517
18+ def _get_current_datetime_stamp () -> str :
19+ """Generate a current date/time stamp for injection into the system prompt.
20+
21+ This ensures the LLM always knows the real date/time without needing
22+ to call a tool (LLMs often skip tool calls and hallucinate dates).
23+ """
24+ tz = get_timezone ()
25+ tz_name = get_timezone_name () or "local time"
26+
27+ if tz is not None :
28+ now = datetime .now (tz )
29+ formatted = now .strftime ("%A, %B %d, %Y at %I:%M %p %Z" )
30+ else :
31+ now = datetime .now ()
32+ formatted = now .strftime ("%A, %B %d, %Y at %I:%M %p" )
33+
34+ return (
35+ f"\n **CURRENT DATE AND TIME: { formatted } **\n "
36+ f"Today is { now .strftime ('%A' )} . The year is { now .year } . "
37+ f"Use this as your reference for ALL date/time operations. "
38+ f"Do NOT guess or assume any other date.\n "
39+ )
40+
41+
1642class AgentSetup (Agent , HangupCall , CallTranscription ):
1743 def __init__ (self ,
1844 config : dict ,
@@ -50,8 +76,7 @@ def __init__(self,
5076 self .send_greeting = send_greeting
5177 self .greeting_instructions = greeting_instructions
5278
53- # Extract and preserve all prompt components
54- # The system_instructions may contain: base + calendar_guidelines + memory_context
79+ # Build system instructions: base + datetime + core agent rules + calendar + memory
5580 memory_context = ""
5681 calendar_context = ""
5782 base_instructions = system_instructions
@@ -70,12 +95,15 @@ def __init__(self,
7095 base_instructions = parts [0 ].strip ()
7196 calendar_context = "---\n ## INTERNAL RULES - CALENDAR OPERATIONS" + parts [1 ]
7297
73- # Reconstruct in correct order: base + internal rules + calendar + memory
98+ # Inject real current date/time directly into the prompt
99+ # This prevents the LLM from hallucinating dates from its training data
100+ datetime_stamp = _get_current_datetime_stamp ()
101+
102+ # Reconstruct: base + datetime + core rules + calendar + memory
74103 self .system_instructions = (
75104 base_instructions +
76- "\n \n " + call_agent_prompt +
77- "\n \n " + proactive_agent_prompt +
78- "\n \n " + datetime_awareness_prompt +
105+ "\n \n " + datetime_stamp +
106+ "\n \n " + call_agent_prompt +
79107 ("\n \n " + calendar_context if calendar_context else "" ) +
80108 ("\n \n " + memory_context if memory_context else "" )
81109 )
@@ -125,7 +153,7 @@ async def setup_recording():
125153 logger .error (f"Recording setup error: { e } " )
126154
127155 async def setup_conversation_monitoring ():
128- if self .save_transcription :
156+ if self .save_transcription or self . _call_memory_enabled :
129157 try :
130158 await self .setup_conversation_monitoring (self .session )
131159 logger .info ("Conversation monitoring setup" )
0 commit comments