@tutti-os/agent-gui 0.0.96 → 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 (60) 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 -17
  10. package/dist/{chunk-WMNS4MAQ.js → chunk-3NOJFKDV.js} +3 -3
  11. package/dist/{chunk-4PQPJ5OY.js → chunk-4ROALW3K.js} +2 -2
  12. package/dist/{chunk-3XXBDYAI.js → chunk-63BE6RGM.js} +3 -3
  13. package/dist/{chunk-JKIZA7EJ.js → chunk-7M77BK6K.js} +54 -91
  14. package/dist/chunk-7M77BK6K.js.map +1 -0
  15. package/dist/{chunk-WKSFPJHZ.js → chunk-7O4D4KOE.js} +1343 -650
  16. package/dist/chunk-7O4D4KOE.js.map +1 -0
  17. package/dist/{chunk-O3Q5SIJH.js → chunk-CPUEPDF7.js} +7 -115
  18. package/dist/chunk-CPUEPDF7.js.map +1 -0
  19. package/dist/{chunk-W6WAGPMD.js → chunk-FSKGEGGX.js} +15 -3
  20. package/dist/chunk-FSKGEGGX.js.map +1 -0
  21. package/dist/{chunk-3Y3F7CS5.js → chunk-GAD6Y3BF.js} +2 -2
  22. package/dist/{chunk-AGT7MUTV.js → chunk-J7ZYAUPC.js} +4 -4
  23. package/dist/{chunk-RE4AXS27.js → chunk-MRRICFWA.js} +2 -2
  24. package/dist/{chunk-QVBF5BN5.js → chunk-OTRZBTFQ.js} +2 -2
  25. package/dist/{chunk-TVIGLNNI.js → chunk-QWGJ5TEG.js} +4 -1
  26. package/dist/chunk-QWGJ5TEG.js.map +1 -0
  27. package/dist/{chunk-E4HQUTM3.js → chunk-RHTZAODZ.js} +2 -2
  28. package/dist/{chunk-XPFHJMZP.js → chunk-SPZJCTBV.js} +3 -3
  29. package/dist/{chunk-2HJEOO7W.js → chunk-T6PEJFRP.js} +10 -40
  30. package/dist/chunk-T6PEJFRP.js.map +1 -0
  31. package/dist/{chunk-H5F3QSCF.js → chunk-Y5M6Q6WX.js} +2 -2
  32. package/dist/context-mention-palette/index.js +8 -8
  33. package/dist/i18n/index.d.ts +14 -2
  34. package/dist/i18n/index.js +2 -2
  35. package/dist/index.d.ts +4 -4
  36. package/dist/index.js +15 -15
  37. package/dist/index.js.map +1 -1
  38. package/dist/mention-search.js +6 -6
  39. package/dist/workbench/contribution.js +2 -2
  40. package/dist/workbench/index.js +5 -5
  41. package/dist/workbench/launch.js +1 -1
  42. package/dist/workbench/sessionTitle.js +3 -3
  43. package/dist/workspace-agent-generated-files.js +4 -4
  44. package/package.json +14 -14
  45. package/dist/chunk-2HJEOO7W.js.map +0 -1
  46. package/dist/chunk-JKIZA7EJ.js.map +0 -1
  47. package/dist/chunk-O3Q5SIJH.js.map +0 -1
  48. package/dist/chunk-TVIGLNNI.js.map +0 -1
  49. package/dist/chunk-W6WAGPMD.js.map +0 -1
  50. package/dist/chunk-WKSFPJHZ.js.map +0 -1
  51. /package/dist/{chunk-WMNS4MAQ.js.map → chunk-3NOJFKDV.js.map} +0 -0
  52. /package/dist/{chunk-4PQPJ5OY.js.map → chunk-4ROALW3K.js.map} +0 -0
  53. /package/dist/{chunk-3XXBDYAI.js.map → chunk-63BE6RGM.js.map} +0 -0
  54. /package/dist/{chunk-3Y3F7CS5.js.map → chunk-GAD6Y3BF.js.map} +0 -0
  55. /package/dist/{chunk-AGT7MUTV.js.map → chunk-J7ZYAUPC.js.map} +0 -0
  56. /package/dist/{chunk-RE4AXS27.js.map → chunk-MRRICFWA.js.map} +0 -0
  57. /package/dist/{chunk-QVBF5BN5.js.map → chunk-OTRZBTFQ.js.map} +0 -0
  58. /package/dist/{chunk-E4HQUTM3.js.map → chunk-RHTZAODZ.js.map} +0 -0
  59. /package/dist/{chunk-XPFHJMZP.js.map → chunk-SPZJCTBV.js.map} +0 -0
  60. /package/dist/{chunk-H5F3QSCF.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-4PQPJ5OY.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-JKIZA7EJ.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-AGT7MUTV.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-WMNS4MAQ.js";
83
+ } from "./chunk-3NOJFKDV.js";
84
84
  import {
85
85
  buildWorkspaceAgentActivityListViewModel
86
- } from "./chunk-3XXBDYAI.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-O3Q5SIJH.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-XPFHJMZP.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-2HJEOO7W.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-E4HQUTM3.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";
@@ -2568,13 +2568,6 @@ function resolveAgentGUIConversationSortTimeUnixMs(conversation) {
2568
2568
  }
2569
2569
 
2570
2570
  // agent-gui/agentGuiNode/model/agentGuiConversationModel.ts
2571
- function selectAgentGUIConversationId(conversations, preferredSessionId) {
2572
- const preferred = preferredSessionId?.trim();
2573
- if (preferred && conversations.some((conversation) => conversation.id === preferred)) {
2574
- return preferred;
2575
- }
2576
- return conversations[0]?.id ?? null;
2577
- }
2578
2571
  function mergeAgentGUITimelineItems(left, right) {
2579
2572
  return mergeTimelineItems(left, right);
2580
2573
  }
@@ -3562,7 +3555,7 @@ function sortAgentTargetRefValue(value) {
3562
3555
  var EMPTY_AGENT_GUI_MESSAGES = [];
3563
3556
  var GOAL_CLEAR_PROMPT = "/goal clear";
3564
3557
  function resolveAgentGUIProviderRailTargetSelection(input) {
3565
- return input.activeConversation && matchesAgentGUIConversationSummaryFilter(
3558
+ return input.nextFilter.kind === "agentTarget" && input.activeConversation && matchesAgentGUIConversationSummaryFilter(
3566
3559
  input.activeConversation,
3567
3560
  input.nextFilter
3568
3561
  ) ? "keep-active-conversation" : "open-home-composer";
@@ -4059,12 +4052,15 @@ function sanitizeComposerSettingsForOptions(settings, options) {
4059
4052
  const reasoningEffort = normalizeOptionalText(settings.reasoningEffort);
4060
4053
  const speed = normalizeOptionalText(settings.speed);
4061
4054
  const permissionModeId = normalizeOptionalText(settings.permissionModeId);
4062
- const modelReasoningProfile = model ? options.reasoningOptionsByModel?.[model] : void 0;
4063
- const modelReasoningValues = modelReasoningProfile ? composerOptionValues(modelReasoningProfile.options) : null;
4055
+ const modelReasoningSelection = reasoningSelectionForModelFromComposerOptions(
4056
+ options,
4057
+ reasoningEffort,
4058
+ model
4059
+ );
4064
4060
  return {
4065
4061
  ...settings,
4066
4062
  model: options.behavior?.modelOptionsAuthoritative === true && model && modelValues.size > 0 && !modelValues.has(model) ? null : model,
4067
- 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,
4068
4064
  speed: speed && speedValues.size > 0 && !speedValues.has(speed) ? null : speed,
4069
4065
  permissionModeId: permissionModeId && permissionValues.size > 0 && !permissionValues.has(permissionModeId) ? null : permissionModeId
4070
4066
  };
@@ -4193,6 +4189,7 @@ function agentGUISessionStateDiagnosticDetails(state) {
4193
4189
  var AGENT_PROVIDER_SESSION_NOT_FOUND_ERROR = "agent.provider_session_not_found";
4194
4190
  var AGENT_RESUME_SESSION_NOT_LOCAL_ERROR = "agent.resume_session_not_local";
4195
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";
4196
4193
  var AGENT_PROVIDER_SESSION_NOT_FOUND_FALLBACK_MESSAGE = "The previous agent session can no longer be restored.";
4197
4194
  var AGENT_RESUME_SESSION_NOT_LOCAL_FALLBACK_MESSAGE = "The previous agent session is not available on this machine.";
4198
4195
  var AGENT_GUI_CAUGHT_ERROR_STACK_LIMIT = 4e3;
@@ -4294,6 +4291,10 @@ function getAgentGUIErrorMessage(error) {
4294
4291
  return translate("messages.agentResumeSessionNotLocal");
4295
4292
  if (isSettingsRequireNewSessionErrorCode(code))
4296
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
+ }
4297
4298
  if (error && typeof error === "object") {
4298
4299
  const debugMessage = error.debugMessage;
4299
4300
  if (typeof debugMessage === "string" && debugMessage.trim())
@@ -4301,6 +4302,13 @@ function getAgentGUIErrorMessage(error) {
4301
4302
  }
4302
4303
  return error instanceof Error ? error.message : String(error);
4303
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
+ }
4304
4312
  function getAgentGUIRawErrorMessage(error) {
4305
4313
  if (error && typeof error === "object") {
4306
4314
  const debugMessage = error.debugMessage;
@@ -4355,7 +4363,57 @@ function token(value) {
4355
4363
  }
4356
4364
 
4357
4365
  // agent-gui/agentGuiNode/controller/useAgentConversationMessagePaging.ts
4358
- 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
4359
4417
  var PAGE_SIZE = 100;
4360
4418
  function minFiniteMessageVersion(messages) {
4361
4419
  let result = null;
@@ -4419,14 +4477,20 @@ function sessionHasRenderableMessages(input) {
4419
4477
  function useAgentConversationMessagePaging(input) {
4420
4478
  const inputRef = useRef3(input);
4421
4479
  inputRef.current = input;
4422
- const olderLoadSequenceRef = useRef3(0);
4423
- const failedOlderCursorBySessionIdRef = useRef3(/* @__PURE__ */ new Map());
4424
- const loadInitialMessages = useCallback2(async (agentSessionId) => {
4425
- const normalized = agentSessionId.trim();
4426
- if (!normalized) return;
4427
- const current = inputRef.current;
4428
- current.reload.reconcileDetail(normalized);
4429
- }, []);
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
+ );
4430
4494
  const loadOlderMessages = useCallback2(
4431
4495
  async (agentSessionId) => {
4432
4496
  const current = inputRef.current;
@@ -4438,7 +4502,7 @@ function useAgentConversationMessagePaging(input) {
4438
4502
  current.getCanonicalMessages(normalized)
4439
4503
  );
4440
4504
  const oldestLoadedVersion = view?.oldestLoadedVersion ?? canonicalOldestVersion;
4441
- const hasOlderMessages = view?.hasOlderMessages === true || canonicalOldestVersion !== null && canonicalOldestVersion > 1;
4505
+ const hasOlderMessages = view?.hasOlderMessages === true || view?.oldestLoadedVersion == null && canonicalOldestVersion !== null && canonicalOldestVersion > 1;
4442
4506
  if (!hasOlderMessages || view?.isLoadingOlderMessages === true || oldestLoadedVersion === null || current.getActiveSessionId() !== normalized) {
4443
4507
  current.diagnostics.page({
4444
4508
  agentSessionId: normalized,
@@ -4454,16 +4518,36 @@ function useAgentConversationMessagePaging(input) {
4454
4518
  return;
4455
4519
  }
4456
4520
  const beforeVersion = oldestLoadedVersion;
4457
- if (failedOlderCursorBySessionIdRef.current.get(normalized) === beforeVersion) {
4458
- current.diagnostics.page({
4459
- 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
+ } : {
4460
4538
  details: { beforeVersion, reason: "previous_cursor_error" },
4461
4539
  event: "agent.gui.messages.older.suppressed_after_error",
4462
4540
  level: "warn"
4541
+ };
4542
+ current.diagnostics.page({
4543
+ agentSessionId: normalized,
4544
+ details: suppression.details,
4545
+ event: suppression.event,
4546
+ level: suppression.level
4463
4547
  });
4464
4548
  return;
4465
4549
  }
4466
- const requestId = ++olderLoadSequenceRef.current;
4550
+ const { request } = beginResult;
4467
4551
  current.view.setOlderMessagesLoading(ref, true);
4468
4552
  try {
4469
4553
  current.diagnostics.page({
@@ -4472,7 +4556,7 @@ function useAgentConversationMessagePaging(input) {
4472
4556
  beforeVersion,
4473
4557
  limit: PAGE_SIZE,
4474
4558
  order: "desc",
4475
- requestId
4559
+ requestId: request.requestId
4476
4560
  },
4477
4561
  event: "agent.gui.messages.older.requested"
4478
4562
  });
@@ -4484,8 +4568,10 @@ function useAgentConversationMessagePaging(input) {
4484
4568
  limit: PAGE_SIZE,
4485
4569
  order: "desc"
4486
4570
  });
4487
- if (!current.isMounted() || current.getActiveSessionId() !== normalized || olderLoadSequenceRef.current !== requestId) {
4488
- current.view.setOlderMessagesLoading(ref, false);
4571
+ if (!current.isMounted() || current.getActiveSessionId() !== normalized) {
4572
+ if (olderPagingState.abandon(request)) {
4573
+ current.view.setOlderMessagesLoading(ref, false);
4574
+ }
4489
4575
  return;
4490
4576
  }
4491
4577
  current.diagnostics.page({
@@ -4494,31 +4580,39 @@ function useAgentConversationMessagePaging(input) {
4494
4580
  beforeVersion,
4495
4581
  hasMore: page.hasMore,
4496
4582
  latestVersion: page.latestVersion,
4497
- requestId
4583
+ requestId: request.requestId
4498
4584
  },
4499
4585
  event: "agent.gui.messages.older.resolved",
4500
4586
  messages: page.messages
4501
4587
  });
4502
- failedOlderCursorBySessionIdRef.current.delete(normalized);
4588
+ if (!olderPagingState.resolve(
4589
+ request,
4590
+ !page.hasMore || page.messages.length === 0
4591
+ )) {
4592
+ return;
4593
+ }
4503
4594
  current.view.mergeOlder(ref, page.messages, {
4504
4595
  hasOlderMessages: page.hasMore && page.messages.length > 0
4505
4596
  });
4597
+ current.view.setOlderMessagesLoading(ref, false);
4506
4598
  } catch (error) {
4507
- if (!current.isMounted() || current.getActiveSessionId() !== normalized || olderLoadSequenceRef.current !== requestId) {
4508
- current.view.setOlderMessagesLoading(ref, false);
4599
+ if (!current.isMounted() || current.getActiveSessionId() !== normalized) {
4600
+ if (olderPagingState.abandon(request)) {
4601
+ current.view.setOlderMessagesLoading(ref, false);
4602
+ }
4509
4603
  return;
4510
4604
  }
4511
- failedOlderCursorBySessionIdRef.current.set(normalized, beforeVersion);
4605
+ if (!olderPagingState.fail(request)) return;
4512
4606
  current.diagnostics.error({
4513
4607
  agentSessionId: normalized,
4514
- context: { beforeVersion, requestId },
4608
+ context: { beforeVersion, requestId: request.requestId },
4515
4609
  error,
4516
4610
  phase: "load_session_messages"
4517
4611
  });
4518
4612
  current.view.setOlderMessagesLoading(ref, false);
4519
4613
  }
4520
4614
  },
4521
- []
4615
+ [olderPagingState]
4522
4616
  );
4523
4617
  const reloadSelectedConversation = useCallback2(
4524
4618
  (agentSessionId, options) => {
@@ -5437,11 +5531,17 @@ import {
5437
5531
  selectSessionActivationPresentations,
5438
5532
  sessionActivationPresentationMapsEqual
5439
5533
  } from "@tutti-os/agent-activity-core";
5440
- 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";
5441
5535
  var ACTIVATION_EXPIRY_MS = 45e3;
5442
5536
  function isPendingNewConversationActivation(activation) {
5443
5537
  return activation?.mode === "new" && (activation.status === "requested" || activation.status === "uncertain");
5444
5538
  }
5539
+ function isPendingNewConversationActivationForSession(activation, agentSessionId) {
5540
+ const normalizedSessionId = agentSessionId?.trim() ?? "";
5541
+ return Boolean(
5542
+ normalizedSessionId && activation?.agentSessionId.trim() === normalizedSessionId && isPendingNewConversationActivation(activation)
5543
+ );
5544
+ }
5445
5545
  function useAgentGUIActivation({
5446
5546
  engine,
5447
5547
  workspaceId,
@@ -5568,7 +5668,7 @@ function useAgentGUIActivation({
5568
5668
  (agentSessionId) => (agentSessionId ? presentations[agentSessionId]?.errorCode : null) ?? null,
5569
5669
  [presentations]
5570
5670
  );
5571
- return useMemo2(
5671
+ return useMemo3(
5572
5672
  () => ({
5573
5673
  activate,
5574
5674
  clearFailure,
@@ -5591,7 +5691,7 @@ function useAgentGUIActivation({
5591
5691
  }
5592
5692
 
5593
5693
  // agent-gui/agentGuiNode/controller/useAgentGUIActiveMessages.ts
5594
- import { useMemo as useMemo3 } from "react";
5694
+ import { useMemo as useMemo4 } from "react";
5595
5695
 
5596
5696
  // host/workspaceAgentSessionMessages.ts
5597
5697
  import {
@@ -5636,7 +5736,7 @@ function useAgentGUIActiveMessages(input) {
5636
5736
  storedMessages,
5637
5737
  workspaceId
5638
5738
  } = input;
5639
- const activeMessages = useMemo3(() => {
5739
+ const activeMessages = useMemo4(() => {
5640
5740
  if (!activeConversationId) return storedMessages;
5641
5741
  const visibleQueuedSubmitIds = new Set(
5642
5742
  activeQueuedPrompts.map(
@@ -5680,7 +5780,7 @@ function useAgentGUIActiveMessages(input) {
5680
5780
  storedMessages,
5681
5781
  workspaceId
5682
5782
  ]);
5683
- const activeTimelineItems = useMemo3(
5783
+ const activeTimelineItems = useMemo4(
5684
5784
  () => projectAgentGUIMessagesToTimelineItems(activeMessages),
5685
5785
  [activeMessages]
5686
5786
  );
@@ -5799,7 +5899,6 @@ function useAgentGUIConversationRouting(input) {
5799
5899
  selectConversation,
5800
5900
  sessionEngine,
5801
5901
  setIntent,
5802
- syncConversationListProjection,
5803
5902
  transientConversation,
5804
5903
  workspaceId
5805
5904
  } = input;
@@ -5875,21 +5974,6 @@ function useAgentGUIConversationRouting(input) {
5875
5974
  selectConversation(intent.id, { reloadConversations: false });
5876
5975
  ensureTransientOpenSessionConversation(intent.id);
5877
5976
  return;
5878
- case "resolving": {
5879
- if (resolveId(intent.id)) {
5880
- selectConversation(intent.id, { reloadConversations: false });
5881
- return;
5882
- }
5883
- const fallback = selectAgentGUIConversationId(
5884
- conversations,
5885
- activeConversationIdRef.current
5886
- );
5887
- if (fallback) {
5888
- selectConversation(fallback, { reloadConversations: false });
5889
- } else {
5890
- setIntent({ tag: "home" });
5891
- }
5892
- }
5893
5977
  }
5894
5978
  }, [
5895
5979
  conversationListQuery,
@@ -5900,7 +5984,6 @@ function useAgentGUIConversationRouting(input) {
5900
5984
  openSessionRequest,
5901
5985
  previewMode,
5902
5986
  selectConversation,
5903
- syncConversationListProjection,
5904
5987
  transientConversation
5905
5988
  ]);
5906
5989
  }
@@ -5910,6 +5993,9 @@ import {
5910
5993
  selectLatestActivationForSession
5911
5994
  } from "@tutti-os/agent-activity-core";
5912
5995
  import { useEffect as useEffect4 } from "react";
5996
+ function clearFailedAgentGUIActivationSelection(current, failedAgentSessionId) {
5997
+ return current.lastActiveAgentSessionId?.trim() === failedAgentSessionId.trim() ? { ...current, lastActiveAgentSessionId: null } : current;
5998
+ }
5913
5999
  function useAgentGUIConversationSelectionController(input) {
5914
6000
  const {
5915
6001
  activation,
@@ -5958,7 +6044,10 @@ function useAgentGUIConversationSelectionController(input) {
5958
6044
  setIsComposerHome(true);
5959
6045
  setIntent({ tag: "home" });
5960
6046
  onDataChangeRef.current(
5961
- (current) => current.lastActiveAgentSessionId === null ? current : { ...current, lastActiveAgentSessionId: null }
6047
+ (current) => clearFailedAgentGUIActivationSelection(
6048
+ current,
6049
+ activePendingActivation.agentSessionId
6050
+ )
5962
6051
  );
5963
6052
  setDetailError(
5964
6053
  activePendingActivation.errorMessage || translate("agentHost.agentGui.sessionActivationFailed")
@@ -5999,7 +6088,10 @@ function useAgentGUIConversationSelectionController(input) {
5999
6088
  runtime: agentActivityRuntime,
6000
6089
  workspaceId
6001
6090
  });
6002
- if (previous && !isPendingNewConversationActivation(activePendingActivation)) {
6091
+ if (previous && !isPendingNewConversationActivationForSession(
6092
+ activePendingActivation,
6093
+ previous
6094
+ )) {
6003
6095
  void activation.unactivate(previous);
6004
6096
  }
6005
6097
  setIntent({ tag: "home" });
@@ -6016,7 +6108,7 @@ function useAgentGUIConversationSelectionController(input) {
6016
6108
  if ((current.tag === "active" || current.tag === "requested") && current.id === externalId) {
6017
6109
  return current;
6018
6110
  }
6019
- if (current.tag === "requested" || current.tag === "resolving") {
6111
+ if (current.tag === "requested") {
6020
6112
  return current;
6021
6113
  }
6022
6114
  return { tag: "requested", id: externalId };
@@ -6099,10 +6191,10 @@ function useAgentGUIConversationSelectionController(input) {
6099
6191
  import {
6100
6192
  selectAttentionReadState
6101
6193
  } from "@tutti-os/agent-activity-core";
6102
- 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";
6103
6195
 
6104
6196
  // contexts/workspace/presentation/renderer/agentGuiConversationList/useAgentGuiConversationList.ts
6105
- import { useMemo as useMemo4 } from "react";
6197
+ import { useMemo as useMemo5 } from "react";
6106
6198
  import {
6107
6199
  selectWorkspaceAgentConsumerSessions,
6108
6200
  selectPendingActivations,
@@ -6152,7 +6244,7 @@ function useAgentGuiConversationList(engine, query, agentTargets = []) {
6152
6244
  selectPendingActivations,
6153
6245
  pendingActivationsEqual
6154
6246
  );
6155
- return useMemo4(() => {
6247
+ return useMemo5(() => {
6156
6248
  if (!query) return null;
6157
6249
  const canonicalIds = new Set(
6158
6250
  sessions.map((item) => item.session.agentSessionId)
@@ -6265,7 +6357,7 @@ function useAgentGUIConversationListState({
6265
6357
  );
6266
6358
  const conversationFilterRef = useRef7(conversationFilter);
6267
6359
  conversationFilterRef.current = conversationFilter;
6268
- const conversationListQuery = useMemo5(() => {
6360
+ const conversationListQuery = useMemo6(() => {
6269
6361
  const userId = currentUserId?.trim() ?? "";
6270
6362
  const provider = data.provider?.trim() ?? "";
6271
6363
  if (!workspaceId.trim() || !userId || !provider) {
@@ -6295,7 +6387,7 @@ function useAgentGUIConversationListState({
6295
6387
  sessionEngine,
6296
6388
  (state) => selectAttentionReadState(state, currentUserId)
6297
6389
  );
6298
- const conversations = useMemo5(() => {
6390
+ const conversations = useMemo6(() => {
6299
6391
  return canonicalConversations.map((conversation) => {
6300
6392
  const projectedTitle = resolveAgentGUIConversationTitleFromTimelineItems({
6301
6393
  conversation,
@@ -6334,16 +6426,19 @@ import {
6334
6426
  resolveAgentActivityCapability as resolveAgentActivityCapability2,
6335
6427
  resolveAgentActivityUsage
6336
6428
  } from "@tutti-os/agent-activity-core";
6337
- import { useMemo as useMemo6 } from "react";
6429
+ import { useMemo as useMemo7 } from "react";
6338
6430
 
6339
6431
  // agent-gui/agentGuiNode/model/composerSettingsSupport.ts
6340
6432
  import {
6341
6433
  resolveAgentActivityCapability
6342
6434
  } from "@tutti-os/agent-activity-core";
6343
6435
  function composerSettingsSupportFromOptions(composerOptions, sessionCapabilities) {
6436
+ const hasModelReasoningOptions = Object.values(
6437
+ composerOptions?.reasoningOptionsByModel ?? {}
6438
+ ).some((profile) => profile.options.length > 0);
6344
6439
  return {
6345
6440
  model: composerOptions?.modelConfigurable ?? false,
6346
- reasoning: composerOptions?.reasoningConfigurable ?? false,
6441
+ reasoning: (composerOptions?.reasoningConfigurable ?? false) || hasModelReasoningOptions,
6347
6442
  speed: composerOptions?.speedConfigurable ?? false,
6348
6443
  permission: composerOptions?.permissionConfig?.configurable ?? false,
6349
6444
  plan: resolveAgentActivityCapability("planMode", {
@@ -6415,7 +6510,7 @@ function useAgentGUIComposerCapabilities(input) {
6415
6510
  const selectedModelImageInputSupported = !modelImageInputRequired ? true : selectedModelForPromptImages !== null && (providerComposerOptions?.models.find(
6416
6511
  (option) => option.value === selectedModelForPromptImages
6417
6512
  )?.supportsImageInput ?? false);
6418
- const composerSupport = useMemo6(() => {
6513
+ const composerSupport = useMemo7(() => {
6419
6514
  const fallback = composerSettingsSupportFromOptions(
6420
6515
  providerComposerOptions,
6421
6516
  sessionCapabilities
@@ -6430,6 +6525,11 @@ function useAgentGUIComposerCapabilities(input) {
6430
6525
  planImplementation: sessionCapabilities?.planImplementation ?? fallback.planImplementation
6431
6526
  };
6432
6527
  }, [providerComposerOptions, sessionCapabilities]);
6528
+ const usageSource = input.activeEngineSession?.usage ?? null;
6529
+ const usage = useMemo7(
6530
+ () => resolveAgentActivityUsage({ sessionUsage: usageSource }),
6531
+ [usageSource]
6532
+ );
6433
6533
  return {
6434
6534
  backgroundAgentCount: input.activeEngineSession?.backgroundAgents?.count ?? 0,
6435
6535
  compactSupported: sessionCapabilities?.compact ?? resolveAgentActivityCapability2("compact", {
@@ -6446,9 +6546,7 @@ function useAgentGUIComposerCapabilities(input) {
6446
6546
  }) ?? false,
6447
6547
  promptImagesSupported: (resolvedPromptImagesSupported ?? true) && selectedModelImageInputSupported,
6448
6548
  providerComposerOptions,
6449
- usage: resolveAgentActivityUsage({
6450
- sessionUsage: input.activeEngineSession?.usage ?? null
6451
- })
6549
+ usage
6452
6550
  };
6453
6551
  }
6454
6552
 
@@ -7136,7 +7234,10 @@ function useAgentGUIContinueConversation(input) {
7136
7234
  runtime: current.agentActivityRuntime,
7137
7235
  workspaceId: current.workspaceId
7138
7236
  });
7139
- if (!isPendingNewConversationActivation(current.activePendingActivation)) {
7237
+ if (!isPendingNewConversationActivationForSession(
7238
+ current.activePendingActivation,
7239
+ currentConversationId
7240
+ )) {
7140
7241
  void current.unactivate(currentConversationId);
7141
7242
  }
7142
7243
  current.setIntent({ tag: "home" });
@@ -7554,7 +7655,10 @@ function useAgentGUIConversationHome({
7554
7655
  runtime: agentActivityRuntime,
7555
7656
  workspaceId
7556
7657
  });
7557
- if (previous && !isPendingNewConversationActivation(activePendingActivation)) {
7658
+ if (previous && !isPendingNewConversationActivationForSession(
7659
+ activePendingActivation,
7660
+ previous
7661
+ )) {
7558
7662
  void unactivate(previous);
7559
7663
  }
7560
7664
  setIntent({ tag: "home" });
@@ -8812,12 +8916,12 @@ function useAgentGUIOperationActions(input) {
8812
8916
  }
8813
8917
 
8814
8918
  // agent-gui/agentGuiNode/controller/useAgentGUIViewAssembly.ts
8815
- import { useMemo as useMemo13 } from "react";
8919
+ import { useMemo as useMemo14 } from "react";
8816
8920
 
8817
8921
  // agent-gui/agentGuiNode/model/useAgentGUIViewModel.ts
8818
- import { useMemo as useMemo7 } from "react";
8922
+ import { useMemo as useMemo8 } from "react";
8819
8923
  function useAgentGUIViewModel(candidate) {
8820
- const shell = useMemo7(
8924
+ const shell = useMemo8(
8821
8925
  () => candidate.shell,
8822
8926
  [
8823
8927
  candidate.shell.currentUserId,
@@ -8826,7 +8930,7 @@ function useAgentGUIViewModel(candidate) {
8826
8930
  candidate.shell.workspacePath
8827
8931
  ]
8828
8932
  );
8829
- const rail = useMemo7(
8933
+ const rail = useMemo8(
8830
8934
  () => candidate.rail,
8831
8935
  [
8832
8936
  candidate.rail.activeConversation,
@@ -8843,7 +8947,7 @@ function useAgentGUIViewModel(candidate) {
8843
8947
  candidate.rail.userProjects
8844
8948
  ]
8845
8949
  );
8846
- const detail = useMemo7(
8950
+ const detail = useMemo8(
8847
8951
  () => candidate.detail,
8848
8952
  [
8849
8953
  candidate.detail.availability,
@@ -8858,7 +8962,7 @@ function useAgentGUIViewModel(candidate) {
8858
8962
  candidate.detail.usage
8859
8963
  ]
8860
8964
  );
8861
- const composer = useMemo7(
8965
+ const composer = useMemo8(
8862
8966
  () => candidate.composer,
8863
8967
  [
8864
8968
  candidate.composer.availableCommands,
@@ -8881,7 +8985,7 @@ function useAgentGUIViewModel(candidate) {
8881
8985
  candidate.composer.queuedPrompts
8882
8986
  ]
8883
8987
  );
8884
- const interaction = useMemo7(
8988
+ const interaction = useMemo8(
8885
8989
  () => candidate.interaction,
8886
8990
  [
8887
8991
  candidate.interaction.inlineNotice,
@@ -8891,7 +8995,7 @@ function useAgentGUIViewModel(candidate) {
8891
8995
  candidate.interaction.sessionChrome
8892
8996
  ]
8893
8997
  );
8894
- const readiness = useMemo7(
8998
+ const readiness = useMemo8(
8895
8999
  () => candidate.readiness,
8896
9000
  [
8897
9001
  candidate.readiness.activationError,
@@ -8900,7 +9004,7 @@ function useAgentGUIViewModel(candidate) {
8900
9004
  candidate.readiness.providerReadinessGate
8901
9005
  ]
8902
9006
  );
8903
- const operations = useMemo7(
9007
+ const operations = useMemo8(
8904
9008
  () => candidate.operations,
8905
9009
  [
8906
9010
  candidate.operations.isDeletingConversation,
@@ -8909,7 +9013,7 @@ function useAgentGUIViewModel(candidate) {
8909
9013
  candidate.operations.pendingDeleteProjectConversations
8910
9014
  ]
8911
9015
  );
8912
- return useMemo7(
9016
+ return useMemo8(
8913
9017
  () => ({
8914
9018
  shell,
8915
9019
  rail,
@@ -8924,7 +9028,7 @@ function useAgentGUIViewModel(candidate) {
8924
9028
  }
8925
9029
 
8926
9030
  // agent-gui/agentGuiNode/controller/useAgentGUIComposerPresentation.ts
8927
- import { useEffect as useEffect8, useMemo as useMemo8 } from "react";
9031
+ import { useEffect as useEffect8, useMemo as useMemo9 } from "react";
8928
9032
 
8929
9033
  // agent-gui/agentGuiNode/model/agentBrowserUseSubmit.ts
8930
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.";
@@ -9446,7 +9550,7 @@ function useAgentGUIComposerPresentation(input) {
9446
9550
  const draftSpeed = normalizeOptionalText(
9447
9551
  draftSettings.speed
9448
9552
  );
9449
- const activeSessionReasoningSelection = useMemo8(
9553
+ const activeSessionReasoningSelection = useMemo9(
9450
9554
  () => reasoningSelectionFromComposerOptions(
9451
9555
  input.providerComposerOptions,
9452
9556
  draftReasoningEffort,
@@ -9454,21 +9558,22 @@ function useAgentGUIComposerPresentation(input) {
9454
9558
  ),
9455
9559
  [draftModel, draftReasoningEffort, input.providerComposerOptions]
9456
9560
  );
9457
- const activeSessionModelSelection = useMemo8(
9561
+ const presentedReasoningEffort = activeSessionReasoningSelection ? activeSessionReasoningSelection.currentValue : draftReasoningEffort;
9562
+ const activeSessionModelSelection = useMemo9(
9458
9563
  () => modelSelectionFromComposerOptions(
9459
9564
  input.providerComposerOptions,
9460
9565
  draftModel
9461
9566
  ),
9462
9567
  [draftModel, input.providerComposerOptions]
9463
9568
  );
9464
- const activeSessionSpeedSelection = useMemo8(
9569
+ const activeSessionSpeedSelection = useMemo9(
9465
9570
  () => speedSelectionFromComposerOptions(
9466
9571
  input.providerComposerOptions,
9467
9572
  draftSpeed
9468
9573
  ),
9469
9574
  [draftSpeed, input.providerComposerOptions]
9470
9575
  );
9471
- const composerSettings = useMemo8(() => {
9576
+ const composerSettings = useMemo9(() => {
9472
9577
  const permissionConfig = permissionConfigFromComposerOptions(
9473
9578
  input.providerComposerOptions
9474
9579
  );
@@ -9482,7 +9587,7 @@ function useAgentGUIComposerPresentation(input) {
9482
9587
  sessionSettings,
9483
9588
  draftSettings: {
9484
9589
  model: draftModel,
9485
- reasoningEffort: draftReasoningEffort,
9590
+ reasoningEffort: presentedReasoningEffort,
9486
9591
  speed: draftSpeed,
9487
9592
  planMode: Boolean(draftSettings.planMode),
9488
9593
  browserUse: draftSettings.browserUse ?? true,
@@ -9515,7 +9620,7 @@ function useAgentGUIComposerPresentation(input) {
9515
9620
  speedUnavailable: input.activeConversationId !== null && sessionSettings === null && input.composerSupport.speed && draftSpeed === null,
9516
9621
  permissionModeUnavailable: input.activeConversationId !== null && sessionSettings === null && supportsPermissionMode && selectedPermissionModeValue === null,
9517
9622
  selectedModelValue: draftModel,
9518
- selectedReasoningEffortValue: activeSessionReasoningSelection?.currentValue ?? draftReasoningEffort,
9623
+ selectedReasoningEffortValue: presentedReasoningEffort,
9519
9624
  selectedSpeedValue: draftSpeed,
9520
9625
  selectedPermissionModeValue,
9521
9626
  permissionConfig,
@@ -9544,6 +9649,7 @@ function useAgentGUIComposerPresentation(input) {
9544
9649
  input.composerTargetProvider,
9545
9650
  input.providerComposerOptions,
9546
9651
  input.selectedProjectPath,
9652
+ presentedReasoningEffort,
9547
9653
  sessionSettings
9548
9654
  ]);
9549
9655
  return {
@@ -9557,7 +9663,7 @@ function useAgentGUIComposerPresentation(input) {
9557
9663
  }
9558
9664
 
9559
9665
  // agent-gui/agentGuiNode/controller/useAgentGUIControllerActions.ts
9560
- import { useMemo as useMemo9 } from "react";
9666
+ import { useMemo as useMemo10 } from "react";
9561
9667
  function useAgentGUIControllerActions(actions) {
9562
9668
  const updateConversationFilter = useStableControllerEventCallback(
9563
9669
  actions.updateConversationFilter
@@ -9643,7 +9749,7 @@ function useAgentGUIControllerActions(actions) {
9643
9749
  const confirmDeleteConversation = useStableControllerEventCallback(
9644
9750
  actions.confirmDeleteConversation
9645
9751
  );
9646
- return useMemo9(
9752
+ return useMemo10(
9647
9753
  () => ({
9648
9754
  updateConversationFilter,
9649
9755
  selectConversationFilterTarget,
@@ -9715,13 +9821,13 @@ function useAgentGUIControllerActions(actions) {
9715
9821
  import {
9716
9822
  selectEngineAvailableCommands
9717
9823
  } from "@tutti-os/agent-activity-core";
9718
- 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";
9719
9825
  function useAgentGUIConversationDetail(input) {
9720
9826
  const projectionConversationRef = useRef10(null);
9721
9827
  const activeCanonicalLiveTurn = Boolean(
9722
9828
  input.activeTurn && input.activeTurn.phase !== "settled"
9723
9829
  );
9724
- const projectionConversation = useMemo10(() => {
9830
+ const projectionConversation = useMemo11(() => {
9725
9831
  if (!input.activeConversation) {
9726
9832
  projectionConversationRef.current = null;
9727
9833
  return null;
@@ -9754,17 +9860,17 @@ function useAgentGUIConversationDetail(input) {
9754
9860
  input.sessionEngine,
9755
9861
  (state) => selectEngineAvailableCommands(state, input.activeConversationId)
9756
9862
  );
9757
- const availableCommands = useMemo10(
9863
+ const availableCommands = useMemo11(
9758
9864
  () => (engineAvailableCommands.length > 0 ? engineAvailableCommands : input.providerComposerOptions?.commands ?? []).map((command) => ({ ...command })),
9759
- [engineAvailableCommands, input.providerComposerOptions]
9865
+ [engineAvailableCommands, input.providerComposerOptions?.commands]
9760
9866
  );
9761
9867
  const availableSkills = useStableProviderSkillOptions(
9762
- useMemo10(
9868
+ useMemo11(
9763
9869
  () => providerSkillsFromComposerOptions(input.providerComposerOptions),
9764
9870
  [input.providerComposerOptions]
9765
9871
  )
9766
9872
  );
9767
- const conversationModels = useMemo10(
9873
+ const conversationModels = useMemo11(
9768
9874
  () => projectionConversation ? buildAgentGUIConversationModels({
9769
9875
  timelineItems: input.activeTimelineItems,
9770
9876
  conversation: projectionConversation,
@@ -9781,7 +9887,7 @@ function useAgentGUIConversationDetail(input) {
9781
9887
  const conversationDetail = useStableConversationDetail(
9782
9888
  conversationModels.detail
9783
9889
  );
9784
- const conversation = useMemo10(() => {
9890
+ const conversation = useMemo11(() => {
9785
9891
  if (!conversationModels.conversation) return null;
9786
9892
  if (conversationDetail && (conversationModels.conversation.sourceDetail !== conversationDetail || conversationModels.conversation.activity !== conversationDetail.activity)) {
9787
9893
  return {
@@ -9843,20 +9949,23 @@ function useAgentGUIConversationDetail(input) {
9843
9949
  const activationError = input.errorFor(input.activeConversationId);
9844
9950
  const activationErrorCode = input.codeFor(input.activeConversationId);
9845
9951
  const hasProviderSessionNotFoundError = isNonRetryableResumeErrorCode(activationErrorCode);
9846
- const rawPendingApproval = useMemo10(() => {
9952
+ const rawPendingApproval = useMemo11(() => {
9847
9953
  const interaction = [...input.activePendingInteractions].reverse().find((candidate) => candidate.kind === "approval") ?? null;
9848
9954
  return interactiveApprovalFromInteraction(interaction);
9849
9955
  }, [input.activePendingInteractions]);
9850
- const rawPendingInteractivePrompt = useMemo10(() => {
9956
+ const rawPendingInteractivePrompt = useMemo11(() => {
9851
9957
  const interaction = [...input.activePendingInteractions].reverse().find((candidate) => candidate.kind !== "approval") ?? null;
9852
9958
  return interactivePromptFromInteraction(interaction);
9853
9959
  }, [input.activePendingInteractions]);
9854
- const queuedPrompts = input.activeConversationId ? input.activeQueuedPrompts.map((prompt) => ({
9855
- id: prompt.id,
9856
- content: [...prompt.content],
9857
- ...prompt.displayPrompt ? { displayPrompt: prompt.displayPrompt } : {},
9858
- createdAtUnixMs: prompt.createdAtUnixMs
9859
- })) : [];
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
+ );
9860
9969
  return {
9861
9970
  activeLiveState,
9862
9971
  activationError,
@@ -9880,19 +9989,54 @@ function useAgentGUIConversationDetail(input) {
9880
9989
  }
9881
9990
 
9882
9991
  // agent-gui/agentGuiNode/controller/useAgentGUIConversationPresentation.ts
9883
- 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";
9884
9993
  function useAgentGUIConversationPresentation(input) {
9885
- const activeConversation = useMemo11(() => {
9886
- const resolvedConversation = resolveConversationSummaryById(
9994
+ const visibleConversationsRef = useRef11(
9995
+ null
9996
+ );
9997
+ const conversationProjection = useMemo12(() => {
9998
+ const source = mergeVisibleConversations(
9887
9999
  input.conversations,
9888
- input.activeConversationId,
9889
10000
  input.transientConversation
9890
10001
  );
9891
- const resolved = resolvedConversation ? applyAgentGUIConversationProjects(
9892
- [resolvedConversation],
9893
- input.userProjects,
9894
- { isNoProjectPath: input.isNoProjectPath }
9895
- )[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
+ );
9896
10040
  if (resolved) {
9897
10041
  const activityDisplayStatus = input.activityDisplayStatuses.get(
9898
10042
  resolved.id
@@ -9902,9 +10046,11 @@ function useAgentGUIConversationPresentation(input) {
9902
10046
  );
9903
10047
  const hasCanonicalTerminalStatus = activityDisplayStatus === "completed" || activityDisplayStatus === "failed" || activityDisplayStatus === "canceled";
9904
10048
  const status = (input.isSubmitting || input.hasUnconfirmedSubmit ? "working" : hasCanonicalTerminalStatus ? activityDisplayStatus : activityBusyStatus2) ?? (resolved.status === "ready" && (input.activeLatestPendingSubmitTurnId || input.isSubmitting) ? "working" : resolved.status);
9905
- return status === resolved.status ? resolved : { ...resolved, status };
10049
+ return stabilize(
10050
+ status === resolved.status ? resolved : { ...resolved, status }
10051
+ );
9906
10052
  }
9907
- if (!input.activeConversationId) return null;
10053
+ if (!input.activeConversationId) return stabilize(null);
9908
10054
  const providerLabel = AGENT_PROVIDER_LABEL[input.data.provider] ?? input.data.provider ?? translate("sidebar.fallbackAgentLabel");
9909
10055
  const fallbackStatus = input.isSubmitting || input.isCreatingConversation || Object.prototype.hasOwnProperty.call(
9910
10056
  input.draftByScopeKey,
@@ -9915,8 +10061,9 @@ function useAgentGUIConversationPresentation(input) {
9915
10061
  const activityBusyStatus = conversationBusyStatusFromAgentActivityDisplayStatus(
9916
10062
  input.activityDisplayStatuses.get(input.activeConversationId)
9917
10063
  );
9918
- const fallbackUpdatedAtUnixMs = Date.now();
9919
- return {
10064
+ const previousActiveConversation = activeConversationRef.current?.[0];
10065
+ const fallbackUpdatedAtUnixMs = previousActiveConversation?.id === input.activeConversationId ? previousActiveConversation.updatedAtUnixMs : Date.now();
10066
+ return stabilize({
9920
10067
  id: input.activeConversationId,
9921
10068
  userId: input.currentUserId?.trim() || void 0,
9922
10069
  provider: input.data.provider,
@@ -9931,12 +10078,11 @@ function useAgentGUIConversationPresentation(input) {
9931
10078
  ),
9932
10079
  sortTimeUnixMs: fallbackUpdatedAtUnixMs,
9933
10080
  updatedAtUnixMs: fallbackUpdatedAtUnixMs
9934
- };
10081
+ });
9935
10082
  }, [
9936
10083
  input.activeConversationId,
9937
10084
  input.activeLatestPendingSubmitTurnId,
9938
10085
  input.activityDisplayStatuses,
9939
- input.conversations,
9940
10086
  input.currentUserId,
9941
10087
  input.data.provider,
9942
10088
  input.draftByScopeKey,
@@ -9944,8 +10090,8 @@ function useAgentGUIConversationPresentation(input) {
9944
10090
  input.isCreatingConversation,
9945
10091
  input.isNoProjectPath,
9946
10092
  input.isSubmitting,
9947
- input.transientConversation,
9948
10093
  input.userProjects,
10094
+ conversationProjection.semanticConversations,
9949
10095
  input.workspacePath
9950
10096
  ]);
9951
10097
  useEffect10(() => {
@@ -10001,36 +10147,6 @@ function useAgentGUIConversationPresentation(input) {
10001
10147
  input.shouldUseStaticProviderTargets,
10002
10148
  input.transientConversation
10003
10149
  ]);
10004
- const visibleConversationsRef = useRef11(
10005
- null
10006
- );
10007
- const visibleConversations = useMemo11(() => {
10008
- const source = mergeVisibleConversations(
10009
- input.conversations,
10010
- input.transientConversation
10011
- );
10012
- const mapped = source.map((conversation) => {
10013
- const activityBusyStatus = conversationBusyStatusFromAgentActivityDisplayStatus(
10014
- input.activityDisplayStatuses.get(conversation.id)
10015
- );
10016
- return activityBusyStatus && conversation.status !== activityBusyStatus ? { ...conversation, status: activityBusyStatus } : conversation;
10017
- });
10018
- const next = applyAgentGUIConversationProjects(mapped, input.userProjects, {
10019
- isNoProjectPath: input.isNoProjectPath
10020
- });
10021
- const stableNext = stableConversationSummaryList(
10022
- visibleConversationsRef.current,
10023
- next
10024
- );
10025
- visibleConversationsRef.current = stableNext;
10026
- return stableNext;
10027
- }, [
10028
- input.activityDisplayStatuses,
10029
- input.conversations,
10030
- input.isNoProjectPath,
10031
- input.transientConversation,
10032
- input.userProjects
10033
- ]);
10034
10150
  return { activeConversation, visibleConversations };
10035
10151
  }
10036
10152
 
@@ -10133,8 +10249,9 @@ function useAgentGUIProviderHome(input) {
10133
10249
  );
10134
10250
  }
10135
10251
  const previous = currentInput.activeConversationIdRef.current;
10136
- if (previous && !isPendingNewConversationActivation(
10137
- currentInput.activePendingActivation
10252
+ if (previous && !isPendingNewConversationActivationForSession(
10253
+ currentInput.activePendingActivation,
10254
+ previous
10138
10255
  )) {
10139
10256
  void currentInput.unactivate(previous);
10140
10257
  }
@@ -10291,7 +10408,7 @@ import {
10291
10408
  selectPlanDecisionForTurn,
10292
10409
  selectPlanTurnDismissed
10293
10410
  } from "@tutti-os/agent-activity-core";
10294
- import { useEffect as useEffect12, useMemo as useMemo12 } from "react";
10411
+ import { useEffect as useEffect12, useMemo as useMemo13 } from "react";
10295
10412
  function useAgentGUISessionPresentation(input) {
10296
10413
  const latestTimelinePlanTurnId = latestPlanTurnId(input.activeTimelineItems);
10297
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;
@@ -10344,7 +10461,14 @@ function useAgentGUISessionPresentation(input) {
10344
10461
  const activeSessionResumable = input.activeEngineSession?.resumable ?? input.activeConversation?.resumable ?? input.activeSessionState?.resumable;
10345
10462
  const activeConversationRequiresResume = input.activeConversationId !== null && input.activationState !== "active";
10346
10463
  const activeConversationResumeUnavailable = activeConversationRequiresResume && activeSessionResumable === false;
10347
- 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(() => {
10348
10472
  const normalizedError = input.activationError?.trim() ?? "";
10349
10473
  const authState = input.activeSessionState?.authState?.trim() ?? "";
10350
10474
  const providerSessionMissing = isNonRetryableResumeErrorCode(
@@ -10372,7 +10496,7 @@ function useAgentGUISessionPresentation(input) {
10372
10496
  message: recoveryMessage,
10373
10497
  canRetry: !providerSessionMissing
10374
10498
  } : null,
10375
- rawState: input.activeEngineSession
10499
+ rawState: sessionChromeRawState
10376
10500
  };
10377
10501
  }, [
10378
10502
  activeConversationResumeUnavailable,
@@ -10380,11 +10504,11 @@ function useAgentGUISessionPresentation(input) {
10380
10504
  input.activationError,
10381
10505
  input.activationErrorCode,
10382
10506
  input.activeConversationId,
10383
- input.activeEngineSession,
10384
10507
  input.activeLiveState,
10385
10508
  input.activeSessionState,
10386
10509
  input.activePendingActivation?.mode,
10387
- input.pendingApproval
10510
+ input.pendingApproval,
10511
+ sessionChromeRawState
10388
10512
  ]);
10389
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;
10390
10514
  const canQueueWhileBusy = input.activeConversationId !== null && (activeConversationBusy || input.isSubmitting || input.activeEngineHasPendingInteractions);
@@ -10482,15 +10606,24 @@ function useAgentGUISessionPresentation(input) {
10482
10606
  // agent-gui/agentGuiNode/controller/useAgentGUIViewAssembly.ts
10483
10607
  function useAgentGUIViewAssembly(input) {
10484
10608
  const { activeConversation, visibleConversations } = useAgentGUIConversationPresentation(input);
10485
- const detail = useAgentGUIConversationDetail({
10486
- ...input,
10487
- activeConversation,
10488
- activeSessionView: input.activeSessionView ? {
10609
+ const stableActiveSessionViewProjection = useMemo14(
10610
+ () => input.activeSessionView ? {
10489
10611
  hasOlderMessages: input.activeSessionView.hasOlderMessages,
10490
10612
  isLoadingOlderMessages: input.activeSessionView.isLoadingOlderMessages,
10491
10613
  olderMessageCount: input.activeSessionView.olderMessages.length,
10492
10614
  oldestLoadedVersion: input.activeSessionView.oldestLoadedVersion
10493
- } : 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
10494
10627
  });
10495
10628
  const { stableComposerSettings } = useAgentGUIComposerPresentation({
10496
10629
  ...input,
@@ -10532,7 +10665,7 @@ function useAgentGUIViewAssembly(input) {
10532
10665
  comingSoonProviders: input.normalizedComingSoonProviders,
10533
10666
  conversationFilter: input.conversationFilter,
10534
10667
  conversations: visibleConversations,
10535
- userProjects: [...input.userProjects],
10668
+ userProjects: input.userProjects,
10536
10669
  activeConversation,
10537
10670
  activeConversationId: input.activeConversationId,
10538
10671
  isLoadingConversations: input.isLoadingConversations,
@@ -10595,14 +10728,14 @@ function useAgentGUIViewAssembly(input) {
10595
10728
  pendingDeleteProjectConversations: input.pendingDeleteProjectConversations
10596
10729
  }
10597
10730
  });
10598
- return useMemo13(
10731
+ return useMemo14(
10599
10732
  () => ({ viewModel, actions: controllerActions }),
10600
10733
  [controllerActions, viewModel]
10601
10734
  );
10602
10735
  }
10603
10736
 
10604
10737
  // agent-gui/agentGuiNode/controller/useAgentGUIProviderCatalogSelection.ts
10605
- 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";
10606
10739
  function useAgentGUIProviderCatalogSelection(input) {
10607
10740
  const {
10608
10741
  comingSoonProviders,
@@ -10613,12 +10746,12 @@ function useAgentGUIProviderCatalogSelection(input) {
10613
10746
  agentTargets,
10614
10747
  agentTargetsLoading
10615
10748
  } = input;
10616
- const normalizedComingSoonProviders = useMemo14(
10749
+ const normalizedComingSoonProviders = useMemo15(
10617
10750
  () => comingSoonProviders && comingSoonProviders.length > 0 ? [...comingSoonProviders] : emptyComingSoonProviders,
10618
10751
  [comingSoonProviders]
10619
10752
  );
10620
10753
  const isExactProviderRailMode = providerRailMode === "exact";
10621
- const normalizedExplicitProviderTargets = useMemo14(() => {
10754
+ const normalizedExplicitProviderTargets = useMemo15(() => {
10622
10755
  const normalized = normalizeAgentGUIAgentTargets(agentTargets, {
10623
10756
  includeDisabledPlaceholders: !isExactProviderRailMode,
10624
10757
  useStaticCatalog: false
@@ -10628,7 +10761,7 @@ function useAgentGUIProviderCatalogSelection(input) {
10628
10761
  normalizedComingSoonProviders
10629
10762
  );
10630
10763
  }, [isExactProviderRailMode, normalizedComingSoonProviders, agentTargets]);
10631
- const normalizedProviderTargets = useMemo14(() => {
10764
+ const normalizedProviderTargets = useMemo15(() => {
10632
10765
  if (agentTargetsLoading) return [];
10633
10766
  if (!isExactProviderRailMode && (agentTargets === void 0 || normalizedExplicitProviderTargets.length === 0)) {
10634
10767
  return applyComingSoonProviderTargets(
@@ -10647,13 +10780,13 @@ function useAgentGUIProviderCatalogSelection(input) {
10647
10780
  agentTargetsLoading
10648
10781
  ]);
10649
10782
  const shouldUseStaticProviderTargets = !isExactProviderRailMode && !agentTargetsLoading && (agentTargets === void 0 || normalizedExplicitProviderTargets.length === 0);
10650
- const handoffAgentTargets = useMemo14(
10783
+ const handoffAgentTargets = useMemo15(
10651
10784
  () => agentTargetsLoading ? [] : normalizedExplicitProviderTargets.filter(
10652
10785
  (target) => target.disabled !== true
10653
10786
  ),
10654
10787
  [normalizedExplicitProviderTargets, agentTargetsLoading]
10655
10788
  );
10656
- const selectedAgentTarget = useMemo14(
10789
+ const selectedAgentTarget = useMemo15(
10657
10790
  () => resolveAgentGUIAgentTarget({
10658
10791
  agentTargetId: data.agentTargetId,
10659
10792
  defaultAgentTargetId,
@@ -10675,14 +10808,14 @@ function useAgentGUIProviderCatalogSelection(input) {
10675
10808
  shouldUseStaticProviderTargets
10676
10809
  ]
10677
10810
  );
10678
- const selectedAgentTargetIsExplicit = useMemo14(
10811
+ const selectedAgentTargetIsExplicit = useMemo15(
10679
10812
  () => normalizedExplicitProviderTargets.some(
10680
10813
  (target) => target.provider === selectedAgentTarget.provider && target.targetId === selectedAgentTarget.targetId && agentGUIAgentTargetRefsEqual(target.ref, selectedAgentTarget.ref)
10681
10814
  ),
10682
10815
  [normalizedExplicitProviderTargets, selectedAgentTarget]
10683
10816
  );
10684
10817
  const [homeComposerTargetOverride, setHomeComposerTargetOverride] = useState4(null);
10685
- const homeComposerTargetOverrideIsExplicit = useMemo14(
10818
+ const homeComposerTargetOverrideIsExplicit = useMemo15(
10686
10819
  () => homeComposerTargetOverride ? normalizedExplicitProviderTargets.some(
10687
10820
  (target) => target.provider === homeComposerTargetOverride.provider && target.targetId === homeComposerTargetOverride.targetId && agentGUIAgentTargetRefsEqual(
10688
10821
  target.ref,
@@ -10692,14 +10825,14 @@ function useAgentGUIProviderCatalogSelection(input) {
10692
10825
  [homeComposerTargetOverride, normalizedExplicitProviderTargets]
10693
10826
  );
10694
10827
  const effectiveSelectedProviderTarget = homeComposerTargetOverride ?? selectedAgentTarget;
10695
- const firstReadyHomeComposerProviderTarget = useMemo14(
10828
+ const firstReadyHomeComposerProviderTarget = useMemo15(
10696
10829
  () => providerReadinessGates ? normalizedProviderTargets.find(
10697
10830
  (target) => target.disabled !== true && providerReadinessGates[target.provider] === null
10698
10831
  ) ?? null : null,
10699
10832
  [normalizedProviderTargets, providerReadinessGates]
10700
10833
  );
10701
10834
  const nodeComposerTargetResolvedByProviderTarget = agentGUINodeDataHasComposerTarget(data) && normalizeOptionalText(data.agentTargetId) !== null && selectedAgentTarget.agentTargetId === normalizeOptionalText(data.agentTargetId);
10702
- const selectedComposerTargetData = useMemo14(
10835
+ const selectedComposerTargetData = useMemo15(
10703
10836
  () => homeComposerTargetOverride ? composerTargetDataFromProviderTarget({
10704
10837
  current: data,
10705
10838
  isExplicit: homeComposerTargetOverrideIsExplicit,
@@ -10771,7 +10904,7 @@ import {
10771
10904
  selectSessionHasUnconfirmedSubmit,
10772
10905
  selectSessionIsSubmitting
10773
10906
  } from "@tutti-os/agent-activity-core";
10774
- import { useMemo as useMemo15 } from "react";
10907
+ import { useMemo as useMemo16 } from "react";
10775
10908
 
10776
10909
  // agent-gui/agentGuiNode/controller/agentGuiQueueStatus.ts
10777
10910
  function agentGUIQueueStatusFromPromptQueue(record) {
@@ -10785,9 +10918,12 @@ function useAgentGUISessionEngineState(input) {
10785
10918
  sessionEngine,
10786
10919
  (state) => selectEnginePromptQueue(state, activeConversationId)
10787
10920
  );
10788
- const activeQueuedPrompts = activeQueuedPromptSnapshot?.prompts.filter(
10789
- (prompt) => prompt.visibleInQueue !== false && prompt.id !== activeQueuedPromptSnapshot.inFlight?.promptId && prompt.id !== activeQueuedPromptSnapshot.sendNextPromptId
10790
- ) ?? 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
+ );
10791
10927
  const activePendingSubmits = useEngineSelector(
10792
10928
  sessionEngine,
10793
10929
  (state) => selectPendingSubmitsForSession3(state, activeConversationId),
@@ -10839,7 +10975,7 @@ function useAgentGUISessionEngineState(input) {
10839
10975
  sessionEngine,
10840
10976
  (state) => selectEngineLatestTurn(state, activeConversationId)
10841
10977
  );
10842
- const activeCanonicalComposerSettings = useMemo15(
10978
+ const activeCanonicalComposerSettings = useMemo16(
10843
10979
  () => ({
10844
10980
  model: activeEngineSession?.settings?.model ?? void 0,
10845
10981
  permissionModeId: activeEngineSession?.settings?.permissionModeId ?? void 0,
@@ -10850,7 +10986,7 @@ function useAgentGUISessionEngineState(input) {
10850
10986
  }),
10851
10987
  [activeEngineSession?.settings]
10852
10988
  );
10853
- const activeSessionState = useMemo15(() => {
10989
+ const activeSessionState = useMemo16(() => {
10854
10990
  if (!activeEngineSession) return null;
10855
10991
  return {
10856
10992
  workspaceId: activeEngineSession.workspaceId,
@@ -10938,7 +11074,7 @@ function useAgentGUISessionEngineState(input) {
10938
11074
  import {
10939
11075
  selectLatestActivationForSession as selectLatestActivationForSession5
10940
11076
  } from "@tutti-os/agent-activity-core";
10941
- import { useCallback as useCallback23, useMemo as useMemo16 } from "react";
11077
+ import { useCallback as useCallback23, useMemo as useMemo17 } from "react";
10942
11078
 
10943
11079
  // contexts/workspace/presentation/renderer/agentSessions/useAgentSessionControllerState.ts
10944
11080
  import { useCallback as useCallback22 } from "react";
@@ -11121,7 +11257,7 @@ function useAgentSessionControllerState(activeRef, canonicalMessages = []) {
11121
11257
  const canonicalOldestVersion = oldestVersion2(canonicalMessages);
11122
11258
  const activeSessionView = storedActiveView ? {
11123
11259
  ...storedActiveView,
11124
- hasOlderMessages: storedActiveView.hasOlderMessages || canonicalOldestVersion !== null && canonicalOldestVersion > 1,
11260
+ hasOlderMessages: storedActiveView.hasOlderMessages || storedActiveView.oldestLoadedVersion === null && canonicalOldestVersion !== null && canonicalOldestVersion > 1,
11125
11261
  oldestLoadedVersion: storedActiveView.oldestLoadedVersion === null ? canonicalOldestVersion : canonicalOldestVersion === null ? storedActiveView.oldestLoadedVersion : Math.min(
11126
11262
  storedActiveView.oldestLoadedVersion,
11127
11263
  canonicalOldestVersion
@@ -11193,7 +11329,7 @@ function useAgentGUISessionDetailTransport(input) {
11193
11329
  loadSessionState,
11194
11330
  reconcileSessionDetail,
11195
11331
  refreshMessagesFromSnapshot
11196
- } = useMemo16(() => {
11332
+ } = useMemo17(() => {
11197
11333
  const reconcileSession = (agentSessionId, scope) => {
11198
11334
  const normalized = agentSessionId.trim();
11199
11335
  if (!normalized) return;
@@ -11369,7 +11505,7 @@ function useAgentGUINodeController({
11369
11505
  }) {
11370
11506
  const agentActivityRuntime = useAgentActivityRuntime();
11371
11507
  const agentActivityRuntimeOrigin = agentActivityRuntime.origin?.trim() || AGENT_GUI_RUNTIME_SESSION_ORIGIN;
11372
- const sessionEngine = useMemo17(() => {
11508
+ const sessionEngine = useMemo18(() => {
11373
11509
  const engine = agentActivityRuntime.getSessionEngine(workspaceId);
11374
11510
  if (engine.identity.workspaceId !== workspaceId || engine.identity.origin !== agentActivityRuntimeOrigin) {
11375
11511
  throw new Error(
@@ -11557,7 +11693,7 @@ function useAgentGUINodeController({
11557
11693
  storedMessages: storedActiveMessages,
11558
11694
  workspaceId
11559
11695
  });
11560
- const transientConversation = useMemo17(() => {
11696
+ const transientConversation = useMemo18(() => {
11561
11697
  const session = activeEngineSession;
11562
11698
  if (!session || session.visible === false || conversations.some(
11563
11699
  (conversation) => conversation.id === session.agentSessionId
@@ -11734,7 +11870,6 @@ function useAgentGUINodeController({
11734
11870
  selectConversation,
11735
11871
  sessionEngine,
11736
11872
  setIntent,
11737
- syncConversationListProjection,
11738
11873
  transientConversation,
11739
11874
  workspaceId
11740
11875
  });
@@ -11860,9 +11995,9 @@ function useAgentGUINodeController({
11860
11995
  // agent-gui/agentGuiNode/AgentGUINodeView.tsx
11861
11996
  import {
11862
11997
  useCallback as useCallback48,
11863
- useEffect as useEffect36,
11864
- useMemo as useMemo36,
11865
- useRef as useRef39,
11998
+ useEffect as useEffect37,
11999
+ useMemo as useMemo37,
12000
+ useRef as useRef41,
11866
12001
  useState as useState34
11867
12002
  } from "react";
11868
12003
  import {
@@ -12104,7 +12239,7 @@ var styles = {
12104
12239
  var AgentGUINode_styles_default = styles;
12105
12240
 
12106
12241
  // agent-gui/agentGuiNode/view/agentGUIViewUtils.ts
12107
- 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";
12108
12243
  function objectRecord(value) {
12109
12244
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
12110
12245
  }
@@ -12133,7 +12268,7 @@ function useOptionalStableEventCallback(callback) {
12133
12268
  useLayoutEffect(() => {
12134
12269
  callbackRef.current = callback;
12135
12270
  }, [callback]);
12136
- return useMemo18(() => {
12271
+ return useMemo19(() => {
12137
12272
  if (callback == null) {
12138
12273
  return void 0;
12139
12274
  }
@@ -12755,7 +12890,7 @@ function AgentGUIConfigMenu({
12755
12890
  import {
12756
12891
  memo as memo4,
12757
12892
  useCallback as useCallback40,
12758
- useMemo as useMemo29,
12893
+ useMemo as useMemo30,
12759
12894
  useRef as useRef31,
12760
12895
  useState as useState24
12761
12896
  } from "react";
@@ -12980,7 +13115,7 @@ function changeAgentGUIProviderManagerVisibility(input) {
12980
13115
  }
12981
13116
 
12982
13117
  // agent-gui/agentGuiNode/view/AgentGUIEmptyState.tsx
12983
- import { memo as memo3, useMemo as useMemo28 } from "react";
13118
+ import { memo as memo3, useMemo as useMemo29 } from "react";
12984
13119
  import {
12985
13120
  Select as Select3,
12986
13121
  SelectContent as SelectContent3,
@@ -13172,7 +13307,7 @@ var RECORD_FADE_CURVE = 1.45;
13172
13307
  var RECORD_EDGE_KILL_START_SLOTS = 1.2;
13173
13308
  var RECORD_EDGE_KILL_END_SLOTS = 2.05;
13174
13309
  var SPRING_STIFFNESS = 120;
13175
- var SPRING_DAMPING_RATIO = 0.78;
13310
+ var SPRING_DAMPING_RATIO = 0.92;
13176
13311
  var SPRING_MIN_LAUNCH_VELOCITY = 2.6;
13177
13312
  var SPRING_SETTLE_EPSILON = 1e-3;
13178
13313
  var SPRING_SETTLE_VELOCITY = 0.02;
@@ -13357,7 +13492,7 @@ var AgentGuiHeroCarouselScene = class _AgentGuiHeroCarouselScene {
13357
13492
  this.renderer.setSize(width, height, false);
13358
13493
  this.camera.aspect = width / height;
13359
13494
  this.camera.updateProjectionMatrix();
13360
- this.requestRender();
13495
+ this.renderer.render(this.scene, this.camera);
13361
13496
  }
13362
13497
  // Agent index of the tile slot the wheel is heading to.
13363
13498
  targetIndex() {
@@ -14901,11 +15036,17 @@ function useComposerDraftAttachments({
14901
15036
  clearActiveFileMentionTrigger,
14902
15037
  onDraftContentChange,
14903
15038
  onPromptImagesUnsupported,
15039
+ onContentEntered,
14904
15040
  onRequestWorkspaceReferences,
14905
15041
  resolveDroppedFileReferences,
14906
15042
  onLinkAction
14907
15043
  }) {
14908
15044
  const agentActivityRuntime = useOptionalAgentActivityRuntime();
15045
+ const reportContentEntered = useStableEventCallback2(
15046
+ (contentType) => {
15047
+ onContentEntered?.(contentType);
15048
+ }
15049
+ );
14909
15050
  const publishScopedDraft = useStableEventCallback2(
14910
15051
  (sourceScopeKey, nextDraft) => {
14911
15052
  draftByScopeKeyRef.current[sourceScopeKey] = nextDraft;
@@ -15019,6 +15160,7 @@ function useComposerDraftAttachments({
15019
15160
  }));
15020
15161
  const nextDraftImages = [...currentDraftImages, ...nextImages];
15021
15162
  draftImagesRef.current = nextDraftImages;
15163
+ reportContentEntered("image");
15022
15164
  publishScopedDraft(
15023
15165
  draftScopeKey,
15024
15166
  buildAgentComposerDraft({
@@ -15116,6 +15258,7 @@ function useComposerDraftAttachments({
15116
15258
  onPromptImagesUnsupported,
15117
15259
  publishScopedDraft,
15118
15260
  promptImagesSupported,
15261
+ reportContentEntered,
15119
15262
  updateScopedDraft,
15120
15263
  workspaceId
15121
15264
  ]
@@ -15210,6 +15353,7 @@ ${item.text}` : item.text;
15210
15353
  if (!normalizedText.trim()) {
15211
15354
  return;
15212
15355
  }
15356
+ reportContentEntered("large_text");
15213
15357
  const stagePastedText = pastedTextStagingSupported ? agentActivityRuntime?.stagePastedText : void 0;
15214
15358
  const id = crypto.randomUUID();
15215
15359
  const name = `${AGENT_COMPOSER_PASTED_TEXT_FILE_PREFIX}.txt`;
@@ -15280,6 +15424,7 @@ ${item.text}` : item.text;
15280
15424
  draftScopeKey,
15281
15425
  pastedTextStagingSupported,
15282
15426
  publishScopedDraft,
15427
+ reportContentEntered,
15283
15428
  updateScopedDraft,
15284
15429
  workspaceId
15285
15430
  ]
@@ -15413,7 +15558,7 @@ ${item.text}` : item.text;
15413
15558
  // agent-gui/agentGuiNode/composer/useComposerLayout.ts
15414
15559
  import {
15415
15560
  useLayoutEffect as useLayoutEffect2,
15416
- useMemo as useMemo19
15561
+ useMemo as useMemo20
15417
15562
  } from "react";
15418
15563
  var DOCK_COMPOSER_INPUT_MIN_HEIGHT = 56;
15419
15564
  var DOCK_COMPOSER_TEXT_LINE_HEIGHT = 24;
@@ -15631,11 +15776,11 @@ function useComposerLayout({
15631
15776
  isHeroLayout,
15632
15777
  paletteDraftPrompt
15633
15778
  ]);
15634
- const inputShellStyle = useMemo19(
15779
+ const inputShellStyle = useMemo20(
15635
15780
  () => showFileMentionPalette || showFloatingCommandMenu ? { zIndex: COMPOSER_PALETTE_Z_INDEX } : void 0,
15636
15781
  [showFileMentionPalette, showFloatingCommandMenu]
15637
15782
  );
15638
- const promptInputAreaStyle = useMemo19(
15783
+ const promptInputAreaStyle = useMemo20(
15639
15784
  () => isHeroLayout ? void 0 : {
15640
15785
  "--agent-gui-composer-attachment-height": `${dockComposerAttachmentHeight}px`,
15641
15786
  "--agent-gui-composer-input-height": `${dockComposerInputHeight}px`,
@@ -15668,7 +15813,7 @@ function useComposerLayout({
15668
15813
  }
15669
15814
 
15670
15815
  // agent-gui/agentGuiNode/composer/useComposerPaletteCatalog.ts
15671
- import { useMemo as useMemo20 } from "react";
15816
+ import { useMemo as useMemo21 } from "react";
15672
15817
 
15673
15818
  // agent-gui/agentGuiNode/composer/slashCommandDisplay.ts
15674
15819
  function slashCommandDescriptionForDisplay(command, labels) {
@@ -15749,7 +15894,7 @@ function useComposerPaletteCatalog({
15749
15894
  const promptBeforeSelection = editorHandleRef.current?.getPromptTextBeforeSelection() ?? "";
15750
15895
  const skillQueryDraft = promptBeforeSelection || paletteDraftPrompt;
15751
15896
  const skillQueryMatch = getAgentComposerTriggerQueryMatch(skillQueryDraft);
15752
- const resolvedSlashCommands = useMemo20(
15897
+ const resolvedSlashCommands = useMemo21(
15753
15898
  () => resolveSlashCommandsForProvider({
15754
15899
  provider,
15755
15900
  policy: slashCommandPolicy,
@@ -15774,11 +15919,11 @@ function useComposerPaletteCatalog({
15774
15919
  slashCommandPolicy
15775
15920
  ]
15776
15921
  );
15777
- const filteredCommands = useMemo20(
15922
+ const filteredCommands = useMemo21(
15778
15923
  () => slashQuery === null ? [] : filterSlashCommands(resolvedSlashCommands, slashQuery),
15779
15924
  [resolvedSlashCommands, slashQuery]
15780
15925
  );
15781
- const filteredSkills = useMemo20(
15926
+ const filteredSkills = useMemo21(
15782
15927
  () => skillQueryMatch === null ? [] : filterProviderSkillsForTrigger({
15783
15928
  skills: availableSkills,
15784
15929
  query: skillQueryMatch.query,
@@ -15786,7 +15931,7 @@ function useComposerPaletteCatalog({
15786
15931
  }),
15787
15932
  [availableSkills, skillQueryMatch]
15788
15933
  );
15789
- const availableCapabilities = useMemo20(() => {
15934
+ const availableCapabilities = useMemo21(() => {
15790
15935
  const entries = [];
15791
15936
  if (composerSettings.supportsBrowser) {
15792
15937
  entries.push({
@@ -15811,7 +15956,7 @@ function useComposerPaletteCatalog({
15811
15956
  labels.browserUseCapabilityLabel,
15812
15957
  labels.computerUseCapabilityLabel
15813
15958
  ]);
15814
- const slashPaletteEntries = useMemo20(() => {
15959
+ const slashPaletteEntries = useMemo21(() => {
15815
15960
  const commandEntries = filteredCommands.flatMap((command) => {
15816
15961
  if (isSlashCommandCapability(command)) {
15817
15962
  const browserConnectionMode = capabilityMenuState?.browserUse?.connectionMode ?? null;
@@ -15914,7 +16059,7 @@ function useComposerPaletteCatalog({
15914
16059
  import {
15915
16060
  useCallback as useCallback30,
15916
16061
  useLayoutEffect as useLayoutEffect3,
15917
- useMemo as useMemo21,
16062
+ useMemo as useMemo22,
15918
16063
  useState as useState11
15919
16064
  } from "react";
15920
16065
 
@@ -16381,7 +16526,7 @@ function useMentionPaletteFrame(inputShellRef, showFileMentionPalette) {
16381
16526
  window.removeEventListener("scroll", syncMentionPaletteFrame, true);
16382
16527
  };
16383
16528
  }, [showFileMentionPalette, syncMentionPaletteFrame]);
16384
- const mentionPaletteStyle = useMemo21(
16529
+ const mentionPaletteStyle = useMemo22(
16385
16530
  () => ({
16386
16531
  position: "fixed",
16387
16532
  left: `${mentionPaletteFrame?.left ?? 0}px`,
@@ -16402,7 +16547,7 @@ function useMentionPaletteFrame(inputShellRef, showFileMentionPalette) {
16402
16547
  // agent-gui/agentGuiNode/composer/useComposerSlashActions.ts
16403
16548
  import {
16404
16549
  useCallback as useCallback31,
16405
- useMemo as useMemo22,
16550
+ useMemo as useMemo23,
16406
16551
  useRef as useRef21
16407
16552
  } from "react";
16408
16553
 
@@ -16500,7 +16645,7 @@ function useComposerSlashActions(input) {
16500
16645
  },
16501
16646
  [clearSlashCommandDraft, onSubmit]
16502
16647
  );
16503
- const reviewBranchLoader = useMemo22(() => {
16648
+ const reviewBranchLoader = useMemo23(() => {
16504
16649
  if (!onRequestGitBranches) {
16505
16650
  return null;
16506
16651
  }
@@ -17166,7 +17311,7 @@ function useComposerMentionActions(input) {
17166
17311
  }
17167
17312
 
17168
17313
  // agent-gui/agentGuiNode/composer/useComposerProviderTargets.ts
17169
- import { useMemo as useMemo23 } from "react";
17314
+ import { useMemo as useMemo24 } from "react";
17170
17315
  function useComposerProviderTargets(input) {
17171
17316
  const {
17172
17317
  layoutMode,
@@ -17190,7 +17335,7 @@ function useComposerProviderTargets(input) {
17190
17335
  };
17191
17336
  const isHeroLayout = layoutMode === "hero";
17192
17337
  const composerClassName = isHeroLayout ? AgentGUINode_styles_default.composerHero : AgentGUINode_styles_default.composer;
17193
- const providerSwitchTargets = useMemo23(
17338
+ const providerSwitchTargets = useMemo24(
17194
17339
  () => agentTargets.filter(Boolean),
17195
17340
  [agentTargets]
17196
17341
  );
@@ -17201,7 +17346,7 @@ function useComposerProviderTargets(input) {
17201
17346
  const providerMenuTargets = selectedProviderSwitchTarget && !providerSwitchTargets.some(
17202
17347
  (target) => target.targetId === selectedProviderSwitchTarget.targetId
17203
17348
  ) ? [selectedProviderSwitchTarget, ...providerSwitchTargets] : providerSwitchTargets;
17204
- const enabledHandoffProviderTargets = useMemo23(
17349
+ const enabledHandoffProviderTargets = useMemo24(
17205
17350
  () => (handoffAgentTargets ?? providerMenuTargets).filter(
17206
17351
  (target) => target.disabled !== true
17207
17352
  ),
@@ -19025,7 +19170,7 @@ function optionsWithSelectedValue(options, selectedValue) {
19025
19170
  }
19026
19171
 
19027
19172
  // agent-gui/agentGuiNode/AgentComposerProjectMenu.tsx
19028
- import { useMemo as useMemo24 } from "react";
19173
+ import { useMemo as useMemo25 } from "react";
19029
19174
  import { ChevronDown } from "lucide-react";
19030
19175
  import {
19031
19176
  WorkspaceUserProjectSelect,
@@ -19054,11 +19199,11 @@ function AgentProjectDropdown({
19054
19199
  }) {
19055
19200
  "use memo";
19056
19201
  const agentHostApi = useAgentHostApi();
19057
- const resolvedLabels = useMemo24(
19202
+ const resolvedLabels = useMemo25(
19058
19203
  () => resolveWorkspaceUserProjectSelectLabels(i18n, labels),
19059
19204
  [i18n, labels]
19060
19205
  );
19061
- const userProjectApi = useMemo24(
19206
+ const userProjectApi = useMemo25(
19062
19207
  () => !previewMode && agentHostApi.userProjects ? {
19063
19208
  ...agentHostApi.userProjects,
19064
19209
  selectDirectory: selectProjectDirectory ?? agentHostApi.workspace.selectDirectory
@@ -19666,7 +19811,7 @@ import {
19666
19811
  forwardRef as forwardRef3,
19667
19812
  useCallback as useCallback36,
19668
19813
  useEffect as useEffect24,
19669
- useMemo as useMemo25,
19814
+ useMemo as useMemo26,
19670
19815
  useRef as useRef25,
19671
19816
  useState as useState17
19672
19817
  } from "react";
@@ -19854,6 +19999,52 @@ function moveSelectionOverCaretAnchor(state, dispatch, key) {
19854
19999
  }
19855
20000
  return false;
19856
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
+ }
19857
20048
  function createAgentRichTextPlaceholderExtension(getPlaceholder) {
19858
20049
  return Extension.create({
19859
20050
  name: "agentRichTextPlaceholder",
@@ -19890,9 +20081,17 @@ function createAgentRichTextCaretAnchorExtension() {
19890
20081
  key: new PluginKey("agentRichTextCaretAnchor"),
19891
20082
  props: {
19892
20083
  handleKeyDown(view, event) {
19893
- 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) {
19894
20085
  return false;
19895
20086
  }
20087
+ if (deleteLineStartMentionWithCaretAnchor(
20088
+ view.state,
20089
+ (transaction) => view.dispatch(transaction),
20090
+ event.key
20091
+ )) {
20092
+ event.preventDefault();
20093
+ return true;
20094
+ }
19896
20095
  if (moveSelectionOverCaretAnchor(
19897
20096
  view.state,
19898
20097
  (transaction) => view.dispatch(transaction),
@@ -20018,6 +20217,30 @@ async function readPlainTextFromClipboard() {
20018
20217
 
20019
20218
  // agent-gui/agentGuiNode/agentRichText/useAgentRichTextEditorHandle.ts
20020
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
20021
20244
  function useAgentRichTextEditorHandle(input) {
20022
20245
  useImperativeHandle2(
20023
20246
  input.ref,
@@ -20027,6 +20250,7 @@ function useAgentRichTextEditorHandle(input) {
20027
20250
  if (!currentEditor || currentEditor.isDestroyed) {
20028
20251
  return;
20029
20252
  }
20253
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20030
20254
  currentEditor.chain().focus().setTextSelection(1).scrollIntoView().run();
20031
20255
  },
20032
20256
  focusAtEnd() {
@@ -20035,6 +20259,7 @@ function useAgentRichTextEditorHandle(input) {
20035
20259
  return;
20036
20260
  }
20037
20261
  const end = currentEditor.state.doc.content.size;
20262
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20038
20263
  currentEditor.chain().focus().setTextSelection(end).run();
20039
20264
  },
20040
20265
  getPromptTextBeforeSelection() {
@@ -20057,13 +20282,15 @@ function useAgentRichTextEditorHandle(input) {
20057
20282
  const triggerText = isMentionTriggerBoundaryBeforeSelection(
20058
20283
  currentEditor
20059
20284
  ) ? "@" : " @";
20060
- 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();
20061
20287
  },
20062
20288
  insertWorkspaceReferences(items) {
20063
20289
  const currentEditor = input.editorRef.current;
20064
20290
  if (!currentEditor || currentEditor.isDestroyed || items.length === 0) {
20065
20291
  return;
20066
20292
  }
20293
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20067
20294
  currentEditor.chain().focus().insertContent(
20068
20295
  createAgentFileMentionContent(items, {
20069
20296
  prefixCaretAnchor: isPromptVisualLineStart(
@@ -20078,6 +20305,7 @@ function useAgentRichTextEditorHandle(input) {
20078
20305
  if (!currentEditor || currentEditor.isDestroyed || items.length === 0) {
20079
20306
  return;
20080
20307
  }
20308
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20081
20309
  currentEditor.chain().focus().insertContent(
20082
20310
  createAgentMentionContent(items, {
20083
20311
  prefixCaretAnchor: isPromptVisualLineStart(
@@ -20094,6 +20322,7 @@ function useAgentRichTextEditorHandle(input) {
20094
20322
  }
20095
20323
  const to = currentEditor.state.selection.from;
20096
20324
  const from = Math.max(1, to - length);
20325
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20097
20326
  currentEditor.chain().focus().insertContentAt(
20098
20327
  { from, to },
20099
20328
  plainTextToAgentRichTextInlineContent(text, {
@@ -20109,7 +20338,10 @@ function useAgentRichTextEditorHandle(input) {
20109
20338
  }
20110
20339
 
20111
20340
  // agent-gui/agentGuiNode/agentRichText/AgentRichTextEditorSurface.tsx
20112
- import { useCallback as useCallback35, useRef as useRef24 } from "react";
20341
+ import {
20342
+ useCallback as useCallback35,
20343
+ useRef as useRef24
20344
+ } from "react";
20113
20345
  import { createPortal as createPortal2 } from "react-dom";
20114
20346
  import { EditorContent } from "@tiptap/react";
20115
20347
  import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
@@ -20121,90 +20353,99 @@ function AgentRichTextEditorSurface({
20121
20353
  disabled,
20122
20354
  editor,
20123
20355
  handleKeyDownCapture,
20356
+ handlePointerDownCapture,
20124
20357
  pasteClipboardText,
20125
20358
  placeholder,
20126
20359
  t
20127
20360
  }) {
20128
- return /* @__PURE__ */ jsxs20("div", { className: "relative min-w-0", onKeyDownCapture: handleKeyDownCapture, children: [
20129
- editor ? /* @__PURE__ */ jsx27(EditorContent, { editor }) : /* @__PURE__ */ jsx27(
20130
- "div",
20131
- {
20132
- role: "textbox",
20133
- "aria-label": placeholder,
20134
- "aria-disabled": disabled ? "true" : "false",
20135
- "aria-multiline": "true",
20136
- className: cn(
20137
- className,
20138
- "overflow-y-auto whitespace-pre-wrap break-words [&_p]:m-0 [&_p]:min-h-[1.45em]"
20139
- )
20140
- }
20141
- ),
20142
- contextMenu ? createPortal2(
20143
- /* @__PURE__ */ jsxs20(
20144
- "div",
20145
- {
20146
- role: "menu",
20147
- "aria-label": t("agentHost.agentGui.composerTextMenu"),
20148
- 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)]",
20149
- "data-agent-composer-text-menu": "true",
20150
- style: { left: contextMenu.x, top: contextMenu.y },
20151
- onContextMenu: (event) => event.preventDefault(),
20152
- onPointerDown: (event) => event.stopPropagation(),
20153
- children: [
20154
- /* @__PURE__ */ jsx27(
20155
- AgentRichTextContextMenuButton,
20156
- {
20157
- disabled: !contextMenu.canEdit || !contextMenu.hasSelection,
20158
- label: t("common.cut"),
20159
- onSelect: cutSelection
20160
- }
20161
- ),
20162
- /* @__PURE__ */ jsx27(
20163
- AgentRichTextContextMenuButton,
20164
- {
20165
- disabled: !contextMenu.hasSelection,
20166
- label: t("common.copy"),
20167
- onSelect: copySelection
20168
- }
20169
- ),
20170
- /* @__PURE__ */ jsx27(
20171
- AgentRichTextContextMenuButton,
20172
- {
20173
- disabled: !contextMenu.canEdit,
20174
- label: t("common.paste"),
20175
- onSelect: pasteClipboardText
20176
- }
20177
- )
20178
- ]
20179
- }
20180
- ),
20181
- document.body
20182
- ) : null
20183
- ] });
20184
- }
20185
- function AgentRichTextContextMenuButton({
20186
- disabled,
20187
- label,
20188
- onSelect
20189
- }) {
20190
- const selectionStartedRef = useRef24(false);
20191
- const select = useCallback35(() => {
20192
- if (disabled || selectionStartedRef.current) return;
20193
- selectionStartedRef.current = true;
20194
- void Promise.resolve(onSelect()).finally(() => {
20195
- selectionStartedRef.current = false;
20196
- });
20197
- }, [disabled, onSelect]);
20198
- return /* @__PURE__ */ jsx27(
20199
- "button",
20361
+ return /* @__PURE__ */ jsxs20(
20362
+ "div",
20200
20363
  {
20201
- role: "menuitem",
20202
- className: "block w-full rounded-[6px] px-3 py-1.5 text-left font-medium transition-colors hover:bg-[var(--transparency-hover)] focus-visible:bg-[var(--transparency-hover)] focus-visible:outline-none disabled:cursor-default disabled:opacity-45",
20203
- disabled,
20204
- type: "button",
20205
- onClick: select,
20206
- onPointerDown: (event) => {
20207
- if (event.button !== 0) return;
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]"
20378
+ )
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
+ );
20425
+ }
20426
+ function AgentRichTextContextMenuButton({
20427
+ disabled,
20428
+ label,
20429
+ onSelect
20430
+ }) {
20431
+ const selectionStartedRef = useRef24(false);
20432
+ const select = useCallback35(() => {
20433
+ if (disabled || selectionStartedRef.current) return;
20434
+ selectionStartedRef.current = true;
20435
+ void Promise.resolve(onSelect()).finally(() => {
20436
+ selectionStartedRef.current = false;
20437
+ });
20438
+ }, [disabled, onSelect]);
20439
+ return /* @__PURE__ */ jsx27(
20440
+ "button",
20441
+ {
20442
+ role: "menuitem",
20443
+ className: "block w-full rounded-[6px] px-3 py-1.5 text-left font-medium transition-colors hover:bg-[var(--transparency-hover)] focus-visible:bg-[var(--transparency-hover)] focus-visible:outline-none disabled:cursor-default disabled:opacity-45",
20444
+ disabled,
20445
+ type: "button",
20446
+ onClick: select,
20447
+ onPointerDown: (event) => {
20448
+ if (event.button !== 0) return;
20208
20449
  event.preventDefault();
20209
20450
  event.stopPropagation();
20210
20451
  select();
@@ -20268,6 +20509,8 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20268
20509
  removeMentionLabel,
20269
20510
  className,
20270
20511
  onChange,
20512
+ onFocus,
20513
+ onUserContentChange,
20271
20514
  onSubmit,
20272
20515
  onSubmitGuidance,
20273
20516
  availableCapabilities = [],
@@ -20290,6 +20533,9 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20290
20533
  const lastEmittedPromptRef = useRef25(value);
20291
20534
  const editorRef = useRef25(null);
20292
20535
  const onChangeRef = useRef25(onChange);
20536
+ const onFocusRef = useRef25(onFocus);
20537
+ const onUserContentChangeRef = useRef25(onUserContentChange);
20538
+ const pendingFocusMethodRef = useRef25(null);
20293
20539
  const onSubmitRef = useRef25(onSubmit);
20294
20540
  const onSubmitGuidanceRef = useRef25(onSubmitGuidance);
20295
20541
  const onKeyDownForPaletteRef = useRef25(onKeyDownForPalette);
@@ -20327,9 +20573,7 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20327
20573
  }
20328
20574
  suppressPastedAtSuggestionRef.current = text.includes("@") && !text.endsWith("@");
20329
20575
  if (suppressPastedAtSuggestionRef.current) {
20330
- window.setTimeout(() => {
20331
- suppressPastedAtSuggestionRef.current = false;
20332
- }, 0);
20576
+ releasePastedAtSuggestionSuppression(suppressPastedAtSuggestionRef);
20333
20577
  }
20334
20578
  currentEditor.chain().focus().insertContent(
20335
20579
  plainTextToAgentRichTextInlineContent(text, {
@@ -20397,7 +20641,7 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20397
20641
  scrollEditorSelectionIntoView(currentEditor);
20398
20642
  });
20399
20643
  };
20400
- const extensions = useMemo25(
20644
+ const extensions = useMemo26(
20401
20645
  () => [
20402
20646
  ...createAgentRichTextInputExtensions(
20403
20647
  {
@@ -20416,6 +20660,8 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20416
20660
  [enableFileMentionSuggestions]
20417
20661
  );
20418
20662
  onChangeRef.current = onChange;
20663
+ onFocusRef.current = onFocus;
20664
+ onUserContentChangeRef.current = onUserContentChange;
20419
20665
  onSubmitRef.current = onSubmit;
20420
20666
  onSubmitGuidanceRef.current = onSubmitGuidance;
20421
20667
  onKeyDownForPaletteRef.current = onKeyDownForPalette;
@@ -20606,9 +20852,7 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20606
20852
  }
20607
20853
  suppressPastedAtSuggestionRef.current = text.includes("@") && !text.endsWith("@");
20608
20854
  if (suppressPastedAtSuggestionRef.current) {
20609
- window.setTimeout(() => {
20610
- suppressPastedAtSuggestionRef.current = false;
20611
- }, 0);
20855
+ releasePastedAtSuggestionSuppression(suppressPastedAtSuggestionRef);
20612
20856
  }
20613
20857
  currentEditor.commands.insertContent(
20614
20858
  plainTextToAgentRichTextInlineContent(text, {
@@ -20738,7 +20982,7 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20738
20982
  }
20739
20983
  }
20740
20984
  },
20741
- onUpdate: ({ editor: nextEditor }) => {
20985
+ onUpdate: ({ editor: nextEditor, transaction }) => {
20742
20986
  editorRef.current = nextEditor;
20743
20987
  scheduleSelectionScroll(nextEditor);
20744
20988
  const nextPrompt = editorToPromptText(nextEditor);
@@ -20746,8 +20990,20 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20746
20990
  return;
20747
20991
  }
20748
20992
  lastEmittedPromptRef.current = nextPrompt;
20993
+ if (isAgentRichTextUserContentInsertion(transaction)) {
20994
+ onUserContentChangeRef.current?.(nextPrompt);
20995
+ }
20749
20996
  onChangeRef.current(nextPrompt);
20750
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
+ },
20751
21007
  onCreate: ({ editor: nextEditor }) => {
20752
21008
  editorRef.current = nextEditor;
20753
21009
  nextEditor.commands.setTextSelection(nextEditor.state.doc.content.size);
@@ -20763,9 +21019,6 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20763
21019
  submitOnEnter
20764
21020
  });
20765
21021
  };
20766
- useEffect24(() => {
20767
- editorRef.current = editor;
20768
- }, [editor]);
20769
21022
  useEffect24(
20770
21023
  () => () => {
20771
21024
  if (scrollFrameRef.current !== null && typeof window.cancelAnimationFrame === "function") {
@@ -20797,6 +21050,9 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20797
21050
  availableCapabilitiesRef,
20798
21051
  availableSkillsRef,
20799
21052
  editorRef,
21053
+ onBeforeProgrammaticFocus: () => {
21054
+ pendingFocusMethodRef.current = "programmatic";
21055
+ },
20800
21056
  ref
20801
21057
  });
20802
21058
  useEffect24(() => {
@@ -20839,12 +21095,18 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20839
21095
  disabled,
20840
21096
  editor,
20841
21097
  handleKeyDownCapture,
21098
+ handlePointerDownCapture: () => markAgentRichTextPointerFocus(pendingFocusMethodRef),
20842
21099
  pasteClipboardText,
20843
21100
  placeholder,
20844
21101
  t
20845
21102
  }
20846
21103
  );
20847
21104
  });
21105
+ function releasePastedAtSuggestionSuppression(ref) {
21106
+ window.setTimeout(() => {
21107
+ ref.current = false;
21108
+ }, 0);
21109
+ }
20848
21110
 
20849
21111
  // agent-gui/agentGuiNode/AgentSlashCommandPalette.tsx
20850
21112
  import { Fragment as Fragment8, useEffect as useEffect25, useRef as useRef26 } from "react";
@@ -21092,7 +21354,7 @@ function slashPaletteEntryIcon(entry) {
21092
21354
  }
21093
21355
 
21094
21356
  // agent-gui/agentGuiNode/AgentReviewPickerPanel.tsx
21095
- 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";
21096
21358
  import { menuItemClassName } from "@tutti-os/ui-system";
21097
21359
 
21098
21360
  // agent-gui/agentGuiNode/AgentReviewBranchController.ts
@@ -21262,7 +21524,7 @@ function AgentReviewPickerPanel({
21262
21524
  }, []);
21263
21525
  const trimmedQuery = query.trim();
21264
21526
  const normalizedQuery = trimmedQuery.toLowerCase();
21265
- const entries = useMemo26(() => {
21527
+ const entries = useMemo27(() => {
21266
21528
  if (stage === "root") {
21267
21529
  const options = [
21268
21530
  {
@@ -21456,7 +21718,7 @@ import {
21456
21718
  useCallback as useCallback38,
21457
21719
  useEffect as useEffect27,
21458
21720
  useLayoutEffect as useLayoutEffect5,
21459
- useMemo as useMemo27,
21721
+ useMemo as useMemo28,
21460
21722
  useRef as useRef28,
21461
21723
  useState as useState19
21462
21724
  } from "react";
@@ -21665,7 +21927,7 @@ var ComposerFloatingMenuSurface = forwardRef4(function ComposerFloatingMenuSurfa
21665
21927
  window.removeEventListener("blur", onDismiss);
21666
21928
  };
21667
21929
  }, [anchorRef, dismissBoundaryRef, onDismiss, open]);
21668
- const style = useMemo27(() => {
21930
+ const style = useMemo28(() => {
21669
21931
  const baseStyle = {
21670
21932
  position: "fixed",
21671
21933
  left: `${frame?.left ?? 0}px`,
@@ -22354,8 +22616,10 @@ function AgentComposerView(input) {
22354
22616
  slashStatus = null,
22355
22617
  usage = null,
22356
22618
  draftContent,
22619
+ engagement,
22357
22620
  availableSkills = EMPTY_PROVIDER_SKILLS,
22358
22621
  composerSettings,
22622
+ workspaceId,
22359
22623
  queueStatus = "active",
22360
22624
  queuedPrompts,
22361
22625
  drainingQueuedPromptId,
@@ -22385,6 +22649,7 @@ function AgentComposerView(input) {
22385
22649
  hasCompactableContext = true
22386
22650
  } = input.props;
22387
22651
  const draftImages = agentComposerDraftImages(draftContent);
22652
+ const slashStatusAgentSessionId = slashStatus?.agentSessionId ?? null;
22388
22653
  const { availableCapabilities, slashPaletteEntries, slashQuery } = input.paletteCatalog;
22389
22654
  const { mentionPaletteFrame, mentionPaletteHeightPx, mentionPaletteStyle } = input.mentionFrame;
22390
22655
  const {
@@ -22534,7 +22799,9 @@ function AgentComposerView(input) {
22534
22799
  onSendQueuedPromptNext,
22535
22800
  onRemoveQueuedPrompt,
22536
22801
  onEditQueuedPrompt,
22802
+ agentSessionId: slashStatusAgentSessionId,
22537
22803
  onLinkClick: handleLinkClick,
22804
+ workspaceId,
22538
22805
  workspaceAppIcons
22539
22806
  }
22540
22807
  )
@@ -22637,6 +22904,19 @@ function AgentComposerView(input) {
22637
22904
  disabled: inputDisabled,
22638
22905
  className: AgentGUINode_styles_default.composerTextarea,
22639
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
+ },
22640
22920
  onSubmit: submitCurrentPrompt,
22641
22921
  onSubmitGuidance: () => submitCurrentPrompt({ guidance: true }),
22642
22922
  availableSkills,
@@ -22904,6 +23184,7 @@ function AgentComposer(props) {
22904
23184
  provider,
22905
23185
  slashStatus = null,
22906
23186
  draftContent,
23187
+ engagement,
22907
23188
  draftScopeKey = "current",
22908
23189
  availableCommands,
22909
23190
  hasCompactableContext = true,
@@ -22974,6 +23255,12 @@ function AgentComposer(props) {
22974
23255
  const pastedTextStagingSupported = Boolean(
22975
23256
  canUploadAttachment && agentActivityRuntime?.stagePastedText
22976
23257
  );
23258
+ const reportContentEntered = (contentType) => {
23259
+ engagement?.contentEntered({
23260
+ contentType,
23261
+ hadPrefill: agentComposerDraftHasContent(draftContent)
23262
+ });
23263
+ };
22977
23264
  const [isPaletteOpen, setIsPaletteOpen] = useState20(true);
22978
23265
  const [isReviewPickerOpen, setIsReviewPickerOpen] = useState20(false);
22979
23266
  const [isHandoffIconPlaying, setIsHandoffIconPlaying] = useState20(false);
@@ -23248,6 +23535,7 @@ function AgentComposer(props) {
23248
23535
  clearActiveFileMentionTrigger,
23249
23536
  onDraftContentChange,
23250
23537
  onPromptImagesUnsupported,
23538
+ onContentEntered: reportContentEntered,
23251
23539
  onRequestWorkspaceReferences,
23252
23540
  resolveDroppedFileReferences,
23253
23541
  onLinkAction
@@ -23777,7 +24065,7 @@ var AgentGUIEmptyHomePane = memo3(function AgentGUIEmptyHomePane2({
23777
24065
  const providerLabel = selectedAgentTarget?.label ?? runtimeProviderLabel;
23778
24066
  const baseLabel = labels.emptyForProvider?.(provider) ?? labels.empty;
23779
24067
  const emptyLabel = runtimeProviderLabel ? baseLabel.replace(runtimeProviderLabel, providerLabel) : baseLabel;
23780
- const avatarPresentations = useMemo28(
24068
+ const avatarPresentations = useMemo29(
23781
24069
  () => agentTargets.length ? agentTargets.map(projectAgentGUIAgentTargetAvatar) : selectedAgentTarget ? [projectAgentGUIAgentTargetAvatar(selectedAgentTarget)] : [
23782
24070
  createFallbackAgentGUIAgentAvatar({
23783
24071
  provider,
@@ -24885,7 +25173,7 @@ var AgentGUIProviderRail = memo4(function AgentGUIProviderRail2({
24885
25173
  },
24886
25174
  []
24887
25175
  );
24888
- const railProviderTargets = useMemo29(
25176
+ const railProviderTargets = useMemo30(
24889
25177
  () => agentGUIProviderRailTargets(
24890
25178
  agentTargets,
24891
25179
  agentTargetsLoading,
@@ -24894,7 +25182,7 @@ var AgentGUIProviderRail = memo4(function AgentGUIProviderRail2({
24894
25182
  ),
24895
25183
  [comingSoonProviders, providerRailMode, agentTargets, agentTargetsLoading]
24896
25184
  );
24897
- const providerTiles = useMemo29(() => {
25185
+ const providerTiles = useMemo30(() => {
24898
25186
  const targets = [...railProviderTargets];
24899
25187
  const orderedTargets = providerRailMode === "exact" ? targets : (() => {
24900
25188
  const originalIndexByTarget = /* @__PURE__ */ new Map();
@@ -24934,7 +25222,7 @@ var AgentGUIProviderRail = memo4(function AgentGUIProviderRail2({
24934
25222
  agentTargets: providerTiles,
24935
25223
  conversations
24936
25224
  });
24937
- const visibleProviderTiles = useMemo29(
25225
+ const visibleProviderTiles = useMemo30(
24938
25226
  () => applyAgentGUIProviderRailVisibility(
24939
25227
  providerTiles,
24940
25228
  effectiveHiddenTargetIds
@@ -25359,11 +25647,14 @@ import {
25359
25647
  useCallback as useCallback43,
25360
25648
  useEffect as useEffect30,
25361
25649
  useLayoutEffect as useLayoutEffect6,
25362
- useMemo as useMemo31,
25650
+ useMemo as useMemo32,
25363
25651
  useRef as useRef33,
25364
25652
  useState as useState27
25365
25653
  } from "react";
25366
- import { ConfirmationDialog } from "@tutti-os/ui-system";
25654
+ import {
25655
+ Button as SystemButton,
25656
+ ConfirmationDialog
25657
+ } from "@tutti-os/ui-system";
25367
25658
  import { ScrollArea } from "@tutti-os/ui-system/components";
25368
25659
  import { CreateChatIcon as CreateChatIcon2 } from "@tutti-os/ui-system/icons";
25369
25660
 
@@ -25674,15 +25965,12 @@ function resolveConversationProjectUpdatedAtUnixMs(project) {
25674
25965
  }
25675
25966
  return project.updatedAtUnixMs ?? project.lastUsedAtUnixMs ?? project.createdAtUnixMs ?? 0;
25676
25967
  }
25677
- function normalizeConversationProjectPath(path) {
25678
- return path.trim().replaceAll("\\", "/").replace(/\/+$/, "") || "/";
25679
- }
25680
25968
  function normalizeConversationProjectPathCached(path, normalizedPathByPath) {
25681
25969
  const cached = normalizedPathByPath.get(path);
25682
25970
  if (cached !== void 0) {
25683
25971
  return cached;
25684
25972
  }
25685
- const normalized = normalizeConversationProjectPath(path);
25973
+ const normalized = normalizeAgentGUIProjectPath(path);
25686
25974
  normalizedPathByPath.set(path, normalized);
25687
25975
  return normalized;
25688
25976
  }
@@ -25848,7 +26136,10 @@ function projectConversationRailSectionsWithActiveConversation(input) {
25848
26136
  if (loadedSection) {
25849
26137
  return {
25850
26138
  activeOverlay: {
25851
- conversation: loadedSection.kind === "project" ? { ...activeConversation, project: loadedSection.project } : activeConversation,
26139
+ conversation: loadedSection.kind === "project" ? conversationWithRailProject(
26140
+ activeConversation,
26141
+ loadedSection.project
26142
+ ) : activeConversation,
25852
26143
  sectionId: loadedSection.id
25853
26144
  },
25854
26145
  sections: input.sections
@@ -25868,7 +26159,10 @@ function projectConversationRailSectionsWithActiveConversation(input) {
25868
26159
  const matchingSection = input.sections[matchingSectionIndex];
25869
26160
  return {
25870
26161
  activeOverlay: {
25871
- conversation: matchingSection?.kind === "project" ? { ...activeConversation, project: matchingSection.project } : activeConversation,
26162
+ conversation: matchingSection?.kind === "project" ? conversationWithRailProject(
26163
+ activeConversation,
26164
+ matchingSection.project
26165
+ ) : activeConversation,
25872
26166
  sectionId: activeSection.id
25873
26167
  },
25874
26168
  sections: input.sections
@@ -25902,6 +26196,9 @@ function projectConversationRailSectionsWithActiveConversation(input) {
25902
26196
  sections
25903
26197
  };
25904
26198
  }
26199
+ function conversationWithRailProject(conversation, project) {
26200
+ return conversationProjectsRenderEqual2(conversation.project, project) ? conversation : { ...conversation, project };
26201
+ }
25905
26202
  function planRuntimeRailMembershipRefresh(input) {
25906
26203
  const previousPendingIds = new Set(
25907
26204
  input.previous.flatMap((conversation) => {
@@ -25994,6 +26291,7 @@ function projectRuntimeSectionsToConversationRailMemberships(input) {
25994
26291
  label: section.userProject.label,
25995
26292
  lastUsedAtUnixMs: section.userProject.lastUsedAtUnixMs,
25996
26293
  path: section.userProject.path,
26294
+ sectionKey: section.userProject.sectionKey,
25997
26295
  updatedAtUnixMs: section.userProject.updatedAtUnixMs
25998
26296
  } : null;
25999
26297
  result.push({
@@ -26115,7 +26413,7 @@ function conversationSummariesRenderEqual2(left, right) {
26115
26413
  return left.id === right.id && left.agentTargetId === right.agentTargetId && left.provider === right.provider && left.title === right.title && left.titleFallback === right.titleFallback && left.status === right.status && left.cwd === right.cwd && left.pinnedAtUnixMs === right.pinnedAtUnixMs && left.sortTimeUnixMs === right.sortTimeUnixMs && left.updatedAtUnixMs === right.updatedAtUnixMs && left.projectionSource === right.projectionSource && left.isImported === right.isImported && left.hasUnreadCompletion === right.hasUnreadCompletion && left.unreadCompletionKey === right.unreadCompletionKey && conversationProjectsRenderEqual2(left.project, right.project);
26116
26414
  }
26117
26415
  function conversationProjectsRenderEqual2(left, right) {
26118
- return left === right || (!left || !right ? !left && !right : left.id === right.id && left.path === right.path && left.label === right.label && left.createdAtUnixMs === right.createdAtUnixMs && left.updatedAtUnixMs === right.updatedAtUnixMs && left.lastUsedAtUnixMs === right.lastUsedAtUnixMs);
26416
+ return left === right || (!left || !right ? !left && !right : left.id === right.id && left.path === right.path && left.label === right.label && left.createdAtUnixMs === right.createdAtUnixMs && left.updatedAtUnixMs === right.updatedAtUnixMs && left.lastUsedAtUnixMs === right.lastUsedAtUnixMs && left.sectionKey === right.sectionKey);
26119
26417
  }
26120
26418
 
26121
26419
  // agent-gui/agentGuiNode/view/AgentGUIConversationRailSection.tsx
@@ -26142,7 +26440,7 @@ import {
26142
26440
  import {
26143
26441
  memo as memo5,
26144
26442
  useCallback as useCallback41,
26145
- useMemo as useMemo30,
26443
+ useMemo as useMemo31,
26146
26444
  useRef as useRef32,
26147
26445
  useState as useState25
26148
26446
  } from "react";
@@ -26208,6 +26506,7 @@ var AgentGUIConversationRailItem = memo5(
26208
26506
  active,
26209
26507
  isPendingDeleteConversation,
26210
26508
  isDeletingConversation,
26509
+ isRailInteractionLocked,
26211
26510
  currentTimeMs,
26212
26511
  labels,
26213
26512
  previewMode,
@@ -26244,63 +26543,89 @@ var AgentGUIConversationRailItem = memo5(
26244
26543
  const contextMenuCopySessionLinkRequestedRef = useRef32(false);
26245
26544
  const agentHostApi = useOptionalAgentHostApi();
26246
26545
  const handleMouseLeave = useCallback41(() => {
26247
- if (isPendingDeleteConversation) {
26546
+ if (isPendingDeleteConversation && !isRailInteractionLocked()) {
26248
26547
  onCancelDeleteConversation();
26249
26548
  }
26250
- }, [isPendingDeleteConversation, onCancelDeleteConversation]);
26549
+ }, [
26550
+ isPendingDeleteConversation,
26551
+ isRailInteractionLocked,
26552
+ onCancelDeleteConversation
26553
+ ]);
26251
26554
  const handleSelect = useCallback41(() => {
26555
+ if (isRailInteractionLocked()) return;
26252
26556
  onSelectConversation(item.id);
26253
- }, [item.id, onSelectConversation]);
26557
+ }, [isRailInteractionLocked, item.id, onSelectConversation]);
26254
26558
  const handleTogglePinned = useCallback41(() => {
26559
+ if (isRailInteractionLocked()) return;
26255
26560
  onToggleConversationPinned(item.id, !pinned);
26256
- }, [item.id, onToggleConversationPinned, pinned]);
26561
+ }, [isRailInteractionLocked, item.id, onToggleConversationPinned, pinned]);
26257
26562
  const canMarkUnread = Boolean(
26258
26563
  !previewMode && !item.hasUnreadCompletion && item.isImported !== true && (item.unreadCompletionKey || item.status === "completed" || item.status === "ready")
26259
26564
  );
26260
26565
  const handleMarkUnread = useCallback41(() => {
26261
- if (!canMarkUnread) {
26566
+ if (!canMarkUnread || isRailInteractionLocked()) {
26262
26567
  return;
26263
26568
  }
26264
26569
  onMarkConversationUnread(item.id);
26265
- }, [canMarkUnread, item.id, onMarkConversationUnread]);
26570
+ }, [
26571
+ canMarkUnread,
26572
+ isRailInteractionLocked,
26573
+ item.id,
26574
+ onMarkConversationUnread
26575
+ ]);
26266
26576
  const handleOpenConversationWindow = useCallback41(() => {
26577
+ if (isRailInteractionLocked()) return;
26267
26578
  onOpenConversationWindow?.(item.id);
26268
- }, [item.id, onOpenConversationWindow]);
26579
+ }, [isRailInteractionLocked, item.id, onOpenConversationWindow]);
26269
26580
  const handleRequestDelete = useCallback41(() => {
26581
+ if (isRailInteractionLocked()) return;
26270
26582
  onRequestDeleteConversation(item.id);
26271
- }, [item.id, onRequestDeleteConversation]);
26583
+ }, [isRailInteractionLocked, item.id, onRequestDeleteConversation]);
26272
26584
  const handleRequestRename = useCallback41(() => {
26585
+ if (isRailInteractionLocked()) return;
26273
26586
  onRequestRenameConversation(item);
26274
- }, [item, onRequestRenameConversation]);
26587
+ }, [isRailInteractionLocked, item, onRequestRenameConversation]);
26275
26588
  const handleContextMenuRename = useCallback41(() => {
26276
- if (contextMenuRenameRequestedRef.current) {
26589
+ if (isRailInteractionLocked() || contextMenuRenameRequestedRef.current) {
26277
26590
  return;
26278
26591
  }
26279
26592
  contextMenuRenameRequestedRef.current = true;
26280
26593
  setContextMenuResetKey((key) => key + 1);
26281
26594
  window.setTimeout(() => {
26595
+ if (isRailInteractionLocked()) {
26596
+ contextMenuRenameRequestedRef.current = false;
26597
+ return;
26598
+ }
26282
26599
  handleRequestRename();
26283
26600
  contextMenuRenameRequestedRef.current = false;
26284
26601
  }, 0);
26285
- }, [handleRequestRename]);
26602
+ }, [handleRequestRename, isRailInteractionLocked]);
26286
26603
  const handleContextMenuOpenConversationWindow = useCallback41(() => {
26287
- if (contextMenuOpenConversationWindowRequestedRef.current) {
26604
+ if (isRailInteractionLocked() || contextMenuOpenConversationWindowRequestedRef.current) {
26288
26605
  return;
26289
26606
  }
26290
26607
  contextMenuOpenConversationWindowRequestedRef.current = true;
26291
26608
  setContextMenuResetKey((key) => key + 1);
26292
26609
  window.setTimeout(() => {
26610
+ if (isRailInteractionLocked()) {
26611
+ contextMenuOpenConversationWindowRequestedRef.current = false;
26612
+ return;
26613
+ }
26293
26614
  handleOpenConversationWindow();
26294
26615
  contextMenuOpenConversationWindowRequestedRef.current = false;
26295
26616
  }, 0);
26296
- }, [handleOpenConversationWindow]);
26617
+ }, [handleOpenConversationWindow, isRailInteractionLocked]);
26297
26618
  const handleContextMenuCopySessionLink = useCallback41(() => {
26298
- if (contextMenuCopySessionLinkRequestedRef.current) {
26619
+ if (isRailInteractionLocked() || contextMenuCopySessionLinkRequestedRef.current) {
26299
26620
  return;
26300
26621
  }
26301
26622
  contextMenuCopySessionLinkRequestedRef.current = true;
26302
26623
  setContextMenuResetKey((key) => key + 1);
26303
26624
  window.setTimeout(() => {
26625
+ if (isRailInteractionLocked()) {
26626
+ contextMenuCopySessionLinkRequestedRef.current = false;
26627
+ return;
26628
+ }
26304
26629
  if (!agentHostApi?.clipboard?.writeText) {
26305
26630
  contextMenuCopySessionLinkRequestedRef.current = false;
26306
26631
  return;
@@ -26317,7 +26642,14 @@ var AgentGUIConversationRailItem = memo5(
26317
26642
  contextMenuCopySessionLinkRequestedRef.current = false;
26318
26643
  });
26319
26644
  }, 0);
26320
- }, [agentHostApi, item, labels, uiLanguage, workspaceId]);
26645
+ }, [
26646
+ agentHostApi,
26647
+ isRailInteractionLocked,
26648
+ item,
26649
+ labels,
26650
+ uiLanguage,
26651
+ workspaceId
26652
+ ]);
26321
26653
  const row = /* @__PURE__ */ jsxs33(
26322
26654
  "div",
26323
26655
  {
@@ -26327,6 +26659,12 @@ var AgentGUIConversationRailItem = memo5(
26327
26659
  "data-pinned": pinned,
26328
26660
  "data-pending-delete": isPendingDeleteConversation,
26329
26661
  "data-testid": `agent-gui-conversation-item-${item.id}`,
26662
+ onContextMenuCapture: (event) => {
26663
+ if (isRailInteractionLocked()) {
26664
+ event.preventDefault();
26665
+ event.stopPropagation();
26666
+ }
26667
+ },
26330
26668
  onMouseLeave: handleMouseLeave,
26331
26669
  children: [
26332
26670
  /* @__PURE__ */ jsxs33(
@@ -26367,7 +26705,9 @@ var AgentGUIConversationRailItem = memo5(
26367
26705
  disabled: isDeletingConversation,
26368
26706
  onClick: (event) => {
26369
26707
  event.stopPropagation();
26370
- onConfirmDeleteConversation();
26708
+ if (!isRailInteractionLocked()) {
26709
+ onConfirmDeleteConversation();
26710
+ }
26371
26711
  },
26372
26712
  children: /* @__PURE__ */ jsx46("span", { className: AgentGUINode_styles_default.conversationDeleteConfirmText, children: labels.deleteSessionConfirm })
26373
26713
  }
@@ -26504,13 +26844,14 @@ var AgentGUIConversationRailItem = memo5(
26504
26844
  }
26505
26845
  );
26506
26846
  function AgentGUIProjectRailHeader({
26847
+ disabled,
26507
26848
  labels,
26508
26849
  selectProjectDirectory,
26509
26850
  workspaceUserProjectI18n
26510
26851
  }) {
26511
26852
  "use memo";
26512
26853
  const agentHostApi = useAgentHostApi();
26513
- const userProjectApi = useMemo30(
26854
+ const userProjectApi = useMemo31(
26514
26855
  () => agentHostApi.userProjects ? {
26515
26856
  ...agentHostApi.userProjects,
26516
26857
  selectDirectory: selectProjectDirectory ?? agentHostApi.workspace.selectDirectory
@@ -26545,6 +26886,7 @@ function AgentGUIProjectRailHeader({
26545
26886
  contentAlign: "end",
26546
26887
  contentSide: "bottom",
26547
26888
  contentSideOffset: 6,
26889
+ disabled,
26548
26890
  i18n: workspaceUserProjectI18n,
26549
26891
  labels: {
26550
26892
  addProject: labels.projectRailCreateProject,
@@ -26603,6 +26945,7 @@ var AgentGUIConversationRailSection = memo6(
26603
26945
  isRequestingBatchDeletion,
26604
26946
  isConversationSearchActive,
26605
26947
  isLoadingMoreConversations,
26948
+ isRailInteractionLocked,
26606
26949
  sectionHasMore,
26607
26950
  sectionTotalCount,
26608
26951
  createConversationDisabled,
@@ -26632,6 +26975,12 @@ var AgentGUIConversationRailSection = memo6(
26632
26975
  limit: AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE,
26633
26976
  scopeKey: paginationScopeKey
26634
26977
  }));
26978
+ if (visibleItemLimitState.scopeKey !== paginationScopeKey) {
26979
+ setVisibleItemLimitState({
26980
+ limit: AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE,
26981
+ scopeKey: paginationScopeKey
26982
+ });
26983
+ }
26635
26984
  const visibleItemLimit = visibleItemLimitState.scopeKey === paginationScopeKey ? visibleItemLimitState.limit : AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE;
26636
26985
  const pageableItems = section.items.filter(
26637
26986
  (item) => item.projectionSource !== "pending_activation"
@@ -26659,6 +27008,7 @@ var AgentGUIConversationRailSection = memo6(
26659
27008
  const canShowMore = !isSectionCollapsed && visibleCountTowardTotal < sectionTotalCount && (visibleItemCount < pageableItems.length || sectionHasMore);
26660
27009
  const canShowLess = !isSectionCollapsed && visibleItemCount > AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE;
26661
27010
  const showMoreConversations = useCallback42(() => {
27011
+ if (isRailInteractionLocked()) return;
26662
27012
  if (visibleItemCount >= pageableItems.length && sectionHasMore) {
26663
27013
  onLoadMoreConversations(section);
26664
27014
  setVisibleItemLimitState((current) => ({
@@ -26676,6 +27026,7 @@ var AgentGUIConversationRailSection = memo6(
26676
27026
  }));
26677
27027
  }, [
26678
27028
  onLoadMoreConversations,
27029
+ isRailInteractionLocked,
26679
27030
  pageableItems.length,
26680
27031
  paginationScopeKey,
26681
27032
  section,
@@ -26683,14 +27034,16 @@ var AgentGUIConversationRailSection = memo6(
26683
27034
  visibleItemCount
26684
27035
  ]);
26685
27036
  const showLessConversations = useCallback42(() => {
27037
+ if (isRailInteractionLocked()) return;
26686
27038
  setVisibleItemLimitState({
26687
27039
  limit: AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE,
26688
27040
  scopeKey: paginationScopeKey
26689
27041
  });
26690
- }, [paginationScopeKey]);
27042
+ }, [isRailInteractionLocked, paginationScopeKey]);
26691
27043
  const canCreateConversationFromSection = section.kind === "conversations" || Boolean(projectPath);
26692
27044
  const createConversationLabel = projectPath ? labels.projectSectionEdit : labels.newConversation;
26693
27045
  const handleCreateConversation = useCallback42(() => {
27046
+ if (isRailInteractionLocked()) return;
26694
27047
  if (projectPath) {
26695
27048
  onCreateConversation({ projectPath, source: "project_section" });
26696
27049
  return;
@@ -26699,7 +27052,7 @@ var AgentGUIConversationRailSection = memo6(
26699
27052
  projectPath: null,
26700
27053
  source: "unscoped_section"
26701
27054
  });
26702
- }, [onCreateConversation, projectPath]);
27055
+ }, [isRailInteractionLocked, onCreateConversation, projectPath]);
26703
27056
  return /* @__PURE__ */ jsxs34(
26704
27057
  "section",
26705
27058
  {
@@ -26714,7 +27067,11 @@ var AgentGUIConversationRailSection = memo6(
26714
27067
  type: "button",
26715
27068
  className: AgentGUINode_styles_default.conversationSectionToggle,
26716
27069
  "aria-expanded": !isSectionCollapsed,
26717
- onClick: () => onToggleProjectSectionCollapsed(section.id),
27070
+ onClick: () => {
27071
+ if (!isRailInteractionLocked()) {
27072
+ onToggleProjectSectionCollapsed(section.id);
27073
+ }
27074
+ },
26718
27075
  children: [
26719
27076
  /* @__PURE__ */ jsx47(
26720
27077
  ChevronRight2,
@@ -26835,6 +27192,7 @@ var AgentGUIConversationRailSection = memo6(
26835
27192
  className: `${AgentGUINode_styles_default.composerMenuItem} nodrag [-webkit-app-region:no-drag]`,
26836
27193
  disabled: !onOpenProjectFiles,
26837
27194
  onSelect: () => {
27195
+ if (isRailInteractionLocked()) return;
26838
27196
  onOpenProjectFiles?.({
26839
27197
  directoryPath: projectPath,
26840
27198
  mode: "open-directory",
@@ -26852,7 +27210,11 @@ var AgentGUIConversationRailSection = memo6(
26852
27210
  {
26853
27211
  className: `${AgentGUINode_styles_default.composerMenuItem} nodrag [-webkit-app-region:no-drag]`,
26854
27212
  disabled: isConversationSearchActive || section.items.length === 0 && !sectionHasMore || isDeletingProjectConversations || isRequestingBatchDeletion,
26855
- onSelect: () => onRequestSectionBatchDeletion(section),
27213
+ onSelect: () => {
27214
+ if (!isRailInteractionLocked()) {
27215
+ onRequestSectionBatchDeletion(section);
27216
+ }
27217
+ },
26856
27218
  children: /* @__PURE__ */ jsx47("span", { children: labels.batchDeleteProjectSessions })
26857
27219
  }
26858
27220
  ),
@@ -26861,6 +27223,7 @@ var AgentGUIConversationRailSection = memo6(
26861
27223
  {
26862
27224
  className: `${AgentGUINode_styles_default.composerMenuItem} nodrag [-webkit-app-region:no-drag]`,
26863
27225
  onSelect: () => {
27226
+ if (isRailInteractionLocked()) return;
26864
27227
  const label = projectLabel || projectPath;
26865
27228
  setPendingProjectAction({
26866
27229
  kind: "remove",
@@ -26927,7 +27290,11 @@ var AgentGUIConversationRailSection = memo6(
26927
27290
  {
26928
27291
  className: `${AgentGUINode_styles_default.composerMenuItem} nodrag [-webkit-app-region:no-drag]`,
26929
27292
  disabled: isConversationSearchActive || section.items.length === 0 && !sectionHasMore || isDeletingProjectConversations || isRequestingBatchDeletion,
26930
- onSelect: () => onRequestSectionBatchDeletion(section),
27293
+ onSelect: () => {
27294
+ if (!isRailInteractionLocked()) {
27295
+ onRequestSectionBatchDeletion(section);
27296
+ }
27297
+ },
26931
27298
  children: /* @__PURE__ */ jsx47("span", { children: labels.batchDeleteConversations })
26932
27299
  }
26933
27300
  )
@@ -26950,6 +27317,7 @@ var AgentGUIConversationRailSection = memo6(
26950
27317
  currentTimeMs,
26951
27318
  isDeletingConversation,
26952
27319
  isPendingDeleteConversation: pendingDeleteConversationId === item.id,
27320
+ isRailInteractionLocked,
26953
27321
  item,
26954
27322
  labels,
26955
27323
  previewMode,
@@ -27035,7 +27403,6 @@ var AgentGUIConversationRailPane = memo7(
27035
27403
  sectionAgentTargetFallbackId,
27036
27404
  conversationQuery,
27037
27405
  railQuery,
27038
- railSearch,
27039
27406
  onCreateConversation,
27040
27407
  onSelectConversation,
27041
27408
  onToggleConversationPinned,
@@ -27057,6 +27424,7 @@ var AgentGUIConversationRailPane = memo7(
27057
27424
  const [currentTimeMs, setCurrentTimeMs] = useState27(() => Date.now());
27058
27425
  const [pendingProjectAction, setPendingProjectAction] = useState27(null);
27059
27426
  const [isRequestingBatchDeletion, setIsRequestingBatchDeletion] = useState27(false);
27427
+ const { railSearch } = railQuery;
27060
27428
  const railElementRef = useRef33(null);
27061
27429
  const conversationListRef = useRef33(null);
27062
27430
  const conversationItemElementsRef = useRef33(
@@ -27064,9 +27432,11 @@ var AgentGUIConversationRailPane = memo7(
27064
27432
  );
27065
27433
  const activeConversationScrollCompletedRef = useRef33(null);
27066
27434
  const previousActiveConversationIdRef = useRef33(null);
27435
+ const railActiveConversationRef = useRef33([]);
27067
27436
  const groupedConversationsRef = useRef33(null);
27068
27437
  const {
27069
27438
  loadMoreSectionConversations,
27439
+ isInteractionLocked,
27070
27440
  runtimeSectionsEnabled,
27071
27441
  runtimeRailConversations,
27072
27442
  runtimeRailMemberships,
@@ -27086,6 +27456,7 @@ var AgentGUIConversationRailPane = memo7(
27086
27456
  const railConversationEntities = [...railConversationEntitiesById.values()];
27087
27457
  const hasConversationQuery = conversationQuery.trim().length > 0;
27088
27458
  const backendSearchActive = hasConversationQuery && railSearch.enabled;
27459
+ const railInteractionsLocked = runtimeRailSectionsPending && !backendSearchActive;
27089
27460
  const backendSearchConversations = backendSearchActive ? railSearch.sessionIds.flatMap((id) => {
27090
27461
  const conversation = railConversationEntitiesById.get(id);
27091
27462
  return conversation ? [conversation] : [];
@@ -27095,11 +27466,17 @@ var AgentGUIConversationRailPane = memo7(
27095
27466
  labels,
27096
27467
  sections: runtimeRailMemberships
27097
27468
  }) : null;
27098
- const railActiveConversation = resolveConversationRailActiveConversation({
27469
+ const railActiveConversationCandidate = resolveConversationRailActiveConversation({
27099
27470
  activeConversation,
27100
27471
  activeConversationId,
27101
27472
  conversations: railConversationEntities
27102
27473
  });
27474
+ const stableRailActiveConversation = stabilizeConversationSectionItems(
27475
+ railActiveConversationRef.current,
27476
+ railActiveConversationCandidate ? [railActiveConversationCandidate] : []
27477
+ );
27478
+ railActiveConversationRef.current = stableRailActiveConversation;
27479
+ const railActiveConversation = stableRailActiveConversation[0] ?? null;
27103
27480
  const runtimeSectionsWithTransientConversations = projectConversationRailSectionsWithTransientConversations({
27104
27481
  conversations,
27105
27482
  labels,
@@ -27121,7 +27498,7 @@ var AgentGUIConversationRailPane = memo7(
27121
27498
  window.clearInterval(timer);
27122
27499
  };
27123
27500
  }, []);
27124
- const displayConversations = useMemo31(() => {
27501
+ const displayConversations = useMemo32(() => {
27125
27502
  if (backendSearchActive) {
27126
27503
  return backendSearchConversations;
27127
27504
  }
@@ -27142,7 +27519,7 @@ var AgentGUIConversationRailPane = memo7(
27142
27519
  runtimeRailSections,
27143
27520
  runtimeSectionsEnabled
27144
27521
  ]);
27145
- const filteredConversationResult = useMemo31(() => {
27522
+ const filteredConversationResult = useMemo32(() => {
27146
27523
  const startedAtMs = agentGuiPerfNowMs();
27147
27524
  const query = conversationQuery.trim().toLowerCase();
27148
27525
  const items = backendSearchActive ? displayConversations : !query ? displayConversations : displayConversations.filter(
@@ -27160,7 +27537,7 @@ var AgentGUIConversationRailPane = memo7(
27160
27537
  uiLanguage
27161
27538
  ]);
27162
27539
  const filteredConversations = filteredConversationResult.items;
27163
- const groupedConversationResult = useMemo31(() => {
27540
+ const groupedConversationResult = useMemo32(() => {
27164
27541
  const startedAtMs = agentGuiPerfNowMs();
27165
27542
  const query = conversationQuery.trim();
27166
27543
  const rawGroups = backendSearchActive ? groupConversations(filteredConversations, labels, userProjects, {
@@ -27200,7 +27577,7 @@ var AgentGUIConversationRailPane = memo7(
27200
27577
  userProjects
27201
27578
  ]);
27202
27579
  const groupedConversations = groupedConversationResult.groups;
27203
- const sectionPaginationScopeKey = `${conversationFilter.kind === "agentTarget" ? `${workspaceId}:agentTarget:${conversationFilter.agentTargetId.trim()}` : `${workspaceId}:all`}:search:${conversationQuery.trim()}`;
27580
+ const sectionPaginationScopeKey = `${conversationFilter.kind === "agentTarget" ? `${workspaceId}:agentTarget:${conversationFilter.agentTargetId.trim()}` : `${workspaceId}:all:${sectionAgentTargetFallbackId?.trim() ?? ""}`}:search:${conversationQuery.trim()}`;
27204
27581
  const toggleProjectSectionCollapsed = useCallback43((sectionId) => {
27205
27582
  setCollapsedProjectSectionIds((current) => {
27206
27583
  const next = new Set(current);
@@ -27212,7 +27589,7 @@ var AgentGUIConversationRailPane = memo7(
27212
27589
  return next;
27213
27590
  });
27214
27591
  }, []);
27215
- const groupedConversationIdentityKey = useMemo31(
27592
+ const groupedConversationIdentityKey = useMemo32(
27216
27593
  () => `${groupedConversations.map(
27217
27594
  (section) => `${section.id}:${section.items.map((item) => item.id).join(",")}`
27218
27595
  ).join("|")}|active:${railActiveOverlay?.conversation.id ?? ""}`,
@@ -27221,7 +27598,7 @@ var AgentGUIConversationRailPane = memo7(
27221
27598
  const sectionAgentTargetId = conversationFilter.kind === "agentTarget" ? conversationFilter.agentTargetId.trim() : sectionAgentTargetFallbackId?.trim() ?? "";
27222
27599
  const requestSectionBatchDeletion = useCallback43(
27223
27600
  (section) => {
27224
- if (isDeletingProjectConversations || isRequestingBatchDeletion) {
27601
+ if (isInteractionLocked() || isDeletingProjectConversations || isRequestingBatchDeletion) {
27225
27602
  return;
27226
27603
  }
27227
27604
  setIsRequestingBatchDeletion(true);
@@ -27229,7 +27606,7 @@ var AgentGUIConversationRailPane = memo7(
27229
27606
  section.id,
27230
27607
  sectionAgentTargetId || void 0
27231
27608
  ).then((sessionIds) => {
27232
- if (sessionIds.length === 0) {
27609
+ if (isInteractionLocked() || sessionIds.length === 0) {
27233
27610
  return;
27234
27611
  }
27235
27612
  setPendingProjectAction({
@@ -27243,6 +27620,7 @@ var AgentGUIConversationRailPane = memo7(
27243
27620
  [
27244
27621
  isDeletingProjectConversations,
27245
27622
  isRequestingBatchDeletion,
27623
+ isInteractionLocked,
27246
27624
  onConfirmDeleteProjectConversations,
27247
27625
  sectionAgentTargetId
27248
27626
  ]
@@ -27254,6 +27632,7 @@ var AgentGUIConversationRailPane = memo7(
27254
27632
  300
27255
27633
  );
27256
27634
  const shouldShowConversationEmptyState = !isConversationRailListLoading && groupedConversations.length === 0;
27635
+ const shouldShowConversationSearchError = backendSearchActive && railSearch.failed && railSearch.sessionIds.length === 0;
27257
27636
  const registerConversationItemElement = useCallback43(
27258
27637
  (itemId, element) => {
27259
27638
  if (element) {
@@ -27330,87 +27709,108 @@ var AgentGUIConversationRailPane = memo7(
27330
27709
  {
27331
27710
  label: labels.loadingConversations
27332
27711
  }
27333
- ) : 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) => {
27334
- const projectPath = section.kind === "project" ? section.project?.path ?? "" : "";
27335
- const projectLabel = section.kind === "project" ? section.label : "";
27336
- const isProjectSection = section.kind === "project";
27337
- const showProjectRailHeader = !conversationQuery.trim() && section.kind !== "pinned" && (sectionIndex === 0 || groupedConversations[sectionIndex - 1]?.kind === "pinned");
27338
- const isSectionCollapsed = isProjectSection && collapsedProjectSectionIds.has(section.id);
27339
- const sectionPageState = sectionPageStates.get(section.id);
27340
- const searchSectionHasMore = backendSearchActive && sectionIndex === groupedConversations.length - 1 && railSearch.hasMore;
27341
- const activeOverlayConversation = !backendSearchActive && railActiveOverlay?.sectionId === section.id && (!conversationQuery.trim() || filteredConversations.some(
27342
- (conversation) => conversation.id === railActiveOverlay.conversation.id
27343
- )) ? railActiveOverlay.conversation : null;
27344
- const activeOverlayIsCanonical = Boolean(
27345
- activeOverlayConversation && section.items.some(
27346
- (item) => item.projectionSource !== "pending_activation" && item.id === activeOverlayConversation.id
27347
- )
27348
- );
27349
- const activeOverlayCountsTowardTotal = Boolean(
27350
- activeOverlayConversation && activeOverlayConversation.projectionSource !== "pending_activation" && matchesAgentGUIConversationSummaryFilter(
27351
- activeOverlayConversation,
27352
- conversationFilter
27353
- )
27354
- );
27355
- const sectionTotalCount = backendSearchActive ? section.items.length + (searchSectionHasMore ? 1 : 0) : sectionPageState?.totalCount ?? section.items.filter(
27356
- (item) => item.projectionSource !== "pending_activation"
27357
- ).length + (activeOverlayCountsTowardTotal && !activeOverlayIsCanonical ? 1 : 0);
27358
- const sectionHasMore = searchSectionHasMore || !conversationQuery.trim() && sectionPageState?.hasMore === true;
27359
- return /* @__PURE__ */ jsxs35(Fragment13, { children: [
27360
- showProjectRailHeader ? /* @__PURE__ */ jsx48(
27361
- AgentGUIProjectRailHeader,
27362
- {
27363
- labels,
27364
- selectProjectDirectory,
27365
- workspaceUserProjectI18n
27366
- }
27367
- ) : null,
27368
- /* @__PURE__ */ jsx48(
27369
- AgentGUIConversationRailSection,
27370
- {
27371
- activeConversation: activeOverlayConversation,
27372
- activeConversationCountsTowardTotal: activeOverlayCountsTowardTotal,
27373
- activeConversationId,
27374
- createConversationDisabled,
27375
- currentTimeMs,
27376
- isDeletingConversation,
27377
- isDeletingProjectConversations,
27378
- isRequestingBatchDeletion,
27379
- isConversationSearchActive: Boolean(
27380
- conversationQuery.trim()
27381
- ),
27382
- isLoadingMoreConversations: backendSearchActive ? railSearch.loadingMore : runtimeRailSectionsPending || (sectionPageState?.isLoading ?? false),
27383
- isSectionCollapsed,
27384
- labels,
27385
- pendingDeleteConversationId,
27386
- paginationScopeKey: sectionPaginationScopeKey,
27387
- previewMode,
27388
- projectLabel,
27389
- projectPath,
27390
- registerItemElement: registerConversationItemElement,
27391
- section,
27392
- sectionHasMore,
27393
- sectionTotalCount,
27394
- uiLanguage,
27395
- workspaceId,
27396
- onCancelDeleteConversation,
27397
- onConfirmDeleteConversation,
27398
- onCreateConversation,
27399
- onLoadMoreConversations: backendSearchActive ? railSearch.loadMore : loadMoreSectionConversations,
27400
- onRequestDeleteConversation,
27401
- onRequestRenameConversation,
27402
- onSelectConversation,
27403
- onRequestSectionBatchDeletion: requestSectionBatchDeletion,
27404
- setPendingProjectAction,
27405
- onToggleConversationPinned,
27406
- onMarkConversationUnread,
27407
- onOpenProjectFiles,
27408
- onOpenConversationWindow,
27409
- onToggleProjectSectionCollapsed: toggleProjectSectionCollapsed
27410
- }
27411
- )
27412
- ] }, section.id);
27413
- })
27712
+ ) : shouldShowConversationSearchError ? /* @__PURE__ */ jsxs35("div", { className: AgentGUINode_styles_default.emptyState, children: [
27713
+ /* @__PURE__ */ jsx48("span", { children: labels.searchFailed }),
27714
+ /* @__PURE__ */ jsx48(
27715
+ SystemButton,
27716
+ {
27717
+ type: "button",
27718
+ variant: "outline",
27719
+ size: "sm",
27720
+ onClick: railSearch.retry,
27721
+ children: labels.retrySearch
27722
+ }
27723
+ )
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
+ )
27414
27814
  }
27415
27815
  ),
27416
27816
  footer ? /* @__PURE__ */ jsx48("div", { className: "shrink-0 pb-2", children: footer }) : null,
@@ -27420,6 +27820,7 @@ var AgentGUIConversationRailPane = memo7(
27420
27820
  cancelLabel: labels.cancel,
27421
27821
  className: AGENT_GUI_CONFIRMATION_DIALOG_CLASS_NAME,
27422
27822
  confirmBusy: (pendingProjectAction?.kind === "batch-delete" || pendingProjectAction?.kind === "batch-delete-conversations") && isDeletingProjectConversations,
27823
+ confirmDisabled: railInteractionsLocked,
27423
27824
  confirmLabel: pendingProjectAction?.kind === "batch-delete" ? labels.batchDeleteProjectSessionsConfirm : pendingProjectAction?.kind === "batch-delete-conversations" ? labels.batchDeleteConversationsConfirm : labels.removeProject,
27424
27825
  description: pendingProjectAction?.kind === "batch-delete" ? labels.batchDeleteProjectSessionsBody(
27425
27826
  pendingProjectAction.conversationCount,
@@ -27431,6 +27832,7 @@ var AgentGUIConversationRailPane = memo7(
27431
27832
  ) : void 0,
27432
27833
  onCancel: () => setPendingProjectAction(null),
27433
27834
  onConfirm: () => {
27835
+ if (isInteractionLocked()) return;
27434
27836
  const action = pendingProjectAction;
27435
27837
  setPendingProjectAction(null);
27436
27838
  if (!action) {
@@ -27464,8 +27866,10 @@ var AgentGUIConversationRailPane = memo7(
27464
27866
  );
27465
27867
 
27466
27868
  // agent-gui/agentGuiNode/controller/useAgentGUIConversationRailQuery.ts
27467
- import { selectWorkspaceAgentConsumerSessions as selectWorkspaceAgentConsumerSessions4 } from "@tutti-os/agent-activity-core";
27468
- 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";
27469
27873
 
27470
27874
  // agent-gui/agentGuiNode/controller/AgentGUIConversationRailQueryController.ts
27471
27875
  import {
@@ -27493,6 +27897,7 @@ var EMPTY_QUERY_STATE = {
27493
27897
  };
27494
27898
  var AgentGUIConversationRailQueryController = class {
27495
27899
  getSnapshot = () => this.snapshot;
27900
+ isInteractionLocked = () => this.snapshot.runtimeRailSectionsPending && !(this.searchQuery && this.snapshot.railSearch.enabled);
27496
27901
  subscribe = (listener) => {
27497
27902
  this.listeners.add(listener);
27498
27903
  return () => this.listeners.delete(listener);
@@ -27560,8 +27965,7 @@ var AgentGUIConversationRailQueryController = class {
27560
27965
  this.queryState = {
27561
27966
  ...this.queryState,
27562
27967
  pending: this.runtimeSectionsEnabled(),
27563
- reconcilingSessionIds: [],
27564
- resolvedScopeKey: nextScopeKey
27968
+ reconcilingSessionIds: []
27565
27969
  };
27566
27970
  this.emit();
27567
27971
  if (this.attached) this.refreshFirstPages();
@@ -27573,7 +27977,7 @@ var AgentGUIConversationRailQueryController = class {
27573
27977
  this.searchQuery = query;
27574
27978
  this.requestSearch();
27575
27979
  }
27576
- loadMoreSectionConversations(section) {
27980
+ loadMoreSectionConversations = (section) => {
27577
27981
  const scopeKey = this.railSectionQueryKey;
27578
27982
  if (this.scope?.previewMode || !scopeKey || this.queryState.pending || this.queryState.resolvedScopeKey !== scopeKey) {
27579
27983
  return;
@@ -27660,8 +28064,8 @@ var AgentGUIConversationRailQueryController = class {
27660
28064
  this.pagingAbortControllers.delete(section.id);
27661
28065
  }
27662
28066
  });
27663
- }
27664
- loadMoreSearchResults() {
28067
+ };
28068
+ loadMoreSearchResults = () => {
27665
28069
  const listSessionsPage = this.runtime.listSessionsPage;
27666
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) {
27667
28071
  return;
@@ -27707,7 +28111,11 @@ var AgentGUIConversationRailQueryController = class {
27707
28111
  };
27708
28112
  this.emit();
27709
28113
  });
27710
- }
28114
+ };
28115
+ retrySearchResults = () => {
28116
+ if (!this.searchQuery || !this.searchEnabled()) return;
28117
+ this.requestSearch();
28118
+ };
27711
28119
  handleEngineState(state) {
27712
28120
  const next = membershipRecords(state);
27713
28121
  if (this.ingestingSessions || !this.runtimeSectionsEnabled()) {
@@ -27742,13 +28150,13 @@ var AgentGUIConversationRailQueryController = class {
27742
28150
  }
27743
28151
  this.pagingRequestSequence += 1;
27744
28152
  const requestSequence = this.pagingRequestSequence;
28153
+ const wasResolvedForScope = this.queryState.resolvedScopeKey === scopeKey && this.queryState.sections !== null;
27745
28154
  this.cancelPagingRequests(false);
27746
28155
  const abortController = new AbortController();
27747
28156
  this.pagingAbortControllers.set("__first_pages__", abortController);
27748
28157
  this.queryState = {
27749
28158
  ...this.queryState,
27750
- pending: true,
27751
- resolvedScopeKey: scopeKey
28159
+ pending: true
27752
28160
  };
27753
28161
  this.emit();
27754
28162
  void listSections({
@@ -27787,9 +28195,13 @@ var AgentGUIConversationRailQueryController = class {
27787
28195
  if (abortController.signal.aborted || requestSequence !== this.pagingRequestSequence || scopeKey !== this.railSectionQueryKey) {
27788
28196
  return;
27789
28197
  }
27790
- this.queryState = {
28198
+ this.queryState = wasResolvedForScope ? {
27791
28199
  ...this.queryState,
27792
28200
  pending: false,
28201
+ reconcilingSessionIds: []
28202
+ } : {
28203
+ pending: false,
28204
+ reconcilingSessionIds: [],
27793
28205
  resolvedScopeKey: scopeKey,
27794
28206
  sectionPageStates: /* @__PURE__ */ new Map(),
27795
28207
  sections: []
@@ -27968,14 +28380,14 @@ function useAgentGUIConversationRailQuery({
27968
28380
  workspaceId
27969
28381
  }) {
27970
28382
  const runtime = useAgentActivityRuntime();
27971
- const engine = useMemo32(
28383
+ const engine = useMemo33(
27972
28384
  () => runtime.getSessionEngine(workspaceId),
27973
28385
  [runtime, workspaceId]
27974
28386
  );
27975
28387
  const activeConversationIdRef = useRef34(activeConversationId);
27976
28388
  activeConversationIdRef.current = activeConversationId;
27977
28389
  const deferredConversationQuery = useDeferredValue(conversationQuery);
27978
- const controller = useMemo32(
28390
+ const controller = useMemo33(
27979
28391
  () => new AgentGUIConversationRailQueryController({
27980
28392
  engine,
27981
28393
  getActiveConversationId: () => activeConversationIdRef.current,
@@ -28006,27 +28418,37 @@ function useAgentGUIConversationRailQuery({
28006
28418
  identitySnapshot,
28007
28419
  Object.is
28008
28420
  );
28009
- const engineConsumerSessions = useEngineSelector(
28421
+ const runtimeRailConversations = useEngineSelector(
28010
28422
  engine,
28011
- selectWorkspaceAgentConsumerSessions4
28423
+ selectRuntimeRailConversations,
28424
+ conversationSummaryListsRenderEqual
28012
28425
  );
28013
- const runtimeRailConversations = useMemo32(
28014
- () => projectCanonicalAgentGUIConversationSummaries(engineConsumerSessions),
28015
- [engineConsumerSessions]
28016
- );
28017
- return useMemo32(
28426
+ return useMemo33(
28018
28427
  () => ({
28019
28428
  ...querySnapshot,
28020
- loadMoreSectionConversations: (section) => controller.loadMoreSectionConversations(section),
28429
+ isInteractionLocked: controller.isInteractionLocked,
28430
+ loadMoreSectionConversations: controller.loadMoreSectionConversations,
28021
28431
  railSearch: {
28022
28432
  ...querySnapshot.railSearch,
28023
- loadMore: () => controller.loadMoreSearchResults()
28433
+ loadMore: controller.loadMoreSearchResults,
28434
+ retry: controller.retrySearchResults
28024
28435
  },
28025
28436
  runtimeRailConversations
28026
28437
  }),
28027
28438
  [controller, querySnapshot, runtimeRailConversations]
28028
28439
  );
28029
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
+ }
28030
28452
  function identitySnapshot(snapshot) {
28031
28453
  return snapshot;
28032
28454
  }
@@ -28051,7 +28473,6 @@ var AgentGUIConversationRailController = memo8(
28051
28473
  ...props,
28052
28474
  conversationQuery,
28053
28475
  railQuery,
28054
- railSearch: railQuery.railSearch,
28055
28476
  onConversationQueryChange: setConversationQuery
28056
28477
  }
28057
28478
  );
@@ -28063,7 +28484,7 @@ import {
28063
28484
  memo as memo12,
28064
28485
  useCallback as useCallback45,
28065
28486
  useEffect as useEffect34,
28066
- useMemo as useMemo34,
28487
+ useMemo as useMemo35,
28067
28488
  useRef as useRef36,
28068
28489
  useState as useState31
28069
28490
  } from "react";
@@ -28072,6 +28493,18 @@ import { ScrollArea as ScrollArea2 } from "@tutti-os/ui-system/components";
28072
28493
 
28073
28494
  // agent-gui/agentGuiNode/view/agentGUIDetailModelHelpers.ts
28074
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
+ }
28075
28508
  function isDifferentKnownConversationOwner(input) {
28076
28509
  const conversationUserId = input.conversationUserId?.trim() ?? "";
28077
28510
  const currentUserId = input.currentUserId?.trim() ?? "";
@@ -28995,7 +29428,7 @@ function useAgentGUIDetailScroll(input) {
28995
29428
  }
28996
29429
 
28997
29430
  // agent-gui/agentGuiNode/view/useAgentGUIDetailModel.tsx
28998
- import { useMemo as useMemo33 } from "react";
29431
+ import { useMemo as useMemo34 } from "react";
28999
29432
 
29000
29433
  // app/renderer/components/icons/UnavailableChatIcon.tsx
29001
29434
  import { jsx as jsx54 } from "react/jsx-runtime";
@@ -29037,11 +29470,11 @@ function useAgentGUIDetailModel(input) {
29037
29470
  const emptyProviderReadinessGate = !hasActiveConversation ? selectedAgentTargetComingSoon ? { status: "coming_soon" } : viewModel.readiness.providerReadinessGate : null;
29038
29471
  const activePrompt = viewModel.interaction.pendingInteractivePrompt ?? viewModel.interaction.pendingApproval;
29039
29472
  const activePromptRequestId = activePrompt?.requestId ?? null;
29040
- const sessionChrome = useMemo33(
29473
+ const sessionChrome = useMemo34(
29041
29474
  () => ({ ...viewModel.interaction.sessionChrome, approval: null }),
29042
29475
  [viewModel.interaction.sessionChrome]
29043
29476
  );
29044
- const rawSlashStatus = useMemo33(
29477
+ const rawSlashStatus = useMemo34(
29045
29478
  () => resolveSlashStatus({
29046
29479
  rawState: viewModel.interaction.sessionChrome.rawState,
29047
29480
  limits: slashStatusLimits,
@@ -29058,7 +29491,7 @@ function useAgentGUIDetailModel(input) {
29058
29491
  ]
29059
29492
  );
29060
29493
  const slashStatus = useStableSlashStatus(rawSlashStatus);
29061
- const displayedInlineNotice = useMemo33(() => {
29494
+ const displayedInlineNotice = useMemo34(() => {
29062
29495
  const inlineNotice = viewModel.interaction.inlineNotice;
29063
29496
  const inlineNoticeMessage = inlineNotice?.message.trim() ?? "";
29064
29497
  if (!inlineNotice || inlineNoticeMessage === "") {
@@ -29082,7 +29515,7 @@ function useAgentGUIDetailModel(input) {
29082
29515
  viewModel.readiness.activeLiveState,
29083
29516
  viewModel.interaction.inlineNotice
29084
29517
  ]);
29085
- const inlineNoticeChrome = useMemo33(() => {
29518
+ const inlineNoticeChrome = useMemo34(() => {
29086
29519
  if (!displayedInlineNotice) {
29087
29520
  return null;
29088
29521
  }
@@ -29126,7 +29559,7 @@ function useAgentGUIDetailModel(input) {
29126
29559
  const submitDisabled = hasNonRetryableRecoveryFailure || isCollaboratorConversation || !isAgentProviderReady || !viewModel.composer.canSubmit && !canQueueWhileBusy;
29127
29560
  const composerDisabled = hasNonRetryableRecoveryFailure || isCollaboratorConversation || !isAgentProviderReady || !canQueueWhileBusy && (viewModel.interaction.pendingApproval !== null || viewModel.interaction.pendingInteractivePrompt !== null || viewModel.composer.isSubmitting || viewModel.composer.isInterrupting || viewModel.composer.isCreatingConversation);
29128
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);
29129
- const conversationFlowLabels = useMemo33(
29562
+ const conversationFlowLabels = useMemo34(
29130
29563
  () => ({
29131
29564
  thinkingLabel: labels.thinkingLabel,
29132
29565
  toolCallsLabel: labels.toolCallsLabel,
@@ -29142,7 +29575,7 @@ function useAgentGUIDetailModel(input) {
29142
29575
  labels.userMessageLocator
29143
29576
  ]
29144
29577
  );
29145
- const conversationFlowEmpty = useMemo33(
29578
+ const conversationFlowEmpty = useMemo34(
29146
29579
  () => showUnavailableChatEmpty ? /* @__PURE__ */ jsxs40(
29147
29580
  "div",
29148
29581
  {
@@ -29156,7 +29589,7 @@ function useAgentGUIDetailModel(input) {
29156
29589
  ) : /* @__PURE__ */ jsx55(Fragment15, {}),
29157
29590
  [labels.conversationUnavailable, showUnavailableChatEmpty]
29158
29591
  );
29159
- const chromeLabels = useMemo33(
29592
+ const chromeLabels = useMemo34(
29160
29593
  () => ({
29161
29594
  approvalRequired: labels.approvalRequired,
29162
29595
  authRequired: labels.authRequired,
@@ -29177,7 +29610,7 @@ function useAgentGUIDetailModel(input) {
29177
29610
  viewModel.composer.isCancelPending
29178
29611
  ]
29179
29612
  );
29180
- const goalBannerLabels = useMemo33(
29613
+ const goalBannerLabels = useMemo34(
29181
29614
  () => ({
29182
29615
  titleActive: labels.goalTitleActive,
29183
29616
  titlePaused: labels.goalTitlePaused,
@@ -29207,7 +29640,7 @@ function useAgentGUIDetailModel(input) {
29207
29640
  labels.goalClearAction
29208
29641
  ]
29209
29642
  );
29210
- const interactivePromptLabels = useMemo33(
29643
+ const interactivePromptLabels = useMemo34(
29211
29644
  () => ({
29212
29645
  approvalLead: labels.approvalRequired,
29213
29646
  planLead: labels.planLead,
@@ -29245,7 +29678,7 @@ function useAgentGUIDetailModel(input) {
29245
29678
  labels.planImplementationSkip
29246
29679
  ]
29247
29680
  );
29248
- const composerLabels = useMemo33(
29681
+ const composerLabels = useMemo34(
29249
29682
  () => ({
29250
29683
  send: labels.send,
29251
29684
  modelLabel: labels.modelLabel,
@@ -29571,22 +30004,9 @@ function mergeWorkspaceAppIconsFromCommands(input) {
29571
30004
  }
29572
30005
  return next ?? input.workspaceAppIcons;
29573
30006
  }
29574
- function commandAppSource(command) {
29575
- if (!command || typeof command !== "object" || !("source" in command)) {
29576
- return null;
29577
- }
29578
- const source = command.source;
29579
- if (!source || typeof source !== "object") {
29580
- return null;
29581
- }
29582
- const sourceRecord = source;
29583
- return sourceRecord.kind === "app" ? sourceRecord : null;
29584
- }
29585
- function workspaceAppIconKey(appId, workspaceId) {
29586
- return `${workspaceId}\0${appId}`;
29587
- }
29588
30007
  var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29589
30008
  viewModel,
30009
+ composerEngagement,
29590
30010
  actions,
29591
30011
  labels,
29592
30012
  workspaceUserProjectI18n,
@@ -29790,7 +30210,24 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29790
30210
  const agentTargetId = viewModel.shell.data.agentTargetId;
29791
30211
  return !agentTargetId || target.targetId === agentTargetId || target.agentTargetId === agentTargetId;
29792
30212
  }) ?? viewModel.rail.selectedAgentTarget;
29793
- 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(
29794
30231
  () => ({
29795
30232
  workspaceId: viewModel.shell.workspaceId,
29796
30233
  workspacePath: viewModel.shell.workspacePath,
@@ -29800,6 +30237,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29800
30237
  onSlashStatusOpen,
29801
30238
  usage: viewModel.detail.usage,
29802
30239
  draftContent: viewModel.composer.draftContent,
30240
+ engagement: composerEngagement,
29803
30241
  draftScopeKey: resolveAgentComposerDraftScopeKey({
29804
30242
  agentSessionId: viewModel.rail.activeConversationId
29805
30243
  }),
@@ -29825,8 +30263,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29825
30263
  showStopButton,
29826
30264
  previewMode,
29827
30265
  workspaceReferencePickerOpen,
29828
- // Plan decisions replace the composer via bottomDockReplacementPrompt;
29829
- // approval / ask-user embed here (composerActivePrompt encodes that).
30266
+ // Plan decisions replace the composer; approval / ask-user embed here.
29830
30267
  activePrompt: composerActivePrompt,
29831
30268
  backgroundAgentStatusText,
29832
30269
  activePromptKeyboardShortcutsEnabled: isActive,
@@ -29857,21 +30294,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29857
30294
  onSubmitInteractivePrompt: submitInteractivePrompt,
29858
30295
  onCapabilitySettingsRequest,
29859
30296
  onLinkAction: stableLinkAction,
29860
- onHandoffConversation: onHandoffConversation && viewModel.rail.activeConversationId !== null ? (target) => onHandoffConversation({
29861
- agentTargetId: target.agentTargetId ?? target.targetId,
29862
- draftPrompt: buildAgentConversationHandoffPrompt({
29863
- activeConversation: viewModel.rail.activeConversation,
29864
- currentUserId: viewModel.shell.currentUserId,
29865
- labels,
29866
- selectedAgentTarget: composerSelectedProviderTarget,
29867
- uiLanguage,
29868
- workspaceId: viewModel.shell.workspaceId
29869
- }),
29870
- provider: target.provider,
29871
- userProjectPath: handoffProjectPathForConversation(
29872
- viewModel.rail.activeConversation
29873
- )
29874
- }) : void 0,
30297
+ onHandoffConversation: stableHandoffConversation,
29875
30298
  onRequestWorkspaceReferences: stableRequestWorkspaceReferences,
29876
30299
  resolveDroppedFileReferences,
29877
30300
  selectProjectDirectory: stableSelectProjectDirectory,
@@ -29886,6 +30309,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29886
30309
  composerDisabled,
29887
30310
  composerDisabledReason,
29888
30311
  composerFocusRequestSequence,
30312
+ composerEngagement,
29889
30313
  composerHandoffProviderTargets,
29890
30314
  composerLabels,
29891
30315
  composerProviderTargets,
@@ -29901,7 +30325,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29901
30325
  labels.promptTips,
29902
30326
  labels.providerSwitchLabel,
29903
30327
  labels,
29904
- onHandoffConversation,
30328
+ stableHandoffConversation,
29905
30329
  onSlashStatusOpen,
29906
30330
  previewMode,
29907
30331
  workspaceReferencePickerOpen,
@@ -29952,7 +30376,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29952
30376
  selectHomeComposerAgentTargetAndFocus
29953
30377
  ]
29954
30378
  );
29955
- const emptyHeroComposerProps = useMemo34(
30379
+ const emptyHeroComposerProps = useMemo35(
29956
30380
  () => ({
29957
30381
  ...bottomDockComposerProps,
29958
30382
  layoutMode: "hero"
@@ -30146,10 +30570,14 @@ var AgentGUIRenameConversationDialog = memo13(
30146
30570
  "use memo";
30147
30571
  const [title, setTitle] = useState32("");
30148
30572
  const [isSaving, setIsSaving] = useState32(false);
30573
+ const isSavingRef = useRef37(false);
30574
+ const armedPointerActionRef = useRef37(null);
30149
30575
  const inputRef = useRef37(null);
30150
30576
  const trimmedTitle = title.trim();
30151
30577
  useEffect35(() => {
30152
30578
  if (!open || !conversation) {
30579
+ isSavingRef.current = false;
30580
+ armedPointerActionRef.current = null;
30153
30581
  setTitle("");
30154
30582
  setIsSaving(false);
30155
30583
  return;
@@ -30167,23 +30595,25 @@ var AgentGUIRenameConversationDialog = memo13(
30167
30595
  return () => window.clearTimeout(timer);
30168
30596
  }, [open, conversation?.id]);
30169
30597
  const closeRenameDialog = useCallback46(() => {
30170
- if (!isSaving) {
30598
+ if (!isSavingRef.current) {
30171
30599
  onOpenChange(false);
30172
30600
  }
30173
- }, [isSaving, onOpenChange]);
30601
+ }, [onOpenChange]);
30174
30602
  const confirmRename = useCallback46(() => {
30175
- if (!conversation || isSaving || !trimmedTitle) {
30603
+ if (!conversation || isSavingRef.current || !trimmedTitle) {
30176
30604
  return;
30177
30605
  }
30606
+ isSavingRef.current = true;
30178
30607
  setIsSaving(true);
30179
30608
  void onRename(conversation.id, trimmedTitle).then(() => {
30180
30609
  onOpenChange(false);
30181
30610
  }).catch(() => {
30182
30611
  inputRef.current?.focus();
30183
30612
  }).finally(() => {
30613
+ isSavingRef.current = false;
30184
30614
  setIsSaving(false);
30185
30615
  });
30186
- }, [conversation, isSaving, onOpenChange, onRename, trimmedTitle]);
30616
+ }, [conversation, onOpenChange, onRename, trimmedTitle]);
30187
30617
  return /* @__PURE__ */ jsx57(
30188
30618
  ConfirmationDialog2,
30189
30619
  {
@@ -30202,8 +30632,30 @@ var AgentGUIRenameConversationDialog = memo13(
30202
30632
  type: "button",
30203
30633
  variant: "ghost",
30204
30634
  onClick: closeRenameDialog,
30205
- 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) => {
30206
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) {
30207
30659
  closeRenameDialog();
30208
30660
  }
30209
30661
  },
@@ -30218,7 +30670,45 @@ var AgentGUIRenameConversationDialog = memo13(
30218
30670
  size: "dialog",
30219
30671
  type: "button",
30220
30672
  variant: "default",
30221
- 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
+ },
30222
30712
  children: labels.renameSessionSave
30223
30713
  }
30224
30714
  )
@@ -30250,7 +30740,7 @@ var AgentGUIRenameConversationDialog = memo13(
30250
30740
  );
30251
30741
 
30252
30742
  // agent-gui/agentGuiNode/view/useAgentGUIWorkspaceReferencePicker.ts
30253
- 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";
30254
30744
  import { createRichTextMentionHref } from "@tutti-os/ui-rich-text/core";
30255
30745
  function useAgentGUIWorkspaceReferencePicker(input) {
30256
30746
  const {
@@ -30266,7 +30756,7 @@ function useAgentGUIWorkspaceReferencePicker(input) {
30266
30756
  const [workspaceReferencePickerOpen, setWorkspaceReferencePickerOpen] = useState33(false);
30267
30757
  const [workspaceReferencePickerTarget, setWorkspaceReferencePickerTarget] = useState33(null);
30268
30758
  const workspaceReferencePickerResolverRef = useRef38(null);
30269
- const emptyReferencePickResult = useMemo35(
30759
+ const emptyReferencePickResult = useMemo36(
30270
30760
  () => ({ files: [], mentionItems: [] }),
30271
30761
  []
30272
30762
  );
@@ -30379,9 +30869,256 @@ function useAgentGUIWorkspaceReferencePicker(input) {
30379
30869
  };
30380
30870
  }
30381
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
+
30382
31120
  // agent-gui/agentGuiNode/AgentGUINodeView.tsx
30383
31121
  import { jsx as jsx58, jsxs as jsxs43 } from "react/jsx-runtime";
30384
- var EMPTY_WORKSPACE_APP_ICONS5 = [];
30385
31122
  function AgentGUINodeView({
30386
31123
  viewModel,
30387
31124
  renderSidebarFooter,
@@ -30393,6 +31130,8 @@ function AgentGUINodeView({
30393
31130
  capabilityMenuState,
30394
31131
  onCapabilitySettingsRequest,
30395
31132
  isActive = true,
31133
+ isVisible = true,
31134
+ onEngagementEvent,
30396
31135
  composerFocusRequestSequence = null,
30397
31136
  newConversationRequestSequence = null,
30398
31137
  isAgentProviderReady,
@@ -30434,12 +31173,19 @@ function AgentGUINodeView({
30434
31173
  resolveWorkspaceReferenceEntryIconUrl,
30435
31174
  resolveMentionReferenceTarget = null,
30436
31175
  resolveWorkspaceReferenceInitialTarget = null,
30437
- workspaceAppIcons = EMPTY_WORKSPACE_APP_ICONS5
31176
+ workspaceAppIcons = EMPTY_WORKSPACE_APP_ICONS4
30438
31177
  }) {
30439
31178
  "use memo";
30440
- const layoutElementRef = useRef39(null);
31179
+ const { composerEngagement, layoutElementRef } = useAgentGUINodeEngagement({
31180
+ composerReady: isAgentProviderReady,
31181
+ isActive,
31182
+ isVisible,
31183
+ onEvent: onEngagementEvent,
31184
+ previewMode,
31185
+ viewModel
31186
+ });
30441
31187
  const [providerManagerOpen, setProviderManagerOpen] = useState34(false);
30442
- const railResizeInteractionRef = useRef39(null);
31188
+ const railResizeInteractionRef = useRef41(null);
30443
31189
  const [isRailResizing, setIsRailResizing] = useState34(false);
30444
31190
  const [railResizeWidthPx, setRailResizeWidthPx] = useState34(
30445
31191
  null
@@ -30448,7 +31194,7 @@ function AgentGUINodeView({
30448
31194
  localComposerFocusRequestSequence,
30449
31195
  setLocalComposerFocusRequestSequence
30450
31196
  ] = useState34(0);
30451
- const handledNewConversationRequestSequenceRef = useRef39(
31197
+ const handledNewConversationRequestSequenceRef = useRef41(
30452
31198
  newConversationRequestSequence
30453
31199
  );
30454
31200
  const {
@@ -30526,7 +31272,7 @@ function AgentGUINodeView({
30526
31272
  viewModel.composer.composerSettings.selectedProjectPath
30527
31273
  ]
30528
31274
  );
30529
- useEffect36(() => {
31275
+ useEffect37(() => {
30530
31276
  if (newConversationRequestSequence === null || handledNewConversationRequestSequenceRef.current === newConversationRequestSequence) {
30531
31277
  return;
30532
31278
  }
@@ -30539,7 +31285,7 @@ function AgentGUINodeView({
30539
31285
  newConversationRequestSequence,
30540
31286
  requestCreateConversation
30541
31287
  ]);
30542
- const effectiveWorkspaceAppIcons = useMemo36(
31288
+ const effectiveWorkspaceAppIcons = useMemo37(
30543
31289
  () => mergeWorkspaceAppIconsFromCommands({
30544
31290
  commands: viewModel.composer.availableCommands,
30545
31291
  workspaceAppIcons,
@@ -30620,7 +31366,7 @@ function AgentGUINodeView({
30620
31366
  },
30621
31367
  [onConversationRailWidthChanged]
30622
31368
  );
30623
- useEffect36(() => {
31369
+ useEffect37(() => {
30624
31370
  if (isRailResizing || railResizeWidthPx === null) {
30625
31371
  return;
30626
31372
  }
@@ -30677,7 +31423,7 @@ function AgentGUINodeView({
30677
31423
  const environmentSetupVisible = !!resolveAgentGUIProviderCatalogIdentity(
30678
31424
  effectiveRailConfigProvider ?? ""
30679
31425
  );
30680
- const effectiveProviderAuthAccountLabel = useMemo36(() => {
31426
+ const effectiveProviderAuthAccountLabel = useMemo37(() => {
30681
31427
  const provider = (effectiveRailConfigProvider ?? viewModel.shell.data.provider)?.trim() ?? "";
30682
31428
  if (!provider) {
30683
31429
  return null;
@@ -30708,7 +31454,7 @@ function AgentGUINodeView({
30708
31454
  },
30709
31455
  []
30710
31456
  );
30711
- const conversationRailStoreState = useMemo36(
31457
+ const conversationRailStoreState = useMemo37(
30712
31458
  () => ({
30713
31459
  activeConversation: viewModel.rail.activeConversation,
30714
31460
  activeConversationId: viewModel.rail.activeConversationId,
@@ -30777,7 +31523,7 @@ function AgentGUINodeView({
30777
31523
  workspaceUserProjectI18n
30778
31524
  ]
30779
31525
  );
30780
- const agentTargetPresentations = useMemo36(
31526
+ const agentTargetPresentations = useMemo37(
30781
31527
  () => viewModel.rail.agentTargets.flatMap(
30782
31528
  (target) => target.agentTargetId ? [
30783
31529
  {
@@ -30947,6 +31693,7 @@ function AgentGUINodeView({
30947
31693
  AgentGUIDetailPane,
30948
31694
  {
30949
31695
  viewModel,
31696
+ composerEngagement,
30950
31697
  actions,
30951
31698
  labels,
30952
31699
  uiLanguage,
@@ -31199,9 +31946,9 @@ function appendDockProbeUsageLines(probe, lines, isLoadingUsage, t) {
31199
31946
  import { Info as Info3 } from "lucide-react";
31200
31947
  import {
31201
31948
  useCallback as useCallback49,
31202
- useEffect as useEffect37,
31949
+ useEffect as useEffect38,
31203
31950
  useLayoutEffect as useLayoutEffect8,
31204
- useRef as useRef40,
31951
+ useRef as useRef42,
31205
31952
  useState as useState35
31206
31953
  } from "react";
31207
31954
  import { createPortal as createPortal5 } from "react-dom";
@@ -31239,8 +31986,8 @@ function AgentProbeInfoPopover({
31239
31986
  onOpen
31240
31987
  }) {
31241
31988
  "use memo";
31242
- const anchorRef = useRef40(null);
31243
- const popoverRef = useRef40(null);
31989
+ const anchorRef = useRef42(null);
31990
+ const popoverRef = useRef42(null);
31244
31991
  const [isOpen, setIsOpen] = useState35(false);
31245
31992
  const [popoverStyle, setPopoverStyle] = useState35(null);
31246
31993
  const openPopover = useCallback49(() => {
@@ -31282,7 +32029,7 @@ function AgentProbeInfoPopover({
31282
32029
  maxWidth: availableWidth
31283
32030
  });
31284
32031
  }, []);
31285
- useEffect37(() => {
32032
+ useEffect38(() => {
31286
32033
  if (!isOpen) {
31287
32034
  return;
31288
32035
  }
@@ -31568,11 +32315,11 @@ function areAgentGUINodePropsEqual(previous, next) {
31568
32315
  const pc = previous.hostCapabilities, nc = next.hostCapabilities;
31569
32316
  const pa = previous.hostActions, na = next.hostActions;
31570
32317
  const ps = previous.renderSlots, ns = next.renderSlots;
31571
- 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;
31572
32319
  }
31573
32320
 
31574
32321
  // agent-gui/agentGuiNode/AgentGUINode.labels.ts
31575
- import { useMemo as useMemo37 } from "react";
32322
+ import { useMemo as useMemo38 } from "react";
31576
32323
 
31577
32324
  // agent-gui/agentGuiNode/model/agentHomeSuggestions.ts
31578
32325
  import { createRichTextMentionHref as createRichTextMentionHref2 } from "@tutti-os/ui-rich-text/core";
@@ -31630,6 +32377,26 @@ function buildAgentHomeSuggestions(t, workspaceId, workspaceAppIcons, disabled =
31630
32377
  return categories.filter((category) => !disabledIds.has(category.id));
31631
32378
  }
31632
32379
 
32380
+ // agent-gui/agentGuiNode/view/agentGUIConversationRailLabels.ts
32381
+ function agentGUIConversationRailLabels(t) {
32382
+ return {
32383
+ conversationUnavailable: t("agentHost.agentGui.conversationUnavailable"),
32384
+ emptyProjectConversations: t(
32385
+ "agentHost.agentGui.emptyProjectConversations"
32386
+ ),
32387
+ loadingConversations: t("agentHost.agentGui.loadingConversations"),
32388
+ noConversations: t("agentHost.agentGui.noConversations"),
32389
+ retrySearch: t("agentHost.agentGui.retrySearch"),
32390
+ searchFailed: t("agentHost.agentGui.searchFailed"),
32391
+ searchNoConversations: t("agentHost.agentGui.searchNoConversations"),
32392
+ searchPlaceholder: t("agentHost.agentGui.searchPlaceholder"),
32393
+ sectionConversations: t("agentHost.agentGui.sectionConversations"),
32394
+ sectionPinned: t("agentHost.agentGui.sectionPinned"),
32395
+ selectConversation: t("agentHost.agentGui.selectConversation"),
32396
+ startConversation: t("agentHost.agentGui.startConversation")
32397
+ };
32398
+ }
32399
+
31633
32400
  // agent-gui/agentGuiNode/view/agentGUIProviderManagerLabels.ts
31634
32401
  function agentGUIProviderManagerLabels(t) {
31635
32402
  return {
@@ -31699,7 +32466,7 @@ function useAgentGUIViewLabels(input) {
31699
32466
  workspaceAppIcons,
31700
32467
  workspaceId
31701
32468
  } = input;
31702
- return useMemo37(
32469
+ return useMemo38(
31703
32470
  () => ({
31704
32471
  initialPlaceholder: t("agentHost.agentGui.initialPlaceholder", {
31705
32472
  provider: displayProviderLabel
@@ -31942,10 +32709,7 @@ function useAgentGUIViewLabels(input) {
31942
32709
  agentSettingsMenu: t("agentHost.agentGui.agentSettingsMenu"),
31943
32710
  agentEnvSetup: t("agentHost.agentGui.agentEnvSetup"),
31944
32711
  ...agentGUIProviderManagerLabels(t),
31945
- noConversations: t("agentHost.agentGui.noConversations"),
31946
- emptyProjectConversations: t(
31947
- "agentHost.agentGui.emptyProjectConversations"
31948
- ),
32712
+ ...agentGUIConversationRailLabels(t),
31949
32713
  conversationFilterAll: t("agentHost.agentGui.conversationFilterAll"),
31950
32714
  conversationFilterCodex: t("agentHost.agentGui.conversationFilterCodex"),
31951
32715
  conversationFilterClaudeCode: t(
@@ -31953,17 +32717,9 @@ function useAgentGUIViewLabels(input) {
31953
32717
  ),
31954
32718
  conversationFilterTutti: t("agentHost.agentGui.conversationFilterTutti"),
31955
32719
  providerSwitchLabel: t("agentHost.agentGui.providerSwitchLabel"),
31956
- startConversation: t("agentHost.agentGui.startConversation"),
31957
- selectConversation: t("agentHost.agentGui.selectConversation"),
31958
- loadingConversations: t("agentHost.agentGui.loadingConversations"),
31959
32720
  loadingConversation: t("agentHost.agentGui.loadingConversation"),
31960
32721
  scrollToBottom: t("agentHost.agentGui.scrollToBottom"),
31961
- searchNoConversations: t("agentHost.agentGui.searchNoConversations"),
31962
- conversationUnavailable: t("agentHost.agentGui.conversationUnavailable"),
31963
32722
  fallbackAgentTitle,
31964
- searchPlaceholder: t("agentHost.agentGui.searchPlaceholder"),
31965
- sectionPinned: t("agentHost.agentGui.sectionPinned"),
31966
- sectionConversations: t("agentHost.agentGui.sectionConversations"),
31967
32723
  sectionToday: t("agentHost.agentGui.sectionToday"),
31968
32724
  sectionYesterday: t("agentHost.agentGui.sectionYesterday"),
31969
32725
  sectionEarlier: t("agentHost.agentGui.sectionEarlier"),
@@ -32305,7 +33061,7 @@ function useAgentGUIViewLabels(input) {
32305
33061
  );
32306
33062
  }
32307
33063
  function useAgentGUIWorkspaceFileReferenceCopy(t) {
32308
- return useMemo37(
33064
+ return useMemo38(
32309
33065
  () => ({
32310
33066
  t(key, values) {
32311
33067
  const localeKey = workspaceFileReferenceLocaleKeyByPickerKey[key];
@@ -32376,69 +33132,6 @@ function slashStatusLimitsFromQuotas(quotas, selectedModel, t) {
32376
33132
  };
32377
33133
  }).filter((limit) => limit !== null);
32378
33134
  }
32379
- function slashStatusQuotasFromCanonicalUsage(usage) {
32380
- if (!usage) {
32381
- return [];
32382
- }
32383
- return usage.quotas.map((quota) => {
32384
- const record = objectRecord2(quota);
32385
- const quotaType = agentUsageQuotaTypeValue(record?.quotaType);
32386
- if (!record || !quotaType) {
32387
- return null;
32388
- }
32389
- const normalized = { quotaType };
32390
- const percentRemaining = numberValue2(record.percentRemaining);
32391
- if (percentRemaining !== null) {
32392
- normalized.percentRemaining = percentRemaining;
32393
- }
32394
- const resetsAtUnixMs = numberValue2(record.resetsAtUnixMs);
32395
- if (resetsAtUnixMs !== null) {
32396
- normalized.resetsAtUnixMs = resetsAtUnixMs;
32397
- }
32398
- const resetText = stringValue3(record.resetText);
32399
- if (resetText) {
32400
- normalized.resetText = resetText;
32401
- }
32402
- const dollarRemaining = numberValue2(record.dollarRemaining);
32403
- if (dollarRemaining !== null) {
32404
- normalized.dollarRemaining = dollarRemaining;
32405
- }
32406
- const modelName = stringValue3(record.modelName);
32407
- if (modelName) {
32408
- normalized.modelName = modelName;
32409
- }
32410
- return normalized;
32411
- }).filter((quota) => quota !== null);
32412
- }
32413
- function agentUsageQuotaTypeValue(value) {
32414
- switch (stringValue3(value)) {
32415
- case "session":
32416
- case "weekly":
32417
- case "monthly":
32418
- case "daily":
32419
- case "model":
32420
- case "cost":
32421
- return stringValue3(value);
32422
- default:
32423
- return null;
32424
- }
32425
- }
32426
- function objectRecord2(value) {
32427
- return value && typeof value === "object" ? value : null;
32428
- }
32429
- function numberValue2(value) {
32430
- if (typeof value === "number" && Number.isFinite(value)) {
32431
- return value;
32432
- }
32433
- if (typeof value === "string" && value.trim()) {
32434
- const parsed = Number(value);
32435
- return Number.isFinite(parsed) ? parsed : null;
32436
- }
32437
- return null;
32438
- }
32439
- function stringValue3(value) {
32440
- return typeof value === "string" ? value.trim() : "";
32441
- }
32442
33135
  function filterSlashStatusQuotasForModel(quotas, selectedModel) {
32443
33136
  const normalizedSelectedModel = normalizeSlashStatusModelName(selectedModel);
32444
33137
  const baseQuotas = (quotas ?? []).filter(
@@ -32466,6 +33159,7 @@ function resolveAgentGUIRailStatusProvider(input) {
32466
33159
 
32467
33160
  // agent-gui/agentGuiNode/AgentGUINode.tsx
32468
33161
  import { jsx as jsx60, jsxs as jsxs45 } from "react/jsx-runtime";
33162
+ var EMPTY_SLASH_STATUS_QUOTAS = [];
32469
33163
  var AgentGUINode = memo14(function AgentGUINode2({
32470
33164
  identity,
32471
33165
  workspace,
@@ -32498,6 +33192,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32498
33192
  desktopSize,
32499
33193
  isMaximized = false,
32500
33194
  isActive,
33195
+ isVisible = true,
32501
33196
  embedded = false,
32502
33197
  previewMode = false,
32503
33198
  conversationRailAutoCollapseWidthPx = null
@@ -32541,7 +33236,8 @@ var AgentGUINode = memo14(function AgentGUINode2({
32541
33236
  isMuted = false,
32542
33237
  onMinimize,
32543
33238
  onToggleMaximize,
32544
- onShowMessage
33239
+ onShowMessage,
33240
+ onEngagementEvent
32545
33241
  } = hostActions;
32546
33242
  const {
32547
33243
  providerRailEmpty: renderProviderRailEmpty,
@@ -32549,22 +33245,19 @@ var AgentGUINode = memo14(function AgentGUINode2({
32549
33245
  sidebarFooter: renderSidebarFooter
32550
33246
  } = renderSlots;
32551
33247
  const { i18n, locale, t } = useTranslation();
32552
- const workspaceUserProjectI18n = useMemo38(
33248
+ const workspaceUserProjectI18n = useMemo39(
32553
33249
  () => createWorkspaceUserProjectI18nRuntime(i18n),
32554
33250
  [i18n]
32555
33251
  );
32556
- const workspaceFileManagerI18n = useMemo38(
33252
+ const workspaceFileManagerI18n = useMemo39(
32557
33253
  () => typeof i18n?.t === "function" ? createWorkspaceFileManagerI18nRuntime(i18n) : null,
32558
33254
  [i18n]
32559
33255
  );
32560
33256
  const handleLinkAction = useCallback50(
32561
33257
  (action) => {
32562
- const agentTargetId = state.agentTargetId?.trim() || null;
32563
- onLinkAction?.(
32564
- action.type === "open-agent-session" && !action.agentTargetId && agentTargetId ? { ...action, agentTargetId } : action
32565
- );
33258
+ onLinkAction?.(action);
32566
33259
  },
32567
- [onLinkAction, state.agentTargetId]
33260
+ [onLinkAction]
32568
33261
  );
32569
33262
  const handleAgentProviderLogin = useCallback50(
32570
33263
  (provider) => {
@@ -32618,7 +33311,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32618
33311
  const isConversationRailManuallyCollapsed = state.conversationRailCollapsed === true;
32619
33312
  const isConversationRailAutoCollapsed = shouldAutoCollapseAgentGUIConversationRail(width, railAutoCollapseWidthPx);
32620
33313
  const isConversationRailCollapsed = isConversationRailManuallyCollapsed || isConversationRailAutoCollapsed;
32621
- const minSize = useMemo38(
33314
+ const minSize = useMemo39(
32622
33315
  () => ({
32623
33316
  ...resolveCanonicalNodeMinSize("agentGui"),
32624
33317
  width: AGENT_GUI_COLLAPSED_MIN_WIDTH_PX
@@ -32706,7 +33399,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32706
33399
  },
32707
33400
  [actions, onUpdateNode, previewMode]
32708
33401
  );
32709
- const viewActions = useMemo38(
33402
+ const viewActions = useMemo39(
32710
33403
  () => ({
32711
33404
  ...actions,
32712
33405
  createConversation: handleCreateConversation
@@ -32729,28 +33422,28 @@ var AgentGUINode = memo14(function AgentGUINode2({
32729
33422
  const workspaceFileReferenceCopy = useAgentGUIWorkspaceFileReferenceCopy(t);
32730
33423
  const windowTitle = title;
32731
33424
  const activeProbeProvider = activeProvider;
32732
- const railStatusProvider = useMemo38(
33425
+ const railStatusProvider = useMemo39(
32733
33426
  () => resolveAgentGUIRailStatusProvider({
32734
33427
  conversationFilter: viewModel.rail.conversationFilter,
32735
33428
  agentTargets: viewModel.rail.agentTargets
32736
33429
  }),
32737
33430
  [viewModel.rail.conversationFilter, viewModel.rail.agentTargets]
32738
33431
  );
32739
- const activeAgentProbe = useMemo38(
33432
+ const activeAgentProbe = useMemo39(
32740
33433
  () => findWorkspaceAgentProbeForDockProvider(
32741
33434
  workspaceAgentProbes?.snapshot ?? null,
32742
33435
  activeProbeProvider
32743
33436
  ),
32744
33437
  [activeProbeProvider, workspaceAgentProbes?.snapshot]
32745
33438
  );
32746
- const railAgentProbe = useMemo38(
33439
+ const railAgentProbe = useMemo39(
32747
33440
  () => railStatusProvider ? findWorkspaceAgentProbeForDockProvider(
32748
33441
  workspaceAgentProbes?.snapshot ?? null,
32749
33442
  railStatusProvider
32750
33443
  ) : null,
32751
33444
  [railStatusProvider, workspaceAgentProbes?.snapshot]
32752
33445
  );
32753
- const isActiveAgentProviderReady = useMemo38(() => {
33446
+ const isActiveAgentProviderReady = useMemo39(() => {
32754
33447
  const managedAgent = getAgentHostManagedToolchainAgentByName(
32755
33448
  activeReadinessProvider
32756
33449
  );
@@ -32765,11 +33458,9 @@ var AgentGUINode = memo14(function AgentGUINode2({
32765
33458
  managedAgentsState
32766
33459
  ) === "installed";
32767
33460
  }, [activeReadinessProvider, managedAgentsState]);
32768
- const canonicalSlashStatusQuotas = slashStatusQuotasFromCanonicalUsage(
32769
- viewModel.detail.usage
32770
- );
32771
- const slashStatusQuotaSource = canonicalSlashStatusQuotas.length > 0 ? canonicalSlashStatusQuotas : activeAgentProbe?.usage?.quotas && activeAgentProbe.usage.quotas.length > 0 ? activeAgentProbe.usage.quotas : [];
32772
- 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(
32773
33464
  () => slashStatusLimitsFromQuotas(
32774
33465
  slashStatusQuotaSource,
32775
33466
  viewModel.composer.composerSettings.selectedModelValue ?? viewModel.composer.composerSettings.draftSettings.model,
@@ -32783,8 +33474,8 @@ var AgentGUINode = memo14(function AgentGUINode2({
32783
33474
  ]
32784
33475
  );
32785
33476
  const slashStatusLimitsUnavailable = slashStatusLimits.length === 0 && canonicalSlashStatusQuotas.length === 0 && !(workspaceAgentProbes?.isLoadingUsage ?? false) && (Boolean(activeAgentProbe?.usage) || Boolean(activeAgentProbe?.lastError));
32786
- const railSlashStatusQuotaSource = railStatusProvider && railAgentProbe?.usage?.quotas && railAgentProbe.usage.quotas.length > 0 ? railAgentProbe.usage.quotas : [];
32787
- 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(
32788
33479
  () => slashStatusLimitsFromQuotas(railSlashStatusQuotaSource, null, t),
32789
33480
  [railSlashStatusQuotaSource, t]
32790
33481
  );
@@ -32792,7 +33483,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32792
33483
  const slashStatusUsageCapturedAtUnixMs = slashStatusUsageProbe?.usage?.capturedAtUnixMs ?? null;
32793
33484
  const slashStatusUsageDidFail = workspaceAgentProbes?.usageLoadFailed ?? false;
32794
33485
  const slashStatusUsageAttempted = Boolean(slashStatusUsageProbe?.usage) || Boolean(slashStatusUsageProbe?.lastError);
32795
- const agentProbeLines = useMemo38(() => {
33486
+ const agentProbeLines = useMemo39(() => {
32796
33487
  return buildDockAgentProbeTooltipLines(
32797
33488
  activeAgentProbe,
32798
33489
  workspaceAgentProbes?.isLoadingAvailability ?? false,
@@ -32808,7 +33499,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32808
33499
  workspaceAgentProbes?.isLoadingUsage,
32809
33500
  t
32810
33501
  ]);
32811
- useEffect38(() => {
33502
+ useEffect39(() => {
32812
33503
  if (previewMode || !onAgentProbeDemandChange) {
32813
33504
  return;
32814
33505
  }
@@ -32818,7 +33509,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32818
33509
  onAgentProbeDemandChange(null, probeSourceId);
32819
33510
  };
32820
33511
  }, [activeProbeProvider, nodeId, onAgentProbeDemandChange, previewMode]);
32821
- useEffect38(() => {
33512
+ useEffect39(() => {
32822
33513
  if (previewMode || !onAgentProbeDemandChange || !railStatusProvider || railStatusProvider === activeProbeProvider) {
32823
33514
  return;
32824
33515
  }
@@ -32942,6 +33633,8 @@ var AgentGUINode = memo14(function AgentGUINode2({
32942
33633
  providerRailAllPresentation,
32943
33634
  actions: viewActions,
32944
33635
  isActive,
33636
+ isVisible,
33637
+ onEngagementEvent,
32945
33638
  composerFocusRequestSequence,
32946
33639
  newConversationRequestSequence,
32947
33640
  isAgentProviderReady: isActiveAgentProviderReady,
@@ -33051,4 +33744,4 @@ export {
33051
33744
  resolveAgentGUIAgentTarget,
33052
33745
  AgentGUI
33053
33746
  };
33054
- //# sourceMappingURL=chunk-WKSFPJHZ.js.map
33747
+ //# sourceMappingURL=chunk-7O4D4KOE.js.map