mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-06 02:41:48 +00:00
fix(tui): stabilize live todo progress
This commit is contained in:
parent
1566f1eecc
commit
f5552f92e2
14 changed files with 256 additions and 86 deletions
|
|
@ -28,10 +28,6 @@ const TranscriptPane = memo(function TranscriptPane({
|
|||
|
||||
return (
|
||||
<>
|
||||
<Box flexDirection="column" flexShrink={0}>
|
||||
<LiveTodoPanel />
|
||||
</Box>
|
||||
|
||||
<ScrollBox flexDirection="column" flexGrow={1} flexShrink={1} ref={transcript.scrollRef} stickyScroll>
|
||||
<Box flexDirection="column" paddingX={1}>
|
||||
{transcript.virtualHistory.topSpacer > 0 ? <Box height={transcript.virtualHistory.topSpacer} /> : null}
|
||||
|
|
@ -73,6 +69,10 @@ const TranscriptPane = memo(function TranscriptPane({
|
|||
</Box>
|
||||
</ScrollBox>
|
||||
|
||||
<Box flexDirection="column" flexShrink={0} paddingX={1}>
|
||||
<LiveTodoPanel />
|
||||
</Box>
|
||||
|
||||
<NoSelect flexShrink={0} marginLeft={1}>
|
||||
<TranscriptScrollbar scrollRef={transcript.scrollRef} t={ui.theme} />
|
||||
</NoSelect>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import type { Theme } from '../theme.js'
|
|||
import type { ActiveTool, DetailsMode, Msg, SectionVisibility } from '../types.js'
|
||||
|
||||
import { Md } from './markdown.js'
|
||||
import { TodoPanel } from './todoPanel.js'
|
||||
import { ToolTrail } from './thinking.js'
|
||||
|
||||
export const MessageLine = memo(function MessageLine({
|
||||
|
|
@ -35,6 +36,10 @@ export const MessageLine = memo(function MessageLine({
|
|||
const activityMode = sectionMode('activity', detailsMode, sections, detailsModeCommandOverride)
|
||||
const thinking = msg.thinking?.trim() ?? ''
|
||||
|
||||
if (msg.kind === 'trail' && msg.todos?.length) {
|
||||
return <TodoPanel t={t} todos={msg.todos} />
|
||||
}
|
||||
|
||||
if (msg.kind === 'trail' && (msg.tools?.length || tools.length || thinking)) {
|
||||
return thinkingMode !== 'hidden' || toolsMode !== 'hidden' || activityMode !== 'hidden' ? (
|
||||
<Box flexDirection="column">
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useStore } from '@nanostores/react'
|
|||
import { memo } from 'react'
|
||||
|
||||
import type { AppLayoutProgressProps } from '../app/interfaces.js'
|
||||
import { useTurnSelector } from '../app/turnStore.js'
|
||||
import { toggleTodoCollapsed, useTurnSelector } from '../app/turnStore.js'
|
||||
import { $uiState } from '../app/uiStore.js'
|
||||
import type { DetailsMode, Msg, SectionVisibility } from '../types.js'
|
||||
|
||||
|
|
@ -105,8 +105,9 @@ export const StreamingAssistant = memo(function StreamingAssistant({
|
|||
export const LiveTodoPanel = memo(function LiveTodoPanel() {
|
||||
const ui = useStore($uiState)
|
||||
const todos = useTurnSelector(state => state.todos)
|
||||
const collapsed = useTurnSelector(state => state.todoCollapsed)
|
||||
|
||||
return <TodoPanel t={ui.theme} todos={todos} />
|
||||
return <TodoPanel collapsed={collapsed} onToggle={toggleTodoCollapsed} t={ui.theme} todos={todos} />
|
||||
})
|
||||
|
||||
interface StreamingAssistantProps {
|
||||
|
|
|
|||
|
|
@ -11,35 +11,52 @@ const rowColor = (t: Theme, status: TodoItem['status']) => {
|
|||
return tone === 'active' ? t.color.cornsilk : tone === 'body' ? t.color.statusFg : t.color.dim
|
||||
}
|
||||
|
||||
export const TodoPanel = memo(function TodoPanel({ t, todos }: { t: Theme; todos: TodoItem[] }) {
|
||||
export const TodoPanel = memo(function TodoPanel({
|
||||
collapsed = false,
|
||||
onToggle,
|
||||
t,
|
||||
todos
|
||||
}: {
|
||||
collapsed?: boolean
|
||||
onToggle?: () => void
|
||||
t: Theme
|
||||
todos: TodoItem[]
|
||||
}) {
|
||||
if (!todos.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
const done = todos.filter(todo => todo.status === 'completed').length
|
||||
|
||||
return (
|
||||
<Box flexDirection="column" marginBottom={1}>
|
||||
<Text color={t.color.dim}>
|
||||
<Text color={t.color.amber}>▾ </Text>
|
||||
<Text bold color={t.color.cornsilk}>
|
||||
Todo
|
||||
</Text>{' '}
|
||||
<Text color={t.color.statusFg} dim>
|
||||
({todos.filter(todo => todo.status === 'completed').length}/{todos.length})
|
||||
<Box onClick={onToggle}>
|
||||
<Text color={t.color.dim}>
|
||||
<Text color={t.color.amber}>{collapsed ? '▸ ' : '▾ '}</Text>
|
||||
<Text bold color={t.color.cornsilk}>
|
||||
Todo
|
||||
</Text>{' '}
|
||||
<Text color={t.color.statusFg} dim>
|
||||
({done}/{todos.length})
|
||||
</Text>
|
||||
</Text>
|
||||
</Text>
|
||||
<Box flexDirection="column" marginLeft={2}>
|
||||
{todos.map(todo => {
|
||||
const tone = todoTone(todo.status)
|
||||
const color = rowColor(t, todo.status)
|
||||
|
||||
return (
|
||||
<Text color={color} dim={tone === 'dim'} key={todo.id}>
|
||||
<Text color={color}>{todoGlyph(todo.status)} </Text>
|
||||
{todo.content}
|
||||
</Text>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
|
||||
{!collapsed && (
|
||||
<Box flexDirection="column" marginLeft={2}>
|
||||
{todos.map(todo => {
|
||||
const tone = todoTone(todo.status)
|
||||
const color = rowColor(t, todo.status)
|
||||
|
||||
return (
|
||||
<Text color={color} dim={tone === 'dim'} key={todo.id}>
|
||||
<Text color={color}>{todoGlyph(todo.status)} </Text>
|
||||
{todo.content}
|
||||
</Text>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue