@inkeep/agents-run-api 0.22.12 → 0.23.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.
@@ -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,235 @@ 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
+ */
648
+ createEnvFileContent(envVarNames) {
649
+ const envLines = [];
650
+ for (const varName of envVarNames) {
651
+ const value = process.env[varName];
652
+ if (value !== void 0) {
653
+ const escapedValue = value.replace(/"/g, '\\"').replace(/\n/g, "\\n");
654
+ envLines.push(`${varName}="${escapedValue}"`);
655
+ logger2.debug({ varName }, "Adding environment variable to sandbox");
656
+ } else {
657
+ logger2.warn(
658
+ { varName },
659
+ "Environment variable referenced in code but not found in host environment"
660
+ );
661
+ }
662
+ }
663
+ return envLines.join("\n");
664
+ }
665
+ /**
666
+ * Execute a function tool in Vercel Sandbox with pooling
492
667
  */
493
668
  async executeFunctionTool(functionId, args, toolConfig) {
494
669
  const startTime = Date.now();
495
670
  const logs = [];
671
+ const dependencies = toolConfig.dependencies || {};
672
+ const dependencyHash = this.generateDependencyHash(dependencies);
496
673
  try {
497
674
  logger2.info(
498
675
  {
499
676
  functionId,
500
- functionName: toolConfig.name
677
+ functionName: toolConfig.name,
678
+ dependencyHash,
679
+ poolSize: this.sandboxPool.size
501
680
  },
502
681
  "Executing function in Vercel Sandbox"
503
682
  );
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
- );
683
+ let sandbox = this.getCachedSandbox(dependencyHash);
684
+ let isNewSandbox = false;
685
+ if (!sandbox) {
686
+ isNewSandbox = true;
687
+ sandbox = await Sandbox.create({
688
+ token: this.config.token,
689
+ teamId: this.config.teamId,
690
+ projectId: this.config.projectId,
691
+ timeout: this.config.timeout,
692
+ resources: {
693
+ vcpus: this.config.vcpus || 1
694
+ },
695
+ runtime: this.config.runtime
696
+ });
697
+ logger2.info(
698
+ {
699
+ functionId,
700
+ sandboxId: sandbox.sandboxId,
701
+ dependencyHash
702
+ },
703
+ `New sandbox created for function ${functionId}`
704
+ );
705
+ this.addToPool(dependencyHash, sandbox, dependencies);
706
+ } else {
707
+ logger2.info(
708
+ {
709
+ functionId,
710
+ sandboxId: sandbox.sandboxId,
711
+ dependencyHash
712
+ },
713
+ `Reusing cached sandbox for function ${functionId}`
714
+ );
715
+ }
716
+ this.incrementUseCount(dependencyHash);
521
717
  try {
522
- if (toolConfig.dependencies && Object.keys(toolConfig.dependencies).length > 0) {
718
+ if (isNewSandbox && toolConfig.dependencies && Object.keys(toolConfig.dependencies).length > 0) {
523
719
  logger2.debug(
524
720
  {
525
721
  functionId,
526
722
  functionName: toolConfig.name,
527
723
  dependencies: toolConfig.dependencies
528
724
  },
529
- "Installing dependencies"
725
+ "Installing dependencies in new sandbox"
530
726
  );
531
727
  const packageJson = {
532
728
  dependencies: toolConfig.dependencies
@@ -553,15 +749,40 @@ var _VercelSandboxExecutor = class _VercelSandboxExecutor {
553
749
  if (installCmd.exitCode !== 0) {
554
750
  throw new Error(`Failed to install dependencies: ${installStderr}`);
555
751
  }
752
+ logger2.info(
753
+ {
754
+ functionId,
755
+ dependencyHash
756
+ },
757
+ "Dependencies installed successfully"
758
+ );
556
759
  }
557
760
  const executionCode = createExecutionWrapper(toolConfig.executeCode, args);
761
+ const envVars = this.extractEnvVars(toolConfig.executeCode);
762
+ const filesToWrite = [];
558
763
  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")
764
+ filesToWrite.push({
765
+ path: filename,
766
+ content: Buffer.from(executionCode, "utf-8")
767
+ });
768
+ if (envVars.size > 0) {
769
+ const envFileContent = this.createEnvFileContent(envVars);
770
+ if (envFileContent) {
771
+ filesToWrite.push({
772
+ path: ".env",
773
+ content: Buffer.from(envFileContent, "utf-8")
774
+ });
775
+ logger2.info(
776
+ {
777
+ functionId,
778
+ envVarCount: envVars.size,
779
+ envVars: Array.from(envVars)
780
+ },
781
+ "Injecting environment variables into sandbox"
782
+ );
563
783
  }
564
- ]);
784
+ }
785
+ await sandbox.writeFiles(filesToWrite);
565
786
  logger2.info(
566
787
  {
567
788
  functionId,
@@ -569,11 +790,19 @@ var _VercelSandboxExecutor = class _VercelSandboxExecutor {
569
790
  },
570
791
  `Execution code written to file for runtime ${this.config.runtime}`
571
792
  );
572
- const runtime = this.config.runtime === "typescript" ? "tsx" : "node";
573
- const executeCmd = await sandbox.runCommand({
574
- cmd: runtime,
575
- args: [filename]
576
- });
793
+ const executeCmd = await (async () => {
794
+ if (envVars.size > 0) {
795
+ return sandbox.runCommand({
796
+ cmd: "npx",
797
+ args: this.config.runtime === "typescript" ? ["--yes", "dotenv-cli", "--", "npx", "tsx", filename] : ["--yes", "dotenv-cli", "--", "node", filename]
798
+ });
799
+ }
800
+ const runtime = this.config.runtime === "typescript" ? "tsx" : "node";
801
+ return sandbox.runCommand({
802
+ cmd: runtime,
803
+ args: [filename]
804
+ });
805
+ })();
577
806
  const executeStdout = await executeCmd.stdout();
578
807
  const executeStderr = await executeCmd.stderr();
579
808
  if (executeStdout) {
@@ -613,8 +842,9 @@ var _VercelSandboxExecutor = class _VercelSandboxExecutor {
613
842
  logs,
614
843
  executionTime
615
844
  };
616
- } finally {
617
- await sandbox.stop();
845
+ } catch (innerError) {
846
+ await this.removeSandbox(dependencyHash);
847
+ throw innerError;
618
848
  }
619
849
  } catch (error) {
620
850
  const executionTime = Date.now() - startTime;
@@ -635,12 +865,6 @@ var _VercelSandboxExecutor = class _VercelSandboxExecutor {
635
865
  };
636
866
  }
637
867
  }
638
- /**
639
- * Clean up resources
640
- */
641
- async cleanup() {
642
- logger2.info({}, "VercelSandboxExecutor cleanup completed");
643
- }
644
868
  };
645
869
  __publicField(_VercelSandboxExecutor, "instance");
646
870
  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,235 @@ 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
+ */
1041
+ createEnvFileContent(envVarNames) {
1042
+ const envLines = [];
1043
+ for (const varName of envVarNames) {
1044
+ const value = process.env[varName];
1045
+ if (value !== void 0) {
1046
+ const escapedValue = value.replace(/"/g, '\\"').replace(/\n/g, "\\n");
1047
+ envLines.push(`${varName}="${escapedValue}"`);
1048
+ logger17.debug({ varName }, "Adding environment variable to sandbox");
1049
+ } else {
1050
+ logger17.warn(
1051
+ { varName },
1052
+ "Environment variable referenced in code but not found in host environment"
1053
+ );
1054
+ }
1055
+ }
1056
+ return envLines.join("\n");
1057
+ }
1058
+ /**
1059
+ * Execute a function tool in Vercel Sandbox with pooling
884
1060
  */
885
1061
  async executeFunctionTool(functionId, args, toolConfig) {
886
1062
  const startTime = Date.now();
887
1063
  const logs = [];
1064
+ const dependencies = toolConfig.dependencies || {};
1065
+ const dependencyHash = this.generateDependencyHash(dependencies);
888
1066
  try {
889
1067
  logger17.info(
890
1068
  {
891
1069
  functionId,
892
- functionName: toolConfig.name
1070
+ functionName: toolConfig.name,
1071
+ dependencyHash,
1072
+ poolSize: this.sandboxPool.size
893
1073
  },
894
1074
  "Executing function in Vercel Sandbox"
895
1075
  );
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
- );
1076
+ let sandbox$1 = this.getCachedSandbox(dependencyHash);
1077
+ let isNewSandbox = false;
1078
+ if (!sandbox$1) {
1079
+ isNewSandbox = true;
1080
+ sandbox$1 = await sandbox.Sandbox.create({
1081
+ token: this.config.token,
1082
+ teamId: this.config.teamId,
1083
+ projectId: this.config.projectId,
1084
+ timeout: this.config.timeout,
1085
+ resources: {
1086
+ vcpus: this.config.vcpus || 1
1087
+ },
1088
+ runtime: this.config.runtime
1089
+ });
1090
+ logger17.info(
1091
+ {
1092
+ functionId,
1093
+ sandboxId: sandbox$1.sandboxId,
1094
+ dependencyHash
1095
+ },
1096
+ `New sandbox created for function ${functionId}`
1097
+ );
1098
+ this.addToPool(dependencyHash, sandbox$1, dependencies);
1099
+ } else {
1100
+ logger17.info(
1101
+ {
1102
+ functionId,
1103
+ sandboxId: sandbox$1.sandboxId,
1104
+ dependencyHash
1105
+ },
1106
+ `Reusing cached sandbox for function ${functionId}`
1107
+ );
1108
+ }
1109
+ this.incrementUseCount(dependencyHash);
913
1110
  try {
914
- if (toolConfig.dependencies && Object.keys(toolConfig.dependencies).length > 0) {
1111
+ if (isNewSandbox && toolConfig.dependencies && Object.keys(toolConfig.dependencies).length > 0) {
915
1112
  logger17.debug(
916
1113
  {
917
1114
  functionId,
918
1115
  functionName: toolConfig.name,
919
1116
  dependencies: toolConfig.dependencies
920
1117
  },
921
- "Installing dependencies"
1118
+ "Installing dependencies in new sandbox"
922
1119
  );
923
1120
  const packageJson = {
924
1121
  dependencies: toolConfig.dependencies
@@ -945,15 +1142,40 @@ var init_VercelSandboxExecutor = __esm({
945
1142
  if (installCmd.exitCode !== 0) {
946
1143
  throw new Error(`Failed to install dependencies: ${installStderr}`);
947
1144
  }
1145
+ logger17.info(
1146
+ {
1147
+ functionId,
1148
+ dependencyHash
1149
+ },
1150
+ "Dependencies installed successfully"
1151
+ );
948
1152
  }
949
1153
  const executionCode = createExecutionWrapper(toolConfig.executeCode, args);
1154
+ const envVars = this.extractEnvVars(toolConfig.executeCode);
1155
+ const filesToWrite = [];
950
1156
  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")
1157
+ filesToWrite.push({
1158
+ path: filename,
1159
+ content: Buffer.from(executionCode, "utf-8")
1160
+ });
1161
+ if (envVars.size > 0) {
1162
+ const envFileContent = this.createEnvFileContent(envVars);
1163
+ if (envFileContent) {
1164
+ filesToWrite.push({
1165
+ path: ".env",
1166
+ content: Buffer.from(envFileContent, "utf-8")
1167
+ });
1168
+ logger17.info(
1169
+ {
1170
+ functionId,
1171
+ envVarCount: envVars.size,
1172
+ envVars: Array.from(envVars)
1173
+ },
1174
+ "Injecting environment variables into sandbox"
1175
+ );
955
1176
  }
956
- ]);
1177
+ }
1178
+ await sandbox$1.writeFiles(filesToWrite);
957
1179
  logger17.info(
958
1180
  {
959
1181
  functionId,
@@ -961,11 +1183,19 @@ var init_VercelSandboxExecutor = __esm({
961
1183
  },
962
1184
  `Execution code written to file for runtime ${this.config.runtime}`
963
1185
  );
964
- const runtime = this.config.runtime === "typescript" ? "tsx" : "node";
965
- const executeCmd = await sandbox$1.runCommand({
966
- cmd: runtime,
967
- args: [filename]
968
- });
1186
+ const executeCmd = await (async () => {
1187
+ if (envVars.size > 0) {
1188
+ return sandbox$1.runCommand({
1189
+ cmd: "npx",
1190
+ args: this.config.runtime === "typescript" ? ["--yes", "dotenv-cli", "--", "npx", "tsx", filename] : ["--yes", "dotenv-cli", "--", "node", filename]
1191
+ });
1192
+ }
1193
+ const runtime = this.config.runtime === "typescript" ? "tsx" : "node";
1194
+ return sandbox$1.runCommand({
1195
+ cmd: runtime,
1196
+ args: [filename]
1197
+ });
1198
+ })();
969
1199
  const executeStdout = await executeCmd.stdout();
970
1200
  const executeStderr = await executeCmd.stderr();
971
1201
  if (executeStdout) {
@@ -1005,8 +1235,9 @@ var init_VercelSandboxExecutor = __esm({
1005
1235
  logs,
1006
1236
  executionTime
1007
1237
  };
1008
- } finally {
1009
- await sandbox$1.stop();
1238
+ } catch (innerError) {
1239
+ await this.removeSandbox(dependencyHash);
1240
+ throw innerError;
1010
1241
  }
1011
1242
  } catch (error) {
1012
1243
  const executionTime = Date.now() - startTime;
@@ -1027,12 +1258,6 @@ var init_VercelSandboxExecutor = __esm({
1027
1258
  };
1028
1259
  }
1029
1260
  }
1030
- /**
1031
- * Clean up resources
1032
- */
1033
- async cleanup() {
1034
- logger17.info({}, "VercelSandboxExecutor cleanup completed");
1035
- }
1036
1261
  };
1037
1262
  __publicField(_VercelSandboxExecutor, "instance");
1038
1263
  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-VKLSUHMW.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.0",
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.0"
56
56
  },
57
57
  "optionalDependencies": {
58
58
  "keytar": "^7.9.0"