@hailer/mcp 0.1.17 → 0.2.2

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 (200) hide show
  1. package/dist/app.js +27 -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-server.d.ts +2 -2
  37. package/dist/mcp-server.js +161 -139
  38. package/package.json +1 -1
  39. package/REFACTOR_STATUS.md +0 -127
  40. package/dist/agents/bot-manager.d.ts +0 -48
  41. package/dist/agents/bot-manager.js +0 -254
  42. package/dist/agents/factory.d.ts +0 -150
  43. package/dist/agents/factory.js +0 -650
  44. package/dist/agents/giuseppe/ai.d.ts +0 -83
  45. package/dist/agents/giuseppe/ai.js +0 -466
  46. package/dist/agents/giuseppe/bot.d.ts +0 -110
  47. package/dist/agents/giuseppe/bot.js +0 -780
  48. package/dist/agents/giuseppe/config.d.ts +0 -25
  49. package/dist/agents/giuseppe/config.js +0 -227
  50. package/dist/agents/giuseppe/files.d.ts +0 -52
  51. package/dist/agents/giuseppe/files.js +0 -338
  52. package/dist/agents/giuseppe/git.d.ts +0 -48
  53. package/dist/agents/giuseppe/git.js +0 -298
  54. package/dist/agents/giuseppe/index.d.ts +0 -97
  55. package/dist/agents/giuseppe/index.js +0 -258
  56. package/dist/agents/giuseppe/lsp.d.ts +0 -113
  57. package/dist/agents/giuseppe/lsp.js +0 -485
  58. package/dist/agents/giuseppe/monitor.d.ts +0 -118
  59. package/dist/agents/giuseppe/monitor.js +0 -621
  60. package/dist/agents/giuseppe/prompt.d.ts +0 -5
  61. package/dist/agents/giuseppe/prompt.js +0 -94
  62. package/dist/agents/giuseppe/registries/pending-classification.d.ts +0 -28
  63. package/dist/agents/giuseppe/registries/pending-classification.js +0 -50
  64. package/dist/agents/giuseppe/registries/pending-fix.d.ts +0 -30
  65. package/dist/agents/giuseppe/registries/pending-fix.js +0 -42
  66. package/dist/agents/giuseppe/registries/pending.d.ts +0 -27
  67. package/dist/agents/giuseppe/registries/pending.js +0 -49
  68. package/dist/agents/giuseppe/specialist.d.ts +0 -47
  69. package/dist/agents/giuseppe/specialist.js +0 -237
  70. package/dist/agents/giuseppe/types.d.ts +0 -123
  71. package/dist/agents/giuseppe/types.js +0 -9
  72. package/dist/agents/hailer-expert/index.d.ts +0 -8
  73. package/dist/agents/hailer-expert/index.js +0 -14
  74. package/dist/agents/hal/daemon.d.ts +0 -142
  75. package/dist/agents/hal/daemon.js +0 -1103
  76. package/dist/agents/hal/definitions.d.ts +0 -55
  77. package/dist/agents/hal/definitions.js +0 -263
  78. package/dist/agents/hal/index.d.ts +0 -3
  79. package/dist/agents/hal/index.js +0 -8
  80. package/dist/agents/index.d.ts +0 -18
  81. package/dist/agents/index.js +0 -48
  82. package/dist/agents/shared/base.d.ts +0 -216
  83. package/dist/agents/shared/base.js +0 -846
  84. package/dist/agents/shared/services/agent-registry.d.ts +0 -107
  85. package/dist/agents/shared/services/agent-registry.js +0 -629
  86. package/dist/agents/shared/services/conversation-manager.d.ts +0 -50
  87. package/dist/agents/shared/services/conversation-manager.js +0 -136
  88. package/dist/agents/shared/services/mcp-client.d.ts +0 -56
  89. package/dist/agents/shared/services/mcp-client.js +0 -124
  90. package/dist/agents/shared/services/message-classifier.d.ts +0 -37
  91. package/dist/agents/shared/services/message-classifier.js +0 -187
  92. package/dist/agents/shared/services/message-formatter.d.ts +0 -89
  93. package/dist/agents/shared/services/message-formatter.js +0 -371
  94. package/dist/agents/shared/services/session-logger.d.ts +0 -106
  95. package/dist/agents/shared/services/session-logger.js +0 -446
  96. package/dist/agents/shared/services/tool-executor.d.ts +0 -41
  97. package/dist/agents/shared/services/tool-executor.js +0 -169
  98. package/dist/agents/shared/services/workspace-schema-cache.d.ts +0 -125
  99. package/dist/agents/shared/services/workspace-schema-cache.js +0 -578
  100. package/dist/agents/shared/specialist.d.ts +0 -91
  101. package/dist/agents/shared/specialist.js +0 -399
  102. package/dist/agents/shared/tool-schema-loader.d.ts +0 -62
  103. package/dist/agents/shared/tool-schema-loader.js +0 -232
  104. package/dist/agents/shared/types.d.ts +0 -327
  105. package/dist/agents/shared/types.js +0 -121
  106. package/dist/client/agents/base.d.ts +0 -207
  107. package/dist/client/agents/base.js +0 -744
  108. package/dist/client/agents/definitions.d.ts +0 -53
  109. package/dist/client/agents/definitions.js +0 -263
  110. package/dist/client/agents/orchestrator.d.ts +0 -141
  111. package/dist/client/agents/orchestrator.js +0 -1062
  112. package/dist/client/agents/specialist.d.ts +0 -86
  113. package/dist/client/agents/specialist.js +0 -340
  114. package/dist/client/bot-entrypoint.d.ts +0 -7
  115. package/dist/client/bot-entrypoint.js +0 -103
  116. package/dist/client/bot-manager.d.ts +0 -44
  117. package/dist/client/bot-manager.js +0 -173
  118. package/dist/client/bot-runner.d.ts +0 -35
  119. package/dist/client/bot-runner.js +0 -188
  120. package/dist/client/chat-agent-daemon.d.ts +0 -464
  121. package/dist/client/chat-agent-daemon.js +0 -1774
  122. package/dist/client/daemon-factory.d.ts +0 -106
  123. package/dist/client/daemon-factory.js +0 -301
  124. package/dist/client/factory.d.ts +0 -111
  125. package/dist/client/factory.js +0 -314
  126. package/dist/client/index.d.ts +0 -17
  127. package/dist/client/index.js +0 -38
  128. package/dist/client/multi-bot-manager.d.ts +0 -42
  129. package/dist/client/multi-bot-manager.js +0 -161
  130. package/dist/client/orchestrator-daemon.d.ts +0 -87
  131. package/dist/client/orchestrator-daemon.js +0 -444
  132. package/dist/client/server.d.ts +0 -8
  133. package/dist/client/server.js +0 -251
  134. package/dist/client/services/agent-registry.d.ts +0 -108
  135. package/dist/client/services/agent-registry.js +0 -630
  136. package/dist/client/services/conversation-manager.d.ts +0 -50
  137. package/dist/client/services/conversation-manager.js +0 -136
  138. package/dist/client/services/mcp-client.d.ts +0 -48
  139. package/dist/client/services/mcp-client.js +0 -105
  140. package/dist/client/services/message-classifier.d.ts +0 -37
  141. package/dist/client/services/message-classifier.js +0 -187
  142. package/dist/client/services/message-formatter.d.ts +0 -84
  143. package/dist/client/services/message-formatter.js +0 -353
  144. package/dist/client/services/session-logger.d.ts +0 -106
  145. package/dist/client/services/session-logger.js +0 -446
  146. package/dist/client/services/tool-executor.d.ts +0 -41
  147. package/dist/client/services/tool-executor.js +0 -169
  148. package/dist/client/services/workspace-schema-cache.d.ts +0 -149
  149. package/dist/client/services/workspace-schema-cache.js +0 -732
  150. package/dist/client/specialist-daemon.d.ts +0 -77
  151. package/dist/client/specialist-daemon.js +0 -197
  152. package/dist/client/specialists.d.ts +0 -53
  153. package/dist/client/specialists.js +0 -178
  154. package/dist/client/tool-schema-loader.d.ts +0 -62
  155. package/dist/client/tool-schema-loader.js +0 -232
  156. package/dist/client/types.d.ts +0 -327
  157. package/dist/client/types.js +0 -121
  158. package/dist/commands/seed-config.d.ts +0 -9
  159. package/dist/commands/seed-config.js +0 -372
  160. package/dist/lib/context-manager.d.ts +0 -111
  161. package/dist/lib/context-manager.js +0 -431
  162. package/dist/lib/prompt-length-manager.d.ts +0 -81
  163. package/dist/lib/prompt-length-manager.js +0 -457
  164. package/dist/mcp/tools/giuseppe-tools.d.ts +0 -21
  165. package/dist/modules/bug-reports/bug-config.d.ts +0 -25
  166. package/dist/modules/bug-reports/bug-config.js +0 -187
  167. package/dist/modules/bug-reports/bug-monitor.d.ts +0 -108
  168. package/dist/modules/bug-reports/bug-monitor.js +0 -510
  169. package/dist/modules/bug-reports/giuseppe-agent.d.ts +0 -58
  170. package/dist/modules/bug-reports/giuseppe-agent.js +0 -467
  171. package/dist/modules/bug-reports/giuseppe-ai.d.ts +0 -83
  172. package/dist/modules/bug-reports/giuseppe-ai.js +0 -466
  173. package/dist/modules/bug-reports/giuseppe-bot.d.ts +0 -110
  174. package/dist/modules/bug-reports/giuseppe-bot.js +0 -804
  175. package/dist/modules/bug-reports/giuseppe-daemon.d.ts +0 -80
  176. package/dist/modules/bug-reports/giuseppe-daemon.js +0 -617
  177. package/dist/modules/bug-reports/giuseppe-files.d.ts +0 -64
  178. package/dist/modules/bug-reports/giuseppe-files.js +0 -375
  179. package/dist/modules/bug-reports/giuseppe-git.d.ts +0 -48
  180. package/dist/modules/bug-reports/giuseppe-git.js +0 -298
  181. package/dist/modules/bug-reports/giuseppe-lsp.d.ts +0 -113
  182. package/dist/modules/bug-reports/giuseppe-lsp.js +0 -485
  183. package/dist/modules/bug-reports/giuseppe-prompt.d.ts +0 -5
  184. package/dist/modules/bug-reports/giuseppe-prompt.js +0 -94
  185. package/dist/modules/bug-reports/index.d.ts +0 -77
  186. package/dist/modules/bug-reports/index.js +0 -215
  187. package/dist/modules/bug-reports/pending-classification-registry.d.ts +0 -28
  188. package/dist/modules/bug-reports/pending-classification-registry.js +0 -50
  189. package/dist/modules/bug-reports/pending-fix-registry.d.ts +0 -30
  190. package/dist/modules/bug-reports/pending-fix-registry.js +0 -42
  191. package/dist/modules/bug-reports/pending-registry.d.ts +0 -27
  192. package/dist/modules/bug-reports/pending-registry.js +0 -49
  193. package/dist/modules/bug-reports/types.d.ts +0 -123
  194. package/dist/modules/bug-reports/types.js +0 -9
  195. package/dist/routes/agents.d.ts +0 -44
  196. package/dist/routes/agents.js +0 -311
  197. package/dist/services/agent-credential-store.d.ts +0 -73
  198. package/dist/services/agent-credential-store.js +0 -212
  199. package/dist/services/bug-monitor.d.ts +0 -23
  200. package/dist/services/bug-monitor.js +0 -275
@@ -1,846 +0,0 @@
1
- "use strict";
2
- /**
3
- * Chat Agent Daemon
4
- *
5
- * A persistent LLM conversation that monitors all workspace chats.
6
- * The LLM maintains context across messages and decides what to respond to.
7
- *
8
- * Architecture:
9
- * - One daemon per bot client
10
- * - Subscribes to ALL messenger.new signals (not filtered)
11
- * - LLM sees every message with priority markers
12
- * - LLM decides: RESPOND / IGNORE / ACTION
13
- */
14
- var __importDefault = (this && this.__importDefault) || function (mod) {
15
- return (mod && mod.__esModule) ? mod : { "default": mod };
16
- };
17
- Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.ChatAgentDaemon = void 0;
19
- const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
20
- const hailer_clients_1 = require("../../mcp/hailer-clients");
21
- const logger_1 = require("../../lib/logger");
22
- const tool_schema_loader_1 = require("./tool-schema-loader");
23
- const tool_registry_1 = require("../../mcp/tool-registry");
24
- const agent_registry_1 = require("./services/agent-registry");
25
- const conversation_manager_1 = require("./services/conversation-manager");
26
- const mcp_client_1 = require("./services/mcp-client");
27
- const message_formatter_1 = require("./services/message-formatter");
28
- const message_classifier_1 = require("./services/message-classifier");
29
- const session_logger_1 = require("./services/session-logger");
30
- const tool_executor_1 = require("./services/tool-executor");
31
- const workspace_schema_cache_1 = require("./services/workspace-schema-cache");
32
- const bot_config_1 = require("../../mcp/tools/bot-config");
33
- const config_1 = require("../../config");
34
- class ChatAgentDaemon {
35
- logger;
36
- client;
37
- botClient;
38
- config;
39
- toolSchemaLoader = new tool_schema_loader_1.ToolSchemaLoader();
40
- // Processing state
41
- isProcessing = false;
42
- messageQueue = [];
43
- processedMessageIds = new Set();
44
- // Typing indicator state
45
- typingInterval = null;
46
- typingDiscussionId = null;
47
- static TYPING_REFRESH_MS = 3000; // Refresh typing every 3 seconds
48
- // Tool schemas (loaded once)
49
- toolIndex = [];
50
- minimalTools = [];
51
- // ===== SERVICES =====
52
- /** Message classifier - handles message extraction and priority classification */
53
- messageClassifier = null;
54
- /** Conversation manager - handles per-discussion context and LRU cache */
55
- conversationManager = null;
56
- /** MCP client service - handles tool schema loading and execution */
57
- mcpClient = null;
58
- /** Tool executor - handles tool execution and write tracking */
59
- toolExecutor = null;
60
- /** Agent registration service - handles Agent Directory, Position, Team, etc. */
61
- registryService = null;
62
- /** Message formatting service - handles tag resolution and formatting */
63
- messageFormatter = null;
64
- /** Session logging service - handles activity session tracking */
65
- sessionLogger = null;
66
- /** Workspace schema cache - dynamic workflow/field ID lookup */
67
- schemaCache = null;
68
- /** Current discussion context for tracking */
69
- currentDiscussionId = null;
70
- currentLinkedActivityId = null;
71
- /** Unsubscribe function for messenger.new signals */
72
- messengerUnsubscribe = null;
73
- /** Original API key for cleanup - stored at init because botClient.config may change */
74
- originalApiKey = null;
75
- constructor(config) {
76
- this.config = config;
77
- this.botClient = config.botClient;
78
- this.logger = (0, logger_1.createLogger)({
79
- component: "ChatAgentDaemon",
80
- botId: config.botClient.userId
81
- });
82
- this.client = new sdk_1.default({
83
- apiKey: config.anthropicApiKey,
84
- });
85
- }
86
- /**
87
- * Initialize the daemon - load tools and subscribe to signals
88
- */
89
- async initialize() {
90
- this.logger.info("Initializing Chat Agent Daemon", {
91
- botId: this.botClient.userId,
92
- email: (0, config_1.maskEmail)(this.botClient.config.email),
93
- });
94
- // Load tool index once
95
- const allowedGroups = [tool_registry_1.ToolGroup.READ, tool_registry_1.ToolGroup.WRITE];
96
- let tools = await this.toolSchemaLoader.loadToolIndex({
97
- mcpServerUrl: this.config.mcpServerUrl,
98
- mcpServerApiKey: this.botClient.config.mcpServerApiKey,
99
- allowedGroups,
100
- });
101
- // Filter by whitelist if agent specifies one
102
- const whitelist = this.getToolWhitelist();
103
- if (whitelist) {
104
- tools = tools.filter((t) => whitelist.includes(t.name));
105
- this.logger.debug("Tools filtered by whitelist", {
106
- total: tools.length,
107
- whitelist: whitelist.length
108
- });
109
- }
110
- this.toolIndex = tools;
111
- this.minimalTools = this.toolSchemaLoader.toMinimalToolDefinitions(this.toolIndex);
112
- this.logger.debug("Tools loaded", { toolCount: this.toolIndex.length });
113
- // Initialize MCP client service (must be first - other services depend on it)
114
- this.mcpClient = new mcp_client_1.McpClientService(this.config.mcpServerUrl, this.botClient.config.mcpServerApiKey, this.logger);
115
- // Get workspace ID early - needed for schema cache and registration
116
- const workspaceId = this.botClient.workspaceCache?.currentWorkspace?._id || "";
117
- // Initialize workspace schema cache FIRST (discovers workflows dynamically)
118
- // This MUST happen before agent registration so we have dynamic workflow IDs
119
- this.schemaCache = new workspace_schema_cache_1.WorkspaceSchemaCacheService(this.logger, this.mcpClient.callMcpTool.bind(this.mcpClient));
120
- // Initialize schema for current workspace (may install template if missing)
121
- if (workspaceId) {
122
- await this.schemaCache.initializeForWorkspace(workspaceId);
123
- }
124
- // Initialize conversation manager
125
- this.conversationManager = new conversation_manager_1.ConversationManager(100, // maxConversations
126
- this.config.maxContextMessages || 50, this.client, this.logger);
127
- // Initialize tool executor
128
- this.toolExecutor = new tool_executor_1.ToolExecutor(this.mcpClient, this.logger);
129
- // Initialize message classifier
130
- this.messageClassifier = new message_classifier_1.MessageClassifier(this.botClient.userId, this.botClient, this.logger);
131
- // Create agent registry service WITH schema cache for dynamic ID lookup
132
- this.registryService = new agent_registry_1.AgentRegistryService(this.schemaCache, this.logger, this.mcpClient.callMcpTool.bind(this.mcpClient), this.getDefaultTeamId.bind(this));
133
- // Initialize message formatter service
134
- this.messageFormatter = new message_formatter_1.MessageFormatterService(this.botClient, this.logger, this.mcpClient.callMcpTool.bind(this.mcpClient));
135
- // Build agent info from config and abstract methods
136
- const { firstName, lastName } = this.getAgentName();
137
- const agentInfo = {
138
- firstName,
139
- lastName,
140
- description: this.getAgentDescription(),
141
- email: this.botClient.config.email,
142
- userId: this.botClient.userId,
143
- };
144
- // Try to load from cache first (workspace-scoped, 1 API call to verify)
145
- const cacheLoaded = await this.registryService.loadFromCache(this.botClient.userId, workspaceId);
146
- if (!cacheLoaded) {
147
- // Cache miss or invalid - do full registration using dynamic schema lookup
148
- this.logger.info("Starting full agent registration", { workspaceId });
149
- await this.registryService.registerAllAgentData(agentInfo, this.getPositionDetails(), this.config.mcpServerUrl, this.toolIndex, workspaceId);
150
- }
151
- // Store the API key at initialization for cleanup
152
- // This is critical because botClient.config.mcpServerApiKey may change during daemon restart
153
- this.originalApiKey = this.botClient.config.mcpServerApiKey;
154
- // Subscribe to messenger.new signals using the working signal system (same as BugMonitor)
155
- this.messengerUnsubscribe = (0, hailer_clients_1.subscribeToSignal)(this.botClient.config.mcpServerApiKey, 'messenger.new', (eventData) => {
156
- // Convert raw event data to HailerSignal format expected by handleSignal
157
- const signal = {
158
- type: 'messenger.new',
159
- data: eventData,
160
- timestamp: Date.now(),
161
- workspaceId: eventData.sid,
162
- };
163
- this.handleSignal(signal);
164
- });
165
- if (this.messengerUnsubscribe) {
166
- this.logger.info("Subscribed to messenger.new signals via HailerClientManager");
167
- }
168
- else {
169
- this.logger.warn("Failed to subscribe to messenger.new signals - no client manager found");
170
- }
171
- // Initialize session logger service (after registration so we have agentDirectoryId)
172
- this.sessionLogger = new session_logger_1.SessionLoggerService(this.registryService?.getAgentDirectoryId() ?? null, this.logger, this.mcpClient.callMcpTool.bind(this.mcpClient), this.getDefaultTeamId.bind(this));
173
- // Pass Anthropic client for conversation summary generation
174
- this.sessionLogger.setAnthropicClient(this.client);
175
- // Pass schema cache for dynamic workflow ID lookup
176
- if (workspaceId && this.schemaCache) {
177
- this.sessionLogger.setSchemaCache(this.schemaCache, workspaceId);
178
- }
179
- // Start idle session check timer (every 30 seconds)
180
- this.sessionLogger.startIdleCheckTimer(30_000);
181
- // Load existing discussions the bot is already a member of
182
- await this.loadExistingDiscussions();
183
- this.logger.info("Chat Agent Daemon initialized and listening", {
184
- workspaceId,
185
- agentDirectoryId: this.registryService.getAgentDirectoryId(),
186
- positionId: this.registryService.getPositionId(),
187
- teamId: this.registryService.getTeamId(),
188
- });
189
- }
190
- /**
191
- * Load existing discussions the bot is already a member of
192
- * This ensures the bot can respond to messages in discussions it was added to before startup
193
- */
194
- async loadExistingDiscussions() {
195
- if (!this.conversationManager) {
196
- this.logger.warn("Cannot load existing discussions - conversationManager not initialized");
197
- return;
198
- }
199
- try {
200
- // Use bot's hailer connection directly to get discussions
201
- const hailerClient = this.botClient.client;
202
- if (!hailerClient) {
203
- this.logger.warn("Cannot load existing discussions - hailer client not available");
204
- return;
205
- }
206
- // Call discussion sync API directly via socket
207
- const syncResponse = await hailerClient.socket.request('v2.discussion.sync', [{ timestamp: 0 }]);
208
- const discussions = syncResponse?.discussions || [];
209
- if (discussions.length === 0) {
210
- this.logger.debug("Bot is not a member of any discussions");
211
- return;
212
- }
213
- this.logger.info("Loading existing discussions", { count: discussions.length });
214
- // Pre-populate ConversationManager with each discussion
215
- for (const discussion of discussions) {
216
- // Create an empty conversation entry - messages will come via signals
217
- this.conversationManager.getConversation(discussion._id);
218
- this.logger.debug("Registered existing discussion", {
219
- discussionId: discussion._id,
220
- name: discussion.name || "Untitled"
221
- });
222
- }
223
- this.logger.info("Existing discussions loaded", {
224
- loaded: discussions.length,
225
- totalTracked: this.conversationManager.getState().discussionCount
226
- });
227
- }
228
- catch (error) {
229
- this.logger.warn("Failed to load existing discussions", { error });
230
- // Non-fatal - bot will still work for new messages
231
- }
232
- }
233
- /**
234
- * Extract and classify incoming message from signal
235
- * Can be overridden in subclasses to customize filtering
236
- */
237
- async extractIncomingMessage(signal) {
238
- return this.messageClassifier.extractIncomingMessage(signal);
239
- }
240
- /**
241
- * Handle incoming signal from Hailer
242
- */
243
- async handleSignal(signal) {
244
- try {
245
- // EARLY dedup check using raw signal data (before async operation)
246
- // This prevents race condition where two signals arrive simultaneously
247
- const signalData = signal.data;
248
- const rawMsgId = signalData.msg_id;
249
- if (rawMsgId) {
250
- if (this.processedMessageIds.has(rawMsgId)) {
251
- this.logger.debug("Early dedup: skipping duplicate signal", { rawMsgId });
252
- return;
253
- }
254
- // Add immediately to prevent race condition
255
- this.processedMessageIds.add(rawMsgId);
256
- }
257
- const message = await this.extractIncomingMessage(signal);
258
- if (!message) {
259
- // Remove from set if extraction failed (message was invalid)
260
- if (rawMsgId)
261
- this.processedMessageIds.delete(rawMsgId);
262
- return;
263
- }
264
- // Clean up old IDs (keep last 500)
265
- if (this.processedMessageIds.size > 500) {
266
- const ids = Array.from(this.processedMessageIds);
267
- this.processedMessageIds = new Set(ids.slice(-250));
268
- }
269
- this.logger.info("Incoming message", {
270
- from: message.senderName,
271
- discussion: message.discussionId,
272
- priority: message.priority,
273
- reason: message.priorityReason,
274
- preview: message.content.substring(0, 50),
275
- });
276
- // Queue the message
277
- this.messageQueue.push(message);
278
- // Process if not already processing
279
- if (!this.isProcessing) {
280
- await this.processQueue();
281
- }
282
- }
283
- catch (error) {
284
- this.logger.error("Failed to handle signal", error);
285
- }
286
- }
287
- /**
288
- * Process queued messages through the LLM
289
- * Note: Uses flag-first pattern to prevent race conditions
290
- */
291
- async processQueue() {
292
- // Set flag FIRST to prevent race condition (multiple async calls)
293
- if (this.isProcessing)
294
- return;
295
- this.isProcessing = true;
296
- // Now check queue (after claiming the lock)
297
- if (this.messageQueue.length === 0) {
298
- this.isProcessing = false;
299
- return;
300
- }
301
- try {
302
- // Sort by priority (high first) then by timestamp
303
- this.messageQueue.sort((a, b) => {
304
- const priorityOrder = { high: 0, normal: 1, low: 2 };
305
- if (priorityOrder[a.priority] !== priorityOrder[b.priority]) {
306
- return priorityOrder[a.priority] - priorityOrder[b.priority];
307
- }
308
- return a.timestamp - b.timestamp;
309
- });
310
- // Process one message at a time for now
311
- while (this.messageQueue.length > 0) {
312
- const message = this.messageQueue.shift();
313
- await this.processMessage(message);
314
- }
315
- }
316
- finally {
317
- this.isProcessing = false;
318
- }
319
- }
320
- /**
321
- * Process a single message through the persistent LLM conversation
322
- */
323
- async processMessage(message) {
324
- // Check if bot is still enabled (may have been disabled via AI Hub)
325
- const botState = (0, bot_config_1.getBotState)();
326
- if (!botState[this.config.botClient.userId]) {
327
- this.logger.info("Bot disabled, skipping message", {
328
- discussion: message.discussionId,
329
- from: message.senderName,
330
- });
331
- return;
332
- }
333
- const startTime = Date.now();
334
- // Update current context for session tracking
335
- this.currentDiscussionId = message.discussionId;
336
- this.currentLinkedActivityId = message.linkedActivityId || null;
337
- // Multi-tenant: Initialize schema cache for this workspace on-demand
338
- // Each workspace has its own workflow IDs - must be cached before processing
339
- if (this.schemaCache && message.workspaceId) {
340
- const schemas = this.schemaCache.getSchemas(message.workspaceId);
341
- if (!schemas?.initialized) {
342
- this.logger.info("Initializing schema cache for workspace", { workspaceId: message.workspaceId });
343
- await this.schemaCache.initializeForWorkspace(message.workspaceId);
344
- // Update session logger with workspace-specific schema
345
- if (this.sessionLogger) {
346
- this.sessionLogger.setSchemaCache(this.schemaCache, message.workspaceId);
347
- }
348
- }
349
- }
350
- // Start typing indicator with auto-refresh
351
- this.startTypingIndicator(message.discussionId);
352
- // Get or create activity session
353
- const session = this.sessionLogger.getOrCreateActivitySession(message);
354
- session.lastActivityTime = Date.now();
355
- session.metrics.messagesProcessed++;
356
- // Add user message to conversation log (compact version)
357
- const userSnippet = message.content.length > 100
358
- ? message.content.substring(0, 100) + "..."
359
- : message.content;
360
- session.conversation.push(`${message.senderName}: ${userSnippet}`);
361
- // Format incoming message for LLM
362
- const incomingContent = this.formatIncomingMessage(message);
363
- // Get conversation for THIS discussion (isolated context)
364
- const conversation = this.conversationManager.getConversation(message.discussionId);
365
- // Load memory from Hailer if this is a new conversation for an activity
366
- if (conversation.length === 0 && message.linkedActivityId) {
367
- await this.injectMemoryForActivity(conversation, message.linkedActivityId, message.workspaceId);
368
- }
369
- // Append to conversation
370
- conversation.push({
371
- role: "user",
372
- content: incomingContent,
373
- });
374
- // Check context size and summarize if needed
375
- await this.conversationManager.manageContextSize(message.discussionId);
376
- try {
377
- // Call LLM with this discussion's conversation
378
- const response = await this.client.messages.create({
379
- model: this.config.model || "claude-haiku-4-5-20251001",
380
- max_tokens: 2000,
381
- system: this.getSystemPrompt(),
382
- messages: conversation,
383
- tools: this.getTools(),
384
- });
385
- // Track token usage in the activity session
386
- if (response.usage) {
387
- session.metrics.inputTokens += response.usage.input_tokens;
388
- session.metrics.outputTokens += response.usage.output_tokens;
389
- }
390
- // Handle response
391
- await this.handleLlmResponse(response, message);
392
- const duration = Date.now() - startTime;
393
- this.logger.info("Message processed", {
394
- discussion: message.discussionId,
395
- duration,
396
- stopReason: response.stop_reason,
397
- sessionActivity: session.activityName,
398
- });
399
- // Update last activity time (idle checker will flush when needed)
400
- session.lastActivityTime = Date.now();
401
- }
402
- catch (error) {
403
- this.logger.error("LLM processing failed", error);
404
- // Stop typing indicator on error
405
- this.stopTypingIndicator();
406
- // On error, remove the message from conversation to avoid poisoning context
407
- if (conversation.length > 0) {
408
- conversation.pop();
409
- }
410
- }
411
- }
412
- /**
413
- * Format incoming message for LLM consumption
414
- */
415
- formatIncomingMessage(message) {
416
- const priorityTag = message.priority === "high" ? " priority=\"high\"" : "";
417
- const reasonAttr = message.priority === "high" ? ` reason="${message.priorityReason}"` : "";
418
- const activityAttr = message.linkedActivityId ? ` activity_id="${message.linkedActivityId}"` : "";
419
- return `<incoming discussion="${message.discussionId}"${activityAttr} from="${message.senderName}" user_id="${message.senderId}" timestamp="${new Date(message.timestamp).toISOString()}"${priorityTag}${reasonAttr}>
420
- ${message.content}
421
- </incoming>`;
422
- }
423
- /**
424
- * Load and inject memory for an activity into conversation context
425
- * Called when entering a new discussion that's linked to an activity
426
- */
427
- async injectMemoryForActivity(conversation, activityId, workspaceId) {
428
- try {
429
- const memoryEntries = await this.sessionLogger.loadMemoryForActivity(activityId, workspaceId, 5);
430
- if (memoryEntries.length > 0) {
431
- const memoryContext = this.sessionLogger.formatMemoryForContext(memoryEntries);
432
- // Inject memory as a system-like user message at the start
433
- conversation.push({
434
- role: "user",
435
- content: memoryContext,
436
- });
437
- // Add acknowledgment to keep conversation valid (assistant must respond)
438
- conversation.push({
439
- role: "assistant",
440
- content: "I've loaded context from previous interactions with this activity. I'll use this to provide better continuity.",
441
- });
442
- this.logger.info("Injected memory into conversation", {
443
- activityId,
444
- memoryCount: memoryEntries.length,
445
- });
446
- }
447
- }
448
- catch (error) {
449
- this.logger.warn("Failed to inject memory", {
450
- activityId,
451
- error: error instanceof Error ? error.message : String(error),
452
- });
453
- // Continue without memory - not critical
454
- }
455
- }
456
- /**
457
- * Execute tool calls and continue the conversation
458
- * Simple passthrough - just execute tools and return results to LLM
459
- */
460
- async executeToolsAndContinue(toolUseBlocks, originalMessage) {
461
- // Get current activity session
462
- const sessionKey = this.currentLinkedActivityId || this.currentDiscussionId || "default";
463
- const session = this.sessionLogger.getSession(sessionKey);
464
- // Store the user's request that triggered these tool calls (for context)
465
- if (session && !session.triggerRequest) {
466
- session.triggerRequest = originalMessage.content.substring(0, 500);
467
- session.requestedBy = originalMessage.senderName;
468
- session.requestedById = originalMessage.senderId;
469
- }
470
- // Execute tools using the tool executor service
471
- const toolResults = await this.toolExecutor.executeTools(toolUseBlocks, {
472
- session,
473
- preprocessToolInput: this.preprocessToolInput.bind(this),
474
- });
475
- // Get conversation for this discussion
476
- const conversation = this.conversationManager.getConversation(originalMessage.discussionId);
477
- // Add tool results to conversation
478
- conversation.push({
479
- role: "user",
480
- content: toolResults,
481
- });
482
- // Continue with LLM
483
- const response = await this.client.messages.create({
484
- model: this.config.model || "claude-haiku-4-5-20251001",
485
- max_tokens: 2000,
486
- system: this.getSystemPrompt(),
487
- messages: conversation,
488
- tools: this.getTools(),
489
- });
490
- // Track token usage in session
491
- if (session && response.usage) {
492
- session.metrics.inputTokens += response.usage.input_tokens;
493
- session.metrics.outputTokens += response.usage.output_tokens;
494
- session.lastActivityTime = Date.now();
495
- }
496
- // Recursively handle (might need more tools or finally respond)
497
- await this.handleLlmResponse(response, originalMessage);
498
- }
499
- /**
500
- * Handle LLM response
501
- * Override in subclasses to customize response handling
502
- */
503
- async handleLlmResponse(response, originalMessage) {
504
- // Get conversation for this discussion
505
- const conversation = this.conversationManager.getConversation(originalMessage.discussionId);
506
- // Add assistant response to conversation
507
- // Cast response content to MessageParam content type (ContentBlock[] → ContentBlockParam[])
508
- conversation.push({
509
- role: "assistant",
510
- content: response.content,
511
- });
512
- // Check for tool calls
513
- const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
514
- if (toolUseBlocks.length > 0) {
515
- // Execute tools and continue conversation
516
- await this.executeToolsAndContinue(toolUseBlocks, originalMessage);
517
- return;
518
- }
519
- // Check for text response
520
- const textBlocks = response.content.filter((block) => block.type === "text");
521
- if (textBlocks.length > 0) {
522
- const responseText = textBlocks.map(b => b.text).join("\n").trim();
523
- // Log metadata only - avoid logging user content (PII risk)
524
- this.logger.info("LLM response received", {
525
- discussion: originalMessage.discussionId,
526
- priority: originalMessage.priority,
527
- responseLength: responseText.length,
528
- hasIgnoreTag: responseText.includes("<ignore"),
529
- hasRespondTag: responseText.includes("<respond"),
530
- });
531
- // Check for IGNORE decision
532
- if (responseText.includes("<decision>IGNORE</decision>") ||
533
- responseText.includes("<ignore")) {
534
- this.logger.debug("LLM decided to ignore message - removing from context", {
535
- discussion: originalMessage.discussionId,
536
- });
537
- // Stop typing indicator
538
- this.stopTypingIndicator();
539
- // Remove both the assistant's ignore response AND the original incoming message
540
- // to keep the context clean from irrelevant chatter
541
- conversation.pop(); // Remove assistant response we just added
542
- conversation.pop(); // Remove the incoming message
543
- return;
544
- }
545
- // Check for explicit response directive
546
- const responseMatch = responseText.match(/<respond discussion="([^"]+)">([\s\S]*?)<\/respond>/);
547
- if (responseMatch) {
548
- const targetDiscussion = responseMatch[1];
549
- const content = responseMatch[2].trim();
550
- await this.postResponse(targetDiscussion, content);
551
- return;
552
- }
553
- // For high priority messages, always send substantive responses
554
- if (originalMessage.priority === "high" && responseText &&
555
- !responseText.includes("<thinking>") &&
556
- !responseText.startsWith("I'll") &&
557
- responseText.length > 10) {
558
- await this.postResponse(originalMessage.discussionId, responseText);
559
- return;
560
- }
561
- // For normal priority, ONLY respond if LLM used explicit <respond> tag
562
- // This was already handled above - if we reach here, don't post
563
- // (LLM should use <respond> or <ignore> for normal priority messages)
564
- if (originalMessage.priority === "normal") {
565
- this.logger.debug("Normal priority without <respond> tag - removing from context", {
566
- discussion: originalMessage.discussionId,
567
- responsePreview: responseText.substring(0, 100),
568
- });
569
- // Stop typing indicator
570
- this.stopTypingIndicator();
571
- // Remove from context - we didn't respond so don't need this in history
572
- conversation.pop(); // Remove assistant response
573
- conversation.pop(); // Remove incoming message
574
- }
575
- }
576
- }
577
- /**
578
- * Start typing indicator with auto-refresh interval
579
- * Keeps refreshing every 3 seconds until stopTypingIndicator is called
580
- */
581
- startTypingIndicator(discussionId) {
582
- // Stop any existing typing interval
583
- this.stopTypingIndicator();
584
- this.typingDiscussionId = discussionId;
585
- // Send initial typing signal
586
- this.sendTypingSignal(discussionId, true);
587
- // Set up interval to refresh typing (prevents server-side timeout)
588
- this.typingInterval = setInterval(() => {
589
- if (this.typingDiscussionId) {
590
- this.sendTypingSignal(this.typingDiscussionId, true);
591
- }
592
- }, ChatAgentDaemon.TYPING_REFRESH_MS);
593
- }
594
- /**
595
- * Stop typing indicator and clear refresh interval
596
- */
597
- stopTypingIndicator() {
598
- if (this.typingInterval) {
599
- clearInterval(this.typingInterval);
600
- this.typingInterval = null;
601
- }
602
- if (this.typingDiscussionId) {
603
- this.sendTypingSignal(this.typingDiscussionId, false);
604
- this.typingDiscussionId = null;
605
- }
606
- }
607
- /**
608
- * Send typing signal to Hailer API
609
- * API: messenger.set_discussion_typing_state(discussionId, typingState)
610
- */
611
- sendTypingSignal(discussionId, isTyping) {
612
- this.botClient.client.socket.request("messenger.set_discussion_typing_state", [
613
- discussionId,
614
- isTyping
615
- ]).catch((error) => {
616
- // Silently ignore - typing indicator is not critical
617
- this.logger.debug("Typing indicator failed", { discussionId, isTyping, error: error?.message });
618
- });
619
- }
620
- /**
621
- * Post a response to a discussion
622
- * Automatically converts @mentions and #activity tags to Hailer tags
623
- * Includes links metadata required for tags to work
624
- */
625
- async postResponse(discussionId, content) {
626
- // Stop typing indicator before posting
627
- this.stopTypingIndicator();
628
- try {
629
- // Resolve tags that need API lookup
630
- let formattedContent = await this.messageFormatter.resolveUserTags(content); // @userId → [hailerTag|Name](id)
631
- formattedContent = await this.messageFormatter.resolveActivityTags(formattedContent); // #activityId → [hailerTag|Name](id)
632
- formattedContent = await this.messageFormatter.resolveHailerUrls(formattedContent); // URLs → [hailerTag|Name](id)
633
- // Then convert any remaining @mentions from cache (fallback)
634
- formattedContent = this.messageFormatter.convertMentionsToTags(formattedContent);
635
- // Remove redundant "(Name)" after tags - LLM sometimes adds these
636
- formattedContent = formattedContent.replace(/(\[hailerTag\|[^\]]+\]\([a-f0-9]{24}\)\uFEFF?)\s*\([^)]+\)/gi, '$1');
637
- // Extract link metadata for any tags in the content
638
- const links = this.messageFormatter.extractTagLinks(formattedContent);
639
- // Build message object with links if we have any
640
- const messageData = {
641
- msg: formattedContent
642
- };
643
- if (links.length > 0) {
644
- messageData.links = links;
645
- }
646
- await this.botClient.client.socket.request("messenger.send", [
647
- messageData,
648
- discussionId,
649
- ]);
650
- // Track response in activity session
651
- const sessionKey = this.currentLinkedActivityId || this.currentDiscussionId || "default";
652
- const session = this.sessionLogger.getSession(sessionKey);
653
- if (session) {
654
- session.metrics.responsesPosted++;
655
- session.actions.push(`Responded in discussion`);
656
- session.lastActivityTime = Date.now();
657
- // Add bot response to conversation log (compact version)
658
- const botSnippet = content.length > 100 ? content.substring(0, 100) + "..." : content;
659
- session.conversation.push(`Bot: ${botSnippet}`);
660
- }
661
- this.logger.info("Response posted", {
662
- discussion: discussionId,
663
- length: formattedContent.length,
664
- hadTags: formattedContent !== content,
665
- linkCount: links.length,
666
- });
667
- }
668
- catch (error) {
669
- this.logger.error("Failed to post response", error);
670
- }
671
- }
672
- /**
673
- * Get the system prompt for the daemon
674
- * MUST be overridden in subclasses
675
- */
676
- getSystemPrompt() {
677
- throw new Error("getSystemPrompt() must be implemented by subclass");
678
- }
679
- /**
680
- * Get tools for LLM calls
681
- * Override in subclass to add custom tools (like trigger_giuseppe_retry)
682
- */
683
- getTools() {
684
- return this.minimalTools;
685
- }
686
- /**
687
- * Get tool whitelist for this agent
688
- * Override in subclass to limit which tools are available
689
- * Return null for all tools, or array of tool names
690
- */
691
- getToolWhitelist() {
692
- return null; // Default: all tools
693
- }
694
- /**
695
- * Preprocess tool input before execution
696
- * Override in subclass to inject context (e.g., sourceActivityId)
697
- * @param toolName - Name of the tool being called
698
- * @param input - Original tool input from LLM
699
- * @returns Processed input (may be modified)
700
- */
701
- preprocessToolInput(toolName, input) {
702
- return input; // Default: no preprocessing
703
- }
704
- /**
705
- * Call MCP tool (delegates to McpClientService)
706
- * Protected for subclass access
707
- */
708
- async callMcpTool(name, args) {
709
- return this.mcpClient.callMcpTool(name, args);
710
- }
711
- /**
712
- * Stop the daemon
713
- * Flushes all pending activity sessions before stopping
714
- */
715
- async stop() {
716
- // Stop idle check timer and flush all pending sessions
717
- this.sessionLogger?.stopIdleCheckTimer();
718
- await this.sessionLogger?.flushAllSessions();
719
- // Unsubscribe from messenger.new signals
720
- if (this.messengerUnsubscribe) {
721
- this.messengerUnsubscribe();
722
- this.messengerUnsubscribe = null;
723
- }
724
- // Disconnect the Hailer client connection using the ORIGINAL API key
725
- // This is critical: botClient.config.mcpServerApiKey may have been updated to a new value
726
- // before stop() is called during restart, so we must use the stored originalApiKey
727
- if (this.originalApiKey) {
728
- (0, hailer_clients_1.disconnectHailerClientByApiKey)(this.originalApiKey);
729
- this.originalApiKey = null;
730
- }
731
- this.botClient.signalHandler.unsubscribe(`daemon-${this.botClient.userId}`);
732
- this.logger.info("Chat Agent Daemon stopped", {
733
- agentDirectoryId: this.registryService?.getAgentDirectoryId(),
734
- activeSessions: this.sessionLogger?.getActiveSessions().size ?? 0,
735
- });
736
- }
737
- /**
738
- * Get current conversation state (for debugging)
739
- */
740
- getConversationState() {
741
- // Get current discussion's conversation
742
- const currentConversation = this.currentDiscussionId
743
- ? this.conversationManager.getConversation(this.currentDiscussionId)
744
- : [];
745
- // Get last 5 messages with preview
746
- const lastMessages = currentConversation.slice(-5).map(msg => {
747
- let preview = "";
748
- if (typeof msg.content === "string") {
749
- preview = msg.content.substring(0, 100);
750
- }
751
- else if (Array.isArray(msg.content)) {
752
- const textBlock = msg.content.find((b) => b.type === "text");
753
- preview = textBlock?.text?.substring(0, 100) || "[tool call/result]";
754
- }
755
- return {
756
- role: msg.role,
757
- preview: preview + (preview.length >= 100 ? "..." : ""),
758
- };
759
- });
760
- const state = this.conversationManager.getState(this.currentDiscussionId ?? undefined);
761
- return {
762
- discussionCount: state.discussionCount,
763
- currentDiscussion: this.currentDiscussionId,
764
- currentMessageCount: currentConversation.length,
765
- queueLength: this.messageQueue.length,
766
- lastMessages,
767
- isProcessing: this.isProcessing,
768
- };
769
- }
770
- /**
771
- * Get full conversation for a specific discussion (for debugging)
772
- */
773
- getFullConversation(discussionId) {
774
- const targetDiscussion = discussionId || this.currentDiscussionId;
775
- if (!targetDiscussion)
776
- return [];
777
- return [...this.conversationManager.getFullConversation(targetDiscussion)];
778
- }
779
- // ===== AGENT REGISTRY & SESSION LOGGING METHODS =====
780
- /**
781
- * Get agent's display name (override in subclass for custom names)
782
- * Default implementation uses the actual Hailer user name from BotClient
783
- */
784
- getAgentName() {
785
- // Use actual Hailer user name from BotClient (populated from workspace cache)
786
- return {
787
- firstName: this.botClient.firstName,
788
- lastName: this.botClient.lastName,
789
- };
790
- }
791
- /**
792
- * Get agent's description/system prompt (override in subclass)
793
- */
794
- getAgentDescription() {
795
- return "Chat Agent Daemon - handles general workspace conversations";
796
- }
797
- /**
798
- * Get default team ID from workspace cache
799
- * Returns the first available team, or undefined if no teams exist
800
- *
801
- * Teams structure in init is: { teams: { workspaceId: { teamId: teamData, ... } } }
802
- */
803
- getDefaultTeamId() {
804
- const rawInit = this.botClient.workspaceCache?.rawInit;
805
- if (!rawInit?.teams) {
806
- this.logger.debug("No teams in workspace cache");
807
- return undefined;
808
- }
809
- // Teams are nested under workspace ID
810
- // Structure: { workspaceId: { teamId1: {...}, teamId2: {...} } }
811
- const workspaceTeams = Object.values(rawInit.teams)[0];
812
- if (!workspaceTeams || typeof workspaceTeams !== 'object') {
813
- this.logger.debug("No workspace teams found");
814
- return undefined;
815
- }
816
- const teamIds = Object.keys(workspaceTeams);
817
- if (teamIds.length === 0) {
818
- this.logger.debug("No teams available in workspace");
819
- return undefined;
820
- }
821
- const defaultTeamId = teamIds[0];
822
- const teamName = workspaceTeams[defaultTeamId]?.name || 'unknown';
823
- this.logger.debug("Using default team", { teamId: defaultTeamId, teamName, teamCount: teamIds.length });
824
- return defaultTeamId;
825
- }
826
- /**
827
- * Get agent's Position details (override in subclass for custom positions)
828
- */
829
- getPositionDetails() {
830
- return {
831
- name: "Chat Agent",
832
- purpose: "General workspace assistant that monitors discussions and responds to user queries.",
833
- personaTone: "Professional, helpful, and concise. Responds directly without unnecessary filler.",
834
- coreCapabilities: "- Monitor workspace discussions\n- Answer questions about workflows and activities\n- Execute MCP tools to read/write data\n- Tag users and link activities",
835
- boundaries: "- Never fabricate data - always use tools\n- Don't respond to off-topic messages\n- Don't share sensitive credentials",
836
- };
837
- }
838
- /**
839
- * Get agent directory ID
840
- */
841
- getAgentDirectoryId() {
842
- return this.registryService?.getAgentDirectoryId() || null;
843
- }
844
- }
845
- exports.ChatAgentDaemon = ChatAgentDaemon;
846
- //# sourceMappingURL=base.js.map