@athenaintel/react 0.42.1 → 0.43.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/README.md +46 -7
- package/dist/agent-runtime/src/conversation-list-groups.d.ts +74 -0
- package/dist/agent-runtime/src/index.d.ts +3 -2
- package/dist/agent-runtime/src/messages.cjs +38 -7
- package/dist/agent-runtime/src/messages.cjs.map +1 -1
- package/dist/agent-runtime/src/messages.d.ts +26 -8
- package/dist/agent-runtime/src/messages.js +38 -7
- package/dist/agent-runtime/src/messages.js.map +1 -1
- package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +10 -0
- package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
- package/dist/agent-runtime/src/quota-safe-local-storage-session.d.ts +7 -0
- package/dist/agent-runtime/src/quota-safe-local-storage-session.js +10 -0
- package/dist/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
- package/dist/agent-runtime/src/session-lane-scope.cjs +25 -0
- package/dist/agent-runtime/src/session-lane-scope.cjs.map +1 -0
- package/dist/agent-runtime/src/session-lane-scope.d.ts +59 -0
- package/dist/agent-runtime/src/session-lane-scope.js +25 -0
- package/dist/agent-runtime/src/session-lane-scope.js.map +1 -0
- package/dist/agent-runtime/src/subagent-transcripts.cjs +2 -2
- package/dist/agent-runtime/src/subagent-transcripts.cjs.map +1 -1
- package/dist/agent-runtime/src/subagent-transcripts.d.ts +2 -2
- package/dist/agent-runtime/src/subagent-transcripts.js +3 -3
- package/dist/agent-runtime/src/subagent-transcripts.js.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.cjs +0 -8
- package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.js +0 -8
- package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
- package/dist/agent-runtime/src/tool-names.cjs +4 -0
- package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-names.d.ts +7 -0
- package/dist/agent-runtime/src/tool-names.js +4 -0
- package/dist/agent-runtime/src/tool-names.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +18 -1
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-runtime.d.ts +19 -10
- package/dist/agent-runtime/src/use-deep-agent-runtime.js +19 -2
- package/dist/agent-runtime/src/use-deep-agent-runtime.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs +28 -10
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.d.ts +35 -3
- package/dist/agent-runtime/src/use-deep-agent-thread.js +28 -10
- package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs +50 -15
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +8 -0
- package/dist/agent-runtime/src/use-deep-agent-voice.js +50 -15
- package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -1
- package/dist/agent-runtime/src/voice-presentation.cjs +2 -0
- package/dist/agent-runtime/src/voice-presentation.cjs.map +1 -1
- package/dist/agent-runtime/src/voice-presentation.js +2 -0
- package/dist/agent-runtime/src/voice-presentation.js.map +1 -1
- package/dist/catalog/runtime-catalog.js +1 -1
- package/dist/chat/AthenaChat.cjs +125 -103
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.d.ts +9 -0
- package/dist/chat/AthenaChat.js +126 -104
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/chat-voice-controls.cjs +128 -0
- package/dist/chat/chat-voice-controls.cjs.map +1 -0
- package/dist/chat/chat-voice-controls.d.ts +19 -0
- package/dist/chat/chat-voice-controls.js +128 -0
- package/dist/chat/chat-voice-controls.js.map +1 -0
- package/dist/chat/super-grouping/SuperGroupingCard.cjs +8 -2
- package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.d.ts +6 -1
- package/dist/chat/super-grouping/SuperGroupingCard.js +8 -2
- package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
- package/dist/chat/super-grouping/ToolTimeline.cjs +27 -0
- package/dist/chat/super-grouping/ToolTimeline.cjs.map +1 -1
- package/dist/chat/super-grouping/ToolTimeline.d.ts +5 -1
- package/dist/chat/super-grouping/ToolTimeline.js +27 -0
- package/dist/chat/super-grouping/ToolTimeline.js.map +1 -1
- package/dist/chat/super-grouping/index.d.ts +1 -0
- package/dist/chat/super-grouping/timeline-step.cjs +61 -2
- package/dist/chat/super-grouping/timeline-step.cjs.map +1 -1
- package/dist/chat/super-grouping/timeline-step.d.ts +13 -1
- package/dist/chat/super-grouping/timeline-step.js +61 -2
- package/dist/chat/super-grouping/timeline-step.js.map +1 -1
- package/dist/chat/use-statewire-approval-request.js +1 -1
- package/dist/chat-ui/composer/tiptap-composer.cjs +42 -22
- package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.d.ts +1 -0
- package/dist/chat-ui/composer/tiptap-composer.js +43 -23
- package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.cjs +144 -35
- package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.d.ts +17 -1
- package/dist/chat-ui/mentions/mention-chip.js +146 -37
- package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +2 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +3 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.js +2 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
- package/dist/chat-ui/mentions/use-account-workspace-id.cjs +29 -51
- package/dist/chat-ui/mentions/use-account-workspace-id.cjs.map +1 -1
- package/dist/chat-ui/mentions/use-account-workspace-id.d.ts +2 -2
- package/dist/chat-ui/mentions/use-account-workspace-id.js +30 -52
- package/dist/chat-ui/mentions/use-account-workspace-id.js.map +1 -1
- package/dist/chat-ui/mentions/use-mention-asset.cjs +140 -0
- package/dist/chat-ui/mentions/use-mention-asset.cjs.map +1 -0
- package/dist/chat-ui/mentions/use-mention-asset.d.ts +16 -0
- package/dist/chat-ui/mentions/use-mention-asset.js +140 -0
- package/dist/chat-ui/mentions/use-mention-asset.js.map +1 -0
- package/dist/chat-ui/rich-text/chat-link.cjs +5 -4
- package/dist/chat-ui/rich-text/chat-link.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-link.d.ts +2 -3
- package/dist/chat-ui/rich-text/chat-link.js +6 -5
- package/dist/chat-ui/rich-text/chat-link.js.map +1 -1
- package/dist/chat-ui/rich-text/chat-node-views.cjs +1 -0
- package/dist/chat-ui/rich-text/chat-node-views.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-node-views.js +1 -0
- package/dist/chat-ui/rich-text/chat-node-views.js.map +1 -1
- package/dist/chat-ui/thread/composer-send-or-stop.cjs +2 -1
- package/dist/chat-ui/thread/composer-send-or-stop.cjs.map +1 -1
- package/dist/chat-ui/thread/composer-send-or-stop.d.ts +2 -0
- package/dist/chat-ui/thread/composer-send-or-stop.js +2 -1
- package/dist/chat-ui/thread/composer-send-or-stop.js.map +1 -1
- package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
- package/dist/diagnostics/athena-diagnostics.d.ts +1 -1
- package/dist/diagnostics/athena-diagnostics.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/references/src/tool-option-schemas.d.ts +0 -34
- package/dist/runtime/statewire-session-key.cjs.map +1 -1
- package/dist/runtime/statewire-session-key.d.ts +8 -5
- package/dist/runtime/statewire-session-key.js.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.cjs +5 -2
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.js +5 -2
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/threads/statewire-thread-list.cjs +6 -2
- package/dist/threads/statewire-thread-list.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.js +6 -2
- package/dist/threads/statewire-thread-list.js.map +1 -1
- package/dist/tools/tool-summary.cjs +0 -2
- package/dist/tools/tool-summary.cjs.map +1 -1
- package/dist/tools/tool-summary.js +0 -2
- package/dist/tools/tool-summary.js.map +1 -1
- package/dist/voice/use-chat-voice-enabled.cjs +43 -0
- package/dist/voice/use-chat-voice-enabled.cjs.map +1 -0
- package/dist/voice/use-chat-voice-enabled.d.ts +9 -0
- package/dist/voice/use-chat-voice-enabled.js +43 -0
- package/dist/voice/use-chat-voice-enabled.js.map +1 -0
- package/package.json +4 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SuperGroupingCard.js","sources":["../../../src/chat/super-grouping/SuperGroupingCard.tsx"],"sourcesContent":["'use client';\n\nimport type {\n AssistantState,\n ReasoningMessagePartComponent,\n TextMessagePartComponent,\n ThreadAssistantMessagePart,\n ToolCallMessagePartComponent,\n ToolCallMessagePartProps,\n} from '@assistant-ui/react';\nimport { MessagePrimitive, useAuiState } from '@assistant-ui/react';\nimport { ChevronRight } from 'lucide-react';\nimport { type ComponentType, memo, type ReactNode, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { cn } from '../../lib/utils';\nimport { isSdkInlineTool } from '../../tools/inline-tools';\nimport { ToolFallback } from '../../tools/tool-fallback';\nimport { collectAssetTitles } from '../../tools/tool-summary';\nimport {\n type ActivityItem,\n type ActivityPhase,\n buildActivityTimeline,\n countActivityTools,\n excludeFinalTextFromGroups,\n excludePartsFromGroups,\n getActivitySummary,\n getFinalTextParts,\n resolveActivityPhase,\n} from './activity-timeline';\nimport { CollapsibleGroup, type CollapsibleGroupProps, SuperGroupingProvider } from './CollapsibleGroup';\nimport { GroupedMessageParts } from './GroupedMessageParts';\nimport { createToolBasedGroupingFunction, type GroupingFunction } from './grouping-function';\nimport { ToolTimeline } from './ToolTimeline';\nimport { toTimelineStep } from './timeline-step';\nimport { defaultGetToolGroupKey, type GetToolGroupKey } from './toolkit-map';\n\nconst DEFAULT_MAX_VISIBLE_STEPS = 3;\nconst MAX_REMEMBERED_EXPANSIONS = 200;\nconst EMPTY_TIMELINE: ActivityItem[] = [];\nconst EMPTY_CONTENT: readonly ThreadAssistantMessagePart[] = [];\n\n/**\n * Whether `next` differs from `previous` only in the words of its last part, a text or reasoning\n * part that is still being written: same length, every earlier part the identical object, and the\n * last parts of the same kind.\n */\nfunction onlyLastPartGrew({\n previous,\n next,\n}: {\n previous: readonly ThreadAssistantMessagePart[];\n next: readonly ThreadAssistantMessagePart[];\n}): boolean {\n if (previous === next) return true;\n if (previous.length === 0 || previous.length !== next.length) return false;\n const lastIndex = next.length - 1;\n const kind = next[lastIndex]?.type;\n if ((kind !== 'text' && kind !== 'reasoning') || previous[lastIndex]?.type !== kind) return false;\n for (let index = 0; index < lastIndex; index += 1) {\n if (previous[index] !== next[index]) return false;\n }\n return true;\n}\n\n/**\n * The card's read of its message's content: the content itself, except that while the message is\n * generating it keeps the previous array when only the last text or reasoning part grew. The card\n * builds its steps from tool calls, their results and reasoning steps, never from those words (the\n * answer renders below it, `SuperGroupingFinalText`), and the turn being generated changes its last\n * part on every streamed token; earlier parts keep their objects across a token (the runtime's\n * conversion cache), so the card re-renders when a step changes, not per token. Any other change,\n * and the run ending, hand over the current content.\n */\nfunction createActivityContentSelector(): (\n state: AssistantState,\n) => readonly ThreadAssistantMessagePart[] {\n let last: readonly ThreadAssistantMessagePart[] = EMPTY_CONTENT;\n return (state) => {\n const message = state.message;\n const content = message.role === 'assistant' ? message.content : EMPTY_CONTENT;\n if (message.status?.type === 'running' && onlyLastPartGrew({ previous: last, next: content })) {\n return last;\n }\n last = content;\n return content;\n };\n}\nconst RUNNING_STATUS = { type: 'running' } as const;\nconst COMPLETE_STATUS = { type: 'complete' } as const;\n\n// ─── Disclosure memory ─────────────────────────────────────────────────\n\n/**\n * Session-local memory of which cards the user opened, keyed by the host's\n * expansion key (the message id by default; the Chrome extension keys by\n * thread + position so a streaming message keeps its choice when it receives\n * its stable id). Bounded so a long session cannot grow it without limit.\n */\nconst rememberedExpansions = new Map<string, boolean>();\n\nfunction rememberExpansion(key: string, expanded: boolean): void {\n rememberedExpansions.delete(key);\n rememberedExpansions.set(key, expanded);\n while (rememberedExpansions.size > MAX_REMEMBERED_EXPANSIONS) {\n const oldestKey = rememberedExpansions.keys().next().value;\n if (oldestKey === undefined) break;\n rememberedExpansions.delete(oldestKey);\n }\n}\n\nexport function resetRememberedExpansionsForTests(): void {\n rememberedExpansions.clear();\n}\n\n/**\n * The details disclosure: remembered per expansion key, and — when the host\n * opts in — opened once when the turn starts waiting on the person, so the\n * approval controls inside the details are visible without a click.\n */\nexport function useActivityExpansion({\n expansionKey,\n phase,\n expandWhileWaiting = false,\n}: {\n expansionKey: string;\n phase: ActivityPhase;\n expandWhileWaiting?: boolean;\n}) {\n const [userExpanded, setUserExpanded] = useState<boolean | undefined>(() =>\n rememberedExpansions.get(expansionKey),\n );\n const [waitingAutoExpanded, setWaitingAutoExpanded] = useState(false);\n const previousRef = useRef({ expansionKey, phase });\n\n useEffect(() => {\n setUserExpanded(rememberedExpansions.get(expansionKey));\n setWaitingAutoExpanded(false);\n }, [expansionKey]);\n\n useEffect(() => {\n const previous = previousRef.current;\n if (expandWhileWaiting && previous.expansionKey === expansionKey) {\n if (previous.phase !== 'waiting' && phase === 'waiting') {\n setWaitingAutoExpanded(true);\n } else if (previous.phase === 'waiting' && phase !== 'waiting') {\n setWaitingAutoExpanded(false);\n }\n }\n previousRef.current = { expansionKey, phase };\n }, [expansionKey, phase, expandWhileWaiting]);\n\n const expanded = waitingAutoExpanded || (userExpanded ?? (expandWhileWaiting && phase === 'waiting'));\n const toggleExpanded = () => {\n const next = !expanded;\n setWaitingAutoExpanded(false);\n rememberExpansion(expansionKey, next);\n setUserExpanded(next);\n };\n\n return { expanded, toggleExpanded };\n}\n\n// ─── Card ──────────────────────────────────────────────────────────────\n\nexport interface SuperGroupingCardProps {\n /** Tool UIs to render inside the details panel, by tool name (registered tool UIs still apply). */\n toolUIs?: Record<string, ToolCallMessagePartComponent>;\n /** Fallback for tools without a UI; the SDK's `ToolFallback` by default. */\n ToolFallback?: ComponentType<ToolCallMessagePartProps>;\n /** Text renderer for the details panel. */\n TextComponent: TextMessagePartComponent;\n /** Reasoning renderer for the details panel. */\n ReasoningComponent?: ReasoningMessagePartComponent;\n /** Per-toolkit block inside the details panel; the SDK's `CollapsibleGroup` by default. */\n GroupComponent?: ComponentType<CollapsibleGroupProps>;\n /** Toolkit lookup driving the per-toolkit sub-grouping; the SDK's static map by default. */\n getToolGroupKey?: GetToolGroupKey;\n /** A complete grouping function, when the host builds its own (overrides `getToolGroupKey`). */\n groupingFunction?: GroupingFunction;\n /** Tools whose unresolved call means the turn is waiting on the person (see `buildActivityTimeline`). */\n waitingTools?: ReadonlySet<string>;\n /**\n * Calls the run is parked on, by tool-call id: each one still without its\n * real result reads as waiting (see `buildActivityTimeline`). Keep the set's\n * identity stable while its ids are unchanged.\n */\n waitingToolCallIds?: ReadonlySet<string>;\n /** Tools whose result is a relayed application payload (see `buildActivityTimeline`). */\n passThroughTools?: ReadonlySet<string>;\n /**\n * Tools whose card renders below the header, outside both disclosures, and\n * stays mounted (an editable email draft, a UI test report). `isSdkInlineTool`\n * by default: the registry's `inline` flag plus the SDK's own report cards.\n */\n isInlineTool?: (toolName: string) => boolean;\n /**\n * Host assertion that the turn is waiting on the person. The SDK derives waiting\n * from `requires-action` and waiting tools itself; no in-repo host passes this.\n */\n waitingForInput?: boolean;\n /** Names tools the shared registry has no entry for (Olympus's tool catalog). */\n resolveToolDisplayName?: (toolName: string) => string | undefined;\n /** Key the disclosure choice is remembered under; the message id by default. */\n expansionKey?: string;\n /** Open the details once when the turn starts waiting on the person. */\n expandWhileWaiting?: boolean;\n /**\n * Keep the details panel mounted (hidden) while collapsed, so a host that\n * needs to find content inside it (a deep link into the run's steps) can.\n */\n mountDetails?: boolean;\n /** Latest steps shown when expanded; unresolved parallel calls always remain visible. */\n maxVisibleSteps?: number;\n /** Extra segments after the collapsed summary (\"1m 23s\", \"12.4k tokens\"), joined with \" · \". */\n summaryDetails?: readonly string[];\n /** Header controls beside the title (a stop button while running, a changes button once done). */\n renderHeaderActions?: (context: {\n phase: ActivityPhase;\n messageContent: readonly ThreadAssistantMessagePart[];\n }) => ReactNode;\n /**\n * Inline on the header row, right of the status, while the turn is running\n * (an elapsed counter). Not rendered while the turn waits on the person.\n */\n renderRunningMeta?: (context: { phase: ActivityPhase }) => ReactNode;\n className?: string;\n classNames?: {\n root?: string;\n details?: string;\n /** The flex column the run's parts render in; override its gap here. */\n detailsParts?: string;\n };\n}\n\n/**\n * The collapsed view (previously called the conversational view) of an\n * assistant turn: a compact current action, an expandable tool timeline, and\n * the original interactive tool UIs behind a separate details disclosure. The\n * answer itself renders below the card (`SuperGroupingFinalText`). Shared by\n * the SDK's `AthenaChat`, Olympus, and the Chrome extension, which supply\n * their own text/tool renderers and the host-specific controls through the\n * slots.\n *\n * The details panel stays mounted (visually hidden) while the turn is live so\n * the tool UIs inside run their effects — an asset-streaming card's follow\n * mode must not wait for \"Show details\".\n *\n * Selector discipline: raw reads only (`message.status`, `message.id`, and the\n * content through `createActivityContentSelector`, which hands back the\n * message's own array or the previous one, never a new array); every\n * derivation runs in `useMemo` — a selector that returned a fresh array would\n * tear through `useSyncExternalStore`.\n */\nexport const SuperGroupingCard = memo(function SuperGroupingCard({\n toolUIs,\n ToolFallback: ToolFallbackComponent = ToolFallback,\n TextComponent,\n ReasoningComponent,\n GroupComponent = CollapsibleGroup,\n getToolGroupKey = defaultGetToolGroupKey,\n groupingFunction,\n waitingTools,\n waitingToolCallIds,\n passThroughTools,\n isInlineTool = isSdkInlineTool,\n waitingForInput = false,\n resolveToolDisplayName,\n expansionKey: expansionKeyProp,\n expandWhileWaiting = false,\n mountDetails = false,\n maxVisibleSteps = DEFAULT_MAX_VISIBLE_STEPS,\n summaryDetails,\n renderHeaderActions,\n renderRunningMeta,\n className,\n classNames,\n}: SuperGroupingCardProps) {\n const messageId = useAuiState((s) => s.message.id);\n const [selectActivityContent] = useState(createActivityContentSelector);\n const messageContent = useAuiState(selectActivityContent);\n const messageStatus = useAuiState((s) => s.message.status);\n\n const timeline = useMemo(() => {\n const items = buildActivityTimeline(messageContent, messageStatus, {\n waitingTools,\n waitingToolCallIds,\n passThroughTools,\n });\n return items.length > 0 ? items : EMPTY_TIMELINE;\n }, [messageContent, messageStatus, waitingTools, waitingToolCallIds, passThroughTools]);\n const phase = useMemo(\n () => resolveActivityPhase(messageStatus, timeline, { waitingForInput }),\n [messageStatus, timeline, waitingForInput],\n );\n const toolCount = countActivityTools(timeline);\n\n const { expanded, toggleExpanded } = useActivityExpansion({\n expansionKey: expansionKeyProp ?? messageId,\n phase,\n expandWhileWaiting,\n });\n const generatedId = useId().replace(/[^A-Za-z0-9_-]/g, '');\n const detailsPanelId = `aui-sg-details-${generatedId}`;\n const statusId = `aui-sg-status-${generatedId}`;\n const { expanded: detailsExpanded, toggleExpanded: toggleDetails } = useActivityExpansion({\n expansionKey: `${expansionKeyProp ?? messageId}:details`,\n phase,\n expandWhileWaiting,\n });\n const assetTitles = useMemo(() => collectAssetTitles(messageContent), [messageContent]);\n const steps = useMemo(\n () =>\n timeline.map((item, index) => toTimelineStep({ item, index, resolveToolDisplayName, assetTitles })),\n [timeline, resolveToolDisplayName, assetTitles],\n );\n\n const inlineParts = useMemo(() => {\n const parts: { index: number; key: string }[] = [];\n messageContent.forEach((part, index) => {\n if (part.type === 'tool-call' && isInlineTool(part.toolName)) {\n parts.push({ index, key: part.toolCallId });\n }\n });\n return parts;\n }, [messageContent, isInlineTool]);\n const grouping = useMemo(\n () =>\n excludePartsFromGroups(\n excludeFinalTextFromGroups(groupingFunction ?? createToolBasedGroupingFunction(getToolGroupKey)),\n (part) => part.type === 'tool-call' && part.toolName !== undefined && isInlineTool(part.toolName),\n ),\n [groupingFunction, getToolGroupKey, isInlineTool],\n );\n const hasDetails = useMemo(() => grouping(messageContent).length > 0, [grouping, messageContent]);\n const isActive = phase === 'running' || phase === 'waiting';\n // The toolkit groups inside keep their tool UIs mounted when the details do.\n const groupingContext = useMemo(\n () => ({ groupingFunction: grouping, mountHidden: isActive || mountDetails }),\n [grouping, isActive, mountDetails],\n );\n const components = useMemo(\n () => ({\n tools: {\n ...(toolUIs ? { by_name: toolUIs } : {}),\n Fallback: ToolFallbackComponent,\n },\n Text: TextComponent,\n ...(ReasoningComponent ? { Reasoning: ReasoningComponent } : {}),\n Group: GroupComponent,\n }),\n [toolUIs, ToolFallbackComponent, TextComponent, ReasoningComponent, GroupComponent],\n );\n\n const hasActivity = timeline.length > 0 || phase !== 'complete';\n if (!hasActivity) return null;\n\n // Tool UIs perform live subscriptions and asset-follow effects. Collapsing\n // either disclosure must only hide them while active or targeted by a deep link.\n const detailsMounted = isActive || mountDetails || (expanded && detailsExpanded);\n const activeSteps = steps.filter((step) => step.state === 'running');\n const currentStep = activeSteps.at(-1);\n const latestStatus =\n phase === 'waiting'\n ? 'Waiting for you'\n : phase === 'error'\n ? messageStatus?.type === 'incomplete' && messageStatus.reason === 'cancelled'\n ? 'Run stopped'\n : 'Something went wrong'\n : phase === 'running'\n ? currentStep\n ? [\n currentStep.verb,\n currentStep.chip,\n activeSteps.length > 1 ? `${activeSteps.length} in progress` : null,\n ]\n .filter(Boolean)\n .join(' · ')\n : steps.length > 0\n ? 'Preparing response'\n : 'Thinking'\n : getActivitySummary(timeline);\n const label = [latestStatus, ...(isActive ? [] : (summaryDetails ?? []))].join(' · ');\n\n return (\n <section\n data-slot=\"super-grouping-card\"\n data-phase={phase}\n data-tool-count={toolCount}\n className={cn('my-3 min-w-0', className, classNames?.root)}\n aria-busy={phase === 'running' ? 'true' : 'false'}\n aria-describedby={statusId}\n >\n <ToolTimeline\n steps={steps}\n open={expanded}\n onOpenChange={toggleExpanded}\n label={label}\n phase={phase}\n maxVisibleSteps={maxVisibleSteps}\n keepMounted={isActive || mountDetails}\n actions={renderHeaderActions?.({ phase, messageContent })}\n meta={phase === 'running' ? renderRunningMeta?.({ phase }) : null}\n >\n {hasDetails ? (\n <div className=\"min-w-0 pl-5\">\n <button\n type=\"button\"\n onClick={toggleDetails}\n aria-expanded={detailsExpanded}\n aria-controls={detailsPanelId}\n className=\"flex items-center gap-1.5 rounded py-1 text-xs text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <ChevronRight\n aria-hidden=\"true\"\n className={cn(\n 'size-3 transition-transform motion-reduce:transition-none',\n detailsExpanded && 'rotate-90',\n )}\n />\n {detailsExpanded ? 'Hide tool details' : 'Show tool details'}\n </button>\n {detailsMounted ? (\n <section\n id={detailsPanelId}\n aria-label=\"Run details\"\n hidden={!expanded || !detailsExpanded}\n className={cn(\n 'min-w-0 overflow-hidden border-l border-border/60 py-2 pl-3',\n classNames?.details,\n )}\n >\n <div className={cn('flex flex-col gap-2', classNames?.detailsParts)}>\n <SuperGroupingProvider value={groupingContext}>\n <GroupedMessageParts groupingFunction={grouping} components={components} />\n </SuperGroupingProvider>\n </div>\n </section>\n ) : null}\n </div>\n ) : null}\n </ToolTimeline>\n {inlineParts.length > 0 ? (\n <div data-slot=\"super-grouping-inline-tools\" className=\"mt-2 flex min-w-0 flex-col gap-2\">\n {inlineParts.map(({ index, key }) => (\n <MessagePrimitive.PartByIndex key={key} index={index} components={components} />\n ))}\n </div>\n ) : null}\n <output id={statusId} aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {phase === 'waiting' ? 'Waiting for your input' : latestStatus}\n </output>\n </section>\n );\n});\n\n/**\n * The turn's visible answer, rendered below the card: the text after the last\n * tool call (all of it when the turn called no tools) and the words of any\n * spoken voice turn the message holds (`getFinalTextParts`), streaming while\n * the turn is live so the person reads the answer as it arrives.\n *\n * Each part renders through its own `TextComponent`, keyed by its content\n * index, so a part only ever grows at its end: a spoken turn streaming while\n * the run's reply streams after it would otherwise change one joined string in\n * the middle, and a streaming reveal restarts from empty on every word. Only\n * the last part carries the running status (and its caret).\n */\nexport const SuperGroupingFinalText = memo(function SuperGroupingFinalText({\n TextComponent,\n}: {\n TextComponent: TextMessagePartComponent;\n}) {\n const messageContent = useAuiState((s) =>\n s.message.role === 'assistant' ? s.message.content : EMPTY_CONTENT,\n );\n const statusType = useAuiState((s) => s.message.status?.type);\n const parts = useMemo(() => getFinalTextParts(messageContent), [messageContent]);\n\n if (parts.length === 0) return null;\n const running = statusType === 'running' || statusType === 'requires-action';\n return (\n <div data-slot=\"super-grouping-final-text\" className=\"flex min-w-0 flex-col gap-1.5\">\n {parts.map((part, position) => (\n <TextComponent\n key={part.index}\n type=\"text\"\n text={part.text}\n status={running && position === parts.length - 1 ? RUNNING_STATUS : COMPLETE_STATUS}\n />\n ))}\n </div>\n );\n});\n"],"names":["SuperGroupingCard","SuperGroupingFinalText"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SuperGroupingCard.js","sources":["../../../src/chat/super-grouping/SuperGroupingCard.tsx"],"sourcesContent":["'use client';\n\nimport type {\n AssistantState,\n ReasoningMessagePartComponent,\n TextMessagePartComponent,\n ThreadAssistantMessagePart,\n ToolCallMessagePartComponent,\n ToolCallMessagePartProps,\n} from '@assistant-ui/react';\nimport { MessagePrimitive, useAuiState } from '@assistant-ui/react';\nimport { ChevronRight } from 'lucide-react';\nimport { type ComponentType, memo, type ReactNode, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { cn } from '../../lib/utils';\nimport { isSdkInlineTool } from '../../tools/inline-tools';\nimport { ToolFallback } from '../../tools/tool-fallback';\nimport { collectAssetTitles } from '../../tools/tool-summary';\nimport {\n type ActivityItem,\n type ActivityPhase,\n buildActivityTimeline,\n countActivityTools,\n excludeFinalTextFromGroups,\n excludePartsFromGroups,\n getActivitySummary,\n getFinalTextParts,\n resolveActivityPhase,\n} from './activity-timeline';\nimport { CollapsibleGroup, type CollapsibleGroupProps, SuperGroupingProvider } from './CollapsibleGroup';\nimport { GroupedMessageParts } from './GroupedMessageParts';\nimport { createToolBasedGroupingFunction, type GroupingFunction } from './grouping-function';\nimport { ToolTimeline } from './ToolTimeline';\nimport { type TimelineStep, toTimelineStep } from './timeline-step';\nimport { defaultGetToolGroupKey, type GetToolGroupKey } from './toolkit-map';\n\nconst DEFAULT_MAX_VISIBLE_STEPS = 3;\nconst MAX_REMEMBERED_EXPANSIONS = 200;\nconst EMPTY_TIMELINE: ActivityItem[] = [];\nconst EMPTY_CONTENT: readonly ThreadAssistantMessagePart[] = [];\n\n/**\n * Whether `next` differs from `previous` only in the words of its last part, a text or reasoning\n * part that is still being written: same length, every earlier part the identical object, and the\n * last parts of the same kind.\n */\nfunction onlyLastPartGrew({\n previous,\n next,\n}: {\n previous: readonly ThreadAssistantMessagePart[];\n next: readonly ThreadAssistantMessagePart[];\n}): boolean {\n if (previous === next) return true;\n if (previous.length === 0 || previous.length !== next.length) return false;\n const lastIndex = next.length - 1;\n const kind = next[lastIndex]?.type;\n if ((kind !== 'text' && kind !== 'reasoning') || previous[lastIndex]?.type !== kind) return false;\n for (let index = 0; index < lastIndex; index += 1) {\n if (previous[index] !== next[index]) return false;\n }\n return true;\n}\n\n/**\n * The card's read of its message's content: the content itself, except that while the message is\n * generating it keeps the previous array when only the last text or reasoning part grew. The card\n * builds its steps from tool calls, their results and reasoning steps, never from those words (the\n * answer renders below it, `SuperGroupingFinalText`), and the turn being generated changes its last\n * part on every streamed token; earlier parts keep their objects across a token (the runtime's\n * conversion cache), so the card re-renders when a step changes, not per token. Any other change,\n * and the run ending, hand over the current content.\n */\nfunction createActivityContentSelector(): (\n state: AssistantState,\n) => readonly ThreadAssistantMessagePart[] {\n let last: readonly ThreadAssistantMessagePart[] = EMPTY_CONTENT;\n return (state) => {\n const message = state.message;\n const content = message.role === 'assistant' ? message.content : EMPTY_CONTENT;\n if (message.status?.type === 'running' && onlyLastPartGrew({ previous: last, next: content })) {\n return last;\n }\n last = content;\n return content;\n };\n}\nconst RUNNING_STATUS = { type: 'running' } as const;\nconst COMPLETE_STATUS = { type: 'complete' } as const;\n\n// ─── Disclosure memory ─────────────────────────────────────────────────\n\n/**\n * Session-local memory of which cards the user opened, keyed by the host's\n * expansion key (the message id by default; the Chrome extension keys by\n * thread + position so a streaming message keeps its choice when it receives\n * its stable id). Bounded so a long session cannot grow it without limit.\n */\nconst rememberedExpansions = new Map<string, boolean>();\n\nfunction rememberExpansion(key: string, expanded: boolean): void {\n rememberedExpansions.delete(key);\n rememberedExpansions.set(key, expanded);\n while (rememberedExpansions.size > MAX_REMEMBERED_EXPANSIONS) {\n const oldestKey = rememberedExpansions.keys().next().value;\n if (oldestKey === undefined) break;\n rememberedExpansions.delete(oldestKey);\n }\n}\n\nexport function resetRememberedExpansionsForTests(): void {\n rememberedExpansions.clear();\n}\n\n/**\n * The details disclosure: remembered per expansion key, and — when the host\n * opts in — opened once when the turn starts waiting on the person, so the\n * approval controls inside the details are visible without a click.\n */\nexport function useActivityExpansion({\n expansionKey,\n phase,\n expandWhileWaiting = false,\n}: {\n expansionKey: string;\n phase: ActivityPhase;\n expandWhileWaiting?: boolean;\n}) {\n const [userExpanded, setUserExpanded] = useState<boolean | undefined>(() =>\n rememberedExpansions.get(expansionKey),\n );\n const [waitingAutoExpanded, setWaitingAutoExpanded] = useState(false);\n const previousRef = useRef({ expansionKey, phase });\n\n useEffect(() => {\n setUserExpanded(rememberedExpansions.get(expansionKey));\n setWaitingAutoExpanded(false);\n }, [expansionKey]);\n\n useEffect(() => {\n const previous = previousRef.current;\n if (expandWhileWaiting && previous.expansionKey === expansionKey) {\n if (previous.phase !== 'waiting' && phase === 'waiting') {\n setWaitingAutoExpanded(true);\n } else if (previous.phase === 'waiting' && phase !== 'waiting') {\n setWaitingAutoExpanded(false);\n }\n }\n previousRef.current = { expansionKey, phase };\n }, [expansionKey, phase, expandWhileWaiting]);\n\n const expanded = waitingAutoExpanded || (userExpanded ?? (expandWhileWaiting && phase === 'waiting'));\n const toggleExpanded = () => {\n const next = !expanded;\n setWaitingAutoExpanded(false);\n rememberExpansion(expansionKey, next);\n setUserExpanded(next);\n };\n\n return { expanded, toggleExpanded };\n}\n\n// ─── Card ──────────────────────────────────────────────────────────────\n\nexport interface SuperGroupingCardProps {\n /** Tool UIs to render inside the details panel, by tool name (registered tool UIs still apply). */\n toolUIs?: Record<string, ToolCallMessagePartComponent>;\n /** Fallback for tools without a UI; the SDK's `ToolFallback` by default. */\n ToolFallback?: ComponentType<ToolCallMessagePartProps>;\n /** Text renderer for the details panel. */\n TextComponent: TextMessagePartComponent;\n /** Reasoning renderer for the details panel. */\n ReasoningComponent?: ReasoningMessagePartComponent;\n /** Per-toolkit block inside the details panel; the SDK's `CollapsibleGroup` by default. */\n GroupComponent?: ComponentType<CollapsibleGroupProps>;\n /** Toolkit lookup driving the per-toolkit sub-grouping; the SDK's static map by default. */\n getToolGroupKey?: GetToolGroupKey;\n /** A complete grouping function, when the host builds its own (overrides `getToolGroupKey`). */\n groupingFunction?: GroupingFunction;\n /** Tools whose unresolved call means the turn is waiting on the person (see `buildActivityTimeline`). */\n waitingTools?: ReadonlySet<string>;\n /**\n * Calls the run is parked on, by tool-call id: each one still without its\n * real result reads as waiting (see `buildActivityTimeline`). Keep the set's\n * identity stable while its ids are unchanged.\n */\n waitingToolCallIds?: ReadonlySet<string>;\n /** Tools whose result is a relayed application payload (see `buildActivityTimeline`). */\n passThroughTools?: ReadonlySet<string>;\n /**\n * Tools whose card renders below the header, outside both disclosures, and\n * stays mounted (an editable email draft, a UI test report). `isSdkInlineTool`\n * by default: the registry's `inline` flag plus the SDK's own report cards.\n */\n isInlineTool?: (toolName: string) => boolean;\n /**\n * Host assertion that the turn is waiting on the person. The SDK derives waiting\n * from `requires-action` and waiting tools itself; no in-repo host passes this.\n */\n waitingForInput?: boolean;\n /** Names tools the shared registry has no entry for (Olympus's tool catalog). */\n resolveToolDisplayName?: (toolName: string) => string | undefined;\n /** Key the disclosure choice is remembered under; the message id by default. */\n expansionKey?: string;\n /** Open the details once when the turn starts waiting on the person. */\n expandWhileWaiting?: boolean;\n /**\n * Keep the details panel mounted (hidden) while collapsed, so a host that\n * needs to find content inside it (a deep link into the run's steps) can.\n */\n mountDetails?: boolean;\n /** Latest steps shown when expanded; unresolved parallel calls always remain visible. */\n maxVisibleSteps?: number;\n /** Extra segments after the collapsed summary (\"1m 23s\", \"12.4k tokens\"), joined with \" · \". */\n summaryDetails?: readonly string[];\n /** Header controls beside the title (a stop button while running, a changes button once done). */\n renderHeaderActions?: (context: {\n phase: ActivityPhase;\n messageContent: readonly ThreadAssistantMessagePart[];\n }) => ReactNode;\n /**\n * Inline on the header row, right of the status, while the turn is running\n * (an elapsed counter). Not rendered while the turn waits on the person.\n */\n renderRunningMeta?: (context: { phase: ActivityPhase }) => ReactNode;\n /** The host's icon for a step's tool, shown on its status row (see `ToolTimeline`). */\n renderStepIcon?: (step: TimelineStep) => ReactNode;\n /** Show the favicons of the sites a finished step's result lists. */\n showSourceFavicons?: boolean;\n className?: string;\n classNames?: {\n root?: string;\n details?: string;\n /** The flex column the run's parts render in; override its gap here. */\n detailsParts?: string;\n };\n}\n\n/**\n * The collapsed view (previously called the conversational view) of an\n * assistant turn: a compact current action, an expandable tool timeline, and\n * the original interactive tool UIs behind a separate details disclosure. The\n * answer itself renders below the card (`SuperGroupingFinalText`). Shared by\n * the SDK's `AthenaChat`, Olympus, and the Chrome extension, which supply\n * their own text/tool renderers and the host-specific controls through the\n * slots.\n *\n * The details panel stays mounted (visually hidden) while the turn is live so\n * the tool UIs inside run their effects — an asset-streaming card's follow\n * mode must not wait for \"Show details\".\n *\n * Selector discipline: raw reads only (`message.status`, `message.id`, and the\n * content through `createActivityContentSelector`, which hands back the\n * message's own array or the previous one, never a new array); every\n * derivation runs in `useMemo` — a selector that returned a fresh array would\n * tear through `useSyncExternalStore`.\n */\nexport const SuperGroupingCard = memo(function SuperGroupingCard({\n toolUIs,\n ToolFallback: ToolFallbackComponent = ToolFallback,\n TextComponent,\n ReasoningComponent,\n GroupComponent = CollapsibleGroup,\n getToolGroupKey = defaultGetToolGroupKey,\n groupingFunction,\n waitingTools,\n waitingToolCallIds,\n passThroughTools,\n isInlineTool = isSdkInlineTool,\n waitingForInput = false,\n resolveToolDisplayName,\n expansionKey: expansionKeyProp,\n expandWhileWaiting = false,\n mountDetails = false,\n maxVisibleSteps = DEFAULT_MAX_VISIBLE_STEPS,\n summaryDetails,\n renderStepIcon,\n showSourceFavicons,\n renderHeaderActions,\n renderRunningMeta,\n className,\n classNames,\n}: SuperGroupingCardProps) {\n const messageId = useAuiState((s) => s.message.id);\n const [selectActivityContent] = useState(createActivityContentSelector);\n const messageContent = useAuiState(selectActivityContent);\n const messageStatus = useAuiState((s) => s.message.status);\n\n const timeline = useMemo(() => {\n const items = buildActivityTimeline(messageContent, messageStatus, {\n waitingTools,\n waitingToolCallIds,\n passThroughTools,\n });\n return items.length > 0 ? items : EMPTY_TIMELINE;\n }, [messageContent, messageStatus, waitingTools, waitingToolCallIds, passThroughTools]);\n const phase = useMemo(\n () => resolveActivityPhase(messageStatus, timeline, { waitingForInput }),\n [messageStatus, timeline, waitingForInput],\n );\n const toolCount = countActivityTools(timeline);\n\n const { expanded, toggleExpanded } = useActivityExpansion({\n expansionKey: expansionKeyProp ?? messageId,\n phase,\n expandWhileWaiting,\n });\n const generatedId = useId().replace(/[^A-Za-z0-9_-]/g, '');\n const detailsPanelId = `aui-sg-details-${generatedId}`;\n const statusId = `aui-sg-status-${generatedId}`;\n const { expanded: detailsExpanded, toggleExpanded: toggleDetails } = useActivityExpansion({\n expansionKey: `${expansionKeyProp ?? messageId}:details`,\n phase,\n expandWhileWaiting,\n });\n const assetTitles = useMemo(() => collectAssetTitles(messageContent), [messageContent]);\n const steps = useMemo(\n () =>\n timeline.map((item, index) =>\n toTimelineStep({ item, index, resolveToolDisplayName, assetTitles, withSourceUrls: showSourceFavicons }),\n ),\n [timeline, resolveToolDisplayName, assetTitles, showSourceFavicons],\n );\n\n const inlineParts = useMemo(() => {\n const parts: { index: number; key: string }[] = [];\n messageContent.forEach((part, index) => {\n if (part.type === 'tool-call' && isInlineTool(part.toolName)) {\n parts.push({ index, key: part.toolCallId });\n }\n });\n return parts;\n }, [messageContent, isInlineTool]);\n const grouping = useMemo(\n () =>\n excludePartsFromGroups(\n excludeFinalTextFromGroups(groupingFunction ?? createToolBasedGroupingFunction(getToolGroupKey)),\n (part) => part.type === 'tool-call' && part.toolName !== undefined && isInlineTool(part.toolName),\n ),\n [groupingFunction, getToolGroupKey, isInlineTool],\n );\n const hasDetails = useMemo(() => grouping(messageContent).length > 0, [grouping, messageContent]);\n const isActive = phase === 'running' || phase === 'waiting';\n // The toolkit groups inside keep their tool UIs mounted when the details do.\n const groupingContext = useMemo(\n () => ({ groupingFunction: grouping, mountHidden: isActive || mountDetails }),\n [grouping, isActive, mountDetails],\n );\n const components = useMemo(\n () => ({\n tools: {\n ...(toolUIs ? { by_name: toolUIs } : {}),\n Fallback: ToolFallbackComponent,\n },\n Text: TextComponent,\n ...(ReasoningComponent ? { Reasoning: ReasoningComponent } : {}),\n Group: GroupComponent,\n }),\n [toolUIs, ToolFallbackComponent, TextComponent, ReasoningComponent, GroupComponent],\n );\n\n const hasActivity = timeline.length > 0 || phase !== 'complete';\n if (!hasActivity) return null;\n\n // Tool UIs perform live subscriptions and asset-follow effects. Collapsing\n // either disclosure must only hide them while active or targeted by a deep link.\n const detailsMounted = isActive || mountDetails || (expanded && detailsExpanded);\n const activeSteps = steps.filter((step) => step.state === 'running');\n const currentStep = activeSteps.at(-1);\n const latestStatus =\n phase === 'waiting'\n ? 'Waiting for you'\n : phase === 'error'\n ? messageStatus?.type === 'incomplete' && messageStatus.reason === 'cancelled'\n ? 'Run stopped'\n : 'Something went wrong'\n : phase === 'running'\n ? currentStep\n ? [\n currentStep.verb,\n currentStep.chip,\n activeSteps.length > 1 ? `${activeSteps.length} in progress` : null,\n ]\n .filter(Boolean)\n .join(' · ')\n : steps.length > 0\n ? 'Preparing response'\n : 'Thinking'\n : getActivitySummary(timeline);\n const label = [latestStatus, ...(isActive ? [] : (summaryDetails ?? []))].join(' · ');\n\n return (\n <section\n data-slot=\"super-grouping-card\"\n data-phase={phase}\n data-tool-count={toolCount}\n className={cn('my-3 min-w-0', className, classNames?.root)}\n aria-busy={phase === 'running' ? 'true' : 'false'}\n aria-describedby={statusId}\n >\n <ToolTimeline\n steps={steps}\n open={expanded}\n onOpenChange={toggleExpanded}\n label={label}\n phase={phase}\n maxVisibleSteps={maxVisibleSteps}\n keepMounted={isActive || mountDetails}\n actions={renderHeaderActions?.({ phase, messageContent })}\n meta={phase === 'running' ? renderRunningMeta?.({ phase }) : null}\n renderStepIcon={renderStepIcon}\n showSourceFavicons={showSourceFavicons}\n >\n {hasDetails ? (\n <div className=\"min-w-0 pl-5\">\n <button\n type=\"button\"\n onClick={toggleDetails}\n aria-expanded={detailsExpanded}\n aria-controls={detailsPanelId}\n className=\"flex items-center gap-1.5 rounded py-1 text-xs text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <ChevronRight\n aria-hidden=\"true\"\n className={cn(\n 'size-3 transition-transform motion-reduce:transition-none',\n detailsExpanded && 'rotate-90',\n )}\n />\n {detailsExpanded ? 'Hide tool details' : 'Show tool details'}\n </button>\n {detailsMounted ? (\n <section\n id={detailsPanelId}\n aria-label=\"Run details\"\n hidden={!expanded || !detailsExpanded}\n className={cn(\n 'min-w-0 overflow-hidden border-l border-border/60 py-2 pl-3',\n classNames?.details,\n )}\n >\n <div className={cn('flex flex-col gap-2', classNames?.detailsParts)}>\n <SuperGroupingProvider value={groupingContext}>\n <GroupedMessageParts groupingFunction={grouping} components={components} />\n </SuperGroupingProvider>\n </div>\n </section>\n ) : null}\n </div>\n ) : null}\n </ToolTimeline>\n {inlineParts.length > 0 ? (\n <div data-slot=\"super-grouping-inline-tools\" className=\"mt-2 flex min-w-0 flex-col gap-2\">\n {inlineParts.map(({ index, key }) => (\n <MessagePrimitive.PartByIndex key={key} index={index} components={components} />\n ))}\n </div>\n ) : null}\n <output id={statusId} aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {phase === 'waiting' ? 'Waiting for your input' : latestStatus}\n </output>\n </section>\n );\n});\n\n/**\n * The turn's visible answer, rendered below the card: the text after the last\n * tool call (all of it when the turn called no tools) and the words of any\n * spoken voice turn the message holds (`getFinalTextParts`), streaming while\n * the turn is live so the person reads the answer as it arrives.\n *\n * Each part renders through its own `TextComponent`, keyed by its content\n * index, so a part only ever grows at its end: a spoken turn streaming while\n * the run's reply streams after it would otherwise change one joined string in\n * the middle, and a streaming reveal restarts from empty on every word. Only\n * the last part carries the running status (and its caret).\n */\nexport const SuperGroupingFinalText = memo(function SuperGroupingFinalText({\n TextComponent,\n}: {\n TextComponent: TextMessagePartComponent;\n}) {\n const messageContent = useAuiState((s) =>\n s.message.role === 'assistant' ? s.message.content : EMPTY_CONTENT,\n );\n const statusType = useAuiState((s) => s.message.status?.type);\n const parts = useMemo(() => getFinalTextParts(messageContent), [messageContent]);\n\n if (parts.length === 0) return null;\n const running = statusType === 'running' || statusType === 'requires-action';\n return (\n <div data-slot=\"super-grouping-final-text\" className=\"flex min-w-0 flex-col gap-1.5\">\n {parts.map((part, position) => (\n <TextComponent\n key={part.index}\n type=\"text\"\n text={part.text}\n status={running && position === parts.length - 1 ? RUNNING_STATUS : COMPLETE_STATUS}\n />\n ))}\n </div>\n );\n});\n"],"names":["SuperGroupingCard","SuperGroupingFinalText"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const jsxRuntime = require("react/jsx-runtime");
|
|
4
4
|
const lucideReact = require("lucide-react");
|
|
5
5
|
const react = require("react");
|
|
6
|
+
const citationAnchors = require("../../chat-ui/rich-text/citation-anchors.cjs");
|
|
6
7
|
const stepText = require("../../tools/step-text.cjs");
|
|
7
8
|
const collapsible = require("../../ui/collapsible.cjs");
|
|
8
9
|
const timelineStep = require("./timeline-step.cjs");
|
|
@@ -21,6 +22,28 @@ function StepIcon({ state }) {
|
|
|
21
22
|
}
|
|
22
23
|
);
|
|
23
24
|
}
|
|
25
|
+
function SourceFavicon({ url }) {
|
|
26
|
+
const [failed, setFailed] = react.useState(false);
|
|
27
|
+
const src = citationAnchors.sourceFaviconUrl(url);
|
|
28
|
+
if (!src || failed) return null;
|
|
29
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
30
|
+
"img",
|
|
31
|
+
{
|
|
32
|
+
src,
|
|
33
|
+
alt: "",
|
|
34
|
+
width: 14,
|
|
35
|
+
height: 14,
|
|
36
|
+
className: "size-3.5 shrink-0 rounded-[3px] ring-2 ring-background [&:not(:first-child)]:-ml-1",
|
|
37
|
+
loading: "lazy",
|
|
38
|
+
referrerPolicy: "no-referrer",
|
|
39
|
+
draggable: false,
|
|
40
|
+
onError: () => setFailed(true)
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
function StepSourceFavicons({ urls }) {
|
|
45
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-slot": "tool-timeline-sources", className: "flex shrink-0 items-center", children: urls.map((url) => /* @__PURE__ */ jsxRuntime.jsx(SourceFavicon, { url }, url)) });
|
|
46
|
+
}
|
|
24
47
|
function ToolTimeline({
|
|
25
48
|
steps,
|
|
26
49
|
open,
|
|
@@ -32,6 +55,8 @@ function ToolTimeline({
|
|
|
32
55
|
keepMounted,
|
|
33
56
|
actions,
|
|
34
57
|
meta,
|
|
58
|
+
renderStepIcon,
|
|
59
|
+
showSourceFavicons = false,
|
|
35
60
|
children
|
|
36
61
|
}) {
|
|
37
62
|
const panelId = react.useId();
|
|
@@ -106,6 +131,7 @@ function ToolTimeline({
|
|
|
106
131
|
className: "flex min-w-0 items-center gap-2 text-[13px] text-muted-foreground",
|
|
107
132
|
children: [
|
|
108
133
|
/* @__PURE__ */ jsxRuntime.jsx(StepIcon, { state: step.state }),
|
|
134
|
+
renderStepIcon == null ? void 0 : renderStepIcon(step),
|
|
109
135
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
110
136
|
"span",
|
|
111
137
|
{
|
|
@@ -118,6 +144,7 @@ function ToolTimeline({
|
|
|
118
144
|
children: /* @__PURE__ */ jsxRuntime.jsx(stepText.StepText, { text: step.verb, code: step.code })
|
|
119
145
|
}
|
|
120
146
|
),
|
|
147
|
+
showSourceFavicons && step.sourceUrls ? /* @__PURE__ */ jsxRuntime.jsx(StepSourceFavicons, { urls: step.sourceUrls }) : null,
|
|
121
148
|
step.chip ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
122
149
|
"span",
|
|
123
150
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolTimeline.cjs","sources":["../../../src/chat/super-grouping/ToolTimeline.tsx"],"sourcesContent":["'use client';\n\n/*!\n * Adapted from assistant-ui's ToolTimeline element:\n * https://github.com/assistant-ui/assistant-ui/blob/main/packages/ui/src/components/react/assistant-ui/elements/tool-timeline.tsx\n * MIT License — Copyright (c) 2025 AgentbaseAI Inc.\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nimport { AlertCircle, Check, ChevronRight, Circle, LoaderCircle, Pause, X } from 'lucide-react';\nimport { type ReactNode, useId, useState } from 'react';\nimport { cn } from '../../lib/utils';\nimport { StepText } from '../../tools/step-text';\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../../ui/collapsible';\nimport type { ActivityPhase } from './activity-timeline';\nimport { type TimelineStep, visibleTimelineSteps } from './timeline-step';\n\nfunction StepIcon({ state }: { state: TimelineStep['state'] }) {\n const Icon =\n state === 'running'\n ? LoaderCircle\n : state === 'complete'\n ? Check\n : state === 'error'\n ? AlertCircle\n : state === 'rejected'\n ? X\n : state === 'paused'\n ? Pause\n : Circle;\n return (\n <Icon\n aria-hidden=\"true\"\n className={cn(\n 'size-3.5 shrink-0',\n state === 'running' && 'motion-safe:animate-spin',\n state === 'error'\n ? 'text-destructive'\n : state === 'waiting' || state === 'paused'\n ? 'text-amber-600 dark:text-amber-400'\n : 'text-muted-foreground',\n )}\n />\n );\n}\n\n/**\n * The upstream disclosure/verb/chip layout, with real per-call states and live\n * tool UIs. `meta` (a host's elapsed counter) sits on the header row itself,\n * right of the status and before `actions`, so a live card carries one status\n * line rather than a second row repeating what the header already says.\n */\nexport function ToolTimeline({\n steps,\n open,\n onOpenChange,\n label,\n labelTitle,\n phase,\n maxVisibleSteps,\n keepMounted,\n actions,\n meta,\n children,\n}: {\n steps: readonly TimelineStep[];\n open: boolean;\n onOpenChange: (open: boolean) => void;\n label: ReactNode;\n /** Tooltip for the header line (the full form of a clipped label). */\n labelTitle?: string;\n phase: ActivityPhase;\n maxVisibleSteps: number;\n keepMounted: boolean;\n actions?: ReactNode;\n meta?: ReactNode;\n children?: ReactNode;\n}) {\n const panelId = useId();\n const [showAll, setShowAll] = useState(false);\n const recentSteps = visibleTimelineSteps({ steps, limit: maxVisibleSteps });\n const shown = showAll ? steps : recentSteps;\n const hiddenCount = steps.length - recentSteps.length;\n return (\n <Collapsible data-slot=\"tool-timeline\" open={open} onOpenChange={onOpenChange} className=\"w-full min-w-0\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <CollapsibleTrigger\n aria-controls={panelId}\n className=\"group/trigger flex min-w-0 flex-1 items-center gap-1.5 rounded-md py-1 text-left text-[13px] text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <ChevronRight\n aria-hidden=\"true\"\n className=\"size-3.5 shrink-0 opacity-60 transition-transform duration-200 group-data-[state=open]/trigger:rotate-90 motion-reduce:transition-none\"\n />\n {phase === 'error' || phase === 'waiting' ? <StepIcon state={phase} /> : null}\n <span\n title={labelTitle}\n className={cn(\n 'min-w-0 break-words leading-5',\n phase === 'running' && 'motion-safe:animate-pulse',\n phase === 'error' && 'text-destructive',\n )}\n >\n {label}\n </span>\n </CollapsibleTrigger>\n {meta ? (\n <div\n data-slot=\"tool-timeline-meta\"\n className=\"flex shrink-0 items-center text-xs text-muted-foreground tabular-nums\"\n >\n {meta}\n </div>\n ) : null}\n {actions ? <div className=\"flex shrink-0 items-center gap-1\">{actions}</div> : null}\n </div>\n <CollapsibleContent\n id={panelId}\n forceMount={keepMounted ? true : undefined}\n hidden={!open}\n className=\"min-w-0\"\n >\n <ol aria-label=\"Work status updates\" className=\"flex list-none flex-col gap-2.5 py-2.5 pl-5\">\n {hiddenCount > 0 ? (\n <li>\n <button\n type=\"button\"\n onClick={() => setShowAll((previous) => !previous)}\n className=\"rounded text-xs text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {showAll\n ? 'Show recent steps'\n : `Show ${hiddenCount} earlier ${hiddenCount === 1 ? 'step' : 'steps'}`}\n </button>\n </li>\n ) : null}\n {shown.map((step) => (\n <li\n key={step.id}\n data-step-id={step.id}\n data-step-state={step.state}\n className=\"flex min-w-0 items-center gap-2 text-[13px] text-muted-foreground\"\n >\n <StepIcon state={step.state} />\n <span\n title={step.detail}\n className={cn(\n 'min-w-0 break-words leading-5',\n step.state === 'error' && 'text-destructive',\n step.state === 'running' && 'text-foreground',\n )}\n >\n <StepText text={step.verb} code={step.code} />\n </span>\n {step.chip ? (\n <span\n title={step.chip}\n className=\"max-w-[45%] truncate rounded-md bg-foreground/[0.06] px-1.5 py-0.5 font-mono text-[11px] text-foreground/70\"\n >\n {step.chip}\n </span>\n ) : null}\n <span className=\"sr-only\">{step.state}</span>\n </li>\n ))}\n </ol>\n {children}\n </CollapsibleContent>\n </Collapsible>\n );\n}\n"],"names":["LoaderCircle","Check","AlertCircle","X","Pause","Circle","jsx","cn","useId","useState","visibleTimelineSteps","Collapsible","jsxs","CollapsibleTrigger","ChevronRight","CollapsibleContent","StepText"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToolTimeline.cjs","sources":["../../../src/chat/super-grouping/ToolTimeline.tsx"],"sourcesContent":["'use client';\n\n/*!\n * Adapted from assistant-ui's ToolTimeline element:\n * https://github.com/assistant-ui/assistant-ui/blob/main/packages/ui/src/components/react/assistant-ui/elements/tool-timeline.tsx\n * MIT License — Copyright (c) 2025 AgentbaseAI Inc.\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nimport { AlertCircle, Check, ChevronRight, Circle, LoaderCircle, Pause, X } from 'lucide-react';\nimport { type ReactNode, useId, useState } from 'react';\nimport { sourceFaviconUrl } from '../../chat-ui/rich-text/citation-anchors';\nimport { cn } from '../../lib/utils';\nimport { StepText } from '../../tools/step-text';\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../../ui/collapsible';\nimport type { ActivityPhase } from './activity-timeline';\nimport { type TimelineStep, visibleTimelineSteps } from './timeline-step';\n\nfunction StepIcon({ state }: { state: TimelineStep['state'] }) {\n const Icon =\n state === 'running'\n ? LoaderCircle\n : state === 'complete'\n ? Check\n : state === 'error'\n ? AlertCircle\n : state === 'rejected'\n ? X\n : state === 'paused'\n ? Pause\n : Circle;\n return (\n <Icon\n aria-hidden=\"true\"\n className={cn(\n 'size-3.5 shrink-0',\n state === 'running' && 'motion-safe:animate-spin',\n state === 'error'\n ? 'text-destructive'\n : state === 'waiting' || state === 'paused'\n ? 'text-amber-600 dark:text-amber-400'\n : 'text-muted-foreground',\n )}\n />\n );\n}\n\nfunction SourceFavicon({ url }: { url: string }) {\n const [failed, setFailed] = useState(false);\n const src = sourceFaviconUrl(url);\n if (!src || failed) return null;\n return (\n <img\n src={src}\n alt=\"\"\n width={14}\n height={14}\n className=\"size-3.5 shrink-0 rounded-[3px] ring-2 ring-background [&:not(:first-child)]:-ml-1\"\n loading=\"lazy\"\n referrerPolicy=\"no-referrer\"\n draggable={false}\n onError={() => setFailed(true)}\n />\n );\n}\n\n/** The sites a step's result came from, as overlapping favicons; one that fails to load is left out. */\nfunction StepSourceFavicons({ urls }: { urls: readonly string[] }) {\n return (\n <span data-slot=\"tool-timeline-sources\" className=\"flex shrink-0 items-center\">\n {urls.map((url) => (\n <SourceFavicon key={url} url={url} />\n ))}\n </span>\n );\n}\n\n/**\n * The upstream disclosure/verb/chip layout, with real per-call states and live\n * tool UIs. `meta` (a host's elapsed counter) sits on the header row itself,\n * right of the status and before `actions`, so a live card carries one status\n * line rather than a second row repeating what the header already says.\n */\nexport function ToolTimeline({\n steps,\n open,\n onOpenChange,\n label,\n labelTitle,\n phase,\n maxVisibleSteps,\n keepMounted,\n actions,\n meta,\n renderStepIcon,\n showSourceFavicons = false,\n children,\n}: {\n steps: readonly TimelineStep[];\n open: boolean;\n onOpenChange: (open: boolean) => void;\n label: ReactNode;\n /** Tooltip for the header line (the full form of a clipped label). */\n labelTitle?: string;\n phase: ActivityPhase;\n maxVisibleSteps: number;\n keepMounted: boolean;\n actions?: ReactNode;\n meta?: ReactNode;\n /** The host's icon for a step's tool (its toolkit icon), after the status icon. */\n renderStepIcon?: (step: TimelineStep) => ReactNode;\n /** Show the favicons of the sites a finished step's result lists. */\n showSourceFavicons?: boolean;\n children?: ReactNode;\n}) {\n const panelId = useId();\n const [showAll, setShowAll] = useState(false);\n const recentSteps = visibleTimelineSteps({ steps, limit: maxVisibleSteps });\n const shown = showAll ? steps : recentSteps;\n const hiddenCount = steps.length - recentSteps.length;\n return (\n <Collapsible data-slot=\"tool-timeline\" open={open} onOpenChange={onOpenChange} className=\"w-full min-w-0\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <CollapsibleTrigger\n aria-controls={panelId}\n className=\"group/trigger flex min-w-0 flex-1 items-center gap-1.5 rounded-md py-1 text-left text-[13px] text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <ChevronRight\n aria-hidden=\"true\"\n className=\"size-3.5 shrink-0 opacity-60 transition-transform duration-200 group-data-[state=open]/trigger:rotate-90 motion-reduce:transition-none\"\n />\n {phase === 'error' || phase === 'waiting' ? <StepIcon state={phase} /> : null}\n <span\n title={labelTitle}\n className={cn(\n 'min-w-0 break-words leading-5',\n phase === 'running' && 'motion-safe:animate-pulse',\n phase === 'error' && 'text-destructive',\n )}\n >\n {label}\n </span>\n </CollapsibleTrigger>\n {meta ? (\n <div\n data-slot=\"tool-timeline-meta\"\n className=\"flex shrink-0 items-center text-xs text-muted-foreground tabular-nums\"\n >\n {meta}\n </div>\n ) : null}\n {actions ? <div className=\"flex shrink-0 items-center gap-1\">{actions}</div> : null}\n </div>\n <CollapsibleContent\n id={panelId}\n forceMount={keepMounted ? true : undefined}\n hidden={!open}\n className=\"min-w-0\"\n >\n <ol aria-label=\"Work status updates\" className=\"flex list-none flex-col gap-2.5 py-2.5 pl-5\">\n {hiddenCount > 0 ? (\n <li>\n <button\n type=\"button\"\n onClick={() => setShowAll((previous) => !previous)}\n className=\"rounded text-xs text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {showAll\n ? 'Show recent steps'\n : `Show ${hiddenCount} earlier ${hiddenCount === 1 ? 'step' : 'steps'}`}\n </button>\n </li>\n ) : null}\n {shown.map((step) => (\n <li\n key={step.id}\n data-step-id={step.id}\n data-step-state={step.state}\n className=\"flex min-w-0 items-center gap-2 text-[13px] text-muted-foreground\"\n >\n <StepIcon state={step.state} />\n {renderStepIcon?.(step)}\n <span\n title={step.detail}\n className={cn(\n 'min-w-0 break-words leading-5',\n step.state === 'error' && 'text-destructive',\n step.state === 'running' && 'text-foreground',\n )}\n >\n <StepText text={step.verb} code={step.code} />\n </span>\n {showSourceFavicons && step.sourceUrls ? <StepSourceFavicons urls={step.sourceUrls} /> : null}\n {step.chip ? (\n <span\n title={step.chip}\n className=\"max-w-[45%] truncate rounded-md bg-foreground/[0.06] px-1.5 py-0.5 font-mono text-[11px] text-foreground/70\"\n >\n {step.chip}\n </span>\n ) : null}\n <span className=\"sr-only\">{step.state}</span>\n </li>\n ))}\n </ol>\n {children}\n </CollapsibleContent>\n </Collapsible>\n );\n}\n"],"names":["LoaderCircle","Check","AlertCircle","X","Pause","Circle","jsx","cn","useState","sourceFaviconUrl","useId","visibleTimelineSteps","Collapsible","jsxs","CollapsibleTrigger","ChevronRight","CollapsibleContent","StepText"],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ import { type TimelineStep } from './timeline-step';
|
|
|
7
7
|
* right of the status and before `actions`, so a live card carries one status
|
|
8
8
|
* line rather than a second row repeating what the header already says.
|
|
9
9
|
*/
|
|
10
|
-
export declare function ToolTimeline({ steps, open, onOpenChange, label, labelTitle, phase, maxVisibleSteps, keepMounted, actions, meta, children, }: {
|
|
10
|
+
export declare function ToolTimeline({ steps, open, onOpenChange, label, labelTitle, phase, maxVisibleSteps, keepMounted, actions, meta, renderStepIcon, showSourceFavicons, children, }: {
|
|
11
11
|
steps: readonly TimelineStep[];
|
|
12
12
|
open: boolean;
|
|
13
13
|
onOpenChange: (open: boolean) => void;
|
|
@@ -19,5 +19,9 @@ export declare function ToolTimeline({ steps, open, onOpenChange, label, labelTi
|
|
|
19
19
|
keepMounted: boolean;
|
|
20
20
|
actions?: ReactNode;
|
|
21
21
|
meta?: ReactNode;
|
|
22
|
+
/** The host's icon for a step's tool (its toolkit icon), after the status icon. */
|
|
23
|
+
renderStepIcon?: (step: TimelineStep) => ReactNode;
|
|
24
|
+
/** Show the favicons of the sites a finished step's result lists. */
|
|
25
|
+
showSourceFavicons?: boolean;
|
|
22
26
|
children?: ReactNode;
|
|
23
27
|
}): import("react").JSX.Element;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { ChevronRight, LoaderCircle, Check, AlertCircle, X, Pause, Circle } from "lucide-react";
|
|
3
3
|
import { useId, useState } from "react";
|
|
4
|
+
import { sourceFaviconUrl } from "../../chat-ui/rich-text/citation-anchors.js";
|
|
4
5
|
import { StepText } from "../../tools/step-text.js";
|
|
5
6
|
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "../../ui/collapsible.js";
|
|
6
7
|
import { visibleTimelineSteps } from "./timeline-step.js";
|
|
@@ -19,6 +20,28 @@ function StepIcon({ state }) {
|
|
|
19
20
|
}
|
|
20
21
|
);
|
|
21
22
|
}
|
|
23
|
+
function SourceFavicon({ url }) {
|
|
24
|
+
const [failed, setFailed] = useState(false);
|
|
25
|
+
const src = sourceFaviconUrl(url);
|
|
26
|
+
if (!src || failed) return null;
|
|
27
|
+
return /* @__PURE__ */ jsx(
|
|
28
|
+
"img",
|
|
29
|
+
{
|
|
30
|
+
src,
|
|
31
|
+
alt: "",
|
|
32
|
+
width: 14,
|
|
33
|
+
height: 14,
|
|
34
|
+
className: "size-3.5 shrink-0 rounded-[3px] ring-2 ring-background [&:not(:first-child)]:-ml-1",
|
|
35
|
+
loading: "lazy",
|
|
36
|
+
referrerPolicy: "no-referrer",
|
|
37
|
+
draggable: false,
|
|
38
|
+
onError: () => setFailed(true)
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
function StepSourceFavicons({ urls }) {
|
|
43
|
+
return /* @__PURE__ */ jsx("span", { "data-slot": "tool-timeline-sources", className: "flex shrink-0 items-center", children: urls.map((url) => /* @__PURE__ */ jsx(SourceFavicon, { url }, url)) });
|
|
44
|
+
}
|
|
22
45
|
function ToolTimeline({
|
|
23
46
|
steps,
|
|
24
47
|
open,
|
|
@@ -30,6 +53,8 @@ function ToolTimeline({
|
|
|
30
53
|
keepMounted,
|
|
31
54
|
actions,
|
|
32
55
|
meta,
|
|
56
|
+
renderStepIcon,
|
|
57
|
+
showSourceFavicons = false,
|
|
33
58
|
children
|
|
34
59
|
}) {
|
|
35
60
|
const panelId = useId();
|
|
@@ -104,6 +129,7 @@ function ToolTimeline({
|
|
|
104
129
|
className: "flex min-w-0 items-center gap-2 text-[13px] text-muted-foreground",
|
|
105
130
|
children: [
|
|
106
131
|
/* @__PURE__ */ jsx(StepIcon, { state: step.state }),
|
|
132
|
+
renderStepIcon == null ? void 0 : renderStepIcon(step),
|
|
107
133
|
/* @__PURE__ */ jsx(
|
|
108
134
|
"span",
|
|
109
135
|
{
|
|
@@ -116,6 +142,7 @@ function ToolTimeline({
|
|
|
116
142
|
children: /* @__PURE__ */ jsx(StepText, { text: step.verb, code: step.code })
|
|
117
143
|
}
|
|
118
144
|
),
|
|
145
|
+
showSourceFavicons && step.sourceUrls ? /* @__PURE__ */ jsx(StepSourceFavicons, { urls: step.sourceUrls }) : null,
|
|
119
146
|
step.chip ? /* @__PURE__ */ jsx(
|
|
120
147
|
"span",
|
|
121
148
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolTimeline.js","sources":["../../../src/chat/super-grouping/ToolTimeline.tsx"],"sourcesContent":["'use client';\n\n/*!\n * Adapted from assistant-ui's ToolTimeline element:\n * https://github.com/assistant-ui/assistant-ui/blob/main/packages/ui/src/components/react/assistant-ui/elements/tool-timeline.tsx\n * MIT License — Copyright (c) 2025 AgentbaseAI Inc.\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nimport { AlertCircle, Check, ChevronRight, Circle, LoaderCircle, Pause, X } from 'lucide-react';\nimport { type ReactNode, useId, useState } from 'react';\nimport { cn } from '../../lib/utils';\nimport { StepText } from '../../tools/step-text';\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../../ui/collapsible';\nimport type { ActivityPhase } from './activity-timeline';\nimport { type TimelineStep, visibleTimelineSteps } from './timeline-step';\n\nfunction StepIcon({ state }: { state: TimelineStep['state'] }) {\n const Icon =\n state === 'running'\n ? LoaderCircle\n : state === 'complete'\n ? Check\n : state === 'error'\n ? AlertCircle\n : state === 'rejected'\n ? X\n : state === 'paused'\n ? Pause\n : Circle;\n return (\n <Icon\n aria-hidden=\"true\"\n className={cn(\n 'size-3.5 shrink-0',\n state === 'running' && 'motion-safe:animate-spin',\n state === 'error'\n ? 'text-destructive'\n : state === 'waiting' || state === 'paused'\n ? 'text-amber-600 dark:text-amber-400'\n : 'text-muted-foreground',\n )}\n />\n );\n}\n\n/**\n * The upstream disclosure/verb/chip layout, with real per-call states and live\n * tool UIs. `meta` (a host's elapsed counter) sits on the header row itself,\n * right of the status and before `actions`, so a live card carries one status\n * line rather than a second row repeating what the header already says.\n */\nexport function ToolTimeline({\n steps,\n open,\n onOpenChange,\n label,\n labelTitle,\n phase,\n maxVisibleSteps,\n keepMounted,\n actions,\n meta,\n children,\n}: {\n steps: readonly TimelineStep[];\n open: boolean;\n onOpenChange: (open: boolean) => void;\n label: ReactNode;\n /** Tooltip for the header line (the full form of a clipped label). */\n labelTitle?: string;\n phase: ActivityPhase;\n maxVisibleSteps: number;\n keepMounted: boolean;\n actions?: ReactNode;\n meta?: ReactNode;\n children?: ReactNode;\n}) {\n const panelId = useId();\n const [showAll, setShowAll] = useState(false);\n const recentSteps = visibleTimelineSteps({ steps, limit: maxVisibleSteps });\n const shown = showAll ? steps : recentSteps;\n const hiddenCount = steps.length - recentSteps.length;\n return (\n <Collapsible data-slot=\"tool-timeline\" open={open} onOpenChange={onOpenChange} className=\"w-full min-w-0\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <CollapsibleTrigger\n aria-controls={panelId}\n className=\"group/trigger flex min-w-0 flex-1 items-center gap-1.5 rounded-md py-1 text-left text-[13px] text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <ChevronRight\n aria-hidden=\"true\"\n className=\"size-3.5 shrink-0 opacity-60 transition-transform duration-200 group-data-[state=open]/trigger:rotate-90 motion-reduce:transition-none\"\n />\n {phase === 'error' || phase === 'waiting' ? <StepIcon state={phase} /> : null}\n <span\n title={labelTitle}\n className={cn(\n 'min-w-0 break-words leading-5',\n phase === 'running' && 'motion-safe:animate-pulse',\n phase === 'error' && 'text-destructive',\n )}\n >\n {label}\n </span>\n </CollapsibleTrigger>\n {meta ? (\n <div\n data-slot=\"tool-timeline-meta\"\n className=\"flex shrink-0 items-center text-xs text-muted-foreground tabular-nums\"\n >\n {meta}\n </div>\n ) : null}\n {actions ? <div className=\"flex shrink-0 items-center gap-1\">{actions}</div> : null}\n </div>\n <CollapsibleContent\n id={panelId}\n forceMount={keepMounted ? true : undefined}\n hidden={!open}\n className=\"min-w-0\"\n >\n <ol aria-label=\"Work status updates\" className=\"flex list-none flex-col gap-2.5 py-2.5 pl-5\">\n {hiddenCount > 0 ? (\n <li>\n <button\n type=\"button\"\n onClick={() => setShowAll((previous) => !previous)}\n className=\"rounded text-xs text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {showAll\n ? 'Show recent steps'\n : `Show ${hiddenCount} earlier ${hiddenCount === 1 ? 'step' : 'steps'}`}\n </button>\n </li>\n ) : null}\n {shown.map((step) => (\n <li\n key={step.id}\n data-step-id={step.id}\n data-step-state={step.state}\n className=\"flex min-w-0 items-center gap-2 text-[13px] text-muted-foreground\"\n >\n <StepIcon state={step.state} />\n <span\n title={step.detail}\n className={cn(\n 'min-w-0 break-words leading-5',\n step.state === 'error' && 'text-destructive',\n step.state === 'running' && 'text-foreground',\n )}\n >\n <StepText text={step.verb} code={step.code} />\n </span>\n {step.chip ? (\n <span\n title={step.chip}\n className=\"max-w-[45%] truncate rounded-md bg-foreground/[0.06] px-1.5 py-0.5 font-mono text-[11px] text-foreground/70\"\n >\n {step.chip}\n </span>\n ) : null}\n <span className=\"sr-only\">{step.state}</span>\n </li>\n ))}\n </ol>\n {children}\n </CollapsibleContent>\n </Collapsible>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToolTimeline.js","sources":["../../../src/chat/super-grouping/ToolTimeline.tsx"],"sourcesContent":["'use client';\n\n/*!\n * Adapted from assistant-ui's ToolTimeline element:\n * https://github.com/assistant-ui/assistant-ui/blob/main/packages/ui/src/components/react/assistant-ui/elements/tool-timeline.tsx\n * MIT License — Copyright (c) 2025 AgentbaseAI Inc.\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nimport { AlertCircle, Check, ChevronRight, Circle, LoaderCircle, Pause, X } from 'lucide-react';\nimport { type ReactNode, useId, useState } from 'react';\nimport { sourceFaviconUrl } from '../../chat-ui/rich-text/citation-anchors';\nimport { cn } from '../../lib/utils';\nimport { StepText } from '../../tools/step-text';\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../../ui/collapsible';\nimport type { ActivityPhase } from './activity-timeline';\nimport { type TimelineStep, visibleTimelineSteps } from './timeline-step';\n\nfunction StepIcon({ state }: { state: TimelineStep['state'] }) {\n const Icon =\n state === 'running'\n ? LoaderCircle\n : state === 'complete'\n ? Check\n : state === 'error'\n ? AlertCircle\n : state === 'rejected'\n ? X\n : state === 'paused'\n ? Pause\n : Circle;\n return (\n <Icon\n aria-hidden=\"true\"\n className={cn(\n 'size-3.5 shrink-0',\n state === 'running' && 'motion-safe:animate-spin',\n state === 'error'\n ? 'text-destructive'\n : state === 'waiting' || state === 'paused'\n ? 'text-amber-600 dark:text-amber-400'\n : 'text-muted-foreground',\n )}\n />\n );\n}\n\nfunction SourceFavicon({ url }: { url: string }) {\n const [failed, setFailed] = useState(false);\n const src = sourceFaviconUrl(url);\n if (!src || failed) return null;\n return (\n <img\n src={src}\n alt=\"\"\n width={14}\n height={14}\n className=\"size-3.5 shrink-0 rounded-[3px] ring-2 ring-background [&:not(:first-child)]:-ml-1\"\n loading=\"lazy\"\n referrerPolicy=\"no-referrer\"\n draggable={false}\n onError={() => setFailed(true)}\n />\n );\n}\n\n/** The sites a step's result came from, as overlapping favicons; one that fails to load is left out. */\nfunction StepSourceFavicons({ urls }: { urls: readonly string[] }) {\n return (\n <span data-slot=\"tool-timeline-sources\" className=\"flex shrink-0 items-center\">\n {urls.map((url) => (\n <SourceFavicon key={url} url={url} />\n ))}\n </span>\n );\n}\n\n/**\n * The upstream disclosure/verb/chip layout, with real per-call states and live\n * tool UIs. `meta` (a host's elapsed counter) sits on the header row itself,\n * right of the status and before `actions`, so a live card carries one status\n * line rather than a second row repeating what the header already says.\n */\nexport function ToolTimeline({\n steps,\n open,\n onOpenChange,\n label,\n labelTitle,\n phase,\n maxVisibleSteps,\n keepMounted,\n actions,\n meta,\n renderStepIcon,\n showSourceFavicons = false,\n children,\n}: {\n steps: readonly TimelineStep[];\n open: boolean;\n onOpenChange: (open: boolean) => void;\n label: ReactNode;\n /** Tooltip for the header line (the full form of a clipped label). */\n labelTitle?: string;\n phase: ActivityPhase;\n maxVisibleSteps: number;\n keepMounted: boolean;\n actions?: ReactNode;\n meta?: ReactNode;\n /** The host's icon for a step's tool (its toolkit icon), after the status icon. */\n renderStepIcon?: (step: TimelineStep) => ReactNode;\n /** Show the favicons of the sites a finished step's result lists. */\n showSourceFavicons?: boolean;\n children?: ReactNode;\n}) {\n const panelId = useId();\n const [showAll, setShowAll] = useState(false);\n const recentSteps = visibleTimelineSteps({ steps, limit: maxVisibleSteps });\n const shown = showAll ? steps : recentSteps;\n const hiddenCount = steps.length - recentSteps.length;\n return (\n <Collapsible data-slot=\"tool-timeline\" open={open} onOpenChange={onOpenChange} className=\"w-full min-w-0\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <CollapsibleTrigger\n aria-controls={panelId}\n className=\"group/trigger flex min-w-0 flex-1 items-center gap-1.5 rounded-md py-1 text-left text-[13px] text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <ChevronRight\n aria-hidden=\"true\"\n className=\"size-3.5 shrink-0 opacity-60 transition-transform duration-200 group-data-[state=open]/trigger:rotate-90 motion-reduce:transition-none\"\n />\n {phase === 'error' || phase === 'waiting' ? <StepIcon state={phase} /> : null}\n <span\n title={labelTitle}\n className={cn(\n 'min-w-0 break-words leading-5',\n phase === 'running' && 'motion-safe:animate-pulse',\n phase === 'error' && 'text-destructive',\n )}\n >\n {label}\n </span>\n </CollapsibleTrigger>\n {meta ? (\n <div\n data-slot=\"tool-timeline-meta\"\n className=\"flex shrink-0 items-center text-xs text-muted-foreground tabular-nums\"\n >\n {meta}\n </div>\n ) : null}\n {actions ? <div className=\"flex shrink-0 items-center gap-1\">{actions}</div> : null}\n </div>\n <CollapsibleContent\n id={panelId}\n forceMount={keepMounted ? true : undefined}\n hidden={!open}\n className=\"min-w-0\"\n >\n <ol aria-label=\"Work status updates\" className=\"flex list-none flex-col gap-2.5 py-2.5 pl-5\">\n {hiddenCount > 0 ? (\n <li>\n <button\n type=\"button\"\n onClick={() => setShowAll((previous) => !previous)}\n className=\"rounded text-xs text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {showAll\n ? 'Show recent steps'\n : `Show ${hiddenCount} earlier ${hiddenCount === 1 ? 'step' : 'steps'}`}\n </button>\n </li>\n ) : null}\n {shown.map((step) => (\n <li\n key={step.id}\n data-step-id={step.id}\n data-step-state={step.state}\n className=\"flex min-w-0 items-center gap-2 text-[13px] text-muted-foreground\"\n >\n <StepIcon state={step.state} />\n {renderStepIcon?.(step)}\n <span\n title={step.detail}\n className={cn(\n 'min-w-0 break-words leading-5',\n step.state === 'error' && 'text-destructive',\n step.state === 'running' && 'text-foreground',\n )}\n >\n <StepText text={step.verb} code={step.code} />\n </span>\n {showSourceFavicons && step.sourceUrls ? <StepSourceFavicons urls={step.sourceUrls} /> : null}\n {step.chip ? (\n <span\n title={step.chip}\n className=\"max-w-[45%] truncate rounded-md bg-foreground/[0.06] px-1.5 py-0.5 font-mono text-[11px] text-foreground/70\"\n >\n {step.chip}\n </span>\n ) : null}\n <span className=\"sr-only\">{step.state}</span>\n </li>\n ))}\n </ol>\n {children}\n </CollapsibleContent>\n </Collapsible>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,7 @@ export { GroupedMessageParts, type GroupedMessagePartsProps } from './GroupedMes
|
|
|
15
15
|
export { createToolBasedGroupingFunction, type GroupablePart, type GroupingFunction, type MessagePartGroup, } from './grouping-function';
|
|
16
16
|
export { resetRememberedExpansionsForTests, SuperGroupingCard, type SuperGroupingCardProps, SuperGroupingFinalText, useActivityExpansion, } from './SuperGroupingCard';
|
|
17
17
|
export { SuperGroupingTranscript, type SuperGroupingTranscriptProps } from './SuperGroupingTranscript';
|
|
18
|
+
export type { TimelineStep } from './timeline-step';
|
|
18
19
|
export { scopeGroupingToSegment, type SegmentablePart, type SegmentSummary, splitTurnSegments, summarizeSegment, type TurnSegment, } from './turn-segments';
|
|
19
20
|
export { formatWorkDuration, readTurnTiming, type TurnTiming, type TurnTimingSources, workedDurationMs, } from './turn-timing';
|
|
20
21
|
export { defaultGetToolGroupKey, type GetToolGroupKey, type ToolGroupKeyOptions } from './toolkit-map';
|
|
@@ -30,7 +30,8 @@ function toTimelineStep({
|
|
|
30
30
|
item,
|
|
31
31
|
index,
|
|
32
32
|
resolveToolDisplayName,
|
|
33
|
-
assetTitles
|
|
33
|
+
assetTitles,
|
|
34
|
+
withSourceUrls = false
|
|
34
35
|
}) {
|
|
35
36
|
const id = item.id ?? `${item.kind}-${index}`;
|
|
36
37
|
if (item.kind !== "tool") {
|
|
@@ -44,8 +45,13 @@ function toTimelineStep({
|
|
|
44
45
|
...summary.detail ? { detail: summary.detail } : {},
|
|
45
46
|
...summary.meta ? { chip: summary.meta } : {},
|
|
46
47
|
state: item.state,
|
|
47
|
-
kind: item.kind
|
|
48
|
+
kind: item.kind,
|
|
49
|
+
toolName: item.toolName
|
|
48
50
|
};
|
|
51
|
+
if (withSourceUrls && item.state === "complete") {
|
|
52
|
+
const sourceUrls = collectSourceUrls(item.result);
|
|
53
|
+
if (sourceUrls.length > 0) step.sourceUrls = sourceUrls;
|
|
54
|
+
}
|
|
49
55
|
const args = item.args;
|
|
50
56
|
if (!args || !item.toolName.startsWith("chrome_")) return step;
|
|
51
57
|
const tabId = args.tabId ?? args.tab_id;
|
|
@@ -69,6 +75,59 @@ function visibleTimelineSteps({ steps, limit }) {
|
|
|
69
75
|
(step, index) => index >= steps.length - safeLimit || step.state === "running" || step.state === "waiting"
|
|
70
76
|
);
|
|
71
77
|
}
|
|
78
|
+
const SOURCE_URL_KEYS = ["url", "link", "href"];
|
|
79
|
+
const MAX_SOURCE_URLS = 3;
|
|
80
|
+
const MAX_SOURCE_DEPTH = 4;
|
|
81
|
+
const MAX_SOURCE_RESULT_CHARS = 256 * 1024;
|
|
82
|
+
function parseJson(text) {
|
|
83
|
+
if (text.length > MAX_SOURCE_RESULT_CHARS) return void 0;
|
|
84
|
+
try {
|
|
85
|
+
return JSON.parse(text);
|
|
86
|
+
} catch {
|
|
87
|
+
return void 0;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function parseResult(result) {
|
|
91
|
+
if (typeof result === "string") return parseJson(result);
|
|
92
|
+
if (Array.isArray(result) && result.length > 0 && result.every(isTextBlock)) {
|
|
93
|
+
return parseJson(result.map((block) => block.text).join(""));
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
function isTextBlock(value) {
|
|
98
|
+
if (typeof value !== "object" || value === null) return false;
|
|
99
|
+
const block = value;
|
|
100
|
+
return block.type === "text" && typeof block.text === "string";
|
|
101
|
+
}
|
|
102
|
+
function collectSourceUrls(result) {
|
|
103
|
+
const urls = [];
|
|
104
|
+
const hosts = /* @__PURE__ */ new Set();
|
|
105
|
+
const visit = ({ value, depth }) => {
|
|
106
|
+
if (urls.length >= MAX_SOURCE_URLS || depth > MAX_SOURCE_DEPTH || value === null) return;
|
|
107
|
+
if (Array.isArray(value)) {
|
|
108
|
+
for (const entry of value) visit({ value: entry, depth: depth + 1 });
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (typeof value !== "object") return;
|
|
112
|
+
const record = value;
|
|
113
|
+
for (const key of SOURCE_URL_KEYS) {
|
|
114
|
+
const candidate = record[key];
|
|
115
|
+
if (typeof candidate !== "string") continue;
|
|
116
|
+
const host = pageTarget(candidate);
|
|
117
|
+
if (host && !hosts.has(host)) {
|
|
118
|
+
hosts.add(host);
|
|
119
|
+
urls.push(candidate);
|
|
120
|
+
}
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
for (const entry of Object.values(record)) {
|
|
124
|
+
if (typeof entry === "object") visit({ value: entry, depth: depth + 1 });
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
visit({ value: parseResult(result), depth: 0 });
|
|
128
|
+
return urls;
|
|
129
|
+
}
|
|
130
|
+
exports.collectSourceUrls = collectSourceUrls;
|
|
72
131
|
exports.toTimelineStep = toTimelineStep;
|
|
73
132
|
exports.visibleTimelineSteps = visibleTimelineSteps;
|
|
74
133
|
//# sourceMappingURL=timeline-step.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline-step.cjs","sources":["../../../src/chat/super-grouping/timeline-step.ts"],"sourcesContent":["import { type ActivityItem, getReasoningLabel, summarizeActivityTool } from './activity-timeline';\n\nexport interface TimelineStep {\n id: string;\n /** The row's line (\"Ran git status\"); `code` marks the literal part of it. */\n verb: string;\n /** The span of `verb` that is literal code (a command, a file name, a pattern). */\n code?: string;\n /** Longer form for the row's tooltip (the full path, the whole command line). */\n detail?: string;\n /** A short chip after the line (\"+4 −1\", \"on jevin-box\", \"Tab 7\"). */\n chip?: string;\n state: ActivityItem['state'];\n kind: ActivityItem['kind'];\n}\n\nconst COMPUTER_ACTIONS: Record<string, readonly [string, string]> = {\n screenshot: ['Taking screenshot', 'Took screenshot'],\n left_click: ['Clicking', 'Clicked'],\n right_click: ['Right-clicking', 'Right-clicked'],\n double_click: ['Double-clicking', 'Double-clicked'],\n triple_click: ['Triple-clicking', 'Triple-clicked'],\n type: ['Typing', 'Typed'],\n key: ['Pressing keys', 'Pressed keys'],\n scroll: ['Scrolling', 'Scrolled'],\n scroll_to: ['Scrolling to element', 'Scrolled to element'],\n zoom: ['Zooming', 'Zoomed'],\n hover: ['Hovering', 'Hovered'],\n left_click_drag: ['Dragging', 'Dragged'],\n wait: ['Waiting', 'Waited'],\n};\n\n/** Keep credentials, query strings, fragments, and typed input out of summary chips. */\nfunction pageTarget(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n try {\n const url = new URL(value);\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return undefined;\n return url.hostname;\n } catch {\n return undefined;\n }\n}\n\nexport function toTimelineStep({\n item,\n index,\n resolveToolDisplayName,\n assetTitles,\n}: {\n item: ActivityItem;\n index: number;\n resolveToolDisplayName?: (toolName: string) => string | undefined;\n /** Titles for asset ids earlier results in the turn named (see `collectAssetTitles`). */\n assetTitles?: ReadonlyMap<string, string>;\n}): TimelineStep {\n const id = item.id ?? `${item.kind}-${index}`;\n if (item.kind !== 'tool') {\n return { id, verb: getReasoningLabel(item.text, item.state), state: item.state, kind: item.kind };\n }\n const summary = summarizeActivityTool(item, resolveToolDisplayName, assetTitles);\n const step: TimelineStep = {\n id,\n verb: summary.label,\n ...(summary.code ? { code: summary.code } : {}),\n ...(summary.detail ? { detail: summary.detail } : {}),\n ...(summary.meta ? { chip: summary.meta } : {}),\n state: item.state,\n kind: item.kind,\n };\n const args = item.args;\n if (!args || !item.toolName.startsWith('chrome_')) return step;\n\n const tabId = args.tabId ?? args.tab_id;\n step.chip = pageTarget(args.url) ?? (typeof tabId === 'number' ? `Tab ${tabId}` : undefined);\n // Only successful/live actions get action-specific tense. Failure, rejection,\n // cancellation and approval copy continues to come from the shared classifier.\n if (item.state !== 'running' && item.state !== 'complete') return step;\n if (item.toolName === 'chrome_computer' && typeof args.action === 'string') {\n const action = COMPUTER_ACTIONS[args.action];\n if (action) step.verb = action[item.state === 'running' ? 0 : 1];\n } else if (item.toolName === 'chrome_navigate') {\n step.verb = item.state === 'running' ? 'Navigating to' : 'Navigated to';\n } else if (item.toolName === 'chrome_batch' && Array.isArray(args.steps)) {\n const count = args.steps.length;\n step.verb = item.state === 'running' ? 'Running Chrome actions' : 'Completed Chrome actions';\n step.chip = `${count} ${count === 1 ? 'action' : 'actions'}`;\n }\n return step;\n}\n\n/** Every unresolved parallel call stays visible even when older settled steps fold away. */\nexport function visibleTimelineSteps({ steps, limit }: { steps: readonly TimelineStep[]; limit: number }) {\n const safeLimit = Number.isFinite(limit) ? Math.max(1, Math.floor(limit)) : 3;\n return steps.filter(\n (step, index) =>\n index >= steps.length - safeLimit || step.state === 'running' || step.state === 'waiting',\n );\n}\n"],"names":["getReasoningLabel","summarizeActivityTool"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"timeline-step.cjs","sources":["../../../src/chat/super-grouping/timeline-step.ts"],"sourcesContent":["import { type ActivityItem, getReasoningLabel, summarizeActivityTool } from './activity-timeline';\n\nexport interface TimelineStep {\n id: string;\n /** The row's line (\"Ran git status\"); `code` marks the literal part of it. */\n verb: string;\n /** The span of `verb` that is literal code (a command, a file name, a pattern). */\n code?: string;\n /** Longer form for the row's tooltip (the full path, the whole command line). */\n detail?: string;\n /** A short chip after the line (\"+4 −1\", \"on jevin-box\", \"Tab 7\"). */\n chip?: string;\n state: ActivityItem['state'];\n kind: ActivityItem['kind'];\n /** The tool a `tool` step called, so a host can show that tool's icon. */\n toolName?: string;\n /** Web pages a finished step's result names (up to three, one per site), for their favicons. */\n sourceUrls?: readonly string[];\n}\n\nconst COMPUTER_ACTIONS: Record<string, readonly [string, string]> = {\n screenshot: ['Taking screenshot', 'Took screenshot'],\n left_click: ['Clicking', 'Clicked'],\n right_click: ['Right-clicking', 'Right-clicked'],\n double_click: ['Double-clicking', 'Double-clicked'],\n triple_click: ['Triple-clicking', 'Triple-clicked'],\n type: ['Typing', 'Typed'],\n key: ['Pressing keys', 'Pressed keys'],\n scroll: ['Scrolling', 'Scrolled'],\n scroll_to: ['Scrolling to element', 'Scrolled to element'],\n zoom: ['Zooming', 'Zoomed'],\n hover: ['Hovering', 'Hovered'],\n left_click_drag: ['Dragging', 'Dragged'],\n wait: ['Waiting', 'Waited'],\n};\n\n/** Keep credentials, query strings, fragments, and typed input out of summary chips. */\nfunction pageTarget(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n try {\n const url = new URL(value);\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return undefined;\n return url.hostname;\n } catch {\n return undefined;\n }\n}\n\nexport function toTimelineStep({\n item,\n index,\n resolveToolDisplayName,\n assetTitles,\n withSourceUrls = false,\n}: {\n item: ActivityItem;\n index: number;\n resolveToolDisplayName?: (toolName: string) => string | undefined;\n /** Titles for asset ids earlier results in the turn named (see `collectAssetTitles`). */\n assetTitles?: ReadonlyMap<string, string>;\n /** Read the web pages a finished result names into `sourceUrls` (only when the card shows favicons). */\n withSourceUrls?: boolean;\n}): TimelineStep {\n const id = item.id ?? `${item.kind}-${index}`;\n if (item.kind !== 'tool') {\n return { id, verb: getReasoningLabel(item.text, item.state), state: item.state, kind: item.kind };\n }\n const summary = summarizeActivityTool(item, resolveToolDisplayName, assetTitles);\n const step: TimelineStep = {\n id,\n verb: summary.label,\n ...(summary.code ? { code: summary.code } : {}),\n ...(summary.detail ? { detail: summary.detail } : {}),\n ...(summary.meta ? { chip: summary.meta } : {}),\n state: item.state,\n kind: item.kind,\n toolName: item.toolName,\n };\n if (withSourceUrls && item.state === 'complete') {\n const sourceUrls = collectSourceUrls(item.result);\n if (sourceUrls.length > 0) step.sourceUrls = sourceUrls;\n }\n const args = item.args;\n if (!args || !item.toolName.startsWith('chrome_')) return step;\n\n const tabId = args.tabId ?? args.tab_id;\n step.chip = pageTarget(args.url) ?? (typeof tabId === 'number' ? `Tab ${tabId}` : undefined);\n // Only successful/live actions get action-specific tense. Failure, rejection,\n // cancellation and approval copy continues to come from the shared classifier.\n if (item.state !== 'running' && item.state !== 'complete') return step;\n if (item.toolName === 'chrome_computer' && typeof args.action === 'string') {\n const action = COMPUTER_ACTIONS[args.action];\n if (action) step.verb = action[item.state === 'running' ? 0 : 1];\n } else if (item.toolName === 'chrome_navigate') {\n step.verb = item.state === 'running' ? 'Navigating to' : 'Navigated to';\n } else if (item.toolName === 'chrome_batch' && Array.isArray(args.steps)) {\n const count = args.steps.length;\n step.verb = item.state === 'running' ? 'Running Chrome actions' : 'Completed Chrome actions';\n step.chip = `${count} ${count === 1 ? 'action' : 'actions'}`;\n }\n return step;\n}\n\n/** Every unresolved parallel call stays visible even when older settled steps fold away. */\nexport function visibleTimelineSteps({ steps, limit }: { steps: readonly TimelineStep[]; limit: number }) {\n const safeLimit = Number.isFinite(limit) ? Math.max(1, Math.floor(limit)) : 3;\n return steps.filter(\n (step, index) =>\n index >= steps.length - safeLimit || step.state === 'running' || step.state === 'waiting',\n );\n}\n\nconst SOURCE_URL_KEYS = ['url', 'link', 'href'] as const;\nconst MAX_SOURCE_URLS = 3;\nconst MAX_SOURCE_DEPTH = 4;\n\nconst MAX_SOURCE_RESULT_CHARS = 256 * 1024;\n\nfunction parseJson(text: string): unknown {\n if (text.length > MAX_SOURCE_RESULT_CHARS) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\n/** A result as JSON: an object, a JSON string, or LangChain text blocks holding JSON. */\nfunction parseResult(result: unknown): unknown {\n if (typeof result === 'string') return parseJson(result);\n if (Array.isArray(result) && result.length > 0 && result.every(isTextBlock)) {\n return parseJson(result.map((block) => block.text).join(''));\n }\n return result;\n}\n\nfunction isTextBlock(value: unknown): value is { type: 'text'; text: string } {\n if (typeof value !== 'object' || value === null) return false;\n const block = value as Record<string, unknown>;\n return block.type === 'text' && typeof block.text === 'string';\n}\n\n/**\n * The web pages a tool result lists (a search's `results[].url`), at most one\n * per site and three in all, in the order the result gives them. Only http(s)\n * links count; anything else in the result is ignored.\n */\nexport function collectSourceUrls(result: unknown): string[] {\n const urls: string[] = [];\n const hosts = new Set<string>();\n const visit = ({ value, depth }: { value: unknown; depth: number }): void => {\n if (urls.length >= MAX_SOURCE_URLS || depth > MAX_SOURCE_DEPTH || value === null) return;\n if (Array.isArray(value)) {\n for (const entry of value) visit({ value: entry, depth: depth + 1 });\n return;\n }\n if (typeof value !== 'object') return;\n const record = value as Record<string, unknown>;\n for (const key of SOURCE_URL_KEYS) {\n const candidate = record[key];\n if (typeof candidate !== 'string') continue;\n const host = pageTarget(candidate);\n if (host && !hosts.has(host)) {\n hosts.add(host);\n urls.push(candidate);\n }\n break;\n }\n for (const entry of Object.values(record)) {\n if (typeof entry === 'object') visit({ value: entry, depth: depth + 1 });\n }\n };\n visit({ value: parseResult(result), depth: 0 });\n return urls;\n}\n"],"names":["getReasoningLabel","summarizeActivityTool"],"mappings":";;;AAoBA,MAAM,mBAA8D;AAAA,EAClE,YAAY,CAAC,qBAAqB,iBAAiB;AAAA,EACnD,YAAY,CAAC,YAAY,SAAS;AAAA,EAClC,aAAa,CAAC,kBAAkB,eAAe;AAAA,EAC/C,cAAc,CAAC,mBAAmB,gBAAgB;AAAA,EAClD,cAAc,CAAC,mBAAmB,gBAAgB;AAAA,EAClD,MAAM,CAAC,UAAU,OAAO;AAAA,EACxB,KAAK,CAAC,iBAAiB,cAAc;AAAA,EACrC,QAAQ,CAAC,aAAa,UAAU;AAAA,EAChC,WAAW,CAAC,wBAAwB,qBAAqB;AAAA,EACzD,MAAM,CAAC,WAAW,QAAQ;AAAA,EAC1B,OAAO,CAAC,YAAY,SAAS;AAAA,EAC7B,iBAAiB,CAAC,YAAY,SAAS;AAAA,EACvC,MAAM,CAAC,WAAW,QAAQ;AAC5B;AAGA,SAAS,WAAW,OAAoC;AACtD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,KAAK;AACzB,QAAI,IAAI,aAAa,WAAW,IAAI,aAAa,SAAU,QAAO;AAClE,WAAO,IAAI;AAAA,EACb,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAiB;AACnB,GAQiB;AACf,QAAM,KAAK,KAAK,MAAM,GAAG,KAAK,IAAI,IAAI,KAAK;AAC3C,MAAI,KAAK,SAAS,QAAQ;AACxB,WAAO,EAAE,IAAI,MAAMA,iBAAAA,kBAAkB,KAAK,MAAM,KAAK,KAAK,GAAG,OAAO,KAAK,OAAO,MAAM,KAAK,KAAA;AAAA,EAC7F;AACA,QAAM,UAAUC,iBAAAA,sBAAsB,MAAM,wBAAwB,WAAW;AAC/E,QAAM,OAAqB;AAAA,IACzB;AAAA,IACA,MAAM,QAAQ;AAAA,IACd,GAAI,QAAQ,OAAO,EAAE,MAAM,QAAQ,KAAA,IAAS,CAAA;AAAA,IAC5C,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAA,IAAW,CAAA;AAAA,IAClD,GAAI,QAAQ,OAAO,EAAE,MAAM,QAAQ,KAAA,IAAS,CAAA;AAAA,IAC5C,OAAO,KAAK;AAAA,IACZ,MAAM,KAAK;AAAA,IACX,UAAU,KAAK;AAAA,EAAA;AAEjB,MAAI,kBAAkB,KAAK,UAAU,YAAY;AAC/C,UAAM,aAAa,kBAAkB,KAAK,MAAM;AAChD,QAAI,WAAW,SAAS,EAAG,MAAK,aAAa;AAAA,EAC/C;AACA,QAAM,OAAO,KAAK;AAClB,MAAI,CAAC,QAAQ,CAAC,KAAK,SAAS,WAAW,SAAS,EAAG,QAAO;AAE1D,QAAM,QAAQ,KAAK,SAAS,KAAK;AACjC,OAAK,OAAO,WAAW,KAAK,GAAG,MAAM,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK;AAGlF,MAAI,KAAK,UAAU,aAAa,KAAK,UAAU,WAAY,QAAO;AAClE,MAAI,KAAK,aAAa,qBAAqB,OAAO,KAAK,WAAW,UAAU;AAC1E,UAAM,SAAS,iBAAiB,KAAK,MAAM;AAC3C,QAAI,aAAa,OAAO,OAAO,KAAK,UAAU,YAAY,IAAI,CAAC;AAAA,EACjE,WAAW,KAAK,aAAa,mBAAmB;AAC9C,SAAK,OAAO,KAAK,UAAU,YAAY,kBAAkB;AAAA,EAC3D,WAAW,KAAK,aAAa,kBAAkB,MAAM,QAAQ,KAAK,KAAK,GAAG;AACxE,UAAM,QAAQ,KAAK,MAAM;AACzB,SAAK,OAAO,KAAK,UAAU,YAAY,2BAA2B;AAClE,SAAK,OAAO,GAAG,KAAK,IAAI,UAAU,IAAI,WAAW,SAAS;AAAA,EAC5D;AACA,SAAO;AACT;AAGO,SAAS,qBAAqB,EAAE,OAAO,SAA4D;AACxG,QAAM,YAAY,OAAO,SAAS,KAAK,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,CAAC,IAAI;AAC5E,SAAO,MAAM;AAAA,IACX,CAAC,MAAM,UACL,SAAS,MAAM,SAAS,aAAa,KAAK,UAAU,aAAa,KAAK,UAAU;AAAA,EAAA;AAEtF;AAEA,MAAM,kBAAkB,CAAC,OAAO,QAAQ,MAAM;AAC9C,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AAEzB,MAAM,0BAA0B,MAAM;AAEtC,SAAS,UAAU,MAAuB;AACxC,MAAI,KAAK,SAAS,wBAAyB,QAAO;AAClD,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,SAAS,YAAY,QAA0B;AAC7C,MAAI,OAAO,WAAW,SAAU,QAAO,UAAU,MAAM;AACvD,MAAI,MAAM,QAAQ,MAAM,KAAK,OAAO,SAAS,KAAK,OAAO,MAAM,WAAW,GAAG;AAC3E,WAAO,UAAU,OAAO,IAAI,CAAC,UAAU,MAAM,IAAI,EAAE,KAAK,EAAE,CAAC;AAAA,EAC7D;AACA,SAAO;AACT;AAEA,SAAS,YAAY,OAAyD;AAC5E,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,QAAQ;AACd,SAAO,MAAM,SAAS,UAAU,OAAO,MAAM,SAAS;AACxD;AAOO,SAAS,kBAAkB,QAA2B;AAC3D,QAAM,OAAiB,CAAA;AACvB,QAAM,4BAAY,IAAA;AAClB,QAAM,QAAQ,CAAC,EAAE,OAAO,YAAqD;AAC3E,QAAI,KAAK,UAAU,mBAAmB,QAAQ,oBAAoB,UAAU,KAAM;AAClF,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,iBAAW,SAAS,MAAO,OAAM,EAAE,OAAO,OAAO,OAAO,QAAQ,GAAG;AACnE;AAAA,IACF;AACA,QAAI,OAAO,UAAU,SAAU;AAC/B,UAAM,SAAS;AACf,eAAW,OAAO,iBAAiB;AACjC,YAAM,YAAY,OAAO,GAAG;AAC5B,UAAI,OAAO,cAAc,SAAU;AACnC,YAAM,OAAO,WAAW,SAAS;AACjC,UAAI,QAAQ,CAAC,MAAM,IAAI,IAAI,GAAG;AAC5B,cAAM,IAAI,IAAI;AACd,aAAK,KAAK,SAAS;AAAA,MACrB;AACA;AAAA,IACF;AACA,eAAW,SAAS,OAAO,OAAO,MAAM,GAAG;AACzC,UAAI,OAAO,UAAU,SAAU,OAAM,EAAE,OAAO,OAAO,OAAO,QAAQ,GAAG;AAAA,IACzE;AAAA,EACF;AACA,QAAM,EAAE,OAAO,YAAY,MAAM,GAAG,OAAO,GAAG;AAC9C,SAAO;AACT;;;;"}
|
|
@@ -11,16 +11,28 @@ export interface TimelineStep {
|
|
|
11
11
|
chip?: string;
|
|
12
12
|
state: ActivityItem['state'];
|
|
13
13
|
kind: ActivityItem['kind'];
|
|
14
|
+
/** The tool a `tool` step called, so a host can show that tool's icon. */
|
|
15
|
+
toolName?: string;
|
|
16
|
+
/** Web pages a finished step's result names (up to three, one per site), for their favicons. */
|
|
17
|
+
sourceUrls?: readonly string[];
|
|
14
18
|
}
|
|
15
|
-
export declare function toTimelineStep({ item, index, resolveToolDisplayName, assetTitles, }: {
|
|
19
|
+
export declare function toTimelineStep({ item, index, resolveToolDisplayName, assetTitles, withSourceUrls, }: {
|
|
16
20
|
item: ActivityItem;
|
|
17
21
|
index: number;
|
|
18
22
|
resolveToolDisplayName?: (toolName: string) => string | undefined;
|
|
19
23
|
/** Titles for asset ids earlier results in the turn named (see `collectAssetTitles`). */
|
|
20
24
|
assetTitles?: ReadonlyMap<string, string>;
|
|
25
|
+
/** Read the web pages a finished result names into `sourceUrls` (only when the card shows favicons). */
|
|
26
|
+
withSourceUrls?: boolean;
|
|
21
27
|
}): TimelineStep;
|
|
22
28
|
/** Every unresolved parallel call stays visible even when older settled steps fold away. */
|
|
23
29
|
export declare function visibleTimelineSteps({ steps, limit }: {
|
|
24
30
|
steps: readonly TimelineStep[];
|
|
25
31
|
limit: number;
|
|
26
32
|
}): TimelineStep[];
|
|
33
|
+
/**
|
|
34
|
+
* The web pages a tool result lists (a search's `results[].url`), at most one
|
|
35
|
+
* per site and three in all, in the order the result gives them. Only http(s)
|
|
36
|
+
* links count; anything else in the result is ignored.
|
|
37
|
+
*/
|
|
38
|
+
export declare function collectSourceUrls(result: unknown): string[];
|