@machina.ai/cell-cli 1.64.0-rc2 → 1.66.0-rc1

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 (194) hide show
  1. package/dist/index.js +14 -9
  2. package/dist/index.js.map +1 -1
  3. package/dist/package.json +4 -4
  4. package/dist/src/acp/acpSession.js +9 -13
  5. package/dist/src/acp/acpSession.js.map +1 -1
  6. package/dist/src/acp/acpSession.test.js +88 -0
  7. package/dist/src/acp/acpSession.test.js.map +1 -1
  8. package/dist/src/commands/mcp/add.js +14 -6
  9. package/dist/src/commands/mcp/add.js.map +1 -1
  10. package/dist/src/commands/mcp/add.test.js +61 -0
  11. package/dist/src/commands/mcp/add.test.js.map +1 -1
  12. package/dist/src/commands/mcp/remove.js +14 -1
  13. package/dist/src/commands/mcp/remove.js.map +1 -1
  14. package/dist/src/commands/mcp/remove.test.js +63 -0
  15. package/dist/src/commands/mcp/remove.test.js.map +1 -1
  16. package/dist/src/config/config.js +12 -0
  17. package/dist/src/config/config.js.map +1 -1
  18. package/dist/src/config/config.test.js +17 -0
  19. package/dist/src/config/config.test.js.map +1 -1
  20. package/dist/src/config/envDefaults.d.ts +20 -0
  21. package/dist/src/config/envDefaults.js +29 -0
  22. package/dist/src/config/envDefaults.js.map +1 -0
  23. package/dist/src/config/envDefaults.test.d.ts +6 -0
  24. package/dist/src/config/envDefaults.test.js +23 -0
  25. package/dist/src/config/envDefaults.test.js.map +1 -0
  26. package/dist/src/config/extension-manager.js +13 -4
  27. package/dist/src/config/extension-manager.js.map +1 -1
  28. package/dist/src/config/extension.test.js +117 -0
  29. package/dist/src/config/extension.test.js.map +1 -1
  30. package/dist/src/config/extensions/github.test.js +34 -0
  31. package/dist/src/config/extensions/github.test.js.map +1 -1
  32. package/dist/src/config/extensions/github_fetch.js +110 -18
  33. package/dist/src/config/extensions/github_fetch.js.map +1 -1
  34. package/dist/src/config/extensions/github_fetch.test.js +251 -36
  35. package/dist/src/config/extensions/github_fetch.test.js.map +1 -1
  36. package/dist/src/config/settings.d.ts +1 -0
  37. package/dist/src/config/settings.js +148 -58
  38. package/dist/src/config/settings.js.map +1 -1
  39. package/dist/src/config/settings.test.js +300 -0
  40. package/dist/src/config/settings.test.js.map +1 -1
  41. package/dist/src/config/settingsSchema.d.ts +1 -1
  42. package/dist/src/config/settingsSchema.js +6 -1
  43. package/dist/src/config/settingsSchema.js.map +1 -1
  44. package/dist/src/gemini.test.js +69 -0
  45. package/dist/src/gemini.test.js.map +1 -1
  46. package/dist/src/generated/git-commit.d.ts +2 -2
  47. package/dist/src/generated/git-commit.js +2 -2
  48. package/dist/src/interactiveCli.js +8 -3
  49. package/dist/src/interactiveCli.js.map +1 -1
  50. package/dist/src/services/CommandService.js +1 -1
  51. package/dist/src/services/CommandService.js.map +1 -1
  52. package/dist/src/services/CommandService.test.js +18 -1
  53. package/dist/src/services/CommandService.test.js.map +1 -1
  54. package/dist/src/services/SlashCommandConflictHandler.d.ts +1 -0
  55. package/dist/src/services/SlashCommandConflictHandler.js +18 -2
  56. package/dist/src/services/SlashCommandConflictHandler.js.map +1 -1
  57. package/dist/src/services/SlashCommandConflictHandler.test.js +85 -8
  58. package/dist/src/services/SlashCommandConflictHandler.test.js.map +1 -1
  59. package/dist/src/ui/AppContainer.js +254 -12
  60. package/dist/src/ui/AppContainer.js.map +1 -1
  61. package/dist/src/ui/AppContainer.test.js +362 -6
  62. package/dist/src/ui/AppContainer.test.js.map +1 -1
  63. package/dist/src/ui/auth/AuthDialog.js +21 -5
  64. package/dist/src/ui/auth/AuthDialog.js.map +1 -1
  65. package/dist/src/ui/auth/AuthDialog.test.js +83 -0
  66. package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
  67. package/dist/src/ui/auth/useAuth.js +7 -1
  68. package/dist/src/ui/auth/useAuth.js.map +1 -1
  69. package/dist/src/ui/auth/useAuth.test.js +9 -0
  70. package/dist/src/ui/auth/useAuth.test.js.map +1 -1
  71. package/dist/src/ui/commands/marketplaceCommand.js +92 -4
  72. package/dist/src/ui/commands/marketplaceCommand.js.map +1 -1
  73. package/dist/src/ui/commands/marketplaceCommand.test.js +98 -1
  74. package/dist/src/ui/commands/marketplaceCommand.test.js.map +1 -1
  75. package/dist/src/ui/components/AsciiArt.d.ts +6 -6
  76. package/dist/src/ui/components/AsciiArt.js +6 -6
  77. package/dist/src/ui/components/CliSpinner.d.ts +3 -2
  78. package/dist/src/ui/components/CliSpinner.js +27 -3
  79. package/dist/src/ui/components/CliSpinner.js.map +1 -1
  80. package/dist/src/ui/components/CliSpinner.test.js +42 -3
  81. package/dist/src/ui/components/CliSpinner.test.js.map +1 -1
  82. package/dist/src/ui/components/Composer.js +3 -3
  83. package/dist/src/ui/components/Composer.js.map +1 -1
  84. package/dist/src/ui/components/Composer.test.js +39 -1
  85. package/dist/src/ui/components/Composer.test.js.map +1 -1
  86. package/dist/src/ui/components/DetailedMessagesDisplay.js +5 -1
  87. package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
  88. package/dist/src/ui/components/DetailedMessagesDisplay.test.js +19 -1
  89. package/dist/src/ui/components/DetailedMessagesDisplay.test.js.map +1 -1
  90. package/dist/src/ui/components/Footer.js +1 -1
  91. package/dist/src/ui/components/Footer.js.map +1 -1
  92. package/dist/src/ui/components/GeminiRespondingSpinner.d.ts +1 -1
  93. package/dist/src/ui/components/GeminiRespondingSpinner.js +9 -2
  94. package/dist/src/ui/components/GeminiRespondingSpinner.js.map +1 -1
  95. package/dist/src/ui/components/GeminiSpinner.d.ts +1 -1
  96. package/dist/src/ui/components/GeminiSpinner.js +18 -7
  97. package/dist/src/ui/components/GeminiSpinner.js.map +1 -1
  98. package/dist/src/ui/components/HistoryItemDisplay.js +5 -2
  99. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  100. package/dist/src/ui/components/HistoryItemDisplay.test.js +21 -0
  101. package/dist/src/ui/components/HistoryItemDisplay.test.js.map +1 -1
  102. package/dist/src/ui/components/LoadingIndicator.d.ts +1 -1
  103. package/dist/src/ui/components/LoadingIndicator.js +4 -2
  104. package/dist/src/ui/components/LoadingIndicator.js.map +1 -1
  105. package/dist/src/ui/components/MainContent.js +47 -9
  106. package/dist/src/ui/components/MainContent.js.map +1 -1
  107. package/dist/src/ui/components/MainContent.test.js +87 -1
  108. package/dist/src/ui/components/MainContent.test.js.map +1 -1
  109. package/dist/src/ui/components/MemoryUsageDisplay.js +8 -4
  110. package/dist/src/ui/components/MemoryUsageDisplay.js.map +1 -1
  111. package/dist/src/ui/components/ModelDialog.js +30 -16
  112. package/dist/src/ui/components/ModelDialog.js.map +1 -1
  113. package/dist/src/ui/components/ModelDialog.test.js +32 -24
  114. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  115. package/dist/src/ui/components/StatusRow.d.ts +7 -6
  116. package/dist/src/ui/components/StatusRow.js +24 -10
  117. package/dist/src/ui/components/StatusRow.js.map +1 -1
  118. package/dist/src/ui/components/ValidationDialog.js +13 -6
  119. package/dist/src/ui/components/ValidationDialog.js.map +1 -1
  120. package/dist/src/ui/components/ValidationDialog.test.js +40 -0
  121. package/dist/src/ui/components/ValidationDialog.test.js.map +1 -1
  122. package/dist/src/ui/components/messages/DenseToolMessage.js +17 -12
  123. package/dist/src/ui/components/messages/DenseToolMessage.js.map +1 -1
  124. package/dist/src/ui/components/messages/DenseToolMessage.test.js +71 -0
  125. package/dist/src/ui/components/messages/DenseToolMessage.test.js.map +1 -1
  126. package/dist/src/ui/components/messages/ToolResultDisplay.js +14 -11
  127. package/dist/src/ui/components/messages/ToolResultDisplay.js.map +1 -1
  128. package/dist/src/ui/components/messages/ToolResultDisplay.test.js +32 -0
  129. package/dist/src/ui/components/messages/ToolResultDisplay.test.js.map +1 -1
  130. package/dist/src/ui/components/shared/MaxSizedBox.js +8 -2
  131. package/dist/src/ui/components/shared/MaxSizedBox.js.map +1 -1
  132. package/dist/src/ui/components/shared/MaxSizedBox.test.js +23 -1
  133. package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -1
  134. package/dist/src/ui/contexts/ToolActionsContext.js +7 -1
  135. package/dist/src/ui/contexts/ToolActionsContext.js.map +1 -1
  136. package/dist/src/ui/contexts/ToolActionsContext.test.js +54 -1
  137. package/dist/src/ui/contexts/ToolActionsContext.test.js.map +1 -1
  138. package/dist/src/ui/hooks/atCommandProcessor.d.ts +2 -1
  139. package/dist/src/ui/hooks/atCommandProcessor.js +15 -15
  140. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  141. package/dist/src/ui/hooks/useAgentStream.d.ts +9 -2
  142. package/dist/src/ui/hooks/useAgentStream.js +173 -8
  143. package/dist/src/ui/hooks/useAgentStream.js.map +1 -1
  144. package/dist/src/ui/hooks/useAgentStream.test.js +104 -1
  145. package/dist/src/ui/hooks/useAgentStream.test.js.map +1 -1
  146. package/dist/src/ui/hooks/useGeminiStream.d.ts +1 -1
  147. package/dist/src/ui/hooks/useGeminiStream.js +174 -59
  148. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  149. package/dist/src/ui/hooks/useGeminiStream.test.js +230 -3
  150. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  151. package/dist/src/ui/hooks/useLoadingIndicator.d.ts +2 -1
  152. package/dist/src/ui/hooks/useLoadingIndicator.js +3 -3
  153. package/dist/src/ui/hooks/useLoadingIndicator.js.map +1 -1
  154. package/dist/src/ui/hooks/useLoadingIndicator.test.js +23 -4
  155. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
  156. package/dist/src/ui/hooks/useReverseSearchCompletion.js +10 -6
  157. package/dist/src/ui/hooks/useReverseSearchCompletion.js.map +1 -1
  158. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +49 -0
  159. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -1
  160. package/dist/src/ui/key/keyBindings.js +19 -6
  161. package/dist/src/ui/key/keyBindings.js.map +1 -1
  162. package/dist/src/ui/key/keyBindings.test.js +106 -0
  163. package/dist/src/ui/key/keyBindings.test.js.map +1 -1
  164. package/dist/src/ui/utils/formatters.d.ts +2 -0
  165. package/dist/src/ui/utils/formatters.js +13 -5
  166. package/dist/src/ui/utils/formatters.js.map +1 -1
  167. package/dist/src/ui/utils/formatters.test.js +18 -0
  168. package/dist/src/ui/utils/formatters.test.js.map +1 -1
  169. package/dist/src/utils/activityLogger.js +109 -33
  170. package/dist/src/utils/activityLogger.js.map +1 -1
  171. package/dist/src/utils/activityLogger.test.js +441 -0
  172. package/dist/src/utils/activityLogger.test.js.map +1 -1
  173. package/dist/src/utils/handleAutoUpdate.d.ts +4 -1
  174. package/dist/src/utils/handleAutoUpdate.js +45 -3
  175. package/dist/src/utils/handleAutoUpdate.js.map +1 -1
  176. package/dist/src/utils/handleAutoUpdate.test.js +280 -2
  177. package/dist/src/utils/handleAutoUpdate.test.js.map +1 -1
  178. package/dist/src/utils/nodeVersion.d.ts +11 -0
  179. package/dist/src/utils/nodeVersion.js +42 -0
  180. package/dist/src/utils/nodeVersion.js.map +1 -0
  181. package/dist/src/utils/nodeVersion.test.d.ts +6 -0
  182. package/dist/src/utils/nodeVersion.test.js +35 -0
  183. package/dist/src/utils/nodeVersion.test.js.map +1 -0
  184. package/dist/src/utils/processUtils.d.ts +23 -0
  185. package/dist/src/utils/processUtils.js +72 -0
  186. package/dist/src/utils/processUtils.js.map +1 -1
  187. package/dist/src/utils/processUtils.test.js +95 -1
  188. package/dist/src/utils/processUtils.test.js.map +1 -1
  189. package/dist/src/utils/relaunch.js +8 -6
  190. package/dist/src/utils/relaunch.js.map +1 -1
  191. package/dist/src/utils/relaunch.test.js +107 -1
  192. package/dist/src/utils/relaunch.test.js.map +1 -1
  193. package/dist/tsconfig.tsbuildinfo +1 -1
  194. package/package.json +4 -4
@@ -12,7 +12,7 @@ import { useGeminiStream } from './useGeminiStream.js';
12
12
  import { useKeypress } from './useKeypress.js';
13
13
  import * as atCommandProcessor from './atCommandProcessor.js';
14
14
  import { useToolScheduler, } from './useToolScheduler.js';
15
- import { CoreToolCallStatus, ApprovalMode, DEFAULT_GEMINI_FLASH_MODEL, AuthType, GeminiEventType as ServerGeminiEventType, uiTelemetryService, ToolErrorType, ToolConfirmationOutcome, MessageBusType, tokenLimit, debugLogger, coreEvents, CoreEvent, SHELL_TOOL_NAME, MCPDiscoveryState, GeminiCliOperation, getPlanModeExitMessage, UPDATE_TOPIC_TOOL_NAME, TRUE_EMPTY_RESPONSE_MESSAGE, } from '@google/gemini-cli-core';
15
+ import { CoreToolCallStatus, ApprovalMode, DEFAULT_GEMINI_FLASH_MODEL, AuthType, GeminiEventType as ServerGeminiEventType, uiTelemetryService, ToolErrorType, ToolConfirmationOutcome, MessageBusType, tokenLimit, debugLogger, coreEvents, CoreEvent, SHELL_TOOL_NAME, MCPDiscoveryState, GeminiCliOperation, getPlanModeExitMessage, UPDATE_TOPIC_TOOL_NAME, TRUE_EMPTY_RESPONSE_MESSAGE, Kind, } from '@google/gemini-cli-core';
16
16
  import { MessageType, StreamingState } from '../types.js';
17
17
  import { findLastSafeSplitPoint } from '../utils/markdownUtilities.js';
18
18
  import { theme } from '../semantic-colors.js';
@@ -1732,7 +1732,7 @@ describe('useGeminiStream', () => {
1732
1732
  expect(result.current.retryStatus).toEqual(retryPayload);
1733
1733
  // Cancel to make isResponding false
1734
1734
  await act(async () => {
1735
- result.current.cancelOngoingRequest();
1735
+ await result.current.cancelOngoingRequest();
1736
1736
  });
1737
1737
  expect(result.current.retryStatus).toBeNull();
1738
1738
  });
@@ -1767,7 +1767,7 @@ describe('useGeminiStream', () => {
1767
1767
  });
1768
1768
  expect(result.current.retryStatus).toEqual(retryPayload);
1769
1769
  await act(async () => {
1770
- result.current.cancelOngoingRequest();
1770
+ await result.current.cancelOngoingRequest();
1771
1771
  });
1772
1772
  await waitFor(() => {
1773
1773
  expect(result.current.retryStatus).toBeNull();
@@ -3223,6 +3223,133 @@ describe('useGeminiStream', () => {
3223
3223
  });
3224
3224
  });
3225
3225
  });
3226
+ describe('Grouped Tool Calls', () => {
3227
+ const createToolCall = (callId, { status = CoreToolCallStatus.Success, kind = Kind.Agent, groupId, } = {}) => ({
3228
+ request: {
3229
+ callId,
3230
+ name: `tool-${callId}`,
3231
+ args: {},
3232
+ isClientInitiated: false,
3233
+ prompt_id: 'prompt-id-1',
3234
+ groupId,
3235
+ },
3236
+ status,
3237
+ responseSubmittedToGemini: false,
3238
+ response: {
3239
+ callId,
3240
+ responseParts: [],
3241
+ resultDisplay: `result of ${callId}`,
3242
+ error: undefined,
3243
+ errorType: undefined,
3244
+ },
3245
+ tool: {
3246
+ name: `tool-${callId}`,
3247
+ displayName: `tool-${callId}`,
3248
+ description: `description of ${callId}`,
3249
+ kind,
3250
+ build: vi.fn(),
3251
+ },
3252
+ invocation: {
3253
+ getDescription: () => `Mock description of ${callId}`,
3254
+ },
3255
+ });
3256
+ const setToolCalls = (toolCalls) => {
3257
+ mockUseToolScheduler.mockReturnValue([
3258
+ toolCalls,
3259
+ mockScheduleToolCalls,
3260
+ mockMarkToolsAsSubmitted,
3261
+ vi.fn(),
3262
+ mockCancelAllToolCalls,
3263
+ 0,
3264
+ ]);
3265
+ };
3266
+ const renderWithToolCalls = async (toolCalls) => {
3267
+ setToolCalls(toolCalls);
3268
+ return renderHookWithProviders(() => useGeminiStream(mockConfig.getGeminiClient(), [], mockAddItem, mockConfig, mockLoadedSettings, mockOnDebugMessage, mockHandleSlashCommand, false, () => 'vscode', () => { }, () => Promise.resolve(), false, () => { }, () => { }, () => { }, 80, 24));
3269
+ };
3270
+ // The call IDs of every tool group pushed to history. `useStateAndRef` is
3271
+ // mocked in this file, so the effect that pushes finished tools starts from
3272
+ // scratch on every render. The assertions below therefore check which
3273
+ // groups were pushed rather than how many times `addItem` was called.
3274
+ const getPushedGroups = () => mockAddItem.mock.calls
3275
+ .map(([item]) => item)
3276
+ .filter((item) => item.type === 'tool_group')
3277
+ .map((item) => item.tools.map((tool) => tool.callId));
3278
+ it('should hold back a group until every call in it has finished', async () => {
3279
+ const { rerender } = await renderWithToolCalls([
3280
+ createToolCall('agent-1', { groupId: 'agent-1' }),
3281
+ createToolCall('agent-2', {
3282
+ status: CoreToolCallStatus.Executing,
3283
+ groupId: 'agent-1',
3284
+ }),
3285
+ ]);
3286
+ expect(getPushedGroups()).toEqual([]);
3287
+ setToolCalls([
3288
+ createToolCall('agent-1', { groupId: 'agent-1' }),
3289
+ createToolCall('agent-2', { groupId: 'agent-1' }),
3290
+ ]);
3291
+ rerender();
3292
+ expect(getPushedGroups()).toContainEqual(['agent-1', 'agent-2']);
3293
+ });
3294
+ it('should treat failed and cancelled calls as finished', async () => {
3295
+ await renderWithToolCalls([
3296
+ createToolCall('agent-1', { groupId: 'agent-1' }),
3297
+ createToolCall('agent-2', {
3298
+ status: CoreToolCallStatus.Error,
3299
+ groupId: 'agent-1',
3300
+ }),
3301
+ createToolCall('agent-3', {
3302
+ status: CoreToolCallStatus.Cancelled,
3303
+ groupId: 'agent-1',
3304
+ }),
3305
+ ]);
3306
+ expect(getPushedGroups()).toContainEqual([
3307
+ 'agent-1',
3308
+ 'agent-2',
3309
+ 'agent-3',
3310
+ ]);
3311
+ });
3312
+ it('should group by group ID rather than by tool kind', async () => {
3313
+ const { rerender } = await renderWithToolCalls([
3314
+ createToolCall('read-1', { kind: Kind.Read, groupId: 'read-1' }),
3315
+ createToolCall('read-2', {
3316
+ kind: Kind.Read,
3317
+ status: CoreToolCallStatus.Executing,
3318
+ groupId: 'read-1',
3319
+ }),
3320
+ ]);
3321
+ expect(getPushedGroups()).toEqual([]);
3322
+ setToolCalls([
3323
+ createToolCall('read-1', { kind: Kind.Read, groupId: 'read-1' }),
3324
+ createToolCall('read-2', { kind: Kind.Read, groupId: 'read-1' }),
3325
+ ]);
3326
+ rerender();
3327
+ expect(getPushedGroups()).toContainEqual(['read-1', 'read-2']);
3328
+ });
3329
+ it('should push calls without a group ID individually, whatever their kind', async () => {
3330
+ await renderWithToolCalls([
3331
+ createToolCall('agent-1'),
3332
+ createToolCall('agent-2'),
3333
+ ]);
3334
+ const groups = getPushedGroups();
3335
+ expect(groups).toContainEqual(['agent-1']);
3336
+ expect(groups).toContainEqual(['agent-2']);
3337
+ expect(groups).not.toContainEqual(['agent-1', 'agent-2']);
3338
+ });
3339
+ it('should push finished calls ahead of a group that is still running', async () => {
3340
+ await renderWithToolCalls([
3341
+ createToolCall('read-1', { kind: Kind.Read }),
3342
+ createToolCall('agent-1', { groupId: 'agent-1' }),
3343
+ createToolCall('agent-2', {
3344
+ status: CoreToolCallStatus.Executing,
3345
+ groupId: 'agent-1',
3346
+ }),
3347
+ ]);
3348
+ const groups = getPushedGroups();
3349
+ expect(groups).toContainEqual(['read-1']);
3350
+ expect(groups.flat()).not.toContain('agent-1');
3351
+ });
3352
+ });
3226
3353
  describe('Stream Splitting', () => {
3227
3354
  it('should not add empty history item when splitting message results in empty or whitespace-only beforeText', async () => {
3228
3355
  // Mock split point to always be 0, causing beforeText to be empty
@@ -3291,5 +3418,105 @@ describe('useGeminiStream', () => {
3291
3418
  });
3292
3419
  expect(spanMetadata.input).toBe('telemetry test query');
3293
3420
  });
3421
+ describe('cancelOngoingRequest session log harmonization & timeout bound', () => {
3422
+ it('immediately synthesizes and records filler functionResponse via recordCompletedToolCalls when cancelling active tools', async () => {
3423
+ const executingToolCall = {
3424
+ request: {
3425
+ callId: 'call-abc',
3426
+ name: 'run_shell_command',
3427
+ args: { command: 'sleep 30' },
3428
+ isClientInitiated: false,
3429
+ prompt_id: 'prompt-1',
3430
+ },
3431
+ status: CoreToolCallStatus.Executing,
3432
+ tool: {
3433
+ name: 'run_shell_command',
3434
+ displayName: 'Shell',
3435
+ },
3436
+ invocation: {
3437
+ getDescription: () => 'sleep 30',
3438
+ },
3439
+ };
3440
+ const { result, client } = await renderTestHook([executingToolCall]);
3441
+ const mockRecordCompletedToolCalls = client.getChat().recordCompletedToolCalls;
3442
+ await act(async () => {
3443
+ await result.current.cancelOngoingRequest();
3444
+ });
3445
+ expect(mockCancelAllToolCalls).toHaveBeenCalledTimes(1);
3446
+ expect(mockRecordCompletedToolCalls).toHaveBeenCalledTimes(1);
3447
+ expect(mockRecordCompletedToolCalls).toHaveBeenCalledWith(expect.any(String), [
3448
+ expect.objectContaining({
3449
+ status: CoreToolCallStatus.Cancelled,
3450
+ request: executingToolCall.request,
3451
+ response: expect.objectContaining({
3452
+ callId: 'call-abc',
3453
+ responseParts: [
3454
+ {
3455
+ functionResponse: {
3456
+ id: 'call-abc',
3457
+ name: 'run_shell_command',
3458
+ response: {
3459
+ error: '[Operation Cancelled] Reason: User cancelled operation',
3460
+ },
3461
+ },
3462
+ },
3463
+ ],
3464
+ }),
3465
+ }),
3466
+ ]);
3467
+ });
3468
+ it('bounds waiting on an unresponsive tool schedule promise at 1000ms', async () => {
3469
+ vi.useFakeTimers();
3470
+ try {
3471
+ mockScheduleToolCalls.mockImplementation(() => new Promise(() => { }));
3472
+ mockSendMessageStream.mockReturnValue((async function* () {
3473
+ yield {
3474
+ type: ServerGeminiEventType.ToolCallRequest,
3475
+ value: {
3476
+ callId: 'call-hang',
3477
+ name: 'hanging_tool',
3478
+ args: {},
3479
+ isClientInitiated: false,
3480
+ prompt_id: 'prompt-hang',
3481
+ },
3482
+ };
3483
+ })());
3484
+ const { result, client } = await renderTestHook();
3485
+ const mockRecordCompletedToolCalls = client.getChat().recordCompletedToolCalls;
3486
+ act(() => {
3487
+ void result.current.submitQuery('run hanging tool');
3488
+ });
3489
+ await act(async () => {
3490
+ await vi.advanceTimersByTimeAsync(10);
3491
+ });
3492
+ expect(mockScheduleToolCalls).toHaveBeenCalledTimes(1);
3493
+ let cancelResolved = false;
3494
+ let cancelPromise;
3495
+ act(() => {
3496
+ cancelPromise = result.current.cancelOngoingRequest().then(() => {
3497
+ cancelResolved = true;
3498
+ });
3499
+ });
3500
+ expect(mockRecordCompletedToolCalls).toHaveBeenCalledWith(expect.any(String), [
3501
+ expect.objectContaining({
3502
+ status: CoreToolCallStatus.Cancelled,
3503
+ request: expect.objectContaining({
3504
+ callId: 'call-hang',
3505
+ name: 'hanging_tool',
3506
+ }),
3507
+ }),
3508
+ ]);
3509
+ expect(cancelResolved).toBe(false);
3510
+ await act(async () => {
3511
+ await vi.advanceTimersByTimeAsync(1000);
3512
+ await cancelPromise;
3513
+ });
3514
+ expect(cancelResolved).toBe(true);
3515
+ }
3516
+ finally {
3517
+ vi.useRealTimers();
3518
+ }
3519
+ });
3520
+ });
3294
3521
  });
3295
3522
  //# sourceMappingURL=useGeminiStream.test.js.map