stream0-channel 0.4.1 → 0.5.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/bin/stream0-channel.mjs +123 -2
- package/package.json +1 -1
package/bin/stream0-channel.mjs
CHANGED
|
@@ -79,8 +79,9 @@ const mcp = new Server(
|
|
|
79
79
|
|
|
80
80
|
When the user asks you to collaborate with, delegate to, or consult other agents:
|
|
81
81
|
1. Use the **discover** tool to see which agents are available and what they do
|
|
82
|
-
2.
|
|
83
|
-
3.
|
|
82
|
+
2. For a single agent: use **delegate** to send a task and wait for the result
|
|
83
|
+
3. For multiple agents in parallel: use **send_task** for each, then **wait_results** to collect all responses
|
|
84
|
+
4. Present the results to the user
|
|
84
85
|
|
|
85
86
|
Examples of user requests that should trigger collaboration:
|
|
86
87
|
- "find someone to review my code"
|
|
@@ -163,6 +164,44 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
163
164
|
required: ["to", "thread_id", "type", "content"],
|
|
164
165
|
},
|
|
165
166
|
},
|
|
167
|
+
{
|
|
168
|
+
name: "send_task",
|
|
169
|
+
description:
|
|
170
|
+
"Send a task to an agent and return immediately without waiting for a response. Returns a thread_id you can pass to wait_results later. Use this when sending tasks to multiple agents in parallel.",
|
|
171
|
+
inputSchema: {
|
|
172
|
+
type: "object",
|
|
173
|
+
properties: {
|
|
174
|
+
to: { type: "string", description: "The agent ID to send the task to" },
|
|
175
|
+
task: { type: "string", description: "Description of what you need the agent to do" },
|
|
176
|
+
context: { type: "string", description: "Additional context like code diffs or file contents" },
|
|
177
|
+
},
|
|
178
|
+
required: ["to", "task"],
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: "wait_results",
|
|
183
|
+
description:
|
|
184
|
+
"Wait for results from one or more agents that were given tasks via send_task. Pass the thread_ids returned by send_task. Returns all results once every agent has responded (done or failed), or when timeout is reached.",
|
|
185
|
+
inputSchema: {
|
|
186
|
+
type: "object",
|
|
187
|
+
properties: {
|
|
188
|
+
threads: {
|
|
189
|
+
type: "array",
|
|
190
|
+
items: {
|
|
191
|
+
type: "object",
|
|
192
|
+
properties: {
|
|
193
|
+
thread_id: { type: "string" },
|
|
194
|
+
from: { type: "string", description: "The agent ID that should respond" },
|
|
195
|
+
},
|
|
196
|
+
required: ["thread_id", "from"],
|
|
197
|
+
},
|
|
198
|
+
description: "List of {thread_id, from} pairs to wait for",
|
|
199
|
+
},
|
|
200
|
+
timeout: { type: "number", description: "Max seconds to wait (default: 120, max: 300)" },
|
|
201
|
+
},
|
|
202
|
+
required: ["threads"],
|
|
203
|
+
},
|
|
204
|
+
},
|
|
166
205
|
{
|
|
167
206
|
name: "ack",
|
|
168
207
|
description: "Acknowledge a message after processing it so it won't appear again.",
|
|
@@ -317,6 +356,88 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
317
356
|
};
|
|
318
357
|
}
|
|
319
358
|
|
|
359
|
+
// --- send_task (agent-auth, fire-and-forget) ---
|
|
360
|
+
if (name === "send_task") {
|
|
361
|
+
const { to, task, context } = args;
|
|
362
|
+
const threadId = `task-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
363
|
+
|
|
364
|
+
const content = { task };
|
|
365
|
+
if (context) content.context = context;
|
|
366
|
+
|
|
367
|
+
await stream0Post(`/agents/${to}/inbox`, {
|
|
368
|
+
thread_id: threadId,
|
|
369
|
+
type: "request",
|
|
370
|
+
content,
|
|
371
|
+
}, true);
|
|
372
|
+
|
|
373
|
+
console.error(`[stream0-channel] Sent task to ${to} (thread: ${threadId})`);
|
|
374
|
+
|
|
375
|
+
return {
|
|
376
|
+
content: [
|
|
377
|
+
{ type: "text", text: `Task sent to **${to}** (thread: ${threadId})` },
|
|
378
|
+
],
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// --- wait_results (agent-auth, poll multiple threads) ---
|
|
383
|
+
if (name === "wait_results") {
|
|
384
|
+
const { threads, timeout: userTimeout } = args;
|
|
385
|
+
const timeoutSec = Math.min(Math.max(userTimeout || 120, 10), 300);
|
|
386
|
+
const deadline = Date.now() + timeoutSec * 1000;
|
|
387
|
+
|
|
388
|
+
// Track which threads we're still waiting for
|
|
389
|
+
const pending = new Map(); // thread_id -> from
|
|
390
|
+
for (const t of threads) pending.set(t.thread_id, t.from);
|
|
391
|
+
|
|
392
|
+
const results = []; // { from, thread_id, type, content }
|
|
393
|
+
|
|
394
|
+
console.error(`[stream0-channel] Waiting for ${pending.size} results (timeout: ${timeoutSec}s)...`);
|
|
395
|
+
|
|
396
|
+
while (pending.size > 0 && Date.now() < deadline) {
|
|
397
|
+
const pollTimeout = Math.min(25, Math.ceil((deadline - Date.now()) / 1000));
|
|
398
|
+
if (pollTimeout <= 0) break;
|
|
399
|
+
|
|
400
|
+
const result = await stream0Get(`/agents/${AGENT_ID}/inbox`, {
|
|
401
|
+
status: "unread",
|
|
402
|
+
timeout: String(pollTimeout),
|
|
403
|
+
}, true);
|
|
404
|
+
|
|
405
|
+
for (const msg of result?.messages || []) {
|
|
406
|
+
if (!pending.has(msg.thread_id)) continue;
|
|
407
|
+
|
|
408
|
+
await stream0Post(`/inbox/messages/${msg.id}/ack`, undefined, true);
|
|
409
|
+
|
|
410
|
+
if (msg.type === "done" || msg.type === "failed") {
|
|
411
|
+
results.push({
|
|
412
|
+
from: msg.from,
|
|
413
|
+
thread_id: msg.thread_id,
|
|
414
|
+
type: msg.type,
|
|
415
|
+
content: msg.content,
|
|
416
|
+
});
|
|
417
|
+
pending.delete(msg.thread_id);
|
|
418
|
+
console.error(`[stream0-channel] Got [${msg.type}] from ${msg.from} (${pending.size} remaining)`);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Format output
|
|
424
|
+
const lines = results.map((r) => {
|
|
425
|
+
const contentText = typeof r.content === "string" ? r.content : JSON.stringify(r.content, null, 2);
|
|
426
|
+
return `### ${r.from} (${r.type})\n${contentText}`;
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
if (pending.size > 0) {
|
|
430
|
+
const timedOut = [...pending.values()];
|
|
431
|
+
lines.push(`\n**Timed out** waiting for: ${timedOut.join(", ")}`);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
return {
|
|
435
|
+
content: [
|
|
436
|
+
{ type: "text", text: `## Results (${results.length}/${threads.length})\n\n${lines.join("\n\n")}` },
|
|
437
|
+
],
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
320
441
|
// --- reply (agent-auth) ---
|
|
321
442
|
if (name === "reply") {
|
|
322
443
|
const { to, thread_id, type, content } = args;
|