@voltagent/core 0.1.49 → 0.1.51

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.d.ts CHANGED
@@ -1227,7 +1227,7 @@ type PublicGenerateOptions = Omit<CommonGenerateOptions, "historyEntryId" | "ope
1227
1227
  /**
1228
1228
  * Agent status information
1229
1229
  */
1230
- type AgentStatus = "idle" | "working" | "tool_calling" | "error" | "completed";
1230
+ type AgentStatus = "idle" | "working" | "error" | "completed" | "cancelled";
1231
1231
  /**
1232
1232
  * Tool call definition
1233
1233
  */
@@ -1322,6 +1322,10 @@ type AgentHandoffOptions = {
1322
1322
  * Parent's operation context to merge SubAgent steps into
1323
1323
  */
1324
1324
  parentOperationContext?: OperationContext;
1325
+ /**
1326
+ * AbortSignal to cancel the handoff operation
1327
+ */
1328
+ signal?: AbortSignal;
1325
1329
  };
1326
1330
  /**
1327
1331
  * Result of a handoff to another agent
@@ -1380,6 +1384,8 @@ type OperationContext = {
1380
1384
  toolSpans?: Map<string, Span>;
1381
1385
  /** Conversation steps for building full message history including tool calls/results */
1382
1386
  conversationSteps?: StepWithContent[];
1387
+ /** AbortSignal for cancelling the operation */
1388
+ signal?: AbortSignal;
1383
1389
  };
1384
1390
  /**
1385
1391
  * Tool execution context passed to tool.execute method
@@ -3434,6 +3440,10 @@ declare class Agent<TProvider extends {
3434
3440
  */
3435
3441
  private _endOtelToolSpan;
3436
3442
  private publishTimelineEvent;
3443
+ /**
3444
+ * Sets up abort signal listener for cancellation handling
3445
+ */
3446
+ private setupAbortSignalListener;
3437
3447
  /**
3438
3448
  * Create an enhanced fullStream with real-time SubAgent event injection
3439
3449
  */
package/dist/index.js CHANGED
@@ -401,7 +401,6 @@ var _AgentEventEmitter = class extends import_node_events.EventEmitter {
401
401
  const { agentId, historyId, event, skipPropagation = false, parentHistoryEntryId } = params;
402
402
  const agent = AgentRegistry.getInstance().getAgent(agentId);
403
403
  if (!agent) {
404
- import_dev2.devLogger.warn("Agent not found: ", agentId);
405
404
  return void 0;
406
405
  }
407
406
  const historyManager = agent.getHistoryManager();
@@ -1599,6 +1598,10 @@ app.openapi(streamRoute, async (c) => {
1599
1598
  temperature: 0.7
1600
1599
  }
1601
1600
  } = c.req.valid("json");
1601
+ const abortController = new AbortController();
1602
+ c.req.raw.signal?.addEventListener("abort", () => {
1603
+ abortController.abort();
1604
+ });
1602
1605
  const stream = new ReadableStream({
1603
1606
  async start(controller) {
1604
1607
  try {
@@ -1633,7 +1636,9 @@ app.openapi(streamRoute, async (c) => {
1633
1636
  temperature: options.temperature
1634
1637
  // Note: No onError callback needed - tool errors are handled via fullStream
1635
1638
  // Stream errors are handled by try/catch blocks around fullStream iteration
1636
- }
1639
+ },
1640
+ // Pass the abort signal to the agent
1641
+ signal: abortController.signal
1637
1642
  };
1638
1643
  const response = await agent.streamText(input, processedStreamOptions);
1639
1644
  try {
@@ -1909,6 +1914,11 @@ app.openapi(streamObjectRoute, async (c) => {
1909
1914
  options = {}
1910
1915
  } = c.req.valid("json");
1911
1916
  const schemaInZodObject = (0, import_zod_from_json_schema.convertJsonSchemaToZod)(schema);
1917
+ const abortController = new AbortController();
1918
+ c.req.raw.signal?.addEventListener("abort", () => {
1919
+ console.log("\u{1F6D1} API: Client aborted object stream request, stopping agent stream...");
1920
+ abortController.abort();
1921
+ });
1912
1922
  const sseStream = new ReadableStream({
1913
1923
  async start(controller) {
1914
1924
  try {
@@ -1955,7 +1965,9 @@ app.openapi(streamObjectRoute, async (c) => {
1955
1965
  safeEnqueue(errorMessage);
1956
1966
  safeClose();
1957
1967
  }
1958
- }
1968
+ },
1969
+ // Pass the abort signal to the agent
1970
+ signal: abortController.signal
1959
1971
  };
1960
1972
  const agentStream = await agent.streamObject(
1961
1973
  input,
@@ -3502,9 +3514,7 @@ var LibSQLStorage = class {
3502
3514
  }
3503
3515
  try {
3504
3516
  const migrationResult = await this.migrateAgentHistorySchema();
3505
- if (migrationResult.success) {
3506
- import_dev6.devLogger.info("Agent history schema migration completed successfully");
3507
- } else {
3517
+ if (!migrationResult.success) {
3508
3518
  import_dev6.devLogger.error("Agent history schema migration error:", migrationResult.error);
3509
3519
  }
3510
3520
  } catch (error) {
@@ -7705,7 +7715,9 @@ Context: ${JSON.stringify(context, null, 2)}`;
7705
7715
  // @ts-expect-error - bad types
7706
7716
  parentAgentId: sourceAgent?.id || parentAgentId,
7707
7717
  parentHistoryEntryId,
7708
- parentOperationContext
7718
+ parentOperationContext,
7719
+ // Pass the abort signal from parent's operation context to subagent
7720
+ signal: parentOperationContext?.signal
7709
7721
  });
7710
7722
  let finalText = "";
7711
7723
  if (streamResponse.fullStream) {
@@ -8472,7 +8484,9 @@ ${retrieverContext}`;
8472
8484
  parentHistoryEntryId: options.parentHistoryEntryId,
8473
8485
  otelSpan,
8474
8486
  // Use parent's conversationSteps if available (for SubAgents), otherwise create new array
8475
- conversationSteps: options.parentOperationContext?.conversationSteps || []
8487
+ conversationSteps: options.parentOperationContext?.conversationSteps || [],
8488
+ // Inherit signal from parent context or use provided signal
8489
+ signal: options.parentOperationContext?.signal || options.signal
8476
8490
  };
8477
8491
  return opContext;
8478
8492
  }
@@ -8606,6 +8620,52 @@ ${retrieverContext}`;
8606
8620
  parentHistoryEntryId: operationContext.parentHistoryEntryId
8607
8621
  });
8608
8622
  }
8623
+ /**
8624
+ * Sets up abort signal listener for cancellation handling
8625
+ */
8626
+ setupAbortSignalListener(signal, operationContext, finalConversationId, agentStartEvent) {
8627
+ if (!signal)
8628
+ return;
8629
+ signal.addEventListener("abort", async () => {
8630
+ this.updateHistoryEntry(operationContext, {
8631
+ status: "cancelled",
8632
+ endTime: /* @__PURE__ */ new Date()
8633
+ });
8634
+ operationContext.isActive = false;
8635
+ const cancellationError = new Error("Operation cancelled by user");
8636
+ cancellationError.name = "AbortError";
8637
+ const agentCancelledEvent = {
8638
+ id: crypto.randomUUID(),
8639
+ name: "agent:cancel",
8640
+ type: "agent",
8641
+ startTime: agentStartEvent.startTime,
8642
+ endTime: (/* @__PURE__ */ new Date()).toISOString(),
8643
+ level: "INFO",
8644
+ input: null,
8645
+ statusMessage: {
8646
+ message: cancellationError.message,
8647
+ code: "USER_CANCELLED",
8648
+ stage: "cancelled"
8649
+ },
8650
+ status: "cancelled",
8651
+ metadata: {
8652
+ displayName: this.name,
8653
+ id: this.id,
8654
+ userContext: Object.fromEntries(operationContext.userContext.entries())
8655
+ },
8656
+ traceId: operationContext.historyEntry.id,
8657
+ parentEventId: agentStartEvent.id
8658
+ };
8659
+ this.publishTimelineEvent(operationContext, agentCancelledEvent);
8660
+ await this.hooks.onEnd?.({
8661
+ agent: this,
8662
+ output: void 0,
8663
+ error: cancellationError,
8664
+ conversationId: finalConversationId || "",
8665
+ context: operationContext
8666
+ });
8667
+ });
8668
+ }
8609
8669
  /**
8610
8670
  * Create an enhanced fullStream with real-time SubAgent event injection
8611
8671
  */
@@ -8662,7 +8722,8 @@ ${retrieverContext}`;
8662
8722
  parentHistoryEntryId,
8663
8723
  parentOperationContext,
8664
8724
  contextLimit = 10,
8665
- userContext
8725
+ userContext,
8726
+ signal
8666
8727
  } = internalOptions;
8667
8728
  const operationContext = await this.initializeHistory(input, "working", {
8668
8729
  parentAgentId,
@@ -8671,7 +8732,8 @@ ${retrieverContext}`;
8671
8732
  userContext,
8672
8733
  userId,
8673
8734
  conversationId: initialConversationId,
8674
- parentOperationContext
8735
+ parentOperationContext,
8736
+ signal
8675
8737
  });
8676
8738
  const { messages: contextMessages, conversationId: finalConversationId } = await this.memoryManager.prepareConversationContext(
8677
8739
  operationContext,
@@ -8730,6 +8792,10 @@ ${retrieverContext}`;
8730
8792
  operationContext.userContext.set("agent_start_time", agentStartTime);
8731
8793
  operationContext.userContext.set("agent_start_event_id", agentStartEvent.id);
8732
8794
  this.publishTimelineEvent(operationContext, agentStartEvent);
8795
+ this.setupAbortSignalListener(signal, operationContext, finalConversationId, {
8796
+ id: agentStartEvent.id,
8797
+ startTime: agentStartTime
8798
+ });
8733
8799
  const onStepFinish = this.memoryManager.createStepFinishHandler(
8734
8800
  operationContext,
8735
8801
  userId,
@@ -8843,7 +8909,7 @@ ${retrieverContext}`;
8843
8909
  id: crypto.randomUUID(),
8844
8910
  name: "tool:success",
8845
8911
  type: "tool",
8846
- startTime: (/* @__PURE__ */ new Date()).toISOString(),
8912
+ startTime: toolStartInfo.startTime,
8847
8913
  // Use the original start time
8848
8914
  endTime: (/* @__PURE__ */ new Date()).toISOString(),
8849
8915
  // Current time as end time
@@ -8922,17 +8988,21 @@ ${retrieverContext}`;
8922
8988
  status: "completed"
8923
8989
  });
8924
8990
  operationContext.isActive = false;
8925
- const extendedResponse = {
8991
+ const initialResponse = {
8926
8992
  ...response,
8927
8993
  userContext: new Map(operationContext.userContext)
8928
8994
  };
8929
8995
  await this.hooks.onEnd?.({
8930
8996
  conversationId: finalConversationId,
8931
8997
  agent: this,
8932
- output: extendedResponse,
8998
+ output: initialResponse,
8933
8999
  error: void 0,
8934
9000
  context: operationContext
8935
9001
  });
9002
+ const extendedResponse = {
9003
+ ...response,
9004
+ userContext: new Map(operationContext.userContext)
9005
+ };
8936
9006
  this.updateHistoryEntry(operationContext, {
8937
9007
  output: response.text,
8938
9008
  usage: response.usage,
@@ -9014,7 +9084,8 @@ ${retrieverContext}`;
9014
9084
  parentHistoryEntryId,
9015
9085
  parentOperationContext,
9016
9086
  contextLimit = 10,
9017
- userContext
9087
+ userContext,
9088
+ signal
9018
9089
  } = internalOptions;
9019
9090
  const operationContext = await this.initializeHistory(input, "working", {
9020
9091
  parentAgentId,
@@ -9023,7 +9094,8 @@ ${retrieverContext}`;
9023
9094
  userContext,
9024
9095
  userId,
9025
9096
  conversationId: initialConversationId,
9026
- parentOperationContext
9097
+ parentOperationContext,
9098
+ signal
9027
9099
  });
9028
9100
  const { messages: contextMessages, conversationId: finalConversationId } = await this.memoryManager.prepareConversationContext(
9029
9101
  operationContext,
@@ -9080,6 +9152,10 @@ ${retrieverContext}`;
9080
9152
  operationContext.userContext.set("agent_start_time", agentStartTime);
9081
9153
  operationContext.userContext.set("agent_start_event_id", agentStartEvent.id);
9082
9154
  this.publishTimelineEvent(operationContext, agentStartEvent);
9155
+ this.setupAbortSignalListener(signal, operationContext, finalConversationId, {
9156
+ id: agentStartEvent.id,
9157
+ startTime: agentStartTime
9158
+ });
9083
9159
  const onStepFinish = this.memoryManager.createStepFinishHandler(
9084
9160
  operationContext,
9085
9161
  userId,
@@ -9200,7 +9276,7 @@ ${retrieverContext}`;
9200
9276
  id: crypto.randomUUID(),
9201
9277
  name: "tool:error",
9202
9278
  type: "tool",
9203
- startTime: (/* @__PURE__ */ new Date()).toISOString(),
9279
+ startTime: toolStartInfo.startTime,
9204
9280
  // Use the original start time
9205
9281
  endTime: (/* @__PURE__ */ new Date()).toISOString(),
9206
9282
  // Current time as end time
@@ -9224,7 +9300,7 @@ ${retrieverContext}`;
9224
9300
  id: crypto.randomUUID(),
9225
9301
  name: "tool:success",
9226
9302
  type: "tool",
9227
- startTime: (/* @__PURE__ */ new Date()).toISOString(),
9303
+ startTime: toolStartInfo.startTime,
9228
9304
  // Use the original start time
9229
9305
  endTime: (/* @__PURE__ */ new Date()).toISOString(),
9230
9306
  // Current time as end time
@@ -9325,17 +9401,21 @@ ${retrieverContext}`;
9325
9401
  }
9326
9402
  });
9327
9403
  operationContext.isActive = false;
9328
- const resultWithContext = {
9404
+ const initialResult = {
9329
9405
  ...result,
9330
9406
  userContext: new Map(operationContext.userContext)
9331
9407
  };
9332
9408
  await this.hooks.onEnd?.({
9333
9409
  agent: this,
9334
- output: resultWithContext,
9410
+ output: initialResult,
9335
9411
  error: void 0,
9336
9412
  conversationId: finalConversationId,
9337
9413
  context: operationContext
9338
9414
  });
9415
+ const resultWithContext = {
9416
+ ...result,
9417
+ userContext: new Map(operationContext.userContext)
9418
+ };
9339
9419
  if (internalOptions.provider?.onFinish) {
9340
9420
  await internalOptions.provider.onFinish(
9341
9421
  resultWithContext
@@ -9351,7 +9431,7 @@ ${retrieverContext}`;
9351
9431
  id: crypto.randomUUID(),
9352
9432
  name: "tool:error",
9353
9433
  type: "tool",
9354
- startTime: (/* @__PURE__ */ new Date()).toISOString(),
9434
+ startTime: toolStartInfo.startTime,
9355
9435
  endTime: (/* @__PURE__ */ new Date()).toISOString(),
9356
9436
  status: "error",
9357
9437
  level: "ERROR",
@@ -9469,7 +9549,8 @@ ${retrieverContext}`;
9469
9549
  parentHistoryEntryId,
9470
9550
  parentOperationContext,
9471
9551
  contextLimit = 10,
9472
- userContext
9552
+ userContext,
9553
+ signal
9473
9554
  } = internalOptions;
9474
9555
  const operationContext = await this.initializeHistory(input, "working", {
9475
9556
  parentAgentId,
@@ -9478,7 +9559,8 @@ ${retrieverContext}`;
9478
9559
  userContext,
9479
9560
  userId,
9480
9561
  conversationId: initialConversationId,
9481
- parentOperationContext
9562
+ parentOperationContext,
9563
+ signal
9482
9564
  });
9483
9565
  const { messages: contextMessages, conversationId: finalConversationId } = await this.memoryManager.prepareConversationContext(
9484
9566
  operationContext,
@@ -9537,6 +9619,10 @@ ${retrieverContext}`;
9537
9619
  operationContext.userContext.set("agent_start_time", agentStartTime);
9538
9620
  operationContext.userContext.set("agent_start_event_id", agentStartEvent.id);
9539
9621
  this.publishTimelineEvent(operationContext, agentStartEvent);
9622
+ this.setupAbortSignalListener(signal, operationContext, finalConversationId, {
9623
+ id: agentStartEvent.id,
9624
+ startTime: agentStartTime
9625
+ });
9540
9626
  const onStepFinish = this.memoryManager.createStepFinishHandler(
9541
9627
  operationContext,
9542
9628
  userId,
@@ -9620,17 +9706,21 @@ ${retrieverContext}`;
9620
9706
  endTime: /* @__PURE__ */ new Date(),
9621
9707
  status: "completed"
9622
9708
  });
9623
- const extendedResponse = {
9709
+ const initialResponse = {
9624
9710
  ...response,
9625
9711
  userContext: new Map(operationContext.userContext)
9626
9712
  };
9627
9713
  await this.hooks.onEnd?.({
9628
9714
  agent: this,
9629
- output: extendedResponse,
9715
+ output: initialResponse,
9630
9716
  error: void 0,
9631
9717
  conversationId: finalConversationId,
9632
9718
  context: operationContext
9633
9719
  });
9720
+ const extendedResponse = {
9721
+ ...response,
9722
+ userContext: new Map(operationContext.userContext)
9723
+ };
9634
9724
  return extendedResponse;
9635
9725
  } catch (error) {
9636
9726
  const voltagentError = error;
@@ -9707,7 +9797,8 @@ ${retrieverContext}`;
9707
9797
  parentOperationContext,
9708
9798
  provider,
9709
9799
  contextLimit = 10,
9710
- userContext
9800
+ userContext,
9801
+ signal
9711
9802
  } = internalOptions;
9712
9803
  const operationContext = await this.initializeHistory(input, "working", {
9713
9804
  parentAgentId,
@@ -9716,7 +9807,8 @@ ${retrieverContext}`;
9716
9807
  userContext,
9717
9808
  userId,
9718
9809
  conversationId: initialConversationId,
9719
- parentOperationContext
9810
+ parentOperationContext,
9811
+ signal
9720
9812
  });
9721
9813
  const { messages: contextMessages, conversationId: finalConversationId } = await this.memoryManager.prepareConversationContext(
9722
9814
  operationContext,
@@ -9773,6 +9865,10 @@ ${retrieverContext}`;
9773
9865
  operationContext.userContext.set("agent_start_time", agentStartTime);
9774
9866
  operationContext.userContext.set("agent_start_event_id", agentStartEvent.id);
9775
9867
  this.publishTimelineEvent(operationContext, agentStartEvent);
9868
+ this.setupAbortSignalListener(signal, operationContext, finalConversationId, {
9869
+ id: agentStartEvent.id,
9870
+ startTime: agentStartTime
9871
+ });
9776
9872
  const onStepFinish = this.memoryManager.createStepFinishHandler(
9777
9873
  operationContext,
9778
9874
  userId,
@@ -9864,17 +9960,21 @@ ${retrieverContext}`;
9864
9960
  status: "completed"
9865
9961
  });
9866
9962
  operationContext.isActive = false;
9867
- const resultWithContext = {
9963
+ const initialResult = {
9868
9964
  ...result,
9869
9965
  userContext: new Map(operationContext.userContext)
9870
9966
  };
9871
9967
  await this.hooks.onEnd?.({
9872
9968
  agent: this,
9873
- output: resultWithContext,
9969
+ output: initialResult,
9874
9970
  error: void 0,
9875
9971
  conversationId: finalConversationId,
9876
9972
  context: operationContext
9877
9973
  });
9974
+ const resultWithContext = {
9975
+ ...result,
9976
+ userContext: new Map(operationContext.userContext)
9977
+ };
9878
9978
  if (provider?.onFinish) {
9879
9979
  await provider.onFinish(
9880
9980
  resultWithContext