@athenaintel/react 0.60.0 → 0.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/README.md +225 -2
  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-ui/AgentTarget.cjs +11 -0
  11. package/dist/agent-ui/AgentTarget.cjs.map +1 -0
  12. package/dist/agent-ui/AgentTarget.d.ts +17 -0
  13. package/dist/agent-ui/AgentTarget.js +11 -0
  14. package/dist/agent-ui/AgentTarget.js.map +1 -0
  15. package/dist/agent-ui/AgentUiLayer.cjs +387 -0
  16. package/dist/agent-ui/AgentUiLayer.cjs.map +1 -0
  17. package/dist/agent-ui/AgentUiLayer.d.ts +40 -0
  18. package/dist/agent-ui/AgentUiLayer.js +387 -0
  19. package/dist/agent-ui/AgentUiLayer.js.map +1 -0
  20. package/dist/agent-ui/contract.cjs +104 -0
  21. package/dist/agent-ui/contract.cjs.map +1 -0
  22. package/dist/agent-ui/contract.d.ts +113 -0
  23. package/dist/agent-ui/contract.js +104 -0
  24. package/dist/agent-ui/contract.js.map +1 -0
  25. package/dist/agent-ui/driver.cjs +335 -0
  26. package/dist/agent-ui/driver.cjs.map +1 -0
  27. package/dist/agent-ui/driver.d.ts +66 -0
  28. package/dist/agent-ui/driver.js +335 -0
  29. package/dist/agent-ui/driver.js.map +1 -0
  30. package/dist/agent-ui/index.cjs +33 -0
  31. package/dist/agent-ui/index.cjs.map +1 -0
  32. package/dist/agent-ui/index.d.ts +19 -0
  33. package/dist/agent-ui/index.js +33 -0
  34. package/dist/agent-ui/index.js.map +1 -0
  35. package/dist/agent-ui/pace.cjs +121 -0
  36. package/dist/agent-ui/pace.cjs.map +1 -0
  37. package/dist/agent-ui/pace.d.ts +66 -0
  38. package/dist/agent-ui/pace.js +121 -0
  39. package/dist/agent-ui/pace.js.map +1 -0
  40. package/dist/agent-ui/screen.cjs +471 -0
  41. package/dist/agent-ui/screen.cjs.map +1 -0
  42. package/dist/agent-ui/screen.d.ts +97 -0
  43. package/dist/agent-ui/screen.js +471 -0
  44. package/dist/agent-ui/screen.js.map +1 -0
  45. package/dist/agent-ui/secret-fields.cjs +50 -0
  46. package/dist/agent-ui/secret-fields.cjs.map +1 -0
  47. package/dist/agent-ui/secret-fields.d.ts +15 -0
  48. package/dist/agent-ui/secret-fields.js +50 -0
  49. package/dist/agent-ui/secret-fields.js.map +1 -0
  50. package/dist/agent-ui/stage.cjs +196 -0
  51. package/dist/agent-ui/stage.cjs.map +1 -0
  52. package/dist/agent-ui/stage.d.ts +110 -0
  53. package/dist/agent-ui/stage.js +196 -0
  54. package/dist/agent-ui/stage.js.map +1 -0
  55. package/dist/agent-ui/tools.cjs +448 -0
  56. package/dist/agent-ui/tools.cjs.map +1 -0
  57. package/dist/agent-ui/tools.d.ts +103 -0
  58. package/dist/agent-ui/tools.js +448 -0
  59. package/dist/agent-ui/tools.js.map +1 -0
  60. package/dist/agent-ui/use-agent-target.cjs +63 -0
  61. package/dist/agent-ui/use-agent-target.cjs.map +1 -0
  62. package/dist/agent-ui/use-agent-target.d.ts +27 -0
  63. package/dist/agent-ui/use-agent-target.js +63 -0
  64. package/dist/agent-ui/use-agent-target.js.map +1 -0
  65. package/dist/agent-ui/use-agent-ui.cjs +15 -0
  66. package/dist/agent-ui/use-agent-ui.cjs.map +1 -0
  67. package/dist/agent-ui/use-agent-ui.d.ts +24 -0
  68. package/dist/agent-ui/use-agent-ui.js +15 -0
  69. package/dist/agent-ui/use-agent-ui.js.map +1 -0
  70. package/dist/chat/AthenaChat.cjs +19 -4
  71. package/dist/chat/AthenaChat.cjs.map +1 -1
  72. package/dist/chat/AthenaChat.d.ts +13 -0
  73. package/dist/chat/AthenaChat.js +19 -4
  74. package/dist/chat/AthenaChat.js.map +1 -1
  75. package/dist/chat/StatewireClientToolBridge.cjs +74 -1
  76. package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
  77. package/dist/chat/StatewireClientToolBridge.d.ts +16 -1
  78. package/dist/chat/StatewireClientToolBridge.js +75 -2
  79. package/dist/chat/StatewireClientToolBridge.js.map +1 -1
  80. package/dist/chat/StatewireClientToolConsentCard.cjs +66 -0
  81. package/dist/chat/StatewireClientToolConsentCard.cjs.map +1 -0
  82. package/dist/chat/StatewireClientToolConsentCard.d.ts +25 -0
  83. package/dist/chat/StatewireClientToolConsentCard.js +66 -0
  84. package/dist/chat/StatewireClientToolConsentCard.js.map +1 -0
  85. package/dist/chat/chat-voice-controls.cjs +5 -2
  86. package/dist/chat/chat-voice-controls.cjs.map +1 -1
  87. package/dist/chat/chat-voice-controls.d.ts +6 -1
  88. package/dist/chat/chat-voice-controls.js +6 -3
  89. package/dist/chat/chat-voice-controls.js.map +1 -1
  90. package/dist/chat/client-tool-write-consent.cjs +122 -0
  91. package/dist/chat/client-tool-write-consent.cjs.map +1 -0
  92. package/dist/chat/client-tool-write-consent.d.ts +79 -0
  93. package/dist/chat/client-tool-write-consent.js +122 -0
  94. package/dist/chat/client-tool-write-consent.js.map +1 -0
  95. package/dist/chat/statewire-client-tools.cjs +30 -5
  96. package/dist/chat/statewire-client-tools.cjs.map +1 -1
  97. package/dist/chat/statewire-client-tools.d.ts +34 -2
  98. package/dist/chat/statewire-client-tools.js +30 -5
  99. package/dist/chat/statewire-client-tools.js.map +1 -1
  100. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs +13 -0
  101. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs.map +1 -1
  102. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.d.ts +12 -0
  103. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js +13 -0
  104. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js.map +1 -1
  105. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +2 -1
  106. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
  107. package/dist/chat-ui/mentions/suggestions/data/sources/index.js +3 -2
  108. package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
  109. package/dist/chat-ui/mentions/use-asset-icon-app-url.cjs +2 -1
  110. package/dist/chat-ui/mentions/use-asset-icon-app-url.cjs.map +1 -1
  111. package/dist/chat-ui/mentions/use-asset-icon-app-url.d.ts +2 -1
  112. package/dist/chat-ui/mentions/use-asset-icon-app-url.js +2 -1
  113. package/dist/chat-ui/mentions/use-asset-icon-app-url.js.map +1 -1
  114. package/dist/chat-ui/messages/message-components.cjs +1 -1
  115. package/dist/chat-ui/messages/message-components.cjs.map +1 -1
  116. package/dist/chat-ui/messages/message-components.d.ts +2 -2
  117. package/dist/chat-ui/messages/message-components.js +1 -1
  118. package/dist/chat-ui/messages/message-components.js.map +1 -1
  119. package/dist/chat-ui/statewire.cjs +4 -0
  120. package/dist/chat-ui/statewire.cjs.map +1 -1
  121. package/dist/chat-ui/statewire.d.ts +2 -0
  122. package/dist/chat-ui/statewire.js +4 -0
  123. package/dist/chat-ui/statewire.js.map +1 -1
  124. package/dist/index.cjs +12 -0
  125. package/dist/index.cjs.map +1 -1
  126. package/dist/index.d.ts +12 -2
  127. package/dist/index.js +13 -1
  128. package/dist/index.js.map +1 -1
  129. package/dist/provider/AthenaProvider.cjs +59 -11
  130. package/dist/provider/AthenaProvider.cjs.map +1 -1
  131. package/dist/provider/AthenaProvider.d.ts +25 -1
  132. package/dist/provider/AthenaProvider.js +55 -7
  133. package/dist/provider/AthenaProvider.js.map +1 -1
  134. package/dist/react/package.json.cjs +1 -1
  135. package/dist/react/package.json.js +1 -1
  136. package/dist/styles.css +1 -1
  137. package/package.json +6 -1
@@ -6,6 +6,37 @@ import { type RegisteredClientTool } from '../agent-runtime/src/index';
6
6
  * that type instead. Retained for one release so existing imports type-check.
7
7
  */
8
8
  export type StatewireClientTool = RegisteredClientTool;
9
+ export interface ClientToolWriteConsentOptions {
10
+ /**
11
+ * What the tool does, as the rest of the sentence "… wants to ___" on the
12
+ * consent card (e.g. `"click and type on this page"`). The card names the
13
+ * tool when this is absent.
14
+ */
15
+ summary?: string;
16
+ }
17
+ /**
18
+ * Mark a `frontendTools` entry as a write: the person is asked before its
19
+ * first call in a conversation runs, the answer covers the rest of that
20
+ * conversation, and a declined call answers the model with an error instead
21
+ * of running. Unmarked tools run without asking, as before.
22
+ *
23
+ * ```ts
24
+ * const frontendTools = {
25
+ * save_note: requiresWriteConsent(
26
+ * { description: '…', parameters, execute: saveNote },
27
+ * { summary: 'save a note on this record' },
28
+ * ),
29
+ * };
30
+ * ```
31
+ *
32
+ * The mark also travels to Athena (`requires_write`), which then never
33
+ * answers the call on the person's behalf while their tab is away.
34
+ */
35
+ export declare function requiresWriteConsent<T extends object>(tool: T, options?: ClientToolWriteConsentOptions): T;
36
+ /** The consent mark on a toolkit entry, or `null` for a tool that never asks. */
37
+ export declare function clientToolWriteConsent(entry: unknown): ClientToolWriteConsentOptions | null;
38
+ /** Each consent-marked tool's own words for what it does, by tool name. */
39
+ export declare function clientToolWriteConsentSummaries(toolkit: Toolkit | undefined): Readonly<Record<string, string>>;
9
40
  /**
10
41
  * Collect the client-executable tools from a frontend toolkit, in the shared
11
42
  * `RegisteredClientTool` shape every statewire surface declares and executes.
@@ -16,8 +47,9 @@ export type StatewireClientTool = RegisteredClientTool;
16
47
  * bridge. Schema conversion reuses `toJSONSchema` — the same conversion
17
48
  * primitive as the legacy assistant-transport — and a tool whose schema cannot
18
49
  * be converted is skipped with a warning rather than failing the whole set.
19
- * SDK tools never gate on write consent (`requiresWrite: false`): a toolkit
20
- * `execute` is the host app's own code.
50
+ * A tool gates on write consent only when its entry is marked with
51
+ * `requiresWriteConsent`: an unmarked toolkit `execute` is the host app's own
52
+ * code and runs without asking.
21
53
  */
22
54
  export declare function collectStatewireClientTools(toolkit: Toolkit): RegisteredClientTool[];
23
55
  /** Wire entries for `runConfig.custom.client_tools` — the shared contract from
@@ -1,6 +1,28 @@
1
1
  import { athenaDiagnostics } from "../diagnostics/athena-diagnostics.js";
2
2
  import { toJSONSchema, ToolResponse } from "assistant-stream";
3
3
  import { clientToolRunConfigEntries } from "../agent-runtime/src/client-tools.js";
4
+ const CLIENT_TOOL_WRITE_CONSENT = Symbol.for("athena.clientTool.writeConsent");
5
+ function requiresWriteConsent(tool, options = {}) {
6
+ var _a;
7
+ const summary = (_a = options.summary) == null ? void 0 : _a.trim();
8
+ return { ...tool, [CLIENT_TOOL_WRITE_CONSENT]: summary ? { summary } : {} };
9
+ }
10
+ function clientToolWriteConsent(entry) {
11
+ if (!entry || typeof entry !== "object") return null;
12
+ const mark = entry[CLIENT_TOOL_WRITE_CONSENT];
13
+ if (!mark || typeof mark !== "object") return null;
14
+ const summary = mark.summary;
15
+ return typeof summary === "string" && summary ? { summary } : {};
16
+ }
17
+ function clientToolWriteConsentSummaries(toolkit) {
18
+ var _a;
19
+ const summaries = {};
20
+ for (const [name, entry] of Object.entries(toolkit ?? {})) {
21
+ const summary = (_a = clientToolWriteConsent(entry)) == null ? void 0 : _a.summary;
22
+ if (summary) summaries[name] = summary;
23
+ }
24
+ return summaries;
25
+ }
4
26
  function hasCallableExecute(entry) {
5
27
  return !!entry && typeof entry === "object" && typeof entry.execute === "function";
6
28
  }
@@ -30,15 +52,15 @@ function collectStatewireClientTools(toolkit) {
30
52
  name,
31
53
  description: entry.description ?? "",
32
54
  parameters,
33
- requiresWrite: false
55
+ requiresWrite: clientToolWriteConsent(entry) !== null
34
56
  },
35
57
  handler: async (args, context) => {
36
- const controller = new AbortController();
37
58
  const output = await execute(args, {
38
- // The bridge always supplies the parked call's id; a host invoking
39
- // the handler directly has no call to correlate.
59
+ // The bridge always supplies the parked call's id and its signal,
60
+ // which aborts when the call's request goes away (the run was
61
+ // stopped); a host invoking the handler directly has neither.
40
62
  toolCallId: (context == null ? void 0 : context.toolCallId) ?? "",
41
- abortSignal: controller.signal,
63
+ abortSignal: (context == null ? void 0 : context.signal) ?? new AbortController().signal,
42
64
  human: () => Promise.reject(
43
65
  new Error("Human input is not supported for statewire client tools.")
44
66
  )
@@ -72,7 +94,10 @@ function resolveClientToolSurface(appId) {
72
94
  export {
73
95
  CLIENT_TOOL_SURFACE_APP_IDS,
74
96
  backendDeclaredFrontendToolIds,
97
+ clientToolWriteConsent,
98
+ clientToolWriteConsentSummaries,
75
99
  collectStatewireClientTools,
100
+ requiresWriteConsent,
76
101
  resolveClientToolSurface,
77
102
  statewireClientToolWireEntries
78
103
  };
@@ -1 +1 @@
1
- {"version":3,"file":"statewire-client-tools.js","sources":["../../src/chat/statewire-client-tools.ts"],"sourcesContent":["import { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport type { Toolkit } from '@assistant-ui/react';\nimport {\n type ClientToolHandlerContext,\n clientToolRunConfigEntries,\n type RegisteredClientTool,\n} from '@athenaintel/agent-runtime';\nimport { ToolResponse, toJSONSchema } from 'assistant-stream';\n\n/**\n * @deprecated The SDK's client tools ARE the shared `RegisteredClientTool`\n * shape from `@athenaintel/agent-runtime` (`definition` + `handler`); import\n * that type instead. Retained for one release so existing imports type-check.\n */\nexport type StatewireClientTool = RegisteredClientTool;\n\nfunction hasCallableExecute(\n entry: unknown,\n): entry is { execute: (args: Record<string, unknown>, context: unknown) => unknown } {\n return (\n !!entry &&\n typeof entry === 'object' &&\n typeof (entry as { execute?: unknown }).execute === 'function'\n );\n}\n\n/**\n * Collect the client-executable tools from a frontend toolkit, in the shared\n * `RegisteredClientTool` shape every statewire surface declares and executes.\n *\n * The deep-agent runtime drops frontend (`ui_*`) tool definitions, so tools\n * with a local `execute` must instead be declared through\n * `runConfig.custom.client_tools` and answered by the statewire client-tool\n * bridge. Schema conversion reuses `toJSONSchema` — the same conversion\n * primitive as the legacy assistant-transport — and a tool whose schema cannot\n * be converted is skipped with a warning rather than failing the whole set.\n * SDK tools never gate on write consent (`requiresWrite: false`): a toolkit\n * `execute` is the host app's own code.\n */\nexport function collectStatewireClientTools(toolkit: Toolkit): RegisteredClientTool[] {\n const executable = Object.entries(toolkit).filter(([, entry]) => hasCallableExecute(entry));\n if (executable.length === 0) return [];\n\n return executable.flatMap(([name, entry]) => {\n if (entry.parameters === undefined) return [];\n\n let parameters: Record<string, unknown>;\n try {\n parameters = { ...toJSONSchema(entry.parameters) };\n } catch (error) {\n athenaDiagnostics.emit('tools.schema.warning', {\n level: 'warn',\n data: {\n tool: name,\n message: 'Frontend tool schema could not be converted for statewire; the tool is not registered',\n error: error instanceof Error ? error.message : String(error),\n },\n });\n return [];\n }\n\n const execute = (entry as {\n execute: (args: Record<string, unknown>, context: unknown) => unknown;\n }).execute;\n return [\n {\n definition: {\n name,\n description: entry.description ?? '',\n parameters,\n requiresWrite: false,\n },\n handler: async (args, context?: ClientToolHandlerContext) => {\n const controller = new AbortController();\n const output = await execute(args, {\n // The bridge always supplies the parked call's id; a host invoking\n // the handler directly has no call to correlate.\n toolCallId: context?.toolCallId ?? '',\n abortSignal: controller.signal,\n human: () =>\n Promise.reject(\n new Error('Human input is not supported for statewire client tools.'),\n ),\n });\n return output instanceof ToolResponse ? output.result : output;\n },\n },\n ];\n });\n}\n\n/** Wire entries for `runConfig.custom.client_tools` — the shared contract from\n * `@athenaintel/agent-runtime`, so the SDK cannot drift from the other surfaces. */\nexport function statewireClientToolWireEntries(\n tools: readonly RegisteredClientTool[],\n): Record<string, unknown>[] {\n return clientToolRunConfigEntries(tools);\n}\n\n/**\n * The frontend-toolkit entries that must ride `enabled_tools`: declarations\n * WITHOUT a local `execute`, which name registry tools the backend already\n * knows how to bind (Olympus's frontend-executed tool ids).\n *\n * Executable entries are deliberately left out. They are declared through\n * `client_tools`, and the run binds them by name; putting the same name into\n * `enabled_tools` would also switch on any backend toolkit that happens to\n * own a tool of that name, and the backend wins the resulting collision —\n * the client tool is dropped and the model calls the backend one instead.\n */\nexport function backendDeclaredFrontendToolIds(toolkit: Toolkit): string[] {\n return Object.entries(toolkit)\n .filter(([, entry]) => !hasCallableExecute(entry))\n .map(([name]) => name);\n}\n\n/**\n * The `app_id` values the deep-agent runtime accepts as a client-tool surface.\n * Mirrors `agora/agora/graphs/athena_deep_agent/client_tools.py`: the fixed\n * first-party ids plus the `computer_asset_<uuid>` shape Athena's provisioning\n * injects into a computer-asset app. Any other `app_id` (or none) gets no\n * surface, and the runtime drops every `client_tools` declaration for the run.\n */\nexport const CLIENT_TOOL_SURFACE_APP_IDS = {\n olympus: 'olympus',\n officeAddin: 'athena-office-addin',\n mobile: 'athena-mobile',\n} as const;\n\nconst SDK_APP_ID_PATTERN = /^computer_asset_[0-9a-f-]{8,64}$/;\n\nexport type ClientToolSurface = 'web' | 'office' | 'mobile' | 'sdk';\n\n/** The surface an `app_id` selects, or null when the runtime would refuse it. */\nexport function resolveClientToolSurface(appId: string | undefined | null): ClientToolSurface | null {\n if (typeof appId !== 'string' || appId.length === 0) return null;\n if (appId === CLIENT_TOOL_SURFACE_APP_IDS.olympus) return 'web';\n if (appId === CLIENT_TOOL_SURFACE_APP_IDS.officeAddin) return 'office';\n if (appId === CLIENT_TOOL_SURFACE_APP_IDS.mobile) return 'mobile';\n if (SDK_APP_ID_PATTERN.test(appId)) return 'sdk';\n return null;\n}\n"],"names":[],"mappings":";;;AAgBA,SAAS,mBACP,OACoF;AACpF,SACE,CAAC,CAAC,SACF,OAAO,UAAU,YACjB,OAAQ,MAAgC,YAAY;AAExD;AAeO,SAAS,4BAA4B,SAA0C;AACpF,QAAM,aAAa,OAAO,QAAQ,OAAO,EAAE,OAAO,CAAC,GAAG,KAAK,MAAM,mBAAmB,KAAK,CAAC;AAC1F,MAAI,WAAW,WAAW,EAAG,QAAO,CAAA;AAEpC,SAAO,WAAW,QAAQ,CAAC,CAAC,MAAM,KAAK,MAAM;AAC3C,QAAI,MAAM,eAAe,OAAW,QAAO,CAAA;AAE3C,QAAI;AACJ,QAAI;AACF,mBAAa,EAAE,GAAG,aAAa,MAAM,UAAU,EAAA;AAAA,IACjD,SAAS,OAAO;AACd,wBAAkB,KAAK,wBAAwB;AAAA,QAC7C,OAAO;AAAA,QACP,MAAM;AAAA,UACJ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAAA;AAAA,MAC9D,CACD;AACD,aAAO,CAAA;AAAA,IACT;AAEA,UAAM,UAAW,MAEd;AACH,WAAO;AAAA,MACL;AAAA,QACE,YAAY;AAAA,UACV;AAAA,UACA,aAAa,MAAM,eAAe;AAAA,UAClC;AAAA,UACA,eAAe;AAAA,QAAA;AAAA,QAEjB,SAAS,OAAO,MAAM,YAAuC;AAC3D,gBAAM,aAAa,IAAI,gBAAA;AACvB,gBAAM,SAAS,MAAM,QAAQ,MAAM;AAAA;AAAA;AAAA,YAGjC,aAAY,mCAAS,eAAc;AAAA,YACnC,aAAa,WAAW;AAAA,YACxB,OAAO,MACL,QAAQ;AAAA,cACN,IAAI,MAAM,0DAA0D;AAAA,YAAA;AAAA,UACtE,CACH;AACD,iBAAO,kBAAkB,eAAe,OAAO,SAAS;AAAA,QAC1D;AAAA,MAAA;AAAA,IACF;AAAA,EAEJ,CAAC;AACH;AAIO,SAAS,+BACd,OAC2B;AAC3B,SAAO,2BAA2B,KAAK;AACzC;AAaO,SAAS,+BAA+B,SAA4B;AACzE,SAAO,OAAO,QAAQ,OAAO,EAC1B,OAAO,CAAC,CAAA,EAAG,KAAK,MAAM,CAAC,mBAAmB,KAAK,CAAC,EAChD,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI;AACzB;AASO,MAAM,8BAA8B;AAAA,EACzC,SAAS;AAAA,EACT,aAAa;AAAA,EACb,QAAQ;AACV;AAEA,MAAM,qBAAqB;AAKpB,SAAS,yBAAyB,OAA4D;AACnG,MAAI,OAAO,UAAU,YAAY,MAAM,WAAW,EAAG,QAAO;AAC5D,MAAI,UAAU,4BAA4B,QAAS,QAAO;AAC1D,MAAI,UAAU,4BAA4B,YAAa,QAAO;AAC9D,MAAI,UAAU,4BAA4B,OAAQ,QAAO;AACzD,MAAI,mBAAmB,KAAK,KAAK,EAAG,QAAO;AAC3C,SAAO;AACT;"}
1
+ {"version":3,"file":"statewire-client-tools.js","sources":["../../src/chat/statewire-client-tools.ts"],"sourcesContent":["import { athenaDiagnostics } from '../diagnostics/athena-diagnostics';\nimport type { Toolkit } from '@assistant-ui/react';\nimport {\n type ClientToolHandlerContext,\n clientToolRunConfigEntries,\n type RegisteredClientTool,\n} from '@athenaintel/agent-runtime';\nimport { ToolResponse, toJSONSchema } from 'assistant-stream';\n\n/**\n * @deprecated The SDK's client tools ARE the shared `RegisteredClientTool`\n * shape from `@athenaintel/agent-runtime` (`definition` + `handler`); import\n * that type instead. Retained for one release so existing imports type-check.\n */\nexport type StatewireClientTool = RegisteredClientTool;\n\n/**\n * Marks a frontend tool as one that changes something for the person, so its\n * calls wait for their consent. Set by {@link requiresWriteConsent}. A\n * registered symbol (not a module-local one), so the mark is read by whichever\n * copy of the SDK collects the toolkit.\n */\nconst CLIENT_TOOL_WRITE_CONSENT = Symbol.for('athena.clientTool.writeConsent');\n\nexport interface ClientToolWriteConsentOptions {\n /**\n * What the tool does, as the rest of the sentence \"… wants to ___\" on the\n * consent card (e.g. `\"click and type on this page\"`). The card names the\n * tool when this is absent.\n */\n summary?: string;\n}\n\n/**\n * Mark a `frontendTools` entry as a write: the person is asked before its\n * first call in a conversation runs, the answer covers the rest of that\n * conversation, and a declined call answers the model with an error instead\n * of running. Unmarked tools run without asking, as before.\n *\n * ```ts\n * const frontendTools = {\n * save_note: requiresWriteConsent(\n * { description: '…', parameters, execute: saveNote },\n * { summary: 'save a note on this record' },\n * ),\n * };\n * ```\n *\n * The mark also travels to Athena (`requires_write`), which then never\n * answers the call on the person's behalf while their tab is away.\n */\nexport function requiresWriteConsent<T extends object>(\n tool: T,\n options: ClientToolWriteConsentOptions = {},\n): T {\n const summary = options.summary?.trim();\n return { ...tool, [CLIENT_TOOL_WRITE_CONSENT]: summary ? { summary } : {} };\n}\n\n/** The consent mark on a toolkit entry, or `null` for a tool that never asks. */\nexport function clientToolWriteConsent(entry: unknown): ClientToolWriteConsentOptions | null {\n if (!entry || typeof entry !== 'object') return null;\n const mark = (entry as Record<symbol, unknown>)[CLIENT_TOOL_WRITE_CONSENT];\n if (!mark || typeof mark !== 'object') return null;\n const summary = (mark as { summary?: unknown }).summary;\n return typeof summary === 'string' && summary ? { summary } : {};\n}\n\n/** Each consent-marked tool's own words for what it does, by tool name. */\nexport function clientToolWriteConsentSummaries(\n toolkit: Toolkit | undefined,\n): Readonly<Record<string, string>> {\n const summaries: Record<string, string> = {};\n for (const [name, entry] of Object.entries(toolkit ?? {})) {\n const summary = clientToolWriteConsent(entry)?.summary;\n if (summary) summaries[name] = summary;\n }\n return summaries;\n}\n\nfunction hasCallableExecute(\n entry: unknown,\n): entry is { execute: (args: Record<string, unknown>, context: unknown) => unknown } {\n return (\n !!entry &&\n typeof entry === 'object' &&\n typeof (entry as { execute?: unknown }).execute === 'function'\n );\n}\n\n/**\n * Collect the client-executable tools from a frontend toolkit, in the shared\n * `RegisteredClientTool` shape every statewire surface declares and executes.\n *\n * The deep-agent runtime drops frontend (`ui_*`) tool definitions, so tools\n * with a local `execute` must instead be declared through\n * `runConfig.custom.client_tools` and answered by the statewire client-tool\n * bridge. Schema conversion reuses `toJSONSchema` — the same conversion\n * primitive as the legacy assistant-transport — and a tool whose schema cannot\n * be converted is skipped with a warning rather than failing the whole set.\n * A tool gates on write consent only when its entry is marked with\n * `requiresWriteConsent`: an unmarked toolkit `execute` is the host app's own\n * code and runs without asking.\n */\nexport function collectStatewireClientTools(toolkit: Toolkit): RegisteredClientTool[] {\n const executable = Object.entries(toolkit).filter(([, entry]) => hasCallableExecute(entry));\n if (executable.length === 0) return [];\n\n return executable.flatMap(([name, entry]) => {\n if (entry.parameters === undefined) return [];\n\n let parameters: Record<string, unknown>;\n try {\n parameters = { ...toJSONSchema(entry.parameters) };\n } catch (error) {\n athenaDiagnostics.emit('tools.schema.warning', {\n level: 'warn',\n data: {\n tool: name,\n message: 'Frontend tool schema could not be converted for statewire; the tool is not registered',\n error: error instanceof Error ? error.message : String(error),\n },\n });\n return [];\n }\n\n const execute = (entry as {\n execute: (args: Record<string, unknown>, context: unknown) => unknown;\n }).execute;\n return [\n {\n definition: {\n name,\n description: entry.description ?? '',\n parameters,\n requiresWrite: clientToolWriteConsent(entry) !== null,\n },\n handler: async (args, context?: ClientToolHandlerContext) => {\n const output = await execute(args, {\n // The bridge always supplies the parked call's id and its signal,\n // which aborts when the call's request goes away (the run was\n // stopped); a host invoking the handler directly has neither.\n toolCallId: context?.toolCallId ?? '',\n abortSignal: context?.signal ?? new AbortController().signal,\n human: () =>\n Promise.reject(\n new Error('Human input is not supported for statewire client tools.'),\n ),\n });\n return output instanceof ToolResponse ? output.result : output;\n },\n },\n ];\n });\n}\n\n/** Wire entries for `runConfig.custom.client_tools` — the shared contract from\n * `@athenaintel/agent-runtime`, so the SDK cannot drift from the other surfaces. */\nexport function statewireClientToolWireEntries(\n tools: readonly RegisteredClientTool[],\n): Record<string, unknown>[] {\n return clientToolRunConfigEntries(tools);\n}\n\n/**\n * The frontend-toolkit entries that must ride `enabled_tools`: declarations\n * WITHOUT a local `execute`, which name registry tools the backend already\n * knows how to bind (Olympus's frontend-executed tool ids).\n *\n * Executable entries are deliberately left out. They are declared through\n * `client_tools`, and the run binds them by name; putting the same name into\n * `enabled_tools` would also switch on any backend toolkit that happens to\n * own a tool of that name, and the backend wins the resulting collision —\n * the client tool is dropped and the model calls the backend one instead.\n */\nexport function backendDeclaredFrontendToolIds(toolkit: Toolkit): string[] {\n return Object.entries(toolkit)\n .filter(([, entry]) => !hasCallableExecute(entry))\n .map(([name]) => name);\n}\n\n/**\n * The `app_id` values the deep-agent runtime accepts as a client-tool surface.\n * Mirrors `agora/agora/graphs/athena_deep_agent/client_tools.py`: the fixed\n * first-party ids plus the `computer_asset_<uuid>` shape Athena's provisioning\n * injects into a computer-asset app. Any other `app_id` (or none) gets no\n * surface, and the runtime drops every `client_tools` declaration for the run.\n */\nexport const CLIENT_TOOL_SURFACE_APP_IDS = {\n olympus: 'olympus',\n officeAddin: 'athena-office-addin',\n mobile: 'athena-mobile',\n} as const;\n\nconst SDK_APP_ID_PATTERN = /^computer_asset_[0-9a-f-]{8,64}$/;\n\nexport type ClientToolSurface = 'web' | 'office' | 'mobile' | 'sdk';\n\n/** The surface an `app_id` selects, or null when the runtime would refuse it. */\nexport function resolveClientToolSurface(appId: string | undefined | null): ClientToolSurface | null {\n if (typeof appId !== 'string' || appId.length === 0) return null;\n if (appId === CLIENT_TOOL_SURFACE_APP_IDS.olympus) return 'web';\n if (appId === CLIENT_TOOL_SURFACE_APP_IDS.officeAddin) return 'office';\n if (appId === CLIENT_TOOL_SURFACE_APP_IDS.mobile) return 'mobile';\n if (SDK_APP_ID_PATTERN.test(appId)) return 'sdk';\n return null;\n}\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const athenaUrls = require("../../../../../lib/athena-urls.cjs");
3
4
  const assetTypeIconNames_generated = require("./asset-type-icon-names.generated.cjs");
4
5
  let hostIconBasePath = null;
5
6
  function configureAssetIconBasePath({
@@ -7,6 +8,17 @@ function configureAssetIconBasePath({
7
8
  }) {
8
9
  hostIconBasePath = basePath ? basePath.replace(/\/*$/, "/") : null;
9
10
  }
11
+ function currentPageOrigin() {
12
+ return typeof window === "undefined" ? null : window.location.origin;
13
+ }
14
+ function assetIconAppUrl({
15
+ appUrl,
16
+ backendUrl,
17
+ pageOrigin = currentPageOrigin()
18
+ }) {
19
+ if (!appUrl) return null;
20
+ return athenaUrls.athenaLinkAppUrl({ appUrl, backendUrl: backendUrl ?? "", pageOrigin });
21
+ }
10
22
  function athenaAppAssetIconBasePath({
11
23
  appUrl
12
24
  }) {
@@ -148,6 +160,7 @@ function assetTypeToIcon(assetType) {
148
160
  if (!key || !Object.hasOwn(ASSET_TYPE_LUCIDE_FALLBACK, key)) return "file";
149
161
  return ASSET_TYPE_LUCIDE_FALLBACK[key] ?? "file";
150
162
  }
163
+ exports.assetIconAppUrl = assetIconAppUrl;
151
164
  exports.assetTypeToIcon = assetTypeToIcon;
152
165
  exports.assetTypeToThumb = assetTypeToThumb;
153
166
  exports.athenaAppAssetIconBasePath = athenaAppAssetIconBasePath;
@@ -1 +1 @@
1
- {"version":3,"file":"asset-type-icons.cjs","sources":["../../../../../../src/chat-ui/mentions/suggestions/data/sources/asset-type-icons.ts"],"sourcesContent":["/**\n * Athena's asset-type icons: the SVG Olympus draws for each asset type.\n *\n * The type → icon table is Olympus's own: `ASSET_TYPE_ICON_NAMES`\n * (`asset-type-icon-names.generated.ts`), generated from its\n * `AthenaTypeToThumb` by Olympus's parity test, which writes the same table\n * into `@athenaintel/sheets` and fails when either drifts. So the `@` menu, the\n * mention chips and the drive cards draw the icon Olympus draws for every type.\n *\n * Where the SVGs load from:\n * - type glyphs (`ic-…`): a host's own copy when it names one with\n * `configureAssetIconBasePath` (the Chrome extension), else the Athena web\n * app the chat talks to (`appUrl`, the provider's: `useAssetIconAppUrl`),\n * which serves the public files Olympus draws at `<appUrl>/assets/icons/files/`;\n * - brand logos (Power BI, Slack, Gmail, Outlook) sit in `apps/` beside them:\n * from that app when the chat names one (a host's copy may carry only the\n * glyphs), else beside the host's copy.\n *\n * With neither there is no SVG, and callers draw the type's Lucide icon\n * (`assetTypeToIcon`). `MentionIcon`, the chips and the drive cards also fall\n * back to it when an SVG cannot load (a strict CSP, offline).\n */\n\nimport {\n ASSET_TYPE_ICON_NAMES,\n DEFAULT_ASSET_TYPE_ICON,\n} from \"./asset-type-icon-names.generated\";\n\nlet hostIconBasePath: string | null = null;\n\n/**\n * Point the asset-type icons at the host's own copy of Olympus's\n * `assets/icons/files/` SVGs. `basePath` is resolved against the host\n * document; a trailing \"/\" is added when the caller omits it. `null` drops the\n * host copy: the icons then load from the Athena web app the chat talks to.\n */\nexport function configureAssetIconBasePath({\n basePath,\n}: {\n basePath: string | null;\n}): void {\n hostIconBasePath = basePath ? basePath.replace(/\\/*$/, \"/\") : null;\n}\n\n/** Where the Athena web app at `appUrl` serves the asset-type SVGs; null for an unusable URL. */\nexport function athenaAppAssetIconBasePath({\n appUrl,\n}: {\n appUrl: string | null | undefined;\n}): string | null {\n if (!appUrl?.trim()) return null;\n try {\n const base = new URL(\"/assets/icons/files/\", appUrl);\n return base.protocol === \"https:\" || base.protocol === \"http:\"\n ? base.toString()\n : null;\n } catch {\n return null;\n }\n}\n\nconst FILES_DIR = \"files/\";\n\n/** An icon's URL, from the host's copy or the chat's Athena web app (see the module doc). */\nfunction iconUrl({\n icon,\n appUrl,\n}: {\n icon: string;\n appUrl: string | null | undefined;\n}): string | undefined {\n const appBasePath = athenaAppAssetIconBasePath({ appUrl });\n if (/^ic[-_]/.test(icon)) {\n const basePath = hostIconBasePath ?? appBasePath;\n return basePath ? `${basePath}${icon}.svg` : undefined;\n }\n const filesBasePath = appBasePath ?? hostIconBasePath;\n if (!filesBasePath) return undefined;\n return filesBasePath.endsWith(`/${FILES_DIR}`)\n ? `${filesBasePath.slice(0, -FILES_DIR.length)}apps/${icon}.svg`\n : `${filesBasePath}${icon}.svg`;\n}\n\nfunction assetTypeIconName(assetType: string | null | undefined): string {\n const key = assetType?.toLowerCase();\n return key && Object.hasOwn(ASSET_TYPE_ICON_NAMES, key)\n ? (ASSET_TYPE_ICON_NAMES[key] ?? DEFAULT_ASSET_TYPE_ICON)\n : DEFAULT_ASSET_TYPE_ICON;\n}\n\n/**\n * The SVG URL of an asset type's icon, the one Olympus draws. `appUrl` is the\n * Athena web app the chat talks to (`useAssetIconAppUrl`); undefined when\n * neither it nor a host copy (`configureAssetIconBasePath`) is available.\n */\nexport function assetTypeToThumb(\n assetType: string | null | undefined,\n { appUrl }: { appUrl?: string | null } = {},\n): string | undefined {\n return iconUrl({ icon: assetTypeIconName(assetType), appUrl });\n}\n\nconst EMAIL_ASSET_TYPES: ReadonlySet<string> = new Set([\n \"email\",\n \"email_draft\",\n \"email_message\",\n \"live_email_thread\",\n]);\n\n/** Whether rows of this type can draw their mailbox's logo (`emailProviderThumb`). */\nexport function isEmailAssetType(assetType: string | null | undefined): boolean {\n return !!assetType && EMAIL_ASSET_TYPES.has(assetType.toLowerCase());\n}\n\nfunction recordOf(value: unknown): Record<string, unknown> | null {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n}\n\nconst LANE_PREFIX = /^paragon_/;\nconst LANE_SUFFIX = /_(direct(_v\\d+)?|paragon|live)$/;\n\n/** Gmail or Outlook, from the provider an email asset records; null for any other or none. */\nfunction mailboxLogo(metadata: unknown): \"gmail\" | \"outlook\" | null {\n const record = recordOf(metadata);\n if (!record) return null;\n const provider: unknown =\n recordOf(record.liveAsset)?.provider ??\n recordOf(record.email)?.provider ??\n recordOf(record.email_draft)?.provider;\n if (typeof provider !== \"string\") return null;\n const name = provider.trim().toLowerCase().replace(LANE_PREFIX, \"\").replace(LANE_SUFFIX, \"\");\n if (name === \"gmail\" || name === \"google\") return \"gmail\";\n if (name === \"outlook\" || name === \"microsoft_graph\") return \"outlook\";\n return null;\n}\n\n/**\n * The Gmail or Outlook logo for an email asset whose mailbox provider its\n * metadata records (`liveAsset.provider`, the `email` block agora writes\n * beside it, or a draft's `email_draft` block), as Olympus draws it;\n * undefined otherwise, for the type's mail icon.\n */\nexport function emailProviderThumb({\n assetType,\n metadata,\n appUrl,\n}: {\n assetType: string | null | undefined;\n metadata: unknown;\n /** The Athena web app the chat talks to (`useAssetIconAppUrl`). */\n appUrl?: string | null;\n}): string | undefined {\n if (!isEmailAssetType(assetType)) return undefined;\n const logo = mailboxLogo(metadata);\n return logo ? iconUrl({ icon: logo, appUrl }) : undefined;\n}\n\n/**\n * The Lucide icon (a `MentionIcon` name) drawn for an asset type when its SVG\n * is not available: no icon source, or the SVG failed to load.\n */\nconst ASSET_TYPE_LUCIDE_FALLBACK: Record<string, string> = {\n aop: \"workflow\",\n application: \"layout-grid\",\n audio: \"headphones\",\n automation: \"zap\",\n browse_profile: \"globe\",\n browse_session: \"globe\",\n canvas: \"palette\",\n catalog: \"database\",\n collab_agent: \"bot\",\n collab_source: \"database\",\n collab_toolkit: \"package\",\n collection: \"library\",\n computer: \"monitor\",\n dashboard: \"layout-dashboard\",\n database: \"database\",\n design_system: \"palette\",\n desktop_session: \"monitor\",\n device: \"smartphone\",\n document: \"file-text\",\n drive: \"hard-drive\",\n email: \"mail\",\n email_draft: \"mail\",\n email_message: \"mail\",\n environment: \"server\",\n figure: \"chart-bar\",\n folder: \"folder\",\n gdrive_folder: \"folder\",\n generic_doc: \"file-text\",\n image: \"image\",\n json: \"file-code\",\n lakehouse_namespace: \"database\",\n lakehouse_sync: \"workflow\",\n lakehouse_table: \"table\",\n live_calendar_event: \"calendar\",\n live_email_thread: \"mail\",\n markdown: \"file-text\",\n meeting: \"video\",\n mobile_session: \"smartphone\",\n notebook: \"book-open\",\n olympus_drive: \"hard-drive\",\n pdf: \"file-text\",\n person: \"user\",\n phone_call: \"phone\",\n playbook: \"book-open\",\n policy: \"check-square\",\n powerpoint_deck: \"presentation\",\n pptx: \"presentation\",\n presentation: \"presentation\",\n presentation_pptx_studio: \"presentation\",\n project: \"folder-kanban\",\n python: \"file-code\",\n query_snippet: \"database\",\n script: \"file-code\",\n secret: \"key\",\n semantic_model: \"database\",\n session: \"message-square\",\n skill: \"sparkles\",\n spreadsheet: \"sheet\",\n table: \"table\",\n transform_project: \"workflow\",\n txt: \"file-text\",\n user_interface: \"layout\",\n video: \"video\",\n video_session: \"video\",\n voice_memo: \"mic\",\n web_page: \"globe\",\n word_document: \"file-text\",\n yaml: \"file-code\",\n};\n\n/** The Lucide icon name for an asset type, drawn when its SVG is not available. */\nexport function assetTypeToIcon(assetType: string | null | undefined): string {\n const key = assetType?.toLowerCase();\n if (!key || !Object.hasOwn(ASSET_TYPE_LUCIDE_FALLBACK, key)) return \"file\";\n return ASSET_TYPE_LUCIDE_FALLBACK[key] ?? \"file\";\n}\n\n"],"names":["ASSET_TYPE_ICON_NAMES","DEFAULT_ASSET_TYPE_ICON"],"mappings":"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"}
1
+ {"version":3,"file":"asset-type-icons.cjs","sources":["../../../../../../src/chat-ui/mentions/suggestions/data/sources/asset-type-icons.ts"],"sourcesContent":["/**\n * Athena's asset-type icons: the SVG Olympus draws for each asset type.\n *\n * The type → icon table is Olympus's own: `ASSET_TYPE_ICON_NAMES`\n * (`asset-type-icon-names.generated.ts`), generated from its\n * `AthenaTypeToThumb` by Olympus's parity test, which writes the same table\n * into `@athenaintel/sheets` and fails when either drifts. So the `@` menu, the\n * mention chips and the drive cards draw the icon Olympus draws for every type.\n *\n * Where the SVGs load from:\n * - type glyphs (`ic-…`): a host's own copy when it names one with\n * `configureAssetIconBasePath` (the Chrome extension), else the Athena web\n * app the chat talks to (`appUrl`, the provider's: `useAssetIconAppUrl`),\n * which serves the public files Olympus draws at `<appUrl>/assets/icons/files/`;\n * - brand logos (Power BI, Slack, Gmail, Outlook) sit in `apps/` beside them:\n * from that app when the chat names one (a host's copy may carry only the\n * glyphs), else beside the host's copy.\n *\n * With neither there is no SVG, and callers draw the type's Lucide icon\n * (`assetTypeToIcon`). `MentionIcon`, the chips and the drive cards also fall\n * back to it when an SVG cannot load (a strict CSP, offline).\n */\n\nimport { athenaLinkAppUrl } from \"../../../../../lib/athena-urls\";\nimport {\n ASSET_TYPE_ICON_NAMES,\n DEFAULT_ASSET_TYPE_ICON,\n} from \"./asset-type-icon-names.generated\";\n\nlet hostIconBasePath: string | null = null;\n\n/**\n * Point the asset-type icons at the host's own copy of Olympus's\n * `assets/icons/files/` SVGs. `basePath` is resolved against the host\n * document; a trailing \"/\" is added when the caller omits it. `null` drops the\n * host copy: the icons then load from the Athena web app the chat talks to.\n */\nexport function configureAssetIconBasePath({\n basePath,\n}: {\n basePath: string | null;\n}): void {\n hostIconBasePath = basePath ? basePath.replace(/\\/*$/, \"/\") : null;\n}\n\nfunction currentPageOrigin(): string | null {\n return typeof window === \"undefined\" ? null : window.location.origin;\n}\n\n/**\n * The Athena web app whose icons a chat draws: the provider's `appUrl`,\n * except in an app a computer serves, where Marathon's `/_athena/auth` mints\n * `appUrl` as the app's own origin (which serves no Athena icons) and the\n * deployment's frontend serves them, as for \"Open in Athena\" links\n * (`athenaLinkAppUrl`). Null without an `appUrl`.\n */\nexport function assetIconAppUrl({\n appUrl,\n backendUrl,\n pageOrigin = currentPageOrigin(),\n}: {\n appUrl: string | null | undefined;\n backendUrl: string | null | undefined;\n pageOrigin?: string | null;\n}): string | null {\n if (!appUrl) return null;\n return athenaLinkAppUrl({ appUrl, backendUrl: backendUrl ?? \"\", pageOrigin });\n}\n\n/** Where the Athena web app at `appUrl` serves the asset-type SVGs; null for an unusable URL. */\nexport function athenaAppAssetIconBasePath({\n appUrl,\n}: {\n appUrl: string | null | undefined;\n}): string | null {\n if (!appUrl?.trim()) return null;\n try {\n const base = new URL(\"/assets/icons/files/\", appUrl);\n return base.protocol === \"https:\" || base.protocol === \"http:\"\n ? base.toString()\n : null;\n } catch {\n return null;\n }\n}\n\nconst FILES_DIR = \"files/\";\n\n/** An icon's URL, from the host's copy or the chat's Athena web app (see the module doc). */\nfunction iconUrl({\n icon,\n appUrl,\n}: {\n icon: string;\n appUrl: string | null | undefined;\n}): string | undefined {\n const appBasePath = athenaAppAssetIconBasePath({ appUrl });\n if (/^ic[-_]/.test(icon)) {\n const basePath = hostIconBasePath ?? appBasePath;\n return basePath ? `${basePath}${icon}.svg` : undefined;\n }\n const filesBasePath = appBasePath ?? hostIconBasePath;\n if (!filesBasePath) return undefined;\n return filesBasePath.endsWith(`/${FILES_DIR}`)\n ? `${filesBasePath.slice(0, -FILES_DIR.length)}apps/${icon}.svg`\n : `${filesBasePath}${icon}.svg`;\n}\n\nfunction assetTypeIconName(assetType: string | null | undefined): string {\n const key = assetType?.toLowerCase();\n return key && Object.hasOwn(ASSET_TYPE_ICON_NAMES, key)\n ? (ASSET_TYPE_ICON_NAMES[key] ?? DEFAULT_ASSET_TYPE_ICON)\n : DEFAULT_ASSET_TYPE_ICON;\n}\n\n/**\n * The SVG URL of an asset type's icon, the one Olympus draws. `appUrl` is the\n * Athena web app the chat talks to (`useAssetIconAppUrl`); undefined when\n * neither it nor a host copy (`configureAssetIconBasePath`) is available.\n */\nexport function assetTypeToThumb(\n assetType: string | null | undefined,\n { appUrl }: { appUrl?: string | null } = {},\n): string | undefined {\n return iconUrl({ icon: assetTypeIconName(assetType), appUrl });\n}\n\nconst EMAIL_ASSET_TYPES: ReadonlySet<string> = new Set([\n \"email\",\n \"email_draft\",\n \"email_message\",\n \"live_email_thread\",\n]);\n\n/** Whether rows of this type can draw their mailbox's logo (`emailProviderThumb`). */\nexport function isEmailAssetType(assetType: string | null | undefined): boolean {\n return !!assetType && EMAIL_ASSET_TYPES.has(assetType.toLowerCase());\n}\n\nfunction recordOf(value: unknown): Record<string, unknown> | null {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n}\n\nconst LANE_PREFIX = /^paragon_/;\nconst LANE_SUFFIX = /_(direct(_v\\d+)?|paragon|live)$/;\n\n/** Gmail or Outlook, from the provider an email asset records; null for any other or none. */\nfunction mailboxLogo(metadata: unknown): \"gmail\" | \"outlook\" | null {\n const record = recordOf(metadata);\n if (!record) return null;\n const provider: unknown =\n recordOf(record.liveAsset)?.provider ??\n recordOf(record.email)?.provider ??\n recordOf(record.email_draft)?.provider;\n if (typeof provider !== \"string\") return null;\n const name = provider.trim().toLowerCase().replace(LANE_PREFIX, \"\").replace(LANE_SUFFIX, \"\");\n if (name === \"gmail\" || name === \"google\") return \"gmail\";\n if (name === \"outlook\" || name === \"microsoft_graph\") return \"outlook\";\n return null;\n}\n\n/**\n * The Gmail or Outlook logo for an email asset whose mailbox provider its\n * metadata records (`liveAsset.provider`, the `email` block agora writes\n * beside it, or a draft's `email_draft` block), as Olympus draws it;\n * undefined otherwise, for the type's mail icon.\n */\nexport function emailProviderThumb({\n assetType,\n metadata,\n appUrl,\n}: {\n assetType: string | null | undefined;\n metadata: unknown;\n /** The Athena web app the chat talks to (`useAssetIconAppUrl`). */\n appUrl?: string | null;\n}): string | undefined {\n if (!isEmailAssetType(assetType)) return undefined;\n const logo = mailboxLogo(metadata);\n return logo ? iconUrl({ icon: logo, appUrl }) : undefined;\n}\n\n/**\n * The Lucide icon (a `MentionIcon` name) drawn for an asset type when its SVG\n * is not available: no icon source, or the SVG failed to load.\n */\nconst ASSET_TYPE_LUCIDE_FALLBACK: Record<string, string> = {\n aop: \"workflow\",\n application: \"layout-grid\",\n audio: \"headphones\",\n automation: \"zap\",\n browse_profile: \"globe\",\n browse_session: \"globe\",\n canvas: \"palette\",\n catalog: \"database\",\n collab_agent: \"bot\",\n collab_source: \"database\",\n collab_toolkit: \"package\",\n collection: \"library\",\n computer: \"monitor\",\n dashboard: \"layout-dashboard\",\n database: \"database\",\n design_system: \"palette\",\n desktop_session: \"monitor\",\n device: \"smartphone\",\n document: \"file-text\",\n drive: \"hard-drive\",\n email: \"mail\",\n email_draft: \"mail\",\n email_message: \"mail\",\n environment: \"server\",\n figure: \"chart-bar\",\n folder: \"folder\",\n gdrive_folder: \"folder\",\n generic_doc: \"file-text\",\n image: \"image\",\n json: \"file-code\",\n lakehouse_namespace: \"database\",\n lakehouse_sync: \"workflow\",\n lakehouse_table: \"table\",\n live_calendar_event: \"calendar\",\n live_email_thread: \"mail\",\n markdown: \"file-text\",\n meeting: \"video\",\n mobile_session: \"smartphone\",\n notebook: \"book-open\",\n olympus_drive: \"hard-drive\",\n pdf: \"file-text\",\n person: \"user\",\n phone_call: \"phone\",\n playbook: \"book-open\",\n policy: \"check-square\",\n powerpoint_deck: \"presentation\",\n pptx: \"presentation\",\n presentation: \"presentation\",\n presentation_pptx_studio: \"presentation\",\n project: \"folder-kanban\",\n python: \"file-code\",\n query_snippet: \"database\",\n script: \"file-code\",\n secret: \"key\",\n semantic_model: \"database\",\n session: \"message-square\",\n skill: \"sparkles\",\n spreadsheet: \"sheet\",\n table: \"table\",\n transform_project: \"workflow\",\n txt: \"file-text\",\n user_interface: \"layout\",\n video: \"video\",\n video_session: \"video\",\n voice_memo: \"mic\",\n web_page: \"globe\",\n word_document: \"file-text\",\n yaml: \"file-code\",\n};\n\n/** The Lucide icon name for an asset type, drawn when its SVG is not available. */\nexport function assetTypeToIcon(assetType: string | null | undefined): string {\n const key = assetType?.toLowerCase();\n if (!key || !Object.hasOwn(ASSET_TYPE_LUCIDE_FALLBACK, key)) return \"file\";\n return ASSET_TYPE_LUCIDE_FALLBACK[key] ?? \"file\";\n}\n\n"],"names":["athenaLinkAppUrl","ASSET_TYPE_ICON_NAMES","DEFAULT_ASSET_TYPE_ICON"],"mappings":"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"}
@@ -29,6 +29,18 @@
29
29
  export declare function configureAssetIconBasePath({ basePath, }: {
30
30
  basePath: string | null;
31
31
  }): void;
32
+ /**
33
+ * The Athena web app whose icons a chat draws: the provider's `appUrl`,
34
+ * except in an app a computer serves, where Marathon's `/_athena/auth` mints
35
+ * `appUrl` as the app's own origin (which serves no Athena icons) and the
36
+ * deployment's frontend serves them, as for "Open in Athena" links
37
+ * (`athenaLinkAppUrl`). Null without an `appUrl`.
38
+ */
39
+ export declare function assetIconAppUrl({ appUrl, backendUrl, pageOrigin, }: {
40
+ appUrl: string | null | undefined;
41
+ backendUrl: string | null | undefined;
42
+ pageOrigin?: string | null;
43
+ }): string | null;
32
44
  /** Where the Athena web app at `appUrl` serves the asset-type SVGs; null for an unusable URL. */
33
45
  export declare function athenaAppAssetIconBasePath({ appUrl, }: {
34
46
  appUrl: string | null | undefined;
@@ -1,3 +1,4 @@
1
+ import { athenaLinkAppUrl } from "../../../../../lib/athena-urls.js";
1
2
  import { ASSET_TYPE_ICON_NAMES, DEFAULT_ASSET_TYPE_ICON } from "./asset-type-icon-names.generated.js";
2
3
  let hostIconBasePath = null;
3
4
  function configureAssetIconBasePath({
@@ -5,6 +6,17 @@ function configureAssetIconBasePath({
5
6
  }) {
6
7
  hostIconBasePath = basePath ? basePath.replace(/\/*$/, "/") : null;
7
8
  }
9
+ function currentPageOrigin() {
10
+ return typeof window === "undefined" ? null : window.location.origin;
11
+ }
12
+ function assetIconAppUrl({
13
+ appUrl,
14
+ backendUrl,
15
+ pageOrigin = currentPageOrigin()
16
+ }) {
17
+ if (!appUrl) return null;
18
+ return athenaLinkAppUrl({ appUrl, backendUrl: backendUrl ?? "", pageOrigin });
19
+ }
8
20
  function athenaAppAssetIconBasePath({
9
21
  appUrl
10
22
  }) {
@@ -147,6 +159,7 @@ function assetTypeToIcon(assetType) {
147
159
  return ASSET_TYPE_LUCIDE_FALLBACK[key] ?? "file";
148
160
  }
149
161
  export {
162
+ assetIconAppUrl,
150
163
  assetTypeToIcon,
151
164
  assetTypeToThumb,
152
165
  athenaAppAssetIconBasePath,
@@ -1 +1 @@
1
- {"version":3,"file":"asset-type-icons.js","sources":["../../../../../../src/chat-ui/mentions/suggestions/data/sources/asset-type-icons.ts"],"sourcesContent":["/**\n * Athena's asset-type icons: the SVG Olympus draws for each asset type.\n *\n * The type → icon table is Olympus's own: `ASSET_TYPE_ICON_NAMES`\n * (`asset-type-icon-names.generated.ts`), generated from its\n * `AthenaTypeToThumb` by Olympus's parity test, which writes the same table\n * into `@athenaintel/sheets` and fails when either drifts. So the `@` menu, the\n * mention chips and the drive cards draw the icon Olympus draws for every type.\n *\n * Where the SVGs load from:\n * - type glyphs (`ic-…`): a host's own copy when it names one with\n * `configureAssetIconBasePath` (the Chrome extension), else the Athena web\n * app the chat talks to (`appUrl`, the provider's: `useAssetIconAppUrl`),\n * which serves the public files Olympus draws at `<appUrl>/assets/icons/files/`;\n * - brand logos (Power BI, Slack, Gmail, Outlook) sit in `apps/` beside them:\n * from that app when the chat names one (a host's copy may carry only the\n * glyphs), else beside the host's copy.\n *\n * With neither there is no SVG, and callers draw the type's Lucide icon\n * (`assetTypeToIcon`). `MentionIcon`, the chips and the drive cards also fall\n * back to it when an SVG cannot load (a strict CSP, offline).\n */\n\nimport {\n ASSET_TYPE_ICON_NAMES,\n DEFAULT_ASSET_TYPE_ICON,\n} from \"./asset-type-icon-names.generated\";\n\nlet hostIconBasePath: string | null = null;\n\n/**\n * Point the asset-type icons at the host's own copy of Olympus's\n * `assets/icons/files/` SVGs. `basePath` is resolved against the host\n * document; a trailing \"/\" is added when the caller omits it. `null` drops the\n * host copy: the icons then load from the Athena web app the chat talks to.\n */\nexport function configureAssetIconBasePath({\n basePath,\n}: {\n basePath: string | null;\n}): void {\n hostIconBasePath = basePath ? basePath.replace(/\\/*$/, \"/\") : null;\n}\n\n/** Where the Athena web app at `appUrl` serves the asset-type SVGs; null for an unusable URL. */\nexport function athenaAppAssetIconBasePath({\n appUrl,\n}: {\n appUrl: string | null | undefined;\n}): string | null {\n if (!appUrl?.trim()) return null;\n try {\n const base = new URL(\"/assets/icons/files/\", appUrl);\n return base.protocol === \"https:\" || base.protocol === \"http:\"\n ? base.toString()\n : null;\n } catch {\n return null;\n }\n}\n\nconst FILES_DIR = \"files/\";\n\n/** An icon's URL, from the host's copy or the chat's Athena web app (see the module doc). */\nfunction iconUrl({\n icon,\n appUrl,\n}: {\n icon: string;\n appUrl: string | null | undefined;\n}): string | undefined {\n const appBasePath = athenaAppAssetIconBasePath({ appUrl });\n if (/^ic[-_]/.test(icon)) {\n const basePath = hostIconBasePath ?? appBasePath;\n return basePath ? `${basePath}${icon}.svg` : undefined;\n }\n const filesBasePath = appBasePath ?? hostIconBasePath;\n if (!filesBasePath) return undefined;\n return filesBasePath.endsWith(`/${FILES_DIR}`)\n ? `${filesBasePath.slice(0, -FILES_DIR.length)}apps/${icon}.svg`\n : `${filesBasePath}${icon}.svg`;\n}\n\nfunction assetTypeIconName(assetType: string | null | undefined): string {\n const key = assetType?.toLowerCase();\n return key && Object.hasOwn(ASSET_TYPE_ICON_NAMES, key)\n ? (ASSET_TYPE_ICON_NAMES[key] ?? DEFAULT_ASSET_TYPE_ICON)\n : DEFAULT_ASSET_TYPE_ICON;\n}\n\n/**\n * The SVG URL of an asset type's icon, the one Olympus draws. `appUrl` is the\n * Athena web app the chat talks to (`useAssetIconAppUrl`); undefined when\n * neither it nor a host copy (`configureAssetIconBasePath`) is available.\n */\nexport function assetTypeToThumb(\n assetType: string | null | undefined,\n { appUrl }: { appUrl?: string | null } = {},\n): string | undefined {\n return iconUrl({ icon: assetTypeIconName(assetType), appUrl });\n}\n\nconst EMAIL_ASSET_TYPES: ReadonlySet<string> = new Set([\n \"email\",\n \"email_draft\",\n \"email_message\",\n \"live_email_thread\",\n]);\n\n/** Whether rows of this type can draw their mailbox's logo (`emailProviderThumb`). */\nexport function isEmailAssetType(assetType: string | null | undefined): boolean {\n return !!assetType && EMAIL_ASSET_TYPES.has(assetType.toLowerCase());\n}\n\nfunction recordOf(value: unknown): Record<string, unknown> | null {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n}\n\nconst LANE_PREFIX = /^paragon_/;\nconst LANE_SUFFIX = /_(direct(_v\\d+)?|paragon|live)$/;\n\n/** Gmail or Outlook, from the provider an email asset records; null for any other or none. */\nfunction mailboxLogo(metadata: unknown): \"gmail\" | \"outlook\" | null {\n const record = recordOf(metadata);\n if (!record) return null;\n const provider: unknown =\n recordOf(record.liveAsset)?.provider ??\n recordOf(record.email)?.provider ??\n recordOf(record.email_draft)?.provider;\n if (typeof provider !== \"string\") return null;\n const name = provider.trim().toLowerCase().replace(LANE_PREFIX, \"\").replace(LANE_SUFFIX, \"\");\n if (name === \"gmail\" || name === \"google\") return \"gmail\";\n if (name === \"outlook\" || name === \"microsoft_graph\") return \"outlook\";\n return null;\n}\n\n/**\n * The Gmail or Outlook logo for an email asset whose mailbox provider its\n * metadata records (`liveAsset.provider`, the `email` block agora writes\n * beside it, or a draft's `email_draft` block), as Olympus draws it;\n * undefined otherwise, for the type's mail icon.\n */\nexport function emailProviderThumb({\n assetType,\n metadata,\n appUrl,\n}: {\n assetType: string | null | undefined;\n metadata: unknown;\n /** The Athena web app the chat talks to (`useAssetIconAppUrl`). */\n appUrl?: string | null;\n}): string | undefined {\n if (!isEmailAssetType(assetType)) return undefined;\n const logo = mailboxLogo(metadata);\n return logo ? iconUrl({ icon: logo, appUrl }) : undefined;\n}\n\n/**\n * The Lucide icon (a `MentionIcon` name) drawn for an asset type when its SVG\n * is not available: no icon source, or the SVG failed to load.\n */\nconst ASSET_TYPE_LUCIDE_FALLBACK: Record<string, string> = {\n aop: \"workflow\",\n application: \"layout-grid\",\n audio: \"headphones\",\n automation: \"zap\",\n browse_profile: \"globe\",\n browse_session: \"globe\",\n canvas: \"palette\",\n catalog: \"database\",\n collab_agent: \"bot\",\n collab_source: \"database\",\n collab_toolkit: \"package\",\n collection: \"library\",\n computer: \"monitor\",\n dashboard: \"layout-dashboard\",\n database: \"database\",\n design_system: \"palette\",\n desktop_session: \"monitor\",\n device: \"smartphone\",\n document: \"file-text\",\n drive: \"hard-drive\",\n email: \"mail\",\n email_draft: \"mail\",\n email_message: \"mail\",\n environment: \"server\",\n figure: \"chart-bar\",\n folder: \"folder\",\n gdrive_folder: \"folder\",\n generic_doc: \"file-text\",\n image: \"image\",\n json: \"file-code\",\n lakehouse_namespace: \"database\",\n lakehouse_sync: \"workflow\",\n lakehouse_table: \"table\",\n live_calendar_event: \"calendar\",\n live_email_thread: \"mail\",\n markdown: \"file-text\",\n meeting: \"video\",\n mobile_session: \"smartphone\",\n notebook: \"book-open\",\n olympus_drive: \"hard-drive\",\n pdf: \"file-text\",\n person: \"user\",\n phone_call: \"phone\",\n playbook: \"book-open\",\n policy: \"check-square\",\n powerpoint_deck: \"presentation\",\n pptx: \"presentation\",\n presentation: \"presentation\",\n presentation_pptx_studio: \"presentation\",\n project: \"folder-kanban\",\n python: \"file-code\",\n query_snippet: \"database\",\n script: \"file-code\",\n secret: \"key\",\n semantic_model: \"database\",\n session: \"message-square\",\n skill: \"sparkles\",\n spreadsheet: \"sheet\",\n table: \"table\",\n transform_project: \"workflow\",\n txt: \"file-text\",\n user_interface: \"layout\",\n video: \"video\",\n video_session: \"video\",\n voice_memo: \"mic\",\n web_page: \"globe\",\n word_document: \"file-text\",\n yaml: \"file-code\",\n};\n\n/** The Lucide icon name for an asset type, drawn when its SVG is not available. */\nexport function assetTypeToIcon(assetType: string | null | undefined): string {\n const key = assetType?.toLowerCase();\n if (!key || !Object.hasOwn(ASSET_TYPE_LUCIDE_FALLBACK, key)) return \"file\";\n return ASSET_TYPE_LUCIDE_FALLBACK[key] ?? \"file\";\n}\n\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"asset-type-icons.js","sources":["../../../../../../src/chat-ui/mentions/suggestions/data/sources/asset-type-icons.ts"],"sourcesContent":["/**\n * Athena's asset-type icons: the SVG Olympus draws for each asset type.\n *\n * The type → icon table is Olympus's own: `ASSET_TYPE_ICON_NAMES`\n * (`asset-type-icon-names.generated.ts`), generated from its\n * `AthenaTypeToThumb` by Olympus's parity test, which writes the same table\n * into `@athenaintel/sheets` and fails when either drifts. So the `@` menu, the\n * mention chips and the drive cards draw the icon Olympus draws for every type.\n *\n * Where the SVGs load from:\n * - type glyphs (`ic-…`): a host's own copy when it names one with\n * `configureAssetIconBasePath` (the Chrome extension), else the Athena web\n * app the chat talks to (`appUrl`, the provider's: `useAssetIconAppUrl`),\n * which serves the public files Olympus draws at `<appUrl>/assets/icons/files/`;\n * - brand logos (Power BI, Slack, Gmail, Outlook) sit in `apps/` beside them:\n * from that app when the chat names one (a host's copy may carry only the\n * glyphs), else beside the host's copy.\n *\n * With neither there is no SVG, and callers draw the type's Lucide icon\n * (`assetTypeToIcon`). `MentionIcon`, the chips and the drive cards also fall\n * back to it when an SVG cannot load (a strict CSP, offline).\n */\n\nimport { athenaLinkAppUrl } from \"../../../../../lib/athena-urls\";\nimport {\n ASSET_TYPE_ICON_NAMES,\n DEFAULT_ASSET_TYPE_ICON,\n} from \"./asset-type-icon-names.generated\";\n\nlet hostIconBasePath: string | null = null;\n\n/**\n * Point the asset-type icons at the host's own copy of Olympus's\n * `assets/icons/files/` SVGs. `basePath` is resolved against the host\n * document; a trailing \"/\" is added when the caller omits it. `null` drops the\n * host copy: the icons then load from the Athena web app the chat talks to.\n */\nexport function configureAssetIconBasePath({\n basePath,\n}: {\n basePath: string | null;\n}): void {\n hostIconBasePath = basePath ? basePath.replace(/\\/*$/, \"/\") : null;\n}\n\nfunction currentPageOrigin(): string | null {\n return typeof window === \"undefined\" ? null : window.location.origin;\n}\n\n/**\n * The Athena web app whose icons a chat draws: the provider's `appUrl`,\n * except in an app a computer serves, where Marathon's `/_athena/auth` mints\n * `appUrl` as the app's own origin (which serves no Athena icons) and the\n * deployment's frontend serves them, as for \"Open in Athena\" links\n * (`athenaLinkAppUrl`). Null without an `appUrl`.\n */\nexport function assetIconAppUrl({\n appUrl,\n backendUrl,\n pageOrigin = currentPageOrigin(),\n}: {\n appUrl: string | null | undefined;\n backendUrl: string | null | undefined;\n pageOrigin?: string | null;\n}): string | null {\n if (!appUrl) return null;\n return athenaLinkAppUrl({ appUrl, backendUrl: backendUrl ?? \"\", pageOrigin });\n}\n\n/** Where the Athena web app at `appUrl` serves the asset-type SVGs; null for an unusable URL. */\nexport function athenaAppAssetIconBasePath({\n appUrl,\n}: {\n appUrl: string | null | undefined;\n}): string | null {\n if (!appUrl?.trim()) return null;\n try {\n const base = new URL(\"/assets/icons/files/\", appUrl);\n return base.protocol === \"https:\" || base.protocol === \"http:\"\n ? base.toString()\n : null;\n } catch {\n return null;\n }\n}\n\nconst FILES_DIR = \"files/\";\n\n/** An icon's URL, from the host's copy or the chat's Athena web app (see the module doc). */\nfunction iconUrl({\n icon,\n appUrl,\n}: {\n icon: string;\n appUrl: string | null | undefined;\n}): string | undefined {\n const appBasePath = athenaAppAssetIconBasePath({ appUrl });\n if (/^ic[-_]/.test(icon)) {\n const basePath = hostIconBasePath ?? appBasePath;\n return basePath ? `${basePath}${icon}.svg` : undefined;\n }\n const filesBasePath = appBasePath ?? hostIconBasePath;\n if (!filesBasePath) return undefined;\n return filesBasePath.endsWith(`/${FILES_DIR}`)\n ? `${filesBasePath.slice(0, -FILES_DIR.length)}apps/${icon}.svg`\n : `${filesBasePath}${icon}.svg`;\n}\n\nfunction assetTypeIconName(assetType: string | null | undefined): string {\n const key = assetType?.toLowerCase();\n return key && Object.hasOwn(ASSET_TYPE_ICON_NAMES, key)\n ? (ASSET_TYPE_ICON_NAMES[key] ?? DEFAULT_ASSET_TYPE_ICON)\n : DEFAULT_ASSET_TYPE_ICON;\n}\n\n/**\n * The SVG URL of an asset type's icon, the one Olympus draws. `appUrl` is the\n * Athena web app the chat talks to (`useAssetIconAppUrl`); undefined when\n * neither it nor a host copy (`configureAssetIconBasePath`) is available.\n */\nexport function assetTypeToThumb(\n assetType: string | null | undefined,\n { appUrl }: { appUrl?: string | null } = {},\n): string | undefined {\n return iconUrl({ icon: assetTypeIconName(assetType), appUrl });\n}\n\nconst EMAIL_ASSET_TYPES: ReadonlySet<string> = new Set([\n \"email\",\n \"email_draft\",\n \"email_message\",\n \"live_email_thread\",\n]);\n\n/** Whether rows of this type can draw their mailbox's logo (`emailProviderThumb`). */\nexport function isEmailAssetType(assetType: string | null | undefined): boolean {\n return !!assetType && EMAIL_ASSET_TYPES.has(assetType.toLowerCase());\n}\n\nfunction recordOf(value: unknown): Record<string, unknown> | null {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n}\n\nconst LANE_PREFIX = /^paragon_/;\nconst LANE_SUFFIX = /_(direct(_v\\d+)?|paragon|live)$/;\n\n/** Gmail or Outlook, from the provider an email asset records; null for any other or none. */\nfunction mailboxLogo(metadata: unknown): \"gmail\" | \"outlook\" | null {\n const record = recordOf(metadata);\n if (!record) return null;\n const provider: unknown =\n recordOf(record.liveAsset)?.provider ??\n recordOf(record.email)?.provider ??\n recordOf(record.email_draft)?.provider;\n if (typeof provider !== \"string\") return null;\n const name = provider.trim().toLowerCase().replace(LANE_PREFIX, \"\").replace(LANE_SUFFIX, \"\");\n if (name === \"gmail\" || name === \"google\") return \"gmail\";\n if (name === \"outlook\" || name === \"microsoft_graph\") return \"outlook\";\n return null;\n}\n\n/**\n * The Gmail or Outlook logo for an email asset whose mailbox provider its\n * metadata records (`liveAsset.provider`, the `email` block agora writes\n * beside it, or a draft's `email_draft` block), as Olympus draws it;\n * undefined otherwise, for the type's mail icon.\n */\nexport function emailProviderThumb({\n assetType,\n metadata,\n appUrl,\n}: {\n assetType: string | null | undefined;\n metadata: unknown;\n /** The Athena web app the chat talks to (`useAssetIconAppUrl`). */\n appUrl?: string | null;\n}): string | undefined {\n if (!isEmailAssetType(assetType)) return undefined;\n const logo = mailboxLogo(metadata);\n return logo ? iconUrl({ icon: logo, appUrl }) : undefined;\n}\n\n/**\n * The Lucide icon (a `MentionIcon` name) drawn for an asset type when its SVG\n * is not available: no icon source, or the SVG failed to load.\n */\nconst ASSET_TYPE_LUCIDE_FALLBACK: Record<string, string> = {\n aop: \"workflow\",\n application: \"layout-grid\",\n audio: \"headphones\",\n automation: \"zap\",\n browse_profile: \"globe\",\n browse_session: \"globe\",\n canvas: \"palette\",\n catalog: \"database\",\n collab_agent: \"bot\",\n collab_source: \"database\",\n collab_toolkit: \"package\",\n collection: \"library\",\n computer: \"monitor\",\n dashboard: \"layout-dashboard\",\n database: \"database\",\n design_system: \"palette\",\n desktop_session: \"monitor\",\n device: \"smartphone\",\n document: \"file-text\",\n drive: \"hard-drive\",\n email: \"mail\",\n email_draft: \"mail\",\n email_message: \"mail\",\n environment: \"server\",\n figure: \"chart-bar\",\n folder: \"folder\",\n gdrive_folder: \"folder\",\n generic_doc: \"file-text\",\n image: \"image\",\n json: \"file-code\",\n lakehouse_namespace: \"database\",\n lakehouse_sync: \"workflow\",\n lakehouse_table: \"table\",\n live_calendar_event: \"calendar\",\n live_email_thread: \"mail\",\n markdown: \"file-text\",\n meeting: \"video\",\n mobile_session: \"smartphone\",\n notebook: \"book-open\",\n olympus_drive: \"hard-drive\",\n pdf: \"file-text\",\n person: \"user\",\n phone_call: \"phone\",\n playbook: \"book-open\",\n policy: \"check-square\",\n powerpoint_deck: \"presentation\",\n pptx: \"presentation\",\n presentation: \"presentation\",\n presentation_pptx_studio: \"presentation\",\n project: \"folder-kanban\",\n python: \"file-code\",\n query_snippet: \"database\",\n script: \"file-code\",\n secret: \"key\",\n semantic_model: \"database\",\n session: \"message-square\",\n skill: \"sparkles\",\n spreadsheet: \"sheet\",\n table: \"table\",\n transform_project: \"workflow\",\n txt: \"file-text\",\n user_interface: \"layout\",\n video: \"video\",\n video_session: \"video\",\n voice_memo: \"mic\",\n web_page: \"globe\",\n word_document: \"file-text\",\n yaml: \"file-code\",\n};\n\n/** The Lucide icon name for an asset type, drawn when its SVG is not available. */\nexport function assetTypeToIcon(assetType: string | null | undefined): string {\n const key = assetType?.toLowerCase();\n if (!key || !Object.hasOwn(ASSET_TYPE_LUCIDE_FALLBACK, key)) return \"file\";\n return ASSET_TYPE_LUCIDE_FALLBACK[key] ?? \"file\";\n}\n\n"],"names":[],"mappings":"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"}
@@ -50,8 +50,9 @@ async function readEmailMetadata(auth, assets) {
50
50
  }
51
51
  async function assetsToMenuItems(auth, assets) {
52
52
  const metadata = await readEmailMetadata(auth, assets);
53
+ const appUrl = assetTypeIcons.assetIconAppUrl({ appUrl: auth.appUrl, backendUrl: auth.backendUrl }) ?? void 0;
53
54
  return assets.map(
54
- (asset) => assetToMenuItem({ asset, metadata: metadata.get(asset.id), appUrl: auth.appUrl })
55
+ (asset) => assetToMenuItem({ asset, metadata: metadata.get(asset.id), appUrl })
55
56
  );
56
57
  }
57
58
  async function querySimpleSearch(auth, opts) {