@amodalai/runtime 0.1.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/LICENSE +21 -0
- package/dist/.last_build +0 -0
- package/dist/src/agent/agent-runner.d.ts +13 -0
- package/dist/src/agent/agent-runner.js +827 -0
- package/dist/src/agent/agent-runner.js.map +1 -0
- package/dist/src/agent/agent-runner.test.d.ts +6 -0
- package/dist/src/agent/agent-runner.test.js +552 -0
- package/dist/src/agent/agent-runner.test.js.map +1 -0
- package/dist/src/agent/agent-types.d.ts +57 -0
- package/dist/src/agent/agent-types.js +17 -0
- package/dist/src/agent/agent-types.js.map +1 -0
- package/dist/src/agent/agent-types.test.d.ts +6 -0
- package/dist/src/agent/agent-types.test.js +44 -0
- package/dist/src/agent/agent-types.test.js.map +1 -0
- package/dist/src/agent/automation-bridge.d.ts +24 -0
- package/dist/src/agent/automation-bridge.js +24 -0
- package/dist/src/agent/automation-bridge.js.map +1 -0
- package/dist/src/agent/automation-bridge.test.d.ts +6 -0
- package/dist/src/agent/automation-bridge.test.js +67 -0
- package/dist/src/agent/automation-bridge.test.js.map +1 -0
- package/dist/src/agent/config-watcher.d.ts +20 -0
- package/dist/src/agent/config-watcher.js +68 -0
- package/dist/src/agent/config-watcher.js.map +1 -0
- package/dist/src/agent/config-watcher.test.d.ts +6 -0
- package/dist/src/agent/config-watcher.test.js +83 -0
- package/dist/src/agent/config-watcher.test.js.map +1 -0
- package/dist/src/agent/custom-tools-e2e.test.d.ts +6 -0
- package/dist/src/agent/custom-tools-e2e.test.js +566 -0
- package/dist/src/agent/custom-tools-e2e.test.js.map +1 -0
- package/dist/src/agent/local-server.d.ts +15 -0
- package/dist/src/agent/local-server.js +158 -0
- package/dist/src/agent/local-server.js.map +1 -0
- package/dist/src/agent/local-server.test.d.ts +6 -0
- package/dist/src/agent/local-server.test.js +126 -0
- package/dist/src/agent/local-server.test.js.map +1 -0
- package/dist/src/agent/proactive/delivery.d.ts +21 -0
- package/dist/src/agent/proactive/delivery.js +68 -0
- package/dist/src/agent/proactive/delivery.js.map +1 -0
- package/dist/src/agent/proactive/delivery.test.d.ts +6 -0
- package/dist/src/agent/proactive/delivery.test.js +65 -0
- package/dist/src/agent/proactive/delivery.test.js.map +1 -0
- package/dist/src/agent/proactive/proactive-runner.d.ts +76 -0
- package/dist/src/agent/proactive/proactive-runner.js +201 -0
- package/dist/src/agent/proactive/proactive-runner.js.map +1 -0
- package/dist/src/agent/proactive/proactive-runner.test.d.ts +6 -0
- package/dist/src/agent/proactive/proactive-runner.test.js +265 -0
- package/dist/src/agent/proactive/proactive-runner.test.js.map +1 -0
- package/dist/src/agent/request-helper.d.ts +16 -0
- package/dist/src/agent/request-helper.js +87 -0
- package/dist/src/agent/request-helper.js.map +1 -0
- package/dist/src/agent/routes/automations.d.ts +19 -0
- package/dist/src/agent/routes/automations.js +58 -0
- package/dist/src/agent/routes/automations.js.map +1 -0
- package/dist/src/agent/routes/automations.test.d.ts +6 -0
- package/dist/src/agent/routes/automations.test.js +117 -0
- package/dist/src/agent/routes/automations.test.js.map +1 -0
- package/dist/src/agent/routes/chat.d.ts +35 -0
- package/dist/src/agent/routes/chat.js +88 -0
- package/dist/src/agent/routes/chat.js.map +1 -0
- package/dist/src/agent/routes/chat.test.d.ts +6 -0
- package/dist/src/agent/routes/chat.test.js +115 -0
- package/dist/src/agent/routes/chat.test.js.map +1 -0
- package/dist/src/agent/routes/inspect.d.ts +12 -0
- package/dist/src/agent/routes/inspect.js +40 -0
- package/dist/src/agent/routes/inspect.js.map +1 -0
- package/dist/src/agent/routes/inspect.test.d.ts +6 -0
- package/dist/src/agent/routes/inspect.test.js +80 -0
- package/dist/src/agent/routes/inspect.test.js.map +1 -0
- package/dist/src/agent/routes/stores.d.ts +20 -0
- package/dist/src/agent/routes/stores.js +137 -0
- package/dist/src/agent/routes/stores.js.map +1 -0
- package/dist/src/agent/routes/stores.test.d.ts +6 -0
- package/dist/src/agent/routes/stores.test.js +191 -0
- package/dist/src/agent/routes/stores.test.js.map +1 -0
- package/dist/src/agent/routes/task.d.ts +11 -0
- package/dist/src/agent/routes/task.js +116 -0
- package/dist/src/agent/routes/task.js.map +1 -0
- package/dist/src/agent/routes/task.test.d.ts +6 -0
- package/dist/src/agent/routes/task.test.js +91 -0
- package/dist/src/agent/routes/task.test.js.map +1 -0
- package/dist/src/agent/routes/webhooks.d.ts +17 -0
- package/dist/src/agent/routes/webhooks.js +53 -0
- package/dist/src/agent/routes/webhooks.js.map +1 -0
- package/dist/src/agent/routes/webhooks.test.d.ts +6 -0
- package/dist/src/agent/routes/webhooks.test.js +100 -0
- package/dist/src/agent/routes/webhooks.test.js.map +1 -0
- package/dist/src/agent/session-manager.d.ts +72 -0
- package/dist/src/agent/session-manager.js +214 -0
- package/dist/src/agent/session-manager.js.map +1 -0
- package/dist/src/agent/session-manager.test.d.ts +6 -0
- package/dist/src/agent/session-manager.test.js +145 -0
- package/dist/src/agent/session-manager.test.js.map +1 -0
- package/dist/src/agent/shell-executor-local.d.ts +16 -0
- package/dist/src/agent/shell-executor-local.js +51 -0
- package/dist/src/agent/shell-executor-local.js.map +1 -0
- package/dist/src/agent/shell-executor-local.test.d.ts +6 -0
- package/dist/src/agent/shell-executor-local.test.js +46 -0
- package/dist/src/agent/shell-executor-local.test.js.map +1 -0
- package/dist/src/agent/snapshot-server.d.ts +38 -0
- package/dist/src/agent/snapshot-server.js +114 -0
- package/dist/src/agent/snapshot-server.js.map +1 -0
- package/dist/src/agent/stores-e2e.test.d.ts +6 -0
- package/dist/src/agent/stores-e2e.test.js +433 -0
- package/dist/src/agent/stores-e2e.test.js.map +1 -0
- package/dist/src/agent/tool-context-builder.d.ts +11 -0
- package/dist/src/agent/tool-context-builder.js +84 -0
- package/dist/src/agent/tool-context-builder.js.map +1 -0
- package/dist/src/agent/tool-context-builder.test.d.ts +6 -0
- package/dist/src/agent/tool-context-builder.test.js +152 -0
- package/dist/src/agent/tool-context-builder.test.js.map +1 -0
- package/dist/src/agent/tool-executor-local.d.ts +15 -0
- package/dist/src/agent/tool-executor-local.js +74 -0
- package/dist/src/agent/tool-executor-local.js.map +1 -0
- package/dist/src/agent/tool-executor-local.test.d.ts +6 -0
- package/dist/src/agent/tool-executor-local.test.js +116 -0
- package/dist/src/agent/tool-executor-local.test.js.map +1 -0
- package/dist/src/agent/tool-harness-template.d.ts +23 -0
- package/dist/src/agent/tool-harness-template.js +94 -0
- package/dist/src/agent/tool-harness-template.js.map +1 -0
- package/dist/src/agent/user-context-fetcher.d.ts +25 -0
- package/dist/src/agent/user-context-fetcher.js +79 -0
- package/dist/src/agent/user-context-fetcher.js.map +1 -0
- package/dist/src/agent/user-context-fetcher.test.d.ts +6 -0
- package/dist/src/agent/user-context-fetcher.test.js +121 -0
- package/dist/src/agent/user-context-fetcher.test.js.map +1 -0
- package/dist/src/audit/audit-client.d.ts +46 -0
- package/dist/src/audit/audit-client.js +83 -0
- package/dist/src/audit/audit-client.js.map +1 -0
- package/dist/src/cron/heartbeat-runner.d.ts +24 -0
- package/dist/src/cron/heartbeat-runner.js +87 -0
- package/dist/src/cron/heartbeat-runner.js.map +1 -0
- package/dist/src/cron/heartbeat-runner.test.d.ts +6 -0
- package/dist/src/cron/heartbeat-runner.test.js +120 -0
- package/dist/src/cron/heartbeat-runner.test.js.map +1 -0
- package/dist/src/cron/heartbeat-scheduler.d.ts +26 -0
- package/dist/src/cron/heartbeat-scheduler.js +54 -0
- package/dist/src/cron/heartbeat-scheduler.js.map +1 -0
- package/dist/src/cron/heartbeat-scheduler.test.d.ts +6 -0
- package/dist/src/cron/heartbeat-scheduler.test.js +61 -0
- package/dist/src/cron/heartbeat-scheduler.test.js.map +1 -0
- package/dist/src/index.d.ts +24 -0
- package/dist/src/index.js +118 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/middleware/auth.d.ts +40 -0
- package/dist/src/middleware/auth.js +135 -0
- package/dist/src/middleware/auth.js.map +1 -0
- package/dist/src/middleware/auth.test.d.ts +6 -0
- package/dist/src/middleware/auth.test.js +268 -0
- package/dist/src/middleware/auth.test.js.map +1 -0
- package/dist/src/middleware/error-handler.d.ts +20 -0
- package/dist/src/middleware/error-handler.js +48 -0
- package/dist/src/middleware/error-handler.js.map +1 -0
- package/dist/src/middleware/error-handler.test.d.ts +6 -0
- package/dist/src/middleware/error-handler.test.js +68 -0
- package/dist/src/middleware/error-handler.test.js.map +1 -0
- package/dist/src/middleware/request-validation.d.ts +13 -0
- package/dist/src/middleware/request-validation.js +26 -0
- package/dist/src/middleware/request-validation.js.map +1 -0
- package/dist/src/middleware/request-validation.test.d.ts +6 -0
- package/dist/src/middleware/request-validation.test.js +57 -0
- package/dist/src/middleware/request-validation.test.js.map +1 -0
- package/dist/src/output/email-output.d.ts +10 -0
- package/dist/src/output/email-output.js +12 -0
- package/dist/src/output/email-output.js.map +1 -0
- package/dist/src/output/output-router.d.ts +12 -0
- package/dist/src/output/output-router.js +36 -0
- package/dist/src/output/output-router.js.map +1 -0
- package/dist/src/output/output-router.test.d.ts +6 -0
- package/dist/src/output/output-router.test.js +132 -0
- package/dist/src/output/output-router.test.js.map +1 -0
- package/dist/src/output/slack-output.d.ts +10 -0
- package/dist/src/output/slack-output.js +54 -0
- package/dist/src/output/slack-output.js.map +1 -0
- package/dist/src/output/webhook-output.d.ts +10 -0
- package/dist/src/output/webhook-output.js +25 -0
- package/dist/src/output/webhook-output.js.map +1 -0
- package/dist/src/routes/ai-stream.d.ts +159 -0
- package/dist/src/routes/ai-stream.js +309 -0
- package/dist/src/routes/ai-stream.js.map +1 -0
- package/dist/src/routes/ai-stream.test.d.ts +6 -0
- package/dist/src/routes/ai-stream.test.js +586 -0
- package/dist/src/routes/ai-stream.test.js.map +1 -0
- package/dist/src/routes/ask-user-response.d.ts +30 -0
- package/dist/src/routes/ask-user-response.js +61 -0
- package/dist/src/routes/ask-user-response.js.map +1 -0
- package/dist/src/routes/ask-user-response.test.d.ts +6 -0
- package/dist/src/routes/ask-user-response.test.js +88 -0
- package/dist/src/routes/ask-user-response.test.js.map +1 -0
- package/dist/src/routes/chat-stream.d.ts +14 -0
- package/dist/src/routes/chat-stream.js +84 -0
- package/dist/src/routes/chat-stream.js.map +1 -0
- package/dist/src/routes/chat-stream.test.d.ts +6 -0
- package/dist/src/routes/chat-stream.test.js +155 -0
- package/dist/src/routes/chat-stream.test.js.map +1 -0
- package/dist/src/routes/chat.d.ts +13 -0
- package/dist/src/routes/chat.js +55 -0
- package/dist/src/routes/chat.js.map +1 -0
- package/dist/src/routes/chat.test.d.ts +6 -0
- package/dist/src/routes/chat.test.js +99 -0
- package/dist/src/routes/chat.test.js.map +1 -0
- package/dist/src/routes/health.d.ts +13 -0
- package/dist/src/routes/health.js +23 -0
- package/dist/src/routes/health.js.map +1 -0
- package/dist/src/routes/health.test.d.ts +6 -0
- package/dist/src/routes/health.test.js +45 -0
- package/dist/src/routes/health.test.js.map +1 -0
- package/dist/src/routes/sessions.d.ts +14 -0
- package/dist/src/routes/sessions.js +82 -0
- package/dist/src/routes/sessions.js.map +1 -0
- package/dist/src/routes/webhooks.d.ts +13 -0
- package/dist/src/routes/webhooks.js +43 -0
- package/dist/src/routes/webhooks.js.map +1 -0
- package/dist/src/routes/webhooks.test.d.ts +6 -0
- package/dist/src/routes/webhooks.test.js +80 -0
- package/dist/src/routes/webhooks.test.js.map +1 -0
- package/dist/src/routes/widget-actions.d.ts +49 -0
- package/dist/src/routes/widget-actions.js +78 -0
- package/dist/src/routes/widget-actions.js.map +1 -0
- package/dist/src/server.d.ts +31 -0
- package/dist/src/server.js +129 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/server.test.d.ts +6 -0
- package/dist/src/server.test.js +153 -0
- package/dist/src/server.test.js.map +1 -0
- package/dist/src/session/history-converter.d.ts +21 -0
- package/dist/src/session/history-converter.js +59 -0
- package/dist/src/session/history-converter.js.map +1 -0
- package/dist/src/session/history-converter.test.d.ts +6 -0
- package/dist/src/session/history-converter.test.js +130 -0
- package/dist/src/session/history-converter.test.js.map +1 -0
- package/dist/src/session/session-manager.d.ts +117 -0
- package/dist/src/session/session-manager.js +480 -0
- package/dist/src/session/session-manager.js.map +1 -0
- package/dist/src/session/session-manager.test.d.ts +6 -0
- package/dist/src/session/session-manager.test.js +586 -0
- package/dist/src/session/session-manager.test.js.map +1 -0
- package/dist/src/session/session-runner.d.ts +30 -0
- package/dist/src/session/session-runner.js +771 -0
- package/dist/src/session/session-runner.js.map +1 -0
- package/dist/src/session/session-runner.test.d.ts +6 -0
- package/dist/src/session/session-runner.test.js +842 -0
- package/dist/src/session/session-runner.test.js.map +1 -0
- package/dist/src/stores/index.d.ts +8 -0
- package/dist/src/stores/index.js +9 -0
- package/dist/src/stores/index.js.map +1 -0
- package/dist/src/stores/key-resolver.d.ts +21 -0
- package/dist/src/stores/key-resolver.js +30 -0
- package/dist/src/stores/key-resolver.js.map +1 -0
- package/dist/src/stores/key-resolver.test.d.ts +6 -0
- package/dist/src/stores/key-resolver.test.js +31 -0
- package/dist/src/stores/key-resolver.test.js.map +1 -0
- package/dist/src/stores/pglite-store-backend.d.ts +36 -0
- package/dist/src/stores/pglite-store-backend.js +227 -0
- package/dist/src/stores/pglite-store-backend.js.map +1 -0
- package/dist/src/stores/pglite-store-backend.test.d.ts +6 -0
- package/dist/src/stores/pglite-store-backend.test.js +150 -0
- package/dist/src/stores/pglite-store-backend.test.js.map +1 -0
- package/dist/src/stores/ttl-resolver.d.ts +24 -0
- package/dist/src/stores/ttl-resolver.js +64 -0
- package/dist/src/stores/ttl-resolver.js.map +1 -0
- package/dist/src/stores/ttl-resolver.test.d.ts +6 -0
- package/dist/src/stores/ttl-resolver.test.js +68 -0
- package/dist/src/stores/ttl-resolver.test.js.map +1 -0
- package/dist/src/types.d.ts +227 -0
- package/dist/src/types.js +50 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/types.test.d.ts +6 -0
- package/dist/src/types.test.js +68 -0
- package/dist/src/types.test.js.map +1 -0
- package/dist/src/utils/jwt-verify.d.ts +20 -0
- package/dist/src/utils/jwt-verify.js +34 -0
- package/dist/src/utils/jwt-verify.js.map +1 -0
- package/dist/src/utils/jwt-verify.test.d.ts +6 -0
- package/dist/src/utils/jwt-verify.test.js +156 -0
- package/dist/src/utils/jwt-verify.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import type { SessionManager } from '../session/session-manager.js';
|
|
8
|
+
export interface HealthRouterOptions {
|
|
9
|
+
sessionManager: SessionManager;
|
|
10
|
+
version?: string;
|
|
11
|
+
startedAt: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function createHealthRouter(options: HealthRouterOptions): Router;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
export function createHealthRouter(options) {
|
|
8
|
+
const router = Router();
|
|
9
|
+
router.get('/health', (_req, res) => {
|
|
10
|
+
res.json({
|
|
11
|
+
status: 'ok',
|
|
12
|
+
uptime_ms: Date.now() - options.startedAt,
|
|
13
|
+
active_sessions: options.sessionManager.size,
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
router.get('/version', (_req, res) => {
|
|
17
|
+
res.json({
|
|
18
|
+
version: options.version ?? 'unknown',
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
return router;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../../src/routes/health.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AASjC,MAAM,UAAU,kBAAkB,CAAC,OAA4B;IAC7D,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QAClC,GAAG,CAAC,IAAI,CAAC;YACP,MAAM,EAAE,IAAI;YACZ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS;YACzC,eAAe,EAAE,OAAO,CAAC,cAAc,CAAC,IAAI;SAC7C,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACnC,GAAG,CAAC,IAAI,CAAC;YACP,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,SAAS;SACtC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect } from 'vitest';
|
|
7
|
+
import express from 'express';
|
|
8
|
+
import request from 'supertest';
|
|
9
|
+
import { createHealthRouter } from './health.js';
|
|
10
|
+
function createApp() {
|
|
11
|
+
const app = express();
|
|
12
|
+
const sessionManager = { size: 3 };
|
|
13
|
+
app.use(createHealthRouter({
|
|
14
|
+
sessionManager: sessionManager,
|
|
15
|
+
version: '1.0.0',
|
|
16
|
+
startedAt: Date.now() - 5000,
|
|
17
|
+
}));
|
|
18
|
+
return app;
|
|
19
|
+
}
|
|
20
|
+
describe('GET /health', () => {
|
|
21
|
+
it('returns 200 with status ok', async () => {
|
|
22
|
+
const res = await request(createApp()).get('/health');
|
|
23
|
+
expect(res.status).toBe(200);
|
|
24
|
+
expect(res.body.status).toBe('ok');
|
|
25
|
+
expect(res.body.active_sessions).toBe(3);
|
|
26
|
+
expect(res.body.uptime_ms).toBeGreaterThan(0);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe('GET /version', () => {
|
|
30
|
+
it('returns 200 with version', async () => {
|
|
31
|
+
const res = await request(createApp()).get('/version');
|
|
32
|
+
expect(res.status).toBe(200);
|
|
33
|
+
expect(res.body.version).toBe('1.0.0');
|
|
34
|
+
});
|
|
35
|
+
it('returns unknown when no version provided', async () => {
|
|
36
|
+
const app = express();
|
|
37
|
+
app.use(createHealthRouter({
|
|
38
|
+
sessionManager: { size: 0 },
|
|
39
|
+
startedAt: Date.now(),
|
|
40
|
+
}));
|
|
41
|
+
const res = await request(app).get('/version');
|
|
42
|
+
expect(res.body.version).toBe('unknown');
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=health.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.test.js","sourceRoot":"","sources":["../../../src/routes/health.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,OAAO,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,SAAS,SAAS;IAChB,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,MAAM,cAAc,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IACnC,GAAG,CAAC,GAAG,CACL,kBAAkB,CAAC;QACjB,cAAc,EAAE,cAAuB;QACvC,OAAO,EAAE,OAAO;QAChB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI;KAC7B,CAAC,CACH,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACtD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;QACtB,GAAG,CAAC,GAAG,CACL,kBAAkB,CAAC;YACjB,cAAc,EAAE,EAAE,IAAI,EAAE,CAAC,EAAW;YACpC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CACH,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC/C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
export interface SessionsRouterOptions {
|
|
8
|
+
platformApiUrl: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Proxy routes for session history.
|
|
12
|
+
* Forwards to platform-api /api/tenants/{tenantId}/sessions endpoints.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createSessionsRouter(options: SessionsRouterOptions): Router;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import { getAuthContext } from '../middleware/auth.js';
|
|
8
|
+
/**
|
|
9
|
+
* Proxy routes for session history.
|
|
10
|
+
* Forwards to platform-api /api/tenants/{tenantId}/sessions endpoints.
|
|
11
|
+
*/
|
|
12
|
+
export function createSessionsRouter(options) {
|
|
13
|
+
const router = Router();
|
|
14
|
+
// List sessions for the authenticated tenant
|
|
15
|
+
router.get('/sessions/history', async (req, res, next) => {
|
|
16
|
+
try {
|
|
17
|
+
const auth = getAuthContext(res);
|
|
18
|
+
if (!auth?.tenantId || !auth.token) {
|
|
19
|
+
res.status(401).json({ error: { code: 'UNAUTHORIZED', message: 'Missing auth context' } });
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const tagsParam = req.query['tags'];
|
|
23
|
+
const qs = tagsParam ? `?tags=${String(tagsParam)}` : '';
|
|
24
|
+
const url = `${options.platformApiUrl}/api/tenants/${auth.tenantId}/sessions${qs}`;
|
|
25
|
+
const response = await fetch(url, {
|
|
26
|
+
headers: { Authorization: `Bearer ${auth.token}` },
|
|
27
|
+
});
|
|
28
|
+
const data = await response.json();
|
|
29
|
+
res.status(response.status).json(data);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
next(err);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
// Get a single session with full messages
|
|
36
|
+
router.get('/sessions/history/:id', async (req, res, next) => {
|
|
37
|
+
try {
|
|
38
|
+
const auth = getAuthContext(res);
|
|
39
|
+
if (!auth?.tenantId || !auth.token) {
|
|
40
|
+
res.status(401).json({ error: { code: 'UNAUTHORIZED', message: 'Missing auth context' } });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const sessionId = req.params['id'];
|
|
44
|
+
const url = `${options.platformApiUrl}/api/tenants/${auth.tenantId}/sessions/${sessionId}`;
|
|
45
|
+
const response = await fetch(url, {
|
|
46
|
+
headers: { Authorization: `Bearer ${auth.token}` },
|
|
47
|
+
});
|
|
48
|
+
const data = await response.json();
|
|
49
|
+
res.status(response.status).json(data);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
next(err);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
// Update session tags/title
|
|
56
|
+
router.patch('/sessions/history/:id', async (req, res, next) => {
|
|
57
|
+
try {
|
|
58
|
+
const auth = getAuthContext(res);
|
|
59
|
+
if (!auth?.tenantId || !auth.token) {
|
|
60
|
+
res.status(401).json({ error: { code: 'UNAUTHORIZED', message: 'Missing auth context' } });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const sessionId = req.params['id'];
|
|
64
|
+
const url = `${options.platformApiUrl}/api/tenants/${auth.tenantId}/sessions/${sessionId}`;
|
|
65
|
+
const response = await fetch(url, {
|
|
66
|
+
method: 'PATCH',
|
|
67
|
+
headers: {
|
|
68
|
+
'Content-Type': 'application/json',
|
|
69
|
+
Authorization: `Bearer ${auth.token}`,
|
|
70
|
+
},
|
|
71
|
+
body: JSON.stringify(req.body),
|
|
72
|
+
});
|
|
73
|
+
const data = await response.json();
|
|
74
|
+
res.status(response.status).json(data);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
next(err);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return router;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../../src/routes/sessions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import type { AutomationDefinition } from '@amodalai/core';
|
|
8
|
+
import type { AutomationRunnerFn } from '../cron/heartbeat-runner.js';
|
|
9
|
+
export interface WebhookRouterOptions {
|
|
10
|
+
automations: AutomationDefinition[];
|
|
11
|
+
runAutomation: AutomationRunnerFn;
|
|
12
|
+
}
|
|
13
|
+
export declare function createWebhookRouter(options: WebhookRouterOptions): Router;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import { WebhookPayloadSchema } from '../types.js';
|
|
8
|
+
import { validate } from '../middleware/request-validation.js';
|
|
9
|
+
import { AppError } from '../middleware/error-handler.js';
|
|
10
|
+
export function createWebhookRouter(options) {
|
|
11
|
+
const router = Router();
|
|
12
|
+
// Build a lookup map: webhook source name → automation definition
|
|
13
|
+
const webhookAutomations = new Map();
|
|
14
|
+
for (const a of options.automations) {
|
|
15
|
+
if (a.trigger.type === 'webhook') {
|
|
16
|
+
webhookAutomations.set(a.name, a);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
router.post('/webhooks/:name', validate(WebhookPayloadSchema), async (req, res, next) => {
|
|
20
|
+
try {
|
|
21
|
+
const { name } = req.params;
|
|
22
|
+
if (!name) {
|
|
23
|
+
throw new AppError(400, 'MISSING_NAME', 'Automation name is required');
|
|
24
|
+
}
|
|
25
|
+
const automation = webhookAutomations.get(name);
|
|
26
|
+
if (!automation) {
|
|
27
|
+
throw new AppError(404, 'AUTOMATION_NOT_FOUND', `No webhook automation named "${name}"`);
|
|
28
|
+
}
|
|
29
|
+
// Run automation asynchronously — respond 202 immediately
|
|
30
|
+
const payload = req.body.data;
|
|
31
|
+
void options.runAutomation(automation, payload);
|
|
32
|
+
res.status(202).json({
|
|
33
|
+
accepted: true,
|
|
34
|
+
automation: name,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
next(err);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
return router;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=webhooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../../src/routes/webhooks.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAQ1D,MAAM,UAAU,mBAAmB,CAAC,OAA6B;IAC/D,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,kEAAkE;IAClE,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAgC,CAAC;IACnE,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACpC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACjC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,QAAQ,CAAC,oBAAoB,CAAC,EAC9B,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACvB,IAAI,CAAC;YACH,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC;YAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,6BAA6B,CAAC,CAAC;YACzE,CAAC;YAED,MAAM,UAAU,GAAG,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,QAAQ,CAChB,GAAG,EACH,sBAAsB,EACtB,gCAAgC,IAAI,GAAG,CACxC,CAAC;YACJ,CAAC;YAED,0DAA0D;YAC1D,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAC9B,KAAK,OAAO,CAAC,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAEhD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,QAAQ,EAAE,IAAI;gBACd,UAAU,EAAE,IAAI;aACjB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
7
|
+
import express from 'express';
|
|
8
|
+
import request from 'supertest';
|
|
9
|
+
import { createWebhookRouter } from './webhooks.js';
|
|
10
|
+
import { errorHandler } from '../middleware/error-handler.js';
|
|
11
|
+
function makeAutomation(name, triggerType = 'webhook') {
|
|
12
|
+
return {
|
|
13
|
+
name,
|
|
14
|
+
trigger: triggerType === 'cron'
|
|
15
|
+
? { type: 'cron', schedule: '*/5 * * * *' }
|
|
16
|
+
: { type: 'webhook', source: name },
|
|
17
|
+
prompt: `Handle ${name}`,
|
|
18
|
+
tools: ['tool1'],
|
|
19
|
+
skills: ['*'],
|
|
20
|
+
output: { channel: 'slack', target: 'https://hooks.slack.com/abc' },
|
|
21
|
+
allow_writes: false,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
describe('POST /webhooks/:name', () => {
|
|
25
|
+
let mockRunAutomation;
|
|
26
|
+
let automations;
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
mockRunAutomation = vi.fn().mockResolvedValue({
|
|
29
|
+
automation: 'test-webhook',
|
|
30
|
+
response: 'done',
|
|
31
|
+
tool_calls: [],
|
|
32
|
+
output_sent: true,
|
|
33
|
+
duration_ms: 100,
|
|
34
|
+
});
|
|
35
|
+
automations = [
|
|
36
|
+
makeAutomation('test-webhook', 'webhook'),
|
|
37
|
+
makeAutomation('cron-only', 'cron'),
|
|
38
|
+
];
|
|
39
|
+
});
|
|
40
|
+
function createApp() {
|
|
41
|
+
const app = express();
|
|
42
|
+
app.use(express.json());
|
|
43
|
+
app.use(createWebhookRouter({
|
|
44
|
+
automations,
|
|
45
|
+
runAutomation: mockRunAutomation,
|
|
46
|
+
}));
|
|
47
|
+
app.use(errorHandler);
|
|
48
|
+
return app;
|
|
49
|
+
}
|
|
50
|
+
it('accepts a known webhook automation with 202', async () => {
|
|
51
|
+
const res = await request(createApp())
|
|
52
|
+
.post('/webhooks/test-webhook')
|
|
53
|
+
.send({});
|
|
54
|
+
expect(res.status).toBe(202);
|
|
55
|
+
expect(res.body.accepted).toBe(true);
|
|
56
|
+
expect(res.body.automation).toBe('test-webhook');
|
|
57
|
+
expect(mockRunAutomation).toHaveBeenCalledOnce();
|
|
58
|
+
});
|
|
59
|
+
it('passes payload data to automation runner', async () => {
|
|
60
|
+
await request(createApp())
|
|
61
|
+
.post('/webhooks/test-webhook')
|
|
62
|
+
.send({ data: { device_id: '42' } });
|
|
63
|
+
const callArgs = mockRunAutomation.mock.calls[0];
|
|
64
|
+
expect(callArgs[1]).toEqual({ device_id: '42' });
|
|
65
|
+
});
|
|
66
|
+
it('returns 404 for unknown automation name', async () => {
|
|
67
|
+
const res = await request(createApp())
|
|
68
|
+
.post('/webhooks/nonexistent')
|
|
69
|
+
.send({});
|
|
70
|
+
expect(res.status).toBe(404);
|
|
71
|
+
expect(res.body.error.code).toBe('AUTOMATION_NOT_FOUND');
|
|
72
|
+
});
|
|
73
|
+
it('returns 404 for cron-only automation', async () => {
|
|
74
|
+
const res = await request(createApp())
|
|
75
|
+
.post('/webhooks/cron-only')
|
|
76
|
+
.send({});
|
|
77
|
+
expect(res.status).toBe(404);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
//# sourceMappingURL=webhooks.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.test.js","sourceRoot":"","sources":["../../../src/routes/webhooks.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import type { SessionManager } from '../session/session-manager.js';
|
|
9
|
+
declare const WidgetActionSchema: z.ZodDiscriminatedUnion<"action", [z.ZodObject<{
|
|
10
|
+
action: z.ZodLiteral<"credential_saved">;
|
|
11
|
+
connection_name: z.ZodString;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
action: "credential_saved";
|
|
14
|
+
connection_name: string;
|
|
15
|
+
}, {
|
|
16
|
+
action: "credential_saved";
|
|
17
|
+
connection_name: string;
|
|
18
|
+
}>, z.ZodObject<{
|
|
19
|
+
action: z.ZodLiteral<"approved">;
|
|
20
|
+
resource_type: z.ZodString;
|
|
21
|
+
preview_id: z.ZodString;
|
|
22
|
+
}, "strip", z.ZodTypeAny, {
|
|
23
|
+
action: "approved";
|
|
24
|
+
resource_type: string;
|
|
25
|
+
preview_id: string;
|
|
26
|
+
}, {
|
|
27
|
+
action: "approved";
|
|
28
|
+
resource_type: string;
|
|
29
|
+
preview_id: string;
|
|
30
|
+
}>]>;
|
|
31
|
+
export type WidgetAction = z.infer<typeof WidgetActionSchema>;
|
|
32
|
+
export interface WidgetActionsRouterOptions {
|
|
33
|
+
sessionManager: SessionManager;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Construct the synthetic user message for a widget action.
|
|
37
|
+
* The chat widget sends this as a follow-up user message so the
|
|
38
|
+
* agent knows the user acted on the widget.
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildSyntheticMessage(action: WidgetAction): string;
|
|
41
|
+
/**
|
|
42
|
+
* POST /chat/sessions/:session_id/widget-action
|
|
43
|
+
*
|
|
44
|
+
* Accepts user actions from input widgets (credential-input, document-preview).
|
|
45
|
+
* Validates the action and returns a synthetic message that the chat widget
|
|
46
|
+
* should send as a follow-up user message.
|
|
47
|
+
*/
|
|
48
|
+
export declare function createWidgetActionsRouter(options: WidgetActionsRouterOptions): Router;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
const WidgetActionSchema = z.discriminatedUnion('action', [
|
|
9
|
+
z.object({
|
|
10
|
+
action: z.literal('credential_saved'),
|
|
11
|
+
connection_name: z.string().min(1),
|
|
12
|
+
}),
|
|
13
|
+
z.object({
|
|
14
|
+
action: z.literal('approved'),
|
|
15
|
+
resource_type: z.string().min(1),
|
|
16
|
+
preview_id: z.string().min(1),
|
|
17
|
+
}),
|
|
18
|
+
]);
|
|
19
|
+
/**
|
|
20
|
+
* Construct the synthetic user message for a widget action.
|
|
21
|
+
* The chat widget sends this as a follow-up user message so the
|
|
22
|
+
* agent knows the user acted on the widget.
|
|
23
|
+
*/
|
|
24
|
+
export function buildSyntheticMessage(action) {
|
|
25
|
+
if (action.action === 'credential_saved') {
|
|
26
|
+
return `Credentials for ${action.connection_name} have been saved.`;
|
|
27
|
+
}
|
|
28
|
+
return `I've approved the ${action.resource_type} '${action.preview_id}'.`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* POST /chat/sessions/:session_id/widget-action
|
|
32
|
+
*
|
|
33
|
+
* Accepts user actions from input widgets (credential-input, document-preview).
|
|
34
|
+
* Validates the action and returns a synthetic message that the chat widget
|
|
35
|
+
* should send as a follow-up user message.
|
|
36
|
+
*/
|
|
37
|
+
export function createWidgetActionsRouter(options) {
|
|
38
|
+
const router = Router();
|
|
39
|
+
router.post('/chat/sessions/:session_id/widget-action', (req, res, next) => {
|
|
40
|
+
try {
|
|
41
|
+
const sessionId = req.params['session_id'];
|
|
42
|
+
if (!sessionId) {
|
|
43
|
+
res.status(400).json({
|
|
44
|
+
error: { code: 'MISSING_SESSION_ID', message: 'session_id is required' },
|
|
45
|
+
});
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const parsed = WidgetActionSchema.safeParse(req.body);
|
|
49
|
+
if (!parsed.success) {
|
|
50
|
+
res.status(400).json({
|
|
51
|
+
error: {
|
|
52
|
+
code: 'INVALID_ACTION',
|
|
53
|
+
message: parsed.error.errors.map((e) => e.message).join(', '),
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Verify session exists
|
|
59
|
+
const session = options.sessionManager.get(sessionId);
|
|
60
|
+
if (!session) {
|
|
61
|
+
res.status(404).json({
|
|
62
|
+
error: { code: 'SESSION_NOT_FOUND', message: `Session '${sessionId}' not found` },
|
|
63
|
+
});
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const syntheticMessage = buildSyntheticMessage(parsed.data);
|
|
67
|
+
res.json({
|
|
68
|
+
ok: true,
|
|
69
|
+
message: syntheticMessage,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
next(err);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return router;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=widget-actions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget-actions.js","sourceRoot":"","sources":["../../../src/routes/widget-actions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import type { Express } from 'express';
|
|
7
|
+
import type http from 'node:http';
|
|
8
|
+
import type { ConfigParameters } from '@amodalai/core';
|
|
9
|
+
import type { ServerConfig } from './types.js';
|
|
10
|
+
export interface ServerInstance {
|
|
11
|
+
app: Express;
|
|
12
|
+
start: () => Promise<http.Server>;
|
|
13
|
+
stop: () => Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export interface CreateServerOptions {
|
|
16
|
+
/** Base ConfigParameters for session creation */
|
|
17
|
+
baseParams: Partial<ConfigParameters>;
|
|
18
|
+
/** Server configuration */
|
|
19
|
+
config: ServerConfig;
|
|
20
|
+
/** Version string for /version endpoint */
|
|
21
|
+
version?: string;
|
|
22
|
+
/** Platform API URL for API key validation (if set, enables auth middleware) */
|
|
23
|
+
platformApiUrl?: string;
|
|
24
|
+
/** JWKS URL for JWT verification (defaults to platformApiUrl/.well-known/jwks.json) */
|
|
25
|
+
jwksUrl?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create the Express server with all routes, session management,
|
|
29
|
+
* automation scheduling, and graceful shutdown.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createServer(options: CreateServerOptions): ServerInstance;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import express from 'express';
|
|
7
|
+
import { errorHandler } from './middleware/error-handler.js';
|
|
8
|
+
import { createAuthMiddleware } from './middleware/auth.js';
|
|
9
|
+
import { createHealthRouter } from './routes/health.js';
|
|
10
|
+
import { createChatRouter } from './routes/chat.js';
|
|
11
|
+
import { createChatStreamRouter } from './routes/chat-stream.js';
|
|
12
|
+
import { createWebhookRouter } from './routes/webhooks.js';
|
|
13
|
+
import { createWidgetActionsRouter } from './routes/widget-actions.js';
|
|
14
|
+
import { createAskUserResponseRouter } from './routes/ask-user-response.js';
|
|
15
|
+
import { createSessionsRouter } from './routes/sessions.js';
|
|
16
|
+
import { createAIStreamRouter } from './routes/ai-stream.js';
|
|
17
|
+
import { SessionManager } from './session/session-manager.js';
|
|
18
|
+
import { createAutomationRunner } from './cron/heartbeat-runner.js';
|
|
19
|
+
import { AutomationScheduler } from './cron/heartbeat-scheduler.js';
|
|
20
|
+
import { AuditClient } from './audit/audit-client.js';
|
|
21
|
+
/**
|
|
22
|
+
* Create the Express server with all routes, session management,
|
|
23
|
+
* automation scheduling, and graceful shutdown.
|
|
24
|
+
*/
|
|
25
|
+
export function createServer(options) {
|
|
26
|
+
const { baseParams, config } = options;
|
|
27
|
+
const startedAt = Date.now();
|
|
28
|
+
// --- Session management ---
|
|
29
|
+
const sessionManager = new SessionManager({
|
|
30
|
+
baseParams,
|
|
31
|
+
ttlMs: config.sessionTtlMs,
|
|
32
|
+
platformApiUrl: options.platformApiUrl,
|
|
33
|
+
});
|
|
34
|
+
// --- Audit client (batching HTTP poster to platform API) ---
|
|
35
|
+
const auditClient = options.platformApiUrl
|
|
36
|
+
? new AuditClient({ platformApiUrl: options.platformApiUrl })
|
|
37
|
+
: undefined;
|
|
38
|
+
// --- Automation runner ---
|
|
39
|
+
const runAutomation = createAutomationRunner({ sessionManager, auditClient });
|
|
40
|
+
// --- Automation scheduler (cron) ---
|
|
41
|
+
const automationScheduler = new AutomationScheduler();
|
|
42
|
+
// --- Express app ---
|
|
43
|
+
const app = express();
|
|
44
|
+
// CORS middleware
|
|
45
|
+
const corsOrigin = config.corsOrigin ?? '*';
|
|
46
|
+
app.use((_req, res, next) => {
|
|
47
|
+
res.header('Access-Control-Allow-Origin', corsOrigin);
|
|
48
|
+
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
|
|
49
|
+
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
|
|
50
|
+
res.header('Access-Control-Expose-Headers', 'x-vercel-ai-ui-message-stream');
|
|
51
|
+
if (_req.method === 'OPTIONS') {
|
|
52
|
+
res.sendStatus(204);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
next();
|
|
56
|
+
});
|
|
57
|
+
app.use(express.json());
|
|
58
|
+
// Routes
|
|
59
|
+
app.use(createHealthRouter({
|
|
60
|
+
sessionManager,
|
|
61
|
+
version: options.version,
|
|
62
|
+
startedAt,
|
|
63
|
+
}));
|
|
64
|
+
// Auth middleware for chat routes (if platform API URL is configured)
|
|
65
|
+
if (options.platformApiUrl) {
|
|
66
|
+
const authMiddleware = createAuthMiddleware({
|
|
67
|
+
platformApiUrl: options.platformApiUrl,
|
|
68
|
+
jwksUrl: options.jwksUrl,
|
|
69
|
+
});
|
|
70
|
+
app.use('/chat', authMiddleware);
|
|
71
|
+
app.use('/chat/stream', authMiddleware);
|
|
72
|
+
app.use('/sessions', authMiddleware);
|
|
73
|
+
}
|
|
74
|
+
app.use(createChatRouter({ sessionManager, auditClient }));
|
|
75
|
+
app.use(createChatStreamRouter({ sessionManager, auditClient, platformApiUrl: options.platformApiUrl }));
|
|
76
|
+
app.use(createAIStreamRouter({ sessionManager, auditClient, platformApiUrl: options.platformApiUrl }));
|
|
77
|
+
app.use(createWidgetActionsRouter({ sessionManager }));
|
|
78
|
+
app.use(createAskUserResponseRouter({ sessionManager }));
|
|
79
|
+
// Session history proxy routes (requires platform API URL)
|
|
80
|
+
if (options.platformApiUrl) {
|
|
81
|
+
app.use(createSessionsRouter({ platformApiUrl: options.platformApiUrl }));
|
|
82
|
+
}
|
|
83
|
+
app.use(createWebhookRouter({
|
|
84
|
+
automations: config.automations,
|
|
85
|
+
runAutomation,
|
|
86
|
+
}));
|
|
87
|
+
// Error handler (must be last)
|
|
88
|
+
app.use(errorHandler);
|
|
89
|
+
let server = null;
|
|
90
|
+
return {
|
|
91
|
+
app,
|
|
92
|
+
async start() {
|
|
93
|
+
// Start cron automations
|
|
94
|
+
automationScheduler.start(config.automations, runAutomation);
|
|
95
|
+
return new Promise((resolve) => {
|
|
96
|
+
const httpServer = app.listen(config.port, config.host, () => {
|
|
97
|
+
process.stderr.write(`[INFO] Server listening on ${config.host}:${config.port}\n`);
|
|
98
|
+
resolve(httpServer);
|
|
99
|
+
});
|
|
100
|
+
server = httpServer;
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
async stop() {
|
|
104
|
+
// Stop cron jobs
|
|
105
|
+
automationScheduler.stop();
|
|
106
|
+
// Close HTTP server
|
|
107
|
+
if (server) {
|
|
108
|
+
const s = server;
|
|
109
|
+
await new Promise((resolve, reject) => {
|
|
110
|
+
s.close((err) => {
|
|
111
|
+
if (err)
|
|
112
|
+
reject(err);
|
|
113
|
+
else
|
|
114
|
+
resolve();
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
server = null;
|
|
118
|
+
}
|
|
119
|
+
// Drain audit entries
|
|
120
|
+
if (auditClient) {
|
|
121
|
+
await auditClient.shutdown();
|
|
122
|
+
}
|
|
123
|
+
// Drain sessions
|
|
124
|
+
await sessionManager.shutdown();
|
|
125
|
+
process.stderr.write('[INFO] Server stopped\n');
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=server.js.map
|