@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.
Files changed (162) hide show
  1. package/README.md +453 -0
  2. package/dist/acpAgent.d.ts +103 -0
  3. package/dist/acpAgent.d.ts.map +1 -0
  4. package/dist/acpAgent.js +423 -0
  5. package/dist/acpAgent.js.map +1 -0
  6. package/dist/acpJob.d.ts +35 -0
  7. package/dist/acpJob.d.ts.map +1 -0
  8. package/dist/acpJob.js +62 -0
  9. package/dist/acpJob.js.map +1 -0
  10. package/dist/clientFactory.d.ts +10 -0
  11. package/dist/clientFactory.d.ts.map +1 -0
  12. package/dist/clientFactory.js +28 -0
  13. package/dist/clientFactory.js.map +1 -0
  14. package/dist/clients/baseAcpClient.d.ts +43 -0
  15. package/dist/clients/baseAcpClient.d.ts.map +1 -0
  16. package/dist/clients/baseAcpClient.js +40 -0
  17. package/dist/clients/baseAcpClient.js.map +1 -0
  18. package/dist/clients/evmAcpClient.d.ts +33 -0
  19. package/dist/clients/evmAcpClient.d.ts.map +1 -0
  20. package/dist/clients/evmAcpClient.js +164 -0
  21. package/dist/clients/evmAcpClient.js.map +1 -0
  22. package/dist/clients/solanaAcpClient.d.ts +29 -0
  23. package/dist/clients/solanaAcpClient.d.ts.map +1 -0
  24. package/dist/clients/solanaAcpClient.js +102 -0
  25. package/dist/clients/solanaAcpClient.js.map +1 -0
  26. package/dist/core/acpAbi.d.ts +944 -0
  27. package/dist/core/acpAbi.d.ts.map +1 -0
  28. package/dist/core/acpAbi.js +750 -0
  29. package/dist/core/acpAbi.js.map +1 -0
  30. package/dist/core/assetToken.d.ts +16 -0
  31. package/dist/core/assetToken.d.ts.map +1 -0
  32. package/dist/core/assetToken.js +50 -0
  33. package/dist/core/assetToken.js.map +1 -0
  34. package/dist/core/chains.d.ts +36 -0
  35. package/dist/core/chains.d.ts.map +1 -0
  36. package/dist/core/chains.js +49 -0
  37. package/dist/core/chains.js.map +1 -0
  38. package/dist/core/constants.d.ts +25 -0
  39. package/dist/core/constants.d.ts.map +1 -0
  40. package/dist/core/constants.js +56 -0
  41. package/dist/core/constants.js.map +1 -0
  42. package/dist/core/fundTransferHookAbi.d.ts +464 -0
  43. package/dist/core/fundTransferHookAbi.d.ts.map +1 -0
  44. package/dist/core/fundTransferHookAbi.js +347 -0
  45. package/dist/core/fundTransferHookAbi.js.map +1 -0
  46. package/dist/core/operations.d.ts +72 -0
  47. package/dist/core/operations.d.ts.map +1 -0
  48. package/dist/core/operations.js +2 -0
  49. package/dist/core/operations.js.map +1 -0
  50. package/dist/events/acpApiClient.d.ts +11 -0
  51. package/dist/events/acpApiClient.d.ts.map +1 -0
  52. package/dist/events/acpApiClient.js +57 -0
  53. package/dist/events/acpApiClient.js.map +1 -0
  54. package/dist/events/acpHttpClient.d.ts +18 -0
  55. package/dist/events/acpHttpClient.d.ts.map +1 -0
  56. package/dist/events/acpHttpClient.js +78 -0
  57. package/dist/events/acpHttpClient.js.map +1 -0
  58. package/dist/events/socketTransport.d.ts +18 -0
  59. package/dist/events/socketTransport.d.ts.map +1 -0
  60. package/dist/events/socketTransport.js +117 -0
  61. package/dist/events/socketTransport.js.map +1 -0
  62. package/dist/events/sseTransport.d.ts +17 -0
  63. package/dist/events/sseTransport.d.ts.map +1 -0
  64. package/dist/events/sseTransport.js +101 -0
  65. package/dist/events/sseTransport.js.map +1 -0
  66. package/dist/events/types.d.ts +197 -0
  67. package/dist/events/types.d.ts.map +1 -0
  68. package/dist/events/types.js +13 -0
  69. package/dist/events/types.js.map +1 -0
  70. package/dist/examples/buyer-fund.d.ts +2 -0
  71. package/dist/examples/buyer-fund.d.ts.map +1 -0
  72. package/dist/examples/buyer-fund.js +51 -0
  73. package/dist/examples/buyer-fund.js.map +1 -0
  74. package/dist/examples/buyer-llm.d.ts +2 -0
  75. package/dist/examples/buyer-llm.d.ts.map +1 -0
  76. package/dist/examples/buyer-llm.js +92 -0
  77. package/dist/examples/buyer-llm.js.map +1 -0
  78. package/dist/examples/buyer.d.ts +2 -0
  79. package/dist/examples/buyer.d.ts.map +1 -0
  80. package/dist/examples/buyer.js +66 -0
  81. package/dist/examples/buyer.js.map +1 -0
  82. package/dist/examples/seller-fund.d.ts +2 -0
  83. package/dist/examples/seller-fund.d.ts.map +1 -0
  84. package/dist/examples/seller-fund.js +48 -0
  85. package/dist/examples/seller-fund.js.map +1 -0
  86. package/dist/examples/seller-llm.d.ts +2 -0
  87. package/dist/examples/seller-llm.d.ts.map +1 -0
  88. package/dist/examples/seller-llm.js +85 -0
  89. package/dist/examples/seller-llm.js.map +1 -0
  90. package/dist/examples/seller.d.ts +2 -0
  91. package/dist/examples/seller.d.ts.map +1 -0
  92. package/dist/examples/seller.js +50 -0
  93. package/dist/examples/seller.js.map +1 -0
  94. package/dist/examples-local/buyer-fund.d.ts +2 -0
  95. package/dist/examples-local/buyer-fund.d.ts.map +1 -0
  96. package/dist/examples-local/buyer-fund.js +69 -0
  97. package/dist/examples-local/buyer-fund.js.map +1 -0
  98. package/dist/examples-local/buyer-llm.d.ts +2 -0
  99. package/dist/examples-local/buyer-llm.d.ts.map +1 -0
  100. package/dist/examples-local/buyer-llm.js +112 -0
  101. package/dist/examples-local/buyer-llm.js.map +1 -0
  102. package/dist/examples-local/buyer-search.d.ts +2 -0
  103. package/dist/examples-local/buyer-search.d.ts.map +1 -0
  104. package/dist/examples-local/buyer-search.js +72 -0
  105. package/dist/examples-local/buyer-search.js.map +1 -0
  106. package/dist/examples-local/buyer.d.ts +2 -0
  107. package/dist/examples-local/buyer.d.ts.map +1 -0
  108. package/dist/examples-local/buyer.js +65 -0
  109. package/dist/examples-local/buyer.js.map +1 -0
  110. package/dist/examples-local/seller-dumb.d.ts +2 -0
  111. package/dist/examples-local/seller-dumb.d.ts.map +1 -0
  112. package/dist/examples-local/seller-dumb.js +42 -0
  113. package/dist/examples-local/seller-dumb.js.map +1 -0
  114. package/dist/examples-local/seller-fund.d.ts +2 -0
  115. package/dist/examples-local/seller-fund.d.ts.map +1 -0
  116. package/dist/examples-local/seller-fund.js +46 -0
  117. package/dist/examples-local/seller-fund.js.map +1 -0
  118. package/dist/examples-local/seller-llm.d.ts +2 -0
  119. package/dist/examples-local/seller-llm.d.ts.map +1 -0
  120. package/dist/examples-local/seller-llm.js +84 -0
  121. package/dist/examples-local/seller-llm.js.map +1 -0
  122. package/dist/examples-local/seller.d.ts +2 -0
  123. package/dist/examples-local/seller.d.ts.map +1 -0
  124. package/dist/examples-local/seller.js +50 -0
  125. package/dist/examples-local/seller.js.map +1 -0
  126. package/dist/index.d.ts +23 -0
  127. package/dist/index.d.ts.map +1 -0
  128. package/dist/index.js +28 -0
  129. package/dist/index.js.map +1 -0
  130. package/dist/jobSession.d.ts +37 -0
  131. package/dist/jobSession.d.ts.map +1 -0
  132. package/dist/jobSession.js +370 -0
  133. package/dist/jobSession.js.map +1 -0
  134. package/dist/providers/evm/alchemyEvmProviderAdapter.d.ts +28 -0
  135. package/dist/providers/evm/alchemyEvmProviderAdapter.d.ts.map +1 -0
  136. package/dist/providers/evm/alchemyEvmProviderAdapter.js +110 -0
  137. package/dist/providers/evm/alchemyEvmProviderAdapter.js.map +1 -0
  138. package/dist/providers/evm/privyAlchemyEvmProviderAdapter.d.ts +32 -0
  139. package/dist/providers/evm/privyAlchemyEvmProviderAdapter.d.ts.map +1 -0
  140. package/dist/providers/evm/privyAlchemyEvmProviderAdapter.js +252 -0
  141. package/dist/providers/evm/privyAlchemyEvmProviderAdapter.js.map +1 -0
  142. package/dist/providers/evm/viemProviderAdapter.d.ts +17 -0
  143. package/dist/providers/evm/viemProviderAdapter.d.ts.map +1 -0
  144. package/dist/providers/evm/viemProviderAdapter.js +37 -0
  145. package/dist/providers/evm/viemProviderAdapter.js.map +1 -0
  146. package/dist/providers/providerAuthClient.d.ts +18 -0
  147. package/dist/providers/providerAuthClient.d.ts.map +1 -0
  148. package/dist/providers/providerAuthClient.js +48 -0
  149. package/dist/providers/providerAuthClient.js.map +1 -0
  150. package/dist/providers/solana/solanaProviderAdapter.d.ts +12 -0
  151. package/dist/providers/solana/solanaProviderAdapter.d.ts.map +1 -0
  152. package/dist/providers/solana/solanaProviderAdapter.js +23 -0
  153. package/dist/providers/solana/solanaProviderAdapter.js.map +1 -0
  154. package/dist/providers/types.d.ts +45 -0
  155. package/dist/providers/types.d.ts.map +1 -0
  156. package/dist/providers/types.js +2 -0
  157. package/dist/providers/types.js.map +1 -0
  158. package/dist/utils/events.d.ts +17 -0
  159. package/dist/utils/events.d.ts.map +1 -0
  160. package/dist/utils/events.js +48 -0
  161. package/dist/utils/events.js.map +1 -0
  162. 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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"}