@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/README.md +231 -0
- package/dist/index.d.cts +162 -3
- package/dist/index.d.ts +162 -3
- package/dist/index.js +964 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +959 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -2
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
|
-
|
|
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())
|
|
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
|
-
|
|
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
|
|
2370
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
});
|