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: deva client integration #1238

Open
wants to merge 40 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
6a0599c
feature: Deva client init
stopmalone Dec 10, 2024
fe40a7b
feat:Deva client bot author
stopmalone Dec 16, 2024
dcb40f7
feature:Deva merge conflict fix
stopmalone Dec 19, 2024
f28abf3
fix:Codestyle indentation fix
stopmalone Dec 19, 2024
943c5ed
Merge branch 'develop' into feat/deva-client-integration
stopmalone Dec 19, 2024
5c2d173
fix:Packages order
stopmalone Dec 19, 2024
1a6ecc4
fix:package.json packages order
stopmalone Dec 19, 2024
c111a80
fix: Removing twitter client
stopmalone Dec 20, 2024
bfb0ca0
fix:Update package.json removed agent-twitter-client
stopmalone Dec 20, 2024
3d6ff01
fix: Conflicts resolved
stopmalone Dec 23, 2024
454d8b7
fix: merge conflict
stopmalone Dec 23, 2024
5109715
fix: updating the core package
stopmalone Dec 23, 2024
799f43f
Merge branch 'develop' into feat/deva-client-integration
stopmalone Dec 23, 2024
4f717ce
fix: agent/package.json conflict
stopmalone Dec 24, 2024
ce1acec
fix: lock file
stopmalone Dec 24, 2024
85afa38
fix: package imports
stopmalone Dec 24, 2024
1db52a7
fix: Additional data check inside fetching data
stopmalone Dec 24, 2024
33cc36d
feat: Docs update
stopmalone Dec 24, 2024
08b6140
fix: documentation indentation
stopmalone Dec 24, 2024
5e0b3eb
fix: documentation graph
stopmalone Dec 24, 2024
494814f
fix: docs/clients.md indentation
stopmalone Dec 24, 2024
62d897d
feat: Deva client, merge fix
stopmalone Dec 30, 2024
88fd552
Merge branch 'develop' into feat/deva-client-integration
stopmalone Dec 30, 2024
7d7a3a9
fix: indentation, spaces
stopmalone Dec 31, 2024
baa914c
fix: lock conflict
stopmalone Dec 31, 2024
b86b483
fix: client package.json indentation
stopmalone Dec 31, 2024
383962c
fix: merge conflict
stopmalone Jan 2, 2025
3e80b7d
Merge branch 'develop' into feat/deva-client-integration
stopmalone Jan 3, 2025
d5b6f87
fix: merge conflict
stopmalone Jan 8, 2025
4ab0fd4
fix: conflicts resolve
stopmalone Jan 8, 2025
0c37ee9
fix: merge conflict
stopmalone Jan 8, 2025
bd1eaeb
Merge branch 'develop' into feat/deva-client-integration
stopmalone Jan 8, 2025
4ddd4fc
Merge branch 'develop' into feat/deva-client-integration
stopmalone Jan 8, 2025
58eb873
Merge branch 'develop' into feat/deva-client-integration
stopmalone Jan 9, 2025
ee4ade0
Merge branch 'develop' into feat/deva-client-integration
stopmalone Jan 9, 2025
158f17a
Merge branch 'develop' into feat/deva-client-integration
stopmalone Jan 9, 2025
eee82b0
Merge branch 'develop' into feat/deva-client-integration
stopmalone Jan 10, 2025
3eb04f9
Merge branch 'develop' into feat/deva-client-integration
stopmalone Jan 10, 2025
78eccd6
fix: merge conflict
stopmalone Jan 13, 2025
cbc16d2
Merge branch 'develop' into feat/deva-client-integration
stopmalone Jan 15, 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
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,10 @@ AWS_REGION=
AWS_S3_BUCKET=
AWS_S3_UPLOAD_PATH=

# Deva Configuration
DEVA_API_KEY= # You can get the API key from the created application in deva.me/settings/apps
DEVA_API_BASE_URL=https://api.deva.me # Default server url is production https://api-staging.deva.me

# Deepgram
DEEPGRAM_API_KEY=

Expand Down
1 change: 1 addition & 0 deletions agent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"@elizaos/plugin-obsidian": "workspace:*",
"@elizaos/plugin-arthera": "workspace:*",
"@elizaos/plugin-allora": "workspace:*",
"@elizaos/client-deva": "workspace:*",
"@elizaos/plugin-opacity": "workspace:*",
"@elizaos/plugin-hyperliquid": "workspace:*",
"@elizaos/plugin-akash": "workspace:*",
Expand Down
6 changes: 6 additions & 0 deletions agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { LensAgentClient } from "@elizaos/client-lens";
import { SlackClientInterface } from "@elizaos/client-slack";
import { TelegramClientInterface } from "@elizaos/client-telegram";
import { TwitterClientInterface } from "@elizaos/client-twitter";
import { DevaClientInterface } from "@elizaos/client-deva";
// import { ReclaimAdapter } from "@elizaos/plugin-reclaim";
import { PrimusAdapter } from "@elizaos/plugin-primus";

Expand Down Expand Up @@ -631,6 +632,11 @@ export async function initializeClients(
if (slackClient) clients.slack = slackClient; // Use object property instead of push
}

if (clientTypes.includes("deva")) {
const devaClients = await DevaClientInterface.start(runtime);
clients.push(devaClients);
}

function determineClientType(client: Client): string {
// Check if client has a direct type identifier
if ("type" in client) {
Expand Down
11 changes: 11 additions & 0 deletions docs/api/enumerations/Clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,14 @@ Available client platforms
#### Defined in

[packages/core/src/types.ts:627](https://github.com/elizaOS/eliza/blob/main/packages/core/src/types.ts#L627)

---

### DEVA

> **DEVA**: `"deva"`

#### Defined in

[packages/core/src/types.ts:643](https://github.com/elizaOS/eliza/blob/main/packages/core/src/types.ts#L643)

123 changes: 106 additions & 17 deletions docs/docs/packages/clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ graph TD
CI --> TC["Telegram Client"]
CI --> TWC["Twitter Client"]
CI --> AC["Auto Client"]
CI --> DEVA["Deva Client"]

%% Key Features - one per client for clarity
DC --> |"REST API"| DC1["Messages & Images"]
DSC --> |"Bot Integration"| DSC1["Voice & Messages"]
TC --> |"Bot API"| TC1["Commands & Media"]
TWC --> |"Social"| TWC1["Posts & Interactions"]
AC --> |"Trading"| AC1["Analysis & Execution"]
DEVA --> |"Social"| DEVA1["Messages & Execution"]

%% Simple styling with better contrast and black text
classDef default fill:#f9f9f9,stroke:#333,stroke-width:1px,color:black
Expand All @@ -35,6 +37,12 @@ graph TD

## Available Clients

- **Discord** (`@eliza/client-discord`) - Full Discord bot integration
- **Twitter** (`@eliza/client-twitter`) - Twitter bot and interaction handling
- **Telegram** (`@eliza/client-telegram`) - Telegram bot integration
- **Direct** (`@eliza/client-direct`) - Direct API interface for custom integrations
- **Auto** (`@eliza/client-auto`) - Automated trading and interaction client
- # **Deva** (`@eliza/client-deva`) - Client for integrating with Deva.me
- **Discord** (`@elizaos/client-discord`) - Full Discord bot integration
- **Twitter** (`@elizaos/client-twitter`) - Twitter bot and interaction handling
- **Telegram** (`@elizaos/client-telegram`) - Telegram bot integration
Expand All @@ -60,6 +68,9 @@ pnpm add @elizaos/client-direct

# Auto Client
pnpm add @elizaos/client-auto

# Deva Client
pnpm add @eliza/client-deva
```

---
Expand Down Expand Up @@ -293,6 +304,80 @@ class AutoClient {
}
```

## Deva Client

The Deva client allows fetching user-related data and making posts based on it.

### Client setup

```typescript
export const DevaClientInterface: Client = {
async start(runtime: IAgentRuntime) {
await validateDevaConfig(runtime);

const deva = new DevaClient(
runtime,
runtime.getSetting("DEVA_API_KEY"),
runtime.getSetting("DEVA_API_BASE_URL"),
);

await deva.start();

elizaLogger.success(
`✅ Deva client successfully started for character ${runtime.character.name}`,
);

return deva;
},
};
```

### Fetch personal user data

```typescript
public async getMe(): Promise<DevaPersona | null> {
return await fetch(`${this.apiBaseUrl}/persona`, {
headers: { ...this.defaultHeaders },
})
.then((res) => res.json())
.catch(() => null);
}
```

### Fetch user posts

```typescript
public async getPersonaPosts(personaId: string): Promise<DevaPost[]> {
const res = await fetch(
`${this.apiBaseUrl}/post?filter_persona_id=${personaId}`,
{
headers: {
Authorization: `Bearer ${this.accessToken}`,
"Content-Type": "application/json",
},
}
).then((res) => res.json());
return res.items;
}
```

### Create and publish a post on behalf of the user

```typescript
public async makePost({ text, in_reply_to_id }: { text: string; in_reply_to_id: string }): Promise<DevaPost> {
const res = await fetch(`${this.apiBaseUrl}/post`, {
method: "POST",
headers: {
Authorization: `Bearer ${this.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ text, in_reply_to_id, author_type: "BOT" }),
}).then((res) => res.json());

console.log(res);
return res;
```

## Common Features

### Message Handling
Expand All @@ -302,7 +387,9 @@ All clients implement standard message handling:
```typescript
interface ClientInterface {
async handleMessage(message: Message): Promise<void>;

async generateResponse(context: Context): Promise<Response>;

async sendMessage(destination: string, content: Content): Promise<void>;
}
```
Expand All @@ -312,7 +399,9 @@ interface ClientInterface {
```typescript
interface MediaProcessor {
async processImage(image: Image): Promise<ProcessedImage>;

async processVideo(video: Video): Promise<ProcessedVideo>;

async processAudio(audio: Audio): Promise<ProcessedAudio>;
}
```
Expand Down Expand Up @@ -462,8 +551,8 @@ class MessageQueue {
```typescript
// Implement token refresh
async refreshAuth() {
const newToken = await this.requestNewToken();
await this.updateToken(newToken);
const newToken = await this.requestNewToken();
await this.updateToken(newToken);
}
```

Expand All @@ -472,9 +561,9 @@ async refreshAuth() {
```typescript
// Handle rate limiting
async handleRateLimit(error) {
const delay = this.calculateBackoff(error);
await wait(delay);
return this.retryRequest();
const delay = this.calculateBackoff(error);
await wait(delay);
return this.retryRequest();
}
```

Expand All @@ -483,25 +572,25 @@ async handleRateLimit(error) {
```typescript
// Implement reconnection logic
async handleDisconnect() {
await this.reconnect({
maxAttempts: 5,
backoff: 'exponential'
});
await this.reconnect({
maxAttempts: 5,
backoff: "exponential",
});
}
```

4. **Message Processing Failure**

```typescript
async processMessage(message) {
try {
return await this.messageProcessor(message);
} catch (error) {
if (error.code === "INVALID_FORMAT") {
return this.handleInvalidFormat(message);
}
throw error;
}
try {
return await this.messageProcessor(message);
} catch (error) {
if (error.code === "INVALID_FORMAT") {
return this.handleInvalidFormat(message);
}
throw error;
}
}
```

Expand Down
6 changes: 6 additions & 0 deletions packages/client-deva/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*

!dist/**
!package.json
!readme.md
!tsup.config.ts
3 changes: 3 additions & 0 deletions packages/client-deva/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];
23 changes: 23 additions & 0 deletions packages/client-deva/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "@elizaos/client-deva",
"version": "0.1.7-alpha.1",
"main": "dist/index.js",
"type": "module",
"types": "dist/index.d.ts",
"dependencies": {
"@elizaos/core": "workspace:*",
"glob": "11.0.0",
"zod": "3.23.8"
},
"devDependencies": {
"tsup": "8.3.5"
},
"scripts": {
"build": "tsup --format esm --dts",
"dev": "tsup --watch",
"lint": "eslint . --fix"
},
"peerDependencies": {
"whatwg-url": "7.1.0"
}
}
60 changes: 60 additions & 0 deletions packages/client-deva/src/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { elizaLogger, IAgentRuntime } from "@elizaos/core";
import { DevaPersona, DevaPost } from "./types";

export class ClientBase {
private readonly runtime: IAgentRuntime;
private readonly accessToken: string;
private readonly apiBaseUrl: string;
private readonly defaultHeaders: Record<string, string>;

constructor(runtime: IAgentRuntime, accessToken: string, baseUrl: string) {
this.runtime = runtime;
this.accessToken = accessToken;
this.apiBaseUrl = baseUrl;
this.defaultHeaders = {
Authorization: `Bearer ${this.accessToken}`,
"Content-Type": "application/json",
};
}

public async getMe(): Promise<DevaPersona | null> {
return await fetch(`${this.apiBaseUrl}/persona`, {
headers: { ...this.defaultHeaders },
})
.then((res) => res.json())
.catch(() => null);
}

public async getPersonaPosts(personaId: string): Promise<DevaPost[]> {
const res = await fetch(
`${this.apiBaseUrl}/post?filter_persona_id=${personaId}`,
{
headers: {
Authorization: `Bearer ${this.accessToken}`,
"Content-Type": "application/json",
},
}
).then((res) => res.json());
return res.items;
}

public async makePost({
text,
in_reply_to_id,
}: {
text: string;
in_reply_to_id: string;
}): Promise<DevaPost> {
const res = await fetch(`${this.apiBaseUrl}/post`, {
method: "POST",
headers: {
Authorization: `Bearer ${this.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ text, in_reply_to_id, author_type: "BOT" }),
}).then((res) => res.json());

console.log(res);
return res;
}
}
Loading
Loading