@mondaydotcomorg/atp-langchain 0.20.2 → 0.20.3

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.
package/dist/index.js CHANGED
@@ -1,6 +1,580 @@
1
- export { createATPTools as createATPToolsBasic, convertToLangChainTools } from './tools.js';
2
- export * from './langgraph-client.js';
3
- export { createATPTools, createSimpleATPTool, } from './langgraph-tools.js';
4
- export { createLangChainEventHandler, createCallbackManagerHandler, } from './event-adapter.js';
5
- export * from './node.js';
1
+ import { ClientCallbackError, AgentToolProtocolClient, createToolsFromATPClient, ToolNames } from '@mondaydotcomorg/atp-client';
2
+ import { DynamicTool, Tool, DynamicStructuredTool } from '@langchain/core/tools';
3
+ import { log } from '@mondaydotcomorg/atp-runtime';
4
+ import { SystemMessage, HumanMessage } from '@langchain/core/messages';
5
+ import { ExecutionStatus, ATPEventType } from '@mondaydotcomorg/atp-protocol';
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
+ async function createATPTools(serverUrl, headers, hooks) {
10
+ const client = new AgentToolProtocolClient({
11
+ baseUrl: serverUrl,
12
+ headers,
13
+ hooks
14
+ });
15
+ await client.connect();
16
+ const atpTools = createToolsFromATPClient(client);
17
+ const tools = atpTools.map((tool) => new DynamicTool({
18
+ name: tool.name,
19
+ description: tool.description || "",
20
+ func: tool.func
21
+ }));
22
+ return {
23
+ client,
24
+ tools
25
+ };
26
+ }
27
+ __name(createATPTools, "createATPTools");
28
+ function convertToLangChainTools(tools) {
29
+ return tools.map((tool) => new DynamicTool({
30
+ name: tool.name,
31
+ description: tool.description || "",
32
+ func: tool.func
33
+ }));
34
+ }
35
+ __name(convertToLangChainTools, "convertToLangChainTools");
36
+ var ApprovalRequiredException = class extends ClientCallbackError {
37
+ static {
38
+ __name(this, "ApprovalRequiredException");
39
+ }
40
+ approvalRequest;
41
+ constructor(approvalRequest) {
42
+ super(`Approval required: ${approvalRequest.message}`);
43
+ this.approvalRequest = approvalRequest;
44
+ this.name = "ApprovalRequiredException";
45
+ }
46
+ };
47
+ var LangGraphATPClient = class {
48
+ static {
49
+ __name(this, "LangGraphATPClient");
50
+ }
51
+ client;
52
+ llm;
53
+ embeddings;
54
+ useLangGraphInterrupts;
55
+ directApprovalHandler;
56
+ pendingApprovals = /* @__PURE__ */ new Map();
57
+ constructor(options) {
58
+ const { serverUrl, headers, llm, embeddings, tools, useLangGraphInterrupts = true, approvalHandler, hooks } = options;
59
+ this.client = new AgentToolProtocolClient({
60
+ baseUrl: serverUrl,
61
+ headers,
62
+ hooks,
63
+ serviceProviders: tools ? {
64
+ tools
65
+ } : void 0
66
+ });
67
+ this.llm = llm;
68
+ this.embeddings = embeddings;
69
+ this.useLangGraphInterrupts = useLangGraphInterrupts;
70
+ this.directApprovalHandler = approvalHandler;
71
+ this.client.provideLLM({
72
+ call: /* @__PURE__ */ __name(async (prompt, options2) => {
73
+ return await this.handleLLMCall(prompt, options2);
74
+ }, "call"),
75
+ extract: /* @__PURE__ */ __name(async (prompt, schema, options2) => {
76
+ return await this.handleLLMExtract(prompt, schema, options2);
77
+ }, "extract"),
78
+ classify: /* @__PURE__ */ __name(async (text, categories, options2) => {
79
+ return await this.handleLLMClassify(text, categories, options2);
80
+ }, "classify")
81
+ });
82
+ if (this.embeddings) {
83
+ this.client.provideEmbedding({
84
+ embed: /* @__PURE__ */ __name(async (text) => {
85
+ return await this.handleEmbedding(text);
86
+ }, "embed")
87
+ });
88
+ }
89
+ this.client.provideApproval({
90
+ request: /* @__PURE__ */ __name(async (message, context) => {
91
+ return await this.handleApprovalRequest(message, context);
92
+ }, "request")
93
+ });
94
+ }
95
+ /**
96
+ * Initialize the client connection
97
+ */
98
+ async connect() {
99
+ await this.client.init({
100
+ name: "langgraph-atp-client",
101
+ version: "1.0.0"
102
+ });
103
+ await this.client.connect();
104
+ }
105
+ /**
106
+ * Get TypeScript API definitions
107
+ */
108
+ getTypeDefinitions() {
109
+ return this.client.getTypeDefinitions();
110
+ }
111
+ /**
112
+ * Execute ATP code with LangGraph interrupt support
113
+ *
114
+ * When approval is needed:
115
+ * - If useLangGraphInterrupts=true: Throws ApprovalRequiredException
116
+ * - If useLangGraphInterrupts=false: Uses direct approval handler
117
+ *
118
+ * @throws ApprovalRequiredException when approval is needed (interrupt mode)
119
+ */
120
+ async execute(code, config) {
121
+ const result = await this.client.execute(code, config);
122
+ return {
123
+ result,
124
+ needsApproval: false
125
+ };
126
+ }
127
+ /**
128
+ * Resume execution after approval decision
129
+ *
130
+ * Call this after LangGraph resumes from interrupt with approval decision.
131
+ */
132
+ async resumeWithApproval(executionId, approved, reason) {
133
+ const approvalResponse = {
134
+ approved,
135
+ reason,
136
+ timestamp: Date.now()
137
+ };
138
+ this.pendingApprovals.delete(executionId);
139
+ return await this.client.resume(executionId, approvalResponse);
140
+ }
141
+ /**
142
+ * Get pending approval request for an execution
143
+ */
144
+ getPendingApproval(executionId) {
145
+ return this.pendingApprovals.get(executionId);
146
+ }
147
+ /**
148
+ * Handle LLM call - route to LangChain LLM
149
+ */
150
+ async handleLLMCall(prompt, options) {
151
+ const messages = [];
152
+ if (options?.systemPrompt) {
153
+ messages.push(new SystemMessage(options.systemPrompt));
154
+ }
155
+ messages.push(new HumanMessage(prompt));
156
+ const response = await this.llm.invoke(messages);
157
+ return typeof response.content === "string" ? response.content : JSON.stringify(response.content);
158
+ }
159
+ /**
160
+ * Handle LLM extract - route to LangChain LLM with structured output
161
+ */
162
+ async handleLLMExtract(prompt, schema, options) {
163
+ const structuredLLM = this.llm.withStructuredOutput(schema);
164
+ const messages = [];
165
+ if (options?.systemPrompt) {
166
+ messages.push(new SystemMessage(options.systemPrompt));
167
+ }
168
+ messages.push(new HumanMessage(prompt));
169
+ const result = await structuredLLM.invoke(messages);
170
+ return result;
171
+ }
172
+ /**
173
+ * Handle LLM classify - route to LangChain LLM
174
+ */
175
+ async handleLLMClassify(text, categories, options) {
176
+ const prompt = `Classify the following text into one of these categories: ${categories.join(", ")}
177
+
178
+ Text: ${text}
179
+
180
+ Category:`;
181
+ const messages = [];
182
+ if (options?.systemPrompt) {
183
+ messages.push(new SystemMessage(options.systemPrompt));
184
+ }
185
+ messages.push(new HumanMessage(prompt));
186
+ const response = await this.llm.invoke(messages);
187
+ const result = typeof response.content === "string" ? response.content.trim() : JSON.stringify(response.content).trim();
188
+ if (!categories.includes(result)) {
189
+ for (const category of categories) {
190
+ if (result.toLowerCase().includes(category.toLowerCase())) {
191
+ return category;
192
+ }
193
+ }
194
+ const fallback = categories[0];
195
+ if (!fallback) {
196
+ throw new Error("No categories provided for classification");
197
+ }
198
+ return fallback;
199
+ }
200
+ return result;
201
+ }
202
+ /**
203
+ * Handle embedding - route to LangChain embeddings model
204
+ */
205
+ async handleEmbedding(text) {
206
+ if (!this.embeddings) {
207
+ throw new Error("Embeddings model not provided. Pass embeddings option when creating LangGraphATPClient.");
208
+ }
209
+ return await this.embeddings.embedQuery(text);
210
+ }
211
+ /**
212
+ * Get the underlying ATP client for advanced usage
213
+ */
214
+ getUnderlyingClient() {
215
+ return this.client;
216
+ }
217
+ async handleApprovalRequest(message, context) {
218
+ const executionId = context?.executionId;
219
+ const cleanContext = context ? {
220
+ ...context
221
+ } : void 0;
222
+ if (cleanContext) {
223
+ delete cleanContext.executionId;
224
+ }
225
+ if (this.useLangGraphInterrupts) {
226
+ if (typeof executionId !== "string" || !executionId) {
227
+ throw new Error("executionId is missing in approval request context");
228
+ }
229
+ const approvalRequest = {
230
+ message,
231
+ context: cleanContext,
232
+ executionId,
233
+ timestamp: Date.now()
234
+ };
235
+ this.pendingApprovals.set(executionId, approvalRequest);
236
+ throw new ApprovalRequiredException(approvalRequest);
237
+ }
238
+ if (this.directApprovalHandler) {
239
+ const approved = await this.directApprovalHandler(message, cleanContext);
240
+ return {
241
+ approved,
242
+ timestamp: Date.now()
243
+ };
244
+ }
245
+ log.warn(`Approval request rejected (no handler): ${message}`);
246
+ return {
247
+ approved: false,
248
+ timestamp: Date.now()
249
+ };
250
+ }
251
+ };
252
+ async function createATPTools2(options) {
253
+ const { serverUrl, defaultExecutionConfig, ...clientOptions } = options;
254
+ const client = new LangGraphATPClient({
255
+ serverUrl,
256
+ ...clientOptions
257
+ });
258
+ await client.connect();
259
+ const atpTools = createToolsFromATPClient(client.getUnderlyingClient());
260
+ const tools = atpTools.map((atpTool) => {
261
+ if (atpTool.name === ToolNames.EXECUTE_CODE) {
262
+ let ATPExecuteTool = class ATPExecuteTool extends Tool {
263
+ static {
264
+ __name(this, "ATPExecuteTool");
265
+ }
266
+ name = `atp_${atpTool.name}`;
267
+ description = atpTool.description || "Execute TypeScript code in ATP sandbox";
268
+ async _call(input) {
269
+ try {
270
+ let code;
271
+ try {
272
+ const parsed = JSON.parse(input);
273
+ code = parsed.code || input;
274
+ } catch {
275
+ code = input;
276
+ }
277
+ const result = await client.execute(code, defaultExecutionConfig);
278
+ if (result.result.status === ExecutionStatus.COMPLETED) {
279
+ return JSON.stringify({
280
+ success: true,
281
+ result: result.result.result,
282
+ stats: result.result.stats
283
+ }, null, 2);
284
+ } else if (result.result.status === ExecutionStatus.FAILED) {
285
+ return JSON.stringify({
286
+ success: false,
287
+ error: result.result.error,
288
+ stats: result.result.stats
289
+ }, null, 2);
290
+ } else {
291
+ return JSON.stringify({
292
+ success: false,
293
+ error: "Execution in unexpected state: " + result.result.status
294
+ }, null, 2);
295
+ }
296
+ } catch (error) {
297
+ if (error instanceof ApprovalRequiredException) {
298
+ throw error;
299
+ }
300
+ return JSON.stringify({
301
+ success: false,
302
+ error: error.message || "Unknown error"
303
+ }, null, 2);
304
+ }
305
+ }
306
+ };
307
+ return new ATPExecuteTool();
308
+ }
309
+ return new DynamicStructuredTool({
310
+ name: `atp_${atpTool.name}`,
311
+ description: atpTool.description || "",
312
+ schema: atpTool.zodSchema || atpTool.inputSchema,
313
+ func: /* @__PURE__ */ __name(async (input) => {
314
+ try {
315
+ const result = await atpTool.func(input);
316
+ return typeof result === "string" ? result : JSON.stringify(result, null, 2);
317
+ } catch (error) {
318
+ return JSON.stringify({
319
+ success: false,
320
+ error: error.message
321
+ }, null, 2);
322
+ }
323
+ }, "func")
324
+ });
325
+ });
326
+ return {
327
+ client,
328
+ tools,
329
+ isApprovalRequired: /* @__PURE__ */ __name((error) => {
330
+ return error instanceof ApprovalRequiredException;
331
+ }, "isApprovalRequired"),
332
+ resumeWithApproval: /* @__PURE__ */ __name(async (executionId, approved, reason) => {
333
+ return await client.resumeWithApproval(executionId, approved, reason);
334
+ }, "resumeWithApproval")
335
+ };
336
+ }
337
+ __name(createATPTools2, "createATPTools");
338
+ async function createSimpleATPTool(serverUrl, llm, headers) {
339
+ const result = await createATPTools2({
340
+ serverUrl,
341
+ headers,
342
+ llm
343
+ });
344
+ const tool = result.tools.find((t) => t.name === `atp_${ToolNames.EXECUTE_CODE}`);
345
+ if (!tool) {
346
+ throw new Error("Failed to create ATP execute_code tool");
347
+ }
348
+ return tool;
349
+ }
350
+ __name(createSimpleATPTool, "createSimpleATPTool");
351
+ function createLangChainEventHandler(onEvent, options = {}) {
352
+ const { tags = [], metadata = {} } = options;
353
+ return (event) => {
354
+ const baseEvent = {
355
+ run_id: event.runId,
356
+ tags: [
357
+ "atp",
358
+ ...tags
359
+ ],
360
+ metadata: {
361
+ ...metadata,
362
+ timestamp: event.timestamp
363
+ }
364
+ };
365
+ switch (event.type) {
366
+ case ATPEventType.THINKING: {
367
+ const data = event.data;
368
+ onEvent({
369
+ ...baseEvent,
370
+ event: "on_llm_stream",
371
+ name: "atp_thinking",
372
+ data: {
373
+ chunk: data.content,
374
+ step: data.step
375
+ }
376
+ });
377
+ break;
378
+ }
379
+ case ATPEventType.TOOL_START: {
380
+ const data = event.data;
381
+ onEvent({
382
+ ...baseEvent,
383
+ event: "on_tool_start",
384
+ name: `${data.apiGroup}.${data.toolName}`,
385
+ data: {
386
+ input: data.input
387
+ },
388
+ metadata: {
389
+ ...baseEvent.metadata,
390
+ apiGroup: data.apiGroup,
391
+ toolName: data.toolName
392
+ }
393
+ });
394
+ break;
395
+ }
396
+ case ATPEventType.TOOL_END: {
397
+ const data = event.data;
398
+ onEvent({
399
+ ...baseEvent,
400
+ event: "on_tool_end",
401
+ name: `${data.apiGroup}.${data.toolName}`,
402
+ data: {
403
+ output: data.output,
404
+ error: data.error
405
+ },
406
+ metadata: {
407
+ ...baseEvent.metadata,
408
+ apiGroup: data.apiGroup,
409
+ toolName: data.toolName,
410
+ duration: data.duration,
411
+ success: data.success
412
+ }
413
+ });
414
+ break;
415
+ }
416
+ case ATPEventType.TEXT: {
417
+ const data = event.data;
418
+ onEvent({
419
+ ...baseEvent,
420
+ event: "on_chain_stream",
421
+ name: "atp_output",
422
+ data: {
423
+ chunk: data.text
424
+ }
425
+ });
426
+ break;
427
+ }
428
+ case ATPEventType.TEXT_END:
429
+ onEvent({
430
+ ...baseEvent,
431
+ event: "on_chain_end",
432
+ name: "atp_output",
433
+ data: {}
434
+ });
435
+ break;
436
+ case ATPEventType.SOURCE: {
437
+ const data = event.data;
438
+ onEvent({
439
+ ...baseEvent,
440
+ event: "on_custom_event",
441
+ name: "atp_source",
442
+ data: {
443
+ url: data.url,
444
+ title: data.title,
445
+ summary: data.summary,
446
+ createdAt: data.createdAt
447
+ }
448
+ });
449
+ break;
450
+ }
451
+ case ATPEventType.PROGRESS: {
452
+ const data = event.data;
453
+ onEvent({
454
+ ...baseEvent,
455
+ event: "on_custom_event",
456
+ name: "atp_progress",
457
+ data: {
458
+ message: data.message,
459
+ fraction: data.fraction,
460
+ percentage: Math.round(data.fraction * 100)
461
+ }
462
+ });
463
+ break;
464
+ }
465
+ case ATPEventType.ERROR: {
466
+ const data = event.data;
467
+ onEvent({
468
+ ...baseEvent,
469
+ event: "on_chain_error",
470
+ name: "atp_error",
471
+ data: {
472
+ error: data.message,
473
+ code: data.code
474
+ }
475
+ });
476
+ break;
477
+ }
478
+ default:
479
+ onEvent({
480
+ ...baseEvent,
481
+ event: "on_custom_event",
482
+ name: `atp_${event.type}`,
483
+ data: event.data
484
+ });
485
+ break;
486
+ }
487
+ };
488
+ }
489
+ __name(createLangChainEventHandler, "createLangChainEventHandler");
490
+ function createCallbackManagerHandler(callbackManager) {
491
+ return (event) => {
492
+ switch (event.type) {
493
+ case ATPEventType.THINKING: {
494
+ const data = event.data;
495
+ callbackManager.handleLLMNewToken?.(data.content, void 0, event.runId);
496
+ break;
497
+ }
498
+ case ATPEventType.TOOL_START: {
499
+ const data = event.data;
500
+ callbackManager.handleToolStart?.({
501
+ name: `${data.apiGroup}.${data.toolName}`
502
+ }, JSON.stringify(data.input), event.runId, void 0, [
503
+ "atp"
504
+ ], {
505
+ apiGroup: data.apiGroup
506
+ });
507
+ break;
508
+ }
509
+ case ATPEventType.TOOL_END: {
510
+ const data = event.data;
511
+ callbackManager.handleToolEnd?.(JSON.stringify(data.output), event.runId, void 0, [
512
+ "atp"
513
+ ]);
514
+ break;
515
+ }
516
+ case ATPEventType.TEXT: {
517
+ const data = event.data;
518
+ callbackManager.handleLLMNewToken?.(data.text, void 0, event.runId);
519
+ break;
520
+ }
521
+ default:
522
+ callbackManager.handleCustomEvent?.(`atp_${event.type}`, event.data, event.runId, [
523
+ "atp"
524
+ ], {
525
+ timestamp: event.timestamp
526
+ });
527
+ break;
528
+ }
529
+ };
530
+ }
531
+ __name(createCallbackManagerHandler, "createCallbackManagerHandler");
532
+ var ATPExecutionNode = class {
533
+ static {
534
+ __name(this, "ATPExecutionNode");
535
+ }
536
+ client;
537
+ constructor(client) {
538
+ this.client = client;
539
+ }
540
+ /**
541
+ * Execute code from the state and update the state with results
542
+ */
543
+ async execute(state) {
544
+ if (!state.code) {
545
+ throw new Error("No code provided in state");
546
+ }
547
+ const result = await this.client.execute(state.code);
548
+ return {
549
+ ...state,
550
+ executionResult: result,
551
+ lastExecutionStatus: result.status,
552
+ lastExecutionOutput: result.status === ExecutionStatus.COMPLETED ? result.result : result.error
553
+ };
554
+ }
555
+ /**
556
+ * Create a function suitable for LangGraph node
557
+ */
558
+ asFunction() {
559
+ return this.execute.bind(this);
560
+ }
561
+ };
562
+ function createATPNode(client) {
563
+ return async (state) => {
564
+ if (!state.code) {
565
+ throw new Error("No code provided in state");
566
+ }
567
+ const result = await client.execute(state.code);
568
+ return {
569
+ ...state,
570
+ executionResult: result,
571
+ lastExecutionStatus: result.status,
572
+ lastExecutionOutput: result.status === ExecutionStatus.COMPLETED ? result.result : result.error
573
+ };
574
+ };
575
+ }
576
+ __name(createATPNode, "createATPNode");
577
+
578
+ export { ATPExecutionNode, ApprovalRequiredException, LangGraphATPClient, convertToLangChainTools, createATPNode, createATPTools2 as createATPTools, createATPTools as createATPToolsBasic, createCallbackManagerHandler, createLangChainEventHandler, createSimpleATPTool };
579
+ //# sourceMappingURL=index.js.map
6
580
  //# sourceMappingURL=index.js.map