@slock-ai/daemon 0.2.1 → 0.2.3
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/{src/chat-bridge.ts → dist/chat-bridge.js} +81 -126
- package/{src/agentProcessManager.ts → dist/index.js} +403 -225
- package/package.json +8 -8
- package/src/connection.ts +0 -100
- package/src/index.ts +0 -154
|
@@ -1,141 +1,109 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/chat-bridge.ts
|
|
2
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
6
|
import { z } from "zod";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
let serverUrl = "http://localhost:3001";
|
|
10
|
-
let authToken = "";
|
|
11
|
-
|
|
7
|
+
var args = process.argv.slice(2);
|
|
8
|
+
var agentId = "";
|
|
9
|
+
var serverUrl = "http://localhost:3001";
|
|
10
|
+
var authToken = "";
|
|
12
11
|
for (let i = 0; i < args.length; i++) {
|
|
13
12
|
if (args[i] === "--agent-id" && args[i + 1]) agentId = args[++i];
|
|
14
13
|
if (args[i] === "--server-url" && args[i + 1]) serverUrl = args[++i];
|
|
15
14
|
if (args[i] === "--auth-token" && args[i + 1]) authToken = args[++i];
|
|
16
15
|
}
|
|
17
|
-
|
|
18
16
|
if (!agentId) {
|
|
19
17
|
console.error("Missing --agent-id");
|
|
20
18
|
process.exit(1);
|
|
21
19
|
}
|
|
22
|
-
|
|
23
|
-
// Build common headers for all requests
|
|
24
|
-
const commonHeaders: Record<string, string> = { "Content-Type": "application/json" };
|
|
20
|
+
var commonHeaders = { "Content-Type": "application/json" };
|
|
25
21
|
if (authToken) {
|
|
26
22
|
commonHeaders["Authorization"] = `Bearer ${authToken}`;
|
|
27
23
|
}
|
|
28
|
-
|
|
29
|
-
const server = new McpServer({
|
|
24
|
+
var server = new McpServer({
|
|
30
25
|
name: "chat",
|
|
31
|
-
version: "1.0.0"
|
|
26
|
+
version: "1.0.0"
|
|
32
27
|
});
|
|
33
|
-
|
|
34
|
-
// send_message tool
|
|
35
28
|
server.tool(
|
|
36
29
|
"send_message",
|
|
37
30
|
"Send a message to a channel or DM. To reply, reuse the channel value from the received message (e.g. channel='#all' or channel='DM:@richard'). To start a NEW DM, use dm_to with the person's name.",
|
|
38
31
|
{
|
|
39
|
-
channel: z
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
.string()
|
|
47
|
-
.optional()
|
|
48
|
-
.describe(
|
|
49
|
-
"Person's name to start a NEW DM with (e.g. 'richard'). Only for starting a new DM — to reply in an existing DM, use channel instead."
|
|
50
|
-
),
|
|
51
|
-
content: z.string().describe("The message content"),
|
|
32
|
+
channel: z.string().optional().describe(
|
|
33
|
+
"Where to send. Reuse the identifier from received messages: '#channel-name' for channels, 'DM:@peer-name' for DMs. Examples: '#all', '#general', 'DM:@richard'."
|
|
34
|
+
),
|
|
35
|
+
dm_to: z.string().optional().describe(
|
|
36
|
+
"Person's name to start a NEW DM with (e.g. 'richard'). Only for starting a new DM \u2014 to reply in an existing DM, use channel instead."
|
|
37
|
+
),
|
|
38
|
+
content: z.string().describe("The message content")
|
|
52
39
|
},
|
|
53
40
|
async ({ channel, dm_to, content }) => {
|
|
54
41
|
try {
|
|
55
42
|
const res = await fetch(`${serverUrl}/internal/agent/${agentId}/send`, {
|
|
56
43
|
method: "POST",
|
|
57
44
|
headers: commonHeaders,
|
|
58
|
-
body: JSON.stringify({ channel, dm_to, content })
|
|
45
|
+
body: JSON.stringify({ channel, dm_to, content })
|
|
59
46
|
});
|
|
60
47
|
const data = await res.json();
|
|
61
48
|
if (!res.ok) {
|
|
62
49
|
return {
|
|
63
50
|
content: [
|
|
64
|
-
{ type: "text"
|
|
65
|
-
]
|
|
51
|
+
{ type: "text", text: `Error: ${data.error}` }
|
|
52
|
+
]
|
|
66
53
|
};
|
|
67
54
|
}
|
|
68
55
|
return {
|
|
69
56
|
content: [
|
|
70
57
|
{
|
|
71
|
-
type: "text"
|
|
72
|
-
text: `Message sent to ${channel || `new DM with ${dm_to}`}
|
|
73
|
-
}
|
|
74
|
-
]
|
|
58
|
+
type: "text",
|
|
59
|
+
text: `Message sent to ${channel || `new DM with ${dm_to}`}`
|
|
60
|
+
}
|
|
61
|
+
]
|
|
75
62
|
};
|
|
76
|
-
} catch (err
|
|
63
|
+
} catch (err) {
|
|
77
64
|
return {
|
|
78
|
-
content: [{ type: "text"
|
|
65
|
+
content: [{ type: "text", text: `Error: ${err.message}` }]
|
|
79
66
|
};
|
|
80
67
|
}
|
|
81
68
|
}
|
|
82
69
|
);
|
|
83
|
-
|
|
84
|
-
// receive_message tool
|
|
85
70
|
server.tool(
|
|
86
71
|
"receive_message",
|
|
87
72
|
"Receive new messages. Use block=true to wait for new messages. Returns messages formatted as [#channel-name] or [DM:@peer-name] followed by the sender and content.",
|
|
88
73
|
{
|
|
89
|
-
block: z
|
|
90
|
-
|
|
91
|
-
.default(true)
|
|
92
|
-
.describe("Whether to block (wait) for new messages"),
|
|
93
|
-
timeout_ms: z
|
|
94
|
-
.number()
|
|
95
|
-
.default(59000)
|
|
96
|
-
.describe("How long to wait in ms when blocking (default 59s, just under MCP tool call timeout)"),
|
|
74
|
+
block: z.boolean().default(true).describe("Whether to block (wait) for new messages"),
|
|
75
|
+
timeout_ms: z.number().default(59e3).describe("How long to wait in ms when blocking (default 59s, just under MCP tool call timeout)")
|
|
97
76
|
},
|
|
98
77
|
async ({ block, timeout_ms }) => {
|
|
99
78
|
try {
|
|
100
79
|
const params = new URLSearchParams();
|
|
101
80
|
if (block) params.set("block", "true");
|
|
102
81
|
params.set("timeout", String(timeout_ms));
|
|
103
|
-
|
|
104
82
|
const res = await fetch(
|
|
105
83
|
`${serverUrl}/internal/agent/${agentId}/receive?${params}`,
|
|
106
84
|
{ method: "GET", headers: commonHeaders }
|
|
107
85
|
);
|
|
108
86
|
const data = await res.json();
|
|
109
|
-
|
|
110
87
|
if (!data.messages || data.messages.length === 0) {
|
|
111
88
|
return {
|
|
112
|
-
content: [{ type: "text"
|
|
89
|
+
content: [{ type: "text", text: "No new messages." }]
|
|
113
90
|
};
|
|
114
91
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
.
|
|
119
|
-
|
|
120
|
-
? `DM:@${m.channel_name}`
|
|
121
|
-
: `#${m.channel_name}`;
|
|
122
|
-
const senderPrefix = m.sender_type === "agent" ? "(agent) " : "";
|
|
123
|
-
return `[${channel}] ${senderPrefix}@${m.sender_name}: ${m.content}`;
|
|
124
|
-
})
|
|
125
|
-
.join("\n");
|
|
126
|
-
|
|
92
|
+
const formatted = data.messages.map((m) => {
|
|
93
|
+
const channel = m.channel_type === "dm" ? `DM:@${m.channel_name}` : `#${m.channel_name}`;
|
|
94
|
+
const senderPrefix = m.sender_type === "agent" ? "(agent) " : "";
|
|
95
|
+
return `[${channel}] ${senderPrefix}@${m.sender_name}: ${m.content}`;
|
|
96
|
+
}).join("\n");
|
|
127
97
|
return {
|
|
128
|
-
content: [{ type: "text"
|
|
98
|
+
content: [{ type: "text", text: formatted }]
|
|
129
99
|
};
|
|
130
|
-
} catch (err
|
|
100
|
+
} catch (err) {
|
|
131
101
|
return {
|
|
132
|
-
content: [{ type: "text"
|
|
102
|
+
content: [{ type: "text", text: `Error: ${err.message}` }]
|
|
133
103
|
};
|
|
134
104
|
}
|
|
135
105
|
}
|
|
136
106
|
);
|
|
137
|
-
|
|
138
|
-
// list_server tool
|
|
139
107
|
server.tool(
|
|
140
108
|
"list_server",
|
|
141
109
|
"List all channels you are in, all agents, and all humans in this server. Use this to discover who and where you can message.",
|
|
@@ -147,68 +115,55 @@ server.tool(
|
|
|
147
115
|
{ method: "GET", headers: commonHeaders }
|
|
148
116
|
);
|
|
149
117
|
const data = await res.json();
|
|
150
|
-
|
|
151
118
|
let text = "## Server\n\n";
|
|
152
|
-
|
|
153
119
|
text += "### Your Channels\n";
|
|
154
120
|
text += "Use `#channel-name` with send_message to post in a channel.\n";
|
|
155
121
|
if (data.channels?.length > 0) {
|
|
156
122
|
for (const t of data.channels) {
|
|
157
|
-
text += ` - #${t.name}
|
|
123
|
+
text += ` - #${t.name}
|
|
124
|
+
`;
|
|
158
125
|
}
|
|
159
126
|
} else {
|
|
160
127
|
text += " (none)\n";
|
|
161
128
|
}
|
|
162
|
-
|
|
163
129
|
text += "\n### Agents\n";
|
|
164
130
|
text += "Other AI agents in this server.\n";
|
|
165
131
|
if (data.agents?.length > 0) {
|
|
166
132
|
for (const a of data.agents) {
|
|
167
|
-
text += ` - @${a.name} (${a.status})
|
|
133
|
+
text += ` - @${a.name} (${a.status})
|
|
134
|
+
`;
|
|
168
135
|
}
|
|
169
136
|
} else {
|
|
170
137
|
text += " (none)\n";
|
|
171
138
|
}
|
|
172
|
-
|
|
173
139
|
text += "\n### Humans\n";
|
|
174
|
-
text +=
|
|
140
|
+
text += 'To start a new DM: send_message(dm_to="<name>"). To reply in an existing DM: reuse channel from the received message.\n';
|
|
175
141
|
if (data.humans?.length > 0) {
|
|
176
142
|
for (const u of data.humans) {
|
|
177
|
-
text += ` - @${u.name}
|
|
143
|
+
text += ` - @${u.name}
|
|
144
|
+
`;
|
|
178
145
|
}
|
|
179
146
|
} else {
|
|
180
147
|
text += " (none)\n";
|
|
181
148
|
}
|
|
182
|
-
|
|
183
149
|
return {
|
|
184
|
-
content: [{ type: "text"
|
|
150
|
+
content: [{ type: "text", text }]
|
|
185
151
|
};
|
|
186
|
-
} catch (err
|
|
152
|
+
} catch (err) {
|
|
187
153
|
return {
|
|
188
|
-
content: [{ type: "text"
|
|
154
|
+
content: [{ type: "text", text: `Error: ${err.message}` }]
|
|
189
155
|
};
|
|
190
156
|
}
|
|
191
157
|
}
|
|
192
158
|
);
|
|
193
|
-
|
|
194
|
-
// read_history tool
|
|
195
159
|
server.tool(
|
|
196
160
|
"read_history",
|
|
197
161
|
"Read message history for a channel or DM. Use #channel-name for channels or DM:@name for DMs. Supports pagination: use 'before' to load older messages, 'after' to load messages after a seq number (e.g. to catch up on unread).",
|
|
198
162
|
{
|
|
199
|
-
channel: z.string().describe("The channel to read history from
|
|
200
|
-
limit: z
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
.describe("Max number of messages to return (default 50, max 100)"),
|
|
204
|
-
before: z
|
|
205
|
-
.number()
|
|
206
|
-
.optional()
|
|
207
|
-
.describe("Return messages before this seq number (for backward pagination). Omit for latest messages."),
|
|
208
|
-
after: z
|
|
209
|
-
.number()
|
|
210
|
-
.optional()
|
|
211
|
-
.describe("Return messages after this seq number (for catching up on unread). Returns oldest-first."),
|
|
163
|
+
channel: z.string().describe("The channel to read history from \u2014 e.g. '#all', '#general', 'DM:@richard'"),
|
|
164
|
+
limit: z.number().default(50).describe("Max number of messages to return (default 50, max 100)"),
|
|
165
|
+
before: z.number().optional().describe("Return messages before this seq number (for backward pagination). Omit for latest messages."),
|
|
166
|
+
after: z.number().optional().describe("Return messages after this seq number (for catching up on unread). Returns oldest-first.")
|
|
212
167
|
},
|
|
213
168
|
async ({ channel, limit, before, after }) => {
|
|
214
169
|
try {
|
|
@@ -217,68 +172,68 @@ server.tool(
|
|
|
217
172
|
params.set("limit", String(Math.min(limit, 100)));
|
|
218
173
|
if (before) params.set("before", String(before));
|
|
219
174
|
if (after) params.set("after", String(after));
|
|
220
|
-
|
|
221
175
|
const res = await fetch(
|
|
222
176
|
`${serverUrl}/internal/agent/${agentId}/history?${params}`,
|
|
223
177
|
{ method: "GET", headers: commonHeaders }
|
|
224
178
|
);
|
|
225
179
|
const data = await res.json();
|
|
226
|
-
|
|
227
180
|
if (!res.ok) {
|
|
228
181
|
return {
|
|
229
182
|
content: [
|
|
230
|
-
{ type: "text"
|
|
231
|
-
]
|
|
183
|
+
{ type: "text", text: `Error: ${data.error}` }
|
|
184
|
+
]
|
|
232
185
|
};
|
|
233
186
|
}
|
|
234
|
-
|
|
235
187
|
if (!data.messages || data.messages.length === 0) {
|
|
236
188
|
return {
|
|
237
189
|
content: [
|
|
238
|
-
{ type: "text"
|
|
239
|
-
]
|
|
190
|
+
{ type: "text", text: "No messages in this channel." }
|
|
191
|
+
]
|
|
240
192
|
};
|
|
241
193
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
.
|
|
245
|
-
|
|
246
|
-
return `[seq:${m.seq}] ${senderPrefix}@${m.senderName}: ${m.content}`;
|
|
247
|
-
})
|
|
248
|
-
.join("\n");
|
|
249
|
-
|
|
194
|
+
const formatted = data.messages.map((m) => {
|
|
195
|
+
const senderPrefix = m.senderType === "agent" ? "(agent) " : "";
|
|
196
|
+
return `[seq:${m.seq}] ${senderPrefix}@${m.senderName}: ${m.content}`;
|
|
197
|
+
}).join("\n");
|
|
250
198
|
let footer = "";
|
|
251
|
-
if (data.
|
|
199
|
+
if (data.historyLimited) {
|
|
200
|
+
footer = `
|
|
201
|
+
|
|
202
|
+
--- ${data.historyLimitMessage || "Message history is limited on this plan."} ---`;
|
|
203
|
+
} else if (data.has_more && data.messages.length > 0) {
|
|
252
204
|
if (after) {
|
|
253
205
|
const maxSeq = data.messages[data.messages.length - 1].seq;
|
|
254
|
-
footer =
|
|
206
|
+
footer = `
|
|
207
|
+
|
|
208
|
+
--- ${data.messages.length} messages shown. Use after=${maxSeq} to load more recent messages. ---`;
|
|
255
209
|
} else {
|
|
256
210
|
const minSeq = data.messages[0].seq;
|
|
257
|
-
footer =
|
|
211
|
+
footer = `
|
|
212
|
+
|
|
213
|
+
--- ${data.messages.length} messages shown. Use before=${minSeq} to load older messages. ---`;
|
|
258
214
|
}
|
|
259
215
|
}
|
|
260
|
-
|
|
261
216
|
let header = `## Message History for ${channel} (${data.messages.length} messages)`;
|
|
262
217
|
if (data.last_read_seq > 0 && !after && !before) {
|
|
263
|
-
header +=
|
|
218
|
+
header += `
|
|
219
|
+
Your last read position: seq ${data.last_read_seq}. Use read_history(channel="${channel}", after=${data.last_read_seq}) to see only unread messages.`;
|
|
264
220
|
}
|
|
265
|
-
|
|
266
221
|
return {
|
|
267
222
|
content: [
|
|
268
223
|
{
|
|
269
|
-
type: "text"
|
|
270
|
-
text: `${header}
|
|
271
|
-
|
|
272
|
-
|
|
224
|
+
type: "text",
|
|
225
|
+
text: `${header}
|
|
226
|
+
|
|
227
|
+
${formatted}${footer}`
|
|
228
|
+
}
|
|
229
|
+
]
|
|
273
230
|
};
|
|
274
|
-
} catch (err
|
|
231
|
+
} catch (err) {
|
|
275
232
|
return {
|
|
276
|
-
content: [{ type: "text"
|
|
233
|
+
content: [{ type: "text", text: `Error: ${err.message}` }]
|
|
277
234
|
};
|
|
278
235
|
}
|
|
279
236
|
}
|
|
280
237
|
);
|
|
281
|
-
|
|
282
|
-
// Start MCP server
|
|
283
|
-
const transport = new StdioServerTransport();
|
|
238
|
+
var transport = new StdioServerTransport();
|
|
284
239
|
await server.connect(transport);
|