@hailer/mcp 0.1.16 → 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.
Files changed (202) hide show
  1. package/dist/app.js +24 -20
  2. package/dist/core.d.ts +33 -9
  3. package/dist/core.js +279 -147
  4. package/dist/mcp/UserContextCache.js +18 -0
  5. package/dist/mcp/hailer-clients.d.ts +9 -1
  6. package/dist/mcp/hailer-clients.js +13 -3
  7. package/dist/mcp/signal-handler.js +1 -1
  8. package/dist/mcp/tool-registry.d.ts +3 -1
  9. package/dist/mcp/tool-registry.js +4 -1
  10. package/dist/mcp/tools/activity.js +43 -34
  11. package/dist/mcp/tools/bot-config/constants.d.ts +23 -0
  12. package/dist/mcp/tools/bot-config/constants.js +94 -0
  13. package/dist/mcp/tools/{bot-config.d.ts → bot-config/core.d.ts} +6 -6
  14. package/dist/mcp/tools/{bot-config.js → bot-config/core.js} +15 -15
  15. package/dist/mcp/tools/bot-config/index.d.ts +10 -0
  16. package/dist/mcp/tools/bot-config/index.js +59 -0
  17. package/dist/mcp/tools/bot-config/tools.d.ts +7 -0
  18. package/dist/mcp/tools/bot-config/tools.js +15 -0
  19. package/dist/mcp/tools/bot-config/types.d.ts +50 -0
  20. package/dist/mcp/tools/bot-config/types.js +6 -0
  21. package/dist/mcp/tools/bug-fixer-tools.d.ts +21 -0
  22. package/dist/mcp/tools/{giuseppe-tools.js → bug-fixer-tools.js} +61 -61
  23. package/dist/mcp/tools/user.js +10 -29
  24. package/dist/mcp/tools/workflow.js +36 -2
  25. package/dist/mcp/utils/data-transformers.d.ts +0 -8
  26. package/dist/mcp/utils/data-transformers.js +0 -28
  27. package/dist/mcp/utils/index.d.ts +4 -1
  28. package/dist/mcp/utils/index.js +17 -3
  29. package/dist/mcp/utils/pagination.d.ts +40 -0
  30. package/dist/mcp/utils/pagination.js +55 -0
  31. package/dist/mcp/utils/response-builder.d.ts +53 -0
  32. package/dist/mcp/utils/response-builder.js +110 -0
  33. package/dist/mcp/utils/tool-helpers.d.ts +0 -8
  34. package/dist/mcp/utils/tool-helpers.js +0 -24
  35. package/dist/mcp/utils/types.d.ts +1 -33
  36. package/dist/mcp/webhook-handler.d.ts +2 -2
  37. package/dist/mcp/webhook-handler.js +5 -3
  38. package/dist/mcp-server.d.ts +2 -2
  39. package/dist/mcp-server.js +167 -140
  40. package/package.json +1 -1
  41. package/REFACTOR_STATUS.md +0 -127
  42. package/dist/agents/bot-manager.d.ts +0 -48
  43. package/dist/agents/bot-manager.js +0 -254
  44. package/dist/agents/factory.d.ts +0 -150
  45. package/dist/agents/factory.js +0 -650
  46. package/dist/agents/giuseppe/ai.d.ts +0 -83
  47. package/dist/agents/giuseppe/ai.js +0 -466
  48. package/dist/agents/giuseppe/bot.d.ts +0 -110
  49. package/dist/agents/giuseppe/bot.js +0 -780
  50. package/dist/agents/giuseppe/config.d.ts +0 -25
  51. package/dist/agents/giuseppe/config.js +0 -227
  52. package/dist/agents/giuseppe/files.d.ts +0 -52
  53. package/dist/agents/giuseppe/files.js +0 -338
  54. package/dist/agents/giuseppe/git.d.ts +0 -48
  55. package/dist/agents/giuseppe/git.js +0 -298
  56. package/dist/agents/giuseppe/index.d.ts +0 -97
  57. package/dist/agents/giuseppe/index.js +0 -258
  58. package/dist/agents/giuseppe/lsp.d.ts +0 -113
  59. package/dist/agents/giuseppe/lsp.js +0 -485
  60. package/dist/agents/giuseppe/monitor.d.ts +0 -118
  61. package/dist/agents/giuseppe/monitor.js +0 -621
  62. package/dist/agents/giuseppe/prompt.d.ts +0 -5
  63. package/dist/agents/giuseppe/prompt.js +0 -94
  64. package/dist/agents/giuseppe/registries/pending-classification.d.ts +0 -28
  65. package/dist/agents/giuseppe/registries/pending-classification.js +0 -50
  66. package/dist/agents/giuseppe/registries/pending-fix.d.ts +0 -30
  67. package/dist/agents/giuseppe/registries/pending-fix.js +0 -42
  68. package/dist/agents/giuseppe/registries/pending.d.ts +0 -27
  69. package/dist/agents/giuseppe/registries/pending.js +0 -49
  70. package/dist/agents/giuseppe/specialist.d.ts +0 -47
  71. package/dist/agents/giuseppe/specialist.js +0 -237
  72. package/dist/agents/giuseppe/types.d.ts +0 -123
  73. package/dist/agents/giuseppe/types.js +0 -9
  74. package/dist/agents/hailer-expert/index.d.ts +0 -8
  75. package/dist/agents/hailer-expert/index.js +0 -14
  76. package/dist/agents/hal/daemon.d.ts +0 -142
  77. package/dist/agents/hal/daemon.js +0 -1103
  78. package/dist/agents/hal/definitions.d.ts +0 -55
  79. package/dist/agents/hal/definitions.js +0 -263
  80. package/dist/agents/hal/index.d.ts +0 -3
  81. package/dist/agents/hal/index.js +0 -8
  82. package/dist/agents/index.d.ts +0 -18
  83. package/dist/agents/index.js +0 -48
  84. package/dist/agents/shared/base.d.ts +0 -216
  85. package/dist/agents/shared/base.js +0 -846
  86. package/dist/agents/shared/services/agent-registry.d.ts +0 -107
  87. package/dist/agents/shared/services/agent-registry.js +0 -629
  88. package/dist/agents/shared/services/conversation-manager.d.ts +0 -50
  89. package/dist/agents/shared/services/conversation-manager.js +0 -136
  90. package/dist/agents/shared/services/mcp-client.d.ts +0 -56
  91. package/dist/agents/shared/services/mcp-client.js +0 -124
  92. package/dist/agents/shared/services/message-classifier.d.ts +0 -37
  93. package/dist/agents/shared/services/message-classifier.js +0 -187
  94. package/dist/agents/shared/services/message-formatter.d.ts +0 -89
  95. package/dist/agents/shared/services/message-formatter.js +0 -371
  96. package/dist/agents/shared/services/session-logger.d.ts +0 -106
  97. package/dist/agents/shared/services/session-logger.js +0 -446
  98. package/dist/agents/shared/services/tool-executor.d.ts +0 -41
  99. package/dist/agents/shared/services/tool-executor.js +0 -169
  100. package/dist/agents/shared/services/workspace-schema-cache.d.ts +0 -125
  101. package/dist/agents/shared/services/workspace-schema-cache.js +0 -578
  102. package/dist/agents/shared/specialist.d.ts +0 -91
  103. package/dist/agents/shared/specialist.js +0 -399
  104. package/dist/agents/shared/tool-schema-loader.d.ts +0 -62
  105. package/dist/agents/shared/tool-schema-loader.js +0 -232
  106. package/dist/agents/shared/types.d.ts +0 -327
  107. package/dist/agents/shared/types.js +0 -121
  108. package/dist/client/agents/base.d.ts +0 -207
  109. package/dist/client/agents/base.js +0 -744
  110. package/dist/client/agents/definitions.d.ts +0 -53
  111. package/dist/client/agents/definitions.js +0 -263
  112. package/dist/client/agents/orchestrator.d.ts +0 -141
  113. package/dist/client/agents/orchestrator.js +0 -1062
  114. package/dist/client/agents/specialist.d.ts +0 -86
  115. package/dist/client/agents/specialist.js +0 -340
  116. package/dist/client/bot-entrypoint.d.ts +0 -7
  117. package/dist/client/bot-entrypoint.js +0 -103
  118. package/dist/client/bot-manager.d.ts +0 -44
  119. package/dist/client/bot-manager.js +0 -173
  120. package/dist/client/bot-runner.d.ts +0 -35
  121. package/dist/client/bot-runner.js +0 -188
  122. package/dist/client/chat-agent-daemon.d.ts +0 -464
  123. package/dist/client/chat-agent-daemon.js +0 -1774
  124. package/dist/client/daemon-factory.d.ts +0 -106
  125. package/dist/client/daemon-factory.js +0 -301
  126. package/dist/client/factory.d.ts +0 -111
  127. package/dist/client/factory.js +0 -314
  128. package/dist/client/index.d.ts +0 -17
  129. package/dist/client/index.js +0 -38
  130. package/dist/client/multi-bot-manager.d.ts +0 -42
  131. package/dist/client/multi-bot-manager.js +0 -161
  132. package/dist/client/orchestrator-daemon.d.ts +0 -87
  133. package/dist/client/orchestrator-daemon.js +0 -444
  134. package/dist/client/server.d.ts +0 -8
  135. package/dist/client/server.js +0 -251
  136. package/dist/client/services/agent-registry.d.ts +0 -108
  137. package/dist/client/services/agent-registry.js +0 -630
  138. package/dist/client/services/conversation-manager.d.ts +0 -50
  139. package/dist/client/services/conversation-manager.js +0 -136
  140. package/dist/client/services/mcp-client.d.ts +0 -48
  141. package/dist/client/services/mcp-client.js +0 -105
  142. package/dist/client/services/message-classifier.d.ts +0 -37
  143. package/dist/client/services/message-classifier.js +0 -187
  144. package/dist/client/services/message-formatter.d.ts +0 -84
  145. package/dist/client/services/message-formatter.js +0 -353
  146. package/dist/client/services/session-logger.d.ts +0 -106
  147. package/dist/client/services/session-logger.js +0 -446
  148. package/dist/client/services/tool-executor.d.ts +0 -41
  149. package/dist/client/services/tool-executor.js +0 -169
  150. package/dist/client/services/workspace-schema-cache.d.ts +0 -149
  151. package/dist/client/services/workspace-schema-cache.js +0 -732
  152. package/dist/client/specialist-daemon.d.ts +0 -77
  153. package/dist/client/specialist-daemon.js +0 -197
  154. package/dist/client/specialists.d.ts +0 -53
  155. package/dist/client/specialists.js +0 -178
  156. package/dist/client/tool-schema-loader.d.ts +0 -62
  157. package/dist/client/tool-schema-loader.js +0 -232
  158. package/dist/client/types.d.ts +0 -327
  159. package/dist/client/types.js +0 -121
  160. package/dist/commands/seed-config.d.ts +0 -9
  161. package/dist/commands/seed-config.js +0 -372
  162. package/dist/lib/context-manager.d.ts +0 -111
  163. package/dist/lib/context-manager.js +0 -431
  164. package/dist/lib/prompt-length-manager.d.ts +0 -81
  165. package/dist/lib/prompt-length-manager.js +0 -457
  166. package/dist/mcp/tools/giuseppe-tools.d.ts +0 -21
  167. package/dist/modules/bug-reports/bug-config.d.ts +0 -25
  168. package/dist/modules/bug-reports/bug-config.js +0 -187
  169. package/dist/modules/bug-reports/bug-monitor.d.ts +0 -108
  170. package/dist/modules/bug-reports/bug-monitor.js +0 -510
  171. package/dist/modules/bug-reports/giuseppe-agent.d.ts +0 -58
  172. package/dist/modules/bug-reports/giuseppe-agent.js +0 -467
  173. package/dist/modules/bug-reports/giuseppe-ai.d.ts +0 -83
  174. package/dist/modules/bug-reports/giuseppe-ai.js +0 -466
  175. package/dist/modules/bug-reports/giuseppe-bot.d.ts +0 -110
  176. package/dist/modules/bug-reports/giuseppe-bot.js +0 -804
  177. package/dist/modules/bug-reports/giuseppe-daemon.d.ts +0 -80
  178. package/dist/modules/bug-reports/giuseppe-daemon.js +0 -617
  179. package/dist/modules/bug-reports/giuseppe-files.d.ts +0 -64
  180. package/dist/modules/bug-reports/giuseppe-files.js +0 -375
  181. package/dist/modules/bug-reports/giuseppe-git.d.ts +0 -48
  182. package/dist/modules/bug-reports/giuseppe-git.js +0 -298
  183. package/dist/modules/bug-reports/giuseppe-lsp.d.ts +0 -113
  184. package/dist/modules/bug-reports/giuseppe-lsp.js +0 -485
  185. package/dist/modules/bug-reports/giuseppe-prompt.d.ts +0 -5
  186. package/dist/modules/bug-reports/giuseppe-prompt.js +0 -94
  187. package/dist/modules/bug-reports/index.d.ts +0 -77
  188. package/dist/modules/bug-reports/index.js +0 -215
  189. package/dist/modules/bug-reports/pending-classification-registry.d.ts +0 -28
  190. package/dist/modules/bug-reports/pending-classification-registry.js +0 -50
  191. package/dist/modules/bug-reports/pending-fix-registry.d.ts +0 -30
  192. package/dist/modules/bug-reports/pending-fix-registry.js +0 -42
  193. package/dist/modules/bug-reports/pending-registry.d.ts +0 -27
  194. package/dist/modules/bug-reports/pending-registry.js +0 -49
  195. package/dist/modules/bug-reports/types.d.ts +0 -123
  196. package/dist/modules/bug-reports/types.js +0 -9
  197. package/dist/routes/agents.d.ts +0 -44
  198. package/dist/routes/agents.js +0 -311
  199. package/dist/services/agent-credential-store.d.ts +0 -73
  200. package/dist/services/agent-credential-store.js +0 -212
  201. package/dist/services/bug-monitor.d.ts +0 -23
  202. package/dist/services/bug-monitor.js +0 -275
@@ -1,446 +0,0 @@
1
- "use strict";
2
- /**
3
- * Session Logger Service
4
- *
5
- * Manages per-activity session tracking and logging to Hailer workflows:
6
- * - Tracks metrics (tokens, tool calls, messages)
7
- * - Logs completed sessions to SESSION_LOG workflow
8
- * - Manages idle session detection and flushing
9
- */
10
- Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.SessionLoggerService = void 0;
12
- const types_1 = require("../../shared/types");
13
- class SessionLoggerService {
14
- agentDirectoryId;
15
- logger;
16
- callMcpTool;
17
- getDefaultTeamId;
18
- activitySessions = new Map();
19
- lastGlobalLogId = null;
20
- idleCheckTimer = null;
21
- anthropicClient = null;
22
- schemaCache = null;
23
- _currentWorkspaceId = null;
24
- constructor(agentDirectoryId, logger, callMcpTool, getDefaultTeamId) {
25
- this.agentDirectoryId = agentDirectoryId;
26
- this.logger = logger;
27
- this.callMcpTool = callMcpTool;
28
- this.getDefaultTeamId = getDefaultTeamId;
29
- }
30
- /**
31
- * Set the workspace schema cache for dynamic ID lookup
32
- */
33
- setSchemaCache(cache, workspaceId) {
34
- this.schemaCache = cache;
35
- this._currentWorkspaceId = workspaceId;
36
- }
37
- /**
38
- * Get Session Log schema from cache for a specific workspace
39
- */
40
- getSessionLogSchema(workspaceId) {
41
- if (!this.schemaCache || !workspaceId) {
42
- return null;
43
- }
44
- return this.schemaCache.getSessionLogSchema(workspaceId) || null;
45
- }
46
- /**
47
- * Set Anthropic client for generating summaries
48
- */
49
- setAnthropicClient(client) {
50
- this.anthropicClient = client;
51
- }
52
- /**
53
- * Get or create an activity session for tracking
54
- * Multi-tenant: workspaceId is required for proper schema lookup
55
- */
56
- getOrCreateActivitySession(message) {
57
- // Use linked activity ID as key, fallback to discussion ID
58
- const sessionKey = message.linkedActivityId || message.discussionId;
59
- let session = this.activitySessions.get(sessionKey);
60
- if (!session) {
61
- session = {
62
- activityId: message.linkedActivityId || "",
63
- activityName: message.linkedActivityName || `Discussion ${message.discussionId.substring(0, 8)}`,
64
- discussionId: message.discussionId,
65
- workspaceId: message.workspaceId, // Multi-tenant: store workspace for this session
66
- startTime: Date.now(),
67
- lastActivityTime: Date.now(),
68
- metrics: {
69
- inputTokens: 0,
70
- outputTokens: 0,
71
- toolCalls: 0,
72
- writeOperations: 0,
73
- messagesProcessed: 0,
74
- responsesPosted: 0,
75
- },
76
- actions: [],
77
- previousLogId: this.lastGlobalLogId,
78
- conversation: [],
79
- writeDetails: [],
80
- triggerRequest: null,
81
- requestedBy: null,
82
- requestedById: null,
83
- };
84
- this.activitySessions.set(sessionKey, session);
85
- this.logger.debug("Created new activity session", {
86
- sessionKey,
87
- workspaceId: message.workspaceId,
88
- activityName: session.activityName,
89
- });
90
- }
91
- return session;
92
- }
93
- /**
94
- * Get session by key
95
- */
96
- getSession(key) {
97
- return this.activitySessions.get(key);
98
- }
99
- /**
100
- * Get all active sessions
101
- */
102
- getActiveSessions() {
103
- return new Map(this.activitySessions);
104
- }
105
- /**
106
- * Check for idle sessions and flush them
107
- * Called periodically by timer
108
- */
109
- async checkAndFlushIdleSessions() {
110
- const now = Date.now();
111
- const sessionsToFlush = [];
112
- for (const [key, session] of this.activitySessions) {
113
- const idleTime = now - session.lastActivityTime;
114
- if (idleTime >= types_1.SESSION_IDLE_TIMEOUT) {
115
- sessionsToFlush.push(key);
116
- }
117
- }
118
- for (const key of sessionsToFlush) {
119
- const session = this.activitySessions.get(key);
120
- if (session) {
121
- await this.flushActivitySession(key, session);
122
- this.activitySessions.delete(key);
123
- }
124
- }
125
- if (sessionsToFlush.length > 0) {
126
- this.logger.debug("Flushed idle sessions", { count: sessionsToFlush.length });
127
- }
128
- }
129
- /**
130
- * Flush a single activity session to the session log
131
- */
132
- async flushActivitySession(_key, session) {
133
- // Only log if WRITE operations occurred (skip read-only sessions)
134
- if (session.metrics.writeOperations === 0) {
135
- this.logger.debug("Skipping session log - no write operations", {
136
- activity: session.activityName,
137
- toolCalls: session.metrics.toolCalls,
138
- });
139
- return;
140
- }
141
- // Get dynamic schema for this session's workspace
142
- const schema = this.getSessionLogSchema(session.workspaceId);
143
- if (!schema) {
144
- this.logger.debug("Skipping session log - no Session Log workflow in workspace", {
145
- workspaceId: session.workspaceId,
146
- });
147
- return;
148
- }
149
- if (!this.agentDirectoryId) {
150
- this.logger.debug("Skipping session log - no agent directory ID");
151
- return;
152
- }
153
- try {
154
- // Build descriptive session name from first write operation
155
- let sessionName;
156
- if (session.writeDetails.length > 0) {
157
- sessionName = session.writeDetails[0].what;
158
- }
159
- else {
160
- sessionName = session.activityName || `Session ${new Date().toISOString()}`;
161
- }
162
- // Build context summary (now async - includes conversation summary)
163
- const summary = await this.buildActivitySessionSummary(session);
164
- // Calculate total tokens
165
- const totalTokens = session.metrics.inputTokens + session.metrics.outputTokens;
166
- // Get field IDs from schema (use our standard keys that were mapped)
167
- const contextSummaryFieldId = schema.fields["contextSummary"] || schema.fields["Context summary"];
168
- const madeByFieldId = schema.fields["madeBy"] || schema.fields["Log entry made by"];
169
- const costFieldId = schema.fields["cost"] || schema.fields["Tokens Used"];
170
- const previousLogFieldId = schema.fields["previousLog"] || schema.fields["Previus log entry"];
171
- const linkedWorkFieldId = schema.fields["linkedWork"] || schema.fields["Most relevant link to work"];
172
- // Build fields
173
- const fields = {};
174
- if (contextSummaryFieldId) {
175
- fields[contextSummaryFieldId] = summary;
176
- }
177
- if (madeByFieldId && this.agentDirectoryId) {
178
- fields[madeByFieldId] = this.agentDirectoryId;
179
- }
180
- if (costFieldId) {
181
- fields[costFieldId] = totalTokens;
182
- }
183
- // Chain to previous log
184
- if (session.previousLogId && previousLogFieldId) {
185
- fields[previousLogFieldId] = session.previousLogId;
186
- }
187
- // Link to activity being worked on
188
- if (session.activityId && linkedWorkFieldId) {
189
- fields[linkedWorkFieldId] = session.activityId;
190
- }
191
- // Get phase ID (try "active" first, then first available)
192
- const phaseId = schema.phases["active"] || Object.values(schema.phases)[0];
193
- const createParams = {
194
- workflowId: schema.workflowId,
195
- name: sessionName,
196
- phaseId,
197
- fields,
198
- };
199
- const wsTeamId = this.getDefaultTeamId();
200
- if (wsTeamId) {
201
- createParams.teamId = wsTeamId;
202
- }
203
- const result = await this.callMcpTool("create_activity", createParams);
204
- // Extract created ID for chaining
205
- const resultText = result?.content?.[0]?.text;
206
- if (resultText) {
207
- const idMatch = resultText.match(/"_id":\s*"([a-f0-9]{24})"/i) ||
208
- resultText.match(/`([a-f0-9]{24})`/);
209
- if (idMatch) {
210
- this.lastGlobalLogId = idMatch[1];
211
- }
212
- }
213
- const durationSec = Math.round((Date.now() - session.startTime) / 1000);
214
- this.logger.info("Activity session logged", {
215
- activity: session.activityName,
216
- durationSec,
217
- messages: session.metrics.messagesProcessed,
218
- toolCalls: session.metrics.toolCalls,
219
- tokens: totalTokens,
220
- });
221
- }
222
- catch (error) {
223
- this.logger.warn("Failed to flush activity session", {
224
- activity: session.activityName,
225
- error: error instanceof Error ? error.message : String(error),
226
- });
227
- }
228
- }
229
- /**
230
- * Flush all active sessions (called on shutdown)
231
- */
232
- async flushAllSessions() {
233
- for (const [key, session] of this.activitySessions) {
234
- await this.flushActivitySession(key, session);
235
- }
236
- this.activitySessions.clear();
237
- }
238
- /**
239
- * Build summary for an activity session
240
- * Now includes conversation summary for memory recall
241
- */
242
- async buildActivitySessionSummary(session) {
243
- const lines = [];
244
- // Who requested this
245
- if (session.requestedBy) {
246
- lines.push(`**Requested by:** ${session.requestedBy}`);
247
- }
248
- // What they asked for
249
- if (session.triggerRequest) {
250
- lines.push(`**Request:** "${session.triggerRequest}"`);
251
- }
252
- // What was changed (write operations only)
253
- if (session.writeDetails.length > 0) {
254
- lines.push("");
255
- lines.push(`**Changes made:**`);
256
- for (const detail of session.writeDetails) {
257
- lines.push(`- ${detail.what}`);
258
- }
259
- }
260
- // Generate and include conversation summary for memory
261
- const conversationSummary = await this.generateConversationSummary(session);
262
- if (conversationSummary) {
263
- lines.push("");
264
- lines.push(`**Conversation:** ${conversationSummary}`);
265
- }
266
- lines.push("");
267
- lines.push("---");
268
- lines.push("");
269
- // Metrics (compact)
270
- const duration = Math.round((Date.now() - session.startTime) / 1000);
271
- const totalTokens = session.metrics.inputTokens + session.metrics.outputTokens;
272
- lines.push(`**Stats:** ${session.metrics.writeOperations} writes, ${totalTokens} tokens, ${duration}s`);
273
- return lines.join("\n");
274
- }
275
- /**
276
- * Start periodic idle session checking
277
- */
278
- startIdleCheckTimer(intervalMs = 30_000) {
279
- if (this.idleCheckTimer) {
280
- clearInterval(this.idleCheckTimer);
281
- }
282
- this.idleCheckTimer = setInterval(() => {
283
- this.checkAndFlushIdleSessions().catch(err => {
284
- this.logger.warn("Error checking idle sessions", { error: err });
285
- });
286
- }, intervalMs);
287
- }
288
- /**
289
- * Stop idle check timer
290
- */
291
- stopIdleCheckTimer() {
292
- if (this.idleCheckTimer) {
293
- clearInterval(this.idleCheckTimer);
294
- this.idleCheckTimer = null;
295
- }
296
- }
297
- // ===== MEMORY SYSTEM =====
298
- /**
299
- * Generate a conversation summary using LLM
300
- * Creates a condensed memory of what was discussed
301
- */
302
- async generateConversationSummary(session) {
303
- if (!this.anthropicClient || session.conversation.length === 0) {
304
- return null;
305
- }
306
- try {
307
- const response = await this.anthropicClient.messages.create({
308
- model: "claude-haiku-4-5-20251001",
309
- max_tokens: 500,
310
- messages: [
311
- {
312
- role: "user",
313
- content: `Summarize this conversation in 2-3 sentences for future context. Focus on:
314
- - What the user wanted to accomplish
315
- - Key decisions or preferences expressed
316
- - Important context for future interactions
317
-
318
- Conversation:
319
- ${session.conversation.join("\n")}
320
-
321
- Summary:`,
322
- },
323
- ],
324
- });
325
- const textBlock = response.content.find((b) => b.type === "text");
326
- return textBlock?.text || null;
327
- }
328
- catch (error) {
329
- this.logger.warn("Failed to generate conversation summary", {
330
- error: error instanceof Error ? error.message : String(error),
331
- });
332
- return null;
333
- }
334
- }
335
- /**
336
- * Load memory entries for an activity from SESSION_LOG
337
- * Returns past conversation summaries for context injection
338
- *
339
- * NOTE: ActivityLink fields store objects {_id, name}, so we fetch recent
340
- * session logs and filter client-side by checking the nested _id.
341
- */
342
- async loadMemoryForActivity(activityId, workspaceId, limit = 5) {
343
- if (!activityId || !workspaceId) {
344
- return [];
345
- }
346
- // Get dynamic schema for this workspace
347
- const schema = this.getSessionLogSchema(workspaceId);
348
- if (!schema) {
349
- this.logger.debug("Cannot load memory - no Session Log workflow in workspace", { workspaceId });
350
- return [];
351
- }
352
- // Get field IDs from schema
353
- const contextSummaryFieldId = schema.fields["contextSummary"] || schema.fields["Context summary"];
354
- const linkedWorkFieldId = schema.fields["linkedWork"] || schema.fields["Most relevant link to work"];
355
- const phaseId = schema.phases["active"] || Object.values(schema.phases)[0];
356
- if (!contextSummaryFieldId || !linkedWorkFieldId || !phaseId) {
357
- this.logger.debug("Cannot load memory - missing required fields in schema");
358
- return [];
359
- }
360
- try {
361
- // Query SESSION_LOG for recent sessions (fetch more to filter client-side)
362
- // ActivityLink filters don't work with simple equals, so we filter after
363
- const result = await this.callMcpTool("list_activities", {
364
- workflowId: schema.workflowId,
365
- phaseId,
366
- fields: [contextSummaryFieldId, linkedWorkFieldId],
367
- limit: 50, // Fetch more, filter client-side
368
- sortBy: "created",
369
- sortOrder: "desc",
370
- });
371
- const resultText = result?.content?.[0]?.text;
372
- if (!resultText) {
373
- return [];
374
- }
375
- // Parse the response to extract memory entries
376
- const entries = [];
377
- // Try to parse as JSON array
378
- try {
379
- const parsed = JSON.parse(resultText);
380
- const activities = parsed.activities || parsed.data || parsed;
381
- if (Array.isArray(activities)) {
382
- for (const activity of activities) {
383
- // Get linkedWork field - it's an ActivityLink with nested {_id, name}
384
- const linkedWorkField = activity.fields?.[linkedWorkFieldId];
385
- const linkedWorkId = linkedWorkField?.value?._id || linkedWorkField?._id;
386
- // Filter: only include entries linked to our target activity
387
- if (linkedWorkId !== activityId) {
388
- continue;
389
- }
390
- // Get context summary
391
- const summaryField = activity.fields?.[contextSummaryFieldId];
392
- const summary = summaryField?.value || summaryField;
393
- if (summary) {
394
- // Extract conversation summary section if present
395
- const conversationMatch = summary.match(/\*\*Conversation:\*\*\s*([\s\S]*?)(?=\n\n\*\*|---\n|$)/);
396
- const memorySummary = conversationMatch?.[1]?.trim() || summary;
397
- entries.push({
398
- sessionId: activity._id,
399
- timestamp: activity.created || Date.now(),
400
- summary: memorySummary,
401
- linkedActivityId: activityId,
402
- });
403
- // Stop once we have enough
404
- if (entries.length >= limit) {
405
- break;
406
- }
407
- }
408
- }
409
- }
410
- }
411
- catch {
412
- // Not JSON, try regex extraction (fallback)
413
- this.logger.debug("Failed to parse as JSON, using regex fallback");
414
- }
415
- this.logger.debug("Loaded memory entries", {
416
- activityId,
417
- count: entries.length,
418
- });
419
- return entries;
420
- }
421
- catch (error) {
422
- this.logger.warn("Failed to load memory for activity", {
423
- activityId,
424
- error: error instanceof Error ? error.message : String(error),
425
- });
426
- return [];
427
- }
428
- }
429
- /**
430
- * Format memory entries for injection into conversation context
431
- */
432
- formatMemoryForContext(entries) {
433
- if (entries.length === 0) {
434
- return "";
435
- }
436
- const lines = ["<previous_memory>", "Past interactions with this activity:"];
437
- for (const entry of entries) {
438
- const date = new Date(entry.timestamp).toLocaleDateString();
439
- lines.push(`- [${date}] ${entry.summary}`);
440
- }
441
- lines.push("</previous_memory>");
442
- return lines.join("\n");
443
- }
444
- }
445
- exports.SessionLoggerService = SessionLoggerService;
446
- //# sourceMappingURL=session-logger.js.map
@@ -1,41 +0,0 @@
1
- /**
2
- * Tool Executor Service
3
- *
4
- * Handles MCP tool execution:
5
- * - Executes tool calls from LLM
6
- * - Tracks write operations
7
- * - Extracts write details for logging
8
- */
9
- import Anthropic from "@anthropic-ai/sdk";
10
- import { Logger } from "../../../lib/logger";
11
- import { McpClientService } from "./mcp-client";
12
- import { WriteDetail, ActivitySession, ToolInput, McpToolResult } from "../../shared/types";
13
- export interface ToolExecutionResult {
14
- type: "tool_result";
15
- tool_use_id: string;
16
- content: string;
17
- is_error?: boolean;
18
- }
19
- export interface ToolExecutionContext {
20
- session?: ActivitySession;
21
- preprocessToolInput?: (toolName: string, input: ToolInput) => ToolInput;
22
- }
23
- export declare class ToolExecutor {
24
- private mcpClient;
25
- private logger;
26
- private static WRITE_TOOLS;
27
- constructor(mcpClient: McpClientService, logger: Logger);
28
- /**
29
- * Check if a tool is a write operation
30
- */
31
- isWriteTool(toolName: string): boolean;
32
- /**
33
- * Execute a list of tool calls and return results
34
- */
35
- executeTools(toolUseBlocks: Anthropic.ToolUseBlock[], context?: ToolExecutionContext): Promise<ToolExecutionResult[]>;
36
- /**
37
- * Extract details about a write operation for logging
38
- */
39
- extractWriteDetail(toolName: string, input: ToolInput, result: McpToolResult): WriteDetail | null;
40
- }
41
- //# sourceMappingURL=tool-executor.d.ts.map
@@ -1,169 +0,0 @@
1
- "use strict";
2
- /**
3
- * Tool Executor Service
4
- *
5
- * Handles MCP tool execution:
6
- * - Executes tool calls from LLM
7
- * - Tracks write operations
8
- * - Extracts write details for logging
9
- */
10
- Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.ToolExecutor = void 0;
12
- class ToolExecutor {
13
- mcpClient;
14
- logger;
15
- // Tools that modify data in Hailer (vs read-only tools)
16
- static WRITE_TOOLS = new Set([
17
- "create_activity",
18
- "update_activity",
19
- "add_discussion_message",
20
- "invite_discussion_members",
21
- "join_discussion",
22
- "create_insight",
23
- "update_insight",
24
- "remove_insight",
25
- "create_app",
26
- "update_app",
27
- "remove_app",
28
- "install_workflow",
29
- "remove_workflow",
30
- "update_workflow_field",
31
- "update_workflow_phase",
32
- "upload_files",
33
- ]);
34
- constructor(mcpClient, logger) {
35
- this.mcpClient = mcpClient;
36
- this.logger = logger;
37
- }
38
- /**
39
- * Check if a tool is a write operation
40
- */
41
- isWriteTool(toolName) {
42
- return ToolExecutor.WRITE_TOOLS.has(toolName);
43
- }
44
- /**
45
- * Execute a list of tool calls and return results
46
- */
47
- async executeTools(toolUseBlocks, context = {}) {
48
- const { session, preprocessToolInput } = context;
49
- const toolResults = [];
50
- for (const toolUse of toolUseBlocks) {
51
- this.logger.info("Executing tool", { tool: toolUse.name });
52
- // Track tool call in session
53
- if (session) {
54
- session.metrics.toolCalls++;
55
- session.actions.push(`Tool: ${toolUse.name}`);
56
- session.lastActivityTime = Date.now();
57
- }
58
- try {
59
- // Load full schema if needed (uses service's cache)
60
- await this.mcpClient.loadToolSchemaIfNeeded(toolUse.name);
61
- // Allow preprocessing of tool input (cast from Anthropic's unknown type)
62
- const rawInput = toolUse.input;
63
- const toolInput = preprocessToolInput
64
- ? preprocessToolInput(toolUse.name, rawInput)
65
- : rawInput;
66
- const result = await this.mcpClient.callMcpTool(toolUse.name, toolInput);
67
- const resultContent = JSON.stringify(result?.content || {});
68
- // Track write operations for session logging
69
- if (session && this.isWriteTool(toolUse.name)) {
70
- session.metrics.writeOperations++;
71
- const writeDetail = this.extractWriteDetail(toolUse.name, toolInput, result);
72
- if (writeDetail) {
73
- session.writeDetails.push(writeDetail);
74
- }
75
- }
76
- toolResults.push({
77
- type: "tool_result",
78
- tool_use_id: toolUse.id,
79
- content: resultContent,
80
- });
81
- }
82
- catch (error) {
83
- const errorMessage = error instanceof Error ? error.message : String(error);
84
- this.logger.warn("Tool execution failed", {
85
- tool: toolUse.name,
86
- error: errorMessage,
87
- });
88
- toolResults.push({
89
- type: "tool_result",
90
- tool_use_id: toolUse.id,
91
- content: `Error: ${errorMessage}`,
92
- is_error: true,
93
- });
94
- }
95
- }
96
- return toolResults;
97
- }
98
- /**
99
- * Extract details about a write operation for logging
100
- */
101
- extractWriteDetail(toolName, input, result) {
102
- try {
103
- const resultText = result?.content?.[0]?.text || "";
104
- // Extract activity ID from result if present
105
- const idMatch = resultText.match(/"_id":\s*"([a-f0-9]{24})"/i) ||
106
- resultText.match(/`([a-f0-9]{24})`/);
107
- const targetId = idMatch?.[1] || input.activityId || input.discussionId;
108
- switch (toolName) {
109
- case "create_activity":
110
- return {
111
- tool: toolName,
112
- what: `Created activity "${input.name || 'unnamed'}"`,
113
- targetId,
114
- };
115
- case "update_activity": {
116
- const fieldCount = input.fields ? Object.keys(input.fields).length : 0;
117
- return {
118
- tool: toolName,
119
- what: `Updated ${fieldCount} field(s)${input.name ? ` on "${input.name}"` : ''}`,
120
- targetId: input.activityId,
121
- };
122
- }
123
- case "add_discussion_message": {
124
- const msgPreview = input.content?.substring(0, 50) || "";
125
- return {
126
- tool: toolName,
127
- what: `Posted message: "${msgPreview}${msgPreview.length >= 50 ? '...' : ''}"`,
128
- targetId: input.discussionId,
129
- };
130
- }
131
- case "invite_discussion_members":
132
- return {
133
- tool: toolName,
134
- what: `Invited ${input.userIds?.length || 0} member(s) to discussion`,
135
- targetId: input.discussionId,
136
- };
137
- case "join_discussion":
138
- return {
139
- tool: toolName,
140
- what: input.inviteUserId ? "Invited user to discussion" : "Joined discussion",
141
- targetId: input.activityId || input.discussionId,
142
- };
143
- case "create_insight":
144
- return {
145
- tool: toolName,
146
- what: `Created insight "${input.name || 'unnamed'}"`,
147
- targetId,
148
- };
149
- case "update_insight":
150
- return {
151
- tool: toolName,
152
- what: `Updated insight`,
153
- targetId: input.insightId,
154
- };
155
- default:
156
- return {
157
- tool: toolName,
158
- what: `Executed ${toolName}`,
159
- targetId,
160
- };
161
- }
162
- }
163
- catch {
164
- return null;
165
- }
166
- }
167
- }
168
- exports.ToolExecutor = ToolExecutor;
169
- //# sourceMappingURL=tool-executor.js.map