@tutti-os/agent-gui 0.0.97 → 0.0.98

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/{AgentGUI-DWdvUV4x.d.ts → AgentGUI-Bkk2TRS0.d.ts} +37 -2
  2. package/dist/agent-conversation/index.d.ts +1 -1
  3. package/dist/agent-conversation/index.js +6 -6
  4. package/dist/agent-gui.d.ts +2 -2
  5. package/dist/agent-gui.js +15 -15
  6. package/dist/agent-message-center/index.js +7 -16
  7. package/dist/agent-message-center/index.js.map +1 -1
  8. package/dist/{agentGuiNodeTypes-B9X4aWfv.d.ts → agentGuiNodeTypes-DAsluxjv.d.ts} +1 -1
  9. package/dist/app/renderer/agentactivity.css +80 -10
  10. package/dist/{chunk-AO2FDYAL.js → chunk-3NOJFKDV.js} +3 -3
  11. package/dist/{chunk-XGGKHIQA.js → chunk-4ROALW3K.js} +2 -2
  12. package/dist/{chunk-4VBKQY24.js → chunk-63BE6RGM.js} +3 -3
  13. package/dist/{chunk-AAFTWZV7.js → chunk-7M77BK6K.js} +54 -91
  14. package/dist/chunk-7M77BK6K.js.map +1 -0
  15. package/dist/{chunk-BIS4QRX7.js → chunk-7O4D4KOE.js} +1230 -570
  16. package/dist/chunk-7O4D4KOE.js.map +1 -0
  17. package/dist/{chunk-4YVGHJIE.js → chunk-CPUEPDF7.js} +2 -2
  18. package/dist/{chunk-K2NURZ7V.js → chunk-FSKGEGGX.js} +11 -3
  19. package/dist/chunk-FSKGEGGX.js.map +1 -0
  20. package/dist/{chunk-NRJEKWLY.js → chunk-GAD6Y3BF.js} +2 -2
  21. package/dist/{chunk-3RYZYA72.js → chunk-J7ZYAUPC.js} +4 -4
  22. package/dist/{chunk-RE4AXS27.js → chunk-MRRICFWA.js} +2 -2
  23. package/dist/{chunk-74CPYRWJ.js → chunk-OTRZBTFQ.js} +2 -2
  24. package/dist/{chunk-TVIGLNNI.js → chunk-QWGJ5TEG.js} +4 -1
  25. package/dist/chunk-QWGJ5TEG.js.map +1 -0
  26. package/dist/{chunk-3EAANCKF.js → chunk-RHTZAODZ.js} +2 -2
  27. package/dist/{chunk-P2BCMPTX.js → chunk-SPZJCTBV.js} +3 -3
  28. package/dist/{chunk-SQTSLCMV.js → chunk-T6PEJFRP.js} +2 -2
  29. package/dist/{chunk-Y57VNTVM.js → chunk-Y5M6Q6WX.js} +2 -2
  30. package/dist/context-mention-palette/index.js +8 -8
  31. package/dist/i18n/index.d.ts +10 -2
  32. package/dist/i18n/index.js +2 -2
  33. package/dist/index.d.ts +4 -4
  34. package/dist/index.js +15 -15
  35. package/dist/index.js.map +1 -1
  36. package/dist/mention-search.js +6 -6
  37. package/dist/workbench/contribution.js +2 -2
  38. package/dist/workbench/index.js +5 -5
  39. package/dist/workbench/launch.js +1 -1
  40. package/dist/workbench/sessionTitle.js +3 -3
  41. package/dist/workspace-agent-generated-files.js +4 -4
  42. package/package.json +12 -12
  43. package/dist/chunk-AAFTWZV7.js.map +0 -1
  44. package/dist/chunk-BIS4QRX7.js.map +0 -1
  45. package/dist/chunk-K2NURZ7V.js.map +0 -1
  46. package/dist/chunk-TVIGLNNI.js.map +0 -1
  47. /package/dist/{chunk-AO2FDYAL.js.map → chunk-3NOJFKDV.js.map} +0 -0
  48. /package/dist/{chunk-XGGKHIQA.js.map → chunk-4ROALW3K.js.map} +0 -0
  49. /package/dist/{chunk-4VBKQY24.js.map → chunk-63BE6RGM.js.map} +0 -0
  50. /package/dist/{chunk-4YVGHJIE.js.map → chunk-CPUEPDF7.js.map} +0 -0
  51. /package/dist/{chunk-NRJEKWLY.js.map → chunk-GAD6Y3BF.js.map} +0 -0
  52. /package/dist/{chunk-3RYZYA72.js.map → chunk-J7ZYAUPC.js.map} +0 -0
  53. /package/dist/{chunk-RE4AXS27.js.map → chunk-MRRICFWA.js.map} +0 -0
  54. /package/dist/{chunk-74CPYRWJ.js.map → chunk-OTRZBTFQ.js.map} +0 -0
  55. /package/dist/{chunk-3EAANCKF.js.map → chunk-RHTZAODZ.js.map} +0 -0
  56. /package/dist/{chunk-P2BCMPTX.js.map → chunk-SPZJCTBV.js.map} +0 -0
  57. /package/dist/{chunk-SQTSLCMV.js.map → chunk-T6PEJFRP.js.map} +0 -0
  58. /package/dist/{chunk-Y57VNTVM.js.map → chunk-Y5M6Q6WX.js.map} +0 -0
@@ -9,7 +9,7 @@ import {
9
9
  resolveAgentGuiSessionProviderFlatIconUrl,
10
10
  resolveNextAgentGUIConversationRailWidthPx,
11
11
  shouldAutoCollapseAgentGUIConversationRail
12
- } from "./chunk-RE4AXS27.js";
12
+ } from "./chunk-MRRICFWA.js";
13
13
  import {
14
14
  AGENT_PROVIDERS,
15
15
  AGENT_PROVIDER_LABEL,
@@ -20,7 +20,7 @@ import {
20
20
  resolveAgentGUIExplicitConversationTitle,
21
21
  resolveAgentGUIProviderDisplayLabel,
22
22
  resolveAgentGUIProviderIdentity
23
- } from "./chunk-XGGKHIQA.js";
23
+ } from "./chunk-4ROALW3K.js";
24
24
  import {
25
25
  resolveAgentGuiWorkbenchProviderLabel
26
26
  } from "./chunk-L3GMMGRS.js";
@@ -64,14 +64,14 @@ import {
64
64
  toLocalShortDateTime,
65
65
  updateAgentComposerDraft,
66
66
  useProjectedAgentConversation
67
- } from "./chunk-AAFTWZV7.js";
67
+ } from "./chunk-7M77BK6K.js";
68
68
  import {
69
69
  openAgentEnvPanel
70
70
  } from "./chunk-7BXWPI4F.js";
71
71
  import {
72
72
  AgentFileMentionPalette,
73
73
  agentMentionItemKey
74
- } from "./chunk-3RYZYA72.js";
74
+ } from "./chunk-J7ZYAUPC.js";
75
75
  import {
76
76
  normalizeAgentGUIAgents,
77
77
  projectAgentGUIAgentsToInternalTargets
@@ -80,10 +80,10 @@ import {
80
80
  AGENT_MENTION_FILTER_TAB_ORDER,
81
81
  AgentMentionSearchController,
82
82
  DEFAULT_AGENT_MENTION_FILTER
83
- } from "./chunk-AO2FDYAL.js";
83
+ } from "./chunk-3NOJFKDV.js";
84
84
  import {
85
85
  buildWorkspaceAgentActivityListViewModel
86
- } from "./chunk-4VBKQY24.js";
86
+ } from "./chunk-63BE6RGM.js";
87
87
  import {
88
88
  AGENT_RICH_TEXT_CARET_ANCHOR,
89
89
  createAgentSessionMarkdownLink,
@@ -93,7 +93,7 @@ import {
93
93
  mentionItemToAttrs,
94
94
  normalizeAgentSessionMentionTitle,
95
95
  parseMentionItemFromHref
96
- } from "./chunk-4YVGHJIE.js";
96
+ } from "./chunk-CPUEPDF7.js";
97
97
  import {
98
98
  AgentInteractivePromptSurface,
99
99
  PLAN_IMPLEMENTATION_ACTION_FEEDBACK,
@@ -104,7 +104,7 @@ import {
104
104
  latestPlanTurnId,
105
105
  planImplementationPromptFromPlanTurn,
106
106
  useEngineSelector
107
- } from "./chunk-P2BCMPTX.js";
107
+ } from "./chunk-SPZJCTBV.js";
108
108
  import {
109
109
  AgentMessageMarkdown,
110
110
  AgentTargetPresentationProvider,
@@ -113,7 +113,7 @@ import {
113
113
  resolveAgentTargetPresentation,
114
114
  resolveWorkspaceLinkAction,
115
115
  useAgentTargetPresentations
116
- } from "./chunk-SQTSLCMV.js";
116
+ } from "./chunk-T6PEJFRP.js";
117
117
  import {
118
118
  resolveWorkspaceAgentSessionSortTimeUnixMs
119
119
  } from "./chunk-YMXYBG7U.js";
@@ -136,7 +136,7 @@ import {
136
136
  AgentGuiI18nProvider,
137
137
  translate,
138
138
  useTranslation
139
- } from "./chunk-3EAANCKF.js";
139
+ } from "./chunk-RHTZAODZ.js";
140
140
  import {
141
141
  migratedAgentGUIProviderIdentityCatalog,
142
142
  resolveAgentGUIProviderCatalogIdentity,
@@ -152,7 +152,7 @@ import { memo as memo15 } from "react";
152
152
  import { TooltipProvider as TooltipProvider5 } from "@tutti-os/ui-system";
153
153
 
154
154
  // agent-gui/agentGuiNode/AgentGUINode.tsx
155
- import { memo as memo14, useCallback as useCallback50, useEffect as useEffect38, useMemo as useMemo38 } from "react";
155
+ import { memo as memo14, useCallback as useCallback50, useEffect as useEffect39, useMemo as useMemo39 } from "react";
156
156
  import { createWorkspaceUserProjectI18nRuntime } from "@tutti-os/workspace-user-project/i18n";
157
157
  import { createWorkspaceFileManagerI18nRuntime } from "@tutti-os/workspace-file-manager";
158
158
 
@@ -2003,7 +2003,7 @@ var trafficLightIconPathByName = {
2003
2003
 
2004
2004
  // agent-gui/agentGuiNode/controller/useAgentGUINodeController.ts
2005
2005
  import { selectWorkspaceAgentConsumerSessions as selectWorkspaceAgentConsumerSessions2 } from "@tutti-os/agent-activity-core";
2006
- import { useCallback as useCallback24, useEffect as useEffect14, useMemo as useMemo17, useRef as useRef16 } from "react";
2006
+ import { useCallback as useCallback24, useEffect as useEffect14, useMemo as useMemo18, useRef as useRef16 } from "react";
2007
2007
 
2008
2008
  // host/agentHostAccountStore.ts
2009
2009
  import { create as create2 } from "zustand";
@@ -4052,12 +4052,15 @@ function sanitizeComposerSettingsForOptions(settings, options) {
4052
4052
  const reasoningEffort = normalizeOptionalText(settings.reasoningEffort);
4053
4053
  const speed = normalizeOptionalText(settings.speed);
4054
4054
  const permissionModeId = normalizeOptionalText(settings.permissionModeId);
4055
- const modelReasoningProfile = model ? options.reasoningOptionsByModel?.[model] : void 0;
4056
- const modelReasoningValues = modelReasoningProfile ? composerOptionValues(modelReasoningProfile.options) : null;
4055
+ const modelReasoningSelection = reasoningSelectionForModelFromComposerOptions(
4056
+ options,
4057
+ reasoningEffort,
4058
+ model
4059
+ );
4057
4060
  return {
4058
4061
  ...settings,
4059
4062
  model: options.behavior?.modelOptionsAuthoritative === true && model && modelValues.size > 0 && !modelValues.has(model) ? null : model,
4060
- reasoningEffort: options.reasoningConfigurable !== true ? null : reasoningEffort && modelReasoningValues !== null ? modelReasoningValues.has(reasoningEffort) ? reasoningEffort : null : reasoningEffort && reasoningValues.size > 0 && !reasoningValues.has(reasoningEffort) ? null : reasoningEffort,
4063
+ reasoningEffort: modelReasoningSelection !== null ? modelReasoningSelection.currentValue : options.reasoningConfigurable !== true ? null : reasoningEffort && reasoningValues.size > 0 && !reasoningValues.has(reasoningEffort) ? null : reasoningEffort,
4061
4064
  speed: speed && speedValues.size > 0 && !speedValues.has(speed) ? null : speed,
4062
4065
  permissionModeId: permissionModeId && permissionValues.size > 0 && !permissionValues.has(permissionModeId) ? null : permissionModeId
4063
4066
  };
@@ -4186,6 +4189,7 @@ function agentGUISessionStateDiagnosticDetails(state) {
4186
4189
  var AGENT_PROVIDER_SESSION_NOT_FOUND_ERROR = "agent.provider_session_not_found";
4187
4190
  var AGENT_RESUME_SESSION_NOT_LOCAL_ERROR = "agent.resume_session_not_local";
4188
4191
  var AGENT_SETTINGS_REQUIRE_NEW_SESSION_ERROR = "agent.settings_require_new_session";
4192
+ var AGENT_SESSION_TITLE_TOO_LONG_REASON = "workspace_agent_session_title_too_long";
4189
4193
  var AGENT_PROVIDER_SESSION_NOT_FOUND_FALLBACK_MESSAGE = "The previous agent session can no longer be restored.";
4190
4194
  var AGENT_RESUME_SESSION_NOT_LOCAL_FALLBACK_MESSAGE = "The previous agent session is not available on this machine.";
4191
4195
  var AGENT_GUI_CAUGHT_ERROR_STACK_LIMIT = 4e3;
@@ -4287,6 +4291,10 @@ function getAgentGUIErrorMessage(error) {
4287
4291
  return translate("messages.agentResumeSessionNotLocal");
4288
4292
  if (isSettingsRequireNewSessionErrorCode(code))
4289
4293
  return translate("messages.agentSettingsRequireNewSession");
4294
+ if (getAgentGUIErrorReason(error) === AGENT_SESSION_TITLE_TOO_LONG_REASON) {
4295
+ const maxCharacters = getAgentGUIErrorNumberParam(error, "maxCharacters");
4296
+ return maxCharacters === null ? translate("messages.agentSessionTitleTooLongWithoutLimit") : translate("messages.agentSessionTitleTooLong", { maxCharacters });
4297
+ }
4290
4298
  if (error && typeof error === "object") {
4291
4299
  const debugMessage = error.debugMessage;
4292
4300
  if (typeof debugMessage === "string" && debugMessage.trim())
@@ -4294,6 +4302,13 @@ function getAgentGUIErrorMessage(error) {
4294
4302
  }
4295
4303
  return error instanceof Error ? error.message : String(error);
4296
4304
  }
4305
+ function getAgentGUIErrorNumberParam(error, key) {
4306
+ if (!error || typeof error !== "object") return null;
4307
+ const params = error.params;
4308
+ if (!params || typeof params !== "object") return null;
4309
+ const value = params[key];
4310
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
4311
+ }
4297
4312
  function getAgentGUIRawErrorMessage(error) {
4298
4313
  if (error && typeof error === "object") {
4299
4314
  const debugMessage = error.debugMessage;
@@ -4348,7 +4363,57 @@ function token(value) {
4348
4363
  }
4349
4364
 
4350
4365
  // agent-gui/agentGuiNode/controller/useAgentConversationMessagePaging.ts
4351
- import { useCallback as useCallback2, useRef as useRef3 } from "react";
4366
+ import { useCallback as useCallback2, useMemo as useMemo2, useRef as useRef3 } from "react";
4367
+
4368
+ // agent-gui/agentGuiNode/controller/AgentConversationOlderPagingState.ts
4369
+ var AgentConversationOlderPagingState = class {
4370
+ entries = /* @__PURE__ */ new Map();
4371
+ nextRequestId = 0;
4372
+ begin(agentSessionId, beforeVersion) {
4373
+ const current = this.entries.get(agentSessionId);
4374
+ if (current?.phase === "in_flight" || current?.phase === "exhausted" || current?.beforeVersion === beforeVersion) {
4375
+ return { kind: "suppressed", entry: current };
4376
+ }
4377
+ const request = {
4378
+ agentSessionId,
4379
+ beforeVersion,
4380
+ requestId: ++this.nextRequestId
4381
+ };
4382
+ this.entries.set(agentSessionId, { ...request, phase: "in_flight" });
4383
+ return { kind: "started", request };
4384
+ }
4385
+ abandon(request) {
4386
+ if (!this.isCurrent(request)) return false;
4387
+ this.entries.delete(request.agentSessionId);
4388
+ return true;
4389
+ }
4390
+ fail(request) {
4391
+ if (!this.isCurrent(request)) return false;
4392
+ this.entries.set(request.agentSessionId, { ...request, phase: "failed" });
4393
+ return true;
4394
+ }
4395
+ resolve(request, exhausted) {
4396
+ if (!this.isCurrent(request)) return false;
4397
+ if (exhausted) {
4398
+ this.entries.set(request.agentSessionId, {
4399
+ ...request,
4400
+ phase: "exhausted"
4401
+ });
4402
+ } else {
4403
+ this.entries.delete(request.agentSessionId);
4404
+ }
4405
+ return true;
4406
+ }
4407
+ reset(agentSessionId) {
4408
+ this.entries.delete(agentSessionId);
4409
+ }
4410
+ isCurrent(request) {
4411
+ const current = this.entries.get(request.agentSessionId);
4412
+ return current?.phase === "in_flight" && current.beforeVersion === request.beforeVersion && current.requestId === request.requestId;
4413
+ }
4414
+ };
4415
+
4416
+ // agent-gui/agentGuiNode/controller/useAgentConversationMessagePaging.ts
4352
4417
  var PAGE_SIZE = 100;
4353
4418
  function minFiniteMessageVersion(messages) {
4354
4419
  let result = null;
@@ -4412,14 +4477,20 @@ function sessionHasRenderableMessages(input) {
4412
4477
  function useAgentConversationMessagePaging(input) {
4413
4478
  const inputRef = useRef3(input);
4414
4479
  inputRef.current = input;
4415
- const olderLoadSequenceRef = useRef3(0);
4416
- const failedOlderCursorBySessionIdRef = useRef3(/* @__PURE__ */ new Map());
4417
- const loadInitialMessages = useCallback2(async (agentSessionId) => {
4418
- const normalized = agentSessionId.trim();
4419
- if (!normalized) return;
4420
- const current = inputRef.current;
4421
- current.reload.reconcileDetail(normalized);
4422
- }, []);
4480
+ const olderPagingState = useMemo2(
4481
+ () => new AgentConversationOlderPagingState(),
4482
+ []
4483
+ );
4484
+ const loadInitialMessages = useCallback2(
4485
+ async (agentSessionId) => {
4486
+ const normalized = agentSessionId.trim();
4487
+ if (!normalized) return;
4488
+ olderPagingState.reset(normalized);
4489
+ const current = inputRef.current;
4490
+ current.reload.reconcileDetail(normalized);
4491
+ },
4492
+ [olderPagingState]
4493
+ );
4423
4494
  const loadOlderMessages = useCallback2(
4424
4495
  async (agentSessionId) => {
4425
4496
  const current = inputRef.current;
@@ -4431,7 +4502,7 @@ function useAgentConversationMessagePaging(input) {
4431
4502
  current.getCanonicalMessages(normalized)
4432
4503
  );
4433
4504
  const oldestLoadedVersion = view?.oldestLoadedVersion ?? canonicalOldestVersion;
4434
- const hasOlderMessages = view?.hasOlderMessages === true || canonicalOldestVersion !== null && canonicalOldestVersion > 1;
4505
+ const hasOlderMessages = view?.hasOlderMessages === true || view?.oldestLoadedVersion == null && canonicalOldestVersion !== null && canonicalOldestVersion > 1;
4435
4506
  if (!hasOlderMessages || view?.isLoadingOlderMessages === true || oldestLoadedVersion === null || current.getActiveSessionId() !== normalized) {
4436
4507
  current.diagnostics.page({
4437
4508
  agentSessionId: normalized,
@@ -4447,16 +4518,36 @@ function useAgentConversationMessagePaging(input) {
4447
4518
  return;
4448
4519
  }
4449
4520
  const beforeVersion = oldestLoadedVersion;
4450
- if (failedOlderCursorBySessionIdRef.current.get(normalized) === beforeVersion) {
4451
- current.diagnostics.page({
4452
- agentSessionId: normalized,
4521
+ const beginResult = olderPagingState.begin(normalized, beforeVersion);
4522
+ if (beginResult.kind === "suppressed") {
4523
+ const { entry } = beginResult;
4524
+ const suppression = entry.phase === "in_flight" ? {
4525
+ details: {
4526
+ beforeVersion,
4527
+ inFlightBeforeVersion: entry.beforeVersion,
4528
+ inFlightRequestId: entry.requestId,
4529
+ reason: "in_flight_request"
4530
+ },
4531
+ event: "agent.gui.messages.older.suppressed_in_flight",
4532
+ level: void 0
4533
+ } : entry.phase === "exhausted" ? {
4534
+ details: { beforeVersion, reason: "exhausted_cursor" },
4535
+ event: "agent.gui.messages.older.suppressed_exhausted_cursor",
4536
+ level: void 0
4537
+ } : {
4453
4538
  details: { beforeVersion, reason: "previous_cursor_error" },
4454
4539
  event: "agent.gui.messages.older.suppressed_after_error",
4455
4540
  level: "warn"
4541
+ };
4542
+ current.diagnostics.page({
4543
+ agentSessionId: normalized,
4544
+ details: suppression.details,
4545
+ event: suppression.event,
4546
+ level: suppression.level
4456
4547
  });
4457
4548
  return;
4458
4549
  }
4459
- const requestId = ++olderLoadSequenceRef.current;
4550
+ const { request } = beginResult;
4460
4551
  current.view.setOlderMessagesLoading(ref, true);
4461
4552
  try {
4462
4553
  current.diagnostics.page({
@@ -4465,7 +4556,7 @@ function useAgentConversationMessagePaging(input) {
4465
4556
  beforeVersion,
4466
4557
  limit: PAGE_SIZE,
4467
4558
  order: "desc",
4468
- requestId
4559
+ requestId: request.requestId
4469
4560
  },
4470
4561
  event: "agent.gui.messages.older.requested"
4471
4562
  });
@@ -4477,8 +4568,10 @@ function useAgentConversationMessagePaging(input) {
4477
4568
  limit: PAGE_SIZE,
4478
4569
  order: "desc"
4479
4570
  });
4480
- if (!current.isMounted() || current.getActiveSessionId() !== normalized || olderLoadSequenceRef.current !== requestId) {
4481
- current.view.setOlderMessagesLoading(ref, false);
4571
+ if (!current.isMounted() || current.getActiveSessionId() !== normalized) {
4572
+ if (olderPagingState.abandon(request)) {
4573
+ current.view.setOlderMessagesLoading(ref, false);
4574
+ }
4482
4575
  return;
4483
4576
  }
4484
4577
  current.diagnostics.page({
@@ -4487,31 +4580,39 @@ function useAgentConversationMessagePaging(input) {
4487
4580
  beforeVersion,
4488
4581
  hasMore: page.hasMore,
4489
4582
  latestVersion: page.latestVersion,
4490
- requestId
4583
+ requestId: request.requestId
4491
4584
  },
4492
4585
  event: "agent.gui.messages.older.resolved",
4493
4586
  messages: page.messages
4494
4587
  });
4495
- failedOlderCursorBySessionIdRef.current.delete(normalized);
4588
+ if (!olderPagingState.resolve(
4589
+ request,
4590
+ !page.hasMore || page.messages.length === 0
4591
+ )) {
4592
+ return;
4593
+ }
4496
4594
  current.view.mergeOlder(ref, page.messages, {
4497
4595
  hasOlderMessages: page.hasMore && page.messages.length > 0
4498
4596
  });
4597
+ current.view.setOlderMessagesLoading(ref, false);
4499
4598
  } catch (error) {
4500
- if (!current.isMounted() || current.getActiveSessionId() !== normalized || olderLoadSequenceRef.current !== requestId) {
4501
- current.view.setOlderMessagesLoading(ref, false);
4599
+ if (!current.isMounted() || current.getActiveSessionId() !== normalized) {
4600
+ if (olderPagingState.abandon(request)) {
4601
+ current.view.setOlderMessagesLoading(ref, false);
4602
+ }
4502
4603
  return;
4503
4604
  }
4504
- failedOlderCursorBySessionIdRef.current.set(normalized, beforeVersion);
4605
+ if (!olderPagingState.fail(request)) return;
4505
4606
  current.diagnostics.error({
4506
4607
  agentSessionId: normalized,
4507
- context: { beforeVersion, requestId },
4608
+ context: { beforeVersion, requestId: request.requestId },
4508
4609
  error,
4509
4610
  phase: "load_session_messages"
4510
4611
  });
4511
4612
  current.view.setOlderMessagesLoading(ref, false);
4512
4613
  }
4513
4614
  },
4514
- []
4615
+ [olderPagingState]
4515
4616
  );
4516
4617
  const reloadSelectedConversation = useCallback2(
4517
4618
  (agentSessionId, options) => {
@@ -5430,7 +5531,7 @@ import {
5430
5531
  selectSessionActivationPresentations,
5431
5532
  sessionActivationPresentationMapsEqual
5432
5533
  } from "@tutti-os/agent-activity-core";
5433
- import { useCallback as useCallback4, useMemo as useMemo2, useRef as useRef5 } from "react";
5534
+ import { useCallback as useCallback4, useMemo as useMemo3, useRef as useRef5 } from "react";
5434
5535
  var ACTIVATION_EXPIRY_MS = 45e3;
5435
5536
  function isPendingNewConversationActivation(activation) {
5436
5537
  return activation?.mode === "new" && (activation.status === "requested" || activation.status === "uncertain");
@@ -5567,7 +5668,7 @@ function useAgentGUIActivation({
5567
5668
  (agentSessionId) => (agentSessionId ? presentations[agentSessionId]?.errorCode : null) ?? null,
5568
5669
  [presentations]
5569
5670
  );
5570
- return useMemo2(
5671
+ return useMemo3(
5571
5672
  () => ({
5572
5673
  activate,
5573
5674
  clearFailure,
@@ -5590,7 +5691,7 @@ function useAgentGUIActivation({
5590
5691
  }
5591
5692
 
5592
5693
  // agent-gui/agentGuiNode/controller/useAgentGUIActiveMessages.ts
5593
- import { useMemo as useMemo3 } from "react";
5694
+ import { useMemo as useMemo4 } from "react";
5594
5695
 
5595
5696
  // host/workspaceAgentSessionMessages.ts
5596
5697
  import {
@@ -5635,7 +5736,7 @@ function useAgentGUIActiveMessages(input) {
5635
5736
  storedMessages,
5636
5737
  workspaceId
5637
5738
  } = input;
5638
- const activeMessages = useMemo3(() => {
5739
+ const activeMessages = useMemo4(() => {
5639
5740
  if (!activeConversationId) return storedMessages;
5640
5741
  const visibleQueuedSubmitIds = new Set(
5641
5742
  activeQueuedPrompts.map(
@@ -5679,7 +5780,7 @@ function useAgentGUIActiveMessages(input) {
5679
5780
  storedMessages,
5680
5781
  workspaceId
5681
5782
  ]);
5682
- const activeTimelineItems = useMemo3(
5783
+ const activeTimelineItems = useMemo4(
5683
5784
  () => projectAgentGUIMessagesToTimelineItems(activeMessages),
5684
5785
  [activeMessages]
5685
5786
  );
@@ -6090,10 +6191,10 @@ function useAgentGUIConversationSelectionController(input) {
6090
6191
  import {
6091
6192
  selectAttentionReadState
6092
6193
  } from "@tutti-os/agent-activity-core";
6093
- import { useMemo as useMemo5, useRef as useRef7, useState as useState3 } from "react";
6194
+ import { useMemo as useMemo6, useRef as useRef7, useState as useState3 } from "react";
6094
6195
 
6095
6196
  // contexts/workspace/presentation/renderer/agentGuiConversationList/useAgentGuiConversationList.ts
6096
- import { useMemo as useMemo4 } from "react";
6197
+ import { useMemo as useMemo5 } from "react";
6097
6198
  import {
6098
6199
  selectWorkspaceAgentConsumerSessions,
6099
6200
  selectPendingActivations,
@@ -6143,7 +6244,7 @@ function useAgentGuiConversationList(engine, query, agentTargets = []) {
6143
6244
  selectPendingActivations,
6144
6245
  pendingActivationsEqual
6145
6246
  );
6146
- return useMemo4(() => {
6247
+ return useMemo5(() => {
6147
6248
  if (!query) return null;
6148
6249
  const canonicalIds = new Set(
6149
6250
  sessions.map((item) => item.session.agentSessionId)
@@ -6256,7 +6357,7 @@ function useAgentGUIConversationListState({
6256
6357
  );
6257
6358
  const conversationFilterRef = useRef7(conversationFilter);
6258
6359
  conversationFilterRef.current = conversationFilter;
6259
- const conversationListQuery = useMemo5(() => {
6360
+ const conversationListQuery = useMemo6(() => {
6260
6361
  const userId = currentUserId?.trim() ?? "";
6261
6362
  const provider = data.provider?.trim() ?? "";
6262
6363
  if (!workspaceId.trim() || !userId || !provider) {
@@ -6286,7 +6387,7 @@ function useAgentGUIConversationListState({
6286
6387
  sessionEngine,
6287
6388
  (state) => selectAttentionReadState(state, currentUserId)
6288
6389
  );
6289
- const conversations = useMemo5(() => {
6390
+ const conversations = useMemo6(() => {
6290
6391
  return canonicalConversations.map((conversation) => {
6291
6392
  const projectedTitle = resolveAgentGUIConversationTitleFromTimelineItems({
6292
6393
  conversation,
@@ -6325,16 +6426,19 @@ import {
6325
6426
  resolveAgentActivityCapability as resolveAgentActivityCapability2,
6326
6427
  resolveAgentActivityUsage
6327
6428
  } from "@tutti-os/agent-activity-core";
6328
- import { useMemo as useMemo6 } from "react";
6429
+ import { useMemo as useMemo7 } from "react";
6329
6430
 
6330
6431
  // agent-gui/agentGuiNode/model/composerSettingsSupport.ts
6331
6432
  import {
6332
6433
  resolveAgentActivityCapability
6333
6434
  } from "@tutti-os/agent-activity-core";
6334
6435
  function composerSettingsSupportFromOptions(composerOptions, sessionCapabilities) {
6436
+ const hasModelReasoningOptions = Object.values(
6437
+ composerOptions?.reasoningOptionsByModel ?? {}
6438
+ ).some((profile) => profile.options.length > 0);
6335
6439
  return {
6336
6440
  model: composerOptions?.modelConfigurable ?? false,
6337
- reasoning: composerOptions?.reasoningConfigurable ?? false,
6441
+ reasoning: (composerOptions?.reasoningConfigurable ?? false) || hasModelReasoningOptions,
6338
6442
  speed: composerOptions?.speedConfigurable ?? false,
6339
6443
  permission: composerOptions?.permissionConfig?.configurable ?? false,
6340
6444
  plan: resolveAgentActivityCapability("planMode", {
@@ -6406,7 +6510,7 @@ function useAgentGUIComposerCapabilities(input) {
6406
6510
  const selectedModelImageInputSupported = !modelImageInputRequired ? true : selectedModelForPromptImages !== null && (providerComposerOptions?.models.find(
6407
6511
  (option) => option.value === selectedModelForPromptImages
6408
6512
  )?.supportsImageInput ?? false);
6409
- const composerSupport = useMemo6(() => {
6513
+ const composerSupport = useMemo7(() => {
6410
6514
  const fallback = composerSettingsSupportFromOptions(
6411
6515
  providerComposerOptions,
6412
6516
  sessionCapabilities
@@ -6421,6 +6525,11 @@ function useAgentGUIComposerCapabilities(input) {
6421
6525
  planImplementation: sessionCapabilities?.planImplementation ?? fallback.planImplementation
6422
6526
  };
6423
6527
  }, [providerComposerOptions, sessionCapabilities]);
6528
+ const usageSource = input.activeEngineSession?.usage ?? null;
6529
+ const usage = useMemo7(
6530
+ () => resolveAgentActivityUsage({ sessionUsage: usageSource }),
6531
+ [usageSource]
6532
+ );
6424
6533
  return {
6425
6534
  backgroundAgentCount: input.activeEngineSession?.backgroundAgents?.count ?? 0,
6426
6535
  compactSupported: sessionCapabilities?.compact ?? resolveAgentActivityCapability2("compact", {
@@ -6437,9 +6546,7 @@ function useAgentGUIComposerCapabilities(input) {
6437
6546
  }) ?? false,
6438
6547
  promptImagesSupported: (resolvedPromptImagesSupported ?? true) && selectedModelImageInputSupported,
6439
6548
  providerComposerOptions,
6440
- usage: resolveAgentActivityUsage({
6441
- sessionUsage: input.activeEngineSession?.usage ?? null
6442
- })
6549
+ usage
6443
6550
  };
6444
6551
  }
6445
6552
 
@@ -8809,12 +8916,12 @@ function useAgentGUIOperationActions(input) {
8809
8916
  }
8810
8917
 
8811
8918
  // agent-gui/agentGuiNode/controller/useAgentGUIViewAssembly.ts
8812
- import { useMemo as useMemo13 } from "react";
8919
+ import { useMemo as useMemo14 } from "react";
8813
8920
 
8814
8921
  // agent-gui/agentGuiNode/model/useAgentGUIViewModel.ts
8815
- import { useMemo as useMemo7 } from "react";
8922
+ import { useMemo as useMemo8 } from "react";
8816
8923
  function useAgentGUIViewModel(candidate) {
8817
- const shell = useMemo7(
8924
+ const shell = useMemo8(
8818
8925
  () => candidate.shell,
8819
8926
  [
8820
8927
  candidate.shell.currentUserId,
@@ -8823,7 +8930,7 @@ function useAgentGUIViewModel(candidate) {
8823
8930
  candidate.shell.workspacePath
8824
8931
  ]
8825
8932
  );
8826
- const rail = useMemo7(
8933
+ const rail = useMemo8(
8827
8934
  () => candidate.rail,
8828
8935
  [
8829
8936
  candidate.rail.activeConversation,
@@ -8840,7 +8947,7 @@ function useAgentGUIViewModel(candidate) {
8840
8947
  candidate.rail.userProjects
8841
8948
  ]
8842
8949
  );
8843
- const detail = useMemo7(
8950
+ const detail = useMemo8(
8844
8951
  () => candidate.detail,
8845
8952
  [
8846
8953
  candidate.detail.availability,
@@ -8855,7 +8962,7 @@ function useAgentGUIViewModel(candidate) {
8855
8962
  candidate.detail.usage
8856
8963
  ]
8857
8964
  );
8858
- const composer = useMemo7(
8965
+ const composer = useMemo8(
8859
8966
  () => candidate.composer,
8860
8967
  [
8861
8968
  candidate.composer.availableCommands,
@@ -8878,7 +8985,7 @@ function useAgentGUIViewModel(candidate) {
8878
8985
  candidate.composer.queuedPrompts
8879
8986
  ]
8880
8987
  );
8881
- const interaction = useMemo7(
8988
+ const interaction = useMemo8(
8882
8989
  () => candidate.interaction,
8883
8990
  [
8884
8991
  candidate.interaction.inlineNotice,
@@ -8888,7 +8995,7 @@ function useAgentGUIViewModel(candidate) {
8888
8995
  candidate.interaction.sessionChrome
8889
8996
  ]
8890
8997
  );
8891
- const readiness = useMemo7(
8998
+ const readiness = useMemo8(
8892
8999
  () => candidate.readiness,
8893
9000
  [
8894
9001
  candidate.readiness.activationError,
@@ -8897,7 +9004,7 @@ function useAgentGUIViewModel(candidate) {
8897
9004
  candidate.readiness.providerReadinessGate
8898
9005
  ]
8899
9006
  );
8900
- const operations = useMemo7(
9007
+ const operations = useMemo8(
8901
9008
  () => candidate.operations,
8902
9009
  [
8903
9010
  candidate.operations.isDeletingConversation,
@@ -8906,7 +9013,7 @@ function useAgentGUIViewModel(candidate) {
8906
9013
  candidate.operations.pendingDeleteProjectConversations
8907
9014
  ]
8908
9015
  );
8909
- return useMemo7(
9016
+ return useMemo8(
8910
9017
  () => ({
8911
9018
  shell,
8912
9019
  rail,
@@ -8921,7 +9028,7 @@ function useAgentGUIViewModel(candidate) {
8921
9028
  }
8922
9029
 
8923
9030
  // agent-gui/agentGuiNode/controller/useAgentGUIComposerPresentation.ts
8924
- import { useEffect as useEffect8, useMemo as useMemo8 } from "react";
9031
+ import { useEffect as useEffect8, useMemo as useMemo9 } from "react";
8925
9032
 
8926
9033
  // agent-gui/agentGuiNode/model/agentBrowserUseSubmit.ts
8927
9034
  var TUTTI_BROWSER_USE_SUBMIT_PREFIX = "Use the injected browser-use skill and only the tutti browser CLI. Do not use any other browser skill, CDP scripts, or direct browser automation.";
@@ -9443,7 +9550,7 @@ function useAgentGUIComposerPresentation(input) {
9443
9550
  const draftSpeed = normalizeOptionalText(
9444
9551
  draftSettings.speed
9445
9552
  );
9446
- const activeSessionReasoningSelection = useMemo8(
9553
+ const activeSessionReasoningSelection = useMemo9(
9447
9554
  () => reasoningSelectionFromComposerOptions(
9448
9555
  input.providerComposerOptions,
9449
9556
  draftReasoningEffort,
@@ -9451,21 +9558,22 @@ function useAgentGUIComposerPresentation(input) {
9451
9558
  ),
9452
9559
  [draftModel, draftReasoningEffort, input.providerComposerOptions]
9453
9560
  );
9454
- const activeSessionModelSelection = useMemo8(
9561
+ const presentedReasoningEffort = activeSessionReasoningSelection ? activeSessionReasoningSelection.currentValue : draftReasoningEffort;
9562
+ const activeSessionModelSelection = useMemo9(
9455
9563
  () => modelSelectionFromComposerOptions(
9456
9564
  input.providerComposerOptions,
9457
9565
  draftModel
9458
9566
  ),
9459
9567
  [draftModel, input.providerComposerOptions]
9460
9568
  );
9461
- const activeSessionSpeedSelection = useMemo8(
9569
+ const activeSessionSpeedSelection = useMemo9(
9462
9570
  () => speedSelectionFromComposerOptions(
9463
9571
  input.providerComposerOptions,
9464
9572
  draftSpeed
9465
9573
  ),
9466
9574
  [draftSpeed, input.providerComposerOptions]
9467
9575
  );
9468
- const composerSettings = useMemo8(() => {
9576
+ const composerSettings = useMemo9(() => {
9469
9577
  const permissionConfig = permissionConfigFromComposerOptions(
9470
9578
  input.providerComposerOptions
9471
9579
  );
@@ -9479,7 +9587,7 @@ function useAgentGUIComposerPresentation(input) {
9479
9587
  sessionSettings,
9480
9588
  draftSettings: {
9481
9589
  model: draftModel,
9482
- reasoningEffort: draftReasoningEffort,
9590
+ reasoningEffort: presentedReasoningEffort,
9483
9591
  speed: draftSpeed,
9484
9592
  planMode: Boolean(draftSettings.planMode),
9485
9593
  browserUse: draftSettings.browserUse ?? true,
@@ -9512,7 +9620,7 @@ function useAgentGUIComposerPresentation(input) {
9512
9620
  speedUnavailable: input.activeConversationId !== null && sessionSettings === null && input.composerSupport.speed && draftSpeed === null,
9513
9621
  permissionModeUnavailable: input.activeConversationId !== null && sessionSettings === null && supportsPermissionMode && selectedPermissionModeValue === null,
9514
9622
  selectedModelValue: draftModel,
9515
- selectedReasoningEffortValue: activeSessionReasoningSelection?.currentValue ?? draftReasoningEffort,
9623
+ selectedReasoningEffortValue: presentedReasoningEffort,
9516
9624
  selectedSpeedValue: draftSpeed,
9517
9625
  selectedPermissionModeValue,
9518
9626
  permissionConfig,
@@ -9541,6 +9649,7 @@ function useAgentGUIComposerPresentation(input) {
9541
9649
  input.composerTargetProvider,
9542
9650
  input.providerComposerOptions,
9543
9651
  input.selectedProjectPath,
9652
+ presentedReasoningEffort,
9544
9653
  sessionSettings
9545
9654
  ]);
9546
9655
  return {
@@ -9554,7 +9663,7 @@ function useAgentGUIComposerPresentation(input) {
9554
9663
  }
9555
9664
 
9556
9665
  // agent-gui/agentGuiNode/controller/useAgentGUIControllerActions.ts
9557
- import { useMemo as useMemo9 } from "react";
9666
+ import { useMemo as useMemo10 } from "react";
9558
9667
  function useAgentGUIControllerActions(actions) {
9559
9668
  const updateConversationFilter = useStableControllerEventCallback(
9560
9669
  actions.updateConversationFilter
@@ -9640,7 +9749,7 @@ function useAgentGUIControllerActions(actions) {
9640
9749
  const confirmDeleteConversation = useStableControllerEventCallback(
9641
9750
  actions.confirmDeleteConversation
9642
9751
  );
9643
- return useMemo9(
9752
+ return useMemo10(
9644
9753
  () => ({
9645
9754
  updateConversationFilter,
9646
9755
  selectConversationFilterTarget,
@@ -9712,13 +9821,13 @@ function useAgentGUIControllerActions(actions) {
9712
9821
  import {
9713
9822
  selectEngineAvailableCommands
9714
9823
  } from "@tutti-os/agent-activity-core";
9715
- import { useEffect as useEffect9, useMemo as useMemo10, useRef as useRef10 } from "react";
9824
+ import { useEffect as useEffect9, useMemo as useMemo11, useRef as useRef10 } from "react";
9716
9825
  function useAgentGUIConversationDetail(input) {
9717
9826
  const projectionConversationRef = useRef10(null);
9718
9827
  const activeCanonicalLiveTurn = Boolean(
9719
9828
  input.activeTurn && input.activeTurn.phase !== "settled"
9720
9829
  );
9721
- const projectionConversation = useMemo10(() => {
9830
+ const projectionConversation = useMemo11(() => {
9722
9831
  if (!input.activeConversation) {
9723
9832
  projectionConversationRef.current = null;
9724
9833
  return null;
@@ -9751,17 +9860,17 @@ function useAgentGUIConversationDetail(input) {
9751
9860
  input.sessionEngine,
9752
9861
  (state) => selectEngineAvailableCommands(state, input.activeConversationId)
9753
9862
  );
9754
- const availableCommands = useMemo10(
9863
+ const availableCommands = useMemo11(
9755
9864
  () => (engineAvailableCommands.length > 0 ? engineAvailableCommands : input.providerComposerOptions?.commands ?? []).map((command) => ({ ...command })),
9756
- [engineAvailableCommands, input.providerComposerOptions]
9865
+ [engineAvailableCommands, input.providerComposerOptions?.commands]
9757
9866
  );
9758
9867
  const availableSkills = useStableProviderSkillOptions(
9759
- useMemo10(
9868
+ useMemo11(
9760
9869
  () => providerSkillsFromComposerOptions(input.providerComposerOptions),
9761
9870
  [input.providerComposerOptions]
9762
9871
  )
9763
9872
  );
9764
- const conversationModels = useMemo10(
9873
+ const conversationModels = useMemo11(
9765
9874
  () => projectionConversation ? buildAgentGUIConversationModels({
9766
9875
  timelineItems: input.activeTimelineItems,
9767
9876
  conversation: projectionConversation,
@@ -9778,7 +9887,7 @@ function useAgentGUIConversationDetail(input) {
9778
9887
  const conversationDetail = useStableConversationDetail(
9779
9888
  conversationModels.detail
9780
9889
  );
9781
- const conversation = useMemo10(() => {
9890
+ const conversation = useMemo11(() => {
9782
9891
  if (!conversationModels.conversation) return null;
9783
9892
  if (conversationDetail && (conversationModels.conversation.sourceDetail !== conversationDetail || conversationModels.conversation.activity !== conversationDetail.activity)) {
9784
9893
  return {
@@ -9840,20 +9949,23 @@ function useAgentGUIConversationDetail(input) {
9840
9949
  const activationError = input.errorFor(input.activeConversationId);
9841
9950
  const activationErrorCode = input.codeFor(input.activeConversationId);
9842
9951
  const hasProviderSessionNotFoundError = isNonRetryableResumeErrorCode(activationErrorCode);
9843
- const rawPendingApproval = useMemo10(() => {
9952
+ const rawPendingApproval = useMemo11(() => {
9844
9953
  const interaction = [...input.activePendingInteractions].reverse().find((candidate) => candidate.kind === "approval") ?? null;
9845
9954
  return interactiveApprovalFromInteraction(interaction);
9846
9955
  }, [input.activePendingInteractions]);
9847
- const rawPendingInteractivePrompt = useMemo10(() => {
9956
+ const rawPendingInteractivePrompt = useMemo11(() => {
9848
9957
  const interaction = [...input.activePendingInteractions].reverse().find((candidate) => candidate.kind !== "approval") ?? null;
9849
9958
  return interactivePromptFromInteraction(interaction);
9850
9959
  }, [input.activePendingInteractions]);
9851
- const queuedPrompts = input.activeConversationId ? input.activeQueuedPrompts.map((prompt) => ({
9852
- id: prompt.id,
9853
- content: [...prompt.content],
9854
- ...prompt.displayPrompt ? { displayPrompt: prompt.displayPrompt } : {},
9855
- createdAtUnixMs: prompt.createdAtUnixMs
9856
- })) : [];
9960
+ const queuedPrompts = useMemo11(
9961
+ () => input.activeConversationId ? input.activeQueuedPrompts.map((prompt) => ({
9962
+ id: prompt.id,
9963
+ content: [...prompt.content],
9964
+ ...prompt.displayPrompt ? { displayPrompt: prompt.displayPrompt } : {},
9965
+ createdAtUnixMs: prompt.createdAtUnixMs
9966
+ })) : [],
9967
+ [input.activeConversationId, input.activeQueuedPrompts]
9968
+ );
9857
9969
  return {
9858
9970
  activeLiveState,
9859
9971
  activationError,
@@ -9877,19 +9989,54 @@ function useAgentGUIConversationDetail(input) {
9877
9989
  }
9878
9990
 
9879
9991
  // agent-gui/agentGuiNode/controller/useAgentGUIConversationPresentation.ts
9880
- import { useEffect as useEffect10, useMemo as useMemo11, useRef as useRef11 } from "react";
9992
+ import { useEffect as useEffect10, useMemo as useMemo12, useRef as useRef11 } from "react";
9881
9993
  function useAgentGUIConversationPresentation(input) {
9882
- const activeConversation = useMemo11(() => {
9883
- const resolvedConversation = resolveConversationSummaryById(
9994
+ const visibleConversationsRef = useRef11(
9995
+ null
9996
+ );
9997
+ const conversationProjection = useMemo12(() => {
9998
+ const source = mergeVisibleConversations(
9884
9999
  input.conversations,
9885
- input.activeConversationId,
9886
10000
  input.transientConversation
9887
10001
  );
9888
- const resolved = resolvedConversation ? applyAgentGUIConversationProjects(
9889
- [resolvedConversation],
9890
- input.userProjects,
9891
- { isNoProjectPath: input.isNoProjectPath }
9892
- )[0] ?? resolvedConversation : null;
10002
+ const mapped = source.map((conversation) => {
10003
+ const activityBusyStatus = conversationBusyStatusFromAgentActivityDisplayStatus(
10004
+ input.activityDisplayStatuses.get(conversation.id)
10005
+ );
10006
+ return activityBusyStatus && conversation.status !== activityBusyStatus ? { ...conversation, status: activityBusyStatus } : conversation;
10007
+ });
10008
+ const next = applyAgentGUIConversationProjects(mapped, input.userProjects, {
10009
+ isNoProjectPath: input.isNoProjectPath
10010
+ });
10011
+ const visibleConversations2 = stableConversationSummaryList(
10012
+ visibleConversationsRef.current,
10013
+ next
10014
+ );
10015
+ visibleConversationsRef.current = visibleConversations2;
10016
+ return { semanticConversations: next, visibleConversations: visibleConversations2 };
10017
+ }, [
10018
+ input.activityDisplayStatuses,
10019
+ input.conversations,
10020
+ input.isNoProjectPath,
10021
+ input.transientConversation,
10022
+ input.userProjects
10023
+ ]);
10024
+ const visibleConversations = conversationProjection.visibleConversations;
10025
+ const activeConversationRef = useRef11(
10026
+ null
10027
+ );
10028
+ const activeConversation = useMemo12(() => {
10029
+ const stabilize = (next) => {
10030
+ const previous = activeConversationRef.current?.[0] ?? null;
10031
+ const canReusePrevious = previous !== null && next !== null && conversationSummariesRenderEqual(previous, next) && previous.agentTargetId === next.agentTargetId && previous.resumable === next.resumable;
10032
+ const stable = next ? [canReusePrevious ? previous : next] : [];
10033
+ activeConversationRef.current = stable;
10034
+ return stable[0] ?? null;
10035
+ };
10036
+ const resolved = resolveConversationSummaryById(
10037
+ conversationProjection.semanticConversations,
10038
+ input.activeConversationId
10039
+ );
9893
10040
  if (resolved) {
9894
10041
  const activityDisplayStatus = input.activityDisplayStatuses.get(
9895
10042
  resolved.id
@@ -9899,9 +10046,11 @@ function useAgentGUIConversationPresentation(input) {
9899
10046
  );
9900
10047
  const hasCanonicalTerminalStatus = activityDisplayStatus === "completed" || activityDisplayStatus === "failed" || activityDisplayStatus === "canceled";
9901
10048
  const status = (input.isSubmitting || input.hasUnconfirmedSubmit ? "working" : hasCanonicalTerminalStatus ? activityDisplayStatus : activityBusyStatus2) ?? (resolved.status === "ready" && (input.activeLatestPendingSubmitTurnId || input.isSubmitting) ? "working" : resolved.status);
9902
- return status === resolved.status ? resolved : { ...resolved, status };
10049
+ return stabilize(
10050
+ status === resolved.status ? resolved : { ...resolved, status }
10051
+ );
9903
10052
  }
9904
- if (!input.activeConversationId) return null;
10053
+ if (!input.activeConversationId) return stabilize(null);
9905
10054
  const providerLabel = AGENT_PROVIDER_LABEL[input.data.provider] ?? input.data.provider ?? translate("sidebar.fallbackAgentLabel");
9906
10055
  const fallbackStatus = input.isSubmitting || input.isCreatingConversation || Object.prototype.hasOwnProperty.call(
9907
10056
  input.draftByScopeKey,
@@ -9912,8 +10061,9 @@ function useAgentGUIConversationPresentation(input) {
9912
10061
  const activityBusyStatus = conversationBusyStatusFromAgentActivityDisplayStatus(
9913
10062
  input.activityDisplayStatuses.get(input.activeConversationId)
9914
10063
  );
9915
- const fallbackUpdatedAtUnixMs = Date.now();
9916
- return {
10064
+ const previousActiveConversation = activeConversationRef.current?.[0];
10065
+ const fallbackUpdatedAtUnixMs = previousActiveConversation?.id === input.activeConversationId ? previousActiveConversation.updatedAtUnixMs : Date.now();
10066
+ return stabilize({
9917
10067
  id: input.activeConversationId,
9918
10068
  userId: input.currentUserId?.trim() || void 0,
9919
10069
  provider: input.data.provider,
@@ -9928,12 +10078,11 @@ function useAgentGUIConversationPresentation(input) {
9928
10078
  ),
9929
10079
  sortTimeUnixMs: fallbackUpdatedAtUnixMs,
9930
10080
  updatedAtUnixMs: fallbackUpdatedAtUnixMs
9931
- };
10081
+ });
9932
10082
  }, [
9933
10083
  input.activeConversationId,
9934
10084
  input.activeLatestPendingSubmitTurnId,
9935
10085
  input.activityDisplayStatuses,
9936
- input.conversations,
9937
10086
  input.currentUserId,
9938
10087
  input.data.provider,
9939
10088
  input.draftByScopeKey,
@@ -9941,8 +10090,8 @@ function useAgentGUIConversationPresentation(input) {
9941
10090
  input.isCreatingConversation,
9942
10091
  input.isNoProjectPath,
9943
10092
  input.isSubmitting,
9944
- input.transientConversation,
9945
10093
  input.userProjects,
10094
+ conversationProjection.semanticConversations,
9946
10095
  input.workspacePath
9947
10096
  ]);
9948
10097
  useEffect10(() => {
@@ -9998,36 +10147,6 @@ function useAgentGUIConversationPresentation(input) {
9998
10147
  input.shouldUseStaticProviderTargets,
9999
10148
  input.transientConversation
10000
10149
  ]);
10001
- const visibleConversationsRef = useRef11(
10002
- null
10003
- );
10004
- const visibleConversations = useMemo11(() => {
10005
- const source = mergeVisibleConversations(
10006
- input.conversations,
10007
- input.transientConversation
10008
- );
10009
- const mapped = source.map((conversation) => {
10010
- const activityBusyStatus = conversationBusyStatusFromAgentActivityDisplayStatus(
10011
- input.activityDisplayStatuses.get(conversation.id)
10012
- );
10013
- return activityBusyStatus && conversation.status !== activityBusyStatus ? { ...conversation, status: activityBusyStatus } : conversation;
10014
- });
10015
- const next = applyAgentGUIConversationProjects(mapped, input.userProjects, {
10016
- isNoProjectPath: input.isNoProjectPath
10017
- });
10018
- const stableNext = stableConversationSummaryList(
10019
- visibleConversationsRef.current,
10020
- next
10021
- );
10022
- visibleConversationsRef.current = stableNext;
10023
- return stableNext;
10024
- }, [
10025
- input.activityDisplayStatuses,
10026
- input.conversations,
10027
- input.isNoProjectPath,
10028
- input.transientConversation,
10029
- input.userProjects
10030
- ]);
10031
10150
  return { activeConversation, visibleConversations };
10032
10151
  }
10033
10152
 
@@ -10289,7 +10408,7 @@ import {
10289
10408
  selectPlanDecisionForTurn,
10290
10409
  selectPlanTurnDismissed
10291
10410
  } from "@tutti-os/agent-activity-core";
10292
- import { useEffect as useEffect12, useMemo as useMemo12 } from "react";
10411
+ import { useEffect as useEffect12, useMemo as useMemo13 } from "react";
10293
10412
  function useAgentGUISessionPresentation(input) {
10294
10413
  const latestTimelinePlanTurnId = latestPlanTurnId(input.activeTimelineItems);
10295
10414
  const planImplementationTurnId = input.activeConversationId !== null && input.composerSupport.planImplementation && input.composerSupport.plan && input.activeEngineLatestTurn?.phase === "settled" && input.activeEngineLatestTurn.outcome === "completed" && input.activeEngineLatestTurn.turnId === latestTimelinePlanTurnId ? latestTimelinePlanTurnId : null;
@@ -10342,7 +10461,14 @@ function useAgentGUISessionPresentation(input) {
10342
10461
  const activeSessionResumable = input.activeEngineSession?.resumable ?? input.activeConversation?.resumable ?? input.activeSessionState?.resumable;
10343
10462
  const activeConversationRequiresResume = input.activeConversationId !== null && input.activationState !== "active";
10344
10463
  const activeConversationResumeUnavailable = activeConversationRequiresResume && activeSessionResumable === false;
10345
- const sessionChrome = useMemo12(() => {
10464
+ const sessionChromeRawState = useMemo13(
10465
+ () => input.activeEngineSession ? {
10466
+ agentSessionId: input.activeEngineSession.agentSessionId,
10467
+ goal: input.activeEngineSession.goal
10468
+ } : null,
10469
+ [input.activeEngineSession?.agentSessionId, input.activeEngineSession?.goal]
10470
+ );
10471
+ const sessionChrome = useMemo13(() => {
10346
10472
  const normalizedError = input.activationError?.trim() ?? "";
10347
10473
  const authState = input.activeSessionState?.authState?.trim() ?? "";
10348
10474
  const providerSessionMissing = isNonRetryableResumeErrorCode(
@@ -10370,7 +10496,7 @@ function useAgentGUISessionPresentation(input) {
10370
10496
  message: recoveryMessage,
10371
10497
  canRetry: !providerSessionMissing
10372
10498
  } : null,
10373
- rawState: input.activeEngineSession
10499
+ rawState: sessionChromeRawState
10374
10500
  };
10375
10501
  }, [
10376
10502
  activeConversationResumeUnavailable,
@@ -10378,11 +10504,11 @@ function useAgentGUISessionPresentation(input) {
10378
10504
  input.activationError,
10379
10505
  input.activationErrorCode,
10380
10506
  input.activeConversationId,
10381
- input.activeEngineSession,
10382
10507
  input.activeLiveState,
10383
10508
  input.activeSessionState,
10384
10509
  input.activePendingActivation?.mode,
10385
- input.pendingApproval
10510
+ input.pendingApproval,
10511
+ sessionChromeRawState
10386
10512
  ]);
10387
10513
  const canSubmit = !input.agentTargetsLoading && input.activeLiveState !== "activating" && input.activeLiveState !== "failed" && !activeConversationResumeUnavailable && input.pendingApproval === null && pendingInteractivePrompt === null && sessionChrome.auth === null && !activeConversationBusy && !input.isCreatingConversation && !input.isSubmitting && !input.isInterrupting;
10388
10514
  const canQueueWhileBusy = input.activeConversationId !== null && (activeConversationBusy || input.isSubmitting || input.activeEngineHasPendingInteractions);
@@ -10480,15 +10606,24 @@ function useAgentGUISessionPresentation(input) {
10480
10606
  // agent-gui/agentGuiNode/controller/useAgentGUIViewAssembly.ts
10481
10607
  function useAgentGUIViewAssembly(input) {
10482
10608
  const { activeConversation, visibleConversations } = useAgentGUIConversationPresentation(input);
10483
- const detail = useAgentGUIConversationDetail({
10484
- ...input,
10485
- activeConversation,
10486
- activeSessionView: input.activeSessionView ? {
10609
+ const stableActiveSessionViewProjection = useMemo14(
10610
+ () => input.activeSessionView ? {
10487
10611
  hasOlderMessages: input.activeSessionView.hasOlderMessages,
10488
10612
  isLoadingOlderMessages: input.activeSessionView.isLoadingOlderMessages,
10489
10613
  olderMessageCount: input.activeSessionView.olderMessages.length,
10490
10614
  oldestLoadedVersion: input.activeSessionView.oldestLoadedVersion
10491
- } : null
10615
+ } : null,
10616
+ [
10617
+ input.activeSessionView?.hasOlderMessages,
10618
+ input.activeSessionView?.isLoadingOlderMessages,
10619
+ input.activeSessionView?.olderMessages.length,
10620
+ input.activeSessionView?.oldestLoadedVersion
10621
+ ]
10622
+ );
10623
+ const detail = useAgentGUIConversationDetail({
10624
+ ...input,
10625
+ activeConversation,
10626
+ activeSessionView: stableActiveSessionViewProjection
10492
10627
  });
10493
10628
  const { stableComposerSettings } = useAgentGUIComposerPresentation({
10494
10629
  ...input,
@@ -10530,7 +10665,7 @@ function useAgentGUIViewAssembly(input) {
10530
10665
  comingSoonProviders: input.normalizedComingSoonProviders,
10531
10666
  conversationFilter: input.conversationFilter,
10532
10667
  conversations: visibleConversations,
10533
- userProjects: [...input.userProjects],
10668
+ userProjects: input.userProjects,
10534
10669
  activeConversation,
10535
10670
  activeConversationId: input.activeConversationId,
10536
10671
  isLoadingConversations: input.isLoadingConversations,
@@ -10593,14 +10728,14 @@ function useAgentGUIViewAssembly(input) {
10593
10728
  pendingDeleteProjectConversations: input.pendingDeleteProjectConversations
10594
10729
  }
10595
10730
  });
10596
- return useMemo13(
10731
+ return useMemo14(
10597
10732
  () => ({ viewModel, actions: controllerActions }),
10598
10733
  [controllerActions, viewModel]
10599
10734
  );
10600
10735
  }
10601
10736
 
10602
10737
  // agent-gui/agentGuiNode/controller/useAgentGUIProviderCatalogSelection.ts
10603
- import { useEffect as useEffect13, useMemo as useMemo14, useState as useState4 } from "react";
10738
+ import { useEffect as useEffect13, useMemo as useMemo15, useState as useState4 } from "react";
10604
10739
  function useAgentGUIProviderCatalogSelection(input) {
10605
10740
  const {
10606
10741
  comingSoonProviders,
@@ -10611,12 +10746,12 @@ function useAgentGUIProviderCatalogSelection(input) {
10611
10746
  agentTargets,
10612
10747
  agentTargetsLoading
10613
10748
  } = input;
10614
- const normalizedComingSoonProviders = useMemo14(
10749
+ const normalizedComingSoonProviders = useMemo15(
10615
10750
  () => comingSoonProviders && comingSoonProviders.length > 0 ? [...comingSoonProviders] : emptyComingSoonProviders,
10616
10751
  [comingSoonProviders]
10617
10752
  );
10618
10753
  const isExactProviderRailMode = providerRailMode === "exact";
10619
- const normalizedExplicitProviderTargets = useMemo14(() => {
10754
+ const normalizedExplicitProviderTargets = useMemo15(() => {
10620
10755
  const normalized = normalizeAgentGUIAgentTargets(agentTargets, {
10621
10756
  includeDisabledPlaceholders: !isExactProviderRailMode,
10622
10757
  useStaticCatalog: false
@@ -10626,7 +10761,7 @@ function useAgentGUIProviderCatalogSelection(input) {
10626
10761
  normalizedComingSoonProviders
10627
10762
  );
10628
10763
  }, [isExactProviderRailMode, normalizedComingSoonProviders, agentTargets]);
10629
- const normalizedProviderTargets = useMemo14(() => {
10764
+ const normalizedProviderTargets = useMemo15(() => {
10630
10765
  if (agentTargetsLoading) return [];
10631
10766
  if (!isExactProviderRailMode && (agentTargets === void 0 || normalizedExplicitProviderTargets.length === 0)) {
10632
10767
  return applyComingSoonProviderTargets(
@@ -10645,13 +10780,13 @@ function useAgentGUIProviderCatalogSelection(input) {
10645
10780
  agentTargetsLoading
10646
10781
  ]);
10647
10782
  const shouldUseStaticProviderTargets = !isExactProviderRailMode && !agentTargetsLoading && (agentTargets === void 0 || normalizedExplicitProviderTargets.length === 0);
10648
- const handoffAgentTargets = useMemo14(
10783
+ const handoffAgentTargets = useMemo15(
10649
10784
  () => agentTargetsLoading ? [] : normalizedExplicitProviderTargets.filter(
10650
10785
  (target) => target.disabled !== true
10651
10786
  ),
10652
10787
  [normalizedExplicitProviderTargets, agentTargetsLoading]
10653
10788
  );
10654
- const selectedAgentTarget = useMemo14(
10789
+ const selectedAgentTarget = useMemo15(
10655
10790
  () => resolveAgentGUIAgentTarget({
10656
10791
  agentTargetId: data.agentTargetId,
10657
10792
  defaultAgentTargetId,
@@ -10673,14 +10808,14 @@ function useAgentGUIProviderCatalogSelection(input) {
10673
10808
  shouldUseStaticProviderTargets
10674
10809
  ]
10675
10810
  );
10676
- const selectedAgentTargetIsExplicit = useMemo14(
10811
+ const selectedAgentTargetIsExplicit = useMemo15(
10677
10812
  () => normalizedExplicitProviderTargets.some(
10678
10813
  (target) => target.provider === selectedAgentTarget.provider && target.targetId === selectedAgentTarget.targetId && agentGUIAgentTargetRefsEqual(target.ref, selectedAgentTarget.ref)
10679
10814
  ),
10680
10815
  [normalizedExplicitProviderTargets, selectedAgentTarget]
10681
10816
  );
10682
10817
  const [homeComposerTargetOverride, setHomeComposerTargetOverride] = useState4(null);
10683
- const homeComposerTargetOverrideIsExplicit = useMemo14(
10818
+ const homeComposerTargetOverrideIsExplicit = useMemo15(
10684
10819
  () => homeComposerTargetOverride ? normalizedExplicitProviderTargets.some(
10685
10820
  (target) => target.provider === homeComposerTargetOverride.provider && target.targetId === homeComposerTargetOverride.targetId && agentGUIAgentTargetRefsEqual(
10686
10821
  target.ref,
@@ -10690,14 +10825,14 @@ function useAgentGUIProviderCatalogSelection(input) {
10690
10825
  [homeComposerTargetOverride, normalizedExplicitProviderTargets]
10691
10826
  );
10692
10827
  const effectiveSelectedProviderTarget = homeComposerTargetOverride ?? selectedAgentTarget;
10693
- const firstReadyHomeComposerProviderTarget = useMemo14(
10828
+ const firstReadyHomeComposerProviderTarget = useMemo15(
10694
10829
  () => providerReadinessGates ? normalizedProviderTargets.find(
10695
10830
  (target) => target.disabled !== true && providerReadinessGates[target.provider] === null
10696
10831
  ) ?? null : null,
10697
10832
  [normalizedProviderTargets, providerReadinessGates]
10698
10833
  );
10699
10834
  const nodeComposerTargetResolvedByProviderTarget = agentGUINodeDataHasComposerTarget(data) && normalizeOptionalText(data.agentTargetId) !== null && selectedAgentTarget.agentTargetId === normalizeOptionalText(data.agentTargetId);
10700
- const selectedComposerTargetData = useMemo14(
10835
+ const selectedComposerTargetData = useMemo15(
10701
10836
  () => homeComposerTargetOverride ? composerTargetDataFromProviderTarget({
10702
10837
  current: data,
10703
10838
  isExplicit: homeComposerTargetOverrideIsExplicit,
@@ -10769,7 +10904,7 @@ import {
10769
10904
  selectSessionHasUnconfirmedSubmit,
10770
10905
  selectSessionIsSubmitting
10771
10906
  } from "@tutti-os/agent-activity-core";
10772
- import { useMemo as useMemo15 } from "react";
10907
+ import { useMemo as useMemo16 } from "react";
10773
10908
 
10774
10909
  // agent-gui/agentGuiNode/controller/agentGuiQueueStatus.ts
10775
10910
  function agentGUIQueueStatusFromPromptQueue(record) {
@@ -10783,9 +10918,12 @@ function useAgentGUISessionEngineState(input) {
10783
10918
  sessionEngine,
10784
10919
  (state) => selectEnginePromptQueue(state, activeConversationId)
10785
10920
  );
10786
- const activeQueuedPrompts = activeQueuedPromptSnapshot?.prompts.filter(
10787
- (prompt) => prompt.visibleInQueue !== false && prompt.id !== activeQueuedPromptSnapshot.inFlight?.promptId && prompt.id !== activeQueuedPromptSnapshot.sendNextPromptId
10788
- ) ?? EMPTY_QUEUED_PROMPTS;
10921
+ const activeQueuedPrompts = useMemo16(
10922
+ () => activeQueuedPromptSnapshot?.prompts.filter(
10923
+ (prompt) => prompt.visibleInQueue !== false && prompt.id !== activeQueuedPromptSnapshot.inFlight?.promptId && prompt.id !== activeQueuedPromptSnapshot.sendNextPromptId
10924
+ ) ?? EMPTY_QUEUED_PROMPTS,
10925
+ [activeQueuedPromptSnapshot]
10926
+ );
10789
10927
  const activePendingSubmits = useEngineSelector(
10790
10928
  sessionEngine,
10791
10929
  (state) => selectPendingSubmitsForSession3(state, activeConversationId),
@@ -10837,7 +10975,7 @@ function useAgentGUISessionEngineState(input) {
10837
10975
  sessionEngine,
10838
10976
  (state) => selectEngineLatestTurn(state, activeConversationId)
10839
10977
  );
10840
- const activeCanonicalComposerSettings = useMemo15(
10978
+ const activeCanonicalComposerSettings = useMemo16(
10841
10979
  () => ({
10842
10980
  model: activeEngineSession?.settings?.model ?? void 0,
10843
10981
  permissionModeId: activeEngineSession?.settings?.permissionModeId ?? void 0,
@@ -10848,7 +10986,7 @@ function useAgentGUISessionEngineState(input) {
10848
10986
  }),
10849
10987
  [activeEngineSession?.settings]
10850
10988
  );
10851
- const activeSessionState = useMemo15(() => {
10989
+ const activeSessionState = useMemo16(() => {
10852
10990
  if (!activeEngineSession) return null;
10853
10991
  return {
10854
10992
  workspaceId: activeEngineSession.workspaceId,
@@ -10936,7 +11074,7 @@ function useAgentGUISessionEngineState(input) {
10936
11074
  import {
10937
11075
  selectLatestActivationForSession as selectLatestActivationForSession5
10938
11076
  } from "@tutti-os/agent-activity-core";
10939
- import { useCallback as useCallback23, useMemo as useMemo16 } from "react";
11077
+ import { useCallback as useCallback23, useMemo as useMemo17 } from "react";
10940
11078
 
10941
11079
  // contexts/workspace/presentation/renderer/agentSessions/useAgentSessionControllerState.ts
10942
11080
  import { useCallback as useCallback22 } from "react";
@@ -11119,7 +11257,7 @@ function useAgentSessionControllerState(activeRef, canonicalMessages = []) {
11119
11257
  const canonicalOldestVersion = oldestVersion2(canonicalMessages);
11120
11258
  const activeSessionView = storedActiveView ? {
11121
11259
  ...storedActiveView,
11122
- hasOlderMessages: storedActiveView.hasOlderMessages || canonicalOldestVersion !== null && canonicalOldestVersion > 1,
11260
+ hasOlderMessages: storedActiveView.hasOlderMessages || storedActiveView.oldestLoadedVersion === null && canonicalOldestVersion !== null && canonicalOldestVersion > 1,
11123
11261
  oldestLoadedVersion: storedActiveView.oldestLoadedVersion === null ? canonicalOldestVersion : canonicalOldestVersion === null ? storedActiveView.oldestLoadedVersion : Math.min(
11124
11262
  storedActiveView.oldestLoadedVersion,
11125
11263
  canonicalOldestVersion
@@ -11191,7 +11329,7 @@ function useAgentGUISessionDetailTransport(input) {
11191
11329
  loadSessionState,
11192
11330
  reconcileSessionDetail,
11193
11331
  refreshMessagesFromSnapshot
11194
- } = useMemo16(() => {
11332
+ } = useMemo17(() => {
11195
11333
  const reconcileSession = (agentSessionId, scope) => {
11196
11334
  const normalized = agentSessionId.trim();
11197
11335
  if (!normalized) return;
@@ -11367,7 +11505,7 @@ function useAgentGUINodeController({
11367
11505
  }) {
11368
11506
  const agentActivityRuntime = useAgentActivityRuntime();
11369
11507
  const agentActivityRuntimeOrigin = agentActivityRuntime.origin?.trim() || AGENT_GUI_RUNTIME_SESSION_ORIGIN;
11370
- const sessionEngine = useMemo17(() => {
11508
+ const sessionEngine = useMemo18(() => {
11371
11509
  const engine = agentActivityRuntime.getSessionEngine(workspaceId);
11372
11510
  if (engine.identity.workspaceId !== workspaceId || engine.identity.origin !== agentActivityRuntimeOrigin) {
11373
11511
  throw new Error(
@@ -11555,7 +11693,7 @@ function useAgentGUINodeController({
11555
11693
  storedMessages: storedActiveMessages,
11556
11694
  workspaceId
11557
11695
  });
11558
- const transientConversation = useMemo17(() => {
11696
+ const transientConversation = useMemo18(() => {
11559
11697
  const session = activeEngineSession;
11560
11698
  if (!session || session.visible === false || conversations.some(
11561
11699
  (conversation) => conversation.id === session.agentSessionId
@@ -11857,9 +11995,9 @@ function useAgentGUINodeController({
11857
11995
  // agent-gui/agentGuiNode/AgentGUINodeView.tsx
11858
11996
  import {
11859
11997
  useCallback as useCallback48,
11860
- useEffect as useEffect36,
11861
- useMemo as useMemo36,
11862
- useRef as useRef39,
11998
+ useEffect as useEffect37,
11999
+ useMemo as useMemo37,
12000
+ useRef as useRef41,
11863
12001
  useState as useState34
11864
12002
  } from "react";
11865
12003
  import {
@@ -12101,7 +12239,7 @@ var styles = {
12101
12239
  var AgentGUINode_styles_default = styles;
12102
12240
 
12103
12241
  // agent-gui/agentGuiNode/view/agentGUIViewUtils.ts
12104
- import { useCallback as useCallback25, useLayoutEffect, useMemo as useMemo18, useRef as useRef17 } from "react";
12242
+ import { useCallback as useCallback25, useLayoutEffect, useMemo as useMemo19, useRef as useRef17 } from "react";
12105
12243
  function objectRecord(value) {
12106
12244
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
12107
12245
  }
@@ -12130,7 +12268,7 @@ function useOptionalStableEventCallback(callback) {
12130
12268
  useLayoutEffect(() => {
12131
12269
  callbackRef.current = callback;
12132
12270
  }, [callback]);
12133
- return useMemo18(() => {
12271
+ return useMemo19(() => {
12134
12272
  if (callback == null) {
12135
12273
  return void 0;
12136
12274
  }
@@ -12752,7 +12890,7 @@ function AgentGUIConfigMenu({
12752
12890
  import {
12753
12891
  memo as memo4,
12754
12892
  useCallback as useCallback40,
12755
- useMemo as useMemo29,
12893
+ useMemo as useMemo30,
12756
12894
  useRef as useRef31,
12757
12895
  useState as useState24
12758
12896
  } from "react";
@@ -12977,7 +13115,7 @@ function changeAgentGUIProviderManagerVisibility(input) {
12977
13115
  }
12978
13116
 
12979
13117
  // agent-gui/agentGuiNode/view/AgentGUIEmptyState.tsx
12980
- import { memo as memo3, useMemo as useMemo28 } from "react";
13118
+ import { memo as memo3, useMemo as useMemo29 } from "react";
12981
13119
  import {
12982
13120
  Select as Select3,
12983
13121
  SelectContent as SelectContent3,
@@ -13169,7 +13307,7 @@ var RECORD_FADE_CURVE = 1.45;
13169
13307
  var RECORD_EDGE_KILL_START_SLOTS = 1.2;
13170
13308
  var RECORD_EDGE_KILL_END_SLOTS = 2.05;
13171
13309
  var SPRING_STIFFNESS = 120;
13172
- var SPRING_DAMPING_RATIO = 0.78;
13310
+ var SPRING_DAMPING_RATIO = 0.92;
13173
13311
  var SPRING_MIN_LAUNCH_VELOCITY = 2.6;
13174
13312
  var SPRING_SETTLE_EPSILON = 1e-3;
13175
13313
  var SPRING_SETTLE_VELOCITY = 0.02;
@@ -13354,7 +13492,7 @@ var AgentGuiHeroCarouselScene = class _AgentGuiHeroCarouselScene {
13354
13492
  this.renderer.setSize(width, height, false);
13355
13493
  this.camera.aspect = width / height;
13356
13494
  this.camera.updateProjectionMatrix();
13357
- this.requestRender();
13495
+ this.renderer.render(this.scene, this.camera);
13358
13496
  }
13359
13497
  // Agent index of the tile slot the wheel is heading to.
13360
13498
  targetIndex() {
@@ -14898,11 +15036,17 @@ function useComposerDraftAttachments({
14898
15036
  clearActiveFileMentionTrigger,
14899
15037
  onDraftContentChange,
14900
15038
  onPromptImagesUnsupported,
15039
+ onContentEntered,
14901
15040
  onRequestWorkspaceReferences,
14902
15041
  resolveDroppedFileReferences,
14903
15042
  onLinkAction
14904
15043
  }) {
14905
15044
  const agentActivityRuntime = useOptionalAgentActivityRuntime();
15045
+ const reportContentEntered = useStableEventCallback2(
15046
+ (contentType) => {
15047
+ onContentEntered?.(contentType);
15048
+ }
15049
+ );
14906
15050
  const publishScopedDraft = useStableEventCallback2(
14907
15051
  (sourceScopeKey, nextDraft) => {
14908
15052
  draftByScopeKeyRef.current[sourceScopeKey] = nextDraft;
@@ -15016,6 +15160,7 @@ function useComposerDraftAttachments({
15016
15160
  }));
15017
15161
  const nextDraftImages = [...currentDraftImages, ...nextImages];
15018
15162
  draftImagesRef.current = nextDraftImages;
15163
+ reportContentEntered("image");
15019
15164
  publishScopedDraft(
15020
15165
  draftScopeKey,
15021
15166
  buildAgentComposerDraft({
@@ -15113,6 +15258,7 @@ function useComposerDraftAttachments({
15113
15258
  onPromptImagesUnsupported,
15114
15259
  publishScopedDraft,
15115
15260
  promptImagesSupported,
15261
+ reportContentEntered,
15116
15262
  updateScopedDraft,
15117
15263
  workspaceId
15118
15264
  ]
@@ -15207,6 +15353,7 @@ ${item.text}` : item.text;
15207
15353
  if (!normalizedText.trim()) {
15208
15354
  return;
15209
15355
  }
15356
+ reportContentEntered("large_text");
15210
15357
  const stagePastedText = pastedTextStagingSupported ? agentActivityRuntime?.stagePastedText : void 0;
15211
15358
  const id = crypto.randomUUID();
15212
15359
  const name = `${AGENT_COMPOSER_PASTED_TEXT_FILE_PREFIX}.txt`;
@@ -15277,6 +15424,7 @@ ${item.text}` : item.text;
15277
15424
  draftScopeKey,
15278
15425
  pastedTextStagingSupported,
15279
15426
  publishScopedDraft,
15427
+ reportContentEntered,
15280
15428
  updateScopedDraft,
15281
15429
  workspaceId
15282
15430
  ]
@@ -15410,7 +15558,7 @@ ${item.text}` : item.text;
15410
15558
  // agent-gui/agentGuiNode/composer/useComposerLayout.ts
15411
15559
  import {
15412
15560
  useLayoutEffect as useLayoutEffect2,
15413
- useMemo as useMemo19
15561
+ useMemo as useMemo20
15414
15562
  } from "react";
15415
15563
  var DOCK_COMPOSER_INPUT_MIN_HEIGHT = 56;
15416
15564
  var DOCK_COMPOSER_TEXT_LINE_HEIGHT = 24;
@@ -15628,11 +15776,11 @@ function useComposerLayout({
15628
15776
  isHeroLayout,
15629
15777
  paletteDraftPrompt
15630
15778
  ]);
15631
- const inputShellStyle = useMemo19(
15779
+ const inputShellStyle = useMemo20(
15632
15780
  () => showFileMentionPalette || showFloatingCommandMenu ? { zIndex: COMPOSER_PALETTE_Z_INDEX } : void 0,
15633
15781
  [showFileMentionPalette, showFloatingCommandMenu]
15634
15782
  );
15635
- const promptInputAreaStyle = useMemo19(
15783
+ const promptInputAreaStyle = useMemo20(
15636
15784
  () => isHeroLayout ? void 0 : {
15637
15785
  "--agent-gui-composer-attachment-height": `${dockComposerAttachmentHeight}px`,
15638
15786
  "--agent-gui-composer-input-height": `${dockComposerInputHeight}px`,
@@ -15665,7 +15813,7 @@ function useComposerLayout({
15665
15813
  }
15666
15814
 
15667
15815
  // agent-gui/agentGuiNode/composer/useComposerPaletteCatalog.ts
15668
- import { useMemo as useMemo20 } from "react";
15816
+ import { useMemo as useMemo21 } from "react";
15669
15817
 
15670
15818
  // agent-gui/agentGuiNode/composer/slashCommandDisplay.ts
15671
15819
  function slashCommandDescriptionForDisplay(command, labels) {
@@ -15746,7 +15894,7 @@ function useComposerPaletteCatalog({
15746
15894
  const promptBeforeSelection = editorHandleRef.current?.getPromptTextBeforeSelection() ?? "";
15747
15895
  const skillQueryDraft = promptBeforeSelection || paletteDraftPrompt;
15748
15896
  const skillQueryMatch = getAgentComposerTriggerQueryMatch(skillQueryDraft);
15749
- const resolvedSlashCommands = useMemo20(
15897
+ const resolvedSlashCommands = useMemo21(
15750
15898
  () => resolveSlashCommandsForProvider({
15751
15899
  provider,
15752
15900
  policy: slashCommandPolicy,
@@ -15771,11 +15919,11 @@ function useComposerPaletteCatalog({
15771
15919
  slashCommandPolicy
15772
15920
  ]
15773
15921
  );
15774
- const filteredCommands = useMemo20(
15922
+ const filteredCommands = useMemo21(
15775
15923
  () => slashQuery === null ? [] : filterSlashCommands(resolvedSlashCommands, slashQuery),
15776
15924
  [resolvedSlashCommands, slashQuery]
15777
15925
  );
15778
- const filteredSkills = useMemo20(
15926
+ const filteredSkills = useMemo21(
15779
15927
  () => skillQueryMatch === null ? [] : filterProviderSkillsForTrigger({
15780
15928
  skills: availableSkills,
15781
15929
  query: skillQueryMatch.query,
@@ -15783,7 +15931,7 @@ function useComposerPaletteCatalog({
15783
15931
  }),
15784
15932
  [availableSkills, skillQueryMatch]
15785
15933
  );
15786
- const availableCapabilities = useMemo20(() => {
15934
+ const availableCapabilities = useMemo21(() => {
15787
15935
  const entries = [];
15788
15936
  if (composerSettings.supportsBrowser) {
15789
15937
  entries.push({
@@ -15808,7 +15956,7 @@ function useComposerPaletteCatalog({
15808
15956
  labels.browserUseCapabilityLabel,
15809
15957
  labels.computerUseCapabilityLabel
15810
15958
  ]);
15811
- const slashPaletteEntries = useMemo20(() => {
15959
+ const slashPaletteEntries = useMemo21(() => {
15812
15960
  const commandEntries = filteredCommands.flatMap((command) => {
15813
15961
  if (isSlashCommandCapability(command)) {
15814
15962
  const browserConnectionMode = capabilityMenuState?.browserUse?.connectionMode ?? null;
@@ -15911,7 +16059,7 @@ function useComposerPaletteCatalog({
15911
16059
  import {
15912
16060
  useCallback as useCallback30,
15913
16061
  useLayoutEffect as useLayoutEffect3,
15914
- useMemo as useMemo21,
16062
+ useMemo as useMemo22,
15915
16063
  useState as useState11
15916
16064
  } from "react";
15917
16065
 
@@ -16378,7 +16526,7 @@ function useMentionPaletteFrame(inputShellRef, showFileMentionPalette) {
16378
16526
  window.removeEventListener("scroll", syncMentionPaletteFrame, true);
16379
16527
  };
16380
16528
  }, [showFileMentionPalette, syncMentionPaletteFrame]);
16381
- const mentionPaletteStyle = useMemo21(
16529
+ const mentionPaletteStyle = useMemo22(
16382
16530
  () => ({
16383
16531
  position: "fixed",
16384
16532
  left: `${mentionPaletteFrame?.left ?? 0}px`,
@@ -16399,7 +16547,7 @@ function useMentionPaletteFrame(inputShellRef, showFileMentionPalette) {
16399
16547
  // agent-gui/agentGuiNode/composer/useComposerSlashActions.ts
16400
16548
  import {
16401
16549
  useCallback as useCallback31,
16402
- useMemo as useMemo22,
16550
+ useMemo as useMemo23,
16403
16551
  useRef as useRef21
16404
16552
  } from "react";
16405
16553
 
@@ -16497,7 +16645,7 @@ function useComposerSlashActions(input) {
16497
16645
  },
16498
16646
  [clearSlashCommandDraft, onSubmit]
16499
16647
  );
16500
- const reviewBranchLoader = useMemo22(() => {
16648
+ const reviewBranchLoader = useMemo23(() => {
16501
16649
  if (!onRequestGitBranches) {
16502
16650
  return null;
16503
16651
  }
@@ -17163,7 +17311,7 @@ function useComposerMentionActions(input) {
17163
17311
  }
17164
17312
 
17165
17313
  // agent-gui/agentGuiNode/composer/useComposerProviderTargets.ts
17166
- import { useMemo as useMemo23 } from "react";
17314
+ import { useMemo as useMemo24 } from "react";
17167
17315
  function useComposerProviderTargets(input) {
17168
17316
  const {
17169
17317
  layoutMode,
@@ -17187,7 +17335,7 @@ function useComposerProviderTargets(input) {
17187
17335
  };
17188
17336
  const isHeroLayout = layoutMode === "hero";
17189
17337
  const composerClassName = isHeroLayout ? AgentGUINode_styles_default.composerHero : AgentGUINode_styles_default.composer;
17190
- const providerSwitchTargets = useMemo23(
17338
+ const providerSwitchTargets = useMemo24(
17191
17339
  () => agentTargets.filter(Boolean),
17192
17340
  [agentTargets]
17193
17341
  );
@@ -17198,7 +17346,7 @@ function useComposerProviderTargets(input) {
17198
17346
  const providerMenuTargets = selectedProviderSwitchTarget && !providerSwitchTargets.some(
17199
17347
  (target) => target.targetId === selectedProviderSwitchTarget.targetId
17200
17348
  ) ? [selectedProviderSwitchTarget, ...providerSwitchTargets] : providerSwitchTargets;
17201
- const enabledHandoffProviderTargets = useMemo23(
17349
+ const enabledHandoffProviderTargets = useMemo24(
17202
17350
  () => (handoffAgentTargets ?? providerMenuTargets).filter(
17203
17351
  (target) => target.disabled !== true
17204
17352
  ),
@@ -19022,7 +19170,7 @@ function optionsWithSelectedValue(options, selectedValue) {
19022
19170
  }
19023
19171
 
19024
19172
  // agent-gui/agentGuiNode/AgentComposerProjectMenu.tsx
19025
- import { useMemo as useMemo24 } from "react";
19173
+ import { useMemo as useMemo25 } from "react";
19026
19174
  import { ChevronDown } from "lucide-react";
19027
19175
  import {
19028
19176
  WorkspaceUserProjectSelect,
@@ -19051,11 +19199,11 @@ function AgentProjectDropdown({
19051
19199
  }) {
19052
19200
  "use memo";
19053
19201
  const agentHostApi = useAgentHostApi();
19054
- const resolvedLabels = useMemo24(
19202
+ const resolvedLabels = useMemo25(
19055
19203
  () => resolveWorkspaceUserProjectSelectLabels(i18n, labels),
19056
19204
  [i18n, labels]
19057
19205
  );
19058
- const userProjectApi = useMemo24(
19206
+ const userProjectApi = useMemo25(
19059
19207
  () => !previewMode && agentHostApi.userProjects ? {
19060
19208
  ...agentHostApi.userProjects,
19061
19209
  selectDirectory: selectProjectDirectory ?? agentHostApi.workspace.selectDirectory
@@ -19663,7 +19811,7 @@ import {
19663
19811
  forwardRef as forwardRef3,
19664
19812
  useCallback as useCallback36,
19665
19813
  useEffect as useEffect24,
19666
- useMemo as useMemo25,
19814
+ useMemo as useMemo26,
19667
19815
  useRef as useRef25,
19668
19816
  useState as useState17
19669
19817
  } from "react";
@@ -19851,6 +19999,52 @@ function moveSelectionOverCaretAnchor(state, dispatch, key) {
19851
19999
  }
19852
20000
  return false;
19853
20001
  }
20002
+ function deleteLineStartMentionWithCaretAnchor(state, dispatch, key) {
20003
+ const { doc, selection } = state;
20004
+ if (!selection.empty) {
20005
+ return false;
20006
+ }
20007
+ if (key === "Backspace") {
20008
+ const mention2 = selection.$from.nodeBefore;
20009
+ if (mention2?.type.name !== "agentFileMention") {
20010
+ return false;
20011
+ }
20012
+ const mentionFrom2 = selection.from - mention2.nodeSize;
20013
+ const anchorFrom2 = mentionFrom2 - AGENT_RICH_TEXT_CARET_ANCHOR.length;
20014
+ if (anchorFrom2 < 1 || doc.textBetween(anchorFrom2, mentionFrom2) !== AGENT_RICH_TEXT_CARET_ANCHOR) {
20015
+ return false;
20016
+ }
20017
+ const nextNode2 = selection.$from.nodeAfter;
20018
+ dispatch(
20019
+ state.tr.delete(
20020
+ nextNode2?.type.name === "agentFileMention" ? mentionFrom2 : anchorFrom2,
20021
+ selection.from
20022
+ )
20023
+ );
20024
+ return true;
20025
+ }
20026
+ if (key !== "Delete") {
20027
+ return false;
20028
+ }
20029
+ const anchorFrom = selection.from;
20030
+ const mentionFrom = anchorFrom + AGENT_RICH_TEXT_CARET_ANCHOR.length;
20031
+ if (doc.textBetween(anchorFrom, mentionFrom) !== AGENT_RICH_TEXT_CARET_ANCHOR) {
20032
+ return false;
20033
+ }
20034
+ const mention = doc.resolve(mentionFrom).nodeAfter;
20035
+ if (mention?.type.name !== "agentFileMention") {
20036
+ return false;
20037
+ }
20038
+ const mentionTo = mentionFrom + mention.nodeSize;
20039
+ const nextNode = doc.resolve(mentionTo).nodeAfter;
20040
+ dispatch(
20041
+ state.tr.delete(
20042
+ nextNode?.type.name === "agentFileMention" ? mentionFrom : anchorFrom,
20043
+ mentionTo
20044
+ )
20045
+ );
20046
+ return true;
20047
+ }
19854
20048
  function createAgentRichTextPlaceholderExtension(getPlaceholder) {
19855
20049
  return Extension.create({
19856
20050
  name: "agentRichTextPlaceholder",
@@ -19887,9 +20081,17 @@ function createAgentRichTextCaretAnchorExtension() {
19887
20081
  key: new PluginKey("agentRichTextCaretAnchor"),
19888
20082
  props: {
19889
20083
  handleKeyDown(view, event) {
19890
- if (event.key !== "ArrowLeft" && event.key !== "ArrowRight" || event.shiftKey || event.metaKey || event.ctrlKey || event.altKey) {
20084
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight" && event.key !== "Backspace" && event.key !== "Delete" || event.shiftKey || event.metaKey || event.ctrlKey || event.altKey) {
19891
20085
  return false;
19892
20086
  }
20087
+ if (deleteLineStartMentionWithCaretAnchor(
20088
+ view.state,
20089
+ (transaction) => view.dispatch(transaction),
20090
+ event.key
20091
+ )) {
20092
+ event.preventDefault();
20093
+ return true;
20094
+ }
19893
20095
  if (moveSelectionOverCaretAnchor(
19894
20096
  view.state,
19895
20097
  (transaction) => view.dispatch(transaction),
@@ -20015,6 +20217,30 @@ async function readPlainTextFromClipboard() {
20015
20217
 
20016
20218
  // agent-gui/agentGuiNode/agentRichText/useAgentRichTextEditorHandle.ts
20017
20219
  import { useImperativeHandle as useImperativeHandle2 } from "react";
20220
+
20221
+ // agent-gui/agentGuiNode/agentRichText/agentRichTextEngagement.ts
20222
+ import { isHistoryTransaction } from "@tiptap/pm/history";
20223
+ var AGENT_RICH_TEXT_SKIP_USER_CONTENT_EVENT_META = "agentRichTextSkipUserContentEvent";
20224
+ function isAgentRichTextUserContentInsertion(transaction) {
20225
+ if (transaction.getMeta(AGENT_RICH_TEXT_SKIP_USER_CONTENT_EVENT_META) === true || isHistoryTransaction(transaction)) {
20226
+ return false;
20227
+ }
20228
+ return transaction.steps.some((step) => {
20229
+ let inserted = false;
20230
+ step.getMap().forEach((_oldStart, _oldEnd, newStart, newEnd) => {
20231
+ if (newEnd > newStart) inserted = true;
20232
+ });
20233
+ return inserted;
20234
+ });
20235
+ }
20236
+ function markAgentRichTextPointerFocus(ref) {
20237
+ ref.current = "pointer";
20238
+ queueMicrotask(() => {
20239
+ if (ref.current === "pointer") ref.current = null;
20240
+ });
20241
+ }
20242
+
20243
+ // agent-gui/agentGuiNode/agentRichText/useAgentRichTextEditorHandle.ts
20018
20244
  function useAgentRichTextEditorHandle(input) {
20019
20245
  useImperativeHandle2(
20020
20246
  input.ref,
@@ -20024,6 +20250,7 @@ function useAgentRichTextEditorHandle(input) {
20024
20250
  if (!currentEditor || currentEditor.isDestroyed) {
20025
20251
  return;
20026
20252
  }
20253
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20027
20254
  currentEditor.chain().focus().setTextSelection(1).scrollIntoView().run();
20028
20255
  },
20029
20256
  focusAtEnd() {
@@ -20032,6 +20259,7 @@ function useAgentRichTextEditorHandle(input) {
20032
20259
  return;
20033
20260
  }
20034
20261
  const end = currentEditor.state.doc.content.size;
20262
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20035
20263
  currentEditor.chain().focus().setTextSelection(end).run();
20036
20264
  },
20037
20265
  getPromptTextBeforeSelection() {
@@ -20054,13 +20282,15 @@ function useAgentRichTextEditorHandle(input) {
20054
20282
  const triggerText = isMentionTriggerBoundaryBeforeSelection(
20055
20283
  currentEditor
20056
20284
  ) ? "@" : " @";
20057
- currentEditor.chain().focus().insertContent(triggerText).run();
20285
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20286
+ currentEditor.chain().focus().setMeta(AGENT_RICH_TEXT_SKIP_USER_CONTENT_EVENT_META, true).insertContent(triggerText).run();
20058
20287
  },
20059
20288
  insertWorkspaceReferences(items) {
20060
20289
  const currentEditor = input.editorRef.current;
20061
20290
  if (!currentEditor || currentEditor.isDestroyed || items.length === 0) {
20062
20291
  return;
20063
20292
  }
20293
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20064
20294
  currentEditor.chain().focus().insertContent(
20065
20295
  createAgentFileMentionContent(items, {
20066
20296
  prefixCaretAnchor: isPromptVisualLineStart(
@@ -20075,6 +20305,7 @@ function useAgentRichTextEditorHandle(input) {
20075
20305
  if (!currentEditor || currentEditor.isDestroyed || items.length === 0) {
20076
20306
  return;
20077
20307
  }
20308
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20078
20309
  currentEditor.chain().focus().insertContent(
20079
20310
  createAgentMentionContent(items, {
20080
20311
  prefixCaretAnchor: isPromptVisualLineStart(
@@ -20091,6 +20322,7 @@ function useAgentRichTextEditorHandle(input) {
20091
20322
  }
20092
20323
  const to = currentEditor.state.selection.from;
20093
20324
  const from = Math.max(1, to - length);
20325
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20094
20326
  currentEditor.chain().focus().insertContentAt(
20095
20327
  { from, to },
20096
20328
  plainTextToAgentRichTextInlineContent(text, {
@@ -20106,7 +20338,10 @@ function useAgentRichTextEditorHandle(input) {
20106
20338
  }
20107
20339
 
20108
20340
  // agent-gui/agentGuiNode/agentRichText/AgentRichTextEditorSurface.tsx
20109
- import { useCallback as useCallback35, useRef as useRef24 } from "react";
20341
+ import {
20342
+ useCallback as useCallback35,
20343
+ useRef as useRef24
20344
+ } from "react";
20110
20345
  import { createPortal as createPortal2 } from "react-dom";
20111
20346
  import { EditorContent } from "@tiptap/react";
20112
20347
  import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
@@ -20118,66 +20353,75 @@ function AgentRichTextEditorSurface({
20118
20353
  disabled,
20119
20354
  editor,
20120
20355
  handleKeyDownCapture,
20356
+ handlePointerDownCapture,
20121
20357
  pasteClipboardText,
20122
20358
  placeholder,
20123
20359
  t
20124
20360
  }) {
20125
- return /* @__PURE__ */ jsxs20("div", { className: "relative min-w-0", onKeyDownCapture: handleKeyDownCapture, children: [
20126
- editor ? /* @__PURE__ */ jsx27(EditorContent, { editor }) : /* @__PURE__ */ jsx27(
20127
- "div",
20128
- {
20129
- role: "textbox",
20130
- "aria-label": placeholder,
20131
- "aria-disabled": disabled ? "true" : "false",
20132
- "aria-multiline": "true",
20133
- className: cn(
20134
- className,
20135
- "overflow-y-auto whitespace-pre-wrap break-words [&_p]:m-0 [&_p]:min-h-[1.45em]"
20136
- )
20137
- }
20138
- ),
20139
- contextMenu ? createPortal2(
20140
- /* @__PURE__ */ jsxs20(
20141
- "div",
20142
- {
20143
- role: "menu",
20144
- "aria-label": t("agentHost.agentGui.composerTextMenu"),
20145
- className: "fixed z-[var(--z-popover)] min-w-[132px] rounded-[8px] border border-[var(--line-1)] bg-[var(--background-panel)] p-1 text-[13px] text-[var(--text-primary)] shadow-[0_14px_34px_rgb(0_0_0_/_0.28)]",
20146
- "data-agent-composer-text-menu": "true",
20147
- style: { left: contextMenu.x, top: contextMenu.y },
20148
- onContextMenu: (event) => event.preventDefault(),
20149
- onPointerDown: (event) => event.stopPropagation(),
20150
- children: [
20151
- /* @__PURE__ */ jsx27(
20152
- AgentRichTextContextMenuButton,
20153
- {
20154
- disabled: !contextMenu.canEdit || !contextMenu.hasSelection,
20155
- label: t("common.cut"),
20156
- onSelect: cutSelection
20157
- }
20158
- ),
20159
- /* @__PURE__ */ jsx27(
20160
- AgentRichTextContextMenuButton,
20161
- {
20162
- disabled: !contextMenu.hasSelection,
20163
- label: t("common.copy"),
20164
- onSelect: copySelection
20165
- }
20166
- ),
20167
- /* @__PURE__ */ jsx27(
20168
- AgentRichTextContextMenuButton,
20169
- {
20170
- disabled: !contextMenu.canEdit,
20171
- label: t("common.paste"),
20172
- onSelect: pasteClipboardText
20173
- }
20361
+ return /* @__PURE__ */ jsxs20(
20362
+ "div",
20363
+ {
20364
+ className: "relative min-w-0",
20365
+ onKeyDownCapture: handleKeyDownCapture,
20366
+ onPointerDownCapture: handlePointerDownCapture,
20367
+ children: [
20368
+ editor ? /* @__PURE__ */ jsx27(EditorContent, { editor }) : /* @__PURE__ */ jsx27(
20369
+ "div",
20370
+ {
20371
+ role: "textbox",
20372
+ "aria-label": placeholder,
20373
+ "aria-disabled": disabled ? "true" : "false",
20374
+ "aria-multiline": "true",
20375
+ className: cn(
20376
+ className,
20377
+ "overflow-y-auto whitespace-pre-wrap break-words [&_p]:m-0 [&_p]:min-h-[1.45em]"
20174
20378
  )
20175
- ]
20176
- }
20177
- ),
20178
- document.body
20179
- ) : null
20180
- ] });
20379
+ }
20380
+ ),
20381
+ contextMenu ? createPortal2(
20382
+ /* @__PURE__ */ jsxs20(
20383
+ "div",
20384
+ {
20385
+ role: "menu",
20386
+ "aria-label": t("agentHost.agentGui.composerTextMenu"),
20387
+ className: "fixed z-[var(--z-popover)] min-w-[132px] rounded-[8px] border border-[var(--line-1)] bg-[var(--background-panel)] p-1 text-[13px] text-[var(--text-primary)] shadow-[0_14px_34px_rgb(0_0_0_/_0.28)]",
20388
+ "data-agent-composer-text-menu": "true",
20389
+ style: { left: contextMenu.x, top: contextMenu.y },
20390
+ onContextMenu: (event) => event.preventDefault(),
20391
+ onPointerDown: (event) => event.stopPropagation(),
20392
+ children: [
20393
+ /* @__PURE__ */ jsx27(
20394
+ AgentRichTextContextMenuButton,
20395
+ {
20396
+ disabled: !contextMenu.canEdit || !contextMenu.hasSelection,
20397
+ label: t("common.cut"),
20398
+ onSelect: cutSelection
20399
+ }
20400
+ ),
20401
+ /* @__PURE__ */ jsx27(
20402
+ AgentRichTextContextMenuButton,
20403
+ {
20404
+ disabled: !contextMenu.hasSelection,
20405
+ label: t("common.copy"),
20406
+ onSelect: copySelection
20407
+ }
20408
+ ),
20409
+ /* @__PURE__ */ jsx27(
20410
+ AgentRichTextContextMenuButton,
20411
+ {
20412
+ disabled: !contextMenu.canEdit,
20413
+ label: t("common.paste"),
20414
+ onSelect: pasteClipboardText
20415
+ }
20416
+ )
20417
+ ]
20418
+ }
20419
+ ),
20420
+ document.body
20421
+ ) : null
20422
+ ]
20423
+ }
20424
+ );
20181
20425
  }
20182
20426
  function AgentRichTextContextMenuButton({
20183
20427
  disabled,
@@ -20265,6 +20509,8 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20265
20509
  removeMentionLabel,
20266
20510
  className,
20267
20511
  onChange,
20512
+ onFocus,
20513
+ onUserContentChange,
20268
20514
  onSubmit,
20269
20515
  onSubmitGuidance,
20270
20516
  availableCapabilities = [],
@@ -20287,6 +20533,9 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20287
20533
  const lastEmittedPromptRef = useRef25(value);
20288
20534
  const editorRef = useRef25(null);
20289
20535
  const onChangeRef = useRef25(onChange);
20536
+ const onFocusRef = useRef25(onFocus);
20537
+ const onUserContentChangeRef = useRef25(onUserContentChange);
20538
+ const pendingFocusMethodRef = useRef25(null);
20290
20539
  const onSubmitRef = useRef25(onSubmit);
20291
20540
  const onSubmitGuidanceRef = useRef25(onSubmitGuidance);
20292
20541
  const onKeyDownForPaletteRef = useRef25(onKeyDownForPalette);
@@ -20324,9 +20573,7 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20324
20573
  }
20325
20574
  suppressPastedAtSuggestionRef.current = text.includes("@") && !text.endsWith("@");
20326
20575
  if (suppressPastedAtSuggestionRef.current) {
20327
- window.setTimeout(() => {
20328
- suppressPastedAtSuggestionRef.current = false;
20329
- }, 0);
20576
+ releasePastedAtSuggestionSuppression(suppressPastedAtSuggestionRef);
20330
20577
  }
20331
20578
  currentEditor.chain().focus().insertContent(
20332
20579
  plainTextToAgentRichTextInlineContent(text, {
@@ -20394,7 +20641,7 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20394
20641
  scrollEditorSelectionIntoView(currentEditor);
20395
20642
  });
20396
20643
  };
20397
- const extensions = useMemo25(
20644
+ const extensions = useMemo26(
20398
20645
  () => [
20399
20646
  ...createAgentRichTextInputExtensions(
20400
20647
  {
@@ -20413,6 +20660,8 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20413
20660
  [enableFileMentionSuggestions]
20414
20661
  );
20415
20662
  onChangeRef.current = onChange;
20663
+ onFocusRef.current = onFocus;
20664
+ onUserContentChangeRef.current = onUserContentChange;
20416
20665
  onSubmitRef.current = onSubmit;
20417
20666
  onSubmitGuidanceRef.current = onSubmitGuidance;
20418
20667
  onKeyDownForPaletteRef.current = onKeyDownForPalette;
@@ -20603,9 +20852,7 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20603
20852
  }
20604
20853
  suppressPastedAtSuggestionRef.current = text.includes("@") && !text.endsWith("@");
20605
20854
  if (suppressPastedAtSuggestionRef.current) {
20606
- window.setTimeout(() => {
20607
- suppressPastedAtSuggestionRef.current = false;
20608
- }, 0);
20855
+ releasePastedAtSuggestionSuppression(suppressPastedAtSuggestionRef);
20609
20856
  }
20610
20857
  currentEditor.commands.insertContent(
20611
20858
  plainTextToAgentRichTextInlineContent(text, {
@@ -20735,7 +20982,7 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20735
20982
  }
20736
20983
  }
20737
20984
  },
20738
- onUpdate: ({ editor: nextEditor }) => {
20985
+ onUpdate: ({ editor: nextEditor, transaction }) => {
20739
20986
  editorRef.current = nextEditor;
20740
20987
  scheduleSelectionScroll(nextEditor);
20741
20988
  const nextPrompt = editorToPromptText(nextEditor);
@@ -20743,8 +20990,20 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20743
20990
  return;
20744
20991
  }
20745
20992
  lastEmittedPromptRef.current = nextPrompt;
20993
+ if (isAgentRichTextUserContentInsertion(transaction)) {
20994
+ onUserContentChangeRef.current?.(nextPrompt);
20995
+ }
20746
20996
  onChangeRef.current(nextPrompt);
20747
20997
  },
20998
+ onFocus: ({ editor: nextEditor }) => {
20999
+ const pendingMethod = pendingFocusMethodRef.current;
21000
+ const focusMethod = pendingMethod ?? (nextEditor.view.dom.matches(":focus-visible") ? "keyboard" : "programmatic");
21001
+ pendingFocusMethodRef.current = null;
21002
+ onFocusRef.current?.(focusMethod);
21003
+ },
21004
+ onBlur: () => {
21005
+ pendingFocusMethodRef.current = null;
21006
+ },
20748
21007
  onCreate: ({ editor: nextEditor }) => {
20749
21008
  editorRef.current = nextEditor;
20750
21009
  nextEditor.commands.setTextSelection(nextEditor.state.doc.content.size);
@@ -20760,9 +21019,6 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20760
21019
  submitOnEnter
20761
21020
  });
20762
21021
  };
20763
- useEffect24(() => {
20764
- editorRef.current = editor;
20765
- }, [editor]);
20766
21022
  useEffect24(
20767
21023
  () => () => {
20768
21024
  if (scrollFrameRef.current !== null && typeof window.cancelAnimationFrame === "function") {
@@ -20794,6 +21050,9 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20794
21050
  availableCapabilitiesRef,
20795
21051
  availableSkillsRef,
20796
21052
  editorRef,
21053
+ onBeforeProgrammaticFocus: () => {
21054
+ pendingFocusMethodRef.current = "programmatic";
21055
+ },
20797
21056
  ref
20798
21057
  });
20799
21058
  useEffect24(() => {
@@ -20836,12 +21095,18 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20836
21095
  disabled,
20837
21096
  editor,
20838
21097
  handleKeyDownCapture,
21098
+ handlePointerDownCapture: () => markAgentRichTextPointerFocus(pendingFocusMethodRef),
20839
21099
  pasteClipboardText,
20840
21100
  placeholder,
20841
21101
  t
20842
21102
  }
20843
21103
  );
20844
21104
  });
21105
+ function releasePastedAtSuggestionSuppression(ref) {
21106
+ window.setTimeout(() => {
21107
+ ref.current = false;
21108
+ }, 0);
21109
+ }
20845
21110
 
20846
21111
  // agent-gui/agentGuiNode/AgentSlashCommandPalette.tsx
20847
21112
  import { Fragment as Fragment8, useEffect as useEffect25, useRef as useRef26 } from "react";
@@ -21089,7 +21354,7 @@ function slashPaletteEntryIcon(entry) {
21089
21354
  }
21090
21355
 
21091
21356
  // agent-gui/agentGuiNode/AgentReviewPickerPanel.tsx
21092
- import { useCallback as useCallback37, useEffect as useEffect26, useMemo as useMemo26, useRef as useRef27, useState as useState18 } from "react";
21357
+ import { useCallback as useCallback37, useEffect as useEffect26, useMemo as useMemo27, useRef as useRef27, useState as useState18 } from "react";
21093
21358
  import { menuItemClassName } from "@tutti-os/ui-system";
21094
21359
 
21095
21360
  // agent-gui/agentGuiNode/AgentReviewBranchController.ts
@@ -21259,7 +21524,7 @@ function AgentReviewPickerPanel({
21259
21524
  }, []);
21260
21525
  const trimmedQuery = query.trim();
21261
21526
  const normalizedQuery = trimmedQuery.toLowerCase();
21262
- const entries = useMemo26(() => {
21527
+ const entries = useMemo27(() => {
21263
21528
  if (stage === "root") {
21264
21529
  const options = [
21265
21530
  {
@@ -21453,7 +21718,7 @@ import {
21453
21718
  useCallback as useCallback38,
21454
21719
  useEffect as useEffect27,
21455
21720
  useLayoutEffect as useLayoutEffect5,
21456
- useMemo as useMemo27,
21721
+ useMemo as useMemo28,
21457
21722
  useRef as useRef28,
21458
21723
  useState as useState19
21459
21724
  } from "react";
@@ -21662,7 +21927,7 @@ var ComposerFloatingMenuSurface = forwardRef4(function ComposerFloatingMenuSurfa
21662
21927
  window.removeEventListener("blur", onDismiss);
21663
21928
  };
21664
21929
  }, [anchorRef, dismissBoundaryRef, onDismiss, open]);
21665
- const style = useMemo27(() => {
21930
+ const style = useMemo28(() => {
21666
21931
  const baseStyle = {
21667
21932
  position: "fixed",
21668
21933
  left: `${frame?.left ?? 0}px`,
@@ -22351,8 +22616,10 @@ function AgentComposerView(input) {
22351
22616
  slashStatus = null,
22352
22617
  usage = null,
22353
22618
  draftContent,
22619
+ engagement,
22354
22620
  availableSkills = EMPTY_PROVIDER_SKILLS,
22355
22621
  composerSettings,
22622
+ workspaceId,
22356
22623
  queueStatus = "active",
22357
22624
  queuedPrompts,
22358
22625
  drainingQueuedPromptId,
@@ -22382,6 +22649,7 @@ function AgentComposerView(input) {
22382
22649
  hasCompactableContext = true
22383
22650
  } = input.props;
22384
22651
  const draftImages = agentComposerDraftImages(draftContent);
22652
+ const slashStatusAgentSessionId = slashStatus?.agentSessionId ?? null;
22385
22653
  const { availableCapabilities, slashPaletteEntries, slashQuery } = input.paletteCatalog;
22386
22654
  const { mentionPaletteFrame, mentionPaletteHeightPx, mentionPaletteStyle } = input.mentionFrame;
22387
22655
  const {
@@ -22531,7 +22799,9 @@ function AgentComposerView(input) {
22531
22799
  onSendQueuedPromptNext,
22532
22800
  onRemoveQueuedPrompt,
22533
22801
  onEditQueuedPrompt,
22802
+ agentSessionId: slashStatusAgentSessionId,
22534
22803
  onLinkClick: handleLinkClick,
22804
+ workspaceId,
22535
22805
  workspaceAppIcons
22536
22806
  }
22537
22807
  )
@@ -22634,6 +22904,19 @@ function AgentComposerView(input) {
22634
22904
  disabled: inputDisabled,
22635
22905
  className: AgentGUINode_styles_default.composerTextarea,
22636
22906
  onChange: handleDraftChange,
22907
+ onFocus: (method) => engagement?.focused(method),
22908
+ onUserContentChange: (nextPrompt) => {
22909
+ if (agentComposerDraftHasContent(
22910
+ updateAgentComposerDraft(draftContent, {
22911
+ prompt: nextPrompt
22912
+ })
22913
+ )) {
22914
+ engagement?.contentEntered({
22915
+ contentType: "text",
22916
+ hadPrefill: agentComposerDraftHasContent(draftContent)
22917
+ });
22918
+ }
22919
+ },
22637
22920
  onSubmit: submitCurrentPrompt,
22638
22921
  onSubmitGuidance: () => submitCurrentPrompt({ guidance: true }),
22639
22922
  availableSkills,
@@ -22901,6 +23184,7 @@ function AgentComposer(props) {
22901
23184
  provider,
22902
23185
  slashStatus = null,
22903
23186
  draftContent,
23187
+ engagement,
22904
23188
  draftScopeKey = "current",
22905
23189
  availableCommands,
22906
23190
  hasCompactableContext = true,
@@ -22971,6 +23255,12 @@ function AgentComposer(props) {
22971
23255
  const pastedTextStagingSupported = Boolean(
22972
23256
  canUploadAttachment && agentActivityRuntime?.stagePastedText
22973
23257
  );
23258
+ const reportContentEntered = (contentType) => {
23259
+ engagement?.contentEntered({
23260
+ contentType,
23261
+ hadPrefill: agentComposerDraftHasContent(draftContent)
23262
+ });
23263
+ };
22974
23264
  const [isPaletteOpen, setIsPaletteOpen] = useState20(true);
22975
23265
  const [isReviewPickerOpen, setIsReviewPickerOpen] = useState20(false);
22976
23266
  const [isHandoffIconPlaying, setIsHandoffIconPlaying] = useState20(false);
@@ -23245,6 +23535,7 @@ function AgentComposer(props) {
23245
23535
  clearActiveFileMentionTrigger,
23246
23536
  onDraftContentChange,
23247
23537
  onPromptImagesUnsupported,
23538
+ onContentEntered: reportContentEntered,
23248
23539
  onRequestWorkspaceReferences,
23249
23540
  resolveDroppedFileReferences,
23250
23541
  onLinkAction
@@ -23774,7 +24065,7 @@ var AgentGUIEmptyHomePane = memo3(function AgentGUIEmptyHomePane2({
23774
24065
  const providerLabel = selectedAgentTarget?.label ?? runtimeProviderLabel;
23775
24066
  const baseLabel = labels.emptyForProvider?.(provider) ?? labels.empty;
23776
24067
  const emptyLabel = runtimeProviderLabel ? baseLabel.replace(runtimeProviderLabel, providerLabel) : baseLabel;
23777
- const avatarPresentations = useMemo28(
24068
+ const avatarPresentations = useMemo29(
23778
24069
  () => agentTargets.length ? agentTargets.map(projectAgentGUIAgentTargetAvatar) : selectedAgentTarget ? [projectAgentGUIAgentTargetAvatar(selectedAgentTarget)] : [
23779
24070
  createFallbackAgentGUIAgentAvatar({
23780
24071
  provider,
@@ -24882,7 +25173,7 @@ var AgentGUIProviderRail = memo4(function AgentGUIProviderRail2({
24882
25173
  },
24883
25174
  []
24884
25175
  );
24885
- const railProviderTargets = useMemo29(
25176
+ const railProviderTargets = useMemo30(
24886
25177
  () => agentGUIProviderRailTargets(
24887
25178
  agentTargets,
24888
25179
  agentTargetsLoading,
@@ -24891,7 +25182,7 @@ var AgentGUIProviderRail = memo4(function AgentGUIProviderRail2({
24891
25182
  ),
24892
25183
  [comingSoonProviders, providerRailMode, agentTargets, agentTargetsLoading]
24893
25184
  );
24894
- const providerTiles = useMemo29(() => {
25185
+ const providerTiles = useMemo30(() => {
24895
25186
  const targets = [...railProviderTargets];
24896
25187
  const orderedTargets = providerRailMode === "exact" ? targets : (() => {
24897
25188
  const originalIndexByTarget = /* @__PURE__ */ new Map();
@@ -24931,7 +25222,7 @@ var AgentGUIProviderRail = memo4(function AgentGUIProviderRail2({
24931
25222
  agentTargets: providerTiles,
24932
25223
  conversations
24933
25224
  });
24934
- const visibleProviderTiles = useMemo29(
25225
+ const visibleProviderTiles = useMemo30(
24935
25226
  () => applyAgentGUIProviderRailVisibility(
24936
25227
  providerTiles,
24937
25228
  effectiveHiddenTargetIds
@@ -25356,7 +25647,7 @@ import {
25356
25647
  useCallback as useCallback43,
25357
25648
  useEffect as useEffect30,
25358
25649
  useLayoutEffect as useLayoutEffect6,
25359
- useMemo as useMemo31,
25650
+ useMemo as useMemo32,
25360
25651
  useRef as useRef33,
25361
25652
  useState as useState27
25362
25653
  } from "react";
@@ -25845,7 +26136,10 @@ function projectConversationRailSectionsWithActiveConversation(input) {
25845
26136
  if (loadedSection) {
25846
26137
  return {
25847
26138
  activeOverlay: {
25848
- conversation: loadedSection.kind === "project" ? { ...activeConversation, project: loadedSection.project } : activeConversation,
26139
+ conversation: loadedSection.kind === "project" ? conversationWithRailProject(
26140
+ activeConversation,
26141
+ loadedSection.project
26142
+ ) : activeConversation,
25849
26143
  sectionId: loadedSection.id
25850
26144
  },
25851
26145
  sections: input.sections
@@ -25865,7 +26159,10 @@ function projectConversationRailSectionsWithActiveConversation(input) {
25865
26159
  const matchingSection = input.sections[matchingSectionIndex];
25866
26160
  return {
25867
26161
  activeOverlay: {
25868
- conversation: matchingSection?.kind === "project" ? { ...activeConversation, project: matchingSection.project } : activeConversation,
26162
+ conversation: matchingSection?.kind === "project" ? conversationWithRailProject(
26163
+ activeConversation,
26164
+ matchingSection.project
26165
+ ) : activeConversation,
25869
26166
  sectionId: activeSection.id
25870
26167
  },
25871
26168
  sections: input.sections
@@ -25899,6 +26196,9 @@ function projectConversationRailSectionsWithActiveConversation(input) {
25899
26196
  sections
25900
26197
  };
25901
26198
  }
26199
+ function conversationWithRailProject(conversation, project) {
26200
+ return conversationProjectsRenderEqual2(conversation.project, project) ? conversation : { ...conversation, project };
26201
+ }
25902
26202
  function planRuntimeRailMembershipRefresh(input) {
25903
26203
  const previousPendingIds = new Set(
25904
26204
  input.previous.flatMap((conversation) => {
@@ -26140,7 +26440,7 @@ import {
26140
26440
  import {
26141
26441
  memo as memo5,
26142
26442
  useCallback as useCallback41,
26143
- useMemo as useMemo30,
26443
+ useMemo as useMemo31,
26144
26444
  useRef as useRef32,
26145
26445
  useState as useState25
26146
26446
  } from "react";
@@ -26206,6 +26506,7 @@ var AgentGUIConversationRailItem = memo5(
26206
26506
  active,
26207
26507
  isPendingDeleteConversation,
26208
26508
  isDeletingConversation,
26509
+ isRailInteractionLocked,
26209
26510
  currentTimeMs,
26210
26511
  labels,
26211
26512
  previewMode,
@@ -26242,63 +26543,89 @@ var AgentGUIConversationRailItem = memo5(
26242
26543
  const contextMenuCopySessionLinkRequestedRef = useRef32(false);
26243
26544
  const agentHostApi = useOptionalAgentHostApi();
26244
26545
  const handleMouseLeave = useCallback41(() => {
26245
- if (isPendingDeleteConversation) {
26546
+ if (isPendingDeleteConversation && !isRailInteractionLocked()) {
26246
26547
  onCancelDeleteConversation();
26247
26548
  }
26248
- }, [isPendingDeleteConversation, onCancelDeleteConversation]);
26549
+ }, [
26550
+ isPendingDeleteConversation,
26551
+ isRailInteractionLocked,
26552
+ onCancelDeleteConversation
26553
+ ]);
26249
26554
  const handleSelect = useCallback41(() => {
26555
+ if (isRailInteractionLocked()) return;
26250
26556
  onSelectConversation(item.id);
26251
- }, [item.id, onSelectConversation]);
26557
+ }, [isRailInteractionLocked, item.id, onSelectConversation]);
26252
26558
  const handleTogglePinned = useCallback41(() => {
26559
+ if (isRailInteractionLocked()) return;
26253
26560
  onToggleConversationPinned(item.id, !pinned);
26254
- }, [item.id, onToggleConversationPinned, pinned]);
26561
+ }, [isRailInteractionLocked, item.id, onToggleConversationPinned, pinned]);
26255
26562
  const canMarkUnread = Boolean(
26256
26563
  !previewMode && !item.hasUnreadCompletion && item.isImported !== true && (item.unreadCompletionKey || item.status === "completed" || item.status === "ready")
26257
26564
  );
26258
26565
  const handleMarkUnread = useCallback41(() => {
26259
- if (!canMarkUnread) {
26566
+ if (!canMarkUnread || isRailInteractionLocked()) {
26260
26567
  return;
26261
26568
  }
26262
26569
  onMarkConversationUnread(item.id);
26263
- }, [canMarkUnread, item.id, onMarkConversationUnread]);
26570
+ }, [
26571
+ canMarkUnread,
26572
+ isRailInteractionLocked,
26573
+ item.id,
26574
+ onMarkConversationUnread
26575
+ ]);
26264
26576
  const handleOpenConversationWindow = useCallback41(() => {
26577
+ if (isRailInteractionLocked()) return;
26265
26578
  onOpenConversationWindow?.(item.id);
26266
- }, [item.id, onOpenConversationWindow]);
26579
+ }, [isRailInteractionLocked, item.id, onOpenConversationWindow]);
26267
26580
  const handleRequestDelete = useCallback41(() => {
26581
+ if (isRailInteractionLocked()) return;
26268
26582
  onRequestDeleteConversation(item.id);
26269
- }, [item.id, onRequestDeleteConversation]);
26583
+ }, [isRailInteractionLocked, item.id, onRequestDeleteConversation]);
26270
26584
  const handleRequestRename = useCallback41(() => {
26585
+ if (isRailInteractionLocked()) return;
26271
26586
  onRequestRenameConversation(item);
26272
- }, [item, onRequestRenameConversation]);
26587
+ }, [isRailInteractionLocked, item, onRequestRenameConversation]);
26273
26588
  const handleContextMenuRename = useCallback41(() => {
26274
- if (contextMenuRenameRequestedRef.current) {
26589
+ if (isRailInteractionLocked() || contextMenuRenameRequestedRef.current) {
26275
26590
  return;
26276
26591
  }
26277
26592
  contextMenuRenameRequestedRef.current = true;
26278
26593
  setContextMenuResetKey((key) => key + 1);
26279
26594
  window.setTimeout(() => {
26595
+ if (isRailInteractionLocked()) {
26596
+ contextMenuRenameRequestedRef.current = false;
26597
+ return;
26598
+ }
26280
26599
  handleRequestRename();
26281
26600
  contextMenuRenameRequestedRef.current = false;
26282
26601
  }, 0);
26283
- }, [handleRequestRename]);
26602
+ }, [handleRequestRename, isRailInteractionLocked]);
26284
26603
  const handleContextMenuOpenConversationWindow = useCallback41(() => {
26285
- if (contextMenuOpenConversationWindowRequestedRef.current) {
26604
+ if (isRailInteractionLocked() || contextMenuOpenConversationWindowRequestedRef.current) {
26286
26605
  return;
26287
26606
  }
26288
26607
  contextMenuOpenConversationWindowRequestedRef.current = true;
26289
26608
  setContextMenuResetKey((key) => key + 1);
26290
26609
  window.setTimeout(() => {
26610
+ if (isRailInteractionLocked()) {
26611
+ contextMenuOpenConversationWindowRequestedRef.current = false;
26612
+ return;
26613
+ }
26291
26614
  handleOpenConversationWindow();
26292
26615
  contextMenuOpenConversationWindowRequestedRef.current = false;
26293
26616
  }, 0);
26294
- }, [handleOpenConversationWindow]);
26617
+ }, [handleOpenConversationWindow, isRailInteractionLocked]);
26295
26618
  const handleContextMenuCopySessionLink = useCallback41(() => {
26296
- if (contextMenuCopySessionLinkRequestedRef.current) {
26619
+ if (isRailInteractionLocked() || contextMenuCopySessionLinkRequestedRef.current) {
26297
26620
  return;
26298
26621
  }
26299
26622
  contextMenuCopySessionLinkRequestedRef.current = true;
26300
26623
  setContextMenuResetKey((key) => key + 1);
26301
26624
  window.setTimeout(() => {
26625
+ if (isRailInteractionLocked()) {
26626
+ contextMenuCopySessionLinkRequestedRef.current = false;
26627
+ return;
26628
+ }
26302
26629
  if (!agentHostApi?.clipboard?.writeText) {
26303
26630
  contextMenuCopySessionLinkRequestedRef.current = false;
26304
26631
  return;
@@ -26315,7 +26642,14 @@ var AgentGUIConversationRailItem = memo5(
26315
26642
  contextMenuCopySessionLinkRequestedRef.current = false;
26316
26643
  });
26317
26644
  }, 0);
26318
- }, [agentHostApi, item, labels, uiLanguage, workspaceId]);
26645
+ }, [
26646
+ agentHostApi,
26647
+ isRailInteractionLocked,
26648
+ item,
26649
+ labels,
26650
+ uiLanguage,
26651
+ workspaceId
26652
+ ]);
26319
26653
  const row = /* @__PURE__ */ jsxs33(
26320
26654
  "div",
26321
26655
  {
@@ -26325,6 +26659,12 @@ var AgentGUIConversationRailItem = memo5(
26325
26659
  "data-pinned": pinned,
26326
26660
  "data-pending-delete": isPendingDeleteConversation,
26327
26661
  "data-testid": `agent-gui-conversation-item-${item.id}`,
26662
+ onContextMenuCapture: (event) => {
26663
+ if (isRailInteractionLocked()) {
26664
+ event.preventDefault();
26665
+ event.stopPropagation();
26666
+ }
26667
+ },
26328
26668
  onMouseLeave: handleMouseLeave,
26329
26669
  children: [
26330
26670
  /* @__PURE__ */ jsxs33(
@@ -26365,7 +26705,9 @@ var AgentGUIConversationRailItem = memo5(
26365
26705
  disabled: isDeletingConversation,
26366
26706
  onClick: (event) => {
26367
26707
  event.stopPropagation();
26368
- onConfirmDeleteConversation();
26708
+ if (!isRailInteractionLocked()) {
26709
+ onConfirmDeleteConversation();
26710
+ }
26369
26711
  },
26370
26712
  children: /* @__PURE__ */ jsx46("span", { className: AgentGUINode_styles_default.conversationDeleteConfirmText, children: labels.deleteSessionConfirm })
26371
26713
  }
@@ -26502,13 +26844,14 @@ var AgentGUIConversationRailItem = memo5(
26502
26844
  }
26503
26845
  );
26504
26846
  function AgentGUIProjectRailHeader({
26847
+ disabled,
26505
26848
  labels,
26506
26849
  selectProjectDirectory,
26507
26850
  workspaceUserProjectI18n
26508
26851
  }) {
26509
26852
  "use memo";
26510
26853
  const agentHostApi = useAgentHostApi();
26511
- const userProjectApi = useMemo30(
26854
+ const userProjectApi = useMemo31(
26512
26855
  () => agentHostApi.userProjects ? {
26513
26856
  ...agentHostApi.userProjects,
26514
26857
  selectDirectory: selectProjectDirectory ?? agentHostApi.workspace.selectDirectory
@@ -26543,6 +26886,7 @@ function AgentGUIProjectRailHeader({
26543
26886
  contentAlign: "end",
26544
26887
  contentSide: "bottom",
26545
26888
  contentSideOffset: 6,
26889
+ disabled,
26546
26890
  i18n: workspaceUserProjectI18n,
26547
26891
  labels: {
26548
26892
  addProject: labels.projectRailCreateProject,
@@ -26601,6 +26945,7 @@ var AgentGUIConversationRailSection = memo6(
26601
26945
  isRequestingBatchDeletion,
26602
26946
  isConversationSearchActive,
26603
26947
  isLoadingMoreConversations,
26948
+ isRailInteractionLocked,
26604
26949
  sectionHasMore,
26605
26950
  sectionTotalCount,
26606
26951
  createConversationDisabled,
@@ -26663,6 +27008,7 @@ var AgentGUIConversationRailSection = memo6(
26663
27008
  const canShowMore = !isSectionCollapsed && visibleCountTowardTotal < sectionTotalCount && (visibleItemCount < pageableItems.length || sectionHasMore);
26664
27009
  const canShowLess = !isSectionCollapsed && visibleItemCount > AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE;
26665
27010
  const showMoreConversations = useCallback42(() => {
27011
+ if (isRailInteractionLocked()) return;
26666
27012
  if (visibleItemCount >= pageableItems.length && sectionHasMore) {
26667
27013
  onLoadMoreConversations(section);
26668
27014
  setVisibleItemLimitState((current) => ({
@@ -26680,6 +27026,7 @@ var AgentGUIConversationRailSection = memo6(
26680
27026
  }));
26681
27027
  }, [
26682
27028
  onLoadMoreConversations,
27029
+ isRailInteractionLocked,
26683
27030
  pageableItems.length,
26684
27031
  paginationScopeKey,
26685
27032
  section,
@@ -26687,14 +27034,16 @@ var AgentGUIConversationRailSection = memo6(
26687
27034
  visibleItemCount
26688
27035
  ]);
26689
27036
  const showLessConversations = useCallback42(() => {
27037
+ if (isRailInteractionLocked()) return;
26690
27038
  setVisibleItemLimitState({
26691
27039
  limit: AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE,
26692
27040
  scopeKey: paginationScopeKey
26693
27041
  });
26694
- }, [paginationScopeKey]);
27042
+ }, [isRailInteractionLocked, paginationScopeKey]);
26695
27043
  const canCreateConversationFromSection = section.kind === "conversations" || Boolean(projectPath);
26696
27044
  const createConversationLabel = projectPath ? labels.projectSectionEdit : labels.newConversation;
26697
27045
  const handleCreateConversation = useCallback42(() => {
27046
+ if (isRailInteractionLocked()) return;
26698
27047
  if (projectPath) {
26699
27048
  onCreateConversation({ projectPath, source: "project_section" });
26700
27049
  return;
@@ -26703,7 +27052,7 @@ var AgentGUIConversationRailSection = memo6(
26703
27052
  projectPath: null,
26704
27053
  source: "unscoped_section"
26705
27054
  });
26706
- }, [onCreateConversation, projectPath]);
27055
+ }, [isRailInteractionLocked, onCreateConversation, projectPath]);
26707
27056
  return /* @__PURE__ */ jsxs34(
26708
27057
  "section",
26709
27058
  {
@@ -26718,7 +27067,11 @@ var AgentGUIConversationRailSection = memo6(
26718
27067
  type: "button",
26719
27068
  className: AgentGUINode_styles_default.conversationSectionToggle,
26720
27069
  "aria-expanded": !isSectionCollapsed,
26721
- onClick: () => onToggleProjectSectionCollapsed(section.id),
27070
+ onClick: () => {
27071
+ if (!isRailInteractionLocked()) {
27072
+ onToggleProjectSectionCollapsed(section.id);
27073
+ }
27074
+ },
26722
27075
  children: [
26723
27076
  /* @__PURE__ */ jsx47(
26724
27077
  ChevronRight2,
@@ -26839,6 +27192,7 @@ var AgentGUIConversationRailSection = memo6(
26839
27192
  className: `${AgentGUINode_styles_default.composerMenuItem} nodrag [-webkit-app-region:no-drag]`,
26840
27193
  disabled: !onOpenProjectFiles,
26841
27194
  onSelect: () => {
27195
+ if (isRailInteractionLocked()) return;
26842
27196
  onOpenProjectFiles?.({
26843
27197
  directoryPath: projectPath,
26844
27198
  mode: "open-directory",
@@ -26856,7 +27210,11 @@ var AgentGUIConversationRailSection = memo6(
26856
27210
  {
26857
27211
  className: `${AgentGUINode_styles_default.composerMenuItem} nodrag [-webkit-app-region:no-drag]`,
26858
27212
  disabled: isConversationSearchActive || section.items.length === 0 && !sectionHasMore || isDeletingProjectConversations || isRequestingBatchDeletion,
26859
- onSelect: () => onRequestSectionBatchDeletion(section),
27213
+ onSelect: () => {
27214
+ if (!isRailInteractionLocked()) {
27215
+ onRequestSectionBatchDeletion(section);
27216
+ }
27217
+ },
26860
27218
  children: /* @__PURE__ */ jsx47("span", { children: labels.batchDeleteProjectSessions })
26861
27219
  }
26862
27220
  ),
@@ -26865,6 +27223,7 @@ var AgentGUIConversationRailSection = memo6(
26865
27223
  {
26866
27224
  className: `${AgentGUINode_styles_default.composerMenuItem} nodrag [-webkit-app-region:no-drag]`,
26867
27225
  onSelect: () => {
27226
+ if (isRailInteractionLocked()) return;
26868
27227
  const label = projectLabel || projectPath;
26869
27228
  setPendingProjectAction({
26870
27229
  kind: "remove",
@@ -26931,7 +27290,11 @@ var AgentGUIConversationRailSection = memo6(
26931
27290
  {
26932
27291
  className: `${AgentGUINode_styles_default.composerMenuItem} nodrag [-webkit-app-region:no-drag]`,
26933
27292
  disabled: isConversationSearchActive || section.items.length === 0 && !sectionHasMore || isDeletingProjectConversations || isRequestingBatchDeletion,
26934
- onSelect: () => onRequestSectionBatchDeletion(section),
27293
+ onSelect: () => {
27294
+ if (!isRailInteractionLocked()) {
27295
+ onRequestSectionBatchDeletion(section);
27296
+ }
27297
+ },
26935
27298
  children: /* @__PURE__ */ jsx47("span", { children: labels.batchDeleteConversations })
26936
27299
  }
26937
27300
  )
@@ -26954,6 +27317,7 @@ var AgentGUIConversationRailSection = memo6(
26954
27317
  currentTimeMs,
26955
27318
  isDeletingConversation,
26956
27319
  isPendingDeleteConversation: pendingDeleteConversationId === item.id,
27320
+ isRailInteractionLocked,
26957
27321
  item,
26958
27322
  labels,
26959
27323
  previewMode,
@@ -27068,9 +27432,11 @@ var AgentGUIConversationRailPane = memo7(
27068
27432
  );
27069
27433
  const activeConversationScrollCompletedRef = useRef33(null);
27070
27434
  const previousActiveConversationIdRef = useRef33(null);
27435
+ const railActiveConversationRef = useRef33([]);
27071
27436
  const groupedConversationsRef = useRef33(null);
27072
27437
  const {
27073
27438
  loadMoreSectionConversations,
27439
+ isInteractionLocked,
27074
27440
  runtimeSectionsEnabled,
27075
27441
  runtimeRailConversations,
27076
27442
  runtimeRailMemberships,
@@ -27090,6 +27456,7 @@ var AgentGUIConversationRailPane = memo7(
27090
27456
  const railConversationEntities = [...railConversationEntitiesById.values()];
27091
27457
  const hasConversationQuery = conversationQuery.trim().length > 0;
27092
27458
  const backendSearchActive = hasConversationQuery && railSearch.enabled;
27459
+ const railInteractionsLocked = runtimeRailSectionsPending && !backendSearchActive;
27093
27460
  const backendSearchConversations = backendSearchActive ? railSearch.sessionIds.flatMap((id) => {
27094
27461
  const conversation = railConversationEntitiesById.get(id);
27095
27462
  return conversation ? [conversation] : [];
@@ -27099,11 +27466,17 @@ var AgentGUIConversationRailPane = memo7(
27099
27466
  labels,
27100
27467
  sections: runtimeRailMemberships
27101
27468
  }) : null;
27102
- const railActiveConversation = resolveConversationRailActiveConversation({
27469
+ const railActiveConversationCandidate = resolveConversationRailActiveConversation({
27103
27470
  activeConversation,
27104
27471
  activeConversationId,
27105
27472
  conversations: railConversationEntities
27106
27473
  });
27474
+ const stableRailActiveConversation = stabilizeConversationSectionItems(
27475
+ railActiveConversationRef.current,
27476
+ railActiveConversationCandidate ? [railActiveConversationCandidate] : []
27477
+ );
27478
+ railActiveConversationRef.current = stableRailActiveConversation;
27479
+ const railActiveConversation = stableRailActiveConversation[0] ?? null;
27107
27480
  const runtimeSectionsWithTransientConversations = projectConversationRailSectionsWithTransientConversations({
27108
27481
  conversations,
27109
27482
  labels,
@@ -27125,7 +27498,7 @@ var AgentGUIConversationRailPane = memo7(
27125
27498
  window.clearInterval(timer);
27126
27499
  };
27127
27500
  }, []);
27128
- const displayConversations = useMemo31(() => {
27501
+ const displayConversations = useMemo32(() => {
27129
27502
  if (backendSearchActive) {
27130
27503
  return backendSearchConversations;
27131
27504
  }
@@ -27146,7 +27519,7 @@ var AgentGUIConversationRailPane = memo7(
27146
27519
  runtimeRailSections,
27147
27520
  runtimeSectionsEnabled
27148
27521
  ]);
27149
- const filteredConversationResult = useMemo31(() => {
27522
+ const filteredConversationResult = useMemo32(() => {
27150
27523
  const startedAtMs = agentGuiPerfNowMs();
27151
27524
  const query = conversationQuery.trim().toLowerCase();
27152
27525
  const items = backendSearchActive ? displayConversations : !query ? displayConversations : displayConversations.filter(
@@ -27164,7 +27537,7 @@ var AgentGUIConversationRailPane = memo7(
27164
27537
  uiLanguage
27165
27538
  ]);
27166
27539
  const filteredConversations = filteredConversationResult.items;
27167
- const groupedConversationResult = useMemo31(() => {
27540
+ const groupedConversationResult = useMemo32(() => {
27168
27541
  const startedAtMs = agentGuiPerfNowMs();
27169
27542
  const query = conversationQuery.trim();
27170
27543
  const rawGroups = backendSearchActive ? groupConversations(filteredConversations, labels, userProjects, {
@@ -27216,7 +27589,7 @@ var AgentGUIConversationRailPane = memo7(
27216
27589
  return next;
27217
27590
  });
27218
27591
  }, []);
27219
- const groupedConversationIdentityKey = useMemo31(
27592
+ const groupedConversationIdentityKey = useMemo32(
27220
27593
  () => `${groupedConversations.map(
27221
27594
  (section) => `${section.id}:${section.items.map((item) => item.id).join(",")}`
27222
27595
  ).join("|")}|active:${railActiveOverlay?.conversation.id ?? ""}`,
@@ -27225,7 +27598,7 @@ var AgentGUIConversationRailPane = memo7(
27225
27598
  const sectionAgentTargetId = conversationFilter.kind === "agentTarget" ? conversationFilter.agentTargetId.trim() : sectionAgentTargetFallbackId?.trim() ?? "";
27226
27599
  const requestSectionBatchDeletion = useCallback43(
27227
27600
  (section) => {
27228
- if (isDeletingProjectConversations || isRequestingBatchDeletion) {
27601
+ if (isInteractionLocked() || isDeletingProjectConversations || isRequestingBatchDeletion) {
27229
27602
  return;
27230
27603
  }
27231
27604
  setIsRequestingBatchDeletion(true);
@@ -27233,7 +27606,7 @@ var AgentGUIConversationRailPane = memo7(
27233
27606
  section.id,
27234
27607
  sectionAgentTargetId || void 0
27235
27608
  ).then((sessionIds) => {
27236
- if (sessionIds.length === 0) {
27609
+ if (isInteractionLocked() || sessionIds.length === 0) {
27237
27610
  return;
27238
27611
  }
27239
27612
  setPendingProjectAction({
@@ -27247,6 +27620,7 @@ var AgentGUIConversationRailPane = memo7(
27247
27620
  [
27248
27621
  isDeletingProjectConversations,
27249
27622
  isRequestingBatchDeletion,
27623
+ isInteractionLocked,
27250
27624
  onConfirmDeleteProjectConversations,
27251
27625
  sectionAgentTargetId
27252
27626
  ]
@@ -27347,87 +27721,96 @@ var AgentGUIConversationRailPane = memo7(
27347
27721
  children: labels.retrySearch
27348
27722
  }
27349
27723
  )
27350
- ] }) : shouldShowConversationEmptyState ? /* @__PURE__ */ jsx48("div", { className: AgentGUINode_styles_default.emptyState, children: /* @__PURE__ */ jsx48("span", { children: conversationQuery.trim() ? labels.searchNoConversations : conversations.length === 0 ? labels.noConversations : labels.conversationUnavailable }) }) : groupedConversations.map((section, sectionIndex) => {
27351
- const projectPath = section.kind === "project" ? section.project?.path ?? "" : "";
27352
- const projectLabel = section.kind === "project" ? section.label : "";
27353
- const isProjectSection = section.kind === "project";
27354
- const showProjectRailHeader = !conversationQuery.trim() && section.kind !== "pinned" && (sectionIndex === 0 || groupedConversations[sectionIndex - 1]?.kind === "pinned");
27355
- const isSectionCollapsed = isProjectSection && collapsedProjectSectionIds.has(section.id);
27356
- const sectionPageState = sectionPageStates.get(section.id);
27357
- const searchSectionHasMore = backendSearchActive && sectionIndex === groupedConversations.length - 1 && railSearch.hasMore;
27358
- const activeOverlayConversation = !backendSearchActive && railActiveOverlay?.sectionId === section.id && (!conversationQuery.trim() || filteredConversations.some(
27359
- (conversation) => conversation.id === railActiveOverlay.conversation.id
27360
- )) ? railActiveOverlay.conversation : null;
27361
- const activeOverlayIsCanonical = Boolean(
27362
- activeOverlayConversation && section.items.some(
27363
- (item) => item.projectionSource !== "pending_activation" && item.id === activeOverlayConversation.id
27364
- )
27365
- );
27366
- const activeOverlayCountsTowardTotal = Boolean(
27367
- activeOverlayConversation && activeOverlayConversation.projectionSource !== "pending_activation" && matchesAgentGUIConversationSummaryFilter(
27368
- activeOverlayConversation,
27369
- conversationFilter
27370
- )
27371
- );
27372
- const sectionTotalCount = backendSearchActive ? section.items.length + (searchSectionHasMore ? 1 : 0) : sectionPageState?.totalCount ?? section.items.filter(
27373
- (item) => item.projectionSource !== "pending_activation"
27374
- ).length + (activeOverlayCountsTowardTotal && !activeOverlayIsCanonical ? 1 : 0);
27375
- const sectionHasMore = searchSectionHasMore || !conversationQuery.trim() && sectionPageState?.hasMore === true;
27376
- return /* @__PURE__ */ jsxs35(Fragment13, { children: [
27377
- showProjectRailHeader ? /* @__PURE__ */ jsx48(
27378
- AgentGUIProjectRailHeader,
27379
- {
27380
- labels,
27381
- selectProjectDirectory,
27382
- workspaceUserProjectI18n
27383
- }
27384
- ) : null,
27385
- /* @__PURE__ */ jsx48(
27386
- AgentGUIConversationRailSection,
27387
- {
27388
- activeConversation: activeOverlayConversation,
27389
- activeConversationCountsTowardTotal: activeOverlayCountsTowardTotal,
27390
- activeConversationId,
27391
- createConversationDisabled,
27392
- currentTimeMs,
27393
- isDeletingConversation,
27394
- isDeletingProjectConversations,
27395
- isRequestingBatchDeletion,
27396
- isConversationSearchActive: Boolean(
27397
- conversationQuery.trim()
27398
- ),
27399
- isLoadingMoreConversations: backendSearchActive ? railSearch.loadingMore : runtimeRailSectionsPending || (sectionPageState?.isLoading ?? false),
27400
- isSectionCollapsed,
27401
- labels,
27402
- pendingDeleteConversationId,
27403
- paginationScopeKey: sectionPaginationScopeKey,
27404
- previewMode,
27405
- projectLabel,
27406
- projectPath,
27407
- registerItemElement: registerConversationItemElement,
27408
- section,
27409
- sectionHasMore,
27410
- sectionTotalCount,
27411
- uiLanguage,
27412
- workspaceId,
27413
- onCancelDeleteConversation,
27414
- onConfirmDeleteConversation,
27415
- onCreateConversation,
27416
- onLoadMoreConversations: backendSearchActive ? railSearch.loadMore : loadMoreSectionConversations,
27417
- onRequestDeleteConversation,
27418
- onRequestRenameConversation,
27419
- onSelectConversation,
27420
- onRequestSectionBatchDeletion: requestSectionBatchDeletion,
27421
- setPendingProjectAction,
27422
- onToggleConversationPinned,
27423
- onMarkConversationUnread,
27424
- onOpenProjectFiles,
27425
- onOpenConversationWindow,
27426
- onToggleProjectSectionCollapsed: toggleProjectSectionCollapsed
27427
- }
27428
- )
27429
- ] }, section.id);
27430
- })
27724
+ ] }) : shouldShowConversationEmptyState ? /* @__PURE__ */ jsx48("div", { className: AgentGUINode_styles_default.emptyState, children: /* @__PURE__ */ jsx48("span", { children: conversationQuery.trim() ? labels.searchNoConversations : conversations.length === 0 ? labels.noConversations : labels.conversationUnavailable }) }) : /* @__PURE__ */ jsx48(
27725
+ "fieldset",
27726
+ {
27727
+ className: "contents",
27728
+ disabled: runtimeRailSectionsPending && !backendSearchActive,
27729
+ children: groupedConversations.map((section, sectionIndex) => {
27730
+ const projectPath = section.kind === "project" ? section.project?.path ?? "" : "";
27731
+ const projectLabel = section.kind === "project" ? section.label : "";
27732
+ const isProjectSection = section.kind === "project";
27733
+ const showProjectRailHeader = !conversationQuery.trim() && section.kind !== "pinned" && (sectionIndex === 0 || groupedConversations[sectionIndex - 1]?.kind === "pinned");
27734
+ const isSectionCollapsed = isProjectSection && collapsedProjectSectionIds.has(section.id);
27735
+ const sectionPageState = sectionPageStates.get(section.id);
27736
+ const searchSectionHasMore = backendSearchActive && sectionIndex === groupedConversations.length - 1 && railSearch.hasMore;
27737
+ const activeOverlayConversation = !backendSearchActive && railActiveOverlay?.sectionId === section.id && (!conversationQuery.trim() || filteredConversations.some(
27738
+ (conversation) => conversation.id === railActiveOverlay.conversation.id
27739
+ )) ? railActiveOverlay.conversation : null;
27740
+ const activeOverlayIsCanonical = Boolean(
27741
+ activeOverlayConversation && section.items.some(
27742
+ (item) => item.projectionSource !== "pending_activation" && item.id === activeOverlayConversation.id
27743
+ )
27744
+ );
27745
+ const activeOverlayCountsTowardTotal = Boolean(
27746
+ activeOverlayConversation && activeOverlayConversation.projectionSource !== "pending_activation" && matchesAgentGUIConversationSummaryFilter(
27747
+ activeOverlayConversation,
27748
+ conversationFilter
27749
+ )
27750
+ );
27751
+ const sectionTotalCount = backendSearchActive ? section.items.length + (searchSectionHasMore ? 1 : 0) : sectionPageState?.totalCount ?? section.items.filter(
27752
+ (item) => item.projectionSource !== "pending_activation"
27753
+ ).length + (activeOverlayCountsTowardTotal && !activeOverlayIsCanonical ? 1 : 0);
27754
+ const sectionHasMore = searchSectionHasMore || !conversationQuery.trim() && sectionPageState?.hasMore === true;
27755
+ return /* @__PURE__ */ jsxs35(Fragment13, { children: [
27756
+ showProjectRailHeader ? /* @__PURE__ */ jsx48(
27757
+ AgentGUIProjectRailHeader,
27758
+ {
27759
+ disabled: railInteractionsLocked,
27760
+ labels,
27761
+ selectProjectDirectory,
27762
+ workspaceUserProjectI18n
27763
+ }
27764
+ ) : null,
27765
+ /* @__PURE__ */ jsx48(
27766
+ AgentGUIConversationRailSection,
27767
+ {
27768
+ activeConversation: activeOverlayConversation,
27769
+ activeConversationCountsTowardTotal: activeOverlayCountsTowardTotal,
27770
+ activeConversationId,
27771
+ createConversationDisabled,
27772
+ currentTimeMs,
27773
+ isDeletingConversation,
27774
+ isDeletingProjectConversations,
27775
+ isRequestingBatchDeletion,
27776
+ isConversationSearchActive: Boolean(
27777
+ conversationQuery.trim()
27778
+ ),
27779
+ isLoadingMoreConversations: backendSearchActive ? railSearch.loadingMore : sectionPageState?.isLoading ?? false,
27780
+ isRailInteractionLocked: isInteractionLocked,
27781
+ isSectionCollapsed,
27782
+ labels,
27783
+ pendingDeleteConversationId,
27784
+ paginationScopeKey: sectionPaginationScopeKey,
27785
+ previewMode,
27786
+ projectLabel,
27787
+ projectPath,
27788
+ registerItemElement: registerConversationItemElement,
27789
+ section,
27790
+ sectionHasMore,
27791
+ sectionTotalCount,
27792
+ uiLanguage,
27793
+ workspaceId,
27794
+ onCancelDeleteConversation,
27795
+ onConfirmDeleteConversation,
27796
+ onCreateConversation,
27797
+ onLoadMoreConversations: backendSearchActive ? railSearch.loadMore : loadMoreSectionConversations,
27798
+ onRequestDeleteConversation,
27799
+ onRequestRenameConversation,
27800
+ onSelectConversation,
27801
+ onRequestSectionBatchDeletion: requestSectionBatchDeletion,
27802
+ setPendingProjectAction,
27803
+ onToggleConversationPinned,
27804
+ onMarkConversationUnread,
27805
+ onOpenProjectFiles,
27806
+ onOpenConversationWindow,
27807
+ onToggleProjectSectionCollapsed: toggleProjectSectionCollapsed
27808
+ }
27809
+ )
27810
+ ] }, section.id);
27811
+ })
27812
+ }
27813
+ )
27431
27814
  }
27432
27815
  ),
27433
27816
  footer ? /* @__PURE__ */ jsx48("div", { className: "shrink-0 pb-2", children: footer }) : null,
@@ -27437,6 +27820,7 @@ var AgentGUIConversationRailPane = memo7(
27437
27820
  cancelLabel: labels.cancel,
27438
27821
  className: AGENT_GUI_CONFIRMATION_DIALOG_CLASS_NAME,
27439
27822
  confirmBusy: (pendingProjectAction?.kind === "batch-delete" || pendingProjectAction?.kind === "batch-delete-conversations") && isDeletingProjectConversations,
27823
+ confirmDisabled: railInteractionsLocked,
27440
27824
  confirmLabel: pendingProjectAction?.kind === "batch-delete" ? labels.batchDeleteProjectSessionsConfirm : pendingProjectAction?.kind === "batch-delete-conversations" ? labels.batchDeleteConversationsConfirm : labels.removeProject,
27441
27825
  description: pendingProjectAction?.kind === "batch-delete" ? labels.batchDeleteProjectSessionsBody(
27442
27826
  pendingProjectAction.conversationCount,
@@ -27448,6 +27832,7 @@ var AgentGUIConversationRailPane = memo7(
27448
27832
  ) : void 0,
27449
27833
  onCancel: () => setPendingProjectAction(null),
27450
27834
  onConfirm: () => {
27835
+ if (isInteractionLocked()) return;
27451
27836
  const action = pendingProjectAction;
27452
27837
  setPendingProjectAction(null);
27453
27838
  if (!action) {
@@ -27481,8 +27866,10 @@ var AgentGUIConversationRailPane = memo7(
27481
27866
  );
27482
27867
 
27483
27868
  // agent-gui/agentGuiNode/controller/useAgentGUIConversationRailQuery.ts
27484
- import { selectWorkspaceAgentConsumerSessions as selectWorkspaceAgentConsumerSessions4 } from "@tutti-os/agent-activity-core";
27485
- import { useDeferredValue, useEffect as useEffect31, useMemo as useMemo32, useRef as useRef34 } from "react";
27869
+ import {
27870
+ selectWorkspaceAgentConsumerSessions as selectWorkspaceAgentConsumerSessions4
27871
+ } from "@tutti-os/agent-activity-core";
27872
+ import { useDeferredValue, useEffect as useEffect31, useMemo as useMemo33, useRef as useRef34 } from "react";
27486
27873
 
27487
27874
  // agent-gui/agentGuiNode/controller/AgentGUIConversationRailQueryController.ts
27488
27875
  import {
@@ -27510,6 +27897,7 @@ var EMPTY_QUERY_STATE = {
27510
27897
  };
27511
27898
  var AgentGUIConversationRailQueryController = class {
27512
27899
  getSnapshot = () => this.snapshot;
27900
+ isInteractionLocked = () => this.snapshot.runtimeRailSectionsPending && !(this.searchQuery && this.snapshot.railSearch.enabled);
27513
27901
  subscribe = (listener) => {
27514
27902
  this.listeners.add(listener);
27515
27903
  return () => this.listeners.delete(listener);
@@ -27589,7 +27977,7 @@ var AgentGUIConversationRailQueryController = class {
27589
27977
  this.searchQuery = query;
27590
27978
  this.requestSearch();
27591
27979
  }
27592
- loadMoreSectionConversations(section) {
27980
+ loadMoreSectionConversations = (section) => {
27593
27981
  const scopeKey = this.railSectionQueryKey;
27594
27982
  if (this.scope?.previewMode || !scopeKey || this.queryState.pending || this.queryState.resolvedScopeKey !== scopeKey) {
27595
27983
  return;
@@ -27676,8 +28064,8 @@ var AgentGUIConversationRailQueryController = class {
27676
28064
  this.pagingAbortControllers.delete(section.id);
27677
28065
  }
27678
28066
  });
27679
- }
27680
- loadMoreSearchResults() {
28067
+ };
28068
+ loadMoreSearchResults = () => {
27681
28069
  const listSessionsPage = this.runtime.listSessionsPage;
27682
28070
  if (!this.searchEnabled() || !listSessionsPage || this.searchState.pending || this.searchState.loadingMore || !this.searchState.hasMore || !this.searchState.nextCursor || this.searchState.requestKey !== this.searchRequestKey || this.searchState.resolvedQuery !== this.searchQuery) {
27683
28071
  return;
@@ -27723,11 +28111,11 @@ var AgentGUIConversationRailQueryController = class {
27723
28111
  };
27724
28112
  this.emit();
27725
28113
  });
27726
- }
27727
- retrySearchResults() {
28114
+ };
28115
+ retrySearchResults = () => {
27728
28116
  if (!this.searchQuery || !this.searchEnabled()) return;
27729
28117
  this.requestSearch();
27730
- }
28118
+ };
27731
28119
  handleEngineState(state) {
27732
28120
  const next = membershipRecords(state);
27733
28121
  if (this.ingestingSessions || !this.runtimeSectionsEnabled()) {
@@ -27992,14 +28380,14 @@ function useAgentGUIConversationRailQuery({
27992
28380
  workspaceId
27993
28381
  }) {
27994
28382
  const runtime = useAgentActivityRuntime();
27995
- const engine = useMemo32(
28383
+ const engine = useMemo33(
27996
28384
  () => runtime.getSessionEngine(workspaceId),
27997
28385
  [runtime, workspaceId]
27998
28386
  );
27999
28387
  const activeConversationIdRef = useRef34(activeConversationId);
28000
28388
  activeConversationIdRef.current = activeConversationId;
28001
28389
  const deferredConversationQuery = useDeferredValue(conversationQuery);
28002
- const controller = useMemo32(
28390
+ const controller = useMemo33(
28003
28391
  () => new AgentGUIConversationRailQueryController({
28004
28392
  engine,
28005
28393
  getActiveConversationId: () => activeConversationIdRef.current,
@@ -28030,28 +28418,37 @@ function useAgentGUIConversationRailQuery({
28030
28418
  identitySnapshot,
28031
28419
  Object.is
28032
28420
  );
28033
- const engineConsumerSessions = useEngineSelector(
28421
+ const runtimeRailConversations = useEngineSelector(
28034
28422
  engine,
28035
- selectWorkspaceAgentConsumerSessions4
28036
- );
28037
- const runtimeRailConversations = useMemo32(
28038
- () => projectCanonicalAgentGUIConversationSummaries(engineConsumerSessions),
28039
- [engineConsumerSessions]
28423
+ selectRuntimeRailConversations,
28424
+ conversationSummaryListsRenderEqual
28040
28425
  );
28041
- return useMemo32(
28426
+ return useMemo33(
28042
28427
  () => ({
28043
28428
  ...querySnapshot,
28044
- loadMoreSectionConversations: (section) => controller.loadMoreSectionConversations(section),
28429
+ isInteractionLocked: controller.isInteractionLocked,
28430
+ loadMoreSectionConversations: controller.loadMoreSectionConversations,
28045
28431
  railSearch: {
28046
28432
  ...querySnapshot.railSearch,
28047
- loadMore: () => controller.loadMoreSearchResults(),
28048
- retry: () => controller.retrySearchResults()
28433
+ loadMore: controller.loadMoreSearchResults,
28434
+ retry: controller.retrySearchResults
28049
28435
  },
28050
28436
  runtimeRailConversations
28051
28437
  }),
28052
28438
  [controller, querySnapshot, runtimeRailConversations]
28053
28439
  );
28054
28440
  }
28441
+ function selectRuntimeRailConversations(state) {
28442
+ return projectCanonicalAgentGUIConversationSummaries(
28443
+ selectWorkspaceAgentConsumerSessions4(state)
28444
+ );
28445
+ }
28446
+ function conversationSummaryListsRenderEqual(left, right) {
28447
+ return left.length === right.length && left.every((conversation, index) => {
28448
+ const other = right[index];
28449
+ return other !== void 0 && conversationSummariesRenderEqual2(conversation, other);
28450
+ });
28451
+ }
28055
28452
  function identitySnapshot(snapshot) {
28056
28453
  return snapshot;
28057
28454
  }
@@ -28087,7 +28484,7 @@ import {
28087
28484
  memo as memo12,
28088
28485
  useCallback as useCallback45,
28089
28486
  useEffect as useEffect34,
28090
- useMemo as useMemo34,
28487
+ useMemo as useMemo35,
28091
28488
  useRef as useRef36,
28092
28489
  useState as useState31
28093
28490
  } from "react";
@@ -28096,6 +28493,18 @@ import { ScrollArea as ScrollArea2 } from "@tutti-os/ui-system/components";
28096
28493
 
28097
28494
  // agent-gui/agentGuiNode/view/agentGUIDetailModelHelpers.ts
28098
28495
  import { useRef as useRef35 } from "react";
28496
+ function commandAppSource(command) {
28497
+ if (!command || typeof command !== "object" || !("source" in command)) {
28498
+ return null;
28499
+ }
28500
+ const source = command.source;
28501
+ if (!source || typeof source !== "object") return null;
28502
+ const sourceRecord = source;
28503
+ return sourceRecord.kind === "app" ? sourceRecord : null;
28504
+ }
28505
+ function workspaceAppIconKey(appId, workspaceId) {
28506
+ return `${workspaceId}\0${appId}`;
28507
+ }
28099
28508
  function isDifferentKnownConversationOwner(input) {
28100
28509
  const conversationUserId = input.conversationUserId?.trim() ?? "";
28101
28510
  const currentUserId = input.currentUserId?.trim() ?? "";
@@ -29019,7 +29428,7 @@ function useAgentGUIDetailScroll(input) {
29019
29428
  }
29020
29429
 
29021
29430
  // agent-gui/agentGuiNode/view/useAgentGUIDetailModel.tsx
29022
- import { useMemo as useMemo33 } from "react";
29431
+ import { useMemo as useMemo34 } from "react";
29023
29432
 
29024
29433
  // app/renderer/components/icons/UnavailableChatIcon.tsx
29025
29434
  import { jsx as jsx54 } from "react/jsx-runtime";
@@ -29061,11 +29470,11 @@ function useAgentGUIDetailModel(input) {
29061
29470
  const emptyProviderReadinessGate = !hasActiveConversation ? selectedAgentTargetComingSoon ? { status: "coming_soon" } : viewModel.readiness.providerReadinessGate : null;
29062
29471
  const activePrompt = viewModel.interaction.pendingInteractivePrompt ?? viewModel.interaction.pendingApproval;
29063
29472
  const activePromptRequestId = activePrompt?.requestId ?? null;
29064
- const sessionChrome = useMemo33(
29473
+ const sessionChrome = useMemo34(
29065
29474
  () => ({ ...viewModel.interaction.sessionChrome, approval: null }),
29066
29475
  [viewModel.interaction.sessionChrome]
29067
29476
  );
29068
- const rawSlashStatus = useMemo33(
29477
+ const rawSlashStatus = useMemo34(
29069
29478
  () => resolveSlashStatus({
29070
29479
  rawState: viewModel.interaction.sessionChrome.rawState,
29071
29480
  limits: slashStatusLimits,
@@ -29082,7 +29491,7 @@ function useAgentGUIDetailModel(input) {
29082
29491
  ]
29083
29492
  );
29084
29493
  const slashStatus = useStableSlashStatus(rawSlashStatus);
29085
- const displayedInlineNotice = useMemo33(() => {
29494
+ const displayedInlineNotice = useMemo34(() => {
29086
29495
  const inlineNotice = viewModel.interaction.inlineNotice;
29087
29496
  const inlineNoticeMessage = inlineNotice?.message.trim() ?? "";
29088
29497
  if (!inlineNotice || inlineNoticeMessage === "") {
@@ -29106,7 +29515,7 @@ function useAgentGUIDetailModel(input) {
29106
29515
  viewModel.readiness.activeLiveState,
29107
29516
  viewModel.interaction.inlineNotice
29108
29517
  ]);
29109
- const inlineNoticeChrome = useMemo33(() => {
29518
+ const inlineNoticeChrome = useMemo34(() => {
29110
29519
  if (!displayedInlineNotice) {
29111
29520
  return null;
29112
29521
  }
@@ -29150,7 +29559,7 @@ function useAgentGUIDetailModel(input) {
29150
29559
  const submitDisabled = hasNonRetryableRecoveryFailure || isCollaboratorConversation || !isAgentProviderReady || !viewModel.composer.canSubmit && !canQueueWhileBusy;
29151
29560
  const composerDisabled = hasNonRetryableRecoveryFailure || isCollaboratorConversation || !isAgentProviderReady || !canQueueWhileBusy && (viewModel.interaction.pendingApproval !== null || viewModel.interaction.pendingInteractivePrompt !== null || viewModel.composer.isSubmitting || viewModel.composer.isInterrupting || viewModel.composer.isCreatingConversation);
29152
29561
  const showStopButton = !viewModel.composer.isSubmitting && viewModel.readiness.activeLiveState !== "failed" && sessionChrome.auth === null && (activeConversationTurnBusy || viewModel.interaction.pendingApproval !== null || viewModel.interaction.pendingInteractivePrompt !== null || viewModel.composer.isInterrupting);
29153
- const conversationFlowLabels = useMemo33(
29562
+ const conversationFlowLabels = useMemo34(
29154
29563
  () => ({
29155
29564
  thinkingLabel: labels.thinkingLabel,
29156
29565
  toolCallsLabel: labels.toolCallsLabel,
@@ -29166,7 +29575,7 @@ function useAgentGUIDetailModel(input) {
29166
29575
  labels.userMessageLocator
29167
29576
  ]
29168
29577
  );
29169
- const conversationFlowEmpty = useMemo33(
29578
+ const conversationFlowEmpty = useMemo34(
29170
29579
  () => showUnavailableChatEmpty ? /* @__PURE__ */ jsxs40(
29171
29580
  "div",
29172
29581
  {
@@ -29180,7 +29589,7 @@ function useAgentGUIDetailModel(input) {
29180
29589
  ) : /* @__PURE__ */ jsx55(Fragment15, {}),
29181
29590
  [labels.conversationUnavailable, showUnavailableChatEmpty]
29182
29591
  );
29183
- const chromeLabels = useMemo33(
29592
+ const chromeLabels = useMemo34(
29184
29593
  () => ({
29185
29594
  approvalRequired: labels.approvalRequired,
29186
29595
  authRequired: labels.authRequired,
@@ -29201,7 +29610,7 @@ function useAgentGUIDetailModel(input) {
29201
29610
  viewModel.composer.isCancelPending
29202
29611
  ]
29203
29612
  );
29204
- const goalBannerLabels = useMemo33(
29613
+ const goalBannerLabels = useMemo34(
29205
29614
  () => ({
29206
29615
  titleActive: labels.goalTitleActive,
29207
29616
  titlePaused: labels.goalTitlePaused,
@@ -29231,7 +29640,7 @@ function useAgentGUIDetailModel(input) {
29231
29640
  labels.goalClearAction
29232
29641
  ]
29233
29642
  );
29234
- const interactivePromptLabels = useMemo33(
29643
+ const interactivePromptLabels = useMemo34(
29235
29644
  () => ({
29236
29645
  approvalLead: labels.approvalRequired,
29237
29646
  planLead: labels.planLead,
@@ -29269,7 +29678,7 @@ function useAgentGUIDetailModel(input) {
29269
29678
  labels.planImplementationSkip
29270
29679
  ]
29271
29680
  );
29272
- const composerLabels = useMemo33(
29681
+ const composerLabels = useMemo34(
29273
29682
  () => ({
29274
29683
  send: labels.send,
29275
29684
  modelLabel: labels.modelLabel,
@@ -29595,22 +30004,9 @@ function mergeWorkspaceAppIconsFromCommands(input) {
29595
30004
  }
29596
30005
  return next ?? input.workspaceAppIcons;
29597
30006
  }
29598
- function commandAppSource(command) {
29599
- if (!command || typeof command !== "object" || !("source" in command)) {
29600
- return null;
29601
- }
29602
- const source = command.source;
29603
- if (!source || typeof source !== "object") {
29604
- return null;
29605
- }
29606
- const sourceRecord = source;
29607
- return sourceRecord.kind === "app" ? sourceRecord : null;
29608
- }
29609
- function workspaceAppIconKey(appId, workspaceId) {
29610
- return `${workspaceId}\0${appId}`;
29611
- }
29612
30007
  var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29613
30008
  viewModel,
30009
+ composerEngagement,
29614
30010
  actions,
29615
30011
  labels,
29616
30012
  workspaceUserProjectI18n,
@@ -29814,7 +30210,24 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29814
30210
  const agentTargetId = viewModel.shell.data.agentTargetId;
29815
30211
  return !agentTargetId || target.targetId === agentTargetId || target.agentTargetId === agentTargetId;
29816
30212
  }) ?? viewModel.rail.selectedAgentTarget;
29817
- const bottomDockComposerProps = useMemo34(
30213
+ const stableHandoffConversation = useOptionalStableEventCallback(
30214
+ onHandoffConversation && viewModel.rail.activeConversationId !== null ? (target) => onHandoffConversation({
30215
+ agentTargetId: target.agentTargetId ?? target.targetId,
30216
+ draftPrompt: buildAgentConversationHandoffPrompt({
30217
+ activeConversation: viewModel.rail.activeConversation,
30218
+ currentUserId: viewModel.shell.currentUserId,
30219
+ labels,
30220
+ selectedAgentTarget: composerSelectedProviderTarget,
30221
+ uiLanguage,
30222
+ workspaceId: viewModel.shell.workspaceId
30223
+ }),
30224
+ provider: target.provider,
30225
+ userProjectPath: handoffProjectPathForConversation(
30226
+ viewModel.rail.activeConversation
30227
+ )
30228
+ }) : void 0
30229
+ );
30230
+ const bottomDockComposerProps = useMemo35(
29818
30231
  () => ({
29819
30232
  workspaceId: viewModel.shell.workspaceId,
29820
30233
  workspacePath: viewModel.shell.workspacePath,
@@ -29824,6 +30237,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29824
30237
  onSlashStatusOpen,
29825
30238
  usage: viewModel.detail.usage,
29826
30239
  draftContent: viewModel.composer.draftContent,
30240
+ engagement: composerEngagement,
29827
30241
  draftScopeKey: resolveAgentComposerDraftScopeKey({
29828
30242
  agentSessionId: viewModel.rail.activeConversationId
29829
30243
  }),
@@ -29849,8 +30263,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29849
30263
  showStopButton,
29850
30264
  previewMode,
29851
30265
  workspaceReferencePickerOpen,
29852
- // Plan decisions replace the composer via bottomDockReplacementPrompt;
29853
- // approval / ask-user embed here (composerActivePrompt encodes that).
30266
+ // Plan decisions replace the composer; approval / ask-user embed here.
29854
30267
  activePrompt: composerActivePrompt,
29855
30268
  backgroundAgentStatusText,
29856
30269
  activePromptKeyboardShortcutsEnabled: isActive,
@@ -29881,21 +30294,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29881
30294
  onSubmitInteractivePrompt: submitInteractivePrompt,
29882
30295
  onCapabilitySettingsRequest,
29883
30296
  onLinkAction: stableLinkAction,
29884
- onHandoffConversation: onHandoffConversation && viewModel.rail.activeConversationId !== null ? (target) => onHandoffConversation({
29885
- agentTargetId: target.agentTargetId ?? target.targetId,
29886
- draftPrompt: buildAgentConversationHandoffPrompt({
29887
- activeConversation: viewModel.rail.activeConversation,
29888
- currentUserId: viewModel.shell.currentUserId,
29889
- labels,
29890
- selectedAgentTarget: composerSelectedProviderTarget,
29891
- uiLanguage,
29892
- workspaceId: viewModel.shell.workspaceId
29893
- }),
29894
- provider: target.provider,
29895
- userProjectPath: handoffProjectPathForConversation(
29896
- viewModel.rail.activeConversation
29897
- )
29898
- }) : void 0,
30297
+ onHandoffConversation: stableHandoffConversation,
29899
30298
  onRequestWorkspaceReferences: stableRequestWorkspaceReferences,
29900
30299
  resolveDroppedFileReferences,
29901
30300
  selectProjectDirectory: stableSelectProjectDirectory,
@@ -29910,6 +30309,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29910
30309
  composerDisabled,
29911
30310
  composerDisabledReason,
29912
30311
  composerFocusRequestSequence,
30312
+ composerEngagement,
29913
30313
  composerHandoffProviderTargets,
29914
30314
  composerLabels,
29915
30315
  composerProviderTargets,
@@ -29925,7 +30325,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29925
30325
  labels.promptTips,
29926
30326
  labels.providerSwitchLabel,
29927
30327
  labels,
29928
- onHandoffConversation,
30328
+ stableHandoffConversation,
29929
30329
  onSlashStatusOpen,
29930
30330
  previewMode,
29931
30331
  workspaceReferencePickerOpen,
@@ -29976,7 +30376,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29976
30376
  selectHomeComposerAgentTargetAndFocus
29977
30377
  ]
29978
30378
  );
29979
- const emptyHeroComposerProps = useMemo34(
30379
+ const emptyHeroComposerProps = useMemo35(
29980
30380
  () => ({
29981
30381
  ...bottomDockComposerProps,
29982
30382
  layoutMode: "hero"
@@ -30170,10 +30570,14 @@ var AgentGUIRenameConversationDialog = memo13(
30170
30570
  "use memo";
30171
30571
  const [title, setTitle] = useState32("");
30172
30572
  const [isSaving, setIsSaving] = useState32(false);
30573
+ const isSavingRef = useRef37(false);
30574
+ const armedPointerActionRef = useRef37(null);
30173
30575
  const inputRef = useRef37(null);
30174
30576
  const trimmedTitle = title.trim();
30175
30577
  useEffect35(() => {
30176
30578
  if (!open || !conversation) {
30579
+ isSavingRef.current = false;
30580
+ armedPointerActionRef.current = null;
30177
30581
  setTitle("");
30178
30582
  setIsSaving(false);
30179
30583
  return;
@@ -30191,23 +30595,25 @@ var AgentGUIRenameConversationDialog = memo13(
30191
30595
  return () => window.clearTimeout(timer);
30192
30596
  }, [open, conversation?.id]);
30193
30597
  const closeRenameDialog = useCallback46(() => {
30194
- if (!isSaving) {
30598
+ if (!isSavingRef.current) {
30195
30599
  onOpenChange(false);
30196
30600
  }
30197
- }, [isSaving, onOpenChange]);
30601
+ }, [onOpenChange]);
30198
30602
  const confirmRename = useCallback46(() => {
30199
- if (!conversation || isSaving || !trimmedTitle) {
30603
+ if (!conversation || isSavingRef.current || !trimmedTitle) {
30200
30604
  return;
30201
30605
  }
30606
+ isSavingRef.current = true;
30202
30607
  setIsSaving(true);
30203
30608
  void onRename(conversation.id, trimmedTitle).then(() => {
30204
30609
  onOpenChange(false);
30205
30610
  }).catch(() => {
30206
30611
  inputRef.current?.focus();
30207
30612
  }).finally(() => {
30613
+ isSavingRef.current = false;
30208
30614
  setIsSaving(false);
30209
30615
  });
30210
- }, [conversation, isSaving, onOpenChange, onRename, trimmedTitle]);
30616
+ }, [conversation, onOpenChange, onRename, trimmedTitle]);
30211
30617
  return /* @__PURE__ */ jsx57(
30212
30618
  ConfirmationDialog2,
30213
30619
  {
@@ -30226,8 +30632,30 @@ var AgentGUIRenameConversationDialog = memo13(
30226
30632
  type: "button",
30227
30633
  variant: "ghost",
30228
30634
  onClick: closeRenameDialog,
30229
- onPointerUp: (event) => {
30635
+ onLostPointerCapture: () => {
30636
+ if (armedPointerActionRef.current === "cancel") {
30637
+ armedPointerActionRef.current = null;
30638
+ }
30639
+ },
30640
+ onPointerCancel: () => {
30641
+ if (armedPointerActionRef.current === "cancel") {
30642
+ armedPointerActionRef.current = null;
30643
+ }
30644
+ },
30645
+ onPointerDown: (event) => {
30230
30646
  if (event.button === 0) {
30647
+ armedPointerActionRef.current = "cancel";
30648
+ }
30649
+ },
30650
+ onPointerLeave: () => {
30651
+ if (armedPointerActionRef.current === "cancel") {
30652
+ armedPointerActionRef.current = null;
30653
+ }
30654
+ },
30655
+ onPointerUp: (event) => {
30656
+ const isArmed = armedPointerActionRef.current === "cancel";
30657
+ armedPointerActionRef.current = null;
30658
+ if (event.button === 0 && isArmed) {
30231
30659
  closeRenameDialog();
30232
30660
  }
30233
30661
  },
@@ -30242,7 +30670,45 @@ var AgentGUIRenameConversationDialog = memo13(
30242
30670
  size: "dialog",
30243
30671
  type: "button",
30244
30672
  variant: "default",
30245
- onClick: confirmRename,
30673
+ onClick: (event) => {
30674
+ if (event.detail !== 0) {
30675
+ return;
30676
+ }
30677
+ confirmRename();
30678
+ },
30679
+ onKeyDown: (event) => {
30680
+ if ((event.key === "Enter" || event.key === " ") && !event.repeat) {
30681
+ event.preventDefault();
30682
+ confirmRename();
30683
+ }
30684
+ },
30685
+ onLostPointerCapture: () => {
30686
+ if (armedPointerActionRef.current === "confirm") {
30687
+ armedPointerActionRef.current = null;
30688
+ }
30689
+ },
30690
+ onPointerCancel: () => {
30691
+ if (armedPointerActionRef.current === "confirm") {
30692
+ armedPointerActionRef.current = null;
30693
+ }
30694
+ },
30695
+ onPointerDown: (event) => {
30696
+ if (event.button === 0) {
30697
+ armedPointerActionRef.current = "confirm";
30698
+ }
30699
+ },
30700
+ onPointerLeave: () => {
30701
+ if (armedPointerActionRef.current === "confirm") {
30702
+ armedPointerActionRef.current = null;
30703
+ }
30704
+ },
30705
+ onPointerUp: (event) => {
30706
+ const isArmed = armedPointerActionRef.current === "confirm";
30707
+ armedPointerActionRef.current = null;
30708
+ if (event.button === 0 && isArmed) {
30709
+ confirmRename();
30710
+ }
30711
+ },
30246
30712
  children: labels.renameSessionSave
30247
30713
  }
30248
30714
  )
@@ -30274,7 +30740,7 @@ var AgentGUIRenameConversationDialog = memo13(
30274
30740
  );
30275
30741
 
30276
30742
  // agent-gui/agentGuiNode/view/useAgentGUIWorkspaceReferencePicker.ts
30277
- import { useCallback as useCallback47, useMemo as useMemo35, useRef as useRef38, useState as useState33 } from "react";
30743
+ import { useCallback as useCallback47, useMemo as useMemo36, useRef as useRef38, useState as useState33 } from "react";
30278
30744
  import { createRichTextMentionHref } from "@tutti-os/ui-rich-text/core";
30279
30745
  function useAgentGUIWorkspaceReferencePicker(input) {
30280
30746
  const {
@@ -30290,7 +30756,7 @@ function useAgentGUIWorkspaceReferencePicker(input) {
30290
30756
  const [workspaceReferencePickerOpen, setWorkspaceReferencePickerOpen] = useState33(false);
30291
30757
  const [workspaceReferencePickerTarget, setWorkspaceReferencePickerTarget] = useState33(null);
30292
30758
  const workspaceReferencePickerResolverRef = useRef38(null);
30293
- const emptyReferencePickResult = useMemo35(
30759
+ const emptyReferencePickResult = useMemo36(
30294
30760
  () => ({ files: [], mentionItems: [] }),
30295
30761
  []
30296
30762
  );
@@ -30403,9 +30869,256 @@ function useAgentGUIWorkspaceReferencePicker(input) {
30403
30869
  };
30404
30870
  }
30405
30871
 
30872
+ // agent-gui/agentGuiNode/engagement/useAgentGUINodeEngagement.ts
30873
+ import { useRef as useRef40 } from "react";
30874
+
30875
+ // agent-gui/agentGuiNode/engagement/projectAgentGUIEngagementContext.ts
30876
+ function projectAgentGUIEngagementContext(viewModel, composerReady) {
30877
+ const agentSessionId = viewModel.rail.activeConversationId;
30878
+ const provider = viewModel.rail.activeConversation?.provider ?? viewModel.rail.selectedAgentTarget.provider ?? viewModel.shell.data.provider;
30879
+ const agentTargetId = viewModel.rail.activeConversation?.agentTargetId ?? viewModel.rail.selectedAgentTarget.agentTargetId ?? viewModel.rail.selectedAgentTarget.targetId ?? null;
30880
+ return {
30881
+ context: {
30882
+ agentSessionId,
30883
+ agentTargetId,
30884
+ composerReady,
30885
+ conversationState: agentSessionId ? "existing" : "new",
30886
+ provider
30887
+ },
30888
+ contextKey: createAgentGUIEngagementContextKey({
30889
+ agentSessionId,
30890
+ agentTargetId,
30891
+ provider
30892
+ })
30893
+ };
30894
+ }
30895
+ function createAgentGUIEngagementContextKey(input) {
30896
+ return JSON.stringify([
30897
+ input.agentSessionId ? "session" : "home",
30898
+ input.agentSessionId,
30899
+ input.provider,
30900
+ input.agentTargetId
30901
+ ]);
30902
+ }
30903
+
30904
+ // agent-gui/agentGuiNode/engagement/useAgentGUIPanelEngagement.ts
30905
+ import { useEffect as useEffect36, useRef as useRef39 } from "react";
30906
+
30907
+ // agent-gui/agentGuiNode/engagement/AgentGUIPanelEngagementController.ts
30908
+ var AGENT_GUI_PANEL_EXPOSURE_DWELL_MS = 1e3;
30909
+ var AGENT_GUI_PANEL_EXPOSURE_INTERSECTION_RATIO = 0.5;
30910
+ var AgentGUIPanelEngagementController = class {
30911
+ constructor(options) {
30912
+ this.options = options;
30913
+ this.intersectionRatio = options.initialIntersectionRatio;
30914
+ }
30915
+ options;
30916
+ documentFocused = documentHasFocus();
30917
+ documentVisible = documentIsVisible();
30918
+ intersectionObserver = null;
30919
+ intersectionRatio;
30920
+ visit = null;
30921
+ attach() {
30922
+ document.addEventListener("visibilitychange", this.updateDocumentState);
30923
+ window.addEventListener("blur", this.updateDocumentState);
30924
+ window.addEventListener("focus", this.updateDocumentState);
30925
+ if (typeof IntersectionObserver === "undefined") {
30926
+ this.intersectionRatio = 0;
30927
+ } else {
30928
+ this.intersectionObserver = new IntersectionObserver(
30929
+ this.updateIntersection,
30930
+ {
30931
+ threshold: [0, AGENT_GUI_PANEL_EXPOSURE_INTERSECTION_RATIO, 1]
30932
+ }
30933
+ );
30934
+ this.intersectionObserver.observe(this.options.element);
30935
+ }
30936
+ this.reconcileVisit();
30937
+ }
30938
+ dispose() {
30939
+ document.removeEventListener("visibilitychange", this.updateDocumentState);
30940
+ window.removeEventListener("blur", this.updateDocumentState);
30941
+ window.removeEventListener("focus", this.updateDocumentState);
30942
+ this.intersectionObserver?.disconnect();
30943
+ this.endVisit();
30944
+ return this.intersectionRatio;
30945
+ }
30946
+ focused(focusMethod) {
30947
+ this.reconcileVisit();
30948
+ const visit = this.visit;
30949
+ if (!visit || visit.pendingFocusMethod) return;
30950
+ visit.pendingFocusMethod = focusMethod;
30951
+ if (!visit.exposed) return;
30952
+ this.report({
30953
+ ...this.eventForVisit(visit, "composer_focused"),
30954
+ focusMethod
30955
+ });
30956
+ }
30957
+ contentEntered(content) {
30958
+ this.reconcileVisit();
30959
+ const visit = this.visit;
30960
+ if (!visit || visit.pendingContentEntered) return;
30961
+ visit.pendingContentEntered = content;
30962
+ if (!visit.exposed) return;
30963
+ this.report({
30964
+ ...this.eventForVisit(visit, "composer_content_entered"),
30965
+ ...content
30966
+ });
30967
+ }
30968
+ updateDocumentState = () => {
30969
+ this.documentFocused = documentHasFocus();
30970
+ this.documentVisible = documentIsVisible();
30971
+ this.reconcileVisit();
30972
+ };
30973
+ updateIntersection = (entries) => {
30974
+ const entry = entries.find(
30975
+ (candidate) => candidate.target === this.options.element
30976
+ );
30977
+ this.intersectionRatio = entry?.intersectionRatio ?? 0;
30978
+ this.reconcileVisit();
30979
+ };
30980
+ reconcileVisit() {
30981
+ if (!this.isExposureEligible()) {
30982
+ this.endVisit();
30983
+ return;
30984
+ }
30985
+ if (this.visit) return;
30986
+ const visit = {
30987
+ exposed: false,
30988
+ id: createPanelVisitId(),
30989
+ pendingContentEntered: null,
30990
+ pendingFocusMethod: null,
30991
+ timeoutId: null
30992
+ };
30993
+ this.visit = visit;
30994
+ visit.timeoutId = setTimeout(
30995
+ () => this.exposeVisit(visit),
30996
+ AGENT_GUI_PANEL_EXPOSURE_DWELL_MS
30997
+ );
30998
+ }
30999
+ exposeVisit(visit) {
31000
+ if (this.visit !== visit || !this.isExposureEligible()) return;
31001
+ visit.timeoutId = null;
31002
+ visit.exposed = true;
31003
+ this.report(this.eventForVisit(visit, "panel_exposed"));
31004
+ if (visit.pendingFocusMethod) {
31005
+ this.report({
31006
+ ...this.eventForVisit(visit, "composer_focused"),
31007
+ focusMethod: visit.pendingFocusMethod
31008
+ });
31009
+ }
31010
+ if (visit.pendingContentEntered) {
31011
+ this.report({
31012
+ ...this.eventForVisit(visit, "composer_content_entered"),
31013
+ ...visit.pendingContentEntered
31014
+ });
31015
+ }
31016
+ }
31017
+ endVisit() {
31018
+ if (this.visit?.timeoutId !== null && this.visit?.timeoutId !== void 0) {
31019
+ clearTimeout(this.visit.timeoutId);
31020
+ }
31021
+ this.visit = null;
31022
+ }
31023
+ isExposureEligible() {
31024
+ const input = this.options.getInput();
31025
+ return Boolean(input.onEvent) && !input.previewMode && input.contextKey === this.options.visitContextKey && input.isActive && input.isVisible && this.documentFocused && this.documentVisible && this.intersectionRatio >= AGENT_GUI_PANEL_EXPOSURE_INTERSECTION_RATIO;
31026
+ }
31027
+ eventForVisit(visit, type) {
31028
+ return {
31029
+ ...this.options.getInput().context,
31030
+ panelVisitId: visit.id,
31031
+ type
31032
+ };
31033
+ }
31034
+ report(event) {
31035
+ const sink = this.options.getInput().onEvent;
31036
+ if (!sink) return;
31037
+ try {
31038
+ void Promise.resolve(sink(event)).catch(reportEngagementFailure);
31039
+ } catch (error) {
31040
+ reportEngagementFailure(error);
31041
+ }
31042
+ }
31043
+ };
31044
+ function reportEngagementFailure(error) {
31045
+ console.warn("[agent-gui] engagement event reporting failed", error);
31046
+ }
31047
+ function createPanelVisitId() {
31048
+ return globalThis.crypto?.randomUUID?.() ?? `agent-gui-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
31049
+ }
31050
+ function documentHasFocus() {
31051
+ return typeof document !== "undefined" && document.hasFocus();
31052
+ }
31053
+ function documentIsVisible() {
31054
+ return typeof document !== "undefined" && document.visibilityState === "visible";
31055
+ }
31056
+
31057
+ // agent-gui/agentGuiNode/engagement/useAgentGUIPanelEngagement.ts
31058
+ function useAgentGUIPanelEngagement(input) {
31059
+ const inputRef = useRef39(input);
31060
+ const controllerRef = useRef39(null);
31061
+ const intersectionRatioRef = useRef39(0);
31062
+ const engagementRef = useRef39(null);
31063
+ inputRef.current = input;
31064
+ if (!engagementRef.current) {
31065
+ engagementRef.current = {
31066
+ contentEntered(content) {
31067
+ controllerRef.current?.contentEntered(content);
31068
+ },
31069
+ focused(focusMethod) {
31070
+ controllerRef.current?.focused(focusMethod);
31071
+ }
31072
+ };
31073
+ }
31074
+ const engagementEnabled = Boolean(input.onEvent) && !input.previewMode;
31075
+ useEffect36(() => {
31076
+ const element = input.elementRef.current;
31077
+ if (!engagementEnabled || !element) return void 0;
31078
+ const controller = new AgentGUIPanelEngagementController({
31079
+ element,
31080
+ getInput: () => inputRef.current,
31081
+ initialIntersectionRatio: intersectionRatioRef.current,
31082
+ visitContextKey: input.contextKey
31083
+ });
31084
+ controllerRef.current = controller;
31085
+ controller.attach();
31086
+ return () => {
31087
+ intersectionRatioRef.current = controller.dispose();
31088
+ if (controllerRef.current === controller) controllerRef.current = null;
31089
+ };
31090
+ }, [
31091
+ engagementEnabled,
31092
+ input.contextKey,
31093
+ input.elementRef,
31094
+ input.isActive,
31095
+ input.isVisible
31096
+ ]);
31097
+ return engagementEnabled ? engagementRef.current : void 0;
31098
+ }
31099
+
31100
+ // agent-gui/agentGuiNode/engagement/useAgentGUINodeEngagement.ts
31101
+ function useAgentGUINodeEngagement(input) {
31102
+ const layoutElementRef = useRef40(null);
31103
+ const projected = projectAgentGUIEngagementContext(
31104
+ input.viewModel,
31105
+ input.composerReady
31106
+ );
31107
+ return {
31108
+ composerEngagement: useAgentGUIPanelEngagement({
31109
+ ...projected,
31110
+ elementRef: layoutElementRef,
31111
+ isActive: input.isActive,
31112
+ isVisible: input.isVisible,
31113
+ onEvent: input.onEvent,
31114
+ previewMode: input.previewMode
31115
+ }),
31116
+ layoutElementRef
31117
+ };
31118
+ }
31119
+
30406
31120
  // agent-gui/agentGuiNode/AgentGUINodeView.tsx
30407
31121
  import { jsx as jsx58, jsxs as jsxs43 } from "react/jsx-runtime";
30408
- var EMPTY_WORKSPACE_APP_ICONS5 = [];
30409
31122
  function AgentGUINodeView({
30410
31123
  viewModel,
30411
31124
  renderSidebarFooter,
@@ -30417,6 +31130,8 @@ function AgentGUINodeView({
30417
31130
  capabilityMenuState,
30418
31131
  onCapabilitySettingsRequest,
30419
31132
  isActive = true,
31133
+ isVisible = true,
31134
+ onEngagementEvent,
30420
31135
  composerFocusRequestSequence = null,
30421
31136
  newConversationRequestSequence = null,
30422
31137
  isAgentProviderReady,
@@ -30458,12 +31173,19 @@ function AgentGUINodeView({
30458
31173
  resolveWorkspaceReferenceEntryIconUrl,
30459
31174
  resolveMentionReferenceTarget = null,
30460
31175
  resolveWorkspaceReferenceInitialTarget = null,
30461
- workspaceAppIcons = EMPTY_WORKSPACE_APP_ICONS5
31176
+ workspaceAppIcons = EMPTY_WORKSPACE_APP_ICONS4
30462
31177
  }) {
30463
31178
  "use memo";
30464
- const layoutElementRef = useRef39(null);
31179
+ const { composerEngagement, layoutElementRef } = useAgentGUINodeEngagement({
31180
+ composerReady: isAgentProviderReady,
31181
+ isActive,
31182
+ isVisible,
31183
+ onEvent: onEngagementEvent,
31184
+ previewMode,
31185
+ viewModel
31186
+ });
30465
31187
  const [providerManagerOpen, setProviderManagerOpen] = useState34(false);
30466
- const railResizeInteractionRef = useRef39(null);
31188
+ const railResizeInteractionRef = useRef41(null);
30467
31189
  const [isRailResizing, setIsRailResizing] = useState34(false);
30468
31190
  const [railResizeWidthPx, setRailResizeWidthPx] = useState34(
30469
31191
  null
@@ -30472,7 +31194,7 @@ function AgentGUINodeView({
30472
31194
  localComposerFocusRequestSequence,
30473
31195
  setLocalComposerFocusRequestSequence
30474
31196
  ] = useState34(0);
30475
- const handledNewConversationRequestSequenceRef = useRef39(
31197
+ const handledNewConversationRequestSequenceRef = useRef41(
30476
31198
  newConversationRequestSequence
30477
31199
  );
30478
31200
  const {
@@ -30550,7 +31272,7 @@ function AgentGUINodeView({
30550
31272
  viewModel.composer.composerSettings.selectedProjectPath
30551
31273
  ]
30552
31274
  );
30553
- useEffect36(() => {
31275
+ useEffect37(() => {
30554
31276
  if (newConversationRequestSequence === null || handledNewConversationRequestSequenceRef.current === newConversationRequestSequence) {
30555
31277
  return;
30556
31278
  }
@@ -30563,7 +31285,7 @@ function AgentGUINodeView({
30563
31285
  newConversationRequestSequence,
30564
31286
  requestCreateConversation
30565
31287
  ]);
30566
- const effectiveWorkspaceAppIcons = useMemo36(
31288
+ const effectiveWorkspaceAppIcons = useMemo37(
30567
31289
  () => mergeWorkspaceAppIconsFromCommands({
30568
31290
  commands: viewModel.composer.availableCommands,
30569
31291
  workspaceAppIcons,
@@ -30644,7 +31366,7 @@ function AgentGUINodeView({
30644
31366
  },
30645
31367
  [onConversationRailWidthChanged]
30646
31368
  );
30647
- useEffect36(() => {
31369
+ useEffect37(() => {
30648
31370
  if (isRailResizing || railResizeWidthPx === null) {
30649
31371
  return;
30650
31372
  }
@@ -30701,7 +31423,7 @@ function AgentGUINodeView({
30701
31423
  const environmentSetupVisible = !!resolveAgentGUIProviderCatalogIdentity(
30702
31424
  effectiveRailConfigProvider ?? ""
30703
31425
  );
30704
- const effectiveProviderAuthAccountLabel = useMemo36(() => {
31426
+ const effectiveProviderAuthAccountLabel = useMemo37(() => {
30705
31427
  const provider = (effectiveRailConfigProvider ?? viewModel.shell.data.provider)?.trim() ?? "";
30706
31428
  if (!provider) {
30707
31429
  return null;
@@ -30732,7 +31454,7 @@ function AgentGUINodeView({
30732
31454
  },
30733
31455
  []
30734
31456
  );
30735
- const conversationRailStoreState = useMemo36(
31457
+ const conversationRailStoreState = useMemo37(
30736
31458
  () => ({
30737
31459
  activeConversation: viewModel.rail.activeConversation,
30738
31460
  activeConversationId: viewModel.rail.activeConversationId,
@@ -30801,7 +31523,7 @@ function AgentGUINodeView({
30801
31523
  workspaceUserProjectI18n
30802
31524
  ]
30803
31525
  );
30804
- const agentTargetPresentations = useMemo36(
31526
+ const agentTargetPresentations = useMemo37(
30805
31527
  () => viewModel.rail.agentTargets.flatMap(
30806
31528
  (target) => target.agentTargetId ? [
30807
31529
  {
@@ -30971,6 +31693,7 @@ function AgentGUINodeView({
30971
31693
  AgentGUIDetailPane,
30972
31694
  {
30973
31695
  viewModel,
31696
+ composerEngagement,
30974
31697
  actions,
30975
31698
  labels,
30976
31699
  uiLanguage,
@@ -31223,9 +31946,9 @@ function appendDockProbeUsageLines(probe, lines, isLoadingUsage, t) {
31223
31946
  import { Info as Info3 } from "lucide-react";
31224
31947
  import {
31225
31948
  useCallback as useCallback49,
31226
- useEffect as useEffect37,
31949
+ useEffect as useEffect38,
31227
31950
  useLayoutEffect as useLayoutEffect8,
31228
- useRef as useRef40,
31951
+ useRef as useRef42,
31229
31952
  useState as useState35
31230
31953
  } from "react";
31231
31954
  import { createPortal as createPortal5 } from "react-dom";
@@ -31263,8 +31986,8 @@ function AgentProbeInfoPopover({
31263
31986
  onOpen
31264
31987
  }) {
31265
31988
  "use memo";
31266
- const anchorRef = useRef40(null);
31267
- const popoverRef = useRef40(null);
31989
+ const anchorRef = useRef42(null);
31990
+ const popoverRef = useRef42(null);
31268
31991
  const [isOpen, setIsOpen] = useState35(false);
31269
31992
  const [popoverStyle, setPopoverStyle] = useState35(null);
31270
31993
  const openPopover = useCallback49(() => {
@@ -31306,7 +32029,7 @@ function AgentProbeInfoPopover({
31306
32029
  maxWidth: availableWidth
31307
32030
  });
31308
32031
  }, []);
31309
- useEffect37(() => {
32032
+ useEffect38(() => {
31310
32033
  if (!isOpen) {
31311
32034
  return;
31312
32035
  }
@@ -31592,11 +32315,11 @@ function areAgentGUINodePropsEqual(previous, next) {
31592
32315
  const pc = previous.hostCapabilities, nc = next.hostCapabilities;
31593
32316
  const pa = previous.hostActions, na = next.hostActions;
31594
32317
  const ps = previous.renderSlots, ns = next.renderSlots;
31595
- return pi.nodeId === ni.nodeId && pi.workspaceId === ni.workspaceId && pi.currentUserId === ni.currentUserId && pi.title === ni.title && pw.path === nw.path && pw.fileReferenceAdapter === nw.fileReferenceAdapter && pw.onRequestGitBranches === nw.onRequestGitBranches && pw.selectProjectDirectory === nw.selectProjectDirectory && pw.resolveDroppedFileReferences === nw.resolveDroppedFileReferences && pw.referenceSourceAggregator === nw.referenceSourceAggregator && pw.resolveReferenceEntryIconUrl === nw.resolveReferenceEntryIconUrl && pw.resolveMentionReferenceTarget === nw.resolveMentionReferenceTarget && pw.resolveReferenceInitialTarget === nw.resolveReferenceInitialTarget && pw.onFileReferencesAdded === nw.onFileReferencesAdded && pw.agentSettings.avoidGroupingEdits === nw.agentSettings.avoidGroupingEdits && agentGuiStateEquals(previous.state, next.state) && pf.position.x === nf.position.x && pf.position.y === nf.position.y && pf.width === nf.width && pf.height === nf.height && pf.desktopSize.width === nf.desktopSize.width && pf.desktopSize.height === nf.desktopSize.height && pf.isMaximized === nf.isMaximized && pf.isActive === nf.isActive && pf.embedded === nf.embedded && pf.previewMode === nf.previewMode && pf.conversationRailAutoCollapseWidthPx === nf.conversationRailAutoCollapseWidthPx && pr.composerFocusSequence === nr.composerFocusSequence && pr.newConversationSequence === nr.newConversationSequence && pr.openSession === nr.openSession && pr.prefillPrompt === nr.prefillPrompt && pr.agentProbes === nr.agentProbes && pr.onProbeDemandChange === nr.onProbeDemandChange && pr.onProbeRefreshRequest === nr.onProbeRefreshRequest && pc.capabilityMenuState === nc.capabilityMenuState && pc.accountMenuState === nc.accountMenuState && pc.agentTargets === nc.agentTargets && pc.agentTargetsLoading === nc.agentTargetsLoading && pc.providerRailAllPresentation?.iconUrl === nc.providerRailAllPresentation?.iconUrl && pc.providerRailMode === nc.providerRailMode && pc.comingSoonProviders === nc.comingSoonProviders && pc.providerReadinessGates === nc.providerReadinessGates && pc.defaultAgentTargetId === nc.defaultAgentTargetId && pc.providerAuthAccountLabels === nc.providerAuthAccountLabels && pc.managedAgentsState === nc.managedAgentsState && pc.contextMentionProviders === nc.contextMentionProviders && pc.workspaceAppIcons === nc.workspaceAppIcons && pc.disabledHomeSuggestions === nc.disabledHomeSuggestions && pa.onLinkAction === na.onLinkAction && pa.onHandoffConversation === na.onHandoffConversation && pa.onCapabilitySettingsRequest === na.onCapabilitySettingsRequest && pa.onAgentProviderLogin === na.onAgentProviderLogin && pa.onOpenConversationWindow === na.onOpenConversationWindow && pa.onClose === na.onClose && pa.onResize === na.onResize && pa.onUpdateNode === na.onUpdateNode && pa.onRememberComposerDefaults === na.onRememberComposerDefaults && pa.isMuted === na.isMuted && pa.onMinimize === na.onMinimize && pa.onToggleMaximize === na.onToggleMaximize && pa.onShowMessage === na.onShowMessage && ps.providerRailEmpty === ns.providerRailEmpty && ps.providerUnavailableState === ns.providerUnavailableState && ps.sidebarFooter === ns.sidebarFooter;
32318
+ return pi.nodeId === ni.nodeId && pi.workspaceId === ni.workspaceId && pi.currentUserId === ni.currentUserId && pi.title === ni.title && pw.path === nw.path && pw.fileReferenceAdapter === nw.fileReferenceAdapter && pw.onRequestGitBranches === nw.onRequestGitBranches && pw.selectProjectDirectory === nw.selectProjectDirectory && pw.resolveDroppedFileReferences === nw.resolveDroppedFileReferences && pw.referenceSourceAggregator === nw.referenceSourceAggregator && pw.resolveReferenceEntryIconUrl === nw.resolveReferenceEntryIconUrl && pw.resolveMentionReferenceTarget === nw.resolveMentionReferenceTarget && pw.resolveReferenceInitialTarget === nw.resolveReferenceInitialTarget && pw.onFileReferencesAdded === nw.onFileReferencesAdded && pw.agentSettings.avoidGroupingEdits === nw.agentSettings.avoidGroupingEdits && agentGuiStateEquals(previous.state, next.state) && pf.position.x === nf.position.x && pf.position.y === nf.position.y && pf.width === nf.width && pf.height === nf.height && pf.desktopSize.width === nf.desktopSize.width && pf.desktopSize.height === nf.desktopSize.height && pf.isMaximized === nf.isMaximized && pf.isActive === nf.isActive && pf.isVisible === nf.isVisible && pf.embedded === nf.embedded && pf.previewMode === nf.previewMode && pf.conversationRailAutoCollapseWidthPx === nf.conversationRailAutoCollapseWidthPx && pr.composerFocusSequence === nr.composerFocusSequence && pr.newConversationSequence === nr.newConversationSequence && pr.openSession === nr.openSession && pr.prefillPrompt === nr.prefillPrompt && pr.agentProbes === nr.agentProbes && pr.onProbeDemandChange === nr.onProbeDemandChange && pr.onProbeRefreshRequest === nr.onProbeRefreshRequest && pc.capabilityMenuState === nc.capabilityMenuState && pc.accountMenuState === nc.accountMenuState && pc.agentTargets === nc.agentTargets && pc.agentTargetsLoading === nc.agentTargetsLoading && pc.providerRailAllPresentation?.iconUrl === nc.providerRailAllPresentation?.iconUrl && pc.providerRailMode === nc.providerRailMode && pc.comingSoonProviders === nc.comingSoonProviders && pc.providerReadinessGates === nc.providerReadinessGates && pc.defaultAgentTargetId === nc.defaultAgentTargetId && pc.providerAuthAccountLabels === nc.providerAuthAccountLabels && pc.managedAgentsState === nc.managedAgentsState && pc.contextMentionProviders === nc.contextMentionProviders && pc.workspaceAppIcons === nc.workspaceAppIcons && pc.disabledHomeSuggestions === nc.disabledHomeSuggestions && pa.onLinkAction === na.onLinkAction && pa.onHandoffConversation === na.onHandoffConversation && pa.onCapabilitySettingsRequest === na.onCapabilitySettingsRequest && pa.onAgentProviderLogin === na.onAgentProviderLogin && pa.onOpenConversationWindow === na.onOpenConversationWindow && pa.onClose === na.onClose && pa.onResize === na.onResize && pa.onUpdateNode === na.onUpdateNode && pa.onRememberComposerDefaults === na.onRememberComposerDefaults && pa.isMuted === na.isMuted && pa.onMinimize === na.onMinimize && pa.onToggleMaximize === na.onToggleMaximize && pa.onShowMessage === na.onShowMessage && pa.onEngagementEvent === na.onEngagementEvent && ps.providerRailEmpty === ns.providerRailEmpty && ps.providerUnavailableState === ns.providerUnavailableState && ps.sidebarFooter === ns.sidebarFooter;
31596
32319
  }
31597
32320
 
31598
32321
  // agent-gui/agentGuiNode/AgentGUINode.labels.ts
31599
- import { useMemo as useMemo37 } from "react";
32322
+ import { useMemo as useMemo38 } from "react";
31600
32323
 
31601
32324
  // agent-gui/agentGuiNode/model/agentHomeSuggestions.ts
31602
32325
  import { createRichTextMentionHref as createRichTextMentionHref2 } from "@tutti-os/ui-rich-text/core";
@@ -31743,7 +32466,7 @@ function useAgentGUIViewLabels(input) {
31743
32466
  workspaceAppIcons,
31744
32467
  workspaceId
31745
32468
  } = input;
31746
- return useMemo37(
32469
+ return useMemo38(
31747
32470
  () => ({
31748
32471
  initialPlaceholder: t("agentHost.agentGui.initialPlaceholder", {
31749
32472
  provider: displayProviderLabel
@@ -32338,7 +33061,7 @@ function useAgentGUIViewLabels(input) {
32338
33061
  );
32339
33062
  }
32340
33063
  function useAgentGUIWorkspaceFileReferenceCopy(t) {
32341
- return useMemo37(
33064
+ return useMemo38(
32342
33065
  () => ({
32343
33066
  t(key, values) {
32344
33067
  const localeKey = workspaceFileReferenceLocaleKeyByPickerKey[key];
@@ -32409,69 +33132,6 @@ function slashStatusLimitsFromQuotas(quotas, selectedModel, t) {
32409
33132
  };
32410
33133
  }).filter((limit) => limit !== null);
32411
33134
  }
32412
- function slashStatusQuotasFromCanonicalUsage(usage) {
32413
- if (!usage) {
32414
- return [];
32415
- }
32416
- return usage.quotas.map((quota) => {
32417
- const record = objectRecord2(quota);
32418
- const quotaType = agentUsageQuotaTypeValue(record?.quotaType);
32419
- if (!record || !quotaType) {
32420
- return null;
32421
- }
32422
- const normalized = { quotaType };
32423
- const percentRemaining = numberValue2(record.percentRemaining);
32424
- if (percentRemaining !== null) {
32425
- normalized.percentRemaining = percentRemaining;
32426
- }
32427
- const resetsAtUnixMs = numberValue2(record.resetsAtUnixMs);
32428
- if (resetsAtUnixMs !== null) {
32429
- normalized.resetsAtUnixMs = resetsAtUnixMs;
32430
- }
32431
- const resetText = stringValue3(record.resetText);
32432
- if (resetText) {
32433
- normalized.resetText = resetText;
32434
- }
32435
- const dollarRemaining = numberValue2(record.dollarRemaining);
32436
- if (dollarRemaining !== null) {
32437
- normalized.dollarRemaining = dollarRemaining;
32438
- }
32439
- const modelName = stringValue3(record.modelName);
32440
- if (modelName) {
32441
- normalized.modelName = modelName;
32442
- }
32443
- return normalized;
32444
- }).filter((quota) => quota !== null);
32445
- }
32446
- function agentUsageQuotaTypeValue(value) {
32447
- switch (stringValue3(value)) {
32448
- case "session":
32449
- case "weekly":
32450
- case "monthly":
32451
- case "daily":
32452
- case "model":
32453
- case "cost":
32454
- return stringValue3(value);
32455
- default:
32456
- return null;
32457
- }
32458
- }
32459
- function objectRecord2(value) {
32460
- return value && typeof value === "object" ? value : null;
32461
- }
32462
- function numberValue2(value) {
32463
- if (typeof value === "number" && Number.isFinite(value)) {
32464
- return value;
32465
- }
32466
- if (typeof value === "string" && value.trim()) {
32467
- const parsed = Number(value);
32468
- return Number.isFinite(parsed) ? parsed : null;
32469
- }
32470
- return null;
32471
- }
32472
- function stringValue3(value) {
32473
- return typeof value === "string" ? value.trim() : "";
32474
- }
32475
33135
  function filterSlashStatusQuotasForModel(quotas, selectedModel) {
32476
33136
  const normalizedSelectedModel = normalizeSlashStatusModelName(selectedModel);
32477
33137
  const baseQuotas = (quotas ?? []).filter(
@@ -32499,6 +33159,7 @@ function resolveAgentGUIRailStatusProvider(input) {
32499
33159
 
32500
33160
  // agent-gui/agentGuiNode/AgentGUINode.tsx
32501
33161
  import { jsx as jsx60, jsxs as jsxs45 } from "react/jsx-runtime";
33162
+ var EMPTY_SLASH_STATUS_QUOTAS = [];
32502
33163
  var AgentGUINode = memo14(function AgentGUINode2({
32503
33164
  identity,
32504
33165
  workspace,
@@ -32531,6 +33192,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32531
33192
  desktopSize,
32532
33193
  isMaximized = false,
32533
33194
  isActive,
33195
+ isVisible = true,
32534
33196
  embedded = false,
32535
33197
  previewMode = false,
32536
33198
  conversationRailAutoCollapseWidthPx = null
@@ -32574,7 +33236,8 @@ var AgentGUINode = memo14(function AgentGUINode2({
32574
33236
  isMuted = false,
32575
33237
  onMinimize,
32576
33238
  onToggleMaximize,
32577
- onShowMessage
33239
+ onShowMessage,
33240
+ onEngagementEvent
32578
33241
  } = hostActions;
32579
33242
  const {
32580
33243
  providerRailEmpty: renderProviderRailEmpty,
@@ -32582,22 +33245,19 @@ var AgentGUINode = memo14(function AgentGUINode2({
32582
33245
  sidebarFooter: renderSidebarFooter
32583
33246
  } = renderSlots;
32584
33247
  const { i18n, locale, t } = useTranslation();
32585
- const workspaceUserProjectI18n = useMemo38(
33248
+ const workspaceUserProjectI18n = useMemo39(
32586
33249
  () => createWorkspaceUserProjectI18nRuntime(i18n),
32587
33250
  [i18n]
32588
33251
  );
32589
- const workspaceFileManagerI18n = useMemo38(
33252
+ const workspaceFileManagerI18n = useMemo39(
32590
33253
  () => typeof i18n?.t === "function" ? createWorkspaceFileManagerI18nRuntime(i18n) : null,
32591
33254
  [i18n]
32592
33255
  );
32593
33256
  const handleLinkAction = useCallback50(
32594
33257
  (action) => {
32595
- const agentTargetId = state.agentTargetId?.trim() || null;
32596
- onLinkAction?.(
32597
- action.type === "open-agent-session" && !action.agentTargetId && agentTargetId ? { ...action, agentTargetId } : action
32598
- );
33258
+ onLinkAction?.(action);
32599
33259
  },
32600
- [onLinkAction, state.agentTargetId]
33260
+ [onLinkAction]
32601
33261
  );
32602
33262
  const handleAgentProviderLogin = useCallback50(
32603
33263
  (provider) => {
@@ -32651,7 +33311,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32651
33311
  const isConversationRailManuallyCollapsed = state.conversationRailCollapsed === true;
32652
33312
  const isConversationRailAutoCollapsed = shouldAutoCollapseAgentGUIConversationRail(width, railAutoCollapseWidthPx);
32653
33313
  const isConversationRailCollapsed = isConversationRailManuallyCollapsed || isConversationRailAutoCollapsed;
32654
- const minSize = useMemo38(
33314
+ const minSize = useMemo39(
32655
33315
  () => ({
32656
33316
  ...resolveCanonicalNodeMinSize("agentGui"),
32657
33317
  width: AGENT_GUI_COLLAPSED_MIN_WIDTH_PX
@@ -32739,7 +33399,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32739
33399
  },
32740
33400
  [actions, onUpdateNode, previewMode]
32741
33401
  );
32742
- const viewActions = useMemo38(
33402
+ const viewActions = useMemo39(
32743
33403
  () => ({
32744
33404
  ...actions,
32745
33405
  createConversation: handleCreateConversation
@@ -32762,28 +33422,28 @@ var AgentGUINode = memo14(function AgentGUINode2({
32762
33422
  const workspaceFileReferenceCopy = useAgentGUIWorkspaceFileReferenceCopy(t);
32763
33423
  const windowTitle = title;
32764
33424
  const activeProbeProvider = activeProvider;
32765
- const railStatusProvider = useMemo38(
33425
+ const railStatusProvider = useMemo39(
32766
33426
  () => resolveAgentGUIRailStatusProvider({
32767
33427
  conversationFilter: viewModel.rail.conversationFilter,
32768
33428
  agentTargets: viewModel.rail.agentTargets
32769
33429
  }),
32770
33430
  [viewModel.rail.conversationFilter, viewModel.rail.agentTargets]
32771
33431
  );
32772
- const activeAgentProbe = useMemo38(
33432
+ const activeAgentProbe = useMemo39(
32773
33433
  () => findWorkspaceAgentProbeForDockProvider(
32774
33434
  workspaceAgentProbes?.snapshot ?? null,
32775
33435
  activeProbeProvider
32776
33436
  ),
32777
33437
  [activeProbeProvider, workspaceAgentProbes?.snapshot]
32778
33438
  );
32779
- const railAgentProbe = useMemo38(
33439
+ const railAgentProbe = useMemo39(
32780
33440
  () => railStatusProvider ? findWorkspaceAgentProbeForDockProvider(
32781
33441
  workspaceAgentProbes?.snapshot ?? null,
32782
33442
  railStatusProvider
32783
33443
  ) : null,
32784
33444
  [railStatusProvider, workspaceAgentProbes?.snapshot]
32785
33445
  );
32786
- const isActiveAgentProviderReady = useMemo38(() => {
33446
+ const isActiveAgentProviderReady = useMemo39(() => {
32787
33447
  const managedAgent = getAgentHostManagedToolchainAgentByName(
32788
33448
  activeReadinessProvider
32789
33449
  );
@@ -32798,11 +33458,9 @@ var AgentGUINode = memo14(function AgentGUINode2({
32798
33458
  managedAgentsState
32799
33459
  ) === "installed";
32800
33460
  }, [activeReadinessProvider, managedAgentsState]);
32801
- const canonicalSlashStatusQuotas = slashStatusQuotasFromCanonicalUsage(
32802
- viewModel.detail.usage
32803
- );
32804
- const slashStatusQuotaSource = canonicalSlashStatusQuotas.length > 0 ? canonicalSlashStatusQuotas : activeAgentProbe?.usage?.quotas && activeAgentProbe.usage.quotas.length > 0 ? activeAgentProbe.usage.quotas : [];
32805
- const slashStatusLimits = useMemo38(
33461
+ const canonicalSlashStatusQuotas = viewModel.detail.usage?.quotas ?? EMPTY_SLASH_STATUS_QUOTAS;
33462
+ const slashStatusQuotaSource = canonicalSlashStatusQuotas.length > 0 ? canonicalSlashStatusQuotas : activeAgentProbe?.usage?.quotas && activeAgentProbe.usage.quotas.length > 0 ? activeAgentProbe.usage.quotas : EMPTY_SLASH_STATUS_QUOTAS;
33463
+ const slashStatusLimits = useMemo39(
32806
33464
  () => slashStatusLimitsFromQuotas(
32807
33465
  slashStatusQuotaSource,
32808
33466
  viewModel.composer.composerSettings.selectedModelValue ?? viewModel.composer.composerSettings.draftSettings.model,
@@ -32816,8 +33474,8 @@ var AgentGUINode = memo14(function AgentGUINode2({
32816
33474
  ]
32817
33475
  );
32818
33476
  const slashStatusLimitsUnavailable = slashStatusLimits.length === 0 && canonicalSlashStatusQuotas.length === 0 && !(workspaceAgentProbes?.isLoadingUsage ?? false) && (Boolean(activeAgentProbe?.usage) || Boolean(activeAgentProbe?.lastError));
32819
- const railSlashStatusQuotaSource = railStatusProvider && railAgentProbe?.usage?.quotas && railAgentProbe.usage.quotas.length > 0 ? railAgentProbe.usage.quotas : [];
32820
- const railSlashStatusLimits = useMemo38(
33477
+ const railSlashStatusQuotaSource = railStatusProvider && railAgentProbe?.usage?.quotas && railAgentProbe.usage.quotas.length > 0 ? railAgentProbe.usage.quotas : EMPTY_SLASH_STATUS_QUOTAS;
33478
+ const railSlashStatusLimits = useMemo39(
32821
33479
  () => slashStatusLimitsFromQuotas(railSlashStatusQuotaSource, null, t),
32822
33480
  [railSlashStatusQuotaSource, t]
32823
33481
  );
@@ -32825,7 +33483,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32825
33483
  const slashStatusUsageCapturedAtUnixMs = slashStatusUsageProbe?.usage?.capturedAtUnixMs ?? null;
32826
33484
  const slashStatusUsageDidFail = workspaceAgentProbes?.usageLoadFailed ?? false;
32827
33485
  const slashStatusUsageAttempted = Boolean(slashStatusUsageProbe?.usage) || Boolean(slashStatusUsageProbe?.lastError);
32828
- const agentProbeLines = useMemo38(() => {
33486
+ const agentProbeLines = useMemo39(() => {
32829
33487
  return buildDockAgentProbeTooltipLines(
32830
33488
  activeAgentProbe,
32831
33489
  workspaceAgentProbes?.isLoadingAvailability ?? false,
@@ -32841,7 +33499,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32841
33499
  workspaceAgentProbes?.isLoadingUsage,
32842
33500
  t
32843
33501
  ]);
32844
- useEffect38(() => {
33502
+ useEffect39(() => {
32845
33503
  if (previewMode || !onAgentProbeDemandChange) {
32846
33504
  return;
32847
33505
  }
@@ -32851,7 +33509,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32851
33509
  onAgentProbeDemandChange(null, probeSourceId);
32852
33510
  };
32853
33511
  }, [activeProbeProvider, nodeId, onAgentProbeDemandChange, previewMode]);
32854
- useEffect38(() => {
33512
+ useEffect39(() => {
32855
33513
  if (previewMode || !onAgentProbeDemandChange || !railStatusProvider || railStatusProvider === activeProbeProvider) {
32856
33514
  return;
32857
33515
  }
@@ -32975,6 +33633,8 @@ var AgentGUINode = memo14(function AgentGUINode2({
32975
33633
  providerRailAllPresentation,
32976
33634
  actions: viewActions,
32977
33635
  isActive,
33636
+ isVisible,
33637
+ onEngagementEvent,
32978
33638
  composerFocusRequestSequence,
32979
33639
  newConversationRequestSequence,
32980
33640
  isAgentProviderReady: isActiveAgentProviderReady,
@@ -33084,4 +33744,4 @@ export {
33084
33744
  resolveAgentGUIAgentTarget,
33085
33745
  AgentGUI
33086
33746
  };
33087
- //# sourceMappingURL=chunk-BIS4QRX7.js.map
33747
+ //# sourceMappingURL=chunk-7O4D4KOE.js.map