chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:38:34 +08:00
commit 0549b088a4
2405 changed files with 810255 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
# composio-google
Adapts Composio tools to the Vertex AI SDK (`vertexai.generative_models`) as `FunctionDeclaration` objects for Gemini function calling.
## Installation
```bash
pip install composio composio-google google-cloud-aiplatform
```
Set `COMPOSIO_API_KEY` (create one at https://dashboard.composio.dev/settings) in your environment. Vertex AI authenticates with Google Cloud credentials; run `gcloud auth application-default login` or set `GOOGLE_APPLICATION_CREDENTIALS`.
## Quickstart
`GoogleProvider` is non-agentic: the model returns function calls, and `composio.provider.handle_response` executes every function call in the response and returns the results.
```python
import vertexai
from vertexai.generative_models import GenerativeModel, Tool
from composio import Composio
from composio_google import GoogleProvider
vertexai.init(project="your-gcp-project", location="us-central1")
composio = Composio(provider=GoogleProvider())
# Create a session for your user
session = composio.create(user_id="user_123")
tools = session.tools()
model = GenerativeModel(
"gemini-2.0-flash",
tools=[Tool(function_declarations=tools)],
)
chat = model.start_chat()
response = chat.send_message(
"Send an email to john@example.com with the subject 'Hello' and body 'Hello from Composio!'"
)
# Execute the function calls the model requested
results = composio.provider.handle_response(user_id="user_123", response=response)
print(results)
```
To execute a single call instead of the whole response, use `composio.provider.execute_tool_call(user_id="user_123", function_call=part.function_call)`.
## composio-google vs composio-gemini
This package targets the Vertex AI SDK (`vertexai.generative_models`, installed via `google-cloud-aiplatform`). [`composio-gemini`](../gemini) targets the newer `google-genai` SDK with Automatic Function Calling. For new projects, use `composio-gemini`.
## Links
- Google provider docs: https://docs.composio.dev/docs/providers/google
- Composio docs: https://docs.composio.dev
@@ -0,0 +1,3 @@
from composio_google.provider import GoogleProvider
__all__ = ("GoogleProvider",)
@@ -0,0 +1,109 @@
"""
Google AI Python Gemini tool spec.
"""
import typing as t
from proto.marshal.collections.maps import MapComposite
from vertexai.generative_models import (
Content,
FunctionDeclaration,
GenerationResponse,
Part,
)
from composio.core.provider import NonAgenticProvider
from composio.types import Modifiers, Tool, ToolExecutionResponse
from composio.utils.shared import normalize_tool_arguments
def _convert_map_composite(obj):
if isinstance(obj, MapComposite):
return {k: _convert_map_composite(v) for k, v in obj.items()}
if isinstance(obj, (list, tuple)):
return [_convert_map_composite(item) for item in obj]
return obj
class GoogleProvider(
NonAgenticProvider[FunctionDeclaration, list[FunctionDeclaration]],
name="google",
):
"""
Composio toolset for Google AI Python Gemini framework.
"""
def wrap_tool(self, tool: Tool) -> FunctionDeclaration:
"""Wraps composio tool as Google AI Python Gemini FunctionDeclaration object."""
# Clean up properties by removing 'examples' field
properties = t.cast(
dict[str, dict],
tool.input_parameters.get("properties", {}),
)
cleaned_properties = {
prop_name: {k: v for k, v in prop_schema.items() if k != "examples"}
for prop_name, prop_schema in properties.items()
}
return FunctionDeclaration(
name=tool.slug,
description=tool.description,
parameters={
"type": "object",
"properties": cleaned_properties,
"required": tool.input_parameters.get("required", []),
},
)
def wrap_tools(self, tools: t.Sequence[Tool]) -> list[FunctionDeclaration]:
return [self.wrap_tool(tool) for tool in tools]
def execute_tool_call(
self,
user_id: str,
function_call: t.Any,
modifiers: t.Optional[Modifiers] = None,
) -> ToolExecutionResponse:
"""
Execute a function call.
:param function_call: Function call metadata from Gemini model response.
:param user_id: User ID to use for executing the function call.
:return: Object containing output data from the function call.
"""
# Gemini returns args as a MapComposite; normalize after converting to a
# plain dict so a stringified payload is handled uniformly too (issue #2406).
return self.execute_tool(
slug=function_call.name,
arguments=normalize_tool_arguments(
_convert_map_composite(function_call.args)
),
modifiers=modifiers,
user_id=user_id,
)
def handle_response(
self,
user_id: str,
response: GenerationResponse,
modifiers: t.Optional[Modifiers] = None,
) -> t.List[ToolExecutionResponse]:
"""
Handle response from Google AI Python Gemini model.
:param response: Generation response from the Gemini model.
:param user_id: User ID to use for executing the function call.
:return: A list of output objects from the function calls.
"""
outputs = []
for candidate in response.candidates:
if isinstance(candidate.content, Content) and candidate.content.parts:
for part in candidate.content.parts:
if isinstance(part, Part) and part.function_call:
outputs.append(
self.execute_tool_call(
user_id=user_id,
function_call=part.function_call,
modifiers=modifiers,
)
)
return outputs
+43
View File
@@ -0,0 +1,43 @@
"""
Google AI Python Gemini demo.
"""
import dotenv
from composio_google import GoogleProvider
from vertexai.generative_models import GenerativeModel
from composio import Composio
# Load environment variables from .env
dotenv.load_dotenv()
# Initialize tools
composio = Composio(provider=GoogleProvider())
# Get GitHub tools that are pre-configured
tool = composio.tools.get(user_id="default", toolkits=["GITHUB"])
# Initialize the Gemini model
model = GenerativeModel("gemini-1.5-pro", tools=[tool])
# Start a chat session
chat = model.start_chat()
def main():
# Define task
task = "Star a repo composiohq/composio on GitHub"
# Send a message to the model
response = chat.send_message(task)
print("Model response:")
print(response)
result = composio.provider.handle_response(user_id="default", response=response)
print("Function call result:")
print(result)
if __name__ == "__main__":
main()
+21
View File
@@ -0,0 +1,21 @@
[project]
name = "composio-google"
version = "0.17.1"
description = "Use Composio to get an array of tools with your Google AI Python Gemini model."
readme = "README.md"
requires-python = ">=3.10,<4"
authors = [
{ name = "Composio", email = "tech@composio.dev" }
]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
]
dependencies = [
"google-cloud-aiplatform>=1.158.0",
"composio",
]
[project.urls]
Homepage = "https://github.com/ComposioHQ/composio"
+29
View File
@@ -0,0 +1,29 @@
"""
Setup configuration for Composio Google AI Python Gemini plugin
"""
from pathlib import Path
from setuptools import setup
setup(
name="composio_google",
version="0.17.1",
author="Composio",
author_email="tech@composio.dev",
description="Use Composio to get an array of tools with your Google AI Python Gemini model.",
long_description=(Path(__file__).parent / "README.md").read_text(encoding="utf-8"),
long_description_content_type="text/markdown",
url="https://github.com/ComposioHQ/composio",
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
],
python_requires=">=3.10,<4",
install_requires=[
"google-cloud-aiplatform>=1.158.0",
"composio",
],
include_package_data=True,
)