feat(vscode-ide-companion): add cancel streaming functionality

- Add handleCancel callback to App component
- Implement cancelStreaming message posting to VS Code
- Add onCancel prop to InputForm component
- Replace send button with stop button during streaming
This commit is contained in:
yiliang114
2025-12-04 01:53:19 +08:00
parent 35f98723ca
commit e3c456a430
27 changed files with 730 additions and 286 deletions

View File

@@ -27,7 +27,7 @@ import type { ToolCallData } from './components/ToolCall.js';
import { PermissionDrawer } from './components/PermissionDrawer.js';
import { ToolCall } from './components/ToolCall.js';
import { hasToolCallOutput } from './components/toolcalls/shared/utils.js';
import { InProgressToolCall } from './components/InProgressToolCall.js';
// import { InProgressToolCall } from './components/InProgressToolCall.js';
import { EmptyState } from './components/ui/EmptyState.js';
import type { PlanEntry } from './components/PlanDisplay.js';
import { type CompletionItem } from './types/CompletionTypes.js';
@@ -172,6 +172,16 @@ export const App: React.FC = () => {
isStreaming: messageHandling.isStreaming,
});
// Handle cancel streaming
const handleCancel = useCallback(() => {
if (messageHandling.isStreaming) {
vscode.postMessage({
type: 'cancelStreaming',
data: {},
});
}
}, [messageHandling.isStreaming, vscode]);
// Message handling
useWebViewMessages({
sessionManagement,
@@ -531,49 +541,47 @@ export const App: React.FC = () => {
if (msg.role === 'thinking') {
return (
<div key={`message-${index}`} className="message-item">
<ThinkingMessage
content={msg.content || ''}
timestamp={msg.timestamp || 0}
onFileClick={handleFileClick}
/>
</div>
<ThinkingMessage
key={`message-${index}`}
content={msg.content || ''}
timestamp={msg.timestamp || 0}
onFileClick={handleFileClick}
/>
);
}
if (msg.role === 'user') {
return (
<div key={`message-${index}`} className="message-item">
<UserMessage
content={msg.content || ''}
timestamp={msg.timestamp || 0}
onFileClick={handleFileClick}
fileContext={msg.fileContext}
/>
</div>
<UserMessage
key={`message-${index}`}
content={msg.content || ''}
timestamp={msg.timestamp || 0}
onFileClick={handleFileClick}
fileContext={msg.fileContext}
/>
);
}
return (
<div key={`message-${index}`} className="message-item">
<AssistantMessage
content={msg.content || ''}
timestamp={msg.timestamp || 0}
onFileClick={handleFileClick}
/>
</div>
<AssistantMessage
key={`message-${index}`}
content={msg.content || ''}
timestamp={msg.timestamp || 0}
onFileClick={handleFileClick}
/>
);
}
case 'in-progress-tool-call':
return (
<InProgressToolCall
key={`in-progress-${(item.data as ToolCallData).toolCallId}`}
toolCall={item.data as ToolCallData}
// onFileClick={handleFileClick}
/>
);
// case 'in-progress-tool-call':
// return (
// <InProgressToolCall
// key={`in-progress-${(item.data as ToolCallData).toolCallId}`}
// toolCall={item.data as ToolCallData}
// // onFileClick={handleFileClick}
// />
// );
case 'in-progress-tool-call':
case 'completed-tool-call':
return (
<ToolCall
@@ -626,6 +634,7 @@ export const App: React.FC = () => {
onCompositionEnd={() => setIsComposing(false)}
onKeyDown={() => {}}
onSubmit={handleSubmit.handleSubmit}
onCancel={handleCancel}
onToggleEditMode={handleToggleEditMode}
onToggleThinking={handleToggleThinking}
onFocusActiveEditor={fileContext.focusActiveEditor}