dv-pipecat-ai 0.0.74.dev770__py3-none-any.whl → 0.0.82.dev776__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of dv-pipecat-ai might be problematic. Click here for more details.

Files changed (244) hide show
  1. {dv_pipecat_ai-0.0.74.dev770.dist-info → dv_pipecat_ai-0.0.82.dev776.dist-info}/METADATA +137 -93
  2. dv_pipecat_ai-0.0.82.dev776.dist-info/RECORD +340 -0
  3. pipecat/__init__.py +17 -0
  4. pipecat/adapters/base_llm_adapter.py +36 -1
  5. pipecat/adapters/schemas/direct_function.py +296 -0
  6. pipecat/adapters/schemas/function_schema.py +15 -6
  7. pipecat/adapters/schemas/tools_schema.py +55 -7
  8. pipecat/adapters/services/anthropic_adapter.py +22 -3
  9. pipecat/adapters/services/aws_nova_sonic_adapter.py +23 -3
  10. pipecat/adapters/services/bedrock_adapter.py +22 -3
  11. pipecat/adapters/services/gemini_adapter.py +16 -3
  12. pipecat/adapters/services/open_ai_adapter.py +17 -2
  13. pipecat/adapters/services/open_ai_realtime_adapter.py +23 -3
  14. pipecat/audio/filters/base_audio_filter.py +30 -6
  15. pipecat/audio/filters/koala_filter.py +37 -2
  16. pipecat/audio/filters/krisp_filter.py +59 -6
  17. pipecat/audio/filters/noisereduce_filter.py +37 -0
  18. pipecat/audio/interruptions/base_interruption_strategy.py +25 -5
  19. pipecat/audio/interruptions/min_words_interruption_strategy.py +21 -4
  20. pipecat/audio/mixers/base_audio_mixer.py +30 -7
  21. pipecat/audio/mixers/soundfile_mixer.py +53 -6
  22. pipecat/audio/resamplers/base_audio_resampler.py +17 -9
  23. pipecat/audio/resamplers/resampy_resampler.py +26 -1
  24. pipecat/audio/resamplers/soxr_resampler.py +32 -1
  25. pipecat/audio/resamplers/soxr_stream_resampler.py +101 -0
  26. pipecat/audio/utils.py +194 -1
  27. pipecat/audio/vad/silero.py +60 -3
  28. pipecat/audio/vad/vad_analyzer.py +114 -30
  29. pipecat/clocks/base_clock.py +19 -0
  30. pipecat/clocks/system_clock.py +25 -0
  31. pipecat/extensions/voicemail/__init__.py +0 -0
  32. pipecat/extensions/voicemail/voicemail_detector.py +707 -0
  33. pipecat/frames/frames.py +590 -156
  34. pipecat/metrics/metrics.py +64 -1
  35. pipecat/observers/base_observer.py +58 -19
  36. pipecat/observers/loggers/debug_log_observer.py +56 -64
  37. pipecat/observers/loggers/llm_log_observer.py +8 -1
  38. pipecat/observers/loggers/transcription_log_observer.py +19 -7
  39. pipecat/observers/loggers/user_bot_latency_log_observer.py +32 -5
  40. pipecat/observers/turn_tracking_observer.py +26 -1
  41. pipecat/pipeline/base_pipeline.py +5 -7
  42. pipecat/pipeline/base_task.py +52 -9
  43. pipecat/pipeline/parallel_pipeline.py +121 -177
  44. pipecat/pipeline/pipeline.py +129 -20
  45. pipecat/pipeline/runner.py +50 -1
  46. pipecat/pipeline/sync_parallel_pipeline.py +132 -32
  47. pipecat/pipeline/task.py +263 -280
  48. pipecat/pipeline/task_observer.py +85 -34
  49. pipecat/pipeline/to_be_updated/merge_pipeline.py +32 -2
  50. pipecat/processors/aggregators/dtmf_aggregator.py +29 -22
  51. pipecat/processors/aggregators/gated.py +25 -24
  52. pipecat/processors/aggregators/gated_openai_llm_context.py +22 -2
  53. pipecat/processors/aggregators/llm_response.py +398 -89
  54. pipecat/processors/aggregators/openai_llm_context.py +161 -13
  55. pipecat/processors/aggregators/sentence.py +25 -14
  56. pipecat/processors/aggregators/user_response.py +28 -3
  57. pipecat/processors/aggregators/vision_image_frame.py +24 -14
  58. pipecat/processors/async_generator.py +28 -0
  59. pipecat/processors/audio/audio_buffer_processor.py +78 -37
  60. pipecat/processors/consumer_processor.py +25 -6
  61. pipecat/processors/filters/frame_filter.py +23 -0
  62. pipecat/processors/filters/function_filter.py +30 -0
  63. pipecat/processors/filters/identity_filter.py +17 -2
  64. pipecat/processors/filters/null_filter.py +24 -1
  65. pipecat/processors/filters/stt_mute_filter.py +56 -21
  66. pipecat/processors/filters/wake_check_filter.py +46 -3
  67. pipecat/processors/filters/wake_notifier_filter.py +21 -3
  68. pipecat/processors/frame_processor.py +488 -131
  69. pipecat/processors/frameworks/langchain.py +38 -3
  70. pipecat/processors/frameworks/rtvi.py +719 -34
  71. pipecat/processors/gstreamer/pipeline_source.py +41 -0
  72. pipecat/processors/idle_frame_processor.py +26 -3
  73. pipecat/processors/logger.py +23 -0
  74. pipecat/processors/metrics/frame_processor_metrics.py +77 -4
  75. pipecat/processors/metrics/sentry.py +42 -4
  76. pipecat/processors/producer_processor.py +34 -14
  77. pipecat/processors/text_transformer.py +22 -10
  78. pipecat/processors/transcript_processor.py +48 -29
  79. pipecat/processors/user_idle_processor.py +31 -21
  80. pipecat/runner/__init__.py +1 -0
  81. pipecat/runner/daily.py +132 -0
  82. pipecat/runner/livekit.py +148 -0
  83. pipecat/runner/run.py +543 -0
  84. pipecat/runner/types.py +67 -0
  85. pipecat/runner/utils.py +515 -0
  86. pipecat/serializers/base_serializer.py +42 -0
  87. pipecat/serializers/exotel.py +17 -6
  88. pipecat/serializers/genesys.py +95 -0
  89. pipecat/serializers/livekit.py +33 -0
  90. pipecat/serializers/plivo.py +16 -15
  91. pipecat/serializers/protobuf.py +37 -1
  92. pipecat/serializers/telnyx.py +18 -17
  93. pipecat/serializers/twilio.py +32 -16
  94. pipecat/services/ai_service.py +5 -3
  95. pipecat/services/anthropic/llm.py +113 -43
  96. pipecat/services/assemblyai/models.py +63 -5
  97. pipecat/services/assemblyai/stt.py +64 -11
  98. pipecat/services/asyncai/__init__.py +0 -0
  99. pipecat/services/asyncai/tts.py +501 -0
  100. pipecat/services/aws/llm.py +185 -111
  101. pipecat/services/aws/stt.py +217 -23
  102. pipecat/services/aws/tts.py +118 -52
  103. pipecat/services/aws/utils.py +101 -5
  104. pipecat/services/aws_nova_sonic/aws.py +82 -64
  105. pipecat/services/aws_nova_sonic/context.py +15 -6
  106. pipecat/services/azure/common.py +10 -2
  107. pipecat/services/azure/image.py +32 -0
  108. pipecat/services/azure/llm.py +9 -7
  109. pipecat/services/azure/stt.py +65 -2
  110. pipecat/services/azure/tts.py +154 -23
  111. pipecat/services/cartesia/stt.py +125 -8
  112. pipecat/services/cartesia/tts.py +102 -38
  113. pipecat/services/cerebras/llm.py +15 -23
  114. pipecat/services/deepgram/stt.py +19 -11
  115. pipecat/services/deepgram/tts.py +36 -0
  116. pipecat/services/deepseek/llm.py +14 -23
  117. pipecat/services/elevenlabs/tts.py +330 -64
  118. pipecat/services/fal/image.py +43 -0
  119. pipecat/services/fal/stt.py +48 -10
  120. pipecat/services/fireworks/llm.py +14 -21
  121. pipecat/services/fish/tts.py +109 -9
  122. pipecat/services/gemini_multimodal_live/__init__.py +1 -0
  123. pipecat/services/gemini_multimodal_live/events.py +83 -2
  124. pipecat/services/gemini_multimodal_live/file_api.py +189 -0
  125. pipecat/services/gemini_multimodal_live/gemini.py +218 -21
  126. pipecat/services/gladia/config.py +17 -10
  127. pipecat/services/gladia/stt.py +82 -36
  128. pipecat/services/google/frames.py +40 -0
  129. pipecat/services/google/google.py +2 -0
  130. pipecat/services/google/image.py +39 -2
  131. pipecat/services/google/llm.py +176 -58
  132. pipecat/services/google/llm_openai.py +26 -4
  133. pipecat/services/google/llm_vertex.py +37 -15
  134. pipecat/services/google/rtvi.py +41 -0
  135. pipecat/services/google/stt.py +65 -17
  136. pipecat/services/google/test-google-chirp.py +45 -0
  137. pipecat/services/google/tts.py +390 -19
  138. pipecat/services/grok/llm.py +8 -6
  139. pipecat/services/groq/llm.py +8 -6
  140. pipecat/services/groq/stt.py +13 -9
  141. pipecat/services/groq/tts.py +40 -0
  142. pipecat/services/hamsa/__init__.py +9 -0
  143. pipecat/services/hamsa/stt.py +241 -0
  144. pipecat/services/heygen/__init__.py +5 -0
  145. pipecat/services/heygen/api.py +281 -0
  146. pipecat/services/heygen/client.py +620 -0
  147. pipecat/services/heygen/video.py +338 -0
  148. pipecat/services/image_service.py +5 -3
  149. pipecat/services/inworld/__init__.py +1 -0
  150. pipecat/services/inworld/tts.py +592 -0
  151. pipecat/services/llm_service.py +127 -45
  152. pipecat/services/lmnt/tts.py +80 -7
  153. pipecat/services/mcp_service.py +85 -44
  154. pipecat/services/mem0/memory.py +42 -13
  155. pipecat/services/minimax/tts.py +74 -15
  156. pipecat/services/mistral/__init__.py +0 -0
  157. pipecat/services/mistral/llm.py +185 -0
  158. pipecat/services/moondream/vision.py +55 -10
  159. pipecat/services/neuphonic/tts.py +275 -48
  160. pipecat/services/nim/llm.py +8 -6
  161. pipecat/services/ollama/llm.py +27 -7
  162. pipecat/services/openai/base_llm.py +54 -16
  163. pipecat/services/openai/image.py +30 -0
  164. pipecat/services/openai/llm.py +7 -5
  165. pipecat/services/openai/stt.py +13 -9
  166. pipecat/services/openai/tts.py +42 -10
  167. pipecat/services/openai_realtime_beta/azure.py +11 -9
  168. pipecat/services/openai_realtime_beta/context.py +7 -5
  169. pipecat/services/openai_realtime_beta/events.py +10 -7
  170. pipecat/services/openai_realtime_beta/openai.py +37 -18
  171. pipecat/services/openpipe/llm.py +30 -24
  172. pipecat/services/openrouter/llm.py +9 -7
  173. pipecat/services/perplexity/llm.py +15 -19
  174. pipecat/services/piper/tts.py +26 -12
  175. pipecat/services/playht/tts.py +227 -65
  176. pipecat/services/qwen/llm.py +8 -6
  177. pipecat/services/rime/tts.py +128 -17
  178. pipecat/services/riva/stt.py +160 -22
  179. pipecat/services/riva/tts.py +67 -2
  180. pipecat/services/sambanova/llm.py +19 -17
  181. pipecat/services/sambanova/stt.py +14 -8
  182. pipecat/services/sarvam/tts.py +60 -13
  183. pipecat/services/simli/video.py +82 -21
  184. pipecat/services/soniox/__init__.py +0 -0
  185. pipecat/services/soniox/stt.py +398 -0
  186. pipecat/services/speechmatics/stt.py +29 -17
  187. pipecat/services/stt_service.py +47 -11
  188. pipecat/services/tavus/video.py +94 -25
  189. pipecat/services/together/llm.py +8 -6
  190. pipecat/services/tts_service.py +77 -53
  191. pipecat/services/ultravox/stt.py +46 -43
  192. pipecat/services/vision_service.py +5 -3
  193. pipecat/services/websocket_service.py +12 -11
  194. pipecat/services/whisper/base_stt.py +58 -12
  195. pipecat/services/whisper/stt.py +69 -58
  196. pipecat/services/xtts/tts.py +59 -2
  197. pipecat/sync/base_notifier.py +19 -0
  198. pipecat/sync/event_notifier.py +24 -0
  199. pipecat/tests/utils.py +73 -5
  200. pipecat/transcriptions/language.py +24 -0
  201. pipecat/transports/base_input.py +112 -8
  202. pipecat/transports/base_output.py +235 -13
  203. pipecat/transports/base_transport.py +119 -0
  204. pipecat/transports/local/audio.py +76 -0
  205. pipecat/transports/local/tk.py +84 -0
  206. pipecat/transports/network/fastapi_websocket.py +174 -15
  207. pipecat/transports/network/small_webrtc.py +383 -39
  208. pipecat/transports/network/webrtc_connection.py +214 -8
  209. pipecat/transports/network/websocket_client.py +171 -1
  210. pipecat/transports/network/websocket_server.py +147 -9
  211. pipecat/transports/services/daily.py +792 -70
  212. pipecat/transports/services/helpers/daily_rest.py +122 -129
  213. pipecat/transports/services/livekit.py +339 -4
  214. pipecat/transports/services/tavus.py +273 -38
  215. pipecat/utils/asyncio/task_manager.py +92 -186
  216. pipecat/utils/base_object.py +83 -1
  217. pipecat/utils/network.py +2 -0
  218. pipecat/utils/string.py +114 -58
  219. pipecat/utils/text/base_text_aggregator.py +44 -13
  220. pipecat/utils/text/base_text_filter.py +46 -0
  221. pipecat/utils/text/markdown_text_filter.py +70 -14
  222. pipecat/utils/text/pattern_pair_aggregator.py +18 -14
  223. pipecat/utils/text/simple_text_aggregator.py +43 -2
  224. pipecat/utils/text/skip_tags_aggregator.py +21 -13
  225. pipecat/utils/time.py +36 -0
  226. pipecat/utils/tracing/class_decorators.py +32 -7
  227. pipecat/utils/tracing/conversation_context_provider.py +12 -2
  228. pipecat/utils/tracing/service_attributes.py +80 -64
  229. pipecat/utils/tracing/service_decorators.py +48 -21
  230. pipecat/utils/tracing/setup.py +13 -7
  231. pipecat/utils/tracing/turn_context_provider.py +12 -2
  232. pipecat/utils/tracing/turn_trace_observer.py +27 -0
  233. pipecat/utils/utils.py +14 -14
  234. dv_pipecat_ai-0.0.74.dev770.dist-info/RECORD +0 -319
  235. pipecat/examples/daily_runner.py +0 -64
  236. pipecat/examples/run.py +0 -265
  237. pipecat/utils/asyncio/watchdog_async_iterator.py +0 -72
  238. pipecat/utils/asyncio/watchdog_event.py +0 -42
  239. pipecat/utils/asyncio/watchdog_priority_queue.py +0 -48
  240. pipecat/utils/asyncio/watchdog_queue.py +0 -48
  241. {dv_pipecat_ai-0.0.74.dev770.dist-info → dv_pipecat_ai-0.0.82.dev776.dist-info}/WHEEL +0 -0
  242. {dv_pipecat_ai-0.0.74.dev770.dist-info → dv_pipecat_ai-0.0.82.dev776.dist-info}/licenses/LICENSE +0 -0
  243. {dv_pipecat_ai-0.0.74.dev770.dist-info → dv_pipecat_ai-0.0.82.dev776.dist-info}/top_level.txt +0 -0
  244. /pipecat/{examples → extensions}/__init__.py +0 -0
@@ -55,9 +55,10 @@ from pipecat.services.llm_service import LLMService
55
55
  from pipecat.utils.tracing.service_decorators import traced_llm
56
56
 
57
57
  try:
58
- import boto3
58
+ import aioboto3
59
59
  import httpx
60
60
  from botocore.config import Config
61
+ from botocore.exceptions import ReadTimeoutError
61
62
  except ModuleNotFoundError as e:
62
63
  logger.error(f"Exception: {e}")
63
64
  logger.error(
@@ -104,12 +105,6 @@ class AWSBedrockLLMContext(OpenAILLMContext):
104
105
  Extends OpenAI LLM context to handle AWS Bedrock's specific message format
105
106
  and system message handling. Manages conversion between OpenAI and Bedrock
106
107
  message formats.
107
-
108
- Args:
109
- messages: List of conversation messages in OpenAI format.
110
- tools: List of available function calling tools.
111
- tool_choice: Tool selection strategy or specific tool choice.
112
- system: System message content for AWS Bedrock.
113
108
  """
114
109
 
115
110
  def __init__(
@@ -120,6 +115,14 @@ class AWSBedrockLLMContext(OpenAILLMContext):
120
115
  *,
121
116
  system: Optional[str] = None,
122
117
  ):
118
+ """Initialize AWS Bedrock LLM context.
119
+
120
+ Args:
121
+ messages: List of conversation messages in OpenAI format.
122
+ tools: List of available function calling tools.
123
+ tool_choice: Tool selection strategy or specific tool choice.
124
+ system: System message content for AWS Bedrock.
125
+ """
123
126
  super().__init__(messages=messages, tools=tools, tool_choice=tool_choice)
124
127
  self.system = system
125
128
 
@@ -205,20 +208,37 @@ class AWSBedrockLLMContext(OpenAILLMContext):
205
208
  Handles text content and function calls for both user and assistant messages.
206
209
 
207
210
  Args:
208
- obj: Message in AWS Bedrock format:
209
- {
210
- "role": "user/assistant",
211
- "content": [{"text": str} | {"toolUse": {...}} | {"toolResult": {...}}]
212
- }
211
+ obj: Message in AWS Bedrock format.
213
212
 
214
213
  Returns:
215
- List of messages in standard format:
216
- [
214
+ List of messages in standard format.
215
+
216
+ Examples:
217
+ AWS Bedrock format input::
218
+
217
219
  {
218
- "role": "user/assistant/tool",
219
- "content": [{"type": "text", "text": str}]
220
+ "role": "assistant",
221
+ "content": [
222
+ {"text": "Hello"},
223
+ {"toolUse": {"toolUseId": "123", "name": "search", "input": {"q": "test"}}}
224
+ ]
220
225
  }
221
- ]
226
+
227
+ Standard format output::
228
+
229
+ [
230
+ {"role": "assistant", "content": [{"type": "text", "text": "Hello"}]},
231
+ {
232
+ "role": "assistant",
233
+ "tool_calls": [
234
+ {
235
+ "type": "function",
236
+ "id": "123",
237
+ "function": {"name": "search", "arguments": '{"q": "test"}'}
238
+ }
239
+ ]
240
+ }
241
+ ]
222
242
  """
223
243
  role = obj.get("role")
224
244
  content = obj.get("content")
@@ -292,23 +312,38 @@ class AWSBedrockLLMContext(OpenAILLMContext):
292
312
  Empty text content is converted to "(empty)".
293
313
 
294
314
  Args:
295
- message: Message in standard format:
315
+ message: Message in standard format.
316
+
317
+ Returns:
318
+ Message in AWS Bedrock format.
319
+
320
+ Examples:
321
+ Standard format input::
322
+
296
323
  {
297
- "role": "user/assistant/tool",
298
- "content": str | [{"type": "text", ...}],
299
- "tool_calls": [{"id": str, "function": {"name": str, "arguments": str}}]
324
+ "role": "assistant",
325
+ "tool_calls": [
326
+ {
327
+ "id": "123",
328
+ "function": {"name": "search", "arguments": '{"q": "test"}'}
329
+ }
330
+ ]
300
331
  }
301
332
 
302
- Returns:
303
- Message in AWS Bedrock format:
304
- {
305
- "role": "user/assistant",
306
- "content": [
307
- {"text": str} |
308
- {"toolUse": {"toolUseId": str, "name": str, "input": dict}} |
309
- {"toolResult": {"toolUseId": str, "content": [...], "status": str}}
310
- ]
311
- }
333
+ AWS Bedrock format output::
334
+
335
+ {
336
+ "role": "assistant",
337
+ "content": [
338
+ {
339
+ "toolUse": {
340
+ "toolUseId": "123",
341
+ "name": "search",
342
+ "input": {"q": "test"}
343
+ }
344
+ }
345
+ ]
346
+ }
312
347
  """
313
348
  if message["role"] == "tool":
314
349
  # Try to parse the content as JSON if it looks like JSON
@@ -656,16 +691,6 @@ class AWSBedrockLLMService(LLMService):
656
691
  Provides inference capabilities for AWS Bedrock models including Amazon Nova
657
692
  and Anthropic Claude. Supports streaming responses, function calling, and
658
693
  vision capabilities.
659
-
660
- Args:
661
- model: The AWS Bedrock model identifier to use.
662
- aws_access_key: AWS access key ID. If None, uses default credentials.
663
- aws_secret_key: AWS secret access key. If None, uses default credentials.
664
- aws_session_token: AWS session token for temporary credentials.
665
- aws_region: AWS region for the Bedrock service.
666
- params: Model parameters and configuration.
667
- client_config: Custom boto3 client configuration.
668
- **kwargs: Additional arguments passed to parent LLMService.
669
694
  """
670
695
 
671
696
  # Overriding the default adapter to use the Anthropic one.
@@ -700,8 +725,24 @@ class AWSBedrockLLMService(LLMService):
700
725
  aws_region: str = "us-east-1",
701
726
  params: Optional[InputParams] = None,
702
727
  client_config: Optional[Config] = None,
728
+ retry_timeout_secs: Optional[float] = 5.0,
729
+ retry_on_timeout: Optional[bool] = False,
703
730
  **kwargs,
704
731
  ):
732
+ """Initialize the AWS Bedrock LLM service.
733
+
734
+ Args:
735
+ model: The AWS Bedrock model identifier to use.
736
+ aws_access_key: AWS access key ID. If None, uses default credentials.
737
+ aws_secret_key: AWS secret access key. If None, uses default credentials.
738
+ aws_session_token: AWS session token for temporary credentials.
739
+ aws_region: AWS region for the Bedrock service.
740
+ params: Model parameters and configuration.
741
+ client_config: Custom boto3 client configuration.
742
+ retry_timeout_secs: Request timeout in seconds for retry logic.
743
+ retry_on_timeout: Whether to retry the request once if it times out.
744
+ **kwargs: Additional arguments passed to parent LLMService.
745
+ """
705
746
  super().__init__(**kwargs)
706
747
 
707
748
  params = params or AWSBedrockLLMService.InputParams()
@@ -713,15 +754,21 @@ class AWSBedrockLLMService(LLMService):
713
754
  read_timeout=300, # 5 minutes
714
755
  retries={"max_attempts": 3},
715
756
  )
716
- session = boto3.Session(
717
- aws_access_key_id=aws_access_key,
718
- aws_secret_access_key=aws_secret_key,
719
- aws_session_token=aws_session_token,
720
- region_name=aws_region,
721
- )
722
- self._client = session.client(service_name="bedrock-runtime", config=client_config)
757
+
758
+ self._aws_session = aioboto3.Session()
759
+
760
+ # Store AWS session parameters for creating client in async context
761
+ self._aws_params = {
762
+ "aws_access_key_id": aws_access_key,
763
+ "aws_secret_access_key": aws_secret_key,
764
+ "aws_session_token": aws_session_token,
765
+ "region_name": aws_region,
766
+ "config": client_config,
767
+ }
723
768
 
724
769
  self.set_model_name(model)
770
+ self._retry_timeout_secs = retry_timeout_secs
771
+ self._retry_on_timeout = retry_on_timeout
725
772
  self._settings = {
726
773
  "max_tokens": params.max_tokens,
727
774
  "temperature": params.temperature,
@@ -742,6 +789,31 @@ class AWSBedrockLLMService(LLMService):
742
789
  """
743
790
  return True
744
791
 
792
+ async def _create_converse_stream(self, client, request_params):
793
+ """Create converse stream with optional timeout and retry.
794
+
795
+ Args:
796
+ client: The AWS Bedrock client instance.
797
+ request_params: Parameters for the converse_stream call.
798
+
799
+ Returns:
800
+ Async stream of response events.
801
+ """
802
+ if self._retry_on_timeout:
803
+ try:
804
+ response = await asyncio.wait_for(
805
+ await client.converse_stream(**request_params), timeout=self._retry_timeout_secs
806
+ )
807
+ return response
808
+ except (ReadTimeoutError, asyncio.TimeoutError) as e:
809
+ # Retry, this time without a timeout so we get a response
810
+ logger.debug(f"{self}: Retrying converse_stream due to timeout")
811
+ response = await client.converse_stream(**request_params)
812
+ return response
813
+ else:
814
+ response = await client.converse_stream(**request_params)
815
+ return response
816
+
745
817
  def create_context_aggregator(
746
818
  self,
747
819
  context: OpenAILLMContext,
@@ -867,70 +939,72 @@ class AWSBedrockLLMService(LLMService):
867
939
 
868
940
  logger.debug(f"Calling AWS Bedrock model with: {request_params}")
869
941
 
870
- # Call AWS Bedrock with streaming
871
- response = self._client.converse_stream(**request_params)
872
-
873
- await self.stop_ttfb_metrics()
874
-
875
- # Process the streaming response
876
- tool_use_block = None
877
- json_accumulator = ""
878
-
879
- function_calls = []
880
- for event in response["stream"]:
881
- self.reset_watchdog()
882
-
883
- # Handle text content
884
- if "contentBlockDelta" in event:
885
- delta = event["contentBlockDelta"]["delta"]
886
- if "text" in delta:
887
- await self.push_frame(LLMTextFrame(delta["text"]))
888
- completion_tokens_estimate += self._estimate_tokens(delta["text"])
889
- elif "toolUse" in delta and "input" in delta["toolUse"]:
890
- # Handle partial JSON for tool use
891
- json_accumulator += delta["toolUse"]["input"]
892
- completion_tokens_estimate += self._estimate_tokens(
893
- delta["toolUse"]["input"]
894
- )
895
-
896
- # Handle tool use start
897
- elif "contentBlockStart" in event:
898
- content_block_start = event["contentBlockStart"]["start"]
899
- if "toolUse" in content_block_start:
900
- tool_use_block = {
901
- "id": content_block_start["toolUse"].get("toolUseId", ""),
902
- "name": content_block_start["toolUse"].get("name", ""),
903
- }
904
- json_accumulator = ""
905
-
906
- # Handle message completion with tool use
907
- elif "messageStop" in event and "stopReason" in event["messageStop"]:
908
- if event["messageStop"]["stopReason"] == "tool_use" and tool_use_block:
909
- try:
910
- arguments = json.loads(json_accumulator) if json_accumulator else {}
911
-
912
- # Only call function if it's not the no_operation tool
913
- if not using_noop_tool:
914
- function_calls.append(
915
- FunctionCallFromLLM(
916
- context=context,
917
- tool_call_id=tool_use_block["id"],
918
- function_name=tool_use_block["name"],
919
- arguments=arguments,
942
+ async with self._aws_session.client(
943
+ service_name="bedrock-runtime", **self._aws_params
944
+ ) as client:
945
+ # Call AWS Bedrock with streaming
946
+ response = await self._create_converse_stream(client, request_params)
947
+
948
+ await self.stop_ttfb_metrics()
949
+
950
+ # Process the streaming response
951
+ tool_use_block = None
952
+ json_accumulator = ""
953
+
954
+ function_calls = []
955
+
956
+ async for event in response["stream"]:
957
+ # Handle text content
958
+ if "contentBlockDelta" in event:
959
+ delta = event["contentBlockDelta"]["delta"]
960
+ if "text" in delta:
961
+ await self.push_frame(LLMTextFrame(delta["text"]))
962
+ completion_tokens_estimate += self._estimate_tokens(delta["text"])
963
+ elif "toolUse" in delta and "input" in delta["toolUse"]:
964
+ # Handle partial JSON for tool use
965
+ json_accumulator += delta["toolUse"]["input"]
966
+ completion_tokens_estimate += self._estimate_tokens(
967
+ delta["toolUse"]["input"]
968
+ )
969
+
970
+ # Handle tool use start
971
+ elif "contentBlockStart" in event:
972
+ content_block_start = event["contentBlockStart"]["start"]
973
+ if "toolUse" in content_block_start:
974
+ tool_use_block = {
975
+ "id": content_block_start["toolUse"].get("toolUseId", ""),
976
+ "name": content_block_start["toolUse"].get("name", ""),
977
+ }
978
+ json_accumulator = ""
979
+
980
+ # Handle message completion with tool use
981
+ elif "messageStop" in event and "stopReason" in event["messageStop"]:
982
+ if event["messageStop"]["stopReason"] == "tool_use" and tool_use_block:
983
+ try:
984
+ arguments = json.loads(json_accumulator) if json_accumulator else {}
985
+
986
+ # Only call function if it's not the no_operation tool
987
+ if not using_noop_tool:
988
+ function_calls.append(
989
+ FunctionCallFromLLM(
990
+ context=context,
991
+ tool_call_id=tool_use_block["id"],
992
+ function_name=tool_use_block["name"],
993
+ arguments=arguments,
994
+ )
920
995
  )
921
- )
922
- else:
923
- logger.debug("Ignoring no_operation tool call")
924
- except json.JSONDecodeError:
925
- logger.error(f"Failed to parse tool arguments: {json_accumulator}")
926
-
927
- # Handle usage metrics if available
928
- if "metadata" in event and "usage" in event["metadata"]:
929
- usage = event["metadata"]["usage"]
930
- prompt_tokens += usage.get("inputTokens", 0)
931
- completion_tokens += usage.get("outputTokens", 0)
932
- cache_read_input_tokens += usage.get("cacheReadInputTokens", 0)
933
- cache_creation_input_tokens += usage.get("cacheWriteInputTokens", 0)
996
+ else:
997
+ logger.debug("Ignoring no_operation tool call")
998
+ except json.JSONDecodeError:
999
+ logger.error(f"Failed to parse tool arguments: {json_accumulator}")
1000
+
1001
+ # Handle usage metrics if available
1002
+ if "metadata" in event and "usage" in event["metadata"]:
1003
+ usage = event["metadata"]["usage"]
1004
+ prompt_tokens += usage.get("inputTokens", 0)
1005
+ completion_tokens += usage.get("outputTokens", 0)
1006
+ cache_read_input_tokens += usage.get("cacheReadInputTokens", 0)
1007
+ cache_creation_input_tokens += usage.get("cacheWriteInputTokens", 0)
934
1008
 
935
1009
  await self.run_function_calls(function_calls)
936
1010
  except asyncio.CancelledError: