@moltium/core 0.1.4 → 0.1.6
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.d.cts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +141 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +141 -32
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -536,7 +536,7 @@ var MoltbookAdapter = class extends SocialAdapter {
|
|
|
536
536
|
super();
|
|
537
537
|
this.config = config;
|
|
538
538
|
this.client = axios.create({
|
|
539
|
-
baseURL: config.baseUrl || "https://
|
|
539
|
+
baseURL: config.baseUrl || "https://www.moltbook.com/api/v1",
|
|
540
540
|
headers: {
|
|
541
541
|
Authorization: `Bearer ${config.apiKey}`,
|
|
542
542
|
"Content-Type": "application/json"
|
|
@@ -544,12 +544,18 @@ var MoltbookAdapter = class extends SocialAdapter {
|
|
|
544
544
|
});
|
|
545
545
|
}
|
|
546
546
|
async connect() {
|
|
547
|
-
await this.client.get("/me");
|
|
547
|
+
await this.client.get("/agents/me");
|
|
548
548
|
}
|
|
549
549
|
async disconnect() {
|
|
550
550
|
}
|
|
551
551
|
async post(content) {
|
|
552
|
-
const
|
|
552
|
+
const submolt = this.config.defaultSubmolt || "general";
|
|
553
|
+
const title = extractTitle(content);
|
|
554
|
+
const response = await this.client.post("/posts", {
|
|
555
|
+
submolt,
|
|
556
|
+
title,
|
|
557
|
+
content
|
|
558
|
+
});
|
|
553
559
|
return {
|
|
554
560
|
id: response.data.id,
|
|
555
561
|
url: response.data.url,
|
|
@@ -557,7 +563,7 @@ var MoltbookAdapter = class extends SocialAdapter {
|
|
|
557
563
|
};
|
|
558
564
|
}
|
|
559
565
|
async reply(postId, content) {
|
|
560
|
-
const response = await this.client.post(`/posts/${postId}/
|
|
566
|
+
const response = await this.client.post(`/posts/${postId}/comments`, { content });
|
|
561
567
|
return {
|
|
562
568
|
id: response.data.id,
|
|
563
569
|
parentId: postId,
|
|
@@ -566,44 +572,48 @@ var MoltbookAdapter = class extends SocialAdapter {
|
|
|
566
572
|
};
|
|
567
573
|
}
|
|
568
574
|
async like(postId) {
|
|
569
|
-
await this.client.post(`/posts/${postId}/
|
|
575
|
+
await this.client.post(`/posts/${postId}/upvote`);
|
|
570
576
|
}
|
|
571
|
-
async follow(
|
|
572
|
-
await this.client.post(`/
|
|
577
|
+
async follow(agentName) {
|
|
578
|
+
await this.client.post(`/agents/${agentName}/follow`);
|
|
573
579
|
}
|
|
574
580
|
async getMentions() {
|
|
575
|
-
const response = await this.client.get("/
|
|
576
|
-
|
|
581
|
+
const response = await this.client.get("/feed", {
|
|
582
|
+
params: { sort: "new", limit: 20 }
|
|
583
|
+
});
|
|
584
|
+
return (response.data.posts || []).map((m) => ({
|
|
577
585
|
id: m.id,
|
|
578
|
-
authorId: m.author_id,
|
|
579
|
-
authorName: m.author_name,
|
|
586
|
+
authorId: m.author_id || m.author?.id || "",
|
|
587
|
+
authorName: m.author_name || m.author?.name || "",
|
|
580
588
|
content: m.content,
|
|
581
589
|
timestamp: new Date(m.created_at),
|
|
582
590
|
platform: "moltbook"
|
|
583
591
|
}));
|
|
584
592
|
}
|
|
585
593
|
async getFeed(options) {
|
|
586
|
-
const params = {};
|
|
594
|
+
const params = { sort: "hot" };
|
|
587
595
|
if (options?.limit) params.limit = options.limit;
|
|
588
596
|
if (options?.cursor) params.cursor = options.cursor;
|
|
589
597
|
if (options?.since) params.since = options.since.toISOString();
|
|
590
598
|
const response = await this.client.get("/feed", { params });
|
|
591
|
-
return response.data.posts.map((p) => ({
|
|
599
|
+
return (response.data.posts || []).map((p) => ({
|
|
592
600
|
id: p.id,
|
|
593
|
-
authorId: p.author_id,
|
|
594
|
-
authorName: p.author_name,
|
|
601
|
+
authorId: p.author_id || p.author?.id || "",
|
|
602
|
+
authorName: p.author_name || p.author?.name || "",
|
|
595
603
|
content: p.content,
|
|
596
604
|
timestamp: new Date(p.created_at),
|
|
597
605
|
platform: "moltbook",
|
|
598
|
-
likes: p.likes_count,
|
|
599
|
-
replies: p.replies_count,
|
|
606
|
+
likes: p.upvotes ?? p.likes_count,
|
|
607
|
+
replies: p.comment_count ?? p.replies_count,
|
|
600
608
|
reposts: p.reposts_count,
|
|
601
609
|
mentions: p.mentions || [],
|
|
602
610
|
url: p.url
|
|
603
611
|
}));
|
|
604
612
|
}
|
|
605
|
-
async getProfile(
|
|
606
|
-
const response = await this.client.get(
|
|
613
|
+
async getProfile(agentName) {
|
|
614
|
+
const response = await this.client.get("/agents/profile", {
|
|
615
|
+
params: { name: agentName }
|
|
616
|
+
});
|
|
607
617
|
return {
|
|
608
618
|
id: response.data.id,
|
|
609
619
|
name: response.data.name,
|
|
@@ -614,6 +624,14 @@ var MoltbookAdapter = class extends SocialAdapter {
|
|
|
614
624
|
};
|
|
615
625
|
}
|
|
616
626
|
};
|
|
627
|
+
function extractTitle(content) {
|
|
628
|
+
const firstLine = content.split("\n")[0].trim();
|
|
629
|
+
const sentenceEnd = firstLine.search(/[.!?]/);
|
|
630
|
+
const raw = sentenceEnd > 0 && sentenceEnd <= 80 ? firstLine.slice(0, sentenceEnd + 1) : firstLine;
|
|
631
|
+
if (raw.length <= 80) return raw;
|
|
632
|
+
const truncated = raw.slice(0, 80).replace(/\s+\S*$/, "");
|
|
633
|
+
return truncated + "...";
|
|
634
|
+
}
|
|
617
635
|
|
|
618
636
|
// src/social/twitter.ts
|
|
619
637
|
var TwitterAdapter = class extends SocialAdapter {
|
|
@@ -794,6 +812,7 @@ var Agent = class {
|
|
|
794
812
|
if (this.hooks.onInit) {
|
|
795
813
|
await this.hooks.onInit(this);
|
|
796
814
|
}
|
|
815
|
+
await this.postStartupMessages();
|
|
797
816
|
logger4.info(`Agent initialized: ${this.config.name}`);
|
|
798
817
|
}
|
|
799
818
|
async start() {
|
|
@@ -924,40 +943,114 @@ var Agent = class {
|
|
|
924
943
|
}
|
|
925
944
|
async initSocialAdapters() {
|
|
926
945
|
const { social } = this.config;
|
|
946
|
+
const configuredPlatforms = Object.keys(social).filter(
|
|
947
|
+
(k) => social[k] && typeof social[k] === "object"
|
|
948
|
+
);
|
|
949
|
+
if (configuredPlatforms.length === 0) {
|
|
950
|
+
logger4.warn("Social: No platforms configured. To post on startup, add a social platform to your config.");
|
|
951
|
+
logger4.warn(' Code-based: Add a moltbook or twitter section to agent.config.ts under "social".');
|
|
952
|
+
logger4.warn(' Markdown: Add a "### Moltbook" section under "## Social Platforms" in agent.md with "enabled: true".');
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
logger4.info(`Social: Found platforms in config: ${configuredPlatforms.join(", ")}`);
|
|
927
956
|
if (social.moltbook?.enabled) {
|
|
957
|
+
const baseUrl = social.moltbook.baseUrl || "https://www.moltbook.com/api/v1";
|
|
928
958
|
if (!social.moltbook.apiKey || social.moltbook.apiKey === "your-moltbook-key-here") {
|
|
929
|
-
logger4.error("Moltbook
|
|
959
|
+
logger4.error("Moltbook: SKIPPED \u2014 MOLTBOOK_API_KEY is missing or still a placeholder.");
|
|
960
|
+
logger4.error(" Fix: Set a valid MOLTBOOK_API_KEY in your .env file.");
|
|
930
961
|
} else {
|
|
962
|
+
logger4.info(`Moltbook: Connecting to ${baseUrl} ...`);
|
|
931
963
|
const adapter = new MoltbookAdapter(social.moltbook);
|
|
932
964
|
try {
|
|
933
965
|
await adapter.connect();
|
|
934
966
|
this.socialAdapters["moltbook"] = adapter;
|
|
935
|
-
logger4.info("Moltbook
|
|
967
|
+
logger4.info("Moltbook: Connected successfully (GET /agents/me OK)");
|
|
936
968
|
} catch (error) {
|
|
937
|
-
logger4.error(`
|
|
938
|
-
|
|
939
|
-
logger4.error(` HTTP ${error.response.status}: ${JSON.stringify(error.response.data)}`);
|
|
940
|
-
}
|
|
969
|
+
logger4.error(`Moltbook: Connection FAILED \u2014 ${error.message || error}`);
|
|
970
|
+
this.logPlatformError("Moltbook", error);
|
|
941
971
|
}
|
|
942
972
|
}
|
|
973
|
+
} else if (social.moltbook) {
|
|
974
|
+
logger4.warn('Moltbook: Present in config but disabled (enabled: false). Set "enabled: true" to activate.');
|
|
943
975
|
}
|
|
944
976
|
if (social.twitter?.enabled) {
|
|
945
977
|
const creds = social.twitter.credentials;
|
|
946
978
|
if (!creds?.apiKey || creds.apiKey === "your-twitter-api-key") {
|
|
947
|
-
logger4.error("Twitter
|
|
979
|
+
logger4.error("Twitter: SKIPPED \u2014 credentials are missing or still placeholders.");
|
|
980
|
+
logger4.error(" Fix: Set valid Twitter keys in your .env file.");
|
|
948
981
|
} else {
|
|
982
|
+
logger4.info("Twitter: Connecting...");
|
|
949
983
|
const adapter = new TwitterAdapter(social.twitter);
|
|
950
984
|
try {
|
|
951
985
|
await adapter.connect();
|
|
952
986
|
this.socialAdapters["twitter"] = adapter;
|
|
953
|
-
logger4.info("Twitter
|
|
987
|
+
logger4.info("Twitter: Connected successfully");
|
|
954
988
|
} catch (error) {
|
|
955
|
-
logger4.error(`
|
|
956
|
-
|
|
957
|
-
logger4.error(` HTTP ${error.response.status}: ${JSON.stringify(error.response.data)}`);
|
|
958
|
-
}
|
|
989
|
+
logger4.error(`Twitter: Connection FAILED \u2014 ${error.message || error}`);
|
|
990
|
+
this.logPlatformError("Twitter", error);
|
|
959
991
|
}
|
|
960
992
|
}
|
|
993
|
+
} else if (social.twitter) {
|
|
994
|
+
logger4.warn('Twitter: Present in config but disabled (enabled: false). Set "enabled: true" to activate.');
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
async postStartupMessages() {
|
|
998
|
+
const adapters = Object.entries(this.socialAdapters);
|
|
999
|
+
if (adapters.length === 0) {
|
|
1000
|
+
logger4.info("Startup post: No connected social adapters \u2014 skipping");
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
const content = `${this.config.name} is now online and ready.`;
|
|
1004
|
+
for (const [platform, adapter] of adapters) {
|
|
1005
|
+
logger4.info(`Startup post: Posting to ${platform}...`);
|
|
1006
|
+
try {
|
|
1007
|
+
const result = await adapter.post(content);
|
|
1008
|
+
logger4.info(`Startup post: ${platform} SUCCESS \u2014 id=${result.id}${result.url ? ` url=${result.url}` : ""}`);
|
|
1009
|
+
} catch (error) {
|
|
1010
|
+
logger4.error(`Startup post: ${platform} FAILED \u2014 ${error.message || error}`);
|
|
1011
|
+
this.logPlatformError(platform, error);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
logPlatformError(platform, error) {
|
|
1016
|
+
if (!error.response) {
|
|
1017
|
+
if (error.code === "ENOTFOUND") {
|
|
1018
|
+
logger4.error(` ${platform}: DNS lookup failed \u2014 check the base URL.`);
|
|
1019
|
+
} else if (error.code === "ECONNREFUSED") {
|
|
1020
|
+
logger4.error(` ${platform}: Connection refused \u2014 is the server running?`);
|
|
1021
|
+
} else if (error.code === "ETIMEDOUT" || error.code === "ECONNABORTED") {
|
|
1022
|
+
logger4.error(` ${platform}: Request timed out.`);
|
|
1023
|
+
} else {
|
|
1024
|
+
logger4.error(` ${platform}: Network error (${error.code || "unknown"})`);
|
|
1025
|
+
}
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
const status = error.response.status;
|
|
1029
|
+
const data = error.response.data;
|
|
1030
|
+
logger4.error(` ${platform}: HTTP ${status}`);
|
|
1031
|
+
if (data) {
|
|
1032
|
+
if (data.error) logger4.error(` ${platform}: API error: ${data.error}`);
|
|
1033
|
+
if (data.hint) logger4.error(` ${platform}: API hint: ${data.hint}`);
|
|
1034
|
+
if (!data.error && !data.hint) logger4.error(` ${platform}: Response: ${JSON.stringify(data)}`);
|
|
1035
|
+
}
|
|
1036
|
+
if (status === 401) {
|
|
1037
|
+
logger4.error(` ${platform}: Your API key was rejected. Verify it is correct and the agent is claimed.`);
|
|
1038
|
+
} else if (status === 403) {
|
|
1039
|
+
logger4.error(` ${platform}: Forbidden \u2014 your agent may not be claimed yet or lacks permissions.`);
|
|
1040
|
+
} else if (status === 429) {
|
|
1041
|
+
const retryMin = data?.retry_after_minutes;
|
|
1042
|
+
const retrySec = data?.retry_after_seconds;
|
|
1043
|
+
if (retryMin) {
|
|
1044
|
+
logger4.error(` ${platform}: Rate limited \u2014 try again in ${retryMin} minute(s).`);
|
|
1045
|
+
} else if (retrySec) {
|
|
1046
|
+
logger4.error(` ${platform}: Rate limited \u2014 try again in ${retrySec} second(s).`);
|
|
1047
|
+
} else {
|
|
1048
|
+
logger4.error(` ${platform}: Rate limited \u2014 wait before retrying.`);
|
|
1049
|
+
}
|
|
1050
|
+
} else if (status === 404) {
|
|
1051
|
+
logger4.error(` ${platform}: Endpoint not found \u2014 check the base URL.`);
|
|
1052
|
+
} else if (status >= 500) {
|
|
1053
|
+
logger4.error(` ${platform}: Server error \u2014 the platform may be temporarily down.`);
|
|
961
1054
|
}
|
|
962
1055
|
}
|
|
963
1056
|
startAutonomousLoop() {
|
|
@@ -1097,8 +1190,10 @@ var MarkdownParser = class {
|
|
|
1097
1190
|
for (const child of section.children) {
|
|
1098
1191
|
const platform = child.title.toLowerCase();
|
|
1099
1192
|
const fields = this.parseKeyValueLines(child.content);
|
|
1193
|
+
const enabled = fields["enabled"] === "true";
|
|
1194
|
+
delete fields["enabled"];
|
|
1100
1195
|
social[platform] = {
|
|
1101
|
-
enabled
|
|
1196
|
+
enabled,
|
|
1102
1197
|
...fields
|
|
1103
1198
|
};
|
|
1104
1199
|
}
|
|
@@ -1528,6 +1623,13 @@ function createRoutes(agent) {
|
|
|
1528
1623
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1529
1624
|
});
|
|
1530
1625
|
});
|
|
1626
|
+
router.get("/message", (_req, res) => {
|
|
1627
|
+
res.status(405).json({
|
|
1628
|
+
error: "Method Not Allowed",
|
|
1629
|
+
message: "Use POST /message to send a message to the agent.",
|
|
1630
|
+
expected_body: { message: "string" }
|
|
1631
|
+
});
|
|
1632
|
+
});
|
|
1531
1633
|
router.post("/message", async (req, res) => {
|
|
1532
1634
|
try {
|
|
1533
1635
|
const { message } = req.body;
|
|
@@ -1544,6 +1646,13 @@ function createRoutes(agent) {
|
|
|
1544
1646
|
res.status(500).json({ error: error instanceof Error ? error.message : "Unknown error" });
|
|
1545
1647
|
}
|
|
1546
1648
|
});
|
|
1649
|
+
router.get("/action", (_req, res) => {
|
|
1650
|
+
res.status(405).json({
|
|
1651
|
+
error: "Method Not Allowed",
|
|
1652
|
+
message: "Use POST /action to trigger an action.",
|
|
1653
|
+
expected_body: { action: "string", parameters: "{}" }
|
|
1654
|
+
});
|
|
1655
|
+
});
|
|
1547
1656
|
router.post("/action", async (req, res) => {
|
|
1548
1657
|
try {
|
|
1549
1658
|
const { action, parameters } = req.body;
|