@inkeep/agents-run-api 0.22.12 → 0.23.1

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.
@@ -1,7 +1,7 @@
1
1
  import { getLogger as getLogger$1 } from './chunk-A2S7GSHL.js';
2
2
  import { __publicField } from './chunk-PKBMQBKP.js';
3
3
  import { spawn } from 'child_process';
4
- import { createHash } from 'crypto';
4
+ import crypto, { createHash } from 'crypto';
5
5
  import { mkdirSync, existsSync, rmSync, writeFileSync } from 'fs';
6
6
  import { tmpdir } from 'os';
7
7
  import { join } from 'path';
@@ -466,6 +466,11 @@ var logger2 = getLogger$1("VercelSandboxExecutor");
466
466
  var _VercelSandboxExecutor = class _VercelSandboxExecutor {
467
467
  constructor(config) {
468
468
  __publicField(this, "config");
469
+ __publicField(this, "sandboxPool", /* @__PURE__ */ new Map());
470
+ __publicField(this, "POOL_TTL", 5 * 60 * 1e3);
471
+ // 5 minutes
472
+ __publicField(this, "MAX_USE_COUNT", 50);
473
+ __publicField(this, "cleanupInterval", null);
469
474
  this.config = config;
470
475
  logger2.info(
471
476
  {
@@ -475,8 +480,9 @@ var _VercelSandboxExecutor = class _VercelSandboxExecutor {
475
480
  timeout: config.timeout,
476
481
  vcpus: config.vcpus
477
482
  },
478
- "VercelSandboxExecutor initialized"
483
+ "VercelSandboxExecutor initialized with pooling"
479
484
  );
485
+ this.startPoolCleanup();
480
486
  }
481
487
  /**
482
488
  * Get singleton instance of VercelSandboxExecutor
@@ -488,45 +494,227 @@ var _VercelSandboxExecutor = class _VercelSandboxExecutor {
488
494
  return _VercelSandboxExecutor.instance;
489
495
  }
490
496
  /**
491
- * Execute a function tool in Vercel Sandbox
497
+ * Generate a hash for dependencies to use as cache key
498
+ */
499
+ generateDependencyHash(dependencies) {
500
+ const sorted = Object.keys(dependencies).sort().map((key) => `${key}@${dependencies[key]}`).join(",");
501
+ return crypto.createHash("md5").update(sorted).digest("hex").substring(0, 8);
502
+ }
503
+ /**
504
+ * Get a cached sandbox if available and still valid
505
+ */
506
+ getCachedSandbox(dependencyHash) {
507
+ const cached = this.sandboxPool.get(dependencyHash);
508
+ if (!cached) return null;
509
+ const now = Date.now();
510
+ const age = now - cached.createdAt;
511
+ if (age > this.POOL_TTL || cached.useCount >= this.MAX_USE_COUNT) {
512
+ logger2.debug(
513
+ {
514
+ dependencyHash,
515
+ age,
516
+ useCount: cached.useCount,
517
+ ttl: this.POOL_TTL,
518
+ maxUseCount: this.MAX_USE_COUNT
519
+ },
520
+ "Sandbox expired, will create new one"
521
+ );
522
+ this.removeSandbox(dependencyHash);
523
+ return null;
524
+ }
525
+ logger2.debug(
526
+ {
527
+ dependencyHash,
528
+ useCount: cached.useCount,
529
+ age
530
+ },
531
+ "Reusing cached sandbox"
532
+ );
533
+ return cached.sandbox;
534
+ }
535
+ /**
536
+ * Add sandbox to pool
537
+ */
538
+ addToPool(dependencyHash, sandbox, dependencies) {
539
+ this.sandboxPool.set(dependencyHash, {
540
+ sandbox,
541
+ createdAt: Date.now(),
542
+ useCount: 0,
543
+ dependencies
544
+ });
545
+ logger2.debug(
546
+ {
547
+ dependencyHash,
548
+ poolSize: this.sandboxPool.size
549
+ },
550
+ "Sandbox added to pool"
551
+ );
552
+ }
553
+ /**
554
+ * Increment use count for a sandbox
555
+ */
556
+ incrementUseCount(dependencyHash) {
557
+ const cached = this.sandboxPool.get(dependencyHash);
558
+ if (cached) {
559
+ cached.useCount++;
560
+ }
561
+ }
562
+ /**
563
+ * Remove and clean up a sandbox
564
+ */
565
+ async removeSandbox(dependencyHash) {
566
+ const cached = this.sandboxPool.get(dependencyHash);
567
+ if (cached) {
568
+ try {
569
+ await cached.sandbox.stop();
570
+ logger2.debug({ dependencyHash }, "Sandbox stopped");
571
+ } catch (error) {
572
+ logger2.warn({ error, dependencyHash }, "Error stopping sandbox");
573
+ }
574
+ this.sandboxPool.delete(dependencyHash);
575
+ }
576
+ }
577
+ /**
578
+ * Start periodic cleanup of expired sandboxes
579
+ */
580
+ startPoolCleanup() {
581
+ this.cleanupInterval = setInterval(
582
+ () => {
583
+ const now = Date.now();
584
+ const toRemove = [];
585
+ for (const [hash, cached] of this.sandboxPool.entries()) {
586
+ const age = now - cached.createdAt;
587
+ if (age > this.POOL_TTL || cached.useCount >= this.MAX_USE_COUNT) {
588
+ toRemove.push(hash);
589
+ }
590
+ }
591
+ if (toRemove.length > 0) {
592
+ logger2.info(
593
+ {
594
+ count: toRemove.length,
595
+ poolSize: this.sandboxPool.size
596
+ },
597
+ "Cleaning up expired sandboxes"
598
+ );
599
+ for (const hash of toRemove) {
600
+ this.removeSandbox(hash);
601
+ }
602
+ }
603
+ },
604
+ 60 * 1e3
605
+ // Run every minute
606
+ );
607
+ }
608
+ /**
609
+ * Cleanup all sandboxes and stop cleanup interval
610
+ */
611
+ async cleanup() {
612
+ if (this.cleanupInterval) {
613
+ clearInterval(this.cleanupInterval);
614
+ this.cleanupInterval = null;
615
+ }
616
+ logger2.info(
617
+ {
618
+ poolSize: this.sandboxPool.size
619
+ },
620
+ "Cleaning up all sandboxes"
621
+ );
622
+ const promises = Array.from(this.sandboxPool.keys()).map((hash) => this.removeSandbox(hash));
623
+ await Promise.all(promises);
624
+ }
625
+ /**
626
+ * Extract environment variable names from code
627
+ * Matches patterns like process.env.VAR_NAME or process.env['VAR_NAME']
628
+ */
629
+ extractEnvVars(code) {
630
+ const envVars = /* @__PURE__ */ new Set();
631
+ const dotNotationRegex = /process\.env\.([A-Z_][A-Z0-9_]*)/g;
632
+ let match = dotNotationRegex.exec(code);
633
+ while (match !== null) {
634
+ envVars.add(match[1]);
635
+ match = dotNotationRegex.exec(code);
636
+ }
637
+ const bracketNotationRegex = /process\.env\[['"]([A-Z_][A-Z0-9_]*)['"]\]/g;
638
+ match = bracketNotationRegex.exec(code);
639
+ while (match !== null) {
640
+ envVars.add(match[1]);
641
+ match = bracketNotationRegex.exec(code);
642
+ }
643
+ return envVars;
644
+ }
645
+ /**
646
+ * Create .env file content from environment variables
647
+ * Note: Currently creates empty placeholders. Values will be populated in the future.
648
+ */
649
+ createEnvFileContent(envVarNames) {
650
+ const envLines = [];
651
+ for (const varName of envVarNames) {
652
+ envLines.push(`${varName}=""`);
653
+ logger2.debug({ varName }, "Adding environment variable placeholder to sandbox");
654
+ }
655
+ return envLines.join("\n");
656
+ }
657
+ /**
658
+ * Execute a function tool in Vercel Sandbox with pooling
492
659
  */
493
660
  async executeFunctionTool(functionId, args, toolConfig) {
494
661
  const startTime = Date.now();
495
662
  const logs = [];
663
+ const dependencies = toolConfig.dependencies || {};
664
+ const dependencyHash = this.generateDependencyHash(dependencies);
496
665
  try {
497
666
  logger2.info(
498
667
  {
499
668
  functionId,
500
- functionName: toolConfig.name
669
+ functionName: toolConfig.name,
670
+ dependencyHash,
671
+ poolSize: this.sandboxPool.size
501
672
  },
502
673
  "Executing function in Vercel Sandbox"
503
674
  );
504
- const sandbox = await Sandbox.create({
505
- token: this.config.token,
506
- teamId: this.config.teamId,
507
- projectId: this.config.projectId,
508
- timeout: this.config.timeout,
509
- resources: {
510
- vcpus: this.config.vcpus || 1
511
- },
512
- runtime: this.config.runtime
513
- });
514
- logger2.info(
515
- {
516
- functionId,
517
- sandboxId: sandbox.sandboxId
518
- },
519
- `Sandbox created for function ${functionId}`
520
- );
675
+ let sandbox = this.getCachedSandbox(dependencyHash);
676
+ let isNewSandbox = false;
677
+ if (!sandbox) {
678
+ isNewSandbox = true;
679
+ sandbox = await Sandbox.create({
680
+ token: this.config.token,
681
+ teamId: this.config.teamId,
682
+ projectId: this.config.projectId,
683
+ timeout: this.config.timeout,
684
+ resources: {
685
+ vcpus: this.config.vcpus || 1
686
+ },
687
+ runtime: this.config.runtime
688
+ });
689
+ logger2.info(
690
+ {
691
+ functionId,
692
+ sandboxId: sandbox.sandboxId,
693
+ dependencyHash
694
+ },
695
+ `New sandbox created for function ${functionId}`
696
+ );
697
+ this.addToPool(dependencyHash, sandbox, dependencies);
698
+ } else {
699
+ logger2.info(
700
+ {
701
+ functionId,
702
+ sandboxId: sandbox.sandboxId,
703
+ dependencyHash
704
+ },
705
+ `Reusing cached sandbox for function ${functionId}`
706
+ );
707
+ }
708
+ this.incrementUseCount(dependencyHash);
521
709
  try {
522
- if (toolConfig.dependencies && Object.keys(toolConfig.dependencies).length > 0) {
710
+ if (isNewSandbox && toolConfig.dependencies && Object.keys(toolConfig.dependencies).length > 0) {
523
711
  logger2.debug(
524
712
  {
525
713
  functionId,
526
714
  functionName: toolConfig.name,
527
715
  dependencies: toolConfig.dependencies
528
716
  },
529
- "Installing dependencies"
717
+ "Installing dependencies in new sandbox"
530
718
  );
531
719
  const packageJson = {
532
720
  dependencies: toolConfig.dependencies
@@ -553,27 +741,61 @@ var _VercelSandboxExecutor = class _VercelSandboxExecutor {
553
741
  if (installCmd.exitCode !== 0) {
554
742
  throw new Error(`Failed to install dependencies: ${installStderr}`);
555
743
  }
744
+ logger2.info(
745
+ {
746
+ functionId,
747
+ dependencyHash
748
+ },
749
+ "Dependencies installed successfully"
750
+ );
556
751
  }
557
752
  const executionCode = createExecutionWrapper(toolConfig.executeCode, args);
753
+ const envVars = this.extractEnvVars(toolConfig.executeCode);
754
+ const filesToWrite = [];
558
755
  const filename = this.config.runtime === "typescript" ? "execute.ts" : "execute.js";
559
- await sandbox.writeFiles([
560
- {
561
- path: filename,
562
- content: Buffer.from(executionCode, "utf-8")
756
+ filesToWrite.push({
757
+ path: filename,
758
+ content: Buffer.from(executionCode, "utf-8")
759
+ });
760
+ if (envVars.size > 0) {
761
+ const envFileContent = this.createEnvFileContent(envVars);
762
+ if (envFileContent) {
763
+ filesToWrite.push({
764
+ path: ".env",
765
+ content: Buffer.from(envFileContent, "utf-8")
766
+ });
767
+ logger2.info(
768
+ {
769
+ functionId,
770
+ envVarCount: envVars.size,
771
+ envVars: Array.from(envVars)
772
+ },
773
+ "Creating environment variable placeholders in sandbox"
774
+ );
563
775
  }
564
- ]);
776
+ }
777
+ await sandbox.writeFiles(filesToWrite);
565
778
  logger2.info(
566
779
  {
567
780
  functionId,
568
- runtime: this.config.runtime === "typescript" ? "tsx" : "node"
781
+ runtime: this.config.runtime === "typescript" ? "tsx" : "node",
782
+ hasEnvVars: envVars.size > 0
569
783
  },
570
784
  `Execution code written to file for runtime ${this.config.runtime}`
571
785
  );
572
- const runtime = this.config.runtime === "typescript" ? "tsx" : "node";
573
- const executeCmd = await sandbox.runCommand({
574
- cmd: runtime,
575
- args: [filename]
576
- });
786
+ const executeCmd = await (async () => {
787
+ if (envVars.size > 0) {
788
+ return sandbox.runCommand({
789
+ cmd: "npx",
790
+ args: this.config.runtime === "typescript" ? ["--yes", "dotenv-cli", "--", "npx", "tsx", filename] : ["--yes", "dotenv-cli", "--", "node", filename]
791
+ });
792
+ }
793
+ const runtime = this.config.runtime === "typescript" ? "tsx" : "node";
794
+ return sandbox.runCommand({
795
+ cmd: runtime,
796
+ args: [filename]
797
+ });
798
+ })();
577
799
  const executeStdout = await executeCmd.stdout();
578
800
  const executeStderr = await executeCmd.stderr();
579
801
  if (executeStdout) {
@@ -613,8 +835,9 @@ var _VercelSandboxExecutor = class _VercelSandboxExecutor {
613
835
  logs,
614
836
  executionTime
615
837
  };
616
- } finally {
617
- await sandbox.stop();
838
+ } catch (innerError) {
839
+ await this.removeSandbox(dependencyHash);
840
+ throw innerError;
618
841
  }
619
842
  } catch (error) {
620
843
  const executionTime = Date.now() - startTime;
@@ -635,12 +858,6 @@ var _VercelSandboxExecutor = class _VercelSandboxExecutor {
635
858
  };
636
859
  }
637
860
  }
638
- /**
639
- * Clean up resources
640
- */
641
- async cleanup() {
642
- logger2.info({}, "VercelSandboxExecutor cleanup completed");
643
- }
644
861
  };
645
862
  __publicField(_VercelSandboxExecutor, "instance");
646
863
  var VercelSandboxExecutor = _VercelSandboxExecutor;
package/dist/index.cjs CHANGED
@@ -48,6 +48,7 @@ var fetchToNode = require('fetch-to-node');
48
48
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
49
49
 
50
50
  var z6__default = /*#__PURE__*/_interopDefault(z6);
51
+ var crypto__default = /*#__PURE__*/_interopDefault(crypto);
51
52
  var jmespath__default = /*#__PURE__*/_interopDefault(jmespath);
52
53
  var Ajv__default = /*#__PURE__*/_interopDefault(Ajv);
53
54
  var destr__default = /*#__PURE__*/_interopDefault(destr);
@@ -858,6 +859,11 @@ var init_VercelSandboxExecutor = __esm({
858
859
  _VercelSandboxExecutor = class _VercelSandboxExecutor {
859
860
  constructor(config) {
860
861
  __publicField(this, "config");
862
+ __publicField(this, "sandboxPool", /* @__PURE__ */ new Map());
863
+ __publicField(this, "POOL_TTL", 5 * 60 * 1e3);
864
+ // 5 minutes
865
+ __publicField(this, "MAX_USE_COUNT", 50);
866
+ __publicField(this, "cleanupInterval", null);
861
867
  this.config = config;
862
868
  logger17.info(
863
869
  {
@@ -867,8 +873,9 @@ var init_VercelSandboxExecutor = __esm({
867
873
  timeout: config.timeout,
868
874
  vcpus: config.vcpus
869
875
  },
870
- "VercelSandboxExecutor initialized"
876
+ "VercelSandboxExecutor initialized with pooling"
871
877
  );
878
+ this.startPoolCleanup();
872
879
  }
873
880
  /**
874
881
  * Get singleton instance of VercelSandboxExecutor
@@ -880,45 +887,227 @@ var init_VercelSandboxExecutor = __esm({
880
887
  return _VercelSandboxExecutor.instance;
881
888
  }
882
889
  /**
883
- * Execute a function tool in Vercel Sandbox
890
+ * Generate a hash for dependencies to use as cache key
891
+ */
892
+ generateDependencyHash(dependencies) {
893
+ const sorted = Object.keys(dependencies).sort().map((key) => `${key}@${dependencies[key]}`).join(",");
894
+ return crypto__default.default.createHash("md5").update(sorted).digest("hex").substring(0, 8);
895
+ }
896
+ /**
897
+ * Get a cached sandbox if available and still valid
898
+ */
899
+ getCachedSandbox(dependencyHash) {
900
+ const cached = this.sandboxPool.get(dependencyHash);
901
+ if (!cached) return null;
902
+ const now = Date.now();
903
+ const age = now - cached.createdAt;
904
+ if (age > this.POOL_TTL || cached.useCount >= this.MAX_USE_COUNT) {
905
+ logger17.debug(
906
+ {
907
+ dependencyHash,
908
+ age,
909
+ useCount: cached.useCount,
910
+ ttl: this.POOL_TTL,
911
+ maxUseCount: this.MAX_USE_COUNT
912
+ },
913
+ "Sandbox expired, will create new one"
914
+ );
915
+ this.removeSandbox(dependencyHash);
916
+ return null;
917
+ }
918
+ logger17.debug(
919
+ {
920
+ dependencyHash,
921
+ useCount: cached.useCount,
922
+ age
923
+ },
924
+ "Reusing cached sandbox"
925
+ );
926
+ return cached.sandbox;
927
+ }
928
+ /**
929
+ * Add sandbox to pool
930
+ */
931
+ addToPool(dependencyHash, sandbox, dependencies) {
932
+ this.sandboxPool.set(dependencyHash, {
933
+ sandbox,
934
+ createdAt: Date.now(),
935
+ useCount: 0,
936
+ dependencies
937
+ });
938
+ logger17.debug(
939
+ {
940
+ dependencyHash,
941
+ poolSize: this.sandboxPool.size
942
+ },
943
+ "Sandbox added to pool"
944
+ );
945
+ }
946
+ /**
947
+ * Increment use count for a sandbox
948
+ */
949
+ incrementUseCount(dependencyHash) {
950
+ const cached = this.sandboxPool.get(dependencyHash);
951
+ if (cached) {
952
+ cached.useCount++;
953
+ }
954
+ }
955
+ /**
956
+ * Remove and clean up a sandbox
957
+ */
958
+ async removeSandbox(dependencyHash) {
959
+ const cached = this.sandboxPool.get(dependencyHash);
960
+ if (cached) {
961
+ try {
962
+ await cached.sandbox.stop();
963
+ logger17.debug({ dependencyHash }, "Sandbox stopped");
964
+ } catch (error) {
965
+ logger17.warn({ error, dependencyHash }, "Error stopping sandbox");
966
+ }
967
+ this.sandboxPool.delete(dependencyHash);
968
+ }
969
+ }
970
+ /**
971
+ * Start periodic cleanup of expired sandboxes
972
+ */
973
+ startPoolCleanup() {
974
+ this.cleanupInterval = setInterval(
975
+ () => {
976
+ const now = Date.now();
977
+ const toRemove = [];
978
+ for (const [hash, cached] of this.sandboxPool.entries()) {
979
+ const age = now - cached.createdAt;
980
+ if (age > this.POOL_TTL || cached.useCount >= this.MAX_USE_COUNT) {
981
+ toRemove.push(hash);
982
+ }
983
+ }
984
+ if (toRemove.length > 0) {
985
+ logger17.info(
986
+ {
987
+ count: toRemove.length,
988
+ poolSize: this.sandboxPool.size
989
+ },
990
+ "Cleaning up expired sandboxes"
991
+ );
992
+ for (const hash of toRemove) {
993
+ this.removeSandbox(hash);
994
+ }
995
+ }
996
+ },
997
+ 60 * 1e3
998
+ // Run every minute
999
+ );
1000
+ }
1001
+ /**
1002
+ * Cleanup all sandboxes and stop cleanup interval
1003
+ */
1004
+ async cleanup() {
1005
+ if (this.cleanupInterval) {
1006
+ clearInterval(this.cleanupInterval);
1007
+ this.cleanupInterval = null;
1008
+ }
1009
+ logger17.info(
1010
+ {
1011
+ poolSize: this.sandboxPool.size
1012
+ },
1013
+ "Cleaning up all sandboxes"
1014
+ );
1015
+ const promises = Array.from(this.sandboxPool.keys()).map((hash) => this.removeSandbox(hash));
1016
+ await Promise.all(promises);
1017
+ }
1018
+ /**
1019
+ * Extract environment variable names from code
1020
+ * Matches patterns like process.env.VAR_NAME or process.env['VAR_NAME']
1021
+ */
1022
+ extractEnvVars(code) {
1023
+ const envVars = /* @__PURE__ */ new Set();
1024
+ const dotNotationRegex = /process\.env\.([A-Z_][A-Z0-9_]*)/g;
1025
+ let match = dotNotationRegex.exec(code);
1026
+ while (match !== null) {
1027
+ envVars.add(match[1]);
1028
+ match = dotNotationRegex.exec(code);
1029
+ }
1030
+ const bracketNotationRegex = /process\.env\[['"]([A-Z_][A-Z0-9_]*)['"]\]/g;
1031
+ match = bracketNotationRegex.exec(code);
1032
+ while (match !== null) {
1033
+ envVars.add(match[1]);
1034
+ match = bracketNotationRegex.exec(code);
1035
+ }
1036
+ return envVars;
1037
+ }
1038
+ /**
1039
+ * Create .env file content from environment variables
1040
+ * Note: Currently creates empty placeholders. Values will be populated in the future.
1041
+ */
1042
+ createEnvFileContent(envVarNames) {
1043
+ const envLines = [];
1044
+ for (const varName of envVarNames) {
1045
+ envLines.push(`${varName}=""`);
1046
+ logger17.debug({ varName }, "Adding environment variable placeholder to sandbox");
1047
+ }
1048
+ return envLines.join("\n");
1049
+ }
1050
+ /**
1051
+ * Execute a function tool in Vercel Sandbox with pooling
884
1052
  */
885
1053
  async executeFunctionTool(functionId, args, toolConfig) {
886
1054
  const startTime = Date.now();
887
1055
  const logs = [];
1056
+ const dependencies = toolConfig.dependencies || {};
1057
+ const dependencyHash = this.generateDependencyHash(dependencies);
888
1058
  try {
889
1059
  logger17.info(
890
1060
  {
891
1061
  functionId,
892
- functionName: toolConfig.name
1062
+ functionName: toolConfig.name,
1063
+ dependencyHash,
1064
+ poolSize: this.sandboxPool.size
893
1065
  },
894
1066
  "Executing function in Vercel Sandbox"
895
1067
  );
896
- const sandbox$1 = await sandbox.Sandbox.create({
897
- token: this.config.token,
898
- teamId: this.config.teamId,
899
- projectId: this.config.projectId,
900
- timeout: this.config.timeout,
901
- resources: {
902
- vcpus: this.config.vcpus || 1
903
- },
904
- runtime: this.config.runtime
905
- });
906
- logger17.info(
907
- {
908
- functionId,
909
- sandboxId: sandbox$1.sandboxId
910
- },
911
- `Sandbox created for function ${functionId}`
912
- );
1068
+ let sandbox$1 = this.getCachedSandbox(dependencyHash);
1069
+ let isNewSandbox = false;
1070
+ if (!sandbox$1) {
1071
+ isNewSandbox = true;
1072
+ sandbox$1 = await sandbox.Sandbox.create({
1073
+ token: this.config.token,
1074
+ teamId: this.config.teamId,
1075
+ projectId: this.config.projectId,
1076
+ timeout: this.config.timeout,
1077
+ resources: {
1078
+ vcpus: this.config.vcpus || 1
1079
+ },
1080
+ runtime: this.config.runtime
1081
+ });
1082
+ logger17.info(
1083
+ {
1084
+ functionId,
1085
+ sandboxId: sandbox$1.sandboxId,
1086
+ dependencyHash
1087
+ },
1088
+ `New sandbox created for function ${functionId}`
1089
+ );
1090
+ this.addToPool(dependencyHash, sandbox$1, dependencies);
1091
+ } else {
1092
+ logger17.info(
1093
+ {
1094
+ functionId,
1095
+ sandboxId: sandbox$1.sandboxId,
1096
+ dependencyHash
1097
+ },
1098
+ `Reusing cached sandbox for function ${functionId}`
1099
+ );
1100
+ }
1101
+ this.incrementUseCount(dependencyHash);
913
1102
  try {
914
- if (toolConfig.dependencies && Object.keys(toolConfig.dependencies).length > 0) {
1103
+ if (isNewSandbox && toolConfig.dependencies && Object.keys(toolConfig.dependencies).length > 0) {
915
1104
  logger17.debug(
916
1105
  {
917
1106
  functionId,
918
1107
  functionName: toolConfig.name,
919
1108
  dependencies: toolConfig.dependencies
920
1109
  },
921
- "Installing dependencies"
1110
+ "Installing dependencies in new sandbox"
922
1111
  );
923
1112
  const packageJson = {
924
1113
  dependencies: toolConfig.dependencies
@@ -945,27 +1134,61 @@ var init_VercelSandboxExecutor = __esm({
945
1134
  if (installCmd.exitCode !== 0) {
946
1135
  throw new Error(`Failed to install dependencies: ${installStderr}`);
947
1136
  }
1137
+ logger17.info(
1138
+ {
1139
+ functionId,
1140
+ dependencyHash
1141
+ },
1142
+ "Dependencies installed successfully"
1143
+ );
948
1144
  }
949
1145
  const executionCode = createExecutionWrapper(toolConfig.executeCode, args);
1146
+ const envVars = this.extractEnvVars(toolConfig.executeCode);
1147
+ const filesToWrite = [];
950
1148
  const filename = this.config.runtime === "typescript" ? "execute.ts" : "execute.js";
951
- await sandbox$1.writeFiles([
952
- {
953
- path: filename,
954
- content: Buffer.from(executionCode, "utf-8")
1149
+ filesToWrite.push({
1150
+ path: filename,
1151
+ content: Buffer.from(executionCode, "utf-8")
1152
+ });
1153
+ if (envVars.size > 0) {
1154
+ const envFileContent = this.createEnvFileContent(envVars);
1155
+ if (envFileContent) {
1156
+ filesToWrite.push({
1157
+ path: ".env",
1158
+ content: Buffer.from(envFileContent, "utf-8")
1159
+ });
1160
+ logger17.info(
1161
+ {
1162
+ functionId,
1163
+ envVarCount: envVars.size,
1164
+ envVars: Array.from(envVars)
1165
+ },
1166
+ "Creating environment variable placeholders in sandbox"
1167
+ );
955
1168
  }
956
- ]);
1169
+ }
1170
+ await sandbox$1.writeFiles(filesToWrite);
957
1171
  logger17.info(
958
1172
  {
959
1173
  functionId,
960
- runtime: this.config.runtime === "typescript" ? "tsx" : "node"
1174
+ runtime: this.config.runtime === "typescript" ? "tsx" : "node",
1175
+ hasEnvVars: envVars.size > 0
961
1176
  },
962
1177
  `Execution code written to file for runtime ${this.config.runtime}`
963
1178
  );
964
- const runtime = this.config.runtime === "typescript" ? "tsx" : "node";
965
- const executeCmd = await sandbox$1.runCommand({
966
- cmd: runtime,
967
- args: [filename]
968
- });
1179
+ const executeCmd = await (async () => {
1180
+ if (envVars.size > 0) {
1181
+ return sandbox$1.runCommand({
1182
+ cmd: "npx",
1183
+ args: this.config.runtime === "typescript" ? ["--yes", "dotenv-cli", "--", "npx", "tsx", filename] : ["--yes", "dotenv-cli", "--", "node", filename]
1184
+ });
1185
+ }
1186
+ const runtime = this.config.runtime === "typescript" ? "tsx" : "node";
1187
+ return sandbox$1.runCommand({
1188
+ cmd: runtime,
1189
+ args: [filename]
1190
+ });
1191
+ })();
969
1192
  const executeStdout = await executeCmd.stdout();
970
1193
  const executeStderr = await executeCmd.stderr();
971
1194
  if (executeStdout) {
@@ -1005,8 +1228,9 @@ var init_VercelSandboxExecutor = __esm({
1005
1228
  logs,
1006
1229
  executionTime
1007
1230
  };
1008
- } finally {
1009
- await sandbox$1.stop();
1231
+ } catch (innerError) {
1232
+ await this.removeSandbox(dependencyHash);
1233
+ throw innerError;
1010
1234
  }
1011
1235
  } catch (error) {
1012
1236
  const executionTime = Date.now() - startTime;
@@ -1027,12 +1251,6 @@ var init_VercelSandboxExecutor = __esm({
1027
1251
  };
1028
1252
  }
1029
1253
  }
1030
- /**
1031
- * Clean up resources
1032
- */
1033
- async cleanup() {
1034
- logger17.info({}, "VercelSandboxExecutor cleanup completed");
1035
- }
1036
1254
  };
1037
1255
  __publicField(_VercelSandboxExecutor, "instance");
1038
1256
  VercelSandboxExecutor = _VercelSandboxExecutor;
package/dist/index.js CHANGED
@@ -7048,7 +7048,7 @@ var Agent = class {
7048
7048
  if (functionToolsData.length === 0) {
7049
7049
  return functionTools;
7050
7050
  }
7051
- const { SandboxExecutorFactory } = await import('./SandboxExecutorFactory-FMNUKYDI.js');
7051
+ const { SandboxExecutorFactory } = await import('./SandboxExecutorFactory-QVNCS6YN.js');
7052
7052
  const sandboxExecutor = SandboxExecutorFactory.getInstance();
7053
7053
  for (const functionToolDef of functionToolsData) {
7054
7054
  const functionId = functionToolDef.functionId;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkeep/agents-run-api",
3
- "version": "0.22.12",
3
+ "version": "0.23.1",
4
4
  "description": "Agents Run API for Inkeep Agent Framework - handles chat, agent execution, and streaming",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -52,7 +52,7 @@
52
52
  "traverse": "^0.6.11",
53
53
  "ts-pattern": "^5.7.1",
54
54
  "zod": "^4.1.11",
55
- "@inkeep/agents-core": "^0.22.12"
55
+ "@inkeep/agents-core": "^0.23.1"
56
56
  },
57
57
  "optionalDependencies": {
58
58
  "keytar": "^7.9.0"