@slock-ai/daemon 0.23.0 → 0.24.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 +36 -12
- package/dist/index.js +97 -74
- package/package.json +1 -1
package/dist/chat-bridge.js
CHANGED
|
@@ -229,12 +229,38 @@ Use your Read tool to view this image.` }]
|
|
|
229
229
|
}
|
|
230
230
|
);
|
|
231
231
|
server.tool(
|
|
232
|
-
"
|
|
233
|
-
"
|
|
234
|
-
{
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
232
|
+
"check_messages",
|
|
233
|
+
"Check for new messages without waiting. Returns immediately with any pending messages, or 'No new messages' if none. Use this freely during work \u2014 at natural breakpoints, after notifications, or whenever you want to see if anything new came in.",
|
|
234
|
+
{},
|
|
235
|
+
async () => {
|
|
236
|
+
try {
|
|
237
|
+
const res = await fetch(
|
|
238
|
+
`${serverUrl}/internal/agent/${agentId}/receive`,
|
|
239
|
+
{ method: "GET", headers: commonHeaders }
|
|
240
|
+
);
|
|
241
|
+
if (!res.ok) {
|
|
242
|
+
const errData = await res.json().catch(() => ({}));
|
|
243
|
+
return { content: [{ type: "text", text: `Error: ${errData.error || res.statusText}` }] };
|
|
244
|
+
}
|
|
245
|
+
const data = await res.json();
|
|
246
|
+
if (data.messages?.length > 0) {
|
|
247
|
+
return { content: [{ type: "text", text: formatMessages(data.messages) }] };
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
content: [{ type: "text", text: "No new messages." }]
|
|
251
|
+
};
|
|
252
|
+
} catch (err) {
|
|
253
|
+
return {
|
|
254
|
+
content: [{ type: "text", text: `Error: ${err.message}` }]
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
);
|
|
259
|
+
server.tool(
|
|
260
|
+
"wait_for_message",
|
|
261
|
+
"Block and wait for new messages. ONLY call this when you have NO work left to do \u2014 all tasks complete, all replies sent, nothing pending. This blocks for up to ~4 minutes waiting for a message to arrive. If you still have work in progress, do NOT call this \u2014 finish your work first.",
|
|
262
|
+
{},
|
|
263
|
+
async () => {
|
|
238
264
|
try {
|
|
239
265
|
const POLL_INTERVAL_MS = 25e3;
|
|
240
266
|
const MAX_WAIT_MS = 27e4;
|
|
@@ -242,12 +268,10 @@ server.tool(
|
|
|
242
268
|
while (true) {
|
|
243
269
|
const elapsed = Date.now() - startTime;
|
|
244
270
|
const remaining = MAX_WAIT_MS - elapsed;
|
|
245
|
-
if (
|
|
271
|
+
if (remaining <= 0) {
|
|
246
272
|
const params2 = new URLSearchParams();
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
params2.set("timeout", "1000");
|
|
250
|
-
}
|
|
273
|
+
params2.set("block", "true");
|
|
274
|
+
params2.set("timeout", "1000");
|
|
251
275
|
const res2 = await fetch(
|
|
252
276
|
`${serverUrl}/internal/agent/${agentId}/receive?${params2}`,
|
|
253
277
|
{ method: "GET", headers: commonHeaders }
|
|
@@ -261,7 +285,7 @@ server.tool(
|
|
|
261
285
|
return { content: [{ type: "text", text: formatMessages(data2.messages) }] };
|
|
262
286
|
}
|
|
263
287
|
return {
|
|
264
|
-
content: [{ type: "text", text: "No new messages. Take a rest \u2014 new messages will be delivered to you directly. Do not
|
|
288
|
+
content: [{ type: "text", text: "No new messages. Take a rest \u2014 new messages will be delivered to you directly. Do not take any further action until notified." }]
|
|
265
289
|
};
|
|
266
290
|
}
|
|
267
291
|
const thisPoll = Math.min(POLL_INTERVAL_MS, remaining);
|
package/dist/index.js
CHANGED
|
@@ -106,9 +106,9 @@ function buildBaseSystemPrompt(config, opts) {
|
|
|
106
106
|
const startupSteps = [
|
|
107
107
|
`1. **Read MEMORY.md** (in your cwd). This is your memory index \u2014 it tells you what you know and where to find it.`,
|
|
108
108
|
`2. Follow the instructions in MEMORY.md to read any other memory files you need (e.g. channel summaries, role definitions, user preferences).`,
|
|
109
|
-
`3. Call ${t("
|
|
109
|
+
`3. Call ${t("wait_for_message")}() to start listening.`,
|
|
110
110
|
`4. When you receive a message, process it and reply with ${t("send_message")}.`,
|
|
111
|
-
`5.
|
|
111
|
+
`5. **Only when you have NO more work to do**, call ${t("wait_for_message")}() to wait for new messages. NEVER call wait_for_message while you still have work in progress \u2014 finish all steps first, report your results, then go back to listening.`
|
|
112
112
|
];
|
|
113
113
|
let prompt = `You are "${config.displayName || config.name}", an AI agent in Slock \u2014 a collaborative platform for human-AI collaboration.
|
|
114
114
|
|
|
@@ -120,16 +120,18 @@ You are a **long-running, persistent agent**. You are NOT a one-shot assistant \
|
|
|
120
120
|
|
|
121
121
|
You have MCP tools from the "chat" server. Use ONLY these for communication:
|
|
122
122
|
|
|
123
|
-
1. **${t("
|
|
124
|
-
2. **${t("
|
|
125
|
-
3. **${t("
|
|
126
|
-
4. **${t("
|
|
127
|
-
5. **${t("
|
|
128
|
-
6. **${t("
|
|
129
|
-
7. **${t("
|
|
130
|
-
8. **${t("
|
|
131
|
-
9. **${t("
|
|
132
|
-
10. **${t("
|
|
123
|
+
1. **${t("wait_for_message")}** \u2014 Block and wait for new messages. ONLY use when you have NO work left to do. This is your idle loop.
|
|
124
|
+
2. **${t("check_messages")}** \u2014 Non-blocking check for new messages. Use freely during work \u2014 at natural breakpoints or after notifications.
|
|
125
|
+
3. **${t("send_message")}** \u2014 Send a message to a channel or DM.
|
|
126
|
+
4. **${t("list_server")}** \u2014 List all channels in this server, which ones you have joined, plus all agents and humans.
|
|
127
|
+
5. **${t("read_history")}** \u2014 Read past messages from a channel or DM.
|
|
128
|
+
6. **${t("list_tasks")}** \u2014 View a channel's task board.
|
|
129
|
+
7. **${t("create_tasks")}** \u2014 Create tasks on a channel's task board (supports batch).
|
|
130
|
+
8. **${t("claim_tasks")}** \u2014 Claim tasks by number (supports batch, handles conflicts).
|
|
131
|
+
9. **${t("unclaim_task")}** \u2014 Release your claim on a task.
|
|
132
|
+
10. **${t("update_task_status")}** \u2014 Change a task's status (e.g. to in_review or done).
|
|
133
|
+
11. **${t("upload_file")}** \u2014 Upload an image file to attach to a message. Returns an attachment ID to pass to send_message.
|
|
134
|
+
12. **${t("view_file")}** \u2014 Download an attached image by its attachment ID so you can view it. Use when messages contain image attachments.
|
|
133
135
|
|
|
134
136
|
CRITICAL RULES:
|
|
135
137
|
${criticalRules.join("\n")}
|
|
@@ -333,13 +335,12 @@ You may develop a specialized role over time through your interactions. Embrace
|
|
|
333
335
|
|
|
334
336
|
While you are busy (executing tools, thinking, etc.), new messages may arrive. When this happens, you will receive a system notification like:
|
|
335
337
|
|
|
336
|
-
\`[System notification: You have N new message(s) waiting. Call
|
|
338
|
+
\`[System notification: You have N new message(s) waiting. Call check_messages to read them when you're ready.]\`
|
|
337
339
|
|
|
338
340
|
How to handle these:
|
|
339
|
-
-
|
|
340
|
-
-
|
|
341
|
-
-
|
|
342
|
-
- These notifications are batched (you won't get one per message), so the count tells you how many are waiting.`;
|
|
341
|
+
- Call \`${t("check_messages")}()\` to check for new messages. You are encouraged to do this frequently \u2014 at natural breakpoints in your work, or whenever you see a notification.
|
|
342
|
+
- If the new message is higher priority, you may pivot to it. If not, continue your current work.
|
|
343
|
+
- **IMPORTANT: \`${t("check_messages")}\` and \`${t("wait_for_message")}\` are very different tools.** \`check_messages\` returns instantly with any pending messages (or "no new messages"). \`wait_for_message\` blocks for up to ~4 minutes \u2014 ONLY use it when you have absolutely NO work left to do.`;
|
|
343
344
|
}
|
|
344
345
|
if (config.description) {
|
|
345
346
|
prompt += `
|
|
@@ -485,6 +486,7 @@ var ClaudeDriver = class {
|
|
|
485
486
|
if (name === "mcp__chat__update_task_status") return "Updating task status\u2026";
|
|
486
487
|
if (name === "mcp__chat__list_server") return "Listing server\u2026";
|
|
487
488
|
if (name === "mcp__chat__read_history") return "Reading history\u2026";
|
|
489
|
+
if (name === "mcp__chat__check_messages") return "Checking messages\u2026";
|
|
488
490
|
if (name.startsWith("mcp__chat__")) return "";
|
|
489
491
|
if (name === "Read" || name === "read_file") return "Reading file\u2026";
|
|
490
492
|
if (name === "Write" || name === "write_file") return "Writing file\u2026";
|
|
@@ -717,10 +719,10 @@ var CodexDriver = class {
|
|
|
717
719
|
toolPrefix: "",
|
|
718
720
|
extraCriticalRules: [
|
|
719
721
|
"- Do NOT use shell commands to send or receive messages. The MCP tools handle everything.",
|
|
720
|
-
"- ALWAYS call
|
|
722
|
+
"- ALWAYS call wait_for_message after completing any task \u2014 this keeps you listening for new messages."
|
|
721
723
|
],
|
|
722
724
|
postStartupNotes: [
|
|
723
|
-
"**IMPORTANT**: Your process exits after each turn completes. You will be automatically restarted when new messages arrive. Always call
|
|
725
|
+
"**IMPORTANT**: Your process exits after each turn completes. You will be automatically restarted when new messages arrive. Always call wait_for_message as your last action \u2014 if no messages are pending, you'll sleep and be woken when one arrives."
|
|
724
726
|
],
|
|
725
727
|
includeStdinNotificationSection: false
|
|
726
728
|
});
|
|
@@ -735,6 +737,7 @@ var CodexDriver = class {
|
|
|
735
737
|
if (name === `${this.mcpToolPrefix}update_task_status`) return "Updating task status\u2026";
|
|
736
738
|
if (name === `${this.mcpToolPrefix}list_server`) return "Listing server\u2026";
|
|
737
739
|
if (name === `${this.mcpToolPrefix}read_history`) return "Reading history\u2026";
|
|
740
|
+
if (name === `${this.mcpToolPrefix}check_messages`) return "Checking messages\u2026";
|
|
738
741
|
if (name.startsWith(this.mcpToolPrefix)) return "";
|
|
739
742
|
if (name === "shell" || name === "command_execution") return "Running command\u2026";
|
|
740
743
|
if (name === "file_change") return "Editing file\u2026";
|
|
@@ -801,6 +804,7 @@ function toLocalTime(iso) {
|
|
|
801
804
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
802
805
|
}
|
|
803
806
|
var MAX_TRAJECTORY_TEXT = 2e3;
|
|
807
|
+
var ACTIVITY_HEARTBEAT_MS = 6e4;
|
|
804
808
|
var AgentProcessManager = class {
|
|
805
809
|
agents = /* @__PURE__ */ new Map();
|
|
806
810
|
agentsStarting = /* @__PURE__ */ new Set();
|
|
@@ -868,11 +872,13 @@ Use read_history to catch up, or respond to the message above first.`;
|
|
|
868
872
|
}
|
|
869
873
|
prompt += `
|
|
870
874
|
|
|
871
|
-
Respond as appropriate \u2014 reply using send_message, or take action as needed. Then call
|
|
875
|
+
Respond as appropriate \u2014 reply using send_message, or take action as needed. Then call wait_for_message to keep listening.
|
|
876
|
+
|
|
877
|
+
IMPORTANT: If the message requires multi-step work (e.g. research, code changes, testing), complete ALL steps before calling wait_for_message. Sending a progress update does NOT mean your task is done \u2014 only call wait_for_message when you have NO more work to do.`;
|
|
872
878
|
if (driver.supportsStdinNotification) {
|
|
873
879
|
prompt += `
|
|
874
880
|
|
|
875
|
-
Note: While you are busy, you may receive [System notification: ...] messages. Finish your current step, then call
|
|
881
|
+
Note: While you are busy, you may receive [System notification: ...] messages. Finish your current step, then call check_messages to check for messages.`;
|
|
876
882
|
}
|
|
877
883
|
} else if (isResume && unreadSummary && Object.keys(unreadSummary).length > 0) {
|
|
878
884
|
prompt = `You have unread messages from while you were offline:`;
|
|
@@ -882,18 +888,18 @@ Note: While you are busy, you may receive [System notification: ...] messages. F
|
|
|
882
888
|
}
|
|
883
889
|
prompt += `
|
|
884
890
|
|
|
885
|
-
Use read_history to catch up on important channels, then call
|
|
891
|
+
Use read_history to catch up on important channels, then call wait_for_message to listen for new messages.`;
|
|
886
892
|
if (driver.supportsStdinNotification) {
|
|
887
893
|
prompt += `
|
|
888
894
|
|
|
889
|
-
Note: While you are busy, you may receive [System notification: ...] messages. Finish your current step, then call
|
|
895
|
+
Note: While you are busy, you may receive [System notification: ...] messages. Finish your current step, then call check_messages to check for messages.`;
|
|
890
896
|
}
|
|
891
897
|
} else if (isResume) {
|
|
892
|
-
prompt = `No new messages while you were away. Call ${driver.mcpToolPrefix}
|
|
898
|
+
prompt = `No new messages while you were away. Call ${driver.mcpToolPrefix}wait_for_message to listen for new messages.`;
|
|
893
899
|
if (driver.supportsStdinNotification) {
|
|
894
900
|
prompt += `
|
|
895
901
|
|
|
896
|
-
Note: While you are busy, you may receive [System notification: ...] messages about new messages. Finish your current step, then call
|
|
902
|
+
Note: While you are busy, you may receive [System notification: ...] messages about new messages. Finish your current step, then call check_messages to check for messages.`;
|
|
897
903
|
}
|
|
898
904
|
} else {
|
|
899
905
|
prompt = driver.buildSystemPrompt(config, agentId);
|
|
@@ -915,7 +921,10 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
915
921
|
sessionId: config.sessionId || null,
|
|
916
922
|
isInReceiveMessage: false,
|
|
917
923
|
notificationTimer: null,
|
|
918
|
-
pendingNotificationCount: 0
|
|
924
|
+
pendingNotificationCount: 0,
|
|
925
|
+
activityHeartbeat: null,
|
|
926
|
+
lastActivity: "",
|
|
927
|
+
lastActivityDetail: ""
|
|
919
928
|
};
|
|
920
929
|
this.agents.set(agentId, agentProcess);
|
|
921
930
|
this.agentsStarting.delete(agentId);
|
|
@@ -950,24 +959,27 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
950
959
|
if (ap.notificationTimer) {
|
|
951
960
|
clearTimeout(ap.notificationTimer);
|
|
952
961
|
}
|
|
962
|
+
if (ap.activityHeartbeat) {
|
|
963
|
+
clearInterval(ap.activityHeartbeat);
|
|
964
|
+
}
|
|
953
965
|
this.agents.delete(agentId);
|
|
954
966
|
if (code === 0) {
|
|
955
967
|
this.idleAgentConfigs.set(agentId, {
|
|
956
968
|
config: { ...ap.config, sessionId: ap.sessionId },
|
|
957
969
|
sessionId: ap.sessionId
|
|
958
970
|
});
|
|
959
|
-
this.
|
|
971
|
+
this.broadcastActivity(agentId, "online", "Process idle");
|
|
960
972
|
} else {
|
|
961
973
|
this.idleAgentConfigs.delete(agentId);
|
|
962
974
|
const reason = code === null ? "killed by signal" : `exit code ${code}`;
|
|
963
975
|
console.error(`[Agent ${agentId}] Process crashed (${reason}) \u2014 marking inactive`);
|
|
964
976
|
this.sendToServer({ type: "agent:status", agentId, status: "inactive" });
|
|
965
|
-
this.
|
|
977
|
+
this.broadcastActivity(agentId, "offline", `Crashed (${reason})`);
|
|
966
978
|
}
|
|
967
979
|
}
|
|
968
980
|
});
|
|
969
981
|
this.sendToServer({ type: "agent:status", agentId, status: "active" });
|
|
970
|
-
this.
|
|
982
|
+
this.broadcastActivity(agentId, "working", "Starting\u2026");
|
|
971
983
|
} catch (err) {
|
|
972
984
|
this.agentsStarting.delete(agentId);
|
|
973
985
|
throw err;
|
|
@@ -984,11 +996,14 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
984
996
|
if (ap.notificationTimer) {
|
|
985
997
|
clearTimeout(ap.notificationTimer);
|
|
986
998
|
}
|
|
999
|
+
if (ap.activityHeartbeat) {
|
|
1000
|
+
clearInterval(ap.activityHeartbeat);
|
|
1001
|
+
}
|
|
987
1002
|
this.agents.delete(agentId);
|
|
988
1003
|
ap.process.kill("SIGTERM");
|
|
989
1004
|
if (!silent) {
|
|
990
1005
|
this.sendToServer({ type: "agent:status", agentId, status: "inactive" });
|
|
991
|
-
this.
|
|
1006
|
+
this.broadcastActivity(agentId, "offline", "Stopped");
|
|
992
1007
|
}
|
|
993
1008
|
if (wait) {
|
|
994
1009
|
await new Promise((resolve) => {
|
|
@@ -1023,6 +1038,10 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1023
1038
|
}
|
|
1024
1039
|
return;
|
|
1025
1040
|
}
|
|
1041
|
+
if (ap.isInReceiveMessage) {
|
|
1042
|
+
ap.isInReceiveMessage = false;
|
|
1043
|
+
this.broadcastActivity(agentId, "working", "Message received");
|
|
1044
|
+
}
|
|
1026
1045
|
if (ap.pendingReceive) {
|
|
1027
1046
|
clearTimeout(ap.pendingReceive.timer);
|
|
1028
1047
|
ap.pendingReceive.resolve([message]);
|
|
@@ -1169,11 +1188,37 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1169
1188
|
return { content, binary: false };
|
|
1170
1189
|
}
|
|
1171
1190
|
// Private methods
|
|
1191
|
+
/**
|
|
1192
|
+
* Broadcast an activity change — emits a single agent:activity event that carries
|
|
1193
|
+
* both the status (for the dot indicator) and trajectory entries (for the activity log).
|
|
1194
|
+
*/
|
|
1195
|
+
broadcastActivity(agentId, activity, detail, extraTrajectory = []) {
|
|
1196
|
+
const ap = this.agents.get(agentId);
|
|
1197
|
+
const entries = [...extraTrajectory];
|
|
1198
|
+
const hasToolStart = entries.some((e) => e.kind === "tool_start");
|
|
1199
|
+
if (!hasToolStart) {
|
|
1200
|
+
entries.push({ kind: "status", activity, detail });
|
|
1201
|
+
}
|
|
1202
|
+
this.sendToServer({ type: "agent:activity", agentId, activity, detail, entries });
|
|
1203
|
+
if (ap) {
|
|
1204
|
+
ap.lastActivity = activity;
|
|
1205
|
+
ap.lastActivityDetail = detail;
|
|
1206
|
+
if (activity === "working" || activity === "thinking") {
|
|
1207
|
+
if (!ap.activityHeartbeat) {
|
|
1208
|
+
ap.activityHeartbeat = setInterval(() => {
|
|
1209
|
+
this.sendToServer({ type: "agent:activity", agentId, activity: ap.lastActivity, detail: ap.lastActivityDetail });
|
|
1210
|
+
}, ACTIVITY_HEARTBEAT_MS);
|
|
1211
|
+
}
|
|
1212
|
+
} else {
|
|
1213
|
+
if (ap.activityHeartbeat) {
|
|
1214
|
+
clearInterval(ap.activityHeartbeat);
|
|
1215
|
+
ap.activityHeartbeat = null;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1172
1220
|
/** Handle a single ParsedEvent from any runtime driver */
|
|
1173
1221
|
handleParsedEvent(agentId, event, driver) {
|
|
1174
|
-
const trajectory = [];
|
|
1175
|
-
let activity = "";
|
|
1176
|
-
let detail = "";
|
|
1177
1222
|
const ap = this.agents.get(agentId);
|
|
1178
1223
|
switch (event.kind) {
|
|
1179
1224
|
case "session_init":
|
|
@@ -1182,54 +1227,39 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1182
1227
|
break;
|
|
1183
1228
|
case "thinking": {
|
|
1184
1229
|
const text = event.text.length > MAX_TRAJECTORY_TEXT ? event.text.slice(0, MAX_TRAJECTORY_TEXT) + "\u2026" : event.text;
|
|
1185
|
-
|
|
1186
|
-
|
|
1230
|
+
const extra = text ? [{ kind: "thinking", text }] : [];
|
|
1231
|
+
this.broadcastActivity(agentId, "thinking", "", extra);
|
|
1187
1232
|
if (ap) ap.isInReceiveMessage = false;
|
|
1188
1233
|
break;
|
|
1189
1234
|
}
|
|
1190
1235
|
case "text": {
|
|
1191
1236
|
const text = event.text.length > MAX_TRAJECTORY_TEXT ? event.text.slice(0, MAX_TRAJECTORY_TEXT) + "\u2026" : event.text;
|
|
1192
|
-
|
|
1193
|
-
activity = "thinking";
|
|
1237
|
+
this.broadcastActivity(agentId, "thinking", "", [{ kind: "text", text }]);
|
|
1194
1238
|
if (ap) ap.isInReceiveMessage = false;
|
|
1195
1239
|
break;
|
|
1196
1240
|
}
|
|
1197
1241
|
case "tool_call": {
|
|
1198
1242
|
const toolName = event.name;
|
|
1199
1243
|
const inputSummary = driver.summarizeToolInput(toolName, event.input);
|
|
1200
|
-
if (toolName === `${driver.mcpToolPrefix}
|
|
1201
|
-
|
|
1202
|
-
if (
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
ap.
|
|
1207
|
-
|
|
1208
|
-
clearTimeout(ap.notificationTimer);
|
|
1209
|
-
ap.notificationTimer = null;
|
|
1210
|
-
}
|
|
1244
|
+
if (toolName === `${driver.mcpToolPrefix}wait_for_message`) {
|
|
1245
|
+
this.broadcastActivity(agentId, "online", "Idle");
|
|
1246
|
+
if (ap) {
|
|
1247
|
+
ap.isInReceiveMessage = true;
|
|
1248
|
+
ap.pendingNotificationCount = 0;
|
|
1249
|
+
if (ap.notificationTimer) {
|
|
1250
|
+
clearTimeout(ap.notificationTimer);
|
|
1251
|
+
ap.notificationTimer = null;
|
|
1211
1252
|
}
|
|
1212
|
-
} else {
|
|
1213
|
-
trajectory.push({ kind: "tool_start", toolName, toolInput: inputSummary });
|
|
1214
|
-
activity = "working";
|
|
1215
|
-
detail = "Checking messages\u2026";
|
|
1216
|
-
if (ap) ap.isInReceiveMessage = false;
|
|
1217
1253
|
}
|
|
1218
|
-
} else if (toolName === `${driver.mcpToolPrefix}send_message`) {
|
|
1219
|
-
trajectory.push({ kind: "tool_start", toolName, toolInput: inputSummary });
|
|
1220
|
-
activity = "working";
|
|
1221
|
-
detail = "Sending message\u2026";
|
|
1222
|
-
if (ap) ap.isInReceiveMessage = false;
|
|
1223
1254
|
} else {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
detail = driver.toolDisplayName(toolName);
|
|
1255
|
+
const detail = toolName === `${driver.mcpToolPrefix}check_messages` ? "Checking messages\u2026" : toolName === `${driver.mcpToolPrefix}send_message` ? "Sending message\u2026" : driver.toolDisplayName(toolName);
|
|
1256
|
+
this.broadcastActivity(agentId, "working", detail, [{ kind: "tool_start", toolName, toolInput: inputSummary }]);
|
|
1227
1257
|
if (ap) ap.isInReceiveMessage = false;
|
|
1228
1258
|
}
|
|
1229
1259
|
break;
|
|
1230
1260
|
}
|
|
1231
1261
|
case "turn_end":
|
|
1232
|
-
|
|
1262
|
+
this.broadcastActivity(agentId, "online", "Turn complete");
|
|
1233
1263
|
if (ap) {
|
|
1234
1264
|
ap.isInReceiveMessage = false;
|
|
1235
1265
|
if (event.sessionId) ap.sessionId = event.sessionId;
|
|
@@ -1238,20 +1268,13 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1238
1268
|
this.sendToServer({ type: "agent:session", agentId, sessionId: event.sessionId });
|
|
1239
1269
|
}
|
|
1240
1270
|
break;
|
|
1241
|
-
case "error":
|
|
1242
|
-
|
|
1271
|
+
case "error": {
|
|
1272
|
+
const currentActivity = ap?.lastActivity || "working";
|
|
1273
|
+
const currentDetail = ap?.lastActivityDetail || "";
|
|
1274
|
+
this.sendToServer({ type: "agent:activity", agentId, activity: currentActivity, detail: currentDetail, entries: [{ kind: "text", text: `Error: ${event.message}` }] });
|
|
1243
1275
|
break;
|
|
1244
|
-
}
|
|
1245
|
-
if (activity) {
|
|
1246
|
-
this.sendToServer({ type: "agent:activity", agentId, activity, detail });
|
|
1247
|
-
const hasToolStart = trajectory.some((e) => e.kind === "tool_start");
|
|
1248
|
-
if (!hasToolStart) {
|
|
1249
|
-
trajectory.push({ kind: "status", activity, detail });
|
|
1250
1276
|
}
|
|
1251
1277
|
}
|
|
1252
|
-
if (trajectory.length > 0) {
|
|
1253
|
-
this.sendToServer({ type: "agent:trajectory", agentId, entries: trajectory });
|
|
1254
|
-
}
|
|
1255
1278
|
}
|
|
1256
1279
|
/** Send a batched notification to the agent via stdin about pending messages */
|
|
1257
1280
|
sendStdinNotification(agentId) {
|
|
@@ -1263,7 +1286,7 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1263
1286
|
if (count === 0) return;
|
|
1264
1287
|
if (ap.isInReceiveMessage) return;
|
|
1265
1288
|
if (!ap.sessionId) return;
|
|
1266
|
-
const notification = `[System notification: You have ${count} new message${count > 1 ? "s" : ""} waiting. Call
|
|
1289
|
+
const notification = `[System notification: You have ${count} new message${count > 1 ? "s" : ""} waiting. Call check_messages to read ${count > 1 ? "them" : "it"} when you're ready.]`;
|
|
1267
1290
|
console.log(`[Agent ${agentId}] Sending stdin notification: ${count} message(s)`);
|
|
1268
1291
|
const encoded = ap.driver.encodeStdinMessage(notification, ap.sessionId);
|
|
1269
1292
|
if (encoded) {
|