@athenaintel/react 0.59.0 → 0.60.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +124 -20
  2. package/dist/agent-runtime/src/client-tool-bridge.cjs +20 -2
  3. package/dist/agent-runtime/src/client-tool-bridge.cjs.map +1 -1
  4. package/dist/agent-runtime/src/client-tool-bridge.d.ts +9 -4
  5. package/dist/agent-runtime/src/client-tool-bridge.js +20 -2
  6. package/dist/agent-runtime/src/client-tool-bridge.js.map +1 -1
  7. package/dist/agent-runtime/src/client-tools.cjs.map +1 -1
  8. package/dist/agent-runtime/src/client-tools.d.ts +9 -0
  9. package/dist/agent-runtime/src/client-tools.js.map +1 -1
  10. package/dist/agent-runtime/src/composer-markdown.cjs +0 -16
  11. package/dist/agent-runtime/src/composer-markdown.cjs.map +1 -1
  12. package/dist/agent-runtime/src/composer-markdown.js +1 -17
  13. package/dist/agent-runtime/src/composer-markdown.js.map +1 -1
  14. package/dist/agent-runtime/src/named-agents.js +1 -1
  15. package/dist/agent-runtime/src/offline-status.cjs.map +1 -1
  16. package/dist/agent-runtime/src/offline-status.d.ts +27 -0
  17. package/dist/agent-runtime/src/offline-status.js.map +1 -1
  18. package/dist/agent-runtime/src/tool-metadata.cjs +7 -0
  19. package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
  20. package/dist/agent-runtime/src/tool-metadata.js +7 -0
  21. package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
  22. package/dist/chat/AthenaChat.cjs +17 -5
  23. package/dist/chat/AthenaChat.cjs.map +1 -1
  24. package/dist/chat/AthenaChat.js +18 -6
  25. package/dist/chat/AthenaChat.js.map +1 -1
  26. package/dist/chat/StatewireClientToolBridge.cjs +69 -1
  27. package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
  28. package/dist/chat/StatewireClientToolBridge.d.ts +14 -1
  29. package/dist/chat/StatewireClientToolBridge.js +70 -2
  30. package/dist/chat/StatewireClientToolBridge.js.map +1 -1
  31. package/dist/chat/StatewireClientToolConsentCard.cjs +65 -0
  32. package/dist/chat/StatewireClientToolConsentCard.cjs.map +1 -0
  33. package/dist/chat/StatewireClientToolConsentCard.d.ts +24 -0
  34. package/dist/chat/StatewireClientToolConsentCard.js +65 -0
  35. package/dist/chat/StatewireClientToolConsentCard.js.map +1 -0
  36. package/dist/chat/client-tool-write-consent.cjs +111 -0
  37. package/dist/chat/client-tool-write-consent.cjs.map +1 -0
  38. package/dist/chat/client-tool-write-consent.d.ts +71 -0
  39. package/dist/chat/client-tool-write-consent.js +111 -0
  40. package/dist/chat/client-tool-write-consent.js.map +1 -0
  41. package/dist/chat/statewire-client-tools.cjs +30 -5
  42. package/dist/chat/statewire-client-tools.cjs.map +1 -1
  43. package/dist/chat/statewire-client-tools.d.ts +34 -2
  44. package/dist/chat/statewire-client-tools.js +30 -5
  45. package/dist/chat/statewire-client-tools.js.map +1 -1
  46. package/dist/chat-ui/index.cjs +2 -0
  47. package/dist/chat-ui/index.cjs.map +1 -1
  48. package/dist/chat-ui/index.d.ts +1 -0
  49. package/dist/chat-ui/index.js +2 -0
  50. package/dist/chat-ui/index.js.map +1 -1
  51. package/dist/chat-ui/mentions/mention-chip.cjs +9 -3
  52. package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
  53. package/dist/chat-ui/mentions/mention-chip.js +9 -3
  54. package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
  55. package/dist/chat-ui/mentions/suggestions/components/mention-icon.cjs +18 -2
  56. package/dist/chat-ui/mentions/suggestions/components/mention-icon.cjs.map +1 -1
  57. package/dist/chat-ui/mentions/suggestions/components/mention-icon.d.ts +10 -1
  58. package/dist/chat-ui/mentions/suggestions/components/mention-icon.js +19 -3
  59. package/dist/chat-ui/mentions/suggestions/components/mention-icon.js.map +1 -1
  60. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +9 -0
  61. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
  62. package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +6 -0
  63. package/dist/chat-ui/mentions/suggestions/data/api-client.js +9 -0
  64. package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
  65. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icon-names.generated.cjs +89 -0
  66. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icon-names.generated.cjs.map +1 -0
  67. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icon-names.generated.d.ts +8 -0
  68. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icon-names.generated.js +89 -0
  69. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icon-names.generated.js.map +1 -0
  70. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs +153 -116
  71. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs.map +1 -1
  72. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.d.ts +58 -12
  73. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js +154 -117
  74. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js.map +1 -1
  75. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +38 -6
  76. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
  77. package/dist/chat-ui/mentions/suggestions/data/sources/index.js +40 -8
  78. package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
  79. package/dist/chat-ui/mentions/use-asset-icon-app-url.cjs +13 -0
  80. package/dist/chat-ui/mentions/use-asset-icon-app-url.cjs.map +1 -0
  81. package/dist/chat-ui/mentions/use-asset-icon-app-url.d.ts +9 -0
  82. package/dist/chat-ui/mentions/use-asset-icon-app-url.js +13 -0
  83. package/dist/chat-ui/mentions/use-asset-icon-app-url.js.map +1 -0
  84. package/dist/chat-ui/statewire.cjs +4 -0
  85. package/dist/chat-ui/statewire.cjs.map +1 -1
  86. package/dist/chat-ui/statewire.d.ts +2 -0
  87. package/dist/chat-ui/statewire.js +4 -0
  88. package/dist/chat-ui/statewire.js.map +1 -1
  89. package/dist/collab/client.cjs +24 -1
  90. package/dist/collab/client.cjs.map +1 -1
  91. package/dist/collab/client.d.ts +16 -0
  92. package/dist/collab/client.js +24 -1
  93. package/dist/collab/client.js.map +1 -1
  94. package/dist/composer/attached-references.js +1 -1
  95. package/dist/composer/staged-message-metadata.cjs +12 -0
  96. package/dist/composer/staged-message-metadata.cjs.map +1 -0
  97. package/dist/composer/staged-message-metadata.d.ts +15 -0
  98. package/dist/composer/staged-message-metadata.js +12 -0
  99. package/dist/composer/staged-message-metadata.js.map +1 -0
  100. package/dist/data/athena-request.cjs +2 -0
  101. package/dist/data/athena-request.cjs.map +1 -1
  102. package/dist/data/athena-request.js +2 -0
  103. package/dist/data/athena-request.js.map +1 -1
  104. package/dist/index.cjs +5 -0
  105. package/dist/index.cjs.map +1 -1
  106. package/dist/index.d.ts +6 -2
  107. package/dist/index.js +6 -1
  108. package/dist/index.js.map +1 -1
  109. package/dist/provider/AthenaProvider.cjs +26 -6
  110. package/dist/provider/AthenaProvider.cjs.map +1 -1
  111. package/dist/provider/AthenaProvider.d.ts +8 -1
  112. package/dist/provider/AthenaProvider.js +27 -7
  113. package/dist/provider/AthenaProvider.js.map +1 -1
  114. package/dist/react/package.json.cjs +1 -1
  115. package/dist/react/package.json.js +1 -1
  116. package/dist/references/src/anchors/parse.cjs +11 -1
  117. package/dist/references/src/anchors/parse.cjs.map +1 -1
  118. package/dist/references/src/anchors/parse.js +11 -1
  119. package/dist/references/src/anchors/parse.js.map +1 -1
  120. package/dist/references/src/anchors/schemas.d.ts +1 -0
  121. package/dist/references/src/anchors/serialize.cjs +1 -0
  122. package/dist/references/src/anchors/serialize.cjs.map +1 -1
  123. package/dist/references/src/anchors/serialize.js +1 -0
  124. package/dist/references/src/anchors/serialize.js.map +1 -1
  125. package/dist/references/src/anchors/types.cjs.map +1 -1
  126. package/dist/references/src/anchors/types.d.ts +9 -0
  127. package/dist/references/src/anchors/types.js.map +1 -1
  128. package/dist/references/src/schemas.d.ts +2 -0
  129. package/dist/runtime/useAthenaStatewireRuntime.cjs +6 -8
  130. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  131. package/dist/runtime/useAthenaStatewireRuntime.js +6 -8
  132. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  133. package/dist/threads/statewire-thread-list.cjs +14 -2
  134. package/dist/threads/statewire-thread-list.cjs.map +1 -1
  135. package/dist/threads/statewire-thread-list.d.ts +11 -2
  136. package/dist/threads/statewire-thread-list.js +14 -2
  137. package/dist/threads/statewire-thread-list.js.map +1 -1
  138. package/dist/tools/drive-tool-uis.cjs +8 -4
  139. package/dist/tools/drive-tool-uis.cjs.map +1 -1
  140. package/dist/tools/drive-tool-uis.d.ts +5 -4
  141. package/dist/tools/drive-tool-uis.js +9 -5
  142. package/dist/tools/drive-tool-uis.js.map +1 -1
  143. package/dist/version.cjs +4 -0
  144. package/dist/version.cjs.map +1 -1
  145. package/dist/version.d.ts +9 -0
  146. package/dist/version.js +4 -0
  147. package/dist/version.js.map +1 -1
  148. package/dist/workbench/live-desktop-api.cjs +2 -1
  149. package/dist/workbench/live-desktop-api.cjs.map +1 -1
  150. package/dist/workbench/live-desktop-api.js +2 -1
  151. package/dist/workbench/live-desktop-api.js.map +1 -1
  152. package/dist/workbench/session-workspace-api.cjs +7 -2
  153. package/dist/workbench/session-workspace-api.cjs.map +1 -1
  154. package/dist/workbench/session-workspace-api.d.ts +10 -0
  155. package/dist/workbench/session-workspace-api.js +7 -2
  156. package/dist/workbench/session-workspace-api.js.map +1 -1
  157. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"drive-tool-uis.cjs","sources":["../../src/tools/drive-tool-uis.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * The Athena Drive cards, as Athena on the web draws them: `search_assets`\n * (the matches, each opening its asset), `list_contents` (a folder's tree and\n * the assets in it) and `project_links` (a project's links as asset chips).\n *\n * Olympus reads each asset's title and thumbnail from its asset cache; these\n * cards draw only what the call's arguments and result carry. An asset shows\n * its type's icon when the result names its type, and an asset the result\n * names by id alone shows its id.\n */\nimport type {\n ToolCallMessagePartComponent,\n ToolCallMessagePartStatus,\n} from \"@assistant-ui/react\";\nimport {\n classifyToolResult,\n isRecord,\n stringField,\n type ToolResultClassification,\n} from \"@athenaintel/agent-runtime\";\nimport { ArrowRightIcon, FolderIcon, LinkIcon, SearchIcon } from \"lucide-react\";\nimport { memo, type ReactNode } from \"react\";\nimport { type AssetType, useAssetPanelStore } from \"../assets/asset-panel-store\";\nimport {\n CHIP_ICON_CLASS,\n CHIP_LINK_CLASS,\n CHIP_PILL_CLASS,\n} from \"../chat-ui/mentions/mention-chip\";\nimport { MentionIcon } from \"../chat-ui/mentions/suggestions/components/mention-icon\";\nimport {\n assetTypeToIcon,\n assetTypeToThumb,\n} from \"../chat-ui/mentions/suggestions/data/sources/asset-type-icons\";\nimport { cn } from \"../lib/utils\";\nimport { ExpandableSection, normalizeResult, ToolCard, type ToolStatus } from \"./primitives\";\nimport { ToolFallback } from \"./tool-fallback\";\n\n// ─── Shared by the Drive and project manager cards ───────────────────\n\n/** A running title without its trailing \"...\": what a stopped or waiting call was doing. */\nexport function withoutEllipsis(title: string): string {\n return title.replace(/(?:\\.{3}|…)\\s*$/u, \"\");\n}\n\n/** How a card shows its call: the status it renders with, and why the call failed when it did. */\nexport interface ToolCardOutcome {\n status: ToolStatus;\n failure: string | null;\n}\n\n/**\n * The card's status. A call the runtime stopped reads as failed with the\n * runtime's reason; a settled call reads as failed when its result reports a\n * failure in the tool's own words (`resultFailure`, as Olympus words it) or\n * the shared classifier reads one. A refusal at the approval gate never gets\n * here: the generic card draws it.\n */\nexport function toolCardOutcome({\n status,\n classification,\n resultFailure = null,\n}: {\n status: ToolCallMessagePartStatus | undefined;\n classification: ToolResultClassification;\n resultFailure?: string | null;\n}): ToolCardOutcome {\n if (status?.type === \"running\") return { status: \"running\", failure: null };\n const classified = classification.state === \"error\" ? classification.failure.message : null;\n const failure = status?.type === \"incomplete\" ? classified : (resultFailure ?? classified);\n if (failure) return { status: \"incomplete\", failure };\n return { status: status?.type ?? \"complete\", failure: null };\n}\n\n/** The asset panel's name for an asset type, when it has one; the panel opens any other as a plain asset. */\nfunction panelAssetType(assetType: string | undefined): AssetType | undefined {\n switch (assetType) {\n case \"presentation\":\n case \"spreadsheet\":\n case \"document\":\n case \"notebook\":\n return assetType;\n default:\n return undefined;\n }\n}\n\nconst ASSET_ICON_TILE = {\n md: { box: \"size-8\", icon: \"size-4\" },\n sm: { box: \"size-6\", icon: \"size-3.5\" },\n} as const;\n\n/**\n * An asset's type icon, as the `@` menu draws it: the host's asset-type SVG\n * when it serves them (`configureAssetIconBasePath`), else the type's Lucide\n * icon on a muted tile. Olympus draws the asset's own thumbnail, which needs\n * the asset read; its type is what a result carries.\n */\nexport function AssetTypeIcon({\n assetType,\n size,\n}: {\n assetType: string | undefined;\n size: keyof typeof ASSET_ICON_TILE;\n}) {\n const tile = ASSET_ICON_TILE[size];\n const thumbnailUrl = assetTypeToThumb(assetType);\n if (thumbnailUrl) {\n return <MentionIcon thumbnailUrl={thumbnailUrl} className={cn(\"shrink-0\", tile.box)} />;\n }\n return (\n <span\n aria-hidden=\"true\"\n className={cn(\n \"flex shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground\",\n tile.box,\n )}\n >\n <MentionIcon fallbackIcon={assetTypeToIcon(assetType)} className={tile.icon} />\n </span>\n );\n}\n\n/**\n * An asset as the chip a chat message draws, opening the asset on click.\n * `title` is the asset's title when the call carried one; without it the\n * chip shows `fallbackLabel` and the asset opens unnamed, for whatever opens\n * it to name.\n */\nexport function AssetChip({\n assetId,\n title,\n fallbackLabel,\n assetType,\n}: {\n assetId: string;\n title?: string;\n fallbackLabel: string;\n assetType?: string;\n}) {\n const openAsset = useAssetPanelStore((s) => s.openAsset);\n const label = title ?? fallbackLabel;\n return (\n <button\n type=\"button\"\n data-asset-id={assetId}\n title={`Open ${label}`}\n onClick={() => openAsset(assetId, { name: title, type: panelAssetType(assetType) })}\n className={cn(CHIP_PILL_CLASS, CHIP_LINK_CLASS, \"max-w-[275px] text-xs\")}\n >\n <MentionIcon\n thumbnailUrl={assetTypeToThumb(assetType)}\n fallbackIcon={assetTypeToIcon(assetType)}\n className={CHIP_ICON_CLASS}\n />\n <span className=\"min-w-0 max-w-[180px] overflow-hidden text-ellipsis\">{label}</span>\n </button>\n );\n}\n\n/** The line under a card's title that finishes its sentence with chips (\"for [project]\"). */\nexport function AssetChipLine({ children }: { children: ReactNode }) {\n return (\n <div className=\"flex flex-wrap items-center gap-1.5 border-t border-border/40 px-4 py-2 text-xs text-muted-foreground\">\n {children}\n </div>\n );\n}\n\n/** The record a tool call's arguments are, or an empty one while they stream. */\nexport function argsRecord(args: unknown): Record<string, unknown> {\n return isRecord(args) ? args : {};\n}\n\n/** A number field of a result record, when it is one. */\nexport function numberField(\n record: Record<string, unknown> | null | undefined,\n key: string,\n): number | undefined {\n const value = record?.[key];\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\n// ─── search_assets ───────────────────────────────────────────────────\n\n/** One match, as the card lists it. */\nexport interface SearchAssetRow {\n id: string;\n title: string;\n /** The type its icon is drawn for (`athena_converted_type`, else `athena_original_type`). */\n assetType: string | undefined;\n creator: string;\n updatedAt: string | undefined;\n workspaceAccess: string | undefined;\n}\n\nexport interface SearchAssetsResult {\n rows: SearchAssetRow[];\n /** `returned_count`: this page's matches. */\n count: number;\n /** The reason a search failed (`error_message`). */\n errorMessage: string | null;\n}\n\nfunction searchAssetCreator(asset: Record<string, unknown>): string {\n const user = isRecord(asset.created_by_user) ? asset.created_by_user : null;\n const fullName = [stringField(user, [\"first_name\"]), stringField(user, [\"last_name\"])]\n .filter(Boolean)\n .join(\" \");\n return stringField(user, [\"email\"]) ?? (fullName || null) ?? stringField(user, [\"id\"]) ?? \"Unknown\";\n}\n\n/** The page of matches agora's `search_assets` returned, or `null` for a result that is not one. */\nexport function readSearchAssetsResult(result: unknown): SearchAssetsResult | null {\n const data = normalizeResult(result);\n if (!data || !Array.isArray(data.assets)) return null;\n const rows = data.assets.flatMap((raw): SearchAssetRow[] => {\n if (!isRecord(raw)) return [];\n const id = stringField(raw, [\"id\"]);\n if (!id) return [];\n return [\n {\n id,\n title: stringField(raw, [\"title\"]) ?? \"Untitled\",\n assetType:\n stringField(raw, [\"athena_converted_type\", \"athena_original_type\", \"asset_type\"]) ??\n undefined,\n creator: searchAssetCreator(raw),\n updatedAt: stringField(raw, [\"updated_at\"]) ?? undefined,\n workspaceAccess: stringField(raw, [\"workspace_access\"]) ?? undefined,\n },\n ];\n });\n return {\n rows,\n count: numberField(data, \"returned_count\") ?? rows.length,\n errorMessage: stringField(data, [\"error_message\"]),\n };\n}\n\nfunction updatedDate(updatedAt: string | undefined): string | null {\n if (!updatedAt) return null;\n const date = new Date(updatedAt);\n return Number.isNaN(date.getTime()) ? null : date.toLocaleDateString();\n}\n\nfunction SearchAssetResultRow({ row, divided }: { row: SearchAssetRow; divided: boolean }) {\n const openAsset = useAssetPanelStore((s) => s.openAsset);\n const updated = updatedDate(row.updatedAt);\n return (\n <li>\n {divided ? <div aria-hidden=\"true\" className=\"ml-11 border-t border-border/60\" /> : null}\n <button\n type=\"button\"\n data-asset-id={row.id}\n onClick={() => openAsset(row.id, { name: row.title, type: panelAssetType(row.assetType) })}\n className=\"flex w-full items-start gap-2 rounded-md px-1 py-3 text-left transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary\"\n >\n <AssetTypeIcon assetType={row.assetType} size=\"md\" />\n <span className=\"flex min-w-0 flex-col gap-0.5\">\n <span className=\"break-words text-[13px] font-medium text-foreground\">{row.title}</span>\n <span className=\"text-[11px] text-muted-foreground\">Created by {row.creator}</span>\n {updated ? (\n <span className=\"text-[11px] text-muted-foreground\">Updated {updated}</span>\n ) : null}\n {row.workspaceAccess ? (\n <span className=\"text-[11px] text-muted-foreground\">{row.workspaceAccess}</span>\n ) : null}\n </span>\n </button>\n </li>\n );\n}\n\nconst SearchAssetsToolUIImpl: ToolCallMessagePartComponent = (props) => {\n const { toolName, args, result, status, isError } = props;\n const classification = classifyToolResult({ status, result, isError });\n // A search refused at the approval gate or parked by the runtime is the\n // generic card's to draw: it is neither a result nor a failure.\n if (classification.state === \"rejected\" || classification.state === \"paused\") {\n return <ToolFallback {...props} icon={SearchIcon} />;\n }\n const typedArgs = argsRecord(args);\n const keyword = stringField(typedArgs, [\"title_contains_keyword\"]);\n const data = readSearchAssetsResult(result);\n const card = toolCardOutcome({\n status,\n classification,\n resultFailure: data?.errorMessage ? `Search failed: ${data.errorMessage}` : null,\n });\n\n const running = keyword ? `Searching assets for \"${keyword}\"...` : \"Searching assets...\";\n const found = data\n ? `Found ${data.count === 1 ? \"1 asset\" : `${data.count} assets`}${keyword ? ` for \"${keyword}\"` : \"\"}`\n : `Search complete${keyword ? ` for \"${keyword}\"` : \"\"}`;\n const title =\n card.status === \"running\" ? running : card.status === \"complete\" ? found : withoutEllipsis(running);\n\n return (\n <ToolCard\n icon={SearchIcon}\n status={card.status}\n title={title}\n toolName={toolName}\n args={typedArgs}\n result={result}\n error={card.failure}\n >\n {card.status === \"complete\" && data && data.rows.length > 0 ? (\n <ExpandableSection label=\"Show assets\">\n <ul className=\"flex flex-col\">\n {data.rows.map((row, index) => (\n <SearchAssetResultRow key={`${row.id}:${index}`} row={row} divided={index > 0} />\n ))}\n </ul>\n </ExpandableSection>\n ) : null}\n </ToolCard>\n );\n};\n\nexport const SearchAssetsToolUI = memo(\n SearchAssetsToolUIImpl,\n) as unknown as ToolCallMessagePartComponent;\nSearchAssetsToolUI.displayName = \"SearchAssetsToolUI\";\n\n// ─── list_contents ───────────────────────────────────────────────────\n\n/** One top-level entry of a listing: its title, and the asset it is when the listing names one. */\nexport interface ListedEntry {\n title: string;\n assetId: string | undefined;\n /** The type its icon is drawn for. */\n assetType: string | undefined;\n}\n\nexport interface ListContentsResult {\n /** `structure_tree_ascii`: the whole tree as text. */\n tree: string | null;\n /** `tree_data`'s top level (this page of it), or `null` when the result has none. */\n entries: ListedEntry[] | null;\n pagination: { currentPage: number; totalPages: number } | null;\n}\n\nconst LISTED_NODE_ID = /(?:^|\\s)id='([^']+)'/;\nconst LISTED_NODE_KIND = /(?:^|\\s)type='([^']+)'/;\nconst LISTED_NODE_MEDIA_TYPE = /(?:^|\\s)media_type='([^']+)'/;\n\n/**\n * One listed node's id, kind (`file` / `folder`) and media type. agora\n * serializes the listing with `default=str`, so a node usually arrives as its\n * pydantic text (`name='Q3' type='folder' id='asset_…' media_type='athena/folder'\n * children={…}`, its own fields ahead of its children's); a node can also\n * arrive as an object.\n */\nfunction readListedNode(raw: unknown): { id?: string; kind?: string; mediaType?: string } {\n if (typeof raw === \"string\") {\n return {\n id: LISTED_NODE_ID.exec(raw)?.[1],\n kind: LISTED_NODE_KIND.exec(raw)?.[1],\n mediaType: LISTED_NODE_MEDIA_TYPE.exec(raw)?.[1],\n };\n }\n if (!isRecord(raw)) return {};\n return {\n id: stringField(raw, [\"id\"]) ?? undefined,\n kind: stringField(raw, [\"type\"]) ?? undefined,\n mediaType: stringField(raw, [\"media_type\"]) ?? undefined,\n };\n}\n\n/** The asset type a listed node's icon is drawn for: an Athena asset's type, a folder, or an upload's kind of file. */\nfunction listedAssetType({ kind, mediaType }: { kind?: string; mediaType?: string }): string | undefined {\n if (mediaType?.startsWith(\"athena/\")) return mediaType.slice(\"athena/\".length);\n if (kind === \"folder\") return \"folder\";\n if (mediaType === \"application/pdf\") return \"pdf\";\n const family = mediaType?.split(\"/\")[0];\n return family === \"image\" || family === \"video\" || family === \"audio\" ? family : undefined;\n}\n\n/** The listing agora's `list_contents` returned, or `null` for a result that is not a record. */\nexport function readListContentsResult(result: unknown): ListContentsResult | null {\n const data = normalizeResult(result);\n if (!data) return null;\n const treeData = isRecord(data.tree_data) ? data.tree_data : null;\n const pagination = isRecord(data.pagination) ? data.pagination : null;\n const currentPage = numberField(pagination, \"current_page\");\n const totalPages = numberField(pagination, \"total_pages\");\n return {\n tree: stringField(data, [\"structure_tree_ascii\"]),\n entries: treeData\n ? Object.entries(treeData).map(([title, raw]) => {\n const node = readListedNode(raw);\n return { title, assetId: node.id, assetType: listedAssetType(node) };\n })\n : null,\n pagination:\n currentPage !== undefined && totalPages !== undefined ? { currentPage, totalPages } : null,\n };\n}\n\nfunction ListedEntryRow({ entry, divided }: { entry: ListedEntry; divided: boolean }) {\n const openAsset = useAssetPanelStore((s) => s.openAsset);\n const { assetId } = entry;\n return (\n <li>\n {divided ? <div aria-hidden=\"true\" className=\"ml-10 border-t border-border/60\" /> : null}\n {assetId ? (\n <button\n type=\"button\"\n data-asset-id={assetId}\n onClick={() =>\n openAsset(assetId, { name: entry.title, type: panelAssetType(entry.assetType) })\n }\n className=\"flex w-full items-center gap-4 rounded-md py-2 text-left transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary\"\n >\n <AssetTypeIcon assetType={entry.assetType} size=\"sm\" />\n <span className=\"min-w-0 truncate text-[13px] font-medium text-foreground\">\n {entry.title}\n </span>\n </button>\n ) : (\n <p className=\"py-1 pl-10 text-[11px] text-muted-foreground\">{entry.title}</p>\n )}\n </li>\n );\n}\n\nconst ListContentsToolUIImpl: ToolCallMessagePartComponent = (props) => {\n const { toolName, args, result, status, isError } = props;\n const classification = classifyToolResult({ status, result, isError });\n if (classification.state === \"rejected\" || classification.state === \"paused\") {\n return <ToolFallback {...props} icon={FolderIcon} />;\n }\n const typedArgs = argsRecord(args);\n // Olympus names the listed asset by its title, read from its asset cache;\n // the call carries only its id, so the card names the workspace alone.\n const target = stringField(typedArgs, [\"asset_id\"]) ? \"\" : \" for workspace\";\n const data = readListContentsResult(result);\n const card = toolCardOutcome({ status, classification });\n\n const running = \"Listing contents...\";\n const listed = data\n ? `Contents listed - Page ${data.pagination?.currentPage ?? 1} of ${data.pagination?.totalPages ?? 1}${target}`\n : `Contents listed${target}`;\n const title =\n card.status === \"running\" ? running : card.status === \"complete\" ? listed : withoutEllipsis(running);\n const entries = data?.entries ?? [];\n const hasListing = Boolean(data && (data.tree || entries.length > 0 || data.pagination));\n\n return (\n <ToolCard\n icon={FolderIcon}\n status={card.status}\n title={title}\n toolName={toolName}\n args={typedArgs}\n result={result}\n error={card.failure}\n >\n {card.status === \"complete\" && data && hasListing ? (\n <ExpandableSection label=\"Show contents\">\n <div className=\"flex flex-col gap-3\">\n {data.tree ? (\n <pre className=\"overflow-x-auto whitespace-pre-wrap rounded bg-muted/50 p-2 text-[11px] leading-4 text-foreground\">\n {data.tree}\n </pre>\n ) : null}\n {entries.length > 0 ? (\n <div className=\"max-h-60 overflow-y-auto pr-0.5\">\n <ul className=\"flex flex-col\">\n {entries.map((entry, index) => (\n <ListedEntryRow\n key={`${entry.title}:${index}`}\n entry={entry}\n divided={index > 0 && entries[index - 1]?.assetId !== undefined}\n />\n ))}\n </ul>\n </div>\n ) : null}\n {data.pagination ? (\n <span className=\"text-[10px] text-muted-foreground\">\n Page {data.pagination.currentPage} of {data.pagination.totalPages}\n </span>\n ) : null}\n </div>\n </ExpandableSection>\n ) : null}\n </ToolCard>\n );\n};\n\nexport const ListContentsToolUI = memo(\n ListContentsToolUIImpl,\n) as unknown as ToolCallMessagePartComponent;\nListContentsToolUI.displayName = \"ListContentsToolUI\";\n\n// ─── project_links ───────────────────────────────────────────────────\n\n/**\n * Streamed or model-written `asset_ids` are not always an array: a single id\n * or a comma-separated string arrives as a string.\n */\nexport function normalizeProjectLinksAssetIds(value: unknown): string[] {\n if (Array.isArray(value)) {\n return value.filter((id): id is string => typeof id === \"string\" && id.length > 0);\n }\n if (typeof value === \"string\") {\n return value\n .split(\",\")\n .map((id) => id.trim())\n .filter((id) => id.length > 0);\n }\n return [];\n}\n\nfunction projectLinksRunningTitle({ operation, count }: { operation: string; count: number }): string {\n const links = `${count} asset link${count !== 1 ? \"s\" : \"\"}`;\n switch (operation) {\n case \"read\":\n return \"Reading project links...\";\n case \"add\":\n return `Adding ${links} to project...`;\n case \"remove\":\n return `Removing ${links} from project...`;\n case \"set\":\n return `Setting ${links} on project...`;\n default:\n return \"Managing project links...\";\n }\n}\n\nconst PROJECT_LINKS_DETAIL_LABEL: Record<string, string> = {\n read: \"Linked\",\n add: \"Added\",\n remove: \"Removed\",\n set: \"Set to\",\n};\n\nconst ProjectLinksToolUIImpl: ToolCallMessagePartComponent = (props) => {\n const { toolName, args, result, status, isError } = props;\n const classification = classifyToolResult({ status, result, isError });\n if (classification.state === \"rejected\" || classification.state === \"paused\") {\n return <ToolFallback {...props} icon={LinkIcon} />;\n }\n const typedArgs = argsRecord(args);\n const operation = stringField(typedArgs, [\"type\"]) ?? \"read\";\n const projectId = stringField(typedArgs, [\"project_id\"]);\n const argAssetIds = normalizeProjectLinksAssetIds(typedArgs.asset_ids);\n const data = normalizeResult(result);\n // Every answer agora writes in prose (\"Project with ID … not found\",\n // \"Error: …\") is a refusal; a change or a read answers in JSON.\n const prose = typeof result === \"string\" && !data ? result.trim() : \"\";\n const card = toolCardOutcome({ status, classification, resultFailure: prose || null });\n\n const assetIds =\n operation === \"read\" && Array.isArray(data?.asset_ids)\n ? normalizeProjectLinksAssetIds(data.asset_ids)\n : argAssetIds;\n const singleAsset = assetIds.length === 1 ? assetIds[0] : undefined;\n const changesOneAsset = singleAsset !== undefined && operation !== \"read\";\n const message = stringField(data, [\"message\"]);\n const projectTitle = stringField(data, [\"project_title\"]) ?? undefined;\n\n const running = projectLinksRunningTitle({ operation, count: argAssetIds.length });\n const title =\n card.status === \"running\"\n ? running\n : card.status === \"complete\"\n ? (message ?? withoutEllipsis(running))\n : withoutEllipsis(running);\n const isDone = card.status === \"complete\";\n const projectChip = projectId ? (\n <AssetChip\n assetId={projectId}\n title={projectTitle}\n fallbackLabel=\"Project\"\n assetType=\"project\"\n />\n ) : null;\n\n return (\n <ToolCard\n icon={LinkIcon}\n status={card.status}\n title={title}\n toolName={toolName}\n args={typedArgs}\n result={result}\n error={card.failure}\n >\n {isDone && changesOneAsset ? (\n <AssetChipLine>\n <AssetChip assetId={singleAsset} fallbackLabel={singleAsset} />\n {projectChip ? (\n <>\n <ArrowRightIcon aria-hidden=\"true\" className=\"size-3.5 shrink-0\" />\n {projectChip}\n </>\n ) : null}\n </AssetChipLine>\n ) : isDone && message && projectChip ? (\n <AssetChipLine>\n <span>on</span>\n {projectChip}\n </AssetChipLine>\n ) : null}\n {isDone && !changesOneAsset && assetIds.length > 0 ? (\n <ExpandableSection label=\"Show assets\">\n <div className=\"flex flex-col\">\n <p className=\"py-1 text-[11px] font-semibold text-muted-foreground\">\n {PROJECT_LINKS_DETAIL_LABEL[operation] ?? operation}\n </p>\n <ul className=\"flex flex-col divide-y divide-border/60\">\n {assetIds.map((assetId, index) => (\n <li key={`${assetId}:${index}`} className=\"py-1\">\n <AssetChip assetId={assetId} fallbackLabel={assetId} />\n </li>\n ))}\n </ul>\n </div>\n </ExpandableSection>\n ) : null}\n </ToolCard>\n );\n};\n\nexport const ProjectLinksToolUI = memo(\n ProjectLinksToolUIImpl,\n) as unknown as ToolCallMessagePartComponent;\nProjectLinksToolUI.displayName = \"ProjectLinksToolUI\";\n"],"names":["assetTypeToThumb","jsx","MentionIcon","cn","assetTypeToIcon","useAssetPanelStore","jsxs","CHIP_PILL_CLASS","CHIP_LINK_CLASS","CHIP_ICON_CLASS","isRecord","stringField","normalizeResult","classifyToolResult","ToolFallback","SearchIcon","ToolCard","ExpandableSection","memo","FolderIcon","_a","LinkIcon","Fragment","ArrowRightIcon"],"mappings":";;;;;;;;;;;;;AA0CO,SAAS,gBAAgB,OAAuB;AACrD,SAAO,MAAM,QAAQ,oBAAoB,EAAE;AAC7C;AAeO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,gBAAgB;AAClB,GAIoB;AAClB,OAAI,iCAAQ,UAAS,UAAW,QAAO,EAAE,QAAQ,WAAW,SAAS,KAAA;AACrE,QAAM,aAAa,eAAe,UAAU,UAAU,eAAe,QAAQ,UAAU;AACvF,QAAM,WAAU,iCAAQ,UAAS,eAAe,aAAc,iBAAiB;AAC/E,MAAI,QAAS,QAAO,EAAE,QAAQ,cAAc,QAAA;AAC5C,SAAO,EAAE,SAAQ,iCAAQ,SAAQ,YAAY,SAAS,KAAA;AACxD;AAGA,SAAS,eAAe,WAAsD;AAC5E,UAAQ,WAAA;AAAA,IACN,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EAAA;AAEb;AAEA,MAAM,kBAAkB;AAAA,EACtB,IAAI,EAAE,KAAK,UAAU,MAAM,SAAA;AAAA,EAC3B,IAAI,EAAE,KAAK,UAAU,MAAM,WAAA;AAC7B;AAQO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AACF,GAGG;AACD,QAAM,OAAO,gBAAgB,IAAI;AACjC,QAAM,eAAeA,eAAAA,iBAAiB,SAAS;AAC/C,MAAI,cAAc;AAChB,WAAOC,2BAAAA,IAACC,2BAAY,cAA4B,WAAWC,OAAAA,GAAG,YAAY,KAAK,GAAG,GAAG;AAAA,EACvF;AACA,SACEF,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,eAAY;AAAA,MACZ,WAAWE,OAAAA;AAAAA,QACT;AAAA,QACA,KAAK;AAAA,MAAA;AAAA,MAGP,UAAAF,2BAAAA,IAACC,YAAAA,eAAY,cAAcE,+BAAgB,SAAS,GAAG,WAAW,KAAK,KAAA,CAAM;AAAA,IAAA;AAAA,EAAA;AAGnF;AAQO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,YAAYC,gBAAAA,mBAAmB,CAAC,MAAM,EAAE,SAAS;AACvD,QAAM,QAAQ,SAAS;AACvB,SACEC,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,iBAAe;AAAA,MACf,OAAO,QAAQ,KAAK;AAAA,MACpB,SAAS,MAAM,UAAU,SAAS,EAAE,MAAM,OAAO,MAAM,eAAe,SAAS,GAAG;AAAA,MAClF,WAAWH,OAAAA,GAAGI,6BAAiBC,YAAAA,iBAAiB,uBAAuB;AAAA,MAEvE,UAAA;AAAA,QAAAP,2BAAAA;AAAAA,UAACC,YAAAA;AAAAA,UAAA;AAAA,YACC,cAAcF,eAAAA,iBAAiB,SAAS;AAAA,YACxC,cAAcI,eAAAA,gBAAgB,SAAS;AAAA,YACvC,WAAWK,YAAAA;AAAAA,UAAA;AAAA,QAAA;AAAA,QAEbR,2BAAAA,IAAC,QAAA,EAAK,WAAU,uDAAuD,UAAA,MAAA,CAAM;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGnF;AAGO,SAAS,cAAc,EAAE,YAAqC;AACnE,SACEA,2BAAAA,IAAC,OAAA,EAAI,WAAU,yGACZ,SAAA,CACH;AAEJ;AAGO,SAAS,WAAW,MAAwC;AACjE,SAAOS,oBAAS,IAAI,IAAI,OAAO,CAAA;AACjC;AAGO,SAAS,YACd,QACA,KACoB;AACpB,QAAM,QAAQ,iCAAS;AACvB,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE;AAuBA,SAAS,mBAAmB,OAAwC;AAClE,QAAM,OAAOA,WAAAA,SAAS,MAAM,eAAe,IAAI,MAAM,kBAAkB;AACvE,QAAM,WAAW,CAACC,WAAAA,YAAY,MAAM,CAAC,YAAY,CAAC,GAAGA,WAAAA,YAAY,MAAM,CAAC,WAAW,CAAC,CAAC,EAClF,OAAO,OAAO,EACd,KAAK,GAAG;AACX,SAAOA,WAAAA,YAAY,MAAM,CAAC,OAAO,CAAC,MAAM,YAAY,SAASA,WAAAA,YAAY,MAAM,CAAC,IAAI,CAAC,KAAK;AAC5F;AAGO,SAAS,uBAAuB,QAA4C;AACjF,QAAM,OAAOC,WAAAA,gBAAgB,MAAM;AACnC,MAAI,CAAC,QAAQ,CAAC,MAAM,QAAQ,KAAK,MAAM,EAAG,QAAO;AACjD,QAAM,OAAO,KAAK,OAAO,QAAQ,CAAC,QAA0B;AAC1D,QAAI,CAACF,WAAAA,SAAS,GAAG,UAAU,CAAA;AAC3B,UAAM,KAAKC,WAAAA,YAAY,KAAK,CAAC,IAAI,CAAC;AAClC,QAAI,CAAC,GAAI,QAAO,CAAA;AAChB,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,OAAOA,WAAAA,YAAY,KAAK,CAAC,OAAO,CAAC,KAAK;AAAA,QACtC,WACEA,WAAAA,YAAY,KAAK,CAAC,yBAAyB,wBAAwB,YAAY,CAAC,KAChF;AAAA,QACF,SAAS,mBAAmB,GAAG;AAAA,QAC/B,WAAWA,WAAAA,YAAY,KAAK,CAAC,YAAY,CAAC,KAAK;AAAA,QAC/C,iBAAiBA,WAAAA,YAAY,KAAK,CAAC,kBAAkB,CAAC,KAAK;AAAA,MAAA;AAAA,IAC7D;AAAA,EAEJ,CAAC;AACD,SAAO;AAAA,IACL;AAAA,IACA,OAAO,YAAY,MAAM,gBAAgB,KAAK,KAAK;AAAA,IACnD,cAAcA,WAAAA,YAAY,MAAM,CAAC,eAAe,CAAC;AAAA,EAAA;AAErD;AAEA,SAAS,YAAY,WAA8C;AACjE,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,OAAO,IAAI,KAAK,SAAS;AAC/B,SAAO,OAAO,MAAM,KAAK,QAAA,CAAS,IAAI,OAAO,KAAK,mBAAA;AACpD;AAEA,SAAS,qBAAqB,EAAE,KAAK,WAAsD;AACzF,QAAM,YAAYN,gBAAAA,mBAAmB,CAAC,MAAM,EAAE,SAAS;AACvD,QAAM,UAAU,YAAY,IAAI,SAAS;AACzC,yCACG,MAAA,EACE,UAAA;AAAA,IAAA,yCAAW,OAAA,EAAI,eAAY,QAAO,WAAU,mCAAkC,IAAK;AAAA,IACpFC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,iBAAe,IAAI;AAAA,QACnB,SAAS,MAAM,UAAU,IAAI,IAAI,EAAE,MAAM,IAAI,OAAO,MAAM,eAAe,IAAI,SAAS,GAAG;AAAA,QACzF,WAAU;AAAA,QAEV,UAAA;AAAA,UAAAL,2BAAAA,IAAC,eAAA,EAAc,WAAW,IAAI,WAAW,MAAK,MAAK;AAAA,UACnDK,2BAAAA,KAAC,QAAA,EAAK,WAAU,iCACd,UAAA;AAAA,YAAAL,2BAAAA,IAAC,QAAA,EAAK,WAAU,uDAAuD,UAAA,IAAI,OAAM;AAAA,YACjFK,2BAAAA,KAAC,QAAA,EAAK,WAAU,qCAAoC,UAAA;AAAA,cAAA;AAAA,cAAY,IAAI;AAAA,YAAA,GAAQ;AAAA,YAC3E,UACCA,2BAAAA,KAAC,QAAA,EAAK,WAAU,qCAAoC,UAAA;AAAA,cAAA;AAAA,cAAS;AAAA,YAAA,EAAA,CAAQ,IACnE;AAAA,YACH,IAAI,kBACHL,+BAAC,QAAA,EAAK,WAAU,qCAAqC,UAAA,IAAI,iBAAgB,IACvE;AAAA,UAAA,EAAA,CACN;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EACF,GACF;AAEJ;AAEA,MAAM,yBAAuD,CAAC,UAAU;AACtE,QAAM,EAAE,UAAU,MAAM,QAAQ,QAAQ,YAAY;AACpD,QAAM,iBAAiBY,WAAAA,mBAAmB,EAAE,QAAQ,QAAQ,SAAS;AAGrE,MAAI,eAAe,UAAU,cAAc,eAAe,UAAU,UAAU;AAC5E,WAAOZ,2BAAAA,IAACa,aAAAA,cAAA,EAAc,GAAG,OAAO,MAAMC,YAAAA,YAAY;AAAA,EACpD;AACA,QAAM,YAAY,WAAW,IAAI;AACjC,QAAM,UAAUJ,WAAAA,YAAY,WAAW,CAAC,wBAAwB,CAAC;AACjE,QAAM,OAAO,uBAAuB,MAAM;AAC1C,QAAM,OAAO,gBAAgB;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,gBAAe,6BAAM,gBAAe,kBAAkB,KAAK,YAAY,KAAK;AAAA,EAAA,CAC7E;AAED,QAAM,UAAU,UAAU,yBAAyB,OAAO,SAAS;AACnE,QAAM,QAAQ,OACV,SAAS,KAAK,UAAU,IAAI,YAAY,GAAG,KAAK,KAAK,SAAS,GAAG,UAAU,SAAS,OAAO,MAAM,EAAE,KACnG,kBAAkB,UAAU,SAAS,OAAO,MAAM,EAAE;AACxD,QAAM,QACJ,KAAK,WAAW,YAAY,UAAU,KAAK,WAAW,aAAa,QAAQ,gBAAgB,OAAO;AAEpG,SACEV,2BAAAA;AAAAA,IAACe,WAAAA;AAAAA,IAAA;AAAA,MACC,MAAMD,YAAAA;AAAAA,MACN,QAAQ,KAAK;AAAA,MACb;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,OAAO,KAAK;AAAA,MAEX,eAAK,WAAW,cAAc,QAAQ,KAAK,KAAK,SAAS,IACxDd,2BAAAA,IAACgB,WAAAA,mBAAA,EAAkB,OAAM,eACvB,UAAAhB,2BAAAA,IAAC,MAAA,EAAG,WAAU,iBACX,UAAA,KAAK,KAAK,IAAI,CAAC,KAAK,UACnBA,2BAAAA,IAAC,sBAAA,EAAgD,KAAU,SAAS,QAAQ,EAAA,GAAjD,GAAG,IAAI,EAAE,IAAI,KAAK,EAAkC,CAChF,GACH,GACF,IACE;AAAA,IAAA;AAAA,EAAA;AAGV;AAEO,MAAM,qBAAqBiB,WAAAA;AAAAA,EAChC;AACF;AACA,mBAAmB,cAAc;AAoBjC,MAAM,iBAAiB;AACvB,MAAM,mBAAmB;AACzB,MAAM,yBAAyB;AAS/B,SAAS,eAAe,KAAkE;;AACxF,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO;AAAA,MACL,KAAI,oBAAe,KAAK,GAAG,MAAvB,mBAA2B;AAAA,MAC/B,OAAM,sBAAiB,KAAK,GAAG,MAAzB,mBAA6B;AAAA,MACnC,YAAW,4BAAuB,KAAK,GAAG,MAA/B,mBAAmC;AAAA,IAAC;AAAA,EAEnD;AACA,MAAI,CAACR,WAAAA,SAAS,GAAG,UAAU,CAAA;AAC3B,SAAO;AAAA,IACL,IAAIC,WAAAA,YAAY,KAAK,CAAC,IAAI,CAAC,KAAK;AAAA,IAChC,MAAMA,WAAAA,YAAY,KAAK,CAAC,MAAM,CAAC,KAAK;AAAA,IACpC,WAAWA,WAAAA,YAAY,KAAK,CAAC,YAAY,CAAC,KAAK;AAAA,EAAA;AAEnD;AAGA,SAAS,gBAAgB,EAAE,MAAM,aAAwE;AACvG,MAAI,uCAAW,WAAW,mBAAmB,UAAU,MAAM,UAAU,MAAM;AAC7E,MAAI,SAAS,SAAU,QAAO;AAC9B,MAAI,cAAc,kBAAmB,QAAO;AAC5C,QAAM,SAAS,uCAAW,MAAM,KAAK;AACrC,SAAO,WAAW,WAAW,WAAW,WAAW,WAAW,UAAU,SAAS;AACnF;AAGO,SAAS,uBAAuB,QAA4C;AACjF,QAAM,OAAOC,WAAAA,gBAAgB,MAAM;AACnC,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,WAAWF,WAAAA,SAAS,KAAK,SAAS,IAAI,KAAK,YAAY;AAC7D,QAAM,aAAaA,WAAAA,SAAS,KAAK,UAAU,IAAI,KAAK,aAAa;AACjE,QAAM,cAAc,YAAY,YAAY,cAAc;AAC1D,QAAM,aAAa,YAAY,YAAY,aAAa;AACxD,SAAO;AAAA,IACL,MAAMC,WAAAA,YAAY,MAAM,CAAC,sBAAsB,CAAC;AAAA,IAChD,SAAS,WACL,OAAO,QAAQ,QAAQ,EAAE,IAAI,CAAC,CAAC,OAAO,GAAG,MAAM;AAC7C,YAAM,OAAO,eAAe,GAAG;AAC/B,aAAO,EAAE,OAAO,SAAS,KAAK,IAAI,WAAW,gBAAgB,IAAI,EAAA;AAAA,IACnE,CAAC,IACD;AAAA,IACJ,YACE,gBAAgB,UAAa,eAAe,SAAY,EAAE,aAAa,eAAe;AAAA,EAAA;AAE5F;AAEA,SAAS,eAAe,EAAE,OAAO,WAAqD;AACpF,QAAM,YAAYN,gBAAAA,mBAAmB,CAAC,MAAM,EAAE,SAAS;AACvD,QAAM,EAAE,YAAY;AACpB,yCACG,MAAA,EACE,UAAA;AAAA,IAAA,yCAAW,OAAA,EAAI,eAAY,QAAO,WAAU,mCAAkC,IAAK;AAAA,IACnF,UACCC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,iBAAe;AAAA,QACf,SAAS,MACP,UAAU,SAAS,EAAE,MAAM,MAAM,OAAO,MAAM,eAAe,MAAM,SAAS,GAAG;AAAA,QAEjF,WAAU;AAAA,QAEV,UAAA;AAAA,UAAAL,2BAAAA,IAAC,eAAA,EAAc,WAAW,MAAM,WAAW,MAAK,MAAK;AAAA,UACrDA,2BAAAA,IAAC,QAAA,EAAK,WAAU,4DACb,gBAAM,MAAA,CACT;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA,IAGFA,2BAAAA,IAAC,KAAA,EAAE,WAAU,gDAAgD,gBAAM,MAAA,CAAM;AAAA,EAAA,GAE7E;AAEJ;AAEA,MAAM,yBAAuD,CAAC,UAAU;;AACtE,QAAM,EAAE,UAAU,MAAM,QAAQ,QAAQ,YAAY;AACpD,QAAM,iBAAiBY,WAAAA,mBAAmB,EAAE,QAAQ,QAAQ,SAAS;AACrE,MAAI,eAAe,UAAU,cAAc,eAAe,UAAU,UAAU;AAC5E,WAAOZ,2BAAAA,IAACa,aAAAA,cAAA,EAAc,GAAG,OAAO,MAAMK,YAAAA,YAAY;AAAA,EACpD;AACA,QAAM,YAAY,WAAW,IAAI;AAGjC,QAAM,SAASR,WAAAA,YAAY,WAAW,CAAC,UAAU,CAAC,IAAI,KAAK;AAC3D,QAAM,OAAO,uBAAuB,MAAM;AAC1C,QAAM,OAAO,gBAAgB,EAAE,QAAQ,gBAAgB;AAEvD,QAAM,UAAU;AAChB,QAAM,SAAS,OACX,4BAA0B,UAAK,eAAL,mBAAiB,gBAAe,CAAC,SAAO,UAAK,eAAL,mBAAiB,eAAc,CAAC,GAAG,MAAM,KAC3G,kBAAkB,MAAM;AAC5B,QAAM,QACJ,KAAK,WAAW,YAAY,UAAU,KAAK,WAAW,aAAa,SAAS,gBAAgB,OAAO;AACrG,QAAM,WAAU,6BAAM,YAAW,CAAA;AACjC,QAAM,aAAa,QAAQ,SAAS,KAAK,QAAQ,QAAQ,SAAS,KAAK,KAAK,WAAW;AAEvF,SACEV,2BAAAA;AAAAA,IAACe,WAAAA;AAAAA,IAAA;AAAA,MACC,MAAMG,YAAAA;AAAAA,MACN,QAAQ,KAAK;AAAA,MACb;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,OAAO,KAAK;AAAA,MAEX,UAAA,KAAK,WAAW,cAAc,QAAQ,aACrClB,2BAAAA,IAACgB,WAAAA,mBAAA,EAAkB,OAAM,iBACvB,UAAAX,2BAAAA,KAAC,OAAA,EAAI,WAAU,uBACZ,UAAA;AAAA,QAAA,KAAK,OACJL,+BAAC,OAAA,EAAI,WAAU,qGACZ,UAAA,KAAK,MACR,IACE;AAAA,QACH,QAAQ,SAAS,IAChBA,2BAAAA,IAAC,SAAI,WAAU,mCACb,UAAAA,2BAAAA,IAAC,MAAA,EAAG,WAAU,iBACX,UAAA,QAAQ,IAAI,CAAC,OAAO;;AACnBA,4CAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cAEC;AAAA,cACA,SAAS,QAAQ,OAAKmB,MAAA,QAAQ,QAAQ,CAAC,MAAjB,gBAAAA,IAAoB,aAAY;AAAA,YAAA;AAAA,YAFjD,GAAG,MAAM,KAAK,IAAI,KAAK;AAAA,UAAA;AAAA,SAI/B,EAAA,CACH,EAAA,CACF,IACE;AAAA,QACH,KAAK,aACJd,gCAAC,QAAA,EAAK,WAAU,qCAAoC,UAAA;AAAA,UAAA;AAAA,UAC5C,KAAK,WAAW;AAAA,UAAY;AAAA,UAAK,KAAK,WAAW;AAAA,QAAA,EAAA,CACzD,IACE;AAAA,MAAA,EAAA,CACN,GACF,IACE;AAAA,IAAA;AAAA,EAAA;AAGV;AAEO,MAAM,qBAAqBY,WAAAA;AAAAA,EAChC;AACF;AACA,mBAAmB,cAAc;AAQ1B,SAAS,8BAA8B,OAA0B;AACtE,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM,OAAO,CAAC,OAAqB,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC;AAAA,EACnF;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,MACJ,MAAM,GAAG,EACT,IAAI,CAAC,OAAO,GAAG,KAAA,CAAM,EACrB,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;AAAA,EACjC;AACA,SAAO,CAAA;AACT;AAEA,SAAS,yBAAyB,EAAE,WAAW,SAAuD;AACpG,QAAM,QAAQ,GAAG,KAAK,cAAc,UAAU,IAAI,MAAM,EAAE;AAC1D,UAAQ,WAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,UAAU,KAAK;AAAA,IACxB,KAAK;AACH,aAAO,YAAY,KAAK;AAAA,IAC1B,KAAK;AACH,aAAO,WAAW,KAAK;AAAA,IACzB;AACE,aAAO;AAAA,EAAA;AAEb;AAEA,MAAM,6BAAqD;AAAA,EACzD,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,KAAK;AACP;AAEA,MAAM,yBAAuD,CAAC,UAAU;AACtE,QAAM,EAAE,UAAU,MAAM,QAAQ,QAAQ,YAAY;AACpD,QAAM,iBAAiBL,WAAAA,mBAAmB,EAAE,QAAQ,QAAQ,SAAS;AACrE,MAAI,eAAe,UAAU,cAAc,eAAe,UAAU,UAAU;AAC5E,WAAOZ,2BAAAA,IAACa,aAAAA,cAAA,EAAc,GAAG,OAAO,MAAMO,YAAAA,UAAU;AAAA,EAClD;AACA,QAAM,YAAY,WAAW,IAAI;AACjC,QAAM,YAAYV,WAAAA,YAAY,WAAW,CAAC,MAAM,CAAC,KAAK;AACtD,QAAM,YAAYA,WAAAA,YAAY,WAAW,CAAC,YAAY,CAAC;AACvD,QAAM,cAAc,8BAA8B,UAAU,SAAS;AACrE,QAAM,OAAOC,WAAAA,gBAAgB,MAAM;AAGnC,QAAM,QAAQ,OAAO,WAAW,YAAY,CAAC,OAAO,OAAO,SAAS;AACpE,QAAM,OAAO,gBAAgB,EAAE,QAAQ,gBAAgB,eAAe,SAAS,MAAM;AAErF,QAAM,WACJ,cAAc,UAAU,MAAM,QAAQ,6BAAM,SAAS,IACjD,8BAA8B,KAAK,SAAS,IAC5C;AACN,QAAM,cAAc,SAAS,WAAW,IAAI,SAAS,CAAC,IAAI;AAC1D,QAAM,kBAAkB,gBAAgB,UAAa,cAAc;AACnE,QAAM,UAAUD,WAAAA,YAAY,MAAM,CAAC,SAAS,CAAC;AAC7C,QAAM,eAAeA,WAAAA,YAAY,MAAM,CAAC,eAAe,CAAC,KAAK;AAE7D,QAAM,UAAU,yBAAyB,EAAE,WAAW,OAAO,YAAY,QAAQ;AACjF,QAAM,QACJ,KAAK,WAAW,YACZ,UACA,KAAK,WAAW,aACb,WAAW,gBAAgB,OAAO,IACnC,gBAAgB,OAAO;AAC/B,QAAM,SAAS,KAAK,WAAW;AAC/B,QAAM,cAAc,YAClBV,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,SAAS;AAAA,MACT,OAAO;AAAA,MACP,eAAc;AAAA,MACd,WAAU;AAAA,IAAA;AAAA,EAAA,IAEV;AAEJ,SACEK,2BAAAA;AAAAA,IAACU,WAAAA;AAAAA,IAAA;AAAA,MACC,MAAMK,YAAAA;AAAAA,MACN,QAAQ,KAAK;AAAA,MACb;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,OAAO,KAAK;AAAA,MAEX,UAAA;AAAA,QAAA,UAAU,kDACR,eAAA,EACC,UAAA;AAAA,UAAApB,2BAAAA,IAAC,WAAA,EAAU,SAAS,aAAa,eAAe,aAAa;AAAA,UAC5D,cACCK,2BAAAA,KAAAgB,qBAAA,EACE,UAAA;AAAA,YAAArB,2BAAAA,IAACsB,YAAAA,gBAAA,EAAe,eAAY,QAAO,WAAU,qBAAoB;AAAA,YAChE;AAAA,UAAA,EAAA,CACH,IACE;AAAA,QAAA,EAAA,CACN,IACE,UAAU,WAAW,8CACtB,eAAA,EACC,UAAA;AAAA,UAAAtB,2BAAAA,IAAC,UAAK,UAAA,KAAA,CAAE;AAAA,UACP;AAAA,QAAA,EAAA,CACH,IACE;AAAA,QACH,UAAU,CAAC,mBAAmB,SAAS,SAAS,IAC/CA,2BAAAA,IAACgB,8BAAA,EAAkB,OAAM,eACvB,UAAAX,gCAAC,OAAA,EAAI,WAAU,iBACb,UAAA;AAAA,UAAAL,+BAAC,OAAE,WAAU,wDACV,UAAA,2BAA2B,SAAS,KAAK,WAC5C;AAAA,UACAA,2BAAAA,IAAC,MAAA,EAAG,WAAU,2CACX,UAAA,SAAS,IAAI,CAAC,SAAS,UACtBA,2BAAAA,IAAC,MAAA,EAA+B,WAAU,QACxC,UAAAA,2BAAAA,IAAC,WAAA,EAAU,SAAkB,eAAe,QAAA,CAAS,KAD9C,GAAG,OAAO,IAAI,KAAK,EAE5B,CACD,EAAA,CACH;AAAA,QAAA,EAAA,CACF,GACF,IACE;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGV;AAEO,MAAM,qBAAqBiB,WAAAA;AAAAA,EAChC;AACF;AACA,mBAAmB,cAAc;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"drive-tool-uis.cjs","sources":["../../src/tools/drive-tool-uis.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * The Athena Drive cards, as Athena on the web draws them: `search_assets`\n * (the matches, each opening its asset), `list_contents` (a folder's tree and\n * the assets in it) and `project_links` (a project's links as asset chips).\n *\n * Olympus reads each asset's title and thumbnail from its asset cache; these\n * cards draw only what the call's arguments and result carry. An asset shows\n * its type's icon when the result names its type, and an asset the result\n * names by id alone shows its id.\n */\nimport type {\n ToolCallMessagePartComponent,\n ToolCallMessagePartStatus,\n} from \"@assistant-ui/react\";\nimport {\n classifyToolResult,\n isRecord,\n stringField,\n type ToolResultClassification,\n} from \"@athenaintel/agent-runtime\";\nimport { ArrowRightIcon, FolderIcon, LinkIcon, SearchIcon } from \"lucide-react\";\nimport { memo, type ReactNode } from \"react\";\nimport { type AssetType, useAssetPanelStore } from \"../assets/asset-panel-store\";\nimport {\n CHIP_ICON_CLASS,\n CHIP_LINK_CLASS,\n CHIP_PILL_CLASS,\n} from \"../chat-ui/mentions/mention-chip\";\nimport {\n MentionIcon,\n useThumbnailLoadFailure,\n} from \"../chat-ui/mentions/suggestions/components/mention-icon\";\nimport { useAssetIconAppUrl } from \"../chat-ui/mentions/use-asset-icon-app-url\";\nimport {\n assetTypeToIcon,\n assetTypeToThumb,\n} from \"../chat-ui/mentions/suggestions/data/sources/asset-type-icons\";\nimport { cn } from \"../lib/utils\";\nimport { ExpandableSection, normalizeResult, ToolCard, type ToolStatus } from \"./primitives\";\nimport { ToolFallback } from \"./tool-fallback\";\n\n// ─── Shared by the Drive and project manager cards ───────────────────\n\n/** A running title without its trailing \"...\": what a stopped or waiting call was doing. */\nexport function withoutEllipsis(title: string): string {\n return title.replace(/(?:\\.{3}|…)\\s*$/u, \"\");\n}\n\n/** How a card shows its call: the status it renders with, and why the call failed when it did. */\nexport interface ToolCardOutcome {\n status: ToolStatus;\n failure: string | null;\n}\n\n/**\n * The card's status. A call the runtime stopped reads as failed with the\n * runtime's reason; a settled call reads as failed when its result reports a\n * failure in the tool's own words (`resultFailure`, as Olympus words it) or\n * the shared classifier reads one. A refusal at the approval gate never gets\n * here: the generic card draws it.\n */\nexport function toolCardOutcome({\n status,\n classification,\n resultFailure = null,\n}: {\n status: ToolCallMessagePartStatus | undefined;\n classification: ToolResultClassification;\n resultFailure?: string | null;\n}): ToolCardOutcome {\n if (status?.type === \"running\") return { status: \"running\", failure: null };\n const classified = classification.state === \"error\" ? classification.failure.message : null;\n const failure = status?.type === \"incomplete\" ? classified : (resultFailure ?? classified);\n if (failure) return { status: \"incomplete\", failure };\n return { status: status?.type ?? \"complete\", failure: null };\n}\n\n/** The asset panel's name for an asset type, when it has one; the panel opens any other as a plain asset. */\nfunction panelAssetType(assetType: string | undefined): AssetType | undefined {\n switch (assetType) {\n case \"presentation\":\n case \"spreadsheet\":\n case \"document\":\n case \"notebook\":\n return assetType;\n default:\n return undefined;\n }\n}\n\nconst ASSET_ICON_TILE = {\n md: { box: \"size-8\", icon: \"size-4\" },\n sm: { box: \"size-6\", icon: \"size-3.5\" },\n} as const;\n\n/**\n * An asset's type icon, as the `@` menu draws it: the asset-type SVG Olympus\n * draws (`assetTypeToThumb`: the host's copy, else the chat's Athena web app's), or\n * the type's Lucide icon on a muted tile when there is none or it cannot load.\n * Olympus draws the asset's own thumbnail, which needs the asset read; its\n * type is what a result carries.\n */\nexport function AssetTypeIcon({\n assetType,\n size,\n}: {\n assetType: string | undefined;\n size: keyof typeof ASSET_ICON_TILE;\n}) {\n const tile = ASSET_ICON_TILE[size];\n const iconAppUrl = useAssetIconAppUrl();\n const thumbnailUrl = assetTypeToThumb(assetType, { appUrl: iconAppUrl });\n const thumbnail = useThumbnailLoadFailure(thumbnailUrl);\n if (thumbnailUrl && !thumbnail.failed) {\n return (\n <img ref={thumbnail.imageRef} src={thumbnailUrl} alt=\"\" className={cn(\"shrink-0\", tile.box)} />\n );\n }\n return (\n <span\n aria-hidden=\"true\"\n className={cn(\n \"flex shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground\",\n tile.box,\n )}\n >\n <MentionIcon fallbackIcon={assetTypeToIcon(assetType)} className={tile.icon} />\n </span>\n );\n}\n\n/**\n * An asset as the chip a chat message draws, opening the asset on click.\n * `title` is the asset's title when the call carried one; without it the\n * chip shows `fallbackLabel` and the asset opens unnamed, for whatever opens\n * it to name.\n */\nexport function AssetChip({\n assetId,\n title,\n fallbackLabel,\n assetType,\n}: {\n assetId: string;\n title?: string;\n fallbackLabel: string;\n assetType?: string;\n}) {\n const openAsset = useAssetPanelStore((s) => s.openAsset);\n const iconAppUrl = useAssetIconAppUrl();\n const label = title ?? fallbackLabel;\n return (\n <button\n type=\"button\"\n data-asset-id={assetId}\n title={`Open ${label}`}\n onClick={() => openAsset(assetId, { name: title, type: panelAssetType(assetType) })}\n className={cn(CHIP_PILL_CLASS, CHIP_LINK_CLASS, \"max-w-[275px] text-xs\")}\n >\n <MentionIcon\n thumbnailUrl={assetTypeToThumb(assetType, { appUrl: iconAppUrl })}\n fallbackIcon={assetTypeToIcon(assetType)}\n className={CHIP_ICON_CLASS}\n />\n <span className=\"min-w-0 max-w-[180px] overflow-hidden text-ellipsis\">{label}</span>\n </button>\n );\n}\n\n/** The line under a card's title that finishes its sentence with chips (\"for [project]\"). */\nexport function AssetChipLine({ children }: { children: ReactNode }) {\n return (\n <div className=\"flex flex-wrap items-center gap-1.5 border-t border-border/40 px-4 py-2 text-xs text-muted-foreground\">\n {children}\n </div>\n );\n}\n\n/** The record a tool call's arguments are, or an empty one while they stream. */\nexport function argsRecord(args: unknown): Record<string, unknown> {\n return isRecord(args) ? args : {};\n}\n\n/** A number field of a result record, when it is one. */\nexport function numberField(\n record: Record<string, unknown> | null | undefined,\n key: string,\n): number | undefined {\n const value = record?.[key];\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\n// ─── search_assets ───────────────────────────────────────────────────\n\n/** One match, as the card lists it. */\nexport interface SearchAssetRow {\n id: string;\n title: string;\n /** The type its icon is drawn for (`athena_converted_type`, else `athena_original_type`). */\n assetType: string | undefined;\n creator: string;\n updatedAt: string | undefined;\n workspaceAccess: string | undefined;\n}\n\nexport interface SearchAssetsResult {\n rows: SearchAssetRow[];\n /** `returned_count`: this page's matches. */\n count: number;\n /** The reason a search failed (`error_message`). */\n errorMessage: string | null;\n}\n\nfunction searchAssetCreator(asset: Record<string, unknown>): string {\n const user = isRecord(asset.created_by_user) ? asset.created_by_user : null;\n const fullName = [stringField(user, [\"first_name\"]), stringField(user, [\"last_name\"])]\n .filter(Boolean)\n .join(\" \");\n return stringField(user, [\"email\"]) ?? (fullName || null) ?? stringField(user, [\"id\"]) ?? \"Unknown\";\n}\n\n/** The page of matches agora's `search_assets` returned, or `null` for a result that is not one. */\nexport function readSearchAssetsResult(result: unknown): SearchAssetsResult | null {\n const data = normalizeResult(result);\n if (!data || !Array.isArray(data.assets)) return null;\n const rows = data.assets.flatMap((raw): SearchAssetRow[] => {\n if (!isRecord(raw)) return [];\n const id = stringField(raw, [\"id\"]);\n if (!id) return [];\n return [\n {\n id,\n title: stringField(raw, [\"title\"]) ?? \"Untitled\",\n assetType:\n stringField(raw, [\"athena_converted_type\", \"athena_original_type\", \"asset_type\"]) ??\n undefined,\n creator: searchAssetCreator(raw),\n updatedAt: stringField(raw, [\"updated_at\"]) ?? undefined,\n workspaceAccess: stringField(raw, [\"workspace_access\"]) ?? undefined,\n },\n ];\n });\n return {\n rows,\n count: numberField(data, \"returned_count\") ?? rows.length,\n errorMessage: stringField(data, [\"error_message\"]),\n };\n}\n\nfunction updatedDate(updatedAt: string | undefined): string | null {\n if (!updatedAt) return null;\n const date = new Date(updatedAt);\n return Number.isNaN(date.getTime()) ? null : date.toLocaleDateString();\n}\n\nfunction SearchAssetResultRow({ row, divided }: { row: SearchAssetRow; divided: boolean }) {\n const openAsset = useAssetPanelStore((s) => s.openAsset);\n const updated = updatedDate(row.updatedAt);\n return (\n <li>\n {divided ? <div aria-hidden=\"true\" className=\"ml-11 border-t border-border/60\" /> : null}\n <button\n type=\"button\"\n data-asset-id={row.id}\n onClick={() => openAsset(row.id, { name: row.title, type: panelAssetType(row.assetType) })}\n className=\"flex w-full items-start gap-2 rounded-md px-1 py-3 text-left transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary\"\n >\n <AssetTypeIcon assetType={row.assetType} size=\"md\" />\n <span className=\"flex min-w-0 flex-col gap-0.5\">\n <span className=\"break-words text-[13px] font-medium text-foreground\">{row.title}</span>\n <span className=\"text-[11px] text-muted-foreground\">Created by {row.creator}</span>\n {updated ? (\n <span className=\"text-[11px] text-muted-foreground\">Updated {updated}</span>\n ) : null}\n {row.workspaceAccess ? (\n <span className=\"text-[11px] text-muted-foreground\">{row.workspaceAccess}</span>\n ) : null}\n </span>\n </button>\n </li>\n );\n}\n\nconst SearchAssetsToolUIImpl: ToolCallMessagePartComponent = (props) => {\n const { toolName, args, result, status, isError } = props;\n const classification = classifyToolResult({ status, result, isError });\n // A search refused at the approval gate or parked by the runtime is the\n // generic card's to draw: it is neither a result nor a failure.\n if (classification.state === \"rejected\" || classification.state === \"paused\") {\n return <ToolFallback {...props} icon={SearchIcon} />;\n }\n const typedArgs = argsRecord(args);\n const keyword = stringField(typedArgs, [\"title_contains_keyword\"]);\n const data = readSearchAssetsResult(result);\n const card = toolCardOutcome({\n status,\n classification,\n resultFailure: data?.errorMessage ? `Search failed: ${data.errorMessage}` : null,\n });\n\n const running = keyword ? `Searching assets for \"${keyword}\"...` : \"Searching assets...\";\n const found = data\n ? `Found ${data.count === 1 ? \"1 asset\" : `${data.count} assets`}${keyword ? ` for \"${keyword}\"` : \"\"}`\n : `Search complete${keyword ? ` for \"${keyword}\"` : \"\"}`;\n const title =\n card.status === \"running\" ? running : card.status === \"complete\" ? found : withoutEllipsis(running);\n\n return (\n <ToolCard\n icon={SearchIcon}\n status={card.status}\n title={title}\n toolName={toolName}\n args={typedArgs}\n result={result}\n error={card.failure}\n >\n {card.status === \"complete\" && data && data.rows.length > 0 ? (\n <ExpandableSection label=\"Show assets\">\n <ul className=\"flex flex-col\">\n {data.rows.map((row, index) => (\n <SearchAssetResultRow key={`${row.id}:${index}`} row={row} divided={index > 0} />\n ))}\n </ul>\n </ExpandableSection>\n ) : null}\n </ToolCard>\n );\n};\n\nexport const SearchAssetsToolUI = memo(\n SearchAssetsToolUIImpl,\n) as unknown as ToolCallMessagePartComponent;\nSearchAssetsToolUI.displayName = \"SearchAssetsToolUI\";\n\n// ─── list_contents ───────────────────────────────────────────────────\n\n/** One top-level entry of a listing: its title, and the asset it is when the listing names one. */\nexport interface ListedEntry {\n title: string;\n assetId: string | undefined;\n /** The type its icon is drawn for. */\n assetType: string | undefined;\n}\n\nexport interface ListContentsResult {\n /** `structure_tree_ascii`: the whole tree as text. */\n tree: string | null;\n /** `tree_data`'s top level (this page of it), or `null` when the result has none. */\n entries: ListedEntry[] | null;\n pagination: { currentPage: number; totalPages: number } | null;\n}\n\nconst LISTED_NODE_ID = /(?:^|\\s)id='([^']+)'/;\nconst LISTED_NODE_KIND = /(?:^|\\s)type='([^']+)'/;\nconst LISTED_NODE_MEDIA_TYPE = /(?:^|\\s)media_type='([^']+)'/;\n\n/**\n * One listed node's id, kind (`file` / `folder`) and media type. agora\n * serializes the listing with `default=str`, so a node usually arrives as its\n * pydantic text (`name='Q3' type='folder' id='asset_…' media_type='athena/folder'\n * children={…}`, its own fields ahead of its children's); a node can also\n * arrive as an object.\n */\nfunction readListedNode(raw: unknown): { id?: string; kind?: string; mediaType?: string } {\n if (typeof raw === \"string\") {\n return {\n id: LISTED_NODE_ID.exec(raw)?.[1],\n kind: LISTED_NODE_KIND.exec(raw)?.[1],\n mediaType: LISTED_NODE_MEDIA_TYPE.exec(raw)?.[1],\n };\n }\n if (!isRecord(raw)) return {};\n return {\n id: stringField(raw, [\"id\"]) ?? undefined,\n kind: stringField(raw, [\"type\"]) ?? undefined,\n mediaType: stringField(raw, [\"media_type\"]) ?? undefined,\n };\n}\n\n/** The asset type a listed node's icon is drawn for: an Athena asset's type, a folder, or an upload's kind of file. */\nfunction listedAssetType({ kind, mediaType }: { kind?: string; mediaType?: string }): string | undefined {\n if (mediaType?.startsWith(\"athena/\")) return mediaType.slice(\"athena/\".length);\n if (kind === \"folder\") return \"folder\";\n if (mediaType === \"application/pdf\") return \"pdf\";\n const family = mediaType?.split(\"/\")[0];\n return family === \"image\" || family === \"video\" || family === \"audio\" ? family : undefined;\n}\n\n/** The listing agora's `list_contents` returned, or `null` for a result that is not a record. */\nexport function readListContentsResult(result: unknown): ListContentsResult | null {\n const data = normalizeResult(result);\n if (!data) return null;\n const treeData = isRecord(data.tree_data) ? data.tree_data : null;\n const pagination = isRecord(data.pagination) ? data.pagination : null;\n const currentPage = numberField(pagination, \"current_page\");\n const totalPages = numberField(pagination, \"total_pages\");\n return {\n tree: stringField(data, [\"structure_tree_ascii\"]),\n entries: treeData\n ? Object.entries(treeData).map(([title, raw]) => {\n const node = readListedNode(raw);\n return { title, assetId: node.id, assetType: listedAssetType(node) };\n })\n : null,\n pagination:\n currentPage !== undefined && totalPages !== undefined ? { currentPage, totalPages } : null,\n };\n}\n\nfunction ListedEntryRow({ entry, divided }: { entry: ListedEntry; divided: boolean }) {\n const openAsset = useAssetPanelStore((s) => s.openAsset);\n const { assetId } = entry;\n return (\n <li>\n {divided ? <div aria-hidden=\"true\" className=\"ml-10 border-t border-border/60\" /> : null}\n {assetId ? (\n <button\n type=\"button\"\n data-asset-id={assetId}\n onClick={() =>\n openAsset(assetId, { name: entry.title, type: panelAssetType(entry.assetType) })\n }\n className=\"flex w-full items-center gap-4 rounded-md py-2 text-left transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary\"\n >\n <AssetTypeIcon assetType={entry.assetType} size=\"sm\" />\n <span className=\"min-w-0 truncate text-[13px] font-medium text-foreground\">\n {entry.title}\n </span>\n </button>\n ) : (\n <p className=\"py-1 pl-10 text-[11px] text-muted-foreground\">{entry.title}</p>\n )}\n </li>\n );\n}\n\nconst ListContentsToolUIImpl: ToolCallMessagePartComponent = (props) => {\n const { toolName, args, result, status, isError } = props;\n const classification = classifyToolResult({ status, result, isError });\n if (classification.state === \"rejected\" || classification.state === \"paused\") {\n return <ToolFallback {...props} icon={FolderIcon} />;\n }\n const typedArgs = argsRecord(args);\n // Olympus names the listed asset by its title, read from its asset cache;\n // the call carries only its id, so the card names the workspace alone.\n const target = stringField(typedArgs, [\"asset_id\"]) ? \"\" : \" for workspace\";\n const data = readListContentsResult(result);\n const card = toolCardOutcome({ status, classification });\n\n const running = \"Listing contents...\";\n const listed = data\n ? `Contents listed - Page ${data.pagination?.currentPage ?? 1} of ${data.pagination?.totalPages ?? 1}${target}`\n : `Contents listed${target}`;\n const title =\n card.status === \"running\" ? running : card.status === \"complete\" ? listed : withoutEllipsis(running);\n const entries = data?.entries ?? [];\n const hasListing = Boolean(data && (data.tree || entries.length > 0 || data.pagination));\n\n return (\n <ToolCard\n icon={FolderIcon}\n status={card.status}\n title={title}\n toolName={toolName}\n args={typedArgs}\n result={result}\n error={card.failure}\n >\n {card.status === \"complete\" && data && hasListing ? (\n <ExpandableSection label=\"Show contents\">\n <div className=\"flex flex-col gap-3\">\n {data.tree ? (\n <pre className=\"overflow-x-auto whitespace-pre-wrap rounded bg-muted/50 p-2 text-[11px] leading-4 text-foreground\">\n {data.tree}\n </pre>\n ) : null}\n {entries.length > 0 ? (\n <div className=\"max-h-60 overflow-y-auto pr-0.5\">\n <ul className=\"flex flex-col\">\n {entries.map((entry, index) => (\n <ListedEntryRow\n key={`${entry.title}:${index}`}\n entry={entry}\n divided={index > 0 && entries[index - 1]?.assetId !== undefined}\n />\n ))}\n </ul>\n </div>\n ) : null}\n {data.pagination ? (\n <span className=\"text-[10px] text-muted-foreground\">\n Page {data.pagination.currentPage} of {data.pagination.totalPages}\n </span>\n ) : null}\n </div>\n </ExpandableSection>\n ) : null}\n </ToolCard>\n );\n};\n\nexport const ListContentsToolUI = memo(\n ListContentsToolUIImpl,\n) as unknown as ToolCallMessagePartComponent;\nListContentsToolUI.displayName = \"ListContentsToolUI\";\n\n// ─── project_links ───────────────────────────────────────────────────\n\n/**\n * Streamed or model-written `asset_ids` are not always an array: a single id\n * or a comma-separated string arrives as a string.\n */\nexport function normalizeProjectLinksAssetIds(value: unknown): string[] {\n if (Array.isArray(value)) {\n return value.filter((id): id is string => typeof id === \"string\" && id.length > 0);\n }\n if (typeof value === \"string\") {\n return value\n .split(\",\")\n .map((id) => id.trim())\n .filter((id) => id.length > 0);\n }\n return [];\n}\n\nfunction projectLinksRunningTitle({ operation, count }: { operation: string; count: number }): string {\n const links = `${count} asset link${count !== 1 ? \"s\" : \"\"}`;\n switch (operation) {\n case \"read\":\n return \"Reading project links...\";\n case \"add\":\n return `Adding ${links} to project...`;\n case \"remove\":\n return `Removing ${links} from project...`;\n case \"set\":\n return `Setting ${links} on project...`;\n default:\n return \"Managing project links...\";\n }\n}\n\nconst PROJECT_LINKS_DETAIL_LABEL: Record<string, string> = {\n read: \"Linked\",\n add: \"Added\",\n remove: \"Removed\",\n set: \"Set to\",\n};\n\nconst ProjectLinksToolUIImpl: ToolCallMessagePartComponent = (props) => {\n const { toolName, args, result, status, isError } = props;\n const classification = classifyToolResult({ status, result, isError });\n if (classification.state === \"rejected\" || classification.state === \"paused\") {\n return <ToolFallback {...props} icon={LinkIcon} />;\n }\n const typedArgs = argsRecord(args);\n const operation = stringField(typedArgs, [\"type\"]) ?? \"read\";\n const projectId = stringField(typedArgs, [\"project_id\"]);\n const argAssetIds = normalizeProjectLinksAssetIds(typedArgs.asset_ids);\n const data = normalizeResult(result);\n // Every answer agora writes in prose (\"Project with ID … not found\",\n // \"Error: …\") is a refusal; a change or a read answers in JSON.\n const prose = typeof result === \"string\" && !data ? result.trim() : \"\";\n const card = toolCardOutcome({ status, classification, resultFailure: prose || null });\n\n const assetIds =\n operation === \"read\" && Array.isArray(data?.asset_ids)\n ? normalizeProjectLinksAssetIds(data.asset_ids)\n : argAssetIds;\n const singleAsset = assetIds.length === 1 ? assetIds[0] : undefined;\n const changesOneAsset = singleAsset !== undefined && operation !== \"read\";\n const message = stringField(data, [\"message\"]);\n const projectTitle = stringField(data, [\"project_title\"]) ?? undefined;\n\n const running = projectLinksRunningTitle({ operation, count: argAssetIds.length });\n const title =\n card.status === \"running\"\n ? running\n : card.status === \"complete\"\n ? (message ?? withoutEllipsis(running))\n : withoutEllipsis(running);\n const isDone = card.status === \"complete\";\n const projectChip = projectId ? (\n <AssetChip\n assetId={projectId}\n title={projectTitle}\n fallbackLabel=\"Project\"\n assetType=\"project\"\n />\n ) : null;\n\n return (\n <ToolCard\n icon={LinkIcon}\n status={card.status}\n title={title}\n toolName={toolName}\n args={typedArgs}\n result={result}\n error={card.failure}\n >\n {isDone && changesOneAsset ? (\n <AssetChipLine>\n <AssetChip assetId={singleAsset} fallbackLabel={singleAsset} />\n {projectChip ? (\n <>\n <ArrowRightIcon aria-hidden=\"true\" className=\"size-3.5 shrink-0\" />\n {projectChip}\n </>\n ) : null}\n </AssetChipLine>\n ) : isDone && message && projectChip ? (\n <AssetChipLine>\n <span>on</span>\n {projectChip}\n </AssetChipLine>\n ) : null}\n {isDone && !changesOneAsset && assetIds.length > 0 ? (\n <ExpandableSection label=\"Show assets\">\n <div className=\"flex flex-col\">\n <p className=\"py-1 text-[11px] font-semibold text-muted-foreground\">\n {PROJECT_LINKS_DETAIL_LABEL[operation] ?? operation}\n </p>\n <ul className=\"flex flex-col divide-y divide-border/60\">\n {assetIds.map((assetId, index) => (\n <li key={`${assetId}:${index}`} className=\"py-1\">\n <AssetChip assetId={assetId} fallbackLabel={assetId} />\n </li>\n ))}\n </ul>\n </div>\n </ExpandableSection>\n ) : null}\n </ToolCard>\n );\n};\n\nexport const ProjectLinksToolUI = memo(\n ProjectLinksToolUIImpl,\n) as unknown as ToolCallMessagePartComponent;\nProjectLinksToolUI.displayName = \"ProjectLinksToolUI\";\n"],"names":["useAssetIconAppUrl","assetTypeToThumb","useThumbnailLoadFailure","jsx","cn","MentionIcon","assetTypeToIcon","useAssetPanelStore","jsxs","CHIP_PILL_CLASS","CHIP_LINK_CLASS","CHIP_ICON_CLASS","isRecord","stringField","normalizeResult","classifyToolResult","ToolFallback","SearchIcon","ToolCard","ExpandableSection","memo","FolderIcon","_a","LinkIcon","Fragment","ArrowRightIcon"],"mappings":"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"}
@@ -42,10 +42,11 @@ declare const ASSET_ICON_TILE: {
42
42
  };
43
43
  };
44
44
  /**
45
- * An asset's type icon, as the `@` menu draws it: the host's asset-type SVG
46
- * when it serves them (`configureAssetIconBasePath`), else the type's Lucide
47
- * icon on a muted tile. Olympus draws the asset's own thumbnail, which needs
48
- * the asset read; its type is what a result carries.
45
+ * An asset's type icon, as the `@` menu draws it: the asset-type SVG Olympus
46
+ * draws (`assetTypeToThumb`: the host's copy, else the chat's Athena web app's), or
47
+ * the type's Lucide icon on a muted tile when there is none or it cannot load.
48
+ * Olympus draws the asset's own thumbnail, which needs the asset read; its
49
+ * type is what a result carries.
49
50
  */
50
51
  export declare function AssetTypeIcon({ assetType, size, }: {
51
52
  assetType: string | undefined;
@@ -3,7 +3,8 @@ import { FolderIcon, LinkIcon, ArrowRightIcon, SearchIcon } from "lucide-react";
3
3
  import { memo } from "react";
4
4
  import { useAssetPanelStore } from "../assets/asset-panel-store.js";
5
5
  import { CHIP_ICON_CLASS, CHIP_PILL_CLASS, CHIP_LINK_CLASS } from "../chat-ui/mentions/mention-chip.js";
6
- import { MentionIcon } from "../chat-ui/mentions/suggestions/components/mention-icon.js";
6
+ import { MentionIcon, useThumbnailLoadFailure } from "../chat-ui/mentions/suggestions/components/mention-icon.js";
7
+ import { useAssetIconAppUrl } from "../chat-ui/mentions/use-asset-icon-app-url.js";
7
8
  import { assetTypeToIcon, assetTypeToThumb } from "../chat-ui/mentions/suggestions/data/sources/asset-type-icons.js";
8
9
  import { ToolCard, ExpandableSection, normalizeResult } from "./primitives.js";
9
10
  import { ToolFallback } from "./tool-fallback.js";
@@ -43,9 +44,11 @@ function AssetTypeIcon({
43
44
  size
44
45
  }) {
45
46
  const tile = ASSET_ICON_TILE[size];
46
- const thumbnailUrl = assetTypeToThumb(assetType);
47
- if (thumbnailUrl) {
48
- return /* @__PURE__ */ jsx(MentionIcon, { thumbnailUrl, className: cn("shrink-0", tile.box) });
47
+ const iconAppUrl = useAssetIconAppUrl();
48
+ const thumbnailUrl = assetTypeToThumb(assetType, { appUrl: iconAppUrl });
49
+ const thumbnail = useThumbnailLoadFailure(thumbnailUrl);
50
+ if (thumbnailUrl && !thumbnail.failed) {
51
+ return /* @__PURE__ */ jsx("img", { ref: thumbnail.imageRef, src: thumbnailUrl, alt: "", className: cn("shrink-0", tile.box) });
49
52
  }
50
53
  return /* @__PURE__ */ jsx(
51
54
  "span",
@@ -66,6 +69,7 @@ function AssetChip({
66
69
  assetType
67
70
  }) {
68
71
  const openAsset = useAssetPanelStore((s) => s.openAsset);
72
+ const iconAppUrl = useAssetIconAppUrl();
69
73
  const label = title ?? fallbackLabel;
70
74
  return /* @__PURE__ */ jsxs(
71
75
  "button",
@@ -79,7 +83,7 @@ function AssetChip({
79
83
  /* @__PURE__ */ jsx(
80
84
  MentionIcon,
81
85
  {
82
- thumbnailUrl: assetTypeToThumb(assetType),
86
+ thumbnailUrl: assetTypeToThumb(assetType, { appUrl: iconAppUrl }),
83
87
  fallbackIcon: assetTypeToIcon(assetType),
84
88
  className: CHIP_ICON_CLASS
85
89
  }
@@ -1 +1 @@
1
- {"version":3,"file":"drive-tool-uis.js","sources":["../../src/tools/drive-tool-uis.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * The Athena Drive cards, as Athena on the web draws them: `search_assets`\n * (the matches, each opening its asset), `list_contents` (a folder's tree and\n * the assets in it) and `project_links` (a project's links as asset chips).\n *\n * Olympus reads each asset's title and thumbnail from its asset cache; these\n * cards draw only what the call's arguments and result carry. An asset shows\n * its type's icon when the result names its type, and an asset the result\n * names by id alone shows its id.\n */\nimport type {\n ToolCallMessagePartComponent,\n ToolCallMessagePartStatus,\n} from \"@assistant-ui/react\";\nimport {\n classifyToolResult,\n isRecord,\n stringField,\n type ToolResultClassification,\n} from \"@athenaintel/agent-runtime\";\nimport { ArrowRightIcon, FolderIcon, LinkIcon, SearchIcon } from \"lucide-react\";\nimport { memo, type ReactNode } from \"react\";\nimport { type AssetType, useAssetPanelStore } from \"../assets/asset-panel-store\";\nimport {\n CHIP_ICON_CLASS,\n CHIP_LINK_CLASS,\n CHIP_PILL_CLASS,\n} from \"../chat-ui/mentions/mention-chip\";\nimport { MentionIcon } from \"../chat-ui/mentions/suggestions/components/mention-icon\";\nimport {\n assetTypeToIcon,\n assetTypeToThumb,\n} from \"../chat-ui/mentions/suggestions/data/sources/asset-type-icons\";\nimport { cn } from \"../lib/utils\";\nimport { ExpandableSection, normalizeResult, ToolCard, type ToolStatus } from \"./primitives\";\nimport { ToolFallback } from \"./tool-fallback\";\n\n// ─── Shared by the Drive and project manager cards ───────────────────\n\n/** A running title without its trailing \"...\": what a stopped or waiting call was doing. */\nexport function withoutEllipsis(title: string): string {\n return title.replace(/(?:\\.{3}|…)\\s*$/u, \"\");\n}\n\n/** How a card shows its call: the status it renders with, and why the call failed when it did. */\nexport interface ToolCardOutcome {\n status: ToolStatus;\n failure: string | null;\n}\n\n/**\n * The card's status. A call the runtime stopped reads as failed with the\n * runtime's reason; a settled call reads as failed when its result reports a\n * failure in the tool's own words (`resultFailure`, as Olympus words it) or\n * the shared classifier reads one. A refusal at the approval gate never gets\n * here: the generic card draws it.\n */\nexport function toolCardOutcome({\n status,\n classification,\n resultFailure = null,\n}: {\n status: ToolCallMessagePartStatus | undefined;\n classification: ToolResultClassification;\n resultFailure?: string | null;\n}): ToolCardOutcome {\n if (status?.type === \"running\") return { status: \"running\", failure: null };\n const classified = classification.state === \"error\" ? classification.failure.message : null;\n const failure = status?.type === \"incomplete\" ? classified : (resultFailure ?? classified);\n if (failure) return { status: \"incomplete\", failure };\n return { status: status?.type ?? \"complete\", failure: null };\n}\n\n/** The asset panel's name for an asset type, when it has one; the panel opens any other as a plain asset. */\nfunction panelAssetType(assetType: string | undefined): AssetType | undefined {\n switch (assetType) {\n case \"presentation\":\n case \"spreadsheet\":\n case \"document\":\n case \"notebook\":\n return assetType;\n default:\n return undefined;\n }\n}\n\nconst ASSET_ICON_TILE = {\n md: { box: \"size-8\", icon: \"size-4\" },\n sm: { box: \"size-6\", icon: \"size-3.5\" },\n} as const;\n\n/**\n * An asset's type icon, as the `@` menu draws it: the host's asset-type SVG\n * when it serves them (`configureAssetIconBasePath`), else the type's Lucide\n * icon on a muted tile. Olympus draws the asset's own thumbnail, which needs\n * the asset read; its type is what a result carries.\n */\nexport function AssetTypeIcon({\n assetType,\n size,\n}: {\n assetType: string | undefined;\n size: keyof typeof ASSET_ICON_TILE;\n}) {\n const tile = ASSET_ICON_TILE[size];\n const thumbnailUrl = assetTypeToThumb(assetType);\n if (thumbnailUrl) {\n return <MentionIcon thumbnailUrl={thumbnailUrl} className={cn(\"shrink-0\", tile.box)} />;\n }\n return (\n <span\n aria-hidden=\"true\"\n className={cn(\n \"flex shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground\",\n tile.box,\n )}\n >\n <MentionIcon fallbackIcon={assetTypeToIcon(assetType)} className={tile.icon} />\n </span>\n );\n}\n\n/**\n * An asset as the chip a chat message draws, opening the asset on click.\n * `title` is the asset's title when the call carried one; without it the\n * chip shows `fallbackLabel` and the asset opens unnamed, for whatever opens\n * it to name.\n */\nexport function AssetChip({\n assetId,\n title,\n fallbackLabel,\n assetType,\n}: {\n assetId: string;\n title?: string;\n fallbackLabel: string;\n assetType?: string;\n}) {\n const openAsset = useAssetPanelStore((s) => s.openAsset);\n const label = title ?? fallbackLabel;\n return (\n <button\n type=\"button\"\n data-asset-id={assetId}\n title={`Open ${label}`}\n onClick={() => openAsset(assetId, { name: title, type: panelAssetType(assetType) })}\n className={cn(CHIP_PILL_CLASS, CHIP_LINK_CLASS, \"max-w-[275px] text-xs\")}\n >\n <MentionIcon\n thumbnailUrl={assetTypeToThumb(assetType)}\n fallbackIcon={assetTypeToIcon(assetType)}\n className={CHIP_ICON_CLASS}\n />\n <span className=\"min-w-0 max-w-[180px] overflow-hidden text-ellipsis\">{label}</span>\n </button>\n );\n}\n\n/** The line under a card's title that finishes its sentence with chips (\"for [project]\"). */\nexport function AssetChipLine({ children }: { children: ReactNode }) {\n return (\n <div className=\"flex flex-wrap items-center gap-1.5 border-t border-border/40 px-4 py-2 text-xs text-muted-foreground\">\n {children}\n </div>\n );\n}\n\n/** The record a tool call's arguments are, or an empty one while they stream. */\nexport function argsRecord(args: unknown): Record<string, unknown> {\n return isRecord(args) ? args : {};\n}\n\n/** A number field of a result record, when it is one. */\nexport function numberField(\n record: Record<string, unknown> | null | undefined,\n key: string,\n): number | undefined {\n const value = record?.[key];\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\n// ─── search_assets ───────────────────────────────────────────────────\n\n/** One match, as the card lists it. */\nexport interface SearchAssetRow {\n id: string;\n title: string;\n /** The type its icon is drawn for (`athena_converted_type`, else `athena_original_type`). */\n assetType: string | undefined;\n creator: string;\n updatedAt: string | undefined;\n workspaceAccess: string | undefined;\n}\n\nexport interface SearchAssetsResult {\n rows: SearchAssetRow[];\n /** `returned_count`: this page's matches. */\n count: number;\n /** The reason a search failed (`error_message`). */\n errorMessage: string | null;\n}\n\nfunction searchAssetCreator(asset: Record<string, unknown>): string {\n const user = isRecord(asset.created_by_user) ? asset.created_by_user : null;\n const fullName = [stringField(user, [\"first_name\"]), stringField(user, [\"last_name\"])]\n .filter(Boolean)\n .join(\" \");\n return stringField(user, [\"email\"]) ?? (fullName || null) ?? stringField(user, [\"id\"]) ?? \"Unknown\";\n}\n\n/** The page of matches agora's `search_assets` returned, or `null` for a result that is not one. */\nexport function readSearchAssetsResult(result: unknown): SearchAssetsResult | null {\n const data = normalizeResult(result);\n if (!data || !Array.isArray(data.assets)) return null;\n const rows = data.assets.flatMap((raw): SearchAssetRow[] => {\n if (!isRecord(raw)) return [];\n const id = stringField(raw, [\"id\"]);\n if (!id) return [];\n return [\n {\n id,\n title: stringField(raw, [\"title\"]) ?? \"Untitled\",\n assetType:\n stringField(raw, [\"athena_converted_type\", \"athena_original_type\", \"asset_type\"]) ??\n undefined,\n creator: searchAssetCreator(raw),\n updatedAt: stringField(raw, [\"updated_at\"]) ?? undefined,\n workspaceAccess: stringField(raw, [\"workspace_access\"]) ?? undefined,\n },\n ];\n });\n return {\n rows,\n count: numberField(data, \"returned_count\") ?? rows.length,\n errorMessage: stringField(data, [\"error_message\"]),\n };\n}\n\nfunction updatedDate(updatedAt: string | undefined): string | null {\n if (!updatedAt) return null;\n const date = new Date(updatedAt);\n return Number.isNaN(date.getTime()) ? null : date.toLocaleDateString();\n}\n\nfunction SearchAssetResultRow({ row, divided }: { row: SearchAssetRow; divided: boolean }) {\n const openAsset = useAssetPanelStore((s) => s.openAsset);\n const updated = updatedDate(row.updatedAt);\n return (\n <li>\n {divided ? <div aria-hidden=\"true\" className=\"ml-11 border-t border-border/60\" /> : null}\n <button\n type=\"button\"\n data-asset-id={row.id}\n onClick={() => openAsset(row.id, { name: row.title, type: panelAssetType(row.assetType) })}\n className=\"flex w-full items-start gap-2 rounded-md px-1 py-3 text-left transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary\"\n >\n <AssetTypeIcon assetType={row.assetType} size=\"md\" />\n <span className=\"flex min-w-0 flex-col gap-0.5\">\n <span className=\"break-words text-[13px] font-medium text-foreground\">{row.title}</span>\n <span className=\"text-[11px] text-muted-foreground\">Created by {row.creator}</span>\n {updated ? (\n <span className=\"text-[11px] text-muted-foreground\">Updated {updated}</span>\n ) : null}\n {row.workspaceAccess ? (\n <span className=\"text-[11px] text-muted-foreground\">{row.workspaceAccess}</span>\n ) : null}\n </span>\n </button>\n </li>\n );\n}\n\nconst SearchAssetsToolUIImpl: ToolCallMessagePartComponent = (props) => {\n const { toolName, args, result, status, isError } = props;\n const classification = classifyToolResult({ status, result, isError });\n // A search refused at the approval gate or parked by the runtime is the\n // generic card's to draw: it is neither a result nor a failure.\n if (classification.state === \"rejected\" || classification.state === \"paused\") {\n return <ToolFallback {...props} icon={SearchIcon} />;\n }\n const typedArgs = argsRecord(args);\n const keyword = stringField(typedArgs, [\"title_contains_keyword\"]);\n const data = readSearchAssetsResult(result);\n const card = toolCardOutcome({\n status,\n classification,\n resultFailure: data?.errorMessage ? `Search failed: ${data.errorMessage}` : null,\n });\n\n const running = keyword ? `Searching assets for \"${keyword}\"...` : \"Searching assets...\";\n const found = data\n ? `Found ${data.count === 1 ? \"1 asset\" : `${data.count} assets`}${keyword ? ` for \"${keyword}\"` : \"\"}`\n : `Search complete${keyword ? ` for \"${keyword}\"` : \"\"}`;\n const title =\n card.status === \"running\" ? running : card.status === \"complete\" ? found : withoutEllipsis(running);\n\n return (\n <ToolCard\n icon={SearchIcon}\n status={card.status}\n title={title}\n toolName={toolName}\n args={typedArgs}\n result={result}\n error={card.failure}\n >\n {card.status === \"complete\" && data && data.rows.length > 0 ? (\n <ExpandableSection label=\"Show assets\">\n <ul className=\"flex flex-col\">\n {data.rows.map((row, index) => (\n <SearchAssetResultRow key={`${row.id}:${index}`} row={row} divided={index > 0} />\n ))}\n </ul>\n </ExpandableSection>\n ) : null}\n </ToolCard>\n );\n};\n\nexport const SearchAssetsToolUI = memo(\n SearchAssetsToolUIImpl,\n) as unknown as ToolCallMessagePartComponent;\nSearchAssetsToolUI.displayName = \"SearchAssetsToolUI\";\n\n// ─── list_contents ───────────────────────────────────────────────────\n\n/** One top-level entry of a listing: its title, and the asset it is when the listing names one. */\nexport interface ListedEntry {\n title: string;\n assetId: string | undefined;\n /** The type its icon is drawn for. */\n assetType: string | undefined;\n}\n\nexport interface ListContentsResult {\n /** `structure_tree_ascii`: the whole tree as text. */\n tree: string | null;\n /** `tree_data`'s top level (this page of it), or `null` when the result has none. */\n entries: ListedEntry[] | null;\n pagination: { currentPage: number; totalPages: number } | null;\n}\n\nconst LISTED_NODE_ID = /(?:^|\\s)id='([^']+)'/;\nconst LISTED_NODE_KIND = /(?:^|\\s)type='([^']+)'/;\nconst LISTED_NODE_MEDIA_TYPE = /(?:^|\\s)media_type='([^']+)'/;\n\n/**\n * One listed node's id, kind (`file` / `folder`) and media type. agora\n * serializes the listing with `default=str`, so a node usually arrives as its\n * pydantic text (`name='Q3' type='folder' id='asset_…' media_type='athena/folder'\n * children={…}`, its own fields ahead of its children's); a node can also\n * arrive as an object.\n */\nfunction readListedNode(raw: unknown): { id?: string; kind?: string; mediaType?: string } {\n if (typeof raw === \"string\") {\n return {\n id: LISTED_NODE_ID.exec(raw)?.[1],\n kind: LISTED_NODE_KIND.exec(raw)?.[1],\n mediaType: LISTED_NODE_MEDIA_TYPE.exec(raw)?.[1],\n };\n }\n if (!isRecord(raw)) return {};\n return {\n id: stringField(raw, [\"id\"]) ?? undefined,\n kind: stringField(raw, [\"type\"]) ?? undefined,\n mediaType: stringField(raw, [\"media_type\"]) ?? undefined,\n };\n}\n\n/** The asset type a listed node's icon is drawn for: an Athena asset's type, a folder, or an upload's kind of file. */\nfunction listedAssetType({ kind, mediaType }: { kind?: string; mediaType?: string }): string | undefined {\n if (mediaType?.startsWith(\"athena/\")) return mediaType.slice(\"athena/\".length);\n if (kind === \"folder\") return \"folder\";\n if (mediaType === \"application/pdf\") return \"pdf\";\n const family = mediaType?.split(\"/\")[0];\n return family === \"image\" || family === \"video\" || family === \"audio\" ? family : undefined;\n}\n\n/** The listing agora's `list_contents` returned, or `null` for a result that is not a record. */\nexport function readListContentsResult(result: unknown): ListContentsResult | null {\n const data = normalizeResult(result);\n if (!data) return null;\n const treeData = isRecord(data.tree_data) ? data.tree_data : null;\n const pagination = isRecord(data.pagination) ? data.pagination : null;\n const currentPage = numberField(pagination, \"current_page\");\n const totalPages = numberField(pagination, \"total_pages\");\n return {\n tree: stringField(data, [\"structure_tree_ascii\"]),\n entries: treeData\n ? Object.entries(treeData).map(([title, raw]) => {\n const node = readListedNode(raw);\n return { title, assetId: node.id, assetType: listedAssetType(node) };\n })\n : null,\n pagination:\n currentPage !== undefined && totalPages !== undefined ? { currentPage, totalPages } : null,\n };\n}\n\nfunction ListedEntryRow({ entry, divided }: { entry: ListedEntry; divided: boolean }) {\n const openAsset = useAssetPanelStore((s) => s.openAsset);\n const { assetId } = entry;\n return (\n <li>\n {divided ? <div aria-hidden=\"true\" className=\"ml-10 border-t border-border/60\" /> : null}\n {assetId ? (\n <button\n type=\"button\"\n data-asset-id={assetId}\n onClick={() =>\n openAsset(assetId, { name: entry.title, type: panelAssetType(entry.assetType) })\n }\n className=\"flex w-full items-center gap-4 rounded-md py-2 text-left transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary\"\n >\n <AssetTypeIcon assetType={entry.assetType} size=\"sm\" />\n <span className=\"min-w-0 truncate text-[13px] font-medium text-foreground\">\n {entry.title}\n </span>\n </button>\n ) : (\n <p className=\"py-1 pl-10 text-[11px] text-muted-foreground\">{entry.title}</p>\n )}\n </li>\n );\n}\n\nconst ListContentsToolUIImpl: ToolCallMessagePartComponent = (props) => {\n const { toolName, args, result, status, isError } = props;\n const classification = classifyToolResult({ status, result, isError });\n if (classification.state === \"rejected\" || classification.state === \"paused\") {\n return <ToolFallback {...props} icon={FolderIcon} />;\n }\n const typedArgs = argsRecord(args);\n // Olympus names the listed asset by its title, read from its asset cache;\n // the call carries only its id, so the card names the workspace alone.\n const target = stringField(typedArgs, [\"asset_id\"]) ? \"\" : \" for workspace\";\n const data = readListContentsResult(result);\n const card = toolCardOutcome({ status, classification });\n\n const running = \"Listing contents...\";\n const listed = data\n ? `Contents listed - Page ${data.pagination?.currentPage ?? 1} of ${data.pagination?.totalPages ?? 1}${target}`\n : `Contents listed${target}`;\n const title =\n card.status === \"running\" ? running : card.status === \"complete\" ? listed : withoutEllipsis(running);\n const entries = data?.entries ?? [];\n const hasListing = Boolean(data && (data.tree || entries.length > 0 || data.pagination));\n\n return (\n <ToolCard\n icon={FolderIcon}\n status={card.status}\n title={title}\n toolName={toolName}\n args={typedArgs}\n result={result}\n error={card.failure}\n >\n {card.status === \"complete\" && data && hasListing ? (\n <ExpandableSection label=\"Show contents\">\n <div className=\"flex flex-col gap-3\">\n {data.tree ? (\n <pre className=\"overflow-x-auto whitespace-pre-wrap rounded bg-muted/50 p-2 text-[11px] leading-4 text-foreground\">\n {data.tree}\n </pre>\n ) : null}\n {entries.length > 0 ? (\n <div className=\"max-h-60 overflow-y-auto pr-0.5\">\n <ul className=\"flex flex-col\">\n {entries.map((entry, index) => (\n <ListedEntryRow\n key={`${entry.title}:${index}`}\n entry={entry}\n divided={index > 0 && entries[index - 1]?.assetId !== undefined}\n />\n ))}\n </ul>\n </div>\n ) : null}\n {data.pagination ? (\n <span className=\"text-[10px] text-muted-foreground\">\n Page {data.pagination.currentPage} of {data.pagination.totalPages}\n </span>\n ) : null}\n </div>\n </ExpandableSection>\n ) : null}\n </ToolCard>\n );\n};\n\nexport const ListContentsToolUI = memo(\n ListContentsToolUIImpl,\n) as unknown as ToolCallMessagePartComponent;\nListContentsToolUI.displayName = \"ListContentsToolUI\";\n\n// ─── project_links ───────────────────────────────────────────────────\n\n/**\n * Streamed or model-written `asset_ids` are not always an array: a single id\n * or a comma-separated string arrives as a string.\n */\nexport function normalizeProjectLinksAssetIds(value: unknown): string[] {\n if (Array.isArray(value)) {\n return value.filter((id): id is string => typeof id === \"string\" && id.length > 0);\n }\n if (typeof value === \"string\") {\n return value\n .split(\",\")\n .map((id) => id.trim())\n .filter((id) => id.length > 0);\n }\n return [];\n}\n\nfunction projectLinksRunningTitle({ operation, count }: { operation: string; count: number }): string {\n const links = `${count} asset link${count !== 1 ? \"s\" : \"\"}`;\n switch (operation) {\n case \"read\":\n return \"Reading project links...\";\n case \"add\":\n return `Adding ${links} to project...`;\n case \"remove\":\n return `Removing ${links} from project...`;\n case \"set\":\n return `Setting ${links} on project...`;\n default:\n return \"Managing project links...\";\n }\n}\n\nconst PROJECT_LINKS_DETAIL_LABEL: Record<string, string> = {\n read: \"Linked\",\n add: \"Added\",\n remove: \"Removed\",\n set: \"Set to\",\n};\n\nconst ProjectLinksToolUIImpl: ToolCallMessagePartComponent = (props) => {\n const { toolName, args, result, status, isError } = props;\n const classification = classifyToolResult({ status, result, isError });\n if (classification.state === \"rejected\" || classification.state === \"paused\") {\n return <ToolFallback {...props} icon={LinkIcon} />;\n }\n const typedArgs = argsRecord(args);\n const operation = stringField(typedArgs, [\"type\"]) ?? \"read\";\n const projectId = stringField(typedArgs, [\"project_id\"]);\n const argAssetIds = normalizeProjectLinksAssetIds(typedArgs.asset_ids);\n const data = normalizeResult(result);\n // Every answer agora writes in prose (\"Project with ID … not found\",\n // \"Error: …\") is a refusal; a change or a read answers in JSON.\n const prose = typeof result === \"string\" && !data ? result.trim() : \"\";\n const card = toolCardOutcome({ status, classification, resultFailure: prose || null });\n\n const assetIds =\n operation === \"read\" && Array.isArray(data?.asset_ids)\n ? normalizeProjectLinksAssetIds(data.asset_ids)\n : argAssetIds;\n const singleAsset = assetIds.length === 1 ? assetIds[0] : undefined;\n const changesOneAsset = singleAsset !== undefined && operation !== \"read\";\n const message = stringField(data, [\"message\"]);\n const projectTitle = stringField(data, [\"project_title\"]) ?? undefined;\n\n const running = projectLinksRunningTitle({ operation, count: argAssetIds.length });\n const title =\n card.status === \"running\"\n ? running\n : card.status === \"complete\"\n ? (message ?? withoutEllipsis(running))\n : withoutEllipsis(running);\n const isDone = card.status === \"complete\";\n const projectChip = projectId ? (\n <AssetChip\n assetId={projectId}\n title={projectTitle}\n fallbackLabel=\"Project\"\n assetType=\"project\"\n />\n ) : null;\n\n return (\n <ToolCard\n icon={LinkIcon}\n status={card.status}\n title={title}\n toolName={toolName}\n args={typedArgs}\n result={result}\n error={card.failure}\n >\n {isDone && changesOneAsset ? (\n <AssetChipLine>\n <AssetChip assetId={singleAsset} fallbackLabel={singleAsset} />\n {projectChip ? (\n <>\n <ArrowRightIcon aria-hidden=\"true\" className=\"size-3.5 shrink-0\" />\n {projectChip}\n </>\n ) : null}\n </AssetChipLine>\n ) : isDone && message && projectChip ? (\n <AssetChipLine>\n <span>on</span>\n {projectChip}\n </AssetChipLine>\n ) : null}\n {isDone && !changesOneAsset && assetIds.length > 0 ? (\n <ExpandableSection label=\"Show assets\">\n <div className=\"flex flex-col\">\n <p className=\"py-1 text-[11px] font-semibold text-muted-foreground\">\n {PROJECT_LINKS_DETAIL_LABEL[operation] ?? operation}\n </p>\n <ul className=\"flex flex-col divide-y divide-border/60\">\n {assetIds.map((assetId, index) => (\n <li key={`${assetId}:${index}`} className=\"py-1\">\n <AssetChip assetId={assetId} fallbackLabel={assetId} />\n </li>\n ))}\n </ul>\n </div>\n </ExpandableSection>\n ) : null}\n </ToolCard>\n );\n};\n\nexport const ProjectLinksToolUI = memo(\n ProjectLinksToolUIImpl,\n) as unknown as ToolCallMessagePartComponent;\nProjectLinksToolUI.displayName = \"ProjectLinksToolUI\";\n"],"names":["_a"],"mappings":"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"}
1
+ {"version":3,"file":"drive-tool-uis.js","sources":["../../src/tools/drive-tool-uis.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * The Athena Drive cards, as Athena on the web draws them: `search_assets`\n * (the matches, each opening its asset), `list_contents` (a folder's tree and\n * the assets in it) and `project_links` (a project's links as asset chips).\n *\n * Olympus reads each asset's title and thumbnail from its asset cache; these\n * cards draw only what the call's arguments and result carry. An asset shows\n * its type's icon when the result names its type, and an asset the result\n * names by id alone shows its id.\n */\nimport type {\n ToolCallMessagePartComponent,\n ToolCallMessagePartStatus,\n} from \"@assistant-ui/react\";\nimport {\n classifyToolResult,\n isRecord,\n stringField,\n type ToolResultClassification,\n} from \"@athenaintel/agent-runtime\";\nimport { ArrowRightIcon, FolderIcon, LinkIcon, SearchIcon } from \"lucide-react\";\nimport { memo, type ReactNode } from \"react\";\nimport { type AssetType, useAssetPanelStore } from \"../assets/asset-panel-store\";\nimport {\n CHIP_ICON_CLASS,\n CHIP_LINK_CLASS,\n CHIP_PILL_CLASS,\n} from \"../chat-ui/mentions/mention-chip\";\nimport {\n MentionIcon,\n useThumbnailLoadFailure,\n} from \"../chat-ui/mentions/suggestions/components/mention-icon\";\nimport { useAssetIconAppUrl } from \"../chat-ui/mentions/use-asset-icon-app-url\";\nimport {\n assetTypeToIcon,\n assetTypeToThumb,\n} from \"../chat-ui/mentions/suggestions/data/sources/asset-type-icons\";\nimport { cn } from \"../lib/utils\";\nimport { ExpandableSection, normalizeResult, ToolCard, type ToolStatus } from \"./primitives\";\nimport { ToolFallback } from \"./tool-fallback\";\n\n// ─── Shared by the Drive and project manager cards ───────────────────\n\n/** A running title without its trailing \"...\": what a stopped or waiting call was doing. */\nexport function withoutEllipsis(title: string): string {\n return title.replace(/(?:\\.{3}|…)\\s*$/u, \"\");\n}\n\n/** How a card shows its call: the status it renders with, and why the call failed when it did. */\nexport interface ToolCardOutcome {\n status: ToolStatus;\n failure: string | null;\n}\n\n/**\n * The card's status. A call the runtime stopped reads as failed with the\n * runtime's reason; a settled call reads as failed when its result reports a\n * failure in the tool's own words (`resultFailure`, as Olympus words it) or\n * the shared classifier reads one. A refusal at the approval gate never gets\n * here: the generic card draws it.\n */\nexport function toolCardOutcome({\n status,\n classification,\n resultFailure = null,\n}: {\n status: ToolCallMessagePartStatus | undefined;\n classification: ToolResultClassification;\n resultFailure?: string | null;\n}): ToolCardOutcome {\n if (status?.type === \"running\") return { status: \"running\", failure: null };\n const classified = classification.state === \"error\" ? classification.failure.message : null;\n const failure = status?.type === \"incomplete\" ? classified : (resultFailure ?? classified);\n if (failure) return { status: \"incomplete\", failure };\n return { status: status?.type ?? \"complete\", failure: null };\n}\n\n/** The asset panel's name for an asset type, when it has one; the panel opens any other as a plain asset. */\nfunction panelAssetType(assetType: string | undefined): AssetType | undefined {\n switch (assetType) {\n case \"presentation\":\n case \"spreadsheet\":\n case \"document\":\n case \"notebook\":\n return assetType;\n default:\n return undefined;\n }\n}\n\nconst ASSET_ICON_TILE = {\n md: { box: \"size-8\", icon: \"size-4\" },\n sm: { box: \"size-6\", icon: \"size-3.5\" },\n} as const;\n\n/**\n * An asset's type icon, as the `@` menu draws it: the asset-type SVG Olympus\n * draws (`assetTypeToThumb`: the host's copy, else the chat's Athena web app's), or\n * the type's Lucide icon on a muted tile when there is none or it cannot load.\n * Olympus draws the asset's own thumbnail, which needs the asset read; its\n * type is what a result carries.\n */\nexport function AssetTypeIcon({\n assetType,\n size,\n}: {\n assetType: string | undefined;\n size: keyof typeof ASSET_ICON_TILE;\n}) {\n const tile = ASSET_ICON_TILE[size];\n const iconAppUrl = useAssetIconAppUrl();\n const thumbnailUrl = assetTypeToThumb(assetType, { appUrl: iconAppUrl });\n const thumbnail = useThumbnailLoadFailure(thumbnailUrl);\n if (thumbnailUrl && !thumbnail.failed) {\n return (\n <img ref={thumbnail.imageRef} src={thumbnailUrl} alt=\"\" className={cn(\"shrink-0\", tile.box)} />\n );\n }\n return (\n <span\n aria-hidden=\"true\"\n className={cn(\n \"flex shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground\",\n tile.box,\n )}\n >\n <MentionIcon fallbackIcon={assetTypeToIcon(assetType)} className={tile.icon} />\n </span>\n );\n}\n\n/**\n * An asset as the chip a chat message draws, opening the asset on click.\n * `title` is the asset's title when the call carried one; without it the\n * chip shows `fallbackLabel` and the asset opens unnamed, for whatever opens\n * it to name.\n */\nexport function AssetChip({\n assetId,\n title,\n fallbackLabel,\n assetType,\n}: {\n assetId: string;\n title?: string;\n fallbackLabel: string;\n assetType?: string;\n}) {\n const openAsset = useAssetPanelStore((s) => s.openAsset);\n const iconAppUrl = useAssetIconAppUrl();\n const label = title ?? fallbackLabel;\n return (\n <button\n type=\"button\"\n data-asset-id={assetId}\n title={`Open ${label}`}\n onClick={() => openAsset(assetId, { name: title, type: panelAssetType(assetType) })}\n className={cn(CHIP_PILL_CLASS, CHIP_LINK_CLASS, \"max-w-[275px] text-xs\")}\n >\n <MentionIcon\n thumbnailUrl={assetTypeToThumb(assetType, { appUrl: iconAppUrl })}\n fallbackIcon={assetTypeToIcon(assetType)}\n className={CHIP_ICON_CLASS}\n />\n <span className=\"min-w-0 max-w-[180px] overflow-hidden text-ellipsis\">{label}</span>\n </button>\n );\n}\n\n/** The line under a card's title that finishes its sentence with chips (\"for [project]\"). */\nexport function AssetChipLine({ children }: { children: ReactNode }) {\n return (\n <div className=\"flex flex-wrap items-center gap-1.5 border-t border-border/40 px-4 py-2 text-xs text-muted-foreground\">\n {children}\n </div>\n );\n}\n\n/** The record a tool call's arguments are, or an empty one while they stream. */\nexport function argsRecord(args: unknown): Record<string, unknown> {\n return isRecord(args) ? args : {};\n}\n\n/** A number field of a result record, when it is one. */\nexport function numberField(\n record: Record<string, unknown> | null | undefined,\n key: string,\n): number | undefined {\n const value = record?.[key];\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\n// ─── search_assets ───────────────────────────────────────────────────\n\n/** One match, as the card lists it. */\nexport interface SearchAssetRow {\n id: string;\n title: string;\n /** The type its icon is drawn for (`athena_converted_type`, else `athena_original_type`). */\n assetType: string | undefined;\n creator: string;\n updatedAt: string | undefined;\n workspaceAccess: string | undefined;\n}\n\nexport interface SearchAssetsResult {\n rows: SearchAssetRow[];\n /** `returned_count`: this page's matches. */\n count: number;\n /** The reason a search failed (`error_message`). */\n errorMessage: string | null;\n}\n\nfunction searchAssetCreator(asset: Record<string, unknown>): string {\n const user = isRecord(asset.created_by_user) ? asset.created_by_user : null;\n const fullName = [stringField(user, [\"first_name\"]), stringField(user, [\"last_name\"])]\n .filter(Boolean)\n .join(\" \");\n return stringField(user, [\"email\"]) ?? (fullName || null) ?? stringField(user, [\"id\"]) ?? \"Unknown\";\n}\n\n/** The page of matches agora's `search_assets` returned, or `null` for a result that is not one. */\nexport function readSearchAssetsResult(result: unknown): SearchAssetsResult | null {\n const data = normalizeResult(result);\n if (!data || !Array.isArray(data.assets)) return null;\n const rows = data.assets.flatMap((raw): SearchAssetRow[] => {\n if (!isRecord(raw)) return [];\n const id = stringField(raw, [\"id\"]);\n if (!id) return [];\n return [\n {\n id,\n title: stringField(raw, [\"title\"]) ?? \"Untitled\",\n assetType:\n stringField(raw, [\"athena_converted_type\", \"athena_original_type\", \"asset_type\"]) ??\n undefined,\n creator: searchAssetCreator(raw),\n updatedAt: stringField(raw, [\"updated_at\"]) ?? undefined,\n workspaceAccess: stringField(raw, [\"workspace_access\"]) ?? undefined,\n },\n ];\n });\n return {\n rows,\n count: numberField(data, \"returned_count\") ?? rows.length,\n errorMessage: stringField(data, [\"error_message\"]),\n };\n}\n\nfunction updatedDate(updatedAt: string | undefined): string | null {\n if (!updatedAt) return null;\n const date = new Date(updatedAt);\n return Number.isNaN(date.getTime()) ? null : date.toLocaleDateString();\n}\n\nfunction SearchAssetResultRow({ row, divided }: { row: SearchAssetRow; divided: boolean }) {\n const openAsset = useAssetPanelStore((s) => s.openAsset);\n const updated = updatedDate(row.updatedAt);\n return (\n <li>\n {divided ? <div aria-hidden=\"true\" className=\"ml-11 border-t border-border/60\" /> : null}\n <button\n type=\"button\"\n data-asset-id={row.id}\n onClick={() => openAsset(row.id, { name: row.title, type: panelAssetType(row.assetType) })}\n className=\"flex w-full items-start gap-2 rounded-md px-1 py-3 text-left transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary\"\n >\n <AssetTypeIcon assetType={row.assetType} size=\"md\" />\n <span className=\"flex min-w-0 flex-col gap-0.5\">\n <span className=\"break-words text-[13px] font-medium text-foreground\">{row.title}</span>\n <span className=\"text-[11px] text-muted-foreground\">Created by {row.creator}</span>\n {updated ? (\n <span className=\"text-[11px] text-muted-foreground\">Updated {updated}</span>\n ) : null}\n {row.workspaceAccess ? (\n <span className=\"text-[11px] text-muted-foreground\">{row.workspaceAccess}</span>\n ) : null}\n </span>\n </button>\n </li>\n );\n}\n\nconst SearchAssetsToolUIImpl: ToolCallMessagePartComponent = (props) => {\n const { toolName, args, result, status, isError } = props;\n const classification = classifyToolResult({ status, result, isError });\n // A search refused at the approval gate or parked by the runtime is the\n // generic card's to draw: it is neither a result nor a failure.\n if (classification.state === \"rejected\" || classification.state === \"paused\") {\n return <ToolFallback {...props} icon={SearchIcon} />;\n }\n const typedArgs = argsRecord(args);\n const keyword = stringField(typedArgs, [\"title_contains_keyword\"]);\n const data = readSearchAssetsResult(result);\n const card = toolCardOutcome({\n status,\n classification,\n resultFailure: data?.errorMessage ? `Search failed: ${data.errorMessage}` : null,\n });\n\n const running = keyword ? `Searching assets for \"${keyword}\"...` : \"Searching assets...\";\n const found = data\n ? `Found ${data.count === 1 ? \"1 asset\" : `${data.count} assets`}${keyword ? ` for \"${keyword}\"` : \"\"}`\n : `Search complete${keyword ? ` for \"${keyword}\"` : \"\"}`;\n const title =\n card.status === \"running\" ? running : card.status === \"complete\" ? found : withoutEllipsis(running);\n\n return (\n <ToolCard\n icon={SearchIcon}\n status={card.status}\n title={title}\n toolName={toolName}\n args={typedArgs}\n result={result}\n error={card.failure}\n >\n {card.status === \"complete\" && data && data.rows.length > 0 ? (\n <ExpandableSection label=\"Show assets\">\n <ul className=\"flex flex-col\">\n {data.rows.map((row, index) => (\n <SearchAssetResultRow key={`${row.id}:${index}`} row={row} divided={index > 0} />\n ))}\n </ul>\n </ExpandableSection>\n ) : null}\n </ToolCard>\n );\n};\n\nexport const SearchAssetsToolUI = memo(\n SearchAssetsToolUIImpl,\n) as unknown as ToolCallMessagePartComponent;\nSearchAssetsToolUI.displayName = \"SearchAssetsToolUI\";\n\n// ─── list_contents ───────────────────────────────────────────────────\n\n/** One top-level entry of a listing: its title, and the asset it is when the listing names one. */\nexport interface ListedEntry {\n title: string;\n assetId: string | undefined;\n /** The type its icon is drawn for. */\n assetType: string | undefined;\n}\n\nexport interface ListContentsResult {\n /** `structure_tree_ascii`: the whole tree as text. */\n tree: string | null;\n /** `tree_data`'s top level (this page of it), or `null` when the result has none. */\n entries: ListedEntry[] | null;\n pagination: { currentPage: number; totalPages: number } | null;\n}\n\nconst LISTED_NODE_ID = /(?:^|\\s)id='([^']+)'/;\nconst LISTED_NODE_KIND = /(?:^|\\s)type='([^']+)'/;\nconst LISTED_NODE_MEDIA_TYPE = /(?:^|\\s)media_type='([^']+)'/;\n\n/**\n * One listed node's id, kind (`file` / `folder`) and media type. agora\n * serializes the listing with `default=str`, so a node usually arrives as its\n * pydantic text (`name='Q3' type='folder' id='asset_…' media_type='athena/folder'\n * children={…}`, its own fields ahead of its children's); a node can also\n * arrive as an object.\n */\nfunction readListedNode(raw: unknown): { id?: string; kind?: string; mediaType?: string } {\n if (typeof raw === \"string\") {\n return {\n id: LISTED_NODE_ID.exec(raw)?.[1],\n kind: LISTED_NODE_KIND.exec(raw)?.[1],\n mediaType: LISTED_NODE_MEDIA_TYPE.exec(raw)?.[1],\n };\n }\n if (!isRecord(raw)) return {};\n return {\n id: stringField(raw, [\"id\"]) ?? undefined,\n kind: stringField(raw, [\"type\"]) ?? undefined,\n mediaType: stringField(raw, [\"media_type\"]) ?? undefined,\n };\n}\n\n/** The asset type a listed node's icon is drawn for: an Athena asset's type, a folder, or an upload's kind of file. */\nfunction listedAssetType({ kind, mediaType }: { kind?: string; mediaType?: string }): string | undefined {\n if (mediaType?.startsWith(\"athena/\")) return mediaType.slice(\"athena/\".length);\n if (kind === \"folder\") return \"folder\";\n if (mediaType === \"application/pdf\") return \"pdf\";\n const family = mediaType?.split(\"/\")[0];\n return family === \"image\" || family === \"video\" || family === \"audio\" ? family : undefined;\n}\n\n/** The listing agora's `list_contents` returned, or `null` for a result that is not a record. */\nexport function readListContentsResult(result: unknown): ListContentsResult | null {\n const data = normalizeResult(result);\n if (!data) return null;\n const treeData = isRecord(data.tree_data) ? data.tree_data : null;\n const pagination = isRecord(data.pagination) ? data.pagination : null;\n const currentPage = numberField(pagination, \"current_page\");\n const totalPages = numberField(pagination, \"total_pages\");\n return {\n tree: stringField(data, [\"structure_tree_ascii\"]),\n entries: treeData\n ? Object.entries(treeData).map(([title, raw]) => {\n const node = readListedNode(raw);\n return { title, assetId: node.id, assetType: listedAssetType(node) };\n })\n : null,\n pagination:\n currentPage !== undefined && totalPages !== undefined ? { currentPage, totalPages } : null,\n };\n}\n\nfunction ListedEntryRow({ entry, divided }: { entry: ListedEntry; divided: boolean }) {\n const openAsset = useAssetPanelStore((s) => s.openAsset);\n const { assetId } = entry;\n return (\n <li>\n {divided ? <div aria-hidden=\"true\" className=\"ml-10 border-t border-border/60\" /> : null}\n {assetId ? (\n <button\n type=\"button\"\n data-asset-id={assetId}\n onClick={() =>\n openAsset(assetId, { name: entry.title, type: panelAssetType(entry.assetType) })\n }\n className=\"flex w-full items-center gap-4 rounded-md py-2 text-left transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary\"\n >\n <AssetTypeIcon assetType={entry.assetType} size=\"sm\" />\n <span className=\"min-w-0 truncate text-[13px] font-medium text-foreground\">\n {entry.title}\n </span>\n </button>\n ) : (\n <p className=\"py-1 pl-10 text-[11px] text-muted-foreground\">{entry.title}</p>\n )}\n </li>\n );\n}\n\nconst ListContentsToolUIImpl: ToolCallMessagePartComponent = (props) => {\n const { toolName, args, result, status, isError } = props;\n const classification = classifyToolResult({ status, result, isError });\n if (classification.state === \"rejected\" || classification.state === \"paused\") {\n return <ToolFallback {...props} icon={FolderIcon} />;\n }\n const typedArgs = argsRecord(args);\n // Olympus names the listed asset by its title, read from its asset cache;\n // the call carries only its id, so the card names the workspace alone.\n const target = stringField(typedArgs, [\"asset_id\"]) ? \"\" : \" for workspace\";\n const data = readListContentsResult(result);\n const card = toolCardOutcome({ status, classification });\n\n const running = \"Listing contents...\";\n const listed = data\n ? `Contents listed - Page ${data.pagination?.currentPage ?? 1} of ${data.pagination?.totalPages ?? 1}${target}`\n : `Contents listed${target}`;\n const title =\n card.status === \"running\" ? running : card.status === \"complete\" ? listed : withoutEllipsis(running);\n const entries = data?.entries ?? [];\n const hasListing = Boolean(data && (data.tree || entries.length > 0 || data.pagination));\n\n return (\n <ToolCard\n icon={FolderIcon}\n status={card.status}\n title={title}\n toolName={toolName}\n args={typedArgs}\n result={result}\n error={card.failure}\n >\n {card.status === \"complete\" && data && hasListing ? (\n <ExpandableSection label=\"Show contents\">\n <div className=\"flex flex-col gap-3\">\n {data.tree ? (\n <pre className=\"overflow-x-auto whitespace-pre-wrap rounded bg-muted/50 p-2 text-[11px] leading-4 text-foreground\">\n {data.tree}\n </pre>\n ) : null}\n {entries.length > 0 ? (\n <div className=\"max-h-60 overflow-y-auto pr-0.5\">\n <ul className=\"flex flex-col\">\n {entries.map((entry, index) => (\n <ListedEntryRow\n key={`${entry.title}:${index}`}\n entry={entry}\n divided={index > 0 && entries[index - 1]?.assetId !== undefined}\n />\n ))}\n </ul>\n </div>\n ) : null}\n {data.pagination ? (\n <span className=\"text-[10px] text-muted-foreground\">\n Page {data.pagination.currentPage} of {data.pagination.totalPages}\n </span>\n ) : null}\n </div>\n </ExpandableSection>\n ) : null}\n </ToolCard>\n );\n};\n\nexport const ListContentsToolUI = memo(\n ListContentsToolUIImpl,\n) as unknown as ToolCallMessagePartComponent;\nListContentsToolUI.displayName = \"ListContentsToolUI\";\n\n// ─── project_links ───────────────────────────────────────────────────\n\n/**\n * Streamed or model-written `asset_ids` are not always an array: a single id\n * or a comma-separated string arrives as a string.\n */\nexport function normalizeProjectLinksAssetIds(value: unknown): string[] {\n if (Array.isArray(value)) {\n return value.filter((id): id is string => typeof id === \"string\" && id.length > 0);\n }\n if (typeof value === \"string\") {\n return value\n .split(\",\")\n .map((id) => id.trim())\n .filter((id) => id.length > 0);\n }\n return [];\n}\n\nfunction projectLinksRunningTitle({ operation, count }: { operation: string; count: number }): string {\n const links = `${count} asset link${count !== 1 ? \"s\" : \"\"}`;\n switch (operation) {\n case \"read\":\n return \"Reading project links...\";\n case \"add\":\n return `Adding ${links} to project...`;\n case \"remove\":\n return `Removing ${links} from project...`;\n case \"set\":\n return `Setting ${links} on project...`;\n default:\n return \"Managing project links...\";\n }\n}\n\nconst PROJECT_LINKS_DETAIL_LABEL: Record<string, string> = {\n read: \"Linked\",\n add: \"Added\",\n remove: \"Removed\",\n set: \"Set to\",\n};\n\nconst ProjectLinksToolUIImpl: ToolCallMessagePartComponent = (props) => {\n const { toolName, args, result, status, isError } = props;\n const classification = classifyToolResult({ status, result, isError });\n if (classification.state === \"rejected\" || classification.state === \"paused\") {\n return <ToolFallback {...props} icon={LinkIcon} />;\n }\n const typedArgs = argsRecord(args);\n const operation = stringField(typedArgs, [\"type\"]) ?? \"read\";\n const projectId = stringField(typedArgs, [\"project_id\"]);\n const argAssetIds = normalizeProjectLinksAssetIds(typedArgs.asset_ids);\n const data = normalizeResult(result);\n // Every answer agora writes in prose (\"Project with ID … not found\",\n // \"Error: …\") is a refusal; a change or a read answers in JSON.\n const prose = typeof result === \"string\" && !data ? result.trim() : \"\";\n const card = toolCardOutcome({ status, classification, resultFailure: prose || null });\n\n const assetIds =\n operation === \"read\" && Array.isArray(data?.asset_ids)\n ? normalizeProjectLinksAssetIds(data.asset_ids)\n : argAssetIds;\n const singleAsset = assetIds.length === 1 ? assetIds[0] : undefined;\n const changesOneAsset = singleAsset !== undefined && operation !== \"read\";\n const message = stringField(data, [\"message\"]);\n const projectTitle = stringField(data, [\"project_title\"]) ?? undefined;\n\n const running = projectLinksRunningTitle({ operation, count: argAssetIds.length });\n const title =\n card.status === \"running\"\n ? running\n : card.status === \"complete\"\n ? (message ?? withoutEllipsis(running))\n : withoutEllipsis(running);\n const isDone = card.status === \"complete\";\n const projectChip = projectId ? (\n <AssetChip\n assetId={projectId}\n title={projectTitle}\n fallbackLabel=\"Project\"\n assetType=\"project\"\n />\n ) : null;\n\n return (\n <ToolCard\n icon={LinkIcon}\n status={card.status}\n title={title}\n toolName={toolName}\n args={typedArgs}\n result={result}\n error={card.failure}\n >\n {isDone && changesOneAsset ? (\n <AssetChipLine>\n <AssetChip assetId={singleAsset} fallbackLabel={singleAsset} />\n {projectChip ? (\n <>\n <ArrowRightIcon aria-hidden=\"true\" className=\"size-3.5 shrink-0\" />\n {projectChip}\n </>\n ) : null}\n </AssetChipLine>\n ) : isDone && message && projectChip ? (\n <AssetChipLine>\n <span>on</span>\n {projectChip}\n </AssetChipLine>\n ) : null}\n {isDone && !changesOneAsset && assetIds.length > 0 ? (\n <ExpandableSection label=\"Show assets\">\n <div className=\"flex flex-col\">\n <p className=\"py-1 text-[11px] font-semibold text-muted-foreground\">\n {PROJECT_LINKS_DETAIL_LABEL[operation] ?? operation}\n </p>\n <ul className=\"flex flex-col divide-y divide-border/60\">\n {assetIds.map((assetId, index) => (\n <li key={`${assetId}:${index}`} className=\"py-1\">\n <AssetChip assetId={assetId} fallbackLabel={assetId} />\n </li>\n ))}\n </ul>\n </div>\n </ExpandableSection>\n ) : null}\n </ToolCard>\n );\n};\n\nexport const ProjectLinksToolUI = memo(\n ProjectLinksToolUIImpl,\n) as unknown as ToolCallMessagePartComponent;\nProjectLinksToolUI.displayName = \"ProjectLinksToolUI\";\n"],"names":["_a"],"mappings":"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"}
package/dist/version.cjs CHANGED
@@ -2,5 +2,9 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const _package = require("./react/package.json.cjs");
4
4
  const ATHENA_REACT_SDK_VERSION = _package.default.version;
5
+ const ATHENA_CLIENT_HEADER = "X-Athena-Client";
6
+ const ATHENA_REACT_CLIENT = `@athenaintel/react/${ATHENA_REACT_SDK_VERSION}`;
7
+ exports.ATHENA_CLIENT_HEADER = ATHENA_CLIENT_HEADER;
8
+ exports.ATHENA_REACT_CLIENT = ATHENA_REACT_CLIENT;
5
9
  exports.ATHENA_REACT_SDK_VERSION = ATHENA_REACT_SDK_VERSION;
6
10
  //# sourceMappingURL=version.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.cjs","sources":["../src/version.ts"],"sourcesContent":["import packageJson from '../package.json';\n\n/**\n * The SDK's own version, inlined at build time. Surfaced in diagnostics, on\n * `window.__ATHENA_SDK__.version`, and available to consumers so a host app\n * can show \"what SDK am I running\" without reading node_modules.\n */\nexport const ATHENA_REACT_SDK_VERSION: string = packageJson.version;\n"],"names":["packageJson"],"mappings":";;;AAOO,MAAM,2BAAmCA,SAAAA,QAAY;;"}
1
+ {"version":3,"file":"version.cjs","sources":["../src/version.ts"],"sourcesContent":["import packageJson from '../package.json';\n\n/**\n * The SDK's own version, inlined at build time. Surfaced in diagnostics, on\n * `window.__ATHENA_SDK__.version`, and available to consumers so a host app\n * can show \"what SDK am I running\" without reading node_modules.\n */\nexport const ATHENA_REACT_SDK_VERSION: string = packageJson.version;\n\n/**\n * The header every Athena client names itself in: `<name>/<version>`. Agora\n * counts requests by it to learn which SDK versions run where, so a breaking\n * change can wait for, and reach, the callers it affects (#55094). Telemetry\n * only: agora never admits or refuses a request by it.\n */\nexport const ATHENA_CLIENT_HEADER = 'X-Athena-Client';\n\n/** This SDK's `X-Athena-Client` value. */\nexport const ATHENA_REACT_CLIENT: string = `@athenaintel/react/${ATHENA_REACT_SDK_VERSION}`;\n"],"names":["packageJson"],"mappings":";;;AAOO,MAAM,2BAAmCA,SAAAA,QAAY;AAQrD,MAAM,uBAAuB;AAG7B,MAAM,sBAA8B,sBAAsB,wBAAwB;;;;"}
package/dist/version.d.ts CHANGED
@@ -4,3 +4,12 @@
4
4
  * can show "what SDK am I running" without reading node_modules.
5
5
  */
6
6
  export declare const ATHENA_REACT_SDK_VERSION: string;
7
+ /**
8
+ * The header every Athena client names itself in: `<name>/<version>`. Agora
9
+ * counts requests by it to learn which SDK versions run where, so a breaking
10
+ * change can wait for, and reach, the callers it affects (#55094). Telemetry
11
+ * only: agora never admits or refuses a request by it.
12
+ */
13
+ export declare const ATHENA_CLIENT_HEADER = "X-Athena-Client";
14
+ /** This SDK's `X-Athena-Client` value. */
15
+ export declare const ATHENA_REACT_CLIENT: string;
package/dist/version.js CHANGED
@@ -1,6 +1,10 @@
1
1
  import packageJson from "./react/package.json.js";
2
2
  const ATHENA_REACT_SDK_VERSION = packageJson.version;
3
+ const ATHENA_CLIENT_HEADER = "X-Athena-Client";
4
+ const ATHENA_REACT_CLIENT = `@athenaintel/react/${ATHENA_REACT_SDK_VERSION}`;
3
5
  export {
6
+ ATHENA_CLIENT_HEADER,
7
+ ATHENA_REACT_CLIENT,
4
8
  ATHENA_REACT_SDK_VERSION
5
9
  };
6
10
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sources":["../src/version.ts"],"sourcesContent":["import packageJson from '../package.json';\n\n/**\n * The SDK's own version, inlined at build time. Surfaced in diagnostics, on\n * `window.__ATHENA_SDK__.version`, and available to consumers so a host app\n * can show \"what SDK am I running\" without reading node_modules.\n */\nexport const ATHENA_REACT_SDK_VERSION: string = packageJson.version;\n"],"names":[],"mappings":";AAOO,MAAM,2BAAmC,YAAY;"}
1
+ {"version":3,"file":"version.js","sources":["../src/version.ts"],"sourcesContent":["import packageJson from '../package.json';\n\n/**\n * The SDK's own version, inlined at build time. Surfaced in diagnostics, on\n * `window.__ATHENA_SDK__.version`, and available to consumers so a host app\n * can show \"what SDK am I running\" without reading node_modules.\n */\nexport const ATHENA_REACT_SDK_VERSION: string = packageJson.version;\n\n/**\n * The header every Athena client names itself in: `<name>/<version>`. Agora\n * counts requests by it to learn which SDK versions run where, so a breaking\n * change can wait for, and reach, the callers it affects (#55094). Telemetry\n * only: agora never admits or refuses a request by it.\n */\nexport const ATHENA_CLIENT_HEADER = 'X-Athena-Client';\n\n/** This SDK's `X-Athena-Client` value. */\nexport const ATHENA_REACT_CLIENT: string = `@athenaintel/react/${ATHENA_REACT_SDK_VERSION}`;\n"],"names":[],"mappings":";AAOO,MAAM,2BAAmC,YAAY;AAQrD,MAAM,uBAAuB;AAG7B,MAAM,sBAA8B,sBAAsB,wBAAwB;"}
@@ -4,6 +4,7 @@ const mint = require("../collab/mint.cjs");
4
4
  const errors = require("../diagnostics/errors.cjs");
5
5
  const utils = require("../lib/utils.cjs");
6
6
  const credentialRenewal = require("../runtime/credential-renewal.cjs");
7
+ const sessionWorkspaceApi = require("./session-workspace-api.cjs");
7
8
  const LiveDesktopMode = { WATCH: "watch", CONTROL: "control" };
8
9
  function computerLiveDesktopSessionPath(assetId) {
9
10
  return `/api/sandbox/computer/${encodeURIComponent(assetId)}/live-desktop/session`;
@@ -82,7 +83,7 @@ async function createComputerLiveDesktopSession({
82
83
  message: refusalDetail(parsed) ?? `Opening the computer’s desktop failed (${response.status}).`,
83
84
  status: response.status,
84
85
  detail: parsed,
85
- hint: response.status === 403 ? "Watching a computer’s desktop needs edit access to it, in its own workspace." : void 0
86
+ hint: response.status === 403 ? "Watching a computer’s desktop needs edit access to it, in its own workspace." : sessionWorkspaceApi.isAssetMissingResponse({ status: response.status, body: parsed }) ? "The computer does not exist, or the signed-in user may not open it." : void 0
86
87
  });
87
88
  }
88
89
  const session = readLiveDesktopSession(parsed);
@@ -1 +1 @@
1
- {"version":3,"file":"live-desktop-api.cjs","sources":["../../src/workbench/live-desktop-api.ts"],"sourcesContent":["/**\n * A computer's live desktop, as an app the computer serves on Athena embeds it.\n *\n * `POST /api/sandbox/computer/{asset_id}/live-desktop/session` (agora\n * `web/api/computer/live_desktop.py`) is the gate: VIEW with the workspace\n * fence, the computer in the caller's current workspace, EDIT and the\n * computer role policy, for watching as for control. It answers the viewer\n * page's path (carrying a 60 s single-use ticket), or why there is nothing to\n * show. The session names the page that will frame the viewer\n * (`embed_origin`, this page's own origin): agora accepts only an Athena app\n * the caller may open in the computer's workspace, and binds the viewer's\n * `frame-ancestors` and messages to it.\n *\n * The viewer page is Selkies' own web client, served by agora from the guest.\n * Whoever controls the computer controls that page, so its messages are hints\n * for the UI (connected, failed, closed) and never trusted beyond that.\n */\nimport { getAthenaApiBaseUrl } from '../collab/mint';\nimport { AthenaSdkError } from '../diagnostics/errors';\nimport { isRecord } from '../lib/utils';\nimport { sendWithCredentialRenewal } from '../runtime/credential-renewal';\nimport type { StatewireAuthSource } from '../runtime/statewire-auth-headers';\n\nexport const LiveDesktopMode = { WATCH: 'watch', CONTROL: 'control' } as const;\nexport type LiveDesktopMode = (typeof LiveDesktopMode)[keyof typeof LiveDesktopMode];\n\n/** What the session route answered. */\nexport type LiveDesktopSession =\n | {\n status: 'ready';\n /** A path on agora's own origin, carrying the single-use ticket. */\n viewerPath: string;\n mode: LiveDesktopMode;\n /** The remote screen, when known: what the frame keeps the aspect of. */\n display: { width: number; height: number } | null;\n }\n | { status: 'display_not_running'; detail: string }\n | { status: 'unsupported'; detail: string };\n\nexport function computerLiveDesktopSessionPath(assetId: string): string {\n return `/api/sandbox/computer/${encodeURIComponent(assetId)}/live-desktop/session`;\n}\n\nfunction readDisplay(value: unknown): { width: number; height: number } | null {\n if (!isRecord(value)) return null;\n const { width, height } = value;\n return typeof width === 'number' && width > 0 && typeof height === 'number' && height > 0\n ? { width, height }\n : null;\n}\n\n/** The route's body as a session, or `null` for a shape the pane cannot use. */\nexport function readLiveDesktopSession(body: unknown): LiveDesktopSession | null {\n if (!isRecord(body)) return null;\n const detail = typeof body.detail === 'string' ? body.detail : '';\n if (body.status === 'display_not_running') return { status: 'display_not_running', detail };\n if (body.status === 'unsupported') return { status: 'unsupported', detail };\n if (body.status !== 'ready') return null;\n const { viewer_path: viewerPath, mode } = body;\n // Only a path on agora's own origin, never a protocol-relative URL.\n if (typeof viewerPath !== 'string' || !/^\\/(?!\\/)/.test(viewerPath)) return null;\n if (mode !== LiveDesktopMode.WATCH && mode !== LiveDesktopMode.CONTROL) return null;\n return { status: 'ready', viewerPath, mode, display: readDisplay(body.display) };\n}\n\n/**\n * The viewer page's URL on agora's origin. Throws when *viewerPath* would\n * leave that origin: the frame is given agora's page or nothing.\n */\nexport function liveDesktopViewerUrl({\n backendUrl,\n viewerPath,\n}: {\n backendUrl: string;\n viewerPath: string;\n}): string {\n const base = new URL(`${getAthenaApiBaseUrl(backendUrl)}/`);\n const url = new URL(viewerPath, base);\n if (url.origin !== base.origin) {\n throw new Error('The live desktop viewer must be served by the Athena API');\n }\n return url.toString();\n}\n\nfunction refusalDetail(body: unknown): string | null {\n if (!isRecord(body)) return null;\n return typeof body.detail === 'string' && body.detail ? body.detail : null;\n}\n\n/** Ask for a viewer of the computer's desktop. Every failure is an `AthenaSdkError`. */\nexport async function createComputerLiveDesktopSession({\n backendUrl,\n auth,\n assetId,\n mode,\n start,\n embedOrigin,\n signal,\n}: {\n backendUrl: string;\n auth: StatewireAuthSource;\n assetId: string;\n mode: LiveDesktopMode;\n /** Start the computer's display when it is down (this also opens its browser). */\n start: boolean;\n /** The origin of the page that will frame the viewer (this page's). */\n embedOrigin: string | null;\n signal?: AbortSignal;\n}): Promise<LiveDesktopSession> {\n const url = `${getAthenaApiBaseUrl(backendUrl)}${computerLiveDesktopSessionPath(assetId)}`;\n const body = JSON.stringify({\n start,\n mode,\n ...(embedOrigin ? { embed_origin: embedOrigin } : {}),\n });\n const send = async (headers: Record<string, string>): Promise<Response> => {\n try {\n return await fetch(url, {\n method: 'POST',\n headers: { ...headers, 'Content-Type': 'application/json' },\n body,\n signal: signal ?? null,\n });\n } catch (error) {\n if ((error instanceof DOMException || error instanceof Error) && error.name === 'AbortError') {\n throw error;\n }\n throw new AthenaSdkError({\n code: 'live_desktop_failed',\n message: 'The computer’s desktop could not be reached.',\n cause: error,\n hint: 'Check the network and that backendUrl points at the Agora API base.',\n });\n }\n };\n const response = await sendWithCredentialRenewal(auth, send);\n const parsed: unknown = await response.json().catch(() => undefined);\n if (!response.ok) {\n throw new AthenaSdkError({\n code: response.status === 401 ? 'auth_rejected' : 'live_desktop_failed',\n message:\n refusalDetail(parsed) ?? `Opening the computer’s desktop failed (${response.status}).`,\n status: response.status,\n detail: parsed,\n hint:\n response.status === 403\n ? 'Watching a computer’s desktop needs edit access to it, in its own workspace.'\n : undefined,\n });\n }\n const session = readLiveDesktopSession(parsed);\n if (!session) {\n throw new AthenaSdkError({\n code: 'live_desktop_failed',\n message: 'The computer’s desktop answered in a shape this app does not understand.',\n status: response.status,\n detail: parsed,\n });\n }\n return session;\n}\n\n/** Names the viewer page's messages (`LIVE_DESKTOP_VIEWER_MESSAGE_SOURCE` in agora). */\nexport const LIVE_DESKTOP_VIEWER_MESSAGE_SOURCE = 'athena-live-desktop';\n\n/** The viewer page's messages the pane acts on; the rest are ignored. */\nexport type LiveDesktopViewerMessage =\n | { status: 'ready' }\n | { status: 'error'; detail: string }\n | { status: 'open' }\n | { status: 'closed'; code: number; reason: string };\n\nexport function readLiveDesktopViewerMessage(data: unknown): LiveDesktopViewerMessage | null {\n if (!isRecord(data) || data.source !== LIVE_DESKTOP_VIEWER_MESSAGE_SOURCE) return null;\n switch (data.status) {\n case 'ready':\n return { status: 'ready' };\n case 'open':\n return { status: 'open' };\n case 'error':\n return typeof data.detail === 'string'\n ? { status: 'error', detail: data.detail.slice(0, 300) }\n : null;\n case 'closed':\n return typeof data.code === 'number'\n ? {\n status: 'closed',\n code: data.code,\n reason: typeof data.reason === 'string' ? data.reason.slice(0, 120) : '',\n }\n : null;\n default:\n return null;\n }\n}\n\n/**\n * Close codes agora's relay ends a view with for good\n * (`LIVE_DESKTOP_CLOSE_*` in agora `live_desktop.py`): the view is over and\n * the pane says why. Any other close is a drop Selkies re-dials by itself.\n */\nexport function finalLiveDesktopCloseNotice(code: number): string | null {\n switch (code) {\n case 4001:\n return 'The desktop session expired. Reconnect to start a new one.';\n case 4003:\n return 'You no longer have access to this computer’s desktop.';\n case 4008:\n return 'The desktop session reached its time limit, so the computer can go idle. Reconnect to keep watching.';\n default:\n return null;\n }\n}\n"],"names":["isRecord","getAthenaApiBaseUrl","AthenaSdkError","sendWithCredentialRenewal"],"mappings":"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"}
1
+ {"version":3,"file":"live-desktop-api.cjs","sources":["../../src/workbench/live-desktop-api.ts"],"sourcesContent":["/**\n * A computer's live desktop, as an app the computer serves on Athena embeds it.\n *\n * `POST /api/sandbox/computer/{asset_id}/live-desktop/session` (agora\n * `web/api/computer/live_desktop.py`) is the gate: VIEW with the workspace\n * fence, the computer in the caller's current workspace, EDIT and the\n * computer role policy, for watching as for control. It answers the viewer\n * page's path (carrying a 60 s single-use ticket), or why there is nothing to\n * show. The session names the page that will frame the viewer\n * (`embed_origin`, this page's own origin): agora accepts only an Athena app\n * the caller may open in the computer's workspace, and binds the viewer's\n * `frame-ancestors` and messages to it.\n *\n * The viewer page is Selkies' own web client, served by agora from the guest.\n * Whoever controls the computer controls that page, so its messages are hints\n * for the UI (connected, failed, closed) and never trusted beyond that.\n */\nimport { getAthenaApiBaseUrl } from '../collab/mint';\nimport { AthenaSdkError } from '../diagnostics/errors';\nimport { isRecord } from '../lib/utils';\nimport { sendWithCredentialRenewal } from '../runtime/credential-renewal';\nimport type { StatewireAuthSource } from '../runtime/statewire-auth-headers';\nimport { isAssetMissingResponse } from './session-workspace-api';\n\nexport const LiveDesktopMode = { WATCH: 'watch', CONTROL: 'control' } as const;\nexport type LiveDesktopMode = (typeof LiveDesktopMode)[keyof typeof LiveDesktopMode];\n\n/** What the session route answered. */\nexport type LiveDesktopSession =\n | {\n status: 'ready';\n /** A path on agora's own origin, carrying the single-use ticket. */\n viewerPath: string;\n mode: LiveDesktopMode;\n /** The remote screen, when known: what the frame keeps the aspect of. */\n display: { width: number; height: number } | null;\n }\n | { status: 'display_not_running'; detail: string }\n | { status: 'unsupported'; detail: string };\n\nexport function computerLiveDesktopSessionPath(assetId: string): string {\n return `/api/sandbox/computer/${encodeURIComponent(assetId)}/live-desktop/session`;\n}\n\nfunction readDisplay(value: unknown): { width: number; height: number } | null {\n if (!isRecord(value)) return null;\n const { width, height } = value;\n return typeof width === 'number' && width > 0 && typeof height === 'number' && height > 0\n ? { width, height }\n : null;\n}\n\n/** The route's body as a session, or `null` for a shape the pane cannot use. */\nexport function readLiveDesktopSession(body: unknown): LiveDesktopSession | null {\n if (!isRecord(body)) return null;\n const detail = typeof body.detail === 'string' ? body.detail : '';\n if (body.status === 'display_not_running') return { status: 'display_not_running', detail };\n if (body.status === 'unsupported') return { status: 'unsupported', detail };\n if (body.status !== 'ready') return null;\n const { viewer_path: viewerPath, mode } = body;\n // Only a path on agora's own origin, never a protocol-relative URL.\n if (typeof viewerPath !== 'string' || !/^\\/(?!\\/)/.test(viewerPath)) return null;\n if (mode !== LiveDesktopMode.WATCH && mode !== LiveDesktopMode.CONTROL) return null;\n return { status: 'ready', viewerPath, mode, display: readDisplay(body.display) };\n}\n\n/**\n * The viewer page's URL on agora's origin. Throws when *viewerPath* would\n * leave that origin: the frame is given agora's page or nothing.\n */\nexport function liveDesktopViewerUrl({\n backendUrl,\n viewerPath,\n}: {\n backendUrl: string;\n viewerPath: string;\n}): string {\n const base = new URL(`${getAthenaApiBaseUrl(backendUrl)}/`);\n const url = new URL(viewerPath, base);\n if (url.origin !== base.origin) {\n throw new Error('The live desktop viewer must be served by the Athena API');\n }\n return url.toString();\n}\n\nfunction refusalDetail(body: unknown): string | null {\n if (!isRecord(body)) return null;\n return typeof body.detail === 'string' && body.detail ? body.detail : null;\n}\n\n/** Ask for a viewer of the computer's desktop. Every failure is an `AthenaSdkError`. */\nexport async function createComputerLiveDesktopSession({\n backendUrl,\n auth,\n assetId,\n mode,\n start,\n embedOrigin,\n signal,\n}: {\n backendUrl: string;\n auth: StatewireAuthSource;\n assetId: string;\n mode: LiveDesktopMode;\n /** Start the computer's display when it is down (this also opens its browser). */\n start: boolean;\n /** The origin of the page that will frame the viewer (this page's). */\n embedOrigin: string | null;\n signal?: AbortSignal;\n}): Promise<LiveDesktopSession> {\n const url = `${getAthenaApiBaseUrl(backendUrl)}${computerLiveDesktopSessionPath(assetId)}`;\n const body = JSON.stringify({\n start,\n mode,\n ...(embedOrigin ? { embed_origin: embedOrigin } : {}),\n });\n const send = async (headers: Record<string, string>): Promise<Response> => {\n try {\n return await fetch(url, {\n method: 'POST',\n headers: { ...headers, 'Content-Type': 'application/json' },\n body,\n signal: signal ?? null,\n });\n } catch (error) {\n if ((error instanceof DOMException || error instanceof Error) && error.name === 'AbortError') {\n throw error;\n }\n throw new AthenaSdkError({\n code: 'live_desktop_failed',\n message: 'The computer’s desktop could not be reached.',\n cause: error,\n hint: 'Check the network and that backendUrl points at the Agora API base.',\n });\n }\n };\n const response = await sendWithCredentialRenewal(auth, send);\n const parsed: unknown = await response.json().catch(() => undefined);\n if (!response.ok) {\n throw new AthenaSdkError({\n code: response.status === 401 ? 'auth_rejected' : 'live_desktop_failed',\n message:\n refusalDetail(parsed) ?? `Opening the computer’s desktop failed (${response.status}).`,\n status: response.status,\n detail: parsed,\n hint:\n response.status === 403\n ? 'Watching a computer’s desktop needs edit access to it, in its own workspace.'\n : isAssetMissingResponse({ status: response.status, body: parsed })\n ? 'The computer does not exist, or the signed-in user may not open it.'\n : undefined,\n });\n }\n const session = readLiveDesktopSession(parsed);\n if (!session) {\n throw new AthenaSdkError({\n code: 'live_desktop_failed',\n message: 'The computer’s desktop answered in a shape this app does not understand.',\n status: response.status,\n detail: parsed,\n });\n }\n return session;\n}\n\n/** Names the viewer page's messages (`LIVE_DESKTOP_VIEWER_MESSAGE_SOURCE` in agora). */\nexport const LIVE_DESKTOP_VIEWER_MESSAGE_SOURCE = 'athena-live-desktop';\n\n/** The viewer page's messages the pane acts on; the rest are ignored. */\nexport type LiveDesktopViewerMessage =\n | { status: 'ready' }\n | { status: 'error'; detail: string }\n | { status: 'open' }\n | { status: 'closed'; code: number; reason: string };\n\nexport function readLiveDesktopViewerMessage(data: unknown): LiveDesktopViewerMessage | null {\n if (!isRecord(data) || data.source !== LIVE_DESKTOP_VIEWER_MESSAGE_SOURCE) return null;\n switch (data.status) {\n case 'ready':\n return { status: 'ready' };\n case 'open':\n return { status: 'open' };\n case 'error':\n return typeof data.detail === 'string'\n ? { status: 'error', detail: data.detail.slice(0, 300) }\n : null;\n case 'closed':\n return typeof data.code === 'number'\n ? {\n status: 'closed',\n code: data.code,\n reason: typeof data.reason === 'string' ? data.reason.slice(0, 120) : '',\n }\n : null;\n default:\n return null;\n }\n}\n\n/**\n * Close codes agora's relay ends a view with for good\n * (`LIVE_DESKTOP_CLOSE_*` in agora `live_desktop.py`): the view is over and\n * the pane says why. Any other close is a drop Selkies re-dials by itself.\n */\nexport function finalLiveDesktopCloseNotice(code: number): string | null {\n switch (code) {\n case 4001:\n return 'The desktop session expired. Reconnect to start a new one.';\n case 4003:\n return 'You no longer have access to this computer’s desktop.';\n case 4008:\n return 'The desktop session reached its time limit, so the computer can go idle. Reconnect to keep watching.';\n default:\n return null;\n }\n}\n"],"names":["isRecord","getAthenaApiBaseUrl","AthenaSdkError","sendWithCredentialRenewal","isAssetMissingResponse"],"mappings":"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"}
@@ -2,6 +2,7 @@ import { getAthenaApiBaseUrl } from "../collab/mint.js";
2
2
  import { AthenaSdkError } from "../diagnostics/errors.js";
3
3
  import { isRecord } from "../lib/utils.js";
4
4
  import { sendWithCredentialRenewal } from "../runtime/credential-renewal.js";
5
+ import { isAssetMissingResponse } from "./session-workspace-api.js";
5
6
  const LiveDesktopMode = { WATCH: "watch", CONTROL: "control" };
6
7
  function computerLiveDesktopSessionPath(assetId) {
7
8
  return `/api/sandbox/computer/${encodeURIComponent(assetId)}/live-desktop/session`;
@@ -80,7 +81,7 @@ async function createComputerLiveDesktopSession({
80
81
  message: refusalDetail(parsed) ?? `Opening the computer’s desktop failed (${response.status}).`,
81
82
  status: response.status,
82
83
  detail: parsed,
83
- hint: response.status === 403 ? "Watching a computer’s desktop needs edit access to it, in its own workspace." : void 0
84
+ hint: response.status === 403 ? "Watching a computer’s desktop needs edit access to it, in its own workspace." : isAssetMissingResponse({ status: response.status, body: parsed }) ? "The computer does not exist, or the signed-in user may not open it." : void 0
84
85
  });
85
86
  }
86
87
  const session = readLiveDesktopSession(parsed);