+6
main.ts
+6
main.ts
···
1
import { logStats } from "./tasks/logStats.ts";
2
import { msFrom, msRandomOffset, msUntilDailyWindow } from "./utils/time.ts";
3
import { sendSleepMessage } from "./tasks/sendSleepMessage.ts";
4
import { sendWakeMessage } from "./tasks/sendWakeMessage.ts";
···
8
import { checkNotifications } from "./tasks/checkNotifications.ts";
9
10
setTimeout(logStats, msRandomOffset(msFrom.minutes(1), msFrom.minutes(5)));
11
setTimeout(
12
sendSleepMessage,
13
msUntilDailyWindow(agentContext.sleepTime, 0, msFrom.minutes(20)),
···
1
import { logStats } from "./tasks/logStats.ts";
2
+
import { logTasks } from "./tasks/logTasks.ts";
3
import { msFrom, msRandomOffset, msUntilDailyWindow } from "./utils/time.ts";
4
import { sendSleepMessage } from "./tasks/sendSleepMessage.ts";
5
import { sendWakeMessage } from "./tasks/sendWakeMessage.ts";
···
9
import { checkNotifications } from "./tasks/checkNotifications.ts";
10
11
setTimeout(logStats, msRandomOffset(msFrom.minutes(1), msFrom.minutes(5)));
12
+
13
+
setTimeout(
14
+
logTasks,
15
+
msRandomOffset(msFrom.minutes(30), msFrom.minutes(60)),
16
+
);
17
setTimeout(
18
sendSleepMessage,
19
msUntilDailyWindow(agentContext.sleepTime, 0, msFrom.minutes(20)),
+7
-5
tasks/checkBluesky.ts
+7
-5
tasks/checkBluesky.ts
···
16
const newDelay = msRandomOffset(msFrom.minutes(5), msFrom.minutes(10));
17
18
console.log(
19
-
`${agentContext.agentBskyName} is busy, will try checking bluesky again in ${
20
newDelay * 60 * 1000
21
} minutes…`,
22
);
···
27
28
if (!agentContext.proactiveEnabled) {
29
console.log(
30
-
`proactively checking bluesky is disabled. Provide a minimum and/or maximum delay in \`.env\` to enable this task…`,
31
);
32
releaseTaskThread();
33
return;
···
43
if (delay !== 0) {
44
setTimeout(checkBluesky, delay);
45
console.log(
46
-
`${agentContext.agentBskyName} is current asleep. scheduling next bluesky session for ${
47
(delay / 1000 / 60 / 60).toFixed(2)
48
} hours from now…`,
49
);
···
53
54
try {
55
const prompt = checkBlueskyPrompt;
56
-
console.log("starting a proactive bluesky session…");
57
await messageAgent(prompt);
58
} catch (error) {
59
console.error("error in checkBluesky:", error);
60
} finally {
61
-
console.log("finished proactive bluesky session. waiting for new tasks…");
62
agentContext.proactiveCount++;
63
// schedules next proactive bluesky session
64
setTimeout(
···
16
const newDelay = msRandomOffset(msFrom.minutes(5), msFrom.minutes(10));
17
18
console.log(
19
+
`🔹 ${agentContext.agentBskyName} is busy, will try checking bluesky again in ${
20
newDelay * 60 * 1000
21
} minutes…`,
22
);
···
27
28
if (!agentContext.proactiveEnabled) {
29
console.log(
30
+
`🔹 proactively checking bluesky is disabled. Provide a minimum and/or maximum delay in \`.env\` to enable this task…`,
31
);
32
releaseTaskThread();
33
return;
···
43
if (delay !== 0) {
44
setTimeout(checkBluesky, delay);
45
console.log(
46
+
`🔹 ${agentContext.agentBskyName} is current asleep. scheduling next bluesky session for ${
47
(delay / 1000 / 60 / 60).toFixed(2)
48
} hours from now…`,
49
);
···
53
54
try {
55
const prompt = checkBlueskyPrompt;
56
+
console.log("🔹 starting a proactive bluesky session…");
57
await messageAgent(prompt);
58
} catch (error) {
59
console.error("error in checkBluesky:", error);
60
} finally {
61
+
console.log(
62
+
"🔹 finished proactive bluesky session. waiting for new tasks…",
63
+
);
64
agentContext.proactiveCount++;
65
// schedules next proactive bluesky session
66
setTimeout(
+7
-5
tasks/checkNotifications.ts
+7
-5
tasks/checkNotifications.ts
···
15
if (!claimTaskThread()) {
16
const newDelay = msRandomOffset(msFrom.minutes(5), msFrom.minutes(10));
17
console.log(
18
-
`${agentContext.agentBskyName} is busy, checking for notifications again in ${
19
(newDelay * 1000) * 60
20
} minutes…`,
21
);
···
32
if (delay !== 0) {
33
setTimeout(checkNotifications, delay);
34
console.log(
35
-
`${agentContext.agentBskyName} is current asleep. scheduling next notification check for ${
36
(delay / 1000 / 60 / 60).toFixed(2)
37
} hours from now…`,
38
);
···
54
55
if (unreadNotifications.length > 0) {
56
console.log(
57
-
`found ${unreadNotifications.length} notification(s), processing…`,
58
);
59
60
// resets delay for future notification checks since
···
69
let notificationCounter = 1;
70
for (const notification of unreadNotifications) {
71
console.log(
72
-
`processing notification #${notificationCounter} [${notification.reason} from @${notification.author.handle}]`,
73
);
74
await processNotification(notification);
75
notificationCounter++;
···
90
));
91
92
console.log(
93
-
"no notifications…",
94
`checking again in ${
95
(agentContext.notifDelayCurrent / 1000).toFixed(2)
96
} seconds`,
···
101
// since something went wrong, lets check for notifications again sooner
102
agentContext.notifDelayCurrent = agentContext.notifDelayMinimum;
103
} finally {
104
// actually schedules next time to check for notifications
105
setTimeout(checkNotifications, agentContext.notifDelayCurrent);
106
// ends work
···
15
if (!claimTaskThread()) {
16
const newDelay = msRandomOffset(msFrom.minutes(5), msFrom.minutes(10));
17
console.log(
18
+
`🔹 ${agentContext.agentBskyName} is busy, checking for notifications again in ${
19
(newDelay * 1000) * 60
20
} minutes…`,
21
);
···
32
if (delay !== 0) {
33
setTimeout(checkNotifications, delay);
34
console.log(
35
+
`🔹 ${agentContext.agentBskyName} is current asleep. scheduling next notification check for ${
36
(delay / 1000 / 60 / 60).toFixed(2)
37
} hours from now…`,
38
);
···
54
55
if (unreadNotifications.length > 0) {
56
console.log(
57
+
`🔹 found ${unreadNotifications.length} notification(s), processing…`,
58
);
59
60
// resets delay for future notification checks since
···
69
let notificationCounter = 1;
70
for (const notification of unreadNotifications) {
71
console.log(
72
+
`🔹 processing notification #${notificationCounter} of #${unreadNotifications.length} [${notification.reason} from @${notification.author.handle}]`,
73
);
74
await processNotification(notification);
75
notificationCounter++;
···
90
));
91
92
console.log(
93
+
"🔹 no notifications…",
94
`checking again in ${
95
(agentContext.notifDelayCurrent / 1000).toFixed(2)
96
} seconds`,
···
101
// since something went wrong, lets check for notifications again sooner
102
agentContext.notifDelayCurrent = agentContext.notifDelayMinimum;
103
} finally {
104
+
// increment check count
105
+
agentContext.checkCount++;
106
// actually schedules next time to check for notifications
107
setTimeout(checkNotifications, agentContext.notifDelayCurrent);
108
// ends work
+74
-33
tasks/logStats.ts
+74
-33
tasks/logStats.ts
···
11
12
export const logStats = () => {
13
if (!claimTaskThread()) {
14
-
const newDelay = msRandomOffset(msFrom.minutes(5), msFrom.minutes(10));
15
console.log(
16
-
`${agentContext.agentBskyName} is busy, attempting to log counts again in ${
17
(newDelay / 1000) / 60
18
} minutes…`,
19
);
20
// session is busy, logging stats in 5~10 minutes.
21
setTimeout(logStats, newDelay);
22
-
return;
23
-
}
24
-
25
-
if (!agentContext.reflectionEnabled) {
26
-
console.log(
27
-
`${agentContext.agentBskyName} reflection is disabled, skipping logStats…`,
28
-
);
29
-
releaseTaskThread();
30
return;
31
}
32
···
46
return;
47
}
48
49
-
console.log(
50
-
`
51
-
===
52
-
# current session interaction counts since last reflection:
53
-
${agentContext.likeCount} ${
54
-
agentContext.likeCount === 1 ? "like" : "likes"
55
-
}, ${agentContext.repostCount} ${
56
-
agentContext.repostCount === 1 ? "repost" : "reposts"
57
-
}, ${agentContext.followCount} ${
58
-
agentContext.followCount === 1 ? "new follower" : "new followers"
59
-
}, ${agentContext.mentionCount} ${
60
-
agentContext.mentionCount === 1 ? "mention" : "mentions"
61
-
}, ${agentContext.replyCount} ${
62
-
agentContext.replyCount === 1 ? "reply" : "replies"
63
-
}, and ${agentContext.quoteCount} ${
64
-
agentContext.quoteCount === 1 ? "quote" : "quotes"
65
-
}.
66
67
-
${agentContext.agentBskyName} has reflected ${agentContext.reflectionCount} time${
68
-
agentContext.reflectionCount > 0 ? "s" : ""
69
-
} since last server start. interaction counts reset after each reflection session.
70
-
===
71
-
`,
72
);
73
-
setTimeout(logStats, msRandomOffset(msFrom.minutes(5), msFrom.minutes(15)));
74
releaseTaskThread();
75
};
···
11
12
export const logStats = () => {
13
if (!claimTaskThread()) {
14
+
const newDelay = msFrom.minutes(2);
15
console.log(
16
+
`Stat log attempt failed, ${agentContext.agentBskyName} is busy. Next attempt in ${
17
(newDelay / 1000) / 60
18
} minutes…`,
19
);
20
// session is busy, logging stats in 5~10 minutes.
21
setTimeout(logStats, newDelay);
22
return;
23
}
24
···
38
return;
39
}
40
41
+
// Check if there are any notifications
42
+
const totalNotifications = agentContext.mentionCount +
43
+
agentContext.likeCount +
44
+
agentContext.repostCount +
45
+
agentContext.quoteCount +
46
+
agentContext.replyCount +
47
+
agentContext.followCount;
48
49
+
const nextCheckDelay = msRandomOffset(
50
+
msFrom.minutes(5),
51
+
msFrom.minutes(15),
52
);
53
+
const nextCheckMinutes = ((nextCheckDelay / 1000) / 60).toFixed(1);
54
+
55
+
if (totalNotifications <= 0) {
56
+
console.log(
57
+
`no engagement stats yet... next check in ${nextCheckMinutes} minutes…`,
58
+
);
59
+
} else {
60
+
const counts = [];
61
+
62
+
if (agentContext.mentionCount > 0) {
63
+
counts.push(
64
+
`${agentContext.mentionCount} ${
65
+
agentContext.mentionCount === 1 ? "mention" : "mentions"
66
+
}`,
67
+
);
68
+
}
69
+
if (agentContext.likeCount > 0) {
70
+
counts.push(
71
+
`${agentContext.likeCount} ${
72
+
agentContext.likeCount === 1 ? "like" : "likes"
73
+
}`,
74
+
);
75
+
}
76
+
if (agentContext.repostCount > 0) {
77
+
counts.push(
78
+
`${agentContext.repostCount} ${
79
+
agentContext.repostCount === 1 ? "repost" : "reposts"
80
+
}`,
81
+
);
82
+
}
83
+
if (agentContext.quoteCount > 0) {
84
+
counts.push(
85
+
`${agentContext.quoteCount} ${
86
+
agentContext.quoteCount === 1 ? "quote" : "quotes"
87
+
}`,
88
+
);
89
+
}
90
+
if (agentContext.replyCount > 0) {
91
+
counts.push(
92
+
`${agentContext.replyCount} ${
93
+
agentContext.replyCount === 1 ? "reply" : "replies"
94
+
}`,
95
+
);
96
+
}
97
+
if (agentContext.followCount > 0) {
98
+
counts.push(
99
+
`${agentContext.followCount} new ${
100
+
agentContext.followCount === 1 ? "follower" : "followers"
101
+
}`,
102
+
);
103
+
}
104
+
105
+
const message = counts.join(", ");
106
+
const suffix = agentContext.reflectionEnabled
107
+
? " since last reflection"
108
+
: "";
109
+
console.log(
110
+
`
111
+
stats: ${message}${suffix}. next check in ${nextCheckMinutes} minutes…`,
112
+
);
113
+
}
114
+
setTimeout(logStats, nextCheckDelay);
115
releaseTaskThread();
116
};
+99
tasks/logTasks.ts
+99
tasks/logTasks.ts
···
···
1
+
import {
2
+
agentContext,
3
+
claimTaskThread,
4
+
releaseTaskThread,
5
+
} from "../utils/agentContext.ts";
6
+
import {
7
+
formatUptime,
8
+
msFrom,
9
+
msRandomOffset,
10
+
msUntilNextWakeWindow,
11
+
} from "../utils/time.ts";
12
+
13
+
// Capture server start time when module is loaded
14
+
const serverStartTime = Date.now();
15
+
16
+
export const logTasks = () => {
17
+
if (!claimTaskThread()) {
18
+
const newDelay = msFrom.minutes(2);
19
+
console.log(
20
+
`🔹 Task log attempt failed, ${agentContext.agentBskyName} is busy. Next attempt in ${
21
+
(newDelay / 1000) / 60
22
+
} minutes…`,
23
+
);
24
+
setTimeout(logTasks, newDelay);
25
+
return;
26
+
}
27
+
28
+
const delay = msUntilNextWakeWindow(
29
+
msFrom.minutes(30),
30
+
msFrom.hours(1),
31
+
);
32
+
33
+
if (delay !== 0) {
34
+
setTimeout(logTasks, delay);
35
+
console.log(
36
+
`🔹 ${agentContext.agentBskyName} is current asleep. scheduling next task log for ${
37
+
(delay / 1000 / 60 / 60).toFixed(2)
38
+
} hours from now…`,
39
+
);
40
+
releaseTaskThread();
41
+
return;
42
+
}
43
+
44
+
// Check if there's any activity
45
+
const totalActivity = agentContext.reflectionCount +
46
+
agentContext.checkCount +
47
+
agentContext.processingCount +
48
+
agentContext.proactiveCount;
49
+
50
+
const uptime = Date.now() - serverStartTime;
51
+
const uptimeFormatted = formatUptime(uptime);
52
+
53
+
const nextCheckDelay = msRandomOffset(
54
+
msFrom.minutes(30),
55
+
msFrom.hours(1),
56
+
);
57
+
const nextCheckMinutes = ((nextCheckDelay / 1000) / 60).toFixed(1);
58
+
59
+
if (totalActivity <= 0) {
60
+
console.log(
61
+
`🔹 no activity yet... uptime: ${uptimeFormatted}. next log in ${nextCheckMinutes} minutes`,
62
+
);
63
+
} else {
64
+
const actions = [];
65
+
66
+
if (agentContext.reflectionCount > 0) {
67
+
const times = agentContext.reflectionCount === 1
68
+
? "once"
69
+
: `${agentContext.reflectionCount} times`;
70
+
actions.push(`reflected ${times}`);
71
+
}
72
+
if (agentContext.checkCount > 0) {
73
+
const times = agentContext.checkCount === 1
74
+
? "once"
75
+
: `${agentContext.checkCount} times`;
76
+
actions.push(`checked notifications ${times}`);
77
+
}
78
+
if (agentContext.processingCount > 0) {
79
+
const times = agentContext.processingCount === 1
80
+
? "once"
81
+
: `${agentContext.processingCount} times`;
82
+
actions.push(`found and processed notifications ${times}`);
83
+
}
84
+
if (agentContext.proactiveCount > 0) {
85
+
const times = agentContext.proactiveCount === 1
86
+
? "once"
87
+
: `${agentContext.proactiveCount} times`;
88
+
actions.push(`proactively used bluesky ${times}`);
89
+
}
90
+
91
+
const message = actions.join(", ");
92
+
console.log(
93
+
`🔹 ${message}. uptime: ${uptimeFormatted}. next log in ${nextCheckMinutes} minutes`,
94
+
);
95
+
}
96
+
97
+
setTimeout(logTasks, nextCheckDelay);
98
+
releaseTaskThread();
99
+
};
+5
-5
tasks/runReflection.ts
+5
-5
tasks/runReflection.ts
···
17
const newDelay = msRandomOffset(msFrom.minutes(5), msFrom.minutes(10));
18
19
console.log(
20
-
`${agentContext.agentBskyName} is busy, will try reflecting again in ${
21
(newDelay / 1000) / 60
22
} minutes…`,
23
);
···
28
29
if (!agentContext.reflectionEnabled) {
30
console.log(
31
-
`Reflection is currently disabled. Provide a minimum and/or maximum delay duration in \`.env\` to enable reflections…`,
32
);
33
releaseTaskThread();
34
return;
···
44
if (delay !== 0) {
45
setTimeout(runReflection, delay);
46
console.log(
47
-
`${agentContext.agentBskyName} is current asleep. scheduling next reflection for ${
48
(delay / 1000 / 60 / 60).toFixed(2)
49
} hours from now…`,
50
);
···
53
}
54
55
try {
56
-
console.log("starting reflection prompt…");
57
await messageAgent(reflectionPrompt);
58
} catch (error) {
59
console.error("Error in reflectionCheck:", error);
···
61
resetAgentContextCounts();
62
agentContext.reflectionCount++;
63
console.log(
64
-
"finished reflection prompt. returning to checking for notifications…",
65
);
66
// schedules the next reflection, random between the min and max delay
67
setTimeout(
···
17
const newDelay = msRandomOffset(msFrom.minutes(5), msFrom.minutes(10));
18
19
console.log(
20
+
`🔹 ${agentContext.agentBskyName} is busy, will try reflecting again in ${
21
(newDelay / 1000) / 60
22
} minutes…`,
23
);
···
28
29
if (!agentContext.reflectionEnabled) {
30
console.log(
31
+
`🔹 Reflection is currently disabled. Provide a minimum and/or maximum delay duration in \`.env\` to enable reflections…`,
32
);
33
releaseTaskThread();
34
return;
···
44
if (delay !== 0) {
45
setTimeout(runReflection, delay);
46
console.log(
47
+
`🔹 ${agentContext.agentBskyName} is current asleep. scheduling next reflection for ${
48
(delay / 1000 / 60 / 60).toFixed(2)
49
} hours from now…`,
50
);
···
53
}
54
55
try {
56
+
console.log("🔹 starting reflection prompt…");
57
await messageAgent(reflectionPrompt);
58
} catch (error) {
59
console.error("Error in reflectionCheck:", error);
···
61
resetAgentContextCounts();
62
agentContext.reflectionCount++;
63
console.log(
64
+
"🔹 finished reflection prompt. returning to checking for notifications…",
65
);
66
// schedules the next reflection, random between the min and max delay
67
setTimeout(
+5
-5
tasks/sendSleepMessage.ts
+5
-5
tasks/sendSleepMessage.ts
···
16
if (!claimTaskThread()) {
17
const newDelay = msRandomOffset(msFrom.minutes(5), msFrom.minutes(10));
18
console.log(
19
-
`${agentContext.agentBskyName} is busy, sending sleep message again in ${
20
(newDelay / 1000) / 60
21
} minutes…`,
22
);
···
27
28
if (!agentContext.sleepEnabled) {
29
console.log(
30
-
`${agentContext.agentBskyName} is not enabled for sleep mode. Opting out of sleep messaging…`,
31
);
32
releaseTaskThread();
33
return;
···
36
const now = getNow();
37
38
if (now.hour >= agentContext.sleepTime) {
39
-
console.log(`attempting to wind down ${agentContext.agentBskyName}`);
40
} else {
41
const delay = msUntilDailyWindow(
42
agentContext.sleepTime,
···
45
);
46
setTimeout(sendSleepMessage, delay);
47
console.log(
48
-
`It's too early to wind down ${agentContext.agentBskyName}. scheduling wind down for ${
49
(delay / 1000 / 60 / 60).toFixed(2)
50
} hours from now…`,
51
);
···
58
} catch (error) {
59
console.error("error in sendSleepMessage: ", error);
60
} finally {
61
-
console.log("wind down attempt processed, scheduling next wind down…");
62
setTimeout(
63
sendSleepMessage,
64
msUntilDailyWindow(agentContext.sleepTime, 0, msFrom.minutes(20)),
···
16
if (!claimTaskThread()) {
17
const newDelay = msRandomOffset(msFrom.minutes(5), msFrom.minutes(10));
18
console.log(
19
+
`🔹 ${agentContext.agentBskyName} is busy, sending sleep message again in ${
20
(newDelay / 1000) / 60
21
} minutes…`,
22
);
···
27
28
if (!agentContext.sleepEnabled) {
29
console.log(
30
+
`🔹 ${agentContext.agentBskyName} is not enabled for sleep mode. Opting out of sleep messaging…`,
31
);
32
releaseTaskThread();
33
return;
···
36
const now = getNow();
37
38
if (now.hour >= agentContext.sleepTime) {
39
+
console.log(`🔹 attempting to wind down ${agentContext.agentBskyName}`);
40
} else {
41
const delay = msUntilDailyWindow(
42
agentContext.sleepTime,
···
45
);
46
setTimeout(sendSleepMessage, delay);
47
console.log(
48
+
`🔹 It's too early to wind down ${agentContext.agentBskyName}. scheduling wind down for ${
49
(delay / 1000 / 60 / 60).toFixed(2)
50
} hours from now…`,
51
);
···
58
} catch (error) {
59
console.error("error in sendSleepMessage: ", error);
60
} finally {
61
+
console.log("🔹 wind down attempt processed, scheduling next wind down…");
62
setTimeout(
63
sendSleepMessage,
64
msUntilDailyWindow(agentContext.sleepTime, 0, msFrom.minutes(20)),
+6
-6
tasks/sendWakeMessage.ts
+6
-6
tasks/sendWakeMessage.ts
···
12
if (!claimTaskThread()) {
13
const newDelay = msRandomOffset(msFrom.minutes(5), msFrom.minutes(10));
14
console.log(
15
-
`${agentContext.agentBskyName} is busy, sending wake message again in ${
16
(newDelay / 1000) / 60
17
} minutes…`,
18
);
···
23
24
if (!agentContext.sleepEnabled) {
25
console.log(
26
-
`${agentContext.agentBskyName} is not enabled for sleep mode. Opting out of wake messaging…`,
27
);
28
releaseTaskThread();
29
return;
···
32
const now = getNow();
33
34
if (now.hour >= agentContext.wakeTime && now.hour < agentContext.sleepTime) {
35
-
console.log(`attempting to wake up ${agentContext.agentBskyName}`);
36
} else {
37
const delay = msUntilDailyWindow(
38
agentContext.wakeTime,
···
41
);
42
setTimeout(sendWakeMessage, delay);
43
console.log(
44
-
`${agentContext.agentBskyName} should still be asleep. Scheduling wake message for ${
45
(delay / 1000 / 60 / 60).toFixed(2)
46
} hours from now…`,
47
);
···
54
} catch (error) {
55
console.error("error in sendWakeMessage: ", error);
56
} finally {
57
-
console.log("wake attempt processed, scheduling next wake prompt…");
58
setTimeout(
59
sendWakeMessage,
60
msUntilDailyWindow(agentContext.wakeTime, 0, msFrom.minutes(80)),
61
);
62
-
console.log("exiting wake process");
63
releaseTaskThread();
64
}
65
};
···
12
if (!claimTaskThread()) {
13
const newDelay = msRandomOffset(msFrom.minutes(5), msFrom.minutes(10));
14
console.log(
15
+
`🔹 ${agentContext.agentBskyName} is busy, sending wake message again in ${
16
(newDelay / 1000) / 60
17
} minutes…`,
18
);
···
23
24
if (!agentContext.sleepEnabled) {
25
console.log(
26
+
`🔹 ${agentContext.agentBskyName} is not enabled for sleep mode. Opting out of wake messaging…`,
27
);
28
releaseTaskThread();
29
return;
···
32
const now = getNow();
33
34
if (now.hour >= agentContext.wakeTime && now.hour < agentContext.sleepTime) {
35
+
console.log(`🔹 attempting to wake up ${agentContext.agentBskyName}`);
36
} else {
37
const delay = msUntilDailyWindow(
38
agentContext.wakeTime,
···
41
);
42
setTimeout(sendWakeMessage, delay);
43
console.log(
44
+
`🔹 ${agentContext.agentBskyName} should still be asleep. Scheduling wake message for ${
45
(delay / 1000 / 60 / 60).toFixed(2)
46
} hours from now…`,
47
);
···
54
} catch (error) {
55
console.error("error in sendWakeMessage: ", error);
56
} finally {
57
+
console.log("🔹 wake attempt processed, scheduling next wake prompt…");
58
setTimeout(
59
sendWakeMessage,
60
msUntilDailyWindow(agentContext.wakeTime, 0, msFrom.minutes(80)),
61
);
62
+
console.log("🔹 exiting wake process");
63
releaseTaskThread();
64
}
65
};
+5
-5
utils/agentContext.ts
+5
-5
utils/agentContext.ts
···
522
for (const service of services) {
523
if (service.length > 200) {
524
throw Error(
525
-
`External service name too long: "${service.substring(0, 50)}..." (max 200 characters)`,
526
);
527
}
528
}
···
538
};
539
540
const populateAgentContext = async (): Promise<agentContextObject> => {
541
-
console.log("building new agentContext object…");
542
const context: agentContextObject = {
543
// state
544
busy: false,
···
602
context.externalServices = externalServices;
603
}
604
console.log(
605
-
`\`agentContext\` object built for ${context.agentBskyName}, BEGIN TASK…`,
606
);
607
return context;
608
};
···
626
agentContext.mentionCount = 0;
627
agentContext.replyCount = 0;
628
agentContext.quoteCount = 0;
629
-
agentContext.checkCount = 0;
630
-
agentContext.processingCount = 0;
631
};
···
522
for (const service of services) {
523
if (service.length > 200) {
524
throw Error(
525
+
`External service name too long: "${
526
+
service.substring(0, 50)
527
+
}..." (max 200 characters)`,
528
);
529
}
530
}
···
540
};
541
542
const populateAgentContext = async (): Promise<agentContextObject> => {
543
+
console.log("🔹 building new agentContext object…");
544
const context: agentContextObject = {
545
// state
546
busy: false,
···
604
context.externalServices = externalServices;
605
}
606
console.log(
607
+
`🔹 \`agentContext\` object built for ${context.agentBskyName}, BEGINING TASKS…`,
608
);
609
return context;
610
};
···
628
agentContext.mentionCount = 0;
629
agentContext.replyCount = 0;
630
agentContext.quoteCount = 0;
631
};
+5
-3
utils/declaration.ts
+5
-3
utils/declaration.ts
···
149
rkey: "self",
150
});
151
exists = true;
152
-
console.log("Existing autonomy declaration found - updating...");
153
} catch (error: any) {
154
// Handle "record not found" errors (status 400 with error: "RecordNotFound")
155
const isNotFound =
···
159
error?.message?.includes("Could not locate record");
160
161
if (isNotFound) {
162
-
console.log("No existing autonomy declaration found - creating new...");
163
} else {
164
// Re-throw if it's not a "not found" error
165
throw error;
···
175
});
176
177
console.log(
178
-
`Autonomy declaration ${exists ? "updated" : "created"} successfully:`,
179
result,
180
);
181
return result;
···
149
rkey: "self",
150
});
151
exists = true;
152
+
console.log("🔹 Existing autonomy declaration found - updating...");
153
} catch (error: any) {
154
// Handle "record not found" errors (status 400 with error: "RecordNotFound")
155
const isNotFound =
···
159
error?.message?.includes("Could not locate record");
160
161
if (isNotFound) {
162
+
console.log(
163
+
"🔹 No existing autonomy declaration found - creating new...",
164
+
);
165
} else {
166
// Re-throw if it's not a "not found" error
167
throw error;
···
177
});
178
179
console.log(
180
+
`🔹 Autonomy declaration ${exists ? "updated" : "created"} successfully:`,
181
result,
182
);
183
return result;
+3
-3
utils/messageAgent.ts
+3
-3
utils/messageAgent.ts
···
21
};
22
23
// Helper function to truncate long strings to 500 characters
24
-
const truncateString = (str: string, maxLength = 500): string => {
25
if (str.length <= maxLength) {
26
return str;
27
}
···
54
55
for await (const response of reachAgent) {
56
if (response.messageType === "reasoning_message") {
57
-
console.log(`💭 reasoning…`);
58
} else if (response.messageType === "assistant_message") {
59
console.log(`💬 ${agentContext.agentBskyName}: ${response.content}`);
60
} else if (response.messageType === "tool_call_message") {
···
76
}
77
} else {
78
console.log(
79
-
"Letta agent ID was not a set variable, skipping notification processing…",
80
);
81
}
82
};
···
21
};
22
23
// Helper function to truncate long strings to 500 characters
24
+
const truncateString = (str: string, maxLength = 140): string => {
25
if (str.length <= maxLength) {
26
return str;
27
}
···
54
55
for await (const response of reachAgent) {
56
if (response.messageType === "reasoning_message") {
57
+
// console.log(`💭 reasoning…`);
58
} else if (response.messageType === "assistant_message") {
59
console.log(`💬 ${agentContext.agentBskyName}: ${response.content}`);
60
} else if (response.messageType === "tool_call_message") {
···
76
}
77
} else {
78
console.log(
79
+
"🔹 Letta agent ID was not a set variable, skipping notification processing…",
80
);
81
}
82
};
+4
-4
utils/processNotification.ts
+4
-4
utils/processNotification.ts
···
44
45
if (!handler) {
46
console.log(
47
-
`kind "${kind}" does not have a system prompt associated with it, moving on…`,
48
);
49
console.log("notification response: ", notification);
50
return;
···
54
const prompt = await handler.promptFn(notification);
55
await messageAgent(prompt);
56
console.log(
57
-
`sent ${kind} notification from ${author} to ${agentProject}. moving on…`,
58
);
59
} catch (error) {
60
console.log(
61
-
`Error processing ${kind} notification from ${author}: `,
62
error,
63
);
64
} finally {
65
-
(agentContext as any)[handler]++;
66
}
67
};
···
44
45
if (!handler) {
46
console.log(
47
+
`🔹 kind "${kind}" does not have a system prompt associated with it, moving on…`,
48
);
49
console.log("notification response: ", notification);
50
return;
···
54
const prompt = await handler.promptFn(notification);
55
await messageAgent(prompt);
56
console.log(
57
+
`🔹 sent ${kind} notification from ${author} to ${agentProject}. moving on…`,
58
);
59
} catch (error) {
60
console.log(
61
+
`🔹 Error processing ${kind} notification from ${author}: `,
62
error,
63
);
64
} finally {
65
+
(agentContext as any)[handler.counter]++;
66
}
67
};
+25
utils/time.ts
+25
utils/time.ts
···
127
export const getNow = () => {
128
return Temporal.Now.zonedDateTimeISO(agentContext.timeZone);
129
};
130
+
131
+
/**
132
+
* Format uptime from milliseconds into a human-readable string
133
+
* @param ms - uptime in milliseconds
134
+
* @returns Formatted string like "2 days, 3 hours, 15 minutes" or "3 hours, 15 minutes"
135
+
*/
136
+
export const formatUptime = (ms: number): string => {
137
+
const days = Math.floor(ms / (1000 * 60 * 60 * 24));
138
+
const hours = Math.floor((ms % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
139
+
const minutes = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60));
140
+
141
+
const parts: string[] = [];
142
+
143
+
if (days > 0) {
144
+
parts.push(`${days} ${days === 1 ? "day" : "days"}`);
145
+
}
146
+
if (hours > 0) {
147
+
parts.push(`${hours} ${hours === 1 ? "hour" : "hours"}`);
148
+
}
149
+
if (minutes > 0 || parts.length === 0) {
150
+
parts.push(`${minutes} ${minutes === 1 ? "minute" : "minutes"}`);
151
+
}
152
+
153
+
return parts.join(", ");
154
+
};