@inkeep/agents-run-api 0.18.0 → 0.19.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.
@@ -7,6 +7,58 @@ import { tmpdir } from 'os';
7
7
  import { join } from 'path';
8
8
 
9
9
  var logger = getLogger("local-sandbox-executor");
10
+ var ExecutionSemaphore = class {
11
+ constructor(permits, maxWaitTimeMs = 3e4) {
12
+ __publicField(this, "permits");
13
+ __publicField(this, "waitQueue", []);
14
+ __publicField(this, "maxWaitTime");
15
+ this.permits = Math.max(1, permits);
16
+ this.maxWaitTime = maxWaitTimeMs;
17
+ }
18
+ async acquire(fn) {
19
+ await new Promise((resolve, reject) => {
20
+ if (this.permits > 0) {
21
+ this.permits--;
22
+ resolve();
23
+ return;
24
+ }
25
+ const timeoutId = setTimeout(() => {
26
+ const index = this.waitQueue.findIndex((item) => item.resolve === resolve);
27
+ if (index !== -1) {
28
+ this.waitQueue.splice(index, 1);
29
+ reject(
30
+ new Error(
31
+ `Function execution queue timeout after ${this.maxWaitTime}ms. Too many concurrent executions.`
32
+ )
33
+ );
34
+ }
35
+ }, this.maxWaitTime);
36
+ this.waitQueue.push({
37
+ resolve: () => {
38
+ clearTimeout(timeoutId);
39
+ this.permits--;
40
+ resolve();
41
+ },
42
+ reject
43
+ });
44
+ });
45
+ try {
46
+ return await fn();
47
+ } finally {
48
+ this.permits++;
49
+ const next = this.waitQueue.shift();
50
+ if (next) {
51
+ next.resolve();
52
+ }
53
+ }
54
+ }
55
+ getAvailablePermits() {
56
+ return this.permits;
57
+ }
58
+ getQueueLength() {
59
+ return this.waitQueue.length;
60
+ }
61
+ };
10
62
  var _LocalSandboxExecutor = class _LocalSandboxExecutor {
11
63
  constructor() {
12
64
  __publicField(this, "tempDir");
@@ -14,6 +66,7 @@ var _LocalSandboxExecutor = class _LocalSandboxExecutor {
14
66
  __publicField(this, "POOL_TTL", 5 * 60 * 1e3);
15
67
  // 5 minutes
16
68
  __publicField(this, "MAX_USE_COUNT", 50);
69
+ __publicField(this, "executionSemaphores", /* @__PURE__ */ new Map());
17
70
  this.tempDir = join(tmpdir(), "inkeep-sandboxes");
18
71
  this.ensureTempDir();
19
72
  this.startPoolCleanup();
@@ -24,6 +77,34 @@ var _LocalSandboxExecutor = class _LocalSandboxExecutor {
24
77
  }
25
78
  return _LocalSandboxExecutor.instance;
26
79
  }
80
+ /**
81
+ * Get or create a semaphore for the specified vCPU limit
82
+ */
83
+ getSemaphore(vcpus) {
84
+ const effectiveVcpus = Math.max(1, vcpus || 1);
85
+ if (!this.executionSemaphores.has(effectiveVcpus)) {
86
+ logger.debug({ vcpus: effectiveVcpus }, "Creating new execution semaphore");
87
+ this.executionSemaphores.set(effectiveVcpus, new ExecutionSemaphore(effectiveVcpus));
88
+ }
89
+ const semaphore = this.executionSemaphores.get(effectiveVcpus);
90
+ if (!semaphore) {
91
+ throw new Error(`Failed to create semaphore for ${effectiveVcpus} vCPUs`);
92
+ }
93
+ return semaphore;
94
+ }
95
+ /**
96
+ * Get execution statistics for monitoring and debugging
97
+ */
98
+ getExecutionStats() {
99
+ const stats = {};
100
+ for (const [vcpus, semaphore] of this.executionSemaphores.entries()) {
101
+ stats[`vcpu_${vcpus}`] = {
102
+ availablePermits: semaphore.getAvailablePermits(),
103
+ queueLength: semaphore.getQueueLength()
104
+ };
105
+ }
106
+ return stats;
107
+ }
27
108
  ensureTempDir() {
28
109
  try {
29
110
  mkdirSync(this.tempDir, { recursive: true });
@@ -98,7 +179,7 @@ var _LocalSandboxExecutor = class _LocalSandboxExecutor {
98
179
  }
99
180
  }, 6e4);
100
181
  }
101
- detectModuleType(executeCode) {
182
+ detectModuleType(executeCode, configuredRuntime) {
102
183
  const esmPatterns = [
103
184
  /import\s+.*\s+from\s+['"]/g,
104
185
  // import ... from '...'
@@ -119,6 +200,9 @@ var _LocalSandboxExecutor = class _LocalSandboxExecutor {
119
200
  ];
120
201
  const hasEsmSyntax = esmPatterns.some((pattern) => pattern.test(executeCode));
121
202
  const hasCjsSyntax = cjsPatterns.some((pattern) => pattern.test(executeCode));
203
+ if (configuredRuntime === "typescript") {
204
+ return hasCjsSyntax ? "cjs" : "esm";
205
+ }
122
206
  if (hasEsmSyntax && hasCjsSyntax) {
123
207
  logger.warn(
124
208
  { executeCode: `${executeCode.substring(0, 100)}...` },
@@ -135,6 +219,24 @@ var _LocalSandboxExecutor = class _LocalSandboxExecutor {
135
219
  return "cjs";
136
220
  }
137
221
  async executeFunctionTool(toolId, args, config) {
222
+ const vcpus = config.sandboxConfig?.vcpus || 1;
223
+ const semaphore = this.getSemaphore(vcpus);
224
+ logger.debug(
225
+ {
226
+ toolId,
227
+ vcpus,
228
+ availablePermits: semaphore.getAvailablePermits(),
229
+ queueLength: semaphore.getQueueLength(),
230
+ sandboxConfig: config.sandboxConfig,
231
+ poolSize: Object.keys(this.sandboxPool).length
232
+ },
233
+ "Acquiring execution slot for function tool"
234
+ );
235
+ return semaphore.acquire(async () => {
236
+ return this.executeInSandbox_Internal(toolId, args, config);
237
+ });
238
+ }
239
+ async executeInSandbox_Internal(toolId, args, config) {
138
240
  const dependencies = config.dependencies || {};
139
241
  const dependencyHash = this.generateDependencyHash(dependencies);
140
242
  logger.debug(
@@ -142,6 +244,7 @@ var _LocalSandboxExecutor = class _LocalSandboxExecutor {
142
244
  toolId,
143
245
  dependencies,
144
246
  dependencyHash,
247
+ sandboxConfig: config.sandboxConfig,
145
248
  poolSize: Object.keys(this.sandboxPool).length
146
249
  },
147
250
  "Executing function tool"
@@ -161,7 +264,7 @@ var _LocalSandboxExecutor = class _LocalSandboxExecutor {
161
264
  },
162
265
  "Creating new sandbox"
163
266
  );
164
- const moduleType = this.detectModuleType(config.executeCode);
267
+ const moduleType = this.detectModuleType(config.executeCode, config.sandboxConfig?.runtime);
165
268
  const packageJson = {
166
269
  name: `function-tool-${toolId}`,
167
270
  version: "1.0.0",
@@ -178,14 +281,15 @@ var _LocalSandboxExecutor = class _LocalSandboxExecutor {
178
281
  this.addToPool(dependencyHash, sandboxDir, dependencies);
179
282
  }
180
283
  try {
181
- const moduleType = this.detectModuleType(config.executeCode);
284
+ const moduleType = this.detectModuleType(config.executeCode, config.sandboxConfig?.runtime);
182
285
  const executionCode = this.wrapFunctionCode(config.executeCode, args);
183
286
  const fileExtension = moduleType === "esm" ? "mjs" : "js";
184
287
  writeFileSync(join(sandboxDir, `index.${fileExtension}`), executionCode, "utf8");
185
288
  const result = await this.executeInSandbox(
186
289
  sandboxDir,
187
290
  config.sandboxConfig?.timeout || 3e4,
188
- moduleType
291
+ moduleType,
292
+ config.sandboxConfig
189
293
  );
190
294
  return result;
191
295
  } catch (error) {
@@ -224,7 +328,7 @@ var _LocalSandboxExecutor = class _LocalSandboxExecutor {
224
328
  });
225
329
  });
226
330
  }
227
- async executeInSandbox(sandboxDir, timeout, moduleType) {
331
+ async executeInSandbox(sandboxDir, timeout, moduleType, _sandboxConfig) {
228
332
  return new Promise((resolve, reject) => {
229
333
  const fileExtension = moduleType === "esm" ? "mjs" : "js";
230
334
  const spawnOptions = {
@@ -262,12 +366,13 @@ var _LocalSandboxExecutor = class _LocalSandboxExecutor {
262
366
  const timeoutId = setTimeout(() => {
263
367
  logger.warn({ sandboxDir, timeout }, "Function execution timed out, killing process");
264
368
  node.kill("SIGTERM");
369
+ const forceKillTimeout = Math.min(Math.max(timeout / 10, 2e3), 5e3);
265
370
  setTimeout(() => {
266
371
  try {
267
372
  node.kill("SIGKILL");
268
373
  } catch {
269
374
  }
270
- }, 5e3);
375
+ }, forceKillTimeout);
271
376
  reject(new Error(`Function execution timed out after ${timeout}ms`));
272
377
  }, timeout);
273
378
  node.on("close", (code, signal) => {
@@ -75,7 +75,7 @@ async function getScopedHistory({
75
75
  let matchesAgent = true;
76
76
  let matchesTask = true;
77
77
  if (filters.subAgentId) {
78
- matchesAgent = msg.role === "agent" && msg.visibility === "user-facing" || msg.toAgentId === filters.subAgentId || msg.fromAgentId === filters.subAgentId;
78
+ matchesAgent = msg.role === "agent" && msg.visibility === "user-facing" || msg.toSubAgentId === filters.subAgentId || msg.fromSubAgentId === filters.subAgentId;
79
79
  }
80
80
  if (filters.taskId) {
81
81
  matchesTask = msg.taskId === filters.taskId || msg.a2aTaskId === filters.taskId;
@@ -150,12 +150,12 @@ async function getFormattedConversationHistory({
150
150
  if (msg.role === "user") {
151
151
  roleLabel = "user";
152
152
  } else if (msg.role === "agent" && (msg.messageType === "a2a-request" || msg.messageType === "a2a-response")) {
153
- const fromAgent = msg.fromAgentId || msg.fromExternalAgentId || "unknown";
154
- const toAgent = msg.toAgentId || msg.toExternalAgentId || "unknown";
155
- roleLabel = `${fromAgent} to ${toAgent}`;
153
+ const fromSubAgent = msg.fromSubAgentId || msg.fromExternalAgentId || "unknown";
154
+ const toSubAgent = msg.toSubAgentId || msg.toExternalAgentId || "unknown";
155
+ roleLabel = `${fromSubAgent} to ${toSubAgent}`;
156
156
  } else if (msg.role === "agent" && msg.messageType === "chat") {
157
- const fromAgent = msg.fromAgentId || "unknown";
158
- roleLabel = `${fromAgent} to User`;
157
+ const fromSubAgent = msg.fromSubAgentId || "unknown";
158
+ roleLabel = `${fromSubAgent} to User`;
159
159
  } else {
160
160
  roleLabel = msg.role || "system";
161
161
  }
@@ -1 +1 @@
1
- export { createDefaultConversationHistoryConfig, getConversationScopedArtifacts, getFormattedConversationHistory, getFullConversationContext, getScopedHistory, getUserFacingHistory, saveA2AMessageResponse } from './chunk-DQQRVSJS.js';
1
+ export { createDefaultConversationHistoryConfig, getConversationScopedArtifacts, getFormattedConversationHistory, getFullConversationContext, getScopedHistory, getUserFacingHistory, saveA2AMessageResponse } from './chunk-QRT6EIUX.js';