@athenaintel/react 0.9.5 → 0.9.7

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
@@ -17,7 +17,7 @@ import '@athenaintel/react/styles.css';
17
17
  function App() {
18
18
  return (
19
19
  <AthenaProvider
20
- apiKey="your-api-key"
20
+ config={{ apiKey: 'your-api-key' }}
21
21
  tools={[Toolkits.DOCUMENT, Toolkits.WEB_SEARCH]}
22
22
  >
23
23
  <AthenaChat />
@@ -26,6 +26,28 @@ function App() {
26
26
  }
27
27
  ```
28
28
 
29
+ ## Provider Config
30
+
31
+ ```tsx
32
+ <AthenaProvider config={{ environment: 'staging' }}>
33
+ <AthenaChat />
34
+ </AthenaProvider>
35
+
36
+ <AthenaProvider
37
+ config={{
38
+ apiUrl: 'https://sync.example.com/api/chat',
39
+ backendUrl: 'https://api.example.com',
40
+ appUrl: 'https://app.example.com',
41
+ }}
42
+ >
43
+ <AthenaChat />
44
+ </AthenaProvider>
45
+ ```
46
+
47
+ `config` accepts `apiKey`, `token`, `apiUrl`, `backendUrl`, `appUrl`, and `environment`. Top-level `apiKey`, `token`, `apiUrl`, `backendUrl`, `appUrl`, and `environment` props remain supported as compatibility aliases, but `config` is now the preferred API.
48
+
49
+ If `config.appUrl` is omitted, the provider resolves it from the parent bridge or from the matching Athena environment defaults. Known Athena staging and production `apiUrl` and `backendUrl` values automatically fall back to the corresponding frontend origin.
50
+
29
51
  ## Theming
30
52
 
31
53
  ```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.
@@ -20675,7 +20777,7 @@ function getAuthHeaders(auth) {
20675
20777
  }
20676
20778
  return {};
20677
20779
  }
20678
- function getAgoraBaseUrl(backendUrl) {
20780
+ function getAthenaApiBaseUrl(backendUrl) {
20679
20781
  const stripped = backendUrl.replace(/\/api\/assistant-ui\/?$/, "");
20680
20782
  if (stripped === backendUrl) {
20681
20783
  return backendUrl.replace(/\/$/, "");
@@ -20683,7 +20785,7 @@ function getAgoraBaseUrl(backendUrl) {
20683
20785
  return stripped;
20684
20786
  }
20685
20787
  async function listThreads(backendUrl, auth, opts = {}) {
20686
- const base2 = getAgoraBaseUrl(backendUrl);
20788
+ const base2 = getAthenaApiBaseUrl(backendUrl);
20687
20789
  const res = await fetch(`${base2}/api/conversations/threads/list`, {
20688
20790
  method: "POST",
20689
20791
  headers: { "Content-Type": "application/json", ...getAuthHeaders(auth) },
@@ -20712,7 +20814,7 @@ function deserializeMessage(msg) {
20712
20814
  return msg;
20713
20815
  }
20714
20816
  async function getThreadState(backendUrl, auth, threadId) {
20715
- const base2 = getAgoraBaseUrl(backendUrl);
20817
+ const base2 = getAthenaApiBaseUrl(backendUrl);
20716
20818
  const res = await fetch(`${base2}/api/unstable/threads/${threadId}`, {
20717
20819
  method: "GET",
20718
20820
  headers: { ...getAuthHeaders(auth) }
@@ -20727,7 +20829,7 @@ async function getThreadState(backendUrl, auth, threadId) {
20727
20829
  return data;
20728
20830
  }
20729
20831
  async function archiveThread(backendUrl, auth, threadId) {
20730
- const base2 = getAgoraBaseUrl(backendUrl);
20832
+ const base2 = getAthenaApiBaseUrl(backendUrl);
20731
20833
  const res = await fetch(`${base2}/api/conversations/threads/archive`, {
20732
20834
  method: "POST",
20733
20835
  headers: { "Content-Type": "application/json", ...getAuthHeaders(auth) },
@@ -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";
@@ -24543,10 +24643,20 @@ const themes = {
24543
24643
  radius: "0.625rem"
24544
24644
  }
24545
24645
  };
24646
+ const resolveTokenOverride = ({
24647
+ config: config2,
24648
+ token
24649
+ }) => {
24650
+ if ((config2 == null ? void 0 : config2.token) !== void 0) {
24651
+ return config2.token;
24652
+ }
24653
+ return token;
24654
+ };
24546
24655
  function AthenaStandalone({
24547
24656
  children,
24548
24657
  apiUrl,
24549
24658
  backendUrl,
24659
+ appUrl,
24550
24660
  apiKey,
24551
24661
  token,
24552
24662
  model,
@@ -24576,8 +24686,8 @@ function AthenaStandalone({
24576
24686
  threadId
24577
24687
  });
24578
24688
  const athenaConfig = React.useMemo(
24579
- () => ({ backendUrl, apiKey, token }),
24580
- [backendUrl, apiKey, token]
24689
+ () => ({ backendUrl, appUrl, apiKey, token }),
24690
+ [backendUrl, appUrl, apiKey, token]
24581
24691
  );
24582
24692
  return /* @__PURE__ */ jsxRuntime.jsx(AssistantRuntimeProvider, { aui, runtime, children: /* @__PURE__ */ jsxRuntime.jsx(AthenaContext.Provider, { value: athenaConfig, children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children }) }) });
24583
24693
  }
@@ -24602,6 +24712,7 @@ function AthenaWithThreadList({
24602
24712
  children,
24603
24713
  apiUrl,
24604
24714
  backendUrl,
24715
+ appUrl,
24605
24716
  apiKey,
24606
24717
  token,
24607
24718
  model,
@@ -24673,13 +24784,14 @@ function AthenaWithThreadList({
24673
24784
  const auiTools = React.useMemo(() => Tools({ toolkit: frontendTools }), [frontendTools]);
24674
24785
  const aui = useAui({ tools: auiTools });
24675
24786
  const athenaConfig = React.useMemo(
24676
- () => ({ backendUrl, apiKey, token }),
24677
- [backendUrl, apiKey, token]
24787
+ () => ({ backendUrl, appUrl, apiKey, token }),
24788
+ [backendUrl, appUrl, apiKey, token]
24678
24789
  );
24679
24790
  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 }) }) }) });
24680
24791
  }
24681
24792
  function AthenaProvider({
24682
24793
  children,
24794
+ config: config2,
24683
24795
  apiKey,
24684
24796
  token: tokenProp,
24685
24797
  agent: agent2,
@@ -24688,6 +24800,8 @@ function AthenaProvider({
24688
24800
  frontendTools = {},
24689
24801
  apiUrl,
24690
24802
  backendUrl,
24803
+ appUrl,
24804
+ environment,
24691
24805
  workbench,
24692
24806
  knowledgeBase,
24693
24807
  systemPrompt,
@@ -24697,10 +24811,21 @@ function AthenaProvider({
24697
24811
  }) {
24698
24812
  const frontendToolNames = React.useMemo(() => Object.keys(frontendTools), [frontendTools]);
24699
24813
  const themeStyleVars = React.useMemo(() => theme ? themeToStyleVars(theme) : void 0, [theme]);
24814
+ const configuredEnvironment = (config2 == null ? void 0 : config2.environment) ?? environment;
24815
+ const environmentUrls = React.useMemo(
24816
+ () => getAthenaEnvironmentUrls({ environment: configuredEnvironment }),
24817
+ [configuredEnvironment]
24818
+ );
24819
+ const configuredApiKey = (config2 == null ? void 0 : config2.apiKey) ?? apiKey;
24820
+ const configuredToken = resolveTokenOverride({ config: config2, token: tokenProp });
24821
+ const configuredApiUrl = (config2 == null ? void 0 : config2.apiUrl) ?? apiUrl;
24822
+ const configuredBackendUrl = (config2 == null ? void 0 : config2.backendUrl) ?? backendUrl;
24823
+ const configuredAppUrl = (config2 == null ? void 0 : config2.appUrl) ?? appUrl;
24700
24824
  const bridge = useParentBridge();
24701
- const effectiveToken = tokenProp ?? bridge.token;
24702
- const effectiveApiUrl = apiUrl ?? bridge.apiUrl ?? DEFAULT_API_URL;
24703
- const effectiveBackendUrl = backendUrl ?? bridge.backendUrl ?? DEFAULT_BACKEND_URL;
24825
+ const effectiveToken = configuredToken !== void 0 ? configuredToken : bridge.token;
24826
+ const effectiveApiUrl = configuredApiUrl ?? bridge.apiUrl ?? environmentUrls.apiUrl ?? DEFAULT_API_URL;
24827
+ const effectiveBackendUrl = configuredBackendUrl ?? bridge.backendUrl ?? environmentUrls.backendUrl ?? DEFAULT_BACKEND_URL;
24828
+ const effectiveAppUrl = configuredAppUrl ?? bridge.appUrl ?? deriveAthenaAppUrl({ apiUrl: effectiveApiUrl, backendUrl: effectiveBackendUrl }) ?? environmentUrls.appUrl ?? DEFAULT_APP_URL;
24704
24829
  if (!bridge.ready) {
24705
24830
  return null;
24706
24831
  }
@@ -24711,7 +24836,8 @@ function AthenaProvider({
24711
24836
  {
24712
24837
  apiUrl: effectiveApiUrl,
24713
24838
  backendUrl: effectiveBackendUrl,
24714
- apiKey,
24839
+ appUrl: effectiveAppUrl,
24840
+ apiKey: configuredApiKey,
24715
24841
  token: effectiveToken,
24716
24842
  model,
24717
24843
  agent: agent2,
@@ -24730,7 +24856,8 @@ function AthenaProvider({
24730
24856
  {
24731
24857
  apiUrl: effectiveApiUrl,
24732
24858
  backendUrl: effectiveBackendUrl,
24733
- apiKey,
24859
+ appUrl: effectiveAppUrl,
24860
+ apiKey: configuredApiKey,
24734
24861
  token: effectiveToken,
24735
24862
  model,
24736
24863
  agent: agent2,
@@ -60527,9 +60654,12 @@ function useAttachments() {
60527
60654
  }
60528
60655
  return ctx;
60529
60656
  }
60530
- function buildAttachmentMarkdown(attachments) {
60657
+ function buildAttachmentMarkdownWithAppUrl({
60658
+ attachments,
60659
+ appUrl = DEFAULT_APP_URL
60660
+ }) {
60531
60661
  if (attachments.length === 0) return "";
60532
- return attachments.map((a) => `[@${a.title}](https://app.athenaintel.com/dashboard/spaces?asset_id=${a.id})`).join("\n");
60662
+ return attachments.map((attachment) => `[@${attachment.title}](${createAthenaSpacesUrl({ appUrl, assetIds: attachment.id })})`).join("\n");
60533
60663
  }
60534
60664
  const QuoteCtx = React.createContext(null);
60535
60665
  function QuoteProvider({ children }) {
@@ -60595,7 +60725,10 @@ function buildComposedMessage(opts) {
60595
60725
  var _a2;
60596
60726
  const parts = [];
60597
60727
  if (opts.attachments && opts.attachments.length > 0) {
60598
- const attachmentMd = buildAttachmentMarkdown(opts.attachments);
60728
+ const attachmentMd = buildAttachmentMarkdownWithAppUrl({
60729
+ attachments: opts.attachments,
60730
+ appUrl: opts.appUrl
60731
+ });
60599
60732
  if (attachmentMd) parts.push(attachmentMd);
60600
60733
  }
60601
60734
  if (opts.quote) {
@@ -60616,6 +60749,7 @@ const TiptapComposer = ({ tools = [] }) => {
60616
60749
  const mentionStore = useMentionSuggestions(tools);
60617
60750
  const { attachments, clearAttachments, isUploading } = useAttachments();
60618
60751
  const { quote, clearQuote } = useQuote();
60752
+ const { appUrl } = useAthenaConfig();
60619
60753
  const attachmentsRef = React.useRef(attachments);
60620
60754
  attachmentsRef.current = attachments;
60621
60755
  const quoteRef = React.useRef(quote);
@@ -60636,7 +60770,8 @@ const TiptapComposer = ({ tools = [] }) => {
60636
60770
  const fullMessage = buildComposedMessage({
60637
60771
  attachments: currentAttachments,
60638
60772
  quote: currentQuote,
60639
- userText: markdown
60773
+ userText: markdown,
60774
+ appUrl
60640
60775
  });
60641
60776
  if (fullMessage) {
60642
60777
  aui.thread().append({
@@ -63561,9 +63696,6 @@ function useFileUpload() {
63561
63696
  formData.append("files", file, file.name);
63562
63697
  }
63563
63698
  const baseUrl = backendUrl.replace(/\/api\/assistant-ui\/?$/, "");
63564
- if (baseUrl === backendUrl) {
63565
- console.warn("[AthenaSDK] useFileUpload: backendUrl does not end with /api/assistant-ui — upload URL may be incorrect:", `${baseUrl}/api/upload/`);
63566
- }
63567
63699
  const uploadUrl = `${baseUrl}/api/upload/`;
63568
63700
  const headers = {};
63569
63701
  if (token) {
@@ -63986,6 +64118,7 @@ const ComposerAction = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { className:
63986
64118
  ] });
63987
64119
  const ComposerSendWithQuote = () => {
63988
64120
  const aui = useAui();
64121
+ const { appUrl } = useAthenaConfig();
63989
64122
  const { quote, clearQuote } = useQuote();
63990
64123
  const { attachments, clearAttachments, isUploading } = useAttachments();
63991
64124
  const editorRef = useComposerEditorRef();
@@ -63999,7 +64132,8 @@ const ComposerSendWithQuote = () => {
63999
64132
  const fullMessage = buildComposedMessage({
64000
64133
  attachments,
64001
64134
  quote,
64002
- userText
64135
+ userText,
64136
+ appUrl
64003
64137
  });
64004
64138
  if (!fullMessage) return;
64005
64139
  aui.thread().append({
@@ -64083,6 +64217,7 @@ const AssistantMessage = ({ toolUIs }) => /* @__PURE__ */ jsxRuntime.jsxs(
64083
64217
  );
64084
64218
  const AssistantActionBar = () => {
64085
64219
  const threadId = useAthenaThreadId();
64220
+ const { appUrl } = useAthenaConfig();
64086
64221
  return /* @__PURE__ */ jsxRuntime.jsxs(
64087
64222
  ActionBarPrimitiveRoot,
64088
64223
  {
@@ -64112,10 +64247,7 @@ const AssistantActionBar = () => {
64112
64247
  {
64113
64248
  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",
64114
64249
  onClick: () => {
64115
- window.open(
64116
- `https://app.athenaintel.com/dashboard/spaces?session_id=${threadId}`,
64117
- "_blank"
64118
- );
64250
+ window.open(createAthenaSpacesUrl({ appUrl, sessionId: threadId }), "_blank");
64119
64251
  },
64120
64252
  children: [
64121
64253
  /* @__PURE__ */ jsxRuntime.jsx(ExternalLink, { className: "size-4" }),
@@ -64164,8 +64296,8 @@ function useAssetEmbed(assetId, options = {
64164
64296
  setError(null);
64165
64297
  return;
64166
64298
  }
64167
- const agoraBase = backendUrl.replace(/\/api\/assistant-ui\/?$/, "");
64168
- const endpoint = `${agoraBase}/api/embed/generate-token`;
64299
+ const apiBaseUrl = backendUrl.replace(/\/api\/assistant-ui\/?$/, "");
64300
+ const endpoint = `${apiBaseUrl}/api/embed/generate-token`;
64169
64301
  (_a2 = abortRef.current) == null ? void 0 : _a2.abort();
64170
64302
  const controller = new AbortController();
64171
64303
  abortRef.current = controller;
@@ -64602,6 +64734,7 @@ exports.CreateNotebookToolUI = CreateNotebookToolUI;
64602
64734
  exports.CreatePresentationToolUI = CreatePresentationToolUI;
64603
64735
  exports.CreateSheetToolUI = CreateSheetToolUI;
64604
64736
  exports.DEFAULT_API_URL = DEFAULT_API_URL;
64737
+ exports.DEFAULT_APP_URL = DEFAULT_APP_URL;
64605
64738
  exports.DEFAULT_BACKEND_URL = DEFAULT_BACKEND_URL;
64606
64739
  exports.EmailSearchToolUI = EmailSearchToolUI;
64607
64740
  exports.ExpandableSection = ExpandableSection;