From 9d5f5844b87c6a428429dd1637dc4297b85980d2 Mon Sep 17 00:00:00 2001 From: Yousif Astarabadi <6870090+yousifa@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:14:45 -0700 Subject: [PATCH 1/9] clean mcp schema for gemini models, update http mcp example to use gemini --- examples/foundational/39c-mcp-run-http.py | 5 ++++- src/pipecat/services/mcp_service.py | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/examples/foundational/39c-mcp-run-http.py b/examples/foundational/39c-mcp-run-http.py index 1c51894b1..df17869bb 100644 --- a/examples/foundational/39c-mcp-run-http.py +++ b/examples/foundational/39c-mcp-run-http.py @@ -16,6 +16,7 @@ from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext +from pipecat.services.google.llm import GoogleLLMService from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.mcp_service import MCPClient @@ -58,7 +59,9 @@ async def run_example(transport: BaseTransport, _: argparse.Namespace, handle_si voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady ) - llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o-mini") + llm = GoogleLLMService( + api_key=os.getenv("GOOGLE_API_KEY"), model="gemini-2.0-flash" + ) try: # Github MCP docs: https://github.com/github/github-mcp-server diff --git a/src/pipecat/services/mcp_service.py b/src/pipecat/services/mcp_service.py index 48202e8f9..13d58ed0c 100644 --- a/src/pipecat/services/mcp_service.py +++ b/src/pipecat/services/mcp_service.py @@ -82,13 +82,14 @@ class MCPClient(BaseObject): return tools_schema def _convert_mcp_schema_to_pipecat( - self, tool_name: str, tool_schema: Dict[str, Any] + self, tool_name: str, tool_schema: Dict[str, Any], llm=None ) -> FunctionSchema: """Convert an mcp tool schema to Pipecat's FunctionSchema format. Args: tool_name: The name of the tool tool_schema: The mcp tool schema + llm: The LLM service instance (used to determine if we need Gemini compatibility) Returns: A FunctionSchema instance """ @@ -97,6 +98,11 @@ class MCPClient(BaseObject): properties = tool_schema["input_schema"].get("properties", {}) required = tool_schema["input_schema"].get("required", []) + + # Only clean properties for Google/Gemini LLM services + if llm and self._is_google_llm(llm): + logger.debug(f"Detected Google LLM service, cleaning schema for Gemini compatibility") + properties = self._clean_schema_for_gemini(properties) schema = FunctionSchema( name=tool_name, From 92df8dc43cca1dc51327bbff154c295b9fc44fd2 Mon Sep 17 00:00:00 2001 From: Yousif Astarabadi <6870090+yousifa@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:15:58 -0700 Subject: [PATCH 2/9] fix formatting --- examples/foundational/39c-mcp-run-http.py | 4 +--- src/pipecat/services/mcp_service.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/foundational/39c-mcp-run-http.py b/examples/foundational/39c-mcp-run-http.py index df17869bb..e39349f37 100644 --- a/examples/foundational/39c-mcp-run-http.py +++ b/examples/foundational/39c-mcp-run-http.py @@ -59,9 +59,7 @@ async def run_example(transport: BaseTransport, _: argparse.Namespace, handle_si voice_id="71a7ad14-091c-4e8e-a314-022ece01c121", # British Reading Lady ) - llm = GoogleLLMService( - api_key=os.getenv("GOOGLE_API_KEY"), model="gemini-2.0-flash" - ) + llm = GoogleLLMService(api_key=os.getenv("GOOGLE_API_KEY"), model="gemini-2.0-flash") try: # Github MCP docs: https://github.com/github/github-mcp-server diff --git a/src/pipecat/services/mcp_service.py b/src/pipecat/services/mcp_service.py index 13d58ed0c..c51a9bd9c 100644 --- a/src/pipecat/services/mcp_service.py +++ b/src/pipecat/services/mcp_service.py @@ -98,7 +98,7 @@ class MCPClient(BaseObject): properties = tool_schema["input_schema"].get("properties", {}) required = tool_schema["input_schema"].get("required", []) - + # Only clean properties for Google/Gemini LLM services if llm and self._is_google_llm(llm): logger.debug(f"Detected Google LLM service, cleaning schema for Gemini compatibility") From 0c2066800849f6d4f3044942a1f2cad0c3a75f5a Mon Sep 17 00:00:00 2001 From: Yousif Astarabadi <6870090+yousifa@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:21:44 -0700 Subject: [PATCH 3/9] fixed linter errors --- examples/foundational/39c-mcp-run-http.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/foundational/39c-mcp-run-http.py b/examples/foundational/39c-mcp-run-http.py index e39349f37..bdcaa78a5 100644 --- a/examples/foundational/39c-mcp-run-http.py +++ b/examples/foundational/39c-mcp-run-http.py @@ -16,9 +16,9 @@ from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.runner import PipelineRunner from pipecat.pipeline.task import PipelineParams, PipelineTask from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext -from pipecat.services.google.llm import GoogleLLMService from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.deepgram.stt import DeepgramSTTService +from pipecat.services.google.llm import GoogleLLMService from pipecat.services.mcp_service import MCPClient from pipecat.services.openai.llm import OpenAILLMService from pipecat.transports.base_transport import BaseTransport, TransportParams From 86c26fd64c69f481312d84796ba9fa3a7370c6ab Mon Sep 17 00:00:00 2001 From: Yousif Astarabadi <6870090+yousifa@users.noreply.github.com> Date: Thu, 26 Jun 2025 19:57:58 -0700 Subject: [PATCH 4/9] moved needs_mcp_clean_schema to LLMService --- .../services/gemini_multimodal_live/gemini.py | 11 ++++ src/pipecat/services/google/llm.py | 11 ++++ src/pipecat/services/llm_service.py | 11 ++++ src/pipecat/services/mcp_service.py | 54 ++++++++++++++++--- 4 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/pipecat/services/gemini_multimodal_live/gemini.py b/src/pipecat/services/gemini_multimodal_live/gemini.py index afaf966dc..f9584df9d 100644 --- a/src/pipecat/services/gemini_multimodal_live/gemini.py +++ b/src/pipecat/services/gemini_multimodal_live/gemini.py @@ -524,6 +524,17 @@ class GeminiMultimodalLiveLLMService(LLMService): """ return True + def needs_mcp_clean_schema(self) -> bool: + """Check if this LLM service requires MCP schema cleaning. + + Google/Gemini has stricter JSON schema validation and requires + certain properties to be removed or modified for compatibility. + + Returns: + True for Google/Gemini services. + """ + return True + def set_audio_input_paused(self, paused: bool): """Set the audio input pause state. diff --git a/src/pipecat/services/google/llm.py b/src/pipecat/services/google/llm.py index 6b8f51f33..e36c6591e 100644 --- a/src/pipecat/services/google/llm.py +++ b/src/pipecat/services/google/llm.py @@ -631,6 +631,17 @@ class GoogleLLMService(LLMService): """ return True + def needs_mcp_clean_schema(self) -> bool: + """Check if this LLM service requires MCP schema cleaning. + + Google/Gemini has stricter JSON schema validation and requires + certain properties to be removed or modified for compatibility. + + Returns: + True for Google/Gemini services. + """ + return True + def _create_client(self, api_key: str): self._client = genai.Client(api_key=api_key) diff --git a/src/pipecat/services/llm_service.py b/src/pipecat/services/llm_service.py index f7779df98..24ed932d8 100644 --- a/src/pipecat/services/llm_service.py +++ b/src/pipecat/services/llm_service.py @@ -307,6 +307,17 @@ class LLMService(AIService): return True return function_name in self._functions.keys() + def needs_mcp_clean_schema(self) -> bool: + """Check if this LLM service requires MCP schema cleaning. + + Some LLM services have stricter JSON schema validation and require + certain properties to be removed or modified for compatibility. + + Returns: + True if MCP schemas should be cleaned for this service, False otherwise. + """ + return False + async def run_function_calls(self, function_calls: Sequence[FunctionCallFromLLM]): """Execute a sequence of function calls from the LLM. diff --git a/src/pipecat/services/mcp_service.py b/src/pipecat/services/mcp_service.py index c51a9bd9c..3d757e32e 100644 --- a/src/pipecat/services/mcp_service.py +++ b/src/pipecat/services/mcp_service.py @@ -51,6 +51,7 @@ class MCPClient(BaseObject): super().__init__(**kwargs) self._server_params = server_params self._session = ClientSession + self._needs_schema_cleaning = False if isinstance(server_params, StdioServerParameters): self._client = stdio_client @@ -78,18 +79,56 @@ class MCPClient(BaseObject): Returns: A ToolsSchema containing all successfully registered tools. """ + # Check once if the LLM needs schema cleaning + self._needs_schema_cleaning = llm and llm.needs_mcp_clean_schema() tools_schema = await self._register_tools(llm) return tools_schema + def _clean_schema_for_strict_validation(self, schema: Dict[str, Any]) -> Dict[str, Any]: + """Clean a JSON schema to be compatible with LLMs that have strict validation. + + Some LLMs have stricter validation and don't allow certain schema properties + that are valid in standard JSON Schema. + + Args: + schema: The JSON schema to clean + + Returns: + A cleaned schema compatible with strict validation + """ + if not isinstance(schema, dict): + return schema + + cleaned = {} + + for key, value in schema.items(): + # Skip additionalProperties as some LLMs don't like additionalProperties: false + if key == "additionalProperties": + continue + + # Recursively clean nested objects + if isinstance(value, dict): + cleaned[key] = self._clean_schema_for_strict_validation(value) + elif isinstance(value, list): + cleaned[key] = [ + self._clean_schema_for_strict_validation(item) + if isinstance(item, dict) + else item + for item in value + ] + else: + cleaned[key] = value + + return cleaned + def _convert_mcp_schema_to_pipecat( - self, tool_name: str, tool_schema: Dict[str, Any], llm=None + self, tool_name: str, tool_schema: Dict[str, Any] ) -> FunctionSchema: """Convert an mcp tool schema to Pipecat's FunctionSchema format. Args: tool_name: The name of the tool tool_schema: The mcp tool schema - llm: The LLM service instance (used to determine if we need Gemini compatibility) Returns: A FunctionSchema instance """ @@ -99,10 +138,10 @@ class MCPClient(BaseObject): properties = tool_schema["input_schema"].get("properties", {}) required = tool_schema["input_schema"].get("required", []) - # Only clean properties for Google/Gemini LLM services - if llm and self._is_google_llm(llm): - logger.debug(f"Detected Google LLM service, cleaning schema for Gemini compatibility") - properties = self._clean_schema_for_gemini(properties) + # Only clean properties for LLMs that need strict schema validation + if self._needs_schema_cleaning: + logger.debug("Cleaning schema for strict validation") + properties = self._clean_schema_for_strict_validation(properties) schema = FunctionSchema( name=tool_name, @@ -283,7 +322,8 @@ class MCPClient(BaseObject): try: # Convert the schema function_schema = self._convert_mcp_schema_to_pipecat( - tool_name, {"description": tool.description, "input_schema": tool.inputSchema} + tool_name, + {"description": tool.description, "input_schema": tool.inputSchema}, ) # Register the wrapped function From cafbda1668825d02920c8236356f60c447884593 Mon Sep 17 00:00:00 2001 From: Yousif Astarabadi <6870090+yousifa@users.noreply.github.com> Date: Thu, 26 Jun 2025 20:21:07 -0700 Subject: [PATCH 5/9] remove openai from mcp run http example --- examples/foundational/39c-mcp-run-http.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/foundational/39c-mcp-run-http.py b/examples/foundational/39c-mcp-run-http.py index bdcaa78a5..6c39da75c 100644 --- a/examples/foundational/39c-mcp-run-http.py +++ b/examples/foundational/39c-mcp-run-http.py @@ -20,7 +20,6 @@ from pipecat.services.cartesia.tts import CartesiaTTSService from pipecat.services.deepgram.stt import DeepgramSTTService from pipecat.services.google.llm import GoogleLLMService from pipecat.services.mcp_service import MCPClient -from pipecat.services.openai.llm import OpenAILLMService from pipecat.transports.base_transport import BaseTransport, TransportParams from pipecat.transports.network.fastapi_websocket import FastAPIWebsocketParams from pipecat.transports.services.daily import DailyParams From 58675f4d5a042de7bb26561c58fcddda4027a30e Mon Sep 17 00:00:00 2001 From: Yousif Astarabadi <6870090+yousifa@users.noreply.github.com> Date: Tue, 1 Jul 2025 11:50:12 -0700 Subject: [PATCH 6/9] renamed clean schema to alternate schema --- .../services/gemini_multimodal_live/gemini.py | 4 +-- src/pipecat/services/google/llm.py | 4 +-- src/pipecat/services/llm_service.py | 4 +-- src/pipecat/services/mcp_service.py | 36 +++++++++---------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/pipecat/services/gemini_multimodal_live/gemini.py b/src/pipecat/services/gemini_multimodal_live/gemini.py index f9584df9d..ec33eb7b4 100644 --- a/src/pipecat/services/gemini_multimodal_live/gemini.py +++ b/src/pipecat/services/gemini_multimodal_live/gemini.py @@ -524,8 +524,8 @@ class GeminiMultimodalLiveLLMService(LLMService): """ return True - def needs_mcp_clean_schema(self) -> bool: - """Check if this LLM service requires MCP schema cleaning. + def needs_mcp_alternate_schema(self) -> bool: + """Check if this LLM service requires alternate MCP schema. Google/Gemini has stricter JSON schema validation and requires certain properties to be removed or modified for compatibility. diff --git a/src/pipecat/services/google/llm.py b/src/pipecat/services/google/llm.py index e36c6591e..ed4939bfb 100644 --- a/src/pipecat/services/google/llm.py +++ b/src/pipecat/services/google/llm.py @@ -631,8 +631,8 @@ class GoogleLLMService(LLMService): """ return True - def needs_mcp_clean_schema(self) -> bool: - """Check if this LLM service requires MCP schema cleaning. + def needs_mcp_alternate_schema(self) -> bool: + """Check if this LLM service requires alternate MCP schema. Google/Gemini has stricter JSON schema validation and requires certain properties to be removed or modified for compatibility. diff --git a/src/pipecat/services/llm_service.py b/src/pipecat/services/llm_service.py index 24ed932d8..ec4ee9eec 100644 --- a/src/pipecat/services/llm_service.py +++ b/src/pipecat/services/llm_service.py @@ -307,8 +307,8 @@ class LLMService(AIService): return True return function_name in self._functions.keys() - def needs_mcp_clean_schema(self) -> bool: - """Check if this LLM service requires MCP schema cleaning. + def needs_mcp_alternate_schema(self) -> bool: + """Check if this LLM service requires alternate MCP schema. Some LLM services have stricter JSON schema validation and require certain properties to be removed or modified for compatibility. diff --git a/src/pipecat/services/mcp_service.py b/src/pipecat/services/mcp_service.py index 3d757e32e..c165b96fa 100644 --- a/src/pipecat/services/mcp_service.py +++ b/src/pipecat/services/mcp_service.py @@ -51,7 +51,7 @@ class MCPClient(BaseObject): super().__init__(**kwargs) self._server_params = server_params self._session = ClientSession - self._needs_schema_cleaning = False + self._needs_alternate_schema = False if isinstance(server_params, StdioServerParameters): self._client = stdio_client @@ -79,47 +79,47 @@ class MCPClient(BaseObject): Returns: A ToolsSchema containing all successfully registered tools. """ - # Check once if the LLM needs schema cleaning - self._needs_schema_cleaning = llm and llm.needs_mcp_clean_schema() + # Check once if the LLM needs alternate strict schema + self._needs_alternate_schema = llm and llm.needs_mcp_alternate_schema() tools_schema = await self._register_tools(llm) return tools_schema - def _clean_schema_for_strict_validation(self, schema: Dict[str, Any]) -> Dict[str, Any]: - """Clean a JSON schema to be compatible with LLMs that have strict validation. + def _get_alternate_schema_for_strict_validation(self, schema: Dict[str, Any]) -> Dict[str, Any]: + """Get an alternate JSON schema to be compatible with LLMs that have strict validation. Some LLMs have stricter validation and don't allow certain schema properties that are valid in standard JSON Schema. Args: - schema: The JSON schema to clean + schema: The JSON schema to get an alternate schema for Returns: - A cleaned schema compatible with strict validation + An alternate schema compatible with strict validation """ if not isinstance(schema, dict): return schema - cleaned = {} + alternate_schema = {} for key, value in schema.items(): # Skip additionalProperties as some LLMs don't like additionalProperties: false if key == "additionalProperties": continue - # Recursively clean nested objects + # Recursively get alternate schema for nested objects if isinstance(value, dict): - cleaned[key] = self._clean_schema_for_strict_validation(value) + alternate_schema[key] = self._get_alternate_schema_for_strict_validation(value) elif isinstance(value, list): - cleaned[key] = [ - self._clean_schema_for_strict_validation(item) + alternate_schema[key] = [ + self._get_alternate_schema_for_strict_validation(item) if isinstance(item, dict) else item for item in value ] else: - cleaned[key] = value + alternate_schema[key] = value - return cleaned + return alternate_schema def _convert_mcp_schema_to_pipecat( self, tool_name: str, tool_schema: Dict[str, Any] @@ -138,10 +138,10 @@ class MCPClient(BaseObject): properties = tool_schema["input_schema"].get("properties", {}) required = tool_schema["input_schema"].get("required", []) - # Only clean properties for LLMs that need strict schema validation - if self._needs_schema_cleaning: - logger.debug("Cleaning schema for strict validation") - properties = self._clean_schema_for_strict_validation(properties) + # Only get alternate schema for LLMs that need strict schema validation + if self._needs_alternate_schema: + logger.debug("Getting alternate schema for strict validation") + properties = self._get_alternate_schema_for_strict_validation(properties) schema = FunctionSchema( name=tool_name, From 1ab2ddd317715c3252528bf14a133d920f61cb26 Mon Sep 17 00:00:00 2001 From: Yousif Astarabadi <6870090+yousifa@users.noreply.github.com> Date: Tue, 1 Jul 2025 23:55:34 -0700 Subject: [PATCH 7/9] fix lint error --- .../services/gemini_multimodal_live/gemini.py | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/pipecat/services/gemini_multimodal_live/gemini.py b/src/pipecat/services/gemini_multimodal_live/gemini.py index f278ca3d4..1fd6e7bbf 100644 --- a/src/pipecat/services/gemini_multimodal_live/gemini.py +++ b/src/pipecat/services/gemini_multimodal_live/gemini.py @@ -72,7 +72,6 @@ from pipecat.utils.time import time_now_iso8601 from pipecat.utils.tracing.service_decorators import traced_gemini_live, traced_stt from . import events - from .file_api import GeminiFileAPI try: @@ -223,9 +222,9 @@ class GeminiMultimodalLiveContext(OpenAILLMContext): def add_file_reference(self, file_uri: str, mime_type: str, text: Optional[str] = None): """Add a file reference to the context. - + This adds a user message with a file reference that will be sent during context initialization. - + Args: file_uri: URI of the uploaded file mime_type: MIME type of the file @@ -235,15 +234,17 @@ class GeminiMultimodalLiveContext(OpenAILLMContext): parts = [] if text: parts.append({"type": "text", "text": text}) - + # Add file reference part - parts.append({"type": "file_data", "file_data": {"mime_type": mime_type, "file_uri": file_uri}}) - + parts.append( + {"type": "file_data", "file_data": {"mime_type": mime_type, "file_uri": file_uri}} + ) + # Add to messages message = {"role": "user", "content": parts} self.messages.append(message) logger.info(f"Added file reference to context: {file_uri}") - + def get_messages_for_initializing_history(self): """Get messages formatted for Gemini history initialization. @@ -270,12 +271,14 @@ class GeminiMultimodalLiveContext(OpenAILLMContext): parts.append({"text": part.get("text")}) elif part.get("type") == "file_data": file_data = part.get("file_data", {}) - parts.append({ - "fileData": { - "mimeType": file_data.get("mime_type"), - "fileUri": file_data.get("file_uri") + parts.append( + { + "fileData": { + "mimeType": file_data.get("mime_type"), + "fileUri": file_data.get("file_uri"), + } } - }) + ) else: logger.warning(f"Unsupported content type: {str(part)[:80]}") else: @@ -465,7 +468,7 @@ class GeminiMultimodalLiveLLMService(LLMService): # Overriding the default adapter to use the Gemini one. adapter_class = GeminiLLMAdapter - + def __init__( self, *, @@ -557,7 +560,7 @@ class GeminiMultimodalLiveLLMService(LLMService): else {}, "extra": params.extra if isinstance(params.extra, dict) else {}, } - + # Initialize the File API client self.file_api = GeminiFileAPI(api_key=api_key, base_url=file_api_base_url) @@ -1011,12 +1014,14 @@ class GeminiMultimodalLiveLLMService(LLMService): parts.append({"text": part.get("text")}) elif part.get("type") == "file_data": file_data = part.get("file_data", {}) - parts.append({ - "fileData": { - "mimeType": file_data.get("mime_type"), - "fileUri": file_data.get("file_uri") + parts.append( + { + "fileData": { + "mimeType": file_data.get("mime_type"), + "fileUri": file_data.get("file_uri"), + } } - }) + ) else: logger.warning(f"Unsupported content type: {str(part)[:80]}") else: From 4bcc536fd2d93d3c70dcbe088f7e4e278926bd1f Mon Sep 17 00:00:00 2001 From: Yousif Astarabadi <6870090+yousifa@users.noreply.github.com> Date: Wed, 2 Jul 2025 00:03:27 -0700 Subject: [PATCH 8/9] added arg description in docstring for gemini live init --- src/pipecat/services/gemini_multimodal_live/gemini.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pipecat/services/gemini_multimodal_live/gemini.py b/src/pipecat/services/gemini_multimodal_live/gemini.py index 1fd6e7bbf..f873e9d84 100644 --- a/src/pipecat/services/gemini_multimodal_live/gemini.py +++ b/src/pipecat/services/gemini_multimodal_live/gemini.py @@ -499,6 +499,7 @@ class GeminiMultimodalLiveLLMService(LLMService): params: Configuration parameters for the model. Defaults to InputParams(). inference_on_context_initialization: Whether to generate a response when context is first set. Defaults to True. + file_api_base_url: Base URL for the file API. Defaults to the official Gemini Live endpoint. **kwargs: Additional arguments passed to parent LLMService. """ super().__init__(base_url=base_url, **kwargs) From 18817fd81be87454ca1bea404fee62d06b616226 Mon Sep 17 00:00:00 2001 From: Yousif Astarabadi <6870090+yousifa@users.noreply.github.com> Date: Wed, 2 Jul 2025 00:09:48 -0700 Subject: [PATCH 9/9] added docstring in public GeminiFileAPI module --- src/pipecat/services/gemini_multimodal_live/file_api.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pipecat/services/gemini_multimodal_live/file_api.py b/src/pipecat/services/gemini_multimodal_live/file_api.py index f0f23ab83..1324d4ee8 100644 --- a/src/pipecat/services/gemini_multimodal_live/file_api.py +++ b/src/pipecat/services/gemini_multimodal_live/file_api.py @@ -4,6 +4,13 @@ # SPDX-License-Identifier: BSD 2-Clause License # +"""Gemini File API client for uploading and managing files. + +This module provides the GeminiFileAPI class for interacting with Google's Gemini File API, +including uploading, fetching, listing, and deleting files that can be used with Gemini +generative models. +""" + import mimetypes from typing import Any, Dict, Optional