-
Notifications
You must be signed in to change notification settings - Fork 163
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1. core types 2. web3.py wallet client 3. langchain tool adapter 4. langchain evm web3.py example
- Loading branch information
Showing
31 changed files
with
5,221 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
wheels/ | ||
share/python-wheels/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
MANIFEST | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.nox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*.cover | ||
*.py,cover | ||
.hypothesis/ | ||
.pytest_cache/ | ||
cover/ | ||
|
||
# Environment variables | ||
.env | ||
.env.local | ||
.env.*.local | ||
.venv | ||
venv/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Goat 🐐 - Python | ||
|
||
[Docs](https://ohmygoat.dev) | [Examples](https://github.com/goat-sdk/goat/tree/main/typescript/examples) | [Discord](https://discord.gg/goat-sdk) | ||
|
||
## Development | ||
|
||
1. Clone the repo | ||
2. Install the dependencies: `poetry install` | ||
3. Build the packages: `poetry build` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Examples | ||
|
||
## Langchain | ||
|
||
### EVM | ||
- [web3.py](https://github.com/goat-sdk/goat/tree/main/python/examples/langchain/web3) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
OPENAI_API_KEY= | ||
WALLET_PRIVATE_KEY= | ||
RPC_PROVIDER_URL= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Langchain with web3.py Example | ||
|
||
## Setup | ||
|
||
Copy the `.env.template` and populate with your values. | ||
|
||
``` | ||
cp .env.template .env | ||
``` | ||
|
||
## Usage | ||
|
||
``` | ||
poetry run python example.py | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import asyncio | ||
import os | ||
import logging | ||
from langchain_openai import OpenAI | ||
from langchain import hub as prompts | ||
from langchain.agents import AgentExecutor, create_structured_chat_agent | ||
from web3 import Web3 | ||
|
||
from goat_sdk.adapters.langchain import getOnChainTools | ||
from goat_sdk.wallets.web3 import Web3EVMWalletClient | ||
|
||
logging.basicConfig( | ||
format="%(asctime)s %(levelname)s: %(message)s", level=logging.DEBUG | ||
) | ||
|
||
|
||
async def main(): | ||
logger = logging.getLogger(__name__) | ||
chain = "sepolia" | ||
prompt = prompts.pull("hwchase17/structured-chat-agent") | ||
llm = OpenAI(model="gpt-4o-mini") | ||
|
||
w3 = Web3( | ||
Web3.HTTPProvider( | ||
# TODO: Export RPC_PROVIDER_URL | ||
"https://eth-%s.g.alchemy.com/v2/%s" | ||
% (chain, os.environ["ALCHEMY_API_KEY"]) | ||
) | ||
) | ||
|
||
walletClient = Web3EVMWalletClient(w3) | ||
|
||
tools = await getOnChainTools(wallet=walletClient, plugins=[]) | ||
logger.debug("Tools: %s", tools) | ||
agent = create_structured_chat_agent(llm, tools, prompt) | ||
logger.debug("Agent: %s", agent) | ||
|
||
logger.debug("Create an agent executor by passing in the agent and tools") | ||
agent_executor = AgentExecutor( | ||
agent=agent, | ||
tools=tools, | ||
verbose=True, | ||
handle_parsing_errors=True, | ||
) | ||
|
||
response = agent_executor.invoke({"input": "Get my balance in USDC"}) | ||
logger.info("Agent response: %s", response) | ||
|
||
|
||
if __name__ == "__main__": | ||
loop = asyncio.get_event_loop() | ||
loop.run_until_complete(main()) |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
[tool.poetry] | ||
name = "goat-examples-langchain-web3" | ||
version = "0.1.0" | ||
description = "" | ||
authors = ["Agustin Armellini Fischer <[email protected]>"] | ||
license = "MIT" | ||
readme = "README.md" | ||
|
||
[tool.poetry.dependencies] | ||
python = "^3.13" | ||
langchain-openai = "^0.2.11" | ||
langchain = "^0.3.10" | ||
goat_sdk = {path = "../../../"} | ||
pydantic = "^2.10.3" | ||
|
||
[build-system] | ||
requires = ["poetry-core"] | ||
build-backend = "poetry.core.masonry.api" |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from goat_sdk.adapters.langchain.tools import ( | ||
getOnChainTools, | ||
) | ||
|
||
|
||
__all__ = [ | ||
"getOnChainTools" | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from typing import List, Optional, Union | ||
from goat_sdk.core.plugins import Plugin | ||
from goat_sdk.core import get_tools | ||
from goat_sdk.core.wallets import WalletClient | ||
from langchain_core.tools import Tool | ||
|
||
|
||
async def getOnChainTools[TWalletClient: WalletClient]( | ||
wallet: TWalletClient, | ||
plugins: Optional[List[Union[Plugin[TWalletClient], Plugin[WalletClient]]]] = [], | ||
wordForTool: Optional[str] = "", | ||
): | ||
tools = await get_tools(wallet, plugins) | ||
return [ | ||
Tool( | ||
name=t.name, | ||
description=t.description, | ||
func=t.method, | ||
args_schema=t.parameters, | ||
) | ||
for t in tools | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from goat_sdk.core.core import ( | ||
get_tools, | ||
) | ||
|
||
|
||
__all__ = [ | ||
"get_tools" | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import logging | ||
import re | ||
from typing import List, Optional, Union | ||
|
||
from goat_sdk.core.plugins import Plugin | ||
from goat_sdk.core.tools import DeferredTool | ||
from goat_sdk.core.wallets import WalletClient, Chain, is_evm_chain, is_solana_chain | ||
from goat_sdk.core.evm import deferredEVMCoreTools | ||
|
||
|
||
async def filter_plugin_tools[TWalletClient: WalletClient]( | ||
plugin: Plugin[TWalletClient], | ||
chain: Chain, | ||
supportsSmartWallets: Optional[bool] = False, | ||
) -> List[DeferredTool[TWalletClient]]: | ||
if not plugin.supports_chain(chain): | ||
logging.warning( | ||
"Plugin %s does not support chain %s. Skipping.", plugin.name, chain.type | ||
) | ||
return [] | ||
if supportsSmartWallets and not plugin.supports_smart_wallets(): | ||
logging.warning( | ||
"Plugin %s does not support smart wallets. Skipping.", plugin.name | ||
) | ||
return [] | ||
tools = await plugin.get_tools(chain) | ||
|
||
if len(tools) == 0: | ||
logging.warning("Plugin %s returned no tools. Skipping.", plugin.name) | ||
|
||
return tools | ||
|
||
|
||
def replace_tool_placeholder(template: str, wordForTool: Optional[str] = "tool"): | ||
""" | ||
Replace the placeholder '{{ tool }}' in the template with the provided word. | ||
:param template: The input template string with the placeholder. | ||
:param word_for_tool: The word to replace the placeholder with. Defaults to "tool". | ||
:return: The template with the placeholder replaced by the word_for_tool. | ||
""" | ||
# Use a regular expression to find and replace the placeholder '{{ tool }}' | ||
placeholder_regex = r"\{\{\s*tool\s*\}\}" | ||
return re.sub(placeholder_regex, wordForTool, template) | ||
|
||
|
||
async def get_deferred_tools[TWalletClient: WalletClient]( | ||
chain: Chain, | ||
plugins: Optional[List[Union[Plugin[TWalletClient], Plugin[WalletClient]]]] = [], | ||
supportsSmartWallets: Optional[bool] = False, | ||
wordForTool: Optional[str] = "", | ||
) -> List[DeferredTool[TWalletClient]]: | ||
tools: List[DeferredTool[TWalletClient]] = [] | ||
if is_evm_chain(chain): | ||
tools += deferredEVMCoreTools | ||
elif is_solana_chain(chain): | ||
pass | ||
else: | ||
raise ValueError("Unsupported chain type: %s" % chain.type) | ||
|
||
for plugin in plugins: | ||
tools += await filter_plugin_tools(plugin, chain, supportsSmartWallets) | ||
|
||
for tool in tools: | ||
tool.description = replace_tool_placeholder(tool.description, wordForTool) | ||
|
||
return tools | ||
|
||
|
||
async def get_tools[TWalletClient: WalletClient]( | ||
wallet: TWalletClient, | ||
plugins: Optional[List[Union[Plugin[TWalletClient], Plugin[WalletClient]]]] = [], | ||
wordForTool: Optional[str] = "", | ||
) -> List[DeferredTool[TWalletClient]]: | ||
chain = wallet.get_chain() | ||
tools = await get_deferred_tools( | ||
chain, | ||
plugins, | ||
# TODO: isEVMSmartWalletClient(wallet) | ||
supportsSmartWallets=False, | ||
wordForTool=wordForTool, | ||
) | ||
for tool in tools: | ||
tool.method = lambda parameters: tool.method(wallet, parameters) | ||
return tools |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from goat_sdk.core.evm.tools import ( | ||
deferredEVMCoreTools, | ||
) | ||
|
||
|
||
__all__ = [ | ||
"deferredEVMCoreTools", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from typing import Dict, Optional | ||
|
||
from goat_sdk.core.wallets import EVMWalletClient | ||
|
||
|
||
def get_address(walletClient: EVMWalletClient, params: Dict) -> str: | ||
return walletClient.get_address() | ||
|
||
|
||
async def get_balance( | ||
walletClient: EVMWalletClient, params: Optional[Dict] = {} | ||
) -> str: | ||
try: | ||
addr = params["address"] if "address" in params else get_address(walletClient) | ||
resAddr = await walletClient.resolve_address(addr) | ||
raw_balance = await walletClient.balance_of(resAddr) | ||
return str(raw_balance.value // raw_balance.decimals) | ||
except Exception as e: | ||
raise ("Failed to fetch balance", e) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from typing import Optional | ||
from pydantic import BaseModel, Field | ||
|
||
|
||
class GetETHBalanceParametersSchema(BaseModel): | ||
address: Optional[str] = Field( | ||
default="", | ||
description="The address to get the balance of, defaults to the address of the wallet", | ||
) | ||
|
||
class GetAddressParametersSchema(BaseModel): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from typing import List | ||
|
||
from goat_sdk.core.evm.methods import get_address, get_balance | ||
from goat_sdk.core.evm.parameters import GetAddressParametersSchema, GetETHBalanceParametersSchema | ||
from goat_sdk.core.tools import DeferredTool | ||
from goat_sdk.core.wallets import EVMWalletClient | ||
|
||
|
||
deferredEVMCoreTools: List[DeferredTool[EVMWalletClient]] = [ | ||
DeferredTool[EVMWalletClient]( | ||
**dict( | ||
{ | ||
"name": "get_address", | ||
"description": "This {{tool}} returns the address of the EVM wallet.", | ||
"parameters": GetAddressParametersSchema, | ||
"method": get_address, | ||
} | ||
) | ||
), | ||
DeferredTool[EVMWalletClient]( | ||
**dict( | ||
{ | ||
"name": "get_eth_balance", | ||
"description": "This {{tool}} returns the ETH balance of an EVM wallet.", | ||
"parameters": GetETHBalanceParametersSchema, | ||
"method": get_balance, | ||
} | ||
) | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from goat_sdk.core.plugins.plugins import ( | ||
Plugin, | ||
) | ||
|
||
|
||
__all__ = [ | ||
"Plugin", | ||
] |
Oops, something went wrong.