@hailer/mcp 1.2.0 → 1.3.9
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/.claude/agents/agent-hailer-helper.md +118 -0
- package/.claude/commands/debug-squad.md +13 -290
- package/.claude/commands/publish.md +2 -2
- package/.claude/commands/review-squad.md +17 -139
- package/.claude/skills/create-and-publish-app/SKILL.md +148 -81
- package/.claude/skills/hailer-app-builder/SKILL.md +29 -2
- package/.claude/skills/hailer-ui-guide/SKILL.md +265 -0
- package/.env.example +50 -1
- package/CLAUDE.md +141 -10
- package/dist/app-prep.d.ts +27 -0
- package/dist/app-prep.d.ts.map +1 -0
- package/dist/app-prep.js +94 -0
- package/dist/app-prep.js.map +1 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +3 -0
- package/dist/app.js.map +1 -1
- package/dist/bot/bot-manager.d.ts +9 -6
- package/dist/bot/bot-manager.d.ts.map +1 -1
- package/dist/bot/bot-manager.js +142 -31
- package/dist/bot/bot-manager.js.map +1 -1
- package/dist/bot/bot.d.ts +61 -16
- package/dist/bot/bot.d.ts.map +1 -1
- package/dist/bot/bot.js +927 -151
- package/dist/bot/bot.js.map +1 -1
- package/dist/bot/operation-logger.d.ts.map +1 -1
- package/dist/bot/operation-logger.js +24 -12
- package/dist/bot/operation-logger.js.map +1 -1
- package/dist/bot/services/bot-permissions.d.ts +37 -5
- package/dist/bot/services/bot-permissions.d.ts.map +1 -1
- package/dist/bot/services/bot-permissions.js +159 -35
- package/dist/bot/services/bot-permissions.js.map +1 -1
- package/dist/bot/services/conversation-manager.d.ts +23 -23
- package/dist/bot/services/conversation-manager.d.ts.map +1 -1
- package/dist/bot/services/conversation-manager.js +52 -49
- package/dist/bot/services/conversation-manager.js.map +1 -1
- package/dist/bot/services/helper-prompt.d.ts +8 -0
- package/dist/bot/services/helper-prompt.d.ts.map +1 -0
- package/dist/bot/services/helper-prompt.js +177 -0
- package/dist/bot/services/helper-prompt.js.map +1 -0
- package/dist/bot/services/message-classifier.d.ts +16 -16
- package/dist/bot/services/message-classifier.d.ts.map +1 -1
- package/dist/bot/services/message-classifier.js +55 -49
- package/dist/bot/services/message-classifier.js.map +1 -1
- package/dist/bot/services/message-formatter.d.ts +47 -38
- package/dist/bot/services/message-formatter.d.ts.map +1 -1
- package/dist/bot/services/message-formatter.js +99 -80
- package/dist/bot/services/message-formatter.js.map +1 -1
- package/dist/bot/services/permission-guard.d.ts.map +1 -1
- package/dist/bot/services/permission-guard.js +20 -10
- package/dist/bot/services/permission-guard.js.map +1 -1
- package/dist/bot/services/signal-router.d.ts.map +1 -1
- package/dist/bot/services/signal-router.js +11 -6
- package/dist/bot/services/signal-router.js.map +1 -1
- package/dist/bot/services/system-prompt.d.ts +14 -0
- package/dist/bot/services/system-prompt.d.ts.map +1 -1
- package/dist/bot/services/system-prompt.js +181 -4
- package/dist/bot/services/system-prompt.js.map +1 -1
- package/dist/bot/services/token-billing.d.ts +23 -23
- package/dist/bot/services/token-billing.d.ts.map +1 -1
- package/dist/bot/services/token-billing.js +51 -36
- package/dist/bot/services/token-billing.js.map +1 -1
- package/dist/bot/services/types.d.ts +3 -1
- package/dist/bot/services/types.d.ts.map +1 -1
- package/dist/bot/services/typing-indicator.d.ts +8 -8
- package/dist/bot/services/typing-indicator.d.ts.map +1 -1
- package/dist/bot/services/typing-indicator.js +12 -10
- package/dist/bot/services/typing-indicator.js.map +1 -1
- package/dist/bot/services/workspace-refresh.d.ts +3 -3
- package/dist/bot/services/workspace-refresh.d.ts.map +1 -1
- package/dist/bot/services/workspace-refresh.js +23 -13
- package/dist/bot/services/workspace-refresh.js.map +1 -1
- package/dist/bot/tool-executor.d.ts +10 -6
- package/dist/bot/tool-executor.d.ts.map +1 -1
- package/dist/bot/tool-executor.js +12 -6
- package/dist/bot/tool-executor.js.map +1 -1
- package/dist/bot/workspace-overview.d.ts.map +1 -1
- package/dist/bot/workspace-overview.js +6 -3
- package/dist/bot/workspace-overview.js.map +1 -1
- package/dist/bot-config/activity-error.d.ts +47 -0
- package/dist/bot-config/activity-error.d.ts.map +1 -0
- package/dist/bot-config/activity-error.js +67 -0
- package/dist/bot-config/activity-error.js.map +1 -0
- package/dist/bot-config/context.d.ts +4 -4
- package/dist/bot-config/context.d.ts.map +1 -1
- package/dist/bot-config/context.js +18 -14
- package/dist/bot-config/context.js.map +1 -1
- package/dist/bot-config/events.d.ts +45 -0
- package/dist/bot-config/events.d.ts.map +1 -0
- package/dist/bot-config/events.js +51 -0
- package/dist/bot-config/events.js.map +1 -0
- package/dist/bot-config/index.d.ts +3 -0
- package/dist/bot-config/index.d.ts.map +1 -1
- package/dist/bot-config/index.js +8 -1
- package/dist/bot-config/index.js.map +1 -1
- package/dist/bot-config/loader.d.ts +3 -0
- package/dist/bot-config/loader.d.ts.map +1 -1
- package/dist/bot-config/loader.js +45 -20
- package/dist/bot-config/loader.js.map +1 -1
- package/dist/bot-config/persistence.js.map +1 -1
- package/dist/bot-config/reconciler.d.ts +11 -0
- package/dist/bot-config/reconciler.d.ts.map +1 -0
- package/dist/bot-config/reconciler.js +121 -0
- package/dist/bot-config/reconciler.js.map +1 -0
- package/dist/bot-config/state.d.ts.map +1 -1
- package/dist/bot-config/state.js.map +1 -1
- package/dist/bot-config/types.d.ts +32 -0
- package/dist/bot-config/types.d.ts.map +1 -1
- package/dist/bot-config/webhooks.d.ts.map +1 -1
- package/dist/bot-config/webhooks.js.map +1 -1
- package/dist/bot-config/workflow-installer.d.ts +37 -0
- package/dist/bot-config/workflow-installer.d.ts.map +1 -0
- package/dist/bot-config/workflow-installer.js +346 -0
- package/dist/bot-config/workflow-installer.js.map +1 -0
- package/dist/cli.d.ts +4 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +92 -11
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +23 -19
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +65 -27
- package/dist/config.js.map +1 -1
- package/dist/core.d.ts +6 -4
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +11 -16
- package/dist/core.js.map +1 -1
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +7 -4
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/request-logger.d.ts +19 -19
- package/dist/lib/request-logger.d.ts.map +1 -1
- package/dist/lib/request-logger.js +19 -19
- package/dist/lib/request-logger.js.map +1 -1
- package/dist/mcp/UserContextCache.d.ts +28 -22
- package/dist/mcp/UserContextCache.d.ts.map +1 -1
- package/dist/mcp/UserContextCache.js +23 -23
- package/dist/mcp/UserContextCache.js.map +1 -1
- package/dist/mcp/auth.js.map +1 -1
- package/dist/mcp/hailer-clients.d.ts +5 -4
- package/dist/mcp/hailer-clients.d.ts.map +1 -1
- package/dist/mcp/hailer-clients.js +83 -34
- package/dist/mcp/hailer-clients.js.map +1 -1
- package/dist/mcp/hailer-rpc.d.ts +40 -0
- package/dist/mcp/hailer-rpc.d.ts.map +1 -0
- package/dist/mcp/hailer-rpc.js +43 -0
- package/dist/mcp/hailer-rpc.js.map +1 -0
- package/dist/mcp/publish-auth-injector.d.ts +22 -0
- package/dist/mcp/publish-auth-injector.d.ts.map +1 -0
- package/dist/mcp/publish-auth-injector.js +100 -0
- package/dist/mcp/publish-auth-injector.js.map +1 -0
- package/dist/mcp/session-store.d.ts +16 -16
- package/dist/mcp/session-store.d.ts.map +1 -1
- package/dist/mcp/session-store.js +16 -16
- package/dist/mcp/session-store.js.map +1 -1
- package/dist/mcp/tool-profiles.d.ts +69 -0
- package/dist/mcp/tool-profiles.d.ts.map +1 -0
- package/dist/mcp/tool-profiles.js +176 -0
- package/dist/mcp/tool-profiles.js.map +1 -0
- package/dist/mcp/tool-registry.d.ts +16 -0
- package/dist/mcp/tool-registry.d.ts.map +1 -1
- package/dist/mcp/tool-registry.js +91 -39
- package/dist/mcp/tool-registry.js.map +1 -1
- package/dist/mcp/tools/activity.d.ts +2 -0
- package/dist/mcp/tools/activity.d.ts.map +1 -1
- package/dist/mcp/tools/activity.js +575 -218
- package/dist/mcp/tools/activity.js.map +1 -1
- package/dist/mcp/tools/aliases.d.ts +11 -0
- package/dist/mcp/tools/aliases.d.ts.map +1 -0
- package/dist/mcp/tools/aliases.js +182 -0
- package/dist/mcp/tools/aliases.js.map +1 -0
- package/dist/mcp/tools/app-core.d.ts +6 -8
- package/dist/mcp/tools/app-core.d.ts.map +1 -1
- package/dist/mcp/tools/app-core.js +355 -254
- package/dist/mcp/tools/app-core.js.map +1 -1
- package/dist/mcp/tools/app-marketplace.d.ts +8 -16
- package/dist/mcp/tools/app-marketplace.d.ts.map +1 -1
- package/dist/mcp/tools/app-marketplace.js +604 -932
- package/dist/mcp/tools/app-marketplace.js.map +1 -1
- package/dist/mcp/tools/app.d.ts +4 -7
- package/dist/mcp/tools/app.d.ts.map +1 -1
- package/dist/mcp/tools/app.js +4 -7
- package/dist/mcp/tools/app.js.map +1 -1
- package/dist/mcp/tools/bot-self.d.ts +21 -0
- package/dist/mcp/tools/bot-self.d.ts.map +1 -0
- package/dist/mcp/tools/bot-self.js +174 -0
- package/dist/mcp/tools/bot-self.js.map +1 -0
- package/dist/mcp/tools/calendar.d.ts +21 -0
- package/dist/mcp/tools/calendar.d.ts.map +1 -0
- package/dist/mcp/tools/calendar.js +741 -0
- package/dist/mcp/tools/calendar.js.map +1 -0
- package/dist/mcp/tools/company.d.ts.map +1 -1
- package/dist/mcp/tools/company.js +2 -1
- package/dist/mcp/tools/company.js.map +1 -1
- package/dist/mcp/tools/date.js.map +1 -1
- package/dist/mcp/tools/discussion.d.ts +29 -3
- package/dist/mcp/tools/discussion.d.ts.map +1 -1
- package/dist/mcp/tools/discussion.js +419 -534
- package/dist/mcp/tools/discussion.js.map +1 -1
- package/dist/mcp/tools/file.d.ts.map +1 -1
- package/dist/mcp/tools/file.js +18 -16
- package/dist/mcp/tools/file.js.map +1 -1
- package/dist/mcp/tools/index.js +4 -4
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/insight.d.ts +24 -5
- package/dist/mcp/tools/insight.d.ts.map +1 -1
- package/dist/mcp/tools/insight.js +513 -480
- package/dist/mcp/tools/insight.js.map +1 -1
- package/dist/mcp/tools/user.d.ts.map +1 -1
- package/dist/mcp/tools/user.js +15 -13
- package/dist/mcp/tools/user.js.map +1 -1
- package/dist/mcp/tools/workflow-permissions.d.ts +2 -4
- package/dist/mcp/tools/workflow-permissions.d.ts.map +1 -1
- package/dist/mcp/tools/workflow-permissions.js +88 -97
- package/dist/mcp/tools/workflow-permissions.js.map +1 -1
- package/dist/mcp/tools/workflow.d.ts +9 -7
- package/dist/mcp/tools/workflow.d.ts.map +1 -1
- package/dist/mcp/tools/workflow.js +852 -860
- package/dist/mcp/tools/workflow.js.map +1 -1
- package/dist/mcp/utils/api-errors.d.ts.map +1 -1
- package/dist/mcp/utils/api-errors.js +2 -2
- package/dist/mcp/utils/api-errors.js.map +1 -1
- package/dist/mcp/utils/data-transformers.d.ts +0 -3
- package/dist/mcp/utils/data-transformers.d.ts.map +1 -1
- package/dist/mcp/utils/data-transformers.js +32 -5
- package/dist/mcp/utils/data-transformers.js.map +1 -1
- package/dist/mcp/utils/file-upload.d.ts.map +1 -1
- package/dist/mcp/utils/file-upload.js +1 -1
- package/dist/mcp/utils/file-upload.js.map +1 -1
- package/dist/mcp/utils/hailer-api-client.d.ts +81 -81
- package/dist/mcp/utils/hailer-api-client.d.ts.map +1 -1
- package/dist/mcp/utils/hailer-api-client.js +113 -103
- package/dist/mcp/utils/hailer-api-client.js.map +1 -1
- package/dist/mcp/utils/index.d.ts.map +1 -1
- package/dist/mcp/utils/index.js.map +1 -1
- package/dist/mcp/utils/logger.d.ts.map +1 -1
- package/dist/mcp/utils/logger.js.map +1 -1
- package/dist/mcp/utils/response-builder.d.ts.map +1 -1
- package/dist/mcp/utils/response-builder.js +8 -4
- package/dist/mcp/utils/response-builder.js.map +1 -1
- package/dist/mcp/utils/role-utils.d.ts.map +1 -1
- package/dist/mcp/utils/role-utils.js +6 -3
- package/dist/mcp/utils/role-utils.js.map +1 -1
- package/dist/mcp/utils/tool-helpers.d.ts.map +1 -1
- package/dist/mcp/utils/tool-helpers.js +2 -2
- package/dist/mcp/utils/tool-helpers.js.map +1 -1
- package/dist/mcp/utils/types.d.ts +2 -1
- package/dist/mcp/utils/types.d.ts.map +1 -1
- package/dist/mcp/utils/types.js.map +1 -1
- package/dist/mcp/webhook-handler.d.ts +43 -8
- package/dist/mcp/webhook-handler.d.ts.map +1 -1
- package/dist/mcp/webhook-handler.js +861 -116
- package/dist/mcp/webhook-handler.js.map +1 -1
- package/dist/mcp/workspace-admin-store.d.ts +49 -0
- package/dist/mcp/workspace-admin-store.d.ts.map +1 -0
- package/dist/mcp/workspace-admin-store.js +168 -0
- package/dist/mcp/workspace-admin-store.js.map +1 -0
- package/dist/mcp/workspace-cache.d.ts +2 -2
- package/dist/mcp/workspace-cache.d.ts.map +1 -1
- package/dist/mcp/workspace-cache.js +9 -5
- package/dist/mcp/workspace-cache.js.map +1 -1
- package/dist/mcp-server.d.ts +26 -11
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +367 -48
- package/dist/mcp-server.js.map +1 -1
- package/dist/plugins/vipunen/client.d.ts +41 -41
- package/dist/plugins/vipunen/client.d.ts.map +1 -1
- package/dist/plugins/vipunen/client.js +53 -48
- package/dist/plugins/vipunen/client.js.map +1 -1
- package/dist/plugins/vipunen/index.js.map +1 -1
- package/dist/plugins/vipunen/tools.d.ts.map +1 -1
- package/dist/plugins/vipunen/tools.js +6 -3
- package/dist/plugins/vipunen/tools.js.map +1 -1
- package/dist/public-chat/graduate.d.ts +29 -0
- package/dist/public-chat/graduate.d.ts.map +1 -0
- package/dist/public-chat/graduate.js +593 -0
- package/dist/public-chat/graduate.js.map +1 -0
- package/dist/public-chat/handler.d.ts +12 -0
- package/dist/public-chat/handler.d.ts.map +1 -0
- package/dist/public-chat/handler.js +183 -0
- package/dist/public-chat/handler.js.map +1 -0
- package/dist/public-chat/index.d.ts +16 -0
- package/dist/public-chat/index.d.ts.map +1 -0
- package/dist/public-chat/index.js +74 -0
- package/dist/public-chat/index.js.map +1 -0
- package/dist/public-chat/knowledge.d.ts +3 -0
- package/dist/public-chat/knowledge.d.ts.map +1 -0
- package/dist/public-chat/knowledge.js +1340 -0
- package/dist/public-chat/knowledge.js.map +1 -0
- package/dist/public-chat/rate-limit.d.ts +16 -0
- package/dist/public-chat/rate-limit.d.ts.map +1 -0
- package/dist/public-chat/rate-limit.js +51 -0
- package/dist/public-chat/rate-limit.js.map +1 -0
- package/dist/public-chat/session-store.d.ts +41 -0
- package/dist/public-chat/session-store.d.ts.map +1 -0
- package/dist/public-chat/session-store.js +95 -0
- package/dist/public-chat/session-store.js.map +1 -0
- package/dist/public-chat/studio-prewarm.d.ts +61 -0
- package/dist/public-chat/studio-prewarm.d.ts.map +1 -0
- package/dist/public-chat/studio-prewarm.js +162 -0
- package/dist/public-chat/studio-prewarm.js.map +1 -0
- package/dist/public-chat/system-prompt.d.ts +22 -0
- package/dist/public-chat/system-prompt.d.ts.map +1 -0
- package/dist/public-chat/system-prompt.js +435 -0
- package/dist/public-chat/system-prompt.js.map +1 -0
- package/package.json +15 -7
- package/scripts/build-public-chat-knowledge.py +101 -0
- package/scripts/smoke-public-chat-live.ts +148 -0
- package/scripts/smoke-public-chat.ts +110 -0
- package/.claude/CLAUDE.md +0 -126
- package/.claude/commands/app-squad.md +0 -131
- package/.claude/commands/audit-squad.md +0 -158
- package/.claude/commands/cleanup-squad.md +0 -98
- package/.claude/commands/config-squad.md +0 -106
- package/.claude/commands/crud-squad.md +0 -87
- package/.claude/commands/data-squad.md +0 -97
- package/.claude/commands/doc-squad.md +0 -65
- package/.claude/commands/help.md +0 -29
- package/.claude/commands/help:agents.md +0 -182
- package/.claude/commands/help:commands.md +0 -78
- package/.claude/commands/help:faq.md +0 -79
- package/.claude/commands/help:plugins.md +0 -50
- package/.claude/commands/help:skills.md +0 -87
- package/.claude/commands/help:tools.md +0 -75
- package/.claude/commands/hotfix-squad.md +0 -112
- package/.claude/commands/integration-squad.md +0 -82
- package/.claude/commands/janitor-squad.md +0 -167
- package/.claude/commands/onboard-squad.md +0 -130
- package/.claude/commands/swarm.md +0 -210
- package/.claude/commands/tool-builder.md +0 -39
- package/.claude/skills/publish-hailer-app/SKILL.md +0 -280
- package/dist/CLAUDE.md +0 -370
- package/dist/agents/bot-manager.d.ts +0 -48
- package/dist/agents/bot-manager.d.ts.map +0 -1
- package/dist/agents/bot-manager.js +0 -254
- package/dist/agents/bot-manager.js.map +0 -1
- package/dist/agents/bug-fixer/ai.d.ts +0 -80
- package/dist/agents/bug-fixer/ai.d.ts.map +0 -1
- package/dist/agents/bug-fixer/ai.js +0 -466
- package/dist/agents/bug-fixer/ai.js.map +0 -1
- package/dist/agents/bug-fixer/bot.d.ts +0 -92
- package/dist/agents/bug-fixer/bot.d.ts.map +0 -1
- package/dist/agents/bug-fixer/bot.js +0 -687
- package/dist/agents/bug-fixer/bot.js.map +0 -1
- package/dist/agents/bug-fixer/config.d.ts +0 -21
- package/dist/agents/bug-fixer/config.d.ts.map +0 -1
- package/dist/agents/bug-fixer/config.js +0 -218
- package/dist/agents/bug-fixer/config.js.map +0 -1
- package/dist/agents/bug-fixer/files.d.ts +0 -67
- package/dist/agents/bug-fixer/files.d.ts.map +0 -1
- package/dist/agents/bug-fixer/files.js +0 -386
- package/dist/agents/bug-fixer/files.js.map +0 -1
- package/dist/agents/bug-fixer/git.d.ts +0 -48
- package/dist/agents/bug-fixer/git.d.ts.map +0 -1
- package/dist/agents/bug-fixer/git.js +0 -298
- package/dist/agents/bug-fixer/git.js.map +0 -1
- package/dist/agents/bug-fixer/index.d.ts +0 -103
- package/dist/agents/bug-fixer/index.d.ts.map +0 -1
- package/dist/agents/bug-fixer/index.js +0 -262
- package/dist/agents/bug-fixer/index.js.map +0 -1
- package/dist/agents/bug-fixer/lsp.d.ts +0 -113
- package/dist/agents/bug-fixer/lsp.d.ts.map +0 -1
- package/dist/agents/bug-fixer/lsp.js +0 -485
- package/dist/agents/bug-fixer/lsp.js.map +0 -1
- package/dist/agents/bug-fixer/monitor.d.ts +0 -123
- package/dist/agents/bug-fixer/monitor.d.ts.map +0 -1
- package/dist/agents/bug-fixer/monitor.js +0 -629
- package/dist/agents/bug-fixer/monitor.js.map +0 -1
- package/dist/agents/bug-fixer/prompt.d.ts +0 -5
- package/dist/agents/bug-fixer/prompt.d.ts.map +0 -1
- package/dist/agents/bug-fixer/prompt.js +0 -94
- package/dist/agents/bug-fixer/prompt.js.map +0 -1
- package/dist/agents/bug-fixer/registries/pending-classification.d.ts +0 -28
- package/dist/agents/bug-fixer/registries/pending-classification.d.ts.map +0 -1
- package/dist/agents/bug-fixer/registries/pending-classification.js +0 -50
- package/dist/agents/bug-fixer/registries/pending-classification.js.map +0 -1
- package/dist/agents/bug-fixer/registries/pending-fix.d.ts +0 -33
- package/dist/agents/bug-fixer/registries/pending-fix.d.ts.map +0 -1
- package/dist/agents/bug-fixer/registries/pending-fix.js +0 -64
- package/dist/agents/bug-fixer/registries/pending-fix.js.map +0 -1
- package/dist/agents/bug-fixer/registries/pending.d.ts +0 -27
- package/dist/agents/bug-fixer/registries/pending.d.ts.map +0 -1
- package/dist/agents/bug-fixer/registries/pending.js +0 -49
- package/dist/agents/bug-fixer/registries/pending.js.map +0 -1
- package/dist/agents/bug-fixer/specialist-daemon.d.ts +0 -88
- package/dist/agents/bug-fixer/specialist-daemon.d.ts.map +0 -1
- package/dist/agents/bug-fixer/specialist-daemon.js +0 -431
- package/dist/agents/bug-fixer/specialist-daemon.js.map +0 -1
- package/dist/agents/bug-fixer/specialist.d.ts +0 -47
- package/dist/agents/bug-fixer/specialist.d.ts.map +0 -1
- package/dist/agents/bug-fixer/specialist.js +0 -327
- package/dist/agents/bug-fixer/specialist.js.map +0 -1
- package/dist/agents/bug-fixer/types.d.ts +0 -123
- package/dist/agents/bug-fixer/types.d.ts.map +0 -1
- package/dist/agents/bug-fixer/types.js +0 -9
- package/dist/agents/bug-fixer/types.js.map +0 -1
- package/dist/agents/factory.d.ts +0 -172
- package/dist/agents/factory.d.ts.map +0 -1
- package/dist/agents/factory.js +0 -706
- package/dist/agents/factory.js.map +0 -1
- package/dist/agents/hailer-expert/index.d.ts +0 -8
- package/dist/agents/hailer-expert/index.d.ts.map +0 -1
- package/dist/agents/hailer-expert/index.js +0 -14
- package/dist/agents/hailer-expert/index.js.map +0 -1
- package/dist/agents/hal/daemon.d.ts +0 -174
- package/dist/agents/hal/daemon.d.ts.map +0 -1
- package/dist/agents/hal/daemon.js +0 -1385
- package/dist/agents/hal/daemon.js.map +0 -1
- package/dist/agents/hal/definitions.d.ts +0 -42
- package/dist/agents/hal/definitions.d.ts.map +0 -1
- package/dist/agents/hal/definitions.js +0 -300
- package/dist/agents/hal/definitions.js.map +0 -1
- package/dist/agents/hal/index.d.ts +0 -3
- package/dist/agents/hal/index.d.ts.map +0 -1
- package/dist/agents/hal/index.js +0 -8
- package/dist/agents/hal/index.js.map +0 -1
- package/dist/agents/index.d.ts +0 -18
- package/dist/agents/index.d.ts.map +0 -1
- package/dist/agents/index.js +0 -48
- package/dist/agents/index.js.map +0 -1
- package/dist/agents/shared/base.d.ts +0 -253
- package/dist/agents/shared/base.d.ts.map +0 -1
- package/dist/agents/shared/base.js +0 -1122
- package/dist/agents/shared/base.js.map +0 -1
- package/dist/agents/shared/schemas/action-schema.d.ts +0 -62
- package/dist/agents/shared/schemas/action-schema.d.ts.map +0 -1
- package/dist/agents/shared/schemas/action-schema.js +0 -483
- package/dist/agents/shared/schemas/action-schema.js.map +0 -1
- package/dist/agents/shared/services/agent-registry.d.ts +0 -108
- package/dist/agents/shared/services/agent-registry.d.ts.map +0 -1
- package/dist/agents/shared/services/agent-registry.js +0 -469
- package/dist/agents/shared/services/agent-registry.js.map +0 -1
- package/dist/agents/shared/services/conversation-manager.d.ts +0 -57
- package/dist/agents/shared/services/conversation-manager.d.ts.map +0 -1
- package/dist/agents/shared/services/conversation-manager.js +0 -168
- package/dist/agents/shared/services/conversation-manager.js.map +0 -1
- package/dist/agents/shared/services/mcp-client.d.ts +0 -56
- package/dist/agents/shared/services/mcp-client.d.ts.map +0 -1
- package/dist/agents/shared/services/mcp-client.js +0 -124
- package/dist/agents/shared/services/mcp-client.js.map +0 -1
- package/dist/agents/shared/services/message-classifier.d.ts +0 -37
- package/dist/agents/shared/services/message-classifier.d.ts.map +0 -1
- package/dist/agents/shared/services/message-classifier.js +0 -203
- package/dist/agents/shared/services/message-classifier.js.map +0 -1
- package/dist/agents/shared/services/message-formatter.d.ts +0 -89
- package/dist/agents/shared/services/message-formatter.d.ts.map +0 -1
- package/dist/agents/shared/services/message-formatter.js +0 -390
- package/dist/agents/shared/services/message-formatter.js.map +0 -1
- package/dist/agents/shared/services/session-logger.d.ts +0 -162
- package/dist/agents/shared/services/session-logger.d.ts.map +0 -1
- package/dist/agents/shared/services/session-logger.js +0 -724
- package/dist/agents/shared/services/session-logger.js.map +0 -1
- package/dist/agents/shared/services/structured-output-executor.d.ts +0 -88
- package/dist/agents/shared/services/structured-output-executor.d.ts.map +0 -1
- package/dist/agents/shared/services/structured-output-executor.js +0 -296
- package/dist/agents/shared/services/structured-output-executor.js.map +0 -1
- package/dist/agents/shared/services/token-billing.d.ts +0 -72
- package/dist/agents/shared/services/token-billing.d.ts.map +0 -1
- package/dist/agents/shared/services/token-billing.js +0 -198
- package/dist/agents/shared/services/token-billing.js.map +0 -1
- package/dist/agents/shared/services/tool-executor.d.ts +0 -43
- package/dist/agents/shared/services/tool-executor.d.ts.map +0 -1
- package/dist/agents/shared/services/tool-executor.js +0 -175
- package/dist/agents/shared/services/tool-executor.js.map +0 -1
- package/dist/agents/shared/services/typing-indicator.d.ts +0 -24
- package/dist/agents/shared/services/typing-indicator.d.ts.map +0 -1
- package/dist/agents/shared/services/typing-indicator.js +0 -54
- package/dist/agents/shared/services/typing-indicator.js.map +0 -1
- package/dist/agents/shared/services/workspace-schema-cache.d.ts +0 -122
- package/dist/agents/shared/services/workspace-schema-cache.d.ts.map +0 -1
- package/dist/agents/shared/services/workspace-schema-cache.js +0 -507
- package/dist/agents/shared/services/workspace-schema-cache.js.map +0 -1
- package/dist/agents/shared/specialist.d.ts +0 -91
- package/dist/agents/shared/specialist.d.ts.map +0 -1
- package/dist/agents/shared/specialist.js +0 -399
- package/dist/agents/shared/specialist.js.map +0 -1
- package/dist/agents/shared/tool-schema-loader.d.ts +0 -65
- package/dist/agents/shared/tool-schema-loader.d.ts.map +0 -1
- package/dist/agents/shared/tool-schema-loader.js +0 -238
- package/dist/agents/shared/tool-schema-loader.js.map +0 -1
- package/dist/agents/shared/types.d.ts +0 -190
- package/dist/agents/shared/types.d.ts.map +0 -1
- package/dist/agents/shared/types.js +0 -13
- package/dist/agents/shared/types.js.map +0 -1
- package/dist/bot/bot-config.d.ts +0 -37
- package/dist/bot/bot-config.d.ts.map +0 -1
- package/dist/bot/bot-config.js +0 -219
- package/dist/bot/bot-config.js.map +0 -1
- package/dist/bot/services/__tests__/permission-guard.test.d.ts +0 -2
- package/dist/bot/services/__tests__/permission-guard.test.d.ts.map +0 -1
- package/dist/bot/services/__tests__/permission-guard.test.js +0 -357
- package/dist/bot/services/__tests__/permission-guard.test.js.map +0 -1
- package/dist/bot/services/session-logger.d.ts +0 -162
- package/dist/bot/services/session-logger.d.ts.map +0 -1
- package/dist/bot/services/session-logger.js +0 -724
- package/dist/bot/services/session-logger.js.map +0 -1
- package/dist/bot/services/workspace-schema-cache.d.ts +0 -122
- package/dist/bot/services/workspace-schema-cache.d.ts.map +0 -1
- package/dist/bot/services/workspace-schema-cache.js +0 -506
- package/dist/bot/services/workspace-schema-cache.js.map +0 -1
- package/dist/bot-config/tools.d.ts +0 -28
- package/dist/bot-config/tools.d.ts.map +0 -1
- package/dist/bot-config/tools.js +0 -279
- package/dist/bot-config/tools.js.map +0 -1
- package/dist/client/agents/base.d.ts +0 -207
- package/dist/client/agents/base.d.ts.map +0 -1
- package/dist/client/agents/base.js +0 -744
- package/dist/client/agents/base.js.map +0 -1
- package/dist/client/agents/definitions.d.ts +0 -53
- package/dist/client/agents/definitions.d.ts.map +0 -1
- package/dist/client/agents/definitions.js +0 -263
- package/dist/client/agents/definitions.js.map +0 -1
- package/dist/client/agents/orchestrator.d.ts +0 -141
- package/dist/client/agents/orchestrator.d.ts.map +0 -1
- package/dist/client/agents/orchestrator.js +0 -1062
- package/dist/client/agents/orchestrator.js.map +0 -1
- package/dist/client/agents/specialist.d.ts +0 -86
- package/dist/client/agents/specialist.d.ts.map +0 -1
- package/dist/client/agents/specialist.js +0 -340
- package/dist/client/agents/specialist.js.map +0 -1
- package/dist/client/bot-entrypoint.d.ts +0 -7
- package/dist/client/bot-entrypoint.d.ts.map +0 -1
- package/dist/client/bot-entrypoint.js +0 -103
- package/dist/client/bot-entrypoint.js.map +0 -1
- package/dist/client/bot-manager.d.ts +0 -44
- package/dist/client/bot-manager.d.ts.map +0 -1
- package/dist/client/bot-manager.js +0 -173
- package/dist/client/bot-manager.js.map +0 -1
- package/dist/client/bot-runner.d.ts +0 -35
- package/dist/client/bot-runner.d.ts.map +0 -1
- package/dist/client/bot-runner.js +0 -188
- package/dist/client/bot-runner.js.map +0 -1
- package/dist/client/chat-agent-daemon.d.ts +0 -464
- package/dist/client/chat-agent-daemon.d.ts.map +0 -1
- package/dist/client/chat-agent-daemon.js +0 -1774
- package/dist/client/chat-agent-daemon.js.map +0 -1
- package/dist/client/daemon-factory.d.ts +0 -106
- package/dist/client/daemon-factory.d.ts.map +0 -1
- package/dist/client/daemon-factory.js +0 -301
- package/dist/client/daemon-factory.js.map +0 -1
- package/dist/client/factory.d.ts +0 -111
- package/dist/client/factory.d.ts.map +0 -1
- package/dist/client/factory.js +0 -314
- package/dist/client/factory.js.map +0 -1
- package/dist/client/index.d.ts +0 -17
- package/dist/client/index.d.ts.map +0 -1
- package/dist/client/index.js +0 -38
- package/dist/client/index.js.map +0 -1
- package/dist/client/multi-bot-manager.d.ts +0 -42
- package/dist/client/multi-bot-manager.d.ts.map +0 -1
- package/dist/client/multi-bot-manager.js +0 -161
- package/dist/client/multi-bot-manager.js.map +0 -1
- package/dist/client/orchestrator-daemon.d.ts +0 -87
- package/dist/client/orchestrator-daemon.d.ts.map +0 -1
- package/dist/client/orchestrator-daemon.js +0 -444
- package/dist/client/orchestrator-daemon.js.map +0 -1
- package/dist/client/server.d.ts +0 -8
- package/dist/client/server.d.ts.map +0 -1
- package/dist/client/server.js +0 -251
- package/dist/client/server.js.map +0 -1
- package/dist/client/services/agent-registry.d.ts +0 -108
- package/dist/client/services/agent-registry.d.ts.map +0 -1
- package/dist/client/services/agent-registry.js +0 -630
- package/dist/client/services/agent-registry.js.map +0 -1
- package/dist/client/services/conversation-manager.d.ts +0 -50
- package/dist/client/services/conversation-manager.d.ts.map +0 -1
- package/dist/client/services/conversation-manager.js +0 -136
- package/dist/client/services/conversation-manager.js.map +0 -1
- package/dist/client/services/mcp-client.d.ts +0 -48
- package/dist/client/services/mcp-client.d.ts.map +0 -1
- package/dist/client/services/mcp-client.js +0 -105
- package/dist/client/services/mcp-client.js.map +0 -1
- package/dist/client/services/message-classifier.d.ts +0 -37
- package/dist/client/services/message-classifier.d.ts.map +0 -1
- package/dist/client/services/message-classifier.js +0 -187
- package/dist/client/services/message-classifier.js.map +0 -1
- package/dist/client/services/message-formatter.d.ts +0 -84
- package/dist/client/services/message-formatter.d.ts.map +0 -1
- package/dist/client/services/message-formatter.js +0 -353
- package/dist/client/services/message-formatter.js.map +0 -1
- package/dist/client/services/session-logger.d.ts +0 -106
- package/dist/client/services/session-logger.d.ts.map +0 -1
- package/dist/client/services/session-logger.js +0 -446
- package/dist/client/services/session-logger.js.map +0 -1
- package/dist/client/services/tool-executor.d.ts +0 -41
- package/dist/client/services/tool-executor.d.ts.map +0 -1
- package/dist/client/services/tool-executor.js +0 -169
- package/dist/client/services/tool-executor.js.map +0 -1
- package/dist/client/services/workspace-schema-cache.d.ts +0 -149
- package/dist/client/services/workspace-schema-cache.d.ts.map +0 -1
- package/dist/client/services/workspace-schema-cache.js +0 -732
- package/dist/client/services/workspace-schema-cache.js.map +0 -1
- package/dist/client/specialist-daemon.d.ts +0 -77
- package/dist/client/specialist-daemon.d.ts.map +0 -1
- package/dist/client/specialist-daemon.js +0 -197
- package/dist/client/specialist-daemon.js.map +0 -1
- package/dist/client/specialists.d.ts +0 -53
- package/dist/client/specialists.d.ts.map +0 -1
- package/dist/client/specialists.js +0 -178
- package/dist/client/specialists.js.map +0 -1
- package/dist/client/tool-schema-loader.d.ts +0 -62
- package/dist/client/tool-schema-loader.d.ts.map +0 -1
- package/dist/client/tool-schema-loader.js +0 -232
- package/dist/client/tool-schema-loader.js.map +0 -1
- package/dist/client/types.d.ts +0 -327
- package/dist/client/types.d.ts.map +0 -1
- package/dist/client/types.js +0 -121
- package/dist/client/types.js.map +0 -1
- package/dist/commands/seed-config.d.ts +0 -9
- package/dist/commands/seed-config.d.ts.map +0 -1
- package/dist/commands/seed-config.js +0 -377
- package/dist/commands/seed-config.js.map +0 -1
- package/dist/commands/setup.d.ts +0 -11
- package/dist/commands/setup.d.ts.map +0 -1
- package/dist/commands/setup.js +0 -320
- package/dist/commands/setup.js.map +0 -1
- package/dist/lib/discussion-lock.d.ts +0 -42
- package/dist/lib/discussion-lock.d.ts.map +0 -1
- package/dist/lib/discussion-lock.js +0 -110
- package/dist/lib/discussion-lock.js.map +0 -1
- package/dist/mcp/signal-handler.d.ts +0 -82
- package/dist/mcp/signal-handler.d.ts.map +0 -1
- package/dist/mcp/signal-handler.js +0 -406
- package/dist/mcp/signal-handler.js.map +0 -1
- package/dist/mcp/tools/__tests__/discussion-forward.test.d.ts +0 -2
- package/dist/mcp/tools/__tests__/discussion-forward.test.d.ts.map +0 -1
- package/dist/mcp/tools/__tests__/discussion-forward.test.js +0 -218
- package/dist/mcp/tools/__tests__/discussion-forward.test.js.map +0 -1
- package/dist/mcp/tools/app-member.d.ts +0 -14
- package/dist/mcp/tools/app-member.d.ts.map +0 -1
- package/dist/mcp/tools/app-member.js +0 -195
- package/dist/mcp/tools/app-member.js.map +0 -1
- package/dist/mcp/tools/app-scaffold.d.ts +0 -14
- package/dist/mcp/tools/app-scaffold.d.ts.map +0 -1
- package/dist/mcp/tools/app-scaffold.js +0 -581
- package/dist/mcp/tools/app-scaffold.js.map +0 -1
- package/dist/mcp/tools/bot-config/constants.d.ts +0 -23
- package/dist/mcp/tools/bot-config/constants.d.ts.map +0 -1
- package/dist/mcp/tools/bot-config/constants.js +0 -94
- package/dist/mcp/tools/bot-config/constants.js.map +0 -1
- package/dist/mcp/tools/bot-config/core.d.ts +0 -253
- package/dist/mcp/tools/bot-config/core.d.ts.map +0 -1
- package/dist/mcp/tools/bot-config/core.js +0 -2456
- package/dist/mcp/tools/bot-config/core.js.map +0 -1
- package/dist/mcp/tools/bot-config/index.d.ts +0 -10
- package/dist/mcp/tools/bot-config/index.d.ts.map +0 -1
- package/dist/mcp/tools/bot-config/index.js +0 -59
- package/dist/mcp/tools/bot-config/index.js.map +0 -1
- package/dist/mcp/tools/bot-config/tools.d.ts +0 -7
- package/dist/mcp/tools/bot-config/tools.d.ts.map +0 -1
- package/dist/mcp/tools/bot-config/tools.js +0 -15
- package/dist/mcp/tools/bot-config/tools.js.map +0 -1
- package/dist/mcp/tools/bot-config/types.d.ts +0 -50
- package/dist/mcp/tools/bot-config/types.d.ts.map +0 -1
- package/dist/mcp/tools/bot-config/types.js +0 -6
- package/dist/mcp/tools/bot-config/types.js.map +0 -1
- package/dist/mcp/tools/bug-fixer-tools.d.ts +0 -45
- package/dist/mcp/tools/bug-fixer-tools.d.ts.map +0 -1
- package/dist/mcp/tools/bug-fixer-tools.js +0 -1096
- package/dist/mcp/tools/bug-fixer-tools.js.map +0 -1
- package/dist/mcp/tools/document.d.ts +0 -11
- package/dist/mcp/tools/document.d.ts.map +0 -1
- package/dist/mcp/tools/document.js +0 -741
- package/dist/mcp/tools/document.js.map +0 -1
- package/dist/mcp/tools/investigate.d.ts +0 -9
- package/dist/mcp/tools/investigate.d.ts.map +0 -1
- package/dist/mcp/tools/investigate.js +0 -254
- package/dist/mcp/tools/investigate.js.map +0 -1
- package/dist/mcp/utils/pagination.d.ts +0 -40
- package/dist/mcp/utils/pagination.d.ts.map +0 -1
- package/dist/mcp/utils/pagination.js +0 -55
- package/dist/mcp/utils/pagination.js.map +0 -1
- package/dist/modules/bug-reports/bug-config.d.ts +0 -25
- package/dist/modules/bug-reports/bug-config.d.ts.map +0 -1
- package/dist/modules/bug-reports/bug-config.js +0 -187
- package/dist/modules/bug-reports/bug-config.js.map +0 -1
- package/dist/modules/bug-reports/bug-monitor.d.ts +0 -108
- package/dist/modules/bug-reports/bug-monitor.d.ts.map +0 -1
- package/dist/modules/bug-reports/bug-monitor.js +0 -510
- package/dist/modules/bug-reports/bug-monitor.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-agent.d.ts +0 -58
- package/dist/modules/bug-reports/giuseppe-agent.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-agent.js +0 -467
- package/dist/modules/bug-reports/giuseppe-agent.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-ai.d.ts +0 -83
- package/dist/modules/bug-reports/giuseppe-ai.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-ai.js +0 -466
- package/dist/modules/bug-reports/giuseppe-ai.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-bot.d.ts +0 -110
- package/dist/modules/bug-reports/giuseppe-bot.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-bot.js +0 -804
- package/dist/modules/bug-reports/giuseppe-bot.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-daemon.d.ts +0 -80
- package/dist/modules/bug-reports/giuseppe-daemon.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-daemon.js +0 -617
- package/dist/modules/bug-reports/giuseppe-daemon.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-files.d.ts +0 -64
- package/dist/modules/bug-reports/giuseppe-files.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-files.js +0 -375
- package/dist/modules/bug-reports/giuseppe-files.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-git.d.ts +0 -48
- package/dist/modules/bug-reports/giuseppe-git.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-git.js +0 -298
- package/dist/modules/bug-reports/giuseppe-git.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-lsp.d.ts +0 -113
- package/dist/modules/bug-reports/giuseppe-lsp.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-lsp.js +0 -485
- package/dist/modules/bug-reports/giuseppe-lsp.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-prompt.d.ts +0 -5
- package/dist/modules/bug-reports/giuseppe-prompt.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-prompt.js +0 -94
- package/dist/modules/bug-reports/giuseppe-prompt.js.map +0 -1
- package/dist/modules/bug-reports/index.d.ts +0 -77
- package/dist/modules/bug-reports/index.d.ts.map +0 -1
- package/dist/modules/bug-reports/index.js +0 -215
- package/dist/modules/bug-reports/index.js.map +0 -1
- package/dist/modules/bug-reports/pending-classification-registry.d.ts +0 -28
- package/dist/modules/bug-reports/pending-classification-registry.d.ts.map +0 -1
- package/dist/modules/bug-reports/pending-classification-registry.js +0 -50
- package/dist/modules/bug-reports/pending-classification-registry.js.map +0 -1
- package/dist/modules/bug-reports/pending-fix-registry.d.ts +0 -30
- package/dist/modules/bug-reports/pending-fix-registry.d.ts.map +0 -1
- package/dist/modules/bug-reports/pending-fix-registry.js +0 -42
- package/dist/modules/bug-reports/pending-fix-registry.js.map +0 -1
- package/dist/modules/bug-reports/pending-registry.d.ts +0 -27
- package/dist/modules/bug-reports/pending-registry.d.ts.map +0 -1
- package/dist/modules/bug-reports/pending-registry.js +0 -49
- package/dist/modules/bug-reports/pending-registry.js.map +0 -1
- package/dist/modules/bug-reports/types.d.ts +0 -123
- package/dist/modules/bug-reports/types.d.ts.map +0 -1
- package/dist/modules/bug-reports/types.js +0 -9
- package/dist/modules/bug-reports/types.js.map +0 -1
- package/dist/plugins/bug-fixer/index.d.ts +0 -2
- package/dist/plugins/bug-fixer/index.d.ts.map +0 -1
- package/dist/plugins/bug-fixer/index.js +0 -18
- package/dist/plugins/bug-fixer/index.js.map +0 -1
- package/dist/plugins/bug-fixer/tools.d.ts +0 -45
- package/dist/plugins/bug-fixer/tools.d.ts.map +0 -1
- package/dist/plugins/bug-fixer/tools.js +0 -1096
- package/dist/plugins/bug-fixer/tools.js.map +0 -1
- package/dist/plugins/vipunen/__tests__/tools.test.d.ts +0 -10
- package/dist/plugins/vipunen/__tests__/tools.test.d.ts.map +0 -1
- package/dist/plugins/vipunen/__tests__/tools.test.js +0 -646
- package/dist/plugins/vipunen/__tests__/tools.test.js.map +0 -1
- package/dist/routes/agents.d.ts +0 -44
- package/dist/routes/agents.d.ts.map +0 -1
- package/dist/routes/agents.js +0 -311
- package/dist/routes/agents.js.map +0 -1
- package/dist/services/agent-credential-store.d.ts +0 -73
- package/dist/services/agent-credential-store.d.ts.map +0 -1
- package/dist/services/agent-credential-store.js +0 -212
- package/dist/services/agent-credential-store.js.map +0 -1
- package/dist/stdio-server.d.ts +0 -14
- package/dist/stdio-server.d.ts.map +0 -1
- package/dist/stdio-server.js +0 -101
- package/dist/stdio-server.js.map +0 -1
- package/dist/workspace/context.d.ts +0 -148
- package/dist/workspace/context.d.ts.map +0 -1
- package/dist/workspace/context.js +0 -339
- package/dist/workspace/context.js.map +0 -1
- package/dist/workspace/credentials.d.ts +0 -55
- package/dist/workspace/credentials.d.ts.map +0 -1
- package/dist/workspace/credentials.js +0 -239
- package/dist/workspace/credentials.js.map +0 -1
- package/dist/workspace/index.d.ts +0 -21
- package/dist/workspace/index.d.ts.map +0 -1
- package/dist/workspace/index.js +0 -45
- package/dist/workspace/index.js.map +0 -1
- package/dist/workspace/loader.d.ts +0 -27
- package/dist/workspace/loader.d.ts.map +0 -1
- package/dist/workspace/loader.js +0 -222
- package/dist/workspace/loader.js.map +0 -1
- package/dist/workspace/schema.d.ts +0 -37
- package/dist/workspace/schema.d.ts.map +0 -1
- package/dist/workspace/schema.js +0 -192
- package/dist/workspace/schema.js.map +0 -1
package/dist/bot/bot.js
CHANGED
|
@@ -9,13 +9,49 @@
|
|
|
9
9
|
* - buildSystemPrompt: LLM system prompt construction
|
|
10
10
|
* - ConversationManager, MessageClassifier, MessageFormatterService, etc.
|
|
11
11
|
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
12
45
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
46
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
47
|
};
|
|
15
48
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.Bot = void 0;
|
|
49
|
+
exports.Bot = exports.ActivityGoneError = void 0;
|
|
50
|
+
const v8 = __importStar(require("v8"));
|
|
17
51
|
const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
|
|
18
52
|
const tool_registry_1 = require("../mcp/tool-registry");
|
|
53
|
+
const tool_profiles_1 = require("../mcp/tool-profiles");
|
|
54
|
+
const hailer_rpc_1 = require("../mcp/hailer-rpc");
|
|
19
55
|
const hailer_clients_1 = require("../mcp/hailer-clients");
|
|
20
56
|
const hailer_api_client_1 = require("../mcp/utils/hailer-api-client");
|
|
21
57
|
const types_1 = require("../mcp/utils/types");
|
|
@@ -24,43 +60,201 @@ const tool_executor_1 = require("./tool-executor");
|
|
|
24
60
|
const workspace_overview_1 = require("./workspace-overview");
|
|
25
61
|
const operation_logger_1 = require("./operation-logger");
|
|
26
62
|
const services_1 = require("./services");
|
|
63
|
+
const bot_config_1 = require("../bot-config");
|
|
27
64
|
const logger_1 = require("../lib/logger");
|
|
65
|
+
const config_1 = require("../config");
|
|
28
66
|
// ===== CONSTANTS =====
|
|
67
|
+
/**
|
|
68
|
+
* Parse the optional `seedContext` field on the bot config — a JSON array
|
|
69
|
+
* of prior chat turns from the public demo — into Anthropic message
|
|
70
|
+
* params suitable for prepending to the self-intro request. Caps the
|
|
71
|
+
* count so a misbehaving caller can't blow the context budget.
|
|
72
|
+
*
|
|
73
|
+
* Returns `[]` for missing, malformed, or empty input; the bot falls
|
|
74
|
+
* back to the generic intro path in that case.
|
|
75
|
+
*/
|
|
76
|
+
const SEED_TURNS_MAX = 24;
|
|
77
|
+
function parseSeedTurns(raw, log) {
|
|
78
|
+
const empty = { turns: [], viewedSlides: [] };
|
|
79
|
+
if (!raw) {
|
|
80
|
+
return empty;
|
|
81
|
+
}
|
|
82
|
+
let parsed;
|
|
83
|
+
try {
|
|
84
|
+
parsed = JSON.parse(raw);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
log.warn('seedContext: JSON parse failed — skipping', {
|
|
88
|
+
err: err instanceof Error ? err.message : String(err),
|
|
89
|
+
});
|
|
90
|
+
return empty;
|
|
91
|
+
}
|
|
92
|
+
// Two supported shapes:
|
|
93
|
+
// - bare array of {role, content} turns (legacy)
|
|
94
|
+
// - object { turns: [...], viewedSlides: [...] } (current)
|
|
95
|
+
let turnSource;
|
|
96
|
+
let viewedSlides = [];
|
|
97
|
+
if (Array.isArray(parsed)) {
|
|
98
|
+
turnSource = parsed;
|
|
99
|
+
}
|
|
100
|
+
else if (parsed && typeof parsed === 'object') {
|
|
101
|
+
turnSource = parsed.turns;
|
|
102
|
+
const slidesRaw = parsed.viewedSlides;
|
|
103
|
+
if (Array.isArray(slidesRaw)) {
|
|
104
|
+
viewedSlides = slidesRaw.filter((id) => typeof id === 'string' && id.length > 0);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (!Array.isArray(turnSource)) {
|
|
108
|
+
return { turns: [], viewedSlides };
|
|
109
|
+
}
|
|
110
|
+
const turns = [];
|
|
111
|
+
for (const item of turnSource) {
|
|
112
|
+
if (!item || typeof item !== 'object') {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const role = item.role;
|
|
116
|
+
const content = item.content;
|
|
117
|
+
if ((role !== 'user' && role !== 'assistant') || typeof content !== 'string' || !content) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
turns.push({ role, content });
|
|
121
|
+
if (turns.length >= SEED_TURNS_MAX) {
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return { turns, viewedSlides };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Thrown by Bot.start() when the bot's own Agent Directory activity has been
|
|
129
|
+
* deleted in Hailer. BotManager catches this and discards the bot without
|
|
130
|
+
* adding it to the running set; the entry has already been removed from
|
|
131
|
+
* .bot-config/{workspaceId}.json by the time this is thrown.
|
|
132
|
+
*/
|
|
133
|
+
class ActivityGoneError extends Error {
|
|
134
|
+
activityId;
|
|
135
|
+
workspaceId;
|
|
136
|
+
constructor(activityId, workspaceId) {
|
|
137
|
+
super(`Activity ${activityId} no longer exists in workspace ${workspaceId}`);
|
|
138
|
+
this.activityId = activityId;
|
|
139
|
+
this.workspaceId = workspaceId;
|
|
140
|
+
this.name = 'ActivityGoneError';
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
exports.ActivityGoneError = ActivityGoneError;
|
|
29
144
|
const WRITE_TOOLS = new Set(['create_activity', 'update_activity']);
|
|
30
145
|
const DISCUSSION_TOOLS = new Set([
|
|
31
146
|
'fetch_discussion_messages', 'fetch_previous_discussion_messages',
|
|
32
147
|
'add_discussion_message', 'invite_discussion_members', 'get_activity_from_discussion',
|
|
33
148
|
]);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
'
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const MODEL_HAIKU = 'claude-haiku-4-5-20251001';
|
|
50
|
-
const MODEL_SONNET = 'claude-sonnet-4-5-20250929';
|
|
149
|
+
/** Model-facing text for a pre-execution permission denial. */
|
|
150
|
+
function permissionDeniedMessage(denied) {
|
|
151
|
+
if (denied.reason === 'bot-scope') {
|
|
152
|
+
return `Permission denied: This bot does not have access to workflow ${denied.workflowId}.`;
|
|
153
|
+
}
|
|
154
|
+
if (denied.reason === 'unverified-insight') {
|
|
155
|
+
return `Permission denied: Could not verify which workflows insight ${denied.workflowId} reads from — `
|
|
156
|
+
+ 'it may have been deleted. Call list_insights to see valid insight IDs, then retry.';
|
|
157
|
+
}
|
|
158
|
+
return `Permission denied: You do not have access to workflow ${denied.workflowId}.`;
|
|
159
|
+
}
|
|
160
|
+
const MODEL_HAIKU = 'claude-haiku-4-5';
|
|
161
|
+
const MODEL_SONNET = 'claude-sonnet-4-6';
|
|
162
|
+
const MAX_TOOL_RESULT_CHARS = 40000;
|
|
163
|
+
const MAX_PROMPT_TRIM_ATTEMPTS = 5;
|
|
51
164
|
const IMAGE_MIME_TYPES = new Set(['image/jpeg', 'image/png', 'image/gif', 'image/webp']);
|
|
52
165
|
const DOCUMENT_MIME_TYPES = new Set(['application/pdf']);
|
|
53
166
|
const TEXT_MIME_TYPES = new Set(['text/plain', 'text/csv', 'text/html', 'text/markdown', 'application/json', 'application/xml']);
|
|
167
|
+
const EXCEL_MIME_TYPES = new Set([
|
|
168
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx only
|
|
169
|
+
]);
|
|
170
|
+
const WORD_MIME_TYPES = new Set([
|
|
171
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
|
|
172
|
+
]);
|
|
54
173
|
const MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
174
|
+
const MAX_OFFICE_FILE_SIZE = 10 * 1024 * 1024;
|
|
175
|
+
const OFFICE_TEXT_CAP = 512 * 1024;
|
|
176
|
+
const HEAP_BACKPRESSURE_THRESHOLD = 0.7;
|
|
177
|
+
function fileSizeLimit(mime) {
|
|
178
|
+
return EXCEL_MIME_TYPES.has(mime) || WORD_MIME_TYPES.has(mime) ? MAX_OFFICE_FILE_SIZE : MAX_FILE_SIZE;
|
|
179
|
+
}
|
|
180
|
+
const ATTACHMENT_KINDS = [
|
|
181
|
+
{ label: 'Image', trailing: 'included below for vision', matches: (mimeType) => IMAGE_MIME_TYPES.has(mimeType) },
|
|
182
|
+
{ label: 'Document', trailing: 'included below', matches: (mimeType) => DOCUMENT_MIME_TYPES.has(mimeType) || TEXT_MIME_TYPES.has(mimeType) },
|
|
183
|
+
{ label: 'Spreadsheet', trailing: 'included below as CSV per sheet', matches: (mimeType) => EXCEL_MIME_TYPES.has(mimeType) },
|
|
184
|
+
{ label: 'Word document', trailing: 'included below as plain text', matches: (mimeType) => WORD_MIME_TYPES.has(mimeType) },
|
|
185
|
+
];
|
|
186
|
+
function describeAttachment(mime, filename, fileId) {
|
|
187
|
+
const matched = ATTACHMENT_KINDS.find((kind) => kind.matches(mime));
|
|
188
|
+
if (!matched) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
return `[${matched.label} attached: ${filename} (fileId: ${fileId}) — ${matched.trailing}]`;
|
|
192
|
+
}
|
|
193
|
+
function isSupportedMime(mime) {
|
|
194
|
+
return IMAGE_MIME_TYPES.has(mime) || DOCUMENT_MIME_TYPES.has(mime) || TEXT_MIME_TYPES.has(mime)
|
|
195
|
+
|| EXCEL_MIME_TYPES.has(mime) || WORD_MIME_TYPES.has(mime);
|
|
196
|
+
}
|
|
197
|
+
function isOfficeMime(mime) {
|
|
198
|
+
return EXCEL_MIME_TYPES.has(mime) || WORD_MIME_TYPES.has(mime);
|
|
199
|
+
}
|
|
200
|
+
function capText(text) {
|
|
201
|
+
return text.length > OFFICE_TEXT_CAP ? text.slice(0, OFFICE_TEXT_CAP) + '\n\n[...content truncated...]' : text;
|
|
202
|
+
}
|
|
203
|
+
function isHeapUnderPressure() {
|
|
204
|
+
const { heapUsed } = process.memoryUsage();
|
|
205
|
+
const heapLimit = v8.getHeapStatistics().heap_size_limit;
|
|
206
|
+
return heapUsed / heapLimit > HEAP_BACKPRESSURE_THRESHOLD;
|
|
207
|
+
}
|
|
208
|
+
function cellToCsv(value) {
|
|
209
|
+
if (value === null || value === undefined) {
|
|
210
|
+
return '';
|
|
211
|
+
}
|
|
212
|
+
if (value instanceof Date) {
|
|
213
|
+
return value.toISOString();
|
|
214
|
+
}
|
|
215
|
+
if (typeof value === 'object') {
|
|
216
|
+
const v = value;
|
|
217
|
+
if (typeof v.result !== 'undefined') {
|
|
218
|
+
return cellToCsv(v.result);
|
|
219
|
+
}
|
|
220
|
+
if (typeof v.text === 'string') {
|
|
221
|
+
return cellToCsv(v.text);
|
|
222
|
+
}
|
|
223
|
+
if (Array.isArray(v.richText)) {
|
|
224
|
+
return v.richText.map((rt) => rt.text || '').join('');
|
|
225
|
+
}
|
|
226
|
+
if (typeof v.error === 'string') {
|
|
227
|
+
return v.error;
|
|
228
|
+
}
|
|
229
|
+
return '';
|
|
230
|
+
}
|
|
231
|
+
const s = String(value);
|
|
232
|
+
return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
|
|
233
|
+
}
|
|
234
|
+
// Global mutex — serialize Office downloads + parses across the pod to bound peak memory
|
|
235
|
+
let officeParseQueue = Promise.resolve();
|
|
236
|
+
function withOfficeParseLock(fn) {
|
|
237
|
+
const next = officeParseQueue.then(fn, fn);
|
|
238
|
+
officeParseQueue = next.catch(() => undefined);
|
|
239
|
+
return next;
|
|
240
|
+
}
|
|
241
|
+
const SONNET_ROUTE = { model: MODEL_SONNET, maxTokens: 16384 };
|
|
55
242
|
const TOOL_STATUS_LABELS = {
|
|
56
|
-
list_activities: 'Searching activities',
|
|
243
|
+
list_activities: 'Searching activities',
|
|
57
244
|
show_activity_by_id: 'Reading activity', create_activity: 'Creating activity',
|
|
58
|
-
update_activity: 'Updating activity',
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
245
|
+
update_activity: 'Updating activity',
|
|
246
|
+
describe_workflows: 'Reading workflows',
|
|
247
|
+
update_workflow_structure: 'Updating workflow structure',
|
|
248
|
+
run_insight: 'Running report', save_insight: 'Saving report',
|
|
249
|
+
search_workspace_users: 'Searching users',
|
|
62
250
|
fetch_discussion_messages: 'Reading messages', add_discussion_message: 'Sending message',
|
|
63
251
|
join_discussion: 'Joining discussion',
|
|
252
|
+
query_events: 'Loading events', manage_calendar: 'Managing calendars',
|
|
253
|
+
create_event: 'Creating event',
|
|
254
|
+
update_event: 'Updating event', delete_event: 'Deleting event',
|
|
255
|
+
respond_to_invite: 'Responding to invite',
|
|
256
|
+
set_workflow_permission: 'Updating workflow access',
|
|
257
|
+
manage_my_profile: 'Updating my profile',
|
|
64
258
|
};
|
|
65
259
|
// ===== BOT CLASS =====
|
|
66
260
|
class Bot {
|
|
@@ -97,37 +291,47 @@ class Bot {
|
|
|
97
291
|
workspaceUpdatedHandler = null;
|
|
98
292
|
cacheInvalidateHandler = null;
|
|
99
293
|
_connected = false;
|
|
100
|
-
// Config
|
|
101
294
|
config;
|
|
295
|
+
anthropicApiKey;
|
|
102
296
|
botManager;
|
|
103
|
-
constructor(config) {
|
|
297
|
+
constructor(config, runtime) {
|
|
104
298
|
this.config = {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
accessLevel: config.accessLevel || 'all',
|
|
111
|
-
allowedWorkflows: config.allowedWorkflows || [],
|
|
112
|
-
allowBotMessages: config.allowBotMessages || false,
|
|
299
|
+
...config,
|
|
300
|
+
accessLevel: config.accessLevel ?? 'all',
|
|
301
|
+
allowedWorkflows: config.allowedWorkflows ?? [],
|
|
302
|
+
allowBotMessages: config.allowBotMessages ?? false,
|
|
303
|
+
helperMode: config.helperMode ?? false,
|
|
113
304
|
};
|
|
114
|
-
this.
|
|
305
|
+
this.anthropicApiKey = runtime.anthropicApiKey;
|
|
306
|
+
this.botManager = runtime.botManager ?? null;
|
|
115
307
|
this._systemPrompt = config.systemPrompt;
|
|
116
|
-
this._responseMode = config.responseMode
|
|
308
|
+
this._responseMode = config.responseMode ?? 'always';
|
|
117
309
|
this.logger = (0, logger_1.createLogger)({ component: 'Bot' });
|
|
118
310
|
this.clientManager = new hailer_clients_1.HailerClientManager(config.apiHost, config.email, config.password);
|
|
119
|
-
this.toolExecutor = new tool_executor_1.ToolExecutor(
|
|
311
|
+
this.toolExecutor = new tool_executor_1.ToolExecutor(runtime.toolRegistry);
|
|
120
312
|
this.signalRouter = new services_1.SignalRouter(this.logger);
|
|
121
313
|
this.permissions = new services_1.BotPermissions(this.config.allowedWorkflows, this.logger);
|
|
122
314
|
this.workspaceRefresh = new services_1.WorkspaceRefresh(this.logger);
|
|
123
315
|
}
|
|
124
316
|
// Public accessors (used by BotManager for hot-reload)
|
|
125
|
-
get email() {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
get
|
|
129
|
-
|
|
130
|
-
|
|
317
|
+
get email() {
|
|
318
|
+
return this.config.email;
|
|
319
|
+
}
|
|
320
|
+
get password() {
|
|
321
|
+
return this.config.password;
|
|
322
|
+
}
|
|
323
|
+
get accessLevel() {
|
|
324
|
+
return this.config.accessLevel;
|
|
325
|
+
}
|
|
326
|
+
get connected() {
|
|
327
|
+
return this._connected;
|
|
328
|
+
}
|
|
329
|
+
get workspaceId() {
|
|
330
|
+
return this._workspaceId;
|
|
331
|
+
}
|
|
332
|
+
get botUserId() {
|
|
333
|
+
return this.userId;
|
|
334
|
+
}
|
|
131
335
|
updateSystemPrompt(prompt) {
|
|
132
336
|
this._systemPrompt = prompt;
|
|
133
337
|
this.logger.info('System prompt updated live', { hasPrompt: !!prompt });
|
|
@@ -136,21 +340,88 @@ class Bot {
|
|
|
136
340
|
this._responseMode = mode || 'always';
|
|
137
341
|
this.logger.info('Response mode updated live', { responseMode: this._responseMode });
|
|
138
342
|
}
|
|
343
|
+
updateHelperMode(helperMode) {
|
|
344
|
+
this.config.helperMode = !!helperMode;
|
|
345
|
+
this.logger.info('Helper mode updated live', { helperMode: this.config.helperMode });
|
|
346
|
+
}
|
|
139
347
|
// ===== LIFECYCLE =====
|
|
140
348
|
async start() {
|
|
141
|
-
if (this._connected)
|
|
349
|
+
if (this._connected) {
|
|
142
350
|
return;
|
|
351
|
+
}
|
|
143
352
|
this.logger.debug('Starting bot', { email: this.config.email });
|
|
144
353
|
// 1. Connect
|
|
145
354
|
this.client = await this.clientManager.connect();
|
|
146
355
|
this.config.password = ''; // Clear from memory — connection is established
|
|
147
356
|
// 2. Fetch workspace data + user in one call
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
357
|
+
const initFields = ['user', 'processes', 'users', 'network', 'networks', 'teams', 'groups'];
|
|
358
|
+
this.init = await this.client.socket.request(hailer_rpc_1.HailerRpc.Core.init, [initFields]);
|
|
359
|
+
try {
|
|
360
|
+
const pendingInvites = await this.client.socket.request(hailer_rpc_1.HailerRpc.User.inviteList, []);
|
|
361
|
+
if (pendingInvites?.length) {
|
|
362
|
+
for (const invite of pendingInvites) {
|
|
363
|
+
await this.client.socket.request(hailer_rpc_1.HailerRpc.User.inviteAccept, [invite.invite_key]);
|
|
364
|
+
await this.client.socket.request(hailer_rpc_1.HailerRpc.Core.switchEcosystem, [invite.cid]);
|
|
365
|
+
this.logger.info('Accepted workspace invite', { workspaceId: invite.cid, workspaceName: invite.network?.name });
|
|
366
|
+
}
|
|
367
|
+
this.init = await this.client.socket.request(hailer_rpc_1.HailerRpc.Core.init, [initFields]);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
catch (err) {
|
|
371
|
+
this.logger.warn('Failed to check/accept pending invites', { error: err instanceof Error ? err.message : err });
|
|
372
|
+
}
|
|
373
|
+
// Hailer drops password-auth users into their personal "My Hailer" ecosystem
|
|
374
|
+
// on each fresh login, even after they've accepted a workspace invite. Force
|
|
375
|
+
// the configured workspace as the active ecosystem so the bot operates where
|
|
376
|
+
// it was provisioned, not in its personal workspace.
|
|
377
|
+
if (this.config.workspaceId && this.init.network?._id !== this.config.workspaceId) {
|
|
378
|
+
const fromWorkspaceId = this.init.network?._id;
|
|
379
|
+
try {
|
|
380
|
+
await this.client.socket.request(hailer_rpc_1.HailerRpc.Core.switchEcosystem, [this.config.workspaceId]);
|
|
381
|
+
this.init = await this.client.socket.request(hailer_rpc_1.HailerRpc.Core.init, [initFields]);
|
|
382
|
+
this.logger.info('Switched to configured workspace', {
|
|
383
|
+
from: fromWorkspaceId, to: this.config.workspaceId,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
catch (err) {
|
|
387
|
+
this.logger.warn('Failed to switch to configured workspace', {
|
|
388
|
+
workspaceId: this.config.workspaceId,
|
|
389
|
+
error: err instanceof Error ? err.message : err,
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
// Self-prune: probe the bot's own Agent Directory activity. If the
|
|
394
|
+
// activity is gone (definitively deleted OR otherwise unreachable in
|
|
395
|
+
// a way that matches the gone signals), drop the local config entry
|
|
396
|
+
// so we stop trying to run this bot. The bot's Hailer user account
|
|
397
|
+
// is NEVER deleted from here — a previous version did, and the
|
|
398
|
+
// classifier shared a numeric code with "Permission denied" which
|
|
399
|
+
// caused mass user-account deletion on transient permission errors.
|
|
400
|
+
// Orphaned bot users are reaped separately by Hailer's inactive-user
|
|
401
|
+
// prune (out-of-band).
|
|
402
|
+
if (this.config.activityId && this.config.workspaceId) {
|
|
403
|
+
try {
|
|
404
|
+
await this.client.socket.request(hailer_rpc_1.HailerRpc.Activities.load, [this.config.activityId]);
|
|
405
|
+
}
|
|
406
|
+
catch (err) {
|
|
407
|
+
const shape = (0, bot_config_1.extractHailerError)(err);
|
|
408
|
+
if ((0, bot_config_1.isActivityGone)(shape)) {
|
|
409
|
+
this.logger.info('Self-probe: activity gone — pruning local config entry (keeping Hailer user)', {
|
|
410
|
+
activityId: this.config.activityId, workspaceId: this.config.workspaceId,
|
|
411
|
+
msg: shape.msg, code: shape.code,
|
|
412
|
+
});
|
|
413
|
+
this.pruneSelfFromConfig();
|
|
414
|
+
throw new ActivityGoneError(this.config.activityId, this.config.workspaceId);
|
|
415
|
+
}
|
|
416
|
+
this.logger.debug('Self-probe non-deletion error — continuing startup', {
|
|
417
|
+
activityId: this.config.activityId, msg: shape.msg, code: shape.code,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
151
421
|
this.userId = this.init.user?._id || '';
|
|
152
|
-
if (!this.userId)
|
|
422
|
+
if (!this.userId) {
|
|
153
423
|
throw new Error('Could not determine bot user ID');
|
|
424
|
+
}
|
|
154
425
|
(0, types_1.normalizeInitProcesses)(this.init);
|
|
155
426
|
this._workspaceId = this.init.network?._id || this.config.workspaceId;
|
|
156
427
|
// 3. Build caches
|
|
@@ -172,7 +443,7 @@ class Bot {
|
|
|
172
443
|
workflowNames: this.init.processes.map(p => p.name),
|
|
173
444
|
});
|
|
174
445
|
// 4. Anthropic client
|
|
175
|
-
this.anthropic = new sdk_1.default({ apiKey: this.
|
|
446
|
+
this.anthropic = new sdk_1.default({ apiKey: this.anthropicApiKey });
|
|
176
447
|
// 5. Services
|
|
177
448
|
const botConnection = {
|
|
178
449
|
client: this.client,
|
|
@@ -194,11 +465,13 @@ class Bot {
|
|
|
194
465
|
email: this.config.email, password: '', // Intentionally empty — cleared after connect
|
|
195
466
|
workspaceRoles: { [currentWorkspaceId]: 'admin' },
|
|
196
467
|
currentWorkspaceId, allowedGroups: [tool_registry_1.ToolGroup.READ, tool_registry_1.ToolGroup.WRITE, tool_registry_1.ToolGroup.BOT_INTERNAL],
|
|
468
|
+
botActivityId: this.config.activityId,
|
|
197
469
|
};
|
|
198
470
|
// 7. Wire workspace refresh
|
|
199
471
|
this.workspaceRefresh.setHandler(async (scopes) => {
|
|
200
|
-
if (!this.client || !this.init)
|
|
472
|
+
if (!this.client || !this.init) {
|
|
201
473
|
return;
|
|
474
|
+
}
|
|
202
475
|
const result = await services_1.WorkspaceRefresh.refresh(this.client, scopes, this.init, this.config.workspaceId, this.permissions, this.userContext, this.logger);
|
|
203
476
|
this.init = result.init;
|
|
204
477
|
this.workspaceCache = result.workspaceCache;
|
|
@@ -206,10 +479,17 @@ class Bot {
|
|
|
206
479
|
this._workspaceId = result.workspaceId;
|
|
207
480
|
});
|
|
208
481
|
// 8. Subscribe to signals
|
|
209
|
-
this.signalHandler = (data) =>
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
482
|
+
this.signalHandler = (data) => {
|
|
483
|
+
this.logger.info('Bot received messenger.new signal', {
|
|
484
|
+
discussion: data.discussion,
|
|
485
|
+
uid: data.uid,
|
|
486
|
+
msg_id: data.msg_id,
|
|
487
|
+
});
|
|
488
|
+
this.handleSignal({
|
|
489
|
+
type: 'messenger.new', data, timestamp: Date.now(),
|
|
490
|
+
workspaceId: data.sid,
|
|
491
|
+
});
|
|
492
|
+
};
|
|
213
493
|
this.clientManager.onSignal('messenger.new', this.signalHandler);
|
|
214
494
|
this.processUpdatedHandler = () => this.workspaceRefresh.schedule('processes');
|
|
215
495
|
this.workspaceUpdatedHandler = () => this.workspaceRefresh.schedule('network');
|
|
@@ -219,6 +499,285 @@ class Bot {
|
|
|
219
499
|
this.clientManager.onSignal('cache.invalidate', this.cacheInvalidateHandler);
|
|
220
500
|
this._connected = true;
|
|
221
501
|
this.logger.debug('Bot started', { userId: this.userId, workspaceId: this._workspaceId });
|
|
502
|
+
// Fire-and-forget: re-assert that the bot is following its own
|
|
503
|
+
// activity discussion on every startup. The self-intro path used to be
|
|
504
|
+
// the only caller of joinActivityDiscussion, but it short-circuits on
|
|
505
|
+
// `introPosted: true`, leaving bots that were unfollowed in the past
|
|
506
|
+
// (e.g. by the pre-fix raw activities.follow toggle, or by any other
|
|
507
|
+
// path that flipped their follow state) silently subscribed to nothing.
|
|
508
|
+
// Running joinActivityDiscussion here closes that loop — it's
|
|
509
|
+
// idempotent (no-op if already following).
|
|
510
|
+
this.ensureFollowingOwnDiscussion().catch((err) => {
|
|
511
|
+
const { msg, code } = (0, bot_config_1.extractHailerError)(err);
|
|
512
|
+
this.logger.warn('ensureFollowingOwnDiscussion threw (non-fatal)', { msg, code });
|
|
513
|
+
});
|
|
514
|
+
// Fire-and-forget self-introduction. One-shot per bot (persisted via
|
|
515
|
+
// BotEntry.introPosted), so restarts don't re-spam the discussion. Errors
|
|
516
|
+
// are logged inside the method — this catch is only a safety net.
|
|
517
|
+
this.introduceSelfIfNeeded().catch((err) => {
|
|
518
|
+
const { msg, code } = (0, bot_config_1.extractHailerError)(err);
|
|
519
|
+
this.logger.warn('Self-intro threw (non-fatal)', { msg, code });
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Re-join the bot's own activity discussion if (and only if) the bot has
|
|
524
|
+
* drifted out of it. Runs every startup so bots that lost their follow
|
|
525
|
+
* state (e.g. via the pre-51254a2 raw activities.follow toggle) recover.
|
|
526
|
+
*
|
|
527
|
+
* Reads the activity's `followers` list and skips the join when the bot's
|
|
528
|
+
* userId is already there. activities.follow is a toggle that emits a
|
|
529
|
+
* leave/join event on every call — even toggle-toggle pairs — so calling
|
|
530
|
+
* unconditionally pollutes the discussion with "left / joined" pairs on
|
|
531
|
+
* every restart (visible in the timeline after deploy → retire → deploy).
|
|
532
|
+
*/
|
|
533
|
+
async ensureFollowingOwnDiscussion() {
|
|
534
|
+
if (!this.config.activityId || !this.hailerApi || !this.userId) {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
try {
|
|
538
|
+
const activity = await this.hailerApi.fetchActivityById(this.config.activityId);
|
|
539
|
+
const followers = Array.isArray(activity?.followers) ? activity.followers : [];
|
|
540
|
+
if (followers.includes(this.userId)) {
|
|
541
|
+
this.logger.debug('Already following own discussion — skipping toggle', {
|
|
542
|
+
activityId: this.config.activityId,
|
|
543
|
+
});
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
await this.hailerApi.joinActivityDiscussion(this.config.activityId);
|
|
547
|
+
}
|
|
548
|
+
catch (err) {
|
|
549
|
+
const { msg, code } = (0, bot_config_1.extractHailerError)(err);
|
|
550
|
+
this.logger.debug('ensureFollowingOwnDiscussion failed (non-fatal)', { msg, code });
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Post a one-time greeting in the bot's own activity discussion explaining
|
|
555
|
+
* what users can ask the bot to change about itself (system prompt, etc.).
|
|
556
|
+
* Marks the entry's `introPosted` flag in `.bot-config` so subsequent
|
|
557
|
+
* restarts don't repeat the message.
|
|
558
|
+
*
|
|
559
|
+
* Follow state is handled separately by ensureFollowingOwnDiscussion()
|
|
560
|
+
* which runs on every startup. We don't flip `introPosted` until the send
|
|
561
|
+
* succeeds, so a permission failure on first start retries on the next
|
|
562
|
+
* start instead of silently giving up.
|
|
563
|
+
*/
|
|
564
|
+
async introduceSelfIfNeeded() {
|
|
565
|
+
if (!this.config.activityId || !this.config.workspaceId || !this.client) {
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
const cfg = (0, bot_config_1.loadWorkspaceConfigFile)(this.config.workspaceId);
|
|
569
|
+
const entry = cfg.bots.find((b) => b.activityId === this.config.activityId);
|
|
570
|
+
if (!entry) {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (entry.introPosted) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
let discussionId;
|
|
577
|
+
try {
|
|
578
|
+
const activity = await this.client.socket.request(hailer_rpc_1.HailerRpc.Activities.load, [this.config.activityId]);
|
|
579
|
+
discussionId = activity?.discussion;
|
|
580
|
+
}
|
|
581
|
+
catch (err) {
|
|
582
|
+
const { msg, code } = (0, bot_config_1.extractHailerError)(err);
|
|
583
|
+
this.logger.warn('Self-intro: activities.load failed', { msg, code });
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
if (!discussionId) {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
if (!this.anthropic) {
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
// Generate the intro via LLM so each bot speaks in its own voice. The
|
|
593
|
+
// bot's system prompt already explains its self-management capabilities,
|
|
594
|
+
// so a "pirate" bot greets in pirate voice while still mentioning users
|
|
595
|
+
// can change it.
|
|
596
|
+
const systemPrompt = (0, services_1.buildSystemPrompt)({
|
|
597
|
+
init: this.init, userId: this.userId,
|
|
598
|
+
workspaceOverview: this.workspaceOverview, customPrompt: this._systemPrompt,
|
|
599
|
+
helperMode: this.config.helperMode,
|
|
600
|
+
hasSeedContext: !!this.config.seedContext,
|
|
601
|
+
responseMode: this._responseMode,
|
|
602
|
+
accessLevel: this.config.accessLevel,
|
|
603
|
+
allowBotMessages: this.config.allowBotMessages,
|
|
604
|
+
});
|
|
605
|
+
const { turns: seedTurns, viewedSlides } = parseSeedTurns(this.config.seedContext, this.logger);
|
|
606
|
+
const hasSeed = seedTurns.length > 0;
|
|
607
|
+
// Map slide ids → short human labels for the prompt. Anything not in
|
|
608
|
+
// the map is dropped (defence against stale ids leaking through).
|
|
609
|
+
const SLIDE_LABEL = {
|
|
610
|
+
title: 'the Hailer overview cover',
|
|
611
|
+
what: 'what Hailer is in one line',
|
|
612
|
+
problem: 'the trackers-vs-chat problem framing',
|
|
613
|
+
'core-label': 'the core-concepts section',
|
|
614
|
+
workspaces: 'Workspaces',
|
|
615
|
+
workflows: 'Workflows',
|
|
616
|
+
activities: 'Activities',
|
|
617
|
+
discussions: 'Discussions',
|
|
618
|
+
'build-label': 'the build-and-extend section',
|
|
619
|
+
'apps-studio': 'Apps & Hailer Studio',
|
|
620
|
+
sdk: 'the Hailer SDK',
|
|
621
|
+
'sdk-code': 'the workflow-as-code example',
|
|
622
|
+
mcp: 'Hailer MCP',
|
|
623
|
+
insights: 'Insights & Automations',
|
|
624
|
+
closer: 'the closing one-platform statement',
|
|
625
|
+
};
|
|
626
|
+
const slideLabels = viewedSlides
|
|
627
|
+
.map((id) => SLIDE_LABEL[id])
|
|
628
|
+
.filter((s) => typeof s === 'string');
|
|
629
|
+
const slideHint = slideLabels.length > 0
|
|
630
|
+
? `\n\nAdditional signal: during the demo the visitor explicitly opened these overview slides — ${slideLabels.join(', ')}. Treat that as an interest signal. Weight your concrete suggestions toward those concepts when the demo conversation is ambiguous, but don't read more into it than "they paid attention here."`
|
|
631
|
+
: '';
|
|
632
|
+
// Only promise an automatic build when Studio session creation is
|
|
633
|
+
// configured for this deployment; otherwise nothing builds the
|
|
634
|
+
// workspace and the bot must not promise a build that never runs. The
|
|
635
|
+
// graduation flow gates createStudioSession on the same env var, so
|
|
636
|
+
// "build promised" matches "build attempted".
|
|
637
|
+
const studioBuilding = !!config_1.environment.STUDIO_SESSIONS_CREATE_URL;
|
|
638
|
+
const introInstruction = hasSeed
|
|
639
|
+
? (studioBuilding
|
|
640
|
+
? `You are being posted in your own activity discussion for the first time. The user just graduated from a public demo chat with you — the messages above are the conversation you both had there.
|
|
641
|
+
|
|
642
|
+
What this first message needs to do:
|
|
643
|
+
|
|
644
|
+
1. Greet them warmly and acknowledge you remember the demo. Be specific — name the thing they were exploring (e.g. "the plumbing-company job tracker you were sketching out" rather than "your business").
|
|
645
|
+
|
|
646
|
+
2. Tell them what's happening RIGHT NOW: based on that conversation, their workspace is being set up for them automatically — the workflow(s) to run that process, a few sample records so they can see it in action, and a custom app on top. It takes a couple of minutes. Do NOT offer to build it yourself and do NOT ask "want me to set this up?" — it is already being built. You are not the one building it; just let them know it's underway.
|
|
647
|
+
|
|
648
|
+
3. Tell them what comes next: as soon as the workflows are ready you'll walk them through their new workspace with a quick guided tour, so there's nothing they need to do yet — they can sit tight or keep chatting with you here.
|
|
649
|
+
|
|
650
|
+
4. Mention in passing that they can shape how you behave (tone, persona, language, even your picture) just by asking you here, and that account-level settings live in the AI Hub app.
|
|
651
|
+
|
|
652
|
+
Tone: conversational, friendly, reassuring. No section headers, no bullet lists. Keep it under ~150 words.`
|
|
653
|
+
: `You are being posted in your own activity discussion for the first time. The user just graduated from a public demo chat with you — the messages above are the conversation you both had there. NOTE: there is no automatic workspace builder running in this deployment, so YOU are how they get set up.
|
|
654
|
+
|
|
655
|
+
What this first message needs to do:
|
|
656
|
+
|
|
657
|
+
1. Greet them warmly and acknowledge you remember the demo. Be specific — name the thing they were exploring (e.g. "the plumbing-company job tracker you were sketching out" rather than "your business").
|
|
658
|
+
|
|
659
|
+
2. Scan the demo for concrete setup intent — a process with stages, or a list of records they want to manage. Offer to set it up for them now: be concrete, naming the phases you'd create (e.g. Quoted → Scheduled → In Progress → Invoiced → Paid) for a lifecycle, or describing it as a simple list for reference data. End with a clear yes/no like "Want me to set this up?" — don't start building unilaterally.
|
|
660
|
+
|
|
661
|
+
3. If the demo is too vague to start, ask ONE or TWO concrete clarifying questions instead.
|
|
662
|
+
|
|
663
|
+
4. Mention in passing that they can shape how you behave (tone, persona, language, even your picture) just by asking you here, and that account-level settings live in the AI Hub app.
|
|
664
|
+
|
|
665
|
+
Tone: conversational, friendly, action-oriented. No section headers; short bullets are fine only when naming proposed phases or fields. Keep it under ~180 words.`)
|
|
666
|
+
: `You are being posted in your own activity discussion for the first time. Introduce yourself briefly in your own voice.
|
|
667
|
+
|
|
668
|
+
CRITICAL: do NOT invent a backstory or claim to be a real person, celebrity, or fictional character based on your name alone. Your name was just chosen by the user — they may have meant a specific person/character, or they may have just liked the sound of it. If you don't have explicit persona instructions, acknowledge your name but be honest that you're a fresh assistant without a defined persona yet, and ask what kind of assistant they want you to be (or invite them to configure you).
|
|
669
|
+
|
|
670
|
+
In all cases, let the user know they can change how you behave — your tone, persona, language, dos and donts, even your profile picture — just by asking you here in chat. They can also ask to see your current configuration. For account-level settings (credentials, who can talk to you, etc.) point them at the AI Hub app.
|
|
671
|
+
|
|
672
|
+
Tell them how to actually get your attention: describe your current response mode in one sentence (you can see it in <your-settings>). For example, if you only respond to mentions or replies, say so — otherwise they'll wonder why you're silent in shared discussions. Mention that they can switch you to a different mode in AI Hub if it doesn't suit them.
|
|
673
|
+
|
|
674
|
+
Keep it short and conversational. No bullet lists, no headers.`;
|
|
675
|
+
const introInstructionFinal = introInstruction + slideHint;
|
|
676
|
+
const messages = [
|
|
677
|
+
...seedTurns,
|
|
678
|
+
{ role: 'user', content: introInstructionFinal },
|
|
679
|
+
];
|
|
680
|
+
let response;
|
|
681
|
+
try {
|
|
682
|
+
response = await this.anthropic.messages.create({
|
|
683
|
+
model: MODEL_HAIKU,
|
|
684
|
+
max_tokens: 400,
|
|
685
|
+
temperature: 0.7,
|
|
686
|
+
system: systemPrompt,
|
|
687
|
+
messages,
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
catch (err) {
|
|
691
|
+
this.logger.warn('Self-intro: LLM call failed', {
|
|
692
|
+
activityId: this.config.activityId,
|
|
693
|
+
error: err instanceof Error ? err.message : String(err),
|
|
694
|
+
});
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
const text = response.content
|
|
698
|
+
.filter((b) => b.type === 'text')
|
|
699
|
+
.map((b) => b.text)
|
|
700
|
+
.join('')
|
|
701
|
+
.trim();
|
|
702
|
+
if (!text) {
|
|
703
|
+
this.logger.warn('Self-intro: empty LLM response', { activityId: this.config.activityId });
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
// Bill the intro generation to the workspace — same as any other LLM call.
|
|
707
|
+
if (this.tokenBilling && this._workspaceId) {
|
|
708
|
+
const usage = response.usage;
|
|
709
|
+
const cacheCreation = usage.cache_creation_input_tokens || 0;
|
|
710
|
+
const cacheRead = usage.cache_read_input_tokens || 0;
|
|
711
|
+
const cost = this.tokenBilling.calculateCost(usage.input_tokens, usage.output_tokens, cacheCreation, cacheRead, MODEL_HAIKU);
|
|
712
|
+
this.tokenBilling.burnTokens({
|
|
713
|
+
workspaceId: this._workspaceId,
|
|
714
|
+
inputTokens: usage.input_tokens, outputTokens: usage.output_tokens,
|
|
715
|
+
cacheCreationTokens: cacheCreation, cacheReadTokens: cacheRead, costUsd: cost,
|
|
716
|
+
sessionId: discussionId, model: MODEL_HAIKU,
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
try {
|
|
720
|
+
await this.client.socket.request(hailer_rpc_1.HailerRpc.Messenger.send, [{ msg: text }, discussionId]);
|
|
721
|
+
}
|
|
722
|
+
catch (err) {
|
|
723
|
+
const { msg: errMsg, code } = (0, bot_config_1.extractHailerError)(err);
|
|
724
|
+
this.logger.warn('Self-intro: messenger.send failed', {
|
|
725
|
+
activityId: this.config.activityId,
|
|
726
|
+
discussionId,
|
|
727
|
+
msg: errMsg,
|
|
728
|
+
code,
|
|
729
|
+
});
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
entry.introPosted = true;
|
|
733
|
+
(0, bot_config_1.saveWorkspaceConfigFile)(cfg);
|
|
734
|
+
(0, bot_config_1.invalidateConfigCache)();
|
|
735
|
+
this.logger.info('Posted self-intro in own discussion', {
|
|
736
|
+
activityId: this.config.activityId,
|
|
737
|
+
discussionId,
|
|
738
|
+
length: text.length,
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Teardown: stop the bot's websocket and live state. We intentionally do
|
|
743
|
+
* NOT delete the Hailer user account from here — that was previously a
|
|
744
|
+
* source of mass user-account deletion when the gone-classifier fired on
|
|
745
|
+
* transient permission errors. Orphaned bot users are reaped out-of-band
|
|
746
|
+
* by Hailer's inactive-user prune.
|
|
747
|
+
*/
|
|
748
|
+
async destroy() {
|
|
749
|
+
await this.stop();
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Remove this bot's entry from .bot-config/{workspaceId}.json. Called when
|
|
753
|
+
* the bot's own activity has been deleted in Hailer (detected via the
|
|
754
|
+
* self-probe in start()). Idempotent — safe if the entry is already gone.
|
|
755
|
+
*/
|
|
756
|
+
pruneSelfFromConfig() {
|
|
757
|
+
if (!this.config.activityId || !this.config.workspaceId) {
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
try {
|
|
761
|
+
const cfg = (0, bot_config_1.loadWorkspaceConfigFile)(this.config.workspaceId);
|
|
762
|
+
const before = cfg.bots.length;
|
|
763
|
+
cfg.bots = cfg.bots.filter((b) => b.activityId !== this.config.activityId);
|
|
764
|
+
if (cfg.bots.length === before) {
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
(0, bot_config_1.saveWorkspaceConfigFile)(cfg);
|
|
768
|
+
(0, bot_config_1.invalidateConfigCache)();
|
|
769
|
+
this.logger.info('Pruned self from bot config', {
|
|
770
|
+
activityId: this.config.activityId,
|
|
771
|
+
workspaceId: this.config.workspaceId,
|
|
772
|
+
remaining: cfg.bots.length,
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
catch (err) {
|
|
776
|
+
this.logger.warn('Failed to prune self from bot config', {
|
|
777
|
+
activityId: this.config.activityId,
|
|
778
|
+
error: err instanceof Error ? err.message : err,
|
|
779
|
+
});
|
|
780
|
+
}
|
|
222
781
|
}
|
|
223
782
|
async stop() {
|
|
224
783
|
this.logger.debug('Stopping bot');
|
|
@@ -247,8 +806,9 @@ class Bot {
|
|
|
247
806
|
}
|
|
248
807
|
// ===== SIGNAL HANDLING =====
|
|
249
808
|
async handleSignal(signal) {
|
|
250
|
-
if (!this._connected || !this.messageClassifier)
|
|
809
|
+
if (!this._connected || !this.messageClassifier) {
|
|
251
810
|
return;
|
|
811
|
+
}
|
|
252
812
|
try {
|
|
253
813
|
const rawMsgId = signal.data.msg_id;
|
|
254
814
|
const discussionId = signal.data.discussion;
|
|
@@ -257,23 +817,27 @@ class Bot {
|
|
|
257
817
|
this.logger.warn('messenger.new signal has no dedup key');
|
|
258
818
|
return;
|
|
259
819
|
}
|
|
260
|
-
if (this.signalRouter.isDuplicate(dedupKey))
|
|
820
|
+
if (this.signalRouter.isDuplicate(dedupKey)) {
|
|
261
821
|
return;
|
|
822
|
+
}
|
|
262
823
|
const message = await this.messageClassifier.extractIncomingMessage(signal);
|
|
263
824
|
if (!message) {
|
|
264
|
-
if (rawMsgId)
|
|
825
|
+
if (rawMsgId) {
|
|
265
826
|
this.signalRouter.removeDedupKey(rawMsgId);
|
|
827
|
+
}
|
|
266
828
|
return;
|
|
267
829
|
}
|
|
268
830
|
// Self-message guard — always skip own messages
|
|
269
|
-
if (message.senderId === this.userId)
|
|
831
|
+
if (message.senderId === this.userId) {
|
|
270
832
|
return;
|
|
833
|
+
}
|
|
271
834
|
// Bot-to-bot guard
|
|
272
835
|
if (this.botManager && this._workspaceId) {
|
|
273
836
|
const botUserIds = this.botManager.getBotUserIdsForWorkspace(this._workspaceId);
|
|
274
837
|
if (botUserIds.has(message.senderId)) {
|
|
275
|
-
if (!this.config.allowBotMessages)
|
|
276
|
-
return;
|
|
838
|
+
if (!this.config.allowBotMessages) {
|
|
839
|
+
return;
|
|
840
|
+
} // Hard block if not opted in
|
|
277
841
|
// Only respond to bot messages if explicitly mentioned or replied to
|
|
278
842
|
if (!message.isMention && !message.isReplyToBot) {
|
|
279
843
|
this.logger.debug('Ignoring bot message - no mention or reply', {
|
|
@@ -304,27 +868,31 @@ class Bot {
|
|
|
304
868
|
}
|
|
305
869
|
}
|
|
306
870
|
// Rate limiting
|
|
307
|
-
if (this.signalRouter.isRateLimited(message.discussionId))
|
|
871
|
+
if (this.signalRouter.isRateLimited(message.discussionId)) {
|
|
308
872
|
return;
|
|
873
|
+
}
|
|
309
874
|
// Layer 1: Workspace membership
|
|
310
875
|
if (!this.permissions.isMember(message.senderId)) {
|
|
311
876
|
this.logger.debug('Ignoring message - not a workspace member', { senderId: message.senderId });
|
|
312
|
-
if (rawMsgId)
|
|
877
|
+
if (rawMsgId) {
|
|
313
878
|
this.signalRouter.removeDedupKey(rawMsgId);
|
|
879
|
+
}
|
|
314
880
|
return;
|
|
315
881
|
}
|
|
316
882
|
// Layer 2: Access level
|
|
317
883
|
if (!this.permissions.meetsAccessLevel(message.senderId, this.config.accessLevel)) {
|
|
318
884
|
this.logger.debug('Ignoring message - access level not met', { senderId: message.senderId });
|
|
319
|
-
if (rawMsgId)
|
|
885
|
+
if (rawMsgId) {
|
|
320
886
|
this.signalRouter.removeDedupKey(rawMsgId);
|
|
887
|
+
}
|
|
321
888
|
return;
|
|
322
889
|
}
|
|
323
890
|
// Engagement logic
|
|
324
891
|
const state = this.signalRouter.getOrCreateState(message.discussionId);
|
|
325
892
|
state.contextBuffer.push(message);
|
|
326
|
-
if (!this.signalRouter.checkTrigger(message, this._responseMode))
|
|
893
|
+
if (!this.signalRouter.checkTrigger(message, this._responseMode)) {
|
|
327
894
|
return;
|
|
895
|
+
}
|
|
328
896
|
const isExplicit = this.signalRouter.isExplicitTrigger(message);
|
|
329
897
|
if (state.state === 'idle') {
|
|
330
898
|
if (isExplicit || this._responseMode === 'always') {
|
|
@@ -336,8 +904,9 @@ class Bot {
|
|
|
336
904
|
return;
|
|
337
905
|
}
|
|
338
906
|
}
|
|
339
|
-
if (this._responseMode !== 'always' && !isExplicit)
|
|
907
|
+
if (this._responseMode !== 'always' && !isExplicit) {
|
|
340
908
|
return;
|
|
909
|
+
}
|
|
341
910
|
// Process if not already running
|
|
342
911
|
if (!this.signalRouter.processingDiscussions.has(message.discussionId)) {
|
|
343
912
|
this.processDiscussion(message.discussionId).catch(err => {
|
|
@@ -352,17 +921,20 @@ class Bot {
|
|
|
352
921
|
}
|
|
353
922
|
// ===== DISCUSSION PROCESSING =====
|
|
354
923
|
async processDiscussion(discussionId) {
|
|
355
|
-
if (this.signalRouter.processingDiscussions.has(discussionId))
|
|
924
|
+
if (this.signalRouter.processingDiscussions.has(discussionId)) {
|
|
356
925
|
return;
|
|
926
|
+
}
|
|
357
927
|
this.signalRouter.processingDiscussions.add(discussionId);
|
|
358
928
|
const state = this.signalRouter.getOrCreateState(discussionId);
|
|
359
929
|
try {
|
|
360
930
|
while (true) {
|
|
361
931
|
const messages = state.contextBuffer.splice(0);
|
|
362
|
-
if (messages.length === 0)
|
|
932
|
+
if (messages.length === 0) {
|
|
363
933
|
break;
|
|
364
|
-
|
|
934
|
+
}
|
|
935
|
+
if (messages.length > 1) {
|
|
365
936
|
this.opLogger.coalesce(discussionId, messages.length);
|
|
937
|
+
}
|
|
366
938
|
// Build conversation entry
|
|
367
939
|
const conversation = this.conversationManager.getConversation(discussionId);
|
|
368
940
|
const parts = messages.map(msg => this.formatIncomingMessage(msg));
|
|
@@ -380,8 +952,9 @@ class Bot {
|
|
|
380
952
|
const primaryMessage = messages[messages.length - 1];
|
|
381
953
|
state.lastProgressTime = 0;
|
|
382
954
|
state.abortController = new AbortController();
|
|
383
|
-
for (const msg of messages)
|
|
955
|
+
for (const msg of messages) {
|
|
384
956
|
this.opLogger.messageIn(msg.discussionId, msg.senderName, msg.content);
|
|
957
|
+
}
|
|
385
958
|
let responded;
|
|
386
959
|
try {
|
|
387
960
|
responded = await this.processMessage(primaryMessage, state.abortController.signal);
|
|
@@ -404,12 +977,14 @@ class Bot {
|
|
|
404
977
|
break;
|
|
405
978
|
}
|
|
406
979
|
}
|
|
407
|
-
if (state.contextBuffer.length === 0)
|
|
980
|
+
if (state.contextBuffer.length === 0) {
|
|
408
981
|
break;
|
|
982
|
+
}
|
|
409
983
|
if (state.state === 'idle') {
|
|
410
984
|
const hasExplicit = state.contextBuffer.some(m => this.signalRouter.isExplicitTrigger(m));
|
|
411
|
-
if (!hasExplicit)
|
|
985
|
+
if (!hasExplicit) {
|
|
412
986
|
break;
|
|
987
|
+
}
|
|
413
988
|
state.state = 'engaged';
|
|
414
989
|
state.consecutiveNonResponses = 0;
|
|
415
990
|
this.opLogger.engage(discussionId, 'reengaged');
|
|
@@ -443,8 +1018,9 @@ class Bot {
|
|
|
443
1018
|
return await this.runLlmLoop(message, route, signal);
|
|
444
1019
|
}
|
|
445
1020
|
catch (error) {
|
|
446
|
-
if (error instanceof sdk_1.default.APIUserAbortError)
|
|
1021
|
+
if (error instanceof sdk_1.default.APIUserAbortError) {
|
|
447
1022
|
throw error;
|
|
1023
|
+
}
|
|
448
1024
|
this.logger.error('Message processing failed', error);
|
|
449
1025
|
this.typingIndicator?.stop(message.discussionId);
|
|
450
1026
|
conversation.length = snapshotLength;
|
|
@@ -454,6 +1030,14 @@ class Bot {
|
|
|
454
1030
|
// ===== MODEL ROUTING =====
|
|
455
1031
|
async routeMessage(message, conversation, signal) {
|
|
456
1032
|
const defaultRoute = { model: MODEL_HAIKU, maxTokens: 2000 };
|
|
1033
|
+
// Any file attachment forces COMPLEX: reading/analysing an attachment plus the
|
|
1034
|
+
// tool calls that typically follow easily blows Haiku's 2000-token budget,
|
|
1035
|
+
// and a truncated response with an unfinished tool_use poisons the conversation.
|
|
1036
|
+
if (message.fileAttachments && message.fileAttachments.length > 0) {
|
|
1037
|
+
const route = { ...SONNET_ROUTE };
|
|
1038
|
+
this.opLogger.route(message.discussionId, 'COMPLEX (attachments)', route.model, message.content);
|
|
1039
|
+
return route;
|
|
1040
|
+
}
|
|
457
1041
|
try {
|
|
458
1042
|
const wsName = this.init?.network?.name || 'Workspace';
|
|
459
1043
|
const recentContext = this.getRecentContext(conversation);
|
|
@@ -465,7 +1049,7 @@ class Bot {
|
|
|
465
1049
|
this.trackTokenUsage(response, message, MODEL_HAIKU);
|
|
466
1050
|
const text = response.content.filter((b) => b.type === 'text').map(b => b.text).join('').trim().toUpperCase();
|
|
467
1051
|
if (text.includes('COMPLEX')) {
|
|
468
|
-
const route = {
|
|
1052
|
+
const route = { ...SONNET_ROUTE };
|
|
469
1053
|
this.opLogger.route(message.discussionId, 'COMPLEX', route.model, message.content);
|
|
470
1054
|
return route;
|
|
471
1055
|
}
|
|
@@ -488,8 +1072,9 @@ class Bot {
|
|
|
488
1072
|
else if (Array.isArray(msg.content)) {
|
|
489
1073
|
text = msg.content.filter((b) => b.type === 'text').map((b) => b.text).join(' ');
|
|
490
1074
|
}
|
|
491
|
-
if (!text)
|
|
1075
|
+
if (!text) {
|
|
492
1076
|
continue;
|
|
1077
|
+
}
|
|
493
1078
|
lines.unshift(`${msg.role === 'user' ? 'User' : 'Assistant'}: ${text.length > 200 ? text.slice(0, 200) + '...' : text}`);
|
|
494
1079
|
count++;
|
|
495
1080
|
}
|
|
@@ -505,38 +1090,54 @@ class Bot {
|
|
|
505
1090
|
const systemPrompt = (0, services_1.buildSystemPrompt)({
|
|
506
1091
|
init: this.init, userId: this.userId,
|
|
507
1092
|
workspaceOverview: this.workspaceOverview, customPrompt: this._systemPrompt,
|
|
508
|
-
botExchangeContext,
|
|
1093
|
+
botExchangeContext, helperMode: this.config.helperMode,
|
|
1094
|
+
hasSeedContext: !!this.config.seedContext,
|
|
1095
|
+
responseMode: this._responseMode,
|
|
1096
|
+
accessLevel: this.config.accessLevel,
|
|
1097
|
+
allowBotMessages: this.config.allowBotMessages,
|
|
509
1098
|
});
|
|
510
1099
|
const tools = this.cachedTools || this.getAnthropicTools();
|
|
511
1100
|
for (let i = 0;; i++) {
|
|
512
|
-
const cachedConversation = this.conversationManager.prepareForCaching(conversation);
|
|
513
1101
|
this.typingIndicator?.updateStatus(message.discussionId, i === 0 ? 'Thinking' : 'Processing');
|
|
514
1102
|
let response;
|
|
515
1103
|
let llmStart = Date.now();
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
messages: cachedConversation, tools,
|
|
521
|
-
}, { signal });
|
|
522
|
-
}
|
|
523
|
-
catch (error) {
|
|
524
|
-
if (error instanceof sdk_1.default.APIUserAbortError) {
|
|
525
|
-
this.cleanupIncompleteExchange(conversation);
|
|
526
|
-
this.opLogger.interrupt(message.discussionId, 'new message received');
|
|
527
|
-
return false;
|
|
528
|
-
}
|
|
529
|
-
if (route.model !== MODEL_HAIKU) {
|
|
530
|
-
this.logger.warn('Sonnet failed, falling back to Haiku');
|
|
531
|
-
route = { model: MODEL_HAIKU, maxTokens: 2000 };
|
|
532
|
-
llmStart = Date.now();
|
|
1104
|
+
let trimAttempts = 0;
|
|
1105
|
+
while (true) {
|
|
1106
|
+
try {
|
|
1107
|
+
const cachedConversation = this.conversationManager.prepareForCaching(conversation);
|
|
533
1108
|
response = await this.anthropic.messages.create({
|
|
534
|
-
model:
|
|
1109
|
+
model: route.model, max_tokens: route.maxTokens, temperature: 0,
|
|
535
1110
|
system: [{ type: 'text', text: systemPrompt, cache_control: { type: 'ephemeral' } }],
|
|
536
1111
|
messages: cachedConversation, tools,
|
|
537
1112
|
}, { signal });
|
|
1113
|
+
break;
|
|
538
1114
|
}
|
|
539
|
-
|
|
1115
|
+
catch (error) {
|
|
1116
|
+
if (error instanceof sdk_1.default.APIUserAbortError) {
|
|
1117
|
+
this.cleanupIncompleteExchange(conversation);
|
|
1118
|
+
this.opLogger.interrupt(message.discussionId, 'new message received');
|
|
1119
|
+
return false;
|
|
1120
|
+
}
|
|
1121
|
+
const isPromptTooLong = error instanceof sdk_1.default.BadRequestError &&
|
|
1122
|
+
/prompt is too long/i.test(error.message || '');
|
|
1123
|
+
if (isPromptTooLong && trimAttempts < MAX_PROMPT_TRIM_ATTEMPTS && conversation.length >= 4) {
|
|
1124
|
+
trimAttempts++;
|
|
1125
|
+
const dropped = conversation.splice(0, 2);
|
|
1126
|
+
this.logger.warn('Prompt too long — dropped oldest conversation pair', {
|
|
1127
|
+
attempt: trimAttempts,
|
|
1128
|
+
droppedRoles: dropped.map(msg => msg.role),
|
|
1129
|
+
remainingMessages: conversation.length,
|
|
1130
|
+
model: route.model,
|
|
1131
|
+
});
|
|
1132
|
+
llmStart = Date.now();
|
|
1133
|
+
continue;
|
|
1134
|
+
}
|
|
1135
|
+
if (route.model !== MODEL_HAIKU && !isPromptTooLong) {
|
|
1136
|
+
this.logger.warn('Sonnet failed, falling back to Haiku');
|
|
1137
|
+
route = { model: MODEL_HAIKU, maxTokens: 2000 };
|
|
1138
|
+
llmStart = Date.now();
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
540
1141
|
throw error;
|
|
541
1142
|
}
|
|
542
1143
|
}
|
|
@@ -546,12 +1147,37 @@ class Bot {
|
|
|
546
1147
|
const cacheRead = usage.cache_read_input_tokens || 0;
|
|
547
1148
|
const totalInput = usage.input_tokens + cacheRead + (usage.cache_creation_input_tokens || 0);
|
|
548
1149
|
this.opLogger.llmCall(message.discussionId, route.model, usage.input_tokens, usage.output_tokens, totalInput > 0 ? Math.round((cacheRead / totalInput) * 100) : 0, llmDuration);
|
|
549
|
-
if (!response.content || response.content.length === 0)
|
|
1150
|
+
if (!response.content || response.content.length === 0) {
|
|
550
1151
|
break;
|
|
1152
|
+
}
|
|
551
1153
|
conversation.push({ role: 'assistant', content: response.content });
|
|
552
|
-
// Truncation guard
|
|
1154
|
+
// Truncation guard. When the response is cut off at max_tokens
|
|
1155
|
+
// AND the truncated assistant content contains tool_use blocks,
|
|
1156
|
+
// Anthropic's API requires the very next message to carry
|
|
1157
|
+
// matching tool_result blocks — otherwise every subsequent
|
|
1158
|
+
// request fails with `tool_use ids were found without tool_result
|
|
1159
|
+
// blocks immediately after`. We can't actually execute the
|
|
1160
|
+
// truncated tools (JSON inputs may be malformed, and the model
|
|
1161
|
+
// expected all of them to run together), so we synthesize error
|
|
1162
|
+
// tool_results that tell the model exactly why nothing ran.
|
|
553
1163
|
if (response.stop_reason === 'max_tokens') {
|
|
554
|
-
|
|
1164
|
+
const truncatedToolUses = response.content.filter((b) => b.type === 'tool_use');
|
|
1165
|
+
const reminder = 'Your previous response was truncated because it exceeded the output token limit. Break it into smaller batches of 25-50 items per tool call.';
|
|
1166
|
+
if (truncatedToolUses.length > 0) {
|
|
1167
|
+
const errorResults = truncatedToolUses.map(b => ({
|
|
1168
|
+
type: 'tool_result',
|
|
1169
|
+
tool_use_id: b.id,
|
|
1170
|
+
content: 'Tool call was truncated before it could run because the response exceeded the output token limit. Try again with a smaller batch.',
|
|
1171
|
+
is_error: true,
|
|
1172
|
+
}));
|
|
1173
|
+
conversation.push({
|
|
1174
|
+
role: 'user',
|
|
1175
|
+
content: [...errorResults, { type: 'text', text: reminder }],
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
else {
|
|
1179
|
+
conversation.push({ role: 'user', content: reminder });
|
|
1180
|
+
}
|
|
555
1181
|
continue;
|
|
556
1182
|
}
|
|
557
1183
|
// Tool calls
|
|
@@ -565,7 +1191,7 @@ class Bot {
|
|
|
565
1191
|
if (route.model === MODEL_HAIKU) {
|
|
566
1192
|
const failedCount = toolResults.filter(r => r.is_error).length;
|
|
567
1193
|
if (failedCount >= 2) {
|
|
568
|
-
route = {
|
|
1194
|
+
route = { ...SONNET_ROUTE };
|
|
569
1195
|
await this.sendMessage(message.discussionId, 'Switching to a more capable model to handle this.');
|
|
570
1196
|
}
|
|
571
1197
|
}
|
|
@@ -595,25 +1221,49 @@ class Bot {
|
|
|
595
1221
|
for (const block of toolUseBlocks) {
|
|
596
1222
|
const toolStart = Date.now();
|
|
597
1223
|
const args = block.input;
|
|
598
|
-
//
|
|
599
|
-
|
|
1224
|
+
// Bot profile gate — the model is only offered BOT_TOOLS, but enforce
|
|
1225
|
+
// at execution too so a hallucinated tool name can't reach the registry.
|
|
1226
|
+
// Resolve deprecation aliases first so mid-conversation calls under
|
|
1227
|
+
// old v1 names keep working during the grace release.
|
|
1228
|
+
const canonicalName = this.toolExecutor.resolveName(block.name);
|
|
1229
|
+
if (!tool_profiles_1.BOT_TOOLS.has(canonicalName)) {
|
|
1230
|
+
this.opLogger.permDenied(message.discussionId, block.name, 'n/a', 'not-in-bot-tools');
|
|
1231
|
+
results.push({
|
|
1232
|
+
type: 'tool_result',
|
|
1233
|
+
tool_use_id: block.id,
|
|
1234
|
+
content: `Tool not available: ${block.name} is not part of this bot's toolset. `
|
|
1235
|
+
+ 'Use only the tools you were given — do not retry.',
|
|
1236
|
+
is_error: true,
|
|
1237
|
+
});
|
|
1238
|
+
continue;
|
|
1239
|
+
}
|
|
1240
|
+
// Admin-only gate (args-aware: merged tools gate per-action)
|
|
1241
|
+
if (this.permissions.isAdminOnlyTool(block.name, args) && !this.permissions.isAdminOrOwner(message.senderId)) {
|
|
600
1242
|
this.opLogger.permDenied(message.discussionId, block.name, 'n/a', 'requires-admin');
|
|
601
|
-
results.push({
|
|
1243
|
+
results.push({
|
|
1244
|
+
type: 'tool_result',
|
|
1245
|
+
tool_use_id: block.id,
|
|
1246
|
+
content: `Permission denied: ${block.name} requires workspace admin or owner permission. Explain to the user that this action is restricted to admins/owners — do not retry, do not try a workaround, do not pretend it succeeded.`,
|
|
1247
|
+
is_error: true,
|
|
1248
|
+
});
|
|
602
1249
|
continue;
|
|
603
1250
|
}
|
|
604
|
-
// Pre-execution permission check
|
|
1251
|
+
// Pre-execution permission check. An UNKNOWN insightId is
|
|
1252
|
+
// resolved against the server first — an insight the bot can't
|
|
1253
|
+
// map to workflows is denied, not run, because the workflow
|
|
1254
|
+
// check can't see inside it (it would fail open).
|
|
605
1255
|
if (!this.permissions.isPostCheckTool(block.name)) {
|
|
606
|
-
const denied = this.permissions.
|
|
1256
|
+
const denied = await this.permissions.checkArgsResolving(args, message.senderId, () => this.fetchInsightWorkflowMap());
|
|
607
1257
|
if (denied) {
|
|
608
1258
|
this.opLogger.permDenied(message.discussionId, block.name, denied.workflowId, denied.reason);
|
|
609
|
-
results.push({ type: 'tool_result', tool_use_id: block.id, content: denied
|
|
1259
|
+
results.push({ type: 'tool_result', tool_use_id: block.id, content: permissionDeniedMessage(denied), is_error: true });
|
|
610
1260
|
continue;
|
|
611
1261
|
}
|
|
612
1262
|
}
|
|
613
1263
|
// Discussion isolation: prevent leaking DMs and discussions the user shouldn't access
|
|
614
1264
|
if (DISCUSSION_TOOLS.has(block.name) && args.discussionId && args.discussionId !== message.discussionId) {
|
|
615
1265
|
try {
|
|
616
|
-
const discResult = await this.client.socket.request(
|
|
1266
|
+
const discResult = await this.client.socket.request(hailer_rpc_1.HailerRpc.Discussion.messageLatest, [args.discussionId]);
|
|
617
1267
|
const disc = discResult?.discussion || {};
|
|
618
1268
|
const participants = disc.participants || [];
|
|
619
1269
|
const isPrivate = disc.private === true;
|
|
@@ -648,22 +1298,24 @@ class Bot {
|
|
|
648
1298
|
// Auto-inject for join_discussion
|
|
649
1299
|
if (block.name === 'join_discussion') {
|
|
650
1300
|
toolArgs = { ...toolArgs };
|
|
651
|
-
if (!toolArgs.inviteUserId && message.senderId)
|
|
1301
|
+
if (!toolArgs.inviteUserId && message.senderId) {
|
|
652
1302
|
toolArgs.inviteUserId = message.senderId;
|
|
653
|
-
|
|
1303
|
+
}
|
|
1304
|
+
if (!toolArgs.welcomeReason && message.content) {
|
|
654
1305
|
toolArgs.welcomeReason = message.content;
|
|
1306
|
+
}
|
|
655
1307
|
// Only auto-inject sourceActivityId if explicitly provided — don't link DMs to random activities
|
|
656
1308
|
}
|
|
657
1309
|
const result = await this.toolExecutor.execute(block.name, toolArgs, this.getUserContext());
|
|
658
1310
|
const text = result?.content?.[0]?.text ?? JSON.stringify(result);
|
|
659
1311
|
let contentStr = typeof text === 'string' ? text : JSON.stringify(text);
|
|
660
1312
|
const toolDuration = (Date.now() - toolStart) / 1000;
|
|
661
|
-
// Cache insight mappings
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
//
|
|
666
|
-
contentStr = await this.permissions.postFilterListResults(
|
|
1313
|
+
// Cache insight mappings (keyed on the canonical name —
|
|
1314
|
+
// create_insight is an alias of save_insight)
|
|
1315
|
+
this.permissions.maybeCacheInsight(canonicalName, contentStr, args);
|
|
1316
|
+
// Post-filter list results (canonical name: alias calls
|
|
1317
|
+
// produce the new tools' output format)
|
|
1318
|
+
contentStr = await this.permissions.postFilterListResults(canonicalName, contentStr, message.senderId, message.discussionId, this.opLogger);
|
|
667
1319
|
// Post-execution permission check
|
|
668
1320
|
if (this.permissions.isPostCheckTool(block.name)) {
|
|
669
1321
|
const wfId = this.permissions.extractWorkflowIdFromResult(block.name, contentStr);
|
|
@@ -685,6 +1337,11 @@ class Bot {
|
|
|
685
1337
|
if (signal?.aborted && WRITE_TOOLS.has(block.name)) {
|
|
686
1338
|
this.logger.warn('Write tool completed before abort', { tool: block.name });
|
|
687
1339
|
}
|
|
1340
|
+
if (contentStr.length > MAX_TOOL_RESULT_CHARS) {
|
|
1341
|
+
const originalLen = contentStr.length;
|
|
1342
|
+
contentStr = `${contentStr.slice(0, MAX_TOOL_RESULT_CHARS)}\n\n[Tool result truncated. Original: ${originalLen} chars (~${Math.round(originalLen / 4)} tokens). Narrow your query: use 'fields' parameter, add filters, lower 'limit', or use run_insight with aggregate SQL.]`;
|
|
1343
|
+
this.logger.warn('Tool result truncated', { tool: block.name, originalLen, truncatedTo: MAX_TOOL_RESULT_CHARS });
|
|
1344
|
+
}
|
|
688
1345
|
results.push({ type: 'tool_result', tool_use_id: block.id, content: contentStr });
|
|
689
1346
|
}
|
|
690
1347
|
catch (error) {
|
|
@@ -708,43 +1365,47 @@ class Bot {
|
|
|
708
1365
|
const parts = [];
|
|
709
1366
|
const unsupported = [];
|
|
710
1367
|
for (const f of message.fileAttachments) {
|
|
711
|
-
if (!f.mime || (f.size && f.size >
|
|
1368
|
+
if (!f.mime || (f.size && f.size > fileSizeLimit(f.mime))) {
|
|
712
1369
|
unsupported.push(f.fileId);
|
|
1370
|
+
continue;
|
|
713
1371
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
}
|
|
717
|
-
else if (DOCUMENT_MIME_TYPES.has(f.mime) || TEXT_MIME_TYPES.has(f.mime)) {
|
|
718
|
-
parts.push(`[Document attached: ${f.filename} — included below]`);
|
|
719
|
-
}
|
|
720
|
-
else {
|
|
1372
|
+
const desc = describeAttachment(f.mime, f.filename, f.fileId);
|
|
1373
|
+
if (!desc) {
|
|
721
1374
|
unsupported.push(f.fileId);
|
|
1375
|
+
continue;
|
|
722
1376
|
}
|
|
1377
|
+
parts.push(desc);
|
|
723
1378
|
}
|
|
724
|
-
if (unsupported.length)
|
|
1379
|
+
if (unsupported.length) {
|
|
725
1380
|
parts.push(`[File attached: ${unsupported.length} file(s) - IDs: ${unsupported.join(', ')}]\nUse download_file tool with fileId to read file contents.`);
|
|
726
|
-
|
|
1381
|
+
}
|
|
1382
|
+
if (parts.length) {
|
|
727
1383
|
fileInfo = '\n' + parts.join('\n');
|
|
1384
|
+
}
|
|
728
1385
|
}
|
|
729
1386
|
const dmNote = isDm ? '\n[This is a private DM conversation, not an activity discussion.]' : '';
|
|
730
|
-
|
|
1387
|
+
const aiContext = message.meta?.aiContext ? `<context>${JSON.stringify(message.meta.aiContext)}</context>\n\n` : '';
|
|
1388
|
+
return `<incoming discussion="${message.discussionId}"${typeAttr}${nameAttr}${activityAttr} from="${message.senderName}" user_id="${message.senderId}" timestamp="${new Date(message.timestamp).toISOString()}">\n${aiContext}${message.content}${fileInfo}${dmNote}\n</incoming>`;
|
|
731
1389
|
}
|
|
732
1390
|
async resolveFileAttachments(messages) {
|
|
733
|
-
if (!this.hailerApi)
|
|
1391
|
+
if (!this.hailerApi) {
|
|
734
1392
|
return [];
|
|
735
|
-
|
|
1393
|
+
}
|
|
1394
|
+
const nonOffice = [];
|
|
1395
|
+
const office = [];
|
|
1396
|
+
const skipped = [];
|
|
736
1397
|
for (const msg of messages) {
|
|
737
1398
|
for (const f of msg.fileAttachments || []) {
|
|
738
|
-
if (!f.mime || (f.size && f.size >
|
|
1399
|
+
if (!f.mime || (f.size && f.size > fileSizeLimit(f.mime))) {
|
|
739
1400
|
continue;
|
|
740
|
-
if (IMAGE_MIME_TYPES.has(f.mime) || DOCUMENT_MIME_TYPES.has(f.mime) || TEXT_MIME_TYPES.has(f.mime)) {
|
|
741
|
-
eligible.push({ fileId: f.fileId, mime: f.mime });
|
|
742
1401
|
}
|
|
1402
|
+
if (!isSupportedMime(f.mime)) {
|
|
1403
|
+
continue;
|
|
1404
|
+
}
|
|
1405
|
+
(isOfficeMime(f.mime) ? office : nonOffice).push({ fileId: f.fileId, mime: f.mime, filename: f.filename });
|
|
743
1406
|
}
|
|
744
1407
|
}
|
|
745
|
-
|
|
746
|
-
return [];
|
|
747
|
-
const results = await Promise.all(eligible.map(async (f) => {
|
|
1408
|
+
const nonOfficeResults = await Promise.all(nonOffice.map(async (f) => {
|
|
748
1409
|
try {
|
|
749
1410
|
const result = await this.hailerApi.downloadFile(f.fileId);
|
|
750
1411
|
if (IMAGE_MIME_TYPES.has(f.mime) && result.encoding === 'base64') {
|
|
@@ -768,11 +1429,98 @@ class Bot {
|
|
|
768
1429
|
}
|
|
769
1430
|
}
|
|
770
1431
|
catch (err) {
|
|
771
|
-
this.logger.warn('Failed to
|
|
1432
|
+
this.logger.warn('Failed to read file attachment', { fileId: f.fileId, mime: f.mime, err: err instanceof Error ? err.message : err });
|
|
1433
|
+
skipped.push({ filename: f.filename || f.fileId, reason: 'download failed' });
|
|
772
1434
|
}
|
|
773
1435
|
return null;
|
|
774
1436
|
}));
|
|
775
|
-
|
|
1437
|
+
// Download Office files in parallel (I/O-bound), parse serially under the lock (memory-bound)
|
|
1438
|
+
const officeDownloads = await Promise.all(office.map(async (f) => {
|
|
1439
|
+
try {
|
|
1440
|
+
const result = await this.hailerApi.downloadFile(f.fileId);
|
|
1441
|
+
return { f, result };
|
|
1442
|
+
}
|
|
1443
|
+
catch (err) {
|
|
1444
|
+
this.logger.warn('Failed to download Office file', { fileId: f.fileId, mime: f.mime, err: err instanceof Error ? err.message : err });
|
|
1445
|
+
skipped.push({ filename: f.filename || f.fileId, reason: 'download failed' });
|
|
1446
|
+
return null;
|
|
1447
|
+
}
|
|
1448
|
+
}));
|
|
1449
|
+
const officeResults = [];
|
|
1450
|
+
for (const entry of officeDownloads) {
|
|
1451
|
+
if (!entry) {
|
|
1452
|
+
continue;
|
|
1453
|
+
}
|
|
1454
|
+
const { f, result } = entry;
|
|
1455
|
+
if (result.encoding !== 'base64') {
|
|
1456
|
+
this.logger.warn('Office file has unexpected encoding, skipping', { fileId: f.fileId, mime: f.mime, encoding: result.encoding });
|
|
1457
|
+
skipped.push({ filename: f.filename || f.fileId, reason: 'unexpected encoding from download' });
|
|
1458
|
+
continue;
|
|
1459
|
+
}
|
|
1460
|
+
if (isHeapUnderPressure()) {
|
|
1461
|
+
this.logger.warn('Heap under pressure, skipping Office parse', { fileId: f.fileId, mime: f.mime });
|
|
1462
|
+
skipped.push({ filename: f.filename || f.fileId, reason: 'bot is under memory pressure — ask the user to retry in a moment' });
|
|
1463
|
+
continue;
|
|
1464
|
+
}
|
|
1465
|
+
const block = await withOfficeParseLock(async () => {
|
|
1466
|
+
try {
|
|
1467
|
+
if (EXCEL_MIME_TYPES.has(f.mime)) {
|
|
1468
|
+
const ExcelJS = (await Promise.resolve().then(() => __importStar(require('exceljs')))).default;
|
|
1469
|
+
const buffer = Buffer.from(result.content, 'base64');
|
|
1470
|
+
const wb = new ExcelJS.Workbook();
|
|
1471
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Node 24 Buffer<ArrayBuffer> vs exceljs Buffer typing mismatch
|
|
1472
|
+
await wb.xlsx.load(buffer);
|
|
1473
|
+
const parts = [];
|
|
1474
|
+
wb.eachSheet((sheet) => {
|
|
1475
|
+
const rows = [];
|
|
1476
|
+
sheet.eachRow({ includeEmpty: false }, (row) => {
|
|
1477
|
+
const values = Array.isArray(row.values) ? row.values.slice(1) : [];
|
|
1478
|
+
rows.push(values.map(cellToCsv).join(','));
|
|
1479
|
+
});
|
|
1480
|
+
parts.push(`=== Sheet: ${sheet.name} (${rows.length} rows) ===\n${rows.join('\n')}`);
|
|
1481
|
+
});
|
|
1482
|
+
return {
|
|
1483
|
+
type: 'document',
|
|
1484
|
+
source: { type: 'text', media_type: 'text/plain', data: capText(`${f.filename || 'spreadsheet'}\n\n${parts.join('\n\n')}`) },
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
if (WORD_MIME_TYPES.has(f.mime)) {
|
|
1488
|
+
const mammoth = await Promise.resolve().then(() => __importStar(require('mammoth')));
|
|
1489
|
+
const buffer = Buffer.from(result.content, 'base64');
|
|
1490
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Node 24 Buffer<ArrayBuffer> vs mammoth Buffer typing mismatch
|
|
1491
|
+
const { value } = await mammoth.extractRawText({ buffer: buffer });
|
|
1492
|
+
return {
|
|
1493
|
+
type: 'document',
|
|
1494
|
+
source: { type: 'text', media_type: 'text/plain', data: capText(`${f.filename || 'document'}\n\n${value}`) },
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
catch (err) {
|
|
1499
|
+
this.logger.warn('Failed to parse Office file', { fileId: f.fileId, mime: f.mime, err: err instanceof Error ? err.message : err });
|
|
1500
|
+
skipped.push({ filename: f.filename || f.fileId, reason: 'parse error' });
|
|
1501
|
+
}
|
|
1502
|
+
return null;
|
|
1503
|
+
});
|
|
1504
|
+
if (block) {
|
|
1505
|
+
officeResults.push(block);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
const blocks = [
|
|
1509
|
+
...nonOfficeResults.filter((b) => b !== null),
|
|
1510
|
+
...officeResults,
|
|
1511
|
+
];
|
|
1512
|
+
if (skipped.length > 0) {
|
|
1513
|
+
const lines = skipped.map((s) => ` - ${s.filename}: ${s.reason}`).join('\n');
|
|
1514
|
+
blocks.push({
|
|
1515
|
+
type: 'document',
|
|
1516
|
+
source: {
|
|
1517
|
+
type: 'text',
|
|
1518
|
+
media_type: 'text/plain',
|
|
1519
|
+
data: `=== SYSTEM NOTICE: some attachments could not be processed ===\nThe following files were attached but could NOT be read. Tell the user clearly which files failed and why. Do not pretend to have read them.\n${lines}`,
|
|
1520
|
+
},
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
return blocks;
|
|
776
1524
|
}
|
|
777
1525
|
async formatOutgoingMessage(text) {
|
|
778
1526
|
let formatted = await this.messageFormatter.resolveUserTags(text);
|
|
@@ -785,27 +1533,31 @@ class Bot {
|
|
|
785
1533
|
formatted = formatted.replace(/(\[hailerTag\|[^\]]+\]\([a-f0-9]{24}\)\uFEFF?)\s*\([^)]+\)/gi, '$1');
|
|
786
1534
|
// Strip hailerTags inside markdown table rows (pipe in hailerTag|Name breaks table columns)
|
|
787
1535
|
formatted = formatted.split('\n').map(line => {
|
|
788
|
-
if (!line.trimStart().startsWith('|'))
|
|
1536
|
+
if (!line.trimStart().startsWith('|')) {
|
|
789
1537
|
return line;
|
|
1538
|
+
}
|
|
790
1539
|
return line.replace(/\uFEFF?\[hailerTag\|([^\]]+)\]\([a-f0-9]{24}\)\uFEFF?/gi, '$1');
|
|
791
1540
|
}).join('\n');
|
|
792
1541
|
formatted = await this.resolveBareIds(formatted);
|
|
793
1542
|
return formatted;
|
|
794
1543
|
}
|
|
795
1544
|
async resolveBareIds(text) {
|
|
796
|
-
const bareIdPattern = /(?<!\()([a-f0-9]{24})(?!\)[
|
|
1545
|
+
const bareIdPattern = /(?<!\()([a-f0-9]{24})(?!\)[^[]*\[hailerTag)/gi;
|
|
797
1546
|
const matches = [...text.matchAll(bareIdPattern)];
|
|
798
1547
|
const idsToResolve = [];
|
|
799
1548
|
for (const match of matches) {
|
|
800
1549
|
const id = match[1];
|
|
801
|
-
if (new RegExp(`\\[hailerTag\\|[^\\]]+\\]\\(${id}\\)`, 'i').test(text))
|
|
1550
|
+
if (new RegExp(`\\[hailerTag\\|[^\\]]+\\]\\(${id}\\)`, 'i').test(text)) {
|
|
802
1551
|
continue;
|
|
1552
|
+
}
|
|
803
1553
|
idsToResolve.push(id);
|
|
804
|
-
if (idsToResolve.length >= 5)
|
|
1554
|
+
if (idsToResolve.length >= 5) {
|
|
805
1555
|
break;
|
|
1556
|
+
}
|
|
806
1557
|
}
|
|
807
|
-
if (idsToResolve.length === 0)
|
|
1558
|
+
if (idsToResolve.length === 0) {
|
|
808
1559
|
return text;
|
|
1560
|
+
}
|
|
809
1561
|
const resolutions = await Promise.all(idsToResolve.map(async (id) => {
|
|
810
1562
|
try {
|
|
811
1563
|
const result = await this.toolExecutor.execute('show_activity_by_id', { activityId: id }, this.getUserContext());
|
|
@@ -814,8 +1566,9 @@ class Bot {
|
|
|
814
1566
|
const j = resultText.match(/\{[\s\S]*\}/);
|
|
815
1567
|
if (j) {
|
|
816
1568
|
const p = JSON.parse(j[0]);
|
|
817
|
-
if (p.name)
|
|
1569
|
+
if (p.name) {
|
|
818
1570
|
return { id, name: p.name };
|
|
1571
|
+
}
|
|
819
1572
|
}
|
|
820
1573
|
}
|
|
821
1574
|
}
|
|
@@ -823,8 +1576,9 @@ class Bot {
|
|
|
823
1576
|
return null;
|
|
824
1577
|
}));
|
|
825
1578
|
for (const r of resolutions) {
|
|
826
|
-
if (!r)
|
|
1579
|
+
if (!r) {
|
|
827
1580
|
continue;
|
|
1581
|
+
}
|
|
828
1582
|
text = text.replace(r.id, `\uFEFF[hailerTag|${r.name}](${r.id})\uFEFF`);
|
|
829
1583
|
}
|
|
830
1584
|
return text;
|
|
@@ -832,15 +1586,17 @@ class Bot {
|
|
|
832
1586
|
// ===== HELPERS =====
|
|
833
1587
|
async injectPendingContext(discussionId, conversation) {
|
|
834
1588
|
const state = this.signalRouter.getState(discussionId);
|
|
835
|
-
if (!state || state.contextBuffer.length === 0)
|
|
1589
|
+
if (!state || state.contextBuffer.length === 0) {
|
|
836
1590
|
return;
|
|
1591
|
+
}
|
|
837
1592
|
const pending = state.contextBuffer.splice(0);
|
|
838
1593
|
const lastMsg = conversation[conversation.length - 1];
|
|
839
1594
|
if (lastMsg?.role === 'user' && Array.isArray(lastMsg.content)) {
|
|
840
1595
|
const content = lastMsg.content;
|
|
841
1596
|
content.push({ type: 'text', text: `<context type="messages-during-processing">\n${pending.map(m => this.formatIncomingMessage(m)).join('\n\n')}\n</context>` });
|
|
842
|
-
for (const block of await this.resolveFileAttachments(pending))
|
|
1597
|
+
for (const block of await this.resolveFileAttachments(pending)) {
|
|
843
1598
|
content.push(block);
|
|
1599
|
+
}
|
|
844
1600
|
this.opLogger.contextInject(discussionId, pending.length);
|
|
845
1601
|
}
|
|
846
1602
|
}
|
|
@@ -860,30 +1616,34 @@ class Bot {
|
|
|
860
1616
|
}
|
|
861
1617
|
}
|
|
862
1618
|
getToolStatus(toolUseBlocks) {
|
|
863
|
-
if (toolUseBlocks.length === 1)
|
|
1619
|
+
if (toolUseBlocks.length === 1) {
|
|
864
1620
|
return TOOL_STATUS_LABELS[toolUseBlocks[0].name] || toolUseBlocks[0].name.replace(/_/g, ' ');
|
|
1621
|
+
}
|
|
865
1622
|
return `${TOOL_STATUS_LABELS[toolUseBlocks[0].name] || toolUseBlocks[0].name.replace(/_/g, ' ')} (+${toolUseBlocks.length - 1} more)`;
|
|
866
1623
|
}
|
|
867
1624
|
getAnthropicTools() {
|
|
868
|
-
if (this.cachedTools)
|
|
1625
|
+
if (this.cachedTools) {
|
|
869
1626
|
return this.cachedTools;
|
|
1627
|
+
}
|
|
870
1628
|
const defs = this.toolExecutor.getToolDefinitions({
|
|
871
1629
|
allowedGroups: [tool_registry_1.ToolGroup.READ, tool_registry_1.ToolGroup.WRITE, tool_registry_1.ToolGroup.PLAYGROUND, tool_registry_1.ToolGroup.BOT_INTERNAL],
|
|
872
1630
|
});
|
|
873
|
-
const tools = defs.filter(d => BOT_TOOLS.has(d.name)).map(d => ({
|
|
1631
|
+
const tools = defs.filter(d => tool_profiles_1.BOT_TOOLS.has(d.name)).map(d => ({
|
|
874
1632
|
name: d.name, description: d.description, input_schema: d.inputSchema,
|
|
875
1633
|
}));
|
|
876
|
-
if (tools.length > 0)
|
|
1634
|
+
if (tools.length > 0) {
|
|
877
1635
|
tools[tools.length - 1].cache_control = { type: 'ephemeral' };
|
|
1636
|
+
}
|
|
878
1637
|
this.cachedTools = tools;
|
|
879
1638
|
return tools;
|
|
880
1639
|
}
|
|
881
1640
|
async sendMessage(discussionId, text, links) {
|
|
882
1641
|
try {
|
|
883
1642
|
const msgData = { msg: text };
|
|
884
|
-
if (links?.length)
|
|
1643
|
+
if (links?.length) {
|
|
885
1644
|
msgData.links = links;
|
|
886
|
-
|
|
1645
|
+
}
|
|
1646
|
+
await this.client.socket.request(hailer_rpc_1.HailerRpc.Messenger.send, [msgData, discussionId]);
|
|
887
1647
|
this.opLogger.messageOut(discussionId, text.length, (text.match(/\[hailerTag\|/g) || []).length);
|
|
888
1648
|
}
|
|
889
1649
|
catch (error) {
|
|
@@ -891,13 +1651,29 @@ class Bot {
|
|
|
891
1651
|
}
|
|
892
1652
|
}
|
|
893
1653
|
getUserContext() {
|
|
894
|
-
if (!this.userContext)
|
|
1654
|
+
if (!this.userContext) {
|
|
895
1655
|
throw new Error('Bot not started');
|
|
1656
|
+
}
|
|
896
1657
|
return this.userContext;
|
|
897
1658
|
}
|
|
1659
|
+
/** Full insight → source-workflow map from v3.insight.list (the endpoint list_insights renders). */
|
|
1660
|
+
async fetchInsightWorkflowMap() {
|
|
1661
|
+
const result = await this.getUserContext().hailer.request('v3.insight.list', [this._workspaceId]);
|
|
1662
|
+
const insights = Array.isArray(result) ? result : (result?.details || result?.insights || []);
|
|
1663
|
+
const map = new Map();
|
|
1664
|
+
for (const insight of insights) {
|
|
1665
|
+
if (!insight?._id) {
|
|
1666
|
+
continue;
|
|
1667
|
+
}
|
|
1668
|
+
const wfIds = (insight.sources || []).map((src) => src?.workflowId).filter(Boolean);
|
|
1669
|
+
map.set(insight._id, new Set(wfIds));
|
|
1670
|
+
}
|
|
1671
|
+
return map;
|
|
1672
|
+
}
|
|
898
1673
|
trackTokenUsage(response, message, model) {
|
|
899
|
-
if (!response.usage)
|
|
1674
|
+
if (!response.usage) {
|
|
900
1675
|
return;
|
|
1676
|
+
}
|
|
901
1677
|
const { input_tokens, output_tokens } = response.usage;
|
|
902
1678
|
const cacheCreation = response.usage.cache_creation_input_tokens || 0;
|
|
903
1679
|
const cacheRead = response.usage.cache_read_input_tokens || 0;
|