@inkeep/agents-run-api 0.0.0-dev-20251222193909 → 0.0.0-dev-20251222214618

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.
Files changed (173) hide show
  1. package/dist/_virtual/_raw_/home/runner/work/agents/agents/agents-run-api/templates/v1/phase1/system-prompt.js +5 -0
  2. package/dist/_virtual/_raw_/home/runner/work/agents/agents/agents-run-api/templates/v1/phase1/thinking-preparation.js +5 -0
  3. package/dist/_virtual/_raw_/home/runner/work/agents/agents/agents-run-api/templates/v1/phase1/tool.js +5 -0
  4. package/dist/_virtual/_raw_/home/runner/work/agents/agents/agents-run-api/templates/v1/phase2/data-component.js +5 -0
  5. package/dist/_virtual/_raw_/home/runner/work/agents/agents/agents-run-api/templates/v1/phase2/data-components.js +5 -0
  6. package/dist/_virtual/_raw_/home/runner/work/agents/agents/agents-run-api/templates/v1/phase2/system-prompt.js +5 -0
  7. package/dist/_virtual/_raw_/home/runner/work/agents/agents/agents-run-api/templates/v1/shared/artifact-retrieval-guidance.js +5 -0
  8. package/dist/_virtual/_raw_/home/runner/work/agents/agents/agents-run-api/templates/v1/shared/artifact.js +5 -0
  9. package/dist/a2a/client.d.ts +184 -0
  10. package/dist/a2a/client.js +510 -0
  11. package/dist/a2a/handlers.d.ts +7 -0
  12. package/dist/a2a/handlers.js +559 -0
  13. package/dist/a2a/transfer.d.ts +22 -0
  14. package/dist/a2a/transfer.js +46 -0
  15. package/dist/a2a/types.d.ts +79 -0
  16. package/dist/a2a/types.js +22 -0
  17. package/dist/agents/Agent.d.ts +220 -0
  18. package/dist/agents/Agent.js +1938 -0
  19. package/dist/agents/ModelFactory.d.ts +63 -0
  20. package/dist/agents/ModelFactory.js +194 -0
  21. package/dist/agents/SystemPromptBuilder.d.ts +21 -0
  22. package/dist/agents/SystemPromptBuilder.js +48 -0
  23. package/dist/agents/ToolSessionManager.d.ts +63 -0
  24. package/dist/agents/ToolSessionManager.js +146 -0
  25. package/dist/agents/generateTaskHandler.d.ts +49 -0
  26. package/dist/agents/generateTaskHandler.js +512 -0
  27. package/dist/agents/relationTools.d.ts +57 -0
  28. package/dist/agents/relationTools.js +262 -0
  29. package/dist/agents/types.d.ts +28 -0
  30. package/dist/agents/types.js +1 -0
  31. package/dist/agents/versions/v1/Phase1Config.d.ts +26 -0
  32. package/dist/agents/versions/v1/Phase1Config.js +413 -0
  33. package/dist/agents/versions/v1/Phase2Config.d.ts +31 -0
  34. package/dist/agents/versions/v1/Phase2Config.js +330 -0
  35. package/dist/constants/execution-limits/defaults.d.ts +47 -0
  36. package/dist/constants/execution-limits/defaults.js +48 -0
  37. package/dist/constants/execution-limits/index.d.ts +6 -0
  38. package/dist/constants/execution-limits/index.js +16 -0
  39. package/dist/create-app.d.ts +9 -0
  40. package/dist/create-app.js +195 -0
  41. package/dist/data/agent.d.ts +7 -0
  42. package/dist/data/agent.js +72 -0
  43. package/dist/data/agents.d.ts +34 -0
  44. package/dist/data/agents.js +139 -0
  45. package/dist/data/conversations.d.ts +88 -0
  46. package/dist/{conversations2.js → data/conversations.js} +42 -7
  47. package/dist/data/db/dbClient.d.ts +6 -0
  48. package/dist/data/db/dbClient.js +17 -0
  49. package/dist/env.d.ts +57 -0
  50. package/dist/env.js +1 -2
  51. package/dist/handlers/executionHandler.d.ts +39 -0
  52. package/dist/handlers/executionHandler.js +456 -0
  53. package/dist/index.d.ts +8 -29
  54. package/dist/index.js +5 -11487
  55. package/dist/instrumentation.d.ts +1 -2
  56. package/dist/instrumentation.js +66 -3
  57. package/dist/{logger2.js → logger.d.ts} +1 -2
  58. package/dist/logger.js +1 -1
  59. package/dist/middleware/api-key-auth.d.ts +26 -0
  60. package/dist/middleware/api-key-auth.js +240 -0
  61. package/dist/middleware/index.d.ts +2 -0
  62. package/dist/middleware/index.js +3 -0
  63. package/dist/openapi.d.ts +4 -0
  64. package/dist/openapi.js +54 -0
  65. package/dist/routes/agents.d.ts +12 -0
  66. package/dist/routes/agents.js +147 -0
  67. package/dist/routes/chat.d.ts +13 -0
  68. package/dist/routes/chat.js +293 -0
  69. package/dist/routes/chatDataStream.d.ts +13 -0
  70. package/dist/routes/chatDataStream.js +352 -0
  71. package/dist/routes/mcp.d.ts +13 -0
  72. package/dist/routes/mcp.js +495 -0
  73. package/dist/services/AgentSession.d.ts +356 -0
  74. package/dist/services/AgentSession.js +1208 -0
  75. package/dist/services/ArtifactParser.d.ts +105 -0
  76. package/dist/services/ArtifactParser.js +338 -0
  77. package/dist/services/ArtifactService.d.ts +123 -0
  78. package/dist/services/ArtifactService.js +611 -0
  79. package/dist/services/IncrementalStreamParser.d.ts +98 -0
  80. package/dist/services/IncrementalStreamParser.js +327 -0
  81. package/dist/services/MidGenerationCompressor.d.ts +91 -0
  82. package/dist/services/MidGenerationCompressor.js +375 -0
  83. package/dist/services/PendingToolApprovalManager.d.ts +62 -0
  84. package/dist/services/PendingToolApprovalManager.js +133 -0
  85. package/dist/services/ResponseFormatter.d.ts +39 -0
  86. package/dist/services/ResponseFormatter.js +152 -0
  87. package/dist/tools/NativeSandboxExecutor.d.ts +38 -0
  88. package/dist/tools/NativeSandboxExecutor.js +432 -0
  89. package/dist/tools/SandboxExecutorFactory.d.ts +36 -0
  90. package/dist/tools/SandboxExecutorFactory.js +80 -0
  91. package/dist/tools/VercelSandboxExecutor.d.ts +71 -0
  92. package/dist/tools/VercelSandboxExecutor.js +340 -0
  93. package/dist/tools/distill-conversation-tool.d.ts +41 -0
  94. package/dist/tools/distill-conversation-tool.js +156 -0
  95. package/dist/tools/sandbox-utils.d.ts +18 -0
  96. package/dist/tools/sandbox-utils.js +53 -0
  97. package/dist/types/chat.d.ts +27 -0
  98. package/dist/types/chat.js +1 -0
  99. package/dist/types/execution-context.d.ts +46 -0
  100. package/dist/types/execution-context.js +27 -0
  101. package/dist/types/xml.d.ts +5 -0
  102. package/dist/utils/SchemaProcessor.d.ts +52 -0
  103. package/dist/utils/SchemaProcessor.js +182 -0
  104. package/dist/utils/agent-operations.d.ts +62 -0
  105. package/dist/utils/agent-operations.js +53 -0
  106. package/dist/utils/artifact-component-schema.d.ts +42 -0
  107. package/dist/utils/artifact-component-schema.js +186 -0
  108. package/dist/utils/cleanup.d.ts +21 -0
  109. package/dist/utils/cleanup.js +59 -0
  110. package/dist/utils/data-component-schema.d.ts +2 -0
  111. package/dist/utils/data-component-schema.js +3 -0
  112. package/dist/utils/default-status-schemas.d.ts +20 -0
  113. package/dist/utils/default-status-schemas.js +24 -0
  114. package/dist/utils/json-postprocessor.d.ts +13 -0
  115. package/dist/{json-postprocessor.cjs → utils/json-postprocessor.js} +1 -2
  116. package/dist/utils/model-context-utils.d.ts +31 -0
  117. package/dist/utils/model-context-utils.js +149 -0
  118. package/dist/utils/model-resolver.d.ts +6 -0
  119. package/dist/utils/model-resolver.js +34 -0
  120. package/dist/utils/schema-validation.d.ts +44 -0
  121. package/dist/utils/schema-validation.js +97 -0
  122. package/dist/utils/stream-helpers.d.ts +197 -0
  123. package/dist/utils/stream-helpers.js +518 -0
  124. package/dist/utils/stream-registry.d.ts +22 -0
  125. package/dist/utils/stream-registry.js +34 -0
  126. package/dist/utils/token-estimator.d.ts +69 -0
  127. package/dist/utils/token-estimator.js +53 -0
  128. package/dist/utils/tracer.d.ts +7 -0
  129. package/dist/utils/tracer.js +7 -0
  130. package/package.json +4 -20
  131. package/dist/SandboxExecutorFactory.cjs +0 -895
  132. package/dist/SandboxExecutorFactory.js +0 -893
  133. package/dist/SandboxExecutorFactory.js.map +0 -1
  134. package/dist/chunk-VBDAOXYI.cjs +0 -927
  135. package/dist/chunk-VBDAOXYI.js +0 -832
  136. package/dist/chunk-VBDAOXYI.js.map +0 -1
  137. package/dist/chunk.cjs +0 -34
  138. package/dist/conversations.cjs +0 -7
  139. package/dist/conversations.js +0 -7
  140. package/dist/conversations2.cjs +0 -209
  141. package/dist/conversations2.js.map +0 -1
  142. package/dist/dbClient.cjs +0 -9676
  143. package/dist/dbClient.js +0 -9670
  144. package/dist/dbClient.js.map +0 -1
  145. package/dist/dbClient2.cjs +0 -5
  146. package/dist/dbClient2.js +0 -5
  147. package/dist/env.cjs +0 -59
  148. package/dist/env.js.map +0 -1
  149. package/dist/execution-limits.cjs +0 -260
  150. package/dist/execution-limits.js +0 -63
  151. package/dist/execution-limits.js.map +0 -1
  152. package/dist/index.cjs +0 -11512
  153. package/dist/index.d.cts +0 -36
  154. package/dist/index.d.cts.map +0 -1
  155. package/dist/index.d.ts.map +0 -1
  156. package/dist/index.js.map +0 -1
  157. package/dist/instrumentation.cjs +0 -12
  158. package/dist/instrumentation.d.cts +0 -18
  159. package/dist/instrumentation.d.cts.map +0 -1
  160. package/dist/instrumentation.d.ts.map +0 -1
  161. package/dist/instrumentation2.cjs +0 -116
  162. package/dist/instrumentation2.js +0 -69
  163. package/dist/instrumentation2.js.map +0 -1
  164. package/dist/json-postprocessor.js +0 -20
  165. package/dist/json-postprocessor.js.map +0 -1
  166. package/dist/logger.cjs +0 -5
  167. package/dist/logger2.cjs +0 -1
  168. package/dist/nodefs.cjs +0 -29
  169. package/dist/nodefs.js +0 -27
  170. package/dist/nodefs.js.map +0 -1
  171. package/dist/opfs-ahp.cjs +0 -367
  172. package/dist/opfs-ahp.js +0 -368
  173. package/dist/opfs-ahp.js.map +0 -1
@@ -0,0 +1,1938 @@
1
+ import { getLogger } from "../logger.js";
2
+ import dbClient_default from "../data/db/dbClient.js";
3
+ import { AGENT_EXECUTION_MAX_GENERATION_STEPS, FUNCTION_TOOL_EXECUTION_TIMEOUT_MS_DEFAULT, FUNCTION_TOOL_SANDBOX_VCPUS_DEFAULT, LLM_GENERATION_FIRST_CALL_TIMEOUT_MS_NON_STREAMING, LLM_GENERATION_FIRST_CALL_TIMEOUT_MS_STREAMING, LLM_GENERATION_MAX_ALLOWED_TIMEOUT_MS, LLM_GENERATION_SUBSEQUENT_CALL_TIMEOUT_MS } from "../constants/execution-limits/index.js";
4
+ import { toolSessionManager } from "./ToolSessionManager.js";
5
+ import { createDefaultConversationHistoryConfig, getFormattedConversationHistory } from "../data/conversations.js";
6
+ import { getStreamHelper } from "../utils/stream-registry.js";
7
+ import { setSpanWithError as setSpanWithError$1, tracer } from "../utils/tracer.js";
8
+ import { agentSessionManager } from "../services/AgentSession.js";
9
+ import { IncrementalStreamParser } from "../services/IncrementalStreamParser.js";
10
+ import { MidGenerationCompressor, getCompressionConfigFromEnv } from "../services/MidGenerationCompressor.js";
11
+ import { pendingToolApprovalManager } from "../services/PendingToolApprovalManager.js";
12
+ import { ResponseFormatter } from "../services/ResponseFormatter.js";
13
+ import { generateToolId } from "../utils/agent-operations.js";
14
+ import { jsonSchemaToZod } from "../utils/data-component-schema.js";
15
+ import { ArtifactCreateSchema, ArtifactReferenceSchema } from "../utils/artifact-component-schema.js";
16
+ import { getCompressionConfigForModel } from "../utils/model-context-utils.js";
17
+ import { calculateBreakdownTotal, estimateTokens } from "../utils/token-estimator.js";
18
+ import { createDelegateToAgentTool, createTransferToAgentTool } from "./relationTools.js";
19
+ import { SystemPromptBuilder } from "./SystemPromptBuilder.js";
20
+ import { Phase1Config } from "./versions/v1/Phase1Config.js";
21
+ import { Phase2Config } from "./versions/v1/Phase2Config.js";
22
+ import { z } from "@hono/zod-openapi";
23
+ import { ContextResolver, CredentialStuffer, MCPServerType, MCPTransportType, McpClient, ModelFactory, TemplateEngine, agentHasArtifactComponents, createMessage, generateId, getContextConfigById, getCredentialReference, getFullAgentDefinition, getFunction, getFunctionToolsForSubAgent, getLedgerArtifacts, getToolsForAgent, getUserScopedCredentialReference, listTaskIdsByContextId, parseEmbeddedJson } from "@inkeep/agents-core";
24
+ import { SpanStatusCode, trace } from "@opentelemetry/api";
25
+ import { generateObject, generateText, streamObject, streamText, tool } from "ai";
26
+
27
+ //#region src/agents/Agent.ts
28
+ /**
29
+ * Creates a stopWhen condition that stops when any tool call name starts with the given prefix
30
+ * @param prefix - The prefix to check for in tool call names
31
+ * @returns A function that can be used as a stopWhen condition
32
+ */
33
+ function hasToolCallWithPrefix(prefix) {
34
+ return ({ steps }) => {
35
+ const last = steps.at(-1);
36
+ if (last && "toolCalls" in last && last.toolCalls) return last.toolCalls.some((tc) => tc.toolName.startsWith(prefix));
37
+ return false;
38
+ };
39
+ }
40
+ const logger = getLogger("Agent");
41
+ function validateModel(modelString, modelType) {
42
+ if (!modelString?.trim()) throw new Error(`${modelType} model is required. Please configure models at the project level.`);
43
+ return modelString.trim();
44
+ }
45
+ function isValidTool(tool$1) {
46
+ return tool$1 && typeof tool$1 === "object" && typeof tool$1.description === "string" && tool$1.inputSchema && typeof tool$1.execute === "function";
47
+ }
48
+ var Agent = class {
49
+ config;
50
+ systemPromptBuilder = new SystemPromptBuilder("v1", new Phase1Config());
51
+ credentialStuffer;
52
+ streamHelper;
53
+ streamRequestId;
54
+ conversationId;
55
+ delegationId;
56
+ artifactComponents = [];
57
+ isDelegatedAgent = false;
58
+ contextResolver;
59
+ credentialStoreRegistry;
60
+ mcpClientCache = /* @__PURE__ */ new Map();
61
+ mcpConnectionLocks = /* @__PURE__ */ new Map();
62
+ currentCompressor = null;
63
+ constructor(config, credentialStoreRegistry) {
64
+ this.artifactComponents = config.artifactComponents || [];
65
+ let processedDataComponents = config.dataComponents || [];
66
+ if (processedDataComponents.length > 0) processedDataComponents.push({
67
+ id: "text-content",
68
+ name: "Text",
69
+ description: "Natural conversational text for the user - write naturally without mentioning technical details. Avoid redundancy and repetition with data components.",
70
+ props: {
71
+ type: "object",
72
+ properties: { text: {
73
+ type: "string",
74
+ description: "Natural conversational text - respond as if having a normal conversation, never mention JSON, components, schemas, or technical implementation. Avoid redundancy and repetition with data components."
75
+ } },
76
+ required: ["text"]
77
+ }
78
+ });
79
+ if (this.artifactComponents.length > 0 && config.dataComponents && config.dataComponents.length > 0) processedDataComponents = [ArtifactReferenceSchema.getDataComponent(config.tenantId, config.projectId), ...processedDataComponents];
80
+ this.config = {
81
+ ...config,
82
+ dataComponents: processedDataComponents,
83
+ conversationHistoryConfig: config.conversationHistoryConfig || createDefaultConversationHistoryConfig()
84
+ };
85
+ this.credentialStoreRegistry = credentialStoreRegistry;
86
+ if (credentialStoreRegistry) {
87
+ this.contextResolver = new ContextResolver(config.tenantId, config.projectId, dbClient_default, credentialStoreRegistry);
88
+ this.credentialStuffer = new CredentialStuffer(credentialStoreRegistry, this.contextResolver);
89
+ }
90
+ }
91
+ /**
92
+ * Get the maximum number of generation steps for this agent
93
+ * Uses agent's stopWhen.stepCountIs config or defaults to AGENT_EXECUTION_MAX_GENERATION_STEPS
94
+ */
95
+ getMaxGenerationSteps() {
96
+ return this.config.stopWhen?.stepCountIs ?? AGENT_EXECUTION_MAX_GENERATION_STEPS;
97
+ }
98
+ /**
99
+ * Sanitizes tool names at runtime for AI SDK compatibility.
100
+ * The AI SDK requires tool names to match pattern ^[a-zA-Z0-9_-]{1,128}$
101
+ */
102
+ sanitizeToolsForAISDK(tools) {
103
+ const sanitizedTools = {};
104
+ for (const [originalKey, toolDef] of Object.entries(tools)) {
105
+ let sanitizedKey = originalKey.replace(/[^a-zA-Z0-9_-]/g, "_");
106
+ sanitizedKey = sanitizedKey.replace(/_+/g, "_");
107
+ sanitizedKey = sanitizedKey.replace(/^_+|_+$/g, "");
108
+ if (!sanitizedKey || sanitizedKey.length === 0) sanitizedKey = "unnamed_tool";
109
+ if (sanitizedKey.length > 100) sanitizedKey = sanitizedKey.substring(0, 100);
110
+ let sanitizedId = (toolDef.id || originalKey).replace(/[^a-zA-Z0-9_.-]/g, "_");
111
+ sanitizedId = sanitizedId.replace(/_+/g, "_");
112
+ sanitizedId = sanitizedId.replace(/^_+|_+$/g, "");
113
+ if (sanitizedId.length > 128) sanitizedId = sanitizedId.substring(0, 128);
114
+ sanitizedTools[sanitizedKey] = {
115
+ ...toolDef,
116
+ id: sanitizedId
117
+ };
118
+ }
119
+ return sanitizedTools;
120
+ }
121
+ #createRelationToolName(prefix, targetId) {
122
+ return `${prefix}_to_${targetId.toLowerCase().replace(/\s+/g, "_")}`;
123
+ }
124
+ #getRelationshipIdForTool(toolName, toolType) {
125
+ if (toolType === "mcp") return (this.config.tools?.find((tool$1) => {
126
+ if (tool$1.config?.type !== "mcp") return false;
127
+ if (tool$1.availableTools?.some((available) => available.name === toolName)) return true;
128
+ if (tool$1.config.mcp.activeTools?.includes(toolName)) return true;
129
+ return tool$1.name === toolName;
130
+ }))?.relationshipId;
131
+ if (toolType === "delegation") return this.config.delegateRelations.find((relation) => this.#createRelationToolName("delegate", relation.config.id) === toolName)?.config.relationId;
132
+ }
133
+ /**
134
+ * Get the primary model settings for text generation and thinking
135
+ * Requires model to be configured at project level
136
+ */
137
+ getPrimaryModel() {
138
+ if (!this.config.models?.base) throw new Error("Base model configuration is required. Please configure models at the project level.");
139
+ return {
140
+ model: validateModel(this.config.models.base.model, "Base"),
141
+ providerOptions: this.config.models.base.providerOptions
142
+ };
143
+ }
144
+ /**
145
+ * Get the model settings for structured output generation
146
+ * Falls back to base model if structured output not configured
147
+ */
148
+ getStructuredOutputModel() {
149
+ if (!this.config.models) throw new Error("Model configuration is required. Please configure models at the project level.");
150
+ const structuredConfig = this.config.models.structuredOutput;
151
+ const baseConfig = this.config.models.base;
152
+ if (structuredConfig) return {
153
+ model: validateModel(structuredConfig.model, "Structured output"),
154
+ providerOptions: structuredConfig.providerOptions
155
+ };
156
+ if (!baseConfig) throw new Error("Base model configuration is required for structured output fallback. Please configure models at the project level.");
157
+ return {
158
+ model: validateModel(baseConfig.model, "Base (fallback for structured output)"),
159
+ providerOptions: baseConfig.providerOptions
160
+ };
161
+ }
162
+ /**
163
+ * Get the model settings for summarization/distillation
164
+ * Falls back to base model if summarizer not configured
165
+ */
166
+ getSummarizerModel() {
167
+ if (!this.config.models) throw new Error("Model configuration is required. Please configure models at the project level.");
168
+ const summarizerConfig = this.config.models.summarizer;
169
+ const baseConfig = this.config.models.base;
170
+ if (summarizerConfig) return {
171
+ model: validateModel(summarizerConfig.model, "Summarizer"),
172
+ providerOptions: summarizerConfig.providerOptions
173
+ };
174
+ if (!baseConfig) throw new Error("Base model configuration is required for summarizer fallback. Please configure models at the project level.");
175
+ return {
176
+ model: validateModel(baseConfig.model, "Base (fallback for summarizer)"),
177
+ providerOptions: baseConfig.providerOptions
178
+ };
179
+ }
180
+ setConversationId(conversationId) {
181
+ this.conversationId = conversationId;
182
+ }
183
+ /**
184
+ * Simple compression fallback: drop oldest messages to fit under token limit
185
+ */
186
+ simpleCompression(messages, targetTokens) {
187
+ if (messages.length === 0) return messages;
188
+ const estimateTokens$1 = (msg) => {
189
+ const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
190
+ return Math.ceil(content.length / 4);
191
+ };
192
+ let totalTokens = messages.reduce((sum, msg) => sum + estimateTokens$1(msg), 0);
193
+ if (totalTokens <= targetTokens) return messages;
194
+ const result = [...messages];
195
+ while (totalTokens > targetTokens && result.length > 1) {
196
+ const dropped = result.shift();
197
+ if (dropped) totalTokens -= estimateTokens$1(dropped);
198
+ }
199
+ return result;
200
+ }
201
+ /**
202
+ * Set delegation status for this agent instance
203
+ */
204
+ setDelegationStatus(isDelegated) {
205
+ this.isDelegatedAgent = isDelegated;
206
+ }
207
+ /**
208
+ * Set delegation ID for this agent instance
209
+ */
210
+ setDelegationId(delegationId) {
211
+ this.delegationId = delegationId;
212
+ }
213
+ /**
214
+ * Get streaming helper if this agent should stream to user
215
+ * Returns undefined for delegated agents to prevent streaming data operations to user
216
+ */
217
+ getStreamingHelper() {
218
+ return this.isDelegatedAgent ? void 0 : this.streamHelper;
219
+ }
220
+ /**
221
+ * Wraps a tool with streaming lifecycle tracking (start, complete, error) and AgentSession recording
222
+ */
223
+ wrapToolWithStreaming(toolName, toolDefinition, streamRequestId, toolType, options) {
224
+ if (!toolDefinition || typeof toolDefinition !== "object" || !("execute" in toolDefinition)) return toolDefinition;
225
+ const relationshipId = this.#getRelationshipIdForTool(toolName, toolType);
226
+ const originalExecute = toolDefinition.execute;
227
+ return {
228
+ ...toolDefinition,
229
+ execute: async (args, context$1) => {
230
+ const startTime = Date.now();
231
+ const toolCallId = context$1?.toolCallId || generateToolId();
232
+ const activeSpan = trace.getActiveSpan();
233
+ if (activeSpan) {
234
+ const attributes = {
235
+ "conversation.id": this.conversationId,
236
+ "tool.purpose": toolDefinition.description || "No description provided",
237
+ "ai.toolType": toolType || "unknown",
238
+ "subAgent.name": this.config.name || "unknown",
239
+ "subAgent.id": this.config.id || "unknown",
240
+ "agent.id": this.config.agentId || "unknown"
241
+ };
242
+ if (options?.mcpServerId) attributes["ai.toolCall.mcpServerId"] = options.mcpServerId;
243
+ if (options?.mcpServerName) attributes["ai.toolCall.mcpServerName"] = options.mcpServerName;
244
+ activeSpan.setAttributes(attributes);
245
+ }
246
+ const isInternalTool = toolName.includes("save_tool_result") || toolName.includes("thinking_complete") || toolName.startsWith("transfer_to_");
247
+ const needsApproval = options?.needsApproval || false;
248
+ if (streamRequestId && !isInternalTool) {
249
+ const toolCallData = {
250
+ toolName,
251
+ input: args,
252
+ toolCallId,
253
+ relationshipId
254
+ };
255
+ if (needsApproval) {
256
+ toolCallData.needsApproval = true;
257
+ toolCallData.conversationId = this.conversationId;
258
+ }
259
+ await agentSessionManager.recordEvent(streamRequestId, "tool_call", this.config.id, toolCallData);
260
+ }
261
+ try {
262
+ const result = await originalExecute(args, context$1);
263
+ const duration = Date.now() - startTime;
264
+ const toolResultConversationId = this.getToolResultConversationId();
265
+ if (streamRequestId && !isInternalTool && toolResultConversationId) try {
266
+ const messagePayload = {
267
+ id: generateId(),
268
+ tenantId: this.config.tenantId,
269
+ projectId: this.config.projectId,
270
+ conversationId: toolResultConversationId,
271
+ role: "assistant",
272
+ content: { text: this.formatToolResult(toolName, args, result, toolCallId) },
273
+ visibility: "internal",
274
+ messageType: "tool-result",
275
+ fromSubAgentId: this.config.id,
276
+ metadata: { a2a_metadata: {
277
+ toolName,
278
+ toolCallId,
279
+ timestamp: Date.now(),
280
+ delegationId: this.delegationId,
281
+ isDelegated: this.isDelegatedAgent
282
+ } }
283
+ };
284
+ await createMessage(dbClient_default)(messagePayload);
285
+ } catch (error) {
286
+ logger.warn({
287
+ error,
288
+ toolName,
289
+ toolCallId,
290
+ conversationId: toolResultConversationId
291
+ }, "Failed to store tool result in conversation history");
292
+ }
293
+ if (streamRequestId && !isInternalTool) agentSessionManager.recordEvent(streamRequestId, "tool_result", this.config.id, {
294
+ toolName,
295
+ output: result,
296
+ toolCallId,
297
+ duration,
298
+ relationshipId,
299
+ needsApproval
300
+ });
301
+ return result;
302
+ } catch (error) {
303
+ const duration = Date.now() - startTime;
304
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
305
+ if (streamRequestId && !isInternalTool) agentSessionManager.recordEvent(streamRequestId, "tool_result", this.config.id, {
306
+ toolName,
307
+ output: null,
308
+ toolCallId,
309
+ duration,
310
+ error: errorMessage,
311
+ relationshipId,
312
+ needsApproval
313
+ });
314
+ throw error;
315
+ }
316
+ }
317
+ };
318
+ }
319
+ getRelationTools(runtimeContext, sessionId) {
320
+ const { transferRelations = [], delegateRelations = [] } = this.config;
321
+ return Object.fromEntries([...transferRelations.map((agentConfig) => {
322
+ const toolName = this.#createRelationToolName("transfer", agentConfig.id);
323
+ return [toolName, this.wrapToolWithStreaming(toolName, createTransferToAgentTool({
324
+ transferConfig: agentConfig,
325
+ callingAgentId: this.config.id,
326
+ subAgent: this,
327
+ streamRequestId: runtimeContext?.metadata?.streamRequestId
328
+ }), runtimeContext?.metadata?.streamRequestId, "transfer")];
329
+ }), ...delegateRelations.map((relation) => {
330
+ const toolName = this.#createRelationToolName("delegate", relation.config.id);
331
+ return [toolName, this.wrapToolWithStreaming(toolName, createDelegateToAgentTool({
332
+ delegateConfig: relation,
333
+ callingAgentId: this.config.id,
334
+ tenantId: this.config.tenantId,
335
+ projectId: this.config.projectId,
336
+ agentId: this.config.agentId,
337
+ contextId: runtimeContext?.contextId || "default",
338
+ metadata: runtimeContext?.metadata || {
339
+ conversationId: runtimeContext?.contextId || "default",
340
+ threadId: runtimeContext?.contextId || "default",
341
+ streamRequestId: runtimeContext?.metadata?.streamRequestId,
342
+ apiKey: runtimeContext?.metadata?.apiKey
343
+ },
344
+ sessionId,
345
+ subAgent: this,
346
+ credentialStoreRegistry: this.credentialStoreRegistry
347
+ }), runtimeContext?.metadata?.streamRequestId, "delegation")];
348
+ })]);
349
+ }
350
+ async getMcpTools(sessionId, streamRequestId) {
351
+ const mcpTools = this.config.tools?.filter((tool$1) => {
352
+ return tool$1.config?.type === "mcp";
353
+ }) || [];
354
+ const tools = await Promise.all(mcpTools.map((tool$1) => this.getMcpTool(tool$1)) || []) || [];
355
+ if (!sessionId) {
356
+ const wrappedTools$1 = {};
357
+ for (const toolSet of tools) for (const [toolName, toolDef] of Object.entries(toolSet.tools)) {
358
+ const needsApproval = toolSet.toolPolicies?.[toolName]?.needsApproval || false;
359
+ const enhancedTool = {
360
+ ...toolDef,
361
+ needsApproval
362
+ };
363
+ wrappedTools$1[toolName] = this.wrapToolWithStreaming(toolName, enhancedTool, streamRequestId, "mcp", {
364
+ needsApproval,
365
+ mcpServerId: toolSet.mcpServerId,
366
+ mcpServerName: toolSet.mcpServerName
367
+ });
368
+ }
369
+ return wrappedTools$1;
370
+ }
371
+ const wrappedTools = {};
372
+ for (const toolResult of tools) for (const [toolName, originalTool] of Object.entries(toolResult.tools)) {
373
+ if (!isValidTool(originalTool)) {
374
+ logger.error({ toolName }, "Invalid MCP tool structure - missing required properties");
375
+ continue;
376
+ }
377
+ const needsApproval = toolResult.toolPolicies?.[toolName]?.needsApproval || false;
378
+ logger.debug({
379
+ toolName,
380
+ toolPolicies: toolResult.toolPolicies,
381
+ needsApproval,
382
+ policyForThisTool: toolResult.toolPolicies?.[toolName]
383
+ }, "Tool approval check");
384
+ const sessionWrappedTool = tool({
385
+ description: originalTool.description,
386
+ inputSchema: originalTool.inputSchema,
387
+ execute: async (args, { toolCallId }) => {
388
+ let processedArgs;
389
+ try {
390
+ processedArgs = parseEmbeddedJson(args);
391
+ if (JSON.stringify(args) !== JSON.stringify(processedArgs)) logger.warn({
392
+ toolName,
393
+ toolCallId
394
+ }, "Fixed stringified JSON parameters (indicates schema ambiguity)");
395
+ } catch (error) {
396
+ logger.warn({
397
+ toolName,
398
+ toolCallId,
399
+ error: error.message
400
+ }, "Failed to parse embedded JSON, using original args");
401
+ processedArgs = args;
402
+ }
403
+ const finalArgs = processedArgs;
404
+ if (needsApproval) {
405
+ logger.info({
406
+ toolName,
407
+ toolCallId,
408
+ args: finalArgs
409
+ }, "Tool requires approval - waiting for user response");
410
+ const currentSpan = trace.getActiveSpan();
411
+ if (currentSpan) currentSpan.addEvent("tool.approval.requested", {
412
+ "tool.name": toolName,
413
+ "tool.callId": toolCallId,
414
+ "subAgent.id": this.config.id
415
+ });
416
+ tracer.startActiveSpan("tool.approval_requested", { attributes: {
417
+ "tool.name": toolName,
418
+ "tool.callId": toolCallId,
419
+ "subAgent.id": this.config.id,
420
+ "subAgent.name": this.config.name
421
+ } }, (requestSpan) => {
422
+ requestSpan.setStatus({ code: SpanStatusCode.OK });
423
+ requestSpan.end();
424
+ });
425
+ const approvalResult = await pendingToolApprovalManager.waitForApproval(toolCallId, toolName, args, this.conversationId || "unknown", this.config.id);
426
+ if (!approvalResult.approved) return tracer.startActiveSpan("tool.approval_denied", { attributes: {
427
+ "tool.name": toolName,
428
+ "tool.callId": toolCallId,
429
+ "subAgent.id": this.config.id,
430
+ "subAgent.name": this.config.name
431
+ } }, (denialSpan) => {
432
+ logger.info({
433
+ toolName,
434
+ toolCallId,
435
+ reason: approvalResult.reason
436
+ }, "Tool execution denied by user");
437
+ denialSpan.setStatus({ code: SpanStatusCode.OK });
438
+ denialSpan.end();
439
+ return `User denied approval to run this tool: ${approvalResult.reason}`;
440
+ });
441
+ tracer.startActiveSpan("tool.approval_approved", { attributes: {
442
+ "tool.name": toolName,
443
+ "tool.callId": toolCallId,
444
+ "subAgent.id": this.config.id,
445
+ "subAgent.name": this.config.name
446
+ } }, (approvedSpan) => {
447
+ logger.info({
448
+ toolName,
449
+ toolCallId
450
+ }, "Tool approved, continuing with execution");
451
+ approvedSpan.setStatus({ code: SpanStatusCode.OK });
452
+ approvedSpan.end();
453
+ });
454
+ }
455
+ logger.debug({
456
+ toolName,
457
+ toolCallId
458
+ }, "MCP Tool Called");
459
+ try {
460
+ const rawResult = await originalTool.execute(finalArgs, { toolCallId });
461
+ if (rawResult && typeof rawResult === "object" && rawResult.isError) {
462
+ const errorMessage = rawResult.content?.[0]?.text || "MCP tool returned an error";
463
+ logger.error({
464
+ toolName,
465
+ toolCallId,
466
+ errorMessage,
467
+ rawResult
468
+ }, "MCP tool returned error status");
469
+ toolSessionManager.recordToolResult(sessionId, {
470
+ toolCallId,
471
+ toolName,
472
+ args: finalArgs,
473
+ result: {
474
+ error: errorMessage,
475
+ failed: true
476
+ },
477
+ timestamp: Date.now()
478
+ });
479
+ if (streamRequestId) {
480
+ const relationshipId = this.#getRelationshipIdForTool(toolName, "mcp");
481
+ agentSessionManager.recordEvent(streamRequestId, "error", this.config.id, {
482
+ message: `MCP tool "${toolName}" failed: ${errorMessage}`,
483
+ code: "mcp_tool_error",
484
+ severity: "error",
485
+ context: {
486
+ toolName,
487
+ toolCallId,
488
+ errorMessage,
489
+ relationshipId
490
+ }
491
+ });
492
+ }
493
+ const activeSpan = trace.getActiveSpan();
494
+ if (activeSpan) {
495
+ const error = /* @__PURE__ */ new Error(`Tool "${toolName}" failed: ${errorMessage}. This tool is currently unavailable. Please try a different approach or inform the user of the issue.`);
496
+ activeSpan.recordException(error);
497
+ activeSpan.setStatus({
498
+ code: SpanStatusCode.ERROR,
499
+ message: `MCP tool returned error: ${errorMessage}`
500
+ });
501
+ }
502
+ throw new Error(`Tool "${toolName}" failed: ${errorMessage}. This tool is currently unavailable. Please try a different approach or inform the user of the issue.`);
503
+ }
504
+ const parsedResult = parseEmbeddedJson(rawResult);
505
+ const enhancedResult = this.enhanceToolResultWithStructureHints(parsedResult);
506
+ toolSessionManager.recordToolResult(sessionId, {
507
+ toolCallId,
508
+ toolName,
509
+ args: finalArgs,
510
+ result: enhancedResult,
511
+ timestamp: Date.now()
512
+ });
513
+ return {
514
+ result: enhancedResult,
515
+ toolCallId
516
+ };
517
+ } catch (error) {
518
+ logger.error({
519
+ toolName,
520
+ toolCallId,
521
+ error
522
+ }, "MCP tool execution failed");
523
+ throw error;
524
+ }
525
+ }
526
+ });
527
+ wrappedTools[toolName] = this.wrapToolWithStreaming(toolName, sessionWrappedTool, streamRequestId, "mcp", {
528
+ needsApproval,
529
+ mcpServerId: toolResult.mcpServerId,
530
+ mcpServerName: toolResult.mcpServerName
531
+ });
532
+ }
533
+ return wrappedTools;
534
+ }
535
+ /**
536
+ * Convert database McpTool to builder MCPToolConfig format
537
+ */
538
+ convertToMCPToolConfig(tool$1, agentToolRelationHeaders) {
539
+ if (tool$1.config.type !== "mcp") throw new Error(`Cannot convert non-MCP tool to MCP config: ${tool$1.id}`);
540
+ return {
541
+ id: tool$1.id,
542
+ name: tool$1.name,
543
+ description: tool$1.name,
544
+ serverUrl: tool$1.config.mcp.server.url,
545
+ activeTools: tool$1.config.mcp.activeTools,
546
+ mcpType: tool$1.config.mcp.server.url.includes("api.nango.dev") ? MCPServerType.nango : MCPServerType.generic,
547
+ transport: tool$1.config.mcp.transport,
548
+ headers: {
549
+ ...tool$1.headers,
550
+ ...agentToolRelationHeaders
551
+ }
552
+ };
553
+ }
554
+ async getMcpTool(tool$1) {
555
+ const cacheKey = `${this.config.tenantId}-${this.config.projectId}-${tool$1.id}-${tool$1.credentialReferenceId || "no-cred"}`;
556
+ const credentialReferenceId = tool$1.credentialReferenceId;
557
+ const toolRelation = (await getToolsForAgent(dbClient_default)({ scopes: {
558
+ tenantId: this.config.tenantId,
559
+ projectId: this.config.projectId,
560
+ agentId: this.config.agentId,
561
+ subAgentId: this.config.id
562
+ } })).data.find((t) => t.toolId === tool$1.id);
563
+ const agentToolRelationHeaders = toolRelation?.headers || void 0;
564
+ const selectedTools = toolRelation?.selectedTools || void 0;
565
+ const toolPolicies = toolRelation?.toolPolicies || {};
566
+ let serverConfig;
567
+ const isUserScoped = tool$1.credentialScope === "user";
568
+ const userId = this.config.userId;
569
+ if (isUserScoped && userId && this.credentialStuffer) {
570
+ const userCredentialReference = await getUserScopedCredentialReference(dbClient_default)({
571
+ scopes: {
572
+ tenantId: this.config.tenantId,
573
+ projectId: this.config.projectId
574
+ },
575
+ toolId: tool$1.id,
576
+ userId
577
+ });
578
+ if (userCredentialReference) {
579
+ const storeReference = {
580
+ credentialStoreId: userCredentialReference.credentialStoreId,
581
+ retrievalParams: userCredentialReference.retrievalParams || {}
582
+ };
583
+ serverConfig = await this.credentialStuffer.buildMcpServerConfig({
584
+ tenantId: this.config.tenantId,
585
+ projectId: this.config.projectId,
586
+ contextConfigId: this.config.contextConfigId || void 0,
587
+ conversationId: this.conversationId || void 0
588
+ }, this.convertToMCPToolConfig(tool$1, agentToolRelationHeaders), storeReference, selectedTools);
589
+ } else {
590
+ logger.warn({
591
+ toolId: tool$1.id,
592
+ userId
593
+ }, "User-scoped tool has no credential connected for this user");
594
+ serverConfig = await this.credentialStuffer.buildMcpServerConfig({
595
+ tenantId: this.config.tenantId,
596
+ projectId: this.config.projectId,
597
+ contextConfigId: this.config.contextConfigId || void 0,
598
+ conversationId: this.conversationId || void 0
599
+ }, this.convertToMCPToolConfig(tool$1, agentToolRelationHeaders), void 0, selectedTools);
600
+ }
601
+ } else if (credentialReferenceId && this.credentialStuffer) {
602
+ const credentialReference = await getCredentialReference(dbClient_default)({
603
+ scopes: {
604
+ tenantId: this.config.tenantId,
605
+ projectId: this.config.projectId
606
+ },
607
+ id: credentialReferenceId
608
+ });
609
+ if (!credentialReference) throw new Error(`Credential store not found: ${credentialReferenceId}`);
610
+ const storeReference = {
611
+ credentialStoreId: credentialReference.credentialStoreId,
612
+ retrievalParams: credentialReference.retrievalParams || {}
613
+ };
614
+ serverConfig = await this.credentialStuffer.buildMcpServerConfig({
615
+ tenantId: this.config.tenantId,
616
+ projectId: this.config.projectId,
617
+ contextConfigId: this.config.contextConfigId || void 0,
618
+ conversationId: this.conversationId || void 0
619
+ }, this.convertToMCPToolConfig(tool$1, agentToolRelationHeaders), storeReference, selectedTools);
620
+ } else if (this.credentialStuffer) serverConfig = await this.credentialStuffer.buildMcpServerConfig({
621
+ tenantId: this.config.tenantId,
622
+ projectId: this.config.projectId,
623
+ contextConfigId: this.config.contextConfigId || void 0,
624
+ conversationId: this.conversationId || void 0
625
+ }, this.convertToMCPToolConfig(tool$1, agentToolRelationHeaders), void 0, selectedTools);
626
+ else {
627
+ if (tool$1.config.type !== "mcp") throw new Error(`Cannot build server config for non-MCP tool: ${tool$1.id}`);
628
+ serverConfig = {
629
+ type: tool$1.config.mcp.transport?.type || MCPTransportType.streamableHttp,
630
+ url: tool$1.config.mcp.server.url,
631
+ activeTools: tool$1.config.mcp.activeTools,
632
+ selectedTools,
633
+ headers: agentToolRelationHeaders
634
+ };
635
+ }
636
+ if (serverConfig.url?.toString().includes("composio.dev")) {
637
+ const urlObj = new URL(serverConfig.url.toString());
638
+ if (isUserScoped && userId) urlObj.searchParams.set("user_id", userId);
639
+ else urlObj.searchParams.set("user_id", `${this.config.tenantId}||${this.config.projectId}`);
640
+ serverConfig.url = urlObj.toString();
641
+ }
642
+ logger.info({
643
+ toolName: tool$1.name,
644
+ credentialReferenceId,
645
+ transportType: serverConfig.type,
646
+ headers: tool$1.headers
647
+ }, "Built MCP server config with credentials");
648
+ let client = this.mcpClientCache.get(cacheKey);
649
+ if (client && !client.isConnected()) {
650
+ this.mcpClientCache.delete(cacheKey);
651
+ client = void 0;
652
+ }
653
+ if (!client) {
654
+ let connectionPromise = this.mcpConnectionLocks.get(cacheKey);
655
+ if (!connectionPromise) {
656
+ connectionPromise = this.createMcpConnection(tool$1, serverConfig);
657
+ this.mcpConnectionLocks.set(cacheKey, connectionPromise);
658
+ }
659
+ try {
660
+ client = await connectionPromise;
661
+ this.mcpClientCache.set(cacheKey, client);
662
+ } catch (error) {
663
+ this.mcpConnectionLocks.delete(cacheKey);
664
+ logger.error({
665
+ toolName: tool$1.name,
666
+ subAgentId: this.config.id,
667
+ cacheKey,
668
+ error: error instanceof Error ? error.message : String(error)
669
+ }, "MCP connection failed");
670
+ throw error;
671
+ }
672
+ }
673
+ const tools = await client.tools();
674
+ if (!tools || Object.keys(tools).length === 0) {
675
+ const streamRequestId = this.getStreamRequestId();
676
+ if (streamRequestId) tracer.startActiveSpan("ai.toolCall", { attributes: {
677
+ "ai.toolCall.name": tool$1.name,
678
+ "ai.toolCall.args": JSON.stringify({ operation: "mcp_tool_discovery" }),
679
+ "ai.toolCall.result": JSON.stringify({
680
+ status: "no_tools_available",
681
+ message: `MCP server has 0 effective tools. Double check the selected tools in your agent and the active tools in the MCP server configuration.`,
682
+ serverUrl: tool$1.config.type === "mcp" ? tool$1.config.mcp.server.url : "unknown",
683
+ originalToolName: tool$1.name
684
+ }),
685
+ "ai.toolType": "mcp",
686
+ "subAgent.name": this.config.name || "unknown",
687
+ "subAgent.id": this.config.id || "unknown",
688
+ "conversation.id": this.conversationId || "unknown",
689
+ "agent.id": this.config.agentId || "unknown",
690
+ "tenant.id": this.config.tenantId || "unknown",
691
+ "project.id": this.config.projectId || "unknown"
692
+ } }, (span) => {
693
+ setSpanWithError$1(span, /* @__PURE__ */ new Error(`0 effective tools available for ${tool$1.name}`));
694
+ agentSessionManager.recordEvent(streamRequestId, "error", this.config.id, {
695
+ message: `MCP server has 0 effective tools. Double check the selected tools in your graph and the active tools in the MCP server configuration.`,
696
+ code: "no_tools_available",
697
+ severity: "error",
698
+ context: {
699
+ toolName: tool$1.name,
700
+ serverUrl: tool$1.config.type === "mcp" ? tool$1.config.mcp.server.url : "unknown",
701
+ operation: "mcp_tool_discovery"
702
+ }
703
+ });
704
+ span.end();
705
+ });
706
+ }
707
+ return {
708
+ tools,
709
+ toolPolicies,
710
+ mcpServerId: tool$1.id,
711
+ mcpServerName: tool$1.name
712
+ };
713
+ }
714
+ async createMcpConnection(tool$1, serverConfig) {
715
+ const client = new McpClient({
716
+ name: tool$1.name,
717
+ server: serverConfig
718
+ });
719
+ try {
720
+ await client.connect();
721
+ return client;
722
+ } catch (error) {
723
+ logger.error({
724
+ toolName: tool$1.name,
725
+ subAgentId: this.config.id,
726
+ error: error instanceof Error ? error.message : String(error)
727
+ }, "Agent failed to connect to MCP server");
728
+ if (error instanceof Error) {
729
+ if (error?.cause && JSON.stringify(error.cause).includes("ECONNREFUSED")) throw new Error("Connection refused. Please check if the MCP server is running.");
730
+ if (error.message.includes("404")) throw new Error("Error accessing endpoint (HTTP 404)");
731
+ throw new Error(`MCP server connection failed: ${error.message}`);
732
+ }
733
+ throw error;
734
+ }
735
+ }
736
+ async getFunctionTools(sessionId, streamRequestId) {
737
+ const functionTools = {};
738
+ try {
739
+ const functionToolsData = (await getFunctionToolsForSubAgent(dbClient_default)({
740
+ scopes: {
741
+ tenantId: this.config.tenantId,
742
+ projectId: this.config.projectId,
743
+ agentId: this.config.agentId
744
+ },
745
+ subAgentId: this.config.id
746
+ })).data || [];
747
+ if (functionToolsData.length === 0) return functionTools;
748
+ const { SandboxExecutorFactory } = await import("../tools/SandboxExecutorFactory.js");
749
+ const sandboxExecutor = SandboxExecutorFactory.getInstance();
750
+ for (const functionToolDef of functionToolsData) {
751
+ const functionId = functionToolDef.functionId;
752
+ if (!functionId) {
753
+ logger.warn({ functionToolId: functionToolDef.id }, "Function tool missing functionId reference");
754
+ continue;
755
+ }
756
+ const functionData = await getFunction(dbClient_default)({
757
+ functionId,
758
+ scopes: {
759
+ tenantId: this.config.tenantId || "default",
760
+ projectId: this.config.projectId || "default"
761
+ }
762
+ });
763
+ if (!functionData) {
764
+ logger.warn({
765
+ functionId,
766
+ functionToolId: functionToolDef.id
767
+ }, "Function not found in functions table");
768
+ continue;
769
+ }
770
+ const zodSchema = jsonSchemaToZod(functionData.inputSchema);
771
+ const aiTool = tool({
772
+ description: functionToolDef.description || functionToolDef.name,
773
+ inputSchema: zodSchema,
774
+ execute: async (args, { toolCallId }) => {
775
+ let processedArgs;
776
+ try {
777
+ processedArgs = parseEmbeddedJson(args);
778
+ if (JSON.stringify(args) !== JSON.stringify(processedArgs)) logger.warn({
779
+ toolName: functionToolDef.name,
780
+ toolCallId
781
+ }, "Fixed stringified JSON parameters (indicates schema ambiguity)");
782
+ } catch (error) {
783
+ logger.warn({
784
+ toolName: functionToolDef.name,
785
+ toolCallId,
786
+ error: error.message
787
+ }, "Failed to parse embedded JSON, using original args");
788
+ processedArgs = args;
789
+ }
790
+ const finalArgs = processedArgs;
791
+ logger.debug({
792
+ toolName: functionToolDef.name,
793
+ toolCallId,
794
+ args: finalArgs
795
+ }, "Function Tool Called");
796
+ try {
797
+ const defaultSandboxConfig = {
798
+ provider: "native",
799
+ runtime: "node22",
800
+ timeout: FUNCTION_TOOL_EXECUTION_TIMEOUT_MS_DEFAULT,
801
+ vcpus: FUNCTION_TOOL_SANDBOX_VCPUS_DEFAULT
802
+ };
803
+ const result = await sandboxExecutor.executeFunctionTool(functionToolDef.id, finalArgs, {
804
+ description: functionToolDef.description || functionToolDef.name,
805
+ inputSchema: functionData.inputSchema || {},
806
+ executeCode: functionData.executeCode,
807
+ dependencies: functionData.dependencies || {},
808
+ sandboxConfig: this.config.sandboxConfig || defaultSandboxConfig
809
+ });
810
+ toolSessionManager.recordToolResult(sessionId || "", {
811
+ toolCallId,
812
+ toolName: functionToolDef.name,
813
+ args: finalArgs,
814
+ result,
815
+ timestamp: Date.now()
816
+ });
817
+ return {
818
+ result,
819
+ toolCallId
820
+ };
821
+ } catch (error) {
822
+ logger.error({
823
+ toolName: functionToolDef.name,
824
+ toolCallId,
825
+ error: error instanceof Error ? error.message : String(error)
826
+ }, "Function tool execution failed");
827
+ throw error;
828
+ }
829
+ }
830
+ });
831
+ functionTools[functionToolDef.name] = this.wrapToolWithStreaming(functionToolDef.name, aiTool, streamRequestId || "", "tool");
832
+ }
833
+ } catch (error) {
834
+ logger.error({ error }, "Failed to load function tools from database");
835
+ }
836
+ return functionTools;
837
+ }
838
+ /**
839
+ * Get resolved context using ContextResolver - will return cached data or fetch fresh data as needed
840
+ */
841
+ async getResolvedContext(conversationId, headers$1) {
842
+ try {
843
+ if (!this.config.contextConfigId) {
844
+ logger.debug({ agentId: this.config.agentId }, "No context config found for agent");
845
+ return null;
846
+ }
847
+ const contextConfig = await getContextConfigById(dbClient_default)({
848
+ scopes: {
849
+ tenantId: this.config.tenantId,
850
+ projectId: this.config.projectId,
851
+ agentId: this.config.agentId
852
+ },
853
+ id: this.config.contextConfigId
854
+ });
855
+ if (!contextConfig) {
856
+ logger.warn({ contextConfigId: this.config.contextConfigId }, "Context config not found");
857
+ return null;
858
+ }
859
+ if (!this.contextResolver) throw new Error("Context resolver not found");
860
+ const result = await this.contextResolver.resolve(contextConfig, {
861
+ triggerEvent: "invocation",
862
+ conversationId,
863
+ headers: headers$1 || {},
864
+ tenantId: this.config.tenantId
865
+ });
866
+ const contextWithBuiltins = {
867
+ ...result.resolvedContext,
868
+ $env: process.env
869
+ };
870
+ logger.debug({
871
+ conversationId,
872
+ contextConfigId: contextConfig.id,
873
+ resolvedKeys: Object.keys(contextWithBuiltins),
874
+ cacheHits: result.cacheHits.length,
875
+ cacheMisses: result.cacheMisses.length,
876
+ fetchedDefinitions: result.fetchedDefinitions.length,
877
+ errors: result.errors.length
878
+ }, "Context resolved for agent");
879
+ return contextWithBuiltins;
880
+ } catch (error) {
881
+ logger.error({
882
+ conversationId,
883
+ error: error instanceof Error ? error.message : "Unknown error"
884
+ }, "Failed to get resolved context");
885
+ return null;
886
+ }
887
+ }
888
+ /**
889
+ * Get the agent prompt for this agent's agent
890
+ */
891
+ async getPrompt() {
892
+ try {
893
+ return (await getFullAgentDefinition(dbClient_default)({ scopes: {
894
+ tenantId: this.config.tenantId,
895
+ projectId: this.config.projectId,
896
+ agentId: this.config.agentId
897
+ } }))?.prompt || void 0;
898
+ } catch (error) {
899
+ logger.warn({
900
+ agentId: this.config.agentId,
901
+ error: error instanceof Error ? error.message : "Unknown error"
902
+ }, "Failed to get agent prompt");
903
+ return;
904
+ }
905
+ }
906
+ /**
907
+ * Check if any agent in the agent has artifact components configured
908
+ */
909
+ async hasAgentArtifactComponents() {
910
+ try {
911
+ const agentDefinition = await getFullAgentDefinition(dbClient_default)({ scopes: {
912
+ tenantId: this.config.tenantId,
913
+ projectId: this.config.projectId,
914
+ agentId: this.config.agentId
915
+ } });
916
+ if (!agentDefinition) return false;
917
+ return Object.values(agentDefinition.subAgents).some((subAgent) => "artifactComponents" in subAgent && subAgent.artifactComponents && subAgent.artifactComponents.length > 0);
918
+ } catch (error) {
919
+ logger.warn({
920
+ agentId: this.config.agentId,
921
+ tenantId: this.config.tenantId,
922
+ projectId: this.config.projectId,
923
+ error: error instanceof Error ? error.message : "Unknown error"
924
+ }, "Failed to check agent artifact components, assuming none exist");
925
+ return this.artifactComponents.length > 0;
926
+ }
927
+ }
928
+ /**
929
+ * Build adaptive system prompt for Phase 2 structured output generation
930
+ * based on configured data components and artifact components across the agent
931
+ */
932
+ async buildPhase2SystemPrompt(runtimeContext) {
933
+ const phase2Config = new Phase2Config();
934
+ const compressionConfig = getCompressionConfigFromEnv();
935
+ const hasAgentArtifactComponents = await this.hasAgentArtifactComponents() || compressionConfig.enabled;
936
+ const conversationId = runtimeContext?.metadata?.conversationId || runtimeContext?.contextId;
937
+ const resolvedContext = conversationId ? await this.getResolvedContext(conversationId) : null;
938
+ let processedPrompt = this.config.prompt || "";
939
+ if (resolvedContext && this.config.prompt) try {
940
+ processedPrompt = TemplateEngine.render(this.config.prompt, resolvedContext, {
941
+ strict: false,
942
+ preserveUnresolved: false
943
+ });
944
+ } catch (error) {
945
+ logger.error({
946
+ conversationId,
947
+ error: error instanceof Error ? error.message : "Unknown error"
948
+ }, "Failed to process agent prompt with context for Phase 2, using original");
949
+ processedPrompt = this.config.prompt;
950
+ }
951
+ const referenceTaskIds = await listTaskIdsByContextId(dbClient_default)({ contextId: this.conversationId || "" });
952
+ const referenceArtifacts = [];
953
+ for (const taskId of referenceTaskIds) {
954
+ const artifacts = await getLedgerArtifacts(dbClient_default)({
955
+ scopes: {
956
+ tenantId: this.config.tenantId,
957
+ projectId: this.config.projectId
958
+ },
959
+ taskId
960
+ });
961
+ referenceArtifacts.push(...artifacts);
962
+ }
963
+ return phase2Config.assemblePhase2Prompt({
964
+ corePrompt: processedPrompt,
965
+ dataComponents: this.config.dataComponents || [],
966
+ artifactComponents: this.artifactComponents,
967
+ hasArtifactComponents: this.artifactComponents && this.artifactComponents.length > 0,
968
+ hasAgentArtifactComponents,
969
+ artifacts: referenceArtifacts
970
+ });
971
+ }
972
+ async buildSystemPrompt(runtimeContext, excludeDataComponents = false) {
973
+ const conversationId = runtimeContext?.metadata?.conversationId || runtimeContext?.contextId;
974
+ if (conversationId) this.setConversationId(conversationId);
975
+ const resolvedContext = conversationId ? await this.getResolvedContext(conversationId) : null;
976
+ let processedPrompt = this.config.prompt || "";
977
+ if (resolvedContext && this.config.prompt) try {
978
+ processedPrompt = TemplateEngine.render(this.config.prompt, resolvedContext, {
979
+ strict: false,
980
+ preserveUnresolved: false
981
+ });
982
+ } catch (error) {
983
+ logger.error({
984
+ conversationId,
985
+ error: error instanceof Error ? error.message : "Unknown error"
986
+ }, "Failed to process agent prompt with context, using original");
987
+ processedPrompt = this.config.prompt;
988
+ }
989
+ const streamRequestId = runtimeContext?.metadata?.streamRequestId;
990
+ const mcpTools = await this.getMcpTools(void 0, streamRequestId);
991
+ const functionTools = await this.getFunctionTools(streamRequestId || "");
992
+ const relationTools = this.getRelationTools(runtimeContext);
993
+ const allTools = {
994
+ ...mcpTools,
995
+ ...functionTools,
996
+ ...relationTools
997
+ };
998
+ logger.info({
999
+ mcpTools: Object.keys(mcpTools),
1000
+ functionTools: Object.keys(functionTools),
1001
+ relationTools: Object.keys(relationTools),
1002
+ allTools: Object.keys(allTools),
1003
+ functionToolsDetails: Object.entries(functionTools).map(([name, tool$1]) => ({
1004
+ name,
1005
+ hasExecute: typeof tool$1.execute === "function",
1006
+ hasDescription: !!tool$1.description,
1007
+ hasInputSchema: !!tool$1.inputSchema
1008
+ }))
1009
+ }, "Tools loaded for agent");
1010
+ const toolDefinitions = Object.entries(allTools).map(([name, tool$1]) => ({
1011
+ name,
1012
+ description: tool$1.description || "",
1013
+ inputSchema: tool$1.inputSchema || tool$1.parameters || {},
1014
+ usageGuidelines: name.startsWith("transfer_to_") || name.startsWith("delegate_to_") ? `Use this tool to ${name.startsWith("transfer_to_") ? "transfer" : "delegate"} to another agent when appropriate.` : "Use this tool when appropriate for the task at hand."
1015
+ }));
1016
+ const { getConversationScopedArtifacts } = await import("../data/conversations.js");
1017
+ const historyConfig = this.config.conversationHistoryConfig ?? createDefaultConversationHistoryConfig();
1018
+ const referenceArtifacts = await getConversationScopedArtifacts({
1019
+ tenantId: this.config.tenantId,
1020
+ projectId: this.config.projectId,
1021
+ conversationId: runtimeContext?.contextId || "",
1022
+ historyConfig
1023
+ });
1024
+ const componentDataComponents = excludeDataComponents ? [] : this.config.dataComponents || [];
1025
+ const isThinkingPreparation = this.config.dataComponents && this.config.dataComponents.length > 0 && excludeDataComponents;
1026
+ let prompt = await this.getPrompt();
1027
+ if (prompt && resolvedContext) try {
1028
+ prompt = TemplateEngine.render(prompt, resolvedContext, {
1029
+ strict: false,
1030
+ preserveUnresolved: false
1031
+ });
1032
+ } catch (error) {
1033
+ logger.error({
1034
+ conversationId,
1035
+ error: error instanceof Error ? error.message : "Unknown error"
1036
+ }, "Failed to process agent prompt with context, using original");
1037
+ }
1038
+ const shouldIncludeArtifactComponents = !excludeDataComponents;
1039
+ const compressionConfig = getCompressionConfigFromEnv();
1040
+ const hasAgentArtifactComponents = await this.hasAgentArtifactComponents() || compressionConfig.enabled;
1041
+ const config = {
1042
+ corePrompt: processedPrompt,
1043
+ prompt,
1044
+ tools: toolDefinitions,
1045
+ dataComponents: componentDataComponents,
1046
+ artifacts: referenceArtifacts,
1047
+ artifactComponents: shouldIncludeArtifactComponents ? this.artifactComponents : [],
1048
+ hasAgentArtifactComponents,
1049
+ isThinkingPreparation,
1050
+ hasTransferRelations: (this.config.transferRelations?.length ?? 0) > 0,
1051
+ hasDelegateRelations: (this.config.delegateRelations?.length ?? 0) > 0
1052
+ };
1053
+ return await this.systemPromptBuilder.buildSystemPrompt(config);
1054
+ }
1055
+ getArtifactTools() {
1056
+ return tool({
1057
+ description: "Call this tool to get the complete artifact data with the given artifactId. This retrieves the full artifact content (not just the summary). Only use this when you need the complete artifact data and the summary shown in your context is insufficient.",
1058
+ inputSchema: z.object({
1059
+ artifactId: z.string().describe("The unique identifier of the artifact to get."),
1060
+ toolCallId: z.string().describe("The tool call ID associated with this artifact.")
1061
+ }),
1062
+ execute: async ({ artifactId, toolCallId }) => {
1063
+ logger.info({
1064
+ artifactId,
1065
+ toolCallId
1066
+ }, "get_artifact_full executed");
1067
+ const streamRequestId = this.getStreamRequestId();
1068
+ const artifactService = agentSessionManager.getArtifactService(streamRequestId);
1069
+ if (!artifactService) throw new Error(`ArtifactService not found for session ${streamRequestId}`);
1070
+ const artifactData = await artifactService.getArtifactFull(artifactId, toolCallId);
1071
+ if (!artifactData) throw new Error(`Artifact ${artifactId} with toolCallId ${toolCallId} not found`);
1072
+ return {
1073
+ artifactId: artifactData.artifactId,
1074
+ name: artifactData.name,
1075
+ description: artifactData.description,
1076
+ type: artifactData.type,
1077
+ data: artifactData.data
1078
+ };
1079
+ }
1080
+ });
1081
+ }
1082
+ createThinkingCompleteTool() {
1083
+ return tool({
1084
+ description: "🚨 CRITICAL: Call this tool IMMEDIATELY when you have gathered enough information to answer the user. This is MANDATORY - you CANNOT provide text responses in thinking mode, only tool calls. Call thinking_complete as soon as you have sufficient data to generate a structured response.",
1085
+ inputSchema: z.object({
1086
+ complete: z.boolean().describe("ALWAYS set to true - marks end of research phase"),
1087
+ summary: z.string().describe("Brief summary of what information was gathered and why it is sufficient to answer the user")
1088
+ }),
1089
+ execute: async (params) => params
1090
+ });
1091
+ }
1092
+ async getDefaultTools(streamRequestId) {
1093
+ const defaultTools = {};
1094
+ const compressionConfig = getCompressionConfigFromEnv();
1095
+ if (await this.agentHasArtifactComponents() || compressionConfig.enabled) defaultTools.get_reference_artifact = this.getArtifactTools();
1096
+ if (this.config.dataComponents && this.config.dataComponents.length > 0) {
1097
+ const thinkingCompleteTool = this.createThinkingCompleteTool();
1098
+ if (thinkingCompleteTool) defaultTools.thinking_complete = this.wrapToolWithStreaming("thinking_complete", thinkingCompleteTool, streamRequestId, "tool");
1099
+ }
1100
+ logger.info({
1101
+ agentId: this.config.id,
1102
+ streamRequestId
1103
+ }, "Adding compress_context tool to defaultTools");
1104
+ defaultTools.compress_context = tool({
1105
+ description: "Manually compress the current conversation context to save space. Use when shifting topics, completing major tasks, or when context feels cluttered.",
1106
+ inputSchema: z.object({ reason: z.string().describe("Why you are requesting compression (e.g., \"shifting from research to coding\", \"completed analysis phase\")") }),
1107
+ execute: async ({ reason }) => {
1108
+ logger.info({
1109
+ agentId: this.config.id,
1110
+ streamRequestId,
1111
+ reason
1112
+ }, "Manual compression requested by LLM");
1113
+ if (this.currentCompressor) this.currentCompressor.requestManualCompression(reason);
1114
+ return {
1115
+ status: "compression_requested",
1116
+ reason,
1117
+ message: "Context compression will be applied on the next generation step. Previous work has been summarized and saved as artifacts."
1118
+ };
1119
+ }
1120
+ });
1121
+ logger.info("getDefaultTools returning tools:", Object.keys(defaultTools).join(", "));
1122
+ return defaultTools;
1123
+ }
1124
+ getStreamRequestId() {
1125
+ return this.streamRequestId || "";
1126
+ }
1127
+ /**
1128
+ * Format tool result for storage in conversation history
1129
+ */
1130
+ formatToolResult(toolName, args, result, toolCallId) {
1131
+ const input = args ? JSON.stringify(args, null, 2) : "No input";
1132
+ let parsedResult = result;
1133
+ if (typeof result === "string") try {
1134
+ parsedResult = JSON.parse(result);
1135
+ } catch (e) {}
1136
+ const cleanResult = parsedResult && typeof parsedResult === "object" && !Array.isArray(parsedResult) ? {
1137
+ ...parsedResult,
1138
+ result: parsedResult.result && typeof parsedResult.result === "object" && !Array.isArray(parsedResult.result) ? Object.fromEntries(Object.entries(parsedResult.result).filter(([key]) => key !== "_structureHints")) : parsedResult.result
1139
+ } : parsedResult;
1140
+ return `## Tool: ${toolName}
1141
+
1142
+ ### 🔧 TOOL_CALL_ID: ${toolCallId}
1143
+
1144
+ ### Input
1145
+ ${input}
1146
+
1147
+ ### Output
1148
+ ${typeof cleanResult === "string" ? cleanResult : JSON.stringify(cleanResult, null, 2)}`;
1149
+ }
1150
+ /**
1151
+ * Get the conversation ID for storing tool results
1152
+ * Always uses the real conversation ID - delegation filtering happens at query time
1153
+ */
1154
+ getToolResultConversationId() {
1155
+ return this.conversationId;
1156
+ }
1157
+ /**
1158
+ * Analyze tool result structure and add helpful path hints for artifact creation
1159
+ * Only adds hints when artifact components are available
1160
+ */
1161
+ enhanceToolResultWithStructureHints(result) {
1162
+ if (!result) return result;
1163
+ if (!this.artifactComponents || this.artifactComponents.length === 0) return result;
1164
+ let parsedForAnalysis = result;
1165
+ if (typeof result === "string") try {
1166
+ parsedForAnalysis = parseEmbeddedJson(result);
1167
+ } catch (_error) {
1168
+ parsedForAnalysis = result;
1169
+ }
1170
+ if (!parsedForAnalysis || typeof parsedForAnalysis !== "object") return result;
1171
+ const findAllPaths = (obj, prefix = "result", depth = 0) => {
1172
+ if (depth > 8) return [];
1173
+ const paths = [];
1174
+ if (Array.isArray(obj)) {
1175
+ if (obj.length > 0) {
1176
+ paths.push(`${prefix}[array-${obj.length}-items]`);
1177
+ if (obj[0] && typeof obj[0] === "object") {
1178
+ const sampleItem = obj[0];
1179
+ Object.keys(sampleItem).forEach((key) => {
1180
+ const value = sampleItem[key];
1181
+ if (typeof value === "string" && value.length < 50) paths.push(`${prefix}[?${key}=='${value}']`);
1182
+ else if (typeof value === "boolean") paths.push(`${prefix}[?${key}==${value}]`);
1183
+ else if (key === "id" || key === "name" || key === "type") paths.push(`${prefix}[?${key}=='value']`);
1184
+ });
1185
+ }
1186
+ paths.push(...findAllPaths(obj[0], `${prefix}[?field=='value']`, depth + 1));
1187
+ }
1188
+ } else if (obj && typeof obj === "object") Object.entries(obj).forEach(([key, value]) => {
1189
+ const currentPath = `${prefix}.${key}`;
1190
+ if (value && typeof value === "object") {
1191
+ if (Array.isArray(value)) paths.push(`${currentPath}[array]`);
1192
+ else paths.push(`${currentPath}[object]`);
1193
+ paths.push(...findAllPaths(value, currentPath, depth + 1));
1194
+ } else paths.push(`${currentPath}[${typeof value}]`);
1195
+ });
1196
+ return paths;
1197
+ };
1198
+ const findCommonFields = (obj, depth = 0) => {
1199
+ if (depth > 5) return /* @__PURE__ */ new Set();
1200
+ const fields = /* @__PURE__ */ new Set();
1201
+ if (Array.isArray(obj)) obj.slice(0, 3).forEach((item) => {
1202
+ if (item && typeof item === "object") Object.keys(item).forEach((key) => {
1203
+ fields.add(key);
1204
+ });
1205
+ });
1206
+ else if (obj && typeof obj === "object") {
1207
+ Object.keys(obj).forEach((key) => {
1208
+ fields.add(key);
1209
+ });
1210
+ Object.values(obj).forEach((value) => {
1211
+ findCommonFields(value, depth + 1).forEach((field) => {
1212
+ fields.add(field);
1213
+ });
1214
+ });
1215
+ }
1216
+ return fields;
1217
+ };
1218
+ const findUsefulSelectors = (obj, prefix = "result", depth = 0) => {
1219
+ if (depth > 5) return [];
1220
+ const selectors = [];
1221
+ if (Array.isArray(obj) && obj.length > 0) {
1222
+ const firstItem = obj[0];
1223
+ if (firstItem && typeof firstItem === "object") {
1224
+ if (firstItem.title) selectors.push(`${prefix}[?title=='${String(firstItem.title).replace(/'/g, "\\'")}'] | [0]`);
1225
+ if (firstItem.type) selectors.push(`${prefix}[?type=='${firstItem.type}'] | [0]`);
1226
+ if (firstItem.record_type) selectors.push(`${prefix}[?record_type=='${firstItem.record_type}'] | [0]`);
1227
+ if (firstItem.url) selectors.push(`${prefix}[?url!=null] | [0]`);
1228
+ if (firstItem.type && firstItem.title) selectors.push(`${prefix}[?type=='${firstItem.type}' && title=='${String(firstItem.title).replace(/'/g, "\\'")}'] | [0]`);
1229
+ selectors.push(`${prefix}[0]`);
1230
+ }
1231
+ } else if (obj && typeof obj === "object") Object.entries(obj).forEach(([key, value]) => {
1232
+ if (typeof value === "object" && value !== null) selectors.push(...findUsefulSelectors(value, `${prefix}.${key}`, depth + 1));
1233
+ });
1234
+ return selectors;
1235
+ };
1236
+ const findNestedContentPaths = (obj, prefix = "result", depth = 0) => {
1237
+ if (depth > 6) return [];
1238
+ const paths = [];
1239
+ if (obj && typeof obj === "object") Object.entries(obj).forEach(([key, value]) => {
1240
+ const currentPath = `${prefix}.${key}`;
1241
+ if (Array.isArray(value) && value.length > 0) {
1242
+ const firstItem = value[0];
1243
+ if (firstItem && typeof firstItem === "object") {
1244
+ if (firstItem.type === "document" || firstItem.type === "text") {
1245
+ paths.push(`${currentPath}[?type=='document'] | [0]`);
1246
+ paths.push(`${currentPath}[?type=='text'] | [0]`);
1247
+ if (firstItem.title) {
1248
+ const titleSample = String(firstItem.title).slice(0, 20);
1249
+ paths.push(`${currentPath}[?title && contains(title, '${titleSample.split(" ")[0]}')] | [0]`);
1250
+ }
1251
+ if (firstItem.record_type) paths.push(`${currentPath}[?record_type=='${firstItem.record_type}'] | [0]`);
1252
+ }
1253
+ }
1254
+ paths.push(...findNestedContentPaths(value, currentPath, depth + 1));
1255
+ } else if (value && typeof value === "object") paths.push(...findNestedContentPaths(value, currentPath, depth + 1));
1256
+ });
1257
+ return paths;
1258
+ };
1259
+ try {
1260
+ const allPaths = findAllPaths(parsedForAnalysis);
1261
+ const commonFields = Array.from(findCommonFields(parsedForAnalysis)).slice(0, 15);
1262
+ const usefulSelectors = findUsefulSelectors(parsedForAnalysis).slice(0, 10);
1263
+ const nestedContentPaths = findNestedContentPaths(parsedForAnalysis).slice(0, 8);
1264
+ const terminalPaths = allPaths.filter((p) => p.includes("[string]") || p.includes("[number]") || p.includes("[boolean]")).slice(0, 20);
1265
+ const arrayPaths = allPaths.filter((p) => p.includes("[array")).slice(0, 15);
1266
+ const objectPaths = allPaths.filter((p) => p.includes("[object]")).slice(0, 15);
1267
+ const allSelectors = [...usefulSelectors, ...nestedContentPaths];
1268
+ const uniqueSelectors = [...new Set(allSelectors)].slice(0, 15);
1269
+ return {
1270
+ ...result,
1271
+ _structureHints: {
1272
+ terminalPaths,
1273
+ arrayPaths,
1274
+ objectPaths,
1275
+ commonFields,
1276
+ exampleSelectors: uniqueSelectors,
1277
+ deepStructureExamples: nestedContentPaths,
1278
+ maxDepthFound: Math.max(...allPaths.map((p) => (p.match(/\./g) || []).length)),
1279
+ totalPathsFound: allPaths.length,
1280
+ artifactGuidance: {
1281
+ creationFirst: "🚨 CRITICAL: Artifacts must be CREATED before they can be referenced. Use ArtifactCreate_[Type] components FIRST, then reference with Artifact components only if citing the SAME artifact again.",
1282
+ baseSelector: "🎯 CRITICAL: Use base_selector to navigate to ONE specific item. For deeply nested structures with repeated keys, use full paths with specific filtering (e.g., \"result.data.content.items[?type=='guide' && status=='active']\")",
1283
+ detailsSelector: "📝 Use relative selectors for specific fields (e.g., \"title\", \"metadata.category\", \"properties.status\", \"content.details\")",
1284
+ avoidLiterals: "❌ NEVER use literal values - always use field selectors to extract from data",
1285
+ avoidArrays: "✨ ALWAYS filter arrays to single items using [?condition] - NEVER use [*] notation which returns arrays",
1286
+ nestedKeys: "🔑 For structures with repeated keys (like result.content.data.content.items.content), use full paths with filtering at each level",
1287
+ filterTips: "💡 Use compound filters for precision: [?type=='document' && category=='api']",
1288
+ forbiddenSyntax: "🚫 FORBIDDEN JMESPATH PATTERNS:\n❌ NEVER: [?title~'.*text.*'] (regex patterns with ~ operator)\n❌ NEVER: [?field~'pattern.*'] (any ~ operator usage)\n❌ NEVER: [?title~'Slack.*Discord.*'] (regex wildcards)\n❌ NEVER: [?name~'https://.*'] (regex in URL matching)\n❌ NEVER: [?text ~ contains(@, 'word')] (~ with @ operator)\n❌ NEVER: contains(@, 'text') (@ operator usage)\n❌ NEVER: [?field==\"value\"] (double quotes in filters)\n❌ NEVER: result.items[?type=='doc'][?status=='active'] (chained filters)\n✅ USE INSTEAD:\n✅ [?contains(title, 'text')] (contains function)\n✅ [?title=='exact match'] (exact string matching)\n✅ [?contains(title, 'Slack') && contains(title, 'Discord')] (compound conditions)\n✅ [?starts_with(url, 'https://')] (starts_with function)\n✅ [?type=='doc' && status=='active'] (single filter with &&)",
1289
+ pathDepth: `📏 This structure goes ${Math.max(...allPaths.map((p) => (p.match(/\./g) || []).length))} levels deep - use full paths to avoid ambiguity`
1290
+ },
1291
+ note: `Comprehensive structure analysis: ${allPaths.length} paths found, ${Math.max(...allPaths.map((p) => (p.match(/\./g) || []).length))} levels deep. Use specific filtering for precise selection.`
1292
+ }
1293
+ };
1294
+ } catch (error) {
1295
+ logger.warn({ error }, "Failed to enhance tool result with structure hints");
1296
+ return result;
1297
+ }
1298
+ }
1299
+ async agentHasArtifactComponents() {
1300
+ try {
1301
+ return await agentHasArtifactComponents(dbClient_default)({ scopes: {
1302
+ tenantId: this.config.tenantId,
1303
+ projectId: this.config.projectId,
1304
+ agentId: this.config.agentId
1305
+ } });
1306
+ } catch (error) {
1307
+ logger.error({
1308
+ error,
1309
+ agentId: this.config.agentId
1310
+ }, "Failed to check agent artifact components");
1311
+ return false;
1312
+ }
1313
+ }
1314
+ async generate(userMessage, runtimeContext) {
1315
+ return tracer.startActiveSpan("agent.generate", { attributes: {
1316
+ "subAgent.id": this.config.id,
1317
+ "subAgent.name": this.config.name
1318
+ } }, async (span) => {
1319
+ const contextId = runtimeContext?.contextId || "default";
1320
+ const taskId = runtimeContext?.metadata?.taskId || "unknown";
1321
+ const streamRequestId = runtimeContext?.metadata?.streamRequestId;
1322
+ const sessionId = streamRequestId || "fallback-session";
1323
+ try {
1324
+ this.streamRequestId = streamRequestId;
1325
+ this.streamHelper = streamRequestId ? getStreamHelper(streamRequestId) : void 0;
1326
+ if (streamRequestId && this.artifactComponents.length > 0) agentSessionManager.updateArtifactComponents(streamRequestId, this.artifactComponents);
1327
+ const conversationId = runtimeContext?.metadata?.conversationId;
1328
+ if (conversationId) this.setConversationId(conversationId);
1329
+ const [mcpTools, systemPromptResult, thinkingSystemPromptResult, functionTools, relationTools, defaultTools] = await tracer.startActiveSpan("agent.load_tools", { attributes: {
1330
+ "subAgent.name": this.config.name,
1331
+ "session.id": sessionId || "none"
1332
+ } }, async (childSpan) => {
1333
+ try {
1334
+ const result = await Promise.all([
1335
+ this.getMcpTools(sessionId, streamRequestId),
1336
+ this.buildSystemPrompt(runtimeContext, false),
1337
+ this.buildSystemPrompt(runtimeContext, true),
1338
+ this.getFunctionTools(sessionId, streamRequestId),
1339
+ Promise.resolve(this.getRelationTools(runtimeContext, sessionId)),
1340
+ this.getDefaultTools(streamRequestId)
1341
+ ]);
1342
+ childSpan.setStatus({ code: SpanStatusCode.OK });
1343
+ return result;
1344
+ } catch (err) {
1345
+ setSpanWithError$1(childSpan, err instanceof Error ? err : new Error(String(err)));
1346
+ throw err;
1347
+ } finally {
1348
+ childSpan.end();
1349
+ }
1350
+ });
1351
+ const systemPrompt = systemPromptResult.prompt;
1352
+ const thinkingSystemPrompt = thinkingSystemPromptResult.prompt;
1353
+ const contextBreakdown = systemPromptResult.breakdown;
1354
+ const allTools = {
1355
+ ...mcpTools,
1356
+ ...functionTools,
1357
+ ...relationTools,
1358
+ ...defaultTools
1359
+ };
1360
+ const sanitizedTools = this.sanitizeToolsForAISDK(allTools);
1361
+ let conversationHistory = "";
1362
+ const historyConfig = this.config.conversationHistoryConfig ?? createDefaultConversationHistoryConfig();
1363
+ if (historyConfig && historyConfig.mode !== "none") {
1364
+ if (historyConfig.mode === "full") {
1365
+ const filters = {
1366
+ delegationId: this.delegationId,
1367
+ isDelegated: this.isDelegatedAgent
1368
+ };
1369
+ conversationHistory = await getFormattedConversationHistory({
1370
+ tenantId: this.config.tenantId,
1371
+ projectId: this.config.projectId,
1372
+ conversationId: contextId,
1373
+ currentMessage: userMessage,
1374
+ options: historyConfig,
1375
+ filters
1376
+ });
1377
+ } else if (historyConfig.mode === "scoped") conversationHistory = await getFormattedConversationHistory({
1378
+ tenantId: this.config.tenantId,
1379
+ projectId: this.config.projectId,
1380
+ conversationId: contextId,
1381
+ currentMessage: userMessage,
1382
+ options: historyConfig,
1383
+ filters: {
1384
+ subAgentId: this.config.id,
1385
+ taskId,
1386
+ delegationId: this.delegationId,
1387
+ isDelegated: this.isDelegatedAgent
1388
+ }
1389
+ });
1390
+ }
1391
+ contextBreakdown.conversationHistory = estimateTokens(conversationHistory);
1392
+ calculateBreakdownTotal(contextBreakdown);
1393
+ span.setAttributes({
1394
+ "context.breakdown.system_template_tokens": contextBreakdown.systemPromptTemplate,
1395
+ "context.breakdown.core_instructions_tokens": contextBreakdown.coreInstructions,
1396
+ "context.breakdown.agent_prompt_tokens": contextBreakdown.agentPrompt,
1397
+ "context.breakdown.tools_tokens": contextBreakdown.toolsSection,
1398
+ "context.breakdown.artifacts_tokens": contextBreakdown.artifactsSection,
1399
+ "context.breakdown.data_components_tokens": contextBreakdown.dataComponents,
1400
+ "context.breakdown.artifact_components_tokens": contextBreakdown.artifactComponents,
1401
+ "context.breakdown.transfer_instructions_tokens": contextBreakdown.transferInstructions,
1402
+ "context.breakdown.delegation_instructions_tokens": contextBreakdown.delegationInstructions,
1403
+ "context.breakdown.thinking_preparation_tokens": contextBreakdown.thinkingPreparation,
1404
+ "context.breakdown.conversation_history_tokens": contextBreakdown.conversationHistory,
1405
+ "context.breakdown.total_tokens": contextBreakdown.total
1406
+ });
1407
+ const primaryModelSettings = this.getPrimaryModel();
1408
+ const modelSettings = ModelFactory.prepareGenerationConfig(primaryModelSettings);
1409
+ let response;
1410
+ let textResponse;
1411
+ const hasStructuredOutput = this.config.dataComponents && this.config.dataComponents.length > 0;
1412
+ const shouldStreamPhase1 = this.getStreamingHelper() && !hasStructuredOutput;
1413
+ const configuredTimeout = modelSettings.maxDuration ? Math.min(modelSettings.maxDuration * 1e3, LLM_GENERATION_MAX_ALLOWED_TIMEOUT_MS) : shouldStreamPhase1 ? LLM_GENERATION_FIRST_CALL_TIMEOUT_MS_STREAMING : LLM_GENERATION_FIRST_CALL_TIMEOUT_MS_NON_STREAMING;
1414
+ const timeoutMs = Math.min(configuredTimeout, LLM_GENERATION_MAX_ALLOWED_TIMEOUT_MS);
1415
+ if (modelSettings.maxDuration && modelSettings.maxDuration * 1e3 > LLM_GENERATION_MAX_ALLOWED_TIMEOUT_MS) logger.warn({
1416
+ requestedTimeout: modelSettings.maxDuration * 1e3,
1417
+ appliedTimeout: timeoutMs,
1418
+ maxAllowed: LLM_GENERATION_MAX_ALLOWED_TIMEOUT_MS
1419
+ }, "Requested timeout exceeded maximum allowed, capping to 10 minutes");
1420
+ const phase1SystemPrompt = hasStructuredOutput ? thinkingSystemPrompt : systemPrompt;
1421
+ const messages = [];
1422
+ messages.push({
1423
+ role: "system",
1424
+ content: phase1SystemPrompt
1425
+ });
1426
+ if (conversationHistory.trim() !== "") messages.push({
1427
+ role: "user",
1428
+ content: conversationHistory
1429
+ });
1430
+ messages.push({
1431
+ role: "user",
1432
+ content: userMessage
1433
+ });
1434
+ const originalMessageCount = messages.length;
1435
+ const compressionConfigResult = getCompressionConfigForModel(primaryModelSettings);
1436
+ const compressionConfig = {
1437
+ hardLimit: compressionConfigResult.hardLimit,
1438
+ safetyBuffer: compressionConfigResult.safetyBuffer,
1439
+ enabled: compressionConfigResult.enabled
1440
+ };
1441
+ const compressor = compressionConfig.enabled ? new MidGenerationCompressor(sessionId, contextId, this.config.tenantId, this.config.projectId, compressionConfig, this.getSummarizerModel(), primaryModelSettings) : null;
1442
+ this.currentCompressor = compressor;
1443
+ if (shouldStreamPhase1) {
1444
+ const streamResult = streamText({
1445
+ ...modelSettings,
1446
+ toolChoice: "auto",
1447
+ messages,
1448
+ tools: sanitizedTools,
1449
+ prepareStep: async ({ messages: stepMessages }) => {
1450
+ if (!compressor) return {};
1451
+ if (compressor.isCompressionNeeded(stepMessages)) {
1452
+ logger.info({ compressorState: compressor.getState() }, "Triggering layered mid-generation compression");
1453
+ try {
1454
+ const originalMessages = stepMessages.slice(0, originalMessageCount);
1455
+ const generatedMessages = stepMessages.slice(originalMessageCount);
1456
+ if (generatedMessages.length > 0) {
1457
+ const compressionResult = await compressor.compress(generatedMessages);
1458
+ const finalMessages = [...originalMessages];
1459
+ if (compressionResult.summary.text_messages && compressionResult.summary.text_messages.length > 0) finalMessages.push(...compressionResult.summary.text_messages);
1460
+ const summaryMessage = JSON.stringify({
1461
+ high_level: compressionResult.summary?.summary?.high_level,
1462
+ user_intent: compressionResult.summary?.summary?.user_intent,
1463
+ decisions: compressionResult.summary?.summary?.decisions,
1464
+ open_questions: compressionResult.summary?.summary?.open_questions,
1465
+ next_steps: compressionResult.summary?.summary?.next_steps,
1466
+ related_artifacts: compressionResult?.summary?.summary?.related_artifacts
1467
+ });
1468
+ finalMessages.push({
1469
+ role: "user",
1470
+ content: `Based on your research, here's what you've discovered: ${summaryMessage}
1471
+
1472
+ Now please provide your answer to my original question using this context.`
1473
+ });
1474
+ logger.info({
1475
+ originalTotal: stepMessages.length,
1476
+ compressed: finalMessages.length,
1477
+ originalKept: originalMessages.length,
1478
+ generatedCompressed: generatedMessages.length
1479
+ }, "Generated content compression completed");
1480
+ logger.info({ summaryMessage }, "Summary message");
1481
+ return { messages: finalMessages };
1482
+ }
1483
+ return {};
1484
+ } catch (error) {
1485
+ logger.error({
1486
+ error: error instanceof Error ? error.message : String(error),
1487
+ stack: error instanceof Error ? error.stack : void 0
1488
+ }, "Smart compression failed, falling back to simple compression");
1489
+ try {
1490
+ const targetSize = Math.floor(compressor.getHardLimit() * .5);
1491
+ const fallbackMessages = this.simpleCompression(stepMessages, targetSize);
1492
+ logger.info({
1493
+ originalCount: stepMessages.length,
1494
+ compressedCount: fallbackMessages.length,
1495
+ compressionType: "simple_fallback"
1496
+ }, "Simple compression fallback completed");
1497
+ return { messages: fallbackMessages };
1498
+ } catch (fallbackError) {
1499
+ logger.error({ error: fallbackError instanceof Error ? fallbackError.message : String(fallbackError) }, "Fallback compression also failed, continuing without compression");
1500
+ return {};
1501
+ }
1502
+ }
1503
+ }
1504
+ return {};
1505
+ },
1506
+ stopWhen: async ({ steps }) => {
1507
+ const last = steps.at(-1);
1508
+ if (last && "text" in last && last.text) try {
1509
+ await agentSessionManager.recordEvent(this.getStreamRequestId(), "agent_reasoning", this.config.id, { parts: [{
1510
+ type: "text",
1511
+ content: last.text
1512
+ }] });
1513
+ } catch (error) {
1514
+ logger.debug({ error }, "Failed to track agent reasoning");
1515
+ }
1516
+ if (last && last["content"] && last["content"].length > 0) {
1517
+ const lastContent = last["content"][last["content"].length - 1];
1518
+ if (lastContent["type"] === "tool-error") {
1519
+ const error = lastContent["error"];
1520
+ if (error && typeof error === "object" && "name" in error && error.name === "connection_refused") return true;
1521
+ }
1522
+ }
1523
+ if (steps.length >= 2) {
1524
+ const previousStep = steps[steps.length - 2];
1525
+ if (previousStep && "toolCalls" in previousStep && previousStep.toolCalls) {
1526
+ if (previousStep.toolCalls.some((tc) => tc.toolName.startsWith("transfer_to_")) && "toolResults" in previousStep && previousStep.toolResults) return true;
1527
+ }
1528
+ }
1529
+ return steps.length >= this.getMaxGenerationSteps();
1530
+ },
1531
+ experimental_telemetry: {
1532
+ isEnabled: true,
1533
+ functionId: this.config.id,
1534
+ recordInputs: true,
1535
+ recordOutputs: true,
1536
+ metadata: {
1537
+ subAgentId: this.config.id,
1538
+ subAgentName: this.config.name
1539
+ }
1540
+ },
1541
+ abortSignal: AbortSignal.timeout(timeoutMs)
1542
+ });
1543
+ const streamHelper = this.getStreamingHelper();
1544
+ if (!streamHelper) throw new Error("Stream helper is unexpectedly undefined in streaming context");
1545
+ const session = toolSessionManager.getSession(sessionId);
1546
+ const artifactParserOptions = {
1547
+ sessionId,
1548
+ taskId: session?.taskId,
1549
+ projectId: session?.projectId,
1550
+ artifactComponents: this.artifactComponents,
1551
+ streamRequestId: this.getStreamRequestId(),
1552
+ subAgentId: this.config.id
1553
+ };
1554
+ const parser = new IncrementalStreamParser(streamHelper, this.config.tenantId, contextId, artifactParserOptions);
1555
+ for await (const event of streamResult.fullStream) switch (event.type) {
1556
+ case "text-delta":
1557
+ await parser.processTextChunk(event.text);
1558
+ break;
1559
+ case "tool-call":
1560
+ parser.markToolResult();
1561
+ break;
1562
+ case "tool-result":
1563
+ parser.markToolResult();
1564
+ break;
1565
+ case "finish":
1566
+ if (event.finishReason === "tool-calls") parser.markToolResult();
1567
+ break;
1568
+ case "error": {
1569
+ if (event.error instanceof Error) throw event.error;
1570
+ const errorMessage = event.error?.error?.message;
1571
+ throw new Error(errorMessage);
1572
+ }
1573
+ }
1574
+ await parser.finalize();
1575
+ response = await streamResult;
1576
+ const collectedParts = parser.getCollectedParts();
1577
+ if (collectedParts.length > 0) response.formattedContent = { parts: collectedParts.map((part) => ({
1578
+ kind: part.kind,
1579
+ ...part.kind === "text" && { text: part.text },
1580
+ ...part.kind === "data" && { data: part.data }
1581
+ })) };
1582
+ const streamedContent = parser.getAllStreamedContent();
1583
+ if (streamedContent.length > 0) response.streamedContent = { parts: streamedContent.map((part) => ({
1584
+ kind: part.kind,
1585
+ ...part.kind === "text" && { text: part.text },
1586
+ ...part.kind === "data" && { data: part.data }
1587
+ })) };
1588
+ } else {
1589
+ let genConfig;
1590
+ if (hasStructuredOutput) genConfig = {
1591
+ ...modelSettings,
1592
+ toolChoice: "required"
1593
+ };
1594
+ else genConfig = {
1595
+ ...modelSettings,
1596
+ toolChoice: "auto"
1597
+ };
1598
+ response = await generateText({
1599
+ ...genConfig,
1600
+ messages,
1601
+ tools: sanitizedTools,
1602
+ prepareStep: async ({ messages: stepMessages }) => {
1603
+ if (!compressor) return {};
1604
+ if (compressor.isCompressionNeeded(stepMessages)) {
1605
+ logger.info({ compressorState: compressor.getState() }, "Triggering layered mid-generation compression");
1606
+ try {
1607
+ const originalMessages = stepMessages.slice(0, originalMessageCount);
1608
+ const generatedMessages = stepMessages.slice(originalMessageCount);
1609
+ if (generatedMessages.length > 0) {
1610
+ const compressionResult = await compressor.compress(generatedMessages);
1611
+ const finalMessages = [...originalMessages];
1612
+ if (compressionResult.summary.text_messages && compressionResult.summary.text_messages.length > 0) finalMessages.push(...compressionResult.summary.text_messages);
1613
+ const summaryMessage = JSON.stringify({
1614
+ high_level: compressionResult.summary?.summary?.high_level,
1615
+ user_intent: compressionResult.summary?.summary?.user_intent,
1616
+ decisions: compressionResult.summary?.summary?.decisions,
1617
+ open_questions: compressionResult.summary?.summary?.open_questions,
1618
+ next_steps: compressionResult.summary?.summary?.next_steps,
1619
+ related_artifacts: compressionResult?.summary?.summary?.related_artifacts
1620
+ });
1621
+ finalMessages.push({
1622
+ role: "user",
1623
+ content: `Based on your research, here's what you've discovered: ${summaryMessage}
1624
+
1625
+ Now please provide your answer to my original question using this context.`
1626
+ });
1627
+ logger.info({
1628
+ originalTotal: stepMessages.length,
1629
+ compressed: finalMessages.length,
1630
+ originalKept: originalMessages.length,
1631
+ generatedCompressed: generatedMessages.length
1632
+ }, "Generated content compression completed");
1633
+ logger.info({ summaryMessage }, "Summary message");
1634
+ return { messages: finalMessages };
1635
+ }
1636
+ return {};
1637
+ } catch (error) {
1638
+ logger.error({
1639
+ error: error instanceof Error ? error.message : String(error),
1640
+ stack: error instanceof Error ? error.stack : void 0
1641
+ }, "Smart compression failed, falling back to simple compression");
1642
+ try {
1643
+ const targetSize = Math.floor(compressor.getHardLimit() * .5);
1644
+ const fallbackMessages = this.simpleCompression(stepMessages, targetSize);
1645
+ logger.info({
1646
+ originalCount: stepMessages.length,
1647
+ compressedCount: fallbackMessages.length,
1648
+ compressionType: "simple_fallback"
1649
+ }, "Simple compression fallback completed");
1650
+ return { messages: fallbackMessages };
1651
+ } catch (fallbackError) {
1652
+ logger.error({ error: fallbackError instanceof Error ? fallbackError.message : String(fallbackError) }, "Fallback compression also failed, continuing without compression");
1653
+ return {};
1654
+ }
1655
+ }
1656
+ }
1657
+ return {};
1658
+ },
1659
+ stopWhen: async ({ steps }) => {
1660
+ const last = steps.at(-1);
1661
+ if (last && "text" in last && last.text) try {
1662
+ await agentSessionManager.recordEvent(this.getStreamRequestId(), "agent_reasoning", this.config.id, { parts: [{
1663
+ type: "text",
1664
+ content: last.text
1665
+ }] });
1666
+ } catch (error) {
1667
+ logger.debug({ error }, "Failed to track agent reasoning");
1668
+ }
1669
+ if (steps.length >= 2) {
1670
+ const previousStep = steps[steps.length - 2];
1671
+ if (previousStep && "toolCalls" in previousStep && previousStep.toolCalls) {
1672
+ if (previousStep.toolCalls.some((tc) => tc.toolName.startsWith("transfer_to_") || tc.toolName === "thinking_complete") && "toolResults" in previousStep && previousStep.toolResults) return true;
1673
+ }
1674
+ }
1675
+ return steps.length >= this.getMaxGenerationSteps();
1676
+ },
1677
+ experimental_telemetry: {
1678
+ isEnabled: true,
1679
+ functionId: this.config.id,
1680
+ recordInputs: true,
1681
+ recordOutputs: true,
1682
+ metadata: {
1683
+ phase: "planning",
1684
+ subAgentId: this.config.id,
1685
+ subAgentName: this.config.name
1686
+ }
1687
+ },
1688
+ abortSignal: AbortSignal.timeout(timeoutMs)
1689
+ });
1690
+ }
1691
+ if (response.steps) {
1692
+ const resolvedSteps = await response.steps;
1693
+ response = {
1694
+ ...response,
1695
+ steps: resolvedSteps
1696
+ };
1697
+ }
1698
+ if (hasStructuredOutput && !hasToolCallWithPrefix("transfer_to_")(response)) if (response.steps?.flatMap((s) => s.toolCalls || [])?.find((tc) => tc.toolName === "thinking_complete")) {
1699
+ const reasoningFlow = [];
1700
+ const compressionSummary = this.currentCompressor?.getCompressionSummary();
1701
+ if (compressionSummary) {
1702
+ const summaryContent = JSON.stringify(compressionSummary, null, 2);
1703
+ reasoningFlow.push({
1704
+ role: "assistant",
1705
+ content: `## Research Summary (Compressed)\n\nBased on tool executions, here's the comprehensive summary:\n\n\`\`\`json\n${summaryContent}\n\`\`\`\n\nThis summary represents all tool execution results in compressed form. Full details are preserved in artifacts.`
1706
+ });
1707
+ } else if (response.steps) response.steps.forEach((step) => {
1708
+ if (step.toolCalls && step.toolResults) step.toolCalls.forEach((call, index) => {
1709
+ const result = step.toolResults[index];
1710
+ if (result) {
1711
+ const storedResult = toolSessionManager.getToolResult(sessionId, result.toolCallId);
1712
+ if ((storedResult?.toolName || call.toolName) === "thinking_complete") return;
1713
+ const actualResult = storedResult?.result || result.result || result;
1714
+ const actualArgs = storedResult?.args || call.args;
1715
+ const cleanResult = actualResult && typeof actualResult === "object" && !Array.isArray(actualResult) ? Object.fromEntries(Object.entries(actualResult).filter(([key]) => key !== "_structureHints")) : actualResult;
1716
+ const input = actualArgs ? JSON.stringify(actualArgs, null, 2) : "No input";
1717
+ const output = typeof cleanResult === "string" ? cleanResult : JSON.stringify(cleanResult, null, 2);
1718
+ let structureHintsFormatted = "";
1719
+ if (actualResult?._structureHints && this.artifactComponents && this.artifactComponents.length > 0) {
1720
+ const hints = actualResult._structureHints;
1721
+ structureHintsFormatted = `
1722
+ ### 📊 Structure Hints for Artifact Creation
1723
+
1724
+ **Terminal Field Paths (${hints.terminalPaths?.length || 0} found):**
1725
+ ${hints.terminalPaths?.map((path) => ` • ${path}`).join("\n") || " None detected"}
1726
+
1727
+ **Array Structures (${hints.arrayPaths?.length || 0} found):**
1728
+ ${hints.arrayPaths?.map((path) => ` • ${path}`).join("\n") || " None detected"}
1729
+
1730
+ **Object Structures (${hints.objectPaths?.length || 0} found):**
1731
+ ${hints.objectPaths?.map((path) => ` • ${path}`).join("\n") || " None detected"}
1732
+
1733
+ **Example Selectors:**
1734
+ ${hints.exampleSelectors?.map((sel) => ` • ${sel}`).join("\n") || " None detected"}
1735
+
1736
+ **Common Fields:**
1737
+ ${hints.commonFields?.map((field) => ` • ${field}`).join("\n") || " None detected"}
1738
+
1739
+ **Structure Stats:** ${hints.totalPathsFound || 0} total paths, ${hints.maxDepthFound || 0} levels deep
1740
+
1741
+ **Note:** ${hints.note || "Use these paths for artifact base selectors."}
1742
+
1743
+ **Forbidden Syntax:** ${hints.forbiddenSyntax || "Use these paths for artifact base selectors."}
1744
+ `;
1745
+ }
1746
+ const formattedResult = `## Tool: ${call.toolName}
1747
+
1748
+ ### 🔧 TOOL_CALL_ID: ${result.toolCallId}
1749
+
1750
+ ### Input
1751
+ ${input}
1752
+
1753
+ ### Output
1754
+ ${output}${structureHintsFormatted}`;
1755
+ reasoningFlow.push({
1756
+ role: "assistant",
1757
+ content: formattedResult
1758
+ });
1759
+ }
1760
+ });
1761
+ });
1762
+ const componentSchemas = [];
1763
+ if (this.config.dataComponents && this.config.dataComponents.length > 0) this.config.dataComponents.forEach((dc) => {
1764
+ const propsSchema = jsonSchemaToZod(dc.props);
1765
+ componentSchemas.push(z.object({
1766
+ id: z.string(),
1767
+ name: z.literal(dc.name),
1768
+ props: propsSchema
1769
+ }));
1770
+ });
1771
+ if (this.artifactComponents.length > 0) {
1772
+ const artifactCreateSchemas = ArtifactCreateSchema.getSchemas(this.artifactComponents);
1773
+ componentSchemas.push(...artifactCreateSchemas);
1774
+ componentSchemas.push(ArtifactReferenceSchema.getSchema());
1775
+ }
1776
+ let dataComponentsSchema;
1777
+ if (componentSchemas.length === 1) dataComponentsSchema = componentSchemas[0];
1778
+ else dataComponentsSchema = z.union(componentSchemas);
1779
+ const structuredModelSettings = ModelFactory.prepareGenerationConfig(this.getStructuredOutputModel());
1780
+ const configuredPhase2Timeout = structuredModelSettings.maxDuration ? Math.min(structuredModelSettings.maxDuration * 1e3, LLM_GENERATION_MAX_ALLOWED_TIMEOUT_MS) : LLM_GENERATION_SUBSEQUENT_CALL_TIMEOUT_MS;
1781
+ const phase2TimeoutMs = Math.min(configuredPhase2Timeout, LLM_GENERATION_MAX_ALLOWED_TIMEOUT_MS);
1782
+ if (structuredModelSettings.maxDuration && structuredModelSettings.maxDuration * 1e3 > LLM_GENERATION_MAX_ALLOWED_TIMEOUT_MS) logger.warn({
1783
+ requestedTimeout: structuredModelSettings.maxDuration * 1e3,
1784
+ appliedTimeout: phase2TimeoutMs,
1785
+ maxAllowed: LLM_GENERATION_MAX_ALLOWED_TIMEOUT_MS,
1786
+ phase: "structured_generation"
1787
+ }, "Phase 2 requested timeout exceeded maximum allowed, capping to 10 minutes");
1788
+ if (this.getStreamingHelper()) {
1789
+ const phase2Messages = [{
1790
+ role: "system",
1791
+ content: await this.buildPhase2SystemPrompt(runtimeContext)
1792
+ }];
1793
+ if (conversationHistory.trim() !== "") phase2Messages.push({
1794
+ role: "user",
1795
+ content: conversationHistory
1796
+ });
1797
+ phase2Messages.push({
1798
+ role: "user",
1799
+ content: userMessage
1800
+ });
1801
+ phase2Messages.push(...reasoningFlow);
1802
+ if (reasoningFlow.length > 0 && reasoningFlow[reasoningFlow.length - 1]?.role === "assistant") phase2Messages.push({
1803
+ role: "user",
1804
+ content: "Continue with the structured response."
1805
+ });
1806
+ const streamResult = streamObject({
1807
+ ...structuredModelSettings,
1808
+ messages: phase2Messages,
1809
+ schema: z.object({ dataComponents: z.array(dataComponentsSchema) }),
1810
+ experimental_telemetry: {
1811
+ isEnabled: true,
1812
+ functionId: this.config.id,
1813
+ recordInputs: true,
1814
+ recordOutputs: true,
1815
+ metadata: {
1816
+ phase: "structured_generation",
1817
+ subAgentId: this.config.id,
1818
+ subAgentName: this.config.name
1819
+ }
1820
+ },
1821
+ abortSignal: AbortSignal.timeout(phase2TimeoutMs)
1822
+ });
1823
+ const streamHelper = this.getStreamingHelper();
1824
+ if (!streamHelper) throw new Error("Stream helper is unexpectedly undefined in streaming context");
1825
+ const session = toolSessionManager.getSession(sessionId);
1826
+ const artifactParserOptions = {
1827
+ sessionId,
1828
+ taskId: session?.taskId,
1829
+ projectId: session?.projectId,
1830
+ artifactComponents: this.artifactComponents,
1831
+ streamRequestId: this.getStreamRequestId(),
1832
+ subAgentId: this.config.id
1833
+ };
1834
+ const parser = new IncrementalStreamParser(streamHelper, this.config.tenantId, contextId, artifactParserOptions);
1835
+ for await (const delta of streamResult.partialObjectStream) if (delta) await parser.processObjectDelta(delta);
1836
+ await parser.finalize();
1837
+ const structuredResponse = await streamResult;
1838
+ const collectedParts = parser.getCollectedParts();
1839
+ if (collectedParts.length > 0) response.formattedContent = { parts: collectedParts.map((part) => ({
1840
+ kind: part.kind,
1841
+ ...part.kind === "text" && { text: part.text },
1842
+ ...part.kind === "data" && { data: part.data }
1843
+ })) };
1844
+ response = {
1845
+ ...response,
1846
+ object: structuredResponse.object
1847
+ };
1848
+ textResponse = JSON.stringify(structuredResponse.object, null, 2);
1849
+ } else {
1850
+ const { withJsonPostProcessing } = await import("../utils/json-postprocessor.js");
1851
+ const phase2Messages = [{
1852
+ role: "system",
1853
+ content: await this.buildPhase2SystemPrompt(runtimeContext)
1854
+ }];
1855
+ if (conversationHistory.trim() !== "") phase2Messages.push({
1856
+ role: "user",
1857
+ content: conversationHistory
1858
+ });
1859
+ phase2Messages.push({
1860
+ role: "user",
1861
+ content: userMessage
1862
+ });
1863
+ phase2Messages.push(...reasoningFlow);
1864
+ if (reasoningFlow.length > 0 && reasoningFlow[reasoningFlow.length - 1]?.role === "assistant") phase2Messages.push({
1865
+ role: "user",
1866
+ content: "Continue with the structured response."
1867
+ });
1868
+ const structuredResponse = await generateObject(withJsonPostProcessing({
1869
+ ...structuredModelSettings,
1870
+ messages: phase2Messages,
1871
+ schema: z.object({ dataComponents: z.array(dataComponentsSchema) }),
1872
+ experimental_telemetry: {
1873
+ isEnabled: true,
1874
+ functionId: this.config.id,
1875
+ recordInputs: true,
1876
+ recordOutputs: true,
1877
+ metadata: {
1878
+ phase: "structured_generation",
1879
+ subAgentId: this.config.id,
1880
+ subAgentName: this.config.name
1881
+ }
1882
+ },
1883
+ abortSignal: AbortSignal.timeout(phase2TimeoutMs)
1884
+ }));
1885
+ response = {
1886
+ ...response,
1887
+ object: structuredResponse.object
1888
+ };
1889
+ textResponse = JSON.stringify(structuredResponse.object, null, 2);
1890
+ }
1891
+ } else textResponse = response.text || "";
1892
+ else textResponse = response.steps[response.steps.length - 1].text || "";
1893
+ span.setStatus({ code: SpanStatusCode.OK });
1894
+ span.end();
1895
+ let formattedContent = response.formattedContent || null;
1896
+ if (!formattedContent) {
1897
+ const session = toolSessionManager.getSession(sessionId);
1898
+ const responseFormatter = new ResponseFormatter(this.config.tenantId, {
1899
+ sessionId,
1900
+ taskId: session?.taskId,
1901
+ projectId: session?.projectId,
1902
+ contextId,
1903
+ artifactComponents: this.artifactComponents,
1904
+ streamRequestId: this.getStreamRequestId(),
1905
+ subAgentId: this.config.id
1906
+ });
1907
+ if (response.object) formattedContent = await responseFormatter.formatObjectResponse(response.object, contextId);
1908
+ else if (textResponse) formattedContent = await responseFormatter.formatResponse(textResponse, contextId);
1909
+ }
1910
+ const formattedResponse = {
1911
+ ...response,
1912
+ formattedContent
1913
+ };
1914
+ if (streamRequestId) {
1915
+ const generationType = response.object ? "object_generation" : "text_generation";
1916
+ agentSessionManager.recordEvent(streamRequestId, "agent_generate", this.config.id, {
1917
+ parts: (formattedContent?.parts || []).map((part) => ({
1918
+ type: part.kind === "text" ? "text" : part.kind === "data" ? "tool_result" : "text",
1919
+ content: part.text || JSON.stringify(part.data)
1920
+ })),
1921
+ generationType
1922
+ });
1923
+ }
1924
+ this.currentCompressor = null;
1925
+ return formattedResponse;
1926
+ } catch (error) {
1927
+ this.currentCompressor = null;
1928
+ const errorToThrow = error instanceof Error ? error : new Error(String(error));
1929
+ setSpanWithError$1(span, errorToThrow);
1930
+ span.end();
1931
+ throw errorToThrow;
1932
+ }
1933
+ });
1934
+ }
1935
+ };
1936
+
1937
+ //#endregion
1938
+ export { Agent, hasToolCallWithPrefix };