@hailer/mcp 0.0.1
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/.claude/commands/tool-builder.md +37 -0
- package/.claude/commands/ws-pull.md +44 -0
- package/.claude/settings.json +8 -0
- package/.claude/settings.local.json +49 -0
- package/.claude/skills/activity-api/SKILL.md +96 -0
- package/.claude/skills/activity-api/references/activity-endpoints.md +845 -0
- package/.claude/skills/add-app-member-skill/SKILL.md +977 -0
- package/.claude/skills/agent-building/SKILL.md +243 -0
- package/.claude/skills/agent-building/references/architecture-patterns.md +446 -0
- package/.claude/skills/agent-building/references/code-examples.md +587 -0
- package/.claude/skills/agent-building/references/implementation-guide.md +619 -0
- package/.claude/skills/app-api/SKILL.md +219 -0
- package/.claude/skills/app-api/references/app-endpoints.md +759 -0
- package/.claude/skills/building-hailer-apps-skill/SKILL.md +548 -0
- package/.claude/skills/create-app-skill/SKILL.md +1101 -0
- package/.claude/skills/create-insight-skill/SKILL.md +1317 -0
- package/.claude/skills/get-insight-data-skill/SKILL.md +1053 -0
- package/.claude/skills/hailer-api/SKILL.md +283 -0
- package/.claude/skills/hailer-api/references/activities.md +620 -0
- package/.claude/skills/hailer-api/references/authentication.md +216 -0
- package/.claude/skills/hailer-api/references/datasets.md +437 -0
- package/.claude/skills/hailer-api/references/files.md +301 -0
- package/.claude/skills/hailer-api/references/insights.md +469 -0
- package/.claude/skills/hailer-api/references/workflows.md +720 -0
- package/.claude/skills/hailer-api/references/workspaces-users.md +445 -0
- package/.claude/skills/insight-api/SKILL.md +185 -0
- package/.claude/skills/insight-api/references/insight-endpoints.md +514 -0
- package/.claude/skills/install-workflow-skill/SKILL.md +1056 -0
- package/.claude/skills/list-apps-skill/SKILL.md +1010 -0
- package/.claude/skills/list-workflows-minimal-skill/SKILL.md +992 -0
- package/.claude/skills/local-first-skill/SKILL.md +570 -0
- package/.claude/skills/mcp-tools/SKILL.md +419 -0
- package/.claude/skills/mcp-tools/references/api-endpoints.md +499 -0
- package/.claude/skills/mcp-tools/references/data-structures.md +554 -0
- package/.claude/skills/mcp-tools/references/implementation-patterns.md +717 -0
- package/.claude/skills/preview-insight-skill/SKILL.md +1290 -0
- package/.claude/skills/publish-hailer-app-skill/SKILL.md +453 -0
- package/.claude/skills/remove-app-member-skill/SKILL.md +671 -0
- package/.claude/skills/remove-app-skill/SKILL.md +985 -0
- package/.claude/skills/remove-insight-skill/SKILL.md +1011 -0
- package/.claude/skills/remove-workflow-skill/SKILL.md +920 -0
- package/.claude/skills/scaffold-hailer-app-skill/SKILL.md +1034 -0
- package/.claude/skills/skill-testing/README.md +137 -0
- package/.claude/skills/skill-testing/SKILL.md +348 -0
- package/.claude/skills/skill-testing/references/test-patterns.md +705 -0
- package/.claude/skills/skill-testing/references/testing-guide.md +603 -0
- package/.claude/skills/skill-testing/references/validation-checklist.md +537 -0
- package/.claude/skills/tool-builder/SKILL.md +328 -0
- package/.claude/skills/update-app-skill/SKILL.md +970 -0
- package/.claude/skills/update-workflow-field-skill/SKILL.md +1098 -0
- package/.env.example +81 -0
- package/.mcp.json +13 -0
- package/README.md +297 -0
- package/dist/app.d.ts +4 -0
- package/dist/app.js +74 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +5 -0
- package/dist/client/adaptive-documentation-bot.d.ts +108 -0
- package/dist/client/adaptive-documentation-bot.js +475 -0
- package/dist/client/adaptive-documentation-types.d.ts +66 -0
- package/dist/client/adaptive-documentation-types.js +9 -0
- package/dist/client/agent-activity-bot.d.ts +51 -0
- package/dist/client/agent-activity-bot.js +166 -0
- package/dist/client/agent-tracker.d.ts +499 -0
- package/dist/client/agent-tracker.js +659 -0
- package/dist/client/description-updater.d.ts +56 -0
- package/dist/client/description-updater.js +259 -0
- package/dist/client/log-parser.d.ts +72 -0
- package/dist/client/log-parser.js +387 -0
- package/dist/client/mcp-client.d.ts +50 -0
- package/dist/client/mcp-client.js +532 -0
- package/dist/client/message-processor.d.ts +35 -0
- package/dist/client/message-processor.js +352 -0
- package/dist/client/multi-bot-manager.d.ts +24 -0
- package/dist/client/multi-bot-manager.js +74 -0
- package/dist/client/providers/anthropic-provider.d.ts +19 -0
- package/dist/client/providers/anthropic-provider.js +631 -0
- package/dist/client/providers/llm-provider.d.ts +47 -0
- package/dist/client/providers/llm-provider.js +367 -0
- package/dist/client/providers/openai-provider.d.ts +23 -0
- package/dist/client/providers/openai-provider.js +621 -0
- package/dist/client/simple-llm-caller.d.ts +19 -0
- package/dist/client/simple-llm-caller.js +100 -0
- package/dist/client/skill-generator.d.ts +81 -0
- package/dist/client/skill-generator.js +386 -0
- package/dist/client/test-adaptive-bot.d.ts +9 -0
- package/dist/client/test-adaptive-bot.js +82 -0
- package/dist/client/token-pricing.d.ts +38 -0
- package/dist/client/token-pricing.js +127 -0
- package/dist/client/token-tracker.d.ts +232 -0
- package/dist/client/token-tracker.js +457 -0
- package/dist/client/token-usage-bot.d.ts +53 -0
- package/dist/client/token-usage-bot.js +153 -0
- package/dist/client/tool-executor.d.ts +69 -0
- package/dist/client/tool-executor.js +159 -0
- package/dist/client/tool-schema-loader.d.ts +60 -0
- package/dist/client/tool-schema-loader.js +178 -0
- package/dist/client/types.d.ts +69 -0
- package/dist/client/types.js +7 -0
- package/dist/config.d.ts +162 -0
- package/dist/config.js +296 -0
- package/dist/core.d.ts +26 -0
- package/dist/core.js +147 -0
- package/dist/lib/context-manager.d.ts +111 -0
- package/dist/lib/context-manager.js +431 -0
- package/dist/lib/logger.d.ts +74 -0
- package/dist/lib/logger.js +277 -0
- package/dist/lib/materialize.d.ts +3 -0
- package/dist/lib/materialize.js +101 -0
- package/dist/lib/normalizedName.d.ts +7 -0
- package/dist/lib/normalizedName.js +48 -0
- package/dist/lib/prompt-length-manager.d.ts +81 -0
- package/dist/lib/prompt-length-manager.js +457 -0
- package/dist/lib/terminal-prompt.d.ts +9 -0
- package/dist/lib/terminal-prompt.js +108 -0
- package/dist/mcp/UserContextCache.d.ts +56 -0
- package/dist/mcp/UserContextCache.js +163 -0
- package/dist/mcp/auth.d.ts +2 -0
- package/dist/mcp/auth.js +29 -0
- package/dist/mcp/hailer-clients.d.ts +42 -0
- package/dist/mcp/hailer-clients.js +246 -0
- package/dist/mcp/signal-handler.d.ts +45 -0
- package/dist/mcp/signal-handler.js +317 -0
- package/dist/mcp/tool-registry.d.ts +100 -0
- package/dist/mcp/tool-registry.js +306 -0
- package/dist/mcp/tools/activity.d.ts +15 -0
- package/dist/mcp/tools/activity.js +955 -0
- package/dist/mcp/tools/app.d.ts +20 -0
- package/dist/mcp/tools/app.js +1488 -0
- package/dist/mcp/tools/discussion.d.ts +19 -0
- package/dist/mcp/tools/discussion.js +950 -0
- package/dist/mcp/tools/file.d.ts +15 -0
- package/dist/mcp/tools/file.js +119 -0
- package/dist/mcp/tools/insight.d.ts +17 -0
- package/dist/mcp/tools/insight.js +806 -0
- package/dist/mcp/tools/skill.d.ts +10 -0
- package/dist/mcp/tools/skill.js +279 -0
- package/dist/mcp/tools/user.d.ts +10 -0
- package/dist/mcp/tools/user.js +108 -0
- package/dist/mcp/tools/workflow-template.d.ts +19 -0
- package/dist/mcp/tools/workflow-template.js +822 -0
- package/dist/mcp/tools/workflow.d.ts +18 -0
- package/dist/mcp/tools/workflow.js +1362 -0
- package/dist/mcp/utils/api-errors.d.ts +45 -0
- package/dist/mcp/utils/api-errors.js +160 -0
- package/dist/mcp/utils/data-transformers.d.ts +102 -0
- package/dist/mcp/utils/data-transformers.js +194 -0
- package/dist/mcp/utils/file-upload.d.ts +33 -0
- package/dist/mcp/utils/file-upload.js +148 -0
- package/dist/mcp/utils/hailer-api-client.d.ts +120 -0
- package/dist/mcp/utils/hailer-api-client.js +323 -0
- package/dist/mcp/utils/index.d.ts +13 -0
- package/dist/mcp/utils/index.js +39 -0
- package/dist/mcp/utils/logger.d.ts +42 -0
- package/dist/mcp/utils/logger.js +103 -0
- package/dist/mcp/utils/types.d.ts +286 -0
- package/dist/mcp/utils/types.js +7 -0
- package/dist/mcp/workspace-cache.d.ts +42 -0
- package/dist/mcp/workspace-cache.js +97 -0
- package/dist/mcp-server.d.ts +42 -0
- package/dist/mcp-server.js +280 -0
- package/package.json +56 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Message Processor for MCP Client
|
|
4
|
+
* Handles incoming socket.io signals and processes messages that mention MCP agents
|
|
5
|
+
* or are sent directly in one-on-one conversations with MCP agents
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.HailerMessageProcessor = void 0;
|
|
9
|
+
class HailerMessageProcessor {
|
|
10
|
+
multiBotManager;
|
|
11
|
+
mcpAgentIds;
|
|
12
|
+
enableDirectMessages;
|
|
13
|
+
constructor(multiBotManager, mcpAgentIds = [], enableDirectMessages = false) {
|
|
14
|
+
this.multiBotManager = multiBotManager;
|
|
15
|
+
this.mcpAgentIds = mcpAgentIds;
|
|
16
|
+
this.enableDirectMessages = enableDirectMessages;
|
|
17
|
+
}
|
|
18
|
+
shouldProcess(signal) {
|
|
19
|
+
// Only process discussion.message and messenger.new signals
|
|
20
|
+
if (signal.type !== "discussion.message" &&
|
|
21
|
+
signal.type !== "messenger.new") {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
// For messenger.new signals, we'll check both hailerTag mentions and direct messages in extractMessage
|
|
25
|
+
if (signal.type === "messenger.new") {
|
|
26
|
+
return true; // Let extractMessage handle all the logic
|
|
27
|
+
}
|
|
28
|
+
// For discussion.message signals, check here
|
|
29
|
+
const messageContent = signal.data?.message?.content || "";
|
|
30
|
+
return this.containsMcpAgentMention(messageContent).found;
|
|
31
|
+
}
|
|
32
|
+
containsMcpAgentMention(content) {
|
|
33
|
+
if (this.mcpAgentIds.length === 0) {
|
|
34
|
+
// Fallback to old @mcp-agent detection if no agent IDs configured
|
|
35
|
+
return {
|
|
36
|
+
found: content.toLowerCase().includes("@mcp-agent"),
|
|
37
|
+
mentionedBotIds: [],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
// Check for hailerTag mentions of our MCP agents
|
|
41
|
+
// Pattern: [hailerTag|Agent Name](agentUserId)
|
|
42
|
+
const hailerTagPattern = /\[hailerTag\|[^\]]+\]\(([^)]+)\)/g;
|
|
43
|
+
let match;
|
|
44
|
+
const mentionedBotIds = [];
|
|
45
|
+
while ((match = hailerTagPattern.exec(content)) !== null) {
|
|
46
|
+
const mentionedUserId = match[1];
|
|
47
|
+
if (this.mcpAgentIds.includes(mentionedUserId)) {
|
|
48
|
+
mentionedBotIds.push(mentionedUserId);
|
|
49
|
+
console.log(`✅ MCP Client: Found mention of bot: ${mentionedUserId}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { found: mentionedBotIds.length > 0, mentionedBotIds };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Fetch discussion participants to determine if it's a one-on-one conversation
|
|
56
|
+
* Uses messenger.load_discussions API to get actual member count
|
|
57
|
+
*/
|
|
58
|
+
async fetchDiscussionParticipants(discussionId, botClient) {
|
|
59
|
+
try {
|
|
60
|
+
// Try messenger.load_discussions - it expects an array of discussion IDs
|
|
61
|
+
const response = await botClient.client.socket.request("messenger.load_discussions", [[discussionId]]);
|
|
62
|
+
// Response is an object with discussionId as key
|
|
63
|
+
if (response && response[discussionId]) {
|
|
64
|
+
const discussion = response[discussionId];
|
|
65
|
+
// First try: Use the 'participants' array which has plain user IDs
|
|
66
|
+
if (discussion.participants && Array.isArray(discussion.participants)) {
|
|
67
|
+
console.log(`📊 MCP Client: Discussion has ${discussion.participants.length} participant(s)`);
|
|
68
|
+
return discussion.participants;
|
|
69
|
+
}
|
|
70
|
+
// Fallback: Use 'members' array and extract IDs
|
|
71
|
+
if (discussion.members && Array.isArray(discussion.members)) {
|
|
72
|
+
const memberIds = [];
|
|
73
|
+
for (const member of discussion.members) {
|
|
74
|
+
// Members have format: { id: "user_USERID", ... }
|
|
75
|
+
if (member && member.id && typeof member.id === "string") {
|
|
76
|
+
// Extract the actual user ID from "user_USERID" format
|
|
77
|
+
const userId = member.id.replace(/^user_/, "");
|
|
78
|
+
memberIds.push(userId);
|
|
79
|
+
}
|
|
80
|
+
else if (typeof member === "string") {
|
|
81
|
+
memberIds.push(member);
|
|
82
|
+
}
|
|
83
|
+
else if (member && member._id) {
|
|
84
|
+
memberIds.push(member._id);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
console.log(`📊 MCP Client: Discussion has ${memberIds.length} member(s)`);
|
|
88
|
+
return memberIds;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const messagesResponse = await botClient.client.socket.request("v3.discussion.message.latest", [discussionId]);
|
|
92
|
+
const messages = messagesResponse?.messages || [];
|
|
93
|
+
const participantIds = new Set();
|
|
94
|
+
// Extract unique participant IDs from messages
|
|
95
|
+
for (const message of messages) {
|
|
96
|
+
if (message.uid) {
|
|
97
|
+
participantIds.add(message.uid);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Add the bot itself as a participant
|
|
101
|
+
participantIds.add(botClient.userId);
|
|
102
|
+
const participants = Array.from(participantIds);
|
|
103
|
+
console.log(`📊 MCP Client: Discussion has ${participants.length} participant(s) (message-based fallback)`);
|
|
104
|
+
return participants;
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
console.error(`❌ MCP Client: Failed to fetch discussion participants:`, error);
|
|
108
|
+
// On error, also try fallback
|
|
109
|
+
try {
|
|
110
|
+
const messagesResponse = await botClient.client.socket.request("v3.discussion.message.latest", [discussionId]);
|
|
111
|
+
const messages = messagesResponse?.messages || [];
|
|
112
|
+
const participantIds = new Set();
|
|
113
|
+
for (const message of messages) {
|
|
114
|
+
if (message.uid) {
|
|
115
|
+
participantIds.add(message.uid);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
participantIds.add(botClient.userId);
|
|
119
|
+
const participants = Array.from(participantIds);
|
|
120
|
+
console.log(`📊 MCP Client: Discussion has ${participants.length} participant(s) (error recovery)`);
|
|
121
|
+
return participants;
|
|
122
|
+
}
|
|
123
|
+
catch (fallbackError) {
|
|
124
|
+
console.error(`❌ MCP Client: All participant detection methods failed`);
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Check if a discussion is a one-on-one conversation with a specific MCP agent
|
|
131
|
+
* @param discussionId - The discussion to check
|
|
132
|
+
* @param senderId - The user who sent the message
|
|
133
|
+
* @param botIdToCheck - The specific bot ID to check for direct message
|
|
134
|
+
* @returns The bot ID if it's a 1:1 conversation with that bot, null otherwise
|
|
135
|
+
*/
|
|
136
|
+
async isDirectMessageToBot(discussionId, senderId, botIdToCheck) {
|
|
137
|
+
// Get the bot client for the specific bot we're checking
|
|
138
|
+
const botClient = this.multiBotManager.getBotClient(botIdToCheck);
|
|
139
|
+
if (!botClient) {
|
|
140
|
+
console.warn(`⚠️ MCP Client: No bot client found for bot ID: ${botIdToCheck}`);
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
const participants = await this.fetchDiscussionParticipants(discussionId, botClient);
|
|
144
|
+
// For a one-on-one conversation, we expect exactly 2 participants
|
|
145
|
+
if (participants.length !== 2) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
// Check if the two participants are the sender and the bot we're checking for
|
|
149
|
+
const includesSender = participants.includes(senderId);
|
|
150
|
+
const includesBot = participants.includes(botIdToCheck);
|
|
151
|
+
if (includesSender && includesBot) {
|
|
152
|
+
console.log(`✅ MCP Client: 1:1 chat detected - will respond without tag`);
|
|
153
|
+
return botIdToCheck;
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
async extractMessage(signal) {
|
|
158
|
+
try {
|
|
159
|
+
if (!this.shouldProcess(signal)) {
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
if (signal.type === "messenger.new") {
|
|
163
|
+
return await this.extractFromMessengerNew(signal);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
// For discussion.message signals
|
|
167
|
+
const messageData = signal.data?.message;
|
|
168
|
+
if (!messageData) {
|
|
169
|
+
console.warn("❌ MCP Client: No message data in signal");
|
|
170
|
+
return [];
|
|
171
|
+
}
|
|
172
|
+
const messageContent = messageData.content || "";
|
|
173
|
+
const mentionResult = this.containsMcpAgentMention(messageContent);
|
|
174
|
+
if (!mentionResult.found) {
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
// Create a message for each mentioned bot
|
|
178
|
+
const messages = [];
|
|
179
|
+
for (const botId of mentionResult.mentionedBotIds) {
|
|
180
|
+
const extractedMessage = {
|
|
181
|
+
id: messageData._id || `msg-${Date.now()}`,
|
|
182
|
+
content: messageContent,
|
|
183
|
+
timestamp: signal.timestamp,
|
|
184
|
+
discussionId: messageData.discussion || "",
|
|
185
|
+
userId: messageData.user || "",
|
|
186
|
+
userName: messageData.userName || "Unknown User",
|
|
187
|
+
workspaceId: signal.workspaceId,
|
|
188
|
+
mentionedOrDirectMessagedBotId: botId,
|
|
189
|
+
};
|
|
190
|
+
messages.push(extractedMessage);
|
|
191
|
+
}
|
|
192
|
+
console.log(`🤖 MCP Client: Processing message from ${messages[0]?.userName} for ${messages.length} bot(s)`);
|
|
193
|
+
return messages;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
console.error("❌ MCP Client: Failed to extract message from signal:", error);
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async extractFromMessengerNew(signal) {
|
|
202
|
+
try {
|
|
203
|
+
const { discussion, msg_id, uid } = signal.data;
|
|
204
|
+
// IMPORTANT: Ignore messages from our own bots to prevent loops
|
|
205
|
+
if (this.mcpAgentIds.includes(uid)) {
|
|
206
|
+
console.log(`🔇 MCP Client: Ignoring message from bot ${uid} (preventing self-trigger loop)`);
|
|
207
|
+
return [];
|
|
208
|
+
}
|
|
209
|
+
// Try to fetch the message with the first available bot client to check mentions
|
|
210
|
+
const botClients = this.multiBotManager.getAllBotClients();
|
|
211
|
+
let targetMessage = null;
|
|
212
|
+
let messageContent = "";
|
|
213
|
+
let workingBotClient = null;
|
|
214
|
+
// Try each bot client until we find the message
|
|
215
|
+
for (const botClient of botClients) {
|
|
216
|
+
try {
|
|
217
|
+
// Fetch the message content using the discussion message API
|
|
218
|
+
const response = await botClient.client.socket.request("v3.discussion.message.latest", [discussion]);
|
|
219
|
+
// Extract messages from the response object
|
|
220
|
+
const messages = response?.messages || [];
|
|
221
|
+
// Find the specific message by ID
|
|
222
|
+
targetMessage = messages.find((msg) => msg._id === msg_id);
|
|
223
|
+
if (targetMessage) {
|
|
224
|
+
messageContent = targetMessage.msg || targetMessage.content || "";
|
|
225
|
+
workingBotClient = botClient;
|
|
226
|
+
break; // Found the message, no need to try other bots
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
// Continue with next bot client if this one fails
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (!targetMessage || !workingBotClient) {
|
|
235
|
+
console.warn(`❌ MCP Client: Could not find message ${msg_id} in discussion ${discussion} with any bot client`);
|
|
236
|
+
return [];
|
|
237
|
+
}
|
|
238
|
+
// Filter out system messages (like "Hi, I created this group!" or user invites)
|
|
239
|
+
const msgType = targetMessage.type;
|
|
240
|
+
if (msgType && msgType !== "user") {
|
|
241
|
+
console.log(`🔇 MCP Client: Ignoring system message type "${msgType}" (discussion: ${discussion})`);
|
|
242
|
+
return [];
|
|
243
|
+
}
|
|
244
|
+
// Also check for common system message patterns
|
|
245
|
+
const systemMessagePatterns = [
|
|
246
|
+
/^Hi, I created this group!$/i,
|
|
247
|
+
/^I invited .+ to this group\.?$/i,
|
|
248
|
+
/^.+ was invited to this group\.?$/i,
|
|
249
|
+
/^.+ joined the group\.?$/i,
|
|
250
|
+
/^.+ left the group\.?$/i,
|
|
251
|
+
];
|
|
252
|
+
for (const pattern of systemMessagePatterns) {
|
|
253
|
+
if (pattern.test(messageContent.trim())) {
|
|
254
|
+
console.log(`🔇 MCP Client: Ignoring system message pattern: "${messageContent}" (discussion: ${discussion})`);
|
|
255
|
+
return [];
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// First, check if the message contains an explicit mention of one of our MCP agents
|
|
259
|
+
const mentionResult = this.containsMcpAgentMention(messageContent);
|
|
260
|
+
let handlingBotIds = mentionResult.mentionedBotIds;
|
|
261
|
+
// If no explicit mention found, check if this is a direct message to one of our bots (if enabled)
|
|
262
|
+
if (handlingBotIds.length === 0 && this.enableDirectMessages) {
|
|
263
|
+
// Check each bot to see if this is a 1:1 conversation with that specific bot
|
|
264
|
+
for (const botId of this.mcpAgentIds) {
|
|
265
|
+
const directMessageBotId = await this.isDirectMessageToBot(discussion, uid, botId);
|
|
266
|
+
if (directMessageBotId) {
|
|
267
|
+
handlingBotIds = [directMessageBotId];
|
|
268
|
+
break; // Found a 1:1 conversation, no need to check other bots
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (handlingBotIds.length === 0) {
|
|
273
|
+
return []; // No mention and not a direct message to our bot
|
|
274
|
+
}
|
|
275
|
+
// Validate that all bot clients exist
|
|
276
|
+
const validBotIds = [];
|
|
277
|
+
for (const botId of handlingBotIds) {
|
|
278
|
+
const botClient = this.multiBotManager.getBotClient(botId);
|
|
279
|
+
if (botClient) {
|
|
280
|
+
validBotIds.push(botId);
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
console.warn(`❌ MCP Client: No bot client found for bot ID: ${botId}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (validBotIds.length === 0) {
|
|
287
|
+
console.warn(`❌ MCP Client: No valid bot clients found for processing`);
|
|
288
|
+
return [];
|
|
289
|
+
}
|
|
290
|
+
// Fetch user info if needed
|
|
291
|
+
const userName = targetMessage.userName || "Unknown User";
|
|
292
|
+
// Create messages for each mentioned bot
|
|
293
|
+
const messages = [];
|
|
294
|
+
for (const botId of validBotIds) {
|
|
295
|
+
const extractedMessage = {
|
|
296
|
+
id: targetMessage._id,
|
|
297
|
+
content: messageContent,
|
|
298
|
+
timestamp: signal.timestamp,
|
|
299
|
+
discussionId: discussion,
|
|
300
|
+
userId: uid,
|
|
301
|
+
userName: userName,
|
|
302
|
+
workspaceId: signal.workspaceId,
|
|
303
|
+
mentionedOrDirectMessagedBotId: botId,
|
|
304
|
+
};
|
|
305
|
+
messages.push(extractedMessage);
|
|
306
|
+
}
|
|
307
|
+
// Clean content for logging (remove hailerTag mentions)
|
|
308
|
+
const cleanContent = messageContent
|
|
309
|
+
.replace(/\[hailerTag\|[^\]]+\]\([^)]+\)/g, "")
|
|
310
|
+
.trim();
|
|
311
|
+
const messageType = mentionResult.found ? "mentioned" : "direct message";
|
|
312
|
+
console.log(`🤖 MCP Client: Processing ${messageType} from ${messages[0]?.userName} for ${messages.length} bot(s): "${cleanContent}"`);
|
|
313
|
+
return messages;
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
console.error("❌ MCP Client: Failed to extract messenger.new message:", error);
|
|
317
|
+
return [];
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async postMessage(discussionId, content, workspaceId, botId) {
|
|
321
|
+
try {
|
|
322
|
+
// Use the specified bot or fall back to the first available bot
|
|
323
|
+
const botClient = botId
|
|
324
|
+
? this.multiBotManager.getBotClient(botId)
|
|
325
|
+
: this.multiBotManager.getAllBotClients()[0];
|
|
326
|
+
if (!botClient) {
|
|
327
|
+
console.error(`❌ MCP Client: No bot client available for posting message (botId: ${botId})`);
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
// Use the bot's socket client to post the message
|
|
331
|
+
const result = await botClient.client.socket.request("messenger.send", [
|
|
332
|
+
{ msg: content },
|
|
333
|
+
discussionId,
|
|
334
|
+
]);
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
console.error("❌ MCP Client: Failed to post message via socket:", error);
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
async postInfoMessage(discussionId, toolName, args, workspaceId, botId) {
|
|
343
|
+
const infoContent = `🔧 Using tool: **${toolName}**\n\`\`\`json\n${JSON.stringify(args, null, 2)}\n\`\`\``;
|
|
344
|
+
return this.postMessage(discussionId, infoContent, workspaceId, botId);
|
|
345
|
+
}
|
|
346
|
+
async postErrorMessage(discussionId, error, workspaceId, botId) {
|
|
347
|
+
const errorContent = `❌ Error: ${error}`;
|
|
348
|
+
return this.postMessage(discussionId, errorContent, workspaceId, botId);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
exports.HailerMessageProcessor = HailerMessageProcessor;
|
|
352
|
+
//# sourceMappingURL=message-processor.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Bot Client Manager
|
|
3
|
+
* Manages multiple bot clients, each with their own Hailer connection
|
|
4
|
+
*/
|
|
5
|
+
import { HailerClient } from "../mcp/hailer-clients";
|
|
6
|
+
import { SignalHandler } from "../mcp/signal-handler";
|
|
7
|
+
import { BotClientConfig } from "./types";
|
|
8
|
+
export interface BotClient {
|
|
9
|
+
userId: string;
|
|
10
|
+
config: BotClientConfig;
|
|
11
|
+
client: HailerClient;
|
|
12
|
+
signalHandler: SignalHandler;
|
|
13
|
+
}
|
|
14
|
+
export declare class MultiBotManager {
|
|
15
|
+
private botConfigs;
|
|
16
|
+
private botClients;
|
|
17
|
+
constructor(botConfigs: BotClientConfig[]);
|
|
18
|
+
initializeAllHailerClientsFromConfig(): Promise<void>;
|
|
19
|
+
getBotClient(userId: string): BotClient | undefined;
|
|
20
|
+
getAllBotClients(): BotClient[];
|
|
21
|
+
getBotIds(): string[];
|
|
22
|
+
shutdown(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=multi-bot-manager.d.ts.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Multi-Bot Client Manager
|
|
4
|
+
* Manages multiple bot clients, each with their own Hailer connection
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.MultiBotManager = void 0;
|
|
8
|
+
const hailer_clients_1 = require("../mcp/hailer-clients");
|
|
9
|
+
const signal_handler_1 = require("../mcp/signal-handler");
|
|
10
|
+
class MultiBotManager {
|
|
11
|
+
botConfigs;
|
|
12
|
+
botClients = new Map();
|
|
13
|
+
constructor(botConfigs) {
|
|
14
|
+
this.botConfigs = botConfigs;
|
|
15
|
+
}
|
|
16
|
+
// for client we may put initializeAllConfigClients method to do it at once
|
|
17
|
+
// in case we only use MCP Server:
|
|
18
|
+
// for MCP Server it may just get a specific client and this class initialize it specifically and even kill it later if not needed
|
|
19
|
+
async initializeAllHailerClientsFromConfig() {
|
|
20
|
+
console.log(`🤖 Initializing ${this.botConfigs.length} bot clients...`);
|
|
21
|
+
for (const config of this.botConfigs) {
|
|
22
|
+
try {
|
|
23
|
+
// Use shared connection pool via API key lookup
|
|
24
|
+
const client = await (0, hailer_clients_1.createHailerClientByApiKey)(config.mcpServerApiKey);
|
|
25
|
+
// Get user ID automatically from authenticated session
|
|
26
|
+
const userId = await (0, hailer_clients_1.getCurrentUserId)(client);
|
|
27
|
+
const signalHandler = new signal_handler_1.SignalHandler(client, undefined);
|
|
28
|
+
const botClient = {
|
|
29
|
+
userId,
|
|
30
|
+
config,
|
|
31
|
+
client,
|
|
32
|
+
signalHandler,
|
|
33
|
+
};
|
|
34
|
+
this.botClients.set(userId, botClient);
|
|
35
|
+
console.log(`✅ Bot client initialized for ${config.email} (${userId}) via API key ${config.mcpServerApiKey.substring(0, 8)}...`);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error(`❌ Failed to initialize bot client for ${config.email}:`, error);
|
|
39
|
+
// Continue with other bots even if one fails
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
console.log(`✅ Initialized ${this.botClients.size} bot clients successfully`);
|
|
43
|
+
}
|
|
44
|
+
getBotClient(userId) {
|
|
45
|
+
const botClient = this.botClients.get(userId);
|
|
46
|
+
if (!botClient) {
|
|
47
|
+
console.warn(`❌ No bot client found for userId: ${userId}`);
|
|
48
|
+
}
|
|
49
|
+
return botClient;
|
|
50
|
+
}
|
|
51
|
+
getAllBotClients() {
|
|
52
|
+
return Array.from(this.botClients.values());
|
|
53
|
+
}
|
|
54
|
+
getBotIds() {
|
|
55
|
+
return Array.from(this.botClients.keys());
|
|
56
|
+
}
|
|
57
|
+
async shutdown() {
|
|
58
|
+
console.log("🤖 Shutting down all bot clients...");
|
|
59
|
+
for (const [userId, botClient] of this.botClients) {
|
|
60
|
+
try {
|
|
61
|
+
// Properly disconnect from shared connection pool
|
|
62
|
+
(0, hailer_clients_1.disconnectHailerClientByApiKey)(botClient.config.mcpServerApiKey);
|
|
63
|
+
console.log(`✅ Bot client ${userId} shut down (API key: ${botClient.config.mcpServerApiKey.substring(0, 8)}...)`);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
console.error(`❌ Error shutting down bot client ${userId}:`, error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
this.botClients.clear();
|
|
70
|
+
console.log("✅ All bot clients shut down");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.MultiBotManager = MultiBotManager;
|
|
74
|
+
//# sourceMappingURL=multi-bot-manager.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ChatMessage, McpResponse } from "../types";
|
|
2
|
+
import { LlmProvider } from "./llm-provider";
|
|
3
|
+
export declare class AnthropicProvider extends LlmProvider {
|
|
4
|
+
private client;
|
|
5
|
+
private contextManager;
|
|
6
|
+
private toolSchemaLoader;
|
|
7
|
+
private toolExecutor;
|
|
8
|
+
private toolSchemaCache;
|
|
9
|
+
constructor(config: any);
|
|
10
|
+
generateConfirmationMessage(userMessage: ChatMessage): Promise<string>;
|
|
11
|
+
processMessage(userMessage: ChatMessage, mcpServerUrl: string, botMcpApiKey: string, botEmail: string): Promise<McpResponse>;
|
|
12
|
+
/**
|
|
13
|
+
* Fetch specific tool schema on-demand
|
|
14
|
+
* Token-efficient: ~690 tokens per tool vs loading all tools upfront
|
|
15
|
+
*/
|
|
16
|
+
private fetchMcpToolSchema;
|
|
17
|
+
protected callMcpTool(mcpServerUrl: string, mcpServerApiKey: string, request: any): Promise<any>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=anthropic-provider.d.ts.map
|