Skip to content

Commit

Permalink
feat: Add Python jsonrpc plugin (#224)
Browse files Browse the repository at this point in the history
* feat: Add Python jsonrpc plugin

- Add jsonrpc plugin Python implementation
- Match TypeScript plugin functionality
- Include JSON-RPC 2.0 protocol support
- Add async implementation using aiohttp
- Add plugin documentation

Co-Authored-By: Agus Armellini Fischer <[email protected]>

* Delete python/src/plugins/jsonrpc/goat_plugins/__init__.py

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Agus Armellini Fischer <[email protected]>
Co-authored-by: Agus <[email protected]>
  • Loading branch information
3 people authored Jan 15, 2025
1 parent 83c3500 commit 035fe58
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 0 deletions.
42 changes: 42 additions & 0 deletions python/src/plugins/jsonrpc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# GOAT SDK JSON-RPC Plugin

A plugin for the GOAT SDK that enables making JSON-RPC calls to any compatible endpoint.

## Features

- Make JSON-RPC calls to any compatible endpoint
- Supports standard JSON-RPC 2.0 protocol
- Fully async implementation using aiohttp
- Integrates seamlessly with GOAT SDK and LangChain

## Installation

```bash
poetry add goat-sdk-plugin-jsonrpc
```

## Usage

```python
from goat_plugins.jsonrpc import jsonrpc, JSONRpcPluginOptions

# Initialize the plugin with your RPC endpoint
tools = get_on_chain_tools(
wallet=wallet_client,
plugins=[
jsonrpc(options=JSONRpcPluginOptions(endpoint="your-rpc-endpoint"))
],
)

# Example JSON-RPC call
response = await tools.JSONRpcFunc({
"method": "eth_blockNumber",
"params": [],
"id": 1,
"jsonrpc": "2.0"
})
```

## License

This project is licensed under the terms of the MIT license.
21 changes: 21 additions & 0 deletions python/src/plugins/jsonrpc/goat_plugins/jsonrpc/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from dataclasses import dataclass

from goat.classes.plugin_base import PluginBase
from .service import JSONRpcService


@dataclass
class JSONRpcPluginOptions:
endpoint: str


class JSONRpcPlugin(PluginBase):
def __init__(self, options: JSONRpcPluginOptions):
super().__init__("jsonrpc", [JSONRpcService(options.endpoint)])

def supports_chain(self, chain) -> bool:
return True


def jsonrpc(options: JSONRpcPluginOptions) -> JSONRpcPlugin:
return JSONRpcPlugin(options)
20 changes: 20 additions & 0 deletions python/src/plugins/jsonrpc/goat_plugins/jsonrpc/parameters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from pydantic import BaseModel, Field
from typing import List

class JSONRpcBodyParameters(BaseModel):
method: str = Field(
...,
description="A string containing the name of the method to be invoked"
)
params: List[str] = Field(
...,
description="A structured value that holds the parameter value to be used during the invokation of the method"
)
id: int = Field(
...,
description="An identifier established by the client that must contain a string number or null"
)
jsonrpc: str = Field(
...,
description="A string that specifies the version of the JSON-RPC protocol must be exactly '2.0'"
)
22 changes: 22 additions & 0 deletions python/src/plugins/jsonrpc/goat_plugins/jsonrpc/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import aiohttp
from goat.decorators.tool import Tool
from .parameters import JSONRpcBodyParameters

class JSONRpcService:
def __init__(self, endpoint: str):
self.endpoint = endpoint

@Tool({
"description": "Make a remote procedure call to a JSON RPC endpoint",
"parameters_schema": JSONRpcBodyParameters
})
async def JSONRpcFunc(self, parameters: dict):
"""Makes a POST request to the configured endpoint with the required JSON-RPC parameters."""
try:
async with aiohttp.ClientSession() as session:
async with session.post(self.endpoint, json=parameters) as response:
if not response.ok:
raise Exception(f"HTTP error! status: {response.status}, body: {await response.text()}")
return await response.json()
except Exception as e:
raise Exception(f"Failed to call {self.endpoint}: {e}")
43 changes: 43 additions & 0 deletions python/src/plugins/jsonrpc/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[tool.poetry]
name = "goat-sdk-plugin-jsonrpc"
version = "0.1.1"
description = "Goat plugin for JSON-RPC"
authors = ["Andrea Villa <[email protected]>"]
readme = "README.md"
keywords = ["goat", "sdk", "web3", "agents", "ai"]
homepage = "https://ohmygoat.dev/"
repository = "https://github.com/goat-sdk/goat"
packages = [
{ include = "goat_plugins" },
]

[tool.poetry.dependencies]
python = "^3.10"
aiohttp = "^3.8.6"
goat-sdk = "^0.1.1"

[tool.poetry.group.test.dependencies]
pytest = "^8.3.4"
pytest-asyncio = "^0.25.0"

[tool.poetry.urls]
"Bug Tracker" = "https://github.com/goat-sdk/goat/issues"

[tool.pytest.ini_options]
addopts = [
"--import-mode=importlib",
]
pythonpath = "src"
asyncio_default_fixture_loop_scope = "function"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.poetry.group.dev.dependencies]
ruff = "^0.8.6"
goat-sdk = { path = "../../goat-sdk", develop = true }

[tool.ruff]
line-length = 120
target-version = "py312"

0 comments on commit 035fe58

Please sign in to comment.