Skip to content

Commit 9fe000a

Browse files
authored
add Google ADK support (#34)
* add initial google adk support * move example to examples * update readme * remove _version.py * remove old uv.lock * remove unused env var * fix args
1 parent bd14f35 commit 9fe000a

File tree

10 files changed

+2919
-4906
lines changed

10 files changed

+2919
-4906
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# thirdweb-ai with Google Agent Development Kit (ADK)
2+
3+
This example demonstrates how to integrate thirdweb-ai's blockchain tooling with [Google ADK](https://github.com/google/adk-python), an open-source toolkit from Google for building autonomous agents.
4+
5+
## Overview
6+
7+
thirdweb-ai provides powerful blockchain data access and interaction tools through its Insight and Nebula services. This example shows how to use these tools with Google ADK to create an AI assistant that can answer queries about blockchain data, check wallet balances, and more, all through natural language.
8+
9+
## Installation
10+
11+
First, ensure you have Python 3.10+ installed. Then install the required packages:
12+
13+
```bash
14+
# Using pip
15+
pip install "thirdweb-ai[google-adk]"
16+
17+
# Using uv
18+
uv add "thirdweb-ai[google-adk]"
19+
```
20+
21+
## Usage
22+
23+
1. Set your thirdweb API key as an environment variable:
24+
```bash
25+
export THIRDWEB_SECRET_KEY=your_api_key_here
26+
```
27+
28+
2. Run the example:
29+
```bash
30+
python example.py
31+
```
32+
33+
The script demonstrates using the agent to:
34+
- Get details of a transaction
35+
36+
## Customization
37+
38+
You can customize the assistant by modifying the example code:
39+
- Add different types of tools by extending the `tools` list
40+
- Change the model by modifying the `model` configuration
41+
- Add your own queries
42+
43+
## Requirements
44+
45+
See `pyproject.toml` for the full list of dependencies.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import asyncio
2+
import os
3+
4+
from google.adk.agents import LlmAgent
5+
from google.adk.models.lite_llm import LiteLlm
6+
from google.adk.runners import Runner
7+
from google.adk.sessions import InMemorySessionService
8+
from google.genai import types
9+
10+
from thirdweb_ai import Insight
11+
from thirdweb_ai.adapters.google_adk.google_adk import get_google_adk_tools
12+
13+
# Example app configuration
14+
APP_NAME = "thirdweb_insight_app"
15+
USER_ID = "test_user"
16+
SESSION_ID = "test_session"
17+
18+
19+
async def setup_agent() -> Runner:
20+
"""Set up an agent with Thirdweb Insight tools.
21+
22+
Returns:
23+
Runner: Google ADK runner for the agent
24+
"""
25+
# Initialize Insight with secret key
26+
secret_key = os.getenv("THIRDWEB_SECRET_KEY")
27+
if not secret_key:
28+
raise ValueError("THIRDWEB_SECRET_KEY environment variable is required")
29+
30+
# Get Insight tools
31+
insight = Insight(secret_key=secret_key, chain_id=1)
32+
insight_tools = insight.get_tools()
33+
34+
# Convert to Google ADK tools
35+
adk_tools = get_google_adk_tools(insight_tools)
36+
37+
# Print all available tools for debugging
38+
print(f"Available tools ({len(adk_tools)}):")
39+
for tool_count, tool in enumerate(adk_tools, start=1):
40+
print(f"- Tool #{tool_count} {tool.name}")
41+
42+
# Create the agent with the tools
43+
agent = LlmAgent(
44+
model=LiteLlm(model="gpt-4o-mini"),
45+
name="thirdweb_insight_agent",
46+
# Convert BaseTool to the expected type for LlmAgent
47+
tools=adk_tools, # type: ignore
48+
)
49+
50+
# Set up session
51+
session_service = InMemorySessionService()
52+
# We need to create the session but don't need to store it
53+
await session_service.create_session(app_name=APP_NAME, user_id=USER_ID, session_id=SESSION_ID)
54+
55+
# Return runner
56+
return Runner(agent=agent, app_name=APP_NAME, session_service=session_service)
57+
58+
59+
async def call_agent(query: str) -> None:
60+
"""Run a query through the agent.
61+
62+
Args:
63+
query: The query to send to the agent
64+
"""
65+
runner = await setup_agent()
66+
content = types.Content(role="user", parts=[types.Part(text=query)])
67+
events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content)
68+
69+
for event in events:
70+
if (
71+
hasattr(event, "is_final_response")
72+
and event.is_final_response()
73+
and (event.content and hasattr(event.content, "parts") and event.content.parts)
74+
):
75+
final_response = event.content.parts[0].text
76+
print("Agent Response: ", final_response)
77+
78+
79+
if __name__ == "__main__":
80+
test_query = "Find information on transaction: 0x45027cce9d2b990349b4a1e015ec29ca7c7ef15d82487d898f24866a09e8b84c."
81+
asyncio.run(call_agent(test_query))
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[project]
2+
name = "thirdweb-ai-examples-autogen"
3+
version = "0.1.0"
4+
description = "Example of using thirdweb_ai with Google ADK"
5+
authors = [{ name = "thirdweb", email = "[email protected]" }]
6+
requires-python = "~=3.10"
7+
dependencies = [
8+
"thirdweb-ai[google-adk]"
9+
]
10+
11+
[tool.uv]
12+
package = false
13+
14+
[build-system]
15+
requires = ["hatchling"]
16+
build-backend = "hatchling.build"

python/examples/adapter_google_adk/uv.lock

Lines changed: 2699 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python/thirdweb-ai/pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ all = [
2727
"mcp>=1.3.0",
2828
"smolagents>=1.10.0",
2929
"pydantic-ai>=0.0.39",
30+
"google-adk>=1.0.0"
3031
]
3132
langchain = ["langchain-core>=0.3.0"]
3233
goat = ["goat-sdk>=0.1.0"]
@@ -37,6 +38,7 @@ agentkit = ["coinbase-agentkit>=0.1.0,<0.2"]
3738
mcp = ["mcp>=1.3.0"]
3839
smolagents = ["smolagents>=1.10.0"]
3940
pydantic-ai = ["pydantic-ai>=0.0.39"]
41+
google-adk = ["google-adk>=1.0.0", "litellm>=v1.70.0"]
4042

4143
[dependency-groups]
4244
dev = [
@@ -84,6 +86,7 @@ dependencies = [
8486
[tool.uv-dynamic-versioning]
8587
vcs = "git"
8688
style = "semver"
89+
format = "{base}"
8790

8891
[tool.pyright]
8992
include = ["src"]

python/thirdweb-ai/src/thirdweb_ai/_version.py

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
from typing import Any
2+
3+
from google.adk.tools import BaseTool, ToolContext
4+
from google.genai import types
5+
6+
from thirdweb_ai.tools.tool import Tool, ToolSchema
7+
8+
from pydantic import BaseModel
9+
10+
class GoogleAdkTool(BaseTool):
11+
"""Adapter for Thirdweb Tool to Google ADK BaseTool.
12+
13+
This allows Thirdweb tools to be used with Google ADK agents.
14+
"""
15+
16+
def __init__(self, tool: Tool):
17+
"""Initialize the Google ADK Tool wrapper.
18+
19+
Args:
20+
tool: The Thirdweb Tool to wrap
21+
"""
22+
self.tool = tool
23+
super().__init__(
24+
name=tool.name,
25+
description=tool.description,
26+
)
27+
28+
@property
29+
def schema(self) -> ToolSchema:
30+
"""Return the schema for the tool.
31+
32+
Returns:
33+
The schema for the function declaration
34+
"""
35+
return self.tool.schema
36+
37+
def _get_declaration(self) -> types.FunctionDeclaration:
38+
"""Generate the function declaration for Google ADK.
39+
40+
Returns:
41+
A FunctionDeclaration for Google ADK
42+
"""
43+
parameters = self.tool.schema["parameters"]
44+
del parameters["additionalProperties"]
45+
return types.FunctionDeclaration(
46+
name=self.name,
47+
description=self.description,
48+
parameters=parameters,
49+
)
50+
51+
# Override the method with the expected signature based on the error message
52+
# and adapting from the reference implementation
53+
async def run_async(self, args: dict[str, Any], tool_context: ToolContext) -> Any:
54+
"""Execute the tool asynchronously.
55+
56+
This method adapts the Thirdweb tool to work with Google ADK's async execution.
57+
58+
Returns:
59+
The result of running the tool
60+
"""
61+
return self.tool.run_json(args)
62+
63+
64+
def get_google_adk_tools(tools: list[Tool]) -> list[BaseTool]:
65+
"""Convert Thirdweb tools to Google ADK tools.
66+
67+
Args:
68+
tools: List of Thirdweb tools to convert
69+
70+
Returns:
71+
List of Google ADK tools
72+
"""
73+
return [GoogleAdkTool(tool) for tool in tools]

0 commit comments

Comments
 (0)