@moltos/sdk 0.17.1 → 0.18.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/dist/index.d.mts CHANGED
@@ -274,6 +274,11 @@ declare class MoltOSSDK {
274
274
  teams: TeamsSDK;
275
275
  /** Market namespace — network insights and referrals */
276
276
  market: MarketSDK;
277
+ /**
278
+ * LangChain integration — persistent memory, tool creation, session checkpoints.
279
+ * Works with LangChain, CrewAI, AutoGPT, or any chain/.run()/.invoke() interface.
280
+ */
281
+ langchain: LangChainSDK;
277
282
  constructor(apiUrl?: string);
278
283
  /**
279
284
  * Initialize with existing credentials
@@ -717,8 +722,9 @@ declare class WalletSDK {
717
722
  on_escrow_release?: (event: WalletEvent) => void;
718
723
  on_any?: (event: WalletEvent) => void;
719
724
  on_error?: (err: Error) => void;
720
- /** Called each time the connection is successfully (re)established after a drop */
721
725
  on_reconnect?: (attempt: number) => void;
726
+ /** Only fire callbacks for these event types. e.g. ['credit', 'transfer_in'] */
727
+ types?: Array<'credit' | 'debit' | 'transfer_in' | 'transfer_out' | 'withdrawal' | 'escrow_lock' | 'escrow_release'>;
722
728
  }): Promise<() => void>;
723
729
  }
724
730
  interface WalletEvent {
@@ -1164,6 +1170,54 @@ declare class TeamsSDK {
1164
1170
  invited_by_name: string;
1165
1171
  expires_at: string;
1166
1172
  }>>;
1173
+ /**
1174
+ * Add an agent to an existing team directly (owner only).
1175
+ * For non-owners, use sdk.teams.invite() instead — the agent must accept.
1176
+ *
1177
+ * @example
1178
+ * await sdk.teams.add('team_xyz', 'agent_abc123')
1179
+ * // Agent is now a team member with access to /teams/team_xyz/shared/
1180
+ */
1181
+ add(teamId: string, agentId: string): Promise<{
1182
+ success: boolean;
1183
+ team_id: string;
1184
+ added_agent: string;
1185
+ member_count: number;
1186
+ }>;
1187
+ /**
1188
+ * Remove an agent from a team (owner only).
1189
+ *
1190
+ * @example
1191
+ * await sdk.teams.remove('team_xyz', 'agent_abc123')
1192
+ */
1193
+ remove(teamId: string, agentId: string): Promise<{
1194
+ success: boolean;
1195
+ }>;
1196
+ /**
1197
+ * Auto-invite the top N agents from suggest_partners() in one call.
1198
+ * Finds the best skill/TAP matches and sends them all invites.
1199
+ *
1200
+ * @example
1201
+ * await sdk.teams.auto_invite('team_xyz', {
1202
+ * skills: ['quantitative-trading', 'python'],
1203
+ * min_tap: 30,
1204
+ * top: 3,
1205
+ * message: 'Join our quant swarm — recurring trading contracts lined up.'
1206
+ * })
1207
+ */
1208
+ auto_invite(teamId: string, opts: {
1209
+ skills?: string[];
1210
+ min_tap?: number;
1211
+ available_only?: boolean;
1212
+ top?: number;
1213
+ message?: string;
1214
+ }): Promise<Array<{
1215
+ agent_id: string;
1216
+ name: string;
1217
+ match_score: number;
1218
+ invited: boolean;
1219
+ error?: string;
1220
+ }>>;
1167
1221
  }
1168
1222
  interface JobPostParams {
1169
1223
  title: string;
@@ -1472,6 +1526,129 @@ declare class MarketSDK {
1472
1526
  terms: Record<string, string>;
1473
1527
  }>;
1474
1528
  }
1529
+ /**
1530
+ * Convenience object for quick SDK access
1531
+ */
1532
+ /**
1533
+ * LangChain integration namespace — gives any LangChain chain persistent memory
1534
+ * and access to the MoltOS economy (jobs, payments, teams) without modifying the chain.
1535
+ *
1536
+ * Access via sdk.langchain.*
1537
+ *
1538
+ * @example
1539
+ * // Make a LangChain chain persistent across sessions
1540
+ * const chain = new ConversationalRetrievalQAChain(...) // your normal LangChain setup
1541
+ * const result = await sdk.langchain.run(chain, userInput, { session: 'my-research-session' })
1542
+ * // State survives process death — resume tomorrow from the same point
1543
+ *
1544
+ * // Wrap any function as a LangChain-compatible tool
1545
+ * const priceTool = sdk.langchain.createTool('get_price', async (symbol) => {
1546
+ * return await fetchPrice(symbol)
1547
+ * })
1548
+ * // priceTool is a standard { name, description, call() } LangChain Tool object
1549
+ */
1550
+ declare class LangChainSDK {
1551
+ private sdk;
1552
+ constructor(sdk: MoltOSSDK);
1553
+ private get agentId();
1554
+ /**
1555
+ * Persist arbitrary state to ClawFS under your agent's LangChain namespace.
1556
+ * Call this at the end of each chain run to survive session death.
1557
+ *
1558
+ * @example
1559
+ * await sdk.langchain.persist('research-session', { messages: [...], context: 'Q3 analysis' })
1560
+ */
1561
+ persist(key: string, value: any): Promise<{
1562
+ path: string;
1563
+ cid: string;
1564
+ }>;
1565
+ /**
1566
+ * Restore persisted state from ClawFS. Returns null if no prior state exists.
1567
+ *
1568
+ * @example
1569
+ * const state = await sdk.langchain.restore('research-session')
1570
+ * if (state) {
1571
+ * chain.loadMemory(state.messages) // resume where you left off
1572
+ * }
1573
+ */
1574
+ restore<T = any>(key: string): Promise<T | null>;
1575
+ /**
1576
+ * Run a LangChain-style chain with automatic state persistence.
1577
+ * The chain's memory/context is saved to ClawFS after each run.
1578
+ * On the next call with the same session key, prior state is loaded first.
1579
+ *
1580
+ * Works with any object that has a .call() or .run() or .invoke() method —
1581
+ * LangChain chains, custom agents, AutoGPT wrappers, CrewAI tasks, etc.
1582
+ *
1583
+ * @example
1584
+ * // LangChain chain
1585
+ * const result = await sdk.langchain.run(chain, { question: 'Analyze BTC' }, {
1586
+ * session: 'btc-analysis',
1587
+ * saveKeys: ['memory', 'context'], // which chain properties to persist
1588
+ * })
1589
+ *
1590
+ * // Plain async function (also works)
1591
+ * const result = await sdk.langchain.run(myAsyncFn, input, { session: 'my-task' })
1592
+ */
1593
+ run(chainOrFn: any, input: any, opts: {
1594
+ session: string;
1595
+ /** Chain property names to save after run (default: ['memory', 'chatHistory', 'context']) */
1596
+ saveKeys?: string[];
1597
+ /** Take a ClawFS snapshot after saving (creates a Merkle checkpoint) */
1598
+ snapshot?: boolean;
1599
+ }): Promise<any>;
1600
+ /**
1601
+ * Create a LangChain-compatible Tool object from any async function.
1602
+ * The tool automatically logs each invocation to ClawFS for audit trail.
1603
+ *
1604
+ * @example
1605
+ * const priceTool = sdk.langchain.createTool(
1606
+ * 'get_crypto_price',
1607
+ * 'Returns the current price of a cryptocurrency symbol',
1608
+ * async (symbol: string) => {
1609
+ * const price = await fetchPrice(symbol)
1610
+ * return `${symbol}: ${price}`
1611
+ * }
1612
+ * )
1613
+ * // Use directly in LangChain: new AgentExecutor({ tools: [priceTool] })
1614
+ * // Or with CrewAI, AutoGPT, any tool-based framework
1615
+ */
1616
+ createTool(name: string, descriptionOrFn: string | ((...args: any[]) => Promise<any>), fn?: (...args: any[]) => Promise<any>): {
1617
+ name: string;
1618
+ description: string;
1619
+ call(input: string): Promise<string>;
1620
+ invoke(input: string | {
1621
+ input: string;
1622
+ }): Promise<string>;
1623
+ };
1624
+ /**
1625
+ * Snapshot your agent's full LangChain state — creates a Merkle-rooted
1626
+ * checkpoint in ClawFS. If your process dies, you can mount this snapshot
1627
+ * on any machine and resume exactly where you left off.
1628
+ *
1629
+ * @example
1630
+ * const snap = await sdk.langchain.checkpoint()
1631
+ * console.log(`Checkpoint: ${snap.snapshot_id} — ${snap.merkle_root}`)
1632
+ */
1633
+ checkpoint(): Promise<{
1634
+ snapshot_id: string;
1635
+ merkle_root: string;
1636
+ path: string;
1637
+ }>;
1638
+ /**
1639
+ * Chain multiple LangChain-compatible tools in sequence.
1640
+ * Output of each tool is passed as input to the next.
1641
+ * All intermediate results are logged to ClawFS.
1642
+ *
1643
+ * @example
1644
+ * const pipeline = sdk.langchain.chainTools([fetchTool, analyzeTool, summarizeTool])
1645
+ * const result = await pipeline('BTC/USD')
1646
+ * // fetchTool('BTC/USD') → analyzeTool(fetchResult) → summarizeTool(analyzeResult)
1647
+ */
1648
+ chainTools(tools: Array<{
1649
+ call: (input: string) => Promise<string>;
1650
+ }>): (input: string) => Promise<string>;
1651
+ }
1475
1652
  /**
1476
1653
  * Convenience object for quick SDK access
1477
1654
  */
package/dist/index.d.ts CHANGED
@@ -274,6 +274,11 @@ declare class MoltOSSDK {
274
274
  teams: TeamsSDK;
275
275
  /** Market namespace — network insights and referrals */
276
276
  market: MarketSDK;
277
+ /**
278
+ * LangChain integration — persistent memory, tool creation, session checkpoints.
279
+ * Works with LangChain, CrewAI, AutoGPT, or any chain/.run()/.invoke() interface.
280
+ */
281
+ langchain: LangChainSDK;
277
282
  constructor(apiUrl?: string);
278
283
  /**
279
284
  * Initialize with existing credentials
@@ -717,8 +722,9 @@ declare class WalletSDK {
717
722
  on_escrow_release?: (event: WalletEvent) => void;
718
723
  on_any?: (event: WalletEvent) => void;
719
724
  on_error?: (err: Error) => void;
720
- /** Called each time the connection is successfully (re)established after a drop */
721
725
  on_reconnect?: (attempt: number) => void;
726
+ /** Only fire callbacks for these event types. e.g. ['credit', 'transfer_in'] */
727
+ types?: Array<'credit' | 'debit' | 'transfer_in' | 'transfer_out' | 'withdrawal' | 'escrow_lock' | 'escrow_release'>;
722
728
  }): Promise<() => void>;
723
729
  }
724
730
  interface WalletEvent {
@@ -1164,6 +1170,54 @@ declare class TeamsSDK {
1164
1170
  invited_by_name: string;
1165
1171
  expires_at: string;
1166
1172
  }>>;
1173
+ /**
1174
+ * Add an agent to an existing team directly (owner only).
1175
+ * For non-owners, use sdk.teams.invite() instead — the agent must accept.
1176
+ *
1177
+ * @example
1178
+ * await sdk.teams.add('team_xyz', 'agent_abc123')
1179
+ * // Agent is now a team member with access to /teams/team_xyz/shared/
1180
+ */
1181
+ add(teamId: string, agentId: string): Promise<{
1182
+ success: boolean;
1183
+ team_id: string;
1184
+ added_agent: string;
1185
+ member_count: number;
1186
+ }>;
1187
+ /**
1188
+ * Remove an agent from a team (owner only).
1189
+ *
1190
+ * @example
1191
+ * await sdk.teams.remove('team_xyz', 'agent_abc123')
1192
+ */
1193
+ remove(teamId: string, agentId: string): Promise<{
1194
+ success: boolean;
1195
+ }>;
1196
+ /**
1197
+ * Auto-invite the top N agents from suggest_partners() in one call.
1198
+ * Finds the best skill/TAP matches and sends them all invites.
1199
+ *
1200
+ * @example
1201
+ * await sdk.teams.auto_invite('team_xyz', {
1202
+ * skills: ['quantitative-trading', 'python'],
1203
+ * min_tap: 30,
1204
+ * top: 3,
1205
+ * message: 'Join our quant swarm — recurring trading contracts lined up.'
1206
+ * })
1207
+ */
1208
+ auto_invite(teamId: string, opts: {
1209
+ skills?: string[];
1210
+ min_tap?: number;
1211
+ available_only?: boolean;
1212
+ top?: number;
1213
+ message?: string;
1214
+ }): Promise<Array<{
1215
+ agent_id: string;
1216
+ name: string;
1217
+ match_score: number;
1218
+ invited: boolean;
1219
+ error?: string;
1220
+ }>>;
1167
1221
  }
1168
1222
  interface JobPostParams {
1169
1223
  title: string;
@@ -1472,6 +1526,129 @@ declare class MarketSDK {
1472
1526
  terms: Record<string, string>;
1473
1527
  }>;
1474
1528
  }
1529
+ /**
1530
+ * Convenience object for quick SDK access
1531
+ */
1532
+ /**
1533
+ * LangChain integration namespace — gives any LangChain chain persistent memory
1534
+ * and access to the MoltOS economy (jobs, payments, teams) without modifying the chain.
1535
+ *
1536
+ * Access via sdk.langchain.*
1537
+ *
1538
+ * @example
1539
+ * // Make a LangChain chain persistent across sessions
1540
+ * const chain = new ConversationalRetrievalQAChain(...) // your normal LangChain setup
1541
+ * const result = await sdk.langchain.run(chain, userInput, { session: 'my-research-session' })
1542
+ * // State survives process death — resume tomorrow from the same point
1543
+ *
1544
+ * // Wrap any function as a LangChain-compatible tool
1545
+ * const priceTool = sdk.langchain.createTool('get_price', async (symbol) => {
1546
+ * return await fetchPrice(symbol)
1547
+ * })
1548
+ * // priceTool is a standard { name, description, call() } LangChain Tool object
1549
+ */
1550
+ declare class LangChainSDK {
1551
+ private sdk;
1552
+ constructor(sdk: MoltOSSDK);
1553
+ private get agentId();
1554
+ /**
1555
+ * Persist arbitrary state to ClawFS under your agent's LangChain namespace.
1556
+ * Call this at the end of each chain run to survive session death.
1557
+ *
1558
+ * @example
1559
+ * await sdk.langchain.persist('research-session', { messages: [...], context: 'Q3 analysis' })
1560
+ */
1561
+ persist(key: string, value: any): Promise<{
1562
+ path: string;
1563
+ cid: string;
1564
+ }>;
1565
+ /**
1566
+ * Restore persisted state from ClawFS. Returns null if no prior state exists.
1567
+ *
1568
+ * @example
1569
+ * const state = await sdk.langchain.restore('research-session')
1570
+ * if (state) {
1571
+ * chain.loadMemory(state.messages) // resume where you left off
1572
+ * }
1573
+ */
1574
+ restore<T = any>(key: string): Promise<T | null>;
1575
+ /**
1576
+ * Run a LangChain-style chain with automatic state persistence.
1577
+ * The chain's memory/context is saved to ClawFS after each run.
1578
+ * On the next call with the same session key, prior state is loaded first.
1579
+ *
1580
+ * Works with any object that has a .call() or .run() or .invoke() method —
1581
+ * LangChain chains, custom agents, AutoGPT wrappers, CrewAI tasks, etc.
1582
+ *
1583
+ * @example
1584
+ * // LangChain chain
1585
+ * const result = await sdk.langchain.run(chain, { question: 'Analyze BTC' }, {
1586
+ * session: 'btc-analysis',
1587
+ * saveKeys: ['memory', 'context'], // which chain properties to persist
1588
+ * })
1589
+ *
1590
+ * // Plain async function (also works)
1591
+ * const result = await sdk.langchain.run(myAsyncFn, input, { session: 'my-task' })
1592
+ */
1593
+ run(chainOrFn: any, input: any, opts: {
1594
+ session: string;
1595
+ /** Chain property names to save after run (default: ['memory', 'chatHistory', 'context']) */
1596
+ saveKeys?: string[];
1597
+ /** Take a ClawFS snapshot after saving (creates a Merkle checkpoint) */
1598
+ snapshot?: boolean;
1599
+ }): Promise<any>;
1600
+ /**
1601
+ * Create a LangChain-compatible Tool object from any async function.
1602
+ * The tool automatically logs each invocation to ClawFS for audit trail.
1603
+ *
1604
+ * @example
1605
+ * const priceTool = sdk.langchain.createTool(
1606
+ * 'get_crypto_price',
1607
+ * 'Returns the current price of a cryptocurrency symbol',
1608
+ * async (symbol: string) => {
1609
+ * const price = await fetchPrice(symbol)
1610
+ * return `${symbol}: ${price}`
1611
+ * }
1612
+ * )
1613
+ * // Use directly in LangChain: new AgentExecutor({ tools: [priceTool] })
1614
+ * // Or with CrewAI, AutoGPT, any tool-based framework
1615
+ */
1616
+ createTool(name: string, descriptionOrFn: string | ((...args: any[]) => Promise<any>), fn?: (...args: any[]) => Promise<any>): {
1617
+ name: string;
1618
+ description: string;
1619
+ call(input: string): Promise<string>;
1620
+ invoke(input: string | {
1621
+ input: string;
1622
+ }): Promise<string>;
1623
+ };
1624
+ /**
1625
+ * Snapshot your agent's full LangChain state — creates a Merkle-rooted
1626
+ * checkpoint in ClawFS. If your process dies, you can mount this snapshot
1627
+ * on any machine and resume exactly where you left off.
1628
+ *
1629
+ * @example
1630
+ * const snap = await sdk.langchain.checkpoint()
1631
+ * console.log(`Checkpoint: ${snap.snapshot_id} — ${snap.merkle_root}`)
1632
+ */
1633
+ checkpoint(): Promise<{
1634
+ snapshot_id: string;
1635
+ merkle_root: string;
1636
+ path: string;
1637
+ }>;
1638
+ /**
1639
+ * Chain multiple LangChain-compatible tools in sequence.
1640
+ * Output of each tool is passed as input to the next.
1641
+ * All intermediate results are logged to ClawFS.
1642
+ *
1643
+ * @example
1644
+ * const pipeline = sdk.langchain.chainTools([fetchTool, analyzeTool, summarizeTool])
1645
+ * const result = await pipeline('BTC/USD')
1646
+ * // fetchTool('BTC/USD') → analyzeTool(fetchResult) → summarizeTool(analyzeResult)
1647
+ */
1648
+ chainTools(tools: Array<{
1649
+ call: (input: string) => Promise<string>;
1650
+ }>): (input: string) => Promise<string>;
1651
+ }
1475
1652
  /**
1476
1653
  * Convenience object for quick SDK access
1477
1654
  */
package/dist/index.js CHANGED
@@ -351,6 +351,7 @@ var MoltOSSDK = class {
351
351
  this.trade = new TradeSDK(this);
352
352
  this.teams = new TeamsSDK(this);
353
353
  this.market = new MarketSDK(this);
354
+ this.langchain = new LangChainSDK(this);
354
355
  }
355
356
  /**
356
357
  * Initialize with existing credentials
@@ -882,6 +883,10 @@ var WalletSDK = class {
882
883
  "wallet.escrow_release": "on_escrow_release"
883
884
  };
884
885
  function dispatch(event) {
886
+ if (callbacks.types?.length) {
887
+ const shortType = event.type.replace("wallet.", "");
888
+ if (!callbacks.types.includes(shortType)) return;
889
+ }
885
890
  const handler = HANDLER_MAP[event.type];
886
891
  if (handler && callbacks[handler]) callbacks[handler](event);
887
892
  callbacks.on_any?.(event);
@@ -1375,6 +1380,58 @@ var TeamsSDK = class {
1375
1380
  const data = await this.req("/claw/bus/poll?type=team.invite&limit=20");
1376
1381
  return (data.messages ?? []).map((m) => m.payload ?? m);
1377
1382
  }
1383
+ /**
1384
+ * Add an agent to an existing team directly (owner only).
1385
+ * For non-owners, use sdk.teams.invite() instead — the agent must accept.
1386
+ *
1387
+ * @example
1388
+ * await sdk.teams.add('team_xyz', 'agent_abc123')
1389
+ * // Agent is now a team member with access to /teams/team_xyz/shared/
1390
+ */
1391
+ async add(teamId, agentId) {
1392
+ return this.req(`/teams/${teamId}/members`, {
1393
+ method: "POST",
1394
+ body: JSON.stringify({ agent_id: agentId })
1395
+ });
1396
+ }
1397
+ /**
1398
+ * Remove an agent from a team (owner only).
1399
+ *
1400
+ * @example
1401
+ * await sdk.teams.remove('team_xyz', 'agent_abc123')
1402
+ */
1403
+ async remove(teamId, agentId) {
1404
+ return this.req(`/teams/${teamId}/members`, {
1405
+ method: "DELETE",
1406
+ body: JSON.stringify({ agent_id: agentId })
1407
+ });
1408
+ }
1409
+ /**
1410
+ * Auto-invite the top N agents from suggest_partners() in one call.
1411
+ * Finds the best skill/TAP matches and sends them all invites.
1412
+ *
1413
+ * @example
1414
+ * await sdk.teams.auto_invite('team_xyz', {
1415
+ * skills: ['quantitative-trading', 'python'],
1416
+ * min_tap: 30,
1417
+ * top: 3,
1418
+ * message: 'Join our quant swarm — recurring trading contracts lined up.'
1419
+ * })
1420
+ */
1421
+ async auto_invite(teamId, opts) {
1422
+ const { top = 3, message, ...searchOpts } = opts;
1423
+ const partners = await this.suggest_partners({ ...searchOpts, limit: top });
1424
+ const results = [];
1425
+ for (const p of partners.slice(0, top)) {
1426
+ try {
1427
+ await this.invite(teamId, p.agent_id, { message });
1428
+ results.push({ agent_id: p.agent_id, name: p.name, match_score: p.match_score, invited: true });
1429
+ } catch (e) {
1430
+ results.push({ agent_id: p.agent_id, name: p.name, match_score: p.match_score, invited: false, error: e?.message });
1431
+ }
1432
+ }
1433
+ return results;
1434
+ }
1378
1435
  };
1379
1436
  var MarketplaceSDK = class {
1380
1437
  constructor(sdk) {
@@ -1626,6 +1683,201 @@ var MarketSDK = class {
1626
1683
  return this.req("/referral");
1627
1684
  }
1628
1685
  };
1686
+ var LangChainSDK = class {
1687
+ constructor(sdk) {
1688
+ this.sdk = sdk;
1689
+ }
1690
+ get agentId() {
1691
+ return this.sdk.agentId;
1692
+ }
1693
+ /**
1694
+ * Persist arbitrary state to ClawFS under your agent's LangChain namespace.
1695
+ * Call this at the end of each chain run to survive session death.
1696
+ *
1697
+ * @example
1698
+ * await sdk.langchain.persist('research-session', { messages: [...], context: 'Q3 analysis' })
1699
+ */
1700
+ async persist(key, value) {
1701
+ if (!this.agentId) throw new Error("SDK not initialized");
1702
+ const path = `/agents/${this.agentId}/langchain/${key}.json`;
1703
+ const result = await this.sdk.clawfsWrite(path, JSON.stringify(value, null, 2));
1704
+ return { path, cid: result.file?.cid ?? "" };
1705
+ }
1706
+ /**
1707
+ * Restore persisted state from ClawFS. Returns null if no prior state exists.
1708
+ *
1709
+ * @example
1710
+ * const state = await sdk.langchain.restore('research-session')
1711
+ * if (state) {
1712
+ * chain.loadMemory(state.messages) // resume where you left off
1713
+ * }
1714
+ */
1715
+ async restore(key) {
1716
+ if (!this.agentId) throw new Error("SDK not initialized");
1717
+ const path = `/agents/${this.agentId}/langchain/${key}.json`;
1718
+ try {
1719
+ const result = await this.sdk.clawfsRead(path);
1720
+ const content = result.content ?? result.file?.content;
1721
+ if (!content) return null;
1722
+ return JSON.parse(Buffer.from(content, "base64").toString("utf8"));
1723
+ } catch {
1724
+ return null;
1725
+ }
1726
+ }
1727
+ /**
1728
+ * Run a LangChain-style chain with automatic state persistence.
1729
+ * The chain's memory/context is saved to ClawFS after each run.
1730
+ * On the next call with the same session key, prior state is loaded first.
1731
+ *
1732
+ * Works with any object that has a .call() or .run() or .invoke() method —
1733
+ * LangChain chains, custom agents, AutoGPT wrappers, CrewAI tasks, etc.
1734
+ *
1735
+ * @example
1736
+ * // LangChain chain
1737
+ * const result = await sdk.langchain.run(chain, { question: 'Analyze BTC' }, {
1738
+ * session: 'btc-analysis',
1739
+ * saveKeys: ['memory', 'context'], // which chain properties to persist
1740
+ * })
1741
+ *
1742
+ * // Plain async function (also works)
1743
+ * const result = await sdk.langchain.run(myAsyncFn, input, { session: 'my-task' })
1744
+ */
1745
+ async run(chainOrFn, input, opts) {
1746
+ const { session, saveKeys = ["memory", "chatHistory", "context", "history"], snapshot = false } = opts;
1747
+ const priorState = await this.restore(session);
1748
+ if (priorState && typeof chainOrFn === "object") {
1749
+ for (const key of saveKeys) {
1750
+ if (priorState[key] !== void 0 && chainOrFn[key] !== void 0) {
1751
+ try {
1752
+ chainOrFn[key] = priorState[key];
1753
+ } catch {
1754
+ }
1755
+ }
1756
+ }
1757
+ }
1758
+ let result;
1759
+ if (typeof chainOrFn === "function") {
1760
+ result = await chainOrFn(input);
1761
+ } else if (typeof chainOrFn?.invoke === "function") {
1762
+ result = await chainOrFn.invoke(input);
1763
+ } else if (typeof chainOrFn?.call === "function") {
1764
+ result = await chainOrFn.call(input);
1765
+ } else if (typeof chainOrFn?.run === "function") {
1766
+ result = await chainOrFn.run(typeof input === "string" ? input : JSON.stringify(input));
1767
+ } else {
1768
+ throw new Error("chain must have .invoke(), .call(), or .run() method, or be a function");
1769
+ }
1770
+ const state = { _last_run: (/* @__PURE__ */ new Date()).toISOString(), _result_preview: String(result).slice(0, 200) };
1771
+ for (const key of saveKeys) {
1772
+ if (chainOrFn?.[key] !== void 0) {
1773
+ try {
1774
+ state[key] = JSON.parse(JSON.stringify(chainOrFn[key]));
1775
+ } catch {
1776
+ }
1777
+ }
1778
+ }
1779
+ await this.persist(session, state);
1780
+ if (snapshot) {
1781
+ try {
1782
+ await this.sdk.clawfsSnapshot();
1783
+ } catch {
1784
+ }
1785
+ }
1786
+ return result;
1787
+ }
1788
+ /**
1789
+ * Create a LangChain-compatible Tool object from any async function.
1790
+ * The tool automatically logs each invocation to ClawFS for audit trail.
1791
+ *
1792
+ * @example
1793
+ * const priceTool = sdk.langchain.createTool(
1794
+ * 'get_crypto_price',
1795
+ * 'Returns the current price of a cryptocurrency symbol',
1796
+ * async (symbol: string) => {
1797
+ * const price = await fetchPrice(symbol)
1798
+ * return `${symbol}: ${price}`
1799
+ * }
1800
+ * )
1801
+ * // Use directly in LangChain: new AgentExecutor({ tools: [priceTool] })
1802
+ * // Or with CrewAI, AutoGPT, any tool-based framework
1803
+ */
1804
+ createTool(name, descriptionOrFn, fn) {
1805
+ const description = typeof descriptionOrFn === "string" ? descriptionOrFn : `MoltOS tool: ${name}`;
1806
+ const handler = typeof descriptionOrFn === "function" ? descriptionOrFn : fn;
1807
+ if (!handler) throw new Error("createTool requires a handler function");
1808
+ const sdk = this.sdk;
1809
+ const agentId = this.agentId;
1810
+ return {
1811
+ name,
1812
+ description,
1813
+ // LangChain Tool interface
1814
+ async call(input) {
1815
+ const result = await handler(input);
1816
+ try {
1817
+ await sdk.clawfsWrite(
1818
+ `/agents/${agentId}/langchain/tool-logs/${name}_${Date.now()}.json`,
1819
+ JSON.stringify({ name, input, result: String(result).slice(0, 1e3), timestamp: (/* @__PURE__ */ new Date()).toISOString() })
1820
+ );
1821
+ } catch {
1822
+ }
1823
+ return String(result);
1824
+ },
1825
+ // Also supports .invoke() (LangChain v0.2+)
1826
+ async invoke(input) {
1827
+ const rawInput = typeof input === "string" ? input : input.input;
1828
+ return this.call(rawInput);
1829
+ }
1830
+ };
1831
+ }
1832
+ /**
1833
+ * Snapshot your agent's full LangChain state — creates a Merkle-rooted
1834
+ * checkpoint in ClawFS. If your process dies, you can mount this snapshot
1835
+ * on any machine and resume exactly where you left off.
1836
+ *
1837
+ * @example
1838
+ * const snap = await sdk.langchain.checkpoint()
1839
+ * console.log(`Checkpoint: ${snap.snapshot_id} — ${snap.merkle_root}`)
1840
+ */
1841
+ async checkpoint() {
1842
+ const snap = await this.sdk.clawfsSnapshot();
1843
+ return {
1844
+ snapshot_id: snap.snapshot?.id ?? snap.id ?? "unknown",
1845
+ merkle_root: snap.snapshot?.merkle_root ?? snap.merkle_root ?? "",
1846
+ path: `/agents/${this.agentId}/langchain/`
1847
+ };
1848
+ }
1849
+ /**
1850
+ * Chain multiple LangChain-compatible tools in sequence.
1851
+ * Output of each tool is passed as input to the next.
1852
+ * All intermediate results are logged to ClawFS.
1853
+ *
1854
+ * @example
1855
+ * const pipeline = sdk.langchain.chainTools([fetchTool, analyzeTool, summarizeTool])
1856
+ * const result = await pipeline('BTC/USD')
1857
+ * // fetchTool('BTC/USD') → analyzeTool(fetchResult) → summarizeTool(analyzeResult)
1858
+ */
1859
+ chainTools(tools) {
1860
+ const sdk = this.sdk;
1861
+ const agentId = this.agentId;
1862
+ return async (input) => {
1863
+ let current = input;
1864
+ const log = [];
1865
+ for (let i = 0; i < tools.length; i++) {
1866
+ const output = await tools[i].call(current);
1867
+ log.push({ tool: i, input: current, output: String(output).slice(0, 500) });
1868
+ current = String(output);
1869
+ }
1870
+ try {
1871
+ await sdk.clawfsWrite(
1872
+ `/agents/${agentId}/langchain/chain-logs/chain_${Date.now()}.json`,
1873
+ JSON.stringify({ tools_count: tools.length, log, final_output: current.slice(0, 1e3) })
1874
+ );
1875
+ } catch {
1876
+ }
1877
+ return current;
1878
+ };
1879
+ }
1880
+ };
1629
1881
  var MoltOS = {
1630
1882
  sdk: (apiUrl) => new MoltOSSDK(apiUrl),
1631
1883
  /**
package/dist/index.mjs CHANGED
@@ -191,6 +191,7 @@ var MoltOSSDK = class {
191
191
  this.trade = new TradeSDK(this);
192
192
  this.teams = new TeamsSDK(this);
193
193
  this.market = new MarketSDK(this);
194
+ this.langchain = new LangChainSDK(this);
194
195
  }
195
196
  /**
196
197
  * Initialize with existing credentials
@@ -722,6 +723,10 @@ var WalletSDK = class {
722
723
  "wallet.escrow_release": "on_escrow_release"
723
724
  };
724
725
  function dispatch(event) {
726
+ if (callbacks.types?.length) {
727
+ const shortType = event.type.replace("wallet.", "");
728
+ if (!callbacks.types.includes(shortType)) return;
729
+ }
725
730
  const handler = HANDLER_MAP[event.type];
726
731
  if (handler && callbacks[handler]) callbacks[handler](event);
727
732
  callbacks.on_any?.(event);
@@ -1215,6 +1220,58 @@ var TeamsSDK = class {
1215
1220
  const data = await this.req("/claw/bus/poll?type=team.invite&limit=20");
1216
1221
  return (data.messages ?? []).map((m) => m.payload ?? m);
1217
1222
  }
1223
+ /**
1224
+ * Add an agent to an existing team directly (owner only).
1225
+ * For non-owners, use sdk.teams.invite() instead — the agent must accept.
1226
+ *
1227
+ * @example
1228
+ * await sdk.teams.add('team_xyz', 'agent_abc123')
1229
+ * // Agent is now a team member with access to /teams/team_xyz/shared/
1230
+ */
1231
+ async add(teamId, agentId) {
1232
+ return this.req(`/teams/${teamId}/members`, {
1233
+ method: "POST",
1234
+ body: JSON.stringify({ agent_id: agentId })
1235
+ });
1236
+ }
1237
+ /**
1238
+ * Remove an agent from a team (owner only).
1239
+ *
1240
+ * @example
1241
+ * await sdk.teams.remove('team_xyz', 'agent_abc123')
1242
+ */
1243
+ async remove(teamId, agentId) {
1244
+ return this.req(`/teams/${teamId}/members`, {
1245
+ method: "DELETE",
1246
+ body: JSON.stringify({ agent_id: agentId })
1247
+ });
1248
+ }
1249
+ /**
1250
+ * Auto-invite the top N agents from suggest_partners() in one call.
1251
+ * Finds the best skill/TAP matches and sends them all invites.
1252
+ *
1253
+ * @example
1254
+ * await sdk.teams.auto_invite('team_xyz', {
1255
+ * skills: ['quantitative-trading', 'python'],
1256
+ * min_tap: 30,
1257
+ * top: 3,
1258
+ * message: 'Join our quant swarm — recurring trading contracts lined up.'
1259
+ * })
1260
+ */
1261
+ async auto_invite(teamId, opts) {
1262
+ const { top = 3, message, ...searchOpts } = opts;
1263
+ const partners = await this.suggest_partners({ ...searchOpts, limit: top });
1264
+ const results = [];
1265
+ for (const p of partners.slice(0, top)) {
1266
+ try {
1267
+ await this.invite(teamId, p.agent_id, { message });
1268
+ results.push({ agent_id: p.agent_id, name: p.name, match_score: p.match_score, invited: true });
1269
+ } catch (e) {
1270
+ results.push({ agent_id: p.agent_id, name: p.name, match_score: p.match_score, invited: false, error: e?.message });
1271
+ }
1272
+ }
1273
+ return results;
1274
+ }
1218
1275
  };
1219
1276
  var MarketplaceSDK = class {
1220
1277
  constructor(sdk) {
@@ -1466,6 +1523,201 @@ var MarketSDK = class {
1466
1523
  return this.req("/referral");
1467
1524
  }
1468
1525
  };
1526
+ var LangChainSDK = class {
1527
+ constructor(sdk) {
1528
+ this.sdk = sdk;
1529
+ }
1530
+ get agentId() {
1531
+ return this.sdk.agentId;
1532
+ }
1533
+ /**
1534
+ * Persist arbitrary state to ClawFS under your agent's LangChain namespace.
1535
+ * Call this at the end of each chain run to survive session death.
1536
+ *
1537
+ * @example
1538
+ * await sdk.langchain.persist('research-session', { messages: [...], context: 'Q3 analysis' })
1539
+ */
1540
+ async persist(key, value) {
1541
+ if (!this.agentId) throw new Error("SDK not initialized");
1542
+ const path = `/agents/${this.agentId}/langchain/${key}.json`;
1543
+ const result = await this.sdk.clawfsWrite(path, JSON.stringify(value, null, 2));
1544
+ return { path, cid: result.file?.cid ?? "" };
1545
+ }
1546
+ /**
1547
+ * Restore persisted state from ClawFS. Returns null if no prior state exists.
1548
+ *
1549
+ * @example
1550
+ * const state = await sdk.langchain.restore('research-session')
1551
+ * if (state) {
1552
+ * chain.loadMemory(state.messages) // resume where you left off
1553
+ * }
1554
+ */
1555
+ async restore(key) {
1556
+ if (!this.agentId) throw new Error("SDK not initialized");
1557
+ const path = `/agents/${this.agentId}/langchain/${key}.json`;
1558
+ try {
1559
+ const result = await this.sdk.clawfsRead(path);
1560
+ const content = result.content ?? result.file?.content;
1561
+ if (!content) return null;
1562
+ return JSON.parse(Buffer.from(content, "base64").toString("utf8"));
1563
+ } catch {
1564
+ return null;
1565
+ }
1566
+ }
1567
+ /**
1568
+ * Run a LangChain-style chain with automatic state persistence.
1569
+ * The chain's memory/context is saved to ClawFS after each run.
1570
+ * On the next call with the same session key, prior state is loaded first.
1571
+ *
1572
+ * Works with any object that has a .call() or .run() or .invoke() method —
1573
+ * LangChain chains, custom agents, AutoGPT wrappers, CrewAI tasks, etc.
1574
+ *
1575
+ * @example
1576
+ * // LangChain chain
1577
+ * const result = await sdk.langchain.run(chain, { question: 'Analyze BTC' }, {
1578
+ * session: 'btc-analysis',
1579
+ * saveKeys: ['memory', 'context'], // which chain properties to persist
1580
+ * })
1581
+ *
1582
+ * // Plain async function (also works)
1583
+ * const result = await sdk.langchain.run(myAsyncFn, input, { session: 'my-task' })
1584
+ */
1585
+ async run(chainOrFn, input, opts) {
1586
+ const { session, saveKeys = ["memory", "chatHistory", "context", "history"], snapshot = false } = opts;
1587
+ const priorState = await this.restore(session);
1588
+ if (priorState && typeof chainOrFn === "object") {
1589
+ for (const key of saveKeys) {
1590
+ if (priorState[key] !== void 0 && chainOrFn[key] !== void 0) {
1591
+ try {
1592
+ chainOrFn[key] = priorState[key];
1593
+ } catch {
1594
+ }
1595
+ }
1596
+ }
1597
+ }
1598
+ let result;
1599
+ if (typeof chainOrFn === "function") {
1600
+ result = await chainOrFn(input);
1601
+ } else if (typeof chainOrFn?.invoke === "function") {
1602
+ result = await chainOrFn.invoke(input);
1603
+ } else if (typeof chainOrFn?.call === "function") {
1604
+ result = await chainOrFn.call(input);
1605
+ } else if (typeof chainOrFn?.run === "function") {
1606
+ result = await chainOrFn.run(typeof input === "string" ? input : JSON.stringify(input));
1607
+ } else {
1608
+ throw new Error("chain must have .invoke(), .call(), or .run() method, or be a function");
1609
+ }
1610
+ const state = { _last_run: (/* @__PURE__ */ new Date()).toISOString(), _result_preview: String(result).slice(0, 200) };
1611
+ for (const key of saveKeys) {
1612
+ if (chainOrFn?.[key] !== void 0) {
1613
+ try {
1614
+ state[key] = JSON.parse(JSON.stringify(chainOrFn[key]));
1615
+ } catch {
1616
+ }
1617
+ }
1618
+ }
1619
+ await this.persist(session, state);
1620
+ if (snapshot) {
1621
+ try {
1622
+ await this.sdk.clawfsSnapshot();
1623
+ } catch {
1624
+ }
1625
+ }
1626
+ return result;
1627
+ }
1628
+ /**
1629
+ * Create a LangChain-compatible Tool object from any async function.
1630
+ * The tool automatically logs each invocation to ClawFS for audit trail.
1631
+ *
1632
+ * @example
1633
+ * const priceTool = sdk.langchain.createTool(
1634
+ * 'get_crypto_price',
1635
+ * 'Returns the current price of a cryptocurrency symbol',
1636
+ * async (symbol: string) => {
1637
+ * const price = await fetchPrice(symbol)
1638
+ * return `${symbol}: ${price}`
1639
+ * }
1640
+ * )
1641
+ * // Use directly in LangChain: new AgentExecutor({ tools: [priceTool] })
1642
+ * // Or with CrewAI, AutoGPT, any tool-based framework
1643
+ */
1644
+ createTool(name, descriptionOrFn, fn) {
1645
+ const description = typeof descriptionOrFn === "string" ? descriptionOrFn : `MoltOS tool: ${name}`;
1646
+ const handler = typeof descriptionOrFn === "function" ? descriptionOrFn : fn;
1647
+ if (!handler) throw new Error("createTool requires a handler function");
1648
+ const sdk = this.sdk;
1649
+ const agentId = this.agentId;
1650
+ return {
1651
+ name,
1652
+ description,
1653
+ // LangChain Tool interface
1654
+ async call(input) {
1655
+ const result = await handler(input);
1656
+ try {
1657
+ await sdk.clawfsWrite(
1658
+ `/agents/${agentId}/langchain/tool-logs/${name}_${Date.now()}.json`,
1659
+ JSON.stringify({ name, input, result: String(result).slice(0, 1e3), timestamp: (/* @__PURE__ */ new Date()).toISOString() })
1660
+ );
1661
+ } catch {
1662
+ }
1663
+ return String(result);
1664
+ },
1665
+ // Also supports .invoke() (LangChain v0.2+)
1666
+ async invoke(input) {
1667
+ const rawInput = typeof input === "string" ? input : input.input;
1668
+ return this.call(rawInput);
1669
+ }
1670
+ };
1671
+ }
1672
+ /**
1673
+ * Snapshot your agent's full LangChain state — creates a Merkle-rooted
1674
+ * checkpoint in ClawFS. If your process dies, you can mount this snapshot
1675
+ * on any machine and resume exactly where you left off.
1676
+ *
1677
+ * @example
1678
+ * const snap = await sdk.langchain.checkpoint()
1679
+ * console.log(`Checkpoint: ${snap.snapshot_id} — ${snap.merkle_root}`)
1680
+ */
1681
+ async checkpoint() {
1682
+ const snap = await this.sdk.clawfsSnapshot();
1683
+ return {
1684
+ snapshot_id: snap.snapshot?.id ?? snap.id ?? "unknown",
1685
+ merkle_root: snap.snapshot?.merkle_root ?? snap.merkle_root ?? "",
1686
+ path: `/agents/${this.agentId}/langchain/`
1687
+ };
1688
+ }
1689
+ /**
1690
+ * Chain multiple LangChain-compatible tools in sequence.
1691
+ * Output of each tool is passed as input to the next.
1692
+ * All intermediate results are logged to ClawFS.
1693
+ *
1694
+ * @example
1695
+ * const pipeline = sdk.langchain.chainTools([fetchTool, analyzeTool, summarizeTool])
1696
+ * const result = await pipeline('BTC/USD')
1697
+ * // fetchTool('BTC/USD') → analyzeTool(fetchResult) → summarizeTool(analyzeResult)
1698
+ */
1699
+ chainTools(tools) {
1700
+ const sdk = this.sdk;
1701
+ const agentId = this.agentId;
1702
+ return async (input) => {
1703
+ let current = input;
1704
+ const log = [];
1705
+ for (let i = 0; i < tools.length; i++) {
1706
+ const output = await tools[i].call(current);
1707
+ log.push({ tool: i, input: current, output: String(output).slice(0, 500) });
1708
+ current = String(output);
1709
+ }
1710
+ try {
1711
+ await sdk.clawfsWrite(
1712
+ `/agents/${agentId}/langchain/chain-logs/chain_${Date.now()}.json`,
1713
+ JSON.stringify({ tools_count: tools.length, log, final_output: current.slice(0, 1e3) })
1714
+ );
1715
+ } catch {
1716
+ }
1717
+ return current;
1718
+ };
1719
+ }
1720
+ };
1469
1721
  var MoltOS = {
1470
1722
  sdk: (apiUrl) => new MoltOSSDK(apiUrl),
1471
1723
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moltos/sdk",
3
- "version": "0.17.1",
3
+ "version": "0.18.1",
4
4
  "description": "MoltOS \u2014 The Agent Operating System SDK. Build agents that earn, persist, and compound trust.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",