- Hoist todo to first-class widget (shadcn checkboxes, brand colors, no tool-accordion). Header derives label from active task; non-active rows fade. - Replace raw JSON dumps with structured key/value summaries via formatToolResultSummary; nested error extraction for clearer failures. - Fix loaded-session grouping: stitch interleaved assistant/tool iterations into one bubble instead of orphaned synthetic messages. - Stable tool/thinking timers via keyed registry so unmount/scroll doesn't reset elapsed counts; gate "running" on real live thread state. - Reorganize chat-only assistant-ui components under components/chat/.
39 lines
1.3 KiB
TypeScript
39 lines
1.3 KiB
TypeScript
export type TodoStatus = 'pending' | 'in_progress' | 'completed' | 'cancelled'
|
|
|
|
export interface TodoItem {
|
|
content: string
|
|
id: string
|
|
status: TodoStatus
|
|
}
|
|
|
|
const STATUSES: readonly TodoStatus[] = ['pending', 'in_progress', 'completed', 'cancelled']
|
|
|
|
const isRecord = (v: unknown): v is Record<string, unknown> => Boolean(v && typeof v === 'object' && !Array.isArray(v))
|
|
const isStatus = (v: unknown): v is TodoStatus => (STATUSES as readonly string[]).includes(v as string)
|
|
|
|
function parseArray(value: unknown[]): TodoItem[] {
|
|
return value.flatMap(item => {
|
|
if (!isRecord(item) || !isStatus(item.status)) {return []}
|
|
const id = String(item.id ?? '').trim()
|
|
const content = String(item.content ?? '').trim()
|
|
|
|
return id && content ? [{ content, id, status: item.status }] : []
|
|
})
|
|
}
|
|
|
|
function parse(value: unknown, depth: number): null | TodoItem[] {
|
|
if (depth > 2) {return null}
|
|
|
|
if (Array.isArray(value)) {return parseArray(value)}
|
|
|
|
if (typeof value === 'string' && value.trim()) {
|
|
try { return parse(JSON.parse(value), depth + 1) } catch { return null }
|
|
}
|
|
|
|
if (isRecord(value) && Object.hasOwn(value, 'todos')) {return parse(value.todos, depth + 1)}
|
|
|
|
return null
|
|
}
|
|
|
|
export const parseTodos = (value: unknown): null | TodoItem[] => parse(value, 0)
|