Improve TUI timestamp consistency and formatting
This commit is contained in:
@@ -78,10 +78,19 @@ export function App({
|
|||||||
onTransfer,
|
onTransfer,
|
||||||
onExit,
|
onExit,
|
||||||
}: AppProps): React.ReactElement {
|
}: AppProps): React.ReactElement {
|
||||||
|
const ensureTimestamp = useCallback((message: Message): Message => ({
|
||||||
|
...message,
|
||||||
|
timestamp: message.timestamp ?? Date.now(),
|
||||||
|
}), []);
|
||||||
|
|
||||||
|
const ensureTimestamps = useCallback((history: Message[]): Message[] => (
|
||||||
|
history.map(ensureTimestamp)
|
||||||
|
), [ensureTimestamp]);
|
||||||
|
|
||||||
const ctrlCExitWindowMs = 1_500;
|
const ctrlCExitWindowMs = 1_500;
|
||||||
const { exit } = useApp();
|
const { exit } = useApp();
|
||||||
const [input, setInput] = useState('');
|
const [input, setInput] = useState('');
|
||||||
const [messages, setMessages] = useState<Message[]>(session.getHistory());
|
const [messages, setMessages] = useState<Message[]>(ensureTimestamps(session.getHistory()));
|
||||||
const [isStreaming, setIsStreaming] = useState(false);
|
const [isStreaming, setIsStreaming] = useState(false);
|
||||||
const [streamingContent, setStreamingContent] = useState('');
|
const [streamingContent, setStreamingContent] = useState('');
|
||||||
const [scrollOffset, setScrollOffset] = useState(0);
|
const [scrollOffset, setScrollOffset] = useState(0);
|
||||||
@@ -682,7 +691,7 @@ export function App({
|
|||||||
const messageWithTimestamp = session.addMessage(userMessage);
|
const messageWithTimestamp = session.addMessage(userMessage);
|
||||||
setMessages(prev => [...prev, messageWithTimestamp]);
|
setMessages(prev => [...prev, messageWithTimestamp]);
|
||||||
} else {
|
} else {
|
||||||
setMessages(prev => [...prev, { ...userMessage, timestamp: Date.now() }]);
|
setMessages(prev => [...prev, ensureTimestamp(userMessage)]);
|
||||||
}
|
}
|
||||||
setScrollOffset(0);
|
setScrollOffset(0);
|
||||||
|
|
||||||
@@ -696,7 +705,7 @@ export function App({
|
|||||||
await agent.process(command.content);
|
await agent.process(command.content);
|
||||||
const usage = agent.getUsage();
|
const usage = agent.getUsage();
|
||||||
setTokenUsage({ inputTokens: usage.inputTokens, outputTokens: usage.outputTokens });
|
setTokenUsage({ inputTokens: usage.inputTokens, outputTokens: usage.outputTokens });
|
||||||
setMessages(session.getHistory());
|
setMessages(ensureTimestamps(session.getHistory()));
|
||||||
} else if (modelClient.chatStream) {
|
} else if (modelClient.chatStream) {
|
||||||
let fullContent = '';
|
let fullContent = '';
|
||||||
|
|
||||||
@@ -757,6 +766,8 @@ export function App({
|
|||||||
exit,
|
exit,
|
||||||
onExit,
|
onExit,
|
||||||
isStreaming,
|
isStreaming,
|
||||||
|
ensureTimestamp,
|
||||||
|
ensureTimestamps,
|
||||||
messages.length,
|
messages.length,
|
||||||
tokenUsage.inputTokens,
|
tokenUsage.inputTokens,
|
||||||
tokenUsage.outputTokens,
|
tokenUsage.outputTokens,
|
||||||
|
|||||||
@@ -13,16 +13,12 @@ export interface MessageListProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper to format timestamp in human-readable way
|
// Helper to format timestamp in human-readable way
|
||||||
function formatTimestamp(timestamp: number): string {
|
function formatTimestampParts(timestamp: number): { date: string; time: string } {
|
||||||
const date = new Date(timestamp);
|
const date = new Date(timestamp);
|
||||||
const now = new Date();
|
return {
|
||||||
const isSameDay = date.toDateString() === now.toDateString();
|
date: date.toLocaleDateString([], { month: 'short', day: 'numeric', year: 'numeric' }),
|
||||||
|
time: date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
||||||
if (isSameDay) {
|
};
|
||||||
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
||||||
}
|
|
||||||
|
|
||||||
return date.toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Individual message component
|
// Individual message component
|
||||||
@@ -35,7 +31,7 @@ const MessageItem = memo(function MessageItem({
|
|||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
const isUser = message.role === 'user';
|
const isUser = message.role === 'user';
|
||||||
const accentColor = isUser ? 'blue' : '#ff8c00';
|
const accentColor = isUser ? 'blue' : '#ff8c00';
|
||||||
const timestampText = message.timestamp ? formatTimestamp(message.timestamp) : 'unknown time';
|
const timestamp = formatTimestampParts(message.timestamp ?? Date.now());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@@ -55,7 +51,7 @@ const MessageItem = memo(function MessageItem({
|
|||||||
<Text color={accentColor} bold>
|
<Text color={accentColor} bold>
|
||||||
{isUser ? 'You' : 'Flynn'}
|
{isUser ? 'You' : 'Flynn'}
|
||||||
</Text>
|
</Text>
|
||||||
<Text color="gray">| {timestampText}</Text>
|
<Text color="gray">| {timestamp.date} | {timestamp.time}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
|
|||||||
@@ -48,12 +48,16 @@ export function formatPrompt(state: 'default' | 'thinking'): string {
|
|||||||
return `${colors.orange}${colors.bold}flynn>${colors.reset} `;
|
return `${colors.orange}${colors.bold}flynn>${colors.reset} `;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatMessageTime(timestamp: number): string {
|
function formatMessageTimestampParts(timestamp: number): { date: string; time: string } {
|
||||||
return new Date(timestamp).toLocaleTimeString([], {
|
const date = new Date(timestamp);
|
||||||
hour: '2-digit',
|
return {
|
||||||
minute: '2-digit',
|
date: date.toLocaleDateString([], { month: 'short', day: 'numeric', year: 'numeric' }),
|
||||||
second: '2-digit',
|
time: date.toLocaleTimeString([], {
|
||||||
});
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
}),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MinimalTuiConfig {
|
export interface MinimalTuiConfig {
|
||||||
@@ -1237,9 +1241,16 @@ export class MinimalTui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async handleMessage(content: string): Promise<void> {
|
private async handleMessage(content: string): Promise<void> {
|
||||||
|
const userTimestamp = formatMessageTimestampParts(Date.now());
|
||||||
|
process.stdout.write(
|
||||||
|
`\n${colors.blue}${colors.bold}You${colors.reset} ${colors.gray}[${userTimestamp.date} | ${userTimestamp.time}]${colors.reset}\n`,
|
||||||
|
);
|
||||||
|
process.stdout.write(`${content}\n`);
|
||||||
|
|
||||||
|
const assistantTimestamp = formatMessageTimestampParts(Date.now());
|
||||||
// Print Flynn label before response
|
// Print Flynn label before response
|
||||||
process.stdout.write(
|
process.stdout.write(
|
||||||
`\n${colors.orange}${colors.bold}Flynn${colors.reset} ${colors.gray}[${formatMessageTime(Date.now())}]${colors.reset}\n`,
|
`\n${colors.orange}${colors.bold}Flynn${colors.reset} ${colors.gray}[${assistantTimestamp.date} | ${assistantTimestamp.time}]${colors.reset}\n`,
|
||||||
);
|
);
|
||||||
this.startBusyIndicator();
|
this.startBusyIndicator();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user