aegiscode 3.1.10 → 3.4.2
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/bin/aegis.js +165 -0
- package/package.json +18 -86
- package/LICENSE +0 -21
- package/README.md +0 -394
- package/dist/main.js +0 -2171
- package/gui/run-gui.cjs +0 -13
- package/src/agent/Agent.ts +0 -903
- package/src/agent/SimpleAgent.ts +0 -48
- package/src/agent/index.ts +0 -54
- package/src/agent/orchestrator/AppBuilder.ts +0 -443
- package/src/agent/orchestrator/CouncilAgent.ts +0 -310
- package/src/agent/orchestrator/DiscussionRoom.ts +0 -462
- package/src/agent/orchestrator/OrchestratorAgent.ts +0 -637
- package/src/agent/orchestrator/index.ts +0 -38
- package/src/agent/orchestrator/utils.ts +0 -397
- package/src/agent/pricing.ts +0 -115
- package/src/agent/router.ts +0 -74
- package/src/agent/routerStats.ts +0 -121
- package/src/agent/types.ts +0 -318
- package/src/auth/login.ts +0 -383
- package/src/cli/config.ts +0 -189
- package/src/cli/index.ts +0 -17
- package/src/cli/middleware.ts +0 -119
- package/src/cli/types.ts +0 -75
- package/src/config/ConfigManager.ts +0 -587
- package/src/config/index.ts +0 -7
- package/src/config/types.ts +0 -584
- package/src/context/CompactionService.ts +0 -300
- package/src/context/ContextManager.ts +0 -450
- package/src/context/FileAnalyzer.ts +0 -267
- package/src/context/TokenCounter.ts +0 -265
- package/src/context/index.ts +0 -27
- package/src/context/storage/CacheStore.ts +0 -176
- package/src/context/storage/JSONLStore.ts +0 -201
- package/src/context/storage/MemoryStore.ts +0 -205
- package/src/context/storage/PersistentStore.ts +0 -327
- package/src/context/storage/index.ts +0 -9
- package/src/context/storage/pathUtils.ts +0 -114
- package/src/context/test.ts +0 -309
- package/src/context/types.ts +0 -268
- package/src/hooks/HookExecutor.ts +0 -434
- package/src/hooks/HookManager.ts +0 -596
- package/src/hooks/HookService.ts +0 -269
- package/src/hooks/Matcher.ts +0 -157
- package/src/hooks/index.ts +0 -63
- package/src/hooks/types.ts +0 -424
- package/src/main.tsx +0 -596
- package/src/mcp/HealthMonitor.ts +0 -150
- package/src/mcp/McpClient.ts +0 -491
- package/src/mcp/McpRegistry.ts +0 -321
- package/src/mcp/createMcpTool.ts +0 -251
- package/src/mcp/index.ts +0 -15
- package/src/mcp/server.ts +0 -334
- package/src/mcp/test-server.ts +0 -88
- package/src/mcp/test.ts +0 -372
- package/src/mcp/types.ts +0 -247
- package/src/memory/AgentMemoryBus.ts +0 -432
- package/src/memory/CloudSync.ts +0 -99
- package/src/memory/DriveSync.ts +0 -106
- package/src/memory/SharedMemory.ts +0 -951
- package/src/memory/index.ts +0 -14
- package/src/memory/machineFingerprint.ts +0 -40
- package/src/orchestrator/SubAgentMetadata.ts +0 -136
- package/src/prompts/builder.ts +0 -213
- package/src/prompts/default.ts +0 -144
- package/src/prompts/index.ts +0 -16
- package/src/prompts/plan.ts +0 -64
- package/src/prompts/test.ts +0 -78
- package/src/services/AnthropicChatService.ts +0 -341
- package/src/services/ChatService.ts +0 -347
- package/src/services/ClaudeCliChatService.ts +0 -256
- package/src/services/CloudSync.ts +0 -168
- package/src/services/CostLedger.ts +0 -211
- package/src/services/Heartbeat.ts +0 -135
- package/src/services/LearningCollector.ts +0 -291
- package/src/services/OllamaInstaller.ts +0 -342
- package/src/services/VersionChecker.ts +0 -445
- package/src/services/index.ts +0 -57
- package/src/services/streaming/OpenAIEventAdapter.ts +0 -126
- package/src/services/streaming/RenderingProfile.ts +0 -90
- package/src/services/streaming/StreamEventParser.ts +0 -181
- package/src/services/streaming/ThrottledRenderer.ts +0 -139
- package/src/services/streaming/TranscriptBuffer.ts +0 -574
- package/src/services/streaming/eventStatusMap.ts +0 -52
- package/src/services/streaming/index.ts +0 -46
- package/src/services/streaming/renderFormatting.ts +0 -79
- package/src/services/streaming/types.ts +0 -234
- package/src/skills/SkillLoader.ts +0 -126
- package/src/skills/SkillRegistry.ts +0 -366
- package/src/skills/index.ts +0 -48
- package/src/skills/types.ts +0 -146
- package/src/slash-commands/billing.ts +0 -70
- package/src/slash-commands/build.ts +0 -413
- package/src/slash-commands/builtinCommands.ts +0 -2733
- package/src/slash-commands/clone.ts +0 -242
- package/src/slash-commands/council.ts +0 -125
- package/src/slash-commands/custom/CustomCommandExecutor.ts +0 -143
- package/src/slash-commands/custom/CustomCommandLoader.ts +0 -251
- package/src/slash-commands/custom/CustomCommandRegistry.ts +0 -144
- package/src/slash-commands/custom/index.ts +0 -7
- package/src/slash-commands/debate.ts +0 -254
- package/src/slash-commands/gmail.ts +0 -105
- package/src/slash-commands/index.ts +0 -388
- package/src/slash-commands/mcpCommand.ts +0 -205
- package/src/slash-commands/types.ts +0 -201
- package/src/store/index.ts +0 -76
- package/src/store/selectors.ts +0 -246
- package/src/store/slices/appSlice.ts +0 -205
- package/src/store/slices/commandSlice.ts +0 -115
- package/src/store/slices/configSlice.ts +0 -46
- package/src/store/slices/focusSlice.ts +0 -64
- package/src/store/slices/index.ts +0 -9
- package/src/store/slices/sessionSlice.ts +0 -424
- package/src/store/streaming-buffer.ts +0 -425
- package/src/store/test.ts +0 -296
- package/src/store/types.ts +0 -274
- package/src/store/vanilla.ts +0 -186
- package/src/tools/builtin/bash.ts +0 -236
- package/src/tools/builtin/council.ts +0 -105
- package/src/tools/builtin/edit.ts +0 -213
- package/src/tools/builtin/glob.ts +0 -136
- package/src/tools/builtin/grep.ts +0 -263
- package/src/tools/builtin/index.ts +0 -61
- package/src/tools/builtin/memory.ts +0 -66
- package/src/tools/builtin/read.ts +0 -168
- package/src/tools/builtin/skill.ts +0 -97
- package/src/tools/builtin/snapshot.ts +0 -40
- package/src/tools/builtin/task.ts +0 -106
- package/src/tools/builtin/write.ts +0 -134
- package/src/tools/createTool.ts +0 -221
- package/src/tools/execution/ExecutionPipeline.ts +0 -263
- package/src/tools/execution/index.ts +0 -40
- package/src/tools/execution/stages/CacheStage.ts +0 -131
- package/src/tools/execution/stages/ConfirmationStage.ts +0 -203
- package/src/tools/execution/stages/DiscoveryStage.ts +0 -46
- package/src/tools/execution/stages/ExecutionStage.ts +0 -48
- package/src/tools/execution/stages/FormattingStage.ts +0 -44
- package/src/tools/execution/stages/HookStage.ts +0 -72
- package/src/tools/execution/stages/PermissionStage.ts +0 -287
- package/src/tools/execution/stages/PostHookStage.ts +0 -71
- package/src/tools/execution/stages/index.ts +0 -12
- package/src/tools/execution/test.ts +0 -266
- package/src/tools/execution/types.ts +0 -273
- package/src/tools/index.ts +0 -81
- package/src/tools/registry.ts +0 -304
- package/src/tools/schemas.ts +0 -109
- package/src/tools/test.ts +0 -220
- package/src/tools/types.ts +0 -175
- package/src/tools/validation/PermissionChecker.ts +0 -242
- package/src/tools/validation/SensitiveFileDetector.ts +0 -210
- package/src/tools/validation/index.ts +0 -11
- package/src/ui/App.tsx +0 -166
- package/src/ui/components/AegisInterface.tsx +0 -484
- package/src/ui/components/common/ChatSearch.tsx +0 -150
- package/src/ui/components/common/ErrorBoundary.tsx +0 -82
- package/src/ui/components/common/ExitMessage.tsx +0 -120
- package/src/ui/components/common/LoadingIndicator.tsx +0 -49
- package/src/ui/components/common/index.ts +0 -6
- package/src/ui/components/dialog/ConfirmationPrompt.tsx +0 -208
- package/src/ui/components/dialog/InteractiveSelector.tsx +0 -149
- package/src/ui/components/dialog/SetupWizard.tsx +0 -297
- package/src/ui/components/dialog/UpdatePrompt.tsx +0 -155
- package/src/ui/components/dialog/index.ts +0 -8
- package/src/ui/components/index.ts +0 -28
- package/src/ui/components/input/CommandSuggestions.tsx +0 -139
- package/src/ui/components/input/CustomTextInput.tsx +0 -220
- package/src/ui/components/input/InputArea.tsx +0 -361
- package/src/ui/components/input/PromptSuggestions.tsx +0 -66
- package/src/ui/components/input/index.ts +0 -6
- package/src/ui/components/layout/ChatStatusBar.tsx +0 -90
- package/src/ui/components/layout/ContextBar.tsx +0 -79
- package/src/ui/components/layout/MessageArea.tsx +0 -96
- package/src/ui/components/layout/MessageList.tsx +0 -647
- package/src/ui/components/layout/MessageSeparator.tsx +0 -26
- package/src/ui/components/layout/WelcomeMessage.tsx +0 -93
- package/src/ui/components/layout/index.ts +0 -7
- package/src/ui/components/markdown/CodeHighlighter.tsx +0 -292
- package/src/ui/components/markdown/MessageRenderer.tsx +0 -1211
- package/src/ui/components/markdown/index.ts +0 -8
- package/src/ui/components/markdown/parser.ts +0 -336
- package/src/ui/components/markdown/types.ts +0 -66
- package/src/ui/focus/FocusManager.ts +0 -137
- package/src/ui/focus/index.ts +0 -13
- package/src/ui/focus/types.ts +0 -54
- package/src/ui/focus/useFocus.ts +0 -75
- package/src/ui/hooks/index.ts +0 -11
- package/src/ui/hooks/useAgent.ts +0 -284
- package/src/ui/hooks/useCommandHistory.ts +0 -87
- package/src/ui/hooks/useCommandProcessor.ts +0 -443
- package/src/ui/hooks/useConfirmation.ts +0 -99
- package/src/ui/hooks/useCtrlCHandler.ts +0 -100
- package/src/ui/hooks/useInputBuffer.ts +0 -122
- package/src/ui/hooks/useTerminalSize.ts +0 -68
- package/src/ui/hooks/useTerminalWidth.ts +0 -5
- package/src/ui/hooks/useWindowedList.ts +0 -118
- package/src/ui/render-debugger.ts +0 -621
- package/src/ui/test.ts +0 -189
- package/src/ui/themes/ThemeManager.ts +0 -332
- package/src/ui/themes/aegisTheme.ts +0 -87
- package/src/ui/themes/darkTheme.ts +0 -87
- package/src/ui/themes/defaultTheme.ts +0 -85
- package/src/ui/themes/index.ts +0 -10
- package/src/ui/themes/lightTheme.ts +0 -89
- package/src/ui/themes/popularThemes.ts +0 -187
- package/src/ui/themes/types.ts +0 -130
- package/src/utils/clipboard.ts +0 -48
- package/src/utils/debug.ts +0 -43
- package/src/utils/environment.ts +0 -68
- package/src/utils/index.ts +0 -10
|
@@ -1,425 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Streaming Buffer - external mutable buffer for streaming content.
|
|
3
|
-
*
|
|
4
|
-
* This completely bypasses the zustand store during streaming deltas.
|
|
5
|
-
* Instead of calling set() on every flush (which triggers React re-renders
|
|
6
|
-
* across all store subscribers), we write directly to a mutable buffer.
|
|
7
|
-
* The MessageList RAF loop reads from this buffer directly.
|
|
8
|
-
*
|
|
9
|
-
* Only start/finish streaming and explicit flushes update the store.
|
|
10
|
-
*
|
|
11
|
-
* Supports Content Block model (Claude-style): text, thinking, tool_use, tool_result.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import type { SessionMessage, ToolCallStatus, ContentBlock } from './types.js';
|
|
15
|
-
import { TranscriptBuffer } from '../services/streaming/TranscriptBuffer.js';
|
|
16
|
-
import { parseStreamEvent } from '../services/streaming/StreamEventParser.js';
|
|
17
|
-
import type { AnthropicStreamEvent } from '../services/streaming/types.js';
|
|
18
|
-
|
|
19
|
-
// Shared mutable state for the currently streaming message
|
|
20
|
-
interface StreamingState {
|
|
21
|
-
messageId: string | null;
|
|
22
|
-
content: string;
|
|
23
|
-
thinking: string;
|
|
24
|
-
// Content block tracking
|
|
25
|
-
currentBlockType: 'text' | 'thinking' | null;
|
|
26
|
-
currentBlockAccumulator: string;
|
|
27
|
-
toolCalls: Map<string, { name: string; arguments: string; status: ToolCallStatus }>;
|
|
28
|
-
/** Canonical rich segment state — single source of truth for streaming content */
|
|
29
|
-
transcriptBuffer: TranscriptBuffer;
|
|
30
|
-
/** Maps content block index → tool use ID for input_json_delta accumulation */
|
|
31
|
-
blockIndexToToolId: Map<number, string>;
|
|
32
|
-
/** Timestamp of last content write — used to measure render latency */
|
|
33
|
-
lastWriteTimestamp: number;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const streamingState: StreamingState = {
|
|
37
|
-
messageId: null,
|
|
38
|
-
content: '',
|
|
39
|
-
thinking: '',
|
|
40
|
-
currentBlockType: null,
|
|
41
|
-
currentBlockAccumulator: '',
|
|
42
|
-
toolCalls: new Map(),
|
|
43
|
-
transcriptBuffer: new TranscriptBuffer({ showToolResults: false }),
|
|
44
|
-
blockIndexToToolId: new Map(),
|
|
45
|
-
lastWriteTimestamp: 0,
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Check if a message IS the currently active streaming message (by ref).
|
|
50
|
-
* This is used by the RAF loop to efficiently skip non-streaming messages.
|
|
51
|
-
*/
|
|
52
|
-
export function isActiveStreamingMessage(msg: SessionMessage): boolean {
|
|
53
|
-
return msg.id === streamingState.messageId;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Get direct reference to current streaming content.
|
|
58
|
-
* Returns null if no streaming is active.
|
|
59
|
-
*/
|
|
60
|
-
export function getStreamingContent(): { content: string; thinking: string } | null {
|
|
61
|
-
if (!streamingState.messageId) return null;
|
|
62
|
-
return {
|
|
63
|
-
content: streamingState.content,
|
|
64
|
-
thinking: streamingState.thinking,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Get streaming content blocks synthesized from the current buffer state.
|
|
70
|
-
* Returns TextBlock and ThinkingBlock objects representing in-flight content,
|
|
71
|
-
* plus any accumulated tool_use blocks.
|
|
72
|
-
*
|
|
73
|
-
* These are merged with store content blocks in MessageList for structured rendering.
|
|
74
|
-
*/
|
|
75
|
-
export function getStreamingContentBlocks(): ContentBlock[] {
|
|
76
|
-
const blocks: ContentBlock[] = [];
|
|
77
|
-
|
|
78
|
-
if (streamingState.thinking) {
|
|
79
|
-
blocks.push({ type: 'thinking', thinking: streamingState.thinking });
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (streamingState.content) {
|
|
83
|
-
blocks.push({ type: 'text', text: streamingState.content });
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return blocks;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Apply a raw Anthropic-format streaming event.
|
|
91
|
-
*
|
|
92
|
-
* This is the primary entry point for the main chat path. It feeds the
|
|
93
|
-
* TranscriptBuffer (rich segment model) and simultaneously updates the
|
|
94
|
-
* mutable content/thinking strings (for drain/flush compat) and the
|
|
95
|
-
* toolCalls map (for arg accumulation before store flush).
|
|
96
|
-
*
|
|
97
|
-
* Legacy paths (slash commands) continue using appendToBuffer /
|
|
98
|
-
* appendThinkingToBuffer directly and bypass the TranscriptBuffer.
|
|
99
|
-
*/
|
|
100
|
-
export function applyStreamEvent(event: AnthropicStreamEvent): void {
|
|
101
|
-
const parsed = parseStreamEvent(event);
|
|
102
|
-
for (const e of parsed) {
|
|
103
|
-
streamingState.transcriptBuffer.apply(e);
|
|
104
|
-
|
|
105
|
-
if ((e.type === 'text_delta' || e.type === 'text_chunk') && e.text) {
|
|
106
|
-
streamingState.content += e.text;
|
|
107
|
-
streamingState.lastWriteTimestamp = Date.now();
|
|
108
|
-
streamingState.currentBlockType = 'text';
|
|
109
|
-
streamingState.currentBlockAccumulator += e.text;
|
|
110
|
-
}
|
|
111
|
-
if ((e.type === 'thinking_delta' || e.type === 'thinking_chunk') && e.text) {
|
|
112
|
-
streamingState.thinking += e.text;
|
|
113
|
-
streamingState.lastWriteTimestamp = Date.now();
|
|
114
|
-
streamingState.currentBlockType = 'thinking';
|
|
115
|
-
streamingState.currentBlockAccumulator += e.text;
|
|
116
|
-
}
|
|
117
|
-
if (e.type === 'tool_use_start' && e.id && e.name) {
|
|
118
|
-
if (!streamingState.toolCalls.has(e.id)) {
|
|
119
|
-
streamingState.toolCalls.set(e.id, { name: e.name, arguments: '', status: 'running' });
|
|
120
|
-
}
|
|
121
|
-
if (e.index !== undefined && e.index >= 0) {
|
|
122
|
-
streamingState.blockIndexToToolId.set(e.index, e.id);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
if (e.type === 'tool_use_delta' && e.partial_json && e.index !== undefined) {
|
|
126
|
-
const toolId = streamingState.blockIndexToToolId.get(e.index);
|
|
127
|
-
if (toolId) {
|
|
128
|
-
const tc = streamingState.toolCalls.get(toolId);
|
|
129
|
-
if (tc) tc.arguments += e.partial_json;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Initialize buffer for a new streaming message.
|
|
137
|
-
* When called with the same ID as the current message (flush cycle),
|
|
138
|
-
* only the content/thinking strings are reset — tool calls are preserved
|
|
139
|
-
* so arg accumulation survives mid-stream flushes.
|
|
140
|
-
*/
|
|
141
|
-
export function initStreamingBuffer(messageId: string): void {
|
|
142
|
-
const isNewMessage = streamingState.messageId !== messageId;
|
|
143
|
-
streamingState.messageId = messageId;
|
|
144
|
-
streamingState.content = '';
|
|
145
|
-
streamingState.thinking = '';
|
|
146
|
-
streamingState.currentBlockType = null;
|
|
147
|
-
streamingState.currentBlockAccumulator = '';
|
|
148
|
-
if (isNewMessage) {
|
|
149
|
-
streamingState.toolCalls.clear();
|
|
150
|
-
streamingState.transcriptBuffer.clear();
|
|
151
|
-
streamingState.blockIndexToToolId.clear();
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Append content delta to the mutable buffer (NO store update).
|
|
157
|
-
* Tracks as 'text' content block if we're in a text block.
|
|
158
|
-
*/
|
|
159
|
-
/**
|
|
160
|
-
* Get the time (ms) since the last content was written to the buffer.
|
|
161
|
-
* Returns 0 if no streaming is active.
|
|
162
|
-
*/
|
|
163
|
-
export function getStreamingLatencyMs(): number {
|
|
164
|
-
if (!streamingState.messageId || streamingState.lastWriteTimestamp === 0) return 0;
|
|
165
|
-
return Date.now() - streamingState.lastWriteTimestamp;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export function appendToBuffer(contentDelta: string): void {
|
|
169
|
-
streamingState.content += contentDelta;
|
|
170
|
-
streamingState.lastWriteTimestamp = Date.now();
|
|
171
|
-
// Track as text block
|
|
172
|
-
streamingState.currentBlockType = 'text';
|
|
173
|
-
streamingState.currentBlockAccumulator += contentDelta;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Append thinking delta to the mutable buffer (NO store update).
|
|
178
|
-
* Tracks as 'thinking' content block.
|
|
179
|
-
*/
|
|
180
|
-
export function appendThinkingToBuffer(thinkingDelta: string): void {
|
|
181
|
-
streamingState.thinking += thinkingDelta;
|
|
182
|
-
streamingState.lastWriteTimestamp = Date.now();
|
|
183
|
-
streamingState.currentBlockType = 'thinking';
|
|
184
|
-
streamingState.currentBlockAccumulator += thinkingDelta;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Signal the start of a tool_use block. Records the tool call ID and name.
|
|
189
|
-
*/
|
|
190
|
-
export function startToolCallInBuffer(toolCallId: string, name: string): void {
|
|
191
|
-
streamingState.toolCalls.set(toolCallId, { name, arguments: '', status: 'running' });
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Accumulate tool call arguments JSON delta.
|
|
196
|
-
*/
|
|
197
|
-
export function appendToolCallDelta(toolCallId: string, argumentsDelta: string): void {
|
|
198
|
-
const existing = streamingState.toolCalls.get(toolCallId);
|
|
199
|
-
if (existing) {
|
|
200
|
-
existing.arguments += argumentsDelta;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Mark a tool call as completed (success or error).
|
|
206
|
-
*/
|
|
207
|
-
export function finishToolCallInBuffer(toolCallId: string, isError: boolean): void {
|
|
208
|
-
const existing = streamingState.toolCalls.get(toolCallId);
|
|
209
|
-
if (existing) {
|
|
210
|
-
existing.status = isError ? 'error' : 'success';
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Get tool calls accumulated in the buffer.
|
|
216
|
-
*/
|
|
217
|
-
export function getBufferedToolCalls(): Array<{ id: string; name: string; arguments: string; status: ToolCallStatus }> {
|
|
218
|
-
return Array.from(streamingState.toolCalls.entries()).map(([id, tc]) => ({
|
|
219
|
-
id,
|
|
220
|
-
...tc,
|
|
221
|
-
}));
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Clear the buffer (e.g., on error/abort or after finishStreamingMessage).
|
|
226
|
-
*/
|
|
227
|
-
export function clearBuffer(): void {
|
|
228
|
-
streamingState.messageId = null;
|
|
229
|
-
streamingState.content = '';
|
|
230
|
-
streamingState.thinking = '';
|
|
231
|
-
streamingState.currentBlockType = null;
|
|
232
|
-
streamingState.currentBlockAccumulator = '';
|
|
233
|
-
streamingState.toolCalls.clear();
|
|
234
|
-
streamingState.transcriptBuffer.clear();
|
|
235
|
-
streamingState.blockIndexToToolId.clear();
|
|
236
|
-
streamingState.lastWriteTimestamp = 0;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Check if buffer has content.
|
|
241
|
-
*/
|
|
242
|
-
export function hasBufferContent(): boolean {
|
|
243
|
-
return streamingState.content.length > 0 || streamingState.thinking.length > 0 || streamingState.toolCalls.size > 0;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Peek at current content without clearing.
|
|
248
|
-
*/
|
|
249
|
-
export function peekBuffer(): { content: string; thinking: string; currentBlockType: string | null; currentBlockContent: string; toolCalls: Array<{ id: string; name: string; arguments: string; status: ToolCallStatus }> } {
|
|
250
|
-
return {
|
|
251
|
-
content: streamingState.content,
|
|
252
|
-
thinking: streamingState.thinking,
|
|
253
|
-
currentBlockType: streamingState.currentBlockType,
|
|
254
|
-
currentBlockContent: streamingState.currentBlockAccumulator,
|
|
255
|
-
toolCalls: getBufferedToolCalls(),
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Drain accumulated content block from the buffer.
|
|
261
|
-
* Returns the block data and resets the accumulator.
|
|
262
|
-
*/
|
|
263
|
-
export function drainContentBlock(): { type: 'text' | 'thinking'; content: string } | null {
|
|
264
|
-
if (!streamingState.currentBlockType || !streamingState.currentBlockAccumulator) {
|
|
265
|
-
return null;
|
|
266
|
-
}
|
|
267
|
-
const block = {
|
|
268
|
-
type: streamingState.currentBlockType as 'text' | 'thinking',
|
|
269
|
-
content: streamingState.currentBlockAccumulator,
|
|
270
|
-
};
|
|
271
|
-
streamingState.currentBlockType = null;
|
|
272
|
-
streamingState.currentBlockAccumulator = '';
|
|
273
|
-
return block;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Drain tool calls from the buffer.
|
|
278
|
-
*/
|
|
279
|
-
export function drainToolCalls(): Array<{ id: string; name: string; arguments: string; status: ToolCallStatus }> {
|
|
280
|
-
const calls = getBufferedToolCalls();
|
|
281
|
-
streamingState.toolCalls.clear();
|
|
282
|
-
return calls;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Drain ALL content from the buffer and return it.
|
|
287
|
-
* Clears the buffer entirely. Used by flushStreamBuffer and finishStreamingMessage.
|
|
288
|
-
*
|
|
289
|
-
* This is the SINGLE function that removes content from the buffer.
|
|
290
|
-
* After calling it, the buffer is empty and ready for new content.
|
|
291
|
-
*
|
|
292
|
-
* Returns null if buffer is empty (no messageId set or no content).
|
|
293
|
-
*/
|
|
294
|
-
export function drainBuffer(): { content: string; thinking: string; toolCalls: Array<{ id: string; name: string; arguments: string; status: ToolCallStatus }> } | null {
|
|
295
|
-
if (!streamingState.messageId) return null;
|
|
296
|
-
if (!streamingState.content && !streamingState.thinking && streamingState.toolCalls.size === 0) return null;
|
|
297
|
-
|
|
298
|
-
const result = {
|
|
299
|
-
content: streamingState.content,
|
|
300
|
-
thinking: streamingState.thinking,
|
|
301
|
-
toolCalls: getBufferedToolCalls(),
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
// Clear content but KEEP messageId (so isActiveStreamingMessage still works)
|
|
305
|
-
// and KEEP toolCalls (they're still in-flight; cleared by clearBuffer after finish).
|
|
306
|
-
streamingState.content = '';
|
|
307
|
-
streamingState.thinking = '';
|
|
308
|
-
streamingState.currentBlockType = null;
|
|
309
|
-
streamingState.currentBlockAccumulator = '';
|
|
310
|
-
|
|
311
|
-
return result;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// ==================== Batch Buffer for Slash Commands ====================
|
|
315
|
-
// Slash commands trigger multiple store updates (addUserMessage, setThinking, addAssistantMessage).
|
|
316
|
-
// Instead of each calling set() individually (causing cascading re-renders), we batch them:
|
|
317
|
-
// 1. Collect all mutations in a pending batch object
|
|
318
|
-
// 2. flushBatch() applies them as a single set() call
|
|
319
|
-
//
|
|
320
|
-
// The MessageList subscription already detects message count changes (see MessageList.tsx:128-133),
|
|
321
|
-
// so a single batch flush triggers exactly ONE re-render for the entire slash command result.
|
|
322
|
-
|
|
323
|
-
interface BatchUpdate {
|
|
324
|
-
userMessage?: string;
|
|
325
|
-
assistantMessage?: string;
|
|
326
|
-
isThinking?: boolean;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
let pendingBatch: BatchUpdate | null = null;
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* Start collecting mutations into a batch.
|
|
333
|
-
*/
|
|
334
|
-
export function startBatch(): void {
|
|
335
|
-
pendingBatch = {};
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Queue a user message in the current batch.
|
|
340
|
-
*/
|
|
341
|
-
export function batchAddUserMessage(content: string): void {
|
|
342
|
-
if (pendingBatch) {
|
|
343
|
-
pendingBatch.userMessage = content;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Queue an assistant message in the current batch.
|
|
349
|
-
*/
|
|
350
|
-
export function batchAddAssistantMessage(content: string): void {
|
|
351
|
-
if (pendingBatch) {
|
|
352
|
-
pendingBatch.assistantMessage = content;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Queue a thinking state change in the current batch.
|
|
358
|
-
*/
|
|
359
|
-
export function batchSetThinking(isThinking: boolean): void {
|
|
360
|
-
if (pendingBatch) {
|
|
361
|
-
pendingBatch.isThinking = isThinking;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Flush the batch: apply all queued mutations as a single set() call.
|
|
367
|
-
* Accepts the store instance to avoid circular dependencies in ESM.
|
|
368
|
-
*
|
|
369
|
-
* Returns true if any mutations were applied.
|
|
370
|
-
*
|
|
371
|
-
* This is equivalent to calling:
|
|
372
|
-
* sessionActions().addUserMessage(...) + sessionActions().addAssistantMessage(...) + sessionActions().setThinking(...)
|
|
373
|
-
* but done as a SINGLE setState call, eliminating cascading re-renders.
|
|
374
|
-
*/
|
|
375
|
-
export function flushBatchWithStore(store: any): boolean {
|
|
376
|
-
if (!pendingBatch) return false;
|
|
377
|
-
const batch = pendingBatch;
|
|
378
|
-
pendingBatch = null;
|
|
379
|
-
|
|
380
|
-
const hasUser = batch.userMessage !== undefined;
|
|
381
|
-
const hasAssistant = batch.assistantMessage !== undefined;
|
|
382
|
-
const hasThinking = batch.isThinking !== undefined;
|
|
383
|
-
|
|
384
|
-
if (!hasUser && !hasAssistant && !hasThinking) return false;
|
|
385
|
-
|
|
386
|
-
const current = store.getState().session;
|
|
387
|
-
const newMessages = [...current.messages];
|
|
388
|
-
const generateId = () => `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
389
|
-
|
|
390
|
-
if (hasUser && batch.userMessage) {
|
|
391
|
-
newMessages.push({
|
|
392
|
-
id: `user-${generateId()}`,
|
|
393
|
-
role: 'user' as const,
|
|
394
|
-
content: batch.userMessage,
|
|
395
|
-
timestamp: Date.now(),
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
if (hasAssistant && batch.assistantMessage) {
|
|
400
|
-
newMessages.push({
|
|
401
|
-
id: `assistant-${generateId()}`,
|
|
402
|
-
role: 'assistant' as const,
|
|
403
|
-
content: batch.assistantMessage,
|
|
404
|
-
timestamp: Date.now(),
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
const update: any = { messages: newMessages };
|
|
409
|
-
if (hasThinking) {
|
|
410
|
-
update.isThinking = batch.isThinking;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
store.setState((s: any) => ({
|
|
414
|
-
session: { ...s.session, ...update },
|
|
415
|
-
}));
|
|
416
|
-
|
|
417
|
-
return true;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Cancel the current batch (e.g., on error before flush).
|
|
422
|
-
*/
|
|
423
|
-
export function cancelBatch(): void {
|
|
424
|
-
pendingBatch = null;
|
|
425
|
-
}
|