feat: better tool parsing ui
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import { atom } from 'nanostores'
|
||||
|
||||
import { sessionTitle } from '@/lib/chat-runtime'
|
||||
import type { PreviewServerRestart } from '@/store/preview'
|
||||
import type { ActionStatusResponse, SessionInfo } from '@/types/hermes'
|
||||
|
||||
const HISTORY_LIMIT = 8
|
||||
const COMPLETED_TTL_MS = 5 * 60 * 1000
|
||||
|
||||
export type RailTaskStatus = 'error' | 'running' | 'success'
|
||||
|
||||
export interface RailTask {
|
||||
id: string
|
||||
label: string
|
||||
detail: string
|
||||
status: RailTaskStatus
|
||||
updatedAt: number
|
||||
}
|
||||
|
||||
export interface DesktopActionTask {
|
||||
status: ActionStatusResponse
|
||||
updatedAt: number
|
||||
}
|
||||
|
||||
export const $desktopActionTasks = atom<Record<string, DesktopActionTask>>({})
|
||||
|
||||
export function upsertDesktopActionTask(status: ActionStatusResponse): void {
|
||||
$desktopActionTasks.set(prune({ ...$desktopActionTasks.get(), [status.name]: { status, updatedAt: Date.now() } }))
|
||||
}
|
||||
|
||||
export function buildRailTasks(
|
||||
workingSessionIds: readonly string[],
|
||||
sessions: readonly SessionInfo[],
|
||||
previewRestart: PreviewServerRestart | null,
|
||||
actionTasks: Record<string, DesktopActionTask>
|
||||
): RailTask[] {
|
||||
const sessionsById = new Map(sessions.map(session => [session.id, session]))
|
||||
|
||||
const sessionTasks: RailTask[] = workingSessionIds.map((id, index) => {
|
||||
const session = sessionsById.get(id)
|
||||
|
||||
return {
|
||||
id: `session:${id}`,
|
||||
label: session ? sessionTitle(session) : 'Session task',
|
||||
detail: 'Agent task running',
|
||||
status: 'running',
|
||||
updatedAt: session?.last_active || Date.now() - index
|
||||
}
|
||||
})
|
||||
|
||||
const previewTasks: RailTask[] = previewRestart
|
||||
? [
|
||||
{
|
||||
id: `preview:${previewRestart.taskId}`,
|
||||
label: 'Preview restart',
|
||||
detail: previewRestart.message || previewRestart.url,
|
||||
status: previewRestart.status === 'error' ? 'error' : previewRestart.status === 'running' ? 'running' : 'success',
|
||||
updatedAt: Date.now()
|
||||
}
|
||||
]
|
||||
: []
|
||||
|
||||
const actions: RailTask[] = Object.values(actionTasks).map(({ status, updatedAt }) => ({
|
||||
id: `action:${status.name}`,
|
||||
label: status.name,
|
||||
detail: actionDetail(status),
|
||||
status: actionStatus(status),
|
||||
updatedAt
|
||||
}))
|
||||
|
||||
return [...sessionTasks, ...previewTasks, ...actions].sort((left, right) => right.updatedAt - left.updatedAt)
|
||||
}
|
||||
|
||||
function actionStatus(status: ActionStatusResponse): RailTaskStatus {
|
||||
if (status.running) {
|
||||
return 'running'
|
||||
}
|
||||
|
||||
return status.exit_code === 0 ? 'success' : 'error'
|
||||
}
|
||||
|
||||
function actionDetail(status: ActionStatusResponse): string {
|
||||
if (status.running) {
|
||||
return 'Running'
|
||||
}
|
||||
|
||||
return status.exit_code === 0 ? 'Completed' : `Failed (${status.exit_code ?? 'unknown'})`
|
||||
}
|
||||
|
||||
function prune(tasks: Record<string, DesktopActionTask>): Record<string, DesktopActionTask> {
|
||||
const now = Date.now()
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(tasks)
|
||||
.filter(([, task]) => task.status.running || now - task.updatedAt <= COMPLETED_TTL_MS)
|
||||
.sort(([, left], [, right]) => right.updatedAt - left.updatedAt)
|
||||
.slice(0, HISTORY_LIMIT)
|
||||
)
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { atom } from 'nanostores'
|
||||
import type { ContextSuggestion } from '@/app/types'
|
||||
import type { HermesConnection } from '@/global'
|
||||
import type { ChatMessage } from '@/lib/chat-messages'
|
||||
import type { SessionInfo } from '@/types/hermes'
|
||||
import type { SessionInfo, UsageStats } from '@/types/hermes'
|
||||
|
||||
type Updater<T> = T | ((current: T) => T)
|
||||
|
||||
@@ -34,6 +34,14 @@ export const $currentServiceTier = atom('')
|
||||
export const $currentFastMode = atom(false)
|
||||
export const $currentCwd = atom('')
|
||||
export const $currentBranch = atom('')
|
||||
export const $currentUsage = atom<UsageStats>({
|
||||
calls: 0,
|
||||
input: 0,
|
||||
output: 0,
|
||||
total: 0
|
||||
})
|
||||
export const $sessionStartedAt = atom<number | null>(null)
|
||||
export const $turnStartedAt = atom<number | null>(null)
|
||||
export const $introPersonality = atom('')
|
||||
export const $currentPersonality = atom('')
|
||||
export const $availablePersonalities = atom<string[]>([])
|
||||
@@ -59,6 +67,9 @@ export const setCurrentServiceTier = (next: Updater<string>) => updateAtom($curr
|
||||
export const setCurrentFastMode = (next: Updater<boolean>) => updateAtom($currentFastMode, next)
|
||||
export const setCurrentCwd = (next: Updater<string>) => updateAtom($currentCwd, next)
|
||||
export const setCurrentBranch = (next: Updater<string>) => updateAtom($currentBranch, next)
|
||||
export const setCurrentUsage = (next: Updater<UsageStats>) => updateAtom($currentUsage, next)
|
||||
export const setSessionStartedAt = (next: Updater<number | null>) => updateAtom($sessionStartedAt, next)
|
||||
export const setTurnStartedAt = (next: Updater<number | null>) => updateAtom($turnStartedAt, next)
|
||||
export const setIntroPersonality = (next: Updater<string>) => updateAtom($introPersonality, next)
|
||||
export const setCurrentPersonality = (next: Updater<string>) => updateAtom($currentPersonality, next)
|
||||
export const setAvailablePersonalities = (next: Updater<string[]>) => updateAtom($availablePersonalities, next)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { atom } from 'nanostores'
|
||||
|
||||
import { persistBoolean, storedBoolean } from '@/lib/storage'
|
||||
|
||||
export type ToolViewMode = 'product' | 'technical'
|
||||
|
||||
const TOOL_VIEW_TECHNICAL_STORAGE_KEY = 'hermes.desktop.toolView.technical'
|
||||
|
||||
export const $toolViewMode = atom<ToolViewMode>(storedBoolean(TOOL_VIEW_TECHNICAL_STORAGE_KEY, false) ? 'technical' : 'product')
|
||||
|
||||
$toolViewMode.subscribe(mode => persistBoolean(TOOL_VIEW_TECHNICAL_STORAGE_KEY, mode === 'technical'))
|
||||
|
||||
export function setToolViewMode(mode: ToolViewMode) {
|
||||
$toolViewMode.set(mode)
|
||||
}
|
||||
Reference in New Issue
Block a user