@voltagent/core 2.3.3 → 2.3.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
@@ -3316,6 +3316,10 @@ declare function createSubagent<TAgent extends Agent, TSchema extends z.ZodType>
3316
3316
  * @template TOOLS - The tool set type parameter from ai-sdk
3317
3317
  */
3318
3318
  type VoltAgentTextStreamPart<TOOLS extends Record<string, any> = Record<string, any>> = TextStreamPart<TOOLS> & {
3319
+ /**
3320
+ * Optional response message identifier (carried on start/step chunks).
3321
+ */
3322
+ messageId?: string;
3319
3323
  /**
3320
3324
  * Optional identifier for the subagent that generated this event
3321
3325
  */
package/dist/index.d.ts CHANGED
@@ -3316,6 +3316,10 @@ declare function createSubagent<TAgent extends Agent, TSchema extends z.ZodType>
3316
3316
  * @template TOOLS - The tool set type parameter from ai-sdk
3317
3317
  */
3318
3318
  type VoltAgentTextStreamPart<TOOLS extends Record<string, any> = Record<string, any>> = TextStreamPart<TOOLS> & {
3319
+ /**
3320
+ * Optional response message identifier (carried on start/step chunks).
3321
+ */
3322
+ messageId?: string;
3319
3323
  /**
3320
3324
  * Optional identifier for the subagent that generated this event
3321
3325
  */
package/dist/index.js CHANGED
@@ -9291,6 +9291,9 @@ var WorkflowStreamWriterImpl = class {
9291
9291
  if ("id" in part && part.id !== void 0) {
9292
9292
  metadata.partId = part.id;
9293
9293
  }
9294
+ if ("messageId" in part && part.messageId !== void 0) {
9295
+ metadata.messageId = part.messageId;
9296
+ }
9294
9297
  if ("providerMetadata" in part && part.providerMetadata !== void 0) {
9295
9298
  metadata.providerMetadata = part.providerMetadata;
9296
9299
  }
@@ -18389,6 +18392,112 @@ function resolveEvalFeedbackClient(host) {
18389
18392
  }
18390
18393
  __name(resolveEvalFeedbackClient, "resolveEvalFeedbackClient");
18391
18394
 
18395
+ // src/agent/openai-reasoning-utils.ts
18396
+ var OPENAI_REASONING_ID_PREFIX = "rs_";
18397
+ var isObject = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null, "isObject");
18398
+ var isOpenAIReasoningId = /* @__PURE__ */ __name((value) => value.trim().startsWith(OPENAI_REASONING_ID_PREFIX), "isOpenAIReasoningId");
18399
+ var hasOpenAIItemId = /* @__PURE__ */ __name((metadata) => {
18400
+ if (!isObject(metadata)) {
18401
+ return false;
18402
+ }
18403
+ const openai = metadata.openai;
18404
+ if (!isObject(openai)) {
18405
+ return false;
18406
+ }
18407
+ const itemId = typeof openai.itemId === "string" ? openai.itemId.trim() : "";
18408
+ return Boolean(itemId);
18409
+ }, "hasOpenAIItemId");
18410
+ var hasOpenAIItemIdForPart = /* @__PURE__ */ __name((part, accessors) => {
18411
+ if (accessors.isToolPart?.(part)) {
18412
+ const callProviderMetadata = accessors.getCallProviderMetadata?.(part);
18413
+ if (callProviderMetadata !== void 0 && hasOpenAIItemId(callProviderMetadata)) {
18414
+ return true;
18415
+ }
18416
+ }
18417
+ return hasOpenAIItemId(accessors.getProviderMetadata(part));
18418
+ }, "hasOpenAIItemIdForPart");
18419
+ var stripDanglingOpenAIReasoningFromParts = /* @__PURE__ */ __name((parts, options) => {
18420
+ const sanitized = [];
18421
+ let changed = false;
18422
+ for (let index = 0; index < parts.length; index += 1) {
18423
+ const part = parts[index];
18424
+ if (!options.isReasoningPart(part)) {
18425
+ sanitized.push(part);
18426
+ continue;
18427
+ }
18428
+ const next = options.getNextPart(parts, index);
18429
+ if (!next) {
18430
+ changed = true;
18431
+ continue;
18432
+ }
18433
+ if (options.isReasoningPart(next)) {
18434
+ changed = true;
18435
+ continue;
18436
+ }
18437
+ if (!options.hasOpenAIItemIdForPart(next)) {
18438
+ changed = true;
18439
+ continue;
18440
+ }
18441
+ sanitized.push(part);
18442
+ }
18443
+ return { parts: sanitized, changed };
18444
+ }, "stripDanglingOpenAIReasoningFromParts");
18445
+
18446
+ // src/agent/model-message-normalizer.ts
18447
+ var isOpenAIReasoningPart = /* @__PURE__ */ __name((part) => {
18448
+ if (!isObject(part)) {
18449
+ return false;
18450
+ }
18451
+ if (part.type !== "reasoning") {
18452
+ return false;
18453
+ }
18454
+ const providerOptions = part.providerOptions;
18455
+ if (hasOpenAIItemId(providerOptions)) {
18456
+ const openai = providerOptions.openai;
18457
+ const itemId = typeof openai?.itemId === "string" ? openai.itemId.trim() : "";
18458
+ if (itemId && isOpenAIReasoningId(itemId)) {
18459
+ return true;
18460
+ }
18461
+ }
18462
+ const reasoningId = typeof part.id === "string" ? part.id.trim() : "";
18463
+ return Boolean(reasoningId && isOpenAIReasoningId(reasoningId));
18464
+ }, "isOpenAIReasoningPart");
18465
+ var hasOpenAIItemIdForPart2 = /* @__PURE__ */ __name((part) => {
18466
+ if (!isObject(part)) {
18467
+ return false;
18468
+ }
18469
+ return hasOpenAIItemIdForPart(part, {
18470
+ getProviderMetadata: /* @__PURE__ */ __name((value) => value.providerOptions, "getProviderMetadata")
18471
+ });
18472
+ }, "hasOpenAIItemIdForPart");
18473
+ var stripDanglingOpenAIReasoningFromModelMessages = /* @__PURE__ */ __name((messages) => {
18474
+ let changed = false;
18475
+ const sanitized = messages.map((message) => {
18476
+ if (message.role !== "assistant" || !Array.isArray(message.content)) {
18477
+ return message;
18478
+ }
18479
+ const content = message.content;
18480
+ const { parts, changed: partsChanged } = stripDanglingOpenAIReasoningFromParts(content, {
18481
+ isReasoningPart: isOpenAIReasoningPart,
18482
+ hasOpenAIItemIdForPart: hasOpenAIItemIdForPart2,
18483
+ getNextPart: /* @__PURE__ */ __name((parts2, index) => parts2[index + 1], "getNextPart")
18484
+ });
18485
+ if (!partsChanged) {
18486
+ return message;
18487
+ }
18488
+ changed = true;
18489
+ if (parts.length === 0) {
18490
+ return null;
18491
+ }
18492
+ const assistantMessage = message;
18493
+ return {
18494
+ ...assistantMessage,
18495
+ content: parts
18496
+ };
18497
+ }).filter((message) => Boolean(message));
18498
+ return changed ? sanitized : messages;
18499
+ }, "stripDanglingOpenAIReasoningFromModelMessages");
18500
+
18392
18501
  // src/agent/open-telemetry/trace-context.ts
18393
18502
  var import_api12 = require("@opentelemetry/api");
18394
18503
  var import_internal8 = require("@voltagent/internal");
@@ -19766,14 +19875,12 @@ var MemoryPersistQueue = class {
19766
19875
  };
19767
19876
 
19768
19877
  // src/agent/message-normalizer.ts
19878
+ var import_internal9 = require("@voltagent/internal");
19769
19879
  var WORKING_MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set([
19770
19880
  "update_working_memory",
19771
19881
  "get_working_memory",
19772
19882
  "clear_working_memory"
19773
19883
  ]);
19774
- var OPENAI_REASONING_ID_PREFIX = "rs_";
19775
- var isObject = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null, "isObject");
19776
- var isOpenAIReasoningId = /* @__PURE__ */ __name((value) => value.trim().startsWith(OPENAI_REASONING_ID_PREFIX), "isOpenAIReasoningId");
19777
19884
  var safeClone = /* @__PURE__ */ __name((value) => {
19778
19885
  if (!isObject(value) && !Array.isArray(value)) {
19779
19886
  return value;
@@ -19783,7 +19890,7 @@ var safeClone = /* @__PURE__ */ __name((value) => {
19783
19890
  return structuredCloneImpl(value);
19784
19891
  }
19785
19892
  try {
19786
- return JSON.parse(JSON.stringify(value));
19893
+ return JSON.parse((0, import_internal9.safeStringify)(value));
19787
19894
  } catch (_error) {
19788
19895
  if (Array.isArray(value)) {
19789
19896
  return value.slice();
@@ -19940,11 +20047,13 @@ var isToolLikePart = /* @__PURE__ */ __name((part) => {
19940
20047
  }, "isToolLikePart");
19941
20048
  var hasToolOutput = /* @__PURE__ */ __name((part) => {
19942
20049
  const state = typeof part.state === "string" ? part.state : void 0;
19943
- if (state === "output-available" || state === "output-error" || state === "output-denied") {
20050
+ if (state === "output-available" || state === "output-error" || state === "output-denied" || state === "output-streaming") {
19944
20051
  return true;
19945
20052
  }
19946
20053
  return part.output !== void 0;
19947
20054
  }, "hasToolOutput");
20055
+ var isToolInputState = /* @__PURE__ */ __name((state) => state === "input-available" || state === "input-streaming" || state === "approval-requested" || state === "approval-responded", "isToolInputState");
20056
+ var isToolOutputState = /* @__PURE__ */ __name((state) => state === "output-available" || state === "output-error" || state === "output-denied" || state === "output-streaming", "isToolOutputState");
19948
20057
  var isApprovalResponded = /* @__PURE__ */ __name((part) => Boolean(part.approval && part.approval.approved != null), "isApprovalResponded");
19949
20058
  var isWorkingMemoryTool = /* @__PURE__ */ __name((part) => {
19950
20059
  const toolName = toolNameFromType(part.type);
@@ -20000,11 +20109,120 @@ var normalizeToolPart = /* @__PURE__ */ __name((part) => {
20000
20109
  }
20001
20110
  return normalized;
20002
20111
  }, "normalizeToolPart");
20112
+ var hasOpenAIReasoningInMessages = /* @__PURE__ */ __name((messages) => messages.some(
20113
+ (message) => message.role === "assistant" && hasOpenAIReasoningContext(message.parts)
20114
+ ), "hasOpenAIReasoningInMessages");
20115
+ var countToolLikeParts = /* @__PURE__ */ __name((messages) => messages.reduce(
20116
+ (count, message) => count + message.parts.filter((part) => isToolLikePart(part)).length,
20117
+ 0
20118
+ ), "countToolLikeParts");
20119
+ var isOpenAIReasoningPart2 = /* @__PURE__ */ __name((part) => {
20120
+ if (part.type !== "reasoning") {
20121
+ return false;
20122
+ }
20123
+ const reasoningId = typeof part.reasoningId === "string" ? part.reasoningId.trim() : "";
20124
+ if (reasoningId && isOpenAIReasoningId(reasoningId)) {
20125
+ return true;
20126
+ }
20127
+ const providerMetadata = part.providerMetadata;
20128
+ if (isObject(providerMetadata)) {
20129
+ const openai = providerMetadata.openai;
20130
+ if (isObject(openai)) {
20131
+ const itemId = typeof openai.itemId === "string" ? openai.itemId.trim() : "";
20132
+ if (itemId && isOpenAIReasoningId(itemId)) {
20133
+ return true;
20134
+ }
20135
+ if (typeof openai.reasoning_trace_id === "string" && openai.reasoning_trace_id.trim()) {
20136
+ return true;
20137
+ }
20138
+ if (isObject(openai.reasoning)) {
20139
+ const id = typeof openai.reasoning.id === "string" ? openai.reasoning.id.trim() : "";
20140
+ if (id && isOpenAIReasoningId(id)) {
20141
+ return true;
20142
+ }
20143
+ }
20144
+ }
20145
+ }
20146
+ return false;
20147
+ }, "isOpenAIReasoningPart");
20148
+ var endsWithOpenAIReasoning = /* @__PURE__ */ __name((parts) => {
20149
+ for (let index = parts.length - 1; index >= 0; index -= 1) {
20150
+ const part = parts[index];
20151
+ if (part.type === "step-start") {
20152
+ continue;
20153
+ }
20154
+ return isOpenAIReasoningPart2(part);
20155
+ }
20156
+ return false;
20157
+ }, "endsWithOpenAIReasoning");
20158
+ var hasOpenAIItemIdForPart3 = /* @__PURE__ */ __name((part) => {
20159
+ return hasOpenAIItemIdForPart(part, {
20160
+ isToolPart: /* @__PURE__ */ __name((candidate) => typeof candidate.type === "string" && candidate.type.startsWith("tool-"), "isToolPart"),
20161
+ getCallProviderMetadata: /* @__PURE__ */ __name((candidate) => candidate.callProviderMetadata, "getCallProviderMetadata"),
20162
+ getProviderMetadata: /* @__PURE__ */ __name((candidate) => candidate.providerMetadata, "getProviderMetadata")
20163
+ });
20164
+ }, "hasOpenAIItemIdForPart");
20165
+ var stripDanglingOpenAIReasoning = /* @__PURE__ */ __name((messages) => {
20166
+ const result = [];
20167
+ for (const message of messages) {
20168
+ if (message.role !== "assistant") {
20169
+ result.push(message);
20170
+ continue;
20171
+ }
20172
+ const { parts } = stripDanglingOpenAIReasoningFromParts(message.parts, {
20173
+ isReasoningPart: isOpenAIReasoningPart2,
20174
+ hasOpenAIItemIdForPart: hasOpenAIItemIdForPart3,
20175
+ getNextPart: /* @__PURE__ */ __name((parts2, index) => {
20176
+ for (let nextIndex = index + 1; nextIndex < parts2.length; nextIndex += 1) {
20177
+ const candidate = parts2[nextIndex];
20178
+ if (candidate.type === "step-start") {
20179
+ continue;
20180
+ }
20181
+ return candidate;
20182
+ }
20183
+ return void 0;
20184
+ }, "getNextPart")
20185
+ });
20186
+ if (parts.length === 0) {
20187
+ continue;
20188
+ }
20189
+ result.push({
20190
+ ...message,
20191
+ parts,
20192
+ ...message.metadata ? { metadata: safeClone(message.metadata) } : {}
20193
+ });
20194
+ }
20195
+ return result;
20196
+ }, "stripDanglingOpenAIReasoning");
20197
+ var mergeTrailingReasoningAssistantMessages = /* @__PURE__ */ __name((messages) => {
20198
+ const merged = [];
20199
+ for (const message of messages) {
20200
+ const last = merged.at(-1);
20201
+ if (last && last.role === "assistant" && message.role === "assistant" && endsWithOpenAIReasoning(last.parts)) {
20202
+ last.parts = [...last.parts, ...message.parts];
20203
+ continue;
20204
+ }
20205
+ merged.push({ ...message, parts: [...message.parts] });
20206
+ }
20207
+ return merged;
20208
+ }, "mergeTrailingReasoningAssistantMessages");
20003
20209
  var sanitizeMessagesForModel = /* @__PURE__ */ __name((messages, options = {}) => {
20004
20210
  const sanitized = messages.map((message) => sanitizeMessageForModel(message)).filter((message) => Boolean(message));
20211
+ const merged = mergeTrailingReasoningAssistantMessages(sanitized);
20005
20212
  const shouldFilterIncomplete = options.filterIncompleteToolCalls !== false;
20006
- const filtered = shouldFilterIncomplete ? filterIncompleteToolCallsForModel(sanitized) : sanitized;
20007
- return addStepStartsBetweenToolRuns(filtered);
20213
+ if (!shouldFilterIncomplete) {
20214
+ return addStepStartsBetweenToolRuns(stripDanglingOpenAIReasoning(merged));
20215
+ }
20216
+ const filtered = filterIncompleteToolCallsForModel(merged);
20217
+ const hasOpenAIReasoning = hasOpenAIReasoningInMessages(merged);
20218
+ if (hasOpenAIReasoning) {
20219
+ const sanitizedToolCount = countToolLikeParts(merged);
20220
+ const filteredToolCount = countToolLikeParts(filtered);
20221
+ if (filteredToolCount < sanitizedToolCount) {
20222
+ return addStepStartsBetweenToolRuns(stripDanglingOpenAIReasoning(merged));
20223
+ }
20224
+ }
20225
+ return addStepStartsBetweenToolRuns(stripDanglingOpenAIReasoning(filtered));
20008
20226
  }, "sanitizeMessagesForModel");
20009
20227
  var sanitizeMessageForModel = /* @__PURE__ */ __name((message) => {
20010
20228
  const sanitizedParts = [];
@@ -20144,8 +20362,9 @@ var pruneEmptyToolRuns = /* @__PURE__ */ __name((parts) => {
20144
20362
  const cleaned = [];
20145
20363
  for (const part of parts) {
20146
20364
  if (typeof part.type === "string" && part.type.startsWith("tool-")) {
20147
- const hasPendingState = part.state === "input-available";
20148
- const hasResult = part.state === "output-available" || part.output !== void 0;
20365
+ const state = typeof part.state === "string" ? part.state : void 0;
20366
+ const hasPendingState = isToolInputState(state);
20367
+ const hasResult = isToolOutputState(state) || part.output !== void 0;
20149
20368
  if (!hasPendingState && !hasResult && part.input == null) {
20150
20369
  continue;
20151
20370
  }
@@ -23172,6 +23391,25 @@ var Agent = class {
23172
23391
  generateMessageId: /* @__PURE__ */ __name(() => responseMessageId, "generateMessageId")
23173
23392
  };
23174
23393
  }, "applyResponseMessageId");
23394
+ const applyResponseMessageIdToStream = /* @__PURE__ */ __name((baseStream) => {
23395
+ if (!responseMessageId) {
23396
+ return baseStream;
23397
+ }
23398
+ return (async function* () {
23399
+ for await (const part of baseStream) {
23400
+ if (part.type !== "start" && part.type !== "start-step") {
23401
+ yield part;
23402
+ continue;
23403
+ }
23404
+ const currentMessageId = part.messageId;
23405
+ if (currentMessageId === responseMessageId) {
23406
+ yield part;
23407
+ continue;
23408
+ }
23409
+ yield { ...part, messageId: responseMessageId };
23410
+ }
23411
+ })();
23412
+ }, "applyResponseMessageIdToStream");
23175
23413
  const createBaseFullStream = /* @__PURE__ */ __name(() => {
23176
23414
  const wrapWithAbortHandling = /* @__PURE__ */ __name(async function* (baseStream) {
23177
23415
  const iterator = baseStream[Symbol.asyncIterator]();
@@ -23198,7 +23436,9 @@ var Agent = class {
23198
23436
  } finally {
23199
23437
  }
23200
23438
  }, "wrapWithAbortHandling");
23201
- const parentStream = normalizeFinishUsageStream(wrapWithAbortHandling(result.fullStream));
23439
+ const parentStream = applyResponseMessageIdToStream(
23440
+ normalizeFinishUsageStream(wrapWithAbortHandling(result.fullStream))
23441
+ );
23202
23442
  if (agent.subAgentManager.hasSubAgents()) {
23203
23443
  const createMergedFullStream = /* @__PURE__ */ __name(async function* () {
23204
23444
  const { readable, writable } = new TransformStream();
@@ -24122,6 +24362,7 @@ Metadata: ${(0, import_utils28.safeStringify)(metadata)}`;
24122
24362
  messages = result.modelMessages;
24123
24363
  }
24124
24364
  }
24365
+ messages = stripDanglingOpenAIReasoningFromModelMessages(messages);
24125
24366
  const maxSteps = options?.maxSteps ?? this.calculateMaxSteps();
24126
24367
  const modelName = this.getModelName();
24127
24368
  const dynamicToolList = await this.resolveValue(this.dynamicTools, oc) || [];
@@ -31436,7 +31677,7 @@ var createPrompt = /* @__PURE__ */ __name(({
31436
31677
  }, "createPrompt");
31437
31678
 
31438
31679
  // src/utils/serialization/index.ts
31439
- var import_internal9 = require("@voltagent/internal");
31680
+ var import_internal10 = require("@voltagent/internal");
31440
31681
  function safeJsonParse(value) {
31441
31682
  if (!value) return void 0;
31442
31683
  try {
@@ -31478,7 +31719,7 @@ function serializeValueForDebug(value) {
31478
31719
  }
31479
31720
  try {
31480
31721
  if (Object.getPrototypeOf(value) === Object.prototype) {
31481
- return (0, import_internal9.deepClone)(value);
31722
+ return (0, import_internal10.deepClone)(value);
31482
31723
  }
31483
31724
  return `[Object: ${value.constructor?.name || "UnknownClass"}]`;
31484
31725
  } catch (e) {
@@ -31490,7 +31731,7 @@ function serializeValueForDebug(value) {
31490
31731
  __name(serializeValueForDebug, "serializeValueForDebug");
31491
31732
 
31492
31733
  // src/retriever/tools/index.ts
31493
- var import_internal10 = require("@voltagent/internal");
31734
+ var import_internal11 = require("@voltagent/internal");
31494
31735
  var import_zod9 = require("zod");
31495
31736
  var createRetrieverTool = /* @__PURE__ */ __name((retriever, options = {}) => {
31496
31737
  const toolName = options.name || "search_knowledge";
@@ -31512,7 +31753,7 @@ var createRetrieverTool = /* @__PURE__ */ __name((retriever, options = {}) => {
31512
31753
  if (Array.isArray(value) && value.every((item) => ["string", "number", "boolean"].includes(typeof item))) {
31513
31754
  return value;
31514
31755
  }
31515
- return (0, import_internal10.safeStringify)(value);
31756
+ return (0, import_internal11.safeStringify)(value);
31516
31757
  }, "normalizeAttributeValue");
31517
31758
  const attachRetrieverAttributes = /* @__PURE__ */ __name(() => {
31518
31759
  if (!toolSpan?.setAttribute) return;
@@ -31627,7 +31868,7 @@ var BaseRetriever = class {
31627
31868
  };
31628
31869
 
31629
31870
  // src/retriever/voltagent-rag-retriever.ts
31630
- var import_internal11 = require("@voltagent/internal");
31871
+ var import_internal12 = require("@voltagent/internal");
31631
31872
 
31632
31873
  // src/voltops/global-client.ts
31633
31874
  var getGlobalVoltOpsClient = /* @__PURE__ */ __name(() => AgentRegistry.getInstance().getGlobalVoltOpsClient(), "getGlobalVoltOpsClient");
@@ -31660,7 +31901,7 @@ async function searchWithVoltOpsClient(voltOpsClient, payload) {
31660
31901
  headers: {
31661
31902
  "Content-Type": "application/json"
31662
31903
  },
31663
- body: (0, import_internal11.safeStringify)(payload)
31904
+ body: (0, import_internal12.safeStringify)(payload)
31664
31905
  });
31665
31906
  const hasJson = response.headers.get("content-type")?.includes("application/json");
31666
31907
  const data = hasJson ? await response.json() : void 0;