@athenaintel/react 0.9.4 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,6 +26,24 @@ function App() {
26
26
  }
27
27
  ```
28
28
 
29
+ ## Environment And URLs
30
+
31
+ ```tsx
32
+ <AthenaProvider environment="staging">
33
+ <AthenaChat />
34
+ </AthenaProvider>
35
+
36
+ <AthenaProvider
37
+ apiUrl="https://sync.example.com/api/chat"
38
+ backendUrl="https://api.example.com/api/assistant-ui"
39
+ appUrl="https://app.example.com"
40
+ >
41
+ <AthenaChat />
42
+ </AthenaProvider>
43
+ ```
44
+
45
+ If `appUrl` is omitted, the provider now resolves it from the parent bridge or from the matching Athena environment defaults. Known Athena staging/prod `apiUrl` and `backendUrl` values automatically fall back to the corresponding frontend origin.
46
+
29
47
  ## Theming
30
48
 
31
49
  ```tsx
package/dist/index.cjs CHANGED
@@ -16475,6 +16475,106 @@ const INTERNAL = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
16475
16475
  useSmoothStatus,
16476
16476
  useToolInvocations
16477
16477
  }, Symbol.toStringTag, { value: "Module" }));
16478
+ const ATHENA_ENVIRONMENT_URLS = {
16479
+ production: {
16480
+ apiUrl: "https://sync.athenaintel.com/api/chat",
16481
+ backendUrl: "https://api.athenaintel.com/api/assistant-ui",
16482
+ appUrl: "https://app.athenaintel.com"
16483
+ },
16484
+ staging: {
16485
+ apiUrl: "https://staging-sync.athenaintel.com/api/chat",
16486
+ backendUrl: "https://staging-api.athenaintel.com/api/assistant-ui",
16487
+ appUrl: "https://staging-app.athenaintel.com"
16488
+ }
16489
+ };
16490
+ const DEFAULT_ATHENA_ENVIRONMENT = "production";
16491
+ const DEFAULT_API_URL = ATHENA_ENVIRONMENT_URLS.production.apiUrl;
16492
+ const DEFAULT_BACKEND_URL = ATHENA_ENVIRONMENT_URLS.production.backendUrl;
16493
+ const DEFAULT_APP_URL = ATHENA_ENVIRONMENT_URLS.production.appUrl;
16494
+ const SPACES_PATHNAME = "/dashboard/spaces/";
16495
+ const normalizeBaseUrl = (url) => url.replace(/\/+$/, "");
16496
+ const getHostname = (value) => {
16497
+ if (!value) return null;
16498
+ try {
16499
+ return new URL(value).hostname;
16500
+ } catch {
16501
+ return null;
16502
+ }
16503
+ };
16504
+ const deriveWorkspaceAppUrl = ({
16505
+ sourceUrl,
16506
+ sourcePort
16507
+ }) => {
16508
+ var _a2;
16509
+ try {
16510
+ const parsedUrl = new URL(sourceUrl);
16511
+ const match2 = parsedUrl.hostname.match(
16512
+ new RegExp(`^(?<prefix>.+)--${sourcePort}\\.(?<domain>app\\.athenaintel\\.com|staging-app\\.athenaintel\\.com)$`)
16513
+ );
16514
+ if (!((_a2 = match2 == null ? void 0 : match2.groups) == null ? void 0 : _a2.prefix) || !match2.groups.domain) {
16515
+ return null;
16516
+ }
16517
+ return `${parsedUrl.protocol}//${match2.groups.prefix}--8082.${match2.groups.domain}`;
16518
+ } catch {
16519
+ return null;
16520
+ }
16521
+ };
16522
+ function getAthenaEnvironmentUrls({
16523
+ environment = DEFAULT_ATHENA_ENVIRONMENT
16524
+ } = {}) {
16525
+ return ATHENA_ENVIRONMENT_URLS[environment];
16526
+ }
16527
+ function deriveAthenaAppUrl({
16528
+ apiUrl,
16529
+ backendUrl
16530
+ }) {
16531
+ if (backendUrl) {
16532
+ const workspaceAppUrl = deriveWorkspaceAppUrl({
16533
+ sourceUrl: backendUrl,
16534
+ sourcePort: "8000"
16535
+ });
16536
+ if (workspaceAppUrl) return workspaceAppUrl;
16537
+ const backendHostname = getHostname(backendUrl);
16538
+ if (backendHostname === "api.athenaintel.com") {
16539
+ return ATHENA_ENVIRONMENT_URLS.production.appUrl;
16540
+ }
16541
+ if (backendHostname === "staging-api.athenaintel.com") {
16542
+ return ATHENA_ENVIRONMENT_URLS.staging.appUrl;
16543
+ }
16544
+ }
16545
+ if (apiUrl) {
16546
+ const workspaceAppUrl = deriveWorkspaceAppUrl({
16547
+ sourceUrl: apiUrl,
16548
+ sourcePort: "8787"
16549
+ });
16550
+ if (workspaceAppUrl) return workspaceAppUrl;
16551
+ const apiHostname = getHostname(apiUrl);
16552
+ if (apiHostname === "sync.athenaintel.com") {
16553
+ return ATHENA_ENVIRONMENT_URLS.production.appUrl;
16554
+ }
16555
+ if (apiHostname === "staging-sync.athenaintel.com") {
16556
+ return ATHENA_ENVIRONMENT_URLS.staging.appUrl;
16557
+ }
16558
+ }
16559
+ return null;
16560
+ }
16561
+ function createAthenaSpacesUrl({
16562
+ appUrl = DEFAULT_APP_URL,
16563
+ assetIds,
16564
+ sessionId
16565
+ }) {
16566
+ const url = new URL(SPACES_PATHNAME, `${normalizeBaseUrl(appUrl)}/`);
16567
+ if (assetIds) {
16568
+ const normalizedAssetIds = (Array.isArray(assetIds) ? assetIds : [assetIds]).map((assetId) => assetId.trim()).filter((assetId) => assetId.length > 0);
16569
+ if (normalizedAssetIds.length > 0) {
16570
+ url.searchParams.set("asset_ids", normalizedAssetIds.join(","));
16571
+ }
16572
+ }
16573
+ if (sessionId) {
16574
+ url.searchParams.set("session_id", sessionId);
16575
+ }
16576
+ return url.toString();
16577
+ }
16478
16578
  function isTrustedOrigin(origin) {
16479
16579
  try {
16480
16580
  const { hostname } = new URL(origin);
@@ -16490,6 +16590,7 @@ function useParentBridge() {
16490
16590
  token: null,
16491
16591
  apiUrl: null,
16492
16592
  backendUrl: null,
16593
+ appUrl: null,
16493
16594
  // If not in an iframe, we're ready immediately (standalone mode)
16494
16595
  ready: !isInIframe
16495
16596
  });
@@ -16505,7 +16606,8 @@ function useParentBridge() {
16505
16606
  setState((prev) => ({
16506
16607
  ...prev,
16507
16608
  apiUrl: typeof event.data.apiUrl === "string" ? event.data.apiUrl : prev.apiUrl,
16508
- backendUrl: typeof event.data.backendUrl === "string" ? event.data.backendUrl : prev.backendUrl
16609
+ backendUrl: typeof event.data.backendUrl === "string" ? event.data.backendUrl : prev.backendUrl,
16610
+ appUrl: typeof event.data.appUrl === "string" ? event.data.appUrl : prev.appUrl
16509
16611
  // Don't set ready here — wait for athena-auth (token) or the timeout.
16510
16612
  // Setting ready on config alone causes a race: the thread list fires
16511
16613
  // before the token arrives, falling back to X-API-KEY.
@@ -20737,8 +20839,6 @@ async function archiveThread(backendUrl, auth, threadId) {
20737
20839
  throw new Error(`[AthenaSDK] Failed to archive thread: ${res.status}`);
20738
20840
  }
20739
20841
  }
20740
- const DEFAULT_API_URL = "https://sync.athenaintel.com/api/chat";
20741
- const DEFAULT_BACKEND_URL = "https://api.athenaintel.com/api/assistant-ui";
20742
20842
  const DEFAULT_MODEL = "claude-opus-4-6-thinking-max-fast";
20743
20843
  const DEFAULT_AGENT = "athena_assist_agent";
20744
20844
  const ATHENA_TRACKING_ID_KEY = "_athena_tracking_id";
@@ -24318,7 +24418,7 @@ function useAthenaThreadListAdapter(config2) {
24318
24418
  );
24319
24419
  return React.useMemo(() => ({
24320
24420
  async list() {
24321
- if (!auth.token) {
24421
+ if (!auth.token && !auth.apiKey) {
24322
24422
  return { threads: [] };
24323
24423
  }
24324
24424
  try {
@@ -24547,6 +24647,7 @@ function AthenaStandalone({
24547
24647
  children,
24548
24648
  apiUrl,
24549
24649
  backendUrl,
24650
+ appUrl,
24550
24651
  apiKey,
24551
24652
  token,
24552
24653
  model,
@@ -24576,8 +24677,8 @@ function AthenaStandalone({
24576
24677
  threadId
24577
24678
  });
24578
24679
  const athenaConfig = React.useMemo(
24579
- () => ({ backendUrl, apiKey, token }),
24580
- [backendUrl, apiKey, token]
24680
+ () => ({ backendUrl, appUrl, apiKey, token }),
24681
+ [backendUrl, appUrl, apiKey, token]
24581
24682
  );
24582
24683
  return /* @__PURE__ */ jsxRuntime.jsx(AssistantRuntimeProvider, { aui, runtime, children: /* @__PURE__ */ jsxRuntime.jsx(AthenaContext.Provider, { value: athenaConfig, children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children }) }) });
24583
24684
  }
@@ -24602,6 +24703,7 @@ function AthenaWithThreadList({
24602
24703
  children,
24603
24704
  apiUrl,
24604
24705
  backendUrl,
24706
+ appUrl,
24605
24707
  apiKey,
24606
24708
  token,
24607
24709
  model,
@@ -24660,11 +24762,21 @@ function AthenaWithThreadList({
24660
24762
  core.__internal_load();
24661
24763
  }
24662
24764
  }, [runtime]);
24765
+ const previousAuthRefreshKeyRef = React.useRef(null);
24766
+ const authRefreshKey = `${backendUrl}::${apiKey ?? ""}::${token ?? ""}`;
24767
+ React.useEffect(() => {
24768
+ const previousAuthRefreshKey = previousAuthRefreshKeyRef.current;
24769
+ previousAuthRefreshKeyRef.current = authRefreshKey;
24770
+ if (previousAuthRefreshKey === null || previousAuthRefreshKey === authRefreshKey) {
24771
+ return;
24772
+ }
24773
+ handleRefresh();
24774
+ }, [authRefreshKey, handleRefresh]);
24663
24775
  const auiTools = React.useMemo(() => Tools({ toolkit: frontendTools }), [frontendTools]);
24664
24776
  const aui = useAui({ tools: auiTools });
24665
24777
  const athenaConfig = React.useMemo(
24666
- () => ({ backendUrl, apiKey, token }),
24667
- [backendUrl, apiKey, token]
24778
+ () => ({ backendUrl, appUrl, apiKey, token }),
24779
+ [backendUrl, appUrl, apiKey, token]
24668
24780
  );
24669
24781
  return /* @__PURE__ */ jsxRuntime.jsx(AssistantRuntimeProvider, { aui, runtime, children: /* @__PURE__ */ jsxRuntime.jsx(AthenaContext.Provider, { value: athenaConfig, children: /* @__PURE__ */ jsxRuntime.jsx(ThreadListRefreshContext.Provider, { value: handleRefresh, children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children }) }) }) });
24670
24782
  }
@@ -24678,6 +24790,8 @@ function AthenaProvider({
24678
24790
  frontendTools = {},
24679
24791
  apiUrl,
24680
24792
  backendUrl,
24793
+ appUrl,
24794
+ environment,
24681
24795
  workbench,
24682
24796
  knowledgeBase,
24683
24797
  systemPrompt,
@@ -24687,10 +24801,15 @@ function AthenaProvider({
24687
24801
  }) {
24688
24802
  const frontendToolNames = React.useMemo(() => Object.keys(frontendTools), [frontendTools]);
24689
24803
  const themeStyleVars = React.useMemo(() => theme ? themeToStyleVars(theme) : void 0, [theme]);
24804
+ const environmentUrls = React.useMemo(
24805
+ () => getAthenaEnvironmentUrls({ environment }),
24806
+ [environment]
24807
+ );
24690
24808
  const bridge = useParentBridge();
24691
24809
  const effectiveToken = tokenProp ?? bridge.token;
24692
- const effectiveApiUrl = apiUrl ?? bridge.apiUrl ?? DEFAULT_API_URL;
24693
- const effectiveBackendUrl = backendUrl ?? bridge.backendUrl ?? DEFAULT_BACKEND_URL;
24810
+ const effectiveApiUrl = apiUrl ?? bridge.apiUrl ?? environmentUrls.apiUrl ?? DEFAULT_API_URL;
24811
+ const effectiveBackendUrl = backendUrl ?? bridge.backendUrl ?? environmentUrls.backendUrl ?? DEFAULT_BACKEND_URL;
24812
+ const effectiveAppUrl = appUrl ?? bridge.appUrl ?? deriveAthenaAppUrl({ apiUrl: effectiveApiUrl, backendUrl: effectiveBackendUrl }) ?? environmentUrls.appUrl ?? DEFAULT_APP_URL;
24694
24813
  if (!bridge.ready) {
24695
24814
  return null;
24696
24815
  }
@@ -24701,6 +24820,7 @@ function AthenaProvider({
24701
24820
  {
24702
24821
  apiUrl: effectiveApiUrl,
24703
24822
  backendUrl: effectiveBackendUrl,
24823
+ appUrl: effectiveAppUrl,
24704
24824
  apiKey,
24705
24825
  token: effectiveToken,
24706
24826
  model,
@@ -24720,6 +24840,7 @@ function AthenaProvider({
24720
24840
  {
24721
24841
  apiUrl: effectiveApiUrl,
24722
24842
  backendUrl: effectiveBackendUrl,
24843
+ appUrl: effectiveAppUrl,
24723
24844
  apiKey,
24724
24845
  token: effectiveToken,
24725
24846
  model,
@@ -60517,9 +60638,12 @@ function useAttachments() {
60517
60638
  }
60518
60639
  return ctx;
60519
60640
  }
60520
- function buildAttachmentMarkdown(attachments) {
60641
+ function buildAttachmentMarkdownWithAppUrl({
60642
+ attachments,
60643
+ appUrl = DEFAULT_APP_URL
60644
+ }) {
60521
60645
  if (attachments.length === 0) return "";
60522
- return attachments.map((a) => `[@${a.title}](https://app.athenaintel.com/dashboard/spaces?asset_id=${a.id})`).join("\n");
60646
+ return attachments.map((attachment) => `[@${attachment.title}](${createAthenaSpacesUrl({ appUrl, assetIds: attachment.id })})`).join("\n");
60523
60647
  }
60524
60648
  const QuoteCtx = React.createContext(null);
60525
60649
  function QuoteProvider({ children }) {
@@ -60585,7 +60709,10 @@ function buildComposedMessage(opts) {
60585
60709
  var _a2;
60586
60710
  const parts = [];
60587
60711
  if (opts.attachments && opts.attachments.length > 0) {
60588
- const attachmentMd = buildAttachmentMarkdown(opts.attachments);
60712
+ const attachmentMd = buildAttachmentMarkdownWithAppUrl({
60713
+ attachments: opts.attachments,
60714
+ appUrl: opts.appUrl
60715
+ });
60589
60716
  if (attachmentMd) parts.push(attachmentMd);
60590
60717
  }
60591
60718
  if (opts.quote) {
@@ -60606,6 +60733,7 @@ const TiptapComposer = ({ tools = [] }) => {
60606
60733
  const mentionStore = useMentionSuggestions(tools);
60607
60734
  const { attachments, clearAttachments, isUploading } = useAttachments();
60608
60735
  const { quote, clearQuote } = useQuote();
60736
+ const { appUrl } = useAthenaConfig();
60609
60737
  const attachmentsRef = React.useRef(attachments);
60610
60738
  attachmentsRef.current = attachments;
60611
60739
  const quoteRef = React.useRef(quote);
@@ -60626,7 +60754,8 @@ const TiptapComposer = ({ tools = [] }) => {
60626
60754
  const fullMessage = buildComposedMessage({
60627
60755
  attachments: currentAttachments,
60628
60756
  quote: currentQuote,
60629
- userText: markdown
60757
+ userText: markdown,
60758
+ appUrl
60630
60759
  });
60631
60760
  if (fullMessage) {
60632
60761
  aui.thread().append({
@@ -63976,6 +64105,7 @@ const ComposerAction = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { className:
63976
64105
  ] });
63977
64106
  const ComposerSendWithQuote = () => {
63978
64107
  const aui = useAui();
64108
+ const { appUrl } = useAthenaConfig();
63979
64109
  const { quote, clearQuote } = useQuote();
63980
64110
  const { attachments, clearAttachments, isUploading } = useAttachments();
63981
64111
  const editorRef = useComposerEditorRef();
@@ -63989,7 +64119,8 @@ const ComposerSendWithQuote = () => {
63989
64119
  const fullMessage = buildComposedMessage({
63990
64120
  attachments,
63991
64121
  quote,
63992
- userText
64122
+ userText,
64123
+ appUrl
63993
64124
  });
63994
64125
  if (!fullMessage) return;
63995
64126
  aui.thread().append({
@@ -64073,6 +64204,7 @@ const AssistantMessage = ({ toolUIs }) => /* @__PURE__ */ jsxRuntime.jsxs(
64073
64204
  );
64074
64205
  const AssistantActionBar = () => {
64075
64206
  const threadId = useAthenaThreadId();
64207
+ const { appUrl } = useAthenaConfig();
64076
64208
  return /* @__PURE__ */ jsxRuntime.jsxs(
64077
64209
  ActionBarPrimitiveRoot,
64078
64210
  {
@@ -64102,10 +64234,7 @@ const AssistantActionBar = () => {
64102
64234
  {
64103
64235
  className: "aui-action-bar-more-item flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
64104
64236
  onClick: () => {
64105
- window.open(
64106
- `https://app.athenaintel.com/dashboard/spaces?session_id=${threadId}`,
64107
- "_blank"
64108
- );
64237
+ window.open(createAthenaSpacesUrl({ appUrl, sessionId: threadId }), "_blank");
64109
64238
  },
64110
64239
  children: [
64111
64240
  /* @__PURE__ */ jsxRuntime.jsx(ExternalLink, { className: "size-4" }),
@@ -64592,6 +64721,7 @@ exports.CreateNotebookToolUI = CreateNotebookToolUI;
64592
64721
  exports.CreatePresentationToolUI = CreatePresentationToolUI;
64593
64722
  exports.CreateSheetToolUI = CreateSheetToolUI;
64594
64723
  exports.DEFAULT_API_URL = DEFAULT_API_URL;
64724
+ exports.DEFAULT_APP_URL = DEFAULT_APP_URL;
64595
64725
  exports.DEFAULT_BACKEND_URL = DEFAULT_BACKEND_URL;
64596
64726
  exports.EmailSearchToolUI = EmailSearchToolUI;
64597
64727
  exports.ExpandableSection = ExpandableSection;