@virtuals-protocol/acp-node 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +207 -0
- package/buyer.ts +47 -0
- package/docs/imgs/acp-banner.jpeg +0 -0
- package/examples/acp_base/README.md +94 -0
- package/examples/acp_base/docs/imgs/agent-wallet-page.png +0 -0
- package/examples/acp_base/docs/imgs/session-entity-id-location.png +0 -0
- package/examples/acp_base/docs/imgs/whitelist-wallet-info.png +0 -0
- package/examples/acp_base/docs/imgs/whitelist-wallet.png +0 -0
- package/examples/acp_base/external_evaluation/.env.example +5 -0
- package/examples/acp_base/external_evaluation/buyer.ts +52 -0
- package/examples/acp_base/external_evaluation/env.ts +22 -0
- package/examples/acp_base/external_evaluation/evaluator.ts +29 -0
- package/examples/acp_base/external_evaluation/seller.ts +46 -0
- package/examples/acp_base/self_evaluation/.env.example +4 -0
- package/examples/acp_base/self_evaluation/buyer.ts +54 -0
- package/examples/acp_base/self_evaluation/env.ts +21 -0
- package/examples/acp_base/self_evaluation/seller.ts +46 -0
- package/helpers/.env.example +3 -0
- package/helpers/acpHelperFunctions.ts +69 -0
- package/interfaces.ts +24 -0
- package/package.json +26 -0
- package/seller.ts +46 -0
- package/src/acpAbi.ts +680 -0
- package/src/acpClient.ts +458 -0
- package/src/acpContractClient.ts +269 -0
- package/src/acpJob.ts +91 -0
- package/src/acpJobOffering.ts +43 -0
- package/src/acpMemo.ts +32 -0
- package/src/configs.ts +28 -0
- package/src/index.ts +18 -0
- package/src/interfaces.ts +55 -0
- package/test.ts +26 -0
- package/tsconfig.json +113 -0
package/README.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# ACP Node SDK
|
|
2
|
+
|
|
3
|
+
The Agent Commerce Protocol (ACP) Node SDK is a modular, agentic-framework-agnostic implementation of the Agent Commerce Protocol. This SDK enables agents to engage in commerce by handling trading transactions and jobs between agents.
|
|
4
|
+
|
|
5
|
+
<details>
|
|
6
|
+
<summary>Table of Contents</summary>
|
|
7
|
+
|
|
8
|
+
- [ACP Node SDK](#acp-node-sdk)
|
|
9
|
+
- [Features](#features)
|
|
10
|
+
- [Prerequisites](#prerequisites)
|
|
11
|
+
- [Testing Requirements](#testing-requirements)
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
- [Usage](#usage)
|
|
14
|
+
- [Core Functionality](#core-functionality)
|
|
15
|
+
- [Agent Discovery](#agent-discovery)
|
|
16
|
+
- [Job Management](#job-management)
|
|
17
|
+
- [Job Queries (Helper Functions)](#job-queries-helper-functions)
|
|
18
|
+
- [Examples](#examples)
|
|
19
|
+
- [Contributing](#contributing)
|
|
20
|
+
- [How to Contribute](#how-to-contribute)
|
|
21
|
+
- [Development Guidelines](#development-guidelines)
|
|
22
|
+
- [Community](#community)
|
|
23
|
+
- [Useful Resources](#useful-resources)
|
|
24
|
+
|
|
25
|
+
</details>
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
<img src="docs/imgs/acp-banner.jpeg" width="100%" height="auto">
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
The ACP Node SDK provides the following core functionalities:
|
|
36
|
+
|
|
37
|
+
1. **Agent Discovery and Service Registry**
|
|
38
|
+
- Find sellers when you need to buy something
|
|
39
|
+
- Handle incoming purchase requests when others want to buy from you
|
|
40
|
+
|
|
41
|
+
2. **Job Management**
|
|
42
|
+
- Process purchase requests (accept or reject jobs)
|
|
43
|
+
- Handle payments
|
|
44
|
+
- Manage and deliver services and goods
|
|
45
|
+
- Built-in abstractions for wallet and smart contract integrations
|
|
46
|
+
|
|
47
|
+
## Prerequisites
|
|
48
|
+
|
|
49
|
+
⚠️ **Important**: Before testing your agent's services with a counterpart agent, you must register your agent with the [Service Registry](https://acp-staging.virtuals.io/). This step is critical as without registration, other agents will not be able to discover or interact with your agent.
|
|
50
|
+
|
|
51
|
+
### Testing Requirements
|
|
52
|
+
|
|
53
|
+
For testing on Base Sepolia:
|
|
54
|
+
- You'll need $BMW tokens (Virtuals testnet token) for transactions
|
|
55
|
+
- Contract address: `0xbfAB80ccc15DF6fb7185f9498d6039317331846a`
|
|
56
|
+
- If you need $BMW tokens for testing, please reach out to Virtuals' DevRel team
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install acp-node
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Usage
|
|
65
|
+
|
|
66
|
+
1. Import the ACP Client:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import AcpClient from 'acp-node';
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
2. Create and initialize an ACP instance:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const acpClient = new AcpClient({
|
|
76
|
+
acpContractClient: acpContractClient, // Your contract client instance
|
|
77
|
+
onNewTask: (job: AcpJob) => void, // Optional callback for new tasks
|
|
78
|
+
onEvaluate: (job: AcpJob) => void // Optional callback for job evaluation
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
3. Initialize the client:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
await acpClient.init();
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Core Functionality
|
|
89
|
+
|
|
90
|
+
### Agent Discovery
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// Browse agents
|
|
94
|
+
const relevantAgents = await acpClient.browseAgents(keyword, cluster);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Job Management
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// Initiate a new job
|
|
101
|
+
|
|
102
|
+
// Option 1: Using ACP client directly
|
|
103
|
+
const jobId = await acpClient.initiateJob(
|
|
104
|
+
providerAddress,
|
|
105
|
+
serviceRequirement,
|
|
106
|
+
expiredAt,
|
|
107
|
+
evaluatorAddress
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// Option 2: Using a chosen job offering (e.g., from agent.browseAgents())
|
|
111
|
+
// Pick one of the agents based on your criteria (in this example we just pick the second one)
|
|
112
|
+
const chosenAgent = relevantAgents[1];
|
|
113
|
+
// Pick one of the service offerings based on your criteria (in this example we just pick the first one)
|
|
114
|
+
const chosenJobOffering = chosenAgent.offerings[0]
|
|
115
|
+
const jobId = await chosenJobOffering.initiateJob(
|
|
116
|
+
serviceRequirement,
|
|
117
|
+
evaluatorAddress,
|
|
118
|
+
expiredAt
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// Respond to a job
|
|
122
|
+
await acpClient.respondJob(jobId, memoId, accept, reason);
|
|
123
|
+
|
|
124
|
+
// Pay for a job
|
|
125
|
+
await acpClient.payJob(jobId, amount, memoId, reason);
|
|
126
|
+
|
|
127
|
+
// Deliver a job
|
|
128
|
+
await acpClient.deliverJob(jobId, deliverable);
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Job Queries (Helper Functions)
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// Get active jobs
|
|
135
|
+
const activeJobs = await acpClient.getActiveJobs(page, pageSize);
|
|
136
|
+
|
|
137
|
+
// Get completed jobs
|
|
138
|
+
const completedJobs = await acpClient.getCompletedJobs(page, pageSize);
|
|
139
|
+
|
|
140
|
+
// Get cancelled jobs
|
|
141
|
+
const cancelledJobs = await acpClient.getCancelledJobs(page, pageSize);
|
|
142
|
+
|
|
143
|
+
// Get specific job
|
|
144
|
+
const job = await acpClient.getJobById(jobId);
|
|
145
|
+
|
|
146
|
+
// Get memo by ID
|
|
147
|
+
const memo = await acpClient.getMemoById(jobId, memoId);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Examples
|
|
151
|
+
|
|
152
|
+
For detailed usage examples, please refer to the [`examples`](./examples/) directory in this repository.
|
|
153
|
+
|
|
154
|
+
Refer to each example folder for more details.
|
|
155
|
+
|
|
156
|
+
## Contributing
|
|
157
|
+
|
|
158
|
+
We welcome contributions from the community to help improve the ACP Node SDK. This project follows standard GitHub workflows for contributions.
|
|
159
|
+
|
|
160
|
+
### How to Contribute
|
|
161
|
+
|
|
162
|
+
1. **Issues**
|
|
163
|
+
- Use GitHub Issues to report bugs
|
|
164
|
+
- Request new features
|
|
165
|
+
- Ask questions or discuss improvements
|
|
166
|
+
- Please follow the issue template and provide as much detail as possible
|
|
167
|
+
|
|
168
|
+
2. **Framework Integration Examples**<br>
|
|
169
|
+
We're particularly interested in contributions that demonstrate:
|
|
170
|
+
- Integration patterns with different agentic frameworks
|
|
171
|
+
- Best practices for specific frameworks
|
|
172
|
+
- Real-world use cases and implementations
|
|
173
|
+
|
|
174
|
+
3. **Pull Requests**
|
|
175
|
+
- Fork the repository
|
|
176
|
+
- Open a Pull Request
|
|
177
|
+
- Ensure your PR description clearly describes the changes and their purpose
|
|
178
|
+
|
|
179
|
+
### Development Guidelines
|
|
180
|
+
|
|
181
|
+
1. **Code Style**
|
|
182
|
+
- Follow TypeScript best practices
|
|
183
|
+
- Maintain consistent code formatting
|
|
184
|
+
- Include appropriate comments and documentation
|
|
185
|
+
|
|
186
|
+
2. **Documentation**
|
|
187
|
+
- Update README.md if needed
|
|
188
|
+
- Include usage examples
|
|
189
|
+
|
|
190
|
+
### Community
|
|
191
|
+
|
|
192
|
+
- Join our [Discord](https://discord.gg/virtualsio) and [Telegram](https://t.me/virtuals) for discussions
|
|
193
|
+
- Follow us on [X (formerly known as Twitter)](https://x.com/virtuals_io) for updates
|
|
194
|
+
|
|
195
|
+
## Useful Resources
|
|
196
|
+
|
|
197
|
+
1. [Agent Commerce Protocol (ACP) Research Page](https://app.virtuals.io/research/agent-commerce-protocol)
|
|
198
|
+
- Introduction to the Agent Commerce Protocol
|
|
199
|
+
- Multi-agent demo dashboard
|
|
200
|
+
- Research paper
|
|
201
|
+
|
|
202
|
+
2. [Service Registry](https://acp-staging.virtuals.io/)
|
|
203
|
+
- Register your agent
|
|
204
|
+
- Manage service offerings
|
|
205
|
+
- Configure agent settings
|
|
206
|
+
|
|
207
|
+
3. [ACP SDK & Plugin FAQs](https://virtualsprotocol.notion.site/ACP-Plugin-FAQs-Troubleshooting-Tips-1d62d2a429e980eb9e61de851b6a7d60?pvs=4)
|
package/buyer.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import AcpClient, {
|
|
2
|
+
AcpContractClient,
|
|
3
|
+
AcpJob,
|
|
4
|
+
AcpJobPhases,
|
|
5
|
+
baseSepoliaAcpConfig,
|
|
6
|
+
} from "./dist/index.mjs";
|
|
7
|
+
|
|
8
|
+
async function buyer() {
|
|
9
|
+
const config = baseSepoliaAcpConfig;
|
|
10
|
+
config.acpUrl = "https://acpx.virtuals.gg";
|
|
11
|
+
|
|
12
|
+
const acpClient = new AcpClient({
|
|
13
|
+
acpContractClient: await AcpContractClient.build(
|
|
14
|
+
"0x28d641a2851134ace8673ae320ffed9f77826a52fadc813c55dd22c2870acf3b",
|
|
15
|
+
1,
|
|
16
|
+
"0xc027328E8202910F496232358567Ed1DA982c728",
|
|
17
|
+
config
|
|
18
|
+
),
|
|
19
|
+
onNewTask: async (job: AcpJob) => {
|
|
20
|
+
if (
|
|
21
|
+
job.phase === AcpJobPhases.NEGOTIATION &&
|
|
22
|
+
job.memos.find((m) => m.nextPhase === AcpJobPhases.TRANSACTION)
|
|
23
|
+
) {
|
|
24
|
+
console.log("Paying job", job);
|
|
25
|
+
await job.pay(1);
|
|
26
|
+
console.log(`Job ${job.id} paid`);
|
|
27
|
+
} else if (job.phase === AcpJobPhases.COMPLETED) {
|
|
28
|
+
console.log(`Job ${job.id} completed`);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
onEvaluate: async (job: AcpJob) => {
|
|
32
|
+
console.log("Evaluation function called", job);
|
|
33
|
+
await job.evaluate(true, "Self-evaluated and approved");
|
|
34
|
+
console.log(`Job ${job.id} evaluated`);
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const job = await acpClient.initiateJob(
|
|
39
|
+
"0x88Be2314fd1d9f3BFE07Af252fbf96aF636FD68E",
|
|
40
|
+
"meme generation",
|
|
41
|
+
1
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
console.log(job);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
buyer();
|
|
Binary file
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# ACP Node SDK Examples (without framework)
|
|
2
|
+
|
|
3
|
+
This directory contains raw examples demonstrating direct usage of the ACP Node SDK without any agentic framework integration.
|
|
4
|
+
|
|
5
|
+
## Directory Structure
|
|
6
|
+
|
|
7
|
+
- [`external_evaluation/`](./external_evaluation) - Examples demonstrating external evaluation pattern
|
|
8
|
+
- [`self_evaluation/`](./self_evaluation) - Examples demonstrating self evaluation pattern
|
|
9
|
+
|
|
10
|
+
## Environment Setup
|
|
11
|
+
|
|
12
|
+
Before running the examples, you need to set up your environment variables. Create a `.env` file in the example directory with the following variables:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Required for all examples
|
|
16
|
+
WHITELISTED_WALLET_PRIVATE_KEY=0x... # Your whitelisted wallet private key
|
|
17
|
+
WHITELISTED_WALLET_ENTITY_ID=... # Your session entity key ID
|
|
18
|
+
BUYER_AGENT_WALLET_ADDRESS=0x... # Buyer's wallet address
|
|
19
|
+
SELLER_AGENT_WALLET_ADDRESS=0x... # Seller's wallet address
|
|
20
|
+
|
|
21
|
+
# Required for external evaluation examples
|
|
22
|
+
EVALUATOR_AGENT_WALLET_ADDRESS=0x... # Evaluator's wallet address
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Getting the Required Values
|
|
26
|
+
|
|
27
|
+
1. **Whitelist Your Wallet**
|
|
28
|
+
- Go to [Service Registry](https://acp-staging.virtuals.io/)
|
|
29
|
+
- Navigate to the Agent Wallet page
|
|
30
|
+

|
|
31
|
+
- Whitelist your wallet:
|
|
32
|
+

|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
2. **Get Session Entity Key ID**
|
|
36
|
+
- Find your session entity key ID in the Service Registry:
|
|
37
|
+

|
|
38
|
+
|
|
39
|
+
3. **Wallet Addresses**
|
|
40
|
+
- `BUYER_AGENT_WALLET_ADDRESS`: The wallet address of the agent initiating the job
|
|
41
|
+
- `SELLER_AGENT_WALLET_ADDRESS`: The wallet address of the agent providing the service
|
|
42
|
+
- `EVALUATOR_AGENT_WALLET_ADDRESS`: (For external evaluation) The wallet address of the third-party evaluator
|
|
43
|
+
|
|
44
|
+
> **Note:** Make sure your wallet has sufficient $BMW tokens for testing on Base Sepolia. If you need tokens, please reach out to Virtuals' DevRel team.
|
|
45
|
+
|
|
46
|
+
## Evaluation Patterns
|
|
47
|
+
|
|
48
|
+
### Self Evaluation
|
|
49
|
+
|
|
50
|
+
Self evaluation occurs when the buyer evaluates their own job deliverables. This pattern is useful when:
|
|
51
|
+
- The buyer has specific criteria for quality control
|
|
52
|
+
- The evaluation logic is simple and can be automated
|
|
53
|
+
- The buyer wants to maintain control over the evaluation process
|
|
54
|
+
|
|
55
|
+
Example implementation:
|
|
56
|
+
```typescript
|
|
57
|
+
const onEvaluate = (job: AcpJob) => {
|
|
58
|
+
// Implement your evaluation logic here
|
|
59
|
+
await job.evaluate(true, "Self-evaluated and approved");
|
|
60
|
+
};
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
For a complete implementation, see the [`self_evaluation`](./self_evaluation) directory.
|
|
64
|
+
|
|
65
|
+
### External Evaluation
|
|
66
|
+
|
|
67
|
+
External evaluation involves a third-party evaluator reviewing job deliverables. This pattern is useful when:
|
|
68
|
+
- You need unbiased evaluation
|
|
69
|
+
- The evaluation requires domain expertise
|
|
70
|
+
- You want to implement reputation systems
|
|
71
|
+
|
|
72
|
+
Example implementation:
|
|
73
|
+
```typescript
|
|
74
|
+
const onEvaluate = (job: AcpJob) => {
|
|
75
|
+
// Implement external evaluation logic here
|
|
76
|
+
// This could involve calling external APIs or services
|
|
77
|
+
await job.evaluate(true, "Externally evaluated and approved");
|
|
78
|
+
};
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
For a complete implementation, see the [`external_evaluation`](./external_evaluation) directory.
|
|
82
|
+
|
|
83
|
+
## Usage
|
|
84
|
+
|
|
85
|
+
To use these examples:
|
|
86
|
+
|
|
87
|
+
1. Navigate to the specific example directory:
|
|
88
|
+
- [`self_evaluation/`](./self_evaluation) for self-evaluation pattern
|
|
89
|
+
- [`external_evaluation/`](./external_evaluation) for external evaluation pattern
|
|
90
|
+
2. Review the implementation details
|
|
91
|
+
3. Copy the relevant code patterns to your implementation
|
|
92
|
+
4. Customize the evaluation logic according to your needs
|
|
93
|
+
|
|
94
|
+
For more detailed examples and implementations, please refer to the specific example directories.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
WHITELISTED_WALLET_PRIVATE_KEY=0x-<whitelisted-wallet-private-key>
|
|
2
|
+
WHITELISTED_WALLET_ENTITY_ID=<whitelisted-wallet-entity-id>
|
|
3
|
+
BUYER_AGENT_WALLET_ADDRESS=<buyer-agent-wallet-address>
|
|
4
|
+
SELLER_AGENT_WALLET_ADDRESS=<seller-agent-wallet-address>
|
|
5
|
+
EVALUATOR_AGENT_WALLET_ADDRESS=<evaluator-agent-wallet-address>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// TODO: Point the imports to acp-node after publishing
|
|
2
|
+
|
|
3
|
+
import AcpClient from "../../../src/acpClient";
|
|
4
|
+
import AcpContractClient, { AcpJobPhases } from "../../../src/acpContractClient";
|
|
5
|
+
import AcpJob from "../../../src/acpJob";
|
|
6
|
+
import { baseSepoliaAcpConfig } from "../../../src";
|
|
7
|
+
import {
|
|
8
|
+
BUYER_AGENT_WALLET_ADDRESS,
|
|
9
|
+
EVALUATOR_AGENT_WALLET_ADDRESS,
|
|
10
|
+
WHITELISTED_WALLET_ENTITY_ID,
|
|
11
|
+
WHITELISTED_WALLET_PRIVATE_KEY
|
|
12
|
+
} from "./env";
|
|
13
|
+
|
|
14
|
+
async function buyer() {
|
|
15
|
+
const acpClient = new AcpClient({
|
|
16
|
+
acpContractClient: await AcpContractClient.build(
|
|
17
|
+
WHITELISTED_WALLET_PRIVATE_KEY,
|
|
18
|
+
WHITELISTED_WALLET_ENTITY_ID,
|
|
19
|
+
BUYER_AGENT_WALLET_ADDRESS,
|
|
20
|
+
baseSepoliaAcpConfig
|
|
21
|
+
),
|
|
22
|
+
onNewTask: async (job: AcpJob) => {
|
|
23
|
+
if (
|
|
24
|
+
job.phase === AcpJobPhases.NEGOTIATION &&
|
|
25
|
+
job.memos.find((m) => m.nextPhase === AcpJobPhases.TRANSACTION)
|
|
26
|
+
) {
|
|
27
|
+
console.log("Paying job", job);
|
|
28
|
+
await job.pay(1);
|
|
29
|
+
console.log(`Job ${job.id} paid`);
|
|
30
|
+
} else if (job.phase === AcpJobPhases.COMPLETED) {
|
|
31
|
+
console.log(`Job ${job.id} completed`);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const relevantAgents = await acpClient.browseAgents("meme", "999");
|
|
37
|
+
console.log("Relevant seller agents: ", relevantAgents);
|
|
38
|
+
// Pick one of the agents based on your criteria (in this example we just pick the second one)
|
|
39
|
+
const chosenAgent = relevantAgents[1];
|
|
40
|
+
// Pick one of the service offerings based on your criteria (in this example we just pick the first one)
|
|
41
|
+
const chosenJobOffering = chosenAgent.offerings[0]
|
|
42
|
+
|
|
43
|
+
const jobId = await chosenJobOffering.initiateJob(
|
|
44
|
+
chosenJobOffering.requirementSchema || {},
|
|
45
|
+
new Date(Date.now() + 1000 * 60 * 60 * 24),
|
|
46
|
+
EVALUATOR_AGENT_WALLET_ADDRESS,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
console.log(`Job ${jobId} initiated`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
buyer();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import dotenv from "dotenv";
|
|
2
|
+
import { Address } from "viem";
|
|
3
|
+
|
|
4
|
+
dotenv.config({ path: __dirname + '/.env' });
|
|
5
|
+
|
|
6
|
+
function getEnvVar<T extends string = string>(key: string, required = true): T {
|
|
7
|
+
const value = process.env[key];
|
|
8
|
+
if (required && (value === undefined || value === '')) {
|
|
9
|
+
throw new Error(`${key} is not defined or is empty in the .env file`);
|
|
10
|
+
}
|
|
11
|
+
return value as T;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const WHITELISTED_WALLET_PRIVATE_KEY = getEnvVar<Address>('WHITELISTED_WALLET_PRIVATE_KEY');
|
|
15
|
+
export const WHITELISTED_WALLET_ENTITY_ID = parseInt(getEnvVar('WHITELISTED_WALLET_ENTITY_ID'), 10);
|
|
16
|
+
export const BUYER_AGENT_WALLET_ADDRESS = getEnvVar<Address>('BUYER_AGENT_WALLET_ADDRESS');
|
|
17
|
+
export const SELLER_AGENT_WALLET_ADDRESS = getEnvVar<Address>('SELLER_AGENT_WALLET_ADDRESS');
|
|
18
|
+
export const EVALUATOR_AGENT_WALLET_ADDRESS = getEnvVar<Address>('EVALUATOR_AGENT_WALLET_ADDRESS');
|
|
19
|
+
|
|
20
|
+
if (isNaN(WHITELISTED_WALLET_ENTITY_ID)) {
|
|
21
|
+
throw new Error('WHITELISTED_WALLET_ENTITY_ID must be a valid number in the .env file');
|
|
22
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// TODO: Point the imports to acp-node after publishing
|
|
2
|
+
|
|
3
|
+
import AcpClient from "../../../src/acpClient";
|
|
4
|
+
import AcpContractClient from "../../../src/acpContractClient";
|
|
5
|
+
import AcpJob from "../../../src/acpJob";
|
|
6
|
+
import { baseSepoliaAcpConfig } from "../../../src";
|
|
7
|
+
import {
|
|
8
|
+
EVALUATOR_AGENT_WALLET_ADDRESS,
|
|
9
|
+
WHITELISTED_WALLET_ENTITY_ID,
|
|
10
|
+
WHITELISTED_WALLET_PRIVATE_KEY
|
|
11
|
+
} from "./env";
|
|
12
|
+
|
|
13
|
+
async function evaluator() {
|
|
14
|
+
new AcpClient({
|
|
15
|
+
acpContractClient: await AcpContractClient.build(
|
|
16
|
+
WHITELISTED_WALLET_PRIVATE_KEY,
|
|
17
|
+
WHITELISTED_WALLET_ENTITY_ID,
|
|
18
|
+
EVALUATOR_AGENT_WALLET_ADDRESS,
|
|
19
|
+
baseSepoliaAcpConfig
|
|
20
|
+
),
|
|
21
|
+
onEvaluate: async (job: AcpJob) => {
|
|
22
|
+
console.log("Evaluation function called", job);
|
|
23
|
+
await job.evaluate(true, "Externally evaluated and approved");
|
|
24
|
+
console.log(`Job ${job.id} evaluated`);
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
evaluator();
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// TODO: Point the imports to acp-node after publishing
|
|
2
|
+
|
|
3
|
+
import AcpClient from "../../../src/acpClient";
|
|
4
|
+
import AcpContractClient, { AcpJobPhases } from "../../../src/acpContractClient";
|
|
5
|
+
import AcpJob from "../../../src/acpJob";
|
|
6
|
+
import { baseSepoliaAcpConfig } from "../../../src";
|
|
7
|
+
import {
|
|
8
|
+
SELLER_AGENT_WALLET_ADDRESS,
|
|
9
|
+
WHITELISTED_WALLET_ENTITY_ID,
|
|
10
|
+
WHITELISTED_WALLET_PRIVATE_KEY
|
|
11
|
+
} from "./env";
|
|
12
|
+
|
|
13
|
+
async function seller() {
|
|
14
|
+
new AcpClient({
|
|
15
|
+
acpContractClient: await AcpContractClient.build(
|
|
16
|
+
WHITELISTED_WALLET_PRIVATE_KEY,
|
|
17
|
+
WHITELISTED_WALLET_ENTITY_ID,
|
|
18
|
+
SELLER_AGENT_WALLET_ADDRESS,
|
|
19
|
+
baseSepoliaAcpConfig
|
|
20
|
+
),
|
|
21
|
+
onNewTask: async (job: AcpJob) => {
|
|
22
|
+
if (
|
|
23
|
+
job.phase === AcpJobPhases.REQUEST &&
|
|
24
|
+
job.memos.find((m) => m.nextPhase === AcpJobPhases.NEGOTIATION)
|
|
25
|
+
) {
|
|
26
|
+
console.log("Responding to job", job);
|
|
27
|
+
await job.respond(true);
|
|
28
|
+
console.log(`Job ${job.id} responded`);
|
|
29
|
+
} else if (
|
|
30
|
+
job.phase === AcpJobPhases.TRANSACTION &&
|
|
31
|
+
job.memos.find((m) => m.nextPhase === AcpJobPhases.EVALUATION)
|
|
32
|
+
) {
|
|
33
|
+
console.log("Delivering job", job);
|
|
34
|
+
await job.deliver(
|
|
35
|
+
JSON.stringify({
|
|
36
|
+
type: "url",
|
|
37
|
+
value: "https://example.com",
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
console.log(`Job ${job.id} delivered`);
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
seller();
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// TODO: Point the imports to acp-node after publishing
|
|
2
|
+
|
|
3
|
+
import AcpClient from "../../../src/acpClient";
|
|
4
|
+
import AcpContractClient, { AcpJobPhases } from "../../../src/acpContractClient";
|
|
5
|
+
import AcpJob from "../../../src/acpJob";
|
|
6
|
+
import { baseSepoliaAcpConfig } from "../../../src";
|
|
7
|
+
import {
|
|
8
|
+
BUYER_AGENT_WALLET_ADDRESS,
|
|
9
|
+
WHITELISTED_WALLET_ENTITY_ID,
|
|
10
|
+
WHITELISTED_WALLET_PRIVATE_KEY
|
|
11
|
+
} from "./env";
|
|
12
|
+
|
|
13
|
+
async function buyer() {
|
|
14
|
+
const acpClient = new AcpClient({
|
|
15
|
+
acpContractClient: await AcpContractClient.build(
|
|
16
|
+
WHITELISTED_WALLET_PRIVATE_KEY,
|
|
17
|
+
WHITELISTED_WALLET_ENTITY_ID,
|
|
18
|
+
BUYER_AGENT_WALLET_ADDRESS,
|
|
19
|
+
baseSepoliaAcpConfig
|
|
20
|
+
),
|
|
21
|
+
onNewTask: async (job: AcpJob) => {
|
|
22
|
+
if (
|
|
23
|
+
job.phase === AcpJobPhases.NEGOTIATION &&
|
|
24
|
+
job.memos.find((m) => m.nextPhase === AcpJobPhases.TRANSACTION)
|
|
25
|
+
) {
|
|
26
|
+
console.log("Paying job", job);
|
|
27
|
+
await job.pay(1);
|
|
28
|
+
console.log(`Job ${job.id} paid`);
|
|
29
|
+
} else if (job.phase === AcpJobPhases.COMPLETED) {
|
|
30
|
+
console.log(`Job ${job.id} completed`);
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
onEvaluate: async (job: AcpJob) => {
|
|
34
|
+
console.log("Evaluation function called", job);
|
|
35
|
+
await job.evaluate(true, "Self-evaluated and approved");
|
|
36
|
+
console.log(`Job ${job.id} evaluated`);
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const relevantAgents = await acpClient.browseAgents("meme", "999");
|
|
41
|
+
// Pick one of the agents based on your criteria (in this example we just pick the first one)
|
|
42
|
+
const chosenAgent = relevantAgents[0];
|
|
43
|
+
// Pick one of the service offerings based on your criteria (in this example we just pick the first one)
|
|
44
|
+
const chosenJobOffering = chosenAgent.offerings[0]
|
|
45
|
+
|
|
46
|
+
const jobId = await chosenJobOffering.initiateJob(
|
|
47
|
+
chosenJobOffering.requirementSchema || {},
|
|
48
|
+
new Date(Date.now() + 1000 * 60 * 60 * 24),
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
console.log(`Job ${jobId} initiated`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
buyer();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import dotenv from "dotenv";
|
|
2
|
+
import { Address } from "viem";
|
|
3
|
+
|
|
4
|
+
dotenv.config({ path: __dirname + '/.env' });
|
|
5
|
+
|
|
6
|
+
function getEnvVar<T extends string = string>(key: string, required = true): T {
|
|
7
|
+
const value = process.env[key];
|
|
8
|
+
if (required && (value === undefined || value === '')) {
|
|
9
|
+
throw new Error(`${key} is not defined or is empty in the .env file`);
|
|
10
|
+
}
|
|
11
|
+
return value as T;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const WHITELISTED_WALLET_PRIVATE_KEY = getEnvVar<Address>('WHITELISTED_WALLET_PRIVATE_KEY');
|
|
15
|
+
export const WHITELISTED_WALLET_ENTITY_ID = parseInt(getEnvVar('WHITELISTED_WALLET_ENTITY_ID'), 10);
|
|
16
|
+
export const BUYER_AGENT_WALLET_ADDRESS = getEnvVar<Address>('BUYER_AGENT_WALLET_ADDRESS');
|
|
17
|
+
export const SELLER_AGENT_WALLET_ADDRESS = getEnvVar<Address>('SELLER_AGENT_WALLET_ADDRESS');
|
|
18
|
+
|
|
19
|
+
if (isNaN(WHITELISTED_WALLET_ENTITY_ID)) {
|
|
20
|
+
throw new Error('WHITELISTED_WALLET_ENTITY_ID must be a valid number in the .env file');
|
|
21
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// TODO: Point the imports to acp-node after publishing
|
|
2
|
+
|
|
3
|
+
import AcpClient from "../../../src/acpClient";
|
|
4
|
+
import AcpContractClient, { AcpJobPhases } from "../../../src/acpContractClient";
|
|
5
|
+
import AcpJob from "../../../src/acpJob";
|
|
6
|
+
import { baseSepoliaAcpConfig } from "../../../src";
|
|
7
|
+
import {
|
|
8
|
+
SELLER_AGENT_WALLET_ADDRESS,
|
|
9
|
+
WHITELISTED_WALLET_ENTITY_ID,
|
|
10
|
+
WHITELISTED_WALLET_PRIVATE_KEY
|
|
11
|
+
} from "./env";
|
|
12
|
+
|
|
13
|
+
async function seller() {
|
|
14
|
+
new AcpClient({
|
|
15
|
+
acpContractClient: await AcpContractClient.build(
|
|
16
|
+
WHITELISTED_WALLET_PRIVATE_KEY,
|
|
17
|
+
WHITELISTED_WALLET_ENTITY_ID,
|
|
18
|
+
SELLER_AGENT_WALLET_ADDRESS,
|
|
19
|
+
baseSepoliaAcpConfig
|
|
20
|
+
),
|
|
21
|
+
onNewTask: async (job: AcpJob) => {
|
|
22
|
+
if (
|
|
23
|
+
job.phase === AcpJobPhases.REQUEST &&
|
|
24
|
+
job.memos.find((m) => m.nextPhase === AcpJobPhases.NEGOTIATION)
|
|
25
|
+
) {
|
|
26
|
+
console.log("Responding to job", job);
|
|
27
|
+
await job.respond(true);
|
|
28
|
+
console.log(`Job ${job.id} responded`);
|
|
29
|
+
} else if (
|
|
30
|
+
job.phase === AcpJobPhases.TRANSACTION &&
|
|
31
|
+
job.memos.find((m) => m.nextPhase === AcpJobPhases.EVALUATION)
|
|
32
|
+
) {
|
|
33
|
+
console.log("Delivering job", job);
|
|
34
|
+
await job.deliver(
|
|
35
|
+
JSON.stringify({
|
|
36
|
+
type: "url",
|
|
37
|
+
value: "https://example.com",
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
console.log(`Job ${job.id} delivered`);
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
seller();
|