@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,532 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Main MCP Client
|
|
4
|
+
* Orchestrates signal handling, message processing, and LLM provider interaction
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.McpClient = void 0;
|
|
8
|
+
const message_processor_1 = require("./message-processor");
|
|
9
|
+
const openai_provider_1 = require("./providers/openai-provider");
|
|
10
|
+
const anthropic_provider_1 = require("./providers/anthropic-provider");
|
|
11
|
+
const multi_bot_manager_1 = require("./multi-bot-manager");
|
|
12
|
+
const agent_tracker_1 = require("./agent-tracker");
|
|
13
|
+
const token_tracker_1 = require("./token-tracker");
|
|
14
|
+
const token_usage_bot_1 = require("./token-usage-bot");
|
|
15
|
+
const agent_activity_bot_1 = require("./agent-activity-bot");
|
|
16
|
+
const adaptive_documentation_bot_1 = require("./adaptive-documentation-bot");
|
|
17
|
+
const config_1 = require("../config");
|
|
18
|
+
class McpClient {
|
|
19
|
+
multiBotManager;
|
|
20
|
+
messageProcessor;
|
|
21
|
+
providers = new Map();
|
|
22
|
+
config;
|
|
23
|
+
isActive = false;
|
|
24
|
+
processedMessages = new Set(); // Global message deduplication
|
|
25
|
+
activeSubscriptions = new Set(); // Track active subscriptions
|
|
26
|
+
agentTracker = (0, agent_tracker_1.createAgentTracker)();
|
|
27
|
+
tokenTracker = (0, token_tracker_1.createTokenTracker)();
|
|
28
|
+
tokenUsageBot;
|
|
29
|
+
agentActivityBot;
|
|
30
|
+
adaptiveDocBot;
|
|
31
|
+
constructor(config) {
|
|
32
|
+
this.config = config;
|
|
33
|
+
this.multiBotManager = new multi_bot_manager_1.MultiBotManager(config.botConfigs);
|
|
34
|
+
this.messageProcessor = new message_processor_1.HailerMessageProcessor(this.multiBotManager, config.mcpAgentIds, config.enableDirectMessages);
|
|
35
|
+
// Initialize Token Usage Bot
|
|
36
|
+
this.tokenUsageBot = (0, token_usage_bot_1.createTokenUsageBot)(this.tokenTracker, this.agentTracker, {
|
|
37
|
+
enabled: config.tokenUsageBotEnabled,
|
|
38
|
+
postSummaryAfterConversation: config.tokenUsageBotEnabled,
|
|
39
|
+
minCostThreshold: 0, // Post summary for every conversation
|
|
40
|
+
});
|
|
41
|
+
// Initialize Agent Activity Bot
|
|
42
|
+
this.agentActivityBot = (0, agent_activity_bot_1.createAgentActivityBot)(this.agentTracker, {
|
|
43
|
+
enabled: config.agentActivityBotEnabled,
|
|
44
|
+
postSummaryAfterConversation: config.agentActivityBotEnabled,
|
|
45
|
+
minDurationThreshold: 1000, // Only post if duration > 1s
|
|
46
|
+
});
|
|
47
|
+
// Initialize Adaptive Documentation Bot
|
|
48
|
+
const appConfig = (0, config_1.createApplicationConfig)();
|
|
49
|
+
if (appConfig.adaptiveDocumentation.enabled && this.config.providers.length > 0) {
|
|
50
|
+
// Use the first available provider's API key for the adaptive bot
|
|
51
|
+
const firstProviderConfig = this.config.providers[0];
|
|
52
|
+
if (firstProviderConfig.apiKey) {
|
|
53
|
+
this.adaptiveDocBot = new adaptive_documentation_bot_1.AdaptiveDocumentationBot(firstProviderConfig.apiKey, firstProviderConfig.type === 'openai' ? 'openai' : 'anthropic', {
|
|
54
|
+
enabled: appConfig.adaptiveDocumentation.enabled,
|
|
55
|
+
autoUpdate: appConfig.adaptiveDocumentation.autoUpdate,
|
|
56
|
+
updateInterval: appConfig.adaptiveDocumentation.updateInterval,
|
|
57
|
+
minErrorCount: appConfig.adaptiveDocumentation.minErrorCount,
|
|
58
|
+
skillGeneration: appConfig.adaptiveDocumentation.skillGeneration,
|
|
59
|
+
});
|
|
60
|
+
console.log('🔧 Adaptive Documentation Bot initialized');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Initialize providers after adaptive bot
|
|
64
|
+
this.initializeProviders();
|
|
65
|
+
}
|
|
66
|
+
async initialize() {
|
|
67
|
+
await this.multiBotManager.initializeAllHailerClientsFromConfig();
|
|
68
|
+
// Update agent IDs with the actual user IDs retrieved from authentication
|
|
69
|
+
const actualAgentIds = this.multiBotManager.getBotIds();
|
|
70
|
+
if (actualAgentIds.length > 0) {
|
|
71
|
+
console.log(`🤖 Updated MCP Agent IDs: ${actualAgentIds.join(", ")}`);
|
|
72
|
+
// Update the message processor with the actual agent IDs
|
|
73
|
+
this.messageProcessor = new message_processor_1.HailerMessageProcessor(this.multiBotManager, actualAgentIds, this.config.enableDirectMessages);
|
|
74
|
+
// Log successful initialization
|
|
75
|
+
this.agentTracker.logSystem({
|
|
76
|
+
success: true,
|
|
77
|
+
message: "MCP Client Initialized",
|
|
78
|
+
details: `Successfully initialized with ${actualAgentIds.length} bot agent(s): ${actualAgentIds.map((id) => id.substring(0, 8)).join(", ")}`,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// Log failed initialization
|
|
83
|
+
this.agentTracker.logSystem({
|
|
84
|
+
success: false,
|
|
85
|
+
message: "MCP Client Initialization Failed",
|
|
86
|
+
error: "No bot agents configured or authentication failed",
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
// Start adaptive documentation monitoring
|
|
90
|
+
if (this.adaptiveDocBot) {
|
|
91
|
+
this.adaptiveDocBot.startMonitoring();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
initializeProviders() {
|
|
95
|
+
for (const providerConfig of this.config.providers) {
|
|
96
|
+
try {
|
|
97
|
+
let provider;
|
|
98
|
+
switch (providerConfig.type) {
|
|
99
|
+
case "openai":
|
|
100
|
+
provider = new openai_provider_1.OpenAIProvider(providerConfig);
|
|
101
|
+
break;
|
|
102
|
+
case "anthropic":
|
|
103
|
+
provider = new anthropic_provider_1.AnthropicProvider(providerConfig);
|
|
104
|
+
break;
|
|
105
|
+
case "gemini":
|
|
106
|
+
// TODO: Implement GeminiProvider
|
|
107
|
+
console.warn(`⚠️ Provider type ${providerConfig.type} not yet implemented`);
|
|
108
|
+
continue;
|
|
109
|
+
default:
|
|
110
|
+
console.warn(`⚠️ Unknown provider type: ${providerConfig.type}`);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (provider.isEnabled()) {
|
|
114
|
+
this.providers.set(providerConfig.name, provider);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
console.warn(`⚠️ Provider "${providerConfig.name}" is disabled or missing API key`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
console.error(`❌ Failed to initialize provider "${providerConfig.name}":`, error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
start() {
|
|
126
|
+
if (this.isActive) {
|
|
127
|
+
console.log("🤖 MCP Client already active, skipping start");
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// Subscribe to signals from ALL bot clients since each bot has access to different discussions
|
|
131
|
+
const botClients = this.multiBotManager.getAllBotClients();
|
|
132
|
+
if (botClients.length === 0) {
|
|
133
|
+
console.error("❌ No bot clients available for signal subscription");
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
// Subscribe to signals from each bot client
|
|
137
|
+
for (const botClient of botClients) {
|
|
138
|
+
const subscriptionId = `mcp-client-${botClient.userId}`;
|
|
139
|
+
botClient.signalHandler.subscribe(subscriptionId, ["messenger.new"], this.handleSignal.bind(this));
|
|
140
|
+
this.activeSubscriptions.add(subscriptionId);
|
|
141
|
+
console.log(`🤖 Subscribed to signals for bot: ${botClient.config.email} (${botClient.userId})`);
|
|
142
|
+
}
|
|
143
|
+
this.isActive = true;
|
|
144
|
+
console.log(`🤖 MCP Client started with ${botClients.length} bot signal handlers (direct messages: enabled)`);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get adaptive documentation bot instance (for error reporting)
|
|
148
|
+
*/
|
|
149
|
+
getAdaptiveBot() {
|
|
150
|
+
return this.adaptiveDocBot;
|
|
151
|
+
}
|
|
152
|
+
stop() {
|
|
153
|
+
if (!this.isActive) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
console.log("🤖 Stopping MCP Client...");
|
|
157
|
+
// Unsubscribe from all bot signal handlers
|
|
158
|
+
const botClients = this.multiBotManager.getAllBotClients();
|
|
159
|
+
for (const botClient of botClients) {
|
|
160
|
+
const subscriptionId = `mcp-client-${botClient.userId}`;
|
|
161
|
+
if (this.activeSubscriptions.has(subscriptionId)) {
|
|
162
|
+
botClient.signalHandler.unsubscribe(subscriptionId);
|
|
163
|
+
this.activeSubscriptions.delete(subscriptionId);
|
|
164
|
+
console.log(`🤖 Unsubscribed from signals for bot: ${botClient.config.email}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Stop adaptive documentation monitoring
|
|
168
|
+
if (this.adaptiveDocBot) {
|
|
169
|
+
this.adaptiveDocBot.stopMonitoring();
|
|
170
|
+
}
|
|
171
|
+
this.isActive = false;
|
|
172
|
+
console.log("🤖 MCP Client stopped");
|
|
173
|
+
}
|
|
174
|
+
async handleSignal(signal) {
|
|
175
|
+
let requestId = null;
|
|
176
|
+
const startTime = Date.now();
|
|
177
|
+
try {
|
|
178
|
+
// Early deduplication check - prevent race conditions from multiple bot subscriptions
|
|
179
|
+
const msgId = signal.data?.msg_id;
|
|
180
|
+
if (msgId) {
|
|
181
|
+
if (this.processedMessages.has(msgId)) {
|
|
182
|
+
console.log(`🔄 MCP Client: Message ${msgId} already being processed, skipping`);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// Mark as processing immediately to prevent race conditions
|
|
186
|
+
this.processedMessages.add(msgId);
|
|
187
|
+
// Clean up old processed message IDs (keep only last 1000)
|
|
188
|
+
if (this.processedMessages.size > 1000) {
|
|
189
|
+
const entries = Array.from(this.processedMessages);
|
|
190
|
+
this.processedMessages.clear();
|
|
191
|
+
entries.slice(-500).forEach((id) => this.processedMessages.add(id)); // Keep last 500
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const messages = await this.messageProcessor.extractMessage(signal);
|
|
195
|
+
if (!messages || messages.length === 0) {
|
|
196
|
+
// If message extraction failed, remove from processed set
|
|
197
|
+
if (msgId) {
|
|
198
|
+
this.processedMessages.delete(msgId);
|
|
199
|
+
}
|
|
200
|
+
return; // Signal doesn't contain a valid MCP agent message
|
|
201
|
+
}
|
|
202
|
+
// Process each message (one per mentioned bot)
|
|
203
|
+
const processingPromises = messages.map(async (message) => {
|
|
204
|
+
// Ensure we have a mentioned bot
|
|
205
|
+
if (!message.mentionedOrDirectMessagedBotId) {
|
|
206
|
+
console.warn(`⚠️ MCP Client: No bot mentioned in message, skipping processing`);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
// Double-check that the mentioned bot exists
|
|
210
|
+
const mentionedBot = this.multiBotManager.getBotClient(message.mentionedOrDirectMessagedBotId);
|
|
211
|
+
if (!mentionedBot) {
|
|
212
|
+
console.error(`❌ MCP Client: Mentioned bot ${message.mentionedOrDirectMessagedBotId} not found`);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
// LOG TRIGGER EVENT - Bot was successfully triggered (only for the first message to avoid duplicate logs)
|
|
216
|
+
let messageRequestId = null;
|
|
217
|
+
if (!requestId) {
|
|
218
|
+
requestId = this.agentTracker.logTrigger({
|
|
219
|
+
triggerType: this.determineTriggerType(message.content),
|
|
220
|
+
discussionId: message.discussionId,
|
|
221
|
+
userId: message.userId,
|
|
222
|
+
userName: message.userName,
|
|
223
|
+
botId: message.mentionedOrDirectMessagedBotId,
|
|
224
|
+
messageContent: message.content,
|
|
225
|
+
workspaceId: message.workspaceId,
|
|
226
|
+
});
|
|
227
|
+
messageRequestId = requestId;
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
// Log additional triggers for multiple bots
|
|
231
|
+
messageRequestId = this.agentTracker.logTrigger({
|
|
232
|
+
triggerType: this.determineTriggerType(message.content),
|
|
233
|
+
discussionId: message.discussionId,
|
|
234
|
+
userId: message.userId,
|
|
235
|
+
userName: message.userName,
|
|
236
|
+
botId: message.mentionedOrDirectMessagedBotId,
|
|
237
|
+
messageContent: message.content,
|
|
238
|
+
workspaceId: message.workspaceId,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
// Process with the first enabled provider (can be enhanced to support multiple or selection)
|
|
242
|
+
const provider = this.getFirstEnabledProvider();
|
|
243
|
+
if (!provider) {
|
|
244
|
+
console.error(`❌ MCP Client: No LLM providers are available`);
|
|
245
|
+
// Log completion failure
|
|
246
|
+
if (messageRequestId) {
|
|
247
|
+
this.agentTracker.logCompletion({
|
|
248
|
+
requestId: messageRequestId,
|
|
249
|
+
success: false,
|
|
250
|
+
duration: Date.now() - startTime,
|
|
251
|
+
error: "No LLM providers are available",
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
await this.messageProcessor.postErrorMessage(message.discussionId, "No LLM providers are available", message.workspaceId, message.mentionedOrDirectMessagedBotId);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
console.log(`🤖 Processing request from ${message.userName} with ${provider.name} (Bot: ${message.mentionedOrDirectMessagedBotId})`);
|
|
258
|
+
// Check if Token Bot is mentioned with a token usage query - handle directly without LLM
|
|
259
|
+
// For other bots (like Manager Bot), they'll use LLM + tools to invite Token Bot
|
|
260
|
+
const tokenBotUserId = '691c07ad702e78dc33797c97';
|
|
261
|
+
if (this.config.tokenUsageBotEnabled &&
|
|
262
|
+
this.tokenUsageBot.isTokenQuery(message.content) &&
|
|
263
|
+
message.mentionedOrDirectMessagedBotId === tokenBotUserId) {
|
|
264
|
+
console.log('📊 Token Bot query detected - generating report with direct JSON access');
|
|
265
|
+
const detailedReport = this.tokenUsageBot.generateDetailedReport(message.discussionId);
|
|
266
|
+
await this.messageProcessor.postMessage(message.discussionId, detailedReport, message.workspaceId, message.mentionedOrDirectMessagedBotId);
|
|
267
|
+
// Token Bot leaves the discussion after posting report
|
|
268
|
+
const tokenBotClient = this.multiBotManager.getBotClient(message.mentionedOrDirectMessagedBotId);
|
|
269
|
+
if (tokenBotClient) {
|
|
270
|
+
try {
|
|
271
|
+
await tokenBotClient.client.socket.request('messenger.leave_discussion', [message.discussionId]);
|
|
272
|
+
console.log('👋 Token Bot left the discussion after posting report');
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
console.error('❌ Failed to leave discussion:', error);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Log completion for token query
|
|
279
|
+
if (messageRequestId) {
|
|
280
|
+
this.agentTracker.logCompletion({
|
|
281
|
+
requestId: messageRequestId,
|
|
282
|
+
success: true,
|
|
283
|
+
provider: 'token-usage-bot',
|
|
284
|
+
toolsCalled: ['generate_detailed_report', 'leave_discussion'],
|
|
285
|
+
responseContent: 'Token usage report generated and left discussion',
|
|
286
|
+
duration: Date.now() - startTime,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
return; // Skip LLM processing
|
|
290
|
+
}
|
|
291
|
+
// Check if this is an agent activity query - handle directly without LLM (only if bot is enabled)
|
|
292
|
+
if (this.config.agentActivityBotEnabled && this.agentActivityBot.isActivityQuery(message.content)) {
|
|
293
|
+
console.log('🤖 Agent activity query detected - generating report');
|
|
294
|
+
const detailedReport = this.agentActivityBot.generateDetailedReport(message.discussionId);
|
|
295
|
+
await this.messageProcessor.postMessage(message.discussionId, detailedReport, message.workspaceId, message.mentionedOrDirectMessagedBotId);
|
|
296
|
+
// Log completion for activity query
|
|
297
|
+
if (messageRequestId) {
|
|
298
|
+
this.agentTracker.logCompletion({
|
|
299
|
+
requestId: messageRequestId,
|
|
300
|
+
success: true,
|
|
301
|
+
provider: 'agent-activity-bot',
|
|
302
|
+
toolsCalled: ['generate_detailed_report'],
|
|
303
|
+
responseContent: 'Agent activity report generated',
|
|
304
|
+
duration: Date.now() - startTime,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
return; // Skip LLM processing
|
|
308
|
+
}
|
|
309
|
+
// Generate and post personalized confirmation message
|
|
310
|
+
const confirmationMessage = await provider.generateConfirmationMessage(message);
|
|
311
|
+
await this.messageProcessor.postMessage(message.discussionId, confirmationMessage, message.workspaceId, message.mentionedOrDirectMessagedBotId);
|
|
312
|
+
const response = await this.processMessage(message, provider);
|
|
313
|
+
await this.handleResponse(message, response);
|
|
314
|
+
// LOG COMPLETION EVENT - Bot finished processing
|
|
315
|
+
if (messageRequestId) {
|
|
316
|
+
const duration = Date.now() - startTime;
|
|
317
|
+
this.agentTracker.logCompletion({
|
|
318
|
+
requestId: messageRequestId,
|
|
319
|
+
success: response.success,
|
|
320
|
+
provider: provider.name,
|
|
321
|
+
toolsCalled: response.toolCalls?.map((tc) => tc.toolName) || [],
|
|
322
|
+
responseContent: response.response,
|
|
323
|
+
duration: duration,
|
|
324
|
+
error: response.error,
|
|
325
|
+
});
|
|
326
|
+
// ANALYZE LOGS - Check for tool call errors after conversation completes
|
|
327
|
+
if (this.adaptiveDocBot) {
|
|
328
|
+
this.adaptiveDocBot.analyzeAfterConversation().catch(error => {
|
|
329
|
+
console.error('❌ Failed to analyze conversation errors:', error);
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
// POST AGENT ACTIVITY SUMMARY - Automatically post summary if duration threshold met
|
|
333
|
+
if (this.agentActivityBot.shouldPostSummary(message.discussionId, duration)) {
|
|
334
|
+
try {
|
|
335
|
+
const summary = this.agentActivityBot.generateSummary(messageRequestId, message.discussionId, duration, response.toolCalls?.map((tc) => tc.toolName) || []);
|
|
336
|
+
await this.messageProcessor.postMessage(message.discussionId, summary, message.workspaceId, message.mentionedOrDirectMessagedBotId);
|
|
337
|
+
this.agentActivityBot.markPosted(message.discussionId);
|
|
338
|
+
console.log('🤖 Agent activity summary posted to discussion');
|
|
339
|
+
}
|
|
340
|
+
catch (error) {
|
|
341
|
+
console.error('❌ Failed to post agent activity summary:', error);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
// LOG TOKEN USAGE - Track costs and usage for optimization
|
|
345
|
+
if (response.tokens && response.tokens.cost !== undefined && response.success) {
|
|
346
|
+
this.tokenTracker.logUsage({
|
|
347
|
+
botId: message.mentionedOrDirectMessagedBotId,
|
|
348
|
+
botName: mentionedBot.config.email, // Use email as bot name
|
|
349
|
+
provider: provider.name,
|
|
350
|
+
conversationId: message.discussionId,
|
|
351
|
+
toolsCalled: response.toolCalls?.map((tc) => tc.toolName) || [],
|
|
352
|
+
tokens: {
|
|
353
|
+
input: response.tokens.input,
|
|
354
|
+
output: response.tokens.output,
|
|
355
|
+
total: response.tokens.total,
|
|
356
|
+
cacheCreation: response.tokens.cacheCreation,
|
|
357
|
+
cacheRead: response.tokens.cacheRead,
|
|
358
|
+
cost: response.tokens.cost,
|
|
359
|
+
},
|
|
360
|
+
duration: Date.now() - startTime,
|
|
361
|
+
success: true,
|
|
362
|
+
});
|
|
363
|
+
// POST TOKEN USAGE SUMMARY - Automatically post summary if cost threshold met
|
|
364
|
+
if (this.tokenUsageBot.shouldPostSummary(message.discussionId, response.tokens.cost)) {
|
|
365
|
+
try {
|
|
366
|
+
const summary = await this.tokenUsageBot.generateSummary(message.discussionId, response.tokens.cost, response.tokens.total);
|
|
367
|
+
await this.messageProcessor.postMessage(message.discussionId, summary, message.workspaceId, message.mentionedOrDirectMessagedBotId);
|
|
368
|
+
this.tokenUsageBot.markPosted(message.discussionId);
|
|
369
|
+
console.log('💰 Token usage summary posted to discussion');
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
console.error('❌ Failed to post token usage summary:', error);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
// Wait for all bot processing to complete
|
|
379
|
+
await Promise.all(processingPromises);
|
|
380
|
+
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
console.error("❌ MCP Client: Error handling signal:", error);
|
|
383
|
+
// Log completion failure
|
|
384
|
+
if (requestId) {
|
|
385
|
+
this.agentTracker.logCompletion({
|
|
386
|
+
requestId,
|
|
387
|
+
success: false,
|
|
388
|
+
duration: Date.now() - startTime,
|
|
389
|
+
error: error instanceof Error ? error.message : String(error),
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
// Remove from processed set on error
|
|
393
|
+
const msgId = signal.data?.msg_id;
|
|
394
|
+
if (msgId) {
|
|
395
|
+
this.processedMessages.delete(msgId);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
getFirstEnabledProvider() {
|
|
400
|
+
for (const provider of this.providers.values()) {
|
|
401
|
+
if (provider.isEnabled()) {
|
|
402
|
+
return provider;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
determineTriggerType(messageContent) {
|
|
408
|
+
// Check if message contains hailerTag mentions
|
|
409
|
+
const hailerTagPattern = /\[hailerTag\|[^\]]+\]\(([^)]+)\)/g;
|
|
410
|
+
if (hailerTagPattern.test(messageContent)) {
|
|
411
|
+
return "mention";
|
|
412
|
+
}
|
|
413
|
+
// Check for old @mcp-agent format (fallback)
|
|
414
|
+
if (messageContent.toLowerCase().includes("@mcp-agent")) {
|
|
415
|
+
return "mention";
|
|
416
|
+
}
|
|
417
|
+
// Otherwise it's a direct message
|
|
418
|
+
return "direct";
|
|
419
|
+
}
|
|
420
|
+
async processMessage(message, provider) {
|
|
421
|
+
try {
|
|
422
|
+
const botClient = this.multiBotManager.getBotClient(message.mentionedOrDirectMessagedBotId);
|
|
423
|
+
if (!botClient) {
|
|
424
|
+
throw new Error(`Bot client not found for mentionedOrDirectMessagedBotId '${message.mentionedOrDirectMessagedBotId}'`);
|
|
425
|
+
}
|
|
426
|
+
const result = await provider.processMessage(message, this.config.mcpServerUrl, botClient.config.mcpServerApiKey, botClient.config.email);
|
|
427
|
+
return result;
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
console.error(`❌ MCP Client: Provider "${provider.name}" failed to process message:`, error);
|
|
431
|
+
return {
|
|
432
|
+
success: false,
|
|
433
|
+
error: `Processing failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
async handleResponse(message, response) {
|
|
438
|
+
// Build complete message with tool usage info and main response
|
|
439
|
+
let combinedMessage = "";
|
|
440
|
+
// Add tool usage information if any tools were called
|
|
441
|
+
// COMMENTED OUT FOR SALES DEMO - uncomment to re-enable tool logs for developmen/debugging
|
|
442
|
+
// if (response.toolCalls && response.toolCalls.length > 0) {
|
|
443
|
+
// const toolSummary = this.buildToolUsageSummary(response.toolCalls);
|
|
444
|
+
// if (toolSummary) {
|
|
445
|
+
// combinedMessage += `${toolSummary}\n\n`;
|
|
446
|
+
// }
|
|
447
|
+
// }
|
|
448
|
+
// Add main response or error
|
|
449
|
+
if (response.success && response.response) {
|
|
450
|
+
combinedMessage += response.response;
|
|
451
|
+
await this.postSuccessResponse(message, combinedMessage.trim());
|
|
452
|
+
}
|
|
453
|
+
else if (!response.success && response.error) {
|
|
454
|
+
combinedMessage += `❌ Error: ${response.error}`;
|
|
455
|
+
await this.postErrorResponse(message, combinedMessage.trim());
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
console.log(`❌Unhandled case while handling the message, response.success: ${response.success}; response.error: ${response.error}`);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
async postSuccessResponse(message, content) {
|
|
462
|
+
await this.messageProcessor.postMessage(message.discussionId, content, message.workspaceId, message.mentionedOrDirectMessagedBotId);
|
|
463
|
+
}
|
|
464
|
+
buildToolUsageSummary(toolCalls) {
|
|
465
|
+
if (!toolCalls || toolCalls.length === 0) {
|
|
466
|
+
return "";
|
|
467
|
+
}
|
|
468
|
+
const successfulTools = toolCalls.filter((tc) => !tc.error);
|
|
469
|
+
const failedTools = toolCalls.filter((tc) => tc.error);
|
|
470
|
+
let summary = "";
|
|
471
|
+
if (successfulTools.length > 0) {
|
|
472
|
+
successfulTools.forEach((tc, index) => {
|
|
473
|
+
if (index > 0)
|
|
474
|
+
summary += "\n\n";
|
|
475
|
+
summary += `🔧 Using tool: **${tc.toolName}**`;
|
|
476
|
+
if (tc.args && Object.keys(tc.args).length > 0) {
|
|
477
|
+
summary += `\n\`\`\`json\n${JSON.stringify(tc.args, null, 2)}\n\`\`\``;
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
if (failedTools.length > 0) {
|
|
482
|
+
if (summary)
|
|
483
|
+
summary += "\n\n";
|
|
484
|
+
failedTools.forEach((tc, index) => {
|
|
485
|
+
if (index > 0)
|
|
486
|
+
summary += "\n\n";
|
|
487
|
+
summary += `❌ Tool **${tc.toolName}** failed: ${tc.error}`;
|
|
488
|
+
if (tc.args && Object.keys(tc.args).length > 0) {
|
|
489
|
+
summary += `\nArguments:\n\`\`\`json\n${JSON.stringify(tc.args, null, 2)}\n\`\`\``;
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
return summary;
|
|
494
|
+
}
|
|
495
|
+
async postErrorResponse(message, error) {
|
|
496
|
+
try {
|
|
497
|
+
await this.messageProcessor.postErrorMessage(message.discussionId, error, message.workspaceId, message.mentionedOrDirectMessagedBotId);
|
|
498
|
+
}
|
|
499
|
+
catch (postError) {
|
|
500
|
+
console.error(`❌ MCP Client: Failed to post error response:`, postError);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
/** Shutdown the dependency: MultiBotManager */
|
|
504
|
+
async shutdownMultiBotManager() {
|
|
505
|
+
await this.multiBotManager.shutdown();
|
|
506
|
+
}
|
|
507
|
+
/** Shutdown the McpClient and MultiBotManager */
|
|
508
|
+
async shutdown() {
|
|
509
|
+
console.log('Shutting down MCP Client');
|
|
510
|
+
this.stop();
|
|
511
|
+
await this.shutdownMultiBotManager();
|
|
512
|
+
console.log('MCP Client shut down successfully');
|
|
513
|
+
}
|
|
514
|
+
getStatus() {
|
|
515
|
+
const enabledProviders = [];
|
|
516
|
+
for (const [name, provider] of this.providers) {
|
|
517
|
+
if (provider.isEnabled()) {
|
|
518
|
+
enabledProviders.push(name);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return {
|
|
522
|
+
active: this.isActive,
|
|
523
|
+
providersCount: this.providers.size,
|
|
524
|
+
enabledProviders,
|
|
525
|
+
activeSubscriptions: this.activeSubscriptions.size,
|
|
526
|
+
botClientsCount: this.multiBotManager.getAllBotClients().length,
|
|
527
|
+
directMessagesEnabled: this.config.enableDirectMessages,
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
exports.McpClient = McpClient;
|
|
532
|
+
//# sourceMappingURL=mcp-client.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message Processor for MCP Client
|
|
3
|
+
* Handles incoming socket.io signals and processes messages that mention MCP agents
|
|
4
|
+
* or are sent directly in one-on-one conversations with MCP agents
|
|
5
|
+
*/
|
|
6
|
+
import { HailerSignal } from "../mcp/signal-handler";
|
|
7
|
+
import { ChatMessage, MessageProcessor } from "./types";
|
|
8
|
+
import { MultiBotManager } from "./multi-bot-manager";
|
|
9
|
+
export declare class HailerMessageProcessor implements MessageProcessor {
|
|
10
|
+
private multiBotManager;
|
|
11
|
+
private mcpAgentIds;
|
|
12
|
+
private enableDirectMessages;
|
|
13
|
+
constructor(multiBotManager: MultiBotManager, mcpAgentIds?: string[], enableDirectMessages?: boolean);
|
|
14
|
+
shouldProcess(signal: HailerSignal): boolean;
|
|
15
|
+
private containsMcpAgentMention;
|
|
16
|
+
/**
|
|
17
|
+
* Fetch discussion participants to determine if it's a one-on-one conversation
|
|
18
|
+
* Uses messenger.load_discussions API to get actual member count
|
|
19
|
+
*/
|
|
20
|
+
private fetchDiscussionParticipants;
|
|
21
|
+
/**
|
|
22
|
+
* Check if a discussion is a one-on-one conversation with a specific MCP agent
|
|
23
|
+
* @param discussionId - The discussion to check
|
|
24
|
+
* @param senderId - The user who sent the message
|
|
25
|
+
* @param botIdToCheck - The specific bot ID to check for direct message
|
|
26
|
+
* @returns The bot ID if it's a 1:1 conversation with that bot, null otherwise
|
|
27
|
+
*/
|
|
28
|
+
private isDirectMessageToBot;
|
|
29
|
+
extractMessage(signal: HailerSignal): Promise<ChatMessage[]>;
|
|
30
|
+
private extractFromMessengerNew;
|
|
31
|
+
postMessage(discussionId: string, content: string, workspaceId?: string, botId?: string): Promise<boolean>;
|
|
32
|
+
postInfoMessage(discussionId: string, toolName: string, args: any, workspaceId?: string, botId?: string): Promise<boolean>;
|
|
33
|
+
postErrorMessage(discussionId: string, error: string, workspaceId?: string, botId?: string): Promise<boolean>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=message-processor.d.ts.map
|