@tutti-os/agent-gui 0.0.214 → 0.0.215

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 (40) hide show
  1. package/dist/{AgentRichTextReadonly-TASIMIK4.js → AgentRichTextReadonly-56TZAJ47.js} +3 -3
  2. package/dist/agent-conversation/index.d.ts +3 -3
  3. package/dist/agent-conversation/index.js +4 -4
  4. package/dist/agent-gui.d.ts +2 -2
  5. package/dist/agent-gui.js +8 -8
  6. package/dist/agent-message-center/index.d.ts +1 -1
  7. package/dist/agent-message-center/index.js +3 -3
  8. package/dist/{agentGuiNodeTypes-BMcpfKTn.d.ts → agentGuiNodeTypes-DW7T--Y8.d.ts} +1 -1
  9. package/dist/app/renderer/agentactivity.css +68 -10
  10. package/dist/{chunk-7SSORDQY.js → chunk-AQ7CRDGX.js} +2 -2
  11. package/dist/{chunk-ZNHMWCO4.js → chunk-GUD5NOHO.js} +3 -3
  12. package/dist/{chunk-RLFO3NJV.js → chunk-JOUEYIV3.js} +173 -132
  13. package/dist/chunk-JOUEYIV3.js.map +1 -0
  14. package/dist/{chunk-LQKLBDBK.js → chunk-KNSLQO52.js} +37 -3
  15. package/dist/chunk-KNSLQO52.js.map +1 -0
  16. package/dist/{chunk-L4E2Y52A.js → chunk-KVFBUOKZ.js} +4 -43
  17. package/dist/chunk-KVFBUOKZ.js.map +1 -0
  18. package/dist/chunk-LQMIEH4C.js +100 -0
  19. package/dist/chunk-LQMIEH4C.js.map +1 -0
  20. package/dist/{chunk-G2QO6HPB.js → chunk-MWAUXAD2.js} +22 -8
  21. package/dist/chunk-MWAUXAD2.js.map +1 -0
  22. package/dist/{chunk-FEUU4YMY.js → chunk-YTU6IUO2.js} +5806 -5722
  23. package/dist/chunk-YTU6IUO2.js.map +1 -0
  24. package/dist/index.d.ts +78 -71
  25. package/dist/index.js +8 -8
  26. package/dist/workbench/contribution.js +2 -2
  27. package/dist/workbench/index.js +2 -2
  28. package/dist/workbench/sessionTitle.js +1 -1
  29. package/dist/{workspaceLinkActions-COfr61YO.d.ts → workspaceLinkActions-CzsbvGmC.d.ts} +78 -71
  30. package/package.json +14 -14
  31. package/dist/chunk-FEUU4YMY.js.map +0 -1
  32. package/dist/chunk-G2QO6HPB.js.map +0 -1
  33. package/dist/chunk-L4E2Y52A.js.map +0 -1
  34. package/dist/chunk-LQKLBDBK.js.map +0 -1
  35. package/dist/chunk-RLFO3NJV.js.map +0 -1
  36. package/dist/chunk-ZVYUTXQJ.js +0 -43
  37. package/dist/chunk-ZVYUTXQJ.js.map +0 -1
  38. /package/dist/{AgentRichTextReadonly-TASIMIK4.js.map → AgentRichTextReadonly-56TZAJ47.js.map} +0 -0
  39. /package/dist/{chunk-7SSORDQY.js.map → chunk-AQ7CRDGX.js.map} +0 -0
  40. /package/dist/{chunk-ZNHMWCO4.js.map → chunk-GUD5NOHO.js.map} +0 -0
@@ -15,7 +15,7 @@ import {
15
15
  resolveAgentGuiSessionProviderFlatIconUrl,
16
16
  resolveNextAgentGUIConversationRailWidthPx,
17
17
  shouldAutoCollapseAgentGUIConversationRail
18
- } from "./chunk-ZNHMWCO4.js";
18
+ } from "./chunk-GUD5NOHO.js";
19
19
  import {
20
20
  AGENT_PROVIDERS,
21
21
  AGENT_PROVIDER_LABEL,
@@ -31,7 +31,7 @@ import {
31
31
  resolveAgentGUIFirstUserMessageDisplayPrompt,
32
32
  resolveAgentGUIProviderDisplayLabel,
33
33
  resolveAgentGUIProviderIdentity
34
- } from "./chunk-L4E2Y52A.js";
34
+ } from "./chunk-KVFBUOKZ.js";
35
35
  import {
36
36
  resolveAgentGuiWorkbenchProviderLabel
37
37
  } from "./chunk-MGSRWYRN.js";
@@ -70,7 +70,7 @@ import {
70
70
  toLocalShortDateTime,
71
71
  updateAgentComposerDraft,
72
72
  useProjectedAgentConversation
73
- } from "./chunk-FEUU4YMY.js";
73
+ } from "./chunk-YTU6IUO2.js";
74
74
  import {
75
75
  agentRichTextContentToPromptText,
76
76
  createAgentRichTextInputExtensions,
@@ -80,7 +80,7 @@ import {
80
80
  plainTextToAgentRichTextInlineContent,
81
81
  skillDescriptionForDisplay,
82
82
  skillTriggerForPrefix
83
- } from "./chunk-G2QO6HPB.js";
83
+ } from "./chunk-MWAUXAD2.js";
84
84
  import {
85
85
  AgentEnvPanelActionProvider
86
86
  } from "./chunk-N4HLBSMJ.js";
@@ -135,7 +135,7 @@ import {
135
135
  normalizePlanIssueBudgetPreset,
136
136
  planImplementationPromptFromPlanTurn,
137
137
  planIssueBudgetPresetsEqual
138
- } from "./chunk-7SSORDQY.js";
138
+ } from "./chunk-AQ7CRDGX.js";
139
139
  import {
140
140
  useEngineSelector
141
141
  } from "./chunk-EVQ4JY3N.js";
@@ -145,13 +145,13 @@ import {
145
145
  blobToBase64,
146
146
  normalizeAgentApprovalPurpose,
147
147
  resolveWorkspaceLinkAction
148
- } from "./chunk-LQKLBDBK.js";
148
+ } from "./chunk-KNSLQO52.js";
149
149
  import {
150
150
  AgentTargetPresentationProvider,
151
151
  cn,
152
152
  resolveAgentTargetPresentation,
153
153
  useAgentTargetPresentations
154
- } from "./chunk-ZVYUTXQJ.js";
154
+ } from "./chunk-LQMIEH4C.js";
155
155
  import {
156
156
  resolveWorkspaceAgentSessionSortTimeUnixMs
157
157
  } from "./chunk-YMXYBG7U.js";
@@ -7284,9 +7284,6 @@ function useAgentGUIComposerCapabilities(input) {
7284
7284
  }
7285
7285
 
7286
7286
  // agent-gui/agentGuiNode/controller/useAgentGUIComposerOptionsSync.ts
7287
- import {
7288
- selectLatestActivationForSession as selectLatestActivationForSession4
7289
- } from "@tutti-os/agent-activity-core";
7290
7287
  import { useCallback as useCallback8, useEffect as useEffect5, useRef as useRef9 } from "react";
7291
7288
 
7292
7289
  // host/agentHostEventBus.ts
@@ -7449,7 +7446,6 @@ function subscribeCoalesced(type, options, callback) {
7449
7446
 
7450
7447
  // agent-gui/agentGuiNode/controller/useAgentGUIComposerOptionsSync.ts
7451
7448
  function useAgentGUIComposerOptionsSync(input) {
7452
- const previousActiveConversationIdRef = useRef9(input.activeConversationId);
7453
7449
  const previousIsCreatingConversationRef = useRef9(
7454
7450
  input.isCreatingConversation
7455
7451
  );
@@ -7604,12 +7600,10 @@ function useAgentGUIComposerOptionsSync(input) {
7604
7600
  ]);
7605
7601
  useEffect5(() => {
7606
7602
  if (input.previewMode) return;
7607
- const conversationActivated = input.activeConversationId !== null && previousActiveConversationIdRef.current !== input.activeConversationId;
7608
7603
  const conversationCreationSettled = previousIsCreatingConversationRef.current && !input.isCreatingConversation;
7609
- previousActiveConversationIdRef.current = input.activeConversationId;
7610
7604
  previousIsCreatingConversationRef.current = input.isCreatingConversation;
7611
7605
  loadDraftComposerOptions(
7612
- conversationActivated || conversationCreationSettled || input.providerComposerOptions?.behavior?.prewarmDraftSession === true && input.isComposerHome ? { force: true } : void 0
7606
+ conversationCreationSettled || input.providerComposerOptions?.behavior?.prewarmDraftSession === true && input.isComposerHome ? { force: true } : void 0
7613
7607
  );
7614
7608
  }, [
7615
7609
  input.activeConversationId,
@@ -7635,25 +7629,6 @@ function useAgentGUIComposerOptionsSync(input) {
7635
7629
  input.previewMode,
7636
7630
  input.syncConversationListProjection
7637
7631
  ]);
7638
- useEffect5(() => {
7639
- if (input.previewMode || !input.activeConversationId) return;
7640
- const activation = selectLatestActivationForSession4(
7641
- input.sessionEngine.getSnapshot(),
7642
- input.activeConversationId
7643
- );
7644
- if (activation?.status === "failed" || activation?.status === "canceled" || activation?.status === "requested" || activation?.status === "uncertain") {
7645
- return;
7646
- }
7647
- input.reloadSelectedConversation(input.activeConversationId, {
7648
- reloadConversations: false,
7649
- reloadDetail: true
7650
- });
7651
- }, [
7652
- input.activeConversationId,
7653
- input.previewMode,
7654
- input.reloadSelectedConversation,
7655
- input.sessionEngine
7656
- ]);
7657
7632
  return { loadDraftComposerOptions, reloadComposerOptionsForTarget };
7658
7633
  }
7659
7634
 
@@ -9186,7 +9161,7 @@ function useAgentGUIConversationMetadataActions(input) {
9186
9161
  // agent-gui/agentGuiNode/controller/useAgentGUINewConversationActivation.ts
9187
9162
  import {
9188
9163
  isPendingActivationViable as isPendingActivationViable5,
9189
- selectLatestActivationForSession as selectLatestActivationForSession5,
9164
+ selectLatestActivationForSession as selectLatestActivationForSession4,
9190
9165
  selectTuttiModeDraftIsActive,
9191
9166
  selectTuttiModeDraftOrchestrationIntensity
9192
9167
  } from "@tutti-os/agent-activity-core";
@@ -9323,7 +9298,7 @@ function useAgentGUINewConversationActivation(input) {
9323
9298
  };
9324
9299
  const prewarmedSessionId = normalizedInitialContent.length > 0 && snapshotComposerOptions?.behavior?.prewarmDraftSession === true ? draftAgentSessionIdFromComposerOptions(snapshotComposerOptions) : null;
9325
9300
  const agentSessionId = prewarmedSessionId && activation.stateFor(prewarmedSessionId) === "inactive" && isPendingActivationViable5(
9326
- selectLatestActivationForSession5(
9301
+ selectLatestActivationForSession4(
9327
9302
  sessionEngine.getSnapshot(),
9328
9303
  prewarmedSessionId
9329
9304
  )
@@ -13007,7 +12982,7 @@ import {
13007
12982
  selectEngineSessionReconcile as selectEngineSessionReconcile2,
13008
12983
  selectEngineSessionSettingsUpdate as selectEngineSessionSettingsUpdate2,
13009
12984
  selectEngineSubmitAvailability,
13010
- selectLatestActivationForSession as selectLatestActivationForSession6,
12985
+ selectLatestActivationForSession as selectLatestActivationForSession5,
13011
12986
  selectLatestPendingSubmitForSession,
13012
12987
  selectPendingSubmitsForSession as selectPendingSubmitsForSession4,
13013
12988
  selectSessionHasUnconfirmedSubmit,
@@ -13044,7 +13019,7 @@ function useAgentGUISessionEngineState(input) {
13044
13019
  );
13045
13020
  const activePendingActivation = useEngineSelector(
13046
13021
  sessionEngine,
13047
- (state) => selectLatestActivationForSession6(state, activeConversationId)
13022
+ (state) => selectLatestActivationForSession5(state, activeConversationId)
13048
13023
  );
13049
13024
  const isCreatingConversation = isPendingNewConversationActivation(
13050
13025
  activePendingActivation
@@ -13223,7 +13198,7 @@ var SESSION_SETTINGS_STATUS_SHOWS_OPTIMISTIC_VALUE = {
13223
13198
 
13224
13199
  // agent-gui/agentGuiNode/controller/useAgentGUISessionDetailTransport.ts
13225
13200
  import {
13226
- selectLatestActivationForSession as selectLatestActivationForSession7
13201
+ selectLatestActivationForSession as selectLatestActivationForSession6
13227
13202
  } from "@tutti-os/agent-activity-core";
13228
13203
  import { useCallback as useCallback25, useMemo as useMemo18 } from "react";
13229
13204
 
@@ -13530,7 +13505,7 @@ function useAgentGUISessionDetailTransport(input) {
13530
13505
  windowHasTurnMissingUserPrompt
13531
13506
  },
13532
13507
  reload: {
13533
- getActivationStatus: (agentSessionId) => selectLatestActivationForSession7(
13508
+ getActivationStatus: (agentSessionId) => selectLatestActivationForSession6(
13534
13509
  sessionEngine.getSnapshot(),
13535
13510
  agentSessionId
13536
13511
  )?.status ?? null,
@@ -14019,7 +13994,6 @@ function useAgentGUINodeController({
14019
13994
  const {
14020
13995
  loadSessionState,
14021
13996
  markSelectedConversationDetailPending,
14022
- reloadSelectedConversation,
14023
13997
  resolveSessionMessages
14024
13998
  } = sessionDetailTransport;
14025
13999
  const storedActiveMessages = activeConversationId ? resolveSessionMessages(activeConversationId) : EMPTY_AGENT_GUI_MESSAGES;
@@ -14236,11 +14210,9 @@ function useAgentGUINodeController({
14236
14210
  onComposerDefaultsAuthorityReloadedRef,
14237
14211
  previewMode,
14238
14212
  providerComposerOptions,
14239
- reloadSelectedConversation,
14240
14213
  selectedComposerTargetDataRef,
14241
14214
  selectedProjectPath,
14242
14215
  selectedProjectPathRef,
14243
- sessionEngine,
14244
14216
  syncConversationListProjection,
14245
14217
  workspaceId,
14246
14218
  workspacePath
@@ -15193,7 +15165,6 @@ var styles = {
15193
15165
  conversationStatusGlyph: "agent-gui-node__conversation-status-glyph",
15194
15166
  conversationTime: "agent-gui-node__conversation-time",
15195
15167
  conversationTitle: "agent-gui-node__conversation-title",
15196
- conversationTitleMentionIcon: "agent-gui-node__conversation-title-mention-icon",
15197
15168
  conversationTitleRow: "agent-gui-node__conversation-title-row",
15198
15169
  conversationUnreadLamp: "agent-gui-node__conversation-unread-lamp",
15199
15170
  detail: "agent-gui-node__detail",
@@ -28409,7 +28380,9 @@ function useScopedProjectMissingState(scopeKey) {
28409
28380
  if (identityRef.current !== identity) {
28410
28381
  return;
28411
28382
  }
28412
- setResult({ identity, isMissing });
28383
+ setResult(
28384
+ (current) => current.identity === identity && current.isMissing === isMissing ? current : { identity, isMissing }
28385
+ );
28413
28386
  },
28414
28387
  [identity]
28415
28388
  );
@@ -28620,13 +28593,13 @@ function AgentComposer(props) {
28620
28593
  goalDraftObjective ?? draftPrompt
28621
28594
  );
28622
28595
  const [fileMentionSuggestion, setFileMentionSuggestion] = useState28(null);
28623
- const [isSelectedProjectMissing, setIsSelectedProjectMissing] = useScopedProjectMissingState(draftScopeKey);
28596
+ const selectedProjectPath = composerSettings.selectedProjectPath?.trim() ?? "";
28597
+ const [isSelectedProjectMissing, setIsSelectedProjectMissing] = useScopedProjectMissingState(selectedProjectPath);
28624
28598
  const [isSlashStatusPanelOpen, setIsSlashStatusPanelOpen] = useState28(false);
28625
28599
  const slashStatusAgentSessionId = slashStatus?.agentSessionId ?? null;
28626
28600
  const previousSlashStatusAgentSessionIdRef = useRef42(
28627
28601
  slashStatusAgentSessionId
28628
28602
  );
28629
- const selectedProjectPath = composerSettings.selectedProjectPath?.trim() ?? "";
28630
28603
  const selectedProjectSectionKey = composerSettings.selectedProjectSectionKey?.trim() ?? "";
28631
28604
  const previousSelectedProjectPathRef = useRef42(selectedProjectPath);
28632
28605
  const composerRef = useRef42(null);
@@ -32529,7 +32502,7 @@ import { memo as memo6, useCallback as useCallback55 } from "react";
32529
32502
  // agent-gui/agentGuiNode/view/AgentGUIConversationRailItem.tsx
32530
32503
  import { memo as memo4, useCallback as useCallback53, useMemo as useMemo39 } from "react";
32531
32504
  import { ExternalLink as ExternalLink2 } from "lucide-react";
32532
- import { IssueIcon, NewWorkspaceLinedIcon as NewWorkspaceLinedIcon2, cn as cn8 } from "@tutti-os/ui-system";
32505
+ import { NewWorkspaceLinedIcon as NewWorkspaceLinedIcon2, cn as cn8 } from "@tutti-os/ui-system";
32533
32506
  import { WorkspaceUserProjectSelect as WorkspaceUserProjectSelect2 } from "@tutti-os/workspace-user-project/ui";
32534
32507
  import { BareIconButton as BareIconButton3 } from "@tutti-os/ui-system/components";
32535
32508
 
@@ -33195,8 +33168,7 @@ function agentGUIConversationIconPresentation(provider, agentTargetId, workspace
33195
33168
  return providerIconUrl ? { kind: "mask", url: providerIconUrl } : null;
33196
33169
  }
33197
33170
  function agentGUIConversationRailTitle(item, labels, uiLanguage) {
33198
- const title = conversationPlainTitle(item, labels, uiLanguage);
33199
- return item.titleLeadingMentionKind === "task" ? title.replace(/^@\s*/, "") : title;
33171
+ return conversationPlainTitle(item, labels, uiLanguage);
33200
33172
  }
33201
33173
  var AgentGUIConversationRailItem = memo4(
33202
33174
  function AgentGUIConversationRailItem2({
@@ -33337,15 +33309,6 @@ var AgentGUIConversationRailItem = memo4(
33337
33309
  src: conversationIcon.url
33338
33310
  }
33339
33311
  ) : null,
33340
- item.titleLeadingMentionKind === "task" ? /* @__PURE__ */ jsx60(
33341
- "span",
33342
- {
33343
- "aria-hidden": "true",
33344
- className: AgentGUINode_styles_default.conversationTitleMentionIcon,
33345
- "data-agent-gui-conversation-title-mention-icon": item.titleLeadingMentionKind,
33346
- children: /* @__PURE__ */ jsx60(IssueIcon, {})
33347
- }
33348
- ) : null,
33349
33312
  /* @__PURE__ */ jsx60("span", { className: AgentGUINode_styles_default.conversationTitle, children: agentGUIConversationRailTitle(item, labels, uiLanguage) })
33350
33313
  ] }),
33351
33314
  /* @__PURE__ */ jsx60(AgentGUIConversationRailRelativeTime, { item, labels })
@@ -39139,6 +39102,52 @@ function readTimelineGeometry(timeline) {
39139
39102
  scrollHeight
39140
39103
  };
39141
39104
  }
39105
+ function readBottomDockSafeArea(bottomDock) {
39106
+ const bottomDockRect = bottomDock.getBoundingClientRect();
39107
+ let timelineVisualTop = bottomDockRect.top;
39108
+ let floatingVisualTop = bottomDockRect.top;
39109
+ bottomDock.querySelectorAll("*").forEach((element) => {
39110
+ if (element.closest(`.${AgentGUINode_styles_default.bottomDockScrollToBottom}`)) {
39111
+ return;
39112
+ }
39113
+ const rect = element.getBoundingClientRect();
39114
+ if (rect.width <= 0 || rect.height <= 0) {
39115
+ return;
39116
+ }
39117
+ if (element.closest(`.${AgentGUINode_styles_default.composerInputShell}`)) {
39118
+ if (element.matches(".agent-gui-node__composer-prompt-input-area")) {
39119
+ floatingVisualTop = Math.min(floatingVisualTop, rect.top);
39120
+ }
39121
+ return;
39122
+ }
39123
+ if (element.closest(`.${AgentGUINode_styles_default.composerDisclosurePanel}`)) {
39124
+ floatingVisualTop = Math.min(floatingVisualTop, rect.top);
39125
+ return;
39126
+ }
39127
+ floatingVisualTop = Math.min(floatingVisualTop, rect.top);
39128
+ timelineVisualTop = Math.min(timelineVisualTop, rect.top);
39129
+ });
39130
+ return {
39131
+ timelineOverflowHeight: Math.max(
39132
+ 0,
39133
+ Math.ceil(bottomDockRect.top - timelineVisualTop)
39134
+ ),
39135
+ floatingOverflowHeight: Math.max(
39136
+ 0,
39137
+ Math.ceil(bottomDockRect.top - floatingVisualTop)
39138
+ )
39139
+ };
39140
+ }
39141
+ function writeBottomDockSafeArea(timeline, safeArea) {
39142
+ timeline.style.setProperty(
39143
+ "--agent-gui-bottom-dock-safe-area",
39144
+ `${safeArea.timelineOverflowHeight}px`
39145
+ );
39146
+ safeArea.bottomDock.style.setProperty(
39147
+ "--agent-gui-bottom-dock-floating-safe-area",
39148
+ `${safeArea.floatingOverflowHeight}px`
39149
+ );
39150
+ }
39142
39151
  function useAgentGUIDetailScroll(input) {
39143
39152
  const {
39144
39153
  actions,
@@ -39157,8 +39166,10 @@ function useAgentGUIDetailScroll(input) {
39157
39166
  const [isTimelineScrolledToTop, setIsTimelineScrolledToTop] = useState45(true);
39158
39167
  const [isTimelineScrolledToBottom, setIsTimelineScrolledToBottom] = useState45(true);
39159
39168
  const bottomLockOwnerRef = useRef52(null);
39169
+ const pointerScrollConversationRef = useRef52(null);
39160
39170
  const userScrollAwayIntentConversationRef = useRef52(null);
39161
39171
  const lastShowTimelineSkeletonRef = useRef52(showTimelineSkeleton);
39172
+ const bottomDockSafeAreaRef = useRef52(null);
39162
39173
  useLayoutEffect7(() => {
39163
39174
  const timelineSkeletonChanged = lastShowTimelineSkeletonRef.current !== showTimelineSkeleton;
39164
39175
  lastShowTimelineSkeletonRef.current = showTimelineSkeleton;
@@ -39171,17 +39182,33 @@ function useAgentGUIDetailScroll(input) {
39171
39182
  timelineScrollAnchorRef.current = null;
39172
39183
  bottomLockOwnerRef.current = null;
39173
39184
  pendingPrependScrollAnchorRef.current = null;
39185
+ pointerScrollConversationRef.current = null;
39174
39186
  submittedPromptScrollConversationRef.current = null;
39175
39187
  userScrollAwayIntentConversationRef.current = null;
39176
39188
  setIsTimelineScrolledToTop(true);
39177
39189
  setIsTimelineScrolledToBottom(true);
39178
39190
  return;
39179
39191
  }
39192
+ if (activeConversationId !== viewModel.rail.activeConversationId) {
39193
+ bottomLockOwnerRef.current = null;
39194
+ return;
39195
+ }
39180
39196
  const anchor = timelineScrollAnchorRef.current;
39181
39197
  const prependAnchor = pendingPrependScrollAnchorRef.current;
39182
39198
  const shouldScrollSubmittedPromptToBottom = submittedPromptScrollConversationRef.current === activeConversationId;
39183
39199
  const conversationChanged = !anchor || anchor.conversationId !== activeConversationId;
39184
39200
  const shouldRestorePrependAnchor = prependAnchor?.conversationId === activeConversationId;
39201
+ if (!conversationChanged && bottomLockOwnerRef.current === null && anchor.scrollHeight - anchor.scrollTop - anchor.clientHeight <= AGENT_GUI_STICK_TO_BOTTOM_THRESHOLD_PX) {
39202
+ bottomLockOwnerRef.current = activeConversationId;
39203
+ }
39204
+ if (conversationChanged && showTimelineSkeleton) {
39205
+ bottomLockOwnerRef.current = activeConversationId;
39206
+ pointerScrollConversationRef.current = null;
39207
+ userScrollAwayIntentConversationRef.current = null;
39208
+ setIsTimelineScrolledToTop(true);
39209
+ setIsTimelineScrolledToBottom(true);
39210
+ return;
39211
+ }
39185
39212
  if (!conversationChanged && !shouldScrollSubmittedPromptToBottom && !shouldRestorePrependAnchor && !timelineSkeletonChanged) {
39186
39213
  return;
39187
39214
  }
@@ -39190,6 +39217,7 @@ function useAgentGUIDetailScroll(input) {
39190
39217
  let nextScrollTop;
39191
39218
  if (conversationChanged || shouldScrollSubmittedPromptToBottom) {
39192
39219
  bottomLockOwnerRef.current = activeConversationId;
39220
+ pointerScrollConversationRef.current = null;
39193
39221
  userScrollAwayIntentConversationRef.current = null;
39194
39222
  }
39195
39223
  const shouldKeepBottomLocked = bottomLockOwnerRef.current === activeConversationId;
@@ -39217,6 +39245,7 @@ function useAgentGUIDetailScroll(input) {
39217
39245
  } else {
39218
39246
  const distanceFromBottom = anchor.scrollHeight - anchor.scrollTop - anchor.clientHeight;
39219
39247
  if (distanceFromBottom <= AGENT_GUI_STICK_TO_BOTTOM_THRESHOLD_PX) {
39248
+ bottomLockOwnerRef.current = activeConversationId;
39220
39249
  setTimelineScrollTopInstantly(timeline, maxScrollTop);
39221
39250
  nextScrollTop = maxScrollTop;
39222
39251
  } else {
@@ -39240,70 +39269,46 @@ function useAgentGUIDetailScroll(input) {
39240
39269
  conversation,
39241
39270
  showTimelineSkeleton,
39242
39271
  timelineConversationId,
39272
+ viewModel.rail.activeConversationId,
39243
39273
  viewModel.detail.isLoadingOlderMessages
39244
39274
  ]);
39275
+ const hasTimelineConversation = timelineConversationId !== null;
39245
39276
  useLayoutEffect7(() => {
39246
39277
  const timeline = timelineRef.current;
39247
39278
  const bottomDock = bottomDockRef.current;
39248
- const activeConversationId = timelineConversationId;
39249
- if (!timeline || !bottomDock || !activeConversationId) {
39279
+ if (!hasTimelineConversation || !timeline || !bottomDock) {
39250
39280
  return;
39251
39281
  }
39252
39282
  let animationFrameId = null;
39253
- const syncBottomDockSafeArea = () => {
39254
- const bottomDockRect = bottomDock.getBoundingClientRect();
39255
- let timelineVisualTop = bottomDockRect.top;
39256
- let floatingVisualTop = bottomDockRect.top;
39257
- bottomDock.querySelectorAll("*").forEach((element) => {
39258
- if (element.closest(`.${AgentGUINode_styles_default.bottomDockScrollToBottom}`)) {
39259
- return;
39260
- }
39261
- const rect = element.getBoundingClientRect();
39262
- if (rect.width <= 0 || rect.height <= 0) {
39263
- return;
39264
- }
39265
- if (element.closest(`.${AgentGUINode_styles_default.composerInputShell}`)) {
39266
- if (element.matches(".agent-gui-node__composer-prompt-input-area")) {
39267
- floatingVisualTop = Math.min(floatingVisualTop, rect.top);
39268
- }
39269
- return;
39270
- }
39271
- if (element.closest(`.${AgentGUINode_styles_default.composerDisclosurePanel}`)) {
39272
- floatingVisualTop = Math.min(floatingVisualTop, rect.top);
39273
- return;
39274
- }
39275
- floatingVisualTop = Math.min(floatingVisualTop, rect.top);
39276
- timelineVisualTop = Math.min(timelineVisualTop, rect.top);
39277
- });
39278
- const timelineOverflowHeight = Math.max(
39279
- 0,
39280
- Math.ceil(bottomDockRect.top - timelineVisualTop)
39281
- );
39282
- const floatingOverflowHeight = Math.max(
39283
- 0,
39284
- Math.ceil(bottomDockRect.top - floatingVisualTop)
39285
- );
39286
- timeline.style.setProperty(
39287
- "--agent-gui-bottom-dock-safe-area",
39288
- `${timelineOverflowHeight}px`
39289
- );
39290
- bottomDock.style.setProperty(
39291
- "--agent-gui-bottom-dock-floating-safe-area",
39292
- `${floatingOverflowHeight}px`
39293
- );
39294
- };
39295
- const syncBottomDockSpace = () => {
39296
- syncBottomDockSafeArea();
39297
- if (activeConversationId !== viewModel.rail.activeConversationId) {
39298
- return;
39283
+ const resolveBottomLockConversation = () => {
39284
+ const activeConversationId = bottomLockOwnerRef.current;
39285
+ if (!activeConversationId) {
39286
+ return null;
39299
39287
  }
39300
39288
  const anchor = timelineScrollAnchorRef.current;
39301
- const bottomLocked = bottomLockOwnerRef.current === activeConversationId;
39302
39289
  if (!anchor || anchor.conversationId !== activeConversationId) {
39290
+ return null;
39291
+ }
39292
+ return activeConversationId;
39293
+ };
39294
+ const syncBottomDockSafeArea = (forceMeasurement) => {
39295
+ const cachedSafeArea = bottomDockSafeAreaRef.current;
39296
+ if (!forceMeasurement && cachedSafeArea?.bottomDock === bottomDock && cachedSafeArea.revision === bottomDockStoreRevision) {
39297
+ writeBottomDockSafeArea(timeline, cachedSafeArea);
39303
39298
  return;
39304
39299
  }
39305
- const distanceFromBottom = anchor.scrollHeight - anchor.scrollTop - anchor.clientHeight;
39306
- if (!bottomLocked && distanceFromBottom > AGENT_GUI_STICK_TO_BOTTOM_THRESHOLD_PX) {
39300
+ const measuredSafeArea = readBottomDockSafeArea(bottomDock);
39301
+ const nextSafeArea = {
39302
+ bottomDock,
39303
+ revision: bottomDockStoreRevision,
39304
+ ...measuredSafeArea
39305
+ };
39306
+ bottomDockSafeAreaRef.current = nextSafeArea;
39307
+ writeBottomDockSafeArea(timeline, nextSafeArea);
39308
+ };
39309
+ const syncConversationBottomLock = () => {
39310
+ const scheduledConversationId = resolveBottomLockConversation();
39311
+ if (!scheduledConversationId) {
39307
39312
  return;
39308
39313
  }
39309
39314
  if (animationFrameId !== null) {
@@ -39311,20 +39316,14 @@ function useAgentGUIDetailScroll(input) {
39311
39316
  }
39312
39317
  animationFrameId = window.requestAnimationFrame(() => {
39313
39318
  animationFrameId = null;
39314
- const latestAnchor = timelineScrollAnchorRef.current;
39315
- if (!latestAnchor || latestAnchor.conversationId !== activeConversationId) {
39316
- return;
39317
- }
39318
- const latestDistanceFromBottom = latestAnchor.scrollHeight - latestAnchor.scrollTop - latestAnchor.clientHeight;
39319
- const latestBottomLocked = bottomLockOwnerRef.current === activeConversationId;
39320
- if (!latestBottomLocked && latestDistanceFromBottom > AGENT_GUI_STICK_TO_BOTTOM_THRESHOLD_PX) {
39319
+ if (resolveBottomLockConversation() !== scheduledConversationId || timelineRef.current !== timeline) {
39321
39320
  return;
39322
39321
  }
39323
39322
  const geometry = readTimelineGeometry(timeline);
39324
39323
  const maxScrollTop = geometry.maxScrollTop;
39325
39324
  timeline.scrollTop = maxScrollTop;
39326
39325
  timelineScrollAnchorRef.current = {
39327
- conversationId: activeConversationId,
39326
+ conversationId: scheduledConversationId,
39328
39327
  scrollHeight: geometry.scrollHeight,
39329
39328
  scrollTop: maxScrollTop,
39330
39329
  clientHeight: geometry.clientHeight
@@ -39335,7 +39334,8 @@ function useAgentGUIDetailScroll(input) {
39335
39334
  setIsTimelineScrolledToBottom(true);
39336
39335
  });
39337
39336
  };
39338
- syncBottomDockSpace();
39337
+ syncBottomDockSafeArea(false);
39338
+ syncConversationBottomLock();
39339
39339
  if (typeof ResizeObserver === "undefined") {
39340
39340
  return () => {
39341
39341
  timeline.style.removeProperty("--agent-gui-bottom-dock-safe-area");
@@ -39347,7 +39347,10 @@ function useAgentGUIDetailScroll(input) {
39347
39347
  }
39348
39348
  };
39349
39349
  }
39350
- const observer = new ResizeObserver(syncBottomDockSpace);
39350
+ const observer = new ResizeObserver(() => {
39351
+ syncBottomDockSafeArea(true);
39352
+ syncConversationBottomLock();
39353
+ });
39351
39354
  observer.observe(bottomDock);
39352
39355
  const promptInputArea = bottomDock.querySelector(
39353
39356
  ".agent-gui-node__composer-prompt-input-area"
@@ -39365,11 +39368,7 @@ function useAgentGUIDetailScroll(input) {
39365
39368
  }
39366
39369
  observer.disconnect();
39367
39370
  };
39368
- }, [
39369
- bottomDockStoreRevision,
39370
- timelineConversationId,
39371
- viewModel.rail.activeConversationId
39372
- ]);
39371
+ }, [bottomDockStoreRevision, hasTimelineConversation]);
39373
39372
  useEffect33(() => {
39374
39373
  const timeline = timelineRef.current;
39375
39374
  const timelineContent = timelineContentRef.current;
@@ -39377,8 +39376,10 @@ function useAgentGUIDetailScroll(input) {
39377
39376
  if (!timeline || !activeConversationId) {
39378
39377
  return;
39379
39378
  }
39380
- const loadOlderMessagesNearTop = (scrollTop, scrollHeight) => {
39381
- if (activeConversationId === viewModel.rail.activeConversationId && viewModel.detail.hasOlderMessages && !viewModel.detail.isLoadingOlderMessages && scrollTop <= AGENT_GUI_TOP_HISTORY_PREFETCH_THRESHOLD_PX) {
39379
+ const loadOlderMessagesNearTop = (scrollTop, scrollHeight, clientHeight) => {
39380
+ const bottomLocked = bottomLockOwnerRef.current === activeConversationId;
39381
+ const needsMoreContentToFillViewport = scrollHeight <= clientHeight;
39382
+ if (activeConversationId === viewModel.rail.activeConversationId && viewModel.detail.hasOlderMessages && !viewModel.detail.isLoadingOlderMessages && !showTimelineSkeleton && (!bottomLocked || needsMoreContentToFillViewport) && scrollTop <= AGENT_GUI_TOP_HISTORY_PREFETCH_THRESHOLD_PX) {
39382
39383
  pendingPrependScrollAnchorRef.current = {
39383
39384
  conversationId: activeConversationId,
39384
39385
  scrollHeight,
@@ -39392,13 +39393,22 @@ function useAgentGUIDetailScroll(input) {
39392
39393
  if (!previousAnchor || previousAnchor.conversationId !== activeConversationId) {
39393
39394
  return;
39394
39395
  }
39395
- const scrollTop = timeline.scrollTop;
39396
- const inferredUserScrollAway = scrollTop < previousAnchor.scrollTop - 1;
39396
+ let scrollTop = timeline.scrollTop;
39397
+ const pointerDrivenScrollAway = pointerScrollConversationRef.current === activeConversationId && scrollTop < previousAnchor.scrollTop - 1;
39397
39398
  const explicitUserScrollAway = userScrollAwayIntentConversationRef.current === activeConversationId;
39398
- if (explicitUserScrollAway || inferredUserScrollAway) {
39399
+ if (explicitUserScrollAway || pointerDrivenScrollAway) {
39399
39400
  bottomLockOwnerRef.current = null;
39400
39401
  userScrollAwayIntentConversationRef.current = null;
39401
39402
  }
39403
+ const bottomLocked = bottomLockOwnerRef.current === activeConversationId;
39404
+ const anchoredMaxScrollTop = Math.max(
39405
+ 0,
39406
+ previousAnchor.scrollHeight - previousAnchor.clientHeight
39407
+ );
39408
+ if (bottomLocked && anchoredMaxScrollTop - scrollTop > AGENT_GUI_STICK_TO_BOTTOM_THRESHOLD_PX) {
39409
+ setTimelineScrollTopInstantly(timeline, anchoredMaxScrollTop);
39410
+ scrollTop = anchoredMaxScrollTop;
39411
+ }
39402
39412
  timelineScrollAnchorRef.current = {
39403
39413
  conversationId: activeConversationId,
39404
39414
  scrollHeight: previousAnchor.scrollHeight,
@@ -39414,7 +39424,11 @@ function useAgentGUIDetailScroll(input) {
39414
39424
  scrollTop <= AGENT_GUI_TOP_MASK_SCROLL_EPSILON_PX
39415
39425
  );
39416
39426
  setIsTimelineScrolledToBottom(effectiveAtBottom);
39417
- loadOlderMessagesNearTop(scrollTop, previousAnchor.scrollHeight);
39427
+ loadOlderMessagesNearTop(
39428
+ scrollTop,
39429
+ previousAnchor.scrollHeight,
39430
+ previousAnchor.clientHeight
39431
+ );
39418
39432
  };
39419
39433
  const syncObservedTimelineGeometry = () => {
39420
39434
  const anchor = timelineScrollAnchorRef.current;
@@ -39454,16 +39468,38 @@ function useAgentGUIDetailScroll(input) {
39454
39468
  userScrollAwayIntentConversationRef.current = activeConversationId;
39455
39469
  }
39456
39470
  };
39471
+ const captureSemanticScrollAwayIntent = (event) => {
39472
+ if (event.target instanceof Element && event.target.closest("[data-agent-transcript-scroll-away-intent]")) {
39473
+ userScrollAwayIntentConversationRef.current = activeConversationId;
39474
+ }
39475
+ };
39476
+ const capturePointerIntent = () => {
39477
+ pointerScrollConversationRef.current = activeConversationId;
39478
+ };
39479
+ const clearPointerIntent = () => {
39480
+ if (pointerScrollConversationRef.current === activeConversationId) {
39481
+ pointerScrollConversationRef.current = null;
39482
+ }
39483
+ };
39457
39484
  const initialAnchor = timelineScrollAnchorRef.current;
39458
39485
  if (initialAnchor?.conversationId === activeConversationId) {
39459
39486
  loadOlderMessagesNearTop(
39460
39487
  initialAnchor.scrollTop,
39461
- initialAnchor.scrollHeight
39488
+ initialAnchor.scrollHeight,
39489
+ initialAnchor.clientHeight
39462
39490
  );
39463
39491
  }
39464
39492
  timeline.addEventListener("scroll", captureScrollAnchor, { passive: true });
39465
39493
  timeline.addEventListener("wheel", captureWheelIntent, { passive: true });
39466
39494
  timeline.addEventListener("keydown", captureKeyboardIntent);
39495
+ timeline.addEventListener("click", captureSemanticScrollAwayIntent);
39496
+ timeline.addEventListener("pointerdown", capturePointerIntent, {
39497
+ passive: true
39498
+ });
39499
+ window.addEventListener("pointerup", clearPointerIntent, { passive: true });
39500
+ window.addEventListener("pointercancel", clearPointerIntent, {
39501
+ passive: true
39502
+ });
39467
39503
  const geometryObserver = timelineContent && typeof ResizeObserver !== "undefined" ? new ResizeObserver(syncObservedTimelineGeometry) : null;
39468
39504
  geometryObserver?.observe(timeline);
39469
39505
  if (timelineContent) {
@@ -39474,10 +39510,15 @@ function useAgentGUIDetailScroll(input) {
39474
39510
  timeline.removeEventListener("scroll", captureScrollAnchor);
39475
39511
  timeline.removeEventListener("wheel", captureWheelIntent);
39476
39512
  timeline.removeEventListener("keydown", captureKeyboardIntent);
39513
+ timeline.removeEventListener("click", captureSemanticScrollAwayIntent);
39514
+ timeline.removeEventListener("pointerdown", capturePointerIntent);
39515
+ window.removeEventListener("pointerup", clearPointerIntent);
39516
+ window.removeEventListener("pointercancel", clearPointerIntent);
39477
39517
  };
39478
39518
  }, [
39479
39519
  actions,
39480
39520
  timelineConversationId,
39521
+ showTimelineSkeleton,
39481
39522
  viewModel.rail.activeConversationId,
39482
39523
  viewModel.detail.hasOlderMessages,
39483
39524
  viewModel.detail.isLoadingOlderMessages
@@ -44568,4 +44609,4 @@ export {
44568
44609
  AgentHandoffMenu,
44569
44610
  AgentGUI
44570
44611
  };
44571
- //# sourceMappingURL=chunk-RLFO3NJV.js.map
44612
+ //# sourceMappingURL=chunk-JOUEYIV3.js.map