@hailer/mcp 1.1.11 → 1.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/.mcp.json +2 -2
  2. package/.opencode/agent/agent-helga-workflow-config.md +1 -2
  3. package/.opencode/opencode.json +7 -0
  4. package/CHANGELOG.md +7 -0
  5. package/SESSION-HANDOFF.md +68 -0
  6. package/dist/bot/bot-config.d.ts +2 -0
  7. package/dist/bot/bot-config.js +34 -11
  8. package/dist/bot/bot-manager.d.ts +11 -3
  9. package/dist/bot/bot-manager.js +73 -25
  10. package/dist/bot/bot.d.ts +13 -0
  11. package/dist/bot/bot.js +100 -25
  12. package/dist/cli.js +0 -0
  13. package/dist/mcp/hailer-clients.js +4 -1
  14. package/dist/mcp/signal-handler.js +10 -12
  15. package/dist/mcp/webhook-handler.d.ts +2 -0
  16. package/dist/mcp/webhook-handler.js +3 -0
  17. package/dist/mcp-server.js +16 -0
  18. package/inbox/2026-03-04-bot-config-patterns.md +24 -0
  19. package/package.json +1 -1
  20. package/.claude/.context-watchdog.json +0 -1
  21. package/.claude/.session-checked +0 -1
  22. package/.hailer-mcp-port +0 -1
  23. package/dist/CLAUDE.md +0 -370
  24. package/dist/lib/discussion-lock.d.ts +0 -42
  25. package/dist/lib/discussion-lock.js +0 -110
  26. package/dist/mcp/tools/bot-config/constants.d.ts +0 -23
  27. package/dist/mcp/tools/bot-config/constants.js +0 -94
  28. package/dist/mcp/tools/bot-config/core.d.ts +0 -253
  29. package/dist/mcp/tools/bot-config/core.js +0 -2456
  30. package/dist/mcp/tools/bot-config/index.d.ts +0 -10
  31. package/dist/mcp/tools/bot-config/index.js +0 -59
  32. package/dist/mcp/tools/bot-config/tools.d.ts +0 -7
  33. package/dist/mcp/tools/bot-config/tools.js +0 -15
  34. package/dist/mcp/tools/bot-config/types.d.ts +0 -50
  35. package/dist/mcp/tools/bot-config/types.js +0 -6
  36. package/dist/mcp/tools/bug-fixer-tools.d.ts +0 -45
  37. package/dist/mcp/tools/bug-fixer-tools.js +0 -1096
  38. package/dist/mcp/tools/document.d.ts +0 -11
  39. package/dist/mcp/tools/document.js +0 -741
  40. package/dist/mcp/tools/investigate.d.ts +0 -9
  41. package/dist/mcp/tools/investigate.js +0 -254
  42. package/dist/stdio-server.d.ts +0 -14
  43. package/dist/stdio-server.js +0 -101
  44. package/inbox/failures.log +0 -1
  45. package/inbox/usage.jsonl +0 -4
package/.mcp.json CHANGED
@@ -5,9 +5,9 @@
5
5
  "command": "npx",
6
6
  "args": [
7
7
  "mcp-remote",
8
- "http://localhost:3031/api/mcp?apiKey=unique-api-key-for-this-agent"
8
+ "http://localhost:3030/api/mcp?apiKey=unique-api-key-for-this-agent"
9
9
  ],
10
10
  "env": {}
11
11
  }
12
12
  }
13
- }
13
+ }
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-helga-workflow-config
3
3
  description: Manages Hailer workspace configuration as infrastructure-as-code using SDK v0.8.4.
4
- model: sonnet
4
+ model: anthropic/claude-sonnet-4-5
5
5
  tools:
6
6
  bash: true
7
7
  read: true
@@ -53,7 +53,6 @@ For on-demand skills, the orchestrator will say "Load skill X" — use the Skill
53
53
  11. **ACTIVITYLINK FIELDS** - data must be plain string array: `["workflowId"]` NOT `[{workflowId: "..."}]`.
54
54
  12. **NUMBER FIELDS** - Type: `numeric` (not number).
55
55
  13. **FIELD TYPES ARE IMMUTABLE** - Cannot change field type via API. To change text→number: create new field, migrate data, delete old field. Or change in Hailer UI manually.
56
- 14. **CANNOT RENAME WORKFLOWS** - Workflow names cannot be changed via SDK. To "rename": create new workflow with desired name, migrate data, delete old workflow. Or rename in Hailer UI manually.
57
56
 
58
57
  **Delegation to specialists:**
59
58
  - For insight SQL query design → delegate to Viktor (after creating insight entry in insights.ts)
@@ -17,5 +17,12 @@
17
17
  "external_directory": "ask",
18
18
  "webfetch": "ask",
19
19
  "websearch": "ask"
20
+ },
21
+ "mcp": {
22
+ "hailer": {
23
+ "type": "remote",
24
+ "url": "http://localhost:3030/api/mcp?apiKey=unique-api-key-for-this-agent",
25
+ "enabled": true
26
+ }
20
27
  }
21
28
  }
package/CHANGELOG.md CHANGED
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [1.1.10] - 25-02-2026
8
+
9
+ ### Added
10
+
11
+ - **OpenCode MCP support:** Added `.opencode/opencode.json` with Hailer MCP server configuration
12
+ - **Dynamic port patching for OpenCode:** On server startup, `.opencode/opencode.json` is now auto-updated with the actual port (alongside the existing `.mcp.json` patching), so both Claude Code and OpenCode always connect to the right server
13
+
7
14
  ## [1.1.7] - 18-02-2026
8
15
 
9
16
  ### Fix
@@ -0,0 +1,68 @@
1
+ # Session Handoff
2
+
3
+ **Last Updated:** 2026-03-04
4
+
5
+ ## What Was Done
6
+
7
+ ### System Prompt — Full End-to-End Wiring
8
+ Wired `systemPrompt` field from Agent Directory through the entire bot pipeline:
9
+
10
+ - **`src/bot-config/constants.ts`** — added `FIELD_KEY_SYSTEM_PROMPT`
11
+ - **`src/bot-config/context.ts`** — `BotSchema.fields.systemPrompt`, `BotCredentials.systemPrompt`, schema discovery, `extractCredentials()`
12
+ - **`src/bot-config/webhooks.ts`** — extract systemPrompt in `extractCredentialsFromActivity()`
13
+ - **`src/bot-config/loader.ts`** — `BotConfigFile` types + `saveBotConfig()` includes systemPrompt
14
+ - **`src/bot/bot-config.ts`** — `BotConfig.systemPrompt`, reads from `orchestrator.systemPrompt`
15
+ - **`src/bot/bot-manager.ts`** — `BotUpdateEntry.systemPrompt`, passes to Bot; smart restart logic: if only systemPrompt changed (credentials same) → `bot.updateSystemPrompt()` without restart
16
+ - **`src/bot/bot.ts`** — `_systemPrompt` instance field (hot-swappable), `updateSystemPrompt()` public method, `buildSystemPrompt()` uses custom prompt + always appends `<bot-identity>` + `<workspace-context>`
17
+ - **`src/commands/seed-config.ts`** — `extractSystemPromptFromActivity()`, wired into orchestrator + specialist output
18
+ - **`src/mcp/webhook-handler.ts`** — `BotEntry.systemPrompt`, `WorkspaceConfig.orchestrator.systemPrompt`, extracts from webhook payload
19
+
20
+ ### System Prompt Design
21
+ - Custom prompt from AI Hub used as full body; `{wsName}`, `{userId}`, `{botName}` substituted at runtime
22
+ - `<bot-identity>` and `<workspace-context>` always appended by bot — never stored
23
+ - Workspace-isolated: each `Bot` instance has own `_systemPrompt`, `BotManager.bots` Map keyed by workspaceId
24
+ - Phase change → full restart picks up new prompt from config file
25
+ - Field edit → webhook fires (with delay) → `handleBotConfigWebhook()` → `updateSystemPrompt()` (no restart)
26
+
27
+ ## Current Work
28
+
29
+ ### Uncommitted — All System Prompt Changes
30
+ 10 files modified, compiles clean (`tsc --noEmit` passes). Not yet committed or pushed.
31
+
32
+ ## Next Steps
33
+
34
+ 1. **Commit the system prompt wiring** — all 10 files are ready
35
+ 2. **Test end-to-end**: edit prompt in AI Hub → wait for webhook → verify bot uses new prompt
36
+ 3. **Cloudflare** — user mentioned needing this (for remote MCP / public webhook URL). See `docs/prd-remote-mcp-server.md` and `docs/prd-remote-mcp-connector.md`
37
+ 4. **`activityId` passthrough** (optional improvement) — pass orchestrator's `activityId` into Bot so it can subscribe to `activities.updated` socket signal for instant prompt updates (vs waiting for webhook)
38
+
39
+ ## Key Decisions
40
+
41
+ - **Hot-swap without restart**: Only credentials change triggers bot restart; systemPrompt-only changes apply live via `updateSystemPrompt()`
42
+ - **Workspace isolation**: Guaranteed by `Map<workspaceId, Bot>` — webhook `cid` field routes to correct bot instance
43
+ - **Webhook-driven updates**: Phase change → webhook (requires public URL). Field-only changes → webhook fires with delay. Socket `activities.updated` would be instant but requires `activityId` passthrough (not yet done)
44
+ - **Prompt structure**: Custom prompt replaces the rules section; `<bot-identity>` + `<workspace-context>` always runtime-injected
45
+
46
+ ## Files Modified (uncommitted)
47
+
48
+ - `src/bot-config/constants.ts` — FIELD_KEY_SYSTEM_PROMPT
49
+ - `src/bot-config/context.ts` — BotSchema, BotCredentials, discovery, extractCredentials
50
+ - `src/bot-config/loader.ts` — BotConfigFile types + saveBotConfig
51
+ - `src/bot-config/webhooks.ts` — extractCredentialsFromActivity
52
+ - `src/bot/bot-config.ts` — BotConfig + loadBotConfigs
53
+ - `src/bot/bot-manager.ts` — BotUpdateEntry, smart restart, updateSystemPrompt call
54
+ - `src/bot/bot.ts` — _systemPrompt field, updateSystemPrompt(), buildSystemPrompt(), email/password getters
55
+ - `src/commands/seed-config.ts` — extractSystemPromptFromActivity + wired into output
56
+ - `src/mcp/webhook-handler.ts` — BotEntry, WorkspaceConfig types + extraction
57
+
58
+ ## Context to Preserve
59
+
60
+ - Agent Directory workflow ID: `69885261c432a499a35313b6`
61
+ - Deployed phase: `8fa543c69749ab4e8f9e3967`, Retired phase: `df66a80fe7cfde1c3b928038`
62
+ - AI Hub app: `695e3665701ef8e3824beebe`, marketplace targetId: `698351e8dda756e689368b60`
63
+ - `systemPrompt` field key must be exactly `systemPrompt` (camelCase) — field type: textarea
64
+ - **seed-config.ts is an independent copy** of field extraction — NOT shared with context.ts. Always update both when adding new Agent Directory fields
65
+ - **Two bot-config readers**: `src/bot-config/loader.ts` (BotContext/webhook path) AND `src/bot/bot-config.ts` (BotManager startup path) — both need updating
66
+ - **webhook-handler.ts has its own local types** (BotEntry, WorkspaceConfig) — update independently
67
+ - Webhook fires on phase changes; field edits may have delay before webhook triggers
68
+ - `app-edit-guard --agent-on` does NOT propagate to subagents — do ai-hub edits directly
@@ -5,11 +5,13 @@
5
5
  * Extracts orchestrator credentials into a flat BotConfig interface.
6
6
  */
7
7
  export interface BotConfig {
8
+ activityId: string;
8
9
  workspaceId: string;
9
10
  workspaceName: string;
10
11
  email: string;
11
12
  password: string;
12
13
  displayName?: string;
14
+ systemPrompt?: string;
13
15
  enabled: boolean;
14
16
  apiHost: string;
15
17
  }
@@ -68,21 +68,43 @@ function loadBotConfigs() {
68
68
  try {
69
69
  const filePath = path.join(configDir, file);
70
70
  const raw = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
71
+ // Load orchestrator
71
72
  const orch = raw.orchestrator;
72
- const hasCredentials = !!orch?.email && !!orch?.password;
73
- configs.push({
74
- workspaceId: raw.workspaceId,
75
- workspaceName: raw.workspaceName,
76
- email: orch?.email ?? '',
77
- password: orch?.password ?? '',
78
- displayName: orch?.displayName,
79
- enabled: hasCredentials,
80
- apiHost: getApiHost(),
81
- });
73
+ if (orch?.email && orch?.password) {
74
+ configs.push({
75
+ activityId: orch.activityId || '',
76
+ workspaceId: raw.workspaceId,
77
+ workspaceName: raw.workspaceName,
78
+ email: orch.email,
79
+ password: orch.password,
80
+ displayName: orch.displayName,
81
+ systemPrompt: orch.systemPrompt,
82
+ enabled: true,
83
+ apiHost: getApiHost(),
84
+ });
85
+ }
86
+ // Load specialists
87
+ if (Array.isArray(raw.specialists)) {
88
+ for (const spec of raw.specialists) {
89
+ if (spec?.email && spec?.password && spec?.enabled !== false) {
90
+ configs.push({
91
+ activityId: spec.activityId || '',
92
+ workspaceId: raw.workspaceId,
93
+ workspaceName: raw.workspaceName,
94
+ email: spec.email,
95
+ password: spec.password,
96
+ displayName: spec.displayName,
97
+ systemPrompt: spec.systemPrompt,
98
+ enabled: true,
99
+ apiHost: getApiHost(),
100
+ });
101
+ }
102
+ }
103
+ }
82
104
  logger.debug('Loaded bot config', {
83
105
  workspaceId: raw.workspaceId,
84
106
  workspaceName: raw.workspaceName,
85
- enabled: hasCredentials,
107
+ botCount: configs.filter(c => c.workspaceId === raw.workspaceId).length,
86
108
  });
87
109
  }
88
110
  catch (error) {
@@ -124,6 +146,7 @@ function saveBotConfig(config) {
124
146
  email: config.email,
125
147
  password: config.password,
126
148
  displayName: config.displayName,
149
+ systemPrompt: config.systemPrompt,
127
150
  } : null,
128
151
  specialists: existing.specialists ?? [],
129
152
  lastSynced: new Date().toISOString(),
@@ -7,23 +7,31 @@
7
7
  import { ToolRegistry } from '../mcp/tool-registry';
8
8
  import { BotConfig } from './bot-config';
9
9
  interface BotUpdateEntry {
10
+ activityId: string;
10
11
  email: string;
11
12
  password: string;
12
13
  botType: string;
13
14
  enabled: boolean;
14
15
  displayName?: string;
16
+ systemPrompt?: string;
15
17
  }
16
18
  export declare class BotManager {
17
19
  private toolRegistry;
18
20
  private anthropicApiKey;
21
+ /** Key: activityId → Bot instance */
19
22
  private bots;
23
+ /** Key: workspaceId → Set of activityIds (for cross-bot awareness) */
24
+ private workspaceBots;
20
25
  private apiHost;
21
26
  constructor(toolRegistry: ToolRegistry, anthropicApiKey: string);
27
+ /** Get all bot userIds in a workspace (for self-message guard) */
28
+ getBotUserIdsForWorkspace(workspaceId: string): Set<string>;
22
29
  startAll(): Promise<void>;
23
30
  startBot(config: BotConfig): Promise<void>;
24
- stopBot(workspaceId: string): Promise<void>;
31
+ stopBot(botKey: string, workspaceId?: string): Promise<void>;
25
32
  stopAll(): Promise<void>;
26
33
  getStatus(): Array<{
34
+ activityId: string;
27
35
  workspaceId: string;
28
36
  connected: boolean;
29
37
  displayName: string;
@@ -31,8 +39,8 @@ export declare class BotManager {
31
39
  getBotCount(): number;
32
40
  /**
33
41
  * Handle hot reload from webhook updates.
34
- * Only processes orchestrator bots. Workspace-isolated only touches
35
- * the bot for the specified workspaceId, never affects other workspaces.
42
+ * Supports all bot types. Routes by activityId so multiple bots
43
+ * can run in the same workspace independently.
36
44
  */
37
45
  handleBotUpdate(workspaceId: string, bot: BotUpdateEntry, action: 'add' | 'update' | 'remove'): Promise<void>;
38
46
  }
@@ -14,13 +14,29 @@ const logger = (0, logger_1.createLogger)({ component: 'bot-manager' });
14
14
  class BotManager {
15
15
  toolRegistry;
16
16
  anthropicApiKey;
17
+ /** Key: activityId → Bot instance */
17
18
  bots = new Map();
19
+ /** Key: workspaceId → Set of activityIds (for cross-bot awareness) */
20
+ workspaceBots = new Map();
18
21
  apiHost;
19
22
  constructor(toolRegistry, anthropicApiKey) {
20
23
  this.toolRegistry = toolRegistry;
21
24
  this.anthropicApiKey = anthropicApiKey;
22
25
  this.apiHost = process.env.BOT_API_BASE_URL || 'https://api.hailer.com';
23
26
  }
27
+ /** Get all bot userIds in a workspace (for self-message guard) */
28
+ getBotUserIdsForWorkspace(workspaceId) {
29
+ const ids = new Set();
30
+ const activityIds = this.workspaceBots.get(workspaceId);
31
+ if (activityIds) {
32
+ for (const actId of activityIds) {
33
+ const bot = this.bots.get(actId);
34
+ if (bot?.botUserId)
35
+ ids.add(bot.botUserId);
36
+ }
37
+ }
38
+ return ids;
39
+ }
24
40
  async startAll() {
25
41
  const configs = (0, bot_config_1.loadBotConfigs)();
26
42
  const enabled = configs.filter(c => c.enabled);
@@ -37,11 +53,13 @@ class BotManager {
37
53
  logger.debug('Bot startup complete', { succeeded, failed });
38
54
  }
39
55
  async startBot(config) {
40
- if (this.bots.has(config.workspaceId)) {
41
- logger.warn('Bot already running', { workspaceId: config.workspaceId });
56
+ const botKey = config.activityId || config.workspaceId; // fallback for legacy configs
57
+ if (this.bots.has(botKey)) {
58
+ logger.warn('Bot already running', { activityId: botKey, workspaceId: config.workspaceId });
42
59
  return;
43
60
  }
44
61
  logger.debug('Starting bot', {
62
+ activityId: botKey,
45
63
  workspaceId: config.workspaceId,
46
64
  workspace: config.workspaceName,
47
65
  });
@@ -52,32 +70,50 @@ class BotManager {
52
70
  anthropicApiKey: this.anthropicApiKey,
53
71
  toolRegistry: this.toolRegistry,
54
72
  workspaceId: config.workspaceId,
73
+ systemPrompt: config.systemPrompt,
74
+ botManager: this,
55
75
  });
56
76
  await bot.start();
57
- this.bots.set(config.workspaceId, bot);
58
- logger.debug('Bot started', { workspaceId: config.workspaceId });
77
+ this.bots.set(botKey, bot);
78
+ // Track in workspace lookup
79
+ if (!this.workspaceBots.has(config.workspaceId)) {
80
+ this.workspaceBots.set(config.workspaceId, new Set());
81
+ }
82
+ this.workspaceBots.get(config.workspaceId).add(botKey);
83
+ logger.debug('Bot started', { activityId: botKey, workspaceId: config.workspaceId });
59
84
  }
60
- async stopBot(workspaceId) {
61
- const bot = this.bots.get(workspaceId);
85
+ async stopBot(botKey, workspaceId) {
86
+ const bot = this.bots.get(botKey);
62
87
  if (!bot)
63
88
  return;
64
89
  await bot.stop();
65
- this.bots.delete(workspaceId);
66
- logger.debug('Bot stopped', { workspaceId });
90
+ this.bots.delete(botKey);
91
+ // Clean up workspace tracking
92
+ if (workspaceId) {
93
+ const wsSet = this.workspaceBots.get(workspaceId);
94
+ if (wsSet) {
95
+ wsSet.delete(botKey);
96
+ if (wsSet.size === 0)
97
+ this.workspaceBots.delete(workspaceId);
98
+ }
99
+ }
100
+ logger.debug('Bot stopped', { activityId: botKey, workspaceId });
67
101
  }
68
102
  async stopAll() {
69
103
  logger.debug('Stopping all bots', { count: this.bots.size });
70
- await Promise.allSettled(Array.from(this.bots.entries()).map(async ([wsId, bot]) => {
104
+ await Promise.allSettled(Array.from(this.bots.entries()).map(async ([botKey, bot]) => {
71
105
  await bot.stop();
72
- logger.debug('Bot stopped', { workspaceId: wsId });
106
+ logger.debug('Bot stopped', { activityId: botKey });
73
107
  }));
74
108
  this.bots.clear();
109
+ this.workspaceBots.clear();
75
110
  }
76
111
  getStatus() {
77
- return Array.from(this.bots.entries()).map(([wsId, bot]) => ({
78
- workspaceId: wsId,
112
+ return Array.from(this.bots.entries()).map(([botKey, bot]) => ({
113
+ activityId: botKey,
114
+ workspaceId: bot.workspaceId || botKey,
79
115
  connected: bot.connected,
80
- displayName: wsId,
116
+ displayName: bot.workspaceId || botKey,
81
117
  }));
82
118
  }
83
119
  getBotCount() {
@@ -85,48 +121,60 @@ class BotManager {
85
121
  }
86
122
  /**
87
123
  * Handle hot reload from webhook updates.
88
- * Only processes orchestrator bots. Workspace-isolated only touches
89
- * the bot for the specified workspaceId, never affects other workspaces.
124
+ * Supports all bot types. Routes by activityId so multiple bots
125
+ * can run in the same workspace independently.
90
126
  */
91
127
  async handleBotUpdate(workspaceId, bot, action) {
92
- if (bot.botType !== 'orchestrator') {
93
- logger.debug('Ignoring non-orchestrator bot update', { workspaceId, botType: bot.botType });
128
+ const botKey = bot.activityId;
129
+ if (!botKey) {
130
+ logger.warn('Bot update missing activityId, skipping', { workspaceId });
94
131
  return;
95
132
  }
96
- const running = this.bots.has(workspaceId);
133
+ const running = this.bots.has(botKey);
97
134
  if (action === 'remove' || !bot.enabled) {
98
135
  if (running) {
99
- logger.info('Stopping bot (disabled via webhook)', { workspaceId });
100
- await this.stopBot(workspaceId);
136
+ logger.info('Stopping bot (disabled via webhook)', { activityId: botKey, workspaceId });
137
+ await this.stopBot(botKey, workspaceId);
101
138
  }
102
139
  return;
103
140
  }
104
141
  // Validate credentials before proceeding
105
142
  if (!/.+@.+\..+/.test(bot.email) || !bot.password || bot.password.length < 6) {
106
- logger.warn('Invalid bot credentials, skipping', { workspaceId });
143
+ logger.warn('Invalid bot credentials, skipping', { activityId: botKey, workspaceId });
107
144
  return;
108
145
  }
109
146
  // action is 'add' or 'update' with enabled=true
110
147
  if (running) {
111
- // Restart credentials or config may have changed
112
- logger.info('Restarting bot (updated via webhook)', { workspaceId });
113
- await this.stopBot(workspaceId);
148
+ const runningBot = this.bots.get(botKey);
149
+ // If only the system prompt changed, update it live — no restart needed
150
+ const credentialsChanged = runningBot.email !== bot.email || runningBot.password !== bot.password;
151
+ if (!credentialsChanged) {
152
+ logger.info('Updating system prompt live (no restart needed)', { activityId: botKey, workspaceId });
153
+ runningBot.updateSystemPrompt(bot.systemPrompt);
154
+ return;
155
+ }
156
+ // Credentials changed — full restart required
157
+ logger.info('Restarting bot (credentials updated via webhook)', { activityId: botKey, workspaceId });
158
+ await this.stopBot(botKey, workspaceId);
114
159
  }
115
160
  const config = {
161
+ activityId: botKey,
116
162
  workspaceId,
117
163
  workspaceName: workspaceId,
118
164
  email: bot.email,
119
165
  password: bot.password,
120
166
  displayName: bot.displayName,
167
+ systemPrompt: bot.systemPrompt,
121
168
  enabled: true,
122
169
  apiHost: this.apiHost,
123
170
  };
124
171
  try {
125
172
  await this.startBot(config);
126
- logger.info('Bot started via webhook', { workspaceId, displayName: bot.displayName });
173
+ logger.info('Bot started via webhook', { activityId: botKey, workspaceId, displayName: bot.displayName });
127
174
  }
128
175
  catch (error) {
129
176
  logger.error('Failed to start bot via webhook', {
177
+ activityId: botKey,
130
178
  workspaceId,
131
179
  error: error instanceof Error ? error.message : String(error),
132
180
  });
package/dist/bot/bot.d.ts CHANGED
@@ -18,6 +18,7 @@ export declare class Bot {
18
18
  private workspaceOverview;
19
19
  private userId;
20
20
  private _workspaceId;
21
+ private _systemPrompt;
21
22
  private conversationManager;
22
23
  private messageClassifier;
23
24
  private messageFormatter;
@@ -45,6 +46,7 @@ export declare class Bot {
45
46
  private adminUserIds;
46
47
  private ownerUserIds;
47
48
  private config;
49
+ private botManager;
48
50
  constructor(config: {
49
51
  email: string;
50
52
  password: string;
@@ -53,9 +55,20 @@ export declare class Bot {
53
55
  model?: string;
54
56
  toolRegistry: ToolRegistry;
55
57
  workspaceId?: string;
58
+ systemPrompt?: string;
59
+ botManager?: any;
56
60
  });
61
+ get email(): string;
62
+ get password(): string;
63
+ /**
64
+ * Hot-update the system prompt without restarting the bot.
65
+ * Takes effect on the next message processed.
66
+ */
67
+ updateSystemPrompt(prompt: string | undefined): void;
57
68
  get connected(): boolean;
58
69
  get workspaceId(): string | undefined;
70
+ /** Exposed for BotManager cross-bot awareness */
71
+ get botUserId(): string;
59
72
  start(): Promise<void>;
60
73
  stop(): Promise<void>;
61
74
  private handleSignal;