@voltagent/core 2.6.2 → 2.6.4

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.mts CHANGED
@@ -9033,6 +9033,7 @@ declare class MemoryManager {
9033
9033
  * Ensure conversation exists (background task)
9034
9034
  * PRESERVED FROM ORIGINAL
9035
9035
  */
9036
+ private isConversationAlreadyExistsError;
9036
9037
  private ensureConversationExists;
9037
9038
  /**
9038
9039
  * Save current input (background task)
@@ -9330,6 +9331,9 @@ declare class Agent {
9330
9331
  private getConversationBuffer;
9331
9332
  private getMemoryPersistQueue;
9332
9333
  private ensureStreamingResponseMessageId;
9334
+ private getOrCreateStepResponseMessageId;
9335
+ private getStepResponseMessageFingerprints;
9336
+ private normalizeStepResponseMessages;
9333
9337
  private flushPendingMessagesOnError;
9334
9338
  /**
9335
9339
  * Get contextual logger with parent tracking
@@ -15908,6 +15912,7 @@ declare class VoltAgent {
15908
15912
  private readonly ensureEnvironmentBinding;
15909
15913
  private readonly triggerRegistry;
15910
15914
  private readonly agentRefs;
15915
+ private lastServerlessRemoteConfig?;
15911
15916
  readonly ready: Promise<void>;
15912
15917
  initError?: unknown;
15913
15918
  degraded: boolean;
@@ -15916,6 +15921,8 @@ declare class VoltAgent {
15916
15921
  private ensureEnvironment;
15917
15922
  private autoConfigureVoltOpsClientFromEnv;
15918
15923
  private syncServerlessObservabilityRemote;
15924
+ private isSameServerlessRemoteConfig;
15925
+ private areHeaderRecordsEqual;
15919
15926
  /**
15920
15927
  * Setup graceful shutdown handlers
15921
15928
  */
package/dist/index.d.ts CHANGED
@@ -9033,6 +9033,7 @@ declare class MemoryManager {
9033
9033
  * Ensure conversation exists (background task)
9034
9034
  * PRESERVED FROM ORIGINAL
9035
9035
  */
9036
+ private isConversationAlreadyExistsError;
9036
9037
  private ensureConversationExists;
9037
9038
  /**
9038
9039
  * Save current input (background task)
@@ -9330,6 +9331,9 @@ declare class Agent {
9330
9331
  private getConversationBuffer;
9331
9332
  private getMemoryPersistQueue;
9332
9333
  private ensureStreamingResponseMessageId;
9334
+ private getOrCreateStepResponseMessageId;
9335
+ private getStepResponseMessageFingerprints;
9336
+ private normalizeStepResponseMessages;
9333
9337
  private flushPendingMessagesOnError;
9334
9338
  /**
9335
9339
  * Get contextual logger with parent tracking
@@ -15908,6 +15912,7 @@ declare class VoltAgent {
15908
15912
  private readonly ensureEnvironmentBinding;
15909
15913
  private readonly triggerRegistry;
15910
15914
  private readonly agentRefs;
15915
+ private lastServerlessRemoteConfig?;
15911
15916
  readonly ready: Promise<void>;
15912
15917
  initError?: unknown;
15913
15918
  degraded: boolean;
@@ -15916,6 +15921,8 @@ declare class VoltAgent {
15916
15921
  private ensureEnvironment;
15917
15922
  private autoConfigureVoltOpsClientFromEnv;
15918
15923
  private syncServerlessObservabilityRemote;
15924
+ private isSameServerlessRemoteConfig;
15925
+ private areHeaderRecordsEqual;
15919
15926
  /**
15920
15927
  * Setup graceful shutdown handlers
15921
15928
  */
package/dist/index.js CHANGED
@@ -12899,6 +12899,17 @@ var MemoryManager = class {
12899
12899
  });
12900
12900
  try {
12901
12901
  await trace13.withSpan(span, async () => {
12902
+ const ensuredConversation = await this.ensureConversationExists(
12903
+ context8,
12904
+ userId,
12905
+ conversationId,
12906
+ context8.input
12907
+ );
12908
+ if (!ensuredConversation) {
12909
+ throw new Error(
12910
+ `Failed to ensure conversation exists before step persistence for conversation ${conversationId}`
12911
+ );
12912
+ }
12902
12913
  await this.conversationMemory?.saveConversationSteps?.(steps);
12903
12914
  });
12904
12915
  trace13.endChildSpan(span, "completed", {
@@ -13101,7 +13112,17 @@ var MemoryManager = class {
13101
13112
  id: `conversation-and-input-${conversationId}-${Date.now()}`,
13102
13113
  operation: /* @__PURE__ */ __name(async () => {
13103
13114
  try {
13104
- await this.ensureConversationExists(context8, userId, conversationId, input);
13115
+ const ensuredConversation = await this.ensureConversationExists(
13116
+ context8,
13117
+ userId,
13118
+ conversationId,
13119
+ input
13120
+ );
13121
+ if (!ensuredConversation) {
13122
+ throw new Error(
13123
+ `Failed to ensure conversation exists before input persistence for conversation ${conversationId}`
13124
+ );
13125
+ }
13105
13126
  await this.saveCurrentInput(context8, input, userId, conversationId);
13106
13127
  } catch (error) {
13107
13128
  context8.logger.error("[Memory] Failed to setup conversation and save input", {
@@ -13146,8 +13167,28 @@ var MemoryManager = class {
13146
13167
  * Ensure conversation exists (background task)
13147
13168
  * PRESERVED FROM ORIGINAL
13148
13169
  */
13170
+ isConversationAlreadyExistsError(error) {
13171
+ if (!error || typeof error !== "object") {
13172
+ return false;
13173
+ }
13174
+ const record = error;
13175
+ const code = typeof record.code === "string" ? record.code : "";
13176
+ const duplicateCodes = /* @__PURE__ */ new Set([
13177
+ "CONVERSATION_ALREADY_EXISTS",
13178
+ "23505",
13179
+ // PostgreSQL unique violation
13180
+ "SQLITE_CONSTRAINT_PRIMARYKEY",
13181
+ "SQLITE_CONSTRAINT_UNIQUE",
13182
+ "SQLITE_CONSTRAINT"
13183
+ ]);
13184
+ if (duplicateCodes.has(code)) {
13185
+ return true;
13186
+ }
13187
+ const message = typeof record.message === "string" ? record.message.toLowerCase() : "";
13188
+ return message.includes("already exists") || message.includes("duplicate");
13189
+ }
13149
13190
  async ensureConversationExists(context8, userId, conversationId, input) {
13150
- if (!this.conversationMemory) return;
13191
+ if (!this.conversationMemory) return false;
13151
13192
  try {
13152
13193
  const existingConversation = await this.conversationMemory.getConversation(conversationId);
13153
13194
  if (!existingConversation) {
@@ -13165,7 +13206,7 @@ var MemoryManager = class {
13165
13206
  title
13166
13207
  });
13167
13208
  } catch (createError) {
13168
- if (createError.code === "CONVERSATION_ALREADY_EXISTS") {
13209
+ if (this.isConversationAlreadyExistsError(createError)) {
13169
13210
  context8.logger.debug("[Memory] Conversation already exists (race condition handled)", {
13170
13211
  conversationId
13171
13212
  });
@@ -13178,10 +13219,12 @@ var MemoryManager = class {
13178
13219
  await this.conversationMemory.updateConversation(conversationId, {});
13179
13220
  context8.logger.trace("[Memory] Updated conversation");
13180
13221
  }
13222
+ return true;
13181
13223
  } catch (error) {
13182
13224
  context8.logger.error("[Memory] Failed to ensure conversation exists", {
13183
13225
  error
13184
13226
  });
13227
+ return false;
13185
13228
  }
13186
13229
  }
13187
13230
  /**
@@ -27047,6 +27090,12 @@ var ConversationBuffer = class {
27047
27090
  return;
27048
27091
  }
27049
27092
  if (source === "response") {
27093
+ const hasSameAssistantId = typeof message.id === "string" && message.id.length > 0 && typeof lastMessage.id === "string" && lastMessage.id.length > 0 && message.id === lastMessage.id;
27094
+ if (hasSameAssistantId) {
27095
+ this.mergeAssistantMessage(message);
27096
+ this.activeAssistantMessageId = lastMessage.id;
27097
+ return;
27098
+ }
27050
27099
  const isActiveTarget = this.activeAssistantMessageId !== void 0 && this.activeAssistantMessageId === lastMessage.id;
27051
27100
  const isActiveIncoming = this.activeAssistantMessageId !== void 0 && this.activeAssistantMessageId === message.id;
27052
27101
  if (isActiveTarget || isActiveIncoming || this.pendingMessageIds.has(lastMessage.id)) {
@@ -29966,6 +30015,7 @@ var STEP_PERSIST_COUNT_KEY = Symbol("persistedStepCount");
29966
30015
  var ABORT_LISTENER_ATTACHED_KEY = Symbol("abortListenerAttached");
29967
30016
  var MIDDLEWARE_RETRY_FEEDBACK_KEY = Symbol("middlewareRetryFeedback");
29968
30017
  var STREAM_RESPONSE_MESSAGE_ID_KEY = Symbol("streamResponseMessageId");
30018
+ var STEP_RESPONSE_MESSAGE_FINGERPRINTS_KEY = Symbol("stepResponseMessageFingerprints");
29969
30019
  var DEFAULT_FEEDBACK_KEY = "satisfaction";
29970
30020
  var DEFAULT_CONVERSATION_TITLE_PROMPT = [
29971
30021
  "You generate concise titles for new conversations.",
@@ -32416,6 +32466,7 @@ Metadata: ${(0, import_utils33.safeStringify)(metadata)}`;
32416
32466
  oc.systemContext.delete("conversationSteps");
32417
32467
  oc.systemContext.delete("bailedResult");
32418
32468
  oc.systemContext.delete(STREAM_RESPONSE_MESSAGE_ID_KEY);
32469
+ oc.systemContext.delete(STEP_RESPONSE_MESSAGE_FINGERPRINTS_KEY);
32419
32470
  oc.conversationSteps = [];
32420
32471
  oc.output = void 0;
32421
32472
  }
@@ -32440,20 +32491,56 @@ Metadata: ${(0, import_utils33.safeStringify)(metadata)}`;
32440
32491
  return queue;
32441
32492
  }
32442
32493
  async ensureStreamingResponseMessageId(oc, buffer) {
32443
- const existing = oc.systemContext.get(STREAM_RESPONSE_MESSAGE_ID_KEY);
32444
- if (typeof existing === "string" && existing.trim().length > 0) {
32445
- return existing;
32446
- }
32447
- const messageId = (0, import_ai7.generateId)();
32494
+ const messageId = this.getOrCreateStepResponseMessageId(oc);
32448
32495
  const placeholder = {
32449
32496
  id: messageId,
32450
32497
  role: "assistant",
32451
32498
  parts: []
32452
32499
  };
32453
32500
  buffer.ingestUIMessages([placeholder], false);
32501
+ return messageId;
32502
+ }
32503
+ getOrCreateStepResponseMessageId(oc) {
32504
+ const existing = oc.systemContext.get(STREAM_RESPONSE_MESSAGE_ID_KEY);
32505
+ if (typeof existing === "string" && existing.trim().length > 0) {
32506
+ return existing;
32507
+ }
32508
+ const messageId = (0, import_ai7.generateId)();
32454
32509
  oc.systemContext.set(STREAM_RESPONSE_MESSAGE_ID_KEY, messageId);
32455
32510
  return messageId;
32456
32511
  }
32512
+ getStepResponseMessageFingerprints(oc) {
32513
+ const existing = oc.systemContext.get(STEP_RESPONSE_MESSAGE_FINGERPRINTS_KEY);
32514
+ if (existing instanceof Set) {
32515
+ return existing;
32516
+ }
32517
+ const fingerprints = /* @__PURE__ */ new Set();
32518
+ oc.systemContext.set(STEP_RESPONSE_MESSAGE_FINGERPRINTS_KEY, fingerprints);
32519
+ return fingerprints;
32520
+ }
32521
+ normalizeStepResponseMessages(oc, responseMessages) {
32522
+ if (!responseMessages?.length) {
32523
+ return void 0;
32524
+ }
32525
+ const fallbackAssistantMessageId = this.getOrCreateStepResponseMessageId(oc);
32526
+ const fingerprints = this.getStepResponseMessageFingerprints(oc);
32527
+ const normalized = [];
32528
+ for (const responseMessage of responseMessages) {
32529
+ const normalizedMessage = responseMessage.role === "assistant" ? { ...responseMessage, id: fallbackAssistantMessageId } : responseMessage;
32530
+ const fingerprintMessageId = normalizedMessage.role === "assistant" ? fallbackAssistantMessageId : normalizedMessage.id ?? null;
32531
+ const fingerprint = (0, import_utils33.safeStringify)({
32532
+ role: normalizedMessage.role,
32533
+ id: fingerprintMessageId,
32534
+ content: normalizedMessage.content
32535
+ });
32536
+ if (fingerprints.has(fingerprint)) {
32537
+ continue;
32538
+ }
32539
+ fingerprints.add(fingerprint);
32540
+ normalized.push(normalizedMessage);
32541
+ }
32542
+ return normalized.length > 0 ? normalized : void 0;
32543
+ }
32457
32544
  async flushPendingMessagesOnError(oc) {
32458
32545
  const buffer = this.getConversationBuffer(oc);
32459
32546
  const queue = this.getMemoryPersistQueue(oc);
@@ -34618,7 +34705,10 @@ ${retrieverContext}`;
34618
34705
  const conversationPersistence = this.getConversationPersistenceOptionsForContext(oc);
34619
34706
  return async (event) => {
34620
34707
  const { shouldFlushForToolCompletion, bailedResult } = this.processStepContent(oc, event);
34621
- const responseMessages = filterResponseMessages(event.response?.messages);
34708
+ const responseMessages = this.normalizeStepResponseMessages(
34709
+ oc,
34710
+ filterResponseMessages(event.response?.messages)
34711
+ );
34622
34712
  const hasResponseMessages = Boolean(responseMessages && responseMessages.length > 0);
34623
34713
  if (hasResponseMessages && responseMessages) {
34624
34714
  buffer.addModelMessages(responseMessages, "response");
@@ -41148,6 +41238,7 @@ var VoltAgent = class {
41148
41238
  ensureEnvironmentBinding;
41149
41239
  triggerRegistry;
41150
41240
  agentRefs;
41241
+ lastServerlessRemoteConfig;
41151
41242
  ready;
41152
41243
  initError;
41153
41244
  degraded = false;
@@ -41366,17 +41457,53 @@ var VoltAgent = class {
41366
41457
  }
41367
41458
  const baseUrl = voltOpsClient.getApiUrl().replace(/\/$/, "");
41368
41459
  const headers = voltOpsClient.getAuthHeaders();
41460
+ const nextConfig = {
41461
+ tracesUrl: `${baseUrl}/api/public/otel/v1/traces`,
41462
+ logsUrl: `${baseUrl}/api/public/otel/v1/logs`,
41463
+ headers
41464
+ };
41465
+ if (this.isSameServerlessRemoteConfig(nextConfig)) {
41466
+ return;
41467
+ }
41468
+ this.lastServerlessRemoteConfig = {
41469
+ tracesUrl: nextConfig.tracesUrl,
41470
+ logsUrl: nextConfig.logsUrl,
41471
+ headers: { ...nextConfig.headers }
41472
+ };
41369
41473
  this.observability.updateServerlessRemote({
41370
41474
  traces: {
41371
- url: `${baseUrl}/api/public/otel/v1/traces`,
41372
- headers
41475
+ url: nextConfig.tracesUrl,
41476
+ headers: nextConfig.headers
41373
41477
  },
41374
41478
  logs: {
41375
- url: `${baseUrl}/api/public/otel/v1/logs`,
41376
- headers
41479
+ url: nextConfig.logsUrl,
41480
+ headers: nextConfig.headers
41377
41481
  }
41378
41482
  });
41379
41483
  }
41484
+ isSameServerlessRemoteConfig(nextConfig) {
41485
+ const previous = this.lastServerlessRemoteConfig;
41486
+ if (!previous) {
41487
+ return false;
41488
+ }
41489
+ if (previous.tracesUrl !== nextConfig.tracesUrl || previous.logsUrl !== nextConfig.logsUrl) {
41490
+ return false;
41491
+ }
41492
+ return this.areHeaderRecordsEqual(previous.headers, nextConfig.headers);
41493
+ }
41494
+ areHeaderRecordsEqual(left, right) {
41495
+ const leftKeys = Object.keys(left);
41496
+ const rightKeys = Object.keys(right);
41497
+ if (leftKeys.length !== rightKeys.length) {
41498
+ return false;
41499
+ }
41500
+ for (const key of leftKeys) {
41501
+ if (left[key] !== right[key]) {
41502
+ return false;
41503
+ }
41504
+ }
41505
+ return true;
41506
+ }
41380
41507
  /**
41381
41508
  * Setup graceful shutdown handlers
41382
41509
  */