Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4be8df7

Browse files
committed
fix: correct Google credential validation, inbound memory phone propagation, and call metadata status schema
- Fix inverted credential guard in Google STT/TTS plugins so that GOOGLE_APPLICATION_CREDENTIALS env-var-based setups work correctly (require at least one of credentials_info or credentials_file). - Add update_phone_number() to AgentSetup to propagate SIP caller number into memory key at runtime; remove incorrect agent_number fallback from inbound metadata phone assignment. - Allow MemoryService.update_phone_number() to handle changed numbers (not just empty initial state). - Normalize call metadata schema: keep status as a plain string and introduce termination_reason as a separate field for consistency. - Correct TTS.from_config return type annotation from 'STT' to 'TTS'.
1 parent b5a8095 commit 4be8df7

5 files changed

Lines changed: 36 additions & 15 deletions

File tree

siphon/agent/core/entrypoint.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ async def _setup_memory_and_agent(
251251
# Try to get phone number from metadata
252252
if is_inbound_call:
253253
# For inbound, we'll get it from SIP participant later
254-
phone_number = metadata.get("user_number") or metadata.get("agent_number")
254+
phone_number = metadata.get("user_number")
255255
else:
256256
# For outbound, it's the number we called
257257
phone_number = metadata.get("number_to_call") or metadata.get("user_number")

siphon/agent/core/voice_agent.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def __init__(self,
4646
system_instructions: str,
4747
interruptions_allowed: bool,
4848
room: rtc.Room = None,
49-
phone_number: str = None,
49+
phone_number: Optional[str] = None,
5050
remember_call: bool = False,
5151
memory_service: Optional[MemoryService] = None,
5252
) -> None:
@@ -166,6 +166,19 @@ async def _send_greeting_task(self):
166166
except Exception as e:
167167
logger.error(f"Greeting error: {e}", exc_info=True)
168168

169+
def update_phone_number(self, phone_number: Optional[str]) -> None:
170+
"""Update memory phone number when SIP participant data becomes available."""
171+
if not phone_number:
172+
return
173+
174+
if phone_number != self._call_memory_phone:
175+
self._call_memory_phone = phone_number
176+
177+
if self._memory_service:
178+
self._memory_service.update_phone_number(phone_number)
179+
180+
logger.info(f"Updated call memory phone number: {phone_number}")
181+
169182
# Agent lifecycle
170183
async def on_enter(self):
171184
"""Send an optional greeting when the agent joins the room."""
@@ -220,4 +233,4 @@ async def on_exit(self):
220233
llm=actual_llm
221234
)
222235
except Exception as e:
223-
logger.error(f"Error saving call memory: {e}")
236+
logger.error(f"Error saving call memory: {e}")

siphon/config/call_metadata.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def _set_timing_metadata(self, metadata: dict, start_time: float = None, end_tim
124124
metadata['duration'] = end_time - start_time
125125
metadata['timezone'] = get_timezone_name() or "local"
126126

127-
def _determine_call_status(self, response) -> tuple:
127+
def _determine_call_status(self, response) -> tuple[str, str]:
128128
"""Determine call status and termination reason"""
129129
if not response:
130130
has_conversation = hasattr(self, 'conversation_history') and len(self.conversation_history) > 0
@@ -138,8 +138,9 @@ def _determine_call_status(self, response) -> tuple:
138138
status = self.STATUS_MAPPING.get(response.status, 'completed')
139139
else:
140140
status = 'completed'
141-
142-
return status
141+
142+
termination_reason = '' if status == 'completed' else status
143+
return status, termination_reason
143144

144145
def _get_recording_filename(self, response) -> str:
145146
"""Extract recording filename from response"""
@@ -191,6 +192,7 @@ async def save_unanswered_call_metadata(self, reason: str = "not_answered") -> N
191192

192193
# Set status and termination reason
193194
metadata['status'] = reason
195+
metadata['termination_reason'] = reason
194196
# Explicit answered flag for downstream consumers
195197
metadata['answered'] = False
196198
metadata['recording_filename'] = ''
@@ -240,8 +242,9 @@ async def save_call_metadata(self, response) -> None:
240242
self._set_timing_metadata(metadata, start_timestamp, end_timestamp)
241243

242244
# Determine status and termination reason
243-
status = self._determine_call_status(response)
245+
status, termination_reason = self._determine_call_status(response)
244246
metadata['status'] = status
247+
metadata['termination_reason'] = termination_reason
245248
# Call reached a state where recording response exists -> treat as answered
246249
metadata['answered'] = True
247250

@@ -256,8 +259,9 @@ async def save_call_metadata(self, response) -> None:
256259
self._set_timing_metadata(metadata, start_timestamp, current_time)
257260

258261
# Determine status for no-response scenario using the actual duration
259-
status = self._determine_call_status(response)
262+
status, termination_reason = self._determine_call_status(response)
260263
metadata['status'] = status
264+
metadata['termination_reason'] = termination_reason
261265
metadata['recording_filename'] = ''
262266

263267
# Heuristic answered flag when we have no recording response:

siphon/memory/service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def phone_number(self) -> Optional[str]:
5252

5353
def update_phone_number(self, phone_number: str) -> None:
5454
"""Update the phone number for this service instance."""
55-
if phone_number and not self._phone_number:
55+
if phone_number and phone_number != self._phone_number:
5656
self._phone_number = phone_number
5757
logger.info(f"Memory service phone number updated: {phone_number}")
5858

siphon/plugins/google.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ def __init__(
2929
self.credentials_info = credentials_info
3030
self.credentials_file = credentials_file
3131

32-
if not self.credentials_info or self.credentials_file:
33-
raise ValueError("GOOGLE_APPLICATION_CREDENTIALS location is required as environment variable or credentials_info (Array) is required")
32+
if not self.credentials_info and not self.credentials_file:
33+
raise ValueError(
34+
"GOOGLE_APPLICATION_CREDENTIALS environment variable or credentials_info is required"
35+
)
3436

3537
self._client = self._build_client()
3638

@@ -96,8 +98,10 @@ def __init__(
9698
self.credentials_info = credentials_info
9799
self.credentials_file = credentials_file
98100

99-
if not self.credentials_info or self.credentials_file:
100-
raise ValueError("GOOGLE_APPLICATION_CREDENTIALS location is required as environment variable or credentials_info (Array) is required")
101+
if not self.credentials_info and not self.credentials_file:
102+
raise ValueError(
103+
"GOOGLE_APPLICATION_CREDENTIALS environment variable or credentials_info is required"
104+
)
101105

102106
self._client = self._build_client()
103107

@@ -126,12 +130,12 @@ def to_config(self) -> dict:
126130

127131
# Recreate STT from config dict
128132
@classmethod
129-
def from_config(cls, cfg: dict) -> "STT":
133+
def from_config(cls, cfg: dict) -> "TTS":
130134
return cls(
131135
language=cfg.get("language", "en-US"),
132136
gender=cfg.get("gender", "female"),
133137
voice_name=cfg.get("voice_name", "en-US-Standard-H"),
134138
voice_cloning_key=cfg.get("voice_cloning_key"),
135139
sample_rate=cfg.get("sample_rate", 24000),
136140
credentials_info=cfg.get("credentials_info")
137-
)
141+
)

0 commit comments

Comments
 (0)