@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,152 @@
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 { buildToolContext } from './tool-context-builder.js';
8
+ // Mock the request-helper module
9
+ const { mockMakeApiRequest } = vi.hoisted(() => ({
10
+ mockMakeApiRequest: vi.fn().mockResolvedValue({ output: '{"ok":true}' }),
11
+ }));
12
+ vi.mock('./request-helper.js', () => ({
13
+ makeApiRequest: mockMakeApiRequest,
14
+ }));
15
+ function makeTool(overrides = {}) {
16
+ return {
17
+ name: 'test_tool',
18
+ description: 'Test tool',
19
+ parameters: {},
20
+ confirm: false,
21
+ timeout: 5000,
22
+ env: ['ALLOWED_KEY'],
23
+ handlerPath: '/tmp/handler.ts',
24
+ location: '/tmp',
25
+ hasPackageJson: false,
26
+ hasDockerfile: false,
27
+ hasSetupScript: false,
28
+ hasRequirementsTxt: false,
29
+ sandboxLanguage: 'typescript',
30
+ ...overrides,
31
+ };
32
+ }
33
+ function makeSession() {
34
+ return {
35
+ id: 'test-session',
36
+ runtime: {
37
+ repo: {
38
+ config: { name: 'test', version: '1.0.0', models: { main: { provider: 'anthropic', model: 'test' } } },
39
+ connections: new Map(),
40
+ skills: [],
41
+ agents: {},
42
+ automations: [],
43
+ knowledge: [],
44
+ evals: [],
45
+ tools: [],
46
+ },
47
+ connectionsMap: {},
48
+ userRoles: ['analyst'],
49
+ fieldScrubber: null,
50
+ telemetry: { logScrub: vi.fn() },
51
+ actionGate: { evaluate: vi.fn() },
52
+ outputPipeline: { process: vi.fn() },
53
+ compiledContext: { systemPrompt: '', tokenUsage: { total: 0, used: 0, remaining: 0, sectionBreakdown: {} }, sections: [] },
54
+ },
55
+ tenantId: 'test-tenant',
56
+ conversationHistory: [],
57
+ createdAt: Date.now(),
58
+ lastAccessedAt: Date.now(),
59
+ planModeManager: { isActive: vi.fn(() => false), enter: vi.fn(), exit: vi.fn(), getPlanningReminder: vi.fn(), getApprovedPlanContext: vi.fn() },
60
+ exploreConfig: { model: { provider: 'anthropic', model: 'test' }, maxTurns: 5, maxDepth: 2, systemPrompt: '' },
61
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
+ };
63
+ }
64
+ describe('buildToolContext', () => {
65
+ const signal = AbortSignal.timeout(10000);
66
+ beforeEach(() => {
67
+ vi.clearAllMocks();
68
+ });
69
+ it('provides user roles', () => {
70
+ const session = makeSession();
71
+ const ctx = buildToolContext(session, makeTool(), signal);
72
+ expect(ctx.user.roles).toEqual(['analyst']);
73
+ });
74
+ it('provides env() that respects allowlist', () => {
75
+ process.env['ALLOWED_KEY'] = 'secret-value';
76
+ process.env['BLOCKED_KEY'] = 'blocked-value';
77
+ const ctx = buildToolContext(makeSession(), makeTool(), signal);
78
+ expect(ctx.env('ALLOWED_KEY')).toBe('secret-value');
79
+ expect(ctx.env('BLOCKED_KEY')).toBeUndefined();
80
+ delete process.env['ALLOWED_KEY'];
81
+ delete process.env['BLOCKED_KEY'];
82
+ });
83
+ it('provides log() that writes to stderr', () => {
84
+ const stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true);
85
+ const ctx = buildToolContext(makeSession(), makeTool(), signal);
86
+ ctx.log('hello world');
87
+ expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining('hello world'));
88
+ stderrSpy.mockRestore();
89
+ });
90
+ it('provides an abort signal', () => {
91
+ const ctx = buildToolContext(makeSession(), makeTool(), signal);
92
+ expect(ctx.signal).toBeDefined();
93
+ expect(ctx.signal.aborted).toBe(false);
94
+ });
95
+ it('rejects non-GET requests when confirm is false', async () => {
96
+ const ctx = buildToolContext(makeSession(), makeTool({ confirm: false }), signal);
97
+ await expect(ctx.request('crm', '/deals', { method: 'POST' })).rejects.toThrow(/only GET requests are allowed/);
98
+ });
99
+ it('allows non-GET requests when confirm is true', async () => {
100
+ mockMakeApiRequest.mockResolvedValueOnce({ output: '{"ok":true}' });
101
+ const ctx = buildToolContext(makeSession(), makeTool({ confirm: true }), signal);
102
+ const result = await ctx.request('crm', '/deals', { method: 'POST' });
103
+ expect(result).toEqual({ ok: true });
104
+ expect(mockMakeApiRequest).toHaveBeenCalledOnce();
105
+ });
106
+ it('allows GET requests when confirm is false', async () => {
107
+ mockMakeApiRequest.mockResolvedValueOnce({ output: '{"ok":true}' });
108
+ const ctx = buildToolContext(makeSession(), makeTool({ confirm: false }), signal);
109
+ const result = await ctx.request('crm', '/deals');
110
+ expect(result).toEqual({ ok: true });
111
+ expect(mockMakeApiRequest).toHaveBeenCalledOnce();
112
+ });
113
+ it('provides exec() that runs shell commands', async () => {
114
+ const ctx = buildToolContext(makeSession(), makeTool(), signal);
115
+ const result = await ctx.exec('echo "hello from exec"');
116
+ expect(result.exitCode).toBe(0);
117
+ expect(result.stdout.trim()).toBe('hello from exec');
118
+ });
119
+ it('exec() captures non-zero exit codes', async () => {
120
+ const ctx = buildToolContext(makeSession(), makeTool(), signal);
121
+ const result = await ctx.exec('exit 42');
122
+ expect(result.exitCode).toBe(42);
123
+ });
124
+ it('exec() uses tool location as default cwd', async () => {
125
+ const ctx = buildToolContext(makeSession(), makeTool({ location: '/tmp' }), signal);
126
+ const result = await ctx.exec('pwd');
127
+ // macOS: /tmp is a symlink to /private/tmp
128
+ expect(result.stdout.trim()).toMatch(/\/?tmp$/);
129
+ });
130
+ it('exec() delegates to session.shellExecutor when present', async () => {
131
+ const mockShellExecutor = {
132
+ exec: vi.fn().mockResolvedValue({ stdout: 'sandbox output', stderr: '', exitCode: 0 }),
133
+ };
134
+ const session = makeSession();
135
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
136
+ session.shellExecutor = mockShellExecutor;
137
+ const ctx = buildToolContext(session, makeTool(), signal);
138
+ const result = await ctx.exec('echo hello');
139
+ expect(result.stdout).toBe('sandbox output');
140
+ expect(result.exitCode).toBe(0);
141
+ expect(mockShellExecutor.exec).toHaveBeenCalledWith('echo hello', 5000, expect.any(AbortSignal));
142
+ });
143
+ it('exec() falls back to local when no shellExecutor', async () => {
144
+ const session = makeSession();
145
+ // No shellExecutor set
146
+ const ctx = buildToolContext(session, makeTool(), signal);
147
+ const result = await ctx.exec('echo "local fallback"');
148
+ expect(result.exitCode).toBe(0);
149
+ expect(result.stdout.trim()).toBe('local fallback');
150
+ });
151
+ });
152
+ //# sourceMappingURL=tool-context-builder.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-context-builder.test.js","sourceRoot":"","sources":["../../../src/agent/tool-context-builder.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import type { CustomToolExecutor, CustomToolContext, LoadedTool } from '@amodalai/core';
7
+ /**
8
+ * Executes custom tool handlers locally via dynamic import.
9
+ */
10
+ export declare class LocalToolExecutor implements CustomToolExecutor {
11
+ private readonly handlerCache;
12
+ execute(tool: LoadedTool, params: Record<string, unknown>, ctx: CustomToolContext): Promise<unknown>;
13
+ dispose(): void;
14
+ private loadHandler;
15
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { pathToFileURL } from 'node:url';
7
+ /**
8
+ * Executes custom tool handlers locally via dynamic import.
9
+ */
10
+ export class LocalToolExecutor {
11
+ handlerCache = new Map();
12
+ async execute(tool, params, ctx) {
13
+ try {
14
+ const handler = await this.loadHandler(tool);
15
+ const fn = resolveHandlerFn(handler, tool.name);
16
+ const result = await fn(params, ctx);
17
+ // Wrap non-object results
18
+ if (result === null || result === undefined) {
19
+ return { result: null };
20
+ }
21
+ if (typeof result !== 'object' || Array.isArray(result)) {
22
+ return { result };
23
+ }
24
+ return result;
25
+ }
26
+ catch (err) {
27
+ if (ctx.signal.aborted) {
28
+ return { error: 'Tool execution aborted' };
29
+ }
30
+ const message = err instanceof Error ? err.message : String(err);
31
+ return { error: message };
32
+ }
33
+ }
34
+ dispose() {
35
+ this.handlerCache.clear();
36
+ }
37
+ async loadHandler(tool) {
38
+ const cached = this.handlerCache.get(tool.handlerPath);
39
+ if (cached) {
40
+ return cached;
41
+ }
42
+ const moduleUrl = pathToFileURL(tool.handlerPath).href;
43
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- dynamic import returns unknown
44
+ const mod = await import(moduleUrl);
45
+ if (typeof mod.default !== 'function' && !isDefineToolResult(mod.default)) {
46
+ throw new Error(`Tool "${tool.name}" handler must export a default function or use defineToolHandler()`);
47
+ }
48
+ this.handlerCache.set(tool.handlerPath, mod);
49
+ return mod;
50
+ }
51
+ }
52
+ /**
53
+ * Check if a default export is a defineToolHandler result.
54
+ */
55
+ function isDefineToolResult(value) {
56
+ return (typeof value === 'object' &&
57
+ value !== null &&
58
+ '__toolHandler' in value &&
59
+ value['__toolHandler'] === true);
60
+ }
61
+ /**
62
+ * Resolve the actual handler function from a module's default export.
63
+ * Handles both plain functions and defineToolHandler results.
64
+ */
65
+ function resolveHandlerFn(mod, toolName) {
66
+ if (typeof mod.default === 'function') {
67
+ return mod.default;
68
+ }
69
+ if (isDefineToolResult(mod.default)) {
70
+ return mod.default.handler;
71
+ }
72
+ throw new Error(`Tool "${toolName}" handler must export a default function or use defineToolHandler()`);
73
+ }
74
+ //# sourceMappingURL=tool-executor-local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-executor-local.js","sourceRoot":"","sources":["../../../src/agent/tool-executor-local.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,116 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
7
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ import { tmpdir } from 'node:os';
10
+ import { LocalToolExecutor } from './tool-executor-local.js';
11
+ describe('LocalToolExecutor', () => {
12
+ let tempDir;
13
+ let executor;
14
+ beforeEach(() => {
15
+ tempDir = mkdtempSync(join(tmpdir(), 'tool-executor-test-'));
16
+ executor = new LocalToolExecutor();
17
+ });
18
+ afterEach(() => {
19
+ executor.dispose();
20
+ rmSync(tempDir, { recursive: true, force: true });
21
+ });
22
+ function createHandler(name, code) {
23
+ const handlerDir = join(tempDir, name);
24
+ mkdirSync(handlerDir, { recursive: true });
25
+ // Write as .mjs so dynamic import works without TS compilation
26
+ const handlerPath = join(handlerDir, 'handler.mjs');
27
+ writeFileSync(handlerPath, code);
28
+ return handlerPath;
29
+ }
30
+ function makeTool(handlerPath, overrides = {}) {
31
+ return {
32
+ name: 'test_tool',
33
+ description: 'Test tool',
34
+ parameters: {},
35
+ confirm: false,
36
+ timeout: 5000,
37
+ env: [],
38
+ handlerPath,
39
+ location: tempDir,
40
+ hasPackageJson: false,
41
+ hasDockerfile: false,
42
+ hasSetupScript: false,
43
+ hasRequirementsTxt: false,
44
+ sandboxLanguage: 'typescript',
45
+ ...overrides,
46
+ };
47
+ }
48
+ function makeCtx() {
49
+ return {
50
+ exec: async () => ({ stdout: '', stderr: '', exitCode: 0 }),
51
+ request: async () => ({}),
52
+ env: () => undefined,
53
+ log: () => { },
54
+ user: { roles: [] },
55
+ signal: AbortSignal.timeout(10000),
56
+ };
57
+ }
58
+ it('executes a handler that returns an object', async () => {
59
+ const handlerPath = createHandler('obj-handler', 'export default async (params) => ({ value: params.x * 2 });');
60
+ const tool = makeTool(handlerPath);
61
+ const result = await executor.execute(tool, { x: 5 }, makeCtx());
62
+ expect(result).toEqual({ value: 10 });
63
+ });
64
+ it('wraps non-object return values', async () => {
65
+ const handlerPath = createHandler('num-handler', 'export default async () => 42;');
66
+ const tool = makeTool(handlerPath);
67
+ const result = await executor.execute(tool, {}, makeCtx());
68
+ expect(result).toEqual({ result: 42 });
69
+ });
70
+ it('wraps null return values', async () => {
71
+ const handlerPath = createHandler('null-handler', 'export default async () => null;');
72
+ const tool = makeTool(handlerPath);
73
+ const result = await executor.execute(tool, {}, makeCtx());
74
+ expect(result).toEqual({ result: null });
75
+ });
76
+ it('wraps array return values', async () => {
77
+ const handlerPath = createHandler('arr-handler', 'export default async () => [1, 2, 3];');
78
+ const tool = makeTool(handlerPath);
79
+ const result = await executor.execute(tool, {}, makeCtx());
80
+ expect(result).toEqual({ result: [1, 2, 3] });
81
+ });
82
+ it('catches handler errors', async () => {
83
+ const handlerPath = createHandler('err-handler', 'export default async () => { throw new Error("boom"); };');
84
+ const tool = makeTool(handlerPath);
85
+ const result = await executor.execute(tool, {}, makeCtx());
86
+ expect(result).toEqual({ error: 'boom' });
87
+ });
88
+ it('caches imported modules', async () => {
89
+ const handlerPath = createHandler('cache-handler', 'let count = 0; export default async () => ({ count: ++count });');
90
+ const tool = makeTool(handlerPath);
91
+ const ctx = makeCtx();
92
+ const r1 = await executor.execute(tool, {}, ctx);
93
+ const r2 = await executor.execute(tool, {}, ctx);
94
+ // Both calls use the same module (count increments)
95
+ expect(r1).toEqual({ count: 1 });
96
+ expect(r2).toEqual({ count: 2 });
97
+ });
98
+ it('clears cache on dispose', async () => {
99
+ const handlerPath = createHandler('dispose-handler', 'export default async () => ({ ok: true });');
100
+ const tool = makeTool(handlerPath);
101
+ await executor.execute(tool, {}, makeCtx());
102
+ executor.dispose();
103
+ // After dispose, a new executor needs to reimport
104
+ const executor2 = new LocalToolExecutor();
105
+ const result = await executor2.execute(tool, {}, makeCtx());
106
+ expect(result).toEqual({ ok: true });
107
+ executor2.dispose();
108
+ });
109
+ it('throws for handler without default export', async () => {
110
+ const handlerPath = createHandler('no-default', 'export const handler = async () => ({});');
111
+ const tool = makeTool(handlerPath);
112
+ const result = await executor.execute(tool, {}, makeCtx());
113
+ expect(result).toHaveProperty('error');
114
+ });
115
+ });
116
+ //# sourceMappingURL=tool-executor-local.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-executor-local.test.js","sourceRoot":"","sources":["../../../src/agent/tool-executor-local.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ /**
7
+ * Generates the entry.js content for a sandbox tool wrapper.
8
+ *
9
+ * This script runs inside a Daytona sandbox workspace:
10
+ * 1. Reads invocation payload from /tmp/invocation.json
11
+ * 2. Imports the tool handler
12
+ * 3. Creates a proxy ToolContext (where request() and exec() delegate to the host)
13
+ * 4. Executes the handler
14
+ * 5. Writes JSON result to stdout
15
+ */
16
+ export declare function generateToolHarnessEntry(handlerRelativePath: string): string;
17
+ /**
18
+ * Generates a default Dockerfile for tools without a custom one.
19
+ *
20
+ * The image contains Node 22 (Alpine), installs npm deps if present,
21
+ * and copies the full tool directory into /tool.
22
+ */
23
+ export declare function generateDefaultDockerfile(hasPackageJson: boolean): string;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ /**
7
+ * Generates the entry.js content for a sandbox tool wrapper.
8
+ *
9
+ * This script runs inside a Daytona sandbox workspace:
10
+ * 1. Reads invocation payload from /tmp/invocation.json
11
+ * 2. Imports the tool handler
12
+ * 3. Creates a proxy ToolContext (where request() and exec() delegate to the host)
13
+ * 4. Executes the handler
14
+ * 5. Writes JSON result to stdout
15
+ */
16
+ export function generateToolHarnessEntry(handlerRelativePath) {
17
+ return `
18
+ import {readFileSync} from 'node:fs';
19
+ import {execSync} from 'node:child_process';
20
+ import handler from '${handlerRelativePath}';
21
+
22
+ const payload = JSON.parse(readFileSync('/tmp/invocation.json', 'utf-8'));
23
+ const {params, callbackUrl} = payload;
24
+
25
+ // Resolve handler function — supports both plain functions and defineToolHandler
26
+ const fn = typeof handler === 'function'
27
+ ? handler
28
+ : (handler.__toolHandler ? handler.handler : handler);
29
+
30
+ const ctx = {
31
+ async request(connection, endpoint, options) {
32
+ const res = await fetch(callbackUrl + '/request', {
33
+ method: 'POST',
34
+ headers: {'Content-Type': 'application/json'},
35
+ body: JSON.stringify({connection, endpoint, ...options}),
36
+ });
37
+ return res.json();
38
+ },
39
+ exec(command, options) {
40
+ try {
41
+ const stdout = execSync(command, {
42
+ cwd: options?.cwd ?? '/tool',
43
+ timeout: options?.timeout ?? payload.timeout ?? 30000,
44
+ maxBuffer: 1024 * 1024,
45
+ encoding: 'utf-8',
46
+ });
47
+ return { stdout, stderr: '', exitCode: 0 };
48
+ } catch (err) {
49
+ return {
50
+ stdout: err.stdout ?? '',
51
+ stderr: err.stderr ?? err.message,
52
+ exitCode: typeof err.status === 'number' ? err.status : 1,
53
+ };
54
+ }
55
+ },
56
+ env(name) {
57
+ return process.env[name];
58
+ },
59
+ log(message) {
60
+ process.stderr.write('[tool] ' + message + '\\n');
61
+ },
62
+ user: payload.user ?? {roles: []},
63
+ signal: AbortSignal.timeout(payload.timeout ?? 30000),
64
+ };
65
+
66
+ try {
67
+ const result = await fn(params, ctx);
68
+ process.stdout.write(JSON.stringify({result}) + '\\n');
69
+ } catch (err) {
70
+ process.stdout.write(JSON.stringify({error: err.message ?? String(err)}) + '\\n');
71
+ process.exit(1);
72
+ }
73
+ `.trim();
74
+ }
75
+ /**
76
+ * Generates a default Dockerfile for tools without a custom one.
77
+ *
78
+ * The image contains Node 22 (Alpine), installs npm deps if present,
79
+ * and copies the full tool directory into /tool.
80
+ */
81
+ export function generateDefaultDockerfile(hasPackageJson) {
82
+ const lines = [
83
+ 'FROM node:22-alpine',
84
+ 'WORKDIR /tool',
85
+ ];
86
+ if (hasPackageJson) {
87
+ lines.push('COPY package.json package-lock.json* ./');
88
+ lines.push('RUN npm install --production');
89
+ }
90
+ lines.push('COPY . .');
91
+ lines.push('');
92
+ return lines.join('\n');
93
+ }
94
+ //# sourceMappingURL=tool-harness-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-harness-template.js","sourceRoot":"","sources":["../../../src/agent/tool-harness-template.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CAAC,mBAA2B;IAClE,OAAO;;;uBAGc,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDzC,CAAC,IAAI,EAAE,CAAC;AACT,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CAAC,cAAuB;IAC/D,MAAM,KAAK,GAAG;QACZ,qBAAqB;QACrB,eAAe;KAChB,CAAC;IAEF,IAAI,cAAc,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;QACtD,KAAK,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACvB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import type { AmodalRepo } from '@amodalai/core';
7
+ import type { ConnectionsMap } from '@amodalai/core';
8
+ /**
9
+ * Fetches user context from a configured endpoint.
10
+ *
11
+ * The `config.userContext` value is a string like "GET crm/users/me"
12
+ * (method connection/path). The connection auth is resolved from
13
+ * the connections map.
14
+ */
15
+ export declare function fetchUserContext(repo: AmodalRepo, tenantToken: string, connectionsMap: ConnectionsMap): Promise<Record<string, unknown>>;
16
+ interface ParsedSpec {
17
+ method: string;
18
+ connection: string;
19
+ path: string;
20
+ }
21
+ /**
22
+ * Parse "GET crm/users/me" → {method: "GET", connection: "crm", path: "users/me"}
23
+ */
24
+ declare function parseUserContextSpec(spec: string): ParsedSpec | null;
25
+ export { parseUserContextSpec as _parseUserContextSpecForTesting };
@@ -0,0 +1,79 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ /**
7
+ * Fetches user context from a configured endpoint.
8
+ *
9
+ * The `config.userContext` value is a string like "GET crm/users/me"
10
+ * (method connection/path). The connection auth is resolved from
11
+ * the connections map.
12
+ */
13
+ export async function fetchUserContext(repo, tenantToken, connectionsMap) {
14
+ const spec = repo.config.userContext;
15
+ if (!spec) {
16
+ return {};
17
+ }
18
+ const parsed = parseUserContextSpec(spec);
19
+ if (!parsed) {
20
+ return {};
21
+ }
22
+ const connConfig = connectionsMap[parsed.connection];
23
+ if (!connConfig) {
24
+ return {};
25
+ }
26
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- SDK boundary: connections map values are records
27
+ const baseUrl = connConfig['base_url'];
28
+ if (!baseUrl) {
29
+ return {};
30
+ }
31
+ const url = `${baseUrl.replace(/\/$/, '')}/${parsed.path.replace(/^\//, '')}`;
32
+ const headers = {
33
+ 'Content-Type': 'application/json',
34
+ 'Authorization': `Bearer ${tenantToken}`,
35
+ };
36
+ const controller = new AbortController();
37
+ const timeout = setTimeout(() => controller.abort(), 5000);
38
+ try {
39
+ const response = await fetch(url, {
40
+ method: parsed.method,
41
+ headers,
42
+ signal: controller.signal,
43
+ });
44
+ if (!response.ok) {
45
+ return {};
46
+ }
47
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- SDK boundary: expecting JSON object from API
48
+ const data = (await response.json());
49
+ return data;
50
+ }
51
+ catch {
52
+ return {};
53
+ }
54
+ finally {
55
+ clearTimeout(timeout);
56
+ }
57
+ }
58
+ /**
59
+ * Parse "GET crm/users/me" → {method: "GET", connection: "crm", path: "users/me"}
60
+ */
61
+ function parseUserContextSpec(spec) {
62
+ const parts = spec.trim().split(/\s+/);
63
+ if (parts.length < 2) {
64
+ return null;
65
+ }
66
+ const method = parts[0]?.toUpperCase() ?? '';
67
+ const fullPath = parts[1] ?? '';
68
+ const slashIdx = fullPath.indexOf('/');
69
+ if (slashIdx === -1) {
70
+ return { method, connection: fullPath, path: '/' };
71
+ }
72
+ return {
73
+ method,
74
+ connection: fullPath.substring(0, slashIdx),
75
+ path: fullPath.substring(slashIdx),
76
+ };
77
+ }
78
+ export { parseUserContextSpec as _parseUserContextSpecForTesting };
79
+ //# sourceMappingURL=user-context-fetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-context-fetcher.js","sourceRoot":"","sources":["../../../src/agent/user-context-fetcher.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 {};