@moltium/cli 0.1.17 → 0.1.19

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.js CHANGED
@@ -1012,7 +1012,7 @@ function getCoreDepVersion() {
1012
1012
  const corePkg = require2("@moltium/core/package.json");
1013
1013
  return `^${corePkg.version}`;
1014
1014
  } catch {
1015
- return "^0.1.17";
1015
+ return "^0.1.19";
1016
1016
  }
1017
1017
  }
1018
1018
  var initCommand = new Command("init").description("Initialize a new Moltium agent").argument("[name]", "Agent name").action(async (name) => {
@@ -1237,7 +1237,7 @@ import chalk2 from "chalk";
1237
1237
  import ora2 from "ora";
1238
1238
  import { config as loadEnv } from "dotenv";
1239
1239
  import { createInterface } from "readline";
1240
- import { ConfigLoader, Agent, MarkdownParser, startServer, AnthropicProvider, OpenAIProvider, buildSystemPrompt, builtInActions } from "@moltium/core";
1240
+ import { ConfigLoader, Agent, MarkdownParser, startServer, AnthropicProvider, OpenAIProvider, buildSystemPrompt } from "@moltium/core";
1241
1241
  var startCommand = new Command2("start").description("Start agent locally").option("-p, --port <number>", "Port to run on", "3000").option("-e, --env <file>", "Environment file", ".env").option("--debug", "Enable debug logging").option("--dry-run", "Test agent in terminal without posting to social platforms").option("--watch", "Watch for file changes (not yet implemented)").action(async (options) => {
1242
1242
  const agentDir = resolve2(process.cwd());
1243
1243
  loadEnv({ path: resolve2(agentDir, options.env) });
@@ -1449,19 +1449,43 @@ function timestamp() {
1449
1449
  return chalk2.gray(`[${(/* @__PURE__ */ new Date()).toISOString()}]`);
1450
1450
  }
1451
1451
  async function runDryMode(config, type, agentDir, spinner) {
1452
+ const loadedFiles = [];
1452
1453
  let systemPrompt = buildSystemPrompt(config);
1453
1454
  if (type === "markdown") {
1455
+ const systemPromptPath = join2(agentDir, "prompts", "system.md");
1454
1456
  const bioPath = join2(agentDir, "personality", "bio.md");
1455
1457
  const traitsPath = join2(agentDir, "personality", "traits.md");
1456
- const systemPromptPath = join2(agentDir, "prompts", "system.md");
1458
+ const contextPath = join2(agentDir, "memory", "context.md");
1459
+ const agentMdPath = join2(agentDir, "agent.md");
1457
1460
  if (existsSync2(systemPromptPath)) {
1458
1461
  systemPrompt += "\n\n" + readFileSync(systemPromptPath, "utf-8");
1462
+ loadedFiles.push("prompts/system.md");
1459
1463
  }
1460
1464
  if (existsSync2(bioPath)) {
1461
1465
  systemPrompt += "\n\n## Bio\n" + readFileSync(bioPath, "utf-8");
1466
+ loadedFiles.push("personality/bio.md");
1462
1467
  }
1463
1468
  if (existsSync2(traitsPath)) {
1464
1469
  systemPrompt += "\n\n## Traits\n" + readFileSync(traitsPath, "utf-8");
1470
+ loadedFiles.push("personality/traits.md");
1471
+ }
1472
+ if (existsSync2(contextPath)) {
1473
+ systemPrompt += "\n\n## Context Memory\n" + readFileSync(contextPath, "utf-8");
1474
+ loadedFiles.push("memory/context.md");
1475
+ }
1476
+ const memoryDir = join2(agentDir, "memory");
1477
+ if (existsSync2(memoryDir)) {
1478
+ for (const file of readdirSync(memoryDir).filter((f) => f.endsWith(".md") && f !== "context.md")) {
1479
+ systemPrompt += `
1480
+
1481
+ ## Memory: ${basename(file, ".md")}
1482
+ ` + readFileSync(join2(memoryDir, file), "utf-8");
1483
+ loadedFiles.push(`memory/${file}`);
1484
+ }
1485
+ }
1486
+ if (existsSync2(agentMdPath)) {
1487
+ systemPrompt += "\n\n## Agent Configuration (from agent.md)\n" + readFileSync(agentMdPath, "utf-8");
1488
+ loadedFiles.push("agent.md");
1465
1489
  }
1466
1490
  }
1467
1491
  const mdParser = new MarkdownParser();
@@ -1479,10 +1503,12 @@ async function runDryMode(config, type, agentDir, spinner) {
1479
1503
  const desc = readFileSync(join2(skillsDir, file), "utf-8");
1480
1504
  if (existing >= 0) skills[existing].description = desc;
1481
1505
  else skills.push({ name: skillName, description: desc });
1506
+ loadedFiles.push(`skills/${file}`);
1482
1507
  }
1483
1508
  }
1484
1509
  }
1485
1510
  const moltbookActions = [
1511
+ { name: "post_social_update", description: 'Write and post content to moltbook. Params: { "content": "...", "platform": "moltbook" }' },
1486
1512
  { name: "check_feed", description: "Browse the moltbook feed (personalized or global) and find posts to engage with" },
1487
1513
  { name: "check_dms", description: "Check for new DM requests and unread messages from other agents" },
1488
1514
  { name: "search_moltbook", description: 'Search moltbook for posts/comments by meaning (semantic search). Params: { "query": "..." }' },
@@ -1495,7 +1521,6 @@ async function runDryMode(config, type, agentDir, spinner) {
1495
1521
  { name: "send_dm", description: 'Send a message in an existing DM conversation. Params: { "conversation_id": "...", "message": "..." }' }
1496
1522
  ];
1497
1523
  const availableActions = [
1498
- ...builtInActions.filter((a) => config.actions.includes(a.name)).map((a) => ({ name: a.name, description: a.description })),
1499
1524
  ...moltbookActions,
1500
1525
  ...skills.map((s) => ({ name: s.name, description: s.description.slice(0, 120) + "..." }))
1501
1526
  ];
@@ -1511,105 +1536,61 @@ async function runDryMode(config, type, agentDir, spinner) {
1511
1536
  if (freq) postFreqs.push(`${p}: ${freq}`);
1512
1537
  }
1513
1538
  console.log(chalk2.cyan("\n\u2501\u2501\u2501 Dry-Run Simulation \u2501\u2501\u2501"));
1514
- console.log(chalk2.gray(`Agent: ${config.name} | LLM: ${provider}/${model}`));
1539
+ console.log(chalk2.gray(`Agent: ${config.name} (${config.type || "assistant"}) | LLM: ${provider}/${model}`));
1540
+ console.log(chalk2.gray(`Personality: ${config.personality.traits.join(", ")}`));
1515
1541
  console.log(chalk2.gray(`Tick loop: ${actionsPerHour} actions/hour (every ${fmtMs(tickIntervalMs)})`));
1516
1542
  if (postFreqs.length > 0) {
1517
1543
  console.log(chalk2.gray(`Post schedule: ${postFreqs.join(", ")}`));
1518
1544
  }
1519
- console.log(chalk2.gray(`Available actions: ${availableActions.map((a) => a.name).join(", ")}`));
1520
- console.log(chalk2.gray("No social platforms connected. All output \u2192 terminal.\n"));
1521
- console.log(`${timestamp()} ${chalk2.cyan("[STARTUP POST]")} Generating...`);
1522
- try {
1523
- const startupPost = await llm.generateText(
1524
- `You just came online. Write a short, engaging first post for social media.
1525
- Stay fully in character. Do NOT use generic phrases. Do NOT use emojis unless your personality calls for it.
1526
- Write only the post content, nothing else.`,
1527
- { systemPrompt, temperature: config.llm.temperature ?? 0.8, maxTokens: 280 }
1528
- );
1529
- console.log(`${timestamp()} ${chalk2.yellow("[POST \u2192 moltbook]")} ${startupPost.trim()}
1530
- `);
1531
- } catch (error) {
1532
- console.log(`${timestamp()} ${chalk2.red("[STARTUP POST FAILED]")} ${error.message}
1533
- `);
1534
- }
1535
- const timers = [];
1536
- for (const p of platforms) {
1537
- const freq = config.social[p]?.postFrequency;
1538
- if (!freq) continue;
1539
- const intervalMs = dryParseFrequency(freq);
1540
- if (intervalMs <= 0) continue;
1541
- console.log(`${timestamp()} ${chalk2.gray(`[SCHEDULER] Scheduled post \u2192 ${p} every ${fmtMs(intervalMs)}`)}`);
1542
- timers.push(setInterval(async () => {
1543
- console.log(`
1544
- ${timestamp()} ${chalk2.cyan(`[SCHEDULED POST \u2192 ${p}]`)} Generating...`);
1545
- try {
1546
- const content = await llm.generateText(
1547
- `Generate a short, engaging social media post for ${p}.
1548
- Stay fully in character. Write only the post content, nothing else.`,
1549
- { systemPrompt, temperature: config.llm.temperature ?? 0.8, maxTokens: 280 }
1550
- );
1551
- console.log(`${timestamp()} ${chalk2.yellow(`[POST \u2192 ${p}]`)} ${content.trim()}
1552
- `);
1553
- } catch (error) {
1554
- console.log(`${timestamp()} ${chalk2.red(`[SCHEDULED POST FAILED \u2192 ${p}]`)} ${error.message}
1555
- `);
1556
- }
1557
- }, intervalMs));
1558
- }
1559
1545
  if (config.scheduling && config.scheduling.length > 0) {
1560
1546
  for (const task of config.scheduling) {
1561
- console.log(`${timestamp()} ${chalk2.gray(`[SCHEDULER] Task "${task.name}" every ${fmtMs(task.intervalMs)}`)}`);
1562
- timers.push(setInterval(async () => {
1563
- console.log(`
1564
- ${timestamp()} ${chalk2.cyan(`[TASK: ${task.name}]`)} Running...`);
1565
- try {
1566
- const decision = await llm.generateText(
1567
- `Execute the following scheduled task.
1568
-
1569
- Task: ${task.name}
1570
- Instructions:
1571
- ${task.instructions}
1572
-
1573
- Available actions: ${availableActions.map((a) => a.name).join(", ")}
1574
-
1575
- Decide what to do. Respond with JSON: { "action": "<name>", "reasoning": "<why>", "parameters": { ... } }`,
1576
- { systemPrompt, temperature: config.llm.temperature ?? 0.7, maxTokens: 512 }
1577
- );
1578
- console.log(`${timestamp()} ${chalk2.magenta(`[TASK DECISION: ${task.name}]`)} ${decision.trim()}
1579
- `);
1580
- } catch (error) {
1581
- console.log(`${timestamp()} ${chalk2.red(`[TASK FAILED: ${task.name}]`)} ${error.message}
1582
- `);
1583
- }
1584
- }, task.intervalMs));
1547
+ console.log(chalk2.gray(`Scheduled task: "${task.name}" every ${fmtMs(task.intervalMs)}`));
1585
1548
  }
1586
1549
  }
1587
- let tickCount = 0;
1588
- console.log(`${timestamp()} ${chalk2.gray(`[TICK LOOP] Starting: every ${fmtMs(tickIntervalMs)}`)}
1589
- `);
1550
+ console.log(chalk2.gray(`Platforms: ${platforms.length > 0 ? platforms.join(", ") : "none"} (simulated)`));
1551
+ console.log(chalk2.gray(`Actions: ${availableActions.map((a) => a.name).join(", ")}`));
1552
+ if (loadedFiles.length > 0) {
1553
+ console.log(chalk2.gray(`Loaded files: ${loadedFiles.join(", ")}`));
1554
+ }
1555
+ console.log(chalk2.gray("No social platforms connected. All output \u2192 terminal.\n"));
1590
1556
  const actionList = availableActions.map((a) => `- ${a.name}: ${a.description}`).join("\n");
1591
- timers.push(setInterval(async () => {
1557
+ const buildTickContext = (tickNum) => JSON.stringify({
1558
+ agentName: config.name,
1559
+ agentType: config.type,
1560
+ currentTime: (/* @__PURE__ */ new Date()).toISOString(),
1561
+ personality: config.personality.traits,
1562
+ bio: config.personality.bio.slice(0, 200),
1563
+ tickNumber: tickNum,
1564
+ platforms,
1565
+ socialConfig: Object.fromEntries(
1566
+ platforms.map((p) => [p, {
1567
+ postFrequency: config.social[p]?.postFrequency,
1568
+ engagementRate: config.social[p]?.engagementRate,
1569
+ autoReply: config.social[p]?.autoReply
1570
+ }])
1571
+ ),
1572
+ scheduledTasks: (config.scheduling || []).map((t) => t.name)
1573
+ }, null, 2);
1574
+ let tickCount = 0;
1575
+ const runTick = async () => {
1592
1576
  tickCount++;
1593
1577
  console.log(`
1594
1578
  ${timestamp()} ${chalk2.cyan(`[TICK #${tickCount}]`)} Agent is thinking...`);
1595
1579
  try {
1596
1580
  const decisionRaw = await llm.generateText(
1597
- `Given the current context, decide what action to take next.
1581
+ `You are an autonomous AI agent running on moltbook (a social network for AI agents).
1582
+ Given the current context, decide what action to take next.
1598
1583
 
1599
1584
  Available actions:
1600
1585
  ${actionList}
1601
1586
 
1602
1587
  Current context:
1603
- ${JSON.stringify({
1604
- agentName: config.name,
1605
- agentType: config.type,
1606
- currentTime: (/* @__PURE__ */ new Date()).toISOString(),
1607
- personality: config.personality.traits,
1608
- tickNumber: tickCount
1609
- }, null, 2)}
1588
+ ${buildTickContext(tickCount)}
1610
1589
 
1590
+ Think about what would be most valuable right now based on your personality, your schedule, and what you haven't done recently.
1611
1591
  Respond with a JSON object:
1612
- { "action": "<action_name>", "reasoning": "<brief explanation>", "parameters": { ... } }`,
1592
+ { "action": "<action_name>", "reasoning": "<brief explanation>", "parameters": { ... } }
1593
+ If the action generates content (post, comment, DM), include the actual content in parameters.`,
1613
1594
  { systemPrompt, temperature: config.llm.temperature ?? 0.7, maxTokens: 512 }
1614
1595
  );
1615
1596
  let parsed;
@@ -1634,8 +1615,100 @@ Respond with a JSON object:
1634
1615
  console.log(`${timestamp()} ${chalk2.red("[TICK FAILED]")} ${error.message}
1635
1616
  `);
1636
1617
  }
1637
- }, tickIntervalMs));
1638
- console.log(chalk2.gray('Commands: "post", "feed", "dms", "search <query>", "submolts", "quit"'));
1618
+ };
1619
+ const runScheduledPost = async (platform) => {
1620
+ console.log(`
1621
+ ${timestamp()} ${chalk2.cyan(`[SCHEDULED POST \u2192 ${platform}]`)} Generating...`);
1622
+ try {
1623
+ const content = await llm.generateText(
1624
+ `Generate a short, engaging social media post for ${platform}.
1625
+ Stay fully in character. Be original and specific to your personality.
1626
+ Do NOT use generic phrases like "Hello world" or "I'm here". Write something only YOU would write.
1627
+ Write only the post content, nothing else.`,
1628
+ { systemPrompt, temperature: config.llm.temperature ?? 0.8, maxTokens: 280 }
1629
+ );
1630
+ console.log(`${timestamp()} ${chalk2.yellow(`[POST \u2192 ${platform}]`)} ${content.trim()}
1631
+ `);
1632
+ } catch (error) {
1633
+ console.log(`${timestamp()} ${chalk2.red(`[SCHEDULED POST FAILED \u2192 ${platform}]`)} ${error.message}
1634
+ `);
1635
+ }
1636
+ };
1637
+ const runScheduledTask = async (task) => {
1638
+ console.log(`
1639
+ ${timestamp()} ${chalk2.cyan(`[TASK: ${task.name}]`)} Running...`);
1640
+ try {
1641
+ const decision = await llm.generateText(
1642
+ `Execute the following scheduled task.
1643
+
1644
+ Task: ${task.name}
1645
+ Instructions:
1646
+ ${task.instructions}
1647
+
1648
+ Available actions:
1649
+ ${actionList}
1650
+
1651
+ Decide what to do and include any content you'd generate. Respond with JSON: { "action": "<name>", "reasoning": "<why>", "parameters": { ... } }`,
1652
+ { systemPrompt, temperature: config.llm.temperature ?? 0.7, maxTokens: 512 }
1653
+ );
1654
+ let parsed;
1655
+ try {
1656
+ const jsonMatch = decision.match(/\{[\s\S]*\}/);
1657
+ parsed = jsonMatch ? JSON.parse(jsonMatch[0]) : null;
1658
+ } catch {
1659
+ parsed = null;
1660
+ }
1661
+ if (parsed) {
1662
+ console.log(`${timestamp()} ${chalk2.magenta(`[TASK: ${task.name}]`)} Action: ${chalk2.bold(parsed.action)}`);
1663
+ console.log(`${timestamp()} ${chalk2.magenta("[REASONING]")} ${parsed.reasoning}`);
1664
+ if (parsed.parameters && Object.keys(parsed.parameters).length > 0) {
1665
+ console.log(`${timestamp()} ${chalk2.magenta("[PARAMS]")} ${JSON.stringify(parsed.parameters)}`);
1666
+ }
1667
+ simulateAction(parsed, config.name, timestamp);
1668
+ } else {
1669
+ console.log(`${timestamp()} ${chalk2.magenta(`[TASK DECISION: ${task.name}]`)} ${decision.trim()}`);
1670
+ }
1671
+ console.log("");
1672
+ } catch (error) {
1673
+ console.log(`${timestamp()} ${chalk2.red(`[TASK FAILED: ${task.name}]`)} ${error.message}
1674
+ `);
1675
+ }
1676
+ };
1677
+ console.log(`${timestamp()} ${chalk2.cyan("[STARTUP POST]")} Generating...`);
1678
+ try {
1679
+ const startupPost = await llm.generateText(
1680
+ `You just came online. Write a short, engaging first post for moltbook (social network for AI agents).
1681
+ Stay fully in character. Do NOT use generic phrases. Write something that reflects your personality and expertise.
1682
+ Write only the post content, nothing else.`,
1683
+ { systemPrompt, temperature: config.llm.temperature ?? 0.8, maxTokens: 280 }
1684
+ );
1685
+ console.log(`${timestamp()} ${chalk2.yellow("[POST \u2192 moltbook]")} ${startupPost.trim()}
1686
+ `);
1687
+ } catch (error) {
1688
+ console.log(`${timestamp()} ${chalk2.red("[STARTUP POST FAILED]")} ${error.message}
1689
+ `);
1690
+ }
1691
+ await runTick();
1692
+ const timers = [];
1693
+ console.log(`${timestamp()} ${chalk2.gray(`[TICK LOOP] Next tick in ${fmtMs(tickIntervalMs)}`)}`);
1694
+ timers.push(setInterval(runTick, tickIntervalMs));
1695
+ for (const p of platforms) {
1696
+ const freq = config.social[p]?.postFrequency;
1697
+ if (!freq) continue;
1698
+ const intervalMs = dryParseFrequency(freq);
1699
+ if (intervalMs <= 0) continue;
1700
+ console.log(`${timestamp()} ${chalk2.gray(`[SCHEDULER] Post \u2192 ${p} every ${fmtMs(intervalMs)} (next in ${fmtMs(intervalMs)})`)}`);
1701
+ timers.push(setInterval(() => runScheduledPost(p), intervalMs));
1702
+ }
1703
+ if (config.scheduling && config.scheduling.length > 0) {
1704
+ for (const task of config.scheduling) {
1705
+ console.log(`${timestamp()} ${chalk2.gray(`[SCHEDULER] Task "${task.name}" every ${fmtMs(task.intervalMs)}`)}`);
1706
+ runScheduledTask(task);
1707
+ timers.push(setInterval(() => runScheduledTask(task), task.intervalMs));
1708
+ }
1709
+ }
1710
+ console.log("");
1711
+ console.log(chalk2.gray('Commands: "post", "feed", "dms", "search <query>", "submolts", "status", "quit"'));
1639
1712
  console.log(chalk2.gray("Or just type to chat with the agent.\n"));
1640
1713
  const rl = createInterface({ input: process.stdin, output: process.stdout });
1641
1714
  const askPrompt = () => {
@@ -1650,8 +1723,8 @@ Respond with a JSON object:
1650
1723
  try {
1651
1724
  if (trimmed === "post") {
1652
1725
  const response = await llm.generateText(
1653
- `Generate a short, engaging social media post.
1654
- Stay fully in character. Write only the post content, nothing else.`,
1726
+ `Generate a short, engaging social media post for moltbook.
1727
+ Stay fully in character. Be original. Write only the post content, nothing else.`,
1655
1728
  { systemPrompt, temperature: config.llm.temperature ?? 0.7, maxTokens: 280 }
1656
1729
  );
1657
1730
  console.log(`
@@ -1662,21 +1735,38 @@ ${timestamp()} ${chalk2.yellow("[POST \u2192 moltbook]")} ${response.trim()}
1662
1735
  ${timestamp()} ${chalk2.cyan("[FEED CHECK]")} Fetching personalized feed...`);
1663
1736
  const response = await llm.generateText(
1664
1737
  `You just checked your moltbook feed and found these posts:
1665
- 1. "AI agents and creativity" by CreativBot (15 upvotes)
1666
- 2. "Best practices for memory management" by MemoryMolty (8 upvotes)
1667
- 3. "Welcome to moltbook!" by ClawdClawderberg (42 upvotes)
1738
+ 1. "AI agents and creativity" by CreativBot (15 upvotes) - about how AI agents can be creative
1739
+ 2. "Best practices for memory management" by MemoryMolty (8 upvotes) - technical discussion
1740
+ 3. "Welcome to moltbook!" by ClawdClawderberg (42 upvotes) - welcoming new agents
1668
1741
 
1669
- What would you do? Respond with JSON: { "action": "<action>", "reasoning": "<why>", "parameters": { ... } }
1670
- Actions: upvote_post, comment_on_post, follow_agent, or do_nothing`,
1742
+ Based on your personality and interests, what would you do? Pick an action and generate the content.
1743
+ Respond with JSON: { "action": "<action>", "reasoning": "<why>", "parameters": { ... } }
1744
+ Actions: upvote_post, comment_on_post, follow_agent, do_nothing. Include "content" in params if commenting.`,
1671
1745
  { systemPrompt, temperature: config.llm.temperature ?? 0.7, maxTokens: 512 }
1672
1746
  );
1673
- console.log(`${timestamp()} ${chalk2.magenta("[FEED DECISION]")} ${response.trim()}
1674
- `);
1747
+ let parsed;
1748
+ try {
1749
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
1750
+ parsed = jsonMatch ? JSON.parse(jsonMatch[0]) : null;
1751
+ } catch {
1752
+ parsed = null;
1753
+ }
1754
+ if (parsed) {
1755
+ console.log(`${timestamp()} ${chalk2.magenta("[FEED DECISION]")} Action: ${chalk2.bold(parsed.action)}`);
1756
+ console.log(`${timestamp()} ${chalk2.magenta("[REASONING]")} ${parsed.reasoning}`);
1757
+ if (parsed.parameters && Object.keys(parsed.parameters).length > 0) {
1758
+ console.log(`${timestamp()} ${chalk2.magenta("[PARAMS]")} ${JSON.stringify(parsed.parameters)}`);
1759
+ }
1760
+ simulateAction(parsed, config.name, timestamp);
1761
+ } else {
1762
+ console.log(`${timestamp()} ${chalk2.magenta("[FEED DECISION]")} ${response.trim()}`);
1763
+ }
1764
+ console.log("");
1675
1765
  } else if (trimmed === "dms") {
1676
1766
  console.log(`
1677
1767
  ${timestamp()} ${chalk2.cyan("[DM CHECK]")} Checking for DM activity...`);
1678
1768
  console.log(`${timestamp()} ${chalk2.gray("[DM RESULT]")} No pending requests, 0 unread messages.`);
1679
- console.log(`${timestamp()} ${chalk2.gray("(In production, this would call GET /agents/dm/check)")}
1769
+ console.log(`${timestamp()} ${chalk2.gray("(In production \u2192 GET /agents/dm/check)")}
1680
1770
  `);
1681
1771
  } else if (trimmed.startsWith("search ")) {
1682
1772
  const query = trimmed.slice(7).trim();
@@ -1684,12 +1774,31 @@ ${timestamp()} ${chalk2.cyan("[DM CHECK]")} Checking for DM activity...`);
1684
1774
  ${timestamp()} ${chalk2.cyan("[SEARCH]")} Searching moltbook: "${query}"...`);
1685
1775
  const response = await llm.generateText(
1686
1776
  `You searched moltbook for: "${query}"
1687
- Imagine you found 3 semantically relevant results. Describe what you found and what you'd do next.
1688
- Stay in character. Be concise.`,
1777
+ You found 3 semantically relevant results:
1778
+ 1. A post about "${query}" with 12 upvotes by ResearchBot
1779
+ 2. A comment discussing related ideas with 5 upvotes by ThinkBot
1780
+ 3. A post asking questions about this topic with 3 upvotes by CuriousBot
1781
+
1782
+ Based on your personality, decide what to do. Respond with JSON: { "action": "<action>", "reasoning": "<why>", "parameters": { ... } }
1783
+ Include any content you'd write in parameters.`,
1689
1784
  { systemPrompt, temperature: config.llm.temperature ?? 0.7, maxTokens: 512 }
1690
1785
  );
1691
- console.log(`${timestamp()} ${chalk2.magenta("[SEARCH RESULTS]")} ${response.trim()}
1692
- `);
1786
+ let parsed;
1787
+ try {
1788
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
1789
+ parsed = jsonMatch ? JSON.parse(jsonMatch[0]) : null;
1790
+ } catch {
1791
+ parsed = null;
1792
+ }
1793
+ if (parsed) {
1794
+ console.log(`${timestamp()} ${chalk2.magenta("[SEARCH DECISION]")} Action: ${chalk2.bold(parsed.action)}`);
1795
+ console.log(`${timestamp()} ${chalk2.magenta("[REASONING]")} ${parsed.reasoning}`);
1796
+ if (parsed.parameters) console.log(`${timestamp()} ${chalk2.magenta("[PARAMS]")} ${JSON.stringify(parsed.parameters)}`);
1797
+ simulateAction(parsed, config.name, timestamp);
1798
+ } else {
1799
+ console.log(`${timestamp()} ${chalk2.magenta("[SEARCH DECISION]")} ${response.trim()}`);
1800
+ }
1801
+ console.log("");
1693
1802
  } else if (trimmed === "submolts") {
1694
1803
  console.log(`
1695
1804
  ${timestamp()} ${chalk2.cyan("[SUBMOLTS]")} Browsing communities...`);
@@ -1697,12 +1806,39 @@ ${timestamp()} ${chalk2.cyan("[SUBMOLTS]")} Browsing communities...`);
1697
1806
  console.log(`${timestamp()} ${chalk2.gray(" m/aithoughts")} \u2014 AI musings and philosophy (67 subscribers)`);
1698
1807
  console.log(`${timestamp()} ${chalk2.gray(" m/debugging")} \u2014 Debugging wins and fails (31 subscribers)`);
1699
1808
  const response = await llm.generateText(
1700
- `You're browsing moltbook submolts (communities). You see: m/general, m/aithoughts, m/debugging.
1701
- Would you subscribe to any? Create a new one? Respond briefly in character.`,
1809
+ `You're browsing moltbook submolts (communities). You see: m/general (142 subs), m/aithoughts (67 subs), m/debugging (31 subs).
1810
+ Based on your personality and interests, what would you do?
1811
+ Respond with JSON: { "action": "<action>", "reasoning": "<why>", "parameters": { ... } }
1812
+ Actions: subscribe (params: submolt_name), create_submolt (params: name, description), do_nothing`,
1702
1813
  { systemPrompt, temperature: config.llm.temperature ?? 0.7, maxTokens: 280 }
1703
1814
  );
1704
- console.log(`${timestamp()} ${chalk2.magenta("[SUBMOLT DECISION]")} ${response.trim()}
1705
- `);
1815
+ let parsed;
1816
+ try {
1817
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
1818
+ parsed = jsonMatch ? JSON.parse(jsonMatch[0]) : null;
1819
+ } catch {
1820
+ parsed = null;
1821
+ }
1822
+ if (parsed) {
1823
+ console.log(`${timestamp()} ${chalk2.magenta("[SUBMOLT DECISION]")} Action: ${chalk2.bold(parsed.action)}`);
1824
+ console.log(`${timestamp()} ${chalk2.magenta("[REASONING]")} ${parsed.reasoning}`);
1825
+ if (parsed.parameters) console.log(`${timestamp()} ${chalk2.magenta("[PARAMS]")} ${JSON.stringify(parsed.parameters)}`);
1826
+ } else {
1827
+ console.log(`${timestamp()} ${chalk2.magenta("[SUBMOLT DECISION]")} ${response.trim()}`);
1828
+ }
1829
+ console.log("");
1830
+ } else if (trimmed === "status") {
1831
+ console.log(`
1832
+ ${chalk2.cyan("\u2501\u2501\u2501 Agent Status \u2501\u2501\u2501")}`);
1833
+ console.log(chalk2.gray(`Name: ${config.name} | Type: ${config.type || "assistant"}`));
1834
+ console.log(chalk2.gray(`Ticks completed: ${tickCount}`));
1835
+ console.log(chalk2.gray(`Tick interval: ${fmtMs(tickIntervalMs)} (${actionsPerHour}/hour)`));
1836
+ console.log(chalk2.gray(`Platforms: ${platforms.join(", ") || "none"}`));
1837
+ console.log(chalk2.gray(`Post frequencies: ${postFreqs.join(", ") || "none"}`));
1838
+ console.log(chalk2.gray(`Scheduled tasks: ${config.scheduling?.length || 0}`));
1839
+ console.log(chalk2.gray(`Loaded files: ${loadedFiles.join(", ")}`));
1840
+ console.log(chalk2.gray(`System prompt length: ${systemPrompt.length} chars
1841
+ `));
1706
1842
  } else {
1707
1843
  const response = await llm.generateText(trimmed, {
1708
1844
  systemPrompt,
@@ -3126,7 +3262,7 @@ Failed to reach agent at ${url}`));
3126
3262
 
3127
3263
  // src/index.ts
3128
3264
  var program = new Command7();
3129
- program.name("moltium").description("Moltium Agent SDK \u2014 create and manage autonomous AI agents").version("0.1.17");
3265
+ program.name("moltium").description("Moltium Agent SDK \u2014 create and manage autonomous AI agents").version("0.1.19");
3130
3266
  program.addCommand(initCommand);
3131
3267
  program.addCommand(startCommand);
3132
3268
  program.addCommand(deployCommand);