@cloudbase/agent-adapter-langgraph 1.0.1-alpha.7 → 1.0.1-alpha.9

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.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ import "./chunk-NSSMTXJJ.mjs";
2
+
1
3
  // src/agent.ts
2
4
  import {
3
5
  EventType,
@@ -58,6 +60,9 @@ function convertJsonSchemaToZodSchema(jsonSchema, required) {
58
60
  }
59
61
 
60
62
  // src/agent.ts
63
+ import { noopLogger, isErrorWithCode } from "@cloudbase/agent-shared";
64
+ var LangChainCallbackHandler;
65
+ var observabilityLoadAttempted = false;
61
66
  var ClientPropertiesAnnotation = Annotation.Root({
62
67
  tools: Annotation
63
68
  });
@@ -69,6 +74,9 @@ var LanggraphAgent = class extends AbstractAgent {
69
74
  constructor(agentConfig) {
70
75
  super(agentConfig);
71
76
  this.compiledWorkflow = agentConfig.compiledWorkflow;
77
+ this.adapterName = agentConfig.adapterName || "LangGraph";
78
+ const baseLogger = agentConfig.logger ?? noopLogger;
79
+ this.logger = baseLogger.child?.({ component: "langgraph-agent" }) ?? baseLogger;
72
80
  }
73
81
  run(input) {
74
82
  return new Observable((subscriber) => {
@@ -77,15 +85,85 @@ var LanggraphAgent = class extends AbstractAgent {
77
85
  }
78
86
  async _run(subscriber, input) {
79
87
  const { messages, runId, threadId } = input;
80
- subscriber.next({
88
+ const logger = this.logger.child?.({ runId, threadId }) ?? this.logger;
89
+ logger.info?.("Run started");
90
+ if (!observabilityLoadAttempted && !this.observabilityCallback) {
91
+ observabilityLoadAttempted = true;
92
+ try {
93
+ logger.debug?.("Attempting to load observability...");
94
+ const obsModule = await import("./langchain-NZNM23PL.mjs");
95
+ LangChainCallbackHandler = obsModule.CallbackHandler;
96
+ if (LangChainCallbackHandler) {
97
+ this.observabilityCallback = new LangChainCallbackHandler({
98
+ adapterName: this.adapterName
99
+ });
100
+ logger.debug?.("\u2713 Observability callback created");
101
+ }
102
+ } catch (e) {
103
+ logger.debug?.(
104
+ "\u2717 Observability not available:",
105
+ e instanceof Error ? e.message : String(e)
106
+ );
107
+ }
108
+ }
109
+ if (this.observabilityCallback && input.forwardedProps?.__agui_server_context) {
110
+ try {
111
+ const serverContextData = input.forwardedProps.__agui_server_context;
112
+ const serverSpanContext = {
113
+ traceId: serverContextData.traceId,
114
+ spanId: serverContextData.spanId,
115
+ traceFlags: serverContextData.traceFlags,
116
+ isRemote: false
117
+ };
118
+ this.observabilityCallback.setExternalParentContext(serverSpanContext);
119
+ logger.debug?.("\u2713 Server context restored:", {
120
+ traceId: serverSpanContext.traceId,
121
+ spanId: serverSpanContext.spanId
122
+ });
123
+ } catch (e) {
124
+ logger.debug?.("Failed to restore server context:", e);
125
+ }
126
+ }
127
+ const runStartedEvent = {
81
128
  type: EventType.RUN_STARTED,
82
129
  threadId,
83
130
  runId
84
- });
85
- const streamEventInput = input.forwardedProps?.resume ? new Command({
131
+ };
132
+ logger.trace?.({ aguiEvent: runStartedEvent }, "Emitting AGUI event");
133
+ subscriber.next(runStartedEvent);
134
+ const isResume = !!input.forwardedProps?.resume;
135
+ const lastUserMessage = messages.filter((m) => m.role === "user").pop();
136
+ logger.debug?.(
137
+ {
138
+ isResume,
139
+ messageCount: messages.length,
140
+ toolCount: input.tools?.length ?? 0,
141
+ tools: input.tools?.map((t) => t.name),
142
+ lastUserMessage: typeof lastUserMessage?.content === "string" ? lastUserMessage.content.slice(0, 200) : void 0
143
+ },
144
+ "Preparing stream input"
145
+ );
146
+ logger.trace?.({ messages, tools: input.tools }, "Full input messages");
147
+ const langChainMessages = isResume ? void 0 : aguiMessagesToLangChain(messages);
148
+ if (langChainMessages) {
149
+ logger.trace?.(
150
+ {
151
+ langChainMessages,
152
+ messageCount: langChainMessages.length,
153
+ messageTypes: langChainMessages.map((m) => ({
154
+ type: m.type,
155
+ id: m.id,
156
+ hasToolCalls: "tool_calls" in m && Array.isArray(m.tool_calls) && m.tool_calls.length > 0,
157
+ toolCallId: "tool_call_id" in m ? m.tool_call_id : void 0
158
+ }))
159
+ },
160
+ "Converted LangGraph messages"
161
+ );
162
+ }
163
+ const streamEventInput = isResume ? new Command({
86
164
  resume: JSON.stringify(input.forwardedProps?.resume?.payload)
87
165
  }) : {
88
- messages: aguiMessagesToLangChain(messages),
166
+ messages: langChainMessages,
89
167
  client: {
90
168
  tools: convertActionsToDynamicStructuredTools(
91
169
  input.tools.map((x) => ({
@@ -97,11 +175,13 @@ var LanggraphAgent = class extends AbstractAgent {
97
175
  };
98
176
  const stream = this.compiledWorkflow.streamEvents(streamEventInput, {
99
177
  version: "v2",
178
+ ...this.observabilityCallback ? { callbacks: [this.observabilityCallback] } : {},
100
179
  runId,
101
180
  configurable: {
102
181
  thread_id: threadId
103
182
  }
104
183
  });
184
+ logger.debug?.("Stream created, starting event processing");
105
185
  const chatModelRuns = [];
106
186
  const handledToolCallIds = /* @__PURE__ */ new Set();
107
187
  for (const msg of messages) {
@@ -109,14 +189,32 @@ var LanggraphAgent = class extends AbstractAgent {
109
189
  handledToolCallIds.add(msg.toolCallId);
110
190
  }
111
191
  }
192
+ if (handledToolCallIds.size > 0) {
193
+ logger.debug?.(
194
+ { count: handledToolCallIds.size },
195
+ "Pre-populated handled tool call IDs from input messages"
196
+ );
197
+ }
112
198
  let interrupt;
113
199
  let currentToolCall = null;
200
+ let eventCount = 0;
201
+ let toolCallCount = 0;
202
+ let textChunkCount = 0;
114
203
  try {
115
204
  for await (const event of stream) {
205
+ eventCount++;
206
+ logger.trace?.(
207
+ { eventType: event.event, eventCount, langGraphEvent: event },
208
+ "Processing stream event"
209
+ );
116
210
  if (event.event.startsWith("ChannelWrite<")) {
117
211
  continue;
118
212
  }
119
213
  if (event.event === "on_chat_model_start") {
214
+ logger.debug?.(
215
+ { chatModelRunId: event.run_id },
216
+ "Chat model started"
217
+ );
120
218
  chatModelRuns.push({ runId: event.run_id });
121
219
  continue;
122
220
  }
@@ -125,8 +223,13 @@ var LanggraphAgent = class extends AbstractAgent {
125
223
  (run) => run.runId === event.run_id
126
224
  );
127
225
  if (!chatModelRun) {
226
+ logger.warn?.(
227
+ { chatModelRunId: event.run_id },
228
+ "Received message from unknown chat model run"
229
+ );
128
230
  subscriber.next({
129
231
  type: EventType.RUN_ERROR,
232
+ code: "INTERNAL_ERROR",
130
233
  message: `Received a message from an unknown chat model run. Run Id: ${event.run_id}`
131
234
  });
132
235
  continue;
@@ -134,14 +237,29 @@ var LanggraphAgent = class extends AbstractAgent {
134
237
  const chunkId = event.data.chunk.id;
135
238
  if (!chatModelRun.messageId) {
136
239
  chatModelRun.messageId = chunkId;
137
- subscriber.next({
240
+ const textStartEvent = {
138
241
  messageId: chunkId,
139
242
  type: EventType.TEXT_MESSAGE_START,
140
243
  role: "assistant"
141
- });
244
+ };
245
+ logger.debug?.({ messageId: chunkId }, "Text message started");
246
+ logger.trace?.(
247
+ { aguiEvent: textStartEvent },
248
+ "Emitting AGUI event"
249
+ );
250
+ subscriber.next(textStartEvent);
142
251
  } else if (chatModelRun.messageId !== chunkId) {
252
+ logger.warn?.(
253
+ {
254
+ expectedMessageId: chatModelRun.messageId,
255
+ receivedMessageId: chunkId,
256
+ chatModelRunId: event.run_id
257
+ },
258
+ "Received message with unexpected ID"
259
+ );
143
260
  subscriber.next({
144
261
  type: EventType.RUN_ERROR,
262
+ code: "INTERNAL_ERROR",
145
263
  message: `Received a message of unknown message id from current run. Run Id: ${event.run_id} Message Id from current run: ${chatModelRun.messageId} Message Id from received message: ${chunkId}`
146
264
  });
147
265
  continue;
@@ -154,29 +272,68 @@ var LanggraphAgent = class extends AbstractAgent {
154
272
  })).forEach((toolCall) => {
155
273
  if (currentToolCall) {
156
274
  if (toolCall.id && currentToolCall.id !== toolCall.id) {
157
- subscriber.next({
275
+ const toolEndEvent = {
158
276
  toolCallId: currentToolCall.id,
159
277
  type: EventType.TOOL_CALL_END
160
- });
278
+ };
279
+ logger.debug?.(
280
+ {
281
+ toolCallId: currentToolCall.id,
282
+ toolCallName: currentToolCall.name
283
+ },
284
+ "Tool call ended"
285
+ );
286
+ logger.trace?.(
287
+ { aguiEvent: toolEndEvent },
288
+ "Emitting AGUI event"
289
+ );
290
+ subscriber.next(toolEndEvent);
161
291
  if (toolCall.name && toolCall.id) {
162
292
  currentToolCall = toolCall;
163
- subscriber.next({
293
+ toolCallCount++;
294
+ const toolStartEvent = {
164
295
  toolCallId: currentToolCall.id,
165
296
  toolCallName: currentToolCall.name,
166
297
  parentMessageId,
167
298
  type: EventType.TOOL_CALL_START
168
- });
299
+ };
300
+ logger.debug?.(
301
+ {
302
+ toolCallId: toolCall.id,
303
+ toolCallName: toolCall.name
304
+ },
305
+ "Tool call started"
306
+ );
307
+ logger.trace?.(
308
+ { aguiEvent: toolStartEvent },
309
+ "Emitting AGUI event"
310
+ );
311
+ subscriber.next(toolStartEvent);
169
312
  if (currentToolCall.args) {
170
- subscriber.next({
313
+ const toolArgsEvent = {
171
314
  toolCallId: currentToolCall.id,
172
315
  delta: currentToolCall.args,
173
316
  type: EventType.TOOL_CALL_ARGS
174
- });
317
+ };
318
+ logger.trace?.(
319
+ { aguiEvent: toolArgsEvent },
320
+ "Emitting AGUI event"
321
+ );
322
+ subscriber.next(toolArgsEvent);
175
323
  if (isValidJson(currentToolCall.args)) {
176
- subscriber.next({
324
+ const toolEndEvent2 = {
177
325
  toolCallId: currentToolCall.id,
178
326
  type: EventType.TOOL_CALL_END
179
- });
327
+ };
328
+ logger.debug?.(
329
+ { toolCallId: currentToolCall.id },
330
+ "Tool call ended (args complete)"
331
+ );
332
+ logger.trace?.(
333
+ { aguiEvent: toolEndEvent2 },
334
+ "Emitting AGUI event"
335
+ );
336
+ subscriber.next(toolEndEvent2);
180
337
  currentToolCall = null;
181
338
  }
182
339
  }
@@ -184,16 +341,30 @@ var LanggraphAgent = class extends AbstractAgent {
184
341
  } else {
185
342
  if (toolCall.args) {
186
343
  currentToolCall.args += toolCall.args;
187
- subscriber.next({
344
+ const toolArgsEvent = {
188
345
  toolCallId: currentToolCall.id,
189
346
  delta: toolCall.args,
190
347
  type: EventType.TOOL_CALL_ARGS
191
- });
348
+ };
349
+ logger.trace?.(
350
+ { aguiEvent: toolArgsEvent },
351
+ "Emitting AGUI event"
352
+ );
353
+ subscriber.next(toolArgsEvent);
192
354
  if (isValidJson(currentToolCall.args)) {
193
- subscriber.next({
355
+ const toolEndEvent = {
194
356
  toolCallId: currentToolCall.id,
195
357
  type: EventType.TOOL_CALL_END
196
- });
358
+ };
359
+ logger.debug?.(
360
+ { toolCallId: currentToolCall.id },
361
+ "Tool call ended (args complete)"
362
+ );
363
+ logger.trace?.(
364
+ { aguiEvent: toolEndEvent },
365
+ "Emitting AGUI event"
366
+ );
367
+ subscriber.next(toolEndEvent);
197
368
  currentToolCall = null;
198
369
  }
199
370
  }
@@ -201,23 +372,47 @@ var LanggraphAgent = class extends AbstractAgent {
201
372
  } else {
202
373
  if (toolCall.name && toolCall.id) {
203
374
  currentToolCall = toolCall;
204
- subscriber.next({
375
+ toolCallCount++;
376
+ const toolStartEvent = {
205
377
  toolCallId: toolCall.id,
206
378
  toolCallName: toolCall.name,
207
379
  parentMessageId,
208
380
  type: EventType.TOOL_CALL_START
209
- });
381
+ };
382
+ logger.debug?.(
383
+ { toolCallId: toolCall.id, toolCallName: toolCall.name },
384
+ "Tool call started"
385
+ );
386
+ logger.trace?.(
387
+ { aguiEvent: toolStartEvent },
388
+ "Emitting AGUI event"
389
+ );
390
+ subscriber.next(toolStartEvent);
210
391
  if (toolCall.args) {
211
- subscriber.next({
392
+ const toolArgsEvent = {
212
393
  toolCallId: toolCall.id,
213
394
  delta: toolCall.args,
214
395
  type: EventType.TOOL_CALL_ARGS
215
- });
396
+ };
397
+ logger.trace?.(
398
+ { aguiEvent: toolArgsEvent },
399
+ "Emitting AGUI event"
400
+ );
401
+ subscriber.next(toolArgsEvent);
216
402
  if (isValidJson(toolCall.args)) {
217
- subscriber.next({
403
+ const toolEndEvent = {
218
404
  toolCallId: toolCall.id,
219
405
  type: EventType.TOOL_CALL_END
220
- });
406
+ };
407
+ logger.debug?.(
408
+ { toolCallId: toolCall.id },
409
+ "Tool call ended (args complete)"
410
+ );
411
+ logger.trace?.(
412
+ { aguiEvent: toolEndEvent },
413
+ "Emitting AGUI event"
414
+ );
415
+ subscriber.next(toolEndEvent);
221
416
  currentToolCall = null;
222
417
  }
223
418
  }
@@ -227,11 +422,17 @@ var LanggraphAgent = class extends AbstractAgent {
227
422
  }
228
423
  const delta = event.data.chunk.content;
229
424
  if (typeof delta === "string" && delta) {
230
- subscriber.next({
425
+ textChunkCount++;
426
+ const textContentEvent = {
231
427
  messageId: chatModelRun.messageId,
232
428
  type: EventType.TEXT_MESSAGE_CONTENT,
233
429
  delta
234
- });
430
+ };
431
+ logger.trace?.(
432
+ { aguiEvent: textContentEvent },
433
+ "Emitting AGUI event"
434
+ );
435
+ subscriber.next(textContentEvent);
235
436
  }
236
437
  continue;
237
438
  }
@@ -240,16 +441,27 @@ var LanggraphAgent = class extends AbstractAgent {
240
441
  (run) => run.runId === event.run_id
241
442
  );
242
443
  if (!chatModelRun) {
444
+ logger.warn?.(
445
+ { chatModelRunId: event.run_id },
446
+ "Received on_chat_model_end from unknown run"
447
+ );
243
448
  subscriber.next({
244
449
  type: EventType.RUN_ERROR,
450
+ code: "INTERNAL_ERROR",
245
451
  message: `Received a on_chat_model_end event from an unknown chat model run. Run Id: ${event.run_id}`
246
452
  });
247
453
  continue;
248
454
  }
249
- subscriber.next({
455
+ const textEndEvent = {
250
456
  type: EventType.TEXT_MESSAGE_END,
251
457
  messageId: chatModelRun.messageId
252
- });
458
+ };
459
+ logger.debug?.(
460
+ { messageId: chatModelRun.messageId },
461
+ "Text message ended"
462
+ );
463
+ logger.trace?.({ aguiEvent: textEndEvent }, "Emitting AGUI event");
464
+ subscriber.next(textEndEvent);
253
465
  continue;
254
466
  }
255
467
  if (event.event === "on_tool_end") {
@@ -262,57 +474,115 @@ var LanggraphAgent = class extends AbstractAgent {
262
474
  toolMessage.lc_kwargs.id = toolMessage.id;
263
475
  }
264
476
  }
265
- subscriber.next({
477
+ const toolResultEvent = {
266
478
  toolCallId: toolMessage.tool_call_id,
267
479
  type: EventType.TOOL_CALL_RESULT,
268
480
  content: typeof toolMessage.content === "string" ? toolMessage.content : JSON.stringify(toolMessage.content),
269
481
  messageId: toolMessage.id
270
- });
482
+ };
483
+ logger.debug?.(
484
+ {
485
+ toolCallId: toolMessage.tool_call_id,
486
+ messageId: toolMessage.id
487
+ },
488
+ "Tool call result received"
489
+ );
490
+ logger.trace?.(
491
+ { aguiEvent: toolResultEvent },
492
+ "Emitting AGUI event"
493
+ );
494
+ subscriber.next(toolResultEvent);
271
495
  handledToolCallIds.add(toolMessage.tool_call_id);
496
+ } else {
497
+ logger.trace?.(
498
+ { toolCallId: toolMessage.tool_call_id },
499
+ "Skipping duplicate tool call result"
500
+ );
272
501
  }
273
502
  }
274
503
  continue;
275
504
  }
276
- if (event.event === "on_chain_stream" && event.data.chunk?.__interrupt__ && Array.isArray(event.data.chunk.__interrupt__) && event.data.chunk.__interrupt__.length > 0) {
277
- const rawInterrupt = event.data.chunk.__interrupt__[0];
278
- interrupt = {
279
- id: rawInterrupt.id,
280
- // TODO: replace with actual reason
281
- reason: "agent requested interrupt",
282
- payload: rawInterrupt.value
283
- };
505
+ if (event.event === "on_chain_stream") {
506
+ const chunk = event.data.chunk;
507
+ if (chunk?.messages && Array.isArray(chunk.messages)) {
508
+ logger.trace?.(
509
+ {
510
+ nodeName: event.name,
511
+ stateMessages: chunk.messages.map((m) => ({
512
+ type: m.type,
513
+ id: m.id,
514
+ contentPreview: typeof m.content === "string" ? m.content.slice(0, 100) : "[non-string content]",
515
+ hasToolCalls: "tool_calls" in m && Array.isArray(m.tool_calls) && m.tool_calls.length > 0,
516
+ toolCallId: "tool_call_id" in m ? m.tool_call_id : void 0
517
+ })),
518
+ messageCount: chunk.messages.length
519
+ },
520
+ "State update with messages"
521
+ );
522
+ }
523
+ if (chunk?.__interrupt__ && Array.isArray(chunk.__interrupt__) && chunk.__interrupt__.length > 0) {
524
+ const rawInterrupt = chunk.__interrupt__[0];
525
+ logger.debug?.(
526
+ { interruptId: rawInterrupt.id },
527
+ "Interrupt received"
528
+ );
529
+ interrupt = {
530
+ id: rawInterrupt.id,
531
+ // TODO: replace with actual reason
532
+ reason: "agent requested interrupt",
533
+ payload: rawInterrupt.value
534
+ };
535
+ }
284
536
  }
285
537
  }
538
+ const stats = { eventCount, toolCallCount, textChunkCount };
286
539
  if (interrupt) {
287
- subscriber.next({
540
+ const runFinishedEvent = {
288
541
  type: EventType.RUN_FINISHED,
289
542
  threadId,
290
543
  runId,
291
544
  outcome: "interrupt",
292
545
  interrupt
293
- });
546
+ };
547
+ logger.info?.(
548
+ { outcome: "interrupt", interruptId: interrupt.id, ...stats },
549
+ "Run finished with interrupt"
550
+ );
551
+ logger.trace?.({ aguiEvent: runFinishedEvent }, "Emitting AGUI event");
552
+ subscriber.next(runFinishedEvent);
294
553
  } else {
295
- subscriber.next({
554
+ const runFinishedEvent = {
296
555
  type: EventType.RUN_FINISHED,
297
556
  threadId,
298
557
  runId
299
- });
558
+ };
559
+ logger.info?.({ outcome: "complete", ...stats }, "Run finished");
560
+ logger.trace?.({ aguiEvent: runFinishedEvent }, "Emitting AGUI event");
561
+ subscriber.next(runFinishedEvent);
300
562
  }
301
563
  } catch (error) {
302
- console.error("[LanggraphAgent] Error during stream processing:", error);
564
+ logger.error?.(
565
+ { err: error, eventCount, toolCallCount, textChunkCount },
566
+ "Error during stream processing"
567
+ );
568
+ const errorCode = isErrorWithCode(error) ? error.code : "INTERNAL_ERROR";
569
+ const errorMessage = error instanceof Error ? error.message : String(error);
303
570
  subscriber.next({
304
571
  type: EventType.RUN_ERROR,
305
- message: error instanceof Error ? error.message : String(error)
572
+ code: errorCode,
573
+ message: errorMessage
306
574
  });
307
575
  }
308
576
  subscriber.complete();
309
577
  }
310
578
  clone() {
311
579
  const workflow = this.compiledWorkflow;
580
+ const logger = this.logger;
312
581
  this.compiledWorkflow = void 0;
313
582
  const cloned = super.clone();
314
583
  this.compiledWorkflow = workflow;
315
584
  cloned.compiledWorkflow = workflow;
585
+ cloned.logger = logger;
316
586
  return cloned;
317
587
  }
318
588
  };
@@ -364,8 +634,7 @@ function aguiMessagesToLangChain(messages) {
364
634
  id: message.id
365
635
  };
366
636
  default:
367
- console.error(`Message role ${message.role} is not implemented`);
368
- throw new Error("message role is not supported.");
637
+ throw new Error(`Message role ${message.role} is not supported.`);
369
638
  }
370
639
  });
371
640
  }
@@ -1060,11 +1329,16 @@ var TDAIStore = class extends BaseStore {
1060
1329
  }
1061
1330
  }
1062
1331
  };
1332
+
1333
+ // src/index.ts
1334
+ import { noopLogger as noopLogger2, createConsoleLogger } from "@cloudbase/agent-shared";
1063
1335
  export {
1064
1336
  ClientPropertiesAnnotation,
1065
1337
  ClientStateAnnotation,
1066
1338
  LanggraphAgent,
1067
1339
  TDAISaver,
1068
- TDAIStore
1340
+ TDAIStore,
1341
+ createConsoleLogger,
1342
+ noopLogger2 as noopLogger
1069
1343
  };
1070
1344
  //# sourceMappingURL=index.mjs.map