@vybestack/llxprt-code 0.10.0 → 0.11.0-nightly.260728.ffaa8d5d7

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 (126) hide show
  1. package/package.json +13 -13
  2. package/src/commands/mcp/add.ts +8 -4
  3. package/src/config/cliArgParser.ts +2 -0
  4. package/src/config/config.ts +2 -0
  5. package/src/config/configBuilder.ts +3 -0
  6. package/src/config/configError.ts +23 -0
  7. package/src/config/extensions/extensionEnablement.ts +62 -1
  8. package/src/config/interactiveContext.ts +2 -1
  9. package/src/config/intermediateConfig.ts +4 -0
  10. package/src/config/keyBindings.ts +29 -3
  11. package/src/config/policy.ts +7 -1
  12. package/src/config/postConfigRuntime.ts +20 -14
  13. package/src/config/settings-schema/schema-ui.ts +9 -0
  14. package/src/config/settingsLoader.ts +21 -17
  15. package/src/config/settingsSchema.ts +2 -2
  16. package/src/config/trustedFolders.ts +275 -58
  17. package/src/config/yargsOptions.ts +7 -0
  18. package/src/generated/git-commit.json +1 -1
  19. package/src/nonInteractiveCli.ts +1 -0
  20. package/src/nonInteractiveCliSupport.ts +171 -51
  21. package/src/runtime/interactiveToolScheduler.ts +6 -6
  22. package/src/services/BuiltinCommandLoader.ts +33 -25
  23. package/src/services/FileCommandLoader.ts +34 -7
  24. package/src/test-utils/async.ts +20 -0
  25. package/src/test-utils/render.tsx +10 -1
  26. package/src/ui/App.tsx +17 -10
  27. package/src/ui/AppContainerRuntime.tsx +7 -9
  28. package/src/ui/cliUiRuntime.ts +28 -0
  29. package/src/ui/commands/authCommand.ts +240 -3
  30. package/src/ui/commands/compressCommand.ts +9 -1
  31. package/src/ui/commands/directoryCommand.tsx +1 -1
  32. package/src/ui/commands/logoutCommand.ts +2 -2
  33. package/src/ui/commands/permissionsCommand.ts +77 -20
  34. package/src/ui/commands/policiesCommand.ts +6 -1
  35. package/src/ui/commands/quotaCommand.ts +501 -0
  36. package/src/ui/commands/statsCommand.ts +2 -2
  37. package/src/ui/commands/statsQuota.ts +1 -1
  38. package/src/ui/commands/subagentCommand.ts +59 -27
  39. package/src/ui/components/AuthDialog.tsx +3 -3
  40. package/src/ui/components/Composer.tsx +1 -0
  41. package/src/ui/components/DialogManager.tsx +9 -2
  42. package/src/ui/components/FolderTrustDialog.tsx +71 -60
  43. package/src/ui/components/PermissionsModifyTrustDialog.tsx +211 -146
  44. package/src/ui/components/ProfileCreateWizard/constants.ts +13 -1
  45. package/src/ui/components/QueuedMessagesPanel.tsx +388 -0
  46. package/src/ui/components/inputPromptHooks.ts +2 -0
  47. package/src/ui/components/inputPromptKeyHandlers.ts +14 -0
  48. package/src/ui/components/inputPromptTypes.ts +6 -0
  49. package/src/ui/components/messages/AiMessage.tsx +24 -12
  50. package/src/ui/components/messages/ToolMessage.tsx +26 -40
  51. package/src/ui/containers/AppContainer/builders/buildUIActions.ts +3 -1
  52. package/src/ui/containers/AppContainer/builders/buildUIState.ts +5 -4
  53. package/src/ui/containers/AppContainer/hooks/useAppBootstrap.ts +3 -33
  54. package/src/ui/containers/AppContainer/hooks/useAppDialogs.ts +2 -14
  55. package/src/ui/containers/AppContainer/hooks/useAppInput.ts +31 -25
  56. package/src/ui/containers/AppContainer/hooks/useAppLayout.ts +90 -60
  57. package/src/ui/containers/AppContainer/hooks/useDisplayPreferences.ts +10 -0
  58. package/src/ui/containers/AppContainer/hooks/useInputHandling.ts +3 -17
  59. package/src/ui/containers/AppContainer/hooks/useKeybindings.ts +51 -38
  60. package/src/ui/containers/AppContainer/hooks/useSteer.ts +51 -0
  61. package/src/ui/contexts/KeypressContext.tsx +13 -2
  62. package/src/ui/contexts/ShellCommandDisplayContext.tsx +103 -0
  63. package/src/ui/contexts/TodoContext.tsx +0 -13
  64. package/src/ui/contexts/TodoProvider.tsx +1 -34
  65. package/src/ui/contexts/UIActionsContext.tsx +2 -1
  66. package/src/ui/contexts/UIStateContext.tsx +3 -2
  67. package/src/ui/hooks/agentStream/streamUtils.ts +0 -24
  68. package/src/ui/hooks/agentStream/thoughtState.ts +110 -30
  69. package/src/ui/hooks/agentStream/types.ts +1 -0
  70. package/src/ui/hooks/agentStream/useAgentEventStream.ts +8 -17
  71. package/src/ui/hooks/agentStream/useAgentStream.ts +2 -2
  72. package/src/ui/hooks/agentStream/useAgentStreamLifecycle.ts +4 -5
  73. package/src/ui/hooks/agentStream/useAgentStreamOrchestration.ts +12 -5
  74. package/src/ui/hooks/agentStream/useQueuedSubmissions.ts +99 -0
  75. package/src/ui/hooks/agentStream/useStreamEventHandlers.ts +4 -13
  76. package/src/ui/hooks/agentStream/useStreamState.ts +60 -41
  77. package/src/ui/hooks/agentStream/useSubmitQuery.ts +284 -59
  78. package/src/ui/hooks/slashCommandProcessorSupport.ts +4 -0
  79. package/src/ui/hooks/useAgentStream-test-helpers.ts +1 -0
  80. package/src/ui/hooks/useAutoAcceptIndicator.ts +13 -0
  81. package/src/ui/hooks/useFolderTrust.ts +118 -81
  82. package/src/ui/hooks/useGitBranchName.ts +79 -33
  83. package/src/ui/hooks/useIdeTrustListener.ts +5 -19
  84. package/src/ui/hooks/usePermissionsModifyTrust.ts +223 -85
  85. package/src/ui/hooks/useReactToolScheduler.ts +13 -17
  86. package/src/ui/hooks/useTodoPausePreserver.ts +0 -55
  87. package/src/ui/layouts/DefaultAppLayout.tsx +2 -0
  88. package/src/ui/layouts/DefaultAppLayoutHelpers.tsx +37 -162
  89. package/src/ui/layouts/InlineContent.tsx +198 -0
  90. package/src/ui/trustDialogHelpers.ts +190 -0
  91. package/src/utils/cleanup-state.ts +115 -0
  92. package/src/utils/cleanup.ts +32 -34
  93. package/src/utils/sandbox-containers.ts +183 -53
  94. package/src/utils/sandbox-exec.ts +9 -3
  95. package/src/zed-integration/acp-terminal-shell-host.ts +112 -0
  96. package/src/zed-integration/acp-types.ts +35 -0
  97. package/src/zed-integration/fileSystemService.ts +1 -1
  98. package/src/zed-integration/runZedIntegration.ts +142 -0
  99. package/src/zed-integration/zed-agent-event-handler.ts +179 -0
  100. package/src/zed-integration/zed-agent-setup.ts +43 -0
  101. package/src/zed-integration/zed-command-registry.ts +167 -0
  102. package/src/zed-integration/zed-config-options.ts +280 -0
  103. package/src/zed-integration/zed-content-utils.ts +2 -2
  104. package/src/zed-integration/zed-helpers.ts +132 -0
  105. package/src/zed-integration/zed-initialize.ts +64 -0
  106. package/src/zed-integration/zed-plan-update.ts +20 -0
  107. package/src/zed-integration/zed-prompt-command.ts +77 -0
  108. package/src/zed-integration/zed-session-config.ts +119 -0
  109. package/src/zed-integration/zed-session-errors.ts +337 -0
  110. package/src/zed-integration/zed-session-events.ts +216 -0
  111. package/src/zed-integration/zed-session-info.ts +255 -0
  112. package/src/zed-integration/zed-session-lifecycle.ts +186 -0
  113. package/src/zed-integration/zed-session-listing.ts +153 -0
  114. package/src/zed-integration/zed-session-loader.ts +193 -0
  115. package/src/zed-integration/zed-session-pagination.ts +240 -0
  116. package/src/zed-integration/zed-session-replay.ts +564 -0
  117. package/src/zed-integration/zed-stream-batcher.ts +236 -0
  118. package/src/zed-integration/zed-terminal-manager.ts +416 -0
  119. package/src/zed-integration/zed-terminal-setup.ts +72 -0
  120. package/src/zed-integration/zed-test-helpers.ts +349 -4
  121. package/src/zed-integration/zed-tool-handler.ts +47 -5
  122. package/src/zed-integration/zedIntegration.ts +538 -587
  123. package/src/services/todo-continuation/todoContinuationService.ts +0 -610
  124. package/src/ui/containers/AppContainer/hooks/useIdeRestartHotkey.ts +0 -33
  125. package/src/ui/containers/AppContainer/hooks/useTodoContinuationFlow.ts +0 -160
  126. package/src/ui/hooks/useTodoContinuation.ts +0 -299
@@ -27,7 +27,7 @@ import type {
27
27
  AgentInput,
28
28
  } from '@vybestack/llxprt-code-agents';
29
29
  import type {
30
- AnsiOutput,
30
+ LiveOutputUpdate,
31
31
  CompletedToolCall,
32
32
  EditorType,
33
33
  ToolCall,
@@ -69,15 +69,13 @@ export interface UseAgentEventStreamArgs {
69
69
  clearPendingHistoryItem: () => void;
70
70
  /** Refreshes in-memory data after a successful save_memory. */
71
71
  performMemoryRefresh: () => Promise<void>;
72
- /** Invoked when the pause tool succeeds. */
73
- onTodoPause?: () => void;
74
72
  /**
75
73
  * Marks the given tool callIds as cleared from the React display state.
76
74
  */
77
75
  markToolsAsDisplayCleared?: (callIds: string[]) => void;
78
76
  /** Display callbacks for tool-call display state. */
79
77
  onToolCallsUpdate?: (toolCalls: ToolCall[]) => void;
80
- outputUpdateHandler?: (callId: string, chunk: string | AnsiOutput) => void;
78
+ outputUpdateHandler?: (callId: string, update: LiveOutputUpdate) => void;
81
79
  getPreferredEditor?: () => EditorType | undefined;
82
80
  onEditorOpen?: () => void;
83
81
  onEditorClose?: () => void;
@@ -96,10 +94,10 @@ export interface UseAgentEventStreamReturn {
96
94
  }
97
95
 
98
96
  /**
99
- * Processes a tools_complete callback: adds the tool-group display item,
100
- * refreshes memory if a save_memory succeeded, and fires onTodoPause if a
101
- * pause-task tool succeeded. The Agent's loop has ALREADY recorded the completed
102
- * calls into chat history — do NOT call recordCompletedToolCalls here.
97
+ * Processes a tools_complete callback: adds the tool-group display item and
98
+ * refreshes memory if a save_memory succeeded. The Agent's loop has ALREADY
99
+ * recorded the completed calls into chat history do NOT call
100
+ * recordCompletedToolCalls here.
103
101
  */
104
102
  function handleToolsComplete(
105
103
  completed: readonly CompletedToolCall[],
@@ -118,13 +116,6 @@ function handleToolsComplete(
118
116
  userMessageTimestamp,
119
117
  );
120
118
  const { primaryTools, externalTools } = classifyCompletedTools(completedArr);
121
- if (
122
- primaryTools.some(
123
- (tc) => tc.request.name === 'todo_pause' && tc.status === 'success',
124
- )
125
- ) {
126
- args.onTodoPause?.();
127
- }
128
119
  const memoryRef = { current: processedMemoryTools };
129
120
  processMemoryToolResults(primaryTools, memoryRef, args.performMemoryRefresh);
130
121
 
@@ -161,8 +152,8 @@ export function useAgentEventStream(
161
152
  agent.tools.setDisplayCallbacks({
162
153
  onToolCallsUpdate: (toolCalls) =>
163
154
  latestArgs.current.onToolCallsUpdate?.(toolCalls),
164
- outputUpdateHandler: (callId, chunk) =>
165
- latestArgs.current.outputUpdateHandler?.(callId, chunk),
155
+ outputUpdateHandler: (callId, update) =>
156
+ latestArgs.current.outputUpdateHandler?.(callId, update),
166
157
  onAllToolCallsComplete: (completed) => {
167
158
  const userMessageTimestamp =
168
159
  currentTurnTimestampRef.current ?? Date.now();
@@ -53,7 +53,6 @@ export const useAgentStream = (
53
53
  setShellInputFocused: (value: boolean) => void,
54
54
  terminalWidth?: number,
55
55
  terminalHeight?: number,
56
- onTodoPause?: () => void,
57
56
  onEditorOpen: () => void = () => {},
58
57
  recordingIntegration?: RecordingIntegration,
59
58
  runtimeMessageBus?: MessageBus,
@@ -74,7 +73,6 @@ export const useAgentStream = (
74
73
  setShellInputFocused,
75
74
  terminalWidth,
76
75
  terminalHeight,
77
- onTodoPause,
78
76
  onEditorOpen,
79
77
  recordingIntegration,
80
78
  runtimeMessageBus,
@@ -114,6 +112,7 @@ function useAgentStreamReturn(
114
112
  return {
115
113
  streamingState: orchestration.streamingState,
116
114
  submitQuery: orchestration.submitQuery,
115
+ sanitizeContent: orchestration.st.sanitizeContent,
117
116
  initError: orchestration.st.initError,
118
117
  pendingHistoryItems,
119
118
  thought: orchestration.st.thought,
@@ -121,6 +120,7 @@ function useAgentStreamReturn(
121
120
  cancelOngoingRequest: orchestration.cancelOngoingRequest,
122
121
  activeShellPtyId: orchestration.activeShellPtyId,
123
122
  lastOutputTime: getLastOutputTime(orchestration),
123
+ queuedSubmissions: orchestration.queuedSubmissions,
124
124
  };
125
125
  }
126
126
 
@@ -29,7 +29,6 @@ import { mapToDisplay as mapTrackedToolCallsToDisplay } from '../toolMapping.js'
29
29
  import { classifyCompletedTools } from './toolCompletionHandler.js';
30
30
  import { useKeypress, type Key } from '../useKeypress.js';
31
31
  import { type UseHistoryManagerReturn } from '../useHistoryManager.js';
32
- import { type QueuedSubmission } from './types.js';
33
32
  import type { StreamRuntime } from '../../cliUiRuntime.js';
34
33
 
35
34
  export function useStreamingState(
@@ -220,7 +219,7 @@ export function useCancellation(
220
219
  >,
221
220
  onCancelSubmit: (shouldRestorePrompt?: boolean) => void,
222
221
  setIsResponding: React.Dispatch<React.SetStateAction<boolean>>,
223
- queuedSubmissionsRef: React.MutableRefObject<QueuedSubmission[]>,
222
+ setShellInputFocused: (value: boolean) => void,
224
223
  cancelRunningAsyncTasks: () => void = () => {},
225
224
  ) {
226
225
  const cancelOngoingRequest = useCallback(() => {
@@ -233,14 +232,14 @@ export function useCancellation(
233
232
  if (turnCancelledRef.current) return;
234
233
  turnCancelledRef.current = true;
235
234
  abortControllerRef.current?.abort();
236
- if (abortControllerRef.current) cancelAllToolCalls();
235
+ cancelAllToolCalls();
237
236
  cancelRunningAsyncTasks();
238
237
  if (pendingHistoryItemRef.current) flushPendingHistoryItem(Date.now());
239
238
  addItem({ type: MessageType.INFO, text: 'Request cancelled.' }, Date.now());
240
239
  setPendingHistoryItem(null);
241
240
  onCancelSubmit();
242
241
  setIsResponding(false);
243
- queuedSubmissionsRef.current = [];
242
+ setShellInputFocused(false);
244
243
  }, [
245
244
  streamingState,
246
245
  turnCancelledRef,
@@ -253,7 +252,7 @@ export function useCancellation(
253
252
  setPendingHistoryItem,
254
253
  onCancelSubmit,
255
254
  setIsResponding,
256
- queuedSubmissionsRef,
255
+ setShellInputFocused,
257
256
  ]);
258
257
  const cancelOngoingRequestRef = useRef(cancelOngoingRequest);
259
258
  cancelOngoingRequestRef.current = cancelOngoingRequest;
@@ -7,7 +7,7 @@
7
7
  import { useCallback, useMemo, useRef } from 'react';
8
8
  import {
9
9
  type EditorType,
10
- type AnsiOutput,
10
+ type LiveOutputUpdate,
11
11
  type MessageBus,
12
12
  type RecordingIntegration,
13
13
  type ToolCall,
@@ -34,6 +34,7 @@ import {
34
34
  useStreamingState,
35
35
  useToolSchedulerSetup,
36
36
  } from './useAgentStreamLifecycle.js';
37
+ import type { QueuedSubmission } from './types.js';
37
38
  import type { StreamRuntime } from '../../cliUiRuntime.js';
38
39
 
39
40
  export interface AgentStreamOrchestrationDeps {
@@ -54,7 +55,6 @@ export interface AgentStreamOrchestrationDeps {
54
55
  setShellInputFocused: (value: boolean) => void;
55
56
  terminalWidth?: number;
56
57
  terminalHeight?: number;
57
- onTodoPause?: () => void;
58
58
  onEditorOpen: () => void;
59
59
  recordingIntegration?: RecordingIntegration;
60
60
  runtimeMessageBus?: MessageBus;
@@ -71,6 +71,7 @@ export interface AgentStreamOrchestrationResult {
71
71
  interactiveRuntimeReady: boolean;
72
72
  cancelOngoingRequest: () => void;
73
73
  activeShellPtyId: number | null;
74
+ queuedSubmissions: readonly QueuedSubmission[];
74
75
  }
75
76
 
76
77
  interface ToolSchedulerState {
@@ -83,7 +84,7 @@ interface ToolSchedulerState {
83
84
  interactiveRuntimeReady: boolean;
84
85
  /** Bound display-state updaters for the AgenticLoop's displayCallbacks. */
85
86
  replaceToolCalls: (calls: ToolCall[]) => void;
86
- updateToolOutput: (callId: string, chunk: string | AnsiOutput) => void;
87
+ updateToolOutput: (callId: string, update: LiveOutputUpdate) => void;
87
88
  }
88
89
 
89
90
  export function useAgentStreamOrchestration(
@@ -123,7 +124,7 @@ export function useAgentStreamOrchestration(
123
124
  st.setPendingHistoryItem,
124
125
  args.onCancelSubmit,
125
126
  st.setIsResponding,
126
- st.queuedSubmissionsRef,
127
+ args.setShellInputFocused,
127
128
  cancelRunningAsyncTasks,
128
129
  );
129
130
  // Refs to break the circular dependency between useSubmitQuery (which
@@ -264,7 +265,6 @@ function useEventStreamForAgent(
264
265
  flushPendingHistoryItem: st.flushPendingHistoryItem,
265
266
  clearPendingHistoryItem: () => st.setPendingHistoryItem(null),
266
267
  performMemoryRefresh: args.performMemoryRefresh,
267
- onTodoPause: args.onTodoPause,
268
268
  markToolsAsDisplayCleared: scheduler.markToolsAsDisplayCleared,
269
269
  onToolCallsUpdate: scheduler.replaceToolCalls,
270
270
  outputUpdateHandler: scheduler.updateToolOutput,
@@ -304,6 +304,7 @@ function buildResult(
304
304
  interactiveRuntimeReady: scheduler.interactiveRuntimeReady,
305
305
  cancelOngoingRequest,
306
306
  activeShellPtyId: shell.activeShellPtyId,
307
+ queuedSubmissions: st.queuedSubmissions,
307
308
  };
308
309
  }
309
310
 
@@ -341,6 +342,12 @@ function buildSubmitQueryDeps({
341
342
  thinkingBlocksRef: st.thinkingBlocksRef,
342
343
  turnCancelledRef: st.turnCancelledRef,
343
344
  queuedSubmissionsRef: st.queuedSubmissionsRef,
345
+ enqueueSubmission: st.enqueueSubmission,
346
+ requeueSubmission: st.requeueSubmission,
347
+ dequeueSubmission: st.dequeueSubmission,
348
+ clearSubmissions: st.clearSubmissions,
349
+ tryReserveDrain: st.tryReserveDrain,
350
+ releaseDrain: st.releaseDrain,
344
351
  setPendingHistoryItem: st.setPendingHistoryItem,
345
352
  setIsResponding: st.setIsResponding,
346
353
  setInitError: st.setInitError,
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Vybestack LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { useCallback, useRef } from 'react';
8
+ import { useStateAndRef } from '../useStateAndRef.js';
9
+ import type { QueuedSubmission } from './types.js';
10
+
11
+ /**
12
+ * State-backed queued-submissions store with serialized drain ownership.
13
+ *
14
+ * Provides:
15
+ * - `queuedSubmissions` (reactive state for rendering)
16
+ * - `queuedSubmissionsRef` (stable ref for callback access)
17
+ * - `enqueueSubmission` (immutable append — updates both ref and state)
18
+ * - `requeueSubmission` (immutable front insertion for retry)
19
+ * - `dequeueSubmission` (FIFO shift — updates both ref and state)
20
+ * - `clearSubmissions` (clear — updates both ref and state)
21
+ *
22
+ * All mutations go through `setStateInternal` from useStateAndRef, which
23
+ * synchronously updates the ref AND schedules a React state update. This
24
+ * eliminates stale-closure/race conditions between the ref reads in
25
+ * scheduleNextQueuedSubmission/submitQuery and the reactive state that
26
+ * drives the QueuedMessagesPanel.
27
+ *
28
+ * Serialized draining: `tryReserveDrain` / `releaseDrain` provide a canonical
29
+ * ownership token that ensures exactly one drain attempt is in-flight at any
30
+ * time, preventing the double-drain race between the idle-effect trigger and
31
+ * the runSubmitQueryCore finally-block trigger (issue #2296).
32
+ */
33
+ export function useQueuedSubmissions() {
34
+ const [queuedSubmissions, queuedSubmissionsRef, setQueuedSubmissions] =
35
+ useStateAndRef<QueuedSubmission[]>([]);
36
+
37
+ // Canonical drain owner: true while a scheduleNextQueuedSubmission call has
38
+ // dequeued an item but the resulting submitQuery hasn't had a chance to set
39
+ // isResponding(true) yet. Prevents concurrent triggers from each dequeuing
40
+ // a separate item.
41
+ const drainInFlightRef = useRef(false);
42
+ const nextQueueIdRef = useRef(0);
43
+
44
+ const enqueueSubmission = useCallback(
45
+ (submission: QueuedSubmission): void => {
46
+ const queueId = nextQueueIdRef.current;
47
+ nextQueueIdRef.current = queueId + 1;
48
+ setQueuedSubmissions((prev) => [...prev, { ...submission, queueId }]);
49
+ },
50
+ [setQueuedSubmissions],
51
+ );
52
+
53
+ const requeueSubmission = useCallback(
54
+ (submission: QueuedSubmission): void => {
55
+ setQueuedSubmissions((prev) => [submission, ...prev]);
56
+ },
57
+ [setQueuedSubmissions],
58
+ );
59
+
60
+ const dequeueSubmission = useCallback((): QueuedSubmission | undefined => {
61
+ if (queuedSubmissionsRef.current.length === 0) {
62
+ return undefined;
63
+ }
64
+ const [first, ...rest] = queuedSubmissionsRef.current;
65
+ setQueuedSubmissions(rest);
66
+ return first;
67
+ }, [queuedSubmissionsRef, setQueuedSubmissions]);
68
+
69
+ const clearSubmissions = useCallback((): void => {
70
+ setQueuedSubmissions([]);
71
+ }, [setQueuedSubmissions]);
72
+
73
+ const tryReserveDrain = useCallback((): boolean => {
74
+ if (drainInFlightRef.current) {
75
+ return false;
76
+ }
77
+ drainInFlightRef.current = true;
78
+ return true;
79
+ }, []);
80
+
81
+ const releaseDrain = useCallback((): void => {
82
+ drainInFlightRef.current = false;
83
+ }, []);
84
+
85
+ return {
86
+ queuedSubmissions,
87
+ queuedSubmissionsRef,
88
+ enqueueSubmission,
89
+ requeueSubmission,
90
+ dequeueSubmission,
91
+ clearSubmissions,
92
+ tryReserveDrain,
93
+ releaseDrain,
94
+ };
95
+ }
96
+
97
+ export type UseQueuedSubmissionsReturn = ReturnType<
98
+ typeof useQueuedSubmissions
99
+ >;
@@ -141,13 +141,7 @@ interface StreamEventHandlerDeps {
141
141
  pendingHistoryItemRef: React.MutableRefObject<HistoryItemWithoutId | null>;
142
142
  thinkingBlocksRef: React.MutableRefObject<ThinkingBlock[]>;
143
143
  turnCancelledRef: React.MutableRefObject<boolean>;
144
- queuedSubmissionsRef: React.MutableRefObject<
145
- Array<{
146
- query: AgentRequestInput;
147
- options?: { isContinuation: boolean };
148
- promptId?: string;
149
- }>
150
- >;
144
+ clearSubmissions: () => void;
151
145
  setPendingHistoryItem: React.Dispatch<
152
146
  React.SetStateAction<HistoryItemWithoutId | null>
153
147
  >;
@@ -249,7 +243,6 @@ function useUserCancelledHandler(deps: StreamEventHandlerDeps) {
249
243
  addItem,
250
244
  flushPendingHistoryItem,
251
245
  pendingHistoryItemRef,
252
- queuedSubmissionsRef,
253
246
  setIsResponding,
254
247
  setPendingHistoryItem,
255
248
  setThought,
@@ -282,14 +275,12 @@ function useUserCancelledHandler(deps: StreamEventHandlerDeps) {
282
275
  userMessageTimestamp,
283
276
  );
284
277
  setIsResponding(false);
285
- queuedSubmissionsRef.current = [];
286
278
  setThought(null);
287
279
  },
288
280
  [
289
281
  addItem,
290
282
  flushPendingHistoryItem,
291
283
  pendingHistoryItemRef,
292
- queuedSubmissionsRef,
293
284
  setIsResponding,
294
285
  setPendingHistoryItem,
295
286
  setThought,
@@ -304,7 +295,7 @@ function useErrorEventHandler(deps: StreamEventHandlerDeps) {
304
295
  runtime,
305
296
  flushPendingHistoryItem,
306
297
  pendingHistoryItemRef,
307
- queuedSubmissionsRef,
298
+ clearSubmissions,
308
299
  setPendingHistoryItem,
309
300
  setThought,
310
301
  } = deps;
@@ -334,7 +325,7 @@ function useErrorEventHandler(deps: StreamEventHandlerDeps) {
334
325
  },
335
326
  userMessageTimestamp,
336
327
  );
337
- if (options?.clearQueue ?? true) queuedSubmissionsRef.current = [];
328
+ if (options?.clearQueue ?? true) clearSubmissions();
338
329
  setThought(null);
339
330
  },
340
331
  [
@@ -342,7 +333,7 @@ function useErrorEventHandler(deps: StreamEventHandlerDeps) {
342
333
  runtime,
343
334
  flushPendingHistoryItem,
344
335
  pendingHistoryItemRef,
345
- queuedSubmissionsRef,
336
+ clearSubmissions,
346
337
  setPendingHistoryItem,
347
338
  setThought,
348
339
  ],
@@ -26,7 +26,9 @@ import { type HistoryItemWithoutId, MessageType } from '../../types.js';
26
26
  import { useStateAndRef } from '../useStateAndRef.js';
27
27
  import { useLogger } from '../useLogger.js';
28
28
  import { type QueuedSubmission } from './types.js';
29
+ import { useQueuedSubmissions } from './useQueuedSubmissions.js';
29
30
  import type { StreamRuntime } from '../../cliUiRuntime.js';
31
+ import type { SubmissionExecutor } from './useSubmitQuery.js';
30
32
 
31
33
  export interface UseStreamStateReturn {
32
34
  initError: string | null;
@@ -49,14 +51,14 @@ export interface UseStreamStateReturn {
49
51
  lastAgentActivityTime: number;
50
52
  setLastAgentActivityTime: React.Dispatch<React.SetStateAction<number>>;
51
53
  queuedSubmissionsRef: React.MutableRefObject<QueuedSubmission[]>;
52
- submitQueryRef: React.MutableRefObject<
53
- | ((
54
- query: unknown,
55
- options?: { isContinuation: boolean },
56
- prompt_id?: string,
57
- ) => Promise<void>)
58
- | null
59
- >;
54
+ queuedSubmissions: readonly QueuedSubmission[];
55
+ enqueueSubmission: (submission: QueuedSubmission) => void;
56
+ requeueSubmission: (submission: QueuedSubmission) => void;
57
+ dequeueSubmission: () => QueuedSubmission | undefined;
58
+ clearSubmissions: () => void;
59
+ tryReserveDrain: () => boolean;
60
+ releaseDrain: () => void;
61
+ submitQueryRef: React.MutableRefObject<SubmissionExecutor | null>;
60
62
  sanitizeContent: (text: string) => {
61
63
  text: string;
62
64
  blocked: boolean;
@@ -187,10 +189,7 @@ function useFlushPendingHistoryItem(
187
189
  );
188
190
  }
189
191
 
190
- export function useStreamState(
191
- addItem: (item: HistoryItemWithoutId, timestamp: number) => number,
192
- runtime: StreamRuntime,
193
- ): UseStreamStateReturn {
192
+ function useBasicStreamState() {
194
193
  const [initError, setInitError] = useState<string | null>(null);
195
194
  const abortControllerRef = useRef<AbortController | null>(null);
196
195
  const abortActiveStream = useCallback((reason?: unknown) => {
@@ -205,36 +204,19 @@ export function useStreamState(
205
204
  const [pendingHistoryItem, pendingHistoryItemRef, setPendingHistoryItem] =
206
205
  useStateAndRef<HistoryItemWithoutId | null>(null);
207
206
  const [lastAgentActivityTime, setLastAgentActivityTime] = useState<number>(0);
208
- const queuedSubmissionsRef = useRef<QueuedSubmission[]>([]);
209
- const submitQueryRef = useRef<
210
- | ((
211
- query: unknown,
212
- options?: { isContinuation: boolean },
213
- prompt_id?: string,
214
- ) => Promise<void>)
215
- | null
216
- >(null);
217
- const storage = runtime.storage;
207
+ const {
208
+ queuedSubmissions,
209
+ queuedSubmissionsRef,
210
+ enqueueSubmission,
211
+ requeueSubmission,
212
+ dequeueSubmission,
213
+ clearSubmissions,
214
+ tryReserveDrain,
215
+ releaseDrain,
216
+ } = useQueuedSubmissions();
217
+ const submitQueryRef = useRef<SubmissionExecutor | null>(null);
218
218
  const thinkingBlocksRef = useRef<ThinkingBlock[]>([]);
219
219
 
220
- const emojiFilter = useEmojiFilter(runtime);
221
- const sanitizeContent = useSanitizeContent(emojiFilter);
222
- const flushPendingHistoryItem = useFlushPendingHistoryItem(
223
- addItem,
224
- pendingHistoryItemRef,
225
- sanitizeContent,
226
- setPendingHistoryItem,
227
- thinkingBlocksRef,
228
- );
229
- const logger = useLogger(storage);
230
- const gitService = useMemo(() => {
231
- const projectRoot = runtime.session.getProjectRoot();
232
- if (projectRoot.length === 0) {
233
- return undefined;
234
- }
235
- return new GitService(projectRoot, storage);
236
- }, [runtime, storage]);
237
-
238
220
  return {
239
221
  initError,
240
222
  setInitError,
@@ -253,12 +235,49 @@ export function useStreamState(
253
235
  setPendingHistoryItem,
254
236
  lastAgentActivityTime,
255
237
  setLastAgentActivityTime,
238
+ queuedSubmissions,
256
239
  queuedSubmissionsRef,
240
+ enqueueSubmission,
241
+ requeueSubmission,
242
+ dequeueSubmission,
243
+ clearSubmissions,
244
+ tryReserveDrain,
245
+ releaseDrain,
257
246
  submitQueryRef,
247
+ thinkingBlocksRef,
248
+ };
249
+ }
250
+
251
+ export function useStreamState(
252
+ addItem: (item: HistoryItemWithoutId, timestamp: number) => number,
253
+ runtime: StreamRuntime,
254
+ ): UseStreamStateReturn {
255
+ const basic = useBasicStreamState();
256
+ const storage = runtime.storage;
257
+
258
+ const emojiFilter = useEmojiFilter(runtime);
259
+ const sanitizeContent = useSanitizeContent(emojiFilter);
260
+ const flushPendingHistoryItem = useFlushPendingHistoryItem(
261
+ addItem,
262
+ basic.pendingHistoryItemRef,
263
+ sanitizeContent,
264
+ basic.setPendingHistoryItem,
265
+ basic.thinkingBlocksRef,
266
+ );
267
+ const logger = useLogger(storage);
268
+ const gitService = useMemo(() => {
269
+ const projectRoot = runtime.session.getProjectRoot();
270
+ if (projectRoot.length === 0) {
271
+ return undefined;
272
+ }
273
+ return new GitService(projectRoot, storage);
274
+ }, [runtime, storage]);
275
+
276
+ return {
277
+ ...basic,
258
278
  sanitizeContent,
259
279
  flushPendingHistoryItem,
260
280
  logger,
261
281
  gitService,
262
- thinkingBlocksRef,
263
282
  };
264
283
  }