@hailer/mcp 1.1.15 → 1.1.16
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/agents/bot-manager.d.ts +48 -0
- package/dist/agents/bot-manager.d.ts.map +1 -0
- package/dist/agents/bot-manager.js +254 -0
- package/dist/agents/bot-manager.js.map +1 -0
- package/dist/agents/bug-fixer/ai.d.ts +80 -0
- package/dist/agents/bug-fixer/ai.d.ts.map +1 -0
- package/dist/agents/bug-fixer/ai.js +466 -0
- package/dist/agents/bug-fixer/ai.js.map +1 -0
- package/dist/agents/bug-fixer/bot.d.ts +92 -0
- package/dist/agents/bug-fixer/bot.d.ts.map +1 -0
- package/dist/agents/bug-fixer/bot.js +687 -0
- package/dist/agents/bug-fixer/bot.js.map +1 -0
- package/dist/agents/bug-fixer/config.d.ts +21 -0
- package/dist/agents/bug-fixer/config.d.ts.map +1 -0
- package/dist/agents/bug-fixer/config.js +218 -0
- package/dist/agents/bug-fixer/config.js.map +1 -0
- package/dist/agents/bug-fixer/files.d.ts +67 -0
- package/dist/agents/bug-fixer/files.d.ts.map +1 -0
- package/dist/agents/bug-fixer/files.js +386 -0
- package/dist/agents/bug-fixer/files.js.map +1 -0
- package/dist/agents/bug-fixer/git.d.ts +48 -0
- package/dist/agents/bug-fixer/git.d.ts.map +1 -0
- package/dist/agents/bug-fixer/git.js +298 -0
- package/dist/agents/bug-fixer/git.js.map +1 -0
- package/dist/agents/bug-fixer/index.d.ts +103 -0
- package/dist/agents/bug-fixer/index.d.ts.map +1 -0
- package/dist/agents/bug-fixer/index.js +262 -0
- package/dist/agents/bug-fixer/index.js.map +1 -0
- package/dist/agents/bug-fixer/lsp.d.ts +113 -0
- package/dist/agents/bug-fixer/lsp.d.ts.map +1 -0
- package/dist/agents/bug-fixer/lsp.js +485 -0
- package/dist/agents/bug-fixer/lsp.js.map +1 -0
- package/dist/agents/bug-fixer/monitor.d.ts +123 -0
- package/dist/agents/bug-fixer/monitor.d.ts.map +1 -0
- package/dist/agents/bug-fixer/monitor.js +629 -0
- package/dist/agents/bug-fixer/monitor.js.map +1 -0
- package/dist/agents/bug-fixer/prompt.d.ts +5 -0
- package/dist/agents/bug-fixer/prompt.d.ts.map +1 -0
- package/dist/agents/bug-fixer/prompt.js +94 -0
- package/dist/agents/bug-fixer/prompt.js.map +1 -0
- package/dist/agents/bug-fixer/registries/pending-classification.d.ts +28 -0
- package/dist/agents/bug-fixer/registries/pending-classification.d.ts.map +1 -0
- package/dist/agents/bug-fixer/registries/pending-classification.js +50 -0
- package/dist/agents/bug-fixer/registries/pending-classification.js.map +1 -0
- package/dist/agents/bug-fixer/registries/pending-fix.d.ts +33 -0
- package/dist/agents/bug-fixer/registries/pending-fix.d.ts.map +1 -0
- package/dist/agents/bug-fixer/registries/pending-fix.js +64 -0
- package/dist/agents/bug-fixer/registries/pending-fix.js.map +1 -0
- package/dist/agents/bug-fixer/registries/pending.d.ts +27 -0
- package/dist/agents/bug-fixer/registries/pending.d.ts.map +1 -0
- package/dist/agents/bug-fixer/registries/pending.js +49 -0
- package/dist/agents/bug-fixer/registries/pending.js.map +1 -0
- package/dist/agents/bug-fixer/specialist-daemon.d.ts +88 -0
- package/dist/agents/bug-fixer/specialist-daemon.d.ts.map +1 -0
- package/dist/agents/bug-fixer/specialist-daemon.js +431 -0
- package/dist/agents/bug-fixer/specialist-daemon.js.map +1 -0
- package/dist/agents/bug-fixer/specialist.d.ts +47 -0
- package/dist/agents/bug-fixer/specialist.d.ts.map +1 -0
- package/dist/agents/bug-fixer/specialist.js +327 -0
- package/dist/agents/bug-fixer/specialist.js.map +1 -0
- package/dist/agents/bug-fixer/types.d.ts +123 -0
- package/dist/agents/bug-fixer/types.d.ts.map +1 -0
- package/dist/agents/bug-fixer/types.js +9 -0
- package/dist/agents/bug-fixer/types.js.map +1 -0
- package/dist/agents/factory.d.ts +172 -0
- package/dist/agents/factory.d.ts.map +1 -0
- package/dist/agents/factory.js +706 -0
- package/dist/agents/factory.js.map +1 -0
- package/dist/agents/hailer-expert/index.d.ts +8 -0
- package/dist/agents/hailer-expert/index.d.ts.map +1 -0
- package/dist/agents/hailer-expert/index.js +14 -0
- package/dist/agents/hailer-expert/index.js.map +1 -0
- package/dist/agents/hal/daemon.d.ts +174 -0
- package/dist/agents/hal/daemon.d.ts.map +1 -0
- package/dist/agents/hal/daemon.js +1385 -0
- package/dist/agents/hal/daemon.js.map +1 -0
- package/dist/agents/hal/definitions.d.ts +42 -0
- package/dist/agents/hal/definitions.d.ts.map +1 -0
- package/dist/agents/hal/definitions.js +300 -0
- package/dist/agents/hal/definitions.js.map +1 -0
- package/dist/agents/hal/index.d.ts +3 -0
- package/dist/agents/hal/index.d.ts.map +1 -0
- package/dist/agents/hal/index.js +8 -0
- package/dist/agents/hal/index.js.map +1 -0
- package/dist/agents/index.d.ts +18 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +48 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/shared/base.d.ts +253 -0
- package/dist/agents/shared/base.d.ts.map +1 -0
- package/dist/agents/shared/base.js +1122 -0
- package/dist/agents/shared/base.js.map +1 -0
- package/dist/agents/shared/schemas/action-schema.d.ts +62 -0
- package/dist/agents/shared/schemas/action-schema.d.ts.map +1 -0
- package/dist/agents/shared/schemas/action-schema.js +483 -0
- package/dist/agents/shared/schemas/action-schema.js.map +1 -0
- package/dist/agents/shared/services/agent-registry.d.ts +108 -0
- package/dist/agents/shared/services/agent-registry.d.ts.map +1 -0
- package/dist/agents/shared/services/agent-registry.js +469 -0
- package/dist/agents/shared/services/agent-registry.js.map +1 -0
- package/dist/agents/shared/services/conversation-manager.d.ts +57 -0
- package/dist/agents/shared/services/conversation-manager.d.ts.map +1 -0
- package/dist/agents/shared/services/conversation-manager.js +168 -0
- package/dist/agents/shared/services/conversation-manager.js.map +1 -0
- package/dist/agents/shared/services/mcp-client.d.ts +56 -0
- package/dist/agents/shared/services/mcp-client.d.ts.map +1 -0
- package/dist/agents/shared/services/mcp-client.js +124 -0
- package/dist/agents/shared/services/mcp-client.js.map +1 -0
- package/dist/agents/shared/services/message-classifier.d.ts +37 -0
- package/dist/agents/shared/services/message-classifier.d.ts.map +1 -0
- package/dist/agents/shared/services/message-classifier.js +203 -0
- package/dist/agents/shared/services/message-classifier.js.map +1 -0
- package/dist/agents/shared/services/message-formatter.d.ts +89 -0
- package/dist/agents/shared/services/message-formatter.d.ts.map +1 -0
- package/dist/agents/shared/services/message-formatter.js +390 -0
- package/dist/agents/shared/services/message-formatter.js.map +1 -0
- package/dist/agents/shared/services/session-logger.d.ts +162 -0
- package/dist/agents/shared/services/session-logger.d.ts.map +1 -0
- package/dist/agents/shared/services/session-logger.js +724 -0
- package/dist/agents/shared/services/session-logger.js.map +1 -0
- package/dist/agents/shared/services/structured-output-executor.d.ts +88 -0
- package/dist/agents/shared/services/structured-output-executor.d.ts.map +1 -0
- package/dist/agents/shared/services/structured-output-executor.js +296 -0
- package/dist/agents/shared/services/structured-output-executor.js.map +1 -0
- package/dist/agents/shared/services/token-billing.d.ts +72 -0
- package/dist/agents/shared/services/token-billing.d.ts.map +1 -0
- package/dist/agents/shared/services/token-billing.js +198 -0
- package/dist/agents/shared/services/token-billing.js.map +1 -0
- package/dist/agents/shared/services/tool-executor.d.ts +43 -0
- package/dist/agents/shared/services/tool-executor.d.ts.map +1 -0
- package/dist/agents/shared/services/tool-executor.js +175 -0
- package/dist/agents/shared/services/tool-executor.js.map +1 -0
- package/dist/agents/shared/services/typing-indicator.d.ts +24 -0
- package/dist/agents/shared/services/typing-indicator.d.ts.map +1 -0
- package/dist/agents/shared/services/typing-indicator.js +54 -0
- package/dist/agents/shared/services/typing-indicator.js.map +1 -0
- package/dist/agents/shared/services/workspace-schema-cache.d.ts +122 -0
- package/dist/agents/shared/services/workspace-schema-cache.d.ts.map +1 -0
- package/dist/agents/shared/services/workspace-schema-cache.js +507 -0
- package/dist/agents/shared/services/workspace-schema-cache.js.map +1 -0
- package/dist/agents/shared/specialist.d.ts +91 -0
- package/dist/agents/shared/specialist.d.ts.map +1 -0
- package/dist/agents/shared/specialist.js +399 -0
- package/dist/agents/shared/specialist.js.map +1 -0
- package/dist/agents/shared/tool-schema-loader.d.ts +65 -0
- package/dist/agents/shared/tool-schema-loader.d.ts.map +1 -0
- package/dist/agents/shared/tool-schema-loader.js +238 -0
- package/dist/agents/shared/tool-schema-loader.js.map +1 -0
- package/dist/agents/shared/types.d.ts +190 -0
- package/dist/agents/shared/types.d.ts.map +1 -0
- package/dist/agents/shared/types.js +13 -0
- package/dist/agents/shared/types.js.map +1 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js.map +1 -0
- package/dist/bot/bot-config.d.ts.map +1 -0
- package/dist/bot/bot-config.js.map +1 -0
- package/dist/bot/bot-manager.d.ts.map +1 -0
- package/dist/bot/bot-manager.js.map +1 -0
- package/dist/bot/bot.d.ts.map +1 -0
- package/dist/bot/bot.js.map +1 -0
- package/dist/bot/operation-logger.d.ts.map +1 -0
- package/dist/bot/operation-logger.js.map +1 -0
- package/dist/bot/services/__tests__/permission-guard.test.d.ts +2 -0
- package/dist/bot/services/__tests__/permission-guard.test.d.ts.map +1 -0
- package/dist/bot/services/__tests__/permission-guard.test.js +357 -0
- package/dist/bot/services/__tests__/permission-guard.test.js.map +1 -0
- package/dist/bot/services/conversation-manager.d.ts.map +1 -0
- package/dist/bot/services/conversation-manager.js.map +1 -0
- package/dist/bot/services/index.d.ts.map +1 -0
- package/dist/bot/services/index.js.map +1 -0
- package/dist/bot/services/message-classifier.d.ts.map +1 -0
- package/dist/bot/services/message-classifier.js.map +1 -0
- package/dist/bot/services/message-formatter.d.ts.map +1 -0
- package/dist/bot/services/message-formatter.js.map +1 -0
- package/dist/bot/services/permission-guard.d.ts.map +1 -0
- package/dist/bot/services/permission-guard.js.map +1 -0
- package/dist/bot/services/session-logger.d.ts.map +1 -0
- package/dist/bot/services/session-logger.js.map +1 -0
- package/dist/bot/services/token-billing.d.ts.map +1 -0
- package/dist/bot/services/token-billing.js.map +1 -0
- package/dist/bot/services/types.d.ts.map +1 -0
- package/dist/bot/services/types.js.map +1 -0
- package/dist/bot/services/typing-indicator.d.ts.map +1 -0
- package/dist/bot/services/typing-indicator.js.map +1 -0
- package/dist/bot/services/workspace-schema-cache.d.ts.map +1 -0
- package/dist/bot/services/workspace-schema-cache.js.map +1 -0
- package/dist/bot/tool-executor.d.ts.map +1 -0
- package/dist/bot/tool-executor.js.map +1 -0
- package/dist/bot/workspace-overview.d.ts.map +1 -0
- package/dist/bot/workspace-overview.js.map +1 -0
- package/dist/bot-config/constants.d.ts +42 -0
- package/dist/bot-config/constants.d.ts.map +1 -0
- package/dist/bot-config/constants.js +118 -0
- package/dist/bot-config/constants.js.map +1 -0
- package/dist/bot-config/context.d.ts +157 -0
- package/dist/bot-config/context.d.ts.map +1 -0
- package/dist/bot-config/context.js +475 -0
- package/dist/bot-config/context.js.map +1 -0
- package/dist/bot-config/index.d.ts +21 -0
- package/dist/bot-config/index.d.ts.map +1 -0
- package/dist/bot-config/index.js +104 -0
- package/dist/bot-config/index.js.map +1 -0
- package/dist/bot-config/loader.d.ts +28 -0
- package/dist/bot-config/loader.d.ts.map +1 -0
- package/dist/bot-config/loader.js +194 -0
- package/dist/bot-config/loader.js.map +1 -0
- package/dist/bot-config/persistence.d.ts +68 -0
- package/dist/bot-config/persistence.d.ts.map +1 -0
- package/dist/bot-config/persistence.js +261 -0
- package/dist/bot-config/persistence.js.map +1 -0
- package/dist/bot-config/state.d.ts +56 -0
- package/dist/bot-config/state.d.ts.map +1 -0
- package/dist/bot-config/state.js +197 -0
- package/dist/bot-config/state.js.map +1 -0
- package/dist/bot-config/tools.d.ts +28 -0
- package/dist/bot-config/tools.d.ts.map +1 -0
- package/dist/bot-config/tools.js +279 -0
- package/dist/bot-config/tools.js.map +1 -0
- package/dist/bot-config/types.d.ts +45 -0
- package/dist/bot-config/types.d.ts.map +1 -0
- package/dist/bot-config/types.js +9 -0
- package/dist/bot-config/types.js.map +1 -0
- package/dist/bot-config/webhooks.d.ts +27 -0
- package/dist/bot-config/webhooks.d.ts.map +1 -0
- package/dist/bot-config/webhooks.js +212 -0
- package/dist/bot-config/webhooks.js.map +1 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/agents/base.d.ts +207 -0
- package/dist/client/agents/base.d.ts.map +1 -0
- package/dist/client/agents/base.js +744 -0
- package/dist/client/agents/base.js.map +1 -0
- package/dist/client/agents/definitions.d.ts +53 -0
- package/dist/client/agents/definitions.d.ts.map +1 -0
- package/dist/client/agents/definitions.js +263 -0
- package/dist/client/agents/definitions.js.map +1 -0
- package/dist/client/agents/orchestrator.d.ts +141 -0
- package/dist/client/agents/orchestrator.d.ts.map +1 -0
- package/dist/client/agents/orchestrator.js +1062 -0
- package/dist/client/agents/orchestrator.js.map +1 -0
- package/dist/client/agents/specialist.d.ts +86 -0
- package/dist/client/agents/specialist.d.ts.map +1 -0
- package/dist/client/agents/specialist.js +340 -0
- package/dist/client/agents/specialist.js.map +1 -0
- package/dist/client/bot-entrypoint.d.ts +7 -0
- package/dist/client/bot-entrypoint.d.ts.map +1 -0
- package/dist/client/bot-entrypoint.js +103 -0
- package/dist/client/bot-entrypoint.js.map +1 -0
- package/dist/client/bot-manager.d.ts +44 -0
- package/dist/client/bot-manager.d.ts.map +1 -0
- package/dist/client/bot-manager.js +173 -0
- package/dist/client/bot-manager.js.map +1 -0
- package/dist/client/bot-runner.d.ts +35 -0
- package/dist/client/bot-runner.d.ts.map +1 -0
- package/dist/client/bot-runner.js +188 -0
- package/dist/client/bot-runner.js.map +1 -0
- package/dist/client/chat-agent-daemon.d.ts +464 -0
- package/dist/client/chat-agent-daemon.d.ts.map +1 -0
- package/dist/client/chat-agent-daemon.js +1774 -0
- package/dist/client/chat-agent-daemon.js.map +1 -0
- package/dist/client/daemon-factory.d.ts +106 -0
- package/dist/client/daemon-factory.d.ts.map +1 -0
- package/dist/client/daemon-factory.js +301 -0
- package/dist/client/daemon-factory.js.map +1 -0
- package/dist/client/factory.d.ts +111 -0
- package/dist/client/factory.d.ts.map +1 -0
- package/dist/client/factory.js +314 -0
- package/dist/client/factory.js.map +1 -0
- package/dist/client/index.d.ts +17 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +38 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/multi-bot-manager.d.ts +42 -0
- package/dist/client/multi-bot-manager.d.ts.map +1 -0
- package/dist/client/multi-bot-manager.js +161 -0
- package/dist/client/multi-bot-manager.js.map +1 -0
- package/dist/client/orchestrator-daemon.d.ts +87 -0
- package/dist/client/orchestrator-daemon.d.ts.map +1 -0
- package/dist/client/orchestrator-daemon.js +444 -0
- package/dist/client/orchestrator-daemon.js.map +1 -0
- package/dist/client/server.d.ts +8 -0
- package/dist/client/server.d.ts.map +1 -0
- package/dist/client/server.js +251 -0
- package/dist/client/server.js.map +1 -0
- package/dist/client/services/agent-registry.d.ts +108 -0
- package/dist/client/services/agent-registry.d.ts.map +1 -0
- package/dist/client/services/agent-registry.js +630 -0
- package/dist/client/services/agent-registry.js.map +1 -0
- package/dist/client/services/conversation-manager.d.ts +50 -0
- package/dist/client/services/conversation-manager.d.ts.map +1 -0
- package/dist/client/services/conversation-manager.js +136 -0
- package/dist/client/services/conversation-manager.js.map +1 -0
- package/dist/client/services/mcp-client.d.ts +48 -0
- package/dist/client/services/mcp-client.d.ts.map +1 -0
- package/dist/client/services/mcp-client.js +105 -0
- package/dist/client/services/mcp-client.js.map +1 -0
- package/dist/client/services/message-classifier.d.ts +37 -0
- package/dist/client/services/message-classifier.d.ts.map +1 -0
- package/dist/client/services/message-classifier.js +187 -0
- package/dist/client/services/message-classifier.js.map +1 -0
- package/dist/client/services/message-formatter.d.ts +84 -0
- package/dist/client/services/message-formatter.d.ts.map +1 -0
- package/dist/client/services/message-formatter.js +353 -0
- package/dist/client/services/message-formatter.js.map +1 -0
- package/dist/client/services/session-logger.d.ts +106 -0
- package/dist/client/services/session-logger.d.ts.map +1 -0
- package/dist/client/services/session-logger.js +446 -0
- package/dist/client/services/session-logger.js.map +1 -0
- package/dist/client/services/tool-executor.d.ts +41 -0
- package/dist/client/services/tool-executor.d.ts.map +1 -0
- package/dist/client/services/tool-executor.js +169 -0
- package/dist/client/services/tool-executor.js.map +1 -0
- package/dist/client/services/workspace-schema-cache.d.ts +149 -0
- package/dist/client/services/workspace-schema-cache.d.ts.map +1 -0
- package/dist/client/services/workspace-schema-cache.js +732 -0
- package/dist/client/services/workspace-schema-cache.js.map +1 -0
- package/dist/client/specialist-daemon.d.ts +77 -0
- package/dist/client/specialist-daemon.d.ts.map +1 -0
- package/dist/client/specialist-daemon.js +197 -0
- package/dist/client/specialist-daemon.js.map +1 -0
- package/dist/client/specialists.d.ts +53 -0
- package/dist/client/specialists.d.ts.map +1 -0
- package/dist/client/specialists.js +178 -0
- package/dist/client/specialists.js.map +1 -0
- package/dist/client/tool-schema-loader.d.ts +62 -0
- package/dist/client/tool-schema-loader.d.ts.map +1 -0
- package/dist/client/tool-schema-loader.js +232 -0
- package/dist/client/tool-schema-loader.js.map +1 -0
- package/dist/client/types.d.ts +327 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +121 -0
- package/dist/client/types.js.map +1 -0
- package/dist/commands/seed-config.d.ts +9 -0
- package/dist/commands/seed-config.d.ts.map +1 -0
- package/dist/commands/seed-config.js +392 -0
- package/dist/commands/seed-config.js.map +1 -0
- package/dist/commands/setup.d.ts +11 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +320 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js.map +1 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js.map +1 -0
- package/dist/lib/discussion-lock.d.ts.map +1 -0
- package/dist/lib/discussion-lock.js.map +1 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/request-logger.d.ts.map +1 -0
- package/dist/lib/request-logger.js.map +1 -0
- package/dist/mcp/UserContextCache.d.ts.map +1 -0
- package/dist/mcp/UserContextCache.js.map +1 -0
- package/dist/mcp/auth.d.ts.map +1 -0
- package/dist/mcp/auth.js.map +1 -0
- package/dist/mcp/hailer-clients.d.ts.map +1 -0
- package/dist/mcp/hailer-clients.js.map +1 -0
- package/dist/mcp/session-store.d.ts.map +1 -0
- package/dist/mcp/session-store.js.map +1 -0
- package/dist/mcp/signal-handler.d.ts.map +1 -0
- package/dist/mcp/signal-handler.js.map +1 -0
- package/dist/mcp/tool-registry.d.ts.map +1 -0
- package/dist/mcp/tool-registry.js.map +1 -0
- package/dist/mcp/tools/__tests__/discussion-forward.test.d.ts +2 -0
- package/dist/mcp/tools/__tests__/discussion-forward.test.d.ts.map +1 -0
- package/dist/mcp/tools/__tests__/discussion-forward.test.js +218 -0
- package/dist/mcp/tools/__tests__/discussion-forward.test.js.map +1 -0
- package/dist/mcp/tools/activity.d.ts.map +1 -0
- package/dist/mcp/tools/activity.js.map +1 -0
- package/dist/mcp/tools/app-core.d.ts.map +1 -0
- package/dist/mcp/tools/app-core.js.map +1 -0
- package/dist/mcp/tools/app-marketplace.d.ts.map +1 -0
- package/dist/mcp/tools/app-marketplace.js.map +1 -0
- package/dist/mcp/tools/app-member.d.ts.map +1 -0
- package/dist/mcp/tools/app-member.js.map +1 -0
- package/dist/mcp/tools/app-scaffold.d.ts.map +1 -0
- package/dist/mcp/tools/app-scaffold.js.map +1 -0
- package/dist/mcp/tools/app.d.ts.map +1 -0
- package/dist/mcp/tools/app.js.map +1 -0
- package/dist/mcp/tools/bot-config/constants.d.ts.map +1 -0
- package/dist/mcp/tools/bot-config/constants.js.map +1 -0
- package/dist/mcp/tools/bot-config/core.d.ts.map +1 -0
- package/dist/mcp/tools/bot-config/core.js.map +1 -0
- package/dist/mcp/tools/bot-config/index.d.ts.map +1 -0
- package/dist/mcp/tools/bot-config/index.js.map +1 -0
- package/dist/mcp/tools/bot-config/tools.d.ts.map +1 -0
- package/dist/mcp/tools/bot-config/tools.js.map +1 -0
- package/dist/mcp/tools/bot-config/types.d.ts.map +1 -0
- package/dist/mcp/tools/bot-config/types.js.map +1 -0
- package/dist/mcp/tools/bug-fixer-tools.d.ts.map +1 -0
- package/dist/mcp/tools/bug-fixer-tools.js.map +1 -0
- package/dist/mcp/tools/company.d.ts.map +1 -0
- package/dist/mcp/tools/company.js.map +1 -0
- package/dist/mcp/tools/discussion.d.ts.map +1 -0
- package/dist/mcp/tools/discussion.js.map +1 -0
- package/dist/mcp/tools/document.d.ts.map +1 -0
- package/dist/mcp/tools/document.js.map +1 -0
- package/dist/mcp/tools/file.d.ts.map +1 -0
- package/dist/mcp/tools/file.js.map +1 -0
- package/dist/mcp/tools/insight.d.ts.map +1 -0
- package/dist/mcp/tools/insight.js.map +1 -0
- package/dist/mcp/tools/investigate.d.ts.map +1 -0
- package/dist/mcp/tools/investigate.js.map +1 -0
- package/dist/mcp/tools/user.d.ts.map +1 -0
- package/dist/mcp/tools/user.js.map +1 -0
- package/dist/mcp/tools/workflow-permissions.d.ts.map +1 -0
- package/dist/mcp/tools/workflow-permissions.js.map +1 -0
- package/dist/mcp/tools/workflow.d.ts.map +1 -0
- package/dist/mcp/tools/workflow.js.map +1 -0
- package/dist/mcp/utils/api-errors.d.ts.map +1 -0
- package/dist/mcp/utils/api-errors.js.map +1 -0
- package/dist/mcp/utils/data-transformers.d.ts.map +1 -0
- package/dist/mcp/utils/data-transformers.js.map +1 -0
- package/dist/mcp/utils/file-upload.d.ts.map +1 -0
- package/dist/mcp/utils/file-upload.js.map +1 -0
- package/dist/mcp/utils/hailer-api-client.d.ts.map +1 -0
- package/dist/mcp/utils/hailer-api-client.js.map +1 -0
- package/dist/mcp/utils/index.d.ts.map +1 -0
- package/dist/mcp/utils/index.js.map +1 -0
- package/dist/mcp/utils/logger.d.ts.map +1 -0
- package/dist/mcp/utils/logger.js.map +1 -0
- package/dist/mcp/utils/pagination.d.ts.map +1 -0
- package/dist/mcp/utils/pagination.js.map +1 -0
- package/dist/mcp/utils/response-builder.d.ts.map +1 -0
- package/dist/mcp/utils/response-builder.js.map +1 -0
- package/dist/mcp/utils/role-utils.d.ts.map +1 -0
- package/dist/mcp/utils/role-utils.js.map +1 -0
- package/dist/mcp/utils/tool-helpers.d.ts.map +1 -0
- package/dist/mcp/utils/tool-helpers.js.map +1 -0
- package/dist/mcp/utils/types.d.ts.map +1 -0
- package/dist/mcp/utils/types.js.map +1 -0
- package/dist/mcp/webhook-handler.d.ts.map +1 -0
- package/dist/mcp/webhook-handler.js.map +1 -0
- package/dist/mcp/workspace-cache.d.ts.map +1 -0
- package/dist/mcp/workspace-cache.js.map +1 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/modules/bug-reports/bug-config.d.ts +25 -0
- package/dist/modules/bug-reports/bug-config.d.ts.map +1 -0
- package/dist/modules/bug-reports/bug-config.js +187 -0
- package/dist/modules/bug-reports/bug-config.js.map +1 -0
- package/dist/modules/bug-reports/bug-monitor.d.ts +108 -0
- package/dist/modules/bug-reports/bug-monitor.d.ts.map +1 -0
- package/dist/modules/bug-reports/bug-monitor.js +510 -0
- package/dist/modules/bug-reports/bug-monitor.js.map +1 -0
- package/dist/modules/bug-reports/giuseppe-agent.d.ts +58 -0
- package/dist/modules/bug-reports/giuseppe-agent.d.ts.map +1 -0
- package/dist/modules/bug-reports/giuseppe-agent.js +467 -0
- package/dist/modules/bug-reports/giuseppe-agent.js.map +1 -0
- package/dist/modules/bug-reports/giuseppe-ai.d.ts +83 -0
- package/dist/modules/bug-reports/giuseppe-ai.d.ts.map +1 -0
- package/dist/modules/bug-reports/giuseppe-ai.js +466 -0
- package/dist/modules/bug-reports/giuseppe-ai.js.map +1 -0
- package/dist/modules/bug-reports/giuseppe-bot.d.ts +110 -0
- package/dist/modules/bug-reports/giuseppe-bot.d.ts.map +1 -0
- package/dist/modules/bug-reports/giuseppe-bot.js +804 -0
- package/dist/modules/bug-reports/giuseppe-bot.js.map +1 -0
- package/dist/modules/bug-reports/giuseppe-daemon.d.ts +80 -0
- package/dist/modules/bug-reports/giuseppe-daemon.d.ts.map +1 -0
- package/dist/modules/bug-reports/giuseppe-daemon.js +617 -0
- package/dist/modules/bug-reports/giuseppe-daemon.js.map +1 -0
- package/dist/modules/bug-reports/giuseppe-files.d.ts +64 -0
- package/dist/modules/bug-reports/giuseppe-files.d.ts.map +1 -0
- package/dist/modules/bug-reports/giuseppe-files.js +375 -0
- package/dist/modules/bug-reports/giuseppe-files.js.map +1 -0
- package/dist/modules/bug-reports/giuseppe-git.d.ts +48 -0
- package/dist/modules/bug-reports/giuseppe-git.d.ts.map +1 -0
- package/dist/modules/bug-reports/giuseppe-git.js +298 -0
- package/dist/modules/bug-reports/giuseppe-git.js.map +1 -0
- package/dist/modules/bug-reports/giuseppe-lsp.d.ts +113 -0
- package/dist/modules/bug-reports/giuseppe-lsp.d.ts.map +1 -0
- package/dist/modules/bug-reports/giuseppe-lsp.js +485 -0
- package/dist/modules/bug-reports/giuseppe-lsp.js.map +1 -0
- package/dist/modules/bug-reports/giuseppe-prompt.d.ts +5 -0
- package/dist/modules/bug-reports/giuseppe-prompt.d.ts.map +1 -0
- package/dist/modules/bug-reports/giuseppe-prompt.js +94 -0
- package/dist/modules/bug-reports/giuseppe-prompt.js.map +1 -0
- package/dist/modules/bug-reports/index.d.ts +77 -0
- package/dist/modules/bug-reports/index.d.ts.map +1 -0
- package/dist/modules/bug-reports/index.js +215 -0
- package/dist/modules/bug-reports/index.js.map +1 -0
- package/dist/modules/bug-reports/pending-classification-registry.d.ts +28 -0
- package/dist/modules/bug-reports/pending-classification-registry.d.ts.map +1 -0
- package/dist/modules/bug-reports/pending-classification-registry.js +50 -0
- package/dist/modules/bug-reports/pending-classification-registry.js.map +1 -0
- package/dist/modules/bug-reports/pending-fix-registry.d.ts +30 -0
- package/dist/modules/bug-reports/pending-fix-registry.d.ts.map +1 -0
- package/dist/modules/bug-reports/pending-fix-registry.js +42 -0
- package/dist/modules/bug-reports/pending-fix-registry.js.map +1 -0
- package/dist/modules/bug-reports/pending-registry.d.ts +27 -0
- package/dist/modules/bug-reports/pending-registry.d.ts.map +1 -0
- package/dist/modules/bug-reports/pending-registry.js +49 -0
- package/dist/modules/bug-reports/pending-registry.js.map +1 -0
- package/dist/modules/bug-reports/types.d.ts +123 -0
- package/dist/modules/bug-reports/types.d.ts.map +1 -0
- package/dist/modules/bug-reports/types.js +9 -0
- package/dist/modules/bug-reports/types.js.map +1 -0
- package/dist/plugins/bug-fixer/index.d.ts.map +1 -0
- package/dist/plugins/bug-fixer/index.js.map +1 -0
- package/dist/plugins/bug-fixer/tools.d.ts.map +1 -0
- package/dist/plugins/bug-fixer/tools.js.map +1 -0
- package/dist/plugins/vipunen/__tests__/tools.test.d.ts +10 -0
- package/dist/plugins/vipunen/__tests__/tools.test.d.ts.map +1 -0
- package/dist/plugins/vipunen/__tests__/tools.test.js +646 -0
- package/dist/plugins/vipunen/__tests__/tools.test.js.map +1 -0
- package/dist/plugins/vipunen/client.d.ts.map +1 -0
- package/dist/plugins/vipunen/client.js.map +1 -0
- package/dist/plugins/vipunen/index.d.ts.map +1 -0
- package/dist/plugins/vipunen/index.js.map +1 -0
- package/dist/plugins/vipunen/tools.d.ts.map +1 -0
- package/dist/plugins/vipunen/tools.js.map +1 -0
- package/dist/routes/agents.d.ts +44 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +311 -0
- package/dist/routes/agents.js.map +1 -0
- package/dist/services/agent-credential-store.d.ts +73 -0
- package/dist/services/agent-credential-store.d.ts.map +1 -0
- package/dist/services/agent-credential-store.js +212 -0
- package/dist/services/agent-credential-store.js.map +1 -0
- package/dist/stdio-server.d.ts.map +1 -0
- package/dist/stdio-server.js.map +1 -0
- package/dist/workspace/context.d.ts +148 -0
- package/dist/workspace/context.d.ts.map +1 -0
- package/dist/workspace/context.js +339 -0
- package/dist/workspace/context.js.map +1 -0
- package/dist/workspace/credentials.d.ts +55 -0
- package/dist/workspace/credentials.d.ts.map +1 -0
- package/dist/workspace/credentials.js +239 -0
- package/dist/workspace/credentials.js.map +1 -0
- package/dist/workspace/index.d.ts +21 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +45 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/loader.d.ts +27 -0
- package/dist/workspace/loader.d.ts.map +1 -0
- package/dist/workspace/loader.js +222 -0
- package/dist/workspace/loader.js.map +1 -0
- package/dist/workspace/schema.d.ts +37 -0
- package/dist/workspace/schema.d.ts.map +1 -0
- package/dist/workspace/schema.js +192 -0
- package/dist/workspace/schema.js.map +1 -0
- package/package.json +13 -1
- package/.claude/.context-watchdog.json +0 -1
- package/.claude/.session-checked +0 -1
- package/test-billing-server.js +0 -136
|
@@ -0,0 +1,1122 @@
|
|
|
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 typing_indicator_1 = require("./services/typing-indicator");
|
|
33
|
+
const token_billing_1 = require("./services/token-billing");
|
|
34
|
+
const structured_output_executor_1 = require("./services/structured-output-executor");
|
|
35
|
+
const action_schema_1 = require("./schemas/action-schema");
|
|
36
|
+
const hailer_api_client_1 = require("../../mcp/utils/hailer-api-client");
|
|
37
|
+
const config_1 = require("../../config");
|
|
38
|
+
const bot_config_1 = require("../../bot-config");
|
|
39
|
+
const config_2 = require("../../config");
|
|
40
|
+
class ChatAgentDaemon {
|
|
41
|
+
logger;
|
|
42
|
+
client;
|
|
43
|
+
botClient;
|
|
44
|
+
config;
|
|
45
|
+
toolSchemaLoader = new tool_schema_loader_1.ToolSchemaLoader();
|
|
46
|
+
// Processing state
|
|
47
|
+
isProcessing = false;
|
|
48
|
+
messageQueue = [];
|
|
49
|
+
processedMessageIds = new Set();
|
|
50
|
+
// Tool schemas (loaded once)
|
|
51
|
+
toolIndex = [];
|
|
52
|
+
minimalTools = [];
|
|
53
|
+
// ===== SERVICES =====
|
|
54
|
+
/** Message classifier - handles message extraction and priority classification */
|
|
55
|
+
messageClassifier = null;
|
|
56
|
+
/** Conversation manager - handles per-discussion context and LRU cache */
|
|
57
|
+
conversationManager = null;
|
|
58
|
+
/** MCP client service - handles tool schema loading and execution */
|
|
59
|
+
mcpClient = null;
|
|
60
|
+
/** Tool executor - handles tool execution and write tracking */
|
|
61
|
+
toolExecutor = null;
|
|
62
|
+
/** Agent registration service - handles Agent Directory, Position, Team, etc. */
|
|
63
|
+
registryService = null;
|
|
64
|
+
/** Message formatting service - handles tag resolution and formatting */
|
|
65
|
+
messageFormatter = null;
|
|
66
|
+
/** Session logging service - handles activity session tracking */
|
|
67
|
+
sessionLogger = null;
|
|
68
|
+
/** Workspace schema cache - dynamic workflow/field ID lookup */
|
|
69
|
+
schemaCache = null;
|
|
70
|
+
/** Typing indicator service - handles typing state with auto-refresh */
|
|
71
|
+
typingIndicator = null;
|
|
72
|
+
/** Token billing service - handles real-time token burning per workspace */
|
|
73
|
+
tokenBilling = null;
|
|
74
|
+
/** Structured output executor - handles action-based output instead of native tools */
|
|
75
|
+
structuredOutputExecutor = null;
|
|
76
|
+
/** Current discussion context for tracking */
|
|
77
|
+
currentDiscussionId = null;
|
|
78
|
+
currentLinkedActivityId = null;
|
|
79
|
+
/** Unsubscribe function for messenger.new signals */
|
|
80
|
+
messengerUnsubscribe = null;
|
|
81
|
+
/** Original API key for cleanup - stored at init because botClient.config may change */
|
|
82
|
+
originalApiKey = null;
|
|
83
|
+
constructor(config) {
|
|
84
|
+
this.config = config;
|
|
85
|
+
this.botClient = config.botClient;
|
|
86
|
+
this.logger = (0, logger_1.createLogger)({
|
|
87
|
+
component: "ChatAgentDaemon",
|
|
88
|
+
botId: config.botClient.userId
|
|
89
|
+
});
|
|
90
|
+
this.client = new sdk_1.default({
|
|
91
|
+
apiKey: config.anthropicApiKey,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get the workspace schema cache for dynamic workflow/field ID lookup
|
|
96
|
+
* Exposed for modules that need to share schema discovery (e.g., Bug Fixer)
|
|
97
|
+
*/
|
|
98
|
+
getSchemaCache() {
|
|
99
|
+
return this.schemaCache;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Initialize the daemon - load tools and subscribe to signals
|
|
103
|
+
*/
|
|
104
|
+
async initialize() {
|
|
105
|
+
this.logger.info("Initializing Chat Agent Daemon", {
|
|
106
|
+
botId: this.botClient.userId,
|
|
107
|
+
email: (0, config_2.maskEmail)(this.botClient.config.email),
|
|
108
|
+
});
|
|
109
|
+
// Load tool index once
|
|
110
|
+
const allowedGroups = this.getToolGroups();
|
|
111
|
+
let tools = await this.toolSchemaLoader.loadToolIndex({
|
|
112
|
+
mcpServerUrl: this.config.mcpServerUrl,
|
|
113
|
+
mcpServerApiKey: this.botClient.config.mcpServerApiKey,
|
|
114
|
+
allowedGroups,
|
|
115
|
+
});
|
|
116
|
+
// Filter by whitelist if agent specifies one
|
|
117
|
+
const whitelist = this.getToolWhitelist();
|
|
118
|
+
if (whitelist) {
|
|
119
|
+
tools = tools.filter((t) => whitelist.includes(t.name));
|
|
120
|
+
this.logger.debug("Tools filtered by whitelist", {
|
|
121
|
+
total: tools.length,
|
|
122
|
+
whitelist: whitelist.length
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
this.toolIndex = tools;
|
|
126
|
+
this.minimalTools = this.toolSchemaLoader.toFullToolDefinitions(this.toolIndex);
|
|
127
|
+
this.logger.debug("Tools loaded", { toolCount: this.toolIndex.length });
|
|
128
|
+
// Initialize MCP client service (must be first - other services depend on it)
|
|
129
|
+
this.mcpClient = new mcp_client_1.McpClientService(this.config.mcpServerUrl, this.botClient.config.mcpServerApiKey, this.logger);
|
|
130
|
+
// Get workspace ID early - needed for schema cache and registration
|
|
131
|
+
const workspaceId = this.botClient.workspaceCache?.currentWorkspace?._id || "";
|
|
132
|
+
// Initialize workspace schema cache FIRST (discovers workflows dynamically)
|
|
133
|
+
// This MUST happen before agent registration so we have dynamic workflow IDs
|
|
134
|
+
this.schemaCache = new workspace_schema_cache_1.WorkspaceSchemaCacheService(this.logger, this.mcpClient.callMcpTool.bind(this.mcpClient));
|
|
135
|
+
// Initialize schema for current workspace (may install template if missing)
|
|
136
|
+
if (workspaceId) {
|
|
137
|
+
await this.schemaCache.initializeForWorkspace(workspaceId);
|
|
138
|
+
}
|
|
139
|
+
// Initialize conversation manager
|
|
140
|
+
this.conversationManager = new conversation_manager_1.ConversationManager(100, // maxConversations
|
|
141
|
+
this.config.maxContextMessages || 50, this.client, this.logger);
|
|
142
|
+
// Initialize tool executor (with token billing for cache invalidation)
|
|
143
|
+
this.toolExecutor = new tool_executor_1.ToolExecutor(this.mcpClient, this.logger, this.tokenBilling || undefined);
|
|
144
|
+
// Initialize structured output executor (if enabled)
|
|
145
|
+
if (this.config.useStructuredOutputs) {
|
|
146
|
+
this.structuredOutputExecutor = new structured_output_executor_1.StructuredOutputExecutor(this.mcpClient, this.toolExecutor, this.logger);
|
|
147
|
+
this.logger.info("Structured outputs enabled - saving ~100K tokens per request");
|
|
148
|
+
}
|
|
149
|
+
// Initialize message classifier
|
|
150
|
+
this.messageClassifier = new message_classifier_1.MessageClassifier(this.botClient.userId, this.botClient, this.logger);
|
|
151
|
+
// Initialize typing indicator service
|
|
152
|
+
this.typingIndicator = new typing_indicator_1.TypingIndicatorService(this.botClient, this.logger);
|
|
153
|
+
// Initialize token billing service (if enabled)
|
|
154
|
+
const appConfig = (0, config_1.createApplicationConfig)();
|
|
155
|
+
if (appConfig.tokenBilling.enabled) {
|
|
156
|
+
// Create HailerApiClient from botClient
|
|
157
|
+
const hailerApiClient = this.botClient?.client
|
|
158
|
+
? new hailer_api_client_1.HailerApiClient(this.botClient.client)
|
|
159
|
+
: null;
|
|
160
|
+
this.tokenBilling = new token_billing_1.TokenBillingService(this.logger, hailerApiClient || undefined);
|
|
161
|
+
this.logger.info("Token billing service initialized", {
|
|
162
|
+
hasHailerClient: !!hailerApiClient,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
// Create agent registry service WITH schema cache for dynamic ID lookup
|
|
166
|
+
this.registryService = new agent_registry_1.AgentRegistryService(this.schemaCache, this.logger, this.mcpClient.callMcpTool.bind(this.mcpClient), this.getDefaultTeamId.bind(this));
|
|
167
|
+
// Initialize message formatter service
|
|
168
|
+
this.messageFormatter = new message_formatter_1.MessageFormatterService(this.botClient, this.logger, this.mcpClient.callMcpTool.bind(this.mcpClient));
|
|
169
|
+
// Build agent info from config and abstract methods
|
|
170
|
+
const { firstName, lastName } = this.getAgentName();
|
|
171
|
+
const agentInfo = {
|
|
172
|
+
firstName,
|
|
173
|
+
lastName,
|
|
174
|
+
description: this.getAgentDescription(),
|
|
175
|
+
email: this.botClient.config.email,
|
|
176
|
+
userId: this.botClient.userId,
|
|
177
|
+
};
|
|
178
|
+
// Register agent in workspace (handles deduplication internally)
|
|
179
|
+
this.logger.info("Starting agent registration", { workspaceId });
|
|
180
|
+
await this.registryService.registerAllAgentData(agentInfo, this.getPositionDetails(), this.config.mcpServerUrl, this.toolIndex, workspaceId);
|
|
181
|
+
// Store the API key at initialization for cleanup
|
|
182
|
+
// This is critical because botClient.config.mcpServerApiKey may change during daemon restart
|
|
183
|
+
this.originalApiKey = this.botClient.config.mcpServerApiKey;
|
|
184
|
+
// Subscribe to messenger.new signals using the working signal system (same as BugMonitor)
|
|
185
|
+
this.messengerUnsubscribe = (0, hailer_clients_1.subscribeToSignal)(this.botClient.config.mcpServerApiKey, 'messenger.new', (eventData) => {
|
|
186
|
+
// Convert raw event data to HailerSignal format expected by handleSignal
|
|
187
|
+
const signal = {
|
|
188
|
+
type: 'messenger.new',
|
|
189
|
+
data: eventData,
|
|
190
|
+
timestamp: Date.now(),
|
|
191
|
+
workspaceId: eventData.sid,
|
|
192
|
+
};
|
|
193
|
+
this.handleSignal(signal);
|
|
194
|
+
});
|
|
195
|
+
if (this.messengerUnsubscribe) {
|
|
196
|
+
this.logger.info("Subscribed to messenger.new signals via HailerClientManager");
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
this.logger.warn("Failed to subscribe to messenger.new signals - no client manager found");
|
|
200
|
+
}
|
|
201
|
+
// Initialize session logger service (after registration so we have agentDirectoryId)
|
|
202
|
+
this.sessionLogger = new session_logger_1.SessionLoggerService(this.registryService?.getAgentDirectoryId() ?? null, this.logger, this.mcpClient.callMcpTool.bind(this.mcpClient), this.getDefaultTeamId.bind(this));
|
|
203
|
+
// Pass Anthropic client for conversation summary generation
|
|
204
|
+
this.sessionLogger.setAnthropicClient(this.client);
|
|
205
|
+
// Pass schema cache for dynamic workflow ID lookup
|
|
206
|
+
if (workspaceId && this.schemaCache) {
|
|
207
|
+
this.sessionLogger.setSchemaCache(this.schemaCache, workspaceId);
|
|
208
|
+
}
|
|
209
|
+
// Start idle session check timer (every 30 seconds)
|
|
210
|
+
this.sessionLogger.startIdleCheckTimer(30_000);
|
|
211
|
+
this.logger.info("Chat Agent Daemon initialized and listening", {
|
|
212
|
+
workspaceId,
|
|
213
|
+
agentDirectoryId: this.registryService.getAgentDirectoryId(),
|
|
214
|
+
positionId: this.registryService.getPositionId(),
|
|
215
|
+
teamId: this.registryService.getTeamId(),
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Extract and classify incoming message from signal
|
|
220
|
+
* Can be overridden in subclasses to customize filtering
|
|
221
|
+
*/
|
|
222
|
+
async extractIncomingMessage(signal) {
|
|
223
|
+
return this.messageClassifier.extractIncomingMessage(signal);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Handle incoming signal from Hailer
|
|
227
|
+
*/
|
|
228
|
+
async handleSignal(signal) {
|
|
229
|
+
try {
|
|
230
|
+
// EARLY dedup check using raw signal data (before async operation)
|
|
231
|
+
// This prevents race condition where two signals arrive simultaneously
|
|
232
|
+
const signalData = signal.data;
|
|
233
|
+
const rawMsgId = signalData.msg_id;
|
|
234
|
+
if (rawMsgId) {
|
|
235
|
+
if (this.processedMessageIds.has(rawMsgId)) {
|
|
236
|
+
this.logger.debug("Early dedup: skipping duplicate signal", { rawMsgId });
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
// Add immediately to prevent race condition
|
|
240
|
+
this.processedMessageIds.add(rawMsgId);
|
|
241
|
+
}
|
|
242
|
+
const message = await this.extractIncomingMessage(signal);
|
|
243
|
+
if (!message) {
|
|
244
|
+
// Remove from set if extraction failed (message was invalid)
|
|
245
|
+
if (rawMsgId)
|
|
246
|
+
this.processedMessageIds.delete(rawMsgId);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
// Clean up old IDs (keep last 500)
|
|
250
|
+
if (this.processedMessageIds.size > 500) {
|
|
251
|
+
const ids = Array.from(this.processedMessageIds);
|
|
252
|
+
this.processedMessageIds = new Set(ids.slice(-250));
|
|
253
|
+
}
|
|
254
|
+
this.logger.info("Incoming message", {
|
|
255
|
+
from: message.senderName,
|
|
256
|
+
discussion: message.discussionId,
|
|
257
|
+
priority: message.priority,
|
|
258
|
+
reason: message.priorityReason,
|
|
259
|
+
preview: message.content.substring(0, 50),
|
|
260
|
+
});
|
|
261
|
+
// Queue the message
|
|
262
|
+
this.messageQueue.push(message);
|
|
263
|
+
// Process if not already processing
|
|
264
|
+
if (!this.isProcessing) {
|
|
265
|
+
await this.processQueue();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
this.logger.error("Failed to handle signal", error);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Process queued messages through the LLM
|
|
274
|
+
* Note: Uses flag-first pattern to prevent race conditions
|
|
275
|
+
*/
|
|
276
|
+
async processQueue() {
|
|
277
|
+
// Set flag FIRST to prevent race condition (multiple async calls)
|
|
278
|
+
if (this.isProcessing)
|
|
279
|
+
return;
|
|
280
|
+
this.isProcessing = true;
|
|
281
|
+
// Now check queue (after claiming the lock)
|
|
282
|
+
if (this.messageQueue.length === 0) {
|
|
283
|
+
this.isProcessing = false;
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
// Sort by priority (high first) then by timestamp
|
|
288
|
+
this.messageQueue.sort((a, b) => {
|
|
289
|
+
const priorityOrder = { high: 0, normal: 1, low: 2 };
|
|
290
|
+
if (priorityOrder[a.priority] !== priorityOrder[b.priority]) {
|
|
291
|
+
return priorityOrder[a.priority] - priorityOrder[b.priority];
|
|
292
|
+
}
|
|
293
|
+
return a.timestamp - b.timestamp;
|
|
294
|
+
});
|
|
295
|
+
// Process one message at a time for now
|
|
296
|
+
while (this.messageQueue.length > 0) {
|
|
297
|
+
const message = this.messageQueue.shift();
|
|
298
|
+
await this.processMessage(message);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
finally {
|
|
302
|
+
this.isProcessing = false;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Process a single message through the persistent LLM conversation
|
|
307
|
+
*/
|
|
308
|
+
async processMessage(message) {
|
|
309
|
+
// Check if bot is still enabled (may have been disabled via AI Hub)
|
|
310
|
+
const botState = (0, bot_config_1.getBotState)();
|
|
311
|
+
if (!botState[this.config.botClient.userId]) {
|
|
312
|
+
this.logger.info("Bot disabled, skipping message", {
|
|
313
|
+
discussion: message.discussionId,
|
|
314
|
+
from: message.senderName,
|
|
315
|
+
});
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const startTime = Date.now();
|
|
319
|
+
// Update current context for session tracking
|
|
320
|
+
this.currentDiscussionId = message.discussionId;
|
|
321
|
+
this.currentLinkedActivityId = message.linkedActivityId || null;
|
|
322
|
+
// Multi-tenant: Initialize schema cache for this workspace on-demand
|
|
323
|
+
// Each workspace has its own workflow IDs - must be cached before processing
|
|
324
|
+
if (this.schemaCache && message.workspaceId) {
|
|
325
|
+
const schemas = this.schemaCache.getSchemas(message.workspaceId);
|
|
326
|
+
if (!schemas?.initialized) {
|
|
327
|
+
this.logger.info("Initializing schema cache for workspace", { workspaceId: message.workspaceId });
|
|
328
|
+
await this.schemaCache.initializeForWorkspace(message.workspaceId);
|
|
329
|
+
// Update session logger with workspace-specific schema
|
|
330
|
+
if (this.sessionLogger) {
|
|
331
|
+
this.sessionLogger.setSchemaCache(this.schemaCache, message.workspaceId);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
// Start typing indicator with auto-refresh
|
|
336
|
+
this.typingIndicator?.start(message.discussionId);
|
|
337
|
+
// Get or create activity session
|
|
338
|
+
const session = this.sessionLogger.getOrCreateActivitySession(message);
|
|
339
|
+
session.lastActivityTime = Date.now();
|
|
340
|
+
session.metrics.messagesProcessed++;
|
|
341
|
+
// Check balance before every message (caching prevents API spam)
|
|
342
|
+
if (this.tokenBilling && message.workspaceId) {
|
|
343
|
+
const balance = await this.tokenBilling.checkBalance(message.workspaceId);
|
|
344
|
+
if (!balance.hasBalance) {
|
|
345
|
+
this.logger.info("Session rejected - no token balance", {
|
|
346
|
+
workspaceId: message.workspaceId,
|
|
347
|
+
balance: balance.balance,
|
|
348
|
+
discussion: message.discussionId,
|
|
349
|
+
});
|
|
350
|
+
this.typingIndicator?.stop();
|
|
351
|
+
await this.sendInsufficientBalanceMessage(message.discussionId);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// Add user message to conversation log (compact version)
|
|
356
|
+
const userSnippet = message.content.length > 100
|
|
357
|
+
? message.content.substring(0, 100) + "..."
|
|
358
|
+
: message.content;
|
|
359
|
+
session.conversation.push(`${message.senderName}: ${userSnippet}`);
|
|
360
|
+
// Format incoming message for LLM
|
|
361
|
+
let incomingContent = this.formatIncomingMessage(message);
|
|
362
|
+
// Get conversation for THIS discussion (isolated context)
|
|
363
|
+
const conversation = this.conversationManager.getConversation(message.discussionId);
|
|
364
|
+
// Track conversation length BEFORE this message for proper cleanup on IGNORE
|
|
365
|
+
const conversationLengthBeforeMessage = conversation.length;
|
|
366
|
+
// COLD START: If conversation is empty, try to load memory context from Hailer
|
|
367
|
+
if (conversation.length === 0) {
|
|
368
|
+
const memoryContext = await this.loadMemoryContext(message.discussionId, message.workspaceId);
|
|
369
|
+
if (memoryContext) {
|
|
370
|
+
// Prepend memory context to the user message
|
|
371
|
+
incomingContent = `${memoryContext}\n\n[Current message]\n${incomingContent}`;
|
|
372
|
+
this.logger.debug("Injected memory context on cold start", {
|
|
373
|
+
discussion: message.discussionId.substring(0, 8),
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
// Append to conversation
|
|
378
|
+
conversation.push({
|
|
379
|
+
role: "user",
|
|
380
|
+
content: incomingContent,
|
|
381
|
+
});
|
|
382
|
+
// Check context size and summarize if needed
|
|
383
|
+
await this.conversationManager.manageContextSize(message.discussionId);
|
|
384
|
+
try {
|
|
385
|
+
// Call LLM with this discussion's conversation (with caching enabled)
|
|
386
|
+
const cachedConversation = this.conversationManager.prepareForCaching(conversation);
|
|
387
|
+
// Use structured outputs if enabled (saves ~100K tokens per request)
|
|
388
|
+
let response;
|
|
389
|
+
if (this.config.useStructuredOutputs) {
|
|
390
|
+
response = await this.callLlmWithStructuredOutputs(cachedConversation);
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
// Log sizing for comparison with structured outputs
|
|
394
|
+
const systemPrompt = this.getCachedSystemPrompt();
|
|
395
|
+
const tools = this.getTools();
|
|
396
|
+
const systemCharCount = systemPrompt.reduce((acc, block) => acc + (block.text?.length || 0), 0);
|
|
397
|
+
const toolsCharCount = JSON.stringify(tools).length;
|
|
398
|
+
const messagesCharCount = JSON.stringify(cachedConversation).length;
|
|
399
|
+
this.logger.info("Native tools request sizing", {
|
|
400
|
+
systemCharCount,
|
|
401
|
+
toolsCharCount,
|
|
402
|
+
messagesCharCount,
|
|
403
|
+
estimatedTokens: Math.round((systemCharCount + toolsCharCount + messagesCharCount) / 4),
|
|
404
|
+
toolCount: tools.length,
|
|
405
|
+
});
|
|
406
|
+
response = await this.client.messages.create({
|
|
407
|
+
model: this.config.model || "claude-haiku-4-5-20251001",
|
|
408
|
+
max_tokens: 2000,
|
|
409
|
+
system: systemPrompt,
|
|
410
|
+
messages: cachedConversation,
|
|
411
|
+
tools,
|
|
412
|
+
});
|
|
413
|
+
// Log actual usage
|
|
414
|
+
if (response.usage) {
|
|
415
|
+
const usage = response.usage;
|
|
416
|
+
this.logger.info("Native tools response usage", {
|
|
417
|
+
inputTokens: usage.input_tokens,
|
|
418
|
+
outputTokens: usage.output_tokens,
|
|
419
|
+
cacheCreationTokens: usage.cache_creation_input_tokens || 0,
|
|
420
|
+
cacheReadTokens: usage.cache_read_input_tokens || 0,
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
// Track token usage in the activity session (including cache stats for billing)
|
|
425
|
+
if (response.usage) {
|
|
426
|
+
const inputTokens = response.usage.input_tokens;
|
|
427
|
+
const outputTokens = response.usage.output_tokens;
|
|
428
|
+
const cacheCreationTokens = response.usage.cache_creation_input_tokens || 0;
|
|
429
|
+
const cacheReadTokens = response.usage.cache_read_input_tokens || 0;
|
|
430
|
+
session.metrics.inputTokens += inputTokens;
|
|
431
|
+
session.metrics.outputTokens += outputTokens;
|
|
432
|
+
session.metrics.cacheCreationTokens += cacheCreationTokens;
|
|
433
|
+
session.metrics.cacheReadTokens += cacheReadTokens;
|
|
434
|
+
session.metrics.apiCalls += 1;
|
|
435
|
+
// Burn tokens real-time (fire-and-forget)
|
|
436
|
+
if (this.tokenBilling && session.workspaceId) {
|
|
437
|
+
const cost = this.tokenBilling.calculateCost(inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens);
|
|
438
|
+
this.tokenBilling.burnTokens({
|
|
439
|
+
workspaceId: session.workspaceId,
|
|
440
|
+
inputTokens,
|
|
441
|
+
outputTokens,
|
|
442
|
+
cacheCreationTokens,
|
|
443
|
+
cacheReadTokens,
|
|
444
|
+
costUsd: cost,
|
|
445
|
+
sessionId: session.discussionId,
|
|
446
|
+
activityId: session.activityId,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
// Handle response (pass original length for proper cleanup on IGNORE)
|
|
451
|
+
if (this.config.useStructuredOutputs) {
|
|
452
|
+
await this.handleStructuredResponse(response, message, conversationLengthBeforeMessage);
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
await this.handleLlmResponse(response, message, conversationLengthBeforeMessage);
|
|
456
|
+
}
|
|
457
|
+
const duration = Date.now() - startTime;
|
|
458
|
+
this.logger.info("Message processed", {
|
|
459
|
+
discussion: message.discussionId,
|
|
460
|
+
duration,
|
|
461
|
+
stopReason: response.stop_reason,
|
|
462
|
+
sessionActivity: session.activityName,
|
|
463
|
+
});
|
|
464
|
+
// Update last activity time (idle checker will flush when needed)
|
|
465
|
+
session.lastActivityTime = Date.now();
|
|
466
|
+
}
|
|
467
|
+
catch (error) {
|
|
468
|
+
this.logger.error("LLM processing failed", error);
|
|
469
|
+
// Stop typing indicator on error
|
|
470
|
+
this.typingIndicator?.stop();
|
|
471
|
+
// On error, remove the message from conversation to avoid poisoning context
|
|
472
|
+
if (conversation.length > 0) {
|
|
473
|
+
conversation.pop();
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Format incoming message for LLM consumption
|
|
479
|
+
*/
|
|
480
|
+
formatIncomingMessage(message) {
|
|
481
|
+
const priorityTag = message.priority === "high" ? " priority=\"high\"" : "";
|
|
482
|
+
const reasonAttr = message.priority === "high" ? ` reason="${message.priorityReason}"` : "";
|
|
483
|
+
const activityAttr = message.linkedActivityId ? ` activity_id="${message.linkedActivityId}"` : "";
|
|
484
|
+
// Build file attachment info if present
|
|
485
|
+
let fileInfo = "";
|
|
486
|
+
if (message.fileAttachments && message.fileAttachments.length > 0) {
|
|
487
|
+
const fileList = message.fileAttachments.map(f => ` - ${f.filename} (ID: ${f.fileId}${f.size ? `, ${Math.round(f.size / 1024)}KB` : ""}${f.mime ? `, ${f.mime}` : ""})`).join("\n");
|
|
488
|
+
fileInfo = `\n[File attached: ${message.fileAttachments.length} file(s) - IDs: ${message.fileAttachments.map(f => f.fileId).join(", ")}]\n${fileList}\n\nUse download_file tool with fileId to read file contents.`;
|
|
489
|
+
}
|
|
490
|
+
return `<incoming discussion="${message.discussionId}"${activityAttr} from="${message.senderName}" user_id="${message.senderId}" timestamp="${new Date(message.timestamp).toISOString()}"${priorityTag}${reasonAttr}>
|
|
491
|
+
${message.content}${fileInfo}
|
|
492
|
+
</incoming>`;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Load memory context on cold start
|
|
496
|
+
* Uses discussion message history (FREE) instead of SESSION_LOG (costs tokens)
|
|
497
|
+
*/
|
|
498
|
+
async loadMemoryContext(discussionId, _workspaceId) {
|
|
499
|
+
if (!this.mcpClient) {
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
try {
|
|
503
|
+
// Fetch last 15 messages from discussion (FREE - read operation)
|
|
504
|
+
const result = await this.mcpClient.callMcpTool("fetch_discussion_messages", {
|
|
505
|
+
discussionId,
|
|
506
|
+
limit: 15,
|
|
507
|
+
});
|
|
508
|
+
const text = result?.content?.[0]?.text;
|
|
509
|
+
if (!text || text.includes("No messages found")) {
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
// Extract just the message content, skip the header/metadata
|
|
513
|
+
const messagesMatch = text.match(/📨 \*\*MESSAGES\*\*[\s\S]*/);
|
|
514
|
+
if (!messagesMatch) {
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
return `[Previous conversation in this discussion]\n${messagesMatch[0]}`;
|
|
518
|
+
}
|
|
519
|
+
catch (error) {
|
|
520
|
+
this.logger.debug("Failed to load memory context from discussion", {
|
|
521
|
+
discussion: discussionId.substring(0, 8),
|
|
522
|
+
error: error instanceof Error ? error.message : String(error),
|
|
523
|
+
});
|
|
524
|
+
return null;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Execute tool calls and continue the conversation
|
|
529
|
+
* Simple passthrough - just execute tools and return results to LLM
|
|
530
|
+
* @param conversationLengthBeforeMessage - passed through for proper IGNORE cleanup
|
|
531
|
+
*/
|
|
532
|
+
async executeToolsAndContinue(toolUseBlocks, originalMessage, conversationLengthBeforeMessage) {
|
|
533
|
+
// Get current activity session
|
|
534
|
+
const sessionKey = this.currentLinkedActivityId || this.currentDiscussionId || "default";
|
|
535
|
+
const session = this.sessionLogger.getSession(sessionKey);
|
|
536
|
+
// Store the user's request that triggered these tool calls (for context)
|
|
537
|
+
if (session && !session.triggerRequest) {
|
|
538
|
+
session.triggerRequest = originalMessage.content.substring(0, 500);
|
|
539
|
+
session.requestedBy = originalMessage.senderName;
|
|
540
|
+
session.requestedById = originalMessage.senderId;
|
|
541
|
+
}
|
|
542
|
+
// Execute tools using the tool executor service
|
|
543
|
+
const toolResults = await this.toolExecutor.executeTools(toolUseBlocks, {
|
|
544
|
+
session,
|
|
545
|
+
preprocessToolInput: this.preprocessToolInput.bind(this),
|
|
546
|
+
});
|
|
547
|
+
// Get conversation for this discussion
|
|
548
|
+
const conversation = this.conversationManager.getConversation(originalMessage.discussionId);
|
|
549
|
+
// Add tool results to conversation
|
|
550
|
+
conversation.push({
|
|
551
|
+
role: "user",
|
|
552
|
+
content: toolResults,
|
|
553
|
+
});
|
|
554
|
+
// Continue with LLM (with caching enabled)
|
|
555
|
+
const cachedConversation = this.conversationManager.prepareForCaching(conversation);
|
|
556
|
+
const response = await this.client.messages.create({
|
|
557
|
+
model: this.config.model || "claude-haiku-4-5-20251001",
|
|
558
|
+
max_tokens: 2000,
|
|
559
|
+
system: this.getCachedSystemPrompt(),
|
|
560
|
+
messages: cachedConversation,
|
|
561
|
+
tools: this.getTools(),
|
|
562
|
+
});
|
|
563
|
+
// Track token usage in session (including cache stats for billing)
|
|
564
|
+
if (session && response.usage) {
|
|
565
|
+
const inputTokens = response.usage.input_tokens;
|
|
566
|
+
const outputTokens = response.usage.output_tokens;
|
|
567
|
+
const cacheCreationTokens = response.usage.cache_creation_input_tokens || 0;
|
|
568
|
+
const cacheReadTokens = response.usage.cache_read_input_tokens || 0;
|
|
569
|
+
session.metrics.inputTokens += inputTokens;
|
|
570
|
+
session.metrics.outputTokens += outputTokens;
|
|
571
|
+
session.metrics.cacheCreationTokens += cacheCreationTokens;
|
|
572
|
+
session.metrics.cacheReadTokens += cacheReadTokens;
|
|
573
|
+
session.metrics.apiCalls += 1;
|
|
574
|
+
session.lastActivityTime = Date.now();
|
|
575
|
+
// Burn tokens real-time (fire-and-forget)
|
|
576
|
+
if (this.tokenBilling && session.workspaceId) {
|
|
577
|
+
const cost = this.tokenBilling.calculateCost(inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens);
|
|
578
|
+
this.tokenBilling.burnTokens({
|
|
579
|
+
workspaceId: session.workspaceId,
|
|
580
|
+
inputTokens,
|
|
581
|
+
outputTokens,
|
|
582
|
+
cacheCreationTokens,
|
|
583
|
+
cacheReadTokens,
|
|
584
|
+
costUsd: cost,
|
|
585
|
+
sessionId: session.discussionId,
|
|
586
|
+
activityId: session.activityId,
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
// Recursively handle (might need more tools or finally respond)
|
|
591
|
+
await this.handleLlmResponse(response, originalMessage, conversationLengthBeforeMessage);
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Handle LLM response
|
|
595
|
+
* Override in subclasses to customize response handling
|
|
596
|
+
* @param conversationLengthBeforeMessage - length to truncate to on IGNORE (cleans up entire tool loop)
|
|
597
|
+
*/
|
|
598
|
+
async handleLlmResponse(response, originalMessage, conversationLengthBeforeMessage) {
|
|
599
|
+
const conversation = this.conversationManager.getConversation(originalMessage.discussionId);
|
|
600
|
+
// Add assistant response to conversation
|
|
601
|
+
conversation.push({
|
|
602
|
+
role: "assistant",
|
|
603
|
+
content: response.content,
|
|
604
|
+
});
|
|
605
|
+
// Check for tool calls - execute and continue
|
|
606
|
+
const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
|
|
607
|
+
if (toolUseBlocks.length > 0) {
|
|
608
|
+
await this.executeToolsAndContinue(toolUseBlocks, originalMessage, conversationLengthBeforeMessage);
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
// Extract text response
|
|
612
|
+
const textBlocks = response.content.filter((block) => block.type === "text");
|
|
613
|
+
if (textBlocks.length === 0)
|
|
614
|
+
return;
|
|
615
|
+
const responseText = textBlocks.map(b => b.text).join("\n").trim();
|
|
616
|
+
this.logger.info("LLM response received", {
|
|
617
|
+
discussion: originalMessage.discussionId,
|
|
618
|
+
responseLength: responseText.length,
|
|
619
|
+
});
|
|
620
|
+
// IGNORE/COMPLETE decision - clean up context (entire tool loop if any)
|
|
621
|
+
// LLM may use IGNORE (don't respond) or COMPLETE (already posted via tool)
|
|
622
|
+
if (responseText.includes("<decision>IGNORE</decision>") ||
|
|
623
|
+
responseText.includes("<decision>COMPLETE</decision>") ||
|
|
624
|
+
responseText.includes("<ignore")) {
|
|
625
|
+
this.logger.debug("LLM decided to ignore", { discussion: originalMessage.discussionId });
|
|
626
|
+
this.typingIndicator?.stop();
|
|
627
|
+
// If we have the original conversation length, truncate to it (cleans up entire tool loop)
|
|
628
|
+
if (conversationLengthBeforeMessage !== undefined) {
|
|
629
|
+
conversation.length = Math.min(conversationLengthBeforeMessage, conversation.length);
|
|
630
|
+
this.logger.debug("Truncated conversation to pre-message state", {
|
|
631
|
+
discussion: originalMessage.discussionId,
|
|
632
|
+
newLength: conversation.length
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
else {
|
|
636
|
+
// Fallback: just remove assistant response and user message
|
|
637
|
+
conversation.pop(); // Remove assistant response
|
|
638
|
+
conversation.pop(); // Remove incoming message
|
|
639
|
+
}
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
// Explicit <respond> tag
|
|
643
|
+
const responseMatch = responseText.match(/<respond discussion="([^"]+)">([\s\S]*?)<\/respond>/);
|
|
644
|
+
if (responseMatch) {
|
|
645
|
+
await this.postResponse(responseMatch[1], responseMatch[2].trim());
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
// High priority: always respond if substantive
|
|
649
|
+
if (originalMessage.priority === "high" && responseText.length > 10 &&
|
|
650
|
+
!responseText.includes("<thinking>") && !responseText.startsWith("I'll")) {
|
|
651
|
+
await this.postResponse(originalMessage.discussionId, responseText);
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
// Normal priority without <respond> tag - clean up context
|
|
655
|
+
if (originalMessage.priority === "normal") {
|
|
656
|
+
this.logger.debug("Normal priority without <respond> - removing from context");
|
|
657
|
+
this.typingIndicator?.stop();
|
|
658
|
+
if (conversationLengthBeforeMessage !== undefined) {
|
|
659
|
+
conversation.length = Math.min(conversationLengthBeforeMessage, conversation.length);
|
|
660
|
+
}
|
|
661
|
+
else {
|
|
662
|
+
conversation.pop();
|
|
663
|
+
conversation.pop();
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
// ===== STRUCTURED OUTPUTS SUPPORT =====
|
|
668
|
+
/**
|
|
669
|
+
* Call LLM with structured outputs instead of native tools
|
|
670
|
+
* Saves ~100K tokens per request by not sending tool schemas
|
|
671
|
+
*/
|
|
672
|
+
async callLlmWithStructuredOutputs(messages) {
|
|
673
|
+
// Build system prompt with action reference
|
|
674
|
+
const systemPrompt = this.getCachedSystemPrompt();
|
|
675
|
+
const actionPrompt = this.structuredOutputExecutor.generateActionPrompt(this.getAllowedActions());
|
|
676
|
+
// Combine system prompt with action reference
|
|
677
|
+
// ARCHITECTURE for caching:
|
|
678
|
+
// 1. Static blocks (all except last) - stripped of cache_control
|
|
679
|
+
// 2. Action prompt - WITH cache_control (this is the cache breakpoint)
|
|
680
|
+
// 3. Dynamic block (last) - NO cache_control, comes AFTER breakpoint
|
|
681
|
+
// This way only static + action are cached, dynamic content is fresh each call
|
|
682
|
+
const systemBlocks = Array.isArray(systemPrompt) ? systemPrompt : [{ type: "text", text: systemPrompt }];
|
|
683
|
+
// Separate static (all but last) from dynamic (last)
|
|
684
|
+
const staticBlocks = systemBlocks.slice(0, -1);
|
|
685
|
+
const dynamicBlock = systemBlocks.length > 1 ? systemBlocks[systemBlocks.length - 1] : null;
|
|
686
|
+
const combinedSystem = [
|
|
687
|
+
// Static blocks (stripped of cache_control)
|
|
688
|
+
...staticBlocks.map(block => ({
|
|
689
|
+
type: "text",
|
|
690
|
+
text: block.text || "",
|
|
691
|
+
})),
|
|
692
|
+
// Action prompt WITH cache_control (cache breakpoint)
|
|
693
|
+
{
|
|
694
|
+
type: "text",
|
|
695
|
+
text: actionPrompt,
|
|
696
|
+
cache_control: { type: "ephemeral" },
|
|
697
|
+
},
|
|
698
|
+
// Dynamic block AFTER breakpoint (not cached)
|
|
699
|
+
...(dynamicBlock ? [{
|
|
700
|
+
type: "text",
|
|
701
|
+
text: dynamicBlock.text || "",
|
|
702
|
+
}] : []),
|
|
703
|
+
];
|
|
704
|
+
// DEBUG: Log what we're sending to API
|
|
705
|
+
const systemCharCount = combinedSystem.reduce((acc, block) => acc + (block.text?.length || 0), 0);
|
|
706
|
+
const messagesCharCount = JSON.stringify(messages).length;
|
|
707
|
+
const outputFormat = this.structuredOutputExecutor.getOutputFormat();
|
|
708
|
+
const schemaCharCount = JSON.stringify(outputFormat).length;
|
|
709
|
+
this.logger.info("Structured outputs request sizing", {
|
|
710
|
+
systemCharCount,
|
|
711
|
+
messagesCharCount,
|
|
712
|
+
schemaCharCount,
|
|
713
|
+
estimatedTokens: Math.round((systemCharCount + messagesCharCount) / 4),
|
|
714
|
+
messagesCount: messages.length,
|
|
715
|
+
});
|
|
716
|
+
// Call with structured outputs beta
|
|
717
|
+
// Note: Prompt caching is now GA (no beta header needed)
|
|
718
|
+
// Note: output_format is a beta feature not yet in SDK types
|
|
719
|
+
const params = {
|
|
720
|
+
model: this.config.model || "claude-haiku-4-5-20251001",
|
|
721
|
+
max_tokens: 2000,
|
|
722
|
+
betas: [structured_output_executor_1.STRUCTURED_OUTPUTS_BETA],
|
|
723
|
+
system: combinedSystem,
|
|
724
|
+
messages,
|
|
725
|
+
output_format: outputFormat,
|
|
726
|
+
};
|
|
727
|
+
const response = await this.client.beta.messages.create(params);
|
|
728
|
+
// DEBUG: Log actual usage from API
|
|
729
|
+
if (response.usage) {
|
|
730
|
+
const usage = response.usage;
|
|
731
|
+
this.logger.info("Structured outputs response usage", {
|
|
732
|
+
inputTokens: usage.input_tokens,
|
|
733
|
+
outputTokens: usage.output_tokens,
|
|
734
|
+
cacheCreationTokens: usage.cache_creation_input_tokens || 0,
|
|
735
|
+
cacheReadTokens: usage.cache_read_input_tokens || 0,
|
|
736
|
+
estimatedVsActual: `${Math.round((systemCharCount + messagesCharCount) / 4)} vs ${usage.input_tokens + (usage.cache_creation_input_tokens || 0)}`,
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
return response;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Handle structured output response
|
|
743
|
+
* Parses JSON action and executes it
|
|
744
|
+
*/
|
|
745
|
+
async handleStructuredResponse(response, originalMessage, conversationLengthBeforeMessage) {
|
|
746
|
+
const conversation = this.conversationManager.getConversation(originalMessage.discussionId);
|
|
747
|
+
// Add assistant response to conversation
|
|
748
|
+
conversation.push({
|
|
749
|
+
role: "assistant",
|
|
750
|
+
content: response.content,
|
|
751
|
+
});
|
|
752
|
+
// Parse the action from response
|
|
753
|
+
const action = this.structuredOutputExecutor.parseResponse(response);
|
|
754
|
+
if (!action) {
|
|
755
|
+
this.logger.warn("Failed to parse action from response");
|
|
756
|
+
this.typingIndicator?.stop();
|
|
757
|
+
// Remove failed response from context
|
|
758
|
+
conversation.pop();
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
this.logger.debug("Parsed action", {
|
|
762
|
+
action: action.action,
|
|
763
|
+
thinking: action.thinking?.substring(0, 50),
|
|
764
|
+
});
|
|
765
|
+
// Get session for tracking
|
|
766
|
+
const sessionKey = this.currentLinkedActivityId || this.currentDiscussionId || "default";
|
|
767
|
+
const session = this.sessionLogger.getSession(sessionKey);
|
|
768
|
+
// Execute the action
|
|
769
|
+
const result = await this.structuredOutputExecutor.executeAction(action, {
|
|
770
|
+
session,
|
|
771
|
+
preprocessToolInput: this.preprocessToolInput.bind(this),
|
|
772
|
+
});
|
|
773
|
+
// Handle terminal actions
|
|
774
|
+
if (result.isTerminal) {
|
|
775
|
+
if (result.action === "respond" && result.responseText) {
|
|
776
|
+
await this.postResponse(originalMessage.discussionId, result.responseText);
|
|
777
|
+
}
|
|
778
|
+
else if (result.action === "ignore") {
|
|
779
|
+
this.logger.debug("Action: ignore", { discussion: originalMessage.discussionId });
|
|
780
|
+
this.typingIndicator?.stop();
|
|
781
|
+
// Clean up context on ignore
|
|
782
|
+
if (conversationLengthBeforeMessage !== undefined) {
|
|
783
|
+
conversation.length = Math.min(conversationLengthBeforeMessage, conversation.length);
|
|
784
|
+
}
|
|
785
|
+
else {
|
|
786
|
+
conversation.pop();
|
|
787
|
+
conversation.pop();
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
else if (result.action === "invite_specialist" && result.specialist) {
|
|
791
|
+
// Handle specialist invitation (override in subclass)
|
|
792
|
+
await this.handleSpecialistInvite(result.specialist.key, result.specialist.context, originalMessage);
|
|
793
|
+
}
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
// Non-terminal action: add result and continue
|
|
797
|
+
if (result.error || result.toolResult) {
|
|
798
|
+
const resultMessage = this.structuredOutputExecutor.formatResultForConversation(result);
|
|
799
|
+
conversation.push(resultMessage);
|
|
800
|
+
// Continue the loop with another LLM call
|
|
801
|
+
await this.executeStructuredActionLoop(originalMessage, conversationLengthBeforeMessage);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Continue executing actions until a terminal action
|
|
806
|
+
*/
|
|
807
|
+
async executeStructuredActionLoop(originalMessage, conversationLengthBeforeMessage) {
|
|
808
|
+
const conversation = this.conversationManager.getConversation(originalMessage.discussionId);
|
|
809
|
+
const sessionKey = this.currentLinkedActivityId || this.currentDiscussionId || "default";
|
|
810
|
+
const session = this.sessionLogger.getSession(sessionKey);
|
|
811
|
+
// Call LLM again with structured outputs
|
|
812
|
+
const cachedConversation = this.conversationManager.prepareForCaching(conversation);
|
|
813
|
+
const response = await this.callLlmWithStructuredOutputs(cachedConversation);
|
|
814
|
+
// Track token usage
|
|
815
|
+
if (session && response.usage) {
|
|
816
|
+
const inputTokens = response.usage.input_tokens;
|
|
817
|
+
const outputTokens = response.usage.output_tokens;
|
|
818
|
+
const cacheCreationTokens = response.usage.cache_creation_input_tokens || 0;
|
|
819
|
+
const cacheReadTokens = response.usage.cache_read_input_tokens || 0;
|
|
820
|
+
session.metrics.inputTokens += inputTokens;
|
|
821
|
+
session.metrics.outputTokens += outputTokens;
|
|
822
|
+
session.metrics.cacheCreationTokens += cacheCreationTokens;
|
|
823
|
+
session.metrics.cacheReadTokens += cacheReadTokens;
|
|
824
|
+
session.metrics.apiCalls += 1;
|
|
825
|
+
session.lastActivityTime = Date.now();
|
|
826
|
+
// Burn tokens real-time
|
|
827
|
+
if (this.tokenBilling && session.workspaceId) {
|
|
828
|
+
const cost = this.tokenBilling.calculateCost(inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens);
|
|
829
|
+
this.tokenBilling.burnTokens({
|
|
830
|
+
workspaceId: session.workspaceId,
|
|
831
|
+
inputTokens,
|
|
832
|
+
outputTokens,
|
|
833
|
+
cacheCreationTokens,
|
|
834
|
+
cacheReadTokens,
|
|
835
|
+
costUsd: cost,
|
|
836
|
+
sessionId: session.discussionId,
|
|
837
|
+
activityId: session.activityId,
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
// Handle the response (recursive)
|
|
842
|
+
await this.handleStructuredResponse(response, originalMessage, conversationLengthBeforeMessage);
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Get allowed actions for this agent
|
|
846
|
+
* Override in subclass to customize available actions
|
|
847
|
+
*/
|
|
848
|
+
getAllowedActions() {
|
|
849
|
+
// Default: all actions except meta actions (handled separately)
|
|
850
|
+
return action_schema_1.BOT_ACTIONS.filter((a) => a !== "respond" && a !== "ignore" && a !== "invite_specialist");
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Handle specialist invitation
|
|
854
|
+
* Override in subclass (e.g., HAL daemon) to implement specialist logic
|
|
855
|
+
*/
|
|
856
|
+
async handleSpecialistInvite(specialistKey, context, originalMessage) {
|
|
857
|
+
this.logger.warn("Specialist invite not implemented in base class", {
|
|
858
|
+
specialist: specialistKey,
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Post a response to a discussion
|
|
863
|
+
* Automatically converts @mentions and #activity tags to Hailer tags
|
|
864
|
+
* Includes links metadata required for tags to work
|
|
865
|
+
*/
|
|
866
|
+
async postResponse(discussionId, content) {
|
|
867
|
+
// Stop typing indicator before posting
|
|
868
|
+
this.typingIndicator?.stop();
|
|
869
|
+
try {
|
|
870
|
+
// Resolve tags that need API lookup
|
|
871
|
+
let formattedContent = await this.messageFormatter.resolveUserTags(content); // @userId → [hailerTag|Name](id)
|
|
872
|
+
formattedContent = await this.messageFormatter.resolveActivityTags(formattedContent); // #activityId → [hailerTag|Name](id)
|
|
873
|
+
formattedContent = await this.messageFormatter.resolveHailerUrls(formattedContent); // URLs → [hailerTag|Name](id)
|
|
874
|
+
// Then convert any remaining @mentions from cache (fallback)
|
|
875
|
+
formattedContent = this.messageFormatter.convertMentionsToTags(formattedContent);
|
|
876
|
+
// Remove redundant "(Name)" after tags - LLM sometimes adds these
|
|
877
|
+
formattedContent = formattedContent.replace(/(\[hailerTag\|[^\]]+\]\([a-f0-9]{24}\)\uFEFF?)\s*\([^)]+\)/gi, '$1');
|
|
878
|
+
// Extract link metadata for any tags in the content
|
|
879
|
+
const links = this.messageFormatter.extractTagLinks(formattedContent);
|
|
880
|
+
// Build message object with links if we have any
|
|
881
|
+
const messageData = {
|
|
882
|
+
msg: formattedContent
|
|
883
|
+
};
|
|
884
|
+
if (links.length > 0) {
|
|
885
|
+
messageData.links = links;
|
|
886
|
+
}
|
|
887
|
+
await this.botClient.client.socket.request("messenger.send", [
|
|
888
|
+
messageData,
|
|
889
|
+
discussionId,
|
|
890
|
+
]);
|
|
891
|
+
// Track response in activity session
|
|
892
|
+
const sessionKey = this.currentLinkedActivityId || this.currentDiscussionId || "default";
|
|
893
|
+
const session = this.sessionLogger.getSession(sessionKey);
|
|
894
|
+
if (session) {
|
|
895
|
+
session.metrics.responsesPosted++;
|
|
896
|
+
session.actions.push(`Responded in discussion`);
|
|
897
|
+
session.lastActivityTime = Date.now();
|
|
898
|
+
// Add bot response to conversation log (compact version)
|
|
899
|
+
const botSnippet = content.length > 100 ? content.substring(0, 100) + "..." : content;
|
|
900
|
+
session.conversation.push(`Bot: ${botSnippet}`);
|
|
901
|
+
}
|
|
902
|
+
this.logger.info("Response posted", {
|
|
903
|
+
discussion: discussionId,
|
|
904
|
+
length: formattedContent.length,
|
|
905
|
+
hadTags: formattedContent !== content,
|
|
906
|
+
linkCount: links.length,
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
catch (error) {
|
|
910
|
+
this.logger.error("Failed to post response", error);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Send insufficient balance message to user
|
|
915
|
+
* Can be overridden in subclasses to customize the message
|
|
916
|
+
*/
|
|
917
|
+
async sendInsufficientBalanceMessage(discussionId) {
|
|
918
|
+
try {
|
|
919
|
+
await this.botClient.client.socket.request("messenger.send", [
|
|
920
|
+
{ msg: "Insufficient balance. Please top up your workspace AI credits to continue." },
|
|
921
|
+
discussionId,
|
|
922
|
+
]);
|
|
923
|
+
}
|
|
924
|
+
catch (error) {
|
|
925
|
+
this.logger.error("Failed to send insufficient balance message", error);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Get the system prompt for the daemon
|
|
930
|
+
* MUST be overridden in subclasses
|
|
931
|
+
*/
|
|
932
|
+
getSystemPrompt() {
|
|
933
|
+
throw new Error("getSystemPrompt() must be implemented by subclass");
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Get the system prompt wrapped with Anthropic prompt caching
|
|
937
|
+
* This enables 50% cost reduction on cached tokens after first use
|
|
938
|
+
*/
|
|
939
|
+
getCachedSystemPrompt() {
|
|
940
|
+
return [
|
|
941
|
+
{
|
|
942
|
+
type: "text",
|
|
943
|
+
text: this.getSystemPrompt(),
|
|
944
|
+
cache_control: { type: "ephemeral" },
|
|
945
|
+
},
|
|
946
|
+
];
|
|
947
|
+
}
|
|
948
|
+
/**
|
|
949
|
+
* Get tools for LLM calls
|
|
950
|
+
* Override in subclass to add custom tools (like trigger_giuseppe_retry)
|
|
951
|
+
*/
|
|
952
|
+
getTools() {
|
|
953
|
+
return this.minimalTools;
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Get tool groups to load for this agent
|
|
957
|
+
* Override in subclass to include additional groups (e.g., BOT_INTERNAL)
|
|
958
|
+
*/
|
|
959
|
+
getToolGroups() {
|
|
960
|
+
return [tool_registry_1.ToolGroup.READ, tool_registry_1.ToolGroup.WRITE];
|
|
961
|
+
}
|
|
962
|
+
/**
|
|
963
|
+
* Get tool whitelist for this agent
|
|
964
|
+
* Override in subclass to limit which tools are available
|
|
965
|
+
* Return null for all tools, or array of tool names
|
|
966
|
+
*/
|
|
967
|
+
getToolWhitelist() {
|
|
968
|
+
return null; // Default: all tools
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* Preprocess tool input before execution
|
|
972
|
+
* Override in subclass to inject context (e.g., sourceActivityId)
|
|
973
|
+
* @param toolName - Name of the tool being called
|
|
974
|
+
* @param input - Original tool input from LLM
|
|
975
|
+
* @returns Processed input (may be modified)
|
|
976
|
+
*/
|
|
977
|
+
preprocessToolInput(toolName, input) {
|
|
978
|
+
// Auto-inject discussionId for leave_discussion if not provided
|
|
979
|
+
if (toolName === "leave_discussion" && !input.discussionId && !input.activityId) {
|
|
980
|
+
if (this.currentDiscussionId) {
|
|
981
|
+
this.logger.debug("Auto-injected discussionId for leave_discussion", {
|
|
982
|
+
discussionId: this.currentDiscussionId,
|
|
983
|
+
});
|
|
984
|
+
return { ...input, discussionId: this.currentDiscussionId };
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
return input; // Default: no preprocessing
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Call MCP tool (delegates to McpClientService)
|
|
991
|
+
* Protected for subclass access
|
|
992
|
+
*/
|
|
993
|
+
async callMcpTool(name, args) {
|
|
994
|
+
return this.mcpClient.callMcpTool(name, args);
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Stop the daemon
|
|
998
|
+
* Flushes all pending activity sessions before stopping
|
|
999
|
+
*/
|
|
1000
|
+
async stop() {
|
|
1001
|
+
// Stop idle check timer and flush all pending sessions
|
|
1002
|
+
this.sessionLogger?.stopIdleCheckTimer();
|
|
1003
|
+
await this.sessionLogger?.flushAllSessions();
|
|
1004
|
+
// Unsubscribe from messenger.new signals
|
|
1005
|
+
if (this.messengerUnsubscribe) {
|
|
1006
|
+
this.messengerUnsubscribe();
|
|
1007
|
+
this.messengerUnsubscribe = null;
|
|
1008
|
+
}
|
|
1009
|
+
// Disconnect the Hailer client connection using the ORIGINAL API key
|
|
1010
|
+
// This is critical: botClient.config.mcpServerApiKey may have been updated to a new value
|
|
1011
|
+
// before stop() is called during restart, so we must use the stored originalApiKey
|
|
1012
|
+
if (this.originalApiKey) {
|
|
1013
|
+
(0, hailer_clients_1.disconnectHailerClientByApiKey)(this.originalApiKey);
|
|
1014
|
+
this.originalApiKey = null;
|
|
1015
|
+
}
|
|
1016
|
+
this.botClient.signalHandler.unsubscribe(`daemon-${this.botClient.userId}`);
|
|
1017
|
+
this.logger.info("Chat Agent Daemon stopped", {
|
|
1018
|
+
agentDirectoryId: this.registryService?.getAgentDirectoryId(),
|
|
1019
|
+
activeSessions: this.sessionLogger?.getActiveSessions().size ?? 0,
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Get current conversation state (for debugging)
|
|
1024
|
+
*/
|
|
1025
|
+
getConversationState() {
|
|
1026
|
+
// Get current discussion's conversation
|
|
1027
|
+
const currentConversation = this.currentDiscussionId
|
|
1028
|
+
? this.conversationManager.getConversation(this.currentDiscussionId)
|
|
1029
|
+
: [];
|
|
1030
|
+
// Get last 5 messages with preview
|
|
1031
|
+
const lastMessages = currentConversation.slice(-5).map(msg => {
|
|
1032
|
+
let preview = "";
|
|
1033
|
+
if (typeof msg.content === "string") {
|
|
1034
|
+
preview = msg.content.substring(0, 100);
|
|
1035
|
+
}
|
|
1036
|
+
else if (Array.isArray(msg.content)) {
|
|
1037
|
+
const textBlock = msg.content.find((b) => b.type === "text");
|
|
1038
|
+
preview = textBlock?.text?.substring(0, 100) || "[tool call/result]";
|
|
1039
|
+
}
|
|
1040
|
+
return {
|
|
1041
|
+
role: msg.role,
|
|
1042
|
+
preview: preview + (preview.length >= 100 ? "..." : ""),
|
|
1043
|
+
};
|
|
1044
|
+
});
|
|
1045
|
+
const state = this.conversationManager.getState(this.currentDiscussionId ?? undefined);
|
|
1046
|
+
return {
|
|
1047
|
+
discussionCount: state.discussionCount,
|
|
1048
|
+
currentDiscussion: this.currentDiscussionId,
|
|
1049
|
+
currentMessageCount: currentConversation.length,
|
|
1050
|
+
queueLength: this.messageQueue.length,
|
|
1051
|
+
lastMessages,
|
|
1052
|
+
isProcessing: this.isProcessing,
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
// ===== AGENT REGISTRY & SESSION LOGGING METHODS =====
|
|
1056
|
+
/**
|
|
1057
|
+
* Get agent's display name (override in subclass for custom names)
|
|
1058
|
+
* Default implementation uses the actual Hailer user name from BotClient
|
|
1059
|
+
*/
|
|
1060
|
+
getAgentName() {
|
|
1061
|
+
// Use actual Hailer user name from BotClient (populated from workspace cache)
|
|
1062
|
+
return {
|
|
1063
|
+
firstName: this.botClient.firstName,
|
|
1064
|
+
lastName: this.botClient.lastName,
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Get agent's description/system prompt (override in subclass)
|
|
1069
|
+
*/
|
|
1070
|
+
getAgentDescription() {
|
|
1071
|
+
return "Chat Agent Daemon - handles general workspace conversations";
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Get default team ID from workspace cache
|
|
1075
|
+
* Returns the first available team, or undefined if no teams exist
|
|
1076
|
+
*
|
|
1077
|
+
* Teams structure in init is: { teams: { workspaceId: { teamId: teamData, ... } } }
|
|
1078
|
+
*/
|
|
1079
|
+
getDefaultTeamId() {
|
|
1080
|
+
const rawInit = this.botClient.workspaceCache?.rawInit;
|
|
1081
|
+
if (!rawInit?.teams) {
|
|
1082
|
+
this.logger.debug("No teams in workspace cache");
|
|
1083
|
+
return undefined;
|
|
1084
|
+
}
|
|
1085
|
+
// Teams are nested under workspace ID
|
|
1086
|
+
// Structure: { workspaceId: { teamId1: {...}, teamId2: {...} } }
|
|
1087
|
+
const workspaceTeams = Object.values(rawInit.teams)[0];
|
|
1088
|
+
if (!workspaceTeams || typeof workspaceTeams !== 'object') {
|
|
1089
|
+
this.logger.debug("No workspace teams found");
|
|
1090
|
+
return undefined;
|
|
1091
|
+
}
|
|
1092
|
+
const teamIds = Object.keys(workspaceTeams);
|
|
1093
|
+
if (teamIds.length === 0) {
|
|
1094
|
+
this.logger.debug("No teams available in workspace");
|
|
1095
|
+
return undefined;
|
|
1096
|
+
}
|
|
1097
|
+
const defaultTeamId = teamIds[0];
|
|
1098
|
+
const teamName = workspaceTeams[defaultTeamId]?.name || 'unknown';
|
|
1099
|
+
this.logger.debug("Using default team", { teamId: defaultTeamId, teamName, teamCount: teamIds.length });
|
|
1100
|
+
return defaultTeamId;
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Get agent's Position details (override in subclass for custom positions)
|
|
1104
|
+
*/
|
|
1105
|
+
getPositionDetails() {
|
|
1106
|
+
return {
|
|
1107
|
+
name: "Chat Agent",
|
|
1108
|
+
purpose: "General workspace assistant that monitors discussions and responds to user queries.",
|
|
1109
|
+
personaTone: "Professional, helpful, and concise. Responds directly without unnecessary filler.",
|
|
1110
|
+
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",
|
|
1111
|
+
boundaries: "- Never fabricate data - always use tools\n- Don't respond to off-topic messages\n- Don't share sensitive credentials",
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
/**
|
|
1115
|
+
* Get agent directory ID
|
|
1116
|
+
*/
|
|
1117
|
+
getAgentDirectoryId() {
|
|
1118
|
+
return this.registryService?.getAgentDirectoryId() || null;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
exports.ChatAgentDaemon = ChatAgentDaemon;
|
|
1122
|
+
//# sourceMappingURL=base.js.map
|