@hailer/mcp 0.2.7 → 1.0.21
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/skills/client-bot-architecture/skill.md +340 -0
- package/.claude/skills/publish-hailer-app/SKILL.md +11 -0
- package/dist/app.d.ts +1 -1
- package/dist/app.js +116 -84
- package/dist/bot/chat-bot.d.ts +31 -0
- package/dist/bot/chat-bot.js +356 -0
- package/dist/cli.d.ts +9 -1
- package/dist/cli.js +71 -2
- package/dist/config.d.ts +15 -2
- package/dist/config.js +53 -3
- package/dist/lib/logger.js +11 -11
- package/dist/mcp/hailer-clients.js +12 -11
- package/dist/mcp/tool-registry.d.ts +4 -0
- package/dist/mcp/tool-registry.js +78 -1
- package/dist/mcp/tools/activity.js +47 -0
- package/dist/mcp/tools/discussion.js +44 -1
- package/dist/mcp/tools/metrics.d.ts +13 -0
- package/dist/mcp/tools/metrics.js +546 -0
- package/dist/mcp/tools/user.d.ts +1 -0
- package/dist/mcp/tools/user.js +94 -1
- package/dist/mcp/tools/workflow.js +109 -40
- package/dist/mcp/webhook-handler.js +7 -4
- package/dist/mcp-server.js +22 -6
- package/dist/stdio-server.d.ts +14 -0
- package/dist/stdio-server.js +101 -0
- package/package.json +6 -6
- package/scripts/test-hal-tools.ts +154 -0
- package/test-billing-server.js +136 -0
- package/dist/lib/discussion-lock.d.ts +0 -42
- package/dist/lib/discussion-lock.js +0 -110
- package/dist/mcp/tools/bot-config/constants.d.ts +0 -23
- package/dist/mcp/tools/bot-config/constants.js +0 -94
- package/dist/mcp/tools/bot-config/core.d.ts +0 -253
- package/dist/mcp/tools/bot-config/core.js +0 -2456
- package/dist/mcp/tools/bot-config/index.d.ts +0 -10
- package/dist/mcp/tools/bot-config/index.js +0 -59
- package/dist/mcp/tools/bot-config/tools.d.ts +0 -7
- package/dist/mcp/tools/bot-config/tools.js +0 -15
- package/dist/mcp/tools/bot-config/types.d.ts +0 -50
- package/dist/mcp/tools/bot-config/types.js +0 -6
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock Token Billing Server for Testing
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* node test-billing-server.js
|
|
6
|
+
*
|
|
7
|
+
* Endpoints:
|
|
8
|
+
* POST /balance - Check workspace balance
|
|
9
|
+
* POST /burn - Burn tokens (deducts from balance)
|
|
10
|
+
*
|
|
11
|
+
* Configure in .env.local:
|
|
12
|
+
* TOKEN_BILLING_ENABLED=true
|
|
13
|
+
* TOKEN_BALANCE_ENDPOINT=http://localhost:3099/balance
|
|
14
|
+
* TOKEN_BURN_ENDPOINT=http://localhost:3099/burn
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const http = require('http');
|
|
18
|
+
|
|
19
|
+
// Starting balance per workspace (simulates real billing)
|
|
20
|
+
const STARTING_BALANCE = 10.00;
|
|
21
|
+
|
|
22
|
+
// Track balance per workspace
|
|
23
|
+
const workspaceBalances = new Map();
|
|
24
|
+
|
|
25
|
+
// Get or initialize workspace balance
|
|
26
|
+
function getBalance(workspaceId) {
|
|
27
|
+
if (!workspaceBalances.has(workspaceId)) {
|
|
28
|
+
workspaceBalances.set(workspaceId, STARTING_BALANCE);
|
|
29
|
+
}
|
|
30
|
+
return workspaceBalances.get(workspaceId);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Deduct from workspace balance
|
|
34
|
+
function deductBalance(workspaceId, amount) {
|
|
35
|
+
const current = getBalance(workspaceId);
|
|
36
|
+
const newBalance = current - amount;
|
|
37
|
+
workspaceBalances.set(workspaceId, newBalance);
|
|
38
|
+
return newBalance;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Track total burned across all workspaces
|
|
42
|
+
let totalBurned = 0;
|
|
43
|
+
|
|
44
|
+
const server = http.createServer((req, res) => {
|
|
45
|
+
res.setHeader('Content-Type', 'application/json');
|
|
46
|
+
|
|
47
|
+
let body = '';
|
|
48
|
+
req.on('data', chunk => body += chunk);
|
|
49
|
+
req.on('end', () => {
|
|
50
|
+
let data = {};
|
|
51
|
+
try {
|
|
52
|
+
data = JSON.parse(body || '{}');
|
|
53
|
+
} catch (e) {
|
|
54
|
+
res.statusCode = 400;
|
|
55
|
+
res.end(JSON.stringify({ error: 'Invalid JSON' }));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const timestamp = new Date().toISOString().substring(11, 19);
|
|
60
|
+
|
|
61
|
+
if (req.url === '/balance') {
|
|
62
|
+
const balance = getBalance(data.workspaceId);
|
|
63
|
+
const isNegative = balance < 0;
|
|
64
|
+
|
|
65
|
+
console.log(`[${timestamp}] BALANCE CHECK`);
|
|
66
|
+
console.log(` Workspace: ${data.workspaceId}`);
|
|
67
|
+
console.log(` Balance: $${balance.toFixed(8)} ${isNegative ? '(NEGATIVE - will reject)' : '(OK)'}`);
|
|
68
|
+
console.log('');
|
|
69
|
+
|
|
70
|
+
res.end(JSON.stringify({
|
|
71
|
+
workspaceId: data.workspaceId,
|
|
72
|
+
balance: balance
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
else if (req.url === '/burn') {
|
|
76
|
+
const cost = data.costUsd || 0;
|
|
77
|
+
const newBalance = deductBalance(data.workspaceId, cost);
|
|
78
|
+
totalBurned += cost;
|
|
79
|
+
|
|
80
|
+
console.log(`[${timestamp}] TOKEN BURN`);
|
|
81
|
+
console.log(` Workspace: ${data.workspaceId}`);
|
|
82
|
+
console.log(` Cost: $${cost.toFixed(8)}`);
|
|
83
|
+
console.log(` Input: ${data.inputTokens} tokens`);
|
|
84
|
+
console.log(` Output: ${data.outputTokens} tokens`);
|
|
85
|
+
console.log(` Cache Write: ${data.cacheCreationTokens} tokens`);
|
|
86
|
+
console.log(` Cache Read: ${data.cacheReadTokens} tokens`);
|
|
87
|
+
console.log(` Session: ${data.sessionId || 'N/A'}`);
|
|
88
|
+
console.log(` Activity: ${data.activityId || 'N/A'}`);
|
|
89
|
+
console.log(` ─────────────────────────────`);
|
|
90
|
+
console.log(` New Balance: $${newBalance.toFixed(8)}`);
|
|
91
|
+
console.log(` Total burned: $${totalBurned.toFixed(8)}`);
|
|
92
|
+
console.log('');
|
|
93
|
+
|
|
94
|
+
res.end(JSON.stringify({ success: true, newBalance }));
|
|
95
|
+
}
|
|
96
|
+
else if (req.url === '/reset') {
|
|
97
|
+
// Reset endpoint for testing
|
|
98
|
+
const workspaceId = data.workspaceId;
|
|
99
|
+
const newBalance = data.balance !== undefined ? data.balance : STARTING_BALANCE;
|
|
100
|
+
workspaceBalances.set(workspaceId, newBalance);
|
|
101
|
+
|
|
102
|
+
console.log(`[${timestamp}] BALANCE RESET`);
|
|
103
|
+
console.log(` Workspace: ${workspaceId}`);
|
|
104
|
+
console.log(` New Balance: $${newBalance.toFixed(8)}`);
|
|
105
|
+
console.log('');
|
|
106
|
+
|
|
107
|
+
res.end(JSON.stringify({ success: true, balance: newBalance }));
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
res.statusCode = 404;
|
|
111
|
+
res.end(JSON.stringify({ error: 'Not found' }));
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const PORT = 3099;
|
|
117
|
+
|
|
118
|
+
server.listen(PORT, () => {
|
|
119
|
+
console.log('═══════════════════════════════════════════');
|
|
120
|
+
console.log(' Mock Token Billing Server');
|
|
121
|
+
console.log('═══════════════════════════════════════════');
|
|
122
|
+
console.log(` Running on: http://localhost:${PORT}`);
|
|
123
|
+
console.log(` Starting balance: $${STARTING_BALANCE.toFixed(2)}`);
|
|
124
|
+
console.log('');
|
|
125
|
+
console.log(' Endpoints:');
|
|
126
|
+
console.log(` POST http://localhost:${PORT}/balance`);
|
|
127
|
+
console.log(` POST http://localhost:${PORT}/burn`);
|
|
128
|
+
console.log(` POST http://localhost:${PORT}/reset`);
|
|
129
|
+
console.log('');
|
|
130
|
+
console.log(' Reset a workspace balance:');
|
|
131
|
+
console.log(` curl -X POST http://localhost:${PORT}/reset \\`);
|
|
132
|
+
console.log(` -H "Content-Type: application/json" \\`);
|
|
133
|
+
console.log(` -d '{"workspaceId":"xxx","balance":-1}'`);
|
|
134
|
+
console.log('═══════════════════════════════════════════');
|
|
135
|
+
console.log('');
|
|
136
|
+
});
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Discussion Lock Registry
|
|
3
|
-
*
|
|
4
|
-
* Prevents multiple bots from responding to the same discussion.
|
|
5
|
-
* When a specialist bot (like Giuseppe) is handling a discussion,
|
|
6
|
-
* it acquires a lock. Other bots (like Orchestrator) check the lock
|
|
7
|
-
* before responding.
|
|
8
|
-
*/
|
|
9
|
-
/**
|
|
10
|
-
* Acquire a lock on a discussion
|
|
11
|
-
* @param discussionId - The discussion to lock
|
|
12
|
-
* @param botName - Name of the bot acquiring the lock (for logging)
|
|
13
|
-
* @param ttlMs - Lock duration in milliseconds (default: 5 minutes)
|
|
14
|
-
* @returns true if lock acquired, false if already locked by another bot
|
|
15
|
-
*/
|
|
16
|
-
export declare function acquireDiscussionLock(discussionId: string, botName: string, ttlMs?: number): boolean;
|
|
17
|
-
/**
|
|
18
|
-
* Release a lock on a discussion
|
|
19
|
-
* @param discussionId - The discussion to unlock
|
|
20
|
-
* @param botName - Name of the bot releasing (must match acquirer)
|
|
21
|
-
*/
|
|
22
|
-
export declare function releaseDiscussionLock(discussionId: string, botName: string): void;
|
|
23
|
-
/**
|
|
24
|
-
* Check if a discussion is locked by another bot
|
|
25
|
-
* @param discussionId - The discussion to check
|
|
26
|
-
* @param myBotName - Name of the checking bot (own locks don't block)
|
|
27
|
-
* @returns true if locked by ANOTHER bot, false if free or own lock
|
|
28
|
-
*/
|
|
29
|
-
export declare function isDiscussionLocked(discussionId: string, myBotName: string): boolean;
|
|
30
|
-
/**
|
|
31
|
-
* Clean up expired locks (call periodically)
|
|
32
|
-
*/
|
|
33
|
-
export declare function cleanupExpiredLocks(): number;
|
|
34
|
-
/**
|
|
35
|
-
* Get current lock status (for debugging)
|
|
36
|
-
*/
|
|
37
|
-
export declare function getLockStatus(): Map<string, {
|
|
38
|
-
botName: string;
|
|
39
|
-
acquiredAt: number;
|
|
40
|
-
expiresAt: number;
|
|
41
|
-
}>;
|
|
42
|
-
//# sourceMappingURL=discussion-lock.d.ts.map
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Discussion Lock Registry
|
|
4
|
-
*
|
|
5
|
-
* Prevents multiple bots from responding to the same discussion.
|
|
6
|
-
* When a specialist bot (like Giuseppe) is handling a discussion,
|
|
7
|
-
* it acquires a lock. Other bots (like Orchestrator) check the lock
|
|
8
|
-
* before responding.
|
|
9
|
-
*/
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.acquireDiscussionLock = acquireDiscussionLock;
|
|
12
|
-
exports.releaseDiscussionLock = releaseDiscussionLock;
|
|
13
|
-
exports.isDiscussionLocked = isDiscussionLocked;
|
|
14
|
-
exports.cleanupExpiredLocks = cleanupExpiredLocks;
|
|
15
|
-
exports.getLockStatus = getLockStatus;
|
|
16
|
-
const logger_1 = require("./logger");
|
|
17
|
-
const logger = (0, logger_1.createLogger)({ component: 'discussion-lock' });
|
|
18
|
-
// Singleton map of discussionId -> { botName, acquiredAt, expiresAt }
|
|
19
|
-
const locks = new Map();
|
|
20
|
-
// Default lock TTL: 5 minutes (allows for LLM processing time)
|
|
21
|
-
const DEFAULT_LOCK_TTL_MS = 5 * 60 * 1000;
|
|
22
|
-
/**
|
|
23
|
-
* Acquire a lock on a discussion
|
|
24
|
-
* @param discussionId - The discussion to lock
|
|
25
|
-
* @param botName - Name of the bot acquiring the lock (for logging)
|
|
26
|
-
* @param ttlMs - Lock duration in milliseconds (default: 5 minutes)
|
|
27
|
-
* @returns true if lock acquired, false if already locked by another bot
|
|
28
|
-
*/
|
|
29
|
-
function acquireDiscussionLock(discussionId, botName, ttlMs = DEFAULT_LOCK_TTL_MS) {
|
|
30
|
-
const now = Date.now();
|
|
31
|
-
const existing = locks.get(discussionId);
|
|
32
|
-
// Check if existing lock is still valid
|
|
33
|
-
if (existing && existing.expiresAt > now) {
|
|
34
|
-
if (existing.botName === botName) {
|
|
35
|
-
// Same bot - extend the lock
|
|
36
|
-
existing.expiresAt = now + ttlMs;
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
// Different bot has the lock
|
|
40
|
-
logger.debug('Discussion already locked', {
|
|
41
|
-
discussionId,
|
|
42
|
-
lockedBy: existing.botName,
|
|
43
|
-
requestedBy: botName
|
|
44
|
-
});
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
// Acquire lock
|
|
48
|
-
locks.set(discussionId, {
|
|
49
|
-
botName,
|
|
50
|
-
acquiredAt: now,
|
|
51
|
-
expiresAt: now + ttlMs
|
|
52
|
-
});
|
|
53
|
-
logger.debug('Discussion lock acquired', { discussionId, botName, ttlMs });
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Release a lock on a discussion
|
|
58
|
-
* @param discussionId - The discussion to unlock
|
|
59
|
-
* @param botName - Name of the bot releasing (must match acquirer)
|
|
60
|
-
*/
|
|
61
|
-
function releaseDiscussionLock(discussionId, botName) {
|
|
62
|
-
const existing = locks.get(discussionId);
|
|
63
|
-
if (existing && existing.botName === botName) {
|
|
64
|
-
locks.delete(discussionId);
|
|
65
|
-
logger.debug('Discussion lock released', { discussionId, botName });
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Check if a discussion is locked by another bot
|
|
70
|
-
* @param discussionId - The discussion to check
|
|
71
|
-
* @param myBotName - Name of the checking bot (own locks don't block)
|
|
72
|
-
* @returns true if locked by ANOTHER bot, false if free or own lock
|
|
73
|
-
*/
|
|
74
|
-
function isDiscussionLocked(discussionId, myBotName) {
|
|
75
|
-
const now = Date.now();
|
|
76
|
-
const existing = locks.get(discussionId);
|
|
77
|
-
// No lock or expired
|
|
78
|
-
if (!existing || existing.expiresAt <= now) {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
// Own lock doesn't block
|
|
82
|
-
if (existing.botName === myBotName) {
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
return true;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Clean up expired locks (call periodically)
|
|
89
|
-
*/
|
|
90
|
-
function cleanupExpiredLocks() {
|
|
91
|
-
const now = Date.now();
|
|
92
|
-
let cleaned = 0;
|
|
93
|
-
for (const [discussionId, lock] of locks.entries()) {
|
|
94
|
-
if (lock.expiresAt <= now) {
|
|
95
|
-
locks.delete(discussionId);
|
|
96
|
-
cleaned++;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
if (cleaned > 0) {
|
|
100
|
-
logger.debug('Cleaned up expired locks', { count: cleaned });
|
|
101
|
-
}
|
|
102
|
-
return cleaned;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Get current lock status (for debugging)
|
|
106
|
-
*/
|
|
107
|
-
function getLockStatus() {
|
|
108
|
-
return new Map(locks);
|
|
109
|
-
}
|
|
110
|
-
//# sourceMappingURL=discussion-lock.js.map
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bot Configuration Constants
|
|
3
|
-
*/
|
|
4
|
-
import type { BotInfo } from './types';
|
|
5
|
-
export declare const LOCAL_STATE_FILE: string;
|
|
6
|
-
export declare const SCHEMAS_DIR: string;
|
|
7
|
-
export declare const LOCAL_CREDENTIALS_FILE: string;
|
|
8
|
-
export declare const SIGNAL_DEDUP_WINDOW_MS = 5000;
|
|
9
|
-
export declare const RESTART_DEBOUNCE_MS = 500;
|
|
10
|
-
export declare const AGENT_DIRECTORY_PATTERNS: string[];
|
|
11
|
-
export declare const DEPLOYED_PHASE_PATTERNS: string[];
|
|
12
|
-
export declare const RETIRED_PHASE_PATTERNS: string[];
|
|
13
|
-
export declare const FIELD_KEY_HAILER_PROFILE: string[];
|
|
14
|
-
export declare const FIELD_KEY_EMAIL: string[];
|
|
15
|
-
export declare const FIELD_KEY_PASSWORD: string[];
|
|
16
|
-
export declare const FIELD_KEY_BOT_TYPE: string[];
|
|
17
|
-
export declare const FIELD_KEY_SCHEMA_CONFIG: string[];
|
|
18
|
-
export declare const LEGACY_AGENT_ACTIVITY_IDS: Record<string, string>;
|
|
19
|
-
/**
|
|
20
|
-
* Available bots - single source of truth
|
|
21
|
-
*/
|
|
22
|
-
export declare const AVAILABLE_BOTS: BotInfo[];
|
|
23
|
-
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Bot Configuration Constants
|
|
4
|
-
*/
|
|
5
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
-
}
|
|
11
|
-
Object.defineProperty(o, k2, desc);
|
|
12
|
-
}) : (function(o, m, k, k2) {
|
|
13
|
-
if (k2 === undefined) k2 = k;
|
|
14
|
-
o[k2] = m[k];
|
|
15
|
-
}));
|
|
16
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
-
}) : function(o, v) {
|
|
19
|
-
o["default"] = v;
|
|
20
|
-
});
|
|
21
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
-
var ownKeys = function(o) {
|
|
23
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
-
var ar = [];
|
|
25
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
-
return ar;
|
|
27
|
-
};
|
|
28
|
-
return ownKeys(o);
|
|
29
|
-
};
|
|
30
|
-
return function (mod) {
|
|
31
|
-
if (mod && mod.__esModule) return mod;
|
|
32
|
-
var result = {};
|
|
33
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
-
__setModuleDefault(result, mod);
|
|
35
|
-
return result;
|
|
36
|
-
};
|
|
37
|
-
})();
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.AVAILABLE_BOTS = exports.LEGACY_AGENT_ACTIVITY_IDS = exports.FIELD_KEY_SCHEMA_CONFIG = exports.FIELD_KEY_BOT_TYPE = exports.FIELD_KEY_PASSWORD = exports.FIELD_KEY_EMAIL = exports.FIELD_KEY_HAILER_PROFILE = exports.RETIRED_PHASE_PATTERNS = exports.DEPLOYED_PHASE_PATTERNS = exports.AGENT_DIRECTORY_PATTERNS = exports.RESTART_DEBOUNCE_MS = exports.SIGNAL_DEDUP_WINDOW_MS = exports.LOCAL_CREDENTIALS_FILE = exports.SCHEMAS_DIR = exports.LOCAL_STATE_FILE = void 0;
|
|
40
|
-
const path = __importStar(require("path"));
|
|
41
|
-
// File paths
|
|
42
|
-
exports.LOCAL_STATE_FILE = path.join(process.cwd(), '.bot-state.json');
|
|
43
|
-
exports.SCHEMAS_DIR = path.join(process.cwd(), '.bot-schemas');
|
|
44
|
-
exports.LOCAL_CREDENTIALS_FILE = path.join(process.cwd(), '.bot-credentials.json');
|
|
45
|
-
// Signal deduplication
|
|
46
|
-
exports.SIGNAL_DEDUP_WINDOW_MS = 5000;
|
|
47
|
-
exports.RESTART_DEBOUNCE_MS = 500;
|
|
48
|
-
// Schema discovery patterns
|
|
49
|
-
exports.AGENT_DIRECTORY_PATTERNS = ['Agent Directory', 'AI Agents', '🤖 Agent Directory'];
|
|
50
|
-
exports.DEPLOYED_PHASE_PATTERNS = ['deployed', 'active', 'enabled'];
|
|
51
|
-
exports.RETIRED_PHASE_PATTERNS = ['retired', 'disabled', 'inactive'];
|
|
52
|
-
// Field key patterns for discovery
|
|
53
|
-
exports.FIELD_KEY_HAILER_PROFILE = ['hailerProfile', 'Agent Hailer profile'];
|
|
54
|
-
exports.FIELD_KEY_EMAIL = ['agentEmailInHailer', 'email', 'Email of Hailer profile'];
|
|
55
|
-
exports.FIELD_KEY_PASSWORD = ['password'];
|
|
56
|
-
exports.FIELD_KEY_BOT_TYPE = ['botType', 'bot_type', 'type'];
|
|
57
|
-
exports.FIELD_KEY_SCHEMA_CONFIG = ['schemaConfig', 'schema_config', 'schema_config_f3a'];
|
|
58
|
-
// Legacy activity IDs (fallback when discovery fails)
|
|
59
|
-
exports.LEGACY_AGENT_ACTIVITY_IDS = {
|
|
60
|
-
hal: '695e42deca61319424bc8b1f',
|
|
61
|
-
hailerExpert: '695e42deca61319424bc8b20',
|
|
62
|
-
bugFixer: '695e42deca61319424bc8b23',
|
|
63
|
-
vastuullisuus: '695e42dfca61319424bc8b2e'
|
|
64
|
-
};
|
|
65
|
-
/**
|
|
66
|
-
* Available bots - single source of truth
|
|
67
|
-
*/
|
|
68
|
-
exports.AVAILABLE_BOTS = [
|
|
69
|
-
{
|
|
70
|
-
id: 'hal',
|
|
71
|
-
name: 'HAL',
|
|
72
|
-
description: 'Main orchestrator - handles general chat and coordinates specialists',
|
|
73
|
-
icon: '🤖'
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
id: 'bugFixer',
|
|
77
|
-
name: 'Bug Fixer',
|
|
78
|
-
description: 'Bug fixing specialist - analyzes and repairs Hailer app issues',
|
|
79
|
-
icon: '🔧'
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
id: 'hailerExpert',
|
|
83
|
-
name: 'Hailer Expert',
|
|
84
|
-
description: 'Workflow & data specialist - bulk operations, insights, reports',
|
|
85
|
-
icon: '📊'
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
id: 'vastuullisuus',
|
|
89
|
-
name: 'Vastuullisuus',
|
|
90
|
-
description: 'Sustainability analysis for SMEs',
|
|
91
|
-
icon: '🌱'
|
|
92
|
-
}
|
|
93
|
-
];
|
|
94
|
-
//# sourceMappingURL=constants.js.map
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bot Configuration MCP Tools
|
|
3
|
-
*
|
|
4
|
-
* Manages which bots are enabled/disabled in the workspace.
|
|
5
|
-
* Config is stored in the Agent Directory workflow - agents are activities.
|
|
6
|
-
* - Deployed agents phase = enabled
|
|
7
|
-
* - Retired agents phase = disabled
|
|
8
|
-
*
|
|
9
|
-
* Architecture (User ID-based discovery):
|
|
10
|
-
* - In-memory state is primary (for speed), keyed by USER ID
|
|
11
|
-
* - Agent Directory workflow is persistence layer (agents as activities, phases for state)
|
|
12
|
-
* - On startup: Load config from Hailer by extracting hailerProfile (user ID) from each agent
|
|
13
|
-
* - On change: Move agent activity between phases
|
|
14
|
-
* - Credentials: Auto-synced from Hailer to local storage on discovery
|
|
15
|
-
* - Orchestrator: Simply the first deployed bot with credentials (no special field needed)
|
|
16
|
-
*/
|
|
17
|
-
import { z } from 'zod';
|
|
18
|
-
import { Tool } from '../../tool-registry';
|
|
19
|
-
import { HailerApiClient } from '../../utils/index';
|
|
20
|
-
interface SchemaConfig {
|
|
21
|
-
agentDirectoryWorkflowId: string | null;
|
|
22
|
-
deployedPhaseId: string | null;
|
|
23
|
-
retiredPhaseId: string | null;
|
|
24
|
-
hailerProfileFieldId: string | null;
|
|
25
|
-
emailFieldId: string | null;
|
|
26
|
-
passwordFieldId: string | null;
|
|
27
|
-
botTypeFieldId: string | null;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Get workspace ID by Agent Directory workflow ID (reverse lookup)
|
|
31
|
-
*/
|
|
32
|
-
export declare function getWorkspaceByWorkflowId(workflowId: string): string | null;
|
|
33
|
-
/**
|
|
34
|
-
* Get all configured workspace IDs
|
|
35
|
-
*/
|
|
36
|
-
export declare function getAllConfiguredWorkspaces(): string[];
|
|
37
|
-
/**
|
|
38
|
-
* Set the active workspace ID (called when switching workspaces)
|
|
39
|
-
*/
|
|
40
|
-
export declare function setActiveWorkspace(workspaceId: string): void;
|
|
41
|
-
/**
|
|
42
|
-
* Get the active workspace ID
|
|
43
|
-
*/
|
|
44
|
-
export declare function getActiveWorkspace(): string | null;
|
|
45
|
-
/**
|
|
46
|
-
* Get schema for a workspace
|
|
47
|
-
*/
|
|
48
|
-
export declare function getWorkspaceSchema(workspaceId: string): SchemaConfig | null;
|
|
49
|
-
/**
|
|
50
|
-
* Set schema for a workspace
|
|
51
|
-
*/
|
|
52
|
-
export declare function setWorkspaceSchema(workspaceId: string, schema: SchemaConfig): void;
|
|
53
|
-
/**
|
|
54
|
-
* Get discovered workflow ID for a workspace (or active workspace if not specified)
|
|
55
|
-
*/
|
|
56
|
-
export declare function getAgentDirectoryWorkflowId(workspaceId?: string): string | null;
|
|
57
|
-
/**
|
|
58
|
-
* Get discovered phase IDs for a workspace (or active workspace if not specified)
|
|
59
|
-
*/
|
|
60
|
-
export declare function getPhaseIds(workspaceId?: string): {
|
|
61
|
-
deployed: string | null;
|
|
62
|
-
retired: string | null;
|
|
63
|
-
};
|
|
64
|
-
/**
|
|
65
|
-
* Available bots - single source of truth
|
|
66
|
-
*
|
|
67
|
-
* All bots that can be enabled/disabled in the workspace.
|
|
68
|
-
* This list should match the AI Hub app and agent definitions.
|
|
69
|
-
*/
|
|
70
|
-
export declare const AVAILABLE_BOTS: {
|
|
71
|
-
id: string;
|
|
72
|
-
name: string;
|
|
73
|
-
description: string;
|
|
74
|
-
icon: string;
|
|
75
|
-
}[];
|
|
76
|
-
/**
|
|
77
|
-
* Get the orchestrator user ID
|
|
78
|
-
* Returns the user ID of the bot marked as orchestrator in Agent Directory
|
|
79
|
-
*/
|
|
80
|
-
export declare function getOrchestratorUserId(): string | null;
|
|
81
|
-
/**
|
|
82
|
-
* Set the orchestrator user ID
|
|
83
|
-
* Called during Agent Directory sync - set to first deployed bot with credentials
|
|
84
|
-
*/
|
|
85
|
-
export declare function setOrchestratorUserId(userId: string | null): void;
|
|
86
|
-
export declare function onBotStateChange(callback: (botId: string, enabled: boolean) => void): void;
|
|
87
|
-
export declare function onBotCredentialsChange(callback: (botId: string) => void): void;
|
|
88
|
-
export declare function onDaemonRestartNeeded(callback: () => void): void;
|
|
89
|
-
/**
|
|
90
|
-
* Cleanup function to clear pending timers and state on shutdown
|
|
91
|
-
* Should be called from Core.stop() to prevent orphaned callbacks
|
|
92
|
-
*/
|
|
93
|
-
export declare function cleanupBotConfig(): void;
|
|
94
|
-
export declare function getBotState(): Record<string, boolean>;
|
|
95
|
-
/**
|
|
96
|
-
* Get the user ID associated with a bot
|
|
97
|
-
*/
|
|
98
|
-
export declare function getBotUserId(botId: string): string | null;
|
|
99
|
-
/**
|
|
100
|
-
* Get the bot type for a user ID
|
|
101
|
-
* Returns values like 'orchestrator', 'workflow-expert', 'bug-fixer', etc.
|
|
102
|
-
*/
|
|
103
|
-
export declare function getBotType(userId: string): string | null;
|
|
104
|
-
/**
|
|
105
|
-
* Get all enabled bots with their types
|
|
106
|
-
* Returns map of userId -> botType for enabled bots only
|
|
107
|
-
*/
|
|
108
|
-
export declare function getEnabledBotsWithTypes(): Map<string, string | null>;
|
|
109
|
-
/**
|
|
110
|
-
* Set the user ID associated with a bot
|
|
111
|
-
*/
|
|
112
|
-
export declare function setBotUserId(botId: string, userId: string | null): void;
|
|
113
|
-
/**
|
|
114
|
-
* Set bot enabled state
|
|
115
|
-
*
|
|
116
|
-
* Updates in-memory state and persists to Agent Directory by moving
|
|
117
|
-
* the agent activity to the appropriate phase (deployed/retired).
|
|
118
|
-
*/
|
|
119
|
-
export declare function setBotEnabled(botId: string, enabled: boolean): void;
|
|
120
|
-
/**
|
|
121
|
-
* Handle activity phase change signal from Hailer
|
|
122
|
-
*
|
|
123
|
-
* Called by signal-handler when an activity.updated signal is received.
|
|
124
|
-
* Updates bot state if the activity belongs to Agent Directory workflow.
|
|
125
|
-
*
|
|
126
|
-
* NEW: Now looks up activities by user ID instead of bot type.
|
|
127
|
-
*
|
|
128
|
-
* @param processId - Workflow ID from the signal
|
|
129
|
-
* @param activityIds - Array of activity IDs that were updated
|
|
130
|
-
* @param newPhaseId - The phase the activities moved to
|
|
131
|
-
*/
|
|
132
|
-
export declare function handleActivityPhaseChange(processId: string, activityIds: string[], newPhaseId: string): Promise<void>;
|
|
133
|
-
/**
|
|
134
|
-
* Force reload bot config from Hailer
|
|
135
|
-
*
|
|
136
|
-
* Can be called to manually refresh state from Hailer.
|
|
137
|
-
* NEW: Now works with user IDs instead of bot IDs.
|
|
138
|
-
*
|
|
139
|
-
* Also handles hot-reload: if schema discovery hasn't succeeded yet
|
|
140
|
-
* (e.g., AI Hub template wasn't installed at startup), it will
|
|
141
|
-
* retry discovery and initialize the daemon.
|
|
142
|
-
*/
|
|
143
|
-
export declare function reloadConfigFromHailer(): Promise<void>;
|
|
144
|
-
/**
|
|
145
|
-
* Initialize persistence layer
|
|
146
|
-
* Called once during MCP server startup
|
|
147
|
-
*
|
|
148
|
-
* Loads bot config from local files only (no Hailer API calls on startup).
|
|
149
|
-
* Real-time updates from Hailer are handled via signal handler when activities change.
|
|
150
|
-
*
|
|
151
|
-
* @param client - HailerApiClient instance for API calls
|
|
152
|
-
*/
|
|
153
|
-
/**
|
|
154
|
-
* Set the target workspace ID for bot config operations
|
|
155
|
-
* Called by signal handler when workspace is switched
|
|
156
|
-
*/
|
|
157
|
-
export declare function initBotConfigPersistence(client: HailerApiClient): Promise<void>;
|
|
158
|
-
/**
|
|
159
|
-
* Initialize workspace schema for a specific workspace
|
|
160
|
-
* Called by bot clients after connecting to discover the Agent Directory in that workspace
|
|
161
|
-
* @param client - HailerApiClient for API calls
|
|
162
|
-
* @param workspaceId - The workspace ID to initialize schema for
|
|
163
|
-
*/
|
|
164
|
-
export declare function initWorkspaceSchema(client: HailerApiClient, workspaceId: string): Promise<boolean>;
|
|
165
|
-
/**
|
|
166
|
-
* Check if persistence is initialized
|
|
167
|
-
*/
|
|
168
|
-
export declare function isPersistenceInitialized(): boolean;
|
|
169
|
-
/**
|
|
170
|
-
* Bot credentials interface
|
|
171
|
-
*/
|
|
172
|
-
export interface BotCredentials {
|
|
173
|
-
email?: string;
|
|
174
|
-
password?: string;
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Get bot credentials from Agent Directory
|
|
178
|
-
*
|
|
179
|
-
* Reads the email and password fields from the bot's activity.
|
|
180
|
-
* Password is masked for security unless showPassword is true.
|
|
181
|
-
* Falls back to local file storage if Hailer is unavailable.
|
|
182
|
-
*
|
|
183
|
-
* @param botIdOrActivityId - The bot ID (hal, bugFixer, etc.) or activity ID
|
|
184
|
-
* @param showPassword - If true, returns unmasked password. Default false for security.
|
|
185
|
-
* @returns Credentials or null if not found
|
|
186
|
-
*/
|
|
187
|
-
export declare function getBotCredentials(botIdOrActivityId: string, showPassword?: boolean): Promise<BotCredentials | null>;
|
|
188
|
-
/**
|
|
189
|
-
* Update bot credentials in Agent Directory
|
|
190
|
-
*
|
|
191
|
-
* Writes the email and/or password to the bot's activity fields.
|
|
192
|
-
* Only updates fields that are provided.
|
|
193
|
-
* Saves to local file storage as backup (and uses as fallback if Hailer unavailable).
|
|
194
|
-
*
|
|
195
|
-
* @param botIdOrActivityId - The bot ID (hal, bugFixer, etc.) or raw activity ID
|
|
196
|
-
* @param credentials - Credentials to update (email and/or password)
|
|
197
|
-
*/
|
|
198
|
-
export declare function updateBotCredentials(botIdOrActivityId: string, credentials: BotCredentials): Promise<void>;
|
|
199
|
-
/**
|
|
200
|
-
* Get unmasked bot credentials for daemon creation
|
|
201
|
-
*
|
|
202
|
-
* NEW: Now primarily looks up by user ID instead of bot ID.
|
|
203
|
-
* This function returns the actual password (not masked) from local storage.
|
|
204
|
-
* Should only be used internally for creating bot daemon instances.
|
|
205
|
-
*
|
|
206
|
-
* @param userIdOrBotId - The user ID or legacy bot ID (hal, bugFixer, etc.)
|
|
207
|
-
* @returns Unmasked credentials or null if not found
|
|
208
|
-
*/
|
|
209
|
-
export declare function getLocalBotCredentials(userIdOrBotId: string): {
|
|
210
|
-
email: string;
|
|
211
|
-
password: string;
|
|
212
|
-
displayName?: string;
|
|
213
|
-
} | null;
|
|
214
|
-
/**
|
|
215
|
-
* Get all local bot credentials (for daemon initialization)
|
|
216
|
-
* Returns all bots stored in .bot-credentials.json
|
|
217
|
-
*/
|
|
218
|
-
export declare function getAllLocalBotCredentials(): Record<string, {
|
|
219
|
-
email: string;
|
|
220
|
-
password: string;
|
|
221
|
-
displayName?: string;
|
|
222
|
-
}>;
|
|
223
|
-
/**
|
|
224
|
-
* Get persistence status info (for debugging)
|
|
225
|
-
*/
|
|
226
|
-
export declare function getPersistenceStatus(): {
|
|
227
|
-
initialized: boolean;
|
|
228
|
-
workflowId: string | null;
|
|
229
|
-
deployedPhaseId: string | null;
|
|
230
|
-
retiredPhaseId: string | null;
|
|
231
|
-
agentActivityIds: Record<string, string>;
|
|
232
|
-
hasClient: boolean;
|
|
233
|
-
};
|
|
234
|
-
/**
|
|
235
|
-
* List available bots and their status
|
|
236
|
-
*/
|
|
237
|
-
export declare const listBotsConfigTool: Tool;
|
|
238
|
-
/**
|
|
239
|
-
* Enable a bot
|
|
240
|
-
*/
|
|
241
|
-
export declare const enableBotTool: Tool;
|
|
242
|
-
/**
|
|
243
|
-
* Disable a bot
|
|
244
|
-
*/
|
|
245
|
-
export declare const disableBotTool: Tool;
|
|
246
|
-
/**
|
|
247
|
-
* Check specialist status from Agent Directory
|
|
248
|
-
* Returns real-time status showing which specialists are deployed vs retired
|
|
249
|
-
*/
|
|
250
|
-
export declare const checkSpecialistStatusTool: Tool;
|
|
251
|
-
export declare const botConfigTools: Tool<z.ZodType<any, z.ZodTypeDef, any>>[];
|
|
252
|
-
export {};
|
|
253
|
-
//# sourceMappingURL=core.d.ts.map
|