overmind-mcp 3.4.3 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/services/HermesGatewayManager.d.ts +92 -0
- package/dist/services/HermesGatewayManager.d.ts.map +1 -0
- package/dist/services/HermesGatewayManager.js +255 -0
- package/dist/services/HermesGatewayManager.js.map +1 -0
- package/dist/services/HermesGatewayRunner.d.ts +82 -0
- package/dist/services/HermesGatewayRunner.d.ts.map +1 -0
- package/dist/services/HermesGatewayRunner.js +249 -0
- package/dist/services/HermesGatewayRunner.js.map +1 -0
- package/dist/tools/run_hermes.d.ts.map +1 -1
- package/dist/tools/run_hermes.js +35 -12
- package/dist/tools/run_hermes.js.map +1 -1
- package/docs/kanbanroadmap.md +108 -0
- package/package.json +1 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HermesGatewayManager — Manages the Hermes API Server lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* ╔══════════════════════════════════════════════════════════════════════╗
|
|
5
|
+
* ║ PURPOSE ║
|
|
6
|
+
* ║ ║
|
|
7
|
+
* ║ Singleton that detects, validates, and ensures the Hermes API ║
|
|
8
|
+
* ║ Server (gateway/platforms/api_server.py) is reachable. ║
|
|
9
|
+
* ║ ║
|
|
10
|
+
* ║ The API Server is a platform adapter inside the Hermes gateway ║
|
|
11
|
+
* ║ process. It exposes an OpenAI-compatible HTTP+SSE API: ║
|
|
12
|
+
* ║ ║
|
|
13
|
+
* ║ GET /health → {"status": "ok", ...} ║
|
|
14
|
+
* ║ GET /v1/models → OpenAI model list ║
|
|
15
|
+
* ║ GET /v1/capabilities → Feature flags ║
|
|
16
|
+
* ║ POST /v1/chat/completions → Chat (streaming SSE or JSON) ║
|
|
17
|
+
* ║ POST /v1/responses → Responses API (stateful) ║
|
|
18
|
+
* ║ POST /v1/runs → Async run (returns run_id) ║
|
|
19
|
+
* ║ GET /v1/runs/{id}/events → SSE lifecycle events ║
|
|
20
|
+
* ║ POST /v1/runs/{id}/stop → Interrupt a run ║
|
|
21
|
+
* ║ POST /v1/runs/{id}/approval → Resolve pending approval ║
|
|
22
|
+
* ║ ║
|
|
23
|
+
* ║ Configuration (read from Hermes .env): ║
|
|
24
|
+
* ║ API_SERVER_ENABLED=1 → enables the adapter ║
|
|
25
|
+
* ║ API_SERVER_KEY=<secret> → Bearer token for auth ║
|
|
26
|
+
* ║ API_SERVER_PORT=8642 → listen port (default: 8642) ║
|
|
27
|
+
* ║ API_SERVER_HOST=127.0.0.1 → listen host (default: loopback) ║
|
|
28
|
+
* ║ ║
|
|
29
|
+
* ║ This manager does NOT start the gateway — that's Hermes' job ║
|
|
30
|
+
* ║ (via `hermes gateway start`). It only detects and health-checks. ║
|
|
31
|
+
* ╚══════════════════════════════════════════════════════════════════════╝
|
|
32
|
+
*/
|
|
33
|
+
export interface GatewayInfo {
|
|
34
|
+
/** Base URL of the API server, e.g. http://127.0.0.1:8642 */
|
|
35
|
+
url: string;
|
|
36
|
+
/** Bearer token for Authorization header */
|
|
37
|
+
apiKey: string;
|
|
38
|
+
/** Port the server listens on */
|
|
39
|
+
port: number;
|
|
40
|
+
/** Host the server listens on */
|
|
41
|
+
host: string;
|
|
42
|
+
/** True if the last health check succeeded */
|
|
43
|
+
healthy: boolean;
|
|
44
|
+
/** PID of the gateway process (from health/detailed), if available */
|
|
45
|
+
pid: number | null;
|
|
46
|
+
/** Hermes version reported by the server */
|
|
47
|
+
version: string | null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Singleton manager for the Hermes API Server connection.
|
|
51
|
+
*
|
|
52
|
+
* Call `await HermesGatewayManager.getInstance()` to get a healthy gateway
|
|
53
|
+
* info object. The first call probes the server; subsequent calls return
|
|
54
|
+
* the cached state with periodic re-validation.
|
|
55
|
+
*/
|
|
56
|
+
export declare class HermesGatewayManager {
|
|
57
|
+
private static instance;
|
|
58
|
+
private cachedInfo;
|
|
59
|
+
private lastHealthCheck;
|
|
60
|
+
private readonly HEALTH_CHECK_TTL_MS;
|
|
61
|
+
private constructor();
|
|
62
|
+
static getInstance(): HermesGatewayManager;
|
|
63
|
+
/**
|
|
64
|
+
* Probe the API server health endpoint.
|
|
65
|
+
* Returns the raw JSON response or null on failure.
|
|
66
|
+
*/
|
|
67
|
+
private probeHealth;
|
|
68
|
+
/**
|
|
69
|
+
* Get detailed health info (includes PID, gateway state, platform status).
|
|
70
|
+
*/
|
|
71
|
+
getDetailedHealth(): Promise<Record<string, unknown> | null>;
|
|
72
|
+
/**
|
|
73
|
+
* Ensure the API server is reachable. Probes health, caches result.
|
|
74
|
+
*
|
|
75
|
+
* @param forceRefresh Skip the cache TTL and re-probe.
|
|
76
|
+
* @returns GatewayInfo if healthy, null if unreachable.
|
|
77
|
+
*/
|
|
78
|
+
ensureReady(forceRefresh?: boolean): Promise<GatewayInfo | null>;
|
|
79
|
+
/**
|
|
80
|
+
* Check if the gateway is ready (quick boolean check).
|
|
81
|
+
*/
|
|
82
|
+
isReady(): Promise<boolean>;
|
|
83
|
+
/**
|
|
84
|
+
* Get cached info without probing. Returns last known state.
|
|
85
|
+
*/
|
|
86
|
+
getCachedInfo(): GatewayInfo | null;
|
|
87
|
+
/**
|
|
88
|
+
* Force a fresh health check on next ensureReady() call.
|
|
89
|
+
*/
|
|
90
|
+
invalidate(): void;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=HermesGatewayManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HermesGatewayManager.d.ts","sourceRoot":"","sources":["../../src/services/HermesGatewayManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AASH,MAAM,WAAW,WAAW;IAC1B,6DAA6D;IAC7D,GAAG,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,sEAAsE;IACtE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AA8FD;;;;;;GAMG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAqC;IAC5D,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAU;IAE9C,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,oBAAoB;IAO1C;;;OAGG;YACW,WAAW;IAczB;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAgBlE;;;;;OAKG;IACG,WAAW,CAAC,YAAY,UAAQ,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA+DpE;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAKjC;;OAEG;IACH,aAAa,IAAI,WAAW,GAAG,IAAI;IAInC;;OAEG;IACH,UAAU,IAAI,IAAI;CAGnB"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HermesGatewayManager — Manages the Hermes API Server lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* ╔══════════════════════════════════════════════════════════════════════╗
|
|
5
|
+
* ║ PURPOSE ║
|
|
6
|
+
* ║ ║
|
|
7
|
+
* ║ Singleton that detects, validates, and ensures the Hermes API ║
|
|
8
|
+
* ║ Server (gateway/platforms/api_server.py) is reachable. ║
|
|
9
|
+
* ║ ║
|
|
10
|
+
* ║ The API Server is a platform adapter inside the Hermes gateway ║
|
|
11
|
+
* ║ process. It exposes an OpenAI-compatible HTTP+SSE API: ║
|
|
12
|
+
* ║ ║
|
|
13
|
+
* ║ GET /health → {"status": "ok", ...} ║
|
|
14
|
+
* ║ GET /v1/models → OpenAI model list ║
|
|
15
|
+
* ║ GET /v1/capabilities → Feature flags ║
|
|
16
|
+
* ║ POST /v1/chat/completions → Chat (streaming SSE or JSON) ║
|
|
17
|
+
* ║ POST /v1/responses → Responses API (stateful) ║
|
|
18
|
+
* ║ POST /v1/runs → Async run (returns run_id) ║
|
|
19
|
+
* ║ GET /v1/runs/{id}/events → SSE lifecycle events ║
|
|
20
|
+
* ║ POST /v1/runs/{id}/stop → Interrupt a run ║
|
|
21
|
+
* ║ POST /v1/runs/{id}/approval → Resolve pending approval ║
|
|
22
|
+
* ║ ║
|
|
23
|
+
* ║ Configuration (read from Hermes .env): ║
|
|
24
|
+
* ║ API_SERVER_ENABLED=1 → enables the adapter ║
|
|
25
|
+
* ║ API_SERVER_KEY=<secret> → Bearer token for auth ║
|
|
26
|
+
* ║ API_SERVER_PORT=8642 → listen port (default: 8642) ║
|
|
27
|
+
* ║ API_SERVER_HOST=127.0.0.1 → listen host (default: loopback) ║
|
|
28
|
+
* ║ ║
|
|
29
|
+
* ║ This manager does NOT start the gateway — that's Hermes' job ║
|
|
30
|
+
* ║ (via `hermes gateway start`). It only detects and health-checks. ║
|
|
31
|
+
* ╚══════════════════════════════════════════════════════════════════════╝
|
|
32
|
+
*/
|
|
33
|
+
import fs from 'fs';
|
|
34
|
+
import path from 'path';
|
|
35
|
+
import os from 'os';
|
|
36
|
+
import { rootLogger } from '../lib/logger.js';
|
|
37
|
+
const logger = rootLogger.child({ module: 'HermesGatewayManager' });
|
|
38
|
+
/**
|
|
39
|
+
* Resolve the Hermes home directory.
|
|
40
|
+
* On Windows: AppData\Local\hermes (official install)
|
|
41
|
+
* On Linux/macOS: ~/.hermes
|
|
42
|
+
*/
|
|
43
|
+
function getHermesHome() {
|
|
44
|
+
// 1. Explicit env var
|
|
45
|
+
if (process.env.HERMES_HOME)
|
|
46
|
+
return process.env.HERMES_HOME;
|
|
47
|
+
// 2. Windows official install
|
|
48
|
+
if (process.platform === 'win32') {
|
|
49
|
+
const localAppData = process.env.LOCALAPPDATA || process.env.USERPROFILE || os.homedir();
|
|
50
|
+
return path.join(localAppData, 'hermes');
|
|
51
|
+
}
|
|
52
|
+
// 3. POSIX
|
|
53
|
+
return path.join(os.homedir(), '.hermes');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Read API_SERVER_KEY from the Hermes .env file.
|
|
57
|
+
* The key is required by the API server for Bearer auth.
|
|
58
|
+
*/
|
|
59
|
+
function readApiKeyFromEnv() {
|
|
60
|
+
const hermesHome = getHermesHome();
|
|
61
|
+
const envPath = path.join(hermesHome, '.env');
|
|
62
|
+
try {
|
|
63
|
+
const content = fs.readFileSync(envPath, 'utf-8');
|
|
64
|
+
for (const line of content.split('\n')) {
|
|
65
|
+
const trimmed = line.trim();
|
|
66
|
+
if (trimmed.startsWith('API_SERVER_KEY=')) {
|
|
67
|
+
const value = trimmed.slice('API_SERVER_KEY='.length).trim();
|
|
68
|
+
// Remove surrounding quotes if present
|
|
69
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
70
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
71
|
+
return value.slice(1, -1);
|
|
72
|
+
}
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// .env not found or unreadable
|
|
79
|
+
}
|
|
80
|
+
// Fallback: environment variable
|
|
81
|
+
return process.env.API_SERVER_KEY || null;
|
|
82
|
+
}
|
|
83
|
+
/** Read port from .env or use default */
|
|
84
|
+
function readPortFromEnv() {
|
|
85
|
+
const hermesHome = getHermesHome();
|
|
86
|
+
const envPath = path.join(hermesHome, '.env');
|
|
87
|
+
try {
|
|
88
|
+
const content = fs.readFileSync(envPath, 'utf-8');
|
|
89
|
+
for (const line of content.split('\n')) {
|
|
90
|
+
const trimmed = line.trim();
|
|
91
|
+
if (trimmed.startsWith('API_SERVER_PORT=')) {
|
|
92
|
+
const port = parseInt(trimmed.slice('API_SERVER_PORT='.length).trim(), 10);
|
|
93
|
+
if (!isNaN(port) && port > 0 && port < 65536)
|
|
94
|
+
return port;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// ignore
|
|
100
|
+
}
|
|
101
|
+
// Fallback: env var or default
|
|
102
|
+
const envPort = parseInt(process.env.API_SERVER_PORT || '', 10);
|
|
103
|
+
return !isNaN(envPort) && envPort > 0 ? envPort : 8642;
|
|
104
|
+
}
|
|
105
|
+
/** Read host from .env or use default */
|
|
106
|
+
function readHostFromEnv() {
|
|
107
|
+
const hermesHome = getHermesHome();
|
|
108
|
+
const envPath = path.join(hermesHome, '.env');
|
|
109
|
+
try {
|
|
110
|
+
const content = fs.readFileSync(envPath, 'utf-8');
|
|
111
|
+
for (const line of content.split('\n')) {
|
|
112
|
+
const trimmed = line.trim();
|
|
113
|
+
if (trimmed.startsWith('API_SERVER_HOST=')) {
|
|
114
|
+
return trimmed.slice('API_SERVER_HOST='.length).trim().replace(/['"]/g, '');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// ignore
|
|
120
|
+
}
|
|
121
|
+
return process.env.API_SERVER_HOST || '127.0.0.1';
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Singleton manager for the Hermes API Server connection.
|
|
125
|
+
*
|
|
126
|
+
* Call `await HermesGatewayManager.getInstance()` to get a healthy gateway
|
|
127
|
+
* info object. The first call probes the server; subsequent calls return
|
|
128
|
+
* the cached state with periodic re-validation.
|
|
129
|
+
*/
|
|
130
|
+
export class HermesGatewayManager {
|
|
131
|
+
static instance = null;
|
|
132
|
+
cachedInfo = null;
|
|
133
|
+
lastHealthCheck = 0;
|
|
134
|
+
HEALTH_CHECK_TTL_MS = 10_000; // re-check at most every 10s
|
|
135
|
+
constructor() { }
|
|
136
|
+
static getInstance() {
|
|
137
|
+
if (!HermesGatewayManager.instance) {
|
|
138
|
+
HermesGatewayManager.instance = new HermesGatewayManager();
|
|
139
|
+
}
|
|
140
|
+
return HermesGatewayManager.instance;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Probe the API server health endpoint.
|
|
144
|
+
* Returns the raw JSON response or null on failure.
|
|
145
|
+
*/
|
|
146
|
+
async probeHealth(baseUrl, apiKey) {
|
|
147
|
+
try {
|
|
148
|
+
const response = await fetch(`${baseUrl}/health`, {
|
|
149
|
+
method: 'GET',
|
|
150
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
151
|
+
signal: AbortSignal.timeout(5000),
|
|
152
|
+
});
|
|
153
|
+
if (!response.ok)
|
|
154
|
+
return null;
|
|
155
|
+
return (await response.json());
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get detailed health info (includes PID, gateway state, platform status).
|
|
163
|
+
*/
|
|
164
|
+
async getDetailedHealth() {
|
|
165
|
+
const info = await this.ensureReady();
|
|
166
|
+
if (!info)
|
|
167
|
+
return null;
|
|
168
|
+
try {
|
|
169
|
+
const response = await fetch(`${info.url}/health/detailed`, {
|
|
170
|
+
method: 'GET',
|
|
171
|
+
headers: { Authorization: `Bearer ${info.apiKey}` },
|
|
172
|
+
signal: AbortSignal.timeout(5000),
|
|
173
|
+
});
|
|
174
|
+
if (!response.ok)
|
|
175
|
+
return null;
|
|
176
|
+
return (await response.json());
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Ensure the API server is reachable. Probes health, caches result.
|
|
184
|
+
*
|
|
185
|
+
* @param forceRefresh Skip the cache TTL and re-probe.
|
|
186
|
+
* @returns GatewayInfo if healthy, null if unreachable.
|
|
187
|
+
*/
|
|
188
|
+
async ensureReady(forceRefresh = false) {
|
|
189
|
+
const now = Date.now();
|
|
190
|
+
if (!forceRefresh &&
|
|
191
|
+
this.cachedInfo &&
|
|
192
|
+
this.cachedInfo.healthy &&
|
|
193
|
+
now - this.lastHealthCheck < this.HEALTH_CHECK_TTL_MS) {
|
|
194
|
+
return this.cachedInfo;
|
|
195
|
+
}
|
|
196
|
+
// Read config from Hermes .env
|
|
197
|
+
const apiKey = readApiKeyFromEnv();
|
|
198
|
+
const port = readPortFromEnv();
|
|
199
|
+
const host = readHostFromEnv();
|
|
200
|
+
const baseUrl = `http://${host}:${port}`;
|
|
201
|
+
if (!apiKey) {
|
|
202
|
+
logger.warn('[HermesGatewayManager] API_SERVER_KEY not found in Hermes .env — API server not configured.');
|
|
203
|
+
this.cachedInfo = {
|
|
204
|
+
url: baseUrl,
|
|
205
|
+
apiKey: '',
|
|
206
|
+
port,
|
|
207
|
+
host,
|
|
208
|
+
healthy: false,
|
|
209
|
+
pid: null,
|
|
210
|
+
version: null,
|
|
211
|
+
};
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
// Probe health
|
|
215
|
+
const health = await this.probeHealth(baseUrl, apiKey);
|
|
216
|
+
const healthy = health?.status === 'ok';
|
|
217
|
+
this.cachedInfo = {
|
|
218
|
+
url: baseUrl,
|
|
219
|
+
apiKey,
|
|
220
|
+
port,
|
|
221
|
+
host,
|
|
222
|
+
healthy,
|
|
223
|
+
pid: null,
|
|
224
|
+
version: health?.version || null,
|
|
225
|
+
};
|
|
226
|
+
this.lastHealthCheck = now;
|
|
227
|
+
if (healthy) {
|
|
228
|
+
logger.info({ url: baseUrl, version: this.cachedInfo.version }, '[HermesGatewayManager] ✅ API server healthy.');
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
logger.warn({ url: baseUrl }, '[HermesGatewayManager] ⚠️ API server not reachable. Run `hermes gateway restart` after setting API_SERVER_ENABLED=1.');
|
|
232
|
+
}
|
|
233
|
+
return healthy ? this.cachedInfo : null;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Check if the gateway is ready (quick boolean check).
|
|
237
|
+
*/
|
|
238
|
+
async isReady() {
|
|
239
|
+
const info = await this.ensureReady();
|
|
240
|
+
return info !== null;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Get cached info without probing. Returns last known state.
|
|
244
|
+
*/
|
|
245
|
+
getCachedInfo() {
|
|
246
|
+
return this.cachedInfo;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Force a fresh health check on next ensureReady() call.
|
|
250
|
+
*/
|
|
251
|
+
invalidate() {
|
|
252
|
+
this.lastHealthCheck = 0;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=HermesGatewayManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HermesGatewayManager.js","sourceRoot":"","sources":["../../src/services/HermesGatewayManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HermesGatewayRunner — HTTP-based runner for the Hermes API Server.
|
|
3
|
+
*
|
|
4
|
+
* ╔══════════════════════════════════════════════════════════════════════╗
|
|
5
|
+
* ║ ARCHITECTURE (v3.5 — Gateway Integration) ║
|
|
6
|
+
* ║ ║
|
|
7
|
+
* ║ Replaces the subprocess spawn in HermesRunner with HTTP+SSE calls ║
|
|
8
|
+
* ║ to the Hermes API Server (gateway/platforms/api_server.py). ║
|
|
9
|
+
* ║ ║
|
|
10
|
+
* ║ BENEFITS over HermesRunner (spawn): ║
|
|
11
|
+
* ║ - No Python startup per call (~5-10s saved) ║
|
|
12
|
+
* ║ - SSE streaming output in real-time ║
|
|
13
|
+
* ║ - Native session management via X-Hermes-Session-Id header ║
|
|
14
|
+
* ║ - Proper abort via fetch AbortController ║
|
|
15
|
+
* ║ - Model/provider swap via config, not CLI flags ║
|
|
16
|
+
* ║ ║
|
|
17
|
+
* ║ ENDPOINTS USED: ║
|
|
18
|
+
* ║ POST /v1/chat/completions → main chat (streaming SSE or JSON) ║
|
|
19
|
+
* ║ GET /health → connectivity check ║
|
|
20
|
+
* ║ ║
|
|
21
|
+
* ║ FALLBACK: ║
|
|
22
|
+
* ║ If the API server is not running, falls back to HermesRunner ║
|
|
23
|
+
* ║ (subprocess spawn) for backward compatibility. ║
|
|
24
|
+
* ╚══════════════════════════════════════════════════════════════════════╝
|
|
25
|
+
*/
|
|
26
|
+
export interface GatewayRunOptions {
|
|
27
|
+
prompt: string;
|
|
28
|
+
agentName?: string;
|
|
29
|
+
sessionId?: string;
|
|
30
|
+
autoResume?: boolean;
|
|
31
|
+
model?: string;
|
|
32
|
+
provider?: string;
|
|
33
|
+
signal?: AbortSignal;
|
|
34
|
+
silent?: boolean;
|
|
35
|
+
/** Profile name for Hermes (maps to -p flag in spawn mode) */
|
|
36
|
+
profile?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface GatewayRunResult {
|
|
39
|
+
result: string;
|
|
40
|
+
sessionId?: string;
|
|
41
|
+
error?: string;
|
|
42
|
+
rawOutput?: string;
|
|
43
|
+
model?: string;
|
|
44
|
+
/** How the run was executed */
|
|
45
|
+
transport: 'gateway-http' | 'fallback-spawn';
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Runner that talks to the Hermes API Server via HTTP+SSE.
|
|
49
|
+
*
|
|
50
|
+
* Falls back to HermesRunner (subprocess spawn) if the API server is not
|
|
51
|
+
* available — ensuring zero downtime during the migration.
|
|
52
|
+
*/
|
|
53
|
+
export declare class HermesGatewayRunner {
|
|
54
|
+
private manager;
|
|
55
|
+
constructor();
|
|
56
|
+
/**
|
|
57
|
+
* Run a prompt against the Hermes API Server.
|
|
58
|
+
*
|
|
59
|
+
* If the server is not reachable, returns an error with transport='fallback-spawn'
|
|
60
|
+
* so the caller can decide to use the old HermesRunner.
|
|
61
|
+
*/
|
|
62
|
+
runAgent(options: GatewayRunOptions): Promise<GatewayRunResult>;
|
|
63
|
+
/**
|
|
64
|
+
* Execute a chat completion against the API server.
|
|
65
|
+
*
|
|
66
|
+
* Uses streaming SSE to get real-time output, assembling the final
|
|
67
|
+
* text from delta chunks.
|
|
68
|
+
*/
|
|
69
|
+
private executeChat;
|
|
70
|
+
/**
|
|
71
|
+
* Parse the SSE stream from /v1/chat/completions.
|
|
72
|
+
*
|
|
73
|
+
* Format (OpenAI-compatible):
|
|
74
|
+
* data: {"choices":[{"delta":{"content":"hello"}}]}
|
|
75
|
+
* data: {"choices":[{"delta":{"content":" world"}}]}
|
|
76
|
+
* data: [DONE]
|
|
77
|
+
*
|
|
78
|
+
* Assembles full text, streams chunks to agent_lifecycle in real-time.
|
|
79
|
+
*/
|
|
80
|
+
private parseSSEStream;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=HermesGatewayRunner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HermesGatewayRunner.d.ts","sourceRoot":"","sources":["../../src/services/HermesGatewayRunner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAiBH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,SAAS,EAAE,cAAc,GAAG,gBAAgB,CAAC;CAC9C;AAQD;;;;;GAKG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,OAAO,CAAuB;;IAMtC;;;;;OAKG;IACG,QAAQ,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAuFrE;;;;;OAKG;YACW,WAAW;IAwEzB;;;;;;;;;OASG;YACW,cAAc;CA8D7B"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HermesGatewayRunner — HTTP-based runner for the Hermes API Server.
|
|
3
|
+
*
|
|
4
|
+
* ╔══════════════════════════════════════════════════════════════════════╗
|
|
5
|
+
* ║ ARCHITECTURE (v3.5 — Gateway Integration) ║
|
|
6
|
+
* ║ ║
|
|
7
|
+
* ║ Replaces the subprocess spawn in HermesRunner with HTTP+SSE calls ║
|
|
8
|
+
* ║ to the Hermes API Server (gateway/platforms/api_server.py). ║
|
|
9
|
+
* ║ ║
|
|
10
|
+
* ║ BENEFITS over HermesRunner (spawn): ║
|
|
11
|
+
* ║ - No Python startup per call (~5-10s saved) ║
|
|
12
|
+
* ║ - SSE streaming output in real-time ║
|
|
13
|
+
* ║ - Native session management via X-Hermes-Session-Id header ║
|
|
14
|
+
* ║ - Proper abort via fetch AbortController ║
|
|
15
|
+
* ║ - Model/provider swap via config, not CLI flags ║
|
|
16
|
+
* ║ ║
|
|
17
|
+
* ║ ENDPOINTS USED: ║
|
|
18
|
+
* ║ POST /v1/chat/completions → main chat (streaming SSE or JSON) ║
|
|
19
|
+
* ║ GET /health → connectivity check ║
|
|
20
|
+
* ║ ║
|
|
21
|
+
* ║ FALLBACK: ║
|
|
22
|
+
* ║ If the API server is not running, falls back to HermesRunner ║
|
|
23
|
+
* ║ (subprocess spawn) for backward compatibility. ║
|
|
24
|
+
* ╚══════════════════════════════════════════════════════════════════════╝
|
|
25
|
+
*/
|
|
26
|
+
import { HermesGatewayManager } from './HermesGatewayManager.js';
|
|
27
|
+
import { registerLiveAgent, appendLiveOutput, setLiveStatus, unregisterLiveAgent, } from '../lib/agent_lifecycle.js';
|
|
28
|
+
import { registerProcess } from '../lib/processRegistry.js';
|
|
29
|
+
import { withSpan } from '../lib/telemetry.js';
|
|
30
|
+
import { rootLogger } from '../lib/logger.js';
|
|
31
|
+
import { saveSessionId, getLastSessionId } from '../lib/sessions.js';
|
|
32
|
+
import { getWorkspaceDir } from '../lib/config.js';
|
|
33
|
+
const logger = rootLogger.child({ module: 'HermesGatewayRunner' });
|
|
34
|
+
/** Pseudo-PID for gateway runs (no real OS process to track) */
|
|
35
|
+
let gatewayPidCounter = 70000;
|
|
36
|
+
/** In-memory session map for gateway runs: agentName → sessionId */
|
|
37
|
+
const gatewaySessions = new Map();
|
|
38
|
+
/**
|
|
39
|
+
* Runner that talks to the Hermes API Server via HTTP+SSE.
|
|
40
|
+
*
|
|
41
|
+
* Falls back to HermesRunner (subprocess spawn) if the API server is not
|
|
42
|
+
* available — ensuring zero downtime during the migration.
|
|
43
|
+
*/
|
|
44
|
+
export class HermesGatewayRunner {
|
|
45
|
+
manager;
|
|
46
|
+
constructor() {
|
|
47
|
+
this.manager = HermesGatewayManager.getInstance();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Run a prompt against the Hermes API Server.
|
|
51
|
+
*
|
|
52
|
+
* If the server is not reachable, returns an error with transport='fallback-spawn'
|
|
53
|
+
* so the caller can decide to use the old HermesRunner.
|
|
54
|
+
*/
|
|
55
|
+
async runAgent(options) {
|
|
56
|
+
const { agentName } = options;
|
|
57
|
+
let { sessionId } = options;
|
|
58
|
+
// ─── Resolve session ──────────────────────────────────────────────────
|
|
59
|
+
if (options.autoResume && agentName && !sessionId) {
|
|
60
|
+
// Try in-memory gateway sessions first
|
|
61
|
+
const gwSession = gatewaySessions.get(agentName);
|
|
62
|
+
if (gwSession) {
|
|
63
|
+
sessionId = gwSession;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// Fall back to persisted sessions (from spawn mode)
|
|
67
|
+
const lastId = await getLastSessionId(agentName, getWorkspaceDir(), 'hermes');
|
|
68
|
+
if (lastId) {
|
|
69
|
+
sessionId = lastId;
|
|
70
|
+
logger.info({ sessionId }, '[GatewayRunner] Auto-resume from persisted sessions.');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return withSpan('hermes.gateway.runAgent', async (span) => {
|
|
75
|
+
span.setAttribute('agentName', agentName || '');
|
|
76
|
+
span.setAttribute('transport', 'gateway-http');
|
|
77
|
+
// ─── Ensure gateway is ready ──────────────────────────────────────
|
|
78
|
+
const gw = await this.manager.ensureReady();
|
|
79
|
+
if (!gw) {
|
|
80
|
+
return {
|
|
81
|
+
result: '',
|
|
82
|
+
error: 'GATEWAY_NOT_READY',
|
|
83
|
+
transport: 'fallback-spawn',
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
// ─── Register a pseudo-agent for lifecycle tracking ───────────────
|
|
87
|
+
const pseudoPid = ++gatewayPidCounter;
|
|
88
|
+
const abortController = new AbortController();
|
|
89
|
+
registerLiveAgent({
|
|
90
|
+
pid: pseudoPid,
|
|
91
|
+
runner: 'hermes-gateway',
|
|
92
|
+
agentName: agentName || 'anonymous',
|
|
93
|
+
sessionId: sessionId || '',
|
|
94
|
+
abortController,
|
|
95
|
+
cleanupFn: async () => {
|
|
96
|
+
abortController.abort();
|
|
97
|
+
},
|
|
98
|
+
childRef: null, // No child process — HTTP-based
|
|
99
|
+
});
|
|
100
|
+
// Also register in processRegistry for cross-system visibility
|
|
101
|
+
void registerProcess(pseudoPid, {
|
|
102
|
+
agentName: agentName || '',
|
|
103
|
+
runner: 'hermes-gateway',
|
|
104
|
+
configPath: getWorkspaceDir(),
|
|
105
|
+
});
|
|
106
|
+
try {
|
|
107
|
+
const result = await this.executeChat(gw, options, sessionId, pseudoPid, abortController.signal);
|
|
108
|
+
// Save session linkage
|
|
109
|
+
if (result.sessionId && agentName) {
|
|
110
|
+
gatewaySessions.set(agentName, result.sessionId);
|
|
111
|
+
await saveSessionId(agentName, result.sessionId, getWorkspaceDir(), 'hermes');
|
|
112
|
+
}
|
|
113
|
+
setLiveStatus(pseudoPid, result.error ? 'failed' : 'done', result.error ? 1 : 0);
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
118
|
+
logger.error({ error: errMsg, agentName }, '[GatewayRunner] Run failed.');
|
|
119
|
+
setLiveStatus(pseudoPid, 'failed', 1);
|
|
120
|
+
return {
|
|
121
|
+
result: '',
|
|
122
|
+
error: `GATEWAY_ERROR: ${errMsg}`,
|
|
123
|
+
transport: 'gateway-http',
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
unregisterLiveAgent(pseudoPid);
|
|
128
|
+
}
|
|
129
|
+
}, { agentName: agentName || '', transport: 'gateway-http' });
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Execute a chat completion against the API server.
|
|
133
|
+
*
|
|
134
|
+
* Uses streaming SSE to get real-time output, assembling the final
|
|
135
|
+
* text from delta chunks.
|
|
136
|
+
*/
|
|
137
|
+
async executeChat(gw, options, sessionId, pseudoPid, externalSignal) {
|
|
138
|
+
const { prompt, agentName, silent } = options;
|
|
139
|
+
// Build request headers
|
|
140
|
+
const headers = {
|
|
141
|
+
'Content-Type': 'application/json',
|
|
142
|
+
Authorization: `Bearer ${gw.apiKey}`,
|
|
143
|
+
};
|
|
144
|
+
// Session management via header
|
|
145
|
+
if (sessionId) {
|
|
146
|
+
headers['X-Hermes-Session-Id'] = sessionId;
|
|
147
|
+
}
|
|
148
|
+
// Profile selection via header (maps to -p <profile>)
|
|
149
|
+
const profile = options.profile || agentName;
|
|
150
|
+
if (profile && profile !== 'default') {
|
|
151
|
+
headers['X-Hermes-Profile'] = profile;
|
|
152
|
+
}
|
|
153
|
+
// Build request body (OpenAI chat completions format)
|
|
154
|
+
const body = {
|
|
155
|
+
model: options.model || 'hermes-agent',
|
|
156
|
+
messages: [{ role: 'user', content: prompt }],
|
|
157
|
+
stream: true, // Always stream — we assemble the final text
|
|
158
|
+
};
|
|
159
|
+
// Combine abort signals
|
|
160
|
+
const combinedSignal = externalSignal;
|
|
161
|
+
logger.info({ url: gw.url, agentName, sessionId: sessionId?.slice(0, 20), profile }, '[GatewayRunner] POST /v1/chat/completions (streaming)');
|
|
162
|
+
const response = await fetch(`${gw.url}/v1/chat/completions`, {
|
|
163
|
+
method: 'POST',
|
|
164
|
+
headers,
|
|
165
|
+
body: JSON.stringify(body),
|
|
166
|
+
signal: combinedSignal,
|
|
167
|
+
});
|
|
168
|
+
if (!response.ok) {
|
|
169
|
+
const errText = await response.text().catch(() => '(no body)');
|
|
170
|
+
return {
|
|
171
|
+
result: '',
|
|
172
|
+
error: `HTTP_${response.status}: ${errText.slice(0, 500)}`,
|
|
173
|
+
transport: 'gateway-http',
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
// ─── Parse SSE stream ────────────────────────────────────────────────
|
|
177
|
+
const fullText = await this.parseSSEStream(response, pseudoPid, silent, agentName);
|
|
178
|
+
// Extract session ID from response headers
|
|
179
|
+
const responseSessionId = response.headers.get('x-hermes-session-id') || undefined;
|
|
180
|
+
return {
|
|
181
|
+
result: fullText.trim(),
|
|
182
|
+
sessionId: responseSessionId || sessionId,
|
|
183
|
+
rawOutput: fullText,
|
|
184
|
+
model: options.model,
|
|
185
|
+
transport: 'gateway-http',
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Parse the SSE stream from /v1/chat/completions.
|
|
190
|
+
*
|
|
191
|
+
* Format (OpenAI-compatible):
|
|
192
|
+
* data: {"choices":[{"delta":{"content":"hello"}}]}
|
|
193
|
+
* data: {"choices":[{"delta":{"content":" world"}}]}
|
|
194
|
+
* data: [DONE]
|
|
195
|
+
*
|
|
196
|
+
* Assembles full text, streams chunks to agent_lifecycle in real-time.
|
|
197
|
+
*/
|
|
198
|
+
async parseSSEStream(response, pseudoPid, silent, agentName) {
|
|
199
|
+
let fullText = '';
|
|
200
|
+
const reader = response.body?.getReader();
|
|
201
|
+
if (!reader) {
|
|
202
|
+
throw new Error('No response body for SSE stream');
|
|
203
|
+
}
|
|
204
|
+
const decoder = new TextDecoder();
|
|
205
|
+
let buffer = '';
|
|
206
|
+
try {
|
|
207
|
+
while (true) {
|
|
208
|
+
const { done, value } = await reader.read();
|
|
209
|
+
if (done)
|
|
210
|
+
break;
|
|
211
|
+
buffer += decoder.decode(value, { stream: true });
|
|
212
|
+
// Process complete SSE events (separated by \n\n)
|
|
213
|
+
const events = buffer.split('\n\n');
|
|
214
|
+
buffer = events.pop() || ''; // Keep incomplete chunk in buffer
|
|
215
|
+
for (const event of events) {
|
|
216
|
+
const line = event.trim();
|
|
217
|
+
if (!line.startsWith('data: '))
|
|
218
|
+
continue;
|
|
219
|
+
const data = line.slice(6); // Remove "data: " prefix
|
|
220
|
+
// End of stream
|
|
221
|
+
if (data === '[DONE]')
|
|
222
|
+
continue;
|
|
223
|
+
try {
|
|
224
|
+
const parsed = JSON.parse(data);
|
|
225
|
+
const delta = parsed.choices?.[0]?.delta;
|
|
226
|
+
if (delta?.content) {
|
|
227
|
+
const chunk = delta.content;
|
|
228
|
+
fullText += chunk;
|
|
229
|
+
// Stream to agent_lifecycle for real-time output
|
|
230
|
+
appendLiveOutput(pseudoPid, chunk);
|
|
231
|
+
// Also write to stderr for live monitoring (matching HermesRunner pattern)
|
|
232
|
+
if (!silent && agentName) {
|
|
233
|
+
process.stderr.write(`[HermesGW:${agentName}] ${chunk}`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
// Non-JSON line (e.g., comments) — skip
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
finally {
|
|
244
|
+
reader.releaseLock?.();
|
|
245
|
+
}
|
|
246
|
+
return fullText;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=HermesGatewayRunner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HermesGatewayRunner.js","sourceRoot":"","sources":["../../src/services/HermesGatewayRunner.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run_hermes.d.ts","sourceRoot":"","sources":["../../src/tools/run_hermes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"run_hermes.d.ts","sourceRoot":"","sources":["../../src/tools/run_hermes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,eAAO,MAAM,eAAe;;;;;;;;;;;;iBAqBZ,CAAC;AAIjB,wBAAsB,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC;;;;;;;;;;;;GAsHzE"}
|
package/dist/tools/run_hermes.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { HermesRunner } from '../services/HermesRunner.js';
|
|
3
|
+
import { HermesGatewayRunner } from '../services/HermesGatewayRunner.js';
|
|
3
4
|
import { storeRun } from '../memory/MemoryFactory.js';
|
|
4
5
|
import { getWorkspaceDir } from '../lib/config.js';
|
|
5
6
|
import { deleteSessionId } from '../lib/sessions.js';
|
|
@@ -35,32 +36,34 @@ export async function runHermesAgent(args) {
|
|
|
35
36
|
isError: true,
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
|
-
const runner = new HermesRunner();
|
|
39
39
|
const { prompt, agentName, autoResume, sessionId, path: argPath, config: argConfig, silent, model, provider, signal, overmindMode, } = args;
|
|
40
40
|
const finalPath = argPath || getWorkspaceDir();
|
|
41
41
|
const finalConfig = argConfig || getWorkspaceDir();
|
|
42
42
|
const start = Date.now();
|
|
43
|
-
|
|
43
|
+
// ─── Try Gateway HTTP first, fall back to subprocess spawn ────────────────
|
|
44
|
+
// The Hermes API Server (port 8642) provides HTTP+SSE chat without the
|
|
45
|
+
// ~5-10s Python startup overhead per call. If it's not running, we
|
|
46
|
+
// transparently fall back to the old HermesRunner (subprocess spawn).
|
|
47
|
+
const gatewayRunner = new HermesGatewayRunner();
|
|
48
|
+
const gwResult = await gatewayRunner.runAgent({
|
|
44
49
|
prompt,
|
|
45
50
|
agentName,
|
|
46
51
|
autoResume,
|
|
47
52
|
sessionId,
|
|
48
|
-
cwd: finalPath,
|
|
49
|
-
configPath: finalConfig,
|
|
50
|
-
silent,
|
|
51
53
|
model,
|
|
52
54
|
provider,
|
|
53
55
|
signal,
|
|
56
|
+
silent,
|
|
54
57
|
});
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
result = await
|
|
58
|
+
let result;
|
|
59
|
+
// If gateway returned GATEWAY_NOT_READY, fall back to subprocess spawn
|
|
60
|
+
if (gwResult.transport === 'fallback-spawn' || gwResult.error === 'GATEWAY_NOT_READY') {
|
|
61
|
+
const spawnRunner = new HermesRunner();
|
|
62
|
+
result = await spawnRunner.runAgent({
|
|
60
63
|
prompt,
|
|
61
64
|
agentName,
|
|
62
|
-
autoResume
|
|
63
|
-
sessionId
|
|
65
|
+
autoResume,
|
|
66
|
+
sessionId,
|
|
64
67
|
cwd: finalPath,
|
|
65
68
|
configPath: finalConfig,
|
|
66
69
|
silent,
|
|
@@ -68,6 +71,26 @@ export async function runHermesAgent(args) {
|
|
|
68
71
|
provider,
|
|
69
72
|
signal,
|
|
70
73
|
});
|
|
74
|
+
// Retry if session invalid (spawn mode only — gateway handles sessions natively)
|
|
75
|
+
if (result.error?.includes('session') || result.error?.includes('EXIT_CODE_1')) {
|
|
76
|
+
if (agentName)
|
|
77
|
+
await deleteSessionId(agentName, finalConfig, 'hermes');
|
|
78
|
+
result = await spawnRunner.runAgent({
|
|
79
|
+
prompt,
|
|
80
|
+
agentName,
|
|
81
|
+
autoResume: false,
|
|
82
|
+
sessionId: undefined,
|
|
83
|
+
cwd: finalPath,
|
|
84
|
+
configPath: finalConfig,
|
|
85
|
+
silent,
|
|
86
|
+
model,
|
|
87
|
+
provider,
|
|
88
|
+
signal,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
result = gwResult;
|
|
71
94
|
}
|
|
72
95
|
const durationMs = Date.now() - start;
|
|
73
96
|
// En mode Overmind (appel MCP), le run est déjà stocké par le MCP Server via memory_runs
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run_hermes.js","sourceRoot":"","sources":["../../src/tools/run_hermes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC;KAC7B,MAAM,CAAC;IACN,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;IACnE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACjD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAC7C,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,oEAAoE,CAAC;IACjF,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,uEAAuE,CAAC;IACpF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAe,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IACvF,oGAAoG;IACpG,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;CACpD,CAAC;KACD,WAAW,EAAE,CAAC;AAEjB,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAqC;IACxE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,iBAAiB;IACrE,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAClD,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QACd,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,IAAI,0BAA0B,EAAE,CAAC;YACvF,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,MAAM,
|
|
1
|
+
{"version":3,"file":"run_hermes.js","sourceRoot":"","sources":["../../src/tools/run_hermes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Kanban Roadmap — Overmind v4.0 (FUTURE)
|
|
2
|
+
|
|
3
|
+
> Statut: **DRAFT** — pas implémenté. Sauvegardé comme roadmap possible.
|
|
4
|
+
> Date: 2026-07-08
|
|
5
|
+
|
|
6
|
+
## Vision
|
|
7
|
+
|
|
8
|
+
Overmind devient l'orchestrateur. Hermes Gateway devient le backbone d'exécution.
|
|
9
|
+
Le Kanban Hermes est exposé via MCP comme **UN SEUL outil** `kanban_hub` (pas 15 outils séparés).
|
|
10
|
+
|
|
11
|
+
## Architecture cible
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
OVERMIND MCP (:3099) → Management + Orchestration
|
|
15
|
+
└─ kanban_hub (1 tool MCP) → Wrappe `hermes kanban` CLI
|
|
16
|
+
└─ a2a_hub (1 tool MCP) → Communication inter-workers
|
|
17
|
+
└─ run_agent, memory_*, etc → Multi-runner + PostgreSQL
|
|
18
|
+
|
|
19
|
+
HERMES GATEWAY (backbone) → Execution engine natif
|
|
20
|
+
└─ Dispatcher (tick 60s)
|
|
21
|
+
└─ Kanban board (kanban.db)
|
|
22
|
+
└─ 9 kanban_* tools (injectés aux workers)
|
|
23
|
+
└─ Dashboard + /kanban slash
|
|
24
|
+
└─ Remote gateway (OAuth)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Outil MCP unique: `kanban_hub`
|
|
28
|
+
|
|
29
|
+
UN SEUL outil MCP avec `action` enum (comme `a2a_hub` et `agent_control`):
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
kanban_hub({
|
|
33
|
+
action: "create", // create|list|show|complete|block|unblock|comment|link|dispatch|stats|archive|boards|watch|init
|
|
34
|
+
title: "...", // pour create
|
|
35
|
+
assignee: "sniperbot", // pour create
|
|
36
|
+
taskId: "t_abc123", // pour show/complete/block/unblock/comment/archive
|
|
37
|
+
body: "...", // pour create/comment
|
|
38
|
+
parents: ["t_001"], // pour create (dependencies)
|
|
39
|
+
reason: "...", // pour block
|
|
40
|
+
status: "running", // pour list (filter)
|
|
41
|
+
board: "my-project", // multi-board
|
|
42
|
+
// ... etc
|
|
43
|
+
})
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Avantages d'un seul outil:
|
|
47
|
+
- Schema compact (1 entrée dans tools/list au lieu de 15)
|
|
48
|
+
- L'agent découvre toutes les actions dans la description
|
|
49
|
+
- Pattern identique à a2a_hub et agent_control (cohérent)
|
|
50
|
+
- Moins de pollution du context window de l'agent
|
|
51
|
+
|
|
52
|
+
## Ce qui serait supprimé d'Overmind (redondant)
|
|
53
|
+
|
|
54
|
+
| Fichier | Raison |
|
|
55
|
+
|---------|--------|
|
|
56
|
+
| `src/services/KanbanAdapter.ts` (420 lignes) | Remplacé par `kanban_hub` MCP tool |
|
|
57
|
+
| `src/lib/orchestration/dispatcher.ts` | Gateway dispatcher natif |
|
|
58
|
+
| `src/bridge/ScenarioLoader.ts` (17KB) | Kanban pipeline + decompose natif |
|
|
59
|
+
| YOLO_CONFIG | Retry/circuit-breaker natifs du dispatcher |
|
|
60
|
+
|
|
61
|
+
## Ce qui reste dans Overmind (son vrai rôle wrapper)
|
|
62
|
+
|
|
63
|
+
- `run_agent` — Multi-runner spawn direct (Mode A)
|
|
64
|
+
- `create_agent` / `list_agents` / `delete_agent` / `update_agent_config`
|
|
65
|
+
- `memory_search` / `memory_store` / `memory_runs` — PostgreSQL vector
|
|
66
|
+
- `agent_control` — Process lifecycle
|
|
67
|
+
- `a2a_hub` — Communication inter-workers HTTP
|
|
68
|
+
- `kanban_hub` — Wrap Kanban Hermes (NOUVEAU, futur)
|
|
69
|
+
- `config_example` / `create_prompt` / `edit_prompt`
|
|
70
|
+
- `run_agents_parallel` — Pour runners non-Hermes
|
|
71
|
+
|
|
72
|
+
## Phases d'implémentation (futur)
|
|
73
|
+
|
|
74
|
+
### Phase 1 — Nettoyage
|
|
75
|
+
- Supprimer KanbanAdapter.ts, dispatcher.ts, ScenarioLoader.ts
|
|
76
|
+
- Nettoyer imports
|
|
77
|
+
- Build + test
|
|
78
|
+
|
|
79
|
+
### Phase 2 — Outil `kanban_hub` MCP unique
|
|
80
|
+
- Créer `src/tools/kanban_hub.ts`
|
|
81
|
+
- 1 schéma Zod avec `action` enum
|
|
82
|
+
- Chaque action appelle `hermes kanban <verb>` via CLI
|
|
83
|
+
- Enregistrer dans server.ts
|
|
84
|
+
- Build + lint + test
|
|
85
|
+
|
|
86
|
+
### Phase 3 — Gateway lifecycle
|
|
87
|
+
- `gateway_control` intégré à `agent_control` (action: "gateway_start/stop/status")
|
|
88
|
+
- Modifier install-overmind-native.sh pour démarrer gateway
|
|
89
|
+
- systemd service inclut `hermes gateway start`
|
|
90
|
+
|
|
91
|
+
### Phase 4 — Install scripts
|
|
92
|
+
- postinstall.mjs détecte Hermes, propose install
|
|
93
|
+
- verify-install.mjs vérifie gateway + kanban.db
|
|
94
|
+
|
|
95
|
+
### Phase 5 — Remote Gateway
|
|
96
|
+
- Documenter Desktop → Server Gateway (OAuth)
|
|
97
|
+
- `docs/REMOTE_GATEWAY.md`
|
|
98
|
+
|
|
99
|
+
### Phase 6 — A2A + Kanban fusion
|
|
100
|
+
- a2a_hub utilise kanban_create comme fallback durable
|
|
101
|
+
- Si worker HTTP injoignable → tâche kanban
|
|
102
|
+
|
|
103
|
+
## Prérequis
|
|
104
|
+
|
|
105
|
+
- Hermes Agent installé sur le serveur (`pip install hermes-agent` ou `hermes setup`)
|
|
106
|
+
- `hermes gateway start` fonctionnel
|
|
107
|
+
- `~/.hermes/kanban.db` accessible (symlink ~/.hermes → ~/.overmind/hermes)
|
|
108
|
+
- Hermes v0.18.1+ (Kanban v1 complet)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "overmind-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"description": "Orchestrateur universel agents IA multi-modeles via MCP. Inclut le protocole 'Custom-Nickname' pour identifier vos agents avec des surnoms originaux (The Chaos Prophet, Shadow Sniper, etc.), l'isolation mémoire (Private Memory Context) et le support pour QwenCli et Nous Hermes. Installation automatique des dépendances Docker (PostgreSQL, pgvector) inclus.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|