@athenaintel/react 0.32.0 → 0.36.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.
Files changed (167) hide show
  1. package/README.md +148 -9
  2. package/dist/agent-runtime/src/composer-markdown.cjs.map +1 -1
  3. package/dist/agent-runtime/src/composer-markdown.js.map +1 -1
  4. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs +2 -3
  5. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
  6. package/dist/agent-runtime/src/deep-agent-transport-recipe.js +3 -4
  7. package/dist/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
  8. package/dist/agent-runtime/src/edit-command.cjs.map +1 -1
  9. package/dist/agent-runtime/src/edit-command.js.map +1 -1
  10. package/dist/agent-runtime/src/generated/runconfig-contract.cjs +4 -0
  11. package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
  12. package/dist/agent-runtime/src/generated/runconfig-contract.js +4 -0
  13. package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
  14. package/dist/agent-runtime/src/messages.cjs +57 -2
  15. package/dist/agent-runtime/src/messages.cjs.map +1 -1
  16. package/dist/agent-runtime/src/messages.js +57 -2
  17. package/dist/agent-runtime/src/messages.js.map +1 -1
  18. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +24 -3
  19. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
  20. package/dist/agent-runtime/src/quota-safe-local-storage-session.js +24 -3
  21. package/dist/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
  22. package/dist/agent-runtime/src/statewire-transport.cjs +4 -13
  23. package/dist/agent-runtime/src/statewire-transport.cjs.map +1 -1
  24. package/dist/agent-runtime/src/statewire-transport.js +5 -14
  25. package/dist/agent-runtime/src/statewire-transport.js.map +1 -1
  26. package/dist/agent-runtime/src/tool-metadata.cjs +12 -1
  27. package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
  28. package/dist/agent-runtime/src/tool-metadata.js +12 -1
  29. package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
  30. package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  31. package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
  32. package/dist/assets/AthenaAssetEmbed.cjs +3 -1
  33. package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
  34. package/dist/assets/AthenaAssetEmbed.d.ts +7 -0
  35. package/dist/assets/AthenaAssetEmbed.js +4 -2
  36. package/dist/assets/AthenaAssetEmbed.js.map +1 -1
  37. package/dist/assets/use-asset-embed.cjs +71 -71
  38. package/dist/assets/use-asset-embed.cjs.map +1 -1
  39. package/dist/assets/use-asset-embed.d.ts +20 -7
  40. package/dist/assets/use-asset-embed.js +72 -72
  41. package/dist/assets/use-asset-embed.js.map +1 -1
  42. package/dist/catalog/agent-mode-menu.cjs +115 -0
  43. package/dist/catalog/agent-mode-menu.cjs.map +1 -0
  44. package/dist/catalog/agent-mode-menu.d.ts +101 -0
  45. package/dist/catalog/agent-mode-menu.js +115 -0
  46. package/dist/catalog/agent-mode-menu.js.map +1 -0
  47. package/dist/catalog/agent-model-options.cjs +122 -0
  48. package/dist/catalog/agent-model-options.cjs.map +1 -0
  49. package/dist/catalog/agent-model-options.d.ts +115 -0
  50. package/dist/catalog/agent-model-options.js +122 -0
  51. package/dist/catalog/agent-model-options.js.map +1 -0
  52. package/dist/catalog/chat-pickers.cjs +235 -4
  53. package/dist/catalog/chat-pickers.cjs.map +1 -1
  54. package/dist/catalog/chat-pickers.d.ts +55 -3
  55. package/dist/catalog/chat-pickers.js +238 -7
  56. package/dist/catalog/chat-pickers.js.map +1 -1
  57. package/dist/catalog/runtime-catalog.cjs +121 -3
  58. package/dist/catalog/runtime-catalog.cjs.map +1 -1
  59. package/dist/catalog/runtime-catalog.d.ts +120 -0
  60. package/dist/catalog/runtime-catalog.js +124 -6
  61. package/dist/catalog/runtime-catalog.js.map +1 -1
  62. package/dist/catalog/use-athena-chat-mode.cjs +139 -0
  63. package/dist/catalog/use-athena-chat-mode.cjs.map +1 -0
  64. package/dist/catalog/use-athena-chat-mode.d.ts +43 -0
  65. package/dist/catalog/use-athena-chat-mode.js +139 -0
  66. package/dist/catalog/use-athena-chat-mode.js.map +1 -0
  67. package/dist/chat/AthenaChat.cjs +2 -0
  68. package/dist/chat/AthenaChat.cjs.map +1 -1
  69. package/dist/chat/AthenaChat.d.ts +8 -7
  70. package/dist/chat/AthenaChat.js +2 -0
  71. package/dist/chat/AthenaChat.js.map +1 -1
  72. package/dist/chat/super-grouping/SuperGroupingCard.cjs +30 -3
  73. package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
  74. package/dist/chat/super-grouping/SuperGroupingCard.d.ts +12 -9
  75. package/dist/chat/super-grouping/SuperGroupingCard.js +31 -4
  76. package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
  77. package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
  78. package/dist/chat/super-grouping/SuperGroupingTranscript.d.ts +8 -8
  79. package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
  80. package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
  81. package/dist/chat/super-grouping/activity-timeline.d.ts +4 -4
  82. package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
  83. package/dist/chat/super-grouping/index.d.ts +6 -5
  84. package/dist/chat/super-grouping/toolkit-map.cjs +3 -1
  85. package/dist/chat/super-grouping/toolkit-map.cjs.map +1 -1
  86. package/dist/chat/super-grouping/toolkit-map.js +3 -1
  87. package/dist/chat/super-grouping/toolkit-map.js.map +1 -1
  88. package/dist/chat-ui/index.cjs +1 -0
  89. package/dist/chat-ui/index.cjs.map +1 -1
  90. package/dist/chat-ui/index.d.ts +1 -1
  91. package/dist/chat-ui/index.js +2 -1
  92. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +33 -2
  93. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
  94. package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +14 -0
  95. package/dist/chat-ui/mentions/suggestions/data/api-client.js +33 -2
  96. package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
  97. package/dist/chat-ui/statewire.cjs +3 -0
  98. package/dist/chat-ui/statewire.cjs.map +1 -1
  99. package/dist/chat-ui/statewire.d.ts +4 -2
  100. package/dist/chat-ui/statewire.js +3 -0
  101. package/dist/chat-ui/statewire.js.map +1 -1
  102. package/dist/index.cjs +4 -0
  103. package/dist/index.cjs.map +1 -1
  104. package/dist/index.d.ts +7 -4
  105. package/dist/index.js +6 -2
  106. package/dist/index.js.map +1 -1
  107. package/dist/lib/use-athena-rest-query.cjs +4 -0
  108. package/dist/lib/use-athena-rest-query.cjs.map +1 -1
  109. package/dist/lib/use-athena-rest-query.d.ts +6 -0
  110. package/dist/lib/use-athena-rest-query.js +4 -0
  111. package/dist/lib/use-athena-rest-query.js.map +1 -1
  112. package/dist/provider/AthenaProvider.cjs +81 -9
  113. package/dist/provider/AthenaProvider.cjs.map +1 -1
  114. package/dist/provider/AthenaProvider.d.ts +25 -5
  115. package/dist/provider/AthenaProvider.js +83 -11
  116. package/dist/provider/AthenaProvider.js.map +1 -1
  117. package/dist/provider/agent-selection-context.cjs +6 -0
  118. package/dist/provider/agent-selection-context.cjs.map +1 -0
  119. package/dist/provider/agent-selection-context.d.ts +14 -0
  120. package/dist/provider/agent-selection-context.js +6 -0
  121. package/dist/provider/agent-selection-context.js.map +1 -0
  122. package/dist/provider/chat-mode-context.cjs +6 -0
  123. package/dist/provider/chat-mode-context.cjs.map +1 -0
  124. package/dist/provider/chat-mode-context.d.ts +35 -0
  125. package/dist/provider/chat-mode-context.js +6 -0
  126. package/dist/provider/chat-mode-context.js.map +1 -0
  127. package/dist/react/package.json.cjs +1 -1
  128. package/dist/react/package.json.js +1 -1
  129. package/dist/runtime/StatewireThreadConfigLaneSync.cjs +125 -0
  130. package/dist/runtime/StatewireThreadConfigLaneSync.cjs.map +1 -0
  131. package/dist/runtime/StatewireThreadConfigLaneSync.d.ts +54 -0
  132. package/dist/runtime/StatewireThreadConfigLaneSync.js +125 -0
  133. package/dist/runtime/StatewireThreadConfigLaneSync.js.map +1 -0
  134. package/dist/runtime/statewire-model-lane.cjs +0 -12
  135. package/dist/runtime/statewire-model-lane.cjs.map +1 -1
  136. package/dist/runtime/statewire-model-lane.d.ts +3 -1
  137. package/dist/runtime/statewire-model-lane.js +0 -12
  138. package/dist/runtime/statewire-model-lane.js.map +1 -1
  139. package/dist/runtime/statewire-run-config.cjs +10 -6
  140. package/dist/runtime/statewire-run-config.cjs.map +1 -1
  141. package/dist/runtime/statewire-run-config.d.ts +7 -0
  142. package/dist/runtime/statewire-run-config.js +10 -6
  143. package/dist/runtime/statewire-run-config.js.map +1 -1
  144. package/dist/runtime/statewire-server-lane-context.cjs.map +1 -1
  145. package/dist/runtime/statewire-server-lane-context.d.ts +2 -2
  146. package/dist/runtime/statewire-server-lane-context.js.map +1 -1
  147. package/dist/runtime/statewire-thread-config-lane.cjs +84 -0
  148. package/dist/runtime/statewire-thread-config-lane.cjs.map +1 -0
  149. package/dist/runtime/statewire-thread-config-lane.d.ts +94 -0
  150. package/dist/runtime/statewire-thread-config-lane.js +84 -0
  151. package/dist/runtime/statewire-thread-config-lane.js.map +1 -0
  152. package/dist/runtime/useAthenaStatewireRuntime.cjs +4 -2
  153. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  154. package/dist/runtime/useAthenaStatewireRuntime.d.ts +2 -0
  155. package/dist/runtime/useAthenaStatewireRuntime.js +4 -2
  156. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  157. package/dist/threads/use-athena-thread-model.cjs +11 -3
  158. package/dist/threads/use-athena-thread-model.cjs.map +1 -1
  159. package/dist/threads/use-athena-thread-model.d.ts +5 -0
  160. package/dist/threads/use-athena-thread-model.js +12 -4
  161. package/dist/threads/use-athena-thread-model.js.map +1 -1
  162. package/package.json +3 -3
  163. package/dist/runtime/StatewireModelLaneSync.cjs +0 -96
  164. package/dist/runtime/StatewireModelLaneSync.cjs.map +0 -1
  165. package/dist/runtime/StatewireModelLaneSync.d.ts +0 -45
  166. package/dist/runtime/StatewireModelLaneSync.js +0 -96
  167. package/dist/runtime/StatewireModelLaneSync.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"SuperGroupingTranscript.js","sources":["../../../src/chat/super-grouping/SuperGroupingTranscript.tsx"],"sourcesContent":["'use client';\n\nimport { isInlineTool as isRegistryInlineTool } from '@athenaintel/agent-runtime';\nimport {\n getExternalStoreMessages,\n MessagePrimitive,\n type TextMessagePartComponent,\n type ThreadAssistantMessagePart,\n useAuiState,\n} from '@assistant-ui/react';\nimport { AlertCircle, Check, ChevronRight, Circle, LoaderCircle } from 'lucide-react';\nimport { memo, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { cn } from '../../lib/utils';\nimport { StepText } from '../../tools/step-text';\nimport { ToolFallback } from '../../tools/tool-fallback';\nimport { collectAssetTitles } from '../../tools/tool-summary';\nimport { readMessageCreatedAt } from '../message-time';\nimport {\n type ActivityPhase,\n buildActivityTimeline,\n countActivityTools,\n excludePartsFromGroups,\n getActivitySummary,\n resolveActivityPhase,\n} from './activity-timeline';\nimport { CollapsibleGroup, SuperGroupingProvider } from './CollapsibleGroup';\nimport { createToolBasedGroupingFunction, type GroupingFunction } from './grouping-function';\nimport { type SuperGroupingCardProps, useActivityExpansion } from './SuperGroupingCard';\nimport { ToolTimeline } from './ToolTimeline';\nimport { type TimelineStep, toTimelineStep } from './timeline-step';\nimport { defaultGetToolGroupKey } from './toolkit-map';\nimport {\n scopeGroupingToSegment,\n splitTurnSegments,\n summarizeSegment,\n type TurnSegment,\n} from './turn-segments';\nimport {\n firstSeenMs,\n formatWorkDuration,\n observedTurnEndMs,\n readTurnTiming,\n recordObservedTurnEnd,\n type TurnTiming,\n workedDurationMs,\n workingLabel,\n} from './turn-timing';\n\nconst DEFAULT_MAX_VISIBLE_STEPS = 6;\nconst EMPTY_CONTENT: readonly ThreadAssistantMessagePart[] = [];\nconst EMPTY_STEPS: readonly TimelineStep[] = [];\n\nexport interface SuperGroupingTranscriptProps\n extends Pick<\n SuperGroupingCardProps,\n | 'toolUIs'\n | 'ToolFallback'\n | 'TextComponent'\n | 'ReasoningComponent'\n | 'GroupComponent'\n | 'getToolGroupKey'\n | 'groupingFunction'\n | 'isInlineTool'\n | 'waitingTools'\n | 'passThroughTools'\n | 'waitingForInput'\n | 'resolveToolDisplayName'\n | 'expansionKey'\n | 'expandWhileWaiting'\n | 'mountDetails'\n | 'summaryDetails'\n | 'renderHeaderActions'\n | 'renderRunningMeta'\n | 'className'\n > {\n /** Steps an opened segment lists before older ones fold away; unresolved calls always show. */\n maxVisibleSteps?: number;\n classNames?: {\n root?: string;\n header?: string;\n body?: string;\n details?: string;\n /** The flex column a segment's parts render in; override its gap here. */\n detailsParts?: string;\n };\n}\n\n// ─── Turn timing ───────────────────────────────────────────────────────\n\n/**\n * The turn's stamps: the prompt it answers, its joined metadata, and the raw\n * messages behind it. Reads the whole message (the bound raw messages hang off\n * it), so only the small header status subscribes here, never the transcript.\n */\nfunction useTurnTimingSources(): { timing: TurnTiming; clockKey: string } {\n const message = useAuiState((s) => s.message);\n const promptCreatedAt = useAuiState((s) => {\n const previous = s.thread.messages[s.message.index - 1];\n return previous?.role === 'user' ? readMessageCreatedAt(previous.metadata?.custom) : null;\n });\n const promptId = useAuiState((s) => {\n const previous = s.thread.messages[s.message.index - 1];\n return previous?.role === 'user' ? previous.id : '';\n });\n const timing = useMemo(\n () =>\n readTurnTiming({\n promptCreatedAt,\n custom: message.metadata?.custom,\n sourceMessages: getExternalStoreMessages<unknown>(message),\n }),\n [message, promptCreatedAt],\n );\n return { timing, clockKey: `${promptId}:${message.id}` };\n}\n\n/** \"Working for 1m 12s\", re-rendered once a second by itself so the transcript does not. */\nfunction WorkingFor({ startMs, clockKey }: { startMs: number | null; clockKey: string }) {\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n const timer = setInterval(() => setNow(Date.now()), 1000);\n return () => clearInterval(timer);\n }, []);\n const anchor = startMs ?? firstSeenMs(clockKey, now);\n return <>{workingLabel(Math.max(0, now - anchor))}</>;\n}\n\n/**\n * The header's words: \"Working for 1m 12s\" while the turn runs, \"Worked for\n * 2m 30s · Used 7 tools\" once done, \"Waiting for you\", or how it ended.\n */\nfunction TurnStatus({\n phase,\n cancelled,\n activitySummary,\n toolCount,\n summaryDetails,\n}: {\n phase: ActivityPhase;\n cancelled: boolean;\n activitySummary: string;\n toolCount: number;\n summaryDetails: readonly string[] | undefined;\n}) {\n const { timing, clockKey } = useTurnTimingSources();\n const [observedEndMs, setObservedEndMs] = useState(() => observedTurnEndMs(clockKey));\n const wasActive = useRef(phase === 'running' || phase === 'waiting');\n useEffect(() => {\n const active = phase === 'running' || phase === 'waiting';\n if (wasActive.current && !active) setObservedEndMs(recordObservedTurnEnd(clockKey));\n wasActive.current = active;\n }, [phase, clockKey]);\n if (phase === 'running') return <WorkingFor startMs={timing.startMs} clockKey={clockKey} />;\n if (phase === 'waiting') return <>Waiting for you</>;\n const workedMs = workedDurationMs(timing, observedEndMs);\n if (phase === 'error') {\n if (!cancelled) return <>Something went wrong</>;\n return <>{workedMs !== null ? `Run stopped after ${formatWorkDuration(workedMs)}` : 'Run stopped'}</>;\n }\n const label = [\n ...(workedMs !== null ? [`Worked for ${formatWorkDuration(workedMs)}`] : []),\n ...(workedMs === null || toolCount > 0 || activitySummary !== 'Reasoning complete' ? [activitySummary] : []),\n ...(summaryDetails ?? []),\n ].join(' · ');\n return <>{label}</>;\n}\n\nfunction TurnGlyph({ phase }: { phase: ActivityPhase }) {\n const className = 'size-3.5 shrink-0';\n if (phase === 'running') {\n return <LoaderCircle aria-hidden=\"true\" className={cn(className, 'motion-safe:animate-spin')} />;\n }\n if (phase === 'waiting') {\n return <Circle aria-hidden=\"true\" className={cn(className, 'text-amber-600 dark:text-amber-400')} />;\n }\n if (phase === 'error') {\n return <AlertCircle aria-hidden=\"true\" className={cn(className, 'text-destructive')} />;\n }\n return <Check aria-hidden=\"true\" className={cn(className, 'opacity-70')} />;\n}\n\n// ─── Segments ──────────────────────────────────────────────────────────\n\nconst ProseSegment = memo(function ProseSegment({\n text,\n TextComponent,\n}: {\n text: string;\n TextComponent: TextMessagePartComponent;\n}) {\n return (\n <div data-slot=\"transcript-prose\" className=\"min-w-0\">\n <TextComponent type=\"text\" text={text} status={{ type: 'complete' }} />\n </div>\n );\n});\n\ninterface ActivitySegmentProps {\n segment: Extract<TurnSegment, { kind: 'activity' }>;\n steps: readonly TimelineStep[];\n turnPhase: ActivityPhase;\n expansionKey: string;\n expandWhileWaiting: boolean;\n mountDetails: boolean;\n maxVisibleSteps: number;\n grouping: GroupingFunction;\n /** This segment's inline tool calls (an editable draft), rendered outside its disclosures. */\n inlineParts: readonly { index: number; key: string }[];\n /** False when every step's UI renders inline, so there is nothing behind \"Show tool details\". */\n hasDetails: boolean;\n components: Parameters<typeof MessagePrimitive.Unstable_PartsGrouped>[0]['components'];\n classNames: SuperGroupingTranscriptProps['classNames'];\n}\n\n/**\n * One collapsed run of work between two of the agent's sentences: the step in\n * progress (or the last one taken) on one line, the segment's steps when\n * opened, and the tool UIs of just this segment behind \"Show tool details\".\n * The tool UIs stay mounted (hidden) while the turn is live so their effects\n * run, as in `SuperGroupingCard`.\n */\nfunction ActivitySegment({\n segment,\n steps,\n turnPhase,\n expansionKey,\n expandWhileWaiting,\n mountDetails,\n maxVisibleSteps,\n grouping,\n inlineParts,\n hasDetails,\n components,\n classNames,\n}: ActivitySegmentProps) {\n const summary = summarizeSegment(steps);\n const phase = summary.phase;\n const { expanded, toggleExpanded } = useActivityExpansion({\n expansionKey: `${expansionKey}:${segment.key}`,\n phase,\n expandWhileWaiting,\n });\n const { expanded: detailsExpanded, toggleExpanded: toggleDetails } = useActivityExpansion({\n expansionKey: `${expansionKey}:${segment.key}:details`,\n phase,\n expandWhileWaiting,\n });\n const indicesKey = segment.partIndices.join(',');\n const scopedGrouping = useMemo(\n () => scopeGroupingToSegment(grouping, indicesKey.split(',').map(Number)),\n [grouping, indicesKey],\n );\n const groupingContext = useMemo(() => ({ groupingFunction: scopedGrouping }), [scopedGrouping]);\n const detailsPanelId = `aui-sg-segment-${useId().replace(/[^A-Za-z0-9_-]/g, '')}`;\n\n const isTurnActive = turnPhase === 'running' || turnPhase === 'waiting';\n const detailsMounted = isTurnActive || mountDetails || (expanded && detailsExpanded);\n const hasToolSteps = steps.some((step) => step.kind === 'tool');\n const meta = [summary.step?.chip, summary.meta].filter(Boolean).join(' · ');\n\n // Parts with no step of their own (an image the agent produced) are content, not work.\n if (steps.length === 0) {\n return (\n <div data-slot=\"transcript-parts\" className={cn('flex min-w-0 flex-col gap-2', classNames?.detailsParts)}>\n <SuperGroupingProvider value={groupingContext}>\n <MessagePrimitive.Unstable_PartsGrouped groupingFunction={scopedGrouping} components={components} />\n </SuperGroupingProvider>\n </div>\n );\n }\n\n return (\n <div data-slot=\"activity-segment\" data-phase={phase} data-segment-key={segment.key} className=\"min-w-0\">\n <ToolTimeline\n steps={steps}\n open={expanded}\n onOpenChange={toggleExpanded}\n label={<StepText text={summary.label} code={summary.step?.code} />}\n labelTitle={summary.step?.detail}\n phase={phase}\n maxVisibleSteps={maxVisibleSteps}\n keepMounted={isTurnActive || mountDetails}\n meta={meta ? <span data-slot=\"activity-segment-meta\">{meta}</span> : 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\n ? hasToolSteps\n ? 'Hide tool details'\n : 'Hide thinking'\n : hasToolSteps\n ? 'Show tool details'\n : 'Show thinking'}\n </button>\n {detailsMounted ? (\n <section\n id={detailsPanelId}\n aria-label=\"Step 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 <MessagePrimitive.Unstable_PartsGrouped groupingFunction={scopedGrouping} components={components} />\n </SuperGroupingProvider>\n </div>\n </section>\n ) : null}\n </div>\n ) : null}\n </ToolTimeline>\n {inlineParts.length > 0 ? (\n <div data-slot=\"activity-segment-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 </div>\n );\n}\n\n// ─── Transcript ────────────────────────────────────────────────────────\n\n/**\n * The grouped (\"conversational\") view of an assistant turn as a transcript:\n * a header that says how long the turn has been working (\"Working for\n * 1m 12s\", then \"Worked for 2m 30s\"), then the agent's own sentences in the\n * order it wrote them, each run of work between them folded into one\n * collapsed activity segment that names its step (\"Ran `git log -1`\",\n * \"Read `config.ts`\"). The answer — the text after the last tool call —\n * renders below it through `SuperGroupingFinalText`, exactly as under\n * `SuperGroupingCard`, so no text renders twice.\n *\n * Takes the same renderer and host slots as `SuperGroupingCard`;\n * `renderRunningMeta` and `renderHeaderActions` sit on the header row.\n *\n * Selector discipline: raw reads only (`message`, `message.content`,\n * `message.status`, the previous message's stamp and id); every derivation\n * runs in `useMemo`.\n */\nexport const SuperGroupingTranscript = memo(function SuperGroupingTranscript({\n toolUIs,\n ToolFallback: ToolFallbackComponent = ToolFallback,\n TextComponent,\n ReasoningComponent,\n GroupComponent = CollapsibleGroup,\n getToolGroupKey = defaultGetToolGroupKey,\n groupingFunction,\n isInlineTool = isRegistryInlineTool,\n waitingTools,\n passThroughTools,\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}: SuperGroupingTranscriptProps) {\n const messageId = useAuiState((s) => s.message.id);\n const messageContent = useAuiState((s) =>\n s.message.role === 'assistant' ? s.message.content : EMPTY_CONTENT,\n );\n const messageStatus = useAuiState((s) => s.message.status);\n\n const timeline = useMemo(\n () => buildActivityTimeline(messageContent, messageStatus, { waitingTools, passThroughTools }),\n [messageContent, messageStatus, waitingTools, passThroughTools],\n );\n const phase = useMemo(\n () => resolveActivityPhase(messageStatus, timeline, { waitingForInput }),\n [messageStatus, timeline, waitingForInput],\n );\n const assetTitles = useMemo(() => collectAssetTitles(messageContent), [messageContent]);\n const stepsByPart = useMemo(() => {\n const byPart = new Map<number, TimelineStep>();\n timeline.forEach((item, index) => {\n if (item.partIndex === undefined) return;\n byPart.set(item.partIndex, toTimelineStep({ item, index, resolveToolDisplayName, assetTitles }));\n });\n return byPart;\n }, [timeline, resolveToolDisplayName, assetTitles]);\n const segments = useMemo(() => splitTurnSegments(messageContent), [messageContent]);\n const grouping = useMemo(\n () =>\n excludePartsFromGroups(\n groupingFunction ?? createToolBasedGroupingFunction(getToolGroupKey),\n (part) => part.type === 'tool-call' && part.toolName !== undefined && isInlineTool(part.toolName),\n ),\n [groupingFunction, getToolGroupKey, isInlineTool],\n );\n const inlineKeys = useMemo(() => {\n const keys = new Map<number, string>();\n messageContent.forEach((part, index) => {\n if (part.type === 'tool-call' && isInlineTool(part.toolName)) keys.set(index, part.toolCallId);\n });\n return keys;\n }, [messageContent, isInlineTool]);\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 const statusId = `aui-sg-turn-${useId().replace(/[^A-Za-z0-9_-]/g, '')}`;\n\n const hasText = messageContent.some((part) => part.type === 'text' && part.text.trim() !== '');\n const isVisible =\n timeline.length > 0 || phase === 'waiting' || phase === 'error' || (phase === 'running' && !hasText);\n if (!isVisible) return null;\n\n const expansionKey = expansionKeyProp ?? messageId;\n const toolCount = countActivityTools(timeline);\n const runningStep = [...stepsByPart.values()].filter((step) => step.state === 'running').at(-1);\n const cancelled = messageStatus?.type === 'incomplete' && messageStatus.reason === 'cancelled';\n const activitySummary = getActivitySummary(timeline);\n // The live region speaks what changed, never the ticking clock.\n const announcement =\n phase === 'running'\n ? (runningStep?.verb ?? 'Working')\n : phase === 'waiting'\n ? 'Waiting for your input'\n : phase === 'error'\n ? cancelled\n ? 'Run stopped'\n : 'Something went wrong'\n : activitySummary;\n const actions = renderHeaderActions?.({ phase, messageContent });\n const meta = phase === 'running' ? renderRunningMeta?.({ phase }) : null;\n\n return (\n <section\n data-slot=\"super-grouping-transcript\"\n data-phase={phase}\n data-tool-count={toolCount}\n className={cn('my-3 flex min-w-0 flex-col gap-1', className, classNames?.root)}\n aria-busy={phase === 'running' ? 'true' : 'false'}\n aria-describedby={statusId}\n >\n <div\n data-slot=\"turn-header\"\n className={cn(\n 'flex min-w-0 items-center gap-2 py-1 text-[13px] text-muted-foreground',\n classNames?.header,\n )}\n >\n <TurnGlyph phase={phase} />\n <span\n data-slot=\"turn-status\"\n className={cn(\n 'min-w-0 flex-1 truncate tabular-nums leading-5',\n phase === 'error' && !cancelled && 'text-destructive',\n )}\n >\n <TurnStatus\n phase={phase}\n cancelled={cancelled}\n activitySummary={activitySummary}\n toolCount={toolCount}\n summaryDetails={summaryDetails}\n />\n </span>\n {meta ? (\n <div data-slot=\"turn-meta\" className=\"flex shrink-0 items-center text-xs tabular-nums\">\n {meta}\n </div>\n ) : null}\n {actions ? <div className=\"flex shrink-0 items-center gap-1\">{actions}</div> : null}\n </div>\n {segments.length > 0 ? (\n <div\n data-slot=\"super-grouping-transcript-body\"\n className={cn('flex min-w-0 flex-col gap-1.5', classNames?.body)}\n >\n {segments.map((segment) =>\n segment.kind === 'prose' ? (\n <ProseSegment key={segment.key} text={segment.text} TextComponent={TextComponent} />\n ) : (\n <ActivitySegment\n key={segment.key}\n segment={segment}\n steps={segmentSteps(segment, stepsByPart)}\n turnPhase={phase}\n expansionKey={expansionKey}\n expandWhileWaiting={expandWhileWaiting}\n mountDetails={mountDetails}\n maxVisibleSteps={maxVisibleSteps}\n grouping={grouping}\n inlineParts={segment.partIndices.flatMap((index) => {\n const key = inlineKeys.get(index);\n return key === undefined ? [] : [{ index, key }];\n })}\n hasDetails={segment.partIndices.some(\n (index) => !inlineKeys.has(index) && messageContent[index]?.type !== 'text',\n )}\n components={components}\n classNames={classNames}\n />\n ),\n )}\n </div>\n ) : null}\n <output id={statusId} aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {announcement}\n </output>\n </section>\n );\n});\n\nfunction segmentSteps(\n segment: Extract<TurnSegment, { kind: 'activity' }>,\n stepsByPart: ReadonlyMap<number, TimelineStep>,\n): readonly TimelineStep[] {\n const steps = segment.partIndices\n .map((index) => stepsByPart.get(index))\n .filter((step): step is TimelineStep => step !== undefined);\n return steps.length > 0 ? steps : EMPTY_STEPS;\n}\n"],"names":["ProseSegment","SuperGroupingTranscript","isInlineTool","isRegistryInlineTool"],"mappings":"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"}
1
+ {"version":3,"file":"SuperGroupingTranscript.js","sources":["../../../src/chat/super-grouping/SuperGroupingTranscript.tsx"],"sourcesContent":["'use client';\n\nimport { isInlineTool as isRegistryInlineTool } from '@athenaintel/agent-runtime';\nimport {\n getExternalStoreMessages,\n MessagePrimitive,\n type TextMessagePartComponent,\n type ThreadAssistantMessagePart,\n useAuiState,\n} from '@assistant-ui/react';\nimport { AlertCircle, Check, ChevronRight, Circle, LoaderCircle } from 'lucide-react';\nimport { memo, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { cn } from '../../lib/utils';\nimport { StepText } from '../../tools/step-text';\nimport { ToolFallback } from '../../tools/tool-fallback';\nimport { collectAssetTitles } from '../../tools/tool-summary';\nimport { readMessageCreatedAt } from '../message-time';\nimport {\n type ActivityPhase,\n buildActivityTimeline,\n countActivityTools,\n excludePartsFromGroups,\n getActivitySummary,\n resolveActivityPhase,\n} from './activity-timeline';\nimport { CollapsibleGroup, SuperGroupingProvider } from './CollapsibleGroup';\nimport { createToolBasedGroupingFunction, type GroupingFunction } from './grouping-function';\nimport { type SuperGroupingCardProps, useActivityExpansion } from './SuperGroupingCard';\nimport { ToolTimeline } from './ToolTimeline';\nimport { type TimelineStep, toTimelineStep } from './timeline-step';\nimport { defaultGetToolGroupKey } from './toolkit-map';\nimport {\n scopeGroupingToSegment,\n splitTurnSegments,\n summarizeSegment,\n type TurnSegment,\n} from './turn-segments';\nimport {\n firstSeenMs,\n formatWorkDuration,\n observedTurnEndMs,\n readTurnTiming,\n recordObservedTurnEnd,\n type TurnTiming,\n workedDurationMs,\n workingLabel,\n} from './turn-timing';\n\nconst DEFAULT_MAX_VISIBLE_STEPS = 6;\nconst EMPTY_CONTENT: readonly ThreadAssistantMessagePart[] = [];\nconst EMPTY_STEPS: readonly TimelineStep[] = [];\n\nexport interface SuperGroupingTranscriptProps\n extends Pick<\n SuperGroupingCardProps,\n | 'toolUIs'\n | 'ToolFallback'\n | 'TextComponent'\n | 'ReasoningComponent'\n | 'GroupComponent'\n | 'getToolGroupKey'\n | 'groupingFunction'\n | 'isInlineTool'\n | 'waitingTools'\n | 'passThroughTools'\n | 'waitingForInput'\n | 'resolveToolDisplayName'\n | 'expansionKey'\n | 'expandWhileWaiting'\n | 'mountDetails'\n | 'summaryDetails'\n | 'renderHeaderActions'\n | 'renderRunningMeta'\n | 'className'\n > {\n /** Steps an opened segment lists before older ones fold away; unresolved calls always show. */\n maxVisibleSteps?: number;\n classNames?: {\n root?: string;\n header?: string;\n body?: string;\n details?: string;\n /** The flex column a segment's parts render in; override its gap here. */\n detailsParts?: string;\n };\n}\n\n// ─── Turn timing ───────────────────────────────────────────────────────\n\n/**\n * The turn's stamps: the prompt it answers, its joined metadata, and the raw\n * messages behind it. Reads the whole message (the bound raw messages hang off\n * it), so only the small header status subscribes here, never the transcript.\n */\nfunction useTurnTimingSources(): { timing: TurnTiming; clockKey: string } {\n const message = useAuiState((s) => s.message);\n const promptCreatedAt = useAuiState((s) => {\n const previous = s.thread.messages[s.message.index - 1];\n return previous?.role === 'user' ? readMessageCreatedAt(previous.metadata?.custom) : null;\n });\n const promptId = useAuiState((s) => {\n const previous = s.thread.messages[s.message.index - 1];\n return previous?.role === 'user' ? previous.id : '';\n });\n const timing = useMemo(\n () =>\n readTurnTiming({\n promptCreatedAt,\n custom: message.metadata?.custom,\n sourceMessages: getExternalStoreMessages<unknown>(message),\n }),\n [message, promptCreatedAt],\n );\n return { timing, clockKey: `${promptId}:${message.id}` };\n}\n\n/** \"Working for 1m 12s\", re-rendered once a second by itself so the transcript does not. */\nfunction WorkingFor({ startMs, clockKey }: { startMs: number | null; clockKey: string }) {\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n const timer = setInterval(() => setNow(Date.now()), 1000);\n return () => clearInterval(timer);\n }, []);\n const anchor = startMs ?? firstSeenMs(clockKey, now);\n return <>{workingLabel(Math.max(0, now - anchor))}</>;\n}\n\n/**\n * The header's words: \"Working for 1m 12s\" while the turn runs, \"Worked for\n * 2m 30s · Used 7 tools\" once done, \"Waiting for you\", or how it ended.\n */\nfunction TurnStatus({\n phase,\n cancelled,\n activitySummary,\n toolCount,\n summaryDetails,\n}: {\n phase: ActivityPhase;\n cancelled: boolean;\n activitySummary: string;\n toolCount: number;\n summaryDetails: readonly string[] | undefined;\n}) {\n const { timing, clockKey } = useTurnTimingSources();\n const [observedEndMs, setObservedEndMs] = useState(() => observedTurnEndMs(clockKey));\n const wasActive = useRef(phase === 'running' || phase === 'waiting');\n useEffect(() => {\n const active = phase === 'running' || phase === 'waiting';\n if (wasActive.current && !active) setObservedEndMs(recordObservedTurnEnd(clockKey));\n wasActive.current = active;\n }, [phase, clockKey]);\n if (phase === 'running') return <WorkingFor startMs={timing.startMs} clockKey={clockKey} />;\n if (phase === 'waiting') return <>Waiting for you</>;\n const workedMs = workedDurationMs(timing, observedEndMs);\n if (phase === 'error') {\n if (!cancelled) return <>Something went wrong</>;\n return <>{workedMs !== null ? `Run stopped after ${formatWorkDuration(workedMs)}` : 'Run stopped'}</>;\n }\n const label = [\n ...(workedMs !== null ? [`Worked for ${formatWorkDuration(workedMs)}`] : []),\n ...(workedMs === null || toolCount > 0 || activitySummary !== 'Reasoning complete' ? [activitySummary] : []),\n ...(summaryDetails ?? []),\n ].join(' · ');\n return <>{label}</>;\n}\n\nfunction TurnGlyph({ phase }: { phase: ActivityPhase }) {\n const className = 'size-3.5 shrink-0';\n if (phase === 'running') {\n return <LoaderCircle aria-hidden=\"true\" className={cn(className, 'motion-safe:animate-spin')} />;\n }\n if (phase === 'waiting') {\n return <Circle aria-hidden=\"true\" className={cn(className, 'text-amber-600 dark:text-amber-400')} />;\n }\n if (phase === 'error') {\n return <AlertCircle aria-hidden=\"true\" className={cn(className, 'text-destructive')} />;\n }\n return <Check aria-hidden=\"true\" className={cn(className, 'opacity-70')} />;\n}\n\n// ─── Segments ──────────────────────────────────────────────────────────\n\nconst ProseSegment = memo(function ProseSegment({\n text,\n TextComponent,\n}: {\n text: string;\n TextComponent: TextMessagePartComponent;\n}) {\n return (\n <div data-slot=\"transcript-prose\" className=\"min-w-0\">\n <TextComponent type=\"text\" text={text} status={{ type: 'complete' }} />\n </div>\n );\n});\n\ninterface ActivitySegmentProps {\n segment: Extract<TurnSegment, { kind: 'activity' }>;\n steps: readonly TimelineStep[];\n turnPhase: ActivityPhase;\n expansionKey: string;\n expandWhileWaiting: boolean;\n mountDetails: boolean;\n maxVisibleSteps: number;\n grouping: GroupingFunction;\n /** This segment's inline tool calls (an editable draft), rendered outside its disclosures. */\n inlineParts: readonly { index: number; key: string }[];\n /** False when every step's UI renders inline, so there is nothing behind \"Show tool details\". */\n hasDetails: boolean;\n components: Parameters<typeof MessagePrimitive.Unstable_PartsGrouped>[0]['components'];\n classNames: SuperGroupingTranscriptProps['classNames'];\n}\n\n/**\n * One collapsed run of work between two of the agent's sentences: the step in\n * progress (or the last one taken) on one line, the segment's steps when\n * opened, and the tool UIs of just this segment behind \"Show tool details\".\n * The tool UIs stay mounted (hidden) while the turn is live so their effects\n * run, as in `SuperGroupingCard`.\n */\nfunction ActivitySegment({\n segment,\n steps,\n turnPhase,\n expansionKey,\n expandWhileWaiting,\n mountDetails,\n maxVisibleSteps,\n grouping,\n inlineParts,\n hasDetails,\n components,\n classNames,\n}: ActivitySegmentProps) {\n const summary = summarizeSegment(steps);\n const phase = summary.phase;\n const { expanded, toggleExpanded } = useActivityExpansion({\n expansionKey: `${expansionKey}:${segment.key}`,\n phase,\n expandWhileWaiting,\n });\n const { expanded: detailsExpanded, toggleExpanded: toggleDetails } = useActivityExpansion({\n expansionKey: `${expansionKey}:${segment.key}:details`,\n phase,\n expandWhileWaiting,\n });\n const indicesKey = segment.partIndices.join(',');\n const scopedGrouping = useMemo(\n () => scopeGroupingToSegment(grouping, indicesKey.split(',').map(Number)),\n [grouping, indicesKey],\n );\n const groupingContext = useMemo(() => ({ groupingFunction: scopedGrouping }), [scopedGrouping]);\n const detailsPanelId = `aui-sg-segment-${useId().replace(/[^A-Za-z0-9_-]/g, '')}`;\n\n const isTurnActive = turnPhase === 'running' || turnPhase === 'waiting';\n const detailsMounted = isTurnActive || mountDetails || (expanded && detailsExpanded);\n const hasToolSteps = steps.some((step) => step.kind === 'tool');\n const meta = [summary.step?.chip, summary.meta].filter(Boolean).join(' · ');\n\n // Parts with no step of their own (an image the agent produced) are content, not work.\n if (steps.length === 0) {\n return (\n <div data-slot=\"transcript-parts\" className={cn('flex min-w-0 flex-col gap-2', classNames?.detailsParts)}>\n <SuperGroupingProvider value={groupingContext}>\n <MessagePrimitive.Unstable_PartsGrouped groupingFunction={scopedGrouping} components={components} />\n </SuperGroupingProvider>\n </div>\n );\n }\n\n return (\n <div data-slot=\"activity-segment\" data-phase={phase} data-segment-key={segment.key} className=\"min-w-0\">\n <ToolTimeline\n steps={steps}\n open={expanded}\n onOpenChange={toggleExpanded}\n label={<StepText text={summary.label} code={summary.step?.code} />}\n labelTitle={summary.step?.detail}\n phase={phase}\n maxVisibleSteps={maxVisibleSteps}\n keepMounted={isTurnActive || mountDetails}\n meta={meta ? <span data-slot=\"activity-segment-meta\">{meta}</span> : 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\n ? hasToolSteps\n ? 'Hide tool details'\n : 'Hide thinking'\n : hasToolSteps\n ? 'Show tool details'\n : 'Show thinking'}\n </button>\n {detailsMounted ? (\n <section\n id={detailsPanelId}\n aria-label=\"Step 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 <MessagePrimitive.Unstable_PartsGrouped groupingFunction={scopedGrouping} components={components} />\n </SuperGroupingProvider>\n </div>\n </section>\n ) : null}\n </div>\n ) : null}\n </ToolTimeline>\n {inlineParts.length > 0 ? (\n <div data-slot=\"activity-segment-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 </div>\n );\n}\n\n// ─── Transcript ────────────────────────────────────────────────────────\n\n/**\n * The collapsed view (previously called the conversational view) of an\n * assistant turn as a transcript: a header that says how long the turn has\n * been working (\"Working for 1m 12s\", then \"Worked for 2m 30s\"), then the\n * agent's own sentences in the order it wrote them, each run of work between\n * them folded into one collapsed activity segment that names its step (\"Ran\n * `git log -1`\", \"Read `config.ts`\"). The answer — the text after the last\n * tool call — renders below it through `SuperGroupingFinalText`, exactly as\n * under `SuperGroupingCard`, so no text renders twice.\n *\n * Takes the same renderer and host slots as `SuperGroupingCard`;\n * `renderRunningMeta` and `renderHeaderActions` sit on the header row.\n *\n * Selector discipline: raw reads only (`message`, `message.content`,\n * `message.status`, the previous message's stamp and id); every derivation\n * runs in `useMemo`.\n */\nexport const SuperGroupingTranscript = memo(function SuperGroupingTranscript({\n toolUIs,\n ToolFallback: ToolFallbackComponent = ToolFallback,\n TextComponent,\n ReasoningComponent,\n GroupComponent = CollapsibleGroup,\n getToolGroupKey = defaultGetToolGroupKey,\n groupingFunction,\n isInlineTool = isRegistryInlineTool,\n waitingTools,\n passThroughTools,\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}: SuperGroupingTranscriptProps) {\n const messageId = useAuiState((s) => s.message.id);\n const messageContent = useAuiState((s) =>\n s.message.role === 'assistant' ? s.message.content : EMPTY_CONTENT,\n );\n const messageStatus = useAuiState((s) => s.message.status);\n\n const timeline = useMemo(\n () => buildActivityTimeline(messageContent, messageStatus, { waitingTools, passThroughTools }),\n [messageContent, messageStatus, waitingTools, passThroughTools],\n );\n const phase = useMemo(\n () => resolveActivityPhase(messageStatus, timeline, { waitingForInput }),\n [messageStatus, timeline, waitingForInput],\n );\n const assetTitles = useMemo(() => collectAssetTitles(messageContent), [messageContent]);\n const stepsByPart = useMemo(() => {\n const byPart = new Map<number, TimelineStep>();\n timeline.forEach((item, index) => {\n if (item.partIndex === undefined) return;\n byPart.set(item.partIndex, toTimelineStep({ item, index, resolveToolDisplayName, assetTitles }));\n });\n return byPart;\n }, [timeline, resolveToolDisplayName, assetTitles]);\n const segments = useMemo(() => splitTurnSegments(messageContent), [messageContent]);\n const grouping = useMemo(\n () =>\n excludePartsFromGroups(\n groupingFunction ?? createToolBasedGroupingFunction(getToolGroupKey),\n (part) => part.type === 'tool-call' && part.toolName !== undefined && isInlineTool(part.toolName),\n ),\n [groupingFunction, getToolGroupKey, isInlineTool],\n );\n const inlineKeys = useMemo(() => {\n const keys = new Map<number, string>();\n messageContent.forEach((part, index) => {\n if (part.type === 'tool-call' && isInlineTool(part.toolName)) keys.set(index, part.toolCallId);\n });\n return keys;\n }, [messageContent, isInlineTool]);\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 const statusId = `aui-sg-turn-${useId().replace(/[^A-Za-z0-9_-]/g, '')}`;\n\n const hasText = messageContent.some((part) => part.type === 'text' && part.text.trim() !== '');\n const isVisible =\n timeline.length > 0 || phase === 'waiting' || phase === 'error' || (phase === 'running' && !hasText);\n if (!isVisible) return null;\n\n const expansionKey = expansionKeyProp ?? messageId;\n const toolCount = countActivityTools(timeline);\n const runningStep = [...stepsByPart.values()].filter((step) => step.state === 'running').at(-1);\n const cancelled = messageStatus?.type === 'incomplete' && messageStatus.reason === 'cancelled';\n const activitySummary = getActivitySummary(timeline);\n // The live region speaks what changed, never the ticking clock.\n const announcement =\n phase === 'running'\n ? (runningStep?.verb ?? 'Working')\n : phase === 'waiting'\n ? 'Waiting for your input'\n : phase === 'error'\n ? cancelled\n ? 'Run stopped'\n : 'Something went wrong'\n : activitySummary;\n const actions = renderHeaderActions?.({ phase, messageContent });\n const meta = phase === 'running' ? renderRunningMeta?.({ phase }) : null;\n\n return (\n <section\n data-slot=\"super-grouping-transcript\"\n data-phase={phase}\n data-tool-count={toolCount}\n className={cn('my-3 flex min-w-0 flex-col gap-1', className, classNames?.root)}\n aria-busy={phase === 'running' ? 'true' : 'false'}\n aria-describedby={statusId}\n >\n <div\n data-slot=\"turn-header\"\n className={cn(\n 'flex min-w-0 items-center gap-2 py-1 text-[13px] text-muted-foreground',\n classNames?.header,\n )}\n >\n <TurnGlyph phase={phase} />\n <span\n data-slot=\"turn-status\"\n className={cn(\n 'min-w-0 flex-1 truncate tabular-nums leading-5',\n phase === 'error' && !cancelled && 'text-destructive',\n )}\n >\n <TurnStatus\n phase={phase}\n cancelled={cancelled}\n activitySummary={activitySummary}\n toolCount={toolCount}\n summaryDetails={summaryDetails}\n />\n </span>\n {meta ? (\n <div data-slot=\"turn-meta\" className=\"flex shrink-0 items-center text-xs tabular-nums\">\n {meta}\n </div>\n ) : null}\n {actions ? <div className=\"flex shrink-0 items-center gap-1\">{actions}</div> : null}\n </div>\n {segments.length > 0 ? (\n <div\n data-slot=\"super-grouping-transcript-body\"\n className={cn('flex min-w-0 flex-col gap-1.5', classNames?.body)}\n >\n {segments.map((segment) =>\n segment.kind === 'prose' ? (\n <ProseSegment key={segment.key} text={segment.text} TextComponent={TextComponent} />\n ) : (\n <ActivitySegment\n key={segment.key}\n segment={segment}\n steps={segmentSteps(segment, stepsByPart)}\n turnPhase={phase}\n expansionKey={expansionKey}\n expandWhileWaiting={expandWhileWaiting}\n mountDetails={mountDetails}\n maxVisibleSteps={maxVisibleSteps}\n grouping={grouping}\n inlineParts={segment.partIndices.flatMap((index) => {\n const key = inlineKeys.get(index);\n return key === undefined ? [] : [{ index, key }];\n })}\n hasDetails={segment.partIndices.some(\n (index) => !inlineKeys.has(index) && messageContent[index]?.type !== 'text',\n )}\n components={components}\n classNames={classNames}\n />\n ),\n )}\n </div>\n ) : null}\n <output id={statusId} aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {announcement}\n </output>\n </section>\n );\n});\n\nfunction segmentSteps(\n segment: Extract<TurnSegment, { kind: 'activity' }>,\n stepsByPart: ReadonlyMap<number, TimelineStep>,\n): readonly TimelineStep[] {\n const steps = segment.partIndices\n .map((index) => stepsByPart.get(index))\n .filter((step): step is TimelineStep => step !== undefined);\n return steps.length > 0 ? steps : EMPTY_STEPS;\n}\n"],"names":["ProseSegment","SuperGroupingTranscript","isInlineTool","isRegistryInlineTool"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"activity-timeline.cjs","sources":["../../../src/chat/super-grouping/activity-timeline.ts"],"sourcesContent":["/**\n * The assistant turn's activity timeline — the one derivation of \"what did\n * this turn do, and how did each step end\" behind the grouped\n * (\"conversational\") view on every surface: the SDK's `AthenaChat`, Olympus's\n * Spaces chat, and the Chrome extension. Pure functions over assistant-ui\n * message parts; `SuperGroupingCard` renders them.\n *\n * Step states come from the shared classifier (`classifyToolResult`) plus the\n * approval outcomes a part carries (`approval`, `interrupt`, a rejection\n * result), so a call that reads as failed, paused, or rejected on one surface\n * cannot read as a green check on another. Copy comes from the shared tool\n * summary registry (`summarizeToolCall`), itself built on the display\n * registry.\n */\nimport type {\n MessageStatus,\n ThreadAssistantMessagePart,\n ToolCallMessagePartStatus,\n} from '@assistant-ui/react';\nimport {\n classifyToolResult,\n isSpokenTurnTextPart,\n readRejectedToolResult,\n type ToolStatusLabelState,\n} from '@athenaintel/agent-runtime';\nimport { summarizeToolCall, type ToolCallSummary } from '../../tools/tool-summary';\nimport type { GroupablePart, GroupingFunction } from './grouping-function';\n\nexport type ActivityToolState = ToolStatusLabelState;\n\nexport type ActivityItem =\n | {\n kind: 'reasoning';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n text: string;\n state: 'running' | 'complete';\n }\n | {\n kind: 'tool';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n toolName: string;\n args?: ToolCallPart['args'];\n /** The tool's real result; absent while it runs or holds only the streaming placeholder. */\n result?: unknown;\n state: ActivityToolState;\n };\n\n/** The turn as a whole: still working, parked on the person, ended in error, or done. */\nexport type ActivityPhase = 'running' | 'waiting' | 'complete' | 'error';\n\ntype ToolCallPart = Extract<ThreadAssistantMessagePart, { type: 'tool-call' }>;\n\nexport interface ActivityTimelineOptions {\n /**\n * Tools whose unresolved call means the turn is waiting on the person even\n * without an interrupt or approval on the part (the Chrome extension's\n * device plan approval, which the tool UI itself collects).\n */\n waitingTools?: ReadonlySet<string>;\n /**\n * Tools whose result is an application payload relayed verbatim (the Chrome\n * extension's page JavaScript), so a `success: false` flag counts only with\n * an error detail — see `classifyToolResult`'s `passThroughPayload`.\n */\n passThroughTools?: ReadonlySet<string>;\n}\n\nconst NO_TOOLS: ReadonlySet<string> = new Set();\n\n/**\n * Whether a tool-call part still holds the backend's streaming placeholder\n * result rather than the tool's real output. Long-running tools (task\n * subagents, studio and Python execution, deep research) append a ToolMessage\n * the moment they start so their card can fill in live; it carries\n * `additional_kwargs.streaming`, which the runtime converter lifts into\n * `artifact._tool_message_metadata`. The real ToolMessage that replaces it\n * has no such flag, so a defined `result` alone does not mean the tool is done.\n */\nexport function isStreamingToolPlaceholder(part: Pick<ToolCallPart, 'artifact'>): boolean {\n const artifact: unknown = part.artifact;\n if (typeof artifact !== 'object' || artifact === null) return false;\n const metadata: unknown = (artifact as { _tool_message_metadata?: unknown })\n ._tool_message_metadata;\n if (typeof metadata !== 'object' || metadata === null) return false;\n return (metadata as { streaming?: unknown }).streaming === true;\n}\n\n/** The tool's real result: undefined while it has none or only the streaming placeholder. */\nfunction finalResult(part: ToolCallPart): unknown {\n return isStreamingToolPlaceholder(part) ? undefined : part.result;\n}\n\nfunction toolCallStatus(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n): ToolCallMessagePartStatus | undefined {\n if (finalResult(part) !== undefined) return { type: 'complete' };\n if (messageStatus?.type === 'incomplete') {\n return {\n type: 'incomplete',\n reason: messageStatus.reason === 'tool-calls' ? 'other' : messageStatus.reason,\n error: messageStatus.error,\n };\n }\n if (messageStatus?.type === 'complete') return { type: 'complete' };\n if (messageStatus?.type === 'requires-action') {\n return { type: 'requires-action', reason: messageStatus.reason };\n }\n if (messageStatus?.type === 'running') return { type: 'running' };\n return undefined;\n}\n\n/** How one tool call ended (or is going), reading the approval fields before the result. */\nexport function getActivityToolState(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n { waitingTools = NO_TOOLS, passThroughTools = NO_TOOLS }: ActivityTimelineOptions = {},\n): ActivityToolState {\n if (part.approval?.approved === false || readRejectedToolResult(part.result) !== null) {\n return 'rejected';\n }\n if (part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired') {\n return 'cancelled';\n }\n const result = finalResult(part);\n const unresolved = result === undefined;\n const messageIsActive =\n messageStatus === undefined ||\n messageStatus.type === 'running' ||\n messageStatus.type === 'requires-action';\n if (\n unresolved &&\n (part.interrupt?.type === 'human' ||\n (part.approval !== undefined &&\n part.approval.approved === undefined &&\n part.approval.resolution === undefined) ||\n (waitingTools.has(part.toolName) && messageIsActive))\n ) {\n return 'waiting';\n }\n\n const classification = classifyToolResult({\n status: toolCallStatus(part, messageStatus),\n result,\n isError: part.isError,\n passThroughPayload: passThroughTools.has(part.toolName),\n });\n if (classification.state === 'requires-action') return 'waiting';\n return classification.state;\n}\n\n/**\n * The compact reasoning/tool timeline in the order the parts streamed.\n *\n * A reasoning part is still streaming only while it is the final part of a\n * running message — once any later part appears, the thought has settled.\n * Settled reasoning parts with no text are dropped so the list never shows an\n * empty thinking row.\n */\nexport function buildActivityTimeline(\n content: readonly ThreadAssistantMessagePart[] | undefined,\n messageStatus: MessageStatus | undefined,\n options: ActivityTimelineOptions = {},\n): ActivityItem[] {\n if (!content?.length) return [];\n\n const lastPartIndex = content.length - 1;\n const timeline: ActivityItem[] = [];\n for (let index = 0; index < content.length; index += 1) {\n const part = content[index];\n if (part.type === 'tool-call') {\n const result = finalResult(part);\n timeline.push({\n kind: 'tool',\n id: part.toolCallId,\n partIndex: index,\n args: part.args,\n ...(result !== undefined ? { result } : {}),\n toolName: part.toolName,\n state: getActivityToolState(part, messageStatus, options),\n });\n continue;\n }\n if (part.type !== 'reasoning') continue;\n\n const text = typeof part.text === 'string' ? part.text : '';\n const stillStreaming = messageStatus?.type === 'running' && index === lastPartIndex;\n if (!stillStreaming && text.trim() === '') continue;\n timeline.push({\n kind: 'reasoning',\n id: `reasoning-${index}`,\n partIndex: index,\n text,\n state: stillStreaming ? 'running' : 'complete',\n });\n }\n return timeline;\n}\n\n/** Number of tool calls in the timeline. */\nexport function countActivityTools(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => (item.kind === 'tool' ? count + 1 : count), 0);\n}\n\n/**\n * The turn's phase. Waiting on the person wins over everything — a\n * `requires-action` status, a waiting tool, or a host's own `waitingForInput`\n * assertion (no in-repo host passes one) — then the message's own status.\n */\nexport function resolveActivityPhase(\n status: MessageStatus | undefined,\n timeline: readonly ActivityItem[],\n { waitingForInput = false }: { waitingForInput?: boolean } = {},\n): ActivityPhase {\n if (\n waitingForInput ||\n status?.type === 'requires-action' ||\n timeline.some((item) => item.kind === 'tool' && item.state === 'waiting')\n ) {\n return 'waiting';\n }\n if (status?.type === 'running') return 'running';\n if (status?.type === 'incomplete') return 'error';\n return 'complete';\n}\n\n/**\n * A settled thought's row: the heading a reasoning summary opens with\n * (\"**Checking the workstation**\" → \"Checking the workstation\"), else the\n * generic wording. The thought itself stays in the run's details.\n */\nexport function getReasoningLabel(text: string, state: 'running' | 'complete'): string {\n if (state === 'running') return 'Thinking';\n const heading = /^\\s*\\*\\*([^*\\n]{3,80}?)\\*\\*/.exec(text)?.[1]?.trim();\n return heading ? heading.replace(/[.:]+$/, '') : 'Thought through the next step';\n}\n\n/**\n * The status-row copy for one step: the call's own summary from the shared\n * summary registry (`summarizeToolCall`: \"Ran git status\", \"Read config.ts\").\n * `resolveToolDisplayName` lets a host with a richer tool catalog name tools\n * neither registry has an entry for; `assetTitles` names the machine or\n * document a call targeted by id when an earlier result in the turn did.\n */\nexport function getActivityItemLabel(\n item: ActivityItem,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): string {\n if (item.kind === 'reasoning') return getReasoningLabel(item.text, item.state);\n return summarizeActivityTool(item, resolveToolDisplayName, assetTitles).label;\n}\n\n/** The summary of one tool step (see {@link getActivityItemLabel}). */\nexport function summarizeActivityTool(\n item: Extract<ActivityItem, { kind: 'tool' }>,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): ToolCallSummary {\n return summarizeToolCall({\n toolName: item.toolName,\n args: item.args,\n result: item.result,\n status: item.state,\n ...(assetTitles ? { assetTitles } : {}),\n ...(resolveToolDisplayName ? { displayName: resolveToolDisplayName(item.toolName) } : {}),\n });\n}\n\n/** The collapsed-card summary of a finished turn. */\nexport function getActivitySummary(timeline: readonly ActivityItem[]): string {\n const toolCount = countActivityTools(timeline);\n const hasIssue = timeline.some(\n (item) => item.kind === 'tool' && (item.state === 'error' || item.state === 'rejected'),\n );\n if (hasIssue) return 'Completed with issues';\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'cancelled')) {\n return 'Action cancelled';\n }\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'paused')) {\n return 'Paused during tool use';\n }\n if (toolCount > 0) return `Used ${toolCount} ${toolCount === 1 ? 'tool' : 'tools'}`;\n return 'Reasoning complete';\n}\n\n/** The part shape the final-text read needs; any message role's parts satisfy it. */\nexport type FinalTextPart = { readonly type: string; readonly text?: string };\n\n/**\n * Whether a text part shows below the card instead of in the details panel:\n * it comes after the final tool call, or it holds a spoken voice turn's words\n * (a live turn heard during a delegated run lands between the run's tool\n * calls, see `isSpokenTurnTextPart`; it is the conversation, not narration).\n */\nfunction isAnswerTextPart(\n part: { readonly type: string } | undefined,\n index: number,\n lastToolIndex: number,\n): boolean {\n return part?.type === 'text' && (index > lastToolIndex || isSpokenTurnTextPart(part));\n}\n\n/**\n * The visible answer of a grouped turn: the text after the final tool call\n * (all of it when the turn never called a tool), plus the words of every\n * spoken voice turn in the message, in order. Other intermediate text (before\n * or between tool calls) stays available in the details panel.\n */\nexport function getFinalText(content: readonly FinalTextPart[] | undefined): string | null {\n const parts = getFinalTextParts(content);\n return parts.length > 0 ? parts.map((part) => part.text).join('\\n\\n') : null;\n}\n\n/** One text part of the visible answer, with its index in the message content. */\nexport interface FinalTextSegment {\n index: number;\n text: string;\n}\n\n/**\n * The parts `getFinalText` joins, each kept separate with its content index.\n * A spoken turn and the run's own reply can stream at the same time, so the\n * earlier part may grow while a later one exists: rendered as one joined\n * string, that text changes in the middle rather than at its end, and the\n * streaming reveal restarts from an empty bubble on every word.\n */\nexport function getFinalTextParts(content: readonly FinalTextPart[] | undefined): FinalTextSegment[] {\n if (!content?.length) return [];\n\n const lastToolIndex = content.findLastIndex((part) => part?.type === 'tool-call');\n const parts: FinalTextSegment[] = [];\n content.forEach((part, index) => {\n if (part.text && isAnswerTextPart(part, index, lastToolIndex)) parts.push({ index, text: part.text });\n });\n return parts;\n}\n\n/**\n * Keep the answer out of the details panel: it renders below the card\n * (`SuperGroupingFinalText`), so the details grouping drops every text part\n * `getFinalText` shows and any group that becomes empty.\n */\nexport function excludeFinalTextFromGroups(grouping: GroupingFunction): GroupingFunction {\n return (parts) => {\n const lastToolIndex = parts.findLastIndex((part) => part?.type === 'tool-call');\n return grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => !isAnswerTextPart(parts[index], index, lastToolIndex)),\n }))\n .filter((group) => group.indices.length > 0);\n };\n}\n\n/**\n * Drop the parts `exclude` matches from every group, and any group left\n * empty: `SuperGroupingCard` renders inline tool calls outside the details,\n * so they must not render a second time inside it.\n */\nexport function excludePartsFromGroups(\n grouping: GroupingFunction,\n exclude: (part: GroupablePart) => boolean,\n): GroupingFunction {\n return (parts) =>\n grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => {\n const part = parts[index];\n return part === undefined || !exclude(part);\n }),\n }))\n .filter((group) => group.indices.length > 0);\n}\n"],"names":["readRejectedToolResult","classifyToolResult","summarizeToolCall","isSpokenTurnTextPart"],"mappings":"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"}
1
+ {"version":3,"file":"activity-timeline.cjs","sources":["../../../src/chat/super-grouping/activity-timeline.ts"],"sourcesContent":["/**\n * The assistant turn's activity timeline — the one derivation of \"what did\n * this turn do, and how did each step end\" behind the collapsed view\n * (previously called the conversational view) on every surface: the SDK's\n * `AthenaChat`, Olympus's Spaces chat, and the Chrome extension. Pure\n * functions over assistant-ui message parts; `SuperGroupingCard` renders them.\n *\n * Step states come from the shared classifier (`classifyToolResult`) plus the\n * approval outcomes a part carries (`approval`, `interrupt`, a rejection\n * result), so a call that reads as failed, paused, or rejected on one surface\n * cannot read as a green check on another. Copy comes from the shared tool\n * summary registry (`summarizeToolCall`), itself built on the display\n * registry.\n */\nimport type {\n MessageStatus,\n ThreadAssistantMessagePart,\n ToolCallMessagePartStatus,\n} from '@assistant-ui/react';\nimport {\n classifyToolResult,\n isSpokenTurnTextPart,\n readRejectedToolResult,\n type ToolStatusLabelState,\n} from '@athenaintel/agent-runtime';\nimport { summarizeToolCall, type ToolCallSummary } from '../../tools/tool-summary';\nimport type { GroupablePart, GroupingFunction } from './grouping-function';\n\nexport type ActivityToolState = ToolStatusLabelState;\n\nexport type ActivityItem =\n | {\n kind: 'reasoning';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n text: string;\n state: 'running' | 'complete';\n }\n | {\n kind: 'tool';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n toolName: string;\n args?: ToolCallPart['args'];\n /** The tool's real result; absent while it runs or holds only the streaming placeholder. */\n result?: unknown;\n state: ActivityToolState;\n };\n\n/** The turn as a whole: still working, parked on the person, ended in error, or done. */\nexport type ActivityPhase = 'running' | 'waiting' | 'complete' | 'error';\n\ntype ToolCallPart = Extract<ThreadAssistantMessagePart, { type: 'tool-call' }>;\n\nexport interface ActivityTimelineOptions {\n /**\n * Tools whose unresolved call means the turn is waiting on the person even\n * without an interrupt or approval on the part (the Chrome extension's\n * device plan approval, which the tool UI itself collects).\n */\n waitingTools?: ReadonlySet<string>;\n /**\n * Tools whose result is an application payload relayed verbatim (the Chrome\n * extension's page JavaScript), so a `success: false` flag counts only with\n * an error detail — see `classifyToolResult`'s `passThroughPayload`.\n */\n passThroughTools?: ReadonlySet<string>;\n}\n\nconst NO_TOOLS: ReadonlySet<string> = new Set();\n\n/**\n * Whether a tool-call part still holds the backend's streaming placeholder\n * result rather than the tool's real output. Long-running tools (task\n * subagents, studio and Python execution, deep research) append a ToolMessage\n * the moment they start so their card can fill in live; it carries\n * `additional_kwargs.streaming`, which the runtime converter lifts into\n * `artifact._tool_message_metadata`. The real ToolMessage that replaces it\n * has no such flag, so a defined `result` alone does not mean the tool is done.\n */\nexport function isStreamingToolPlaceholder(part: Pick<ToolCallPart, 'artifact'>): boolean {\n const artifact: unknown = part.artifact;\n if (typeof artifact !== 'object' || artifact === null) return false;\n const metadata: unknown = (artifact as { _tool_message_metadata?: unknown })\n ._tool_message_metadata;\n if (typeof metadata !== 'object' || metadata === null) return false;\n return (metadata as { streaming?: unknown }).streaming === true;\n}\n\n/** The tool's real result: undefined while it has none or only the streaming placeholder. */\nfunction finalResult(part: ToolCallPart): unknown {\n return isStreamingToolPlaceholder(part) ? undefined : part.result;\n}\n\nfunction toolCallStatus(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n): ToolCallMessagePartStatus | undefined {\n if (finalResult(part) !== undefined) return { type: 'complete' };\n if (messageStatus?.type === 'incomplete') {\n return {\n type: 'incomplete',\n reason: messageStatus.reason === 'tool-calls' ? 'other' : messageStatus.reason,\n error: messageStatus.error,\n };\n }\n if (messageStatus?.type === 'complete') return { type: 'complete' };\n if (messageStatus?.type === 'requires-action') {\n return { type: 'requires-action', reason: messageStatus.reason };\n }\n if (messageStatus?.type === 'running') return { type: 'running' };\n return undefined;\n}\n\n/** How one tool call ended (or is going), reading the approval fields before the result. */\nexport function getActivityToolState(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n { waitingTools = NO_TOOLS, passThroughTools = NO_TOOLS }: ActivityTimelineOptions = {},\n): ActivityToolState {\n if (part.approval?.approved === false || readRejectedToolResult(part.result) !== null) {\n return 'rejected';\n }\n if (part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired') {\n return 'cancelled';\n }\n const result = finalResult(part);\n const unresolved = result === undefined;\n const messageIsActive =\n messageStatus === undefined ||\n messageStatus.type === 'running' ||\n messageStatus.type === 'requires-action';\n if (\n unresolved &&\n (part.interrupt?.type === 'human' ||\n (part.approval !== undefined &&\n part.approval.approved === undefined &&\n part.approval.resolution === undefined) ||\n (waitingTools.has(part.toolName) && messageIsActive))\n ) {\n return 'waiting';\n }\n\n const classification = classifyToolResult({\n status: toolCallStatus(part, messageStatus),\n result,\n isError: part.isError,\n passThroughPayload: passThroughTools.has(part.toolName),\n });\n if (classification.state === 'requires-action') return 'waiting';\n return classification.state;\n}\n\n/**\n * The compact reasoning/tool timeline in the order the parts streamed.\n *\n * A reasoning part is still streaming only while it is the final part of a\n * running message — once any later part appears, the thought has settled.\n * Settled reasoning parts with no text are dropped so the list never shows an\n * empty thinking row.\n */\nexport function buildActivityTimeline(\n content: readonly ThreadAssistantMessagePart[] | undefined,\n messageStatus: MessageStatus | undefined,\n options: ActivityTimelineOptions = {},\n): ActivityItem[] {\n if (!content?.length) return [];\n\n const lastPartIndex = content.length - 1;\n const timeline: ActivityItem[] = [];\n for (let index = 0; index < content.length; index += 1) {\n const part = content[index];\n if (part.type === 'tool-call') {\n const result = finalResult(part);\n timeline.push({\n kind: 'tool',\n id: part.toolCallId,\n partIndex: index,\n args: part.args,\n ...(result !== undefined ? { result } : {}),\n toolName: part.toolName,\n state: getActivityToolState(part, messageStatus, options),\n });\n continue;\n }\n if (part.type !== 'reasoning') continue;\n\n const text = typeof part.text === 'string' ? part.text : '';\n const stillStreaming = messageStatus?.type === 'running' && index === lastPartIndex;\n if (!stillStreaming && text.trim() === '') continue;\n timeline.push({\n kind: 'reasoning',\n id: `reasoning-${index}`,\n partIndex: index,\n text,\n state: stillStreaming ? 'running' : 'complete',\n });\n }\n return timeline;\n}\n\n/** Number of tool calls in the timeline. */\nexport function countActivityTools(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => (item.kind === 'tool' ? count + 1 : count), 0);\n}\n\n/**\n * The turn's phase. Waiting on the person wins over everything — a\n * `requires-action` status, a waiting tool, or a host's own `waitingForInput`\n * assertion (no in-repo host passes one) — then the message's own status.\n */\nexport function resolveActivityPhase(\n status: MessageStatus | undefined,\n timeline: readonly ActivityItem[],\n { waitingForInput = false }: { waitingForInput?: boolean } = {},\n): ActivityPhase {\n if (\n waitingForInput ||\n status?.type === 'requires-action' ||\n timeline.some((item) => item.kind === 'tool' && item.state === 'waiting')\n ) {\n return 'waiting';\n }\n if (status?.type === 'running') return 'running';\n if (status?.type === 'incomplete') return 'error';\n return 'complete';\n}\n\n/**\n * A settled thought's row: the heading a reasoning summary opens with\n * (\"**Checking the workstation**\" → \"Checking the workstation\"), else the\n * generic wording. The thought itself stays in the run's details.\n */\nexport function getReasoningLabel(text: string, state: 'running' | 'complete'): string {\n if (state === 'running') return 'Thinking';\n const heading = /^\\s*\\*\\*([^*\\n]{3,80}?)\\*\\*/.exec(text)?.[1]?.trim();\n return heading ? heading.replace(/[.:]+$/, '') : 'Thought through the next step';\n}\n\n/**\n * The status-row copy for one step: the call's own summary from the shared\n * summary registry (`summarizeToolCall`: \"Ran git status\", \"Read config.ts\").\n * `resolveToolDisplayName` lets a host with a richer tool catalog name tools\n * neither registry has an entry for; `assetTitles` names the machine or\n * document a call targeted by id when an earlier result in the turn did.\n */\nexport function getActivityItemLabel(\n item: ActivityItem,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): string {\n if (item.kind === 'reasoning') return getReasoningLabel(item.text, item.state);\n return summarizeActivityTool(item, resolveToolDisplayName, assetTitles).label;\n}\n\n/** The summary of one tool step (see {@link getActivityItemLabel}). */\nexport function summarizeActivityTool(\n item: Extract<ActivityItem, { kind: 'tool' }>,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): ToolCallSummary {\n return summarizeToolCall({\n toolName: item.toolName,\n args: item.args,\n result: item.result,\n status: item.state,\n ...(assetTitles ? { assetTitles } : {}),\n ...(resolveToolDisplayName ? { displayName: resolveToolDisplayName(item.toolName) } : {}),\n });\n}\n\n/** The collapsed-card summary of a finished turn. */\nexport function getActivitySummary(timeline: readonly ActivityItem[]): string {\n const toolCount = countActivityTools(timeline);\n const hasIssue = timeline.some(\n (item) => item.kind === 'tool' && (item.state === 'error' || item.state === 'rejected'),\n );\n if (hasIssue) return 'Completed with issues';\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'cancelled')) {\n return 'Action cancelled';\n }\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'paused')) {\n return 'Paused during tool use';\n }\n if (toolCount > 0) return `Used ${toolCount} ${toolCount === 1 ? 'tool' : 'tools'}`;\n return 'Reasoning complete';\n}\n\n/** The part shape the final-text read needs; any message role's parts satisfy it. */\nexport type FinalTextPart = { readonly type: string; readonly text?: string };\n\n/**\n * Whether a text part shows below the card instead of in the details panel:\n * it comes after the final tool call, or it holds a spoken voice turn's words\n * (a live turn heard during a delegated run lands between the run's tool\n * calls, see `isSpokenTurnTextPart`; it is the conversation, not narration).\n */\nfunction isAnswerTextPart(\n part: { readonly type: string } | undefined,\n index: number,\n lastToolIndex: number,\n): boolean {\n return part?.type === 'text' && (index > lastToolIndex || isSpokenTurnTextPart(part));\n}\n\n/**\n * The visible answer of a grouped turn: the text after the final tool call\n * (all of it when the turn never called a tool), plus the words of every\n * spoken voice turn in the message, in order. Other intermediate text (before\n * or between tool calls) stays available in the details panel.\n */\nexport function getFinalText(content: readonly FinalTextPart[] | undefined): string | null {\n const parts = getFinalTextParts(content);\n return parts.length > 0 ? parts.map((part) => part.text).join('\\n\\n') : null;\n}\n\n/** One text part of the visible answer, with its index in the message content. */\nexport interface FinalTextSegment {\n index: number;\n text: string;\n}\n\n/**\n * The parts `getFinalText` joins, each kept separate with its content index.\n * A spoken turn and the run's own reply can stream at the same time, so the\n * earlier part may grow while a later one exists: rendered as one joined\n * string, that text changes in the middle rather than at its end, and the\n * streaming reveal restarts from an empty bubble on every word.\n */\nexport function getFinalTextParts(content: readonly FinalTextPart[] | undefined): FinalTextSegment[] {\n if (!content?.length) return [];\n\n const lastToolIndex = content.findLastIndex((part) => part?.type === 'tool-call');\n const parts: FinalTextSegment[] = [];\n content.forEach((part, index) => {\n if (part.text && isAnswerTextPart(part, index, lastToolIndex)) parts.push({ index, text: part.text });\n });\n return parts;\n}\n\n/**\n * Keep the answer out of the details panel: it renders below the card\n * (`SuperGroupingFinalText`), so the details grouping drops every text part\n * `getFinalText` shows and any group that becomes empty.\n */\nexport function excludeFinalTextFromGroups(grouping: GroupingFunction): GroupingFunction {\n return (parts) => {\n const lastToolIndex = parts.findLastIndex((part) => part?.type === 'tool-call');\n return grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => !isAnswerTextPart(parts[index], index, lastToolIndex)),\n }))\n .filter((group) => group.indices.length > 0);\n };\n}\n\n/**\n * Drop the parts `exclude` matches from every group, and any group left\n * empty: `SuperGroupingCard` renders inline tool calls outside the details,\n * so they must not render a second time inside it.\n */\nexport function excludePartsFromGroups(\n grouping: GroupingFunction,\n exclude: (part: GroupablePart) => boolean,\n): GroupingFunction {\n return (parts) =>\n grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => {\n const part = parts[index];\n return part === undefined || !exclude(part);\n }),\n }))\n .filter((group) => group.indices.length > 0);\n}\n"],"names":["readRejectedToolResult","classifyToolResult","summarizeToolCall","isSpokenTurnTextPart"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * The assistant turn's activity timeline — the one derivation of "what did
3
- * this turn do, and how did each step end" behind the grouped
4
- * ("conversational") view on every surface: the SDK's `AthenaChat`, Olympus's
5
- * Spaces chat, and the Chrome extension. Pure functions over assistant-ui
6
- * message parts; `SuperGroupingCard` renders them.
3
+ * this turn do, and how did each step end" behind the collapsed view
4
+ * (previously called the conversational view) on every surface: the SDK's
5
+ * `AthenaChat`, Olympus's Spaces chat, and the Chrome extension. Pure
6
+ * functions over assistant-ui message parts; `SuperGroupingCard` renders them.
7
7
  *
8
8
  * Step states come from the shared classifier (`classifyToolResult`) plus the
9
9
  * approval outcomes a part carries (`approval`, `interrupt`, a rejection
@@ -1 +1 @@
1
- {"version":3,"file":"activity-timeline.js","sources":["../../../src/chat/super-grouping/activity-timeline.ts"],"sourcesContent":["/**\n * The assistant turn's activity timeline — the one derivation of \"what did\n * this turn do, and how did each step end\" behind the grouped\n * (\"conversational\") view on every surface: the SDK's `AthenaChat`, Olympus's\n * Spaces chat, and the Chrome extension. Pure functions over assistant-ui\n * message parts; `SuperGroupingCard` renders them.\n *\n * Step states come from the shared classifier (`classifyToolResult`) plus the\n * approval outcomes a part carries (`approval`, `interrupt`, a rejection\n * result), so a call that reads as failed, paused, or rejected on one surface\n * cannot read as a green check on another. Copy comes from the shared tool\n * summary registry (`summarizeToolCall`), itself built on the display\n * registry.\n */\nimport type {\n MessageStatus,\n ThreadAssistantMessagePart,\n ToolCallMessagePartStatus,\n} from '@assistant-ui/react';\nimport {\n classifyToolResult,\n isSpokenTurnTextPart,\n readRejectedToolResult,\n type ToolStatusLabelState,\n} from '@athenaintel/agent-runtime';\nimport { summarizeToolCall, type ToolCallSummary } from '../../tools/tool-summary';\nimport type { GroupablePart, GroupingFunction } from './grouping-function';\n\nexport type ActivityToolState = ToolStatusLabelState;\n\nexport type ActivityItem =\n | {\n kind: 'reasoning';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n text: string;\n state: 'running' | 'complete';\n }\n | {\n kind: 'tool';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n toolName: string;\n args?: ToolCallPart['args'];\n /** The tool's real result; absent while it runs or holds only the streaming placeholder. */\n result?: unknown;\n state: ActivityToolState;\n };\n\n/** The turn as a whole: still working, parked on the person, ended in error, or done. */\nexport type ActivityPhase = 'running' | 'waiting' | 'complete' | 'error';\n\ntype ToolCallPart = Extract<ThreadAssistantMessagePart, { type: 'tool-call' }>;\n\nexport interface ActivityTimelineOptions {\n /**\n * Tools whose unresolved call means the turn is waiting on the person even\n * without an interrupt or approval on the part (the Chrome extension's\n * device plan approval, which the tool UI itself collects).\n */\n waitingTools?: ReadonlySet<string>;\n /**\n * Tools whose result is an application payload relayed verbatim (the Chrome\n * extension's page JavaScript), so a `success: false` flag counts only with\n * an error detail — see `classifyToolResult`'s `passThroughPayload`.\n */\n passThroughTools?: ReadonlySet<string>;\n}\n\nconst NO_TOOLS: ReadonlySet<string> = new Set();\n\n/**\n * Whether a tool-call part still holds the backend's streaming placeholder\n * result rather than the tool's real output. Long-running tools (task\n * subagents, studio and Python execution, deep research) append a ToolMessage\n * the moment they start so their card can fill in live; it carries\n * `additional_kwargs.streaming`, which the runtime converter lifts into\n * `artifact._tool_message_metadata`. The real ToolMessage that replaces it\n * has no such flag, so a defined `result` alone does not mean the tool is done.\n */\nexport function isStreamingToolPlaceholder(part: Pick<ToolCallPart, 'artifact'>): boolean {\n const artifact: unknown = part.artifact;\n if (typeof artifact !== 'object' || artifact === null) return false;\n const metadata: unknown = (artifact as { _tool_message_metadata?: unknown })\n ._tool_message_metadata;\n if (typeof metadata !== 'object' || metadata === null) return false;\n return (metadata as { streaming?: unknown }).streaming === true;\n}\n\n/** The tool's real result: undefined while it has none or only the streaming placeholder. */\nfunction finalResult(part: ToolCallPart): unknown {\n return isStreamingToolPlaceholder(part) ? undefined : part.result;\n}\n\nfunction toolCallStatus(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n): ToolCallMessagePartStatus | undefined {\n if (finalResult(part) !== undefined) return { type: 'complete' };\n if (messageStatus?.type === 'incomplete') {\n return {\n type: 'incomplete',\n reason: messageStatus.reason === 'tool-calls' ? 'other' : messageStatus.reason,\n error: messageStatus.error,\n };\n }\n if (messageStatus?.type === 'complete') return { type: 'complete' };\n if (messageStatus?.type === 'requires-action') {\n return { type: 'requires-action', reason: messageStatus.reason };\n }\n if (messageStatus?.type === 'running') return { type: 'running' };\n return undefined;\n}\n\n/** How one tool call ended (or is going), reading the approval fields before the result. */\nexport function getActivityToolState(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n { waitingTools = NO_TOOLS, passThroughTools = NO_TOOLS }: ActivityTimelineOptions = {},\n): ActivityToolState {\n if (part.approval?.approved === false || readRejectedToolResult(part.result) !== null) {\n return 'rejected';\n }\n if (part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired') {\n return 'cancelled';\n }\n const result = finalResult(part);\n const unresolved = result === undefined;\n const messageIsActive =\n messageStatus === undefined ||\n messageStatus.type === 'running' ||\n messageStatus.type === 'requires-action';\n if (\n unresolved &&\n (part.interrupt?.type === 'human' ||\n (part.approval !== undefined &&\n part.approval.approved === undefined &&\n part.approval.resolution === undefined) ||\n (waitingTools.has(part.toolName) && messageIsActive))\n ) {\n return 'waiting';\n }\n\n const classification = classifyToolResult({\n status: toolCallStatus(part, messageStatus),\n result,\n isError: part.isError,\n passThroughPayload: passThroughTools.has(part.toolName),\n });\n if (classification.state === 'requires-action') return 'waiting';\n return classification.state;\n}\n\n/**\n * The compact reasoning/tool timeline in the order the parts streamed.\n *\n * A reasoning part is still streaming only while it is the final part of a\n * running message — once any later part appears, the thought has settled.\n * Settled reasoning parts with no text are dropped so the list never shows an\n * empty thinking row.\n */\nexport function buildActivityTimeline(\n content: readonly ThreadAssistantMessagePart[] | undefined,\n messageStatus: MessageStatus | undefined,\n options: ActivityTimelineOptions = {},\n): ActivityItem[] {\n if (!content?.length) return [];\n\n const lastPartIndex = content.length - 1;\n const timeline: ActivityItem[] = [];\n for (let index = 0; index < content.length; index += 1) {\n const part = content[index];\n if (part.type === 'tool-call') {\n const result = finalResult(part);\n timeline.push({\n kind: 'tool',\n id: part.toolCallId,\n partIndex: index,\n args: part.args,\n ...(result !== undefined ? { result } : {}),\n toolName: part.toolName,\n state: getActivityToolState(part, messageStatus, options),\n });\n continue;\n }\n if (part.type !== 'reasoning') continue;\n\n const text = typeof part.text === 'string' ? part.text : '';\n const stillStreaming = messageStatus?.type === 'running' && index === lastPartIndex;\n if (!stillStreaming && text.trim() === '') continue;\n timeline.push({\n kind: 'reasoning',\n id: `reasoning-${index}`,\n partIndex: index,\n text,\n state: stillStreaming ? 'running' : 'complete',\n });\n }\n return timeline;\n}\n\n/** Number of tool calls in the timeline. */\nexport function countActivityTools(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => (item.kind === 'tool' ? count + 1 : count), 0);\n}\n\n/**\n * The turn's phase. Waiting on the person wins over everything — a\n * `requires-action` status, a waiting tool, or a host's own `waitingForInput`\n * assertion (no in-repo host passes one) — then the message's own status.\n */\nexport function resolveActivityPhase(\n status: MessageStatus | undefined,\n timeline: readonly ActivityItem[],\n { waitingForInput = false }: { waitingForInput?: boolean } = {},\n): ActivityPhase {\n if (\n waitingForInput ||\n status?.type === 'requires-action' ||\n timeline.some((item) => item.kind === 'tool' && item.state === 'waiting')\n ) {\n return 'waiting';\n }\n if (status?.type === 'running') return 'running';\n if (status?.type === 'incomplete') return 'error';\n return 'complete';\n}\n\n/**\n * A settled thought's row: the heading a reasoning summary opens with\n * (\"**Checking the workstation**\" → \"Checking the workstation\"), else the\n * generic wording. The thought itself stays in the run's details.\n */\nexport function getReasoningLabel(text: string, state: 'running' | 'complete'): string {\n if (state === 'running') return 'Thinking';\n const heading = /^\\s*\\*\\*([^*\\n]{3,80}?)\\*\\*/.exec(text)?.[1]?.trim();\n return heading ? heading.replace(/[.:]+$/, '') : 'Thought through the next step';\n}\n\n/**\n * The status-row copy for one step: the call's own summary from the shared\n * summary registry (`summarizeToolCall`: \"Ran git status\", \"Read config.ts\").\n * `resolveToolDisplayName` lets a host with a richer tool catalog name tools\n * neither registry has an entry for; `assetTitles` names the machine or\n * document a call targeted by id when an earlier result in the turn did.\n */\nexport function getActivityItemLabel(\n item: ActivityItem,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): string {\n if (item.kind === 'reasoning') return getReasoningLabel(item.text, item.state);\n return summarizeActivityTool(item, resolveToolDisplayName, assetTitles).label;\n}\n\n/** The summary of one tool step (see {@link getActivityItemLabel}). */\nexport function summarizeActivityTool(\n item: Extract<ActivityItem, { kind: 'tool' }>,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): ToolCallSummary {\n return summarizeToolCall({\n toolName: item.toolName,\n args: item.args,\n result: item.result,\n status: item.state,\n ...(assetTitles ? { assetTitles } : {}),\n ...(resolveToolDisplayName ? { displayName: resolveToolDisplayName(item.toolName) } : {}),\n });\n}\n\n/** The collapsed-card summary of a finished turn. */\nexport function getActivitySummary(timeline: readonly ActivityItem[]): string {\n const toolCount = countActivityTools(timeline);\n const hasIssue = timeline.some(\n (item) => item.kind === 'tool' && (item.state === 'error' || item.state === 'rejected'),\n );\n if (hasIssue) return 'Completed with issues';\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'cancelled')) {\n return 'Action cancelled';\n }\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'paused')) {\n return 'Paused during tool use';\n }\n if (toolCount > 0) return `Used ${toolCount} ${toolCount === 1 ? 'tool' : 'tools'}`;\n return 'Reasoning complete';\n}\n\n/** The part shape the final-text read needs; any message role's parts satisfy it. */\nexport type FinalTextPart = { readonly type: string; readonly text?: string };\n\n/**\n * Whether a text part shows below the card instead of in the details panel:\n * it comes after the final tool call, or it holds a spoken voice turn's words\n * (a live turn heard during a delegated run lands between the run's tool\n * calls, see `isSpokenTurnTextPart`; it is the conversation, not narration).\n */\nfunction isAnswerTextPart(\n part: { readonly type: string } | undefined,\n index: number,\n lastToolIndex: number,\n): boolean {\n return part?.type === 'text' && (index > lastToolIndex || isSpokenTurnTextPart(part));\n}\n\n/**\n * The visible answer of a grouped turn: the text after the final tool call\n * (all of it when the turn never called a tool), plus the words of every\n * spoken voice turn in the message, in order. Other intermediate text (before\n * or between tool calls) stays available in the details panel.\n */\nexport function getFinalText(content: readonly FinalTextPart[] | undefined): string | null {\n const parts = getFinalTextParts(content);\n return parts.length > 0 ? parts.map((part) => part.text).join('\\n\\n') : null;\n}\n\n/** One text part of the visible answer, with its index in the message content. */\nexport interface FinalTextSegment {\n index: number;\n text: string;\n}\n\n/**\n * The parts `getFinalText` joins, each kept separate with its content index.\n * A spoken turn and the run's own reply can stream at the same time, so the\n * earlier part may grow while a later one exists: rendered as one joined\n * string, that text changes in the middle rather than at its end, and the\n * streaming reveal restarts from an empty bubble on every word.\n */\nexport function getFinalTextParts(content: readonly FinalTextPart[] | undefined): FinalTextSegment[] {\n if (!content?.length) return [];\n\n const lastToolIndex = content.findLastIndex((part) => part?.type === 'tool-call');\n const parts: FinalTextSegment[] = [];\n content.forEach((part, index) => {\n if (part.text && isAnswerTextPart(part, index, lastToolIndex)) parts.push({ index, text: part.text });\n });\n return parts;\n}\n\n/**\n * Keep the answer out of the details panel: it renders below the card\n * (`SuperGroupingFinalText`), so the details grouping drops every text part\n * `getFinalText` shows and any group that becomes empty.\n */\nexport function excludeFinalTextFromGroups(grouping: GroupingFunction): GroupingFunction {\n return (parts) => {\n const lastToolIndex = parts.findLastIndex((part) => part?.type === 'tool-call');\n return grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => !isAnswerTextPart(parts[index], index, lastToolIndex)),\n }))\n .filter((group) => group.indices.length > 0);\n };\n}\n\n/**\n * Drop the parts `exclude` matches from every group, and any group left\n * empty: `SuperGroupingCard` renders inline tool calls outside the details,\n * so they must not render a second time inside it.\n */\nexport function excludePartsFromGroups(\n grouping: GroupingFunction,\n exclude: (part: GroupablePart) => boolean,\n): GroupingFunction {\n return (parts) =>\n grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => {\n const part = parts[index];\n return part === undefined || !exclude(part);\n }),\n }))\n .filter((group) => group.indices.length > 0);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"activity-timeline.js","sources":["../../../src/chat/super-grouping/activity-timeline.ts"],"sourcesContent":["/**\n * The assistant turn's activity timeline — the one derivation of \"what did\n * this turn do, and how did each step end\" behind the collapsed view\n * (previously called the conversational view) on every surface: the SDK's\n * `AthenaChat`, Olympus's Spaces chat, and the Chrome extension. Pure\n * functions over assistant-ui message parts; `SuperGroupingCard` renders them.\n *\n * Step states come from the shared classifier (`classifyToolResult`) plus the\n * approval outcomes a part carries (`approval`, `interrupt`, a rejection\n * result), so a call that reads as failed, paused, or rejected on one surface\n * cannot read as a green check on another. Copy comes from the shared tool\n * summary registry (`summarizeToolCall`), itself built on the display\n * registry.\n */\nimport type {\n MessageStatus,\n ThreadAssistantMessagePart,\n ToolCallMessagePartStatus,\n} from '@assistant-ui/react';\nimport {\n classifyToolResult,\n isSpokenTurnTextPart,\n readRejectedToolResult,\n type ToolStatusLabelState,\n} from '@athenaintel/agent-runtime';\nimport { summarizeToolCall, type ToolCallSummary } from '../../tools/tool-summary';\nimport type { GroupablePart, GroupingFunction } from './grouping-function';\n\nexport type ActivityToolState = ToolStatusLabelState;\n\nexport type ActivityItem =\n | {\n kind: 'reasoning';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n text: string;\n state: 'running' | 'complete';\n }\n | {\n kind: 'tool';\n id?: string;\n /** Position of the part in the message's content. */\n partIndex?: number;\n toolName: string;\n args?: ToolCallPart['args'];\n /** The tool's real result; absent while it runs or holds only the streaming placeholder. */\n result?: unknown;\n state: ActivityToolState;\n };\n\n/** The turn as a whole: still working, parked on the person, ended in error, or done. */\nexport type ActivityPhase = 'running' | 'waiting' | 'complete' | 'error';\n\ntype ToolCallPart = Extract<ThreadAssistantMessagePart, { type: 'tool-call' }>;\n\nexport interface ActivityTimelineOptions {\n /**\n * Tools whose unresolved call means the turn is waiting on the person even\n * without an interrupt or approval on the part (the Chrome extension's\n * device plan approval, which the tool UI itself collects).\n */\n waitingTools?: ReadonlySet<string>;\n /**\n * Tools whose result is an application payload relayed verbatim (the Chrome\n * extension's page JavaScript), so a `success: false` flag counts only with\n * an error detail — see `classifyToolResult`'s `passThroughPayload`.\n */\n passThroughTools?: ReadonlySet<string>;\n}\n\nconst NO_TOOLS: ReadonlySet<string> = new Set();\n\n/**\n * Whether a tool-call part still holds the backend's streaming placeholder\n * result rather than the tool's real output. Long-running tools (task\n * subagents, studio and Python execution, deep research) append a ToolMessage\n * the moment they start so their card can fill in live; it carries\n * `additional_kwargs.streaming`, which the runtime converter lifts into\n * `artifact._tool_message_metadata`. The real ToolMessage that replaces it\n * has no such flag, so a defined `result` alone does not mean the tool is done.\n */\nexport function isStreamingToolPlaceholder(part: Pick<ToolCallPart, 'artifact'>): boolean {\n const artifact: unknown = part.artifact;\n if (typeof artifact !== 'object' || artifact === null) return false;\n const metadata: unknown = (artifact as { _tool_message_metadata?: unknown })\n ._tool_message_metadata;\n if (typeof metadata !== 'object' || metadata === null) return false;\n return (metadata as { streaming?: unknown }).streaming === true;\n}\n\n/** The tool's real result: undefined while it has none or only the streaming placeholder. */\nfunction finalResult(part: ToolCallPart): unknown {\n return isStreamingToolPlaceholder(part) ? undefined : part.result;\n}\n\nfunction toolCallStatus(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n): ToolCallMessagePartStatus | undefined {\n if (finalResult(part) !== undefined) return { type: 'complete' };\n if (messageStatus?.type === 'incomplete') {\n return {\n type: 'incomplete',\n reason: messageStatus.reason === 'tool-calls' ? 'other' : messageStatus.reason,\n error: messageStatus.error,\n };\n }\n if (messageStatus?.type === 'complete') return { type: 'complete' };\n if (messageStatus?.type === 'requires-action') {\n return { type: 'requires-action', reason: messageStatus.reason };\n }\n if (messageStatus?.type === 'running') return { type: 'running' };\n return undefined;\n}\n\n/** How one tool call ended (or is going), reading the approval fields before the result. */\nexport function getActivityToolState(\n part: ToolCallPart,\n messageStatus: MessageStatus | undefined,\n { waitingTools = NO_TOOLS, passThroughTools = NO_TOOLS }: ActivityTimelineOptions = {},\n): ActivityToolState {\n if (part.approval?.approved === false || readRejectedToolResult(part.result) !== null) {\n return 'rejected';\n }\n if (part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired') {\n return 'cancelled';\n }\n const result = finalResult(part);\n const unresolved = result === undefined;\n const messageIsActive =\n messageStatus === undefined ||\n messageStatus.type === 'running' ||\n messageStatus.type === 'requires-action';\n if (\n unresolved &&\n (part.interrupt?.type === 'human' ||\n (part.approval !== undefined &&\n part.approval.approved === undefined &&\n part.approval.resolution === undefined) ||\n (waitingTools.has(part.toolName) && messageIsActive))\n ) {\n return 'waiting';\n }\n\n const classification = classifyToolResult({\n status: toolCallStatus(part, messageStatus),\n result,\n isError: part.isError,\n passThroughPayload: passThroughTools.has(part.toolName),\n });\n if (classification.state === 'requires-action') return 'waiting';\n return classification.state;\n}\n\n/**\n * The compact reasoning/tool timeline in the order the parts streamed.\n *\n * A reasoning part is still streaming only while it is the final part of a\n * running message — once any later part appears, the thought has settled.\n * Settled reasoning parts with no text are dropped so the list never shows an\n * empty thinking row.\n */\nexport function buildActivityTimeline(\n content: readonly ThreadAssistantMessagePart[] | undefined,\n messageStatus: MessageStatus | undefined,\n options: ActivityTimelineOptions = {},\n): ActivityItem[] {\n if (!content?.length) return [];\n\n const lastPartIndex = content.length - 1;\n const timeline: ActivityItem[] = [];\n for (let index = 0; index < content.length; index += 1) {\n const part = content[index];\n if (part.type === 'tool-call') {\n const result = finalResult(part);\n timeline.push({\n kind: 'tool',\n id: part.toolCallId,\n partIndex: index,\n args: part.args,\n ...(result !== undefined ? { result } : {}),\n toolName: part.toolName,\n state: getActivityToolState(part, messageStatus, options),\n });\n continue;\n }\n if (part.type !== 'reasoning') continue;\n\n const text = typeof part.text === 'string' ? part.text : '';\n const stillStreaming = messageStatus?.type === 'running' && index === lastPartIndex;\n if (!stillStreaming && text.trim() === '') continue;\n timeline.push({\n kind: 'reasoning',\n id: `reasoning-${index}`,\n partIndex: index,\n text,\n state: stillStreaming ? 'running' : 'complete',\n });\n }\n return timeline;\n}\n\n/** Number of tool calls in the timeline. */\nexport function countActivityTools(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => (item.kind === 'tool' ? count + 1 : count), 0);\n}\n\n/**\n * The turn's phase. Waiting on the person wins over everything — a\n * `requires-action` status, a waiting tool, or a host's own `waitingForInput`\n * assertion (no in-repo host passes one) — then the message's own status.\n */\nexport function resolveActivityPhase(\n status: MessageStatus | undefined,\n timeline: readonly ActivityItem[],\n { waitingForInput = false }: { waitingForInput?: boolean } = {},\n): ActivityPhase {\n if (\n waitingForInput ||\n status?.type === 'requires-action' ||\n timeline.some((item) => item.kind === 'tool' && item.state === 'waiting')\n ) {\n return 'waiting';\n }\n if (status?.type === 'running') return 'running';\n if (status?.type === 'incomplete') return 'error';\n return 'complete';\n}\n\n/**\n * A settled thought's row: the heading a reasoning summary opens with\n * (\"**Checking the workstation**\" → \"Checking the workstation\"), else the\n * generic wording. The thought itself stays in the run's details.\n */\nexport function getReasoningLabel(text: string, state: 'running' | 'complete'): string {\n if (state === 'running') return 'Thinking';\n const heading = /^\\s*\\*\\*([^*\\n]{3,80}?)\\*\\*/.exec(text)?.[1]?.trim();\n return heading ? heading.replace(/[.:]+$/, '') : 'Thought through the next step';\n}\n\n/**\n * The status-row copy for one step: the call's own summary from the shared\n * summary registry (`summarizeToolCall`: \"Ran git status\", \"Read config.ts\").\n * `resolveToolDisplayName` lets a host with a richer tool catalog name tools\n * neither registry has an entry for; `assetTitles` names the machine or\n * document a call targeted by id when an earlier result in the turn did.\n */\nexport function getActivityItemLabel(\n item: ActivityItem,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): string {\n if (item.kind === 'reasoning') return getReasoningLabel(item.text, item.state);\n return summarizeActivityTool(item, resolveToolDisplayName, assetTitles).label;\n}\n\n/** The summary of one tool step (see {@link getActivityItemLabel}). */\nexport function summarizeActivityTool(\n item: Extract<ActivityItem, { kind: 'tool' }>,\n resolveToolDisplayName?: (toolName: string) => string | undefined,\n assetTitles?: ReadonlyMap<string, string>,\n): ToolCallSummary {\n return summarizeToolCall({\n toolName: item.toolName,\n args: item.args,\n result: item.result,\n status: item.state,\n ...(assetTitles ? { assetTitles } : {}),\n ...(resolveToolDisplayName ? { displayName: resolveToolDisplayName(item.toolName) } : {}),\n });\n}\n\n/** The collapsed-card summary of a finished turn. */\nexport function getActivitySummary(timeline: readonly ActivityItem[]): string {\n const toolCount = countActivityTools(timeline);\n const hasIssue = timeline.some(\n (item) => item.kind === 'tool' && (item.state === 'error' || item.state === 'rejected'),\n );\n if (hasIssue) return 'Completed with issues';\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'cancelled')) {\n return 'Action cancelled';\n }\n if (timeline.some((item) => item.kind === 'tool' && item.state === 'paused')) {\n return 'Paused during tool use';\n }\n if (toolCount > 0) return `Used ${toolCount} ${toolCount === 1 ? 'tool' : 'tools'}`;\n return 'Reasoning complete';\n}\n\n/** The part shape the final-text read needs; any message role's parts satisfy it. */\nexport type FinalTextPart = { readonly type: string; readonly text?: string };\n\n/**\n * Whether a text part shows below the card instead of in the details panel:\n * it comes after the final tool call, or it holds a spoken voice turn's words\n * (a live turn heard during a delegated run lands between the run's tool\n * calls, see `isSpokenTurnTextPart`; it is the conversation, not narration).\n */\nfunction isAnswerTextPart(\n part: { readonly type: string } | undefined,\n index: number,\n lastToolIndex: number,\n): boolean {\n return part?.type === 'text' && (index > lastToolIndex || isSpokenTurnTextPart(part));\n}\n\n/**\n * The visible answer of a grouped turn: the text after the final tool call\n * (all of it when the turn never called a tool), plus the words of every\n * spoken voice turn in the message, in order. Other intermediate text (before\n * or between tool calls) stays available in the details panel.\n */\nexport function getFinalText(content: readonly FinalTextPart[] | undefined): string | null {\n const parts = getFinalTextParts(content);\n return parts.length > 0 ? parts.map((part) => part.text).join('\\n\\n') : null;\n}\n\n/** One text part of the visible answer, with its index in the message content. */\nexport interface FinalTextSegment {\n index: number;\n text: string;\n}\n\n/**\n * The parts `getFinalText` joins, each kept separate with its content index.\n * A spoken turn and the run's own reply can stream at the same time, so the\n * earlier part may grow while a later one exists: rendered as one joined\n * string, that text changes in the middle rather than at its end, and the\n * streaming reveal restarts from an empty bubble on every word.\n */\nexport function getFinalTextParts(content: readonly FinalTextPart[] | undefined): FinalTextSegment[] {\n if (!content?.length) return [];\n\n const lastToolIndex = content.findLastIndex((part) => part?.type === 'tool-call');\n const parts: FinalTextSegment[] = [];\n content.forEach((part, index) => {\n if (part.text && isAnswerTextPart(part, index, lastToolIndex)) parts.push({ index, text: part.text });\n });\n return parts;\n}\n\n/**\n * Keep the answer out of the details panel: it renders below the card\n * (`SuperGroupingFinalText`), so the details grouping drops every text part\n * `getFinalText` shows and any group that becomes empty.\n */\nexport function excludeFinalTextFromGroups(grouping: GroupingFunction): GroupingFunction {\n return (parts) => {\n const lastToolIndex = parts.findLastIndex((part) => part?.type === 'tool-call');\n return grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => !isAnswerTextPart(parts[index], index, lastToolIndex)),\n }))\n .filter((group) => group.indices.length > 0);\n };\n}\n\n/**\n * Drop the parts `exclude` matches from every group, and any group left\n * empty: `SuperGroupingCard` renders inline tool calls outside the details,\n * so they must not render a second time inside it.\n */\nexport function excludePartsFromGroups(\n grouping: GroupingFunction,\n exclude: (part: GroupablePart) => boolean,\n): GroupingFunction {\n return (parts) =>\n grouping(parts)\n .map((group) => ({\n ...group,\n indices: group.indices.filter((index) => {\n const part = parts[index];\n return part === undefined || !exclude(part);\n }),\n }))\n .filter((group) => group.indices.length > 0);\n}\n"],"names":[],"mappings":";;;AAuEA,MAAM,+BAAoC,IAAA;AAWnC,SAAS,2BAA2B,MAA+C;AACxF,QAAM,WAAoB,KAAK;AAC/B,MAAI,OAAO,aAAa,YAAY,aAAa,KAAM,QAAO;AAC9D,QAAM,WAAqB,SACxB;AACH,MAAI,OAAO,aAAa,YAAY,aAAa,KAAM,QAAO;AAC9D,SAAQ,SAAqC,cAAc;AAC7D;AAGA,SAAS,YAAY,MAA6B;AAChD,SAAO,2BAA2B,IAAI,IAAI,SAAY,KAAK;AAC7D;AAEA,SAAS,eACP,MACA,eACuC;AACvC,MAAI,YAAY,IAAI,MAAM,OAAW,QAAO,EAAE,MAAM,WAAA;AACpD,OAAI,+CAAe,UAAS,cAAc;AACxC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ,cAAc,WAAW,eAAe,UAAU,cAAc;AAAA,MACxE,OAAO,cAAc;AAAA,IAAA;AAAA,EAEzB;AACA,OAAI,+CAAe,UAAS,WAAY,QAAO,EAAE,MAAM,WAAA;AACvD,OAAI,+CAAe,UAAS,mBAAmB;AAC7C,WAAO,EAAE,MAAM,mBAAmB,QAAQ,cAAc,OAAA;AAAA,EAC1D;AACA,OAAI,+CAAe,UAAS,UAAW,QAAO,EAAE,MAAM,UAAA;AACtD,SAAO;AACT;AAGO,SAAS,qBACd,MACA,eACA,EAAE,eAAe,UAAU,mBAAmB,SAAA,IAAsC,IACjE;;AACnB,QAAI,UAAK,aAAL,mBAAe,cAAa,SAAS,uBAAuB,KAAK,MAAM,MAAM,MAAM;AACrF,WAAO;AAAA,EACT;AACA,QAAI,UAAK,aAAL,mBAAe,gBAAe,iBAAe,UAAK,aAAL,mBAAe,gBAAe,WAAW;AACxF,WAAO;AAAA,EACT;AACA,QAAM,SAAS,YAAY,IAAI;AAC/B,QAAM,aAAa,WAAW;AAC9B,QAAM,kBACJ,kBAAkB,UAClB,cAAc,SAAS,aACvB,cAAc,SAAS;AACzB,MACE,iBACC,UAAK,cAAL,mBAAgB,UAAS,WACvB,KAAK,aAAa,UACjB,KAAK,SAAS,aAAa,UAC3B,KAAK,SAAS,eAAe,UAC9B,aAAa,IAAI,KAAK,QAAQ,KAAK,kBACtC;AACA,WAAO;AAAA,EACT;AAEA,QAAM,iBAAiB,mBAAmB;AAAA,IACxC,QAAQ,eAAe,MAAM,aAAa;AAAA,IAC1C;AAAA,IACA,SAAS,KAAK;AAAA,IACd,oBAAoB,iBAAiB,IAAI,KAAK,QAAQ;AAAA,EAAA,CACvD;AACD,MAAI,eAAe,UAAU,kBAAmB,QAAO;AACvD,SAAO,eAAe;AACxB;AAUO,SAAS,sBACd,SACA,eACA,UAAmC,CAAA,GACnB;AAChB,MAAI,EAAC,mCAAS,QAAQ,QAAO,CAAA;AAE7B,QAAM,gBAAgB,QAAQ,SAAS;AACvC,QAAM,WAA2B,CAAA;AACjC,WAAS,QAAQ,GAAG,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtD,UAAM,OAAO,QAAQ,KAAK;AAC1B,QAAI,KAAK,SAAS,aAAa;AAC7B,YAAM,SAAS,YAAY,IAAI;AAC/B,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,IAAI,KAAK;AAAA,QACT,WAAW;AAAA,QACX,MAAM,KAAK;AAAA,QACX,GAAI,WAAW,SAAY,EAAE,OAAA,IAAW,CAAA;AAAA,QACxC,UAAU,KAAK;AAAA,QACf,OAAO,qBAAqB,MAAM,eAAe,OAAO;AAAA,MAAA,CACzD;AACD;AAAA,IACF;AACA,QAAI,KAAK,SAAS,YAAa;AAE/B,UAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AACzD,UAAM,kBAAiB,+CAAe,UAAS,aAAa,UAAU;AACtE,QAAI,CAAC,kBAAkB,KAAK,KAAA,MAAW,GAAI;AAC3C,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,IAAI,aAAa,KAAK;AAAA,MACtB,WAAW;AAAA,MACX;AAAA,MACA,OAAO,iBAAiB,YAAY;AAAA,IAAA,CACrC;AAAA,EACH;AACA,SAAO;AACT;AAGO,SAAS,mBAAmB,UAA2C;AAC5E,SAAO,SAAS,OAAO,CAAC,OAAO,SAAU,KAAK,SAAS,SAAS,QAAQ,IAAI,OAAQ,CAAC;AACvF;AAOO,SAAS,qBACd,QACA,UACA,EAAE,kBAAkB,MAAA,IAAyC,IAC9C;AACf,MACE,oBACA,iCAAQ,UAAS,qBACjB,SAAS,KAAK,CAAC,SAAS,KAAK,SAAS,UAAU,KAAK,UAAU,SAAS,GACxE;AACA,WAAO;AAAA,EACT;AACA,OAAI,iCAAQ,UAAS,UAAW,QAAO;AACvC,OAAI,iCAAQ,UAAS,aAAc,QAAO;AAC1C,SAAO;AACT;AAOO,SAAS,kBAAkB,MAAc,OAAuC;;AACrF,MAAI,UAAU,UAAW,QAAO;AAChC,QAAM,WAAU,yCAA8B,KAAK,IAAI,MAAvC,mBAA2C,OAA3C,mBAA+C;AAC/D,SAAO,UAAU,QAAQ,QAAQ,UAAU,EAAE,IAAI;AACnD;AASO,SAAS,qBACd,MACA,wBACA,aACQ;AACR,MAAI,KAAK,SAAS,YAAa,QAAO,kBAAkB,KAAK,MAAM,KAAK,KAAK;AAC7E,SAAO,sBAAsB,MAAM,wBAAwB,WAAW,EAAE;AAC1E;AAGO,SAAS,sBACd,MACA,wBACA,aACiB;AACjB,SAAO,kBAAkB;AAAA,IACvB,UAAU,KAAK;AAAA,IACf,MAAM,KAAK;AAAA,IACX,QAAQ,KAAK;AAAA,IACb,QAAQ,KAAK;AAAA,IACb,GAAI,cAAc,EAAE,YAAA,IAAgB,CAAA;AAAA,IACpC,GAAI,yBAAyB,EAAE,aAAa,uBAAuB,KAAK,QAAQ,MAAM,CAAA;AAAA,EAAC,CACxF;AACH;AAGO,SAAS,mBAAmB,UAA2C;AAC5E,QAAM,YAAY,mBAAmB,QAAQ;AAC7C,QAAM,WAAW,SAAS;AAAA,IACxB,CAAC,SAAS,KAAK,SAAS,WAAW,KAAK,UAAU,WAAW,KAAK,UAAU;AAAA,EAAA;AAE9E,MAAI,SAAU,QAAO;AACrB,MAAI,SAAS,KAAK,CAAC,SAAS,KAAK,SAAS,UAAU,KAAK,UAAU,WAAW,GAAG;AAC/E,WAAO;AAAA,EACT;AACA,MAAI,SAAS,KAAK,CAAC,SAAS,KAAK,SAAS,UAAU,KAAK,UAAU,QAAQ,GAAG;AAC5E,WAAO;AAAA,EACT;AACA,MAAI,YAAY,EAAG,QAAO,QAAQ,SAAS,IAAI,cAAc,IAAI,SAAS,OAAO;AACjF,SAAO;AACT;AAWA,SAAS,iBACP,MACA,OACA,eACS;AACT,UAAO,6BAAM,UAAS,WAAW,QAAQ,iBAAiB,qBAAqB,IAAI;AACrF;AAQO,SAAS,aAAa,SAA8D;AACzF,QAAM,QAAQ,kBAAkB,OAAO;AACvC,SAAO,MAAM,SAAS,IAAI,MAAM,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,KAAK,MAAM,IAAI;AAC1E;AAeO,SAAS,kBAAkB,SAAmE;AACnG,MAAI,EAAC,mCAAS,QAAQ,QAAO,CAAA;AAE7B,QAAM,gBAAgB,QAAQ,cAAc,CAAC,UAAS,6BAAM,UAAS,WAAW;AAChF,QAAM,QAA4B,CAAA;AAClC,UAAQ,QAAQ,CAAC,MAAM,UAAU;AAC/B,QAAI,KAAK,QAAQ,iBAAiB,MAAM,OAAO,aAAa,EAAG,OAAM,KAAK,EAAE,OAAO,MAAM,KAAK,MAAM;AAAA,EACtG,CAAC;AACD,SAAO;AACT;AAOO,SAAS,2BAA2B,UAA8C;AACvF,SAAO,CAAC,UAAU;AAChB,UAAM,gBAAgB,MAAM,cAAc,CAAC,UAAS,6BAAM,UAAS,WAAW;AAC9E,WAAO,SAAS,KAAK,EAClB,IAAI,CAAC,WAAW;AAAA,MACf,GAAG;AAAA,MACH,SAAS,MAAM,QAAQ,OAAO,CAAC,UAAU,CAAC,iBAAiB,MAAM,KAAK,GAAG,OAAO,aAAa,CAAC;AAAA,IAAA,EAC9F,EACD,OAAO,CAAC,UAAU,MAAM,QAAQ,SAAS,CAAC;AAAA,EAC/C;AACF;AAOO,SAAS,uBACd,UACA,SACkB;AAClB,SAAO,CAAC,UACN,SAAS,KAAK,EACX,IAAI,CAAC,WAAW;AAAA,IACf,GAAG;AAAA,IACH,SAAS,MAAM,QAAQ,OAAO,CAAC,UAAU;AACvC,YAAM,OAAO,MAAM,KAAK;AACxB,aAAO,SAAS,UAAa,CAAC,QAAQ,IAAI;AAAA,IAC5C,CAAC;AAAA,EAAA,EACD,EACD,OAAO,CAAC,UAAU,MAAM,QAAQ,SAAS,CAAC;AACjD;"}
@@ -1,9 +1,10 @@
1
1
  /**
2
- * `@athenaintel/react/super-grouping` — the grouped ("conversational") view of
3
- * an assistant turn: the activity card, its per-toolkit collapsible blocks,
4
- * the timeline derivation behind them, the tool-based grouping function, and
5
- * the transcript layout (the agent's sentences in order with the work between
6
- * them folded, under a "Working for …" header).
2
+ * `@athenaintel/react/super-grouping` — the collapsed view (previously called
3
+ * the conversational view) of an assistant turn: the activity card, its
4
+ * per-toolkit collapsible blocks, the timeline derivation behind them, the
5
+ * tool-based grouping function, and the transcript layout (the agent's
6
+ * sentences in order with the work between them folded, under a "Working
7
+ * for …" header).
7
8
  * A lean entry so hosts with their own thread (Olympus, the Chrome extension)
8
9
  * mount it from source without the SDK's composer stack.
9
10
  */
@@ -29,12 +29,14 @@ const DEFAULT_TOOL_TO_TOOLKIT = {
29
29
  bulk_format_sheet_range: "Spreadsheet",
30
30
  create_table: "Spreadsheet",
31
31
  update_table: "Spreadsheet",
32
- create_chart: "Spreadsheet",
33
32
  update_chart: "Spreadsheet",
34
33
  // Studio sheet PTC
35
34
  CreateWorkbook: "Spreadsheet",
36
35
  AddSheet: "Spreadsheet",
37
36
  OpenWorkbook: "Spreadsheet",
37
+ // Visualizations
38
+ create_chart: "Visualizations (Charts, Dashboards, Figures)",
39
+ create_new_figure: "Visualizations (Charts, Dashboards, Figures)",
38
40
  // Presentation
39
41
  create_powerpoint_deck: "Presentation",
40
42
  create_presentation_pptx_studio: "Presentation",
@@ -1 +1 @@
1
- {"version":3,"file":"toolkit-map.cjs","sources":["../../../src/chat/super-grouping/toolkit-map.ts"],"sourcesContent":["/**\n * Static map of tool names → toolkit group display key, mirroring Olympus's\n * runtime `toolDefinitionsStore` output. The SDK doesn't ship a backend-fetched\n * toolkit catalog, so this provides the same grouping behavior using the names\n * the agent typically calls. Consumers can override via the `getToolGroupKey`\n * prop on `<AthenaChat>`.\n *\n * Keys here are toolkit *display* names (what users see in the toolkit\n * selector), not toolkit IDs — they match Olympus's\n * `getToolkitToGroupKeyMap()` output.\n */\nconst DEFAULT_TOOL_TO_TOOLKIT: Record<string, string> = {\n // Web\n search: 'Web',\n browse: 'Web',\n web_search: 'Web',\n search_web: 'Web',\n web_scrape: 'Web',\n scrape_web: 'Web',\n\n // Document\n create_new_document: 'Document',\n create_document_from_markdown: 'Document',\n append_markdown_to_athena_document: 'Document',\n replace_markdown_in_athena_document: 'Document',\n delete_blocks_from_athena_document: 'Document',\n convert_athena_doc_to_pdf: 'Document',\n convert_to_pdf: 'Document',\n\n // Word document (Studio)\n CreateDocument: 'Document (Word)',\n CreateParagraph: 'Document (Word)',\n OpenDocument: 'Document (Word)',\n execute_word_commands: 'Document (Word)',\n create_new_word_document: 'Document (Word)',\n\n // Spreadsheet\n create_new_sheet: 'Spreadsheet',\n update_sheet_range: 'Spreadsheet',\n format_sheet_range: 'Spreadsheet',\n bulk_format_sheet_range: 'Spreadsheet',\n create_table: 'Spreadsheet',\n update_table: 'Spreadsheet',\n create_chart: 'Spreadsheet',\n update_chart: 'Spreadsheet',\n // Studio sheet PTC\n CreateWorkbook: 'Spreadsheet',\n AddSheet: 'Spreadsheet',\n OpenWorkbook: 'Spreadsheet',\n\n // Presentation\n create_powerpoint_deck: 'Presentation',\n create_presentation_pptx_studio: 'Presentation',\n execute_presentation_code: 'Presentation',\n capture_slide_screenshot: 'Presentation',\n capture_slide_screenshots: 'Presentation',\n // Studio presentation PTC\n CreatePresentation: 'Presentation',\n OpenPresentation: 'Presentation',\n AddSlide: 'Presentation',\n\n // Notebook\n create_new_notebook: 'Notebook',\n run_notebook_cell: 'Notebook',\n\n // Python / code execution\n run_python_code: 'Python',\n run_python: 'Python',\n\n // Database\n run_sql: 'Database',\n run_database_sql: 'Database',\n run_sql_query_tool: 'Database',\n execute_sql: 'Database',\n describe_database: 'Database',\n list_database_tables: 'Database',\n get_database_table_schema: 'Database',\n\n // Email / calendar\n search_email: 'Email',\n unified_email_search: 'Email',\n\n // Media\n capture_moment: 'Computer',\n};\n\n/**\n * Tools that should never participate in grouping — even when surrounded by\n * tools of the same toolkit. Mirrors Olympus's `UNGROUPED_TOOLS`.\n */\nconst UNGROUPED_TOOLS: readonly string[] = [\n 'read_asset',\n 'read_full_asset',\n 'ask',\n 'open_asset_in_workspace',\n 'create_email_draft',\n 'unified_email_create_draft',\n 'unified_email_send',\n 'unified_email_edit_draft',\n];\n\n/**\n * Generic sandbox runtime tools shared across many toolkits (notebook,\n * computer, session sandbox, …). Mirrors Olympus's `CONTEXT_ONLY_TOOLS`:\n * they never start a toolkit group on their own — they only inherit the\n * surrounding group.\n */\nconst CONTEXT_ONLY_TOOLS: readonly string[] = [\n 'execute',\n 'ls',\n 'read_file',\n 'write_file',\n 'edit_file',\n 'glob',\n 'grep',\n];\n\n/**\n * Group display keys for toolkits that target a sandbox and therefore contain\n * the shared runtime tools. Context-only tools may only inherit these groups —\n * an open Web or Email group must not absorb a sandbox call.\n */\nconst SANDBOX_TOOLKIT_GROUPS: readonly string[] = ['Notebook', 'Computer', 'Session Sandbox'];\n\nexport type ToolGroupKeyOptions = {\n /** Display name of the surrounding group, when one is already open. */\n preferredGroupKey?: string;\n /**\n * Distinct tool names the message called. Hosts with a toolkit catalog use\n * it to attribute a tool shared by several toolkits to the one the message\n * leans on; the default map ignores it.\n */\n calledToolNames?: ReadonlySet<string>;\n};\n\n/**\n * Default `getToolGroupKey` implementation used by the SDK's tool grouping.\n * Returns the toolkit display key for a tool name, or `undefined` if the tool\n * is ungrouped or unknown. Context-only tools inherit the surrounding group\n * and are otherwise ungrouped.\n *\n * Override per-app by passing `getToolGroupKey` (or a whole `groupingFunction`) to\n * `SuperGroupingCard`.\n */\nexport const defaultGetToolGroupKey = (\n toolName: string,\n options?: ToolGroupKeyOptions\n): string | undefined => {\n if (UNGROUPED_TOOLS.includes(toolName)) return undefined;\n if (CONTEXT_ONLY_TOOLS.includes(toolName)) {\n const preferred = options?.preferredGroupKey;\n return preferred && SANDBOX_TOOLKIT_GROUPS.includes(preferred) ? preferred : undefined;\n }\n return DEFAULT_TOOL_TO_TOOLKIT[toolName];\n};\n\nexport type GetToolGroupKey = (\n toolName: string,\n options?: ToolGroupKeyOptions\n) => string | undefined;\n"],"names":[],"mappings":";;AAWA,MAAM,0BAAkD;AAAA;AAAA,EAEtD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AAAA;AAAA,EAGZ,qBAAqB;AAAA,EACrB,+BAA+B;AAAA,EAC/B,oCAAoC;AAAA,EACpC,qCAAqC;AAAA,EACrC,oCAAoC;AAAA,EACpC,2BAA2B;AAAA,EAC3B,gBAAgB;AAAA;AAAA,EAGhB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,uBAAuB;AAAA,EACvB,0BAA0B;AAAA;AAAA,EAG1B,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,yBAAyB;AAAA,EACzB,cAAc;AAAA,EACd,cAAc;AAAA,EACd,cAAc;AAAA,EACd,cAAc;AAAA;AAAA,EAEd,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,cAAc;AAAA;AAAA,EAGd,wBAAwB;AAAA,EACxB,iCAAiC;AAAA,EACjC,2BAA2B;AAAA,EAC3B,0BAA0B;AAAA,EAC1B,2BAA2B;AAAA;AAAA,EAE3B,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,UAAU;AAAA;AAAA,EAGV,qBAAqB;AAAA,EACrB,mBAAmB;AAAA;AAAA,EAGnB,iBAAiB;AAAA,EACjB,YAAY;AAAA;AAAA,EAGZ,SAAS;AAAA,EACT,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,2BAA2B;AAAA;AAAA,EAG3B,cAAc;AAAA,EACd,sBAAsB;AAAA;AAAA,EAGtB,gBAAgB;AAClB;AAMA,MAAM,kBAAqC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQA,MAAM,qBAAwC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOA,MAAM,yBAA4C,CAAC,YAAY,YAAY,iBAAiB;AAsBrF,MAAM,yBAAyB,CACpC,UACA,YACuB;AACvB,MAAI,gBAAgB,SAAS,QAAQ,EAAG,QAAO;AAC/C,MAAI,mBAAmB,SAAS,QAAQ,GAAG;AACzC,UAAM,YAAY,mCAAS;AAC3B,WAAO,aAAa,uBAAuB,SAAS,SAAS,IAAI,YAAY;AAAA,EAC/E;AACA,SAAO,wBAAwB,QAAQ;AACzC;;"}
1
+ {"version":3,"file":"toolkit-map.cjs","sources":["../../../src/chat/super-grouping/toolkit-map.ts"],"sourcesContent":["/**\n * Static map of tool names → toolkit group display key, mirroring Olympus's\n * runtime `toolDefinitionsStore` output. The SDK doesn't ship a backend-fetched\n * toolkit catalog, so this provides the same grouping behavior using the names\n * the agent typically calls. Consumers can override via the `getToolGroupKey`\n * prop on `<AthenaChat>`.\n *\n * Keys here are toolkit *display* names (what users see in the toolkit\n * selector), not toolkit IDs — they match Olympus's\n * `getToolkitToGroupKeyMap()` output.\n */\nconst DEFAULT_TOOL_TO_TOOLKIT: Record<string, string> = {\n // Web\n search: 'Web',\n browse: 'Web',\n web_search: 'Web',\n search_web: 'Web',\n web_scrape: 'Web',\n scrape_web: 'Web',\n\n // Document\n create_new_document: 'Document',\n create_document_from_markdown: 'Document',\n append_markdown_to_athena_document: 'Document',\n replace_markdown_in_athena_document: 'Document',\n delete_blocks_from_athena_document: 'Document',\n convert_athena_doc_to_pdf: 'Document',\n convert_to_pdf: 'Document',\n\n // Word document (Studio)\n CreateDocument: 'Document (Word)',\n CreateParagraph: 'Document (Word)',\n OpenDocument: 'Document (Word)',\n execute_word_commands: 'Document (Word)',\n create_new_word_document: 'Document (Word)',\n\n // Spreadsheet\n create_new_sheet: 'Spreadsheet',\n update_sheet_range: 'Spreadsheet',\n format_sheet_range: 'Spreadsheet',\n bulk_format_sheet_range: 'Spreadsheet',\n create_table: 'Spreadsheet',\n update_table: 'Spreadsheet',\n update_chart: 'Spreadsheet',\n // Studio sheet PTC\n CreateWorkbook: 'Spreadsheet',\n AddSheet: 'Spreadsheet',\n OpenWorkbook: 'Spreadsheet',\n\n // Visualizations\n create_chart: 'Visualizations (Charts, Dashboards, Figures)',\n create_new_figure: 'Visualizations (Charts, Dashboards, Figures)',\n\n // Presentation\n create_powerpoint_deck: 'Presentation',\n create_presentation_pptx_studio: 'Presentation',\n execute_presentation_code: 'Presentation',\n capture_slide_screenshot: 'Presentation',\n capture_slide_screenshots: 'Presentation',\n // Studio presentation PTC\n CreatePresentation: 'Presentation',\n OpenPresentation: 'Presentation',\n AddSlide: 'Presentation',\n\n // Notebook\n create_new_notebook: 'Notebook',\n run_notebook_cell: 'Notebook',\n\n // Python / code execution\n run_python_code: 'Python',\n run_python: 'Python',\n\n // Database\n run_sql: 'Database',\n run_database_sql: 'Database',\n run_sql_query_tool: 'Database',\n execute_sql: 'Database',\n describe_database: 'Database',\n list_database_tables: 'Database',\n get_database_table_schema: 'Database',\n\n // Email / calendar\n search_email: 'Email',\n unified_email_search: 'Email',\n\n // Media\n capture_moment: 'Computer',\n};\n\n/**\n * Tools that should never participate in grouping — even when surrounded by\n * tools of the same toolkit. Mirrors Olympus's `UNGROUPED_TOOLS`.\n */\nconst UNGROUPED_TOOLS: readonly string[] = [\n 'read_asset',\n 'read_full_asset',\n 'ask',\n 'open_asset_in_workspace',\n 'create_email_draft',\n 'unified_email_create_draft',\n 'unified_email_send',\n 'unified_email_edit_draft',\n];\n\n/**\n * Generic sandbox runtime tools shared across many toolkits (notebook,\n * computer, session sandbox, …). Mirrors Olympus's `CONTEXT_ONLY_TOOLS`:\n * they never start a toolkit group on their own — they only inherit the\n * surrounding group.\n */\nconst CONTEXT_ONLY_TOOLS: readonly string[] = [\n 'execute',\n 'ls',\n 'read_file',\n 'write_file',\n 'edit_file',\n 'glob',\n 'grep',\n];\n\n/**\n * Group display keys for toolkits that target a sandbox and therefore contain\n * the shared runtime tools. Context-only tools may only inherit these groups —\n * an open Web or Email group must not absorb a sandbox call.\n */\nconst SANDBOX_TOOLKIT_GROUPS: readonly string[] = ['Notebook', 'Computer', 'Session Sandbox'];\n\nexport type ToolGroupKeyOptions = {\n /** Display name of the surrounding group, when one is already open. */\n preferredGroupKey?: string;\n /**\n * Distinct tool names the message called. Hosts with a toolkit catalog use\n * it to attribute a tool shared by several toolkits to the one the message\n * leans on; the default map ignores it.\n */\n calledToolNames?: ReadonlySet<string>;\n};\n\n/**\n * Default `getToolGroupKey` implementation used by the SDK's tool grouping.\n * Returns the toolkit display key for a tool name, or `undefined` if the tool\n * is ungrouped or unknown. Context-only tools inherit the surrounding group\n * and are otherwise ungrouped.\n *\n * Override per-app by passing `getToolGroupKey` (or a whole `groupingFunction`) to\n * `SuperGroupingCard`.\n */\nexport const defaultGetToolGroupKey = (\n toolName: string,\n options?: ToolGroupKeyOptions\n): string | undefined => {\n if (UNGROUPED_TOOLS.includes(toolName)) return undefined;\n if (CONTEXT_ONLY_TOOLS.includes(toolName)) {\n const preferred = options?.preferredGroupKey;\n return preferred && SANDBOX_TOOLKIT_GROUPS.includes(preferred) ? preferred : undefined;\n }\n return DEFAULT_TOOL_TO_TOOLKIT[toolName];\n};\n\nexport type GetToolGroupKey = (\n toolName: string,\n options?: ToolGroupKeyOptions\n) => string | undefined;\n"],"names":[],"mappings":";;AAWA,MAAM,0BAAkD;AAAA;AAAA,EAEtD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AAAA;AAAA,EAGZ,qBAAqB;AAAA,EACrB,+BAA+B;AAAA,EAC/B,oCAAoC;AAAA,EACpC,qCAAqC;AAAA,EACrC,oCAAoC;AAAA,EACpC,2BAA2B;AAAA,EAC3B,gBAAgB;AAAA;AAAA,EAGhB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,uBAAuB;AAAA,EACvB,0BAA0B;AAAA;AAAA,EAG1B,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,yBAAyB;AAAA,EACzB,cAAc;AAAA,EACd,cAAc;AAAA,EACd,cAAc;AAAA;AAAA,EAEd,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,cAAc;AAAA;AAAA,EAGd,cAAc;AAAA,EACd,mBAAmB;AAAA;AAAA,EAGnB,wBAAwB;AAAA,EACxB,iCAAiC;AAAA,EACjC,2BAA2B;AAAA,EAC3B,0BAA0B;AAAA,EAC1B,2BAA2B;AAAA;AAAA,EAE3B,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,UAAU;AAAA;AAAA,EAGV,qBAAqB;AAAA,EACrB,mBAAmB;AAAA;AAAA,EAGnB,iBAAiB;AAAA,EACjB,YAAY;AAAA;AAAA,EAGZ,SAAS;AAAA,EACT,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,2BAA2B;AAAA;AAAA,EAG3B,cAAc;AAAA,EACd,sBAAsB;AAAA;AAAA,EAGtB,gBAAgB;AAClB;AAMA,MAAM,kBAAqC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQA,MAAM,qBAAwC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOA,MAAM,yBAA4C,CAAC,YAAY,YAAY,iBAAiB;AAsBrF,MAAM,yBAAyB,CACpC,UACA,YACuB;AACvB,MAAI,gBAAgB,SAAS,QAAQ,EAAG,QAAO;AAC/C,MAAI,mBAAmB,SAAS,QAAQ,GAAG;AACzC,UAAM,YAAY,mCAAS;AAC3B,WAAO,aAAa,uBAAuB,SAAS,SAAS,IAAI,YAAY;AAAA,EAC/E;AACA,SAAO,wBAAwB,QAAQ;AACzC;;"}
@@ -27,12 +27,14 @@ const DEFAULT_TOOL_TO_TOOLKIT = {
27
27
  bulk_format_sheet_range: "Spreadsheet",
28
28
  create_table: "Spreadsheet",
29
29
  update_table: "Spreadsheet",
30
- create_chart: "Spreadsheet",
31
30
  update_chart: "Spreadsheet",
32
31
  // Studio sheet PTC
33
32
  CreateWorkbook: "Spreadsheet",
34
33
  AddSheet: "Spreadsheet",
35
34
  OpenWorkbook: "Spreadsheet",
35
+ // Visualizations
36
+ create_chart: "Visualizations (Charts, Dashboards, Figures)",
37
+ create_new_figure: "Visualizations (Charts, Dashboards, Figures)",
36
38
  // Presentation
37
39
  create_powerpoint_deck: "Presentation",
38
40
  create_presentation_pptx_studio: "Presentation",
@@ -1 +1 @@
1
- {"version":3,"file":"toolkit-map.js","sources":["../../../src/chat/super-grouping/toolkit-map.ts"],"sourcesContent":["/**\n * Static map of tool names → toolkit group display key, mirroring Olympus's\n * runtime `toolDefinitionsStore` output. The SDK doesn't ship a backend-fetched\n * toolkit catalog, so this provides the same grouping behavior using the names\n * the agent typically calls. Consumers can override via the `getToolGroupKey`\n * prop on `<AthenaChat>`.\n *\n * Keys here are toolkit *display* names (what users see in the toolkit\n * selector), not toolkit IDs — they match Olympus's\n * `getToolkitToGroupKeyMap()` output.\n */\nconst DEFAULT_TOOL_TO_TOOLKIT: Record<string, string> = {\n // Web\n search: 'Web',\n browse: 'Web',\n web_search: 'Web',\n search_web: 'Web',\n web_scrape: 'Web',\n scrape_web: 'Web',\n\n // Document\n create_new_document: 'Document',\n create_document_from_markdown: 'Document',\n append_markdown_to_athena_document: 'Document',\n replace_markdown_in_athena_document: 'Document',\n delete_blocks_from_athena_document: 'Document',\n convert_athena_doc_to_pdf: 'Document',\n convert_to_pdf: 'Document',\n\n // Word document (Studio)\n CreateDocument: 'Document (Word)',\n CreateParagraph: 'Document (Word)',\n OpenDocument: 'Document (Word)',\n execute_word_commands: 'Document (Word)',\n create_new_word_document: 'Document (Word)',\n\n // Spreadsheet\n create_new_sheet: 'Spreadsheet',\n update_sheet_range: 'Spreadsheet',\n format_sheet_range: 'Spreadsheet',\n bulk_format_sheet_range: 'Spreadsheet',\n create_table: 'Spreadsheet',\n update_table: 'Spreadsheet',\n create_chart: 'Spreadsheet',\n update_chart: 'Spreadsheet',\n // Studio sheet PTC\n CreateWorkbook: 'Spreadsheet',\n AddSheet: 'Spreadsheet',\n OpenWorkbook: 'Spreadsheet',\n\n // Presentation\n create_powerpoint_deck: 'Presentation',\n create_presentation_pptx_studio: 'Presentation',\n execute_presentation_code: 'Presentation',\n capture_slide_screenshot: 'Presentation',\n capture_slide_screenshots: 'Presentation',\n // Studio presentation PTC\n CreatePresentation: 'Presentation',\n OpenPresentation: 'Presentation',\n AddSlide: 'Presentation',\n\n // Notebook\n create_new_notebook: 'Notebook',\n run_notebook_cell: 'Notebook',\n\n // Python / code execution\n run_python_code: 'Python',\n run_python: 'Python',\n\n // Database\n run_sql: 'Database',\n run_database_sql: 'Database',\n run_sql_query_tool: 'Database',\n execute_sql: 'Database',\n describe_database: 'Database',\n list_database_tables: 'Database',\n get_database_table_schema: 'Database',\n\n // Email / calendar\n search_email: 'Email',\n unified_email_search: 'Email',\n\n // Media\n capture_moment: 'Computer',\n};\n\n/**\n * Tools that should never participate in grouping — even when surrounded by\n * tools of the same toolkit. Mirrors Olympus's `UNGROUPED_TOOLS`.\n */\nconst UNGROUPED_TOOLS: readonly string[] = [\n 'read_asset',\n 'read_full_asset',\n 'ask',\n 'open_asset_in_workspace',\n 'create_email_draft',\n 'unified_email_create_draft',\n 'unified_email_send',\n 'unified_email_edit_draft',\n];\n\n/**\n * Generic sandbox runtime tools shared across many toolkits (notebook,\n * computer, session sandbox, …). Mirrors Olympus's `CONTEXT_ONLY_TOOLS`:\n * they never start a toolkit group on their own — they only inherit the\n * surrounding group.\n */\nconst CONTEXT_ONLY_TOOLS: readonly string[] = [\n 'execute',\n 'ls',\n 'read_file',\n 'write_file',\n 'edit_file',\n 'glob',\n 'grep',\n];\n\n/**\n * Group display keys for toolkits that target a sandbox and therefore contain\n * the shared runtime tools. Context-only tools may only inherit these groups —\n * an open Web or Email group must not absorb a sandbox call.\n */\nconst SANDBOX_TOOLKIT_GROUPS: readonly string[] = ['Notebook', 'Computer', 'Session Sandbox'];\n\nexport type ToolGroupKeyOptions = {\n /** Display name of the surrounding group, when one is already open. */\n preferredGroupKey?: string;\n /**\n * Distinct tool names the message called. Hosts with a toolkit catalog use\n * it to attribute a tool shared by several toolkits to the one the message\n * leans on; the default map ignores it.\n */\n calledToolNames?: ReadonlySet<string>;\n};\n\n/**\n * Default `getToolGroupKey` implementation used by the SDK's tool grouping.\n * Returns the toolkit display key for a tool name, or `undefined` if the tool\n * is ungrouped or unknown. Context-only tools inherit the surrounding group\n * and are otherwise ungrouped.\n *\n * Override per-app by passing `getToolGroupKey` (or a whole `groupingFunction`) to\n * `SuperGroupingCard`.\n */\nexport const defaultGetToolGroupKey = (\n toolName: string,\n options?: ToolGroupKeyOptions\n): string | undefined => {\n if (UNGROUPED_TOOLS.includes(toolName)) return undefined;\n if (CONTEXT_ONLY_TOOLS.includes(toolName)) {\n const preferred = options?.preferredGroupKey;\n return preferred && SANDBOX_TOOLKIT_GROUPS.includes(preferred) ? preferred : undefined;\n }\n return DEFAULT_TOOL_TO_TOOLKIT[toolName];\n};\n\nexport type GetToolGroupKey = (\n toolName: string,\n options?: ToolGroupKeyOptions\n) => string | undefined;\n"],"names":[],"mappings":"AAWA,MAAM,0BAAkD;AAAA;AAAA,EAEtD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AAAA;AAAA,EAGZ,qBAAqB;AAAA,EACrB,+BAA+B;AAAA,EAC/B,oCAAoC;AAAA,EACpC,qCAAqC;AAAA,EACrC,oCAAoC;AAAA,EACpC,2BAA2B;AAAA,EAC3B,gBAAgB;AAAA;AAAA,EAGhB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,uBAAuB;AAAA,EACvB,0BAA0B;AAAA;AAAA,EAG1B,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,yBAAyB;AAAA,EACzB,cAAc;AAAA,EACd,cAAc;AAAA,EACd,cAAc;AAAA,EACd,cAAc;AAAA;AAAA,EAEd,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,cAAc;AAAA;AAAA,EAGd,wBAAwB;AAAA,EACxB,iCAAiC;AAAA,EACjC,2BAA2B;AAAA,EAC3B,0BAA0B;AAAA,EAC1B,2BAA2B;AAAA;AAAA,EAE3B,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,UAAU;AAAA;AAAA,EAGV,qBAAqB;AAAA,EACrB,mBAAmB;AAAA;AAAA,EAGnB,iBAAiB;AAAA,EACjB,YAAY;AAAA;AAAA,EAGZ,SAAS;AAAA,EACT,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,2BAA2B;AAAA;AAAA,EAG3B,cAAc;AAAA,EACd,sBAAsB;AAAA;AAAA,EAGtB,gBAAgB;AAClB;AAMA,MAAM,kBAAqC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQA,MAAM,qBAAwC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOA,MAAM,yBAA4C,CAAC,YAAY,YAAY,iBAAiB;AAsBrF,MAAM,yBAAyB,CACpC,UACA,YACuB;AACvB,MAAI,gBAAgB,SAAS,QAAQ,EAAG,QAAO;AAC/C,MAAI,mBAAmB,SAAS,QAAQ,GAAG;AACzC,UAAM,YAAY,mCAAS;AAC3B,WAAO,aAAa,uBAAuB,SAAS,SAAS,IAAI,YAAY;AAAA,EAC/E;AACA,SAAO,wBAAwB,QAAQ;AACzC;"}
1
+ {"version":3,"file":"toolkit-map.js","sources":["../../../src/chat/super-grouping/toolkit-map.ts"],"sourcesContent":["/**\n * Static map of tool names → toolkit group display key, mirroring Olympus's\n * runtime `toolDefinitionsStore` output. The SDK doesn't ship a backend-fetched\n * toolkit catalog, so this provides the same grouping behavior using the names\n * the agent typically calls. Consumers can override via the `getToolGroupKey`\n * prop on `<AthenaChat>`.\n *\n * Keys here are toolkit *display* names (what users see in the toolkit\n * selector), not toolkit IDs — they match Olympus's\n * `getToolkitToGroupKeyMap()` output.\n */\nconst DEFAULT_TOOL_TO_TOOLKIT: Record<string, string> = {\n // Web\n search: 'Web',\n browse: 'Web',\n web_search: 'Web',\n search_web: 'Web',\n web_scrape: 'Web',\n scrape_web: 'Web',\n\n // Document\n create_new_document: 'Document',\n create_document_from_markdown: 'Document',\n append_markdown_to_athena_document: 'Document',\n replace_markdown_in_athena_document: 'Document',\n delete_blocks_from_athena_document: 'Document',\n convert_athena_doc_to_pdf: 'Document',\n convert_to_pdf: 'Document',\n\n // Word document (Studio)\n CreateDocument: 'Document (Word)',\n CreateParagraph: 'Document (Word)',\n OpenDocument: 'Document (Word)',\n execute_word_commands: 'Document (Word)',\n create_new_word_document: 'Document (Word)',\n\n // Spreadsheet\n create_new_sheet: 'Spreadsheet',\n update_sheet_range: 'Spreadsheet',\n format_sheet_range: 'Spreadsheet',\n bulk_format_sheet_range: 'Spreadsheet',\n create_table: 'Spreadsheet',\n update_table: 'Spreadsheet',\n update_chart: 'Spreadsheet',\n // Studio sheet PTC\n CreateWorkbook: 'Spreadsheet',\n AddSheet: 'Spreadsheet',\n OpenWorkbook: 'Spreadsheet',\n\n // Visualizations\n create_chart: 'Visualizations (Charts, Dashboards, Figures)',\n create_new_figure: 'Visualizations (Charts, Dashboards, Figures)',\n\n // Presentation\n create_powerpoint_deck: 'Presentation',\n create_presentation_pptx_studio: 'Presentation',\n execute_presentation_code: 'Presentation',\n capture_slide_screenshot: 'Presentation',\n capture_slide_screenshots: 'Presentation',\n // Studio presentation PTC\n CreatePresentation: 'Presentation',\n OpenPresentation: 'Presentation',\n AddSlide: 'Presentation',\n\n // Notebook\n create_new_notebook: 'Notebook',\n run_notebook_cell: 'Notebook',\n\n // Python / code execution\n run_python_code: 'Python',\n run_python: 'Python',\n\n // Database\n run_sql: 'Database',\n run_database_sql: 'Database',\n run_sql_query_tool: 'Database',\n execute_sql: 'Database',\n describe_database: 'Database',\n list_database_tables: 'Database',\n get_database_table_schema: 'Database',\n\n // Email / calendar\n search_email: 'Email',\n unified_email_search: 'Email',\n\n // Media\n capture_moment: 'Computer',\n};\n\n/**\n * Tools that should never participate in grouping — even when surrounded by\n * tools of the same toolkit. Mirrors Olympus's `UNGROUPED_TOOLS`.\n */\nconst UNGROUPED_TOOLS: readonly string[] = [\n 'read_asset',\n 'read_full_asset',\n 'ask',\n 'open_asset_in_workspace',\n 'create_email_draft',\n 'unified_email_create_draft',\n 'unified_email_send',\n 'unified_email_edit_draft',\n];\n\n/**\n * Generic sandbox runtime tools shared across many toolkits (notebook,\n * computer, session sandbox, …). Mirrors Olympus's `CONTEXT_ONLY_TOOLS`:\n * they never start a toolkit group on their own — they only inherit the\n * surrounding group.\n */\nconst CONTEXT_ONLY_TOOLS: readonly string[] = [\n 'execute',\n 'ls',\n 'read_file',\n 'write_file',\n 'edit_file',\n 'glob',\n 'grep',\n];\n\n/**\n * Group display keys for toolkits that target a sandbox and therefore contain\n * the shared runtime tools. Context-only tools may only inherit these groups —\n * an open Web or Email group must not absorb a sandbox call.\n */\nconst SANDBOX_TOOLKIT_GROUPS: readonly string[] = ['Notebook', 'Computer', 'Session Sandbox'];\n\nexport type ToolGroupKeyOptions = {\n /** Display name of the surrounding group, when one is already open. */\n preferredGroupKey?: string;\n /**\n * Distinct tool names the message called. Hosts with a toolkit catalog use\n * it to attribute a tool shared by several toolkits to the one the message\n * leans on; the default map ignores it.\n */\n calledToolNames?: ReadonlySet<string>;\n};\n\n/**\n * Default `getToolGroupKey` implementation used by the SDK's tool grouping.\n * Returns the toolkit display key for a tool name, or `undefined` if the tool\n * is ungrouped or unknown. Context-only tools inherit the surrounding group\n * and are otherwise ungrouped.\n *\n * Override per-app by passing `getToolGroupKey` (or a whole `groupingFunction`) to\n * `SuperGroupingCard`.\n */\nexport const defaultGetToolGroupKey = (\n toolName: string,\n options?: ToolGroupKeyOptions\n): string | undefined => {\n if (UNGROUPED_TOOLS.includes(toolName)) return undefined;\n if (CONTEXT_ONLY_TOOLS.includes(toolName)) {\n const preferred = options?.preferredGroupKey;\n return preferred && SANDBOX_TOOLKIT_GROUPS.includes(preferred) ? preferred : undefined;\n }\n return DEFAULT_TOOL_TO_TOOLKIT[toolName];\n};\n\nexport type GetToolGroupKey = (\n toolName: string,\n options?: ToolGroupKeyOptions\n) => string | undefined;\n"],"names":[],"mappings":"AAWA,MAAM,0BAAkD;AAAA;AAAA,EAEtD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AAAA;AAAA,EAGZ,qBAAqB;AAAA,EACrB,+BAA+B;AAAA,EAC/B,oCAAoC;AAAA,EACpC,qCAAqC;AAAA,EACrC,oCAAoC;AAAA,EACpC,2BAA2B;AAAA,EAC3B,gBAAgB;AAAA;AAAA,EAGhB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,uBAAuB;AAAA,EACvB,0BAA0B;AAAA;AAAA,EAG1B,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,yBAAyB;AAAA,EACzB,cAAc;AAAA,EACd,cAAc;AAAA,EACd,cAAc;AAAA;AAAA,EAEd,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,cAAc;AAAA;AAAA,EAGd,cAAc;AAAA,EACd,mBAAmB;AAAA;AAAA,EAGnB,wBAAwB;AAAA,EACxB,iCAAiC;AAAA,EACjC,2BAA2B;AAAA,EAC3B,0BAA0B;AAAA,EAC1B,2BAA2B;AAAA;AAAA,EAE3B,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,UAAU;AAAA;AAAA,EAGV,qBAAqB;AAAA,EACrB,mBAAmB;AAAA;AAAA,EAGnB,iBAAiB;AAAA,EACjB,YAAY;AAAA;AAAA,EAGZ,SAAS;AAAA,EACT,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,2BAA2B;AAAA;AAAA,EAG3B,cAAc;AAAA,EACd,sBAAsB;AAAA;AAAA,EAGtB,gBAAgB;AAClB;AAMA,MAAM,kBAAqC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQA,MAAM,qBAAwC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOA,MAAM,yBAA4C,CAAC,YAAY,YAAY,iBAAiB;AAsBrF,MAAM,yBAAyB,CACpC,UACA,YACuB;AACvB,MAAI,gBAAgB,SAAS,QAAQ,EAAG,QAAO;AAC/C,MAAI,mBAAmB,SAAS,QAAQ,GAAG;AACzC,UAAM,YAAY,mCAAS;AAC3B,WAAO,aAAa,uBAAuB,SAAS,SAAS,IAAI,YAAY;AAAA,EAC/E;AACA,SAAO,wBAAwB,QAAQ;AACzC;"}
@@ -77,6 +77,7 @@ exports.MentionSuggestionList = mentionSuggestionList.MentionSuggestionList;
77
77
  exports.MentionSuggestionPopup = mentionSuggestionPopup.MentionSuggestionPopup;
78
78
  exports.MentionIcon = mentionIcon.MentionIcon;
79
79
  exports.MenuList = menuList.MenuList;
80
+ exports.AthenaGraphQLError = apiClient.AthenaGraphQLError;
80
81
  exports.MentionAuthCtx = apiClient.MentionAuthCtx;
81
82
  exports.SIMPLE_SEARCH_QUERY = apiClient.SIMPLE_SEARCH_QUERY;
82
83
  exports.fetchGraphQL = apiClient.fetchGraphQL;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -29,7 +29,7 @@ export { MentionSuggestionList } from "./mentions/suggestions/components/mention
29
29
  export { MentionSuggestionPopup } from "./mentions/suggestions/components/mention-suggestion-popup";
30
30
  export { MentionIcon } from "./mentions/suggestions/components/mention-icon";
31
31
  export { MenuList } from "./mentions/suggestions/components/menu-list";
32
- export { MentionAuthCtx, fetchGraphQL, SIMPLE_SEARCH_QUERY, useMentionAuth, type MentionAuthContext, } from "./mentions/suggestions/data/api-client";
32
+ export { AthenaGraphQLError, MentionAuthCtx, fetchGraphQL, SIMPLE_SEARCH_QUERY, useMentionAuth, type MentionAuthContext, } from "./mentions/suggestions/data/api-client";
33
33
  export { ROOT_MENTION_CATEGORIES, useMentionSuggestions, webpageMentionFingerprint, type MentionRootCategory, type MentionSuggestionsStore, } from "./mentions/suggestions/data/use-mention-suggestions";
34
34
  export { buildRootMenuItems } from "./mentions/suggestions/data/sources";
35
35
  export { assetTypeToIcon, assetTypeToThumb, configureAssetIconBasePath, } from "./mentions/suggestions/data/sources/asset-type-icons";
@@ -17,7 +17,7 @@ import { MentionSuggestionList } from "./mentions/suggestions/components/mention
17
17
  import { MentionSuggestionPopup } from "./mentions/suggestions/components/mention-suggestion-popup.js";
18
18
  import { MentionIcon } from "./mentions/suggestions/components/mention-icon.js";
19
19
  import { MenuList } from "./mentions/suggestions/components/menu-list.js";
20
- import { MentionAuthCtx, SIMPLE_SEARCH_QUERY, fetchGraphQL, useMentionAuth } from "./mentions/suggestions/data/api-client.js";
20
+ import { AthenaGraphQLError, MentionAuthCtx, SIMPLE_SEARCH_QUERY, fetchGraphQL, useMentionAuth } from "./mentions/suggestions/data/api-client.js";
21
21
  import { ROOT_MENTION_CATEGORIES, useMentionSuggestions, webpageMentionFingerprint } from "./mentions/suggestions/data/use-mention-suggestions.js";
22
22
  import { buildRootMenuItems } from "./mentions/suggestions/data/sources/index.js";
23
23
  import { assetTypeToIcon, assetTypeToThumb, configureAssetIconBasePath } from "./mentions/suggestions/data/sources/asset-type-icons.js";
@@ -40,6 +40,7 @@ import { StatewireQueuedMessages } from "../chat/StatewireQueuedMessages.js";
40
40
  import { WaitingOnYouBanner, WaitingOnYouBannerView } from "../chat/WaitingOnYouBanner.js";
41
41
  import { HITL_PENDING_RESUME_GRACE_MS } from "../agent-runtime/src/interrupts.js";
42
42
  export {
43
+ AthenaGraphQLError,
43
44
  BranchPicker,
44
45
  COMPOSER_DOCK_CLASS,
45
46
  COMPOSER_EDITOR_ROW_CLASS,