@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,121 @@
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 { fetchUserContext, _parseUserContextSpecForTesting as parseSpec } from './user-context-fetcher.js';
8
+ function makeRepo(userContext) {
9
+ return {
10
+ source: 'local',
11
+ origin: '/test',
12
+ config: {
13
+ name: 'test',
14
+ version: '1.0.0',
15
+ userContext,
16
+ models: {
17
+ main: { provider: 'anthropic', model: 'claude-sonnet-4-20250514' },
18
+ },
19
+ },
20
+ connections: new Map(),
21
+ skills: [],
22
+ agents: { subagents: [] },
23
+ automations: [],
24
+ knowledge: [],
25
+ evals: [],
26
+ tools: [],
27
+ stores: [],
28
+ };
29
+ }
30
+ describe('parseUserContextSpec', () => {
31
+ it('should parse "GET crm/users/me"', () => {
32
+ const result = parseSpec('GET crm/users/me');
33
+ expect(result).toEqual({
34
+ method: 'GET',
35
+ connection: 'crm',
36
+ path: '/users/me',
37
+ });
38
+ });
39
+ it('should parse "POST api/auth"', () => {
40
+ const result = parseSpec('POST api/auth');
41
+ expect(result).toEqual({
42
+ method: 'POST',
43
+ connection: 'api',
44
+ path: '/auth',
45
+ });
46
+ });
47
+ it('should handle connection with no path', () => {
48
+ const result = parseSpec('GET crm');
49
+ expect(result).toEqual({
50
+ method: 'GET',
51
+ connection: 'crm',
52
+ path: '/',
53
+ });
54
+ });
55
+ it('should return null for empty string', () => {
56
+ const result = parseSpec('');
57
+ expect(result).toBeNull();
58
+ });
59
+ it('should return null for single word', () => {
60
+ const result = parseSpec('GET');
61
+ expect(result).toBeNull();
62
+ });
63
+ });
64
+ describe('fetchUserContext', () => {
65
+ beforeEach(() => {
66
+ vi.restoreAllMocks();
67
+ });
68
+ it('should return empty object when no userContext configured', async () => {
69
+ const repo = makeRepo();
70
+ const result = await fetchUserContext(repo, 'token', {});
71
+ expect(result).toEqual({});
72
+ });
73
+ it('should return empty object when connection not found', async () => {
74
+ const repo = makeRepo('GET unknown/users/me');
75
+ const result = await fetchUserContext(repo, 'token', {});
76
+ expect(result).toEqual({});
77
+ });
78
+ it('should return empty object when base_url missing', async () => {
79
+ const repo = makeRepo('GET crm/users/me');
80
+ const connMap = {
81
+ crm: { no_base_url: true },
82
+ };
83
+ const result = await fetchUserContext(repo, 'token', connMap);
84
+ expect(result).toEqual({});
85
+ });
86
+ it('should fetch user context successfully', async () => {
87
+ const repo = makeRepo('GET crm/users/me');
88
+ const connMap = {
89
+ crm: { base_url: 'https://api.example.com' },
90
+ };
91
+ const mockResponse = { role: 'admin', name: 'Test User' };
92
+ vi.spyOn(globalThis, 'fetch').mockResolvedValue(new Response(JSON.stringify(mockResponse), { status: 200 }));
93
+ const result = await fetchUserContext(repo, 'my-token', connMap);
94
+ expect(result).toEqual(mockResponse);
95
+ expect(fetch).toHaveBeenCalledWith('https://api.example.com/users/me', expect.objectContaining({
96
+ method: 'GET',
97
+ headers: expect.objectContaining({
98
+ Authorization: 'Bearer my-token',
99
+ }),
100
+ }));
101
+ });
102
+ it('should return empty object on HTTP error', async () => {
103
+ const repo = makeRepo('GET crm/users/me');
104
+ const connMap = {
105
+ crm: { base_url: 'https://api.example.com' },
106
+ };
107
+ vi.spyOn(globalThis, 'fetch').mockResolvedValue(new Response('Not Found', { status: 404 }));
108
+ const result = await fetchUserContext(repo, 'token', connMap);
109
+ expect(result).toEqual({});
110
+ });
111
+ it('should return empty object on fetch error', async () => {
112
+ const repo = makeRepo('GET crm/users/me');
113
+ const connMap = {
114
+ crm: { base_url: 'https://api.example.com' },
115
+ };
116
+ vi.spyOn(globalThis, 'fetch').mockRejectedValue(new Error('Network error'));
117
+ const result = await fetchUserContext(repo, 'token', connMap);
118
+ expect(result).toEqual({});
119
+ });
120
+ });
121
+ //# sourceMappingURL=user-context-fetcher.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-context-fetcher.test.js","sourceRoot":"","sources":["../../../src/agent/user-context-fetcher.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ /**
7
+ * Batching HTTP client that posts audit entries to the platform API.
8
+ * Fire-and-forget — never blocks chat processing.
9
+ */
10
+ export interface AuditEntry {
11
+ event: string;
12
+ resource_name: string;
13
+ author?: string;
14
+ details?: Record<string, unknown>;
15
+ timestamp?: string;
16
+ }
17
+ export interface AuditClientOptions {
18
+ /** Platform API base URL */
19
+ platformApiUrl: string;
20
+ /** Flush interval in ms (default 2000) */
21
+ flushIntervalMs?: number;
22
+ /** Max batch size before auto-flush (default 20) */
23
+ maxBatchSize?: number;
24
+ }
25
+ export declare class AuditClient {
26
+ private readonly platformApiUrl;
27
+ private readonly flushIntervalMs;
28
+ private readonly maxBatchSize;
29
+ private readonly pending;
30
+ private flushTimer;
31
+ constructor(options: AuditClientOptions);
32
+ /**
33
+ * Queue an audit entry for batched delivery.
34
+ * Fire-and-forget — never throws.
35
+ */
36
+ log(appId: string, token: string, entry: AuditEntry): void;
37
+ /**
38
+ * Flush all pending batches immediately.
39
+ */
40
+ flush(): Promise<void>;
41
+ /**
42
+ * Stop the flush timer and drain remaining entries.
43
+ */
44
+ shutdown(): Promise<void>;
45
+ private send;
46
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ const DEFAULT_FLUSH_INTERVAL_MS = 2000;
7
+ const DEFAULT_MAX_BATCH_SIZE = 20;
8
+ export class AuditClient {
9
+ platformApiUrl;
10
+ flushIntervalMs;
11
+ maxBatchSize;
12
+ pending = new Map();
13
+ flushTimer = null;
14
+ constructor(options) {
15
+ this.platformApiUrl = options.platformApiUrl;
16
+ this.flushIntervalMs = options.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
17
+ this.maxBatchSize = options.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE;
18
+ this.flushTimer = setInterval(() => {
19
+ void this.flush();
20
+ }, this.flushIntervalMs);
21
+ this.flushTimer.unref();
22
+ }
23
+ /**
24
+ * Queue an audit entry for batched delivery.
25
+ * Fire-and-forget — never throws.
26
+ */
27
+ log(appId, token, entry) {
28
+ const key = `${appId}:${token}`;
29
+ let batch = this.pending.get(key);
30
+ if (!batch) {
31
+ batch = { appId, token, entries: [] };
32
+ this.pending.set(key, batch);
33
+ }
34
+ batch.entries.push({
35
+ ...entry,
36
+ timestamp: entry.timestamp ?? new Date().toISOString(),
37
+ });
38
+ if (batch.entries.length >= this.maxBatchSize) {
39
+ const toSend = batch;
40
+ this.pending.delete(key);
41
+ void this.send(toSend);
42
+ }
43
+ }
44
+ /**
45
+ * Flush all pending batches immediately.
46
+ */
47
+ async flush() {
48
+ const batches = [...this.pending.values()];
49
+ this.pending.clear();
50
+ await Promise.all(batches.map((b) => this.send(b)));
51
+ }
52
+ /**
53
+ * Stop the flush timer and drain remaining entries.
54
+ */
55
+ async shutdown() {
56
+ if (this.flushTimer) {
57
+ clearInterval(this.flushTimer);
58
+ this.flushTimer = null;
59
+ }
60
+ await this.flush();
61
+ }
62
+ async send(batch) {
63
+ try {
64
+ const controller = new AbortController();
65
+ const timer = setTimeout(() => controller.abort(), 10000);
66
+ await fetch(`${this.platformApiUrl}/api/applications/${batch.appId}/audit-logs`, {
67
+ method: 'POST',
68
+ signal: controller.signal,
69
+ headers: {
70
+ 'Content-Type': 'application/json',
71
+ Authorization: `Bearer ${batch.token}`,
72
+ },
73
+ body: JSON.stringify({ entries: batch.entries }),
74
+ });
75
+ clearTimeout(timer);
76
+ }
77
+ catch (err) {
78
+ // Fire-and-forget — log but don't throw
79
+ process.stderr.write(`[WARN] Failed to send audit batch: ${err instanceof Error ? err.message : String(err)}\n`);
80
+ }
81
+ }
82
+ }
83
+ //# sourceMappingURL=audit-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-client.js","sourceRoot":"","sources":["../../../src/audit/audit-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import type { AutomationDefinition } from '@amodalai/core';
7
+ import type { AutomationResult } from '../types.js';
8
+ import type { SessionManager } from '../session/session-manager.js';
9
+ import type { AuditClient } from '../audit/audit-client.js';
10
+ export type AutomationRunnerFn = (automation: AutomationDefinition, payload?: Record<string, unknown>) => Promise<AutomationResult>;
11
+ export interface AutomationRunnerOptions {
12
+ sessionManager: SessionManager;
13
+ auditClient?: AuditClient;
14
+ /** App ID for audit logging (e.g. from platform config) */
15
+ auditAppId?: string;
16
+ /** Auth token for audit logging */
17
+ auditToken?: string;
18
+ }
19
+ /**
20
+ * Create an automation runner function.
21
+ * Each invocation creates an ephemeral session, runs the prompt, routes output,
22
+ * and destroys the session.
23
+ */
24
+ export declare function createAutomationRunner(options: AutomationRunnerOptions): AutomationRunnerFn;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { runMessage } from '../session/session-runner.js';
7
+ import { routeOutput } from '../output/output-router.js';
8
+ /**
9
+ * Create an automation runner function.
10
+ * Each invocation creates an ephemeral session, runs the prompt, routes output,
11
+ * and destroys the session.
12
+ */
13
+ export function createAutomationRunner(options) {
14
+ return async (automation, payload) => {
15
+ const startTime = Date.now();
16
+ let session;
17
+ try {
18
+ session = await options.sessionManager.create();
19
+ }
20
+ catch (err) {
21
+ const message = err instanceof Error ? err.message : String(err);
22
+ process.stderr.write(`[ERROR] Automation "${automation.name}" failed to create session: ${message}\n`);
23
+ return {
24
+ automation: automation.name,
25
+ response: '',
26
+ tool_calls: [],
27
+ output_sent: false,
28
+ duration_ms: Date.now() - startTime,
29
+ };
30
+ }
31
+ // Build audit context if audit client is available
32
+ let audit;
33
+ if (options.auditClient && options.auditAppId && options.auditToken) {
34
+ audit = {
35
+ auditClient: options.auditClient,
36
+ appId: options.auditAppId,
37
+ token: options.auditToken,
38
+ };
39
+ }
40
+ try {
41
+ // Build prompt — optionally include payload data
42
+ let prompt = automation.prompt;
43
+ if (payload && Object.keys(payload).length > 0) {
44
+ prompt += `\n\nEvent data: ${JSON.stringify(payload)}`;
45
+ }
46
+ // Set up timeout if constraints specify one
47
+ const controller = new AbortController();
48
+ let timeoutId;
49
+ if (automation.constraints?.timeout_seconds) {
50
+ timeoutId = setTimeout(() => controller.abort(), automation.constraints.timeout_seconds * 1000);
51
+ }
52
+ try {
53
+ const result = await runMessage(session, prompt, controller.signal, audit);
54
+ const automationResult = {
55
+ automation: automation.name,
56
+ response: result.response,
57
+ tool_calls: result.tool_calls,
58
+ output_sent: false,
59
+ duration_ms: Date.now() - startTime,
60
+ };
61
+ // Route output
62
+ const outputSent = await routeOutput(automation.output, automationResult);
63
+ automationResult.output_sent = outputSent;
64
+ return automationResult;
65
+ }
66
+ finally {
67
+ if (timeoutId)
68
+ clearTimeout(timeoutId);
69
+ }
70
+ }
71
+ catch (err) {
72
+ const message = err instanceof Error ? err.message : String(err);
73
+ process.stderr.write(`[ERROR] Automation "${automation.name}" failed: ${message}\n`);
74
+ return {
75
+ automation: automation.name,
76
+ response: '',
77
+ tool_calls: [],
78
+ output_sent: false,
79
+ duration_ms: Date.now() - startTime,
80
+ };
81
+ }
82
+ finally {
83
+ await options.sessionManager.destroy(session.id);
84
+ }
85
+ };
86
+ }
87
+ //# sourceMappingURL=heartbeat-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat-runner.js","sourceRoot":"","sources":["../../../src/cron/heartbeat-runner.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,120 @@
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
+ // Mock dependencies
8
+ const mockRunMessage = vi.fn();
9
+ vi.mock('../session/session-runner.js', () => ({
10
+ runMessage: (...args) => mockRunMessage(...args),
11
+ }));
12
+ const mockRouteOutput = vi.fn();
13
+ vi.mock('../output/output-router.js', () => ({
14
+ routeOutput: (...args) => mockRouteOutput(...args),
15
+ }));
16
+ const { createAutomationRunner } = await import('./heartbeat-runner.js');
17
+ function makeAutomation(overrides = {}) {
18
+ return {
19
+ name: 'zone-monitor',
20
+ trigger: { type: 'cron', schedule: '*/5 * * * *' },
21
+ prompt: 'Check all zones.',
22
+ tools: ['get_zone_overview'],
23
+ skills: ['*'],
24
+ output: { channel: 'slack', target: 'https://hooks.slack.com/abc' },
25
+ allow_writes: false,
26
+ ...overrides,
27
+ };
28
+ }
29
+ describe('createAutomationRunner', () => {
30
+ const mockCreate = vi.fn();
31
+ const mockDestroy = vi.fn();
32
+ beforeEach(() => {
33
+ vi.clearAllMocks();
34
+ mockCreate.mockResolvedValue({
35
+ id: 'hb-sess-1',
36
+ config: {},
37
+ geminiClient: {},
38
+ scheduler: {},
39
+ });
40
+ mockDestroy.mockResolvedValue(undefined);
41
+ mockRunMessage.mockResolvedValue({
42
+ session_id: 'hb-sess-1',
43
+ response: 'All clear.',
44
+ tool_calls: [],
45
+ });
46
+ mockRouteOutput.mockResolvedValue(true);
47
+ });
48
+ function makeRunner() {
49
+ return createAutomationRunner({
50
+ sessionManager: {
51
+ create: mockCreate,
52
+ destroy: mockDestroy,
53
+ },
54
+ });
55
+ }
56
+ it('creates session, runs prompt, routes output, and destroys session', async () => {
57
+ const runner = makeRunner();
58
+ const result = await runner(makeAutomation());
59
+ expect(mockCreate).toHaveBeenCalledOnce();
60
+ expect(mockRunMessage).toHaveBeenCalledOnce();
61
+ expect(mockRouteOutput).toHaveBeenCalledOnce();
62
+ expect(mockDestroy).toHaveBeenCalledWith('hb-sess-1');
63
+ expect(result.automation).toBe('zone-monitor');
64
+ expect(result.response).toBe('All clear.');
65
+ expect(result.output_sent).toBe(true);
66
+ expect(result.duration_ms).toBeGreaterThanOrEqual(0);
67
+ });
68
+ it('includes payload data in prompt', async () => {
69
+ const runner = makeRunner();
70
+ await runner(makeAutomation(), { device_id: '42' });
71
+ const promptArg = mockRunMessage.mock.calls[0][1];
72
+ expect(promptArg).toContain('Check all zones.');
73
+ expect(promptArg).toContain('device_id');
74
+ expect(promptArg).toContain('42');
75
+ });
76
+ it('handles session creation failure gracefully', async () => {
77
+ mockCreate.mockRejectedValue(new Error('config error'));
78
+ vi.spyOn(process.stderr, 'write').mockReturnValue(true);
79
+ const runner = makeRunner();
80
+ const result = await runner(makeAutomation());
81
+ expect(result.automation).toBe('zone-monitor');
82
+ expect(result.response).toBe('');
83
+ expect(result.output_sent).toBe(false);
84
+ });
85
+ it('handles runMessage failure gracefully', async () => {
86
+ mockRunMessage.mockRejectedValue(new Error('LLM error'));
87
+ vi.spyOn(process.stderr, 'write').mockReturnValue(true);
88
+ const runner = makeRunner();
89
+ const result = await runner(makeAutomation());
90
+ expect(result.response).toBe('');
91
+ expect(result.output_sent).toBe(false);
92
+ expect(mockDestroy).toHaveBeenCalledOnce(); // Still cleans up
93
+ });
94
+ it('handles output routing failure gracefully', async () => {
95
+ mockRouteOutput.mockResolvedValue(false);
96
+ const runner = makeRunner();
97
+ const result = await runner(makeAutomation());
98
+ expect(result.output_sent).toBe(false);
99
+ expect(result.response).toBe('All clear.'); // Still has response
100
+ });
101
+ it('destroys session even on error', async () => {
102
+ mockRunMessage.mockRejectedValue(new Error('boom'));
103
+ vi.spyOn(process.stderr, 'write').mockReturnValue(true);
104
+ const runner = makeRunner();
105
+ await runner(makeAutomation());
106
+ expect(mockDestroy).toHaveBeenCalledWith('hb-sess-1');
107
+ });
108
+ it('respects timeout constraint', async () => {
109
+ // Create a slow runMessage
110
+ mockRunMessage.mockImplementation(() => new Promise((resolve) => setTimeout(resolve, 100)));
111
+ const runner = makeRunner();
112
+ const automation = makeAutomation({
113
+ constraints: { timeout_seconds: 1 },
114
+ });
115
+ // This should still complete (1s timeout > 100ms)
116
+ await runner(automation);
117
+ expect(mockRunMessage).toHaveBeenCalledOnce();
118
+ });
119
+ });
120
+ //# sourceMappingURL=heartbeat-runner.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat-runner.test.js","sourceRoot":"","sources":["../../../src/cron/heartbeat-runner.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import type { AutomationDefinition } from '@amodalai/core';
7
+ import type { AutomationRunnerFn } from './heartbeat-runner.js';
8
+ /**
9
+ * Registers in-process cron jobs from automation definitions.
10
+ * Only registers automations with trigger type "cron".
11
+ */
12
+ export declare class AutomationScheduler {
13
+ private readonly jobs;
14
+ /**
15
+ * Register cron automations and start them.
16
+ */
17
+ start(automations: AutomationDefinition[], runAutomation: AutomationRunnerFn): void;
18
+ /**
19
+ * Stop all scheduled cron jobs.
20
+ */
21
+ stop(): void;
22
+ /**
23
+ * Number of registered cron jobs.
24
+ */
25
+ get size(): number;
26
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import cron from 'node-cron';
7
+ /**
8
+ * Registers in-process cron jobs from automation definitions.
9
+ * Only registers automations with trigger type "cron".
10
+ */
11
+ export class AutomationScheduler {
12
+ jobs = [];
13
+ /**
14
+ * Register cron automations and start them.
15
+ */
16
+ start(automations, runAutomation) {
17
+ const cronAutomations = automations.filter((a) => a.trigger.type === 'cron');
18
+ for (const a of cronAutomations) {
19
+ if (a.trigger.type !== 'cron')
20
+ continue;
21
+ const schedule = a.trigger.schedule;
22
+ if (!cron.validate(schedule)) {
23
+ process.stderr.write(`[WARN] Invalid cron schedule for automation "${a.name}": ${schedule}\n`);
24
+ continue;
25
+ }
26
+ const task = cron.schedule(schedule, () => {
27
+ void runAutomation(a).catch((err) => {
28
+ const message = err instanceof Error ? err.message : String(err);
29
+ process.stderr.write(`[ERROR] Cron automation "${a.name}" failed: ${message}\n`);
30
+ });
31
+ });
32
+ this.jobs.push({ automation: a, task });
33
+ }
34
+ if (this.jobs.length > 0) {
35
+ process.stderr.write(`[INFO] Registered ${this.jobs.length} cron automation(s)\n`);
36
+ }
37
+ }
38
+ /**
39
+ * Stop all scheduled cron jobs.
40
+ */
41
+ stop() {
42
+ for (const job of this.jobs) {
43
+ job.task.stop();
44
+ }
45
+ this.jobs.length = 0;
46
+ }
47
+ /**
48
+ * Number of registered cron jobs.
49
+ */
50
+ get size() {
51
+ return this.jobs.length;
52
+ }
53
+ }
54
+ //# sourceMappingURL=heartbeat-scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat-scheduler.js","sourceRoot":"","sources":["../../../src/cron/heartbeat-scheduler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAS7B;;;GAGG;AACH,MAAM,OAAO,mBAAmB;IACb,IAAI,GAAmB,EAAE,CAAC;IAE3C;;OAEG;IACH,KAAK,CACH,WAAmC,EACnC,aAAiC;QAEjC,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,CACxC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,CACjC,CAAC;QAEF,KAAK,MAAM,CAAC,IAAI,eAAe,EAAE,CAAC;YAChC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM;gBAAE,SAAS;YAExC,MAAM,QAAQ,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gDAAgD,CAAC,CAAC,IAAI,MAAM,QAAQ,IAAI,CACzE,CAAC;gBACF,SAAS;YACX,CAAC;YAED,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;gBACxC,KAAK,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;oBAC3C,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,4BAA4B,CAAC,CAAC,IAAI,aAAa,OAAO,IAAI,CAC3D,CAAC;gBACJ,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,qBAAqB,IAAI,CAAC,IAAI,CAAC,MAAM,uBAAuB,CAC7D,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,IAAI;QACF,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IAC1B,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ export {};