@wingman-ai/gateway 0.2.2 → 0.2.4
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/.wingman/agents/README.md +7 -1
- package/.wingman/agents/coding/agent.md +299 -201
- package/.wingman/agents/coding-v2/agent.md +127 -0
- package/.wingman/agents/coding-v2/implementor.md +89 -0
- package/.wingman/agents/main/agent.md +4 -0
- package/README.md +1 -0
- package/dist/agent/config/agentConfig.cjs +31 -17
- package/dist/agent/config/agentConfig.d.ts +23 -1
- package/dist/agent/config/agentConfig.js +30 -19
- package/dist/agent/config/agentLoader.cjs +26 -8
- package/dist/agent/config/agentLoader.d.ts +4 -2
- package/dist/agent/config/agentLoader.js +26 -8
- package/dist/agent/config/modelFactory.cjs +95 -25
- package/dist/agent/config/modelFactory.d.ts +13 -1
- package/dist/agent/config/modelFactory.js +95 -25
- package/dist/agent/config/toolRegistry.cjs +19 -6
- package/dist/agent/config/toolRegistry.d.ts +5 -2
- package/dist/agent/config/toolRegistry.js +19 -6
- package/dist/agent/middleware/hooks/types.cjs +13 -13
- package/dist/agent/middleware/hooks/types.d.ts +1 -1
- package/dist/agent/middleware/hooks/types.js +14 -14
- package/dist/agent/tests/agentConfig.test.cjs +22 -2
- package/dist/agent/tests/agentConfig.test.js +22 -2
- package/dist/agent/tests/agentLoader.test.cjs +38 -1
- package/dist/agent/tests/agentLoader.test.js +38 -1
- package/dist/agent/tests/backgroundTerminal.test.cjs +70 -0
- package/dist/agent/tests/backgroundTerminal.test.d.ts +1 -0
- package/dist/agent/tests/backgroundTerminal.test.js +64 -0
- package/dist/agent/tests/commandExecuteTool.test.cjs +29 -0
- package/dist/agent/tests/commandExecuteTool.test.d.ts +1 -0
- package/dist/agent/tests/commandExecuteTool.test.js +23 -0
- package/dist/agent/tests/modelFactory.test.cjs +47 -5
- package/dist/agent/tests/modelFactory.test.js +47 -5
- package/dist/agent/tests/terminalSessionManager.test.cjs +121 -0
- package/dist/agent/tests/terminalSessionManager.test.d.ts +1 -0
- package/dist/agent/tests/terminalSessionManager.test.js +115 -0
- package/dist/agent/tests/toolRegistry.test.cjs +14 -2
- package/dist/agent/tests/toolRegistry.test.js +14 -2
- package/dist/agent/tools/background_terminal.cjs +128 -0
- package/dist/agent/tools/background_terminal.d.ts +41 -0
- package/dist/agent/tools/background_terminal.js +94 -0
- package/dist/agent/tools/code_search.cjs +6 -6
- package/dist/agent/tools/code_search.d.ts +1 -1
- package/dist/agent/tools/code_search.js +7 -7
- package/dist/agent/tools/command_execute.cjs +22 -7
- package/dist/agent/tools/command_execute.d.ts +3 -2
- package/dist/agent/tools/command_execute.js +23 -8
- package/dist/agent/tools/git_status.cjs +3 -3
- package/dist/agent/tools/git_status.d.ts +1 -1
- package/dist/agent/tools/git_status.js +4 -4
- package/dist/agent/tools/internet_search.cjs +6 -6
- package/dist/agent/tools/internet_search.d.ts +1 -1
- package/dist/agent/tools/internet_search.js +7 -7
- package/dist/agent/tools/terminal_session_manager.cjs +321 -0
- package/dist/agent/tools/terminal_session_manager.d.ts +77 -0
- package/dist/agent/tools/terminal_session_manager.js +284 -0
- package/dist/agent/tools/think.cjs +4 -4
- package/dist/agent/tools/think.d.ts +1 -1
- package/dist/agent/tools/think.js +5 -5
- package/dist/agent/tools/ui_registry.cjs +13 -13
- package/dist/agent/tools/ui_registry.d.ts +4 -4
- package/dist/agent/tools/ui_registry.js +14 -14
- package/dist/agent/tools/web_crawler.cjs +4 -4
- package/dist/agent/tools/web_crawler.d.ts +1 -1
- package/dist/agent/tools/web_crawler.js +5 -5
- package/dist/agent/utils.cjs +2 -1
- package/dist/agent/utils.js +2 -1
- package/dist/cli/commands/init.cjs +7 -6
- package/dist/cli/commands/init.js +7 -6
- package/dist/cli/commands/provider.cjs +17 -3
- package/dist/cli/commands/provider.js +17 -3
- package/dist/cli/config/loader.cjs +27 -0
- package/dist/cli/config/loader.js +27 -0
- package/dist/cli/config/schema.cjs +146 -68
- package/dist/cli/config/schema.d.ts +89 -1
- package/dist/cli/config/schema.js +134 -68
- package/dist/cli/core/agentInvoker.cjs +344 -17
- package/dist/cli/core/agentInvoker.d.ts +63 -3
- package/dist/cli/core/agentInvoker.js +303 -12
- package/dist/cli/core/sessionManager.cjs +32 -5
- package/dist/cli/core/sessionManager.js +32 -5
- package/dist/cli/core/streamParser.cjs +15 -0
- package/dist/cli/core/streamParser.js +15 -0
- package/dist/cli/index.cjs +6 -5
- package/dist/cli/index.js +6 -5
- package/dist/cli/types.d.ts +32 -0
- package/dist/cli/ui/toolDisplayHelpers.cjs +2 -0
- package/dist/cli/ui/toolDisplayHelpers.js +2 -0
- package/dist/gateway/hooks/registry.cjs +2 -1
- package/dist/gateway/hooks/registry.d.ts +1 -1
- package/dist/gateway/hooks/registry.js +2 -1
- package/dist/gateway/hooks/types.cjs +11 -11
- package/dist/gateway/hooks/types.d.ts +1 -1
- package/dist/gateway/hooks/types.js +12 -12
- package/dist/gateway/http/agents.cjs +67 -4
- package/dist/gateway/http/agents.js +67 -4
- package/dist/gateway/http/sessions.cjs +7 -7
- package/dist/gateway/http/sessions.js +7 -7
- package/dist/gateway/http/types.d.ts +5 -3
- package/dist/gateway/http/webhooks.cjs +6 -5
- package/dist/gateway/http/webhooks.js +6 -5
- package/dist/gateway/server.cjs +198 -41
- package/dist/gateway/server.d.ts +9 -1
- package/dist/gateway/server.js +198 -41
- package/dist/gateway/types.d.ts +1 -0
- package/dist/gateway/validation.cjs +39 -39
- package/dist/gateway/validation.d.ts +1 -1
- package/dist/gateway/validation.js +40 -40
- package/dist/providers/codex.cjs +167 -0
- package/dist/providers/codex.d.ts +15 -0
- package/dist/providers/codex.js +127 -0
- package/dist/providers/credentials.cjs +8 -0
- package/dist/providers/credentials.js +8 -0
- package/dist/providers/registry.cjs +11 -0
- package/dist/providers/registry.d.ts +1 -1
- package/dist/providers/registry.js +11 -0
- package/dist/tests/additionalMessageMiddleware.test.cjs +3 -0
- package/dist/tests/additionalMessageMiddleware.test.js +3 -0
- package/dist/tests/agentInvokerSummarization.test.cjs +455 -0
- package/dist/tests/agentInvokerSummarization.test.d.ts +1 -0
- package/dist/tests/agentInvokerSummarization.test.js +449 -0
- package/dist/tests/agents-api.test.cjs +45 -5
- package/dist/tests/agents-api.test.js +45 -5
- package/dist/tests/cli-config-loader.test.cjs +88 -0
- package/dist/tests/cli-config-loader.test.js +88 -0
- package/dist/tests/cli-init.test.cjs +27 -3
- package/dist/tests/cli-init.test.js +27 -3
- package/dist/tests/codex-credentials-precedence.test.cjs +94 -0
- package/dist/tests/codex-credentials-precedence.test.d.ts +1 -0
- package/dist/tests/codex-credentials-precedence.test.js +88 -0
- package/dist/tests/codex-provider.test.cjs +210 -0
- package/dist/tests/codex-provider.test.d.ts +1 -0
- package/dist/tests/codex-provider.test.js +204 -0
- package/dist/tests/gateway.test.cjs +115 -8
- package/dist/tests/gateway.test.js +115 -8
- package/dist/tests/provider-command-codex.test.cjs +57 -0
- package/dist/tests/provider-command-codex.test.d.ts +1 -0
- package/dist/tests/provider-command-codex.test.js +51 -0
- package/dist/tests/sessionStateMessages.test.cjs +38 -0
- package/dist/tests/sessionStateMessages.test.js +38 -0
- package/dist/tests/toolDisplayHelpers.test.cjs +3 -0
- package/dist/tests/toolDisplayHelpers.test.js +3 -0
- package/dist/tools/mcp-finance.cjs +48 -48
- package/dist/tools/mcp-finance.js +48 -48
- package/dist/types/mcp.cjs +15 -15
- package/dist/types/mcp.d.ts +1 -1
- package/dist/types/mcp.js +16 -16
- package/dist/types/voice.cjs +21 -21
- package/dist/types/voice.d.ts +1 -1
- package/dist/types/voice.js +22 -22
- package/dist/webui/assets/index-DVWQluit.css +11 -0
- package/dist/webui/assets/index-Dlyzwalc.js +270 -0
- package/dist/webui/favicon-32x32.png +0 -0
- package/dist/webui/favicon-64x64.png +0 -0
- package/dist/webui/favicon.webp +0 -0
- package/dist/webui/index.html +4 -2
- package/package.json +13 -12
- package/.wingman/agents/coding/implementor.md +0 -79
- package/dist/webui/assets/index-CPhfGPHc.js +0 -182
- package/dist/webui/assets/index-DDsMIOTX.css +0 -11
package/dist/gateway/server.js
CHANGED
|
@@ -1,28 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { MDNSDiscoveryService, TailscaleDiscoveryService } from "./discovery/index.js";
|
|
7
|
-
import { createLogger } from "../logger.js";
|
|
1
|
+
import { existsSync, mkdirSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, isAbsolute, join, normalize, sep } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { TerminalSessionManager } from "../agent/tools/terminal_session_manager.js";
|
|
8
6
|
import { WingmanConfigLoader } from "../cli/config/loader.js";
|
|
9
|
-
import { GatewayRouter } from "./router.js";
|
|
10
|
-
import { OutputManager } from "../cli/core/outputManager.js";
|
|
11
7
|
import { AgentInvoker } from "../cli/core/agentInvoker.js";
|
|
8
|
+
import { OutputManager } from "../cli/core/outputManager.js";
|
|
12
9
|
import { SessionManager } from "../cli/core/sessionManager.js";
|
|
10
|
+
import { createLogger } from "../logger.js";
|
|
11
|
+
import { DiscordGatewayAdapter } from "./adapters/discord.js";
|
|
12
|
+
import { GatewayAuth } from "./auth.js";
|
|
13
|
+
import { BroadcastGroupManager } from "./broadcast.js";
|
|
14
|
+
import { MDNSDiscoveryService, TailscaleDiscoveryService } from "./discovery/index.js";
|
|
15
|
+
import { getGatewayTokenFromEnv } from "./env.js";
|
|
16
|
+
import { InternalHookRegistry } from "./hooks/registry.js";
|
|
13
17
|
import { handleAgentsApi } from "./http/agents.js";
|
|
14
18
|
import { handleFsApi } from "./http/fs.js";
|
|
15
19
|
import { handleProvidersApi } from "./http/providers.js";
|
|
16
|
-
import {
|
|
20
|
+
import { createRoutineStore, handleRoutinesApi } from "./http/routines.js";
|
|
17
21
|
import { handleSessionsApi } from "./http/sessions.js";
|
|
22
|
+
import { handleVoiceApi } from "./http/voice.js";
|
|
18
23
|
import { createWebhookStore, handleWebhookInvoke, handleWebhooksApi } from "./http/webhooks.js";
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import { homedir } from "node:os";
|
|
23
|
-
import { dirname, isAbsolute, join, normalize, sep } from "node:path";
|
|
24
|
-
import { existsSync, mkdirSync, statSync, writeFileSync } from "node:fs";
|
|
25
|
-
import { fileURLToPath } from "node:url";
|
|
24
|
+
import { NodeManager } from "./node.js";
|
|
25
|
+
import { GatewayRouter } from "./router.js";
|
|
26
|
+
import { validateGatewayMessage } from "./validation.js";
|
|
26
27
|
function _define_property(obj, key, value) {
|
|
27
28
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
28
29
|
value: value,
|
|
@@ -76,6 +77,7 @@ class GatewayServer {
|
|
|
76
77
|
});
|
|
77
78
|
return;
|
|
78
79
|
}
|
|
80
|
+
if (url.pathname.startsWith("/api/")) return this.handleUiRequest(req);
|
|
79
81
|
const webhookResponse = await handleWebhookInvoke(this.getHttpContext(), this.webhookStore, req, url);
|
|
80
82
|
if (webhookResponse) return webhookResponse;
|
|
81
83
|
if (this.controlUiSamePort) return this.handleUiRequest(req);
|
|
@@ -132,6 +134,7 @@ class GatewayServer {
|
|
|
132
134
|
this.uiServer.stop();
|
|
133
135
|
this.uiServer = null;
|
|
134
136
|
}
|
|
137
|
+
this.terminalSessionManager.dispose();
|
|
135
138
|
this.log("info", "Gateway stopped");
|
|
136
139
|
}
|
|
137
140
|
getPort() {
|
|
@@ -319,6 +322,7 @@ class GatewayServer {
|
|
|
319
322
|
existing?.abortController.abort();
|
|
320
323
|
this.activeAgentRequests.delete(msg.id);
|
|
321
324
|
}
|
|
325
|
+
this.removeQueuedRequestById(msg.id);
|
|
322
326
|
const payload = msg.payload;
|
|
323
327
|
const content = "string" == typeof payload?.content ? payload.content : "";
|
|
324
328
|
const attachments = Array.isArray(payload?.attachments) ? payload.attachments : [];
|
|
@@ -328,6 +332,7 @@ class GatewayServer {
|
|
|
328
332
|
const agentId = this.router.selectAgent(payload.agentId, payload.routing);
|
|
329
333
|
if (!agentId) return void this.sendAgentError(ws, msg.id, "No agent matched the request");
|
|
330
334
|
const sessionKey = payload.sessionKey || this.router.buildSessionKey(agentId, payload.routing);
|
|
335
|
+
const sessionQueueKey = this.buildSessionQueueKey(agentId, sessionKey);
|
|
331
336
|
const sessionManager = await this.getSessionManager(agentId);
|
|
332
337
|
const existingSession = sessionManager.getSession(sessionKey);
|
|
333
338
|
const session = existingSession || sessionManager.getOrCreateSession(sessionKey, agentId);
|
|
@@ -378,9 +383,70 @@ class GatewayServer {
|
|
|
378
383
|
],
|
|
379
384
|
skipSessionId: sessionKey
|
|
380
385
|
});
|
|
386
|
+
const request = {
|
|
387
|
+
ws,
|
|
388
|
+
msg,
|
|
389
|
+
payload,
|
|
390
|
+
agentId,
|
|
391
|
+
sessionKey,
|
|
392
|
+
sessionQueueKey,
|
|
393
|
+
content,
|
|
394
|
+
attachments,
|
|
395
|
+
sessionManager,
|
|
396
|
+
workdir,
|
|
397
|
+
defaultOutputDir
|
|
398
|
+
};
|
|
399
|
+
this.requestSessionKeys.set(msg.id, sessionQueueKey);
|
|
400
|
+
const queueIfBusy = false !== payload.queueIfBusy;
|
|
401
|
+
const activeRequestId = this.activeSessionRequests.get(sessionQueueKey);
|
|
402
|
+
if (activeRequestId && queueIfBusy) {
|
|
403
|
+
const queued = this.queuedSessionRequests.get(sessionQueueKey) || [];
|
|
404
|
+
queued.push(request);
|
|
405
|
+
this.queuedSessionRequests.set(sessionQueueKey, queued);
|
|
406
|
+
const position = queued.length;
|
|
407
|
+
this.sendMessage(ws, {
|
|
408
|
+
type: "ack",
|
|
409
|
+
id: msg.id,
|
|
410
|
+
payload: {
|
|
411
|
+
action: "req:agent",
|
|
412
|
+
status: "queued",
|
|
413
|
+
requestId: msg.id,
|
|
414
|
+
sessionId: sessionKey,
|
|
415
|
+
agentId,
|
|
416
|
+
position
|
|
417
|
+
},
|
|
418
|
+
timestamp: Date.now()
|
|
419
|
+
});
|
|
420
|
+
this.sendMessage(ws, {
|
|
421
|
+
type: "event:agent",
|
|
422
|
+
id: msg.id,
|
|
423
|
+
clientId: ws.data.clientId,
|
|
424
|
+
payload: this.attachSessionContext({
|
|
425
|
+
type: "request-queued",
|
|
426
|
+
position
|
|
427
|
+
}, sessionKey, agentId),
|
|
428
|
+
timestamp: Date.now()
|
|
429
|
+
});
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
if (activeRequestId && !queueIfBusy) {
|
|
433
|
+
this.requestSessionKeys.delete(msg.id);
|
|
434
|
+
this.sendAgentError(ws, msg.id, "Session already has an in-flight request. Set queueIfBusy=true to enqueue.", {
|
|
435
|
+
sessionId: sessionKey,
|
|
436
|
+
agentId
|
|
437
|
+
});
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
this.executeAgentRequest(request);
|
|
441
|
+
}
|
|
442
|
+
async executeAgentRequest(request) {
|
|
443
|
+
const { ws, msg, agentId, sessionKey, sessionQueueKey, content, attachments, sessionManager, workdir, defaultOutputDir } = request;
|
|
444
|
+
this.activeSessionRequests.set(sessionQueueKey, msg.id);
|
|
381
445
|
const outputManager = new OutputManager("interactive");
|
|
446
|
+
let emittedAgentError = false;
|
|
382
447
|
const outputHandler = (event)=>{
|
|
383
448
|
const payloadWithSession = this.attachSessionContext(event, sessionKey, agentId);
|
|
449
|
+
if (payloadWithSession && "object" == typeof payloadWithSession && !Array.isArray(payloadWithSession) && "agent-error" === payloadWithSession.type) emittedAgentError = true;
|
|
384
450
|
const baseMessage = {
|
|
385
451
|
type: "event:agent",
|
|
386
452
|
id: msg.id,
|
|
@@ -401,6 +467,7 @@ class GatewayServer {
|
|
|
401
467
|
outputManager,
|
|
402
468
|
logger: this.logger,
|
|
403
469
|
sessionManager,
|
|
470
|
+
terminalSessionManager: this.terminalSessionManager,
|
|
404
471
|
workdir,
|
|
405
472
|
defaultOutputDir
|
|
406
473
|
});
|
|
@@ -419,41 +486,111 @@ class GatewayServer {
|
|
|
419
486
|
});
|
|
420
487
|
} catch (error) {
|
|
421
488
|
this.logger.error("Agent invocation failed", error);
|
|
489
|
+
if (!emittedAgentError) {
|
|
490
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
491
|
+
const stack = error instanceof Error ? error.stack : void 0;
|
|
492
|
+
this.sendAgentError(ws, msg.id, message, {
|
|
493
|
+
sessionId: sessionKey,
|
|
494
|
+
agentId,
|
|
495
|
+
stack,
|
|
496
|
+
broadcastToSession: true,
|
|
497
|
+
exclude: ws
|
|
498
|
+
});
|
|
499
|
+
}
|
|
422
500
|
} finally{
|
|
423
501
|
this.activeAgentRequests.delete(msg.id);
|
|
502
|
+
this.activeSessionRequests.delete(sessionQueueKey);
|
|
503
|
+
this.requestSessionKeys.delete(msg.id);
|
|
424
504
|
outputManager.off("output-event", outputHandler);
|
|
505
|
+
this.processNextQueuedAgentRequest(sessionQueueKey);
|
|
425
506
|
}
|
|
426
507
|
}
|
|
508
|
+
processNextQueuedAgentRequest(sessionQueueKey) {
|
|
509
|
+
if (this.activeSessionRequests.has(sessionQueueKey)) return;
|
|
510
|
+
const queue = this.queuedSessionRequests.get(sessionQueueKey);
|
|
511
|
+
if (!queue || 0 === queue.length) return void this.queuedSessionRequests.delete(sessionQueueKey);
|
|
512
|
+
const next = queue.shift();
|
|
513
|
+
if (!next) return;
|
|
514
|
+
if (0 === queue.length) this.queuedSessionRequests.delete(sessionQueueKey);
|
|
515
|
+
else this.queuedSessionRequests.set(sessionQueueKey, queue);
|
|
516
|
+
this.sendMessage(next.ws, {
|
|
517
|
+
type: "ack",
|
|
518
|
+
id: next.msg.id,
|
|
519
|
+
payload: {
|
|
520
|
+
action: "req:agent",
|
|
521
|
+
status: "dequeued",
|
|
522
|
+
requestId: next.msg.id,
|
|
523
|
+
sessionId: next.sessionKey,
|
|
524
|
+
agentId: next.agentId,
|
|
525
|
+
remaining: queue.length
|
|
526
|
+
},
|
|
527
|
+
timestamp: Date.now()
|
|
528
|
+
});
|
|
529
|
+
this.executeAgentRequest(next);
|
|
530
|
+
}
|
|
427
531
|
handleAgentCancel(ws, msg) {
|
|
428
532
|
if (!ws.data.authenticated) return void this.sendError(ws, "AUTH_FAILED", "Client is not authenticated");
|
|
429
533
|
const payload = msg.payload;
|
|
430
534
|
const requestId = "string" == typeof payload?.requestId && payload.requestId || void 0;
|
|
431
535
|
if (!requestId) return void this.sendError(ws, "INVALID_REQUEST", "Missing requestId for cancellation");
|
|
432
536
|
const active = this.activeAgentRequests.get(requestId);
|
|
433
|
-
if (
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
537
|
+
if (active) {
|
|
538
|
+
if (active.socket !== ws) return void this.sendError(ws, "FORBIDDEN", "Cannot cancel a request started by another client");
|
|
539
|
+
active.abortController.abort();
|
|
540
|
+
this.activeAgentRequests.delete(requestId);
|
|
541
|
+
this.sendMessage(ws, {
|
|
542
|
+
type: "ack",
|
|
543
|
+
id: msg.id,
|
|
544
|
+
payload: {
|
|
545
|
+
action: "req:agent:cancel",
|
|
546
|
+
requestId,
|
|
547
|
+
status: "cancelled"
|
|
548
|
+
},
|
|
549
|
+
timestamp: Date.now()
|
|
550
|
+
});
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
const queued = this.removeQueuedRequestById(requestId);
|
|
554
|
+
if (queued) {
|
|
555
|
+
if (queued.ws !== ws) return void this.sendError(ws, "FORBIDDEN", "Cannot cancel a request started by another client");
|
|
556
|
+
this.sendMessage(ws, {
|
|
557
|
+
type: "ack",
|
|
558
|
+
id: msg.id,
|
|
559
|
+
payload: {
|
|
560
|
+
action: "req:agent:cancel",
|
|
561
|
+
requestId,
|
|
562
|
+
status: "cancelled_queued"
|
|
563
|
+
},
|
|
564
|
+
timestamp: Date.now()
|
|
565
|
+
});
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
446
568
|
this.sendMessage(ws, {
|
|
447
569
|
type: "ack",
|
|
448
570
|
id: msg.id,
|
|
449
571
|
payload: {
|
|
450
572
|
action: "req:agent:cancel",
|
|
451
573
|
requestId,
|
|
452
|
-
status: "
|
|
574
|
+
status: "not_found"
|
|
453
575
|
},
|
|
454
576
|
timestamp: Date.now()
|
|
455
577
|
});
|
|
456
578
|
}
|
|
579
|
+
buildSessionQueueKey(agentId, sessionKey) {
|
|
580
|
+
return `${agentId}:${sessionKey}`;
|
|
581
|
+
}
|
|
582
|
+
removeQueuedRequestById(requestId) {
|
|
583
|
+
for (const [queueKey, queue] of this.queuedSessionRequests){
|
|
584
|
+
const index = queue.findIndex((item)=>item.msg.id === requestId);
|
|
585
|
+
if (-1 === index) continue;
|
|
586
|
+
const [removed] = queue.splice(index, 1);
|
|
587
|
+
if (0 === queue.length) this.queuedSessionRequests.delete(queueKey);
|
|
588
|
+
else this.queuedSessionRequests.set(queueKey, queue);
|
|
589
|
+
this.requestSessionKeys.delete(requestId);
|
|
590
|
+
return removed || null;
|
|
591
|
+
}
|
|
592
|
+
return null;
|
|
593
|
+
}
|
|
457
594
|
handleRegister(ws, msg) {
|
|
458
595
|
const payload = msg.payload;
|
|
459
596
|
if (!this.auth.validate({
|
|
@@ -616,23 +753,39 @@ class GatewayServer {
|
|
|
616
753
|
timestamp: Date.now()
|
|
617
754
|
});
|
|
618
755
|
}
|
|
619
|
-
sendAgentError(ws, requestId, message) {
|
|
620
|
-
|
|
756
|
+
sendAgentError(ws, requestId, message, options) {
|
|
757
|
+
let payload = {
|
|
758
|
+
type: "agent-error",
|
|
759
|
+
error: message,
|
|
760
|
+
timestamp: new Date().toISOString()
|
|
761
|
+
};
|
|
762
|
+
if (options?.stack) payload.stack = options.stack;
|
|
763
|
+
if (options?.sessionId && options?.agentId) payload = this.attachSessionContext(payload, options.sessionId, options.agentId);
|
|
764
|
+
const baseMessage = {
|
|
621
765
|
type: "event:agent",
|
|
622
766
|
id: requestId,
|
|
623
|
-
payload
|
|
624
|
-
type: "agent-error",
|
|
625
|
-
error: message,
|
|
626
|
-
timestamp: new Date().toISOString()
|
|
627
|
-
},
|
|
767
|
+
payload,
|
|
628
768
|
timestamp: Date.now()
|
|
769
|
+
};
|
|
770
|
+
this.sendMessage(ws, {
|
|
771
|
+
...baseMessage,
|
|
772
|
+
clientId: ws.data.clientId
|
|
629
773
|
});
|
|
774
|
+
if (options?.broadcastToSession && options.sessionId) this.broadcastSessionEvent(options.sessionId, baseMessage, options.exclude);
|
|
630
775
|
}
|
|
631
776
|
cancelSocketAgentRequests(ws) {
|
|
632
777
|
for (const [requestId, active] of this.activeAgentRequests)if (active.socket === ws) {
|
|
633
778
|
active.abortController.abort();
|
|
634
779
|
this.activeAgentRequests.delete(requestId);
|
|
635
780
|
}
|
|
781
|
+
for (const [queueKey, queue] of this.queuedSessionRequests){
|
|
782
|
+
const nextQueue = queue.filter((request)=>request.ws !== ws);
|
|
783
|
+
if (nextQueue.length !== queue.length) {
|
|
784
|
+
for (const request of queue)if (request.ws === ws && request.msg.id) this.requestSessionKeys.delete(request.msg.id);
|
|
785
|
+
if (0 === nextQueue.length) this.queuedSessionRequests.delete(queueKey);
|
|
786
|
+
else this.queuedSessionRequests.set(queueKey, nextQueue);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
636
789
|
}
|
|
637
790
|
attachSessionContext(event, sessionId, agentId) {
|
|
638
791
|
if (event && "object" == typeof event && !Array.isArray(event)) return {
|
|
@@ -752,6 +905,7 @@ class GatewayServer {
|
|
|
752
905
|
resolveFsRoots: ()=>this.resolveFsRoots(),
|
|
753
906
|
resolveFsPath: (path)=>this.resolveFsPath(path),
|
|
754
907
|
isPathWithinRoots: (path, roots)=>this.isPathWithinRoots(path, roots),
|
|
908
|
+
getTerminalSessionManager: ()=>this.terminalSessionManager,
|
|
755
909
|
getBuiltInTools: ()=>this.getBuiltInTools()
|
|
756
910
|
};
|
|
757
911
|
}
|
|
@@ -824,9 +978,7 @@ class GatewayServer {
|
|
|
824
978
|
];
|
|
825
979
|
for (const candidate of candidates)try {
|
|
826
980
|
if (existsSync(candidate) && statSync(candidate).isDirectory() && existsSync(join(candidate, "index.html"))) return candidate;
|
|
827
|
-
} catch {
|
|
828
|
-
continue;
|
|
829
|
-
}
|
|
981
|
+
} catch {}
|
|
830
982
|
return null;
|
|
831
983
|
}
|
|
832
984
|
async getSessionManager(agentId) {
|
|
@@ -1150,6 +1302,10 @@ class GatewayServer {
|
|
|
1150
1302
|
_define_property(this, "socketSubscriptions", new Map());
|
|
1151
1303
|
_define_property(this, "connectedClients", new Set());
|
|
1152
1304
|
_define_property(this, "activeAgentRequests", new Map());
|
|
1305
|
+
_define_property(this, "activeSessionRequests", new Map());
|
|
1306
|
+
_define_property(this, "queuedSessionRequests", new Map());
|
|
1307
|
+
_define_property(this, "requestSessionKeys", new Map());
|
|
1308
|
+
_define_property(this, "terminalSessionManager", void 0);
|
|
1153
1309
|
_define_property(this, "bridgeQueues", new Map());
|
|
1154
1310
|
_define_property(this, "bridgePollWaiters", new Map());
|
|
1155
1311
|
this.workspace = config.workspace || process.cwd();
|
|
@@ -1200,6 +1356,7 @@ class GatewayServer {
|
|
|
1200
1356
|
this.controlUiPort = controlUi?.port || 18790;
|
|
1201
1357
|
this.controlUiSamePort = this.controlUiEnabled && this.controlUiPort === this.config.port;
|
|
1202
1358
|
this.uiDistDir = this.controlUiEnabled ? this.resolveControlUiDir() : null;
|
|
1359
|
+
this.terminalSessionManager = new TerminalSessionManager();
|
|
1203
1360
|
}
|
|
1204
1361
|
}
|
|
1205
1362
|
function buildAttachmentPreview(attachments) {
|
package/dist/gateway/types.d.ts
CHANGED
|
@@ -38,7 +38,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
38
38
|
BroadcastPayloadSchema: ()=>BroadcastPayloadSchema
|
|
39
39
|
});
|
|
40
40
|
const external_zod_namespaceObject = require("zod");
|
|
41
|
-
const MessageTypeSchema = external_zod_namespaceObject
|
|
41
|
+
const MessageTypeSchema = external_zod_namespaceObject["enum"]([
|
|
42
42
|
"connect",
|
|
43
43
|
"res",
|
|
44
44
|
"req:agent",
|
|
@@ -58,52 +58,52 @@ const MessageTypeSchema = external_zod_namespaceObject.z["enum"]([
|
|
|
58
58
|
"error",
|
|
59
59
|
"ack"
|
|
60
60
|
]);
|
|
61
|
-
const GatewayMessageSchema = external_zod_namespaceObject.
|
|
61
|
+
const GatewayMessageSchema = external_zod_namespaceObject.object({
|
|
62
62
|
type: MessageTypeSchema,
|
|
63
|
-
id: external_zod_namespaceObject.
|
|
64
|
-
client: external_zod_namespaceObject.
|
|
65
|
-
instanceId: external_zod_namespaceObject.
|
|
66
|
-
clientType: external_zod_namespaceObject.
|
|
67
|
-
version: external_zod_namespaceObject.
|
|
63
|
+
id: external_zod_namespaceObject.string().optional(),
|
|
64
|
+
client: external_zod_namespaceObject.object({
|
|
65
|
+
instanceId: external_zod_namespaceObject.string().min(1),
|
|
66
|
+
clientType: external_zod_namespaceObject.string().min(1),
|
|
67
|
+
version: external_zod_namespaceObject.string().optional()
|
|
68
68
|
}).optional(),
|
|
69
|
-
auth: external_zod_namespaceObject.
|
|
70
|
-
token: external_zod_namespaceObject.
|
|
71
|
-
password: external_zod_namespaceObject.
|
|
72
|
-
deviceId: external_zod_namespaceObject.
|
|
69
|
+
auth: external_zod_namespaceObject.object({
|
|
70
|
+
token: external_zod_namespaceObject.string().optional(),
|
|
71
|
+
password: external_zod_namespaceObject.string().optional(),
|
|
72
|
+
deviceId: external_zod_namespaceObject.string().optional()
|
|
73
73
|
}).optional(),
|
|
74
|
-
ok: external_zod_namespaceObject.
|
|
75
|
-
clientId: external_zod_namespaceObject.
|
|
76
|
-
nodeId: external_zod_namespaceObject.
|
|
77
|
-
groupId: external_zod_namespaceObject.
|
|
78
|
-
roomId: external_zod_namespaceObject.
|
|
79
|
-
targetNodeId: external_zod_namespaceObject.
|
|
80
|
-
payload: external_zod_namespaceObject.
|
|
81
|
-
timestamp: external_zod_namespaceObject.
|
|
82
|
-
messageId: external_zod_namespaceObject.
|
|
74
|
+
ok: external_zod_namespaceObject.boolean().optional(),
|
|
75
|
+
clientId: external_zod_namespaceObject.string().optional(),
|
|
76
|
+
nodeId: external_zod_namespaceObject.string().optional(),
|
|
77
|
+
groupId: external_zod_namespaceObject.string().optional(),
|
|
78
|
+
roomId: external_zod_namespaceObject.string().optional(),
|
|
79
|
+
targetNodeId: external_zod_namespaceObject.string().optional(),
|
|
80
|
+
payload: external_zod_namespaceObject.unknown().optional(),
|
|
81
|
+
timestamp: external_zod_namespaceObject.number(),
|
|
82
|
+
messageId: external_zod_namespaceObject.string().optional()
|
|
83
83
|
});
|
|
84
|
-
const RegisterPayloadSchema = external_zod_namespaceObject.
|
|
85
|
-
name: external_zod_namespaceObject.
|
|
86
|
-
capabilities: external_zod_namespaceObject.
|
|
87
|
-
token: external_zod_namespaceObject.
|
|
84
|
+
const RegisterPayloadSchema = external_zod_namespaceObject.object({
|
|
85
|
+
name: external_zod_namespaceObject.string().min(1).max(100),
|
|
86
|
+
capabilities: external_zod_namespaceObject.array(external_zod_namespaceObject.string()).optional(),
|
|
87
|
+
token: external_zod_namespaceObject.string().optional()
|
|
88
88
|
});
|
|
89
|
-
const JoinGroupPayloadSchema = external_zod_namespaceObject.
|
|
90
|
-
groupId: external_zod_namespaceObject.
|
|
91
|
-
groupName: external_zod_namespaceObject.
|
|
92
|
-
createIfNotExists: external_zod_namespaceObject.
|
|
93
|
-
description: external_zod_namespaceObject.
|
|
89
|
+
const JoinGroupPayloadSchema = external_zod_namespaceObject.object({
|
|
90
|
+
groupId: external_zod_namespaceObject.string().optional(),
|
|
91
|
+
groupName: external_zod_namespaceObject.string().min(1).max(100).optional(),
|
|
92
|
+
createIfNotExists: external_zod_namespaceObject.boolean().optional(),
|
|
93
|
+
description: external_zod_namespaceObject.string().max(500).optional()
|
|
94
94
|
});
|
|
95
|
-
const BroadcastPayloadSchema = external_zod_namespaceObject.
|
|
96
|
-
groupId: external_zod_namespaceObject.
|
|
97
|
-
message: external_zod_namespaceObject.
|
|
95
|
+
const BroadcastPayloadSchema = external_zod_namespaceObject.object({
|
|
96
|
+
groupId: external_zod_namespaceObject.string().min(1),
|
|
97
|
+
message: external_zod_namespaceObject.unknown()
|
|
98
98
|
});
|
|
99
|
-
const DirectPayloadSchema = external_zod_namespaceObject.
|
|
100
|
-
targetNodeId: external_zod_namespaceObject.
|
|
101
|
-
message: external_zod_namespaceObject.
|
|
99
|
+
const DirectPayloadSchema = external_zod_namespaceObject.object({
|
|
100
|
+
targetNodeId: external_zod_namespaceObject.string().min(1),
|
|
101
|
+
message: external_zod_namespaceObject.unknown()
|
|
102
102
|
});
|
|
103
|
-
const ErrorPayloadSchema = external_zod_namespaceObject.
|
|
104
|
-
code: external_zod_namespaceObject.
|
|
105
|
-
message: external_zod_namespaceObject.
|
|
106
|
-
details: external_zod_namespaceObject.
|
|
103
|
+
const ErrorPayloadSchema = external_zod_namespaceObject.object({
|
|
104
|
+
code: external_zod_namespaceObject.string().min(1),
|
|
105
|
+
message: external_zod_namespaceObject.string().min(1),
|
|
106
|
+
details: external_zod_namespaceObject.unknown().optional()
|
|
107
107
|
});
|
|
108
108
|
function validateGatewayMessage(data) {
|
|
109
109
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const MessageTypeSchema =
|
|
1
|
+
import { array, boolean as external_zod_boolean, enum as external_zod_enum, number, object, string, unknown } from "zod";
|
|
2
|
+
const MessageTypeSchema = external_zod_enum([
|
|
3
3
|
"connect",
|
|
4
4
|
"res",
|
|
5
5
|
"req:agent",
|
|
@@ -19,52 +19,52 @@ const MessageTypeSchema = z["enum"]([
|
|
|
19
19
|
"error",
|
|
20
20
|
"ack"
|
|
21
21
|
]);
|
|
22
|
-
const GatewayMessageSchema =
|
|
22
|
+
const GatewayMessageSchema = object({
|
|
23
23
|
type: MessageTypeSchema,
|
|
24
|
-
id:
|
|
25
|
-
client:
|
|
26
|
-
instanceId:
|
|
27
|
-
clientType:
|
|
28
|
-
version:
|
|
24
|
+
id: string().optional(),
|
|
25
|
+
client: object({
|
|
26
|
+
instanceId: string().min(1),
|
|
27
|
+
clientType: string().min(1),
|
|
28
|
+
version: string().optional()
|
|
29
29
|
}).optional(),
|
|
30
|
-
auth:
|
|
31
|
-
token:
|
|
32
|
-
password:
|
|
33
|
-
deviceId:
|
|
30
|
+
auth: object({
|
|
31
|
+
token: string().optional(),
|
|
32
|
+
password: string().optional(),
|
|
33
|
+
deviceId: string().optional()
|
|
34
34
|
}).optional(),
|
|
35
|
-
ok:
|
|
36
|
-
clientId:
|
|
37
|
-
nodeId:
|
|
38
|
-
groupId:
|
|
39
|
-
roomId:
|
|
40
|
-
targetNodeId:
|
|
41
|
-
payload:
|
|
42
|
-
timestamp:
|
|
43
|
-
messageId:
|
|
35
|
+
ok: external_zod_boolean().optional(),
|
|
36
|
+
clientId: string().optional(),
|
|
37
|
+
nodeId: string().optional(),
|
|
38
|
+
groupId: string().optional(),
|
|
39
|
+
roomId: string().optional(),
|
|
40
|
+
targetNodeId: string().optional(),
|
|
41
|
+
payload: unknown().optional(),
|
|
42
|
+
timestamp: number(),
|
|
43
|
+
messageId: string().optional()
|
|
44
44
|
});
|
|
45
|
-
const RegisterPayloadSchema =
|
|
46
|
-
name:
|
|
47
|
-
capabilities:
|
|
48
|
-
token:
|
|
45
|
+
const RegisterPayloadSchema = object({
|
|
46
|
+
name: string().min(1).max(100),
|
|
47
|
+
capabilities: array(string()).optional(),
|
|
48
|
+
token: string().optional()
|
|
49
49
|
});
|
|
50
|
-
const JoinGroupPayloadSchema =
|
|
51
|
-
groupId:
|
|
52
|
-
groupName:
|
|
53
|
-
createIfNotExists:
|
|
54
|
-
description:
|
|
50
|
+
const JoinGroupPayloadSchema = object({
|
|
51
|
+
groupId: string().optional(),
|
|
52
|
+
groupName: string().min(1).max(100).optional(),
|
|
53
|
+
createIfNotExists: external_zod_boolean().optional(),
|
|
54
|
+
description: string().max(500).optional()
|
|
55
55
|
});
|
|
56
|
-
const BroadcastPayloadSchema =
|
|
57
|
-
groupId:
|
|
58
|
-
message:
|
|
56
|
+
const BroadcastPayloadSchema = object({
|
|
57
|
+
groupId: string().min(1),
|
|
58
|
+
message: unknown()
|
|
59
59
|
});
|
|
60
|
-
const DirectPayloadSchema =
|
|
61
|
-
targetNodeId:
|
|
62
|
-
message:
|
|
60
|
+
const DirectPayloadSchema = object({
|
|
61
|
+
targetNodeId: string().min(1),
|
|
62
|
+
message: unknown()
|
|
63
63
|
});
|
|
64
|
-
const ErrorPayloadSchema =
|
|
65
|
-
code:
|
|
66
|
-
message:
|
|
67
|
-
details:
|
|
64
|
+
const ErrorPayloadSchema = object({
|
|
65
|
+
code: string().min(1),
|
|
66
|
+
message: string().min(1),
|
|
67
|
+
details: unknown().optional()
|
|
68
68
|
});
|
|
69
69
|
function validateGatewayMessage(data) {
|
|
70
70
|
try {
|