@malette/agent-sdk 0.1.1-alpha.0 → 0.1.2

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.mjs CHANGED
@@ -4,7 +4,7 @@ import { create } from 'zustand';
4
4
  import { devtools } from 'zustand/middleware';
5
5
  import * as React20 from 'react';
6
6
  import React20__default, { memo, useState, useMemo, useEffect, createContext, useCallback, useRef, useImperativeHandle, useContext } from 'react';
7
- import { Loader2, Check, AlertCircle, ChevronUp, ChevronDown, ExternalLink, Download, Bot, Users, X, Copy, Image, Maximize2, Clock, Sparkles, AlertTriangle, Play, Pencil, Square, RotateCcw, SkipForward, FileText, Code2, FileJson, FileCode, CheckCheck, Eye, Zap, ChevronRight, Lightbulb, RefreshCw, Trash2, ImageIcon, GripVertical, Minimize2, Smartphone, Tablet, Monitor, Globe, PanelLeft, ArrowLeft, Settings, CheckCircle2, Brain, UserCheck, Shield, User, Plus, PanelLeftClose, Search, MessageSquare, ImagePlus, Send, HelpCircle, Lock, Calendar, Link, Share2, Wand2, LayoutGrid, Mic, CheckCircle, ListOrdered, Ban, Pause, Save, Tag, Folder, EyeOff, FileEdit, BookOpen, Edit, XCircle, ArrowRight } from 'lucide-react';
7
+ import { Loader2, Check, AlertCircle, ChevronUp, ChevronDown, ExternalLink, Download, Bot, Users, X, Copy, Image, Maximize2, Clock, Sparkles, AlertTriangle, Play, Pencil, Square, RotateCcw, SkipForward, FileText, Code2, FileJson, FileCode, CheckCheck, Eye, Video, Zap, ChevronRight, Lightbulb, RefreshCw, Trash2, ImageIcon, GripVertical, Minimize2, Smartphone, Tablet, Monitor, Globe, FileImage, ChevronLeft, LayoutGrid, Undo2, Redo2, Save, PanelLeft, ArrowLeft, Settings, CheckCircle2, Brain, UserCheck, Shield, User, Plus, PanelLeftClose, Search, MessageSquare, Unlink, ImagePlus, Send, HelpCircle, Lock, Calendar, Link, Share2, Wand2, Mic, CheckCircle, ListOrdered, Ban, Pause, Tag, Folder, EyeOff, FileEdit, BookOpen, Edit, XCircle, ArrowRight } from 'lucide-react';
8
8
  import ReactMarkdown from 'react-markdown';
9
9
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
10
10
  import { useShallow } from 'zustand/react/shallow';
@@ -12,6 +12,7 @@ import * as DialogPrimitive from '@radix-ui/react-dialog';
12
12
  import { Slot } from '@radix-ui/react-slot';
13
13
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
14
14
  import 'react-dom';
15
+ import { marked } from 'marked';
15
16
 
16
17
  // src/lib/fetch.ts
17
18
  async function fetcher(input, init, isServer = false) {
@@ -398,6 +399,52 @@ AI\u56DE\u590D\u6458\u8981\uFF1A${assistantMessage.slice(0, 200)}` : ""}`
398
399
  return userMessage.slice(0, 20) + (userMessage.length > 20 ? "..." : "");
399
400
  }
400
401
  }
402
+ var artifactService = {
403
+ /**
404
+ * 获取会话的所有产物列表
405
+ */
406
+ list: async (sessionId) => {
407
+ return fetcher(`${API_BASE}/sessions/${sessionId}/artifacts`);
408
+ },
409
+ /**
410
+ * 获取产物详情
411
+ */
412
+ get: async (artifactId) => {
413
+ return fetcher(`${API_BASE}/artifacts/${artifactId}`);
414
+ },
415
+ /**
416
+ * 更新产物内容(用户编辑后保存)
417
+ */
418
+ updateContent: async (artifactId, content) => {
419
+ return fetcher(`${API_BASE}/artifacts/${artifactId}/content`, {
420
+ method: "PUT",
421
+ body: JSON.stringify({ content })
422
+ });
423
+ },
424
+ /**
425
+ * 删除产物
426
+ */
427
+ delete: async (artifactId) => {
428
+ return fetcher(`${API_BASE}/artifacts/${artifactId}`, {
429
+ method: "DELETE"
430
+ });
431
+ },
432
+ /**
433
+ * 获取产物版本历史
434
+ */
435
+ getVersions: async (artifactId) => {
436
+ return fetcher(`${API_BASE}/artifacts/${artifactId}/versions`);
437
+ },
438
+ /**
439
+ * 回滚到指定版本
440
+ */
441
+ revert: async (artifactId, version) => {
442
+ return fetcher(`${API_BASE}/artifacts/${artifactId}/revert`, {
443
+ method: "POST",
444
+ body: JSON.stringify({ version })
445
+ });
446
+ }
447
+ };
401
448
  var shareService = {
402
449
  /**
403
450
  * 创建分享链接
@@ -786,6 +833,9 @@ var useAgentStore = create()(
786
833
  subAgents: [],
787
834
  tools: [],
788
835
  skills: [],
836
+ artifacts: {},
837
+ artifactOrder: [],
838
+ activeArtifactId: null,
789
839
  // ============ Session Actions ============
790
840
  setSessions: (sessions) => set({ sessions }, false, "setSessions"),
791
841
  setTools: (tools) => set({ tools }, false, "setTools"),
@@ -1150,19 +1200,99 @@ var useAgentStore = create()(
1150
1200
  false,
1151
1201
  "setActiveSubAgent"
1152
1202
  ),
1203
+ // ============ Artifact Actions ============
1204
+ upsertArtifact: (artifact) => set(
1205
+ (state) => {
1206
+ const isNew = !state.artifacts[artifact.id];
1207
+ return {
1208
+ artifacts: {
1209
+ ...state.artifacts,
1210
+ [artifact.id]: artifact
1211
+ },
1212
+ artifactOrder: isNew ? [...state.artifactOrder, artifact.id] : state.artifactOrder
1213
+ };
1214
+ },
1215
+ false,
1216
+ "upsertArtifact"
1217
+ ),
1218
+ updateArtifactContent: (artifactId, content, source) => set(
1219
+ (state) => {
1220
+ const existing = state.artifacts[artifactId];
1221
+ if (!existing) return state;
1222
+ return {
1223
+ artifacts: {
1224
+ ...state.artifacts,
1225
+ [artifactId]: {
1226
+ ...existing,
1227
+ currentContent: content,
1228
+ version: existing.version + 1,
1229
+ gmtModified: (/* @__PURE__ */ new Date()).toISOString()
1230
+ }
1231
+ }
1232
+ };
1233
+ },
1234
+ false,
1235
+ "updateArtifactContent"
1236
+ ),
1237
+ setActiveArtifact: (artifactId) => set(
1238
+ { activeArtifactId: artifactId },
1239
+ false,
1240
+ "setActiveArtifact"
1241
+ ),
1242
+ removeArtifact: (artifactId) => set(
1243
+ (state) => {
1244
+ const { [artifactId]: _, ...remaining } = state.artifacts;
1245
+ return {
1246
+ artifacts: remaining,
1247
+ artifactOrder: state.artifactOrder.filter((id) => id !== artifactId),
1248
+ activeArtifactId: state.activeArtifactId === artifactId ? null : state.activeArtifactId
1249
+ };
1250
+ },
1251
+ false,
1252
+ "removeArtifact"
1253
+ ),
1254
+ clearArtifacts: () => set(
1255
+ { artifacts: {}, artifactOrder: [], activeArtifactId: null },
1256
+ false,
1257
+ "clearArtifacts"
1258
+ ),
1259
+ setArtifacts: (artifacts) => set(
1260
+ {
1261
+ artifacts: artifacts.reduce((acc, a) => {
1262
+ acc[a.id] = a;
1263
+ return acc;
1264
+ }, {}),
1265
+ artifactOrder: artifacts.map((a) => a.id)
1266
+ },
1267
+ false,
1268
+ "setArtifacts"
1269
+ ),
1270
+ reorderArtifacts: (fromIndex, toIndex) => set(
1271
+ (state) => {
1272
+ const newOrder = [...state.artifactOrder];
1273
+ const [movedId] = newOrder.splice(fromIndex, 1);
1274
+ newOrder.splice(toIndex, 0, movedId);
1275
+ return { artifactOrder: newOrder };
1276
+ },
1277
+ false,
1278
+ "reorderArtifacts"
1279
+ ),
1153
1280
  // ============ 复合操作 ============
1154
1281
  startNewChat: (sessionId) => {
1155
1282
  set(
1156
1283
  (state) => ({
1157
1284
  messages: [],
1158
- chatUI: initialChatUIState
1285
+ chatUI: initialChatUIState,
1286
+ artifacts: {},
1287
+ artifactOrder: [],
1288
+ activeArtifactId: null
1159
1289
  }),
1160
1290
  false,
1161
1291
  "startNewChat"
1162
1292
  );
1163
1293
  },
1164
1294
  resetChatState: () => set(
1165
- { chatUI: initialChatUIState },
1295
+ { chatUI: initialChatUIState, artifacts: {}, artifactOrder: [], activeArtifactId: null },
1166
1296
  false,
1167
1297
  "resetChatState"
1168
1298
  )
@@ -1189,6 +1319,23 @@ var useCurrentSession = () => useAgentStore((state) => state.currentSession);
1189
1319
  var useSessions = () => useAgentStore((state) => state.sessions);
1190
1320
  var useSubAgents = () => useAgentStore((state) => state.subAgents);
1191
1321
  var useChatUI = () => useAgentStore((state) => state.chatUI);
1322
+ var useArtifacts = () => useAgentStore((state) => state.artifacts);
1323
+ var useActiveArtifactId = () => useAgentStore((state) => state.activeArtifactId);
1324
+ var useActiveArtifact = () => {
1325
+ const artifacts = useAgentStore((state) => state.artifacts);
1326
+ const activeId = useAgentStore((state) => state.activeArtifactId);
1327
+ return activeId ? artifacts[activeId] ?? null : null;
1328
+ };
1329
+ var useArtifactList = () => {
1330
+ const artifacts = useAgentStore((state) => state.artifacts);
1331
+ const artifactOrder = useAgentStore((state) => state.artifactOrder);
1332
+ const ordered = artifactOrder.map((id) => artifacts[id]).filter(Boolean);
1333
+ const unordered = Object.values(artifacts).filter(
1334
+ (a) => !artifactOrder.includes(a.id)
1335
+ );
1336
+ return [...ordered, ...unordered];
1337
+ };
1338
+ var useArtifactOrder = () => useAgentStore((state) => state.artifactOrder);
1192
1339
  var useSessionsLoading = () => useAgentStore((state) => state.sessionsLoading);
1193
1340
  var findMessageById = (messageId) => {
1194
1341
  return useAgentStore.getState().messages.find((m) => m.messageId === messageId);
@@ -1377,7 +1524,11 @@ function useSSE(options) {
1377
1524
  setShowPlanConfirmDialog,
1378
1525
  setShowHumanInputDialog,
1379
1526
  setWaitingStepId,
1380
- clearPlanState
1527
+ clearPlanState,
1528
+ // Artifact actions
1529
+ upsertArtifact,
1530
+ updateArtifactContent,
1531
+ setActiveArtifact
1381
1532
  } = useAgentStore();
1382
1533
  const clearHeartbeatTimeout = useCallback(() => {
1383
1534
  if (heartbeatTimeoutRef.current) {
@@ -1575,6 +1726,37 @@ function useSSE(options) {
1575
1726
  });
1576
1727
  return;
1577
1728
  }
1729
+ if (eventType === "artifact_created") {
1730
+ const sessionId = useAgentStore.getState().currentSession?.sessionId;
1731
+ if (data.artifactId && sessionId) {
1732
+ const artifactType = data.type || "code";
1733
+ const artifactEntry = {
1734
+ id: data.artifactId,
1735
+ sessionId,
1736
+ type: artifactType,
1737
+ title: data.title || "Untitled",
1738
+ currentContent: data.content || "",
1739
+ language: data.language,
1740
+ version: 1,
1741
+ source: "tool",
1742
+ sourceId: data.sourceToolCallId,
1743
+ metadata: data.metadata,
1744
+ gmtCreate: (/* @__PURE__ */ new Date()).toISOString(),
1745
+ gmtModified: (/* @__PURE__ */ new Date()).toISOString()
1746
+ };
1747
+ upsertArtifact(artifactEntry);
1748
+ setActiveArtifact(data.artifactId);
1749
+ console.log("[SSE] Artifact created:", data.artifactId, data.title);
1750
+ }
1751
+ return;
1752
+ }
1753
+ if (eventType === "artifact_updated") {
1754
+ if (data.artifactId && data.content) {
1755
+ updateArtifactContent(data.artifactId, data.content, "ai");
1756
+ console.log("[SSE] Artifact updated:", data.artifactId, "version:", data.version);
1757
+ }
1758
+ return;
1759
+ }
1578
1760
  const rawToolCalls = data.toolCalls || data.tool_calls || data.actions || [];
1579
1761
  const normalizedToolCalls = rawToolCalls.length > 0 ? normalizeToolCalls2(rawToolCalls) : void 0;
1580
1762
  let finalToolCalls = normalizedToolCalls;
@@ -2280,7 +2462,7 @@ function useSSE(options) {
2280
2462
  try {
2281
2463
  console.log("[SSE] Step 1: Sending message...");
2282
2464
  const response = await messageService.sendStream(
2283
- { sessionId, content, frontendTools: sendOptions?.frontendTools },
2465
+ { sessionId, content, frontendTools: sendOptions?.frontendTools, artifactContext: sendOptions?.artifactContext },
2284
2466
  abortControllerRef.current.signal
2285
2467
  );
2286
2468
  const reader = response.body?.getReader();
@@ -2420,6 +2602,92 @@ function useSSE(options) {
2420
2602
  isConnected
2421
2603
  };
2422
2604
  }
2605
+ var CHANNEL_ID = "adic-agent-canvas-bridge";
2606
+ function useCanvasBridge(options = {}) {
2607
+ const {
2608
+ canvasIframeRef,
2609
+ targetOrigin = "*",
2610
+ enabled = false,
2611
+ onArtifactSelected,
2612
+ onArtifactContentChanged
2613
+ } = options;
2614
+ const optionsRef = useRef(options);
2615
+ optionsRef.current = options;
2616
+ const postToCanvas = useCallback((type, payload) => {
2617
+ const iframe = canvasIframeRef?.current;
2618
+ if (!iframe?.contentWindow) {
2619
+ console.warn("[CanvasBridge] Canvas iframe not available");
2620
+ return;
2621
+ }
2622
+ const envelope = {
2623
+ channel: CHANNEL_ID,
2624
+ message: {
2625
+ type,
2626
+ payload,
2627
+ timestamp: Date.now()
2628
+ }
2629
+ };
2630
+ iframe.contentWindow.postMessage(envelope, targetOrigin);
2631
+ console.log("[CanvasBridge] Sent:", type, payload.artifactId || payload.artifact?.id);
2632
+ }, [canvasIframeRef, targetOrigin]);
2633
+ useEffect(() => {
2634
+ if (!enabled) return;
2635
+ const handleMessage = (event) => {
2636
+ if (targetOrigin !== "*" && event.origin !== targetOrigin) return;
2637
+ const envelope = event.data;
2638
+ if (!envelope || envelope.channel !== CHANNEL_ID) return;
2639
+ const { type, payload } = envelope.message;
2640
+ console.log("[CanvasBridge] Received:", type, payload);
2641
+ switch (type) {
2642
+ case "artifact_selected": {
2643
+ if (payload.artifactId) {
2644
+ optionsRef.current.onArtifactSelected?.(payload.artifactId);
2645
+ useAgentStore.getState().setActiveArtifact(payload.artifactId);
2646
+ }
2647
+ break;
2648
+ }
2649
+ case "artifact_content_changed": {
2650
+ if (payload.artifactId && payload.content !== void 0) {
2651
+ optionsRef.current.onArtifactContentChanged?.(payload.artifactId, payload.content);
2652
+ useAgentStore.getState().updateArtifactContent(
2653
+ payload.artifactId,
2654
+ payload.content,
2655
+ "user"
2656
+ );
2657
+ }
2658
+ break;
2659
+ }
2660
+ default:
2661
+ console.log("[CanvasBridge] Unknown message type:", type);
2662
+ }
2663
+ };
2664
+ window.addEventListener("message", handleMessage);
2665
+ return () => window.removeEventListener("message", handleMessage);
2666
+ }, [enabled, targetOrigin]);
2667
+ const notifyArtifactCreated = useCallback((artifact) => {
2668
+ if (!enabled) return;
2669
+ postToCanvas("artifact_created", { artifact });
2670
+ }, [enabled, postToCanvas]);
2671
+ const notifyArtifactUpdated = useCallback((artifact) => {
2672
+ if (!enabled) return;
2673
+ postToCanvas("artifact_updated", { artifact });
2674
+ }, [enabled, postToCanvas]);
2675
+ const notifyArtifactDeleted = useCallback((artifactId) => {
2676
+ if (!enabled) return;
2677
+ postToCanvas("artifact_deleted", { artifactId });
2678
+ }, [enabled, postToCanvas]);
2679
+ const syncAllArtifacts = useCallback(() => {
2680
+ if (!enabled) return;
2681
+ const artifacts = Object.values(useAgentStore.getState().artifacts);
2682
+ postToCanvas("artifacts_sync", { artifacts });
2683
+ }, [enabled, postToCanvas]);
2684
+ return {
2685
+ notifyArtifactCreated,
2686
+ notifyArtifactUpdated,
2687
+ notifyArtifactDeleted,
2688
+ syncAllArtifacts
2689
+ };
2690
+ }
2423
2691
 
2424
2692
  // src/hooks/sseConnection.ts
2425
2693
  var SSE_HEARTBEAT_TIMEOUT2 = 45e3;
@@ -2882,14 +3150,14 @@ function getParamsSummary(params, maxItems = 2) {
2882
3150
  }
2883
3151
  function generateToolCallDescription(toolName, params) {
2884
3152
  const formatted = formatParameters(params);
2885
- const prompt = formatted.find((p) => p.key === "prompt" || p.key === "query" || p.key === "content");
3153
+ const prompt2 = formatted.find((p) => p.key === "prompt" || p.key === "query" || p.key === "content");
2886
3154
  const image2 = formatted.find((p) => p.key === "image" || p.key === "image_url" || p.key === "imageUrl");
2887
3155
  const style = formatted.find((p) => p.key === "style");
2888
3156
  formatted.find((p) => p.key === "width" || p.key === "size");
2889
3157
  const toolLower = toolName.toLowerCase();
2890
3158
  if (toolLower.includes("generate") || toolLower.includes("image") || toolLower.includes("art")) {
2891
- if (prompt) {
2892
- return `\u751F\u6210\u56FE\u50CF\uFF1A${prompt.displayValue.slice(0, 50)}${prompt.displayValue.length > 50 ? "..." : ""}`;
3159
+ if (prompt2) {
3160
+ return `\u751F\u6210\u56FE\u50CF\uFF1A${prompt2.displayValue.slice(0, 50)}${prompt2.displayValue.length > 50 ? "..." : ""}`;
2893
3161
  }
2894
3162
  if (style) {
2895
3163
  return `\u751F\u6210 ${style.displayValue} \u98CE\u683C\u7684\u56FE\u50CF`;
@@ -2897,14 +3165,14 @@ function generateToolCallDescription(toolName, params) {
2897
3165
  return "\u751F\u6210\u56FE\u50CF";
2898
3166
  }
2899
3167
  if (toolLower.includes("search") || toolLower.includes("query")) {
2900
- if (prompt) {
2901
- return `\u641C\u7D22\uFF1A${prompt.displayValue}`;
3168
+ if (prompt2) {
3169
+ return `\u641C\u7D22\uFF1A${prompt2.displayValue}`;
2902
3170
  }
2903
3171
  return "\u6267\u884C\u641C\u7D22";
2904
3172
  }
2905
3173
  if (toolLower.includes("translate")) {
2906
- if (prompt) {
2907
- return `\u7FFB\u8BD1\uFF1A${prompt.displayValue.slice(0, 30)}...`;
3174
+ if (prompt2) {
3175
+ return `\u7FFB\u8BD1\uFF1A${prompt2.displayValue.slice(0, 30)}...`;
2908
3176
  }
2909
3177
  return "\u6267\u884C\u7FFB\u8BD1";
2910
3178
  }
@@ -2914,8 +3182,8 @@ function generateToolCallDescription(toolName, params) {
2914
3182
  }
2915
3183
  return "\u6267\u884C\u5206\u6790";
2916
3184
  }
2917
- if (prompt) {
2918
- return prompt.displayValue.slice(0, 60) + (prompt.displayValue.length > 60 ? "..." : "");
3185
+ if (prompt2) {
3186
+ return prompt2.displayValue.slice(0, 60) + (prompt2.displayValue.length > 60 ? "..." : "");
2919
3187
  }
2920
3188
  const paramCount = formatted.length;
2921
3189
  if (paramCount === 0) {
@@ -6910,7 +7178,6 @@ var createAssetFromSource = (options) => {
6910
7178
  var resolveAssetForDisplay = async (asset, config) => {
6911
7179
  let working = asset;
6912
7180
  const strategy = config?.asset;
6913
- console.log("Resolving asset for display:", asset, "with strategy:", strategy);
6914
7181
  if (strategy?.resolve && !working.url) {
6915
7182
  working = await strategy.resolve(working);
6916
7183
  }
@@ -6925,6 +7192,9 @@ var resolveAssetForDisplay = async (asset, config) => {
6925
7192
  if (resolved) return resolved;
6926
7193
  }
6927
7194
  if (working.url) {
7195
+ if (working.url.includes("industryai")) {
7196
+ working.url = working.url.split("?")[0];
7197
+ }
6928
7198
  return {
6929
7199
  url: working.url,
6930
7200
  hdUrl: working.url,
@@ -6934,7 +7204,7 @@ var resolveAssetForDisplay = async (asset, config) => {
6934
7204
  return null;
6935
7205
  };
6936
7206
 
6937
- // ../../node_modules/clsx/dist/clsx.mjs
7207
+ // node_modules/clsx/dist/clsx.mjs
6938
7208
  function r(e) {
6939
7209
  var t, f, n = "";
6940
7210
  if ("string" == typeof e || "number" == typeof e) n += e;
@@ -10543,7 +10813,7 @@ var MessageImageInternal = memo(function MessageImageInternal2({ src, alt, class
10543
10813
  /* @__PURE__ */ jsx("span", { children: "\u56FE\u7247\u52A0\u8F7D\u5931\u8D25" })
10544
10814
  ] });
10545
10815
  }
10546
- return /* @__PURE__ */ jsxs("div", { className: "relative cursor-pointer overflow-hidden rounded-lg my-2", children: [
10816
+ return /* @__PURE__ */ jsxs("div", { className: "relative inline-block max-w-full overflow-hidden rounded-lg my-2", children: [
10547
10817
  previewUrl && /* @__PURE__ */ jsx(
10548
10818
  ImagePreviewComp,
10549
10819
  {
@@ -10551,7 +10821,7 @@ var MessageImageInternal = memo(function MessageImageInternal2({ src, alt, class
10551
10821
  onClose: () => setPreviewUrl(null)
10552
10822
  }
10553
10823
  ),
10554
- !loaded && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-zinc-800 animate-pulse rounded-lg", style: { minHeight: "100px" } }),
10824
+ !loaded && /* @__PURE__ */ jsx("div", { className: "bg-zinc-800 animate-pulse rounded-lg", style: { minHeight: "100px", minWidth: "150px" } }),
10555
10825
  /* @__PURE__ */ jsx(
10556
10826
  "img",
10557
10827
  {
@@ -10561,23 +10831,284 @@ var MessageImageInternal = memo(function MessageImageInternal2({ src, alt, class
10561
10831
  onLoad: handleLoad,
10562
10832
  onError: handleError,
10563
10833
  onClick: () => setPreviewUrl(src),
10564
- className: cn("rounded-lg cursor-zoom-in", className, !loaded && "opacity-0"),
10565
- style: { maxHeight: "400px" }
10834
+ className: cn(
10835
+ "rounded-lg cursor-zoom-in max-w-full h-auto block",
10836
+ className,
10837
+ !loaded && "opacity-0 absolute"
10838
+ ),
10839
+ style: { maxHeight: "400px", objectFit: "contain" }
10566
10840
  }
10567
10841
  )
10568
10842
  ] });
10569
10843
  });
10570
10844
  var MessageVideoInternal = memo(function MessageVideoInternal2({ src, className }) {
10571
- return /* @__PURE__ */ jsx("div", { className: "my-2 relative rounded-lg overflow-hidden bg-zinc-900 border border-zinc-800", children: /* @__PURE__ */ jsx(
10572
- "video",
10573
- {
10574
- src,
10575
- controls: true,
10576
- className: cn("max-w-full rounded-lg max-h-[400px] w-full", className),
10577
- preload: "metadata",
10578
- children: "\u60A8\u7684\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u89C6\u9891\u64AD\u653E"
10845
+ const videoRef = React20__default.useRef(null);
10846
+ const canvasRef = React20__default.useRef(null);
10847
+ const [posterUrl, setPosterUrl] = useState(null);
10848
+ const [isHovering, setIsHovering] = useState(false);
10849
+ const [isPlaying, setIsPlaying] = useState(false);
10850
+ const [isMuted, setIsMuted] = useState(true);
10851
+ const [duration, setDuration] = useState(0);
10852
+ const [currentTime, setCurrentTime] = useState(0);
10853
+ const [isFullPlaying, setIsFullPlaying] = useState(false);
10854
+ const hoverTimerRef = React20__default.useRef(null);
10855
+ const VideoPreviewComp = useComponent("VideoPreview") || VideoPreviewInternal;
10856
+ const [showPreview, setShowPreview] = useState(false);
10857
+ useEffect(() => {
10858
+ const video = document.createElement("video");
10859
+ video.crossOrigin = "anonymous";
10860
+ video.preload = "metadata";
10861
+ video.muted = true;
10862
+ video.addEventListener("loadeddata", () => {
10863
+ video.currentTime = Math.min(0.5, video.duration * 0.1);
10864
+ });
10865
+ video.addEventListener("seeked", () => {
10866
+ try {
10867
+ const canvas = document.createElement("canvas");
10868
+ canvas.width = video.videoWidth;
10869
+ canvas.height = video.videoHeight;
10870
+ const ctx = canvas.getContext("2d");
10871
+ if (ctx) {
10872
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
10873
+ const dataUrl = canvas.toDataURL("image/jpeg", 0.8);
10874
+ setPosterUrl(dataUrl);
10875
+ }
10876
+ } catch {
10877
+ }
10878
+ video.remove();
10879
+ });
10880
+ video.addEventListener("error", () => {
10881
+ video.remove();
10882
+ });
10883
+ video.src = src;
10884
+ video.load();
10885
+ return () => {
10886
+ video.remove();
10887
+ };
10888
+ }, [src]);
10889
+ const handleLoadedMetadata = () => {
10890
+ const video = videoRef.current;
10891
+ if (video) {
10892
+ setDuration(video.duration);
10579
10893
  }
10580
- ) });
10894
+ };
10895
+ const handleTimeUpdate = () => {
10896
+ const video = videoRef.current;
10897
+ if (video) {
10898
+ setCurrentTime(video.currentTime);
10899
+ }
10900
+ };
10901
+ const handleMouseEnter = () => {
10902
+ setIsHovering(true);
10903
+ if (isFullPlaying) return;
10904
+ hoverTimerRef.current = setTimeout(() => {
10905
+ const video = videoRef.current;
10906
+ if (video) {
10907
+ video.muted = true;
10908
+ video.currentTime = 0;
10909
+ video.play().then(() => setIsPlaying(true)).catch(() => {
10910
+ });
10911
+ }
10912
+ }, 300);
10913
+ };
10914
+ const handleMouseLeave = () => {
10915
+ setIsHovering(false);
10916
+ if (hoverTimerRef.current) {
10917
+ clearTimeout(hoverTimerRef.current);
10918
+ hoverTimerRef.current = null;
10919
+ }
10920
+ if (!isFullPlaying) {
10921
+ const video = videoRef.current;
10922
+ if (video) {
10923
+ video.pause();
10924
+ video.currentTime = 0;
10925
+ setIsPlaying(false);
10926
+ }
10927
+ }
10928
+ };
10929
+ const handleClick = (e) => {
10930
+ e.stopPropagation();
10931
+ const video = videoRef.current;
10932
+ if (!video) return;
10933
+ if (isFullPlaying) {
10934
+ video.pause();
10935
+ setIsPlaying(false);
10936
+ setIsFullPlaying(false);
10937
+ } else {
10938
+ video.muted = isMuted;
10939
+ video.play().then(() => {
10940
+ setIsPlaying(true);
10941
+ setIsFullPlaying(true);
10942
+ }).catch(() => {
10943
+ });
10944
+ }
10945
+ };
10946
+ const handleToggleMute = (e) => {
10947
+ e.stopPropagation();
10948
+ const video = videoRef.current;
10949
+ if (video) {
10950
+ video.muted = !isMuted;
10951
+ setIsMuted(!isMuted);
10952
+ }
10953
+ };
10954
+ const handleProgressClick = (e) => {
10955
+ e.stopPropagation();
10956
+ const video = videoRef.current;
10957
+ if (!video || !duration) return;
10958
+ const rect = e.currentTarget.getBoundingClientRect();
10959
+ const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
10960
+ video.currentTime = ratio * duration;
10961
+ setCurrentTime(ratio * duration);
10962
+ };
10963
+ const formatTime2 = (seconds) => {
10964
+ const mins = Math.floor(seconds / 60);
10965
+ const secs = Math.floor(seconds % 60);
10966
+ return `${mins}:${secs.toString().padStart(2, "0")}`;
10967
+ };
10968
+ const progressPercent = duration > 0 ? currentTime / duration * 100 : 0;
10969
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
10970
+ showPreview && /* @__PURE__ */ jsx(VideoPreviewComp, { src, onClose: () => setShowPreview(false) }),
10971
+ /* @__PURE__ */ jsxs(
10972
+ "div",
10973
+ {
10974
+ className: cn(
10975
+ "my-2 relative rounded-xl overflow-hidden bg-black group/video cursor-pointer",
10976
+ "border border-zinc-800/60 agent-sdk-light:border-zinc-200",
10977
+ "transition-shadow duration-200 hover:shadow-xl hover:shadow-black/20",
10978
+ className
10979
+ ),
10980
+ style: { maxHeight: "400px", maxWidth: "100%" },
10981
+ onMouseEnter: handleMouseEnter,
10982
+ onMouseLeave: handleMouseLeave,
10983
+ onClick: handleClick,
10984
+ children: [
10985
+ posterUrl && !isPlaying && /* @__PURE__ */ jsx(
10986
+ "img",
10987
+ {
10988
+ src: posterUrl,
10989
+ alt: "Video cover",
10990
+ className: "absolute inset-0 w-full h-full object-contain z-[1]"
10991
+ }
10992
+ ),
10993
+ /* @__PURE__ */ jsx(
10994
+ "video",
10995
+ {
10996
+ ref: videoRef,
10997
+ src,
10998
+ muted: isMuted,
10999
+ playsInline: true,
11000
+ preload: "metadata",
11001
+ onLoadedMetadata: handleLoadedMetadata,
11002
+ onTimeUpdate: handleTimeUpdate,
11003
+ onEnded: () => {
11004
+ setIsPlaying(false);
11005
+ setIsFullPlaying(false);
11006
+ },
11007
+ className: cn(
11008
+ "w-full max-h-[400px] object-contain",
11009
+ !isPlaying && posterUrl && "opacity-0"
11010
+ )
11011
+ }
11012
+ ),
11013
+ /* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "hidden" }),
11014
+ !isFullPlaying && /* @__PURE__ */ jsx("div", { className: cn(
11015
+ "absolute inset-0 z-[2] flex items-center justify-center",
11016
+ "bg-gradient-to-t from-black/50 via-transparent to-transparent",
11017
+ "transition-opacity duration-200",
11018
+ isHovering && isPlaying ? "opacity-0" : "opacity-100"
11019
+ ), children: /* @__PURE__ */ jsx("div", { className: cn(
11020
+ "w-14 h-14 rounded-full bg-white/20 backdrop-blur-md",
11021
+ "flex items-center justify-center",
11022
+ "transition-all duration-200",
11023
+ "group-hover/video:scale-110 group-hover/video:bg-white/30",
11024
+ "shadow-lg shadow-black/20"
11025
+ ), children: /* @__PURE__ */ jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "white", className: "ml-1", children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" }) }) }) }),
11026
+ /* @__PURE__ */ jsxs("div", { className: cn(
11027
+ "absolute bottom-0 left-0 right-0 z-[3]",
11028
+ "bg-gradient-to-t from-black/80 via-black/40 to-transparent",
11029
+ "px-3 pb-2.5 pt-8",
11030
+ "transition-opacity duration-200",
11031
+ isHovering || isFullPlaying ? "opacity-100" : "opacity-0"
11032
+ ), children: [
11033
+ /* @__PURE__ */ jsx(
11034
+ "div",
11035
+ {
11036
+ className: "w-full h-1 bg-white/20 rounded-full mb-2 cursor-pointer group/progress",
11037
+ onClick: handleProgressClick,
11038
+ children: /* @__PURE__ */ jsx(
11039
+ "div",
11040
+ {
11041
+ className: "h-full bg-[#d8ff00] rounded-full relative transition-all duration-75",
11042
+ style: { width: `${progressPercent}%` },
11043
+ children: /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 w-3 h-3 bg-[#d8ff00] rounded-full opacity-0 group-hover/progress:opacity-100 transition-opacity shadow-md" })
11044
+ }
11045
+ )
11046
+ }
11047
+ ),
11048
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
11049
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
11050
+ /* @__PURE__ */ jsx(
11051
+ "button",
11052
+ {
11053
+ onClick: handleClick,
11054
+ className: "p-1 text-white/80 hover:text-white transition-colors",
11055
+ children: isPlaying ? /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: [
11056
+ /* @__PURE__ */ jsx("rect", { x: "6", y: "4", width: "4", height: "16", rx: "1" }),
11057
+ /* @__PURE__ */ jsx("rect", { x: "14", y: "4", width: "4", height: "16", rx: "1" })
11058
+ ] }) : /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" }) })
11059
+ }
11060
+ ),
11061
+ /* @__PURE__ */ jsx(
11062
+ "button",
11063
+ {
11064
+ onClick: handleToggleMute,
11065
+ className: "p-1 text-white/80 hover:text-white transition-colors",
11066
+ children: isMuted ? /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
11067
+ /* @__PURE__ */ jsx("polygon", { points: "11 5 6 9 2 9 2 15 6 15 11 19 11 5" }),
11068
+ /* @__PURE__ */ jsx("line", { x1: "23", y1: "9", x2: "17", y2: "15" }),
11069
+ /* @__PURE__ */ jsx("line", { x1: "17", y1: "9", x2: "23", y2: "15" })
11070
+ ] }) : /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
11071
+ /* @__PURE__ */ jsx("polygon", { points: "11 5 6 9 2 9 2 15 6 15 11 19 11 5" }),
11072
+ /* @__PURE__ */ jsx("path", { d: "M19.07 4.93a10 10 0 0 1 0 14.14" }),
11073
+ /* @__PURE__ */ jsx("path", { d: "M15.54 8.46a5 5 0 0 1 0 7.07" })
11074
+ ] })
11075
+ }
11076
+ ),
11077
+ /* @__PURE__ */ jsxs("span", { className: "text-[11px] text-white/60 font-mono tabular-nums", children: [
11078
+ formatTime2(currentTime),
11079
+ " / ",
11080
+ formatTime2(duration)
11081
+ ] })
11082
+ ] }),
11083
+ /* @__PURE__ */ jsx(
11084
+ "button",
11085
+ {
11086
+ onClick: (e) => {
11087
+ e.stopPropagation();
11088
+ const video = videoRef.current;
11089
+ if (video) {
11090
+ video.pause();
11091
+ setIsPlaying(false);
11092
+ setIsFullPlaying(false);
11093
+ }
11094
+ setShowPreview(true);
11095
+ },
11096
+ className: "p-1 text-white/60 hover:text-white transition-colors",
11097
+ title: "\u5168\u5C4F\u9884\u89C8",
11098
+ children: /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
11099
+ /* @__PURE__ */ jsx("polyline", { points: "15 3 21 3 21 9" }),
11100
+ /* @__PURE__ */ jsx("polyline", { points: "9 21 3 21 3 15" }),
11101
+ /* @__PURE__ */ jsx("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
11102
+ /* @__PURE__ */ jsx("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
11103
+ ] })
11104
+ }
11105
+ )
11106
+ ] })
11107
+ ] })
11108
+ ]
11109
+ }
11110
+ )
11111
+ ] });
10581
11112
  });
10582
11113
  var ImagePreviewInternal = memo(function ImagePreviewInternal2({
10583
11114
  src,
@@ -12223,6 +12754,7 @@ var ToolResultRenderer = memo(function ToolResultRenderer2({
12223
12754
  result,
12224
12755
  mediaUrls,
12225
12756
  config,
12757
+ toolCallData,
12226
12758
  onOpenArtifact
12227
12759
  }) {
12228
12760
  const [imgLoaded, setImgLoaded] = useState({});
@@ -12289,32 +12821,134 @@ var ToolResultRenderer = memo(function ToolResultRenderer2({
12289
12821
  }
12290
12822
  ),
12291
12823
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
12292
- hasMedia && /* @__PURE__ */ jsxs("div", { className: "p-2", children: [
12293
- videoUrls.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-2 mb-2", children: videoUrls.map((video, i) => /* @__PURE__ */ jsx("div", { className: "relative rounded-lg overflow-hidden bg-black", children: /* @__PURE__ */ jsx(
12294
- "video",
12295
- {
12296
- src: video.url,
12297
- controls: true,
12298
- className: "w-full max-h-60 object-contain",
12299
- preload: "metadata",
12300
- children: "\u60A8\u7684\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u89C6\u9891\u64AD\u653E"
12824
+ hasMedia && /* @__PURE__ */ jsx("div", { className: "p-2", children: (() => {
12825
+ const totalMedia = imageUrls.length + videoUrls.length;
12826
+ const isMultiple = totalMedia > 1;
12827
+ const buildMediaMetadata = (mediaIndex) => {
12828
+ if (!toolCallData) return void 0;
12829
+ const resultAny = toolCallData.result;
12830
+ const metadata = {};
12831
+ if (toolCallData.name) metadata.toolName = toolCallData.name;
12832
+ if (resultAny?.relation?.toolName) metadata.toolName = resultAny.relation.toolName;
12833
+ if (toolCallData.arguments) metadata.generationParams = toolCallData.arguments;
12834
+ if (resultAny?.relation) metadata.relation = resultAny.relation;
12835
+ if (resultAny?.taskId) metadata.taskId = resultAny.taskId;
12836
+ const work = resultAny?.works?.[mediaIndex];
12837
+ if (work) {
12838
+ if (work.publicId) metadata.workId = work.publicId;
12839
+ if (work.fileId) metadata.fileId = work.fileId;
12301
12840
  }
12302
- ) }, `video-${i}`)) }),
12303
- imageUrls.length > 0 && /* @__PURE__ */ jsx("div", { children: imageUrls.map((img, i) => /* @__PURE__ */ jsxs("div", { className: `relative group/img overflow-hidden ${imageUrls.length > 1 ? "aspect-square bg-black" : ""}`, children: [
12304
- !imgLoaded[i] && /* @__PURE__ */ jsx("div", { className: `bg-zinc-800 animate-pulse flex items-center justify-center`, children: /* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-5 w-5 border-b-2 border-[#d8ff00]" }) }),
12305
- /* @__PURE__ */ jsx(
12306
- "img",
12841
+ return metadata;
12842
+ };
12843
+ return /* @__PURE__ */ jsxs("div", { className: isMultiple ? "grid grid-cols-2 gap-2" : "flex", children: [
12844
+ videoUrls.map((video, i) => /* @__PURE__ */ jsxs(
12845
+ "div",
12307
12846
  {
12308
- src: img.url,
12309
- alt: "Generated",
12310
- onLoad: () => handleImgLoad(i),
12311
- className: `cursor-zoom-in ${imgLoaded[i] ? "" : "hidden"}`,
12312
- onClick: () => setPreviewUrl(img.hdUrl),
12313
- style: { height: 80 }
12314
- }
12315
- )
12316
- ] }, `img-${i}`)) })
12317
- ] }),
12847
+ className: `relative group/media overflow-hidden rounded-lg bg-black ${isMultiple ? "aspect-square" : "max-h-[375px]"}`,
12848
+ children: [
12849
+ /* @__PURE__ */ jsx(
12850
+ MessageVideoInternal,
12851
+ {
12852
+ src: video.hdUrl || video.url,
12853
+ className: isMultiple ? "w-full h-full object-cover" : "max-h-[375px] max-w-full object-contain"
12854
+ }
12855
+ ),
12856
+ /* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover/media:opacity-100 transition-opacity duration-200 flex items-center justify-between z-[10]", children: [
12857
+ onOpenArtifact && /* @__PURE__ */ jsxs(
12858
+ "button",
12859
+ {
12860
+ onClick: (e) => {
12861
+ e.stopPropagation();
12862
+ const resultAny = toolCallData?.result;
12863
+ const displayName = resultAny?.relation?.toolName || toolCallData?.name || "\u89C6\u9891\u751F\u6210";
12864
+ onOpenArtifact({
12865
+ type: "video",
12866
+ title: `${displayName} #${i + 1}`,
12867
+ content: video.hdUrl || video.url,
12868
+ metadata: buildMediaMetadata(imageUrls.length + i)
12869
+ });
12870
+ },
12871
+ className: "flex items-center gap-1.5 px-2.5 py-1.5 text-[11px] font-medium text-white bg-white/15 hover:bg-white/25 backdrop-blur-sm rounded-md transition-colors",
12872
+ children: [
12873
+ /* @__PURE__ */ jsx(Sparkles, { size: 12 }),
12874
+ "\u67E5\u770B\u8BE6\u60C5"
12875
+ ]
12876
+ }
12877
+ ),
12878
+ /* @__PURE__ */ jsx(
12879
+ "button",
12880
+ {
12881
+ onClick: (e) => {
12882
+ e.stopPropagation();
12883
+ window.open(video.hdUrl || video.url, "_blank");
12884
+ },
12885
+ className: "p-1.5 text-white/80 hover:text-white bg-white/15 hover:bg-white/25 backdrop-blur-sm rounded-md transition-colors",
12886
+ title: "\u65B0\u7A97\u53E3\u6253\u5F00",
12887
+ children: /* @__PURE__ */ jsx(Video, { size: 14 })
12888
+ }
12889
+ )
12890
+ ] })
12891
+ ]
12892
+ },
12893
+ `video-${i}`
12894
+ )),
12895
+ imageUrls.map((img, i) => /* @__PURE__ */ jsxs(
12896
+ "div",
12897
+ {
12898
+ className: `relative group/media overflow-hidden rounded-lg bg-black ${isMultiple ? "aspect-square" : "max-h-[375px]"}`,
12899
+ children: [
12900
+ !imgLoaded[i] && /* @__PURE__ */ jsx("div", { className: "bg-zinc-800 animate-pulse flex items-center justify-center w-full aspect-square", children: /* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-5 w-5 border-b-2 border-[#d8ff00]" }) }),
12901
+ /* @__PURE__ */ jsx(
12902
+ "img",
12903
+ {
12904
+ src: img.url,
12905
+ alt: "Generated",
12906
+ onLoad: () => handleImgLoad(i),
12907
+ className: `cursor-zoom-in ${imgLoaded[i] ? "" : "hidden"} ${isMultiple ? "w-full h-full object-cover" : "max-h-[375px] max-w-full h-auto object-contain"}`,
12908
+ onClick: () => setPreviewUrl(img.hdUrl)
12909
+ }
12910
+ ),
12911
+ imgLoaded[i] && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover/media:opacity-100 transition-opacity duration-200 flex items-center justify-between", children: [
12912
+ onOpenArtifact && /* @__PURE__ */ jsxs(
12913
+ "button",
12914
+ {
12915
+ onClick: (e) => {
12916
+ e.stopPropagation();
12917
+ const resultAny = toolCallData?.result;
12918
+ const displayName = resultAny?.relation?.toolName || toolCallData?.name || "\u56FE\u7247\u751F\u6210";
12919
+ onOpenArtifact({
12920
+ type: "image",
12921
+ title: `${displayName} #${i + 1}`,
12922
+ content: img.hdUrl || img.url,
12923
+ metadata: buildMediaMetadata(i)
12924
+ });
12925
+ },
12926
+ className: "flex items-center gap-1.5 px-2.5 py-1.5 text-[11px] font-medium text-white bg-white/15 hover:bg-white/25 backdrop-blur-sm rounded-md transition-colors",
12927
+ children: [
12928
+ /* @__PURE__ */ jsx(Sparkles, { size: 12 }),
12929
+ "\u67E5\u770B\u8BE6\u60C5"
12930
+ ]
12931
+ }
12932
+ ),
12933
+ /* @__PURE__ */ jsx(
12934
+ "button",
12935
+ {
12936
+ onClick: (e) => {
12937
+ e.stopPropagation();
12938
+ setPreviewUrl(img.hdUrl);
12939
+ },
12940
+ className: "p-1.5 text-white/80 hover:text-white bg-white/15 hover:bg-white/25 backdrop-blur-sm rounded-md transition-colors",
12941
+ title: "\u653E\u5927\u9884\u89C8",
12942
+ children: /* @__PURE__ */ jsx(Image, { size: 14 })
12943
+ }
12944
+ )
12945
+ ] })
12946
+ ]
12947
+ },
12948
+ `img-${i}`
12949
+ ))
12950
+ ] });
12951
+ })() }),
12318
12952
  hasCustomResponses && customResult
12319
12953
  ] })
12320
12954
  ] });
@@ -12440,6 +13074,7 @@ var ToolCallCard3 = memo(function ToolCallCard4({
12440
13074
  result: toolCall.result,
12441
13075
  mediaUrls,
12442
13076
  config,
13077
+ toolCallData: toolCall,
12443
13078
  defaultExpanded: false,
12444
13079
  onOpenArtifact
12445
13080
  }
@@ -12710,7 +13345,7 @@ var ComponentPendingCard = memo(function ComponentPendingCard2({
12710
13345
  })() })
12711
13346
  ] });
12712
13347
  });
12713
- var ThoughtTimelineCard = memo(function ThoughtTimelineCard2({ thought, config, isLoading = false }) {
13348
+ var ThoughtTimelineCard = memo(function ThoughtTimelineCard2({ thought, config, isLoading = false, skipImages = false }) {
12714
13349
  const [expanded, setExpanded] = useState(true);
12715
13350
  const { showItemTime } = useAgentStore();
12716
13351
  const thoughtType = thought?.type || "";
@@ -12734,9 +13369,9 @@ var ThoughtTimelineCard = memo(function ThoughtTimelineCard2({ thought, config,
12734
13369
  return null;
12735
13370
  }
12736
13371
  if (thought?.raw && Array.isArray(thought.raw)) {
12737
- const hasConfirmationEvent = thought.raw.some((r2) => {
12738
- const type = r2?.type || "";
12739
- return excludedTypes.includes(type) || r2?.content && (r2.content.includes('"type":"tool_confirmed"') || r2.content.includes('"type":"component_submitted"') || r2.content.includes("\u7528\u6237\u786E\u8BA4\u6267\u884C\u5DE5\u5177\u8C03\u7528"));
13372
+ const hasConfirmationEvent = thought.raw.some((r3) => {
13373
+ const type = r3?.type || "";
13374
+ return excludedTypes.includes(type) || r3?.content && (r3.content.includes('"type":"tool_confirmed"') || r3.content.includes('"type":"component_submitted"') || r3.content.includes("\u7528\u6237\u786E\u8BA4\u6267\u884C\u5DE5\u5177\u8C03\u7528"));
12740
13375
  });
12741
13376
  if (hasConfirmationEvent) {
12742
13377
  return null;
@@ -12748,12 +13383,19 @@ var ThoughtTimelineCard = memo(function ThoughtTimelineCard2({ thought, config,
12748
13383
  if (!cleaned || !cleaned.trim()) return null;
12749
13384
  return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("div", { className: "px-3 py-2", children: [
12750
13385
  /* @__PURE__ */ jsx("div", { className: "", children: /* @__PURE__ */ jsxs("div", { className: "text-sm leading-relaxed prose prose-invert prose-sm max-w-none [&_*]:break-words", children: [
12751
- /* @__PURE__ */ jsx(MarkdownContent, { content: cleaned, skipImages: false, config, variant: "thought" }),
13386
+ /* @__PURE__ */ jsx(MarkdownContent, { content: cleaned, skipImages, config, variant: "thought" }),
12752
13387
  isLoading && /* @__PURE__ */ jsx("span", { className: "inline-block w-2 h-4 ml-0.5 bg-[#d8ff00] animate-pulse rounded-sm" })
12753
13388
  ] }) }),
12754
13389
  thought?.raw?.length > 0 && showItemTime && /* @__PURE__ */ jsx("div", { className: "text-xs text-zinc-500 mt-2", children: new Date(
12755
13390
  thought.raw[thought.raw.length - 1]?.gmt_create || thought.raw[thought.raw.length - 1]?.gmtCreate || thought.raw[thought.raw.length - 1]?.timestamp || ""
12756
- ).toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit", second: "2-digit" }) })
13391
+ ).toLocaleTimeString("zh-CN", {
13392
+ year: "numeric",
13393
+ month: "2-digit",
13394
+ day: "2-digit",
13395
+ hour: "2-digit",
13396
+ minute: "2-digit",
13397
+ second: "2-digit"
13398
+ }) })
12757
13399
  ] }) });
12758
13400
  });
12759
13401
  var COMPONENT_TAGS_TO_STRIP = [
@@ -13753,7 +14395,8 @@ ${m.content}`;
13753
14395
  }
13754
14396
  var ThoughtBlockItem = memo(function ThoughtBlockItem2({
13755
14397
  content,
13756
- config
14398
+ config,
14399
+ skipImages = false
13757
14400
  }) {
13758
14401
  const [expanded, setExpanded] = useState(false);
13759
14402
  const lineCount = useMemo(() => content.split("\n").length, [content]);
@@ -13766,7 +14409,7 @@ var ThoughtBlockItem = memo(function ThoughtBlockItem2({
13766
14409
  "text-sm text-zinc-400 leading-relaxed prose prose-invert prose-sm max-w-none [&_*]:break-words",
13767
14410
  shouldToggle && !expanded ? "max-h-[3.5em] overflow-hidden" : ""
13768
14411
  ),
13769
- children: /* @__PURE__ */ jsx(MarkdownContent, { content, skipImages: false, config, variant: "thought" })
14412
+ children: /* @__PURE__ */ jsx(MarkdownContent, { content, skipImages, config, variant: "thought" })
13770
14413
  }
13771
14414
  ),
13772
14415
  shouldToggle && /* @__PURE__ */ jsx(
@@ -13952,7 +14595,6 @@ var MessageBubble = memo(function MessageBubble2({
13952
14595
  const shouldShowAvatar = isUser ? showUserAvatar : showAssistantAvatar;
13953
14596
  const shouldShowName = isUser ? showUserName : showAssistantName;
13954
14597
  const shouldShowDescription = isUser ? showUserDescription : showAssistantDescription;
13955
- console.log("[MessageBubble] \u6E32\u67D3\u6D88\u606F\u6C14\u6CE1, config?.identity:", config?.identity);
13956
14598
  const resolveFileName = (url) => {
13957
14599
  try {
13958
14600
  const pathname = new URL(url, "http://dummy").pathname;
@@ -14013,7 +14655,8 @@ var MessageBubble = memo(function MessageBubble2({
14013
14655
  {
14014
14656
  thought: item.data,
14015
14657
  config,
14016
- isLoading: showLoadingCursor
14658
+ isLoading: showLoadingCursor,
14659
+ skipImages: hasToolCallImages
14017
14660
  },
14018
14661
  item.id
14019
14662
  );
@@ -14113,7 +14756,8 @@ var MessageBubble = memo(function MessageBubble2({
14113
14756
  ThoughtBlockItem,
14114
14757
  {
14115
14758
  content: block.content,
14116
- config
14759
+ config,
14760
+ skipImages: hasToolCallImages
14117
14761
  },
14118
14762
  `${block.ts}-${index}`
14119
14763
  )),
@@ -14158,15 +14802,23 @@ var MessageBubble = memo(function MessageBubble2({
14158
14802
  const isVideo = att.type === "video" || att.type?.startsWith("video/") || isVideoUrl2(att.url);
14159
14803
  const isImage2 = att.type === "image" || att.type?.startsWith("image/") || !isVideo && /\.(jpg|jpeg|png|gif|webp|bmp|svg)(\?|#|$)/i.test(att.url);
14160
14804
  const fileName = att.name || resolveFileName(att.url);
14805
+ if (att.url.includes("industryai")) {
14806
+ att.url = att.url.split("?")[0];
14807
+ }
14808
+ const assets = config?.asset?.transform?.({
14809
+ type: att.type,
14810
+ url: att.url,
14811
+ name: fileName
14812
+ }) || { url: att.url, type: att.type };
14161
14813
  if (isImage2 || isVideo) {
14162
14814
  return /* @__PURE__ */ jsxs(
14163
14815
  "button",
14164
14816
  {
14165
14817
  type: "button",
14166
- onClick: () => setPreviewMedia({ url: att.url, isVideo }),
14818
+ onClick: () => setPreviewMedia({ url: assets.url, isVideo }),
14167
14819
  className: "group/att relative w-[88px] h-[88px] rounded-lg overflow-hidden border border-zinc-700/40 bg-zinc-900/60 hover:border-zinc-500/60 transition-colors",
14168
14820
  children: [
14169
- isVideo ? /* @__PURE__ */ jsx(MessageVideoComp, { src: att.url, className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsx(MessageImageComp, { src: att.url, alt: fileName, className: "w-full h-full object-cover" }),
14821
+ isVideo ? /* @__PURE__ */ jsx(MessageVideoComp, { src: assets.url, className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsx(MessageImageComp, { src: att.url, alt: fileName, className: "w-full h-full object-cover" }),
14170
14822
  /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/20 opacity-0 group-hover/att:opacity-100 transition-opacity" })
14171
14823
  ]
14172
14824
  },
@@ -14271,7 +14923,14 @@ var MessageBubble = memo(function MessageBubble2({
14271
14923
  ]
14272
14924
  }
14273
14925
  ) }),
14274
- message.gmtCreate && !isStreaming && /* @__PURE__ */ jsx("div", { className: "text-zinc-600 text-[10px] mt-1", children: new Date(message.gmtCreate).toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit", second: "2-digit" }) })
14926
+ message.gmtCreate && !isStreaming && /* @__PURE__ */ jsx("div", { className: "text-zinc-600 text-[10px] mt-1 opacity-0 group-hover:opacity-100 transition-opacity", children: new Date(message.gmtCreate).toLocaleTimeString("zh-CN", {
14927
+ year: "numeric",
14928
+ month: "2-digit",
14929
+ day: "2-digit",
14930
+ hour: "2-digit",
14931
+ minute: "2-digit",
14932
+ second: "2-digit"
14933
+ }) })
14275
14934
  ] })
14276
14935
  ] });
14277
14936
  });
@@ -15146,9 +15805,24 @@ var DialogDescription = React20.forwardRef(({ className, ...props }, ref) => /*
15146
15805
  ));
15147
15806
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
15148
15807
 
15808
+ // ../../node_modules/clsx/dist/clsx.mjs
15809
+ function r2(e) {
15810
+ var t, f, n = "";
15811
+ if ("string" == typeof e || "number" == typeof e) n += e;
15812
+ else if ("object" == typeof e) if (Array.isArray(e)) {
15813
+ var o = e.length;
15814
+ for (t = 0; t < o; t++) e[t] && (f = r2(e[t])) && (n && (n += " "), n += f);
15815
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
15816
+ return n;
15817
+ }
15818
+ function clsx2() {
15819
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r2(e)) && (n && (n += " "), n += t);
15820
+ return n;
15821
+ }
15822
+
15149
15823
  // ../../node_modules/class-variance-authority/dist/index.mjs
15150
15824
  var falsyToString = (value) => typeof value === "boolean" ? `${value}` : value === 0 ? "0" : value;
15151
- var cx = clsx;
15825
+ var cx = clsx2;
15152
15826
  var cva = (base, config) => (props) => {
15153
15827
  var _config_compoundVariants;
15154
15828
  if ((config === null || config === void 0 ? void 0 : config.variants) == null) return cx(base, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
@@ -15966,10 +16640,10 @@ var Observer = class {
15966
16640
  });
15967
16641
  }
15968
16642
  };
15969
- this.custom = (jsx50, data) => {
16643
+ this.custom = (jsx59, data) => {
15970
16644
  const id = (data == null ? void 0 : data.id) || toastsCounter++;
15971
16645
  this.create({
15972
- jsx: jsx50(id),
16646
+ jsx: jsx59(id),
15973
16647
  id,
15974
16648
  ...data
15975
16649
  });
@@ -18470,7 +19144,57 @@ var ToolbarButton = memo(function ToolbarButton2({
18470
19144
  }
18471
19145
  );
18472
19146
  });
18473
- var CodeBlock3 = memo(function CodeBlock4({
19147
+ var artifactTypeConfig = {
19148
+ html: {
19149
+ icon: Globe,
19150
+ label: "HTML",
19151
+ color: "text-orange-400",
19152
+ bgColor: "bg-orange-500/10"
19153
+ },
19154
+ svg: {
19155
+ icon: Globe,
19156
+ label: "SVG",
19157
+ color: "text-orange-300",
19158
+ bgColor: "bg-orange-500/10"
19159
+ },
19160
+ markdown: {
19161
+ icon: FileText,
19162
+ label: "Markdown",
19163
+ color: "text-blue-400",
19164
+ bgColor: "bg-blue-500/10"
19165
+ },
19166
+ json: {
19167
+ icon: FileJson,
19168
+ label: "JSON",
19169
+ color: "text-yellow-400",
19170
+ bgColor: "bg-yellow-500/10"
19171
+ },
19172
+ code: {
19173
+ icon: FileCode,
19174
+ label: "Code",
19175
+ color: "text-purple-400",
19176
+ bgColor: "bg-purple-500/10"
19177
+ },
19178
+ text: {
19179
+ icon: FileText,
19180
+ label: "Text",
19181
+ color: "text-zinc-400",
19182
+ bgColor: "bg-zinc-500/10"
19183
+ },
19184
+ image: {
19185
+ icon: FileImage,
19186
+ label: "Image",
19187
+ color: "text-green-400",
19188
+ bgColor: "bg-green-500/10"
19189
+ },
19190
+ video: {
19191
+ icon: Video,
19192
+ label: "Video",
19193
+ color: "text-pink-400",
19194
+ bgColor: "bg-pink-500/10"
19195
+ }
19196
+ };
19197
+ var CodeBlock3 = memo(function CodeBlock4({
18474
19198
  code: code3,
18475
19199
  language,
18476
19200
  showLineNumbers = true
@@ -18758,38 +19482,1305 @@ memo(function JsonPreview2({ content }) {
18758
19482
  }
18759
19483
  return /* @__PURE__ */ jsx(CodeBlock3, { code: formattedJson, language: "json" });
18760
19484
  });
18761
- var artifactTypeConfig = {
18762
- html: {
18763
- icon: Globe,
18764
- label: "HTML",
18765
- color: "text-orange-400",
18766
- bgColor: "bg-orange-500/10"
18767
- },
18768
- markdown: {
18769
- icon: FileText,
18770
- label: "Markdown",
18771
- color: "text-blue-400",
18772
- bgColor: "bg-blue-500/10"
18773
- },
18774
- json: {
18775
- icon: FileJson,
18776
- label: "JSON",
18777
- color: "text-yellow-400",
18778
- bgColor: "bg-yellow-500/10"
18779
- },
18780
- code: {
18781
- icon: FileCode,
18782
- label: "Code",
18783
- color: "text-purple-400",
18784
- bgColor: "bg-purple-500/10"
18785
- },
18786
- text: {
18787
- icon: FileText,
18788
- label: "Text",
18789
- color: "text-zinc-400",
18790
- bgColor: "bg-zinc-500/10"
18791
- }
18792
- };
19485
+ var CodeEditor = memo(function CodeEditor2({
19486
+ code: code3,
19487
+ language,
19488
+ onChange
19489
+ }) {
19490
+ const textareaRef = useRef(null);
19491
+ const handleKeyDown = useCallback((e) => {
19492
+ if (e.key === "Tab") {
19493
+ e.preventDefault();
19494
+ const textarea = e.currentTarget;
19495
+ const start = textarea.selectionStart;
19496
+ const end = textarea.selectionEnd;
19497
+ const newValue = code3.substring(0, start) + " " + code3.substring(end);
19498
+ onChange(newValue);
19499
+ requestAnimationFrame(() => {
19500
+ textarea.selectionStart = textarea.selectionEnd = start + 2;
19501
+ });
19502
+ }
19503
+ }, [code3, onChange]);
19504
+ return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col bg-zinc-950 agent-sdk-light:bg-white", children: [
19505
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between px-4 py-2 border-b border-zinc-800/50 agent-sdk-light:border-zinc-200 bg-zinc-900/30 agent-sdk-light:bg-zinc-50 flex-shrink-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
19506
+ /* @__PURE__ */ jsx(Pencil, { size: 12, className: "text-[#d8ff00]" }),
19507
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-[#d8ff00] font-medium", children: "\u7F16\u8F91\u6A21\u5F0F" }),
19508
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-zinc-500 agent-sdk-light:text-zinc-600 font-mono uppercase ml-2", children: language || "text" })
19509
+ ] }) }),
19510
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
19511
+ "textarea",
19512
+ {
19513
+ ref: textareaRef,
19514
+ value: code3,
19515
+ onChange: (e) => onChange(e.target.value),
19516
+ onKeyDown: handleKeyDown,
19517
+ className: "w-full h-full p-4 bg-zinc-950 agent-sdk-light:bg-white text-xs font-mono text-zinc-300 agent-sdk-light:text-zinc-800 leading-relaxed resize-none focus:outline-none",
19518
+ spellCheck: false,
19519
+ autoComplete: "off",
19520
+ autoCorrect: "off",
19521
+ autoCapitalize: "off"
19522
+ }
19523
+ ) })
19524
+ ] });
19525
+ });
19526
+ function useResolvedMediaUrl(content, options) {
19527
+ const { fileId, type = "image", config } = options || {};
19528
+ const [resolvedUrl, setResolvedUrl] = useState(content);
19529
+ const [resolvedHdUrl, setResolvedHdUrl] = useState(content);
19530
+ const [isLoading, setIsLoading] = useState(true);
19531
+ useEffect(() => {
19532
+ let active = true;
19533
+ setIsLoading(true);
19534
+ const resolve = async () => {
19535
+ const httpUrl = isHttpUrl(content) ? content : void 0;
19536
+ const asset = createAssetFromSource({
19537
+ fileId: fileId || (!httpUrl ? content : void 0),
19538
+ fileUrl: httpUrl,
19539
+ type
19540
+ });
19541
+ if (!asset) {
19542
+ if (active) {
19543
+ setResolvedUrl(content);
19544
+ setResolvedHdUrl(content);
19545
+ setIsLoading(false);
19546
+ }
19547
+ return;
19548
+ }
19549
+ const resolved = await resolveAssetForDisplay(asset, config);
19550
+ if (!active) return;
19551
+ if (resolved) {
19552
+ setResolvedUrl(resolved.url);
19553
+ setResolvedHdUrl(resolved.hdUrl || resolved.url);
19554
+ } else {
19555
+ setResolvedUrl(content);
19556
+ setResolvedHdUrl(content);
19557
+ }
19558
+ setIsLoading(false);
19559
+ };
19560
+ resolve();
19561
+ return () => {
19562
+ active = false;
19563
+ };
19564
+ }, [content, fileId, type, config]);
19565
+ return { url: resolvedUrl, hdUrl: resolvedHdUrl, isLoading };
19566
+ }
19567
+ function useResolvedThumbnailUrl(content, options) {
19568
+ const { fileId, type = "image", config, enabled = true } = options || {};
19569
+ const [url, setUrl] = useState(null);
19570
+ useEffect(() => {
19571
+ if (!enabled || !content) {
19572
+ setUrl(null);
19573
+ return;
19574
+ }
19575
+ if (type === "video") {
19576
+ setUrl(null);
19577
+ return;
19578
+ }
19579
+ let active = true;
19580
+ const resolve = async () => {
19581
+ const httpUrl = isHttpUrl(content) ? content : void 0;
19582
+ const asset = createAssetFromSource({
19583
+ fileId: fileId || (!httpUrl ? content : void 0),
19584
+ fileUrl: httpUrl,
19585
+ type
19586
+ });
19587
+ if (!asset) {
19588
+ if (active) setUrl(isHttpUrl(content) ? content : null);
19589
+ return;
19590
+ }
19591
+ const resolved = await resolveAssetForDisplay(asset, config);
19592
+ if (!active) return;
19593
+ setUrl(resolved?.url || (isHttpUrl(content) ? content : null));
19594
+ };
19595
+ resolve();
19596
+ return () => {
19597
+ active = false;
19598
+ };
19599
+ }, [content, fileId, type, config, enabled]);
19600
+ return url;
19601
+ }
19602
+ var ImageArtifactPreview = memo(function ImageArtifactPreview2({
19603
+ content,
19604
+ metadata,
19605
+ config
19606
+ }) {
19607
+ const [isZoomed, setIsZoomed] = useState(false);
19608
+ const [showInfo, setShowInfo] = useState(true);
19609
+ const [imgNaturalSize, setImgNaturalSize] = useState(null);
19610
+ const [copied, setCopied] = useState(null);
19611
+ const { hdUrl: resolvedHdUrl } = useResolvedMediaUrl(content, {
19612
+ fileId: metadata?.fileId,
19613
+ type: "image",
19614
+ config
19615
+ });
19616
+ const generationParams = metadata?.generationParams;
19617
+ const toolName = metadata?.toolName;
19618
+ const relation = metadata?.relation;
19619
+ const handleCopy = useCallback(async (text3, label) => {
19620
+ try {
19621
+ await navigator.clipboard.writeText(text3);
19622
+ setCopied(label);
19623
+ setTimeout(() => setCopied(null), 2e3);
19624
+ } catch {
19625
+ }
19626
+ }, []);
19627
+ const handleDownload = useCallback(() => {
19628
+ const link2 = document.createElement("a");
19629
+ link2.href = resolvedHdUrl;
19630
+ link2.download = `generated-${Date.now()}.png`;
19631
+ link2.target = "_blank";
19632
+ document.body.appendChild(link2);
19633
+ link2.click();
19634
+ document.body.removeChild(link2);
19635
+ }, [resolvedHdUrl]);
19636
+ const formatParamKey = (key) => {
19637
+ const keyMap = {
19638
+ content: "Prompt",
19639
+ width: "\u5BBD\u5EA6",
19640
+ height: "\u9AD8\u5EA6",
19641
+ batchSize: "\u751F\u6210\u6570\u91CF",
19642
+ steps: "\u6B65\u6570",
19643
+ cfg_scale: "CFG Scale",
19644
+ seed: "\u79CD\u5B50",
19645
+ sampler: "\u91C7\u6837\u5668",
19646
+ model: "\u6A21\u578B",
19647
+ negative_prompt: "\u53CD\u5411\u63D0\u793A\u8BCD",
19648
+ style: "\u98CE\u683C",
19649
+ quality: "\u8D28\u91CF"
19650
+ };
19651
+ return keyMap[key] || key.replace(/([A-Z])/g, " $1").replace(/_/g, " ").replace(/^./, (s) => s.toUpperCase());
19652
+ };
19653
+ const promptText = generationParams?.content ? String(generationParams.content) : null;
19654
+ const otherParams = generationParams ? Object.entries(generationParams).filter(([key]) => key !== "content") : [];
19655
+ return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col bg-zinc-950 agent-sdk-light:bg-white", children: [
19656
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-auto flex items-center justify-center p-6 bg-zinc-950 agent-sdk-light:bg-zinc-50 relative", children: [
19657
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 opacity-[0.03]", style: {
19658
+ backgroundImage: "linear-gradient(45deg, #808080 25%, transparent 25%), linear-gradient(-45deg, #808080 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #808080 75%), linear-gradient(-45deg, transparent 75%, #808080 75%)",
19659
+ backgroundSize: "20px 20px",
19660
+ backgroundPosition: "0 0, 0 10px, 10px -10px, -10px 0px"
19661
+ } }),
19662
+ /* @__PURE__ */ jsx(
19663
+ "div",
19664
+ {
19665
+ className: cn2(
19666
+ "relative transition-transform duration-300 cursor-zoom-in z-10",
19667
+ isZoomed && "cursor-zoom-out scale-[2] z-50"
19668
+ ),
19669
+ onClick: () => setIsZoomed((prev) => !prev),
19670
+ children: /* @__PURE__ */ jsx(
19671
+ "img",
19672
+ {
19673
+ src: resolvedHdUrl,
19674
+ alt: "Generated image",
19675
+ className: "max-w-full max-h-[60vh] object-contain rounded-lg shadow-2xl",
19676
+ loading: "lazy",
19677
+ onLoad: (e) => {
19678
+ const img = e.target;
19679
+ setImgNaturalSize({ width: img.naturalWidth, height: img.naturalHeight });
19680
+ }
19681
+ }
19682
+ )
19683
+ }
19684
+ ),
19685
+ /* @__PURE__ */ jsxs("div", { className: "absolute top-4 right-4 flex items-center gap-1.5 z-20", children: [
19686
+ /* @__PURE__ */ jsx(
19687
+ "button",
19688
+ {
19689
+ onClick: () => setShowInfo((prev) => !prev),
19690
+ className: cn2(
19691
+ "p-2 rounded-lg backdrop-blur-sm transition-colors",
19692
+ showInfo ? "bg-[#d8ff00]/20 text-[#d8ff00]" : "bg-black/30 text-white/70 hover:text-white hover:bg-black/50"
19693
+ ),
19694
+ title: showInfo ? "\u9690\u85CF\u8BE6\u60C5" : "\u663E\u793A\u8BE6\u60C5",
19695
+ children: /* @__PURE__ */ jsx(FileText, { size: 16 })
19696
+ }
19697
+ ),
19698
+ /* @__PURE__ */ jsx(
19699
+ "button",
19700
+ {
19701
+ onClick: handleDownload,
19702
+ className: "p-2 bg-black/30 text-white/70 hover:text-white hover:bg-black/50 rounded-lg backdrop-blur-sm transition-colors",
19703
+ title: "\u4E0B\u8F7D\u56FE\u7247",
19704
+ children: /* @__PURE__ */ jsx(Download, { size: 16 })
19705
+ }
19706
+ )
19707
+ ] }),
19708
+ imgNaturalSize && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-4 left-4 z-20 flex items-center gap-2 px-2.5 py-1.5 bg-black/40 backdrop-blur-sm rounded-lg", children: [
19709
+ /* @__PURE__ */ jsx(FileImage, { size: 12, className: "text-white/60" }),
19710
+ /* @__PURE__ */ jsxs("span", { className: "text-[11px] text-white/80 font-mono", children: [
19711
+ imgNaturalSize.width,
19712
+ " \xD7 ",
19713
+ imgNaturalSize.height
19714
+ ] })
19715
+ ] })
19716
+ ] }),
19717
+ showInfo && (generationParams || toolName) && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 border-t border-zinc-800/50 agent-sdk-light:border-zinc-200 bg-zinc-900/80 agent-sdk-light:bg-zinc-50 max-h-[40%] overflow-y-auto", children: /* @__PURE__ */ jsxs("div", { className: "px-5 py-4 space-y-4", children: [
19718
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
19719
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
19720
+ /* @__PURE__ */ jsx("div", { className: "w-7 h-7 rounded-lg bg-[#d8ff00]/10 flex items-center justify-center", children: /* @__PURE__ */ jsx(Sparkles, { size: 14, className: "text-[#d8ff00]" }) }),
19721
+ /* @__PURE__ */ jsxs("div", { children: [
19722
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-zinc-200 agent-sdk-light:text-zinc-800", children: toolName || "\u56FE\u7247\u751F\u6210" }),
19723
+ relation?.workflowCode && /* @__PURE__ */ jsx("span", { className: "ml-2 text-[10px] text-zinc-500 font-mono bg-zinc-800/50 agent-sdk-light:bg-zinc-200 px-1.5 py-0.5 rounded", children: relation.workflowCode })
19724
+ ] })
19725
+ ] }),
19726
+ metadata?.taskId && /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-zinc-600 font-mono", children: [
19727
+ "Task: ",
19728
+ metadata.taskId
19729
+ ] })
19730
+ ] }),
19731
+ promptText && /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
19732
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
19733
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-zinc-500 uppercase tracking-wider font-medium", children: "Prompt" }),
19734
+ /* @__PURE__ */ jsx(
19735
+ "button",
19736
+ {
19737
+ onClick: () => handleCopy(promptText, "prompt"),
19738
+ className: "text-[10px] text-zinc-500 hover:text-zinc-300 transition-colors flex items-center gap-1",
19739
+ children: copied === "prompt" ? /* @__PURE__ */ jsxs(Fragment, { children: [
19740
+ /* @__PURE__ */ jsx(CheckCheck, { size: 10, className: "text-green-400" }),
19741
+ " \u5DF2\u590D\u5236"
19742
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
19743
+ /* @__PURE__ */ jsx(Copy, { size: 10 }),
19744
+ " \u590D\u5236"
19745
+ ] })
19746
+ }
19747
+ )
19748
+ ] }),
19749
+ /* @__PURE__ */ jsx("div", { className: "p-3 bg-zinc-800/50 agent-sdk-light:bg-zinc-100 rounded-lg border border-zinc-700/30 agent-sdk-light:border-zinc-200", children: /* @__PURE__ */ jsx("p", { className: "text-xs text-zinc-300 agent-sdk-light:text-zinc-700 leading-relaxed whitespace-pre-wrap", children: promptText }) })
19750
+ ] }),
19751
+ otherParams.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
19752
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-zinc-500 uppercase tracking-wider font-medium", children: "\u53C2\u6570" }),
19753
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 sm:grid-cols-3 gap-2", children: otherParams.map(([key, value]) => {
19754
+ const displayValue = String(value);
19755
+ if (displayValue.length > 100) return null;
19756
+ return /* @__PURE__ */ jsxs(
19757
+ "div",
19758
+ {
19759
+ className: "flex flex-col gap-0.5 p-2 bg-zinc-800/30 agent-sdk-light:bg-zinc-100 rounded-lg border border-zinc-700/20 agent-sdk-light:border-zinc-200",
19760
+ children: [
19761
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-zinc-500 agent-sdk-light:text-zinc-500", children: formatParamKey(key) }),
19762
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-zinc-200 agent-sdk-light:text-zinc-800 font-mono font-medium truncate", title: displayValue, children: displayValue })
19763
+ ]
19764
+ },
19765
+ key
19766
+ );
19767
+ }) })
19768
+ ] }),
19769
+ (metadata?.fileId || metadata?.workId) && /* @__PURE__ */ jsx("div", { className: "pt-2 border-t border-zinc-800/30 agent-sdk-light:border-zinc-200", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 text-[10px] text-zinc-600", children: [
19770
+ metadata.workId && /* @__PURE__ */ jsxs("span", { children: [
19771
+ "ID: ",
19772
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-zinc-500", children: metadata.workId })
19773
+ ] }),
19774
+ metadata.fileId && /* @__PURE__ */ jsxs("span", { className: "truncate max-w-[200px]", title: metadata.fileId, children: [
19775
+ "File: ",
19776
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-zinc-500", children: metadata.fileId })
19777
+ ] })
19778
+ ] }) })
19779
+ ] }) })
19780
+ ] });
19781
+ });
19782
+ var VideoArtifactPreview = memo(function VideoArtifactPreview2({
19783
+ content,
19784
+ metadata,
19785
+ config
19786
+ }) {
19787
+ const { hdUrl: resolvedUrl } = useResolvedMediaUrl(content, {
19788
+ fileId: metadata?.fileId,
19789
+ type: "video",
19790
+ config
19791
+ });
19792
+ const videoRef = useRef(null);
19793
+ const progressRef = useRef(null);
19794
+ const [isPlaying, setIsPlaying] = useState(false);
19795
+ const [isMuted, setIsMuted] = useState(false);
19796
+ const [duration, setDuration] = useState(0);
19797
+ const [currentTime, setCurrentTime] = useState(0);
19798
+ const [volume, setVolume] = useState(1);
19799
+ const [isLoaded, setIsLoaded] = useState(false);
19800
+ const [showVolumeSlider, setShowVolumeSlider] = useState(false);
19801
+ const [posterUrl, setPosterUrl] = useState(null);
19802
+ const [isDraggingProgress, setIsDraggingProgress] = useState(false);
19803
+ const generationParams = metadata?.generationParams;
19804
+ const toolName = metadata?.toolName;
19805
+ useEffect(() => {
19806
+ const video = document.createElement("video");
19807
+ video.crossOrigin = "anonymous";
19808
+ video.preload = "metadata";
19809
+ video.muted = true;
19810
+ video.addEventListener("loadeddata", () => {
19811
+ video.currentTime = Math.min(0.5, video.duration * 0.1);
19812
+ });
19813
+ video.addEventListener("seeked", () => {
19814
+ try {
19815
+ const canvas = document.createElement("canvas");
19816
+ canvas.width = video.videoWidth;
19817
+ canvas.height = video.videoHeight;
19818
+ const ctx = canvas.getContext("2d");
19819
+ if (ctx) {
19820
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
19821
+ setPosterUrl(canvas.toDataURL("image/jpeg", 0.8));
19822
+ }
19823
+ } catch {
19824
+ }
19825
+ video.remove();
19826
+ });
19827
+ video.addEventListener("error", () => video.remove());
19828
+ video.src = resolvedUrl;
19829
+ video.load();
19830
+ return () => {
19831
+ video.remove();
19832
+ };
19833
+ }, [resolvedUrl]);
19834
+ const handleLoadedMetadata = () => {
19835
+ const video = videoRef.current;
19836
+ if (video) {
19837
+ setDuration(video.duration);
19838
+ setIsLoaded(true);
19839
+ }
19840
+ };
19841
+ const handleTimeUpdate = () => {
19842
+ if (!isDraggingProgress && videoRef.current) {
19843
+ setCurrentTime(videoRef.current.currentTime);
19844
+ }
19845
+ };
19846
+ const togglePlay = useCallback(() => {
19847
+ const video = videoRef.current;
19848
+ if (!video) return;
19849
+ if (isPlaying) {
19850
+ video.pause();
19851
+ setIsPlaying(false);
19852
+ } else {
19853
+ video.play().then(() => setIsPlaying(true)).catch(() => {
19854
+ });
19855
+ }
19856
+ }, [isPlaying]);
19857
+ const toggleMute = useCallback(() => {
19858
+ const video = videoRef.current;
19859
+ if (video) {
19860
+ video.muted = !isMuted;
19861
+ setIsMuted(!isMuted);
19862
+ }
19863
+ }, [isMuted]);
19864
+ const handleVolumeChange = useCallback((e) => {
19865
+ const newVolume = parseFloat(e.target.value);
19866
+ setVolume(newVolume);
19867
+ if (videoRef.current) {
19868
+ videoRef.current.volume = newVolume;
19869
+ if (newVolume === 0) {
19870
+ setIsMuted(true);
19871
+ videoRef.current.muted = true;
19872
+ } else if (isMuted) {
19873
+ setIsMuted(false);
19874
+ videoRef.current.muted = false;
19875
+ }
19876
+ }
19877
+ }, [isMuted]);
19878
+ const handleProgressClick = useCallback((e) => {
19879
+ const video = videoRef.current;
19880
+ const bar = progressRef.current;
19881
+ if (!video || !bar || !duration) return;
19882
+ const rect = bar.getBoundingClientRect();
19883
+ const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
19884
+ video.currentTime = ratio * duration;
19885
+ setCurrentTime(ratio * duration);
19886
+ }, [duration]);
19887
+ const handleProgressDrag = useCallback((e) => {
19888
+ if (!isDraggingProgress) return;
19889
+ const bar = progressRef.current;
19890
+ if (!bar || !duration) return;
19891
+ const rect = bar.getBoundingClientRect();
19892
+ const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
19893
+ setCurrentTime(ratio * duration);
19894
+ }, [isDraggingProgress, duration]);
19895
+ const handleProgressDragEnd = useCallback(() => {
19896
+ if (isDraggingProgress && videoRef.current) {
19897
+ videoRef.current.currentTime = currentTime;
19898
+ }
19899
+ setIsDraggingProgress(false);
19900
+ }, [isDraggingProgress, currentTime]);
19901
+ useEffect(() => {
19902
+ if (!isDraggingProgress) return;
19903
+ const handleMouseUp = () => handleProgressDragEnd();
19904
+ const handleMouseMove = (e) => {
19905
+ const bar = progressRef.current;
19906
+ if (!bar || !duration) return;
19907
+ const rect = bar.getBoundingClientRect();
19908
+ const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
19909
+ setCurrentTime(ratio * duration);
19910
+ };
19911
+ window.addEventListener("mouseup", handleMouseUp);
19912
+ window.addEventListener("mousemove", handleMouseMove);
19913
+ return () => {
19914
+ window.removeEventListener("mouseup", handleMouseUp);
19915
+ window.removeEventListener("mousemove", handleMouseMove);
19916
+ };
19917
+ }, [isDraggingProgress, duration, handleProgressDragEnd]);
19918
+ const handleDownload = useCallback(() => {
19919
+ const link2 = document.createElement("a");
19920
+ link2.href = resolvedUrl;
19921
+ link2.download = `video-${Date.now()}.mp4`;
19922
+ document.body.appendChild(link2);
19923
+ link2.click();
19924
+ document.body.removeChild(link2);
19925
+ }, [resolvedUrl]);
19926
+ const formatTime2 = (seconds) => {
19927
+ const mins = Math.floor(seconds / 60);
19928
+ const secs = Math.floor(seconds % 60);
19929
+ return `${mins}:${secs.toString().padStart(2, "0")}`;
19930
+ };
19931
+ const progressPercent = duration > 0 ? currentTime / duration * 100 : 0;
19932
+ return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col bg-zinc-950 agent-sdk-light:bg-white", children: [
19933
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-hidden flex items-center justify-center bg-black relative group/player", children: [
19934
+ posterUrl && !isPlaying && !currentTime && /* @__PURE__ */ jsx(
19935
+ "img",
19936
+ {
19937
+ src: posterUrl,
19938
+ alt: "Video cover",
19939
+ className: "absolute inset-0 w-full h-full object-contain z-[1]"
19940
+ }
19941
+ ),
19942
+ /* @__PURE__ */ jsx(
19943
+ "video",
19944
+ {
19945
+ ref: videoRef,
19946
+ src: resolvedUrl,
19947
+ muted: isMuted,
19948
+ playsInline: true,
19949
+ preload: "metadata",
19950
+ onLoadedMetadata: handleLoadedMetadata,
19951
+ onTimeUpdate: handleTimeUpdate,
19952
+ onEnded: () => setIsPlaying(false),
19953
+ onClick: togglePlay,
19954
+ className: cn2(
19955
+ "max-w-full max-h-full object-contain cursor-pointer",
19956
+ !isPlaying && posterUrl && !currentTime && "opacity-0"
19957
+ )
19958
+ }
19959
+ ),
19960
+ !isPlaying && /* @__PURE__ */ jsx(
19961
+ "div",
19962
+ {
19963
+ className: "absolute inset-0 z-[2] flex items-center justify-center cursor-pointer",
19964
+ onClick: togglePlay,
19965
+ children: /* @__PURE__ */ jsx("div", { className: cn2(
19966
+ "w-16 h-16 rounded-full bg-white/15 backdrop-blur-md",
19967
+ "flex items-center justify-center",
19968
+ "transition-all duration-200",
19969
+ "group-hover/player:scale-110 group-hover/player:bg-white/25",
19970
+ "shadow-2xl shadow-black/30"
19971
+ ), children: /* @__PURE__ */ jsx("svg", { width: "26", height: "26", viewBox: "0 0 24 24", fill: "white", className: "ml-1", children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" }) }) })
19972
+ }
19973
+ ),
19974
+ /* @__PURE__ */ jsxs("div", { className: cn2(
19975
+ "absolute bottom-0 left-0 right-0 z-[3]",
19976
+ "bg-gradient-to-t from-black/90 via-black/50 to-transparent",
19977
+ "px-4 pb-3 pt-10",
19978
+ "transition-opacity duration-300",
19979
+ "opacity-0 group-hover/player:opacity-100",
19980
+ isPlaying ? "" : "opacity-100"
19981
+ ), children: [
19982
+ /* @__PURE__ */ jsx(
19983
+ "div",
19984
+ {
19985
+ ref: progressRef,
19986
+ className: "w-full h-1.5 bg-white/20 rounded-full mb-3 cursor-pointer group/progress hover:h-2 transition-all",
19987
+ onClick: handleProgressClick,
19988
+ onMouseDown: () => setIsDraggingProgress(true),
19989
+ onMouseMove: handleProgressDrag,
19990
+ children: /* @__PURE__ */ jsx(
19991
+ "div",
19992
+ {
19993
+ className: "h-full bg-[#d8ff00] rounded-full relative",
19994
+ style: { width: `${progressPercent}%` },
19995
+ children: /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 w-3.5 h-3.5 bg-[#d8ff00] rounded-full opacity-0 group-hover/progress:opacity-100 transition-opacity shadow-lg -mr-1.5" })
19996
+ }
19997
+ )
19998
+ }
19999
+ ),
20000
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
20001
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
20002
+ /* @__PURE__ */ jsx("button", { onClick: togglePlay, className: "p-1 text-white/90 hover:text-white transition-colors", children: isPlaying ? /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor", children: [
20003
+ /* @__PURE__ */ jsx("rect", { x: "6", y: "4", width: "4", height: "16", rx: "1" }),
20004
+ /* @__PURE__ */ jsx("rect", { x: "14", y: "4", width: "4", height: "16", rx: "1" })
20005
+ ] }) : /* @__PURE__ */ jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" }) }) }),
20006
+ /* @__PURE__ */ jsxs(
20007
+ "div",
20008
+ {
20009
+ className: "flex items-center gap-1.5 relative",
20010
+ onMouseEnter: () => setShowVolumeSlider(true),
20011
+ onMouseLeave: () => setShowVolumeSlider(false),
20012
+ children: [
20013
+ /* @__PURE__ */ jsx("button", { onClick: toggleMute, className: "p-1 text-white/80 hover:text-white transition-colors", children: isMuted || volume === 0 ? /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
20014
+ /* @__PURE__ */ jsx("polygon", { points: "11 5 6 9 2 9 2 15 6 15 11 19 11 5" }),
20015
+ /* @__PURE__ */ jsx("line", { x1: "23", y1: "9", x2: "17", y2: "15" }),
20016
+ /* @__PURE__ */ jsx("line", { x1: "17", y1: "9", x2: "23", y2: "15" })
20017
+ ] }) : /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
20018
+ /* @__PURE__ */ jsx("polygon", { points: "11 5 6 9 2 9 2 15 6 15 11 19 11 5" }),
20019
+ /* @__PURE__ */ jsx("path", { d: "M19.07 4.93a10 10 0 0 1 0 14.14" }),
20020
+ /* @__PURE__ */ jsx("path", { d: "M15.54 8.46a5 5 0 0 1 0 7.07" })
20021
+ ] }) }),
20022
+ showVolumeSlider && /* @__PURE__ */ jsx(
20023
+ "input",
20024
+ {
20025
+ type: "range",
20026
+ min: "0",
20027
+ max: "1",
20028
+ step: "0.05",
20029
+ value: isMuted ? 0 : volume,
20030
+ onChange: handleVolumeChange,
20031
+ className: "w-20 h-1 appearance-none bg-white/20 rounded-full cursor-pointer accent-[#d8ff00]"
20032
+ }
20033
+ )
20034
+ ]
20035
+ }
20036
+ ),
20037
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-white/60 font-mono tabular-nums", children: [
20038
+ formatTime2(currentTime),
20039
+ " / ",
20040
+ formatTime2(duration)
20041
+ ] })
20042
+ ] }),
20043
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx(
20044
+ "button",
20045
+ {
20046
+ onClick: handleDownload,
20047
+ className: "p-1.5 text-white/60 hover:text-white transition-colors",
20048
+ title: "\u4E0B\u8F7D\u89C6\u9891",
20049
+ children: /* @__PURE__ */ jsx(Download, { size: 16 })
20050
+ }
20051
+ ) })
20052
+ ] })
20053
+ ] })
20054
+ ] }),
20055
+ generationParams && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 border-t border-zinc-800/50 agent-sdk-light:border-zinc-200 bg-zinc-900/50 agent-sdk-light:bg-zinc-50", children: /* @__PURE__ */ jsxs("div", { className: "px-4 py-3", children: [
20056
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
20057
+ /* @__PURE__ */ jsx(Sparkles, { size: 12, className: "text-[#d8ff00]" }),
20058
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-zinc-300 agent-sdk-light:text-zinc-700", children: toolName || "\u751F\u6210\u53C2\u6570" })
20059
+ ] }),
20060
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-x-4 gap-y-1.5", children: Object.entries(generationParams).map(([key, value]) => {
20061
+ const displayValue = String(value);
20062
+ if (displayValue.length > 80) return null;
20063
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs", children: [
20064
+ /* @__PURE__ */ jsx("span", { className: "text-zinc-500 agent-sdk-light:text-zinc-500 capitalize", children: key.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase()) }),
20065
+ /* @__PURE__ */ jsx("span", { className: "text-zinc-300 agent-sdk-light:text-zinc-700 font-mono", children: displayValue })
20066
+ ] }, key);
20067
+ }) }),
20068
+ generationParams.content && String(generationParams.content).length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-2 pt-2 border-t border-zinc-800/30 agent-sdk-light:border-zinc-200", children: [
20069
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-zinc-500 agent-sdk-light:text-zinc-500 uppercase tracking-wider", children: "Prompt" }),
20070
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-zinc-300 agent-sdk-light:text-zinc-700 mt-1 leading-relaxed line-clamp-3", children: String(generationParams.content) })
20071
+ ] })
20072
+ ] }) })
20073
+ ] });
20074
+ });
20075
+ function htmlToMarkdown(element) {
20076
+ const lines = [];
20077
+ function processNode(node2, listDepth = 0) {
20078
+ if (node2.nodeType === Node.TEXT_NODE) {
20079
+ return node2.textContent || "";
20080
+ }
20081
+ if (node2.nodeType !== Node.ELEMENT_NODE) return "";
20082
+ const el = node2;
20083
+ const tag = el.tagName.toLowerCase();
20084
+ const childContent = () => {
20085
+ let result = "";
20086
+ el.childNodes.forEach((child) => {
20087
+ result += processNode(child, listDepth);
20088
+ });
20089
+ return result;
20090
+ };
20091
+ switch (tag) {
20092
+ case "h1":
20093
+ return `# ${childContent().trim()}
20094
+
20095
+ `;
20096
+ case "h2":
20097
+ return `## ${childContent().trim()}
20098
+
20099
+ `;
20100
+ case "h3":
20101
+ return `### ${childContent().trim()}
20102
+
20103
+ `;
20104
+ case "h4":
20105
+ return `#### ${childContent().trim()}
20106
+
20107
+ `;
20108
+ case "h5":
20109
+ return `##### ${childContent().trim()}
20110
+
20111
+ `;
20112
+ case "h6":
20113
+ return `###### ${childContent().trim()}
20114
+
20115
+ `;
20116
+ case "p": {
20117
+ const inner = childContent().trim();
20118
+ return inner ? `${inner}
20119
+
20120
+ ` : "\n";
20121
+ }
20122
+ case "br":
20123
+ return "\n";
20124
+ case "strong":
20125
+ case "b":
20126
+ return `**${childContent()}**`;
20127
+ case "em":
20128
+ case "i":
20129
+ return `*${childContent()}*`;
20130
+ case "del":
20131
+ case "s":
20132
+ return `~~${childContent()}~~`;
20133
+ case "code": {
20134
+ if (el.parentElement?.tagName.toLowerCase() === "pre") {
20135
+ return childContent();
20136
+ }
20137
+ return `\`${childContent()}\``;
20138
+ }
20139
+ case "pre": {
20140
+ const codeEl = el.querySelector("code");
20141
+ const codeContent = codeEl ? codeEl.textContent || "" : el.textContent || "";
20142
+ const langClass = codeEl?.className?.match(/language-(\w+)/);
20143
+ const lang = langClass ? langClass[1] : "";
20144
+ return `\`\`\`${lang}
20145
+ ${codeContent.trim()}
20146
+ \`\`\`
20147
+
20148
+ `;
20149
+ }
20150
+ case "blockquote": {
20151
+ const inner = childContent().trim();
20152
+ return inner.split("\n").map((line) => `> ${line}`).join("\n") + "\n\n";
20153
+ }
20154
+ case "ul": {
20155
+ let result = "";
20156
+ el.childNodes.forEach((child) => {
20157
+ if (child.tagName?.toLowerCase() === "li") {
20158
+ const indent2 = " ".repeat(listDepth);
20159
+ const liContent = processListItem(child, listDepth);
20160
+ result += `${indent2}- ${liContent}
20161
+ `;
20162
+ }
20163
+ });
20164
+ return listDepth === 0 ? result + "\n" : result;
20165
+ }
20166
+ case "ol": {
20167
+ let result = "";
20168
+ let index = 1;
20169
+ el.childNodes.forEach((child) => {
20170
+ if (child.tagName?.toLowerCase() === "li") {
20171
+ const indent2 = " ".repeat(listDepth);
20172
+ const liContent = processListItem(child, listDepth);
20173
+ result += `${indent2}${index}. ${liContent}
20174
+ `;
20175
+ index++;
20176
+ }
20177
+ });
20178
+ return listDepth === 0 ? result + "\n" : result;
20179
+ }
20180
+ case "li": {
20181
+ return childContent();
20182
+ }
20183
+ case "a": {
20184
+ const href = el.getAttribute("href") || "";
20185
+ const text3 = childContent();
20186
+ return `[${text3}](${href})`;
20187
+ }
20188
+ case "img": {
20189
+ const src = el.getAttribute("src") || "";
20190
+ const alt = el.getAttribute("alt") || "";
20191
+ return `![${alt}](${src})`;
20192
+ }
20193
+ case "hr":
20194
+ return "---\n\n";
20195
+ case "table": {
20196
+ return processTable(el) + "\n";
20197
+ }
20198
+ case "input": {
20199
+ if (el.getAttribute("type") === "checkbox") {
20200
+ return el.hasAttribute("checked") ? "[x] " : "[ ] ";
20201
+ }
20202
+ return "";
20203
+ }
20204
+ case "div":
20205
+ case "span":
20206
+ case "section":
20207
+ case "article":
20208
+ case "main":
20209
+ case "header":
20210
+ case "footer":
20211
+ return childContent();
20212
+ default:
20213
+ return childContent();
20214
+ }
20215
+ }
20216
+ function processListItem(li, depth, _ordered) {
20217
+ let textParts = [];
20218
+ let subLists = "";
20219
+ li.childNodes.forEach((child) => {
20220
+ const childTag = child.tagName?.toLowerCase();
20221
+ if (childTag === "ul" || childTag === "ol") {
20222
+ subLists += processNode(child, depth + 1);
20223
+ } else {
20224
+ textParts.push(processNode(child, depth));
20225
+ }
20226
+ });
20227
+ let result = textParts.join("").trim();
20228
+ if (subLists) {
20229
+ result += "\n" + subLists;
20230
+ }
20231
+ return result;
20232
+ }
20233
+ function processTable(table) {
20234
+ const rows = [];
20235
+ table.querySelectorAll("tr").forEach((tr) => {
20236
+ const cells = [];
20237
+ tr.querySelectorAll("th, td").forEach((cell) => {
20238
+ cells.push((cell.textContent || "").trim());
20239
+ });
20240
+ rows.push(cells);
20241
+ });
20242
+ if (rows.length === 0) return "";
20243
+ const colCount = Math.max(...rows.map((r3) => r3.length));
20244
+ const colWidths = Array(colCount).fill(3);
20245
+ rows.forEach((row) => {
20246
+ row.forEach((cell, i) => {
20247
+ colWidths[i] = Math.max(colWidths[i], cell.length);
20248
+ });
20249
+ });
20250
+ let result = "";
20251
+ rows.forEach((row, rowIndex) => {
20252
+ const paddedCells = Array(colCount).fill("").map((_, i) => {
20253
+ const cell = row[i] || "";
20254
+ return cell.padEnd(colWidths[i]);
20255
+ });
20256
+ result += `| ${paddedCells.join(" | ")} |
20257
+ `;
20258
+ if (rowIndex === 0) {
20259
+ const separators = colWidths.map((w) => "-".repeat(w));
20260
+ result += `| ${separators.join(" | ")} |
20261
+ `;
20262
+ }
20263
+ });
20264
+ return result;
20265
+ }
20266
+ element.childNodes.forEach((child) => {
20267
+ lines.push(processNode(child));
20268
+ });
20269
+ return lines.join("").replace(/\n{3,}/g, "\n\n").trim() + "\n";
20270
+ }
20271
+ var MarkdownEditor = memo(function MarkdownEditor2({
20272
+ content,
20273
+ onChange,
20274
+ config
20275
+ }) {
20276
+ const editorRef = useRef(null);
20277
+ const textareaRef = useRef(null);
20278
+ const [isSourceMode, setIsSourceMode] = useState(false);
20279
+ const isInternalUpdate = useRef(false);
20280
+ const lastMarkdownRef = useRef(content);
20281
+ const contentToHtml = useCallback((markdown) => {
20282
+ return marked.parse(markdown, { breaks: true, gfm: true });
20283
+ }, []);
20284
+ useEffect(() => {
20285
+ if (isSourceMode) return;
20286
+ if (isInternalUpdate.current) {
20287
+ isInternalUpdate.current = false;
20288
+ return;
20289
+ }
20290
+ if (editorRef.current && content !== lastMarkdownRef.current) {
20291
+ const html2 = contentToHtml(content);
20292
+ editorRef.current.innerHTML = html2;
20293
+ lastMarkdownRef.current = content;
20294
+ }
20295
+ }, [content, isSourceMode, contentToHtml]);
20296
+ useEffect(() => {
20297
+ if (editorRef.current && !isSourceMode) {
20298
+ const html2 = contentToHtml(content);
20299
+ editorRef.current.innerHTML = html2;
20300
+ }
20301
+ }, []);
20302
+ const handleInput = useCallback(() => {
20303
+ if (!editorRef.current) return;
20304
+ const markdown = htmlToMarkdown(editorRef.current);
20305
+ lastMarkdownRef.current = markdown;
20306
+ isInternalUpdate.current = true;
20307
+ onChange(markdown);
20308
+ }, [onChange]);
20309
+ const execCommand = useCallback((command, value) => {
20310
+ editorRef.current?.focus();
20311
+ document.execCommand(command, false, value);
20312
+ requestAnimationFrame(() => handleInput());
20313
+ }, [handleInput]);
20314
+ const formatBlock = useCallback((tag) => {
20315
+ execCommand("formatBlock", tag);
20316
+ }, [execCommand]);
20317
+ const insertHorizontalRule = useCallback(() => {
20318
+ execCommand("insertHorizontalRule");
20319
+ }, [execCommand]);
20320
+ const insertLink = useCallback(() => {
20321
+ const selection = window.getSelection();
20322
+ const selectedText = selection?.toString() || "\u94FE\u63A5\u6587\u672C";
20323
+ const url = prompt("\u8BF7\u8F93\u5165\u94FE\u63A5\u5730\u5740:", "https://");
20324
+ if (url) {
20325
+ if (selection && selection.rangeCount > 0) {
20326
+ const range = selection.getRangeAt(0);
20327
+ range.deleteContents();
20328
+ const anchor = document.createElement("a");
20329
+ anchor.href = url;
20330
+ anchor.textContent = selectedText;
20331
+ range.insertNode(anchor);
20332
+ range.setStartAfter(anchor);
20333
+ range.collapse(true);
20334
+ selection.removeAllRanges();
20335
+ selection.addRange(range);
20336
+ }
20337
+ requestAnimationFrame(() => handleInput());
20338
+ }
20339
+ }, [handleInput]);
20340
+ const insertImage = useCallback(() => {
20341
+ const url = prompt("\u8BF7\u8F93\u5165\u56FE\u7247\u5730\u5740:", "https://");
20342
+ if (url) {
20343
+ execCommand("insertImage", url);
20344
+ }
20345
+ }, [execCommand]);
20346
+ const insertCodeBlock = useCallback(() => {
20347
+ const editor = editorRef.current;
20348
+ if (!editor) return;
20349
+ const selection = window.getSelection();
20350
+ if (selection && selection.rangeCount > 0) {
20351
+ const range = selection.getRangeAt(0);
20352
+ const pre = document.createElement("pre");
20353
+ const code3 = document.createElement("code");
20354
+ code3.textContent = selection.toString() || "\u4EE3\u7801\u5185\u5BB9";
20355
+ pre.appendChild(code3);
20356
+ range.deleteContents();
20357
+ range.insertNode(pre);
20358
+ const paragraph2 = document.createElement("p");
20359
+ paragraph2.innerHTML = "<br>";
20360
+ pre.parentNode?.insertBefore(paragraph2, pre.nextSibling);
20361
+ range.setStart(paragraph2, 0);
20362
+ range.collapse(true);
20363
+ selection.removeAllRanges();
20364
+ selection.addRange(range);
20365
+ }
20366
+ requestAnimationFrame(() => handleInput());
20367
+ }, [handleInput]);
20368
+ const handleKeyDown = useCallback((e) => {
20369
+ const isMod = e.metaKey || e.ctrlKey;
20370
+ if (isMod && e.key === "b") {
20371
+ e.preventDefault();
20372
+ execCommand("bold");
20373
+ } else if (isMod && e.key === "i") {
20374
+ e.preventDefault();
20375
+ execCommand("italic");
20376
+ } else if (isMod && e.key === "u") {
20377
+ e.preventDefault();
20378
+ execCommand("underline");
20379
+ } else if (isMod && e.key === "e") {
20380
+ e.preventDefault();
20381
+ const selection = window.getSelection();
20382
+ if (selection && selection.rangeCount > 0) {
20383
+ const selectedText = selection.toString() || "code";
20384
+ execCommand("insertHTML", `<code>${selectedText}</code>`);
20385
+ }
20386
+ } else if (e.key === "Tab") {
20387
+ e.preventDefault();
20388
+ execCommand("insertHTML", "&nbsp;&nbsp;&nbsp;&nbsp;");
20389
+ }
20390
+ }, [execCommand]);
20391
+ const handleSourceKeyDown = useCallback((e) => {
20392
+ if (e.key === "Tab") {
20393
+ e.preventDefault();
20394
+ const textarea = e.currentTarget;
20395
+ const start = textarea.selectionStart;
20396
+ const end = textarea.selectionEnd;
20397
+ const newValue = content.substring(0, start) + " " + content.substring(end);
20398
+ onChange(newValue);
20399
+ requestAnimationFrame(() => {
20400
+ textarea.selectionStart = textarea.selectionEnd = start + 2;
20401
+ });
20402
+ }
20403
+ }, [content, onChange]);
20404
+ const toggleSourceMode = useCallback(() => {
20405
+ if (isSourceMode) {
20406
+ setIsSourceMode(false);
20407
+ requestAnimationFrame(() => {
20408
+ if (editorRef.current) {
20409
+ const html2 = contentToHtml(content);
20410
+ editorRef.current.innerHTML = html2;
20411
+ lastMarkdownRef.current = content;
20412
+ }
20413
+ });
20414
+ } else {
20415
+ if (editorRef.current) {
20416
+ const markdown = htmlToMarkdown(editorRef.current);
20417
+ lastMarkdownRef.current = markdown;
20418
+ isInternalUpdate.current = true;
20419
+ onChange(markdown);
20420
+ }
20421
+ setIsSourceMode(true);
20422
+ }
20423
+ }, [isSourceMode, content, contentToHtml, onChange]);
20424
+ const toolbarGroups = useMemo(() => [
20425
+ {
20426
+ items: [
20427
+ { icon: /* @__PURE__ */ jsx("span", { className: "font-bold text-[11px]", children: "B" }), label: "\u52A0\u7C97 (\u2318B)", onClick: () => execCommand("bold") },
20428
+ { icon: /* @__PURE__ */ jsx("span", { className: "italic text-[11px]", children: "I" }), label: "\u659C\u4F53 (\u2318I)", onClick: () => execCommand("italic") },
20429
+ { icon: /* @__PURE__ */ jsx("span", { className: "line-through text-[11px]", children: "S" }), label: "\u5220\u9664\u7EBF", onClick: () => execCommand("strikeThrough") },
20430
+ { icon: /* @__PURE__ */ jsx(Code2, { size: 13 }), label: "\u884C\u5185\u4EE3\u7801 (\u2318E)", onClick: () => {
20431
+ const selection = window.getSelection();
20432
+ const text3 = selection?.toString() || "code";
20433
+ execCommand("insertHTML", `<code>${text3}</code>`);
20434
+ } }
20435
+ ]
20436
+ },
20437
+ {
20438
+ items: [
20439
+ { icon: /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold", children: "H1" }), label: "\u4E00\u7EA7\u6807\u9898", onClick: () => formatBlock("h1") },
20440
+ { icon: /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold", children: "H2" }), label: "\u4E8C\u7EA7\u6807\u9898", onClick: () => formatBlock("h2") },
20441
+ { icon: /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold", children: "H3" }), label: "\u4E09\u7EA7\u6807\u9898", onClick: () => formatBlock("h3") }
20442
+ ]
20443
+ },
20444
+ {
20445
+ items: [
20446
+ { icon: /* @__PURE__ */ jsx("span", { className: "text-[11px]", children: "\u2022" }), label: "\u65E0\u5E8F\u5217\u8868", onClick: () => execCommand("insertUnorderedList") },
20447
+ { icon: /* @__PURE__ */ jsx("span", { className: "text-[11px]", children: "1." }), label: "\u6709\u5E8F\u5217\u8868", onClick: () => execCommand("insertOrderedList") },
20448
+ { icon: /* @__PURE__ */ jsx("span", { className: "text-[11px]", children: "\u275D" }), label: "\u5F15\u7528", onClick: () => formatBlock("blockquote") }
20449
+ ]
20450
+ },
20451
+ {
20452
+ items: [
20453
+ { icon: /* @__PURE__ */ jsx("span", { className: "text-[11px]", children: "\u2014" }), label: "\u5206\u5272\u7EBF", onClick: insertHorizontalRule },
20454
+ { icon: /* @__PURE__ */ jsx(Globe, { size: 13 }), label: "\u94FE\u63A5", onClick: insertLink },
20455
+ { icon: /* @__PURE__ */ jsx(FileImage, { size: 13 }), label: "\u56FE\u7247", onClick: insertImage },
20456
+ { icon: /* @__PURE__ */ jsx(Code2, { size: 13, className: "opacity-60" }), label: "\u4EE3\u7801\u5757", onClick: insertCodeBlock }
20457
+ ]
20458
+ }
20459
+ ], [execCommand, formatBlock, insertHorizontalRule, insertLink, insertImage, insertCodeBlock]);
20460
+ return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col bg-zinc-950 agent-sdk-light:bg-white", children: [
20461
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 px-3 py-1.5 border-b border-zinc-800/50 agent-sdk-light:border-zinc-200 bg-zinc-900/50 agent-sdk-light:bg-zinc-50 flex-shrink-0 overflow-x-auto", style: { scrollbarWidth: "none" }, children: [
20462
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 mr-2", children: [
20463
+ /* @__PURE__ */ jsx(Pencil, { size: 12, className: "text-[#d8ff00]" }),
20464
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-[#d8ff00] font-medium whitespace-nowrap", children: isSourceMode ? "Markdown \u6E90\u7801" : "\u5BCC\u6587\u672C\u7F16\u8F91" })
20465
+ ] }),
20466
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-zinc-700/50 agent-sdk-light:bg-zinc-300 mx-1" }),
20467
+ !isSourceMode && toolbarGroups.map((group, groupIndex) => /* @__PURE__ */ jsxs(React20__default.Fragment, { children: [
20468
+ group.items.map((action, actionIndex) => /* @__PURE__ */ jsx(
20469
+ "button",
20470
+ {
20471
+ onClick: action.onClick,
20472
+ className: "p-1.5 min-w-[28px] h-7 flex items-center justify-center text-zinc-400 agent-sdk-light:text-zinc-600 hover:text-zinc-100 agent-sdk-light:hover:text-zinc-900 hover:bg-zinc-700/50 agent-sdk-light:hover:bg-zinc-200 rounded transition-colors",
20473
+ title: action.label,
20474
+ children: action.icon
20475
+ },
20476
+ actionIndex
20477
+ )),
20478
+ groupIndex < toolbarGroups.length - 1 && /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-zinc-700/50 agent-sdk-light:bg-zinc-300 mx-0.5" })
20479
+ ] }, groupIndex)),
20480
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-zinc-700/50 agent-sdk-light:bg-zinc-300 mx-1 ml-auto" }),
20481
+ /* @__PURE__ */ jsxs(
20482
+ "button",
20483
+ {
20484
+ onClick: toggleSourceMode,
20485
+ className: cn2(
20486
+ "p-1.5 flex items-center gap-1 text-[11px] rounded transition-colors whitespace-nowrap",
20487
+ isSourceMode ? "bg-[#d8ff00]/10 text-[#d8ff00]" : "text-zinc-400 agent-sdk-light:text-zinc-600 hover:text-zinc-100 agent-sdk-light:hover:text-zinc-900 hover:bg-zinc-700/50 agent-sdk-light:hover:bg-zinc-200"
20488
+ ),
20489
+ title: isSourceMode ? "\u5207\u6362\u5230\u5BCC\u6587\u672C\u6A21\u5F0F" : "\u5207\u6362\u5230\u6E90\u7801\u6A21\u5F0F",
20490
+ children: [
20491
+ isSourceMode ? /* @__PURE__ */ jsx(Eye, { size: 13 }) : /* @__PURE__ */ jsx(Code2, { size: 13 }),
20492
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: isSourceMode ? "\u5BCC\u6587\u672C" : "\u6E90\u7801" })
20493
+ ]
20494
+ }
20495
+ )
20496
+ ] }),
20497
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-hidden", children: isSourceMode ? (
20498
+ /* 源码编辑模式 */
20499
+ /* @__PURE__ */ jsx(
20500
+ "textarea",
20501
+ {
20502
+ ref: textareaRef,
20503
+ value: content,
20504
+ onChange: (e) => onChange(e.target.value),
20505
+ onKeyDown: handleSourceKeyDown,
20506
+ className: "w-full h-full p-5 bg-zinc-950 agent-sdk-light:bg-white text-sm text-zinc-300 agent-sdk-light:text-zinc-800 leading-[1.8] resize-none focus:outline-none",
20507
+ style: { fontFamily: '"SF Mono", "Fira Code", "JetBrains Mono", Menlo, Monaco, monospace' },
20508
+ spellCheck: false,
20509
+ autoComplete: "off",
20510
+ autoCorrect: "off",
20511
+ autoCapitalize: "off",
20512
+ placeholder: "\u7F16\u5199 Markdown \u6E90\u7801..."
20513
+ }
20514
+ )
20515
+ ) : (
20516
+ /* WYSIWYG 富文本编辑模式 */
20517
+ /* @__PURE__ */ jsx(
20518
+ "div",
20519
+ {
20520
+ ref: editorRef,
20521
+ contentEditable: true,
20522
+ suppressContentEditableWarning: true,
20523
+ onInput: handleInput,
20524
+ onKeyDown: handleKeyDown,
20525
+ className: "w-full h-full p-5 overflow-auto bg-zinc-950 agent-sdk-light:bg-white text-sm text-zinc-300 agent-sdk-light:text-zinc-800 leading-[1.8] focus:outline-none prose prose-invert prose-zinc agent-sdk-light:prose prose-sm max-w-none\n [&_h1]:text-2xl [&_h1]:font-bold [&_h1]:text-zinc-100 [&_h1]:agent-sdk-light:text-zinc-900 [&_h1]:mb-4 [&_h1]:mt-6 [&_h1]:border-b [&_h1]:border-zinc-800/30 [&_h1]:agent-sdk-light:border-zinc-200 [&_h1]:pb-2\n [&_h2]:text-xl [&_h2]:font-bold [&_h2]:text-zinc-200 [&_h2]:agent-sdk-light:text-zinc-800 [&_h2]:mb-3 [&_h2]:mt-5\n [&_h3]:text-lg [&_h3]:font-semibold [&_h3]:text-zinc-200 [&_h3]:agent-sdk-light:text-zinc-800 [&_h3]:mb-2 [&_h3]:mt-4\n [&_p]:mb-3 [&_p]:leading-relaxed\n [&_strong]:text-zinc-100 [&_strong]:agent-sdk-light:text-zinc-900 [&_strong]:font-semibold\n [&_em]:text-zinc-300 [&_em]:agent-sdk-light:text-zinc-700\n [&_code]:bg-zinc-800/60 [&_code]:agent-sdk-light:bg-zinc-100 [&_code]:text-[#d8ff00] [&_code]:agent-sdk-light:text-pink-600 [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-[13px] [&_code]:font-mono\n [&_pre]:bg-zinc-900/80 [&_pre]:agent-sdk-light:bg-zinc-50 [&_pre]:border [&_pre]:border-zinc-800/50 [&_pre]:agent-sdk-light:border-zinc-200 [&_pre]:rounded-lg [&_pre]:p-4 [&_pre]:my-3 [&_pre]:overflow-x-auto\n [&_pre_code]:bg-transparent [&_pre_code]:p-0 [&_pre_code]:text-zinc-300 [&_pre_code]:agent-sdk-light:text-zinc-800\n [&_blockquote]:border-l-3 [&_blockquote]:border-[#d8ff00]/40 [&_blockquote]:pl-4 [&_blockquote]:my-3 [&_blockquote]:text-zinc-400 [&_blockquote]:agent-sdk-light:text-zinc-600 [&_blockquote]:italic\n [&_ul]:list-disc [&_ul]:pl-6 [&_ul]:my-2\n [&_ol]:list-decimal [&_ol]:pl-6 [&_ol]:my-2\n [&_li]:mb-1\n [&_a]:text-[#d8ff00] [&_a]:agent-sdk-light:text-blue-600 [&_a]:underline [&_a]:underline-offset-2\n [&_hr]:border-zinc-700/50 [&_hr]:agent-sdk-light:border-zinc-300 [&_hr]:my-6\n [&_img]:max-w-full [&_img]:rounded-lg [&_img]:my-3\n [&_table]:w-full [&_table]:border-collapse [&_table]:my-3\n [&_th]:border [&_th]:border-zinc-700/50 [&_th]:agent-sdk-light:border-zinc-300 [&_th]:px-3 [&_th]:py-2 [&_th]:bg-zinc-800/30 [&_th]:agent-sdk-light:bg-zinc-100 [&_th]:text-left [&_th]:font-medium\n [&_td]:border [&_td]:border-zinc-700/50 [&_td]:agent-sdk-light:border-zinc-300 [&_td]:px-3 [&_td]:py-2",
20526
+ "data-placeholder": "\u5F00\u59CB\u7F16\u5199\u5185\u5BB9..."
20527
+ }
20528
+ )
20529
+ ) })
20530
+ ] });
20531
+ });
20532
+ var ArtifactThumbnail = memo(function ArtifactThumbnail2({
20533
+ artifact,
20534
+ config
20535
+ }) {
20536
+ const typeConf = artifactTypeConfig[artifact.type] || artifactTypeConfig.text;
20537
+ const TypeIcon = typeConf.icon;
20538
+ const isMedia = artifact.type === "image" || artifact.type === "video";
20539
+ const thumbnailUrl = useResolvedThumbnailUrl(
20540
+ artifact.currentContent,
20541
+ {
20542
+ fileId: artifact.metadata?.fileId,
20543
+ type: artifact.type,
20544
+ config,
20545
+ enabled: isMedia
20546
+ }
20547
+ );
20548
+ if (isMedia && thumbnailUrl) {
20549
+ return /* @__PURE__ */ jsx(
20550
+ "img",
20551
+ {
20552
+ src: thumbnailUrl,
20553
+ alt: "",
20554
+ className: "w-6 h-6 rounded object-cover flex-shrink-0",
20555
+ loading: "lazy"
20556
+ }
20557
+ );
20558
+ }
20559
+ return /* @__PURE__ */ jsx("div", { className: cn2("w-6 h-6 rounded flex items-center justify-center flex-shrink-0", typeConf.bgColor), children: /* @__PURE__ */ jsx(TypeIcon, { size: 12, className: typeConf.color }) });
20560
+ });
20561
+ var ArtifactTabs = memo(function ArtifactTabs2({
20562
+ artifacts,
20563
+ activeId,
20564
+ onSwitch,
20565
+ onClose,
20566
+ onReorder,
20567
+ config
20568
+ }) {
20569
+ const scrollContainerRef = useRef(null);
20570
+ const [canScrollLeft, setCanScrollLeft] = useState(false);
20571
+ const [canScrollRight, setCanScrollRight] = useState(false);
20572
+ const [showAllPanel, setShowAllPanel] = useState(false);
20573
+ const allPanelRef = useRef(null);
20574
+ const [dragState, setDragState] = useState({ draggingId: null, dragOverId: null, dragStartX: 0, isDragging: false });
20575
+ const checkScrollState = useCallback(() => {
20576
+ const container = scrollContainerRef.current;
20577
+ if (!container) return;
20578
+ setCanScrollLeft(container.scrollLeft > 2);
20579
+ setCanScrollRight(container.scrollLeft < container.scrollWidth - container.clientWidth - 2);
20580
+ }, []);
20581
+ useEffect(() => {
20582
+ checkScrollState();
20583
+ const container = scrollContainerRef.current;
20584
+ if (!container) return;
20585
+ container.addEventListener("scroll", checkScrollState, { passive: true });
20586
+ const resizeObserver = new ResizeObserver(checkScrollState);
20587
+ resizeObserver.observe(container);
20588
+ return () => {
20589
+ container.removeEventListener("scroll", checkScrollState);
20590
+ resizeObserver.disconnect();
20591
+ };
20592
+ }, [checkScrollState, artifacts.length]);
20593
+ useEffect(() => {
20594
+ if (!showAllPanel) return;
20595
+ const handleClickOutside = (e) => {
20596
+ if (allPanelRef.current && !allPanelRef.current.contains(e.target)) {
20597
+ setShowAllPanel(false);
20598
+ }
20599
+ };
20600
+ document.addEventListener("mousedown", handleClickOutside);
20601
+ return () => document.removeEventListener("mousedown", handleClickOutside);
20602
+ }, [showAllPanel]);
20603
+ const scrollBy = useCallback((direction) => {
20604
+ const container = scrollContainerRef.current;
20605
+ if (!container) return;
20606
+ const scrollAmount = 200;
20607
+ container.scrollBy({
20608
+ left: direction === "left" ? -scrollAmount : scrollAmount,
20609
+ behavior: "smooth"
20610
+ });
20611
+ }, []);
20612
+ const handleDragStart = useCallback((e, artifactId) => {
20613
+ e.dataTransfer.effectAllowed = "move";
20614
+ e.dataTransfer.setData("text/plain", artifactId);
20615
+ setDragState((prev) => ({ ...prev, draggingId: artifactId, dragStartX: e.clientX, isDragging: true }));
20616
+ }, []);
20617
+ const handleDragOver = useCallback((e, artifactId) => {
20618
+ e.preventDefault();
20619
+ e.dataTransfer.dropEffect = "move";
20620
+ setDragState((prev) => ({ ...prev, dragOverId: artifactId }));
20621
+ }, []);
20622
+ const handleDragEnd = useCallback(() => {
20623
+ setDragState({ draggingId: null, dragOverId: null, dragStartX: 0, isDragging: false });
20624
+ }, []);
20625
+ const handleDrop = useCallback((e, targetId) => {
20626
+ e.preventDefault();
20627
+ const sourceId = e.dataTransfer.getData("text/plain");
20628
+ if (!sourceId || sourceId === targetId || !onReorder) {
20629
+ handleDragEnd();
20630
+ return;
20631
+ }
20632
+ const fromIndex = artifacts.findIndex((a) => a.id === sourceId);
20633
+ const toIndex = artifacts.findIndex((a) => a.id === targetId);
20634
+ if (fromIndex !== -1 && toIndex !== -1 && fromIndex !== toIndex) {
20635
+ onReorder(fromIndex, toIndex);
20636
+ }
20637
+ handleDragEnd();
20638
+ }, [artifacts, onReorder, handleDragEnd]);
20639
+ const handleCloseTab = useCallback((e, artifactId) => {
20640
+ e.stopPropagation();
20641
+ if (!onClose) return;
20642
+ if (artifactId === activeId && artifacts.length > 1) {
20643
+ const currentIndex = artifacts.findIndex((a) => a.id === artifactId);
20644
+ const nextIndex = currentIndex < artifacts.length - 1 ? currentIndex + 1 : currentIndex - 1;
20645
+ if (nextIndex >= 0 && nextIndex < artifacts.length) {
20646
+ onSwitch(artifacts[nextIndex].id);
20647
+ }
20648
+ }
20649
+ onClose(artifactId);
20650
+ }, [onClose, activeId, artifacts, onSwitch]);
20651
+ if (artifacts.length <= 1) return null;
20652
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center border-b border-zinc-800/50 agent-sdk-light:border-zinc-200 bg-zinc-950/50 agent-sdk-light:bg-zinc-100 flex-shrink-0 relative", children: [
20653
+ canScrollLeft && /* @__PURE__ */ jsx(
20654
+ "button",
20655
+ {
20656
+ onClick: () => scrollBy("left"),
20657
+ className: "flex-shrink-0 p-1 text-zinc-500 hover:text-zinc-300 hover:bg-zinc-800/50 transition-colors z-10",
20658
+ children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
20659
+ }
20660
+ ),
20661
+ /* @__PURE__ */ jsx(
20662
+ "div",
20663
+ {
20664
+ ref: scrollContainerRef,
20665
+ className: "flex items-center gap-0.5 px-1 py-1 overflow-x-auto flex-1 min-w-0",
20666
+ style: { scrollbarWidth: "none", msOverflowStyle: "none" },
20667
+ children: artifacts.map((artifact) => {
20668
+ const typeConf = artifactTypeConfig[artifact.type] || artifactTypeConfig.text;
20669
+ const isActive = artifact.id === activeId;
20670
+ const isDragging = dragState.draggingId === artifact.id;
20671
+ const isDragOver = dragState.dragOverId === artifact.id && dragState.draggingId !== artifact.id;
20672
+ const TypeIcon = typeConf.icon;
20673
+ return /* @__PURE__ */ jsxs(
20674
+ "div",
20675
+ {
20676
+ draggable: !!onReorder,
20677
+ onDragStart: (e) => handleDragStart(e, artifact.id),
20678
+ onDragOver: (e) => handleDragOver(e, artifact.id),
20679
+ onDragEnd: handleDragEnd,
20680
+ onDrop: (e) => handleDrop(e, artifact.id),
20681
+ onClick: () => onSwitch(artifact.id),
20682
+ className: cn2(
20683
+ "group/tab flex items-center gap-1 pl-2.5 pr-1 py-1 text-xs rounded-md transition-all whitespace-nowrap flex-shrink-0 cursor-pointer select-none",
20684
+ isActive ? "bg-zinc-800 text-zinc-100 agent-sdk-light:bg-zinc-200 agent-sdk-light:text-zinc-900" : "text-zinc-500 agent-sdk-light:text-zinc-600 hover:text-zinc-300 agent-sdk-light:hover:text-zinc-900 hover:bg-zinc-800/50 agent-sdk-light:hover:bg-zinc-200/50",
20685
+ isDragging && "opacity-40",
20686
+ isDragOver && "ring-1 ring-[#d8ff00]/50",
20687
+ onReorder && "cursor-grab active:cursor-grabbing"
20688
+ ),
20689
+ title: artifact.title,
20690
+ children: [
20691
+ /* @__PURE__ */ jsx(TypeIcon, { size: 12, className: cn2("flex-shrink-0", isActive ? typeConf.color : "") }),
20692
+ /* @__PURE__ */ jsx("span", { className: "max-w-[120px] truncate", children: artifact.title }),
20693
+ onClose && /* @__PURE__ */ jsx(
20694
+ "button",
20695
+ {
20696
+ onClick: (e) => handleCloseTab(e, artifact.id),
20697
+ className: cn2(
20698
+ "ml-0.5 p-0.5 rounded transition-colors flex-shrink-0",
20699
+ isActive ? "text-zinc-400 hover:text-zinc-100 hover:bg-zinc-700" : "text-transparent group-hover/tab:text-zinc-500 hover:!text-zinc-300 hover:!bg-zinc-700"
20700
+ ),
20701
+ title: "\u5173\u95ED",
20702
+ children: /* @__PURE__ */ jsx(X, { size: 10 })
20703
+ }
20704
+ )
20705
+ ]
20706
+ },
20707
+ artifact.id
20708
+ );
20709
+ })
20710
+ }
20711
+ ),
20712
+ canScrollRight && /* @__PURE__ */ jsx(
20713
+ "button",
20714
+ {
20715
+ onClick: () => scrollBy("right"),
20716
+ className: "flex-shrink-0 p-1 text-zinc-500 hover:text-zinc-300 hover:bg-zinc-800/50 transition-colors z-10",
20717
+ children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
20718
+ }
20719
+ ),
20720
+ artifacts.length > 0 && /* @__PURE__ */ jsxs("div", { className: "relative flex-shrink-0", ref: allPanelRef, children: [
20721
+ /* @__PURE__ */ jsx(
20722
+ "button",
20723
+ {
20724
+ onClick: () => setShowAllPanel((prev) => !prev),
20725
+ className: cn2(
20726
+ "p-1.5 mr-1 text-zinc-500 hover:text-zinc-300 hover:bg-zinc-800/50 rounded transition-colors",
20727
+ showAllPanel && "bg-zinc-800 text-zinc-300"
20728
+ ),
20729
+ title: "\u5168\u90E8\u4EA7\u7269",
20730
+ children: /* @__PURE__ */ jsx(LayoutGrid, { size: 14 })
20731
+ }
20732
+ ),
20733
+ showAllPanel && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 top-full mt-1 z-50 w-72 max-h-80 overflow-y-auto bg-zinc-900 agent-sdk-light:bg-white border border-zinc-700 agent-sdk-light:border-zinc-300 rounded-lg shadow-xl", children: [
20734
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-2 border-b border-zinc-800 agent-sdk-light:border-zinc-200", children: /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-zinc-400 agent-sdk-light:text-zinc-600", children: [
20735
+ "\u5168\u90E8\u4EA7\u7269 (",
20736
+ artifacts.length,
20737
+ ")"
20738
+ ] }) }),
20739
+ /* @__PURE__ */ jsx("div", { className: "p-1.5 grid grid-cols-1 gap-0.5", children: artifacts.map((artifact) => {
20740
+ const typeConf = artifactTypeConfig[artifact.type] || artifactTypeConfig.text;
20741
+ const isActive = artifact.id === activeId;
20742
+ typeConf.icon;
20743
+ return /* @__PURE__ */ jsxs(
20744
+ "button",
20745
+ {
20746
+ onClick: () => {
20747
+ onSwitch(artifact.id);
20748
+ setShowAllPanel(false);
20749
+ },
20750
+ className: cn2(
20751
+ "flex items-center gap-2.5 px-2.5 py-2 text-xs rounded-md transition-all w-full text-left",
20752
+ isActive ? "bg-zinc-800 text-zinc-100 agent-sdk-light:bg-zinc-100 agent-sdk-light:text-zinc-900" : "text-zinc-400 agent-sdk-light:text-zinc-600 hover:text-zinc-200 agent-sdk-light:hover:text-zinc-900 hover:bg-zinc-800/50 agent-sdk-light:hover:bg-zinc-100"
20753
+ ),
20754
+ children: [
20755
+ /* @__PURE__ */ jsx(ArtifactThumbnail, { artifact, config }),
20756
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
20757
+ /* @__PURE__ */ jsx("div", { className: "truncate font-medium", children: artifact.title }),
20758
+ /* @__PURE__ */ jsxs("div", { className: "text-[10px] text-zinc-600 agent-sdk-light:text-zinc-500 mt-0.5", children: [
20759
+ typeConf.label,
20760
+ artifact.language && artifact.language !== artifact.type && ` \u2022 ${artifact.language}`
20761
+ ] })
20762
+ ] }),
20763
+ onClose && /* @__PURE__ */ jsx(
20764
+ "button",
20765
+ {
20766
+ onClick: (e) => {
20767
+ e.stopPropagation();
20768
+ handleCloseTab(e, artifact.id);
20769
+ },
20770
+ className: "p-1 text-zinc-600 hover:text-zinc-300 hover:bg-zinc-700 rounded transition-colors flex-shrink-0",
20771
+ title: "\u5173\u95ED",
20772
+ children: /* @__PURE__ */ jsx(X, { size: 12 })
20773
+ }
20774
+ )
20775
+ ]
20776
+ },
20777
+ artifact.id
20778
+ );
20779
+ }) })
20780
+ ] })
20781
+ ] })
20782
+ ] });
20783
+ });
18793
20784
  var ArtifactViewer = memo(function ArtifactViewer2({
18794
20785
  artifact,
18795
20786
  isOpen,
@@ -18798,41 +20789,127 @@ var ArtifactViewer = memo(function ArtifactViewer2({
18798
20789
  defaultView = "preview",
18799
20790
  isFullscreen,
18800
20791
  onFullscreenToggle,
18801
- embedded = false
20792
+ embedded = false,
20793
+ artifacts = [],
20794
+ activeArtifactId,
20795
+ onSwitchArtifact,
20796
+ onCloseArtifact,
20797
+ onReorderArtifacts,
20798
+ onContentChange,
20799
+ onSave
18802
20800
  }) {
18803
20801
  const [viewMode, setViewMode] = useState(defaultView);
20802
+ const [isEditing, setIsEditing] = useState(false);
20803
+ const [editContent, setEditContent] = useState("");
20804
+ const [undoStack, setUndoStack] = useState([]);
20805
+ const [redoStack, setRedoStack] = useState([]);
18804
20806
  useEffect(() => {
18805
20807
  if (artifact) {
18806
- if (artifact.type === "html" || artifact.type === "markdown") {
20808
+ if (artifact.type === "html" || artifact.type === "markdown" || artifact.type === "svg") {
18807
20809
  setViewMode("preview");
18808
20810
  } else {
18809
20811
  setViewMode("code");
18810
20812
  }
20813
+ setIsEditing(false);
20814
+ setEditContent(artifact.content);
20815
+ setUndoStack([]);
20816
+ setRedoStack([]);
18811
20817
  }
18812
20818
  }, [artifact?.id]);
20819
+ useEffect(() => {
20820
+ if (artifact && !isEditing) {
20821
+ setEditContent(artifact.content);
20822
+ }
20823
+ }, [artifact?.content, isEditing]);
18813
20824
  if (!artifact) return null;
18814
- const typeConfig = artifactTypeConfig[artifact.type];
18815
- const canPreview = artifact.type === "html" || artifact.type === "markdown";
20825
+ const typeConfig = artifactTypeConfig[artifact.type] || artifactTypeConfig.text;
20826
+ const canPreview = artifact.type === "html" || artifact.type === "markdown" || artifact.type === "svg";
20827
+ const canEdit = artifact.type !== "image" && artifact.type !== "video";
20828
+ const handleStartEdit = () => {
20829
+ setEditContent(artifact.content);
20830
+ setUndoStack([artifact.content]);
20831
+ setRedoStack([]);
20832
+ setIsEditing(true);
20833
+ setViewMode("code");
20834
+ };
20835
+ const handleEditChange = (newContent) => {
20836
+ setUndoStack((prev) => [...prev, editContent]);
20837
+ setRedoStack([]);
20838
+ setEditContent(newContent);
20839
+ onContentChange?.(newContent);
20840
+ };
20841
+ const handleUndo = () => {
20842
+ if (undoStack.length === 0) return;
20843
+ const previous2 = undoStack[undoStack.length - 1];
20844
+ setUndoStack((prev) => prev.slice(0, -1));
20845
+ setRedoStack((prev) => [...prev, editContent]);
20846
+ setEditContent(previous2);
20847
+ onContentChange?.(previous2);
20848
+ };
20849
+ const handleRedo = () => {
20850
+ if (redoStack.length === 0) return;
20851
+ const next = redoStack[redoStack.length - 1];
20852
+ setRedoStack((prev) => prev.slice(0, -1));
20853
+ setUndoStack((prev) => [...prev, editContent]);
20854
+ setEditContent(next);
20855
+ onContentChange?.(next);
20856
+ };
20857
+ const handleSave = () => {
20858
+ onSave?.(artifact.id, editContent);
20859
+ setIsEditing(false);
20860
+ };
20861
+ const handleCancelEdit = () => {
20862
+ setEditContent(artifact.content);
20863
+ setIsEditing(false);
20864
+ };
20865
+ const displayContent = isEditing ? editContent : artifact.content;
18816
20866
  const renderContent = () => {
20867
+ if (isEditing) {
20868
+ if (artifact.type === "markdown") {
20869
+ return /* @__PURE__ */ jsx(
20870
+ MarkdownEditor,
20871
+ {
20872
+ content: editContent,
20873
+ onChange: handleEditChange,
20874
+ config
20875
+ }
20876
+ );
20877
+ }
20878
+ return /* @__PURE__ */ jsx(
20879
+ CodeEditor,
20880
+ {
20881
+ code: editContent,
20882
+ language: artifact.language || artifact.type,
20883
+ onChange: handleEditChange
20884
+ }
20885
+ );
20886
+ }
20887
+ if (artifact.type === "image") {
20888
+ return /* @__PURE__ */ jsx(ImageArtifactPreview, { content: displayContent, metadata: artifact.metadata, config });
20889
+ }
20890
+ if (artifact.type === "video") {
20891
+ return /* @__PURE__ */ jsx(VideoArtifactPreview, { content: displayContent, metadata: artifact.metadata, config });
20892
+ }
18817
20893
  if (viewMode === "code" || !canPreview) {
18818
20894
  return /* @__PURE__ */ jsx(
18819
20895
  CodeBlock3,
18820
20896
  {
18821
- code: artifact.content,
20897
+ code: displayContent,
18822
20898
  language: artifact.language || artifact.type
18823
20899
  }
18824
20900
  );
18825
20901
  }
18826
20902
  switch (artifact.type) {
18827
20903
  case "html":
18828
- return /* @__PURE__ */ jsx(HtmlPreview3, { content: artifact.content });
20904
+ case "svg":
20905
+ return /* @__PURE__ */ jsx(HtmlPreview3, { content: displayContent });
18829
20906
  case "markdown":
18830
- return /* @__PURE__ */ jsx(MarkdownPreview, { content: artifact.content, config });
20907
+ return /* @__PURE__ */ jsx(MarkdownPreview, { content: displayContent, config });
18831
20908
  default:
18832
20909
  return /* @__PURE__ */ jsx(
18833
20910
  CodeBlock3,
18834
20911
  {
18835
- code: artifact.content,
20912
+ code: displayContent,
18836
20913
  language: artifact.language || artifact.type
18837
20914
  }
18838
20915
  );
@@ -18855,26 +20932,79 @@ var ArtifactViewer = memo(function ArtifactViewer2({
18855
20932
  ] })
18856
20933
  ] }),
18857
20934
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
18858
- onFullscreenToggle && /* @__PURE__ */ jsx(
18859
- "button",
18860
- {
18861
- onClick: onFullscreenToggle,
18862
- className: "p-1.5 text-zinc-500 agent-sdk-light:text-zinc-600 hover:text-zinc-300 agent-sdk-light:hover:text-zinc-900 hover:bg-zinc-800 agent-sdk-light:hover:bg-zinc-200 rounded-lg transition-colors",
18863
- title: isFullscreen ? "\u9000\u51FA\u5168\u5C4F" : "\u5168\u5C4F",
18864
- children: isFullscreen ? /* @__PURE__ */ jsx(Minimize2, { size: 14 }) : /* @__PURE__ */ jsx(Maximize2, { size: 14 })
18865
- }
18866
- ),
18867
- canPreview && /* @__PURE__ */ jsx(
18868
- ViewTabs,
18869
- {
18870
- activeView: viewMode,
18871
- onViewChange: (v) => setViewMode(v),
18872
- views: [
18873
- { id: "preview", label: "Preview", icon: /* @__PURE__ */ jsx(Eye, { size: 12 }) },
18874
- { id: "code", label: "Code", icon: /* @__PURE__ */ jsx(Code2, { size: 12 }) }
18875
- ]
18876
- }
18877
- ),
20935
+ isEditing ? /* @__PURE__ */ jsxs(Fragment, { children: [
20936
+ /* @__PURE__ */ jsx(
20937
+ "button",
20938
+ {
20939
+ onClick: handleUndo,
20940
+ disabled: undoStack.length === 0,
20941
+ className: "p-1.5 text-zinc-500 hover:text-zinc-300 hover:bg-zinc-800 rounded-lg transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
20942
+ title: "\u64A4\u9500",
20943
+ children: /* @__PURE__ */ jsx(Undo2, { size: 14 })
20944
+ }
20945
+ ),
20946
+ /* @__PURE__ */ jsx(
20947
+ "button",
20948
+ {
20949
+ onClick: handleRedo,
20950
+ disabled: redoStack.length === 0,
20951
+ className: "p-1.5 text-zinc-500 hover:text-zinc-300 hover:bg-zinc-800 rounded-lg transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
20952
+ title: "\u91CD\u505A",
20953
+ children: /* @__PURE__ */ jsx(Redo2, { size: 14 })
20954
+ }
20955
+ ),
20956
+ /* @__PURE__ */ jsxs(
20957
+ "button",
20958
+ {
20959
+ onClick: handleSave,
20960
+ className: "flex items-center gap-1 px-2.5 py-1 text-xs bg-[#d8ff00] hover:bg-[#e5ff4d] text-black rounded-lg transition-colors font-medium",
20961
+ title: "\u4FDD\u5B58",
20962
+ children: [
20963
+ /* @__PURE__ */ jsx(Save, { size: 12 }),
20964
+ "\u4FDD\u5B58"
20965
+ ]
20966
+ }
20967
+ ),
20968
+ /* @__PURE__ */ jsx(
20969
+ "button",
20970
+ {
20971
+ onClick: handleCancelEdit,
20972
+ className: "px-2.5 py-1 text-xs text-zinc-400 hover:text-zinc-200 hover:bg-zinc-800 rounded-lg transition-colors",
20973
+ title: "\u53D6\u6D88\u7F16\u8F91",
20974
+ children: "\u53D6\u6D88"
20975
+ }
20976
+ )
20977
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
20978
+ canEdit && onContentChange && /* @__PURE__ */ jsx(
20979
+ "button",
20980
+ {
20981
+ onClick: handleStartEdit,
20982
+ className: "p-1.5 text-zinc-500 agent-sdk-light:text-zinc-600 hover:text-zinc-300 agent-sdk-light:hover:text-zinc-900 hover:bg-zinc-800 agent-sdk-light:hover:bg-zinc-200 rounded-lg transition-colors",
20983
+ title: "\u7F16\u8F91",
20984
+ children: /* @__PURE__ */ jsx(Pencil, { size: 14 })
20985
+ }
20986
+ ),
20987
+ onFullscreenToggle && /* @__PURE__ */ jsx(
20988
+ "button",
20989
+ {
20990
+ onClick: onFullscreenToggle,
20991
+ className: "p-1.5 text-zinc-500 agent-sdk-light:text-zinc-600 hover:text-zinc-300 agent-sdk-light:hover:text-zinc-900 hover:bg-zinc-800 agent-sdk-light:hover:bg-zinc-200 rounded-lg transition-colors",
20992
+ title: isFullscreen ? "\u9000\u51FA\u5168\u5C4F" : "\u5168\u5C4F",
20993
+ children: isFullscreen ? /* @__PURE__ */ jsx(Minimize2, { size: 14 }) : /* @__PURE__ */ jsx(Maximize2, { size: 14 })
20994
+ }
20995
+ ),
20996
+ canPreview && /* @__PURE__ */ jsx(
20997
+ ViewTabs,
20998
+ {
20999
+ activeView: viewMode,
21000
+ onViewChange: (v) => setViewMode(v),
21001
+ views: [
21002
+ { id: "preview", label: "Preview", icon: /* @__PURE__ */ jsx(Eye, { size: 12 }) },
21003
+ { id: "code", label: "Code", icon: /* @__PURE__ */ jsx(Code2, { size: 12 }) }
21004
+ ]
21005
+ }
21006
+ )
21007
+ ] }),
18878
21008
  /* @__PURE__ */ jsx(
18879
21009
  "button",
18880
21010
  {
@@ -18889,6 +21019,16 @@ var ArtifactViewer = memo(function ArtifactViewer2({
18889
21019
  )
18890
21020
  ] })
18891
21021
  ] }),
21022
+ onSwitchArtifact && /* @__PURE__ */ jsx(
21023
+ ArtifactTabs,
21024
+ {
21025
+ artifacts,
21026
+ activeId: activeArtifactId ?? artifact.id,
21027
+ onSwitch: onSwitchArtifact,
21028
+ onClose: onCloseArtifact,
21029
+ onReorder: onReorderArtifacts
21030
+ }
21031
+ ),
18892
21032
  /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden", children: renderContent() })
18893
21033
  ] });
18894
21034
  }
@@ -18934,6 +21074,145 @@ var ArtifactViewer = memo(function ArtifactViewer2({
18934
21074
  }
18935
21075
  );
18936
21076
  });
21077
+
21078
+ // src/utils/artifactExtractor.ts
21079
+ function getMediaTypeFromParamType(paramType) {
21080
+ const upper = paramType?.toUpperCase();
21081
+ if (upper === "IMAGE") return "image";
21082
+ if (upper === "VIDEO") return "video";
21083
+ return null;
21084
+ }
21085
+ function inferMediaTypeFromUrl(url) {
21086
+ if (!url) return null;
21087
+ const lower = url.toLowerCase();
21088
+ if (/\.(jpg|jpeg|png|gif|webp|svg|bmp)(\?|#|$)/.test(lower)) return "image";
21089
+ if (/\.(mp4|mov|webm|avi|mkv|m4v)(\?|#|$)/.test(lower)) return "video";
21090
+ if (/\.(jpg|jpeg|png|gif|webp)/.test(lower)) return "image";
21091
+ if (/\.(mp4|mov|webm)/.test(lower)) return "video";
21092
+ return null;
21093
+ }
21094
+ function extractArtifactsFromToolCall(toolCall, sessionId, messageId) {
21095
+ const artifacts = [];
21096
+ if (!toolCall || toolCall.status?.toLowerCase() !== "completed") return artifacts;
21097
+ const result = toolCall.result;
21098
+ if (!result) return artifacts;
21099
+ const toolName = result?.relation?.toolName || toolCall.name || "AI Tool";
21100
+ const args = toolCall.arguments || {};
21101
+ if (result.works && Array.isArray(result.works)) {
21102
+ result.works.forEach((work, index) => {
21103
+ const paramType = work.customResponse?.paramType;
21104
+ const fileId = work.fileId;
21105
+ const fileUrl = work.fileUrl || work.customResponse?.url;
21106
+ if (!fileId && !fileUrl) return;
21107
+ const mediaType = getMediaTypeFromParamType(paramType) || (fileUrl ? inferMediaTypeFromUrl(fileUrl) : null) || (fileId ? inferMediaTypeFromUrl(fileId) : null);
21108
+ if (!mediaType) return;
21109
+ const artifactId = work.publicId || `media-${toolCall.id}-${index}`;
21110
+ artifacts.push({
21111
+ id: artifactId,
21112
+ sessionId,
21113
+ type: mediaType,
21114
+ title: `${toolName} #${index + 1}`,
21115
+ // 优先存 fileId,resolveAssetForDisplay 会将其转换为可用 URL
21116
+ currentContent: fileId || fileUrl,
21117
+ version: 1,
21118
+ source: "tool",
21119
+ sourceId: toolCall.id,
21120
+ metadata: {
21121
+ toolName,
21122
+ generationParams: args,
21123
+ messageId,
21124
+ workflowCode: result.workflowCode,
21125
+ taskId: result.taskId,
21126
+ fileId: work.fileId,
21127
+ fileUrl: work.fileUrl
21128
+ },
21129
+ gmtCreate: (/* @__PURE__ */ new Date()).toISOString(),
21130
+ gmtModified: (/* @__PURE__ */ new Date()).toISOString()
21131
+ });
21132
+ });
21133
+ }
21134
+ if (artifacts.length === 0 && result.outputs?.images) {
21135
+ const imgUrl = typeof result.outputs.images === "string" ? result.outputs.images : null;
21136
+ if (imgUrl) {
21137
+ artifacts.push({
21138
+ id: `media-${toolCall.id}-output`,
21139
+ sessionId,
21140
+ type: "image",
21141
+ title: `${toolName}`,
21142
+ currentContent: imgUrl,
21143
+ version: 1,
21144
+ source: "tool",
21145
+ sourceId: toolCall.id,
21146
+ metadata: {
21147
+ toolName,
21148
+ generationParams: args,
21149
+ messageId
21150
+ },
21151
+ gmtCreate: (/* @__PURE__ */ new Date()).toISOString(),
21152
+ gmtModified: (/* @__PURE__ */ new Date()).toISOString()
21153
+ });
21154
+ }
21155
+ }
21156
+ if (result.works && Array.isArray(result.works)) {
21157
+ result.works.forEach((work, index) => {
21158
+ if (work.customResponse?.value) {
21159
+ const parsed = detectContentType(work.customResponse.value);
21160
+ if (parsed.content && parsed.type !== "text") {
21161
+ artifacts.push({
21162
+ id: `content-${toolCall.id}-${index}`,
21163
+ sessionId,
21164
+ type: parsed.type,
21165
+ title: parsed.title || `${toolName} - ${parsed.type.toUpperCase()}`,
21166
+ currentContent: parsed.content,
21167
+ language: parsed.language,
21168
+ version: 1,
21169
+ source: "tool",
21170
+ sourceId: toolCall.id,
21171
+ metadata: {
21172
+ toolName,
21173
+ messageId
21174
+ },
21175
+ gmtCreate: (/* @__PURE__ */ new Date()).toISOString(),
21176
+ gmtModified: (/* @__PURE__ */ new Date()).toISOString()
21177
+ });
21178
+ }
21179
+ }
21180
+ });
21181
+ }
21182
+ return artifacts;
21183
+ }
21184
+ function extractArtifactsFromMessages(messages, sessionId) {
21185
+ const allArtifacts = [];
21186
+ const seenIds = /* @__PURE__ */ new Set();
21187
+ for (const message of messages) {
21188
+ if (message.role !== "assistant") continue;
21189
+ const toolCalls = message.extraData?.tool_calls || [];
21190
+ for (const tc of toolCalls) {
21191
+ const extracted = extractArtifactsFromToolCall(tc, sessionId, message.messageId);
21192
+ for (const artifact of extracted) {
21193
+ if (!seenIds.has(artifact.id)) {
21194
+ seenIds.add(artifact.id);
21195
+ allArtifacts.push(artifact);
21196
+ }
21197
+ }
21198
+ }
21199
+ const thoughts = message.extraData?.thoughts || message.thoughts || [];
21200
+ for (const thought of thoughts) {
21201
+ if (thought.toolCalls) {
21202
+ for (const tc of thought.toolCalls) {
21203
+ const extracted = extractArtifactsFromToolCall(tc, sessionId, message.messageId);
21204
+ for (const artifact of extracted) {
21205
+ if (!seenIds.has(artifact.id)) {
21206
+ seenIds.add(artifact.id);
21207
+ allArtifacts.push(artifact);
21208
+ }
21209
+ }
21210
+ }
21211
+ }
21212
+ }
21213
+ }
21214
+ return allArtifacts;
21215
+ }
18937
21216
  var Field = ({ label, value }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 text-xs text-zinc-400", children: [
18938
21217
  /* @__PURE__ */ jsx("span", { children: label }),
18939
21218
  /* @__PURE__ */ jsx("span", { className: "text-zinc-200 truncate max-w-[60%]", children: value ?? "-" })
@@ -19265,7 +21544,9 @@ function ChatInputArea({
19265
21544
  onSend,
19266
21545
  onStop,
19267
21546
  isStreaming,
19268
- config
21547
+ config,
21548
+ activeArtifact,
21549
+ onDetachArtifact
19269
21550
  }) {
19270
21551
  const textareaRef = useRef(null);
19271
21552
  const fileInputRef = useRef(null);
@@ -19346,6 +21627,20 @@ function ChatInputArea({
19346
21627
  };
19347
21628
  return /* @__PURE__ */ jsx("div", { className: "bg-zinc-950 px-4 py-4 flex-shrink-0", children: /* @__PURE__ */ jsxs("div", { className: "max-w-3xl mx-auto", children: [
19348
21629
  /* @__PURE__ */ jsxs("div", { className: "relative bg-zinc-900 border border-zinc-800 rounded-2xl shadow-lg shadow-black/20 focus-within:border-zinc-700 focus-within:shadow-xl focus-within:shadow-black/30 transition-all duration-200", children: [
21630
+ activeArtifact && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 px-4 pt-3 pb-1", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-2.5 py-1 bg-zinc-800/80 rounded-lg text-xs", children: [
21631
+ /* @__PURE__ */ jsx(FileCode, { size: 12, className: "text-[#d8ff00] flex-shrink-0" }),
21632
+ /* @__PURE__ */ jsx("span", { className: "text-zinc-400", children: "\u5173\u8054\u4EA7\u7269\uFF1A" }),
21633
+ /* @__PURE__ */ jsx("span", { className: "text-zinc-200 font-medium max-w-[200px] truncate", children: activeArtifact.title }),
21634
+ onDetachArtifact && /* @__PURE__ */ jsx(
21635
+ "button",
21636
+ {
21637
+ onClick: onDetachArtifact,
21638
+ className: "p-0.5 text-zinc-500 hover:text-zinc-300 rounded transition-colors",
21639
+ title: "\u53D6\u6D88\u5173\u8054",
21640
+ children: /* @__PURE__ */ jsx(Unlink, { size: 10 })
21641
+ }
21642
+ )
21643
+ ] }) }),
19349
21644
  images.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3 p-4 pb-2", children: images.map((img, i) => /* @__PURE__ */ jsxs("div", { className: "relative group", children: [
19350
21645
  /* @__PURE__ */ jsx(
19351
21646
  "img",
@@ -19510,6 +21805,188 @@ var DragHandle = React20__default.memo(function DragHandle2({
19510
21805
  }
19511
21806
  );
19512
21807
  });
21808
+ var artifactTypeIconMap = {
21809
+ html: Globe,
21810
+ svg: Globe,
21811
+ markdown: FileText,
21812
+ json: FileJson,
21813
+ code: FileCode,
21814
+ text: FileText,
21815
+ image: FileImage,
21816
+ video: Video
21817
+ };
21818
+ var ArtifactBarItemThumbnail = memo(function ArtifactBarItemThumbnail2({
21819
+ artifact,
21820
+ config
21821
+ }) {
21822
+ const TypeIcon = artifactTypeIconMap[artifact.type] || FileText;
21823
+ const isMedia = artifact.type === "image" || artifact.type === "video";
21824
+ const thumbnailUrl = useResolvedThumbnailUrl(
21825
+ artifact.currentContent,
21826
+ {
21827
+ fileId: artifact.metadata?.fileId,
21828
+ type: artifact.type,
21829
+ config,
21830
+ enabled: isMedia
21831
+ }
21832
+ );
21833
+ if (isMedia && thumbnailUrl) {
21834
+ return /* @__PURE__ */ jsx(
21835
+ "img",
21836
+ {
21837
+ src: thumbnailUrl,
21838
+ alt: "",
21839
+ className: "w-10 h-10 rounded-lg object-cover flex-shrink-0 border border-zinc-700/50 agent-sdk-light:border-zinc-300",
21840
+ loading: "lazy"
21841
+ }
21842
+ );
21843
+ }
21844
+ return /* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded-lg bg-zinc-800/50 agent-sdk-light:bg-zinc-100 flex items-center justify-center flex-shrink-0 border border-zinc-700/30 agent-sdk-light:border-zinc-300", children: /* @__PURE__ */ jsx(TypeIcon, { size: 18, className: "text-zinc-400 agent-sdk-light:text-zinc-500" }) });
21845
+ });
21846
+ var ArtifactBarMiniThumbnail = memo(function ArtifactBarMiniThumbnail2({
21847
+ artifact,
21848
+ config
21849
+ }) {
21850
+ const TypeIcon = artifactTypeIconMap[artifact.type] || FileText;
21851
+ const isMedia = artifact.type === "image" || artifact.type === "video";
21852
+ const thumbnailUrl = useResolvedThumbnailUrl(
21853
+ artifact.currentContent,
21854
+ {
21855
+ fileId: artifact.metadata?.fileId,
21856
+ type: artifact.type,
21857
+ config,
21858
+ enabled: isMedia
21859
+ }
21860
+ );
21861
+ if (isMedia && thumbnailUrl) {
21862
+ return /* @__PURE__ */ jsx(
21863
+ "img",
21864
+ {
21865
+ src: thumbnailUrl,
21866
+ alt: "",
21867
+ className: "w-6 h-6 rounded border border-zinc-700 agent-sdk-light:border-zinc-300 object-cover",
21868
+ loading: "lazy"
21869
+ }
21870
+ );
21871
+ }
21872
+ return /* @__PURE__ */ jsx("div", { className: "w-6 h-6 rounded border border-zinc-700 agent-sdk-light:border-zinc-300 bg-zinc-800 agent-sdk-light:bg-zinc-200 flex items-center justify-center", children: /* @__PURE__ */ jsx(TypeIcon, { size: 10, className: "text-zinc-400" }) });
21873
+ });
21874
+ var ArtifactBar = React20__default.memo(function ArtifactBar2({
21875
+ artifacts,
21876
+ onOpenArtifact,
21877
+ config
21878
+ }) {
21879
+ const [expanded, setExpanded] = useState(false);
21880
+ const barRef = useRef(null);
21881
+ useEffect(() => {
21882
+ if (!expanded) return;
21883
+ const handleClickOutside = (e) => {
21884
+ if (barRef.current && !barRef.current.contains(e.target)) {
21885
+ setExpanded(false);
21886
+ }
21887
+ };
21888
+ document.addEventListener("mousedown", handleClickOutside);
21889
+ return () => document.removeEventListener("mousedown", handleClickOutside);
21890
+ }, [expanded]);
21891
+ if (artifacts.length === 0) return null;
21892
+ const imageCount = artifacts.filter((a) => a.type === "image").length;
21893
+ const codeCount = artifacts.filter((a) => ["code", "html", "svg", "json"].includes(a.type)).length;
21894
+ const docCount = artifacts.filter((a) => ["markdown", "text"].includes(a.type)).length;
21895
+ const videoCount = artifacts.filter((a) => a.type === "video").length;
21896
+ return /* @__PURE__ */ jsxs("div", { ref: barRef, className: "relative flex-shrink-0 mx-auto max-w-md", children: [
21897
+ expanded && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-full left-0 right-0 mb-1 z-30 max-h-[50vh] overflow-y-auto bg-zinc-900/95 agent-sdk-light:bg-white/95 backdrop-blur-md border border-zinc-700/50 agent-sdk-light:border-zinc-300 rounded-xl shadow-2xl", children: [
21898
+ /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 border-b border-zinc-800/50 agent-sdk-light:border-zinc-200 flex items-center justify-between", children: [
21899
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
21900
+ /* @__PURE__ */ jsx(LayoutGrid, { size: 14, className: "text-[#d8ff00]" }),
21901
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-zinc-200 agent-sdk-light:text-zinc-800", children: "\u5168\u90E8\u4EA7\u7269" }),
21902
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-zinc-500 bg-zinc-800/50 agent-sdk-light:bg-zinc-200 px-1.5 py-0.5 rounded-full", children: artifacts.length })
21903
+ ] }),
21904
+ /* @__PURE__ */ jsx(
21905
+ "button",
21906
+ {
21907
+ onClick: () => setExpanded(false),
21908
+ className: "p-1 text-zinc-500 hover:text-zinc-300 agent-sdk-light:hover:text-zinc-700 rounded transition-colors",
21909
+ children: /* @__PURE__ */ jsx(ChevronDown, { size: 16 })
21910
+ }
21911
+ )
21912
+ ] }),
21913
+ /* @__PURE__ */ jsx("div", { className: "p-2 grid grid-cols-1 gap-1", children: artifacts.map((artifact) => {
21914
+ return /* @__PURE__ */ jsxs(
21915
+ "button",
21916
+ {
21917
+ onClick: () => {
21918
+ onOpenArtifact(artifact.id);
21919
+ setExpanded(false);
21920
+ },
21921
+ className: "flex items-center gap-3 px-3 py-2.5 rounded-lg text-left w-full hover:bg-zinc-800/60 agent-sdk-light:hover:bg-zinc-100 transition-colors group",
21922
+ children: [
21923
+ /* @__PURE__ */ jsx(ArtifactBarItemThumbnail, { artifact, config }),
21924
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
21925
+ /* @__PURE__ */ jsx("div", { className: "text-sm text-zinc-200 agent-sdk-light:text-zinc-800 truncate font-medium group-hover:text-white agent-sdk-light:group-hover:text-zinc-900", children: artifact.title }),
21926
+ /* @__PURE__ */ jsxs("div", { className: "text-[11px] text-zinc-500 agent-sdk-light:text-zinc-500 mt-0.5", children: [
21927
+ artifact.type.toUpperCase(),
21928
+ artifact.language && artifact.language !== artifact.type && ` \u2022 ${artifact.language}`
21929
+ ] })
21930
+ ] })
21931
+ ]
21932
+ },
21933
+ artifact.id
21934
+ );
21935
+ }) })
21936
+ ] }),
21937
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-2 border-t border-zinc-800/30 agent-sdk-light:border-zinc-200/50 bg-zinc-900/30 agent-sdk-light:bg-zinc-50/50", children: /* @__PURE__ */ jsxs(
21938
+ "button",
21939
+ {
21940
+ onClick: () => setExpanded((prev) => !prev),
21941
+ className: "w-full flex items-center gap-2.5 px-3 py-2 rounded-lg bg-zinc-800/40 agent-sdk-light:bg-zinc-100 hover:bg-zinc-800/60 agent-sdk-light:hover:bg-zinc-200/80 border border-zinc-700/30 agent-sdk-light:border-zinc-300/50 transition-colors group",
21942
+ children: [
21943
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
21944
+ /* @__PURE__ */ jsx(Sparkles, { size: 14, className: "text-[#d8ff00]" }),
21945
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-zinc-300 agent-sdk-light:text-zinc-700", children: [
21946
+ artifacts.length,
21947
+ " \u4E2A\u4EA7\u7269"
21948
+ ] })
21949
+ ] }),
21950
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 flex-1 min-w-0", children: [
21951
+ imageCount > 0 && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-[10px] text-zinc-500 bg-zinc-700/30 agent-sdk-light:bg-zinc-200 px-1.5 py-0.5 rounded", children: [
21952
+ /* @__PURE__ */ jsx(FileImage, { size: 10 }),
21953
+ " ",
21954
+ imageCount
21955
+ ] }),
21956
+ codeCount > 0 && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-[10px] text-zinc-500 bg-zinc-700/30 agent-sdk-light:bg-zinc-200 px-1.5 py-0.5 rounded", children: [
21957
+ /* @__PURE__ */ jsx(FileCode, { size: 10 }),
21958
+ " ",
21959
+ codeCount
21960
+ ] }),
21961
+ docCount > 0 && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-[10px] text-zinc-500 bg-zinc-700/30 agent-sdk-light:bg-zinc-200 px-1.5 py-0.5 rounded", children: [
21962
+ /* @__PURE__ */ jsx(FileText, { size: 10 }),
21963
+ " ",
21964
+ docCount
21965
+ ] }),
21966
+ videoCount > 0 && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-[10px] text-zinc-500 bg-zinc-700/30 agent-sdk-light:bg-zinc-200 px-1.5 py-0.5 rounded", children: [
21967
+ /* @__PURE__ */ jsx(Video, { size: 10 }),
21968
+ " ",
21969
+ videoCount
21970
+ ] })
21971
+ ] }),
21972
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center -space-x-1.5", children: [
21973
+ artifacts.slice(0, 4).map((artifact) => {
21974
+ return /* @__PURE__ */ jsx(ArtifactBarMiniThumbnail, { artifact, config }, artifact.id);
21975
+ }),
21976
+ artifacts.length > 4 && /* @__PURE__ */ jsx("div", { className: "w-6 h-6 rounded border border-zinc-700 agent-sdk-light:border-zinc-300 bg-zinc-800 agent-sdk-light:bg-zinc-200 flex items-center justify-center", children: /* @__PURE__ */ jsxs("span", { className: "text-[9px] text-zinc-400", children: [
21977
+ "+",
21978
+ artifacts.length - 4
21979
+ ] }) })
21980
+ ] }),
21981
+ /* @__PURE__ */ jsx(ChevronUp, { size: 14, className: cn2(
21982
+ "text-zinc-500 transition-transform flex-shrink-0",
21983
+ expanded && "rotate-180"
21984
+ ) })
21985
+ ]
21986
+ }
21987
+ ) })
21988
+ ] });
21989
+ });
19513
21990
  var AgentChat = React20__default.forwardRef(({
19514
21991
  agentId,
19515
21992
  projectId,
@@ -19552,7 +22029,7 @@ var AgentChat = React20__default.forwardRef(({
19552
22029
  ComponentRegistry: mergedRegistry
19553
22030
  };
19554
22031
  }, [config?.components, outerComponents]);
19555
- const { sessions, setSessions, currentSession, setCurrentSession, addSession, removeSession, tools: _tools, setTools, setSkills, setShowItemTime } = useAgentStore();
22032
+ const { sessions, setSessions, currentSession, setCurrentSession, addSession, removeSession, tools: _tools, setTools, setSkills, setShowItemTime, artifacts, artifactOrder, activeArtifactId, upsertArtifact, updateArtifactContent, setActiveArtifact, removeArtifact, clearArtifacts, setArtifacts, reorderArtifacts } = useAgentStore();
19556
22033
  const [loading, setLoading] = useState(true);
19557
22034
  const [messagesLoading, setMessagesLoading] = useState(false);
19558
22035
  const [collapsed, setCollapsed] = useState(false);
@@ -19564,7 +22041,23 @@ var AgentChat = React20__default.forwardRef(({
19564
22041
  const lastUserMessageRef = useRef("");
19565
22042
  const [shareModalOpen, setShareModalOpen] = useState(false);
19566
22043
  const [shareSession, setShareSession] = useState(null);
19567
- const [currentArtifact, setCurrentArtifact] = useState(null);
22044
+ const artifactList = useMemo(() => {
22045
+ const ordered = artifactOrder.map((id) => artifacts[id]).filter(Boolean);
22046
+ const unordered = Object.values(artifacts).filter(
22047
+ (a) => !artifactOrder.includes(a.id)
22048
+ );
22049
+ return [...ordered, ...unordered];
22050
+ }, [artifacts, artifactOrder]);
22051
+ const activeArtifact = activeArtifactId ? artifacts[activeArtifactId] ?? null : null;
22052
+ const currentArtifact = activeArtifact ? {
22053
+ id: activeArtifact.id,
22054
+ type: activeArtifact.type,
22055
+ title: activeArtifact.title,
22056
+ content: activeArtifact.currentContent,
22057
+ language: activeArtifact.language,
22058
+ source: activeArtifact.sourceId,
22059
+ metadata: activeArtifact.metadata
22060
+ } : null;
19568
22061
  const [isArtifactFullscreen, setIsArtifactFullscreen] = useState(false);
19569
22062
  const [artifactPanelWidth, setArtifactPanelWidth] = useState(50);
19570
22063
  const [isDragging, setIsDragging] = useState(false);
@@ -19590,7 +22083,11 @@ var AgentChat = React20__default.forwardRef(({
19590
22083
  const deltaX = dragStartRef.current.startX - e.clientX;
19591
22084
  const deltaPercent = deltaX / containerWidth * 100;
19592
22085
  const newWidth = dragStartRef.current.startWidth + deltaPercent;
19593
- const clampedWidth = Math.max(25, Math.min(75, newWidth));
22086
+ const minChatPx = 350;
22087
+ const minArtifactPx = 400;
22088
+ const maxArtifactPercent = (containerWidth - minChatPx) / containerWidth * 100;
22089
+ const minArtifactPercent = minArtifactPx / containerWidth * 100;
22090
+ const clampedWidth = Math.max(minArtifactPercent, Math.min(maxArtifactPercent, newWidth));
19594
22091
  setArtifactPanelWidth(clampedWidth);
19595
22092
  };
19596
22093
  const handleMouseUp = () => {
@@ -19612,38 +22109,52 @@ var AgentChat = React20__default.forwardRef(({
19612
22109
  setShowItemTime(showItemTime);
19613
22110
  }, [showItemTime]);
19614
22111
  const handleOpenArtifact = useCallback((data) => {
19615
- if (currentArtifact && currentArtifact.content === data.content && currentArtifact.type === data.type) {
19616
- setCurrentArtifact(null);
22112
+ if (activeArtifact && activeArtifact.currentContent === data.content && activeArtifact.type === data.type) {
22113
+ setActiveArtifact(null);
19617
22114
  setIsArtifactFullscreen(false);
19618
22115
  return;
19619
22116
  }
19620
- const artifact = {
19621
- id: `artifact-${Date.now()}`,
19622
- type: data.type,
19623
- title: data.title,
19624
- content: data.content,
19625
- language: data.language,
19626
- timestamp: Date.now()
19627
- };
19628
- setCurrentArtifact(artifact);
19629
- }, [currentArtifact]);
22117
+ const existingArtifact = Object.values(artifacts).find(
22118
+ (a) => a.currentContent === data.content && a.type === data.type
22119
+ );
22120
+ if (existingArtifact) {
22121
+ setActiveArtifact(existingArtifact.id);
22122
+ } else {
22123
+ const sessionId = currentSession?.sessionId || "";
22124
+ const newArtifactEntry = {
22125
+ id: `artifact-${Date.now()}`,
22126
+ sessionId,
22127
+ type: data.type,
22128
+ title: data.title,
22129
+ currentContent: data.content,
22130
+ language: data.language,
22131
+ metadata: data.metadata,
22132
+ version: 1,
22133
+ source: "llm",
22134
+ gmtCreate: (/* @__PURE__ */ new Date()).toISOString(),
22135
+ gmtModified: (/* @__PURE__ */ new Date()).toISOString()
22136
+ };
22137
+ upsertArtifact(newArtifactEntry);
22138
+ setActiveArtifact(newArtifactEntry.id);
22139
+ }
22140
+ }, [activeArtifact, artifacts, currentSession, upsertArtifact, setActiveArtifact]);
19630
22141
  const handleCloseArtifact = useCallback(() => {
19631
- setCurrentArtifact(null);
22142
+ setActiveArtifact(null);
19632
22143
  setIsArtifactFullscreen(false);
19633
- }, []);
22144
+ }, [setActiveArtifact]);
19634
22145
  useEffect(() => {
19635
22146
  const handleKeyDown = (e) => {
19636
- if (e.key === "Escape" && currentArtifact) {
22147
+ if (e.key === "Escape" && activeArtifactId) {
19637
22148
  if (isArtifactFullscreen) {
19638
22149
  setIsArtifactFullscreen(false);
19639
22150
  } else {
19640
- setCurrentArtifact(null);
22151
+ setActiveArtifact(null);
19641
22152
  }
19642
22153
  }
19643
22154
  };
19644
22155
  document.addEventListener("keydown", handleKeyDown);
19645
22156
  return () => document.removeEventListener("keydown", handleKeyDown);
19646
- }, [currentArtifact, isArtifactFullscreen]);
22157
+ }, [activeArtifactId, isArtifactFullscreen, setActiveArtifact]);
19647
22158
  const handleToggleArtifactFullscreen = useCallback(() => {
19648
22159
  setIsArtifactFullscreen((prev) => !prev);
19649
22160
  }, []);
@@ -19845,8 +22356,9 @@ var AgentChat = React20__default.forwardRef(({
19845
22356
  addSession(s);
19846
22357
  setCurrentSession(s);
19847
22358
  useAgentStore.getState().setMessages([]);
22359
+ clearArtifacts();
19848
22360
  }
19849
- }, [projectId, agentId]);
22361
+ }, [projectId, agentId, clearArtifacts]);
19850
22362
  const handlePrompt = useCallback(async (p) => {
19851
22363
  await handleNew();
19852
22364
  setInput(p);
@@ -19857,10 +22369,29 @@ var AgentChat = React20__default.forwardRef(({
19857
22369
  onSessionIdChange?.(s.sessionId);
19858
22370
  setMobileOpen(false);
19859
22371
  useAgentStore.getState().setMessages([]);
22372
+ clearArtifacts();
19860
22373
  setMessagesLoading(true);
19861
- await loadMessages(s.sessionId);
22374
+ await Promise.all([
22375
+ loadMessages(s.sessionId),
22376
+ artifactService.list(s.sessionId).then((res) => {
22377
+ if (res.success && res.data && res.data.length > 0) {
22378
+ setArtifacts(res.data);
22379
+ }
22380
+ }).catch((err) => {
22381
+ console.error("[AgentChat] Load artifacts failed:", err);
22382
+ })
22383
+ ]);
22384
+ const currentArtifacts = useAgentStore.getState().artifacts;
22385
+ if (Object.keys(currentArtifacts).length === 0) {
22386
+ const currentMessages = useAgentStore.getState().messages;
22387
+ const extracted = extractArtifactsFromMessages(currentMessages, s.sessionId);
22388
+ if (extracted.length > 0) {
22389
+ console.log("[AgentChat] Fallback: extracted", extracted.length, "artifacts from messages");
22390
+ extracted.forEach((artifact) => upsertArtifact(artifact));
22391
+ }
22392
+ }
19862
22393
  setMessagesLoading(false);
19863
- }, []);
22394
+ }, [clearArtifacts, setArtifacts, upsertArtifact]);
19864
22395
  const handleDelete2 = useCallback(async (id) => {
19865
22396
  toast("\u5220\u9664\u6B64\u5BF9\u8BDD\uFF1F", {
19866
22397
  action: {
@@ -19956,8 +22487,14 @@ var AgentChat = React20__default.forwardRef(({
19956
22487
  }
19957
22488
  });
19958
22489
  setImages([]);
19959
- await sendMessage(currentSession.sessionId, messageContent);
19960
- }, [input, images, currentSession, sendMessage, config]);
22490
+ const currentActiveArtifact = activeArtifactId ? artifacts[activeArtifactId] : null;
22491
+ const artifactContext = currentActiveArtifact ? {
22492
+ artifactId: currentActiveArtifact.id,
22493
+ title: currentActiveArtifact.title,
22494
+ currentContent: currentActiveArtifact.currentContent
22495
+ } : void 0;
22496
+ await sendMessage(currentSession.sessionId, messageContent, { artifactContext });
22497
+ }, [input, images, currentSession, sendMessage, config, activeArtifactId, artifacts]);
19961
22498
  const sendTextMessage = useCallback(async (content) => {
19962
22499
  if (!content.trim()) return;
19963
22500
  if (!currentSession) return;
@@ -20122,6 +22659,13 @@ var AgentChat = React20__default.forwardRef(({
20122
22659
  onOpenArtifact: handleOpenArtifact
20123
22660
  }
20124
22661
  ),
22662
+ artifactList.length > 0 && !currentArtifact && /* @__PURE__ */ jsx(
22663
+ ArtifactBar,
22664
+ {
22665
+ artifacts: artifactList,
22666
+ onOpenArtifact: (id) => setActiveArtifact(id)
22667
+ }
22668
+ ),
20125
22669
  !hideInput && /* @__PURE__ */ jsx(
20126
22670
  ChatInputArea,
20127
22671
  {
@@ -20132,7 +22676,9 @@ var AgentChat = React20__default.forwardRef(({
20132
22676
  onSend: handleSend,
20133
22677
  onStop: handleStop,
20134
22678
  isStreaming: isCurrentSessionStreaming,
20135
- config
22679
+ config,
22680
+ activeArtifact,
22681
+ onDetachArtifact: () => setActiveArtifact(null)
20136
22682
  }
20137
22683
  )
20138
22684
  ]
@@ -20171,7 +22717,36 @@ var AgentChat = React20__default.forwardRef(({
20171
22717
  config,
20172
22718
  isFullscreen: isArtifactFullscreen,
20173
22719
  onFullscreenToggle: handleToggleArtifactFullscreen,
20174
- embedded: true
22720
+ embedded: true,
22721
+ artifacts: artifactList,
22722
+ activeArtifactId,
22723
+ onSwitchArtifact: (id) => setActiveArtifact(id),
22724
+ onCloseArtifact: (id) => {
22725
+ removeArtifact(id);
22726
+ if (artifactList.length <= 1) {
22727
+ setIsArtifactFullscreen(false);
22728
+ }
22729
+ },
22730
+ onReorderArtifacts: reorderArtifacts,
22731
+ onContentChange: (content) => {
22732
+ if (activeArtifactId) {
22733
+ updateArtifactContent(activeArtifactId, content, "user");
22734
+ }
22735
+ },
22736
+ onSave: async (artifactId, content) => {
22737
+ try {
22738
+ const res = await artifactService.updateContent(artifactId, content);
22739
+ if (res.success) {
22740
+ updateArtifactContent(artifactId, content, "user");
22741
+ toast.success("\u4EA7\u7269\u5DF2\u4FDD\u5B58");
22742
+ } else {
22743
+ toast.error("\u4FDD\u5B58\u5931\u8D25");
22744
+ }
22745
+ } catch (err) {
22746
+ console.error("[AgentChat] Save artifact failed:", err);
22747
+ toast.error("\u4FDD\u5B58\u4EA7\u7269\u5931\u8D25");
22748
+ }
22749
+ }
20175
22750
  }
20176
22751
  )
20177
22752
  ]
@@ -20647,6 +23222,6 @@ function ShareReplayPage({ shareId, onNavigateBack }) {
20647
23222
  ] });
20648
23223
  }
20649
23224
 
20650
- export { AgentChat_default as AgentChat, ChatWindow_default as ChatWindow, ComponentProvider, HumanInputDialog_default as HumanInputDialog, ImagePreview, MAX_RECONNECT_ATTEMPTS2 as MAX_RECONNECT_ATTEMPTS, MessageBubble_default as MessageBubble, MessageImage, MessageVideo, MultiAgentThoughts_default as MultiAgentThoughts, ParameterDisplay, PlanCard_default as PlanCard, PlanConfirmDialog_default as PlanConfirmDialog, PlanProgressPanel_default as PlanProgressPanel, RECONNECT_BASE_DELAY2 as RECONNECT_BASE_DELAY, SSE_HEARTBEAT_TIMEOUT2 as SSE_HEARTBEAT_TIMEOUT, SaveTemplateDialog_default as SaveTemplateDialog, ShareModal, ShareReplayPage, StreamingJsonDisplay, TemplateSelector_default as TemplateSelector, TemplateSourceBadge_default as TemplateSourceBadge, TemplateVariableDialog_default as TemplateVariableDialog, ThinkingProcess, ToolConfirmCard, ToolConfirmDialog, UpdateTemplateDialog_default as UpdateTemplateDialog, VoiceInput, VoiceInputButton, VoiceRecordingModal, VoiceWaveform, agentService, agentSkillService, agentToolService, calculateReconnectDelay, componentService, confirmAllPendingToolCalls, createAndStartSession, createHeartbeatManager, createReconnectManager, createStreamReader, embedding, extractJsonContent, extractThinkingContent, extractToolCalls, filterMediaAttachments, findMessageById, findSessionById, formatParameters, generateSSEId, generateSessionTitle, generateToolCallDescription, getCurrentSessionMessages, getFileUrl, getHDImageUrl, getImageUrl, getOSSClient, getParamsSummary, getSessionCurrentThoughts, getSessionPendingToolCalls, getSessionWithMessages, getToolCallDisplayStatus, getToolCallStatusPriority, hasExecutingToolCalls, hasPendingToolCalls, hasWaitingConfirmation, isConversationActive, isCurrentlyThinking, isImageUrl, isMechanicalSummary, isPendingToolCallsForSession, isVideoUrl3 as isVideoUrl, llmService, looksLikeJson, mergeToolCalls, messageService, normalizeToolCall, normalizeToolCalls, parseSSELine2 as parseSSELine, parseThinkingContent, parseThoughts, planService, rejectAllPendingToolCalls, resolveMediaUrl, sessionService, shareService, templateService, toolCallService, uploadOSS, useActiveSubAgent, useAgentStore, useChatError, useChatUI, useComponent, useComponents, useCurrentSession, useCurrentThoughts, useCurrentThoughtsSessionId, useIsStreaming, useIsThinking, useMessages, usePendingComponents, usePendingComponentsSessionId, usePendingFrontendToolCalls, usePendingFrontendToolCallsSessionId, usePendingToolCalls, usePendingToolCallsSessionId, useSSE, useSessions, useSessionsLoading, useStreamingContent, useStreamingSessionId, useSubAgents, useVoiceRecognition };
23225
+ export { AgentChat_default as AgentChat, ChatWindow_default as ChatWindow, ComponentProvider, HumanInputDialog_default as HumanInputDialog, ImagePreview, MAX_RECONNECT_ATTEMPTS2 as MAX_RECONNECT_ATTEMPTS, MessageBubble_default as MessageBubble, MessageImage, MessageVideo, MultiAgentThoughts_default as MultiAgentThoughts, ParameterDisplay, PlanCard_default as PlanCard, PlanConfirmDialog_default as PlanConfirmDialog, PlanProgressPanel_default as PlanProgressPanel, RECONNECT_BASE_DELAY2 as RECONNECT_BASE_DELAY, SSE_HEARTBEAT_TIMEOUT2 as SSE_HEARTBEAT_TIMEOUT, SaveTemplateDialog_default as SaveTemplateDialog, ShareModal, ShareReplayPage, StreamingJsonDisplay, TemplateSelector_default as TemplateSelector, TemplateSourceBadge_default as TemplateSourceBadge, TemplateVariableDialog_default as TemplateVariableDialog, ThinkingProcess, ToolConfirmCard, ToolConfirmDialog, UpdateTemplateDialog_default as UpdateTemplateDialog, VoiceInput, VoiceInputButton, VoiceRecordingModal, VoiceWaveform, agentService, agentSkillService, agentToolService, artifactService, calculateReconnectDelay, componentService, confirmAllPendingToolCalls, createAndStartSession, createHeartbeatManager, createReconnectManager, createStreamReader, embedding, extractJsonContent, extractThinkingContent, extractToolCalls, filterMediaAttachments, findMessageById, findSessionById, formatParameters, generateSSEId, generateSessionTitle, generateToolCallDescription, getCurrentSessionMessages, getFileUrl, getHDImageUrl, getImageUrl, getOSSClient, getParamsSummary, getSessionCurrentThoughts, getSessionPendingToolCalls, getSessionWithMessages, getToolCallDisplayStatus, getToolCallStatusPriority, hasExecutingToolCalls, hasPendingToolCalls, hasWaitingConfirmation, isConversationActive, isCurrentlyThinking, isImageUrl, isMechanicalSummary, isPendingToolCallsForSession, isVideoUrl3 as isVideoUrl, llmService, looksLikeJson, mergeToolCalls, messageService, normalizeToolCall, normalizeToolCalls, parseSSELine2 as parseSSELine, parseThinkingContent, parseThoughts, planService, rejectAllPendingToolCalls, resolveMediaUrl, sessionService, shareService, templateService, toolCallService, uploadOSS, useActiveArtifact, useActiveArtifactId, useActiveSubAgent, useAgentStore, useArtifactList, useArtifactOrder, useArtifacts, useCanvasBridge, useChatError, useChatUI, useComponent, useComponents, useCurrentSession, useCurrentThoughts, useCurrentThoughtsSessionId, useIsStreaming, useIsThinking, useMessages, usePendingComponents, usePendingComponentsSessionId, usePendingFrontendToolCalls, usePendingFrontendToolCallsSessionId, usePendingToolCalls, usePendingToolCallsSessionId, useSSE, useSessions, useSessionsLoading, useStreamingContent, useStreamingSessionId, useSubAgents, useVoiceRecognition };
20651
23226
  //# sourceMappingURL=index.mjs.map
20652
23227
  //# sourceMappingURL=index.mjs.map