@mondaydotcomorg/atp-client 0.19.6 → 0.19.8

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 (40) hide show
  1. package/README.md +4 -1
  2. package/dist/client.d.ts +23 -2
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +26 -5
  5. package/dist/client.js.map +1 -1
  6. package/dist/core/api-operations.d.ts +4 -2
  7. package/dist/core/api-operations.d.ts.map +1 -1
  8. package/dist/core/api-operations.js +25 -1
  9. package/dist/core/api-operations.js.map +1 -1
  10. package/dist/core/execution-operations.d.ts +4 -2
  11. package/dist/core/execution-operations.d.ts.map +1 -1
  12. package/dist/core/execution-operations.js +60 -40
  13. package/dist/core/execution-operations.js.map +1 -1
  14. package/dist/core/in-process-session.d.ts +96 -0
  15. package/dist/core/in-process-session.d.ts.map +1 -0
  16. package/dist/core/in-process-session.js +175 -0
  17. package/dist/core/in-process-session.js.map +1 -0
  18. package/dist/core/index.cjs +1192 -0
  19. package/dist/core/index.cjs.map +1 -0
  20. package/dist/core/index.d.ts +1 -0
  21. package/dist/core/index.d.ts.map +1 -1
  22. package/dist/core/index.js +1181 -5
  23. package/dist/core/index.js.map +1 -1
  24. package/dist/core/session.d.ts +24 -1
  25. package/dist/core/session.d.ts.map +1 -1
  26. package/dist/core/session.js.map +1 -1
  27. package/dist/index.cjs +1589 -0
  28. package/dist/index.cjs.map +1 -0
  29. package/dist/index.d.ts +2 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +1577 -6
  32. package/dist/index.js.map +1 -1
  33. package/package.json +12 -7
  34. package/src/client.ts +51 -7
  35. package/src/core/api-operations.ts +38 -3
  36. package/src/core/execution-operations.ts +73 -45
  37. package/src/core/in-process-session.ts +293 -0
  38. package/src/core/index.ts +1 -0
  39. package/src/core/session.ts +20 -1
  40. package/src/index.ts +2 -0
@@ -0,0 +1,1192 @@
1
+ 'use strict';
2
+
3
+ var atpProtocol = require('@mondaydotcomorg/atp-protocol');
4
+ var atpRuntime = require('@mondaydotcomorg/atp-runtime');
5
+
6
+ var __defProp = Object.defineProperty;
7
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
+ }) : x)(function(x) {
11
+ if (typeof require !== "undefined") return require.apply(this, arguments);
12
+ throw Error('Dynamic require of "' + x + '" is not supported');
13
+ });
14
+
15
+ // src/core/session.ts
16
+ var ClientSession = class {
17
+ static {
18
+ __name(this, "ClientSession");
19
+ }
20
+ baseUrl;
21
+ customHeaders;
22
+ clientId;
23
+ clientToken;
24
+ initPromise;
25
+ hooks;
26
+ constructor(baseUrl, headers, hooks) {
27
+ this.baseUrl = baseUrl;
28
+ this.customHeaders = headers || {};
29
+ this.hooks = hooks;
30
+ }
31
+ /**
32
+ * Initializes the client session with the server.
33
+ * This MUST be called before any other operations.
34
+ * The server generates and returns a unique client ID and token.
35
+ * @param clientInfo - Optional client information
36
+ * @param tools - Optional client tool definitions to register with the server
37
+ * @param services - Optional client service capabilities (LLM, approval, embedding)
38
+ */
39
+ async init(clientInfo, tools, services) {
40
+ if (this.initPromise) {
41
+ await this.initPromise;
42
+ return {
43
+ clientId: this.clientId,
44
+ token: this.clientToken,
45
+ expiresAt: 0,
46
+ tokenRotateAt: 0
47
+ };
48
+ }
49
+ this.initPromise = (async () => {
50
+ const url = `${this.baseUrl}/api/init`;
51
+ const body = JSON.stringify({
52
+ clientInfo,
53
+ tools: tools || [],
54
+ services
55
+ });
56
+ const headers = await this.prepareHeaders("POST", url, body);
57
+ const response = await fetch(url, {
58
+ method: "POST",
59
+ headers,
60
+ body
61
+ });
62
+ if (!response.ok) {
63
+ throw new Error(`Client initialization failed: ${response.status} ${response.statusText}`);
64
+ }
65
+ const data = await response.json();
66
+ this.clientId = data.clientId;
67
+ this.clientToken = data.token;
68
+ })();
69
+ await this.initPromise;
70
+ return {
71
+ clientId: this.clientId,
72
+ token: this.clientToken,
73
+ expiresAt: 0,
74
+ tokenRotateAt: 0
75
+ };
76
+ }
77
+ /**
78
+ * Gets the unique client ID.
79
+ */
80
+ getClientId() {
81
+ if (!this.clientId) {
82
+ throw new Error("Client not initialized. Call init() first.");
83
+ }
84
+ return this.clientId;
85
+ }
86
+ /**
87
+ * Ensures the client is initialized before making requests.
88
+ */
89
+ async ensureInitialized() {
90
+ if (!this.clientId) {
91
+ throw new Error("Client not initialized. Call init() first.");
92
+ }
93
+ }
94
+ /**
95
+ * Creates HTTP headers for requests.
96
+ */
97
+ getHeaders() {
98
+ const headers = {
99
+ "Content-Type": "application/json",
100
+ ...this.customHeaders
101
+ };
102
+ if (this.clientId) {
103
+ headers["X-Client-ID"] = this.clientId;
104
+ }
105
+ if (this.clientToken) {
106
+ headers["Authorization"] = `Bearer ${this.clientToken}`;
107
+ }
108
+ return headers;
109
+ }
110
+ getBaseUrl() {
111
+ return this.baseUrl;
112
+ }
113
+ /**
114
+ * Updates the client token from response headers (token refresh).
115
+ */
116
+ updateToken(response) {
117
+ const newToken = response.headers.get("X-ATP-Token");
118
+ if (newToken) {
119
+ this.clientToken = newToken;
120
+ }
121
+ }
122
+ /**
123
+ * Prepares headers for a request, calling preRequest hook if configured
124
+ */
125
+ async prepareHeaders(method, url, body) {
126
+ let headers = {
127
+ "Content-Type": "application/json",
128
+ ...this.customHeaders
129
+ };
130
+ if (this.clientId) {
131
+ headers["X-Client-ID"] = this.clientId;
132
+ }
133
+ if (this.clientToken) {
134
+ headers["Authorization"] = `Bearer ${this.clientToken}`;
135
+ }
136
+ if (this.hooks?.preRequest) {
137
+ try {
138
+ const result = await this.hooks.preRequest({
139
+ url,
140
+ method,
141
+ currentHeaders: headers,
142
+ body
143
+ });
144
+ if (result.abort) {
145
+ throw new Error(result.abortReason || "Request aborted by preRequest hook");
146
+ }
147
+ if (result.headers) {
148
+ headers = result.headers;
149
+ }
150
+ } catch (error) {
151
+ throw error;
152
+ }
153
+ }
154
+ return headers;
155
+ }
156
+ };
157
+
158
+ // src/core/in-process-session.ts
159
+ var InProcessSession = class {
160
+ static {
161
+ __name(this, "InProcessSession");
162
+ }
163
+ server;
164
+ clientId;
165
+ clientToken;
166
+ initialized = false;
167
+ initPromise;
168
+ constructor(server) {
169
+ this.server = server;
170
+ }
171
+ async init(clientInfo, tools, services) {
172
+ if (this.initPromise) {
173
+ await this.initPromise;
174
+ return {
175
+ clientId: this.clientId,
176
+ token: this.clientToken,
177
+ expiresAt: 0,
178
+ tokenRotateAt: 0
179
+ };
180
+ }
181
+ this.initPromise = (async () => {
182
+ await this.server.start();
183
+ const ctx = this.createContext({
184
+ method: "POST",
185
+ path: "/api/init",
186
+ body: {
187
+ clientInfo,
188
+ tools: tools || [],
189
+ services
190
+ }
191
+ });
192
+ const result = await this.server.handleInit(ctx);
193
+ this.clientId = result.clientId;
194
+ this.clientToken = result.token;
195
+ this.initialized = true;
196
+ })();
197
+ await this.initPromise;
198
+ return {
199
+ clientId: this.clientId,
200
+ token: this.clientToken,
201
+ expiresAt: 0,
202
+ tokenRotateAt: 0
203
+ };
204
+ }
205
+ getClientId() {
206
+ if (!this.clientId) {
207
+ throw new Error("Client not initialized. Call init() first.");
208
+ }
209
+ return this.clientId;
210
+ }
211
+ async ensureInitialized() {
212
+ if (!this.initialized) {
213
+ throw new Error("Client not initialized. Call init() first.");
214
+ }
215
+ }
216
+ getHeaders() {
217
+ const headers = {
218
+ "content-type": "application/json"
219
+ };
220
+ if (this.clientId) {
221
+ headers["x-client-id"] = this.clientId;
222
+ }
223
+ if (this.clientToken) {
224
+ headers["authorization"] = `Bearer ${this.clientToken}`;
225
+ }
226
+ return headers;
227
+ }
228
+ getBaseUrl() {
229
+ return "";
230
+ }
231
+ updateToken(_response) {
232
+ }
233
+ async prepareHeaders(_method, _url, _body) {
234
+ return this.getHeaders();
235
+ }
236
+ async getDefinitions(options) {
237
+ await this.ensureInitialized();
238
+ const ctx = this.createContext({
239
+ method: "GET",
240
+ path: "/api/definitions",
241
+ query: options?.apiGroups ? {
242
+ apiGroups: options.apiGroups.join(",")
243
+ } : {}
244
+ });
245
+ return await this.server.getDefinitions(ctx);
246
+ }
247
+ async getRuntimeDefinitions(options) {
248
+ await this.ensureInitialized();
249
+ const ctx = this.createContext({
250
+ method: "GET",
251
+ path: "/api/runtime",
252
+ query: options?.apis?.length ? {
253
+ apis: options.apis.join(",")
254
+ } : {}
255
+ });
256
+ return await this.server.getRuntimeDefinitions(ctx);
257
+ }
258
+ async getServerInfo() {
259
+ await this.ensureInitialized();
260
+ return this.server.getInfo();
261
+ }
262
+ async search(query, options) {
263
+ await this.ensureInitialized();
264
+ const ctx = this.createContext({
265
+ method: "POST",
266
+ path: "/api/search",
267
+ body: {
268
+ query,
269
+ ...options
270
+ }
271
+ });
272
+ return await this.server.handleSearch(ctx);
273
+ }
274
+ async explore(path) {
275
+ await this.ensureInitialized();
276
+ const ctx = this.createContext({
277
+ method: "POST",
278
+ path: "/api/explore",
279
+ body: {
280
+ path
281
+ }
282
+ });
283
+ return await this.server.handleExplore(ctx);
284
+ }
285
+ async execute(code, config) {
286
+ await this.ensureInitialized();
287
+ const ctx = this.createContext({
288
+ method: "POST",
289
+ path: "/api/execute",
290
+ body: {
291
+ code,
292
+ config
293
+ }
294
+ });
295
+ return await this.server.handleExecute(ctx);
296
+ }
297
+ async resume(executionId, callbackResult) {
298
+ await this.ensureInitialized();
299
+ const ctx = this.createContext({
300
+ method: "POST",
301
+ path: `/api/resume/${executionId}`,
302
+ body: {
303
+ result: callbackResult
304
+ }
305
+ });
306
+ return await this.server.handleResume(ctx, executionId);
307
+ }
308
+ async resumeWithBatchResults(executionId, batchResults) {
309
+ await this.ensureInitialized();
310
+ const ctx = this.createContext({
311
+ method: "POST",
312
+ path: `/api/resume/${executionId}`,
313
+ body: {
314
+ results: batchResults
315
+ }
316
+ });
317
+ return await this.server.handleResume(ctx, executionId);
318
+ }
319
+ createContext(options) {
320
+ const noopLogger = {
321
+ debug: /* @__PURE__ */ __name(() => {
322
+ }, "debug"),
323
+ info: /* @__PURE__ */ __name(() => {
324
+ }, "info"),
325
+ warn: /* @__PURE__ */ __name(() => {
326
+ }, "warn"),
327
+ error: /* @__PURE__ */ __name(() => {
328
+ }, "error")
329
+ };
330
+ return {
331
+ method: options.method,
332
+ path: options.path,
333
+ query: options.query || {},
334
+ headers: this.getHeaders(),
335
+ body: options.body,
336
+ clientId: this.clientId,
337
+ clientToken: this.clientToken,
338
+ logger: noopLogger,
339
+ status: 200,
340
+ responseBody: null,
341
+ throw: /* @__PURE__ */ __name((status, message) => {
342
+ const error = new Error(message);
343
+ error.status = status;
344
+ throw error;
345
+ }, "throw"),
346
+ assert: /* @__PURE__ */ __name((condition, message) => {
347
+ if (!condition) {
348
+ throw new Error(message);
349
+ }
350
+ }, "assert"),
351
+ set: /* @__PURE__ */ __name(() => {
352
+ }, "set")
353
+ };
354
+ }
355
+ };
356
+
357
+ // src/core/api-operations.ts
358
+ var APIOperations = class {
359
+ static {
360
+ __name(this, "APIOperations");
361
+ }
362
+ session;
363
+ inProcessSession;
364
+ apiDefinitions;
365
+ constructor(session, inProcessSession) {
366
+ this.session = session;
367
+ this.inProcessSession = inProcessSession;
368
+ }
369
+ /**
370
+ * Connects to the server and retrieves API definitions.
371
+ */
372
+ async connect(options) {
373
+ await this.session.ensureInitialized();
374
+ if (this.inProcessSession) {
375
+ const data2 = await this.inProcessSession.getDefinitions(options);
376
+ this.apiDefinitions = data2.typescript;
377
+ return {
378
+ serverVersion: data2.version,
379
+ capabilities: {},
380
+ apiGroups: data2.apiGroups
381
+ };
382
+ }
383
+ const params = new URLSearchParams();
384
+ if (options?.apiGroups) {
385
+ params.set("apiGroups", options.apiGroups.join(","));
386
+ }
387
+ const url = `${this.session.getBaseUrl()}/api/definitions?${params}`;
388
+ const headers = await this.session.prepareHeaders("GET", url);
389
+ const response = await fetch(url, {
390
+ headers
391
+ });
392
+ if (!response.ok) {
393
+ throw new Error(`Connection failed: ${response.status} ${response.statusText}`);
394
+ }
395
+ const data = await response.json();
396
+ this.apiDefinitions = data.typescript;
397
+ return {
398
+ serverVersion: data.version,
399
+ capabilities: {},
400
+ apiGroups: data.apiGroups
401
+ };
402
+ }
403
+ /**
404
+ * Gets the TypeScript type definitions for available APIs.
405
+ */
406
+ getTypeDefinitions() {
407
+ if (!this.apiDefinitions) {
408
+ throw new Error("Not connected. Call connect() first.");
409
+ }
410
+ return this.apiDefinitions;
411
+ }
412
+ /**
413
+ * Searches for available API functions.
414
+ */
415
+ async searchAPI(query, options) {
416
+ await this.session.ensureInitialized();
417
+ if (this.inProcessSession) {
418
+ const data2 = await this.inProcessSession.search(query, options);
419
+ return data2.results;
420
+ }
421
+ const url = `${this.session.getBaseUrl()}/api/search`;
422
+ const body = JSON.stringify({
423
+ query,
424
+ ...options
425
+ });
426
+ const headers = await this.session.prepareHeaders("POST", url, body);
427
+ const response = await fetch(url, {
428
+ method: "POST",
429
+ headers,
430
+ body
431
+ });
432
+ if (!response.ok) {
433
+ throw new Error(`Search failed: ${response.status} ${response.statusText}`);
434
+ }
435
+ const data = await response.json();
436
+ return data.results;
437
+ }
438
+ /**
439
+ * Explores the API filesystem at the given path.
440
+ */
441
+ async exploreAPI(path) {
442
+ await this.session.ensureInitialized();
443
+ if (this.inProcessSession) {
444
+ return await this.inProcessSession.explore(path);
445
+ }
446
+ const url = `${this.session.getBaseUrl()}/api/explore`;
447
+ const body = JSON.stringify({
448
+ path
449
+ });
450
+ const headers = await this.session.prepareHeaders("POST", url, body);
451
+ const response = await fetch(url, {
452
+ method: "POST",
453
+ headers,
454
+ body
455
+ });
456
+ if (!response.ok) {
457
+ throw new Error(`Explore failed: ${response.status} ${response.statusText}`);
458
+ }
459
+ return await response.json();
460
+ }
461
+ /**
462
+ * Gets information about the server.
463
+ */
464
+ async getServerInfo() {
465
+ await this.session.ensureInitialized();
466
+ if (this.inProcessSession) {
467
+ return await this.inProcessSession.getServerInfo();
468
+ }
469
+ const url = `${this.session.getBaseUrl()}/api/info`;
470
+ const headers = await this.session.prepareHeaders("GET", url);
471
+ const response = await fetch(url, {
472
+ headers
473
+ });
474
+ if (!response.ok) {
475
+ throw new Error(`Failed to get server info: ${response.status}`);
476
+ }
477
+ return await response.json();
478
+ }
479
+ /**
480
+ * Gets ATP runtime API definitions as TypeScript declarations.
481
+ * Returns the full TypeScript definitions for atp.llm.*, atp.cache.*, etc.
482
+ * These are the APIs available during code execution.
483
+ *
484
+ * Behavior:
485
+ * - No options: Returns APIs based on client capabilities (default filtering)
486
+ * - apis: ['llm', 'cache']: Returns only specified APIs (intersection with client capabilities)
487
+ * - apis: []: Returns all APIs regardless of client capabilities
488
+ *
489
+ * @param options - Optional filtering options
490
+ * @param options.apis - Specific APIs to include (e.g., ['llm', 'cache', 'approval'])
491
+ */
492
+ async getRuntimeDefinitions(options) {
493
+ await this.session.ensureInitialized();
494
+ if (this.inProcessSession) {
495
+ return await this.inProcessSession.getRuntimeDefinitions(options?.apis ? {
496
+ apis: options.apis
497
+ } : void 0);
498
+ }
499
+ const params = new URLSearchParams();
500
+ if (options?.apis && options.apis.length > 0) {
501
+ params.set("apis", options.apis.join(","));
502
+ }
503
+ const url = `${this.session.getBaseUrl()}/api/runtime${params.toString() ? `?${params}` : ""}`;
504
+ const headers = await this.session.prepareHeaders("GET", url);
505
+ const response = await fetch(url, {
506
+ headers
507
+ });
508
+ if (!response.ok) {
509
+ throw new Error(`Failed to get runtime definitions: ${response.status}`);
510
+ }
511
+ return await response.text();
512
+ }
513
+ };
514
+
515
+ // src/errors.ts
516
+ var ClientCallbackError = class extends Error {
517
+ static {
518
+ __name(this, "ClientCallbackError");
519
+ }
520
+ constructor(message) {
521
+ super(message);
522
+ this.name = "ClientCallbackError";
523
+ }
524
+ };
525
+
526
+ // src/core/provenance-registry.ts
527
+ var ProvenanceTokenRegistry = class {
528
+ static {
529
+ __name(this, "ProvenanceTokenRegistry");
530
+ }
531
+ cache = /* @__PURE__ */ new Map();
532
+ maxSize;
533
+ ttl;
534
+ sequenceCounter = 0;
535
+ constructor(maxSize = 1e4, ttlHours = 1) {
536
+ this.maxSize = maxSize;
537
+ this.ttl = ttlHours * 3600 * 1e3;
538
+ }
539
+ /**
540
+ * Add a token to the registry
541
+ */
542
+ add(token) {
543
+ this.evictExpired();
544
+ if (this.cache.size >= this.maxSize) {
545
+ this.evictLRU();
546
+ }
547
+ this.cache.set(token, {
548
+ token,
549
+ addedAt: Date.now(),
550
+ sequence: this.sequenceCounter++
551
+ });
552
+ }
553
+ /**
554
+ * Get recent tokens (non-expired, sorted by age, limited)
555
+ * Returns tokens in chronological order (oldest first, most recent last)
556
+ */
557
+ getRecentTokens(maxCount = 1e3) {
558
+ if (maxCount <= 0) {
559
+ return [];
560
+ }
561
+ this.evictExpired();
562
+ const now = Date.now();
563
+ const expiredTokens = [];
564
+ const entries = Array.from(this.cache.values()).filter((entry) => {
565
+ try {
566
+ const [body] = entry.token.split(".");
567
+ if (!body) {
568
+ expiredTokens.push(entry.token);
569
+ return false;
570
+ }
571
+ const payload = JSON.parse(Buffer.from(body, "base64url").toString());
572
+ if (!payload.expiresAt || payload.expiresAt <= now) {
573
+ expiredTokens.push(entry.token);
574
+ return false;
575
+ }
576
+ return true;
577
+ } catch {
578
+ expiredTokens.push(entry.token);
579
+ return false;
580
+ }
581
+ }).sort((a, b) => a.sequence - b.sequence).slice(-maxCount);
582
+ for (const token of expiredTokens) {
583
+ this.cache.delete(token);
584
+ }
585
+ return entries.map((e) => e.token);
586
+ }
587
+ /**
588
+ * Clear all tokens
589
+ */
590
+ clear() {
591
+ this.cache.clear();
592
+ }
593
+ /**
594
+ * Get registry size
595
+ */
596
+ size() {
597
+ return this.cache.size;
598
+ }
599
+ /**
600
+ * Evict expired tokens
601
+ */
602
+ evictExpired() {
603
+ const now = Date.now();
604
+ const toDelete = [];
605
+ for (const [token, entry] of this.cache.entries()) {
606
+ if (now - entry.addedAt > this.ttl) {
607
+ toDelete.push(token);
608
+ }
609
+ }
610
+ for (const token of toDelete) {
611
+ this.cache.delete(token);
612
+ }
613
+ }
614
+ /**
615
+ * Evict least recently used (oldest) token
616
+ */
617
+ evictLRU() {
618
+ let oldestToken = null;
619
+ let oldestSequence = Infinity;
620
+ for (const [token, entry] of this.cache.entries()) {
621
+ if (entry.sequence < oldestSequence) {
622
+ oldestSequence = entry.sequence;
623
+ oldestToken = token;
624
+ }
625
+ }
626
+ if (oldestToken) {
627
+ this.cache.delete(oldestToken);
628
+ }
629
+ }
630
+ };
631
+
632
+ // src/core/execution-operations.ts
633
+ var ExecutionOperations = class {
634
+ static {
635
+ __name(this, "ExecutionOperations");
636
+ }
637
+ session;
638
+ inProcessSession;
639
+ serviceProviders;
640
+ tokenRegistry;
641
+ lastExecutionConfig = null;
642
+ constructor(session, serviceProviders, inProcessSession) {
643
+ this.session = session;
644
+ this.inProcessSession = inProcessSession;
645
+ this.serviceProviders = serviceProviders;
646
+ this.tokenRegistry = new ProvenanceTokenRegistry();
647
+ }
648
+ /**
649
+ * Executes code on the server with real-time progress updates via SSE.
650
+ */
651
+ async executeStream(code, config, onProgress) {
652
+ await this.session.ensureInitialized();
653
+ const url = `${this.session.getBaseUrl()}/api/execute/stream`;
654
+ const body = JSON.stringify({
655
+ code,
656
+ config
657
+ });
658
+ const headers = await this.session.prepareHeaders("POST", url, body);
659
+ return new Promise((resolve, reject) => {
660
+ const fetchImpl = typeof fetch !== "undefined" ? fetch : __require("undici").fetch;
661
+ fetchImpl(url, {
662
+ method: "POST",
663
+ headers,
664
+ body
665
+ }).then(async (response) => {
666
+ if (!response.ok) {
667
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
668
+ }
669
+ const reader = response.body?.getReader();
670
+ if (!reader) {
671
+ throw new Error("Response body is not readable");
672
+ }
673
+ const decoder = new TextDecoder();
674
+ let buffer = "";
675
+ let result = null;
676
+ while (true) {
677
+ const { done, value } = await reader.read();
678
+ if (done) break;
679
+ buffer += decoder.decode(value, {
680
+ stream: true
681
+ });
682
+ const lines = buffer.split("\n");
683
+ buffer = lines.pop() || "";
684
+ for (let i = 0; i < lines.length; i++) {
685
+ const line = lines[i];
686
+ if (line && line.startsWith("event:")) {
687
+ const event = line.substring(6).trim();
688
+ for (let j = i + 1; j < lines.length; j++) {
689
+ const dataLine = lines[j];
690
+ if (dataLine && dataLine.startsWith("data:")) {
691
+ const dataStr = dataLine.substring(5).trim();
692
+ if (dataStr) {
693
+ try {
694
+ const data = JSON.parse(dataStr);
695
+ if (event === "progress" && onProgress) {
696
+ onProgress(data.message, data.fraction);
697
+ } else if (event === "result") {
698
+ result = data;
699
+ } else if (event === "error") {
700
+ reject(new Error(data.message));
701
+ return;
702
+ }
703
+ } catch (e) {
704
+ atpRuntime.log.error("Failed to parse SSE data", {
705
+ dataStr,
706
+ error: e
707
+ });
708
+ }
709
+ }
710
+ break;
711
+ }
712
+ }
713
+ }
714
+ }
715
+ }
716
+ if (result) {
717
+ resolve(result);
718
+ } else {
719
+ reject(new Error("No result received from server"));
720
+ }
721
+ }).catch(reject);
722
+ });
723
+ }
724
+ /**
725
+ * Executes code on the server in a sandboxed environment.
726
+ */
727
+ async execute(code, config) {
728
+ await this.session.ensureInitialized();
729
+ const hints = this.tokenRegistry.getRecentTokens(1e3);
730
+ const detectedClientServices = {
731
+ hasLLM: !!this.serviceProviders.getLLM(),
732
+ hasApproval: !!this.serviceProviders.getApproval(),
733
+ hasEmbedding: !!this.serviceProviders.getEmbedding(),
734
+ hasTools: this.serviceProviders.hasTools()
735
+ };
736
+ const executionConfig = {
737
+ ...config,
738
+ clientServices: {
739
+ ...detectedClientServices,
740
+ ...config?.clientServices || {}
741
+ },
742
+ provenanceHints: hints.length > 0 ? hints : void 0
743
+ };
744
+ this.lastExecutionConfig = executionConfig;
745
+ let result;
746
+ if (this.inProcessSession) {
747
+ result = await this.inProcessSession.execute(code, executionConfig);
748
+ } else {
749
+ const url = `${this.session.getBaseUrl()}/api/execute`;
750
+ const body = JSON.stringify({
751
+ code,
752
+ config: executionConfig
753
+ });
754
+ const headers = await this.session.prepareHeaders("POST", url, body);
755
+ const response = await fetch(url, {
756
+ method: "POST",
757
+ headers,
758
+ body
759
+ });
760
+ this.session.updateToken(response);
761
+ if (!response.ok) {
762
+ const error = await response.json();
763
+ throw new Error(`Execution failed: ${error.error || response.statusText}`);
764
+ }
765
+ result = await response.json();
766
+ }
767
+ if (result.provenanceTokens && result.provenanceTokens.length > 0) {
768
+ for (const { token } of result.provenanceTokens) {
769
+ this.tokenRegistry.add(token);
770
+ }
771
+ }
772
+ if (result.status === atpProtocol.ExecutionStatus.PAUSED && result.needsCallbacks) {
773
+ return await this.handleBatchCallbacksAndResume(result);
774
+ }
775
+ if (result.status === atpProtocol.ExecutionStatus.PAUSED && result.needsCallback) {
776
+ return await this.handlePauseAndResume(result);
777
+ }
778
+ return result;
779
+ }
780
+ /**
781
+ * Handles batch callbacks by executing them in parallel and resuming.
782
+ */
783
+ async handleBatchCallbacksAndResume(pausedResult) {
784
+ if (!pausedResult.needsCallbacks || pausedResult.needsCallbacks.length === 0) {
785
+ throw new Error("No batch callback requests in paused execution");
786
+ }
787
+ const missingServiceIds = new Set(pausedResult.needsCallbacks.filter((cb) => !this.serviceProviders.hasServiceForCallback(cb.type)).map((cb) => cb.id));
788
+ if (missingServiceIds.size > 0) {
789
+ const missingServices = pausedResult.needsCallbacks.filter((cb) => missingServiceIds.has(cb.id));
790
+ const explicitlyRequestedMissing = missingServices.filter((cb) => this.wasServiceExplicitlyRequested(cb.type));
791
+ const unexpectedMissing = missingServices.filter((cb) => !this.wasServiceExplicitlyRequested(cb.type));
792
+ if (explicitlyRequestedMissing.length > 0) {
793
+ return pausedResult;
794
+ }
795
+ const errorMessage = `Missing service providers for callback types: ${unexpectedMissing.map((cb) => cb.type).join(", ")}`;
796
+ atpRuntime.log.error(`Auto-handling batch paused execution without service providers: ${errorMessage}`, {
797
+ executionId: pausedResult.executionId,
798
+ missingServices: unexpectedMissing.map((cb) => ({
799
+ type: cb.type,
800
+ operation: cb.operation,
801
+ id: cb.id
802
+ }))
803
+ });
804
+ const existingCallbacks = pausedResult.needsCallbacks.filter((cb) => !missingServiceIds.has(cb.id));
805
+ if (existingCallbacks.length > 0) {
806
+ try {
807
+ const existingResults = await Promise.all(existingCallbacks.map(async (cb) => {
808
+ const callbackResult = await this.serviceProviders.handleCallback(cb.type, {
809
+ ...cb.payload,
810
+ operation: cb.operation
811
+ });
812
+ return {
813
+ id: cb.id,
814
+ result: callbackResult
815
+ };
816
+ }));
817
+ const allResults = pausedResult.needsCallbacks.map((cb) => {
818
+ if (missingServiceIds.has(cb.id)) {
819
+ return {
820
+ id: cb.id,
821
+ result: {
822
+ __error: true,
823
+ message: `${cb.type} service not provided by client`
824
+ }
825
+ };
826
+ }
827
+ return existingResults.find((r) => r.id === cb.id);
828
+ });
829
+ return await this.resumeWithBatchResults(pausedResult.executionId, allResults);
830
+ } catch (error) {
831
+ const errorMessage2 = error instanceof Error ? error.message : String(error);
832
+ atpRuntime.log.error(`Error handling existing services in batch: ${errorMessage2}`, {
833
+ executionId: pausedResult.executionId
834
+ });
835
+ const allErrorResults = pausedResult.needsCallbacks.map((cb) => ({
836
+ id: cb.id,
837
+ result: {
838
+ __error: true,
839
+ message: missingServiceIds.has(cb.id) ? `${cb.type} service not provided by client` : errorMessage2
840
+ }
841
+ }));
842
+ return await this.resumeWithBatchResults(pausedResult.executionId, allErrorResults);
843
+ }
844
+ } else {
845
+ const allErrorResults = pausedResult.needsCallbacks.map((cb) => ({
846
+ id: cb.id,
847
+ result: {
848
+ __error: true,
849
+ message: `${cb.type} service not provided by client`
850
+ }
851
+ }));
852
+ return await this.resumeWithBatchResults(pausedResult.executionId, allErrorResults);
853
+ }
854
+ }
855
+ try {
856
+ const batchResults = await Promise.all(pausedResult.needsCallbacks.map(async (cb) => {
857
+ const callbackResult = await this.serviceProviders.handleCallback(cb.type, {
858
+ ...cb.payload,
859
+ operation: cb.operation
860
+ });
861
+ return {
862
+ id: cb.id,
863
+ result: callbackResult
864
+ };
865
+ }));
866
+ return await this.resumeWithBatchResults(pausedResult.executionId, batchResults);
867
+ } catch (error) {
868
+ const errorMessage = error instanceof Error ? error.message : String(error);
869
+ atpRuntime.log.error(`Error handling batch callbacks: ${errorMessage}`, {
870
+ executionId: pausedResult.executionId,
871
+ callbackCount: pausedResult.needsCallbacks.length
872
+ });
873
+ const allErrorResults = pausedResult.needsCallbacks.map((cb) => ({
874
+ id: cb.id,
875
+ result: {
876
+ __error: true,
877
+ message: errorMessage
878
+ }
879
+ }));
880
+ return await this.resumeWithBatchResults(pausedResult.executionId, allErrorResults);
881
+ }
882
+ }
883
+ /**
884
+ * Handles a paused execution by processing the callback and resuming.
885
+ */
886
+ async handlePauseAndResume(pausedResult) {
887
+ if (!pausedResult.needsCallback) {
888
+ throw new Error("No callback request in paused execution");
889
+ }
890
+ if (!this.serviceProviders.hasServiceForCallback(pausedResult.needsCallback.type)) {
891
+ const wasExplicitlyRequested = this.wasServiceExplicitlyRequested(pausedResult.needsCallback.type);
892
+ if (wasExplicitlyRequested) {
893
+ return pausedResult;
894
+ }
895
+ const errorMessage = `${pausedResult.needsCallback.type} service not provided by client`;
896
+ atpRuntime.log.error(`Auto-handling paused execution without service provider: ${errorMessage}`, {
897
+ executionId: pausedResult.executionId,
898
+ callbackType: pausedResult.needsCallback.type,
899
+ operation: pausedResult.needsCallback.operation
900
+ });
901
+ return await this.resume(pausedResult.executionId, {
902
+ __error: true,
903
+ message: errorMessage
904
+ });
905
+ }
906
+ try {
907
+ const callbackResult = await this.serviceProviders.handleCallback(pausedResult.needsCallback.type, {
908
+ ...pausedResult.needsCallback.payload,
909
+ operation: pausedResult.needsCallback.operation,
910
+ executionId: pausedResult.executionId
911
+ });
912
+ return await this.resume(pausedResult.executionId, callbackResult);
913
+ } catch (error) {
914
+ if (error instanceof ClientCallbackError) {
915
+ throw error;
916
+ }
917
+ const errorMessage = error instanceof Error ? error.message : String(error);
918
+ atpRuntime.log.error(`Error handling callback: ${errorMessage}`, {
919
+ executionId: pausedResult.executionId,
920
+ callbackType: pausedResult.needsCallback.type,
921
+ operation: pausedResult.needsCallback.operation
922
+ });
923
+ return await this.resume(pausedResult.executionId, {
924
+ __error: true,
925
+ message: errorMessage
926
+ });
927
+ }
928
+ }
929
+ /**
930
+ * Check if a service was explicitly requested in clientServices config
931
+ */
932
+ wasServiceExplicitlyRequested(callbackType) {
933
+ if (!this.lastExecutionConfig?.clientServices) {
934
+ return false;
935
+ }
936
+ switch (callbackType) {
937
+ case atpProtocol.CallbackType.LLM:
938
+ return this.lastExecutionConfig.clientServices.hasLLM;
939
+ case atpProtocol.CallbackType.APPROVAL:
940
+ return this.lastExecutionConfig.clientServices.hasApproval;
941
+ case atpProtocol.CallbackType.EMBEDDING:
942
+ return this.lastExecutionConfig.clientServices.hasEmbedding;
943
+ case atpProtocol.CallbackType.TOOL:
944
+ return this.lastExecutionConfig.clientServices.hasTools;
945
+ default:
946
+ return false;
947
+ }
948
+ }
949
+ /**
950
+ * Resumes a paused execution with a callback result.
951
+ */
952
+ async resume(executionId, callbackResult) {
953
+ await this.session.ensureInitialized();
954
+ let result;
955
+ if (this.inProcessSession) {
956
+ result = await this.inProcessSession.resume(executionId, callbackResult);
957
+ } else {
958
+ const url = `${this.session.getBaseUrl()}/api/resume/${executionId}`;
959
+ const body = JSON.stringify({
960
+ result: callbackResult
961
+ });
962
+ const headers = await this.session.prepareHeaders("POST", url, body);
963
+ const response = await fetch(url, {
964
+ method: "POST",
965
+ headers,
966
+ body
967
+ });
968
+ this.session.updateToken(response);
969
+ if (!response.ok) {
970
+ const error = await response.json();
971
+ throw new Error(`Resume failed: ${error.error || response.statusText}`);
972
+ }
973
+ result = await response.json();
974
+ }
975
+ if (result.provenanceTokens && result.provenanceTokens.length > 0) {
976
+ for (const { token } of result.provenanceTokens) {
977
+ this.tokenRegistry.add(token);
978
+ }
979
+ }
980
+ if (result.status === atpProtocol.ExecutionStatus.PAUSED && result.needsCallbacks) {
981
+ return await this.handleBatchCallbacksAndResume(result);
982
+ }
983
+ if (result.status === atpProtocol.ExecutionStatus.PAUSED && result.needsCallback) {
984
+ return await this.handlePauseAndResume(result);
985
+ }
986
+ return result;
987
+ }
988
+ /**
989
+ * Resumes a paused execution with batch callback results.
990
+ */
991
+ async resumeWithBatchResults(executionId, batchResults) {
992
+ await this.session.ensureInitialized();
993
+ let result;
994
+ if (this.inProcessSession) {
995
+ result = await this.inProcessSession.resumeWithBatchResults(executionId, batchResults);
996
+ } else {
997
+ const url = `${this.session.getBaseUrl()}/api/resume/${executionId}`;
998
+ const body = JSON.stringify({
999
+ results: batchResults
1000
+ });
1001
+ const headers = await this.session.prepareHeaders("POST", url, body);
1002
+ const response = await fetch(url, {
1003
+ method: "POST",
1004
+ headers,
1005
+ body
1006
+ });
1007
+ this.session.updateToken(response);
1008
+ if (!response.ok) {
1009
+ const error = await response.json();
1010
+ throw new Error(`Batch resume failed: ${error.error || response.statusText}`);
1011
+ }
1012
+ result = await response.json();
1013
+ }
1014
+ if (result.provenanceTokens && result.provenanceTokens.length > 0) {
1015
+ for (const { token } of result.provenanceTokens) {
1016
+ this.tokenRegistry.add(token);
1017
+ }
1018
+ }
1019
+ if (result.status === atpProtocol.ExecutionStatus.PAUSED && result.needsCallbacks) {
1020
+ return await this.handleBatchCallbacksAndResume(result);
1021
+ }
1022
+ if (result.status === atpProtocol.ExecutionStatus.PAUSED && result.needsCallback) {
1023
+ return await this.handlePauseAndResume(result);
1024
+ }
1025
+ return result;
1026
+ }
1027
+ };
1028
+ var LLMOperation = {
1029
+ CALL: "call",
1030
+ EXTRACT: "extract",
1031
+ CLASSIFY: "classify"
1032
+ };
1033
+ var EmbeddingOperation = {
1034
+ EMBED: "embed",
1035
+ SEARCH: "search"
1036
+ };
1037
+ var ServiceProviders = class {
1038
+ static {
1039
+ __name(this, "ServiceProviders");
1040
+ }
1041
+ providers = {};
1042
+ toolHandlers = /* @__PURE__ */ new Map();
1043
+ constructor(providers) {
1044
+ this.providers = providers || {};
1045
+ if (providers?.tools) {
1046
+ for (const tool of providers.tools) {
1047
+ this.toolHandlers.set(tool.name, tool.handler);
1048
+ }
1049
+ }
1050
+ }
1051
+ provideLLM(handler) {
1052
+ this.providers.llm = handler;
1053
+ }
1054
+ provideApproval(handler) {
1055
+ this.providers.approval = handler;
1056
+ }
1057
+ provideEmbedding(handler) {
1058
+ this.providers.embedding = handler;
1059
+ }
1060
+ provideTools(tools) {
1061
+ this.providers.tools = tools;
1062
+ for (const tool of tools) {
1063
+ this.toolHandlers.set(tool.name, tool.handler);
1064
+ }
1065
+ }
1066
+ getLLM() {
1067
+ return this.providers.llm;
1068
+ }
1069
+ getApproval() {
1070
+ return this.providers.approval;
1071
+ }
1072
+ getEmbedding() {
1073
+ return this.providers.embedding;
1074
+ }
1075
+ getTools() {
1076
+ return this.providers.tools;
1077
+ }
1078
+ /**
1079
+ * Get tool definitions (without handlers) for sending to server
1080
+ */
1081
+ getToolDefinitions() {
1082
+ if (!this.providers.tools) {
1083
+ return [];
1084
+ }
1085
+ return this.providers.tools.map((tool) => {
1086
+ const { handler, ...definition } = tool;
1087
+ return definition;
1088
+ });
1089
+ }
1090
+ /**
1091
+ * Check if client has tools
1092
+ */
1093
+ hasTools() {
1094
+ return !!(this.providers.tools && this.providers.tools.length > 0);
1095
+ }
1096
+ /**
1097
+ * Check if client has any services or tools
1098
+ */
1099
+ hasAnyServices() {
1100
+ return !!(this.providers.llm || this.providers.approval || this.providers.embedding || this.hasTools());
1101
+ }
1102
+ /**
1103
+ * Check if client has a service for a specific callback type
1104
+ */
1105
+ hasServiceForCallback(callbackType) {
1106
+ switch (callbackType) {
1107
+ case atpProtocol.CallbackType.LLM:
1108
+ return !!this.providers.llm;
1109
+ case atpProtocol.CallbackType.APPROVAL:
1110
+ return !!this.providers.approval;
1111
+ case atpProtocol.CallbackType.EMBEDDING:
1112
+ return !!this.providers.embedding;
1113
+ case atpProtocol.CallbackType.TOOL:
1114
+ return this.hasTools();
1115
+ default:
1116
+ return false;
1117
+ }
1118
+ }
1119
+ async handleCallback(callbackType, payload) {
1120
+ if (payload.operation === "batch_parallel" && payload.calls) {
1121
+ return await Promise.all(payload.calls.map(async (call) => {
1122
+ return await this.handleCallback(call.type, {
1123
+ ...call.payload,
1124
+ operation: call.operation
1125
+ });
1126
+ }));
1127
+ }
1128
+ switch (callbackType) {
1129
+ case atpProtocol.CallbackType.LLM:
1130
+ if (!this.providers.llm) {
1131
+ throw new Error("LLM service not provided by client");
1132
+ }
1133
+ if (payload.operation === LLMOperation.CALL) {
1134
+ return await this.providers.llm.call(payload.prompt, payload.options);
1135
+ } else if (payload.operation === LLMOperation.EXTRACT && this.providers.llm.extract) {
1136
+ return await this.providers.llm.extract(payload.prompt, payload.schema, payload.options);
1137
+ } else if (payload.operation === LLMOperation.CLASSIFY && this.providers.llm.classify) {
1138
+ return await this.providers.llm.classify(payload.text, payload.categories, payload.options);
1139
+ }
1140
+ throw new Error(`Unsupported LLM operation: ${payload.operation}`);
1141
+ case atpProtocol.CallbackType.APPROVAL:
1142
+ if (!this.providers.approval) {
1143
+ throw new Error("Approval service not provided by client");
1144
+ }
1145
+ const contextWithExecutionId = payload.context ? {
1146
+ ...payload.context,
1147
+ executionId: payload.executionId
1148
+ } : {
1149
+ executionId: payload.executionId
1150
+ };
1151
+ return await this.providers.approval.request(payload.message, contextWithExecutionId);
1152
+ case atpProtocol.CallbackType.EMBEDDING:
1153
+ if (!this.providers.embedding) {
1154
+ throw new Error("Embedding service not provided by client");
1155
+ }
1156
+ if (payload.operation === EmbeddingOperation.EMBED) {
1157
+ return await this.providers.embedding.embed(payload.text);
1158
+ } else if (payload.operation === EmbeddingOperation.SEARCH) {
1159
+ const queryEmbedding = await this.providers.embedding.embed(payload.query);
1160
+ return queryEmbedding;
1161
+ } else if (payload.operation === "similarity" && this.providers.embedding.similarity) {
1162
+ return await this.providers.embedding.similarity(payload.text1, payload.text2);
1163
+ }
1164
+ throw new Error(`Unsupported embedding operation: ${payload.operation}`);
1165
+ case atpProtocol.CallbackType.TOOL:
1166
+ if (payload.operation === atpProtocol.ToolOperation.CALL) {
1167
+ const toolName = payload.toolName;
1168
+ const handler = this.toolHandlers.get(toolName);
1169
+ if (!handler) {
1170
+ throw new Error(`Tool '${toolName}' not found in client tools`);
1171
+ }
1172
+ const result = await handler(payload.input);
1173
+ return result;
1174
+ }
1175
+ throw new Error(`Unsupported tool operation: ${payload.operation}`);
1176
+ default:
1177
+ throw new Error(`Unknown callback type: ${callbackType}`);
1178
+ }
1179
+ }
1180
+ };
1181
+
1182
+ Object.defineProperty(exports, "CallbackType", {
1183
+ enumerable: true,
1184
+ get: function () { return atpProtocol.CallbackType; }
1185
+ });
1186
+ exports.APIOperations = APIOperations;
1187
+ exports.ClientSession = ClientSession;
1188
+ exports.ExecutionOperations = ExecutionOperations;
1189
+ exports.InProcessSession = InProcessSession;
1190
+ exports.ServiceProviders = ServiceProviders;
1191
+ //# sourceMappingURL=index.cjs.map
1192
+ //# sourceMappingURL=index.cjs.map