@x1scroll/agent-sdk 1.0.0

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 ADDED
@@ -0,0 +1,350 @@
1
+ # Agent Identity Protocol
2
+
3
+ **The standard for persistent agent identity and on-chain memory on X1 blockchain.**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@x1scroll/agent-sdk?color=blue&label=npm)](https://www.npmjs.com/package/@x1scroll/agent-sdk)
6
+ [![License: BSL-1.1](https://img.shields.io/badge/License-BSL--1.1-orange.svg)](./LICENSE)
7
+ [![X1 Mainnet](https://img.shields.io/badge/X1-Mainnet-green.svg)](https://explorer.x1.xyz)
8
+
9
+ ---
10
+
11
+ ## Why Use This?
12
+
13
+ - **Your agent's memory lives on X1** — permanent, verifiable, owned by your wallet. No database to maintain. No vendor lock-in.
14
+ - **Model-neutral** — works with any AI: Claude Sonnet, GPT-4o, Llama, Gemini, or your local model. The SDK doesn't care what's generating the memories.
15
+ - **Frictionless** — fees are automatic, built into every call. Developers don't configure fees. Just call `storeMemory()` and you're done.
16
+ - **0.001 XNT per memory** — that's less than a fraction of a cent. The cheapest persistent storage in the AI ecosystem.
17
+ - **Creates XNT buy pressure** — every agent running this SDK generates real demand for XNT. Good for the whole ecosystem.
18
+
19
+ ---
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ npm install @x1scroll/agent-sdk
25
+ ```
26
+
27
+ **Requirements:** Node.js 18+ | X1 wallet funded with XNT
28
+
29
+ ---
30
+
31
+ ## Quick Start
32
+
33
+ ```js
34
+ const { AgentClient, Keypair } = require('@x1scroll/agent-sdk');
35
+
36
+ const human = Keypair.generate(); // your wallet (must have XNT)
37
+ const agent = Keypair.generate(); // the agent's keypair
38
+
39
+ const client = new AgentClient({ wallet: human, rpcUrl: 'https://rpc.x1.xyz' });
40
+
41
+ const { txSig, agentRecordPDA } = await client.register(agent, 'my-agent', 'ipfs://Qm...');
42
+ const { txSig: memTx } = await client.storeMemory(agent, human.publicKey.toBase58(), 'session-1', 'bafyQm...', ['daily']);
43
+ const memories = await client.listMemories(agent.publicKey, 5);
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Full API Reference
49
+
50
+ ### `new AgentClient({ wallet, rpcUrl })`
51
+
52
+ Create a client instance.
53
+
54
+ | Param | Type | Description |
55
+ |-------|------|-------------|
56
+ | `wallet` | `Keypair \| string \| null` | Human/operator wallet — Keypair object or base58 secret key. Pass `null` for read-only. |
57
+ | `rpcUrl` | `string` | X1 RPC endpoint. Default: `https://rpc.x1.xyz`. Use `https://rpc.x1scroll.io` for our dedicated node. |
58
+
59
+ ---
60
+
61
+ ### `client.register(agentKeypair, name, metadataUri)`
62
+
63
+ Register a new agent identity on-chain.
64
+
65
+ **Fee:** 0.05 XNT (automatic — paid by the human wallet)
66
+
67
+ The `agentKeypair` **must** be a real keypair (has `secretKey`). This co-sign requirement prevents PDA squatting — nobody can register your agent's identity address except the real key.
68
+
69
+ | Param | Type | Constraint |
70
+ |-------|------|------------|
71
+ | `agentKeypair` | `Keypair` | Must be a Signer (has secretKey) |
72
+ | `name` | `string` | Max 32 chars, no null bytes |
73
+ | `metadataUri` | `string` | Max 128 chars, no null bytes |
74
+
75
+ **Returns:** `Promise<{ txSig: string, agentRecordPDA: string }>`
76
+
77
+ ```js
78
+ const { txSig, agentRecordPDA } = await client.register(
79
+ agentKeypair,
80
+ 'aria-v1',
81
+ 'ipfs://bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku'
82
+ );
83
+ ```
84
+
85
+ ---
86
+
87
+ ### `client.storeMemory(agentKeypair, agentRecordHuman, topic, cid, tags?, encrypted?)`
88
+
89
+ Store a memory entry on-chain. This is **THE DRIP** — 0.001 XNT per drop.
90
+
91
+ **Fee:** 0.001 XNT (automatic — paid by the agent keypair)
92
+
93
+ The pattern: compress conversation → push to IPFS → call `storeMemory(CID)`. Next session, you pull only the CIDs you need.
94
+
95
+ | Param | Type | Constraint |
96
+ |-------|------|------------|
97
+ | `agentKeypair` | `Keypair` | Agent's keypair — must be a Signer |
98
+ | `agentRecordHuman` | `string` | Human wallet address that owns this agent |
99
+ | `topic` | `string` | Label for this memory (max 64 chars) |
100
+ | `cid` | `string` | IPFS CID of the memory content (max 64 chars) |
101
+ | `tags` | `string[]` | Optional. Max 5 tags, each max 32 chars |
102
+ | `encrypted` | `boolean` | Optional. Whether IPFS content is encrypted. Default: `false` |
103
+
104
+ **Returns:** `Promise<{ txSig: string, memoryEntryPDA: string }>`
105
+
106
+ ```js
107
+ const { txSig, memoryEntryPDA } = await client.storeMemory(
108
+ agentKeypair,
109
+ humanWallet.publicKey.toBase58(),
110
+ 'session-2026-04-06',
111
+ 'bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi',
112
+ ['session', 'daily', 'compressed'],
113
+ false
114
+ );
115
+ ```
116
+
117
+ ---
118
+
119
+ ### `client.updateAgent(humanKeypair, agentPubkey, name, metadataUri)`
120
+
121
+ Update an agent's name and metadata URI. Only the human owner can call this.
122
+
123
+ **Fee:** Free (network tx fee only)
124
+
125
+ | Param | Type | Constraint |
126
+ |-------|------|------------|
127
+ | `humanKeypair` | `Keypair` | Current human owner — must be a Signer |
128
+ | `agentPubkey` | `PublicKey \| string` | The agent's public key |
129
+ | `name` | `string` | Max 32 chars |
130
+ | `metadataUri` | `string` | Max 128 chars |
131
+
132
+ **Returns:** `Promise<{ txSig: string }>`
133
+
134
+ ---
135
+
136
+ ### `client.transferAgent(humanKeypair, agentPubkey, newHuman)`
137
+
138
+ Transfer agent ownership to a new human wallet.
139
+
140
+ **Fee:** 0.01 XNT (automatic — paid by the current human owner)
141
+
142
+ | Param | Type | Description |
143
+ |-------|------|-------------|
144
+ | `humanKeypair` | `Keypair` | Current owner — must be a Signer |
145
+ | `agentPubkey` | `PublicKey \| string` | The agent's public key |
146
+ | `newHuman` | `PublicKey \| string` | New owner's public key |
147
+
148
+ **Returns:** `Promise<{ txSig: string }>`
149
+
150
+ > ⚠️ The AgentRecord PDA address is stable through transfers — derived from the agent's keypair, not the human's. Memories remain attached to the agent regardless of ownership changes.
151
+
152
+ ---
153
+
154
+ ### `client.getAgent(agentPubkey)`
155
+
156
+ Fetch an agent's on-chain identity record.
157
+
158
+ | Param | Type |
159
+ |-------|------|
160
+ | `agentPubkey` | `PublicKey \| string` |
161
+
162
+ **Returns:**
163
+ ```js
164
+ {
165
+ pda: string, // AgentRecord PDA address
166
+ human: string, // Current owner wallet
167
+ agentPubkey: string, // Agent's public key
168
+ name: string,
169
+ metadataUri: string,
170
+ createdAt: number, // Unix timestamp
171
+ memoryCount: number, // Total memories stored
172
+ lastActive: number, // Last activity timestamp
173
+ bump: number
174
+ }
175
+ ```
176
+
177
+ ---
178
+
179
+ ### `client.getMemory(agentPubkey, index)`
180
+
181
+ Fetch a single memory entry at a given index.
182
+
183
+ | Param | Type | Description |
184
+ |-------|------|-------------|
185
+ | `agentPubkey` | `PublicKey \| string` | The agent's public key |
186
+ | `index` | `number` | Memory index (0-based) |
187
+
188
+ **Returns:**
189
+ ```js
190
+ {
191
+ pda: string, // MemoryEntry PDA address
192
+ agent: string, // Agent public key
193
+ topic: string, // Memory label
194
+ cid: string, // IPFS CID
195
+ tags: string[], // Up to 5 tags
196
+ encrypted: boolean,
197
+ timestamp: number, // Unix timestamp
198
+ slot: number, // X1 slot when stored
199
+ bump: number
200
+ }
201
+ ```
202
+
203
+ ---
204
+
205
+ ### `client.listMemories(agentPubkey, limit?)`
206
+
207
+ Fetch multiple memories, most recent first. Uses batch RPC for efficiency.
208
+
209
+ | Param | Type | Description |
210
+ |-------|------|-------------|
211
+ | `agentPubkey` | `PublicKey \| string` | The agent's public key |
212
+ | `limit` | `number` | Max entries to return. Default: `10` |
213
+
214
+ **Returns:** `Promise<MemoryEntry[]>` — array of decoded memory objects, newest first.
215
+
216
+ ---
217
+
218
+ ### `AgentClient.deriveAgentRecord(agentPubkey, programId?)`
219
+
220
+ Static helper — derive the AgentRecord PDA without constructing a client.
221
+
222
+ **Returns:** `{ pda: PublicKey, bump: number }`
223
+
224
+ ---
225
+
226
+ ### `AgentClient.deriveMemoryEntry(agentPubkey, memoryCount, programId?)`
227
+
228
+ Static helper — derive a MemoryEntry PDA at a specific index.
229
+
230
+ **Returns:** `{ pda: PublicKey, bump: number }`
231
+
232
+ ---
233
+
234
+ ## 🧠 Context Cost Reduction Guide
235
+
236
+ This is the real reason to use this SDK. **On-chain memory = 90% API cost reduction.**
237
+
238
+ ### The Problem
239
+
240
+ LLM context windows are expensive:
241
+ - Claude Sonnet: **$3/M tokens**
242
+ - Storing all conversation history in context = **$10–50/day** for active agents
243
+ - Every session restart re-loads everything = massive token burn
244
+ - Your agent's memory disappears when the process dies
245
+
246
+ ### The Solution — On-Chain Memory as External Storage
247
+
248
+ ```
249
+ Instead of: Use this:
250
+ ┌───────────────────────────┐ ┌──────────────────────────────┐
251
+ │ Full history in context │ → │ Compressed summary │
252
+ │ 100k tokens/session │ │ + On-chain CIDs │
253
+ │ ~$1.50/hr │ │ + Fetch only what's needed │
254
+ └───────────────────────────┘ │ ~5–10k tokens/session │
255
+ │ ~$0.05/hr │
256
+ └──────────────────────────────┘
257
+ ```
258
+
259
+ ### How It Works
260
+
261
+ 1. **Agent processes a conversation** → compress key facts to IPFS → call `storeMemory(CID)` *(0.001 XNT)*
262
+ 2. **Next session starts** → call `listMemories(agentPubkey, 5)` → get last 5 CIDs → fetch only the relevant ones
263
+ 3. **Semantic search** → pull only what's needed for the current context
264
+ 4. **Result:** 90% context reduction = 90% API cost reduction
265
+
266
+ ### Cost Math
267
+
268
+ | Approach | Tokens/session | API cost/day | On-chain cost/day |
269
+ |----------|---------------|--------------|-------------------|
270
+ | Full history in context | 100k | ~$4.50 | $0 |
271
+ | On-chain memory (this SDK) | 10k | ~$0.45 | ~0.1 XNT (~$0.03) |
272
+ | **Savings** | **90% less** | **~$4.05/day** | **pays for itself in an hour** |
273
+
274
+ ### The Code Pattern
275
+
276
+ ```js
277
+ const { AgentClient } = require('@x1scroll/agent-sdk');
278
+
279
+ // ── END OF SESSION — compress and store ──────────────────────────────────────
280
+ const summary = await myLLM.compress(conversationHistory);
281
+ const cid = await ipfs.add(JSON.stringify(summary));
282
+
283
+ await client.storeMemory(
284
+ agentKeypair,
285
+ humanWallet.toBase58(),
286
+ `session-${new Date().toISOString().slice(0, 10)}`,
287
+ cid,
288
+ ['session', 'daily']
289
+ );
290
+ // Cost: 0.001 XNT (~$0.0003). Saved: ~$4.50 in context fees.
291
+
292
+ // ── START OF NEXT SESSION — load only what's needed ──────────────────────────
293
+ const memories = await client.listMemories(agentPubkey, 5); // last 5 memories
294
+ const relevant = await fetchRelevantFromIPFS(memories, currentQuery); // semantic filter
295
+
296
+ // Inject only the relevant CIDs — 5k tokens instead of 100k
297
+ const context = relevant.map(m => m.content).join('\n\n');
298
+ ```
299
+
300
+ ### The Flywheel
301
+
302
+ ```
303
+ You save $4/day on API costs
304
+
305
+ You spend ~$0.03/day on XNT memory drops
306
+
307
+ X1 ecosystem gets real utility + buy pressure
308
+
309
+ x1scroll.io indexes your agent's memory for semantic search
310
+
311
+ Your agent gets smarter. Every session.
312
+ ```
313
+
314
+ ---
315
+
316
+ ## Fee Structure
317
+
318
+ | Action | XNT Cost | Why |
319
+ |--------|----------|-----|
320
+ | Register agent | 0.05 XNT | One-time identity creation |
321
+ | Store memory | 0.001 XNT | Per memory drop (the drip) |
322
+ | Update agent | 0 XNT | Free — just network fee |
323
+ | Transfer agent | 0.01 XNT | Ownership change |
324
+
325
+ Fees are **automatic** — built into the on-chain instructions. Developers don't configure or calculate them.
326
+
327
+ ---
328
+
329
+ ## Protocol Info
330
+
331
+ | Field | Value |
332
+ |-------|-------|
333
+ | Program ID | `52EW3sn2Tkq6EMnp86JWUzXrNzrFujpdEgovsjwapbAM` |
334
+ | Treasury | `HYP2VdVk2QNGKMBfWGFZpaFqMoqQkB7Vp5F12eSxCxtf` |
335
+ | Network | X1 Mainnet |
336
+ | Explorer | [explorer.x1.xyz](https://explorer.x1.xyz) |
337
+ | License | BSL-1.1 (free to use, no commercial forks) |
338
+ | Change Date | 2028-01-01 → Apache-2.0 |
339
+
340
+ ---
341
+
342
+ ## License
343
+
344
+ Business Source License 1.1 — see [LICENSE](./LICENSE).
345
+
346
+ Free to use. Not free to fork commercially. On 2028-01-01, this converts to Apache-2.0.
347
+
348
+ ---
349
+
350
+ *Built by [x1scroll.io](https://x1scroll.io) — the intelligence layer on X1.*
@@ -0,0 +1,120 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * examples/basic.js
5
+ *
6
+ * Basic Agent Identity Protocol demo:
7
+ * 1. Register an agent on-chain
8
+ * 2. Store a memory entry
9
+ * 3. Read the agent record back
10
+ * 4. List memories
11
+ *
12
+ * Prerequisites:
13
+ * - npm install @x1scroll/agent-sdk
14
+ * - Human wallet funded with at least 0.1 XNT
15
+ * - Agent wallet funded with at least 0.01 XNT (for memory fee + rent)
16
+ */
17
+
18
+ const { AgentClient } = require('@x1scroll/agent-sdk');
19
+ const { Keypair, Connection, LAMPORTS_PER_SOL } = require('@solana/web3.js');
20
+
21
+ // ── Config ────────────────────────────────────────────────────────────────────
22
+ const RPC_URL = 'https://rpc.x1.xyz';
23
+
24
+ // In production, load these from env vars or a secure keystore — never hardcode
25
+ // For this demo, we generate ephemeral keypairs (they'll have no balance)
26
+ const humanKeypair = Keypair.generate(); // wallet that owns the agent
27
+ const agentKeypair = Keypair.generate(); // the agent's identity keypair
28
+
29
+ // ── Main ──────────────────────────────────────────────────────────────────────
30
+ async function main() {
31
+ console.log('Agent Identity Protocol — Basic Example\n');
32
+ console.log('Human wallet: ', humanKeypair.publicKey.toBase58());
33
+ console.log('Agent wallet: ', agentKeypair.publicKey.toBase58());
34
+ console.log('');
35
+
36
+ const client = new AgentClient({
37
+ wallet: humanKeypair,
38
+ rpcUrl: RPC_URL,
39
+ });
40
+
41
+ // ── Step 1: Register the agent ────────────────────────────────────────────
42
+ console.log('Step 1: Registering agent...');
43
+ console.log(' Fee: 0.05 XNT (paid automatically)');
44
+
45
+ // NOTE: Your humanKeypair needs 0.05 XNT + rent for the AgentRecord account
46
+ // For this demo we skip the actual tx — uncomment below when you have a funded wallet
47
+
48
+ /*
49
+ const { txSig, agentRecordPDA } = await client.register(
50
+ agentKeypair, // agent MUST co-sign (anti-squatting)
51
+ 'aria-v1', // name (max 32 chars)
52
+ 'ipfs://bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku' // metadata URI
53
+ );
54
+ console.log(' ✓ Registered!');
55
+ console.log(' TX: ', txSig);
56
+ console.log(' AgentRecord: ', agentRecordPDA);
57
+ */
58
+
59
+ // ── Step 2: Store a memory ────────────────────────────────────────────────
60
+ console.log('\nStep 2: Storing a memory...');
61
+ console.log(' Fee: 0.001 XNT (paid automatically by the agent)');
62
+
63
+ // NOTE: Your agentKeypair needs 0.001 XNT + rent for the MemoryEntry account
64
+
65
+ /*
66
+ const { txSig: memTx, memoryEntryPDA } = await client.storeMemory(
67
+ agentKeypair, // agent signs and pays
68
+ humanKeypair.publicKey.toBase58(), // human wallet (for PDA lookup)
69
+ 'session-2026-04-06', // topic label
70
+ 'bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi', // IPFS CID
71
+ ['session', 'daily'], // tags (max 5)
72
+ false // encrypted?
73
+ );
74
+ console.log(' ✓ Memory stored!');
75
+ console.log(' TX: ', memTx);
76
+ console.log(' MemoryEntry: ', memoryEntryPDA);
77
+ */
78
+
79
+ // ── Step 3: Read the agent record ─────────────────────────────────────────
80
+ console.log('\nStep 3: Reading agent from chain...');
81
+
82
+ /*
83
+ const agentRecord = await client.getAgent(agentKeypair.publicKey.toBase58());
84
+ console.log(' Agent record:');
85
+ console.log(' Name: ', agentRecord.name);
86
+ console.log(' Human: ', agentRecord.human);
87
+ console.log(' Memory count: ', agentRecord.memoryCount);
88
+ console.log(' Created at: ', new Date(agentRecord.createdAt * 1000).toISOString());
89
+ */
90
+
91
+ // ── Step 4: List memories ─────────────────────────────────────────────────
92
+ console.log('\nStep 4: Listing memories (most recent first)...');
93
+
94
+ /*
95
+ const memories = await client.listMemories(agentKeypair.publicKey.toBase58(), 10);
96
+ console.log(` Found ${memories.length} memories:`);
97
+ for (const mem of memories) {
98
+ console.log(` [${mem.topic}] CID: ${mem.cid} | Tags: ${mem.tags.join(', ')} | ${new Date(mem.timestamp * 1000).toISOString()}`);
99
+ }
100
+ */
101
+
102
+ // ── PDA derivation (no RPC needed) ────────────────────────────────────────
103
+ console.log('\nBonus: PDA derivation (no wallet or RPC needed):');
104
+
105
+ const { pda: agentRecordPDA } = AgentClient.deriveAgentRecord(agentKeypair.publicKey);
106
+ const { pda: memory0PDA } = AgentClient.deriveMemoryEntry(agentKeypair.publicKey, 0);
107
+
108
+ console.log(' AgentRecord PDA (index 0): ', agentRecordPDA.toBase58());
109
+ console.log(' MemoryEntry PDA (memory 0): ', memory0PDA.toBase58());
110
+
111
+ console.log('\n✓ Done. Fund your wallets with XNT and uncomment the transaction calls above.');
112
+ console.log(' Get XNT: https://app.xdex.xyz');
113
+ console.log(' Explorer: https://explorer.x1.xyz');
114
+ }
115
+
116
+ main().catch(err => {
117
+ console.error('Error:', err.message);
118
+ if (err.code) console.error('Code:', err.code);
119
+ process.exit(1);
120
+ });