@deepagents/devtool-history 7.1.1 → 7.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +2 -2
- package/package.json +4 -3
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// packages/devtool/history/src/index.tsx
|
|
2
|
+
import { cn } from "cn";
|
|
2
3
|
import {
|
|
3
4
|
CircleAlertIcon,
|
|
4
5
|
CircleDotIcon,
|
|
@@ -14,7 +15,6 @@ import {
|
|
|
14
15
|
useMemo,
|
|
15
16
|
useState
|
|
16
17
|
} from "react";
|
|
17
|
-
import { cn } from "@deepagents/react-shadcn";
|
|
18
18
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
19
19
|
function conversationStatusLabel(status) {
|
|
20
20
|
switch (status.type) {
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.tsx"],
|
|
4
|
-
"sourcesContent": ["import {\n CircleAlertIcon,\n CircleDotIcon,\n CirclePauseIcon,\n MessageCircleQuestionIcon,\n MessageSquareIcon,\n} from 'lucide-react';\nimport {\n type ReactNode,\n createContext,\n use,\n useEffect,\n useEffectEvent,\n useMemo,\n useState,\n} from 'react';\n\nimport type {\n ChildActivity,\n ChildProgress,\n ConversationStatus,\n} from '@deepagents/experimental/zukhruf';\nimport type { OwnerEvent } from '@deepagents/experimental/zukhruf/http';\nimport { cn } from '@deepagents/react-shadcn';\n\nexport type { ConversationStatus } from '@deepagents/experimental/zukhruf';\n\nexport type HistoryRecord = {\n chatId: string;\n userId: string;\n title?: string;\n createdAt: number;\n updatedAt: number;\n messageCount: number;\n status: ConversationStatus;\n children?: readonly ChildProgress[];\n};\n\nexport type ConversationEvent = {\n type: 'change';\n resource: 'conversation';\n id: string;\n status: ConversationStatus;\n child?: ChildProgress;\n};\n\nexport type RuntimeEvent = OwnerEvent;\n\nexport function conversationStatusLabel(status: ConversationStatus) {\n switch (status.type) {\n case 'idle':\n return 'idle';\n case 'systemError':\n return 'error';\n case 'active':\n if (status.activeFlags.includes('waitingOnApproval')) return 'approval';\n if (status.activeFlags.includes('waitingOnUserInput')) return 'input';\n return 'active';\n }\n}\n\ntype LiveStatuses = ReadonlyMap<string, ConversationEvent>;\n\nconst ConversationStatusContext = createContext<LiveStatuses | null>(null);\nconst RuntimeHistoryContext = createContext<readonly HistoryRecord[]>([]);\n\nexport function RuntimeEventsProvider({\n href,\n onEvent,\n history = [],\n children,\n}: {\n href: string | undefined;\n onEvent: (event: RuntimeEvent) => void;\n history?: readonly HistoryRecord[];\n children: ReactNode;\n}) {\n const [statuses, setStatuses] = useState<LiveStatuses>(new Map());\n const notify = useEffectEvent(onEvent);\n useEffect(() => {\n if (!href) return;\n const source = new EventSource(href);\n const handleEvent = (message: MessageEvent<string>) => {\n const event = parseRuntimeEvent(message.data);\n if (!event) return;\n if (event.type === 'ready') {\n setStatuses(new Map());\n } else if (isConversationEvent(event)) {\n setStatuses((previous) => new Map(previous).set(event.id, event));\n }\n notify(event);\n };\n source.addEventListener('message', handleEvent);\n return () => {\n source.removeEventListener('message', handleEvent);\n source.close();\n };\n }, [href]);\n return (\n <ConversationStatusContext value={statuses}>\n <RuntimeHistoryContext value={history}>{children}</RuntimeHistoryContext>\n </ConversationStatusContext>\n );\n}\n\nexport function useConversationStatus(\n chatId: string,\n snapshot: ConversationStatus,\n): ConversationStatus {\n const statuses = use(ConversationStatusContext);\n if (!statuses) {\n throw new Error(\n 'useConversationStatus must be used inside <RuntimeEventsProvider>.',\n );\n }\n return statuses.get(chatId)?.status ?? snapshot;\n}\n\nconst childStateLabels: Record<ChildProgress['state'], string> = {\n pending: 'Pending',\n queued: 'Queued',\n running: 'Running',\n waitingOnApproval: 'Waiting on approval',\n waitingOnUserInput: 'Waiting on user input',\n completed: 'Completed',\n failed: 'Failed',\n interrupted: 'Interrupted',\n};\n\nconst activityLabels: Record<ChildActivity['type'], string> = {\n spawn: 'Spawned',\n message: 'Message sent',\n followup: 'Follow-up sent',\n interrupt: 'Interrupt accepted',\n completion: 'Turn finished',\n};\n\n/** One row per child in the selected project, refreshed by the owner stream. */\nexport function ChildProgressList({\n treeId,\n snapshot = [],\n}: {\n treeId: string;\n snapshot?: readonly ChildProgress[];\n}) {\n const events = use(ConversationStatusContext);\n const history = use(RuntimeHistoryContext);\n const saved =\n history.find((record) => record.chatId === treeId)?.children ?? snapshot;\n const children = new Map(\n saved\n .filter((child) => child.treeId === treeId)\n .map((child) => [child.chatId, child]),\n );\n for (const event of events?.values() ?? []) {\n if (event.child?.treeId === treeId) children.set(event.id, event.child);\n }\n if (children.size === 0) return null;\n return (\n <section aria-label=\"Child agents\" className=\"border-t px-6 py-3\">\n <h2 className=\"mb-2 text-sm font-medium\">Child agents</h2>\n <ul className=\"space-y-2\">\n {[...children.values()]\n .sort((a, b) => a.path.localeCompare(b.path))\n .map((child) => {\n const latest = Object.values(child.activities).sort(\n (a, b) => b.at - a.at,\n )[0];\n return (\n <li\n key={child.chatId}\n className=\"flex items-center justify-between gap-4 text-sm\"\n >\n <div className=\"min-w-0\">\n <p className=\"truncate font-mono text-xs\">{child.path}</p>\n {latest && (\n <p className=\"text-muted-foreground text-xs\">\n {activityLabels[latest.type]} \u00B7 {latest.actorPath} \u2192{' '}\n {latest.targetPath}\n </p>\n )}\n </div>\n <StatusBadge status={childStateLabels[child.state]} />\n </li>\n );\n })}\n </ul>\n </section>\n );\n}\n\nexport function isConversationEvent(\n event: RuntimeEvent,\n): event is ConversationEvent {\n return (\n event.type === 'change' &&\n event.resource === 'conversation' &&\n isConversationStatus(event.status) &&\n (event.child === undefined ||\n (isChildProgress(event.child) && event.child.chatId === event.id))\n );\n}\n\n/** One entry of the runtime's `/history` response (`AgentHistoryItem`). */\nexport function isHistoryRecord(value: unknown): value is HistoryRecord {\n return (\n isRecord(value) &&\n typeof value.chatId === 'string' &&\n typeof value.userId === 'string' &&\n (value.title === undefined || typeof value.title === 'string') &&\n typeof value.createdAt === 'number' &&\n typeof value.updatedAt === 'number' &&\n typeof value.messageCount === 'number' &&\n isConversationStatus(value.status) &&\n (value.children === undefined ||\n (Array.isArray(value.children) && value.children.every(isChildProgress)))\n );\n}\n\nfunction parseRuntimeEvent(data: string): RuntimeEvent | undefined {\n let event: unknown;\n try {\n event = JSON.parse(data);\n } catch {\n return undefined;\n }\n if (!isRecord(event) || typeof event.type !== 'string') return undefined;\n if (event.type === 'ready') return { type: 'ready' };\n if (\n event.type !== 'change' ||\n typeof event.resource !== 'string' ||\n !event.resource ||\n typeof event.id !== 'string' ||\n !event.id\n ) {\n return undefined;\n }\n if (\n event.resource === 'conversation' &&\n (!isConversationStatus(event.status) ||\n (event.child !== undefined &&\n (!isChildProgress(event.child) || event.child.chatId !== event.id)))\n ) {\n return undefined;\n }\n return { ...event, type: 'change', resource: event.resource, id: event.id };\n}\n\nfunction isConversationStatus(value: unknown): value is ConversationStatus {\n if (!isRecord(value) || typeof value.type !== 'string') return false;\n if (value.type === 'idle' || value.type === 'systemError') return true;\n return (\n value.type === 'active' &&\n Array.isArray(value.activeFlags) &&\n value.activeFlags.every(\n (flag) => flag === 'waitingOnApproval' || flag === 'waitingOnUserInput',\n )\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isChildProgress(value: unknown): value is ChildProgress {\n if (\n !isRecord(value) ||\n !isRecord(value.activities) ||\n !['chatId', 'treeId', 'path', 'parentChatId', 'declarationName'].every(\n (key) => typeof value[key] === 'string',\n ) ||\n typeof value.state !== 'string' ||\n !Object.hasOwn(childStateLabels, value.state)\n )\n return false;\n return Object.entries(value.activities).every(\n ([kind, activity]) =>\n Object.hasOwn(activityLabels, kind) &&\n isRecord(activity) &&\n activity.type === kind &&\n typeof activity.at === 'number' &&\n Number.isFinite(activity.at) &&\n (activity.outcome === undefined ||\n activity.outcome === 'completed' ||\n activity.outcome === 'failed' ||\n activity.outcome === 'cancelled') &&\n ['id', 'actorPath', 'targetPath', 'streamId'].every(\n (key) => typeof activity[key] === 'string',\n ),\n );\n}\n\ntype HistoryContextValue = {\n activeChatId: string | undefined;\n onSelect: (history: HistoryRecord) => void;\n};\n\nconst HistoryContext = createContext<HistoryContextValue | null>(null);\n\nfunction useHistoryContext() {\n const context = use(HistoryContext);\n if (!context) {\n throw new Error('History.* parts must be rendered inside <History.Root>.');\n }\n return context;\n}\n\nfunction HistoryRoot({\n activeChatId,\n onSelect,\n className,\n children,\n}: {\n activeChatId: string | undefined;\n onSelect: (history: HistoryRecord) => void;\n className?: string;\n children: ReactNode;\n}) {\n const value = useMemo(\n () => ({ activeChatId, onSelect }),\n [activeChatId, onSelect],\n );\n return (\n <HistoryContext.Provider value={value}>\n <div className={cn('flex min-h-0 flex-col gap-1', className)}>\n {children}\n </div>\n </HistoryContext.Provider>\n );\n}\n\nfunction HistoryItem({\n className,\n children,\n}: {\n className?: string;\n children: ReactNode;\n}) {\n return (\n <div className={cn('group/history-item relative', className)}>\n {children}\n </div>\n );\n}\n\nfunction HistoryItemTrigger({\n history,\n className,\n children,\n}: {\n history: HistoryRecord;\n className?: string;\n children: ReactNode;\n}) {\n const { activeChatId, onSelect } = useHistoryContext();\n const isActive = activeChatId === history.chatId;\n return (\n <button\n type=\"button\"\n aria-current={isActive ? 'true' : undefined}\n onClick={() => onSelect(history)}\n className={cn(\n 'flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-left text-sm transition-colors',\n isActive\n ? 'bg-accent text-foreground'\n : 'text-muted-foreground hover:bg-accent hover:text-foreground',\n className,\n )}\n >\n {children}\n </button>\n );\n}\n\nfunction HistoryEmpty({\n className,\n children,\n}: {\n className?: string;\n children: ReactNode;\n}) {\n return (\n <div className={cn('text-muted-foreground px-2 py-4 text-sm', className)}>\n {children}\n </div>\n );\n}\n\nexport function ChatStatusIcon({\n chatId,\n status,\n}: Pick<HistoryRecord, 'chatId' | 'status'>) {\n const className = 'size-3.5 shrink-0';\n const label = conversationStatusLabel(useConversationStatus(chatId, status));\n switch (label) {\n case 'active':\n return <CircleDotIcon aria-label=\"Active\" className={className} />;\n case 'error':\n return (\n <CircleAlertIcon\n aria-label=\"Error\"\n className={cn(className, 'text-destructive')}\n />\n );\n case 'idle':\n return <MessageSquareIcon aria-label=\"idle\" className={className} />;\n case 'approval':\n return (\n <CirclePauseIcon\n aria-label=\"Waiting on approval\"\n className={className}\n />\n );\n case 'input':\n return (\n <MessageCircleQuestionIcon\n aria-label=\"Waiting on user input\"\n className={className}\n />\n );\n }\n}\n\nexport function StatusBadge({ status }: { status: string }) {\n return (\n <span\n className={cn(\n 'text-muted-foreground rounded-md border px-2 py-1 font-mono text-[0.6875rem] capitalize',\n (status === 'failed' || status === 'error') &&\n 'text-destructive border-destructive/30',\n )}\n >\n {status}\n </span>\n );\n}\n\nconst dateTime = new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n timeStyle: 'short',\n});\n\nexport function formatTimestamp(value: number | string) {\n return dateTime.format(new Date(value));\n}\n\nexport const History = {\n Root: HistoryRoot,\n Item: HistoryItem,\n ItemTrigger: HistoryItemTrigger,\n Empty: HistoryEmpty,\n} as const;\n"],
|
|
5
|
-
"mappings": ";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;
|
|
4
|
+
"sourcesContent": ["import { cn } from 'cn';\nimport {\n CircleAlertIcon,\n CircleDotIcon,\n CirclePauseIcon,\n MessageCircleQuestionIcon,\n MessageSquareIcon,\n} from 'lucide-react';\nimport {\n type ReactNode,\n createContext,\n use,\n useEffect,\n useEffectEvent,\n useMemo,\n useState,\n} from 'react';\n\nimport type {\n ChildActivity,\n ChildProgress,\n ConversationStatus,\n} from '@deepagents/experimental/zukhruf';\nimport type { OwnerEvent } from '@deepagents/experimental/zukhruf/http';\n\nexport type { ConversationStatus } from '@deepagents/experimental/zukhruf';\n\nexport type HistoryRecord = {\n chatId: string;\n userId: string;\n title?: string;\n createdAt: number;\n updatedAt: number;\n messageCount: number;\n status: ConversationStatus;\n children?: readonly ChildProgress[];\n};\n\nexport type ConversationEvent = {\n type: 'change';\n resource: 'conversation';\n id: string;\n status: ConversationStatus;\n child?: ChildProgress;\n};\n\nexport type RuntimeEvent = OwnerEvent;\n\nexport function conversationStatusLabel(status: ConversationStatus) {\n switch (status.type) {\n case 'idle':\n return 'idle';\n case 'systemError':\n return 'error';\n case 'active':\n if (status.activeFlags.includes('waitingOnApproval')) return 'approval';\n if (status.activeFlags.includes('waitingOnUserInput')) return 'input';\n return 'active';\n }\n}\n\ntype LiveStatuses = ReadonlyMap<string, ConversationEvent>;\n\nconst ConversationStatusContext = createContext<LiveStatuses | null>(null);\nconst RuntimeHistoryContext = createContext<readonly HistoryRecord[]>([]);\n\nexport function RuntimeEventsProvider({\n href,\n onEvent,\n history = [],\n children,\n}: {\n href: string | undefined;\n onEvent: (event: RuntimeEvent) => void;\n history?: readonly HistoryRecord[];\n children: ReactNode;\n}) {\n const [statuses, setStatuses] = useState<LiveStatuses>(new Map());\n const notify = useEffectEvent(onEvent);\n useEffect(() => {\n if (!href) return;\n const source = new EventSource(href);\n const handleEvent = (message: MessageEvent<string>) => {\n const event = parseRuntimeEvent(message.data);\n if (!event) return;\n if (event.type === 'ready') {\n setStatuses(new Map());\n } else if (isConversationEvent(event)) {\n setStatuses((previous) => new Map(previous).set(event.id, event));\n }\n notify(event);\n };\n source.addEventListener('message', handleEvent);\n return () => {\n source.removeEventListener('message', handleEvent);\n source.close();\n };\n }, [href]);\n return (\n <ConversationStatusContext value={statuses}>\n <RuntimeHistoryContext value={history}>{children}</RuntimeHistoryContext>\n </ConversationStatusContext>\n );\n}\n\nexport function useConversationStatus(\n chatId: string,\n snapshot: ConversationStatus,\n): ConversationStatus {\n const statuses = use(ConversationStatusContext);\n if (!statuses) {\n throw new Error(\n 'useConversationStatus must be used inside <RuntimeEventsProvider>.',\n );\n }\n return statuses.get(chatId)?.status ?? snapshot;\n}\n\nconst childStateLabels: Record<ChildProgress['state'], string> = {\n pending: 'Pending',\n queued: 'Queued',\n running: 'Running',\n waitingOnApproval: 'Waiting on approval',\n waitingOnUserInput: 'Waiting on user input',\n completed: 'Completed',\n failed: 'Failed',\n interrupted: 'Interrupted',\n};\n\nconst activityLabels: Record<ChildActivity['type'], string> = {\n spawn: 'Spawned',\n message: 'Message sent',\n followup: 'Follow-up sent',\n interrupt: 'Interrupt accepted',\n completion: 'Turn finished',\n};\n\n/** One row per child in the selected project, refreshed by the owner stream. */\nexport function ChildProgressList({\n treeId,\n snapshot = [],\n}: {\n treeId: string;\n snapshot?: readonly ChildProgress[];\n}) {\n const events = use(ConversationStatusContext);\n const history = use(RuntimeHistoryContext);\n const saved =\n history.find((record) => record.chatId === treeId)?.children ?? snapshot;\n const children = new Map(\n saved\n .filter((child) => child.treeId === treeId)\n .map((child) => [child.chatId, child]),\n );\n for (const event of events?.values() ?? []) {\n if (event.child?.treeId === treeId) children.set(event.id, event.child);\n }\n if (children.size === 0) return null;\n return (\n <section aria-label=\"Child agents\" className=\"border-t px-6 py-3\">\n <h2 className=\"mb-2 text-sm font-medium\">Child agents</h2>\n <ul className=\"space-y-2\">\n {[...children.values()]\n .sort((a, b) => a.path.localeCompare(b.path))\n .map((child) => {\n const latest = Object.values(child.activities).sort(\n (a, b) => b.at - a.at,\n )[0];\n return (\n <li\n key={child.chatId}\n className=\"flex items-center justify-between gap-4 text-sm\"\n >\n <div className=\"min-w-0\">\n <p className=\"truncate font-mono text-xs\">{child.path}</p>\n {latest && (\n <p className=\"text-muted-foreground text-xs\">\n {activityLabels[latest.type]} \u00B7 {latest.actorPath} \u2192{' '}\n {latest.targetPath}\n </p>\n )}\n </div>\n <StatusBadge status={childStateLabels[child.state]} />\n </li>\n );\n })}\n </ul>\n </section>\n );\n}\n\nexport function isConversationEvent(\n event: RuntimeEvent,\n): event is ConversationEvent {\n return (\n event.type === 'change' &&\n event.resource === 'conversation' &&\n isConversationStatus(event.status) &&\n (event.child === undefined ||\n (isChildProgress(event.child) && event.child.chatId === event.id))\n );\n}\n\n/** One entry of the runtime's `/history` response (`AgentHistoryItem`). */\nexport function isHistoryRecord(value: unknown): value is HistoryRecord {\n return (\n isRecord(value) &&\n typeof value.chatId === 'string' &&\n typeof value.userId === 'string' &&\n (value.title === undefined || typeof value.title === 'string') &&\n typeof value.createdAt === 'number' &&\n typeof value.updatedAt === 'number' &&\n typeof value.messageCount === 'number' &&\n isConversationStatus(value.status) &&\n (value.children === undefined ||\n (Array.isArray(value.children) && value.children.every(isChildProgress)))\n );\n}\n\nfunction parseRuntimeEvent(data: string): RuntimeEvent | undefined {\n let event: unknown;\n try {\n event = JSON.parse(data);\n } catch {\n return undefined;\n }\n if (!isRecord(event) || typeof event.type !== 'string') return undefined;\n if (event.type === 'ready') return { type: 'ready' };\n if (\n event.type !== 'change' ||\n typeof event.resource !== 'string' ||\n !event.resource ||\n typeof event.id !== 'string' ||\n !event.id\n ) {\n return undefined;\n }\n if (\n event.resource === 'conversation' &&\n (!isConversationStatus(event.status) ||\n (event.child !== undefined &&\n (!isChildProgress(event.child) || event.child.chatId !== event.id)))\n ) {\n return undefined;\n }\n return { ...event, type: 'change', resource: event.resource, id: event.id };\n}\n\nfunction isConversationStatus(value: unknown): value is ConversationStatus {\n if (!isRecord(value) || typeof value.type !== 'string') return false;\n if (value.type === 'idle' || value.type === 'systemError') return true;\n return (\n value.type === 'active' &&\n Array.isArray(value.activeFlags) &&\n value.activeFlags.every(\n (flag) => flag === 'waitingOnApproval' || flag === 'waitingOnUserInput',\n )\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isChildProgress(value: unknown): value is ChildProgress {\n if (\n !isRecord(value) ||\n !isRecord(value.activities) ||\n !['chatId', 'treeId', 'path', 'parentChatId', 'declarationName'].every(\n (key) => typeof value[key] === 'string',\n ) ||\n typeof value.state !== 'string' ||\n !Object.hasOwn(childStateLabels, value.state)\n )\n return false;\n return Object.entries(value.activities).every(\n ([kind, activity]) =>\n Object.hasOwn(activityLabels, kind) &&\n isRecord(activity) &&\n activity.type === kind &&\n typeof activity.at === 'number' &&\n Number.isFinite(activity.at) &&\n (activity.outcome === undefined ||\n activity.outcome === 'completed' ||\n activity.outcome === 'failed' ||\n activity.outcome === 'cancelled') &&\n ['id', 'actorPath', 'targetPath', 'streamId'].every(\n (key) => typeof activity[key] === 'string',\n ),\n );\n}\n\ntype HistoryContextValue = {\n activeChatId: string | undefined;\n onSelect: (history: HistoryRecord) => void;\n};\n\nconst HistoryContext = createContext<HistoryContextValue | null>(null);\n\nfunction useHistoryContext() {\n const context = use(HistoryContext);\n if (!context) {\n throw new Error('History.* parts must be rendered inside <History.Root>.');\n }\n return context;\n}\n\nfunction HistoryRoot({\n activeChatId,\n onSelect,\n className,\n children,\n}: {\n activeChatId: string | undefined;\n onSelect: (history: HistoryRecord) => void;\n className?: string;\n children: ReactNode;\n}) {\n const value = useMemo(\n () => ({ activeChatId, onSelect }),\n [activeChatId, onSelect],\n );\n return (\n <HistoryContext.Provider value={value}>\n <div className={cn('flex min-h-0 flex-col gap-1', className)}>\n {children}\n </div>\n </HistoryContext.Provider>\n );\n}\n\nfunction HistoryItem({\n className,\n children,\n}: {\n className?: string;\n children: ReactNode;\n}) {\n return (\n <div className={cn('group/history-item relative', className)}>\n {children}\n </div>\n );\n}\n\nfunction HistoryItemTrigger({\n history,\n className,\n children,\n}: {\n history: HistoryRecord;\n className?: string;\n children: ReactNode;\n}) {\n const { activeChatId, onSelect } = useHistoryContext();\n const isActive = activeChatId === history.chatId;\n return (\n <button\n type=\"button\"\n aria-current={isActive ? 'true' : undefined}\n onClick={() => onSelect(history)}\n className={cn(\n 'flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-left text-sm transition-colors',\n isActive\n ? 'bg-accent text-foreground'\n : 'text-muted-foreground hover:bg-accent hover:text-foreground',\n className,\n )}\n >\n {children}\n </button>\n );\n}\n\nfunction HistoryEmpty({\n className,\n children,\n}: {\n className?: string;\n children: ReactNode;\n}) {\n return (\n <div className={cn('text-muted-foreground px-2 py-4 text-sm', className)}>\n {children}\n </div>\n );\n}\n\nexport function ChatStatusIcon({\n chatId,\n status,\n}: Pick<HistoryRecord, 'chatId' | 'status'>) {\n const className = 'size-3.5 shrink-0';\n const label = conversationStatusLabel(useConversationStatus(chatId, status));\n switch (label) {\n case 'active':\n return <CircleDotIcon aria-label=\"Active\" className={className} />;\n case 'error':\n return (\n <CircleAlertIcon\n aria-label=\"Error\"\n className={cn(className, 'text-destructive')}\n />\n );\n case 'idle':\n return <MessageSquareIcon aria-label=\"idle\" className={className} />;\n case 'approval':\n return (\n <CirclePauseIcon\n aria-label=\"Waiting on approval\"\n className={className}\n />\n );\n case 'input':\n return (\n <MessageCircleQuestionIcon\n aria-label=\"Waiting on user input\"\n className={className}\n />\n );\n }\n}\n\nexport function StatusBadge({ status }: { status: string }) {\n return (\n <span\n className={cn(\n 'text-muted-foreground rounded-md border px-2 py-1 font-mono text-[0.6875rem] capitalize',\n (status === 'failed' || status === 'error') &&\n 'text-destructive border-destructive/30',\n )}\n >\n {status}\n </span>\n );\n}\n\nconst dateTime = new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n timeStyle: 'short',\n});\n\nexport function formatTimestamp(value: number | string) {\n return dateTime.format(new Date(value));\n}\n\nexport const History = {\n Root: HistoryRoot,\n Item: HistoryItem,\n ItemTrigger: HistoryItemTrigger,\n Empty: HistoryEmpty,\n} as const;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepagents/devtool-history",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,14 +23,15 @@
|
|
|
23
23
|
"exports": {
|
|
24
24
|
"./package.json": "./package.json",
|
|
25
25
|
".": {
|
|
26
|
+
"@deepagents/source": "./src/index.tsx",
|
|
26
27
|
"types": "./dist/index.d.ts",
|
|
27
28
|
"import": "./dist/index.js",
|
|
28
29
|
"default": "./dist/index.js"
|
|
29
30
|
}
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
32
|
-
"@deepagents/experimental": "7.1.
|
|
33
|
-
"
|
|
33
|
+
"@deepagents/experimental": "7.1.3",
|
|
34
|
+
"cn": "^0.4.0",
|
|
34
35
|
"lucide-react": "^1.33.0"
|
|
35
36
|
},
|
|
36
37
|
"peerDependencies": {
|