@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.
Files changed (277) hide show
  1. package/LICENSE +21 -0
  2. package/dist/.last_build +0 -0
  3. package/dist/src/agent/agent-runner.d.ts +13 -0
  4. package/dist/src/agent/agent-runner.js +827 -0
  5. package/dist/src/agent/agent-runner.js.map +1 -0
  6. package/dist/src/agent/agent-runner.test.d.ts +6 -0
  7. package/dist/src/agent/agent-runner.test.js +552 -0
  8. package/dist/src/agent/agent-runner.test.js.map +1 -0
  9. package/dist/src/agent/agent-types.d.ts +57 -0
  10. package/dist/src/agent/agent-types.js +17 -0
  11. package/dist/src/agent/agent-types.js.map +1 -0
  12. package/dist/src/agent/agent-types.test.d.ts +6 -0
  13. package/dist/src/agent/agent-types.test.js +44 -0
  14. package/dist/src/agent/agent-types.test.js.map +1 -0
  15. package/dist/src/agent/automation-bridge.d.ts +24 -0
  16. package/dist/src/agent/automation-bridge.js +24 -0
  17. package/dist/src/agent/automation-bridge.js.map +1 -0
  18. package/dist/src/agent/automation-bridge.test.d.ts +6 -0
  19. package/dist/src/agent/automation-bridge.test.js +67 -0
  20. package/dist/src/agent/automation-bridge.test.js.map +1 -0
  21. package/dist/src/agent/config-watcher.d.ts +20 -0
  22. package/dist/src/agent/config-watcher.js +68 -0
  23. package/dist/src/agent/config-watcher.js.map +1 -0
  24. package/dist/src/agent/config-watcher.test.d.ts +6 -0
  25. package/dist/src/agent/config-watcher.test.js +83 -0
  26. package/dist/src/agent/config-watcher.test.js.map +1 -0
  27. package/dist/src/agent/custom-tools-e2e.test.d.ts +6 -0
  28. package/dist/src/agent/custom-tools-e2e.test.js +566 -0
  29. package/dist/src/agent/custom-tools-e2e.test.js.map +1 -0
  30. package/dist/src/agent/local-server.d.ts +15 -0
  31. package/dist/src/agent/local-server.js +158 -0
  32. package/dist/src/agent/local-server.js.map +1 -0
  33. package/dist/src/agent/local-server.test.d.ts +6 -0
  34. package/dist/src/agent/local-server.test.js +126 -0
  35. package/dist/src/agent/local-server.test.js.map +1 -0
  36. package/dist/src/agent/proactive/delivery.d.ts +21 -0
  37. package/dist/src/agent/proactive/delivery.js +68 -0
  38. package/dist/src/agent/proactive/delivery.js.map +1 -0
  39. package/dist/src/agent/proactive/delivery.test.d.ts +6 -0
  40. package/dist/src/agent/proactive/delivery.test.js +65 -0
  41. package/dist/src/agent/proactive/delivery.test.js.map +1 -0
  42. package/dist/src/agent/proactive/proactive-runner.d.ts +76 -0
  43. package/dist/src/agent/proactive/proactive-runner.js +201 -0
  44. package/dist/src/agent/proactive/proactive-runner.js.map +1 -0
  45. package/dist/src/agent/proactive/proactive-runner.test.d.ts +6 -0
  46. package/dist/src/agent/proactive/proactive-runner.test.js +265 -0
  47. package/dist/src/agent/proactive/proactive-runner.test.js.map +1 -0
  48. package/dist/src/agent/request-helper.d.ts +16 -0
  49. package/dist/src/agent/request-helper.js +87 -0
  50. package/dist/src/agent/request-helper.js.map +1 -0
  51. package/dist/src/agent/routes/automations.d.ts +19 -0
  52. package/dist/src/agent/routes/automations.js +58 -0
  53. package/dist/src/agent/routes/automations.js.map +1 -0
  54. package/dist/src/agent/routes/automations.test.d.ts +6 -0
  55. package/dist/src/agent/routes/automations.test.js +117 -0
  56. package/dist/src/agent/routes/automations.test.js.map +1 -0
  57. package/dist/src/agent/routes/chat.d.ts +35 -0
  58. package/dist/src/agent/routes/chat.js +88 -0
  59. package/dist/src/agent/routes/chat.js.map +1 -0
  60. package/dist/src/agent/routes/chat.test.d.ts +6 -0
  61. package/dist/src/agent/routes/chat.test.js +115 -0
  62. package/dist/src/agent/routes/chat.test.js.map +1 -0
  63. package/dist/src/agent/routes/inspect.d.ts +12 -0
  64. package/dist/src/agent/routes/inspect.js +40 -0
  65. package/dist/src/agent/routes/inspect.js.map +1 -0
  66. package/dist/src/agent/routes/inspect.test.d.ts +6 -0
  67. package/dist/src/agent/routes/inspect.test.js +80 -0
  68. package/dist/src/agent/routes/inspect.test.js.map +1 -0
  69. package/dist/src/agent/routes/stores.d.ts +20 -0
  70. package/dist/src/agent/routes/stores.js +137 -0
  71. package/dist/src/agent/routes/stores.js.map +1 -0
  72. package/dist/src/agent/routes/stores.test.d.ts +6 -0
  73. package/dist/src/agent/routes/stores.test.js +191 -0
  74. package/dist/src/agent/routes/stores.test.js.map +1 -0
  75. package/dist/src/agent/routes/task.d.ts +11 -0
  76. package/dist/src/agent/routes/task.js +116 -0
  77. package/dist/src/agent/routes/task.js.map +1 -0
  78. package/dist/src/agent/routes/task.test.d.ts +6 -0
  79. package/dist/src/agent/routes/task.test.js +91 -0
  80. package/dist/src/agent/routes/task.test.js.map +1 -0
  81. package/dist/src/agent/routes/webhooks.d.ts +17 -0
  82. package/dist/src/agent/routes/webhooks.js +53 -0
  83. package/dist/src/agent/routes/webhooks.js.map +1 -0
  84. package/dist/src/agent/routes/webhooks.test.d.ts +6 -0
  85. package/dist/src/agent/routes/webhooks.test.js +100 -0
  86. package/dist/src/agent/routes/webhooks.test.js.map +1 -0
  87. package/dist/src/agent/session-manager.d.ts +72 -0
  88. package/dist/src/agent/session-manager.js +214 -0
  89. package/dist/src/agent/session-manager.js.map +1 -0
  90. package/dist/src/agent/session-manager.test.d.ts +6 -0
  91. package/dist/src/agent/session-manager.test.js +145 -0
  92. package/dist/src/agent/session-manager.test.js.map +1 -0
  93. package/dist/src/agent/shell-executor-local.d.ts +16 -0
  94. package/dist/src/agent/shell-executor-local.js +51 -0
  95. package/dist/src/agent/shell-executor-local.js.map +1 -0
  96. package/dist/src/agent/shell-executor-local.test.d.ts +6 -0
  97. package/dist/src/agent/shell-executor-local.test.js +46 -0
  98. package/dist/src/agent/shell-executor-local.test.js.map +1 -0
  99. package/dist/src/agent/snapshot-server.d.ts +38 -0
  100. package/dist/src/agent/snapshot-server.js +114 -0
  101. package/dist/src/agent/snapshot-server.js.map +1 -0
  102. package/dist/src/agent/stores-e2e.test.d.ts +6 -0
  103. package/dist/src/agent/stores-e2e.test.js +433 -0
  104. package/dist/src/agent/stores-e2e.test.js.map +1 -0
  105. package/dist/src/agent/tool-context-builder.d.ts +11 -0
  106. package/dist/src/agent/tool-context-builder.js +84 -0
  107. package/dist/src/agent/tool-context-builder.js.map +1 -0
  108. package/dist/src/agent/tool-context-builder.test.d.ts +6 -0
  109. package/dist/src/agent/tool-context-builder.test.js +152 -0
  110. package/dist/src/agent/tool-context-builder.test.js.map +1 -0
  111. package/dist/src/agent/tool-executor-local.d.ts +15 -0
  112. package/dist/src/agent/tool-executor-local.js +74 -0
  113. package/dist/src/agent/tool-executor-local.js.map +1 -0
  114. package/dist/src/agent/tool-executor-local.test.d.ts +6 -0
  115. package/dist/src/agent/tool-executor-local.test.js +116 -0
  116. package/dist/src/agent/tool-executor-local.test.js.map +1 -0
  117. package/dist/src/agent/tool-harness-template.d.ts +23 -0
  118. package/dist/src/agent/tool-harness-template.js +94 -0
  119. package/dist/src/agent/tool-harness-template.js.map +1 -0
  120. package/dist/src/agent/user-context-fetcher.d.ts +25 -0
  121. package/dist/src/agent/user-context-fetcher.js +79 -0
  122. package/dist/src/agent/user-context-fetcher.js.map +1 -0
  123. package/dist/src/agent/user-context-fetcher.test.d.ts +6 -0
  124. package/dist/src/agent/user-context-fetcher.test.js +121 -0
  125. package/dist/src/agent/user-context-fetcher.test.js.map +1 -0
  126. package/dist/src/audit/audit-client.d.ts +46 -0
  127. package/dist/src/audit/audit-client.js +83 -0
  128. package/dist/src/audit/audit-client.js.map +1 -0
  129. package/dist/src/cron/heartbeat-runner.d.ts +24 -0
  130. package/dist/src/cron/heartbeat-runner.js +87 -0
  131. package/dist/src/cron/heartbeat-runner.js.map +1 -0
  132. package/dist/src/cron/heartbeat-runner.test.d.ts +6 -0
  133. package/dist/src/cron/heartbeat-runner.test.js +120 -0
  134. package/dist/src/cron/heartbeat-runner.test.js.map +1 -0
  135. package/dist/src/cron/heartbeat-scheduler.d.ts +26 -0
  136. package/dist/src/cron/heartbeat-scheduler.js +54 -0
  137. package/dist/src/cron/heartbeat-scheduler.js.map +1 -0
  138. package/dist/src/cron/heartbeat-scheduler.test.d.ts +6 -0
  139. package/dist/src/cron/heartbeat-scheduler.test.js +61 -0
  140. package/dist/src/cron/heartbeat-scheduler.test.js.map +1 -0
  141. package/dist/src/index.d.ts +24 -0
  142. package/dist/src/index.js +118 -0
  143. package/dist/src/index.js.map +1 -0
  144. package/dist/src/middleware/auth.d.ts +40 -0
  145. package/dist/src/middleware/auth.js +135 -0
  146. package/dist/src/middleware/auth.js.map +1 -0
  147. package/dist/src/middleware/auth.test.d.ts +6 -0
  148. package/dist/src/middleware/auth.test.js +268 -0
  149. package/dist/src/middleware/auth.test.js.map +1 -0
  150. package/dist/src/middleware/error-handler.d.ts +20 -0
  151. package/dist/src/middleware/error-handler.js +48 -0
  152. package/dist/src/middleware/error-handler.js.map +1 -0
  153. package/dist/src/middleware/error-handler.test.d.ts +6 -0
  154. package/dist/src/middleware/error-handler.test.js +68 -0
  155. package/dist/src/middleware/error-handler.test.js.map +1 -0
  156. package/dist/src/middleware/request-validation.d.ts +13 -0
  157. package/dist/src/middleware/request-validation.js +26 -0
  158. package/dist/src/middleware/request-validation.js.map +1 -0
  159. package/dist/src/middleware/request-validation.test.d.ts +6 -0
  160. package/dist/src/middleware/request-validation.test.js +57 -0
  161. package/dist/src/middleware/request-validation.test.js.map +1 -0
  162. package/dist/src/output/email-output.d.ts +10 -0
  163. package/dist/src/output/email-output.js +12 -0
  164. package/dist/src/output/email-output.js.map +1 -0
  165. package/dist/src/output/output-router.d.ts +12 -0
  166. package/dist/src/output/output-router.js +36 -0
  167. package/dist/src/output/output-router.js.map +1 -0
  168. package/dist/src/output/output-router.test.d.ts +6 -0
  169. package/dist/src/output/output-router.test.js +132 -0
  170. package/dist/src/output/output-router.test.js.map +1 -0
  171. package/dist/src/output/slack-output.d.ts +10 -0
  172. package/dist/src/output/slack-output.js +54 -0
  173. package/dist/src/output/slack-output.js.map +1 -0
  174. package/dist/src/output/webhook-output.d.ts +10 -0
  175. package/dist/src/output/webhook-output.js +25 -0
  176. package/dist/src/output/webhook-output.js.map +1 -0
  177. package/dist/src/routes/ai-stream.d.ts +159 -0
  178. package/dist/src/routes/ai-stream.js +309 -0
  179. package/dist/src/routes/ai-stream.js.map +1 -0
  180. package/dist/src/routes/ai-stream.test.d.ts +6 -0
  181. package/dist/src/routes/ai-stream.test.js +586 -0
  182. package/dist/src/routes/ai-stream.test.js.map +1 -0
  183. package/dist/src/routes/ask-user-response.d.ts +30 -0
  184. package/dist/src/routes/ask-user-response.js +61 -0
  185. package/dist/src/routes/ask-user-response.js.map +1 -0
  186. package/dist/src/routes/ask-user-response.test.d.ts +6 -0
  187. package/dist/src/routes/ask-user-response.test.js +88 -0
  188. package/dist/src/routes/ask-user-response.test.js.map +1 -0
  189. package/dist/src/routes/chat-stream.d.ts +14 -0
  190. package/dist/src/routes/chat-stream.js +84 -0
  191. package/dist/src/routes/chat-stream.js.map +1 -0
  192. package/dist/src/routes/chat-stream.test.d.ts +6 -0
  193. package/dist/src/routes/chat-stream.test.js +155 -0
  194. package/dist/src/routes/chat-stream.test.js.map +1 -0
  195. package/dist/src/routes/chat.d.ts +13 -0
  196. package/dist/src/routes/chat.js +55 -0
  197. package/dist/src/routes/chat.js.map +1 -0
  198. package/dist/src/routes/chat.test.d.ts +6 -0
  199. package/dist/src/routes/chat.test.js +99 -0
  200. package/dist/src/routes/chat.test.js.map +1 -0
  201. package/dist/src/routes/health.d.ts +13 -0
  202. package/dist/src/routes/health.js +23 -0
  203. package/dist/src/routes/health.js.map +1 -0
  204. package/dist/src/routes/health.test.d.ts +6 -0
  205. package/dist/src/routes/health.test.js +45 -0
  206. package/dist/src/routes/health.test.js.map +1 -0
  207. package/dist/src/routes/sessions.d.ts +14 -0
  208. package/dist/src/routes/sessions.js +82 -0
  209. package/dist/src/routes/sessions.js.map +1 -0
  210. package/dist/src/routes/webhooks.d.ts +13 -0
  211. package/dist/src/routes/webhooks.js +43 -0
  212. package/dist/src/routes/webhooks.js.map +1 -0
  213. package/dist/src/routes/webhooks.test.d.ts +6 -0
  214. package/dist/src/routes/webhooks.test.js +80 -0
  215. package/dist/src/routes/webhooks.test.js.map +1 -0
  216. package/dist/src/routes/widget-actions.d.ts +49 -0
  217. package/dist/src/routes/widget-actions.js +78 -0
  218. package/dist/src/routes/widget-actions.js.map +1 -0
  219. package/dist/src/server.d.ts +31 -0
  220. package/dist/src/server.js +129 -0
  221. package/dist/src/server.js.map +1 -0
  222. package/dist/src/server.test.d.ts +6 -0
  223. package/dist/src/server.test.js +153 -0
  224. package/dist/src/server.test.js.map +1 -0
  225. package/dist/src/session/history-converter.d.ts +21 -0
  226. package/dist/src/session/history-converter.js +59 -0
  227. package/dist/src/session/history-converter.js.map +1 -0
  228. package/dist/src/session/history-converter.test.d.ts +6 -0
  229. package/dist/src/session/history-converter.test.js +130 -0
  230. package/dist/src/session/history-converter.test.js.map +1 -0
  231. package/dist/src/session/session-manager.d.ts +117 -0
  232. package/dist/src/session/session-manager.js +480 -0
  233. package/dist/src/session/session-manager.js.map +1 -0
  234. package/dist/src/session/session-manager.test.d.ts +6 -0
  235. package/dist/src/session/session-manager.test.js +586 -0
  236. package/dist/src/session/session-manager.test.js.map +1 -0
  237. package/dist/src/session/session-runner.d.ts +30 -0
  238. package/dist/src/session/session-runner.js +771 -0
  239. package/dist/src/session/session-runner.js.map +1 -0
  240. package/dist/src/session/session-runner.test.d.ts +6 -0
  241. package/dist/src/session/session-runner.test.js +842 -0
  242. package/dist/src/session/session-runner.test.js.map +1 -0
  243. package/dist/src/stores/index.d.ts +8 -0
  244. package/dist/src/stores/index.js +9 -0
  245. package/dist/src/stores/index.js.map +1 -0
  246. package/dist/src/stores/key-resolver.d.ts +21 -0
  247. package/dist/src/stores/key-resolver.js +30 -0
  248. package/dist/src/stores/key-resolver.js.map +1 -0
  249. package/dist/src/stores/key-resolver.test.d.ts +6 -0
  250. package/dist/src/stores/key-resolver.test.js +31 -0
  251. package/dist/src/stores/key-resolver.test.js.map +1 -0
  252. package/dist/src/stores/pglite-store-backend.d.ts +36 -0
  253. package/dist/src/stores/pglite-store-backend.js +227 -0
  254. package/dist/src/stores/pglite-store-backend.js.map +1 -0
  255. package/dist/src/stores/pglite-store-backend.test.d.ts +6 -0
  256. package/dist/src/stores/pglite-store-backend.test.js +150 -0
  257. package/dist/src/stores/pglite-store-backend.test.js.map +1 -0
  258. package/dist/src/stores/ttl-resolver.d.ts +24 -0
  259. package/dist/src/stores/ttl-resolver.js +64 -0
  260. package/dist/src/stores/ttl-resolver.js.map +1 -0
  261. package/dist/src/stores/ttl-resolver.test.d.ts +6 -0
  262. package/dist/src/stores/ttl-resolver.test.js +68 -0
  263. package/dist/src/stores/ttl-resolver.test.js.map +1 -0
  264. package/dist/src/types.d.ts +227 -0
  265. package/dist/src/types.js +50 -0
  266. package/dist/src/types.js.map +1 -0
  267. package/dist/src/types.test.d.ts +6 -0
  268. package/dist/src/types.test.js +68 -0
  269. package/dist/src/types.test.js.map +1 -0
  270. package/dist/src/utils/jwt-verify.d.ts +20 -0
  271. package/dist/src/utils/jwt-verify.js +34 -0
  272. package/dist/src/utils/jwt-verify.js.map +1 -0
  273. package/dist/src/utils/jwt-verify.test.d.ts +6 -0
  274. package/dist/src/utils/jwt-verify.test.js +156 -0
  275. package/dist/src/utils/jwt-verify.test.js.map +1 -0
  276. package/dist/tsconfig.tsbuildinfo +1 -0
  277. package/package.json +51 -0
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ /**
8
+ * Creates routes for listing, starting, stopping, and triggering automations.
9
+ *
10
+ * GET /automations — list all registered automations
11
+ * POST /automations/:name/start — start a cron automation
12
+ * POST /automations/:name/stop — stop a running cron automation
13
+ * POST /automations/:name/run — manually trigger an automation
14
+ */
15
+ export function createAutomationRouter(options) {
16
+ const router = Router();
17
+ router.get('/automations', (_req, res) => {
18
+ const automations = options.runner.listAutomations();
19
+ res.json({ automations });
20
+ });
21
+ router.post('/automations/:name/start', (req, res) => {
22
+ const name = req.params['name'] ?? '';
23
+ const result = options.runner.startAutomation(name);
24
+ if (!result.success) {
25
+ res.status(400).json({ error: result.error });
26
+ return;
27
+ }
28
+ res.json({ status: 'started', automation: name });
29
+ });
30
+ router.post('/automations/:name/stop', (req, res) => {
31
+ const name = req.params['name'] ?? '';
32
+ const result = options.runner.stopAutomation(name);
33
+ if (!result.success) {
34
+ res.status(400).json({ error: result.error });
35
+ return;
36
+ }
37
+ res.json({ status: 'stopped', automation: name });
38
+ });
39
+ router.post('/automations/:name/run', async (req, res) => {
40
+ const name = req.params['name'] ?? '';
41
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Express body parsing
42
+ const payload = (req.body ?? {});
43
+ try {
44
+ const result = await options.runner.triggerAutomation(name, payload);
45
+ if (!result.success) {
46
+ res.status(404).json({ error: result.error });
47
+ return;
48
+ }
49
+ res.json({ status: 'triggered', automation: name });
50
+ }
51
+ catch (err) {
52
+ const msg = err instanceof Error ? err.message : String(err);
53
+ res.status(500).json({ error: msg });
54
+ }
55
+ });
56
+ return router;
57
+ }
58
+ //# sourceMappingURL=automations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automations.js","sourceRoot":"","sources":["../../../../src/agent/routes/automations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ export {};
@@ -0,0 +1,117 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { describe, it, expect, vi } from 'vitest';
7
+ import express from 'express';
8
+ import request from 'supertest';
9
+ import { createAutomationRouter } from './automations.js';
10
+ function makeMockRunner(overrides) {
11
+ return {
12
+ start: vi.fn(),
13
+ stop: vi.fn(),
14
+ startAutomation: vi.fn().mockReturnValue({ success: true }),
15
+ stopAutomation: vi.fn().mockReturnValue({ success: true }),
16
+ listAutomations: vi.fn().mockReturnValue([
17
+ { name: 'daily-check', title: 'Daily Check', schedule: '0 9 * * *', webhookTriggered: false, running: false },
18
+ { name: 'alert-handler', title: 'Alert Handler', webhookTriggered: true, running: true },
19
+ ]),
20
+ handleWebhook: vi.fn().mockResolvedValue({ matched: true }),
21
+ triggerAutomation: vi.fn().mockResolvedValue({ success: true }),
22
+ ...overrides,
23
+ };
24
+ }
25
+ function createApp(runner) {
26
+ const app = express();
27
+ app.use(express.json());
28
+ app.use(createAutomationRouter({ runner }));
29
+ return app;
30
+ }
31
+ describe('repo-automations routes', () => {
32
+ it('should list automations with running state', async () => {
33
+ const runner = makeMockRunner();
34
+ const app = createApp(runner);
35
+ const res = await request(app).get('/automations');
36
+ expect(res.status).toBe(200);
37
+ expect(res.body.automations).toHaveLength(2);
38
+ expect(res.body.automations[0].name).toBe('daily-check');
39
+ expect(res.body.automations[0].running).toBe(false);
40
+ expect(res.body.automations[1].running).toBe(true);
41
+ });
42
+ it('should start an automation', async () => {
43
+ const runner = makeMockRunner();
44
+ const app = createApp(runner);
45
+ const res = await request(app).post('/automations/daily-check/start');
46
+ expect(res.status).toBe(200);
47
+ expect(res.body.status).toBe('started');
48
+ expect(runner.startAutomation).toHaveBeenCalledWith('daily-check');
49
+ });
50
+ it('should return 400 when start fails', async () => {
51
+ const runner = makeMockRunner({
52
+ startAutomation: vi.fn().mockReturnValue({ success: false, error: 'Already running' }),
53
+ });
54
+ const app = createApp(runner);
55
+ const res = await request(app).post('/automations/daily-check/start');
56
+ expect(res.status).toBe(400);
57
+ expect(res.body.error).toBe('Already running');
58
+ });
59
+ it('should stop an automation', async () => {
60
+ const runner = makeMockRunner();
61
+ const app = createApp(runner);
62
+ const res = await request(app).post('/automations/daily-check/stop');
63
+ expect(res.status).toBe(200);
64
+ expect(res.body.status).toBe('stopped');
65
+ expect(runner.stopAutomation).toHaveBeenCalledWith('daily-check');
66
+ });
67
+ it('should return 400 when stop fails', async () => {
68
+ const runner = makeMockRunner({
69
+ stopAutomation: vi.fn().mockReturnValue({ success: false, error: 'Not running' }),
70
+ });
71
+ const app = createApp(runner);
72
+ const res = await request(app).post('/automations/daily-check/stop');
73
+ expect(res.status).toBe(400);
74
+ expect(res.body.error).toBe('Not running');
75
+ });
76
+ it('should trigger automation manually', async () => {
77
+ const runner = makeMockRunner();
78
+ const app = createApp(runner);
79
+ const res = await request(app)
80
+ .post('/automations/daily-check/run')
81
+ .send({});
82
+ expect(res.status).toBe(200);
83
+ expect(res.body.status).toBe('triggered');
84
+ expect(runner.triggerAutomation).toHaveBeenCalledWith('daily-check', {});
85
+ });
86
+ it('should return 404 for unknown automation', async () => {
87
+ const runner = makeMockRunner({
88
+ triggerAutomation: vi.fn().mockResolvedValue({ success: false, error: 'Not found' }),
89
+ });
90
+ const app = createApp(runner);
91
+ const res = await request(app)
92
+ .post('/automations/unknown/run')
93
+ .send({});
94
+ expect(res.status).toBe(404);
95
+ expect(res.body.error).toContain('Not found');
96
+ });
97
+ it('should pass payload to triggerAutomation', async () => {
98
+ const runner = makeMockRunner();
99
+ const app = createApp(runner);
100
+ await request(app)
101
+ .post('/automations/daily-check/run')
102
+ .send({ context: 'manual-trigger' });
103
+ expect(runner.triggerAutomation).toHaveBeenCalledWith('daily-check', { context: 'manual-trigger' });
104
+ });
105
+ it('should handle trigger errors', async () => {
106
+ const runner = makeMockRunner({
107
+ triggerAutomation: vi.fn().mockRejectedValue(new Error('Runtime failure')),
108
+ });
109
+ const app = createApp(runner);
110
+ const res = await request(app)
111
+ .post('/automations/daily-check/run')
112
+ .send({});
113
+ expect(res.status).toBe(500);
114
+ expect(res.body.error).toBe('Runtime failure');
115
+ });
116
+ });
117
+ //# sourceMappingURL=automations.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automations.test.js","sourceRoot":"","sources":["../../../../src/agent/routes/automations.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ import type { Request, Response } from 'express';
8
+ import type { AgentSession } from '../agent-types.js';
9
+ import type { AgentSessionManager } from '../session-manager.js';
10
+ /**
11
+ * Optional hook for customizing session creation.
12
+ * When provided, called instead of sessionManager.create().
13
+ * Receives the Express request and response (for auth context access).
14
+ */
15
+ export type SessionCreator = (req: Request, res: Response, tenantId: string, tenantToken?: string) => Promise<AgentSession>;
16
+ /**
17
+ * Optional hook for hydrating a session from external storage.
18
+ * Called when session_id is provided but not found in memory.
19
+ */
20
+ export type SessionHydrator = (req: Request, res: Response, sessionId: string, tenantId: string) => Promise<AgentSession | null>;
21
+ /**
22
+ * Optional hook called after each agent turn completes.
23
+ * Used by hosted runtime to persist conversation history.
24
+ */
25
+ export type TurnCompleteHandler = (session: AgentSession, req: Request, res: Response) => void;
26
+ export interface ChatRouterOptions {
27
+ sessionManager: AgentSessionManager;
28
+ /** Optional session creator hook — used by hosted runtime to inject tenant config from platform API */
29
+ sessionCreator?: SessionCreator;
30
+ /** Optional session hydrator — called when session_id not found in memory (e.g., load from platform API) */
31
+ sessionHydrator?: SessionHydrator;
32
+ /** Optional callback after each agent turn — used for persisting conversation history */
33
+ onTurnComplete?: TurnCompleteHandler;
34
+ }
35
+ export declare function createChatRouter(options: ChatRouterOptions): Router;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ import { AgentChatRequestSchema } from '../agent-types.js';
8
+ import { runAgentTurn } from '../agent-runner.js';
9
+ import { SSEEventType } from '../../types.js';
10
+ export function createChatRouter(options) {
11
+ const router = Router();
12
+ router.post('/chat', async (req, res) => {
13
+ const parsed = AgentChatRequestSchema.safeParse(req.body);
14
+ if (!parsed.success) {
15
+ res.status(400).json({
16
+ error: {
17
+ code: 'VALIDATION_ERROR',
18
+ message: parsed.error.message,
19
+ },
20
+ });
21
+ return;
22
+ }
23
+ const { message, session_id, tenant_id, tenant_token } = parsed.data;
24
+ // SSE headers
25
+ res.writeHead(200, {
26
+ 'Content-Type': 'text/event-stream',
27
+ 'Cache-Control': 'no-cache',
28
+ 'Connection': 'keep-alive',
29
+ });
30
+ // Get or create session
31
+ let session = session_id ? options.sessionManager.get(session_id) : undefined;
32
+ // Try hydration if session not in memory
33
+ if (!session && session_id && options.sessionHydrator) {
34
+ try {
35
+ session = await options.sessionHydrator(req, res, session_id, tenant_id) ?? undefined;
36
+ }
37
+ catch {
38
+ // Hydration failed — fall through to create new session
39
+ }
40
+ }
41
+ if (!session) {
42
+ try {
43
+ session = options.sessionCreator
44
+ ? await options.sessionCreator(req, res, tenant_id, tenant_token)
45
+ : await options.sessionManager.create(tenant_id, tenant_token);
46
+ }
47
+ catch (err) {
48
+ const errMsg = err instanceof Error ? err.message : String(err);
49
+ writeSSE(res, { type: SSEEventType.Error, message: errMsg, timestamp: ts() });
50
+ writeSSE(res, { type: SSEEventType.Done, timestamp: ts() });
51
+ res.end();
52
+ return;
53
+ }
54
+ }
55
+ // Send init event
56
+ writeSSE(res, { type: SSEEventType.Init, session_id: session.id, timestamp: ts() });
57
+ // Abort on client disconnect (use res, not req — req closes when body is consumed)
58
+ const controller = new AbortController();
59
+ res.on('close', () => controller.abort());
60
+ try {
61
+ for await (const event of runAgentTurn(session, message, controller.signal)) {
62
+ if (controller.signal.aborted)
63
+ break;
64
+ writeSSE(res, event);
65
+ }
66
+ }
67
+ catch (err) {
68
+ if (!controller.signal.aborted) {
69
+ const errMsg = err instanceof Error ? err.message : String(err);
70
+ writeSSE(res, { type: SSEEventType.Error, message: errMsg, timestamp: ts() });
71
+ writeSSE(res, { type: SSEEventType.Done, timestamp: ts() });
72
+ }
73
+ }
74
+ // Notify after turn completes (e.g., persist history)
75
+ if (options.onTurnComplete) {
76
+ options.onTurnComplete(session, req, res);
77
+ }
78
+ res.end();
79
+ });
80
+ return router;
81
+ }
82
+ function writeSSE(res, event) {
83
+ res.write(`data: ${JSON.stringify(event)}\n\n`);
84
+ }
85
+ function ts() {
86
+ return new Date().toISOString();
87
+ }
88
+ //# sourceMappingURL=chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../../src/agent/routes/chat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ export {};
@@ -0,0 +1,115 @@
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 { createChatRouter } from './chat.js';
10
+ // Mock agent-runner
11
+ vi.mock('../agent-runner.js', () => ({
12
+ runAgentTurn: vi.fn(async function* () {
13
+ yield { type: 'text_delta', content: 'Hello!', timestamp: new Date().toISOString() };
14
+ yield { type: 'done', timestamp: new Date().toISOString() };
15
+ }),
16
+ }));
17
+ function makeSessionManager() {
18
+ const sessions = new Map();
19
+ return {
20
+ size: 0,
21
+ create: vi.fn(async (tenantId) => {
22
+ const session = {
23
+ id: 'session-1',
24
+ tenantId,
25
+ runtime: { compiledContext: { systemPrompt: 'test' } },
26
+ conversationHistory: [],
27
+ createdAt: Date.now(),
28
+ lastAccessedAt: Date.now(),
29
+ planModeManager: {},
30
+ exploreConfig: {},
31
+ };
32
+ sessions.set(session.id, session);
33
+ return session;
34
+ }),
35
+ get: vi.fn((id) => sessions.get(id)),
36
+ destroy: vi.fn(),
37
+ cleanup: vi.fn(),
38
+ updateRepo: vi.fn(),
39
+ shutdown: vi.fn(),
40
+ };
41
+ }
42
+ function createTestApp(sessionManager) {
43
+ const app = express();
44
+ app.use(express.json());
45
+ app.use(createChatRouter({ sessionManager }));
46
+ return app;
47
+ }
48
+ describe('repo-chat route', () => {
49
+ let sessionManager;
50
+ beforeEach(() => {
51
+ sessionManager = makeSessionManager();
52
+ });
53
+ it('should reject invalid request body', async () => {
54
+ const app = createTestApp(sessionManager);
55
+ const res = await request(app).post('/chat').send({});
56
+ expect(res.status).toBe(400);
57
+ });
58
+ it('should reject missing tenant_id', async () => {
59
+ const app = createTestApp(sessionManager);
60
+ const res = await request(app).post('/chat').send({ message: 'hello' });
61
+ expect(res.status).toBe(400);
62
+ });
63
+ it('should return SSE events for valid request', async () => {
64
+ const app = createTestApp(sessionManager);
65
+ const res = await request(app)
66
+ .post('/chat')
67
+ .send({ message: 'hello', tenant_id: 'tenant-1' })
68
+ .set('Accept', 'text/event-stream');
69
+ expect(res.status).toBe(200);
70
+ expect(res.headers['content-type']).toContain('text/event-stream');
71
+ expect(res.text).toContain('data:');
72
+ });
73
+ it('should create a new session if no session_id', async () => {
74
+ const app = createTestApp(sessionManager);
75
+ await request(app)
76
+ .post('/chat')
77
+ .send({ message: 'hello', tenant_id: 'tenant-1' });
78
+ expect(sessionManager.create).toHaveBeenCalledWith('tenant-1', undefined);
79
+ });
80
+ it('should reuse existing session if session_id provided', async () => {
81
+ const app = createTestApp(sessionManager);
82
+ // Create a session first
83
+ await request(app)
84
+ .post('/chat')
85
+ .send({ message: 'hello', tenant_id: 'tenant-1' });
86
+ // Reuse it
87
+ await request(app)
88
+ .post('/chat')
89
+ .send({ message: 'follow up', tenant_id: 'tenant-1', session_id: 'session-1' });
90
+ expect(sessionManager.get).toHaveBeenCalledWith('session-1');
91
+ });
92
+ it('should include init event in response', async () => {
93
+ const app = createTestApp(sessionManager);
94
+ const res = await request(app)
95
+ .post('/chat')
96
+ .send({ message: 'hello', tenant_id: 'tenant-1' });
97
+ expect(res.text).toContain('"type":"init"');
98
+ });
99
+ it('should handle session creation failure', async () => {
100
+ sessionManager.create.mockRejectedValue(new Error('Setup failed'));
101
+ const app = createTestApp(sessionManager);
102
+ const res = await request(app)
103
+ .post('/chat')
104
+ .send({ message: 'hello', tenant_id: 'tenant-1' });
105
+ expect(res.text).toContain('"type":"error"');
106
+ });
107
+ it('should pass tenant_token when provided', async () => {
108
+ const app = createTestApp(sessionManager);
109
+ await request(app)
110
+ .post('/chat')
111
+ .send({ message: 'hello', tenant_id: 'tenant-1', tenant_token: 'tok-123' });
112
+ expect(sessionManager.create).toHaveBeenCalledWith('tenant-1', 'tok-123');
113
+ });
114
+ });
115
+ //# sourceMappingURL=chat.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.test.js","sourceRoot":"","sources":["../../../../src/agent/routes/chat.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ import type { AgentSessionManager } from '../session-manager.js';
8
+ export interface InspectRouterOptions {
9
+ sessionManager: AgentSessionManager;
10
+ repoPath: string;
11
+ }
12
+ export declare function createInspectRouter(options: InspectRouterOptions): Router;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ export function createInspectRouter(options) {
8
+ const router = Router();
9
+ router.get('/inspect/context', async (_req, res) => {
10
+ try {
11
+ // Create a temporary session to inspect the compiled context
12
+ const session = await options.sessionManager.create('__inspect__');
13
+ const runtime = session.runtime;
14
+ const compiled = runtime.compiledContext;
15
+ res.json({
16
+ repo_path: options.repoPath,
17
+ system_prompt_length: compiled.systemPrompt.length,
18
+ token_usage: compiled.tokenUsage,
19
+ sections: compiled.sections.map((s) => ({
20
+ name: s.name,
21
+ tokens: s.tokens,
22
+ priority: s.priority,
23
+ trimmed: s.trimmed,
24
+ })),
25
+ connections: Array.from(runtime.repo.connections.keys()),
26
+ skills: runtime.repo.skills.map((s) => s.name),
27
+ automations: runtime.repo.automations.map((a) => a.name),
28
+ knowledge: runtime.repo.knowledge.map((k) => k.name),
29
+ });
30
+ // Clean up the temporary session
31
+ options.sessionManager.destroy(session.id);
32
+ }
33
+ catch (err) {
34
+ const msg = err instanceof Error ? err.message : String(err);
35
+ res.status(500).json({ error: { code: 'INSPECT_FAILED', message: msg } });
36
+ }
37
+ });
38
+ return router;
39
+ }
40
+ //# sourceMappingURL=inspect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../../../src/agent/routes/inspect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,MAAM,EAAC,MAAM,SAAS,CAAC;AAS/B,MAAM,UAAU,mBAAmB,CAAC,OAA6B;IAC/D,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,kBAAkB,EAAE,KAAK,EAAE,IAAa,EAAE,GAAa,EAAE,EAAE;QACpE,IAAI,CAAC;YACH,6DAA6D;YAC7D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YAEnE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;YAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,eAAe,CAAC;YAEzC,GAAG,CAAC,IAAI,CAAC;gBACP,SAAS,EAAE,OAAO,CAAC,QAAQ;gBAC3B,oBAAoB,EAAE,QAAQ,CAAC,YAAY,CAAC,MAAM;gBAClD,WAAW,EAAE,QAAQ,CAAC,UAAU;gBAChC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACtC,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,MAAM,EAAE,CAAC,CAAC,MAAM;oBAChB,QAAQ,EAAE,CAAC,CAAC,QAAQ;oBACpB,OAAO,EAAE,CAAC,CAAC,OAAO;iBACnB,CAAC,CAAC;gBACH,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;gBACxD,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;gBAC9C,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;gBACxD,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;aACrD,CAAC,CAAC;YAEH,iCAAiC;YACjC,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAC,KAAK,EAAE,EAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,GAAG,EAAC,EAAC,CAAC,CAAC;QACxE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ export {};
@@ -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 { createInspectRouter } from './inspect.js';
10
+ function makeSessionManager() {
11
+ return {
12
+ size: 0,
13
+ create: vi.fn(async () => ({
14
+ id: 'inspect-session',
15
+ tenantId: '__inspect__',
16
+ runtime: {
17
+ compiledContext: {
18
+ systemPrompt: 'You are a test agent.',
19
+ tokenUsage: { total: 100000, used: 500, remaining: 99500, sectionBreakdown: { core: 200, skills: 300 } },
20
+ sections: [
21
+ { name: 'core', content: 'Core instructions', tokens: 200, priority: 10, trimmed: false },
22
+ { name: 'skills', content: 'Skill definitions', tokens: 300, priority: 5, trimmed: false },
23
+ ],
24
+ },
25
+ repo: {
26
+ connections: new Map([['crm', {}]]),
27
+ skills: [{ name: 'triage' }, { name: 'investigate' }],
28
+ automations: [{ name: 'daily-scan' }],
29
+ knowledge: [{ name: 'api-docs' }],
30
+ },
31
+ },
32
+ })),
33
+ destroy: vi.fn(),
34
+ get: vi.fn(),
35
+ cleanup: vi.fn(),
36
+ updateRepo: vi.fn(),
37
+ shutdown: vi.fn(),
38
+ };
39
+ }
40
+ function createTestApp(sessionManager) {
41
+ const app = express();
42
+ app.use(createInspectRouter({ sessionManager, repoPath: '/test/repo' }));
43
+ return app;
44
+ }
45
+ describe('repo-inspect route', () => {
46
+ let sessionManager;
47
+ beforeEach(() => {
48
+ sessionManager = makeSessionManager();
49
+ });
50
+ it('should return compiled context info', async () => {
51
+ const app = createTestApp(sessionManager);
52
+ const res = await request(app).get('/inspect/context');
53
+ expect(res.status).toBe(200);
54
+ expect(res.body).toHaveProperty('repo_path', '/test/repo');
55
+ expect(res.body['token_usage']).toEqual({
56
+ total: 100000,
57
+ used: 500,
58
+ remaining: 99500,
59
+ sectionBreakdown: { core: 200, skills: 300 },
60
+ });
61
+ expect(res.body['sections']).toHaveLength(2);
62
+ expect(res.body['connections']).toEqual(['crm']);
63
+ expect(res.body['skills']).toEqual(['triage', 'investigate']);
64
+ expect(res.body['automations']).toEqual(['daily-scan']);
65
+ expect(res.body['knowledge']).toEqual(['api-docs']);
66
+ });
67
+ it('should destroy temporary session after inspect', async () => {
68
+ const app = createTestApp(sessionManager);
69
+ await request(app).get('/inspect/context');
70
+ expect(sessionManager.destroy).toHaveBeenCalledWith('inspect-session');
71
+ });
72
+ it('should handle session creation errors', async () => {
73
+ sessionManager.create.mockRejectedValue(new Error('Config invalid'));
74
+ const app = createTestApp(sessionManager);
75
+ const res = await request(app).get('/inspect/context');
76
+ expect(res.status).toBe(500);
77
+ expect(res.body['error']['code']).toBe('INSPECT_FAILED');
78
+ });
79
+ });
80
+ //# sourceMappingURL=inspect.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect.test.js","sourceRoot":"","sources":["../../../../src/agent/routes/inspect.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ import type { AmodalRepo, StoreBackend } from '@amodalai/core';
8
+ export interface StoreRouterOptions {
9
+ repo: AmodalRepo;
10
+ storeBackend: StoreBackend;
11
+ tenantId: string;
12
+ }
13
+ /**
14
+ * Creates routes for reading store data directly (without going through the LLM).
15
+ *
16
+ * GET /api/stores — list store definitions with doc counts
17
+ * GET /api/stores/:name — list documents (filter, sort, limit, offset)
18
+ * GET /api/stores/:name/:key — get single document + version history
19
+ */
20
+ export declare function createStoresRouter(options: StoreRouterOptions): Router;