Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Irys plugin #1708

Merged
merged 25 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9c667c9
Irys plugin
Hugo-SEQUIER Jan 1, 2025
df0fb77
Fix after test
Hugo-SEQUIER Jan 1, 2025
f489f83
More data structure
Hugo-SEQUIER Jan 2, 2025
6e1df61
Test + file
Hugo-SEQUIER Jan 2, 2025
963eb63
readme
Hugo-SEQUIER Jan 2, 2025
46fc6c5
Merge branch 'develop' into main
Hugo-SEQUIER Jan 3, 2025
1d89e2b
Merge branch 'develop' into main
Hugo-SEQUIER Jan 3, 2025
b7a7174
tags logic to store and retrieve data
Hugo-SEQUIER Jan 6, 2025
42af984
Worker, Provider and Orchestrator basic logic
Hugo-SEQUIER Jan 9, 2025
9790335
Timestamp for better retrieval
Hugo-SEQUIER Jan 9, 2025
e1ebb4a
My vision about AI Agent narrative and framework
Hugo-SEQUIER Jan 9, 2025
d9c7f49
test
Hugo-SEQUIER Jan 9, 2025
8c80de5
Test
Hugo-SEQUIER Jan 10, 2025
6008e0d
Merge branch 'elizaOS:main' into main
Hugo-SEQUIER Jan 10, 2025
826e3b7
Merge pull request #1 from Hugo-SEQUIER/alpha.2
Hugo-SEQUIER Jan 10, 2025
6086e4e
orchestrator diagram
Hugo-SEQUIER Jan 10, 2025
3e57117
How it works section
Hugo-SEQUIER Jan 10, 2025
f386f2e
New plugin version + ReadMe
Hugo-SEQUIER Jan 10, 2025
02f6188
Merge branch 'develop' into main
Hugo-SEQUIER Jan 10, 2025
0eead2b
Merge branch 'develop' into main
Hugo-SEQUIER Jan 10, 2025
d049f0d
Merge branch 'develop' into main
tcm390 Jan 10, 2025
7d7929d
Merge branch 'develop' into main
Hugo-SEQUIER Jan 10, 2025
0efa787
Merge branch 'develop' into main
shakkernerd Jan 10, 2025
cc54ac5
chore: pnpm lock file
shakkernerd Jan 10, 2025
73be9cf
chore: pnpm lock file check on PRs into main
shakkernerd Jan 10, 2025
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
20 changes: 20 additions & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,25 @@ export interface IAwsS3Service extends Service {
generateSignedUrl(fileName: string, expiresIn: number): Promise<string>;
}


export interface UploadIrysResult {
success: boolean;
url?: string;
error?: string;
}

export interface DataIrysFetchedFromGQL {
success: boolean;
data: any;
error?: string;
}

export interface IIrysService extends Service {
uploadDataOnIrys(data: any): Promise<UploadIrysResult>;
getDataFromAnAgent(agentsWalletPublicKeys: string[]): Promise<DataIrysFetchedFromGQL>;
uploadFileOrImageOnIrys(data: string): Promise<UploadIrysResult>;
}

export type SearchResult = {
title: string;
url: string;
Expand Down Expand Up @@ -1255,6 +1274,7 @@ export enum ServiceType {
AWS_S3 = "aws_s3",
BUTTPLUG = "buttplug",
SLACK = "slack",
IRYS = "irys",
}

export enum LoggingLevel {
Expand Down
6 changes: 6 additions & 0 deletions packages/plugin-irys/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*

!dist/**
!package.json
!readme.md
!tsup.config.ts
139 changes: 139 additions & 0 deletions packages/plugin-irys/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# @elizaos/plugin-irys

A plugin for ElizaOS that enables decentralized data storage and retrieval using Irys, a programmable datachain platform.

## Overview

This plugin integrates Irys functionality into ElizaOS, allowing agents to store and retrieve data in a decentralized manner. It provides a robust service for creating a decentralized knowledge base and enabling multi-agent collaboration.

## Installation

To install this plugin, run the following command:

```bash
pnpm add @elizaos/plugin-irys
```


## Features

- **Decentralized Data Storage**: Store data permanently on the Irys network
- **Data Retrieval**: Fetch stored data using GraphQL queries
- **Multi-Agent Support**: Enable data sharing and collaboration between agents
- **Ethereum Integration**: Built-in support for Ethereum wallet authentication

## Configuration

The plugin requires the following environment variables:

- `EVM_WALLET_PRIVATE_KEY`: Your EVM wallet private key
- `AGENTS_WALLET_PUBLIC_KEYS`: The public keys of the agents that will be used to retrieve the data (string separated by commas)

For this plugin to work, you need to have an EVM (Base network) wallet with a private key and public address. To prevent any security issues, we recommend using a dedicated wallet for this plugin.

> **Important**: The wallet address needs to have Base Sepolia ETH tokens to store images/files and any data larger than 100KB.

## Usage

### Uploading Data

To upload data to the Irys network, you can use the `uploadDataOnIrys` function. This function will upload the data to the Irys network and return the transaction hash.

```typescript
const { IrysService } = require('@elizaos/plugin-irys');

const irysService : IrysService = runtime.getService(ServiceType.IRYS)
const data = "Hello, world!";
const transactionResult = await irysService.uploadDataOnIrys(data);
console.log(`Data uploaded successfully. Transaction hash: ${transactionResult}`);
```

To upload files or images to the Irys network, you can use the `uploadFileOrImageOnIrys` function:

```typescript
const { IrysService } = require('@elizaos/plugin-irys');

const irysService : IrysService = runtime.getService(ServiceType.IRYS)
const userAttachmentToStore = state.recentMessagesData[1].content.attachments[0].url.replace("agent\\agent", "agent");

const transactionResult = await irysService.uploadFileOrImageOnIrys(userAttachmentToStore);
console.log(`Data uploaded successfully. Transaction hash: ${transactionResult}`);
```

### Retrieving Data

To retrieve data from the Irys network, you can use the `getDataFromAnAgent` function. This function will retrieve all data associated with the given wallet addresses. The function automatically detects the content type and returns either JSON data or file URLs accordingly.

- For files and images: Returns the URL of the stored content
- For other data types: Returns a JSON object with the following structure:
```typescript
{
data: string, // The stored data
timestamp: Date // When the data was stored
}
```

```typescript
const { IrysService } = require('@elizaos/plugin-irys');

const irysService = runtime.getService(ServiceType.IRYS)
const agentsWalletPublicKeys = runtime.getSetting("AGENTS_WALLET_PUBLIC_KEYS").split(",");
const data = await irysService.getDataFromAnAgent(agentsWalletPublicKeys);
console.log(`Data retrieved successfully. Data: ${data}`);
```

## About Irys

Irys is the first Layer 1 (L1) programmable datachain designed to optimize both data storage and execution. By integrating storage and execution, Irys enhances the utility of blockspace, enabling a broader spectrum of web services to operate on-chain.

### Key Features of Irys

- **Unified Platform**: Combines data storage and execution, allowing developers to eliminate dependencies and integrate efficient on-chain data seamlessly.
- **Cost-Effective Storage**: Optimized specifically for data storage, making it significantly cheaper to store data on-chain compared to traditional blockchains.
- **Programmable Datachain**: The IrysVM can utilize on-chain data during computations, enabling dynamic and real-time applications.
- **Decentralization**: Designed to minimize centralization risks by distributing control.
- **Free Storage for Small Data**: Storing less than 100KB of data is free.
- **GraphQL Querying**: Metadata stored on Irys can be queried using GraphQL.

### GraphQL Query Examples

The plugin uses GraphQL to retrieve transaction metadata. Here's an example query structure:

```graphql
query {
transactions(owners: ["0x1234567890", "0x0987654321"]) {
edges {
node {
id
}
}
}
}
```


## API Reference

### IrysService

The main service provided by this plugin implements the following interface:

```typescript
interface IrysService {
uploadStringToIrys(data: string): Promise<string>;
getDataFromAnAgent(agentsWalletPublicKeys: string[]): Promise<string>;
}
```

#### Methods

- `uploadStringToIrys(data: string)`: Uploads a string to Irys and returns the transaction URL
- `getDataFromAnAgent(agentsWalletPublicKeys: string[])`: Retrieves all data associated with the given wallet addresses

## Testing

While we don't currently have a formal test suite, all functions have been manually tested through agent actions to verify their functionality. Each function has been validated in real-world scenarios to ensure reliable performance.

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.
3 changes: 3 additions & 0 deletions packages/plugin-irys/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import eslintGlobalConfig from "../../eslint.config.mjs";

export default [...eslintGlobalConfig];
22 changes: 22 additions & 0 deletions packages/plugin-irys/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "@elizaos/plugin-irys",
"version": "0.1.0-alpha.1",
"main": "dist/index.js",
"type": "module",
"types": "dist/index.d.ts",
"dependencies": {
"@elizaos/core": "workspace:*",
"@irys/upload": "^0.0.14",
"@irys/upload-ethereum": "^0.0.14",
"graphql-request": "^4.0.0"
},
"devDependencies": {
"tsup": "8.3.5",
"@types/node": "^20.0.0"
},
"scripts": {
"build": "tsup --format esm --dts",
"dev": "tsup --format esm --dts --watch",
"lint": "eslint --fix --cache ."
}
}
44 changes: 44 additions & 0 deletions packages/plugin-irys/src/agent-test/actions/retrieveData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
IAgentRuntime,
Action,
Memory,
State,
HandlerCallback,
ActionExample,
ServiceType,
} from "@elizaos/core";

import { IrysService } from "../services/irysService";

export const retrieveDataAction: Action = {
name: "RETRIEVE_DATA_FROM_IRYS",
description: "Retrieve data from Irys for any message",
similes: ["RETRIEVE_DATA"],
validate: async (
_runtime: IAgentRuntime,
_message: Memory,
) => {
return true;
},
handler: async (
runtime: IAgentRuntime,
message: Memory,
state: State,
options: any,
callback?: HandlerCallback
): Promise<boolean> => {
console.log("Starting RETRIEVE_DATA_FROM_IRYS handler...");
const irysService: IrysService = runtime.getService(ServiceType.IRYS);
const agentsWalletPublicKeys = runtime.getSetting("AGENTS_WALLET_PUBLIC_KEYS").split(",");
const data = await irysService.getDataFromAnAgent(agentsWalletPublicKeys);
if (!data.success) {
console.log("Error retrieving data:", data.error);
return false;
}
console.log(`Data retrieved successfully. Data:`);
console.log(data.data);
return true;
},
examples: [
] as ActionExample[][],
}
47 changes: 47 additions & 0 deletions packages/plugin-irys/src/agent-test/actions/storeData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
IAgentRuntime,
Action,
Memory,
State,
HandlerCallback,
ActionExample,
ServiceType,
} from "@elizaos/core";

import { IrysService } from "../services/irysService";

export const storeDataAction: Action = {
name: "STORE_DATA_ON_IRYS",
description: "Store data on Irys for any message",
similes: ["DEFAULT_ACTION", "ANY_MESSAGE", "CATCH_ALL", "IRYS"],
validate: async (
_runtime: IAgentRuntime,
_message: Memory,
) => {
console.log("Validating message:", _message.content.text);
return true;
},
handler: async (
runtime: IAgentRuntime,
message: Memory,
state: State,
options: any,
callback?: HandlerCallback
): Promise<boolean> => {
console.log("Starting STORE_DATA_ON_IRYS handler...");
console.log("User message:", message.content.text);
console.log("Message generated:", state.recentMessagesData[0].content.text);
const irysService: IrysService = runtime.getService(ServiceType.IRYS);
const result = await irysService.uploadDataOnIrys(state.recentMessagesData[0].content.text);
if (state.recentMessagesData[1].content.attachments.length > 0) {
const userAttachmentToStore = state.recentMessagesData[1].content.attachments[0].url.replace("agent\\agent", "agent");
const resultImage = await irysService.uploadFileOrImageOnIrys(userAttachmentToStore);
console.log("Result Image:", resultImage);
}
console.log("Result:", result);

return true;
},
examples: [
] as ActionExample[][],
}
Loading
Loading