@google/gemini-cli-core 0.15.0-preview.3 → 0.16.0-nightly.20251113.ad1f0d99

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 (144) hide show
  1. package/dist/google-gemini-cli-core-0.16.0-nightly.20251112.c961f274.tgz +0 -0
  2. package/dist/src/agents/codebase-investigator.test.d.ts +6 -0
  3. package/dist/src/agents/codebase-investigator.test.js +35 -0
  4. package/dist/src/agents/codebase-investigator.test.js.map +1 -0
  5. package/dist/src/agents/executor.test.js +181 -1
  6. package/dist/src/agents/executor.test.js.map +1 -1
  7. package/dist/src/code_assist/codeAssist.test.d.ts +6 -0
  8. package/dist/src/code_assist/codeAssist.test.js +99 -0
  9. package/dist/src/code_assist/codeAssist.test.js.map +1 -0
  10. package/dist/src/code_assist/experiments/client_metadata.js +2 -1
  11. package/dist/src/code_assist/experiments/client_metadata.js.map +1 -1
  12. package/dist/src/code_assist/experiments/client_metadata.test.d.ts +6 -0
  13. package/dist/src/code_assist/experiments/client_metadata.test.js +99 -0
  14. package/dist/src/code_assist/experiments/client_metadata.test.js.map +1 -0
  15. package/dist/src/code_assist/experiments/experiments.test.d.ts +6 -0
  16. package/dist/src/code_assist/experiments/experiments.test.js +92 -0
  17. package/dist/src/code_assist/experiments/experiments.test.js.map +1 -0
  18. package/dist/src/code_assist/oauth-credential-storage.test.js +49 -0
  19. package/dist/src/code_assist/oauth-credential-storage.test.js.map +1 -1
  20. package/dist/src/code_assist/server.js +5 -8
  21. package/dist/src/code_assist/server.js.map +1 -1
  22. package/dist/src/code_assist/server.test.js +109 -28
  23. package/dist/src/code_assist/server.test.js.map +1 -1
  24. package/dist/src/config/defaultModelConfigs.js +6 -0
  25. package/dist/src/config/defaultModelConfigs.js.map +1 -1
  26. package/dist/src/confirmation-bus/message-bus.d.ts +1 -1
  27. package/dist/src/confirmation-bus/message-bus.js +2 -2
  28. package/dist/src/confirmation-bus/message-bus.js.map +1 -1
  29. package/dist/src/confirmation-bus/message-bus.test.js +30 -24
  30. package/dist/src/confirmation-bus/message-bus.test.js.map +1 -1
  31. package/dist/src/core/loggingContentGenerator.test.d.ts +6 -0
  32. package/dist/src/core/loggingContentGenerator.test.js +180 -0
  33. package/dist/src/core/loggingContentGenerator.test.js.map +1 -0
  34. package/dist/src/core/tokenLimits.test.d.ts +6 -0
  35. package/dist/src/core/tokenLimits.test.js +26 -0
  36. package/dist/src/core/tokenLimits.test.js.map +1 -0
  37. package/dist/src/generated/git-commit.d.ts +2 -2
  38. package/dist/src/generated/git-commit.js +2 -2
  39. package/dist/src/generated/git-commit.js.map +1 -1
  40. package/dist/src/hooks/hookAggregator.d.ts +68 -0
  41. package/dist/src/hooks/hookAggregator.js +262 -0
  42. package/dist/src/hooks/hookAggregator.js.map +1 -0
  43. package/dist/src/hooks/hookAggregator.test.d.ts +6 -0
  44. package/dist/src/hooks/hookAggregator.test.js +387 -0
  45. package/dist/src/hooks/hookAggregator.test.js.map +1 -0
  46. package/dist/src/hooks/types.js +1 -1
  47. package/dist/src/hooks/types.js.map +1 -1
  48. package/dist/src/hooks/types.test.js +280 -2
  49. package/dist/src/hooks/types.test.js.map +1 -1
  50. package/dist/src/ide/ide-client.test.js +159 -0
  51. package/dist/src/ide/ide-client.test.js.map +1 -1
  52. package/dist/src/mcp/oauth-provider.test.js +177 -0
  53. package/dist/src/mcp/oauth-provider.test.js.map +1 -1
  54. package/dist/src/policy/config.js +3 -1
  55. package/dist/src/policy/config.js.map +1 -1
  56. package/dist/src/policy/config.test.js +118 -1
  57. package/dist/src/policy/config.test.js.map +1 -1
  58. package/dist/src/policy/policies/write.toml +10 -0
  59. package/dist/src/policy/policy-engine.d.ts +12 -3
  60. package/dist/src/policy/policy-engine.js +61 -7
  61. package/dist/src/policy/policy-engine.js.map +1 -1
  62. package/dist/src/policy/policy-engine.test.js +422 -86
  63. package/dist/src/policy/policy-engine.test.js.map +1 -1
  64. package/dist/src/policy/toml-loader.d.ts +2 -1
  65. package/dist/src/policy/toml-loader.js +103 -6
  66. package/dist/src/policy/toml-loader.js.map +1 -1
  67. package/dist/src/policy/toml-loader.test.js +32 -88
  68. package/dist/src/policy/toml-loader.test.js.map +1 -1
  69. package/dist/src/policy/types.d.ts +65 -0
  70. package/dist/src/policy/types.js +4 -0
  71. package/dist/src/policy/types.js.map +1 -1
  72. package/dist/src/prompts/mcp-prompts.test.d.ts +6 -0
  73. package/dist/src/prompts/mcp-prompts.test.js +40 -0
  74. package/dist/src/prompts/mcp-prompts.test.js.map +1 -0
  75. package/dist/src/prompts/prompt-registry.test.d.ts +6 -0
  76. package/dist/src/prompts/prompt-registry.test.js +111 -0
  77. package/dist/src/prompts/prompt-registry.test.js.map +1 -0
  78. package/dist/src/safety/built-in.d.ts +21 -0
  79. package/dist/src/safety/built-in.js +106 -0
  80. package/dist/src/safety/built-in.js.map +1 -0
  81. package/dist/src/safety/built-in.test.d.ts +6 -0
  82. package/dist/src/safety/built-in.test.js +199 -0
  83. package/dist/src/safety/built-in.test.js.map +1 -0
  84. package/dist/src/safety/checker-runner.d.ts +48 -0
  85. package/dist/src/safety/checker-runner.js +208 -0
  86. package/dist/src/safety/checker-runner.js.map +1 -0
  87. package/dist/src/safety/checker-runner.test.d.ts +6 -0
  88. package/dist/src/safety/checker-runner.test.js +238 -0
  89. package/dist/src/safety/checker-runner.test.js.map +1 -0
  90. package/dist/src/safety/context-builder.d.ts +23 -0
  91. package/dist/src/safety/context-builder.js +47 -0
  92. package/dist/src/safety/context-builder.js.map +1 -0
  93. package/dist/src/safety/context-builder.test.d.ts +6 -0
  94. package/dist/src/safety/context-builder.test.js +49 -0
  95. package/dist/src/safety/context-builder.test.js.map +1 -0
  96. package/dist/src/safety/protocol.d.ts +88 -0
  97. package/dist/src/safety/protocol.js +15 -0
  98. package/dist/src/safety/protocol.js.map +1 -0
  99. package/dist/src/safety/registry.d.ts +26 -0
  100. package/dist/src/safety/registry.js +65 -0
  101. package/dist/src/safety/registry.js.map +1 -0
  102. package/dist/src/safety/registry.test.d.ts +6 -0
  103. package/dist/src/safety/registry.test.js +31 -0
  104. package/dist/src/safety/registry.test.js.map +1 -0
  105. package/dist/src/services/loopDetectionService.d.ts +3 -0
  106. package/dist/src/services/loopDetectionService.js +81 -41
  107. package/dist/src/services/loopDetectionService.js.map +1 -1
  108. package/dist/src/services/loopDetectionService.test.js +96 -4
  109. package/dist/src/services/loopDetectionService.test.js.map +1 -1
  110. package/dist/src/services/test-data/resolved-aliases.golden.json +7 -0
  111. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +4 -2
  112. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +29 -0
  113. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  114. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +31 -0
  115. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
  116. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +5 -1
  117. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +12 -1
  118. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  119. package/dist/src/telemetry/loggers.d.ts +2 -1
  120. package/dist/src/telemetry/loggers.js +11 -0
  121. package/dist/src/telemetry/loggers.js.map +1 -1
  122. package/dist/src/telemetry/types.d.ts +15 -2
  123. package/dist/src/telemetry/types.js +42 -3
  124. package/dist/src/telemetry/types.js.map +1 -1
  125. package/dist/src/tools/base-tool-invocation.test.js +2 -2
  126. package/dist/src/tools/base-tool-invocation.test.js.map +1 -1
  127. package/dist/src/tools/memoryTool.js +1 -1
  128. package/dist/src/tools/memoryTool.js.map +1 -1
  129. package/dist/src/tools/memoryTool.test.js +1 -1
  130. package/dist/src/tools/memoryTool.test.js.map +1 -1
  131. package/dist/src/tools/ripGrep.d.ts +24 -7
  132. package/dist/src/tools/ripGrep.js +125 -145
  133. package/dist/src/tools/ripGrep.js.map +1 -1
  134. package/dist/src/tools/ripGrep.test.js +144 -20
  135. package/dist/src/tools/ripGrep.test.js.map +1 -1
  136. package/dist/src/tools/tools.js +1 -1
  137. package/dist/src/tools/tools.js.map +1 -1
  138. package/dist/src/tools/write-todos.js +1 -1
  139. package/dist/src/tools/write-todos.js.map +1 -1
  140. package/dist/src/utils/llm-edit-fixer.test.js +8 -1
  141. package/dist/src/utils/llm-edit-fixer.test.js.map +1 -1
  142. package/dist/tsconfig.tsbuildinfo +1 -1
  143. package/package.json +1 -1
  144. package/dist/google-gemini-cli-core-0.15.0-preview.2.tgz +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-builder.test.js","sourceRoot":"","sources":["../../../src/safety/context-builder.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAItD,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,IAAI,cAA8B,CAAC;IACnC,IAAI,UAAkB,CAAC;IACvB,MAAM,WAAW,GAAuB;QACtC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;KACnD,CAAC;IACF,MAAM,OAAO,GAAG,oBAAoB,CAAC;IACrC,MAAM,cAAc,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAE9C,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QAClD,UAAU,GAAG;YACX,mBAAmB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC;gBAC3C,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,cAAc,CAAC;aACxD,CAAC;YACF,MAAM,EAAE,gBAAgB;YACxB,gBAAgB,EAAE,cAAc;YAChC,MAAM,EAAE;gBACN,WAAW,EAAE,QAAQ;gBACrB,MAAM,EAAE,SAAS;aAClB;SACmB,CAAC;QACvB,cAAc,GAAG,IAAI,cAAc,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,OAAO,GAAG,cAAc,CAAC,gBAAgB,EAAE,CAAC;QAClD,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAC/D,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,OAAO,GAAG,cAAc,CAAC,mBAAmB,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;QACpE,MAAM,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;QAC9C,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,cAAc,GAAG,IAAI,cAAc,CAAC,UAAU,CAAC,CAAC;QAChD,MAAM,OAAO,GAAG,cAAc,CAAC,gBAAgB,EAAE,CAAC;QAClD,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { FunctionCall } from '@google/genai';
7
+ /**
8
+ * Represents a single turn in the conversation between the user and the model.
9
+ * This provides semantic context for why a tool call might be happening.
10
+ */
11
+ export interface ConversationTurn {
12
+ user: {
13
+ text: string;
14
+ };
15
+ model: {
16
+ text?: string;
17
+ toolCalls?: FunctionCall[];
18
+ };
19
+ }
20
+ /**
21
+ * The data structure passed from the CLI to a safety checker process via stdin.
22
+ */
23
+ export interface SafetyCheckInput {
24
+ /**
25
+ * The semantic version of the protocol (e.g., "1.0.0"). This allows
26
+ * for introducing breaking changes in the future while maintaining
27
+ * support for older checkers.
28
+ */
29
+ protocolVersion: '1.0.0';
30
+ /**
31
+ * The specific tool call that is being validated.
32
+ */
33
+ toolCall: FunctionCall;
34
+ /**
35
+ * A container for all contextual information from the CLI's internal state.
36
+ * By grouping data into categories, we can easily add new context in the
37
+ * future without creating a flat, unmanageable object.
38
+ */
39
+ context: {
40
+ /**
41
+ * Information about the user's file system and execution environment.
42
+ */
43
+ environment: {
44
+ cwd: string;
45
+ workspaces: string[];
46
+ };
47
+ /**
48
+ * The recent history of the conversation. This can be used by checkers
49
+ * that need to understand the intent behind a tool call.
50
+ */
51
+ history?: {
52
+ turns: ConversationTurn[];
53
+ };
54
+ };
55
+ /**
56
+ * Configuration for the safety checker.
57
+ * This allows checkers to be parameterized (e.g. allowed paths).
58
+ */
59
+ config?: unknown;
60
+ }
61
+ /**
62
+ * The possible decisions a safety checker can make.
63
+ */
64
+ export declare enum SafetyCheckDecision {
65
+ ALLOW = "allow",
66
+ DENY = "deny",
67
+ ASK_USER = "ask_user"
68
+ }
69
+ /**
70
+ * The data structure returned by a safety checker process via stdout.
71
+ */
72
+ export type SafetyCheckResult = {
73
+ /**
74
+ * The decision made by the safety checker.
75
+ */
76
+ decision: SafetyCheckDecision.ALLOW;
77
+ /**
78
+ * If not allowed, a message explaining why the tool call was blocked.
79
+ * This will be shown to the user.
80
+ */
81
+ reason?: string;
82
+ } | {
83
+ decision: SafetyCheckDecision.DENY;
84
+ reason: string;
85
+ } | {
86
+ decision: SafetyCheckDecision.ASK_USER;
87
+ reason: string;
88
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /**
7
+ * The possible decisions a safety checker can make.
8
+ */
9
+ export var SafetyCheckDecision;
10
+ (function (SafetyCheckDecision) {
11
+ SafetyCheckDecision["ALLOW"] = "allow";
12
+ SafetyCheckDecision["DENY"] = "deny";
13
+ SafetyCheckDecision["ASK_USER"] = "ask_user";
14
+ })(SafetyCheckDecision || (SafetyCheckDecision = {}));
15
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/safety/protocol.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgEH;;GAEG;AACH,MAAM,CAAN,IAAY,mBAIX;AAJD,WAAY,mBAAmB;IAC7B,sCAAe,CAAA;IACf,oCAAa,CAAA;IACb,4CAAqB,CAAA;AACvB,CAAC,EAJW,mBAAmB,KAAnB,mBAAmB,QAI9B"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { type InProcessChecker } from './built-in.js';
7
+ /**
8
+ * Registry for managing safety checker resolution.
9
+ */
10
+ export declare class CheckerRegistry {
11
+ private readonly checkersPath;
12
+ private static readonly BUILT_IN_EXTERNAL_CHECKERS;
13
+ private static readonly BUILT_IN_IN_PROCESS_CHECKERS;
14
+ private static readonly VALID_NAME_PATTERN;
15
+ constructor(checkersPath: string);
16
+ /**
17
+ * Resolves an external checker name to an absolute executable path.
18
+ */
19
+ resolveExternal(name: string): string;
20
+ /**
21
+ * Resolves an in-process checker name to a checker instance.
22
+ */
23
+ resolveInProcess(name: string): InProcessChecker;
24
+ private static isValidCheckerName;
25
+ static getBuiltInCheckers(): string[];
26
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import * as path from 'node:path';
7
+ import * as fs from 'node:fs';
8
+ import { AllowedPathChecker } from './built-in.js';
9
+ import { InProcessCheckerType } from '../policy/types.js';
10
+ /**
11
+ * Registry for managing safety checker resolution.
12
+ */
13
+ export class CheckerRegistry {
14
+ checkersPath;
15
+ static BUILT_IN_EXTERNAL_CHECKERS = new Map([
16
+ // No external built-ins for now
17
+ ]);
18
+ static BUILT_IN_IN_PROCESS_CHECKERS = new Map([[InProcessCheckerType.ALLOWED_PATH, new AllowedPathChecker()]]);
19
+ // Regex to validate checker names (alphanumeric and hyphens only)
20
+ static VALID_NAME_PATTERN = /^[a-z0-9-]+$/;
21
+ constructor(checkersPath) {
22
+ this.checkersPath = checkersPath;
23
+ }
24
+ /**
25
+ * Resolves an external checker name to an absolute executable path.
26
+ */
27
+ resolveExternal(name) {
28
+ if (!CheckerRegistry.isValidCheckerName(name)) {
29
+ throw new Error(`Invalid checker name "${name}". Checker names must contain only lowercase letters, numbers, and hyphens.`);
30
+ }
31
+ const builtInPath = CheckerRegistry.BUILT_IN_EXTERNAL_CHECKERS.get(name);
32
+ if (builtInPath) {
33
+ const fullPath = path.join(this.checkersPath, builtInPath);
34
+ if (!fs.existsSync(fullPath)) {
35
+ throw new Error(`Built-in checker "${name}" not found at ${fullPath}`);
36
+ }
37
+ return fullPath;
38
+ }
39
+ // TODO: Phase 5 - Add support for custom external checkers
40
+ throw new Error(`Unknown external checker "${name}".`);
41
+ }
42
+ /**
43
+ * Resolves an in-process checker name to a checker instance.
44
+ */
45
+ resolveInProcess(name) {
46
+ if (!CheckerRegistry.isValidCheckerName(name)) {
47
+ throw new Error(`Invalid checker name "${name}".`);
48
+ }
49
+ const checker = CheckerRegistry.BUILT_IN_IN_PROCESS_CHECKERS.get(name);
50
+ if (checker) {
51
+ return checker;
52
+ }
53
+ throw new Error(`Unknown in-process checker "${name}". Available: ${Array.from(CheckerRegistry.BUILT_IN_IN_PROCESS_CHECKERS.keys()).join(', ')}`);
54
+ }
55
+ static isValidCheckerName(name) {
56
+ return this.VALID_NAME_PATTERN.test(name) && !name.includes('..');
57
+ }
58
+ static getBuiltInCheckers() {
59
+ return [
60
+ ...Array.from(this.BUILT_IN_EXTERNAL_CHECKERS.keys()),
61
+ ...Array.from(this.BUILT_IN_IN_PROCESS_CHECKERS.keys()),
62
+ ];
63
+ }
64
+ }
65
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/safety/registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAyB,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D;;GAEG;AACH,MAAM,OAAO,eAAe;IAaG;IAZrB,MAAM,CAAU,0BAA0B,GAAG,IAAI,GAAG,CAAiB;IAC3E,gCAAgC;KACjC,CAAC,CAAC;IAEK,MAAM,CAAU,4BAA4B,GAAG,IAAI,GAAG,CAG5D,CAAC,CAAC,oBAAoB,CAAC,YAAY,EAAE,IAAI,kBAAkB,EAAE,CAAC,CAAC,CAAC,CAAC;IAEnE,kEAAkE;IAC1D,MAAM,CAAU,kBAAkB,GAAG,cAAc,CAAC;IAE5D,YAA6B,YAAoB;QAApB,iBAAY,GAAZ,YAAY,CAAQ;IAAG,CAAC;IAErD;;OAEG;IACH,eAAe,CAAC,IAAY;QAC1B,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CACb,yBAAyB,IAAI,6EAA6E,CAC3G,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,eAAe,CAAC,0BAA0B,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzE,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;YAC3D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,kBAAkB,QAAQ,EAAE,CAAC,CAAC;YACzE,CAAC;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,2DAA2D;QAC3D,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,IAAI,CAAC,CAAC;IACzD,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAC,IAAY;QAC3B,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,IAAI,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,OAAO,GAAG,eAAe,CAAC,4BAA4B,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvE,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,MAAM,IAAI,KAAK,CACb,+BAA+B,IAAI,iBAAiB,KAAK,CAAC,IAAI,CAC5D,eAAe,CAAC,4BAA4B,CAAC,IAAI,EAAE,CACpD,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACf,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,kBAAkB,CAAC,IAAY;QAC5C,OAAO,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,CAAC,kBAAkB;QACvB,OAAO;YACL,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,0BAA0B,CAAC,IAAI,EAAE,CAAC;YACrD,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,4BAA4B,CAAC,IAAI,EAAE,CAAC;SACxD,CAAC;IACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export {};
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, beforeEach } from 'vitest';
7
+ import { CheckerRegistry } from './registry.js';
8
+ import { InProcessCheckerType } from '../policy/types.js';
9
+ import { AllowedPathChecker } from './built-in.js';
10
+ describe('CheckerRegistry', () => {
11
+ let registry;
12
+ const mockCheckersPath = '/mock/checkers/path';
13
+ beforeEach(() => {
14
+ registry = new CheckerRegistry(mockCheckersPath);
15
+ });
16
+ it('should resolve built-in in-process checkers', () => {
17
+ const checker = registry.resolveInProcess(InProcessCheckerType.ALLOWED_PATH);
18
+ expect(checker).toBeInstanceOf(AllowedPathChecker);
19
+ });
20
+ it('should throw for unknown in-process checkers', () => {
21
+ expect(() => registry.resolveInProcess('unknown-checker')).toThrow('Unknown in-process checker "unknown-checker"');
22
+ });
23
+ it('should validate checker names', () => {
24
+ expect(() => registry.resolveInProcess('invalid name!')).toThrow('Invalid checker name');
25
+ expect(() => registry.resolveInProcess('../escape')).toThrow('Invalid checker name');
26
+ });
27
+ it('should throw for unknown external checkers (for now)', () => {
28
+ expect(() => registry.resolveExternal('some-external')).toThrow('Unknown external checker "some-external"');
29
+ });
30
+ });
31
+ //# sourceMappingURL=registry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.test.js","sourceRoot":"","sources":["../../../src/safety/registry.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,IAAI,QAAyB,CAAC;IAC9B,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;IAE/C,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,GAAG,IAAI,eAAe,CAAC,gBAAgB,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,OAAO,GAAG,QAAQ,CAAC,gBAAgB,CACvC,oBAAoB,CAAC,YAAY,CAClC,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAChE,8CAA8C,CAC/C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAC9D,sBAAsB,CACvB,CAAC;QACF,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAC1D,sBAAsB,CACvB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAC7D,0CAA0C,CAC3C,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -93,6 +93,9 @@ export declare class LoopDetectionService {
93
93
  private isActualContentMatch;
94
94
  private trimRecentHistory;
95
95
  private checkForLoopWithLLM;
96
+ private queryLoopDetectionModel;
97
+ private handleConfirmedLoop;
98
+ private updateCheckInterval;
96
99
  /**
97
100
  * Resets all loop detection state.
98
101
  */
@@ -5,8 +5,8 @@
5
5
  */
6
6
  import { createHash } from 'node:crypto';
7
7
  import { GeminiEventType } from '../core/turn.js';
8
- import { logLoopDetected, logLoopDetectionDisabled, } from '../telemetry/loggers.js';
9
- import { LoopDetectedEvent, LoopDetectionDisabledEvent, LoopType, } from '../telemetry/types.js';
8
+ import { logLoopDetected, logLoopDetectionDisabled, logLlmLoopCheck, } from '../telemetry/loggers.js';
9
+ import { LoopDetectedEvent, LoopDetectionDisabledEvent, LoopType, LlmLoopCheckEvent, } from '../telemetry/types.js';
10
10
  import { isFunctionCall, isFunctionResponse, } from '../utils/messageInspectors.js';
11
11
  import { debugLogger } from '../utils/debugLogger.js';
12
12
  const TOOL_CALL_LOOP_THRESHOLD = 5;
@@ -36,6 +36,11 @@ const MIN_LLM_CHECK_INTERVAL = 5;
36
36
  * This is used when the confidence of a loop is low, to check less frequently.
37
37
  */
38
38
  const MAX_LLM_CHECK_INTERVAL = 15;
39
+ /**
40
+ * The confidence threshold above which the LLM is considered to have detected a loop.
41
+ */
42
+ const LLM_CONFIDENCE_THRESHOLD = 0.9;
43
+ const DOUBLE_CHECK_MODEL_ALIAS = 'loop-detection-double-check';
39
44
  const LOOP_DETECTION_SYSTEM_PROMPT = `You are a sophisticated AI diagnostic agent specializing in identifying when a conversational AI is stuck in an unproductive state. Your task is to analyze the provided conversation history and determine if the assistant has ceased to make meaningful progress.
40
45
 
41
46
  An unproductive state is characterized by one or more of the following patterns over the last 5 or more assistant turns:
@@ -46,6 +51,20 @@ Cognitive Loop: The assistant seems unable to determine the next logical step. I
46
51
 
47
52
  Crucially, differentiate between a true unproductive state and legitimate, incremental progress.
48
53
  For example, a series of 'tool_A' or 'tool_B' tool calls that make small, distinct changes to the same file (like adding docstrings to functions one by one) is considered forward progress and is NOT a loop. A loop would be repeatedly replacing the same text with the same content, or cycling between a small set of files with no net change.`;
54
+ const LOOP_DETECTION_SCHEMA = {
55
+ type: 'object',
56
+ properties: {
57
+ unproductive_state_analysis: {
58
+ type: 'string',
59
+ description: 'Your reasoning on if the conversation is looping without forward progress.',
60
+ },
61
+ unproductive_state_confidence: {
62
+ type: 'number',
63
+ description: 'A number between 0.0 and 1.0 representing your confidence that the conversation is in an unproductive state.',
64
+ },
65
+ },
66
+ required: ['unproductive_state_analysis', 'unproductive_state_confidence'],
67
+ };
49
68
  /**
50
69
  * Service for detecting and preventing infinite loops in AI responses.
51
70
  * Monitors tool call repetitions and content sentence repetitions.
@@ -312,55 +331,76 @@ export class LoopDetectionService {
312
331
  parts: [{ text: 'Recent conversation history:' }],
313
332
  });
314
333
  }
315
- const schema = {
316
- type: 'object',
317
- properties: {
318
- unproductive_state_analysis: {
319
- type: 'string',
320
- description: 'Your reasoning on if the conversation is looping without forward progress.',
321
- },
322
- unproductive_state_confidence: {
323
- type: 'number',
324
- description: 'A number between 0.0 and 1.0 representing your confidence that the conversation is in an unproductive state.',
325
- },
326
- },
327
- required: [
328
- 'unproductive_state_analysis',
329
- 'unproductive_state_confidence',
330
- ],
331
- };
332
- let result;
334
+ const flashResult = await this.queryLoopDetectionModel('loop-detection', contents, signal);
335
+ if (!flashResult) {
336
+ return false;
337
+ }
338
+ const flashConfidence = flashResult['unproductive_state_confidence'];
339
+ const doubleCheckModelName = this.config.modelConfigService.getResolvedConfig({
340
+ model: DOUBLE_CHECK_MODEL_ALIAS,
341
+ }).model;
342
+ if (flashConfidence < LLM_CONFIDENCE_THRESHOLD) {
343
+ logLlmLoopCheck(this.config, new LlmLoopCheckEvent(this.promptId, flashConfidence, doubleCheckModelName, -1));
344
+ this.updateCheckInterval(flashConfidence);
345
+ return false;
346
+ }
347
+ if (this.config.isInFallbackMode()) {
348
+ const flashModelName = this.config.modelConfigService.getResolvedConfig({
349
+ model: 'loop-detection',
350
+ }).model;
351
+ this.handleConfirmedLoop(flashResult, flashModelName);
352
+ return true;
353
+ }
354
+ // Double check with configured model
355
+ const mainModelResult = await this.queryLoopDetectionModel(DOUBLE_CHECK_MODEL_ALIAS, contents, signal);
356
+ const mainModelConfidence = mainModelResult
357
+ ? mainModelResult['unproductive_state_confidence']
358
+ : 0;
359
+ logLlmLoopCheck(this.config, new LlmLoopCheckEvent(this.promptId, flashConfidence, doubleCheckModelName, mainModelConfidence));
360
+ if (mainModelResult) {
361
+ if (mainModelConfidence >= LLM_CONFIDENCE_THRESHOLD) {
362
+ this.handleConfirmedLoop(mainModelResult, doubleCheckModelName);
363
+ return true;
364
+ }
365
+ else {
366
+ this.updateCheckInterval(mainModelConfidence);
367
+ }
368
+ }
369
+ return false;
370
+ }
371
+ async queryLoopDetectionModel(model, contents, signal) {
333
372
  try {
334
- result = await this.config.getBaseLlmClient().generateJson({
335
- modelConfigKey: { model: 'loop-detection' },
373
+ const result = (await this.config.getBaseLlmClient().generateJson({
374
+ modelConfigKey: { model },
336
375
  contents,
337
- schema,
376
+ schema: LOOP_DETECTION_SCHEMA,
338
377
  systemInstruction: LOOP_DETECTION_SYSTEM_PROMPT,
339
378
  abortSignal: signal,
340
379
  promptId: this.promptId,
341
- });
380
+ maxAttempts: 2,
381
+ }));
382
+ if (result &&
383
+ typeof result['unproductive_state_confidence'] === 'number') {
384
+ return result;
385
+ }
386
+ return null;
342
387
  }
343
388
  catch (e) {
344
- // Do nothing, treat it as a non-loop.
345
389
  this.config.getDebugMode() ? debugLogger.warn(e) : debugLogger.debug(e);
346
- return false;
390
+ return null;
347
391
  }
348
- if (typeof result['unproductive_state_confidence'] === 'number') {
349
- if (result['unproductive_state_confidence'] > 0.9) {
350
- if (typeof result['unproductive_state_analysis'] === 'string' &&
351
- result['unproductive_state_analysis']) {
352
- debugLogger.warn(result['unproductive_state_analysis']);
353
- }
354
- logLoopDetected(this.config, new LoopDetectedEvent(LoopType.LLM_DETECTED_LOOP, this.promptId));
355
- return true;
356
- }
357
- else {
358
- this.llmCheckInterval = Math.round(MIN_LLM_CHECK_INTERVAL +
359
- (MAX_LLM_CHECK_INTERVAL - MIN_LLM_CHECK_INTERVAL) *
360
- (1 - result['unproductive_state_confidence']));
361
- }
392
+ }
393
+ handleConfirmedLoop(result, modelName) {
394
+ if (typeof result['unproductive_state_analysis'] === 'string' &&
395
+ result['unproductive_state_analysis']) {
396
+ debugLogger.warn(result['unproductive_state_analysis']);
362
397
  }
363
- return false;
398
+ logLoopDetected(this.config, new LoopDetectedEvent(LoopType.LLM_DETECTED_LOOP, this.promptId, modelName));
399
+ }
400
+ updateCheckInterval(unproductive_state_confidence) {
401
+ this.llmCheckInterval = Math.round(MIN_LLM_CHECK_INTERVAL +
402
+ (MAX_LLM_CHECK_INTERVAL - MIN_LLM_CHECK_INTERVAL) *
403
+ (1 - unproductive_state_confidence));
364
404
  }
365
405
  /**
366
406
  * Resets all loop detection state.
@@ -1 +1 @@
1
- {"version":3,"file":"loopDetectionService.js","sourceRoot":"","sources":["../../../src/services/loopDetectionService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loopDetectionService.js","sourceRoot":"","sources":["../../../src/services/loopDetectionService.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@ import { LoopDetectionService } from './loopDetectionService.js';
11
11
  vi.mock('../telemetry/loggers.js', () => ({
12
12
  logLoopDetected: vi.fn(),
13
13
  logLoopDetectionDisabled: vi.fn(),
14
+ logLlmLoopCheck: vi.fn(),
14
15
  }));
15
16
  const TOOL_CALL_LOOP_THRESHOLD = 5;
16
17
  const CONTENT_LOOP_THRESHOLD = 10;
@@ -574,10 +575,17 @@ describe('LoopDetectionService LLM Checks', () => {
574
575
  getBaseLlmClient: () => mockBaseLlmClient,
575
576
  getDebugMode: () => false,
576
577
  getTelemetryEnabled: () => true,
578
+ getModel: vi.fn().mockReturnValue('cognitive-loop-v1'),
579
+ isInFallbackMode: vi.fn().mockReturnValue(false),
577
580
  modelConfigService: {
578
- getResolvedConfig: vi.fn().mockReturnValue({
579
- model: 'cognitive-loop-v1',
580
- generateContentConfig: {},
581
+ getResolvedConfig: vi.fn().mockImplementation((key) => {
582
+ if (key.model === 'loop-detection') {
583
+ return { model: 'gemini-2.5-flash', generateContentConfig: {} };
584
+ }
585
+ return {
586
+ model: 'cognitive-loop-v1',
587
+ generateContentConfig: {},
588
+ };
581
589
  }),
582
590
  },
583
591
  isInteractive: () => false,
@@ -605,7 +613,7 @@ describe('LoopDetectionService LLM Checks', () => {
605
613
  await advanceTurns(30);
606
614
  expect(mockBaseLlmClient.generateJson).toHaveBeenCalledTimes(1);
607
615
  expect(mockBaseLlmClient.generateJson).toHaveBeenCalledWith(expect.objectContaining({
608
- modelConfigKey: expect.any(Object),
616
+ modelConfigKey: { model: 'loop-detection' },
609
617
  systemInstruction: expect.any(String),
610
618
  contents: expect.any(Array),
611
619
  schema: expect.any(Object),
@@ -620,6 +628,9 @@ describe('LoopDetectionService LLM Checks', () => {
620
628
  });
621
629
  await advanceTurns(30);
622
630
  expect(mockBaseLlmClient.generateJson).toHaveBeenCalledTimes(1);
631
+ expect(mockBaseLlmClient.generateJson).toHaveBeenCalledWith(expect.objectContaining({
632
+ modelConfigKey: { model: 'loop-detection' },
633
+ }));
623
634
  // The confidence of 0.85 will result in a low interval.
624
635
  // The interval will be: 5 + (15 - 5) * (1 - 0.85) = 5 + 10 * 0.15 = 6.5 -> rounded to 7
625
636
  await advanceTurns(6); // advance to turn 36
@@ -632,6 +643,7 @@ describe('LoopDetectionService LLM Checks', () => {
632
643
  expect(loggers.logLoopDetected).toHaveBeenCalledWith(mockConfig, expect.objectContaining({
633
644
  'event.name': 'loop_detected',
634
645
  loop_type: LoopType.LLM_DETECTED_LOOP,
646
+ confirmed_by_model: 'cognitive-loop-v1',
635
647
  }));
636
648
  });
637
649
  it('should not detect a loop when confidence is low', async () => {
@@ -699,5 +711,85 @@ describe('LoopDetectionService LLM Checks', () => {
699
711
  // Verify the original history follows
700
712
  expect(calledArg.contents[1]).toEqual(functionCallHistory[0]);
701
713
  });
714
+ it('should detect a loop when confidence is exactly equal to the threshold (0.9)', async () => {
715
+ // Mock isInFallbackMode to false so it double checks
716
+ vi.mocked(mockConfig.isInFallbackMode).mockReturnValue(false);
717
+ mockBaseLlmClient.generateJson = vi
718
+ .fn()
719
+ .mockResolvedValueOnce({
720
+ unproductive_state_confidence: 0.9,
721
+ unproductive_state_analysis: 'Flash says loop',
722
+ })
723
+ .mockResolvedValueOnce({
724
+ unproductive_state_confidence: 0.9,
725
+ unproductive_state_analysis: 'Main says loop',
726
+ });
727
+ await advanceTurns(30);
728
+ // It should have called generateJson twice
729
+ expect(mockBaseLlmClient.generateJson).toHaveBeenCalledTimes(2);
730
+ expect(mockBaseLlmClient.generateJson).toHaveBeenNthCalledWith(1, expect.objectContaining({
731
+ modelConfigKey: { model: 'loop-detection' },
732
+ }));
733
+ expect(mockBaseLlmClient.generateJson).toHaveBeenNthCalledWith(2, expect.objectContaining({
734
+ modelConfigKey: { model: 'loop-detection-double-check' },
735
+ }));
736
+ // And it should have detected a loop
737
+ expect(loggers.logLoopDetected).toHaveBeenCalledWith(mockConfig, expect.objectContaining({
738
+ 'event.name': 'loop_detected',
739
+ loop_type: LoopType.LLM_DETECTED_LOOP,
740
+ confirmed_by_model: 'cognitive-loop-v1',
741
+ }));
742
+ });
743
+ it('should not detect a loop when Flash is confident (0.9) but Main model is not (0.89)', async () => {
744
+ // Mock isInFallbackMode to false so it double checks
745
+ vi.mocked(mockConfig.isInFallbackMode).mockReturnValue(false);
746
+ mockBaseLlmClient.generateJson = vi
747
+ .fn()
748
+ .mockResolvedValueOnce({
749
+ unproductive_state_confidence: 0.9,
750
+ unproductive_state_analysis: 'Flash says loop',
751
+ })
752
+ .mockResolvedValueOnce({
753
+ unproductive_state_confidence: 0.89,
754
+ unproductive_state_analysis: 'Main says no loop',
755
+ });
756
+ await advanceTurns(30);
757
+ expect(mockBaseLlmClient.generateJson).toHaveBeenCalledTimes(2);
758
+ expect(mockBaseLlmClient.generateJson).toHaveBeenNthCalledWith(1, expect.objectContaining({
759
+ modelConfigKey: { model: 'loop-detection' },
760
+ }));
761
+ expect(mockBaseLlmClient.generateJson).toHaveBeenNthCalledWith(2, expect.objectContaining({
762
+ modelConfigKey: { model: 'loop-detection-double-check' },
763
+ }));
764
+ // Should NOT have detected a loop
765
+ expect(loggers.logLoopDetected).not.toHaveBeenCalled();
766
+ // But should have updated the interval based on the main model's confidence (0.89)
767
+ // Interval = 5 + (15-5) * (1 - 0.89) = 5 + 10 * 0.11 = 5 + 1.1 = 6.1 -> 6
768
+ // Advance by 6 turns
769
+ await advanceTurns(6);
770
+ // Next turn (37) should trigger another check
771
+ await service.turnStarted(abortController.signal);
772
+ expect(mockBaseLlmClient.generateJson).toHaveBeenCalledTimes(3);
773
+ });
774
+ it('should only call Flash model if in fallback mode', async () => {
775
+ // Mock isInFallbackMode to true
776
+ vi.mocked(mockConfig.isInFallbackMode).mockReturnValue(true);
777
+ mockBaseLlmClient.generateJson = vi.fn().mockResolvedValueOnce({
778
+ unproductive_state_confidence: 0.9,
779
+ unproductive_state_analysis: 'Flash says loop',
780
+ });
781
+ await advanceTurns(30);
782
+ // It should have called generateJson only once
783
+ expect(mockBaseLlmClient.generateJson).toHaveBeenCalledTimes(1);
784
+ expect(mockBaseLlmClient.generateJson).toHaveBeenCalledWith(expect.objectContaining({
785
+ modelConfigKey: { model: 'loop-detection' },
786
+ }));
787
+ // And it should have detected a loop
788
+ expect(loggers.logLoopDetected).toHaveBeenCalledWith(mockConfig, expect.objectContaining({
789
+ 'event.name': 'loop_detected',
790
+ loop_type: LoopType.LLM_DETECTED_LOOP,
791
+ confirmed_by_model: 'gemini-2.5-flash',
792
+ }));
793
+ });
702
794
  });
703
795
  //# sourceMappingURL=loopDetectionService.test.js.map