@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,353 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Message Formatter Service
|
|
4
|
-
*
|
|
5
|
-
* Handles formatting of messages for Hailer:
|
|
6
|
-
* - Converting @mentions and #activity tags to Hailer tags
|
|
7
|
-
* - Resolving user/activity IDs via API
|
|
8
|
-
* - Extracting tag links for messenger.send
|
|
9
|
-
*/
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.MessageFormatterService = void 0;
|
|
12
|
-
class MessageFormatterService {
|
|
13
|
-
botClient;
|
|
14
|
-
logger;
|
|
15
|
-
callMcpTool;
|
|
16
|
-
constructor(botClient, logger, callMcpTool) {
|
|
17
|
-
this.botClient = botClient;
|
|
18
|
-
this.logger = logger;
|
|
19
|
-
this.callMcpTool = callMcpTool;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Format a Hailer tag for mentioning a user or activity
|
|
23
|
-
* Hailer requires ZWNBSP (U+FEFF) around the tag
|
|
24
|
-
*/
|
|
25
|
-
formatHailerTag(targetId, displayName) {
|
|
26
|
-
const ZWNBSP = '\uFEFF';
|
|
27
|
-
return `${ZWNBSP}[hailerTag|${displayName}](${targetId})${ZWNBSP}`;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Get user's display name from workspace cache
|
|
31
|
-
*/
|
|
32
|
-
getUserDisplayName(userId) {
|
|
33
|
-
const cache = this.botClient.workspaceCache;
|
|
34
|
-
if (!cache)
|
|
35
|
-
return null;
|
|
36
|
-
const user = cache.usersById[userId];
|
|
37
|
-
if (!user)
|
|
38
|
-
return null;
|
|
39
|
-
return user.fullName || `${user.firstname || ''} ${user.lastname || ''}`.trim() || null;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Look up user by ID and create a Hailer tag
|
|
43
|
-
*/
|
|
44
|
-
createUserTagById(userId) {
|
|
45
|
-
const cache = this.botClient.workspaceCache;
|
|
46
|
-
if (!cache)
|
|
47
|
-
return null;
|
|
48
|
-
const user = cache.usersById[userId];
|
|
49
|
-
if (!user)
|
|
50
|
-
return null;
|
|
51
|
-
const displayName = user.fullName || `${user.firstname} ${user.lastname}`.trim();
|
|
52
|
-
return this.formatHailerTag(userId, displayName);
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Look up user by name and create a Hailer tag
|
|
56
|
-
*/
|
|
57
|
-
createUserTagByName(name) {
|
|
58
|
-
const cache = this.botClient.workspaceCache;
|
|
59
|
-
if (!cache)
|
|
60
|
-
return null;
|
|
61
|
-
const nameLower = name.toLowerCase();
|
|
62
|
-
const user = cache.users.find(u => {
|
|
63
|
-
const fullName = u.fullName || `${u.firstname} ${u.lastname}`.trim();
|
|
64
|
-
return fullName.toLowerCase() === nameLower ||
|
|
65
|
-
u.firstname?.toLowerCase() === nameLower ||
|
|
66
|
-
u.lastname?.toLowerCase() === nameLower;
|
|
67
|
-
});
|
|
68
|
-
if (!user)
|
|
69
|
-
return null;
|
|
70
|
-
const displayName = user.fullName || `${user.firstname} ${user.lastname}`.trim();
|
|
71
|
-
return this.formatHailerTag(user.id, displayName);
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Convert @mentions and #activity tags in response to Hailer tags
|
|
75
|
-
* Supports:
|
|
76
|
-
* - @userId (24-char hex MongoDB ID) → user tag
|
|
77
|
-
* - @"Full Name" (quoted name lookup) → user tag
|
|
78
|
-
* - @FirstName (single word name lookup) → user tag
|
|
79
|
-
* - #activityId (24-char hex) → activity tag
|
|
80
|
-
* - #"Activity Name" (quoted) → activity tag (requires lookup)
|
|
81
|
-
*/
|
|
82
|
-
convertMentionsToTags(content) {
|
|
83
|
-
// User mentions (from cache)
|
|
84
|
-
const cache = this.botClient.workspaceCache;
|
|
85
|
-
if (cache) {
|
|
86
|
-
// Pattern 1: @userId (24-char hex)
|
|
87
|
-
content = content.replace(/@([a-f0-9]{24})\b/gi, (match, userId) => {
|
|
88
|
-
const tag = this.createUserTagById(userId);
|
|
89
|
-
return tag || match;
|
|
90
|
-
});
|
|
91
|
-
// Pattern 2: @"Full Name" (quoted)
|
|
92
|
-
content = content.replace(/@"([^"]+)"/g, (match, name) => {
|
|
93
|
-
const tag = this.createUserTagByName(name);
|
|
94
|
-
return tag || match;
|
|
95
|
-
});
|
|
96
|
-
// Pattern 3: @FirstName (single word, capitalized)
|
|
97
|
-
content = content.replace(/@([A-Z][a-z]+)\b/g, (match, name) => {
|
|
98
|
-
const tag = this.createUserTagByName(name);
|
|
99
|
-
return tag || match;
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
// Activity tags (#activityId and #"Name") are handled by
|
|
103
|
-
// resolveActivityTags (async) which runs before this
|
|
104
|
-
return content;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Resolve user tags - look up names for IDs via API when not in cache
|
|
108
|
-
* Handles @userId (24-char hex) format
|
|
109
|
-
*/
|
|
110
|
-
async resolveUserTags(content) {
|
|
111
|
-
const pattern = /@([a-f0-9]{24})\b/gi;
|
|
112
|
-
const matches = [...content.matchAll(pattern)];
|
|
113
|
-
for (const match of matches) {
|
|
114
|
-
const userId = match[1];
|
|
115
|
-
// Try cache first
|
|
116
|
-
const cachedTag = this.createUserTagById(userId);
|
|
117
|
-
if (cachedTag) {
|
|
118
|
-
content = content.replace(match[0], cachedTag);
|
|
119
|
-
this.logger.debug("User tag from cache", { userId });
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
// Fallback to API
|
|
123
|
-
try {
|
|
124
|
-
this.logger.info("Resolving user tag via API", { userId });
|
|
125
|
-
const result = await this.callMcpTool("search_workspace_users", { query: userId });
|
|
126
|
-
const resultText = result?.content?.[0]?.text;
|
|
127
|
-
if (resultText) {
|
|
128
|
-
// Parse the JSON array from the response
|
|
129
|
-
// Response format: "Found X users:\n\n```json\n[...]\n```"
|
|
130
|
-
const jsonMatch = resultText.match(/```json\s*([\s\S]*?)\s*```/);
|
|
131
|
-
if (jsonMatch) {
|
|
132
|
-
const users = JSON.parse(jsonMatch[1]);
|
|
133
|
-
const user = users.find((u) => u._id === userId);
|
|
134
|
-
if (user) {
|
|
135
|
-
const displayName = `${user.firstname || ''} ${user.lastname || ''}`.trim() || user.fullName || userId;
|
|
136
|
-
const tag = this.formatHailerTag(userId, displayName);
|
|
137
|
-
content = content.replace(match[0], tag);
|
|
138
|
-
this.logger.info("Created user tag from API", { userId, displayName });
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
catch (error) {
|
|
144
|
-
this.logger.warn("Failed to resolve user tag", { userId, error });
|
|
145
|
-
// Leave as @userId - won't be clickable but visible
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return content;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Resolve activity tags - look up names for IDs and IDs for names
|
|
152
|
-
* Handles both #activityId and #"Activity Name" formats
|
|
153
|
-
*/
|
|
154
|
-
async resolveActivityTags(content) {
|
|
155
|
-
// Pattern 1: #activityId (24-char hex) - need to look up the name
|
|
156
|
-
const activityIdPattern = /#([a-f0-9]{24})\b/gi;
|
|
157
|
-
const idMatches = [...content.matchAll(activityIdPattern)];
|
|
158
|
-
for (const match of idMatches) {
|
|
159
|
-
const activityId = match[1];
|
|
160
|
-
try {
|
|
161
|
-
this.logger.info("Resolving activity tag by ID", { activityId });
|
|
162
|
-
// Fetch activity by ID to get its name
|
|
163
|
-
const result = await this.callMcpTool("show_activity_by_id", {
|
|
164
|
-
activityId: activityId,
|
|
165
|
-
});
|
|
166
|
-
const resultText = result?.content?.[0]?.text;
|
|
167
|
-
this.logger.debug("show_activity_by_id response", {
|
|
168
|
-
hasResult: !!resultText,
|
|
169
|
-
preview: resultText?.substring(0, 200)
|
|
170
|
-
});
|
|
171
|
-
if (resultText) {
|
|
172
|
-
// Response format: "✅ Loaded activity with ID "xxx":\n\n{ JSON }"
|
|
173
|
-
// Extract the JSON part after the header
|
|
174
|
-
const jsonMatch = resultText.match(/\{[\s\S]*\}/);
|
|
175
|
-
if (jsonMatch) {
|
|
176
|
-
const parsed = JSON.parse(jsonMatch[0]);
|
|
177
|
-
const activityName = parsed.name;
|
|
178
|
-
this.logger.info("Extracted activity name", { activityId, activityName });
|
|
179
|
-
if (activityName) {
|
|
180
|
-
const tag = this.formatHailerTag(activityId, activityName);
|
|
181
|
-
content = content.replace(match[0], tag);
|
|
182
|
-
this.logger.info("Created activity tag", { tag });
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
this.logger.warn("Could not extract JSON from response", { preview: resultText.substring(0, 100) });
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
catch (error) {
|
|
191
|
-
this.logger.warn("Failed to resolve activity ID tag", { activityId, error });
|
|
192
|
-
// Leave as #id - won't be clickable but at least visible
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
// Pattern 2: #"Activity Name" - need to look up the ID
|
|
196
|
-
// This is harder because list_activities requires workflowId/phaseId
|
|
197
|
-
// For now, search in each workflow until we find a match
|
|
198
|
-
const activityNamePattern = /#"([^"]+)"/g;
|
|
199
|
-
const nameMatches = [...content.matchAll(activityNamePattern)];
|
|
200
|
-
for (const match of nameMatches) {
|
|
201
|
-
const activityName = match[1];
|
|
202
|
-
try {
|
|
203
|
-
// Get list of workflows first
|
|
204
|
-
const workflowsResult = await this.callMcpTool("list_workflows_minimal", {});
|
|
205
|
-
const workflowsText = workflowsResult?.content?.[0]?.text;
|
|
206
|
-
if (workflowsText) {
|
|
207
|
-
// Extract workflow IDs from the response (format varies)
|
|
208
|
-
const workflowIdMatches = workflowsText.matchAll(/"_id":\s*"([a-f0-9]{24})"/gi);
|
|
209
|
-
const workflowIds = [...workflowIdMatches].map(m => m[1]);
|
|
210
|
-
// Search each workflow for the activity
|
|
211
|
-
for (const workflowId of workflowIds.slice(0, 5)) { // Limit to first 5 workflows
|
|
212
|
-
try {
|
|
213
|
-
const phasesResult = await this.callMcpTool("list_workflow_phases", { workflowId });
|
|
214
|
-
const phasesText = phasesResult?.content?.[0]?.text;
|
|
215
|
-
if (phasesText) {
|
|
216
|
-
const phaseIdMatches = phasesText.matchAll(/"_id":\s*"([a-f0-9]{24})"/gi);
|
|
217
|
-
const phaseIds = [...phaseIdMatches].map(m => m[1]);
|
|
218
|
-
for (const phaseId of phaseIds.slice(0, 3)) { // Limit to first 3 phases
|
|
219
|
-
const activitiesResult = await this.callMcpTool("list_activities", {
|
|
220
|
-
workflowId,
|
|
221
|
-
phaseId,
|
|
222
|
-
search: activityName,
|
|
223
|
-
limit: 1,
|
|
224
|
-
});
|
|
225
|
-
const activitiesText = activitiesResult?.content?.[0]?.text;
|
|
226
|
-
if (activitiesText) {
|
|
227
|
-
// Look for activity ID and name in the response
|
|
228
|
-
const activityIdMatch = activitiesText.match(/"_id":\s*"([a-f0-9]{24})"/i);
|
|
229
|
-
if (activityIdMatch) {
|
|
230
|
-
const foundId = activityIdMatch[1];
|
|
231
|
-
const tag = this.formatHailerTag(foundId, activityName);
|
|
232
|
-
content = content.replace(match[0], tag);
|
|
233
|
-
break; // Found it, stop searching
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
catch {
|
|
240
|
-
// Continue to next workflow
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
catch (error) {
|
|
246
|
-
this.logger.warn("Failed to resolve activity name tag", { activityName, error });
|
|
247
|
-
// Leave the original #"Name" in place
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
return content;
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Convert Hailer URLs to Hailer tags
|
|
254
|
-
* Handles:
|
|
255
|
-
* - https://app.hailer.com/#/activities/{activityId}
|
|
256
|
-
* - https://app.hailer.com/#/discussions/{discussionId}
|
|
257
|
-
*/
|
|
258
|
-
async resolveHailerUrls(content) {
|
|
259
|
-
// Pattern for activity URLs
|
|
260
|
-
const activityUrlPattern = /https?:\/\/app\.hailer\.com\/#\/activities\/([a-f0-9]{24})/gi;
|
|
261
|
-
const activityMatches = [...content.matchAll(activityUrlPattern)];
|
|
262
|
-
for (const match of activityMatches) {
|
|
263
|
-
const activityId = match[1];
|
|
264
|
-
try {
|
|
265
|
-
const result = await this.callMcpTool("show_activity_by_id", { activityId });
|
|
266
|
-
const resultText = result?.content?.[0]?.text;
|
|
267
|
-
if (resultText) {
|
|
268
|
-
const jsonMatch = resultText.match(/\{[\s\S]*\}/);
|
|
269
|
-
if (jsonMatch) {
|
|
270
|
-
const parsed = JSON.parse(jsonMatch[0]);
|
|
271
|
-
const activityName = parsed.name;
|
|
272
|
-
if (activityName) {
|
|
273
|
-
const tag = this.formatHailerTag(activityId, activityName);
|
|
274
|
-
content = content.replace(match[0], tag);
|
|
275
|
-
this.logger.debug("Converted activity URL to tag", { activityId, activityName });
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
catch (error) {
|
|
281
|
-
this.logger.debug("Failed to resolve activity URL", { activityId, error });
|
|
282
|
-
// Leave URL as-is
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
// Pattern for discussion URLs - need to look up the linked activity
|
|
286
|
-
const discussionUrlPattern = /https?:\/\/app\.hailer\.com\/#\/discussions\/([a-f0-9]{24})/gi;
|
|
287
|
-
const discussionMatches = [...content.matchAll(discussionUrlPattern)];
|
|
288
|
-
for (const match of discussionMatches) {
|
|
289
|
-
const discussionId = match[1];
|
|
290
|
-
try {
|
|
291
|
-
// Load discussion to get linked activity
|
|
292
|
-
const discussionResponse = await this.botClient.client.socket.request("messenger.load_discussions", [[discussionId]]);
|
|
293
|
-
if (discussionResponse && discussionResponse[discussionId]) {
|
|
294
|
-
const discData = discussionResponse[discussionId];
|
|
295
|
-
const linkedActivityId = discData.linked_activity;
|
|
296
|
-
const discussionName = discData.name;
|
|
297
|
-
if (linkedActivityId) {
|
|
298
|
-
// It's an activity discussion - use the activity ID for the tag
|
|
299
|
-
const tag = this.formatHailerTag(linkedActivityId, discussionName || "Activity");
|
|
300
|
-
content = content.replace(match[0], tag);
|
|
301
|
-
this.logger.debug("Converted discussion URL to activity tag", { discussionId, linkedActivityId, discussionName });
|
|
302
|
-
}
|
|
303
|
-
else if (discussionName) {
|
|
304
|
-
// It's a standalone discussion - use discussion name but discussion ID
|
|
305
|
-
const tag = this.formatHailerTag(discussionId, discussionName);
|
|
306
|
-
content = content.replace(match[0], tag);
|
|
307
|
-
this.logger.debug("Converted discussion URL to discussion tag", { discussionId, discussionName });
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
catch (error) {
|
|
312
|
-
this.logger.debug("Failed to resolve discussion URL", { discussionId, error });
|
|
313
|
-
// Leave URL as-is
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return content;
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
* Extract link metadata from hailerTag formatted content
|
|
320
|
-
* Returns array of links for the messenger.send API
|
|
321
|
-
*/
|
|
322
|
-
extractTagLinks(content) {
|
|
323
|
-
const links = [];
|
|
324
|
-
// Match all hailerTag patterns: [hailerTag|Name](id)
|
|
325
|
-
const tagPattern = /\[hailerTag\|[^\]]+\]\(([a-f0-9]{24})\)/gi;
|
|
326
|
-
const matches = content.matchAll(tagPattern);
|
|
327
|
-
for (const match of matches) {
|
|
328
|
-
const targetId = match[1];
|
|
329
|
-
// Determine if it's a user or activity based on context
|
|
330
|
-
// For now, check if it's in the user cache
|
|
331
|
-
const isUser = this.botClient.workspaceCache?.usersById[targetId];
|
|
332
|
-
links.push({
|
|
333
|
-
target: targetId,
|
|
334
|
-
targetType: isUser ? 'user' : 'activity',
|
|
335
|
-
type: 'linked-to'
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
return links;
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* Format incoming message for LLM consumption
|
|
342
|
-
*/
|
|
343
|
-
formatIncomingMessage(message) {
|
|
344
|
-
const priorityTag = message.priority === "high" ? " priority=\"high\"" : "";
|
|
345
|
-
const reasonAttr = message.priority === "high" ? ` reason="${message.priorityReason}"` : "";
|
|
346
|
-
const activityAttr = message.linkedActivityId ? ` activity_id="${message.linkedActivityId}"` : "";
|
|
347
|
-
return `<incoming discussion="${message.discussionId}"${activityAttr} from="${message.senderName}" user_id="${message.senderId}" timestamp="${new Date(message.timestamp).toISOString()}"${priorityTag}${reasonAttr}>
|
|
348
|
-
${message.content}
|
|
349
|
-
</incoming>`;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
exports.MessageFormatterService = MessageFormatterService;
|
|
353
|
-
//# sourceMappingURL=message-formatter.js.map
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session Logger Service
|
|
3
|
-
*
|
|
4
|
-
* Manages per-activity session tracking and logging to Hailer workflows:
|
|
5
|
-
* - Tracks metrics (tokens, tool calls, messages)
|
|
6
|
-
* - Logs completed sessions to SESSION_LOG workflow
|
|
7
|
-
* - Manages idle session detection and flushing
|
|
8
|
-
*/
|
|
9
|
-
import Anthropic from "@anthropic-ai/sdk";
|
|
10
|
-
import { Logger } from "../../lib/logger";
|
|
11
|
-
import { ActivitySession, McpToolCallback } from "../types";
|
|
12
|
-
import { WorkspaceSchemaCacheService } from "./workspace-schema-cache";
|
|
13
|
-
/** Memory entry loaded from SESSION_LOG */
|
|
14
|
-
export interface MemoryEntry {
|
|
15
|
-
sessionId: string;
|
|
16
|
-
timestamp: number;
|
|
17
|
-
summary: string;
|
|
18
|
-
linkedActivityId?: string;
|
|
19
|
-
}
|
|
20
|
-
export declare class SessionLoggerService {
|
|
21
|
-
private agentDirectoryId;
|
|
22
|
-
private logger;
|
|
23
|
-
private callMcpTool;
|
|
24
|
-
private getDefaultTeamId;
|
|
25
|
-
private activitySessions;
|
|
26
|
-
private lastGlobalLogId;
|
|
27
|
-
private idleCheckTimer;
|
|
28
|
-
private anthropicClient;
|
|
29
|
-
private schemaCache;
|
|
30
|
-
private currentWorkspaceId;
|
|
31
|
-
constructor(agentDirectoryId: string | null, logger: Logger, callMcpTool: McpToolCallback, getDefaultTeamId: () => string | undefined);
|
|
32
|
-
/**
|
|
33
|
-
* Set the workspace schema cache for dynamic ID lookup
|
|
34
|
-
*/
|
|
35
|
-
setSchemaCache(cache: WorkspaceSchemaCacheService, workspaceId: string): void;
|
|
36
|
-
/**
|
|
37
|
-
* Get Session Log schema from cache for a specific workspace
|
|
38
|
-
*/
|
|
39
|
-
private getSessionLogSchema;
|
|
40
|
-
/**
|
|
41
|
-
* Set Anthropic client for generating summaries
|
|
42
|
-
*/
|
|
43
|
-
setAnthropicClient(client: Anthropic): void;
|
|
44
|
-
/**
|
|
45
|
-
* Get or create an activity session for tracking
|
|
46
|
-
* Multi-tenant: workspaceId is required for proper schema lookup
|
|
47
|
-
*/
|
|
48
|
-
getOrCreateActivitySession(message: {
|
|
49
|
-
linkedActivityId?: string;
|
|
50
|
-
linkedActivityName?: string;
|
|
51
|
-
discussionId: string;
|
|
52
|
-
workspaceId: string;
|
|
53
|
-
}): ActivitySession;
|
|
54
|
-
/**
|
|
55
|
-
* Get session by key
|
|
56
|
-
*/
|
|
57
|
-
getSession(key: string): ActivitySession | undefined;
|
|
58
|
-
/**
|
|
59
|
-
* Get all active sessions
|
|
60
|
-
*/
|
|
61
|
-
getActiveSessions(): Map<string, ActivitySession>;
|
|
62
|
-
/**
|
|
63
|
-
* Check for idle sessions and flush them
|
|
64
|
-
* Called periodically by timer
|
|
65
|
-
*/
|
|
66
|
-
checkAndFlushIdleSessions(): Promise<void>;
|
|
67
|
-
/**
|
|
68
|
-
* Flush a single activity session to the session log
|
|
69
|
-
*/
|
|
70
|
-
flushActivitySession(key: string, session: ActivitySession): Promise<void>;
|
|
71
|
-
/**
|
|
72
|
-
* Flush all active sessions (called on shutdown)
|
|
73
|
-
*/
|
|
74
|
-
flushAllSessions(): Promise<void>;
|
|
75
|
-
/**
|
|
76
|
-
* Build summary for an activity session
|
|
77
|
-
* Now includes conversation summary for memory recall
|
|
78
|
-
*/
|
|
79
|
-
private buildActivitySessionSummary;
|
|
80
|
-
/**
|
|
81
|
-
* Start periodic idle session checking
|
|
82
|
-
*/
|
|
83
|
-
startIdleCheckTimer(intervalMs?: number): void;
|
|
84
|
-
/**
|
|
85
|
-
* Stop idle check timer
|
|
86
|
-
*/
|
|
87
|
-
stopIdleCheckTimer(): void;
|
|
88
|
-
/**
|
|
89
|
-
* Generate a conversation summary using LLM
|
|
90
|
-
* Creates a condensed memory of what was discussed
|
|
91
|
-
*/
|
|
92
|
-
private generateConversationSummary;
|
|
93
|
-
/**
|
|
94
|
-
* Load memory entries for an activity from SESSION_LOG
|
|
95
|
-
* Returns past conversation summaries for context injection
|
|
96
|
-
*
|
|
97
|
-
* NOTE: ActivityLink fields store objects {_id, name}, so we fetch recent
|
|
98
|
-
* session logs and filter client-side by checking the nested _id.
|
|
99
|
-
*/
|
|
100
|
-
loadMemoryForActivity(activityId: string, workspaceId: string, limit?: number): Promise<MemoryEntry[]>;
|
|
101
|
-
/**
|
|
102
|
-
* Format memory entries for injection into conversation context
|
|
103
|
-
*/
|
|
104
|
-
formatMemoryForContext(entries: MemoryEntry[]): string;
|
|
105
|
-
}
|
|
106
|
-
//# sourceMappingURL=session-logger.d.ts.map
|