@librechat/agents 3.4.5 → 3.4.7
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/cjs/common/enum.cjs +2 -0
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +268 -14
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/langfuseTraceShaping.cjs +9 -6
- package/dist/cjs/langfuseTraceShaping.cjs.map +1 -1
- package/dist/cjs/llm/google/utils/common.cjs +10 -5
- package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
- package/dist/cjs/run.cjs +147 -14
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +93 -31
- package/dist/cjs/session/AgentSession.cjs.map +1 -1
- package/dist/cjs/session/handlers.cjs +10 -0
- package/dist/cjs/session/handlers.cjs.map +1 -1
- package/dist/cjs/stream.cjs +17 -3
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +1 -0
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +4 -2
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/handlers.cjs +1 -0
- package/dist/cjs/tools/handlers.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +28 -0
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/utils/handlers.cjs +3 -0
- package/dist/cjs/utils/handlers.cjs.map +1 -1
- package/dist/esm/common/enum.mjs +2 -0
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +268 -14
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/langfuseTraceShaping.mjs +9 -6
- package/dist/esm/langfuseTraceShaping.mjs.map +1 -1
- package/dist/esm/llm/google/utils/common.mjs +10 -5
- package/dist/esm/llm/google/utils/common.mjs.map +1 -1
- package/dist/esm/run.mjs +147 -14
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +93 -31
- package/dist/esm/session/AgentSession.mjs.map +1 -1
- package/dist/esm/session/handlers.mjs +10 -0
- package/dist/esm/session/handlers.mjs.map +1 -1
- package/dist/esm/stream.mjs +17 -3
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +1 -0
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +4 -2
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/handlers.mjs +1 -0
- package/dist/esm/tools/handlers.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +28 -0
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/utils/handlers.mjs +3 -0
- package/dist/esm/utils/handlers.mjs.map +1 -1
- package/dist/types/common/enum.d.ts +2 -0
- package/dist/types/graphs/Graph.d.ts +87 -0
- package/dist/types/langfuseTraceShaping.d.ts +4 -3
- package/dist/types/run.d.ts +9 -1
- package/dist/types/session/types.d.ts +1 -1
- package/dist/types/summarization/node.d.ts +6 -0
- package/dist/types/types/graph.d.ts +3 -3
- package/dist/types/types/stream.d.ts +57 -0
- package/dist/types/utils/handlers.d.ts +1 -0
- package/package.json +1 -1
- package/src/aggregator.test.ts +127 -0
- package/src/common/enum.ts +2 -0
- package/src/graphs/Graph.ts +365 -7
- package/src/graphs/__tests__/Graph.closeRunStep.test.ts +385 -0
- package/src/langfuseTraceShaping.ts +14 -7
- package/src/llm/google/utils/common.test.ts +11 -0
- package/src/llm/google/utils/common.ts +6 -4
- package/src/run.ts +219 -41
- package/src/session/AgentSession.ts +105 -13
- package/src/session/handlers.ts +14 -2
- package/src/session/types.ts +1 -0
- package/src/specs/activity-label-observability.live.test.ts +262 -0
- package/src/specs/activity-label-observability.test.ts +167 -0
- package/src/specs/langfuse-trace-shaping.test.ts +32 -0
- package/src/specs/run-step-timestamps.test.ts +414 -0
- package/src/stream.ts +29 -6
- package/src/summarization/node.ts +11 -0
- package/src/tools/ToolNode.ts +2 -0
- package/src/tools/__tests__/SubagentExecutor.test.ts +52 -10
- package/src/tools/__tests__/handlers.test.ts +2 -0
- package/src/tools/handlers.ts +1 -0
- package/src/tools/subagent/SubagentExecutor.ts +46 -4
- package/src/types/graph.ts +9 -6
- package/src/types/stream.ts +65 -12
- package/src/utils/handlers.ts +13 -0
|
@@ -99,6 +99,7 @@ const handleToolCalls = async (toolCalls, metadata, graph) => {
|
|
|
99
99
|
const details = prevRunStep.stepDetails;
|
|
100
100
|
if ((!details.tool_calls || details.tool_calls.length === 0) && prevStepId !== reusedChunkStepId) {
|
|
101
101
|
graph.toolCallStepIds.set(toolCallId, prevStepId);
|
|
102
|
+
graph.registerPendingToolCall(toolCallId, prevStepId);
|
|
102
103
|
reusedChunkStepId = prevStepId;
|
|
103
104
|
continue;
|
|
104
105
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.mjs","names":[],"sources":["../../../src/tools/handlers.ts"],"sourcesContent":["/* eslint-disable no-console */\n// src/tools/handlers.ts\nimport { nanoid } from 'nanoid';\nimport { ToolMessage } from '@langchain/core/messages';\nimport type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';\nimport type { AnthropicWebSearchResultBlockParam } from '@/llm/anthropic/types';\nimport type { Graph, MultiAgentGraph, StandardGraph } from '@/graphs';\nimport type { AgentContext } from '@/agents/AgentContext';\nimport type * as t from '@/types';\nimport {\n coerceAnthropicSearchResults,\n isAnthropicWebSearchResult,\n} from '@/tools/search/anthropic';\nimport {\n ToolCallTypes,\n GraphEvents,\n StepTypes,\n Providers,\n Constants,\n} from '@/common';\nimport { formatResultsForLLM } from '@/tools/search/format';\nimport { getMessageId } from '@/messages';\n\nexport async function handleToolCallChunks({\n graph,\n stepKey,\n toolCallChunks,\n metadata,\n}: {\n graph: StandardGraph | MultiAgentGraph;\n stepKey: string;\n toolCallChunks: ToolCallChunk[];\n metadata?: Record<string, unknown>;\n}): Promise<void> {\n let prevStepId: string;\n let prevRunStep: t.RunStep | undefined;\n try {\n prevStepId = graph.getStepIdByKey(stepKey);\n prevRunStep = graph.getRunStep(prevStepId);\n } catch {\n /** Edge Case: If no previous step exists, create a new message creation step */\n const message_id = getMessageId(stepKey, graph, true) ?? '';\n prevStepId = await graph.dispatchRunStep(\n stepKey,\n {\n type: StepTypes.MESSAGE_CREATION,\n message_creation: {\n message_id,\n },\n },\n metadata\n );\n prevRunStep = graph.getRunStep(prevStepId);\n }\n\n const _stepId = graph.getStepIdByKey(stepKey);\n\n /** Edge Case: Tool Call Run Step or `tool_call_ids` never dispatched */\n const tool_calls: ToolCall[] | undefined =\n prevStepId && prevRunStep && prevRunStep.type === StepTypes.MESSAGE_CREATION\n ? []\n : undefined;\n\n /** Edge Case: `id` and `name` fields cannot be empty strings */\n for (const toolCallChunk of toolCallChunks) {\n if (toolCallChunk.name === '') {\n toolCallChunk.name = undefined;\n }\n if (toolCallChunk.id === '') {\n toolCallChunk.id = undefined;\n } else if (\n tool_calls != null &&\n toolCallChunk.id != null &&\n toolCallChunk.name != null\n ) {\n tool_calls.push({\n args: {},\n id: toolCallChunk.id,\n name: toolCallChunk.name,\n type: ToolCallTypes.TOOL_CALL,\n });\n }\n }\n\n let stepId: string = _stepId;\n const alreadyDispatched =\n prevRunStep?.type === StepTypes.MESSAGE_CREATION &&\n graph.messageStepHasToolCalls.has(prevStepId);\n\n if (prevRunStep?.type === StepTypes.TOOL_CALLS) {\n /**\n * If previous step is already a tool_calls step, use that step ID\n * This ensures tool call deltas are dispatched to the correct step\n */\n stepId = prevStepId;\n } else if (\n !alreadyDispatched &&\n prevRunStep?.type === StepTypes.MESSAGE_CREATION\n ) {\n /**\n * Create tool_calls step as soon as we receive the first tool call chunk\n * This ensures deltas are always associated with the correct step\n *\n * NOTE: We do NOT dispatch an empty text block here because:\n * - Empty text blocks cause providers (Anthropic, Bedrock) to reject messages\n * - The tool_calls themselves are sufficient for the step\n * - Empty content with tool_call_ids gets stored in conversation history\n * and causes \"messages must have non-empty content\" errors on replay\n */\n graph.messageStepHasToolCalls.set(prevStepId, true);\n stepId = await graph.dispatchRunStep(\n stepKey,\n {\n type: StepTypes.TOOL_CALLS,\n tool_calls: tool_calls ?? [],\n },\n metadata\n );\n }\n\n await graph.dispatchRunStepDelta(\n stepId,\n {\n type: StepTypes.TOOL_CALLS,\n tool_calls: toolCallChunks,\n },\n metadata\n );\n}\n\nexport const handleToolCalls = async (\n toolCalls?: ToolCall[],\n metadata?: Record<string, unknown>,\n graph?: Graph | StandardGraph | MultiAgentGraph\n): Promise<void> => {\n if (!graph || !metadata) {\n console.warn('Graph or metadata not found in `handleToolCalls`');\n return;\n }\n\n if (!toolCalls) {\n return;\n }\n\n if (toolCalls.length === 0) {\n return;\n }\n\n const stepKey = graph.getStepKey(metadata);\n\n /**\n * Track whether we've already reused an empty TOOL_CALLS step created by\n * handleToolCallChunks during streaming. Only reuse it once (for the first\n * tool call); subsequent parallel tool calls must create their own steps.\n */\n let reusedChunkStepId: string | undefined;\n\n for (const tool_call of toolCalls) {\n const toolCallId = tool_call.id ?? `toolu_${nanoid()}`;\n tool_call.id = toolCallId;\n if (!toolCallId || graph.toolCallStepIds.has(toolCallId)) {\n continue;\n }\n\n let prevStepId = '';\n let prevRunStep: t.RunStep | undefined;\n try {\n prevStepId = graph.getStepIdByKey(stepKey);\n prevRunStep = graph.getRunStep(prevStepId);\n } catch {\n // no previous step\n }\n\n /**\n * If the previous step is TOOL_CALLS (from handleToolCallChunks or a prior\n * iteration), either reuse it (if empty) or dispatch a new TOOL_CALLS step\n * directly — skip the intermediate MESSAGE_CREATION to avoid orphaned gaps.\n */\n if (prevRunStep?.type === StepTypes.TOOL_CALLS) {\n const details = prevRunStep.stepDetails as t.ToolCallsDetails;\n const isEmpty = !details.tool_calls || details.tool_calls.length === 0;\n if (isEmpty && prevStepId !== reusedChunkStepId) {\n graph.toolCallStepIds.set(toolCallId, prevStepId);\n reusedChunkStepId = prevStepId;\n continue;\n }\n await graph.dispatchRunStep(\n stepKey,\n { type: StepTypes.TOOL_CALLS, tool_calls: [tool_call] },\n metadata\n );\n continue;\n }\n\n /**\n * NOTE: We do NOT dispatch empty text blocks with tool_call_ids because:\n * - Empty text blocks cause providers (Anthropic, Bedrock) to reject messages\n * - They get stored in conversation history and cause errors on replay:\n * \"messages must have non-empty content\" (Anthropic)\n * \"The content field in the Message object is empty\" (Bedrock)\n * - The tool_calls themselves are sufficient\n */\n if (prevStepId && prevRunStep) {\n graph.messageStepHasToolCalls.set(prevStepId, true);\n } else if (!prevRunStep) {\n const messageId = getMessageId(stepKey, graph, true) ?? '';\n const stepId = await graph.dispatchRunStep(\n stepKey,\n {\n type: StepTypes.MESSAGE_CREATION,\n message_creation: {\n message_id: messageId,\n },\n },\n metadata\n );\n graph.messageStepHasToolCalls.set(stepId, true);\n }\n\n await graph.dispatchRunStep(\n stepKey,\n {\n type: StepTypes.TOOL_CALLS,\n tool_calls: [tool_call],\n },\n metadata\n );\n }\n};\n\nexport const toolResultTypes = new Set([\n // 'tool_use',\n // 'server_tool_use',\n // 'input_json_delta',\n 'tool_result',\n 'web_search_result',\n 'web_search_tool_result',\n]);\n\n/**\n * Handles the result of a server tool call; in other words, a provider's built-in tool.\n * As of 2025-07-06, only Anthropic handles server tool calls with this pattern.\n */\nexport async function handleServerToolResult({\n graph,\n content,\n metadata,\n agentContext,\n}: {\n graph: StandardGraph | MultiAgentGraph;\n content?: string | t.MessageContentComplex[];\n metadata?: Record<string, unknown>;\n agentContext?: AgentContext;\n}): Promise<boolean> {\n let skipHandling = false;\n if (agentContext?.provider !== Providers.ANTHROPIC) {\n return skipHandling;\n }\n if (\n typeof content === 'string' ||\n content == null ||\n content.length === 0 ||\n (content.length === 1 &&\n (content[0] as t.ToolResultContent).tool_use_id == null)\n ) {\n return skipHandling;\n }\n\n for (const contentPart of content) {\n const toolUseId = (contentPart as t.ToolResultContent).tool_use_id;\n if (toolUseId == null || toolUseId === '') {\n continue;\n }\n const stepId = graph.toolCallStepIds.get(toolUseId);\n if (stepId == null || stepId === '') {\n console.warn(\n `Tool use ID ${toolUseId} not found in graph, cannot dispatch tool result.`\n );\n continue;\n }\n const runStep = graph.getRunStep(stepId);\n if (!runStep) {\n console.warn(\n `Run step for ${stepId} does not exist, cannot dispatch tool result.`\n );\n continue;\n } else if (runStep.type !== StepTypes.TOOL_CALLS) {\n console.warn(\n `Run step for ${stepId} is not a tool call step, cannot dispatch tool result.`\n );\n continue;\n }\n\n const toolCall =\n runStep.stepDetails.type === StepTypes.TOOL_CALLS\n ? (runStep.stepDetails.tool_calls?.find(\n (toolCall) => toolCall.id === toolUseId\n ) as ToolCall)\n : undefined;\n\n if (!toolCall) {\n continue;\n }\n\n if (\n contentPart.type === 'web_search_result' ||\n contentPart.type === 'web_search_tool_result'\n ) {\n await handleAnthropicSearchResults({\n contentPart: contentPart as t.ToolResultContent,\n toolCall,\n metadata,\n graph,\n });\n }\n\n if (!skipHandling) {\n skipHandling = true;\n }\n }\n\n return skipHandling;\n}\n\nasync function handleAnthropicSearchResults({\n contentPart,\n toolCall,\n metadata,\n graph,\n}: {\n contentPart: t.ToolResultContent;\n toolCall: Partial<ToolCall>;\n metadata?: Record<string, unknown>;\n graph: StandardGraph | MultiAgentGraph;\n}): Promise<void> {\n if (!Array.isArray(contentPart.content)) {\n console.warn(\n `Expected content to be an array, got ${typeof contentPart.content}`\n );\n return;\n }\n\n if (!isAnthropicWebSearchResult(contentPart.content[0])) {\n console.warn(\n `Expected content to be an Anthropic web search result, got ${JSON.stringify(\n contentPart.content\n )}`\n );\n return;\n }\n\n const turn = graph.invokedToolIds?.size ?? 0;\n const searchResultData = coerceAnthropicSearchResults({\n turn,\n results: contentPart.content as AnthropicWebSearchResultBlockParam[],\n });\n\n const name = toolCall.name;\n const input = toolCall.args ?? {};\n const artifact = {\n [Constants.WEB_SEARCH]: searchResultData,\n };\n const { output: formattedOutput } = formatResultsForLLM(\n turn,\n searchResultData\n );\n const output = new ToolMessage({\n name,\n artifact,\n content: formattedOutput,\n tool_call_id: toolCall.id!,\n });\n const toolEndData: t.ToolEndData = {\n input,\n output,\n };\n await graph.handlerRegistry\n ?.getHandler(GraphEvents.TOOL_END)\n ?.handle(GraphEvents.TOOL_END, toolEndData, metadata, graph);\n\n if (graph.invokedToolIds == null) {\n graph.invokedToolIds = new Set<string>();\n }\n\n graph.invokedToolIds.add(toolCall.id!);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"handlers.mjs","names":[],"sources":["../../../src/tools/handlers.ts"],"sourcesContent":["/* eslint-disable no-console */\n// src/tools/handlers.ts\nimport { nanoid } from 'nanoid';\nimport { ToolMessage } from '@langchain/core/messages';\nimport type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';\nimport type { AnthropicWebSearchResultBlockParam } from '@/llm/anthropic/types';\nimport type { Graph, MultiAgentGraph, StandardGraph } from '@/graphs';\nimport type { AgentContext } from '@/agents/AgentContext';\nimport type * as t from '@/types';\nimport {\n coerceAnthropicSearchResults,\n isAnthropicWebSearchResult,\n} from '@/tools/search/anthropic';\nimport {\n ToolCallTypes,\n GraphEvents,\n StepTypes,\n Providers,\n Constants,\n} from '@/common';\nimport { formatResultsForLLM } from '@/tools/search/format';\nimport { getMessageId } from '@/messages';\n\nexport async function handleToolCallChunks({\n graph,\n stepKey,\n toolCallChunks,\n metadata,\n}: {\n graph: StandardGraph | MultiAgentGraph;\n stepKey: string;\n toolCallChunks: ToolCallChunk[];\n metadata?: Record<string, unknown>;\n}): Promise<void> {\n let prevStepId: string;\n let prevRunStep: t.RunStep | undefined;\n try {\n prevStepId = graph.getStepIdByKey(stepKey);\n prevRunStep = graph.getRunStep(prevStepId);\n } catch {\n /** Edge Case: If no previous step exists, create a new message creation step */\n const message_id = getMessageId(stepKey, graph, true) ?? '';\n prevStepId = await graph.dispatchRunStep(\n stepKey,\n {\n type: StepTypes.MESSAGE_CREATION,\n message_creation: {\n message_id,\n },\n },\n metadata\n );\n prevRunStep = graph.getRunStep(prevStepId);\n }\n\n const _stepId = graph.getStepIdByKey(stepKey);\n\n /** Edge Case: Tool Call Run Step or `tool_call_ids` never dispatched */\n const tool_calls: ToolCall[] | undefined =\n prevStepId && prevRunStep && prevRunStep.type === StepTypes.MESSAGE_CREATION\n ? []\n : undefined;\n\n /** Edge Case: `id` and `name` fields cannot be empty strings */\n for (const toolCallChunk of toolCallChunks) {\n if (toolCallChunk.name === '') {\n toolCallChunk.name = undefined;\n }\n if (toolCallChunk.id === '') {\n toolCallChunk.id = undefined;\n } else if (\n tool_calls != null &&\n toolCallChunk.id != null &&\n toolCallChunk.name != null\n ) {\n tool_calls.push({\n args: {},\n id: toolCallChunk.id,\n name: toolCallChunk.name,\n type: ToolCallTypes.TOOL_CALL,\n });\n }\n }\n\n let stepId: string = _stepId;\n const alreadyDispatched =\n prevRunStep?.type === StepTypes.MESSAGE_CREATION &&\n graph.messageStepHasToolCalls.has(prevStepId);\n\n if (prevRunStep?.type === StepTypes.TOOL_CALLS) {\n /**\n * If previous step is already a tool_calls step, use that step ID\n * This ensures tool call deltas are dispatched to the correct step\n */\n stepId = prevStepId;\n } else if (\n !alreadyDispatched &&\n prevRunStep?.type === StepTypes.MESSAGE_CREATION\n ) {\n /**\n * Create tool_calls step as soon as we receive the first tool call chunk\n * This ensures deltas are always associated with the correct step\n *\n * NOTE: We do NOT dispatch an empty text block here because:\n * - Empty text blocks cause providers (Anthropic, Bedrock) to reject messages\n * - The tool_calls themselves are sufficient for the step\n * - Empty content with tool_call_ids gets stored in conversation history\n * and causes \"messages must have non-empty content\" errors on replay\n */\n graph.messageStepHasToolCalls.set(prevStepId, true);\n stepId = await graph.dispatchRunStep(\n stepKey,\n {\n type: StepTypes.TOOL_CALLS,\n tool_calls: tool_calls ?? [],\n },\n metadata\n );\n }\n\n await graph.dispatchRunStepDelta(\n stepId,\n {\n type: StepTypes.TOOL_CALLS,\n tool_calls: toolCallChunks,\n },\n metadata\n );\n}\n\nexport const handleToolCalls = async (\n toolCalls?: ToolCall[],\n metadata?: Record<string, unknown>,\n graph?: Graph | StandardGraph | MultiAgentGraph\n): Promise<void> => {\n if (!graph || !metadata) {\n console.warn('Graph or metadata not found in `handleToolCalls`');\n return;\n }\n\n if (!toolCalls) {\n return;\n }\n\n if (toolCalls.length === 0) {\n return;\n }\n\n const stepKey = graph.getStepKey(metadata);\n\n /**\n * Track whether we've already reused an empty TOOL_CALLS step created by\n * handleToolCallChunks during streaming. Only reuse it once (for the first\n * tool call); subsequent parallel tool calls must create their own steps.\n */\n let reusedChunkStepId: string | undefined;\n\n for (const tool_call of toolCalls) {\n const toolCallId = tool_call.id ?? `toolu_${nanoid()}`;\n tool_call.id = toolCallId;\n if (!toolCallId || graph.toolCallStepIds.has(toolCallId)) {\n continue;\n }\n\n let prevStepId = '';\n let prevRunStep: t.RunStep | undefined;\n try {\n prevStepId = graph.getStepIdByKey(stepKey);\n prevRunStep = graph.getRunStep(prevStepId);\n } catch {\n // no previous step\n }\n\n /**\n * If the previous step is TOOL_CALLS (from handleToolCallChunks or a prior\n * iteration), either reuse it (if empty) or dispatch a new TOOL_CALLS step\n * directly — skip the intermediate MESSAGE_CREATION to avoid orphaned gaps.\n */\n if (prevRunStep?.type === StepTypes.TOOL_CALLS) {\n const details = prevRunStep.stepDetails as t.ToolCallsDetails;\n const isEmpty = !details.tool_calls || details.tool_calls.length === 0;\n if (isEmpty && prevStepId !== reusedChunkStepId) {\n graph.toolCallStepIds.set(toolCallId, prevStepId);\n graph.registerPendingToolCall(toolCallId, prevStepId);\n reusedChunkStepId = prevStepId;\n continue;\n }\n await graph.dispatchRunStep(\n stepKey,\n { type: StepTypes.TOOL_CALLS, tool_calls: [tool_call] },\n metadata\n );\n continue;\n }\n\n /**\n * NOTE: We do NOT dispatch empty text blocks with tool_call_ids because:\n * - Empty text blocks cause providers (Anthropic, Bedrock) to reject messages\n * - They get stored in conversation history and cause errors on replay:\n * \"messages must have non-empty content\" (Anthropic)\n * \"The content field in the Message object is empty\" (Bedrock)\n * - The tool_calls themselves are sufficient\n */\n if (prevStepId && prevRunStep) {\n graph.messageStepHasToolCalls.set(prevStepId, true);\n } else if (!prevRunStep) {\n const messageId = getMessageId(stepKey, graph, true) ?? '';\n const stepId = await graph.dispatchRunStep(\n stepKey,\n {\n type: StepTypes.MESSAGE_CREATION,\n message_creation: {\n message_id: messageId,\n },\n },\n metadata\n );\n graph.messageStepHasToolCalls.set(stepId, true);\n }\n\n await graph.dispatchRunStep(\n stepKey,\n {\n type: StepTypes.TOOL_CALLS,\n tool_calls: [tool_call],\n },\n metadata\n );\n }\n};\n\nexport const toolResultTypes = new Set([\n // 'tool_use',\n // 'server_tool_use',\n // 'input_json_delta',\n 'tool_result',\n 'web_search_result',\n 'web_search_tool_result',\n]);\n\n/**\n * Handles the result of a server tool call; in other words, a provider's built-in tool.\n * As of 2025-07-06, only Anthropic handles server tool calls with this pattern.\n */\nexport async function handleServerToolResult({\n graph,\n content,\n metadata,\n agentContext,\n}: {\n graph: StandardGraph | MultiAgentGraph;\n content?: string | t.MessageContentComplex[];\n metadata?: Record<string, unknown>;\n agentContext?: AgentContext;\n}): Promise<boolean> {\n let skipHandling = false;\n if (agentContext?.provider !== Providers.ANTHROPIC) {\n return skipHandling;\n }\n if (\n typeof content === 'string' ||\n content == null ||\n content.length === 0 ||\n (content.length === 1 &&\n (content[0] as t.ToolResultContent).tool_use_id == null)\n ) {\n return skipHandling;\n }\n\n for (const contentPart of content) {\n const toolUseId = (contentPart as t.ToolResultContent).tool_use_id;\n if (toolUseId == null || toolUseId === '') {\n continue;\n }\n const stepId = graph.toolCallStepIds.get(toolUseId);\n if (stepId == null || stepId === '') {\n console.warn(\n `Tool use ID ${toolUseId} not found in graph, cannot dispatch tool result.`\n );\n continue;\n }\n const runStep = graph.getRunStep(stepId);\n if (!runStep) {\n console.warn(\n `Run step for ${stepId} does not exist, cannot dispatch tool result.`\n );\n continue;\n } else if (runStep.type !== StepTypes.TOOL_CALLS) {\n console.warn(\n `Run step for ${stepId} is not a tool call step, cannot dispatch tool result.`\n );\n continue;\n }\n\n const toolCall =\n runStep.stepDetails.type === StepTypes.TOOL_CALLS\n ? (runStep.stepDetails.tool_calls?.find(\n (toolCall) => toolCall.id === toolUseId\n ) as ToolCall)\n : undefined;\n\n if (!toolCall) {\n continue;\n }\n\n if (\n contentPart.type === 'web_search_result' ||\n contentPart.type === 'web_search_tool_result'\n ) {\n await handleAnthropicSearchResults({\n contentPart: contentPart as t.ToolResultContent,\n toolCall,\n metadata,\n graph,\n });\n }\n\n if (!skipHandling) {\n skipHandling = true;\n }\n }\n\n return skipHandling;\n}\n\nasync function handleAnthropicSearchResults({\n contentPart,\n toolCall,\n metadata,\n graph,\n}: {\n contentPart: t.ToolResultContent;\n toolCall: Partial<ToolCall>;\n metadata?: Record<string, unknown>;\n graph: StandardGraph | MultiAgentGraph;\n}): Promise<void> {\n if (!Array.isArray(contentPart.content)) {\n console.warn(\n `Expected content to be an array, got ${typeof contentPart.content}`\n );\n return;\n }\n\n if (!isAnthropicWebSearchResult(contentPart.content[0])) {\n console.warn(\n `Expected content to be an Anthropic web search result, got ${JSON.stringify(\n contentPart.content\n )}`\n );\n return;\n }\n\n const turn = graph.invokedToolIds?.size ?? 0;\n const searchResultData = coerceAnthropicSearchResults({\n turn,\n results: contentPart.content as AnthropicWebSearchResultBlockParam[],\n });\n\n const name = toolCall.name;\n const input = toolCall.args ?? {};\n const artifact = {\n [Constants.WEB_SEARCH]: searchResultData,\n };\n const { output: formattedOutput } = formatResultsForLLM(\n turn,\n searchResultData\n );\n const output = new ToolMessage({\n name,\n artifact,\n content: formattedOutput,\n tool_call_id: toolCall.id!,\n });\n const toolEndData: t.ToolEndData = {\n input,\n output,\n };\n await graph.handlerRegistry\n ?.getHandler(GraphEvents.TOOL_END)\n ?.handle(GraphEvents.TOOL_END, toolEndData, metadata, graph);\n\n if (graph.invokedToolIds == null) {\n graph.invokedToolIds = new Set<string>();\n }\n\n graph.invokedToolIds.add(toolCall.id!);\n}\n"],"mappings":"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"}
|
|
@@ -1380,6 +1380,10 @@ var SubagentExecutor = class {
|
|
|
1380
1380
|
scheduleWrap(eventName, "run_step_completed", data, memberAgentId);
|
|
1381
1381
|
return;
|
|
1382
1382
|
}
|
|
1383
|
+
if (eventName === "on_run_step_closed") {
|
|
1384
|
+
scheduleWrap(eventName, "run_step_closed", data, memberAgentId);
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1383
1387
|
if (eventName === "on_message_delta") {
|
|
1384
1388
|
scheduleWrap(eventName, "message_delta", data, memberAgentId);
|
|
1385
1389
|
return;
|
|
@@ -1585,6 +1589,7 @@ function sanitizeForwardedSubagentUpdateData(eventName, data) {
|
|
|
1585
1589
|
if (eventName === "on_run_step") return sanitizeRunStepUpdateData(data);
|
|
1586
1590
|
if (eventName === "on_run_step_delta") return sanitizeRunStepDeltaUpdateData(data);
|
|
1587
1591
|
if (eventName === "on_run_step_completed") return sanitizeRunStepCompletedUpdateData(data);
|
|
1592
|
+
if (eventName === "on_run_step_closed") return sanitizeRunStepClosedUpdateData(data);
|
|
1588
1593
|
if (eventName === "on_message_delta") return sanitizeMessageDeltaUpdateData(data);
|
|
1589
1594
|
if (eventName === "on_reasoning_delta") return sanitizeReasoningDeltaUpdateData(data);
|
|
1590
1595
|
}
|
|
@@ -1609,10 +1614,12 @@ function sanitizeRunStepUpdateData(data) {
|
|
|
1609
1614
|
const step = data;
|
|
1610
1615
|
const sanitized = {};
|
|
1611
1616
|
assignString(sanitized, "agentId", step.agentId);
|
|
1617
|
+
assignNumber(sanitized, "created_at", step.created_at);
|
|
1612
1618
|
assignNumber(sanitized, "groupId", step.groupId);
|
|
1613
1619
|
assignString(sanitized, "id", step.id);
|
|
1614
1620
|
assignNumber(sanitized, "index", step.index);
|
|
1615
1621
|
assignString(sanitized, "runId", step.runId);
|
|
1622
|
+
assignString(sanitized, "status", step.status);
|
|
1616
1623
|
assignNumber(sanitized, "stepIndex", step.stepIndex);
|
|
1617
1624
|
assignString(sanitized, "type", step.type);
|
|
1618
1625
|
if (step.summary !== void 0) sanitized.summary = step.summary;
|
|
@@ -1620,6 +1627,22 @@ function sanitizeRunStepUpdateData(data) {
|
|
|
1620
1627
|
sanitized.stepDetails = sanitizeStepDetails(step.stepDetails);
|
|
1621
1628
|
return sanitized;
|
|
1622
1629
|
}
|
|
1630
|
+
function sanitizeRunStepClosedUpdateData(data) {
|
|
1631
|
+
if (!isObjectLike(data)) return;
|
|
1632
|
+
const event = data;
|
|
1633
|
+
const sanitized = {};
|
|
1634
|
+
assignString(sanitized, "agentId", event.agentId);
|
|
1635
|
+
assignNumber(sanitized, "closed_at", event.closed_at);
|
|
1636
|
+
assignNumber(sanitized, "created_at", event.created_at);
|
|
1637
|
+
assignNumber(sanitized, "groupId", event.groupId);
|
|
1638
|
+
assignString(sanitized, "id", event.id);
|
|
1639
|
+
assignNumber(sanitized, "index", event.index);
|
|
1640
|
+
assignString(sanitized, "runId", event.runId);
|
|
1641
|
+
assignString(sanitized, "status", event.status);
|
|
1642
|
+
assignNumber(sanitized, "stepIndex", event.stepIndex);
|
|
1643
|
+
assignString(sanitized, "type", event.type);
|
|
1644
|
+
return sanitized;
|
|
1645
|
+
}
|
|
1623
1646
|
function sanitizeRunStepDeltaUpdateData(data) {
|
|
1624
1647
|
if (!isObjectLike(data)) return;
|
|
1625
1648
|
const event = data;
|
|
@@ -1695,6 +1718,7 @@ function sanitizeStepCompleted(data) {
|
|
|
1695
1718
|
const sanitized = { type: "tool_call" };
|
|
1696
1719
|
assignString(sanitized, "id", completed.id);
|
|
1697
1720
|
assignNumber(sanitized, "index", completed.index);
|
|
1721
|
+
assignNumber(sanitized, "completed_at", completed.completed_at);
|
|
1698
1722
|
sanitized.tool_call = sanitizeProcessedToolCall(completed.tool_call);
|
|
1699
1723
|
return sanitized;
|
|
1700
1724
|
}
|
|
@@ -1760,6 +1784,10 @@ function summarizeEvent(eventName, data) {
|
|
|
1760
1784
|
if (tool?.name != null && tool.name !== "") return `Tool ${tool.name} complete`;
|
|
1761
1785
|
return "Step complete";
|
|
1762
1786
|
}
|
|
1787
|
+
if (eventName === "on_run_step_closed") {
|
|
1788
|
+
const closed = data;
|
|
1789
|
+
return closed.status != null && closed.status !== "" ? `Step ${closed.status}` : "Step closed";
|
|
1790
|
+
}
|
|
1763
1791
|
if (eventName === "on_message_delta") return "Streaming…";
|
|
1764
1792
|
return eventName;
|
|
1765
1793
|
}
|