Skip to content

Commit 8bedd58

Browse files
committed
fix thinking stall
1 parent 909647c commit 8bedd58

1 file changed

Lines changed: 22 additions & 11 deletions

File tree

src/eva/assistant/deepgram_server.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import asyncio
2525
import contextlib
2626
import json
27+
import os
2728
import time
2829
from typing import Any
2930

@@ -247,8 +248,6 @@ def _aws_credentials_from_env(self) -> dict[str, Any] | None:
247248
Mirrors how the cascade pipeline reaches Bedrock, so the agent's think step can
248249
use the *same* model and credentials for an apples-to-apples comparison.
249250
"""
250-
import os
251-
252251
access_key = os.environ.get("AWS_ACCESS_KEY_ID")
253252
secret_key = os.environ.get("AWS_SECRET_ACCESS_KEY")
254253
if not (access_key and secret_key):
@@ -280,9 +279,18 @@ def _build_settings_dict(self) -> dict[str, Any]:
280279
}
281280
if self._functions:
282281
think["functions"] = self._functions
283-
# BYO endpoint (anthropic/open_ai/google) and long-prompt context window.
282+
# BYO endpoint. For aws_bedrock, the Bedrock runtime URL is required by Deepgram
283+
# even when credentials are supplied — auto-build it from the region if not explicit.
284284
if self._think_endpoint:
285285
think["endpoint"] = self._think_endpoint
286+
elif self._think_provider == "aws_bedrock":
287+
region = (
288+
self._think_region
289+
or os.environ.get("AWS_REGION")
290+
or os.environ.get("AWS_DEFAULT_REGION")
291+
or "us-east-1"
292+
)
293+
think["endpoint"] = {"url": f"https://bedrock-runtime.{region}.amazonaws.com/"}
286294
if self._context_length is not None:
287295
think["context_length"] = self._context_length
288296

@@ -331,6 +339,7 @@ async def _handle_session(self, websocket: WebSocket) -> None:
331339

332340
_in_model_turn = False
333341
_user_speaking = False
342+
_think_step_active = False # True between ConversationText(user) and first agent audio
334343
_user_speech_start_ts: str | None = None # From the simulator's VAD
335344
_user_speech_stop_ts: str | None = None # From the simulator's VAD
336345
_assistant_turn_start_ts: str | None = None # Wall-clock ms of first audio chunk
@@ -350,13 +359,10 @@ async def _handle_session(self, websocket: WebSocket) -> None:
350359
try:
351360
async with client.agent.v1.connect() as connection:
352361
logger.info(f"Deepgram agent session connected (think_model={self._think_model})")
353-
if self._omit_think_model():
354-
# Custom Google endpoint: the typed AgentV1Settings requires
355-
# provider.model, but Deepgram wants it only in the URL. Send the
356-
# raw (model-less) settings dict via the SDK's low-level _send.
357-
await connection._send(self._build_settings_dict())
358-
else:
359-
await connection.send_settings(self._build_settings())
362+
# Always send settings as raw dict — avoids the Pydantic round-trip
363+
# in send_settings() → _send_model() → .dict(), which can silently
364+
# drop fields (e.g. think.functions) not declared in AgentV1Settings.
365+
await connection._send(self._build_settings_dict())
360366
fw_log.turn_start()
361367

362368
# ----- Concurrent tasks -----
@@ -470,7 +476,7 @@ async def _process_deepgram_events() -> None:
470476
and tool-call requests. Parsing the JSON ourselves is deterministic.
471477
Binary frames (TTS audio) are delivered as ``bytes`` unchanged.
472478
"""
473-
nonlocal _assistant_turn_text, _in_model_turn, _user_speaking
479+
nonlocal _assistant_turn_text, _in_model_turn, _user_speaking, _think_step_active
474480
nonlocal _user_speech_start_ts, _user_speech_stop_ts, _assistant_turn_start_ts
475481
nonlocal _user_turn_count, _fatal_error
476482
try:
@@ -484,6 +490,7 @@ async def _process_deepgram_events() -> None:
484490
continue
485491
if not _in_model_turn:
486492
_in_model_turn = True
493+
_think_step_active = False
487494
_user_speaking = False
488495
_assistant_turn_start_ts = str(int(round(time.time() * 1000)))
489496
fw_log.turn_start()
@@ -526,6 +533,7 @@ async def _process_deepgram_events() -> None:
526533
continue
527534
if event.get("role") == "user":
528535
_user_speaking = False
536+
_think_step_active = True
529537
_user_turn_count += 1
530538
logger.info(f"User transcription: {text}")
531539
self.audit_log.append_user_input(text, timestamp_ms=_user_speech_start_ts)
@@ -582,6 +590,7 @@ async def _process_deepgram_events() -> None:
582590
"PromptUpdated",
583591
"SpeakUpdated",
584592
"ThinkUpdated",
593+
"FunctionCallResponse",
585594
):
586595
logger.debug(f"Deepgram agent event: {event_type}")
587596

@@ -614,6 +623,8 @@ async def _send_keepalives() -> None:
614623
try:
615624
while self._running and twilio_connected:
616625
await asyncio.sleep(KEEPALIVE_INTERVAL_S)
626+
if _think_step_active:
627+
continue
617628
try:
618629
await connection.send_keep_alive()
619630
except Exception:

0 commit comments

Comments
 (0)