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
@@ -0,0 +1,296 @@
1
+ #
2
+ # Copyright (c) 2024–2025, Daily
3
+ #
4
+ # SPDX-License-Identifier: BSD 2-Clause License
5
+ #
6
+
7
+ """Direct function wrapper utilities for LLM function calling.
8
+
9
+ This module provides utilities for wrapping "direct" functions that handle LLM
10
+ function calls. Direct functions have their metadata automatically extracted
11
+ from function signatures and docstrings, allowing them to be used without
12
+ accompanying configurations (as FunctionSchemas or in provider-specific
13
+ formats).
14
+ """
15
+
16
+ import inspect
17
+ import types
18
+ from typing import (
19
+ TYPE_CHECKING,
20
+ Any,
21
+ Callable,
22
+ Dict,
23
+ List,
24
+ Mapping,
25
+ Protocol,
26
+ Set,
27
+ Tuple,
28
+ Union,
29
+ get_args,
30
+ get_origin,
31
+ get_type_hints,
32
+ )
33
+
34
+ import docstring_parser
35
+
36
+ from pipecat.adapters.schemas.function_schema import FunctionSchema
37
+
38
+ if TYPE_CHECKING:
39
+ from pipecat.services.llm_service import FunctionCallParams
40
+
41
+
42
+ class DirectFunction(Protocol):
43
+ """Protocol for a "direct" function that handles LLM function calls.
44
+
45
+ "Direct" functions' metadata is automatically extracted from their function signature and
46
+ docstrings, allowing them to be used without accompanying function configurations (as
47
+ FunctionSchemas or in provider-specific formats).
48
+ """
49
+
50
+ async def __call__(self, params: "FunctionCallParams", **kwargs: Any) -> None:
51
+ """Execute the direct function.
52
+
53
+ Args:
54
+ params: Function call parameters from the LLM service.
55
+ **kwargs: Additional keyword arguments passed to the function.
56
+ """
57
+ ...
58
+
59
+
60
+ class BaseDirectFunctionWrapper:
61
+ """Base class for a wrapper around a DirectFunction.
62
+
63
+ Provides functionality to:
64
+
65
+ - extract metadata from the function signature and docstring
66
+ - use that metadata to generate a corresponding FunctionSchema
67
+ """
68
+
69
+ def __init__(self, function: Callable):
70
+ """Initialize the direct function wrapper.
71
+
72
+ Args:
73
+ function: The function to wrap and extract metadata from.
74
+ """
75
+ self.__class__.validate_function(function)
76
+ self.function = function
77
+ self._initialize_metadata()
78
+
79
+ @classmethod
80
+ def special_first_param_name(cls) -> str:
81
+ """Get the name of the special first function parameter.
82
+
83
+ The special first parameter is ignored by metadata extraction as it's
84
+ not relevant to the LLM (e.g., 'params' for FunctionCallParams).
85
+
86
+ Returns:
87
+ The name of the special first parameter.
88
+ """
89
+ raise NotImplementedError("Subclasses must define the special first parameter name.")
90
+
91
+ @classmethod
92
+ def validate_function(cls, function: Callable) -> None:
93
+ """Validate that the function meets direct function requirements.
94
+
95
+ Args:
96
+ function: The function to validate.
97
+
98
+ Raises:
99
+ Exception: If function doesn't meet requirements (not async, missing
100
+ parameters, incorrect first parameter name).
101
+ """
102
+ if not inspect.iscoroutinefunction(function):
103
+ raise Exception(f"Direct function {function.__name__} must be async")
104
+ params = list(inspect.signature(function).parameters.items())
105
+ special_first_param_name = cls.special_first_param_name()
106
+ if len(params) == 0:
107
+ raise Exception(
108
+ f"Direct function {function.__name__} must have at least one parameter ({special_first_param_name})"
109
+ )
110
+ first_param_name = params[0][0]
111
+ if first_param_name != special_first_param_name:
112
+ raise Exception(
113
+ f"Direct function {function.__name__} first parameter must be named '{special_first_param_name}'"
114
+ )
115
+
116
+ def to_function_schema(self) -> FunctionSchema:
117
+ """Convert the wrapped function to a FunctionSchema.
118
+
119
+ Returns:
120
+ A FunctionSchema instance with extracted metadata.
121
+ """
122
+ return FunctionSchema(
123
+ name=self.name,
124
+ description=self.description,
125
+ properties=self.properties,
126
+ required=self.required,
127
+ )
128
+
129
+ def _initialize_metadata(self):
130
+ """Initialize metadata from function signature and docstring."""
131
+ # Get function name
132
+ self.name = self.function.__name__
133
+
134
+ # Parse docstring for description and parameters
135
+ docstring = docstring_parser.parse(inspect.getdoc(self.function))
136
+
137
+ # Get function description
138
+ self.description = (docstring.description or "").strip()
139
+
140
+ # Get function parameters as JSON schemas, and the list of required parameters
141
+ self.properties, self.required = self._get_parameters_as_jsonschema(
142
+ self.function, docstring.params
143
+ )
144
+
145
+ # TODO: maybe to better support things like enums, check if each type is a pydantic type and use its convert-to-jsonschema function
146
+ def _get_parameters_as_jsonschema(
147
+ self, func: Callable, docstring_params: List[docstring_parser.DocstringParam]
148
+ ) -> Tuple[Dict[str, Any], List[str]]:
149
+ """Get function parameters as a dictionary of JSON schemas and a list of required parameters.
150
+
151
+ Ignore the first parameter, as it's expected to be the "special" one.
152
+
153
+ Args:
154
+ func: Function to get parameters from.
155
+ docstring_params: List of parameters extracted from the function's docstring.
156
+
157
+ Returns:
158
+ A tuple containing:
159
+
160
+ - A dictionary mapping each function parameter to its JSON schema
161
+ - A list of required parameter names
162
+ """
163
+ sig = inspect.signature(func)
164
+ hints = get_type_hints(func)
165
+ properties = {}
166
+ required = []
167
+
168
+ for name, param in sig.parameters.items():
169
+ # Ignore 'self' parameter
170
+ if name == "self":
171
+ continue
172
+
173
+ # Ignore the first parameter, which is expected to be the "special" one
174
+ # (We have already validated that this is the case in validate_function())
175
+ is_first_param = name == next(iter(sig.parameters))
176
+ if is_first_param:
177
+ continue
178
+
179
+ type_hint = hints.get(name)
180
+
181
+ # Convert type hint to JSON schema
182
+ properties[name] = self._typehint_to_jsonschema(type_hint)
183
+
184
+ # Add whether the parameter is required
185
+ # If the parameter has no default value, it's required
186
+ if param.default is inspect.Parameter.empty:
187
+ required.append(name)
188
+
189
+ # Add parameter description from docstring
190
+ for doc_param in docstring_params:
191
+ if doc_param.arg_name == name:
192
+ properties[name]["description"] = doc_param.description or ""
193
+
194
+ return properties, required
195
+
196
+ def _typehint_to_jsonschema(self, type_hint: Any) -> Dict[str, Any]:
197
+ """Convert a Python type hint to a JSON Schema.
198
+
199
+ Args:
200
+ type_hint: A Python type hint
201
+
202
+ Returns:
203
+ A dictionary representing the JSON Schema
204
+ """
205
+ if type_hint is None:
206
+ return {}
207
+
208
+ # Handle basic types
209
+ if type_hint is type(None):
210
+ return {"type": "null"}
211
+ if type_hint is str:
212
+ return {"type": "string"}
213
+ elif type_hint is int:
214
+ return {"type": "integer"}
215
+ elif type_hint is float:
216
+ return {"type": "number"}
217
+ elif type_hint is bool:
218
+ return {"type": "boolean"}
219
+ elif type_hint is dict or type_hint is Dict:
220
+ return {"type": "object"}
221
+ elif type_hint is list or type_hint is List:
222
+ return {"type": "array"}
223
+
224
+ # Get origin and arguments for complex types
225
+ origin = get_origin(type_hint)
226
+ args = get_args(type_hint)
227
+
228
+ # Handle Optional/Union types
229
+ if origin is Union or origin is types.UnionType:
230
+ return {"anyOf": [self._typehint_to_jsonschema(arg) for arg in args]}
231
+
232
+ # Handle List, Tuple, Set with specific item types
233
+ if origin in (list, List, tuple, Tuple, set, Set) and args:
234
+ return {"type": "array", "items": self._typehint_to_jsonschema(args[0])}
235
+
236
+ # Handle Dict with specific key/value types
237
+ if origin in (dict, Dict) and len(args) == 2:
238
+ # For JSON Schema, keys must be strings
239
+ return {"type": "object", "additionalProperties": self._typehint_to_jsonschema(args[1])}
240
+
241
+ # Handle TypedDict
242
+ if hasattr(type_hint, "__annotations__"):
243
+ properties = {}
244
+ required = []
245
+
246
+ # NOTE: this does not yet support some fields being required and others not, which could happen when:
247
+ # - the base class is a TypedDict with required fields (total=True or not specified) and the derived class has optional fields (total=False)
248
+ # - Python 3.11+ NotRequired is used
249
+ all_fields_required = getattr(type_hint, "__total__", True)
250
+
251
+ for field_name, field_type in get_type_hints(type_hint).items():
252
+ properties[field_name] = self._typehint_to_jsonschema(field_type)
253
+ if all_fields_required:
254
+ required.append(field_name)
255
+
256
+ schema = {"type": "object", "properties": properties}
257
+
258
+ if required:
259
+ schema["required"] = required
260
+
261
+ return schema
262
+
263
+ # Default to any type if we can't determine the specific schema
264
+ return {}
265
+
266
+
267
+ class DirectFunctionWrapper(BaseDirectFunctionWrapper):
268
+ """Wrapper around a DirectFunction for LLM function calling.
269
+
270
+ This class:
271
+
272
+ - Extracts metadata from the function signature and docstring
273
+ - Generates a corresponding FunctionSchema
274
+ - Helps with function invocation
275
+ """
276
+
277
+ @classmethod
278
+ def special_first_param_name(cls) -> str:
279
+ """Get the special first parameter name for direct functions.
280
+
281
+ Returns:
282
+ The string "params" which is expected as the first parameter.
283
+ """
284
+ return "params"
285
+
286
+ async def invoke(self, args: Mapping[str, Any], params: "FunctionCallParams"):
287
+ """Invoke the wrapped function with the provided arguments.
288
+
289
+ Args:
290
+ args: Arguments to pass to the function.
291
+ params: Function call parameters from the LLM service.
292
+
293
+ Returns:
294
+ The result of the function call.
295
+ """
296
+ return await self.function(params=params, **args)
@@ -4,6 +4,13 @@
4
4
  # SPDX-License-Identifier: BSD 2-Clause License
5
5
  #
6
6
 
7
+ """Function schema utilities for AI tool definitions.
8
+
9
+ This module provides standardized function schema representation for defining
10
+ tools and functions used with AI models, ensuring consistent formatting
11
+ across different AI service providers.
12
+ """
13
+
7
14
  from typing import Any, Dict, List
8
15
 
9
16
 
@@ -13,17 +20,19 @@ class FunctionSchema:
13
20
  Provides a structured way to define function tools used with AI models like OpenAI.
14
21
  This schema defines the function's name, description, parameter properties, and
15
22
  required parameters, following specifications required by AI service providers.
16
-
17
- Args:
18
- name: Name of the function to be called.
19
- description: Description of what the function does.
20
- properties: Dictionary defining parameter types, descriptions, and constraints.
21
- required: List of property names that are required parameters.
22
23
  """
23
24
 
24
25
  def __init__(
25
26
  self, name: str, description: str, properties: Dict[str, Any], required: List[str]
26
27
  ) -> None:
28
+ """Initialize the function schema.
29
+
30
+ Args:
31
+ name: Name of the function to be called.
32
+ description: Description of what the function does.
33
+ properties: Dictionary defining parameter types, descriptions, and constraints.
34
+ required: List of property names that are required parameters.
35
+ """
27
36
  self._name = name
28
37
  self._description = description
29
38
  self._properties = properties
@@ -4,40 +4,88 @@
4
4
  # SPDX-License-Identifier: BSD 2-Clause License
5
5
  #
6
6
 
7
+ """Tools schema definitions for function calling adapters.
8
+
9
+ This module provides schemas for managing both standardized function tools
10
+ and custom adapter-specific tools in the Pipecat framework.
11
+ """
12
+
7
13
  from enum import Enum
8
14
  from typing import Any, Dict, List, Optional
9
15
 
16
+ from pipecat.adapters.schemas.direct_function import DirectFunction, DirectFunctionWrapper
10
17
  from pipecat.adapters.schemas.function_schema import FunctionSchema
11
18
 
12
19
 
13
20
  class AdapterType(Enum):
21
+ """Supported adapter types for custom tools.
22
+
23
+ Parameters:
24
+ GEMINI: Google Gemini adapter - currently the only service supporting custom tools.
25
+ """
26
+
14
27
  GEMINI = "gemini" # that is the only service where we are able to add custom tools for now
15
28
 
16
29
 
17
30
  class ToolsSchema:
31
+ """Schema for managing both standard and custom function calling tools.
32
+
33
+ This class provides a unified interface for handling standardized function
34
+ schemas alongside custom tools that may not follow the standard format,
35
+ such as adapter-specific search tools.
36
+ """
37
+
18
38
  def __init__(
19
39
  self,
20
- standard_tools: List[FunctionSchema],
40
+ standard_tools: List[FunctionSchema | DirectFunction],
21
41
  custom_tools: Optional[Dict[AdapterType, List[Dict[str, Any]]]] = None,
22
42
  ) -> None:
23
- """
24
- A schema for tools that includes both standardized function schemas
25
- and custom tools that do not follow the FunctionSchema format.
43
+ """Initialize the tools schema.
26
44
 
27
- :param standard_tools: List of tools following FunctionSchema.
28
- :param custom_tools: List of tools in a custom format (e.g., search_tool).
45
+ Args:
46
+ standard_tools: List of tools following the standardized FunctionSchema format.
47
+ custom_tools: Dictionary mapping adapter types to their custom tool definitions.
48
+ These tools may not follow the FunctionSchema format (e.g., search_tool).
29
49
  """
30
- self._standard_tools = standard_tools
50
+
51
+ def _map_standard_tools(tools):
52
+ schemas = []
53
+ for tool in tools:
54
+ if isinstance(tool, FunctionSchema):
55
+ schemas.append(tool)
56
+ elif callable(tool):
57
+ wrapper = DirectFunctionWrapper(tool)
58
+ schemas.append(wrapper.to_function_schema())
59
+ else:
60
+ raise TypeError(f"Unsupported tool type: {type(tool)}")
61
+ return schemas
62
+
63
+ self._standard_tools = _map_standard_tools(standard_tools)
31
64
  self._custom_tools = custom_tools
32
65
 
33
66
  @property
34
67
  def standard_tools(self) -> List[FunctionSchema]:
68
+ """Get the list of standard function schema tools.
69
+
70
+ Returns:
71
+ List of tools following the FunctionSchema format.
72
+ """
35
73
  return self._standard_tools
36
74
 
37
75
  @property
38
76
  def custom_tools(self) -> Dict[AdapterType, List[Dict[str, Any]]]:
77
+ """Get the custom tools dictionary.
78
+
79
+ Returns:
80
+ Dictionary mapping adapter types to their custom tool definitions.
81
+ """
39
82
  return self._custom_tools
40
83
 
41
84
  @custom_tools.setter
42
85
  def custom_tools(self, value: Dict[AdapterType, List[Dict[str, Any]]]) -> None:
86
+ """Set the custom tools dictionary.
87
+
88
+ Args:
89
+ value: Dictionary mapping adapter types to their custom tool definitions.
90
+ """
43
91
  self._custom_tools = value
@@ -4,6 +4,8 @@
4
4
  # SPDX-License-Identifier: BSD 2-Clause License
5
5
  #
6
6
 
7
+ """Anthropic LLM adapter for Pipecat."""
8
+
7
9
  from typing import Any, Dict, List
8
10
 
9
11
  from pipecat.adapters.base_llm_adapter import BaseLLMAdapter
@@ -12,8 +14,22 @@ from pipecat.adapters.schemas.tools_schema import ToolsSchema
12
14
 
13
15
 
14
16
  class AnthropicLLMAdapter(BaseLLMAdapter):
17
+ """Adapter for converting tool schemas to Anthropic's function-calling format.
18
+
19
+ This adapter handles the conversion of Pipecat's standard function schemas
20
+ to the specific format required by Anthropic's Claude models for function calling.
21
+ """
22
+
15
23
  @staticmethod
16
24
  def _to_anthropic_function_format(function: FunctionSchema) -> Dict[str, Any]:
25
+ """Convert a single function schema to Anthropic's format.
26
+
27
+ Args:
28
+ function: The function schema to convert.
29
+
30
+ Returns:
31
+ Dictionary containing the function definition in Anthropic's format.
32
+ """
17
33
  return {
18
34
  "name": function.name,
19
35
  "description": function.description,
@@ -25,10 +41,13 @@ class AnthropicLLMAdapter(BaseLLMAdapter):
25
41
  }
26
42
 
27
43
  def to_provider_tools_format(self, tools_schema: ToolsSchema) -> List[Dict[str, Any]]:
28
- """Converts function schemas to Anthropic's function-calling format.
44
+ """Convert function schemas to Anthropic's function-calling format.
29
45
 
30
- :return: Anthropic formatted function call definition.
31
- """
46
+ Args:
47
+ tools_schema: The tools schema containing functions to convert.
32
48
 
49
+ Returns:
50
+ List of function definitions formatted for Anthropic's API.
51
+ """
33
52
  functions_schema = tools_schema.standard_tools
34
53
  return [self._to_anthropic_function_format(func) for func in functions_schema]
@@ -3,6 +3,9 @@
3
3
  #
4
4
  # SPDX-License-Identifier: BSD 2-Clause License
5
5
  #
6
+
7
+ """AWS Nova Sonic LLM adapter for Pipecat."""
8
+
6
9
  import json
7
10
  from typing import Any, Dict, List
8
11
 
@@ -12,8 +15,22 @@ from pipecat.adapters.schemas.tools_schema import ToolsSchema
12
15
 
13
16
 
14
17
  class AWSNovaSonicLLMAdapter(BaseLLMAdapter):
18
+ """Adapter for AWS Nova Sonic language models.
19
+
20
+ Converts Pipecat's standard function schemas into AWS Nova Sonic's
21
+ specific function-calling format, enabling tool use with Nova Sonic models.
22
+ """
23
+
15
24
  @staticmethod
16
25
  def _to_aws_nova_sonic_function_format(function: FunctionSchema) -> Dict[str, Any]:
26
+ """Convert a function schema to AWS Nova Sonic format.
27
+
28
+ Args:
29
+ function: The function schema to convert.
30
+
31
+ Returns:
32
+ Dictionary in AWS Nova Sonic function format with toolSpec structure.
33
+ """
17
34
  return {
18
35
  "toolSpec": {
19
36
  "name": function.name,
@@ -31,10 +48,13 @@ class AWSNovaSonicLLMAdapter(BaseLLMAdapter):
31
48
  }
32
49
 
33
50
  def to_provider_tools_format(self, tools_schema: ToolsSchema) -> List[Dict[str, Any]]:
34
- """Converts function schemas to AWS Nova Sonic function-calling format.
51
+ """Convert tools schema to AWS Nova Sonic function-calling format.
35
52
 
36
- :return: AWS Nova Sonic formatted function call definition.
37
- """
53
+ Args:
54
+ tools_schema: The tools schema containing function definitions to convert.
38
55
 
56
+ Returns:
57
+ List of dictionaries in AWS Nova Sonic function format.
58
+ """
39
59
  functions_schema = tools_schema.standard_tools
40
60
  return [self._to_aws_nova_sonic_function_format(func) for func in functions_schema]
@@ -4,6 +4,8 @@
4
4
  # SPDX-License-Identifier: BSD 2-Clause License
5
5
  #
6
6
 
7
+ """AWS Bedrock LLM adapter for Pipecat."""
8
+
7
9
  from typing import Any, Dict, List
8
10
 
9
11
  from pipecat.adapters.base_llm_adapter import BaseLLMAdapter
@@ -12,8 +14,22 @@ from pipecat.adapters.schemas.tools_schema import ToolsSchema
12
14
 
13
15
 
14
16
  class AWSBedrockLLMAdapter(BaseLLMAdapter):
17
+ """Adapter for AWS Bedrock LLM integration with Pipecat.
18
+
19
+ Provides conversion utilities for transforming Pipecat function schemas
20
+ into AWS Bedrock's expected tool format for function calling capabilities.
21
+ """
22
+
15
23
  @staticmethod
16
24
  def _to_bedrock_function_format(function: FunctionSchema) -> Dict[str, Any]:
25
+ """Convert a function schema to Bedrock's tool format.
26
+
27
+ Args:
28
+ function: The function schema to convert.
29
+
30
+ Returns:
31
+ Dictionary formatted for Bedrock's tool specification.
32
+ """
17
33
  return {
18
34
  "toolSpec": {
19
35
  "name": function.name,
@@ -29,10 +45,13 @@ class AWSBedrockLLMAdapter(BaseLLMAdapter):
29
45
  }
30
46
 
31
47
  def to_provider_tools_format(self, tools_schema: ToolsSchema) -> List[Dict[str, Any]]:
32
- """Converts function schemas to Bedrock's function-calling format.
48
+ """Convert function schemas to Bedrock's function-calling format.
33
49
 
34
- :return: Bedrock formatted function call definition.
35
- """
50
+ Args:
51
+ tools_schema: The tools schema containing functions to convert.
36
52
 
53
+ Returns:
54
+ List of Bedrock formatted function call definitions.
55
+ """
37
56
  functions_schema = tools_schema.standard_tools
38
57
  return [self._to_bedrock_function_format(func) for func in functions_schema]
@@ -4,6 +4,8 @@
4
4
  # SPDX-License-Identifier: BSD 2-Clause License
5
5
  #
6
6
 
7
+ """Gemini LLM adapter for Pipecat."""
8
+
7
9
  from typing import Any, Dict, List, Union
8
10
 
9
11
  from pipecat.adapters.base_llm_adapter import BaseLLMAdapter
@@ -11,12 +13,23 @@ from pipecat.adapters.schemas.tools_schema import AdapterType, ToolsSchema
11
13
 
12
14
 
13
15
  class GeminiLLMAdapter(BaseLLMAdapter):
16
+ """LLM adapter for Google's Gemini service.
17
+
18
+ Provides tool schema conversion functionality to transform standard tool
19
+ definitions into Gemini's specific function-calling format for use with
20
+ Gemini LLM models.
21
+ """
22
+
14
23
  def to_provider_tools_format(self, tools_schema: ToolsSchema) -> List[Dict[str, Any]]:
15
- """Converts function schemas to Gemini's function-calling format.
24
+ """Convert tool schemas to Gemini's function-calling format.
16
25
 
17
- :return: Gemini formatted function call definition.
18
- """
26
+ Args:
27
+ tools_schema: The tools schema containing standard and custom tool definitions.
19
28
 
29
+ Returns:
30
+ List of tool definitions formatted for Gemini's function-calling API.
31
+ Includes both converted standard tools and any custom Gemini-specific tools.
32
+ """
20
33
  functions_schema = tools_schema.standard_tools
21
34
  formatted_standard_tools = [
22
35
  {"function_declarations": [func.to_default_dict() for func in functions_schema]}
@@ -3,6 +3,9 @@
3
3
  #
4
4
  # SPDX-License-Identifier: BSD 2-Clause License
5
5
  #
6
+
7
+ """OpenAI LLM adapter for Pipecat."""
8
+
6
9
  from typing import List
7
10
 
8
11
  from openai.types.chat import ChatCompletionToolParam
@@ -12,10 +15,22 @@ from pipecat.adapters.schemas.tools_schema import ToolsSchema
12
15
 
13
16
 
14
17
  class OpenAILLMAdapter(BaseLLMAdapter):
18
+ """Adapter for converting tool schemas to OpenAI's format.
19
+
20
+ Provides conversion utilities for transforming Pipecat's standard tool
21
+ schemas into the format expected by OpenAI's ChatCompletion API for
22
+ function calling capabilities.
23
+ """
24
+
15
25
  def to_provider_tools_format(self, tools_schema: ToolsSchema) -> List[ChatCompletionToolParam]:
16
- """Converts function schemas to OpenAI's function-calling format.
26
+ """Convert function schemas to OpenAI's function-calling format.
27
+
28
+ Args:
29
+ tools_schema: The Pipecat tools schema to convert.
17
30
 
18
- :return: OpenAI formatted function call definition.
31
+ Returns:
32
+ List of OpenAI formatted function call definitions ready for use
33
+ with ChatCompletion API.
19
34
  """
20
35
  functions_schema = tools_schema.standard_tools
21
36
  return [