@athenaintel/react 0.10.26 → 0.10.28

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.cjs CHANGED
@@ -14152,14 +14152,20 @@ const useAssetPanelStore = create()(
14152
14152
  const existing = s.tabs.find((t) => t.id === assetId);
14153
14153
  if (existing) {
14154
14154
  const tabs = meta ? s.tabs.map(
14155
- (t) => t.id === assetId ? { ...t, name: meta.name ?? t.name, type: meta.type ?? t.type } : t
14155
+ (t) => t.id === assetId ? {
14156
+ ...t,
14157
+ name: meta.name ?? t.name,
14158
+ type: meta.type ?? t.type,
14159
+ slideNumber: "slideNumber" in meta ? meta.slideNumber : t.slideNumber
14160
+ } : t
14156
14161
  ) : s.tabs;
14157
14162
  return { isOpen: true, tabs, activeTabId: assetId };
14158
14163
  }
14159
14164
  const newTab = {
14160
14165
  id: assetId,
14161
14166
  name: (meta == null ? void 0 : meta.name) ?? null,
14162
- type: (meta == null ? void 0 : meta.type) ?? "unknown"
14167
+ type: (meta == null ? void 0 : meta.type) ?? "unknown",
14168
+ slideNumber: meta == null ? void 0 : meta.slideNumber
14163
14169
  };
14164
14170
  return { isOpen: true, tabs: [...s.tabs, newTab], activeTabId: assetId };
14165
14171
  }),
@@ -50041,18 +50047,6 @@ function AssetToolCard({
50041
50047
  const assetId = extractAssetId$1(result);
50042
50048
  const title = extractTitle(argsText, result);
50043
50049
  const assetType = toolMetaToAssetType(toolName);
50044
- const wasCompleteAtMount = React.useRef(isComplete);
50045
- React.useEffect(() => {
50046
- if (isComplete && !isCancelled && assetId && !wasCompleteAtMount.current) {
50047
- const store = useAssetPanelStore.getState();
50048
- if (store.markAutoOpened(assetId)) {
50049
- store.openAsset(assetId, {
50050
- name: title ?? void 0,
50051
- type: assetType
50052
- });
50053
- }
50054
- }
50055
- }, [isComplete, isCancelled, assetId, title, assetType]);
50056
50050
  const success = isComplete && isResultSuccess(result);
50057
50051
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(
50058
50052
  "aui-tool-fallback-root my-3 w-full rounded-xl border border-border/60 bg-background py-2.5 shadow-sm",
@@ -50614,6 +50608,32 @@ function normalizeResult(result) {
50614
50608
  function truncate(text2, max2) {
50615
50609
  return text2.length > max2 ? `${text2.slice(0, max2)}...` : text2;
50616
50610
  }
50611
+ function isSdkToolDebugEnabled() {
50612
+ var _a2, _b;
50613
+ try {
50614
+ const hostname = (_a2 = globalThis.location) == null ? void 0 : _a2.hostname;
50615
+ if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1") {
50616
+ return true;
50617
+ }
50618
+ return ((_b = globalThis.localStorage) == null ? void 0 : _b.getItem("athena:sdk:debug")) === "1";
50619
+ } catch {
50620
+ return false;
50621
+ }
50622
+ }
50623
+ function stringifyDebugPayload(payload) {
50624
+ return JSON.stringify(payload, (_key, value) => {
50625
+ if (typeof value === "string" && value.length > 800) {
50626
+ return `${value.slice(0, 800)}... [truncated ${value.length - 800} chars]`;
50627
+ }
50628
+ return value;
50629
+ });
50630
+ }
50631
+ function logDebugPayload(label, payload) {
50632
+ if (!isSdkToolDebugEnabled()) {
50633
+ return;
50634
+ }
50635
+ console.info(`${label} ${stringifyDebugPayload(payload)}`);
50636
+ }
50617
50637
  function formatToolName(name) {
50618
50638
  return name.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
50619
50639
  }
@@ -50904,6 +50924,83 @@ function extractAssetId(result) {
50904
50924
  function resetAssetAutoOpen() {
50905
50925
  useAssetPanelStore.getState().resetAutoOpen();
50906
50926
  }
50927
+ function getStringField(source, keys2) {
50928
+ if (!source) return null;
50929
+ for (const key of keys2) {
50930
+ const value = source[key];
50931
+ if (typeof value === "string" && value.trim()) {
50932
+ return value;
50933
+ }
50934
+ }
50935
+ return null;
50936
+ }
50937
+ function getNumberField(source, keys2) {
50938
+ if (!source) return null;
50939
+ for (const key of keys2) {
50940
+ const value = source[key];
50941
+ if (typeof value === "number" && Number.isFinite(value)) {
50942
+ return value;
50943
+ }
50944
+ }
50945
+ return null;
50946
+ }
50947
+ const PRESENTATION_CODE_SLIDE_NUMBER_KEYS = [
50948
+ "slideNumber",
50949
+ "slide_number",
50950
+ "targetSlideNumber",
50951
+ "target_slide_number",
50952
+ "targetSlide",
50953
+ "target_slide"
50954
+ ];
50955
+ const PRESENTATION_CODE_SLIDE_INDEX_KEYS = [
50956
+ "slideIndex",
50957
+ "slide_index",
50958
+ "targetSlideIndex",
50959
+ "target_slide_index"
50960
+ ];
50961
+ function getStudioAssetId({
50962
+ args,
50963
+ result
50964
+ }) {
50965
+ const id = getStringField(result, ["asset_id", "assetId", "id"]) ?? getStringField(args, ["asset_id", "assetId", "id"]);
50966
+ return (id == null ? void 0 : id.startsWith("asset_")) ? id : null;
50967
+ }
50968
+ function getPresentationCodeDeckId(code2) {
50969
+ const match2 = code2.match(/\bdeck_id\s*=\s*["']([^"']+)["']/);
50970
+ const deckId = match2 == null ? void 0 : match2[1];
50971
+ return (deckId == null ? void 0 : deckId.startsWith("asset_")) ? deckId : null;
50972
+ }
50973
+ function getPresentationCodeSlideNumberFromFields(source) {
50974
+ const explicit = getNumberField(source, PRESENTATION_CODE_SLIDE_NUMBER_KEYS);
50975
+ if (explicit != null && Number.isInteger(explicit) && explicit >= 1) {
50976
+ return explicit;
50977
+ }
50978
+ const zeroBasedIndex = getNumberField(source, PRESENTATION_CODE_SLIDE_INDEX_KEYS);
50979
+ if (zeroBasedIndex != null && Number.isInteger(zeroBasedIndex) && zeroBasedIndex >= 0) {
50980
+ return zeroBasedIndex + 1;
50981
+ }
50982
+ return void 0;
50983
+ }
50984
+ function getPresentationCodeSlideNumberFromText(text2) {
50985
+ const match2 = text2 == null ? void 0 : text2.match(/\bslide\s*(?:#|number\s*)?(\d+)\b/i);
50986
+ if (!match2) {
50987
+ return void 0;
50988
+ }
50989
+ const slideNumber = Number.parseInt(match2[1] ?? "", 10);
50990
+ return Number.isInteger(slideNumber) && slideNumber >= 1 ? slideNumber : void 0;
50991
+ }
50992
+ function getPresentationCodeSlideNumber({
50993
+ args,
50994
+ result
50995
+ }) {
50996
+ return getPresentationCodeSlideNumberFromFields(args) ?? getPresentationCodeSlideNumberFromFields(result) ?? getPresentationCodeSlideNumberFromText(
50997
+ getStringField(args, ["summary", "title", "description"])
50998
+ );
50999
+ }
51000
+ function getAddSlideNumber(args) {
51001
+ const index2 = getNumberField(args, ["index"]);
51002
+ return index2 != null && Number.isInteger(index2) && index2 >= 0 ? index2 + 1 : void 0;
51003
+ }
50907
51004
  function CreateAssetToolUIImpl({
50908
51005
  icon: Icon2,
50909
51006
  assetType,
@@ -50924,18 +51021,6 @@ function CreateAssetToolUIImpl({
50924
51021
  const isCancelled = (status == null ? void 0 : status.type) === "incomplete" && status.reason === "cancelled";
50925
51022
  const errorMsg = (status == null ? void 0 : status.type) === "incomplete" ? status.error : null;
50926
51023
  const openAsset = useAssetPanelStore((s) => s.openAsset);
50927
- const wasCompleteAtMount = React.useRef(isComplete);
50928
- React.useEffect(() => {
50929
- if (isComplete && !isCancelled && assetId && !wasCompleteAtMount.current) {
50930
- const store = useAssetPanelStore.getState();
50931
- if (store.markAutoOpened(assetId)) {
50932
- store.openAsset(assetId, {
50933
- name: createdName || name || void 0,
50934
- type: assetType
50935
- });
50936
- }
50937
- }
50938
- }, [isComplete, isCancelled, assetId, createdName, name, assetType]);
50939
51024
  const handleOpen = () => {
50940
51025
  if (assetId) {
50941
51026
  openAsset(assetId, {
@@ -51013,6 +51098,258 @@ const CreatePresentationToolUI = React.memo(
51013
51098
  CreatePresentationToolUIImpl
51014
51099
  );
51015
51100
  CreatePresentationToolUI.displayName = "CreatePresentationToolUI";
51101
+ function openStudioAsset({
51102
+ assetId,
51103
+ assetType,
51104
+ slideNumber,
51105
+ preserveExistingSlide
51106
+ }) {
51107
+ const store = useAssetPanelStore.getState();
51108
+ const existing = store.tabs.find((tab) => tab.id === assetId);
51109
+ const shouldKeepCurrentSlide = preserveExistingSlide && existing;
51110
+ store.openAsset(assetId, {
51111
+ type: assetType,
51112
+ ...!shouldKeepCurrentSlide && slideNumber !== void 0 ? { slideNumber } : {}
51113
+ });
51114
+ }
51115
+ function StudioPtcToolUI({
51116
+ config: config2,
51117
+ toolName,
51118
+ args,
51119
+ result,
51120
+ status
51121
+ }) {
51122
+ var _a2, _b;
51123
+ const typedArgs = args;
51124
+ const data = React.useMemo(() => normalizeResult(result), [result]);
51125
+ const slideNumber = (_a2 = config2.getSlideNumber) == null ? void 0 : _a2.call(config2, typedArgs);
51126
+ const assetId = getStudioAssetId({ args: typedArgs, result: data });
51127
+ const subtitle = (_b = config2.getSubtitle) == null ? void 0 : _b.call(config2, typedArgs, data, slideNumber);
51128
+ const isRunning = (status == null ? void 0 : status.type) === "running";
51129
+ const isComplete = (status == null ? void 0 : status.type) === "complete" || !status;
51130
+ const isCancelled = (status == null ? void 0 : status.type) === "incomplete" && status.reason === "cancelled";
51131
+ const errorMsg = (status == null ? void 0 : status.type) === "incomplete" ? String(status.error ?? status.reason ?? "Tool failed") : null;
51132
+ const handleOpen = React.useCallback(() => {
51133
+ if (!assetId) return;
51134
+ if (toolName === "AddSlide") {
51135
+ logDebugPayload("[Athena SDK AddSlide] manual open", {
51136
+ args: typedArgs,
51137
+ parsedResult: data,
51138
+ rawResult: result,
51139
+ assetId,
51140
+ slideNumber
51141
+ });
51142
+ }
51143
+ openStudioAsset({
51144
+ assetId,
51145
+ assetType: config2.assetType,
51146
+ slideNumber,
51147
+ preserveExistingSlide: config2.preserveExistingSlide
51148
+ });
51149
+ }, [
51150
+ assetId,
51151
+ config2.assetType,
51152
+ config2.preserveExistingSlide,
51153
+ data,
51154
+ result,
51155
+ slideNumber,
51156
+ toolName,
51157
+ typedArgs
51158
+ ]);
51159
+ React.useEffect(() => {
51160
+ if (toolName !== "AddSlide") {
51161
+ return;
51162
+ }
51163
+ logDebugPayload("[Athena SDK AddSlide] tool state", {
51164
+ args: typedArgs,
51165
+ parsedResult: data,
51166
+ rawResult: result,
51167
+ status,
51168
+ assetId,
51169
+ slideNumber,
51170
+ isComplete,
51171
+ isCancelled
51172
+ });
51173
+ }, [
51174
+ assetId,
51175
+ data,
51176
+ isCancelled,
51177
+ isComplete,
51178
+ result,
51179
+ slideNumber,
51180
+ status,
51181
+ toolName,
51182
+ typedArgs
51183
+ ]);
51184
+ return /* @__PURE__ */ jsxRuntime.jsx(
51185
+ ToolCard,
51186
+ {
51187
+ icon: config2.icon,
51188
+ status: (status == null ? void 0 : status.type) ?? "complete",
51189
+ title: isRunning ? config2.runningLabel(typedArgs) : config2.doneLabel(typedArgs, slideNumber),
51190
+ subtitle,
51191
+ badge: config2.badge,
51192
+ toolName,
51193
+ args: typedArgs,
51194
+ result,
51195
+ error: errorMsg,
51196
+ children: assetId && isComplete && !isCancelled && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-border/40 px-4 py-2", children: /* @__PURE__ */ jsxRuntime.jsxs(
51197
+ "button",
51198
+ {
51199
+ type: "button",
51200
+ onClick: handleOpen,
51201
+ 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",
51202
+ children: [
51203
+ /* @__PURE__ */ jsxRuntime.jsx(ExternalLink, { className: "size-3" }),
51204
+ config2.openLabel(slideNumber)
51205
+ ]
51206
+ }
51207
+ ) })
51208
+ }
51209
+ );
51210
+ }
51211
+ function createStudioPtcToolUI(displayName, config2) {
51212
+ const Component = (props) => /* @__PURE__ */ jsxRuntime.jsx(StudioPtcToolUI, { config: config2, ...props });
51213
+ const Memoized = React.memo(Component);
51214
+ Memoized.displayName = displayName;
51215
+ return Memoized;
51216
+ }
51217
+ const getNameSubtitle = (args, result) => getStringField(result, ["title", "name", "asset_name"]) ?? getStringField(args, ["title", "name"]) ?? void 0;
51218
+ const getParagraphSubtitle = (args) => {
51219
+ const text2 = getStringField(args, ["text"]);
51220
+ return text2 ? truncate(text2, 80) : void 0;
51221
+ };
51222
+ const getSlideSubtitle = (args, _result, slideNumber) => {
51223
+ const layout = getStringField(args, ["layoutName", "layout_name"]) ?? getStringField(args, ["layoutPath", "layout_path"]);
51224
+ const slideLabel = slideNumber ? `Slide ${slideNumber}` : null;
51225
+ if (slideLabel && layout) return `${slideLabel} - ${truncate(layout, 48)}`;
51226
+ return slideLabel ?? (layout ? truncate(layout, 64) : void 0);
51227
+ };
51228
+ const StudioCreateWorkbookToolUI = createStudioPtcToolUI(
51229
+ "StudioCreateWorkbookToolUI",
51230
+ {
51231
+ icon: ChartColumn,
51232
+ assetType: "spreadsheet",
51233
+ badge: "Sheet",
51234
+ runningLabel: (args) => {
51235
+ const title = getStringField(args, ["title", "name"]);
51236
+ return title ? `Creating workbook "${title}"...` : "Creating workbook...";
51237
+ },
51238
+ doneLabel: () => "Workbook created",
51239
+ getSubtitle: getNameSubtitle,
51240
+ openLabel: () => "Open workbook"
51241
+ }
51242
+ );
51243
+ const StudioAddSheetToolUI = createStudioPtcToolUI(
51244
+ "StudioAddSheetToolUI",
51245
+ {
51246
+ icon: ChartColumn,
51247
+ assetType: "spreadsheet",
51248
+ badge: "Sheet",
51249
+ runningLabel: (args) => {
51250
+ const name = getStringField(args, ["name", "sheetName", "sheet_name"]);
51251
+ return name ? `Adding sheet "${name}"...` : "Adding sheet...";
51252
+ },
51253
+ doneLabel: (args) => {
51254
+ const name = getStringField(args, ["name", "sheetName", "sheet_name"]);
51255
+ return name ? `Sheet added: ${name}` : "Sheet added";
51256
+ },
51257
+ getSubtitle: (args) => getStringField(args, ["name", "sheetName", "sheet_name"]) ?? void 0,
51258
+ openLabel: () => "Open workbook"
51259
+ }
51260
+ );
51261
+ const StudioOpenWorkbookToolUI = createStudioPtcToolUI(
51262
+ "StudioOpenWorkbookToolUI",
51263
+ {
51264
+ icon: ChartColumn,
51265
+ assetType: "spreadsheet",
51266
+ badge: "Sheet",
51267
+ runningLabel: () => "Opening workbook...",
51268
+ doneLabel: () => "Workbook opened",
51269
+ openLabel: () => "Open workbook"
51270
+ }
51271
+ );
51272
+ const StudioCreatePresentationToolUI = createStudioPtcToolUI(
51273
+ "StudioCreatePresentationToolUI",
51274
+ {
51275
+ icon: Presentation,
51276
+ assetType: "presentation",
51277
+ badge: "Deck",
51278
+ runningLabel: (args) => {
51279
+ const title = getStringField(args, ["title", "name"]);
51280
+ return title ? `Creating presentation "${title}"...` : "Creating presentation...";
51281
+ },
51282
+ doneLabel: () => "Presentation created",
51283
+ getSubtitle: getNameSubtitle,
51284
+ getSlideNumber: () => 1,
51285
+ openLabel: () => "Open presentation"
51286
+ }
51287
+ );
51288
+ const StudioOpenPresentationToolUI = createStudioPtcToolUI(
51289
+ "StudioOpenPresentationToolUI",
51290
+ {
51291
+ icon: Presentation,
51292
+ assetType: "presentation",
51293
+ badge: "Deck",
51294
+ runningLabel: () => "Opening presentation...",
51295
+ doneLabel: () => "Presentation opened",
51296
+ getSlideNumber: () => 1,
51297
+ getSubtitle: (_args, _result, slideNumber) => slideNumber ? `Slide ${slideNumber}` : void 0,
51298
+ openLabel: () => "Open presentation",
51299
+ preserveExistingSlide: true
51300
+ }
51301
+ );
51302
+ const StudioAddSlideToolUI = createStudioPtcToolUI(
51303
+ "StudioAddSlideToolUI",
51304
+ {
51305
+ icon: Presentation,
51306
+ assetType: "presentation",
51307
+ badge: "Deck",
51308
+ runningLabel: () => "Adding slide...",
51309
+ doneLabel: (_args, slideNumber) => slideNumber ? `Slide ${slideNumber} added` : "Slide added",
51310
+ getSubtitle: getSlideSubtitle,
51311
+ getSlideNumber: (args) => getAddSlideNumber(args) ?? 1,
51312
+ openLabel: (slideNumber) => slideNumber ? `Open slide ${slideNumber}` : "Open presentation"
51313
+ }
51314
+ );
51315
+ const StudioCreateDocumentToolUI = createStudioPtcToolUI(
51316
+ "StudioCreateDocumentToolUI",
51317
+ {
51318
+ icon: FileText,
51319
+ assetType: "document",
51320
+ badge: "Doc",
51321
+ runningLabel: (args) => {
51322
+ const title = getStringField(args, ["title", "name"]);
51323
+ return title ? `Creating document "${title}"...` : "Creating document...";
51324
+ },
51325
+ doneLabel: () => "Document created",
51326
+ getSubtitle: getNameSubtitle,
51327
+ openLabel: () => "Open document"
51328
+ }
51329
+ );
51330
+ const StudioCreateParagraphToolUI = createStudioPtcToolUI(
51331
+ "StudioCreateParagraphToolUI",
51332
+ {
51333
+ icon: FileText,
51334
+ assetType: "document",
51335
+ badge: "Doc",
51336
+ runningLabel: () => "Adding paragraph...",
51337
+ doneLabel: () => "Paragraph added",
51338
+ getSubtitle: getParagraphSubtitle,
51339
+ openLabel: () => "Open document"
51340
+ }
51341
+ );
51342
+ const StudioOpenDocumentToolUI = createStudioPtcToolUI(
51343
+ "StudioOpenDocumentToolUI",
51344
+ {
51345
+ icon: FileText,
51346
+ assetType: "document",
51347
+ badge: "Doc",
51348
+ runningLabel: () => "Opening document...",
51349
+ doneLabel: () => "Document opened",
51350
+ openLabel: () => "Open document"
51351
+ }
51352
+ );
51016
51353
  const CreateEmailDraftToolUIImpl = ({
51017
51354
  toolName,
51018
51355
  args,
@@ -51518,7 +51855,7 @@ const ExecutePresentationCodeToolUIImpl = ({
51518
51855
  const typedArgs = args;
51519
51856
  const code2 = (typedArgs == null ? void 0 : typedArgs.code) ?? "";
51520
51857
  const summary = (typedArgs == null ? void 0 : typedArgs.summary) ?? null;
51521
- const deckIdFromArgs = typeof (typedArgs == null ? void 0 : typedArgs.deck_id) === "string" ? typedArgs.deck_id : null;
51858
+ const deckIdFromArgs = getStringField(typedArgs, ["deck_id", "deckId", "asset_id", "assetId"]) ?? getPresentationCodeDeckId(code2);
51522
51859
  const isRunning = (status == null ? void 0 : status.type) === "running";
51523
51860
  const isComplete = (status == null ? void 0 : status.type) === "complete";
51524
51861
  const errorMsg = (status == null ? void 0 : status.type) === "incomplete" ? status.error : null;
@@ -51526,21 +51863,55 @@ const ExecutePresentationCodeToolUIImpl = ({
51526
51863
  () => isComplete ? parsePythonResult(result) : null,
51527
51864
  [result, isComplete]
51528
51865
  );
51866
+ const resultData = React.useMemo(() => normalizeResult(result), [result]);
51529
51867
  const outputText = parsed ? getExecutionTextOutput(parsed) : null;
51530
- const assetId = (parsed == null ? void 0 : parsed.assetId) ?? null;
51868
+ const targetSlideNumber = getPresentationCodeSlideNumber({
51869
+ args: typedArgs,
51870
+ result: resultData
51871
+ });
51531
51872
  const deckId = (parsed == null ? void 0 : parsed.deckId) ?? deckIdFromArgs;
51873
+ const assetId = (parsed == null ? void 0 : parsed.assetId) ?? ((deckId == null ? void 0 : deckId.startsWith("asset_")) ? deckId : null);
51532
51874
  const hasError = parsed && (parsed.error || parsed.exception);
51533
51875
  const openAsset = useAssetPanelStore((s) => s.openAsset);
51534
- const wasCompleteAtMount = React.useRef(isComplete);
51535
51876
  React.useEffect(() => {
51536
- if (!isComplete || !assetId || wasCompleteAtMount.current) {
51877
+ if (!isComplete) {
51537
51878
  return;
51538
51879
  }
51539
- const store = useAssetPanelStore.getState();
51540
- if (store.markAutoOpened(assetId)) {
51541
- store.openAsset(assetId, { type: "presentation" });
51880
+ logDebugPayload("[Athena SDK execute_presentation_code] tool state", {
51881
+ args: typedArgs,
51882
+ parsedResult: resultData,
51883
+ status,
51884
+ assetId,
51885
+ deckId,
51886
+ targetSlideNumber,
51887
+ outputText
51888
+ });
51889
+ }, [
51890
+ assetId,
51891
+ deckId,
51892
+ isComplete,
51893
+ outputText,
51894
+ resultData,
51895
+ status,
51896
+ targetSlideNumber,
51897
+ typedArgs
51898
+ ]);
51899
+ const openPresentation = React.useCallback(() => {
51900
+ if (!assetId) {
51901
+ return;
51542
51902
  }
51543
- }, [assetId, isComplete]);
51903
+ logDebugPayload("[Athena SDK execute_presentation_code] open deck", {
51904
+ args: typedArgs,
51905
+ parsedResult: resultData,
51906
+ assetId,
51907
+ deckId,
51908
+ targetSlideNumber
51909
+ });
51910
+ openAsset(assetId, {
51911
+ type: "presentation",
51912
+ ...targetSlideNumber !== void 0 ? { slideNumber: targetSlideNumber } : {}
51913
+ });
51914
+ }, [assetId, deckId, openAsset, resultData, targetSlideNumber, typedArgs]);
51544
51915
  return /* @__PURE__ */ jsxRuntime.jsxs(
51545
51916
  ToolCard,
51546
51917
  {
@@ -51563,11 +51934,11 @@ const ExecutePresentationCodeToolUIImpl = ({
51563
51934
  "button",
51564
51935
  {
51565
51936
  type: "button",
51566
- onClick: () => openAsset(assetId, { type: "presentation" }),
51937
+ onClick: openPresentation,
51567
51938
  className: "flex shrink-0 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",
51568
51939
  children: [
51569
51940
  /* @__PURE__ */ jsxRuntime.jsx(ExternalLink, { className: "size-3" }),
51570
- "Open deck"
51941
+ targetSlideNumber ? `Open slide ${targetSlideNumber}` : "Open deck"
51571
51942
  ]
51572
51943
  }
51573
51944
  )
@@ -51626,15 +51997,6 @@ const OpenAssetToolUIImpl = ({
51626
51997
  const isCancelled = (status == null ? void 0 : status.type) === "incomplete" && status.reason === "cancelled";
51627
51998
  const errorMsg = (status == null ? void 0 : status.type) === "incomplete" ? status.error : null;
51628
51999
  const openAsset = useAssetPanelStore((s) => s.openAsset);
51629
- const wasCompleteAtMount = React.useRef(isComplete);
51630
- React.useEffect(() => {
51631
- if (isComplete && !isCancelled && assetId && !wasCompleteAtMount.current) {
51632
- const store = useAssetPanelStore.getState();
51633
- if (store.markAutoOpened(assetId)) {
51634
- store.openAsset(assetId);
51635
- }
51636
- }
51637
- }, [isComplete, isCancelled, assetId]);
51638
52000
  return /* @__PURE__ */ jsxRuntime.jsx(
51639
52001
  ToolCard,
51640
52002
  {
@@ -52373,18 +52735,6 @@ const CaptureMomentToolUIImpl = ({
52373
52735
  const isComplete = (status == null ? void 0 : status.type) === "complete" || !status;
52374
52736
  const isCancelled = (status == null ? void 0 : status.type) === "incomplete" && status.reason === "cancelled";
52375
52737
  const openAsset = useAssetPanelStore((s) => s.openAsset);
52376
- const wasCompleteAtMount = React.useRef(isComplete);
52377
- React.useEffect(() => {
52378
- if (isComplete && !isCancelled && createdAssetId && !wasCompleteAtMount.current) {
52379
- const store = useAssetPanelStore.getState();
52380
- if (store.markAutoOpened(createdAssetId)) {
52381
- store.openAsset(createdAssetId, {
52382
- name: void 0,
52383
- type: "unknown"
52384
- });
52385
- }
52386
- }
52387
- }, [isComplete, isCancelled, createdAssetId, resultType]);
52388
52738
  const handleOpen = () => {
52389
52739
  if (createdAssetId) {
52390
52740
  openAsset(createdAssetId, {
@@ -52444,6 +52794,153 @@ const CaptureMomentToolUI = React.memo(
52444
52794
  CaptureMomentToolUIImpl
52445
52795
  );
52446
52796
  CaptureMomentToolUI.displayName = "CaptureMomentToolUI";
52797
+ function normalizeContentResult(result) {
52798
+ if (Array.isArray(result)) {
52799
+ return result;
52800
+ }
52801
+ if (typeof result === "string") {
52802
+ try {
52803
+ const parsed = JSON.parse(result);
52804
+ return normalizeContentResult(parsed);
52805
+ } catch {
52806
+ return [];
52807
+ }
52808
+ }
52809
+ if (result && typeof result === "object") {
52810
+ const obj = result;
52811
+ if (Array.isArray(obj.result)) {
52812
+ return obj.result;
52813
+ }
52814
+ if (typeof obj.result === "string") {
52815
+ return normalizeContentResult(obj.result);
52816
+ }
52817
+ if (Array.isArray(obj.content)) {
52818
+ return obj.content;
52819
+ }
52820
+ }
52821
+ return [];
52822
+ }
52823
+ function getSlideScreenshotResult(result) {
52824
+ let text2 = null;
52825
+ let imageUrl = null;
52826
+ let mediaType = null;
52827
+ let s3Key = null;
52828
+ for (const item of normalizeContentResult(result)) {
52829
+ if (!item || typeof item !== "object") {
52830
+ continue;
52831
+ }
52832
+ const part = item;
52833
+ if (!text2 && part.type === "text" && typeof part.text === "string") {
52834
+ text2 = part.text;
52835
+ continue;
52836
+ }
52837
+ if (part.type !== "image") {
52838
+ continue;
52839
+ }
52840
+ const source = part.source && typeof part.source === "object" ? part.source : {};
52841
+ if (!imageUrl) {
52842
+ imageUrl = getStringField(source, ["presigned_url", "url"]) ?? getStringField(part, ["url", "image_url"]);
52843
+ }
52844
+ if (!mediaType) {
52845
+ mediaType = getStringField(source, ["media_type", "mime_type"]) ?? getStringField(part, ["media_type", "mime_type"]);
52846
+ }
52847
+ if (!s3Key) {
52848
+ s3Key = getStringField(source, ["data", "s3_key"]);
52849
+ }
52850
+ }
52851
+ return { text: text2, imageUrl, mediaType, s3Key };
52852
+ }
52853
+ const CaptureSlideScreenshotToolUIImpl = ({
52854
+ toolName,
52855
+ args,
52856
+ result,
52857
+ status
52858
+ }) => {
52859
+ const typedArgs = args;
52860
+ const assetId = getStringField(typedArgs, ["asset_id", "assetId"]);
52861
+ const slideNumber = getNumberField(typedArgs, ["slide_number", "slideNumber"]) ?? void 0;
52862
+ const { text: text2, imageUrl, mediaType } = React.useMemo(
52863
+ () => getSlideScreenshotResult(result),
52864
+ [result]
52865
+ );
52866
+ const isRunning = (status == null ? void 0 : status.type) === "running";
52867
+ const isComplete = (status == null ? void 0 : status.type) === "complete" || !status;
52868
+ const isCancelled = (status == null ? void 0 : status.type) === "incomplete" && status.reason === "cancelled";
52869
+ const errorMsg = (status == null ? void 0 : status.type) === "incomplete" ? String(status.error ?? status.reason ?? "Capture failed") : null;
52870
+ const openAsset = useAssetPanelStore((s) => s.openAsset);
52871
+ const handleOpenSlide = React.useCallback(() => {
52872
+ if (!assetId) {
52873
+ return;
52874
+ }
52875
+ openAsset(assetId, {
52876
+ type: "presentation",
52877
+ ...slideNumber ? { slideNumber } : {}
52878
+ });
52879
+ }, [assetId, openAsset, slideNumber]);
52880
+ const subtitle = [
52881
+ slideNumber ? `Slide ${slideNumber}` : null,
52882
+ assetId ? truncate(assetId, 34) : null
52883
+ ].filter((value) => Boolean(value)).join(" · ");
52884
+ return /* @__PURE__ */ jsxRuntime.jsxs(
52885
+ ToolCard,
52886
+ {
52887
+ icon: Camera,
52888
+ status: (status == null ? void 0 : status.type) ?? "complete",
52889
+ title: isRunning ? "Capturing slide screenshot..." : errorMsg ? "Slide screenshot failed" : "Slide screenshot captured",
52890
+ subtitle: subtitle || void 0,
52891
+ badge: slideNumber ? `Slide ${slideNumber}` : mediaType ?? void 0,
52892
+ toolName,
52893
+ args: typedArgs,
52894
+ result,
52895
+ error: errorMsg,
52896
+ children: [
52897
+ isComplete && !isCancelled && imageUrl && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-border/40 p-3", children: [
52898
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-lg border border-border/50 bg-muted/20", children: /* @__PURE__ */ jsxRuntime.jsx(
52899
+ "img",
52900
+ {
52901
+ src: imageUrl,
52902
+ alt: slideNumber ? `Slide ${slideNumber} screenshot` : "Slide screenshot",
52903
+ className: "aspect-video w-full object-contain",
52904
+ loading: "lazy"
52905
+ }
52906
+ ) }),
52907
+ text2 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-[11px] leading-relaxed text-muted-foreground", children: truncate(text2, 160) })
52908
+ ] }),
52909
+ isComplete && !isCancelled && assetId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2 border-t border-border/40 px-4 py-2", children: [
52910
+ /* @__PURE__ */ jsxRuntime.jsxs(
52911
+ "button",
52912
+ {
52913
+ type: "button",
52914
+ onClick: handleOpenSlide,
52915
+ 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",
52916
+ children: [
52917
+ /* @__PURE__ */ jsxRuntime.jsx(ExternalLink, { className: "size-3" }),
52918
+ slideNumber ? `Open slide ${slideNumber}` : "Open presentation"
52919
+ ]
52920
+ }
52921
+ ),
52922
+ imageUrl && /* @__PURE__ */ jsxRuntime.jsxs(
52923
+ "a",
52924
+ {
52925
+ href: imageUrl,
52926
+ target: "_blank",
52927
+ rel: "noreferrer",
52928
+ 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",
52929
+ children: [
52930
+ /* @__PURE__ */ jsxRuntime.jsx(Image, { className: "size-3" }),
52931
+ "Open image"
52932
+ ]
52933
+ }
52934
+ )
52935
+ ] })
52936
+ ]
52937
+ }
52938
+ );
52939
+ };
52940
+ const CaptureSlideScreenshotToolUI = React.memo(
52941
+ CaptureSlideScreenshotToolUIImpl
52942
+ );
52943
+ CaptureSlideScreenshotToolUI.displayName = "CaptureSlideScreenshotToolUI";
52447
52944
  const TOOL_UI_REGISTRY = {
52448
52945
  search: WebSearchToolUI,
52449
52946
  browse: BrowseToolUI,
@@ -52456,11 +52953,22 @@ const TOOL_UI_REGISTRY = {
52456
52953
  create_new_sheet: CreateSheetToolUI,
52457
52954
  create_powerpoint_deck: CreatePresentationToolUI,
52458
52955
  create_new_notebook: CreateNotebookToolUI,
52956
+ // Studio SDK nested PTC tools
52957
+ CreateWorkbook: StudioCreateWorkbookToolUI,
52958
+ AddSheet: StudioAddSheetToolUI,
52959
+ OpenWorkbook: StudioOpenWorkbookToolUI,
52960
+ CreatePresentation: StudioCreatePresentationToolUI,
52961
+ OpenPresentation: StudioOpenPresentationToolUI,
52962
+ AddSlide: StudioAddSlideToolUI,
52963
+ CreateDocument: StudioCreateDocumentToolUI,
52964
+ OpenDocument: StudioOpenDocumentToolUI,
52965
+ CreateParagraph: StudioCreateParagraphToolUI,
52459
52966
  execute_presentation_code: ExecutePresentationCodeToolUI,
52460
52967
  run_python_code: RunPythonCodeToolUI,
52461
52968
  open_asset_in_workspace: OpenAssetToolUI,
52462
52969
  // Media capture
52463
52970
  capture_moment: CaptureMomentToolUI,
52971
+ capture_slide_screenshot: CaptureSlideScreenshotToolUI,
52464
52972
  // Spreadsheet toolkit
52465
52973
  update_sheet_range: UpdateSheetRangeToolUI,
52466
52974
  // Database toolkit
@@ -53570,10 +54078,37 @@ const AthenaUserMessage = ({
53570
54078
  }
53571
54079
  );
53572
54080
  const embedCache = /* @__PURE__ */ new Map();
54081
+ function resolveAssetEmbedUrl({
54082
+ embedUrl,
54083
+ appUrl
54084
+ }) {
54085
+ if (!appUrl) {
54086
+ return embedUrl;
54087
+ }
54088
+ try {
54089
+ const resolvedEmbedUrl = new URL(embedUrl);
54090
+ const resolvedAppUrl = new URL(appUrl);
54091
+ if (!resolvedEmbedUrl.pathname.startsWith("/embed/")) {
54092
+ return embedUrl;
54093
+ }
54094
+ resolvedEmbedUrl.protocol = resolvedAppUrl.protocol;
54095
+ resolvedEmbedUrl.host = resolvedAppUrl.host;
54096
+ return resolvedEmbedUrl.toString();
54097
+ } catch {
54098
+ return embedUrl;
54099
+ }
54100
+ }
53573
54101
  function useAssetEmbed(assetId, options = {
53574
54102
  backendUrl: ""
53575
54103
  }) {
53576
- const { readOnly = false, expiresInSeconds = 60 * 60 * 24 * 30, backendUrl, apiKey, token } = options;
54104
+ const {
54105
+ readOnly = false,
54106
+ expiresInSeconds = 60 * 60 * 24 * 30,
54107
+ backendUrl,
54108
+ appUrl,
54109
+ apiKey,
54110
+ token
54111
+ } = options;
53577
54112
  const [embedUrl, setEmbedUrl] = React.useState(null);
53578
54113
  const [isLoading, setIsLoading] = React.useState(false);
53579
54114
  const [error2, setError] = React.useState(null);
@@ -53590,7 +54125,7 @@ function useAssetEmbed(assetId, options = {
53590
54125
  return;
53591
54126
  }
53592
54127
  const authContext = hasToken ? "token" : apiKey ?? "anon";
53593
- const cacheKey = `${assetId}:${readOnly}:${authContext}`;
54128
+ const cacheKey = `${assetId}:${readOnly}:${authContext}:${appUrl ?? ""}`;
53594
54129
  const cached2 = embedCache.get(cacheKey);
53595
54130
  if (cached2 && cached2.expiresAt > Date.now() / 1e3) {
53596
54131
  setEmbedUrl(cached2.url);
@@ -53628,8 +54163,12 @@ function useAssetEmbed(assetId, options = {
53628
54163
  }
53629
54164
  return res.json();
53630
54165
  }).then((data) => {
53631
- embedCache.set(cacheKey, { url: data.embed_url, expiresAt: data.expires_at });
53632
- setEmbedUrl(data.embed_url);
54166
+ const resolvedEmbedUrl = resolveAssetEmbedUrl({
54167
+ embedUrl: data.embed_url,
54168
+ appUrl
54169
+ });
54170
+ embedCache.set(cacheKey, { url: resolvedEmbedUrl, expiresAt: data.expires_at });
54171
+ setEmbedUrl(resolvedEmbedUrl);
53633
54172
  setIsLoading(false);
53634
54173
  }).catch((err) => {
53635
54174
  if (err.name === "AbortError") return;
@@ -53637,9 +54176,44 @@ function useAssetEmbed(assetId, options = {
53637
54176
  setIsLoading(false);
53638
54177
  });
53639
54178
  return () => controller.abort();
53640
- }, [assetId, readOnly, expiresInSeconds, backendUrl, apiKey, hasToken]);
54179
+ }, [assetId, readOnly, expiresInSeconds, backendUrl, appUrl, apiKey, hasToken]);
53641
54180
  return { embedUrl, isLoading, error: error2 };
53642
54181
  }
54182
+ const ABSOLUTE_URL_PATTERN = /^[a-zA-Z][a-zA-Z\d+\-.]*:/;
54183
+ function buildAssetIframeSrc({
54184
+ embedUrl,
54185
+ assetType,
54186
+ slideNumber
54187
+ }) {
54188
+ const targetSlide = slideNumber;
54189
+ if (assetType !== "presentation" || typeof targetSlide !== "number" || !Number.isInteger(targetSlide) || targetSlide < 1) {
54190
+ return embedUrl;
54191
+ }
54192
+ try {
54193
+ const isAbsolute = ABSOLUTE_URL_PATTERN.test(embedUrl);
54194
+ const url = new URL(embedUrl, "https://athena.local");
54195
+ url.searchParams.set("slide", String(targetSlide));
54196
+ return isAbsolute ? url.toString() : `${url.pathname}${url.search}${url.hash}`;
54197
+ } catch {
54198
+ const separator = embedUrl.includes("?") ? "&" : "?";
54199
+ return `${embedUrl}${separator}slide=${targetSlide}`;
54200
+ }
54201
+ }
54202
+ function buildPresentationNavigationMessage({
54203
+ assetId,
54204
+ assetType,
54205
+ slideNumber
54206
+ }) {
54207
+ if (assetType !== "presentation" || typeof slideNumber !== "number" || !Number.isInteger(slideNumber) || slideNumber < 1) {
54208
+ return null;
54209
+ }
54210
+ return {
54211
+ type: "NAVIGATE_TO_SLIDE",
54212
+ assetId,
54213
+ deckId: assetId,
54214
+ slideNumber
54215
+ };
54216
+ }
53643
54217
  const ASSET_TYPE_CONFIG = {
53644
54218
  presentation: { icon: Presentation, label: "Presentation" },
53645
54219
  spreadsheet: { icon: FileSpreadsheet, label: "Spreadsheet" },
@@ -53648,13 +54222,39 @@ const ASSET_TYPE_CONFIG = {
53648
54222
  unknown: { icon: File$1, label: "Asset" }
53649
54223
  };
53650
54224
  const AssetIframe = React.memo(
53651
- ({ tabId, tabName }) => {
53652
- const { backendUrl, apiKey, token } = useAthenaConfig();
53653
- const { embedUrl, isLoading, error: error2 } = useAssetEmbed(tabId, {
54225
+ ({ tab }) => {
54226
+ const iframeRef = React.useRef(null);
54227
+ const { backendUrl, appUrl, apiKey, token } = useAthenaConfig();
54228
+ const { embedUrl, isLoading, error: error2 } = useAssetEmbed(tab.id, {
53654
54229
  backendUrl,
54230
+ appUrl,
53655
54231
  apiKey,
53656
54232
  token
53657
54233
  });
54234
+ const iframeSrc = React.useMemo(
54235
+ () => embedUrl ? buildAssetIframeSrc({
54236
+ embedUrl,
54237
+ assetType: tab.type,
54238
+ slideNumber: tab.slideNumber
54239
+ }) : null,
54240
+ [embedUrl, tab.slideNumber, tab.type]
54241
+ );
54242
+ const navigationMessage = React.useMemo(
54243
+ () => buildPresentationNavigationMessage({
54244
+ assetId: tab.id,
54245
+ assetType: tab.type,
54246
+ slideNumber: tab.slideNumber
54247
+ }),
54248
+ [tab.id, tab.slideNumber, tab.type]
54249
+ );
54250
+ const postNavigationMessage = React.useCallback(() => {
54251
+ var _a2, _b;
54252
+ if (!navigationMessage) return;
54253
+ (_b = (_a2 = iframeRef.current) == null ? void 0 : _a2.contentWindow) == null ? void 0 : _b.postMessage(navigationMessage, "*");
54254
+ }, [navigationMessage]);
54255
+ React.useEffect(() => {
54256
+ postNavigationMessage();
54257
+ }, [postNavigationMessage]);
53658
54258
  if (isLoading) {
53659
54259
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
53660
54260
  /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { className: "mx-auto size-6 animate-spin text-muted-foreground" }),
@@ -53668,20 +54268,23 @@ const AssetIframe = React.memo(
53668
54268
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 line-clamp-2 break-words text-[10px] text-muted-foreground", children: error2 })
53669
54269
  ] }) });
53670
54270
  }
53671
- if (!embedUrl) return null;
54271
+ if (!iframeSrc) return null;
53672
54272
  return /* @__PURE__ */ jsxRuntime.jsx(
53673
54273
  "iframe",
53674
54274
  {
53675
- src: embedUrl,
54275
+ ref: iframeRef,
54276
+ src: iframeSrc,
53676
54277
  width: "100%",
53677
54278
  height: "100%",
53678
54279
  frameBorder: "0",
53679
54280
  allow: "fullscreen",
53680
- title: tabName ?? `Asset ${tabId}`,
53681
- className: "h-full w-full"
54281
+ title: tab.name ?? `Asset ${tab.id}`,
54282
+ className: "h-full w-full",
54283
+ onLoad: postNavigationMessage
53682
54284
  }
53683
54285
  );
53684
- }
54286
+ },
54287
+ (prev, next) => prev.tab.id === next.tab.id && prev.tab.name === next.tab.name && prev.tab.type === next.tab.type && prev.tab.slideNumber === next.tab.slideNumber
53685
54288
  );
53686
54289
  AssetIframe.displayName = "AssetIframe";
53687
54290
  const PanelContent = ({
@@ -53739,7 +54342,7 @@ const PanelContent = ({
53739
54342
  }
53740
54343
  )
53741
54344
  ] }),
53742
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(AssetIframe, { tabId: tab.id, tabName: tab.name }) })
54345
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(AssetIframe, { tab }) })
53743
54346
  ]
53744
54347
  },
53745
54348
  tab.id
@@ -53749,7 +54352,7 @@ const PanelContent = ({
53749
54352
  "div",
53750
54353
  {
53751
54354
  className: isActive2 ? "h-full w-full" : "hidden",
53752
- children: /* @__PURE__ */ jsxRuntime.jsx(AssetIframe, { tabId: tab.id, tabName: tab.name })
54355
+ children: /* @__PURE__ */ jsxRuntime.jsx(AssetIframe, { tab })
53753
54356
  },
53754
54357
  tab.id
53755
54358
  );