@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":"index.cjs","sources":["../../../../../../src/chat-ui/mentions/suggestions/data/sources/index.ts"],"sourcesContent":["/**\n * Mention data sources shared by every chat host.\n *\n * Each source function implements the SourceFn interface:\n * (context: SourceContext) => Promise<SourceResult>\n *\n * Sources are either:\n * - FETCHERS: Call GraphQL API (assets, folders, team, etc.)\n * - TRANSFORMERS: Return static/local data (root categories, host-provided items)\n */\n\nimport type {\n MenuItem,\n MentionChatAgent,\n MentionTool,\n SourceFn,\n SourceResult,\n SourceToRegister,\n FetchMetadata,\n WebpageMention,\n} from \"../types\";\nimport { MentionMenuSection } from \"../types\";\nimport {\n fetchGraphQL,\n SIMPLE_SEARCH_QUERY,\n PAGINATED_ASSETS_QUERY,\n WORKSPACE_MEMBERS_QUERY,\n WORKSPACE_GROUPS_QUERY,\n PERSON_MENTION_CANDIDATES_QUERY,\n TOOL_CATALOG_QUERY,\n type MentionAuthContext,\n type AssetResult,\n type WorkspaceMember,\n type WorkspaceGroup,\n type PersonMentionCandidate,\n type ToolCatalogResult,\n} from \"../api-client\";\nimport { filterItems } from \"../utils/filter-items\";\nimport { assetTypeToThumb, assetTypeToIcon } from \"./asset-type-icons\";\n\n// ── Helpers ──\n\nfunction assetToMenuItem(asset: AssetResult): MenuItem {\n const isFolder = asset.athenaOriginalType === \"folder\";\n const displayType = asset.athenaConvertedType || asset.athenaOriginalType;\n return {\n id: asset.id,\n name: asset.title || \"Untitled\",\n type: isFolder ? \"folder\" : \"asset\",\n thumbnailUrl: assetTypeToThumb(displayType),\n fallbackIcon: assetTypeToIcon(displayType),\n navigatesToScope: isFolder ? asset.id : undefined,\n visibleInScopes: new Set(),\n updatedAt: asset.updatedAt ?? undefined,\n extra: {\n athenaOriginalType: asset.athenaOriginalType,\n athenaConvertedType: asset.athenaConvertedType,\n parentFolderId: asset.parentFolderId,\n },\n };\n}\n\nasync function querySimpleSearch(\n auth: MentionAuthContext,\n opts: {\n query?: string;\n limit: number;\n offset: number;\n includeTypes?: string[];\n excludeTypes?: string[];\n },\n): Promise<{ items: MenuItem[]; hasMore: boolean }> {\n const searchRequest: Record<string, any> = {\n query: opts.query?.trim() || \"\",\n type: opts.includeTypes || [],\n notType: opts.excludeTypes || [],\n limit: opts.limit,\n offset: opts.offset,\n };\n\n const input = {\n searchRequest,\n returnFullAsset: true,\n shouldCalculateTotal: false,\n sort: { field: \"UPDATED_AT\", direction: \"DESC\" },\n filterColumns: { isArchived: false, isHidden: false },\n };\n\n const data = await fetchGraphQL<{\n simpleSearch: { assets: AssetResult[]; totalCount: number };\n }>(auth, SIMPLE_SEARCH_QUERY, { input });\n\n const assets = data.simpleSearch?.assets || [];\n return {\n items: assets.map(assetToMenuItem),\n hasMore: assets.length === opts.limit,\n };\n}\n\n// ══════════════════════════════════════════════════════════════════════\n// ROOT CATEGORIES (Transformer)\n// ══════════════════════════════════════════════════════════════════════\n\n/** The scope of the composer's Agents section (Olympus's `CHAT_AGENTS_SCOPE`). */\nexport const CHAT_AGENTS_SCOPE = \"athena_chat_agents\";\n\nexport interface RootCategoriesConfig {\n categories: string[];\n getWebpages: () => readonly WebpageMention[];\n /**\n * The agents the Agents category offers now: the category shows only while\n * there is one to name (it hides once eight are named, or for a viewer who is\n * offered none).\n */\n getChatAgents?: () => readonly MentionChatAgent[];\n}\n\nconst CATEGORY_DEFS: Record<\n string,\n { name: string; icon: string; scope: string }\n> = {\n favorites: { name: \"Favorites\", icon: \"star\", scope: \"favorites\" },\n assets: { name: \"Assets\", icon: \"file-text\", scope: \"athena_assets\" },\n projects: {\n name: \"Projects\",\n icon: \"folder-kanban\",\n scope: \"athena_projects\",\n },\n browse_profiles: {\n name: \"Browse Profiles\",\n icon: \"globe\",\n scope: \"athena_browse_profiles\",\n },\n folders: { name: \"Folders\", icon: \"folder\", scope: \"athena_folders\" },\n tools: { name: \"Tools\", icon: \"wrench\", scope: \"tools\" },\n toolkits: { name: \"Toolkits\", icon: \"package\", scope: \"toolkits\" },\n team: { name: \"Team\", icon: \"users\", scope: \"team\" },\n agents: { name: \"Agents\", icon: \"bot\", scope: CHAT_AGENTS_SCOPE },\n drives: { name: \"Drives\", icon: \"hard-drive\", scope: \"drive_catalogs\" },\n};\n\nfunction webpageDescription(webpage: WebpageMention): string {\n try {\n const hostname = new URL(webpage.url).hostname;\n return webpage.isCurrent ? `${webpage.title} · ${hostname}` : hostname;\n } catch {\n return webpage.title;\n }\n}\n\nfunction webpageToMenuItem(webpage: WebpageMention): MenuItem {\n return {\n id: `webpage-tab-${webpage.tabId}`,\n name: webpage.isCurrent ? \"This webpage\" : webpage.title,\n type: \"tab\",\n thumbnailUrl: assetTypeToThumb(\"web_page\"),\n fallbackIcon: \"globe\",\n visibleInScopes: new Set([\"root\"]),\n description: webpageDescription(webpage),\n url: webpage.url,\n menuSection: webpage.isCurrent\n ? MentionMenuSection.CURRENT_WEBPAGE\n : MentionMenuSection.OTHER_WEBPAGES,\n extra: {\n tabId: webpage.tabId,\n title: webpage.title,\n isCurrent: webpage.isCurrent,\n },\n };\n}\n\nexport function buildRootMenuItems({\n categories,\n webpages,\n hasChatAgents = false,\n}: {\n categories: readonly string[];\n webpages: readonly WebpageMention[];\n /** Whether the Agents category has an agent to offer (it shows only then). */\n hasChatAgents?: boolean;\n}): MenuItem[] {\n const webpageItems = webpages.map(webpageToMenuItem);\n const categoryItems = categories\n .filter((cat: string) => CATEGORY_DEFS[cat])\n .filter((cat: string) => cat !== \"agents\" || hasChatAgents)\n .map((cat: string) => {\n const def = CATEGORY_DEFS[cat];\n return {\n id: cat,\n name: def.name,\n type: \"menu\" as const,\n fallbackIcon: def.icon,\n visibleInScopes: new Set([\"root\"]),\n navigatesToScope: def.scope,\n isNavigationOnly: true,\n menuSection: MentionMenuSection.LIBRARY,\n };\n });\n\n return [...webpageItems, ...categoryItems];\n}\n\nexport const transformRootCategories: SourceFn<RootCategoriesConfig> = async (\n context,\n) => {\n const { sourceConfig } = context;\n const items = buildRootMenuItems({\n categories: sourceConfig.categories,\n webpages: sourceConfig.getWebpages(),\n hasChatAgents: (sourceConfig.getChatAgents?.().length ?? 0) > 0,\n });\n\n return { items, pagination: { hasMore: false } };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// ASSETS (Fetcher) — All non-folder assets via SimpleSearch\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface AssetsConfig {\n auth: MentionAuthContext;\n limit?: number;\n}\n\nexport const fetchAssets: SourceFn<AssetsConfig> = async (context) => {\n const { query, fetchState, sourceConfig } = context;\n const limit = sourceConfig.limit ?? 50;\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n const result = await querySimpleSearch(sourceConfig.auth, {\n query,\n limit,\n offset,\n excludeTypes: [\"folder\", \"catalog\", \"session\"],\n });\n\n return {\n items: result.items,\n pagination: { hasMore: result.hasMore },\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// FAVORITES (Fetcher) — Favorited assets\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface FavoritesConfig {\n auth: MentionAuthContext;\n limit?: number;\n}\n\nexport const fetchFavorites: SourceFn<FavoritesConfig> = async (context) => {\n const { query, fetchState, sourceConfig } = context;\n const limit = sourceConfig.limit ?? 50;\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n const data = await fetchGraphQL<{\n getPaginatedAssetsForWorkspace: AssetResult[];\n }>(sourceConfig.auth, PAGINATED_ASSETS_QUERY, {\n limit,\n offset,\n parentFolderId: null,\n filterTypes: null,\n filterColumns: {\n isFavorited: true,\n isArchived: false,\n isHidden: false,\n },\n });\n\n const assets = data.getPaginatedAssetsForWorkspace || [];\n const items = assets.map(assetToMenuItem);\n\n return {\n items,\n pagination: { hasMore: assets.length === limit },\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// FOLDERS (Fetcher) — All folders as flat list\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface FoldersConfig {\n auth: MentionAuthContext;\n limit?: number;\n}\n\nexport const fetchFolders: SourceFn<FoldersConfig> = async (context) => {\n const { query, fetchState, sourceConfig } = context;\n const limit = sourceConfig.limit ?? 50;\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n const result = await querySimpleSearch(sourceConfig.auth, {\n query,\n limit,\n offset,\n includeTypes: [\"folder\"],\n });\n\n return {\n items: result.items,\n pagination: { hasMore: result.hasMore },\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// FOLDER CONTENTS (Fetcher) — Contents of a specific folder\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface FolderContentsConfig {\n auth: MentionAuthContext;\n limit?: number;\n}\n\nexport const fetchFolderContents: SourceFn<FolderContentsConfig> = async (\n context,\n) => {\n const { scope, query, fetchState, sourceConfig } = context;\n const limit = sourceConfig.limit ?? 50;\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n // Scope IS the folder ID (or 'internal_drive' for root)\n const parentFolderId = scope === \"internal_drive\" ? null : scope;\n\n const data = await fetchGraphQL<{\n getPaginatedAssetsForWorkspace: AssetResult[];\n }>(sourceConfig.auth, PAGINATED_ASSETS_QUERY, {\n limit,\n offset,\n parentFolderId,\n filterTypes: null,\n filterColumns: {\n isArchived: false,\n isHidden: false,\n ...(query ? { title: [{ op: \"LIKE\", value: `%${query}%` }] } : {}),\n },\n });\n\n const rawAssets = data.getPaginatedAssetsForWorkspace || [];\n // Exclude catalogs from folder contents\n const assets = rawAssets.filter(\n (a) =>\n a.athenaConvertedType !== \"catalog\" && a.athenaOriginalType !== \"catalog\",\n );\n const items = assets.map(assetToMenuItem);\n\n return {\n items,\n pagination: {\n hasMore: rawAssets.length === limit,\n consumedCount: rawAssets.length,\n },\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// PROJECTS (Fetcher) — Project assets\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface TypedAssetsConfig {\n auth: MentionAuthContext;\n includeOnlyTypes: string[];\n limit?: number;\n}\n\nexport const fetchTypedAssets: SourceFn<TypedAssetsConfig> = async (\n context,\n) => {\n const { query, fetchState, sourceConfig } = context;\n const limit = sourceConfig.limit ?? 50;\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n const result = await querySimpleSearch(sourceConfig.auth, {\n query,\n limit,\n offset,\n includeTypes: sourceConfig.includeOnlyTypes,\n });\n\n return {\n items: result.items,\n pagination: { hasMore: result.hasMore },\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// TEAM (Fetcher) — Workspace members, the viewer's people, the workspace's groups\n// ══════════════════════════════════════════════════════════════════════\n\n/** Loads the Team list; browsing Team and every root search read one fetch. */\nexport type TeamLoader = () => Promise<MenuItem[]>;\n\nexport interface TeamConfig {\n auth: MentionAuthContext;\n /** Shared member loader, so browsing Team and searching read one fetch. */\n loadTeam?: TeamLoader;\n}\n\nexport interface TeamLoaderOptions {\n /**\n * Whether the viewer is an Athena admin, read at each load: while Person is in\n * preview the ranked people are an admin's alone, as in Olympus.\n */\n getIsAdmin?: () => boolean;\n}\n\n/**\n * Where a Team item names the saved person asset it stands for: a root search\n * drops that asset's own row, since the person is already listed once, as\n * themselves (Olympus's `SAVED_PERSON_ASSET_ID_EXTRA`).\n */\nexport const SAVED_PERSON_ASSET_ID_EXTRA = \"savedPersonAssetId\";\n\n/** How many of the viewer's people Team reads (agora's most). */\nconst PERSON_CANDIDATES_LIMIT = 500;\n\nfunction normalizeEmail(email: string | null | undefined): string {\n return (email ?? \"\").trim().toLowerCase();\n}\n\ntype MemberWithEmail = WorkspaceMember & { email: string };\n\ntype TeamEntry =\n | {\n kind: \"member\";\n member: MemberWithEmail;\n savedName: string | null;\n savedPersonAssetId: string | null;\n }\n | { kind: \"saved\"; person: PersonMentionCandidate };\n\n/**\n * One ordered Team list, as Olympus ranks it: the viewer's people in their\n * order (most recently talked to first) — a member under the name the viewer\n * saved them as, a saved person who is not a member as themselves — then the\n * members the ranking did not reach. Without people the members keep their\n * order.\n */\nexport function rankTeam({\n members,\n people,\n}: {\n members: readonly MemberWithEmail[];\n people: readonly PersonMentionCandidate[];\n}): TeamEntry[] {\n if (people.length === 0) {\n return members.map((member) => ({\n kind: \"member\",\n member,\n savedName: null,\n savedPersonAssetId: null,\n }));\n }\n const membersByEmail = new Map(\n members.map((member) => [normalizeEmail(member.email), member]),\n );\n const placed = new Set<MemberWithEmail>();\n const entries: TeamEntry[] = [];\n for (const person of people) {\n const member = membersByEmail.get(normalizeEmail(person.email));\n if (member) {\n if (placed.has(member)) continue;\n placed.add(member);\n entries.push({\n kind: \"member\",\n member,\n savedName: person.savedPersonAssetId ? person.displayName : null,\n savedPersonAssetId: person.savedPersonAssetId ?? null,\n });\n } else if (person.savedPersonAssetId) {\n entries.push({ kind: \"saved\", person });\n }\n }\n for (const member of members) {\n if (!placed.has(member)) {\n entries.push({ kind: \"member\", member, savedName: null, savedPersonAssetId: null });\n }\n }\n return entries;\n}\n\n// Person mentions are keyed on email (`mention://person?id=<email>&email=…`),\n// so a member without one cannot be mentioned.\nfunction memberToMenuItem({\n member,\n savedName,\n savedPersonAssetId,\n}: {\n member: MemberWithEmail;\n savedName: string | null;\n savedPersonAssetId: string | null;\n}): MenuItem {\n // The viewer's own name for them, else first + last name, else the email.\n const displayName =\n savedName ||\n [member.firstName, member.lastName].filter(Boolean).join(\" \").trim() ||\n member.email;\n\n return {\n id: member.email,\n name: displayName,\n type: \"user\" as const,\n fallbackIcon: \"user\",\n thumbnailUrl: member.avatarUrl || undefined,\n visibleInScopes: new Set<string>(),\n email: member.email,\n extra: {\n isAdmin: member.isAdmin,\n ...(savedPersonAssetId ? { [SAVED_PERSON_ASSET_ID_EXTRA]: savedPersonAssetId } : {}),\n },\n };\n}\n\n/** A saved person who is not a member mentions like a member: a person reference keyed on email. */\nfunction savedPersonToMenuItem(person: PersonMentionCandidate): MenuItem {\n return {\n id: person.email,\n name: person.displayName,\n type: \"user\" as const,\n fallbackIcon: \"user\",\n thumbnailUrl: person.photoUrl || undefined,\n visibleInScopes: new Set<string>(),\n email: person.email,\n ...(person.savedPersonAssetId\n ? { extra: { [SAVED_PERSON_ASSET_ID_EXTRA]: person.savedPersonAssetId } }\n : {}),\n };\n}\n\nfunction groupMemberCount(count: number): string {\n return count === 1 ? \"1 member\" : `${count} members`;\n}\n\n/**\n * A workspace group: a pointer to the group, not to its members\n * (`mention://group?id=…&name=…`). It shares nothing and notifies nobody, which\n * is why the row shows the member count rather than the members.\n */\nfunction groupToMenuItem(group: WorkspaceGroup): MenuItem {\n return {\n id: group.id,\n name: group.name,\n type: \"group\" as const,\n fallbackIcon: \"users\",\n description: groupMemberCount(group.memberCount),\n visibleInScopes: new Set<string>(),\n extra: {\n memberCount: group.memberCount,\n ...(group.slug ? { slug: group.slug } : {}),\n },\n };\n}\n\nasync function queryMembers(\n auth: MentionAuthContext & { workspaceId: string },\n): Promise<MemberWithEmail[]> {\n const data = await fetchGraphQL<{ getUsersInWorkspace: WorkspaceMember[] }>(\n auth,\n WORKSPACE_MEMBERS_QUERY,\n { workspaceId: auth.workspaceId },\n );\n return (data.getUsersInWorkspace || []).filter(\n (member): member is MemberWithEmail => Boolean(member.email),\n );\n}\n\n/** The workspace's groups, archived ones never offered; none from an agora that predates groups. */\nasync function queryGroups(\n auth: MentionAuthContext & { workspaceId: string },\n): Promise<WorkspaceGroup[]> {\n try {\n const data = await fetchGraphQL<{ getWorkspaceGroups: WorkspaceGroup[] }>(\n auth,\n WORKSPACE_GROUPS_QUERY,\n { workspaceId: auth.workspaceId },\n );\n return (data.getWorkspaceGroups || []).filter((group) => group.archivedAt == null);\n } catch {\n return [];\n }\n}\n\n/** The viewer's people, for an admin; none when agora refuses them (Person's gate, an older agora). */\nasync function queryPeople(auth: MentionAuthContext): Promise<PersonMentionCandidate[]> {\n try {\n const data = await fetchGraphQL<{ personMentionCandidates: PersonMentionCandidate[] }>(\n auth,\n PERSON_MENTION_CANDIDATES_QUERY,\n { limit: PERSON_CANDIDATES_LIMIT },\n );\n return data.personMentionCandidates || [];\n } catch {\n return [];\n }\n}\n\n/**\n * The Team list Olympus offers: the members (ranked by the viewer's people for\n * an admin, with the people they saved who are not members), then the\n * workspace's groups. The members' read decides: when it fails the list fails,\n * and the next load asks again.\n */\nasync function queryTeam(\n auth: MentionAuthContext,\n { isAdmin }: { isAdmin: boolean },\n): Promise<MenuItem[]> {\n const { workspaceId } = auth;\n if (!workspaceId) return [];\n const scoped = { ...auth, workspaceId };\n const [members, groups, people] = await Promise.all([\n queryMembers(scoped),\n queryGroups(scoped),\n isAdmin ? queryPeople(auth) : Promise.resolve<PersonMentionCandidate[]>([]),\n ]);\n return [\n ...rankTeam({ members, people }).map((entry) =>\n entry.kind === \"member\" ? memberToMenuItem(entry) : savedPersonToMenuItem(entry.person),\n ),\n ...groups.map(groupToMenuItem),\n ];\n}\n\n/**\n * One Team fetch per store (and per admin answer): every keystroke of a root\n * search reads the same list. A failed fetch is forgotten so the next one\n * retries.\n */\nexport function createTeamLoader(\n auth: MentionAuthContext,\n { getIsAdmin = () => false }: TeamLoaderOptions = {},\n): TeamLoader {\n let pending: { isAdmin: boolean; team: Promise<MenuItem[]> } | null = null;\n return () => {\n const isAdmin = getIsAdmin();\n if (pending?.isAdmin !== isAdmin) {\n const team = queryTeam(auth, { isAdmin }).catch((error: unknown) => {\n if (pending?.team === team) pending = null;\n throw error;\n });\n pending = { isAdmin, team };\n }\n return pending.team;\n };\n}\n\nexport const fetchTeam: SourceFn<TeamConfig> = async (context) => {\n const { auth, loadTeam } = context.sourceConfig;\n const items = await (loadTeam ? loadTeam() : queryTeam(auth, { isAdmin: false }));\n return { items, pagination: { hasMore: false } };\n};\n\n// Asset results never wait on the roster for longer than this; a slow roster\n// lands on a later keystroke, which reads the same pending request.\nconst TEAM_WAIT_MS = 1500;\n\nfunction withinTeamWait(members: Promise<MenuItem[]>): Promise<MenuItem[]> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<MenuItem[]>((resolve) => {\n timer = setTimeout(() => resolve([]), TEAM_WAIT_MS);\n });\n return Promise.race([members.catch(() => []), timeout]).finally(() =>\n clearTimeout(timer),\n );\n}\n\n/** The saved person assets Team lists, each with its person row. */\nfunction savedPeopleListedAsPeople(team: readonly MenuItem[]): ReadonlyMap<string, MenuItem> {\n const rows = new Map<string, MenuItem>();\n for (const item of team) {\n const assetId: unknown = item.extra?.[SAVED_PERSON_ASSET_ID_EXTRA];\n if (item.type === \"user\" && typeof assetId === \"string\") rows.set(assetId, item);\n }\n return rows;\n}\n\n/**\n * Drops the asset row of a saved person Team lists: one person is one row, the\n * person mention. A query only the asset answers (a pasted asset id) keeps the\n * asset row, since the person row cannot match it.\n */\nfunction withoutListedSavedPeople({\n items,\n listed,\n query,\n}: {\n items: MenuItem[];\n listed: ReadonlyMap<string, MenuItem>;\n query: string;\n}): MenuItem[] {\n if (listed.size === 0) return items;\n return items.filter((item) => {\n if (item.type === \"user\") return true;\n const person = listed.get(item.id);\n if (!person) return true;\n return (\n filterItems([item], query, \"global_search\").length > 0 &&\n filterItems([person], query, \"global_search\").length === 0\n );\n });\n}\n\n/**\n * Add the Team list to a root search's first page, so `@<name>` finds people\n * and groups beside assets (the cache filters them by the query), and drop the\n * asset row of a saved person Team lists, on every page. Like\n * `withProvidedTools`, `consumedCount` stays the server's row count so the\n * members never advance the asset offset; a failed member fetch leaves the\n * asset results alone.\n */\nexport function withTeam<TConfig>(\n source: SourceFn<TConfig>,\n loadTeam: TeamLoader,\n): SourceFn<TConfig> {\n // Members come from Athena: while it can't be reached, only what the wrapped source can list\n // without it stands in (a host's own tools).\n return keepOfflineItems(source, async (context) => {\n const meta = (context.fetchState.meta as FetchMetadata) || {};\n const isFirstPage = (meta.validatedCount || 0) === 0;\n const query = context.query?.trim() ?? \"\";\n const [result, team] = await Promise.all([\n source(context),\n query ? withinTeamWait(loadTeam()) : Promise.resolve([]),\n ]);\n if (team.length === 0) return result;\n const items = withoutListedSavedPeople({\n items: result.items,\n listed: savedPeopleListedAsPeople(team),\n query,\n });\n return {\n ...result,\n items: isFirstPage ? [...team, ...items] : items,\n pagination: {\n ...result.pagination,\n hasMore: result.pagination?.hasMore ?? false,\n consumedCount: result.pagination?.consumedCount ?? result.items.length,\n },\n };\n });\n}\n\n// ══════════════════════════════════════════════════════════════════════\n// TOOLS / TOOLKITS (Fetcher) — Mentionable tool catalog\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface ToolCatalogConfig {\n auth: MentionAuthContext;\n}\n\n// getToolkitToToolsMapping is already filtered server-side for the\n// authenticated user (admin-only entries, beta allowlist, workspace registry),\n// so only mention/menu visibility is applied here.\nasync function queryToolCatalog(\n auth: MentionAuthContext,\n): Promise<ToolCatalogResult[\"getToolkitToToolsMapping\"]> {\n const data = await fetchGraphQL<ToolCatalogResult>(auth, TOOL_CATALOG_QUERY);\n return data.getToolkitToToolsMapping;\n}\n\nexport const fetchTools: SourceFn<ToolCatalogConfig> = async (context) => {\n const catalog = await queryToolCatalog(context.sourceConfig.auth);\n\n const items: MenuItem[] = catalog.tools\n .filter((tool) => tool.isMentionable)\n .map((tool) => ({\n id: tool.id,\n name: tool.name,\n type: \"tool\" as const,\n fallbackIcon: tool.icon,\n description: tool.description ?? undefined,\n visibleInScopes: new Set<string>(),\n ...(tool.adminOnly ? { extra: { isAdminOnly: true } } : {}),\n }));\n\n return { items, pagination: { hasMore: false } };\n};\n\nexport const fetchToolkits: SourceFn<ToolCatalogConfig> = async (context) => {\n const catalog = await queryToolCatalog(context.sourceConfig.auth);\n\n const items: MenuItem[] = catalog.toolkits\n .filter((toolkit) => toolkit.isMentionable && !toolkit.hideFromMenu)\n .map((toolkit) => ({\n id: toolkit.name,\n name: toolkit.displayName,\n type: \"toolkit\" as const,\n fallbackIcon: toolkit.icon,\n description: toolkit.description || undefined,\n visibleInScopes: new Set<string>(),\n ...(toolkit.onlyAdmin ? { extra: { isAdminOnly: true } } : {}),\n }));\n\n return { items, pagination: { hasMore: false } };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// DRIVES (Fetcher) — Drive catalog assets\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface DrivesConfig {\n auth: MentionAuthContext;\n}\n\nexport const fetchDrives: SourceFn<DrivesConfig> = async (context) => {\n const { fetchState, sourceConfig } = context;\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n const result = await querySimpleSearch(sourceConfig.auth, {\n limit: 50,\n offset,\n includeTypes: [\"catalog\"],\n });\n\n // Drive catalogs are navigation-only (navigate into them to see contents)\n const items: MenuItem[] = result.items.map((item) => ({\n ...item,\n type: \"drive_catalog\" as const,\n fallbackIcon: \"hard-drive\",\n isNavigationOnly: true,\n navigatesToScope: item.id,\n }));\n\n // Register folder contents source for each catalog\n const sources: SourceToRegister[] = items.map((item) => ({\n scope: item.id,\n sourceFn: fetchFolderContents,\n sourceConfig: { auth: sourceConfig.auth, limit: 50 },\n }));\n\n return {\n items,\n pagination: { hasMore: result.hasMore },\n sources,\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// GLOBAL SEARCH (Fetcher) — Aggregated search across all sources\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface GlobalSearchConfig {\n auth: MentionAuthContext;\n}\n\nexport const fetchGlobalSearch: SourceFn<GlobalSearchConfig> = async (\n context,\n) => {\n const { query, fetchState, sourceConfig } = context;\n if (!query?.trim()) return { items: [], pagination: { hasMore: false } };\n\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n const result = await querySimpleSearch(sourceConfig.auth, {\n query,\n limit: 50,\n offset,\n excludeTypes: [\"catalog\", \"session\"],\n });\n\n return {\n items: result.items,\n pagination: { hasMore: result.hasMore },\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// HOST-PROVIDED TOOLS (Transformer) — a host's own Tools / Toolkits list\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface ProvidedToolsConfig {\n getTools: () => readonly MentionTool[];\n type: MentionTool[\"type\"];\n}\n\n/** Menu items for a host-provided tool list, in the host's order. */\nexport function providedToolMenuItems(\n tools: readonly MentionTool[],\n type?: MentionTool[\"type\"],\n): MenuItem[] {\n return tools\n .filter((tool) => type === undefined || tool.type === type)\n .map((tool) => ({\n id: tool.id,\n name: tool.name,\n type: tool.type,\n fallbackIcon: tool.icon ?? (tool.type === \"toolkit\" ? \"Package\" : \"Wrench\"),\n description: tool.description,\n visibleInScopes: new Set<string>(),\n }));\n}\n\nexport const transformProvidedTools: SourceFn<ProvidedToolsConfig> = async (\n context,\n) => ({\n items: providedToolMenuItems(\n context.sourceConfig.getTools(),\n context.sourceConfig.type,\n ),\n pagination: { hasMore: false },\n});\n\n/**\n * Prepend a host's tool list to another source's items so a root query matches\n * them the way it matches assets (the cache filters by query and sorts\n * toolkits first). The wrapped source's offset bookkeeping is preserved:\n * `consumedCount` stays the number of rows the server returned, so the added\n * items never advance the next page's offset.\n */\nexport function withProvidedTools<TConfig>(\n source: SourceFn<TConfig>,\n getTools: () => readonly MentionTool[],\n): SourceFn<TConfig> {\n const wrapped: SourceFn<TConfig> = async (context) => {\n const result = await source(context);\n return {\n ...result,\n items: [...providedToolMenuItems(getTools()), ...result.items],\n pagination: {\n ...result.pagination,\n hasMore: result.pagination?.hasMore ?? false,\n consumedCount: result.pagination?.consumedCount ?? result.items.length,\n },\n };\n };\n // The host's tools are the host's own: while Athena can't be reached, a search still finds them.\n OFFLINE_ITEMS.set(wrapped as SourceFn, () => providedToolMenuItems(getTools()));\n return wrapped;\n}\n\n/**\n * What a source that asks Athena can still list while Athena can't be reached: the host's own items\n * it carries (a host's tool list), by source. The source itself is never called then.\n */\nconst OFFLINE_ITEMS = new WeakMap<SourceFn, () => MenuItem[]>();\n\n/** `wrapped` keeps what `inner` lists without Athena (a wrapper that adds Athena's items alone). */\nfunction keepOfflineItems<TConfig>(\n inner: SourceFn<TConfig>,\n wrapped: SourceFn<TConfig>,\n): SourceFn<TConfig> {\n const offline = OFFLINE_ITEMS.get(inner as SourceFn);\n if (offline) OFFLINE_ITEMS.set(wrapped as SourceFn, offline);\n return wrapped;\n}\n\n/**\n * The host's own items a source asking Athena can still list while Athena can't be reached (a\n * root search's host tools), unfiltered; none for a source that holds no such items.\n */\nexport function offlineItemsOf(sourceFn: SourceFn): MenuItem[] {\n return OFFLINE_ITEMS.get(sourceFn)?.() ?? [];\n}\n\n// ══════════════════════════════════════════════════════════════════════\n// CHAT AGENTS (Transformer) — the agents a chat message can name\n// ══════════════════════════════════════════════════════════════════════\n\n/** Item ids stay apart from every other item's (asset ids, tool names) in the shared cache. */\nconst CHAT_AGENT_ITEM_ID_PREFIX = \"agent:\";\n\nexport interface ChatAgentsConfig {\n /** Reactive getter for the agents offered now. */\n getAgents: () => readonly MentionChatAgent[];\n}\n\n/**\n * The menu item that names `agent`: choosing it names the agent for the\n * message (a chip on the composer's To line) and never writes a mention into\n * the text.\n */\nexport function chatAgentMenuItem(agent: MentionChatAgent): MenuItem {\n return {\n id: `${CHAT_AGENT_ITEM_ID_PREFIX}${agent.ref}`,\n name: agent.name,\n type: \"agent\" as const,\n fallbackIcon: agent.icon || \"bot\",\n visibleInScopes: new Set<string>(),\n extra: { agentRef: agent.ref, agentAssetId: agent.assetId },\n };\n}\n\n/** The agent an `agent` item names, or `null` for any other item. */\nexport function chatAgentFromMenuItem(item: MenuItem): MentionChatAgent | null {\n if (item.type !== \"agent\") return null;\n const ref: unknown = item.extra?.agentRef;\n if (typeof ref !== \"string\" || !ref) return null;\n const assetId: unknown = item.extra?.agentAssetId;\n return {\n ref,\n name: item.name,\n assetId: typeof assetId === \"string\" && assetId ? assetId : null,\n icon: item.fallbackIcon,\n };\n}\n\n/**\n * The agents the composer offers (`MentionChatAgents.getAgents`): the person's\n * own assistant and the collab agents the agent picker lists, minus those\n * already named. agora checks every name a message carries, so nothing here\n * gates.\n */\nexport const transformChatAgents: SourceFn<ChatAgentsConfig> = async (context) => {\n const items = context.sourceConfig.getAgents().map(chatAgentMenuItem);\n return { items, pagination: { hasMore: false, totalCount: items.length } };\n};\n\n/**\n * Prepend the agents offered now to a root search, so typing an agent's name\n * after `@` finds it beside assets (the cache filters them by the query).\n * `consumedCount` stays the wrapped source's row count, so the agents never\n * advance the next page's offset. The agents are the host's own list: while\n * Athena can't be reached, a search still finds them.\n */\nexport function withChatAgents<TConfig>(\n source: SourceFn<TConfig>,\n getAgents: () => readonly MentionChatAgent[],\n): SourceFn<TConfig> {\n const wrapped: SourceFn<TConfig> = async (context) => {\n const result = await source(context);\n const agents = getAgents().map(chatAgentMenuItem);\n if (agents.length === 0) return result;\n return {\n ...result,\n items: [...agents, ...result.items],\n pagination: {\n ...result.pagination,\n hasMore: result.pagination?.hasMore ?? false,\n consumedCount: result.pagination?.consumedCount ?? result.items.length,\n },\n };\n };\n const inner = OFFLINE_ITEMS.get(source as SourceFn);\n OFFLINE_ITEMS.set(wrapped as SourceFn, () => [\n ...getAgents().map(chatAgentMenuItem),\n ...(inner?.() ?? []),\n ]);\n return wrapped;\n}\n\n// ══════════════════════════════════════════════════════════════════════\n// LOCAL SOURCES — what a scope can show while Athena can't be reached\n// ══════════════════════════════════════════════════════════════════════\n\n/**\n * The transformers: they read only what the host already holds (its tabs, its\n * own tool list, the agents it offers to name), so their scopes keep working\n * while Athena can't be reached.\n * Every other source asks Athena.\n */\nconst LOCAL_SOURCES: ReadonlySet<SourceFn> = new Set<SourceFn>([\n transformRootCategories,\n transformProvidedTools,\n transformChatAgents,\n]);\n\n/** Whether a scope's source asks Athena for its items (a fetcher, not a transformer). */\nexport function sourceAsksAthena(sourceFn: SourceFn): boolean {\n return !LOCAL_SOURCES.has(sourceFn);\n}\n"],"names":["assetTypeToThumb","assetTypeToIcon","fetchGraphQL","SIMPLE_SEARCH_QUERY","MentionMenuSection","PAGINATED_ASSETS_QUERY","WORKSPACE_MEMBERS_QUERY","WORKSPACE_GROUPS_QUERY","PERSON_MENTION_CANDIDATES_QUERY","filterItems","TOOL_CATALOG_QUERY"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../../../src/chat-ui/mentions/suggestions/data/sources/index.ts"],"sourcesContent":["/**\n * Mention data sources shared by every chat host.\n *\n * Each source function implements the SourceFn interface:\n * (context: SourceContext) => Promise<SourceResult>\n *\n * Sources are either:\n * - FETCHERS: Call GraphQL API (assets, folders, team, etc.)\n * - TRANSFORMERS: Return static/local data (root categories, host-provided items)\n */\n\nimport type {\n MenuItem,\n MentionChatAgent,\n MentionTool,\n SourceFn,\n SourceResult,\n SourceToRegister,\n FetchMetadata,\n WebpageMention,\n} from \"../types\";\nimport { MentionMenuSection } from \"../types\";\nimport {\n fetchGraphQL,\n SIMPLE_SEARCH_QUERY,\n PAGINATED_ASSETS_QUERY,\n MENTION_EMAIL_METADATA_QUERY,\n WORKSPACE_MEMBERS_QUERY,\n WORKSPACE_GROUPS_QUERY,\n PERSON_MENTION_CANDIDATES_QUERY,\n TOOL_CATALOG_QUERY,\n type MentionAuthContext,\n type AssetResult,\n type WorkspaceMember,\n type WorkspaceGroup,\n type PersonMentionCandidate,\n type ToolCatalogResult,\n} from \"../api-client\";\nimport { filterItems } from \"../utils/filter-items\";\nimport {\n assetIconAppUrl,\n assetTypeToIcon,\n assetTypeToThumb,\n emailProviderThumb,\n isEmailAssetType,\n} from \"./asset-type-icons\";\n\n// ── Helpers ──\n\n/** The type an asset row is drawn as: its own type, as Olympus's menu reads it. */\nfunction assetDisplayType(asset: AssetResult): string | null {\n return asset.athenaOriginalType || asset.athenaConvertedType;\n}\n\nfunction assetToMenuItem({\n asset,\n metadata,\n appUrl,\n}: {\n asset: AssetResult;\n /** The row's metadata, read for email rows alone (`readEmailMetadata`). */\n metadata?: unknown;\n /** The Athena web app the chat talks to, which serves the icons. */\n appUrl: string | undefined;\n}): MenuItem {\n const isFolder = asset.athenaOriginalType === \"folder\";\n const displayType = assetDisplayType(asset);\n return {\n id: asset.id,\n name: asset.title || \"Untitled\",\n type: isFolder ? \"folder\" : \"asset\",\n thumbnailUrl:\n emailProviderThumb({ assetType: displayType, metadata, appUrl }) ??\n assetTypeToThumb(displayType, { appUrl }),\n fallbackIcon: assetTypeToIcon(displayType),\n navigatesToScope: isFolder ? asset.id : undefined,\n visibleInScopes: new Set(),\n updatedAt: asset.updatedAt ?? undefined,\n extra: {\n athenaOriginalType: asset.athenaOriginalType,\n athenaConvertedType: asset.athenaConvertedType,\n parentFolderId: asset.parentFolderId,\n },\n };\n}\n\n/** How long a page waits for its email rows' metadata before it lists them with the mail icon. */\nconst EMAIL_METADATA_TIMEOUT_MS = 2_000;\n\n/**\n * The metadata of a page's email rows, which names the mailbox whose logo\n * each draws (Olympus draws Gmail's or Outlook's). Only those rows are read,\n * so the search itself stays slim; a page without one reads nothing, and a\n * failed or slow read lists the rows with the mail icon.\n */\nasync function readEmailMetadata(\n auth: MentionAuthContext,\n assets: readonly AssetResult[],\n): Promise<ReadonlyMap<string, unknown>> {\n const assetIds = assets\n .filter((asset) => isEmailAssetType(assetDisplayType(asset)))\n .map((asset) => asset.id);\n if (!assetIds.length) return new Map();\n try {\n const data = await fetchGraphQL<{\n getAssetsByIds: { id: string; athenaMetadata: unknown }[] | null;\n }>(\n auth,\n MENTION_EMAIL_METADATA_QUERY,\n { assetIds },\n typeof AbortSignal.timeout === \"function\"\n ? { signal: AbortSignal.timeout(EMAIL_METADATA_TIMEOUT_MS) }\n : {},\n );\n return new Map(\n (data.getAssetsByIds ?? []).map((row) => [row.id, row.athenaMetadata]),\n );\n } catch {\n return new Map();\n }\n}\n\n/** A page of assets as menu items, each email row with its mailbox's logo. */\nasync function assetsToMenuItems(\n auth: MentionAuthContext,\n assets: readonly AssetResult[],\n): Promise<MenuItem[]> {\n const metadata = await readEmailMetadata(auth, assets);\n const appUrl = assetIconAppUrl({ appUrl: auth.appUrl, backendUrl: auth.backendUrl }) ?? undefined;\n return assets.map((asset) =>\n assetToMenuItem({ asset, metadata: metadata.get(asset.id), appUrl }),\n );\n}\n\nasync function querySimpleSearch(\n auth: MentionAuthContext,\n opts: {\n query?: string;\n limit: number;\n offset: number;\n includeTypes?: string[];\n excludeTypes?: string[];\n },\n): Promise<{ items: MenuItem[]; hasMore: boolean }> {\n const searchRequest: Record<string, any> = {\n query: opts.query?.trim() || \"\",\n type: opts.includeTypes || [],\n notType: opts.excludeTypes || [],\n limit: opts.limit,\n offset: opts.offset,\n };\n\n const input = {\n searchRequest,\n returnFullAsset: true,\n shouldCalculateTotal: false,\n sort: { field: \"UPDATED_AT\", direction: \"DESC\" },\n filterColumns: { isArchived: false, isHidden: false },\n };\n\n const data = await fetchGraphQL<{\n simpleSearch: { assets: AssetResult[]; totalCount: number };\n }>(auth, SIMPLE_SEARCH_QUERY, { input });\n\n const assets = data.simpleSearch?.assets || [];\n return {\n items: await assetsToMenuItems(auth, assets),\n hasMore: assets.length === opts.limit,\n };\n}\n\n// ══════════════════════════════════════════════════════════════════════\n// ROOT CATEGORIES (Transformer)\n// ══════════════════════════════════════════════════════════════════════\n\n/** The scope of the composer's Agents section (Olympus's `CHAT_AGENTS_SCOPE`). */\nexport const CHAT_AGENTS_SCOPE = \"athena_chat_agents\";\n\nexport interface RootCategoriesConfig {\n categories: string[];\n getWebpages: () => readonly WebpageMention[];\n /**\n * The agents the Agents category offers now: the category shows only while\n * there is one to name (it hides once eight are named, or for a viewer who is\n * offered none).\n */\n getChatAgents?: () => readonly MentionChatAgent[];\n}\n\nconst CATEGORY_DEFS: Record<\n string,\n { name: string; icon: string; scope: string }\n> = {\n favorites: { name: \"Favorites\", icon: \"star\", scope: \"favorites\" },\n assets: { name: \"Assets\", icon: \"file-text\", scope: \"athena_assets\" },\n projects: {\n name: \"Projects\",\n icon: \"folder-kanban\",\n scope: \"athena_projects\",\n },\n browse_profiles: {\n name: \"Browse Profiles\",\n icon: \"globe\",\n scope: \"athena_browse_profiles\",\n },\n folders: { name: \"Folders\", icon: \"folder\", scope: \"athena_folders\" },\n tools: { name: \"Tools\", icon: \"wrench\", scope: \"tools\" },\n toolkits: { name: \"Toolkits\", icon: \"package\", scope: \"toolkits\" },\n team: { name: \"Team\", icon: \"users\", scope: \"team\" },\n agents: { name: \"Agents\", icon: \"bot\", scope: CHAT_AGENTS_SCOPE },\n drives: { name: \"Drives\", icon: \"hard-drive\", scope: \"drive_catalogs\" },\n};\n\nfunction webpageDescription(webpage: WebpageMention): string {\n try {\n const hostname = new URL(webpage.url).hostname;\n return webpage.isCurrent ? `${webpage.title} · ${hostname}` : hostname;\n } catch {\n return webpage.title;\n }\n}\n\nfunction webpageToMenuItem(webpage: WebpageMention): MenuItem {\n return {\n id: `webpage-tab-${webpage.tabId}`,\n name: webpage.isCurrent ? \"This webpage\" : webpage.title,\n type: \"tab\",\n thumbnailUrl: assetTypeToThumb(\"web_page\"),\n fallbackIcon: \"globe\",\n visibleInScopes: new Set([\"root\"]),\n description: webpageDescription(webpage),\n url: webpage.url,\n menuSection: webpage.isCurrent\n ? MentionMenuSection.CURRENT_WEBPAGE\n : MentionMenuSection.OTHER_WEBPAGES,\n extra: {\n tabId: webpage.tabId,\n title: webpage.title,\n isCurrent: webpage.isCurrent,\n },\n };\n}\n\nexport function buildRootMenuItems({\n categories,\n webpages,\n hasChatAgents = false,\n}: {\n categories: readonly string[];\n webpages: readonly WebpageMention[];\n /** Whether the Agents category has an agent to offer (it shows only then). */\n hasChatAgents?: boolean;\n}): MenuItem[] {\n const webpageItems = webpages.map(webpageToMenuItem);\n const categoryItems = categories\n .filter((cat: string) => CATEGORY_DEFS[cat])\n .filter((cat: string) => cat !== \"agents\" || hasChatAgents)\n .map((cat: string) => {\n const def = CATEGORY_DEFS[cat];\n return {\n id: cat,\n name: def.name,\n type: \"menu\" as const,\n fallbackIcon: def.icon,\n visibleInScopes: new Set([\"root\"]),\n navigatesToScope: def.scope,\n isNavigationOnly: true,\n menuSection: MentionMenuSection.LIBRARY,\n };\n });\n\n return [...webpageItems, ...categoryItems];\n}\n\nexport const transformRootCategories: SourceFn<RootCategoriesConfig> = async (\n context,\n) => {\n const { sourceConfig } = context;\n const items = buildRootMenuItems({\n categories: sourceConfig.categories,\n webpages: sourceConfig.getWebpages(),\n hasChatAgents: (sourceConfig.getChatAgents?.().length ?? 0) > 0,\n });\n\n return { items, pagination: { hasMore: false } };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// ASSETS (Fetcher) — All non-folder assets via SimpleSearch\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface AssetsConfig {\n auth: MentionAuthContext;\n limit?: number;\n}\n\nexport const fetchAssets: SourceFn<AssetsConfig> = async (context) => {\n const { query, fetchState, sourceConfig } = context;\n const limit = sourceConfig.limit ?? 50;\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n const result = await querySimpleSearch(sourceConfig.auth, {\n query,\n limit,\n offset,\n excludeTypes: [\"folder\", \"catalog\", \"session\"],\n });\n\n return {\n items: result.items,\n pagination: { hasMore: result.hasMore },\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// FAVORITES (Fetcher) — Favorited assets\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface FavoritesConfig {\n auth: MentionAuthContext;\n limit?: number;\n}\n\nexport const fetchFavorites: SourceFn<FavoritesConfig> = async (context) => {\n const { query, fetchState, sourceConfig } = context;\n const limit = sourceConfig.limit ?? 50;\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n const data = await fetchGraphQL<{\n getPaginatedAssetsForWorkspace: AssetResult[];\n }>(sourceConfig.auth, PAGINATED_ASSETS_QUERY, {\n limit,\n offset,\n parentFolderId: null,\n filterTypes: null,\n filterColumns: {\n isFavorited: true,\n isArchived: false,\n isHidden: false,\n },\n });\n\n const assets = data.getPaginatedAssetsForWorkspace || [];\n const items = await assetsToMenuItems(sourceConfig.auth, assets);\n\n return {\n items,\n pagination: { hasMore: assets.length === limit },\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// FOLDERS (Fetcher) — All folders as flat list\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface FoldersConfig {\n auth: MentionAuthContext;\n limit?: number;\n}\n\nexport const fetchFolders: SourceFn<FoldersConfig> = async (context) => {\n const { query, fetchState, sourceConfig } = context;\n const limit = sourceConfig.limit ?? 50;\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n const result = await querySimpleSearch(sourceConfig.auth, {\n query,\n limit,\n offset,\n includeTypes: [\"folder\"],\n });\n\n return {\n items: result.items,\n pagination: { hasMore: result.hasMore },\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// FOLDER CONTENTS (Fetcher) — Contents of a specific folder\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface FolderContentsConfig {\n auth: MentionAuthContext;\n limit?: number;\n}\n\nexport const fetchFolderContents: SourceFn<FolderContentsConfig> = async (\n context,\n) => {\n const { scope, query, fetchState, sourceConfig } = context;\n const limit = sourceConfig.limit ?? 50;\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n // Scope IS the folder ID (or 'internal_drive' for root)\n const parentFolderId = scope === \"internal_drive\" ? null : scope;\n\n const data = await fetchGraphQL<{\n getPaginatedAssetsForWorkspace: AssetResult[];\n }>(sourceConfig.auth, PAGINATED_ASSETS_QUERY, {\n limit,\n offset,\n parentFolderId,\n filterTypes: null,\n filterColumns: {\n isArchived: false,\n isHidden: false,\n ...(query ? { title: [{ op: \"LIKE\", value: `%${query}%` }] } : {}),\n },\n });\n\n const rawAssets = data.getPaginatedAssetsForWorkspace || [];\n // Exclude catalogs from folder contents\n const assets = rawAssets.filter(\n (a) =>\n a.athenaConvertedType !== \"catalog\" && a.athenaOriginalType !== \"catalog\",\n );\n const items = await assetsToMenuItems(sourceConfig.auth, assets);\n\n return {\n items,\n pagination: {\n hasMore: rawAssets.length === limit,\n consumedCount: rawAssets.length,\n },\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// PROJECTS (Fetcher) — Project assets\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface TypedAssetsConfig {\n auth: MentionAuthContext;\n includeOnlyTypes: string[];\n limit?: number;\n}\n\nexport const fetchTypedAssets: SourceFn<TypedAssetsConfig> = async (\n context,\n) => {\n const { query, fetchState, sourceConfig } = context;\n const limit = sourceConfig.limit ?? 50;\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n const result = await querySimpleSearch(sourceConfig.auth, {\n query,\n limit,\n offset,\n includeTypes: sourceConfig.includeOnlyTypes,\n });\n\n return {\n items: result.items,\n pagination: { hasMore: result.hasMore },\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// TEAM (Fetcher) — Workspace members, the viewer's people, the workspace's groups\n// ══════════════════════════════════════════════════════════════════════\n\n/** Loads the Team list; browsing Team and every root search read one fetch. */\nexport type TeamLoader = () => Promise<MenuItem[]>;\n\nexport interface TeamConfig {\n auth: MentionAuthContext;\n /** Shared member loader, so browsing Team and searching read one fetch. */\n loadTeam?: TeamLoader;\n}\n\nexport interface TeamLoaderOptions {\n /**\n * Whether the viewer is an Athena admin, read at each load: while Person is in\n * preview the ranked people are an admin's alone, as in Olympus.\n */\n getIsAdmin?: () => boolean;\n}\n\n/**\n * Where a Team item names the saved person asset it stands for: a root search\n * drops that asset's own row, since the person is already listed once, as\n * themselves (Olympus's `SAVED_PERSON_ASSET_ID_EXTRA`).\n */\nexport const SAVED_PERSON_ASSET_ID_EXTRA = \"savedPersonAssetId\";\n\n/** How many of the viewer's people Team reads (agora's most). */\nconst PERSON_CANDIDATES_LIMIT = 500;\n\nfunction normalizeEmail(email: string | null | undefined): string {\n return (email ?? \"\").trim().toLowerCase();\n}\n\ntype MemberWithEmail = WorkspaceMember & { email: string };\n\ntype TeamEntry =\n | {\n kind: \"member\";\n member: MemberWithEmail;\n savedName: string | null;\n savedPersonAssetId: string | null;\n }\n | { kind: \"saved\"; person: PersonMentionCandidate };\n\n/**\n * One ordered Team list, as Olympus ranks it: the viewer's people in their\n * order (most recently talked to first) — a member under the name the viewer\n * saved them as, a saved person who is not a member as themselves — then the\n * members the ranking did not reach. Without people the members keep their\n * order.\n */\nexport function rankTeam({\n members,\n people,\n}: {\n members: readonly MemberWithEmail[];\n people: readonly PersonMentionCandidate[];\n}): TeamEntry[] {\n if (people.length === 0) {\n return members.map((member) => ({\n kind: \"member\",\n member,\n savedName: null,\n savedPersonAssetId: null,\n }));\n }\n const membersByEmail = new Map(\n members.map((member) => [normalizeEmail(member.email), member]),\n );\n const placed = new Set<MemberWithEmail>();\n const entries: TeamEntry[] = [];\n for (const person of people) {\n const member = membersByEmail.get(normalizeEmail(person.email));\n if (member) {\n if (placed.has(member)) continue;\n placed.add(member);\n entries.push({\n kind: \"member\",\n member,\n savedName: person.savedPersonAssetId ? person.displayName : null,\n savedPersonAssetId: person.savedPersonAssetId ?? null,\n });\n } else if (person.savedPersonAssetId) {\n entries.push({ kind: \"saved\", person });\n }\n }\n for (const member of members) {\n if (!placed.has(member)) {\n entries.push({ kind: \"member\", member, savedName: null, savedPersonAssetId: null });\n }\n }\n return entries;\n}\n\n// Person mentions are keyed on email (`mention://person?id=<email>&email=…`),\n// so a member without one cannot be mentioned.\nfunction memberToMenuItem({\n member,\n savedName,\n savedPersonAssetId,\n}: {\n member: MemberWithEmail;\n savedName: string | null;\n savedPersonAssetId: string | null;\n}): MenuItem {\n // The viewer's own name for them, else first + last name, else the email.\n const displayName =\n savedName ||\n [member.firstName, member.lastName].filter(Boolean).join(\" \").trim() ||\n member.email;\n\n return {\n id: member.email,\n name: displayName,\n type: \"user\" as const,\n fallbackIcon: \"user\",\n thumbnailUrl: member.avatarUrl || undefined,\n visibleInScopes: new Set<string>(),\n email: member.email,\n extra: {\n isAdmin: member.isAdmin,\n ...(savedPersonAssetId ? { [SAVED_PERSON_ASSET_ID_EXTRA]: savedPersonAssetId } : {}),\n },\n };\n}\n\n/** A saved person who is not a member mentions like a member: a person reference keyed on email. */\nfunction savedPersonToMenuItem(person: PersonMentionCandidate): MenuItem {\n return {\n id: person.email,\n name: person.displayName,\n type: \"user\" as const,\n fallbackIcon: \"user\",\n thumbnailUrl: person.photoUrl || undefined,\n visibleInScopes: new Set<string>(),\n email: person.email,\n ...(person.savedPersonAssetId\n ? { extra: { [SAVED_PERSON_ASSET_ID_EXTRA]: person.savedPersonAssetId } }\n : {}),\n };\n}\n\nfunction groupMemberCount(count: number): string {\n return count === 1 ? \"1 member\" : `${count} members`;\n}\n\n/**\n * A workspace group: a pointer to the group, not to its members\n * (`mention://group?id=…&name=…`). It shares nothing and notifies nobody, which\n * is why the row shows the member count rather than the members.\n */\nfunction groupToMenuItem(group: WorkspaceGroup): MenuItem {\n return {\n id: group.id,\n name: group.name,\n type: \"group\" as const,\n fallbackIcon: \"users\",\n description: groupMemberCount(group.memberCount),\n visibleInScopes: new Set<string>(),\n extra: {\n memberCount: group.memberCount,\n ...(group.slug ? { slug: group.slug } : {}),\n },\n };\n}\n\nasync function queryMembers(\n auth: MentionAuthContext & { workspaceId: string },\n): Promise<MemberWithEmail[]> {\n const data = await fetchGraphQL<{ getUsersInWorkspace: WorkspaceMember[] }>(\n auth,\n WORKSPACE_MEMBERS_QUERY,\n { workspaceId: auth.workspaceId },\n );\n return (data.getUsersInWorkspace || []).filter(\n (member): member is MemberWithEmail => Boolean(member.email),\n );\n}\n\n/** The workspace's groups, archived ones never offered; none from an agora that predates groups. */\nasync function queryGroups(\n auth: MentionAuthContext & { workspaceId: string },\n): Promise<WorkspaceGroup[]> {\n try {\n const data = await fetchGraphQL<{ getWorkspaceGroups: WorkspaceGroup[] }>(\n auth,\n WORKSPACE_GROUPS_QUERY,\n { workspaceId: auth.workspaceId },\n );\n return (data.getWorkspaceGroups || []).filter((group) => group.archivedAt == null);\n } catch {\n return [];\n }\n}\n\n/** The viewer's people, for an admin; none when agora refuses them (Person's gate, an older agora). */\nasync function queryPeople(auth: MentionAuthContext): Promise<PersonMentionCandidate[]> {\n try {\n const data = await fetchGraphQL<{ personMentionCandidates: PersonMentionCandidate[] }>(\n auth,\n PERSON_MENTION_CANDIDATES_QUERY,\n { limit: PERSON_CANDIDATES_LIMIT },\n );\n return data.personMentionCandidates || [];\n } catch {\n return [];\n }\n}\n\n/**\n * The Team list Olympus offers: the members (ranked by the viewer's people for\n * an admin, with the people they saved who are not members), then the\n * workspace's groups. The members' read decides: when it fails the list fails,\n * and the next load asks again.\n */\nasync function queryTeam(\n auth: MentionAuthContext,\n { isAdmin }: { isAdmin: boolean },\n): Promise<MenuItem[]> {\n const { workspaceId } = auth;\n if (!workspaceId) return [];\n const scoped = { ...auth, workspaceId };\n const [members, groups, people] = await Promise.all([\n queryMembers(scoped),\n queryGroups(scoped),\n isAdmin ? queryPeople(auth) : Promise.resolve<PersonMentionCandidate[]>([]),\n ]);\n return [\n ...rankTeam({ members, people }).map((entry) =>\n entry.kind === \"member\" ? memberToMenuItem(entry) : savedPersonToMenuItem(entry.person),\n ),\n ...groups.map(groupToMenuItem),\n ];\n}\n\n/**\n * One Team fetch per store (and per admin answer): every keystroke of a root\n * search reads the same list. A failed fetch is forgotten so the next one\n * retries.\n */\nexport function createTeamLoader(\n auth: MentionAuthContext,\n { getIsAdmin = () => false }: TeamLoaderOptions = {},\n): TeamLoader {\n let pending: { isAdmin: boolean; team: Promise<MenuItem[]> } | null = null;\n return () => {\n const isAdmin = getIsAdmin();\n if (pending?.isAdmin !== isAdmin) {\n const team = queryTeam(auth, { isAdmin }).catch((error: unknown) => {\n if (pending?.team === team) pending = null;\n throw error;\n });\n pending = { isAdmin, team };\n }\n return pending.team;\n };\n}\n\nexport const fetchTeam: SourceFn<TeamConfig> = async (context) => {\n const { auth, loadTeam } = context.sourceConfig;\n const items = await (loadTeam ? loadTeam() : queryTeam(auth, { isAdmin: false }));\n return { items, pagination: { hasMore: false } };\n};\n\n// Asset results never wait on the roster for longer than this; a slow roster\n// lands on a later keystroke, which reads the same pending request.\nconst TEAM_WAIT_MS = 1500;\n\nfunction withinTeamWait(members: Promise<MenuItem[]>): Promise<MenuItem[]> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<MenuItem[]>((resolve) => {\n timer = setTimeout(() => resolve([]), TEAM_WAIT_MS);\n });\n return Promise.race([members.catch(() => []), timeout]).finally(() =>\n clearTimeout(timer),\n );\n}\n\n/** The saved person assets Team lists, each with its person row. */\nfunction savedPeopleListedAsPeople(team: readonly MenuItem[]): ReadonlyMap<string, MenuItem> {\n const rows = new Map<string, MenuItem>();\n for (const item of team) {\n const assetId: unknown = item.extra?.[SAVED_PERSON_ASSET_ID_EXTRA];\n if (item.type === \"user\" && typeof assetId === \"string\") rows.set(assetId, item);\n }\n return rows;\n}\n\n/**\n * Drops the asset row of a saved person Team lists: one person is one row, the\n * person mention. A query only the asset answers (a pasted asset id) keeps the\n * asset row, since the person row cannot match it.\n */\nfunction withoutListedSavedPeople({\n items,\n listed,\n query,\n}: {\n items: MenuItem[];\n listed: ReadonlyMap<string, MenuItem>;\n query: string;\n}): MenuItem[] {\n if (listed.size === 0) return items;\n return items.filter((item) => {\n if (item.type === \"user\") return true;\n const person = listed.get(item.id);\n if (!person) return true;\n return (\n filterItems([item], query, \"global_search\").length > 0 &&\n filterItems([person], query, \"global_search\").length === 0\n );\n });\n}\n\n/**\n * Add the Team list to a root search's first page, so `@<name>` finds people\n * and groups beside assets (the cache filters them by the query), and drop the\n * asset row of a saved person Team lists, on every page. Like\n * `withProvidedTools`, `consumedCount` stays the server's row count so the\n * members never advance the asset offset; a failed member fetch leaves the\n * asset results alone.\n */\nexport function withTeam<TConfig>(\n source: SourceFn<TConfig>,\n loadTeam: TeamLoader,\n): SourceFn<TConfig> {\n // Members come from Athena: while it can't be reached, only what the wrapped source can list\n // without it stands in (a host's own tools).\n return keepOfflineItems(source, async (context) => {\n const meta = (context.fetchState.meta as FetchMetadata) || {};\n const isFirstPage = (meta.validatedCount || 0) === 0;\n const query = context.query?.trim() ?? \"\";\n const [result, team] = await Promise.all([\n source(context),\n query ? withinTeamWait(loadTeam()) : Promise.resolve([]),\n ]);\n if (team.length === 0) return result;\n const items = withoutListedSavedPeople({\n items: result.items,\n listed: savedPeopleListedAsPeople(team),\n query,\n });\n return {\n ...result,\n items: isFirstPage ? [...team, ...items] : items,\n pagination: {\n ...result.pagination,\n hasMore: result.pagination?.hasMore ?? false,\n consumedCount: result.pagination?.consumedCount ?? result.items.length,\n },\n };\n });\n}\n\n// ══════════════════════════════════════════════════════════════════════\n// TOOLS / TOOLKITS (Fetcher) — Mentionable tool catalog\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface ToolCatalogConfig {\n auth: MentionAuthContext;\n}\n\n// getToolkitToToolsMapping is already filtered server-side for the\n// authenticated user (admin-only entries, beta allowlist, workspace registry),\n// so only mention/menu visibility is applied here.\nasync function queryToolCatalog(\n auth: MentionAuthContext,\n): Promise<ToolCatalogResult[\"getToolkitToToolsMapping\"]> {\n const data = await fetchGraphQL<ToolCatalogResult>(auth, TOOL_CATALOG_QUERY);\n return data.getToolkitToToolsMapping;\n}\n\nexport const fetchTools: SourceFn<ToolCatalogConfig> = async (context) => {\n const catalog = await queryToolCatalog(context.sourceConfig.auth);\n\n const items: MenuItem[] = catalog.tools\n .filter((tool) => tool.isMentionable)\n .map((tool) => ({\n id: tool.id,\n name: tool.name,\n type: \"tool\" as const,\n fallbackIcon: tool.icon,\n description: tool.description ?? undefined,\n visibleInScopes: new Set<string>(),\n ...(tool.adminOnly ? { extra: { isAdminOnly: true } } : {}),\n }));\n\n return { items, pagination: { hasMore: false } };\n};\n\nexport const fetchToolkits: SourceFn<ToolCatalogConfig> = async (context) => {\n const catalog = await queryToolCatalog(context.sourceConfig.auth);\n\n const items: MenuItem[] = catalog.toolkits\n .filter((toolkit) => toolkit.isMentionable && !toolkit.hideFromMenu)\n .map((toolkit) => ({\n id: toolkit.name,\n name: toolkit.displayName,\n type: \"toolkit\" as const,\n fallbackIcon: toolkit.icon,\n description: toolkit.description || undefined,\n visibleInScopes: new Set<string>(),\n ...(toolkit.onlyAdmin ? { extra: { isAdminOnly: true } } : {}),\n }));\n\n return { items, pagination: { hasMore: false } };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// DRIVES (Fetcher) — Drive catalog assets\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface DrivesConfig {\n auth: MentionAuthContext;\n}\n\nexport const fetchDrives: SourceFn<DrivesConfig> = async (context) => {\n const { fetchState, sourceConfig } = context;\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n const result = await querySimpleSearch(sourceConfig.auth, {\n limit: 50,\n offset,\n includeTypes: [\"catalog\"],\n });\n\n // Drive catalogs are navigation-only (navigate into them to see contents)\n const items: MenuItem[] = result.items.map((item) => ({\n ...item,\n type: \"drive_catalog\" as const,\n fallbackIcon: \"hard-drive\",\n isNavigationOnly: true,\n navigatesToScope: item.id,\n }));\n\n // Register folder contents source for each catalog\n const sources: SourceToRegister[] = items.map((item) => ({\n scope: item.id,\n sourceFn: fetchFolderContents,\n sourceConfig: { auth: sourceConfig.auth, limit: 50 },\n }));\n\n return {\n items,\n pagination: { hasMore: result.hasMore },\n sources,\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// GLOBAL SEARCH (Fetcher) — Aggregated search across all sources\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface GlobalSearchConfig {\n auth: MentionAuthContext;\n}\n\nexport const fetchGlobalSearch: SourceFn<GlobalSearchConfig> = async (\n context,\n) => {\n const { query, fetchState, sourceConfig } = context;\n if (!query?.trim()) return { items: [], pagination: { hasMore: false } };\n\n const meta = (fetchState.meta as FetchMetadata) || {};\n const offset = meta.validatedCount || 0;\n\n const result = await querySimpleSearch(sourceConfig.auth, {\n query,\n limit: 50,\n offset,\n excludeTypes: [\"catalog\", \"session\"],\n });\n\n return {\n items: result.items,\n pagination: { hasMore: result.hasMore },\n };\n};\n\n// ══════════════════════════════════════════════════════════════════════\n// HOST-PROVIDED TOOLS (Transformer) — a host's own Tools / Toolkits list\n// ══════════════════════════════════════════════════════════════════════\n\nexport interface ProvidedToolsConfig {\n getTools: () => readonly MentionTool[];\n type: MentionTool[\"type\"];\n}\n\n/** Menu items for a host-provided tool list, in the host's order. */\nexport function providedToolMenuItems(\n tools: readonly MentionTool[],\n type?: MentionTool[\"type\"],\n): MenuItem[] {\n return tools\n .filter((tool) => type === undefined || tool.type === type)\n .map((tool) => ({\n id: tool.id,\n name: tool.name,\n type: tool.type,\n fallbackIcon: tool.icon ?? (tool.type === \"toolkit\" ? \"Package\" : \"Wrench\"),\n description: tool.description,\n visibleInScopes: new Set<string>(),\n }));\n}\n\nexport const transformProvidedTools: SourceFn<ProvidedToolsConfig> = async (\n context,\n) => ({\n items: providedToolMenuItems(\n context.sourceConfig.getTools(),\n context.sourceConfig.type,\n ),\n pagination: { hasMore: false },\n});\n\n/**\n * Prepend a host's tool list to another source's items so a root query matches\n * them the way it matches assets (the cache filters by query and sorts\n * toolkits first). The wrapped source's offset bookkeeping is preserved:\n * `consumedCount` stays the number of rows the server returned, so the added\n * items never advance the next page's offset.\n */\nexport function withProvidedTools<TConfig>(\n source: SourceFn<TConfig>,\n getTools: () => readonly MentionTool[],\n): SourceFn<TConfig> {\n const wrapped: SourceFn<TConfig> = async (context) => {\n const result = await source(context);\n return {\n ...result,\n items: [...providedToolMenuItems(getTools()), ...result.items],\n pagination: {\n ...result.pagination,\n hasMore: result.pagination?.hasMore ?? false,\n consumedCount: result.pagination?.consumedCount ?? result.items.length,\n },\n };\n };\n // The host's tools are the host's own: while Athena can't be reached, a search still finds them.\n OFFLINE_ITEMS.set(wrapped as SourceFn, () => providedToolMenuItems(getTools()));\n return wrapped;\n}\n\n/**\n * What a source that asks Athena can still list while Athena can't be reached: the host's own items\n * it carries (a host's tool list), by source. The source itself is never called then.\n */\nconst OFFLINE_ITEMS = new WeakMap<SourceFn, () => MenuItem[]>();\n\n/** `wrapped` keeps what `inner` lists without Athena (a wrapper that adds Athena's items alone). */\nfunction keepOfflineItems<TConfig>(\n inner: SourceFn<TConfig>,\n wrapped: SourceFn<TConfig>,\n): SourceFn<TConfig> {\n const offline = OFFLINE_ITEMS.get(inner as SourceFn);\n if (offline) OFFLINE_ITEMS.set(wrapped as SourceFn, offline);\n return wrapped;\n}\n\n/**\n * The host's own items a source asking Athena can still list while Athena can't be reached (a\n * root search's host tools), unfiltered; none for a source that holds no such items.\n */\nexport function offlineItemsOf(sourceFn: SourceFn): MenuItem[] {\n return OFFLINE_ITEMS.get(sourceFn)?.() ?? [];\n}\n\n// ══════════════════════════════════════════════════════════════════════\n// CHAT AGENTS (Transformer) — the agents a chat message can name\n// ══════════════════════════════════════════════════════════════════════\n\n/** Item ids stay apart from every other item's (asset ids, tool names) in the shared cache. */\nconst CHAT_AGENT_ITEM_ID_PREFIX = \"agent:\";\n\nexport interface ChatAgentsConfig {\n /** Reactive getter for the agents offered now. */\n getAgents: () => readonly MentionChatAgent[];\n}\n\n/**\n * The menu item that names `agent`: choosing it names the agent for the\n * message (a chip on the composer's To line) and never writes a mention into\n * the text.\n */\nexport function chatAgentMenuItem(agent: MentionChatAgent): MenuItem {\n return {\n id: `${CHAT_AGENT_ITEM_ID_PREFIX}${agent.ref}`,\n name: agent.name,\n type: \"agent\" as const,\n fallbackIcon: agent.icon || \"bot\",\n visibleInScopes: new Set<string>(),\n extra: { agentRef: agent.ref, agentAssetId: agent.assetId },\n };\n}\n\n/** The agent an `agent` item names, or `null` for any other item. */\nexport function chatAgentFromMenuItem(item: MenuItem): MentionChatAgent | null {\n if (item.type !== \"agent\") return null;\n const ref: unknown = item.extra?.agentRef;\n if (typeof ref !== \"string\" || !ref) return null;\n const assetId: unknown = item.extra?.agentAssetId;\n return {\n ref,\n name: item.name,\n assetId: typeof assetId === \"string\" && assetId ? assetId : null,\n icon: item.fallbackIcon,\n };\n}\n\n/**\n * The agents the composer offers (`MentionChatAgents.getAgents`): the person's\n * own assistant and the collab agents the agent picker lists, minus those\n * already named. agora checks every name a message carries, so nothing here\n * gates.\n */\nexport const transformChatAgents: SourceFn<ChatAgentsConfig> = async (context) => {\n const items = context.sourceConfig.getAgents().map(chatAgentMenuItem);\n return { items, pagination: { hasMore: false, totalCount: items.length } };\n};\n\n/**\n * Prepend the agents offered now to a root search, so typing an agent's name\n * after `@` finds it beside assets (the cache filters them by the query).\n * `consumedCount` stays the wrapped source's row count, so the agents never\n * advance the next page's offset. The agents are the host's own list: while\n * Athena can't be reached, a search still finds them.\n */\nexport function withChatAgents<TConfig>(\n source: SourceFn<TConfig>,\n getAgents: () => readonly MentionChatAgent[],\n): SourceFn<TConfig> {\n const wrapped: SourceFn<TConfig> = async (context) => {\n const result = await source(context);\n const agents = getAgents().map(chatAgentMenuItem);\n if (agents.length === 0) return result;\n return {\n ...result,\n items: [...agents, ...result.items],\n pagination: {\n ...result.pagination,\n hasMore: result.pagination?.hasMore ?? false,\n consumedCount: result.pagination?.consumedCount ?? result.items.length,\n },\n };\n };\n const inner = OFFLINE_ITEMS.get(source as SourceFn);\n OFFLINE_ITEMS.set(wrapped as SourceFn, () => [\n ...getAgents().map(chatAgentMenuItem),\n ...(inner?.() ?? []),\n ]);\n return wrapped;\n}\n\n// ══════════════════════════════════════════════════════════════════════\n// LOCAL SOURCES — what a scope can show while Athena can't be reached\n// ══════════════════════════════════════════════════════════════════════\n\n/**\n * The transformers: they read only what the host already holds (its tabs, its\n * own tool list, the agents it offers to name), so their scopes keep working\n * while Athena can't be reached.\n * Every other source asks Athena.\n */\nconst LOCAL_SOURCES: ReadonlySet<SourceFn> = new Set<SourceFn>([\n transformRootCategories,\n transformProvidedTools,\n transformChatAgents,\n]);\n\n/** Whether a scope's source asks Athena for its items (a fetcher, not a transformer). */\nexport function sourceAsksAthena(sourceFn: SourceFn): boolean {\n return !LOCAL_SOURCES.has(sourceFn);\n}\n"],"names":["emailProviderThumb","assetTypeToThumb","assetTypeToIcon","isEmailAssetType","fetchGraphQL","MENTION_EMAIL_METADATA_QUERY","assetIconAppUrl","SIMPLE_SEARCH_QUERY","MentionMenuSection","PAGINATED_ASSETS_QUERY","WORKSPACE_MEMBERS_QUERY","WORKSPACE_GROUPS_QUERY","PERSON_MENTION_CANDIDATES_QUERY","filterItems","TOOL_CATALOG_QUERY"],"mappings":"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"}
@@ -1,15 +1,22 @@
1
1
  import { MentionMenuSection } from "../types.js";
2
- import { fetchGraphQL, SIMPLE_SEARCH_QUERY, PAGINATED_ASSETS_QUERY, TOOL_CATALOG_QUERY, WORKSPACE_MEMBERS_QUERY, WORKSPACE_GROUPS_QUERY, PERSON_MENTION_CANDIDATES_QUERY } from "../api-client.js";
2
+ import { fetchGraphQL, SIMPLE_SEARCH_QUERY, MENTION_EMAIL_METADATA_QUERY, PAGINATED_ASSETS_QUERY, TOOL_CATALOG_QUERY, WORKSPACE_MEMBERS_QUERY, WORKSPACE_GROUPS_QUERY, PERSON_MENTION_CANDIDATES_QUERY } from "../api-client.js";
3
3
  import { filterItems } from "../utils/filter-items.js";
4
- import { assetTypeToThumb, assetTypeToIcon } from "./asset-type-icons.js";
5
- function assetToMenuItem(asset) {
4
+ import { assetTypeToThumb, assetIconAppUrl, isEmailAssetType, assetTypeToIcon, emailProviderThumb } from "./asset-type-icons.js";
5
+ function assetDisplayType(asset) {
6
+ return asset.athenaOriginalType || asset.athenaConvertedType;
7
+ }
8
+ function assetToMenuItem({
9
+ asset,
10
+ metadata,
11
+ appUrl
12
+ }) {
6
13
  const isFolder = asset.athenaOriginalType === "folder";
7
- const displayType = asset.athenaConvertedType || asset.athenaOriginalType;
14
+ const displayType = assetDisplayType(asset);
8
15
  return {
9
16
  id: asset.id,
10
17
  name: asset.title || "Untitled",
11
18
  type: isFolder ? "folder" : "asset",
12
- thumbnailUrl: assetTypeToThumb(displayType),
19
+ thumbnailUrl: emailProviderThumb({ assetType: displayType, metadata, appUrl }) ?? assetTypeToThumb(displayType, { appUrl }),
13
20
  fallbackIcon: assetTypeToIcon(displayType),
14
21
  navigatesToScope: isFolder ? asset.id : void 0,
15
22
  visibleInScopes: /* @__PURE__ */ new Set(),
@@ -21,6 +28,31 @@ function assetToMenuItem(asset) {
21
28
  }
22
29
  };
23
30
  }
31
+ const EMAIL_METADATA_TIMEOUT_MS = 2e3;
32
+ async function readEmailMetadata(auth, assets) {
33
+ const assetIds = assets.filter((asset) => isEmailAssetType(assetDisplayType(asset))).map((asset) => asset.id);
34
+ if (!assetIds.length) return /* @__PURE__ */ new Map();
35
+ try {
36
+ const data = await fetchGraphQL(
37
+ auth,
38
+ MENTION_EMAIL_METADATA_QUERY,
39
+ { assetIds },
40
+ typeof AbortSignal.timeout === "function" ? { signal: AbortSignal.timeout(EMAIL_METADATA_TIMEOUT_MS) } : {}
41
+ );
42
+ return new Map(
43
+ (data.getAssetsByIds ?? []).map((row) => [row.id, row.athenaMetadata])
44
+ );
45
+ } catch {
46
+ return /* @__PURE__ */ new Map();
47
+ }
48
+ }
49
+ async function assetsToMenuItems(auth, assets) {
50
+ const metadata = await readEmailMetadata(auth, assets);
51
+ const appUrl = assetIconAppUrl({ appUrl: auth.appUrl, backendUrl: auth.backendUrl }) ?? void 0;
52
+ return assets.map(
53
+ (asset) => assetToMenuItem({ asset, metadata: metadata.get(asset.id), appUrl })
54
+ );
55
+ }
24
56
  async function querySimpleSearch(auth, opts) {
25
57
  var _a, _b;
26
58
  const searchRequest = {
@@ -40,7 +72,7 @@ async function querySimpleSearch(auth, opts) {
40
72
  const data = await fetchGraphQL(auth, SIMPLE_SEARCH_QUERY, { input });
41
73
  const assets = ((_b = data.simpleSearch) == null ? void 0 : _b.assets) || [];
42
74
  return {
43
- items: assets.map(assetToMenuItem),
75
+ items: await assetsToMenuItems(auth, assets),
44
76
  hasMore: assets.length === opts.limit
45
77
  };
46
78
  }
@@ -155,7 +187,7 @@ const fetchFavorites = async (context) => {
155
187
  }
156
188
  });
157
189
  const assets = data.getPaginatedAssetsForWorkspace || [];
158
- const items = assets.map(assetToMenuItem);
190
+ const items = await assetsToMenuItems(sourceConfig.auth, assets);
159
191
  return {
160
192
  items,
161
193
  pagination: { hasMore: assets.length === limit }
@@ -198,7 +230,7 @@ const fetchFolderContents = async (context) => {
198
230
  const assets = rawAssets.filter(
199
231
  (a) => a.athenaConvertedType !== "catalog" && a.athenaOriginalType !== "catalog"
200
232
  );
201
- const items = assets.map(assetToMenuItem);
233
+ const items = await assetsToMenuItems(sourceConfig.auth, assets);
202
234
  return {
203
235
  items,
204
236
  pagination: {