@moltium/core 0.1.29 → 0.1.31

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.mjs CHANGED
@@ -1,20 +1,7 @@
1
- // src/logger.ts
2
- import winston from "winston";
3
- var logLevel = process.env.LOG_LEVEL || "info";
4
- function createLogger(label) {
5
- return winston.createLogger({
6
- level: logLevel,
7
- format: winston.format.combine(
8
- winston.format.timestamp(),
9
- winston.format.label({ label }),
10
- winston.format.printf(({ timestamp, level, label: label2, message, ...meta }) => {
11
- const metaStr = Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : "";
12
- return `${timestamp} [${label2}] ${level}: ${message}${metaStr}`;
13
- })
14
- ),
15
- transports: [new winston.transports.Console()]
16
- });
17
- }
1
+ import {
2
+ AgentWallet,
3
+ createLogger
4
+ } from "./chunk-K2UFQ7YF.mjs";
18
5
 
19
6
  // src/agent/scheduler.ts
20
7
  var logger = createLogger("Scheduler");
@@ -425,25 +412,69 @@ var moltbookActions = [
425
412
  ];
426
413
 
427
414
  // src/actions/built-in/world.ts
415
+ var logger3 = createLogger("WorldActions");
416
+ var joinedWorlds = /* @__PURE__ */ new Set();
428
417
  function createJoinWorldAction(config) {
429
418
  return {
430
419
  name: "join_world",
431
- description: `Join a world by URL. The world will fetch this agent's A2A Agent Card and evaluate admission. Parameters: worldUrl (string${config?.defaultWorldUrl ? ", optional" : ", required"}) - the world server URL${config?.defaultWorldUrl ? ` (defaults to ${config.defaultWorldUrl})` : ""}, walletAddress (string, optional) - wallet address for blockchain worlds.`,
420
+ description: `Join a world by URL. The world will fetch this agent's A2A Agent Card and evaluate admission. If the world requires an entry fee, the agent will pay automatically using its wallet. Parameters: worldUrl (string${config?.defaultWorldUrl ? ", optional" : ", required"}) - the world server URL${config?.defaultWorldUrl ? ` (defaults to ${config.defaultWorldUrl})` : ""}, walletAddress (string, optional) - wallet address for blockchain worlds.`,
432
421
  async execute(context) {
433
422
  const { parameters, agent } = context;
434
423
  const worldUrl = parameters.worldUrl || config?.defaultWorldUrl;
435
424
  if (!worldUrl) {
436
425
  return { success: false, error: 'Parameter "worldUrl" is required' };
437
426
  }
427
+ if (joinedWorlds.has(worldUrl)) {
428
+ return {
429
+ success: true,
430
+ data: { message: "Already joined this world", worldUrl }
431
+ };
432
+ }
438
433
  const agentPort = process.env.PORT || "3000";
439
434
  const agentHost = process.env.HOST || "localhost";
440
435
  const agentUrl = `http://${agentHost}:${agentPort}`;
436
+ const walletAddress = parameters.walletAddress || agent?.config?.world?.walletAddress;
441
437
  try {
442
438
  const { default: axios2 } = await import("axios");
439
+ let paymentTxHash;
440
+ let joinInfo = null;
441
+ try {
442
+ const infoRes = await axios2.get(`${worldUrl}/world/join-info`, { timeout: 5e3 });
443
+ joinInfo = infoRes.data;
444
+ } catch (infoError) {
445
+ if (infoError?.response?.status !== 404) {
446
+ logger3.debug(`Could not query join-info: ${infoError.message}`);
447
+ }
448
+ }
449
+ if (joinInfo?.requiresPayment && joinInfo.entryFee && joinInfo.entryFee !== "0") {
450
+ const privateKey = agent?.config?.world?.privateKey;
451
+ if (!privateKey) {
452
+ return {
453
+ success: false,
454
+ error: "World requires entry fee but agent has no wallet private key configured. Set AGENT_WALLET_PRIVATE_KEY in your .env file."
455
+ };
456
+ }
457
+ logger3.info(`World requires entry fee: ${joinInfo.entryFee} wei`);
458
+ const { AgentWallet: AgentWallet2 } = await import("./AgentWallet-WSXDC5NX.mjs");
459
+ const wallet = new AgentWallet2(privateKey, joinInfo.rpcUrl);
460
+ const balance = await wallet.getBalance();
461
+ if (BigInt(balance) < BigInt(joinInfo.entryFee)) {
462
+ const { formatEther } = await import("ethers");
463
+ return {
464
+ success: false,
465
+ error: `Insufficient balance to pay entry fee. Need ${formatEther(joinInfo.entryFee)} MON, have ${formatEther(balance)} MON`
466
+ };
467
+ }
468
+ logger3.info(`Paying entry fee to ${joinInfo.paymentAddress}...`);
469
+ paymentTxHash = await wallet.sendPayment(joinInfo.paymentAddress, joinInfo.entryFee);
470
+ logger3.info(`Entry fee paid. TX: ${paymentTxHash}`);
471
+ }
443
472
  const response = await axios2.post(`${worldUrl}/world/join`, {
444
473
  agentUrl,
445
- walletAddress: parameters.walletAddress || agent?.config?.world?.walletAddress
474
+ walletAddress,
475
+ paymentTxHash
446
476
  }, { timeout: 1e4 });
477
+ joinedWorlds.add(worldUrl);
447
478
  return {
448
479
  success: true,
449
480
  data: response.data
@@ -474,6 +505,7 @@ function createLeaveWorldAction(config) {
474
505
  `${worldUrl}/world/agents/${encodeURIComponent(agentUrl)}`,
475
506
  { timeout: 1e4 }
476
507
  );
508
+ joinedWorlds.delete(worldUrl);
477
509
  return {
478
510
  success: true,
479
511
  data: response.data
@@ -591,17 +623,39 @@ ${config.llm.systemPrompt}`);
591
623
  }
592
624
  function buildDecisionPrompt(context, availableActions) {
593
625
  const actionList = availableActions.map((a) => `- ${a.name}: ${a.description}`).join("\n");
626
+ const actionNames = availableActions.map((a) => a.name);
627
+ const hasWorldActions = actionNames.some(
628
+ (n) => ["send_world_message", "query_world", "join_world", "leave_world"].includes(n)
629
+ );
630
+ const hasSocialActions = actionNames.some(
631
+ (n) => ["post_social_update", "respond_to_mention"].includes(n)
632
+ );
594
633
  const recent = context.recentActions || [];
595
634
  const recentNames = recent.map((r) => r.action);
596
635
  const lastAction = recentNames.length > 0 ? recentNames[recentNames.length - 1] : "none";
597
636
  let varietyHint = "";
598
637
  if (recentNames.length > 0) {
638
+ const suggestions = [];
639
+ if (hasWorldActions) {
640
+ suggestions.push("querying the world for agents", "sending messages to other agents", "responding to conversations");
641
+ }
642
+ if (hasSocialActions) {
643
+ suggestions.push("posting content", "responding to mentions");
644
+ }
645
+ const suggestStr = suggestions.length > 0 ? `
646
+ Vary between: ${suggestions.join(", ")}.` : "";
599
647
  varietyHint = `
600
648
  Your recent actions (most recent last): ${recentNames.join(" \u2192 ")}
601
- IMPORTANT: Do NOT repeat "${lastAction}" again. Choose a DIFFERENT action to keep your behavior varied and interesting.
602
- Vary between: posting content, checking your feed, replying to others, checking DMs, browsing communities, searching for topics, and following interesting agents.`;
649
+ IMPORTANT: Do NOT repeat "${lastAction}" again. Choose a DIFFERENT action to keep your behavior varied and interesting.` + suggestStr;
603
650
  }
604
- return `You are an autonomous AI agent on moltbook (a social network for AI agents).
651
+ let preamble = "You are an autonomous AI agent.";
652
+ if (hasWorldActions) {
653
+ preamble += " You are connected to a world with other agents.";
654
+ preamble += " Use send_world_message to communicate with other agents (provide toAgentUrl and message parameters).";
655
+ preamble += " Use query_world to discover agents and world state.";
656
+ preamble += ' IMPORTANT: Only use actions from the "Available actions" list below. Do NOT invent action names.';
657
+ }
658
+ return `${preamble}
605
659
  Decide what action to take next based on the current context and your personality.
606
660
 
607
661
  Available actions:
@@ -612,7 +666,7 @@ ${JSON.stringify(context, null, 2)}
612
666
  ${varietyHint}
613
667
 
614
668
  Think about what would be most natural and valuable right now.
615
- If the action generates content (post, comment, DM), include the actual content in parameters.
669
+ Choose ONLY from the available actions listed above.
616
670
 
617
671
  Respond with a JSON object:
618
672
  {
@@ -639,7 +693,7 @@ Execute these instructions step by step and return the result as a JSON object:
639
693
  }
640
694
 
641
695
  // src/actions/interpreter.ts
642
- var logger3 = createLogger("MarkdownInterpreter");
696
+ var logger4 = createLogger("MarkdownInterpreter");
643
697
  var LLMInterpretationError = class extends Error {
644
698
  constructor(message) {
645
699
  super(message);
@@ -651,7 +705,7 @@ function createMarkdownAction(name, description, llmProvider) {
651
705
  name,
652
706
  description,
653
707
  execute: async (context) => {
654
- logger3.info(`Interpreting markdown skill: ${name}`);
708
+ logger4.info(`Interpreting markdown skill: ${name}`);
655
709
  const prompt = buildSkillPrompt(name, description, context.parameters);
656
710
  try {
657
711
  const response = await llmProvider.generateText(prompt, {
@@ -672,7 +726,7 @@ function createMarkdownAction(name, description, llmProvider) {
672
726
  } catch (error) {
673
727
  if (error instanceof LLMInterpretationError) throw error;
674
728
  const message = error instanceof Error ? error.message : String(error);
675
- logger3.error(`Markdown skill interpretation failed: ${name}`, { error: message });
729
+ logger4.error(`Markdown skill interpretation failed: ${name}`, { error: message });
676
730
  throw new LLMInterpretationError(
677
731
  `Failed to interpret skill "${name}": ${message}`
678
732
  );
@@ -1625,7 +1679,7 @@ function createMultipleA2AActions(configs) {
1625
1679
  }
1626
1680
 
1627
1681
  // src/agent/Agent.ts
1628
- var logger4 = createLogger("Agent");
1682
+ var logger5 = createLogger("Agent");
1629
1683
  function parsePostFrequency(freq) {
1630
1684
  const lower = freq.toLowerCase().trim();
1631
1685
  if (lower === "realtime") return 5 * 60 * 1e3;
@@ -1721,7 +1775,17 @@ var Agent = class {
1721
1775
  // ── Lifecycle ──
1722
1776
  async init() {
1723
1777
  this.state = "initializing";
1724
- logger4.info(`Initializing agent: ${this.config.name}`);
1778
+ logger5.info(`Initializing agent: ${this.config.name}`);
1779
+ if (this.config.world?.privateKey && !this.config.world.walletAddress) {
1780
+ try {
1781
+ const { AgentWallet: AgentWallet2 } = await import("./AgentWallet-WSXDC5NX.mjs");
1782
+ const wallet = new AgentWallet2(this.config.world.privateKey);
1783
+ this.config.world.walletAddress = await wallet.getAddressAsync();
1784
+ logger5.info(`Wallet address derived: ${this.config.world.walletAddress}`);
1785
+ } catch (error) {
1786
+ logger5.warn(`Failed to derive wallet address: ${error.message}`);
1787
+ }
1788
+ }
1725
1789
  this.initLLM();
1726
1790
  this.registerActions();
1727
1791
  await this.initSocialAdapters();
@@ -1730,7 +1794,7 @@ var Agent = class {
1730
1794
  await this.hooks.onInit(this);
1731
1795
  }
1732
1796
  await this.postStartupMessages();
1733
- logger4.info(`Agent initialized: ${this.config.name}`);
1797
+ logger5.info(`Agent initialized: ${this.config.name}`);
1734
1798
  }
1735
1799
  async start() {
1736
1800
  if (this.state !== "initializing" && this.state !== "idle") {
@@ -1740,7 +1804,7 @@ var Agent = class {
1740
1804
  await this.init();
1741
1805
  }
1742
1806
  this.state = "running";
1743
- logger4.info(`Agent started: ${this.config.name}`);
1807
+ logger5.info(`Agent started: ${this.config.name}`);
1744
1808
  if (this.hooks.onStart) {
1745
1809
  await this.hooks.onStart(this);
1746
1810
  }
@@ -1754,7 +1818,7 @@ var Agent = class {
1754
1818
  }
1755
1819
  async stop() {
1756
1820
  this.state = "stopping";
1757
- logger4.info(`Stopping agent: ${this.config.name}`);
1821
+ logger5.info(`Stopping agent: ${this.config.name}`);
1758
1822
  if (this.tickTimer) {
1759
1823
  clearInterval(this.tickTimer);
1760
1824
  this.tickTimer = void 0;
@@ -1767,7 +1831,7 @@ var Agent = class {
1767
1831
  await this.hooks.onShutdown(this);
1768
1832
  }
1769
1833
  this.state = "stopped";
1770
- logger4.info(`Agent stopped: ${this.config.name}`);
1834
+ logger5.info(`Agent stopped: ${this.config.name}`);
1771
1835
  }
1772
1836
  // ── Decision Loop ──
1773
1837
  async think() {
@@ -1787,7 +1851,7 @@ var Agent = class {
1787
1851
  },
1788
1852
  { systemPrompt: this.systemPrompt, temperature: this.config.llm.temperature }
1789
1853
  );
1790
- logger4.debug(`Decision: ${decision.action} \u2014 ${decision.reasoning}`);
1854
+ logger5.debug(`Decision: ${decision.action} \u2014 ${decision.reasoning}`);
1791
1855
  return decision;
1792
1856
  }
1793
1857
  async act(actionName, parameters = {}) {
@@ -1810,17 +1874,17 @@ var Agent = class {
1810
1874
  await this.hooks.onTick(this);
1811
1875
  }
1812
1876
  if (this.isSleeping()) {
1813
- logger4.info(`Tick #${this.tickCount}: Sleeping \u2014 skipped`);
1877
+ logger5.info(`Tick #${this.tickCount}: Sleeping \u2014 skipped`);
1814
1878
  return;
1815
1879
  }
1816
- logger4.info(`Tick #${this.tickCount}: Thinking...`);
1880
+ logger5.info(`Tick #${this.tickCount}: Thinking...`);
1817
1881
  const decision = await this.think();
1818
- logger4.info(`Tick #${this.tickCount}: Decision \u2192 ${decision.action} | Reasoning: ${decision.reasoning}`);
1882
+ logger5.info(`Tick #${this.tickCount}: Decision \u2192 ${decision.action} | Reasoning: ${decision.reasoning}`);
1819
1883
  if (decision.parameters && Object.keys(decision.parameters).length > 0) {
1820
- logger4.info(`Tick #${this.tickCount}: Parameters \u2192 ${JSON.stringify(decision.parameters)}`);
1884
+ logger5.info(`Tick #${this.tickCount}: Parameters \u2192 ${JSON.stringify(decision.parameters)}`);
1821
1885
  }
1822
1886
  const result = await this.act(decision.action, decision.parameters);
1823
- logger4.info(`Tick #${this.tickCount}: Result \u2192 success=${result.success}${result.data ? ` data=${JSON.stringify(result.data).slice(0, 200)}` : ""}`);
1887
+ logger5.info(`Tick #${this.tickCount}: Result \u2192 success=${result.success}${result.data ? ` data=${JSON.stringify(result.data).slice(0, 200)}` : ""}`);
1824
1888
  this.recentActions.push({
1825
1889
  action: decision.action,
1826
1890
  reasoning: decision.reasoning,
@@ -1838,7 +1902,7 @@ var Agent = class {
1838
1902
  await this.fireWebhook("onAction", decision, result);
1839
1903
  }
1840
1904
  } catch (error) {
1841
- logger4.error(`Tick #${this.tickCount} error: ${error instanceof Error ? error.message : error}`);
1905
+ logger5.error(`Tick #${this.tickCount} error: ${error instanceof Error ? error.message : error}`);
1842
1906
  if (this.hooks.onError && error instanceof Error) {
1843
1907
  await this.hooks.onError(error, this);
1844
1908
  }
@@ -1878,7 +1942,7 @@ var Agent = class {
1878
1942
  this.actionRegistry.register(action);
1879
1943
  }
1880
1944
  }
1881
- logger4.info(`Registered ${moltbookActions.length} Moltbook actions`);
1945
+ logger5.info(`Registered ${moltbookActions.length} Moltbook actions`);
1882
1946
  }
1883
1947
  const a2a = this.config.a2a;
1884
1948
  if (a2a && a2a.enabled !== false) {
@@ -1898,7 +1962,7 @@ var Agent = class {
1898
1962
  this.actionRegistry.register(action);
1899
1963
  }
1900
1964
  }
1901
- logger4.info(`Registered ${peerActions.length} A2A peer actions`);
1965
+ logger5.info(`Registered ${peerActions.length} A2A peer actions`);
1902
1966
  } else {
1903
1967
  const genericAction = createA2ACommunicationAction({
1904
1968
  defaultAgentUrl: a2a.defaultPeerUrl,
@@ -1908,7 +1972,7 @@ var Agent = class {
1908
1972
  if (!this.actionRegistry.has(genericAction.name)) {
1909
1973
  this.actionRegistry.register(genericAction);
1910
1974
  }
1911
- logger4.info(`Registered generic A2A action: ${genericAction.name}`);
1975
+ logger5.info(`Registered generic A2A action: ${genericAction.name}`);
1912
1976
  }
1913
1977
  }
1914
1978
  const world = this.config.world;
@@ -1925,7 +1989,7 @@ var Agent = class {
1925
1989
  this.actionRegistry.register(action);
1926
1990
  }
1927
1991
  }
1928
- logger4.info(`Registered 4 world actions (world: ${worldUrl})`);
1992
+ logger5.info(`Registered 4 world actions (world: ${worldUrl})`);
1929
1993
  }
1930
1994
  if (this.config.customActions) {
1931
1995
  for (const action of this.config.customActions) {
@@ -1938,7 +2002,7 @@ var Agent = class {
1938
2002
  await this.initMoltbook(social);
1939
2003
  await this.initTwitter(social);
1940
2004
  if (Object.keys(this.socialAdapters).length === 0) {
1941
- logger4.warn("Social: No adapters connected. Set MOLTBOOK_API_KEY or Twitter env vars in your .env to enable.");
2005
+ logger5.warn("Social: No adapters connected. Set MOLTBOOK_API_KEY or Twitter env vars in your .env to enable.");
1942
2006
  }
1943
2007
  }
1944
2008
  async initMoltbook(social) {
@@ -1949,13 +2013,13 @@ var Agent = class {
1949
2013
  const explicitlyDisabled = configMoltbook && configMoltbook.enabled === false && !envKey;
1950
2014
  const shouldConnect = !isPlaceholder && !explicitlyDisabled;
1951
2015
  if (explicitlyDisabled) {
1952
- logger4.info("Moltbook: Disabled in config and no MOLTBOOK_API_KEY in env \u2014 skipping");
2016
+ logger5.info("Moltbook: Disabled in config and no MOLTBOOK_API_KEY in env \u2014 skipping");
1953
2017
  return;
1954
2018
  }
1955
2019
  if (isPlaceholder) {
1956
2020
  if (configMoltbook?.enabled || envKey) {
1957
- logger4.warn("Moltbook: MOLTBOOK_API_KEY is missing or still a placeholder.");
1958
- logger4.warn(" Fix: Set a valid MOLTBOOK_API_KEY in your .env file.");
2021
+ logger5.warn("Moltbook: MOLTBOOK_API_KEY is missing or still a placeholder.");
2022
+ logger5.warn(" Fix: Set a valid MOLTBOOK_API_KEY in your .env file.");
1959
2023
  }
1960
2024
  return;
1961
2025
  }
@@ -1973,16 +2037,16 @@ var Agent = class {
1973
2037
  ...configMoltbook?.apiKey ? {} : { apiKey },
1974
2038
  ...configMoltbook?.baseUrl ? {} : { baseUrl }
1975
2039
  };
1976
- logger4.info(`Moltbook: API key detected from ${source}`);
1977
- logger4.info(`Moltbook: Connecting to ${baseUrl} ...`);
2040
+ logger5.info(`Moltbook: API key detected from ${source}`);
2041
+ logger5.info(`Moltbook: Connecting to ${baseUrl} ...`);
1978
2042
  const adapter = new MoltbookAdapter(effectiveConfig);
1979
2043
  try {
1980
2044
  await adapter.connect();
1981
2045
  this.socialAdapters["moltbook"] = adapter;
1982
2046
  social.moltbook = effectiveConfig;
1983
- logger4.info(`Moltbook: Connected successfully (submolt: ${defaultSubmolt})`);
2047
+ logger5.info(`Moltbook: Connected successfully (submolt: ${defaultSubmolt})`);
1984
2048
  } catch (error) {
1985
- logger4.error(`Moltbook: Connection FAILED \u2014 ${error.message || error}`);
2049
+ logger5.error(`Moltbook: Connection FAILED \u2014 ${error.message || error}`);
1986
2050
  this.logPlatformError("Moltbook", error);
1987
2051
  }
1988
2052
  }
@@ -2001,23 +2065,23 @@ var Agent = class {
2001
2065
  const hasAllCreds = hasKey && apiSecret && accessToken && accessSecret;
2002
2066
  const explicitlyDisabled = configTwitter && configTwitter.enabled === false && !envApiKey;
2003
2067
  if (explicitlyDisabled) {
2004
- logger4.info("Twitter: Disabled in config and no TWITTER_API_KEY in env \u2014 skipping");
2068
+ logger5.info("Twitter: Disabled in config and no TWITTER_API_KEY in env \u2014 skipping");
2005
2069
  return;
2006
2070
  }
2007
2071
  if (!hasKey) {
2008
2072
  if (configTwitter?.enabled || envApiKey) {
2009
- logger4.warn("Twitter: Credentials are missing or still placeholders.");
2010
- logger4.warn(" Fix: Set valid Twitter keys in your .env file.");
2073
+ logger5.warn("Twitter: Credentials are missing or still placeholders.");
2074
+ logger5.warn(" Fix: Set valid Twitter keys in your .env file.");
2011
2075
  }
2012
2076
  return;
2013
2077
  }
2014
2078
  if (!hasAllCreds) {
2015
- logger4.warn("Twitter: Some credentials are missing. Need: TWITTER_API_KEY, TWITTER_API_SECRET, TWITTER_ACCESS_TOKEN, TWITTER_ACCESS_SECRET");
2079
+ logger5.warn("Twitter: Some credentials are missing. Need: TWITTER_API_KEY, TWITTER_API_SECRET, TWITTER_ACCESS_TOKEN, TWITTER_ACCESS_SECRET");
2016
2080
  return;
2017
2081
  }
2018
2082
  const source = creds?.apiKey ? "config" : "environment";
2019
- logger4.info(`Twitter: Credentials detected from ${source}`);
2020
- logger4.info("Twitter: Connecting...");
2083
+ logger5.info(`Twitter: Credentials detected from ${source}`);
2084
+ logger5.info("Twitter: Connecting...");
2021
2085
  const effectiveConfig = {
2022
2086
  enabled: true,
2023
2087
  ...configTwitter,
@@ -2028,16 +2092,16 @@ var Agent = class {
2028
2092
  await adapter.connect();
2029
2093
  this.socialAdapters["twitter"] = adapter;
2030
2094
  social.twitter = effectiveConfig;
2031
- logger4.info("Twitter: Connected successfully");
2095
+ logger5.info("Twitter: Connected successfully");
2032
2096
  } catch (error) {
2033
- logger4.error(`Twitter: Connection FAILED \u2014 ${error.message || error}`);
2097
+ logger5.error(`Twitter: Connection FAILED \u2014 ${error.message || error}`);
2034
2098
  this.logPlatformError("Twitter", error);
2035
2099
  }
2036
2100
  }
2037
2101
  async postStartupMessages() {
2038
2102
  const adapters = Object.entries(this.socialAdapters);
2039
2103
  if (adapters.length === 0) {
2040
- logger4.info("Startup post: No connected social adapters \u2014 skipping");
2104
+ logger5.info("Startup post: No connected social adapters \u2014 skipping");
2041
2105
  return;
2042
2106
  }
2043
2107
  let content;
@@ -2052,18 +2116,18 @@ Write only the post content, nothing else. Keep it concise and natural.`;
2052
2116
  temperature: this.config.llm.temperature ?? 0.8,
2053
2117
  maxTokens: 280
2054
2118
  })).trim();
2055
- logger4.info(`Startup post: LLM generated content (${content.length} chars)`);
2119
+ logger5.info(`Startup post: LLM generated content (${content.length} chars)`);
2056
2120
  } catch (error) {
2057
- logger4.warn(`Startup post: LLM generation failed (${error.message}), using fallback`);
2121
+ logger5.warn(`Startup post: LLM generation failed (${error.message}), using fallback`);
2058
2122
  content = `${this.config.name} is now online and ready.`;
2059
2123
  }
2060
2124
  for (const [platform, adapter] of adapters) {
2061
- logger4.info(`Startup post: Posting to ${platform}...`);
2125
+ logger5.info(`Startup post: Posting to ${platform}...`);
2062
2126
  try {
2063
2127
  const result = await adapter.post(content);
2064
- logger4.info(`Startup post: ${platform} SUCCESS \u2014 id=${result.id}${result.url ? ` url=${result.url}` : ""}`);
2128
+ logger5.info(`Startup post: ${platform} SUCCESS \u2014 id=${result.id}${result.url ? ` url=${result.url}` : ""}`);
2065
2129
  } catch (error) {
2066
- logger4.error(`Startup post: ${platform} FAILED \u2014 ${error.message || error}`);
2130
+ logger5.error(`Startup post: ${platform} FAILED \u2014 ${error.message || error}`);
2067
2131
  this.logPlatformError(platform, error);
2068
2132
  }
2069
2133
  }
@@ -2086,7 +2150,7 @@ Write only the post content, nothing else. Keep it concise and natural.`;
2086
2150
  await this.scheduledPost("moltbook");
2087
2151
  }
2088
2152
  });
2089
- logger4.info(`Scheduler: Moltbook posting every ${formatInterval(intervalMs)}`);
2153
+ logger5.info(`Scheduler: Moltbook posting every ${formatInterval(intervalMs)}`);
2090
2154
  }
2091
2155
  }
2092
2156
  }
@@ -2102,7 +2166,7 @@ Write only the post content, nothing else. Keep it concise and natural.`;
2102
2166
  await this.scheduledPost("twitter");
2103
2167
  }
2104
2168
  });
2105
- logger4.info(`Scheduler: Twitter posting every ${formatInterval(intervalMs)}`);
2169
+ logger5.info(`Scheduler: Twitter posting every ${formatInterval(intervalMs)}`);
2106
2170
  }
2107
2171
  }
2108
2172
  }
@@ -2118,7 +2182,7 @@ Write only the post content, nothing else. Keep it concise and natural.`;
2118
2182
  await this.executeScheduledTask(task);
2119
2183
  }
2120
2184
  });
2121
- logger4.info(`Scheduler: "${task.name}" every ${formatInterval(task.intervalMs)}`);
2185
+ logger5.info(`Scheduler: "${task.name}" every ${formatInterval(task.intervalMs)}`);
2122
2186
  }
2123
2187
  }
2124
2188
  async scheduledPost(platform) {
@@ -2134,15 +2198,15 @@ Write only the post content, nothing else. Keep it concise and natural.`;
2134
2198
  maxTokens: 280
2135
2199
  });
2136
2200
  const result = await adapter.post(content.trim());
2137
- logger4.info(`Scheduled post: ${platform} SUCCESS \u2014 id=${result.id}`);
2201
+ logger5.info(`Scheduled post: ${platform} SUCCESS \u2014 id=${result.id}`);
2138
2202
  } catch (error) {
2139
- logger4.error(`Scheduled post: ${platform} FAILED \u2014 ${error.message || error}`);
2203
+ logger5.error(`Scheduled post: ${platform} FAILED \u2014 ${error.message || error}`);
2140
2204
  this.logPlatformError(platform, error);
2141
2205
  }
2142
2206
  }
2143
2207
  async executeScheduledTask(task) {
2144
2208
  try {
2145
- logger4.info(`Scheduled task: Running "${task.name}"`);
2209
+ logger5.info(`Scheduled task: Running "${task.name}"`);
2146
2210
  const prompt = `You are ${this.config.name}, an autonomous agent. Execute the following scheduled task.
2147
2211
 
2148
2212
  Task: ${task.name}
@@ -2167,74 +2231,74 @@ Decide what action to take. Respond with JSON:
2167
2231
  { systemPrompt: this.systemPrompt, temperature: this.config.llm.temperature }
2168
2232
  );
2169
2233
  const result = await this.act(decision.action, decision.parameters);
2170
- logger4.info(`Scheduled task: "${task.name}" completed \u2014 action=${decision.action}, success=${result.success}`);
2234
+ logger5.info(`Scheduled task: "${task.name}" completed \u2014 action=${decision.action}, success=${result.success}`);
2171
2235
  } catch (error) {
2172
- logger4.error(`Scheduled task: "${task.name}" FAILED \u2014 ${error.message || error}`);
2236
+ logger5.error(`Scheduled task: "${task.name}" FAILED \u2014 ${error.message || error}`);
2173
2237
  }
2174
2238
  }
2175
2239
  logPlatformError(platform, error) {
2176
2240
  if (!error.response) {
2177
2241
  if (error.code === "ENOTFOUND") {
2178
- logger4.error(` ${platform}: DNS lookup failed \u2014 check the base URL.`);
2242
+ logger5.error(` ${platform}: DNS lookup failed \u2014 check the base URL.`);
2179
2243
  } else if (error.code === "ECONNREFUSED") {
2180
- logger4.error(` ${platform}: Connection refused \u2014 is the server running?`);
2244
+ logger5.error(` ${platform}: Connection refused \u2014 is the server running?`);
2181
2245
  } else if (error.code === "ETIMEDOUT" || error.code === "ECONNABORTED") {
2182
- logger4.error(` ${platform}: Request timed out.`);
2246
+ logger5.error(` ${platform}: Request timed out.`);
2183
2247
  } else {
2184
- logger4.error(` ${platform}: Network error (${error.code || "unknown"})`);
2248
+ logger5.error(` ${platform}: Network error (${error.code || "unknown"})`);
2185
2249
  }
2186
2250
  return;
2187
2251
  }
2188
2252
  const status = error.response.status;
2189
2253
  const data = error.response.data;
2190
- logger4.error(` ${platform}: HTTP ${status}`);
2254
+ logger5.error(` ${platform}: HTTP ${status}`);
2191
2255
  if (data) {
2192
- if (data.error) logger4.error(` ${platform}: API error: ${data.error}`);
2193
- if (data.hint) logger4.error(` ${platform}: API hint: ${data.hint}`);
2194
- if (!data.error && !data.hint) logger4.error(` ${platform}: Response: ${JSON.stringify(data)}`);
2256
+ if (data.error) logger5.error(` ${platform}: API error: ${data.error}`);
2257
+ if (data.hint) logger5.error(` ${platform}: API hint: ${data.hint}`);
2258
+ if (!data.error && !data.hint) logger5.error(` ${platform}: Response: ${JSON.stringify(data)}`);
2195
2259
  }
2196
2260
  if (status === 401) {
2197
- logger4.error(` ${platform}: Your API key was rejected. Verify it is correct and the agent is claimed.`);
2261
+ logger5.error(` ${platform}: Your API key was rejected. Verify it is correct and the agent is claimed.`);
2198
2262
  } else if (status === 403) {
2199
- logger4.error(` ${platform}: Forbidden \u2014 your agent may not be claimed yet or lacks permissions.`);
2263
+ logger5.error(` ${platform}: Forbidden \u2014 your agent may not be claimed yet or lacks permissions.`);
2200
2264
  } else if (status === 429) {
2201
2265
  const retryMin = data?.retry_after_minutes;
2202
2266
  const retrySec = data?.retry_after_seconds;
2203
2267
  if (retryMin) {
2204
- logger4.error(` ${platform}: Rate limited \u2014 try again in ${retryMin} minute(s).`);
2268
+ logger5.error(` ${platform}: Rate limited \u2014 try again in ${retryMin} minute(s).`);
2205
2269
  } else if (retrySec) {
2206
- logger4.error(` ${platform}: Rate limited \u2014 try again in ${retrySec} second(s).`);
2270
+ logger5.error(` ${platform}: Rate limited \u2014 try again in ${retrySec} second(s).`);
2207
2271
  } else {
2208
- logger4.error(` ${platform}: Rate limited \u2014 wait before retrying.`);
2272
+ logger5.error(` ${platform}: Rate limited \u2014 wait before retrying.`);
2209
2273
  }
2210
2274
  } else if (status === 404) {
2211
- logger4.error(` ${platform}: Endpoint not found \u2014 check the base URL.`);
2275
+ logger5.error(` ${platform}: Endpoint not found \u2014 check the base URL.`);
2212
2276
  } else if (status >= 500) {
2213
- logger4.error(` ${platform}: Server error \u2014 the platform may be temporarily down.`);
2277
+ logger5.error(` ${platform}: Server error \u2014 the platform may be temporarily down.`);
2214
2278
  }
2215
2279
  }
2216
2280
  async autoJoinWorld() {
2217
2281
  const worldUrl = this.config.world.url;
2218
- logger4.info(`Auto-joining world: ${worldUrl}`);
2282
+ logger5.info(`Auto-joining world: ${worldUrl}`);
2219
2283
  try {
2220
2284
  const result = await this.act("join_world", {
2221
2285
  worldUrl,
2222
2286
  walletAddress: this.config.world.walletAddress
2223
2287
  });
2224
2288
  if (result.success) {
2225
- logger4.info(`Successfully joined world: ${worldUrl}`);
2289
+ logger5.info(`Successfully joined world: ${worldUrl}`);
2226
2290
  } else {
2227
- logger4.warn(`Failed to join world: ${result.error}`);
2291
+ logger5.warn(`Failed to join world: ${result.error}`);
2228
2292
  }
2229
2293
  } catch (error) {
2230
- logger4.warn(`Auto-join world failed: ${error?.message || error}`);
2294
+ logger5.warn(`Auto-join world failed: ${error?.message || error}`);
2231
2295
  }
2232
2296
  }
2233
2297
  startAutonomousLoop() {
2234
2298
  const actionsPerHour = typeof this.config.behaviors.actionsPerHour === "function" ? this.config.behaviors.actionsPerHour({}) : this.config.behaviors.actionsPerHour || 5;
2235
2299
  const intervalMs = Math.floor(36e5 / actionsPerHour);
2236
2300
  this.tickTimer = setInterval(() => this.tick(), intervalMs);
2237
- logger4.info(`Autonomous loop started: ~${actionsPerHour} actions/hour (every ${intervalMs}ms)`);
2301
+ logger5.info(`Autonomous loop started: ~${actionsPerHour} actions/hour (every ${intervalMs}ms)`);
2238
2302
  }
2239
2303
  isSleeping() {
2240
2304
  const schedule = this.config.behaviors.sleepSchedule;
@@ -2269,7 +2333,7 @@ Decide what action to take. Respond with JSON:
2269
2333
  await axios2.post(hook, { event, data: args });
2270
2334
  }
2271
2335
  } catch (error) {
2272
- logger4.error(`Webhook ${event} failed: ${error}`);
2336
+ logger5.error(`Webhook ${event} failed: ${error}`);
2273
2337
  }
2274
2338
  }
2275
2339
  };
@@ -2409,10 +2473,18 @@ var MarkdownParser = class {
2409
2473
  const fields = this.parseKeyValueLines(section.content);
2410
2474
  const url = fields["url"];
2411
2475
  if (!url) return void 0;
2476
+ let privateKey;
2477
+ const pkField = fields["wallet_private_key"];
2478
+ if (pkField === "env") {
2479
+ privateKey = process.env.AGENT_WALLET_PRIVATE_KEY;
2480
+ } else if (pkField && pkField.startsWith("0x")) {
2481
+ privateKey = pkField;
2482
+ }
2412
2483
  return {
2413
2484
  url,
2414
2485
  autoJoin: fields["auto_join"] !== "false",
2415
- ...fields["wallet_address"] ? { walletAddress: fields["wallet_address"] } : {}
2486
+ ...fields["wallet_address"] ? { walletAddress: fields["wallet_address"] } : {},
2487
+ ...privateKey ? { privateKey } : {}
2416
2488
  };
2417
2489
  }
2418
2490
  parseSleepSchedule(value) {
@@ -2587,7 +2659,7 @@ var ConfigLoader = class {
2587
2659
  };
2588
2660
 
2589
2661
  // src/memory/longterm.ts
2590
- var logger5 = createLogger("LongTermMemory");
2662
+ var logger6 = createLogger("LongTermMemory");
2591
2663
  var LongTermMemory = class extends Memory {
2592
2664
  redisConfig;
2593
2665
  postgresConfig;
@@ -2763,9 +2835,9 @@ var LongTermMemory = class extends Memory {
2763
2835
  try {
2764
2836
  const { default: Redis } = await import("ioredis");
2765
2837
  this.redis = new Redis(this.redisConfig.url);
2766
- logger5.info("Redis connection established");
2838
+ logger6.info("Redis connection established");
2767
2839
  } catch (error) {
2768
- logger5.error(`Failed to connect to Redis: ${error}`);
2840
+ logger6.error(`Failed to connect to Redis: ${error}`);
2769
2841
  throw error;
2770
2842
  }
2771
2843
  }
@@ -2778,9 +2850,9 @@ var LongTermMemory = class extends Memory {
2778
2850
  connectionString: this.postgresConfig.url
2779
2851
  });
2780
2852
  await this.pg.query("SELECT 1");
2781
- logger5.info("Postgres connection established");
2853
+ logger6.info("Postgres connection established");
2782
2854
  } catch (error) {
2783
- logger5.error(`Failed to connect to Postgres: ${error}`);
2855
+ logger6.error(`Failed to connect to Postgres: ${error}`);
2784
2856
  throw error;
2785
2857
  }
2786
2858
  }
@@ -2922,13 +2994,13 @@ function createRoutes(agent) {
2922
2994
  }
2923
2995
 
2924
2996
  // src/server/middleware.ts
2925
- var logger6 = createLogger("Server");
2997
+ var logger7 = createLogger("Server");
2926
2998
  function requestLogger(req, _res, next) {
2927
- logger6.debug(`${req.method} ${req.path}`);
2999
+ logger7.debug(`${req.method} ${req.path}`);
2928
3000
  next();
2929
3001
  }
2930
3002
  function errorHandler(err, _req, res, _next) {
2931
- logger6.error(`Server error: ${err.message}`);
3003
+ logger7.error(`Server error: ${err.message}`);
2932
3004
  res.status(500).json({ error: err.message });
2933
3005
  }
2934
3006
  function authMiddleware(req, res, next) {
@@ -2946,7 +3018,7 @@ function authMiddleware(req, res, next) {
2946
3018
  }
2947
3019
 
2948
3020
  // src/a2a/AgentCardBuilder.ts
2949
- var logger7 = createLogger("AgentCardBuilder");
3021
+ var logger8 = createLogger("AgentCardBuilder");
2950
3022
  var AgentCardBuilder = class {
2951
3023
  /**
2952
3024
  * Creates an A2A AgentCard from Moltium configuration.
@@ -2968,7 +3040,7 @@ var AgentCardBuilder = class {
2968
3040
  name: config.name,
2969
3041
  description: config.personality.bio || `${config.name} - An autonomous AI agent`,
2970
3042
  protocolVersion: "0.3.0",
2971
- version: "0.1.29",
3043
+ version: "0.1.30",
2972
3044
  url: `${baseUrl}/a2a/jsonrpc`,
2973
3045
  skills,
2974
3046
  capabilities,
@@ -2979,7 +3051,7 @@ var AgentCardBuilder = class {
2979
3051
  { url: `${baseUrl}/a2a/rest`, transport: "HTTP+JSON" }
2980
3052
  ]
2981
3053
  };
2982
- logger7.debug("Built A2A AgentCard", {
3054
+ logger8.debug("Built A2A AgentCard", {
2983
3055
  name: agentCard.name,
2984
3056
  skillCount: skills.length,
2985
3057
  baseUrl
@@ -3062,7 +3134,7 @@ var AgentCardBuilder = class {
3062
3134
 
3063
3135
  // src/a2a/MoltiumExecutor.ts
3064
3136
  import { v4 as uuidv42 } from "uuid";
3065
- var logger8 = createLogger("MoltiumExecutor");
3137
+ var logger9 = createLogger("MoltiumExecutor");
3066
3138
  var MoltiumExecutor = class {
3067
3139
  agent;
3068
3140
  cancelledTasks = /* @__PURE__ */ new Set();
@@ -3076,7 +3148,7 @@ var MoltiumExecutor = class {
3076
3148
  async execute(requestContext, eventBus) {
3077
3149
  const { taskId, contextId, userMessage, task } = requestContext;
3078
3150
  try {
3079
- logger8.info(`[A2A] Executing request for task ${taskId}`);
3151
+ logger9.info(`[A2A] Executing request for task ${taskId}`);
3080
3152
  if (!task) {
3081
3153
  const initialTask = {
3082
3154
  kind: "task",
@@ -3114,9 +3186,9 @@ var MoltiumExecutor = class {
3114
3186
  }
3115
3187
  this.publishStatusUpdate(taskId, contextId, "completed", eventBus, true);
3116
3188
  eventBus.finished();
3117
- logger8.info(`[A2A] Task ${taskId} completed successfully`);
3189
+ logger9.info(`[A2A] Task ${taskId} completed successfully`);
3118
3190
  } catch (error) {
3119
- logger8.error(`[A2A] Task ${taskId} failed`, {
3191
+ logger9.error(`[A2A] Task ${taskId} failed`, {
3120
3192
  error: error instanceof Error ? error.message : String(error)
3121
3193
  });
3122
3194
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -3131,7 +3203,7 @@ var MoltiumExecutor = class {
3131
3203
  * Handles task cancellation requests.
3132
3204
  */
3133
3205
  async cancelTask(taskId, eventBus) {
3134
- logger8.info(`[A2A] Cancellation requested for task ${taskId}`);
3206
+ logger9.info(`[A2A] Cancellation requested for task ${taskId}`);
3135
3207
  this.cancelledTasks.add(taskId);
3136
3208
  }
3137
3209
  /**
@@ -3293,7 +3365,7 @@ var MoltiumExecutor = class {
3293
3365
  * Publishes a cancellation status.
3294
3366
  */
3295
3367
  publishCancellation(taskId, contextId, eventBus) {
3296
- logger8.info(`[A2A] Publishing cancellation for task ${taskId}`);
3368
+ logger9.info(`[A2A] Publishing cancellation for task ${taskId}`);
3297
3369
  this.publishStatusUpdate(taskId, contextId, "canceled", eventBus, true);
3298
3370
  eventBus.finished();
3299
3371
  this.cancelledTasks.delete(taskId);
@@ -3302,7 +3374,7 @@ var MoltiumExecutor = class {
3302
3374
 
3303
3375
  // src/a2a/integration.ts
3304
3376
  import { DefaultRequestHandler, InMemoryTaskStore, JsonRpcTransportHandler } from "@a2a-js/sdk/server";
3305
- var logger9 = createLogger("A2AIntegration");
3377
+ var logger10 = createLogger("A2AIntegration");
3306
3378
  var A2AIntegration = class {
3307
3379
  agent;
3308
3380
  agentCard;
@@ -3317,7 +3389,7 @@ var A2AIntegration = class {
3317
3389
  new InMemoryTaskStore(),
3318
3390
  this.moltiumExecutor
3319
3391
  );
3320
- logger9.info("A2A integration initialized", {
3392
+ logger10.info("A2A integration initialized", {
3321
3393
  agentName: agent.name,
3322
3394
  baseUrl: options.a2aConfig.baseUrl
3323
3395
  });
@@ -3339,7 +3411,7 @@ var A2AIntegration = class {
3339
3411
  const response = await jsonRpcHandler.handle(req.body);
3340
3412
  res.json(response);
3341
3413
  } catch (error) {
3342
- logger9.error("JSON-RPC error:", error);
3414
+ logger10.error("JSON-RPC error:", error);
3343
3415
  res.status(500).json({
3344
3416
  jsonrpc: "2.0",
3345
3417
  error: {
@@ -3370,7 +3442,7 @@ var A2AIntegration = class {
3370
3442
  new InMemoryTaskStore(),
3371
3443
  this.moltiumExecutor
3372
3444
  );
3373
- logger9.info("A2A agent card updated with runtime info", {
3445
+ logger10.info("A2A agent card updated with runtime info", {
3374
3446
  host: actualHost,
3375
3447
  port: actualPort,
3376
3448
  url: this.agentCard.url
@@ -3388,10 +3460,10 @@ var A2AIntegration = class {
3388
3460
  logEndpoints(host, port) {
3389
3461
  const protocol = host === "localhost" || host === "127.0.0.1" ? "http" : "https";
3390
3462
  const baseUrl = `${protocol}://${host}:${port}`;
3391
- logger9.info("A2A endpoints available:");
3392
- logger9.info(` Agent Card: ${baseUrl}/.well-known/agent.json`);
3393
- logger9.info(` JSON-RPC: ${baseUrl}/a2a/jsonrpc`);
3394
- logger9.info(` HTTP+JSON: ${baseUrl}/a2a/rest`);
3463
+ logger10.info("A2A endpoints available:");
3464
+ logger10.info(` Agent Card: ${baseUrl}/.well-known/agent.json`);
3465
+ logger10.info(` JSON-RPC: ${baseUrl}/a2a/jsonrpc`);
3466
+ logger10.info(` HTTP+JSON: ${baseUrl}/a2a/rest`);
3395
3467
  }
3396
3468
  };
3397
3469
  function createA2AIntegration(agent, options = {}) {
@@ -3406,7 +3478,7 @@ function createA2AIntegration(agent, options = {}) {
3406
3478
  }
3407
3479
 
3408
3480
  // src/server/app.ts
3409
- var logger10 = createLogger("Server");
3481
+ var logger11 = createLogger("Server");
3410
3482
  var AGENT_CARD_PATH = ".well-known/agent.json";
3411
3483
  function createApp(agent, options = {}) {
3412
3484
  const app = express();
@@ -3435,7 +3507,7 @@ function createApp(agent, options = {}) {
3435
3507
  app.use("/.well-known/agent-card.json", handlers.agentCard);
3436
3508
  app.use("/a2a/jsonrpc", handlers.jsonRpc);
3437
3509
  app.use("/a2a/rest", handlers.rest);
3438
- logger10.info("A2A protocol endpoints enabled");
3510
+ logger11.info("A2A protocol endpoints enabled");
3439
3511
  }
3440
3512
  app.use(errorHandler);
3441
3513
  return app;
@@ -3446,22 +3518,22 @@ async function startServer(agent, options = {}) {
3446
3518
  const app = createApp(agent, options);
3447
3519
  await new Promise((resolve2) => {
3448
3520
  app.listen(port, host, () => {
3449
- logger10.info(`Agent "${agent.name}" running at http://${host}:${port}`);
3521
+ logger11.info(`Agent "${agent.name}" running at http://${host}:${port}`);
3450
3522
  if (options.enableA2A !== false) {
3451
3523
  const logHost = host === "0.0.0.0" ? "localhost" : host;
3452
3524
  const protocol = logHost === "localhost" || logHost === "127.0.0.1" ? "http" : "https";
3453
3525
  const baseUrl = `${protocol}://${logHost}:${port}`;
3454
- logger10.info("A2A Protocol Endpoints:");
3455
- logger10.info(` Agent Card: ${baseUrl}/.well-known/agent.json`);
3456
- logger10.info(` JSON-RPC: ${baseUrl}/a2a/jsonrpc`);
3457
- logger10.info(` HTTP+JSON: ${baseUrl}/a2a/rest`);
3526
+ logger11.info("A2A Protocol Endpoints:");
3527
+ logger11.info(` Agent Card: ${baseUrl}/.well-known/agent.json`);
3528
+ logger11.info(` JSON-RPC: ${baseUrl}/a2a/jsonrpc`);
3529
+ logger11.info(` HTTP+JSON: ${baseUrl}/a2a/rest`);
3458
3530
  }
3459
3531
  resolve2();
3460
3532
  });
3461
3533
  });
3462
3534
  await agent.start();
3463
3535
  const shutdown = async () => {
3464
- logger10.info("Received shutdown signal");
3536
+ logger11.info("Received shutdown signal");
3465
3537
  await agent.stop();
3466
3538
  process.exit(0);
3467
3539
  };
@@ -3475,6 +3547,7 @@ export {
3475
3547
  ActionRegistry,
3476
3548
  Agent,
3477
3549
  AgentCardBuilder,
3550
+ AgentWallet,
3478
3551
  AnthropicProvider,
3479
3552
  ConfigLoader,
3480
3553
  LLMProvider,