@tutti-os/agent-gui 0.0.49 → 0.0.51

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.
Files changed (58) hide show
  1. package/dist/agent-conversation/index.d.ts +5 -3
  2. package/dist/agent-conversation/index.js +6 -6
  3. package/dist/agent-message-center/index.d.ts +185 -4
  4. package/dist/agent-message-center/index.js +126 -60
  5. package/dist/agent-message-center/index.js.map +1 -1
  6. package/dist/{agentConversationVM-DSXrFL9v.d.ts → agentConversationVM-Qbz9GBwR.d.ts} +25 -0
  7. package/dist/{agentGuiNodeTypes-Bp1G8pOj.d.ts → agentGuiNodeTypes-wzOITHRW.d.ts} +1 -1
  8. package/dist/app/renderer/agentactivity.css +426 -4
  9. package/dist/{chunk-XRJZCEOX.js → chunk-23YM25SG.js} +1764 -594
  10. package/dist/chunk-23YM25SG.js.map +1 -0
  11. package/dist/{chunk-AKK7UOAS.js → chunk-5Y3PC7HP.js} +9 -4
  12. package/dist/chunk-5Y3PC7HP.js.map +1 -0
  13. package/dist/{chunk-U6JWW45G.js → chunk-66EQ6EQO.js} +1 -1
  14. package/dist/chunk-66EQ6EQO.js.map +1 -0
  15. package/dist/{chunk-Q3MOU4CD.js → chunk-ARCM7YB2.js} +2 -2
  16. package/dist/{chunk-5HJWT6YN.js → chunk-BQVYICR7.js} +5 -5
  17. package/dist/{chunk-TTDBLIQ3.js → chunk-DPG2J7N5.js} +2 -2
  18. package/dist/{chunk-FSRS2JFR.js → chunk-FYVVHRLZ.js} +2 -2
  19. package/dist/{chunk-AYEYXKLF.js → chunk-HDBKB5RA.js} +2 -2
  20. package/dist/{chunk-A2EN24OI.js → chunk-M7GNA2WD.js} +5 -5
  21. package/dist/{chunk-QGBIGRZA.js → chunk-OBFDA7RG.js} +14 -2
  22. package/dist/chunk-OBFDA7RG.js.map +1 -0
  23. package/dist/{chunk-RJR2OZ6T.js → chunk-RKZMETSQ.js} +189 -187
  24. package/dist/chunk-RKZMETSQ.js.map +1 -0
  25. package/dist/{chunk-6KQHNUR5.js → chunk-UUY5VEK4.js} +2 -2
  26. package/dist/{chunk-77UR4G7P.js → chunk-Y7ZVTWMZ.js} +2 -2
  27. package/dist/{chunk-K6SRLYC3.js → chunk-ZTSS2NU2.js} +17 -1
  28. package/dist/chunk-ZTSS2NU2.js.map +1 -0
  29. package/dist/context-mention-palette/index.js +7 -7
  30. package/dist/i18n/index.d.ts +16 -0
  31. package/dist/i18n/index.js +2 -2
  32. package/dist/index.d.ts +50 -3
  33. package/dist/index.js +519 -29
  34. package/dist/index.js.map +1 -1
  35. package/dist/plan-decision-ops.d.ts +1 -1
  36. package/dist/queued-prompt-runtime.d.ts +2 -2
  37. package/dist/workbench/contribution.d.ts +5 -1
  38. package/dist/workbench/contribution.js +4 -2
  39. package/dist/workbench/index.js +5 -5
  40. package/dist/workbench/launch.d.ts +4 -0
  41. package/dist/workbench/launch.js +1 -1
  42. package/dist/workbench/sessionTitle.js +3 -3
  43. package/dist/workspace-agent-generated-files.js +3 -3
  44. package/package.json +14 -14
  45. package/dist/chunk-AKK7UOAS.js.map +0 -1
  46. package/dist/chunk-K6SRLYC3.js.map +0 -1
  47. package/dist/chunk-QGBIGRZA.js.map +0 -1
  48. package/dist/chunk-RJR2OZ6T.js.map +0 -1
  49. package/dist/chunk-U6JWW45G.js.map +0 -1
  50. package/dist/chunk-XRJZCEOX.js.map +0 -1
  51. /package/dist/{chunk-Q3MOU4CD.js.map → chunk-ARCM7YB2.js.map} +0 -0
  52. /package/dist/{chunk-5HJWT6YN.js.map → chunk-BQVYICR7.js.map} +0 -0
  53. /package/dist/{chunk-TTDBLIQ3.js.map → chunk-DPG2J7N5.js.map} +0 -0
  54. /package/dist/{chunk-FSRS2JFR.js.map → chunk-FYVVHRLZ.js.map} +0 -0
  55. /package/dist/{chunk-AYEYXKLF.js.map → chunk-HDBKB5RA.js.map} +0 -0
  56. /package/dist/{chunk-A2EN24OI.js.map → chunk-M7GNA2WD.js.map} +0 -0
  57. /package/dist/{chunk-6KQHNUR5.js.map → chunk-UUY5VEK4.js.map} +0 -0
  58. /package/dist/{chunk-77UR4G7P.js.map → chunk-Y7ZVTWMZ.js.map} +0 -0
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  import {
23
23
  AgentInteractivePromptSurface,
24
24
  approvalOptionDisplayLabel
25
- } from "./chunk-A2EN24OI.js";
25
+ } from "./chunk-M7GNA2WD.js";
26
26
  import {
27
27
  PLAN_IMPLEMENTATION_ACTION_FEEDBACK,
28
28
  PLAN_IMPLEMENTATION_ACTION_IMPLEMENT,
@@ -41,17 +41,20 @@ import {
41
41
  resolveAgentGUIExplicitConversationTitle,
42
42
  resolveAgentGUIProviderDisplayLabel,
43
43
  resolveAgentGUIProviderIdentity
44
- } from "./chunk-TTDBLIQ3.js";
44
+ } from "./chunk-DPG2J7N5.js";
45
45
  import {
46
46
  AgentConversationFlow,
47
47
  Button,
48
48
  agentRichTextContentToPromptText,
49
+ attachSubAgentLanesToConversationVM,
50
+ buildSubAgentLanesByCallId,
49
51
  buildWorkspaceAgentSessionDetailViewModel,
50
52
  createAgentRichTextInputExtensions,
51
53
  editorToPromptText,
52
54
  getAppErrorCode,
53
55
  labelForProviderSkill,
54
56
  openAgentEnvPanel,
57
+ partitionSubAgentTimelineItems,
55
58
  plainTextToAgentRichTextDoc,
56
59
  plainTextToAgentRichTextInlineContent,
57
60
  projectAgentConversationVM,
@@ -60,13 +63,13 @@ import {
60
63
  skillTriggerForPrefix,
61
64
  toLocalShortDateTime,
62
65
  useProjectedAgentConversation
63
- } from "./chunk-XRJZCEOX.js";
66
+ } from "./chunk-23YM25SG.js";
64
67
  import {
65
68
  AgentMessageMarkdown,
66
69
  ZoomableImage,
67
70
  cn,
68
71
  resolveWorkspaceLinkAction
69
- } from "./chunk-RJR2OZ6T.js";
72
+ } from "./chunk-RKZMETSQ.js";
70
73
  import {
71
74
  AGENT_MENTION_FILTER_TAB_ORDER,
72
75
  AgentFileMentionPalette,
@@ -74,7 +77,7 @@ import {
74
77
  DEFAULT_AGENT_MENTION_FILTER,
75
78
  agentMentionItemKey,
76
79
  preloadAgentMentionBrowse
77
- } from "./chunk-5HJWT6YN.js";
80
+ } from "./chunk-BQVYICR7.js";
78
81
  import {
79
82
  WORKSPACE_AGENT_ACTIVITY_RUNTIME_SESSION_ORIGIN,
80
83
  buildWorkspaceAgentActivityListViewModel,
@@ -84,13 +87,13 @@ import {
84
87
  isWorkspaceAgentUntitledTask,
85
88
  mergeWorkspaceAgentActivityDurableAndOverlayMessages,
86
89
  selectWorkspaceAgentActivityOverlayMessages
87
- } from "./chunk-Q3MOU4CD.js";
90
+ } from "./chunk-ARCM7YB2.js";
88
91
  import {
89
92
  MANAGED_AGENT_ICON_FALLBACK_URL,
90
93
  MANAGED_AGENT_ICON_URLS,
91
94
  Spinner,
92
95
  normalizeManagedAgentProvider
93
- } from "./chunk-AYEYXKLF.js";
96
+ } from "./chunk-HDBKB5RA.js";
94
97
  import {
95
98
  resolveWorkspaceAgentSessionSortTimeUnixMs
96
99
  } from "./chunk-IBIMGLCD.js";
@@ -102,7 +105,7 @@ import {
102
105
  mentionItemToAttrs,
103
106
  normalizeAgentSessionMentionTitle,
104
107
  parseMentionItemFromHref
105
- } from "./chunk-6KQHNUR5.js";
108
+ } from "./chunk-UUY5VEK4.js";
106
109
  import "./chunk-Y35GDLP2.js";
107
110
  import "./chunk-LUGELG5V.js";
108
111
  import {
@@ -118,7 +121,7 @@ import {
118
121
  useAgentHostApi,
119
122
  useOptionalAgentActivityRuntime,
120
123
  useOptionalAgentHostApi
121
- } from "./chunk-U6JWW45G.js";
124
+ } from "./chunk-66EQ6EQO.js";
122
125
  import "./chunk-TYGL25EL.js";
123
126
  import "./chunk-PJP5BUU6.js";
124
127
  import {
@@ -134,8 +137,8 @@ import {
134
137
  agentGuiI18nResources,
135
138
  translate,
136
139
  useTranslation
137
- } from "./chunk-77UR4G7P.js";
138
- import "./chunk-K6SRLYC3.js";
140
+ } from "./chunk-Y7ZVTWMZ.js";
141
+ import "./chunk-ZTSS2NU2.js";
139
142
 
140
143
  // shared/agentActivitySnapshotProjection.ts
141
144
  import {
@@ -2549,8 +2552,14 @@ function buildAgentGUIConversationModels({
2549
2552
  if (!detail) {
2550
2553
  return { conversation: null, detail: null };
2551
2554
  }
2555
+ const subAgentLanesByCallId = buildSubAgentLanesByCallId(
2556
+ partitionSubAgentTimelineItems(timelineItems)
2557
+ );
2552
2558
  return {
2553
- conversation: projectAgentConversationVM(detail, { avoidGroupingEdits }),
2559
+ conversation: attachSubAgentLanesToConversationVM(
2560
+ projectAgentConversationVM(detail, { avoidGroupingEdits }),
2561
+ subAgentLanesByCallId
2562
+ ),
2554
2563
  detail
2555
2564
  };
2556
2565
  }
@@ -22249,7 +22258,7 @@ function groupConversations(conversations, labels, userProjects = [], options =
22249
22258
  }
22250
22259
  groups.push(
22251
22260
  ...[...projectGroups.values()].sort(
22252
- (left, right) => left.sectionOrder - right.sectionOrder || right.projectUpdatedAtUnixMs - left.projectUpdatedAtUnixMs || left.projectOrder - right.projectOrder || left.label.localeCompare(right.label) || left.id.localeCompare(right.id)
22261
+ (left, right) => left.sectionOrder - right.sectionOrder || Number(right.items.length > 0) - Number(left.items.length > 0) || right.projectUpdatedAtUnixMs - left.projectUpdatedAtUnixMs || left.projectOrder - right.projectOrder || left.label.localeCompare(right.label) || left.id.localeCompare(right.id)
22253
22262
  ).map(
22254
22263
  ({
22255
22264
  projectOrder: _projectOrder,
@@ -23005,9 +23014,11 @@ function AgentGUINodeView({
23005
23014
  AgentGUIConversationRailStorePane,
23006
23015
  {
23007
23016
  conversations: viewModel.conversations,
23017
+ provider: viewModel.data.provider,
23008
23018
  store: conversationRailStore,
23009
23019
  storeState: conversationRailStoreState,
23010
- userProjects: viewModel.userProjects
23020
+ userProjects: viewModel.userProjects,
23021
+ workspaceId: viewModel.workspaceId
23011
23022
  }
23012
23023
  )
23013
23024
  }
@@ -23294,13 +23305,15 @@ var AgentGUIDetailPane = memo(function AgentGUIDetailPane2({
23294
23305
  thinkingLabel: labels.thinkingLabel,
23295
23306
  toolCallsLabel: labels.toolCallsLabel,
23296
23307
  processing: labels.processing,
23297
- turnSummary: labels.turnSummary
23308
+ turnSummary: labels.turnSummary,
23309
+ userMessageLocator: labels.userMessageLocator
23298
23310
  }),
23299
23311
  [
23300
23312
  labels.processing,
23301
23313
  labels.thinkingLabel,
23302
23314
  labels.toolCallsLabel,
23303
- labels.turnSummary
23315
+ labels.turnSummary,
23316
+ labels.userMessageLocator
23304
23317
  ]
23305
23318
  );
23306
23319
  const conversationFlowEmpty = useMemo10(
@@ -24430,9 +24443,11 @@ function agentGUIConversationRailStoreSnapshotsEqual(current, next) {
24430
24443
  var AgentGUIConversationRailStorePane = memo(
24431
24444
  function AgentGUIConversationRailStorePane2({
24432
24445
  conversations,
24446
+ provider,
24433
24447
  store,
24434
24448
  storeState: _storeState,
24435
- userProjects
24449
+ userProjects,
24450
+ workspaceId
24436
24451
  }) {
24437
24452
  "use memo";
24438
24453
  const state = useSnapshot(store);
@@ -24441,7 +24456,9 @@ var AgentGUIConversationRailStorePane = memo(
24441
24456
  {
24442
24457
  ...state,
24443
24458
  conversations,
24444
- userProjects
24459
+ provider,
24460
+ userProjects,
24461
+ workspaceId
24445
24462
  }
24446
24463
  );
24447
24464
  }
@@ -24453,6 +24470,47 @@ function normalizeConversationRailProjectPath(path) {
24453
24470
  }
24454
24471
  return normalized.replace(/\/+$/, "") || "/";
24455
24472
  }
24473
+ function buildRailSessionGroupProjects({
24474
+ groups,
24475
+ userProjects
24476
+ }) {
24477
+ const userProjectByPath = new Map(
24478
+ userProjects.map((project) => [
24479
+ normalizeConversationRailProjectPath(project.path),
24480
+ project
24481
+ ])
24482
+ );
24483
+ const groupProjectPaths = /* @__PURE__ */ new Set();
24484
+ const groupProjects = [];
24485
+ for (const group of groups) {
24486
+ const normalizedPath = normalizeConversationRailProjectPath(group.cwd);
24487
+ if (!normalizedPath || groupProjectPaths.has(normalizedPath)) {
24488
+ continue;
24489
+ }
24490
+ groupProjectPaths.add(normalizedPath);
24491
+ const existingProject = userProjectByPath.get(normalizedPath);
24492
+ groupProjects.push({
24493
+ ...existingProject ?? {
24494
+ id: `agent-session-group:${normalizedPath}`,
24495
+ label: labelFromProjectPath(normalizedPath),
24496
+ path: group.cwd
24497
+ },
24498
+ lastUsedAtUnixMs: group.latestSessionUpdatedAtUnixMs,
24499
+ updatedAtUnixMs: group.latestSessionUpdatedAtUnixMs
24500
+ });
24501
+ }
24502
+ const emptyUserProjects = userProjects.filter(
24503
+ (project) => !groupProjectPaths.has(normalizeConversationRailProjectPath(project.path))
24504
+ );
24505
+ return [...groupProjects, ...emptyUserProjects];
24506
+ }
24507
+ function labelFromProjectPath(path) {
24508
+ const normalized = normalizeConversationRailProjectPath(path);
24509
+ if (!normalized || normalized === "/") {
24510
+ return path || "/";
24511
+ }
24512
+ return normalized.split("/").filter(Boolean).at(-1) ?? normalized;
24513
+ }
24456
24514
  function stabilizeConversationSections(previous, next) {
24457
24515
  if (!previous) {
24458
24516
  return [...next];
@@ -24486,6 +24544,37 @@ function stabilizeConversationSections(previous, next) {
24486
24544
  });
24487
24545
  return changed ? stable : previous;
24488
24546
  }
24547
+ function mergeRefreshedRailSessionGroups(current, refreshed) {
24548
+ const currentByCwd = new Map(current.map((group) => [group.cwd, group]));
24549
+ return refreshed.map((group) => {
24550
+ const existing = currentByCwd.get(group.cwd);
24551
+ if (!existing || existing.sessions.length <= group.sessions.length) {
24552
+ return group;
24553
+ }
24554
+ const sessionIds = new Set(
24555
+ group.sessions.map((session) => session.agentSessionId)
24556
+ );
24557
+ const sessions = [...group.sessions];
24558
+ for (const session of existing.sessions) {
24559
+ if (sessions.length >= group.sessionCount) {
24560
+ break;
24561
+ }
24562
+ if (sessionIds.has(session.agentSessionId)) {
24563
+ continue;
24564
+ }
24565
+ sessionIds.add(session.agentSessionId);
24566
+ sessions.push(session);
24567
+ }
24568
+ const preservedLoadedPages = sessions.length > group.sessions.length;
24569
+ const hasMore = preservedLoadedPages ? existing.hasMore && sessions.length < group.sessionCount : group.hasMore;
24570
+ return {
24571
+ ...group,
24572
+ hasMore,
24573
+ nextCursor: hasMore ? preservedLoadedPages ? existing.nextCursor : group.nextCursor : void 0,
24574
+ sessions
24575
+ };
24576
+ });
24577
+ }
24489
24578
  function stabilizeConversationSectionItems(previous, next) {
24490
24579
  if (previous.length !== next.length) {
24491
24580
  const previousById = /* @__PURE__ */ new Map();
@@ -24525,6 +24614,8 @@ function conversationProjectsRenderEqual2(left, right) {
24525
24614
  var AgentGUIConversationRailPane = memo(
24526
24615
  function AgentGUIConversationRailPane2({
24527
24616
  conversations,
24617
+ provider,
24618
+ workspaceId,
24528
24619
  userProjects,
24529
24620
  activeConversationId,
24530
24621
  pendingDeleteConversationId,
@@ -24555,7 +24646,21 @@ var AgentGUIConversationRailPane = memo(
24555
24646
  onConfirmDeleteConversation
24556
24647
  }) {
24557
24648
  "use memo";
24649
+ const agentActivityRuntime = useAgentActivityRuntime();
24558
24650
  const [conversationQuery, setConversationQuery] = useState11("");
24651
+ const [searchConversations, setSearchConversations] = useState11([]);
24652
+ const [searchConversationQuery, setSearchConversationQuery] = useState11("");
24653
+ const [searchHasMore, setSearchHasMore] = useState11(false);
24654
+ const [searchNextCursor, setSearchNextCursor] = useState11(
24655
+ null
24656
+ );
24657
+ const [
24658
+ isLoadingMoreSearchConversations,
24659
+ setIsLoadingMoreSearchConversations
24660
+ ] = useState11(false);
24661
+ const [railSessionGroups, setRailSessionGroups] = useState11([]);
24662
+ const [activeConversationOverlay, setActiveConversationOverlay] = useState11(null);
24663
+ const [loadingMoreSectionIds, setLoadingMoreSectionIds] = useState11(() => /* @__PURE__ */ new Set());
24559
24664
  const [collapsedProjectSectionIds, setCollapsedProjectSectionIds] = useState11(() => /* @__PURE__ */ new Set());
24560
24665
  const [currentTimeMs, setCurrentTimeMs] = useState11(() => Date.now());
24561
24666
  const [pendingProjectAction, setPendingProjectAction] = useState11(null);
@@ -24565,6 +24670,7 @@ var AgentGUIConversationRailPane = memo(
24565
24670
  /* @__PURE__ */ new Map()
24566
24671
  );
24567
24672
  const groupedConversationsRef = useRef12(null);
24673
+ const wasDeletingConversationRef = useRef12(false);
24568
24674
  useEffect12(() => {
24569
24675
  const timer = window.setInterval(() => {
24570
24676
  setCurrentTimeMs(Date.now());
@@ -24573,25 +24679,217 @@ var AgentGUIConversationRailPane = memo(
24573
24679
  window.clearInterval(timer);
24574
24680
  };
24575
24681
  }, []);
24682
+ const trimmedConversationQuery = conversationQuery.trim();
24683
+ const hasConversationQuery = trimmedConversationQuery.length > 0;
24684
+ const hasRuntimeGroupSource = !previewMode && Boolean(agentActivityRuntime.listSessionGroups);
24685
+ const conversationIdentityKey = useMemo10(
24686
+ () => conversations.map((conversation) => conversation.id).join("|"),
24687
+ [conversations]
24688
+ );
24689
+ const railSessionGroupProjects = useMemo10(
24690
+ () => buildRailSessionGroupProjects({
24691
+ groups: railSessionGroups,
24692
+ userProjects
24693
+ }),
24694
+ [railSessionGroups, userProjects]
24695
+ );
24696
+ const defaultRailGroupConversations = useMemo10(() => {
24697
+ const freshConversationById = new Map(
24698
+ conversations.map((conversation) => [conversation.id, conversation])
24699
+ );
24700
+ return buildAgentGUIConversationSummaries({
24701
+ provider,
24702
+ snapshot: {
24703
+ composerOptionsByProvider: {},
24704
+ presences: [],
24705
+ sessionMessagesById: {},
24706
+ sessions: railSessionGroups.flatMap((group) => group.sessions),
24707
+ workspaceId
24708
+ },
24709
+ userProjects: railSessionGroupProjects
24710
+ }).map(
24711
+ (conversation) => freshConversationById.get(conversation.id) ?? conversation
24712
+ );
24713
+ }, [
24714
+ conversations,
24715
+ provider,
24716
+ railSessionGroupProjects,
24717
+ railSessionGroups,
24718
+ workspaceId
24719
+ ]);
24720
+ const defaultRailSourceConversations = useMemo10(() => {
24721
+ const source = hasRuntimeGroupSource ? defaultRailGroupConversations : conversations;
24722
+ if (!activeConversationOverlay || source.some((item) => item.id === activeConversationOverlay.id)) {
24723
+ return source;
24724
+ }
24725
+ return [...source, activeConversationOverlay];
24726
+ }, [
24727
+ activeConversationOverlay,
24728
+ conversations,
24729
+ defaultRailGroupConversations,
24730
+ hasRuntimeGroupSource
24731
+ ]);
24732
+ const effectiveSearchConversations = searchConversationQuery === trimmedConversationQuery ? searchConversations : [];
24733
+ const railSourceConversations = hasConversationQuery ? effectiveSearchConversations : defaultRailSourceConversations;
24734
+ const runtimeSearchSessions = agentActivityRuntime.searchSessions;
24735
+ useEffect12(() => {
24736
+ if (!activeConversationOverlay || activeConversationOverlay.id !== activeConversationId) {
24737
+ return;
24738
+ }
24739
+ if (defaultRailGroupConversations.some(
24740
+ (item) => item.id === activeConversationOverlay.id
24741
+ )) {
24742
+ setActiveConversationOverlay(null);
24743
+ }
24744
+ }, [
24745
+ activeConversationId,
24746
+ activeConversationOverlay,
24747
+ defaultRailGroupConversations
24748
+ ]);
24749
+ useEffect12(() => {
24750
+ if (!hasConversationQuery) {
24751
+ setSearchConversationQuery("");
24752
+ setSearchConversations([]);
24753
+ setSearchHasMore(false);
24754
+ setSearchNextCursor(null);
24755
+ return;
24756
+ }
24757
+ if (!runtimeSearchSessions) {
24758
+ return;
24759
+ }
24760
+ let disposed = false;
24761
+ const timer = window.setTimeout(() => {
24762
+ void runtimeSearchSessions({
24763
+ limit: 100,
24764
+ query: trimmedConversationQuery,
24765
+ workspaceId
24766
+ }).then((result) => {
24767
+ if (disposed) {
24768
+ return;
24769
+ }
24770
+ setSearchConversationQuery(trimmedConversationQuery);
24771
+ setSearchConversations(
24772
+ buildAgentGUIConversationSummaries({
24773
+ provider,
24774
+ snapshot: {
24775
+ composerOptionsByProvider: {},
24776
+ presences: [],
24777
+ sessionMessagesById: {},
24778
+ sessions: result.sessions,
24779
+ workspaceId: result.workspaceId
24780
+ },
24781
+ userProjects
24782
+ })
24783
+ );
24784
+ setSearchHasMore(result.hasMore);
24785
+ setSearchNextCursor(result.nextCursor ?? null);
24786
+ }).catch(() => {
24787
+ if (!disposed) {
24788
+ setSearchConversationQuery(trimmedConversationQuery);
24789
+ setSearchConversations([]);
24790
+ setSearchHasMore(false);
24791
+ setSearchNextCursor(null);
24792
+ }
24793
+ });
24794
+ }, 150);
24795
+ return () => {
24796
+ disposed = true;
24797
+ window.clearTimeout(timer);
24798
+ };
24799
+ }, [
24800
+ hasConversationQuery,
24801
+ provider,
24802
+ runtimeSearchSessions,
24803
+ trimmedConversationQuery,
24804
+ userProjects,
24805
+ workspaceId
24806
+ ]);
24807
+ useEffect12(() => {
24808
+ if (!hasConversationQuery || runtimeSearchSessions) {
24809
+ return;
24810
+ }
24811
+ setSearchConversationQuery(trimmedConversationQuery);
24812
+ setSearchConversations(
24813
+ conversations.filter(
24814
+ (candidate) => conversationPlainTitle(candidate, labels, uiLanguage).toLowerCase().includes(trimmedConversationQuery.toLowerCase())
24815
+ )
24816
+ );
24817
+ setSearchHasMore(false);
24818
+ setSearchNextCursor(null);
24819
+ }, [
24820
+ conversations,
24821
+ hasConversationQuery,
24822
+ labels,
24823
+ runtimeSearchSessions,
24824
+ trimmedConversationQuery,
24825
+ uiLanguage
24826
+ ]);
24827
+ useEffect12(() => {
24828
+ if (!agentActivityRuntime.listSessionGroups || previewMode) {
24829
+ setRailSessionGroups([]);
24830
+ return;
24831
+ }
24832
+ let disposed = false;
24833
+ const isDeletingNow = isDeletingConversation || isDeletingProjectConversations;
24834
+ const resetLoadedGroups = wasDeletingConversationRef.current && !isDeletingNow;
24835
+ wasDeletingConversationRef.current = isDeletingNow;
24836
+ void agentActivityRuntime.listSessionGroups({
24837
+ sessionLimit: AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE,
24838
+ visibleOnly: true,
24839
+ workspaceId
24840
+ }).then((result) => {
24841
+ if (!disposed) {
24842
+ setRailSessionGroups(
24843
+ (current) => resetLoadedGroups ? result.groups : mergeRefreshedRailSessionGroups(current, result.groups)
24844
+ );
24845
+ }
24846
+ }).catch(() => {
24847
+ if (!disposed) {
24848
+ setRailSessionGroups([]);
24849
+ }
24850
+ });
24851
+ return () => {
24852
+ disposed = true;
24853
+ };
24854
+ }, [
24855
+ agentActivityRuntime,
24856
+ conversationIdentityKey,
24857
+ isDeletingConversation,
24858
+ isDeletingProjectConversations,
24859
+ previewMode,
24860
+ workspaceId
24861
+ ]);
24862
+ const groupingProjects = hasConversationQuery ? [] : hasRuntimeGroupSource ? railSessionGroupProjects : userProjects;
24863
+ const showEmptyConversationSection = useMemo10(
24864
+ () => !hasConversationQuery && (hasRuntimeGroupSource ? railSessionGroups.some((group) => !group.cwd.trim()) : !conversations.some(
24865
+ (conversation) => conversation.project == null
24866
+ )),
24867
+ [
24868
+ conversations,
24869
+ hasConversationQuery,
24870
+ hasRuntimeGroupSource,
24871
+ railSessionGroups
24872
+ ]
24873
+ );
24576
24874
  const filteredConversationResult = useMemo10(() => {
24577
24875
  const startedAtMs = agentGuiPerfNowMs();
24578
- const query = conversationQuery.trim().toLowerCase();
24579
- const items = !query ? conversations : conversations.filter(
24876
+ const query = trimmedConversationQuery.toLowerCase();
24877
+ const items = !query ? railSourceConversations : railSourceConversations.filter(
24580
24878
  (candidate) => conversationPlainTitle(candidate, labels, uiLanguage).toLowerCase().includes(query)
24581
24879
  );
24582
24880
  return {
24583
24881
  items,
24584
24882
  filterMs: roundAgentGuiPerfMs(agentGuiPerfNowMs() - startedAtMs)
24585
24883
  };
24586
- }, [conversationQuery, conversations, labels, uiLanguage]);
24884
+ }, [labels, railSourceConversations, trimmedConversationQuery, uiLanguage]);
24587
24885
  const filteredConversations = filteredConversationResult.items;
24588
24886
  const groupedConversationResult = useMemo10(() => {
24589
24887
  const startedAtMs = agentGuiPerfNowMs();
24590
24888
  const rawGroups = groupConversations(
24591
24889
  filteredConversations,
24592
24890
  labels,
24593
- conversationQuery.trim() ? [] : userProjects,
24594
- { includeEmptyConversations: !conversationQuery.trim() }
24891
+ groupingProjects,
24892
+ { includeEmptyConversations: showEmptyConversationSection }
24595
24893
  );
24596
24894
  const groups = stabilizeConversationSections(
24597
24895
  groupedConversationsRef.current,
@@ -24602,7 +24900,12 @@ var AgentGUIConversationRailPane = memo(
24602
24900
  groups,
24603
24901
  groupMs: roundAgentGuiPerfMs(agentGuiPerfNowMs() - startedAtMs)
24604
24902
  };
24605
- }, [conversationQuery, filteredConversations, labels, userProjects]);
24903
+ }, [
24904
+ filteredConversations,
24905
+ groupingProjects,
24906
+ labels,
24907
+ showEmptyConversationSection
24908
+ ]);
24606
24909
  const groupedConversations = groupedConversationResult.groups;
24607
24910
  const toggleProjectSectionCollapsed = useCallback10((sectionId) => {
24608
24911
  setCollapsedProjectSectionIds((current) => {
@@ -24623,17 +24926,140 @@ var AgentGUIConversationRailPane = memo(
24623
24926
  );
24624
24927
  const projectConversationCountsByPath = useMemo10(() => {
24625
24928
  const counts = /* @__PURE__ */ new Map();
24929
+ const pathsFromGroups = /* @__PURE__ */ new Set();
24930
+ for (const group of railSessionGroups) {
24931
+ const normalizedPath = normalizeConversationRailProjectPath(group.cwd);
24932
+ if (!normalizedPath) {
24933
+ continue;
24934
+ }
24935
+ counts.set(normalizedPath, group.sessionCount);
24936
+ pathsFromGroups.add(normalizedPath);
24937
+ }
24626
24938
  for (const conversation of conversations) {
24627
24939
  const normalizedPath = normalizeConversationRailProjectPath(
24628
24940
  conversation.project?.path
24629
24941
  );
24630
- if (!normalizedPath) {
24942
+ if (!normalizedPath || pathsFromGroups.has(normalizedPath)) {
24631
24943
  continue;
24632
24944
  }
24633
24945
  counts.set(normalizedPath, (counts.get(normalizedPath) ?? 0) + 1);
24634
24946
  }
24635
24947
  return counts;
24636
- }, [conversations]);
24948
+ }, [conversations, railSessionGroups]);
24949
+ const railSessionGroupBySectionId = useMemo10(() => {
24950
+ const groupsBySectionId = /* @__PURE__ */ new Map();
24951
+ for (const group of railSessionGroups) {
24952
+ const normalizedPath = normalizeConversationRailProjectPath(group.cwd);
24953
+ groupsBySectionId.set(
24954
+ normalizedPath ? `project:${normalizedPath}` : "conversations",
24955
+ group
24956
+ );
24957
+ }
24958
+ return groupsBySectionId;
24959
+ }, [railSessionGroups]);
24960
+ const loadMoreSectionConversations = useCallback10(
24961
+ (sectionId) => {
24962
+ const group = railSessionGroupBySectionId.get(sectionId);
24963
+ const listSessionsPage = agentActivityRuntime.listSessionsPage;
24964
+ if (!group?.hasMore || !group.nextCursor || !listSessionsPage) {
24965
+ return;
24966
+ }
24967
+ setLoadingMoreSectionIds((current) => {
24968
+ if (current.has(sectionId)) {
24969
+ return current;
24970
+ }
24971
+ const next = new Set(current);
24972
+ next.add(sectionId);
24973
+ return next;
24974
+ });
24975
+ void listSessionsPage({
24976
+ cursor: group.nextCursor,
24977
+ cwd: group.cwd,
24978
+ limit: AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE,
24979
+ visibleOnly: true,
24980
+ workspaceId
24981
+ }).then((page) => {
24982
+ setRailSessionGroups(
24983
+ (current) => current.map((candidate) => {
24984
+ if (candidate.cwd !== group.cwd) {
24985
+ return candidate;
24986
+ }
24987
+ const sessionIds = new Set(
24988
+ candidate.sessions.map((session) => session.agentSessionId)
24989
+ );
24990
+ const nextSessions = [...candidate.sessions];
24991
+ for (const session of page.sessions) {
24992
+ if (!sessionIds.has(session.agentSessionId)) {
24993
+ sessionIds.add(session.agentSessionId);
24994
+ nextSessions.push(session);
24995
+ }
24996
+ }
24997
+ return {
24998
+ ...candidate,
24999
+ hasMore: page.hasMore,
25000
+ nextCursor: page.nextCursor,
25001
+ sessions: nextSessions
25002
+ };
25003
+ })
25004
+ );
25005
+ }).finally(() => {
25006
+ setLoadingMoreSectionIds((current) => {
25007
+ if (!current.has(sectionId)) {
25008
+ return current;
25009
+ }
25010
+ const next = new Set(current);
25011
+ next.delete(sectionId);
25012
+ return next;
25013
+ });
25014
+ });
25015
+ },
25016
+ [agentActivityRuntime, railSessionGroupBySectionId, workspaceId]
25017
+ );
25018
+ const loadMoreSearchConversations = useCallback10(() => {
25019
+ const searchSessions = agentActivityRuntime.searchSessions;
25020
+ if (!searchSessions || !searchHasMore || !searchNextCursor || isLoadingMoreSearchConversations) {
25021
+ return;
25022
+ }
25023
+ setIsLoadingMoreSearchConversations(true);
25024
+ void searchSessions({
25025
+ cursor: searchNextCursor,
25026
+ limit: 100,
25027
+ query: trimmedConversationQuery,
25028
+ workspaceId
25029
+ }).then((result) => {
25030
+ const nextConversations = buildAgentGUIConversationSummaries({
25031
+ provider,
25032
+ snapshot: {
25033
+ composerOptionsByProvider: {},
25034
+ presences: [],
25035
+ sessionMessagesById: {},
25036
+ sessions: result.sessions,
25037
+ workspaceId: result.workspaceId
25038
+ },
25039
+ userProjects
25040
+ });
25041
+ setSearchConversations((current) => {
25042
+ const currentIds = new Set(current.map((item) => item.id));
25043
+ return [
25044
+ ...current,
25045
+ ...nextConversations.filter((item) => !currentIds.has(item.id))
25046
+ ];
25047
+ });
25048
+ setSearchHasMore(result.hasMore);
25049
+ setSearchNextCursor(result.nextCursor ?? null);
25050
+ }).finally(() => {
25051
+ setIsLoadingMoreSearchConversations(false);
25052
+ });
25053
+ }, [
25054
+ agentActivityRuntime,
25055
+ isLoadingMoreSearchConversations,
25056
+ provider,
25057
+ searchHasMore,
25058
+ searchNextCursor,
25059
+ trimmedConversationQuery,
25060
+ userProjects,
25061
+ workspaceId
25062
+ ]);
24637
25063
  const registerConversationItemElement = useCallback10(
24638
25064
  (itemId, element) => {
24639
25065
  if (element) {
@@ -24644,6 +25070,46 @@ var AgentGUIConversationRailPane = memo(
24644
25070
  },
24645
25071
  []
24646
25072
  );
25073
+ const handleSelectConversation = useCallback10(
25074
+ (agentSessionId) => {
25075
+ const normalizedAgentSessionId = agentSessionId.trim();
25076
+ if (!normalizedAgentSessionId) {
25077
+ return;
25078
+ }
25079
+ const isLoadedConversation = conversations.some(
25080
+ (conversation) => conversation.id === normalizedAgentSessionId
25081
+ );
25082
+ if (!hasConversationQuery || isLoadedConversation) {
25083
+ onSelectConversation(normalizedAgentSessionId);
25084
+ return;
25085
+ }
25086
+ void agentActivityRuntime.getSession(workspaceId, normalizedAgentSessionId).then((session) => {
25087
+ const [overlay] = buildAgentGUIConversationSummaries({
25088
+ provider,
25089
+ snapshot: {
25090
+ composerOptionsByProvider: {},
25091
+ presences: [],
25092
+ sessionMessagesById: {},
25093
+ sessions: [session],
25094
+ workspaceId
25095
+ },
25096
+ userProjects: railSessionGroupProjects
25097
+ });
25098
+ setActiveConversationOverlay(overlay ?? null);
25099
+ onSelectConversation(normalizedAgentSessionId);
25100
+ }).catch(() => {
25101
+ });
25102
+ },
25103
+ [
25104
+ agentActivityRuntime,
25105
+ conversations,
25106
+ hasConversationQuery,
25107
+ onSelectConversation,
25108
+ provider,
25109
+ railSessionGroupProjects,
25110
+ workspaceId
25111
+ ]
25112
+ );
24647
25113
  useLayoutEffect4(() => {
24648
25114
  if (!activeConversationId) {
24649
25115
  return;
@@ -24726,6 +25192,9 @@ var AgentGUIConversationRailPane = memo(
24726
25192
  const showProjectRailHeader = !conversationQuery.trim() && section.kind !== "pinned" && (sectionIndex === 0 || groupedConversations[sectionIndex - 1]?.kind === "pinned");
24727
25193
  const isSectionCollapsed = isProjectSection && collapsedProjectSectionIds.has(section.id);
24728
25194
  const projectConversationCount = normalizedProjectPath ? projectConversationCountsByPath.get(normalizedProjectPath) ?? 0 : 0;
25195
+ const sectionSessionGroup = railSessionGroupBySectionId.get(
25196
+ section.id
25197
+ );
24729
25198
  return /* @__PURE__ */ jsxs17(Fragment7, { children: [
24730
25199
  showProjectRailHeader ? /* @__PURE__ */ jsx31(
24731
25200
  AgentGUIProjectRailHeader,
@@ -24742,11 +25211,13 @@ var AgentGUIConversationRailPane = memo(
24742
25211
  createConversationDisabled,
24743
25212
  currentTimeMs,
24744
25213
  isDeletingConversation,
25214
+ isLoadingMoreConversations: hasConversationQuery ? isLoadingMoreSearchConversations : loadingMoreSectionIds.has(section.id),
24745
25215
  isSectionCollapsed,
24746
25216
  labels,
24747
25217
  pendingDeleteConversationId,
24748
25218
  previewMode,
24749
25219
  projectConversationCount,
25220
+ sectionHasMore: hasConversationQuery ? searchHasMore : Boolean(sectionSessionGroup?.hasMore),
24750
25221
  projectLabel,
24751
25222
  projectPath,
24752
25223
  registerItemElement: registerConversationItemElement,
@@ -24756,11 +25227,12 @@ var AgentGUIConversationRailPane = memo(
24756
25227
  onConfirmDeleteConversation,
24757
25228
  onCreateConversation,
24758
25229
  onRequestDeleteConversation,
24759
- onSelectConversation,
25230
+ onSelectConversation: handleSelectConversation,
24760
25231
  setPendingProjectAction,
24761
25232
  onToggleConversationPinned,
24762
25233
  onOpenProjectFiles,
24763
25234
  onOpenConversationWindow,
25235
+ onLoadMoreConversations: hasConversationQuery ? loadMoreSearchConversations : loadMoreSectionConversations,
24764
25236
  onToggleProjectSectionCollapsed: toggleProjectSectionCollapsed
24765
25237
  }
24766
25238
  )
@@ -24890,6 +25362,8 @@ var AgentGUIConversationRailSection = memo(
24890
25362
  pendingDeleteConversationId,
24891
25363
  previewMode,
24892
25364
  isDeletingConversation,
25365
+ isLoadingMoreConversations,
25366
+ sectionHasMore,
24893
25367
  createConversationDisabled,
24894
25368
  currentTimeMs,
24895
25369
  labels,
@@ -24898,6 +25372,7 @@ var AgentGUIConversationRailSection = memo(
24898
25372
  onCreateConversation,
24899
25373
  onToggleProjectSectionCollapsed,
24900
25374
  onSelectConversation,
25375
+ onLoadMoreConversations,
24901
25376
  setPendingProjectAction,
24902
25377
  onToggleConversationPinned,
24903
25378
  onOpenProjectFiles,
@@ -24913,16 +25388,29 @@ var AgentGUIConversationRailSection = memo(
24913
25388
  );
24914
25389
  const visibleItemCount = isSectionCollapsed ? 0 : Math.min(visibleItemLimit, section.items.length);
24915
25390
  const visibleItems = isSectionCollapsed ? [] : section.items.slice(0, visibleItemCount);
24916
- const canShowMore = !isSectionCollapsed && visibleItemCount < section.items.length;
25391
+ const canShowMore = !isSectionCollapsed && (visibleItemCount < section.items.length || sectionHasMore);
24917
25392
  const canShowLess = !isSectionCollapsed && visibleItemCount > AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE;
24918
25393
  const showMoreConversations = useCallback10(() => {
25394
+ if (visibleItemCount >= section.items.length && sectionHasMore) {
25395
+ onLoadMoreConversations(section.id);
25396
+ setVisibleItemLimit(
25397
+ (current) => current + AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE
25398
+ );
25399
+ return;
25400
+ }
24919
25401
  setVisibleItemLimit(
24920
25402
  (current) => Math.min(
24921
25403
  section.items.length,
24922
25404
  current + AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE
24923
25405
  )
24924
25406
  );
24925
- }, [section.items.length]);
25407
+ }, [
25408
+ onLoadMoreConversations,
25409
+ section.id,
25410
+ section.items.length,
25411
+ sectionHasMore,
25412
+ visibleItemCount
25413
+ ]);
24926
25414
  const showLessConversations = useCallback10(() => {
24927
25415
  setVisibleItemLimit(AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE);
24928
25416
  }, []);
@@ -25215,6 +25703,7 @@ var AgentGUIConversationRailSection = memo(
25215
25703
  {
25216
25704
  type: "button",
25217
25705
  className: AgentGUINode_styles_default.conversationSectionPaginationButton,
25706
+ disabled: isLoadingMoreConversations,
25218
25707
  onClick: showMoreConversations,
25219
25708
  children: labels.showMoreConversations
25220
25709
  }
@@ -26639,6 +27128,7 @@ var AgentGUINode = memo2(function AgentGUINode2({
26639
27128
  goalClearHint: t("agentHost.agentGui.goalClearHint"),
26640
27129
  processing: t("agentHost.agentGui.processing"),
26641
27130
  turnSummary: t("agentHost.agentGui.turnSummary"),
27131
+ userMessageLocator: t("agentHost.agentGui.userMessageLocator"),
26642
27132
  planLead: t("agentHost.agentGui.planLead"),
26643
27133
  planModes: [
26644
27134
  {