@athenaintel/react 0.54.0 → 0.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/agent-runtime/src/answer-label.cjs +8 -2
- package/dist/agent-runtime/src/answer-label.cjs.map +1 -1
- package/dist/agent-runtime/src/answer-label.d.ts +10 -4
- package/dist/agent-runtime/src/answer-label.js +8 -2
- package/dist/agent-runtime/src/answer-label.js.map +1 -1
- package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs +6 -3
- package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
- package/dist/agent-runtime/src/deep-agent-transport-recipe.js +6 -3
- package/dist/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
- package/dist/agent-runtime/src/edit-command.cjs +42 -15
- package/dist/agent-runtime/src/edit-command.cjs.map +1 -1
- package/dist/agent-runtime/src/edit-command.d.ts +2 -0
- package/dist/agent-runtime/src/edit-command.js +43 -16
- package/dist/agent-runtime/src/edit-command.js.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs +12 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +21 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.js +12 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
- package/dist/agent-runtime/src/history-store.cjs +426 -0
- package/dist/agent-runtime/src/history-store.cjs.map +1 -0
- package/dist/agent-runtime/src/history-store.d.ts +282 -0
- package/dist/agent-runtime/src/history-store.js +426 -0
- package/dist/agent-runtime/src/history-store.js.map +1 -0
- package/dist/agent-runtime/src/index.d.ts +3 -2
- package/dist/agent-runtime/src/message-window.cjs +43 -5
- package/dist/agent-runtime/src/message-window.cjs.map +1 -1
- package/dist/agent-runtime/src/message-window.d.ts +26 -2
- package/dist/agent-runtime/src/message-window.js +44 -6
- package/dist/agent-runtime/src/message-window.js.map +1 -1
- package/dist/agent-runtime/src/offline-status.cjs.map +1 -1
- package/dist/agent-runtime/src/offline-status.d.ts +115 -5
- package/dist/agent-runtime/src/offline-status.js.map +1 -1
- package/dist/agent-runtime/src/runtime.d.ts +1 -0
- package/dist/agent-runtime/src/tool-metadata.cjs +8 -0
- package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.js +8 -0
- package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs +7 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.js +8 -2
- package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs +73 -14
- package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-window-sync.d.ts +2 -2
- package/dist/agent-runtime/src/use-deep-agent-window-sync.js +75 -16
- package/dist/agent-runtime/src/use-deep-agent-window-sync.js.map +1 -1
- package/dist/chat/super-grouping/CollapsibleGroup.cjs +1 -1
- package/dist/chat/super-grouping/CollapsibleGroup.cjs.map +1 -1
- package/dist/chat/super-grouping/CollapsibleGroup.d.ts +6 -5
- package/dist/chat/super-grouping/CollapsibleGroup.js +1 -1
- package/dist/chat/super-grouping/CollapsibleGroup.js.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.cjs +51 -43
- package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.js +51 -43
- package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs +9 -4
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.js +9 -4
- package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.cjs +7 -4
- package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.d.ts +10 -1
- package/dist/chat/super-grouping/activity-timeline.js +7 -4
- package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
- package/dist/chat/super-grouping/earlier-steps-button.cjs +49 -0
- package/dist/chat/super-grouping/earlier-steps-button.cjs.map +1 -0
- package/dist/chat/super-grouping/earlier-steps-button.d.ts +11 -0
- package/dist/chat/super-grouping/earlier-steps-button.js +49 -0
- package/dist/chat/super-grouping/earlier-steps-button.js.map +1 -0
- package/dist/chat/super-grouping/toolkit-map.cjs +1 -0
- package/dist/chat/super-grouping/toolkit-map.cjs.map +1 -1
- package/dist/chat/super-grouping/toolkit-map.js +1 -0
- package/dist/chat/super-grouping/toolkit-map.js.map +1 -1
- package/dist/chat/super-grouping/use-turn-steps.cjs +28 -0
- package/dist/chat/super-grouping/use-turn-steps.cjs.map +1 -0
- package/dist/chat/super-grouping/use-turn-steps.d.ts +23 -0
- package/dist/chat/super-grouping/use-turn-steps.js +28 -0
- package/dist/chat/super-grouping/use-turn-steps.js.map +1 -0
- package/dist/chat-ui/statewire.cjs +6 -0
- package/dist/chat-ui/statewire.cjs.map +1 -1
- package/dist/chat-ui/statewire.d.ts +3 -1
- package/dist/chat-ui/statewire.js +7 -1
- package/dist/chat-ui/statewire.js.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.d.ts +8 -0
- package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
- package/dist/collab/client.cjs +40 -1
- package/dist/collab/client.cjs.map +1 -1
- package/dist/collab/client.d.ts +17 -0
- package/dist/collab/client.js +40 -1
- package/dist/collab/client.js.map +1 -1
- package/dist/composer/QuoteContext.cjs +3 -3
- package/dist/composer/QuoteContext.cjs.map +1 -1
- package/dist/composer/QuoteContext.js +3 -3
- package/dist/composer/QuoteContext.js.map +1 -1
- package/dist/provider/AthenaProvider.cjs +13 -4
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.js +11 -2
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/provider/statewire-window-context.cjs +6 -0
- package/dist/provider/statewire-window-context.cjs.map +1 -1
- package/dist/provider/statewire-window-context.d.ts +9 -0
- package/dist/provider/statewire-window-context.js +6 -0
- package/dist/provider/statewire-window-context.js.map +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.d.ts +6 -0
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/threads/sessions-query.cjs +2 -0
- package/dist/threads/sessions-query.cjs.map +1 -1
- package/dist/threads/sessions-query.js +2 -0
- package/dist/threads/sessions-query.js.map +1 -1
- package/package.json +1 -1
|
@@ -152,19 +152,22 @@ function summarizeActivityTool(item, resolveToolDisplayName, assetTitles) {
|
|
|
152
152
|
...resolveToolDisplayName ? { displayName: resolveToolDisplayName(item.toolName) } : {}
|
|
153
153
|
});
|
|
154
154
|
}
|
|
155
|
-
function getActivitySummary(timeline, { earlierStepsUnloaded = false } = {}) {
|
|
155
|
+
function getActivitySummary(timeline, { earlierStepsUnloaded = false, hiddenSteps } = {}) {
|
|
156
156
|
const tools = timeline.filter((item) => item.kind === "tool");
|
|
157
157
|
const outcome = activityOutcome(tools);
|
|
158
|
-
const
|
|
158
|
+
const hiddenTools = (hiddenSteps == null ? void 0 : hiddenSteps.tools) ?? 0;
|
|
159
|
+
const hiddenDelegations = (hiddenSteps == null ? void 0 : hiddenSteps.delegations) ?? 0;
|
|
160
|
+
const delegations = countActivityDelegations(timeline) + hiddenDelegations;
|
|
159
161
|
const more = earlierStepsUnloaded ? "+" : "";
|
|
160
162
|
if (delegations > 0) {
|
|
161
163
|
const lead = `Delegated to ${delegations}${more} ${delegations === 1 && !more ? "agent" : "agents"}`;
|
|
162
|
-
const otherTools = tools.filter((item) => item.toolName !== toolNames.TASK_TOOL_NAME).length;
|
|
164
|
+
const otherTools = tools.filter((item) => item.toolName !== toolNames.TASK_TOOL_NAME).length + hiddenTools - hiddenDelegations;
|
|
163
165
|
const rest = outcome ? `${outcome.charAt(0).toLowerCase()}${outcome.slice(1)}` : otherTools > 0 ? `used ${otherTools}${more} ${otherTools === 1 && !more ? "tool" : "tools"}` : null;
|
|
164
166
|
return rest ? `${lead} · ${rest}` : lead;
|
|
165
167
|
}
|
|
166
168
|
if (outcome) return outcome;
|
|
167
|
-
|
|
169
|
+
const toolTotal = tools.length + hiddenTools;
|
|
170
|
+
if (toolTotal > 0) return `Used ${toolTotal}${more} ${toolTotal === 1 && !more ? "tool" : "tools"}`;
|
|
168
171
|
if (earlierStepsUnloaded) return "Earlier steps not loaded";
|
|
169
172
|
return "Reasoning complete";
|
|
170
173
|
}
|
|
@@ -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 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 countInEvalDispatches,\n EVAL_TOOL_NAME,\n isRunningToolPlaceholderArtifact,\n isSpokenTurnTextPart,\n readRejectedToolResult,\n TASK_TOOL_NAME,\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 * Subagents the call delegated to: for a `task` call one, or none when it\n * was refused, withdrawn or expired at its approval and never ran; for an\n * `eval` call its in-interpreter `task()` dispatches\n * (`countInEvalDispatches`), absent when it made none.\n */\n delegations?: number;\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 * Calls the run is parked on, by tool-call id, as the host reads them off\n * its pending approval: a gated call, or (in Olympus) a `task` call whose\n * subagent waits on an approval. Any of them still without its real result\n * reads as waiting.\n */\n waitingToolCallIds?: 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();\nconst NO_TOOL_CALLS: ReadonlySet<string> = new Set();\n\n/**\n * Whether a tool-call part still holds the backend's running-tool 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; its marker reaches the\n * part's artifact (`isRunningToolPlaceholderArtifact`). The real ToolMessage\n * that replaces it has no such marker, so a defined `result` alone does not\n * mean the tool is done.\n */\nexport function isStreamingToolPlaceholder(part: Pick<ToolCallPart, 'artifact'>): boolean {\n return isRunningToolPlaceholderArtifact(part.artifact);\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') {\n // The placeholder is the backend's word that the call is still in flight.\n // A turn reads `complete` whenever nothing streams (a run parked on an\n // approval inside a subagent, the gap before a drained run resumes), and\n // assistant-ui counts the placeholder as the call's result when it settles\n // that status, so the turn's status cannot finish the call.\n return isStreamingToolPlaceholder(part) ? { type: 'running' } : { type: 'complete' };\n }\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 {\n waitingTools = NO_TOOLS,\n waitingToolCallIds = NO_TOOL_CALLS,\n passThroughTools = NO_TOOLS,\n }: 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 waitingToolCallIds.has(part.toolCallId) ||\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 const state = getActivityToolState(part, messageStatus, options);\n const delegations = toolCallDelegations({ part, state });\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,\n ...(delegations !== null ? { delegations } : {}),\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/**\n * Subagents one tool call delegated to (see `ActivityItem.delegations`), or\n * `null` for a call that delegates by nature of neither: a `task` call one,\n * unless the person refused it or its approval was withdrawn or expired (it\n * never ran); an `eval` call its in-interpreter dispatches, when it made any.\n */\nfunction toolCallDelegations({\n part,\n state,\n}: {\n part: ToolCallPart;\n state: ActivityToolState;\n}): number | null {\n if (part.toolName === TASK_TOOL_NAME) {\n const withdrawn =\n part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired';\n return state === 'rejected' || withdrawn ? 0 : 1;\n }\n if (part.toolName === EVAL_TOOL_NAME) {\n const dispatches = countInEvalDispatches(part.artifact);\n return dispatches > 0 ? dispatches : null;\n }\n return null;\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 * Subagents the turn delegated to: its `task` calls that ran, plus the\n * `task()` dispatches its `eval` calls made from inside the interpreter. A\n * `task` step built without its count (a host's own timeline) counts unless it\n * reads refused or cancelled.\n */\nexport function countActivityDelegations(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => {\n if (item.kind !== 'tool') return count;\n if (item.delegations !== undefined) return count + item.delegations;\n const ranTask =\n item.toolName === TASK_TOOL_NAME && item.state !== 'rejected' && item.state !== 'cancelled';\n return ranTask ? count + 1 : count;\n }, 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. A\n * complete turn with a step still running is running: only a step holding the\n * backend's running placeholder reads so once nothing streams (a run parked on\n * an approval inside a subagent, the gap before a drained run resumes).\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 if (\n status?.type === 'complete' &&\n timeline.some((item) => item.kind === 'tool' && item.state === 'running')\n ) {\n return 'running';\n }\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/**\n * The collapsed-card summary of a finished turn. \"Completed with issues\" means\n * the turn ended on a problem: a call the person refused, or a failed call\n * that no later call completed after. A failed command the agent then got past\n * (a search that found nothing, a retry that worked) is ordinary work, so a\n * long turn that recovered from it reads as the tools it used.\n *\n * A turn that delegated work leads with it — \"Delegated to 10 agents · used 6\n * tools\" — counting its `task` calls and the `task()` dispatches its `eval`\n * calls made from inside the interpreter (`countActivityDelegations`). A\n * `task` call is the delegation itself, so the tools it is followed by are the\n * turn's other calls; an outcome above replaces them (\"Delegated to 3 agents ·\n * completed with issues\").\n */\nexport function getActivitySummary(\n timeline: readonly ActivityItem[],\n { earlierStepsUnloaded = false }: ActivitySummaryOptions = {},\n): string {\n const tools = timeline.filter((item): item is ToolActivityItem => item.kind === 'tool');\n const outcome = activityOutcome(tools);\n const delegations = countActivityDelegations(timeline);\n // A turn whose earlier steps have not loaded counts what has: a floor.\n const more = earlierStepsUnloaded ? '+' : '';\n if (delegations > 0) {\n const lead = `Delegated to ${delegations}${more} ${delegations === 1 && !more ? 'agent' : 'agents'}`;\n const otherTools = tools.filter((item) => item.toolName !== TASK_TOOL_NAME).length;\n const rest = outcome\n ? `${outcome.charAt(0).toLowerCase()}${outcome.slice(1)}`\n : otherTools > 0\n ? `used ${otherTools}${more} ${otherTools === 1 && !more ? 'tool' : 'tools'}`\n : null;\n return rest ? `${lead} · ${rest}` : lead;\n }\n if (outcome) return outcome;\n if (tools.length > 0) return `Used ${tools.length}${more} ${tools.length === 1 && !more ? 'tool' : 'tools'}`;\n if (earlierStepsUnloaded) return 'Earlier steps not loaded';\n return 'Reasoning complete';\n}\n\n/** How {@link getActivitySummary} reads a turn that may not be loaded whole. */\nexport interface ActivitySummaryOptions {\n /**\n * The turn's earlier steps have not loaded yet (older history above it, see\n * `useEarlierStepsUnloaded`): its counts read as floors, \"Used 43+ tools\".\n */\n earlierStepsUnloaded?: boolean;\n}\n\ntype ToolActivityItem = Extract<ActivityItem, { kind: 'tool' }>;\n\n/** How a finished turn's tool calls ended, when that is not simply the tools it used. */\nfunction activityOutcome(tools: readonly ToolActivityItem[]): string | null {\n const lastFailure = tools.findLastIndex((item) => item.state === 'error');\n const endedOnFailure =\n lastFailure >= 0 && !tools.slice(lastFailure + 1).some((item) => item.state === 'complete');\n if (endedOnFailure || tools.some((item) => item.state === 'rejected')) return 'Completed with issues';\n if (tools.some((item) => item.state === 'cancelled')) return 'Action cancelled';\n if (tools.some((item) => item.state === 'paused')) return 'Paused during tool use';\n return null;\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":["isRunningToolPlaceholderArtifact","readRejectedToolResult","classifyToolResult","TASK_TOOL_NAME","EVAL_TOOL_NAME","countInEvalDispatches","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 countInEvalDispatches,\n EVAL_TOOL_NAME,\n isRunningToolPlaceholderArtifact,\n isSpokenTurnTextPart,\n readRejectedToolResult,\n TASK_TOOL_NAME,\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 * Subagents the call delegated to: for a `task` call one, or none when it\n * was refused, withdrawn or expired at its approval and never ran; for an\n * `eval` call its in-interpreter `task()` dispatches\n * (`countInEvalDispatches`), absent when it made none.\n */\n delegations?: number;\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 * Calls the run is parked on, by tool-call id, as the host reads them off\n * its pending approval: a gated call, or (in Olympus) a `task` call whose\n * subagent waits on an approval. Any of them still without its real result\n * reads as waiting.\n */\n waitingToolCallIds?: 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();\nconst NO_TOOL_CALLS: ReadonlySet<string> = new Set();\n\n/**\n * Whether a tool-call part still holds the backend's running-tool 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; its marker reaches the\n * part's artifact (`isRunningToolPlaceholderArtifact`). The real ToolMessage\n * that replaces it has no such marker, so a defined `result` alone does not\n * mean the tool is done.\n */\nexport function isStreamingToolPlaceholder(part: Pick<ToolCallPart, 'artifact'>): boolean {\n return isRunningToolPlaceholderArtifact(part.artifact);\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') {\n // The placeholder is the backend's word that the call is still in flight.\n // A turn reads `complete` whenever nothing streams (a run parked on an\n // approval inside a subagent, the gap before a drained run resumes), and\n // assistant-ui counts the placeholder as the call's result when it settles\n // that status, so the turn's status cannot finish the call.\n return isStreamingToolPlaceholder(part) ? { type: 'running' } : { type: 'complete' };\n }\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 {\n waitingTools = NO_TOOLS,\n waitingToolCallIds = NO_TOOL_CALLS,\n passThroughTools = NO_TOOLS,\n }: 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 waitingToolCallIds.has(part.toolCallId) ||\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 const state = getActivityToolState(part, messageStatus, options);\n const delegations = toolCallDelegations({ part, state });\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,\n ...(delegations !== null ? { delegations } : {}),\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/**\n * Subagents one tool call delegated to (see `ActivityItem.delegations`), or\n * `null` for a call that delegates by nature of neither: a `task` call one,\n * unless the person refused it or its approval was withdrawn or expired (it\n * never ran); an `eval` call its in-interpreter dispatches, when it made any.\n */\nfunction toolCallDelegations({\n part,\n state,\n}: {\n part: ToolCallPart;\n state: ActivityToolState;\n}): number | null {\n if (part.toolName === TASK_TOOL_NAME) {\n const withdrawn =\n part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired';\n return state === 'rejected' || withdrawn ? 0 : 1;\n }\n if (part.toolName === EVAL_TOOL_NAME) {\n const dispatches = countInEvalDispatches(part.artifact);\n return dispatches > 0 ? dispatches : null;\n }\n return null;\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 * Subagents the turn delegated to: its `task` calls that ran, plus the\n * `task()` dispatches its `eval` calls made from inside the interpreter. A\n * `task` step built without its count (a host's own timeline) counts unless it\n * reads refused or cancelled.\n */\nexport function countActivityDelegations(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => {\n if (item.kind !== 'tool') return count;\n if (item.delegations !== undefined) return count + item.delegations;\n const ranTask =\n item.toolName === TASK_TOOL_NAME && item.state !== 'rejected' && item.state !== 'cancelled';\n return ranTask ? count + 1 : count;\n }, 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. A\n * complete turn with a step still running is running: only a step holding the\n * backend's running placeholder reads so once nothing streams (a run parked on\n * an approval inside a subagent, the gap before a drained run resumes).\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 if (\n status?.type === 'complete' &&\n timeline.some((item) => item.kind === 'tool' && item.state === 'running')\n ) {\n return 'running';\n }\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/**\n * The collapsed-card summary of a finished turn. \"Completed with issues\" means\n * the turn ended on a problem: a call the person refused, or a failed call\n * that no later call completed after. A failed command the agent then got past\n * (a search that found nothing, a retry that worked) is ordinary work, so a\n * long turn that recovered from it reads as the tools it used.\n *\n * A turn that delegated work leads with it — \"Delegated to 10 agents · used 6\n * tools\" — counting its `task` calls and the `task()` dispatches its `eval`\n * calls made from inside the interpreter (`countActivityDelegations`). A\n * `task` call is the delegation itself, so the tools it is followed by are the\n * turn's other calls; an outcome above replaces them (\"Delegated to 3 agents ·\n * completed with issues\").\n */\nexport function getActivitySummary(\n timeline: readonly ActivityItem[],\n { earlierStepsUnloaded = false, hiddenSteps }: ActivitySummaryOptions = {},\n): string {\n const tools = timeline.filter((item): item is ToolActivityItem => item.kind === 'tool');\n const outcome = activityOutcome(tools);\n // A turn of older history whose steps the page left out counts them exactly.\n const hiddenTools = hiddenSteps?.tools ?? 0;\n const hiddenDelegations = hiddenSteps?.delegations ?? 0;\n const delegations = countActivityDelegations(timeline) + hiddenDelegations;\n // A turn whose earlier steps have not loaded counts what has: a floor.\n const more = earlierStepsUnloaded ? '+' : '';\n if (delegations > 0) {\n const lead = `Delegated to ${delegations}${more} ${delegations === 1 && !more ? 'agent' : 'agents'}`;\n const otherTools =\n tools.filter((item) => item.toolName !== TASK_TOOL_NAME).length + hiddenTools - hiddenDelegations;\n const rest = outcome\n ? `${outcome.charAt(0).toLowerCase()}${outcome.slice(1)}`\n : otherTools > 0\n ? `used ${otherTools}${more} ${otherTools === 1 && !more ? 'tool' : 'tools'}`\n : null;\n return rest ? `${lead} · ${rest}` : lead;\n }\n if (outcome) return outcome;\n const toolTotal = tools.length + hiddenTools;\n if (toolTotal > 0) return `Used ${toolTotal}${more} ${toolTotal === 1 && !more ? 'tool' : 'tools'}`;\n if (earlierStepsUnloaded) return 'Earlier steps not loaded';\n return 'Reasoning complete';\n}\n\n/** How {@link getActivitySummary} reads a turn that may not be loaded whole. */\nexport interface ActivitySummaryOptions {\n /**\n * The turn's earlier steps have not loaded yet (older history above it, see\n * `useEarlierStepsUnloaded`): its counts read as floors, \"Used 43+ tools\".\n */\n earlierStepsUnloaded?: boolean;\n /**\n * The tool calls a page of older history left out of this turn\n * (`history/page`'s summary, via `useTurnSteps`): counted with the loaded\n * ones, exactly — \"Used 313 tools\".\n */\n hiddenSteps?: { tools: number; delegations: number } | undefined;\n}\n\ntype ToolActivityItem = Extract<ActivityItem, { kind: 'tool' }>;\n\n/** How a finished turn's tool calls ended, when that is not simply the tools it used. */\nfunction activityOutcome(tools: readonly ToolActivityItem[]): string | null {\n const lastFailure = tools.findLastIndex((item) => item.state === 'error');\n const endedOnFailure =\n lastFailure >= 0 && !tools.slice(lastFailure + 1).some((item) => item.state === 'complete');\n if (endedOnFailure || tools.some((item) => item.state === 'rejected')) return 'Completed with issues';\n if (tools.some((item) => item.state === 'cancelled')) return 'Action cancelled';\n if (tools.some((item) => item.state === 'paused')) return 'Paused during tool use';\n return null;\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":["isRunningToolPlaceholderArtifact","readRejectedToolResult","classifyToolResult","TASK_TOOL_NAME","EVAL_TOOL_NAME","countInEvalDispatches","summarizeToolCall","isSpokenTurnTextPart"],"mappings":"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"}
|
|
@@ -141,7 +141,7 @@ export declare function summarizeActivityTool(item: Extract<ActivityItem, {
|
|
|
141
141
|
* turn's other calls; an outcome above replaces them ("Delegated to 3 agents ·
|
|
142
142
|
* completed with issues").
|
|
143
143
|
*/
|
|
144
|
-
export declare function getActivitySummary(timeline: readonly ActivityItem[], { earlierStepsUnloaded }?: ActivitySummaryOptions): string;
|
|
144
|
+
export declare function getActivitySummary(timeline: readonly ActivityItem[], { earlierStepsUnloaded, hiddenSteps }?: ActivitySummaryOptions): string;
|
|
145
145
|
/** How {@link getActivitySummary} reads a turn that may not be loaded whole. */
|
|
146
146
|
export interface ActivitySummaryOptions {
|
|
147
147
|
/**
|
|
@@ -149,6 +149,15 @@ export interface ActivitySummaryOptions {
|
|
|
149
149
|
* `useEarlierStepsUnloaded`): its counts read as floors, "Used 43+ tools".
|
|
150
150
|
*/
|
|
151
151
|
earlierStepsUnloaded?: boolean;
|
|
152
|
+
/**
|
|
153
|
+
* The tool calls a page of older history left out of this turn
|
|
154
|
+
* (`history/page`'s summary, via `useTurnSteps`): counted with the loaded
|
|
155
|
+
* ones, exactly — "Used 313 tools".
|
|
156
|
+
*/
|
|
157
|
+
hiddenSteps?: {
|
|
158
|
+
tools: number;
|
|
159
|
+
delegations: number;
|
|
160
|
+
} | undefined;
|
|
152
161
|
}
|
|
153
162
|
/** The part shape the final-text read needs; any message role's parts satisfy it. */
|
|
154
163
|
export type FinalTextPart = {
|
|
@@ -150,19 +150,22 @@ function summarizeActivityTool(item, resolveToolDisplayName, assetTitles) {
|
|
|
150
150
|
...resolveToolDisplayName ? { displayName: resolveToolDisplayName(item.toolName) } : {}
|
|
151
151
|
});
|
|
152
152
|
}
|
|
153
|
-
function getActivitySummary(timeline, { earlierStepsUnloaded = false } = {}) {
|
|
153
|
+
function getActivitySummary(timeline, { earlierStepsUnloaded = false, hiddenSteps } = {}) {
|
|
154
154
|
const tools = timeline.filter((item) => item.kind === "tool");
|
|
155
155
|
const outcome = activityOutcome(tools);
|
|
156
|
-
const
|
|
156
|
+
const hiddenTools = (hiddenSteps == null ? void 0 : hiddenSteps.tools) ?? 0;
|
|
157
|
+
const hiddenDelegations = (hiddenSteps == null ? void 0 : hiddenSteps.delegations) ?? 0;
|
|
158
|
+
const delegations = countActivityDelegations(timeline) + hiddenDelegations;
|
|
157
159
|
const more = earlierStepsUnloaded ? "+" : "";
|
|
158
160
|
if (delegations > 0) {
|
|
159
161
|
const lead = `Delegated to ${delegations}${more} ${delegations === 1 && !more ? "agent" : "agents"}`;
|
|
160
|
-
const otherTools = tools.filter((item) => item.toolName !== TASK_TOOL_NAME).length;
|
|
162
|
+
const otherTools = tools.filter((item) => item.toolName !== TASK_TOOL_NAME).length + hiddenTools - hiddenDelegations;
|
|
161
163
|
const rest = outcome ? `${outcome.charAt(0).toLowerCase()}${outcome.slice(1)}` : otherTools > 0 ? `used ${otherTools}${more} ${otherTools === 1 && !more ? "tool" : "tools"}` : null;
|
|
162
164
|
return rest ? `${lead} · ${rest}` : lead;
|
|
163
165
|
}
|
|
164
166
|
if (outcome) return outcome;
|
|
165
|
-
|
|
167
|
+
const toolTotal = tools.length + hiddenTools;
|
|
168
|
+
if (toolTotal > 0) return `Used ${toolTotal}${more} ${toolTotal === 1 && !more ? "tool" : "tools"}`;
|
|
166
169
|
if (earlierStepsUnloaded) return "Earlier steps not loaded";
|
|
167
170
|
return "Reasoning complete";
|
|
168
171
|
}
|
|
@@ -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 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 countInEvalDispatches,\n EVAL_TOOL_NAME,\n isRunningToolPlaceholderArtifact,\n isSpokenTurnTextPart,\n readRejectedToolResult,\n TASK_TOOL_NAME,\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 * Subagents the call delegated to: for a `task` call one, or none when it\n * was refused, withdrawn or expired at its approval and never ran; for an\n * `eval` call its in-interpreter `task()` dispatches\n * (`countInEvalDispatches`), absent when it made none.\n */\n delegations?: number;\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 * Calls the run is parked on, by tool-call id, as the host reads them off\n * its pending approval: a gated call, or (in Olympus) a `task` call whose\n * subagent waits on an approval. Any of them still without its real result\n * reads as waiting.\n */\n waitingToolCallIds?: 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();\nconst NO_TOOL_CALLS: ReadonlySet<string> = new Set();\n\n/**\n * Whether a tool-call part still holds the backend's running-tool 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; its marker reaches the\n * part's artifact (`isRunningToolPlaceholderArtifact`). The real ToolMessage\n * that replaces it has no such marker, so a defined `result` alone does not\n * mean the tool is done.\n */\nexport function isStreamingToolPlaceholder(part: Pick<ToolCallPart, 'artifact'>): boolean {\n return isRunningToolPlaceholderArtifact(part.artifact);\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') {\n // The placeholder is the backend's word that the call is still in flight.\n // A turn reads `complete` whenever nothing streams (a run parked on an\n // approval inside a subagent, the gap before a drained run resumes), and\n // assistant-ui counts the placeholder as the call's result when it settles\n // that status, so the turn's status cannot finish the call.\n return isStreamingToolPlaceholder(part) ? { type: 'running' } : { type: 'complete' };\n }\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 {\n waitingTools = NO_TOOLS,\n waitingToolCallIds = NO_TOOL_CALLS,\n passThroughTools = NO_TOOLS,\n }: 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 waitingToolCallIds.has(part.toolCallId) ||\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 const state = getActivityToolState(part, messageStatus, options);\n const delegations = toolCallDelegations({ part, state });\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,\n ...(delegations !== null ? { delegations } : {}),\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/**\n * Subagents one tool call delegated to (see `ActivityItem.delegations`), or\n * `null` for a call that delegates by nature of neither: a `task` call one,\n * unless the person refused it or its approval was withdrawn or expired (it\n * never ran); an `eval` call its in-interpreter dispatches, when it made any.\n */\nfunction toolCallDelegations({\n part,\n state,\n}: {\n part: ToolCallPart;\n state: ActivityToolState;\n}): number | null {\n if (part.toolName === TASK_TOOL_NAME) {\n const withdrawn =\n part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired';\n return state === 'rejected' || withdrawn ? 0 : 1;\n }\n if (part.toolName === EVAL_TOOL_NAME) {\n const dispatches = countInEvalDispatches(part.artifact);\n return dispatches > 0 ? dispatches : null;\n }\n return null;\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 * Subagents the turn delegated to: its `task` calls that ran, plus the\n * `task()` dispatches its `eval` calls made from inside the interpreter. A\n * `task` step built without its count (a host's own timeline) counts unless it\n * reads refused or cancelled.\n */\nexport function countActivityDelegations(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => {\n if (item.kind !== 'tool') return count;\n if (item.delegations !== undefined) return count + item.delegations;\n const ranTask =\n item.toolName === TASK_TOOL_NAME && item.state !== 'rejected' && item.state !== 'cancelled';\n return ranTask ? count + 1 : count;\n }, 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. A\n * complete turn with a step still running is running: only a step holding the\n * backend's running placeholder reads so once nothing streams (a run parked on\n * an approval inside a subagent, the gap before a drained run resumes).\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 if (\n status?.type === 'complete' &&\n timeline.some((item) => item.kind === 'tool' && item.state === 'running')\n ) {\n return 'running';\n }\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/**\n * The collapsed-card summary of a finished turn. \"Completed with issues\" means\n * the turn ended on a problem: a call the person refused, or a failed call\n * that no later call completed after. A failed command the agent then got past\n * (a search that found nothing, a retry that worked) is ordinary work, so a\n * long turn that recovered from it reads as the tools it used.\n *\n * A turn that delegated work leads with it — \"Delegated to 10 agents · used 6\n * tools\" — counting its `task` calls and the `task()` dispatches its `eval`\n * calls made from inside the interpreter (`countActivityDelegations`). A\n * `task` call is the delegation itself, so the tools it is followed by are the\n * turn's other calls; an outcome above replaces them (\"Delegated to 3 agents ·\n * completed with issues\").\n */\nexport function getActivitySummary(\n timeline: readonly ActivityItem[],\n { earlierStepsUnloaded = false }: ActivitySummaryOptions = {},\n): string {\n const tools = timeline.filter((item): item is ToolActivityItem => item.kind === 'tool');\n const outcome = activityOutcome(tools);\n const delegations = countActivityDelegations(timeline);\n // A turn whose earlier steps have not loaded counts what has: a floor.\n const more = earlierStepsUnloaded ? '+' : '';\n if (delegations > 0) {\n const lead = `Delegated to ${delegations}${more} ${delegations === 1 && !more ? 'agent' : 'agents'}`;\n const otherTools = tools.filter((item) => item.toolName !== TASK_TOOL_NAME).length;\n const rest = outcome\n ? `${outcome.charAt(0).toLowerCase()}${outcome.slice(1)}`\n : otherTools > 0\n ? `used ${otherTools}${more} ${otherTools === 1 && !more ? 'tool' : 'tools'}`\n : null;\n return rest ? `${lead} · ${rest}` : lead;\n }\n if (outcome) return outcome;\n if (tools.length > 0) return `Used ${tools.length}${more} ${tools.length === 1 && !more ? 'tool' : 'tools'}`;\n if (earlierStepsUnloaded) return 'Earlier steps not loaded';\n return 'Reasoning complete';\n}\n\n/** How {@link getActivitySummary} reads a turn that may not be loaded whole. */\nexport interface ActivitySummaryOptions {\n /**\n * The turn's earlier steps have not loaded yet (older history above it, see\n * `useEarlierStepsUnloaded`): its counts read as floors, \"Used 43+ tools\".\n */\n earlierStepsUnloaded?: boolean;\n}\n\ntype ToolActivityItem = Extract<ActivityItem, { kind: 'tool' }>;\n\n/** How a finished turn's tool calls ended, when that is not simply the tools it used. */\nfunction activityOutcome(tools: readonly ToolActivityItem[]): string | null {\n const lastFailure = tools.findLastIndex((item) => item.state === 'error');\n const endedOnFailure =\n lastFailure >= 0 && !tools.slice(lastFailure + 1).some((item) => item.state === 'complete');\n if (endedOnFailure || tools.some((item) => item.state === 'rejected')) return 'Completed with issues';\n if (tools.some((item) => item.state === 'cancelled')) return 'Action cancelled';\n if (tools.some((item) => item.state === 'paused')) return 'Paused during tool use';\n return null;\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 countInEvalDispatches,\n EVAL_TOOL_NAME,\n isRunningToolPlaceholderArtifact,\n isSpokenTurnTextPart,\n readRejectedToolResult,\n TASK_TOOL_NAME,\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 * Subagents the call delegated to: for a `task` call one, or none when it\n * was refused, withdrawn or expired at its approval and never ran; for an\n * `eval` call its in-interpreter `task()` dispatches\n * (`countInEvalDispatches`), absent when it made none.\n */\n delegations?: number;\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 * Calls the run is parked on, by tool-call id, as the host reads them off\n * its pending approval: a gated call, or (in Olympus) a `task` call whose\n * subagent waits on an approval. Any of them still without its real result\n * reads as waiting.\n */\n waitingToolCallIds?: 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();\nconst NO_TOOL_CALLS: ReadonlySet<string> = new Set();\n\n/**\n * Whether a tool-call part still holds the backend's running-tool 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; its marker reaches the\n * part's artifact (`isRunningToolPlaceholderArtifact`). The real ToolMessage\n * that replaces it has no such marker, so a defined `result` alone does not\n * mean the tool is done.\n */\nexport function isStreamingToolPlaceholder(part: Pick<ToolCallPart, 'artifact'>): boolean {\n return isRunningToolPlaceholderArtifact(part.artifact);\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') {\n // The placeholder is the backend's word that the call is still in flight.\n // A turn reads `complete` whenever nothing streams (a run parked on an\n // approval inside a subagent, the gap before a drained run resumes), and\n // assistant-ui counts the placeholder as the call's result when it settles\n // that status, so the turn's status cannot finish the call.\n return isStreamingToolPlaceholder(part) ? { type: 'running' } : { type: 'complete' };\n }\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 {\n waitingTools = NO_TOOLS,\n waitingToolCallIds = NO_TOOL_CALLS,\n passThroughTools = NO_TOOLS,\n }: 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 waitingToolCallIds.has(part.toolCallId) ||\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 const state = getActivityToolState(part, messageStatus, options);\n const delegations = toolCallDelegations({ part, state });\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,\n ...(delegations !== null ? { delegations } : {}),\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/**\n * Subagents one tool call delegated to (see `ActivityItem.delegations`), or\n * `null` for a call that delegates by nature of neither: a `task` call one,\n * unless the person refused it or its approval was withdrawn or expired (it\n * never ran); an `eval` call its in-interpreter dispatches, when it made any.\n */\nfunction toolCallDelegations({\n part,\n state,\n}: {\n part: ToolCallPart;\n state: ActivityToolState;\n}): number | null {\n if (part.toolName === TASK_TOOL_NAME) {\n const withdrawn =\n part.approval?.resolution === 'cancelled' || part.approval?.resolution === 'expired';\n return state === 'rejected' || withdrawn ? 0 : 1;\n }\n if (part.toolName === EVAL_TOOL_NAME) {\n const dispatches = countInEvalDispatches(part.artifact);\n return dispatches > 0 ? dispatches : null;\n }\n return null;\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 * Subagents the turn delegated to: its `task` calls that ran, plus the\n * `task()` dispatches its `eval` calls made from inside the interpreter. A\n * `task` step built without its count (a host's own timeline) counts unless it\n * reads refused or cancelled.\n */\nexport function countActivityDelegations(timeline: readonly ActivityItem[]): number {\n return timeline.reduce((count, item) => {\n if (item.kind !== 'tool') return count;\n if (item.delegations !== undefined) return count + item.delegations;\n const ranTask =\n item.toolName === TASK_TOOL_NAME && item.state !== 'rejected' && item.state !== 'cancelled';\n return ranTask ? count + 1 : count;\n }, 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. A\n * complete turn with a step still running is running: only a step holding the\n * backend's running placeholder reads so once nothing streams (a run parked on\n * an approval inside a subagent, the gap before a drained run resumes).\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 if (\n status?.type === 'complete' &&\n timeline.some((item) => item.kind === 'tool' && item.state === 'running')\n ) {\n return 'running';\n }\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/**\n * The collapsed-card summary of a finished turn. \"Completed with issues\" means\n * the turn ended on a problem: a call the person refused, or a failed call\n * that no later call completed after. A failed command the agent then got past\n * (a search that found nothing, a retry that worked) is ordinary work, so a\n * long turn that recovered from it reads as the tools it used.\n *\n * A turn that delegated work leads with it — \"Delegated to 10 agents · used 6\n * tools\" — counting its `task` calls and the `task()` dispatches its `eval`\n * calls made from inside the interpreter (`countActivityDelegations`). A\n * `task` call is the delegation itself, so the tools it is followed by are the\n * turn's other calls; an outcome above replaces them (\"Delegated to 3 agents ·\n * completed with issues\").\n */\nexport function getActivitySummary(\n timeline: readonly ActivityItem[],\n { earlierStepsUnloaded = false, hiddenSteps }: ActivitySummaryOptions = {},\n): string {\n const tools = timeline.filter((item): item is ToolActivityItem => item.kind === 'tool');\n const outcome = activityOutcome(tools);\n // A turn of older history whose steps the page left out counts them exactly.\n const hiddenTools = hiddenSteps?.tools ?? 0;\n const hiddenDelegations = hiddenSteps?.delegations ?? 0;\n const delegations = countActivityDelegations(timeline) + hiddenDelegations;\n // A turn whose earlier steps have not loaded counts what has: a floor.\n const more = earlierStepsUnloaded ? '+' : '';\n if (delegations > 0) {\n const lead = `Delegated to ${delegations}${more} ${delegations === 1 && !more ? 'agent' : 'agents'}`;\n const otherTools =\n tools.filter((item) => item.toolName !== TASK_TOOL_NAME).length + hiddenTools - hiddenDelegations;\n const rest = outcome\n ? `${outcome.charAt(0).toLowerCase()}${outcome.slice(1)}`\n : otherTools > 0\n ? `used ${otherTools}${more} ${otherTools === 1 && !more ? 'tool' : 'tools'}`\n : null;\n return rest ? `${lead} · ${rest}` : lead;\n }\n if (outcome) return outcome;\n const toolTotal = tools.length + hiddenTools;\n if (toolTotal > 0) return `Used ${toolTotal}${more} ${toolTotal === 1 && !more ? 'tool' : 'tools'}`;\n if (earlierStepsUnloaded) return 'Earlier steps not loaded';\n return 'Reasoning complete';\n}\n\n/** How {@link getActivitySummary} reads a turn that may not be loaded whole. */\nexport interface ActivitySummaryOptions {\n /**\n * The turn's earlier steps have not loaded yet (older history above it, see\n * `useEarlierStepsUnloaded`): its counts read as floors, \"Used 43+ tools\".\n */\n earlierStepsUnloaded?: boolean;\n /**\n * The tool calls a page of older history left out of this turn\n * (`history/page`'s summary, via `useTurnSteps`): counted with the loaded\n * ones, exactly — \"Used 313 tools\".\n */\n hiddenSteps?: { tools: number; delegations: number } | undefined;\n}\n\ntype ToolActivityItem = Extract<ActivityItem, { kind: 'tool' }>;\n\n/** How a finished turn's tool calls ended, when that is not simply the tools it used. */\nfunction activityOutcome(tools: readonly ToolActivityItem[]): string | null {\n const lastFailure = tools.findLastIndex((item) => item.state === 'error');\n const endedOnFailure =\n lastFailure >= 0 && !tools.slice(lastFailure + 1).some((item) => item.state === 'complete');\n if (endedOnFailure || tools.some((item) => item.state === 'rejected')) return 'Completed with issues';\n if (tools.some((item) => item.state === 'cancelled')) return 'Action cancelled';\n if (tools.some((item) => item.state === 'paused')) return 'Paused during tool use';\n return null;\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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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const react = require("@assistant-ui/react");
|
|
5
|
+
const lucideReact = require("lucide-react");
|
|
6
|
+
const require$$0 = require("react");
|
|
7
|
+
const historyStore = require("../../agent-runtime/src/history-store.cjs");
|
|
8
|
+
const errors = require("../../agent-runtime/src/errors.cjs");
|
|
9
|
+
function EarlierStepsButton({ marker, autoLoad = false }) {
|
|
10
|
+
const send = react.useAuiState(
|
|
11
|
+
(s) => {
|
|
12
|
+
var _a;
|
|
13
|
+
return (_a = s.thread.extras) == null ? void 0 : _a.sendCommand;
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
const [loading, setLoading] = require$$0.useState(false);
|
|
17
|
+
const loadSteps = require$$0.useCallback(() => {
|
|
18
|
+
if (marker.hiddenSteps === 0 || loading || !send) return;
|
|
19
|
+
setLoading(true);
|
|
20
|
+
historyStore.loadDeepAgentTurnSteps({ send, marker }).catch((error) => {
|
|
21
|
+
if (error instanceof Error && errors.isStatewireChannelTeardown(error)) return;
|
|
22
|
+
console.warn("[AthenaChat] history/page steps failed:", error);
|
|
23
|
+
}).finally(() => setLoading(false));
|
|
24
|
+
}, [loading, marker, send]);
|
|
25
|
+
const autoLoadedTurn = require$$0.useRef(null);
|
|
26
|
+
const wantsNewest = autoLoad && marker.before === void 0 && marker.hiddenSteps > 0;
|
|
27
|
+
require$$0.useEffect(() => {
|
|
28
|
+
if (!wantsNewest || autoLoadedTurn.current === marker.turn) return;
|
|
29
|
+
autoLoadedTurn.current = marker.turn;
|
|
30
|
+
loadSteps();
|
|
31
|
+
}, [wantsNewest, marker.turn, loadSteps]);
|
|
32
|
+
if (marker.hiddenSteps === 0 || !send) return null;
|
|
33
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
34
|
+
"button",
|
|
35
|
+
{
|
|
36
|
+
type: "button",
|
|
37
|
+
"data-slot": "turn-earlier-steps",
|
|
38
|
+
onClick: loadSteps,
|
|
39
|
+
disabled: loading,
|
|
40
|
+
className: "flex w-fit items-center gap-1.5 rounded py-0.5 text-xs text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-70",
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": "true", className: "size-3" }),
|
|
43
|
+
loading ? "Loading earlier steps…" : `Show ${marker.hiddenSteps} earlier ${marker.hiddenSteps === 1 ? "step" : "steps"}`
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
exports.EarlierStepsButton = EarlierStepsButton;
|
|
49
|
+
//# sourceMappingURL=earlier-steps-button.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"earlier-steps-button.cjs","sources":["../../../src/chat/super-grouping/earlier-steps-button.tsx"],"sourcesContent":["import { useAuiState } from '@assistant-ui/react';\nimport {\n type DeepAgentHistorySend,\n isStatewireChannelTeardown,\n loadDeepAgentTurnSteps,\n} from '@athenaintel/agent-runtime';\nimport { ChevronRight } from 'lucide-react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { TurnStepsControlProps } from './use-turn-steps';\n\n/**\n * \"Show 600 earlier steps\": fetches the next (older) steps a turn of older\n * history left out (`history/page` with its `turn`, into the conversation's\n * history store through `loadDeepAgentTurnSteps`), newest first, until none\n * are left. With `autoLoad` (an opened card) it fetches the newest page by\n * itself, once per turn; a failed or further page is the reader's to ask for,\n * never a retry loop. Renders nothing for a turn with no steps left, or with\n * no thread to ask. `AthenaProvider` provides it (`TurnStepsControlContext`).\n */\nexport function EarlierStepsButton({ marker, autoLoad = false }: TurnStepsControlProps) {\n const send = useAuiState(\n (s) => (s.thread.extras as { sendCommand?: DeepAgentHistorySend } | undefined)?.sendCommand,\n );\n const [loading, setLoading] = useState(false);\n const loadSteps = useCallback(() => {\n if (marker.hiddenSteps === 0 || loading || !send) return;\n setLoading(true);\n loadDeepAgentTurnSteps({ send, marker })\n .catch((error: unknown) => {\n if (error instanceof Error && isStatewireChannelTeardown(error)) return;\n console.warn('[AthenaChat] history/page steps failed:', error);\n })\n .finally(() => setLoading(false));\n }, [loading, marker, send]);\n const autoLoadedTurn = useRef<string | null>(null);\n const wantsNewest = autoLoad && marker.before === undefined && marker.hiddenSteps > 0;\n useEffect(() => {\n if (!wantsNewest || autoLoadedTurn.current === marker.turn) return;\n autoLoadedTurn.current = marker.turn;\n loadSteps();\n }, [wantsNewest, marker.turn, loadSteps]);\n if (marker.hiddenSteps === 0 || !send) return null;\n return (\n <button\n type=\"button\"\n data-slot=\"turn-earlier-steps\"\n onClick={loadSteps}\n disabled={loading}\n className=\"flex w-fit items-center gap-1.5 rounded py-0.5 text-xs text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-70\"\n >\n <ChevronRight aria-hidden=\"true\" className=\"size-3\" />\n {loading\n ? 'Loading earlier steps…'\n : `Show ${marker.hiddenSteps} earlier ${marker.hiddenSteps === 1 ? 'step' : 'steps'}`}\n </button>\n );\n}\n"],"names":["useAuiState","useState","useCallback","loadDeepAgentTurnSteps","isStatewireChannelTeardown","useRef","useEffect","jsxs","jsx","ChevronRight"],"mappings":";;;;;;;;AAmBO,SAAS,mBAAmB,EAAE,QAAQ,WAAW,SAAgC;AACtF,QAAM,OAAOA,MAAAA;AAAAA,IACX,CAAC,MAAA;;AAAO,qBAAE,OAAO,WAAT,mBAAwE;AAAA;AAAA,EAAA;AAElF,QAAM,CAAC,SAAS,UAAU,IAAIC,WAAAA,SAAS,KAAK;AAC5C,QAAM,YAAYC,WAAAA,YAAY,MAAM;AAClC,QAAI,OAAO,gBAAgB,KAAK,WAAW,CAAC,KAAM;AAClD,eAAW,IAAI;AACfC,iBAAAA,uBAAuB,EAAE,MAAM,OAAA,CAAQ,EACpC,MAAM,CAAC,UAAmB;AACzB,UAAI,iBAAiB,SAASC,OAAAA,2BAA2B,KAAK,EAAG;AACjE,cAAQ,KAAK,2CAA2C,KAAK;AAAA,IAC/D,CAAC,EACA,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,EACpC,GAAG,CAAC,SAAS,QAAQ,IAAI,CAAC;AAC1B,QAAM,iBAAiBC,WAAAA,OAAsB,IAAI;AACjD,QAAM,cAAc,YAAY,OAAO,WAAW,UAAa,OAAO,cAAc;AACpFC,aAAAA,UAAU,MAAM;AACd,QAAI,CAAC,eAAe,eAAe,YAAY,OAAO,KAAM;AAC5D,mBAAe,UAAU,OAAO;AAChC,cAAA;AAAA,EACF,GAAG,CAAC,aAAa,OAAO,MAAM,SAAS,CAAC;AACxC,MAAI,OAAO,gBAAgB,KAAK,CAAC,KAAM,QAAO;AAC9C,SACEC,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAU;AAAA,MAEV,UAAA;AAAA,QAAAC,2BAAAA,IAACC,YAAAA,cAAA,EAAa,eAAY,QAAO,WAAU,UAAS;AAAA,QACnD,UACG,2BACA,QAAQ,OAAO,WAAW,YAAY,OAAO,gBAAgB,IAAI,SAAS,OAAO;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAG3F;;"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TurnStepsControlProps } from './use-turn-steps';
|
|
2
|
+
/**
|
|
3
|
+
* "Show 600 earlier steps": fetches the next (older) steps a turn of older
|
|
4
|
+
* history left out (`history/page` with its `turn`, into the conversation's
|
|
5
|
+
* history store through `loadDeepAgentTurnSteps`), newest first, until none
|
|
6
|
+
* are left. With `autoLoad` (an opened card) it fetches the newest page by
|
|
7
|
+
* itself, once per turn; a failed or further page is the reader's to ask for,
|
|
8
|
+
* never a retry loop. Renders nothing for a turn with no steps left, or with
|
|
9
|
+
* no thread to ask. `AthenaProvider` provides it (`TurnStepsControlContext`).
|
|
10
|
+
*/
|
|
11
|
+
export declare function EarlierStepsButton({ marker, autoLoad }: TurnStepsControlProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useAuiState } from "@assistant-ui/react";
|
|
3
|
+
import { ChevronRight } from "lucide-react";
|
|
4
|
+
import { useState, useCallback, useRef, useEffect } from "react";
|
|
5
|
+
import { loadDeepAgentTurnSteps } from "../../agent-runtime/src/history-store.js";
|
|
6
|
+
import { isStatewireChannelTeardown } from "../../agent-runtime/src/errors.js";
|
|
7
|
+
function EarlierStepsButton({ marker, autoLoad = false }) {
|
|
8
|
+
const send = useAuiState(
|
|
9
|
+
(s) => {
|
|
10
|
+
var _a;
|
|
11
|
+
return (_a = s.thread.extras) == null ? void 0 : _a.sendCommand;
|
|
12
|
+
}
|
|
13
|
+
);
|
|
14
|
+
const [loading, setLoading] = useState(false);
|
|
15
|
+
const loadSteps = useCallback(() => {
|
|
16
|
+
if (marker.hiddenSteps === 0 || loading || !send) return;
|
|
17
|
+
setLoading(true);
|
|
18
|
+
loadDeepAgentTurnSteps({ send, marker }).catch((error) => {
|
|
19
|
+
if (error instanceof Error && isStatewireChannelTeardown(error)) return;
|
|
20
|
+
console.warn("[AthenaChat] history/page steps failed:", error);
|
|
21
|
+
}).finally(() => setLoading(false));
|
|
22
|
+
}, [loading, marker, send]);
|
|
23
|
+
const autoLoadedTurn = useRef(null);
|
|
24
|
+
const wantsNewest = autoLoad && marker.before === void 0 && marker.hiddenSteps > 0;
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!wantsNewest || autoLoadedTurn.current === marker.turn) return;
|
|
27
|
+
autoLoadedTurn.current = marker.turn;
|
|
28
|
+
loadSteps();
|
|
29
|
+
}, [wantsNewest, marker.turn, loadSteps]);
|
|
30
|
+
if (marker.hiddenSteps === 0 || !send) return null;
|
|
31
|
+
return /* @__PURE__ */ jsxs(
|
|
32
|
+
"button",
|
|
33
|
+
{
|
|
34
|
+
type: "button",
|
|
35
|
+
"data-slot": "turn-earlier-steps",
|
|
36
|
+
onClick: loadSteps,
|
|
37
|
+
disabled: loading,
|
|
38
|
+
className: "flex w-fit items-center gap-1.5 rounded py-0.5 text-xs text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-70",
|
|
39
|
+
children: [
|
|
40
|
+
/* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "size-3" }),
|
|
41
|
+
loading ? "Loading earlier steps…" : `Show ${marker.hiddenSteps} earlier ${marker.hiddenSteps === 1 ? "step" : "steps"}`
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
EarlierStepsButton
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=earlier-steps-button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"earlier-steps-button.js","sources":["../../../src/chat/super-grouping/earlier-steps-button.tsx"],"sourcesContent":["import { useAuiState } from '@assistant-ui/react';\nimport {\n type DeepAgentHistorySend,\n isStatewireChannelTeardown,\n loadDeepAgentTurnSteps,\n} from '@athenaintel/agent-runtime';\nimport { ChevronRight } from 'lucide-react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { TurnStepsControlProps } from './use-turn-steps';\n\n/**\n * \"Show 600 earlier steps\": fetches the next (older) steps a turn of older\n * history left out (`history/page` with its `turn`, into the conversation's\n * history store through `loadDeepAgentTurnSteps`), newest first, until none\n * are left. With `autoLoad` (an opened card) it fetches the newest page by\n * itself, once per turn; a failed or further page is the reader's to ask for,\n * never a retry loop. Renders nothing for a turn with no steps left, or with\n * no thread to ask. `AthenaProvider` provides it (`TurnStepsControlContext`).\n */\nexport function EarlierStepsButton({ marker, autoLoad = false }: TurnStepsControlProps) {\n const send = useAuiState(\n (s) => (s.thread.extras as { sendCommand?: DeepAgentHistorySend } | undefined)?.sendCommand,\n );\n const [loading, setLoading] = useState(false);\n const loadSteps = useCallback(() => {\n if (marker.hiddenSteps === 0 || loading || !send) return;\n setLoading(true);\n loadDeepAgentTurnSteps({ send, marker })\n .catch((error: unknown) => {\n if (error instanceof Error && isStatewireChannelTeardown(error)) return;\n console.warn('[AthenaChat] history/page steps failed:', error);\n })\n .finally(() => setLoading(false));\n }, [loading, marker, send]);\n const autoLoadedTurn = useRef<string | null>(null);\n const wantsNewest = autoLoad && marker.before === undefined && marker.hiddenSteps > 0;\n useEffect(() => {\n if (!wantsNewest || autoLoadedTurn.current === marker.turn) return;\n autoLoadedTurn.current = marker.turn;\n loadSteps();\n }, [wantsNewest, marker.turn, loadSteps]);\n if (marker.hiddenSteps === 0 || !send) return null;\n return (\n <button\n type=\"button\"\n data-slot=\"turn-earlier-steps\"\n onClick={loadSteps}\n disabled={loading}\n className=\"flex w-fit items-center gap-1.5 rounded py-0.5 text-xs text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-70\"\n >\n <ChevronRight aria-hidden=\"true\" className=\"size-3\" />\n {loading\n ? 'Loading earlier steps…'\n : `Show ${marker.hiddenSteps} earlier ${marker.hiddenSteps === 1 ? 'step' : 'steps'}`}\n </button>\n );\n}\n"],"names":[],"mappings":";;;;;;AAmBO,SAAS,mBAAmB,EAAE,QAAQ,WAAW,SAAgC;AACtF,QAAM,OAAO;AAAA,IACX,CAAC,MAAA;;AAAO,qBAAE,OAAO,WAAT,mBAAwE;AAAA;AAAA,EAAA;AAElF,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,YAAY,YAAY,MAAM;AAClC,QAAI,OAAO,gBAAgB,KAAK,WAAW,CAAC,KAAM;AAClD,eAAW,IAAI;AACf,2BAAuB,EAAE,MAAM,OAAA,CAAQ,EACpC,MAAM,CAAC,UAAmB;AACzB,UAAI,iBAAiB,SAAS,2BAA2B,KAAK,EAAG;AACjE,cAAQ,KAAK,2CAA2C,KAAK;AAAA,IAC/D,CAAC,EACA,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,EACpC,GAAG,CAAC,SAAS,QAAQ,IAAI,CAAC;AAC1B,QAAM,iBAAiB,OAAsB,IAAI;AACjD,QAAM,cAAc,YAAY,OAAO,WAAW,UAAa,OAAO,cAAc;AACpF,YAAU,MAAM;AACd,QAAI,CAAC,eAAe,eAAe,YAAY,OAAO,KAAM;AAC5D,mBAAe,UAAU,OAAO;AAChC,cAAA;AAAA,EACF,GAAG,CAAC,aAAa,OAAO,MAAM,SAAS,CAAC;AACxC,MAAI,OAAO,gBAAgB,KAAK,CAAC,KAAM,QAAO;AAC9C,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAU;AAAA,MAEV,UAAA;AAAA,QAAA,oBAAC,cAAA,EAAa,eAAY,QAAO,WAAU,UAAS;AAAA,QACnD,UACG,2BACA,QAAQ,OAAO,WAAW,YAAY,OAAO,gBAAgB,IAAI,SAAS,OAAO;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAG3F;"}
|
|
@@ -44,6 +44,7 @@ const DEFAULT_TOOL_TO_TOOLKIT = {
|
|
|
44
44
|
capture_slide_screenshot: "Presentation",
|
|
45
45
|
capture_slide_screenshots: "Presentation",
|
|
46
46
|
restore_presentation_slides: "Presentation",
|
|
47
|
+
restore_spreadsheet_sheets: "Spreadsheet",
|
|
47
48
|
// Studio presentation PTC
|
|
48
49
|
CreatePresentation: "Presentation",
|
|
49
50
|
OpenPresentation: "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 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 restore_presentation_slides: '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,EAC3B,6BAA6B;AAAA;AAAA,
|
|
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 restore_presentation_slides: 'Presentation',\n restore_spreadsheet_sheets: 'Spreadsheet',\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,EAC3B,6BAA6B;AAAA,EAC7B,4BAA4B;AAAA;AAAA,EAE5B,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;;"}
|
|
@@ -42,6 +42,7 @@ const DEFAULT_TOOL_TO_TOOLKIT = {
|
|
|
42
42
|
capture_slide_screenshot: "Presentation",
|
|
43
43
|
capture_slide_screenshots: "Presentation",
|
|
44
44
|
restore_presentation_slides: "Presentation",
|
|
45
|
+
restore_spreadsheet_sheets: "Spreadsheet",
|
|
45
46
|
// Studio presentation PTC
|
|
46
47
|
CreatePresentation: "Presentation",
|
|
47
48
|
OpenPresentation: "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 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 restore_presentation_slides: '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,EAC3B,6BAA6B;AAAA;AAAA,
|
|
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 restore_presentation_slides: 'Presentation',\n restore_spreadsheet_sheets: 'Spreadsheet',\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,EAC3B,6BAA6B;AAAA,EAC7B,4BAA4B;AAAA;AAAA,EAE5B,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;"}
|