@athenaintel/react 0.16.2 → 0.17.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.
package/README.md CHANGED
@@ -82,15 +82,19 @@ back onto the legacy Iris `/api/chat` stream:
82
82
  `collab_agent:<id>` refs (with `transport: 'statewire'` semantics) or the
83
83
  default agent.
84
84
 
85
- The sync endpoint defaults to the effective `apiUrl` host + `/v2/threads`
86
- (e.g. staging resolves to `https://iris.stg.athenaintel.com/v2/threads`, the
87
- same statewire base the mobile app and Chrome extension ship); pass
88
- `statewireSyncUrl` to override it for custom hosts whose sync mount lives on
89
- a different origin. If neither yields a URL (e.g. an unparseable custom
90
- `apiUrl`), the provider throws instead of falling back to an Athena default —
91
- credentials are never sent to a host you didn't configure. Auth reuses the
92
- provider's existing credential plumbing: tokens ride `Authorization: Bearer`
93
- and API keys ride `X-API-KEY`.
85
+ The sync endpoint resolves in this order: an explicit `statewireSyncUrl`; the
86
+ `statewireSyncUrl` the host environment supplies (a Marathon-served computer
87
+ asset mints it from `/_athena/auth` alongside `backendBaseUrl`, the bare Agora
88
+ base a trusted parent iframe can post the same fields); then the effective
89
+ `apiUrl` host + `/v2/threads` (e.g. staging resolves to
90
+ `https://iris.stg.athenaintel.com/v2/threads`, the same statewire base the
91
+ mobile app and Chrome extension ship). Pass `statewireSyncUrl` to pin a custom
92
+ host whose sync mount lives on a different origin. If nothing yields a URL
93
+ (e.g. an unparseable custom `apiUrl`), the provider throws instead of falling
94
+ back to an Athena default — credentials are never sent to a host you didn't
95
+ configure. Hosts that predate the minted statewire fields keep working through
96
+ the `apiUrl` derivation. Auth reuses the provider's existing credential
97
+ plumbing: tokens ride `Authorization: Bearer` and API keys ride `X-API-KEY`.
94
98
 
95
99
  What the statewire transport wires up in `AthenaChat`:
96
100
 
@@ -38,6 +38,13 @@ export interface AssetPanelState {
38
38
  slideNumber?: number;
39
39
  /** Citation target (anchor + excerpt) the open should navigate to. */
40
40
  reference?: AthenaAssetCitationReference;
41
+ /**
42
+ * Swap the active tab for this asset instead of appending another tab.
43
+ * Citation clicks use this: reading references shouldn't accumulate a
44
+ * tab per cited document — the panel behaves as one preview surface.
45
+ * A tab that already exists for the asset is re-targeted either way.
46
+ */
47
+ replaceActiveTab?: boolean;
41
48
  }) => void;
42
49
  closeTab: (assetId: string) => void;
43
50
  setActiveTab: (assetId: string) => void;
@@ -29,6 +29,10 @@ export declare function resolveAssetEmbedUrl({ embedUrl, appUrl, backendUrl, cur
29
29
  backendUrl?: string | null;
30
30
  currentOrigin?: string | null;
31
31
  }): string;
32
+ export declare function appendCitationReferenceParams({ params, reference, }: {
33
+ params: URLSearchParams;
34
+ reference?: AthenaAssetCitationReference;
35
+ }): void;
32
36
  export declare function buildSdkAssetEmbedUrl(embedUrl: string, reference?: AthenaAssetCitationReference): string;
33
37
  export declare function getAssetEmbedAuthContext({ token, apiKey }: {
34
38
  token?: string | null;
@@ -15,6 +15,14 @@ export interface AthenaChatProps {
15
15
  welcomeSubtext?: string;
16
16
  /** Maximum width for the thread content. Defaults to "44rem". */
17
17
  maxWidth?: string;
18
+ /**
19
+ * Scroll anchoring for new turns. "bottom" (default) keeps the viewport
20
+ * pinned to the end while the assistant streams — classic chat follow.
21
+ * "top" pins the just-sent user message to the top of the viewport and
22
+ * intentionally does NOT follow the streaming response (assistant-ui
23
+ * disables autoScroll in that mode), so readers scroll at their own pace.
24
+ */
25
+ turnAnchor?: "top" | "bottom";
18
26
  /** Additional tool UIs to register by name. */
19
27
  toolUIs?: Record<string, ToolCallMessagePartComponent>;
20
28
  /** Mention tools available in the composer. */
package/dist/chat-ui.cjs CHANGED
@@ -3,7 +3,7 @@ var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
6
- const useRestConversationHistory = require("./use-rest-conversation-history-CbMCaMzR.cjs");
6
+ const useRestConversationHistory = require("./use-rest-conversation-history-BdnG8jEP.cjs");
7
7
  const jsxRuntime = require("react/jsx-runtime");
8
8
  const React = require("react");
9
9
  const react = require("@assistant-ui/react");
package/dist/chat-ui.js CHANGED
@@ -1,8 +1,8 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { au as createLucideIcon, O as cn, bJ as THREAD_HEADER_ACTIONS_CLASS, bK as THREAD_HEADER_PILL_CLASS, bL as THREAD_HEADER_CLASS, b4 as RefreshCw, bm as Plus, b9 as Search, be as LoaderCircle, bx as conversationDisplayTitle, b7 as Archive, bM as assetTypeToThumb, aA as MessageSquare, ak as Node, a2 as mergeAttributes, aq as Extension, aW as Suggestion, aU as useFloating, aV as FloatingPortal, N as autoUpdate, F as offset, I as flip, G as shift, aS as getFilteredItems, bN as getFetchState, bO as getEntry, bP as updateFetchState, a_ as addItems, aZ as registerSource, bQ as bindScopes, aR as useStore, aH as FileText, aw as Workflow, aK as BookOpen, bc as Sheet, ba as Table, aI as Database, aJ as Calendar, aB as Mail, bb as Image, az as Monitor, b8 as Code, bd as Camera, aC as LayoutGrid, aD as HardDrive, ay as Package, av as Wrench, ax as Users, aE as Globe, aF as FolderKanban, aG as Folder, bl as File$1, aY as Store, bR as getSearchScope, bS as fetchGraphQL, bT as PAGINATED_ASSETS_QUERY, bU as WORKSPACE_MEMBERS_QUERY, bV as SIMPLE_SEARCH_QUERY, bW as assetTypeToIcon, bX as useMentionAuth, b0 as createScopeRegistry, a$ as createItemCache, aO as useEditor, aQ as StarterKit, b3 as Placeholder, aP as EditorContent } from "./use-rest-conversation-history-FoEmnZcH.js";
5
- import { bY, bZ, b_, b$, c0, bh, bg, c1, bi, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn as cn2, co } from "./use-rest-conversation-history-FoEmnZcH.js";
4
+ import { au as createLucideIcon, O as cn, bJ as THREAD_HEADER_ACTIONS_CLASS, bK as THREAD_HEADER_PILL_CLASS, bL as THREAD_HEADER_CLASS, b4 as RefreshCw, bm as Plus, b9 as Search, be as LoaderCircle, bx as conversationDisplayTitle, b7 as Archive, bM as assetTypeToThumb, aA as MessageSquare, ak as Node, a2 as mergeAttributes, aq as Extension, aW as Suggestion, aU as useFloating, aV as FloatingPortal, N as autoUpdate, F as offset, I as flip, G as shift, aS as getFilteredItems, bN as getFetchState, bO as getEntry, bP as updateFetchState, a_ as addItems, aZ as registerSource, bQ as bindScopes, aR as useStore, aH as FileText, aw as Workflow, aK as BookOpen, bc as Sheet, ba as Table, aI as Database, aJ as Calendar, aB as Mail, bb as Image, az as Monitor, b8 as Code, bd as Camera, aC as LayoutGrid, aD as HardDrive, ay as Package, av as Wrench, ax as Users, aE as Globe, aF as FolderKanban, aG as Folder, bl as File$1, aY as Store, bR as getSearchScope, bS as fetchGraphQL, bT as PAGINATED_ASSETS_QUERY, bU as WORKSPACE_MEMBERS_QUERY, bV as SIMPLE_SEARCH_QUERY, bW as assetTypeToIcon, bX as useMentionAuth, b0 as createScopeRegistry, a$ as createItemCache, aO as useEditor, aQ as StarterKit, b3 as Placeholder, aP as EditorContent } from "./use-rest-conversation-history-DpEswBqQ.js";
5
+ import { bY, bZ, b_, b$, c0, bh, bg, c1, bi, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn as cn2, co } from "./use-rest-conversation-history-DpEswBqQ.js";
6
6
  import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
7
7
  import { useMemo, useEffect, useState, useRef, Fragment, useImperativeHandle, forwardRef, useCallback, useId } from "react";
8
8
  import { useAui, unstable_useComposerInput } from "@assistant-ui/react";
package/dist/index.cjs CHANGED
@@ -19,7 +19,7 @@ var __privateWrapper = (obj, member, setter, getter) => ({
19
19
  });
20
20
  var _mutations, _scopes, _mutationId, _a2, _queries, _b, _queryCache, _mutationCache, _defaultOptions, _queryDefaults, _mutationDefaults, _mountCount, _unsubscribeFocus, _unsubscribeOnline, _c;
21
21
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
22
- const useRestConversationHistory = require("./use-rest-conversation-history-CbMCaMzR.cjs");
22
+ const useRestConversationHistory = require("./use-rest-conversation-history-BdnG8jEP.cjs");
23
23
  const React = require("react");
24
24
  const jsxRuntime = require("react/jsx-runtime");
25
25
  const react = require("@assistant-ui/react");
@@ -123,6 +123,39 @@ function isTrustedOrigin({
123
123
  return false;
124
124
  }
125
125
  }
126
+ const BRIDGE_URL_FIELDS = [
127
+ "apiUrl",
128
+ "backendUrl",
129
+ "statewireSyncUrl",
130
+ "backendBaseUrl",
131
+ "appUrl"
132
+ ];
133
+ const EMPTY_BRIDGE_URLS = {
134
+ apiUrl: null,
135
+ backendUrl: null,
136
+ statewireSyncUrl: null,
137
+ backendBaseUrl: null,
138
+ appUrl: null
139
+ };
140
+ function mergeBridgeConfigMessage(previous, payload) {
141
+ const next = {
142
+ apiUrl: previous.apiUrl,
143
+ backendUrl: previous.backendUrl,
144
+ statewireSyncUrl: previous.statewireSyncUrl,
145
+ backendBaseUrl: previous.backendBaseUrl,
146
+ appUrl: previous.appUrl
147
+ };
148
+ for (const field of BRIDGE_URL_FIELDS) {
149
+ const value = payload[field];
150
+ if (typeof value === "string") {
151
+ next[field] = value;
152
+ }
153
+ }
154
+ return next;
155
+ }
156
+ function readAuthMintUrls(data) {
157
+ return mergeBridgeConfigMessage(EMPTY_BRIDGE_URLS, data);
158
+ }
126
159
  const BRIDGE_TIMEOUT_MS = 2e3;
127
160
  const TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1e3;
128
161
  const TOKEN_REFRESH_RETRY_BASE_MS = 60 * 1e3;
@@ -169,9 +202,7 @@ function useParentBridge({
169
202
  }, [trustedOrigins]);
170
203
  const [state, setState] = React.useState({
171
204
  token: null,
172
- apiUrl: null,
173
- backendUrl: null,
174
- appUrl: null,
205
+ ...EMPTY_BRIDGE_URLS,
175
206
  ready: false
176
207
  });
177
208
  const readySignalSent = React.useRef(false);
@@ -196,9 +227,7 @@ function useParentBridge({
196
227
  configReceived.current = true;
197
228
  setState((prev) => ({
198
229
  ...prev,
199
- apiUrl: typeof event.data.apiUrl === "string" ? event.data.apiUrl : prev.apiUrl,
200
- backendUrl: typeof event.data.backendUrl === "string" ? event.data.backendUrl : prev.backendUrl,
201
- appUrl: typeof event.data.appUrl === "string" ? event.data.appUrl : prev.appUrl
230
+ ...mergeBridgeConfigMessage(prev, event.data)
202
231
  // Don't set ready here — wait for athena-auth (token) or the timeout.
203
232
  // Setting ready on config alone causes a race: the thread list fires
204
233
  // before the token arrives, falling back to X-API-KEY.
@@ -348,9 +377,7 @@ function useParentBridge({
348
377
  }
349
378
  setState({
350
379
  token: typeof data.token === "string" ? data.token : null,
351
- apiUrl: typeof data.apiUrl === "string" ? data.apiUrl : null,
352
- backendUrl: typeof data.backendUrl === "string" ? data.backendUrl : null,
353
- appUrl: typeof data.appUrl === "string" ? data.appUrl : null,
380
+ ...readAuthMintUrls(data),
354
381
  ready: true
355
382
  });
356
383
  scheduleRefresh(data.expires_at);
@@ -6214,7 +6241,7 @@ const convertLangChainToThreadMessages = (messages, isRunning = false, metadata
6214
6241
  return convertExternalMessages(filteredMessages, convertLangChainMessage, isRunning, metadata);
6215
6242
  };
6216
6243
  const __vite_import_meta_env__ = { "DEV": false };
6217
- const DEFAULT_MODEL = "claude-opus-4-6-thinking-max-fast";
6244
+ const DEFAULT_MODEL = "claude-opus-4-8-thinking-max-fast";
6218
6245
  const DEFAULT_AGENT = "athena_assist_agent";
6219
6246
  const getIsDev = () => {
6220
6247
  const importMetaEnv = __vite_import_meta_env__;
@@ -11052,6 +11079,14 @@ const useAssetPanelStore = create()(
11052
11079
  slideNumber: meta == null ? void 0 : meta.slideNumber,
11053
11080
  reference: meta == null ? void 0 : meta.reference
11054
11081
  };
11082
+ if ((meta == null ? void 0 : meta.replaceActiveTab) && s.activeTabId) {
11083
+ const activeIndex = s.tabs.findIndex((t) => t.id === s.activeTabId);
11084
+ if (activeIndex >= 0) {
11085
+ const tabs = s.tabs.slice();
11086
+ tabs[activeIndex] = newTab;
11087
+ return { isOpen: true, tabs, activeTabId: assetId };
11088
+ }
11089
+ }
11055
11090
  return { isOpen: true, tabs: [...s.tabs, newTab], activeTabId: assetId };
11056
11091
  }),
11057
11092
  closeTab: (assetId) => set2((s) => {
@@ -12464,7 +12499,7 @@ function AthenaProvider({
12464
12499
  const configuredExtraRunConfig = (config2 == null ? void 0 : config2.extraRunConfig) ?? extraRunConfig;
12465
12500
  const configuredTrustedParentOrigins = config2 == null ? void 0 : config2.trustedParentOrigins;
12466
12501
  const posthogConfig = (config2 == null ? void 0 : config2.posthog) ?? posthogProp;
12467
- const { transport: effectiveTransport, fallbackReason: transportFallbackReason } = resolveAthenaTransport({
12502
+ const { transport: effectiveTransport } = resolveAthenaTransport({
12468
12503
  transport: configuredTransport
12469
12504
  });
12470
12505
  React.useEffect(() => {
@@ -12473,14 +12508,7 @@ function AthenaProvider({
12473
12508
  level: "debug",
12474
12509
  data: { transport: effectiveTransport, thread_list: enableThreadList }
12475
12510
  });
12476
- if (transportFallbackReason) {
12477
- useRestConversationHistory.athenaDiagnostics.emit("sdk.config.warning", {
12478
- level: "warn",
12479
- data: { prop: "transport", reason: transportFallbackReason }
12480
- });
12481
- console.warn(`[AthenaSDK] ${transportFallbackReason}`);
12482
- }
12483
- }, [effectiveTransport, enableThreadList, transportFallbackReason]);
12511
+ }, [effectiveTransport, enableThreadList]);
12484
12512
  React.useEffect(() => {
12485
12513
  if (channel && effectiveTransport !== "statewire") {
12486
12514
  useRestConversationHistory.athenaDiagnostics.emit("sdk.config.warning", {
@@ -12501,6 +12529,8 @@ function AthenaProvider({
12501
12529
  const effectiveToken = configuredToken !== void 0 ? configuredToken : authProviderToken ?? bridge.token;
12502
12530
  const effectiveApiUrl = configuredApiUrl ?? bridge.apiUrl ?? environmentUrls.apiUrl;
12503
12531
  const effectiveBackendUrl = configuredBackendUrl ?? bridge.backendUrl ?? environmentUrls.backendUrl;
12532
+ const hostStatewireSyncUrl = configuredStatewireSyncUrl ?? bridge.statewireSyncUrl ?? void 0;
12533
+ const effectiveBackendBaseUrl = configuredBackendUrl ?? bridge.backendBaseUrl ?? effectiveBackendUrl;
12504
12534
  const effectiveAppUrl = configuredAppUrl ?? bridge.appUrl ?? useRestConversationHistory.deriveAthenaAppUrl({ apiUrl: effectiveApiUrl, backendUrl: effectiveBackendUrl }) ?? environmentUrls.appUrl;
12505
12535
  if (!bridge.ready) {
12506
12536
  return null;
@@ -12508,12 +12538,12 @@ function AthenaProvider({
12508
12538
  let inner;
12509
12539
  if (effectiveTransport === "statewire") {
12510
12540
  const effectiveStatewireSyncUrl = useRestConversationHistory.resolveStatewireSyncUrl({
12511
- statewireSyncUrl: configuredStatewireSyncUrl,
12541
+ statewireSyncUrl: hostStatewireSyncUrl,
12512
12542
  apiUrl: effectiveApiUrl
12513
12543
  });
12514
12544
  const statewireProps = {
12515
12545
  syncUrl: effectiveStatewireSyncUrl,
12516
- backendUrl: effectiveBackendUrl,
12546
+ backendUrl: effectiveBackendBaseUrl,
12517
12547
  appUrl: effectiveAppUrl,
12518
12548
  apiKey: configuredApiKey,
12519
12549
  token: effectiveToken,
@@ -24674,7 +24704,11 @@ const useAthenaLinkClickHandler = () => {
24674
24704
  type: citationLink.assetType ?? void 0,
24675
24705
  // Carry the citation target so the panel's iframe navigates to
24676
24706
  // the cited range/page instead of opening at the top.
24677
- reference: citationLink.reference
24707
+ reference: citationLink.reference,
24708
+ // Reading references is one preview surface: a citation to a
24709
+ // different asset swaps the active tab rather than stacking a
24710
+ // tab per cited document.
24711
+ replaceActiveTab: true
24678
24712
  });
24679
24713
  } : void 0;
24680
24714
  const context = {
@@ -31966,6 +32000,7 @@ const AthenaChat = ({
31966
32000
  welcomeMessage = "Hello there!",
31967
32001
  welcomeSubtext = "What can I help you with?",
31968
32002
  maxWidth = "44rem",
32003
+ turnAnchor = "bottom",
31969
32004
  toolUIs,
31970
32005
  mentionTools,
31971
32006
  welcomeSuggestions = DEFAULT_SUGGESTIONS,
@@ -32031,7 +32066,7 @@ const AthenaChat = ({
32031
32066
  className
32032
32067
  ),
32033
32068
  maxWidth,
32034
- turnAnchor: "top",
32069
+ turnAnchor,
32035
32070
  viewportClassName: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth px-4 pt-4",
32036
32071
  contentClassName: "flex w-full flex-1 flex-col",
32037
32072
  viewportOverlay: /* @__PURE__ */ jsxRuntime.jsx(ThreadScrollToTop, {}),
@@ -33049,17 +33084,21 @@ const AssetIframe = React.memo(
33049
33084
  };
33050
33085
  }
33051
33086
  const initialSlideNumber = initialSlideRef.current.slideNumber;
33052
- const iframeSrc = React.useMemo(
33053
- () => embedUrl ? buildSdkAssetEmbedUrl(
33054
- buildAssetIframeSrc({
33055
- embedUrl,
33056
- assetType: tab.type,
33057
- slideNumber: initialSlideNumber
33058
- }),
33059
- tab.reference
33060
- ) : null,
33061
- [embedUrl, initialSlideNumber, tab.type, tab.reference]
33062
- );
33087
+ const iframeSrc = React.useMemo(() => {
33088
+ if (!embedUrl) return null;
33089
+ const base2 = buildAssetIframeSrc({
33090
+ embedUrl,
33091
+ assetType: tab.type,
33092
+ slideNumber: initialSlideNumber
33093
+ });
33094
+ try {
33095
+ const url = new URL(base2, window.location.href);
33096
+ appendCitationReferenceParams({ params: url.searchParams, reference: tab.reference });
33097
+ return url.toString();
33098
+ } catch {
33099
+ return base2;
33100
+ }
33101
+ }, [embedUrl, initialSlideNumber, tab.type, tab.reference]);
33063
33102
  const navigationMessage = React.useMemo(
33064
33103
  () => buildPresentationNavigationMessage({
33065
33104
  assetId: tab.id,