@athenaintel/react 0.9.7 → 0.9.9

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/dist/index.d.ts CHANGED
@@ -49,6 +49,29 @@ export declare interface AssetPanelState {
49
49
  markAutoOpened: (assetId: string) => boolean;
50
50
  }
51
51
 
52
+ /**
53
+ * Render an Athena asset anywhere inside AthenaProvider.
54
+ *
55
+ * This component only needs `assetId`. The embed token endpoint resolves the
56
+ * correct viewer from that ID, so callers do not need to pass an asset type.
57
+ */
58
+ export declare const AssetRenderer: FC<AssetRendererProps>;
59
+
60
+ export declare interface AssetRendererProps extends UseAssetEmbedOptions {
61
+ /** Athena asset ID to render. */
62
+ assetId: string | null;
63
+ /** Accessible iframe title. */
64
+ title?: string | null;
65
+ /** Applied to the iframe or fallback container. */
66
+ className?: string;
67
+ /** Optional loading UI override. */
68
+ loadingFallback?: ReactNode;
69
+ /** Optional empty state override when assetId is missing. */
70
+ emptyFallback?: ReactNode;
71
+ /** Optional error UI override. */
72
+ errorFallback?: ReactNode | ((error: string) => ReactNode);
73
+ }
74
+
52
75
  export declare interface AssetTab {
53
76
  id: string;
54
77
  name: string | null;
@@ -72,7 +95,9 @@ export declare interface AthenaChatProps {
72
95
  toolUIs?: Record<string, ToolCallMessagePartComponent>;
73
96
  /** Mention tools available in the composer. */
74
97
  mentionTools?: MentionTool[];
75
- /** Suggestion cards shown on the welcome screen. Pass `[]` to hide. */
98
+ /** Suggestion cards shown on the welcome screen. Pass `[]` to hide.
99
+ * For workflow launchers outside AthenaChat, use `useSendMessage()`.
100
+ */
76
101
  welcomeSuggestions?: WelcomeSuggestion[];
77
102
  }
78
103
 
@@ -212,7 +237,7 @@ export declare interface AthenaRuntimeConfig {
212
237
  export declare interface AthenaTheme {
213
238
  /** Brand / accent color. Send button, active states, focus ring, spinner. */
214
239
  primary?: string;
215
- /** Text color on primary background. */
240
+ /** Text color on primary background. If omitted, the SDK tries to derive a readable black/white fallback for solid colors. */
216
241
  primaryForeground?: string;
217
242
  /** Page / panel background. */
218
243
  background?: string;
@@ -258,11 +283,11 @@ export declare interface AthenaTheme {
258
283
  sidebarWidth?: string;
259
284
  /** User message bubble background. Falls back to muted. */
260
285
  userBubble?: string;
261
- /** User message bubble text color. Falls back to foreground. */
286
+ /** User message bubble text color. If omitted, the SDK tries to derive a readable black/white fallback for solid colors. */
262
287
  userBubbleForeground?: string;
263
288
  /** User message bubble border radius. e.g. '1rem', '0.5rem'. */
264
289
  userBubbleRadius?: string;
265
- /** Assistant message text color. Falls back to foreground. */
290
+ /** Assistant message text color. If omitted, the SDK tries to derive a readable black/white fallback for solid colors. */
266
291
  assistantForeground?: string;
267
292
  /** Assistant message bubble background. Transparent by default. */
268
293
  assistantBubble?: string;
@@ -428,7 +453,7 @@ export declare interface ParentBridgeState {
428
453
  token: string | null;
429
454
  /** Sync server chat URL provided by the Marathon wrapper. */
430
455
  apiUrl: string | null;
431
- /** Agora backend URL provided by the Marathon wrapper. */
456
+ /** Athena backend URL provided by the Marathon wrapper. */
432
457
  backendUrl: string | null;
433
458
  /** Athena frontend origin provided by the parent wrapper. */
434
459
  appUrl: string | null;
@@ -470,6 +495,14 @@ declare interface ScopeRegistryEntry {
470
495
  fetchStates: Map<string, FetchState>;
471
496
  }
472
497
 
498
+ export declare interface SendMessageOptions {
499
+ /**
500
+ * Replace the current composer text before sending.
501
+ * Defaults to `true`.
502
+ */
503
+ replace?: boolean;
504
+ }
505
+
473
506
  declare interface SourceContext {
474
507
  scope: MenuScope;
475
508
  query: string;
@@ -831,7 +864,10 @@ export declare interface UploadProgress {
831
864
  }
832
865
 
833
866
  /**
834
- * Hook to programmatically append text to the composer.
867
+ * Hook to programmatically append text to the composer without sending it.
868
+ *
869
+ * Use `useSendMessage()` for workflow shortcuts or other UI that should
870
+ * immediately submit a prompt.
835
871
  *
836
872
  * Usage:
837
873
  * const append = useAppendToComposer();
@@ -938,6 +974,21 @@ export declare function useQuote(): QuoteContextValue;
938
974
  /** Trigger a re-fetch of the thread list. No-op outside of thread list mode. */
939
975
  export declare function useRefreshThreadList(): (() => void) | null;
940
976
 
977
+ /**
978
+ * Hook to programmatically send a user message from anywhere inside AthenaProvider.
979
+ *
980
+ * This is intended for custom workflow buttons, sidebar shortcuts, or other UI
981
+ * that lives outside the AthenaChat thread tree. Unlike `aui.thread().append()`,
982
+ * this uses the provider-scoped composer runtime and does not depend on
983
+ * ThreadPrimitive context.
984
+ *
985
+ * Usage:
986
+ * const sendMessage = useSendMessage();
987
+ * await sendMessage("Run the quarterly workflow");
988
+ * await sendMessage("Add this follow-up", { replace: false });
989
+ */
990
+ export declare function useSendMessage(): (text: string, options?: SendMessageOptions) => Promise<void>;
991
+
941
992
  export declare type ViewMode = 'tabs' | 'tiled';
942
993
 
943
994
  export declare const WebSearchToolUI: ToolCallMessagePartComponent;
package/dist/index.js CHANGED
@@ -11916,7 +11916,7 @@ const oppositeSideMap = {
11916
11916
  bottom: "top",
11917
11917
  top: "bottom"
11918
11918
  };
11919
- function clamp(start, value, end) {
11919
+ function clamp$1(start, value, end) {
11920
11920
  return max(start, min(value, end));
11921
11921
  }
11922
11922
  function evaluate(value, param) {
@@ -12273,7 +12273,7 @@ const arrow$4 = (options) => ({
12273
12273
  const min$1 = minPadding;
12274
12274
  const max2 = clientSize - arrowDimensions[length] - maxPadding;
12275
12275
  const center = clientSize / 2 - arrowDimensions[length] / 2 + centerToReference;
12276
- const offset2 = clamp(min$1, center, max2);
12276
+ const offset2 = clamp$1(min$1, center, max2);
12277
12277
  const shouldAddOffset = !middlewareData.arrow && getAlignment(placement) != null && center !== offset2 && rects.reference[length] / 2 - (center < min$1 ? minPadding : maxPadding) - arrowDimensions[length] / 2 < 0;
12278
12278
  const alignmentOffset = shouldAddOffset ? center < min$1 ? center - min$1 : center - max2 : 0;
12279
12279
  return {
@@ -12572,14 +12572,14 @@ const shift$3 = function(options) {
12572
12572
  const maxSide = mainAxis === "y" ? "bottom" : "right";
12573
12573
  const min2 = mainAxisCoord + overflow[minSide];
12574
12574
  const max2 = mainAxisCoord - overflow[maxSide];
12575
- mainAxisCoord = clamp(min2, mainAxisCoord, max2);
12575
+ mainAxisCoord = clamp$1(min2, mainAxisCoord, max2);
12576
12576
  }
12577
12577
  if (checkCrossAxis) {
12578
12578
  const minSide = crossAxis === "y" ? "top" : "left";
12579
12579
  const maxSide = crossAxis === "y" ? "bottom" : "right";
12580
12580
  const min2 = crossAxisCoord + overflow[minSide];
12581
12581
  const max2 = crossAxisCoord - overflow[maxSide];
12582
- crossAxisCoord = clamp(min2, crossAxisCoord, max2);
12582
+ crossAxisCoord = clamp$1(min2, crossAxisCoord, max2);
12583
12583
  }
12584
12584
  const limitedCoords = limiter.fn({
12585
12585
  ...state,
@@ -16473,8 +16473,16 @@ const DEFAULT_ATHENA_ENVIRONMENT = "production";
16473
16473
  const DEFAULT_API_URL = ATHENA_ENVIRONMENT_URLS.production.apiUrl;
16474
16474
  const DEFAULT_BACKEND_URL = ATHENA_ENVIRONMENT_URLS.production.backendUrl;
16475
16475
  const DEFAULT_APP_URL = ATHENA_ENVIRONMENT_URLS.production.appUrl;
16476
- const SPACES_PATHNAME = "/dashboard/spaces/";
16476
+ const MARATHON_APP_PORT = "8082";
16477
+ const SPACES_PATHNAME = "dashboard/spaces/";
16477
16478
  const normalizeBaseUrl = (url) => url.replace(/\/+$/, "");
16479
+ const createUrlWithFallback = (url, fallbackUrl) => {
16480
+ try {
16481
+ return new URL(`${normalizeBaseUrl(url)}/`);
16482
+ } catch {
16483
+ return new URL(`${normalizeBaseUrl(fallbackUrl)}/`);
16484
+ }
16485
+ };
16478
16486
  const getHostname = (value) => {
16479
16487
  if (!value) return null;
16480
16488
  try {
@@ -16496,7 +16504,7 @@ const deriveWorkspaceAppUrl = ({
16496
16504
  if (!((_a2 = match2 == null ? void 0 : match2.groups) == null ? void 0 : _a2.prefix) || !match2.groups.domain) {
16497
16505
  return null;
16498
16506
  }
16499
- return `${parsedUrl.protocol}//${match2.groups.prefix}--8082.${match2.groups.domain}`;
16507
+ return `${parsedUrl.protocol}//${match2.groups.prefix}--${MARATHON_APP_PORT}.${match2.groups.domain}`;
16500
16508
  } catch {
16501
16509
  return null;
16502
16510
  }
@@ -16545,7 +16553,7 @@ function createAthenaSpacesUrl({
16545
16553
  assetIds,
16546
16554
  sessionId
16547
16555
  }) {
16548
- const url = new URL(SPACES_PATHNAME, `${normalizeBaseUrl(appUrl)}/`);
16556
+ const url = new URL(SPACES_PATHNAME, createUrlWithFallback(appUrl, DEFAULT_APP_URL));
16549
16557
  if (assetIds) {
16550
16558
  const normalizedAssetIds = (Array.isArray(assetIds) ? assetIds : [assetIds]).map((assetId) => assetId.trim()).filter((assetId) => assetId.length > 0);
16551
16559
  if (normalizedAssetIds.length > 0) {
@@ -20607,7 +20615,9 @@ const toolMessageSchema = objectType({
20607
20615
  type: literalType("tool"),
20608
20616
  content: toolMessageContentSchema,
20609
20617
  tool_call_id: stringType(),
20610
- name: stringType().nullable(),
20618
+ // Some backend/tool result flows omit the tool name entirely.
20619
+ // The converter already treats toolName as optional, so accept that shape.
20620
+ name: nullableToOptionalString,
20611
20621
  artifact: anyType().optional(),
20612
20622
  status: enumType(["success", "error"]),
20613
20623
  additional_kwargs: recordType(stringType(), unknownType()).optional()
@@ -20774,7 +20784,9 @@ async function listThreads(backendUrl, auth, opts = {}) {
20774
20784
  body: JSON.stringify({
20775
20785
  limit: opts.limit ?? 50,
20776
20786
  offset: opts.offset ?? 0,
20777
- exclude_triggered: opts.exclude_triggered ?? true
20787
+ // Default to the full recent-conversations set unless a caller
20788
+ // explicitly asks to hide triggered/background sessions.
20789
+ exclude_triggered: opts.exclude_triggered ?? false
20778
20790
  })
20779
20791
  });
20780
20792
  if (!res.ok) {
@@ -24448,6 +24460,163 @@ const ThreadListRefreshContext = createContext(null);
24448
24460
  function useRefreshThreadList() {
24449
24461
  return useContext(ThreadListRefreshContext);
24450
24462
  }
24463
+ const WHITE = "#ffffff";
24464
+ const BLACK = "#000000";
24465
+ const CONTRAST_PAIRS = {
24466
+ primary: "primaryForeground",
24467
+ secondary: "secondaryForeground",
24468
+ accent: "accentForeground",
24469
+ card: "cardForeground",
24470
+ popover: "popoverForeground",
24471
+ userBubble: "userBubbleForeground",
24472
+ assistantBubble: "assistantForeground"
24473
+ };
24474
+ const clamp = (value, min2 = 0, max2 = 1) => Math.min(max2, Math.max(min2, value));
24475
+ const parseNumber = (raw) => {
24476
+ const value = Number.parseFloat(raw);
24477
+ return Number.isFinite(value) ? value : null;
24478
+ };
24479
+ const parsePercentLike = (raw, max2 = 1) => {
24480
+ const value = parseNumber(raw);
24481
+ if (value == null) return null;
24482
+ return raw.trim().endsWith("%") ? value / 100 * max2 : value;
24483
+ };
24484
+ const parseHexColor = (input) => {
24485
+ const hex = input.slice(1).trim();
24486
+ if (![3, 4, 6, 8].includes(hex.length)) return null;
24487
+ const expanded = hex.length <= 4 ? hex.split("").map((char) => `${char}${char}`).join("") : hex;
24488
+ const channels = expanded.match(/.{2}/g);
24489
+ if (!channels) return null;
24490
+ const [r2, g, b, alpha2 = 255] = channels.map(
24491
+ (channel) => Number.parseInt(channel, 16)
24492
+ );
24493
+ return {
24494
+ r: clamp(r2 / 255),
24495
+ g: clamp(g / 255),
24496
+ b: clamp(b / 255),
24497
+ alpha: clamp(alpha2 / 255)
24498
+ };
24499
+ };
24500
+ const splitColorArgs = (input) => input.replace(/^[^(]+\(/, "").replace(/\)$/, "").replace(/\//g, " ").replace(/,/g, " ").trim().split(/\s+/).filter(Boolean);
24501
+ const parseRgbColor = (input) => {
24502
+ const parts = splitColorArgs(input);
24503
+ if (parts.length < 3) return null;
24504
+ const r2 = parsePercentLike(parts[0], 255);
24505
+ const g = parsePercentLike(parts[1], 255);
24506
+ const b = parsePercentLike(parts[2], 255);
24507
+ const alpha2 = parts[3] ? parsePercentLike(parts[3], 1) : 1;
24508
+ if ([r2, g, b, alpha2].some((value) => value == null)) return null;
24509
+ return {
24510
+ r: clamp(r2 / 255),
24511
+ g: clamp(g / 255),
24512
+ b: clamp(b / 255),
24513
+ alpha: clamp(alpha2)
24514
+ };
24515
+ };
24516
+ const hueToRgb = (p, q, t) => {
24517
+ let value = t;
24518
+ if (value < 0) value += 1;
24519
+ if (value > 1) value -= 1;
24520
+ if (value < 1 / 6) return p + (q - p) * 6 * value;
24521
+ if (value < 1 / 2) return q;
24522
+ if (value < 2 / 3) return p + (q - p) * (2 / 3 - value) * 6;
24523
+ return p;
24524
+ };
24525
+ const parseHslColor = (input) => {
24526
+ const parts = splitColorArgs(input);
24527
+ if (parts.length < 3) return null;
24528
+ const hue = parseNumber(parts[0]);
24529
+ const saturation = parsePercentLike(parts[1], 1);
24530
+ const lightness = parsePercentLike(parts[2], 1);
24531
+ const alpha2 = parts[3] ? parsePercentLike(parts[3], 1) : 1;
24532
+ if ([hue, saturation, lightness, alpha2].some((value) => value == null)) {
24533
+ return null;
24534
+ }
24535
+ const h2 = (hue % 360 + 360) % 360 / 360;
24536
+ const s = clamp(saturation);
24537
+ const l = clamp(lightness);
24538
+ if (s === 0) {
24539
+ return { r: l, g: l, b: l, alpha: clamp(alpha2) };
24540
+ }
24541
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
24542
+ const p = 2 * l - q;
24543
+ return {
24544
+ r: clamp(hueToRgb(p, q, h2 + 1 / 3)),
24545
+ g: clamp(hueToRgb(p, q, h2)),
24546
+ b: clamp(hueToRgb(p, q, h2 - 1 / 3)),
24547
+ alpha: clamp(alpha2)
24548
+ };
24549
+ };
24550
+ const parseOklchColor = (input) => {
24551
+ const parts = splitColorArgs(input);
24552
+ if (parts.length < 3) return null;
24553
+ const lightness = parsePercentLike(parts[0], 1);
24554
+ const chroma = parseNumber(parts[1]);
24555
+ const hue = parseNumber(parts[2]);
24556
+ const alpha2 = parts[3] ? parsePercentLike(parts[3], 1) : 1;
24557
+ if ([lightness, chroma, hue, alpha2].some((value) => value == null)) {
24558
+ return null;
24559
+ }
24560
+ const l = clamp(lightness);
24561
+ const c = Math.max(0, chroma);
24562
+ const h2 = hue * Math.PI / 180;
24563
+ const a = c * Math.cos(h2);
24564
+ const b = c * Math.sin(h2);
24565
+ const lPrime = l + 0.3963377774 * a + 0.2158037573 * b;
24566
+ const mPrime = l - 0.1055613458 * a - 0.0638541728 * b;
24567
+ const sPrime = l - 0.0894841775 * a - 1.291485548 * b;
24568
+ const lLinear = lPrime ** 3;
24569
+ const mLinear = mPrime ** 3;
24570
+ const sLinear = sPrime ** 3;
24571
+ return {
24572
+ r: clamp(
24573
+ 4.0767416621 * lLinear - 3.3077115913 * mLinear + 0.2309699292 * sLinear
24574
+ ),
24575
+ g: clamp(
24576
+ -1.2684380046 * lLinear + 2.6097574011 * mLinear - 0.3413193965 * sLinear
24577
+ ),
24578
+ b: clamp(
24579
+ -0.0041960863 * lLinear - 0.7034186147 * mLinear + 1.707614701 * sLinear
24580
+ ),
24581
+ alpha: clamp(alpha2)
24582
+ };
24583
+ };
24584
+ const parseColor = (input) => {
24585
+ const value = input.trim().toLowerCase();
24586
+ if (value.startsWith("#")) return parseHexColor(value);
24587
+ if (value.startsWith("rgb")) return parseRgbColor(value);
24588
+ if (value.startsWith("hsl")) return parseHslColor(value);
24589
+ if (value.startsWith("oklch")) return parseOklchColor(value);
24590
+ return null;
24591
+ };
24592
+ const srgbToLinear = (value) => value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;
24593
+ const relativeLuminance = (color) => 0.2126 * srgbToLinear(color.r) + 0.7152 * srgbToLinear(color.g) + 0.0722 * srgbToLinear(color.b);
24594
+ const contrastRatio = (luminanceA, luminanceB) => {
24595
+ const lighter = Math.max(luminanceA, luminanceB);
24596
+ const darker = Math.min(luminanceA, luminanceB);
24597
+ return (lighter + 0.05) / (darker + 0.05);
24598
+ };
24599
+ const getReadableForeground = (background) => {
24600
+ const parsed = parseColor(background);
24601
+ if (!parsed || parsed.alpha < 1) return null;
24602
+ const backgroundLuminance = relativeLuminance(parsed);
24603
+ const whiteContrast = contrastRatio(backgroundLuminance, 1);
24604
+ const blackContrast = contrastRatio(backgroundLuminance, 0);
24605
+ return whiteContrast > blackContrast ? WHITE : BLACK;
24606
+ };
24607
+ const withAutoContrastTheme = (theme) => {
24608
+ const resolvedTheme = { ...theme };
24609
+ for (const backgroundKey of Object.keys(CONTRAST_PAIRS)) {
24610
+ const foregroundKey = CONTRAST_PAIRS[backgroundKey];
24611
+ const backgroundValue = theme[backgroundKey];
24612
+ if (theme[foregroundKey] || !backgroundValue) continue;
24613
+ const derivedForeground = getReadableForeground(backgroundValue);
24614
+ if (derivedForeground) {
24615
+ resolvedTheme[foregroundKey] = derivedForeground;
24616
+ }
24617
+ }
24618
+ return resolvedTheme;
24619
+ };
24451
24620
  const THEME_TO_CSS = {
24452
24621
  primary: "--primary",
24453
24622
  primaryForeground: "--primary-foreground",
@@ -24484,7 +24653,8 @@ const THEME_TO_CSS = {
24484
24653
  };
24485
24654
  function themeToStyleVars(theme) {
24486
24655
  const vars = {};
24487
- for (const [key, value] of Object.entries(theme)) {
24656
+ const resolvedTheme = withAutoContrastTheme(theme);
24657
+ for (const [key, value] of Object.entries(resolvedTheme)) {
24488
24658
  if (value != null && THEME_TO_CSS[key]) {
24489
24659
  vars[THEME_TO_CSS[key]] = value;
24490
24660
  }
@@ -24805,9 +24975,9 @@ function AthenaProvider({
24805
24975
  const configuredAppUrl = (config2 == null ? void 0 : config2.appUrl) ?? appUrl;
24806
24976
  const bridge = useParentBridge();
24807
24977
  const effectiveToken = configuredToken !== void 0 ? configuredToken : bridge.token;
24808
- const effectiveApiUrl = configuredApiUrl ?? bridge.apiUrl ?? environmentUrls.apiUrl ?? DEFAULT_API_URL;
24809
- const effectiveBackendUrl = configuredBackendUrl ?? bridge.backendUrl ?? environmentUrls.backendUrl ?? DEFAULT_BACKEND_URL;
24810
- const effectiveAppUrl = configuredAppUrl ?? bridge.appUrl ?? deriveAthenaAppUrl({ apiUrl: effectiveApiUrl, backendUrl: effectiveBackendUrl }) ?? environmentUrls.appUrl ?? DEFAULT_APP_URL;
24978
+ const effectiveApiUrl = configuredApiUrl ?? bridge.apiUrl ?? environmentUrls.apiUrl;
24979
+ const effectiveBackendUrl = configuredBackendUrl ?? bridge.backendUrl ?? environmentUrls.backendUrl;
24980
+ const effectiveAppUrl = configuredAppUrl ?? bridge.appUrl ?? deriveAthenaAppUrl({ apiUrl: effectiveApiUrl, backendUrl: effectiveBackendUrl }) ?? environmentUrls.appUrl;
24811
24981
  if (!bridge.ready) {
24812
24982
  return null;
24813
24983
  }
@@ -60768,7 +60938,7 @@ const TiptapComposer = ({ tools = [] }) => {
60768
60938
  composerRuntime.send();
60769
60939
  }
60770
60940
  editor2.commands.clearContent();
60771
- }, [aui, composerRuntime, clearAttachments, clearQuote]);
60941
+ }, [aui, composerRuntime, clearAttachments, clearQuote, appUrl]);
60772
60942
  const handleSubmitRef = useRef(handleSubmit);
60773
60943
  handleSubmitRef.current = handleSubmit;
60774
60944
  const editor = useEditor({
@@ -63940,6 +64110,23 @@ const ComposerDropZone = ({
63940
64110
  }
63941
64111
  );
63942
64112
  };
64113
+ function useSendMessage() {
64114
+ const aui = useAui();
64115
+ return useCallback(
64116
+ async (text2, options) => {
64117
+ if (!text2.trim()) return;
64118
+ const composer = aui.composer();
64119
+ const currentText = composer.getState().text;
64120
+ const shouldReplace = (options == null ? void 0 : options.replace) ?? true;
64121
+ composer.setText(
64122
+ shouldReplace || !currentText ? text2 : `${currentText}
64123
+ ${text2}`
64124
+ );
64125
+ await composer.send();
64126
+ },
64127
+ [aui]
64128
+ );
64129
+ }
63943
64130
  const EMPTY_MENTION_TOOLS = [];
63944
64131
  function QuotePostMessageBridge() {
63945
64132
  useQuoteFromPostMessage();
@@ -63971,14 +64158,11 @@ const SuggestionCard = ({
63971
64158
  suggestion,
63972
64159
  index: index2
63973
64160
  }) => {
63974
- const aui = useAui();
63975
64161
  const Icon2 = suggestion.icon;
64162
+ const sendMessage = useSendMessage();
63976
64163
  const handleClick2 = useCallback(() => {
63977
- aui.thread().append({
63978
- role: "user",
63979
- content: [{ type: "text", text: suggestion.prompt }]
63980
- });
63981
- }, [aui, suggestion.prompt]);
64164
+ void sendMessage(suggestion.prompt);
64165
+ }, [sendMessage, suggestion.prompt]);
63982
64166
  return /* @__PURE__ */ jsxs(
63983
64167
  "button",
63984
64168
  {
@@ -64125,7 +64309,7 @@ const ComposerSendWithQuote = () => {
64125
64309
  editor == null ? void 0 : editor.clear();
64126
64310
  clearQuote();
64127
64311
  clearAttachments();
64128
- }, [aui, quote, attachments, isUploading, clearQuote, clearAttachments, editorRef]);
64312
+ }, [aui, quote, attachments, isUploading, clearQuote, clearAttachments, editorRef, appUrl]);
64129
64313
  if (hasExtras) {
64130
64314
  return /* @__PURE__ */ jsx(
64131
64315
  TooltipIconButton,
@@ -64319,6 +64503,75 @@ function useAssetEmbed(assetId, options = {
64319
64503
  }, [assetId, readOnly, expiresInSeconds, backendUrl, apiKey, token]);
64320
64504
  return { embedUrl, isLoading, error: error2 };
64321
64505
  }
64506
+ const AssetRenderer = ({
64507
+ assetId,
64508
+ title,
64509
+ className,
64510
+ loadingFallback,
64511
+ emptyFallback = null,
64512
+ errorFallback,
64513
+ readOnly,
64514
+ expiresInSeconds
64515
+ }) => {
64516
+ const { backendUrl, apiKey, token } = useAthenaConfig();
64517
+ const { embedUrl, isLoading, error: error2 } = useAssetEmbed(assetId, {
64518
+ backendUrl,
64519
+ apiKey,
64520
+ token,
64521
+ readOnly,
64522
+ expiresInSeconds
64523
+ });
64524
+ if (!assetId) {
64525
+ return emptyFallback ? /* @__PURE__ */ jsx("div", { className: cn("h-full w-full", className), children: emptyFallback }) : null;
64526
+ }
64527
+ if (isLoading) {
64528
+ return /* @__PURE__ */ jsx(
64529
+ "div",
64530
+ {
64531
+ className: cn(
64532
+ "flex h-full w-full items-center justify-center",
64533
+ className
64534
+ ),
64535
+ children: loadingFallback ?? /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
64536
+ /* @__PURE__ */ jsx(LoaderCircle, { className: "mx-auto size-6 animate-spin text-muted-foreground" }),
64537
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: "Loading..." })
64538
+ ] })
64539
+ }
64540
+ );
64541
+ }
64542
+ if (error2) {
64543
+ const resolvedErrorFallback = typeof errorFallback === "function" ? errorFallback(error2) : errorFallback;
64544
+ return /* @__PURE__ */ jsx(
64545
+ "div",
64546
+ {
64547
+ className: cn(
64548
+ "flex h-full w-full items-center justify-center p-4",
64549
+ className
64550
+ ),
64551
+ children: resolvedErrorFallback ?? /* @__PURE__ */ jsxs("div", { className: "max-w-sm text-center", children: [
64552
+ /* @__PURE__ */ jsx(CircleAlert, { className: "mx-auto size-5 text-red-400" }),
64553
+ /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-xs font-medium text-foreground", children: "Failed to load" }),
64554
+ /* @__PURE__ */ jsx("p", { className: "mt-0.5 line-clamp-2 break-words text-[10px] text-muted-foreground", children: error2 })
64555
+ ] })
64556
+ }
64557
+ );
64558
+ }
64559
+ if (!embedUrl) {
64560
+ return emptyFallback ? /* @__PURE__ */ jsx("div", { className: cn("h-full w-full", className), children: emptyFallback }) : null;
64561
+ }
64562
+ return /* @__PURE__ */ jsx(
64563
+ "iframe",
64564
+ {
64565
+ src: embedUrl,
64566
+ width: "100%",
64567
+ height: "100%",
64568
+ frameBorder: "0",
64569
+ allow: "fullscreen",
64570
+ title: title ?? `Asset ${assetId}`,
64571
+ className: cn("h-full w-full", className)
64572
+ }
64573
+ );
64574
+ };
64322
64575
  const ASSET_TYPE_CONFIG = {
64323
64576
  presentation: { icon: Presentation, label: "Presentation" },
64324
64577
  spreadsheet: { icon: FileSpreadsheet, label: "Spreadsheet" },
@@ -64328,38 +64581,7 @@ const ASSET_TYPE_CONFIG = {
64328
64581
  };
64329
64582
  const AssetIframe = memo(
64330
64583
  ({ tabId, tabName }) => {
64331
- const { backendUrl, apiKey, token } = useAthenaConfig();
64332
- const { embedUrl, isLoading, error: error2 } = useAssetEmbed(tabId, {
64333
- backendUrl,
64334
- apiKey,
64335
- token
64336
- });
64337
- if (isLoading) {
64338
- return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
64339
- /* @__PURE__ */ jsx(LoaderCircle, { className: "mx-auto size-6 animate-spin text-muted-foreground" }),
64340
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: "Loading..." })
64341
- ] }) });
64342
- }
64343
- if (error2) {
64344
- return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center p-4", children: /* @__PURE__ */ jsxs("div", { className: "max-w-sm text-center", children: [
64345
- /* @__PURE__ */ jsx(CircleAlert, { className: "mx-auto size-5 text-red-400" }),
64346
- /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-xs font-medium text-foreground", children: "Failed to load" }),
64347
- /* @__PURE__ */ jsx("p", { className: "mt-0.5 line-clamp-2 break-words text-[10px] text-muted-foreground", children: error2 })
64348
- ] }) });
64349
- }
64350
- if (!embedUrl) return null;
64351
- return /* @__PURE__ */ jsx(
64352
- "iframe",
64353
- {
64354
- src: embedUrl,
64355
- width: "100%",
64356
- height: "100%",
64357
- frameBorder: "0",
64358
- allow: "fullscreen",
64359
- title: tabName ?? `Asset ${tabId}`,
64360
- className: "h-full w-full"
64361
- }
64362
- );
64584
+ return /* @__PURE__ */ jsx(AssetRenderer, { assetId: tabId, title: tabName });
64363
64585
  }
64364
64586
  );
64365
64587
  AssetIframe.displayName = "AssetIframe";
@@ -64701,6 +64923,7 @@ const Toolkits = {
64701
64923
  export {
64702
64924
  AppendDocumentToolUI,
64703
64925
  AssetPanel,
64926
+ AssetRenderer,
64704
64927
  AthenaChat,
64705
64928
  AthenaLayout,
64706
64929
  AthenaProvider,
@@ -64767,6 +64990,7 @@ export {
64767
64990
  useParentAuth,
64768
64991
  useParentBridge,
64769
64992
  useQuote,
64770
- useRefreshThreadList
64993
+ useRefreshThreadList,
64994
+ useSendMessage
64771
64995
  };
64772
64996
  //# sourceMappingURL=index.js.map