@hailer/mcp 0.1.17 → 0.2.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/dist/app.js +24 -20
- package/dist/core.d.ts +33 -9
- package/dist/core.js +279 -147
- package/dist/mcp/UserContextCache.js +18 -0
- package/dist/mcp/hailer-clients.d.ts +9 -1
- package/dist/mcp/hailer-clients.js +13 -3
- package/dist/mcp/signal-handler.js +1 -1
- package/dist/mcp/tool-registry.d.ts +3 -1
- package/dist/mcp/tool-registry.js +4 -1
- package/dist/mcp/tools/activity.js +43 -34
- package/dist/mcp/tools/bot-config/constants.d.ts +23 -0
- package/dist/mcp/tools/bot-config/constants.js +94 -0
- package/dist/mcp/tools/{bot-config.d.ts → bot-config/core.d.ts} +6 -6
- package/dist/mcp/tools/{bot-config.js → bot-config/core.js} +15 -15
- package/dist/mcp/tools/bot-config/index.d.ts +10 -0
- package/dist/mcp/tools/bot-config/index.js +59 -0
- package/dist/mcp/tools/bot-config/tools.d.ts +7 -0
- package/dist/mcp/tools/bot-config/tools.js +15 -0
- package/dist/mcp/tools/bot-config/types.d.ts +50 -0
- package/dist/mcp/tools/bot-config/types.js +6 -0
- package/dist/mcp/tools/bug-fixer-tools.d.ts +21 -0
- package/dist/mcp/tools/{giuseppe-tools.js → bug-fixer-tools.js} +61 -61
- package/dist/mcp/tools/user.js +10 -29
- package/dist/mcp/tools/workflow.js +36 -2
- package/dist/mcp/utils/data-transformers.d.ts +0 -8
- package/dist/mcp/utils/data-transformers.js +0 -28
- package/dist/mcp/utils/index.d.ts +4 -1
- package/dist/mcp/utils/index.js +17 -3
- package/dist/mcp/utils/pagination.d.ts +40 -0
- package/dist/mcp/utils/pagination.js +55 -0
- package/dist/mcp/utils/response-builder.d.ts +53 -0
- package/dist/mcp/utils/response-builder.js +110 -0
- package/dist/mcp/utils/tool-helpers.d.ts +0 -8
- package/dist/mcp/utils/tool-helpers.js +0 -24
- package/dist/mcp/utils/types.d.ts +1 -33
- package/dist/mcp-server.d.ts +2 -2
- package/dist/mcp-server.js +161 -139
- package/package.json +1 -1
- package/REFACTOR_STATUS.md +0 -127
- package/dist/agents/bot-manager.d.ts +0 -48
- package/dist/agents/bot-manager.js +0 -254
- package/dist/agents/factory.d.ts +0 -150
- package/dist/agents/factory.js +0 -650
- package/dist/agents/giuseppe/ai.d.ts +0 -83
- package/dist/agents/giuseppe/ai.js +0 -466
- package/dist/agents/giuseppe/bot.d.ts +0 -110
- package/dist/agents/giuseppe/bot.js +0 -780
- package/dist/agents/giuseppe/config.d.ts +0 -25
- package/dist/agents/giuseppe/config.js +0 -227
- package/dist/agents/giuseppe/files.d.ts +0 -52
- package/dist/agents/giuseppe/files.js +0 -338
- package/dist/agents/giuseppe/git.d.ts +0 -48
- package/dist/agents/giuseppe/git.js +0 -298
- package/dist/agents/giuseppe/index.d.ts +0 -97
- package/dist/agents/giuseppe/index.js +0 -258
- package/dist/agents/giuseppe/lsp.d.ts +0 -113
- package/dist/agents/giuseppe/lsp.js +0 -485
- package/dist/agents/giuseppe/monitor.d.ts +0 -118
- package/dist/agents/giuseppe/monitor.js +0 -621
- package/dist/agents/giuseppe/prompt.d.ts +0 -5
- package/dist/agents/giuseppe/prompt.js +0 -94
- package/dist/agents/giuseppe/registries/pending-classification.d.ts +0 -28
- package/dist/agents/giuseppe/registries/pending-classification.js +0 -50
- package/dist/agents/giuseppe/registries/pending-fix.d.ts +0 -30
- package/dist/agents/giuseppe/registries/pending-fix.js +0 -42
- package/dist/agents/giuseppe/registries/pending.d.ts +0 -27
- package/dist/agents/giuseppe/registries/pending.js +0 -49
- package/dist/agents/giuseppe/specialist.d.ts +0 -47
- package/dist/agents/giuseppe/specialist.js +0 -237
- package/dist/agents/giuseppe/types.d.ts +0 -123
- package/dist/agents/giuseppe/types.js +0 -9
- package/dist/agents/hailer-expert/index.d.ts +0 -8
- package/dist/agents/hailer-expert/index.js +0 -14
- package/dist/agents/hal/daemon.d.ts +0 -142
- package/dist/agents/hal/daemon.js +0 -1103
- package/dist/agents/hal/definitions.d.ts +0 -55
- package/dist/agents/hal/definitions.js +0 -263
- package/dist/agents/hal/index.d.ts +0 -3
- package/dist/agents/hal/index.js +0 -8
- package/dist/agents/index.d.ts +0 -18
- package/dist/agents/index.js +0 -48
- package/dist/agents/shared/base.d.ts +0 -216
- package/dist/agents/shared/base.js +0 -846
- package/dist/agents/shared/services/agent-registry.d.ts +0 -107
- package/dist/agents/shared/services/agent-registry.js +0 -629
- package/dist/agents/shared/services/conversation-manager.d.ts +0 -50
- package/dist/agents/shared/services/conversation-manager.js +0 -136
- package/dist/agents/shared/services/mcp-client.d.ts +0 -56
- package/dist/agents/shared/services/mcp-client.js +0 -124
- package/dist/agents/shared/services/message-classifier.d.ts +0 -37
- package/dist/agents/shared/services/message-classifier.js +0 -187
- package/dist/agents/shared/services/message-formatter.d.ts +0 -89
- package/dist/agents/shared/services/message-formatter.js +0 -371
- package/dist/agents/shared/services/session-logger.d.ts +0 -106
- package/dist/agents/shared/services/session-logger.js +0 -446
- package/dist/agents/shared/services/tool-executor.d.ts +0 -41
- package/dist/agents/shared/services/tool-executor.js +0 -169
- package/dist/agents/shared/services/workspace-schema-cache.d.ts +0 -125
- package/dist/agents/shared/services/workspace-schema-cache.js +0 -578
- package/dist/agents/shared/specialist.d.ts +0 -91
- package/dist/agents/shared/specialist.js +0 -399
- package/dist/agents/shared/tool-schema-loader.d.ts +0 -62
- package/dist/agents/shared/tool-schema-loader.js +0 -232
- package/dist/agents/shared/types.d.ts +0 -327
- package/dist/agents/shared/types.js +0 -121
- package/dist/client/agents/base.d.ts +0 -207
- package/dist/client/agents/base.js +0 -744
- package/dist/client/agents/definitions.d.ts +0 -53
- package/dist/client/agents/definitions.js +0 -263
- package/dist/client/agents/orchestrator.d.ts +0 -141
- package/dist/client/agents/orchestrator.js +0 -1062
- package/dist/client/agents/specialist.d.ts +0 -86
- package/dist/client/agents/specialist.js +0 -340
- package/dist/client/bot-entrypoint.d.ts +0 -7
- package/dist/client/bot-entrypoint.js +0 -103
- package/dist/client/bot-manager.d.ts +0 -44
- package/dist/client/bot-manager.js +0 -173
- package/dist/client/bot-runner.d.ts +0 -35
- package/dist/client/bot-runner.js +0 -188
- package/dist/client/chat-agent-daemon.d.ts +0 -464
- package/dist/client/chat-agent-daemon.js +0 -1774
- package/dist/client/daemon-factory.d.ts +0 -106
- package/dist/client/daemon-factory.js +0 -301
- package/dist/client/factory.d.ts +0 -111
- package/dist/client/factory.js +0 -314
- package/dist/client/index.d.ts +0 -17
- package/dist/client/index.js +0 -38
- package/dist/client/multi-bot-manager.d.ts +0 -42
- package/dist/client/multi-bot-manager.js +0 -161
- package/dist/client/orchestrator-daemon.d.ts +0 -87
- package/dist/client/orchestrator-daemon.js +0 -444
- package/dist/client/server.d.ts +0 -8
- package/dist/client/server.js +0 -251
- package/dist/client/services/agent-registry.d.ts +0 -108
- package/dist/client/services/agent-registry.js +0 -630
- package/dist/client/services/conversation-manager.d.ts +0 -50
- package/dist/client/services/conversation-manager.js +0 -136
- package/dist/client/services/mcp-client.d.ts +0 -48
- package/dist/client/services/mcp-client.js +0 -105
- package/dist/client/services/message-classifier.d.ts +0 -37
- package/dist/client/services/message-classifier.js +0 -187
- package/dist/client/services/message-formatter.d.ts +0 -84
- package/dist/client/services/message-formatter.js +0 -353
- package/dist/client/services/session-logger.d.ts +0 -106
- package/dist/client/services/session-logger.js +0 -446
- package/dist/client/services/tool-executor.d.ts +0 -41
- package/dist/client/services/tool-executor.js +0 -169
- package/dist/client/services/workspace-schema-cache.d.ts +0 -149
- package/dist/client/services/workspace-schema-cache.js +0 -732
- package/dist/client/specialist-daemon.d.ts +0 -77
- package/dist/client/specialist-daemon.js +0 -197
- package/dist/client/specialists.d.ts +0 -53
- package/dist/client/specialists.js +0 -178
- package/dist/client/tool-schema-loader.d.ts +0 -62
- package/dist/client/tool-schema-loader.js +0 -232
- package/dist/client/types.d.ts +0 -327
- package/dist/client/types.js +0 -121
- package/dist/commands/seed-config.d.ts +0 -9
- package/dist/commands/seed-config.js +0 -372
- package/dist/lib/context-manager.d.ts +0 -111
- package/dist/lib/context-manager.js +0 -431
- package/dist/lib/prompt-length-manager.d.ts +0 -81
- package/dist/lib/prompt-length-manager.js +0 -457
- package/dist/mcp/tools/giuseppe-tools.d.ts +0 -21
- package/dist/modules/bug-reports/bug-config.d.ts +0 -25
- package/dist/modules/bug-reports/bug-config.js +0 -187
- package/dist/modules/bug-reports/bug-monitor.d.ts +0 -108
- package/dist/modules/bug-reports/bug-monitor.js +0 -510
- package/dist/modules/bug-reports/giuseppe-agent.d.ts +0 -58
- package/dist/modules/bug-reports/giuseppe-agent.js +0 -467
- package/dist/modules/bug-reports/giuseppe-ai.d.ts +0 -83
- package/dist/modules/bug-reports/giuseppe-ai.js +0 -466
- package/dist/modules/bug-reports/giuseppe-bot.d.ts +0 -110
- package/dist/modules/bug-reports/giuseppe-bot.js +0 -804
- package/dist/modules/bug-reports/giuseppe-daemon.d.ts +0 -80
- package/dist/modules/bug-reports/giuseppe-daemon.js +0 -617
- package/dist/modules/bug-reports/giuseppe-files.d.ts +0 -64
- package/dist/modules/bug-reports/giuseppe-files.js +0 -375
- package/dist/modules/bug-reports/giuseppe-git.d.ts +0 -48
- package/dist/modules/bug-reports/giuseppe-git.js +0 -298
- package/dist/modules/bug-reports/giuseppe-lsp.d.ts +0 -113
- package/dist/modules/bug-reports/giuseppe-lsp.js +0 -485
- package/dist/modules/bug-reports/giuseppe-prompt.d.ts +0 -5
- package/dist/modules/bug-reports/giuseppe-prompt.js +0 -94
- package/dist/modules/bug-reports/index.d.ts +0 -77
- package/dist/modules/bug-reports/index.js +0 -215
- package/dist/modules/bug-reports/pending-classification-registry.d.ts +0 -28
- package/dist/modules/bug-reports/pending-classification-registry.js +0 -50
- package/dist/modules/bug-reports/pending-fix-registry.d.ts +0 -30
- package/dist/modules/bug-reports/pending-fix-registry.js +0 -42
- package/dist/modules/bug-reports/pending-registry.d.ts +0 -27
- package/dist/modules/bug-reports/pending-registry.js +0 -49
- package/dist/modules/bug-reports/types.d.ts +0 -123
- package/dist/modules/bug-reports/types.js +0 -9
- package/dist/routes/agents.d.ts +0 -44
- package/dist/routes/agents.js +0 -311
- package/dist/services/agent-credential-store.d.ts +0 -73
- package/dist/services/agent-credential-store.js +0 -212
- package/dist/services/bug-monitor.d.ts +0 -23
- package/dist/services/bug-monitor.js +0 -275
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Conversation Manager Service
|
|
4
|
-
*
|
|
5
|
-
* Manages per-discussion conversation state:
|
|
6
|
-
* - LRU cache of conversation histories
|
|
7
|
-
* - Context size management with summarization
|
|
8
|
-
* - Conversation state access
|
|
9
|
-
*/
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.ConversationManager = void 0;
|
|
12
|
-
class ConversationManager {
|
|
13
|
-
maxConversations;
|
|
14
|
-
maxContextMessages;
|
|
15
|
-
anthropicClient;
|
|
16
|
-
logger;
|
|
17
|
-
conversationsByDiscussion = new Map();
|
|
18
|
-
constructor(maxConversations, maxContextMessages, anthropicClient, logger) {
|
|
19
|
-
this.maxConversations = maxConversations;
|
|
20
|
-
this.maxContextMessages = maxContextMessages;
|
|
21
|
-
this.anthropicClient = anthropicClient;
|
|
22
|
-
this.logger = logger;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Get or create conversation history for a specific discussion
|
|
26
|
-
* Each discussion has its own isolated context to prevent bloat
|
|
27
|
-
* Uses LRU eviction when map exceeds maxConversations
|
|
28
|
-
*/
|
|
29
|
-
getConversation(discussionId) {
|
|
30
|
-
let conversation = this.conversationsByDiscussion.get(discussionId);
|
|
31
|
-
if (conversation) {
|
|
32
|
-
// Move to end for LRU (delete and re-add to update insertion order)
|
|
33
|
-
this.conversationsByDiscussion.delete(discussionId);
|
|
34
|
-
this.conversationsByDiscussion.set(discussionId, conversation);
|
|
35
|
-
return conversation;
|
|
36
|
-
}
|
|
37
|
-
// Evict oldest conversations if at capacity
|
|
38
|
-
if (this.conversationsByDiscussion.size >= this.maxConversations) {
|
|
39
|
-
const toEvict = this.conversationsByDiscussion.size - this.maxConversations + 1;
|
|
40
|
-
const keys = [...this.conversationsByDiscussion.keys()].slice(0, toEvict);
|
|
41
|
-
for (const key of keys) {
|
|
42
|
-
this.conversationsByDiscussion.delete(key);
|
|
43
|
-
}
|
|
44
|
-
this.logger.debug("Evicted old conversations", { evicted: toEvict, remaining: this.conversationsByDiscussion.size });
|
|
45
|
-
}
|
|
46
|
-
conversation = [];
|
|
47
|
-
this.conversationsByDiscussion.set(discussionId, conversation);
|
|
48
|
-
this.logger.debug("Created new conversation context", { discussionId });
|
|
49
|
-
return conversation;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Add a message to a conversation
|
|
53
|
-
*/
|
|
54
|
-
addMessage(discussionId, message) {
|
|
55
|
-
const conversation = this.getConversation(discussionId);
|
|
56
|
-
conversation.push(message);
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Manage conversation context size - summarize if too large
|
|
60
|
-
*/
|
|
61
|
-
async manageContextSize(discussionId) {
|
|
62
|
-
const conversation = this.getConversation(discussionId);
|
|
63
|
-
if (conversation.length > this.maxContextMessages) {
|
|
64
|
-
this.logger.info("Context size limit reached, summarizing", {
|
|
65
|
-
discussionId,
|
|
66
|
-
messageCount: conversation.length,
|
|
67
|
-
});
|
|
68
|
-
// Keep last 10 messages, summarize the rest
|
|
69
|
-
const toSummarize = conversation.slice(0, -10);
|
|
70
|
-
const toKeep = conversation.slice(-10);
|
|
71
|
-
// Create summary using LLM with structured content to mitigate prompt injection
|
|
72
|
-
const summaryResponse = await this.anthropicClient.messages.create({
|
|
73
|
-
model: "claude-haiku-4-5-20251001",
|
|
74
|
-
max_tokens: 1000,
|
|
75
|
-
messages: [
|
|
76
|
-
{
|
|
77
|
-
role: "user",
|
|
78
|
-
content: [
|
|
79
|
-
{ type: "text", text: "Summarize this conversation context concisely, preserving key information. The conversation data follows in JSON format:" },
|
|
80
|
-
{ type: "text", text: JSON.stringify(toSummarize) },
|
|
81
|
-
],
|
|
82
|
-
},
|
|
83
|
-
],
|
|
84
|
-
});
|
|
85
|
-
const summary = summaryResponse.content
|
|
86
|
-
.filter((b) => b.type === "text")
|
|
87
|
-
.map(b => b.text)
|
|
88
|
-
.join("\n");
|
|
89
|
-
// Replace conversation with summary + recent messages
|
|
90
|
-
const newConversation = [
|
|
91
|
-
{
|
|
92
|
-
role: "user",
|
|
93
|
-
content: `<context_summary>${summary}</context_summary>`,
|
|
94
|
-
},
|
|
95
|
-
...toKeep,
|
|
96
|
-
];
|
|
97
|
-
this.conversationsByDiscussion.set(discussionId, newConversation);
|
|
98
|
-
this.logger.info("Context summarized", {
|
|
99
|
-
discussionId,
|
|
100
|
-
originalCount: toSummarize.length + toKeep.length,
|
|
101
|
-
newCount: newConversation.length,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Get conversation state for debugging
|
|
107
|
-
*/
|
|
108
|
-
getState(currentDiscussionId) {
|
|
109
|
-
const currentConvo = currentDiscussionId
|
|
110
|
-
? this.conversationsByDiscussion.get(currentDiscussionId)
|
|
111
|
-
: null;
|
|
112
|
-
return {
|
|
113
|
-
discussionCount: this.conversationsByDiscussion.size,
|
|
114
|
-
currentMessageCount: currentConvo?.length ?? 0,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Get full conversation for a discussion (for debugging)
|
|
119
|
-
*/
|
|
120
|
-
getFullConversation(discussionId) {
|
|
121
|
-
if (!discussionId) {
|
|
122
|
-
// Return first conversation if no ID specified
|
|
123
|
-
const first = this.conversationsByDiscussion.values().next().value;
|
|
124
|
-
return first || [];
|
|
125
|
-
}
|
|
126
|
-
return this.conversationsByDiscussion.get(discussionId) || [];
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Clear all conversations
|
|
130
|
-
*/
|
|
131
|
-
clear() {
|
|
132
|
-
this.conversationsByDiscussion.clear();
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
exports.ConversationManager = ConversationManager;
|
|
136
|
-
//# sourceMappingURL=conversation-manager.js.map
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP Client Service
|
|
3
|
-
*
|
|
4
|
-
* Handles all communication with the MCP server:
|
|
5
|
-
* - Tool schema loading
|
|
6
|
-
* - Tool execution
|
|
7
|
-
* - Response parsing
|
|
8
|
-
*/
|
|
9
|
-
import { Logger } from "../../../lib/logger";
|
|
10
|
-
import { ToolInput, McpToolResult } from "../../shared/types";
|
|
11
|
-
/** MCP tool schema definition */
|
|
12
|
-
export interface McpToolSchema {
|
|
13
|
-
name: string;
|
|
14
|
-
description?: string;
|
|
15
|
-
inputSchema?: {
|
|
16
|
-
type: string;
|
|
17
|
-
properties?: Record<string, unknown>;
|
|
18
|
-
required?: string[];
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
export declare class McpClientService {
|
|
22
|
-
private mcpServerUrl;
|
|
23
|
-
private mcpServerApiKey;
|
|
24
|
-
private loadedToolSchemas;
|
|
25
|
-
private logger;
|
|
26
|
-
constructor(mcpServerUrl: string, mcpServerApiKey: string, logger: Logger);
|
|
27
|
-
/**
|
|
28
|
-
* Mask sensitive data for safe logging
|
|
29
|
-
*/
|
|
30
|
-
private maskApiKey;
|
|
31
|
-
/**
|
|
32
|
-
* Create safe error without exposing API key
|
|
33
|
-
*/
|
|
34
|
-
private createSafeError;
|
|
35
|
-
/**
|
|
36
|
-
* Fetch tool schema from MCP server
|
|
37
|
-
*/
|
|
38
|
-
fetchToolSchema(toolName: string): Promise<any>;
|
|
39
|
-
/**
|
|
40
|
-
* Call MCP tool
|
|
41
|
-
*/
|
|
42
|
-
callMcpTool(name: string, args: ToolInput): Promise<McpToolResult>;
|
|
43
|
-
/**
|
|
44
|
-
* Load tool schema if not already loaded
|
|
45
|
-
*/
|
|
46
|
-
loadToolSchemaIfNeeded(toolName: string): Promise<McpToolSchema | undefined>;
|
|
47
|
-
/**
|
|
48
|
-
* Get cached tool schema
|
|
49
|
-
*/
|
|
50
|
-
getCachedToolSchema(toolName: string): McpToolSchema | undefined;
|
|
51
|
-
/**
|
|
52
|
-
* Clear tool schema cache
|
|
53
|
-
*/
|
|
54
|
-
clearSchemaCache(): void;
|
|
55
|
-
}
|
|
56
|
-
//# sourceMappingURL=mcp-client.d.ts.map
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* MCP Client Service
|
|
4
|
-
*
|
|
5
|
-
* Handles all communication with the MCP server:
|
|
6
|
-
* - Tool schema loading
|
|
7
|
-
* - Tool execution
|
|
8
|
-
* - Response parsing
|
|
9
|
-
*/
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.McpClientService = void 0;
|
|
12
|
-
class McpClientService {
|
|
13
|
-
mcpServerUrl;
|
|
14
|
-
mcpServerApiKey;
|
|
15
|
-
loadedToolSchemas = new Map();
|
|
16
|
-
logger;
|
|
17
|
-
constructor(mcpServerUrl, mcpServerApiKey, logger) {
|
|
18
|
-
this.mcpServerUrl = mcpServerUrl;
|
|
19
|
-
this.mcpServerApiKey = mcpServerApiKey;
|
|
20
|
-
this.logger = logger;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Mask sensitive data for safe logging
|
|
24
|
-
*/
|
|
25
|
-
maskApiKey(key) {
|
|
26
|
-
if (!key || key.length < 8)
|
|
27
|
-
return '***';
|
|
28
|
-
return `${key.slice(0, 4)}...${key.slice(-4)}`;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Create safe error without exposing API key
|
|
32
|
-
*/
|
|
33
|
-
createSafeError(message, originalError) {
|
|
34
|
-
const safeMessage = message.replace(this.mcpServerApiKey, this.maskApiKey(this.mcpServerApiKey));
|
|
35
|
-
const error = new Error(safeMessage);
|
|
36
|
-
if (originalError instanceof Error) {
|
|
37
|
-
error.stack = originalError.stack?.replace(this.mcpServerApiKey, this.maskApiKey(this.mcpServerApiKey));
|
|
38
|
-
}
|
|
39
|
-
return error;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Fetch tool schema from MCP server
|
|
43
|
-
*/
|
|
44
|
-
async fetchToolSchema(toolName) {
|
|
45
|
-
const url = `${this.mcpServerUrl}?apiKey=${this.mcpServerApiKey}`;
|
|
46
|
-
const response = await fetch(url, {
|
|
47
|
-
method: "POST",
|
|
48
|
-
headers: { "Content-Type": "application/json" },
|
|
49
|
-
body: JSON.stringify({
|
|
50
|
-
jsonrpc: "2.0",
|
|
51
|
-
id: Math.random().toString(36).substring(2),
|
|
52
|
-
method: "tools/get_schema",
|
|
53
|
-
params: { name: toolName },
|
|
54
|
-
}),
|
|
55
|
-
});
|
|
56
|
-
const text = await response.text();
|
|
57
|
-
const lines = text.split("\n");
|
|
58
|
-
for (const line of lines) {
|
|
59
|
-
if (line.startsWith("data: ")) {
|
|
60
|
-
const data = JSON.parse(line.substring(6));
|
|
61
|
-
if (data.result) {
|
|
62
|
-
return {
|
|
63
|
-
name: data.result.name,
|
|
64
|
-
description: data.result.description,
|
|
65
|
-
input_schema: data.result.inputSchema,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
throw this.createSafeError(`Failed to load schema for ${toolName}`);
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Call MCP tool
|
|
74
|
-
*/
|
|
75
|
-
async callMcpTool(name, args) {
|
|
76
|
-
const url = `${this.mcpServerUrl}?apiKey=${this.mcpServerApiKey}`;
|
|
77
|
-
const response = await fetch(url, {
|
|
78
|
-
method: "POST",
|
|
79
|
-
headers: { "Content-Type": "application/json" },
|
|
80
|
-
body: JSON.stringify({
|
|
81
|
-
jsonrpc: "2.0",
|
|
82
|
-
id: Math.random().toString(36).substring(2),
|
|
83
|
-
method: "tools/call",
|
|
84
|
-
params: { name, arguments: args },
|
|
85
|
-
}),
|
|
86
|
-
});
|
|
87
|
-
const text = await response.text();
|
|
88
|
-
const lines = text.split("\n");
|
|
89
|
-
for (const line of lines) {
|
|
90
|
-
if (line.startsWith("data: ")) {
|
|
91
|
-
const data = JSON.parse(line.substring(6));
|
|
92
|
-
if (data.error) {
|
|
93
|
-
throw this.createSafeError(data.error.message || String(data.error));
|
|
94
|
-
}
|
|
95
|
-
return data.result;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
throw this.createSafeError("Failed to parse MCP response");
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Load tool schema if not already loaded
|
|
102
|
-
*/
|
|
103
|
-
async loadToolSchemaIfNeeded(toolName) {
|
|
104
|
-
if (!this.loadedToolSchemas.has(toolName)) {
|
|
105
|
-
const schema = await this.fetchToolSchema(toolName);
|
|
106
|
-
this.loadedToolSchemas.set(toolName, schema);
|
|
107
|
-
}
|
|
108
|
-
return this.loadedToolSchemas.get(toolName);
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Get cached tool schema
|
|
112
|
-
*/
|
|
113
|
-
getCachedToolSchema(toolName) {
|
|
114
|
-
return this.loadedToolSchemas.get(toolName);
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Clear tool schema cache
|
|
118
|
-
*/
|
|
119
|
-
clearSchemaCache() {
|
|
120
|
-
this.loadedToolSchemas.clear();
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
exports.McpClientService = McpClientService;
|
|
124
|
-
//# sourceMappingURL=mcp-client.js.map
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Message Classifier Service
|
|
3
|
-
*
|
|
4
|
-
* Handles incoming message extraction and classification:
|
|
5
|
-
* - Extracts message content from Hailer signals
|
|
6
|
-
* - Classifies message priority (high/normal)
|
|
7
|
-
* - Detects mentions, replies, and DMs
|
|
8
|
-
*/
|
|
9
|
-
import { Logger } from "../../../lib/logger";
|
|
10
|
-
import { BotClient } from "../../bot-manager";
|
|
11
|
-
import { HailerSignal } from "../../../mcp/signal-handler";
|
|
12
|
-
import { IncomingMessage } from "../../shared/types";
|
|
13
|
-
export declare class MessageClassifier {
|
|
14
|
-
private botUserId;
|
|
15
|
-
private botClient;
|
|
16
|
-
private logger;
|
|
17
|
-
private mentionPattern;
|
|
18
|
-
constructor(botUserId: string, botClient: BotClient, logger: Logger);
|
|
19
|
-
/**
|
|
20
|
-
* Extract and classify incoming message from signal
|
|
21
|
-
*/
|
|
22
|
-
extractIncomingMessage(signal: HailerSignal): Promise<IncomingMessage | null>;
|
|
23
|
-
/**
|
|
24
|
-
* Check if message mentions this bot
|
|
25
|
-
* Uses pre-compiled regex pattern for performance
|
|
26
|
-
*/
|
|
27
|
-
checkMention(content: string): boolean;
|
|
28
|
-
/**
|
|
29
|
-
* Check if message is a reply to one of our messages
|
|
30
|
-
*/
|
|
31
|
-
checkReplyToBot(discussionId: string, messageId: string): Promise<boolean>;
|
|
32
|
-
/**
|
|
33
|
-
* Check if this is a 1:1 DM with the bot
|
|
34
|
-
*/
|
|
35
|
-
checkDirectMessage(discussionId: string, senderId: string): Promise<boolean>;
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=message-classifier.d.ts.map
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Message Classifier Service
|
|
4
|
-
*
|
|
5
|
-
* Handles incoming message extraction and classification:
|
|
6
|
-
* - Extracts message content from Hailer signals
|
|
7
|
-
* - Classifies message priority (high/normal)
|
|
8
|
-
* - Detects mentions, replies, and DMs
|
|
9
|
-
*/
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.MessageClassifier = void 0;
|
|
12
|
-
class MessageClassifier {
|
|
13
|
-
botUserId;
|
|
14
|
-
botClient;
|
|
15
|
-
logger;
|
|
16
|
-
// Pre-compiled mention pattern for performance
|
|
17
|
-
mentionPattern;
|
|
18
|
-
constructor(botUserId, botClient, logger) {
|
|
19
|
-
this.botUserId = botUserId;
|
|
20
|
-
this.botClient = botClient;
|
|
21
|
-
this.logger = logger;
|
|
22
|
-
// Compile mention pattern once
|
|
23
|
-
this.mentionPattern = new RegExp(`\\[hailerTag\\|[^\\]]+\\]\\(${this.botUserId}\\)`, "i");
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Extract and classify incoming message from signal
|
|
27
|
-
*/
|
|
28
|
-
async extractIncomingMessage(signal) {
|
|
29
|
-
const { discussion, msg_id, uid } = signal.data;
|
|
30
|
-
// Skip our own messages
|
|
31
|
-
if (uid === this.botUserId) {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
// Fetch the actual message content
|
|
35
|
-
let messageContent = "";
|
|
36
|
-
let senderName = "Unknown";
|
|
37
|
-
try {
|
|
38
|
-
const response = await this.botClient.client.socket.request("v3.discussion.message.latest", [discussion]);
|
|
39
|
-
const messages = response?.messages || [];
|
|
40
|
-
const targetMessage = messages.find((msg) => msg._id === msg_id);
|
|
41
|
-
if (!targetMessage) {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
messageContent = targetMessage.msg || targetMessage.content || "";
|
|
45
|
-
// Get sender name: try workspace cache first, then message field
|
|
46
|
-
const cachedUser = this.botClient.workspaceCache?.usersById[uid];
|
|
47
|
-
const cachedName = cachedUser?.fullName ?? `${cachedUser?.firstname || ''} ${cachedUser?.lastname || ''}`.trim();
|
|
48
|
-
senderName = cachedName || targetMessage.userName || "Unknown";
|
|
49
|
-
// Skip system messages
|
|
50
|
-
if (targetMessage.type && targetMessage.type !== "user") {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
this.logger.warn("Could not fetch message content", { error });
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
// Classify priority
|
|
59
|
-
const isMention = this.checkMention(messageContent);
|
|
60
|
-
const isReplyToBot = await this.checkReplyToBot(discussion, msg_id);
|
|
61
|
-
const isDirectMessage = await this.checkDirectMessage(discussion, uid);
|
|
62
|
-
// Get linked activity ID, name, and workspace ID from discussion metadata
|
|
63
|
-
let linkedActivityId;
|
|
64
|
-
let linkedActivityName;
|
|
65
|
-
let discussionWorkspaceId;
|
|
66
|
-
try {
|
|
67
|
-
const discussionResponse = await this.botClient.client.socket.request("messenger.load_discussions", [[discussion]]);
|
|
68
|
-
if (discussionResponse && discussionResponse[discussion]) {
|
|
69
|
-
const discData = discussionResponse[discussion];
|
|
70
|
-
linkedActivityId = discData.linked_activity;
|
|
71
|
-
linkedActivityName = discData.name; // Discussion name is usually the activity name
|
|
72
|
-
discussionWorkspaceId = discData.cid; // Workspace ID (cid = company ID in Hailer)
|
|
73
|
-
this.logger.debug("Discussion metadata loaded", {
|
|
74
|
-
discussionId: discussion,
|
|
75
|
-
linkedActivityId: linkedActivityId || "none",
|
|
76
|
-
linkedActivityName: linkedActivityName || "none",
|
|
77
|
-
hasLinkedActivity: !!linkedActivityId,
|
|
78
|
-
cid: discussionWorkspaceId || "not in response",
|
|
79
|
-
discDataKeys: Object.keys(discData).join(","),
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
catch (error) {
|
|
84
|
-
this.logger.debug("Failed to load discussion metadata", {
|
|
85
|
-
discussionId: discussion,
|
|
86
|
-
error: error instanceof Error ? error.message : String(error),
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
let priority = "normal";
|
|
90
|
-
let priorityReason = "General chat message";
|
|
91
|
-
if (isDirectMessage) {
|
|
92
|
-
priority = "high";
|
|
93
|
-
priorityReason = "Direct message (1:1 conversation)";
|
|
94
|
-
}
|
|
95
|
-
else if (isMention) {
|
|
96
|
-
priority = "high";
|
|
97
|
-
priorityReason = "Bot mentioned in message";
|
|
98
|
-
}
|
|
99
|
-
else if (isReplyToBot) {
|
|
100
|
-
priority = "high";
|
|
101
|
-
priorityReason = "Reply to bot's message";
|
|
102
|
-
}
|
|
103
|
-
// Extract workspaceId - prefer discussion metadata (accurate), fallback to signal
|
|
104
|
-
// Discussion metadata contains authoritative workspace ID from Hailer
|
|
105
|
-
const workspaceId = discussionWorkspaceId || signal.workspaceId;
|
|
106
|
-
if (!workspaceId) {
|
|
107
|
-
this.logger.warn("Cannot determine workspace - rejecting message for isolation safety", {
|
|
108
|
-
discussionId: discussion,
|
|
109
|
-
messageId: msg_id,
|
|
110
|
-
discussionWorkspaceId: discussionWorkspaceId || "none",
|
|
111
|
-
signalWorkspaceId: signal.workspaceId || "none",
|
|
112
|
-
});
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
// Debug log workspace context (normal in multi-tenant setup)
|
|
116
|
-
if (discussionWorkspaceId) {
|
|
117
|
-
this.logger.debug("Message workspace context", {
|
|
118
|
-
discussionId: discussion,
|
|
119
|
-
workspaceId: discussionWorkspaceId,
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
return {
|
|
123
|
-
id: msg_id,
|
|
124
|
-
discussionId: discussion,
|
|
125
|
-
workspaceId,
|
|
126
|
-
linkedActivityId,
|
|
127
|
-
linkedActivityName,
|
|
128
|
-
senderId: uid,
|
|
129
|
-
senderName,
|
|
130
|
-
content: messageContent,
|
|
131
|
-
timestamp: signal.timestamp,
|
|
132
|
-
priority,
|
|
133
|
-
priorityReason,
|
|
134
|
-
isReplyToBot,
|
|
135
|
-
isMention,
|
|
136
|
-
isDirectMessage,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Check if message mentions this bot
|
|
141
|
-
* Uses pre-compiled regex pattern for performance
|
|
142
|
-
*/
|
|
143
|
-
checkMention(content) {
|
|
144
|
-
return this.mentionPattern.test(content);
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Check if message is a reply to one of our messages
|
|
148
|
-
*/
|
|
149
|
-
async checkReplyToBot(discussionId, messageId) {
|
|
150
|
-
try {
|
|
151
|
-
const response = await this.botClient.client.socket.request("v3.discussion.message.latest", [discussionId]);
|
|
152
|
-
const messages = response?.messages || [];
|
|
153
|
-
const targetMessage = messages.find((msg) => msg._id === messageId);
|
|
154
|
-
if (targetMessage?.replyTo) {
|
|
155
|
-
const repliedToMessage = messages.find((msg) => msg._id === targetMessage.replyTo);
|
|
156
|
-
return repliedToMessage?.uid === this.botUserId;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
catch {
|
|
160
|
-
// Ignore errors
|
|
161
|
-
}
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Check if this is a 1:1 DM with the bot
|
|
166
|
-
*/
|
|
167
|
-
async checkDirectMessage(discussionId, senderId) {
|
|
168
|
-
try {
|
|
169
|
-
const response = await this.botClient.client.socket.request("messenger.load_discussions", [[discussionId]]);
|
|
170
|
-
if (response && response[discussionId]) {
|
|
171
|
-
const discussion = response[discussionId];
|
|
172
|
-
const participants = discussion.participants || [];
|
|
173
|
-
// 1:1 = exactly 2 participants: sender and bot
|
|
174
|
-
if (participants.length === 2) {
|
|
175
|
-
return participants.includes(this.botUserId) &&
|
|
176
|
-
participants.includes(senderId);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
catch {
|
|
181
|
-
// Ignore errors
|
|
182
|
-
}
|
|
183
|
-
return false;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
exports.MessageClassifier = MessageClassifier;
|
|
187
|
-
//# sourceMappingURL=message-classifier.js.map
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Message Formatter Service
|
|
3
|
-
*
|
|
4
|
-
* Handles formatting of messages for Hailer:
|
|
5
|
-
* - Converting @mentions and #activity tags to Hailer tags
|
|
6
|
-
* - Resolving user/activity IDs via API
|
|
7
|
-
* - Extracting tag links for messenger.send
|
|
8
|
-
*/
|
|
9
|
-
import { BotClient } from "../../bot-manager";
|
|
10
|
-
import { Logger } from "../../../lib/logger";
|
|
11
|
-
import { McpToolCallback } from "../../shared/types";
|
|
12
|
-
export declare class MessageFormatterService {
|
|
13
|
-
private botClient;
|
|
14
|
-
private logger;
|
|
15
|
-
private callMcpTool;
|
|
16
|
-
constructor(botClient: BotClient, logger: Logger, callMcpTool: McpToolCallback);
|
|
17
|
-
/**
|
|
18
|
-
* Sanitize display name to prevent tag injection attacks
|
|
19
|
-
* Removes/escapes characters that could break the tag format
|
|
20
|
-
*/
|
|
21
|
-
private sanitizeDisplayName;
|
|
22
|
-
/**
|
|
23
|
-
* Validate that targetId is a valid MongoDB ObjectId format
|
|
24
|
-
*/
|
|
25
|
-
private isValidTargetId;
|
|
26
|
-
/**
|
|
27
|
-
* Format a Hailer tag for mentioning a user or activity
|
|
28
|
-
* Hailer requires ZWNBSP (U+FEFF) around the tag
|
|
29
|
-
*/
|
|
30
|
-
private formatHailerTag;
|
|
31
|
-
/**
|
|
32
|
-
* Look up user by ID and create a Hailer tag
|
|
33
|
-
*/
|
|
34
|
-
private createUserTagById;
|
|
35
|
-
/**
|
|
36
|
-
* Look up user by name and create a Hailer tag
|
|
37
|
-
*/
|
|
38
|
-
private createUserTagByName;
|
|
39
|
-
/**
|
|
40
|
-
* Convert @mentions and #activity tags in response to Hailer tags
|
|
41
|
-
* Supports:
|
|
42
|
-
* - @userId (24-char hex MongoDB ID) → user tag
|
|
43
|
-
* - @"Full Name" (quoted name lookup) → user tag
|
|
44
|
-
* - @FirstName (single word name lookup) → user tag
|
|
45
|
-
* - #activityId (24-char hex) → activity tag
|
|
46
|
-
* - #"Activity Name" (quoted) → activity tag (requires lookup)
|
|
47
|
-
*/
|
|
48
|
-
convertMentionsToTags(content: string): string;
|
|
49
|
-
/**
|
|
50
|
-
* Resolve user tags - look up names for IDs via API when not in cache
|
|
51
|
-
* Handles @userId (24-char hex) format
|
|
52
|
-
*/
|
|
53
|
-
resolveUserTags(content: string): Promise<string>;
|
|
54
|
-
/**
|
|
55
|
-
* Resolve activity tags - look up names for IDs and IDs for names
|
|
56
|
-
* Handles both #activityId and #"Activity Name" formats
|
|
57
|
-
*/
|
|
58
|
-
resolveActivityTags(content: string): Promise<string>;
|
|
59
|
-
/**
|
|
60
|
-
* Convert Hailer URLs to Hailer tags
|
|
61
|
-
* Handles:
|
|
62
|
-
* - https://app.hailer.com/#/activities/{activityId}
|
|
63
|
-
* - https://app.hailer.com/#/discussions/{discussionId}
|
|
64
|
-
*/
|
|
65
|
-
resolveHailerUrls(content: string): Promise<string>;
|
|
66
|
-
/**
|
|
67
|
-
* Extract link metadata from hailerTag formatted content
|
|
68
|
-
* Returns array of links for the messenger.send API
|
|
69
|
-
*/
|
|
70
|
-
extractTagLinks(content: string): Array<{
|
|
71
|
-
target: string;
|
|
72
|
-
targetType: string;
|
|
73
|
-
type: string;
|
|
74
|
-
}>;
|
|
75
|
-
/**
|
|
76
|
-
* Format incoming message for LLM consumption
|
|
77
|
-
*/
|
|
78
|
-
formatIncomingMessage(message: {
|
|
79
|
-
discussionId: string;
|
|
80
|
-
linkedActivityId?: string;
|
|
81
|
-
senderName: string;
|
|
82
|
-
senderId: string;
|
|
83
|
-
timestamp: number;
|
|
84
|
-
priority: string;
|
|
85
|
-
priorityReason: string;
|
|
86
|
-
content: string;
|
|
87
|
-
}): string;
|
|
88
|
-
}
|
|
89
|
-
//# sourceMappingURL=message-formatter.d.ts.map
|