@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.
- package/package.json +13 -13
- package/src/commands/mcp/add.ts +8 -4
- package/src/config/cliArgParser.ts +2 -0
- package/src/config/config.ts +2 -0
- package/src/config/configBuilder.ts +3 -0
- package/src/config/configError.ts +23 -0
- package/src/config/extensions/extensionEnablement.ts +62 -1
- package/src/config/interactiveContext.ts +2 -1
- package/src/config/intermediateConfig.ts +4 -0
- package/src/config/keyBindings.ts +29 -3
- package/src/config/policy.ts +7 -1
- package/src/config/postConfigRuntime.ts +20 -14
- package/src/config/settings-schema/schema-ui.ts +9 -0
- package/src/config/settingsLoader.ts +21 -17
- package/src/config/settingsSchema.ts +2 -2
- package/src/config/trustedFolders.ts +275 -58
- package/src/config/yargsOptions.ts +7 -0
- package/src/generated/git-commit.json +1 -1
- package/src/nonInteractiveCli.ts +1 -0
- package/src/nonInteractiveCliSupport.ts +171 -51
- package/src/runtime/interactiveToolScheduler.ts +6 -6
- package/src/services/BuiltinCommandLoader.ts +33 -25
- package/src/services/FileCommandLoader.ts +34 -7
- package/src/test-utils/async.ts +20 -0
- package/src/test-utils/render.tsx +10 -1
- package/src/ui/App.tsx +17 -10
- package/src/ui/AppContainerRuntime.tsx +7 -9
- package/src/ui/cliUiRuntime.ts +28 -0
- package/src/ui/commands/authCommand.ts +240 -3
- package/src/ui/commands/compressCommand.ts +9 -1
- package/src/ui/commands/directoryCommand.tsx +1 -1
- package/src/ui/commands/logoutCommand.ts +2 -2
- package/src/ui/commands/permissionsCommand.ts +77 -20
- package/src/ui/commands/policiesCommand.ts +6 -1
- package/src/ui/commands/quotaCommand.ts +501 -0
- package/src/ui/commands/statsCommand.ts +2 -2
- package/src/ui/commands/statsQuota.ts +1 -1
- package/src/ui/commands/subagentCommand.ts +59 -27
- package/src/ui/components/AuthDialog.tsx +3 -3
- package/src/ui/components/Composer.tsx +1 -0
- package/src/ui/components/DialogManager.tsx +9 -2
- package/src/ui/components/FolderTrustDialog.tsx +71 -60
- package/src/ui/components/PermissionsModifyTrustDialog.tsx +211 -146
- package/src/ui/components/ProfileCreateWizard/constants.ts +13 -1
- package/src/ui/components/QueuedMessagesPanel.tsx +388 -0
- package/src/ui/components/inputPromptHooks.ts +2 -0
- package/src/ui/components/inputPromptKeyHandlers.ts +14 -0
- package/src/ui/components/inputPromptTypes.ts +6 -0
- package/src/ui/components/messages/AiMessage.tsx +24 -12
- package/src/ui/components/messages/ToolMessage.tsx +26 -40
- package/src/ui/containers/AppContainer/builders/buildUIActions.ts +3 -1
- package/src/ui/containers/AppContainer/builders/buildUIState.ts +5 -4
- package/src/ui/containers/AppContainer/hooks/useAppBootstrap.ts +3 -33
- package/src/ui/containers/AppContainer/hooks/useAppDialogs.ts +2 -14
- package/src/ui/containers/AppContainer/hooks/useAppInput.ts +31 -25
- package/src/ui/containers/AppContainer/hooks/useAppLayout.ts +90 -60
- package/src/ui/containers/AppContainer/hooks/useDisplayPreferences.ts +10 -0
- package/src/ui/containers/AppContainer/hooks/useInputHandling.ts +3 -17
- package/src/ui/containers/AppContainer/hooks/useKeybindings.ts +51 -38
- package/src/ui/containers/AppContainer/hooks/useSteer.ts +51 -0
- package/src/ui/contexts/KeypressContext.tsx +13 -2
- package/src/ui/contexts/ShellCommandDisplayContext.tsx +103 -0
- package/src/ui/contexts/TodoContext.tsx +0 -13
- package/src/ui/contexts/TodoProvider.tsx +1 -34
- package/src/ui/contexts/UIActionsContext.tsx +2 -1
- package/src/ui/contexts/UIStateContext.tsx +3 -2
- package/src/ui/hooks/agentStream/streamUtils.ts +0 -24
- package/src/ui/hooks/agentStream/thoughtState.ts +110 -30
- package/src/ui/hooks/agentStream/types.ts +1 -0
- package/src/ui/hooks/agentStream/useAgentEventStream.ts +8 -17
- package/src/ui/hooks/agentStream/useAgentStream.ts +2 -2
- package/src/ui/hooks/agentStream/useAgentStreamLifecycle.ts +4 -5
- package/src/ui/hooks/agentStream/useAgentStreamOrchestration.ts +12 -5
- package/src/ui/hooks/agentStream/useQueuedSubmissions.ts +99 -0
- package/src/ui/hooks/agentStream/useStreamEventHandlers.ts +4 -13
- package/src/ui/hooks/agentStream/useStreamState.ts +60 -41
- package/src/ui/hooks/agentStream/useSubmitQuery.ts +284 -59
- package/src/ui/hooks/slashCommandProcessorSupport.ts +4 -0
- package/src/ui/hooks/useAgentStream-test-helpers.ts +1 -0
- package/src/ui/hooks/useAutoAcceptIndicator.ts +13 -0
- package/src/ui/hooks/useFolderTrust.ts +118 -81
- package/src/ui/hooks/useGitBranchName.ts +79 -33
- package/src/ui/hooks/useIdeTrustListener.ts +5 -19
- package/src/ui/hooks/usePermissionsModifyTrust.ts +223 -85
- package/src/ui/hooks/useReactToolScheduler.ts +13 -17
- package/src/ui/hooks/useTodoPausePreserver.ts +0 -55
- package/src/ui/layouts/DefaultAppLayout.tsx +2 -0
- package/src/ui/layouts/DefaultAppLayoutHelpers.tsx +37 -162
- package/src/ui/layouts/InlineContent.tsx +198 -0
- package/src/ui/trustDialogHelpers.ts +190 -0
- package/src/utils/cleanup-state.ts +115 -0
- package/src/utils/cleanup.ts +32 -34
- package/src/utils/sandbox-containers.ts +183 -53
- package/src/utils/sandbox-exec.ts +9 -3
- package/src/zed-integration/acp-terminal-shell-host.ts +112 -0
- package/src/zed-integration/acp-types.ts +35 -0
- package/src/zed-integration/fileSystemService.ts +1 -1
- package/src/zed-integration/runZedIntegration.ts +142 -0
- package/src/zed-integration/zed-agent-event-handler.ts +179 -0
- package/src/zed-integration/zed-agent-setup.ts +43 -0
- package/src/zed-integration/zed-command-registry.ts +167 -0
- package/src/zed-integration/zed-config-options.ts +280 -0
- package/src/zed-integration/zed-content-utils.ts +2 -2
- package/src/zed-integration/zed-helpers.ts +132 -0
- package/src/zed-integration/zed-initialize.ts +64 -0
- package/src/zed-integration/zed-plan-update.ts +20 -0
- package/src/zed-integration/zed-prompt-command.ts +77 -0
- package/src/zed-integration/zed-session-config.ts +119 -0
- package/src/zed-integration/zed-session-errors.ts +337 -0
- package/src/zed-integration/zed-session-events.ts +216 -0
- package/src/zed-integration/zed-session-info.ts +255 -0
- package/src/zed-integration/zed-session-lifecycle.ts +186 -0
- package/src/zed-integration/zed-session-listing.ts +153 -0
- package/src/zed-integration/zed-session-loader.ts +193 -0
- package/src/zed-integration/zed-session-pagination.ts +240 -0
- package/src/zed-integration/zed-session-replay.ts +564 -0
- package/src/zed-integration/zed-stream-batcher.ts +236 -0
- package/src/zed-integration/zed-terminal-manager.ts +416 -0
- package/src/zed-integration/zed-terminal-setup.ts +72 -0
- package/src/zed-integration/zed-test-helpers.ts +349 -4
- package/src/zed-integration/zed-tool-handler.ts +47 -5
- package/src/zed-integration/zedIntegration.ts +538 -587
- package/src/services/todo-continuation/todoContinuationService.ts +0 -610
- package/src/ui/containers/AppContainer/hooks/useIdeRestartHotkey.ts +0 -33
- package/src/ui/containers/AppContainer/hooks/useTodoContinuationFlow.ts +0 -160
- 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
|
-
|
|
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,
|
|
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
|
|
101
|
-
*
|
|
102
|
-
*
|
|
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,
|
|
165
|
-
latestArgs.current.outputUpdateHandler?.(callId,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
|
}
|