@google/gemini-cli-core 0.1.18 → 0.1.19-nightly.250814.514e883a

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 (285) hide show
  1. package/README.md +199 -132
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.js +3 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/src/code_assist/converter.d.ts +3 -2
  6. package/dist/src/code_assist/converter.js +2 -2
  7. package/dist/src/code_assist/converter.js.map +1 -1
  8. package/dist/src/code_assist/converter.test.js +48 -1
  9. package/dist/src/code_assist/converter.test.js.map +1 -1
  10. package/dist/src/code_assist/oauth2.js +1 -1
  11. package/dist/src/code_assist/oauth2.js.map +1 -1
  12. package/dist/src/code_assist/server.test.js +4 -1
  13. package/dist/src/code_assist/server.test.js.map +1 -1
  14. package/dist/src/code_assist/setup.js +48 -17
  15. package/dist/src/code_assist/setup.js.map +1 -1
  16. package/dist/src/code_assist/setup.test.js +105 -5
  17. package/dist/src/code_assist/setup.test.js.map +1 -1
  18. package/dist/src/config/config.d.ts +25 -6
  19. package/dist/src/config/config.js +47 -16
  20. package/dist/src/config/config.js.map +1 -1
  21. package/dist/src/config/config.test.js +95 -1
  22. package/dist/src/config/config.test.js.map +1 -1
  23. package/dist/src/core/client.d.ts +8 -5
  24. package/dist/src/core/client.js +184 -119
  25. package/dist/src/core/client.js.map +1 -1
  26. package/dist/src/core/client.test.js +342 -37
  27. package/dist/src/core/client.test.js.map +1 -1
  28. package/dist/src/core/contentGenerator.js +3 -2
  29. package/dist/src/core/contentGenerator.js.map +1 -1
  30. package/dist/src/core/contentGenerator.test.js +3 -2
  31. package/dist/src/core/contentGenerator.test.js.map +1 -1
  32. package/dist/src/core/coreToolScheduler.d.ts +21 -8
  33. package/dist/src/core/coreToolScheduler.js +170 -61
  34. package/dist/src/core/coreToolScheduler.js.map +1 -1
  35. package/dist/src/core/coreToolScheduler.test.js +183 -41
  36. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  37. package/dist/src/core/geminiChat.d.ts +7 -6
  38. package/dist/src/core/geminiChat.js +43 -43
  39. package/dist/src/core/geminiChat.js.map +1 -1
  40. package/dist/src/core/logger.d.ts +1 -0
  41. package/dist/src/core/logger.js +18 -0
  42. package/dist/src/core/logger.js.map +1 -1
  43. package/dist/src/core/logger.test.js +29 -0
  44. package/dist/src/core/logger.test.js.map +1 -1
  45. package/dist/src/core/loggingContentGenerator.d.ts +29 -0
  46. package/dist/src/core/loggingContentGenerator.js +97 -0
  47. package/dist/src/core/loggingContentGenerator.js.map +1 -0
  48. package/dist/src/core/nonInteractiveToolExecutor.js +20 -1
  49. package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
  50. package/dist/src/core/nonInteractiveToolExecutor.test.js +7 -31
  51. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
  52. package/dist/src/core/subagent.d.ts +230 -0
  53. package/dist/src/core/subagent.js +447 -0
  54. package/dist/src/core/subagent.js.map +1 -0
  55. package/dist/src/core/subagent.test.d.ts +6 -0
  56. package/dist/src/core/subagent.test.js +515 -0
  57. package/dist/src/core/subagent.test.js.map +1 -0
  58. package/dist/src/core/turn.js +1 -0
  59. package/dist/src/core/turn.js.map +1 -1
  60. package/dist/src/core/turn.test.js +4 -0
  61. package/dist/src/core/turn.test.js.map +1 -1
  62. package/dist/src/ide/detect-ide.d.ts +12 -2
  63. package/dist/src/ide/detect-ide.js +64 -5
  64. package/dist/src/ide/detect-ide.js.map +1 -1
  65. package/dist/src/ide/detect-ide.test.d.ts +6 -0
  66. package/dist/src/ide/detect-ide.test.js +65 -0
  67. package/dist/src/ide/detect-ide.test.js.map +1 -0
  68. package/dist/src/ide/ide-client.d.ts +20 -1
  69. package/dist/src/ide/ide-client.js +145 -19
  70. package/dist/src/ide/ide-client.js.map +1 -1
  71. package/dist/src/ide/ide-installer.js +1 -26
  72. package/dist/src/ide/ide-installer.js.map +1 -1
  73. package/dist/src/ide/ide-installer.test.js +0 -4
  74. package/dist/src/ide/ide-installer.test.js.map +1 -1
  75. package/dist/src/ide/ideContext.d.ts +95 -0
  76. package/dist/src/ide/ideContext.js +45 -0
  77. package/dist/src/ide/ideContext.js.map +1 -1
  78. package/dist/src/index.d.ts +2 -1
  79. package/dist/src/index.js +2 -1
  80. package/dist/src/index.js.map +1 -1
  81. package/dist/src/mcp/google-auth-provider.js +9 -0
  82. package/dist/src/mcp/google-auth-provider.js.map +1 -1
  83. package/dist/src/mcp/google-auth-provider.test.js +45 -10
  84. package/dist/src/mcp/google-auth-provider.test.js.map +1 -1
  85. package/dist/src/mcp/oauth-provider.d.ts +0 -1
  86. package/dist/src/mcp/oauth-provider.js +0 -1
  87. package/dist/src/mcp/oauth-provider.js.map +1 -1
  88. package/dist/src/mocks/msw.d.ts +6 -0
  89. package/dist/src/mocks/msw.js +8 -0
  90. package/dist/src/mocks/msw.js.map +1 -0
  91. package/dist/src/services/loopDetectionService.js +14 -11
  92. package/dist/src/services/loopDetectionService.js.map +1 -1
  93. package/dist/src/services/loopDetectionService.test.js +191 -0
  94. package/dist/src/services/loopDetectionService.test.js.map +1 -1
  95. package/dist/src/services/shellExecutionService.js +29 -9
  96. package/dist/src/services/shellExecutionService.js.map +1 -1
  97. package/dist/src/services/shellExecutionService.test.js +8 -0
  98. package/dist/src/services/shellExecutionService.test.js.map +1 -1
  99. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +50 -7
  100. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +236 -116
  101. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  102. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.d.ts +6 -0
  103. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +281 -0
  104. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -0
  105. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +8 -1
  106. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +17 -0
  107. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  108. package/dist/src/telemetry/index.d.ts +2 -2
  109. package/dist/src/telemetry/index.js +2 -2
  110. package/dist/src/telemetry/index.js.map +1 -1
  111. package/dist/src/telemetry/loggers.d.ts +2 -1
  112. package/dist/src/telemetry/loggers.js +15 -0
  113. package/dist/src/telemetry/loggers.js.map +1 -1
  114. package/dist/src/telemetry/loggers.test.circular.js +7 -2
  115. package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
  116. package/dist/src/telemetry/loggers.test.js +7 -2
  117. package/dist/src/telemetry/loggers.test.js.map +1 -1
  118. package/dist/src/telemetry/metrics.d.ts +3 -2
  119. package/dist/src/telemetry/metrics.js +7 -1
  120. package/dist/src/telemetry/metrics.js.map +1 -1
  121. package/dist/src/telemetry/metrics.test.js +50 -0
  122. package/dist/src/telemetry/metrics.test.js.map +1 -1
  123. package/dist/src/telemetry/sdk.d.ts +1 -1
  124. package/dist/src/telemetry/sdk.js +13 -5
  125. package/dist/src/telemetry/sdk.js.map +1 -1
  126. package/dist/src/telemetry/telemetry.test.js +2 -2
  127. package/dist/src/telemetry/telemetry.test.js.map +1 -1
  128. package/dist/src/telemetry/tool-call-decision.d.ts +13 -0
  129. package/dist/src/telemetry/tool-call-decision.js +29 -0
  130. package/dist/src/telemetry/tool-call-decision.js.map +1 -0
  131. package/dist/src/telemetry/types.d.ts +37 -21
  132. package/dist/src/telemetry/types.js +55 -44
  133. package/dist/src/telemetry/types.js.map +1 -1
  134. package/dist/src/telemetry/uiTelemetry.d.ts +4 -1
  135. package/dist/src/telemetry/uiTelemetry.js +3 -1
  136. package/dist/src/telemetry/uiTelemetry.js.map +1 -1
  137. package/dist/src/telemetry/uiTelemetry.test.js +13 -2
  138. package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
  139. package/dist/src/test-utils/config.d.ts +16 -0
  140. package/dist/src/test-utils/config.js +32 -0
  141. package/dist/src/test-utils/config.js.map +1 -0
  142. package/dist/src/test-utils/tools.d.ts +23 -0
  143. package/dist/src/test-utils/tools.js +41 -0
  144. package/dist/src/test-utils/tools.js.map +1 -0
  145. package/dist/src/tools/diffOptions.d.ts +2 -0
  146. package/dist/src/tools/diffOptions.js +28 -0
  147. package/dist/src/tools/diffOptions.js.map +1 -1
  148. package/dist/src/tools/diffOptions.test.d.ts +6 -0
  149. package/dist/src/tools/diffOptions.test.js +119 -0
  150. package/dist/src/tools/diffOptions.test.js.map +1 -0
  151. package/dist/src/tools/edit.d.ts +9 -33
  152. package/dist/src/tools/edit.js +142 -132
  153. package/dist/src/tools/edit.js.map +1 -1
  154. package/dist/src/tools/edit.test.js +115 -51
  155. package/dist/src/tools/edit.test.js.map +1 -1
  156. package/dist/src/tools/glob.d.ts +3 -10
  157. package/dist/src/tools/glob.js +85 -89
  158. package/dist/src/tools/glob.js.map +1 -1
  159. package/dist/src/tools/glob.test.js +22 -12
  160. package/dist/src/tools/glob.test.js.map +1 -1
  161. package/dist/src/tools/grep.d.ts +3 -35
  162. package/dist/src/tools/grep.js +111 -83
  163. package/dist/src/tools/grep.js.map +1 -1
  164. package/dist/src/tools/grep.test.js +40 -23
  165. package/dist/src/tools/grep.test.js.map +1 -1
  166. package/dist/src/tools/ls.d.ts +3 -22
  167. package/dist/src/tools/ls.js +81 -78
  168. package/dist/src/tools/ls.js.map +1 -1
  169. package/dist/src/tools/ls.test.js +62 -34
  170. package/dist/src/tools/ls.test.js.map +1 -1
  171. package/dist/src/tools/mcp-client.d.ts +14 -3
  172. package/dist/src/tools/mcp-client.js +82 -6
  173. package/dist/src/tools/mcp-client.js.map +1 -1
  174. package/dist/src/tools/mcp-client.test.js +340 -5
  175. package/dist/src/tools/mcp-client.test.js.map +1 -1
  176. package/dist/src/tools/mcp-tool.d.ts +6 -13
  177. package/dist/src/tools/mcp-tool.js +41 -31
  178. package/dist/src/tools/mcp-tool.js.map +1 -1
  179. package/dist/src/tools/mcp-tool.test.js +53 -51
  180. package/dist/src/tools/mcp-tool.test.js.map +1 -1
  181. package/dist/src/tools/memoryTool.d.ts +10 -14
  182. package/dist/src/tools/memoryTool.js +128 -121
  183. package/dist/src/tools/memoryTool.js.map +1 -1
  184. package/dist/src/tools/memoryTool.test.js +38 -18
  185. package/dist/src/tools/memoryTool.test.js.map +1 -1
  186. package/dist/src/tools/modifiable-tool.d.ts +8 -5
  187. package/dist/src/tools/modifiable-tool.js +4 -1
  188. package/dist/src/tools/modifiable-tool.js.map +1 -1
  189. package/dist/src/tools/modifiable-tool.test.js +3 -3
  190. package/dist/src/tools/modifiable-tool.test.js.map +1 -1
  191. package/dist/src/tools/read-file.d.ts +4 -6
  192. package/dist/src/tools/read-file.js +92 -45
  193. package/dist/src/tools/read-file.js.map +1 -1
  194. package/dist/src/tools/read-file.test.js +192 -130
  195. package/dist/src/tools/read-file.test.js.map +1 -1
  196. package/dist/src/tools/read-many-files.d.ts +4 -5
  197. package/dist/src/tools/read-many-files.js +120 -103
  198. package/dist/src/tools/read-many-files.js.map +1 -1
  199. package/dist/src/tools/read-many-files.test.js +81 -47
  200. package/dist/src/tools/read-many-files.test.js.map +1 -1
  201. package/dist/src/tools/shell.d.ts +4 -6
  202. package/dist/src/tools/shell.js +99 -101
  203. package/dist/src/tools/shell.js.map +1 -1
  204. package/dist/src/tools/shell.test.js +43 -28
  205. package/dist/src/tools/shell.test.js.map +1 -1
  206. package/dist/src/tools/tool-error.d.ts +4 -0
  207. package/dist/src/tools/tool-error.js +4 -0
  208. package/dist/src/tools/tool-error.js.map +1 -1
  209. package/dist/src/tools/tool-registry.d.ts +17 -20
  210. package/dist/src/tools/tool-registry.js +35 -77
  211. package/dist/src/tools/tool-registry.js.map +1 -1
  212. package/dist/src/tools/tool-registry.test.js +19 -192
  213. package/dist/src/tools/tool-registry.test.js.map +1 -1
  214. package/dist/src/tools/tools.d.ts +156 -54
  215. package/dist/src/tools/tools.js +196 -25
  216. package/dist/src/tools/tools.js.map +1 -1
  217. package/dist/src/tools/tools.test.d.ts +6 -0
  218. package/dist/src/tools/tools.test.js +117 -0
  219. package/dist/src/tools/tools.test.js.map +1 -0
  220. package/dist/src/tools/web-fetch.d.ts +4 -7
  221. package/dist/src/tools/web-fetch.js +62 -63
  222. package/dist/src/tools/web-fetch.js.map +1 -1
  223. package/dist/src/tools/web-fetch.test.js +8 -4
  224. package/dist/src/tools/web-fetch.test.js.map +1 -1
  225. package/dist/src/tools/web-search.js +3 -3
  226. package/dist/src/tools/web-search.js.map +1 -1
  227. package/dist/src/tools/write-file.d.ts +8 -3
  228. package/dist/src/tools/write-file.js +89 -22
  229. package/dist/src/tools/write-file.js.map +1 -1
  230. package/dist/src/tools/write-file.test.js +112 -8
  231. package/dist/src/tools/write-file.test.js.map +1 -1
  232. package/dist/src/utils/bfsFileSearch.test.js +28 -56
  233. package/dist/src/utils/bfsFileSearch.test.js.map +1 -1
  234. package/dist/src/utils/editCorrector.js +8 -9
  235. package/dist/src/utils/editCorrector.js.map +1 -1
  236. package/dist/src/utils/environmentContext.d.ts +21 -0
  237. package/dist/src/utils/environmentContext.js +90 -0
  238. package/dist/src/utils/environmentContext.js.map +1 -0
  239. package/dist/src/utils/environmentContext.test.d.ts +6 -0
  240. package/dist/src/utils/environmentContext.test.js +139 -0
  241. package/dist/src/utils/environmentContext.test.js.map +1 -0
  242. package/dist/src/utils/errorParsing.d.ts +8 -0
  243. package/dist/src/utils/errorParsing.js +93 -0
  244. package/dist/src/utils/errorParsing.js.map +1 -0
  245. package/dist/src/utils/errorParsing.test.d.ts +6 -0
  246. package/dist/src/utils/errorParsing.test.js +172 -0
  247. package/dist/src/utils/errorParsing.test.js.map +1 -0
  248. package/dist/src/utils/fileUtils.d.ts +7 -0
  249. package/dist/src/utils/fileUtils.js +15 -12
  250. package/dist/src/utils/fileUtils.js.map +1 -1
  251. package/dist/src/utils/fileUtils.test.js +6 -5
  252. package/dist/src/utils/fileUtils.test.js.map +1 -1
  253. package/dist/src/utils/filesearch/crawlCache.d.ts +1 -1
  254. package/dist/src/utils/filesearch/crawlCache.js +4 -1
  255. package/dist/src/utils/filesearch/crawlCache.js.map +1 -1
  256. package/dist/src/utils/filesearch/crawlCache.test.js +10 -0
  257. package/dist/src/utils/filesearch/crawlCache.test.js.map +1 -1
  258. package/dist/src/utils/filesearch/fileSearch.d.ts +2 -0
  259. package/dist/src/utils/filesearch/fileSearch.js +33 -8
  260. package/dist/src/utils/filesearch/fileSearch.js.map +1 -1
  261. package/dist/src/utils/filesearch/fileSearch.test.js +139 -0
  262. package/dist/src/utils/filesearch/fileSearch.test.js.map +1 -1
  263. package/dist/src/utils/filesearch/result-cache.d.ts +1 -2
  264. package/dist/src/utils/filesearch/result-cache.js +1 -3
  265. package/dist/src/utils/filesearch/result-cache.js.map +1 -1
  266. package/dist/src/utils/filesearch/result-cache.test.js +3 -4
  267. package/dist/src/utils/filesearch/result-cache.test.js.map +1 -1
  268. package/dist/src/utils/memoryDiscovery.js +4 -1
  269. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  270. package/dist/src/utils/memoryImportProcessor.js +1 -1
  271. package/dist/src/utils/memoryImportProcessor.js.map +1 -1
  272. package/dist/src/utils/memoryImportProcessor.test.js +17 -20
  273. package/dist/src/utils/memoryImportProcessor.test.js.map +1 -1
  274. package/dist/src/utils/nextSpeakerChecker.js +5 -6
  275. package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
  276. package/dist/src/utils/nextSpeakerChecker.test.js +2 -2
  277. package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -1
  278. package/dist/src/utils/quotaErrorDetection.d.ts +1 -5
  279. package/dist/src/utils/quotaErrorDetection.js.map +1 -1
  280. package/dist/src/utils/schemaValidator.d.ts +1 -8
  281. package/dist/src/utils/schemaValidator.js +1 -32
  282. package/dist/src/utils/schemaValidator.js.map +1 -1
  283. package/dist/tsconfig.tsbuildinfo +1 -1
  284. package/package.json +3 -1
  285. package/dist/google-gemini-cli-core-0.1.17.tgz +0 -0
@@ -170,11 +170,13 @@ describe('Gemini Client (client.ts)', () => {
170
170
  getUsageStatisticsEnabled: vi.fn().mockReturnValue(true),
171
171
  getIdeModeFeature: vi.fn().mockReturnValue(false),
172
172
  getIdeMode: vi.fn().mockReturnValue(true),
173
+ getDebugMode: vi.fn().mockReturnValue(false),
173
174
  getWorkspaceContext: vi.fn().mockReturnValue({
174
175
  getDirectories: vi.fn().mockReturnValue(['/test/dir']),
175
176
  }),
176
177
  getGeminiClient: vi.fn(),
177
178
  setFallbackMode: vi.fn(),
179
+ getChatCompression: vi.fn().mockReturnValue(undefined),
178
180
  };
179
181
  const MockedConfig = vi.mocked(Config, true);
180
182
  MockedConfig.mockImplementation(() => mockConfigObject);
@@ -314,7 +316,7 @@ describe('Gemini Client (client.ts)', () => {
314
316
  systemInstruction: getCoreSystemPrompt(''),
315
317
  temperature: 0,
316
318
  topP: 1,
317
- responseSchema: schema,
319
+ responseJsonSchema: schema,
318
320
  responseMimeType: 'application/json',
319
321
  },
320
322
  contents,
@@ -340,7 +342,7 @@ describe('Gemini Client (client.ts)', () => {
340
342
  temperature: 0.9,
341
343
  topP: 1, // from default
342
344
  topK: 20,
343
- responseSchema: schema,
345
+ responseJsonSchema: schema,
344
346
  responseMimeType: 'application/json',
345
347
  },
346
348
  contents,
@@ -352,7 +354,6 @@ describe('Gemini Client (client.ts)', () => {
352
354
  const mockChat = {
353
355
  addHistory: vi.fn(),
354
356
  };
355
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
356
357
  client['chat'] = mockChat;
357
358
  const newContent = {
358
359
  role: 'user',
@@ -418,13 +419,17 @@ describe('Gemini Client (client.ts)', () => {
418
419
  expect(result).toBeNull();
419
420
  expect(newChat).toBe(initialChat);
420
421
  });
421
- it('should trigger summarization if token count is at threshold', async () => {
422
+ it('should trigger summarization if token count is at threshold with contextPercentageThreshold setting', async () => {
422
423
  const MOCKED_TOKEN_LIMIT = 1000;
424
+ const MOCKED_CONTEXT_PERCENTAGE_THRESHOLD = 0.5;
423
425
  vi.mocked(tokenLimit).mockReturnValue(MOCKED_TOKEN_LIMIT);
426
+ vi.spyOn(client['config'], 'getChatCompression').mockReturnValue({
427
+ contextPercentageThreshold: MOCKED_CONTEXT_PERCENTAGE_THRESHOLD,
428
+ });
424
429
  mockGetHistory.mockReturnValue([
425
430
  { role: 'user', parts: [{ text: '...history...' }] },
426
431
  ]);
427
- const originalTokenCount = 1000 * 0.7;
432
+ const originalTokenCount = MOCKED_TOKEN_LIMIT * MOCKED_CONTEXT_PERCENTAGE_THRESHOLD;
428
433
  const newTokenCount = 100;
429
434
  mockCountTokens
430
435
  .mockResolvedValueOnce({ totalTokens: originalTokenCount }) // First call for the check
@@ -524,7 +529,7 @@ describe('Gemini Client (client.ts)', () => {
524
529
  });
525
530
  });
526
531
  describe('sendMessageStream', () => {
527
- it('should include IDE context when ideModeFeature is enabled', async () => {
532
+ it('should include editor context when ideMode is enabled', async () => {
528
533
  // Arrange
529
534
  vi.mocked(ideContext.getIdeContext).mockReturnValue({
530
535
  workspaceState: {
@@ -547,7 +552,7 @@ describe('Gemini Client (client.ts)', () => {
547
552
  ],
548
553
  },
549
554
  });
550
- vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
555
+ vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
551
556
  const mockStream = (async function* () {
552
557
  yield { type: 'content', value: 'Hello' };
553
558
  })();
@@ -571,27 +576,35 @@ describe('Gemini Client (client.ts)', () => {
571
576
  // Assert
572
577
  expect(ideContext.getIdeContext).toHaveBeenCalled();
573
578
  const expectedContext = `
574
- This is the file that the user is looking at:
575
- - Path: /path/to/active/file.ts
576
- This is the cursor position in the file:
577
- - Cursor Position: Line 5, Character 10
578
- This is the selected text in the file:
579
- - hello
580
- Here are some other files the user has open, with the most recent at the top:
581
- - /path/to/recent/file1.ts
582
- - /path/to/recent/file2.ts
579
+ Here is the user's editor context as a JSON object. This is for your information only.
580
+ \`\`\`json
581
+ ${JSON.stringify({
582
+ activeFile: {
583
+ path: '/path/to/active/file.ts',
584
+ cursor: {
585
+ line: 5,
586
+ character: 10,
587
+ },
588
+ selectedText: 'hello',
589
+ },
590
+ otherOpenFiles: ['/path/to/recent/file1.ts', '/path/to/recent/file2.ts'],
591
+ }, null, 2)}
592
+ \`\`\`
583
593
  `.trim();
584
- const expectedRequest = [{ text: expectedContext }, ...initialRequest];
585
- expect(mockTurnRunFn).toHaveBeenCalledWith(expectedRequest, expect.any(Object));
594
+ const expectedRequest = [{ text: expectedContext }];
595
+ expect(mockChat.addHistory).toHaveBeenCalledWith({
596
+ role: 'user',
597
+ parts: expectedRequest,
598
+ });
586
599
  });
587
- it('should not add context if ideModeFeature is enabled but no open files', async () => {
600
+ it('should not add context if ideMode is enabled but no open files', async () => {
588
601
  // Arrange
589
602
  vi.mocked(ideContext.getIdeContext).mockReturnValue({
590
603
  workspaceState: {
591
604
  openFiles: [],
592
605
  },
593
606
  });
594
- vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
607
+ vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
595
608
  const mockStream = (async function* () {
596
609
  yield { type: 'content', value: 'Hello' };
597
610
  })();
@@ -616,7 +629,7 @@ Here are some other files the user has open, with the most recent at the top:
616
629
  expect(ideContext.getIdeContext).toHaveBeenCalled();
617
630
  expect(mockTurnRunFn).toHaveBeenCalledWith(initialRequest, expect.any(Object));
618
631
  });
619
- it('should add context if ideModeFeature is enabled and there is one active file', async () => {
632
+ it('should add context if ideMode is enabled and there is one active file', async () => {
620
633
  // Arrange
621
634
  vi.mocked(ideContext.getIdeContext).mockReturnValue({
622
635
  workspaceState: {
@@ -631,7 +644,7 @@ Here are some other files the user has open, with the most recent at the top:
631
644
  ],
632
645
  },
633
646
  });
634
- vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
647
+ vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
635
648
  const mockStream = (async function* () {
636
649
  yield { type: 'content', value: 'Hello' };
637
650
  })();
@@ -655,17 +668,27 @@ Here are some other files the user has open, with the most recent at the top:
655
668
  // Assert
656
669
  expect(ideContext.getIdeContext).toHaveBeenCalled();
657
670
  const expectedContext = `
658
- This is the file that the user is looking at:
659
- - Path: /path/to/active/file.ts
660
- This is the cursor position in the file:
661
- - Cursor Position: Line 5, Character 10
662
- This is the selected text in the file:
663
- - hello
671
+ Here is the user's editor context as a JSON object. This is for your information only.
672
+ \`\`\`json
673
+ ${JSON.stringify({
674
+ activeFile: {
675
+ path: '/path/to/active/file.ts',
676
+ cursor: {
677
+ line: 5,
678
+ character: 10,
679
+ },
680
+ selectedText: 'hello',
681
+ },
682
+ }, null, 2)}
683
+ \`\`\`
664
684
  `.trim();
665
- const expectedRequest = [{ text: expectedContext }, ...initialRequest];
666
- expect(mockTurnRunFn).toHaveBeenCalledWith(expectedRequest, expect.any(Object));
685
+ const expectedRequest = [{ text: expectedContext }];
686
+ expect(mockChat.addHistory).toHaveBeenCalledWith({
687
+ role: 'user',
688
+ parts: expectedRequest,
689
+ });
667
690
  });
668
- it('should add context if ideModeFeature is enabled and there are open files but no active file', async () => {
691
+ it('should add context if ideMode is enabled and there are open files but no active file', async () => {
669
692
  // Arrange
670
693
  vi.mocked(ideContext.getIdeContext).mockReturnValue({
671
694
  workspaceState: {
@@ -681,7 +704,7 @@ This is the selected text in the file:
681
704
  ],
682
705
  },
683
706
  });
684
- vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
707
+ vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
685
708
  const mockStream = (async function* () {
686
709
  yield { type: 'content', value: 'Hello' };
687
710
  })();
@@ -705,12 +728,18 @@ This is the selected text in the file:
705
728
  // Assert
706
729
  expect(ideContext.getIdeContext).toHaveBeenCalled();
707
730
  const expectedContext = `
708
- Here are some files the user has open, with the most recent at the top:
709
- - /path/to/recent/file1.ts
710
- - /path/to/recent/file2.ts
731
+ Here is the user's editor context as a JSON object. This is for your information only.
732
+ \`\`\`json
733
+ ${JSON.stringify({
734
+ otherOpenFiles: ['/path/to/recent/file1.ts', '/path/to/recent/file2.ts'],
735
+ }, null, 2)}
736
+ \`\`\`
711
737
  `.trim();
712
- const expectedRequest = [{ text: expectedContext }, ...initialRequest];
713
- expect(mockTurnRunFn).toHaveBeenCalledWith(expectedRequest, expect.any(Object));
738
+ const expectedRequest = [{ text: expectedContext }];
739
+ expect(mockChat.addHistory).toHaveBeenCalledWith({
740
+ role: 'user',
741
+ parts: expectedRequest,
742
+ });
714
743
  });
715
744
  it('should return the turn instance after the stream is complete', async () => {
716
745
  // Arrange
@@ -913,6 +942,222 @@ Here are some files the user has open, with the most recent at the top:
913
942
  console.log(`Infinite loop protection working: checkNextSpeaker called ${callCount} times, ` +
914
943
  `${eventCount} events generated (properly bounded by MAX_TURNS)`);
915
944
  });
945
+ describe('Editor context delta', () => {
946
+ const mockStream = (async function* () {
947
+ yield { type: 'content', value: 'Hello' };
948
+ })();
949
+ beforeEach(() => {
950
+ client['forceFullIdeContext'] = false; // Reset before each delta test
951
+ vi.spyOn(client, 'tryCompressChat').mockResolvedValue(null);
952
+ vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
953
+ mockTurnRunFn.mockReturnValue(mockStream);
954
+ const mockChat = {
955
+ addHistory: vi.fn(),
956
+ setHistory: vi.fn(),
957
+ sendMessage: vi.fn().mockResolvedValue({ text: 'summary' }),
958
+ // Assume history is not empty for delta checks
959
+ getHistory: vi
960
+ .fn()
961
+ .mockReturnValue([
962
+ { role: 'user', parts: [{ text: 'previous message' }] },
963
+ ]),
964
+ };
965
+ client['chat'] = mockChat;
966
+ const mockGenerator = {
967
+ countTokens: vi.fn().mockResolvedValue({ totalTokens: 0 }),
968
+ generateContent: mockGenerateContentFn,
969
+ };
970
+ client['contentGenerator'] = mockGenerator;
971
+ });
972
+ const testCases = [
973
+ {
974
+ description: 'sends delta when active file changes',
975
+ previousActiveFile: {
976
+ path: '/path/to/old/file.ts',
977
+ cursor: { line: 5, character: 10 },
978
+ selectedText: 'hello',
979
+ },
980
+ currentActiveFile: {
981
+ path: '/path/to/active/file.ts',
982
+ cursor: { line: 5, character: 10 },
983
+ selectedText: 'hello',
984
+ },
985
+ shouldSendContext: true,
986
+ },
987
+ {
988
+ description: 'sends delta when cursor line changes',
989
+ previousActiveFile: {
990
+ path: '/path/to/active/file.ts',
991
+ cursor: { line: 1, character: 10 },
992
+ selectedText: 'hello',
993
+ },
994
+ currentActiveFile: {
995
+ path: '/path/to/active/file.ts',
996
+ cursor: { line: 5, character: 10 },
997
+ selectedText: 'hello',
998
+ },
999
+ shouldSendContext: true,
1000
+ },
1001
+ {
1002
+ description: 'sends delta when cursor character changes',
1003
+ previousActiveFile: {
1004
+ path: '/path/to/active/file.ts',
1005
+ cursor: { line: 5, character: 1 },
1006
+ selectedText: 'hello',
1007
+ },
1008
+ currentActiveFile: {
1009
+ path: '/path/to/active/file.ts',
1010
+ cursor: { line: 5, character: 10 },
1011
+ selectedText: 'hello',
1012
+ },
1013
+ shouldSendContext: true,
1014
+ },
1015
+ {
1016
+ description: 'sends delta when selected text changes',
1017
+ previousActiveFile: {
1018
+ path: '/path/to/active/file.ts',
1019
+ cursor: { line: 5, character: 10 },
1020
+ selectedText: 'world',
1021
+ },
1022
+ currentActiveFile: {
1023
+ path: '/path/to/active/file.ts',
1024
+ cursor: { line: 5, character: 10 },
1025
+ selectedText: 'hello',
1026
+ },
1027
+ shouldSendContext: true,
1028
+ },
1029
+ {
1030
+ description: 'sends delta when selected text is added',
1031
+ previousActiveFile: {
1032
+ path: '/path/to/active/file.ts',
1033
+ cursor: { line: 5, character: 10 },
1034
+ },
1035
+ currentActiveFile: {
1036
+ path: '/path/to/active/file.ts',
1037
+ cursor: { line: 5, character: 10 },
1038
+ selectedText: 'hello',
1039
+ },
1040
+ shouldSendContext: true,
1041
+ },
1042
+ {
1043
+ description: 'sends delta when selected text is removed',
1044
+ previousActiveFile: {
1045
+ path: '/path/to/active/file.ts',
1046
+ cursor: { line: 5, character: 10 },
1047
+ selectedText: 'hello',
1048
+ },
1049
+ currentActiveFile: {
1050
+ path: '/path/to/active/file.ts',
1051
+ cursor: { line: 5, character: 10 },
1052
+ },
1053
+ shouldSendContext: true,
1054
+ },
1055
+ {
1056
+ description: 'does not send context when nothing changes',
1057
+ previousActiveFile: {
1058
+ path: '/path/to/active/file.ts',
1059
+ cursor: { line: 5, character: 10 },
1060
+ selectedText: 'hello',
1061
+ },
1062
+ currentActiveFile: {
1063
+ path: '/path/to/active/file.ts',
1064
+ cursor: { line: 5, character: 10 },
1065
+ selectedText: 'hello',
1066
+ },
1067
+ shouldSendContext: false,
1068
+ },
1069
+ ];
1070
+ it.each(testCases)('$description', async ({ previousActiveFile, currentActiveFile, shouldSendContext, }) => {
1071
+ // Setup previous context
1072
+ client['lastSentIdeContext'] = {
1073
+ workspaceState: {
1074
+ openFiles: [
1075
+ {
1076
+ path: previousActiveFile.path,
1077
+ cursor: previousActiveFile.cursor,
1078
+ selectedText: previousActiveFile.selectedText,
1079
+ isActive: true,
1080
+ timestamp: Date.now() - 1000,
1081
+ },
1082
+ ],
1083
+ },
1084
+ };
1085
+ // Setup current context
1086
+ vi.mocked(ideContext.getIdeContext).mockReturnValue({
1087
+ workspaceState: {
1088
+ openFiles: [
1089
+ { ...currentActiveFile, isActive: true, timestamp: Date.now() },
1090
+ ],
1091
+ },
1092
+ });
1093
+ const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-delta');
1094
+ for await (const _ of stream) {
1095
+ // consume stream
1096
+ }
1097
+ const mockChat = client['chat'];
1098
+ if (shouldSendContext) {
1099
+ expect(mockChat.addHistory).toHaveBeenCalledWith(expect.objectContaining({
1100
+ parts: expect.arrayContaining([
1101
+ expect.objectContaining({
1102
+ text: expect.stringContaining("Here is a summary of changes in the user's editor context"),
1103
+ }),
1104
+ ]),
1105
+ }));
1106
+ }
1107
+ else {
1108
+ expect(mockChat.addHistory).not.toHaveBeenCalled();
1109
+ }
1110
+ });
1111
+ it('sends full context when history is cleared, even if editor state is unchanged', async () => {
1112
+ const activeFile = {
1113
+ path: '/path/to/active/file.ts',
1114
+ cursor: { line: 5, character: 10 },
1115
+ selectedText: 'hello',
1116
+ };
1117
+ // Setup previous context
1118
+ client['lastSentIdeContext'] = {
1119
+ workspaceState: {
1120
+ openFiles: [
1121
+ {
1122
+ path: activeFile.path,
1123
+ cursor: activeFile.cursor,
1124
+ selectedText: activeFile.selectedText,
1125
+ isActive: true,
1126
+ timestamp: Date.now() - 1000,
1127
+ },
1128
+ ],
1129
+ },
1130
+ };
1131
+ // Setup current context (same as previous)
1132
+ vi.mocked(ideContext.getIdeContext).mockReturnValue({
1133
+ workspaceState: {
1134
+ openFiles: [
1135
+ { ...activeFile, isActive: true, timestamp: Date.now() },
1136
+ ],
1137
+ },
1138
+ });
1139
+ // Make history empty
1140
+ const mockChat = client['chat'];
1141
+ mockChat.getHistory.mockReturnValue([]);
1142
+ const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-history-cleared');
1143
+ for await (const _ of stream) {
1144
+ // consume stream
1145
+ }
1146
+ expect(mockChat.addHistory).toHaveBeenCalledWith(expect.objectContaining({
1147
+ parts: expect.arrayContaining([
1148
+ expect.objectContaining({
1149
+ text: expect.stringContaining("Here is the user's editor context"),
1150
+ }),
1151
+ ]),
1152
+ }));
1153
+ // Also verify it's the full context, not a delta.
1154
+ const call = mockChat.addHistory.mock.calls[0][0];
1155
+ const contextText = call.parts[0].text;
1156
+ const contextJson = JSON.parse(contextText.match(/```json\n(.*)\n```/s)[1]);
1157
+ expect(contextJson).toHaveProperty('activeFile');
1158
+ expect(contextJson.activeFile.path).toBe('/path/to/active/file.ts');
1159
+ });
1160
+ });
916
1161
  });
917
1162
  describe('generateContent', () => {
918
1163
  it('should use current model from config for content generation', async () => {
@@ -999,5 +1244,65 @@ Here are some files the user has open, with the most recent at the top:
999
1244
  expect(mockFallbackHandler).toHaveBeenCalledWith(currentModel, fallbackModel, undefined);
1000
1245
  });
1001
1246
  });
1247
+ describe('setHistory', () => {
1248
+ it('should strip thought signatures when stripThoughts is true', () => {
1249
+ const mockChat = {
1250
+ setHistory: vi.fn(),
1251
+ };
1252
+ client['chat'] = mockChat;
1253
+ const historyWithThoughts = [
1254
+ {
1255
+ role: 'user',
1256
+ parts: [{ text: 'hello' }],
1257
+ },
1258
+ {
1259
+ role: 'model',
1260
+ parts: [
1261
+ { text: 'thinking...', thoughtSignature: 'thought-123' },
1262
+ {
1263
+ functionCall: { name: 'test', args: {} },
1264
+ thoughtSignature: 'thought-456',
1265
+ },
1266
+ ],
1267
+ },
1268
+ ];
1269
+ client.setHistory(historyWithThoughts, { stripThoughts: true });
1270
+ const expectedHistory = [
1271
+ {
1272
+ role: 'user',
1273
+ parts: [{ text: 'hello' }],
1274
+ },
1275
+ {
1276
+ role: 'model',
1277
+ parts: [
1278
+ { text: 'thinking...' },
1279
+ { functionCall: { name: 'test', args: {} } },
1280
+ ],
1281
+ },
1282
+ ];
1283
+ expect(mockChat.setHistory).toHaveBeenCalledWith(expectedHistory);
1284
+ });
1285
+ it('should not strip thought signatures when stripThoughts is false', () => {
1286
+ const mockChat = {
1287
+ setHistory: vi.fn(),
1288
+ };
1289
+ client['chat'] = mockChat;
1290
+ const historyWithThoughts = [
1291
+ {
1292
+ role: 'user',
1293
+ parts: [{ text: 'hello' }],
1294
+ },
1295
+ {
1296
+ role: 'model',
1297
+ parts: [
1298
+ { text: 'thinking...', thoughtSignature: 'thought-123' },
1299
+ { text: 'ok', thoughtSignature: 'thought-456' },
1300
+ ],
1301
+ },
1302
+ ];
1303
+ client.setHistory(historyWithThoughts, { stripThoughts: false });
1304
+ expect(mockChat.setHistory).toHaveBeenCalledWith(historyWithThoughts);
1305
+ });
1306
+ });
1002
1307
  });
1003
1308
  //# sourceMappingURL=client.test.js.map