@inkeep/agents-run-api 0.39.5 → 0.40.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 +560 -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 +266 -0
  18. package/dist/agents/Agent.js +1927 -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 +521 -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 +39 -0
  52. package/dist/handlers/executionHandler.js +456 -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 +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 +612 -0
  79. package/dist/services/BaseCompressor.d.ts +183 -0
  80. package/dist/services/BaseCompressor.js +504 -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} +1 -2
  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 +4 -20
  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,522 @@
1
+ import { getLogger } from "../logger.js";
2
+ import dbClient_default from "./db/dbClient.js";
3
+ import { CONVERSATION_ARTIFACTS_LIMIT, CONVERSATION_HISTORY_DEFAULT_LIMIT as CONVERSATION_HISTORY_DEFAULT_LIMIT$1 } from "../constants/execution-limits/index.js";
4
+ import { getCompressionConfigForModel } from "../utils/model-context-utils.js";
5
+ import { ConversationCompressor } from "../services/ConversationCompressor.js";
6
+ import { CONVERSATION_HISTORY_MAX_OUTPUT_TOKENS_DEFAULT, createMessage, generateId, getConversationHistory } from "@inkeep/agents-core";
7
+
8
+ //#region src/data/conversations.ts
9
+ const logger = getLogger("conversations");
10
+ const compressionLocks = /* @__PURE__ */ new Map();
11
+ /**
12
+ * Creates default conversation history configuration
13
+ * @param mode - The conversation history mode ('full' | 'scoped' | 'none')
14
+ * @returns Default AgentConversationHistoryConfig
15
+ */
16
+ function createDefaultConversationHistoryConfig(mode = "full") {
17
+ return {
18
+ mode,
19
+ limit: CONVERSATION_HISTORY_DEFAULT_LIMIT$1,
20
+ includeInternal: true,
21
+ messageTypes: ["chat", "tool-result"],
22
+ maxOutputTokens: CONVERSATION_HISTORY_MAX_OUTPUT_TOKENS_DEFAULT
23
+ };
24
+ }
25
+ /**
26
+ * Extracts text content from A2A Message parts array
27
+ */
28
+ function extractA2AMessageText(parts) {
29
+ return parts.filter((part) => part.kind === "text" && part.text).map((part) => part.text).join("");
30
+ }
31
+ /**
32
+ * Saves the result of an A2A client sendMessage call as a conversation message
33
+ * @param response - The response from a2aClient.sendMessage()
34
+ * @param params - Parameters for saving the message
35
+ * @returns The saved message or null if no text content was found
36
+ */
37
+ async function saveA2AMessageResponse(response, params) {
38
+ if (response.error) throw new Error(response.error.message);
39
+ let messageText = "";
40
+ if (response.result.kind === "message") messageText = extractA2AMessageText(response.result.parts);
41
+ else if (response.result.kind === "task") {
42
+ if (response.result.artifacts && response.result.artifacts.length > 0) {
43
+ const firstArtifact = response.result.artifacts[0];
44
+ if (firstArtifact.parts) messageText = extractA2AMessageText(firstArtifact.parts);
45
+ }
46
+ } else if (typeof response.result === "string") messageText = response.result;
47
+ if (!messageText || messageText.trim() === "") return null;
48
+ return await createMessage(dbClient_default)({
49
+ id: generateId(),
50
+ tenantId: params.tenantId,
51
+ projectId: params.projectId,
52
+ conversationId: params.conversationId,
53
+ role: "agent",
54
+ content: { text: messageText },
55
+ visibility: params.visibility,
56
+ messageType: params.messageType,
57
+ fromSubAgentId: params.fromSubAgentId,
58
+ toSubAgentId: params.toSubAgentId,
59
+ fromExternalAgentId: params.fromExternalAgentId,
60
+ toExternalAgentId: params.toExternalAgentId,
61
+ a2aTaskId: params.a2aTaskId,
62
+ a2aSessionId: params.a2aSessionId,
63
+ metadata: params.metadata
64
+ });
65
+ }
66
+ /**
67
+ * Applies filtering based on agent, task, or both criteria
68
+ * Returns the filtered messages array
69
+ */
70
+ async function getScopedHistory({ tenantId, projectId, conversationId, filters, options }) {
71
+ try {
72
+ const allMessages = await getConversationHistory(dbClient_default)({
73
+ scopes: {
74
+ tenantId,
75
+ projectId
76
+ },
77
+ conversationId,
78
+ options: {
79
+ ...options,
80
+ limit: 1e4,
81
+ includeInternal: true,
82
+ maxOutputTokens: void 0
83
+ }
84
+ });
85
+ const compressionSummaries = allMessages.filter((msg) => msg.messageType === "compression_summary" && msg.metadata?.compressionType === "conversation_history");
86
+ const latestCompressionSummary = compressionSummaries.length > 0 ? compressionSummaries.reduce((latest, current) => new Date(current.createdAt) > new Date(latest.createdAt) ? current : latest) : null;
87
+ let messages;
88
+ if (latestCompressionSummary) {
89
+ const summaryDate = new Date(latestCompressionSummary.createdAt);
90
+ messages = [latestCompressionSummary, ...allMessages.filter((msg) => new Date(msg.createdAt) > summaryDate && msg.messageType !== "compression_summary")];
91
+ logger.debug({
92
+ conversationId,
93
+ latestCompressionSummaryId: latestCompressionSummary.id,
94
+ summaryDate: summaryDate.toISOString(),
95
+ messagesAfterCompression: messages.length - 1,
96
+ totalMessages: allMessages.length
97
+ }, "Retrieved conversation with compression summary");
98
+ } else {
99
+ messages = allMessages;
100
+ logger.debug({
101
+ conversationId,
102
+ totalMessages: messages.length
103
+ }, "Retrieved conversation without compression summary");
104
+ }
105
+ if (!filters || !filters.subAgentId && !filters.taskId && !filters.delegationId && filters.isDelegated === void 0) return messages;
106
+ return messages.filter((msg) => {
107
+ if (msg.role === "user") return true;
108
+ let matchesAgent = true;
109
+ let matchesTask = true;
110
+ let matchesDelegation = true;
111
+ if (filters.subAgentId) matchesAgent = msg.role === "agent" && msg.visibility === "user-facing" || msg.toSubAgentId === filters.subAgentId || msg.fromSubAgentId === filters.subAgentId;
112
+ if (filters.taskId) matchesTask = msg.taskId === filters.taskId || msg.a2aTaskId === filters.taskId;
113
+ if (filters.delegationId !== void 0 || filters.isDelegated !== void 0) {
114
+ if (msg.messageType === "tool-result") {
115
+ const messageDelegationId = msg.metadata?.a2a_metadata?.delegationId;
116
+ const messageIsDelegated = msg.metadata?.a2a_metadata?.isDelegated;
117
+ if (filters.delegationId) matchesDelegation = messageDelegationId === filters.delegationId || !messageDelegationId;
118
+ else if (filters.isDelegated === false) matchesDelegation = !messageIsDelegated;
119
+ else if (filters.isDelegated === true) matchesDelegation = messageIsDelegated === true;
120
+ }
121
+ }
122
+ const conditions = [];
123
+ if (filters.subAgentId) conditions.push(matchesAgent);
124
+ if (filters.taskId) conditions.push(matchesTask);
125
+ if (filters.delegationId !== void 0 || filters.isDelegated !== void 0) conditions.push(matchesDelegation);
126
+ return conditions.length === 0 || conditions.every(Boolean);
127
+ });
128
+ } catch (error) {
129
+ console.error("Failed to fetch scoped messages:", error);
130
+ return [];
131
+ }
132
+ }
133
+ /**
134
+ * Get user-facing conversation history (for client display)
135
+ */
136
+ async function getUserFacingHistory(tenantId, projectId, conversationId, limit = CONVERSATION_HISTORY_DEFAULT_LIMIT$1) {
137
+ return await getConversationHistory(dbClient_default)({
138
+ scopes: {
139
+ tenantId,
140
+ projectId
141
+ },
142
+ conversationId,
143
+ options: {
144
+ limit,
145
+ includeInternal: false,
146
+ messageTypes: ["chat"]
147
+ }
148
+ });
149
+ }
150
+ /**
151
+ * Get full conversation context (for agent processing)
152
+ */
153
+ async function getFullConversationContext(tenantId, projectId, conversationId, maxTokens) {
154
+ const defaultConfig = createDefaultConversationHistoryConfig();
155
+ return await getConversationHistory(dbClient_default)({
156
+ scopes: {
157
+ tenantId,
158
+ projectId
159
+ },
160
+ conversationId,
161
+ options: {
162
+ ...defaultConfig,
163
+ limit: 100,
164
+ includeInternal: true,
165
+ maxOutputTokens: maxTokens
166
+ }
167
+ });
168
+ }
169
+ /**
170
+ * Get formatted conversation history for a2a
171
+ */
172
+ async function getFormattedConversationHistory({ tenantId, projectId, conversationId, currentMessage, options, filters, sessionId, summarizerModel }) {
173
+ const conversationHistory = await getScopedHistory({
174
+ tenantId,
175
+ projectId,
176
+ conversationId,
177
+ filters,
178
+ options: options ?? createDefaultConversationHistoryConfig()
179
+ });
180
+ let messagesToFormat = conversationHistory;
181
+ if (currentMessage && conversationHistory.length > 0) {
182
+ if (conversationHistory[conversationHistory.length - 1].content.text === currentMessage) messagesToFormat = conversationHistory.slice(0, -1);
183
+ }
184
+ if (!messagesToFormat.length) return "";
185
+ let finalMessagesToFormat = messagesToFormat;
186
+ if (sessionId && summarizerModel) finalMessagesToFormat = await compressConversationIfNeeded(messagesToFormat, {
187
+ conversationId,
188
+ tenantId,
189
+ projectId,
190
+ summarizerModel,
191
+ streamRequestId: sessionId
192
+ });
193
+ return `<conversation_history>\n${finalMessagesToFormat.map((msg) => {
194
+ let roleLabel;
195
+ if (msg.role === "user") roleLabel = "user";
196
+ else if (msg.role === "agent" && (msg.messageType === "a2a-request" || msg.messageType === "a2a-response")) roleLabel = `${msg.fromSubAgentId || msg.fromExternalAgentId || "unknown"} to ${msg.toSubAgentId || msg.toExternalAgentId || "unknown"}`;
197
+ else if (msg.role === "agent" && msg.messageType === "chat") roleLabel = `${msg.fromSubAgentId || "unknown"} to User`;
198
+ else if (msg.role === "assistant" && msg.messageType === "tool-result") roleLabel = `${msg.fromSubAgentId || "unknown"} tool: ${msg.metadata?.a2a_metadata?.toolName || "unknown"}`;
199
+ else roleLabel = msg.role || "system";
200
+ return `${roleLabel}: """${msg.content.text}"""`;
201
+ }).join("\n")}\n</conversation_history>\n`;
202
+ }
203
+ /**
204
+ * Modern conversation history retrieval with compression support
205
+ * Replaces getFormattedConversationHistory with built-in compression when needed
206
+ */
207
+ async function getConversationHistoryWithCompression({ tenantId, projectId, conversationId, currentMessage, options, filters, summarizerModel, streamRequestId, fullContextSize }) {
208
+ const conversationHistory = await getScopedHistory({
209
+ tenantId,
210
+ projectId,
211
+ conversationId,
212
+ filters,
213
+ options: {
214
+ ...options ?? createDefaultConversationHistoryConfig(),
215
+ includeInternal: true,
216
+ maxOutputTokens: void 0
217
+ }
218
+ });
219
+ let messagesToFormat = conversationHistory;
220
+ if (currentMessage && conversationHistory.length > 0) {
221
+ if (conversationHistory[conversationHistory.length - 1].content.text === currentMessage) messagesToFormat = conversationHistory.slice(0, -1);
222
+ }
223
+ if (!messagesToFormat.length) return "";
224
+ if (summarizerModel) {
225
+ const compressionInfo = getCompressionConfigForModel(summarizerModel, .5);
226
+ const estimatedTokens = messagesToFormat.reduce((total, msg) => {
227
+ const text = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
228
+ return total + Math.ceil(text.length / 4);
229
+ }, 0);
230
+ const remaining = compressionInfo.hardLimit - estimatedTokens;
231
+ const compressionNeeded = remaining <= compressionInfo.safetyBuffer;
232
+ const contextWindowUtilization = compressionInfo.modelContextInfo.contextWindow ? (estimatedTokens / compressionInfo.modelContextInfo.contextWindow * 100).toFixed(1) : "unknown";
233
+ logger.info({
234
+ conversationId,
235
+ model: summarizerModel.model,
236
+ modelContextWindow: compressionInfo.modelContextInfo.contextWindow,
237
+ currentTokens: estimatedTokens,
238
+ hardLimit: compressionInfo.hardLimit,
239
+ safetyBuffer: compressionInfo.safetyBuffer,
240
+ remaining,
241
+ compressionNeeded,
242
+ contextWindowUtilization: `${contextWindowUtilization}%`,
243
+ messageCount: messagesToFormat.length,
244
+ source: compressionInfo.source
245
+ }, "Conversation history fetch - model context analysis");
246
+ const compressionSummary = messagesToFormat.find((msg) => msg.messageType === "compression_summary" && msg.metadata?.compressionType === "conversation_history");
247
+ if (compressionSummary) {
248
+ const messagesAfterCompression = messagesToFormat.filter((msg) => new Date(msg.createdAt) > new Date(compressionSummary.createdAt) && msg.messageType !== "compression_summary");
249
+ if (messagesAfterCompression.length >= 10) {
250
+ logger.info({
251
+ conversationId,
252
+ messagesAfterLastCompression: messagesAfterCompression.length,
253
+ lastCompressionDate: compressionSummary.createdAt
254
+ }, "Checking if re-compression needed for new messages");
255
+ const newMessagesCompressed = await compressConversationIfNeeded(messagesAfterCompression, {
256
+ conversationId,
257
+ tenantId,
258
+ projectId,
259
+ summarizerModel,
260
+ streamRequestId,
261
+ fullContextSize
262
+ });
263
+ if (newMessagesCompressed.length === 1 && newMessagesCompressed[0].messageType === "compression_summary") {
264
+ messagesToFormat = [compressionSummary, ...newMessagesCompressed];
265
+ logger.info({
266
+ conversationId,
267
+ totalCompressedMessages: messagesToFormat.length
268
+ }, "Re-compression completed - combined with existing summary");
269
+ } else messagesToFormat = [compressionSummary, ...messagesAfterCompression];
270
+ }
271
+ } else {
272
+ messagesToFormat.length;
273
+ messagesToFormat = await compressConversationIfNeeded(messagesToFormat, {
274
+ conversationId,
275
+ tenantId,
276
+ projectId,
277
+ summarizerModel,
278
+ streamRequestId,
279
+ fullContextSize
280
+ });
281
+ }
282
+ const compressedTokens = messagesToFormat.reduce((total, msg) => {
283
+ const text = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
284
+ return total + Math.ceil(text.length / 4);
285
+ }, 0);
286
+ const compressionSummaryMessages = messagesToFormat.filter((msg) => msg.messageType === "compression_summary");
287
+ if (compressionSummaryMessages.length > 0) logger.info({
288
+ conversationId,
289
+ finalMessages: messagesToFormat.length,
290
+ compressionSummaries: compressionSummaryMessages.length,
291
+ finalTokens: compressedTokens,
292
+ contextWindowUtilization: compressionInfo.modelContextInfo.contextWindow ? `${(compressedTokens / compressionInfo.modelContextInfo.contextWindow * 100).toFixed(1)}%` : "unknown"
293
+ }, "Final conversation history with compression summaries");
294
+ }
295
+ return formatMessagesAsConversationHistory(messagesToFormat);
296
+ }
297
+ /**
298
+ * Apply conversation compression using the BaseCompressor infrastructure
299
+ */
300
+ async function compressConversationIfNeeded(messages, params) {
301
+ const { conversationId, tenantId, projectId, summarizerModel, streamRequestId } = params;
302
+ const lockKey = `${conversationId}_${tenantId}_${projectId}`;
303
+ if (compressionLocks.has(lockKey)) {
304
+ logger.debug({ conversationId }, "Waiting for existing compression to complete");
305
+ await compressionLocks.get(lockKey);
306
+ return messages;
307
+ }
308
+ const compressionPromise = performActualCompression(messages, params);
309
+ compressionLocks.set(lockKey, compressionPromise);
310
+ try {
311
+ return await compressionPromise;
312
+ } finally {
313
+ compressionLocks.delete(lockKey);
314
+ }
315
+ }
316
+ async function performActualCompression(messages, params) {
317
+ const { conversationId, tenantId, projectId, summarizerModel, streamRequestId } = params;
318
+ const compressor = new ConversationCompressor(streamRequestId || conversationId, conversationId, tenantId, projectId, void 0, summarizerModel);
319
+ if (!compressor.isCompressionNeeded(messages)) return messages;
320
+ logger.info({
321
+ conversationId,
322
+ messageCount: messages.length
323
+ }, "Applying conversation-level compression");
324
+ try {
325
+ const compressionResult = await compressor.safeCompress(messages, params.fullContextSize);
326
+ if (compressionResult.summary) {
327
+ const compressionMessage = await createMessage(dbClient_default)({
328
+ id: generateId(),
329
+ tenantId,
330
+ projectId,
331
+ conversationId,
332
+ role: "system",
333
+ content: { text: buildCompressionSummaryMessage(compressionResult.summary, compressionResult.artifactIds) },
334
+ visibility: "internal",
335
+ messageType: "compression_summary",
336
+ metadata: { a2a_metadata: {
337
+ compressionType: "conversation_history",
338
+ artifactIds: compressionResult.artifactIds,
339
+ originalMessageCount: messages.length,
340
+ compressedAt: (/* @__PURE__ */ new Date()).toISOString(),
341
+ summaryData: compressionResult.summary
342
+ } }
343
+ });
344
+ logger.debug({
345
+ conversationId,
346
+ originalMessageCount: messages.length,
347
+ artifactCount: compressionResult.artifactIds?.length || 0,
348
+ compressionMessageId: compressionMessage.id
349
+ }, "Conversation compression saved to messages table");
350
+ compressor.fullCleanup();
351
+ return [compressionMessage];
352
+ }
353
+ compressor.fullCleanup();
354
+ return messages;
355
+ } catch (error) {
356
+ logger.error({
357
+ conversationId,
358
+ error: error instanceof Error ? error.message : String(error)
359
+ }, "Conversation compression failed, using original messages");
360
+ compressor.fullCleanup();
361
+ return messages;
362
+ }
363
+ }
364
+ /**
365
+ * Build a summary message for compressed conversation content
366
+ */
367
+ function buildCompressionSummaryMessage(summary, artifactIds) {
368
+ const parts = [];
369
+ parts.push("=== CONVERSATION SUMMARY ===");
370
+ parts.push("Previous conversation has been compressed to save context space.");
371
+ parts.push("");
372
+ if (summary.conversation_overview) parts.push(`📋 Overview: ${summary.conversation_overview}`);
373
+ if (summary.user_goals?.primary) {
374
+ parts.push(`🎯 Primary Goal: ${summary.user_goals.primary}`);
375
+ if (summary.user_goals.secondary && summary.user_goals.secondary.length > 0) {
376
+ parts.push(`🎯 Secondary Goals:`);
377
+ summary.user_goals.secondary.forEach((goal) => parts.push(` • ${goal}`));
378
+ }
379
+ }
380
+ if (summary.key_outcomes) {
381
+ if (summary.key_outcomes.completed && summary.key_outcomes.completed.length > 0) {
382
+ parts.push(`✅ Completed:`);
383
+ summary.key_outcomes.completed.forEach((item) => parts.push(` • ${item}`));
384
+ }
385
+ if (summary.key_outcomes.discoveries && summary.key_outcomes.discoveries.length > 0) {
386
+ parts.push(`💡 Key Discoveries:`);
387
+ summary.key_outcomes.discoveries.forEach((discovery) => parts.push(` • ${discovery}`));
388
+ }
389
+ if (summary.key_outcomes.partial && summary.key_outcomes.partial.length > 0) {
390
+ parts.push(`⏳ In Progress:`);
391
+ summary.key_outcomes.partial.forEach((item) => parts.push(` • ${item}`));
392
+ }
393
+ }
394
+ if (summary.context_for_continuation) {
395
+ if (summary.context_for_continuation.current_state) parts.push(`📍 Current State: ${summary.context_for_continuation.current_state}`);
396
+ if (summary.context_for_continuation.next_logical_steps && summary.context_for_continuation.next_logical_steps.length > 0) {
397
+ parts.push(`📝 Next Steps:`);
398
+ summary.context_for_continuation.next_logical_steps.forEach((step) => parts.push(` • ${step}`));
399
+ }
400
+ if (summary.context_for_continuation.important_context && summary.context_for_continuation.important_context.length > 0) {
401
+ parts.push(`🔑 Key Context:`);
402
+ summary.context_for_continuation.important_context.forEach((context) => parts.push(` • ${context}`));
403
+ }
404
+ }
405
+ if (summary.technical_context) {
406
+ if (summary.technical_context.technologies && summary.technical_context.technologies.length > 0) parts.push(`🔧 Technologies: ${summary.technical_context.technologies.join(", ")}`);
407
+ if (summary.technical_context.issues_encountered && summary.technical_context.issues_encountered.length > 0) {
408
+ parts.push(`⚠️ Issues Encountered:`);
409
+ summary.technical_context.issues_encountered.forEach((issue) => parts.push(` • ${issue}`));
410
+ }
411
+ if (summary.technical_context.solutions_applied && summary.technical_context.solutions_applied.length > 0) {
412
+ parts.push(`✨ Solutions Applied:`);
413
+ summary.technical_context.solutions_applied.forEach((solution) => parts.push(` • ${solution}`));
414
+ }
415
+ }
416
+ if (summary.high_level) parts.push(`📋 Overview: ${summary.high_level}`);
417
+ if (summary.user_intent) parts.push(`🎯 User Goal: ${summary.user_intent}`);
418
+ if (summary.decisions && summary.decisions.length > 0) {
419
+ parts.push(`✅ Key Decisions Made:`);
420
+ summary.decisions.forEach((decision) => parts.push(` • ${decision}`));
421
+ }
422
+ if (summary.next_steps && summary.next_steps.length > 0) {
423
+ parts.push(`📝 Planned Next Steps:`);
424
+ summary.next_steps.forEach((step) => parts.push(` • ${step}`));
425
+ }
426
+ if (summary.open_questions && summary.open_questions.length > 0) {
427
+ parts.push(`❓ Outstanding Questions:`);
428
+ summary.open_questions.forEach((question) => parts.push(` • ${question}`));
429
+ }
430
+ if (summary.conversation_artifacts && summary.conversation_artifacts.length > 0) {
431
+ parts.push(`💾 Research Artifacts: ${summary.conversation_artifacts.length} created from previous work`);
432
+ summary.conversation_artifacts.forEach((artifact) => {
433
+ parts.push(` [ARTIFACT: ${artifact.id}]`);
434
+ parts.push(` 📋 ${artifact.name || "Research Data"}`);
435
+ if (artifact.content_summary) parts.push(` 📝 ${artifact.content_summary}`);
436
+ if (artifact.tool_name && artifact.tool_name !== "unknown") parts.push(` 🔧 Source: ${artifact.tool_name}`);
437
+ parts.push(` 🔗 Reference: <artifact:ref id="${artifact.id}" tool_call_id="${artifact.tool_call_id}" />`);
438
+ parts.push("");
439
+ });
440
+ } else if (artifactIds && artifactIds.length > 0) {
441
+ parts.push(`💾 Research Artifacts: ${artifactIds.length} created from previous work`);
442
+ artifactIds.forEach((artifactId) => {
443
+ parts.push(` [ARTIFACT: ${artifactId}]`);
444
+ parts.push(` 🔗 Reference: <artifact:ref id="${artifactId}" />`);
445
+ });
446
+ }
447
+ parts.push("");
448
+ parts.push("=== END SUMMARY ===");
449
+ parts.push("Recent conversation continues below...");
450
+ return parts.join("\n");
451
+ }
452
+ /**
453
+ * Format messages into conversation history string (extracted from legacy method)
454
+ */
455
+ function formatMessagesAsConversationHistory(messages) {
456
+ return `<conversation_history>\n${messages.map((msg) => {
457
+ let roleLabel;
458
+ if (msg.role === "user") roleLabel = "user";
459
+ else if (msg.role === "agent" && (msg.messageType === "a2a-request" || msg.messageType === "a2a-response")) roleLabel = `${msg.fromSubAgentId || msg.fromExternalAgentId || "unknown"} to ${msg.toSubAgentId || msg.toExternalAgentId || "unknown"}`;
460
+ else if (msg.role === "agent" && msg.messageType === "chat") roleLabel = `${msg.fromSubAgentId || "unknown"} to User`;
461
+ else if (msg.role === "assistant" && msg.messageType === "tool-result") roleLabel = `${msg.fromSubAgentId || "unknown"} tool: ${msg.metadata?.a2a_metadata?.toolName || "unknown"}`;
462
+ else if (msg.role === "system") roleLabel = "system";
463
+ else roleLabel = msg.role || "system";
464
+ return `${roleLabel}: """${msg.content.text}"""`;
465
+ }).join("\n")}\n</conversation_history>\n`;
466
+ }
467
+ /**
468
+ * Get artifacts that are within the scope of the conversation history
469
+ * Only returns artifacts from messages that are actually visible to the LLM
470
+ * Uses the same scoping logic as getFormattedConversationHistory
471
+ */
472
+ async function getConversationScopedArtifacts(params) {
473
+ const { tenantId, projectId, conversationId, historyConfig } = params;
474
+ if (!conversationId) return [];
475
+ try {
476
+ if (historyConfig.mode === "none") return [];
477
+ const visibleMessages = await getScopedHistory({
478
+ tenantId,
479
+ projectId,
480
+ conversationId,
481
+ options: historyConfig
482
+ });
483
+ if (visibleMessages.length === 0) return [];
484
+ if (visibleMessages.filter((msg) => !(msg.messageType === "system" && msg.content?.text?.includes("Previous conversation history truncated"))).map((msg) => msg.id).length === 0) return [];
485
+ const { getLedgerArtifacts: getLedgerArtifacts$1 } = await import("@inkeep/agents-core");
486
+ const dbClient = (await import("./db/dbClient.js")).default;
487
+ const visibleTaskIds = visibleMessages.map((msg) => msg.taskId).filter((taskId) => Boolean(taskId));
488
+ const referenceArtifacts = [];
489
+ for (const taskId of visibleTaskIds) {
490
+ const artifacts = await getLedgerArtifacts$1(dbClient)({
491
+ scopes: {
492
+ tenantId,
493
+ projectId
494
+ },
495
+ taskId
496
+ });
497
+ referenceArtifacts.push(...artifacts);
498
+ }
499
+ const logger$1 = (await import("../logger.js")).getLogger("conversations");
500
+ const ARTIFACT_COUNT_LIMIT = CONVERSATION_ARTIFACTS_LIMIT;
501
+ const limitedArtifacts = referenceArtifacts.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()).slice(0, ARTIFACT_COUNT_LIMIT);
502
+ logger$1.debug({
503
+ conversationId,
504
+ visibleMessages: visibleMessages.length,
505
+ visibleTasks: visibleTaskIds.length,
506
+ totalArtifacts: referenceArtifacts.length,
507
+ limitedArtifacts: limitedArtifacts.length,
508
+ artifactLimit: ARTIFACT_COUNT_LIMIT,
509
+ historyMode: historyConfig.mode
510
+ }, "Loaded conversation-scoped artifacts with count limit");
511
+ return limitedArtifacts;
512
+ } catch (error) {
513
+ (await import("../logger.js")).getLogger("conversations").error({
514
+ error: error instanceof Error ? error.message : "Unknown error",
515
+ conversationId
516
+ }, "Failed to get conversation-scoped artifacts");
517
+ return [];
518
+ }
519
+ }
520
+
521
+ //#endregion
522
+ export { compressConversationIfNeeded, compressionLocks, createDefaultConversationHistoryConfig, getConversationHistoryWithCompression, getConversationScopedArtifacts, getFormattedConversationHistory, getFullConversationContext, getScopedHistory, getUserFacingHistory, saveA2AMessageResponse };
@@ -0,0 +1,6 @@
1
+ import { DatabaseClient } from "@inkeep/agents-core";
2
+
3
+ //#region src/data/db/dbClient.d.ts
4
+ declare let dbClient: DatabaseClient;
5
+ //#endregion
6
+ export { dbClient as default };
@@ -0,0 +1,17 @@
1
+ import { env } from "../../env.js";
2
+ import { createDatabaseClient } from "@inkeep/agents-core";
3
+ import { PGlite } from "@electric-sql/pglite";
4
+ import * as schema from "@inkeep/agents-core/db/schema";
5
+ import { drizzle } from "drizzle-orm/pglite";
6
+
7
+ //#region src/data/db/dbClient.ts
8
+ let dbClient;
9
+ if (env.ENVIRONMENT === "test") dbClient = drizzle({
10
+ client: new PGlite(),
11
+ schema
12
+ });
13
+ else dbClient = createDatabaseClient({ connectionString: env.DATABASE_URL });
14
+ var dbClient_default = dbClient;
15
+
16
+ //#endregion
17
+ export { dbClient_default as default };
package/dist/env.d.ts ADDED
@@ -0,0 +1,57 @@
1
+ import { z } from "@hono/zod-openapi";
2
+
3
+ //#region src/env.d.ts
4
+ declare const envSchema: z.ZodObject<{
5
+ NODE_ENV: z.ZodOptional<z.ZodEnum<{
6
+ development: "development";
7
+ production: "production";
8
+ test: "test";
9
+ }>>;
10
+ ENVIRONMENT: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
11
+ development: "development";
12
+ production: "production";
13
+ test: "test";
14
+ pentest: "pentest";
15
+ }>>>;
16
+ DATABASE_URL: z.ZodOptional<z.ZodString>;
17
+ INKEEP_AGENTS_RUN_API_URL: z.ZodDefault<z.ZodOptional<z.ZodString>>;
18
+ AGENTS_MANAGE_UI_URL: z.ZodDefault<z.ZodOptional<z.ZodString>>;
19
+ LOG_LEVEL: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
20
+ error: "error";
21
+ trace: "trace";
22
+ debug: "debug";
23
+ info: "info";
24
+ warn: "warn";
25
+ }>>>;
26
+ NANGO_SERVER_URL: z.ZodDefault<z.ZodOptional<z.ZodString>>;
27
+ NANGO_SECRET_KEY: z.ZodOptional<z.ZodString>;
28
+ ANTHROPIC_API_KEY: z.ZodString;
29
+ OPENAI_API_KEY: z.ZodOptional<z.ZodString>;
30
+ GOOGLE_GENERATIVE_AI_API_KEY: z.ZodOptional<z.ZodString>;
31
+ INKEEP_AGENTS_RUN_API_BYPASS_SECRET: z.ZodOptional<z.ZodString>;
32
+ INKEEP_AGENTS_JWT_SIGNING_SECRET: z.ZodOptional<z.ZodString>;
33
+ INKEEP_AGENTS_TEMP_JWT_PUBLIC_KEY: z.ZodOptional<z.ZodString>;
34
+ OTEL_BSP_SCHEDULE_DELAY: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
35
+ OTEL_BSP_MAX_EXPORT_BATCH_SIZE: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
36
+ }, z.core.$strip>;
37
+ declare const env: {
38
+ ENVIRONMENT: "development" | "production" | "test" | "pentest";
39
+ INKEEP_AGENTS_RUN_API_URL: string;
40
+ AGENTS_MANAGE_UI_URL: string;
41
+ LOG_LEVEL: "error" | "trace" | "debug" | "info" | "warn";
42
+ NANGO_SERVER_URL: string;
43
+ ANTHROPIC_API_KEY: string;
44
+ OTEL_BSP_SCHEDULE_DELAY: number;
45
+ OTEL_BSP_MAX_EXPORT_BATCH_SIZE: number;
46
+ NODE_ENV?: "development" | "production" | "test" | undefined;
47
+ DATABASE_URL?: string | undefined;
48
+ NANGO_SECRET_KEY?: string | undefined;
49
+ OPENAI_API_KEY?: string | undefined;
50
+ GOOGLE_GENERATIVE_AI_API_KEY?: string | undefined;
51
+ INKEEP_AGENTS_RUN_API_BYPASS_SECRET?: string | undefined;
52
+ INKEEP_AGENTS_JWT_SIGNING_SECRET?: string | undefined;
53
+ INKEEP_AGENTS_TEMP_JWT_PUBLIC_KEY?: string | undefined;
54
+ };
55
+ type Env = z.infer<typeof envSchema>;
56
+ //#endregion
57
+ export { Env, env };
package/dist/env.js CHANGED
@@ -50,5 +50,4 @@ const parseEnv = () => {
50
50
  const env = parseEnv();
51
51
 
52
52
  //#endregion
53
- export { env as t };
54
- //# sourceMappingURL=env.js.map
53
+ export { env };
@@ -0,0 +1,39 @@
1
+ import { StreamHelper } from "../utils/stream-helpers.js";
2
+ import { ExecutionContext } from "@inkeep/agents-core";
3
+
4
+ //#region src/handlers/executionHandler.d.ts
5
+ interface ExecutionHandlerParams {
6
+ executionContext: ExecutionContext;
7
+ conversationId: string;
8
+ userMessage: string;
9
+ initialAgentId: string;
10
+ requestId: string;
11
+ sseHelper: StreamHelper;
12
+ emitOperations?: boolean;
13
+ }
14
+ interface ExecutionResult {
15
+ success: boolean;
16
+ error?: string;
17
+ iterations: number;
18
+ response?: string;
19
+ }
20
+ declare class ExecutionHandler {
21
+ private readonly MAX_ERRORS;
22
+ /**
23
+ * performs exeuction loop
24
+ *
25
+ * Do up to limit of MAX_ITERATIONS
26
+ *
27
+ * 1. lookup active agent for thread
28
+ * 2. Send A2A message to selected agent
29
+ * 3. Parse A2A message response
30
+ * 4. Handle transfer messages (if any)
31
+ * 5. Handle completion messages (if any)
32
+ * 6. If no valid response or transfer, return error
33
+ * @param params
34
+ * @returns
35
+ */
36
+ execute(params: ExecutionHandlerParams): Promise<ExecutionResult>;
37
+ }
38
+ //#endregion
39
+ export { ExecutionHandler };