From 795b67ad23cafa22b7062d25848ca3674649b2b1 Mon Sep 17 00:00:00 2001 From: EfeDurmaz16 Date: Sun, 8 Mar 2026 14:37:23 +0300 Subject: [PATCH 1/5] feat: add Sardis payment tools for ADK agents --- tools/sardis/README.md | 54 +++++++++++++++++++++++++++++++++++++ tools/sardis/__init__.py | 15 +++++++++++ tools/sardis/sardis_tool.py | 32 ++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 tools/sardis/README.md create mode 100644 tools/sardis/__init__.py create mode 100644 tools/sardis/sardis_tool.py diff --git a/tools/sardis/README.md b/tools/sardis/README.md new file mode 100644 index 0000000..2d7f66e --- /dev/null +++ b/tools/sardis/README.md @@ -0,0 +1,54 @@ +# Sardis Payment Tools for Google ADK + +Policy-controlled payments for AI agents built with [Google Agent Development Kit](https://google.github.io/adk-docs/). + +## Installation + +```bash +pip install sardis-adk +``` + +## Setup + +Set your environment variables: + +```bash +export SARDIS_API_KEY="sk_..." +export SARDIS_WALLET_ID="wal_..." +``` + +## Usage + +```python +from google.adk.agents import Agent +from tools.sardis import sardis_pay, sardis_check_balance, sardis_check_policy + +agent = Agent( + model="gemini-2.0-flash", + name="payment_agent", + description="An agent that can make policy-controlled payments", + tools=[sardis_pay, sardis_check_balance, sardis_check_policy], +) +``` + +## Available Tools + +| Tool | Description | +|------|-------------| +| `sardis_pay` | Execute a payment with policy guardrails | +| `sardis_check_balance` | Check wallet balance and spending limits | +| `sardis_check_policy` | Pre-check if a payment would be allowed | + +## Features + +- **Policy guardrails** — spending limits, merchant restrictions, category rules +- **Non-custodial** — MPC wallets, no private keys stored +- **Multi-chain** — Base, Polygon, Ethereum, Arbitrum, Optimism +- **Stablecoin native** — USDC, USDT, EURC, PYUSD +- **Full audit trail** — append-only ledger for compliance + +## Links + +- [Sardis Documentation](https://sardis.sh/docs) +- [sardis-adk on PyPI](https://pypi.org/project/sardis-adk/) +- [GitHub](https://github.com/EfeDurmaz16/sardis) diff --git a/tools/sardis/__init__.py b/tools/sardis/__init__.py new file mode 100644 index 0000000..95f5463 --- /dev/null +++ b/tools/sardis/__init__.py @@ -0,0 +1,15 @@ +"""Sardis payment tools for Google ADK agents.""" + +from sardis_adk.tools import ( + sardis_pay, + sardis_check_balance, + sardis_check_policy, + SARDIS_TOOLS, +) + +__all__ = [ + "sardis_pay", + "sardis_check_balance", + "sardis_check_policy", + "SARDIS_TOOLS", +] diff --git a/tools/sardis/sardis_tool.py b/tools/sardis/sardis_tool.py new file mode 100644 index 0000000..abce6f0 --- /dev/null +++ b/tools/sardis/sardis_tool.py @@ -0,0 +1,32 @@ +"""Sardis payment tool for Google Agent Development Kit. + +This tool enables ADK agents to make policy-controlled payments through +Sardis non-custodial MPC wallets. + +Installation: + pip install sardis-adk + +Usage: + from tools.sardis import sardis_pay, sardis_check_balance + + # Use in an ADK agent + agent = Agent( + model="gemini-2.0-flash", + name="payment_agent", + tools=[sardis_pay, sardis_check_balance], + ) +""" + +from sardis_adk.tools import ( + sardis_pay, + sardis_check_balance, + sardis_check_policy, + SARDIS_TOOLS, +) + +__all__ = [ + "sardis_pay", + "sardis_check_balance", + "sardis_check_policy", + "SARDIS_TOOLS", +] From baacc4059d5c21292ac9c4943c05811bba2166af Mon Sep 17 00:00:00 2001 From: EfeDurmaz16 Date: Sun, 8 Mar 2026 14:44:48 +0300 Subject: [PATCH 2/5] fix: restructure to match monorepo layout with Apache 2.0 headers and tests --- .../tools}/sardis/README.md | 0 src/google/adk_community/tools/__init__.py | 13 ++ .../adk_community/tools/sardis/__init__.py | 25 +++ .../tools/sardis/sardis_tools.py | 168 ++++++++++++++++++ tests/unittests/tools/__init__.py | 13 ++ tests/unittests/tools/sardis/__init__.py | 13 ++ .../tools/sardis/test_sardis_tools.py | 42 +++++ tools/sardis/__init__.py | 15 -- tools/sardis/sardis_tool.py | 32 ---- 9 files changed, 274 insertions(+), 47 deletions(-) rename {tools => contributing/tools}/sardis/README.md (100%) create mode 100644 src/google/adk_community/tools/__init__.py create mode 100644 src/google/adk_community/tools/sardis/__init__.py create mode 100644 src/google/adk_community/tools/sardis/sardis_tools.py create mode 100644 tests/unittests/tools/__init__.py create mode 100644 tests/unittests/tools/sardis/__init__.py create mode 100644 tests/unittests/tools/sardis/test_sardis_tools.py delete mode 100644 tools/sardis/__init__.py delete mode 100644 tools/sardis/sardis_tool.py diff --git a/tools/sardis/README.md b/contributing/tools/sardis/README.md similarity index 100% rename from tools/sardis/README.md rename to contributing/tools/sardis/README.md diff --git a/src/google/adk_community/tools/__init__.py b/src/google/adk_community/tools/__init__.py new file mode 100644 index 0000000..0a2669d --- /dev/null +++ b/src/google/adk_community/tools/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/src/google/adk_community/tools/sardis/__init__.py b/src/google/adk_community/tools/sardis/__init__.py new file mode 100644 index 0000000..6766781 --- /dev/null +++ b/src/google/adk_community/tools/sardis/__init__.py @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Sardis payment tools for Google ADK - policy-controlled AI agent payments.""" + +from .sardis_tools import sardis_check_balance +from .sardis_tools import sardis_check_policy +from .sardis_tools import sardis_pay + +__all__ = [ + "sardis_pay", + "sardis_check_balance", + "sardis_check_policy", +] diff --git a/src/google/adk_community/tools/sardis/sardis_tools.py b/src/google/adk_community/tools/sardis/sardis_tools.py new file mode 100644 index 0000000..941add4 --- /dev/null +++ b/src/google/adk_community/tools/sardis/sardis_tools.py @@ -0,0 +1,168 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Sardis payment tools for Google Agent Development Kit. + +These tools enable ADK agents to make policy-controlled payments through +Sardis non-custodial MPC wallets. + +Installation: + pip install google-adk-community sardis-adk + +Usage: + from google.adk.agents import Agent + from google.adk_community.tools.sardis import sardis_pay, sardis_check_balance + + agent = Agent( + model="gemini-2.0-flash", + name="payment_agent", + tools=[sardis_pay, sardis_check_balance], + ) +""" + +from __future__ import annotations + +import logging +import os +from typing import Optional + +logger = logging.getLogger("google_adk." + __name__) + + +def sardis_pay( + recipient: str, + amount: str, + token: str = "USDC", + chain: str = "base", + memo: Optional[str] = None, +) -> dict: + """Execute a policy-controlled payment via Sardis. + + Args: + recipient: Destination wallet address or Sardis wallet ID. + amount: Amount to send as a decimal string (e.g. "10.00"). + token: Token symbol (USDC, EURC, USDT, PYUSD). Default: USDC. + chain: Chain to execute on (base, polygon, ethereum, arbitrum, + optimism). Default: base. + memo: Optional human-readable memo for the payment. + + Returns: + A dict with keys: status, transaction_id, tx_hash, amount, token, chain. + """ + try: + from sardis import SardisClient + except ImportError: + return { + "status": "error", + "error": "sardis package required. Install with: pip install sardis", + } + + api_key = os.environ.get("SARDIS_API_KEY") + wallet_id = os.environ.get("SARDIS_WALLET_ID") + if not api_key: + return { + "status": "error", + "error": "SARDIS_API_KEY environment variable not set.", + } + if not wallet_id: + return { + "status": "error", + "error": "SARDIS_WALLET_ID environment variable not set.", + } + + client = SardisClient(api_key=api_key) + result = client.payments.send( + wallet_id, to=recipient, amount=float(amount), token=token, + purpose=memo or "Payment", + ) + return { + "status": "APPROVED" if result.success else "BLOCKED", + "transaction_id": getattr(result, "tx_id", ""), + "message": getattr(result, "message", ""), + "amount": amount, + "token": token, + "chain": chain, + } + + +def sardis_check_balance( + token: str = "USDC", +) -> dict: + """Check the balance of a Sardis wallet. + + Args: + token: Token symbol to check (e.g. "USDC"). Default: USDC. + + Returns: + A dict with keys: balance, remaining, token. + """ + try: + from sardis import SardisClient + except ImportError: + return {"status": "error", "error": "sardis package required."} + + api_key = os.environ.get("SARDIS_API_KEY") + wallet_id = os.environ.get("SARDIS_WALLET_ID") + if not api_key or not wallet_id: + return {"status": "error", "error": "SARDIS_API_KEY and SARDIS_WALLET_ID required."} + + client = SardisClient(api_key=api_key) + balance = client.wallets.get_balance(wallet_id, token=token) + return { + "balance": str(balance.balance), + "remaining": str(balance.remaining), + "token": token, + } + + +def sardis_check_policy( + amount: str, + merchant: str, +) -> dict: + """Check if a payment would be allowed by spending policy. + + Args: + amount: Amount to check as a decimal string (e.g. "250.00"). + merchant: Merchant or recipient to check against policy rules. + + Returns: + A dict with keys: allowed (bool), reason (str). + """ + try: + from sardis import SardisClient + except ImportError: + return {"status": "error", "error": "sardis package required."} + + api_key = os.environ.get("SARDIS_API_KEY") + wallet_id = os.environ.get("SARDIS_WALLET_ID") + if not api_key or not wallet_id: + return {"status": "error", "error": "SARDIS_API_KEY and SARDIS_WALLET_ID required."} + + client = SardisClient(api_key=api_key) + balance = client.wallets.get_balance(wallet_id) + amt = float(amount) + if amt > balance.remaining: + return { + "allowed": False, + "reason": f"Amount ${amt} exceeds remaining limit ${balance.remaining}", + } + if amt > balance.balance: + return { + "allowed": False, + "reason": f"Amount ${amt} exceeds balance ${balance.balance}", + } + return { + "allowed": True, + "reason": f"Payment of ${amt} to {merchant} would be allowed", + } diff --git a/tests/unittests/tools/__init__.py b/tests/unittests/tools/__init__.py new file mode 100644 index 0000000..0a2669d --- /dev/null +++ b/tests/unittests/tools/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/unittests/tools/sardis/__init__.py b/tests/unittests/tools/sardis/__init__.py new file mode 100644 index 0000000..0a2669d --- /dev/null +++ b/tests/unittests/tools/sardis/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/unittests/tools/sardis/test_sardis_tools.py b/tests/unittests/tools/sardis/test_sardis_tools.py new file mode 100644 index 0000000..81055cb --- /dev/null +++ b/tests/unittests/tools/sardis/test_sardis_tools.py @@ -0,0 +1,42 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests for Sardis payment tools.""" + +from unittest.mock import MagicMock, patch + +from google.adk_community.tools.sardis.sardis_tools import ( + sardis_check_balance, + sardis_check_policy, + sardis_pay, +) + + +def test_sardis_pay_missing_api_key(monkeypatch): + monkeypatch.delenv("SARDIS_API_KEY", raising=False) + monkeypatch.delenv("SARDIS_WALLET_ID", raising=False) + result = sardis_pay(recipient="0xABC", amount="10.00") + assert result["status"] == "error" + + +def test_sardis_check_balance_missing_key(monkeypatch): + monkeypatch.delenv("SARDIS_API_KEY", raising=False) + result = sardis_check_balance() + assert result["status"] == "error" + + +def test_sardis_check_policy_missing_key(monkeypatch): + monkeypatch.delenv("SARDIS_API_KEY", raising=False) + result = sardis_check_policy(amount="100.00", merchant="openai") + assert result["status"] == "error" diff --git a/tools/sardis/__init__.py b/tools/sardis/__init__.py deleted file mode 100644 index 95f5463..0000000 --- a/tools/sardis/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Sardis payment tools for Google ADK agents.""" - -from sardis_adk.tools import ( - sardis_pay, - sardis_check_balance, - sardis_check_policy, - SARDIS_TOOLS, -) - -__all__ = [ - "sardis_pay", - "sardis_check_balance", - "sardis_check_policy", - "SARDIS_TOOLS", -] diff --git a/tools/sardis/sardis_tool.py b/tools/sardis/sardis_tool.py deleted file mode 100644 index abce6f0..0000000 --- a/tools/sardis/sardis_tool.py +++ /dev/null @@ -1,32 +0,0 @@ -"""Sardis payment tool for Google Agent Development Kit. - -This tool enables ADK agents to make policy-controlled payments through -Sardis non-custodial MPC wallets. - -Installation: - pip install sardis-adk - -Usage: - from tools.sardis import sardis_pay, sardis_check_balance - - # Use in an ADK agent - agent = Agent( - model="gemini-2.0-flash", - name="payment_agent", - tools=[sardis_pay, sardis_check_balance], - ) -""" - -from sardis_adk.tools import ( - sardis_pay, - sardis_check_balance, - sardis_check_policy, - SARDIS_TOOLS, -) - -__all__ = [ - "sardis_pay", - "sardis_check_balance", - "sardis_check_policy", - "SARDIS_TOOLS", -] From 9e391d79aa293f9cab129737355ad5c4261170a2 Mon Sep 17 00:00:00 2001 From: EfeDurmaz16 Date: Mon, 9 Mar 2026 09:58:10 +0300 Subject: [PATCH 3/5] fix: address review feedback on code examples and import paths - Include sardis_check_policy in all usage examples for consistency - Fix import path in README from tools.sardis to google.adk_community.tools.sardis - Update installation command to reflect monorepo package structure Co-Authored-By: Claude Opus 4.6 --- contributing/tools/sardis/README.md | 6 ++++-- src/google/adk_community/tools/sardis/sardis_tools.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/contributing/tools/sardis/README.md b/contributing/tools/sardis/README.md index 2d7f66e..0eacd90 100644 --- a/contributing/tools/sardis/README.md +++ b/contributing/tools/sardis/README.md @@ -5,7 +5,7 @@ Policy-controlled payments for AI agents built with [Google Agent Development Ki ## Installation ```bash -pip install sardis-adk +pip install google-adk-community sardis ``` ## Setup @@ -21,7 +21,9 @@ export SARDIS_WALLET_ID="wal_..." ```python from google.adk.agents import Agent -from tools.sardis import sardis_pay, sardis_check_balance, sardis_check_policy +from google.adk_community.tools.sardis import ( + sardis_pay, sardis_check_balance, sardis_check_policy, +) agent = Agent( model="gemini-2.0-flash", diff --git a/src/google/adk_community/tools/sardis/sardis_tools.py b/src/google/adk_community/tools/sardis/sardis_tools.py index 941add4..f159008 100644 --- a/src/google/adk_community/tools/sardis/sardis_tools.py +++ b/src/google/adk_community/tools/sardis/sardis_tools.py @@ -22,12 +22,14 @@ Usage: from google.adk.agents import Agent - from google.adk_community.tools.sardis import sardis_pay, sardis_check_balance + from google.adk_community.tools.sardis import ( + sardis_pay, sardis_check_balance, sardis_check_policy, + ) agent = Agent( model="gemini-2.0-flash", name="payment_agent", - tools=[sardis_pay, sardis_check_balance], + tools=[sardis_pay, sardis_check_balance, sardis_check_policy], ) """ From 8813b6b4f8e19dc1f6555f6b3ac18b0f616d8e80 Mon Sep 17 00:00:00 2001 From: EfeDurmaz16 Date: Tue, 10 Mar 2026 02:19:09 +0300 Subject: [PATCH 4/5] fix: address Gemini Code Assist review feedback - Fix model name to `gemini-2.0-flash-001` in README.md and sardis_tools.py docstring (gemini-2.0-flash is not a valid model ID) - Fix install command in sardis_tools.py docstring (`sardis` not `sardis-adk`) - sardis_tools.py is kept as-is since it contains the actual tool implementations while __init__.py re-exports them (standard Python package pattern, not redundant) Co-Authored-By: Claude Opus 4.6 --- contributing/tools/sardis/README.md | 2 +- src/google/adk_community/tools/sardis/sardis_tools.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contributing/tools/sardis/README.md b/contributing/tools/sardis/README.md index 0eacd90..4d354cd 100644 --- a/contributing/tools/sardis/README.md +++ b/contributing/tools/sardis/README.md @@ -26,7 +26,7 @@ from google.adk_community.tools.sardis import ( ) agent = Agent( - model="gemini-2.0-flash", + model="gemini-2.0-flash-001", name="payment_agent", description="An agent that can make policy-controlled payments", tools=[sardis_pay, sardis_check_balance, sardis_check_policy], diff --git a/src/google/adk_community/tools/sardis/sardis_tools.py b/src/google/adk_community/tools/sardis/sardis_tools.py index f159008..f606bef 100644 --- a/src/google/adk_community/tools/sardis/sardis_tools.py +++ b/src/google/adk_community/tools/sardis/sardis_tools.py @@ -18,7 +18,7 @@ Sardis non-custodial MPC wallets. Installation: - pip install google-adk-community sardis-adk + pip install google-adk-community sardis Usage: from google.adk.agents import Agent @@ -27,7 +27,7 @@ ) agent = Agent( - model="gemini-2.0-flash", + model="gemini-2.0-flash-001", name="payment_agent", tools=[sardis_pay, sardis_check_balance, sardis_check_policy], ) From 611b73bab0c26eb03f70f088134040346e39d036 Mon Sep 17 00:00:00 2001 From: EfeDurmaz16 Date: Tue, 10 Mar 2026 02:21:09 +0300 Subject: [PATCH 5/5] fix: use canonical model name gemini-2.0-flash in examples Address review feedback: drop the -001 suffix from model name in README and docstring to use the canonical short form. Co-Authored-By: Claude Opus 4.6 --- contributing/tools/sardis/README.md | 2 +- src/google/adk_community/tools/sardis/sardis_tools.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contributing/tools/sardis/README.md b/contributing/tools/sardis/README.md index 4d354cd..0eacd90 100644 --- a/contributing/tools/sardis/README.md +++ b/contributing/tools/sardis/README.md @@ -26,7 +26,7 @@ from google.adk_community.tools.sardis import ( ) agent = Agent( - model="gemini-2.0-flash-001", + model="gemini-2.0-flash", name="payment_agent", description="An agent that can make policy-controlled payments", tools=[sardis_pay, sardis_check_balance, sardis_check_policy], diff --git a/src/google/adk_community/tools/sardis/sardis_tools.py b/src/google/adk_community/tools/sardis/sardis_tools.py index f606bef..8805134 100644 --- a/src/google/adk_community/tools/sardis/sardis_tools.py +++ b/src/google/adk_community/tools/sardis/sardis_tools.py @@ -27,7 +27,7 @@ ) agent = Agent( - model="gemini-2.0-flash-001", + model="gemini-2.0-flash", name="payment_agent", tools=[sardis_pay, sardis_check_balance, sardis_check_policy], )