diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 4e7300438a..ff0957efae 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -80,6 +80,7 @@ jobs:
praisonai,
langgraph,
phidata,
+ google,
]
runs-on: ${{ matrix.os }}
steps:
diff --git a/docs/framework/google.mdx b/docs/framework/google.mdx
new file mode 100644
index 0000000000..6b9d3dc00a
--- /dev/null
+++ b/docs/framework/google.mdx
@@ -0,0 +1,119 @@
+---
+title: "Using Composio With Google AI"
+sidebarTitle: "Google AI"
+icon: "robot"
+description: "Enable Google AI models to seamlessly interact with external apps via Composio for enhanced functionality"
+---
+
+**Composio enables** your **Google AI models** to **connect** with many **tools**!
+
+### Install Packages & Connect a Tool
+
+
+ Goal: Enable Google AI models to perform tasks like starring a repository on
+ GitHub via natural language commands
+
+
+These steps prepare your environment to enable interactions between Google AI and GitHub through Composio.
+
+
+ ```bash Run Command
+ pip install composio-google
+
+ # Connect your GitHub so models can interact with it
+
+ composio add github
+
+ # Check all supported apps
+
+ composio apps
+ ```
+
+
+
+
+
+Replace `{google_api_key}` with your actual API key.
+
+ ```python Default Imports & Configuration
+ import dotenv
+ from composio_google import App, ComposioToolset
+ from vertexai.generative_models import GenerativeModel
+
+ # Load environment variables from .env
+ dotenv.load_dotenv()
+
+ # Initialize the Composio Toolset
+ composio_toolset = ComposioToolset()
+
+ # Get GitHub tools that are pre-configured
+ tool = composio_toolset.get_tool(apps=[App.GITHUB])
+
+ # Initialize the Google AI Gemini model
+ model = GenerativeModel("gemini-1.5-pro", tools=[tool])
+ ```
+
+
+
+
+
+ ```python Start Chat Session
+ # Start a chat session
+ chat = model.start_chat()
+ ```
+
+
+
+
+
+ ```python Execute Task
+ # 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)
+ ```
+
+
+
+
+
+ ```python Handle Tool Calls
+ result = composio_toolset.handle_response(response)
+ print("Function call result:")
+ print(result)
+ ```
+
+
+
+
+
+### Use Specific Actions
+
+
+ ```python Filter Specific Action
+ # To restrict models from executing any actions, filter specific actions
+ actions = composio_toolset.get_tool(actions=[Action.GITHUB_CREATE_ISSUE])
+ ```
+
+
+### Use Specific Apps
+
+
+ ```python Filter Specific App
+ # To restrict models from using all tools, filter specific tools
+ actions = composio_toolset.get_tool(apps=[App.ASANA, App.GITHUB])
+ ```
+
+
+### Filter apps actions by tags
+
+
+ ```python Filter Actions by Tags
+ actions = composio_toolset.get_tool(apps=[App.ASANA], tags=[Tag.ASANA_TASKS])
+ ```
+
+
diff --git a/docs/framework/julep.mdx b/docs/framework/julep.mdx
index 5cb9a68b13..5fe1d98b75 100644
--- a/docs/framework/julep.mdx
+++ b/docs/framework/julep.mdx
@@ -1,7 +1,7 @@
---
title: "Using Composio With Julep"
sidebarTitle: "Julep"
-icon: "glass"
+icon: "robot"
description: "Integrate Composio with Julep agents to enhance their interaction with external apps"
---
diff --git a/python/plugins/google/README.md b/python/plugins/google/README.md
new file mode 100644
index 0000000000..17fd750581
--- /dev/null
+++ b/python/plugins/google/README.md
@@ -0,0 +1,66 @@
+## 🚀🔗 Integrating Composio with Google AI Python
+
+Streamline the integration of Composio with Google AI Python to enhance the capabilities of Gemini models, allowing them to interact directly with external applications and expanding their operational scope.
+
+### Objective
+
+- **Automate starring a GitHub repository** using conversational instructions via Google AI Python's Function Calling feature.
+
+### Installation and Setup
+
+Ensure you have the necessary packages installed and connect your GitHub account to allow your agents to utilize GitHub functionalities.
+
+```bash
+# Install Composio LangChain package
+pip install composio-google
+
+# Connect your GitHub account
+composio-cli add github
+
+# View available applications you can connect with
+composio-cli show-apps
+```
+
+### Usage Steps
+
+#### 1. Import Base Packages
+
+Prepare your environment by initializing necessary imports from Google AI Python and setting up your client.
+
+```python
+from vertexai.generative_models import GenerativeModel
+
+# Initialize Google AI Python client
+model = GenerativeModel("gemini-pro")
+```
+
+### Step 2: Integrating GitHub Tools with Composio
+
+This step involves fetching and integrating GitHub tools provided by Composio, enabling enhanced functionality for Google AI Python operations.
+```python
+from composio_google import App, ComposioToolset
+
+toolset = ComposioToolset()
+actions = toolset.get_tools(apps=[App.GITHUB])
+```
+
+### Step 3: Agent Execution
+
+This step involves configuring and executing the agent to carry out actions, such as starring a GitHub repository.
+
+```python
+# Define task
+task = "Star a repo composiohq/composio on GitHub"
+
+# Send a message to the model
+response = chat.send_message(task)
+```
+
+### Step 4: Validate Execution Response
+
+Execute the following code to validate the response, ensuring that the intended task has been successfully completed.
+
+```python
+result = composio_toolset.handle_response(response)
+print("Function call result:", result)
+```
diff --git a/python/plugins/google/composio_google/__init__.py b/python/plugins/google/composio_google/__init__.py
new file mode 100644
index 0000000000..4cc89c427b
--- /dev/null
+++ b/python/plugins/google/composio_google/__init__.py
@@ -0,0 +1,13 @@
+from composio_google.toolset import ComposioToolset
+
+from composio import Action, App, Tag, Trigger, WorkspaceType
+
+
+__all__ = (
+ "Action",
+ "App",
+ "Tag",
+ "Trigger",
+ "WorkspaceType",
+ "ComposioToolset",
+)
diff --git a/python/plugins/google/composio_google/toolset.py b/python/plugins/google/composio_google/toolset.py
new file mode 100644
index 0000000000..6045e66cce
--- /dev/null
+++ b/python/plugins/google/composio_google/toolset.py
@@ -0,0 +1,213 @@
+"""
+Google AI Python Gemini tool spec.
+"""
+
+import typing as t
+
+import typing_extensions as te
+from proto.marshal.collections.maps import MapComposite
+from vertexai.generative_models import (
+ Content,
+ FunctionDeclaration,
+ GenerationResponse,
+ Part,
+ Tool,
+)
+
+from composio import Action, ActionType, AppType, TagType
+from composio.constants import DEFAULT_ENTITY_ID
+from composio.tools import ComposioToolSet as BaseComposioToolSet
+from composio.utils.shared import json_schema_to_model
+
+
+class ComposioToolset(
+ BaseComposioToolSet,
+ runtime="google_ai",
+ description_char_limit=1024,
+):
+ """
+ Composio toolset for Google AI Python Gemini framework.
+
+ Example:
+ ```python
+ import os
+ import dotenv
+ from vertexai.generative_models import GenerativeModel
+ from composio_google import ComposioToolSet, App
+
+ # Load environment variables from .env
+ dotenv.load_dotenv()
+
+ # Initialize tools
+ composio_toolset = ComposioToolSet()
+
+ # Get GitHub tools that are pre-configured
+ tools = composio_toolset.get_tools(apps=[App.GITHUB])
+
+ # Initialize the Gemini model
+ model = GenerativeModel("gemini-pro", tools=tools)
+
+ # Start a chat
+ chat = model.start_chat()
+
+ # Define task
+ task = "Star a repo composiohq/composio on GitHub"
+
+ # Send a message to the model
+ response = chat.send_message(task)
+
+ print(response.text)
+
+ # Handle function calls if any
+ result = composio_toolset.handle_response(response)
+ if result:
+ print(result)
+ ```
+ """
+
+ def validate_entity_id(self, entity_id: str) -> str:
+ """Validate entity ID."""
+ if (
+ self.entity_id != DEFAULT_ENTITY_ID
+ and entity_id != DEFAULT_ENTITY_ID
+ and self.entity_id != entity_id
+ ):
+ raise ValueError(
+ "separate `entity_id` can not be provided during "
+ "initialization and handling tool calls"
+ )
+ if self.entity_id != DEFAULT_ENTITY_ID:
+ entity_id = self.entity_id
+ return entity_id
+
+ def _wrap_tool(
+ self,
+ schema: t.Dict[str, t.Any],
+ ) -> FunctionDeclaration:
+ """Wraps composio tool as Google AI Python Gemini FunctionDeclaration object."""
+ action = schema["name"]
+ description = schema.get("description", action)
+ parameters = json_schema_to_model(schema["parameters"])
+
+ # Clean up properties by removing 'examples' field
+ properties = parameters.schema().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()
+ }
+
+ # Create cleaned parameters
+ cleaned_parameters = {
+ "type": "object",
+ "properties": cleaned_properties,
+ "required": parameters.schema().get("required", []),
+ }
+
+ return FunctionDeclaration(
+ name=action,
+ description=description,
+ parameters=cleaned_parameters,
+ )
+
+ @te.deprecated("Use `ComposioToolSet.get_tools` instead")
+ def get_actions(
+ self,
+ actions: t.Sequence[ActionType],
+ entity_id: t.Optional[str] = None,
+ ) -> Tool:
+ """
+ Get composio tools wrapped as Google AI Python Gemini FunctionDeclaration objects.
+
+ :param actions: List of actions to wrap
+ :param entity_id: Entity ID for the function wrapper
+
+ :return: Composio tools wrapped as `FunctionDeclaration` objects
+ """
+ return self.get_tool(actions=actions, entity_id=entity_id)
+
+ def get_tool(
+ self,
+ actions: t.Optional[t.Sequence[ActionType]] = None,
+ apps: t.Optional[t.Sequence[AppType]] = None,
+ tags: t.Optional[t.List[TagType]] = None,
+ entity_id: t.Optional[str] = None,
+ ) -> Tool:
+ """
+ Get composio tools wrapped as Google AI Python Gemini FunctionDeclaration objects.
+
+ :param actions: List of actions to wrap
+ :param apps: List of apps to wrap
+ :param tags: Filter the apps by given tags
+ :param entity_id: Entity ID for the function wrapper
+
+ :return: Composio tools wrapped as `FunctionDeclaration` objects
+ """
+ entity_id = self.validate_entity_id(entity_id or self.entity_id)
+ self.validate_tools(apps=apps, actions=actions, tags=tags)
+ return Tool(
+ function_declarations=[
+ self._wrap_tool(
+ schema=tool.model_dump(
+ exclude_none=True,
+ ),
+ )
+ for tool in self.get_action_schemas(
+ actions=actions, apps=apps, tags=tags
+ )
+ ]
+ )
+
+ def execute_function_call(
+ self,
+ function_call: t.Any,
+ entity_id: t.Optional[str] = DEFAULT_ENTITY_ID,
+ ) -> t.Dict:
+ """
+ Execute a function call.
+
+ :param function_call: Function call metadata from Gemini model response.
+ :param entity_id: Entity ID to use for executing the function call.
+ :return: Object containing output data from the function call.
+ """
+ entity_id = self.validate_entity_id(entity_id or self.entity_id)
+
+ 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
+
+ args = convert_map_composite(function_call.args)
+
+ return self.execute_action(
+ action=Action(value=function_call.name),
+ params=args,
+ entity_id=entity_id,
+ )
+
+ def handle_response(
+ self,
+ response: GenerationResponse,
+ entity_id: t.Optional[str] = None,
+ ) -> t.List[t.Dict]:
+ """
+ Handle response from Google AI Python Gemini model.
+
+ :param response: Generation response from the Gemini model.
+ :param entity_id: Entity ID to use for executing the function call.
+ :return: A list of output objects from the function calls.
+ """
+ entity_id = self.validate_entity_id(entity_id or self.entity_id)
+ 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_function_call(
+ function_call=part.function_call,
+ entity_id=entity_id,
+ )
+ )
+ return outputs
diff --git a/python/plugins/google/google_demo.py b/python/plugins/google/google_demo.py
new file mode 100644
index 0000000000..1c6cf0bfa7
--- /dev/null
+++ b/python/plugins/google/google_demo.py
@@ -0,0 +1,41 @@
+"""
+Google AI Python Gemini demo.
+"""
+import dotenv
+from composio_google import App, ComposioToolset
+from vertexai.generative_models import GenerativeModel
+
+
+# Load environment variables from .env
+dotenv.load_dotenv()
+
+# Initialize tools
+composio_toolset = ComposioToolset()
+
+# Get GitHub tools that are pre-configured
+tool = composio_toolset.get_tool(apps=[App.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_toolset.handle_response(response)
+ print("Function call result:")
+ print(result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/python/plugins/google/setup.py b/python/plugins/google/setup.py
new file mode 100644
index 0000000000..330625ded4
--- /dev/null
+++ b/python/plugins/google/setup.py
@@ -0,0 +1,30 @@
+"""
+Setup configuration for Composio Google AI Python Gemini plugin
+"""
+
+from pathlib import Path
+
+from setuptools import setup
+
+
+setup(
+ name="composio_google",
+ version="0.5.25",
+ author="Assistant",
+ author_email="karan@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.9,<4",
+ install_requires=[
+ "composio_core==0.5.25",
+ "google-cloud-aiplatform>=1.38.0",
+ ],
+ include_package_data=True,
+)
diff --git a/python/scripts/bump.py b/python/scripts/bump.py
index 61d9d4d950..e647e80d0b 100644
--- a/python/scripts/bump.py
+++ b/python/scripts/bump.py
@@ -34,6 +34,7 @@ class BumpType(Enum):
"composio_langgraph==",
"composio_praisonai==",
"composio_camel==",
+ "composio_google==",
)