@slock-ai/daemon 0.20.0 → 0.21.0
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 +57 -27
- package/dist/index.js +74 -39
- package/package.json +1 -1
package/dist/chat-bridge.js
CHANGED
|
@@ -230,37 +230,57 @@ Use your Read tool to view this image.` }]
|
|
|
230
230
|
);
|
|
231
231
|
server.tool(
|
|
232
232
|
"receive_message",
|
|
233
|
-
"Receive new messages.
|
|
233
|
+
"Receive new messages. Blocks and waits for new messages (polls internally). Returns messages formatted as [#channel], [dm:@peer], or [thread:#channel:id] followed by the sender and content.",
|
|
234
234
|
{
|
|
235
|
-
block: z.boolean().default(true).describe("Whether to block (wait) for new messages")
|
|
236
|
-
timeout_ms: z.number().default(59e3).describe("How long to wait in ms when blocking (default 59s, just under MCP tool call timeout)")
|
|
235
|
+
block: z.boolean().default(true).describe("Whether to block (wait) for new messages")
|
|
237
236
|
},
|
|
238
|
-
async ({ block
|
|
237
|
+
async ({ block }) => {
|
|
239
238
|
try {
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
239
|
+
const POLL_INTERVAL_MS = 25e3;
|
|
240
|
+
const MAX_WAIT_MS = 27e4;
|
|
241
|
+
const startTime = Date.now();
|
|
242
|
+
while (true) {
|
|
243
|
+
const elapsed = Date.now() - startTime;
|
|
244
|
+
const remaining = MAX_WAIT_MS - elapsed;
|
|
245
|
+
if (!block || remaining <= 0) {
|
|
246
|
+
const params2 = new URLSearchParams();
|
|
247
|
+
if (block) {
|
|
248
|
+
params2.set("block", "true");
|
|
249
|
+
params2.set("timeout", "1000");
|
|
250
|
+
}
|
|
251
|
+
const res2 = await fetch(
|
|
252
|
+
`${serverUrl}/internal/agent/${agentId}/receive?${params2}`,
|
|
253
|
+
{ method: "GET", headers: commonHeaders }
|
|
254
|
+
);
|
|
255
|
+
if (!res2.ok) {
|
|
256
|
+
const errData = await res2.json().catch(() => ({}));
|
|
257
|
+
return { content: [{ type: "text", text: `Error: ${errData.error || res2.statusText}` }] };
|
|
258
|
+
}
|
|
259
|
+
const data2 = await res2.json();
|
|
260
|
+
if (data2.messages?.length > 0) {
|
|
261
|
+
return { content: [{ type: "text", text: formatMessages(data2.messages) }] };
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
content: [{ type: "text", text: "No new messages. Take a rest \u2014 new messages will be delivered to you directly. Do not call receive_message or take any further action until notified." }]
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
const thisPoll = Math.min(POLL_INTERVAL_MS, remaining);
|
|
268
|
+
const params = new URLSearchParams();
|
|
269
|
+
params.set("block", "true");
|
|
270
|
+
params.set("timeout", String(thisPoll));
|
|
271
|
+
const res = await fetch(
|
|
272
|
+
`${serverUrl}/internal/agent/${agentId}/receive?${params}`,
|
|
273
|
+
{ method: "GET", headers: commonHeaders }
|
|
274
|
+
);
|
|
275
|
+
if (!res.ok) {
|
|
276
|
+
const errData = await res.json().catch(() => ({}));
|
|
277
|
+
return { content: [{ type: "text", text: `Error: ${errData.error || res.statusText}` }] };
|
|
278
|
+
}
|
|
279
|
+
const data = await res.json();
|
|
280
|
+
if (data.messages?.length > 0) {
|
|
281
|
+
return { content: [{ type: "text", text: formatMessages(data.messages) }] };
|
|
282
|
+
}
|
|
252
283
|
}
|
|
253
|
-
const formatted = data.messages.map((m) => {
|
|
254
|
-
const target = formatTarget(m);
|
|
255
|
-
const msgId = m.message_id ? m.message_id.slice(0, 8) : "-";
|
|
256
|
-
const time = m.timestamp ? toLocalTime(m.timestamp) : "-";
|
|
257
|
-
const senderType = m.sender_type === "agent" ? " type=agent" : "";
|
|
258
|
-
const attachSuffix = m.attachments?.length ? ` [${m.attachments.length} image${m.attachments.length > 1 ? "s" : ""}: ${m.attachments.map((a) => `${a.filename} (id:${a.id})`).join(", ")} \u2014 use view_file to see]` : "";
|
|
259
|
-
return `[target=${target} msg=${msgId} time=${time}${senderType}] @${m.sender_name}: ${m.content}${attachSuffix}`;
|
|
260
|
-
}).join("\n");
|
|
261
|
-
return {
|
|
262
|
-
content: [{ type: "text", text: formatted }]
|
|
263
|
-
};
|
|
264
284
|
} catch (err) {
|
|
265
285
|
return {
|
|
266
286
|
content: [{ type: "text", text: `Error: ${err.message}` }]
|
|
@@ -268,6 +288,16 @@ server.tool(
|
|
|
268
288
|
}
|
|
269
289
|
}
|
|
270
290
|
);
|
|
291
|
+
function formatMessages(messages) {
|
|
292
|
+
return messages.map((m) => {
|
|
293
|
+
const target = formatTarget(m);
|
|
294
|
+
const msgId = m.message_id ? m.message_id.slice(0, 8) : "-";
|
|
295
|
+
const time = m.timestamp ? toLocalTime(m.timestamp) : "-";
|
|
296
|
+
const senderType = m.sender_type === "agent" ? " type=agent" : "";
|
|
297
|
+
const attachSuffix = m.attachments?.length ? ` [${m.attachments.length} image${m.attachments.length > 1 ? "s" : ""}: ${m.attachments.map((a) => `${a.filename} (id:${a.id})`).join(", ")} \u2014 use view_file to see]` : "";
|
|
298
|
+
return `[target=${target} msg=${msgId} time=${time}${senderType}] @${m.sender_name}: ${m.content}${attachSuffix}`;
|
|
299
|
+
}).join("\n");
|
|
300
|
+
}
|
|
271
301
|
server.tool(
|
|
272
302
|
"list_server",
|
|
273
303
|
"List all channels in this server, including which ones you have joined, plus all agents and humans. Use this to discover who and where you can message.",
|
package/dist/index.js
CHANGED
|
@@ -570,7 +570,7 @@ var CodexDriver = class {
|
|
|
570
570
|
"-c",
|
|
571
571
|
"mcp_servers.chat.startup_timeout_sec=30",
|
|
572
572
|
"-c",
|
|
573
|
-
"mcp_servers.chat.tool_timeout_sec=
|
|
573
|
+
"mcp_servers.chat.tool_timeout_sec=300",
|
|
574
574
|
"-c",
|
|
575
575
|
"mcp_servers.chat.enabled=true",
|
|
576
576
|
"-c",
|
|
@@ -803,6 +803,8 @@ var AgentProcessManager = class {
|
|
|
803
803
|
agents = /* @__PURE__ */ new Map();
|
|
804
804
|
agentsStarting = /* @__PURE__ */ new Set();
|
|
805
805
|
// Prevent concurrent starts of same agent
|
|
806
|
+
/** Cached configs for agents whose process exited normally — enables auto-restart on next message */
|
|
807
|
+
idleAgentConfigs = /* @__PURE__ */ new Map();
|
|
806
808
|
chatBridgePath;
|
|
807
809
|
sendToServer;
|
|
808
810
|
daemonApiKey;
|
|
@@ -948,9 +950,13 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
948
950
|
}
|
|
949
951
|
this.agents.delete(agentId);
|
|
950
952
|
if (code === 0) {
|
|
951
|
-
this.
|
|
952
|
-
|
|
953
|
+
this.idleAgentConfigs.set(agentId, {
|
|
954
|
+
config: { ...ap.config, sessionId: ap.sessionId },
|
|
955
|
+
sessionId: ap.sessionId
|
|
956
|
+
});
|
|
957
|
+
this.sendToServer({ type: "agent:activity", agentId, activity: "online", detail: "" });
|
|
953
958
|
} else {
|
|
959
|
+
this.idleAgentConfigs.delete(agentId);
|
|
954
960
|
const reason = code === null ? "killed by signal" : `exit code ${code}`;
|
|
955
961
|
console.error(`[Agent ${agentId}] Process crashed (${reason}) \u2014 marking inactive`);
|
|
956
962
|
this.sendToServer({ type: "agent:status", agentId, status: "inactive" });
|
|
@@ -965,7 +971,8 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
965
971
|
throw err;
|
|
966
972
|
}
|
|
967
973
|
}
|
|
968
|
-
async stopAgent(agentId) {
|
|
974
|
+
async stopAgent(agentId, { wait = false, silent = false } = {}) {
|
|
975
|
+
this.idleAgentConfigs.delete(agentId);
|
|
969
976
|
const ap = this.agents.get(agentId);
|
|
970
977
|
if (!ap) return;
|
|
971
978
|
if (ap.pendingReceive) {
|
|
@@ -977,27 +984,43 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
977
984
|
}
|
|
978
985
|
this.agents.delete(agentId);
|
|
979
986
|
ap.process.kill("SIGTERM");
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
/** Hibernate: kill process but keep status as "sleeping" (auto-wakes on next message via --resume) */
|
|
984
|
-
sleepAgent(agentId) {
|
|
985
|
-
const ap = this.agents.get(agentId);
|
|
986
|
-
if (!ap) return;
|
|
987
|
-
console.log(`[Agent ${agentId}] Hibernating (sleeping)`);
|
|
988
|
-
if (ap.pendingReceive) {
|
|
989
|
-
clearTimeout(ap.pendingReceive.timer);
|
|
990
|
-
ap.pendingReceive.resolve([]);
|
|
987
|
+
if (!silent) {
|
|
988
|
+
this.sendToServer({ type: "agent:status", agentId, status: "inactive" });
|
|
989
|
+
this.sendToServer({ type: "agent:activity", agentId, activity: "offline", detail: "" });
|
|
991
990
|
}
|
|
992
|
-
if (
|
|
993
|
-
|
|
991
|
+
if (wait) {
|
|
992
|
+
await new Promise((resolve) => {
|
|
993
|
+
const forceKillTimer = setTimeout(() => {
|
|
994
|
+
try {
|
|
995
|
+
ap.process.kill("SIGKILL");
|
|
996
|
+
} catch {
|
|
997
|
+
}
|
|
998
|
+
resolve();
|
|
999
|
+
}, 5e3);
|
|
1000
|
+
ap.process.on("exit", () => {
|
|
1001
|
+
clearTimeout(forceKillTimer);
|
|
1002
|
+
resolve();
|
|
1003
|
+
});
|
|
1004
|
+
if (ap.process.exitCode !== null || ap.process.signalCode !== null) {
|
|
1005
|
+
clearTimeout(forceKillTimer);
|
|
1006
|
+
resolve();
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
994
1009
|
}
|
|
995
|
-
this.agents.delete(agentId);
|
|
996
|
-
ap.process.kill("SIGTERM");
|
|
997
1010
|
}
|
|
998
1011
|
deliverMessage(agentId, message) {
|
|
999
1012
|
const ap = this.agents.get(agentId);
|
|
1000
|
-
if (!ap)
|
|
1013
|
+
if (!ap) {
|
|
1014
|
+
const cached = this.idleAgentConfigs.get(agentId);
|
|
1015
|
+
if (cached) {
|
|
1016
|
+
console.log(`[Agent ${agentId}] Auto-restarting idle process for incoming message`);
|
|
1017
|
+
this.idleAgentConfigs.delete(agentId);
|
|
1018
|
+
this.startAgent(agentId, cached.config, message).catch((err) => {
|
|
1019
|
+
console.error(`[Agent ${agentId}] Failed to auto-restart:`, err);
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1001
1024
|
if (ap.pendingReceive) {
|
|
1002
1025
|
clearTimeout(ap.pendingReceive.timer);
|
|
1003
1026
|
ap.pendingReceive.resolve([message]);
|
|
@@ -1025,8 +1048,9 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1025
1048
|
}
|
|
1026
1049
|
}
|
|
1027
1050
|
async stopAll() {
|
|
1051
|
+
this.idleAgentConfigs.clear();
|
|
1028
1052
|
const ids = [...this.agents.keys()];
|
|
1029
|
-
await Promise.all(ids.map((id) => this.stopAgent(id)));
|
|
1053
|
+
await Promise.all(ids.map((id) => this.stopAgent(id, { wait: true, silent: true })));
|
|
1030
1054
|
}
|
|
1031
1055
|
getRunningAgentIds() {
|
|
1032
1056
|
return [...this.agents.keys()];
|
|
@@ -1157,39 +1181,51 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1157
1181
|
case "thinking": {
|
|
1158
1182
|
const text = event.text.length > MAX_TRAJECTORY_TEXT ? event.text.slice(0, MAX_TRAJECTORY_TEXT) + "\u2026" : event.text;
|
|
1159
1183
|
trajectory.push({ kind: "thinking", text });
|
|
1160
|
-
|
|
1161
|
-
|
|
1184
|
+
if (ap?.isInReceiveMessage) {
|
|
1185
|
+
ap.isInReceiveMessage = false;
|
|
1186
|
+
} else {
|
|
1187
|
+
activity = "thinking";
|
|
1188
|
+
}
|
|
1162
1189
|
break;
|
|
1163
1190
|
}
|
|
1164
1191
|
case "text": {
|
|
1165
1192
|
const text = event.text.length > MAX_TRAJECTORY_TEXT ? event.text.slice(0, MAX_TRAJECTORY_TEXT) + "\u2026" : event.text;
|
|
1166
1193
|
trajectory.push({ kind: "text", text });
|
|
1167
|
-
|
|
1168
|
-
|
|
1194
|
+
if (ap?.isInReceiveMessage) {
|
|
1195
|
+
ap.isInReceiveMessage = false;
|
|
1196
|
+
} else {
|
|
1197
|
+
activity = "thinking";
|
|
1198
|
+
}
|
|
1169
1199
|
break;
|
|
1170
1200
|
}
|
|
1171
1201
|
case "tool_call": {
|
|
1172
1202
|
const toolName = event.name;
|
|
1173
1203
|
const inputSummary = driver.summarizeToolInput(toolName, event.input);
|
|
1174
|
-
trajectory.push({ kind: "tool_start", toolName, toolInput: inputSummary });
|
|
1175
1204
|
if (toolName === `${driver.mcpToolPrefix}receive_message`) {
|
|
1176
|
-
const isBlocking = event.input?.block
|
|
1205
|
+
const isBlocking = event.input?.block === true || event.input?.block === "true";
|
|
1177
1206
|
if (isBlocking) {
|
|
1178
1207
|
activity = "online";
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1208
|
+
if (ap) {
|
|
1209
|
+
ap.isInReceiveMessage = true;
|
|
1210
|
+
ap.pendingNotificationCount = 0;
|
|
1211
|
+
if (ap.notificationTimer) {
|
|
1212
|
+
clearTimeout(ap.notificationTimer);
|
|
1213
|
+
ap.notificationTimer = null;
|
|
1214
|
+
}
|
|
1186
1215
|
}
|
|
1216
|
+
} else {
|
|
1217
|
+
trajectory.push({ kind: "tool_start", toolName, toolInput: inputSummary });
|
|
1218
|
+
activity = "working";
|
|
1219
|
+
detail = "Checking messages\u2026";
|
|
1220
|
+
if (ap) ap.isInReceiveMessage = false;
|
|
1187
1221
|
}
|
|
1188
1222
|
} else if (toolName === `${driver.mcpToolPrefix}send_message`) {
|
|
1223
|
+
trajectory.push({ kind: "tool_start", toolName, toolInput: inputSummary });
|
|
1189
1224
|
activity = "working";
|
|
1190
1225
|
detail = "Sending message\u2026";
|
|
1191
1226
|
if (ap) ap.isInReceiveMessage = false;
|
|
1192
1227
|
} else {
|
|
1228
|
+
trajectory.push({ kind: "tool_start", toolName, toolInput: inputSummary });
|
|
1193
1229
|
activity = "working";
|
|
1194
1230
|
detail = driver.toolDisplayName(toolName);
|
|
1195
1231
|
if (ap) ap.isInReceiveMessage = false;
|
|
@@ -1212,7 +1248,10 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1212
1248
|
}
|
|
1213
1249
|
if (activity) {
|
|
1214
1250
|
this.sendToServer({ type: "agent:activity", agentId, activity, detail });
|
|
1215
|
-
trajectory.
|
|
1251
|
+
const hasToolStart = trajectory.some((e) => e.kind === "tool_start");
|
|
1252
|
+
if (!hasToolStart) {
|
|
1253
|
+
trajectory.push({ kind: "status", activity, detail });
|
|
1254
|
+
}
|
|
1216
1255
|
}
|
|
1217
1256
|
if (trajectory.length > 0) {
|
|
1218
1257
|
this.sendToServer({ type: "agent:trajectory", agentId, entries: trajectory });
|
|
@@ -1377,10 +1416,6 @@ connection = new DaemonConnection({
|
|
|
1377
1416
|
console.log(`[Daemon] Stopping agent ${msg.agentId}`);
|
|
1378
1417
|
agentManager.stopAgent(msg.agentId);
|
|
1379
1418
|
break;
|
|
1380
|
-
case "agent:sleep":
|
|
1381
|
-
console.log(`[Daemon] Sleeping agent ${msg.agentId}`);
|
|
1382
|
-
agentManager.sleepAgent(msg.agentId);
|
|
1383
|
-
break;
|
|
1384
1419
|
case "agent:reset-workspace":
|
|
1385
1420
|
console.log(`[Daemon] Resetting workspace for agent ${msg.agentId}`);
|
|
1386
1421
|
agentManager.resetWorkspace(msg.agentId);
|