@mondaydotcomorg/atp-server 0.17.14

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 (307) hide show
  1. package/README.md +489 -0
  2. package/dist/aggregator/index.d.ts +59 -0
  3. package/dist/aggregator/index.d.ts.map +1 -0
  4. package/dist/aggregator/index.js +171 -0
  5. package/dist/aggregator/index.js.map +1 -0
  6. package/dist/callback/index.d.ts +98 -0
  7. package/dist/callback/index.d.ts.map +1 -0
  8. package/dist/callback/index.js +136 -0
  9. package/dist/callback/index.js.map +1 -0
  10. package/dist/client-sessions.d.ts +82 -0
  11. package/dist/client-sessions.d.ts.map +1 -0
  12. package/dist/client-sessions.js +174 -0
  13. package/dist/client-sessions.js.map +1 -0
  14. package/dist/controllers/definitions.controller.d.ts +4 -0
  15. package/dist/controllers/definitions.controller.d.ts.map +1 -0
  16. package/dist/controllers/definitions.controller.js +11 -0
  17. package/dist/controllers/definitions.controller.js.map +1 -0
  18. package/dist/controllers/execute.controller.d.ts +18 -0
  19. package/dist/controllers/execute.controller.d.ts.map +1 -0
  20. package/dist/controllers/execute.controller.js +122 -0
  21. package/dist/controllers/execute.controller.js.map +1 -0
  22. package/dist/controllers/info.controller.d.ts +3 -0
  23. package/dist/controllers/info.controller.d.ts.map +1 -0
  24. package/dist/controllers/info.controller.js +13 -0
  25. package/dist/controllers/info.controller.js.map +1 -0
  26. package/dist/controllers/resume.controller.d.ts +11 -0
  27. package/dist/controllers/resume.controller.d.ts.map +1 -0
  28. package/dist/controllers/resume.controller.js +61 -0
  29. package/dist/controllers/resume.controller.js.map +1 -0
  30. package/dist/controllers/search.controller.d.ts +4 -0
  31. package/dist/controllers/search.controller.d.ts.map +1 -0
  32. package/dist/controllers/search.controller.js +7 -0
  33. package/dist/controllers/search.controller.js.map +1 -0
  34. package/dist/controllers/stream.controller.d.ts +19 -0
  35. package/dist/controllers/stream.controller.d.ts.map +1 -0
  36. package/dist/controllers/stream.controller.js +141 -0
  37. package/dist/controllers/stream.controller.js.map +1 -0
  38. package/dist/core/config.d.ts +161 -0
  39. package/dist/core/config.d.ts.map +1 -0
  40. package/dist/core/config.js +7 -0
  41. package/dist/core/config.js.map +1 -0
  42. package/dist/core/http.d.ts +4 -0
  43. package/dist/core/http.d.ts.map +1 -0
  44. package/dist/core/http.js +17 -0
  45. package/dist/core/http.js.map +1 -0
  46. package/dist/create-server.d.ts +120 -0
  47. package/dist/create-server.d.ts.map +1 -0
  48. package/dist/create-server.js +423 -0
  49. package/dist/create-server.js.map +1 -0
  50. package/dist/execution-state/index.d.ts +95 -0
  51. package/dist/execution-state/index.d.ts.map +1 -0
  52. package/dist/execution-state/index.js +128 -0
  53. package/dist/execution-state/index.js.map +1 -0
  54. package/dist/executor/ast-provenance-bridge.d.ts +12 -0
  55. package/dist/executor/ast-provenance-bridge.d.ts.map +1 -0
  56. package/dist/executor/ast-provenance-bridge.js +66 -0
  57. package/dist/executor/ast-provenance-bridge.js.map +1 -0
  58. package/dist/executor/ast-tracking-runtime.d.ts +7 -0
  59. package/dist/executor/ast-tracking-runtime.d.ts.map +1 -0
  60. package/dist/executor/ast-tracking-runtime.js +559 -0
  61. package/dist/executor/ast-tracking-runtime.js.map +1 -0
  62. package/dist/executor/bootstrap-generated.d.ts +32 -0
  63. package/dist/executor/bootstrap-generated.d.ts.map +1 -0
  64. package/dist/executor/bootstrap-generated.js +90 -0
  65. package/dist/executor/bootstrap-generated.js.map +1 -0
  66. package/dist/executor/compiler-config.d.ts +32 -0
  67. package/dist/executor/compiler-config.d.ts.map +1 -0
  68. package/dist/executor/compiler-config.js +99 -0
  69. package/dist/executor/compiler-config.js.map +1 -0
  70. package/dist/executor/constants.d.ts +4 -0
  71. package/dist/executor/constants.d.ts.map +1 -0
  72. package/dist/executor/constants.js +4 -0
  73. package/dist/executor/constants.js.map +1 -0
  74. package/dist/executor/error-handler.d.ts +9 -0
  75. package/dist/executor/error-handler.d.ts.map +1 -0
  76. package/dist/executor/error-handler.js +95 -0
  77. package/dist/executor/error-handler.js.map +1 -0
  78. package/dist/executor/execution-error-handler.d.ts +7 -0
  79. package/dist/executor/execution-error-handler.d.ts.map +1 -0
  80. package/dist/executor/execution-error-handler.js +136 -0
  81. package/dist/executor/execution-error-handler.js.map +1 -0
  82. package/dist/executor/executor.d.ts +20 -0
  83. package/dist/executor/executor.d.ts.map +1 -0
  84. package/dist/executor/executor.js +452 -0
  85. package/dist/executor/executor.js.map +1 -0
  86. package/dist/executor/index.d.ts +4 -0
  87. package/dist/executor/index.d.ts.map +1 -0
  88. package/dist/executor/index.js +3 -0
  89. package/dist/executor/index.js.map +1 -0
  90. package/dist/executor/resume-handler.d.ts +9 -0
  91. package/dist/executor/resume-handler.d.ts.map +1 -0
  92. package/dist/executor/resume-handler.js +22 -0
  93. package/dist/executor/resume-handler.js.map +1 -0
  94. package/dist/executor/sandbox-builder.d.ts +29 -0
  95. package/dist/executor/sandbox-builder.d.ts.map +1 -0
  96. package/dist/executor/sandbox-builder.js +538 -0
  97. package/dist/executor/sandbox-builder.js.map +1 -0
  98. package/dist/executor/sandbox-injector.d.ts +7 -0
  99. package/dist/executor/sandbox-injector.d.ts.map +1 -0
  100. package/dist/executor/sandbox-injector.js +293 -0
  101. package/dist/executor/sandbox-injector.js.map +1 -0
  102. package/dist/executor/types.d.ts +21 -0
  103. package/dist/executor/types.d.ts.map +1 -0
  104. package/dist/executor/types.js +2 -0
  105. package/dist/executor/types.js.map +1 -0
  106. package/dist/explorer/index.d.ts +69 -0
  107. package/dist/explorer/index.d.ts.map +1 -0
  108. package/dist/explorer/index.js +228 -0
  109. package/dist/explorer/index.js.map +1 -0
  110. package/dist/handlers/definitions.handler.d.ts +3 -0
  111. package/dist/handlers/definitions.handler.d.ts.map +1 -0
  112. package/dist/handlers/definitions.handler.js +11 -0
  113. package/dist/handlers/definitions.handler.js.map +1 -0
  114. package/dist/handlers/execute.handler.d.ts +7 -0
  115. package/dist/handlers/execute.handler.d.ts.map +1 -0
  116. package/dist/handlers/execute.handler.js +225 -0
  117. package/dist/handlers/execute.handler.js.map +1 -0
  118. package/dist/handlers/explorer.handler.d.ts +4 -0
  119. package/dist/handlers/explorer.handler.d.ts.map +1 -0
  120. package/dist/handlers/explorer.handler.js +10 -0
  121. package/dist/handlers/explorer.handler.js.map +1 -0
  122. package/dist/handlers/init.handler.d.ts +5 -0
  123. package/dist/handlers/init.handler.d.ts.map +1 -0
  124. package/dist/handlers/init.handler.js +41 -0
  125. package/dist/handlers/init.handler.js.map +1 -0
  126. package/dist/handlers/resume.handler.d.ts +6 -0
  127. package/dist/handlers/resume.handler.d.ts.map +1 -0
  128. package/dist/handlers/resume.handler.js +256 -0
  129. package/dist/handlers/resume.handler.js.map +1 -0
  130. package/dist/handlers/search.handler.d.ts +5 -0
  131. package/dist/handlers/search.handler.d.ts.map +1 -0
  132. package/dist/handlers/search.handler.js +11 -0
  133. package/dist/handlers/search.handler.js.map +1 -0
  134. package/dist/http/request-handler.d.ts +15 -0
  135. package/dist/http/request-handler.d.ts.map +1 -0
  136. package/dist/http/request-handler.js +94 -0
  137. package/dist/http/request-handler.js.map +1 -0
  138. package/dist/http/router.d.ts +4 -0
  139. package/dist/http/router.d.ts.map +1 -0
  140. package/dist/http/router.js +32 -0
  141. package/dist/http/router.js.map +1 -0
  142. package/dist/index.d.ts +10 -0
  143. package/dist/index.d.ts.map +1 -0
  144. package/dist/index.js +8 -0
  145. package/dist/index.js.map +1 -0
  146. package/dist/instrumentation/index.d.ts +5 -0
  147. package/dist/instrumentation/index.d.ts.map +1 -0
  148. package/dist/instrumentation/index.js +5 -0
  149. package/dist/instrumentation/index.js.map +1 -0
  150. package/dist/instrumentation/serializer.d.ts +61 -0
  151. package/dist/instrumentation/serializer.d.ts.map +1 -0
  152. package/dist/instrumentation/serializer.js +334 -0
  153. package/dist/instrumentation/serializer.js.map +1 -0
  154. package/dist/instrumentation/state-manager.d.ts +61 -0
  155. package/dist/instrumentation/state-manager.d.ts.map +1 -0
  156. package/dist/instrumentation/state-manager.js +205 -0
  157. package/dist/instrumentation/state-manager.js.map +1 -0
  158. package/dist/instrumentation/transformer.d.ts +9 -0
  159. package/dist/instrumentation/transformer.d.ts.map +1 -0
  160. package/dist/instrumentation/transformer.js +70 -0
  161. package/dist/instrumentation/transformer.js.map +1 -0
  162. package/dist/instrumentation/types.d.ts +59 -0
  163. package/dist/instrumentation/types.d.ts.map +1 -0
  164. package/dist/instrumentation/types.js +5 -0
  165. package/dist/instrumentation/types.js.map +1 -0
  166. package/dist/middleware/audit.d.ts +18 -0
  167. package/dist/middleware/audit.d.ts.map +1 -0
  168. package/dist/middleware/audit.js +76 -0
  169. package/dist/middleware/audit.js.map +1 -0
  170. package/dist/openapi/index.d.ts +133 -0
  171. package/dist/openapi/index.d.ts.map +1 -0
  172. package/dist/openapi/index.js +235 -0
  173. package/dist/openapi/index.js.map +1 -0
  174. package/dist/openapi-loader.d.ts +87 -0
  175. package/dist/openapi-loader.d.ts.map +1 -0
  176. package/dist/openapi-loader.js +491 -0
  177. package/dist/openapi-loader.js.map +1 -0
  178. package/dist/routes/index.d.ts +21 -0
  179. package/dist/routes/index.d.ts.map +1 -0
  180. package/dist/routes/index.js +47 -0
  181. package/dist/routes/index.js.map +1 -0
  182. package/dist/search/index.d.ts +48 -0
  183. package/dist/search/index.d.ts.map +1 -0
  184. package/dist/search/index.js +156 -0
  185. package/dist/search/index.js.map +1 -0
  186. package/dist/security/index.d.ts +2 -0
  187. package/dist/security/index.d.ts.map +1 -0
  188. package/dist/security/index.js +2 -0
  189. package/dist/security/index.js.map +1 -0
  190. package/dist/shutdown.d.ts +19 -0
  191. package/dist/shutdown.d.ts.map +1 -0
  192. package/dist/shutdown.js +87 -0
  193. package/dist/shutdown.js.map +1 -0
  194. package/dist/utils/banner.d.ts +12 -0
  195. package/dist/utils/banner.d.ts.map +1 -0
  196. package/dist/utils/banner.js +18 -0
  197. package/dist/utils/banner.js.map +1 -0
  198. package/dist/utils/context.d.ts +16 -0
  199. package/dist/utils/context.d.ts.map +1 -0
  200. package/dist/utils/context.js +44 -0
  201. package/dist/utils/context.js.map +1 -0
  202. package/dist/utils/error.d.ts +8 -0
  203. package/dist/utils/error.d.ts.map +1 -0
  204. package/dist/utils/error.js +17 -0
  205. package/dist/utils/error.js.map +1 -0
  206. package/dist/utils/hint-based-instrumentation.d.ts +14 -0
  207. package/dist/utils/hint-based-instrumentation.d.ts.map +1 -0
  208. package/dist/utils/hint-based-instrumentation.js +84 -0
  209. package/dist/utils/hint-based-instrumentation.js.map +1 -0
  210. package/dist/utils/index.d.ts +8 -0
  211. package/dist/utils/index.d.ts.map +1 -0
  212. package/dist/utils/index.js +8 -0
  213. package/dist/utils/index.js.map +1 -0
  214. package/dist/utils/info.d.ts +20 -0
  215. package/dist/utils/info.d.ts.map +1 -0
  216. package/dist/utils/info.js +15 -0
  217. package/dist/utils/info.js.map +1 -0
  218. package/dist/utils/provenance-reattachment.d.ts +32 -0
  219. package/dist/utils/provenance-reattachment.d.ts.map +1 -0
  220. package/dist/utils/provenance-reattachment.js +115 -0
  221. package/dist/utils/provenance-reattachment.js.map +1 -0
  222. package/dist/utils/request.d.ts +21 -0
  223. package/dist/utils/request.d.ts.map +1 -0
  224. package/dist/utils/request.js +44 -0
  225. package/dist/utils/request.js.map +1 -0
  226. package/dist/utils/response.d.ts +30 -0
  227. package/dist/utils/response.d.ts.map +1 -0
  228. package/dist/utils/response.js +53 -0
  229. package/dist/utils/response.js.map +1 -0
  230. package/dist/utils/runtime-types.d.ts +6 -0
  231. package/dist/utils/runtime-types.d.ts.map +1 -0
  232. package/dist/utils/runtime-types.js +14 -0
  233. package/dist/utils/runtime-types.js.map +1 -0
  234. package/dist/utils/schema.d.ts +9 -0
  235. package/dist/utils/schema.d.ts.map +1 -0
  236. package/dist/utils/schema.js +13 -0
  237. package/dist/utils/schema.js.map +1 -0
  238. package/dist/utils/token-emitter.d.ts +21 -0
  239. package/dist/utils/token-emitter.d.ts.map +1 -0
  240. package/dist/utils/token-emitter.js +129 -0
  241. package/dist/utils/token-emitter.js.map +1 -0
  242. package/dist/validator/index.d.ts +36 -0
  243. package/dist/validator/index.d.ts.map +1 -0
  244. package/dist/validator/index.js +224 -0
  245. package/dist/validator/index.js.map +1 -0
  246. package/package.json +68 -0
  247. package/src/aggregator/index.ts +207 -0
  248. package/src/callback/index.ts +191 -0
  249. package/src/client-sessions.ts +234 -0
  250. package/src/controllers/definitions.controller.ts +19 -0
  251. package/src/controllers/execute.controller.ts +166 -0
  252. package/src/controllers/info.controller.ts +14 -0
  253. package/src/controllers/resume.controller.ts +92 -0
  254. package/src/controllers/search.controller.ts +16 -0
  255. package/src/controllers/stream.controller.ts +190 -0
  256. package/src/core/config.ts +180 -0
  257. package/src/core/http.ts +21 -0
  258. package/src/create-server.ts +536 -0
  259. package/src/execution-state/index.ts +204 -0
  260. package/src/executor/ast-provenance-bridge.ts +80 -0
  261. package/src/executor/ast-tracking-runtime.ts +558 -0
  262. package/src/executor/bootstrap-generated.ts +90 -0
  263. package/src/executor/compiler-config.ts +146 -0
  264. package/src/executor/constants.ts +5 -0
  265. package/src/executor/error-handler.ts +118 -0
  266. package/src/executor/execution-error-handler.ts +178 -0
  267. package/src/executor/executor.ts +631 -0
  268. package/src/executor/index.ts +3 -0
  269. package/src/executor/resume-handler.ts +39 -0
  270. package/src/executor/sandbox-builder.ts +684 -0
  271. package/src/executor/sandbox-injector.ts +345 -0
  272. package/src/executor/types.ts +22 -0
  273. package/src/explorer/index.ts +297 -0
  274. package/src/handlers/definitions.handler.ts +13 -0
  275. package/src/handlers/execute.handler.ts +286 -0
  276. package/src/handlers/explorer.handler.ts +18 -0
  277. package/src/handlers/init.handler.ts +53 -0
  278. package/src/handlers/resume.handler.ts +316 -0
  279. package/src/handlers/search.handler.ts +32 -0
  280. package/src/http/request-handler.ts +117 -0
  281. package/src/http/router.ts +29 -0
  282. package/src/index.ts +60 -0
  283. package/src/instrumentation/index.ts +4 -0
  284. package/src/instrumentation/serializer.ts +421 -0
  285. package/src/instrumentation/state-manager.ts +237 -0
  286. package/src/instrumentation/transformer.ts +84 -0
  287. package/src/instrumentation/types.ts +76 -0
  288. package/src/middleware/audit.ts +101 -0
  289. package/src/openapi/index.ts +378 -0
  290. package/src/openapi-loader.ts +744 -0
  291. package/src/routes/index.ts +93 -0
  292. package/src/search/index.ts +216 -0
  293. package/src/security/index.ts +1 -0
  294. package/src/shutdown.ts +108 -0
  295. package/src/utils/banner.ts +25 -0
  296. package/src/utils/context.ts +58 -0
  297. package/src/utils/error.ts +25 -0
  298. package/src/utils/hint-based-instrumentation.ts +99 -0
  299. package/src/utils/index.ts +15 -0
  300. package/src/utils/info.ts +31 -0
  301. package/src/utils/provenance-reattachment.ts +144 -0
  302. package/src/utils/request.ts +53 -0
  303. package/src/utils/response.ts +69 -0
  304. package/src/utils/runtime-types.ts +14 -0
  305. package/src/utils/schema.ts +18 -0
  306. package/src/utils/token-emitter.ts +182 -0
  307. package/src/validator/index.ts +253 -0
@@ -0,0 +1,536 @@
1
+ import { createServer as createHTTPServer, IncomingMessage, ServerResponse } from 'node:http';
2
+ import type {
3
+ CacheProvider,
4
+ AuthProvider,
5
+ AuditSink,
6
+ APIGroupConfig,
7
+ AuditEvent,
8
+ ToolMetadata,
9
+ } from '@mondaydotcomorg/atp-protocol';
10
+ import { ProvenanceMode } from '@mondaydotcomorg/atp-protocol';
11
+ import { log, initializeLogger } from '@mondaydotcomorg/atp-runtime';
12
+ import { shutdownLogger } from '@mondaydotcomorg/atp-runtime';
13
+ import type {
14
+ ServerConfig,
15
+ Middleware,
16
+ RequestContext,
17
+ ResolvedServerConfig,
18
+ } from './core/config.js';
19
+ import { MB, HOUR, MINUTE } from './core/config.js';
20
+ import { ClientSessionManager } from './client-sessions.js';
21
+ import { SandboxExecutor } from './executor/index.js';
22
+ import { CodeValidator } from './validator/index.js';
23
+ import { SearchEngine } from './search/index.js';
24
+ import { ExecutionStateManager } from './execution-state/index.js';
25
+ import { ExplorerService } from './explorer/index.js';
26
+ import { toJSONSchema, printBanner, getServerInfo } from './utils/index.js';
27
+ import { handleHTTPRequest } from './http/request-handler.js';
28
+ import { handleRoute } from './http/router.js';
29
+ import { handleInit } from './handlers/init.handler.js';
30
+ import { handleSearch, handleSearchQuery } from './handlers/search.handler.js';
31
+ import { handleExplore } from './handlers/explorer.handler.js';
32
+ import { handleExecute } from './handlers/execute.handler.js';
33
+ import { handleResume } from './handlers/resume.handler.js';
34
+ import { getDefinitions } from './handlers/definitions.handler.js';
35
+ import { shutdownAudit } from './middleware/audit.js';
36
+ import {
37
+ EnvAuthProvider,
38
+ MemoryCache,
39
+ OpenTelemetryAuditSink,
40
+ } from '@mondaydotcomorg/atp-providers';
41
+
42
+ export class AgentToolProtocolServer {
43
+ private config: ResolvedServerConfig;
44
+ private middleware: Middleware[] = [];
45
+ private apiGroups: APIGroupConfig[] = [];
46
+ private httpServer: ReturnType<typeof createHTTPServer> | null = null;
47
+ private responseHeaders: Map<IncomingMessage, Map<string, string>> = new Map();
48
+ private isRunning: boolean = false;
49
+ sessionManager?: ClientSessionManager;
50
+ executor?: SandboxExecutor;
51
+ validator?: CodeValidator;
52
+ searchEngine?: SearchEngine;
53
+ explorerService?: ExplorerService;
54
+ stateManager?: ExecutionStateManager;
55
+ approvalHandler?: (request: {
56
+ message: string;
57
+ context?: any;
58
+ }) => Promise<{ approved: boolean; data?: any }>;
59
+
60
+ cacheProvider?: CacheProvider;
61
+ authProvider?: AuthProvider;
62
+ auditSink?: AuditSink;
63
+ private customLogger?: any;
64
+
65
+ constructor(config: ServerConfig = {}) {
66
+ this.config = {
67
+ execution: {
68
+ timeout: config.execution?.timeout ?? 30000,
69
+ memory: config.execution?.memory ?? 128 * MB,
70
+ llmCalls: config.execution?.llmCalls ?? 10,
71
+ provenanceMode: config.execution?.provenanceMode ?? ProvenanceMode.NONE,
72
+ securityPolicies: config.execution?.securityPolicies ?? [],
73
+ },
74
+ clientInit: {
75
+ tokenTTL: config.clientInit?.tokenTTL ?? HOUR,
76
+ tokenRotation: config.clientInit?.tokenRotation ?? 30 * MINUTE,
77
+ },
78
+ executionState: {
79
+ ttl: config.executionState?.ttl ?? 3600,
80
+ maxPauseDuration: config.executionState?.maxPauseDuration ?? 3600,
81
+ },
82
+ discovery: {
83
+ embeddings: config.discovery?.embeddings ?? false,
84
+ },
85
+ audit: {
86
+ enabled: config.audit?.enabled ?? false,
87
+ sinks: config.audit?.sinks,
88
+ },
89
+ otel: {
90
+ enabled: config.otel?.enabled ?? false,
91
+ serviceName:
92
+ config.otel?.serviceName ?? process.env.OTEL_SERVICE_NAME ?? 'agent-tool-protocol',
93
+ serviceVersion: config.otel?.serviceVersion ?? process.env.OTEL_SERVICE_VERSION ?? '1.0.0',
94
+ traceEndpoint:
95
+ config.otel?.traceEndpoint ??
96
+ process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ??
97
+ (process.env.OTEL_EXPORTER_OTLP_ENDPOINT
98
+ ? `${process.env.OTEL_EXPORTER_OTLP_ENDPOINT}/v1/traces`
99
+ : 'http://localhost:4318/v1/traces'),
100
+ metricsEndpoint:
101
+ config.otel?.metricsEndpoint ??
102
+ process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT ??
103
+ (process.env.OTEL_EXPORTER_OTLP_ENDPOINT
104
+ ? `${process.env.OTEL_EXPORTER_OTLP_ENDPOINT}/v1/metrics`
105
+ : 'http://localhost:4318/v1/metrics'),
106
+ headers:
107
+ config.otel?.headers ?? this.parseOtelHeaders(process.env.OTEL_EXPORTER_OTLP_HEADERS),
108
+ metricsInterval: config.otel?.metricsInterval ?? 60000,
109
+ resourceAttributes: config.otel?.resourceAttributes ?? {},
110
+ },
111
+ logger: config.logger ?? 'info',
112
+ };
113
+
114
+ if (config.providers) {
115
+ if (config.providers.cache) {
116
+ this.cacheProvider = config.providers.cache;
117
+ log.info('Cache provider configured', { provider: config.providers.cache.name });
118
+ }
119
+ if (config.providers.auth) {
120
+ this.authProvider = config.providers.auth;
121
+ log.info('Token store configured', { provider: config.providers.auth.name });
122
+ }
123
+ }
124
+
125
+ if (!this.cacheProvider) {
126
+ this.cacheProvider = new MemoryCache({ maxKeys: 1000, defaultTTL: 3600 });
127
+ log.info('Cache provider configured (default)', { provider: 'memory' });
128
+ }
129
+
130
+ if (!this.authProvider) {
131
+ this.authProvider = new EnvAuthProvider();
132
+ log.info('Token store configured (default)', { provider: 'env' });
133
+ }
134
+
135
+ if (this.config.otel.enabled && !this.config.audit.sinks) {
136
+ this.config.audit.enabled = true;
137
+ this.config.audit.sinks = [new OpenTelemetryAuditSink()];
138
+ log.info('Auto-configured OpenTelemetry audit sink from otel config');
139
+ }
140
+
141
+ if (this.config.audit.enabled && this.config.audit.sinks) {
142
+ const auditSinks = Array.isArray(this.config.audit.sinks)
143
+ ? this.config.audit.sinks
144
+ : [this.config.audit.sinks];
145
+
146
+ if (auditSinks.length > 1) {
147
+ this.auditSink = {
148
+ name: 'multi',
149
+ async write(event: AuditEvent) {
150
+ await Promise.all(auditSinks.map((s: AuditSink) => s.write(event)));
151
+ },
152
+ async writeBatch(events: AuditEvent[]) {
153
+ await Promise.all(auditSinks.map((s: AuditSink) => s.writeBatch(events)));
154
+ },
155
+ };
156
+ log.info('Audit sinks configured', { count: auditSinks.length });
157
+ } else {
158
+ this.auditSink = auditSinks[0];
159
+ log.info('Audit sink configured', { sink: auditSinks[0]?.name });
160
+ }
161
+ }
162
+
163
+ if (typeof this.config.logger === 'string') {
164
+ initializeLogger({
165
+ level: this.config.logger,
166
+ pretty: process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test',
167
+ });
168
+ } else {
169
+ this.customLogger = this.config.logger;
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Register middleware or API groups.
175
+ * SECURITY: Cannot be called after server starts to prevent runtime injection attacks.
176
+ * @throws {Error} If called after listen() or handler()
177
+ */
178
+ use(...items: (Middleware | APIGroupConfig | APIGroupConfig[])[]): this {
179
+ if (this.isRunning) {
180
+ throw new Error('Cannot add middleware or API groups after server has started. ');
181
+ }
182
+
183
+ for (const item of items) {
184
+ if (Array.isArray(item)) {
185
+ this.apiGroups.push(...item);
186
+ } else if (typeof item === 'function') {
187
+ this.middleware.push(item);
188
+ } else if ('name' in item && 'type' in item) {
189
+ this.apiGroups.push(item);
190
+ }
191
+ }
192
+ return this;
193
+ }
194
+
195
+ /**
196
+ * Register a tool/function with optional hierarchical grouping.
197
+ * Supports hierarchical paths like 'github/readOnly' for better organization.
198
+ * All functions registered here will be exposed as api.{group}.{name}()
199
+ *
200
+ * @param name - Function name
201
+ * @param definition - Function definition including description, input schema, handler
202
+ * @param definition.group - Optional hierarchical group path (e.g., 'github/readOnly'). Defaults to 'custom'
203
+ *
204
+ * @example
205
+ * // Simple function in default 'custom' group -> api.custom.hello()
206
+ * server.tool('hello', {
207
+ * description: 'Say hello',
208
+ * input: { name: 'string' },
209
+ * handler: async (input) => ({ message: `Hello ${input.name}` })
210
+ * });
211
+ *
212
+ * // Hierarchical grouping -> api.github.readOnly.getUser()
213
+ * server.tool('getUser', {
214
+ * group: 'github/readOnly',
215
+ * description: 'Get GitHub user',
216
+ * input: { username: 'string' },
217
+ * handler: async (input) => ({ username: input.username })
218
+ * });
219
+ */
220
+ tool(
221
+ name: string,
222
+ definition: {
223
+ group?: string;
224
+ description: string;
225
+ input: Record<string, string>;
226
+ output?: Record<string, string>;
227
+ handler: (input: unknown) => Promise<unknown>;
228
+ metadata?: ToolMetadata;
229
+ }
230
+ ): this {
231
+ const groupName = definition.group || 'custom';
232
+
233
+ let targetGroup = this.apiGroups.find((g) => g.name === groupName);
234
+ if (!targetGroup) {
235
+ targetGroup = {
236
+ name: groupName,
237
+ type: 'custom',
238
+ functions: [],
239
+ };
240
+ this.apiGroups.push(targetGroup);
241
+ }
242
+
243
+ targetGroup.functions!.push({
244
+ name,
245
+ description: definition.description,
246
+ inputSchema: toJSONSchema(definition.input),
247
+ outputSchema: definition.output ? toJSONSchema(definition.output) : undefined,
248
+ handler: definition.handler,
249
+ metadata: definition.metadata,
250
+ });
251
+ return this;
252
+ }
253
+
254
+ /**
255
+ * Configure approval handler for human-in-the-loop operations
256
+ * The handler will be called when code requests approval via atp.approval.request()
257
+ */
258
+ onApproval(
259
+ handler: (request: {
260
+ message: string;
261
+ context?: any;
262
+ }) => Promise<{ approved: boolean; data?: any }>
263
+ ): this {
264
+ this.approvalHandler = handler;
265
+ log.info('Approval handler configured');
266
+ return this;
267
+ }
268
+
269
+ async listen(port: number): Promise<void> {
270
+ if (this.httpServer) {
271
+ throw new Error('Server is already running');
272
+ }
273
+
274
+ this.isRunning = true;
275
+
276
+ this.sessionManager = new ClientSessionManager({
277
+ cache: this.cacheProvider,
278
+ tokenTTL: this.config.clientInit.tokenTTL,
279
+ tokenRotation: this.config.clientInit.tokenRotation,
280
+ });
281
+
282
+ this.validator = new CodeValidator();
283
+ this.executor = new SandboxExecutor(
284
+ {
285
+ defaultTimeout: this.config.execution.timeout,
286
+ maxTimeout: this.config.execution.timeout * 2,
287
+ defaultMemoryLimit: this.config.execution.memory,
288
+ maxMemoryLimit: this.config.execution.memory * 2,
289
+ defaultLLMCallLimit: this.config.execution.llmCalls,
290
+ maxLLMCallLimit: this.config.execution.llmCalls * 2,
291
+ cacheProvider: this.cacheProvider,
292
+ },
293
+ this.apiGroups,
294
+ this.approvalHandler,
295
+ this.sessionManager
296
+ );
297
+
298
+ for (const group of this.apiGroups) {
299
+ log.info(` - ${group.name}: ${group.functions?.length || 0} functions`);
300
+ }
301
+
302
+ this.searchEngine = new SearchEngine(this.apiGroups);
303
+ this.explorerService = new ExplorerService(this.apiGroups);
304
+ this.stateManager = new ExecutionStateManager(this.cacheProvider!, {
305
+ ttl: this.config.executionState.ttl,
306
+ maxPauseDuration: this.config.executionState.maxPauseDuration,
307
+ keyPrefix: this.config.executionState.keyPrefix,
308
+ });
309
+
310
+ this.httpServer = createHTTPServer((req, res) => {
311
+ handleHTTPRequest(
312
+ req,
313
+ res,
314
+ {
315
+ cacheProvider: this.cacheProvider,
316
+ authProvider: this.authProvider,
317
+ auditSink: this.auditSink,
318
+ customLogger: this.customLogger,
319
+ middleware: this.middleware,
320
+ routeHandler: (ctx) => handleRoute(ctx, this),
321
+ sessionManager: this.sessionManager,
322
+ },
323
+ this.responseHeaders
324
+ ).catch((error) => {
325
+ log.error('Unhandled error in HTTP request handler:', error);
326
+ try {
327
+ if (!res.headersSent) {
328
+ res.writeHead(500, { 'Content-Type': 'application/json' });
329
+ res.end(JSON.stringify({ error: 'Internal server error' }));
330
+ }
331
+ } catch (e) {}
332
+ });
333
+ });
334
+
335
+ if (process.env.NODE_ENV === 'test') {
336
+ this.httpServer.keepAliveTimeout = 5000;
337
+ this.httpServer.headersTimeout = 6000;
338
+ }
339
+
340
+ return new Promise((resolve, reject) => {
341
+ this.httpServer!.listen(port, () => {
342
+ printBanner({
343
+ port,
344
+ cacheProvider: this.cacheProvider,
345
+ authProvider: this.authProvider,
346
+ auditSink: this.auditSink,
347
+ });
348
+ resolve();
349
+ });
350
+ this.httpServer!.on('error', reject);
351
+ });
352
+ }
353
+
354
+ async stop(): Promise<void> {
355
+ if (!this.httpServer) return;
356
+
357
+ this.httpServer.closeAllConnections?.();
358
+
359
+ await new Promise<void>((resolve, reject) => {
360
+ this.httpServer!.close((err) => (err ? reject(err) : resolve()));
361
+ });
362
+
363
+ shutdownAudit();
364
+ shutdownLogger();
365
+
366
+ await Promise.all([
367
+ this.cacheProvider?.disconnect?.(),
368
+ this.authProvider?.disconnect?.(),
369
+ this.auditSink?.disconnect?.(),
370
+ this.stateManager?.close(),
371
+ this.sessionManager?.cleanupAll(),
372
+ ]);
373
+
374
+ this.isRunning = false;
375
+ }
376
+
377
+ getInfo(): unknown {
378
+ return getServerInfo({
379
+ maxTimeout: this.config.execution.timeout,
380
+ maxMemory: this.config.execution.memory,
381
+ maxLLMCalls: this.config.execution.llmCalls,
382
+ });
383
+ }
384
+
385
+ async getDefinitions(ctx?: RequestContext): Promise<unknown> {
386
+ const definitions = await getDefinitions(this.apiGroups);
387
+
388
+ if (ctx && ctx.clientId && this.sessionManager) {
389
+ const session = await this.sessionManager.getSession(ctx.clientId);
390
+ if (session?.guidance) {
391
+ return {
392
+ ...(definitions as object),
393
+ guidance: session.guidance,
394
+ };
395
+ }
396
+ }
397
+
398
+ return definitions;
399
+ }
400
+
401
+ async handleInit(ctx: RequestContext): Promise<unknown> {
402
+ if (!this.sessionManager) ctx.throw(503, 'Session manager not initialized');
403
+ return await handleInit(ctx, this.sessionManager, this.auditSink);
404
+ }
405
+
406
+ async handleSearch(ctx: RequestContext): Promise<unknown> {
407
+ if (!this.searchEngine) ctx.throw(503, 'Search not initialized');
408
+ return await handleSearch(ctx, this.searchEngine, this.config);
409
+ }
410
+
411
+ async handleSearchQuery(ctx: RequestContext): Promise<unknown> {
412
+ if (!this.searchEngine) ctx.throw(503, 'Search not initialized');
413
+ return await handleSearchQuery(ctx, this.searchEngine, this.config);
414
+ }
415
+
416
+ async handleExplore(ctx: RequestContext): Promise<unknown> {
417
+ if (!this.explorerService) ctx.throw(503, 'Explorer not initialized');
418
+ return await handleExplore(ctx, this.explorerService);
419
+ }
420
+
421
+ async handleExecute(ctx: RequestContext): Promise<unknown> {
422
+ if (!this.executor || !this.validator || !this.stateManager) {
423
+ ctx.throw(503, 'Execution not initialized');
424
+ }
425
+ return await handleExecute(
426
+ ctx,
427
+ this.executor,
428
+ this.stateManager,
429
+ this.config,
430
+ this.auditSink,
431
+ this.sessionManager
432
+ );
433
+ }
434
+
435
+ async handleResume(ctx: RequestContext, executionId: string): Promise<unknown> {
436
+ if (!this.executor || !this.stateManager) {
437
+ ctx.throw(503, 'Execution not initialized');
438
+ }
439
+ return await handleResume(
440
+ ctx,
441
+ executionId,
442
+ this.executor,
443
+ this.stateManager,
444
+ this.config,
445
+ this.sessionManager
446
+ );
447
+ }
448
+
449
+ /**
450
+ * Get raw Node.js request handler for framework integration
451
+ * Use this to integrate ATP with Express, Fastify, or any Node.js framework
452
+ */
453
+ handler(): (req: IncomingMessage, res: ServerResponse) => Promise<void> {
454
+ if (
455
+ !this.executor ||
456
+ !this.validator ||
457
+ !this.stateManager ||
458
+ !this.sessionManager ||
459
+ !this.searchEngine ||
460
+ !this.explorerService
461
+ ) {
462
+ throw new Error(
463
+ 'Server not initialized. Call listen() first or initialize components manually.'
464
+ );
465
+ }
466
+
467
+ this.isRunning = true;
468
+
469
+ return (req, res) =>
470
+ handleHTTPRequest(
471
+ req,
472
+ res,
473
+ {
474
+ cacheProvider: this.cacheProvider,
475
+ authProvider: this.authProvider,
476
+ auditSink: this.auditSink,
477
+ customLogger: this.customLogger,
478
+ middleware: this.middleware,
479
+ routeHandler: (ctx) => handleRoute(ctx, this),
480
+ sessionManager: this.sessionManager,
481
+ },
482
+ this.responseHeaders
483
+ );
484
+ }
485
+
486
+ /**
487
+ * Get Express middleware
488
+ * @example
489
+ * const app = express();
490
+ * app.use('/atp', server.toExpress());
491
+ */
492
+ toExpress(): (req: unknown, res: unknown, next: (err?: unknown) => void) => void {
493
+ const requestHandler = this.handler();
494
+ return (req: unknown, res: unknown, next: (err?: unknown) => void) => {
495
+ requestHandler(req as IncomingMessage, res as ServerResponse).catch(next);
496
+ };
497
+ }
498
+
499
+ /**
500
+ * Get Fastify handler
501
+ * @example
502
+ * fastify.all('/atp/*', server.toFastify());
503
+ */
504
+ toFastify(): (request: unknown, reply: unknown) => Promise<void> {
505
+ const requestHandler = this.handler();
506
+ return async (request: unknown, reply: unknown) => {
507
+ const req = (request as { raw: IncomingMessage }).raw;
508
+ const res = (reply as { raw: ServerResponse }).raw;
509
+ await requestHandler(req, res);
510
+ };
511
+ }
512
+
513
+ /**
514
+ * Parse OpenTelemetry headers from environment variable format
515
+ * Format: "key1=value1,key2=value2"
516
+ */
517
+ private parseOtelHeaders(headersStr?: string): Record<string, string> {
518
+ if (!headersStr) return {};
519
+
520
+ const headers: Record<string, string> = {};
521
+ const pairs = headersStr.split(',');
522
+
523
+ for (const pair of pairs) {
524
+ const [key, value] = pair.split('=');
525
+ if (key && value) {
526
+ headers[key.trim()] = value.trim();
527
+ }
528
+ }
529
+
530
+ return headers;
531
+ }
532
+ }
533
+
534
+ export function createServer(config?: ServerConfig): AgentToolProtocolServer {
535
+ return new AgentToolProtocolServer(config);
536
+ }