Skip to content

Commit 0bdafda

Browse files
authored
Merge pull request #2086 from primus-labs/develop
feat: Primus zkTLS plugin to fully verify agent activities
2 parents 565f4e7 + d90f838 commit 0bdafda

17 files changed

+3151
-4763
lines changed

agent/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"@elizaos/plugin-near": "workspace:*",
7373
"@elizaos/plugin-zksync-era": "workspace:*",
7474
"@elizaos/plugin-twitter": "workspace:*",
75+
"@elizaos/plugin-primus": "workspace:*",
7576
"@elizaos/plugin-cronoszkevm": "workspace:*",
7677
"@elizaos/plugin-3d-generation": "workspace:*",
7778
"@elizaos/plugin-fuel": "workspace:*",

agent/src/index.ts

+17
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import { SlackClientInterface } from "@elizaos/client-slack";
1010
import { TelegramClientInterface } from "@elizaos/client-telegram";
1111
import { TwitterClientInterface } from "@elizaos/client-twitter";
1212
// import { ReclaimAdapter } from "@elizaos/plugin-reclaim";
13+
import { DirectClient } from "@elizaos/client-direct";
14+
import { PrimusAdapter } from "@elizaos/plugin-primus";
15+
1316
import {
1417
AgentRuntime,
1518
CacheManager,
@@ -98,6 +101,7 @@ import net from "net";
98101
import path from "path";
99102
import { fileURLToPath } from "url";
100103
import yargs from "yargs";
104+
import {dominosPlugin} from "@elizaos/plugin-dominos";
101105

102106
const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file
103107
const __dirname = path.dirname(__filename); // get the name of the directory
@@ -622,6 +626,19 @@ export async function createAgent(
622626
elizaLogger.log("modelProvider", character.modelProvider);
623627
elizaLogger.log("token", token);
624628
}
629+
if (
630+
process.env.PRIMUS_APP_ID &&
631+
process.env.PRIMUS_APP_SECRET &&
632+
process.env.VERIFIABLE_INFERENCE_ENABLED === "true"){
633+
verifiableInferenceAdapter = new PrimusAdapter({
634+
appId: process.env.PRIMUS_APP_ID,
635+
appSecret: process.env.PRIMUS_APP_SECRET,
636+
attMode: "proxytls",
637+
modelProvider: character.modelProvider,
638+
token,
639+
});
640+
elizaLogger.log("Verifiable inference primus adapter initialized");
641+
}
625642

626643
return new AgentRuntime({
627644
databaseAdapter: db,

packages/core/src/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1477,7 +1477,9 @@ export interface ISlackService extends Service {
14771477
* Available verifiable inference providers
14781478
*/
14791479
export enum VerifiableInferenceProvider {
1480+
RECLAIM = "reclaim",
14801481
OPACITY = "opacity",
1482+
PRIMUS = "primus",
14811483
}
14821484

14831485
/**

packages/plugin-primus/.npmignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*
2+
3+
!dist/**
4+
!package.json
5+
!readme.md
6+
!tsup.config.ts

packages/plugin-primus/README.md

+208
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
# @elizaos/plugin-primus
2+
3+
A plugin to fully verify agent activities, including LLM access, actions, and interactions with external providers,
4+
powered by Primus' zkTLS protocol.
5+
6+
## Overview
7+
8+
In the Eliza framework, an agent consists of three key components: a brain (accessing an LLM), actions (the tasks the
9+
agent performs), and perception (gathering external information from providers). To fully verify agent activities, it's
10+
essential to ensure that the agent's thoughts, actions, and external information requests are all verifiable. This
11+
plugin enables full verification of these activities.
12+
13+
The current plugin includes:
14+
15+
- Verification of inference from OpenAI's LLM.
16+
- An example for verifying actions, such as posting a tweet (this can be extended to any other actions).
17+
- An example to verify that the Bitcoin price is accurately fetched from Binance (this can be extended to any other data
18+
providers).
19+
20+
## Usage
21+
### LLM inference verification (PrimusAdapter)
22+
`PrimusAdapter` implements `IVerifiableInferenceAdapter` and can be used as follows.
23+
```typescript
24+
import {PrimusAdapter} from "@elizaos/plugin-primus";
25+
import {VerifiableInferenceOptions} from '@elizaos/core';
26+
27+
// Initialize primus adapter
28+
const primusAdatper = new PrimusAdapter({
29+
appId: process.env.PRIMUS_APP_ID,
30+
appSecret: process.env.PRIMUS_APP_SECRET,
31+
// Choose MPC-TLS or Proxy-TLS
32+
attMode: "proxytls",
33+
modelProvider: character.modelProvider,
34+
token,
35+
});
36+
37+
interface PrimusOptions {
38+
appId: string;
39+
appSecret: string;
40+
attMode: string;
41+
modelProvider?: ModelProviderName;
42+
token?: string;
43+
}
44+
45+
// The options for generating an attestation
46+
const options: VerifiableInferenceOptions = {
47+
// Optional: Override the default endpoint
48+
endpoint: "https://api.openapi.com/chat/completions",
49+
// Optional: Add custom headers
50+
headers: {
51+
"Content-Type": "application/json",
52+
"Authorization": "bearer Token",
53+
},
54+
// Optional: Provider-specific options
55+
providerOptions: {
56+
temperature: 0.7,
57+
},
58+
};
59+
60+
// Generate an attestation for a network request.
61+
const result = await primusAdapter.generateText(context, "gpt-4o", options);
62+
// Verify the validity of the attestation.
63+
const isValid = await primusAdapter.verifyProof(result.proof);
64+
```
65+
66+
The core functions in `PrimusAdatper` are the following, which are also used in Actions and Providers.
67+
```typescript
68+
// Generate a zkTLS proof.
69+
generateProof = async (
70+
// The target endpoint of the network request.
71+
endpoint: string,
72+
// The HTTP method of the request, such as 'GET', 'POST', etc.
73+
method: string,
74+
// A record containing the headers of the request.
75+
headers: Record<string, any>,
76+
// The body of the request. It should be a string.
77+
body: string,
78+
//A [JSONPath](https://datatracker.ietf.org/doc/rfc9535/) expression to locate the specific field in the response you want to attest.
79+
responseParsePath: string
80+
): Promise<any>
81+
82+
// Verify the proof.
83+
verifyProof = async (attestation: any): Promise<boolean>
84+
85+
```
86+
87+
### Verify the interaction with Providers
88+
89+
Here’s an example showcasing how to verify the validity of the BTC price retrieved from Binance. Developers can easily customize this process for other providers.
90+
91+
```typescript
92+
const tokenPriceProvider: Provider = {
93+
get: async (runtime: IAgentRuntime, message: Memory, _state?: State) => {
94+
// Set the URL
95+
const url = "https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT";
96+
const method = 'GET';
97+
const headers = {
98+
'Accept ': '*/*',
99+
};
100+
// Generate the proof
101+
const attestation = await generateProof(url, method, headers, "", "$.price");
102+
// Verify the proof.
103+
const valid = await verifyProof(attestation);
104+
if (!valid) {
105+
throw new Error("Invalid price attestation");
106+
}
107+
......
108+
},
109+
};
110+
```
111+
112+
### Verify the Actions
113+
Below is an example showcasing how to post price information from the [tokenPriceProvider](./src/providers/tokenPriceProvider.ts) to Twitter. Developers can easily adapt this process for other providers.
114+
115+
Note that you need to configure the `.env` file correctly to post tweets.
116+
```typescript
117+
export const postTweetAction: Action = {
118+
description: "Post a tweet on Twitter and be verified by Primus",
119+
examples: [],
120+
handler: async (
121+
runtime: IAgentRuntime,
122+
message: Memory,
123+
state?: State
124+
): Promise<boolean> => {
125+
const contentYouWantToPost = await tokenPriceProvider.get(runtime, message, state);
126+
const endpoint = 'https://twitter.com/i/api/graphql/a1p9RWpkYKBjWv_I3WzS-A/CreateTweet';
127+
const method = 'POST';
128+
const attestation = await generateProof(endpoint,method,headers,bodyStr,"$.data.create_tweet.tweet_results.result.rest_id");
129+
elizaLogger.info(
130+
"Tweet posting proof generated successfully:",
131+
attestation
132+
);
133+
const verifyResult = verifyProof(attestation);
134+
if (!verifyResult) {
135+
throw new Error(
136+
"Attestation verify failed, data from source is illegality"
137+
);
138+
}
139+
140+
},
141+
name: "POST_TWEET",
142+
similes: [],
143+
validate: async (
144+
runtime: IAgentRuntime,
145+
message: Memory,
146+
state?: State
147+
) => {
148+
const hasCredentials =
149+
!!process.env.TWITTER_USERNAME && !!process.env.TWITTER_PASSWORD;
150+
elizaLogger.log(`Has credentials: ${hasCredentials}`);
151+
152+
return hasCredentials;
153+
},
154+
};
155+
```
156+
157+
## Installation
158+
159+
```bash
160+
pnpm add @elizaos/plugin-primus
161+
```
162+
163+
## Configuration
164+
165+
Add the following environment variables to your .env file:
166+
167+
```
168+
PRIMUS_APP_ID=your_app_id
169+
PRIMUS_APP_SECRET=your_app_secret
170+
VERIFIABLE_INFERENCE_ENABLED=true
171+
VERIFIABLE_INFERENCE_PROVIDER=primus
172+
```
173+
174+
***How to get PRIMUS_APP_ID and PRIMUS_APP_SECRET***
175+
176+
1. Visit the [Primus Developer Hub](https://dev.primuslabs.xyz/).
177+
2. Create a new project
178+
3. Save your 'Application ID(PRIMUS_APP_ID)' and 'Secret Key(PRIMUS_APP_SECRET)'
179+
180+
To use the plugin, add `@elizaos/plugin-primus` to the plugins field in your character file. Here's an example of how your character file might look after the update:
181+
182+
```json
183+
{
184+
"name": "trump",
185+
"modelProvider": "openai",
186+
// just support openai now
187+
"plugins": [
188+
"@elizaos/plugin-primus"
189+
],
190+
// other fields
191+
.....
192+
}
193+
```
194+
195+
## Run
196+
197+
```bash
198+
# Start the server
199+
pnpm start --characters="characters/xxx.character.json"
200+
```
201+
202+
```bash
203+
# Start the client
204+
pnpm start:client
205+
```
206+
207+
You can ask the agent: "Get the BTC price and tweet."
208+

packages/plugin-primus/package.json

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "@elizaos/plugin-primus",
3+
"version": "0.1.7",
4+
"type": "module",
5+
"main": "dist/index.js",
6+
"module": "dist/index.js",
7+
"types": "dist/index.d.ts",
8+
"exports": {
9+
"./package.json": "./package.json",
10+
".": {
11+
"import": {
12+
"@elizaos/source": "./src/index.ts",
13+
"types": "./dist/index.d.ts",
14+
"default": "./dist/index.js"
15+
}
16+
}
17+
},
18+
"files": [
19+
"dist"
20+
],
21+
"dependencies": {
22+
"@elizaos/core": "workspace:*",
23+
"agent-twitter-client": "0.0.18",
24+
"@primuslabs/zktls-core-sdk": "^0.1.0",
25+
"tsup": "8.3.5"
26+
},
27+
"scripts": {
28+
"build": "tsup --format esm --dts",
29+
"dev": "tsup --format esm --dts --watch",
30+
"test": "vitest run"
31+
}
32+
}

0 commit comments

Comments
 (0)