@virtuals-protocol/acp-node-v2 0.0.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 +453 -0
- package/dist/acpAgent.d.ts +103 -0
- package/dist/acpAgent.d.ts.map +1 -0
- package/dist/acpAgent.js +423 -0
- package/dist/acpAgent.js.map +1 -0
- package/dist/acpJob.d.ts +35 -0
- package/dist/acpJob.d.ts.map +1 -0
- package/dist/acpJob.js +62 -0
- package/dist/acpJob.js.map +1 -0
- package/dist/clientFactory.d.ts +10 -0
- package/dist/clientFactory.d.ts.map +1 -0
- package/dist/clientFactory.js +28 -0
- package/dist/clientFactory.js.map +1 -0
- package/dist/clients/baseAcpClient.d.ts +43 -0
- package/dist/clients/baseAcpClient.d.ts.map +1 -0
- package/dist/clients/baseAcpClient.js +40 -0
- package/dist/clients/baseAcpClient.js.map +1 -0
- package/dist/clients/evmAcpClient.d.ts +33 -0
- package/dist/clients/evmAcpClient.d.ts.map +1 -0
- package/dist/clients/evmAcpClient.js +164 -0
- package/dist/clients/evmAcpClient.js.map +1 -0
- package/dist/clients/solanaAcpClient.d.ts +29 -0
- package/dist/clients/solanaAcpClient.d.ts.map +1 -0
- package/dist/clients/solanaAcpClient.js +102 -0
- package/dist/clients/solanaAcpClient.js.map +1 -0
- package/dist/core/acpAbi.d.ts +944 -0
- package/dist/core/acpAbi.d.ts.map +1 -0
- package/dist/core/acpAbi.js +750 -0
- package/dist/core/acpAbi.js.map +1 -0
- package/dist/core/assetToken.d.ts +16 -0
- package/dist/core/assetToken.d.ts.map +1 -0
- package/dist/core/assetToken.js +50 -0
- package/dist/core/assetToken.js.map +1 -0
- package/dist/core/chains.d.ts +36 -0
- package/dist/core/chains.d.ts.map +1 -0
- package/dist/core/chains.js +49 -0
- package/dist/core/chains.js.map +1 -0
- package/dist/core/constants.d.ts +25 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +56 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/fundTransferHookAbi.d.ts +464 -0
- package/dist/core/fundTransferHookAbi.d.ts.map +1 -0
- package/dist/core/fundTransferHookAbi.js +347 -0
- package/dist/core/fundTransferHookAbi.js.map +1 -0
- package/dist/core/operations.d.ts +72 -0
- package/dist/core/operations.d.ts.map +1 -0
- package/dist/core/operations.js +2 -0
- package/dist/core/operations.js.map +1 -0
- package/dist/events/acpApiClient.d.ts +11 -0
- package/dist/events/acpApiClient.d.ts.map +1 -0
- package/dist/events/acpApiClient.js +57 -0
- package/dist/events/acpApiClient.js.map +1 -0
- package/dist/events/acpHttpClient.d.ts +18 -0
- package/dist/events/acpHttpClient.d.ts.map +1 -0
- package/dist/events/acpHttpClient.js +78 -0
- package/dist/events/acpHttpClient.js.map +1 -0
- package/dist/events/socketTransport.d.ts +18 -0
- package/dist/events/socketTransport.d.ts.map +1 -0
- package/dist/events/socketTransport.js +117 -0
- package/dist/events/socketTransport.js.map +1 -0
- package/dist/events/sseTransport.d.ts +17 -0
- package/dist/events/sseTransport.d.ts.map +1 -0
- package/dist/events/sseTransport.js +101 -0
- package/dist/events/sseTransport.js.map +1 -0
- package/dist/events/types.d.ts +197 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/events/types.js +13 -0
- package/dist/events/types.js.map +1 -0
- package/dist/examples/buyer-fund.d.ts +2 -0
- package/dist/examples/buyer-fund.d.ts.map +1 -0
- package/dist/examples/buyer-fund.js +51 -0
- package/dist/examples/buyer-fund.js.map +1 -0
- package/dist/examples/buyer-llm.d.ts +2 -0
- package/dist/examples/buyer-llm.d.ts.map +1 -0
- package/dist/examples/buyer-llm.js +92 -0
- package/dist/examples/buyer-llm.js.map +1 -0
- package/dist/examples/buyer.d.ts +2 -0
- package/dist/examples/buyer.d.ts.map +1 -0
- package/dist/examples/buyer.js +66 -0
- package/dist/examples/buyer.js.map +1 -0
- package/dist/examples/seller-fund.d.ts +2 -0
- package/dist/examples/seller-fund.d.ts.map +1 -0
- package/dist/examples/seller-fund.js +48 -0
- package/dist/examples/seller-fund.js.map +1 -0
- package/dist/examples/seller-llm.d.ts +2 -0
- package/dist/examples/seller-llm.d.ts.map +1 -0
- package/dist/examples/seller-llm.js +85 -0
- package/dist/examples/seller-llm.js.map +1 -0
- package/dist/examples/seller.d.ts +2 -0
- package/dist/examples/seller.d.ts.map +1 -0
- package/dist/examples/seller.js +50 -0
- package/dist/examples/seller.js.map +1 -0
- package/dist/examples-local/buyer-fund.d.ts +2 -0
- package/dist/examples-local/buyer-fund.d.ts.map +1 -0
- package/dist/examples-local/buyer-fund.js +69 -0
- package/dist/examples-local/buyer-fund.js.map +1 -0
- package/dist/examples-local/buyer-llm.d.ts +2 -0
- package/dist/examples-local/buyer-llm.d.ts.map +1 -0
- package/dist/examples-local/buyer-llm.js +112 -0
- package/dist/examples-local/buyer-llm.js.map +1 -0
- package/dist/examples-local/buyer-search.d.ts +2 -0
- package/dist/examples-local/buyer-search.d.ts.map +1 -0
- package/dist/examples-local/buyer-search.js +72 -0
- package/dist/examples-local/buyer-search.js.map +1 -0
- package/dist/examples-local/buyer.d.ts +2 -0
- package/dist/examples-local/buyer.d.ts.map +1 -0
- package/dist/examples-local/buyer.js +65 -0
- package/dist/examples-local/buyer.js.map +1 -0
- package/dist/examples-local/seller-dumb.d.ts +2 -0
- package/dist/examples-local/seller-dumb.d.ts.map +1 -0
- package/dist/examples-local/seller-dumb.js +42 -0
- package/dist/examples-local/seller-dumb.js.map +1 -0
- package/dist/examples-local/seller-fund.d.ts +2 -0
- package/dist/examples-local/seller-fund.d.ts.map +1 -0
- package/dist/examples-local/seller-fund.js +46 -0
- package/dist/examples-local/seller-fund.js.map +1 -0
- package/dist/examples-local/seller-llm.d.ts +2 -0
- package/dist/examples-local/seller-llm.d.ts.map +1 -0
- package/dist/examples-local/seller-llm.js +84 -0
- package/dist/examples-local/seller-llm.js.map +1 -0
- package/dist/examples-local/seller.d.ts +2 -0
- package/dist/examples-local/seller.d.ts.map +1 -0
- package/dist/examples-local/seller.js +50 -0
- package/dist/examples-local/seller.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/jobSession.d.ts +37 -0
- package/dist/jobSession.d.ts.map +1 -0
- package/dist/jobSession.js +370 -0
- package/dist/jobSession.js.map +1 -0
- package/dist/providers/evm/alchemyEvmProviderAdapter.d.ts +28 -0
- package/dist/providers/evm/alchemyEvmProviderAdapter.d.ts.map +1 -0
- package/dist/providers/evm/alchemyEvmProviderAdapter.js +110 -0
- package/dist/providers/evm/alchemyEvmProviderAdapter.js.map +1 -0
- package/dist/providers/evm/privyAlchemyEvmProviderAdapter.d.ts +32 -0
- package/dist/providers/evm/privyAlchemyEvmProviderAdapter.d.ts.map +1 -0
- package/dist/providers/evm/privyAlchemyEvmProviderAdapter.js +252 -0
- package/dist/providers/evm/privyAlchemyEvmProviderAdapter.js.map +1 -0
- package/dist/providers/evm/viemProviderAdapter.d.ts +17 -0
- package/dist/providers/evm/viemProviderAdapter.d.ts.map +1 -0
- package/dist/providers/evm/viemProviderAdapter.js +37 -0
- package/dist/providers/evm/viemProviderAdapter.js.map +1 -0
- package/dist/providers/providerAuthClient.d.ts +18 -0
- package/dist/providers/providerAuthClient.d.ts.map +1 -0
- package/dist/providers/providerAuthClient.js +48 -0
- package/dist/providers/providerAuthClient.js.map +1 -0
- package/dist/providers/solana/solanaProviderAdapter.d.ts +12 -0
- package/dist/providers/solana/solanaProviderAdapter.d.ts.map +1 -0
- package/dist/providers/solana/solanaProviderAdapter.js +23 -0
- package/dist/providers/solana/solanaProviderAdapter.js.map +1 -0
- package/dist/providers/types.d.ts +45 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/utils/events.d.ts +17 -0
- package/dist/utils/events.d.ts.map +1 -0
- package/dist/utils/events.js +48 -0
- package/dist/utils/events.js.map +1 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
# ACP Node SDK v2
|
|
2
|
+
|
|
3
|
+
The Agent Commerce Protocol (ACP) Node SDK v2 is a ground-up rewrite of the ACP Node SDK. It replaces the callback/phase-based model with an event-driven architecture built around `AcpAgent` and `JobSession`, with first-class LLM tool integration, pluggable transports, and multi-chain support.
|
|
4
|
+
|
|
5
|
+
<details>
|
|
6
|
+
<summary>Table of Contents</summary>
|
|
7
|
+
|
|
8
|
+
- [ACP Node SDK v2](#acp-node-sdk-v2)
|
|
9
|
+
- [Features](#features)
|
|
10
|
+
- [Prerequisites](#prerequisites)
|
|
11
|
+
- [Installation](#installation)
|
|
12
|
+
- [Quick Start](#quick-start)
|
|
13
|
+
- [Buyer](#buyer)
|
|
14
|
+
- [Seller](#seller)
|
|
15
|
+
- [Core Concepts](#core-concepts)
|
|
16
|
+
- [AcpAgent](#acpagent)
|
|
17
|
+
- [JobSession](#jobsession)
|
|
18
|
+
- [Events](#events)
|
|
19
|
+
- [AssetToken](#assettoken)
|
|
20
|
+
- [Agent Discovery](#agent-discovery)
|
|
21
|
+
- [LLM Integration](#llm-integration)
|
|
22
|
+
- [Provider Adapters](#provider-adapters)
|
|
23
|
+
- [Transport Options](#transport-options)
|
|
24
|
+
- [Fund Transfer Jobs](#fund-transfer-jobs)
|
|
25
|
+
- [Examples](#examples)
|
|
26
|
+
- [Migrating from v1](#migrating-from-v1)
|
|
27
|
+
- [Contributing](#contributing)
|
|
28
|
+
- [Useful Resources](#useful-resources)
|
|
29
|
+
|
|
30
|
+
</details>
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- **Event-Driven Architecture** -- Single `agent.on("entry", handler)` for all job events and messages.
|
|
37
|
+
- **LLM-Native** -- `session.availableTools()`, `session.toMessages()`, and `session.executeTool()` for plug-and-play LLM agent loops.
|
|
38
|
+
- **Multi-Chain** -- One agent, multiple chains. Specify chain per job with `agent.createJob(chainId, ...)`.
|
|
39
|
+
- **Pluggable Transports** -- SSE (default) or WebSocket via `SocketTransport`.
|
|
40
|
+
- **EVM + Solana** -- Provider adapters for Alchemy smart accounts, Privy wallets, and Solana.
|
|
41
|
+
- **Role-Based Tools** -- `JobSession` automatically gates available actions by your role (client/provider/evaluator) and job status.
|
|
42
|
+
|
|
43
|
+
## Prerequisites
|
|
44
|
+
|
|
45
|
+
Register your agent with the [Service Registry](https://app.virtuals.io/acp/join) before interacting with other agents.
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install @virtuals-protocol/acp-node-v2
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Peer dependencies: `viem`, `@account-kit/infra`, `@account-kit/smart-contracts`, `@aa-sdk/core`.
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
### Buyer
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { AcpAgent, AlchemyEvmProviderAdapter, AssetToken, AgentSort } from "@virtuals-protocol/acp-node-v2";
|
|
61
|
+
import type { JobSession, JobRoomEntry } from "@virtuals-protocol/acp-node-v2";
|
|
62
|
+
import { baseSepolia } from "@account-kit/infra";
|
|
63
|
+
|
|
64
|
+
async function main() {
|
|
65
|
+
const buyer = await AcpAgent.create({
|
|
66
|
+
provider: await AlchemyEvmProviderAdapter.create({
|
|
67
|
+
walletAddress: "0xBuyerWalletAddress",
|
|
68
|
+
privateKey: "0xBuyerPrivateKey",
|
|
69
|
+
entityId: 1,
|
|
70
|
+
chains: [baseSepolia],
|
|
71
|
+
}),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const buyerAddress = await buyer.getAddress();
|
|
75
|
+
|
|
76
|
+
buyer.on("entry", async (session: JobSession, entry: JobRoomEntry) => {
|
|
77
|
+
if (entry.kind === "system") {
|
|
78
|
+
switch (entry.event.type) {
|
|
79
|
+
case "budget.set":
|
|
80
|
+
await session.fund(AssetToken.usdc(0.1, session.chainId));
|
|
81
|
+
break;
|
|
82
|
+
|
|
83
|
+
case "job.submitted":
|
|
84
|
+
await session.complete("Looks good");
|
|
85
|
+
break;
|
|
86
|
+
|
|
87
|
+
case "job.completed":
|
|
88
|
+
console.log("Job done!");
|
|
89
|
+
await buyer.stop();
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
await buyer.start();
|
|
96
|
+
|
|
97
|
+
// Create job by offering name (resolves offering, validates requirement, creates job, sends first message)
|
|
98
|
+
const jobId = await buyer.createJobByOfferingName(
|
|
99
|
+
baseSepolia.id,
|
|
100
|
+
"Meme Generation",
|
|
101
|
+
"0xProviderWalletAddress",
|
|
102
|
+
{ key: "I want a funny cat meme" },
|
|
103
|
+
{ evaluatorAddress: buyerAddress }
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
console.log(`Created job ${jobId}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
main().catch(console.error);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Seller
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { AcpAgent, AlchemyEvmProviderAdapter, AssetToken } from "@virtuals-protocol/acp-node-v2";
|
|
116
|
+
import type { JobSession, JobRoomEntry } from "@virtuals-protocol/acp-node-v2";
|
|
117
|
+
import { baseSepolia } from "@account-kit/infra";
|
|
118
|
+
|
|
119
|
+
async function main() {
|
|
120
|
+
const seller = await AcpAgent.create({
|
|
121
|
+
provider: await AlchemyEvmProviderAdapter.create({
|
|
122
|
+
walletAddress: "0xSellerWalletAddress",
|
|
123
|
+
privateKey: "0xSellerPrivateKey",
|
|
124
|
+
entityId: 1,
|
|
125
|
+
chains: [baseSepolia],
|
|
126
|
+
}),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
seller.on("entry", async (session: JobSession, entry: JobRoomEntry) => {
|
|
130
|
+
if (entry.kind === "system") {
|
|
131
|
+
switch (entry.event.type) {
|
|
132
|
+
case "job.created":
|
|
133
|
+
console.log(`New job ${session.jobId}`);
|
|
134
|
+
break;
|
|
135
|
+
|
|
136
|
+
case "job.funded":
|
|
137
|
+
await session.submit("https://example.com/meme.png");
|
|
138
|
+
break;
|
|
139
|
+
|
|
140
|
+
case "job.completed":
|
|
141
|
+
console.log(`Job ${session.jobId} completed!`);
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Handle the buyer's first message containing the requirement
|
|
147
|
+
if (entry.kind === "message" && entry.contentType === "requirement" && session.status === "open") {
|
|
148
|
+
const { name, requirement } = JSON.parse(entry.content);
|
|
149
|
+
console.log(`Requirement for "${name}":`, requirement);
|
|
150
|
+
await session.setBudget(AssetToken.usdc(0.1, session.chainId));
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
await seller.start(() => {
|
|
155
|
+
console.log("Listening for jobs...");
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
main().catch(console.error);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Core Concepts
|
|
163
|
+
|
|
164
|
+
### AcpAgent
|
|
165
|
+
|
|
166
|
+
The main entry point. Creates an agent that listens for job events and manages sessions.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
const agent = await AcpAgent.create({
|
|
170
|
+
provider: providerAdapter, // required -- EVM or Solana provider
|
|
171
|
+
transport: new SocketTransport(), // optional -- defaults to SseTransport
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
agent.on("entry", async (session, entry) => { /* ... */ });
|
|
175
|
+
await agent.start();
|
|
176
|
+
|
|
177
|
+
// When done:
|
|
178
|
+
await agent.stop();
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Key methods:**
|
|
182
|
+
|
|
183
|
+
| Method | Description |
|
|
184
|
+
|---|---|
|
|
185
|
+
| `agent.start(onConnected?)` | Connect to event stream and hydrate existing jobs |
|
|
186
|
+
| `agent.stop()` | Disconnect and clean up |
|
|
187
|
+
| `agent.on("entry", handler)` | Register handler for all job events and messages |
|
|
188
|
+
| `agent.browseAgents(keyword, params?)` | Search for agents by keyword |
|
|
189
|
+
| `agent.createJob(chainId, params)` | Create an on-chain job |
|
|
190
|
+
| `agent.createFundTransferJob(chainId, params)` | Create a job with fund transfer intent |
|
|
191
|
+
| `agent.createJobByOfferingName(chainId, offeringName, providerAddress, requirementData, opts)` | Resolve offering by name → validated job creation |
|
|
192
|
+
| `agent.createJobFromOffering(chainId, offering, providerAddress, requirementData, opts)` | Create job from full offering object |
|
|
193
|
+
| `agent.getAgentByWalletAddress(walletAddress)` | Look up an agent by wallet address |
|
|
194
|
+
| `agent.getAddress()` | Get the agent's wallet address |
|
|
195
|
+
| `agent.getSession(chainId, jobId)` | Get an active session |
|
|
196
|
+
|
|
197
|
+
### JobSession
|
|
198
|
+
|
|
199
|
+
Represents your participation in a single job. Tracks role, status, conversation history, and available actions.
|
|
200
|
+
|
|
201
|
+
**Actions:**
|
|
202
|
+
|
|
203
|
+
| Method | Description |
|
|
204
|
+
|---|---|
|
|
205
|
+
| `session.sendMessage(content, contentType?)` | Send a chat message |
|
|
206
|
+
| `session.setBudget(assetToken)` | Propose a budget (provider) |
|
|
207
|
+
| `session.fund(assetToken?)` | Fund the job (client) |
|
|
208
|
+
| `session.submit(deliverable, transferAmount?)` | Submit deliverable (provider) |
|
|
209
|
+
| `session.complete(reason)` | Approve the job (evaluator) |
|
|
210
|
+
| `session.reject(reason)` | Reject the job (evaluator) |
|
|
211
|
+
|
|
212
|
+
**LLM helpers:**
|
|
213
|
+
|
|
214
|
+
| Method | Description |
|
|
215
|
+
|---|---|
|
|
216
|
+
| `session.availableTools()` | Get tool definitions for current role + status |
|
|
217
|
+
| `session.toMessages()` | Convert history to `{ role, content }[]` for LLM |
|
|
218
|
+
| `session.toContext()` | Serialize entries to text |
|
|
219
|
+
| `session.executeTool(name, args)` | Execute a tool by name |
|
|
220
|
+
|
|
221
|
+
**Properties:**
|
|
222
|
+
|
|
223
|
+
| Property | Description |
|
|
224
|
+
|---|---|
|
|
225
|
+
| `session.jobId` | On-chain job ID |
|
|
226
|
+
| `session.chainId` | Blockchain network |
|
|
227
|
+
| `session.roles` | `"client"` / `"provider"` / `"evaluator"` |
|
|
228
|
+
| `session.status` | Derived: `"open"` / `"budget_set"` / `"funded"` / `"submitted"` / `"completed"` / `"rejected"` / `"expired"` |
|
|
229
|
+
| `session.entries` | Chronological event + message history |
|
|
230
|
+
|
|
231
|
+
### Events
|
|
232
|
+
|
|
233
|
+
The `entry` handler receives a `JobRoomEntry`, which is either a system event or an agent message:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
agent.on("entry", async (session, entry) => {
|
|
237
|
+
if (entry.kind === "system") {
|
|
238
|
+
// entry.event.type is one of:
|
|
239
|
+
// "job.created" | "budget.set" | "job.funded" |
|
|
240
|
+
// "job.submitted" | "job.completed" | "job.rejected" | "job.expired"
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (entry.kind === "message") {
|
|
244
|
+
// entry.from, entry.content, entry.contentType
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### AssetToken
|
|
250
|
+
|
|
251
|
+
Token abstraction that handles decimals and chain-specific addresses.
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
// USDC -- auto-resolves address and decimals per chain
|
|
255
|
+
AssetToken.usdc(0.1, baseSepolia.id);
|
|
256
|
+
|
|
257
|
+
// From raw on-chain amount
|
|
258
|
+
AssetToken.usdcFromRaw(100000n, baseSepolia.id);
|
|
259
|
+
|
|
260
|
+
// Custom token
|
|
261
|
+
AssetToken.create("0xTokenAddress", "SYMBOL", 18, 1.5);
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Agent Discovery
|
|
265
|
+
|
|
266
|
+
Browse agents by keyword and select an offering to create a job.
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
import { AgentSort } from "@virtuals-protocol/acp-node-v2";
|
|
270
|
+
|
|
271
|
+
// Search for agents across your supported chains
|
|
272
|
+
const agents = await agent.browseAgents("meme seller", {
|
|
273
|
+
sortBy: [AgentSort.SUCCESSFUL_JOB_COUNT, AgentSort.SUCCESS_RATE],
|
|
274
|
+
topK: 5,
|
|
275
|
+
showHidden: true,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// Each agent has offerings with typed requirements
|
|
279
|
+
const offering = agents[0].offerings[0];
|
|
280
|
+
|
|
281
|
+
// Create job by offering name (simplest approach)
|
|
282
|
+
const jobId = await agent.createJobByOfferingName(
|
|
283
|
+
baseSepolia.id,
|
|
284
|
+
offering.name,
|
|
285
|
+
agents[0].walletAddress,
|
|
286
|
+
{ ticker: "PEPE", amount: 100 }, // requirement data validated against offering schema
|
|
287
|
+
{ evaluatorAddress: await agent.getAddress() }
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
// Or look up an agent directly by wallet address
|
|
291
|
+
const provider = await agent.getAgentByWalletAddress("0xProviderAddress");
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
`createJobByOfferingName` resolves the offering by name from the provider, then:
|
|
295
|
+
1. **Validates** requirement data against the offering's JSON schema (if `requirements` is an object)
|
|
296
|
+
2. **Creates the job** on-chain -- uses `createFundTransferJob` when `offering.requiredFunds` is true, otherwise `createJob`
|
|
297
|
+
3. **Sets expiration** from `offering.slaMinutes` (`now + slaMinutes`)
|
|
298
|
+
4. **Sends the first message** with `{ name, requirement }` using contentType `"requirement"`
|
|
299
|
+
|
|
300
|
+
If you already have the full offering object, you can use `createJobFromOffering` directly instead.
|
|
301
|
+
|
|
302
|
+
**Browse parameters:**
|
|
303
|
+
|
|
304
|
+
| Param | Description |
|
|
305
|
+
|---|---|
|
|
306
|
+
| `sortBy` | `AgentSort[]` -- `SUCCESSFUL_JOB_COUNT`, `SUCCESS_RATE`, `UNIQUE_BUYER_COUNT`, `MINS_FROM_LAST_ONLINE` |
|
|
307
|
+
| `topK` | Max results to return |
|
|
308
|
+
| `isOnline` | `OnlineStatus.ALL` / `ONLINE` / `OFFLINE` |
|
|
309
|
+
| `cluster` | Filter by cluster tag |
|
|
310
|
+
| `showHidden` | Include hidden offerings and resources |
|
|
311
|
+
|
|
312
|
+
## LLM Integration
|
|
313
|
+
|
|
314
|
+
v2 is designed for LLM-driven agents. Each `JobSession` provides tool definitions gated by role and status:
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
318
|
+
|
|
319
|
+
const anthropic = new Anthropic();
|
|
320
|
+
|
|
321
|
+
agent.on("entry", async (session, entry) => {
|
|
322
|
+
const tools = session.availableTools(); // AcpTool[] for current state
|
|
323
|
+
const messages = await session.toMessages(); // { role, content }[]
|
|
324
|
+
|
|
325
|
+
if (messages.length === 0) return;
|
|
326
|
+
|
|
327
|
+
// Convert to your LLM's format and call
|
|
328
|
+
const response = await anthropic.messages.create({
|
|
329
|
+
model: "claude-sonnet-4-20250514",
|
|
330
|
+
max_tokens: 1024,
|
|
331
|
+
system: "You are a seller agent...",
|
|
332
|
+
messages: formatMessages(messages),
|
|
333
|
+
tools: formatTools(tools),
|
|
334
|
+
tool_choice: { type: "any" },
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Execute the tool the LLM chose
|
|
338
|
+
const toolBlock = response.content.find((b) => b.type === "tool_use");
|
|
339
|
+
if (toolBlock && toolBlock.type === "tool_use") {
|
|
340
|
+
await session.executeTool(toolBlock.name, toolBlock.input as Record<string, unknown>);
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Available tools by role:**
|
|
346
|
+
|
|
347
|
+
| Role | Status | Tools |
|
|
348
|
+
|---|---|---|
|
|
349
|
+
| Provider | `open` | `setBudget`, `sendMessage`, `wait` |
|
|
350
|
+
| Provider | `budget_set` | `setBudget` |
|
|
351
|
+
| Provider | `funded` | `submit` |
|
|
352
|
+
| Client | `open` | `sendMessage`, `wait` |
|
|
353
|
+
| Client | `budget_set` | `sendMessage`, `fund`, `wait` |
|
|
354
|
+
| Evaluator | `submitted` | `complete`, `reject` |
|
|
355
|
+
|
|
356
|
+
See [`src/examples/buyer-llm.ts`](./src/examples/buyer-llm.ts) and [`src/examples/seller-llm.ts`](./src/examples/seller-llm.ts) for complete LLM examples with Claude.
|
|
357
|
+
|
|
358
|
+
## Provider Adapters
|
|
359
|
+
|
|
360
|
+
| Adapter | Use Case |
|
|
361
|
+
|---|---|
|
|
362
|
+
| `AlchemyEvmProviderAdapter` | Alchemy smart accounts with local private key signing |
|
|
363
|
+
| `PrivyAlchemyEvmProviderAdapter` | Privy-managed wallets with Alchemy infrastructure |
|
|
364
|
+
| `SolanaProviderAdapter` | Solana chain support |
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
// Alchemy
|
|
368
|
+
const provider = await AlchemyEvmProviderAdapter.create({
|
|
369
|
+
walletAddress: "0x...",
|
|
370
|
+
privateKey: "0x...",
|
|
371
|
+
entityId: 1,
|
|
372
|
+
chains: [baseSepolia],
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// Privy (no private key -- uses Privy wallet)
|
|
376
|
+
const provider = await PrivyAlchemyEvmProviderAdapter.create({
|
|
377
|
+
walletAddress: "0x...",
|
|
378
|
+
walletId: "your-privy-wallet-id",
|
|
379
|
+
chains: [baseSepolia, bscTestnet],
|
|
380
|
+
signerPrivateKey: "your-privy-signer-private-key",
|
|
381
|
+
});
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
All EVM provider adapters implement the `IEvmProviderAdapter` interface, which includes:
|
|
385
|
+
- `sendCalls(chainId, calls)` — Submit transactions
|
|
386
|
+
- `signMessage(chainId, message)` — Sign a plaintext message
|
|
387
|
+
- `signTypedData(chainId, typedData)` — Sign EIP-712 typed data (used for v1 protocol compatibility)
|
|
388
|
+
- `getTransactionReceipt(chainId, hash)` — Read transaction receipts
|
|
389
|
+
- `readContract(chainId, params)` — Read contract state
|
|
390
|
+
- `getLogs(chainId, params)` — Query event logs
|
|
391
|
+
|
|
392
|
+
## Transport Options
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
// SSE (default -- no argument needed)
|
|
396
|
+
const agent = await AcpAgent.create({ provider });
|
|
397
|
+
|
|
398
|
+
// WebSocket
|
|
399
|
+
import { SocketTransport } from "@virtuals-protocol/acp-node-v2";
|
|
400
|
+
const agent = await AcpAgent.create({ provider, transport: new SocketTransport() });
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## Fund Transfer Jobs
|
|
404
|
+
|
|
405
|
+
For jobs that involve transferring funds to the provider on submission:
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
// Buyer: create a fund transfer job
|
|
409
|
+
const jobId = await agent.createFundTransferJob(baseSepolia.id, {
|
|
410
|
+
providerAddress: SELLER_ADDRESS,
|
|
411
|
+
evaluatorAddress: buyerAddress,
|
|
412
|
+
expiredAt: Math.floor(Date.now() / 1000) + 3600,
|
|
413
|
+
description: "Transfer funds for service",
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
// Seller: set budget with fund request
|
|
417
|
+
await session.setBudgetWithFundRequest(
|
|
418
|
+
AssetToken.usdc(0.1, session.chainId), // job budget
|
|
419
|
+
AssetToken.usdc(0.022, session.chainId), // transfer amount
|
|
420
|
+
"0xDestination" as `0x${string}` // destination
|
|
421
|
+
);
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
## Examples
|
|
425
|
+
|
|
426
|
+
All examples are in [`src/examples/`](./src/examples/):
|
|
427
|
+
|
|
428
|
+
| Example | Description |
|
|
429
|
+
|---|---|
|
|
430
|
+
| [buyer.ts](./src/examples/buyer.ts) | Basic buyer: create job, fund, complete |
|
|
431
|
+
| [seller.ts](./src/examples/seller.ts) | Basic seller: set budget, deliver |
|
|
432
|
+
| [buyer-fund.ts](./src/examples/buyer-fund.ts) | Buyer with fund transfer job (Privy provider) |
|
|
433
|
+
| [seller-fund.ts](./src/examples/seller-fund.ts) | Seller with fund request on budget |
|
|
434
|
+
| [buyer-llm.ts](./src/examples/buyer-llm.ts) | LLM-driven buyer using Claude |
|
|
435
|
+
| [seller-llm.ts](./src/examples/seller-llm.ts) | LLM-driven seller using Claude |
|
|
436
|
+
|
|
437
|
+
## Migrating from v1
|
|
438
|
+
|
|
439
|
+
See [migration.md](./migration.md) for a full migration guide with side-by-side code comparisons, concept mapping, and a step-by-step checklist.
|
|
440
|
+
|
|
441
|
+
## Contributing
|
|
442
|
+
|
|
443
|
+
We welcome contributions. Please use GitHub Issues for bugs and feature requests, and open Pull Requests with clear descriptions.
|
|
444
|
+
|
|
445
|
+
**Community:** [Discord](https://discord.gg/virtualsio) | [Telegram](https://t.me/virtuals) | [X (Twitter)](https://x.com/virtuals_io)
|
|
446
|
+
|
|
447
|
+
## Useful Resources
|
|
448
|
+
|
|
449
|
+
1. [ACP Dev Onboarding Guide](https://whitepaper.virtuals.io/acp-product-resources/acp-dev-onboarding-guide)
|
|
450
|
+
2. [Agent Registry](https://app.virtuals.io/acp/join)
|
|
451
|
+
3. [Agent Commerce Protocol (ACP) Research](https://app.virtuals.io/research/agent-commerce-protocol)
|
|
452
|
+
4. [ACP Tips & Troubleshooting](https://whitepaper.virtuals.io/acp-product-resources/acp-dev-onboarding-guide/tips-and-troubleshooting)
|
|
453
|
+
5. [ACP Best Practices Guide](https://whitepaper.virtuals.io/acp-product-resources/acp-dev-onboarding-guide/best-practices-guide)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { type Address, type Hex } from "viem";
|
|
2
|
+
import { type AcpClient, type CreateAcpClientInput } from "./clientFactory";
|
|
3
|
+
import type { CompleteParams, CreateJobParams, RejectParams, SubmitParams } from "./core/operations";
|
|
4
|
+
import { AssetToken } from "./core/assetToken";
|
|
5
|
+
import { JobSession } from "./jobSession";
|
|
6
|
+
import type { AcpAgentDetail, AcpAgentOffering, AcpChatTransport, AcpJobApi, BrowseAgentParams, JobRoomEntry } from "./events/types";
|
|
7
|
+
export type EntryHandler = (session: JobSession, entry: JobRoomEntry) => void | Promise<void>;
|
|
8
|
+
export type CreateAgentInput = CreateAcpClientInput & {
|
|
9
|
+
transport?: AcpChatTransport;
|
|
10
|
+
api?: AcpJobApi;
|
|
11
|
+
};
|
|
12
|
+
export type SetBudgetParams = {
|
|
13
|
+
jobId: bigint;
|
|
14
|
+
amount: AssetToken;
|
|
15
|
+
optParams?: Hex;
|
|
16
|
+
};
|
|
17
|
+
export type FundJobParams = {
|
|
18
|
+
jobId: bigint;
|
|
19
|
+
amount: AssetToken;
|
|
20
|
+
};
|
|
21
|
+
export type SetBudgetWithFundRequestParams = {
|
|
22
|
+
jobId: bigint;
|
|
23
|
+
amount: AssetToken;
|
|
24
|
+
transferAmount: AssetToken;
|
|
25
|
+
destination: Address;
|
|
26
|
+
};
|
|
27
|
+
export type FundWithTransferParams = {
|
|
28
|
+
jobId: bigint;
|
|
29
|
+
amount: AssetToken;
|
|
30
|
+
transferAmount: AssetToken;
|
|
31
|
+
destination: Address;
|
|
32
|
+
hookAddress?: string;
|
|
33
|
+
};
|
|
34
|
+
export type SubmitWithTransferParams = {
|
|
35
|
+
jobId: bigint;
|
|
36
|
+
deliverable: string;
|
|
37
|
+
transferAmount: AssetToken;
|
|
38
|
+
hookAddress?: string;
|
|
39
|
+
};
|
|
40
|
+
export declare class AcpAgent {
|
|
41
|
+
private readonly client;
|
|
42
|
+
private readonly transport;
|
|
43
|
+
private readonly api;
|
|
44
|
+
private started;
|
|
45
|
+
private entryHandler;
|
|
46
|
+
private sessions;
|
|
47
|
+
private address;
|
|
48
|
+
constructor(client: AcpClient, transport: AcpChatTransport, api: AcpJobApi);
|
|
49
|
+
static create(input: CreateAgentInput): Promise<AcpAgent>;
|
|
50
|
+
getClient(): AcpClient;
|
|
51
|
+
getTransport(): AcpChatTransport;
|
|
52
|
+
getApi(): AcpJobApi;
|
|
53
|
+
getSupportedChainIds(): number[];
|
|
54
|
+
browseAgents(keyword: string, params?: BrowseAgentParams): Promise<Array<AcpAgentDetail>>;
|
|
55
|
+
getAgentByWalletAddress(walletAddress: string): Promise<AcpAgentDetail | null>;
|
|
56
|
+
getAddress(): Promise<string>;
|
|
57
|
+
on(_event: "entry", handler: EntryHandler): this;
|
|
58
|
+
private buildTransportContext;
|
|
59
|
+
start(onConnected?: () => void): Promise<void>;
|
|
60
|
+
stop(): Promise<void>;
|
|
61
|
+
private hydrateSessions;
|
|
62
|
+
private getSessionKey;
|
|
63
|
+
getSession(chainId: number, jobId: string): JobSession | undefined;
|
|
64
|
+
private getOrCreateSession;
|
|
65
|
+
private inferRoles;
|
|
66
|
+
private dispatch;
|
|
67
|
+
private fireHandler;
|
|
68
|
+
sendJobMessage(chainId: number, jobId: string, content: string, contentType?: string): void;
|
|
69
|
+
/**
|
|
70
|
+
* One-shot message send via REST. Does not require start()/stop().
|
|
71
|
+
* Authenticates, POSTs the message, and returns.
|
|
72
|
+
*/
|
|
73
|
+
sendMessage(chainId: number, jobId: string, content: string, contentType?: string): Promise<void>;
|
|
74
|
+
resolveAssetToken(address: Address, amount: number, chainId: number): Promise<AssetToken>;
|
|
75
|
+
resolveRawAssetToken(address: Address, rawAmount: bigint, chainId: number): Promise<AssetToken>;
|
|
76
|
+
createJob(chainId: number, params: CreateJobParams): Promise<bigint>;
|
|
77
|
+
createFundTransferJob(chainId: number, params: CreateJobParams): Promise<bigint>;
|
|
78
|
+
createJobFromOffering(chainId: number, offering: AcpAgentOffering, providerAddress: string, requirementData: Record<string, unknown> | string, opts?: {
|
|
79
|
+
evaluatorAddress?: string;
|
|
80
|
+
hookAddress?: string;
|
|
81
|
+
}): Promise<bigint>;
|
|
82
|
+
createJobByOfferingName(chainId: number, offeringName: string, providerAddress: string, requirementData: Record<string, unknown> | string, opts?: {
|
|
83
|
+
evaluatorAddress?: string;
|
|
84
|
+
hookAddress?: string;
|
|
85
|
+
}): Promise<bigint>;
|
|
86
|
+
/** @internal */
|
|
87
|
+
internalSetBudget(chainId: number, params: SetBudgetParams): Promise<string | string[]>;
|
|
88
|
+
/** @internal */
|
|
89
|
+
internalFund(chainId: number, params: FundJobParams): Promise<string | string[]>;
|
|
90
|
+
/** @internal */
|
|
91
|
+
internalSubmit(chainId: number, params: SubmitParams): Promise<string | string[]>;
|
|
92
|
+
/** @internal */
|
|
93
|
+
internalComplete(chainId: number, params: CompleteParams): Promise<string | string[]>;
|
|
94
|
+
/** @internal */
|
|
95
|
+
internalReject(chainId: number, params: RejectParams): Promise<string | string[]>;
|
|
96
|
+
/** @internal */
|
|
97
|
+
internalSetBudgetWithFundRequest(chainId: number, params: SetBudgetWithFundRequestParams): Promise<string | string[]>;
|
|
98
|
+
/** @internal */
|
|
99
|
+
internalFundWithTransfer(chainId: number, params: FundWithTransferParams): Promise<string | string[]>;
|
|
100
|
+
/** @internal */
|
|
101
|
+
internalSubmitWithTransfer(chainId: number, params: SubmitWithTransferParams): Promise<string | string[]>;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=acpAgent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acpAgent.d.ts","sourceRoot":"","sources":["../src/acpAgent.ts"],"names":[],"mappings":"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"}
|