@google/gemini-cli-core 0.1.18 → 0.1.19
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/README.md +199 -132
- package/dist/google-gemini-cli-core-0.1.18.tgz +0 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/src/code_assist/converter.d.ts +3 -2
- package/dist/src/code_assist/converter.js +2 -2
- package/dist/src/code_assist/converter.js.map +1 -1
- package/dist/src/code_assist/converter.test.js +48 -1
- package/dist/src/code_assist/converter.test.js.map +1 -1
- package/dist/src/code_assist/oauth2.js +1 -1
- package/dist/src/code_assist/oauth2.js.map +1 -1
- package/dist/src/code_assist/server.test.js +4 -1
- package/dist/src/code_assist/server.test.js.map +1 -1
- package/dist/src/code_assist/setup.js +4 -4
- package/dist/src/code_assist/setup.js.map +1 -1
- package/dist/src/config/config.d.ts +19 -0
- package/dist/src/config/config.js +29 -5
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +8 -0
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/core/client.d.ts +5 -4
- package/dist/src/core/client.js +162 -116
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +275 -30
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.js +3 -2
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/contentGenerator.test.js +3 -2
- package/dist/src/core/contentGenerator.test.js.map +1 -1
- package/dist/src/core/coreToolScheduler.d.ts +21 -8
- package/dist/src/core/coreToolScheduler.js +170 -61
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/coreToolScheduler.test.js +181 -37
- package/dist/src/core/coreToolScheduler.test.js.map +1 -1
- package/dist/src/core/geminiChat.d.ts +7 -6
- package/dist/src/core/geminiChat.js +43 -43
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/logger.d.ts +1 -0
- package/dist/src/core/logger.js +18 -0
- package/dist/src/core/logger.js.map +1 -1
- package/dist/src/core/logger.test.js +29 -0
- package/dist/src/core/logger.test.js.map +1 -1
- package/dist/src/core/loggingContentGenerator.d.ts +29 -0
- package/dist/src/core/loggingContentGenerator.js +97 -0
- package/dist/src/core/loggingContentGenerator.js.map +1 -0
- package/dist/src/core/nonInteractiveToolExecutor.js +20 -1
- package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
- package/dist/src/core/nonInteractiveToolExecutor.test.js +7 -31
- package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
- package/dist/src/core/subagent.d.ts +230 -0
- package/dist/src/core/subagent.js +447 -0
- package/dist/src/core/subagent.js.map +1 -0
- package/dist/src/core/subagent.test.d.ts +6 -0
- package/dist/src/core/subagent.test.js +515 -0
- package/dist/src/core/subagent.test.js.map +1 -0
- package/dist/src/core/turn.js +1 -0
- package/dist/src/core/turn.js.map +1 -1
- package/dist/src/core/turn.test.js +4 -0
- package/dist/src/core/turn.test.js.map +1 -1
- package/dist/src/ide/detect-ide.d.ts +8 -1
- package/dist/src/ide/detect-ide.js +40 -3
- package/dist/src/ide/detect-ide.js.map +1 -1
- package/dist/src/ide/ide-client.d.ts +20 -1
- package/dist/src/ide/ide-client.js +144 -18
- package/dist/src/ide/ide-client.js.map +1 -1
- package/dist/src/ide/ide-installer.js +20 -1
- package/dist/src/ide/ide-installer.js.map +1 -1
- package/dist/src/ide/ide-installer.test.js +37 -2
- package/dist/src/ide/ide-installer.test.js.map +1 -1
- package/dist/src/ide/ideContext.d.ts +95 -0
- package/dist/src/ide/ideContext.js +45 -0
- package/dist/src/ide/ideContext.js.map +1 -1
- package/dist/src/mcp/google-auth-provider.js +9 -0
- package/dist/src/mcp/google-auth-provider.js.map +1 -1
- package/dist/src/mcp/google-auth-provider.test.js +45 -10
- package/dist/src/mcp/google-auth-provider.test.js.map +1 -1
- package/dist/src/services/loopDetectionService.js +14 -11
- package/dist/src/services/loopDetectionService.js.map +1 -1
- package/dist/src/services/loopDetectionService.test.js +191 -0
- package/dist/src/services/loopDetectionService.test.js.map +1 -1
- package/dist/src/services/shellExecutionService.js +29 -9
- package/dist/src/services/shellExecutionService.js.map +1 -1
- package/dist/src/services/shellExecutionService.test.js +8 -0
- package/dist/src/services/shellExecutionService.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +27 -2
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +187 -58
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.d.ts +6 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +186 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +5 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +8 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
- package/dist/src/telemetry/loggers.test.circular.js +7 -2
- package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +7 -2
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/metrics.d.ts +3 -2
- package/dist/src/telemetry/metrics.js +7 -1
- package/dist/src/telemetry/metrics.js.map +1 -1
- package/dist/src/telemetry/metrics.test.js +50 -0
- package/dist/src/telemetry/metrics.test.js.map +1 -1
- package/dist/src/telemetry/tool-call-decision.d.ts +13 -0
- package/dist/src/telemetry/tool-call-decision.js +29 -0
- package/dist/src/telemetry/tool-call-decision.js.map +1 -0
- package/dist/src/telemetry/types.d.ts +4 -7
- package/dist/src/telemetry/types.js +17 -21
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.d.ts +4 -1
- package/dist/src/telemetry/uiTelemetry.js +3 -1
- package/dist/src/telemetry/uiTelemetry.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.test.js +13 -2
- package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
- package/dist/src/test-utils/tools.d.ts +23 -0
- package/dist/src/test-utils/tools.js +41 -0
- package/dist/src/test-utils/tools.js.map +1 -0
- package/dist/src/tools/diffOptions.d.ts +2 -0
- package/dist/src/tools/diffOptions.js +28 -0
- package/dist/src/tools/diffOptions.js.map +1 -1
- package/dist/src/tools/diffOptions.test.d.ts +6 -0
- package/dist/src/tools/diffOptions.test.js +119 -0
- package/dist/src/tools/diffOptions.test.js.map +1 -0
- package/dist/src/tools/edit.d.ts +9 -33
- package/dist/src/tools/edit.js +143 -132
- package/dist/src/tools/edit.js.map +1 -1
- package/dist/src/tools/edit.test.js +117 -51
- package/dist/src/tools/edit.test.js.map +1 -1
- package/dist/src/tools/glob.d.ts +3 -10
- package/dist/src/tools/glob.js +85 -89
- package/dist/src/tools/glob.js.map +1 -1
- package/dist/src/tools/glob.test.js +22 -12
- package/dist/src/tools/glob.test.js.map +1 -1
- package/dist/src/tools/grep.d.ts +3 -35
- package/dist/src/tools/grep.js +111 -83
- package/dist/src/tools/grep.js.map +1 -1
- package/dist/src/tools/grep.test.js +40 -23
- package/dist/src/tools/grep.test.js.map +1 -1
- package/dist/src/tools/ls.js +8 -9
- package/dist/src/tools/ls.js.map +1 -1
- package/dist/src/tools/mcp-client.d.ts +14 -3
- package/dist/src/tools/mcp-client.js +82 -6
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +340 -5
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/mcp-tool.d.ts +3 -8
- package/dist/src/tools/mcp-tool.js +5 -18
- package/dist/src/tools/mcp-tool.js.map +1 -1
- package/dist/src/tools/memoryTool.d.ts +2 -2
- package/dist/src/tools/memoryTool.js +5 -5
- package/dist/src/tools/memoryTool.js.map +1 -1
- package/dist/src/tools/memoryTool.test.js +10 -1
- package/dist/src/tools/memoryTool.test.js.map +1 -1
- package/dist/src/tools/modifiable-tool.d.ts +8 -5
- package/dist/src/tools/modifiable-tool.js +4 -1
- package/dist/src/tools/modifiable-tool.js.map +1 -1
- package/dist/src/tools/modifiable-tool.test.js +3 -3
- package/dist/src/tools/modifiable-tool.test.js.map +1 -1
- package/dist/src/tools/read-file.d.ts +4 -6
- package/dist/src/tools/read-file.js +92 -45
- package/dist/src/tools/read-file.js.map +1 -1
- package/dist/src/tools/read-file.test.js +192 -130
- package/dist/src/tools/read-file.test.js.map +1 -1
- package/dist/src/tools/read-many-files.js +25 -20
- package/dist/src/tools/read-many-files.js.map +1 -1
- package/dist/src/tools/read-many-files.test.js +22 -11
- package/dist/src/tools/read-many-files.test.js.map +1 -1
- package/dist/src/tools/shell.js +11 -7
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/shell.test.js +21 -0
- package/dist/src/tools/shell.test.js.map +1 -1
- package/dist/src/tools/tool-error.d.ts +4 -0
- package/dist/src/tools/tool-error.js +4 -0
- package/dist/src/tools/tool-error.js.map +1 -1
- package/dist/src/tools/tool-registry.d.ts +12 -20
- package/dist/src/tools/tool-registry.js +23 -76
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/tools/tool-registry.test.js +19 -192
- package/dist/src/tools/tool-registry.test.js.map +1 -1
- package/dist/src/tools/tools.d.ts +144 -43
- package/dist/src/tools/tools.js +181 -11
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/tools.test.d.ts +6 -0
- package/dist/src/tools/tools.test.js +117 -0
- package/dist/src/tools/tools.test.js.map +1 -0
- package/dist/src/tools/web-fetch.js +3 -4
- package/dist/src/tools/web-fetch.js.map +1 -1
- package/dist/src/tools/web-search.js +1 -1
- package/dist/src/tools/web-search.js.map +1 -1
- package/dist/src/tools/write-file.d.ts +6 -2
- package/dist/src/tools/write-file.js +85 -20
- package/dist/src/tools/write-file.js.map +1 -1
- package/dist/src/tools/write-file.test.js +113 -8
- package/dist/src/tools/write-file.test.js.map +1 -1
- package/dist/src/utils/bfsFileSearch.test.js +28 -56
- package/dist/src/utils/bfsFileSearch.test.js.map +1 -1
- package/dist/src/utils/editCorrector.js +8 -9
- package/dist/src/utils/editCorrector.js.map +1 -1
- package/dist/src/utils/environmentContext.d.ts +21 -0
- package/dist/src/utils/environmentContext.js +90 -0
- package/dist/src/utils/environmentContext.js.map +1 -0
- package/dist/src/utils/environmentContext.test.d.ts +6 -0
- package/dist/src/utils/environmentContext.test.js +139 -0
- package/dist/src/utils/environmentContext.test.js.map +1 -0
- package/dist/src/utils/fileUtils.d.ts +7 -0
- package/dist/src/utils/fileUtils.js +15 -12
- package/dist/src/utils/fileUtils.js.map +1 -1
- package/dist/src/utils/fileUtils.test.js +6 -5
- package/dist/src/utils/fileUtils.test.js.map +1 -1
- package/dist/src/utils/filesearch/crawlCache.d.ts +1 -1
- package/dist/src/utils/filesearch/crawlCache.js +4 -1
- package/dist/src/utils/filesearch/crawlCache.js.map +1 -1
- package/dist/src/utils/filesearch/crawlCache.test.js +10 -0
- package/dist/src/utils/filesearch/crawlCache.test.js.map +1 -1
- package/dist/src/utils/filesearch/fileSearch.d.ts +2 -0
- package/dist/src/utils/filesearch/fileSearch.js +32 -7
- package/dist/src/utils/filesearch/fileSearch.js.map +1 -1
- package/dist/src/utils/filesearch/fileSearch.test.js +139 -0
- package/dist/src/utils/filesearch/fileSearch.test.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.js +4 -1
- package/dist/src/utils/memoryDiscovery.js.map +1 -1
- package/dist/src/utils/nextSpeakerChecker.js +5 -6
- package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
- package/dist/src/utils/nextSpeakerChecker.test.js +2 -2
- package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -1
- package/dist/src/utils/schemaValidator.d.ts +1 -8
- package/dist/src/utils/schemaValidator.js +1 -32
- package/dist/src/utils/schemaValidator.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -1
- package/dist/google-gemini-cli-core-0.1.17.tgz +0 -0
|
@@ -133,6 +133,7 @@ export type IdeContext = z.infer<typeof IdeContextSchema>;
|
|
|
133
133
|
* Zod schema for validating the 'ide/contextUpdate' notification from the IDE.
|
|
134
134
|
*/
|
|
135
135
|
export declare const IdeContextNotificationSchema: z.ZodObject<{
|
|
136
|
+
jsonrpc: z.ZodLiteral<"2.0">;
|
|
136
137
|
method: z.ZodLiteral<"ide/contextUpdate">;
|
|
137
138
|
params: z.ZodObject<{
|
|
138
139
|
workspaceState: z.ZodOptional<z.ZodObject<{
|
|
@@ -236,6 +237,7 @@ export declare const IdeContextNotificationSchema: z.ZodObject<{
|
|
|
236
237
|
}[] | undefined;
|
|
237
238
|
} | undefined;
|
|
238
239
|
};
|
|
240
|
+
jsonrpc: "2.0";
|
|
239
241
|
}, {
|
|
240
242
|
method: "ide/contextUpdate";
|
|
241
243
|
params: {
|
|
@@ -252,7 +254,100 @@ export declare const IdeContextNotificationSchema: z.ZodObject<{
|
|
|
252
254
|
}[] | undefined;
|
|
253
255
|
} | undefined;
|
|
254
256
|
};
|
|
257
|
+
jsonrpc: "2.0";
|
|
255
258
|
}>;
|
|
259
|
+
export declare const IdeDiffAcceptedNotificationSchema: z.ZodObject<{
|
|
260
|
+
jsonrpc: z.ZodLiteral<"2.0">;
|
|
261
|
+
method: z.ZodLiteral<"ide/diffAccepted">;
|
|
262
|
+
params: z.ZodObject<{
|
|
263
|
+
filePath: z.ZodString;
|
|
264
|
+
content: z.ZodString;
|
|
265
|
+
}, "strip", z.ZodTypeAny, {
|
|
266
|
+
filePath: string;
|
|
267
|
+
content: string;
|
|
268
|
+
}, {
|
|
269
|
+
filePath: string;
|
|
270
|
+
content: string;
|
|
271
|
+
}>;
|
|
272
|
+
}, "strip", z.ZodTypeAny, {
|
|
273
|
+
method: "ide/diffAccepted";
|
|
274
|
+
params: {
|
|
275
|
+
filePath: string;
|
|
276
|
+
content: string;
|
|
277
|
+
};
|
|
278
|
+
jsonrpc: "2.0";
|
|
279
|
+
}, {
|
|
280
|
+
method: "ide/diffAccepted";
|
|
281
|
+
params: {
|
|
282
|
+
filePath: string;
|
|
283
|
+
content: string;
|
|
284
|
+
};
|
|
285
|
+
jsonrpc: "2.0";
|
|
286
|
+
}>;
|
|
287
|
+
export declare const IdeDiffClosedNotificationSchema: z.ZodObject<{
|
|
288
|
+
jsonrpc: z.ZodLiteral<"2.0">;
|
|
289
|
+
method: z.ZodLiteral<"ide/diffClosed">;
|
|
290
|
+
params: z.ZodObject<{
|
|
291
|
+
filePath: z.ZodString;
|
|
292
|
+
content: z.ZodOptional<z.ZodString>;
|
|
293
|
+
}, "strip", z.ZodTypeAny, {
|
|
294
|
+
filePath: string;
|
|
295
|
+
content?: string | undefined;
|
|
296
|
+
}, {
|
|
297
|
+
filePath: string;
|
|
298
|
+
content?: string | undefined;
|
|
299
|
+
}>;
|
|
300
|
+
}, "strip", z.ZodTypeAny, {
|
|
301
|
+
method: "ide/diffClosed";
|
|
302
|
+
params: {
|
|
303
|
+
filePath: string;
|
|
304
|
+
content?: string | undefined;
|
|
305
|
+
};
|
|
306
|
+
jsonrpc: "2.0";
|
|
307
|
+
}, {
|
|
308
|
+
method: "ide/diffClosed";
|
|
309
|
+
params: {
|
|
310
|
+
filePath: string;
|
|
311
|
+
content?: string | undefined;
|
|
312
|
+
};
|
|
313
|
+
jsonrpc: "2.0";
|
|
314
|
+
}>;
|
|
315
|
+
export declare const CloseDiffResponseSchema: z.ZodEffects<z.ZodObject<{
|
|
316
|
+
content: z.ZodArray<z.ZodObject<{
|
|
317
|
+
text: z.ZodString;
|
|
318
|
+
type: z.ZodLiteral<"text">;
|
|
319
|
+
}, "strip", z.ZodTypeAny, {
|
|
320
|
+
text: string;
|
|
321
|
+
type: "text";
|
|
322
|
+
}, {
|
|
323
|
+
text: string;
|
|
324
|
+
type: "text";
|
|
325
|
+
}>, "many">;
|
|
326
|
+
}, "strip", z.ZodTypeAny, {
|
|
327
|
+
content: {
|
|
328
|
+
text: string;
|
|
329
|
+
type: "text";
|
|
330
|
+
}[];
|
|
331
|
+
}, {
|
|
332
|
+
content: {
|
|
333
|
+
text: string;
|
|
334
|
+
type: "text";
|
|
335
|
+
}[];
|
|
336
|
+
}>, {
|
|
337
|
+
content?: string | undefined;
|
|
338
|
+
}, {
|
|
339
|
+
content: {
|
|
340
|
+
text: string;
|
|
341
|
+
type: "text";
|
|
342
|
+
}[];
|
|
343
|
+
}>;
|
|
344
|
+
export type DiffUpdateResult = {
|
|
345
|
+
status: 'accepted';
|
|
346
|
+
content?: string;
|
|
347
|
+
} | {
|
|
348
|
+
status: 'rejected';
|
|
349
|
+
content: undefined;
|
|
350
|
+
};
|
|
256
351
|
type IdeContextSubscriber = (ideContext: IdeContext | undefined) => void;
|
|
257
352
|
/**
|
|
258
353
|
* Creates a new store for managing the IDE's context.
|
|
@@ -30,9 +30,54 @@ export const IdeContextSchema = z.object({
|
|
|
30
30
|
* Zod schema for validating the 'ide/contextUpdate' notification from the IDE.
|
|
31
31
|
*/
|
|
32
32
|
export const IdeContextNotificationSchema = z.object({
|
|
33
|
+
jsonrpc: z.literal('2.0'),
|
|
33
34
|
method: z.literal('ide/contextUpdate'),
|
|
34
35
|
params: IdeContextSchema,
|
|
35
36
|
});
|
|
37
|
+
export const IdeDiffAcceptedNotificationSchema = z.object({
|
|
38
|
+
jsonrpc: z.literal('2.0'),
|
|
39
|
+
method: z.literal('ide/diffAccepted'),
|
|
40
|
+
params: z.object({
|
|
41
|
+
filePath: z.string(),
|
|
42
|
+
content: z.string(),
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
export const IdeDiffClosedNotificationSchema = z.object({
|
|
46
|
+
jsonrpc: z.literal('2.0'),
|
|
47
|
+
method: z.literal('ide/diffClosed'),
|
|
48
|
+
params: z.object({
|
|
49
|
+
filePath: z.string(),
|
|
50
|
+
content: z.string().optional(),
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
export const CloseDiffResponseSchema = z
|
|
54
|
+
.object({
|
|
55
|
+
content: z
|
|
56
|
+
.array(z.object({
|
|
57
|
+
text: z.string(),
|
|
58
|
+
type: z.literal('text'),
|
|
59
|
+
}))
|
|
60
|
+
.min(1),
|
|
61
|
+
})
|
|
62
|
+
.transform((val, ctx) => {
|
|
63
|
+
try {
|
|
64
|
+
const parsed = JSON.parse(val.content[0].text);
|
|
65
|
+
const innerSchema = z.object({ content: z.string().optional() });
|
|
66
|
+
const validationResult = innerSchema.safeParse(parsed);
|
|
67
|
+
if (!validationResult.success) {
|
|
68
|
+
validationResult.error.issues.forEach((issue) => ctx.addIssue(issue));
|
|
69
|
+
return z.NEVER;
|
|
70
|
+
}
|
|
71
|
+
return validationResult.data;
|
|
72
|
+
}
|
|
73
|
+
catch (_) {
|
|
74
|
+
ctx.addIssue({
|
|
75
|
+
code: z.ZodIssueCode.custom,
|
|
76
|
+
message: 'Invalid JSON in text content',
|
|
77
|
+
});
|
|
78
|
+
return z.NEVER;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
36
81
|
/**
|
|
37
82
|
* Creates a new store for managing the IDE's context.
|
|
38
83
|
* This factory function encapsulates the state and logic, allowing for the creation
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ideContext.js","sourceRoot":"","sources":["../../../src/ide/ideContext.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAChC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,MAAM,EAAE,CAAC;SACN,MAAM,CAAC;QACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;QAChB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;KACtB,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,cAAc,EAAE,CAAC;SACd,MAAM,CAAC;QACN,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE;KAC1C,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC;AAGH;;GAEG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IACnD,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC;IACtC,MAAM,EAAE,gBAAgB;CACzB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"ideContext.js","sourceRoot":"","sources":["../../../src/ide/ideContext.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import { GoogleAuth } from 'google-auth-library';
|
|
7
|
+
const ALLOWED_HOSTS = [/^.+\.googleapis\.com$/, /^(.*\.)?luci\.app$/];
|
|
7
8
|
export class GoogleCredentialProvider {
|
|
8
9
|
config;
|
|
9
10
|
auth;
|
|
@@ -19,6 +20,14 @@ export class GoogleCredentialProvider {
|
|
|
19
20
|
_clientInformation;
|
|
20
21
|
constructor(config) {
|
|
21
22
|
this.config = config;
|
|
23
|
+
const url = this.config?.url || this.config?.httpUrl;
|
|
24
|
+
if (!url) {
|
|
25
|
+
throw new Error('URL must be provided in the config for Google Credentials provider');
|
|
26
|
+
}
|
|
27
|
+
const hostname = new URL(url).hostname;
|
|
28
|
+
if (!ALLOWED_HOSTS.some((pattern) => pattern.test(hostname))) {
|
|
29
|
+
throw new Error(`Host "${hostname}" is not an allowed host for Google Credential provider.`);
|
|
30
|
+
}
|
|
22
31
|
const scopes = this.config?.oauth?.scopes;
|
|
23
32
|
if (!scopes || scopes.length === 0) {
|
|
24
33
|
throw new Error('Scopes must be provided in the oauth config for Google Credentials provider');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-auth-provider.js","sourceRoot":"","sources":["../../../src/mcp/google-auth-provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD,MAAM,OAAO,wBAAwB;IAcN;IAbZ,IAAI,CAAa;IAElC,gEAAgE;IACvD,WAAW,GAAG,EAAE,CAAC;IACjB,cAAc,GAAwB;QAC7C,WAAW,EAAE,yBAAyB;QACtC,aAAa,EAAE,EAAE;QACjB,WAAW,EAAE,EAAE;QACf,cAAc,EAAE,EAAE;QAClB,0BAA0B,EAAE,MAAM;KACnC,CAAC;IACM,kBAAkB,CAA8B;IAExD,YAA6B,MAAwB;QAAxB,WAAM,GAAN,MAAM,CAAkB;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC;QAC1C,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,6EAA6E,CAC9E,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,CAAC;YACzB,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC,kBAAkB,CAAC;IACjC,CAAC;IAED,qBAAqB,CAAC,iBAA6C;QACjE,IAAI,CAAC,kBAAkB,GAAG,iBAAiB,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,MAAM;QACV,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QAC3C,MAAM,mBAAmB,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,CAAC;QAE1D,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,CAAC;YAC/B,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAC5D,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,MAAM,GAAgB;YAC1B,YAAY,EAAE,mBAAmB,CAAC,KAAK;YACvC,UAAU,EAAE,QAAQ;SACrB,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,UAAU,CAAC,OAAoB;QAC7B,6BAA6B;IAC/B,CAAC;IAED,uBAAuB,CAAC,iBAAsB;QAC5C,QAAQ;IACV,CAAC;IAED,gBAAgB,CAAC,aAAqB;QACpC,QAAQ;IACV,CAAC;IAED,YAAY;QACV,QAAQ;QACR,OAAO,EAAE,CAAC;IACZ,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"google-auth-provider.js","sourceRoot":"","sources":["../../../src/mcp/google-auth-provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD,MAAM,aAAa,GAAG,CAAC,uBAAuB,EAAE,oBAAoB,CAAC,CAAC;AAEtE,MAAM,OAAO,wBAAwB;IAcN;IAbZ,IAAI,CAAa;IAElC,gEAAgE;IACvD,WAAW,GAAG,EAAE,CAAC;IACjB,cAAc,GAAwB;QAC7C,WAAW,EAAE,yBAAyB;QACtC,aAAa,EAAE,EAAE;QACjB,WAAW,EAAE,EAAE;QACf,cAAc,EAAE,EAAE;QAClB,0BAA0B,EAAE,MAAM;KACnC,CAAC;IACM,kBAAkB,CAA8B;IAExD,YAA6B,MAAwB;QAAxB,WAAM,GAAN,MAAM,CAAkB;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;QACrD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,oEAAoE,CACrE,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;QACvC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;YAC7D,MAAM,IAAI,KAAK,CACb,SAAS,QAAQ,0DAA0D,CAC5E,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC;QAC1C,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,6EAA6E,CAC9E,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,CAAC;YACzB,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC,kBAAkB,CAAC;IACjC,CAAC;IAED,qBAAqB,CAAC,iBAA6C;QACjE,IAAI,CAAC,kBAAkB,GAAG,iBAAiB,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,MAAM;QACV,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QAC3C,MAAM,mBAAmB,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,CAAC;QAE1D,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,CAAC;YAC/B,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAC5D,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,MAAM,GAAgB;YAC1B,YAAY,EAAE,mBAAmB,CAAC,KAAK;YACvC,UAAU,EAAE,QAAQ;SACrB,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,UAAU,CAAC,OAAoB;QAC7B,6BAA6B;IAC/B,CAAC;IAED,uBAAuB,CAAC,iBAAsB;QAC5C,QAAQ;IACV,CAAC;IAED,gBAAgB,CAAC,aAAqB;QACpC,QAAQ;IACV,CAAC;IAED,YAAY;QACV,QAAQ;QACR,OAAO,EAAE,CAAC;IACZ,CAAC;CACF"}
|
|
@@ -8,29 +8,64 @@ import { GoogleCredentialProvider } from './google-auth-provider.js';
|
|
|
8
8
|
import { vi, describe, beforeEach, it, expect } from 'vitest';
|
|
9
9
|
vi.mock('google-auth-library');
|
|
10
10
|
describe('GoogleCredentialProvider', () => {
|
|
11
|
+
const validConfig = {
|
|
12
|
+
url: 'https://test.googleapis.com',
|
|
13
|
+
oauth: {
|
|
14
|
+
scopes: ['scope1', 'scope2'],
|
|
15
|
+
},
|
|
16
|
+
};
|
|
11
17
|
it('should throw an error if no scopes are provided', () => {
|
|
12
|
-
|
|
18
|
+
const config = {
|
|
19
|
+
url: 'https://test.googleapis.com',
|
|
20
|
+
};
|
|
21
|
+
expect(() => new GoogleCredentialProvider(config)).toThrow('Scopes must be provided in the oauth config for Google Credentials provider');
|
|
13
22
|
});
|
|
14
23
|
it('should use scopes from the config if provided', () => {
|
|
24
|
+
new GoogleCredentialProvider(validConfig);
|
|
25
|
+
expect(GoogleAuth).toHaveBeenCalledWith({
|
|
26
|
+
scopes: ['scope1', 'scope2'],
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
it('should throw an error for a non-allowlisted host', () => {
|
|
15
30
|
const config = {
|
|
31
|
+
url: 'https://example.com',
|
|
32
|
+
oauth: {
|
|
33
|
+
scopes: ['scope1', 'scope2'],
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
expect(() => new GoogleCredentialProvider(config)).toThrow('Host "example.com" is not an allowed host for Google Credential provider.');
|
|
37
|
+
});
|
|
38
|
+
it('should allow luci.app', () => {
|
|
39
|
+
const config = {
|
|
40
|
+
url: 'https://luci.app',
|
|
41
|
+
oauth: {
|
|
42
|
+
scopes: ['scope1', 'scope2'],
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
new GoogleCredentialProvider(config);
|
|
46
|
+
});
|
|
47
|
+
it('should allow sub.luci.app', () => {
|
|
48
|
+
const config = {
|
|
49
|
+
url: 'https://sub.luci.app',
|
|
16
50
|
oauth: {
|
|
17
51
|
scopes: ['scope1', 'scope2'],
|
|
18
52
|
},
|
|
19
53
|
};
|
|
20
54
|
new GoogleCredentialProvider(config);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
55
|
+
});
|
|
56
|
+
it('should not allow googleapis.com without a subdomain', () => {
|
|
57
|
+
const config = {
|
|
58
|
+
url: 'https://googleapis.com',
|
|
59
|
+
oauth: {
|
|
60
|
+
scopes: ['scope1', 'scope2'],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
expect(() => new GoogleCredentialProvider(config)).toThrow('Host "googleapis.com" is not an allowed host for Google Credential provider.');
|
|
24
64
|
});
|
|
25
65
|
describe('with provider instance', () => {
|
|
26
66
|
let provider;
|
|
27
67
|
beforeEach(() => {
|
|
28
|
-
|
|
29
|
-
oauth: {
|
|
30
|
-
scopes: ['scope1', 'scope2'],
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
provider = new GoogleCredentialProvider(config);
|
|
68
|
+
provider = new GoogleCredentialProvider(validConfig);
|
|
34
69
|
vi.clearAllMocks();
|
|
35
70
|
});
|
|
36
71
|
it('should return credentials', async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-auth-provider.test.js","sourceRoot":"","sources":["../../../src/mcp/google-auth-provider.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAQ,MAAM,QAAQ,CAAC;AAGpE,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;AAE/B,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,wBAAwB,
|
|
1
|
+
{"version":3,"file":"google-auth-provider.test.js","sourceRoot":"","sources":["../../../src/mcp/google-auth-provider.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,6 @@ import { GeminiEventType } from '../core/turn.js';
|
|
|
8
8
|
import { logLoopDetected } from '../telemetry/loggers.js';
|
|
9
9
|
import { LoopDetectedEvent, LoopType } from '../telemetry/types.js';
|
|
10
10
|
import { DEFAULT_GEMINI_FLASH_MODEL } from '../config/config.js';
|
|
11
|
-
import { Type } from '@google/genai';
|
|
12
11
|
const TOOL_CALL_LOOP_THRESHOLD = 5;
|
|
13
12
|
const CONTENT_LOOP_THRESHOLD = 10;
|
|
14
13
|
const CONTENT_CHUNK_SIZE = 50;
|
|
@@ -134,19 +133,23 @@ export class LoopDetectionService {
|
|
|
134
133
|
* as repetitive code structures are common and not necessarily loops.
|
|
135
134
|
*/
|
|
136
135
|
checkContentLoop(content) {
|
|
137
|
-
//
|
|
138
|
-
// To avoid false positives, we detect when we
|
|
139
|
-
//
|
|
136
|
+
// Different content elements can often contain repetitive syntax that is not indicative of a loop.
|
|
137
|
+
// To avoid false positives, we detect when we encounter different content types and
|
|
138
|
+
// reset tracking to avoid analyzing content that spans across different element boundaries.
|
|
140
139
|
const numFences = (content.match(/```/g) ?? []).length;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
140
|
+
const hasTable = /(^|\n)\s*(\|.*\||[|+-]{3,})/.test(content);
|
|
141
|
+
const hasListItem = /(^|\n)\s*[*-+]\s/.test(content) || /(^|\n)\s*\d+\.\s/.test(content);
|
|
142
|
+
const hasHeading = /(^|\n)#+\s/.test(content);
|
|
143
|
+
const hasBlockquote = /(^|\n)>\s/.test(content);
|
|
144
|
+
if (numFences || hasTable || hasListItem || hasHeading || hasBlockquote) {
|
|
145
|
+
// Reset tracking when different content elements are detected to avoid analyzing content
|
|
146
|
+
// that spans across different element boundaries.
|
|
144
147
|
this.resetContentTracking();
|
|
145
148
|
}
|
|
146
149
|
const wasInCodeBlock = this.inCodeBlock;
|
|
147
150
|
this.inCodeBlock =
|
|
148
151
|
numFences % 2 === 0 ? this.inCodeBlock : !this.inCodeBlock;
|
|
149
|
-
if (wasInCodeBlock) {
|
|
152
|
+
if (wasInCodeBlock || this.inCodeBlock) {
|
|
150
153
|
return false;
|
|
151
154
|
}
|
|
152
155
|
this.streamContentHistory += content;
|
|
@@ -266,14 +269,14 @@ Please analyze the conversation history to determine the possibility that the co
|
|
|
266
269
|
{ role: 'user', parts: [{ text: prompt }] },
|
|
267
270
|
];
|
|
268
271
|
const schema = {
|
|
269
|
-
type:
|
|
272
|
+
type: 'object',
|
|
270
273
|
properties: {
|
|
271
274
|
reasoning: {
|
|
272
|
-
type:
|
|
275
|
+
type: 'string',
|
|
273
276
|
description: 'Your reasoning on if the conversation is looping without forward progress.',
|
|
274
277
|
},
|
|
275
278
|
confidence: {
|
|
276
|
-
type:
|
|
279
|
+
type: 'number',
|
|
277
280
|
description: 'A number between 0.0 and 1.0 representing your confidence that the conversation is in an unproductive state.',
|
|
278
281
|
},
|
|
279
282
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loopDetectionService.js","sourceRoot":"","sources":["../../../src/services/loopDetectionService.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,eAAe,EAA2B,MAAM,iBAAiB,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,EAAU,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"loopDetectionService.js","sourceRoot":"","sources":["../../../src/services/loopDetectionService.ts"],"names":[],"mappings":"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"}
|
|
@@ -159,6 +159,58 @@ describe('LoopDetectionService', () => {
|
|
|
159
159
|
expect(isLoop).toBe(false);
|
|
160
160
|
expect(loggers.logLoopDetected).not.toHaveBeenCalled();
|
|
161
161
|
});
|
|
162
|
+
it('should not detect loops when content transitions into a code block', () => {
|
|
163
|
+
service.reset('');
|
|
164
|
+
const repeatedContent = createRepetitiveContent(1, CONTENT_CHUNK_SIZE);
|
|
165
|
+
// Add some repetitive content outside of code block
|
|
166
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 2; i++) {
|
|
167
|
+
service.addAndCheck(createContentEvent(repeatedContent));
|
|
168
|
+
}
|
|
169
|
+
// Now transition into a code block - this should prevent loop detection
|
|
170
|
+
// even though we were already close to the threshold
|
|
171
|
+
const codeBlockStart = '```javascript\n';
|
|
172
|
+
const isLoop = service.addAndCheck(createContentEvent(codeBlockStart));
|
|
173
|
+
expect(isLoop).toBe(false);
|
|
174
|
+
// Continue adding repetitive content inside the code block - should not trigger loop
|
|
175
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD; i++) {
|
|
176
|
+
const isLoopInside = service.addAndCheck(createContentEvent(repeatedContent));
|
|
177
|
+
expect(isLoopInside).toBe(false);
|
|
178
|
+
}
|
|
179
|
+
expect(loggers.logLoopDetected).not.toHaveBeenCalled();
|
|
180
|
+
});
|
|
181
|
+
it('should skip loop detection when already inside a code block (this.inCodeBlock)', () => {
|
|
182
|
+
service.reset('');
|
|
183
|
+
// Start with content that puts us inside a code block
|
|
184
|
+
service.addAndCheck(createContentEvent('Here is some code:\n```\n'));
|
|
185
|
+
// Verify we are now inside a code block and any content should be ignored for loop detection
|
|
186
|
+
const repeatedContent = createRepetitiveContent(1, CONTENT_CHUNK_SIZE);
|
|
187
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD + 5; i++) {
|
|
188
|
+
const isLoop = service.addAndCheck(createContentEvent(repeatedContent));
|
|
189
|
+
expect(isLoop).toBe(false);
|
|
190
|
+
}
|
|
191
|
+
expect(loggers.logLoopDetected).not.toHaveBeenCalled();
|
|
192
|
+
});
|
|
193
|
+
it('should correctly track inCodeBlock state with multiple fence transitions', () => {
|
|
194
|
+
service.reset('');
|
|
195
|
+
const repeatedContent = createRepetitiveContent(1, CONTENT_CHUNK_SIZE);
|
|
196
|
+
// Outside code block - should track content
|
|
197
|
+
service.addAndCheck(createContentEvent('Normal text '));
|
|
198
|
+
// Enter code block (1 fence) - should stop tracking
|
|
199
|
+
const enterResult = service.addAndCheck(createContentEvent('```\n'));
|
|
200
|
+
expect(enterResult).toBe(false);
|
|
201
|
+
// Inside code block - should not track loops
|
|
202
|
+
for (let i = 0; i < 5; i++) {
|
|
203
|
+
const insideResult = service.addAndCheck(createContentEvent(repeatedContent));
|
|
204
|
+
expect(insideResult).toBe(false);
|
|
205
|
+
}
|
|
206
|
+
// Exit code block (2nd fence) - should reset tracking but still return false
|
|
207
|
+
const exitResult = service.addAndCheck(createContentEvent('```\n'));
|
|
208
|
+
expect(exitResult).toBe(false);
|
|
209
|
+
// Enter code block again (3rd fence) - should stop tracking again
|
|
210
|
+
const reenterResult = service.addAndCheck(createContentEvent('```python\n'));
|
|
211
|
+
expect(reenterResult).toBe(false);
|
|
212
|
+
expect(loggers.logLoopDetected).not.toHaveBeenCalled();
|
|
213
|
+
});
|
|
162
214
|
it('should detect a loop when repetitive content is outside a code block', () => {
|
|
163
215
|
service.reset('');
|
|
164
216
|
const repeatedContent = createRepetitiveContent(1, CONTENT_CHUNK_SIZE);
|
|
@@ -222,6 +274,145 @@ describe('LoopDetectionService', () => {
|
|
|
222
274
|
}
|
|
223
275
|
expect(loggers.logLoopDetected).not.toHaveBeenCalled();
|
|
224
276
|
});
|
|
277
|
+
it('should reset tracking when a table is detected', () => {
|
|
278
|
+
service.reset('');
|
|
279
|
+
const repeatedContent = createRepetitiveContent(1, CONTENT_CHUNK_SIZE);
|
|
280
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
281
|
+
service.addAndCheck(createContentEvent(repeatedContent));
|
|
282
|
+
}
|
|
283
|
+
// This should reset tracking and not trigger a loop
|
|
284
|
+
service.addAndCheck(createContentEvent('| Column 1 | Column 2 |'));
|
|
285
|
+
// Add more repeated content after table - should not trigger loop
|
|
286
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
287
|
+
const isLoop = service.addAndCheck(createContentEvent(repeatedContent));
|
|
288
|
+
expect(isLoop).toBe(false);
|
|
289
|
+
}
|
|
290
|
+
expect(loggers.logLoopDetected).not.toHaveBeenCalled();
|
|
291
|
+
});
|
|
292
|
+
it('should reset tracking when a list item is detected', () => {
|
|
293
|
+
service.reset('');
|
|
294
|
+
const repeatedContent = createRepetitiveContent(1, CONTENT_CHUNK_SIZE);
|
|
295
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
296
|
+
service.addAndCheck(createContentEvent(repeatedContent));
|
|
297
|
+
}
|
|
298
|
+
// This should reset tracking and not trigger a loop
|
|
299
|
+
service.addAndCheck(createContentEvent('* List item'));
|
|
300
|
+
// Add more repeated content after list - should not trigger loop
|
|
301
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
302
|
+
const isLoop = service.addAndCheck(createContentEvent(repeatedContent));
|
|
303
|
+
expect(isLoop).toBe(false);
|
|
304
|
+
}
|
|
305
|
+
expect(loggers.logLoopDetected).not.toHaveBeenCalled();
|
|
306
|
+
});
|
|
307
|
+
it('should reset tracking when a heading is detected', () => {
|
|
308
|
+
service.reset('');
|
|
309
|
+
const repeatedContent = createRepetitiveContent(1, CONTENT_CHUNK_SIZE);
|
|
310
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
311
|
+
service.addAndCheck(createContentEvent(repeatedContent));
|
|
312
|
+
}
|
|
313
|
+
// This should reset tracking and not trigger a loop
|
|
314
|
+
service.addAndCheck(createContentEvent('## Heading'));
|
|
315
|
+
// Add more repeated content after heading - should not trigger loop
|
|
316
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
317
|
+
const isLoop = service.addAndCheck(createContentEvent(repeatedContent));
|
|
318
|
+
expect(isLoop).toBe(false);
|
|
319
|
+
}
|
|
320
|
+
expect(loggers.logLoopDetected).not.toHaveBeenCalled();
|
|
321
|
+
});
|
|
322
|
+
it('should reset tracking when a blockquote is detected', () => {
|
|
323
|
+
service.reset('');
|
|
324
|
+
const repeatedContent = createRepetitiveContent(1, CONTENT_CHUNK_SIZE);
|
|
325
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
326
|
+
service.addAndCheck(createContentEvent(repeatedContent));
|
|
327
|
+
}
|
|
328
|
+
// This should reset tracking and not trigger a loop
|
|
329
|
+
service.addAndCheck(createContentEvent('> Quote text'));
|
|
330
|
+
// Add more repeated content after blockquote - should not trigger loop
|
|
331
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
332
|
+
const isLoop = service.addAndCheck(createContentEvent(repeatedContent));
|
|
333
|
+
expect(isLoop).toBe(false);
|
|
334
|
+
}
|
|
335
|
+
expect(loggers.logLoopDetected).not.toHaveBeenCalled();
|
|
336
|
+
});
|
|
337
|
+
it('should reset tracking for various list item formats', () => {
|
|
338
|
+
const repeatedContent = createRepetitiveContent(1, CONTENT_CHUNK_SIZE);
|
|
339
|
+
// Test different list formats - make sure they start at beginning of line
|
|
340
|
+
const listFormats = [
|
|
341
|
+
'* Bullet item',
|
|
342
|
+
'- Dash item',
|
|
343
|
+
'+ Plus item',
|
|
344
|
+
'1. Numbered item',
|
|
345
|
+
'42. Another numbered item',
|
|
346
|
+
];
|
|
347
|
+
listFormats.forEach((listFormat, index) => {
|
|
348
|
+
service.reset('');
|
|
349
|
+
// Build up to near threshold
|
|
350
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
351
|
+
service.addAndCheck(createContentEvent(repeatedContent));
|
|
352
|
+
}
|
|
353
|
+
// Reset should occur with list item - add newline to ensure it starts at beginning
|
|
354
|
+
service.addAndCheck(createContentEvent('\n' + listFormat));
|
|
355
|
+
// Should not trigger loop after reset - use different content to avoid any cached state issues
|
|
356
|
+
const newRepeatedContent = createRepetitiveContent(index + 100, CONTENT_CHUNK_SIZE);
|
|
357
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
358
|
+
const isLoop = service.addAndCheck(createContentEvent(newRepeatedContent));
|
|
359
|
+
expect(isLoop).toBe(false);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
expect(loggers.logLoopDetected).not.toHaveBeenCalled();
|
|
363
|
+
});
|
|
364
|
+
it('should reset tracking for various table formats', () => {
|
|
365
|
+
const repeatedContent = createRepetitiveContent(1, CONTENT_CHUNK_SIZE);
|
|
366
|
+
const tableFormats = [
|
|
367
|
+
'| Column 1 | Column 2 |',
|
|
368
|
+
'|---|---|',
|
|
369
|
+
'|++|++|',
|
|
370
|
+
'+---+---+',
|
|
371
|
+
];
|
|
372
|
+
tableFormats.forEach((tableFormat, index) => {
|
|
373
|
+
service.reset('');
|
|
374
|
+
// Build up to near threshold
|
|
375
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
376
|
+
service.addAndCheck(createContentEvent(repeatedContent));
|
|
377
|
+
}
|
|
378
|
+
// Reset should occur with table format - add newline to ensure it starts at beginning
|
|
379
|
+
service.addAndCheck(createContentEvent('\n' + tableFormat));
|
|
380
|
+
// Should not trigger loop after reset - use different content to avoid any cached state issues
|
|
381
|
+
const newRepeatedContent = createRepetitiveContent(index + 200, CONTENT_CHUNK_SIZE);
|
|
382
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
383
|
+
const isLoop = service.addAndCheck(createContentEvent(newRepeatedContent));
|
|
384
|
+
expect(isLoop).toBe(false);
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
expect(loggers.logLoopDetected).not.toHaveBeenCalled();
|
|
388
|
+
});
|
|
389
|
+
it('should reset tracking for various heading levels', () => {
|
|
390
|
+
const repeatedContent = createRepetitiveContent(1, CONTENT_CHUNK_SIZE);
|
|
391
|
+
const headingFormats = [
|
|
392
|
+
'# H1 Heading',
|
|
393
|
+
'## H2 Heading',
|
|
394
|
+
'### H3 Heading',
|
|
395
|
+
'#### H4 Heading',
|
|
396
|
+
'##### H5 Heading',
|
|
397
|
+
'###### H6 Heading',
|
|
398
|
+
];
|
|
399
|
+
headingFormats.forEach((headingFormat, index) => {
|
|
400
|
+
service.reset('');
|
|
401
|
+
// Build up to near threshold
|
|
402
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
403
|
+
service.addAndCheck(createContentEvent(repeatedContent));
|
|
404
|
+
}
|
|
405
|
+
// Reset should occur with heading - add newline to ensure it starts at beginning
|
|
406
|
+
service.addAndCheck(createContentEvent('\n' + headingFormat));
|
|
407
|
+
// Should not trigger loop after reset - use different content to avoid any cached state issues
|
|
408
|
+
const newRepeatedContent = createRepetitiveContent(index + 300, CONTENT_CHUNK_SIZE);
|
|
409
|
+
for (let i = 0; i < CONTENT_LOOP_THRESHOLD - 1; i++) {
|
|
410
|
+
const isLoop = service.addAndCheck(createContentEvent(newRepeatedContent));
|
|
411
|
+
expect(isLoop).toBe(false);
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
expect(loggers.logLoopDetected).not.toHaveBeenCalled();
|
|
415
|
+
});
|
|
225
416
|
});
|
|
226
417
|
describe('Edge Cases', () => {
|
|
227
418
|
it('should handle empty content', () => {
|