mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-21 09:17:53 +00:00
feat: add loading for summary
This commit is contained in:
@@ -20,7 +20,11 @@ import {
|
||||
getProjectSummaryPrompt,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
import path from 'path';
|
||||
import { HistoryItemWithoutId, MessageType } from '../types.js';
|
||||
import {
|
||||
HistoryItemWithoutId,
|
||||
HistoryItemSummary,
|
||||
MessageType,
|
||||
} from '../types.js';
|
||||
|
||||
interface ChatDetail {
|
||||
name: string;
|
||||
@@ -331,9 +335,12 @@ const summaryCommand: SlashCommand = {
|
||||
}
|
||||
|
||||
// Show loading state
|
||||
const pendingMessage = {
|
||||
type: 'info' as const,
|
||||
text: '🔄 Generating project summary...',
|
||||
const pendingMessage: HistoryItemSummary = {
|
||||
type: 'summary',
|
||||
summary: {
|
||||
isPending: true,
|
||||
stage: 'generating',
|
||||
},
|
||||
};
|
||||
ui.setPendingItem(pendingMessage);
|
||||
|
||||
@@ -377,8 +384,11 @@ const summaryCommand: SlashCommand = {
|
||||
|
||||
// Update loading message to show saving progress
|
||||
ui.setPendingItem({
|
||||
type: 'info' as const,
|
||||
text: '💾 Saving project summary...',
|
||||
type: 'summary',
|
||||
summary: {
|
||||
isPending: true,
|
||||
stage: 'saving',
|
||||
},
|
||||
});
|
||||
|
||||
// Ensure .qwen directory exists
|
||||
@@ -404,13 +414,14 @@ const summaryCommand: SlashCommand = {
|
||||
|
||||
// Clear pending item and show success message
|
||||
ui.setPendingItem(null);
|
||||
ui.addItem(
|
||||
{
|
||||
type: 'info' as const,
|
||||
text: '✅ Project summary generated and saved to .qwen/PROJECT_SUMMARY.md',
|
||||
const completedSummaryItem: HistoryItemSummary = {
|
||||
type: 'summary',
|
||||
summary: {
|
||||
isPending: false,
|
||||
stage: 'completed',
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
};
|
||||
ui.addItem(completedSummaryItem, Date.now());
|
||||
|
||||
return {
|
||||
type: 'message',
|
||||
|
||||
@@ -14,6 +14,7 @@ import { ErrorMessage } from './messages/ErrorMessage.js';
|
||||
import { ToolGroupMessage } from './messages/ToolGroupMessage.js';
|
||||
import { GeminiMessageContent } from './messages/GeminiMessageContent.js';
|
||||
import { CompressionMessage } from './messages/CompressionMessage.js';
|
||||
import { SummaryMessage } from './messages/SummaryMessage.js';
|
||||
import { Box } from 'ink';
|
||||
import { AboutBox } from './AboutBox.js';
|
||||
import { StatsDisplay } from './StatsDisplay.js';
|
||||
@@ -97,5 +98,6 @@ export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({
|
||||
{item.type === 'compression' && (
|
||||
<CompressionMessage compression={item.compression} />
|
||||
)}
|
||||
{item.type === 'summary' && <SummaryMessage summary={item.summary} />}
|
||||
</Box>
|
||||
);
|
||||
|
||||
55
packages/cli/src/ui/components/messages/SummaryMessage.tsx
Normal file
55
packages/cli/src/ui/components/messages/SummaryMessage.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import { SummaryProps } from '../../types.js';
|
||||
import Spinner from 'ink-spinner';
|
||||
import { Colors } from '../../colors.js';
|
||||
|
||||
export interface SummaryDisplayProps {
|
||||
summary: SummaryProps;
|
||||
}
|
||||
|
||||
/*
|
||||
* Summary messages appear when the /chat summary command is run, and show a loading spinner
|
||||
* while summary generation is in progress, followed up by success confirmation.
|
||||
*/
|
||||
export const SummaryMessage: React.FC<SummaryDisplayProps> = ({ summary }) => {
|
||||
const getText = () => {
|
||||
if (summary.isPending) {
|
||||
switch (summary.stage) {
|
||||
case 'generating':
|
||||
return 'Generating project summary...';
|
||||
case 'saving':
|
||||
return 'Saving project summary...';
|
||||
default:
|
||||
return 'Processing summary...';
|
||||
}
|
||||
}
|
||||
return 'Project summary generated and saved successfully!';
|
||||
};
|
||||
|
||||
const getIcon = () => {
|
||||
if (summary.isPending) {
|
||||
return <Spinner type="dots" />;
|
||||
}
|
||||
return <Text color={Colors.AccentGreen}>✅</Text>;
|
||||
};
|
||||
|
||||
return (
|
||||
<Box flexDirection="row">
|
||||
<Box marginRight={1}>{getIcon()}</Box>
|
||||
<Box>
|
||||
<Text
|
||||
color={summary.isPending ? Colors.AccentPurple : Colors.AccentGreen}
|
||||
>
|
||||
{getText()}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -157,6 +157,11 @@ export const useSlashCommandProcessor = (
|
||||
type: 'compression',
|
||||
compression: message.compression,
|
||||
};
|
||||
} else if (message.type === MessageType.SUMMARY) {
|
||||
historyItemContent = {
|
||||
type: 'summary',
|
||||
summary: message.summary,
|
||||
};
|
||||
} else {
|
||||
historyItemContent = {
|
||||
type: message.type,
|
||||
|
||||
@@ -58,6 +58,11 @@ export interface CompressionProps {
|
||||
newTokenCount: number | null;
|
||||
}
|
||||
|
||||
export interface SummaryProps {
|
||||
isPending: boolean;
|
||||
stage: 'generating' | 'saving' | 'completed';
|
||||
}
|
||||
|
||||
export interface HistoryItemBase {
|
||||
text?: string; // Text content for user/gemini/info/error messages
|
||||
}
|
||||
@@ -141,6 +146,11 @@ export type HistoryItemCompression = HistoryItemBase & {
|
||||
compression: CompressionProps;
|
||||
};
|
||||
|
||||
export type HistoryItemSummary = HistoryItemBase & {
|
||||
type: 'summary';
|
||||
summary: SummaryProps;
|
||||
};
|
||||
|
||||
// Using Omit<HistoryItem, 'id'> seems to have some issues with typescript's
|
||||
// type inference e.g. historyItem.type === 'tool_group' isn't auto-inferring that
|
||||
// 'tools' in historyItem.
|
||||
@@ -160,7 +170,8 @@ export type HistoryItemWithoutId =
|
||||
| HistoryItemToolStats
|
||||
| HistoryItemQuit
|
||||
| HistoryItemQuitConfirmation
|
||||
| HistoryItemCompression;
|
||||
| HistoryItemCompression
|
||||
| HistoryItemSummary;
|
||||
|
||||
export type HistoryItem = HistoryItemWithoutId & { id: number };
|
||||
|
||||
@@ -178,6 +189,7 @@ export enum MessageType {
|
||||
QUIT_CONFIRMATION = 'quit_confirmation',
|
||||
GEMINI = 'gemini',
|
||||
COMPRESSION = 'compression',
|
||||
SUMMARY = 'summary',
|
||||
}
|
||||
|
||||
// Simplified message structure for internal feedback
|
||||
@@ -236,6 +248,11 @@ export type Message =
|
||||
type: MessageType.COMPRESSION;
|
||||
compression: CompressionProps;
|
||||
timestamp: Date;
|
||||
}
|
||||
| {
|
||||
type: MessageType.SUMMARY;
|
||||
summary: SummaryProps;
|
||||
timestamp: Date;
|
||||
};
|
||||
|
||||
export interface ConsoleMessageItem {
|
||||
|
||||
Reference in New Issue
Block a user