@tutti-os/agent-gui 0.0.104 → 0.0.106

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 (81) hide show
  1. package/dist/{AgentGUI-DQ9gVoXh.d.ts → AgentGUI-Do6py-T_.d.ts} +10 -5
  2. package/dist/AgentRichTextReadonly-F6PHC5SX.js +18 -0
  3. package/dist/AgentRichTextReadonly-F6PHC5SX.js.map +1 -0
  4. package/dist/agent-conversation/index.d.ts +3 -3
  5. package/dist/agent-conversation/index.js +11 -7
  6. package/dist/agent-conversation/index.js.map +1 -1
  7. package/dist/agent-gui.d.ts +4 -4
  8. package/dist/agent-gui.js +18 -14
  9. package/dist/agent-message-center/index.d.ts +1 -1
  10. package/dist/agent-message-center/index.js +13 -9
  11. package/dist/agent-message-center/index.js.map +1 -1
  12. package/dist/{agentConversationVM-CkcYM5Wg.d.ts → agentConversationVM-Bf3Zv3iI.d.ts} +9 -1
  13. package/dist/{agentFileMentionContracts-58IjMU-u.d.ts → agentFileMentionContracts-B70VnPWO.d.ts} +2 -0
  14. package/dist/{agentGuiNodeTypes-B9vcvjmR.d.ts → agentGuiNodeTypes-DbgQBiYz.d.ts} +4 -1
  15. package/dist/app/renderer/agentactivity.css +99 -0
  16. package/dist/{chunk-7N524ZK7.js → chunk-4HSLSSPJ.js} +1387 -941
  17. package/dist/chunk-4HSLSSPJ.js.map +1 -0
  18. package/dist/{chunk-FJ4W2VC5.js → chunk-4ZWV57MF.js} +42 -10
  19. package/dist/chunk-4ZWV57MF.js.map +1 -0
  20. package/dist/{chunk-TPV2SV6L.js → chunk-7MPN2JGL.js} +122 -154
  21. package/dist/chunk-7MPN2JGL.js.map +1 -0
  22. package/dist/{chunk-747L443E.js → chunk-BXOKBZH4.js} +728 -77
  23. package/dist/chunk-BXOKBZH4.js.map +1 -0
  24. package/dist/{chunk-5X7YDOC6.js → chunk-D2JUDUYY.js} +1 -1
  25. package/dist/chunk-D2JUDUYY.js.map +1 -0
  26. package/dist/{chunk-HLVC4NNL.js → chunk-IR2CL2X2.js} +721 -1280
  27. package/dist/chunk-IR2CL2X2.js.map +1 -0
  28. package/dist/{chunk-NOXQOGT5.js → chunk-J2HG7UCP.js} +46 -22
  29. package/dist/chunk-J2HG7UCP.js.map +1 -0
  30. package/dist/chunk-KPMQGPYU.js +43 -0
  31. package/dist/chunk-KPMQGPYU.js.map +1 -0
  32. package/dist/{chunk-OFSDOID4.js → chunk-LDZ6C3YV.js} +3 -39
  33. package/dist/chunk-LDZ6C3YV.js.map +1 -0
  34. package/dist/{chunk-MUPZPISC.js → chunk-N4WVVCNI.js} +2 -2
  35. package/dist/{chunk-F5LFPORI.js → chunk-OWW7CU4U.js} +2 -2
  36. package/dist/{chunk-VAB7EIL5.js → chunk-P3CVAWGJ.js} +19 -8
  37. package/dist/chunk-P3CVAWGJ.js.map +1 -0
  38. package/dist/chunk-SN6UYX54.js +42 -0
  39. package/dist/chunk-SN6UYX54.js.map +1 -0
  40. package/dist/{chunk-SKCLZXSW.js → chunk-TKBEVCHG.js} +5 -1
  41. package/dist/chunk-TKBEVCHG.js.map +1 -0
  42. package/dist/chunk-UFIEUC3Y.js +755 -0
  43. package/dist/chunk-UFIEUC3Y.js.map +1 -0
  44. package/dist/{chunk-AKKDP2LI.js → chunk-V5ROOS2O.js} +124 -2
  45. package/dist/chunk-V5ROOS2O.js.map +1 -0
  46. package/dist/chunk-XJ34OIEQ.js +18 -0
  47. package/dist/chunk-XJ34OIEQ.js.map +1 -0
  48. package/dist/{chunk-QI3JAO4J.js → chunk-ZSJBCZUH.js} +54 -7
  49. package/dist/chunk-ZSJBCZUH.js.map +1 -0
  50. package/dist/context-mention-palette/index.d.ts +1 -1
  51. package/dist/context-mention-palette/index.js +10 -8
  52. package/dist/{contribution-CTVBPN0R.d.ts → contribution-C6K5YfJ7.d.ts} +1 -0
  53. package/dist/custom-mention.d.ts +6 -0
  54. package/dist/custom-mention.js +1 -1
  55. package/dist/i18n/index.d.ts +4 -0
  56. package/dist/i18n/index.js +2 -2
  57. package/dist/index.d.ts +6 -6
  58. package/dist/index.js +18 -14
  59. package/dist/index.js.map +1 -1
  60. package/dist/mention-search.d.ts +47 -7
  61. package/dist/mention-search.js +8 -6
  62. package/dist/workbench/contribution.d.ts +1 -1
  63. package/dist/workbench/contribution.js +3 -3
  64. package/dist/workbench/index.d.ts +3 -2
  65. package/dist/workbench/index.js +3 -3
  66. package/dist/workbench/sessionTitle.js +2 -2
  67. package/package.json +12 -12
  68. package/dist/chunk-5X7YDOC6.js.map +0 -1
  69. package/dist/chunk-747L443E.js.map +0 -1
  70. package/dist/chunk-7N524ZK7.js.map +0 -1
  71. package/dist/chunk-AKKDP2LI.js.map +0 -1
  72. package/dist/chunk-FJ4W2VC5.js.map +0 -1
  73. package/dist/chunk-HLVC4NNL.js.map +0 -1
  74. package/dist/chunk-NOXQOGT5.js.map +0 -1
  75. package/dist/chunk-OFSDOID4.js.map +0 -1
  76. package/dist/chunk-QI3JAO4J.js.map +0 -1
  77. package/dist/chunk-SKCLZXSW.js.map +0 -1
  78. package/dist/chunk-TPV2SV6L.js.map +0 -1
  79. package/dist/chunk-VAB7EIL5.js.map +0 -1
  80. /package/dist/{chunk-MUPZPISC.js.map → chunk-N4WVVCNI.js.map} +0 -0
  81. /package/dist/{chunk-F5LFPORI.js.map → chunk-OWW7CU4U.js.map} +0 -0
@@ -3,9 +3,11 @@ import {
3
3
  workspaceAgentSessionMessageAliases
4
4
  } from "./chunk-4YCCATI4.js";
5
5
  import {
6
- isWorkspaceAgentSyntheticControlMessage,
6
+ isWorkspaceAgentSyntheticControlMessage
7
+ } from "./chunk-XJ34OIEQ.js";
8
+ import {
7
9
  normalizeAgentSessionMentionTitle
8
- } from "./chunk-NOXQOGT5.js";
10
+ } from "./chunk-J2HG7UCP.js";
9
11
  import {
10
12
  resolveAgentMentionFileThumbnailUrl
11
13
  } from "./chunk-LUGELG5V.js";
@@ -18,17 +20,20 @@ import {
18
20
  import {
19
21
  getOptionalAgentHostApi,
20
22
  workspaceAgentProviderLabel
21
- } from "./chunk-OFSDOID4.js";
23
+ } from "./chunk-LDZ6C3YV.js";
22
24
  import {
23
25
  normalizeAgentTitleText
24
26
  } from "./chunk-MIJXEELH.js";
25
27
  import {
26
28
  translate,
27
29
  translateInUiLanguage
28
- } from "./chunk-F5LFPORI.js";
30
+ } from "./chunk-OWW7CU4U.js";
29
31
 
30
32
  // agent-gui/agentGuiNode/AgentMentionLabels.ts
31
33
  function agentMentionGroupLabel(groupId) {
34
+ if (groupId.startsWith("issue-topic:")) {
35
+ return "";
36
+ }
32
37
  switch (groupId) {
33
38
  case "apps":
34
39
  return translate("agentHost.agentGui.mentionGroupApps");
@@ -46,6 +51,8 @@ function agentMentionGroupLabel(groupId) {
46
51
  return translate("agentHost.agentGui.mentionGroupCollabSessions");
47
52
  case "issues":
48
53
  return translate("agentHost.agentGui.mentionGroupIssues");
54
+ default:
55
+ return "";
49
56
  }
50
57
  }
51
58
  function agentMentionFilterLabel(filter) {
@@ -63,6 +70,9 @@ function agentMentionFilterLabel(filter) {
63
70
  }
64
71
  }
65
72
  function agentMentionEmptyGroupLabel(groupId, query) {
73
+ if (groupId.startsWith("issue-topic:")) {
74
+ return "";
75
+ }
66
76
  if (groupId === "files" || groupId === "opened_files") {
67
77
  return query.trim() ? translate("agentHost.agentGui.mentionNoMatchingFiles") : translate("agentHost.agentGui.mentionEmptyDockFiles");
68
78
  }
@@ -81,6 +91,9 @@ function agentMentionEmptyGroupLabel(groupId, query) {
81
91
  if (groupId === "collab_sessions") {
82
92
  return translate("agentHost.agentGui.mentionEmptyCollabSessions");
83
93
  }
94
+ if (groupId.startsWith("agent:")) {
95
+ return translate("agentHost.agentGui.mentionEmptyMySessions");
96
+ }
84
97
  return translate("agentHost.agentGui.mentionEmptyIssues");
85
98
  }
86
99
 
@@ -414,6 +427,9 @@ function groupIdsForFilter(filter) {
414
427
  }
415
428
  }
416
429
  function shouldShowEmptyGroup(groupId, filter, query) {
430
+ if (groupId.startsWith("issue-topic:")) {
431
+ return false;
432
+ }
417
433
  const hasQuery = query.trim().length > 0;
418
434
  if (groupId === "files") {
419
435
  return false;
@@ -449,12 +465,29 @@ function emptyGroupLabel(groupId, query) {
449
465
  return agentMentionEmptyGroupLabel(groupId, query);
450
466
  }
451
467
  function resolveMentionGroupItems(groupId, rawGroups) {
468
+ if (groupId.startsWith("issue-topic:")) {
469
+ return [];
470
+ }
452
471
  if (groupId === "files") {
453
472
  return [...rawGroups.opened_files, ...rawGroups.agent_generated_files];
454
473
  }
455
- return rawGroups[groupId] ?? [];
474
+ if (groupId === "my_sessions" || groupId === "collab_sessions") {
475
+ return rawGroups.sessions.filter(
476
+ (item) => item.kind === "session" && item.scope === groupId
477
+ );
478
+ }
479
+ if (groupId.startsWith("agent:")) {
480
+ return [];
481
+ }
482
+ if (groupId === "apps" || groupId === "agents" || groupId === "opened_files" || groupId === "agent_generated_files" || groupId === "issues") {
483
+ return rawGroups[groupId];
484
+ }
485
+ return [];
456
486
  }
457
487
  function resolveMentionGroupTotalCount(groupId, totalCounts, itemCount) {
488
+ if (groupId.startsWith("issue-topic:")) {
489
+ return itemCount;
490
+ }
458
491
  if (groupId === "files") {
459
492
  return (totalCounts.opened_files ?? 0) + (totalCounts.agent_generated_files ?? 0);
460
493
  }
@@ -602,6 +635,21 @@ function agentGeneratedMentionItemKey(item) {
602
635
 
603
636
  // agent-gui/agentGuiNode/AgentMentionSearchModel.ts
604
637
  function buildAgentMentionGroups(input) {
638
+ if (input.currentFilter === "issue" && input.issueTopicGroups !== null) {
639
+ return input.issueTopicGroups.map((group) => ({
640
+ id: group.id,
641
+ label: group.label,
642
+ items: group.items,
643
+ totalCount: group.totalCount,
644
+ visibleCount: group.items.length,
645
+ hasMore: group.nextPageToken !== null,
646
+ expandStatus: group.loadMoreStatus
647
+ }));
648
+ }
649
+ const provenanceGroups = buildSessionProvenanceGroups(input);
650
+ if (provenanceGroups) {
651
+ return provenanceGroups;
652
+ }
605
653
  const orderedGroupIds = groupIdsForFilter(input.currentFilter);
606
654
  return orderedGroupIds.map((groupId) => {
607
655
  const rawItems = resolveMentionGroupItems(groupId, input.rawGroups);
@@ -636,14 +684,120 @@ function buildAgentMentionGroups(input) {
636
684
  };
637
685
  }).filter((group) => group !== null);
638
686
  }
687
+ function cloneAgentMentionIssueTopicGroups(groups) {
688
+ return groups?.map((group) => ({ ...group, items: [...group.items] })) ?? null;
689
+ }
690
+ function issueTopicPaginationChanges(groupsAtStart, currentGroups) {
691
+ if (!groupsAtStart || !currentGroups) {
692
+ return [];
693
+ }
694
+ const startingGroups = new Map(
695
+ groupsAtStart.map((group) => [group.id, group])
696
+ );
697
+ return currentGroups.flatMap((group) => {
698
+ const startingGroup = startingGroups.get(group.id);
699
+ if (!startingGroup) {
700
+ return [];
701
+ }
702
+ const startingIssueIds = new Set(
703
+ startingGroup.items.filter((item) => item.kind === "workspace-issue").map((item) => item.targetId)
704
+ );
705
+ const appendedItems = group.items.filter(
706
+ (item) => item.kind !== "workspace-issue" || !startingIssueIds.has(item.targetId)
707
+ );
708
+ if (appendedItems.length === 0 && group.nextPageToken === startingGroup.nextPageToken) {
709
+ return [];
710
+ }
711
+ return [{ ...group, items: appendedItems }];
712
+ });
713
+ }
714
+ function buildSessionProvenanceGroups(input) {
715
+ if (input.currentFilter !== "session" || !input.provenanceCatalog?.enabledDimensions.includes("agent")) {
716
+ return null;
717
+ }
718
+ const selectedAgentTargetIds = input.provenanceFilter?.agentTargetIds ?? null;
719
+ const selectedAgentTargetIdSet = selectedAgentTargetIds === null ? null : new Set(selectedAgentTargetIds);
720
+ const sessionItems = input.rawGroups.sessions.filter(
721
+ (item) => item.kind === "session" && (selectedAgentTargetIdSet === null || (item.agentTargetId ? selectedAgentTargetIdSet.has(item.agentTargetId) : false))
722
+ );
723
+ const catalogAgentTargetIds = new Set(
724
+ input.provenanceCatalog.agentOptions.map((option) => option.id)
725
+ );
726
+ const catalogGroups = input.provenanceCatalog.agentOptions.flatMap(
727
+ (option) => {
728
+ const items = sessionItems.filter(
729
+ (item) => item.kind === "session" && item.agentTargetId === option.id
730
+ );
731
+ if (items.length === 0) {
732
+ return [];
733
+ }
734
+ const groupId = agentProvenanceMentionGroupId(option.id);
735
+ const pageSize = mentionGroupPageSize(input.currentFilter, groupId);
736
+ const visibleCount = Math.min(
737
+ items.length,
738
+ input.expandedCounts[groupId] ?? pageSize
739
+ );
740
+ return [
741
+ {
742
+ id: groupId,
743
+ label: option.label,
744
+ items: items.slice(0, visibleCount),
745
+ totalCount: items.length,
746
+ visibleCount,
747
+ hasMore: items.length > visibleCount
748
+ }
749
+ ];
750
+ }
751
+ );
752
+ if (selectedAgentTargetIdSet !== null) {
753
+ return catalogGroups;
754
+ }
755
+ const unmatchedGroups = /* @__PURE__ */ new Map();
756
+ for (const item of sessionItems) {
757
+ if (item.kind !== "session" || item.agentTargetId && catalogAgentTargetIds.has(item.agentTargetId)) {
758
+ continue;
759
+ }
760
+ const identity = item.agentTargetId?.trim() || item.agentName.trim() || item.initiatorName.trim() || item.targetId;
761
+ const key = `uncatalogued:${identity}`;
762
+ const existing = unmatchedGroups.get(key);
763
+ if (existing) {
764
+ existing.items.push(item);
765
+ continue;
766
+ }
767
+ unmatchedGroups.set(key, {
768
+ id: agentProvenanceMentionGroupId(key),
769
+ label: item.agentName.trim() || item.initiatorName.trim() || item.agentTargetId?.trim() || item.title,
770
+ items: [item]
771
+ });
772
+ }
773
+ return [
774
+ ...catalogGroups,
775
+ ...[...unmatchedGroups.values()].map((group) => {
776
+ const pageSize = mentionGroupPageSize(input.currentFilter, group.id);
777
+ const visibleCount = Math.min(
778
+ group.items.length,
779
+ input.expandedCounts[group.id] ?? pageSize
780
+ );
781
+ return {
782
+ ...group,
783
+ items: group.items.slice(0, visibleCount),
784
+ totalCount: group.items.length,
785
+ visibleCount,
786
+ hasMore: group.items.length > visibleCount
787
+ };
788
+ })
789
+ ];
790
+ }
791
+ function agentProvenanceMentionGroupId(agentTargetId) {
792
+ return `agent:${encodeURIComponent(agentTargetId)}`;
793
+ }
639
794
  function emptyAgentMentionRawGroups() {
640
795
  return {
641
796
  apps: [],
642
797
  agents: [],
643
798
  opened_files: [],
644
799
  agent_generated_files: [],
645
- my_sessions: [],
646
- collab_sessions: [],
800
+ sessions: [],
647
801
  issues: []
648
802
  };
649
803
  }
@@ -653,8 +807,7 @@ function cloneAgentMentionRawGroups(rawGroups) {
653
807
  agents: [...rawGroups.agents],
654
808
  opened_files: [...rawGroups.opened_files],
655
809
  agent_generated_files: [...rawGroups.agent_generated_files],
656
- my_sessions: [...rawGroups.my_sessions],
657
- collab_sessions: [...rawGroups.collab_sessions],
810
+ sessions: [...rawGroups.sessions],
658
811
  issues: [...rawGroups.issues]
659
812
  };
660
813
  }
@@ -664,8 +817,12 @@ function totalCountsFromRawGroups(rawGroups) {
664
817
  agents: rawGroups.agents.length,
665
818
  opened_files: rawGroups.opened_files.length,
666
819
  agent_generated_files: rawGroups.agent_generated_files.length,
667
- my_sessions: rawGroups.my_sessions.length,
668
- collab_sessions: rawGroups.collab_sessions.length,
820
+ my_sessions: rawGroups.sessions.filter(
821
+ (item) => item.kind === "session" && item.scope === "my_sessions"
822
+ ).length,
823
+ collab_sessions: rawGroups.sessions.filter(
824
+ (item) => item.kind === "session" && item.scope === "collab_sessions"
825
+ ).length,
669
826
  issues: rawGroups.issues.length
670
827
  };
671
828
  }
@@ -718,12 +875,8 @@ function logAgentMentionLifecycleDiagnostic(payload) {
718
875
  );
719
876
  }
720
877
  }
721
- function normalizeSessionMentionItemsForMySessions(input) {
722
- return input.items.filter((item) => item.kind === "session").filter(
723
- (item) => input.currentUserId ? item.scope === "my_sessions" : true
724
- ).map(
725
- (item) => item.scope === "my_sessions" ? item : { ...item, scope: "my_sessions" }
726
- );
878
+ function normalizeSessionMentionItems(input) {
879
+ return input.items.filter((item) => item.kind === "session");
727
880
  }
728
881
  function providerItemToAgentMentionItem(input) {
729
882
  const label = compactText4(input.label);
@@ -851,6 +1004,7 @@ function providerItemToAgentMentionItem(input) {
851
1004
  initiatorName: "",
852
1005
  agentName,
853
1006
  agentIconUrl: presentation.agentIconUrl?.trim() || presentation.iconUrl?.trim() || void 0,
1007
+ ...scope.agentTargetId ? { agentTargetId: scope.agentTargetId } : {},
854
1008
  status: presentation.status?.trim() || void 0,
855
1009
  inputPreview: description || void 0,
856
1010
  summaryPreview
@@ -899,6 +1053,51 @@ function writeBrowseCacheEntry(cacheKey, entry) {
899
1053
  sharedAgentMentionBrowseCache.delete(oldestKey);
900
1054
  }
901
1055
  }
1056
+ function mergeAgentMentionBrowseIssueGroupPage(input) {
1057
+ const entry = sharedAgentMentionBrowseCache.get(input.cacheKey);
1058
+ if (!entry?.issueTopicGroups) {
1059
+ return;
1060
+ }
1061
+ const groupIndex = entry.issueTopicGroups.findIndex(
1062
+ (group) => group.id === input.group.id
1063
+ );
1064
+ if (groupIndex < 0) {
1065
+ return;
1066
+ }
1067
+ const previous = entry.issueTopicGroups[groupIndex];
1068
+ if (!previous) {
1069
+ return;
1070
+ }
1071
+ const seen = new Set(
1072
+ previous.items.filter((item) => item.kind === "workspace-issue").map((item) => item.targetId)
1073
+ );
1074
+ const appended = input.group.items.filter((item) => {
1075
+ if (item.kind !== "workspace-issue") {
1076
+ return true;
1077
+ }
1078
+ if (seen.has(item.targetId)) {
1079
+ return false;
1080
+ }
1081
+ seen.add(item.targetId);
1082
+ return true;
1083
+ });
1084
+ const mergedItems = [...previous.items, ...appended];
1085
+ const groups = entry.issueTopicGroups.map(
1086
+ (group, index) => index === groupIndex ? {
1087
+ ...previous,
1088
+ items: mergedItems,
1089
+ totalCount: Math.max(input.group.totalCount, mergedItems.length),
1090
+ nextPageToken: input.group.nextPageToken,
1091
+ loadMoreStatus: "idle",
1092
+ loadMoreError: null
1093
+ } : group
1094
+ );
1095
+ writeBrowseCacheEntry(input.cacheKey, {
1096
+ ...entry,
1097
+ issueTopicGroups: groups,
1098
+ cachedAt: input.cachedAt
1099
+ });
1100
+ }
902
1101
  function scheduleAgentMentionIdleTask(task) {
903
1102
  const scope = globalThis;
904
1103
  if (typeof scope.requestIdleCallback === "function") {
@@ -910,49 +1109,113 @@ function scheduleAgentMentionIdleTask(task) {
910
1109
  }
911
1110
  function resetAgentMentionSearchBrowseCacheForTests() {
912
1111
  sharedAgentMentionBrowseCache.clear();
1112
+ for (const fetch of sharedAgentMentionBrowseFetches.values()) {
1113
+ fetch.abortController.abort();
1114
+ }
913
1115
  sharedAgentMentionBrowseFetches.clear();
914
1116
  }
915
1117
  globalThis.__tuttiResetAgentMentionSearchBrowseCacheForTests = resetAgentMentionSearchBrowseCacheForTests;
916
1118
  async function loadAgentMentionBrowseFetchResult(input) {
917
1119
  const { cacheKey, reason } = input;
918
1120
  const browseInput = input.input;
919
- const existingFetch = sharedAgentMentionBrowseFetches.get(cacheKey);
920
- if (existingFetch) {
1121
+ let sharedFetch = sharedAgentMentionBrowseFetches.get(cacheKey);
1122
+ if (sharedFetch) {
921
1123
  input.logLifecycle("browse.fetch.dedupe", {
922
1124
  filter: browseInput.filter,
923
1125
  reason,
924
1126
  workspaceId: browseInput.workspaceId
925
1127
  });
926
- return existingFetch;
927
- }
928
- const startedAt = input.diagnosticNow();
929
- input.logLifecycle("browse.fetch.start", {
930
- filter: browseInput.filter,
931
- providerIds: input.providerIds,
932
- reason,
933
- workspaceId: browseInput.workspaceId
934
- });
935
- const fetchPromise = input.fetchBrowseResult().then((result) => {
936
- writeBrowseCacheEntry(cacheKey, {
937
- ...result,
938
- cachedAt: input.diagnosticNow()
939
- });
940
- input.logLifecycle("browse.fetch.success", {
941
- durationMs: elapsedDiagnosticMs(input.diagnosticNow(), startedAt),
1128
+ } else {
1129
+ const startedAt = input.diagnosticNow();
1130
+ input.logLifecycle("browse.fetch.start", {
942
1131
  filter: browseInput.filter,
943
- itemCount: rawGroupItemCount(result.rawGroups),
944
- providerResults: providerDiagnosticsSummary(result.providerDiagnostics),
1132
+ providerIds: input.providerIds,
945
1133
  reason,
946
1134
  workspaceId: browseInput.workspaceId
947
1135
  });
948
- return result;
949
- }).finally(() => {
950
- if (sharedAgentMentionBrowseFetches.get(cacheKey) === fetchPromise) {
951
- sharedAgentMentionBrowseFetches.delete(cacheKey);
1136
+ const abortController = new AbortController();
1137
+ sharedFetch = {
1138
+ abortController,
1139
+ consumers: /* @__PURE__ */ new Set(),
1140
+ promise: null,
1141
+ settled: false
1142
+ };
1143
+ const entry = sharedFetch;
1144
+ entry.promise = input.fetchBrowseResult(abortController.signal).then((result) => {
1145
+ if (abortController.signal.aborted) {
1146
+ const error = new Error("Mention browse request aborted");
1147
+ error.name = "AbortError";
1148
+ throw error;
1149
+ }
1150
+ writeBrowseCacheEntry(cacheKey, {
1151
+ ...result,
1152
+ cachedAt: input.diagnosticNow()
1153
+ });
1154
+ input.logLifecycle("browse.fetch.success", {
1155
+ durationMs: elapsedDiagnosticMs(input.diagnosticNow(), startedAt),
1156
+ filter: browseInput.filter,
1157
+ itemCount: rawGroupItemCount(result.rawGroups),
1158
+ providerResults: providerDiagnosticsSummary(
1159
+ result.providerDiagnostics
1160
+ ),
1161
+ reason,
1162
+ workspaceId: browseInput.workspaceId
1163
+ });
1164
+ return result;
1165
+ }).finally(() => {
1166
+ entry.settled = true;
1167
+ if (sharedAgentMentionBrowseFetches.get(cacheKey) === entry) {
1168
+ sharedAgentMentionBrowseFetches.delete(cacheKey);
1169
+ }
1170
+ });
1171
+ sharedAgentMentionBrowseFetches.set(cacheKey, entry);
1172
+ }
1173
+ return consumeSharedBrowseFetch({
1174
+ abortSignal: input.abortSignal,
1175
+ cacheKey,
1176
+ sharedFetch
1177
+ });
1178
+ }
1179
+ function consumeSharedBrowseFetch(input) {
1180
+ const consumer = Symbol(input.cacheKey);
1181
+ input.sharedFetch.consumers.add(consumer);
1182
+ const sharedPromise = input.sharedFetch.promise;
1183
+ if (!sharedPromise) {
1184
+ input.sharedFetch.consumers.delete(consumer);
1185
+ return Promise.reject(new Error("Mention browse request was not started"));
1186
+ }
1187
+ return new Promise((resolve, reject) => {
1188
+ let finished = false;
1189
+ const finish = (settle, abortWhenUnused) => {
1190
+ if (finished) {
1191
+ return;
1192
+ }
1193
+ finished = true;
1194
+ input.abortSignal?.removeEventListener("abort", onAbort);
1195
+ input.sharedFetch.consumers.delete(consumer);
1196
+ if (abortWhenUnused && !input.sharedFetch.settled && input.sharedFetch.consumers.size === 0) {
1197
+ if (sharedAgentMentionBrowseFetches.get(input.cacheKey) === input.sharedFetch) {
1198
+ sharedAgentMentionBrowseFetches.delete(input.cacheKey);
1199
+ }
1200
+ input.sharedFetch.abortController.abort();
1201
+ }
1202
+ settle();
1203
+ };
1204
+ const onAbort = () => {
1205
+ const error = new Error("Mention browse request aborted");
1206
+ error.name = "AbortError";
1207
+ finish(() => reject(error), true);
1208
+ };
1209
+ if (input.abortSignal?.aborted) {
1210
+ onAbort();
1211
+ return;
952
1212
  }
1213
+ input.abortSignal?.addEventListener("abort", onAbort, { once: true });
1214
+ sharedPromise.then(
1215
+ (result) => finish(() => resolve(result), false),
1216
+ (error) => finish(() => reject(error), false)
1217
+ );
953
1218
  });
954
- sharedAgentMentionBrowseFetches.set(cacheKey, fetchPromise);
955
- return fetchPromise;
956
1219
  }
957
1220
  function readAgentMentionBrowseCache(input) {
958
1221
  const entry = sharedAgentMentionBrowseCache.get(input.cacheKey);
@@ -1042,6 +1305,7 @@ async function queryAgentMentionProviderWithDiagnostics(input) {
1042
1305
  const startedAt = input.diagnosticNow();
1043
1306
  try {
1044
1307
  const { result, timedOut } = await runAgentMentionProviderQuery({
1308
+ abortSignal: input.abortSignal,
1045
1309
  fallback: input.fallback,
1046
1310
  providerTimeoutMs: input.providerTimeoutMs,
1047
1311
  query: input.query
@@ -1055,8 +1319,16 @@ async function queryAgentMentionProviderWithDiagnostics(input) {
1055
1319
  resultCount: input.resultCount(result),
1056
1320
  status: timedOut ? "timeout" : "success"
1057
1321
  });
1322
+ if (timedOut && input.throwOnTimeout) {
1323
+ const error = new Error("Mention provider query timed out.");
1324
+ error.name = "TimeoutError";
1325
+ throw error;
1326
+ }
1058
1327
  return result;
1059
1328
  } catch (error) {
1329
+ if (error instanceof Error && error.name === "TimeoutError" && input.diagnostics.at(-1)?.providerId === input.providerId && input.diagnostics.at(-1)?.status === "timeout") {
1330
+ throw error;
1331
+ }
1060
1332
  input.diagnostics.push({
1061
1333
  durationMs: elapsedAgentMentionSearchDiagnosticMs(
1062
1334
  input.diagnosticNow(),
@@ -1102,6 +1374,14 @@ function providerDiagnosticOrder(providerId) {
1102
1374
  }
1103
1375
  async function runAgentMentionProviderQuery(input) {
1104
1376
  const abortController = new AbortController();
1377
+ const abortFromParent = () => abortController.abort();
1378
+ if (input.abortSignal?.aborted) {
1379
+ abortController.abort();
1380
+ } else {
1381
+ input.abortSignal?.addEventListener("abort", abortFromParent, {
1382
+ once: true
1383
+ });
1384
+ }
1105
1385
  let timedOut = false;
1106
1386
  const queryPromise = Promise.resolve().then(
1107
1387
  () => input.query(abortController.signal)
@@ -1116,7 +1396,11 @@ async function runAgentMentionProviderQuery(input) {
1116
1396
  }
1117
1397
  );
1118
1398
  if (input.providerTimeoutMs <= 0 || !Number.isFinite(input.providerTimeoutMs)) {
1119
- return queryResultPromise;
1399
+ try {
1400
+ return await queryResultPromise;
1401
+ } finally {
1402
+ input.abortSignal?.removeEventListener("abort", abortFromParent);
1403
+ }
1120
1404
  }
1121
1405
  let timeout = null;
1122
1406
  const timeoutPromise = new Promise(
@@ -1131,6 +1415,7 @@ async function runAgentMentionProviderQuery(input) {
1131
1415
  try {
1132
1416
  return await Promise.race([queryResultPromise, timeoutPromise]);
1133
1417
  } finally {
1418
+ input.abortSignal?.removeEventListener("abort", abortFromParent);
1134
1419
  if (timeout !== null) {
1135
1420
  clearTimeout(timeout);
1136
1421
  }
@@ -1178,7 +1463,8 @@ async function fetchAgentMentionFilterResult(input) {
1178
1463
  return {
1179
1464
  providerDiagnostics,
1180
1465
  rawGroups,
1181
- totalCounts: totalCountsFromRawGroups(rawGroups)
1466
+ totalCounts: totalCountsFromRawGroups(rawGroups),
1467
+ issueTopicGroups: null
1182
1468
  };
1183
1469
  }
1184
1470
  case "session": {
@@ -1187,24 +1473,27 @@ async function fetchAgentMentionFilterResult(input) {
1187
1473
  workspaceId: input.workspaceId,
1188
1474
  currentUserId: input.currentUserId,
1189
1475
  query: input.query,
1190
- limit: DEFAULT_SESSION_LIMIT,
1476
+ // A provenance-aware host owns a room-scoped directory snapshot and
1477
+ // grouping must see that complete snapshot. Legacy providers retain
1478
+ // the bounded query contract.
1479
+ limit: input.provenanceCatalog?.enabledDimensions.includes("agent") ? void 0 : DEFAULT_SESSION_LIMIT,
1191
1480
  sessionCwd: input.sessionCwd,
1192
1481
  diagnostics: providerDiagnostics,
1193
1482
  provenanceFilter: input.provenanceFilter
1194
1483
  });
1195
1484
  const rawGroups = emptyAgentMentionRawGroups();
1196
- rawGroups.my_sessions = normalizeSessionMentionItemsForMySessions({
1197
- currentUserId: input.currentUserId,
1485
+ rawGroups.sessions = normalizeSessionMentionItems({
1198
1486
  items: sessionItems
1199
1487
  });
1200
1488
  return {
1201
1489
  providerDiagnostics,
1202
1490
  rawGroups,
1203
- totalCounts: totalCountsFromRawGroups(rawGroups)
1491
+ totalCounts: totalCountsFromRawGroups(rawGroups),
1492
+ issueTopicGroups: null
1204
1493
  };
1205
1494
  }
1206
1495
  case "issue": {
1207
- const issueItems = provenanceFilterActive ? [] : await input.queryProviderMentionItemsById({
1496
+ const queryInput = {
1208
1497
  providerId: WORKSPACE_ISSUE_PROVIDER_ID,
1209
1498
  workspaceId: input.workspaceId,
1210
1499
  currentUserId: input.currentUserId,
@@ -1213,7 +1502,9 @@ async function fetchAgentMentionFilterResult(input) {
1213
1502
  sessionCwd: input.sessionCwd,
1214
1503
  diagnostics: providerDiagnostics,
1215
1504
  provenanceFilter: input.provenanceFilter
1216
- });
1505
+ };
1506
+ const issueTopicGroups = provenanceFilterActive ? [] : input.queryProviderMentionGroupsById ? await input.queryProviderMentionGroupsById(queryInput) : null;
1507
+ const issueItems = provenanceFilterActive ? [] : issueTopicGroups === null ? await input.queryProviderMentionItemsById(queryInput) : [];
1217
1508
  const rawGroups = emptyAgentMentionRawGroups();
1218
1509
  rawGroups.issues = issueItems.filter(
1219
1510
  (item) => item.kind === "workspace-issue"
@@ -1221,7 +1512,8 @@ async function fetchAgentMentionFilterResult(input) {
1221
1512
  return {
1222
1513
  providerDiagnostics,
1223
1514
  rawGroups,
1224
- totalCounts: totalCountsFromRawGroups(rawGroups)
1515
+ totalCounts: totalCountsFromRawGroups(rawGroups),
1516
+ issueTopicGroups
1225
1517
  };
1226
1518
  }
1227
1519
  case "agent": {
@@ -1241,7 +1533,8 @@ async function fetchAgentMentionFilterResult(input) {
1241
1533
  return {
1242
1534
  providerDiagnostics,
1243
1535
  rawGroups,
1244
- totalCounts: totalCountsFromRawGroups(rawGroups)
1536
+ totalCounts: totalCountsFromRawGroups(rawGroups),
1537
+ issueTopicGroups: null
1245
1538
  };
1246
1539
  }
1247
1540
  case "app": {
@@ -1259,7 +1552,8 @@ async function fetchAgentMentionFilterResult(input) {
1259
1552
  return {
1260
1553
  providerDiagnostics,
1261
1554
  rawGroups,
1262
- totalCounts: totalCountsFromRawGroups(rawGroups)
1555
+ totalCounts: totalCountsFromRawGroups(rawGroups),
1556
+ issueTopicGroups: null
1263
1557
  };
1264
1558
  }
1265
1559
  }
@@ -1283,8 +1577,111 @@ async function queryAgentMentionProviderItems(input) {
1283
1577
  if (input.abortSignal.aborted) {
1284
1578
  return [];
1285
1579
  }
1580
+ return mapProviderItemsToAgentMentionItems({
1581
+ ...input,
1582
+ items
1583
+ });
1584
+ }
1585
+ async function queryAgentMentionProviderGroups(input) {
1586
+ if (!input.provider.queryGroups) {
1587
+ return null;
1588
+ }
1589
+ const result = await input.provider.queryGroups({
1590
+ keyword: input.query,
1591
+ maxResults: input.limit,
1592
+ abortSignal: input.abortSignal,
1593
+ trigger: "@",
1594
+ context: {
1595
+ metadata: {
1596
+ currentUserId: input.currentUserId,
1597
+ sessionCwd: input.sessionCwd || void 0,
1598
+ target: "agent-gui",
1599
+ workspaceId: input.workspaceId,
1600
+ referenceProvenanceFilter: input.provenanceFilter ?? void 0
1601
+ }
1602
+ }
1603
+ });
1604
+ if (input.abortSignal.aborted) {
1605
+ return [];
1606
+ }
1607
+ return Promise.all(
1608
+ result.groups.map(async (group) => {
1609
+ const items = await mapProviderItemsToAgentMentionItems({
1610
+ ...input,
1611
+ items: group.items
1612
+ });
1613
+ const uniqueItems = dedupeWorkspaceIssueMentionItems(items);
1614
+ return {
1615
+ id: agentMentionIssueTopicGroupId(group.id),
1616
+ providerGroupId: group.id,
1617
+ label: group.label,
1618
+ items: uniqueItems,
1619
+ totalCount: Math.max(group.totalCount, uniqueItems.length),
1620
+ nextPageToken: group.nextCursor ?? null,
1621
+ loadMoreStatus: "idle",
1622
+ loadMoreError: null
1623
+ };
1624
+ })
1625
+ );
1626
+ }
1627
+ async function queryAgentMentionProviderGroupPage(input) {
1628
+ if (!input.provider.queryGroupPage) {
1629
+ throw new Error("Mention provider does not support grouped pagination.");
1630
+ }
1631
+ const group = await input.provider.queryGroupPage({
1632
+ groupId: input.providerGroupId,
1633
+ cursor: input.cursor,
1634
+ pageSize: input.pageSize,
1635
+ keyword: input.query,
1636
+ maxResults: input.pageSize,
1637
+ abortSignal: input.abortSignal,
1638
+ trigger: "@",
1639
+ context: {
1640
+ metadata: {
1641
+ currentUserId: input.currentUserId,
1642
+ sessionCwd: input.sessionCwd || void 0,
1643
+ target: "agent-gui",
1644
+ workspaceId: input.workspaceId,
1645
+ referenceProvenanceFilter: input.provenanceFilter ?? void 0
1646
+ }
1647
+ }
1648
+ });
1649
+ const items = await mapProviderItemsToAgentMentionItems({
1650
+ ...input,
1651
+ provider: input.provider,
1652
+ items: group.items
1653
+ });
1654
+ const uniqueItems = dedupeWorkspaceIssueMentionItems(items);
1655
+ return {
1656
+ id: agentMentionIssueTopicGroupId(input.providerGroupId),
1657
+ providerGroupId: input.providerGroupId,
1658
+ label: group.label,
1659
+ items: uniqueItems,
1660
+ totalCount: Math.max(group.totalCount, uniqueItems.length),
1661
+ nextPageToken: group.nextCursor ?? null,
1662
+ loadMoreStatus: "idle",
1663
+ loadMoreError: null
1664
+ };
1665
+ }
1666
+ function agentMentionIssueTopicGroupId(topicId) {
1667
+ return `issue-topic:${encodeURIComponent(topicId)}`;
1668
+ }
1669
+ function dedupeWorkspaceIssueMentionItems(items) {
1670
+ const issueIds = /* @__PURE__ */ new Set();
1671
+ return items.filter((item) => {
1672
+ if (item.kind !== "workspace-issue") {
1673
+ return true;
1674
+ }
1675
+ if (issueIds.has(item.targetId)) {
1676
+ return false;
1677
+ }
1678
+ issueIds.add(item.targetId);
1679
+ return true;
1680
+ });
1681
+ }
1682
+ async function mapProviderItemsToAgentMentionItems(input) {
1286
1683
  const mentionItems = await Promise.all(
1287
- items.map(async (item) => {
1684
+ input.items.map(async (item) => {
1288
1685
  const mentionItem = providerItemToAgentMentionItem({
1289
1686
  currentUserId: input.currentUserId,
1290
1687
  insertResult: input.provider.toInsertResult(item),
@@ -1351,6 +1748,7 @@ var AgentMentionSearchControllerBase = class {
1351
1748
  preloadCancel = null;
1352
1749
  pendingPreloadKey = null;
1353
1750
  requestId = 0;
1751
+ activeRequestAbortController = null;
1354
1752
  disposed = false;
1355
1753
  activeWorkspaceId = "";
1356
1754
  currentUserId = "";
@@ -1358,10 +1756,12 @@ var AgentMentionSearchControllerBase = class {
1358
1756
  currentQuery = "";
1359
1757
  currentSessionCwd = "";
1360
1758
  currentProvenanceFilter = null;
1759
+ currentProvenanceCatalog = null;
1361
1760
  currentFileSearchLimit;
1362
1761
  currentIssueSearchLimit;
1363
1762
  agentGeneratedBrowsePath = null;
1364
1763
  rawGroups = emptyAgentMentionRawGroups();
1764
+ issueTopicGroups = null;
1365
1765
  state = {
1366
1766
  status: "idle",
1367
1767
  query: "",
@@ -1437,26 +1837,32 @@ var AgentMentionSearchControllerBase = class {
1437
1837
  this.resetTotalCounts();
1438
1838
  this.emitBrowseState("loading");
1439
1839
  }
1840
+ const abortSignal = this.beginActiveRequest();
1440
1841
  void this.runBrowseSearch({
1441
1842
  workspaceId: this.activeWorkspaceId,
1442
1843
  currentUserId: this.currentUserId,
1443
1844
  requestId,
1444
1845
  filter,
1445
- sessionCwd: this.currentSessionCwd
1846
+ sessionCwd: this.currentSessionCwd,
1847
+ abortSignal
1446
1848
  });
1447
1849
  }
1448
1850
  async runSearch(input) {
1449
1851
  const startedAt = this.diagnosticNow();
1450
1852
  let providerDiagnostics = [];
1451
1853
  try {
1452
- const result = await this.fetchFilterResult({
1453
- workspaceId: input.workspaceId,
1454
- currentUserId: input.currentUserId,
1455
- query: input.query,
1456
- filter: input.filter,
1457
- sessionCwd: this.currentSessionCwd,
1458
- includeAgentGeneratedFiles: false
1459
- });
1854
+ const result = await this.fetchFilterResult(
1855
+ {
1856
+ workspaceId: input.workspaceId,
1857
+ currentUserId: input.currentUserId,
1858
+ query: input.query,
1859
+ filter: input.filter,
1860
+ sessionCwd: input.sessionCwd,
1861
+ includeAgentGeneratedFiles: false
1862
+ },
1863
+ input.provenanceFilter,
1864
+ input.abortSignal
1865
+ );
1460
1866
  providerDiagnostics = result.providerDiagnostics;
1461
1867
  if (!this.canApply(
1462
1868
  input.requestId,
@@ -1525,12 +1931,16 @@ var AgentMentionSearchControllerBase = class {
1525
1931
  let providerDiagnostics = [];
1526
1932
  const provenanceFilter = this.currentProvenanceFilter;
1527
1933
  const cacheKey = this.browseCacheKey(input, provenanceFilter);
1934
+ const issueTopicGroupsAtStart = cloneAgentMentionIssueTopicGroups(
1935
+ this.issueTopicGroups
1936
+ );
1528
1937
  try {
1529
1938
  const result = await this.loadBrowseFetchResult(
1530
1939
  input,
1531
1940
  cacheKey,
1532
1941
  "open",
1533
- provenanceFilter
1942
+ provenanceFilter,
1943
+ input.abortSignal
1534
1944
  );
1535
1945
  providerDiagnostics = result.providerDiagnostics;
1536
1946
  if (!this.canApply(input.requestId, input.workspaceId, "", input.filter)) {
@@ -1542,7 +1952,19 @@ var AgentMentionSearchControllerBase = class {
1542
1952
  });
1543
1953
  return;
1544
1954
  }
1545
- this.applyBrowseFetchResult(result);
1955
+ const paginationChanges = issueTopicPaginationChanges(
1956
+ issueTopicGroupsAtStart,
1957
+ this.issueTopicGroups
1958
+ );
1959
+ for (const group of paginationChanges) {
1960
+ mergeAgentMentionBrowseIssueGroupPage({
1961
+ cacheKey,
1962
+ group,
1963
+ cachedAt: this.diagnosticNow()
1964
+ });
1965
+ }
1966
+ const resultToApply = paginationChanges.length > 0 ? this.readBrowseCache(cacheKey).entry ?? result : result;
1967
+ this.applyBrowseFetchResult(resultToApply);
1546
1968
  const groups = this.groupsFromRawGroups();
1547
1969
  this.setState({
1548
1970
  status: "ready",
@@ -1591,18 +2013,22 @@ var AgentMentionSearchControllerBase = class {
1591
2013
  });
1592
2014
  }
1593
2015
  }
1594
- async fetchBrowseResult(input, provenanceFilter = this.currentProvenanceFilter) {
2016
+ async fetchBrowseResult(input, provenanceFilter = this.currentProvenanceFilter, abortSignal) {
1595
2017
  return this.fetchFilterResult(
1596
2018
  {
1597
2019
  ...input,
1598
2020
  query: "",
1599
2021
  includeAgentGeneratedFiles: input.filter === "file"
1600
2022
  },
1601
- provenanceFilter
2023
+ provenanceFilter,
2024
+ abortSignal
1602
2025
  );
1603
2026
  }
1604
2027
  applyBrowseFetchResult(result) {
1605
2028
  this.rawGroups = cloneAgentMentionRawGroups(result.rawGroups);
2029
+ this.issueTopicGroups = cloneAgentMentionIssueTopicGroups(
2030
+ result.issueTopicGroups
2031
+ );
1606
2032
  this.resetTotalCounts();
1607
2033
  for (const [groupId, count] of Object.entries(result.totalCounts)) {
1608
2034
  this.totalCounts[groupId] = count;
@@ -1629,6 +2055,7 @@ var AgentMentionSearchControllerBase = class {
1629
2055
  const provider = this.contextMentionProviders.get(input.providerId);
1630
2056
  return queryAgentMentionProviderWithDiagnostics({
1631
2057
  diagnosticNow: this.diagnosticNow,
2058
+ abortSignal: input.abortSignal,
1632
2059
  diagnostics: input.diagnostics,
1633
2060
  fallback: [],
1634
2061
  providerId: input.providerId,
@@ -1646,6 +2073,32 @@ var AgentMentionSearchControllerBase = class {
1646
2073
  resultCount: (result) => result.length
1647
2074
  });
1648
2075
  }
2076
+ async queryProviderMentionGroupsById(input) {
2077
+ const provider = this.contextMentionProviders.get(input.providerId);
2078
+ if (!provider?.queryGroups) {
2079
+ return null;
2080
+ }
2081
+ return queryAgentMentionProviderWithDiagnostics({
2082
+ abortSignal: input.abortSignal,
2083
+ diagnosticNow: this.diagnosticNow,
2084
+ diagnostics: input.diagnostics,
2085
+ fallback: [],
2086
+ providerId: input.providerId,
2087
+ providerTimeoutMs: this.providerTimeoutMs,
2088
+ throwOnTimeout: true,
2089
+ query: (abortSignal) => queryAgentMentionProviderGroups({
2090
+ provider,
2091
+ workspaceId: input.workspaceId,
2092
+ currentUserId: input.currentUserId,
2093
+ query: input.query,
2094
+ limit: input.limit,
2095
+ sessionCwd: input.sessionCwd ?? this.currentSessionCwd,
2096
+ abortSignal,
2097
+ provenanceFilter: input.provenanceFilter
2098
+ }).then((groups) => groups ?? []),
2099
+ resultCount: (groups) => groups.reduce((count, group) => count + group.items.length, 0)
2100
+ });
2101
+ }
1649
2102
  logSearchDiagnostic(input) {
1650
2103
  emitAgentMentionSearchDiagnostic({
1651
2104
  debounceMs: this.debounceMs,
@@ -1686,6 +2139,9 @@ var AgentMentionSearchControllerBase = class {
1686
2139
  }
1687
2140
  }
1688
2141
  resetExpandedCounts() {
2142
+ for (const groupId of Object.keys(this.expandedCounts)) {
2143
+ delete this.expandedCounts[groupId];
2144
+ }
1689
2145
  for (const groupId of [
1690
2146
  "files",
1691
2147
  "opened_files",
@@ -1708,6 +2164,7 @@ var AgentMentionSearchControllerBase = class {
1708
2164
  }
1709
2165
  resetRawGroups() {
1710
2166
  this.rawGroups = emptyAgentMentionRawGroups();
2167
+ this.issueTopicGroups = null;
1711
2168
  this.resetTotalCounts();
1712
2169
  }
1713
2170
  resetAgentGeneratedBrowsePath() {
@@ -1741,7 +2198,10 @@ var AgentMentionSearchControllerBase = class {
1741
2198
  currentQuery: this.currentQuery,
1742
2199
  expandedCounts: this.expandedCounts,
1743
2200
  rawGroups: this.rawGroups,
1744
- totalCounts: this.totalCounts
2201
+ totalCounts: this.totalCounts,
2202
+ issueTopicGroups: this.issueTopicGroups,
2203
+ provenanceCatalog: this.currentProvenanceCatalog,
2204
+ provenanceFilter: this.currentProvenanceFilter
1745
2205
  });
1746
2206
  }
1747
2207
  browseCacheKey(input, provenanceFilter = this.currentProvenanceFilter) {
@@ -1760,32 +2220,57 @@ var AgentMentionSearchControllerBase = class {
1760
2220
  diagnosticNow: this.diagnosticNow
1761
2221
  });
1762
2222
  }
1763
- loadBrowseFetchResult(input, cacheKey, reason, provenanceFilter = this.currentProvenanceFilter) {
2223
+ loadBrowseFetchResult(input, cacheKey, reason, provenanceFilter = this.currentProvenanceFilter, abortSignal) {
1764
2224
  return loadAgentMentionBrowseFetchResult({
1765
2225
  input,
1766
2226
  cacheKey,
1767
2227
  reason,
2228
+ abortSignal,
1768
2229
  diagnosticNow: this.diagnosticNow,
1769
2230
  providerIds: this.providerIdsForDiagnostics(),
1770
- fetchBrowseResult: () => this.fetchBrowseResult(input, provenanceFilter),
2231
+ fetchBrowseResult: (sharedAbortSignal) => this.fetchBrowseResult(input, provenanceFilter, sharedAbortSignal),
1771
2232
  logLifecycle: (event, details) => this.logLifecycle(event, details)
1772
2233
  });
1773
2234
  }
1774
- fetchFilterResult(input, provenanceFilter = this.currentProvenanceFilter) {
2235
+ fetchFilterResult(input, provenanceFilter = this.currentProvenanceFilter, abortSignal) {
1775
2236
  return fetchAgentMentionFilterResult({
1776
2237
  ...input,
1777
2238
  fileLimit: this.fileLimit,
1778
2239
  currentFileSearchLimit: this.currentFileSearchLimit,
1779
2240
  currentIssueSearchLimit: this.currentIssueSearchLimit,
2241
+ provenanceCatalog: this.currentProvenanceCatalog,
1780
2242
  provenanceFilter,
1781
- queryProviderMentionItemsById: (queryInput) => this.queryProviderMentionItemsById(queryInput)
2243
+ queryProviderMentionGroupsById: (queryInput) => this.queryProviderMentionGroupsById({ ...queryInput, abortSignal }),
2244
+ queryProviderMentionItemsById: (queryInput) => this.queryProviderMentionItemsById({ ...queryInput, abortSignal })
1782
2245
  });
1783
2246
  }
2247
+ beginActiveRequest() {
2248
+ this.abortActiveRequest();
2249
+ const controller = new AbortController();
2250
+ this.activeRequestAbortController = controller;
2251
+ return controller.signal;
2252
+ }
2253
+ abortActiveRequest() {
2254
+ this.activeRequestAbortController?.abort();
2255
+ this.activeRequestAbortController = null;
2256
+ }
1784
2257
  };
1785
2258
 
1786
2259
  // agent-gui/agentGuiNode/AgentMentionSearchController.ts
1787
2260
  import { referenceProvenanceFilterCacheKey as referenceProvenanceFilterCacheKey2 } from "@tutti-os/workspace-file-reference/core";
1788
2261
  var AgentMentionSearchController = class extends AgentMentionSearchControllerBase {
2262
+ issueLoadMoreRequests = /* @__PURE__ */ new Map();
2263
+ setProvenanceCatalog(catalog) {
2264
+ if (this.currentProvenanceCatalog === catalog) return;
2265
+ this.currentProvenanceCatalog = catalog;
2266
+ if (this.currentFilter !== "session" || this.state.status !== "ready" && this.state.status !== "loading") {
2267
+ return;
2268
+ }
2269
+ this.setState({
2270
+ ...this.state,
2271
+ groups: this.groupsFromRawGroups()
2272
+ });
2273
+ }
1789
2274
  setProvenanceFilter(filter) {
1790
2275
  const previousKey = this.currentProvenanceFilter ? referenceProvenanceFilterCacheKey2(this.currentProvenanceFilter) : "disabled";
1791
2276
  const nextKey = filter ? referenceProvenanceFilterCacheKey2(filter) : "disabled";
@@ -1815,6 +2300,8 @@ var AgentMentionSearchController = class extends AgentMentionSearchControllerBas
1815
2300
  this.currentSessionCwd = input.sessionCwd?.trim() ?? "";
1816
2301
  this.currentQuery = normalizeQuery(input.query);
1817
2302
  this.clearTimer();
2303
+ this.abortActiveRequest();
2304
+ this.cancelIssueLoadMoreRequests();
1818
2305
  const requestId = ++this.requestId;
1819
2306
  this.resetAgentGeneratedBrowsePath();
1820
2307
  this.resetExpandedCounts();
@@ -1845,13 +2332,17 @@ var AgentMentionSearchController = class extends AgentMentionSearchControllerBas
1845
2332
  groups: this.groupsFromRawGroups(),
1846
2333
  error: null
1847
2334
  });
2335
+ const abortSignal = this.beginActiveRequest();
1848
2336
  this.timer = this.scheduler.schedule(this.debounceMs, () => {
1849
2337
  void this.runSearch({
1850
2338
  workspaceId: this.activeWorkspaceId,
1851
2339
  currentUserId: this.currentUserId,
1852
2340
  query: this.currentQuery,
1853
2341
  requestId,
1854
- filter: this.currentFilter
2342
+ filter: this.currentFilter,
2343
+ provenanceFilter: this.currentProvenanceFilter,
2344
+ sessionCwd: this.currentSessionCwd,
2345
+ abortSignal
1855
2346
  });
1856
2347
  });
1857
2348
  }
@@ -1861,6 +2352,8 @@ var AgentMentionSearchController = class extends AgentMentionSearchControllerBas
1861
2352
  }
1862
2353
  this.currentFilter = filter;
1863
2354
  this.clearTimer();
2355
+ this.abortActiveRequest();
2356
+ this.cancelIssueLoadMoreRequests();
1864
2357
  const requestId = ++this.requestId;
1865
2358
  this.resetAgentGeneratedBrowsePath();
1866
2359
  this.resetExpandedCounts();
@@ -1891,12 +2384,16 @@ var AgentMentionSearchController = class extends AgentMentionSearchControllerBas
1891
2384
  groups: this.groupsFromRawGroups(),
1892
2385
  error: null
1893
2386
  });
2387
+ const abortSignal = this.beginActiveRequest();
1894
2388
  void this.runSearch({
1895
2389
  workspaceId: this.activeWorkspaceId,
1896
2390
  currentUserId: this.currentUserId,
1897
2391
  query: this.currentQuery,
1898
2392
  requestId,
1899
- filter
2393
+ filter,
2394
+ provenanceFilter: this.currentProvenanceFilter,
2395
+ sessionCwd: this.currentSessionCwd,
2396
+ abortSignal
1900
2397
  });
1901
2398
  }
1902
2399
  preloadBrowse(input) {
@@ -2047,6 +2544,10 @@ var AgentMentionSearchController = class extends AgentMentionSearchControllerBas
2047
2544
  return true;
2048
2545
  }
2049
2546
  expandGroup(groupId) {
2547
+ if (groupId.startsWith("issue-topic:")) {
2548
+ this.loadMoreIssueTopic(groupId);
2549
+ return;
2550
+ }
2050
2551
  const pageSize = mentionGroupPageSize(this.currentFilter, groupId);
2051
2552
  const current = this.expandedCounts[groupId] ?? pageSize;
2052
2553
  this.expandedCounts[groupId] = current + pageSize;
@@ -2072,6 +2573,7 @@ var AgentMentionSearchController = class extends AgentMentionSearchControllerBas
2072
2573
  }
2073
2574
  if (needsMoreFiles || needsMoreIssues) {
2074
2575
  this.clearTimer();
2576
+ this.abortActiveRequest();
2075
2577
  const requestId = ++this.requestId;
2076
2578
  this.setState({
2077
2579
  status: "loading",
@@ -2082,12 +2584,16 @@ var AgentMentionSearchController = class extends AgentMentionSearchControllerBas
2082
2584
  groups: this.groupsFromRawGroups(),
2083
2585
  error: null
2084
2586
  });
2587
+ const abortSignal = this.beginActiveRequest();
2085
2588
  void this.runSearch({
2086
2589
  workspaceId: this.activeWorkspaceId,
2087
2590
  currentUserId: this.currentUserId,
2088
2591
  query: this.currentQuery,
2089
2592
  requestId,
2090
- filter: this.currentFilter
2593
+ filter: this.currentFilter,
2594
+ provenanceFilter: this.currentProvenanceFilter,
2595
+ sessionCwd: this.currentSessionCwd,
2596
+ abortSignal
2091
2597
  });
2092
2598
  return;
2093
2599
  }
@@ -2103,6 +2609,8 @@ var AgentMentionSearchController = class extends AgentMentionSearchControllerBas
2103
2609
  }
2104
2610
  close() {
2105
2611
  this.clearTimer();
2612
+ this.abortActiveRequest();
2613
+ this.cancelIssueLoadMoreRequests();
2106
2614
  this.requestId += 1;
2107
2615
  this.currentFilter = DEFAULT_AGENT_MENTION_FILTER;
2108
2616
  this.resetAgentGeneratedBrowsePath();
@@ -2123,10 +2631,153 @@ var AgentMentionSearchController = class extends AgentMentionSearchControllerBas
2123
2631
  dispose() {
2124
2632
  this.disposed = true;
2125
2633
  this.clearTimer();
2634
+ this.abortActiveRequest();
2635
+ this.cancelIssueLoadMoreRequests();
2126
2636
  this.cancelPendingPreload();
2127
2637
  this.listeners.clear();
2128
2638
  this.requestId += 1;
2129
2639
  }
2640
+ loadMoreIssueTopic(groupId) {
2641
+ const group = this.issueTopicGroups?.find(
2642
+ (candidate) => candidate.id === groupId
2643
+ );
2644
+ const cursor = group?.nextPageToken;
2645
+ const provider = this.contextMentionProviders.get(
2646
+ WORKSPACE_ISSUE_PROVIDER_ID
2647
+ );
2648
+ if (!group || !cursor || !provider?.queryGroupPage) {
2649
+ return;
2650
+ }
2651
+ const requestKey = JSON.stringify({
2652
+ workspaceId: this.activeWorkspaceId,
2653
+ query: this.currentQuery,
2654
+ providerGroupId: group.providerGroupId,
2655
+ cursor
2656
+ });
2657
+ if (this.issueLoadMoreRequests.has(requestKey)) {
2658
+ return;
2659
+ }
2660
+ const requestId = this.requestId;
2661
+ const workspaceId = this.activeWorkspaceId;
2662
+ const currentUserId = this.currentUserId;
2663
+ const sessionCwd = this.currentSessionCwd;
2664
+ const provenanceFilter = this.currentProvenanceFilter;
2665
+ const query = this.currentQuery;
2666
+ const filter = this.currentFilter;
2667
+ const abortController = new AbortController();
2668
+ const requestToken = Symbol(requestKey);
2669
+ group.loadMoreStatus = "loading";
2670
+ group.loadMoreError = null;
2671
+ this.emitIssueTopicGroupsState();
2672
+ void (async () => {
2673
+ try {
2674
+ const diagnostics = [];
2675
+ const page = await queryAgentMentionProviderWithDiagnostics({
2676
+ abortSignal: abortController.signal,
2677
+ diagnosticNow: this.diagnosticNow,
2678
+ diagnostics,
2679
+ fallback: null,
2680
+ providerId: WORKSPACE_ISSUE_PROVIDER_ID,
2681
+ providerTimeoutMs: this.providerTimeoutMs,
2682
+ throwOnTimeout: true,
2683
+ query: (abortSignal) => queryAgentMentionProviderGroupPage({
2684
+ provider,
2685
+ providerGroupId: group.providerGroupId,
2686
+ workspaceId,
2687
+ currentUserId,
2688
+ query,
2689
+ cursor,
2690
+ pageSize: DEFAULT_MENTION_GROUP_PAGE_SIZE,
2691
+ sessionCwd,
2692
+ abortSignal,
2693
+ provenanceFilter
2694
+ }),
2695
+ resultCount: (result) => result?.items.length ?? 0
2696
+ });
2697
+ if (!page || !this.canApply(requestId, workspaceId, query, filter) || abortController.signal.aborted) {
2698
+ return;
2699
+ }
2700
+ const current = this.issueTopicGroups?.find(
2701
+ (candidate) => candidate.id === groupId
2702
+ );
2703
+ if (!current || current.nextPageToken !== cursor) {
2704
+ return;
2705
+ }
2706
+ const seen = new Set(
2707
+ current.items.filter((item) => item.kind === "workspace-issue").map((item) => item.targetId)
2708
+ );
2709
+ const appended = page.items.filter((item) => {
2710
+ if (item.kind !== "workspace-issue") {
2711
+ return true;
2712
+ }
2713
+ if (seen.has(item.targetId)) {
2714
+ return false;
2715
+ }
2716
+ seen.add(item.targetId);
2717
+ return true;
2718
+ });
2719
+ current.items = [...current.items, ...appended];
2720
+ current.totalCount = Math.max(page.totalCount, current.items.length);
2721
+ current.nextPageToken = page.nextPageToken;
2722
+ current.loadMoreStatus = "idle";
2723
+ current.loadMoreError = null;
2724
+ if (!query) {
2725
+ mergeAgentMentionBrowseIssueGroupPage({
2726
+ cacheKey: this.browseCacheKey(
2727
+ {
2728
+ workspaceId,
2729
+ currentUserId,
2730
+ filter,
2731
+ sessionCwd
2732
+ },
2733
+ provenanceFilter
2734
+ ),
2735
+ group: page,
2736
+ cachedAt: this.diagnosticNow()
2737
+ });
2738
+ }
2739
+ this.emitIssueTopicGroupsState();
2740
+ } catch (error) {
2741
+ if (!this.canApply(requestId, workspaceId, query, filter) || abortController.signal.aborted) {
2742
+ return;
2743
+ }
2744
+ const current = this.issueTopicGroups?.find(
2745
+ (candidate) => candidate.id === groupId
2746
+ );
2747
+ if (current?.nextPageToken === cursor) {
2748
+ current.loadMoreStatus = "error";
2749
+ current.loadMoreError = error instanceof Error ? error.message : String(error);
2750
+ this.emitIssueTopicGroupsState();
2751
+ }
2752
+ } finally {
2753
+ const active = this.issueLoadMoreRequests.get(requestKey);
2754
+ if (active?.token === requestToken) {
2755
+ this.issueLoadMoreRequests.delete(requestKey);
2756
+ }
2757
+ }
2758
+ })();
2759
+ this.issueLoadMoreRequests.set(requestKey, {
2760
+ abortController,
2761
+ token: requestToken
2762
+ });
2763
+ }
2764
+ emitIssueTopicGroupsState() {
2765
+ this.setState({
2766
+ status: "ready",
2767
+ query: this.currentQuery,
2768
+ mode: this.currentQuery ? "results" : "browse",
2769
+ filter: this.currentFilter,
2770
+ categories: buildBrowseCategories(),
2771
+ groups: this.groupsFromRawGroups(),
2772
+ error: null
2773
+ });
2774
+ }
2775
+ cancelIssueLoadMoreRequests() {
2776
+ for (const request of this.issueLoadMoreRequests.values()) {
2777
+ request.abortController.abort();
2778
+ }
2779
+ this.issueLoadMoreRequests.clear();
2780
+ }
2130
2781
  };
2131
2782
  function preloadAgentMentionBrowse(input) {
2132
2783
  const controller = new AgentMentionSearchController({
@@ -2155,4 +2806,4 @@ export {
2155
2806
  AgentMentionSearchController,
2156
2807
  preloadAgentMentionBrowse
2157
2808
  };
2158
- //# sourceMappingURL=chunk-747L443E.js.map
2809
+ //# sourceMappingURL=chunk-BXOKBZH4.js.map