@moltium/core 0.1.19 → 0.1.21

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,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ A2AClient: () => A2AClient,
34
+ A2AIntegration: () => A2AIntegration,
33
35
  ActionHandler: () => ActionHandler,
34
36
  ActionRegistry: () => ActionRegistry,
35
37
  Agent: () => Agent,
38
+ AgentCardBuilder: () => AgentCardBuilder,
36
39
  AnthropicProvider: () => AnthropicProvider,
37
40
  ConfigLoader: () => ConfigLoader,
38
41
  LLMProvider: () => LLMProvider,
@@ -40,6 +43,7 @@ __export(index_exports, {
40
43
  MarkdownParser: () => MarkdownParser,
41
44
  Memory: () => Memory,
42
45
  MoltbookAdapter: () => MoltbookAdapter,
46
+ MoltiumExecutor: () => MoltiumExecutor,
43
47
  OpenAIProvider: () => OpenAIProvider,
44
48
  Scheduler: () => Scheduler,
45
49
  ShortTermMemory: () => ShortTermMemory,
@@ -49,13 +53,20 @@ __export(index_exports, {
49
53
  buildSkillPrompt: () => buildSkillPrompt,
50
54
  buildSystemPrompt: () => buildSystemPrompt,
51
55
  builtInActions: () => builtInActions,
56
+ createA2AClient: () => createA2AClient,
57
+ createA2AIntegration: () => createA2AIntegration,
52
58
  createApp: () => createApp,
59
+ createJoinWorldAction: () => createJoinWorldAction,
60
+ createLeaveWorldAction: () => createLeaveWorldAction,
53
61
  createLogger: () => createLogger,
54
62
  createMarkdownAction: () => createMarkdownAction,
63
+ createQueryWorldAction: () => createQueryWorldAction,
55
64
  createRoutes: () => createRoutes,
65
+ createSendWorldMessageAction: () => createSendWorldMessageAction,
56
66
  moltbookActions: () => moltbookActions,
57
67
  startServer: () => startServer,
58
- validateConfig: () => validateConfig
68
+ validateConfig: () => validateConfig,
69
+ worldActions: () => worldActions
59
70
  });
60
71
  module.exports = __toCommonJS(index_exports);
61
72
 
@@ -485,6 +496,140 @@ var moltbookActions = [
485
496
  readConversationAction
486
497
  ];
487
498
 
499
+ // src/actions/built-in/world.ts
500
+ function createJoinWorldAction(config) {
501
+ return {
502
+ name: "join_world",
503
+ 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.`,
504
+ async execute(context) {
505
+ const { parameters, agent } = context;
506
+ const worldUrl = parameters.worldUrl || config?.defaultWorldUrl;
507
+ if (!worldUrl) {
508
+ return { success: false, error: 'Parameter "worldUrl" is required' };
509
+ }
510
+ const agentPort = process.env.PORT || "3000";
511
+ const agentHost = process.env.HOST || "localhost";
512
+ const agentUrl = `http://${agentHost}:${agentPort}`;
513
+ try {
514
+ const { default: axios2 } = await import("axios");
515
+ const response = await axios2.post(`${worldUrl}/world/join`, {
516
+ agentUrl,
517
+ walletAddress: parameters.walletAddress || agent?.config?.world?.walletAddress
518
+ }, { timeout: 1e4 });
519
+ return {
520
+ success: true,
521
+ data: response.data
522
+ };
523
+ } catch (error) {
524
+ const msg = error?.response?.data?.error || error?.message || String(error);
525
+ return { success: false, error: `Failed to join world: ${msg}` };
526
+ }
527
+ }
528
+ };
529
+ }
530
+ function createLeaveWorldAction(config) {
531
+ return {
532
+ name: "leave_world",
533
+ description: `Leave a world. Parameters: worldUrl (string${config?.defaultWorldUrl ? ", optional" : ", required"}) - the world server URL.`,
534
+ async execute(context) {
535
+ const { parameters } = context;
536
+ const worldUrl = parameters.worldUrl || config?.defaultWorldUrl;
537
+ if (!worldUrl) {
538
+ return { success: false, error: 'Parameter "worldUrl" is required' };
539
+ }
540
+ const agentPort = process.env.PORT || "3000";
541
+ const agentHost = process.env.HOST || "localhost";
542
+ const agentUrl = `http://${agentHost}:${agentPort}`;
543
+ try {
544
+ const { default: axios2 } = await import("axios");
545
+ const response = await axios2.delete(
546
+ `${worldUrl}/world/agents/${encodeURIComponent(agentUrl)}`,
547
+ { timeout: 1e4 }
548
+ );
549
+ return {
550
+ success: true,
551
+ data: response.data
552
+ };
553
+ } catch (error) {
554
+ const msg = error?.response?.data?.error || error?.message || String(error);
555
+ return { success: false, error: `Failed to leave world: ${msg}` };
556
+ }
557
+ }
558
+ };
559
+ }
560
+ function createQueryWorldAction(config) {
561
+ return {
562
+ name: "query_world",
563
+ description: `Query a world's state, agents, and available actions. Parameters: worldUrl (string${config?.defaultWorldUrl ? ", optional" : ", required"}) - the world server URL, endpoint (string, optional) - specific endpoint: "state", "agents", "actions", or "info" (default: "info").`,
564
+ async execute(context) {
565
+ const { parameters } = context;
566
+ const worldUrl = parameters.worldUrl || config?.defaultWorldUrl;
567
+ if (!worldUrl) {
568
+ return { success: false, error: 'Parameter "worldUrl" is required' };
569
+ }
570
+ const endpoint = parameters.endpoint || "info";
571
+ const pathMap = {
572
+ info: "/",
573
+ state: "/world/state",
574
+ agents: "/world/agents",
575
+ actions: "/world/actions"
576
+ };
577
+ const path = pathMap[endpoint] || "/";
578
+ try {
579
+ const { default: axios2 } = await import("axios");
580
+ const response = await axios2.get(`${worldUrl}${path}`, { timeout: 1e4 });
581
+ return {
582
+ success: true,
583
+ data: response.data
584
+ };
585
+ } catch (error) {
586
+ const msg = error?.response?.data?.error || error?.message || String(error);
587
+ return { success: false, error: `Failed to query world: ${msg}` };
588
+ }
589
+ }
590
+ };
591
+ }
592
+ function createSendWorldMessageAction(config) {
593
+ return {
594
+ name: "send_world_message",
595
+ description: `Send a message to another agent through the world hub. Parameters: worldUrl (string${config?.defaultWorldUrl ? ", optional" : ", required"}) - the world server URL, toAgentUrl (string, optional) - target agent URL (omit to broadcast to all), message (string, required) - the message to send.`,
596
+ async execute(context) {
597
+ const { parameters } = context;
598
+ const worldUrl = parameters.worldUrl || config?.defaultWorldUrl;
599
+ if (!worldUrl) {
600
+ return { success: false, error: 'Parameter "worldUrl" is required' };
601
+ }
602
+ if (!parameters.message) {
603
+ return { success: false, error: 'Parameter "message" is required' };
604
+ }
605
+ const agentPort = process.env.PORT || "3000";
606
+ const agentHost = process.env.HOST || "localhost";
607
+ const agentUrl = `http://${agentHost}:${agentPort}`;
608
+ try {
609
+ const { default: axios2 } = await import("axios");
610
+ const response = await axios2.post(`${worldUrl}/world/message`, {
611
+ fromAgentUrl: agentUrl,
612
+ toAgentUrl: parameters.toAgentUrl,
613
+ message: parameters.message
614
+ }, { timeout: 15e3 });
615
+ return {
616
+ success: true,
617
+ data: response.data
618
+ };
619
+ } catch (error) {
620
+ const msg = error?.response?.data?.error || error?.message || String(error);
621
+ return { success: false, error: `Failed to send world message: ${msg}` };
622
+ }
623
+ }
624
+ };
625
+ }
626
+ var worldActions = {
627
+ createJoinWorldAction,
628
+ createLeaveWorldAction,
629
+ createQueryWorldAction,
630
+ createSendWorldMessageAction
631
+ };
632
+
488
633
  // src/actions/built-in/index.ts
489
634
  var builtInActions = [
490
635
  postSocialUpdateAction,
@@ -1379,6 +1524,178 @@ var TwitterAdapter = class extends SocialAdapter {
1379
1524
  }
1380
1525
  };
1381
1526
 
1527
+ // src/a2a/client.ts
1528
+ var import_client = require("@a2a-js/sdk/client");
1529
+ var import_uuid = require("uuid");
1530
+ var A2AClient = class {
1531
+ sdkClient;
1532
+ config;
1533
+ constructor(config) {
1534
+ this.config = {
1535
+ agentUrl: config.agentUrl,
1536
+ agentCardPath: config.agentCardPath || ".well-known/agent-card.json",
1537
+ timeout: config.timeout || 3e4
1538
+ };
1539
+ const agentUrl = this.config.agentUrl;
1540
+ const agentCardPath = this.config.agentCardPath;
1541
+ this.sdkClient = new import_client.A2AClient(agentUrl, agentCardPath);
1542
+ }
1543
+ /**
1544
+ * Send a text message to the agent and get a response
1545
+ *
1546
+ * @param options Message options including text content
1547
+ * @returns Promise resolving to the agent's response
1548
+ *
1549
+ * @example
1550
+ * ```typescript
1551
+ * const response = await client.sendMessage({
1552
+ * text: 'What are your thoughts on AI?',
1553
+ * contextId: 'conversation-123'
1554
+ * });
1555
+ *
1556
+ * if (response.success) {
1557
+ * console.log('Agent replied:', response.reply);
1558
+ * }
1559
+ * ```
1560
+ */
1561
+ async sendMessage(options) {
1562
+ try {
1563
+ const response = await this.sdkClient.sendMessage({
1564
+ message: {
1565
+ kind: "message",
1566
+ messageId: (0, import_uuid.v4)(),
1567
+ role: "user",
1568
+ contextId: options.contextId,
1569
+ metadata: options.metadata,
1570
+ parts: [
1571
+ {
1572
+ kind: "text",
1573
+ text: options.text
1574
+ }
1575
+ ]
1576
+ }
1577
+ });
1578
+ const reply = this.extractReply(response);
1579
+ return {
1580
+ success: true,
1581
+ reply,
1582
+ agentUrl: this.config.agentUrl,
1583
+ raw: response
1584
+ };
1585
+ } catch (error) {
1586
+ return {
1587
+ success: false,
1588
+ error: error.message || "Unknown error occurred",
1589
+ agentUrl: this.config.agentUrl
1590
+ };
1591
+ }
1592
+ }
1593
+ /**
1594
+ * Extract text reply from A2A protocol response
1595
+ * Handles both Message and Task response types
1596
+ */
1597
+ extractReply(response) {
1598
+ if (!("result" in response) || !response.result) {
1599
+ return JSON.stringify(response);
1600
+ }
1601
+ const result = response.result;
1602
+ if ("kind" in result && result.kind === "message" && "parts" in result) {
1603
+ const textParts = result.parts.filter((part) => part.kind === "text").map((part) => part.text);
1604
+ return textParts.join("\n");
1605
+ }
1606
+ return typeof result === "string" ? result : JSON.stringify(result);
1607
+ }
1608
+ /**
1609
+ * Get the agent card information
1610
+ *
1611
+ * @returns Promise resolving to the agent card
1612
+ */
1613
+ async getAgentCard() {
1614
+ return this.sdkClient.getAgentCard();
1615
+ }
1616
+ /**
1617
+ * Get the base URL of the agent
1618
+ */
1619
+ getAgentUrl() {
1620
+ return this.config.agentUrl;
1621
+ }
1622
+ };
1623
+ function createA2AClient(agentUrlOrConfig) {
1624
+ const config = typeof agentUrlOrConfig === "string" ? { agentUrl: agentUrlOrConfig } : agentUrlOrConfig;
1625
+ return new A2AClient(config);
1626
+ }
1627
+
1628
+ // src/a2a/actions.ts
1629
+ function createA2ACommunicationAction(config = {}) {
1630
+ const {
1631
+ defaultAgentUrl,
1632
+ actionName = "talk_to_agent",
1633
+ description,
1634
+ verbose = false
1635
+ } = config;
1636
+ 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})` : ""}`;
1637
+ return {
1638
+ name: actionName,
1639
+ description: defaultDescription,
1640
+ async execute(context) {
1641
+ const { parameters } = context;
1642
+ const message = parameters.message;
1643
+ const agentUrl = parameters.agentUrl || defaultAgentUrl;
1644
+ if (!message) {
1645
+ return {
1646
+ success: false,
1647
+ error: 'Parameter "message" is required'
1648
+ };
1649
+ }
1650
+ if (!agentUrl) {
1651
+ return {
1652
+ success: false,
1653
+ error: 'Parameter "agentUrl" is required or defaultAgentUrl must be configured'
1654
+ };
1655
+ }
1656
+ if (verbose) {
1657
+ console.log(`[A2A] Sending message to ${agentUrl}:`, message);
1658
+ }
1659
+ try {
1660
+ const client = new A2AClient({ agentUrl });
1661
+ const response = await client.sendMessage({ text: message });
1662
+ if (verbose) {
1663
+ console.log(`[A2A] Response from ${agentUrl}:`, response.reply);
1664
+ }
1665
+ if (!response.success) {
1666
+ return {
1667
+ success: false,
1668
+ error: response.error || "Failed to communicate with agent"
1669
+ };
1670
+ }
1671
+ return {
1672
+ success: true,
1673
+ data: {
1674
+ reply: response.reply,
1675
+ agentUrl: response.agentUrl
1676
+ }
1677
+ };
1678
+ } catch (error) {
1679
+ if (verbose) {
1680
+ console.error(`[A2A] Error:`, error);
1681
+ }
1682
+ return {
1683
+ success: false,
1684
+ error: error.message || "Unknown error occurred"
1685
+ };
1686
+ }
1687
+ }
1688
+ };
1689
+ }
1690
+ function createMultipleA2AActions(configs) {
1691
+ return Object.entries(configs).map(
1692
+ ([name, config]) => createA2ACommunicationAction({
1693
+ ...config,
1694
+ actionName: name
1695
+ })
1696
+ );
1697
+ }
1698
+
1382
1699
  // src/agent/Agent.ts
1383
1700
  var logger4 = createLogger("Agent");
1384
1701
  function parsePostFrequency(freq) {
@@ -1499,6 +1816,9 @@ var Agent = class {
1499
1816
  if (this.hooks.onStart) {
1500
1817
  await this.hooks.onStart(this);
1501
1818
  }
1819
+ if (this.config.world?.url && this.config.world.autoJoin !== false) {
1820
+ await this.autoJoinWorld();
1821
+ }
1502
1822
  this.scheduler.start();
1503
1823
  if (this.config.behaviors.autonomous) {
1504
1824
  this.startAutonomousLoop();
@@ -1632,6 +1952,53 @@ var Agent = class {
1632
1952
  }
1633
1953
  logger4.info(`Registered ${moltbookActions.length} Moltbook actions`);
1634
1954
  }
1955
+ const a2a = this.config.a2a;
1956
+ if (a2a && a2a.enabled !== false) {
1957
+ if (a2a.peers && Object.keys(a2a.peers).length > 0) {
1958
+ const peerActions = createMultipleA2AActions(
1959
+ Object.entries(a2a.peers).reduce((acc, [actionName, url]) => {
1960
+ acc[actionName] = {
1961
+ defaultAgentUrl: url,
1962
+ verbose: a2a.verbose,
1963
+ description: `Communicate with peer agent at ${url}`
1964
+ };
1965
+ return acc;
1966
+ }, {})
1967
+ );
1968
+ for (const action of peerActions) {
1969
+ if (!this.actionRegistry.has(action.name)) {
1970
+ this.actionRegistry.register(action);
1971
+ }
1972
+ }
1973
+ logger4.info(`Registered ${peerActions.length} A2A peer actions`);
1974
+ } else {
1975
+ const genericAction = createA2ACommunicationAction({
1976
+ defaultAgentUrl: a2a.defaultPeerUrl,
1977
+ actionName: a2a.genericActionName || "talk_to_agent",
1978
+ verbose: a2a.verbose
1979
+ });
1980
+ if (!this.actionRegistry.has(genericAction.name)) {
1981
+ this.actionRegistry.register(genericAction);
1982
+ }
1983
+ logger4.info(`Registered generic A2A action: ${genericAction.name}`);
1984
+ }
1985
+ }
1986
+ const world = this.config.world;
1987
+ if (world?.url) {
1988
+ const worldUrl = world.url;
1989
+ const worldActionsList = [
1990
+ createJoinWorldAction({ defaultWorldUrl: worldUrl }),
1991
+ createLeaveWorldAction({ defaultWorldUrl: worldUrl }),
1992
+ createQueryWorldAction({ defaultWorldUrl: worldUrl }),
1993
+ createSendWorldMessageAction({ defaultWorldUrl: worldUrl })
1994
+ ];
1995
+ for (const action of worldActionsList) {
1996
+ if (!this.actionRegistry.has(action.name)) {
1997
+ this.actionRegistry.register(action);
1998
+ }
1999
+ }
2000
+ logger4.info(`Registered 4 world actions (world: ${worldUrl})`);
2001
+ }
1635
2002
  if (this.config.customActions) {
1636
2003
  for (const action of this.config.customActions) {
1637
2004
  this.actionRegistry.register(action);
@@ -1918,6 +2285,23 @@ Decide what action to take. Respond with JSON:
1918
2285
  logger4.error(` ${platform}: Server error \u2014 the platform may be temporarily down.`);
1919
2286
  }
1920
2287
  }
2288
+ async autoJoinWorld() {
2289
+ const worldUrl = this.config.world.url;
2290
+ logger4.info(`Auto-joining world: ${worldUrl}`);
2291
+ try {
2292
+ const result = await this.act("join_world", {
2293
+ worldUrl,
2294
+ walletAddress: this.config.world.walletAddress
2295
+ });
2296
+ if (result.success) {
2297
+ logger4.info(`Successfully joined world: ${worldUrl}`);
2298
+ } else {
2299
+ logger4.warn(`Failed to join world: ${result.error}`);
2300
+ }
2301
+ } catch (error) {
2302
+ logger4.warn(`Auto-join world failed: ${error?.message || error}`);
2303
+ }
2304
+ }
1921
2305
  startAutonomousLoop() {
1922
2306
  const actionsPerHour = typeof this.config.behaviors.actionsPerHour === "function" ? this.config.behaviors.actionsPerHour({}) : this.config.behaviors.actionsPerHour || 5;
1923
2307
  const intervalMs = Math.floor(36e5 / actionsPerHour);
@@ -1980,6 +2364,7 @@ var MarkdownParser = class {
1980
2364
  const memory = this.findSection(sections, "Memory");
1981
2365
  const skills = this.findSection(sections, "Skills");
1982
2366
  const scheduling = this.findSection(sections, "Scheduling");
2367
+ const world = this.findSection(sections, "World");
1983
2368
  const identityData = this.parseIdentity(identity);
1984
2369
  const bioText = bio ? bio.content.trim() : identityData?.personality?.bio || "";
1985
2370
  const config = {
@@ -1991,6 +2376,7 @@ var MarkdownParser = class {
1991
2376
  ...social ? { social: this.parseSocial(social) } : {},
1992
2377
  ...behaviors ? { behaviors: this.parseBehaviors(behaviors) } : {},
1993
2378
  ...memory ? { memory: this.parseMemory(memory) } : {},
2379
+ ...world ? { world: this.parseWorld(world) } : {},
1994
2380
  actions: [],
1995
2381
  ...frontmatter
1996
2382
  };
@@ -2091,6 +2477,16 @@ var MarkdownParser = class {
2091
2477
  retention: fields["retention"]
2092
2478
  };
2093
2479
  }
2480
+ parseWorld(section) {
2481
+ const fields = this.parseKeyValueLines(section.content);
2482
+ const url = fields["url"];
2483
+ if (!url) return void 0;
2484
+ return {
2485
+ url,
2486
+ autoJoin: fields["auto_join"] !== "false",
2487
+ ...fields["wallet_address"] ? { walletAddress: fields["wallet_address"] } : {}
2488
+ };
2489
+ }
2094
2490
  parseSleepSchedule(value) {
2095
2491
  const match = value.match(/(\d{1,2}):?\d{0,2}\s*-\s*(\d{1,2}):?\d{0,2}\s*(.*)?/);
2096
2492
  if (!match) return { start: 22, end: 6 };
@@ -2621,27 +3017,516 @@ function authMiddleware(req, res, next) {
2621
3017
  next();
2622
3018
  }
2623
3019
 
3020
+ // src/a2a/AgentCardBuilder.ts
3021
+ var logger7 = createLogger("AgentCardBuilder");
3022
+ var AgentCardBuilder = class {
3023
+ /**
3024
+ * Creates an A2A AgentCard from Moltium configuration.
3025
+ * @param config The Moltium agent configuration
3026
+ * @param a2aConfig A2A-specific configuration (URLs, capabilities)
3027
+ * @returns A2A-compliant AgentCard
3028
+ */
3029
+ static build(config, a2aConfig) {
3030
+ const baseUrl = a2aConfig.baseUrl;
3031
+ const skills = this.buildSkills(config);
3032
+ const capabilities = {
3033
+ streaming: a2aConfig.streaming ?? true,
3034
+ pushNotifications: a2aConfig.pushNotifications ?? false,
3035
+ stateTransitionHistory: a2aConfig.stateTransitionHistory ?? true
3036
+ };
3037
+ const defaultInputModes = ["text"];
3038
+ const defaultOutputModes = ["text"];
3039
+ const agentCard = {
3040
+ name: config.name,
3041
+ description: config.personality.bio || `${config.name} - An autonomous AI agent`,
3042
+ protocolVersion: "0.3.0",
3043
+ version: "0.1.0",
3044
+ url: `${baseUrl}/a2a/jsonrpc`,
3045
+ skills,
3046
+ capabilities,
3047
+ defaultInputModes,
3048
+ defaultOutputModes,
3049
+ additionalInterfaces: [
3050
+ { url: `${baseUrl}/a2a/jsonrpc`, transport: "JSONRPC" },
3051
+ { url: `${baseUrl}/a2a/rest`, transport: "HTTP+JSON" }
3052
+ ]
3053
+ };
3054
+ logger7.debug("Built A2A AgentCard", {
3055
+ name: agentCard.name,
3056
+ skillCount: skills.length,
3057
+ baseUrl
3058
+ });
3059
+ return agentCard;
3060
+ }
3061
+ /**
3062
+ * Converts Moltium actions to A2A skills.
3063
+ */
3064
+ static buildSkills(config) {
3065
+ const skills = [];
3066
+ skills.push({
3067
+ id: "chat",
3068
+ name: "Chat",
3069
+ description: `Interact with ${config.name}. ${config.personality.bio || ""}`,
3070
+ tags: ["chat", "conversation"]
3071
+ });
3072
+ const hasPosting = config.actions.some(
3073
+ (a) => a.includes("post") || a.includes("update")
3074
+ );
3075
+ if (hasPosting) {
3076
+ skills.push({
3077
+ id: "social_posting",
3078
+ name: "Social Posting",
3079
+ description: "Post updates and content to social platforms",
3080
+ tags: ["social", "posting"]
3081
+ });
3082
+ }
3083
+ const hasEngagement = config.actions.some(
3084
+ (a) => a.includes("comment") || a.includes("reply") || a.includes("respond")
3085
+ );
3086
+ if (hasEngagement) {
3087
+ skills.push({
3088
+ id: "social_engagement",
3089
+ name: "Social Engagement",
3090
+ description: "Engage with others through comments and replies",
3091
+ tags: ["social", "engagement"]
3092
+ });
3093
+ }
3094
+ const hasSearch = config.actions.some(
3095
+ (a) => a.includes("search") || a.includes("check_feed") || a.includes("browse")
3096
+ );
3097
+ if (hasSearch) {
3098
+ skills.push({
3099
+ id: "content_discovery",
3100
+ name: "Content Discovery",
3101
+ description: "Search and discover relevant content",
3102
+ tags: ["search", "discovery"]
3103
+ });
3104
+ }
3105
+ const hasAnalysis = config.actions.some(
3106
+ (a) => a.includes("analyze") || a.includes("think") || a.includes("research")
3107
+ );
3108
+ if (hasAnalysis) {
3109
+ skills.push({
3110
+ id: "analysis",
3111
+ name: "Analysis & Research",
3112
+ description: "Analyze problems and conduct research",
3113
+ tags: ["analysis", "research", "thinking"]
3114
+ });
3115
+ }
3116
+ return skills;
3117
+ }
3118
+ /**
3119
+ * Updates an agent card with runtime information.
3120
+ */
3121
+ static updateWithRuntime(agentCard, actualPort, actualHost = "localhost") {
3122
+ const protocol = actualHost === "localhost" || actualHost === "127.0.0.1" ? "http" : "https";
3123
+ const baseUrl = `${protocol}://${actualHost}:${actualPort}`;
3124
+ return {
3125
+ ...agentCard,
3126
+ url: `${baseUrl}/a2a/jsonrpc`,
3127
+ additionalInterfaces: [
3128
+ { url: `${baseUrl}/a2a/jsonrpc`, transport: "JSONRPC" },
3129
+ { url: `${baseUrl}/a2a/rest`, transport: "HTTP+JSON" }
3130
+ ]
3131
+ };
3132
+ }
3133
+ };
3134
+
3135
+ // src/a2a/MoltiumExecutor.ts
3136
+ var import_uuid2 = require("uuid");
3137
+ var logger8 = createLogger("MoltiumExecutor");
3138
+ var MoltiumExecutor = class {
3139
+ agent;
3140
+ cancelledTasks = /* @__PURE__ */ new Set();
3141
+ constructor(agent) {
3142
+ this.agent = agent;
3143
+ }
3144
+ /**
3145
+ * Executes an A2A request using the Moltium agent.
3146
+ * Converts A2A messages to Moltium actions and publishes results back via the event bus.
3147
+ */
3148
+ async execute(requestContext, eventBus) {
3149
+ const { taskId, contextId, userMessage, task } = requestContext;
3150
+ try {
3151
+ logger8.info(`[A2A] Executing request for task ${taskId}`);
3152
+ if (!task) {
3153
+ const initialTask = {
3154
+ kind: "task",
3155
+ id: taskId,
3156
+ contextId,
3157
+ status: {
3158
+ state: "submitted",
3159
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
3160
+ },
3161
+ history: [userMessage]
3162
+ };
3163
+ eventBus.publish(initialTask);
3164
+ }
3165
+ if (this.cancelledTasks.has(taskId)) {
3166
+ this.publishCancellation(taskId, contextId, eventBus);
3167
+ return;
3168
+ }
3169
+ this.publishStatusUpdate(taskId, contextId, "working", eventBus, false);
3170
+ const userContent = this.extractMessageContent(userMessage);
3171
+ const isActionRequest = this.isActionRequest(userContent);
3172
+ let result;
3173
+ if (isActionRequest) {
3174
+ result = await this.executeAction(userContent, taskId);
3175
+ } else {
3176
+ result = await this.executeChat(userContent, taskId);
3177
+ }
3178
+ if (this.cancelledTasks.has(taskId)) {
3179
+ this.publishCancellation(taskId, contextId, eventBus);
3180
+ return;
3181
+ }
3182
+ if (result.success) {
3183
+ await this.publishResult(taskId, contextId, result, eventBus);
3184
+ } else {
3185
+ await this.publishError(taskId, contextId, result.error || "Unknown error", eventBus);
3186
+ }
3187
+ this.publishStatusUpdate(taskId, contextId, "completed", eventBus, true);
3188
+ eventBus.finished();
3189
+ logger8.info(`[A2A] Task ${taskId} completed successfully`);
3190
+ } catch (error) {
3191
+ logger8.error(`[A2A] Task ${taskId} failed`, {
3192
+ error: error instanceof Error ? error.message : String(error)
3193
+ });
3194
+ const errorMessage = error instanceof Error ? error.message : String(error);
3195
+ await this.publishError(taskId, contextId, errorMessage, eventBus);
3196
+ this.publishStatusUpdate(taskId, contextId, "failed", eventBus, true);
3197
+ eventBus.finished();
3198
+ } finally {
3199
+ this.cancelledTasks.delete(taskId);
3200
+ }
3201
+ }
3202
+ /**
3203
+ * Handles task cancellation requests.
3204
+ */
3205
+ async cancelTask(taskId, eventBus) {
3206
+ logger8.info(`[A2A] Cancellation requested for task ${taskId}`);
3207
+ this.cancelledTasks.add(taskId);
3208
+ }
3209
+ /**
3210
+ * Extracts text content from an A2A message.
3211
+ */
3212
+ extractMessageContent(message) {
3213
+ const textParts = message.parts.filter((part) => part.kind === "text");
3214
+ return textParts.map((part) => part.text).join("\n");
3215
+ }
3216
+ /**
3217
+ * Determines if the user message is requesting a specific action.
3218
+ */
3219
+ isActionRequest(content) {
3220
+ const actionKeywords = [
3221
+ "post",
3222
+ "search",
3223
+ "check feed",
3224
+ "browse",
3225
+ "comment",
3226
+ "upvote",
3227
+ "follow",
3228
+ "send dm"
3229
+ ];
3230
+ const lowerContent = content.toLowerCase();
3231
+ return actionKeywords.some((keyword) => lowerContent.includes(keyword));
3232
+ }
3233
+ /**
3234
+ * Executes a chat interaction using the agent's LLM.
3235
+ */
3236
+ async executeChat(userContent, taskId) {
3237
+ try {
3238
+ const llm = this.agent.getLLM();
3239
+ const systemPrompt = this.agent.getSystemPrompt();
3240
+ const response = await llm.generateText(userContent, {
3241
+ systemPrompt,
3242
+ temperature: this.agent.config.llm.temperature
3243
+ });
3244
+ return {
3245
+ success: true,
3246
+ data: { response, type: "chat" }
3247
+ };
3248
+ } catch (error) {
3249
+ return {
3250
+ success: false,
3251
+ error: `Chat execution failed: ${error instanceof Error ? error.message : String(error)}`
3252
+ };
3253
+ }
3254
+ }
3255
+ /**
3256
+ * Executes an action based on the user's request.
3257
+ */
3258
+ async executeAction(userContent, taskId) {
3259
+ try {
3260
+ const decision = await this.agent.think();
3261
+ const result = await this.agent.act(decision.action, decision.parameters);
3262
+ return {
3263
+ success: result.success,
3264
+ data: {
3265
+ action: decision.action,
3266
+ reasoning: decision.reasoning,
3267
+ result: result.data,
3268
+ type: "action"
3269
+ },
3270
+ error: result.error
3271
+ };
3272
+ } catch (error) {
3273
+ return {
3274
+ success: false,
3275
+ error: `Action execution failed: ${error instanceof Error ? error.message : String(error)}`
3276
+ };
3277
+ }
3278
+ }
3279
+ /**
3280
+ * Publishes a successful result as an A2A artifact.
3281
+ */
3282
+ async publishResult(taskId, contextId, result, eventBus) {
3283
+ const data = result.data;
3284
+ if (data?.type === "chat") {
3285
+ const artifactUpdate = {
3286
+ kind: "artifact-update",
3287
+ taskId,
3288
+ contextId,
3289
+ artifact: {
3290
+ artifactId: `response-${(0, import_uuid2.v4)()}`,
3291
+ name: "response.txt",
3292
+ parts: [{ kind: "text", text: data.response }]
3293
+ }
3294
+ };
3295
+ eventBus.publish(artifactUpdate);
3296
+ } else if (data?.type === "action") {
3297
+ const resultText = JSON.stringify(
3298
+ {
3299
+ action: data.action,
3300
+ reasoning: data.reasoning,
3301
+ result: data.result
3302
+ },
3303
+ null,
3304
+ 2
3305
+ );
3306
+ const artifactUpdate = {
3307
+ kind: "artifact-update",
3308
+ taskId,
3309
+ contextId,
3310
+ artifact: {
3311
+ artifactId: `action-result-${(0, import_uuid2.v4)()}`,
3312
+ name: "action_result.json",
3313
+ parts: [{ kind: "text", text: resultText }]
3314
+ }
3315
+ };
3316
+ eventBus.publish(artifactUpdate);
3317
+ } else {
3318
+ const resultText = typeof result.data === "string" ? result.data : JSON.stringify(result.data, null, 2);
3319
+ const artifactUpdate = {
3320
+ kind: "artifact-update",
3321
+ taskId,
3322
+ contextId,
3323
+ artifact: {
3324
+ artifactId: `result-${(0, import_uuid2.v4)()}`,
3325
+ name: "result.txt",
3326
+ parts: [{ kind: "text", text: resultText }]
3327
+ }
3328
+ };
3329
+ eventBus.publish(artifactUpdate);
3330
+ }
3331
+ }
3332
+ /**
3333
+ * Publishes an error as an A2A artifact.
3334
+ */
3335
+ async publishError(taskId, contextId, error, eventBus) {
3336
+ const artifactUpdate = {
3337
+ kind: "artifact-update",
3338
+ taskId,
3339
+ contextId,
3340
+ artifact: {
3341
+ artifactId: `error-${(0, import_uuid2.v4)()}`,
3342
+ name: "error.txt",
3343
+ parts: [{ kind: "text", text: `Error: ${error}` }]
3344
+ }
3345
+ };
3346
+ eventBus.publish(artifactUpdate);
3347
+ }
3348
+ /**
3349
+ * Publishes a status update event.
3350
+ */
3351
+ publishStatusUpdate(taskId, contextId, state, eventBus, final) {
3352
+ const statusUpdate = {
3353
+ kind: "status-update",
3354
+ taskId,
3355
+ contextId,
3356
+ status: {
3357
+ state,
3358
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
3359
+ },
3360
+ final
3361
+ };
3362
+ eventBus.publish(statusUpdate);
3363
+ }
3364
+ /**
3365
+ * Publishes a cancellation status.
3366
+ */
3367
+ publishCancellation(taskId, contextId, eventBus) {
3368
+ logger8.info(`[A2A] Publishing cancellation for task ${taskId}`);
3369
+ this.publishStatusUpdate(taskId, contextId, "canceled", eventBus, true);
3370
+ eventBus.finished();
3371
+ this.cancelledTasks.delete(taskId);
3372
+ }
3373
+ };
3374
+
3375
+ // src/a2a/integration.ts
3376
+ var import_server = require("@a2a-js/sdk/server");
3377
+ var logger9 = createLogger("A2AIntegration");
3378
+ var A2AIntegration = class {
3379
+ agent;
3380
+ agentCard;
3381
+ requestHandler;
3382
+ moltiumExecutor;
3383
+ constructor(agent, options) {
3384
+ this.agent = agent;
3385
+ this.agentCard = AgentCardBuilder.build(agent.config, options.a2aConfig);
3386
+ this.moltiumExecutor = new MoltiumExecutor(agent);
3387
+ this.requestHandler = new import_server.DefaultRequestHandler(
3388
+ this.agentCard,
3389
+ new import_server.InMemoryTaskStore(),
3390
+ this.moltiumExecutor
3391
+ );
3392
+ logger9.info("A2A integration initialized", {
3393
+ agentName: agent.name,
3394
+ baseUrl: options.a2aConfig.baseUrl
3395
+ });
3396
+ }
3397
+ /**
3398
+ * Creates Express middleware handlers for A2A endpoints.
3399
+ * Returns an object with individual handlers that can be mounted on specific routes.
3400
+ */
3401
+ getHandlers() {
3402
+ return {
3403
+ // Agent Card endpoint - serves the static agent card JSON
3404
+ agentCard: ((req, res) => {
3405
+ res.json(this.agentCard);
3406
+ }),
3407
+ // JSON-RPC endpoint - handles A2A protocol requests
3408
+ jsonRpc: (async (req, res) => {
3409
+ try {
3410
+ const jsonRpcHandler = new import_server.JsonRpcTransportHandler(this.requestHandler);
3411
+ const response = await jsonRpcHandler.handle(req.body);
3412
+ res.json(response);
3413
+ } catch (error) {
3414
+ logger9.error("JSON-RPC error:", error);
3415
+ res.status(500).json({
3416
+ jsonrpc: "2.0",
3417
+ error: {
3418
+ code: -32603,
3419
+ message: "Internal error",
3420
+ data: error.message
3421
+ },
3422
+ id: req.body?.id || null
3423
+ });
3424
+ }
3425
+ }),
3426
+ // REST endpoint - simplified HTTP+JSON interface
3427
+ rest: ((req, res) => {
3428
+ res.status(501).json({
3429
+ error: "REST transport not implemented in SDK v0.3.0",
3430
+ message: "Please use the JSON-RPC endpoint at /a2a/jsonrpc"
3431
+ });
3432
+ })
3433
+ };
3434
+ }
3435
+ /**
3436
+ * Updates the agent card with actual runtime information (host/port).
3437
+ */
3438
+ updateAgentCard(actualPort, actualHost = "localhost") {
3439
+ this.agentCard = AgentCardBuilder.updateWithRuntime(this.agentCard, actualPort, actualHost);
3440
+ this.requestHandler = new import_server.DefaultRequestHandler(
3441
+ this.agentCard,
3442
+ new import_server.InMemoryTaskStore(),
3443
+ this.moltiumExecutor
3444
+ );
3445
+ logger9.info("A2A agent card updated with runtime info", {
3446
+ host: actualHost,
3447
+ port: actualPort,
3448
+ url: this.agentCard.url
3449
+ });
3450
+ }
3451
+ /**
3452
+ * Gets the current agent card.
3453
+ */
3454
+ getAgentCard() {
3455
+ return this.agentCard;
3456
+ }
3457
+ /**
3458
+ * Logs A2A endpoint information.
3459
+ */
3460
+ logEndpoints(host, port) {
3461
+ const protocol = host === "localhost" || host === "127.0.0.1" ? "http" : "https";
3462
+ const baseUrl = `${protocol}://${host}:${port}`;
3463
+ logger9.info("A2A endpoints available:");
3464
+ logger9.info(` Agent Card: ${baseUrl}/.well-known/agent-card.json`);
3465
+ logger9.info(` JSON-RPC: ${baseUrl}/a2a/jsonrpc`);
3466
+ logger9.info(` HTTP+JSON: ${baseUrl}/a2a/rest`);
3467
+ }
3468
+ };
3469
+ function createA2AIntegration(agent, options = {}) {
3470
+ const a2aConfig = {
3471
+ enabled: true,
3472
+ baseUrl: options.a2aConfig?.baseUrl || "http://localhost:3000",
3473
+ pushNotifications: options.a2aConfig?.pushNotifications ?? false,
3474
+ streaming: options.a2aConfig?.streaming ?? true,
3475
+ stateTransitionHistory: options.a2aConfig?.stateTransitionHistory ?? true
3476
+ };
3477
+ return new A2AIntegration(agent, { a2aConfig, ...options });
3478
+ }
3479
+
2624
3480
  // src/server/app.ts
2625
- var logger7 = createLogger("Server");
2626
- function createApp(agent) {
3481
+ var logger10 = createLogger("Server");
3482
+ var AGENT_CARD_PATH = ".well-known/agent-card.json";
3483
+ function createApp(agent, options = {}) {
2627
3484
  const app = (0, import_express2.default)();
2628
3485
  app.use(import_express2.default.json());
2629
3486
  app.use(requestLogger);
2630
3487
  app.use(authMiddleware);
2631
3488
  app.use(createRoutes(agent));
3489
+ if (options.enableA2A !== false) {
3490
+ const port = options.port || parseInt(process.env.PORT || "3000", 10);
3491
+ const host = options.host || "0.0.0.0";
3492
+ const protocol = host === "localhost" || host === "127.0.0.1" || host === "0.0.0.0" ? "http" : "https";
3493
+ const baseUrl = options.a2aConfig?.baseUrl || `${protocol}://${host}:${port}`;
3494
+ const a2aIntegration = createA2AIntegration(agent, {
3495
+ a2aConfig: {
3496
+ enabled: true,
3497
+ baseUrl,
3498
+ pushNotifications: options.a2aConfig?.pushNotifications ?? false,
3499
+ streaming: options.a2aConfig?.streaming ?? true,
3500
+ stateTransitionHistory: options.a2aConfig?.stateTransitionHistory ?? true
3501
+ }
3502
+ });
3503
+ const handlers = a2aIntegration.getHandlers();
3504
+ app.use(`/${AGENT_CARD_PATH}`, handlers.agentCard);
3505
+ app.use("/a2a/jsonrpc", handlers.jsonRpc);
3506
+ app.use("/a2a/rest", handlers.rest);
3507
+ logger10.info("A2A protocol endpoints enabled");
3508
+ }
2632
3509
  app.use(errorHandler);
2633
3510
  return app;
2634
3511
  }
2635
3512
  async function startServer(agent, options = {}) {
2636
3513
  const port = options.port || parseInt(process.env.PORT || "3000", 10);
2637
3514
  const host = options.host || "0.0.0.0";
2638
- const app = createApp(agent);
3515
+ const app = createApp(agent, options);
2639
3516
  await agent.start();
2640
3517
  app.listen(port, host, () => {
2641
- logger7.info(`Agent "${agent.name}" running at http://${host}:${port}`);
3518
+ logger10.info(`Agent "${agent.name}" running at http://${host}:${port}`);
3519
+ if (options.enableA2A !== false) {
3520
+ const protocol = host === "localhost" || host === "127.0.0.1" ? "http" : "https";
3521
+ const baseUrl = `${protocol}://${host}:${port}`;
3522
+ logger10.info("A2A Protocol Endpoints:");
3523
+ logger10.info(` Agent Card: ${baseUrl}/.well-known/agent-card.json`);
3524
+ logger10.info(` JSON-RPC: ${baseUrl}/a2a/jsonrpc`);
3525
+ logger10.info(` HTTP+JSON: ${baseUrl}/a2a/rest`);
3526
+ }
2642
3527
  });
2643
3528
  const shutdown = async () => {
2644
- logger7.info("Received shutdown signal");
3529
+ logger10.info("Received shutdown signal");
2645
3530
  await agent.stop();
2646
3531
  process.exit(0);
2647
3532
  };
@@ -2650,9 +3535,12 @@ async function startServer(agent, options = {}) {
2650
3535
  }
2651
3536
  // Annotate the CommonJS export names for ESM import in node:
2652
3537
  0 && (module.exports = {
3538
+ A2AClient,
3539
+ A2AIntegration,
2653
3540
  ActionHandler,
2654
3541
  ActionRegistry,
2655
3542
  Agent,
3543
+ AgentCardBuilder,
2656
3544
  AnthropicProvider,
2657
3545
  ConfigLoader,
2658
3546
  LLMProvider,
@@ -2660,6 +3548,7 @@ async function startServer(agent, options = {}) {
2660
3548
  MarkdownParser,
2661
3549
  Memory,
2662
3550
  MoltbookAdapter,
3551
+ MoltiumExecutor,
2663
3552
  OpenAIProvider,
2664
3553
  Scheduler,
2665
3554
  ShortTermMemory,
@@ -2669,12 +3558,19 @@ async function startServer(agent, options = {}) {
2669
3558
  buildSkillPrompt,
2670
3559
  buildSystemPrompt,
2671
3560
  builtInActions,
3561
+ createA2AClient,
3562
+ createA2AIntegration,
2672
3563
  createApp,
3564
+ createJoinWorldAction,
3565
+ createLeaveWorldAction,
2673
3566
  createLogger,
2674
3567
  createMarkdownAction,
3568
+ createQueryWorldAction,
2675
3569
  createRoutes,
3570
+ createSendWorldMessageAction,
2676
3571
  moltbookActions,
2677
3572
  startServer,
2678
- validateConfig
3573
+ validateConfig,
3574
+ worldActions
2679
3575
  });
2680
3576
  //# sourceMappingURL=index.js.map