feat(broker): add list_meshes tool + multilingual AI responses
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,14 @@ const TOOLS: AiTool[] = [
|
|||||||
properties: {},
|
properties: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "list_meshes",
|
||||||
|
description: "List all meshes this Telegram chat is connected to. Use when user asks about their meshes, which meshes are available, or wants to see their workspace list.",
|
||||||
|
input_schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "remember",
|
name: "remember",
|
||||||
description: "Store a memory/note in the mesh's shared knowledge. Use when user wants to save information for later.",
|
description: "Store a memory/note in the mesh's shared knowledge. Use when user wants to save information for later.",
|
||||||
@@ -140,6 +148,8 @@ const SYSTEM_PROMPT = `You are the claudemesh Telegram assistant. You help users
|
|||||||
|
|
||||||
You have access to tools for mesh operations. When the user's intent maps to a tool, use it. When it's a general question or conversation, respond directly.
|
You have access to tools for mesh operations. When the user's intent maps to a tool, use it. When it's a general question or conversation, respond directly.
|
||||||
|
|
||||||
|
IMPORTANT: Always respond in the same language the user writes in. If they write in Spanish, respond in Spanish. If English, respond in English.
|
||||||
|
|
||||||
Rules:
|
Rules:
|
||||||
- Be concise — Telegram messages should be short
|
- Be concise — Telegram messages should be short
|
||||||
- When sending messages to peers, preserve the user's tone and intent
|
- When sending messages to peers, preserve the user's tone and intent
|
||||||
@@ -246,13 +256,21 @@ export function formatResult(toolName: string, result: unknown): string {
|
|||||||
|
|
||||||
case "list_peers": {
|
case "list_peers": {
|
||||||
const peers = result as Array<{ displayName: string; status: string; summary?: string }>;
|
const peers = result as Array<{ displayName: string; status: string; summary?: string }>;
|
||||||
if (!peers || peers.length === 0) return "No peers online.";
|
if (!peers || peers.length === 0) return "No peers online\\.";
|
||||||
return "👥 *Online peers:*\n\n" + peers.map(p => {
|
return "👥 *Online peers:*\n\n" + peers.map(p => {
|
||||||
const icon = p.status === "idle" ? "🟢" : p.status === "working" ? "🟡" : p.status === "dnd" ? "🔴" : "⚪";
|
const icon = p.status === "idle" ? "🟢" : p.status === "working" ? "🟡" : p.status === "dnd" ? "🔴" : "⚪";
|
||||||
return `${icon} *${escMd(p.displayName)}*${p.summary ? ` — ${escMd(p.summary)}` : ""}`;
|
return `${icon} *${escMd(p.displayName)}*${p.summary ? ` — ${escMd(p.summary)}` : ""}`;
|
||||||
}).join("\n");
|
}).join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "list_meshes": {
|
||||||
|
const meshes = result as Array<{ slug: string; peers: number }>;
|
||||||
|
if (!meshes || meshes.length === 0) return "No meshes connected\\. Use /connect to add one\\.";
|
||||||
|
return "🔗 *Connected meshes:*\n\n" + meshes.map(m =>
|
||||||
|
`• *${escMd(m.slug)}* — ${m.peers} peer${m.peers !== 1 ? "s" : ""} online`
|
||||||
|
).join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
case "recall": {
|
case "recall": {
|
||||||
const memories = result as Array<{ content: string; tags: string[] }>;
|
const memories = result as Array<{ content: string; tags: string[] }>;
|
||||||
if (!memories || memories.length === 0) return "No memories found.";
|
if (!memories || memories.length === 0) return "No memories found.";
|
||||||
|
|||||||
@@ -1592,7 +1592,7 @@ function setupBotCommands(
|
|||||||
// Gather context for the AI
|
// Gather context for the AI
|
||||||
const firstMeshId = meshIds[0]!;
|
const firstMeshId = meshIds[0]!;
|
||||||
const firstConn = meshConnections.get(firstMeshId);
|
const firstConn = meshConnections.get(firstMeshId);
|
||||||
const meshSlug = chatMeshSlugs.get(chatId)?.[0];
|
const meshSlug = meshSlugs.get(firstMeshId) ?? firstMeshId.slice(0, 12);
|
||||||
let recentPeers: string[] = [];
|
let recentPeers: string[] = [];
|
||||||
if (firstConn?.isConnected()) {
|
if (firstConn?.isConnected()) {
|
||||||
try {
|
try {
|
||||||
@@ -1706,12 +1706,27 @@ async function executeAiToolCall(
|
|||||||
case "list_peers":
|
case "list_peers":
|
||||||
return conn.listPeers();
|
return conn.listPeers();
|
||||||
|
|
||||||
|
case "list_meshes": {
|
||||||
|
const results: Array<{ slug: string; peers: number }> = [];
|
||||||
|
for (const meshId of meshIds) {
|
||||||
|
const conn = meshConnections.get(meshId);
|
||||||
|
const slug = meshSlugs.get(meshId) ?? meshId.slice(0, 12);
|
||||||
|
let peerCount = 0;
|
||||||
|
if (conn?.isConnected()) {
|
||||||
|
try {
|
||||||
|
const peers = await conn.listPeers();
|
||||||
|
peerCount = peers.length;
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
results.push({ slug, peers: peerCount });
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
case "remember":
|
case "remember":
|
||||||
case "recall":
|
case "recall":
|
||||||
case "get_state":
|
case "get_state":
|
||||||
case "set_state":
|
case "set_state":
|
||||||
// These operations require WS request/response patterns not yet
|
|
||||||
// implemented in MeshConnection. Coming in a future update.
|
|
||||||
throw new Error(`${toolCall.name} not yet available via Telegram. Use the CLI.`);
|
throw new Error(`${toolCall.name} not yet available via Telegram. Use the CLI.`);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user