@sleep2agi/commhub-server 0.5.0-preview.2 → 0.5.0-preview.4
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/package.json +1 -1
- package/src/tools.ts +73 -5
package/package.json
CHANGED
package/src/tools.ts
CHANGED
|
@@ -35,8 +35,9 @@ export function registerTools(server: McpServer, clientIP?: string) {
|
|
|
35
35
|
config_path: z.string().max(1000).optional().describe("Config file path"),
|
|
36
36
|
channels: z.string().max(2000).optional().describe("JSON array of channels"),
|
|
37
37
|
model: z.string().max(200).optional().describe("AI model name"),
|
|
38
|
+
node_name: z.string().max(200).optional().describe("Stable node display name (may differ from alias)"),
|
|
38
39
|
},
|
|
39
|
-
async ({ resume_id, alias, status, task, output, score, progress, server: srv, hostname: hn, agent: ag, project_dir: pd, version: ver, tmux_name: tmux, node_id, session_id, config_path, channels, model: mdl }) => {
|
|
40
|
+
async ({ resume_id, alias, status, task, output, score, progress, server: srv, hostname: hn, agent: ag, project_dir: pd, version: ver, tmux_name: tmux, node_id, session_id, config_path, channels, model: mdl, node_name: nn }) => {
|
|
40
41
|
console.log(`[${ts()}] ${alias} (${resume_id.slice(0, 8)}) → report_status: ${status}${task ? " | " + task.slice(0, 60) : ""}`);
|
|
41
42
|
const trimmedOutput = output?.slice(0, 4000);
|
|
42
43
|
|
|
@@ -103,7 +104,7 @@ export function registerTools(server: McpServer, clientIP?: string) {
|
|
|
103
104
|
server = COALESCE(?8, nodes.server),
|
|
104
105
|
hostname = COALESCE(?9, nodes.hostname),
|
|
105
106
|
updated_at = datetime('now')`,
|
|
106
|
-
[node_id, alias, alias, nodeRuntime, mdl ?? null, config_path ?? null, channels ?? null, srv ?? null, hn ?? null]
|
|
107
|
+
[node_id, nn || alias, alias, nodeRuntime, mdl ?? null, config_path ?? null, channels ?? null, srv ?? null, hn ?? null]
|
|
107
108
|
);
|
|
108
109
|
} catch {}
|
|
109
110
|
}
|
|
@@ -319,8 +320,9 @@ export function registerTools(server: McpServer, clientIP?: string) {
|
|
|
319
320
|
priority: z.enum(["high", "normal", "low"]).optional().default("normal"),
|
|
320
321
|
context: z.string().max(10000).optional(),
|
|
321
322
|
from_session: z.string().max(200).optional().default("hub"),
|
|
323
|
+
ttl_seconds: z.number().min(1).max(86400).optional().describe("Task TTL in seconds (default: 3600)"),
|
|
322
324
|
},
|
|
323
|
-
async ({ alias, task, priority, context, from_session }) => {
|
|
325
|
+
async ({ alias, task, priority, context, from_session, ttl_seconds }) => {
|
|
324
326
|
console.log(`[${ts()}] ${from_session} → send_task → ${alias}: ${task.slice(0, 60)}${priority === "high" ? " [HIGH]" : ""}`);
|
|
325
327
|
const id = uuidv4();
|
|
326
328
|
// 事务:inbox + tasks 双写
|
|
@@ -333,8 +335,8 @@ export function registerTools(server: McpServer, clientIP?: string) {
|
|
|
333
335
|
);
|
|
334
336
|
db.run(
|
|
335
337
|
`INSERT INTO tasks (task_id, from_name, to_name, priority, status, content, requires_response, created_at, delivered_at, expires_at)
|
|
336
|
-
VALUES (?1, ?2, ?3, ?4, 'delivered', ?5, 'reply', datetime('now'), datetime('now'), datetime('now',
|
|
337
|
-
[id, from_session, alias, priority, task]
|
|
338
|
+
VALUES (?1, ?2, ?3, ?4, 'delivered', ?5, 'reply', datetime('now'), datetime('now'), datetime('now', ?6))`,
|
|
339
|
+
[id, from_session, alias, priority, task, `+${ttl_seconds || 3600} seconds`]
|
|
338
340
|
);
|
|
339
341
|
db.run("COMMIT");
|
|
340
342
|
} catch (e) {
|
|
@@ -475,6 +477,72 @@ export function registerTools(server: McpServer, clientIP?: string) {
|
|
|
475
477
|
}
|
|
476
478
|
);
|
|
477
479
|
|
|
480
|
+
// ── V2: retry_task (重新投递失败/过期任务) ──
|
|
481
|
+
server.tool(
|
|
482
|
+
"retry_task",
|
|
483
|
+
"Retry a failed, expired, or cancelled task. Resets status to delivered and re-queues in inbox.",
|
|
484
|
+
{
|
|
485
|
+
task_id: z.string().min(1).max(200).describe("Task ID to retry"),
|
|
486
|
+
from_session: z.string().max(200).optional().default("hub"),
|
|
487
|
+
},
|
|
488
|
+
async ({ task_id, from_session }) => {
|
|
489
|
+
console.log(`[${ts()}] ${from_session} → retry_task → ${task_id.slice(0, 8)}`);
|
|
490
|
+
// Find the original task
|
|
491
|
+
const task = db.query<any, [string]>(
|
|
492
|
+
"SELECT * FROM tasks WHERE task_id = ?1"
|
|
493
|
+
).get(task_id);
|
|
494
|
+
if (!task) {
|
|
495
|
+
return { content: [{ type: "text" as const, text: JSON.stringify({ ok: false, error: "task not found" }) }] };
|
|
496
|
+
}
|
|
497
|
+
if (!["failed", "expired", "cancelled"].includes(task.status)) {
|
|
498
|
+
return { content: [{ type: "text" as const, text: JSON.stringify({ ok: false, error: `task status is ${task.status}, not retryable` }) }] };
|
|
499
|
+
}
|
|
500
|
+
try {
|
|
501
|
+
db.run("BEGIN IMMEDIATE");
|
|
502
|
+
// Reset task status
|
|
503
|
+
db.run(
|
|
504
|
+
`UPDATE tasks SET status = 'delivered', result = NULL, completed_at = NULL, started_at = NULL, delivered_at = datetime('now'), expires_at = datetime('now', '+1 hour')
|
|
505
|
+
WHERE task_id = ?1`,
|
|
506
|
+
[task_id]
|
|
507
|
+
);
|
|
508
|
+
// Re-queue in inbox with new ID (original ID may already exist)
|
|
509
|
+
const retryInboxId = uuidv4();
|
|
510
|
+
db.run(
|
|
511
|
+
`INSERT INTO inbox (id, session_name, type, priority, content, from_session, requires_response)
|
|
512
|
+
VALUES (?1, ?2, 'task', ?3, ?4, ?5, 'reply')`,
|
|
513
|
+
[retryInboxId, task.to_name, task.priority, task.content, from_session]
|
|
514
|
+
);
|
|
515
|
+
db.run("COMMIT");
|
|
516
|
+
} catch (e) {
|
|
517
|
+
try { db.run("ROLLBACK"); } catch {}
|
|
518
|
+
throw e;
|
|
519
|
+
}
|
|
520
|
+
// SSE push
|
|
521
|
+
pushEvent(task.to_name, { type: "new_task", inbox_count: 1, priority: task.priority, from: from_session });
|
|
522
|
+
return {
|
|
523
|
+
content: [{ type: "text" as const, text: JSON.stringify({ ok: true, task_id, retried_to: task.to_name }) }],
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
);
|
|
527
|
+
|
|
528
|
+
// ── V2: get_task (查询任务状态) ──
|
|
529
|
+
server.tool(
|
|
530
|
+
"get_task",
|
|
531
|
+
"Get task details by task_id. Returns status, result, timestamps.",
|
|
532
|
+
{
|
|
533
|
+
task_id: z.string().min(1).max(200).describe("Task ID to query"),
|
|
534
|
+
},
|
|
535
|
+
async ({ task_id }) => {
|
|
536
|
+
const task = db.query<any, [string]>("SELECT * FROM tasks WHERE task_id = ?1").get(task_id);
|
|
537
|
+
return {
|
|
538
|
+
content: [{
|
|
539
|
+
type: "text" as const,
|
|
540
|
+
text: JSON.stringify(task ? { ok: true, task } : { ok: false, error: "task not found" }),
|
|
541
|
+
}],
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
);
|
|
545
|
+
|
|
478
546
|
server.tool(
|
|
479
547
|
"broadcast",
|
|
480
548
|
"Send a message to multiple sessions.",
|