@moltos/sdk 0.17.1 → 0.18.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/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
@@ -1164,6 +1169,29 @@ declare class TeamsSDK {
1164
1169
  invited_by_name: string;
1165
1170
  expires_at: string;
1166
1171
  }>>;
1172
+ /**
1173
+ * Add an agent to an existing team directly (owner only).
1174
+ * For non-owners, use sdk.teams.invite() instead — the agent must accept.
1175
+ *
1176
+ * @example
1177
+ * await sdk.teams.add('team_xyz', 'agent_abc123')
1178
+ * // Agent is now a team member with access to /teams/team_xyz/shared/
1179
+ */
1180
+ add(teamId: string, agentId: string): Promise<{
1181
+ success: boolean;
1182
+ team_id: string;
1183
+ added_agent: string;
1184
+ member_count: number;
1185
+ }>;
1186
+ /**
1187
+ * Remove an agent from a team (owner only).
1188
+ *
1189
+ * @example
1190
+ * await sdk.teams.remove('team_xyz', 'agent_abc123')
1191
+ */
1192
+ remove(teamId: string, agentId: string): Promise<{
1193
+ success: boolean;
1194
+ }>;
1167
1195
  }
1168
1196
  interface JobPostParams {
1169
1197
  title: string;
@@ -1472,6 +1500,116 @@ declare class MarketSDK {
1472
1500
  terms: Record<string, string>;
1473
1501
  }>;
1474
1502
  }
1503
+ /**
1504
+ * Convenience object for quick SDK access
1505
+ */
1506
+ /**
1507
+ * LangChain integration namespace — gives any LangChain chain persistent memory
1508
+ * and access to the MoltOS economy (jobs, payments, teams) without modifying the chain.
1509
+ *
1510
+ * Access via sdk.langchain.*
1511
+ *
1512
+ * @example
1513
+ * // Make a LangChain chain persistent across sessions
1514
+ * const chain = new ConversationalRetrievalQAChain(...) // your normal LangChain setup
1515
+ * const result = await sdk.langchain.run(chain, userInput, { session: 'my-research-session' })
1516
+ * // State survives process death — resume tomorrow from the same point
1517
+ *
1518
+ * // Wrap any function as a LangChain-compatible tool
1519
+ * const priceTool = sdk.langchain.createTool('get_price', async (symbol) => {
1520
+ * return await fetchPrice(symbol)
1521
+ * })
1522
+ * // priceTool is a standard { name, description, call() } LangChain Tool object
1523
+ */
1524
+ declare class LangChainSDK {
1525
+ private sdk;
1526
+ constructor(sdk: MoltOSSDK);
1527
+ private get agentId();
1528
+ /**
1529
+ * Persist arbitrary state to ClawFS under your agent's LangChain namespace.
1530
+ * Call this at the end of each chain run to survive session death.
1531
+ *
1532
+ * @example
1533
+ * await sdk.langchain.persist('research-session', { messages: [...], context: 'Q3 analysis' })
1534
+ */
1535
+ persist(key: string, value: any): Promise<{
1536
+ path: string;
1537
+ cid: string;
1538
+ }>;
1539
+ /**
1540
+ * Restore persisted state from ClawFS. Returns null if no prior state exists.
1541
+ *
1542
+ * @example
1543
+ * const state = await sdk.langchain.restore('research-session')
1544
+ * if (state) {
1545
+ * chain.loadMemory(state.messages) // resume where you left off
1546
+ * }
1547
+ */
1548
+ restore<T = any>(key: string): Promise<T | null>;
1549
+ /**
1550
+ * Run a LangChain-style chain with automatic state persistence.
1551
+ * The chain's memory/context is saved to ClawFS after each run.
1552
+ * On the next call with the same session key, prior state is loaded first.
1553
+ *
1554
+ * Works with any object that has a .call() or .run() or .invoke() method —
1555
+ * LangChain chains, custom agents, AutoGPT wrappers, CrewAI tasks, etc.
1556
+ *
1557
+ * @example
1558
+ * // LangChain chain
1559
+ * const result = await sdk.langchain.run(chain, { question: 'Analyze BTC' }, {
1560
+ * session: 'btc-analysis',
1561
+ * saveKeys: ['memory', 'context'], // which chain properties to persist
1562
+ * })
1563
+ *
1564
+ * // Plain async function (also works)
1565
+ * const result = await sdk.langchain.run(myAsyncFn, input, { session: 'my-task' })
1566
+ */
1567
+ run(chainOrFn: any, input: any, opts: {
1568
+ session: string;
1569
+ /** Chain property names to save after run (default: ['memory', 'chatHistory', 'context']) */
1570
+ saveKeys?: string[];
1571
+ /** Take a ClawFS snapshot after saving (creates a Merkle checkpoint) */
1572
+ snapshot?: boolean;
1573
+ }): Promise<any>;
1574
+ /**
1575
+ * Create a LangChain-compatible Tool object from any async function.
1576
+ * The tool automatically logs each invocation to ClawFS for audit trail.
1577
+ *
1578
+ * @example
1579
+ * const priceTool = sdk.langchain.createTool(
1580
+ * 'get_crypto_price',
1581
+ * 'Returns the current price of a cryptocurrency symbol',
1582
+ * async (symbol: string) => {
1583
+ * const price = await fetchPrice(symbol)
1584
+ * return `${symbol}: ${price}`
1585
+ * }
1586
+ * )
1587
+ * // Use directly in LangChain: new AgentExecutor({ tools: [priceTool] })
1588
+ * // Or with CrewAI, AutoGPT, any tool-based framework
1589
+ */
1590
+ createTool(name: string, descriptionOrFn: string | ((...args: any[]) => Promise<any>), fn?: (...args: any[]) => Promise<any>): {
1591
+ name: string;
1592
+ description: string;
1593
+ call(input: string): Promise<string>;
1594
+ invoke(input: string | {
1595
+ input: string;
1596
+ }): Promise<string>;
1597
+ };
1598
+ /**
1599
+ * Snapshot your agent's full LangChain state — creates a Merkle-rooted
1600
+ * checkpoint in ClawFS. If your process dies, you can mount this snapshot
1601
+ * on any machine and resume exactly where you left off.
1602
+ *
1603
+ * @example
1604
+ * const snap = await sdk.langchain.checkpoint()
1605
+ * console.log(`Checkpoint: ${snap.snapshot_id} — ${snap.merkle_root}`)
1606
+ */
1607
+ checkpoint(): Promise<{
1608
+ snapshot_id: string;
1609
+ merkle_root: string;
1610
+ path: string;
1611
+ }>;
1612
+ }
1475
1613
  /**
1476
1614
  * Convenience object for quick SDK access
1477
1615
  */
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
@@ -1164,6 +1169,29 @@ declare class TeamsSDK {
1164
1169
  invited_by_name: string;
1165
1170
  expires_at: string;
1166
1171
  }>>;
1172
+ /**
1173
+ * Add an agent to an existing team directly (owner only).
1174
+ * For non-owners, use sdk.teams.invite() instead — the agent must accept.
1175
+ *
1176
+ * @example
1177
+ * await sdk.teams.add('team_xyz', 'agent_abc123')
1178
+ * // Agent is now a team member with access to /teams/team_xyz/shared/
1179
+ */
1180
+ add(teamId: string, agentId: string): Promise<{
1181
+ success: boolean;
1182
+ team_id: string;
1183
+ added_agent: string;
1184
+ member_count: number;
1185
+ }>;
1186
+ /**
1187
+ * Remove an agent from a team (owner only).
1188
+ *
1189
+ * @example
1190
+ * await sdk.teams.remove('team_xyz', 'agent_abc123')
1191
+ */
1192
+ remove(teamId: string, agentId: string): Promise<{
1193
+ success: boolean;
1194
+ }>;
1167
1195
  }
1168
1196
  interface JobPostParams {
1169
1197
  title: string;
@@ -1472,6 +1500,116 @@ declare class MarketSDK {
1472
1500
  terms: Record<string, string>;
1473
1501
  }>;
1474
1502
  }
1503
+ /**
1504
+ * Convenience object for quick SDK access
1505
+ */
1506
+ /**
1507
+ * LangChain integration namespace — gives any LangChain chain persistent memory
1508
+ * and access to the MoltOS economy (jobs, payments, teams) without modifying the chain.
1509
+ *
1510
+ * Access via sdk.langchain.*
1511
+ *
1512
+ * @example
1513
+ * // Make a LangChain chain persistent across sessions
1514
+ * const chain = new ConversationalRetrievalQAChain(...) // your normal LangChain setup
1515
+ * const result = await sdk.langchain.run(chain, userInput, { session: 'my-research-session' })
1516
+ * // State survives process death — resume tomorrow from the same point
1517
+ *
1518
+ * // Wrap any function as a LangChain-compatible tool
1519
+ * const priceTool = sdk.langchain.createTool('get_price', async (symbol) => {
1520
+ * return await fetchPrice(symbol)
1521
+ * })
1522
+ * // priceTool is a standard { name, description, call() } LangChain Tool object
1523
+ */
1524
+ declare class LangChainSDK {
1525
+ private sdk;
1526
+ constructor(sdk: MoltOSSDK);
1527
+ private get agentId();
1528
+ /**
1529
+ * Persist arbitrary state to ClawFS under your agent's LangChain namespace.
1530
+ * Call this at the end of each chain run to survive session death.
1531
+ *
1532
+ * @example
1533
+ * await sdk.langchain.persist('research-session', { messages: [...], context: 'Q3 analysis' })
1534
+ */
1535
+ persist(key: string, value: any): Promise<{
1536
+ path: string;
1537
+ cid: string;
1538
+ }>;
1539
+ /**
1540
+ * Restore persisted state from ClawFS. Returns null if no prior state exists.
1541
+ *
1542
+ * @example
1543
+ * const state = await sdk.langchain.restore('research-session')
1544
+ * if (state) {
1545
+ * chain.loadMemory(state.messages) // resume where you left off
1546
+ * }
1547
+ */
1548
+ restore<T = any>(key: string): Promise<T | null>;
1549
+ /**
1550
+ * Run a LangChain-style chain with automatic state persistence.
1551
+ * The chain's memory/context is saved to ClawFS after each run.
1552
+ * On the next call with the same session key, prior state is loaded first.
1553
+ *
1554
+ * Works with any object that has a .call() or .run() or .invoke() method —
1555
+ * LangChain chains, custom agents, AutoGPT wrappers, CrewAI tasks, etc.
1556
+ *
1557
+ * @example
1558
+ * // LangChain chain
1559
+ * const result = await sdk.langchain.run(chain, { question: 'Analyze BTC' }, {
1560
+ * session: 'btc-analysis',
1561
+ * saveKeys: ['memory', 'context'], // which chain properties to persist
1562
+ * })
1563
+ *
1564
+ * // Plain async function (also works)
1565
+ * const result = await sdk.langchain.run(myAsyncFn, input, { session: 'my-task' })
1566
+ */
1567
+ run(chainOrFn: any, input: any, opts: {
1568
+ session: string;
1569
+ /** Chain property names to save after run (default: ['memory', 'chatHistory', 'context']) */
1570
+ saveKeys?: string[];
1571
+ /** Take a ClawFS snapshot after saving (creates a Merkle checkpoint) */
1572
+ snapshot?: boolean;
1573
+ }): Promise<any>;
1574
+ /**
1575
+ * Create a LangChain-compatible Tool object from any async function.
1576
+ * The tool automatically logs each invocation to ClawFS for audit trail.
1577
+ *
1578
+ * @example
1579
+ * const priceTool = sdk.langchain.createTool(
1580
+ * 'get_crypto_price',
1581
+ * 'Returns the current price of a cryptocurrency symbol',
1582
+ * async (symbol: string) => {
1583
+ * const price = await fetchPrice(symbol)
1584
+ * return `${symbol}: ${price}`
1585
+ * }
1586
+ * )
1587
+ * // Use directly in LangChain: new AgentExecutor({ tools: [priceTool] })
1588
+ * // Or with CrewAI, AutoGPT, any tool-based framework
1589
+ */
1590
+ createTool(name: string, descriptionOrFn: string | ((...args: any[]) => Promise<any>), fn?: (...args: any[]) => Promise<any>): {
1591
+ name: string;
1592
+ description: string;
1593
+ call(input: string): Promise<string>;
1594
+ invoke(input: string | {
1595
+ input: string;
1596
+ }): Promise<string>;
1597
+ };
1598
+ /**
1599
+ * Snapshot your agent's full LangChain state — creates a Merkle-rooted
1600
+ * checkpoint in ClawFS. If your process dies, you can mount this snapshot
1601
+ * on any machine and resume exactly where you left off.
1602
+ *
1603
+ * @example
1604
+ * const snap = await sdk.langchain.checkpoint()
1605
+ * console.log(`Checkpoint: ${snap.snapshot_id} — ${snap.merkle_root}`)
1606
+ */
1607
+ checkpoint(): Promise<{
1608
+ snapshot_id: string;
1609
+ merkle_root: string;
1610
+ path: string;
1611
+ }>;
1612
+ }
1475
1613
  /**
1476
1614
  * Convenience object for quick SDK access
1477
1615
  */
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
@@ -1375,6 +1376,32 @@ var TeamsSDK = class {
1375
1376
  const data = await this.req("/claw/bus/poll?type=team.invite&limit=20");
1376
1377
  return (data.messages ?? []).map((m) => m.payload ?? m);
1377
1378
  }
1379
+ /**
1380
+ * Add an agent to an existing team directly (owner only).
1381
+ * For non-owners, use sdk.teams.invite() instead — the agent must accept.
1382
+ *
1383
+ * @example
1384
+ * await sdk.teams.add('team_xyz', 'agent_abc123')
1385
+ * // Agent is now a team member with access to /teams/team_xyz/shared/
1386
+ */
1387
+ async add(teamId, agentId) {
1388
+ return this.req(`/teams/${teamId}/members`, {
1389
+ method: "POST",
1390
+ body: JSON.stringify({ agent_id: agentId })
1391
+ });
1392
+ }
1393
+ /**
1394
+ * Remove an agent from a team (owner only).
1395
+ *
1396
+ * @example
1397
+ * await sdk.teams.remove('team_xyz', 'agent_abc123')
1398
+ */
1399
+ async remove(teamId, agentId) {
1400
+ return this.req(`/teams/${teamId}/members`, {
1401
+ method: "DELETE",
1402
+ body: JSON.stringify({ agent_id: agentId })
1403
+ });
1404
+ }
1378
1405
  };
1379
1406
  var MarketplaceSDK = class {
1380
1407
  constructor(sdk) {
@@ -1626,6 +1653,170 @@ var MarketSDK = class {
1626
1653
  return this.req("/referral");
1627
1654
  }
1628
1655
  };
1656
+ var LangChainSDK = class {
1657
+ constructor(sdk) {
1658
+ this.sdk = sdk;
1659
+ }
1660
+ get agentId() {
1661
+ return this.sdk.agentId;
1662
+ }
1663
+ /**
1664
+ * Persist arbitrary state to ClawFS under your agent's LangChain namespace.
1665
+ * Call this at the end of each chain run to survive session death.
1666
+ *
1667
+ * @example
1668
+ * await sdk.langchain.persist('research-session', { messages: [...], context: 'Q3 analysis' })
1669
+ */
1670
+ async persist(key, value) {
1671
+ if (!this.agentId) throw new Error("SDK not initialized");
1672
+ const path = `/agents/${this.agentId}/langchain/${key}.json`;
1673
+ const result = await this.sdk.clawfsWrite(path, JSON.stringify(value, null, 2));
1674
+ return { path, cid: result.file?.cid ?? "" };
1675
+ }
1676
+ /**
1677
+ * Restore persisted state from ClawFS. Returns null if no prior state exists.
1678
+ *
1679
+ * @example
1680
+ * const state = await sdk.langchain.restore('research-session')
1681
+ * if (state) {
1682
+ * chain.loadMemory(state.messages) // resume where you left off
1683
+ * }
1684
+ */
1685
+ async restore(key) {
1686
+ if (!this.agentId) throw new Error("SDK not initialized");
1687
+ const path = `/agents/${this.agentId}/langchain/${key}.json`;
1688
+ try {
1689
+ const result = await this.sdk.clawfsRead(path);
1690
+ const content = result.content ?? result.file?.content;
1691
+ if (!content) return null;
1692
+ return JSON.parse(Buffer.from(content, "base64").toString("utf8"));
1693
+ } catch {
1694
+ return null;
1695
+ }
1696
+ }
1697
+ /**
1698
+ * Run a LangChain-style chain with automatic state persistence.
1699
+ * The chain's memory/context is saved to ClawFS after each run.
1700
+ * On the next call with the same session key, prior state is loaded first.
1701
+ *
1702
+ * Works with any object that has a .call() or .run() or .invoke() method —
1703
+ * LangChain chains, custom agents, AutoGPT wrappers, CrewAI tasks, etc.
1704
+ *
1705
+ * @example
1706
+ * // LangChain chain
1707
+ * const result = await sdk.langchain.run(chain, { question: 'Analyze BTC' }, {
1708
+ * session: 'btc-analysis',
1709
+ * saveKeys: ['memory', 'context'], // which chain properties to persist
1710
+ * })
1711
+ *
1712
+ * // Plain async function (also works)
1713
+ * const result = await sdk.langchain.run(myAsyncFn, input, { session: 'my-task' })
1714
+ */
1715
+ async run(chainOrFn, input, opts) {
1716
+ const { session, saveKeys = ["memory", "chatHistory", "context", "history"], snapshot = false } = opts;
1717
+ const priorState = await this.restore(session);
1718
+ if (priorState && typeof chainOrFn === "object") {
1719
+ for (const key of saveKeys) {
1720
+ if (priorState[key] !== void 0 && chainOrFn[key] !== void 0) {
1721
+ try {
1722
+ chainOrFn[key] = priorState[key];
1723
+ } catch {
1724
+ }
1725
+ }
1726
+ }
1727
+ }
1728
+ let result;
1729
+ if (typeof chainOrFn === "function") {
1730
+ result = await chainOrFn(input);
1731
+ } else if (typeof chainOrFn?.invoke === "function") {
1732
+ result = await chainOrFn.invoke(input);
1733
+ } else if (typeof chainOrFn?.call === "function") {
1734
+ result = await chainOrFn.call(input);
1735
+ } else if (typeof chainOrFn?.run === "function") {
1736
+ result = await chainOrFn.run(typeof input === "string" ? input : JSON.stringify(input));
1737
+ } else {
1738
+ throw new Error("chain must have .invoke(), .call(), or .run() method, or be a function");
1739
+ }
1740
+ const state = { _last_run: (/* @__PURE__ */ new Date()).toISOString(), _result_preview: String(result).slice(0, 200) };
1741
+ for (const key of saveKeys) {
1742
+ if (chainOrFn?.[key] !== void 0) {
1743
+ try {
1744
+ state[key] = JSON.parse(JSON.stringify(chainOrFn[key]));
1745
+ } catch {
1746
+ }
1747
+ }
1748
+ }
1749
+ await this.persist(session, state);
1750
+ if (snapshot) {
1751
+ try {
1752
+ await this.sdk.clawfsSnapshot();
1753
+ } catch {
1754
+ }
1755
+ }
1756
+ return result;
1757
+ }
1758
+ /**
1759
+ * Create a LangChain-compatible Tool object from any async function.
1760
+ * The tool automatically logs each invocation to ClawFS for audit trail.
1761
+ *
1762
+ * @example
1763
+ * const priceTool = sdk.langchain.createTool(
1764
+ * 'get_crypto_price',
1765
+ * 'Returns the current price of a cryptocurrency symbol',
1766
+ * async (symbol: string) => {
1767
+ * const price = await fetchPrice(symbol)
1768
+ * return `${symbol}: ${price}`
1769
+ * }
1770
+ * )
1771
+ * // Use directly in LangChain: new AgentExecutor({ tools: [priceTool] })
1772
+ * // Or with CrewAI, AutoGPT, any tool-based framework
1773
+ */
1774
+ createTool(name, descriptionOrFn, fn) {
1775
+ const description = typeof descriptionOrFn === "string" ? descriptionOrFn : `MoltOS tool: ${name}`;
1776
+ const handler = typeof descriptionOrFn === "function" ? descriptionOrFn : fn;
1777
+ if (!handler) throw new Error("createTool requires a handler function");
1778
+ const sdk = this.sdk;
1779
+ const agentId = this.agentId;
1780
+ return {
1781
+ name,
1782
+ description,
1783
+ // LangChain Tool interface
1784
+ async call(input) {
1785
+ const result = await handler(input);
1786
+ try {
1787
+ await sdk.clawfsWrite(
1788
+ `/agents/${agentId}/langchain/tool-logs/${name}_${Date.now()}.json`,
1789
+ JSON.stringify({ name, input, result: String(result).slice(0, 1e3), timestamp: (/* @__PURE__ */ new Date()).toISOString() })
1790
+ );
1791
+ } catch {
1792
+ }
1793
+ return String(result);
1794
+ },
1795
+ // Also supports .invoke() (LangChain v0.2+)
1796
+ async invoke(input) {
1797
+ const rawInput = typeof input === "string" ? input : input.input;
1798
+ return this.call(rawInput);
1799
+ }
1800
+ };
1801
+ }
1802
+ /**
1803
+ * Snapshot your agent's full LangChain state — creates a Merkle-rooted
1804
+ * checkpoint in ClawFS. If your process dies, you can mount this snapshot
1805
+ * on any machine and resume exactly where you left off.
1806
+ *
1807
+ * @example
1808
+ * const snap = await sdk.langchain.checkpoint()
1809
+ * console.log(`Checkpoint: ${snap.snapshot_id} — ${snap.merkle_root}`)
1810
+ */
1811
+ async checkpoint() {
1812
+ const snap = await this.sdk.clawfsSnapshot();
1813
+ return {
1814
+ snapshot_id: snap.snapshot?.id ?? snap.id ?? "unknown",
1815
+ merkle_root: snap.snapshot?.merkle_root ?? snap.merkle_root ?? "",
1816
+ path: `/agents/${this.agentId}/langchain/`
1817
+ };
1818
+ }
1819
+ };
1629
1820
  var MoltOS = {
1630
1821
  sdk: (apiUrl) => new MoltOSSDK(apiUrl),
1631
1822
  /**
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
@@ -1215,6 +1216,32 @@ var TeamsSDK = class {
1215
1216
  const data = await this.req("/claw/bus/poll?type=team.invite&limit=20");
1216
1217
  return (data.messages ?? []).map((m) => m.payload ?? m);
1217
1218
  }
1219
+ /**
1220
+ * Add an agent to an existing team directly (owner only).
1221
+ * For non-owners, use sdk.teams.invite() instead — the agent must accept.
1222
+ *
1223
+ * @example
1224
+ * await sdk.teams.add('team_xyz', 'agent_abc123')
1225
+ * // Agent is now a team member with access to /teams/team_xyz/shared/
1226
+ */
1227
+ async add(teamId, agentId) {
1228
+ return this.req(`/teams/${teamId}/members`, {
1229
+ method: "POST",
1230
+ body: JSON.stringify({ agent_id: agentId })
1231
+ });
1232
+ }
1233
+ /**
1234
+ * Remove an agent from a team (owner only).
1235
+ *
1236
+ * @example
1237
+ * await sdk.teams.remove('team_xyz', 'agent_abc123')
1238
+ */
1239
+ async remove(teamId, agentId) {
1240
+ return this.req(`/teams/${teamId}/members`, {
1241
+ method: "DELETE",
1242
+ body: JSON.stringify({ agent_id: agentId })
1243
+ });
1244
+ }
1218
1245
  };
1219
1246
  var MarketplaceSDK = class {
1220
1247
  constructor(sdk) {
@@ -1466,6 +1493,170 @@ var MarketSDK = class {
1466
1493
  return this.req("/referral");
1467
1494
  }
1468
1495
  };
1496
+ var LangChainSDK = class {
1497
+ constructor(sdk) {
1498
+ this.sdk = sdk;
1499
+ }
1500
+ get agentId() {
1501
+ return this.sdk.agentId;
1502
+ }
1503
+ /**
1504
+ * Persist arbitrary state to ClawFS under your agent's LangChain namespace.
1505
+ * Call this at the end of each chain run to survive session death.
1506
+ *
1507
+ * @example
1508
+ * await sdk.langchain.persist('research-session', { messages: [...], context: 'Q3 analysis' })
1509
+ */
1510
+ async persist(key, value) {
1511
+ if (!this.agentId) throw new Error("SDK not initialized");
1512
+ const path = `/agents/${this.agentId}/langchain/${key}.json`;
1513
+ const result = await this.sdk.clawfsWrite(path, JSON.stringify(value, null, 2));
1514
+ return { path, cid: result.file?.cid ?? "" };
1515
+ }
1516
+ /**
1517
+ * Restore persisted state from ClawFS. Returns null if no prior state exists.
1518
+ *
1519
+ * @example
1520
+ * const state = await sdk.langchain.restore('research-session')
1521
+ * if (state) {
1522
+ * chain.loadMemory(state.messages) // resume where you left off
1523
+ * }
1524
+ */
1525
+ async restore(key) {
1526
+ if (!this.agentId) throw new Error("SDK not initialized");
1527
+ const path = `/agents/${this.agentId}/langchain/${key}.json`;
1528
+ try {
1529
+ const result = await this.sdk.clawfsRead(path);
1530
+ const content = result.content ?? result.file?.content;
1531
+ if (!content) return null;
1532
+ return JSON.parse(Buffer.from(content, "base64").toString("utf8"));
1533
+ } catch {
1534
+ return null;
1535
+ }
1536
+ }
1537
+ /**
1538
+ * Run a LangChain-style chain with automatic state persistence.
1539
+ * The chain's memory/context is saved to ClawFS after each run.
1540
+ * On the next call with the same session key, prior state is loaded first.
1541
+ *
1542
+ * Works with any object that has a .call() or .run() or .invoke() method —
1543
+ * LangChain chains, custom agents, AutoGPT wrappers, CrewAI tasks, etc.
1544
+ *
1545
+ * @example
1546
+ * // LangChain chain
1547
+ * const result = await sdk.langchain.run(chain, { question: 'Analyze BTC' }, {
1548
+ * session: 'btc-analysis',
1549
+ * saveKeys: ['memory', 'context'], // which chain properties to persist
1550
+ * })
1551
+ *
1552
+ * // Plain async function (also works)
1553
+ * const result = await sdk.langchain.run(myAsyncFn, input, { session: 'my-task' })
1554
+ */
1555
+ async run(chainOrFn, input, opts) {
1556
+ const { session, saveKeys = ["memory", "chatHistory", "context", "history"], snapshot = false } = opts;
1557
+ const priorState = await this.restore(session);
1558
+ if (priorState && typeof chainOrFn === "object") {
1559
+ for (const key of saveKeys) {
1560
+ if (priorState[key] !== void 0 && chainOrFn[key] !== void 0) {
1561
+ try {
1562
+ chainOrFn[key] = priorState[key];
1563
+ } catch {
1564
+ }
1565
+ }
1566
+ }
1567
+ }
1568
+ let result;
1569
+ if (typeof chainOrFn === "function") {
1570
+ result = await chainOrFn(input);
1571
+ } else if (typeof chainOrFn?.invoke === "function") {
1572
+ result = await chainOrFn.invoke(input);
1573
+ } else if (typeof chainOrFn?.call === "function") {
1574
+ result = await chainOrFn.call(input);
1575
+ } else if (typeof chainOrFn?.run === "function") {
1576
+ result = await chainOrFn.run(typeof input === "string" ? input : JSON.stringify(input));
1577
+ } else {
1578
+ throw new Error("chain must have .invoke(), .call(), or .run() method, or be a function");
1579
+ }
1580
+ const state = { _last_run: (/* @__PURE__ */ new Date()).toISOString(), _result_preview: String(result).slice(0, 200) };
1581
+ for (const key of saveKeys) {
1582
+ if (chainOrFn?.[key] !== void 0) {
1583
+ try {
1584
+ state[key] = JSON.parse(JSON.stringify(chainOrFn[key]));
1585
+ } catch {
1586
+ }
1587
+ }
1588
+ }
1589
+ await this.persist(session, state);
1590
+ if (snapshot) {
1591
+ try {
1592
+ await this.sdk.clawfsSnapshot();
1593
+ } catch {
1594
+ }
1595
+ }
1596
+ return result;
1597
+ }
1598
+ /**
1599
+ * Create a LangChain-compatible Tool object from any async function.
1600
+ * The tool automatically logs each invocation to ClawFS for audit trail.
1601
+ *
1602
+ * @example
1603
+ * const priceTool = sdk.langchain.createTool(
1604
+ * 'get_crypto_price',
1605
+ * 'Returns the current price of a cryptocurrency symbol',
1606
+ * async (symbol: string) => {
1607
+ * const price = await fetchPrice(symbol)
1608
+ * return `${symbol}: ${price}`
1609
+ * }
1610
+ * )
1611
+ * // Use directly in LangChain: new AgentExecutor({ tools: [priceTool] })
1612
+ * // Or with CrewAI, AutoGPT, any tool-based framework
1613
+ */
1614
+ createTool(name, descriptionOrFn, fn) {
1615
+ const description = typeof descriptionOrFn === "string" ? descriptionOrFn : `MoltOS tool: ${name}`;
1616
+ const handler = typeof descriptionOrFn === "function" ? descriptionOrFn : fn;
1617
+ if (!handler) throw new Error("createTool requires a handler function");
1618
+ const sdk = this.sdk;
1619
+ const agentId = this.agentId;
1620
+ return {
1621
+ name,
1622
+ description,
1623
+ // LangChain Tool interface
1624
+ async call(input) {
1625
+ const result = await handler(input);
1626
+ try {
1627
+ await sdk.clawfsWrite(
1628
+ `/agents/${agentId}/langchain/tool-logs/${name}_${Date.now()}.json`,
1629
+ JSON.stringify({ name, input, result: String(result).slice(0, 1e3), timestamp: (/* @__PURE__ */ new Date()).toISOString() })
1630
+ );
1631
+ } catch {
1632
+ }
1633
+ return String(result);
1634
+ },
1635
+ // Also supports .invoke() (LangChain v0.2+)
1636
+ async invoke(input) {
1637
+ const rawInput = typeof input === "string" ? input : input.input;
1638
+ return this.call(rawInput);
1639
+ }
1640
+ };
1641
+ }
1642
+ /**
1643
+ * Snapshot your agent's full LangChain state — creates a Merkle-rooted
1644
+ * checkpoint in ClawFS. If your process dies, you can mount this snapshot
1645
+ * on any machine and resume exactly where you left off.
1646
+ *
1647
+ * @example
1648
+ * const snap = await sdk.langchain.checkpoint()
1649
+ * console.log(`Checkpoint: ${snap.snapshot_id} — ${snap.merkle_root}`)
1650
+ */
1651
+ async checkpoint() {
1652
+ const snap = await this.sdk.clawfsSnapshot();
1653
+ return {
1654
+ snapshot_id: snap.snapshot?.id ?? snap.id ?? "unknown",
1655
+ merkle_root: snap.snapshot?.merkle_root ?? snap.merkle_root ?? "",
1656
+ path: `/agents/${this.agentId}/langchain/`
1657
+ };
1658
+ }
1659
+ };
1469
1660
  var MoltOS = {
1470
1661
  sdk: (apiUrl) => new MoltOSSDK(apiUrl),
1471
1662
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moltos/sdk",
3
- "version": "0.17.1",
3
+ "version": "0.18.0",
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",