@slock-ai/daemon 0.39.0 → 0.39.1-alpha.1
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/chat-bridge.js +164 -0
- package/dist/{chunk-72UW4SIL.js → chunk-7JPDXVD5.js} +800 -268
- package/dist/cli/index.js +1181 -0
- package/dist/core.js +3 -1
- package/dist/index.js +1 -1
- package/package.json +16 -16
package/dist/chat-bridge.js
CHANGED
|
@@ -228,6 +228,21 @@ function bridgeFetch(url, init = {}) {
|
|
|
228
228
|
var RECENT_DELIVERY_CACHE_LIMIT = 5e3;
|
|
229
229
|
var deliveredMessageKeys = /* @__PURE__ */ new Set();
|
|
230
230
|
var deliveredMessageOrder = [];
|
|
231
|
+
var lastChatContextTarget = null;
|
|
232
|
+
function rememberChatContextTarget(target) {
|
|
233
|
+
if (typeof target === "string" && target.length > 0) {
|
|
234
|
+
lastChatContextTarget = target;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function captureChatContextFromMessages(messages) {
|
|
238
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
239
|
+
const target = formatTarget(messages[i]);
|
|
240
|
+
if (target) {
|
|
241
|
+
lastChatContextTarget = target;
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
231
246
|
function messageDeliveryKey(message) {
|
|
232
247
|
if (message.seq) return `seq:${message.seq}`;
|
|
233
248
|
if (message.message_id) return `msg:${message.message_id}`;
|
|
@@ -402,6 +417,7 @@ server.tool(
|
|
|
402
417
|
]
|
|
403
418
|
};
|
|
404
419
|
}
|
|
420
|
+
rememberChatContextTarget(target);
|
|
405
421
|
const shortId = data.messageId ? data.messageId.slice(0, 8) : null;
|
|
406
422
|
const replyHint = shortId ? ` (to reply in this message's thread, use target "${target.includes(":") ? target : target + ":" + shortId}")` : "";
|
|
407
423
|
let unreadSection = "";
|
|
@@ -409,6 +425,7 @@ server.tool(
|
|
|
409
425
|
await acknowledgeReceivedMessages(data.recentUnread);
|
|
410
426
|
const unreadToShow = rememberDeliveredMessages(data.recentUnread);
|
|
411
427
|
if (unreadToShow.length > 0) {
|
|
428
|
+
captureChatContextFromMessages(unreadToShow);
|
|
412
429
|
unreadSection = `
|
|
413
430
|
|
|
414
431
|
--- New messages you may have missed ---
|
|
@@ -600,6 +617,7 @@ server.tool(
|
|
|
600
617
|
await acknowledgeReceivedMessages(messages);
|
|
601
618
|
const messagesToShow = rememberDeliveredMessages(messages);
|
|
602
619
|
if (messagesToShow.length > 0) {
|
|
620
|
+
captureChatContextFromMessages(messagesToShow);
|
|
603
621
|
return { content: [{ type: "text", text: formatMessages(messagesToShow) }] };
|
|
604
622
|
}
|
|
605
623
|
}
|
|
@@ -1125,5 +1143,151 @@ server.tool(
|
|
|
1125
1143
|
}
|
|
1126
1144
|
}
|
|
1127
1145
|
);
|
|
1146
|
+
function formatReminder(r) {
|
|
1147
|
+
const fireLocal = toLocalTime(r.fireAt);
|
|
1148
|
+
const ref = r.msgRef ? ` ref=${r.msgRef}` : "";
|
|
1149
|
+
const repeat = r.recurrence ? ` repeat=${r.recurrence.description}` : "";
|
|
1150
|
+
return `#${r.reminderId.slice(0, 8)} [${r.status}] fires=${fireLocal} "${r.title}"${ref}${repeat}`;
|
|
1151
|
+
}
|
|
1152
|
+
server.tool(
|
|
1153
|
+
"schedule_reminder",
|
|
1154
|
+
"Schedule a reminder that will fire at a future time and wake you up with a DM. Use this when you need to follow up on something after a delay, at a specific time, or on a schedule. The reminder persists across daemon restarts. For one-shot reminders, provide delay_seconds (preferred) OR fire_at. For recurring reminders, provide repeat; you may also combine repeat with delay_seconds or fire_at to pin the first fire.",
|
|
1155
|
+
{
|
|
1156
|
+
title: z.string().describe("Short description of what the reminder is about. This is what you'll see when it fires."),
|
|
1157
|
+
delay_seconds: z.number().int().positive().optional().describe("Preferred for relative times. Fires this many seconds from now (server-computed, timezone-safe). Use this for any 'in N seconds/minutes/hours' request."),
|
|
1158
|
+
fire_at: z.string().optional().describe("ISO-8601 UTC timestamp, e.g. '2026-04-21T09:00:00Z'. Use only for absolute calendar times ('tomorrow 9am UTC'). Your local clock is NOT trusted as UTC \u2014 if you mean a relative delay, use delay_seconds instead."),
|
|
1159
|
+
repeat: z.string().optional().describe("Recurrence rule. Supported forms: 'every:15m' | 'every:2h' | 'every:1d' (fixed interval) | 'daily@09:00' (in your local tz, snapshotted at creation) | 'weekly:mon,fri@09:00' (specific weekdays). The reminder auto-reschedules after each fire until you cancel it."),
|
|
1160
|
+
channel: z.string().optional().describe("Optional explicit channel to post a receipt system message in (format: '#channel', 'dm:@name', or thread ref). Normally you don't need to pass this \u2014 when you're actively in a conversation, the receipt is auto-posted in the most recent chat context. Use this only to redirect the receipt elsewhere."),
|
|
1161
|
+
msg_id: z.string().optional().describe("Optional message id this reminder is anchored to (from received messages), for context linking. If set, the receipt is posted in that message's channel automatically.")
|
|
1162
|
+
},
|
|
1163
|
+
async ({ title, delay_seconds, fire_at, repeat, channel, msg_id }) => {
|
|
1164
|
+
try {
|
|
1165
|
+
const body = { title, msgId: msg_id ?? null };
|
|
1166
|
+
if (delay_seconds !== void 0) body.delaySeconds = delay_seconds;
|
|
1167
|
+
if (fire_at !== void 0) body.fireAt = fire_at;
|
|
1168
|
+
if (repeat !== void 0) {
|
|
1169
|
+
body.repeat = repeat;
|
|
1170
|
+
body.tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
1171
|
+
}
|
|
1172
|
+
const effectiveChannel = channel ?? (msg_id ? void 0 : lastChatContextTarget ?? void 0);
|
|
1173
|
+
if (effectiveChannel !== void 0) body.channel = effectiveChannel;
|
|
1174
|
+
const { response: res, data } = await executeJsonRequest(
|
|
1175
|
+
`${serverUrl}/internal/agent/${agentId}/reminders`,
|
|
1176
|
+
{
|
|
1177
|
+
method: "POST",
|
|
1178
|
+
headers: commonHeaders,
|
|
1179
|
+
body: JSON.stringify(body)
|
|
1180
|
+
},
|
|
1181
|
+
{
|
|
1182
|
+
toolName: "schedule_reminder",
|
|
1183
|
+
fetchImpl: bridgeFetch
|
|
1184
|
+
}
|
|
1185
|
+
);
|
|
1186
|
+
if (!res.ok || !data.reminder) {
|
|
1187
|
+
return { isError: true, content: [{ type: "text", text: `Error: ${data.error || res.statusText}` }] };
|
|
1188
|
+
}
|
|
1189
|
+
const lines = [`Reminder scheduled: ${formatReminder(data.reminder)}`];
|
|
1190
|
+
if (data.warning) lines.push(`Warning: ${data.warning}`);
|
|
1191
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
1192
|
+
} catch (err) {
|
|
1193
|
+
return {
|
|
1194
|
+
isError: true,
|
|
1195
|
+
content: [{ type: "text", text: `Error: ${err.message}` }]
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
);
|
|
1200
|
+
server.tool(
|
|
1201
|
+
"list_reminders",
|
|
1202
|
+
"List your own reminders. Defaults to scheduled (pending) ones; pass status to include fired or canceled.",
|
|
1203
|
+
{
|
|
1204
|
+
status: z.string().optional().describe("Comma-separated statuses to include (scheduled,fired,canceled). Defaults to 'scheduled'.")
|
|
1205
|
+
},
|
|
1206
|
+
async ({ status }) => {
|
|
1207
|
+
try {
|
|
1208
|
+
const qs = new URLSearchParams();
|
|
1209
|
+
qs.set("status", status && status.trim().length > 0 ? status.trim() : "scheduled");
|
|
1210
|
+
const { response: res, data } = await executeJsonRequest(
|
|
1211
|
+
`${serverUrl}/internal/agent/${agentId}/reminders?${qs.toString()}`,
|
|
1212
|
+
{ method: "GET", headers: commonHeaders },
|
|
1213
|
+
{
|
|
1214
|
+
toolName: "list_reminders",
|
|
1215
|
+
fetchImpl: bridgeFetch
|
|
1216
|
+
}
|
|
1217
|
+
);
|
|
1218
|
+
if (!res.ok) {
|
|
1219
|
+
return { isError: true, content: [{ type: "text", text: `Error: ${data.error || res.statusText}` }] };
|
|
1220
|
+
}
|
|
1221
|
+
const list = data.reminders ?? [];
|
|
1222
|
+
if (list.length === 0) {
|
|
1223
|
+
return { content: [{ type: "text", text: "No reminders." }] };
|
|
1224
|
+
}
|
|
1225
|
+
return {
|
|
1226
|
+
content: [
|
|
1227
|
+
{ type: "text", text: list.map(formatReminder).join("\n") }
|
|
1228
|
+
]
|
|
1229
|
+
};
|
|
1230
|
+
} catch (err) {
|
|
1231
|
+
return {
|
|
1232
|
+
isError: true,
|
|
1233
|
+
content: [{ type: "text", text: `Error: ${err.message}` }]
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
);
|
|
1238
|
+
server.tool(
|
|
1239
|
+
"cancel_reminder",
|
|
1240
|
+
"Cancel one of your own scheduled reminders by id. Only reminders in 'scheduled' status can be canceled.",
|
|
1241
|
+
{
|
|
1242
|
+
reminder_id: z.string().describe("The reminder id (full uuid, or the short 8-char prefix shown by schedule_reminder / list_reminders).")
|
|
1243
|
+
},
|
|
1244
|
+
async ({ reminder_id }) => {
|
|
1245
|
+
try {
|
|
1246
|
+
let fullId = reminder_id;
|
|
1247
|
+
if (reminder_id.length < 32) {
|
|
1248
|
+
const { response: listRes, data: listData } = await executeJsonRequest(
|
|
1249
|
+
`${serverUrl}/internal/agent/${agentId}/reminders?status=scheduled`,
|
|
1250
|
+
{ method: "GET", headers: commonHeaders },
|
|
1251
|
+
{
|
|
1252
|
+
toolName: "cancel_reminder.resolve",
|
|
1253
|
+
fetchImpl: bridgeFetch
|
|
1254
|
+
}
|
|
1255
|
+
);
|
|
1256
|
+
if (!listRes.ok) {
|
|
1257
|
+
return { isError: true, content: [{ type: "text", text: `Error: ${listData.error || listRes.statusText}` }] };
|
|
1258
|
+
}
|
|
1259
|
+
const matches = (listData.reminders ?? []).filter((r) => r.reminderId.startsWith(reminder_id));
|
|
1260
|
+
if (matches.length === 0) {
|
|
1261
|
+
return { isError: true, content: [{ type: "text", text: `No scheduled reminder matches id prefix '${reminder_id}'.` }] };
|
|
1262
|
+
}
|
|
1263
|
+
if (matches.length > 1) {
|
|
1264
|
+
return { isError: true, content: [{ type: "text", text: `Ambiguous id prefix '${reminder_id}' matches ${matches.length} reminders; pass a longer id.` }] };
|
|
1265
|
+
}
|
|
1266
|
+
fullId = matches[0].reminderId;
|
|
1267
|
+
}
|
|
1268
|
+
const { response: res, data } = await executeJsonRequest(
|
|
1269
|
+
`${serverUrl}/internal/agent/${agentId}/reminders/${fullId}`,
|
|
1270
|
+
{ method: "DELETE", headers: commonHeaders },
|
|
1271
|
+
{
|
|
1272
|
+
toolName: "cancel_reminder",
|
|
1273
|
+
fetchImpl: bridgeFetch
|
|
1274
|
+
}
|
|
1275
|
+
);
|
|
1276
|
+
if (!res.ok || !data.reminder) {
|
|
1277
|
+
return { isError: true, content: [{ type: "text", text: `Error: ${data.error || res.statusText}` }] };
|
|
1278
|
+
}
|
|
1279
|
+
return {
|
|
1280
|
+
content: [
|
|
1281
|
+
{ type: "text", text: `Reminder canceled: ${formatReminder(data.reminder)}` }
|
|
1282
|
+
]
|
|
1283
|
+
};
|
|
1284
|
+
} catch (err) {
|
|
1285
|
+
return {
|
|
1286
|
+
isError: true,
|
|
1287
|
+
content: [{ type: "text", text: `Error: ${err.message}` }]
|
|
1288
|
+
};
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
);
|
|
1128
1292
|
var transport = new StdioServerTransport();
|
|
1129
1293
|
await server.connect(transport);
|