Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# ⛽ Fuel Agent Kit

<p align="center">
<img src="https://img.shields.io/badge/Fuel-Network-000000?style=for-the-badge&logo=fuel" alt="Fuel Base Badge" />
<img src="https://img.shields.io/npm/v/fuel-agent-kit?style=for-the-badge&logo=npm" alt="NPM Version" />
<img src="https://img.shields.io/badge/LangChain-Integration-blue?style=for-the-badge&logo=langchain" alt="Langchain Integration" />
</p>

**Fuel Agent Kit** is an open-source AI agent toolkit designed specifically for the [Fuel](https://fuel.network) network. It enables AI agents (powered by LangChain, OpenAI, Anthropic, or Google GenAI) to autonomously interact with the Fuel blockchain, execute transfers, trade on decentralized exchanges (Mira DEX), and fetch real-time Pyth network data.

---

## ⚡ Features

* **AI-Ready Infrastructure:** First-class integration with `@langchain/core`. You can plug these tools directly into your `AgentExecutor`.
* **Asset Transfers:** Secure and autonomous `transfer` functionalities built on top of the official `fuels` SDK.
* **DeFi Integrations:** Pre-built modules to interact with **Mira Dex** (`mira-dex-ts`) and fetch accurate oracle feeds via **Pyth Network** (`@pythnetwork/pyth-fuel-js`).
* **Swaylend Operations:** Supports interactions with lending protocols.

---

## 📦 Installation

To use `fuel-agent-kit` in your project, install it alongside its peer dependency (`fuels`) and your LLM connector of choice.

```bash
npm install fuel-agent-kit fuels
```

If you are using LangChain and OpenAI:
```bash
npm install langchain @langchain/openai
```

---

## 🚀 Quickstart

Below is a minimal example demonstrating how to initialize the `FuelAgent` and utilize its built-in tools.

```typescript
import { FuelAgent } from "fuel-agent-kit";
import { ChatOpenAI } from "@langchain/openai";
import { AgentExecutor, createReactAgent } from "langchain/agents";
import { Provider, Wallet } from "fuels";

async function main() {
// 1. Initialize the Fuel Wallet and Provider
const provider = await Provider.create("https://mainnet.fuel.network/graphql");
const wallet = Wallet.fromPrivateKey(process.env.FUEL_PRIVATE_KEY!, provider);

// 2. Initialize the Fuel Agent Kit
const agentKit = new FuelAgent({
wallet: wallet
});

// 3. Extract the LangChain-compatible tools
const tools = agentKit.getTools();

// 4. Set up your LangChain standard agent
const llm = new ChatOpenAI({ temperature: 0 });
const agent = await createReactAgent({ llm, tools, prompt });
const executor = new AgentExecutor({ agent, tools });

// 5. Run it autonomously
const result = await executor.invoke({
messages: [
{ role: "user", content: "Transfer 0.1 ETH to fuel1... address." }
]
});

console.log(result.messages);
}

main();
```

---

## 🛠️ Architecture

The toolkit provides highly modular actions under `src/`:
- `FuelAgent.ts`: The central orchestrator uniting all available sub-modules.
- `/transfers`: Logic handling native asset and token transfers.
- `/mira`: Decentralized exchange interactions.
- `/swaylend`: Lending protocol interactions.
- `/read`: Data inspection (balances, chain-state, Pyth oracle).

---

## 💻 Contributing

We welcome community contributions! Please read our [CHANGELOG.md](CHANGELOG.md) for versioning history.

1. Fork the Project
2. Create your Feature Branch (`git checkout -b dev/AmazingFeature`)
3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
4. Verify by running `npm run ci` to execute linters and typings checks.
5. Push to the Branch (`git push origin dev/AmazingFeature`)
6. Open a Pull Request

---

## 📄 License

Distributed under the MIT License. See `LICENSE` for more information.
56 changes: 56 additions & 0 deletions python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# ⛽ Fuel Agent Kit (Python)

**Fuel Agent Kit** is an open-source AI agent toolkit designed specifically for the [Fuel](https://fuel.network) network. It enables AI agents (powered by LangChain, OpenAI, Anthropic, or Google GenAI) to autonomously interact with the Fuel blockchain, execute transfers, trade on decentralized exchanges (Mira DEX), and fetch real-time data.

## ⚡ Features

* **AI-Ready Infrastructure:** First-class integration with `langchain`.
* **Asset Transfers:** Secure and autonomous `transfer` functionalities.
* **DeFi Integrations:** Pre-built modules to interact with **Mira Dex** and **Swaylend**.

## 📦 Installation

To use `fuel-agent-kit` in your python project:

```bash
pip install fuel-agent-kit fuels
pip install langchain langchain-openai pydantic requests
```

## 🚀 Quickstart

Below is a minimal example demonstrating how to initialize the `FuelAgent` and utilize its built-in tools.

```python
import os
import asyncio
from fuel_agent_kit import FuelAgent, FuelAgentConfig

async def main():
config = FuelAgentConfig(
wallet_private_key=os.environ.get("FUEL_PRIVATE_KEY"),
model="gpt-4-turbo-preview",
open_ai_api_key=os.environ.get("OPENAI_API_KEY")
)

agent = FuelAgent(config)

result = await agent.execute("Transfer 0.1 ETH to fuel1... address.")
print(result)

if __name__ == "__main__":
asyncio.run(main())
```

## 🛠️ Architecture

The toolkit provides highly modular actions under `src/`:
- `fuel_agent.py`: The central orchestrator uniting all available sub-modules.
- `transfers/`: Logic handling native asset and token transfers.
- `mira/`: Decentralized exchange interactions.
- `swaylend/`: Lending protocol interactions.
- `read/`: Data inspection (balances).

## 📄 License

Distributed under the MIT License.
21 changes: 21 additions & 0 deletions python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[tool.poetry]
name = "fuel-agent-kit"
version = "0.1.0"
description = "An AI agent for Fuel - Python Implementation"
authors = ["Ojaswee Upadhyay <ojaswee2095@gmail.com>"]
readme = "README.md"
packages = [{include = "fuel_agent_kit", from = "src"}]

[tool.poetry.dependencies]
python = "^3.10"
langchain = "^0.1.0"
langchain-openai = "^0.0.5"
langchain-anthropic = "^0.1.0"
langchain-google-genai = "^0.0.9"
pydantic = "^2.0.0"
requests = "^2.31.0"
fuels = "^0.1.0"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
3 changes: 3 additions & 0 deletions python/src/fuel_agent_kit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .fuel_agent import FuelAgent, FuelAgentConfig

__all__ = ["FuelAgent", "FuelAgentConfig"]
60 changes: 60 additions & 0 deletions python/src/fuel_agent_kit/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import SystemMessage
from .tools import create_tools
from .utils.models import MODEL_MAPPING

SYSTEM_MESSAGE = SystemMessage(content=''' You are an AI agent on Fuel network capable of executing all kinds of transactions and interacting with the Fuel blockchain.
You are able to execute transactions on behalf of the user.

If the transaction was successful, return the response in the following format:
The transaction was successful. The explorer link is: https://app.fuel.network/tx/0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef/simple

If the transaction was unsuccessful, return the response in the following format, followed by an explanation if any known:
The transaction failed.
''')

prompt = ChatPromptTemplate.from_messages([
SYSTEM_MESSAGE,
("placeholder", "{chat_history}"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}")
])

def create_agent(fuel_agent, model_name: str, openai_api_key: str = None, anthropic_api_key: str = None, google_gemini_api_key: str = None) -> AgentExecutor:
provider = MODEL_MAPPING.get(model_name)

selected_model = None
if provider == "openai":
if not openai_api_key:
raise ValueError("OpenAI API key is required")
from langchain_openai import ChatOpenAI
selected_model = ChatOpenAI(model=model_name, api_key=openai_api_key)
elif provider == "anthropic":
if not anthropic_api_key:
raise ValueError("Anthropic API key is required")
try:
from langchain_anthropic import ChatAnthropic
selected_model = ChatAnthropic(model=model_name, api_key=anthropic_api_key)
except ImportError:
raise ImportError("langchain-anthropic is not installed")
elif provider == "gemini":
if not google_gemini_api_key:
raise ValueError("Google Gemini API key is required")
try:
from langchain_google_genai import ChatGoogleGenerativeAI
selected_model = ChatGoogleGenerativeAI(model=model_name, api_key=google_gemini_api_key, convert_system_message_to_human=True)
except ImportError:
raise ImportError("langchain-google-genai is not installed")
else:
raise ValueError(f"Model {model_name} not supported or recognized")

tools = create_tools(fuel_agent)

agent = create_tool_calling_agent(
llm=selected_model,
tools=tools,
prompt=prompt
)

return AgentExecutor(agent=agent, tools=tools)
1 change: 1 addition & 0 deletions python/src/fuel_agent_kit/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DEFAULT_SLIPPAGE = 0.01 # 1%
68 changes: 68 additions & 0 deletions python/src/fuel_agent_kit/fuel_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from typing import Optional, Dict, Any
from .agent import create_agent
from .mira.swap import swap_exact_input
from .mira.add_liquidity import add_liquidity
from .swaylend.borrow import borrow_asset
from .swaylend.supply import supply_collateral
from .transfers.transfers import transfer as wallet_transfer
from .read.balance import get_own_balance

class FuelAgentConfig:
def __init__(self, wallet_private_key: str, model: str, open_ai_api_key: Optional[str] = None, anthropic_api_key: Optional[str] = None, google_gemini_api_key: Optional[str] = None):
self.wallet_private_key = wallet_private_key
self.model = model
self.open_ai_api_key = open_ai_api_key
self.anthropic_api_key = anthropic_api_key
self.google_gemini_api_key = google_gemini_api_key

class FuelAgent:
def __init__(self, config: FuelAgentConfig):
self.wallet_private_key = config.wallet_private_key
self.model = config.model
self.open_ai_api_key = config.open_ai_api_key
self.anthropic_api_key = config.anthropic_api_key
self.google_gemini_api_key = config.google_gemini_api_key

if not self.wallet_private_key:
raise ValueError("Fuel wallet private key is required.")

self.agent_executor = create_agent(
fuel_agent=self,
model_name=self.model,
openai_api_key=self.open_ai_api_key,
anthropic_api_key=self.anthropic_api_key,
google_gemini_api_key=self.google_gemini_api_key
)

def get_credentials(self) -> Dict[str, str]:
return {
"walletPrivateKey": self.wallet_private_key,
"openAiApiKey": self.open_ai_api_key or "",
"anthropicApiKey": self.anthropic_api_key or "",
"googleGeminiApiKey": self.google_gemini_api_key or ""
}

def get_tools(self) -> list:
from .tools import create_tools
return create_tools(self)

async def execute(self, input_str: str) -> Any:
return await self.agent_executor.ainvoke({"input": input_str})

async def swap_exact_input(self, params: dict):
return await swap_exact_input(params, self.wallet_private_key)

async def transfer(self, params: dict):
return await wallet_transfer(params, self.wallet_private_key)

async def supply_collateral(self, params: dict):
return await supply_collateral(params, self.wallet_private_key)

async def borrow_asset(self, params: dict):
return await borrow_asset(params, self.wallet_private_key)

async def add_liquidity(self, params: dict):
return await add_liquidity(params, self.wallet_private_key)

async def get_own_balance(self, params: dict):
return await get_own_balance(params, self.wallet_private_key)
1 change: 1 addition & 0 deletions python/src/fuel_agent_kit/mira/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# init
31 changes: 31 additions & 0 deletions python/src/fuel_agent_kit/mira/add_liquidity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import json
from ..utils.assets import get_all_verified_fuel_assets
from ..utils.setup import setup_wallet
from ..constants import DEFAULT_SLIPPAGE

async def add_liquidity(params: dict, private_key: str) -> str:
"""
Mocked implementation of add_liquidity for Mira.
"""
try:
setup_res = await setup_wallet(private_key)

all_assets = get_all_verified_fuel_assets()
asset0 = next((a for a in all_assets if a.get("symbol") == params["asset0Symbol"]), None)
asset1 = next((a for a in all_assets if a.get("symbol") == params["asset1Symbol"]), None)

if not asset0 or not asset1:
raise ValueError(f"Asset {params['asset0Symbol']} or {params['asset1Symbol']} not found")

# MOCK EXECUTION
mock_tx_id = "0x" + "c" * 64

return json.dumps({
"status": "success",
"id": mock_tx_id
})
except Exception as e:
return json.dumps({
"status": "failure",
"error": str(e)
})
38 changes: 38 additions & 0 deletions python/src/fuel_agent_kit/mira/swap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import json
from ..utils.assets import get_all_verified_fuel_assets
from ..utils.setup import setup_wallet
from ..utils.explorer import get_tx_explorer_url
from ..constants import DEFAULT_SLIPPAGE

async def swap_exact_input(params: dict, private_key: str) -> str:
"""
Mocked implementation of swap_exact_input for Mira.
Since mira-dex-ts equivalent is not available in Python, this acts as a placeholder.
"""
try:
setup_res = await setup_wallet(private_key)
wallet = setup_res["wallet"]
provider = setup_res["provider"]

all_assets = get_all_verified_fuel_assets()
from_asset = next((a for a in all_assets if a.get("symbol") == params["fromSymbol"]), None)
to_asset = next((a for a in all_assets if a.get("symbol") == params["toSymbol"]), None)

if not from_asset:
raise ValueError(f"Asset {params['fromSymbol']} not found")
if not to_asset:
raise ValueError(f"Asset {params['toSymbol']} not found")

# MOCK EXECUTION
mock_tx_id = "0x" + "b" * 64

return json.dumps({
"status": "success",
"id": mock_tx_id,
"link": get_tx_explorer_url(mock_tx_id)
})
except Exception as e:
return json.dumps({
"status": "failure",
"error": str(e)
})
1 change: 1 addition & 0 deletions python/src/fuel_agent_kit/read/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# init
Loading