@reap-protocol/sdk 0.1.1 โ 0.1.3
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 +103 -0
- package/package.json +1 -1
- package/src/README.md +50 -18
- package/src/index.ts +200 -70
package/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# @reap-protocol/sdk
|
|
2
|
+
|
|
3
|
+
**The official TypeScript/Node.js SDK for the Reap Protocol: The Agentic Commerce Grid.**
|
|
4
|
+
|
|
5
|
+
The Reap Protocol enables AI Agents to search for products, register them on-chain, and execute atomic purchases without needing to understand smart contract ABIs. It acts as the bridge between Web2 products data and Web3 commerce settlement.
|
|
6
|
+
|
|
7
|
+
## ๐ฆ Installation
|
|
8
|
+
```bash
|
|
9
|
+
npm install @reap-protocol/sdk ethers axios
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## ๐ Quick Start
|
|
13
|
+
|
|
14
|
+
This example demonstrates the full Agentic Commerce Loop: Identity -> Discovery -> Settlement.
|
|
15
|
+
|
|
16
|
+
### 1. Setup
|
|
17
|
+
|
|
18
|
+
If using TypeScript, ensure your tsconfig.json targets ES2020 or higher.
|
|
19
|
+
|
|
20
|
+
### 2. The Agent Code (agent.ts)
|
|
21
|
+
```typescript
|
|
22
|
+
import { ReapClient } from "@reap-protocol/sdk";
|
|
23
|
+
|
|
24
|
+
// Load your private key securely
|
|
25
|
+
const PRIVATE_KEY = process.env.MY_WALLET_KEY || "";
|
|
26
|
+
|
|
27
|
+
async function main() {
|
|
28
|
+
// 1. Initialize the Agent
|
|
29
|
+
// (Points to official middleware by default)
|
|
30
|
+
const client = new ReapClient(PRIVATE_KEY);
|
|
31
|
+
console.log("๐ค Agent Online");
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
// 2. Identity (One-time setup)
|
|
35
|
+
// Registers your wallet as an authorized Agent on the Protocol
|
|
36
|
+
console.log("๐ Checking Identity...");
|
|
37
|
+
await client.registerIdentity();
|
|
38
|
+
|
|
39
|
+
// 3. JIT Stocking (Discovery)
|
|
40
|
+
// Searches Web2 (Reap Deals), registers items on-chain, and returns inventory
|
|
41
|
+
console.log("๐ฆ Stocking Shelf with 'Gaming Laptop'...");
|
|
42
|
+
const result = await client.stockShelf("Gaming Laptop");
|
|
43
|
+
|
|
44
|
+
const inventory = result.items;
|
|
45
|
+
console.log(` ๐ Found ${inventory.length} items on-chain.`);
|
|
46
|
+
|
|
47
|
+
if (inventory.length > 0) {
|
|
48
|
+
// 4. Decision Logic
|
|
49
|
+
// Example: Pick the first available item
|
|
50
|
+
const target = inventory[0];
|
|
51
|
+
console.log(` ๐ฏ Selected: ${target.name} ($${target.price})`);
|
|
52
|
+
console.log(` ID: ${target.id}`);
|
|
53
|
+
|
|
54
|
+
// 5. Agentic Cart (Settlement)
|
|
55
|
+
// Automatically approves USDC and executes the atomic purchase
|
|
56
|
+
console.log("๐ธ Buying Item...");
|
|
57
|
+
const receipt = await client.buyProduct(target.id);
|
|
58
|
+
|
|
59
|
+
if (receipt) {
|
|
60
|
+
console.log(`๐ SUCCESS! Transaction Hash: ${receipt.hash}`);
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
console.log("โ No items found.");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
} catch (e: any) {
|
|
67
|
+
console.error("โ Error:", e.message);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
main();
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3. Run It
|
|
75
|
+
```bash
|
|
76
|
+
# Install execution tools if you haven't already
|
|
77
|
+
npm install --save-dev ts-node typescript @types/node
|
|
78
|
+
|
|
79
|
+
# Run
|
|
80
|
+
npx ts-node agent.ts
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## ๐ง Configuration
|
|
84
|
+
|
|
85
|
+
You can override defaults for custom RPCs or self-hosted middleware.
|
|
86
|
+
```typescript
|
|
87
|
+
const client = new ReapClient(
|
|
88
|
+
"YOUR_PRIVATE_KEY",
|
|
89
|
+
"https://base-sepolia.g.alchemy.com/v2/YOUR_KEY", // Custom RPC
|
|
90
|
+
"https://api.reap.deals" // Middleware URL
|
|
91
|
+
);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## โจ Features
|
|
95
|
+
|
|
96
|
+
* **JIT Stocking**: "Just-In-Time" inventory system. If an agent searches for an item not yet on the blockchain, the Protocol indexes it in real-time.
|
|
97
|
+
* **Agentic Cart**: Automatically routes purchases through the Protocol's batch processor.
|
|
98
|
+
* **Protocol Negotiation**: Built-in support for HTTP 402 Payment Negotiation loops.
|
|
99
|
+
* **Gas Optimized**: Checks on-chain state before sending registration transactions.
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
MIT
|
package/package.json
CHANGED
package/src/README.md
CHANGED
|
@@ -11,7 +11,8 @@ npm install @reap-protocol/sdk ethers axios
|
|
|
11
11
|
|
|
12
12
|
## ๐ Quick Start
|
|
13
13
|
|
|
14
|
-
This example demonstrates the full Agentic Commerce Loop: Identity -> Discovery -> Settlement.
|
|
14
|
+
This example demonstrates the full Agentic Commerce Loop: Identity -> Discovery -> Smart Sync -> Settlement.
|
|
15
|
+
|
|
15
16
|
|
|
16
17
|
### 1. Setup
|
|
17
18
|
|
|
@@ -23,11 +24,14 @@ import { ReapClient } from "@reap-protocol/sdk";
|
|
|
23
24
|
|
|
24
25
|
// Load your private key securely
|
|
25
26
|
const PRIVATE_KEY = process.env.MY_WALLET_KEY || "";
|
|
27
|
+
const CHAIN_RPC = "https://api.avax-test.network/ext/bc/C/rpc";
|
|
26
28
|
|
|
27
29
|
async function main() {
|
|
28
30
|
// 1. Initialize the Agent
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
const client = new ReapClient(PRIVATE_KEY, CHAIN_RPC);
|
|
32
|
+
|
|
33
|
+
// Wait for Chain ID initialization
|
|
34
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
31
35
|
console.log("๐ค Agent Online");
|
|
32
36
|
|
|
33
37
|
try {
|
|
@@ -36,25 +40,36 @@ async function main() {
|
|
|
36
40
|
console.log("๐ Checking Identity...");
|
|
37
41
|
await client.registerIdentity();
|
|
38
42
|
|
|
39
|
-
// 3.
|
|
40
|
-
//
|
|
41
|
-
console.log("๐ฆ
|
|
42
|
-
|
|
43
|
+
// 3. Discovery (Dry Run Mode)
|
|
44
|
+
// Pass 'true' to get the items AND the transactions without executing them yet.
|
|
45
|
+
console.log("๐ฆ Browsing for 'Gaming Laptop'...");
|
|
46
|
+
|
|
47
|
+
// dryRun = true
|
|
48
|
+
const result = await client.stockShelf("Gaming Laptop", true);
|
|
43
49
|
|
|
44
|
-
const inventory = result.items;
|
|
45
|
-
|
|
50
|
+
const inventory = result.items || [];
|
|
51
|
+
const transactions = result.transactions || [];
|
|
52
|
+
|
|
53
|
+
console.log(` ๐ Found ${inventory.length} items.`);
|
|
46
54
|
|
|
47
55
|
if (inventory.length > 0) {
|
|
48
56
|
// 4. Decision Logic
|
|
49
|
-
//
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
// Pick the first item and its corresponding registration transaction
|
|
58
|
+
const targetItem = inventory[0];
|
|
59
|
+
const targetTx = transactions[0];
|
|
60
|
+
|
|
61
|
+
console.log(` ๐ฏ Selected: ${targetItem.name} ($${targetItem.price})`);
|
|
53
62
|
|
|
54
|
-
// 5.
|
|
63
|
+
// 5. Smart Sync (The "Gas Saver")
|
|
64
|
+
// Checks the Holocron (Index) first.
|
|
65
|
+
// If the item exists, it skips registration.
|
|
66
|
+
// If not, it executes the targetTx and indexes it.
|
|
67
|
+
await client.smartSync(targetItem, targetTx);
|
|
68
|
+
|
|
69
|
+
// 6. Agentic Cart (Settlement)
|
|
55
70
|
// Automatically approves USDC and executes the atomic purchase
|
|
56
71
|
console.log("๐ธ Buying Item...");
|
|
57
|
-
const receipt = await client.buyProduct(
|
|
72
|
+
const receipt = await client.buyProduct(targetItem.id);
|
|
58
73
|
|
|
59
74
|
if (receipt) {
|
|
60
75
|
console.log(`๐ SUCCESS! Transaction Hash: ${receipt.hash}`);
|
|
@@ -80,23 +95,40 @@ npm install --save-dev ts-node typescript @types/node
|
|
|
80
95
|
npx ts-node agent.ts
|
|
81
96
|
```
|
|
82
97
|
|
|
98
|
+
## ๐ต๏ธ Agent Discovery (New)
|
|
99
|
+
|
|
100
|
+
You can now search for other AI Agents (MCP, x402, A2A).
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
// 1. Search for Agents
|
|
104
|
+
// Registries: 'mcp' (AI Models), 'x402' (Payment Agents), 'a2a' (Autonomous)
|
|
105
|
+
const agents = await client.searchAgents("ecommerce", "x402");
|
|
106
|
+
|
|
107
|
+
if (agents.length > 0) {
|
|
108
|
+
const targetAgent = agents[0];
|
|
109
|
+
console.log(`Found: ${targetAgent.name}`);
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
83
113
|
## ๐ง Configuration
|
|
84
114
|
|
|
85
115
|
You can override defaults for custom RPCs or self-hosted middleware.
|
|
86
116
|
```typescript
|
|
87
117
|
const client = new ReapClient(
|
|
88
118
|
"YOUR_PRIVATE_KEY",
|
|
89
|
-
"https://
|
|
90
|
-
"https://api.reap.deals" // Middleware URL
|
|
119
|
+
"https://avax-fuji.g.alchemy.com/v2/YOUR_KEY", // Custom RPC
|
|
120
|
+
"https://avax2.api.reap.deals" // Middleware URL
|
|
91
121
|
);
|
|
92
122
|
```
|
|
93
123
|
|
|
94
124
|
## โจ Features
|
|
95
125
|
|
|
126
|
+
* **Agent Discovery**: Search thousands of AI Agents from MCP, x402, and A2A registries.
|
|
96
127
|
* **JIT Stocking**: "Just-In-Time" inventory system. If an agent searches for an item not yet on the blockchain, the Protocol indexes it in real-time.
|
|
97
128
|
* **Agentic Cart**: Automatically routes purchases through the Protocol's batch processor.
|
|
98
129
|
* **Protocol Negotiation**: Built-in support for HTTP 402 Payment Negotiation loops.
|
|
99
|
-
|
|
130
|
+
|
|
131
|
+
|
|
100
132
|
|
|
101
133
|
## License
|
|
102
134
|
|
package/src/index.ts
CHANGED
|
@@ -1,31 +1,90 @@
|
|
|
1
1
|
import { ethers } from "ethers";
|
|
2
|
-
import axios
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
|
|
4
|
+
// ==========================================
|
|
5
|
+
// CONSTANTS & CONFIGURATION
|
|
6
|
+
// ==========================================
|
|
7
|
+
|
|
8
|
+
const HOLOCRON_ROUTER_ADDRESS = "0x2cEC5Bf3a0D3fEe4E13e8f2267176BdD579F4fd8";
|
|
9
|
+
|
|
10
|
+
const NETWORKS: Record<string, string> = {
|
|
11
|
+
"BASE": "https://sepolia.base.org",
|
|
12
|
+
"AVAX": "https://api.avax-test.network/ext/bc/C/rpc",
|
|
13
|
+
"CELO": "https://forno.celo-sepolia.celo-testnet.org"
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const HOLOCRON_ABI = [
|
|
17
|
+
"function checkExistence(uint256 _c) view returns (bool)",
|
|
18
|
+
"function stock(uint256 _c) external"
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// --- Agent Registry Configuration ---
|
|
22
|
+
export type AgentRegistry = 'mcp' | 'x402' | 'a2a';
|
|
23
|
+
|
|
24
|
+
const REGISTRY_MAP: Record<AgentRegistry, string> = {
|
|
25
|
+
"mcp": "pulsemcp",
|
|
26
|
+
"x402": "coinbase-x402-bazaar",
|
|
27
|
+
"a2a": "a2a-registry"
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const SEARCH_API_URL = "https://www.reap.deals/api/search-agents";
|
|
31
|
+
|
|
32
|
+
// ==========================================
|
|
33
|
+
// REAP CLIENT CLASS
|
|
34
|
+
// ==========================================
|
|
3
35
|
|
|
4
36
|
export class ReapClient {
|
|
5
37
|
private wallet: ethers.Wallet;
|
|
6
38
|
private builderUrl: string;
|
|
7
39
|
private provider: ethers.JsonRpcProvider;
|
|
40
|
+
private holocron: ethers.Contract;
|
|
41
|
+
private chainId: number = 43113;
|
|
8
42
|
|
|
9
43
|
constructor(
|
|
10
44
|
privateKey: string,
|
|
11
45
|
chainRpc: string = "https://avalanche-fuji.drpc.org",
|
|
12
|
-
builderUrl: string = "https://api.reap.deals"
|
|
46
|
+
builderUrl: string = "https://avax2.api.reap.deals"
|
|
13
47
|
) {
|
|
14
48
|
this.provider = new ethers.JsonRpcProvider(chainRpc);
|
|
15
49
|
this.wallet = new ethers.Wallet(privateKey, this.provider);
|
|
16
|
-
this.builderUrl = builderUrl.replace(/\/$/, "");
|
|
17
|
-
|
|
50
|
+
this.builderUrl = builderUrl.replace(/\/$/, "");
|
|
51
|
+
|
|
52
|
+
// Initialize Holocron Contract
|
|
53
|
+
this.holocron = new ethers.Contract(HOLOCRON_ROUTER_ADDRESS, HOLOCRON_ABI, this.wallet);
|
|
54
|
+
|
|
55
|
+
this.init();
|
|
18
56
|
}
|
|
19
57
|
|
|
20
58
|
/**
|
|
21
|
-
*
|
|
22
|
-
|
|
59
|
+
* Async initialization to fetch Chain ID
|
|
60
|
+
*/
|
|
61
|
+
private async init() {
|
|
62
|
+
try {
|
|
63
|
+
const net = await this.provider.getNetwork();
|
|
64
|
+
this.chainId = Number(net.chainId);
|
|
65
|
+
console.log(`๐ค Reap Agent Online: ${this.wallet.address} (Chain: ${this.chainId})`);
|
|
66
|
+
} catch (e) {
|
|
67
|
+
console.error("โ ๏ธ Failed to fetch chain ID. Defaulting to 43113.");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ==========================================
|
|
72
|
+
// CORE TRANSACTION LOGIC
|
|
73
|
+
// ==========================================
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Execute Transactions with Nonce & Gas Fixes.
|
|
77
|
+
* Handles sequential nonce increments locally to prevent RPC lag.
|
|
23
78
|
*/
|
|
24
79
|
private async executeTransactions(txList: any[]) {
|
|
25
80
|
let lastReceipt;
|
|
26
81
|
|
|
27
82
|
// 1. Fetch Nonce ONCE
|
|
28
83
|
let currentNonce = await this.provider.getTransactionCount(this.wallet.address, "pending");
|
|
84
|
+
|
|
85
|
+
// 2. Gas Price Buffer (1.1x) for fast propagation
|
|
86
|
+
const feeData = await this.provider.getFeeData();
|
|
87
|
+
const gasPrice = feeData.gasPrice ? (feeData.gasPrice * 110n) / 100n : undefined;
|
|
29
88
|
|
|
30
89
|
for (const txData of txList) {
|
|
31
90
|
const label = txData.label || "Transaction";
|
|
@@ -35,33 +94,29 @@ export class ReapClient {
|
|
|
35
94
|
to: txData.to,
|
|
36
95
|
data: txData.data,
|
|
37
96
|
value: BigInt(txData.value),
|
|
38
|
-
gasLimit: 500000, //
|
|
97
|
+
gasLimit: 500000, // Safe default limit
|
|
39
98
|
nonce: currentNonce,
|
|
40
|
-
chainId:
|
|
99
|
+
chainId: this.chainId,
|
|
100
|
+
gasPrice: gasPrice
|
|
41
101
|
};
|
|
42
102
|
|
|
43
103
|
try {
|
|
44
|
-
// 2. Sign & Send
|
|
45
104
|
const response = await this.wallet.sendTransaction(tx);
|
|
46
105
|
console.log(` ๐ Broadcasting: ${response.hash}`);
|
|
47
106
|
|
|
48
|
-
// 3. Wait
|
|
49
107
|
const receipt = await response.wait();
|
|
50
108
|
|
|
51
|
-
// 4. Check Status (1 = Success, 0 = Revert)
|
|
52
109
|
if (receipt && receipt.status === 0) {
|
|
53
110
|
throw new Error(`Transaction Reverted! Hash: ${receipt.hash}`);
|
|
54
111
|
}
|
|
55
112
|
|
|
56
113
|
console.log(` โ
Settled on-chain.`);
|
|
57
114
|
lastReceipt = receipt;
|
|
58
|
-
|
|
59
|
-
// 5. Increment Nonce
|
|
60
115
|
currentNonce++;
|
|
61
116
|
|
|
62
117
|
} catch (e: any) {
|
|
63
118
|
console.error(` โ Tx Failed: ${e.message}`);
|
|
64
|
-
|
|
119
|
+
// Stop execution if payment or approval fails. Continue for others if needed.
|
|
65
120
|
if (label.includes("Approve") || label.includes("Payment")) throw e;
|
|
66
121
|
}
|
|
67
122
|
}
|
|
@@ -70,23 +125,125 @@ export class ReapClient {
|
|
|
70
125
|
|
|
71
126
|
private async callBuilder(endpoint: string, payload: any) {
|
|
72
127
|
try {
|
|
73
|
-
|
|
74
|
-
|
|
128
|
+
// Inject Chain ID for Middleware routing
|
|
129
|
+
payload.chain_id = this.chainId;
|
|
130
|
+
const { data } = await axios.post(`${this.builderUrl}${endpoint}`, payload);
|
|
131
|
+
return data;
|
|
75
132
|
} catch (error: any) {
|
|
76
133
|
const msg = error.response?.data?.detail || error.message;
|
|
77
134
|
throw new Error(`Reap Protocol Error: ${msg}`);
|
|
78
135
|
}
|
|
79
136
|
}
|
|
80
137
|
|
|
81
|
-
//
|
|
138
|
+
// ==========================================
|
|
139
|
+
// HOLOCRON & SMART SYNC
|
|
140
|
+
// ==========================================
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Check if a coordinate exists in the Holocron Registry.
|
|
144
|
+
*/
|
|
145
|
+
async checkHolocron(coordinate: string) {
|
|
146
|
+
console.log(`๐ Scanning Holocron for ${coordinate}...`);
|
|
147
|
+
|
|
148
|
+
let exists = false;
|
|
149
|
+
try {
|
|
150
|
+
exists = await this.holocron.checkExistence(BigInt(coordinate));
|
|
151
|
+
} catch (e) { exists = false; }
|
|
152
|
+
|
|
153
|
+
console.log(` โข Holocron Index: ${exists ? 'โ
FOUND' : 'โ EMPTY'}`);
|
|
154
|
+
return exists;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Internal method to execute the 'stock' function on the Holocron.
|
|
159
|
+
*/
|
|
160
|
+
private async indexToHolocron(coordinate: string) {
|
|
161
|
+
console.log(` ๐ Indexing Coordinate ${coordinate} to Holocron...`);
|
|
162
|
+
|
|
163
|
+
const nonce = await this.provider.getTransactionCount(this.wallet.address, "pending");
|
|
164
|
+
const feeData = await this.provider.getFeeData();
|
|
165
|
+
const gasPrice = feeData.gasPrice ? (feeData.gasPrice * 110n) / 100n : undefined;
|
|
82
166
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
167
|
+
const tx = await this.holocron.stock(BigInt(coordinate), {
|
|
168
|
+
gasLimit: 150000,
|
|
169
|
+
nonce,
|
|
170
|
+
gasPrice
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
console.log(` ๐ Broadcast Holocron TX: ${tx.hash}`);
|
|
174
|
+
await tx.wait();
|
|
175
|
+
console.log(" โ
Index Updated.");
|
|
176
|
+
|
|
177
|
+
// Small sleep to let RPC sync
|
|
178
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
87
179
|
}
|
|
88
180
|
|
|
89
|
-
|
|
181
|
+
/**
|
|
182
|
+
* Smart Sync: Checks Holocron first.
|
|
183
|
+
* If item exists -> Skip registration (Save Gas).
|
|
184
|
+
* If missing -> Execute registration TX -> Index to Holocron.
|
|
185
|
+
*/
|
|
186
|
+
async smartSync(item: any, transaction: any) {
|
|
187
|
+
const coordinate = item.id;
|
|
188
|
+
|
|
189
|
+
// 1. Check Status
|
|
190
|
+
const onHolocron = await this.checkHolocron(coordinate);
|
|
191
|
+
|
|
192
|
+
if (onHolocron) {
|
|
193
|
+
console.log("โก๏ธ Fast Path: Item is indexed. Skipping registration.");
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
console.log("\n๐ข Syncing to Chain (Full Path)...");
|
|
198
|
+
|
|
199
|
+
// 2. Register Data (if transaction exists)
|
|
200
|
+
if (transaction) {
|
|
201
|
+
console.log(" ๐ธ Registering Data on-chain...");
|
|
202
|
+
// Wrap single transaction in array
|
|
203
|
+
await this.executeTransactions([transaction]);
|
|
204
|
+
} else {
|
|
205
|
+
console.log(" โ ๏ธ No registration transaction provided. Skipping to index.");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 3. Index on Holocron
|
|
209
|
+
await this.indexToHolocron(coordinate);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ==========================================
|
|
213
|
+
// AGENT DISCOVERY (NEW)
|
|
214
|
+
// ==========================================
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Search for AI Agents across different registries (MCP, x402, A2A).
|
|
218
|
+
* @param query Keywords to search for (e.g. "customer support", "ecommerce")
|
|
219
|
+
* @param registry 'mcp' | 'x402' | 'a2a'
|
|
220
|
+
* @param limit Max results (default 40)
|
|
221
|
+
*/
|
|
222
|
+
async searchAgents(query: string, registry: AgentRegistry = 'mcp', limit: number = 40) {
|
|
223
|
+
console.log(`๐ Searching Registry [${REGISTRY_MAP[registry]}] for: "${query}"...`);
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
const payload = {
|
|
227
|
+
limit: limit,
|
|
228
|
+
query: query,
|
|
229
|
+
registry: REGISTRY_MAP[registry] // Maps 'mcp' -> 'pulsemcp', etc.
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const response = await axios.post(SEARCH_API_URL, payload);
|
|
233
|
+
const hits = response.data.hits || [];
|
|
234
|
+
|
|
235
|
+
console.log(` โ
Found ${hits.length} agents.`);
|
|
236
|
+
return hits;
|
|
237
|
+
|
|
238
|
+
} catch (error: any) {
|
|
239
|
+
console.error(" โ Search Failed:", error.message);
|
|
240
|
+
return [];
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ==========================================
|
|
245
|
+
// PUBLIC API (Commerce & Identity)
|
|
246
|
+
// ==========================================
|
|
90
247
|
|
|
91
248
|
async registerIdentity(profileUri: string = "ipfs://default") {
|
|
92
249
|
console.log("๐ Registering Protocol Identity...");
|
|
@@ -96,40 +253,45 @@ export class ReapClient {
|
|
|
96
253
|
});
|
|
97
254
|
|
|
98
255
|
if (res.status === "already_registered") {
|
|
99
|
-
console.log(` โ
Already Registered (Agent #${res.agent_id}). Skipping
|
|
256
|
+
console.log(` โ
Already Registered (Agent #${res.agent_id}). Skipping.`);
|
|
100
257
|
return null;
|
|
101
258
|
}
|
|
102
|
-
|
|
103
259
|
return this.executeTransactions(res.transactions);
|
|
104
260
|
}
|
|
105
261
|
|
|
106
|
-
|
|
107
|
-
|
|
262
|
+
/**
|
|
263
|
+
* Search for Products/Inventory.
|
|
264
|
+
* Use dryRun=true to get items without executing on-chain registration immediately.
|
|
265
|
+
*/
|
|
266
|
+
async stockShelf(productQuery: string, dryRun: boolean = false) {
|
|
267
|
+
console.log(`๐ฆ Stocking Shelf: '${productQuery}' (Dry Run: ${dryRun})`);
|
|
268
|
+
|
|
108
269
|
const res = await this.callBuilder("/build/inventory/stock", {
|
|
109
270
|
product_query: productQuery,
|
|
110
271
|
provider_address: this.wallet.address
|
|
111
272
|
});
|
|
112
273
|
|
|
274
|
+
const items = res.meta?.items || [];
|
|
275
|
+
const transactions = res.transactions || [];
|
|
276
|
+
|
|
113
277
|
if (res.status === "payment_required") {
|
|
114
|
-
console.log("๐ 402 Payment Required
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
278
|
+
console.log("๐ 402 Payment Required.");
|
|
279
|
+
if (dryRun) return { receipt: null, items: [] };
|
|
280
|
+
const receipt = await this.executeTransactions(transactions);
|
|
281
|
+
return { receipt, items: [] };
|
|
118
282
|
}
|
|
119
283
|
|
|
120
|
-
|
|
284
|
+
if (dryRun) {
|
|
285
|
+
console.log(` ๐ Preview: Found ${items.length} items. Cached ${transactions.length} TXs.`);
|
|
286
|
+
return { receipt: null, items, transactions };
|
|
287
|
+
}
|
|
121
288
|
|
|
122
|
-
|
|
123
|
-
return {
|
|
124
|
-
receipt,
|
|
125
|
-
items: res.meta?.items || []
|
|
126
|
-
};
|
|
127
|
-
// ----------------------------------------------
|
|
289
|
+
const receipt = await this.executeTransactions(transactions);
|
|
290
|
+
return { receipt, items };
|
|
128
291
|
}
|
|
129
292
|
|
|
130
293
|
async buyProduct(productId: string) {
|
|
131
294
|
console.log(`๐ธ Initiating Agentic Cart (Single Item): ${productId}`);
|
|
132
|
-
// Route to batch endpoint
|
|
133
295
|
const res = await this.callBuilder("/build/commerce/batch", {
|
|
134
296
|
product_ids: [productId]
|
|
135
297
|
});
|
|
@@ -143,36 +305,4 @@ async stockShelf(productQuery: string) {
|
|
|
143
305
|
});
|
|
144
306
|
return this.executeTransactions(res.transactions);
|
|
145
307
|
}
|
|
146
|
-
|
|
147
|
-
async fetch(url: string, config: AxiosRequestConfig = {}) {
|
|
148
|
-
console.log(`๐ Accessing ${url}...`);
|
|
149
|
-
try {
|
|
150
|
-
return await axios.get(url, config);
|
|
151
|
-
} catch (error: any) {
|
|
152
|
-
if (error.response && error.response.status === 402) {
|
|
153
|
-
console.log("๐ x402 Payment Required. Engaging Protocol...");
|
|
154
|
-
const header = error.response.headers["www-authenticate"];
|
|
155
|
-
|
|
156
|
-
if (header && header.includes("X402")) {
|
|
157
|
-
const match = header.match(/resource_id="([^"]+)"/);
|
|
158
|
-
if (match && match[1]) {
|
|
159
|
-
const rid = match[1];
|
|
160
|
-
|
|
161
|
-
// Pay Protocol
|
|
162
|
-
const receipt = await this.buyProduct(rid);
|
|
163
|
-
|
|
164
|
-
if (!receipt) throw new Error("Payment Transaction failed");
|
|
165
|
-
const proof = receipt.hash;
|
|
166
|
-
|
|
167
|
-
console.log(` ๐ Submitting Proof for Reactive Release: ${proof}`);
|
|
168
|
-
|
|
169
|
-
// Release Data
|
|
170
|
-
const newConfig = { ...config, headers: { ...config.headers, "Authorization": `X402-Proof ${proof}` } };
|
|
171
|
-
return await axios.get(url, newConfig);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
throw error;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
308
|
}
|