@tutti-os/agent-gui 0.0.21 → 0.0.23

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.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  import {
14
14
  AgentInteractivePromptSurface,
15
15
  approvalOptionDisplayLabel
16
- } from "./chunk-2BGUS7DE.js";
16
+ } from "./chunk-ZC4E2QJU.js";
17
17
  import {
18
18
  PLAN_IMPLEMENTATION_ACTION_FEEDBACK,
19
19
  PLAN_IMPLEMENTATION_ACTION_IMPLEMENT,
@@ -25,7 +25,6 @@ import {
25
25
  import {
26
26
  AgentConversationFlow,
27
27
  Button,
28
- buildCanonicalWorkspaceAgentDetailView,
29
28
  buildWorkspaceAgentSessionDetailViewModel,
30
29
  createAgentRichTextInputExtensions,
31
30
  editorToPromptText,
@@ -37,13 +36,13 @@ import {
37
36
  skillDescriptionForDisplay,
38
37
  skillTriggerForPrefix,
39
38
  useProjectedAgentConversation
40
- } from "./chunk-4NGM7NFL.js";
39
+ } from "./chunk-MQAGIHYM.js";
41
40
  import {
42
41
  AgentMessageMarkdown,
43
42
  ZoomableImage,
44
43
  cn,
45
44
  resolveWorkspaceLinkAction
46
- } from "./chunk-BMGCH4JC.js";
45
+ } from "./chunk-7Q3JKSQ5.js";
47
46
  import {
48
47
  AGENT_MENTION_FILTER_TAB_ORDER,
49
48
  AgentFileMentionPalette,
@@ -51,7 +50,7 @@ import {
51
50
  DEFAULT_AGENT_MENTION_FILTER,
52
51
  flattenAgentMentionPaletteEntries,
53
52
  preloadAgentMentionBrowse
54
- } from "./chunk-WP7ZZ56R.js";
53
+ } from "./chunk-3LVEFR2N.js";
55
54
  import {
56
55
  WORKSPACE_AGENT_ACTIVITY_RUNTIME_SESSION_ORIGIN,
57
56
  buildWorkspaceAgentActivityListViewModel,
@@ -2347,16 +2346,6 @@ var AGENT_PROVIDER_LABEL = {
2347
2346
  hermes: "Hermes Agent"
2348
2347
  };
2349
2348
 
2350
- // shared/agentConversation/projection/workspaceAgentTimelineProjection.ts
2351
- function projectWorkspaceAgentTimelineToConversationVM(input, options = {}) {
2352
- const detail = buildCanonicalWorkspaceAgentDetailView(input);
2353
- const conversation = projectAgentConversationVM(detail, options);
2354
- return conversation;
2355
- }
2356
-
2357
- // agent-gui/agentGuiNode/model/agentGuiConversationModel.ts
2358
- import { resolveWorkspaceUserProjectDisplayLabel } from "@tutti-os/workspace-user-project/core";
2359
-
2360
2349
  // agent-gui/agentGuiNode/model/agentGuiProviderIdentity.ts
2361
2350
  function normalizeAgentGUIProviderIdentity(provider) {
2362
2351
  switch (provider?.trim().toLowerCase() ?? "") {
@@ -2481,10 +2470,127 @@ function isUserTimelineItem(item) {
2481
2470
  return item.itemType.trim().toLowerCase() === "message.user";
2482
2471
  }
2483
2472
 
2484
- // agent-gui/agentGuiNode/model/agentGuiConversationModel.ts
2485
- var AGENT_GUI_RUNTIME_SESSION_ORIGIN = WORKSPACE_AGENT_ACTIVITY_RUNTIME_SESSION_ORIGIN;
2473
+ // agent-gui/agentGuiNode/model/agentGuiConversationProjectResolver.ts
2474
+ import { resolveWorkspaceUserProjectDisplayLabel } from "@tutti-os/workspace-user-project/core";
2486
2475
  var AGENT_GUI_CONVERSATION_PROJECT_SUMMARY_CACHE_LIMIT = 512;
2487
2476
  var agentGUIConversationProjectSummaryCache = /* @__PURE__ */ new Map();
2477
+ function createAgentGUIConversationProjectResolver(userProjects = [], options = {}) {
2478
+ const projectByNormalizedPath = buildAgentGUIConversationProjectIndex(userProjects);
2479
+ const resolvedByNormalizedCwd = /* @__PURE__ */ new Map();
2480
+ return {
2481
+ resolve: (cwd) => {
2482
+ const normalizedCwd = normalizeAgentGUIProjectPath(cwd);
2483
+ if (!normalizedCwd) {
2484
+ return null;
2485
+ }
2486
+ const cached = resolvedByNormalizedCwd.get(normalizedCwd);
2487
+ if (cached !== void 0) {
2488
+ return cached;
2489
+ }
2490
+ const resolved = resolveAgentGUIConversationProjectFromIndex(
2491
+ normalizedCwd,
2492
+ projectByNormalizedPath,
2493
+ options
2494
+ );
2495
+ resolvedByNormalizedCwd.set(normalizedCwd, resolved);
2496
+ return resolved;
2497
+ }
2498
+ };
2499
+ }
2500
+ function resolveAgentGUIConversationProject(cwd, userProjects = [], options = {}) {
2501
+ return createAgentGUIConversationProjectResolver(
2502
+ userProjects,
2503
+ options
2504
+ ).resolve(cwd);
2505
+ }
2506
+ function buildAgentGUIConversationProjectIndex(userProjects) {
2507
+ const projectByNormalizedPath = /* @__PURE__ */ new Map();
2508
+ for (const project of userProjects) {
2509
+ const projectPath = normalizeAgentGUIProjectPath(project.path);
2510
+ if (!projectPath || projectByNormalizedPath.has(projectPath)) {
2511
+ continue;
2512
+ }
2513
+ projectByNormalizedPath.set(projectPath, project);
2514
+ }
2515
+ return projectByNormalizedPath;
2516
+ }
2517
+ function resolveAgentGUIConversationProjectFromIndex(normalizedCwd, projectByNormalizedPath, options) {
2518
+ if (options.isNoProjectPath?.({ path: normalizedCwd })) {
2519
+ return null;
2520
+ }
2521
+ const matchedProject = lookupAgentGUIConversationProject(
2522
+ normalizedCwd,
2523
+ projectByNormalizedPath
2524
+ );
2525
+ if (!matchedProject) {
2526
+ return null;
2527
+ }
2528
+ const summary = {
2529
+ id: matchedProject.id,
2530
+ path: matchedProject.path,
2531
+ label: resolveWorkspaceUserProjectDisplayLabel(matchedProject)
2532
+ };
2533
+ if (matchedProject.createdAtUnixMs !== void 0) {
2534
+ summary.createdAtUnixMs = matchedProject.createdAtUnixMs;
2535
+ }
2536
+ if (matchedProject.updatedAtUnixMs !== void 0) {
2537
+ summary.updatedAtUnixMs = matchedProject.updatedAtUnixMs;
2538
+ }
2539
+ if (matchedProject.lastUsedAtUnixMs !== void 0) {
2540
+ summary.lastUsedAtUnixMs = matchedProject.lastUsedAtUnixMs;
2541
+ }
2542
+ return cachedAgentGUIConversationProjectSummary(summary);
2543
+ }
2544
+ function lookupAgentGUIConversationProject(normalizedCwd, projectByNormalizedPath) {
2545
+ let currentPath = normalizedCwd;
2546
+ while (currentPath) {
2547
+ const project = projectByNormalizedPath.get(currentPath);
2548
+ if (project) {
2549
+ return project;
2550
+ }
2551
+ const slashIndex = currentPath.lastIndexOf("/");
2552
+ if (slashIndex <= 0) {
2553
+ break;
2554
+ }
2555
+ currentPath = currentPath.slice(0, slashIndex);
2556
+ }
2557
+ if (normalizedCwd === "/") {
2558
+ return projectByNormalizedPath.get("/") ?? null;
2559
+ }
2560
+ return null;
2561
+ }
2562
+ function normalizeAgentGUIProjectPath(path) {
2563
+ const normalized = path?.trim().replaceAll("\\", "/") ?? "";
2564
+ if (!normalized) {
2565
+ return "";
2566
+ }
2567
+ return normalized.replace(/\/+$/, "") || "/";
2568
+ }
2569
+ function cachedAgentGUIConversationProjectSummary(summary) {
2570
+ const key = [
2571
+ summary.id,
2572
+ summary.path,
2573
+ summary.label,
2574
+ summary.createdAtUnixMs ?? "",
2575
+ summary.updatedAtUnixMs ?? "",
2576
+ summary.lastUsedAtUnixMs ?? ""
2577
+ ].join("");
2578
+ const cached = agentGUIConversationProjectSummaryCache.get(key);
2579
+ if (cached) {
2580
+ return cached;
2581
+ }
2582
+ if (agentGUIConversationProjectSummaryCache.size >= AGENT_GUI_CONVERSATION_PROJECT_SUMMARY_CACHE_LIMIT) {
2583
+ const oldestKey = agentGUIConversationProjectSummaryCache.keys().next().value;
2584
+ if (oldestKey) {
2585
+ agentGUIConversationProjectSummaryCache.delete(oldestKey);
2586
+ }
2587
+ }
2588
+ agentGUIConversationProjectSummaryCache.set(key, summary);
2589
+ return summary;
2590
+ }
2591
+
2592
+ // agent-gui/agentGuiNode/model/agentGuiConversationModel.ts
2593
+ var AGENT_GUI_RUNTIME_SESSION_ORIGIN = WORKSPACE_AGENT_ACTIVITY_RUNTIME_SESSION_ORIGIN;
2488
2594
  function resolveAgentGUIConversationSortTimeUnixMs(conversation) {
2489
2595
  return conversation.sortTimeUnixMs ?? conversation.updatedAtUnixMs;
2490
2596
  }
@@ -2499,13 +2605,17 @@ function buildAgentGUIConversationSummaries({
2499
2605
  const sessionsById = new Map(
2500
2606
  runtimeSnapshot.sessions.map((session) => [session.agentSessionId, session])
2501
2607
  );
2608
+ const projectResolver = createAgentGUIConversationProjectResolver(
2609
+ userProjects,
2610
+ { isNoProjectPath }
2611
+ );
2502
2612
  return buildWorkspaceAgentActivityListViewModel(runtimeSnapshot, {
2503
2613
  sessionMessagesById
2504
2614
  }).activities.map(
2505
2615
  (activity) => conversationSummaryFromActivity(
2506
2616
  activity,
2507
2617
  sessionsById.get(activity.sessionId),
2508
- { isNoProjectPath, userProjects }
2618
+ { projectResolver }
2509
2619
  )
2510
2620
  ).filter(
2511
2621
  (conversation) => conversation.provider === provider || conversation.provider === "unknown"
@@ -2553,52 +2663,38 @@ function buildAgentGUIConversationDetail({
2553
2663
  });
2554
2664
  return detail;
2555
2665
  }
2556
- function buildAgentGUIConversationVM({
2666
+ function buildAgentGUIConversationModels({
2557
2667
  timelineItems,
2558
2668
  conversation,
2559
2669
  workspaceRoot = null,
2560
2670
  avoidGroupingEdits = false
2561
2671
  }) {
2562
- const session = timelineSessionFromItems(timelineItems, conversation);
2563
- const activity = buildWorkspaceAgentActivityListViewModel(
2564
- {
2565
- presences: [],
2566
- sessions: [session]
2567
- },
2568
- {
2569
- sessionMessagesById: {
2570
- [session.agentSessionId]: workspaceAgentMessagesFromTimelineItems(timelineItems)
2571
- }
2572
- }
2573
- ).activities[0] ?? null;
2574
- if (!activity) {
2575
- return null;
2672
+ const detail = buildAgentGUIConversationDetail({
2673
+ timelineItems,
2674
+ conversation,
2675
+ workspaceRoot
2676
+ });
2677
+ if (!detail) {
2678
+ return { conversation: null, detail: null };
2576
2679
  }
2577
- const resolvedActivity = activityWithExplicitConversationTitle(
2578
- activity,
2579
- conversation
2580
- );
2581
- const conversationVM = projectWorkspaceAgentTimelineToConversationVM(
2582
- {
2583
- activity: resolvedActivity,
2584
- session,
2585
- timelineItems: [...timelineItems],
2586
- workspaceRoot
2587
- },
2588
- { avoidGroupingEdits }
2589
- );
2590
- return conversationVM;
2680
+ return {
2681
+ conversation: projectAgentConversationVM(detail, { avoidGroupingEdits }),
2682
+ detail
2683
+ };
2591
2684
  }
2592
2685
  function conversationSummaryFromAgentSession(session, options = {}) {
2593
2686
  const workspaceAgentSession = agentSessionToWorkspaceAgentSession(session);
2687
+ const projectResolver = createAgentGUIConversationProjectResolver(
2688
+ options.userProjects ?? [],
2689
+ { isNoProjectPath: options.isNoProjectPath }
2690
+ );
2594
2691
  const activity = buildWorkspaceAgentActivityListViewModel({
2595
2692
  presences: [],
2596
2693
  sessions: [workspaceAgentSession]
2597
2694
  }).activities[0] ?? null;
2598
2695
  if (activity) {
2599
2696
  return conversationSummaryFromActivity(activity, workspaceAgentSession, {
2600
- isNoProjectPath: options.isNoProjectPath,
2601
- userProjects: options.userProjects ?? []
2697
+ projectResolver
2602
2698
  });
2603
2699
  }
2604
2700
  const provider = resolveAgentGUIProviderIdentity({
@@ -2617,11 +2713,7 @@ function conversationSummaryFromAgentSession(session, options = {}) {
2617
2713
  titleFallback,
2618
2714
  status: conversationStatusFromActivity("idle"),
2619
2715
  cwd: session.cwd?.trim() ?? "",
2620
- project: resolveAgentGUIConversationProject(
2621
- session.cwd,
2622
- options.userProjects ?? [],
2623
- { isNoProjectPath: options.isNoProjectPath }
2624
- ),
2716
+ project: projectResolver.resolve(session.cwd),
2625
2717
  pinnedAtUnixMs: session.pinnedAtUnixMs ?? null,
2626
2718
  sortTimeUnixMs: resolveWorkspaceAgentSessionSortTimeUnixMs(
2627
2719
  workspaceAgentSession
@@ -2630,54 +2722,14 @@ function conversationSummaryFromAgentSession(session, options = {}) {
2630
2722
  syncState: void 0
2631
2723
  };
2632
2724
  }
2633
- function resolveAgentGUIConversationProject(cwd, userProjects = [], options = {}) {
2634
- const normalizedCwd = normalizeAgentGUIProjectPath(cwd);
2635
- if (!normalizedCwd) {
2636
- return null;
2637
- }
2638
- if (options.isNoProjectPath?.({ path: normalizedCwd })) {
2639
- return null;
2640
- }
2641
- let matchedProject = null;
2642
- let matchedPath = "";
2643
- for (const project of userProjects) {
2644
- const projectPath = normalizeAgentGUIProjectPath(project.path);
2645
- if (!projectPath || normalizedCwd !== projectPath && !normalizedCwd.startsWith(`${projectPath}/`)) {
2646
- continue;
2647
- }
2648
- if (projectPath.length <= matchedPath.length) {
2649
- continue;
2650
- }
2651
- matchedProject = project;
2652
- matchedPath = projectPath;
2653
- }
2654
- if (!matchedProject) {
2655
- return null;
2656
- }
2657
- const summary = {
2658
- id: matchedProject.id,
2659
- path: matchedProject.path,
2660
- label: resolveWorkspaceUserProjectDisplayLabel(matchedProject)
2661
- };
2662
- if (matchedProject.createdAtUnixMs !== void 0) {
2663
- summary.createdAtUnixMs = matchedProject.createdAtUnixMs;
2664
- }
2665
- if (matchedProject.updatedAtUnixMs !== void 0) {
2666
- summary.updatedAtUnixMs = matchedProject.updatedAtUnixMs;
2667
- }
2668
- if (matchedProject.lastUsedAtUnixMs !== void 0) {
2669
- summary.lastUsedAtUnixMs = matchedProject.lastUsedAtUnixMs;
2670
- }
2671
- return cachedAgentGUIConversationProjectSummary(summary);
2672
- }
2673
2725
  function applyAgentGUIConversationProjects(conversations, userProjects = [], options = {}) {
2674
2726
  let changed = false;
2727
+ const projectResolver = createAgentGUIConversationProjectResolver(
2728
+ userProjects,
2729
+ options
2730
+ );
2675
2731
  const next = conversations.map((conversation) => {
2676
- const project = resolveAgentGUIConversationProject(
2677
- conversation.cwd,
2678
- userProjects,
2679
- options
2680
- );
2732
+ const project = projectResolver.resolve(conversation.cwd);
2681
2733
  if (isSameAgentGUIConversationProject(conversation.project, project)) {
2682
2734
  return conversation;
2683
2735
  }
@@ -2732,7 +2784,7 @@ function filterAgentGUIRuntimeSnapshot(snapshot3) {
2732
2784
  function isAgentGUIRuntimeSession(session) {
2733
2785
  return session.agentSessionId.trim().length > 0 && isWorkspaceAgentActivityRuntimeSessionOrigin(session.sessionOrigin);
2734
2786
  }
2735
- function conversationSummaryFromActivity(activity, session, options = {}) {
2787
+ function conversationSummaryFromActivity(activity, session, options) {
2736
2788
  const status = conversationStatusFromActivity(activity.status);
2737
2789
  const provider = resolveAgentGUIProviderIdentity({
2738
2790
  workspaceSessionProvider: session?.provider,
@@ -2756,46 +2808,13 @@ function conversationSummaryFromActivity(activity, session, options = {}) {
2756
2808
  titleFallback,
2757
2809
  status,
2758
2810
  cwd: session?.cwd.trim() ?? "",
2759
- project: resolveAgentGUIConversationProject(
2760
- session?.cwd,
2761
- options.userProjects ?? [],
2762
- { isNoProjectPath: options.isNoProjectPath }
2763
- ),
2811
+ project: options.projectResolver.resolve(session?.cwd),
2764
2812
  pinnedAtUnixMs: session?.pinnedAtUnixMs ?? null,
2765
2813
  sortTimeUnixMs: activity.sortTimeUnixMs,
2766
2814
  updatedAtUnixMs: session?.updatedAtUnixMs || activity.sortTimeUnixMs || 0,
2767
2815
  syncState: session?.syncState
2768
2816
  };
2769
2817
  }
2770
- function normalizeAgentGUIProjectPath(path) {
2771
- const normalized = path?.trim().replaceAll("\\", "/") ?? "";
2772
- if (!normalized) {
2773
- return "";
2774
- }
2775
- return normalized.replace(/\/+$/, "") || "/";
2776
- }
2777
- function cachedAgentGUIConversationProjectSummary(summary) {
2778
- const key = [
2779
- summary.id,
2780
- summary.path,
2781
- summary.label,
2782
- summary.createdAtUnixMs ?? "",
2783
- summary.updatedAtUnixMs ?? "",
2784
- summary.lastUsedAtUnixMs ?? ""
2785
- ].join("");
2786
- const cached = agentGUIConversationProjectSummaryCache.get(key);
2787
- if (cached) {
2788
- return cached;
2789
- }
2790
- if (agentGUIConversationProjectSummaryCache.size >= AGENT_GUI_CONVERSATION_PROJECT_SUMMARY_CACHE_LIMIT) {
2791
- const oldestKey = agentGUIConversationProjectSummaryCache.keys().next().value;
2792
- if (oldestKey) {
2793
- agentGUIConversationProjectSummaryCache.delete(oldestKey);
2794
- }
2795
- }
2796
- agentGUIConversationProjectSummaryCache.set(key, summary);
2797
- return summary;
2798
- }
2799
2818
  function isSameAgentGUIConversationProject(left, right) {
2800
2819
  if (!left && !right) {
2801
2820
  return true;
@@ -3966,7 +3985,7 @@ function watchAgentSession(payload, options = {}) {
3966
3985
  entry = {
3967
3986
  key,
3968
3987
  payload: normalizedPayload2,
3969
- listeners: /* @__PURE__ */ new Set(),
3988
+ batchListeners: /* @__PURE__ */ new Set(),
3970
3989
  lingerTimer: null,
3971
3990
  pendingMessageBatch: null,
3972
3991
  releaseRuntimeEvents: null,
@@ -3975,8 +3994,8 @@ function watchAgentSession(payload, options = {}) {
3975
3994
  activityStreamEntries.set(key, entry);
3976
3995
  }
3977
3996
  clearEntryLingerTimer(entry);
3978
- if (options.onEvent) {
3979
- entry.listeners.add(options.onEvent);
3997
+ if (options.onEvents) {
3998
+ entry.batchListeners.add(options.onEvents);
3980
3999
  }
3981
4000
  ignoreEmptyViewUpdatesAfterTestReset = false;
3982
4001
  updateAgentSessionView(normalizedPayload2, (current) => ({
@@ -3991,8 +4010,8 @@ function watchAgentSession(payload, options = {}) {
3991
4010
  if (!currentEntry) {
3992
4011
  return;
3993
4012
  }
3994
- if (options.onEvent) {
3995
- currentEntry.listeners.delete(options.onEvent);
4013
+ if (options.onEvents) {
4014
+ currentEntry.batchListeners.delete(options.onEvents);
3996
4015
  }
3997
4016
  updateAgentSessionView(normalizedPayload2, (current) => ({
3998
4017
  ...current,
@@ -4257,11 +4276,7 @@ function flushPendingMessageBatch(entry) {
4257
4276
  return;
4258
4277
  }
4259
4278
  recordAgentSessionStreamEvents(entry, batch.events);
4260
- for (const event of batch.events) {
4261
- for (const listener of entry.listeners) {
4262
- listener(event);
4263
- }
4264
- }
4279
+ dispatchAgentSessionStreamEvents(entry, batch.events);
4265
4280
  reportMessageBatchDiagnostics(entry, batch);
4266
4281
  }
4267
4282
  function clearPendingMessageBatch(entry) {
@@ -4277,8 +4292,14 @@ function clearPendingMessageBatch(entry) {
4277
4292
  }
4278
4293
  function dispatchAgentSessionStreamEvent(entry, event) {
4279
4294
  recordAgentSessionStreamEvent(entry, event);
4280
- for (const listener of entry.listeners) {
4281
- listener(event);
4295
+ dispatchAgentSessionStreamEvents(entry, [event]);
4296
+ }
4297
+ function dispatchAgentSessionStreamEvents(entry, events) {
4298
+ if (events.length === 0) {
4299
+ return;
4300
+ }
4301
+ for (const listener of entry.batchListeners) {
4302
+ listener(events);
4282
4303
  }
4283
4304
  }
4284
4305
  function upsertCoalescedMessageUpdate(events, event) {
@@ -4466,14 +4487,15 @@ function useAgentSessionView2(ref) {
4466
4487
  return useAgentSessionView(ref);
4467
4488
  }
4468
4489
  function useWatchAgentSession(input) {
4469
- const onEventRef = useRef3(input.onEvent);
4490
+ const onEventsRef = useRef3(input.onEvents);
4470
4491
  const onSubscribeRef = useRef3(input.onSubscribe);
4471
4492
  const onCleanupRef = useRef3(input.onCleanup);
4493
+ const hasBatchEventListener = input.onEvents !== void 0;
4472
4494
  useEffect3(() => {
4473
- onEventRef.current = input.onEvent;
4495
+ onEventsRef.current = input.onEvents;
4474
4496
  onSubscribeRef.current = input.onSubscribe;
4475
4497
  onCleanupRef.current = input.onCleanup;
4476
- }, [input.onCleanup, input.onEvent, input.onSubscribe]);
4498
+ }, [input.onCleanup, input.onEvents, input.onSubscribe]);
4477
4499
  useEffect3(() => {
4478
4500
  const workspaceId = input.workspaceId.trim();
4479
4501
  const agentSessionId = input.agentSessionId?.trim();
@@ -4484,25 +4506,33 @@ function useWatchAgentSession(input) {
4484
4506
  const unsubscribe = watchAgentSession(
4485
4507
  { workspaceId, agentSessionId },
4486
4508
  {
4487
- onEvent: (event) => {
4488
- onEventRef.current?.(event);
4489
- }
4509
+ ...hasBatchEventListener ? {
4510
+ onEvents: (events) => {
4511
+ onEventsRef.current?.(events);
4512
+ }
4513
+ } : {}
4490
4514
  }
4491
4515
  );
4492
4516
  return () => {
4493
4517
  onCleanupRef.current?.();
4494
4518
  unsubscribe();
4495
4519
  };
4496
- }, [input.agentSessionId, input.enabled, input.workspaceId]);
4520
+ }, [
4521
+ hasBatchEventListener,
4522
+ input.agentSessionId,
4523
+ input.enabled,
4524
+ input.workspaceId
4525
+ ]);
4497
4526
  }
4498
4527
  function useWatchAgentSessions(input) {
4499
- const onEventRef = useRef3(input.onEvent);
4528
+ const onEventsRef = useRef3(input.onEvents);
4529
+ const hasBatchEventListener = input.onEvents !== void 0;
4500
4530
  const agentSessionIdsKey = JSON.stringify(
4501
4531
  [...new Set(input.agentSessionIds.map((id) => id.trim()))].filter(Boolean).sort()
4502
4532
  );
4503
4533
  useEffect3(() => {
4504
- onEventRef.current = input.onEvent;
4505
- }, [input.onEvent]);
4534
+ onEventsRef.current = input.onEvents;
4535
+ }, [input.onEvents]);
4506
4536
  useEffect3(() => {
4507
4537
  const workspaceId = input.workspaceId.trim();
4508
4538
  if (!input.enabled || !workspaceId) {
@@ -4516,9 +4546,11 @@ function useWatchAgentSessions(input) {
4516
4546
  (agentSessionId) => watchAgentSession(
4517
4547
  { workspaceId, agentSessionId },
4518
4548
  {
4519
- onEvent: (event) => {
4520
- onEventRef.current?.(event);
4521
- }
4549
+ ...hasBatchEventListener ? {
4550
+ onEvents: (events) => {
4551
+ onEventsRef.current?.(events);
4552
+ }
4553
+ } : {}
4522
4554
  }
4523
4555
  )
4524
4556
  );
@@ -4527,7 +4559,12 @@ function useWatchAgentSessions(input) {
4527
4559
  unsubscribe();
4528
4560
  }
4529
4561
  };
4530
- }, [agentSessionIdsKey, input.enabled, input.workspaceId]);
4562
+ }, [
4563
+ agentSessionIdsKey,
4564
+ hasBatchEventListener,
4565
+ input.enabled,
4566
+ input.workspaceId
4567
+ ]);
4531
4568
  }
4532
4569
 
4533
4570
  // contexts/workspace/presentation/renderer/agentGuiConversationList/agentGuiConversationListStore.ts
@@ -4634,6 +4671,7 @@ var listeners = /* @__PURE__ */ new Set();
4634
4671
  var refreshTimers = /* @__PURE__ */ new Map();
4635
4672
  var inflightRefreshByQueryKey = /* @__PURE__ */ new Map();
4636
4673
  var needsRefreshAfterInflight = /* @__PURE__ */ new Set();
4674
+ var pendingDirtySessionIdsByQueryKey = /* @__PURE__ */ new Map();
4637
4675
  var requestIdByQueryKey = /* @__PURE__ */ new Map();
4638
4676
  var localCreatedConversationIdsByQueryKey = /* @__PURE__ */ new Map();
4639
4677
  var deletedConversationIdsByQueryKey = /* @__PURE__ */ new Map();
@@ -5143,6 +5181,53 @@ function mergeSessionMessagesById(left, right) {
5143
5181
  }
5144
5182
  return next;
5145
5183
  }
5184
+ function normalizeDirtySessionIds(sessionIds) {
5185
+ if (!sessionIds || sessionIds.length === 0) {
5186
+ return [];
5187
+ }
5188
+ const seen = /* @__PURE__ */ new Set();
5189
+ const normalized = [];
5190
+ for (const sessionId of sessionIds) {
5191
+ const value = sessionId.trim();
5192
+ if (!value || seen.has(value)) {
5193
+ continue;
5194
+ }
5195
+ seen.add(value);
5196
+ normalized.push(value);
5197
+ }
5198
+ return normalized;
5199
+ }
5200
+ function addPendingDirtySessionIds(queryKey, sessionIds) {
5201
+ const normalized = normalizeDirtySessionIds(sessionIds);
5202
+ if (normalized.length === 0) {
5203
+ return;
5204
+ }
5205
+ const pending = pendingDirtySessionIdsByQueryKey.get(queryKey) ?? /* @__PURE__ */ new Set();
5206
+ for (const sessionId of normalized) {
5207
+ pending.add(sessionId);
5208
+ }
5209
+ pendingDirtySessionIdsByQueryKey.set(queryKey, pending);
5210
+ }
5211
+ function consumePendingDirtySessionIds(queryKey) {
5212
+ const pending = pendingDirtySessionIdsByQueryKey.get(queryKey);
5213
+ pendingDirtySessionIdsByQueryKey.delete(queryKey);
5214
+ return pending ?? /* @__PURE__ */ new Set();
5215
+ }
5216
+ function decorateConversationForRefresh(input) {
5217
+ const title = resolveAgentGUIConversationTitleFromMessages({
5218
+ messages: input.mergedMessages,
5219
+ conversation: input.conversation
5220
+ });
5221
+ const nextConversation = {
5222
+ ...input.conversation,
5223
+ ...title ? { title: title.title, titleFallback: title.titleFallback } : {},
5224
+ hasUnreadCompletion: input.conversation.status === "completed" ? input.currentConversation?.status !== "completed" && !hasActiveConversationOwner(input.queryKey, input.conversation.id) ? true : input.conversation.hasUnreadCompletion ?? false : false,
5225
+ status: input.conversation.status,
5226
+ updatedAtUnixMs: input.conversation.updatedAtUnixMs,
5227
+ pinnedAtUnixMs: input.conversation.pinnedAtUnixMs
5228
+ };
5229
+ return areConversationsEqual(input.conversation, nextConversation) ? input.conversation : nextConversation;
5230
+ }
5146
5231
  async function loadWorkspaceAgentSnapshotForConversations(input) {
5147
5232
  const snapshot3 = await getAgentActivityRuntime().load(input.workspaceId);
5148
5233
  return workspaceAgentSnapshotForConversations(snapshot3);
@@ -5151,7 +5236,7 @@ function getWorkspaceAgentSnapshotForConversations(input) {
5151
5236
  const snapshot3 = getAgentActivityRuntime().getSnapshot(input.workspaceId);
5152
5237
  return workspaceAgentSnapshotForConversations(snapshot3);
5153
5238
  }
5154
- async function refreshAgentGUIConversationListQuery(query, reason) {
5239
+ async function refreshAgentGUIConversationListQuery(query, reason, options = {}) {
5155
5240
  const state = ensureQueryState(query);
5156
5241
  if (!state) {
5157
5242
  return;
@@ -5178,12 +5263,16 @@ async function refreshAgentGUIConversationListQuery(query, reason) {
5178
5263
  sessionOrigin: state.query.sessionOrigin,
5179
5264
  userId: state.query.userId
5180
5265
  };
5181
- const workspaceAgentSnapshot = reason === "workspace-agent-update" ? getWorkspaceAgentSnapshotForConversations(workspaceAgentsInput) : await loadWorkspaceAgentSnapshotForConversations(
5266
+ const workspaceAgentSnapshot = reason === "workspace-agent-update" || reason === "session-overlay-update" ? getWorkspaceAgentSnapshotForConversations(workspaceAgentsInput) : await loadWorkspaceAgentSnapshotForConversations(
5182
5267
  workspaceAgentsInput
5183
5268
  );
5184
5269
  if (requestId !== requestIdByQueryKey.get(queryKey)) {
5185
5270
  return;
5186
5271
  }
5272
+ const dirtySessionIds = consumePendingDirtySessionIds(queryKey);
5273
+ for (const sessionId of normalizeDirtySessionIds(options.dirtySessionIds)) {
5274
+ dirtySessionIds.add(sessionId);
5275
+ }
5187
5276
  const sessionViewDataById = workspaceSessionViewDataBySessionId(
5188
5277
  state.query.workspaceId
5189
5278
  );
@@ -5194,11 +5283,6 @@ async function refreshAgentGUIConversationListQuery(query, reason) {
5194
5283
  sessionViewDataById
5195
5284
  )
5196
5285
  );
5197
- const baseConversations = buildAgentGUIConversationSummaries({
5198
- snapshot: workspaceAgentSnapshot,
5199
- provider: state.query.provider,
5200
- sessionMessagesById: sessionMessagesByIdForSummaries
5201
- });
5202
5286
  const deletedConversationIds = deletedConversationIdsByQueryKey.get(queryKey) ?? /* @__PURE__ */ new Set();
5203
5287
  const localCreatedConversationIds = localCreatedConversationIdsByQueryKey.get(queryKey) ?? /* @__PURE__ */ new Set();
5204
5288
  const snapshotSessionIds = new Set(
@@ -5229,6 +5313,24 @@ async function refreshAgentGUIConversationListQuery(query, reason) {
5229
5313
  conversation
5230
5314
  ])
5231
5315
  );
5316
+ const canApplyDirtySessionProjection = reason === "session-overlay-update" && state.initialized && dirtySessionIds.size > 0;
5317
+ const projectionSessions = canApplyDirtySessionProjection ? workspaceAgentSnapshot.sessions.filter((session) => {
5318
+ const agentSessionId = session.agentSessionId.trim();
5319
+ const syncSessionId = session.syncState?.agentSessionId?.trim() ?? "";
5320
+ return agentSessionId && dirtySessionIds.has(agentSessionId) || syncSessionId && dirtySessionIds.has(syncSessionId);
5321
+ }) : workspaceAgentSnapshot.sessions;
5322
+ const baseConversations = buildAgentGUIConversationSummaries({
5323
+ snapshot: canApplyDirtySessionProjection ? {
5324
+ ...workspaceAgentSnapshot,
5325
+ sessions: projectionSessions
5326
+ } : workspaceAgentSnapshot,
5327
+ provider: state.query.provider,
5328
+ sessionMessagesById: sessionMessagesByIdForSummaries
5329
+ });
5330
+ const conversationsToDecorate = canApplyDirtySessionProjection ? /* @__PURE__ */ new Set([
5331
+ ...dirtySessionIds,
5332
+ ...baseConversations.map((conversation) => conversation.id)
5333
+ ]) : null;
5232
5334
  const retainedSessionIds = new Set(retainedSnapshotSessionIds);
5233
5335
  if (reason === "workspace-agent-update") {
5234
5336
  for (const conversation of currentConversations) {
@@ -5244,6 +5346,13 @@ async function refreshAgentGUIConversationListQuery(query, reason) {
5244
5346
  }
5245
5347
  }
5246
5348
  }
5349
+ if (canApplyDirtySessionProjection) {
5350
+ for (const conversation of currentConversations) {
5351
+ if (!nextDeletedConversationIds.has(conversation.id)) {
5352
+ retainedSessionIds.add(conversation.id);
5353
+ }
5354
+ }
5355
+ }
5247
5356
  const nextConversations = sortConversationsByRecency(
5248
5357
  mergeLoadedConversations(
5249
5358
  currentConversations,
@@ -5254,24 +5363,21 @@ async function refreshAgentGUIConversationListQuery(query, reason) {
5254
5363
  ),
5255
5364
  createConversationOrderIndex(currentConversations)
5256
5365
  ).map((conversation) => {
5366
+ if (conversationsToDecorate !== null && !conversationsToDecorate.has(conversation.id)) {
5367
+ return conversation;
5368
+ }
5257
5369
  const currentConversation = currentConversationById.get(conversation.id);
5258
5370
  const sessionViewData = sessionViewDataById[conversation.id];
5259
5371
  const mergedMessages = sessionMessagesByIdForSummaries[conversation.id] ?? mergeWorkspaceAgentActivityDurableAndOverlayMessages({
5260
5372
  durableMessages: workspaceAgentSnapshot.sessionMessagesById?.[conversation.id],
5261
5373
  localMessages: sessionViewData?.overlayMessages
5262
5374
  });
5263
- const title = resolveAgentGUIConversationTitleFromMessages({
5264
- messages: mergedMessages,
5265
- conversation
5375
+ return decorateConversationForRefresh({
5376
+ conversation,
5377
+ currentConversation,
5378
+ mergedMessages,
5379
+ queryKey
5266
5380
  });
5267
- return {
5268
- ...conversation,
5269
- ...title ? { title: title.title, titleFallback: title.titleFallback } : {},
5270
- hasUnreadCompletion: conversation.status === "completed" ? currentConversation?.status !== "completed" && !hasActiveConversationOwner(queryKey, conversation.id) ? true : conversation.hasUnreadCompletion ?? false : false,
5271
- status: conversation.status,
5272
- updatedAtUnixMs: conversation.updatedAtUnixMs,
5273
- pinnedAtUnixMs: conversation.pinnedAtUnixMs
5274
- };
5275
5381
  });
5276
5382
  updateQueryState(query, (current) => {
5277
5383
  const conversations = areConversationListsEqual(
@@ -5308,12 +5414,13 @@ async function refreshAgentGUIConversationListQuery(query, reason) {
5308
5414
  throw error;
5309
5415
  }
5310
5416
  }
5311
- function scheduleQueryRefresh(query, _reason) {
5417
+ function scheduleQueryRefresh(query, _reason, options = {}) {
5312
5418
  const state = ensureQueryState(query);
5313
5419
  if (!state) {
5314
5420
  return;
5315
5421
  }
5316
5422
  const queryKey = state.queryKey;
5423
+ addPendingDirtySessionIds(queryKey, options.dirtySessionIds);
5317
5424
  const delayMs = _reason === "projection-sync" && !state.initialized ? 0 : REFRESH_DEBOUNCE_MS;
5318
5425
  const runRefresh = () => {
5319
5426
  refreshTimers.delete(queryKey);
@@ -5321,7 +5428,11 @@ function scheduleQueryRefresh(query, _reason) {
5321
5428
  needsRefreshAfterInflight.add(queryKey);
5322
5429
  return;
5323
5430
  }
5324
- const promise = refreshAgentGUIConversationListQuery(state.query, _reason).catch(() => void 0).finally(() => {
5431
+ const promise = refreshAgentGUIConversationListQuery(
5432
+ state.query,
5433
+ _reason,
5434
+ options
5435
+ ).catch(() => void 0).finally(() => {
5325
5436
  inflightRefreshByQueryKey.delete(queryKey);
5326
5437
  if (needsRefreshAfterInflight.has(queryKey)) {
5327
5438
  needsRefreshAfterInflight.delete(queryKey);
@@ -5379,8 +5490,8 @@ function isAgentGUIConversationListRefreshing(query) {
5379
5490
  const key = createAgentGUIConversationListQueryKey(query);
5380
5491
  return key !== null && inflightRefreshByQueryKey.has(key);
5381
5492
  }
5382
- function scheduleAgentGUIConversationListProjection(query, reason) {
5383
- scheduleQueryRefresh(query, reason);
5493
+ function scheduleAgentGUIConversationListProjection(query, reason, options = {}) {
5494
+ scheduleQueryRefresh(query, reason, options);
5384
5495
  }
5385
5496
  function stripProjectFromConversations(conversations) {
5386
5497
  let changed = false;
@@ -6401,14 +6512,83 @@ function mergeVisibleConversations(conversations, transientConversation) {
6401
6512
  }
6402
6513
  function stableConversationSummaryList(previous, next) {
6403
6514
  if (previous?.length !== next.length) {
6404
- return next;
6515
+ const previousById = new Map(
6516
+ (previous ?? []).map((conversation) => [conversation.id, conversation])
6517
+ );
6518
+ return next.map((conversation) => {
6519
+ const previousConversation = previousById.get(conversation.id);
6520
+ return previousConversation && conversationSummariesRenderEqual(previousConversation, conversation) ? previousConversation : conversation;
6521
+ });
6405
6522
  }
6406
- for (let index = 0; index < next.length; index += 1) {
6407
- if (previous[index] !== next[index]) {
6408
- return next;
6523
+ let hasRenderChange = false;
6524
+ const stable = next.map((conversation, index) => {
6525
+ const previousConversation = previous[index];
6526
+ if (previousConversation && conversationSummariesRenderEqual(previousConversation, conversation)) {
6527
+ return previousConversation;
6409
6528
  }
6529
+ hasRenderChange = true;
6530
+ return conversation;
6531
+ });
6532
+ return hasRenderChange ? stable : previous;
6533
+ }
6534
+ function useStableConversationDetail(detail) {
6535
+ const detailRef = useRef4(null);
6536
+ detailRef.current = stabilizeConversationDetail(detailRef.current, detail);
6537
+ return detailRef.current;
6538
+ }
6539
+ function stabilizeConversationDetail(previous, next) {
6540
+ if (!previous || !next) {
6541
+ return next;
6410
6542
  }
6411
- return previous;
6543
+ const session = conversationDetailSessionsEqual(
6544
+ previous.session,
6545
+ next.session
6546
+ ) ? previous.session : next.session;
6547
+ const activity = stabilizeConversationDetailActivity(
6548
+ previous.activity,
6549
+ next.activity
6550
+ );
6551
+ if (previous.cwd === next.cwd && previous.workspaceRoot === next.workspaceRoot && previous.showProcessingIndicator === next.showProcessingIndicator && previous.turns === next.turns && previous.session === session && previous.activity === activity) {
6552
+ return previous;
6553
+ }
6554
+ return {
6555
+ ...next,
6556
+ activity,
6557
+ session
6558
+ };
6559
+ }
6560
+ function stabilizeConversationDetailActivity(previous, next) {
6561
+ const changedFiles = conversationDetailChangedFilesEqual(
6562
+ previous.changedFiles,
6563
+ next.changedFiles
6564
+ ) ? previous.changedFiles : next.changedFiles;
6565
+ if (previous.id === next.id && previous.sessionId === next.sessionId && previous.userId === next.userId && previous.userName === next.userName && previous.userAvatarUrl === next.userAvatarUrl && previous.agentProvider === next.agentProvider && previous.agentName === next.agentName && previous.title === next.title && previous.status === next.status && previous.latestActivitySummary === next.latestActivitySummary && previous.conversationPreview === next.conversationPreview && previous.latestActivityActorName === next.latestActivityActorName && previous.toolCalls === next.toolCalls && previous.changedFiles === changedFiles && previous.sortTimeUnixMs === next.sortTimeUnixMs && previous.readTimeUnixMs === next.readTimeUnixMs) {
6566
+ return previous;
6567
+ }
6568
+ return {
6569
+ ...next,
6570
+ changedFiles
6571
+ };
6572
+ }
6573
+ function conversationDetailChangedFilesEqual(left, right) {
6574
+ return left.length === right.length && left.every(
6575
+ (file, index) => file.path === right[index]?.path && file.label === right[index]?.label
6576
+ );
6577
+ }
6578
+ function conversationDetailSessionsEqual(left, right) {
6579
+ return left.id === right.id && left.workspaceId === right.workspaceId && left.agentSessionId === right.agentSessionId && left.presenceId === right.presenceId && left.userId === right.userId && left.provider === right.provider && left.providerSessionId === right.providerSessionId && left.resumable === right.resumable && left.sessionOrigin === right.sessionOrigin && left.lifecycleStatus === right.lifecycleStatus && left.turnPhase === right.turnPhase && left.endedAtUnixMs === right.endedAtUnixMs && left.effectiveStatus === right.effectiveStatus && left.status === right.status && left.title === right.title && left.pinnedAtUnixMs === right.pinnedAtUnixMs && left.createdAtUnixMs === right.createdAtUnixMs && left.updatedAtUnixMs === right.updatedAtUnixMs && left.cwd === right.cwd && conversationSyncStatesEqual(left.syncState, right.syncState);
6580
+ }
6581
+ function conversationSummariesRenderEqual(left, right) {
6582
+ return left.id === right.id && left.userId === right.userId && left.provider === right.provider && left.title === right.title && conversationTitleFallbacksRenderEqual(
6583
+ left.titleFallback,
6584
+ right.titleFallback
6585
+ ) && left.status === right.status && left.cwd === right.cwd && left.pinnedAtUnixMs === right.pinnedAtUnixMs && left.sortTimeUnixMs === right.sortTimeUnixMs && left.updatedAtUnixMs === right.updatedAtUnixMs && left.hasUnreadCompletion === right.hasUnreadCompletion && conversationProjectsRenderEqual(left.project, right.project) && conversationSyncStatesEqual(left.syncState, right.syncState);
6586
+ }
6587
+ function conversationTitleFallbacksRenderEqual(left, right) {
6588
+ return left === right || JSON.stringify(left ?? null) === JSON.stringify(right ?? null);
6589
+ }
6590
+ function conversationProjectsRenderEqual(left, right) {
6591
+ return left === right || (!left || !right ? !left && !right : left.id === right.id && left.path === right.path && left.label === right.label && left.createdAtUnixMs === right.createdAtUnixMs && left.updatedAtUnixMs === right.updatedAtUnixMs && left.lastUsedAtUnixMs === right.lastUsedAtUnixMs);
6412
6592
  }
6413
6593
  function mergeConversationTitleUpdateFields(current, incomingTitle, provider) {
6414
6594
  const title = incomingTitle.trim();
@@ -6826,7 +7006,7 @@ function useStableProviderSkillOptions(skills) {
6826
7006
  return skillsRef.current;
6827
7007
  }
6828
7008
  function areComposerSettingsDraftsEqual(left, right) {
6829
- return left.model === right.model && left.reasoningEffort === right.reasoningEffort && left.speed === right.speed && left.planMode === right.planMode && (left.permissionModeId ?? null) === (right.permissionModeId ?? null);
7009
+ return left.model === right.model && left.reasoningEffort === right.reasoningEffort && left.speed === right.speed && left.planMode === right.planMode && (left.browserUse ?? true) === (right.browserUse ?? true) && (left.computerUse ?? true) === (right.computerUse ?? true) && (left.permissionModeId ?? null) === (right.permissionModeId ?? null);
6830
7010
  }
6831
7011
  function arePermissionModeOptionsEqual(left, right) {
6832
7012
  return left.id === right.id && left.label === right.label && left.description === right.description && left.semantic === right.semantic;
@@ -6840,7 +7020,7 @@ function arePermissionConfigsEqual(left, right) {
6840
7020
  );
6841
7021
  }
6842
7022
  function areComposerSettingsVMsEqual(left, right) {
6843
- return left.sessionSettings === right.sessionSettings && areComposerSettingsDraftsEqual(left.draftSettings, right.draftSettings) && left.supportsModel === right.supportsModel && left.supportsReasoningEffort === right.supportsReasoningEffort && left.supportsSpeed === right.supportsSpeed && (left.supportsPermissionMode ?? false) === (right.supportsPermissionMode ?? false) && left.supportsPlanMode === right.supportsPlanMode && left.isSettingsLoading === right.isSettingsLoading && left.modelUnavailable === right.modelUnavailable && left.reasoningUnavailable === right.reasoningUnavailable && left.speedUnavailable === right.speedUnavailable && (left.permissionModeUnavailable ?? false) === (right.permissionModeUnavailable ?? false) && (left.planExclusiveWithPermissionMode ?? false) === (right.planExclusiveWithPermissionMode ?? false) && (left.selectedModelValue ?? null) === (right.selectedModelValue ?? null) && (left.selectedReasoningEffortValue ?? null) === (right.selectedReasoningEffortValue ?? null) && (left.selectedSpeedValue ?? null) === (right.selectedSpeedValue ?? null) && (left.selectedPermissionModeValue ?? null) === (right.selectedPermissionModeValue ?? null) && arePermissionConfigsEqual(left.permissionConfig, right.permissionConfig) && (left.selectedProjectPath ?? null) === (right.selectedProjectPath ?? null) && Boolean(left.projectLocked) === Boolean(right.projectLocked) && areComposerSettingOptionListsEqual(
7023
+ return sameComposerSettings(left.sessionSettings, right.sessionSettings) && areComposerSettingsDraftsEqual(left.draftSettings, right.draftSettings) && left.supportsModel === right.supportsModel && left.supportsReasoningEffort === right.supportsReasoningEffort && left.supportsSpeed === right.supportsSpeed && (left.supportsPermissionMode ?? false) === (right.supportsPermissionMode ?? false) && left.supportsPlanMode === right.supportsPlanMode && (left.supportsBrowser ?? false) === (right.supportsBrowser ?? false) && (left.supportsComputerUse ?? false) === (right.supportsComputerUse ?? false) && left.isSettingsLoading === right.isSettingsLoading && left.modelUnavailable === right.modelUnavailable && left.reasoningUnavailable === right.reasoningUnavailable && left.speedUnavailable === right.speedUnavailable && (left.permissionModeUnavailable ?? false) === (right.permissionModeUnavailable ?? false) && (left.planExclusiveWithPermissionMode ?? false) === (right.planExclusiveWithPermissionMode ?? false) && (left.selectedModelValue ?? null) === (right.selectedModelValue ?? null) && (left.selectedReasoningEffortValue ?? null) === (right.selectedReasoningEffortValue ?? null) && (left.selectedSpeedValue ?? null) === (right.selectedSpeedValue ?? null) && (left.selectedPermissionModeValue ?? null) === (right.selectedPermissionModeValue ?? null) && arePermissionConfigsEqual(left.permissionConfig, right.permissionConfig) && (left.selectedProjectPath ?? null) === (right.selectedProjectPath ?? null) && Boolean(left.projectLocked) === Boolean(right.projectLocked) && areComposerSettingOptionListsEqual(
6844
7024
  left.availableModels,
6845
7025
  right.availableModels
6846
7026
  ) && areComposerSettingOptionListsEqual(
@@ -6856,11 +7036,58 @@ function areComposerSettingsVMsEqual(left, right) {
6856
7036
  }
6857
7037
  function useStableComposerSettingsVM(settings) {
6858
7038
  const settingsRef = useRef4(null);
6859
- if (settingsRef.current === null || !areComposerSettingsVMsEqual(settingsRef.current, settings)) {
6860
- settingsRef.current = settings;
6861
- }
7039
+ settingsRef.current = stabilizeComposerSettingsVM(
7040
+ settingsRef.current,
7041
+ settings
7042
+ );
6862
7043
  return settingsRef.current;
6863
7044
  }
7045
+ function stabilizeComposerSettingsVM(previous, next) {
7046
+ if (!previous) {
7047
+ return next;
7048
+ }
7049
+ if (areComposerSettingsVMsEqual(previous, next)) {
7050
+ return previous;
7051
+ }
7052
+ const sessionSettings = sameComposerSettings(
7053
+ previous.sessionSettings,
7054
+ next.sessionSettings
7055
+ ) ? previous.sessionSettings : next.sessionSettings;
7056
+ const draftSettings = areComposerSettingsDraftsEqual(
7057
+ previous.draftSettings,
7058
+ next.draftSettings
7059
+ ) ? previous.draftSettings : next.draftSettings;
7060
+ const permissionConfig = arePermissionConfigsEqual(
7061
+ previous.permissionConfig,
7062
+ next.permissionConfig
7063
+ ) ? previous.permissionConfig : next.permissionConfig;
7064
+ const availableModels = areComposerSettingOptionListsEqual(
7065
+ previous.availableModels,
7066
+ next.availableModels
7067
+ ) ? previous.availableModels : next.availableModels;
7068
+ const availableReasoningEfforts = areComposerSettingOptionListsEqual(
7069
+ previous.availableReasoningEfforts,
7070
+ next.availableReasoningEfforts
7071
+ ) ? previous.availableReasoningEfforts : next.availableReasoningEfforts;
7072
+ const availableSpeeds = areComposerSettingOptionListsEqual(
7073
+ previous.availableSpeeds,
7074
+ next.availableSpeeds
7075
+ ) ? previous.availableSpeeds : next.availableSpeeds;
7076
+ const availablePermissionModes = areComposerSettingOptionListsEqual(
7077
+ previous.availablePermissionModes ?? [],
7078
+ next.availablePermissionModes ?? []
7079
+ ) ? previous.availablePermissionModes : next.availablePermissionModes;
7080
+ return {
7081
+ ...next,
7082
+ sessionSettings,
7083
+ draftSettings,
7084
+ permissionConfig,
7085
+ availableModels,
7086
+ availableReasoningEfforts,
7087
+ availableSpeeds,
7088
+ availablePermissionModes
7089
+ };
7090
+ }
6864
7091
  function useStableControllerEventCallback(callback) {
6865
7092
  const callbackRef = useRef4(callback);
6866
7093
  callbackRef.current = callback;
@@ -7210,7 +7437,9 @@ function useAgentGUINodeController({
7210
7437
  );
7211
7438
  const [pendingCreateConversationId, setPendingCreateConversationId] = useState4(resolvePendingCreateConversationId);
7212
7439
  const conversations = conversationListState?.conversations ?? [];
7213
- const [userProjects, setUserProjects] = useState4([]);
7440
+ const [userProjects, setUserProjects] = useState4(
7441
+ () => readAgentGUIUserProjectSnapshot(agentHostApi.userProjects)
7442
+ );
7214
7443
  const isNoProjectPath = agentHostApi.userProjects?.isNoProjectPath;
7215
7444
  const [activeConversationId, setActiveConversationId] = useState4(data.lastActiveAgentSessionId);
7216
7445
  const [intent, setIntent] = useState4(
@@ -7411,7 +7640,16 @@ function useAgentGUINodeController({
7411
7640
  [agentActivitySnapshot.sessions]
7412
7641
  );
7413
7642
  const stableRuntimeSyncStateBySessionId = useMemo4(() => {
7414
- const next = { ...stableRuntimeSyncStateBySessionIdRef.current };
7643
+ const current = stableRuntimeSyncStateBySessionIdRef.current;
7644
+ let next = current;
7645
+ let changed = false;
7646
+ const mutableNext = () => {
7647
+ if (!changed) {
7648
+ next = { ...current };
7649
+ changed = true;
7650
+ }
7651
+ return next;
7652
+ };
7415
7653
  const activeSessionIds = /* @__PURE__ */ new Set();
7416
7654
  for (const session of agentActivitySnapshot.sessions) {
7417
7655
  const agentSessionId = session.agentSessionId.trim();
@@ -7421,7 +7659,9 @@ function useAgentGUINodeController({
7421
7659
  activeSessionIds.add(agentSessionId);
7422
7660
  const nextSyncState = runtimeSessionSyncState(session);
7423
7661
  if (!nextSyncState) {
7424
- delete next[agentSessionId];
7662
+ if (current[agentSessionId] !== void 0) {
7663
+ delete mutableNext()[agentSessionId];
7664
+ }
7425
7665
  delete latestRuntimeSyncStateBySessionIdRef.current[agentSessionId];
7426
7666
  continue;
7427
7667
  }
@@ -7435,16 +7675,18 @@ function useAgentGUINodeController({
7435
7675
  };
7436
7676
  const currentSyncState = next[agentSessionId];
7437
7677
  if (!currentSyncState || !syncStateRenderFieldsEqual(currentSyncState, nextSyncState)) {
7438
- next[agentSessionId] = nextSyncState;
7678
+ mutableNext()[agentSessionId] = nextSyncState;
7439
7679
  }
7440
7680
  }
7441
7681
  for (const agentSessionId of Object.keys(next)) {
7442
7682
  if (!activeSessionIds.has(agentSessionId)) {
7443
- delete next[agentSessionId];
7683
+ delete mutableNext()[agentSessionId];
7444
7684
  delete latestRuntimeSyncStateBySessionIdRef.current[agentSessionId];
7445
7685
  }
7446
7686
  }
7447
- stableRuntimeSyncStateBySessionIdRef.current = next;
7687
+ if (changed) {
7688
+ stableRuntimeSyncStateBySessionIdRef.current = next;
7689
+ }
7448
7690
  return next;
7449
7691
  }, [agentActivitySnapshot.sessions]);
7450
7692
  const markSessionSettingsRequestState = useCallback4(
@@ -7633,11 +7875,9 @@ function useAgentGUINodeController({
7633
7875
  []
7634
7876
  );
7635
7877
  useEffect4(() => {
7636
- if (previewMode) {
7637
- return void 0;
7638
- }
7639
7878
  const api = agentHostApi.userProjects;
7640
7879
  let disposed = false;
7880
+ setUserProjectsSnapshot(readAgentGUIUserProjectSnapshot(api));
7641
7881
  const loadUserProjects = async () => {
7642
7882
  const requestSeq = ++userProjectsLoadSeqRef.current;
7643
7883
  if (!api) {
@@ -7658,7 +7898,7 @@ function useAgentGUINodeController({
7658
7898
  }
7659
7899
  };
7660
7900
  void loadUserProjects();
7661
- const unsubscribe = api?.subscribe?.(() => {
7901
+ const unsubscribe = previewMode ? void 0 : api?.subscribe?.(() => {
7662
7902
  void loadUserProjects();
7663
7903
  });
7664
7904
  return () => {
@@ -8884,11 +9124,19 @@ function useAgentGUINodeController({
8884
9124
  sessionViewRef(agentSessionId),
8885
9125
  overlayMessages
8886
9126
  );
9127
+ if (conversationListQuery) {
9128
+ scheduleAgentGUIConversationListProjection(
9129
+ conversationListQuery,
9130
+ "session-overlay-update",
9131
+ { dirtySessionIds: [agentSessionId] }
9132
+ );
9133
+ }
8887
9134
  applyTimelineProjectionUpdate(agentSessionId, nextItems, mergedItems);
8888
9135
  },
8889
9136
  [
8890
9137
  agentActivitySnapshot.sessionMessagesById,
8891
9138
  applyTimelineProjectionUpdate,
9139
+ conversationListQuery,
8892
9140
  sessionViewRef
8893
9141
  ]
8894
9142
  );
@@ -9002,39 +9250,50 @@ function useAgentGUINodeController({
9002
9250
  workspaceId
9003
9251
  ]
9004
9252
  );
9005
- const handleActivityStreamEvent = useCallback4(
9006
- (event) => {
9007
- if (event.eventType === "available_commands_update") {
9008
- return;
9009
- }
9010
- if (event.eventType === "message_update") {
9011
- const message = messageFromMessageUpdate(event.data);
9012
- const agentSessionId = message.agentSessionId.trim();
9013
- if (agentSessionId) {
9253
+ const handleActivityStreamEvents = useCallback4(
9254
+ (events) => {
9255
+ const pendingMessagesBySessionId = /* @__PURE__ */ new Map();
9256
+ const flushPendingMessages = () => {
9257
+ for (const [agentSessionId, messages] of pendingMessagesBySessionId) {
9014
9258
  applyBackgroundTimelineStatusUpdate(
9015
9259
  agentSessionId,
9016
- projectAgentGUIMessagesToTimelineItems([message])
9260
+ projectAgentGUIMessagesToTimelineItems(messages)
9017
9261
  );
9018
9262
  }
9019
- return;
9020
- }
9021
- if (event.eventType === "state_patch") {
9022
- applyStatePatch(event.data);
9263
+ pendingMessagesBySessionId.clear();
9264
+ };
9265
+ for (const event of events) {
9266
+ if (event.eventType === "available_commands_update") {
9267
+ continue;
9268
+ }
9269
+ if (event.eventType === "message_update") {
9270
+ const message = messageFromMessageUpdate(event.data);
9271
+ const agentSessionId = message.agentSessionId.trim();
9272
+ if (!agentSessionId) {
9273
+ continue;
9274
+ }
9275
+ const messages = pendingMessagesBySessionId.get(agentSessionId);
9276
+ if (messages) {
9277
+ messages.push(message);
9278
+ } else {
9279
+ pendingMessagesBySessionId.set(agentSessionId, [message]);
9280
+ }
9281
+ continue;
9282
+ }
9283
+ flushPendingMessages();
9284
+ if (event.eventType === "state_patch") {
9285
+ applyStatePatch(event.data);
9286
+ }
9023
9287
  }
9288
+ flushPendingMessages();
9024
9289
  },
9025
9290
  [applyStatePatch, applyBackgroundTimelineStatusUpdate]
9026
9291
  );
9027
- const handleBackgroundActivityStreamEvent = useCallback4(
9028
- (event) => {
9029
- if (event.eventType === "message_update") {
9030
- handleActivityStreamEvent(event);
9031
- return;
9032
- }
9033
- if (event.eventType === "state_patch") {
9034
- applyStatePatch(event.data);
9035
- }
9292
+ const handleBackgroundActivityStreamEvents = useCallback4(
9293
+ (events) => {
9294
+ handleActivityStreamEvents(events);
9036
9295
  },
9037
- [applyStatePatch, handleActivityStreamEvent]
9296
+ [handleActivityStreamEvents]
9038
9297
  );
9039
9298
  useEffect4(() => {
9040
9299
  if (previewMode) {
@@ -9077,16 +9336,19 @@ function useAgentGUINodeController({
9077
9336
  return;
9078
9337
  }
9079
9338
  },
9080
- onEvent: (event) => {
9339
+ onEvents: (events) => {
9081
9340
  if (!activeConversationId) {
9082
9341
  return;
9083
9342
  }
9084
- handleActivityStreamEvent(event);
9085
- const eventSessionId = event.data.agentSessionId?.trim() || activeConversationId;
9086
- if (activeConversationIdRef.current !== activeConversationId || activeConversationIdRef.current !== eventSessionId) {
9087
- return;
9088
- }
9089
- if (event.eventType !== "message_update") {
9343
+ handleActivityStreamEvents(events);
9344
+ for (const event of events) {
9345
+ const eventSessionId = event.data.agentSessionId?.trim() || activeConversationId;
9346
+ if (activeConversationIdRef.current !== activeConversationId || activeConversationIdRef.current !== eventSessionId) {
9347
+ continue;
9348
+ }
9349
+ if (event.eventType === "message_update" || event.eventType === "available_commands_update") {
9350
+ continue;
9351
+ }
9090
9352
  scheduleActivityStreamStateReload(activeConversationId, {
9091
9353
  source: "activity-stream",
9092
9354
  eventType: event.eventType
@@ -9103,8 +9365,8 @@ function useAgentGUINodeController({
9103
9365
  workspaceId,
9104
9366
  agentSessionIds: backgroundWatchedConversationIds,
9105
9367
  enabled: backgroundWatchedConversationIds.length > 0,
9106
- onEvent: (event) => {
9107
- handleBackgroundActivityStreamEvent(event);
9368
+ onEvents: (events) => {
9369
+ handleBackgroundActivityStreamEvents(events);
9108
9370
  }
9109
9371
  });
9110
9372
  useEffect4(() => {
@@ -11308,21 +11570,13 @@ function useAgentGUINodeController({
11308
11570
  [providerComposerOptions]
11309
11571
  )
11310
11572
  );
11311
- const conversationDetail = useMemo4(
11312
- () => projectionConversation ? buildAgentGUIConversationDetail({
11313
- timelineItems: activeTimelineItems,
11314
- conversation: projectionConversation,
11315
- workspaceRoot: workspacePath
11316
- }) : null,
11317
- [activeTimelineItems, projectionConversation, workspacePath]
11318
- );
11319
- const conversation = useMemo4(
11320
- () => projectionConversation ? buildAgentGUIConversationVM({
11573
+ const conversationModels = useMemo4(
11574
+ () => projectionConversation ? buildAgentGUIConversationModels({
11321
11575
  timelineItems: activeTimelineItems,
11322
11576
  conversation: projectionConversation,
11323
11577
  workspaceRoot: workspacePath,
11324
11578
  avoidGroupingEdits
11325
- }) : null,
11579
+ }) : { conversation: null, detail: null },
11326
11580
  [
11327
11581
  activeTimelineItems,
11328
11582
  avoidGroupingEdits,
@@ -11330,6 +11584,22 @@ function useAgentGUINodeController({
11330
11584
  workspacePath
11331
11585
  ]
11332
11586
  );
11587
+ const conversationDetail = useStableConversationDetail(
11588
+ conversationModels.detail
11589
+ );
11590
+ const conversation = useMemo4(() => {
11591
+ if (!conversationModels.conversation) {
11592
+ return null;
11593
+ }
11594
+ if (conversationDetail && (conversationModels.conversation.sourceDetail !== conversationDetail || conversationModels.conversation.activity !== conversationDetail.activity)) {
11595
+ return {
11596
+ ...conversationModels.conversation,
11597
+ activity: conversationDetail.activity,
11598
+ sourceDetail: conversationDetail
11599
+ };
11600
+ }
11601
+ return conversationModels.conversation;
11602
+ }, [conversationDetail, conversationModels.conversation]);
11333
11603
  const activeLiveState = activeConversationLiveState;
11334
11604
  const activationError = activation.errorFor(activeConversationId);
11335
11605
  const activationErrorCode = activation.codeFor(activeConversationId);
@@ -11911,6 +12181,17 @@ function areAgentGUIUserProjectsEqual(left, right) {
11911
12181
  return candidate !== void 0 && project.id === candidate.id && project.path === candidate.path && project.label === candidate.label;
11912
12182
  });
11913
12183
  }
12184
+ function readAgentGUIUserProjectSnapshot(api) {
12185
+ const projects = api?.service?.getSnapshot?.().projects ?? [];
12186
+ return projects.map((project) => ({
12187
+ ...project.createdAtUnixMs === void 0 ? {} : { createdAtUnixMs: project.createdAtUnixMs },
12188
+ id: project.id,
12189
+ ...project.lastUsedAtUnixMs === void 0 || project.lastUsedAtUnixMs === null ? {} : { lastUsedAtUnixMs: project.lastUsedAtUnixMs },
12190
+ label: project.label,
12191
+ path: project.path,
12192
+ ...project.updatedAtUnixMs === void 0 ? {} : { updatedAtUnixMs: project.updatedAtUnixMs }
12193
+ }));
12194
+ }
11914
12195
  function normalizeInteractiveQuestions(value) {
11915
12196
  if (!Array.isArray(value)) {
11916
12197
  return [];
@@ -11984,7 +12265,7 @@ import { WorkspaceUserProjectSelect as WorkspaceUserProjectSelect2 } from "@tutt
11984
12265
  import { BareIconButton, ScrollArea } from "@tutti-os/ui-system/components";
11985
12266
  import {
11986
12267
  EditIcon,
11987
- FolderIcon,
12268
+ FolderIcon as FolderIcon2,
11988
12269
  MoreHorizontalIcon
11989
12270
  } from "@tutti-os/ui-system/icons";
11990
12271
 
@@ -14210,7 +14491,8 @@ import {
14210
14491
  } from "react";
14211
14492
  import { ChevronDown as ChevronDown2, ZapIcon } from "lucide-react";
14212
14493
  import {
14213
- WorkspaceUserProjectSelect
14494
+ WorkspaceUserProjectSelect,
14495
+ resolveWorkspaceUserProjectSelectLabels
14214
14496
  } from "@tutti-os/workspace-user-project/ui";
14215
14497
  import { prepareWorkspaceUserProjectSelection } from "@tutti-os/workspace-user-project/core";
14216
14498
  import {
@@ -14224,7 +14506,9 @@ import {
14224
14506
  DropdownMenuSubContent as DropdownMenuSubContent2,
14225
14507
  DropdownMenuSubTrigger as DropdownMenuSubTrigger2,
14226
14508
  DropdownMenuTrigger as DropdownMenuTrigger2,
14509
+ FolderIcon,
14227
14510
  NewWorkspaceLinedIcon,
14511
+ NoWorkspaceLinedIcon,
14228
14512
  RoomsHintIcon,
14229
14513
  Select,
14230
14514
  SelectContent,
@@ -14564,22 +14848,73 @@ function optionsWithSelectedValue(options, selectedValue) {
14564
14848
 
14565
14849
  // agent-gui/agentGuiNode/AgentComposerSettingsMenus.tsx
14566
14850
  import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
14851
+ function basenameProjectPath(path) {
14852
+ const normalized = path.trim().replaceAll("\\", "/").replace(/\/+$/, "");
14853
+ return normalized.split("/").filter(Boolean).at(-1) ?? path;
14854
+ }
14567
14855
  function AgentProjectDropdown({
14568
14856
  composerSettings,
14569
14857
  labels,
14570
14858
  i18n,
14859
+ previewMode = false,
14571
14860
  onProjectMissingChange,
14572
14861
  onProjectPathChange
14573
14862
  }) {
14574
14863
  "use memo";
14575
14864
  const agentHostApi = useAgentHostApi();
14865
+ const resolvedLabels = useMemo5(
14866
+ () => resolveWorkspaceUserProjectSelectLabels(i18n, labels),
14867
+ [i18n, labels]
14868
+ );
14576
14869
  const userProjectApi = useMemo5(
14577
- () => agentHostApi.userProjects ? {
14870
+ () => !previewMode && agentHostApi.userProjects ? {
14578
14871
  ...agentHostApi.userProjects,
14579
14872
  selectDirectory: agentHostApi.workspace.selectDirectory
14580
14873
  } : null,
14581
- [agentHostApi.userProjects, agentHostApi.workspace.selectDirectory]
14874
+ [
14875
+ agentHostApi.userProjects,
14876
+ agentHostApi.workspace.selectDirectory,
14877
+ previewMode
14878
+ ]
14582
14879
  );
14880
+ if (previewMode) {
14881
+ const selectedPath = composerSettings.selectedProjectPath?.trim() ?? "";
14882
+ const triggerLabel = selectedPath ? basenameProjectPath(selectedPath) : resolvedLabels.noProject;
14883
+ return /* @__PURE__ */ jsxs10(
14884
+ "button",
14885
+ {
14886
+ type: "button",
14887
+ "aria-label": composerSettings.projectLocked ? resolvedLabels.projectLocked : resolvedLabels.projectLabel,
14888
+ className: cn2(
14889
+ "w-auto max-w-full",
14890
+ AgentGUINode_styles_default.composerMenuTrigger,
14891
+ "text-[var(--agent-gui-text-tertiary)]"
14892
+ ),
14893
+ children: [
14894
+ /* @__PURE__ */ jsxs10(
14895
+ "span",
14896
+ {
14897
+ className: "workspace-user-project-trigger-label",
14898
+ "data-workspace-user-project-trigger-label": "true",
14899
+ children: [
14900
+ selectedPath ? /* @__PURE__ */ jsx21(FolderIcon, { "aria-hidden": true, className: "shrink-0", size: 15 }) : /* @__PURE__ */ jsx21(
14901
+ NoWorkspaceLinedIcon,
14902
+ {
14903
+ "aria-hidden": true,
14904
+ className: "shrink-0",
14905
+ "data-agent-project-trigger-no-workspace-icon": "true",
14906
+ size: 15
14907
+ }
14908
+ ),
14909
+ /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate", children: triggerLabel })
14910
+ ]
14911
+ }
14912
+ ),
14913
+ /* @__PURE__ */ jsx21(ChevronDown2, { "aria-hidden": "true", className: "shrink-0", size: 16 })
14914
+ ]
14915
+ }
14916
+ );
14917
+ }
14583
14918
  return /* @__PURE__ */ jsx21(
14584
14919
  WorkspaceUserProjectSelect,
14585
14920
  {
@@ -14619,6 +14954,7 @@ function AgentProjectDropdown({
14619
14954
  function AgentPermissionModeDropdown({
14620
14955
  composerSettings,
14621
14956
  disabled = false,
14957
+ previewMode = false,
14622
14958
  labels,
14623
14959
  onSettingsChange
14624
14960
  }) {
@@ -14650,6 +14986,27 @@ function AgentPermissionModeDropdown({
14650
14986
  }
14651
14987
  applyPermissionModeId(permissionModeId);
14652
14988
  };
14989
+ const trigger = /* @__PURE__ */ jsxs10(
14990
+ "button",
14991
+ {
14992
+ type: "button",
14993
+ className: cn2(
14994
+ "w-auto max-w-full",
14995
+ AgentGUINode_styles_default.composerMenuTrigger,
14996
+ selectDisabled && "cursor-not-allowed text-[var(--agent-gui-text-tertiary)] opacity-60 hover:text-[var(--agent-gui-text-tertiary)]",
14997
+ composerSettings.isSettingsLoading && "animate-pulse"
14998
+ ),
14999
+ "aria-label": labels.permissionLabel,
15000
+ "data-permission-tone": triggerTone,
15001
+ children: [
15002
+ /* @__PURE__ */ jsx21("span", { className: "flex min-w-0 flex-1 items-center", children: /* @__PURE__ */ jsx21("span", { className: "truncate", children: triggerLabel }) }),
15003
+ /* @__PURE__ */ jsx21(ChevronDown2, { "aria-hidden": "true", className: "shrink-0", size: 16 })
15004
+ ]
15005
+ }
15006
+ );
15007
+ if (previewMode) {
15008
+ return trigger;
15009
+ }
14653
15010
  return /* @__PURE__ */ jsxs10(
14654
15011
  Select,
14655
15012
  {
@@ -14693,7 +15050,13 @@ function AgentPermissionModeDropdown({
14693
15050
  onPointerDown: (event) => handleSelectedItemPointerDown(event, option.value),
14694
15051
  children: /* @__PURE__ */ jsxs10("span", { className: "flex min-w-0 items-center gap-1.5", children: [
14695
15052
  /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate", children: option.label }),
14696
- option.description ? /* @__PURE__ */ jsx21(ComposerOptionInfoTooltip, { description: option.description }) : null
15053
+ option.description ? /* @__PURE__ */ jsx21(
15054
+ ComposerOptionInfoTooltip,
15055
+ {
15056
+ description: option.description,
15057
+ tooltipsEnabled: !previewMode
15058
+ }
15059
+ ) : null
14697
15060
  ] })
14698
15061
  },
14699
15062
  option.value
@@ -14761,23 +15124,28 @@ function AgentProjectMissingStatusProbe({
14761
15124
  return null;
14762
15125
  }
14763
15126
  function ComposerOptionInfoTooltip({
14764
- description
15127
+ description,
15128
+ tooltipsEnabled = true
14765
15129
  }) {
14766
15130
  const stopSelect = (event) => {
14767
15131
  event.preventDefault();
14768
15132
  event.stopPropagation();
14769
15133
  };
15134
+ const trigger = /* @__PURE__ */ jsx21(
15135
+ "span",
15136
+ {
15137
+ className: "pointer-events-none inline-flex shrink-0 cursor-help text-[var(--agent-gui-text-tertiary)] opacity-0 transition-opacity group-hover/composer-option:pointer-events-auto group-hover/composer-option:opacity-100 group-data-[highlighted]/composer-option:pointer-events-auto group-data-[highlighted]/composer-option:opacity-100",
15138
+ "data-agent-composer-option-info-trigger": "true",
15139
+ onClick: stopSelect,
15140
+ onPointerDown: stopSelect,
15141
+ children: /* @__PURE__ */ jsx21(RoomsHintIcon, { "aria-hidden": true, className: "size-3" })
15142
+ }
15143
+ );
15144
+ if (!tooltipsEnabled) {
15145
+ return trigger;
15146
+ }
14770
15147
  return /* @__PURE__ */ jsxs10(Tooltip2, { children: [
14771
- /* @__PURE__ */ jsx21(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ jsx21(
14772
- "span",
14773
- {
14774
- className: "pointer-events-none inline-flex shrink-0 cursor-help text-[var(--agent-gui-text-tertiary)] opacity-0 transition-opacity group-hover/composer-option:pointer-events-auto group-hover/composer-option:opacity-100 group-data-[highlighted]/composer-option:pointer-events-auto group-data-[highlighted]/composer-option:opacity-100",
14775
- "data-agent-composer-option-info-trigger": "true",
14776
- onClick: stopSelect,
14777
- onPointerDown: stopSelect,
14778
- children: /* @__PURE__ */ jsx21(RoomsHintIcon, { "aria-hidden": true, className: "size-3" })
14779
- }
14780
- ) }),
15148
+ /* @__PURE__ */ jsx21(TooltipTrigger2, { asChild: true, children: trigger }),
14781
15149
  /* @__PURE__ */ jsx21(TooltipContent2, { side: "right", className: "max-w-[240px] whitespace-normal", children: description })
14782
15150
  ] });
14783
15151
  }
@@ -14806,6 +15174,7 @@ function normalizePermissionModeValue(value) {
14806
15174
  function AgentModelReasoningDropdown({
14807
15175
  composerSettings,
14808
15176
  disabled = false,
15177
+ previewMode = false,
14809
15178
  labels,
14810
15179
  onSettingsChange
14811
15180
  }) {
@@ -14817,39 +15186,43 @@ function AgentModelReasoningDropdown({
14817
15186
  onSettingsChange(patch);
14818
15187
  setMenuOpen(false);
14819
15188
  };
15189
+ const trigger = /* @__PURE__ */ jsxs10(
15190
+ "button",
15191
+ {
15192
+ type: "button",
15193
+ className: cn2(
15194
+ "w-auto",
15195
+ AgentGUINode_styles_default.composerMenuTrigger,
15196
+ menuDisabled && "cursor-not-allowed text-[var(--agent-gui-text-tertiary)] opacity-60 hover:text-[var(--agent-gui-text-tertiary)]",
15197
+ composerSettings.isSettingsLoading && "animate-pulse"
15198
+ ),
15199
+ "aria-label": `${labels.modelLabel} / ${labels.reasoningLabel}`,
15200
+ "data-agent-model-reasoning-trigger": "true",
15201
+ children: [
15202
+ /* @__PURE__ */ jsxs10("span", { className: "flex min-w-0 flex-1 items-center gap-2 overflow-hidden", children: [
15203
+ menu.speed.show && menu.trigger.isFast ? /* @__PURE__ */ jsx21(
15204
+ ZapIcon,
15205
+ {
15206
+ "aria-hidden": true,
15207
+ className: "size-3.5 shrink-0",
15208
+ "data-agent-speed-indicator": "fast",
15209
+ strokeWidth: 2.5
15210
+ }
15211
+ ) : null,
15212
+ menu.trigger.showCombined ? /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate", children: menu.trigger.combinedLabel }) : /* @__PURE__ */ jsxs10(Fragment4, { children: [
15213
+ /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate", children: menu.trigger.modelLabel }),
15214
+ /* @__PURE__ */ jsx21("span", { className: "shrink-0", children: menu.trigger.reasoningLabel })
15215
+ ] })
15216
+ ] }),
15217
+ /* @__PURE__ */ jsx21(ChevronDown2, { "aria-hidden": "true", className: "shrink-0", size: 16 })
15218
+ ]
15219
+ }
15220
+ );
15221
+ if (previewMode) {
15222
+ return trigger;
15223
+ }
14820
15224
  return /* @__PURE__ */ jsxs10(DropdownMenu2, { open: menuOpen, onOpenChange: setMenuOpen, children: [
14821
- /* @__PURE__ */ jsx21(DropdownMenuTrigger2, { asChild: true, disabled: menuDisabled, children: /* @__PURE__ */ jsxs10(
14822
- "button",
14823
- {
14824
- type: "button",
14825
- className: cn2(
14826
- "w-auto",
14827
- AgentGUINode_styles_default.composerMenuTrigger,
14828
- menuDisabled && "cursor-not-allowed text-[var(--agent-gui-text-tertiary)] opacity-60 hover:text-[var(--agent-gui-text-tertiary)]",
14829
- composerSettings.isSettingsLoading && "animate-pulse"
14830
- ),
14831
- "aria-label": `${labels.modelLabel} / ${labels.reasoningLabel}`,
14832
- "data-agent-model-reasoning-trigger": "true",
14833
- children: [
14834
- /* @__PURE__ */ jsxs10("span", { className: "flex min-w-0 flex-1 items-center gap-2 overflow-hidden", children: [
14835
- menu.speed.show && menu.trigger.isFast ? /* @__PURE__ */ jsx21(
14836
- ZapIcon,
14837
- {
14838
- "aria-hidden": true,
14839
- className: "size-3.5 shrink-0",
14840
- "data-agent-speed-indicator": "fast",
14841
- strokeWidth: 2.5
14842
- }
14843
- ) : null,
14844
- menu.trigger.showCombined ? /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate", children: menu.trigger.combinedLabel }) : /* @__PURE__ */ jsxs10(Fragment4, { children: [
14845
- /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate", children: menu.trigger.modelLabel }),
14846
- /* @__PURE__ */ jsx21("span", { className: "shrink-0", children: menu.trigger.reasoningLabel })
14847
- ] })
14848
- ] }),
14849
- /* @__PURE__ */ jsx21(ChevronDown2, { "aria-hidden": "true", className: "shrink-0", size: 16 })
14850
- ]
14851
- }
14852
- ) }),
15225
+ /* @__PURE__ */ jsx21(DropdownMenuTrigger2, { asChild: true, disabled: menuDisabled, children: trigger }),
14853
15226
  /* @__PURE__ */ jsxs10(
14854
15227
  DropdownMenuContent2,
14855
15228
  {
@@ -14871,6 +15244,7 @@ function AgentModelReasoningDropdown({
14871
15244
  options: menu.model.options,
14872
15245
  selectedValue: menu.model.selectedValue,
14873
15246
  descriptionPresentation: "model-tooltip",
15247
+ tooltipsEnabled: !previewMode,
14874
15248
  onSelect: (value) => applySettingsChange({ model: value })
14875
15249
  }
14876
15250
  )
@@ -14898,6 +15272,7 @@ function AgentModelReasoningDropdown({
14898
15272
  {
14899
15273
  options: menu.reasoning.options,
14900
15274
  selectedValue: menu.reasoning.selectedValue,
15275
+ tooltipsEnabled: !previewMode,
14901
15276
  onSelect: (value) => applySettingsChange({ reasoningEffort: value })
14902
15277
  }
14903
15278
  )
@@ -14927,6 +15302,7 @@ function AgentModelReasoningDropdown({
14927
15302
  options: menu.speed.options,
14928
15303
  selectedValue: menu.speed.selectedValue,
14929
15304
  descriptionPresentation: "inline",
15305
+ tooltipsEnabled: !previewMode,
14930
15306
  onSelect: (value) => applySettingsChange({ speed: value })
14931
15307
  }
14932
15308
  )
@@ -14942,6 +15318,7 @@ function ComposerMenuOptionItems({
14942
15318
  options,
14943
15319
  selectedValue,
14944
15320
  descriptionPresentation = "none",
15321
+ tooltipsEnabled = true,
14945
15322
  onSelect
14946
15323
  }) {
14947
15324
  return /* @__PURE__ */ jsx21(Fragment4, { children: options.map((option) => {
@@ -14992,7 +15369,8 @@ function ComposerMenuOptionItems({
14992
15369
  showTooltipDescription && option.description ? /* @__PURE__ */ jsx21(
14993
15370
  ComposerOptionInfoTooltip,
14994
15371
  {
14995
- description: option.description
15372
+ description: option.description,
15373
+ tooltipsEnabled
14996
15374
  }
14997
15375
  ) : null
14998
15376
  ] }),
@@ -15014,14 +15392,23 @@ function ComposerMenuOptionItems({
15014
15392
  },
15015
15393
  option.value
15016
15394
  );
15017
- return showModelTooltip ? /* @__PURE__ */ jsx21(ComposerModelOptionTooltip, { option, children: item }, option.value) : item;
15395
+ return showModelTooltip ? /* @__PURE__ */ jsx21(
15396
+ ComposerModelOptionTooltip,
15397
+ {
15398
+ option,
15399
+ tooltipsEnabled,
15400
+ children: item
15401
+ },
15402
+ option.value
15403
+ ) : item;
15018
15404
  }) });
15019
15405
  }
15020
15406
  function ComposerModelOptionTooltip({
15021
15407
  children,
15022
- option
15408
+ option,
15409
+ tooltipsEnabled = true
15023
15410
  }) {
15024
- if (!option.tooltip) {
15411
+ if (!tooltipsEnabled || !option.tooltip) {
15025
15412
  return children;
15026
15413
  }
15027
15414
  return /* @__PURE__ */ jsxs10(Tooltip2, { children: [
@@ -16505,7 +16892,8 @@ function AgentUsageChip({
16505
16892
  usedTokens,
16506
16893
  totalTokens,
16507
16894
  limits,
16508
- labels
16895
+ labels,
16896
+ tooltipsEnabled = true
16509
16897
  }) {
16510
16898
  "use memo";
16511
16899
  const clampedPercent = Math.max(0, Math.min(100, percentUsed));
@@ -16513,29 +16901,33 @@ function AgentUsageChip({
16513
16901
  const showTokens = usedTokens !== null && totalTokens !== null;
16514
16902
  const usageLevel = agentUsageChipLevel(clampedPercent);
16515
16903
  const ringColor = agentUsageRingColor(usageLevel);
16516
- return /* @__PURE__ */ jsxs13(Popover, { children: [
16517
- /* @__PURE__ */ jsx26(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs13(Tooltip, { children: [
16518
- /* @__PURE__ */ jsx26(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx26(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx26(
16519
- "button",
16904
+ const trigger = /* @__PURE__ */ jsx26(
16905
+ "button",
16906
+ {
16907
+ type: "button",
16908
+ "aria-label": chipLabel,
16909
+ className: "nodrag relative mr-2 inline-flex size-4 shrink-0 cursor-default items-center justify-center rounded-full p-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:color-mix(in_srgb,var(--text-primary)_34%,transparent)] [-webkit-app-region:no-drag]",
16910
+ "data-testid": "agent-gui-usage-chip",
16911
+ "data-usage-level": usageLevel,
16912
+ title: chipLabel,
16913
+ style: {
16914
+ background: `conic-gradient(${ringColor} ${clampedPercent}%, color-mix(in srgb, ${ringColor} 16%, transparent) 0)`
16915
+ },
16916
+ children: /* @__PURE__ */ jsx26(
16917
+ "span",
16520
16918
  {
16521
- type: "button",
16522
- "aria-label": chipLabel,
16523
- className: "nodrag relative mr-2 inline-flex size-4 shrink-0 cursor-default items-center justify-center rounded-full p-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:color-mix(in_srgb,var(--text-primary)_34%,transparent)] [-webkit-app-region:no-drag]",
16524
- "data-testid": "agent-gui-usage-chip",
16525
- "data-usage-level": usageLevel,
16526
- title: chipLabel,
16527
- style: {
16528
- background: `conic-gradient(${ringColor} ${clampedPercent}%, color-mix(in srgb, ${ringColor} 16%, transparent) 0)`
16529
- },
16530
- children: /* @__PURE__ */ jsx26(
16531
- "span",
16532
- {
16533
- "aria-hidden": "true",
16534
- className: "absolute inset-0.5 rounded-full bg-[var(--agent-gui-surface-raised,var(--background-fronted))]"
16535
- }
16536
- )
16919
+ "aria-hidden": "true",
16920
+ className: "absolute inset-0.5 rounded-full bg-[var(--agent-gui-surface-raised,var(--background-fronted))]"
16537
16921
  }
16538
- ) }) }),
16922
+ )
16923
+ }
16924
+ );
16925
+ if (!tooltipsEnabled) {
16926
+ return trigger;
16927
+ }
16928
+ return /* @__PURE__ */ jsxs13(Popover, { children: [
16929
+ /* @__PURE__ */ jsx26(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs13(Tooltip, { children: [
16930
+ /* @__PURE__ */ jsx26(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx26(TooltipTrigger, { asChild: true, children: trigger }) }),
16539
16931
  /* @__PURE__ */ jsx26(TooltipContent, { side: "top", children: labels.usageTooltipLabel })
16540
16932
  ] }) }),
16541
16933
  /* @__PURE__ */ jsx26(
@@ -16684,6 +17076,7 @@ function AgentComposer({
16684
17076
  isSendingTurn,
16685
17077
  isSubmittingPrompt,
16686
17078
  isActive = true,
17079
+ previewMode = false,
16687
17080
  promptImagesSupported = true,
16688
17081
  composerFocusRequestSequence = null,
16689
17082
  layoutMode = "dock",
@@ -17834,6 +18227,10 @@ function AgentComposer({
17834
18227
  "--agent-gui-prompt-tip-cycle-duration": `${promptTips.length * PROMPT_TIP_CYCLE_STEP_MS}ms`
17835
18228
  } : void 0;
17836
18229
  useLayoutEffect4(() => {
18230
+ if (previewMode) {
18231
+ setIsPromptTipOverflowing(false);
18232
+ return;
18233
+ }
17837
18234
  if (!activePromptTipId) {
17838
18235
  setIsPromptTipOverflowing(false);
17839
18236
  return;
@@ -17857,7 +18254,12 @@ function AgentComposer({
17857
18254
  resizeObserver?.disconnect();
17858
18255
  window.removeEventListener("resize", measure);
17859
18256
  };
17860
- }, [activePromptTipId, activePromptTipText, isPromptTipOverflowing]);
18257
+ }, [
18258
+ activePromptTipId,
18259
+ activePromptTipText,
18260
+ isPromptTipOverflowing,
18261
+ previewMode
18262
+ ]);
17861
18263
  const inputShellStyle = useMemo9(
17862
18264
  () => showFileMentionPalette || showFloatingCommandMenu ? { zIndex: composerPaletteZIndex } : void 0,
17863
18265
  [showFileMentionPalette, showFloatingCommandMenu]
@@ -17957,6 +18359,7 @@ function AgentComposer({
17957
18359
  embedded: true,
17958
18360
  edgeGlow: true,
17959
18361
  keyboardShortcuts: activePromptKeyboardShortcutsEnabled,
18362
+ previewMode,
17960
18363
  isSubmitting: isSubmittingPrompt,
17961
18364
  onSubmit: submitInteractivePromptAndDismiss,
17962
18365
  labels: {
@@ -18271,7 +18674,27 @@ function AgentComposer({
18271
18674
  ),
18272
18675
  /* @__PURE__ */ jsxs13("div", { className: AgentGUINode_styles_default.composerFooter, children: [
18273
18676
  /* @__PURE__ */ jsxs13("div", { className: composerStyles.footerGroup, children: [
18274
- /* @__PURE__ */ jsx26(
18677
+ previewMode ? /* @__PURE__ */ jsx26(
18678
+ "button",
18679
+ {
18680
+ type: "button",
18681
+ "aria-label": labels.referenceWorkspaceFiles,
18682
+ title: labels.referenceWorkspaceFiles,
18683
+ className: cn(
18684
+ AgentGUINode_styles_default.composerMenuTrigger,
18685
+ AgentGUINode_styles_default.composerReferenceTrigger,
18686
+ "w-auto justify-center px-1 text-[var(--agent-gui-text-secondary)] [&_svg]:shrink-0"
18687
+ ),
18688
+ children: /* @__PURE__ */ jsx26(
18689
+ AddIcon,
18690
+ {
18691
+ "aria-hidden": true,
18692
+ className: "size-3.5",
18693
+ "data-agent-reference-add-icon": "true"
18694
+ }
18695
+ )
18696
+ }
18697
+ ) : /* @__PURE__ */ jsx26(
18275
18698
  Select2,
18276
18699
  {
18277
18700
  open: false,
@@ -18339,6 +18762,7 @@ function AgentComposer({
18339
18762
  usedTokens: usage.usedTokens,
18340
18763
  totalTokens: usage.totalTokens,
18341
18764
  limits: slashStatus?.limits ?? [],
18765
+ tooltipsEnabled: !previewMode,
18342
18766
  labels: {
18343
18767
  usageChipLabel: labels.usageChipLabel,
18344
18768
  usageTooltipLabel: labels.usageTooltipLabel,
@@ -18353,6 +18777,7 @@ function AgentComposer({
18353
18777
  {
18354
18778
  composerSettings,
18355
18779
  disabled: settingsControlsDisabled,
18780
+ previewMode,
18356
18781
  labels: {
18357
18782
  permissionLabel: labels.permissionLabel
18358
18783
  },
@@ -18364,6 +18789,7 @@ function AgentComposer({
18364
18789
  {
18365
18790
  composerSettings,
18366
18791
  disabled: settingsControlsDisabled,
18792
+ previewMode,
18367
18793
  labels: {
18368
18794
  modelLabel: labels.modelLabel,
18369
18795
  modelSelectionLabel: labels.modelSelectionLabel,
@@ -18462,6 +18888,7 @@ function AgentComposer({
18462
18888
  {
18463
18889
  composerSettings,
18464
18890
  i18n: workspaceUserProjectI18n,
18891
+ previewMode,
18465
18892
  labels: {
18466
18893
  projectLocked: labels.projectLocked,
18467
18894
  projectMissingDescription: labels.projectMissingDescription
@@ -18475,7 +18902,7 @@ function AgentComposer({
18475
18902
  {
18476
18903
  className: AgentGUINode_styles_default.composerPromptTips,
18477
18904
  "data-testid": "agent-gui-prompt-tips",
18478
- children: isPromptTipOverflowing && promptTipNode ? /* @__PURE__ */ jsx26(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs13(Tooltip, { children: [
18905
+ children: !previewMode && isPromptTipOverflowing && promptTipNode ? /* @__PURE__ */ jsx26(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs13(Tooltip, { children: [
18479
18906
  /* @__PURE__ */ jsx26(TooltipTrigger, { asChild: true, children: promptTipNode }),
18480
18907
  /* @__PURE__ */ jsx26(
18481
18908
  TooltipContent,
@@ -18668,13 +19095,16 @@ function groupConversations(conversations, labels, userProjects = [], options =
18668
19095
  });
18669
19096
  }
18670
19097
  const projectGroups = /* @__PURE__ */ new Map();
19098
+ const normalizedProjectPathByPath = /* @__PURE__ */ new Map();
19099
+ const normalizeProjectPath = (path) => normalizeConversationProjectPathCached(path, normalizedProjectPathByPath);
18671
19100
  userProjects.forEach((project, projectOrder) => {
18672
- const normalizedPath = normalizeConversationProjectPath(project.path);
18673
- if (!normalizedPath || projectGroups.has(`project:${normalizedPath}`)) {
19101
+ const normalizedPath = normalizeProjectPath(project.path);
19102
+ const sectionId = `project:${normalizedPath}`;
19103
+ if (projectGroups.has(sectionId)) {
18674
19104
  return;
18675
19105
  }
18676
- projectGroups.set(`project:${normalizedPath}`, {
18677
- id: `project:${normalizedPath}`,
19106
+ projectGroups.set(sectionId, {
19107
+ id: sectionId,
18678
19108
  kind: "project",
18679
19109
  label: project.label,
18680
19110
  project,
@@ -18700,19 +19130,41 @@ function groupConversations(conversations, labels, userProjects = [], options =
18700
19130
  if ((conversation.pinnedAtUnixMs ?? 0) > 0) {
18701
19131
  continue;
18702
19132
  }
18703
- const section = resolveConversationProjectSection(conversation, labels);
18704
- const existing = projectGroups.get(section.id);
19133
+ if (!conversation.project) {
19134
+ const existing2 = projectGroups.get("conversations");
19135
+ if (existing2) {
19136
+ existing2.items.push(conversation);
19137
+ continue;
19138
+ }
19139
+ projectGroups.set("conversations", {
19140
+ id: "conversations",
19141
+ kind: "conversations",
19142
+ label: labels.sectionConversations,
19143
+ project: null,
19144
+ items: [conversation],
19145
+ projectOrder: Number.MAX_SAFE_INTEGER,
19146
+ sectionOrder: 1,
19147
+ projectUpdatedAtUnixMs: 0
19148
+ });
19149
+ continue;
19150
+ }
19151
+ const normalizedPath = normalizeProjectPath(conversation.project.path);
19152
+ const sectionId = `project:${normalizedPath}`;
19153
+ const existing = projectGroups.get(sectionId);
18705
19154
  if (existing) {
18706
19155
  existing.items.push(conversation);
18707
19156
  continue;
18708
19157
  }
18709
- projectGroups.set(section.id, {
18710
- ...section,
19158
+ projectGroups.set(sectionId, {
19159
+ id: sectionId,
19160
+ kind: "project",
19161
+ label: conversation.project.label,
19162
+ project: conversation.project,
18711
19163
  items: [conversation],
18712
- projectOrder: section.kind === "project" ? Number.MAX_SAFE_INTEGER - 1 : Number.MAX_SAFE_INTEGER,
18713
- sectionOrder: section.kind === "project" ? 0 : 1,
19164
+ projectOrder: Number.MAX_SAFE_INTEGER - 1,
19165
+ sectionOrder: 0,
18714
19166
  projectUpdatedAtUnixMs: resolveConversationProjectUpdatedAtUnixMs(
18715
- section.project
19167
+ conversation.project
18716
19168
  )
18717
19169
  });
18718
19170
  }
@@ -18736,27 +19188,18 @@ function resolveConversationProjectUpdatedAtUnixMs(project) {
18736
19188
  }
18737
19189
  return project.updatedAtUnixMs ?? project.lastUsedAtUnixMs ?? project.createdAtUnixMs ?? 0;
18738
19190
  }
18739
- function resolveConversationProjectSection(conversation, labels) {
18740
- if (conversation.project) {
18741
- return {
18742
- id: `project:${normalizeConversationProjectPath(
18743
- conversation.project.path
18744
- )}`,
18745
- kind: "project",
18746
- label: conversation.project.label,
18747
- project: conversation.project
18748
- };
18749
- }
18750
- return {
18751
- id: "conversations",
18752
- kind: "conversations",
18753
- label: labels.sectionConversations,
18754
- project: null
18755
- };
18756
- }
18757
19191
  function normalizeConversationProjectPath(path) {
18758
19192
  return path.trim().replaceAll("\\", "/").replace(/\/+$/, "") || "/";
18759
19193
  }
19194
+ function normalizeConversationProjectPathCached(path, normalizedPathByPath) {
19195
+ const cached = normalizedPathByPath.get(path);
19196
+ if (cached !== void 0) {
19197
+ return cached;
19198
+ }
19199
+ const normalized = normalizeConversationProjectPath(path);
19200
+ normalizedPathByPath.set(path, normalized);
19201
+ return normalized;
19202
+ }
18760
19203
  function conversationMetaKind(conversation) {
18761
19204
  if (conversation.status === "working") {
18762
19205
  return "loading";
@@ -19356,8 +19799,6 @@ function AgentGUINodeView({
19356
19799
  };
19357
19800
  const conversationRailStoreState = useMemo10(
19358
19801
  () => ({
19359
- conversations: viewModel.conversations,
19360
- userProjects: viewModel.userProjects,
19361
19802
  activeConversationId: viewModel.activeConversationId,
19362
19803
  pendingDeleteConversationId: viewModel.pendingDeleteConversation?.id ?? null,
19363
19804
  isLoadingConversations: viewModel.isLoadingConversations,
@@ -19367,6 +19808,7 @@ function AgentGUINodeView({
19367
19808
  workspaceUserProjectI18n,
19368
19809
  uiLanguage,
19369
19810
  showProjectSelector,
19811
+ previewMode,
19370
19812
  createConversationDisabled,
19371
19813
  openclawGateway,
19372
19814
  isCollapsed: conversationRailCollapsed,
@@ -19392,6 +19834,7 @@ function AgentGUINodeView({
19392
19834
  openConversationWindow,
19393
19835
  openProjectFiles,
19394
19836
  openclawGateway,
19837
+ previewMode,
19395
19838
  removeProject,
19396
19839
  requestCreateConversation,
19397
19840
  requestDeleteConversation,
@@ -19401,12 +19844,10 @@ function AgentGUINodeView({
19401
19844
  toggleConversationPinned,
19402
19845
  uiLanguage,
19403
19846
  viewModel.activeConversationId,
19404
- viewModel.conversations,
19405
19847
  viewModel.isDeletingConversation,
19406
19848
  viewModel.isDeletingProjectConversations,
19407
19849
  viewModel.isLoadingConversations,
19408
19850
  viewModel.pendingDeleteConversation?.id,
19409
- viewModel.userProjects,
19410
19851
  workspaceUserProjectI18n
19411
19852
  ]
19412
19853
  );
@@ -19423,7 +19864,7 @@ function AgentGUINodeView({
19423
19864
  conversationRailStore,
19424
19865
  conversationRailStoreState
19425
19866
  );
19426
- return /* @__PURE__ */ jsxs15(TooltipProvider2, { children: [
19867
+ const content = /* @__PURE__ */ jsxs15(Fragment8, { children: [
19427
19868
  /* @__PURE__ */ jsxs15(
19428
19869
  "div",
19429
19870
  {
@@ -19444,8 +19885,10 @@ function AgentGUINodeView({
19444
19885
  children: /* @__PURE__ */ jsx29(
19445
19886
  AgentGUIConversationRailStorePane,
19446
19887
  {
19888
+ conversations: viewModel.conversations,
19447
19889
  store: conversationRailStore,
19448
- storeState: conversationRailStoreState
19890
+ storeState: conversationRailStoreState,
19891
+ userProjects: viewModel.userProjects
19449
19892
  }
19450
19893
  )
19451
19894
  }
@@ -19496,7 +19939,8 @@ function AgentGUINodeView({
19496
19939
  onRequestGitBranches,
19497
19940
  contextMentionProviders,
19498
19941
  workspaceAppIcons: effectiveWorkspaceAppIcons,
19499
- workspaceUserProjectI18n
19942
+ workspaceUserProjectI18n,
19943
+ previewMode
19500
19944
  }
19501
19945
  ) })
19502
19946
  ]
@@ -19528,6 +19972,7 @@ function AgentGUINodeView({
19528
19972
  }
19529
19973
  )
19530
19974
  ] });
19975
+ return previewMode ? content : /* @__PURE__ */ jsx29(TooltipProvider2, { children: content });
19531
19976
  }
19532
19977
  function mergeWorkspaceAppIconsFromCommands(input) {
19533
19978
  const seen = new Set(
@@ -19595,6 +20040,7 @@ var AgentGUIDetailPane = memo(function AgentGUIDetailPane2({
19595
20040
  uiLanguage,
19596
20041
  hideDetailHeader,
19597
20042
  isActive,
20043
+ previewMode,
19598
20044
  composerFocusRequestSequence,
19599
20045
  isAgentProviderReady,
19600
20046
  slashStatusLimits,
@@ -20073,6 +20519,7 @@ var AgentGUIDetailPane = memo(function AgentGUIDetailPane2({
20073
20519
  canQueueWhileBusy,
20074
20520
  placeholder: viewModel.hasSentUserMessage ? labels.followupPlaceholder : labels.initialPlaceholder,
20075
20521
  showStopButton,
20522
+ previewMode,
20076
20523
  // Plan decisions replace the composer via bottomDockReplacementPrompt;
20077
20524
  // approval / ask-user embed here (composerActivePrompt encodes that).
20078
20525
  activePrompt: composerActivePrompt,
@@ -20117,6 +20564,7 @@ var AgentGUIDetailPane = memo(function AgentGUIDetailPane2({
20117
20564
  labels.followupPlaceholder,
20118
20565
  labels.initialPlaceholder,
20119
20566
  labels.promptTips,
20567
+ previewMode,
20120
20568
  composerActivePrompt,
20121
20569
  editQueuedPrompt,
20122
20570
  onCapabilitySettingsRequest,
@@ -20156,6 +20604,14 @@ var AgentGUIDetailPane = memo(function AgentGUIDetailPane2({
20156
20604
  workspaceAppIcons
20157
20605
  ]
20158
20606
  );
20607
+ const emptyHeroComposerProps = useMemo10(
20608
+ () => ({
20609
+ ...bottomDockComposerProps,
20610
+ compactSupported: viewModel.compactSupported,
20611
+ layoutMode: "hero"
20612
+ }),
20613
+ [bottomDockComposerProps, viewModel.compactSupported]
20614
+ );
20159
20615
  const bottomDockStoreState = useMemo10(
20160
20616
  () => ({
20161
20617
  // The lifted prompt is rendered from props on the pane; the store still
@@ -20311,7 +20767,8 @@ var AgentGUIDetailPane = memo(function AgentGUIDetailPane2({
20311
20767
  showSyncIndicator,
20312
20768
  syncStatus,
20313
20769
  syncLabel,
20314
- showFailedSyncLabel
20770
+ showFailedSyncLabel,
20771
+ previewMode
20315
20772
  }
20316
20773
  ),
20317
20774
  showProviderSetupNotice ? /* @__PURE__ */ jsxs15(
@@ -20356,57 +20813,7 @@ var AgentGUIDetailPane = memo(function AgentGUIDetailPane2({
20356
20813
  onAuthLogin: authLogin,
20357
20814
  onContinueInNewConversation: continueInNewConversation,
20358
20815
  chromeLabels,
20359
- composerProps: {
20360
- workspaceId: viewModel.workspaceId,
20361
- workspacePath: viewModel.workspacePath,
20362
- currentUserId: viewModel.currentUserId,
20363
- provider: viewModel.data.provider,
20364
- slashStatus,
20365
- usage: viewModel.usage,
20366
- draftContent: viewModel.draftContent,
20367
- availableCommands: viewModel.availableCommands,
20368
- hasCompactableContext: viewModel.hasSentUserMessage,
20369
- compactSupported: viewModel.compactSupported,
20370
- availableSkills: viewModel.availableSkills,
20371
- disabled: composerDisabled,
20372
- disabledReason: composerDisabledReason,
20373
- submitDisabled,
20374
- composerSettings: viewModel.composerSettings,
20375
- queuedPrompts: viewModel.queuedPrompts,
20376
- drainingQueuedPromptId: viewModel.drainingQueuedPromptId,
20377
- workspaceAppIcons,
20378
- canQueueWhileBusy,
20379
- placeholder: viewModel.hasSentUserMessage ? labels.followupPlaceholder : labels.initialPlaceholder,
20380
- showStopButton,
20381
- activePrompt: composerActivePrompt,
20382
- activePromptKeyboardShortcutsEnabled: isActive,
20383
- composerFocusRequestSequence,
20384
- isActive,
20385
- promptImagesSupported: viewModel.promptImagesSupported,
20386
- promptTips: labels.promptTips,
20387
- showProjectSelector,
20388
- isInterrupting: viewModel.isInterrupting,
20389
- isSendingTurn: isComposerSending,
20390
- isSubmittingPrompt: viewModel.isRespondingApproval,
20391
- labels: composerLabels,
20392
- workspaceUserProjectI18n,
20393
- capabilityMenuState,
20394
- onDraftContentChange: updateDraftContent,
20395
- onProjectPathChange: updateSelectedProjectPath,
20396
- onSettingsChange: updateComposerSettings,
20397
- onSubmit: submitPrompt,
20398
- onPromptImagesUnsupported: showPromptImagesUnsupported,
20399
- onSendQueuedPromptNext: sendQueuedPromptNext,
20400
- onRemoveQueuedPrompt: removeQueuedPrompt,
20401
- onEditQueuedPrompt: editQueuedPrompt,
20402
- onInterruptCurrentTurn: handleInterruptCurrentTurn,
20403
- onSubmitInteractivePrompt: submitInteractivePrompt,
20404
- onCapabilitySettingsRequest,
20405
- onLinkAction: stableLinkAction,
20406
- onRequestWorkspaceReferences: stableRequestWorkspaceReferences,
20407
- onRequestGitBranches: stableRequestGitBranches,
20408
- contextMentionProviders
20409
- }
20816
+ composerProps: emptyHeroComposerProps
20410
20817
  }
20411
20818
  ) : /* @__PURE__ */ jsx29(
20412
20819
  AgentGUIConversationTimelinePane,
@@ -20419,6 +20826,7 @@ var AgentGUIDetailPane = memo(function AgentGUIDetailPane2({
20419
20826
  onAuthLogin: authLogin,
20420
20827
  availableSkills: viewModel.availableSkills,
20421
20828
  workspaceAppIcons,
20829
+ previewMode,
20422
20830
  labels: conversationFlowLabels
20423
20831
  }
20424
20832
  )
@@ -20459,7 +20867,8 @@ var AgentGUIDetailHeader = memo(function AgentGUIDetailHeader2({
20459
20867
  showSyncIndicator,
20460
20868
  syncStatus,
20461
20869
  syncLabel,
20462
- showFailedSyncLabel
20870
+ showFailedSyncLabel,
20871
+ previewMode
20463
20872
  }) {
20464
20873
  "use memo";
20465
20874
  if (hidden || !activeConversation) {
@@ -20470,7 +20879,7 @@ var AgentGUIDetailHeader = memo(function AgentGUIDetailHeader2({
20470
20879
  return /* @__PURE__ */ jsxs15("div", { className: AgentGUINode_styles_default.detailHeader, children: [
20471
20880
  /* @__PURE__ */ jsxs15("span", { className: AgentGUINode_styles_default.detailHeaderTitleGroup, children: [
20472
20881
  /* @__PURE__ */ jsx29("span", { className: AgentGUINode_styles_default.detailHeaderTitle, children: conversationPlainTitle(activeConversation, labels, uiLanguage) }),
20473
- runPath ? /* @__PURE__ */ jsx29(AgentRunPathInfo, { path: runPath }) : null
20882
+ runPath ? /* @__PURE__ */ jsx29(AgentRunPathInfo, { path: runPath, previewMode }) : null
20474
20883
  ] }),
20475
20884
  /* @__PURE__ */ jsxs15(
20476
20885
  "span",
@@ -20494,18 +20903,25 @@ var AgentGUIDetailHeader = memo(function AgentGUIDetailHeader2({
20494
20903
  )
20495
20904
  ] });
20496
20905
  });
20497
- function AgentRunPathInfo({ path }) {
20906
+ function AgentRunPathInfo({
20907
+ path,
20908
+ previewMode
20909
+ }) {
20498
20910
  "use memo";
20911
+ const trigger = /* @__PURE__ */ jsx29(
20912
+ "button",
20913
+ {
20914
+ type: "button",
20915
+ className: AgentGUINode_styles_default.detailHeaderPathInfo,
20916
+ "aria-label": path,
20917
+ children: /* @__PURE__ */ jsx29(Info, { size: 14, strokeWidth: 2, "aria-hidden": "true" })
20918
+ }
20919
+ );
20920
+ if (previewMode) {
20921
+ return trigger;
20922
+ }
20499
20923
  return /* @__PURE__ */ jsxs15(Tooltip3, { children: [
20500
- /* @__PURE__ */ jsx29(TooltipTrigger3, { asChild: true, children: /* @__PURE__ */ jsx29(
20501
- "button",
20502
- {
20503
- type: "button",
20504
- className: AgentGUINode_styles_default.detailHeaderPathInfo,
20505
- "aria-label": path,
20506
- children: /* @__PURE__ */ jsx29(Info, { size: 14, strokeWidth: 2, "aria-hidden": "true" })
20507
- }
20508
- ) }),
20924
+ /* @__PURE__ */ jsx29(TooltipTrigger3, { asChild: true, children: trigger }),
20509
20925
  /* @__PURE__ */ jsx29(
20510
20926
  TooltipContent3,
20511
20927
  {
@@ -20575,7 +20991,7 @@ var AgentGUIEmptyHeroPane = memo(function AgentGUIEmptyHeroPane2({
20575
20991
  labels: chromeLabels
20576
20992
  }
20577
20993
  ) : null,
20578
- /* @__PURE__ */ jsx29(AgentComposer, { ...composerProps, layoutMode: "hero" })
20994
+ /* @__PURE__ */ jsx29(AgentComposer, { ...composerProps })
20579
20995
  ] }) });
20580
20996
  });
20581
20997
  function EmptyHeroTitle({
@@ -20674,6 +21090,7 @@ var AgentGUIBottomDockPane = memo(function AgentGUIBottomDockPane2({
20674
21090
  isRespondingApproval,
20675
21091
  sessionChrome
20676
21092
  } = state;
21093
+ const previewMode = composerProps.previewMode === true;
20677
21094
  const goal = objectRecord(sessionChrome.rawState?.runtimeContext?.goal);
20678
21095
  const goalObjective = goal ? stringValue2(goal.objective) : "";
20679
21096
  const goalStatus = goal ? stringValue2(goal.status) : "";
@@ -20699,6 +21116,7 @@ var AgentGUIBottomDockPane = memo(function AgentGUIBottomDockPane2({
20699
21116
  embedded: true,
20700
21117
  edgeGlow: true,
20701
21118
  keyboardShortcuts: keyboardShortcutsEnabled,
21119
+ previewMode,
20702
21120
  isSubmitting: isRespondingApproval,
20703
21121
  onSubmit: onSubmitBottomDockInteractivePrompt,
20704
21122
  labels: promptLabels
@@ -20763,6 +21181,7 @@ var AgentGUIBottomDockPane = memo(function AgentGUIBottomDockPane2({
20763
21181
  embedded: true,
20764
21182
  edgeGlow: true,
20765
21183
  keyboardShortcuts: keyboardShortcutsEnabled,
21184
+ previewMode,
20766
21185
  isSubmitting: isRespondingApproval,
20767
21186
  onSubmit: onSubmitBottomDockInteractivePrompt,
20768
21187
  labels: promptLabels
@@ -20784,16 +21203,25 @@ function syncAgentGUIConversationRailStore(store, next) {
20784
21203
  Object.assign(store, next);
20785
21204
  }
20786
21205
  function agentGUIConversationRailStoreSnapshotsEqual(current, next) {
20787
- return current.conversations === next.conversations && current.userProjects === next.userProjects && current.activeConversationId === next.activeConversationId && current.pendingDeleteConversationId === next.pendingDeleteConversationId && current.isLoadingConversations === next.isLoadingConversations && current.isDeletingConversation === next.isDeletingConversation && current.isDeletingProjectConversations === next.isDeletingProjectConversations && current.labels === next.labels && current.workspaceUserProjectI18n === next.workspaceUserProjectI18n && current.uiLanguage === next.uiLanguage && current.showProjectSelector === next.showProjectSelector && current.createConversationDisabled === next.createConversationDisabled && current.openclawGateway === next.openclawGateway && current.isCollapsed === next.isCollapsed && current.onCreateConversation === next.onCreateConversation && current.onRetryOpenclawGateway === next.onRetryOpenclawGateway && current.onSelectConversation === next.onSelectConversation && current.onToggleConversationPinned === next.onToggleConversationPinned && current.onOpenProjectFiles === next.onOpenProjectFiles && current.onOpenConversationWindow === next.onOpenConversationWindow && current.onRemoveProject === next.onRemoveProject && current.onConfirmDeleteProjectConversations === next.onConfirmDeleteProjectConversations && current.onRequestDeleteConversation === next.onRequestDeleteConversation && current.onCancelDeleteConversation === next.onCancelDeleteConversation && current.onConfirmDeleteConversation === next.onConfirmDeleteConversation;
21206
+ return current.activeConversationId === next.activeConversationId && current.pendingDeleteConversationId === next.pendingDeleteConversationId && current.isLoadingConversations === next.isLoadingConversations && current.isDeletingConversation === next.isDeletingConversation && current.isDeletingProjectConversations === next.isDeletingProjectConversations && current.labels === next.labels && current.workspaceUserProjectI18n === next.workspaceUserProjectI18n && current.uiLanguage === next.uiLanguage && current.showProjectSelector === next.showProjectSelector && current.previewMode === next.previewMode && current.createConversationDisabled === next.createConversationDisabled && current.openclawGateway === next.openclawGateway && current.isCollapsed === next.isCollapsed && current.onCreateConversation === next.onCreateConversation && current.onRetryOpenclawGateway === next.onRetryOpenclawGateway && current.onSelectConversation === next.onSelectConversation && current.onToggleConversationPinned === next.onToggleConversationPinned && current.onOpenProjectFiles === next.onOpenProjectFiles && current.onOpenConversationWindow === next.onOpenConversationWindow && current.onRemoveProject === next.onRemoveProject && current.onConfirmDeleteProjectConversations === next.onConfirmDeleteProjectConversations && current.onRequestDeleteConversation === next.onRequestDeleteConversation && current.onCancelDeleteConversation === next.onCancelDeleteConversation && current.onConfirmDeleteConversation === next.onConfirmDeleteConversation;
20788
21207
  }
20789
21208
  var AgentGUIConversationRailStorePane = memo(
20790
21209
  function AgentGUIConversationRailStorePane2({
21210
+ conversations,
20791
21211
  store,
20792
- storeState: _storeState
21212
+ storeState: _storeState,
21213
+ userProjects
20793
21214
  }) {
20794
21215
  "use memo";
20795
21216
  const state = useSnapshot(store);
20796
- return /* @__PURE__ */ jsx29(AgentGUIConversationRailPane, { ...state });
21217
+ return /* @__PURE__ */ jsx29(
21218
+ AgentGUIConversationRailPane,
21219
+ {
21220
+ ...state,
21221
+ conversations,
21222
+ userProjects
21223
+ }
21224
+ );
20797
21225
  }
20798
21226
  );
20799
21227
  function normalizeConversationRailProjectPath(path) {
@@ -20803,6 +21231,75 @@ function normalizeConversationRailProjectPath(path) {
20803
21231
  }
20804
21232
  return normalized.replace(/\/+$/, "") || "/";
20805
21233
  }
21234
+ function stabilizeConversationSections(previous, next) {
21235
+ if (!previous) {
21236
+ return [...next];
21237
+ }
21238
+ const previousById = new Map(
21239
+ previous.map((section) => [section.id, section])
21240
+ );
21241
+ let changed = previous.length !== next.length;
21242
+ const stable = next.map((section, index) => {
21243
+ const previousSection = previousById.get(section.id) ?? null;
21244
+ if (!previousSection) {
21245
+ changed = true;
21246
+ return section;
21247
+ }
21248
+ const items = stabilizeConversationSectionItems(
21249
+ previousSection.items,
21250
+ section.items
21251
+ );
21252
+ const canReuseSection = previousSection.kind === section.kind && previousSection.label === section.label && conversationProjectsRenderEqual2(
21253
+ previousSection.project,
21254
+ section.project
21255
+ ) && items === previousSection.items;
21256
+ if (canReuseSection) {
21257
+ if (previous[index] !== previousSection) {
21258
+ changed = true;
21259
+ }
21260
+ return previousSection;
21261
+ }
21262
+ changed = true;
21263
+ return { ...section, items };
21264
+ });
21265
+ return changed ? stable : previous;
21266
+ }
21267
+ function stabilizeConversationSectionItems(previous, next) {
21268
+ if (previous.length !== next.length) {
21269
+ const previousById = /* @__PURE__ */ new Map();
21270
+ for (const item of previous) {
21271
+ if (!previousById.has(item.id)) {
21272
+ previousById.set(item.id, item);
21273
+ }
21274
+ }
21275
+ return next.map((item) => {
21276
+ const previousItem = previousById.get(item.id);
21277
+ return previousItem && conversationSummariesRenderEqual2(previousItem, item) ? previousItem : item;
21278
+ });
21279
+ }
21280
+ let changed = false;
21281
+ const stable = next.map((item, index) => {
21282
+ const previousItem = previous[index];
21283
+ if (previousItem && conversationSummariesRenderEqual2(previousItem, item)) {
21284
+ if (previousItem !== item) {
21285
+ changed = true;
21286
+ }
21287
+ return previousItem;
21288
+ }
21289
+ changed = true;
21290
+ return item;
21291
+ });
21292
+ return changed ? stable : previous;
21293
+ }
21294
+ function conversationSummariesRenderEqual2(left, right) {
21295
+ return left.id === right.id && left.provider === right.provider && left.title === right.title && left.titleFallback === right.titleFallback && left.status === right.status && left.cwd === right.cwd && left.pinnedAtUnixMs === right.pinnedAtUnixMs && left.sortTimeUnixMs === right.sortTimeUnixMs && left.updatedAtUnixMs === right.updatedAtUnixMs && left.hasUnreadCompletion === right.hasUnreadCompletion && conversationProjectsRenderEqual2(left.project, right.project) && conversationSyncStatesRenderEqual(left.syncState, right.syncState);
21296
+ }
21297
+ function conversationSyncStatesRenderEqual(left, right) {
21298
+ return left === right || (!left || !right ? (left ?? null) === (right ?? null) : left.workspaceId === right.workspaceId && left.agentSessionId === right.agentSessionId && left.status === right.status && left.pendingTimelineItemCount === right.pendingTimelineItemCount && left.pendingStatePatchCount === right.pendingStatePatchCount && left.attemptCount === right.attemptCount && left.failedReportCount === right.failedReportCount && left.lastError === right.lastError && left.lastAttemptAtUnixMs === right.lastAttemptAtUnixMs && left.lastSyncedAtUnixMs === right.lastSyncedAtUnixMs && left.updatedAtUnixMs === right.updatedAtUnixMs);
21299
+ }
21300
+ function conversationProjectsRenderEqual2(left, right) {
21301
+ return left === right || (!left || !right ? !left && !right : left.id === right.id && left.path === right.path && left.label === right.label && left.createdAtUnixMs === right.createdAtUnixMs && left.updatedAtUnixMs === right.updatedAtUnixMs && left.lastUsedAtUnixMs === right.lastUsedAtUnixMs);
21302
+ }
20806
21303
  var AgentGUIConversationRailPane = memo(
20807
21304
  function AgentGUIConversationRailPane2({
20808
21305
  conversations,
@@ -20816,6 +21313,7 @@ var AgentGUIConversationRailPane = memo(
20816
21313
  workspaceUserProjectI18n,
20817
21314
  uiLanguage,
20818
21315
  showProjectSelector,
21316
+ previewMode,
20819
21317
  createConversationDisabled,
20820
21318
  openclawGateway,
20821
21319
  isCollapsed,
@@ -20841,6 +21339,7 @@ var AgentGUIConversationRailPane = memo(
20841
21339
  const conversationItemElementsRef = useRef13(
20842
21340
  /* @__PURE__ */ new Map()
20843
21341
  );
21342
+ const groupedConversationsRef = useRef13(null);
20844
21343
  useEffect12(() => {
20845
21344
  const timer = window.setInterval(() => {
20846
21345
  setCurrentTimeMs(Date.now());
@@ -20863,13 +21362,19 @@ var AgentGUIConversationRailPane = memo(
20863
21362
  const filteredConversations = filteredConversationResult.items;
20864
21363
  const groupedConversationResult = useMemo10(() => {
20865
21364
  const startedAtMs = agentGuiPerfNowMs();
21365
+ const rawGroups = groupConversations(
21366
+ filteredConversations,
21367
+ labels,
21368
+ conversationQuery.trim() ? [] : userProjects,
21369
+ { includeEmptyConversations: !conversationQuery.trim() }
21370
+ );
21371
+ const groups = stabilizeConversationSections(
21372
+ groupedConversationsRef.current,
21373
+ rawGroups
21374
+ );
21375
+ groupedConversationsRef.current = groups;
20866
21376
  return {
20867
- groups: groupConversations(
20868
- filteredConversations,
20869
- labels,
20870
- conversationQuery.trim() ? [] : userProjects,
20871
- { includeEmptyConversations: !conversationQuery.trim() }
20872
- ),
21377
+ groups,
20873
21378
  groupMs: roundAgentGuiPerfMs(agentGuiPerfNowMs() - startedAtMs)
20874
21379
  };
20875
21380
  }, [conversationQuery, filteredConversations, labels, userProjects]);
@@ -21013,6 +21518,7 @@ var AgentGUIConversationRailPane = memo(
21013
21518
  isSectionCollapsed,
21014
21519
  labels,
21015
21520
  pendingDeleteConversationId,
21521
+ previewMode,
21016
21522
  projectConversationCount,
21017
21523
  projectLabel,
21018
21524
  projectPath,
@@ -21086,6 +21592,7 @@ var AgentGUIConversationRailSection = memo(
21086
21592
  isSectionCollapsed,
21087
21593
  activeConversationId,
21088
21594
  pendingDeleteConversationId,
21595
+ previewMode,
21089
21596
  isDeletingConversation,
21090
21597
  createConversationDisabled,
21091
21598
  currentTimeMs,
@@ -21108,10 +21615,10 @@ var AgentGUIConversationRailSection = memo(
21108
21615
  const [visibleItemLimit, setVisibleItemLimit] = useState11(
21109
21616
  AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE
21110
21617
  );
21111
- const visibleItemCount = Math.min(visibleItemLimit, section.items.length);
21112
- const visibleItems = section.items.slice(0, visibleItemCount);
21113
- const canShowMore = visibleItemCount < section.items.length;
21114
- const canShowLess = visibleItemCount > AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE;
21618
+ const visibleItemCount = isSectionCollapsed ? 0 : Math.min(visibleItemLimit, section.items.length);
21619
+ const visibleItems = isSectionCollapsed ? [] : section.items.slice(0, visibleItemCount);
21620
+ const canShowMore = !isSectionCollapsed && visibleItemCount < section.items.length;
21621
+ const canShowLess = !isSectionCollapsed && visibleItemCount > AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE;
21115
21622
  const showMoreConversations = useCallback10(() => {
21116
21623
  setVisibleItemLimit(
21117
21624
  (current) => Math.min(
@@ -21148,7 +21655,7 @@ var AgentGUIConversationRailSection = memo(
21148
21655
  ),
21149
21656
  /* @__PURE__ */ jsxs15("span", { className: AgentGUINode_styles_default.conversationSectionLabel, children: [
21150
21657
  /* @__PURE__ */ jsx29(
21151
- FolderIcon,
21658
+ FolderIcon2,
21152
21659
  {
21153
21660
  "aria-hidden": "true",
21154
21661
  className: AgentGUINode_styles_default.conversationSectionLabelIcon
@@ -21269,7 +21776,7 @@ var AgentGUIConversationRailSection = memo(
21269
21776
  className: AgentGUINode_styles_default.conversationSectionItems,
21270
21777
  "aria-hidden": isSectionCollapsed ? "true" : void 0,
21271
21778
  children: /* @__PURE__ */ jsxs15("div", { className: AgentGUINode_styles_default.conversationSectionItemsInner, children: [
21272
- section.items.length === 0 ? /* @__PURE__ */ jsx29("div", { className: AgentGUINode_styles_default.conversationSectionEmpty, children: labels.emptyProjectConversations }) : null,
21779
+ !isSectionCollapsed && section.items.length === 0 ? /* @__PURE__ */ jsx29("div", { className: AgentGUINode_styles_default.conversationSectionEmpty, children: labels.emptyProjectConversations }) : null,
21273
21780
  visibleItems.map((item) => /* @__PURE__ */ jsx29(
21274
21781
  AgentGUIConversationRailItem,
21275
21782
  {
@@ -21279,6 +21786,7 @@ var AgentGUIConversationRailSection = memo(
21279
21786
  isPendingDeleteConversation: pendingDeleteConversationId === item.id,
21280
21787
  item,
21281
21788
  labels,
21789
+ previewMode,
21282
21790
  registerItemElement,
21283
21791
  uiLanguage,
21284
21792
  onCancelDeleteConversation,
@@ -21326,6 +21834,7 @@ var AgentGUIConversationRailItem = memo(
21326
21834
  isDeletingConversation,
21327
21835
  currentTimeMs,
21328
21836
  labels,
21837
+ previewMode,
21329
21838
  uiLanguage,
21330
21839
  registerItemElement,
21331
21840
  onSelectConversation,
@@ -21383,7 +21892,7 @@ var AgentGUIConversationRailItem = memo(
21383
21892
  ]
21384
21893
  }
21385
21894
  ),
21386
- /* @__PURE__ */ jsx29("div", { className: AgentGUINode_styles_default.conversationActions, children: isPendingDeleteConversation ? /* @__PURE__ */ jsx29(
21895
+ previewMode ? null : /* @__PURE__ */ jsx29("div", { className: AgentGUINode_styles_default.conversationActions, children: isPendingDeleteConversation ? /* @__PURE__ */ jsx29(
21387
21896
  "button",
21388
21897
  {
21389
21898
  type: "button",
@@ -21548,6 +22057,7 @@ var AgentGUIConversationTimelinePane = memo(
21548
22057
  onAuthLogin,
21549
22058
  availableSkills,
21550
22059
  workspaceAppIcons = EMPTY_WORKSPACE_APP_ICONS3,
22060
+ previewMode = false,
21551
22061
  labels
21552
22062
  }) {
21553
22063
  "use memo";
@@ -21562,6 +22072,7 @@ var AgentGUIConversationTimelinePane = memo(
21562
22072
  onAuthLogin,
21563
22073
  availableSkills,
21564
22074
  workspaceAppIcons,
22075
+ previewMode,
21565
22076
  labels
21566
22077
  }
21567
22078
  );
@@ -23061,14 +23572,15 @@ var AgentGUI = memo3(function AgentGUI2({
23061
23572
  locale,
23062
23573
  ...props
23063
23574
  }) {
23064
- return /* @__PURE__ */ jsx32(TooltipProvider3, { delayDuration: 120, skipDelayDuration: 0, children: /* @__PURE__ */ jsx32(AgentGuiI18nProvider, { runtime: i18n, locale, children: /* @__PURE__ */ jsx32(
23575
+ const content = /* @__PURE__ */ jsx32(AgentGuiI18nProvider, { runtime: i18n, locale, children: /* @__PURE__ */ jsx32(
23065
23576
  AgentActivityHostProvider,
23066
23577
  {
23067
23578
  agentActivityRuntime,
23068
23579
  agentHostApi,
23069
23580
  children: /* @__PURE__ */ jsx32(AgentGUINode, { ...props })
23070
23581
  }
23071
- ) }) });
23582
+ ) });
23583
+ return props.previewMode ? content : /* @__PURE__ */ jsx32(TooltipProvider3, { delayDuration: 120, skipDelayDuration: 0, children: content });
23072
23584
  });
23073
23585
 
23074
23586
  // index.ts