@deepagents/devtool-history 7.0.1 → 7.1.0

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 CHANGED
@@ -34,6 +34,8 @@ export declare function ChildProgressList({ treeId, snapshot, }: {
34
34
  snapshot?: readonly ChildProgress[];
35
35
  }): import("react").JSX.Element | null;
36
36
  export declare function isConversationEvent(event: RuntimeEvent): event is ConversationEvent;
37
+ /** One entry of the runtime's `/history` response (`AgentHistoryItem`). */
38
+ export declare function isHistoryRecord(value: unknown): value is HistoryRecord;
37
39
  declare function HistoryRoot({ activeChatId, onSelect, className, children, }: {
38
40
  activeChatId: string | undefined;
39
41
  onSelect: (history: HistoryRecord) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -132,6 +132,9 @@ function ChildProgressList({
132
132
  function isConversationEvent(event) {
133
133
  return event.type === "change" && event.resource === "conversation" && isConversationStatus(event.status) && (event.child === void 0 || isChildProgress(event.child) && event.child.chatId === event.id);
134
134
  }
135
+ function isHistoryRecord(value) {
136
+ return isRecord(value) && typeof value.chatId === "string" && typeof value.userId === "string" && (value.title === void 0 || typeof value.title === "string") && typeof value.createdAt === "number" && typeof value.updatedAt === "number" && typeof value.messageCount === "number" && isConversationStatus(value.status) && (value.children === void 0 || Array.isArray(value.children) && value.children.every(isChildProgress));
137
+ }
135
138
  function parseRuntimeEvent(data) {
136
139
  let event;
137
140
  try {
@@ -147,7 +150,7 @@ function parseRuntimeEvent(data) {
147
150
  if (event.resource === "conversation" && (!isConversationStatus(event.status) || event.child !== void 0 && (!isChildProgress(event.child) || event.child.chatId !== event.id))) {
148
151
  return void 0;
149
152
  }
150
- return event;
153
+ return { ...event, type: "change", resource: event.resource, id: event.id };
151
154
  }
152
155
  function isConversationStatus(value) {
153
156
  if (!isRecord(value) || typeof value.type !== "string") return false;
@@ -165,9 +168,7 @@ function isChildProgress(value) {
165
168
  ) || typeof value.state !== "string" || !Object.hasOwn(childStateLabels, value.state))
166
169
  return false;
167
170
  return Object.entries(value.activities).every(
168
- ([kind, activity]) => Object.hasOwn(activityLabels, kind) && isRecord(activity) && activity.type === kind && typeof activity.at === "number" && Number.isFinite(activity.at) && (activity.outcome === void 0 || ["completed", "failed", "cancelled"].includes(
169
- activity.outcome
170
- )) && ["id", "actorPath", "targetPath", "streamId"].every(
171
+ ([kind, activity]) => Object.hasOwn(activityLabels, kind) && isRecord(activity) && activity.type === kind && typeof activity.at === "number" && Number.isFinite(activity.at) && (activity.outcome === void 0 || activity.outcome === "completed" || activity.outcome === "failed" || activity.outcome === "cancelled") && ["id", "actorPath", "targetPath", "streamId"].every(
171
172
  (key) => typeof activity[key] === "string"
172
173
  )
173
174
  );
@@ -297,6 +298,7 @@ export {
297
298
  conversationStatusLabel,
298
299
  formatTimestamp,
299
300
  isConversationEvent,
301
+ isHistoryRecord,
300
302
  useConversationStatus
301
303
  };
302
304
  //# sourceMappingURL=index.js.map
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\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 as RuntimeEvent;\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 ['completed', 'failed', 'cancelled'].includes(\n activity.outcome as string,\n )) &&\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;AAQP,SAAS,UAAU;AA6Eb,cA4Ec,YA5Ed;AApDC,SAAS,wBAAwB,QAA4B;AAClE,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,UAAI,OAAO,YAAY,SAAS,mBAAmB,EAAG,QAAO;AAC7D,UAAI,OAAO,YAAY,SAAS,oBAAoB,EAAG,QAAO;AAC9D,aAAO;AAAA,EACX;AACF;AAIA,IAAM,4BAA4B,cAAmC,IAAI;AACzE,IAAM,wBAAwB,cAAwC,CAAC,CAAC;AAEjE,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA,UAAU,CAAC;AAAA,EACX;AACF,GAKG;AACD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAuB,oBAAI,IAAI,CAAC;AAChE,QAAM,SAAS,eAAe,OAAO;AACrC,YAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,UAAM,SAAS,IAAI,YAAY,IAAI;AACnC,UAAM,cAAc,CAAC,YAAkC;AACrD,YAAM,QAAQ,kBAAkB,QAAQ,IAAI;AAC5C,UAAI,CAAC,MAAO;AACZ,UAAI,MAAM,SAAS,SAAS;AAC1B,oBAAY,oBAAI,IAAI,CAAC;AAAA,MACvB,WAAW,oBAAoB,KAAK,GAAG;AACrC,oBAAY,CAAC,aAAa,IAAI,IAAI,QAAQ,EAAE,IAAI,MAAM,IAAI,KAAK,CAAC;AAAA,MAClE;AACA,aAAO,KAAK;AAAA,IACd;AACA,WAAO,iBAAiB,WAAW,WAAW;AAC9C,WAAO,MAAM;AACX,aAAO,oBAAoB,WAAW,WAAW;AACjD,aAAO,MAAM;AAAA,IACf;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AACT,SACE,oBAAC,6BAA0B,OAAO,UAChC,8BAAC,yBAAsB,OAAO,SAAU,UAAS,GACnD;AAEJ;AAEO,SAAS,sBACd,QACA,UACoB;AACpB,QAAM,WAAW,IAAI,yBAAyB;AAC9C,MAAI,CAAC,UAAU;AACb,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO,SAAS,IAAI,MAAM,GAAG,UAAU;AACzC;AAEA,IAAM,mBAA2D;AAAA,EAC/D,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,aAAa;AACf;AAEA,IAAM,iBAAwD;AAAA,EAC5D,OAAO;AAAA,EACP,SAAS;AAAA,EACT,UAAU;AAAA,EACV,WAAW;AAAA,EACX,YAAY;AACd;AAGO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA,WAAW,CAAC;AACd,GAGG;AACD,QAAM,SAAS,IAAI,yBAAyB;AAC5C,QAAM,UAAU,IAAI,qBAAqB;AACzC,QAAM,QACJ,QAAQ,KAAK,CAAC,WAAW,OAAO,WAAW,MAAM,GAAG,YAAY;AAClE,QAAM,WAAW,IAAI;AAAA,IACnB,MACG,OAAO,CAAC,UAAU,MAAM,WAAW,MAAM,EACzC,IAAI,CAAC,UAAU,CAAC,MAAM,QAAQ,KAAK,CAAC;AAAA,EACzC;AACA,aAAW,SAAS,QAAQ,OAAO,KAAK,CAAC,GAAG;AAC1C,QAAI,MAAM,OAAO,WAAW,OAAQ,UAAS,IAAI,MAAM,IAAI,MAAM,KAAK;AAAA,EACxE;AACA,MAAI,SAAS,SAAS,EAAG,QAAO;AAChC,SACE,qBAAC,aAAQ,cAAW,gBAAe,WAAU,sBAC3C;AAAA,wBAAC,QAAG,WAAU,4BAA2B,0BAAY;AAAA,IACrD,oBAAC,QAAG,WAAU,aACX,WAAC,GAAG,SAAS,OAAO,CAAC,EACnB,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC,EAC3C,IAAI,CAAC,UAAU;AACd,YAAM,SAAS,OAAO,OAAO,MAAM,UAAU,EAAE;AAAA,QAC7C,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE;AAAA,MACrB,EAAE,CAAC;AACH,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,WAAU;AAAA,UAEV;AAAA,iCAAC,SAAI,WAAU,WACb;AAAA,kCAAC,OAAE,WAAU,8BAA8B,gBAAM,MAAK;AAAA,cACrD,UACC,qBAAC,OAAE,WAAU,iCACV;AAAA,+BAAe,OAAO,IAAI;AAAA,gBAAE;AAAA,gBAAI,OAAO;AAAA,gBAAU;AAAA,gBAAG;AAAA,gBACpD,OAAO;AAAA,iBACV;AAAA,eAEJ;AAAA,YACA,oBAAC,eAAY,QAAQ,iBAAiB,MAAM,KAAK,GAAG;AAAA;AAAA;AAAA,QAZ/C,MAAM;AAAA,MAab;AAAA,IAEJ,CAAC,GACL;AAAA,KACF;AAEJ;AAEO,SAAS,oBACd,OAC4B;AAC5B,SACE,MAAM,SAAS,YACf,MAAM,aAAa,kBACnB,qBAAqB,MAAM,MAAM,MAChC,MAAM,UAAU,UACd,gBAAgB,MAAM,KAAK,KAAK,MAAM,MAAM,WAAW,MAAM;AAEpE;AAEA,SAAS,kBAAkB,MAAwC;AACjE,MAAI;AACJ,MAAI;AACF,YAAQ,KAAK,MAAM,IAAI;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,CAAC,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS,SAAU,QAAO;AAC/D,MAAI,MAAM,SAAS,QAAS,QAAO,EAAE,MAAM,QAAQ;AACnD,MACE,MAAM,SAAS,YACf,OAAO,MAAM,aAAa,YAC1B,CAAC,MAAM,YACP,OAAO,MAAM,OAAO,YACpB,CAAC,MAAM,IACP;AACA,WAAO;AAAA,EACT;AACA,MACE,MAAM,aAAa,mBAClB,CAAC,qBAAqB,MAAM,MAAM,KAChC,MAAM,UAAU,WACd,CAAC,gBAAgB,MAAM,KAAK,KAAK,MAAM,MAAM,WAAW,MAAM,MACnE;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,qBAAqB,OAA6C;AACzE,MAAI,CAAC,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS,SAAU,QAAO;AAC/D,MAAI,MAAM,SAAS,UAAU,MAAM,SAAS,cAAe,QAAO;AAClE,SACE,MAAM,SAAS,YACf,MAAM,QAAQ,MAAM,WAAW,KAC/B,MAAM,YAAY;AAAA,IAChB,CAAC,SAAS,SAAS,uBAAuB,SAAS;AAAA,EACrD;AAEJ;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,gBAAgB,OAAwC;AAC/D,MACE,CAAC,SAAS,KAAK,KACf,CAAC,SAAS,MAAM,UAAU,KAC1B,CAAC,CAAC,UAAU,UAAU,QAAQ,gBAAgB,iBAAiB,EAAE;AAAA,IAC/D,CAAC,QAAQ,OAAO,MAAM,GAAG,MAAM;AAAA,EACjC,KACA,OAAO,MAAM,UAAU,YACvB,CAAC,OAAO,OAAO,kBAAkB,MAAM,KAAK;AAE5C,WAAO;AACT,SAAO,OAAO,QAAQ,MAAM,UAAU,EAAE;AAAA,IACtC,CAAC,CAAC,MAAM,QAAQ,MACd,OAAO,OAAO,gBAAgB,IAAI,KAClC,SAAS,QAAQ,KACjB,SAAS,SAAS,QAClB,OAAO,SAAS,OAAO,YACvB,OAAO,SAAS,SAAS,EAAE,MAC1B,SAAS,YAAY,UACpB,CAAC,aAAa,UAAU,WAAW,EAAE;AAAA,MACnC,SAAS;AAAA,IACX,MACF,CAAC,MAAM,aAAa,cAAc,UAAU,EAAE;AAAA,MAC5C,CAAC,QAAQ,OAAO,SAAS,GAAG,MAAM;AAAA,IACpC;AAAA,EACJ;AACF;AAOA,IAAM,iBAAiB,cAA0C,IAAI;AAErE,SAAS,oBAAoB;AAC3B,QAAM,UAAU,IAAI,cAAc;AAClC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,SAAO;AACT;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,QAAQ;AAAA,IACZ,OAAO,EAAE,cAAc,SAAS;AAAA,IAChC,CAAC,cAAc,QAAQ;AAAA,EACzB;AACA,SACE,oBAAC,eAAe,UAAf,EAAwB,OACvB,8BAAC,SAAI,WAAW,GAAG,+BAA+B,SAAS,GACxD,UACH,GACF;AAEJ;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AACF,GAGG;AACD,SACE,oBAAC,SAAI,WAAW,GAAG,+BAA+B,SAAS,GACxD,UACH;AAEJ;AAEA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,EAAE,cAAc,SAAS,IAAI,kBAAkB;AACrD,QAAM,WAAW,iBAAiB,QAAQ;AAC1C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,gBAAc,WAAW,SAAS;AAAA,MAClC,SAAS,MAAM,SAAS,OAAO;AAAA,MAC/B,WAAW;AAAA,QACT;AAAA,QACA,WACI,8BACA;AAAA,QACJ;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;AAEA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AACF,GAGG;AACD,SACE,oBAAC,SAAI,WAAW,GAAG,2CAA2C,SAAS,GACpE,UACH;AAEJ;AAEO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AACF,GAA6C;AAC3C,QAAM,YAAY;AAClB,QAAM,QAAQ,wBAAwB,sBAAsB,QAAQ,MAAM,CAAC;AAC3E,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aAAO,oBAAC,iBAAc,cAAW,UAAS,WAAsB;AAAA,IAClE,KAAK;AACH,aACE;AAAA,QAAC;AAAA;AAAA,UACC,cAAW;AAAA,UACX,WAAW,GAAG,WAAW,kBAAkB;AAAA;AAAA,MAC7C;AAAA,IAEJ,KAAK;AACH,aAAO,oBAAC,qBAAkB,cAAW,QAAO,WAAsB;AAAA,IACpE,KAAK;AACH,aACE;AAAA,QAAC;AAAA;AAAA,UACC,cAAW;AAAA,UACX;AAAA;AAAA,MACF;AAAA,IAEJ,KAAK;AACH,aACE;AAAA,QAAC;AAAA;AAAA,UACC,cAAW;AAAA,UACX;AAAA;AAAA,MACF;AAAA,EAEN;AACF;AAEO,SAAS,YAAY,EAAE,OAAO,GAAuB;AAC1D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,SACC,WAAW,YAAY,WAAW,YACjC;AAAA,MACJ;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;AAEA,IAAM,WAAW,IAAI,KAAK,eAAe,QAAW;AAAA,EAClD,WAAW;AAAA,EACX,WAAW;AACb,CAAC;AAEM,SAAS,gBAAgB,OAAwB;AACtD,SAAO,SAAS,OAAO,IAAI,KAAK,KAAK,CAAC;AACxC;AAEO,IAAM,UAAU;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,EACN,aAAa;AAAA,EACb,OAAO;AACT;",
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": "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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.0.1",
3
+ "version": "7.1.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,8 +29,8 @@
29
29
  }
30
30
  },
31
31
  "dependencies": {
32
- "@deepagents/experimental": "7.0.1",
33
- "@deepagents/react-shadcn": "7.0.1",
32
+ "@deepagents/experimental": "7.1.0",
33
+ "@deepagents/react-shadcn": "7.1.0",
34
34
  "lucide-react": "^1.33.0"
35
35
  },
36
36
  "peerDependencies": {