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: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
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",
|
||||
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.
|
||||
|
||||
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:
|
||||
- Be concise — Telegram messages should be short
|
||||
- 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": {
|
||||
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 => {
|
||||
const icon = p.status === "idle" ? "🟢" : p.status === "working" ? "🟡" : p.status === "dnd" ? "🔴" : "⚪";
|
||||
return `${icon} *${escMd(p.displayName)}*${p.summary ? ` — ${escMd(p.summary)}` : ""}`;
|
||||
}).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": {
|
||||
const memories = result as Array<{ content: string; tags: string[] }>;
|
||||
if (!memories || memories.length === 0) return "No memories found.";
|
||||
|
||||
@@ -1592,7 +1592,7 @@ function setupBotCommands(
|
||||
// Gather context for the AI
|
||||
const firstMeshId = meshIds[0]!;
|
||||
const firstConn = meshConnections.get(firstMeshId);
|
||||
const meshSlug = chatMeshSlugs.get(chatId)?.[0];
|
||||
const meshSlug = meshSlugs.get(firstMeshId) ?? firstMeshId.slice(0, 12);
|
||||
let recentPeers: string[] = [];
|
||||
if (firstConn?.isConnected()) {
|
||||
try {
|
||||
@@ -1706,12 +1706,27 @@ async function executeAiToolCall(
|
||||
case "list_peers":
|
||||
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 "recall":
|
||||
case "get_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.`);
|
||||
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user