agent-swarm-kit 1.1.59 → 1.1.61

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.
package/build/index.cjs CHANGED
@@ -104,6 +104,7 @@ const validationServices$1 = {
104
104
  computeValidationService: Symbol('computeValidationService'),
105
105
  stateValidationService: Symbol('stateValidationService'),
106
106
  pipelineValidationService: Symbol('pipelineValidationService'),
107
+ executionValidationService: Symbol('executionValidationService'),
107
108
  };
108
109
  const TYPES = {
109
110
  ...baseServices$1,
@@ -2443,27 +2444,16 @@ const nameToTitle = (name) => {
2443
2444
  */
2444
2445
  const beginContext = (run) => (...args) => {
2445
2446
  let fn = () => run(...args);
2447
+ if (ExecutionContextService.hasContext()) {
2448
+ const { clientId, executionId } = swarm$1.executionContextService.context;
2449
+ swarm$1.executionValidationService.incrementCount(executionId, clientId);
2450
+ }
2446
2451
  if (MethodContextService.hasContext()) {
2447
2452
  fn = MethodContextService.runOutOfContext(fn);
2448
2453
  }
2449
2454
  if (ExecutionContextService.hasContext()) {
2450
2455
  fn = ExecutionContextService.runOutOfContext(fn);
2451
2456
  }
2452
- /*
2453
-
2454
- // TODO: wait for asyncLocalStorage.disable() stability
2455
- if (
2456
- MethodContextService.hasContext() ||
2457
- ExecutionContextService.hasContext()
2458
- ) {
2459
- const resource = new AsyncResource("UNTRACKED");
2460
- const result = resource.runInAsyncScope(() => run(...args));
2461
- resource.emitDestroy();
2462
- return result;
2463
- }
2464
- return run(...args);
2465
-
2466
- */
2467
2457
  return fn();
2468
2458
  };
2469
2459
 
@@ -3115,6 +3105,11 @@ const CC_ENABLE_OPERATOR_TIMEOUT = false;
3115
3105
  * Disable fetch of data from all storages. Quite usefull for unit tests
3116
3106
  */
3117
3107
  const CC_STORAGE_DISABLE_GET_DATA = false;
3108
+ /**
3109
+ * When the model run more than 10 nested tool call iterations including
3110
+ * navigations throw an exeption
3111
+ */
3112
+ const CC_MAX_NESTED_EXECUTIONS = 10;
3118
3113
  const GLOBAL_CONFIG = {
3119
3114
  CC_TOOL_CALL_EXCEPTION_FLUSH_PROMPT,
3120
3115
  CC_TOOL_CALL_EXCEPTION_RECOMPLETE_PROMPT,
@@ -3166,6 +3161,7 @@ const GLOBAL_CONFIG = {
3166
3161
  CC_DEFAULT_CONNECT_OPERATOR,
3167
3162
  CC_ENABLE_OPERATOR_TIMEOUT,
3168
3163
  CC_STORAGE_DISABLE_GET_DATA,
3164
+ CC_MAX_NESTED_EXECUTIONS,
3169
3165
  };
3170
3166
  GLOBAL_CONFIG.CC_RESQUE_STRATEGY = "flush";
3171
3167
  /**
@@ -5010,6 +5006,7 @@ const executeInternal = beginContext(async (content, clientId, agentName) => {
5010
5006
  if (!isFinished) {
5011
5007
  swarm$1.perfService.endExecution(executionId, clientId, 0);
5012
5008
  }
5009
+ swarm$1.executionValidationService.decrementCount(executionId, clientId, swarmName);
5013
5010
  }
5014
5011
  }, {
5015
5012
  clientId,
@@ -8846,6 +8843,13 @@ class SessionPublicService {
8846
8843
  * @private
8847
8844
  */
8848
8845
  this.perfService = inject(TYPES.perfService);
8846
+ /**
8847
+ * Service for execution validation to prevent the model to call the tools
8848
+ * recursively
8849
+ * @type {ExecutionValidationService}
8850
+ * @private
8851
+ */
8852
+ this.executionValidationService = inject(TYPES.executionValidationService);
8849
8853
  /**
8850
8854
  * Session connection service instance, injected via DI, for underlying session operations.
8851
8855
  * Provides core functionality (e.g., emit, execute) called by public methods, supporting ClientAgent’s session model.
@@ -9036,6 +9040,7 @@ class SessionPublicService {
9036
9040
  if (!isFinished) {
9037
9041
  this.perfService.endExecution(executionId, clientId, 0);
9038
9042
  }
9043
+ this.executionValidationService.decrementCount(executionId, clientId, swarmName);
9039
9044
  }
9040
9045
  }, {
9041
9046
  clientId,
@@ -17682,6 +17687,96 @@ class PipelineValidationService {
17682
17687
  }
17683
17688
  }
17684
17689
 
17690
+ /**
17691
+ * @module ExecutionValidationService
17692
+ * @description Service for validating and managing execution counts for client sessions in a swarm context.
17693
+ */
17694
+ /**
17695
+ * @class ExecutionValidationService
17696
+ * @description Manages execution count validation to prevent excessive nested executions within a swarm.
17697
+ */
17698
+ class ExecutionValidationService {
17699
+ constructor() {
17700
+ /**
17701
+ * @private
17702
+ * @type {LoggerService}
17703
+ * @description Injected logger service for logging execution-related information.
17704
+ */
17705
+ this.loggerService = inject(TYPES.loggerService);
17706
+ /**
17707
+ * @private
17708
+ * @type {SessionValidationService}
17709
+ * @description Injected session validation service for checking client sessions and swarm associations.
17710
+ */
17711
+ this.sessionValidationService = inject(TYPES.sessionValidationService);
17712
+ /**
17713
+ * Retrieves a memoized set of execution IDs for a given client and swarm.
17714
+ * @param {string} clientId - The unique identifier for the client.
17715
+ * @param {SwarmName} swarmName - The name of the swarm associated with the client.
17716
+ * @returns {Set<ExecutionId>} A set containing execution IDs for the client and swarm.
17717
+ */
17718
+ this.getExecutionCount = functoolsKit.memoize(([clientId, swarmName]) => `${clientId}-${swarmName}`, () => new Set());
17719
+ /**
17720
+ * Increments the execution count for a client and checks for excessive nested executions.
17721
+ * @param {string} executionId - The unique identifier for the execution.
17722
+ * @param {string} clientId - The unique identifier for the client.
17723
+ * @param {SwarmName} swarmName - The name of the swarm associated with the client.
17724
+ * @throws {Error} If the maximum nested execution limit is reached.
17725
+ * @returns {void}
17726
+ */
17727
+ this.incrementCount = (executionId, clientId) => {
17728
+ GLOBAL_CONFIG.CC_LOGGER_ENABLE_INFO &&
17729
+ this.loggerService.info("executionValidationService incrementCount", {
17730
+ clientId,
17731
+ executionId,
17732
+ });
17733
+ if (!this.sessionValidationService.hasSession(clientId)) {
17734
+ return;
17735
+ }
17736
+ const swarmName = this.sessionValidationService.getSwarm(clientId);
17737
+ const { size } = this.getExecutionCount(clientId, swarmName).add(executionId);
17738
+ if (size >= GLOBAL_CONFIG.CC_MAX_NESTED_EXECUTIONS) {
17739
+ const msg = `agent-swarm recursive execution prevented for clientId=${clientId} swarmName=${swarmName} executionId=${executionId} size=${size}`;
17740
+ console.error(msg);
17741
+ throw new Error(msg);
17742
+ }
17743
+ };
17744
+ /**
17745
+ * Resets the execution count for a client and swarm.
17746
+ * @param {string} executionId - The unique identifier for the execution.
17747
+ * @param {string} clientId - The unique identifier for the client.
17748
+ * @param {SwarmName} swarmName - The name of the swarm associated with the client.
17749
+ * @returns {void}
17750
+ */
17751
+ this.decrementCount = (executionId, clientId, swarmName) => {
17752
+ GLOBAL_CONFIG.CC_LOGGER_ENABLE_INFO &&
17753
+ this.loggerService.info("executionValidationService decrementCount", {
17754
+ clientId,
17755
+ executionId,
17756
+ swarmName,
17757
+ });
17758
+ if (!this.sessionValidationService.hasSession(clientId)) {
17759
+ return;
17760
+ }
17761
+ this.getExecutionCount(clientId, swarmName).delete(executionId);
17762
+ };
17763
+ /**
17764
+ * Clears the memoized execution count for a specific client and swarm.
17765
+ * @param {string} clientId - The unique identifier for the client.
17766
+ * @param {SwarmName} swarmName - The name of the swarm associated with the client.
17767
+ * @returns {void}
17768
+ */
17769
+ this.dispose = (clientId, swarmName) => {
17770
+ GLOBAL_CONFIG.CC_LOGGER_ENABLE_INFO &&
17771
+ this.loggerService.info("executionValidationService dispose", {
17772
+ clientId,
17773
+ swarmName,
17774
+ });
17775
+ this.getExecutionCount.clear(`${clientId}-${swarmName}`);
17776
+ };
17777
+ }
17778
+ }
17779
+
17685
17780
  {
17686
17781
  provide(TYPES.docService, () => new DocService());
17687
17782
  provide(TYPES.busService, () => new BusService());
@@ -17757,6 +17852,7 @@ class PipelineValidationService {
17757
17852
  provide(TYPES.computeValidationService, () => new ComputeValidationService());
17758
17853
  provide(TYPES.stateValidationService, () => new StateValidationService());
17759
17854
  provide(TYPES.pipelineValidationService, () => new PipelineValidationService());
17855
+ provide(TYPES.executionValidationService, () => new ExecutionValidationService());
17760
17856
  }
17761
17857
 
17762
17858
  const baseServices = {
@@ -17834,6 +17930,7 @@ const validationServices = {
17834
17930
  computeValidationService: inject(TYPES.computeValidationService),
17835
17931
  stateValidationService: inject(TYPES.stateValidationService),
17836
17932
  pipelineValidationService: inject(TYPES.pipelineValidationService),
17933
+ executionValidationService: inject(TYPES.executionValidationService),
17837
17934
  };
17838
17935
  /** @inheritDoc */
17839
17936
  const swarm = {
@@ -18366,6 +18463,7 @@ const executeForceInternal = beginContext(async (content, clientId) => {
18366
18463
  if (!isFinished) {
18367
18464
  swarm$1.perfService.endExecution(executionId, clientId, 0);
18368
18465
  }
18466
+ swarm$1.executionValidationService.decrementCount(executionId, clientId, swarmName);
18369
18467
  }
18370
18468
  }, {
18371
18469
  clientId,
@@ -20437,6 +20535,7 @@ const disposeConnection = beginContext(async (clientId, swarmName, methodName =
20437
20535
  {
20438
20536
  swarm$1.sessionValidationService.removeSession(clientId);
20439
20537
  swarm$1.navigationValidationService.dispose(clientId, swarmName);
20538
+ swarm$1.executionValidationService.dispose(clientId, swarmName);
20440
20539
  }
20441
20540
  PersistMemoryAdapter.dispose(clientId);
20442
20541
  });
@@ -20654,6 +20753,7 @@ const runStatelessInternal = beginContext(async (content, clientId, agentName) =
20654
20753
  if (!isFinished) {
20655
20754
  swarm$1.perfService.endExecution(executionId, clientId, 0);
20656
20755
  }
20756
+ swarm$1.executionValidationService.decrementCount(executionId, clientId, swarmName);
20657
20757
  }
20658
20758
  }, {
20659
20759
  clientId,
@@ -20715,6 +20815,7 @@ const runStatelessForceInternal = beginContext(async (content, clientId) => {
20715
20815
  if (!isFinished) {
20716
20816
  swarm$1.perfService.endExecution(executionId, clientId, 0);
20717
20817
  }
20818
+ swarm$1.executionValidationService.decrementCount(executionId, clientId, swarmName);
20718
20819
  }
20719
20820
  }, {
20720
20821
  clientId,
@@ -21013,6 +21114,7 @@ const complete = beginContext(async (content, clientId, swarmName, payload = nul
21013
21114
  if (!isFinished) {
21014
21115
  swarm$1.perfService.endExecution(executionId, clientId, 0);
21015
21116
  }
21117
+ swarm$1.executionValidationService.decrementCount(executionId, clientId, swarmName);
21016
21118
  }
21017
21119
  }, {
21018
21120
  clientId,
@@ -21074,6 +21176,7 @@ const sessionInternal = (clientId, swarmName, { onDispose = () => { } } = {}) =>
21074
21176
  if (!isFinished) {
21075
21177
  swarm$1.perfService.endExecution(executionId, clientId, 0);
21076
21178
  }
21179
+ swarm$1.executionValidationService.decrementCount(executionId, clientId, swarmName);
21077
21180
  }
21078
21181
  }, {
21079
21182
  clientId,
package/build/index.mjs CHANGED
@@ -102,6 +102,7 @@ const validationServices$1 = {
102
102
  computeValidationService: Symbol('computeValidationService'),
103
103
  stateValidationService: Symbol('stateValidationService'),
104
104
  pipelineValidationService: Symbol('pipelineValidationService'),
105
+ executionValidationService: Symbol('executionValidationService'),
105
106
  };
106
107
  const TYPES = {
107
108
  ...baseServices$1,
@@ -2441,27 +2442,16 @@ const nameToTitle = (name) => {
2441
2442
  */
2442
2443
  const beginContext = (run) => (...args) => {
2443
2444
  let fn = () => run(...args);
2445
+ if (ExecutionContextService.hasContext()) {
2446
+ const { clientId, executionId } = swarm$1.executionContextService.context;
2447
+ swarm$1.executionValidationService.incrementCount(executionId, clientId);
2448
+ }
2444
2449
  if (MethodContextService.hasContext()) {
2445
2450
  fn = MethodContextService.runOutOfContext(fn);
2446
2451
  }
2447
2452
  if (ExecutionContextService.hasContext()) {
2448
2453
  fn = ExecutionContextService.runOutOfContext(fn);
2449
2454
  }
2450
- /*
2451
-
2452
- // TODO: wait for asyncLocalStorage.disable() stability
2453
- if (
2454
- MethodContextService.hasContext() ||
2455
- ExecutionContextService.hasContext()
2456
- ) {
2457
- const resource = new AsyncResource("UNTRACKED");
2458
- const result = resource.runInAsyncScope(() => run(...args));
2459
- resource.emitDestroy();
2460
- return result;
2461
- }
2462
- return run(...args);
2463
-
2464
- */
2465
2455
  return fn();
2466
2456
  };
2467
2457
 
@@ -3113,6 +3103,11 @@ const CC_ENABLE_OPERATOR_TIMEOUT = false;
3113
3103
  * Disable fetch of data from all storages. Quite usefull for unit tests
3114
3104
  */
3115
3105
  const CC_STORAGE_DISABLE_GET_DATA = false;
3106
+ /**
3107
+ * When the model run more than 10 nested tool call iterations including
3108
+ * navigations throw an exeption
3109
+ */
3110
+ const CC_MAX_NESTED_EXECUTIONS = 10;
3116
3111
  const GLOBAL_CONFIG = {
3117
3112
  CC_TOOL_CALL_EXCEPTION_FLUSH_PROMPT,
3118
3113
  CC_TOOL_CALL_EXCEPTION_RECOMPLETE_PROMPT,
@@ -3164,6 +3159,7 @@ const GLOBAL_CONFIG = {
3164
3159
  CC_DEFAULT_CONNECT_OPERATOR,
3165
3160
  CC_ENABLE_OPERATOR_TIMEOUT,
3166
3161
  CC_STORAGE_DISABLE_GET_DATA,
3162
+ CC_MAX_NESTED_EXECUTIONS,
3167
3163
  };
3168
3164
  GLOBAL_CONFIG.CC_RESQUE_STRATEGY = "flush";
3169
3165
  /**
@@ -5008,6 +5004,7 @@ const executeInternal = beginContext(async (content, clientId, agentName) => {
5008
5004
  if (!isFinished) {
5009
5005
  swarm$1.perfService.endExecution(executionId, clientId, 0);
5010
5006
  }
5007
+ swarm$1.executionValidationService.decrementCount(executionId, clientId, swarmName);
5011
5008
  }
5012
5009
  }, {
5013
5010
  clientId,
@@ -8844,6 +8841,13 @@ class SessionPublicService {
8844
8841
  * @private
8845
8842
  */
8846
8843
  this.perfService = inject(TYPES.perfService);
8844
+ /**
8845
+ * Service for execution validation to prevent the model to call the tools
8846
+ * recursively
8847
+ * @type {ExecutionValidationService}
8848
+ * @private
8849
+ */
8850
+ this.executionValidationService = inject(TYPES.executionValidationService);
8847
8851
  /**
8848
8852
  * Session connection service instance, injected via DI, for underlying session operations.
8849
8853
  * Provides core functionality (e.g., emit, execute) called by public methods, supporting ClientAgent’s session model.
@@ -9034,6 +9038,7 @@ class SessionPublicService {
9034
9038
  if (!isFinished) {
9035
9039
  this.perfService.endExecution(executionId, clientId, 0);
9036
9040
  }
9041
+ this.executionValidationService.decrementCount(executionId, clientId, swarmName);
9037
9042
  }
9038
9043
  }, {
9039
9044
  clientId,
@@ -17680,6 +17685,96 @@ class PipelineValidationService {
17680
17685
  }
17681
17686
  }
17682
17687
 
17688
+ /**
17689
+ * @module ExecutionValidationService
17690
+ * @description Service for validating and managing execution counts for client sessions in a swarm context.
17691
+ */
17692
+ /**
17693
+ * @class ExecutionValidationService
17694
+ * @description Manages execution count validation to prevent excessive nested executions within a swarm.
17695
+ */
17696
+ class ExecutionValidationService {
17697
+ constructor() {
17698
+ /**
17699
+ * @private
17700
+ * @type {LoggerService}
17701
+ * @description Injected logger service for logging execution-related information.
17702
+ */
17703
+ this.loggerService = inject(TYPES.loggerService);
17704
+ /**
17705
+ * @private
17706
+ * @type {SessionValidationService}
17707
+ * @description Injected session validation service for checking client sessions and swarm associations.
17708
+ */
17709
+ this.sessionValidationService = inject(TYPES.sessionValidationService);
17710
+ /**
17711
+ * Retrieves a memoized set of execution IDs for a given client and swarm.
17712
+ * @param {string} clientId - The unique identifier for the client.
17713
+ * @param {SwarmName} swarmName - The name of the swarm associated with the client.
17714
+ * @returns {Set<ExecutionId>} A set containing execution IDs for the client and swarm.
17715
+ */
17716
+ this.getExecutionCount = memoize(([clientId, swarmName]) => `${clientId}-${swarmName}`, () => new Set());
17717
+ /**
17718
+ * Increments the execution count for a client and checks for excessive nested executions.
17719
+ * @param {string} executionId - The unique identifier for the execution.
17720
+ * @param {string} clientId - The unique identifier for the client.
17721
+ * @param {SwarmName} swarmName - The name of the swarm associated with the client.
17722
+ * @throws {Error} If the maximum nested execution limit is reached.
17723
+ * @returns {void}
17724
+ */
17725
+ this.incrementCount = (executionId, clientId) => {
17726
+ GLOBAL_CONFIG.CC_LOGGER_ENABLE_INFO &&
17727
+ this.loggerService.info("executionValidationService incrementCount", {
17728
+ clientId,
17729
+ executionId,
17730
+ });
17731
+ if (!this.sessionValidationService.hasSession(clientId)) {
17732
+ return;
17733
+ }
17734
+ const swarmName = this.sessionValidationService.getSwarm(clientId);
17735
+ const { size } = this.getExecutionCount(clientId, swarmName).add(executionId);
17736
+ if (size >= GLOBAL_CONFIG.CC_MAX_NESTED_EXECUTIONS) {
17737
+ const msg = `agent-swarm recursive execution prevented for clientId=${clientId} swarmName=${swarmName} executionId=${executionId} size=${size}`;
17738
+ console.error(msg);
17739
+ throw new Error(msg);
17740
+ }
17741
+ };
17742
+ /**
17743
+ * Resets the execution count for a client and swarm.
17744
+ * @param {string} executionId - The unique identifier for the execution.
17745
+ * @param {string} clientId - The unique identifier for the client.
17746
+ * @param {SwarmName} swarmName - The name of the swarm associated with the client.
17747
+ * @returns {void}
17748
+ */
17749
+ this.decrementCount = (executionId, clientId, swarmName) => {
17750
+ GLOBAL_CONFIG.CC_LOGGER_ENABLE_INFO &&
17751
+ this.loggerService.info("executionValidationService decrementCount", {
17752
+ clientId,
17753
+ executionId,
17754
+ swarmName,
17755
+ });
17756
+ if (!this.sessionValidationService.hasSession(clientId)) {
17757
+ return;
17758
+ }
17759
+ this.getExecutionCount(clientId, swarmName).delete(executionId);
17760
+ };
17761
+ /**
17762
+ * Clears the memoized execution count for a specific client and swarm.
17763
+ * @param {string} clientId - The unique identifier for the client.
17764
+ * @param {SwarmName} swarmName - The name of the swarm associated with the client.
17765
+ * @returns {void}
17766
+ */
17767
+ this.dispose = (clientId, swarmName) => {
17768
+ GLOBAL_CONFIG.CC_LOGGER_ENABLE_INFO &&
17769
+ this.loggerService.info("executionValidationService dispose", {
17770
+ clientId,
17771
+ swarmName,
17772
+ });
17773
+ this.getExecutionCount.clear(`${clientId}-${swarmName}`);
17774
+ };
17775
+ }
17776
+ }
17777
+
17683
17778
  {
17684
17779
  provide(TYPES.docService, () => new DocService());
17685
17780
  provide(TYPES.busService, () => new BusService());
@@ -17755,6 +17850,7 @@ class PipelineValidationService {
17755
17850
  provide(TYPES.computeValidationService, () => new ComputeValidationService());
17756
17851
  provide(TYPES.stateValidationService, () => new StateValidationService());
17757
17852
  provide(TYPES.pipelineValidationService, () => new PipelineValidationService());
17853
+ provide(TYPES.executionValidationService, () => new ExecutionValidationService());
17758
17854
  }
17759
17855
 
17760
17856
  const baseServices = {
@@ -17832,6 +17928,7 @@ const validationServices = {
17832
17928
  computeValidationService: inject(TYPES.computeValidationService),
17833
17929
  stateValidationService: inject(TYPES.stateValidationService),
17834
17930
  pipelineValidationService: inject(TYPES.pipelineValidationService),
17931
+ executionValidationService: inject(TYPES.executionValidationService),
17835
17932
  };
17836
17933
  /** @inheritDoc */
17837
17934
  const swarm = {
@@ -18364,6 +18461,7 @@ const executeForceInternal = beginContext(async (content, clientId) => {
18364
18461
  if (!isFinished) {
18365
18462
  swarm$1.perfService.endExecution(executionId, clientId, 0);
18366
18463
  }
18464
+ swarm$1.executionValidationService.decrementCount(executionId, clientId, swarmName);
18367
18465
  }
18368
18466
  }, {
18369
18467
  clientId,
@@ -20435,6 +20533,7 @@ const disposeConnection = beginContext(async (clientId, swarmName, methodName =
20435
20533
  {
20436
20534
  swarm$1.sessionValidationService.removeSession(clientId);
20437
20535
  swarm$1.navigationValidationService.dispose(clientId, swarmName);
20536
+ swarm$1.executionValidationService.dispose(clientId, swarmName);
20438
20537
  }
20439
20538
  PersistMemoryAdapter.dispose(clientId);
20440
20539
  });
@@ -20652,6 +20751,7 @@ const runStatelessInternal = beginContext(async (content, clientId, agentName) =
20652
20751
  if (!isFinished) {
20653
20752
  swarm$1.perfService.endExecution(executionId, clientId, 0);
20654
20753
  }
20754
+ swarm$1.executionValidationService.decrementCount(executionId, clientId, swarmName);
20655
20755
  }
20656
20756
  }, {
20657
20757
  clientId,
@@ -20713,6 +20813,7 @@ const runStatelessForceInternal = beginContext(async (content, clientId) => {
20713
20813
  if (!isFinished) {
20714
20814
  swarm$1.perfService.endExecution(executionId, clientId, 0);
20715
20815
  }
20816
+ swarm$1.executionValidationService.decrementCount(executionId, clientId, swarmName);
20716
20817
  }
20717
20818
  }, {
20718
20819
  clientId,
@@ -21011,6 +21112,7 @@ const complete = beginContext(async (content, clientId, swarmName, payload = nul
21011
21112
  if (!isFinished) {
21012
21113
  swarm$1.perfService.endExecution(executionId, clientId, 0);
21013
21114
  }
21115
+ swarm$1.executionValidationService.decrementCount(executionId, clientId, swarmName);
21014
21116
  }
21015
21117
  }, {
21016
21118
  clientId,
@@ -21072,6 +21174,7 @@ const sessionInternal = (clientId, swarmName, { onDispose = () => { } } = {}) =>
21072
21174
  if (!isFinished) {
21073
21175
  swarm$1.perfService.endExecution(executionId, clientId, 0);
21074
21176
  }
21177
+ swarm$1.executionValidationService.decrementCount(executionId, clientId, swarmName);
21075
21178
  }
21076
21179
  }, {
21077
21180
  clientId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-swarm-kit",
3
- "version": "1.1.59",
3
+ "version": "1.1.61",
4
4
  "description": "A TypeScript library for building orchestrated framework-agnostic multi-agent AI systems",
5
5
  "author": {
6
6
  "name": "Petr Tripolsky",
package/types.d.ts CHANGED
@@ -6006,6 +6006,13 @@ declare class SessionPublicService implements TSessionConnectionService {
6006
6006
  * @private
6007
6007
  */
6008
6008
  private readonly perfService;
6009
+ /**
6010
+ * Service for execution validation to prevent the model to call the tools
6011
+ * recursively
6012
+ * @type {ExecutionValidationService}
6013
+ * @private
6014
+ */
6015
+ private readonly executionValidationService;
6009
6016
  /**
6010
6017
  * Session connection service instance, injected via DI, for underlying session operations.
6011
6018
  * Provides core functionality (e.g., emit, execute) called by public methods, supporting ClientAgent’s session model.
@@ -10597,6 +10604,61 @@ declare class PipelineValidationService {
10597
10604
  validate: (pipelineName: PipelineName, source: string) => void;
10598
10605
  }
10599
10606
 
10607
+ /**
10608
+ * @typedef {string} ExecutionId
10609
+ * @description A unique identifier for an execution instance.
10610
+ */
10611
+ type ExecutionId = string;
10612
+ /**
10613
+ * @class ExecutionValidationService
10614
+ * @description Manages execution count validation to prevent excessive nested executions within a swarm.
10615
+ */
10616
+ declare class ExecutionValidationService {
10617
+ /**
10618
+ * @private
10619
+ * @type {LoggerService}
10620
+ * @description Injected logger service for logging execution-related information.
10621
+ */
10622
+ private readonly loggerService;
10623
+ /**
10624
+ * @private
10625
+ * @type {SessionValidationService}
10626
+ * @description Injected session validation service for checking client sessions and swarm associations.
10627
+ */
10628
+ private readonly sessionValidationService;
10629
+ /**
10630
+ * Retrieves a memoized set of execution IDs for a given client and swarm.
10631
+ * @param {string} clientId - The unique identifier for the client.
10632
+ * @param {SwarmName} swarmName - The name of the swarm associated with the client.
10633
+ * @returns {Set<ExecutionId>} A set containing execution IDs for the client and swarm.
10634
+ */
10635
+ getExecutionCount: ((clientId: string, swarmName: SwarmName) => Set<ExecutionId>) & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<string, Set<string>>;
10636
+ /**
10637
+ * Increments the execution count for a client and checks for excessive nested executions.
10638
+ * @param {string} executionId - The unique identifier for the execution.
10639
+ * @param {string} clientId - The unique identifier for the client.
10640
+ * @param {SwarmName} swarmName - The name of the swarm associated with the client.
10641
+ * @throws {Error} If the maximum nested execution limit is reached.
10642
+ * @returns {void}
10643
+ */
10644
+ incrementCount: (executionId: string, clientId: string) => void;
10645
+ /**
10646
+ * Resets the execution count for a client and swarm.
10647
+ * @param {string} executionId - The unique identifier for the execution.
10648
+ * @param {string} clientId - The unique identifier for the client.
10649
+ * @param {SwarmName} swarmName - The name of the swarm associated with the client.
10650
+ * @returns {void}
10651
+ */
10652
+ decrementCount: (executionId: string, clientId: string, swarmName: SwarmName) => void;
10653
+ /**
10654
+ * Clears the memoized execution count for a specific client and swarm.
10655
+ * @param {string} clientId - The unique identifier for the client.
10656
+ * @param {SwarmName} swarmName - The name of the swarm associated with the client.
10657
+ * @returns {void}
10658
+ */
10659
+ dispose: (clientId: string, swarmName: SwarmName) => void;
10660
+ }
10661
+
10600
10662
  /**
10601
10663
  * Interface defining the structure of the dependency injection container for the swarm system.
10602
10664
  * Aggregates all services providing core functionality, context management, connectivity, schema definitions,
@@ -10911,6 +10973,11 @@ interface ISwarmDI {
10911
10973
  * Ensures pipeline integrity via `PipelineValidationService`.
10912
10974
  */
10913
10975
  pipelineValidationService: PipelineValidationService;
10976
+ /**
10977
+ * Service for validating nested executions
10978
+ * Used to prevent the model to call tools recursively
10979
+ */
10980
+ executionValidationService: ExecutionValidationService;
10914
10981
  }
10915
10982
 
10916
10983
  /** @inheritDoc */
@@ -13752,6 +13819,11 @@ interface IGlobalConfig {
13752
13819
  * Disable fetch of data from all storages. Quite usefull for unit tests
13753
13820
  */
13754
13821
  CC_STORAGE_DISABLE_GET_DATA: boolean;
13822
+ /**
13823
+ * When the model run more than 10 nested tool call iterations including
13824
+ * navigations throw an exeption
13825
+ */
13826
+ CC_MAX_NESTED_EXECUTIONS: number;
13755
13827
  }
13756
13828
 
13757
13829
  declare const GLOBAL_CONFIG: IGlobalConfig;