@x1scroll/agent-sdk 1.0.0 → 1.0.2

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 (3) hide show
  1. package/README.md +69 -0
  2. package/package.json +1 -1
  3. package/src/index.js +68 -0
package/README.md CHANGED
@@ -116,6 +116,37 @@ const { txSig, memoryEntryPDA } = await client.storeMemory(
116
116
 
117
117
  ---
118
118
 
119
+ ### `client.uploadMemory(agentKeypair, agentRecordHuman, topic, content, options?)`
120
+
121
+ **The easy path** — handles IPFS upload, pinning, and on-chain storage in one call. No IPFS knowledge required.
122
+
123
+ **Fee:** 0.001 XNT (same as `storeMemory`)
124
+
125
+ Requires a free [Pinata](https://pinata.cloud) API key (free tier: 100 pins, 1GB — enough for development and testing).
126
+
127
+ ```js
128
+ const { txSig, cid } = await client.uploadMemory(
129
+ agentKeypair,
130
+ humanWallet.publicKey.toBase58(),
131
+ 'session-2026-04-06',
132
+ { summary: 'Discussed SDK launch', decisions: ['publish to npm', 'BSL license'] },
133
+ { pinataJwt: process.env.PINATA_JWT, tags: ['session', 'daily'] }
134
+ );
135
+ // Content is pinned on IPFS, CID stored on X1. Done.
136
+ ```
137
+
138
+ | Option | Type | Default | Description |
139
+ |--------|------|---------|-------------|
140
+ | `pinataJwt` | `string` | — | **Required.** Get free at pinata.cloud |
141
+ | `tags` | `string[]` | `[]` | Up to 5 tags |
142
+ | `encrypted` | `boolean` | `false` | Whether content is encrypted |
143
+
144
+ **Returns:** `Promise<{ txSig: string, memoryEntryPDA: string, cid: string }>`
145
+
146
+ > **Use `uploadMemory()` if you want zero IPFS configuration.** Use `storeMemory()` directly if you manage your own pinning infrastructure.
147
+
148
+ ---
149
+
119
150
  ### `client.updateAgent(humanKeypair, agentPubkey, name, metadataUri)`
120
151
 
121
152
  Update an agent's name and metadata URI. Only the human owner can call this.
@@ -313,6 +344,44 @@ Your agent gets smarter. Every session.
313
344
 
314
345
  ---
315
346
 
347
+ ## ⚠️ IPFS Pinning — Read This First
348
+
349
+ `storeMemory()` stores a **pointer** (CID) on-chain — not the content itself. The on-chain record is permanent. The content is only as permanent as your IPFS pin.
350
+
351
+ **If you don't pin the CID, your content can disappear. The on-chain record will still exist, but it will point to nothing.**
352
+
353
+ ### Pin your CIDs (pick one):
354
+
355
+ **Pinata (easiest):**
356
+ ```js
357
+ const pinata = new PinataSDK({ pinataJwt: process.env.PINATA_JWT });
358
+ const { IpfsHash } = await pinata.upload.json(memoryObject);
359
+ // IpfsHash is your CID — it's already pinned
360
+ await client.storeMemory(agentKeypair, human, topic, IpfsHash, tags);
361
+ ```
362
+
363
+ **Filebase (S3-compatible, cheap):**
364
+ ```js
365
+ // Upload to Filebase bucket → get CID → pin is automatic
366
+ ```
367
+
368
+ **Self-hosted (advanced):**
369
+ ```bash
370
+ ipfs pin add <CID>
371
+ ```
372
+
373
+ **What the chain gives you:**
374
+ - Immutable, ordered index of memory events
375
+ - Ownership + transferability
376
+ - XNT-gated writes (spam resistance)
377
+ - No single point of failure for the *record*
378
+
379
+ **What you must provide:**
380
+ - IPFS content pinning (Pinata, Filebase, or your own node)
381
+ - x1scroll.io indexes pinned memories for semantic search — use our RPC for full retrieval stack
382
+
383
+ ---
384
+
316
385
  ## Fee Structure
317
386
 
318
387
  | Action | XNT Cost | Why |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x1scroll/agent-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Agent identity and on-chain memory protocol for X1 blockchain",
5
5
  "license": "BSL-1.1",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -526,6 +526,74 @@ class AgentClient {
526
526
  };
527
527
  }
528
528
 
529
+ /**
530
+ * Upload memory content to IPFS (with auto-pinning) and store the CID on-chain.
531
+ *
532
+ * This is the one-stop method for developers who don't want to manage IPFS manually.
533
+ * It handles: JSON serialization → IPFS upload → pinning → on-chain storeMemory().
534
+ *
535
+ * Supported pinning providers:
536
+ * - 'pinata' — requires { pinataJwt } in options
537
+ * - 'x1scroll' — uses x1scroll.io IPFS node (free, rate-limited). Default.
538
+ *
539
+ * Fee: 0.001 XNT (same as storeMemory — automatic).
540
+ *
541
+ * @param {Keypair} agentKeypair The agent's keypair — must be a real Signer
542
+ * @param {string} agentRecordHuman The human wallet address that owns this agent
543
+ * @param {string} topic Memory topic label (max 64 chars)
544
+ * @param {object|string} content Memory content — object (auto-serialized) or string
545
+ * @param {object} [options={}]
546
+ * @param {string} [options.provider='x1scroll'] Pinning provider: 'pinata' | 'x1scroll'
547
+ * @param {string} [options.pinataJwt] Required if provider='pinata'
548
+ * @param {string[]} [options.tags=[]] Tags (max 5)
549
+ * @param {boolean} [options.encrypted=false] Whether content is encrypted before upload
550
+ * @returns {Promise<{ txSig: string, memoryEntryPDA: string, cid: string }>}
551
+ */
552
+ async uploadMemory(agentKeypair, agentRecordHuman, topic, content, options = {}) {
553
+ const {
554
+ pinataJwt = null,
555
+ tags = [],
556
+ encrypted = false,
557
+ } = options;
558
+
559
+ if (!pinataJwt) {
560
+ throw new AgentSDKError(
561
+ 'pinataJwt is required for uploadMemory(). Get a free API key at https://pinata.cloud (free tier: 100 pins, 1GB). Pass it as options.pinataJwt.',
562
+ 'MISSING_PINATA_JWT'
563
+ );
564
+ }
565
+
566
+ // Serialize content
567
+ const body = (typeof content === 'string') ? content : JSON.stringify(content);
568
+
569
+ let cid;
570
+
571
+ // Upload to Pinata — auto-pinned, persistent
572
+ const res = await fetch('https://api.pinata.cloud/pinning/pinJSONToIPFS', {
573
+ method: 'POST',
574
+ headers: {
575
+ 'Content-Type': 'application/json',
576
+ 'Authorization': `Bearer ${pinataJwt}`,
577
+ },
578
+ body: JSON.stringify({ pinataContent: body, pinataMetadata: { name: topic } }),
579
+ });
580
+ if (!res.ok) {
581
+ const err = await res.text();
582
+ throw new AgentSDKError(`Pinata upload failed: ${err}`, 'PINATA_ERROR');
583
+ }
584
+ const json = await res.json();
585
+ cid = json.IpfsHash;
586
+
587
+ if (!cid) {
588
+ throw new AgentSDKError('IPFS upload returned no CID', 'NO_CID');
589
+ }
590
+
591
+ // Store CID on-chain
592
+ const result = await this.storeMemory(agentKeypair, agentRecordHuman, topic, cid, tags, encrypted);
593
+
594
+ return { ...result, cid };
595
+ }
596
+
529
597
  /**
530
598
  * Update an agent's name and metadata URI.
531
599
  * Only the human owner can call this. Free (network tx fee only).