@athenaintel/react 0.10.26 → 0.10.27

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
@@ -65,6 +65,7 @@ export declare interface AssetPanelState {
65
65
  openAsset: (assetId: string, meta?: {
66
66
  name?: string;
67
67
  type?: AssetType;
68
+ slideNumber?: number;
68
69
  }) => void;
69
70
  closeTab: (assetId: string) => void;
70
71
  setActiveTab: (assetId: string) => void;
@@ -86,6 +87,7 @@ export declare interface AssetTab {
86
87
  id: string;
87
88
  name: string | null;
88
89
  type: AssetType;
90
+ slideNumber?: number;
89
91
  }
90
92
 
91
93
  export declare type AssetType = 'presentation' | 'spreadsheet' | 'document' | 'notebook' | 'unknown';
package/dist/index.js CHANGED
@@ -14112,14 +14112,20 @@ const useAssetPanelStore = create()(
14112
14112
  const existing = s.tabs.find((t) => t.id === assetId);
14113
14113
  if (existing) {
14114
14114
  const tabs = meta ? s.tabs.map(
14115
- (t) => t.id === assetId ? { ...t, name: meta.name ?? t.name, type: meta.type ?? t.type } : t
14115
+ (t) => t.id === assetId ? {
14116
+ ...t,
14117
+ name: meta.name ?? t.name,
14118
+ type: meta.type ?? t.type,
14119
+ slideNumber: meta.slideNumber ?? t.slideNumber
14120
+ } : t
14116
14121
  ) : s.tabs;
14117
14122
  return { isOpen: true, tabs, activeTabId: assetId };
14118
14123
  }
14119
14124
  const newTab = {
14120
14125
  id: assetId,
14121
14126
  name: (meta == null ? void 0 : meta.name) ?? null,
14122
- type: (meta == null ? void 0 : meta.type) ?? "unknown"
14127
+ type: (meta == null ? void 0 : meta.type) ?? "unknown",
14128
+ slideNumber: meta == null ? void 0 : meta.slideNumber
14123
14129
  };
14124
14130
  return { isOpen: true, tabs: [...s.tabs, newTab], activeTabId: assetId };
14125
14131
  }),
@@ -50864,6 +50870,68 @@ function extractAssetId(result) {
50864
50870
  function resetAssetAutoOpen() {
50865
50871
  useAssetPanelStore.getState().resetAutoOpen();
50866
50872
  }
50873
+ function getStringField(source, keys2) {
50874
+ if (!source) return null;
50875
+ for (const key of keys2) {
50876
+ const value = source[key];
50877
+ if (typeof value === "string" && value.trim()) {
50878
+ return value;
50879
+ }
50880
+ }
50881
+ return null;
50882
+ }
50883
+ function getNumberField(source, keys2) {
50884
+ if (!source) return null;
50885
+ for (const key of keys2) {
50886
+ const value = source[key];
50887
+ if (typeof value === "number" && Number.isFinite(value)) {
50888
+ return value;
50889
+ }
50890
+ }
50891
+ return null;
50892
+ }
50893
+ function getStudioAssetId({
50894
+ args,
50895
+ result
50896
+ }) {
50897
+ const id = getStringField(result, ["asset_id", "assetId", "id"]) ?? getStringField(args, ["asset_id", "assetId", "id"]);
50898
+ return (id == null ? void 0 : id.startsWith("asset_")) ? id : null;
50899
+ }
50900
+ function getSlideNumber(args) {
50901
+ const explicit = getNumberField(args, ["slideNumber", "slide_number"]);
50902
+ if (explicit != null && Number.isInteger(explicit) && explicit >= 1) {
50903
+ return explicit;
50904
+ }
50905
+ const zeroBasedIndex = getNumberField(args, ["index", "slideIndex", "slide_index"]);
50906
+ if (zeroBasedIndex != null && Number.isInteger(zeroBasedIndex) && zeroBasedIndex >= 0) {
50907
+ return zeroBasedIndex + 1;
50908
+ }
50909
+ return void 0;
50910
+ }
50911
+ const completedStudioToolEffects = /* @__PURE__ */ new Set();
50912
+ const MAX_COMPLETED_STUDIO_TOOL_EFFECTS = 500;
50913
+ function markStudioToolEffect(key) {
50914
+ if (completedStudioToolEffects.has(key)) {
50915
+ return false;
50916
+ }
50917
+ if (completedStudioToolEffects.size >= MAX_COMPLETED_STUDIO_TOOL_EFFECTS) {
50918
+ const oldest = completedStudioToolEffects.values().next().value;
50919
+ if (oldest) completedStudioToolEffects.delete(oldest);
50920
+ }
50921
+ completedStudioToolEffects.add(key);
50922
+ return true;
50923
+ }
50924
+ function dispatchPresentationNavigate(assetId, slideNumber) {
50925
+ const targetSlide = slideNumber;
50926
+ if (typeof targetSlide !== "number" || !Number.isInteger(targetSlide) || targetSlide < 1) {
50927
+ return;
50928
+ }
50929
+ window.dispatchEvent(
50930
+ new CustomEvent("pptx-studio-navigate", {
50931
+ detail: { assetId, slideNumber: targetSlide }
50932
+ })
50933
+ );
50934
+ }
50867
50935
  function CreateAssetToolUIImpl({
50868
50936
  icon: Icon2,
50869
50937
  assetType,
@@ -50973,6 +51041,238 @@ const CreatePresentationToolUI = memo(
50973
51041
  CreatePresentationToolUIImpl
50974
51042
  );
50975
51043
  CreatePresentationToolUI.displayName = "CreatePresentationToolUI";
51044
+ function StudioPtcToolUI({
51045
+ config: config2,
51046
+ toolName,
51047
+ toolCallId,
51048
+ args,
51049
+ result,
51050
+ status
51051
+ }) {
51052
+ var _a2, _b;
51053
+ const typedArgs = args;
51054
+ const data = useMemo(() => normalizeResult(result), [result]);
51055
+ const slideNumber = (_a2 = config2.getSlideNumber) == null ? void 0 : _a2.call(config2, typedArgs);
51056
+ const assetId = getStudioAssetId({ args: typedArgs, result: data });
51057
+ const subtitle = (_b = config2.getSubtitle) == null ? void 0 : _b.call(config2, typedArgs, data, slideNumber);
51058
+ const isRunning = (status == null ? void 0 : status.type) === "running";
51059
+ const isComplete = (status == null ? void 0 : status.type) === "complete" || !status;
51060
+ const isCancelled = (status == null ? void 0 : status.type) === "incomplete" && status.reason === "cancelled";
51061
+ const errorMsg = (status == null ? void 0 : status.type) === "incomplete" ? String(status.error ?? status.reason ?? "Tool failed") : null;
51062
+ const openAsset = useAssetPanelStore((s) => s.openAsset);
51063
+ const handleOpen = useCallback(() => {
51064
+ if (!assetId) return;
51065
+ openAsset(assetId, {
51066
+ type: config2.assetType,
51067
+ slideNumber
51068
+ });
51069
+ if (config2.assetType === "presentation") {
51070
+ dispatchPresentationNavigate(assetId, slideNumber);
51071
+ }
51072
+ }, [assetId, config2.assetType, openAsset, slideNumber]);
51073
+ useEffect(() => {
51074
+ if (!config2.autoOpen || !isComplete || isCancelled || !assetId) {
51075
+ return;
51076
+ }
51077
+ const effectKey = toolCallId ?? `${toolName ?? "studio-tool"}:${assetId}:${slideNumber ?? "asset"}`;
51078
+ if (!markStudioToolEffect(effectKey)) {
51079
+ return;
51080
+ }
51081
+ const store = useAssetPanelStore.getState();
51082
+ store.openAsset(assetId, {
51083
+ type: config2.assetType,
51084
+ slideNumber
51085
+ });
51086
+ if (config2.assetType === "presentation") {
51087
+ dispatchPresentationNavigate(assetId, slideNumber);
51088
+ }
51089
+ }, [
51090
+ assetId,
51091
+ config2.assetType,
51092
+ config2.autoOpen,
51093
+ isCancelled,
51094
+ isComplete,
51095
+ slideNumber,
51096
+ toolCallId,
51097
+ toolName
51098
+ ]);
51099
+ return /* @__PURE__ */ jsx(
51100
+ ToolCard,
51101
+ {
51102
+ icon: config2.icon,
51103
+ status: (status == null ? void 0 : status.type) ?? "complete",
51104
+ title: isRunning ? config2.runningLabel(typedArgs) : config2.doneLabel(typedArgs, slideNumber),
51105
+ subtitle,
51106
+ badge: config2.badge,
51107
+ toolName,
51108
+ args: typedArgs,
51109
+ result,
51110
+ error: errorMsg,
51111
+ children: assetId && isComplete && !isCancelled && /* @__PURE__ */ jsx("div", { className: "border-t border-border/40 px-4 py-2", children: /* @__PURE__ */ jsxs(
51112
+ "button",
51113
+ {
51114
+ type: "button",
51115
+ onClick: handleOpen,
51116
+ className: "flex items-center gap-1.5 rounded-md border border-border/60 px-3 py-1.5 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground",
51117
+ children: [
51118
+ /* @__PURE__ */ jsx(ExternalLink, { className: "size-3" }),
51119
+ config2.openLabel(slideNumber)
51120
+ ]
51121
+ }
51122
+ ) })
51123
+ }
51124
+ );
51125
+ }
51126
+ function createStudioPtcToolUI(displayName, config2) {
51127
+ const Component = (props) => /* @__PURE__ */ jsx(StudioPtcToolUI, { config: config2, ...props });
51128
+ const Memoized = memo(Component);
51129
+ Memoized.displayName = displayName;
51130
+ return Memoized;
51131
+ }
51132
+ const getNameSubtitle = (args, result) => getStringField(result, ["title", "name", "asset_name"]) ?? getStringField(args, ["title", "name"]) ?? void 0;
51133
+ const getParagraphSubtitle = (args) => {
51134
+ const text2 = getStringField(args, ["text"]);
51135
+ return text2 ? truncate(text2, 80) : void 0;
51136
+ };
51137
+ const getSlideSubtitle = (args, _result, slideNumber) => {
51138
+ const layout = getStringField(args, ["layoutName", "layout_name"]) ?? getStringField(args, ["layoutPath", "layout_path"]);
51139
+ const slideLabel = slideNumber ? `Slide ${slideNumber}` : null;
51140
+ if (slideLabel && layout) return `${slideLabel} - ${truncate(layout, 48)}`;
51141
+ return slideLabel ?? (layout ? truncate(layout, 64) : void 0);
51142
+ };
51143
+ const StudioCreateWorkbookToolUI = createStudioPtcToolUI(
51144
+ "StudioCreateWorkbookToolUI",
51145
+ {
51146
+ icon: ChartColumn,
51147
+ assetType: "spreadsheet",
51148
+ badge: "Sheet",
51149
+ runningLabel: (args) => {
51150
+ const title = getStringField(args, ["title", "name"]);
51151
+ return title ? `Creating workbook "${title}"...` : "Creating workbook...";
51152
+ },
51153
+ doneLabel: () => "Workbook created",
51154
+ getSubtitle: getNameSubtitle,
51155
+ openLabel: () => "Open workbook",
51156
+ autoOpen: true
51157
+ }
51158
+ );
51159
+ const StudioAddSheetToolUI = createStudioPtcToolUI(
51160
+ "StudioAddSheetToolUI",
51161
+ {
51162
+ icon: ChartColumn,
51163
+ assetType: "spreadsheet",
51164
+ badge: "Sheet",
51165
+ runningLabel: (args) => {
51166
+ const name = getStringField(args, ["name", "sheetName", "sheet_name"]);
51167
+ return name ? `Adding sheet "${name}"...` : "Adding sheet...";
51168
+ },
51169
+ doneLabel: (args) => {
51170
+ const name = getStringField(args, ["name", "sheetName", "sheet_name"]);
51171
+ return name ? `Sheet added: ${name}` : "Sheet added";
51172
+ },
51173
+ getSubtitle: (args) => getStringField(args, ["name", "sheetName", "sheet_name"]) ?? void 0,
51174
+ openLabel: () => "Open workbook",
51175
+ autoOpen: true
51176
+ }
51177
+ );
51178
+ const StudioOpenWorkbookToolUI = createStudioPtcToolUI(
51179
+ "StudioOpenWorkbookToolUI",
51180
+ {
51181
+ icon: ChartColumn,
51182
+ assetType: "spreadsheet",
51183
+ badge: "Sheet",
51184
+ runningLabel: () => "Opening workbook...",
51185
+ doneLabel: () => "Workbook opened",
51186
+ openLabel: () => "Open workbook",
51187
+ autoOpen: true
51188
+ }
51189
+ );
51190
+ const StudioCreatePresentationToolUI = createStudioPtcToolUI(
51191
+ "StudioCreatePresentationToolUI",
51192
+ {
51193
+ icon: Presentation,
51194
+ assetType: "presentation",
51195
+ badge: "Deck",
51196
+ runningLabel: (args) => {
51197
+ const title = getStringField(args, ["title", "name"]);
51198
+ return title ? `Creating presentation "${title}"...` : "Creating presentation...";
51199
+ },
51200
+ doneLabel: () => "Presentation created",
51201
+ getSubtitle: getNameSubtitle,
51202
+ getSlideNumber: () => 1,
51203
+ openLabel: () => "Open presentation",
51204
+ autoOpen: true
51205
+ }
51206
+ );
51207
+ const StudioOpenPresentationToolUI = createStudioPtcToolUI(
51208
+ "StudioOpenPresentationToolUI",
51209
+ {
51210
+ icon: Presentation,
51211
+ assetType: "presentation",
51212
+ badge: "Deck",
51213
+ runningLabel: () => "Opening presentation...",
51214
+ doneLabel: () => "Presentation opened",
51215
+ getSlideNumber: () => 1,
51216
+ getSubtitle: (_args, _result, slideNumber) => slideNumber ? `Slide ${slideNumber}` : void 0,
51217
+ openLabel: () => "Open presentation",
51218
+ autoOpen: true
51219
+ }
51220
+ );
51221
+ const StudioAddSlideToolUI = createStudioPtcToolUI(
51222
+ "StudioAddSlideToolUI",
51223
+ {
51224
+ icon: Presentation,
51225
+ assetType: "presentation",
51226
+ badge: "Deck",
51227
+ runningLabel: () => "Adding slide...",
51228
+ doneLabel: (_args, slideNumber) => slideNumber ? `Slide ${slideNumber} added` : "Slide added",
51229
+ getSubtitle: getSlideSubtitle,
51230
+ getSlideNumber,
51231
+ openLabel: (slideNumber) => slideNumber ? `Open slide ${slideNumber}` : "Open presentation",
51232
+ autoOpen: true
51233
+ }
51234
+ );
51235
+ const StudioCreateDocumentToolUI = createStudioPtcToolUI(
51236
+ "StudioCreateDocumentToolUI",
51237
+ {
51238
+ icon: FileText,
51239
+ assetType: "document",
51240
+ badge: "Doc",
51241
+ runningLabel: (args) => {
51242
+ const title = getStringField(args, ["title", "name"]);
51243
+ return title ? `Creating document "${title}"...` : "Creating document...";
51244
+ },
51245
+ doneLabel: () => "Document created",
51246
+ getSubtitle: getNameSubtitle,
51247
+ openLabel: () => "Open document",
51248
+ autoOpen: true
51249
+ }
51250
+ );
51251
+ const StudioCreateParagraphToolUI = createStudioPtcToolUI(
51252
+ "StudioCreateParagraphToolUI",
51253
+ {
51254
+ icon: FileText,
51255
+ assetType: "document",
51256
+ badge: "Doc",
51257
+ runningLabel: () => "Adding paragraph...",
51258
+ doneLabel: () => "Paragraph added",
51259
+ getSubtitle: getParagraphSubtitle,
51260
+ openLabel: () => "Open document",
51261
+ autoOpen: true
51262
+ }
51263
+ );
51264
+ const StudioOpenDocumentToolUI = createStudioPtcToolUI(
51265
+ "StudioOpenDocumentToolUI",
51266
+ {
51267
+ icon: FileText,
51268
+ assetType: "document",
51269
+ badge: "Doc",
51270
+ runningLabel: () => "Opening document...",
51271
+ doneLabel: () => "Document opened",
51272
+ openLabel: () => "Open document",
51273
+ autoOpen: true
51274
+ }
51275
+ );
50976
51276
  const CreateEmailDraftToolUIImpl = ({
50977
51277
  toolName,
50978
51278
  args,
@@ -52416,6 +52716,16 @@ const TOOL_UI_REGISTRY = {
52416
52716
  create_new_sheet: CreateSheetToolUI,
52417
52717
  create_powerpoint_deck: CreatePresentationToolUI,
52418
52718
  create_new_notebook: CreateNotebookToolUI,
52719
+ // Studio SDK nested PTC tools
52720
+ CreateWorkbook: StudioCreateWorkbookToolUI,
52721
+ AddSheet: StudioAddSheetToolUI,
52722
+ OpenWorkbook: StudioOpenWorkbookToolUI,
52723
+ CreatePresentation: StudioCreatePresentationToolUI,
52724
+ OpenPresentation: StudioOpenPresentationToolUI,
52725
+ AddSlide: StudioAddSlideToolUI,
52726
+ CreateDocument: StudioCreateDocumentToolUI,
52727
+ OpenDocument: StudioOpenDocumentToolUI,
52728
+ CreateParagraph: StudioCreateParagraphToolUI,
52419
52729
  execute_presentation_code: ExecutePresentationCodeToolUI,
52420
52730
  run_python_code: RunPythonCodeToolUI,
52421
52731
  open_asset_in_workspace: OpenAssetToolUI,
@@ -53600,6 +53910,26 @@ function useAssetEmbed(assetId, options = {
53600
53910
  }, [assetId, readOnly, expiresInSeconds, backendUrl, apiKey, hasToken]);
53601
53911
  return { embedUrl, isLoading, error: error2 };
53602
53912
  }
53913
+ const ABSOLUTE_URL_PATTERN = /^[a-zA-Z][a-zA-Z\d+\-.]*:/;
53914
+ function buildAssetIframeSrc({
53915
+ embedUrl,
53916
+ assetType,
53917
+ slideNumber
53918
+ }) {
53919
+ const targetSlide = slideNumber;
53920
+ if (assetType !== "presentation" || typeof targetSlide !== "number" || !Number.isInteger(targetSlide) || targetSlide < 1) {
53921
+ return embedUrl;
53922
+ }
53923
+ try {
53924
+ const isAbsolute = ABSOLUTE_URL_PATTERN.test(embedUrl);
53925
+ const url = new URL(embedUrl, "https://athena.local");
53926
+ url.searchParams.set("slide", String(targetSlide));
53927
+ return isAbsolute ? url.toString() : `${url.pathname}${url.search}${url.hash}`;
53928
+ } catch {
53929
+ const separator = embedUrl.includes("?") ? "&" : "?";
53930
+ return `${embedUrl}${separator}slide=${targetSlide}`;
53931
+ }
53932
+ }
53603
53933
  const ASSET_TYPE_CONFIG = {
53604
53934
  presentation: { icon: Presentation, label: "Presentation" },
53605
53935
  spreadsheet: { icon: FileSpreadsheet, label: "Spreadsheet" },
@@ -53608,13 +53938,21 @@ const ASSET_TYPE_CONFIG = {
53608
53938
  unknown: { icon: File$1, label: "Asset" }
53609
53939
  };
53610
53940
  const AssetIframe = memo(
53611
- ({ tabId, tabName }) => {
53941
+ ({ tab }) => {
53612
53942
  const { backendUrl, apiKey, token } = useAthenaConfig();
53613
- const { embedUrl, isLoading, error: error2 } = useAssetEmbed(tabId, {
53943
+ const { embedUrl, isLoading, error: error2 } = useAssetEmbed(tab.id, {
53614
53944
  backendUrl,
53615
53945
  apiKey,
53616
53946
  token
53617
53947
  });
53948
+ const iframeSrc = useMemo(
53949
+ () => embedUrl ? buildAssetIframeSrc({
53950
+ embedUrl,
53951
+ assetType: tab.type,
53952
+ slideNumber: tab.slideNumber
53953
+ }) : null,
53954
+ [embedUrl, tab.slideNumber, tab.type]
53955
+ );
53618
53956
  if (isLoading) {
53619
53957
  return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
53620
53958
  /* @__PURE__ */ jsx(LoaderCircle, { className: "mx-auto size-6 animate-spin text-muted-foreground" }),
@@ -53628,16 +53966,16 @@ const AssetIframe = memo(
53628
53966
  /* @__PURE__ */ jsx("p", { className: "mt-0.5 line-clamp-2 break-words text-[10px] text-muted-foreground", children: error2 })
53629
53967
  ] }) });
53630
53968
  }
53631
- if (!embedUrl) return null;
53969
+ if (!iframeSrc) return null;
53632
53970
  return /* @__PURE__ */ jsx(
53633
53971
  "iframe",
53634
53972
  {
53635
- src: embedUrl,
53973
+ src: iframeSrc,
53636
53974
  width: "100%",
53637
53975
  height: "100%",
53638
53976
  frameBorder: "0",
53639
53977
  allow: "fullscreen",
53640
- title: tabName ?? `Asset ${tabId}`,
53978
+ title: tab.name ?? `Asset ${tab.id}`,
53641
53979
  className: "h-full w-full"
53642
53980
  }
53643
53981
  );
@@ -53699,7 +54037,7 @@ const PanelContent = ({
53699
54037
  }
53700
54038
  )
53701
54039
  ] }),
53702
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(AssetIframe, { tabId: tab.id, tabName: tab.name }) })
54040
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(AssetIframe, { tab }) })
53703
54041
  ]
53704
54042
  },
53705
54043
  tab.id
@@ -53709,7 +54047,7 @@ const PanelContent = ({
53709
54047
  "div",
53710
54048
  {
53711
54049
  className: isActive2 ? "h-full w-full" : "hidden",
53712
- children: /* @__PURE__ */ jsx(AssetIframe, { tabId: tab.id, tabName: tab.name })
54050
+ children: /* @__PURE__ */ jsx(AssetIframe, { tab })
53713
54051
  },
53714
54052
  tab.id
53715
54053
  );