@inkeep/agents-run-api 0.39.5 → 0.41.0

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 (180) 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 +576 -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 +268 -0
  18. package/dist/agents/Agent.js +1932 -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 +523 -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 +27 -0
  32. package/dist/agents/versions/v1/Phase1Config.js +424 -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 +51 -0
  36. package/dist/constants/execution-limits/defaults.js +52 -0
  37. package/dist/constants/execution-limits/index.d.ts +6 -0
  38. package/dist/constants/execution-limits/index.js +21 -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 +128 -0
  46. package/dist/data/conversations.js +522 -0
  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 +41 -0
  52. package/dist/handlers/executionHandler.js +457 -0
  53. package/dist/index.d.ts +8 -29
  54. package/dist/index.js +5 -11386
  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 +305 -0
  69. package/dist/routes/chatDataStream.d.ts +13 -0
  70. package/dist/routes/chatDataStream.js +365 -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 +612 -0
  79. package/dist/services/BaseCompressor.d.ts +183 -0
  80. package/dist/services/BaseCompressor.js +500 -0
  81. package/dist/services/ConversationCompressor.d.ts +32 -0
  82. package/dist/services/ConversationCompressor.js +91 -0
  83. package/dist/services/IncrementalStreamParser.d.ts +98 -0
  84. package/dist/services/IncrementalStreamParser.js +327 -0
  85. package/dist/services/MidGenerationCompressor.d.ts +63 -0
  86. package/dist/services/MidGenerationCompressor.js +104 -0
  87. package/dist/services/PendingToolApprovalManager.d.ts +62 -0
  88. package/dist/services/PendingToolApprovalManager.js +133 -0
  89. package/dist/services/ResponseFormatter.d.ts +39 -0
  90. package/dist/services/ResponseFormatter.js +152 -0
  91. package/dist/tools/NativeSandboxExecutor.d.ts +38 -0
  92. package/dist/tools/NativeSandboxExecutor.js +432 -0
  93. package/dist/tools/SandboxExecutorFactory.d.ts +36 -0
  94. package/dist/tools/SandboxExecutorFactory.js +80 -0
  95. package/dist/tools/VercelSandboxExecutor.d.ts +71 -0
  96. package/dist/tools/VercelSandboxExecutor.js +340 -0
  97. package/dist/tools/distill-conversation-history-tool.d.ts +62 -0
  98. package/dist/tools/distill-conversation-history-tool.js +206 -0
  99. package/dist/tools/distill-conversation-tool.d.ts +41 -0
  100. package/dist/tools/distill-conversation-tool.js +141 -0
  101. package/dist/tools/sandbox-utils.d.ts +18 -0
  102. package/dist/tools/sandbox-utils.js +53 -0
  103. package/dist/types/chat.d.ts +27 -0
  104. package/dist/types/chat.js +1 -0
  105. package/dist/types/execution-context.d.ts +46 -0
  106. package/dist/types/execution-context.js +27 -0
  107. package/dist/types/xml.d.ts +5 -0
  108. package/dist/utils/SchemaProcessor.d.ts +52 -0
  109. package/dist/utils/SchemaProcessor.js +182 -0
  110. package/dist/utils/agent-operations.d.ts +62 -0
  111. package/dist/utils/agent-operations.js +53 -0
  112. package/dist/utils/artifact-component-schema.d.ts +42 -0
  113. package/dist/utils/artifact-component-schema.js +186 -0
  114. package/dist/utils/cleanup.d.ts +21 -0
  115. package/dist/utils/cleanup.js +59 -0
  116. package/dist/utils/data-component-schema.d.ts +2 -0
  117. package/dist/utils/data-component-schema.js +3 -0
  118. package/dist/utils/default-status-schemas.d.ts +20 -0
  119. package/dist/utils/default-status-schemas.js +24 -0
  120. package/dist/utils/json-postprocessor.d.ts +13 -0
  121. package/dist/{json-postprocessor.cjs → utils/json-postprocessor.js} +2 -3
  122. package/dist/utils/model-context-utils.d.ts +39 -0
  123. package/dist/utils/model-context-utils.js +181 -0
  124. package/dist/utils/model-resolver.d.ts +6 -0
  125. package/dist/utils/model-resolver.js +34 -0
  126. package/dist/utils/schema-validation.d.ts +44 -0
  127. package/dist/utils/schema-validation.js +97 -0
  128. package/dist/utils/stream-helpers.d.ts +197 -0
  129. package/dist/utils/stream-helpers.js +518 -0
  130. package/dist/utils/stream-registry.d.ts +22 -0
  131. package/dist/utils/stream-registry.js +34 -0
  132. package/dist/utils/token-estimator.d.ts +69 -0
  133. package/dist/utils/token-estimator.js +53 -0
  134. package/dist/utils/tracer.d.ts +7 -0
  135. package/dist/utils/tracer.js +7 -0
  136. package/package.json +10 -26
  137. package/dist/SandboxExecutorFactory.cjs +0 -895
  138. package/dist/SandboxExecutorFactory.js +0 -893
  139. package/dist/SandboxExecutorFactory.js.map +0 -1
  140. package/dist/chunk-VBDAOXYI.cjs +0 -927
  141. package/dist/chunk-VBDAOXYI.js +0 -832
  142. package/dist/chunk-VBDAOXYI.js.map +0 -1
  143. package/dist/chunk.cjs +0 -34
  144. package/dist/conversations.cjs +0 -7
  145. package/dist/conversations.js +0 -7
  146. package/dist/conversations2.cjs +0 -209
  147. package/dist/conversations2.js +0 -180
  148. package/dist/conversations2.js.map +0 -1
  149. package/dist/dbClient.cjs +0 -9676
  150. package/dist/dbClient.js +0 -9670
  151. package/dist/dbClient.js.map +0 -1
  152. package/dist/dbClient2.cjs +0 -5
  153. package/dist/dbClient2.js +0 -5
  154. package/dist/env.cjs +0 -59
  155. package/dist/env.js.map +0 -1
  156. package/dist/execution-limits.cjs +0 -260
  157. package/dist/execution-limits.js +0 -63
  158. package/dist/execution-limits.js.map +0 -1
  159. package/dist/index.cjs +0 -11411
  160. package/dist/index.d.cts +0 -36
  161. package/dist/index.d.cts.map +0 -1
  162. package/dist/index.d.ts.map +0 -1
  163. package/dist/index.js.map +0 -1
  164. package/dist/instrumentation.cjs +0 -12
  165. package/dist/instrumentation.d.cts +0 -18
  166. package/dist/instrumentation.d.cts.map +0 -1
  167. package/dist/instrumentation.d.ts.map +0 -1
  168. package/dist/instrumentation2.cjs +0 -116
  169. package/dist/instrumentation2.js +0 -69
  170. package/dist/instrumentation2.js.map +0 -1
  171. package/dist/json-postprocessor.js +0 -20
  172. package/dist/json-postprocessor.js.map +0 -1
  173. package/dist/logger.cjs +0 -5
  174. package/dist/logger2.cjs +0 -1
  175. package/dist/nodefs.cjs +0 -29
  176. package/dist/nodefs.js +0 -27
  177. package/dist/nodefs.js.map +0 -1
  178. package/dist/opfs-ahp.cjs +0 -367
  179. package/dist/opfs-ahp.js +0 -368
  180. package/dist/opfs-ahp.js.map +0 -1
@@ -0,0 +1,1208 @@
1
+ import { getLogger } from "../logger.js";
2
+ import dbClient_default from "../data/db/dbClient.js";
3
+ import { ARTIFACT_GENERATION_BACKOFF_INITIAL_MS, ARTIFACT_GENERATION_BACKOFF_MAX_MS, ARTIFACT_GENERATION_MAX_RETRIES, ARTIFACT_SESSION_MAX_PENDING, ARTIFACT_SESSION_MAX_PREVIOUS_SUMMARIES, STATUS_UPDATE_DEFAULT_INTERVAL_SECONDS, STATUS_UPDATE_DEFAULT_NUM_EVENTS } from "../constants/execution-limits/index.js";
4
+ import { toolSessionManager } from "../agents/ToolSessionManager.js";
5
+ import { setSpanWithError as setSpanWithError$1, tracer } from "../utils/tracer.js";
6
+ import { getFormattedConversationHistory } from "../data/conversations.js";
7
+ import { defaultStatusSchemas } from "../utils/default-status-schemas.js";
8
+ import { getStreamHelper } from "../utils/stream-registry.js";
9
+ import { ArtifactService } from "./ArtifactService.js";
10
+ import { ArtifactParser } from "./ArtifactParser.js";
11
+ import { z } from "@hono/zod-openapi";
12
+ import { CONVERSATION_HISTORY_DEFAULT_LIMIT, CONVERSATION_HISTORY_MAX_OUTPUT_TOKENS_DEFAULT, ModelFactory, getLedgerArtifacts, getSubAgentById } from "@inkeep/agents-core";
13
+ import { SpanStatusCode } from "@opentelemetry/api";
14
+ import { Output, generateText } from "ai";
15
+
16
+ //#region src/services/AgentSession.ts
17
+ const logger = getLogger("AgentSession");
18
+ /**
19
+ * Tracks all agent operations and interactions for a single message
20
+ * Now includes intelligent status update functionality
21
+ */
22
+ var AgentSession = class {
23
+ events = [];
24
+ statusUpdateState;
25
+ statusUpdateTimer;
26
+ previousSummaries = [];
27
+ isEnded = false;
28
+ isTextStreaming = false;
29
+ isGeneratingUpdate = false;
30
+ pendingArtifacts = /* @__PURE__ */ new Set();
31
+ artifactProcessingErrors = /* @__PURE__ */ new Map();
32
+ MAX_ARTIFACT_RETRIES = ARTIFACT_GENERATION_MAX_RETRIES;
33
+ MAX_PENDING_ARTIFACTS = ARTIFACT_SESSION_MAX_PENDING;
34
+ scheduledTimeouts;
35
+ artifactCache = /* @__PURE__ */ new Map();
36
+ artifactService;
37
+ artifactParser;
38
+ isEmitOperations = false;
39
+ constructor(sessionId, messageId, agentId, tenantId, projectId, contextId) {
40
+ this.sessionId = sessionId;
41
+ this.messageId = messageId;
42
+ this.agentId = agentId;
43
+ this.tenantId = tenantId;
44
+ this.projectId = projectId;
45
+ this.contextId = contextId;
46
+ logger.debug({
47
+ sessionId,
48
+ messageId,
49
+ agentId
50
+ }, "AgentSession created");
51
+ if (tenantId && projectId) {
52
+ toolSessionManager.createSessionWithId(sessionId, tenantId, projectId, contextId || "default", `task_${contextId}-${messageId}`);
53
+ this.artifactService = new ArtifactService({
54
+ tenantId,
55
+ projectId,
56
+ sessionId,
57
+ contextId,
58
+ taskId: `task_${contextId}-${messageId}`,
59
+ streamRequestId: sessionId
60
+ });
61
+ this.artifactParser = new ArtifactParser(tenantId, {
62
+ projectId,
63
+ sessionId,
64
+ contextId,
65
+ taskId: `task_${contextId}-${messageId}`,
66
+ streamRequestId: sessionId,
67
+ artifactService: this.artifactService
68
+ });
69
+ }
70
+ }
71
+ /**
72
+ * Enable emit operations to send data operations
73
+ */
74
+ enableEmitOperations() {
75
+ this.isEmitOperations = true;
76
+ logger.info({ sessionId: this.sessionId }, "🔍 DEBUG: Emit operations enabled for AgentSession");
77
+ }
78
+ /**
79
+ * Send data operation to stream when emit operations is enabled
80
+ */
81
+ async sendDataOperation(event) {
82
+ try {
83
+ const streamHelper = getStreamHelper(this.sessionId);
84
+ if (streamHelper) {
85
+ const formattedOperation = {
86
+ type: event.eventType,
87
+ label: this.generateEventLabel(event),
88
+ details: {
89
+ timestamp: event.timestamp,
90
+ subAgentId: event.subAgentId,
91
+ data: event.data
92
+ }
93
+ };
94
+ await streamHelper.writeOperation(formattedOperation);
95
+ }
96
+ } catch (error) {
97
+ logger.error({
98
+ sessionId: this.sessionId,
99
+ eventType: event.eventType,
100
+ error: error instanceof Error ? error.message : error
101
+ }, "❌ DEBUG: Failed to send data operation");
102
+ }
103
+ }
104
+ /**
105
+ * Generate human-readable labels for events
106
+ */
107
+ generateEventLabel(event) {
108
+ switch (event.eventType) {
109
+ case "agent_generate": return `Agent ${event.subAgentId} generating response`;
110
+ case "agent_reasoning": return `Agent ${event.subAgentId} reasoning through request`;
111
+ case "tool_call": return `Tool call: ${event.data.toolName || "unknown"}`;
112
+ case "tool_result": {
113
+ const status = event.data.error ? "failed" : "completed";
114
+ return `Tool result: ${event.data.toolName || "unknown"} (${status})`;
115
+ }
116
+ case "error": return `Error: ${event.data.message}`;
117
+ case "transfer": return `Agent transfer: ${event.data.fromSubAgent} → ${event.data.targetSubAgent}`;
118
+ case "delegation_sent": return `Task delegated: ${event.data.fromSubAgent} → ${event.data.targetSubAgent}`;
119
+ case "delegation_returned": return `Task completed: ${event.data.targetSubAgent} → ${event.data.fromSubAgent}`;
120
+ case "artifact_saved": return `Artifact saved: ${event.data.artifactType || "unknown type"}`;
121
+ case "compression": return `Compressed ${event.data.messageCount} messages and ${event.data.artifactCount} artifacts (${event.data.reason})`;
122
+ default: return `${event.eventType} event`;
123
+ }
124
+ }
125
+ /**
126
+ * Initialize status updates for this session
127
+ */
128
+ initializeStatusUpdates(config, summarizerModel, baseModel) {
129
+ const now = Date.now();
130
+ this.statusUpdateState = {
131
+ lastUpdateTime: now,
132
+ lastEventCount: 0,
133
+ startTime: now,
134
+ summarizerModel,
135
+ baseModel,
136
+ config: {
137
+ numEvents: config.numEvents || STATUS_UPDATE_DEFAULT_NUM_EVENTS,
138
+ timeInSeconds: config.timeInSeconds || STATUS_UPDATE_DEFAULT_INTERVAL_SECONDS,
139
+ ...config
140
+ }
141
+ };
142
+ if (this.statusUpdateState.config.timeInSeconds) {
143
+ this.statusUpdateTimer = setInterval(async () => {
144
+ if (!this.statusUpdateState || this.isEnded) {
145
+ logger.debug({ sessionId: this.sessionId }, "Timer triggered but session already cleaned up or ended");
146
+ if (this.statusUpdateTimer) {
147
+ clearInterval(this.statusUpdateTimer);
148
+ this.statusUpdateTimer = void 0;
149
+ }
150
+ return;
151
+ }
152
+ await this.checkAndSendTimeBasedUpdate();
153
+ }, this.statusUpdateState.config.timeInSeconds * 1e3);
154
+ logger.info({
155
+ sessionId: this.sessionId,
156
+ intervalMs: this.statusUpdateState.config.timeInSeconds * 1e3
157
+ }, "Time-based status update timer started");
158
+ }
159
+ }
160
+ /**
161
+ * Record an event in the session and trigger status updates if configured
162
+ * Generic type parameter T ensures eventType and data are correctly paired
163
+ */
164
+ recordEvent(eventType, subAgentId, data) {
165
+ if (this.isEmitOperations) {
166
+ const dataOpEvent = {
167
+ timestamp: Date.now(),
168
+ eventType,
169
+ subAgentId,
170
+ data
171
+ };
172
+ this.sendDataOperation(dataOpEvent);
173
+ }
174
+ if (this.isEnded) {
175
+ logger.debug({
176
+ sessionId: this.sessionId,
177
+ eventType,
178
+ subAgentId
179
+ }, "Event received after session ended - ignoring");
180
+ return;
181
+ }
182
+ const event = {
183
+ timestamp: Date.now(),
184
+ eventType,
185
+ subAgentId,
186
+ data
187
+ };
188
+ this.events.push(event);
189
+ if (eventType === "artifact_saved") {
190
+ const artifactData = data;
191
+ if (artifactData.pendingGeneration) {
192
+ const artifactId = artifactData.artifactId;
193
+ if (this.pendingArtifacts.size >= this.MAX_PENDING_ARTIFACTS) {
194
+ logger.warn({
195
+ sessionId: this.sessionId,
196
+ artifactId,
197
+ pendingCount: this.pendingArtifacts.size,
198
+ maxAllowed: this.MAX_PENDING_ARTIFACTS
199
+ }, "Too many pending artifacts, skipping processing");
200
+ return;
201
+ }
202
+ this.pendingArtifacts.add(artifactId);
203
+ setImmediate(() => {
204
+ const artifactDataWithAgent = {
205
+ ...artifactData,
206
+ subAgentId
207
+ };
208
+ this.processArtifact(artifactDataWithAgent).then(() => {
209
+ this.pendingArtifacts.delete(artifactId);
210
+ this.artifactProcessingErrors.delete(artifactId);
211
+ }).catch((error) => {
212
+ const errorCount = (this.artifactProcessingErrors.get(artifactId) || 0) + 1;
213
+ this.artifactProcessingErrors.set(artifactId, errorCount);
214
+ if (errorCount >= this.MAX_ARTIFACT_RETRIES) {
215
+ this.pendingArtifacts.delete(artifactId);
216
+ logger.error({
217
+ sessionId: this.sessionId,
218
+ artifactId,
219
+ errorCount,
220
+ maxRetries: this.MAX_ARTIFACT_RETRIES,
221
+ error: error instanceof Error ? error.message : "Unknown error",
222
+ stack: error instanceof Error ? error.stack : void 0
223
+ }, "Artifact processing failed after max retries, giving up");
224
+ } else logger.warn({
225
+ sessionId: this.sessionId,
226
+ artifactId,
227
+ errorCount,
228
+ error: error instanceof Error ? error.message : "Unknown error"
229
+ }, "Artifact processing failed, may retry");
230
+ });
231
+ });
232
+ }
233
+ }
234
+ if (!this.isEnded) this.checkStatusUpdates();
235
+ }
236
+ /**
237
+ * Check and send status updates if configured (async, non-blocking)
238
+ */
239
+ checkStatusUpdates() {
240
+ if (this.isEnded) {
241
+ logger.debug({ sessionId: this.sessionId }, "Session has ended - skipping status update check");
242
+ return;
243
+ }
244
+ if (!this.statusUpdateState) {
245
+ logger.debug({ sessionId: this.sessionId }, "No status update state - skipping check");
246
+ return;
247
+ }
248
+ const statusUpdateState = this.statusUpdateState;
249
+ this.scheduleStatusUpdateCheck(statusUpdateState);
250
+ }
251
+ /**
252
+ * Check and send time-based status updates
253
+ */
254
+ async checkAndSendTimeBasedUpdate() {
255
+ if (this.isEnded) {
256
+ logger.debug({ sessionId: this.sessionId }, "Session has ended - skipping time-based update");
257
+ return;
258
+ }
259
+ if (!this.statusUpdateState) {
260
+ logger.debug({ sessionId: this.sessionId }, "No status updates configured for time-based check");
261
+ return;
262
+ }
263
+ if (this.events.length - this.statusUpdateState.lastEventCount === 0) return;
264
+ try {
265
+ await this.generateAndSendUpdate();
266
+ } catch (error) {
267
+ logger.error({
268
+ sessionId: this.sessionId,
269
+ error: error instanceof Error ? error.message : "Unknown error"
270
+ }, "Failed to send time-based status update");
271
+ }
272
+ }
273
+ /**
274
+ * Get all events in chronological order
275
+ */
276
+ getEvents() {
277
+ return [...this.events];
278
+ }
279
+ /**
280
+ * Get events filtered by type
281
+ */
282
+ getEventsByType(eventType) {
283
+ return this.events.filter((event) => event.eventType === eventType);
284
+ }
285
+ /**
286
+ * Get events filtered by agent
287
+ */
288
+ getEventsByAgent(subAgentId) {
289
+ return this.events.filter((event) => event.subAgentId === subAgentId);
290
+ }
291
+ /**
292
+ * Get summary of session activity
293
+ */
294
+ getSummary() {
295
+ const eventCounts = this.events.reduce((counts, event) => {
296
+ counts[event.eventType] = (counts[event.eventType] || 0) + 1;
297
+ return counts;
298
+ }, {});
299
+ const agentCounts = this.events.reduce((counts, event) => {
300
+ counts[event.subAgentId] = (counts[event.subAgentId] || 0) + 1;
301
+ return counts;
302
+ }, {});
303
+ return {
304
+ sessionId: this.sessionId,
305
+ messageId: this.messageId,
306
+ agentId: this.agentId,
307
+ totalEvents: this.events.length,
308
+ eventCounts,
309
+ agentCounts,
310
+ startTime: this.events[0]?.timestamp,
311
+ endTime: this.events[this.events.length - 1]?.timestamp,
312
+ duration: this.events.length > 0 ? this.events[this.events.length - 1].timestamp - this.events[0].timestamp : 0
313
+ };
314
+ }
315
+ /**
316
+ * Mark that text streaming has started (to suppress status updates)
317
+ */
318
+ setTextStreaming(isStreaming) {
319
+ this.isTextStreaming = isStreaming;
320
+ }
321
+ /**
322
+ * Check if text is currently being streamed
323
+ */
324
+ isCurrentlyStreaming() {
325
+ return this.isTextStreaming;
326
+ }
327
+ /**
328
+ * Clean up status update resources when session ends
329
+ */
330
+ async cleanup() {
331
+ this.isEnded = true;
332
+ if (this.statusUpdateTimer) {
333
+ clearInterval(this.statusUpdateTimer);
334
+ this.statusUpdateTimer = void 0;
335
+ }
336
+ this.statusUpdateState = void 0;
337
+ if (this.pendingArtifacts.size > 0) {
338
+ const maxWaitTime = 1e4;
339
+ const startTime = Date.now();
340
+ while (this.pendingArtifacts.size > 0 && Date.now() - startTime < maxWaitTime) await new Promise((resolve) => setTimeout(resolve, 100));
341
+ if (this.pendingArtifacts.size > 0) logger.warn({
342
+ sessionId: this.sessionId,
343
+ pendingCount: this.pendingArtifacts.size,
344
+ pendingIds: Array.from(this.pendingArtifacts)
345
+ }, "Cleanup proceeding with pending artifacts still processing");
346
+ }
347
+ this.pendingArtifacts.clear();
348
+ this.artifactProcessingErrors.clear();
349
+ this.artifactCache.clear();
350
+ if (this.sessionId) toolSessionManager.endSession(this.sessionId);
351
+ if (this.scheduledTimeouts) {
352
+ for (const timeoutId of this.scheduledTimeouts) clearTimeout(timeoutId);
353
+ this.scheduledTimeouts.clear();
354
+ }
355
+ if (this.artifactService) {
356
+ this.artifactService.constructor.clearCaches();
357
+ this.artifactService = void 0;
358
+ } else ArtifactService.clearCaches();
359
+ }
360
+ /**
361
+ * Generate and send a status update using agent-level summarizer
362
+ */
363
+ async generateAndSendUpdate() {
364
+ if (this.isEnded) {
365
+ logger.debug({ sessionId: this.sessionId }, "Session has ended - not generating update");
366
+ return;
367
+ }
368
+ if (this.isTextStreaming) {
369
+ logger.debug({ sessionId: this.sessionId }, "Text is currently streaming - skipping status update");
370
+ return;
371
+ }
372
+ if (this.isGeneratingUpdate) {
373
+ logger.debug({ sessionId: this.sessionId }, "Update already in progress - skipping duplicate generation");
374
+ return;
375
+ }
376
+ if (!this.statusUpdateState) {
377
+ logger.warn({ sessionId: this.sessionId }, "No status update state - cannot generate update");
378
+ return;
379
+ }
380
+ if (!this.agentId) {
381
+ logger.warn({ sessionId: this.sessionId }, "No agent ID - cannot generate update");
382
+ return;
383
+ }
384
+ if (this.events.length - this.statusUpdateState.lastEventCount === 0) return;
385
+ this.isGeneratingUpdate = true;
386
+ const statusUpdateState = this.statusUpdateState;
387
+ try {
388
+ const streamHelper = getStreamHelper(this.sessionId);
389
+ if (!streamHelper) {
390
+ logger.warn({ sessionId: this.sessionId }, "No stream helper found - cannot send status update");
391
+ this.isGeneratingUpdate = false;
392
+ return;
393
+ }
394
+ const now = Date.now();
395
+ const elapsedTime = now - statusUpdateState.startTime;
396
+ const statusComponents = statusUpdateState.config.statusComponents && statusUpdateState.config.statusComponents.length > 0 ? statusUpdateState.config.statusComponents : defaultStatusSchemas;
397
+ const result = await this.generateStructuredStatusUpdate(this.events.slice(statusUpdateState.lastEventCount), elapsedTime, statusComponents, statusUpdateState.summarizerModel, this.previousSummaries);
398
+ if (result.summaries && result.summaries.length > 0) {
399
+ for (const summary of result.summaries) {
400
+ if (!summary || !summary.type || !summary.data || !summary.data.label || Object.keys(summary.data).length === 0) {
401
+ logger.warn({
402
+ sessionId: this.sessionId,
403
+ summary
404
+ }, "Skipping empty or invalid structured operation");
405
+ continue;
406
+ }
407
+ const summaryToSend = {
408
+ type: summary.data.type || summary.type,
409
+ label: summary.data.label,
410
+ details: Object.fromEntries(Object.entries(summary.data).filter(([key]) => !["label", "type"].includes(key)))
411
+ };
412
+ await streamHelper.writeSummary(summaryToSend);
413
+ }
414
+ const summaryTexts = result.summaries.map((summary) => JSON.stringify({
415
+ type: summary.type,
416
+ data: summary.data
417
+ }));
418
+ this.previousSummaries.push(...summaryTexts);
419
+ if (this.statusUpdateState) {
420
+ this.statusUpdateState.lastUpdateTime = now;
421
+ this.statusUpdateState.lastEventCount = this.events.length;
422
+ }
423
+ return;
424
+ }
425
+ if (this.previousSummaries.length > ARTIFACT_SESSION_MAX_PREVIOUS_SUMMARIES) this.previousSummaries.shift();
426
+ if (this.statusUpdateState) {
427
+ this.statusUpdateState.lastUpdateTime = now;
428
+ this.statusUpdateState.lastEventCount = this.events.length;
429
+ }
430
+ } catch (error) {
431
+ logger.error({
432
+ sessionId: this.sessionId,
433
+ error: error instanceof Error ? error.message : "Unknown error",
434
+ stack: error instanceof Error ? error.stack : void 0
435
+ }, "❌ Failed to generate status update");
436
+ } finally {
437
+ this.isGeneratingUpdate = false;
438
+ }
439
+ }
440
+ /**
441
+ * Schedule status update check without setImmediate race conditions
442
+ */
443
+ scheduleStatusUpdateCheck(statusUpdateState) {
444
+ const timeoutId = setTimeout(async () => {
445
+ try {
446
+ if (this.isEnded || !this.statusUpdateState) return;
447
+ if (!this.acquireUpdateLock()) return;
448
+ try {
449
+ if (this.isEnded || !statusUpdateState || this.isTextStreaming) return;
450
+ const currentEventCount = this.events.length;
451
+ const numEventsThreshold = statusUpdateState.config.numEvents;
452
+ if (numEventsThreshold && currentEventCount >= statusUpdateState.lastEventCount + numEventsThreshold) await this.generateAndSendUpdate();
453
+ } finally {
454
+ this.releaseUpdateLock();
455
+ }
456
+ } catch (error) {
457
+ logger.error({
458
+ sessionId: this.sessionId,
459
+ error: error instanceof Error ? error.message : "Unknown error"
460
+ }, "Failed to check status updates during event recording");
461
+ this.releaseUpdateLock();
462
+ }
463
+ }, 0);
464
+ if (!this.scheduledTimeouts) this.scheduledTimeouts = /* @__PURE__ */ new Set();
465
+ this.scheduledTimeouts.add(timeoutId);
466
+ setTimeout(() => {
467
+ if (this.scheduledTimeouts) this.scheduledTimeouts.delete(timeoutId);
468
+ }, 1e3);
469
+ }
470
+ /**
471
+ * Acquire update lock with atomic check
472
+ */
473
+ acquireUpdateLock() {
474
+ if (this.statusUpdateState?.updateLock) return false;
475
+ if (this.statusUpdateState) this.statusUpdateState.updateLock = true;
476
+ return true;
477
+ }
478
+ /**
479
+ * Release update lock
480
+ */
481
+ releaseUpdateLock() {
482
+ if (this.statusUpdateState) this.statusUpdateState.updateLock = false;
483
+ }
484
+ /**
485
+ * Generate structured status update using configured data components
486
+ */
487
+ async generateStructuredStatusUpdate(newEvents, elapsedTime, statusComponents, summarizerModel, previousSummaries = []) {
488
+ return tracer.startActiveSpan("agent_session.generate_structured_update", { attributes: {
489
+ "agent_session.id": this.sessionId,
490
+ "events.count": newEvents.length,
491
+ "elapsed_time.seconds": Math.round(elapsedTime / 1e3),
492
+ "llm.model": summarizerModel?.model,
493
+ "status_components.count": statusComponents.length,
494
+ "previous_summaries.count": previousSummaries.length
495
+ } }, async (span) => {
496
+ try {
497
+ const userVisibleActivities = this.extractUserVisibleActivities(newEvents);
498
+ let conversationContext = "";
499
+ if (this.tenantId && this.projectId) try {
500
+ const conversationHistory = await getFormattedConversationHistory({
501
+ tenantId: this.tenantId,
502
+ projectId: this.projectId,
503
+ conversationId: this.contextId || "default",
504
+ options: {
505
+ limit: CONVERSATION_HISTORY_DEFAULT_LIMIT,
506
+ maxOutputTokens: CONVERSATION_HISTORY_MAX_OUTPUT_TOKENS_DEFAULT,
507
+ includeInternal: true,
508
+ messageTypes: ["chat", "tool-result"]
509
+ },
510
+ filters: {}
511
+ });
512
+ conversationContext = conversationHistory.trim() ? `\nUser's Question/Context:\n${conversationHistory}\n` : "";
513
+ } catch (error) {
514
+ logger.warn({
515
+ sessionId: this.sessionId,
516
+ error
517
+ }, "Failed to fetch conversation history for structured status update");
518
+ }
519
+ const previousSummaryContext = previousSummaries.length > 0 ? `\nPrevious updates sent to user:\n${previousSummaries.map((s, i) => `${i + 1}. ${s}`).join("\n")}\n` : "";
520
+ const selectionSchema = z.object(Object.fromEntries([["no_relevant_updates", z.object({ no_updates: z.boolean().default(true) }).optional().describe("Use when nothing substantially new to report. Should only use on its own.")], ...statusComponents.map((component) => [component.type, this.getComponentSchema(component).optional().describe(component.description || component.type)])]));
521
+ const prompt = `Generate status updates for relevant components based on what the user has asked for.${conversationContext}${previousSummaries.length > 0 ? `\n${previousSummaryContext}` : ""}
522
+
523
+ Activities:\n${userVisibleActivities.join("\n") || "No New Activities"}
524
+
525
+ Available components: no_relevant_updates, ${statusComponents.map((c) => c.type).join(", ")}
526
+
527
+ Rules:
528
+ - Fill in data for relevant components only
529
+ - Use 'no_relevant_updates' if nothing substantially new to report. DO NOT WRITE LABELS OR USE OTHER COMPONENTS IF YOU USE THIS COMPONENT.
530
+ - Never repeat previous values, make every update EXTREMELY unique. If you cannot do that the update is not worth mentioning.
531
+ - Labels MUST be short 3-7 word phrases with ACTUAL information discovered. NEVER MAKE UP SOMETHING WITHOUT BACKING IT UP WITH ACTUAL INFORMATION.
532
+ - Use sentence case: only capitalize the first word and proper nouns (e.g., "Admin permissions required", not "Admin Permissions Required"). ALWAYS capitalize the first word of the label.
533
+ - DO NOT use action words like "Searching", "Processing", "Analyzing" - state what was FOUND
534
+ - Include specific details, numbers, requirements, or insights discovered
535
+ - Examples: "Admin permissions required", "Three OAuth steps found", "Token expires daily"
536
+
537
+ CRITICAL - HIDE ALL INTERNAL SYSTEM OPERATIONS:
538
+ - You are ONE unified AI system presenting results to the user
539
+ - ABSOLUTELY FORBIDDEN WORDS/PHRASES: "transfer", "transferring", "delegation", "delegating", "delegate", "agent", "routing", "route", "artifact", "saving artifact", "stored artifact", "artifact saved", "continuing", "passing to", "handing off", "switching to"
540
+ - NEVER reveal internal architecture: No mentions of different agents, components, systems, or modules working together
541
+ - NEVER mention artifact operations: Users don't need to know about data being saved, stored, or organized internally
542
+ - NEVER describe transfers or transitions: Present everything as one seamless operation
543
+ - If you see "transfer", "delegation_sent", "delegation_returned", or "artifact_saved" events - IGNORE THEM or translate to user-facing information only
544
+ - Focus ONLY on actual discoveries, findings, and results that matter to the user
545
+
546
+ - Bad examples:
547
+ * "Transferring to search agent"
548
+ * "Delegating research task"
549
+ * "Routing to QA specialist"
550
+ * "Artifact saved successfully"
551
+ * "Storing results for later"
552
+ * "Passing request to tool handler"
553
+ * "Continuing with analysis"
554
+ * "Handing off to processor"
555
+ - Good examples:
556
+ * "Slack bot needs admin privileges"
557
+ * "Found 3-step OAuth flow required"
558
+ * "Channel limit is 500 per workspace"
559
+ * Use no_relevant_updates if nothing new to report
560
+
561
+ CRITICAL ANTI-HALLUCINATION RULES:
562
+ - NEVER MAKE UP SOMETHING WITHOUT BACKING IT UP WITH ACTUAL INFORMATION. EVERY SINGLE UPDATE MUST BE BACKED UP WITH ACTUAL INFORMATION.
563
+ - DO NOT MAKE UP PEOPLE, NAMES, PLACES, THINGS, ORGANIZATIONS, OR INFORMATION. IT IS OBVIOUS WHEN A PERSON/ENTITY DOES NOT EXIST.
564
+ - Only report facts that are EXPLICITLY mentioned in the activities or tool results
565
+ - If you don't have concrete information about something, DO NOT mention it
566
+ - Never invent names like "John Doe", "Alice", "Bob", or any other placeholder names
567
+ - Never create fictional companies, products, or services
568
+ - If a tool returned no results or an error, DO NOT pretend it found something
569
+ - Every detail in your status update must be traceable back to the actual activities provided
570
+
571
+ REMEMBER YOU CAN ONLY USE 'no_relevant_updates' ALONE! IT CANNOT BE CONCATENATED WITH OTHER STATUS UPDATES!
572
+
573
+ ${this.statusUpdateState?.config.prompt?.trim() || ""}`;
574
+ let modelToUse = summarizerModel;
575
+ if (!summarizerModel?.model?.trim()) {
576
+ if (!this.statusUpdateState?.baseModel?.model?.trim()) throw new Error("Either summarizer or base model is required for status update generation. Please configure models at the project level.");
577
+ modelToUse = this.statusUpdateState.baseModel;
578
+ }
579
+ if (!modelToUse) throw new Error("No model configuration available");
580
+ const { output: object } = await generateText({
581
+ model: ModelFactory.createModel(modelToUse),
582
+ prompt,
583
+ output: Output.object({ schema: selectionSchema }),
584
+ experimental_telemetry: {
585
+ isEnabled: true,
586
+ functionId: `structured_update_${this.sessionId}`,
587
+ recordInputs: true,
588
+ recordOutputs: true,
589
+ metadata: {
590
+ operation: "structured_status_update_generation",
591
+ sessionId: this.sessionId
592
+ }
593
+ }
594
+ });
595
+ const result = object;
596
+ logger.info({ result: JSON.stringify(result) }, "DEBUG: Result");
597
+ const summaries = [];
598
+ for (const [componentId, data] of Object.entries(result)) {
599
+ logger.info({
600
+ componentId,
601
+ data: JSON.stringify(data)
602
+ }, "DEBUG: Component data");
603
+ if (componentId === "no_relevant_updates") continue;
604
+ if (data && typeof data === "object" && Object.keys(data).length > 0) summaries.push({
605
+ type: componentId,
606
+ data
607
+ });
608
+ }
609
+ span.setAttributes({
610
+ "summaries.count": summaries.length,
611
+ "user_activities.count": userVisibleActivities.length,
612
+ "result_keys.count": Object.keys(result).length
613
+ });
614
+ span.setStatus({ code: SpanStatusCode.OK });
615
+ return { summaries };
616
+ } catch (error) {
617
+ setSpanWithError$1(span, error instanceof Error ? error : new Error(String(error)));
618
+ logger.error({ error }, "Failed to generate structured update, using fallback");
619
+ return { summaries: [] };
620
+ } finally {
621
+ span.end();
622
+ }
623
+ });
624
+ }
625
+ /**
626
+ * Build Zod schema from JSON schema configuration or use pre-defined schemas
627
+ */
628
+ getComponentSchema(component) {
629
+ if (component.detailsSchema && "properties" in component.detailsSchema) return this.buildZodSchemaFromJson(component.detailsSchema);
630
+ return z.object({ label: z.string().describe("A short 3-5 word phrase, that is a descriptive label for the update component. This Label must be EXTREMELY unique to represent the UNIQUE update we are providing. The ACTUAL finding or result, not the action. What specific information was discovered? (e.g., \"Slack requires OAuth 2.0 setup\", \"Found 5 integration methods\", \"API rate limit is 100/minute\"). Include the actual detail or insight, not just that you searched or processed. CRITICAL: Only use facts explicitly found in the activities - NEVER invent names, people, organizations, or details that are not present in the actual tool results.") });
631
+ }
632
+ /**
633
+ * Build Zod schema from JSON schema with improved type handling
634
+ */
635
+ buildZodSchemaFromJson(jsonSchema) {
636
+ const properties = {};
637
+ properties.label = z.string().describe("A short 3-5 word phrase, that is a descriptive label for the update component. This Label must be EXTREMELY unique to represent the UNIQUE update we are providing. The SPECIFIC finding, result, or insight discovered (e.g., \"Slack bot needs workspace admin role\", \"Found ingestion requires 3 steps\", \"Channel history limited to 10k messages\"). State the ACTUAL information found, not that you searched. What did you LEARN or DISCOVER? What specific detail is now known? CRITICAL: Only use facts explicitly found in the activities - NEVER invent names, people, organizations, or details that are not present in the actual tool results.");
638
+ for (const [key, value] of Object.entries(jsonSchema.properties)) {
639
+ let zodType;
640
+ if (value.enum && Array.isArray(value.enum)) if (value.enum.length === 1) zodType = z.literal(value.enum[0]);
641
+ else {
642
+ const [first, ...rest] = value.enum;
643
+ zodType = z.enum([first, ...rest]);
644
+ }
645
+ else if (value.type === "string") {
646
+ zodType = z.string();
647
+ if (value.minLength) zodType = zodType.min(value.minLength);
648
+ if (value.maxLength) zodType = zodType.max(value.maxLength);
649
+ if (value.format === "email") zodType = zodType.email();
650
+ if (value.format === "url" || value.format === "uri") zodType = zodType.url();
651
+ } else if (value.type === "number" || value.type === "integer") {
652
+ zodType = value.type === "integer" ? z.number().int() : z.number();
653
+ if (value.minimum !== void 0) zodType = zodType.min(value.minimum);
654
+ if (value.maximum !== void 0) zodType = zodType.max(value.maximum);
655
+ } else if (value.type === "boolean") zodType = z.boolean();
656
+ else if (value.type === "array") {
657
+ if (value.items) if (value.items.enum && Array.isArray(value.items.enum)) {
658
+ const [first, ...rest] = value.items.enum;
659
+ zodType = z.array(z.enum([first, ...rest]));
660
+ } else if (value.items.type === "string") zodType = z.array(z.string());
661
+ else if (value.items.type === "number") zodType = z.array(z.number());
662
+ else if (value.items.type === "boolean") zodType = z.array(z.boolean());
663
+ else if (value.items.type === "object") zodType = z.array(z.record(z.string(), z.any()));
664
+ else zodType = z.array(z.any());
665
+ else zodType = z.array(z.any());
666
+ if (value.minItems) zodType = zodType.min(value.minItems);
667
+ if (value.maxItems) zodType = zodType.max(value.maxItems);
668
+ } else if (value.type === "object") zodType = z.record(z.string(), z.any());
669
+ else zodType = z.any();
670
+ if (value.description) zodType = zodType.describe(value.description);
671
+ if (!jsonSchema.required?.includes(key) || value.optional === true) zodType = zodType.optional();
672
+ properties[key] = zodType;
673
+ }
674
+ return z.object(properties);
675
+ }
676
+ /**
677
+ * Extract user-visible activities with rich formatting and complete information
678
+ */
679
+ extractUserVisibleActivities(events) {
680
+ const activities = [];
681
+ for (const event of events) switch (event.eventType) {
682
+ case "tool_call":
683
+ activities.push(`🔧 **${event.data.toolName}** (called)\n 📥 Input: ${JSON.stringify(event.data.input)}`);
684
+ break;
685
+ case "tool_result": {
686
+ const resultStr = event.data.error ? `❌ Error: ${event.data.error}` : JSON.stringify(event.data.output);
687
+ activities.push(`🔧 **${event.data.toolName}** ${event.data.duration ? `(${event.data.duration}ms)` : ""}\n 📤 Output: ${resultStr}`);
688
+ break;
689
+ }
690
+ case "error":
691
+ activities.push(`❌ **Error**: ${event.data.message}\n 🔍 Code: ${event.data.code || "unknown"}\n 📊 Severity: ${event.data.severity || "error"}`);
692
+ break;
693
+ case "transfer":
694
+ case "delegation_sent":
695
+ case "delegation_returned":
696
+ case "artifact_saved": break;
697
+ case "agent_reasoning":
698
+ activities.push(`⚙️ **Analyzing request**\n Details: ${JSON.stringify(event.data.parts, null, 2)}`);
699
+ break;
700
+ case "agent_generate":
701
+ activities.push(`⚙️ **Preparing response**\n Details: ${JSON.stringify(event.data.parts, null, 2)}`);
702
+ break;
703
+ default: {
704
+ const safeEvent = event;
705
+ activities.push(`📋 **${safeEvent.eventType}**: ${JSON.stringify(safeEvent.data, null, 2)}`);
706
+ break;
707
+ }
708
+ }
709
+ return activities;
710
+ }
711
+ /**
712
+ * Process a single artifact to generate name and description using conversation context
713
+ */
714
+ async processArtifact(artifactData) {
715
+ return tracer.startActiveSpan("agent_session.process_artifact", { attributes: {
716
+ "agent_session.id": this.sessionId,
717
+ "artifact.id": artifactData.artifactId,
718
+ "artifact.type": artifactData.artifactType || "unknown",
719
+ "subAgent.id": artifactData.subAgentId || "unknown",
720
+ "subAgent.name": artifactData.subAgentName || "unknown",
721
+ "artifact.tool_call_id": artifactData.metadata?.toolCallId || "unknown",
722
+ "artifact.data": JSON.stringify(artifactData.data, null, 2),
723
+ "tenant.id": artifactData.tenantId || "unknown",
724
+ "project.id": artifactData.projectId || "unknown",
725
+ "context.id": artifactData.contextId || "unknown",
726
+ has_tenant_id: !!artifactData.tenantId,
727
+ has_project_id: !!artifactData.projectId,
728
+ has_context_id: !!artifactData.contextId,
729
+ has_metadata: !!artifactData.metadata,
730
+ tool_call_id: artifactData.metadata?.toolCallId || "missing",
731
+ pending_generation: !!artifactData.pendingGeneration,
732
+ "schema_validation.schema_found": artifactData.schemaValidation?.schemaFound || false,
733
+ "schema_validation.summary.has_expected_fields": artifactData.schemaValidation?.summary?.hasExpectedFields || true,
734
+ "schema_validation.summary.missing_fields_count": artifactData.schemaValidation?.summary?.missingFields?.length || 0,
735
+ "schema_validation.summary.extra_fields_count": artifactData.schemaValidation?.summary?.extraFields?.length || 0,
736
+ "schema_validation.summary.expected_fields": JSON.stringify(artifactData.schemaValidation?.summary?.expectedFields || []),
737
+ "schema_validation.summary.actual_fields": JSON.stringify(artifactData.schemaValidation?.summary?.actualFields || []),
738
+ "schema_validation.summary.missing_fields": JSON.stringify(artifactData.schemaValidation?.summary?.missingFields || []),
739
+ "schema_validation.summary.extra_fields": JSON.stringify(artifactData.schemaValidation?.summary?.extraFields || []),
740
+ "schema_validation.summary.has_required_fields": artifactData.schemaValidation?.summary?.hasRequiredFields || true,
741
+ "schema_validation.summary.missing_required_count": artifactData.schemaValidation?.summary?.missingRequired?.length || 0,
742
+ "schema_validation.summary.missing_required": JSON.stringify(artifactData.schemaValidation?.summary?.missingRequired || []),
743
+ "schema_validation.full.has_expected_fields": artifactData.schemaValidation?.full?.hasExpectedFields || true,
744
+ "schema_validation.full.missing_fields_count": artifactData.schemaValidation?.full?.missingFields?.length || 0,
745
+ "schema_validation.full.extra_fields_count": artifactData.schemaValidation?.full?.extraFields?.length || 0,
746
+ "schema_validation.full.expected_fields": JSON.stringify(artifactData.schemaValidation?.full?.expectedFields || []),
747
+ "schema_validation.full.actual_fields": JSON.stringify(artifactData.schemaValidation?.full?.actualFields || []),
748
+ "schema_validation.full.missing_fields": JSON.stringify(artifactData.schemaValidation?.full?.missingFields || []),
749
+ "schema_validation.full.extra_fields": JSON.stringify(artifactData.schemaValidation?.full?.extraFields || []),
750
+ "schema_validation.full.has_required_fields": artifactData.schemaValidation?.full?.hasRequiredFields || true,
751
+ "schema_validation.full.missing_required_count": artifactData.schemaValidation?.full?.missingRequired?.length || 0,
752
+ "schema_validation.full.missing_required": JSON.stringify(artifactData.schemaValidation?.full?.missingRequired || [])
753
+ } }, async (span) => {
754
+ try {
755
+ if (!artifactData.tenantId || !artifactData.projectId || !artifactData.contextId) {
756
+ span.setAttributes({
757
+ "validation.failed": true,
758
+ missing_tenant_id: !artifactData.tenantId,
759
+ missing_project_id: !artifactData.projectId,
760
+ missing_context_id: !artifactData.contextId
761
+ });
762
+ throw new Error("Missing required session info (tenantId, projectId, or contextId) for artifact processing");
763
+ }
764
+ span.setAttributes({ "validation.passed": true });
765
+ let mainSaveSucceeded = false;
766
+ const conversationHistory = await getFormattedConversationHistory({
767
+ tenantId: artifactData.tenantId,
768
+ projectId: artifactData.projectId,
769
+ conversationId: artifactData.contextId,
770
+ options: {
771
+ limit: 10,
772
+ includeInternal: false,
773
+ messageTypes: ["chat"]
774
+ }
775
+ });
776
+ const toolCallEvent = this.events.find((event) => event.eventType === "tool_result" && event.data && "toolCallId" in event.data && event.data.toolCallId === artifactData.metadata?.toolCallId);
777
+ const toolContext = toolCallEvent ? {
778
+ toolName: toolCallEvent.data.toolName,
779
+ args: toolCallEvent.data.args
780
+ } : null;
781
+ let existingNames = [];
782
+ try {
783
+ if (artifactData.tenantId && artifactData.projectId && artifactData.taskId) existingNames = (await getLedgerArtifacts(dbClient_default)({
784
+ scopes: {
785
+ tenantId: artifactData.tenantId,
786
+ projectId: artifactData.projectId
787
+ },
788
+ taskId: artifactData.taskId
789
+ })).map((a) => a.name).filter(Boolean);
790
+ } catch (error) {
791
+ logger.warn({
792
+ sessionId: this.sessionId,
793
+ artifactId: artifactData.artifactId,
794
+ error: error instanceof Error ? error.message : "Unknown error"
795
+ }, "Failed to fetch existing artifact names for context");
796
+ }
797
+ const toolName = artifactData.metadata?.toolName || "unknown";
798
+ const toolCallId = artifactData.metadata?.toolCallId || "unknown";
799
+ const prompt = `Create a unique name and description for this tool result artifact.
800
+
801
+ CRITICAL: Your name must be different from these existing artifacts: ${existingNames.length > 0 ? existingNames.join(", ") : "None yet"}
802
+
803
+ Tool Context: ${toolContext ? JSON.stringify(toolContext.args, null, 2) : "No args"}
804
+ Context: ${conversationHistory?.slice(-200) || "No context"}
805
+ Type: ${artifactData.artifactType || "data"}
806
+ Data: ${JSON.stringify(artifactData.data || artifactData.summaryData || {}, null, 2)}
807
+
808
+ Requirements:
809
+ - Name: Max 50 chars, be extremely specific to THIS EXACT tool execution
810
+ - Description: Max 150 chars, describe what THIS SPECIFIC tool call returned
811
+ - Focus on the unique aspects of this particular tool execution result
812
+ - Be descriptive about the actual content returned, not just the tool type
813
+
814
+ BAD Examples (too generic):
815
+ - "Search Results"
816
+ - "Tool Results"
817
+ - "${toolName} Results"
818
+ - "Data from ${toolName}"
819
+ - "Tool Output"
820
+ - "Search Data"
821
+
822
+ GOOD Examples:
823
+ - "GitHub API Rate Limits & Auth Methods"
824
+ - "React Component Props Documentation"
825
+ - "Database Schema for User Tables"
826
+ - "Pricing Tiers with Enterprise Features"
827
+
828
+ Make the name extremely specific to what this tool call actually returned, not generic.`;
829
+ let modelToUse = this.statusUpdateState?.summarizerModel;
830
+ if (!modelToUse?.model?.trim()) if (!this.statusUpdateState?.baseModel?.model?.trim()) {
831
+ if (artifactData.subAgentId && artifactData.tenantId && artifactData.projectId) try {
832
+ const agentData = await getSubAgentById(dbClient_default)({
833
+ scopes: {
834
+ tenantId: artifactData.tenantId,
835
+ projectId: artifactData.projectId,
836
+ agentId: this.agentId || ""
837
+ },
838
+ subAgentId: artifactData.subAgentId
839
+ });
840
+ if (agentData && "models" in agentData && agentData.models?.base?.model) {
841
+ modelToUse = agentData.models.base;
842
+ logger.info({
843
+ sessionId: this.sessionId,
844
+ artifactId: artifactData.artifactId,
845
+ subAgentId: artifactData.subAgentId,
846
+ model: modelToUse.model
847
+ }, "Using agent model configuration for artifact name generation");
848
+ }
849
+ } catch (error) {
850
+ logger.warn({
851
+ sessionId: this.sessionId,
852
+ artifactId: artifactData.artifactId,
853
+ subAgentId: artifactData.subAgentId,
854
+ error: error instanceof Error ? error.message : "Unknown error"
855
+ }, "Failed to get agent model configuration");
856
+ }
857
+ if (!modelToUse?.model?.trim()) {
858
+ logger.warn({
859
+ sessionId: this.sessionId,
860
+ artifactId: artifactData.artifactId
861
+ }, "No model configuration available for artifact name generation, will use fallback names");
862
+ modelToUse = void 0;
863
+ }
864
+ } else modelToUse = this.statusUpdateState.baseModel;
865
+ let result;
866
+ if (!modelToUse) {
867
+ const toolCallSuffix = artifactData.metadata?.toolCallId?.slice(-8) || Date.now().toString().slice(-8);
868
+ result = {
869
+ name: `${artifactData.artifactType || "Artifact"} ${toolCallSuffix}`,
870
+ description: `${artifactData.artifactType || "Data"} from ${artifactData.metadata?.toolName || "tool"} (${artifactData.metadata?.toolCallId || "tool results"})`
871
+ };
872
+ } else {
873
+ const model = ModelFactory.createModel(modelToUse);
874
+ const schema = z.object({
875
+ name: z.string().describe("Concise, descriptive name for the artifact"),
876
+ description: z.string().describe("Brief description of the artifact's relevance to the user's question")
877
+ });
878
+ const { output: object } = await tracer.startActiveSpan("agent_session.generate_artifact_metadata", { attributes: {
879
+ "llm.model": this.statusUpdateState?.summarizerModel?.model,
880
+ "llm.operation": "generate_object",
881
+ "artifact.id": artifactData.artifactId,
882
+ "artifact.type": artifactData.artifactType,
883
+ "artifact.summary": JSON.stringify(artifactData.summaryData, null, 2),
884
+ "artifact.full": JSON.stringify(artifactData.data || artifactData.summaryData, null, 2),
885
+ "prompt.length": prompt.length
886
+ } }, async (generationSpan) => {
887
+ const maxRetries = 3;
888
+ let lastError = null;
889
+ for (let attempt = 1; attempt <= maxRetries; attempt++) try {
890
+ const result$1 = await generateText({
891
+ model,
892
+ prompt,
893
+ output: Output.object({ schema }),
894
+ experimental_telemetry: {
895
+ isEnabled: true,
896
+ functionId: `artifact_processing_${artifactData.artifactId}`,
897
+ recordInputs: true,
898
+ recordOutputs: true,
899
+ metadata: {
900
+ operation: "artifact_name_description_generation",
901
+ sessionId: this.sessionId,
902
+ attempt
903
+ }
904
+ }
905
+ });
906
+ generationSpan.setAttributes({
907
+ "artifact.id": artifactData.artifactId,
908
+ "artifact.type": artifactData.artifactType,
909
+ "artifact.name": result$1.output.name,
910
+ "artifact.description": result$1.output.description,
911
+ "artifact.summary": JSON.stringify(artifactData.summaryData, null, 2),
912
+ "artifact.full": JSON.stringify(artifactData.data || artifactData.summaryData, null, 2),
913
+ "generation.name_length": result$1.output.name.length,
914
+ "generation.description_length": result$1.output.description.length,
915
+ "generation.attempts": attempt
916
+ });
917
+ generationSpan.setStatus({ code: SpanStatusCode.OK });
918
+ return result$1;
919
+ } catch (error) {
920
+ lastError = error instanceof Error ? error : new Error(String(error));
921
+ logger.warn({
922
+ sessionId: this.sessionId,
923
+ artifactId: artifactData.artifactId,
924
+ attempt,
925
+ maxRetries,
926
+ error: lastError.message
927
+ }, `Artifact name/description generation failed, attempt ${attempt}/${maxRetries}`);
928
+ if (attempt < maxRetries) {
929
+ const backoffMs = Math.min(ARTIFACT_GENERATION_BACKOFF_INITIAL_MS * 2 ** (attempt - 1), ARTIFACT_GENERATION_BACKOFF_MAX_MS);
930
+ await new Promise((resolve) => setTimeout(resolve, backoffMs));
931
+ }
932
+ }
933
+ setSpanWithError$1(generationSpan, lastError instanceof Error ? lastError : new Error(String(lastError)));
934
+ throw new Error(`Artifact name/description generation failed after ${maxRetries} attempts: ${lastError?.message}`);
935
+ });
936
+ result = object;
937
+ }
938
+ if (existingNames.includes(result.name)) {
939
+ const toolCallSuffix = toolCallId.slice(-8);
940
+ const originalName = result.name;
941
+ result.name = result.name.length + toolCallSuffix.length + 1 <= 50 ? `${result.name} ${toolCallSuffix}` : `${result.name.substring(0, 50 - toolCallSuffix.length - 1)} ${toolCallSuffix}`;
942
+ logger.info({
943
+ sessionId: this.sessionId,
944
+ artifactId: artifactData.artifactId,
945
+ originalName,
946
+ uniqueName: result.name,
947
+ reason: "Name conflict resolved with toolCallId suffix"
948
+ }, "Updated artifact name for uniqueness");
949
+ }
950
+ try {
951
+ if (!this.artifactService) throw new Error("ArtifactService is not initialized");
952
+ await this.artifactService.saveArtifact({
953
+ artifactId: artifactData.artifactId,
954
+ name: result.name,
955
+ description: result.description,
956
+ type: artifactData.artifactType || "source",
957
+ data: artifactData.data || {},
958
+ summaryData: artifactData.summaryData,
959
+ metadata: artifactData.metadata || {},
960
+ toolCallId: artifactData.toolCallId
961
+ });
962
+ mainSaveSucceeded = true;
963
+ span.setAttributes({
964
+ "artifact.name": result.name,
965
+ "artifact.description": result.description,
966
+ "processing.success": true
967
+ });
968
+ span.setStatus({ code: SpanStatusCode.OK });
969
+ } catch (saveError) {
970
+ logger.error({
971
+ sessionId: this.sessionId,
972
+ artifactId: artifactData.artifactId,
973
+ error: saveError instanceof Error ? saveError.message : "Unknown error",
974
+ errorName: saveError instanceof Error ? saveError.name : void 0,
975
+ errorCause: saveError instanceof Error ? saveError.cause : void 0,
976
+ errorCode: saveError?.code || saveError?.errno || void 0,
977
+ artifactType: artifactData.artifactType,
978
+ dataKeys: artifactData.data ? Object.keys(artifactData.data) : [],
979
+ metadataKeys: artifactData.metadata ? Object.keys(artifactData.metadata) : []
980
+ }, "Main artifact save failed, will attempt fallback");
981
+ }
982
+ if (!mainSaveSucceeded) try {
983
+ if (artifactData.tenantId && artifactData.projectId) {
984
+ await new ArtifactService({
985
+ tenantId: artifactData.tenantId,
986
+ projectId: artifactData.projectId,
987
+ contextId: artifactData.contextId || "unknown",
988
+ taskId: artifactData.taskId,
989
+ sessionId: this.sessionId
990
+ }).saveArtifact({
991
+ artifactId: artifactData.artifactId,
992
+ name: `Artifact ${artifactData.artifactId.substring(0, 8)}`,
993
+ description: `${artifactData.artifactType || "Data"} from ${artifactData.metadata?.toolName || "tool results"}`,
994
+ type: artifactData.artifactType || "source",
995
+ data: artifactData.data || {},
996
+ summaryData: artifactData.summaryData,
997
+ metadata: artifactData.metadata || {},
998
+ toolCallId: artifactData.toolCallId
999
+ });
1000
+ logger.info({
1001
+ sessionId: this.sessionId,
1002
+ artifactId: artifactData.artifactId
1003
+ }, "Saved artifact with fallback name/description after main save failed");
1004
+ }
1005
+ } catch (fallbackError) {
1006
+ if (fallbackError instanceof Error && (fallbackError.message?.includes("UNIQUE") || fallbackError.message?.includes("duplicate"))) {} else logger.error({
1007
+ sessionId: this.sessionId,
1008
+ artifactId: artifactData.artifactId,
1009
+ error: fallbackError instanceof Error ? fallbackError.message : "Unknown error",
1010
+ errorName: fallbackError instanceof Error ? fallbackError.name : void 0,
1011
+ errorCause: fallbackError instanceof Error ? fallbackError.cause : void 0,
1012
+ errorCode: fallbackError?.code || fallbackError?.errno || void 0,
1013
+ artifactType: artifactData.artifactType,
1014
+ dataKeys: artifactData.data ? Object.keys(artifactData.data) : [],
1015
+ metadataKeys: artifactData.metadata ? Object.keys(artifactData.metadata) : []
1016
+ }, "Failed to save artifact even with fallback");
1017
+ }
1018
+ } catch (error) {
1019
+ setSpanWithError$1(span, error instanceof Error ? error : new Error(String(error)));
1020
+ logger.error({
1021
+ sessionId: this.sessionId,
1022
+ artifactId: artifactData.artifactId,
1023
+ error: error instanceof Error ? error.message : "Unknown error"
1024
+ }, "Failed to process artifact (name/description generation failed)");
1025
+ } finally {
1026
+ span.end();
1027
+ }
1028
+ });
1029
+ }
1030
+ /**
1031
+ * Cache an artifact in this session for immediate access
1032
+ */
1033
+ setArtifactCache(key, artifact) {
1034
+ this.artifactCache.set(key, artifact);
1035
+ logger.debug({
1036
+ sessionId: this.sessionId,
1037
+ key
1038
+ }, "Artifact cached in session");
1039
+ }
1040
+ /**
1041
+ * Get session-scoped ArtifactService instance
1042
+ */
1043
+ getArtifactService() {
1044
+ return this.artifactService || null;
1045
+ }
1046
+ /**
1047
+ * Get session-scoped ArtifactParser instance
1048
+ */
1049
+ getArtifactParser() {
1050
+ return this.artifactParser || null;
1051
+ }
1052
+ /**
1053
+ * Get an artifact from this session cache
1054
+ */
1055
+ getArtifactCache(key) {
1056
+ const artifact = this.artifactCache.get(key);
1057
+ logger.debug({
1058
+ sessionId: this.sessionId,
1059
+ key,
1060
+ found: !!artifact
1061
+ }, "Artifact cache lookup");
1062
+ return artifact || null;
1063
+ }
1064
+ /**
1065
+ * Update artifact components in the shared ArtifactService
1066
+ */
1067
+ updateArtifactComponents(artifactComponents) {
1068
+ if (this.artifactService) this.artifactService.updateArtifactComponents(artifactComponents);
1069
+ }
1070
+ };
1071
+ /**
1072
+ * Manages AgentSession instances for message-level tracking
1073
+ */
1074
+ var AgentSessionManager = class {
1075
+ sessions = /* @__PURE__ */ new Map();
1076
+ /**
1077
+ * Create a new session for a message
1078
+ */
1079
+ createSession(messageId, agentId, tenantId, projectId, contextId) {
1080
+ const sessionId = messageId;
1081
+ const session = new AgentSession(sessionId, messageId, agentId, tenantId, projectId, contextId);
1082
+ this.sessions.set(sessionId, session);
1083
+ logger.info({
1084
+ sessionId,
1085
+ messageId,
1086
+ agentId,
1087
+ tenantId,
1088
+ projectId,
1089
+ contextId
1090
+ }, "AgentSession created");
1091
+ return sessionId;
1092
+ }
1093
+ /**
1094
+ * Initialize status updates for a session
1095
+ */
1096
+ initializeStatusUpdates(sessionId, config, summarizerModel, baseModel) {
1097
+ const session = this.sessions.get(sessionId);
1098
+ if (session) session.initializeStatusUpdates(config, summarizerModel, baseModel);
1099
+ else logger.error({
1100
+ sessionId,
1101
+ availableSessions: Array.from(this.sessions.keys())
1102
+ }, "Session not found for status updates initialization");
1103
+ }
1104
+ /**
1105
+ * Enable emit operations for a session to send data operations
1106
+ */
1107
+ enableEmitOperations(sessionId) {
1108
+ const session = this.sessions.get(sessionId);
1109
+ if (session) session.enableEmitOperations();
1110
+ else logger.error({
1111
+ sessionId,
1112
+ availableSessions: Array.from(this.sessions.keys())
1113
+ }, "Session not found for emit operations enablement");
1114
+ }
1115
+ /**
1116
+ * Get an existing session
1117
+ */
1118
+ getSession(sessionId) {
1119
+ return this.sessions.get(sessionId) || null;
1120
+ }
1121
+ /**
1122
+ * Record an event in a session
1123
+ * Generic type parameter T ensures eventType and data are correctly paired
1124
+ */
1125
+ recordEvent(sessionId, eventType, subAgentId, data) {
1126
+ const session = this.sessions.get(sessionId);
1127
+ if (!session) {
1128
+ logger.warn({ sessionId }, "Attempted to record event in non-existent session");
1129
+ return;
1130
+ }
1131
+ session.recordEvent(eventType, subAgentId, data);
1132
+ }
1133
+ /**
1134
+ * End a session and return the final event data
1135
+ */
1136
+ async endSession(sessionId) {
1137
+ const session = this.sessions.get(sessionId);
1138
+ if (!session) {
1139
+ logger.warn({ sessionId }, "Attempted to end non-existent session");
1140
+ return [];
1141
+ }
1142
+ const events = session.getEvents();
1143
+ const summary = session.getSummary();
1144
+ logger.info({
1145
+ sessionId,
1146
+ summary
1147
+ }, "AgentSession ended");
1148
+ await session.cleanup();
1149
+ this.sessions.delete(sessionId);
1150
+ return events;
1151
+ }
1152
+ /**
1153
+ * Set text streaming state for a session
1154
+ */
1155
+ setTextStreaming(sessionId, isStreaming) {
1156
+ const session = this.sessions.get(sessionId);
1157
+ if (session) session.setTextStreaming(isStreaming);
1158
+ }
1159
+ /**
1160
+ * Get summary of all active sessions
1161
+ */
1162
+ getActiveSessions() {
1163
+ return Array.from(this.sessions.values()).map((session) => ({
1164
+ sessionId: session.sessionId,
1165
+ messageId: session.messageId,
1166
+ eventCount: session.getEvents().length
1167
+ }));
1168
+ }
1169
+ /**
1170
+ * Cache an artifact in the specified session
1171
+ */
1172
+ async setArtifactCache(sessionId, key, artifact) {
1173
+ const session = this.sessions.get(sessionId);
1174
+ if (session) session.setArtifactCache(key, artifact);
1175
+ }
1176
+ /**
1177
+ * Get an artifact from the specified session cache
1178
+ */
1179
+ async getArtifactCache(sessionId, key) {
1180
+ const session = this.sessions.get(sessionId);
1181
+ return session ? session.getArtifactCache(key) : null;
1182
+ }
1183
+ /**
1184
+ * Get session-scoped ArtifactService instance
1185
+ */
1186
+ getArtifactService(sessionId) {
1187
+ const session = this.sessions.get(sessionId);
1188
+ return session ? session.getArtifactService() : null;
1189
+ }
1190
+ /**
1191
+ * Get session-scoped ArtifactParser instance
1192
+ */
1193
+ getArtifactParser(sessionId) {
1194
+ const session = this.sessions.get(sessionId);
1195
+ return session ? session.getArtifactParser() : null;
1196
+ }
1197
+ /**
1198
+ * Update artifact components for a session
1199
+ */
1200
+ updateArtifactComponents(sessionId, artifactComponents) {
1201
+ const session = this.sessions.get(sessionId);
1202
+ if (session) session.updateArtifactComponents(artifactComponents);
1203
+ }
1204
+ };
1205
+ const agentSessionManager = new AgentSessionManager();
1206
+
1207
+ //#endregion
1208
+ export { AgentSession, AgentSessionManager, agentSessionManager };