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