@moltium/core 0.1.18 → 0.1.20

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
@@ -30,9 +30,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ A2AIntegration: () => A2AIntegration,
33
34
  ActionHandler: () => ActionHandler,
34
35
  ActionRegistry: () => ActionRegistry,
35
36
  Agent: () => Agent,
37
+ AgentCardBuilder: () => AgentCardBuilder,
36
38
  AnthropicProvider: () => AnthropicProvider,
37
39
  ConfigLoader: () => ConfigLoader,
38
40
  LLMProvider: () => LLMProvider,
@@ -40,6 +42,7 @@ __export(index_exports, {
40
42
  MarkdownParser: () => MarkdownParser,
41
43
  Memory: () => Memory,
42
44
  MoltbookAdapter: () => MoltbookAdapter,
45
+ MoltiumExecutor: () => MoltiumExecutor,
43
46
  OpenAIProvider: () => OpenAIProvider,
44
47
  Scheduler: () => Scheduler,
45
48
  ShortTermMemory: () => ShortTermMemory,
@@ -49,10 +52,12 @@ __export(index_exports, {
49
52
  buildSkillPrompt: () => buildSkillPrompt,
50
53
  buildSystemPrompt: () => buildSystemPrompt,
51
54
  builtInActions: () => builtInActions,
55
+ createA2AIntegration: () => createA2AIntegration,
52
56
  createApp: () => createApp,
53
57
  createLogger: () => createLogger,
54
58
  createMarkdownAction: () => createMarkdownAction,
55
59
  createRoutes: () => createRoutes,
60
+ moltbookActions: () => moltbookActions,
56
61
  startServer: () => startServer,
57
62
  validateConfig: () => validateConfig
58
63
  });
@@ -276,12 +281,221 @@ var scheduleTaskAction = {
276
281
  }
277
282
  };
278
283
 
284
+ // src/actions/built-in/moltbook.ts
285
+ function getMoltbook(context) {
286
+ return context.agent?.socialAdapters?.["moltbook"] || null;
287
+ }
288
+ var checkFeedAction = {
289
+ name: "check_feed",
290
+ description: "Browse the moltbook feed (personalized or global) to find posts to engage with",
291
+ async execute(context) {
292
+ const mb = getMoltbook(context);
293
+ if (!mb) return { success: false, error: "Moltbook not connected" };
294
+ const { sort, limit, global: useGlobal } = context.parameters;
295
+ try {
296
+ const posts = useGlobal ? await mb.getGlobalFeed({ sort: sort || "hot", limit: limit || 15 }) : await mb.getFeed({ sort: sort || "new", limit: limit || 15 });
297
+ return { success: true, data: { posts, count: posts.length } };
298
+ } catch (error) {
299
+ return { success: false, error: error.message };
300
+ }
301
+ }
302
+ };
303
+ var checkDMsAction = {
304
+ name: "check_dms",
305
+ description: "Check for new DM requests and unread messages from other agents",
306
+ async execute(context) {
307
+ const mb = getMoltbook(context);
308
+ if (!mb) return { success: false, error: "Moltbook not connected" };
309
+ try {
310
+ const result = await mb.checkDMs();
311
+ return { success: true, data: result };
312
+ } catch (error) {
313
+ return { success: false, error: error.message };
314
+ }
315
+ }
316
+ };
317
+ var searchMoltbookAction = {
318
+ name: "search_moltbook",
319
+ description: 'Search moltbook for posts and comments by meaning (semantic search). Params: { "query": "..." }',
320
+ async execute(context) {
321
+ const mb = getMoltbook(context);
322
+ if (!mb) return { success: false, error: "Moltbook not connected" };
323
+ const { query, limit } = context.parameters;
324
+ if (!query) return { success: false, error: "Missing required parameter: query" };
325
+ try {
326
+ const results = await mb.search(query, { limit: limit || 10 });
327
+ return { success: true, data: { results, count: results.length } };
328
+ } catch (error) {
329
+ return { success: false, error: error.message };
330
+ }
331
+ }
332
+ };
333
+ var commentOnPostAction = {
334
+ name: "comment_on_post",
335
+ description: 'Reply to a post with a comment. Params: { "post_id": "...", "content": "..." }',
336
+ async execute(context) {
337
+ const mb = getMoltbook(context);
338
+ if (!mb) return { success: false, error: "Moltbook not connected" };
339
+ const { post_id, content } = context.parameters;
340
+ if (!post_id || !content) return { success: false, error: "Missing required parameters: post_id, content" };
341
+ try {
342
+ const result = await mb.reply(post_id, content);
343
+ return { success: true, data: result };
344
+ } catch (error) {
345
+ return { success: false, error: error.message };
346
+ }
347
+ }
348
+ };
349
+ var upvotePostAction = {
350
+ name: "upvote_post",
351
+ description: 'Upvote a post you find valuable. Params: { "post_id": "..." }',
352
+ async execute(context) {
353
+ const mb = getMoltbook(context);
354
+ if (!mb) return { success: false, error: "Moltbook not connected" };
355
+ const { post_id } = context.parameters;
356
+ if (!post_id) return { success: false, error: "Missing required parameter: post_id" };
357
+ try {
358
+ await mb.like(post_id);
359
+ return { success: true, data: { post_id, action: "upvoted" } };
360
+ } catch (error) {
361
+ return { success: false, error: error.message };
362
+ }
363
+ }
364
+ };
365
+ var downvotePostAction = {
366
+ name: "downvote_post",
367
+ description: 'Downvote a post you disagree with. Params: { "post_id": "..." }',
368
+ async execute(context) {
369
+ const mb = getMoltbook(context);
370
+ if (!mb) return { success: false, error: "Moltbook not connected" };
371
+ const { post_id } = context.parameters;
372
+ if (!post_id) return { success: false, error: "Missing required parameter: post_id" };
373
+ try {
374
+ await mb.downvote(post_id);
375
+ return { success: true, data: { post_id, action: "downvoted" } };
376
+ } catch (error) {
377
+ return { success: false, error: error.message };
378
+ }
379
+ }
380
+ };
381
+ var browseSubmoltsAction = {
382
+ name: "browse_submolts",
383
+ description: "Discover moltbook communities (submolts) to subscribe to",
384
+ async execute(context) {
385
+ const mb = getMoltbook(context);
386
+ if (!mb) return { success: false, error: "Moltbook not connected" };
387
+ try {
388
+ const submolts = await mb.listSubmolts();
389
+ return { success: true, data: { submolts, count: submolts.length } };
390
+ } catch (error) {
391
+ return { success: false, error: error.message };
392
+ }
393
+ }
394
+ };
395
+ var followAgentAction = {
396
+ name: "follow_agent",
397
+ description: 'Follow another agent whose posts you enjoy. Params: { "agent_name": "..." }',
398
+ async execute(context) {
399
+ const mb = getMoltbook(context);
400
+ if (!mb) return { success: false, error: "Moltbook not connected" };
401
+ const { agent_name } = context.parameters;
402
+ if (!agent_name) return { success: false, error: "Missing required parameter: agent_name" };
403
+ try {
404
+ await mb.follow(agent_name);
405
+ return { success: true, data: { agent_name, action: "followed" } };
406
+ } catch (error) {
407
+ return { success: false, error: error.message };
408
+ }
409
+ }
410
+ };
411
+ var sendDMRequestAction = {
412
+ name: "send_dm_request",
413
+ description: 'Request to start a private conversation with another agent. Params: { "to": "...", "message": "..." }',
414
+ async execute(context) {
415
+ const mb = getMoltbook(context);
416
+ if (!mb) return { success: false, error: "Moltbook not connected" };
417
+ const { to, to_owner, message } = context.parameters;
418
+ if (!to && !to_owner || !message) return { success: false, error: "Missing required parameters: (to or to_owner), message" };
419
+ try {
420
+ const target = to || to_owner || "";
421
+ const byOwner = !to && !!to_owner;
422
+ const result = await mb.sendDMRequest(target, message, byOwner);
423
+ return { success: true, data: result };
424
+ } catch (error) {
425
+ return { success: false, error: error.message };
426
+ }
427
+ }
428
+ };
429
+ var sendDMAction = {
430
+ name: "send_dm",
431
+ description: 'Send a message in an existing DM conversation. Params: { "conversation_id": "...", "message": "..." }',
432
+ async execute(context) {
433
+ const mb = getMoltbook(context);
434
+ if (!mb) return { success: false, error: "Moltbook not connected" };
435
+ const { conversation_id, message, needs_human_input } = context.parameters;
436
+ if (!conversation_id || !message) return { success: false, error: "Missing required parameters: conversation_id, message" };
437
+ try {
438
+ const result = await mb.sendDM(conversation_id, message, needs_human_input);
439
+ return { success: true, data: result };
440
+ } catch (error) {
441
+ return { success: false, error: error.message };
442
+ }
443
+ }
444
+ };
445
+ var approveDMRequestAction = {
446
+ name: "approve_dm_request",
447
+ description: 'Approve a pending DM request from another agent. Params: { "conversation_id": "..." }',
448
+ async execute(context) {
449
+ const mb = getMoltbook(context);
450
+ if (!mb) return { success: false, error: "Moltbook not connected" };
451
+ const { conversation_id } = context.parameters;
452
+ if (!conversation_id) return { success: false, error: "Missing required parameter: conversation_id" };
453
+ try {
454
+ await mb.approveDMRequest(conversation_id);
455
+ return { success: true, data: { conversation_id, action: "approved" } };
456
+ } catch (error) {
457
+ return { success: false, error: error.message };
458
+ }
459
+ }
460
+ };
461
+ var readConversationAction = {
462
+ name: "read_conversation",
463
+ description: 'Read messages in a DM conversation (marks as read). Params: { "conversation_id": "..." }',
464
+ async execute(context) {
465
+ const mb = getMoltbook(context);
466
+ if (!mb) return { success: false, error: "Moltbook not connected" };
467
+ const { conversation_id } = context.parameters;
468
+ if (!conversation_id) return { success: false, error: "Missing required parameter: conversation_id" };
469
+ try {
470
+ const detail = await mb.readConversation(conversation_id);
471
+ return { success: true, data: detail };
472
+ } catch (error) {
473
+ return { success: false, error: error.message };
474
+ }
475
+ }
476
+ };
477
+ var moltbookActions = [
478
+ checkFeedAction,
479
+ checkDMsAction,
480
+ searchMoltbookAction,
481
+ commentOnPostAction,
482
+ upvotePostAction,
483
+ downvotePostAction,
484
+ browseSubmoltsAction,
485
+ followAgentAction,
486
+ sendDMRequestAction,
487
+ sendDMAction,
488
+ approveDMRequestAction,
489
+ readConversationAction
490
+ ];
491
+
279
492
  // src/actions/built-in/index.ts
280
493
  var builtInActions = [
281
494
  postSocialUpdateAction,
282
495
  respondToMentionAction,
283
496
  dmUserAction,
284
- scheduleTaskAction
497
+ scheduleTaskAction,
498
+ ...moltbookActions
285
499
  ];
286
500
 
287
501
  // src/llm/prompt.ts
@@ -308,18 +522,33 @@ ${config.llm.systemPrompt}`);
308
522
  }
309
523
  function buildDecisionPrompt(context, availableActions) {
310
524
  const actionList = availableActions.map((a) => `- ${a.name}: ${a.description}`).join("\n");
311
- return `Given the current context, decide what action to take next.
525
+ const recent = context.recentActions || [];
526
+ const recentNames = recent.map((r) => r.action);
527
+ const lastAction = recentNames.length > 0 ? recentNames[recentNames.length - 1] : "none";
528
+ let varietyHint = "";
529
+ if (recentNames.length > 0) {
530
+ varietyHint = `
531
+ Your recent actions (most recent last): ${recentNames.join(" \u2192 ")}
532
+ IMPORTANT: Do NOT repeat "${lastAction}" again. Choose a DIFFERENT action to keep your behavior varied and interesting.
533
+ Vary between: posting content, checking your feed, replying to others, checking DMs, browsing communities, searching for topics, and following interesting agents.`;
534
+ }
535
+ return `You are an autonomous AI agent on moltbook (a social network for AI agents).
536
+ Decide what action to take next based on the current context and your personality.
312
537
 
313
538
  Available actions:
314
539
  ${actionList}
315
540
 
316
541
  Current context:
317
542
  ${JSON.stringify(context, null, 2)}
543
+ ${varietyHint}
544
+
545
+ Think about what would be most natural and valuable right now.
546
+ If the action generates content (post, comment, DM), include the actual content in parameters.
318
547
 
319
548
  Respond with a JSON object:
320
549
  {
321
550
  "action": "<action_name>",
322
- "reasoning": "<brief explanation>",
551
+ "reasoning": "<brief explanation of why you chose this>",
323
552
  "parameters": { <any parameters for the action> }
324
553
  }`;
325
554
  }
@@ -1154,6 +1383,174 @@ var TwitterAdapter = class extends SocialAdapter {
1154
1383
  }
1155
1384
  };
1156
1385
 
1386
+ // src/a2a/client.ts
1387
+ var import_client = require("@a2a-js/sdk/client");
1388
+ var import_uuid = require("uuid");
1389
+ var A2AClient = class {
1390
+ sdkClient;
1391
+ config;
1392
+ constructor(config) {
1393
+ this.config = {
1394
+ agentUrl: config.agentUrl,
1395
+ agentCardPath: config.agentCardPath || ".well-known/agent-card.json",
1396
+ timeout: config.timeout || 3e4
1397
+ };
1398
+ const agentUrl = this.config.agentUrl;
1399
+ const agentCardPath = this.config.agentCardPath;
1400
+ this.sdkClient = new import_client.A2AClient(agentUrl, agentCardPath);
1401
+ }
1402
+ /**
1403
+ * Send a text message to the agent and get a response
1404
+ *
1405
+ * @param options Message options including text content
1406
+ * @returns Promise resolving to the agent's response
1407
+ *
1408
+ * @example
1409
+ * ```typescript
1410
+ * const response = await client.sendMessage({
1411
+ * text: 'What are your thoughts on AI?',
1412
+ * contextId: 'conversation-123'
1413
+ * });
1414
+ *
1415
+ * if (response.success) {
1416
+ * console.log('Agent replied:', response.reply);
1417
+ * }
1418
+ * ```
1419
+ */
1420
+ async sendMessage(options) {
1421
+ try {
1422
+ const response = await this.sdkClient.sendMessage({
1423
+ message: {
1424
+ kind: "message",
1425
+ messageId: (0, import_uuid.v4)(),
1426
+ role: "user",
1427
+ contextId: options.contextId,
1428
+ metadata: options.metadata,
1429
+ parts: [
1430
+ {
1431
+ kind: "text",
1432
+ text: options.text
1433
+ }
1434
+ ]
1435
+ }
1436
+ });
1437
+ const reply = this.extractReply(response);
1438
+ return {
1439
+ success: true,
1440
+ reply,
1441
+ agentUrl: this.config.agentUrl,
1442
+ raw: response
1443
+ };
1444
+ } catch (error) {
1445
+ return {
1446
+ success: false,
1447
+ error: error.message || "Unknown error occurred",
1448
+ agentUrl: this.config.agentUrl
1449
+ };
1450
+ }
1451
+ }
1452
+ /**
1453
+ * Extract text reply from A2A protocol response
1454
+ * Handles both Message and Task response types
1455
+ */
1456
+ extractReply(response) {
1457
+ if (!("result" in response) || !response.result) {
1458
+ return JSON.stringify(response);
1459
+ }
1460
+ const result = response.result;
1461
+ if ("kind" in result && result.kind === "message" && "parts" in result) {
1462
+ const textParts = result.parts.filter((part) => part.kind === "text").map((part) => part.text);
1463
+ return textParts.join("\n");
1464
+ }
1465
+ return typeof result === "string" ? result : JSON.stringify(result);
1466
+ }
1467
+ /**
1468
+ * Get the agent card information
1469
+ *
1470
+ * @returns Promise resolving to the agent card
1471
+ */
1472
+ async getAgentCard() {
1473
+ return this.sdkClient.getAgentCard();
1474
+ }
1475
+ /**
1476
+ * Get the base URL of the agent
1477
+ */
1478
+ getAgentUrl() {
1479
+ return this.config.agentUrl;
1480
+ }
1481
+ };
1482
+
1483
+ // src/a2a/actions.ts
1484
+ function createA2ACommunicationAction(config = {}) {
1485
+ const {
1486
+ defaultAgentUrl,
1487
+ actionName = "talk_to_agent",
1488
+ description,
1489
+ verbose = false
1490
+ } = config;
1491
+ const defaultDescription = description || `Send a message to another A2A-compliant agent and receive their response. Parameters: message (required string) - the message to send, agentUrl (optional string) - target agent URL${defaultAgentUrl ? ` (defaults to ${defaultAgentUrl})` : ""}`;
1492
+ return {
1493
+ name: actionName,
1494
+ description: defaultDescription,
1495
+ async execute(context) {
1496
+ const { parameters } = context;
1497
+ const message = parameters.message;
1498
+ const agentUrl = parameters.agentUrl || defaultAgentUrl;
1499
+ if (!message) {
1500
+ return {
1501
+ success: false,
1502
+ error: 'Parameter "message" is required'
1503
+ };
1504
+ }
1505
+ if (!agentUrl) {
1506
+ return {
1507
+ success: false,
1508
+ error: 'Parameter "agentUrl" is required or defaultAgentUrl must be configured'
1509
+ };
1510
+ }
1511
+ if (verbose) {
1512
+ console.log(`[A2A] Sending message to ${agentUrl}:`, message);
1513
+ }
1514
+ try {
1515
+ const client = new A2AClient({ agentUrl });
1516
+ const response = await client.sendMessage({ text: message });
1517
+ if (verbose) {
1518
+ console.log(`[A2A] Response from ${agentUrl}:`, response.reply);
1519
+ }
1520
+ if (!response.success) {
1521
+ return {
1522
+ success: false,
1523
+ error: response.error || "Failed to communicate with agent"
1524
+ };
1525
+ }
1526
+ return {
1527
+ success: true,
1528
+ data: {
1529
+ reply: response.reply,
1530
+ agentUrl: response.agentUrl
1531
+ }
1532
+ };
1533
+ } catch (error) {
1534
+ if (verbose) {
1535
+ console.error(`[A2A] Error:`, error);
1536
+ }
1537
+ return {
1538
+ success: false,
1539
+ error: error.message || "Unknown error occurred"
1540
+ };
1541
+ }
1542
+ }
1543
+ };
1544
+ }
1545
+ function createMultipleA2AActions(configs) {
1546
+ return Object.entries(configs).map(
1547
+ ([name, config]) => createA2ACommunicationAction({
1548
+ ...config,
1549
+ actionName: name
1550
+ })
1551
+ );
1552
+ }
1553
+
1157
1554
  // src/agent/Agent.ts
1158
1555
  var logger4 = createLogger("Agent");
1159
1556
  function parsePostFrequency(freq) {
@@ -1195,6 +1592,8 @@ var Agent = class {
1195
1592
  tickTimer;
1196
1593
  systemPrompt;
1197
1594
  socialAdapters = {};
1595
+ recentActions = [];
1596
+ tickCount = 0;
1198
1597
  constructor(config, hooks) {
1199
1598
  this.config = config;
1200
1599
  this.hooks = hooks || {};
@@ -1329,13 +1728,29 @@ var Agent = class {
1329
1728
  }
1330
1729
  async tick() {
1331
1730
  if (this.state !== "running") return;
1731
+ this.tickCount++;
1332
1732
  try {
1333
1733
  if (this.hooks.onTick) {
1334
1734
  await this.hooks.onTick(this);
1335
1735
  }
1336
- if (this.isSleeping()) return;
1736
+ if (this.isSleeping()) {
1737
+ logger4.info(`Tick #${this.tickCount}: Sleeping \u2014 skipped`);
1738
+ return;
1739
+ }
1740
+ logger4.info(`Tick #${this.tickCount}: Thinking...`);
1337
1741
  const decision = await this.think();
1742
+ logger4.info(`Tick #${this.tickCount}: Decision \u2192 ${decision.action} | Reasoning: ${decision.reasoning}`);
1743
+ if (decision.parameters && Object.keys(decision.parameters).length > 0) {
1744
+ logger4.info(`Tick #${this.tickCount}: Parameters \u2192 ${JSON.stringify(decision.parameters)}`);
1745
+ }
1338
1746
  const result = await this.act(decision.action, decision.parameters);
1747
+ logger4.info(`Tick #${this.tickCount}: Result \u2192 success=${result.success}${result.data ? ` data=${JSON.stringify(result.data).slice(0, 200)}` : ""}`);
1748
+ this.recentActions.push({
1749
+ action: decision.action,
1750
+ reasoning: decision.reasoning,
1751
+ time: (/* @__PURE__ */ new Date()).toISOString()
1752
+ });
1753
+ if (this.recentActions.length > 10) this.recentActions.shift();
1339
1754
  await this.learn({
1340
1755
  type: "action",
1341
1756
  action: decision.action,
@@ -1347,7 +1762,7 @@ var Agent = class {
1347
1762
  await this.fireWebhook("onAction", decision, result);
1348
1763
  }
1349
1764
  } catch (error) {
1350
- logger4.error(`Tick error: ${error instanceof Error ? error.message : error}`);
1765
+ logger4.error(`Tick #${this.tickCount} error: ${error instanceof Error ? error.message : error}`);
1351
1766
  if (this.hooks.onError && error instanceof Error) {
1352
1767
  await this.hooks.onError(error, this);
1353
1768
  }
@@ -1380,6 +1795,46 @@ var Agent = class {
1380
1795
  this.actionRegistry.register(action);
1381
1796
  }
1382
1797
  }
1798
+ const mb = this.config.social.moltbook;
1799
+ if (mb && mb.enabled !== false) {
1800
+ for (const action of moltbookActions) {
1801
+ if (!this.actionRegistry.has(action.name)) {
1802
+ this.actionRegistry.register(action);
1803
+ }
1804
+ }
1805
+ logger4.info(`Registered ${moltbookActions.length} Moltbook actions`);
1806
+ }
1807
+ const a2a = this.config.a2a;
1808
+ if (a2a && a2a.enabled !== false) {
1809
+ if (a2a.peers && Object.keys(a2a.peers).length > 0) {
1810
+ const peerActions = createMultipleA2AActions(
1811
+ Object.entries(a2a.peers).reduce((acc, [actionName, url]) => {
1812
+ acc[actionName] = {
1813
+ defaultAgentUrl: url,
1814
+ verbose: a2a.verbose,
1815
+ description: `Communicate with peer agent at ${url}`
1816
+ };
1817
+ return acc;
1818
+ }, {})
1819
+ );
1820
+ for (const action of peerActions) {
1821
+ if (!this.actionRegistry.has(action.name)) {
1822
+ this.actionRegistry.register(action);
1823
+ }
1824
+ }
1825
+ logger4.info(`Registered ${peerActions.length} A2A peer actions`);
1826
+ } else {
1827
+ const genericAction = createA2ACommunicationAction({
1828
+ defaultAgentUrl: a2a.defaultPeerUrl,
1829
+ actionName: a2a.genericActionName || "talk_to_agent",
1830
+ verbose: a2a.verbose
1831
+ });
1832
+ if (!this.actionRegistry.has(genericAction.name)) {
1833
+ this.actionRegistry.register(genericAction);
1834
+ }
1835
+ logger4.info(`Registered generic A2A action: ${genericAction.name}`);
1836
+ }
1837
+ }
1383
1838
  if (this.config.customActions) {
1384
1839
  for (const action of this.config.customActions) {
1385
1840
  this.actionRegistry.register(action);
@@ -1688,7 +2143,11 @@ Decide what action to take. Respond with JSON:
1688
2143
  agentType: this.config.type,
1689
2144
  currentTime: (/* @__PURE__ */ new Date()).toISOString(),
1690
2145
  state: this.state,
1691
- personality: this.config.personality.traits
2146
+ tickNumber: this.tickCount,
2147
+ personality: this.config.personality.traits,
2148
+ connectedPlatforms: Object.keys(this.socialAdapters),
2149
+ recentActions: this.recentActions.slice(-5),
2150
+ scheduledTasks: (this.config.scheduling || []).map((t) => t.name)
1692
2151
  };
1693
2152
  }
1694
2153
  async fireWebhook(event, ...args) {
@@ -2365,27 +2824,516 @@ function authMiddleware(req, res, next) {
2365
2824
  next();
2366
2825
  }
2367
2826
 
2827
+ // src/a2a/AgentCardBuilder.ts
2828
+ var logger7 = createLogger("AgentCardBuilder");
2829
+ var AgentCardBuilder = class {
2830
+ /**
2831
+ * Creates an A2A AgentCard from Moltium configuration.
2832
+ * @param config The Moltium agent configuration
2833
+ * @param a2aConfig A2A-specific configuration (URLs, capabilities)
2834
+ * @returns A2A-compliant AgentCard
2835
+ */
2836
+ static build(config, a2aConfig) {
2837
+ const baseUrl = a2aConfig.baseUrl;
2838
+ const skills = this.buildSkills(config);
2839
+ const capabilities = {
2840
+ streaming: a2aConfig.streaming ?? true,
2841
+ pushNotifications: a2aConfig.pushNotifications ?? false,
2842
+ stateTransitionHistory: a2aConfig.stateTransitionHistory ?? true
2843
+ };
2844
+ const defaultInputModes = ["text"];
2845
+ const defaultOutputModes = ["text"];
2846
+ const agentCard = {
2847
+ name: config.name,
2848
+ description: config.personality.bio || `${config.name} - An autonomous AI agent`,
2849
+ protocolVersion: "0.3.0",
2850
+ version: "0.1.0",
2851
+ url: `${baseUrl}/a2a/jsonrpc`,
2852
+ skills,
2853
+ capabilities,
2854
+ defaultInputModes,
2855
+ defaultOutputModes,
2856
+ additionalInterfaces: [
2857
+ { url: `${baseUrl}/a2a/jsonrpc`, transport: "JSONRPC" },
2858
+ { url: `${baseUrl}/a2a/rest`, transport: "HTTP+JSON" }
2859
+ ]
2860
+ };
2861
+ logger7.debug("Built A2A AgentCard", {
2862
+ name: agentCard.name,
2863
+ skillCount: skills.length,
2864
+ baseUrl
2865
+ });
2866
+ return agentCard;
2867
+ }
2868
+ /**
2869
+ * Converts Moltium actions to A2A skills.
2870
+ */
2871
+ static buildSkills(config) {
2872
+ const skills = [];
2873
+ skills.push({
2874
+ id: "chat",
2875
+ name: "Chat",
2876
+ description: `Interact with ${config.name}. ${config.personality.bio || ""}`,
2877
+ tags: ["chat", "conversation"]
2878
+ });
2879
+ const hasPosting = config.actions.some(
2880
+ (a) => a.includes("post") || a.includes("update")
2881
+ );
2882
+ if (hasPosting) {
2883
+ skills.push({
2884
+ id: "social_posting",
2885
+ name: "Social Posting",
2886
+ description: "Post updates and content to social platforms",
2887
+ tags: ["social", "posting"]
2888
+ });
2889
+ }
2890
+ const hasEngagement = config.actions.some(
2891
+ (a) => a.includes("comment") || a.includes("reply") || a.includes("respond")
2892
+ );
2893
+ if (hasEngagement) {
2894
+ skills.push({
2895
+ id: "social_engagement",
2896
+ name: "Social Engagement",
2897
+ description: "Engage with others through comments and replies",
2898
+ tags: ["social", "engagement"]
2899
+ });
2900
+ }
2901
+ const hasSearch = config.actions.some(
2902
+ (a) => a.includes("search") || a.includes("check_feed") || a.includes("browse")
2903
+ );
2904
+ if (hasSearch) {
2905
+ skills.push({
2906
+ id: "content_discovery",
2907
+ name: "Content Discovery",
2908
+ description: "Search and discover relevant content",
2909
+ tags: ["search", "discovery"]
2910
+ });
2911
+ }
2912
+ const hasAnalysis = config.actions.some(
2913
+ (a) => a.includes("analyze") || a.includes("think") || a.includes("research")
2914
+ );
2915
+ if (hasAnalysis) {
2916
+ skills.push({
2917
+ id: "analysis",
2918
+ name: "Analysis & Research",
2919
+ description: "Analyze problems and conduct research",
2920
+ tags: ["analysis", "research", "thinking"]
2921
+ });
2922
+ }
2923
+ return skills;
2924
+ }
2925
+ /**
2926
+ * Updates an agent card with runtime information.
2927
+ */
2928
+ static updateWithRuntime(agentCard, actualPort, actualHost = "localhost") {
2929
+ const protocol = actualHost === "localhost" || actualHost === "127.0.0.1" ? "http" : "https";
2930
+ const baseUrl = `${protocol}://${actualHost}:${actualPort}`;
2931
+ return {
2932
+ ...agentCard,
2933
+ url: `${baseUrl}/a2a/jsonrpc`,
2934
+ additionalInterfaces: [
2935
+ { url: `${baseUrl}/a2a/jsonrpc`, transport: "JSONRPC" },
2936
+ { url: `${baseUrl}/a2a/rest`, transport: "HTTP+JSON" }
2937
+ ]
2938
+ };
2939
+ }
2940
+ };
2941
+
2942
+ // src/a2a/MoltiumExecutor.ts
2943
+ var import_uuid2 = require("uuid");
2944
+ var logger8 = createLogger("MoltiumExecutor");
2945
+ var MoltiumExecutor = class {
2946
+ agent;
2947
+ cancelledTasks = /* @__PURE__ */ new Set();
2948
+ constructor(agent) {
2949
+ this.agent = agent;
2950
+ }
2951
+ /**
2952
+ * Executes an A2A request using the Moltium agent.
2953
+ * Converts A2A messages to Moltium actions and publishes results back via the event bus.
2954
+ */
2955
+ async execute(requestContext, eventBus) {
2956
+ const { taskId, contextId, userMessage, task } = requestContext;
2957
+ try {
2958
+ logger8.info(`[A2A] Executing request for task ${taskId}`);
2959
+ if (!task) {
2960
+ const initialTask = {
2961
+ kind: "task",
2962
+ id: taskId,
2963
+ contextId,
2964
+ status: {
2965
+ state: "submitted",
2966
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2967
+ },
2968
+ history: [userMessage]
2969
+ };
2970
+ eventBus.publish(initialTask);
2971
+ }
2972
+ if (this.cancelledTasks.has(taskId)) {
2973
+ this.publishCancellation(taskId, contextId, eventBus);
2974
+ return;
2975
+ }
2976
+ this.publishStatusUpdate(taskId, contextId, "working", eventBus, false);
2977
+ const userContent = this.extractMessageContent(userMessage);
2978
+ const isActionRequest = this.isActionRequest(userContent);
2979
+ let result;
2980
+ if (isActionRequest) {
2981
+ result = await this.executeAction(userContent, taskId);
2982
+ } else {
2983
+ result = await this.executeChat(userContent, taskId);
2984
+ }
2985
+ if (this.cancelledTasks.has(taskId)) {
2986
+ this.publishCancellation(taskId, contextId, eventBus);
2987
+ return;
2988
+ }
2989
+ if (result.success) {
2990
+ await this.publishResult(taskId, contextId, result, eventBus);
2991
+ } else {
2992
+ await this.publishError(taskId, contextId, result.error || "Unknown error", eventBus);
2993
+ }
2994
+ this.publishStatusUpdate(taskId, contextId, "completed", eventBus, true);
2995
+ eventBus.finished();
2996
+ logger8.info(`[A2A] Task ${taskId} completed successfully`);
2997
+ } catch (error) {
2998
+ logger8.error(`[A2A] Task ${taskId} failed`, {
2999
+ error: error instanceof Error ? error.message : String(error)
3000
+ });
3001
+ const errorMessage = error instanceof Error ? error.message : String(error);
3002
+ await this.publishError(taskId, contextId, errorMessage, eventBus);
3003
+ this.publishStatusUpdate(taskId, contextId, "failed", eventBus, true);
3004
+ eventBus.finished();
3005
+ } finally {
3006
+ this.cancelledTasks.delete(taskId);
3007
+ }
3008
+ }
3009
+ /**
3010
+ * Handles task cancellation requests.
3011
+ */
3012
+ async cancelTask(taskId, eventBus) {
3013
+ logger8.info(`[A2A] Cancellation requested for task ${taskId}`);
3014
+ this.cancelledTasks.add(taskId);
3015
+ }
3016
+ /**
3017
+ * Extracts text content from an A2A message.
3018
+ */
3019
+ extractMessageContent(message) {
3020
+ const textParts = message.parts.filter((part) => part.kind === "text");
3021
+ return textParts.map((part) => part.text).join("\n");
3022
+ }
3023
+ /**
3024
+ * Determines if the user message is requesting a specific action.
3025
+ */
3026
+ isActionRequest(content) {
3027
+ const actionKeywords = [
3028
+ "post",
3029
+ "search",
3030
+ "check feed",
3031
+ "browse",
3032
+ "comment",
3033
+ "upvote",
3034
+ "follow",
3035
+ "send dm"
3036
+ ];
3037
+ const lowerContent = content.toLowerCase();
3038
+ return actionKeywords.some((keyword) => lowerContent.includes(keyword));
3039
+ }
3040
+ /**
3041
+ * Executes a chat interaction using the agent's LLM.
3042
+ */
3043
+ async executeChat(userContent, taskId) {
3044
+ try {
3045
+ const llm = this.agent.getLLM();
3046
+ const systemPrompt = this.agent.getSystemPrompt();
3047
+ const response = await llm.generateText(userContent, {
3048
+ systemPrompt,
3049
+ temperature: this.agent.config.llm.temperature
3050
+ });
3051
+ return {
3052
+ success: true,
3053
+ data: { response, type: "chat" }
3054
+ };
3055
+ } catch (error) {
3056
+ return {
3057
+ success: false,
3058
+ error: `Chat execution failed: ${error instanceof Error ? error.message : String(error)}`
3059
+ };
3060
+ }
3061
+ }
3062
+ /**
3063
+ * Executes an action based on the user's request.
3064
+ */
3065
+ async executeAction(userContent, taskId) {
3066
+ try {
3067
+ const decision = await this.agent.think();
3068
+ const result = await this.agent.act(decision.action, decision.parameters);
3069
+ return {
3070
+ success: result.success,
3071
+ data: {
3072
+ action: decision.action,
3073
+ reasoning: decision.reasoning,
3074
+ result: result.data,
3075
+ type: "action"
3076
+ },
3077
+ error: result.error
3078
+ };
3079
+ } catch (error) {
3080
+ return {
3081
+ success: false,
3082
+ error: `Action execution failed: ${error instanceof Error ? error.message : String(error)}`
3083
+ };
3084
+ }
3085
+ }
3086
+ /**
3087
+ * Publishes a successful result as an A2A artifact.
3088
+ */
3089
+ async publishResult(taskId, contextId, result, eventBus) {
3090
+ const data = result.data;
3091
+ if (data?.type === "chat") {
3092
+ const artifactUpdate = {
3093
+ kind: "artifact-update",
3094
+ taskId,
3095
+ contextId,
3096
+ artifact: {
3097
+ artifactId: `response-${(0, import_uuid2.v4)()}`,
3098
+ name: "response.txt",
3099
+ parts: [{ kind: "text", text: data.response }]
3100
+ }
3101
+ };
3102
+ eventBus.publish(artifactUpdate);
3103
+ } else if (data?.type === "action") {
3104
+ const resultText = JSON.stringify(
3105
+ {
3106
+ action: data.action,
3107
+ reasoning: data.reasoning,
3108
+ result: data.result
3109
+ },
3110
+ null,
3111
+ 2
3112
+ );
3113
+ const artifactUpdate = {
3114
+ kind: "artifact-update",
3115
+ taskId,
3116
+ contextId,
3117
+ artifact: {
3118
+ artifactId: `action-result-${(0, import_uuid2.v4)()}`,
3119
+ name: "action_result.json",
3120
+ parts: [{ kind: "text", text: resultText }]
3121
+ }
3122
+ };
3123
+ eventBus.publish(artifactUpdate);
3124
+ } else {
3125
+ const resultText = typeof result.data === "string" ? result.data : JSON.stringify(result.data, null, 2);
3126
+ const artifactUpdate = {
3127
+ kind: "artifact-update",
3128
+ taskId,
3129
+ contextId,
3130
+ artifact: {
3131
+ artifactId: `result-${(0, import_uuid2.v4)()}`,
3132
+ name: "result.txt",
3133
+ parts: [{ kind: "text", text: resultText }]
3134
+ }
3135
+ };
3136
+ eventBus.publish(artifactUpdate);
3137
+ }
3138
+ }
3139
+ /**
3140
+ * Publishes an error as an A2A artifact.
3141
+ */
3142
+ async publishError(taskId, contextId, error, eventBus) {
3143
+ const artifactUpdate = {
3144
+ kind: "artifact-update",
3145
+ taskId,
3146
+ contextId,
3147
+ artifact: {
3148
+ artifactId: `error-${(0, import_uuid2.v4)()}`,
3149
+ name: "error.txt",
3150
+ parts: [{ kind: "text", text: `Error: ${error}` }]
3151
+ }
3152
+ };
3153
+ eventBus.publish(artifactUpdate);
3154
+ }
3155
+ /**
3156
+ * Publishes a status update event.
3157
+ */
3158
+ publishStatusUpdate(taskId, contextId, state, eventBus, final) {
3159
+ const statusUpdate = {
3160
+ kind: "status-update",
3161
+ taskId,
3162
+ contextId,
3163
+ status: {
3164
+ state,
3165
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
3166
+ },
3167
+ final
3168
+ };
3169
+ eventBus.publish(statusUpdate);
3170
+ }
3171
+ /**
3172
+ * Publishes a cancellation status.
3173
+ */
3174
+ publishCancellation(taskId, contextId, eventBus) {
3175
+ logger8.info(`[A2A] Publishing cancellation for task ${taskId}`);
3176
+ this.publishStatusUpdate(taskId, contextId, "canceled", eventBus, true);
3177
+ eventBus.finished();
3178
+ this.cancelledTasks.delete(taskId);
3179
+ }
3180
+ };
3181
+
3182
+ // src/a2a/integration.ts
3183
+ var import_server = require("@a2a-js/sdk/server");
3184
+ var logger9 = createLogger("A2AIntegration");
3185
+ var A2AIntegration = class {
3186
+ agent;
3187
+ agentCard;
3188
+ requestHandler;
3189
+ moltiumExecutor;
3190
+ constructor(agent, options) {
3191
+ this.agent = agent;
3192
+ this.agentCard = AgentCardBuilder.build(agent.config, options.a2aConfig);
3193
+ this.moltiumExecutor = new MoltiumExecutor(agent);
3194
+ this.requestHandler = new import_server.DefaultRequestHandler(
3195
+ this.agentCard,
3196
+ new import_server.InMemoryTaskStore(),
3197
+ this.moltiumExecutor
3198
+ );
3199
+ logger9.info("A2A integration initialized", {
3200
+ agentName: agent.name,
3201
+ baseUrl: options.a2aConfig.baseUrl
3202
+ });
3203
+ }
3204
+ /**
3205
+ * Creates Express middleware handlers for A2A endpoints.
3206
+ * Returns an object with individual handlers that can be mounted on specific routes.
3207
+ */
3208
+ getHandlers() {
3209
+ return {
3210
+ // Agent Card endpoint - serves the static agent card JSON
3211
+ agentCard: ((req, res) => {
3212
+ res.json(this.agentCard);
3213
+ }),
3214
+ // JSON-RPC endpoint - handles A2A protocol requests
3215
+ jsonRpc: (async (req, res) => {
3216
+ try {
3217
+ const jsonRpcHandler = new import_server.JsonRpcTransportHandler(this.requestHandler);
3218
+ const response = await jsonRpcHandler.handle(req.body);
3219
+ res.json(response);
3220
+ } catch (error) {
3221
+ logger9.error("JSON-RPC error:", error);
3222
+ res.status(500).json({
3223
+ jsonrpc: "2.0",
3224
+ error: {
3225
+ code: -32603,
3226
+ message: "Internal error",
3227
+ data: error.message
3228
+ },
3229
+ id: req.body?.id || null
3230
+ });
3231
+ }
3232
+ }),
3233
+ // REST endpoint - simplified HTTP+JSON interface
3234
+ rest: ((req, res) => {
3235
+ res.status(501).json({
3236
+ error: "REST transport not implemented in SDK v0.3.0",
3237
+ message: "Please use the JSON-RPC endpoint at /a2a/jsonrpc"
3238
+ });
3239
+ })
3240
+ };
3241
+ }
3242
+ /**
3243
+ * Updates the agent card with actual runtime information (host/port).
3244
+ */
3245
+ updateAgentCard(actualPort, actualHost = "localhost") {
3246
+ this.agentCard = AgentCardBuilder.updateWithRuntime(this.agentCard, actualPort, actualHost);
3247
+ this.requestHandler = new import_server.DefaultRequestHandler(
3248
+ this.agentCard,
3249
+ new import_server.InMemoryTaskStore(),
3250
+ this.moltiumExecutor
3251
+ );
3252
+ logger9.info("A2A agent card updated with runtime info", {
3253
+ host: actualHost,
3254
+ port: actualPort,
3255
+ url: this.agentCard.url
3256
+ });
3257
+ }
3258
+ /**
3259
+ * Gets the current agent card.
3260
+ */
3261
+ getAgentCard() {
3262
+ return this.agentCard;
3263
+ }
3264
+ /**
3265
+ * Logs A2A endpoint information.
3266
+ */
3267
+ logEndpoints(host, port) {
3268
+ const protocol = host === "localhost" || host === "127.0.0.1" ? "http" : "https";
3269
+ const baseUrl = `${protocol}://${host}:${port}`;
3270
+ logger9.info("A2A endpoints available:");
3271
+ logger9.info(` Agent Card: ${baseUrl}/.well-known/agent-card.json`);
3272
+ logger9.info(` JSON-RPC: ${baseUrl}/a2a/jsonrpc`);
3273
+ logger9.info(` HTTP+JSON: ${baseUrl}/a2a/rest`);
3274
+ }
3275
+ };
3276
+ function createA2AIntegration(agent, options = {}) {
3277
+ const a2aConfig = {
3278
+ enabled: true,
3279
+ baseUrl: options.a2aConfig?.baseUrl || "http://localhost:3000",
3280
+ pushNotifications: options.a2aConfig?.pushNotifications ?? false,
3281
+ streaming: options.a2aConfig?.streaming ?? true,
3282
+ stateTransitionHistory: options.a2aConfig?.stateTransitionHistory ?? true
3283
+ };
3284
+ return new A2AIntegration(agent, { a2aConfig, ...options });
3285
+ }
3286
+
2368
3287
  // src/server/app.ts
2369
- var logger7 = createLogger("Server");
2370
- function createApp(agent) {
3288
+ var logger10 = createLogger("Server");
3289
+ var AGENT_CARD_PATH = ".well-known/agent-card.json";
3290
+ function createApp(agent, options = {}) {
2371
3291
  const app = (0, import_express2.default)();
2372
3292
  app.use(import_express2.default.json());
2373
3293
  app.use(requestLogger);
2374
3294
  app.use(authMiddleware);
2375
3295
  app.use(createRoutes(agent));
3296
+ if (options.enableA2A !== false) {
3297
+ const port = options.port || parseInt(process.env.PORT || "3000", 10);
3298
+ const host = options.host || "0.0.0.0";
3299
+ const protocol = host === "localhost" || host === "127.0.0.1" || host === "0.0.0.0" ? "http" : "https";
3300
+ const baseUrl = options.a2aConfig?.baseUrl || `${protocol}://${host}:${port}`;
3301
+ const a2aIntegration = createA2AIntegration(agent, {
3302
+ a2aConfig: {
3303
+ enabled: true,
3304
+ baseUrl,
3305
+ pushNotifications: options.a2aConfig?.pushNotifications ?? false,
3306
+ streaming: options.a2aConfig?.streaming ?? true,
3307
+ stateTransitionHistory: options.a2aConfig?.stateTransitionHistory ?? true
3308
+ }
3309
+ });
3310
+ const handlers = a2aIntegration.getHandlers();
3311
+ app.use(`/${AGENT_CARD_PATH}`, handlers.agentCard);
3312
+ app.use("/a2a/jsonrpc", handlers.jsonRpc);
3313
+ app.use("/a2a/rest", handlers.rest);
3314
+ logger10.info("A2A protocol endpoints enabled");
3315
+ }
2376
3316
  app.use(errorHandler);
2377
3317
  return app;
2378
3318
  }
2379
3319
  async function startServer(agent, options = {}) {
2380
3320
  const port = options.port || parseInt(process.env.PORT || "3000", 10);
2381
3321
  const host = options.host || "0.0.0.0";
2382
- const app = createApp(agent);
3322
+ const app = createApp(agent, options);
2383
3323
  await agent.start();
2384
3324
  app.listen(port, host, () => {
2385
- logger7.info(`Agent "${agent.name}" running at http://${host}:${port}`);
3325
+ logger10.info(`Agent "${agent.name}" running at http://${host}:${port}`);
3326
+ if (options.enableA2A !== false) {
3327
+ const protocol = host === "localhost" || host === "127.0.0.1" ? "http" : "https";
3328
+ const baseUrl = `${protocol}://${host}:${port}`;
3329
+ logger10.info("A2A Protocol Endpoints:");
3330
+ logger10.info(` Agent Card: ${baseUrl}/.well-known/agent-card.json`);
3331
+ logger10.info(` JSON-RPC: ${baseUrl}/a2a/jsonrpc`);
3332
+ logger10.info(` HTTP+JSON: ${baseUrl}/a2a/rest`);
3333
+ }
2386
3334
  });
2387
3335
  const shutdown = async () => {
2388
- logger7.info("Received shutdown signal");
3336
+ logger10.info("Received shutdown signal");
2389
3337
  await agent.stop();
2390
3338
  process.exit(0);
2391
3339
  };
@@ -2394,9 +3342,11 @@ async function startServer(agent, options = {}) {
2394
3342
  }
2395
3343
  // Annotate the CommonJS export names for ESM import in node:
2396
3344
  0 && (module.exports = {
3345
+ A2AIntegration,
2397
3346
  ActionHandler,
2398
3347
  ActionRegistry,
2399
3348
  Agent,
3349
+ AgentCardBuilder,
2400
3350
  AnthropicProvider,
2401
3351
  ConfigLoader,
2402
3352
  LLMProvider,
@@ -2404,6 +3354,7 @@ async function startServer(agent, options = {}) {
2404
3354
  MarkdownParser,
2405
3355
  Memory,
2406
3356
  MoltbookAdapter,
3357
+ MoltiumExecutor,
2407
3358
  OpenAIProvider,
2408
3359
  Scheduler,
2409
3360
  ShortTermMemory,
@@ -2413,10 +3364,12 @@ async function startServer(agent, options = {}) {
2413
3364
  buildSkillPrompt,
2414
3365
  buildSystemPrompt,
2415
3366
  builtInActions,
3367
+ createA2AIntegration,
2416
3368
  createApp,
2417
3369
  createLogger,
2418
3370
  createMarkdownAction,
2419
3371
  createRoutes,
3372
+ moltbookActions,
2420
3373
  startServer,
2421
3374
  validateConfig
2422
3375
  });