@hasna/conversations 0.1.25 → 0.1.26
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/hook.js +23 -0
- package/bin/index.js +116 -109
- package/bin/mcp.js +112 -100
- package/dashboard/dist/assets/index-Bw0wMcXE.js +186 -0
- package/dashboard/dist/assets/index-CF_GDtNp.css +1 -0
- package/dashboard/dist/index.html +13 -0
- package/dashboard/dist/logo.jpg +0 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +80 -17
- package/dist/lib/identity.d.ts +0 -4
- package/dist/lib/presence.d.ts +3 -2
- package/dist/types.d.ts +15 -0
- package/package.json +1 -1
package/bin/mcp.js
CHANGED
|
@@ -6302,7 +6302,7 @@ var require_formats = __commonJS((exports) => {
|
|
|
6302
6302
|
}
|
|
6303
6303
|
var TIME = /^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;
|
|
6304
6304
|
function getTime(strictTimeZone) {
|
|
6305
|
-
return function
|
|
6305
|
+
return function time(str) {
|
|
6306
6306
|
const matches = TIME.exec(str);
|
|
6307
6307
|
if (!matches)
|
|
6308
6308
|
return false;
|
|
@@ -6600,9 +6600,13 @@ function getDb() {
|
|
|
6600
6600
|
`);
|
|
6601
6601
|
db.exec(`
|
|
6602
6602
|
CREATE TABLE IF NOT EXISTS agent_presence (
|
|
6603
|
+
id TEXT NOT NULL,
|
|
6603
6604
|
agent TEXT PRIMARY KEY,
|
|
6605
|
+
session_id TEXT,
|
|
6606
|
+
role TEXT NOT NULL DEFAULT 'agent',
|
|
6604
6607
|
status TEXT NOT NULL DEFAULT 'online',
|
|
6605
6608
|
last_seen_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
|
|
6609
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
|
|
6606
6610
|
metadata TEXT
|
|
6607
6611
|
)
|
|
6608
6612
|
`);
|
|
@@ -6681,6 +6685,25 @@ function getDb() {
|
|
|
6681
6685
|
db.exec("ALTER TABLE messages ADD COLUMN reply_to INTEGER REFERENCES messages(id)");
|
|
6682
6686
|
db.exec("CREATE INDEX IF NOT EXISTS idx_messages_reply_to ON messages(reply_to)");
|
|
6683
6687
|
}
|
|
6688
|
+
const presenceCols = db.prepare("PRAGMA table_info(agent_presence)").all();
|
|
6689
|
+
const presenceColNames = presenceCols.map((c) => c.name);
|
|
6690
|
+
if (!presenceColNames.includes("id")) {
|
|
6691
|
+
db.exec("ALTER TABLE agent_presence ADD COLUMN id TEXT NOT NULL DEFAULT ''");
|
|
6692
|
+
const rows = db.prepare("SELECT agent FROM agent_presence").all();
|
|
6693
|
+
for (const row of rows) {
|
|
6694
|
+
const id = crypto.randomUUID().slice(0, 8);
|
|
6695
|
+
db.prepare("UPDATE agent_presence SET id = ? WHERE agent = ?").run(id, row.agent);
|
|
6696
|
+
}
|
|
6697
|
+
}
|
|
6698
|
+
if (!presenceColNames.includes("session_id")) {
|
|
6699
|
+
db.exec("ALTER TABLE agent_presence ADD COLUMN session_id TEXT");
|
|
6700
|
+
}
|
|
6701
|
+
if (!presenceColNames.includes("role")) {
|
|
6702
|
+
db.exec("ALTER TABLE agent_presence ADD COLUMN role TEXT NOT NULL DEFAULT 'agent'");
|
|
6703
|
+
}
|
|
6704
|
+
if (!presenceColNames.includes("created_at")) {
|
|
6705
|
+
db.exec("ALTER TABLE agent_presence ADD COLUMN created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now'))");
|
|
6706
|
+
}
|
|
6684
6707
|
const ftsExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages_fts'").get();
|
|
6685
6708
|
if (!ftsExists) {
|
|
6686
6709
|
db.exec(`
|
|
@@ -27263,62 +27286,6 @@ class ExperimentalServerTasks {
|
|
|
27263
27286
|
requestStream(request, resultSchema, options) {
|
|
27264
27287
|
return this._server.requestStream(request, resultSchema, options);
|
|
27265
27288
|
}
|
|
27266
|
-
createMessageStream(params, options) {
|
|
27267
|
-
const clientCapabilities = this._server.getClientCapabilities();
|
|
27268
|
-
if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) {
|
|
27269
|
-
throw new Error("Client does not support sampling tools capability.");
|
|
27270
|
-
}
|
|
27271
|
-
if (params.messages.length > 0) {
|
|
27272
|
-
const lastMessage = params.messages[params.messages.length - 1];
|
|
27273
|
-
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
|
|
27274
|
-
const hasToolResults = lastContent.some((c) => c.type === "tool_result");
|
|
27275
|
-
const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : undefined;
|
|
27276
|
-
const previousContent = previousMessage ? Array.isArray(previousMessage.content) ? previousMessage.content : [previousMessage.content] : [];
|
|
27277
|
-
const hasPreviousToolUse = previousContent.some((c) => c.type === "tool_use");
|
|
27278
|
-
if (hasToolResults) {
|
|
27279
|
-
if (lastContent.some((c) => c.type !== "tool_result")) {
|
|
27280
|
-
throw new Error("The last message must contain only tool_result content if any is present");
|
|
27281
|
-
}
|
|
27282
|
-
if (!hasPreviousToolUse) {
|
|
27283
|
-
throw new Error("tool_result blocks are not matching any tool_use from the previous message");
|
|
27284
|
-
}
|
|
27285
|
-
}
|
|
27286
|
-
if (hasPreviousToolUse) {
|
|
27287
|
-
const toolUseIds = new Set(previousContent.filter((c) => c.type === "tool_use").map((c) => c.id));
|
|
27288
|
-
const toolResultIds = new Set(lastContent.filter((c) => c.type === "tool_result").map((c) => c.toolUseId));
|
|
27289
|
-
if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id) => toolResultIds.has(id))) {
|
|
27290
|
-
throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match");
|
|
27291
|
-
}
|
|
27292
|
-
}
|
|
27293
|
-
}
|
|
27294
|
-
return this.requestStream({
|
|
27295
|
-
method: "sampling/createMessage",
|
|
27296
|
-
params
|
|
27297
|
-
}, CreateMessageResultSchema, options);
|
|
27298
|
-
}
|
|
27299
|
-
elicitInputStream(params, options) {
|
|
27300
|
-
const clientCapabilities = this._server.getClientCapabilities();
|
|
27301
|
-
const mode = params.mode ?? "form";
|
|
27302
|
-
switch (mode) {
|
|
27303
|
-
case "url": {
|
|
27304
|
-
if (!clientCapabilities?.elicitation?.url) {
|
|
27305
|
-
throw new Error("Client does not support url elicitation.");
|
|
27306
|
-
}
|
|
27307
|
-
break;
|
|
27308
|
-
}
|
|
27309
|
-
case "form": {
|
|
27310
|
-
if (!clientCapabilities?.elicitation?.form) {
|
|
27311
|
-
throw new Error("Client does not support form elicitation.");
|
|
27312
|
-
}
|
|
27313
|
-
break;
|
|
27314
|
-
}
|
|
27315
|
-
}
|
|
27316
|
-
const normalizedParams = mode === "form" && params.mode === undefined ? { ...params, mode: "form" } : params;
|
|
27317
|
-
return this.requestStream({
|
|
27318
|
-
method: "elicitation/create",
|
|
27319
|
-
params: normalizedParams
|
|
27320
|
-
}, ElicitResultSchema, options);
|
|
27321
|
-
}
|
|
27322
27289
|
async getTask(taskId, options) {
|
|
27323
27290
|
return this._server.getTask({ taskId }, options);
|
|
27324
27291
|
}
|
|
@@ -29766,18 +29733,11 @@ function resolveIdentity(explicit) {
|
|
|
29766
29733
|
return envValue;
|
|
29767
29734
|
return getAutoName();
|
|
29768
29735
|
}
|
|
29769
|
-
function updateCachedAutoName(newName) {
|
|
29770
|
-
cachedAutoName = newName;
|
|
29771
|
-
try {
|
|
29772
|
-
mkdirSync3(dirname2(AGENT_ID_FILE), { recursive: true });
|
|
29773
|
-
writeFileSync(AGENT_ID_FILE, newName + `
|
|
29774
|
-
`, "utf-8");
|
|
29775
|
-
} catch {}
|
|
29776
|
-
}
|
|
29777
29736
|
|
|
29778
29737
|
// src/lib/presence.ts
|
|
29779
29738
|
init_db();
|
|
29780
29739
|
var ONLINE_THRESHOLD_SECONDS = 60;
|
|
29740
|
+
var CONFLICT_THRESHOLD_SECONDS = 30 * 60;
|
|
29781
29741
|
function parsePresence(row) {
|
|
29782
29742
|
let metadata = null;
|
|
29783
29743
|
if (row.metadata) {
|
|
@@ -29792,61 +29752,100 @@ function parsePresence(row) {
|
|
|
29792
29752
|
const nowMs = Date.now();
|
|
29793
29753
|
const online = nowMs - lastSeenMs < ONLINE_THRESHOLD_SECONDS * 1000;
|
|
29794
29754
|
return {
|
|
29755
|
+
id: row.id || "",
|
|
29795
29756
|
agent: row.agent,
|
|
29757
|
+
session_id: row.session_id ?? null,
|
|
29758
|
+
role: row.role || "agent",
|
|
29796
29759
|
status: row.status,
|
|
29797
29760
|
last_seen_at: lastSeenAt,
|
|
29761
|
+
created_at: row.created_at || lastSeenAt,
|
|
29798
29762
|
online,
|
|
29799
29763
|
metadata
|
|
29800
29764
|
};
|
|
29801
29765
|
}
|
|
29802
|
-
function
|
|
29766
|
+
function isActiveSession(lastSeenAt) {
|
|
29767
|
+
const lastSeenMs = new Date(lastSeenAt + "Z").getTime();
|
|
29768
|
+
const nowMs = Date.now();
|
|
29769
|
+
return nowMs - lastSeenMs < CONFLICT_THRESHOLD_SECONDS * 1000;
|
|
29770
|
+
}
|
|
29771
|
+
function registerAgent(name, sessionId, role) {
|
|
29772
|
+
const db2 = getDb();
|
|
29773
|
+
const existing = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(name);
|
|
29774
|
+
if (existing) {
|
|
29775
|
+
const lastSeenAt = existing.last_seen_at;
|
|
29776
|
+
const existingSessionId = existing.session_id;
|
|
29777
|
+
if (isActiveSession(lastSeenAt) && existingSessionId && existingSessionId !== sessionId) {
|
|
29778
|
+
return {
|
|
29779
|
+
error: "agent_conflict",
|
|
29780
|
+
message: `Agent "${name}" is already active (last seen: ${lastSeenAt}). Wait 30 minutes or use force takeover.`,
|
|
29781
|
+
existing_session_id: existingSessionId,
|
|
29782
|
+
last_seen_at: lastSeenAt
|
|
29783
|
+
};
|
|
29784
|
+
}
|
|
29785
|
+
const tookOver = existingSessionId !== sessionId;
|
|
29786
|
+
db2.prepare(`
|
|
29787
|
+
UPDATE agent_presence
|
|
29788
|
+
SET session_id = ?, role = ?, last_seen_at = strftime('%Y-%m-%dT%H:%M:%f', 'now')
|
|
29789
|
+
WHERE agent = ?
|
|
29790
|
+
`).run(sessionId, role || existing.role || "agent", name);
|
|
29791
|
+
const updated = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(name);
|
|
29792
|
+
return { agent: parsePresence(updated), created: false, took_over: tookOver };
|
|
29793
|
+
}
|
|
29794
|
+
const id = crypto.randomUUID().slice(0, 8);
|
|
29795
|
+
const resolvedRole = role || "agent";
|
|
29796
|
+
db2.prepare(`
|
|
29797
|
+
INSERT INTO agent_presence (id, agent, session_id, role, status, last_seen_at, created_at)
|
|
29798
|
+
VALUES (?, ?, ?, ?, 'online', strftime('%Y-%m-%dT%H:%M:%f', 'now'), strftime('%Y-%m-%dT%H:%M:%f', 'now'))
|
|
29799
|
+
`).run(id, name, sessionId, resolvedRole);
|
|
29800
|
+
const created = db2.prepare("SELECT * FROM agent_presence WHERE agent = ?").get(name);
|
|
29801
|
+
return { agent: parsePresence(created), created: true, took_over: false };
|
|
29802
|
+
}
|
|
29803
|
+
function heartbeat(agent, status, metadata, sessionId) {
|
|
29803
29804
|
const db2 = getDb();
|
|
29804
29805
|
const metadataJson = metadata ? JSON.stringify(metadata) : null;
|
|
29805
29806
|
const resolvedStatus = status || "online";
|
|
29806
|
-
const
|
|
29807
|
+
const existing = db2.prepare("SELECT id FROM agent_presence WHERE agent = ?").get(agent);
|
|
29808
|
+
const id = existing?.id || crypto.randomUUID().slice(0, 8);
|
|
29807
29809
|
db2.prepare(`
|
|
29808
|
-
INSERT INTO agent_presence (agent, status, last_seen_at, metadata)
|
|
29809
|
-
VALUES (?, ?, strftime('%Y-%m-%dT%H:%M:%f', 'now'), ?)
|
|
29810
|
+
INSERT INTO agent_presence (id, agent, session_id, role, status, last_seen_at, created_at, metadata)
|
|
29811
|
+
VALUES (?, ?, ?, 'agent', ?, strftime('%Y-%m-%dT%H:%M:%f', 'now'), strftime('%Y-%m-%dT%H:%M:%f', 'now'), ?)
|
|
29810
29812
|
ON CONFLICT(agent) DO UPDATE SET
|
|
29811
29813
|
status = excluded.status,
|
|
29812
29814
|
last_seen_at = excluded.last_seen_at,
|
|
29815
|
+
session_id = COALESCE(excluded.session_id, agent_presence.session_id),
|
|
29813
29816
|
metadata = excluded.metadata
|
|
29814
|
-
`).run(
|
|
29817
|
+
`).run(id, agent, sessionId ?? null, resolvedStatus, metadataJson);
|
|
29815
29818
|
}
|
|
29816
29819
|
function listAgents(opts) {
|
|
29817
29820
|
const db2 = getDb();
|
|
29818
29821
|
let query = "SELECT * FROM agent_presence";
|
|
29819
|
-
const params = [];
|
|
29820
29822
|
if (opts?.online_only) {
|
|
29821
29823
|
query += " WHERE last_seen_at > strftime('%Y-%m-%dT%H:%M:%f', 'now', '-60 seconds')";
|
|
29822
29824
|
}
|
|
29823
29825
|
query += " ORDER BY last_seen_at DESC";
|
|
29824
|
-
const rows = db2.prepare(query).all(
|
|
29826
|
+
const rows = db2.prepare(query).all();
|
|
29825
29827
|
return rows.map(parsePresence);
|
|
29826
29828
|
}
|
|
29827
29829
|
function removePresence(agent) {
|
|
29828
29830
|
const db2 = getDb();
|
|
29829
|
-
const
|
|
29830
|
-
const result = db2.prepare("DELETE FROM agent_presence WHERE LOWER(agent) = ?").run(normalizedAgent);
|
|
29831
|
+
const result = db2.prepare("DELETE FROM agent_presence WHERE agent = ?").run(agent);
|
|
29831
29832
|
return result.changes > 0;
|
|
29832
29833
|
}
|
|
29833
29834
|
function renameAgent(oldName, newName) {
|
|
29834
29835
|
const db2 = getDb();
|
|
29835
|
-
const
|
|
29836
|
-
const normalizedNew = newName.trim().toLowerCase();
|
|
29837
|
-
const existing = db2.prepare("SELECT agent FROM agent_presence WHERE LOWER(agent) = ?").get(normalizedOld);
|
|
29836
|
+
const existing = db2.prepare("SELECT agent FROM agent_presence WHERE agent = ?").get(oldName);
|
|
29838
29837
|
if (!existing)
|
|
29839
29838
|
return false;
|
|
29840
|
-
const conflict = db2.prepare("SELECT agent FROM agent_presence WHERE
|
|
29839
|
+
const conflict = db2.prepare("SELECT agent FROM agent_presence WHERE agent = ?").get(newName);
|
|
29841
29840
|
if (conflict)
|
|
29842
|
-
throw new Error(`Agent "${
|
|
29843
|
-
db2.prepare("UPDATE agent_presence SET agent = ? WHERE
|
|
29841
|
+
throw new Error(`Agent "${newName}" already exists`);
|
|
29842
|
+
db2.prepare("UPDATE agent_presence SET agent = ? WHERE agent = ?").run(newName, oldName);
|
|
29844
29843
|
return true;
|
|
29845
29844
|
}
|
|
29846
29845
|
// package.json
|
|
29847
29846
|
var package_default = {
|
|
29848
29847
|
name: "@hasna/conversations",
|
|
29849
|
-
version: "0.1.
|
|
29848
|
+
version: "0.1.26",
|
|
29850
29849
|
description: "Real-time CLI messaging for AI agents",
|
|
29851
29850
|
type: "module",
|
|
29852
29851
|
bin: {
|
|
@@ -29935,7 +29934,7 @@ server.registerTool("send_message", {
|
|
|
29935
29934
|
content: exports_external.string(),
|
|
29936
29935
|
from: exports_external.string().optional(),
|
|
29937
29936
|
priority: exports_external.string().optional(),
|
|
29938
|
-
blocking: exports_external.
|
|
29937
|
+
blocking: exports_external.boolean().optional()
|
|
29939
29938
|
}
|
|
29940
29939
|
}, async (args) => {
|
|
29941
29940
|
const { from: fromParam, to, content, priority, blocking } = args;
|
|
@@ -29959,8 +29958,8 @@ server.registerTool("read_messages", {
|
|
|
29959
29958
|
to: exports_external.string().optional(),
|
|
29960
29959
|
space: exports_external.string().optional(),
|
|
29961
29960
|
since: exports_external.string().optional(),
|
|
29962
|
-
limit: exports_external.
|
|
29963
|
-
unread_only: exports_external.
|
|
29961
|
+
limit: exports_external.number().optional(),
|
|
29962
|
+
unread_only: exports_external.boolean().optional()
|
|
29964
29963
|
}
|
|
29965
29964
|
}, async (args) => {
|
|
29966
29965
|
const messages = readMessages(args);
|
|
@@ -29983,7 +29982,7 @@ server.registerTool("list_sessions", {
|
|
|
29983
29982
|
server.registerTool("reply", {
|
|
29984
29983
|
description: "Reply to a message by ID.",
|
|
29985
29984
|
inputSchema: {
|
|
29986
|
-
message_id: exports_external.
|
|
29985
|
+
message_id: exports_external.number(),
|
|
29987
29986
|
content: exports_external.string(),
|
|
29988
29987
|
from: exports_external.string().optional()
|
|
29989
29988
|
}
|
|
@@ -30014,8 +30013,8 @@ server.registerTool("mark_read", {
|
|
|
30014
30013
|
description: "Mark messages read by IDs or all.",
|
|
30015
30014
|
inputSchema: {
|
|
30016
30015
|
from: exports_external.string().optional(),
|
|
30017
|
-
ids: exports_external.array(exports_external.
|
|
30018
|
-
all: exports_external.
|
|
30016
|
+
ids: exports_external.array(exports_external.number()).optional(),
|
|
30017
|
+
all: exports_external.boolean().optional()
|
|
30019
30018
|
}
|
|
30020
30019
|
}, async (args) => {
|
|
30021
30020
|
const { from: fromParam, ids, all } = args;
|
|
@@ -30042,7 +30041,7 @@ server.registerTool("search_messages", {
|
|
|
30042
30041
|
space: exports_external.string().optional(),
|
|
30043
30042
|
from: exports_external.string().optional(),
|
|
30044
30043
|
to: exports_external.string().optional(),
|
|
30045
|
-
limit: exports_external.
|
|
30044
|
+
limit: exports_external.number().optional()
|
|
30046
30045
|
}
|
|
30047
30046
|
}, async (args) => {
|
|
30048
30047
|
const { query, space, from, to, limit } = args;
|
|
@@ -30103,7 +30102,7 @@ server.registerTool("list_spaces", {
|
|
|
30103
30102
|
inputSchema: {
|
|
30104
30103
|
project_id: exports_external.string().optional(),
|
|
30105
30104
|
parent_id: exports_external.string().optional(),
|
|
30106
|
-
include_archived: exports_external.
|
|
30105
|
+
include_archived: exports_external.boolean().optional()
|
|
30107
30106
|
}
|
|
30108
30107
|
}, async (args) => {
|
|
30109
30108
|
const { project_id, parent_id, include_archived } = args;
|
|
@@ -30129,7 +30128,7 @@ server.registerTool("send_to_space", {
|
|
|
30129
30128
|
content: exports_external.string(),
|
|
30130
30129
|
from: exports_external.string().optional(),
|
|
30131
30130
|
priority: exports_external.string().optional(),
|
|
30132
|
-
blocking: exports_external.
|
|
30131
|
+
blocking: exports_external.boolean().optional()
|
|
30133
30132
|
}
|
|
30134
30133
|
}, async (args) => {
|
|
30135
30134
|
const { from: fromParam, space, content, priority, blocking } = args;
|
|
@@ -30159,7 +30158,7 @@ server.registerTool("read_space", {
|
|
|
30159
30158
|
inputSchema: {
|
|
30160
30159
|
space: exports_external.string(),
|
|
30161
30160
|
since: exports_external.string().optional(),
|
|
30162
|
-
limit: exports_external.
|
|
30161
|
+
limit: exports_external.number().optional()
|
|
30163
30162
|
}
|
|
30164
30163
|
}, async (args) => {
|
|
30165
30164
|
const { space, since, limit } = args;
|
|
@@ -30469,7 +30468,7 @@ server.registerTool("delete_project", {
|
|
|
30469
30468
|
server.registerTool("delete_message", {
|
|
30470
30469
|
description: "Delete a message (sender only).",
|
|
30471
30470
|
inputSchema: {
|
|
30472
|
-
id: exports_external.
|
|
30471
|
+
id: exports_external.number(),
|
|
30473
30472
|
from: exports_external.string().optional()
|
|
30474
30473
|
}
|
|
30475
30474
|
}, async (args) => {
|
|
@@ -30489,7 +30488,7 @@ server.registerTool("delete_message", {
|
|
|
30489
30488
|
server.registerTool("edit_message", {
|
|
30490
30489
|
description: "Edit message content (sender only).",
|
|
30491
30490
|
inputSchema: {
|
|
30492
|
-
id: exports_external.
|
|
30491
|
+
id: exports_external.number(),
|
|
30493
30492
|
content: exports_external.string(),
|
|
30494
30493
|
from: exports_external.string().optional()
|
|
30495
30494
|
}
|
|
@@ -30510,7 +30509,7 @@ server.registerTool("edit_message", {
|
|
|
30510
30509
|
server.registerTool("pin_message", {
|
|
30511
30510
|
description: "Pin a message.",
|
|
30512
30511
|
inputSchema: {
|
|
30513
|
-
id: exports_external.
|
|
30512
|
+
id: exports_external.number()
|
|
30514
30513
|
}
|
|
30515
30514
|
}, async ({ id }) => {
|
|
30516
30515
|
const msg = pinMessage(id);
|
|
@@ -30527,7 +30526,7 @@ server.registerTool("pin_message", {
|
|
|
30527
30526
|
server.registerTool("unpin_message", {
|
|
30528
30527
|
description: "Unpin a message.",
|
|
30529
30528
|
inputSchema: {
|
|
30530
|
-
id: exports_external.
|
|
30529
|
+
id: exports_external.number()
|
|
30531
30530
|
}
|
|
30532
30531
|
}, async ({ id }) => {
|
|
30533
30532
|
const msg = unpinMessage(id);
|
|
@@ -30546,7 +30545,7 @@ server.registerTool("get_pinned_messages", {
|
|
|
30546
30545
|
inputSchema: {
|
|
30547
30546
|
space: exports_external.string().optional(),
|
|
30548
30547
|
session_id: exports_external.string().optional(),
|
|
30549
|
-
limit: exports_external.
|
|
30548
|
+
limit: exports_external.number().optional()
|
|
30550
30549
|
}
|
|
30551
30550
|
}, async (args) => {
|
|
30552
30551
|
const { space, session_id, limit } = args;
|
|
@@ -30555,6 +30554,20 @@ server.registerTool("get_pinned_messages", {
|
|
|
30555
30554
|
content: [{ type: "text", text: JSON.stringify(messages) }]
|
|
30556
30555
|
};
|
|
30557
30556
|
});
|
|
30557
|
+
server.registerTool("register_agent", {
|
|
30558
|
+
description: "Register an agent with conflict detection. Returns AgentConflictError if another active session exists (active = heartbeat within last 30 min).",
|
|
30559
|
+
inputSchema: {
|
|
30560
|
+
name: exports_external.string(),
|
|
30561
|
+
session_id: exports_external.string(),
|
|
30562
|
+
role: exports_external.string().optional()
|
|
30563
|
+
}
|
|
30564
|
+
}, async (args) => {
|
|
30565
|
+
const { name, session_id, role } = args;
|
|
30566
|
+
const result = registerAgent(name, session_id, role);
|
|
30567
|
+
return {
|
|
30568
|
+
content: [{ type: "text", text: JSON.stringify(result) }]
|
|
30569
|
+
};
|
|
30570
|
+
});
|
|
30558
30571
|
server.registerTool("heartbeat", {
|
|
30559
30572
|
description: "Send presence heartbeat.",
|
|
30560
30573
|
inputSchema: {
|
|
@@ -30572,7 +30585,7 @@ server.registerTool("heartbeat", {
|
|
|
30572
30585
|
server.registerTool("list_agents", {
|
|
30573
30586
|
description: "List agents with presence status.",
|
|
30574
30587
|
inputSchema: {
|
|
30575
|
-
online_only: exports_external.
|
|
30588
|
+
online_only: exports_external.boolean().optional()
|
|
30576
30589
|
}
|
|
30577
30590
|
}, async (args) => {
|
|
30578
30591
|
const { online_only } = args;
|
|
@@ -30639,9 +30652,6 @@ server.registerTool("rename_agent", {
|
|
|
30639
30652
|
isError: true
|
|
30640
30653
|
};
|
|
30641
30654
|
}
|
|
30642
|
-
if (!fromParam) {
|
|
30643
|
-
updateCachedAutoName(newName);
|
|
30644
|
-
}
|
|
30645
30655
|
return {
|
|
30646
30656
|
content: [{ type: "text", text: JSON.stringify({ old_name: oldName, new_name: newName, renamed: true }) }]
|
|
30647
30657
|
};
|
|
@@ -30686,6 +30696,7 @@ server.registerTool("search_tools", {
|
|
|
30686
30696
|
"pin_message",
|
|
30687
30697
|
"unpin_message",
|
|
30688
30698
|
"get_pinned_messages",
|
|
30699
|
+
"register_agent",
|
|
30689
30700
|
"heartbeat",
|
|
30690
30701
|
"list_agents",
|
|
30691
30702
|
"get_blockers",
|
|
@@ -30731,6 +30742,7 @@ server.registerTool("describe_tools", {
|
|
|
30731
30742
|
pin_message: "Pin a message. Required: id",
|
|
30732
30743
|
unpin_message: "Unpin a message. Required: id",
|
|
30733
30744
|
get_pinned_messages: "Get pinned messages. Optional: space?, session_id?, limit?",
|
|
30745
|
+
register_agent: "Register agent with conflict detection (30min active window). Required: name, session_id. Optional: role?. Returns AgentConflictError if another session is active.",
|
|
30734
30746
|
heartbeat: "Register/refresh agent presence. Optional: from?, status?(online|busy|idle, default: online)",
|
|
30735
30747
|
list_agents: "List agents with presence timestamps. Optional: online_only?(only agents seen in last 60s)",
|
|
30736
30748
|
get_blockers: "Get unread blocking messages for agent. Optional: from?",
|