@tutti-os/agent-gui 0.0.97 → 0.0.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/{AgentGUI-DWdvUV4x.d.ts → AgentGUI-Bkk2TRS0.d.ts} +37 -2
  2. package/dist/agent-conversation/index.d.ts +1 -1
  3. package/dist/agent-conversation/index.js +6 -6
  4. package/dist/agent-gui.d.ts +2 -2
  5. package/dist/agent-gui.js +15 -15
  6. package/dist/agent-message-center/index.js +7 -16
  7. package/dist/agent-message-center/index.js.map +1 -1
  8. package/dist/{agentGuiNodeTypes-B9X4aWfv.d.ts → agentGuiNodeTypes-DAsluxjv.d.ts} +1 -1
  9. package/dist/app/renderer/agentactivity.css +80 -10
  10. package/dist/{chunk-AO2FDYAL.js → chunk-3NOJFKDV.js} +3 -3
  11. package/dist/{chunk-XGGKHIQA.js → chunk-4ROALW3K.js} +2 -2
  12. package/dist/{chunk-4VBKQY24.js → chunk-63BE6RGM.js} +3 -3
  13. package/dist/{chunk-AAFTWZV7.js → chunk-7M77BK6K.js} +54 -91
  14. package/dist/chunk-7M77BK6K.js.map +1 -0
  15. package/dist/{chunk-4YVGHJIE.js → chunk-CPUEPDF7.js} +2 -2
  16. package/dist/{chunk-K2NURZ7V.js → chunk-FSKGEGGX.js} +11 -3
  17. package/dist/chunk-FSKGEGGX.js.map +1 -0
  18. package/dist/{chunk-NRJEKWLY.js → chunk-GAD6Y3BF.js} +2 -2
  19. package/dist/{chunk-3RYZYA72.js → chunk-J7ZYAUPC.js} +4 -4
  20. package/dist/{chunk-RE4AXS27.js → chunk-MRRICFWA.js} +2 -2
  21. package/dist/{chunk-74CPYRWJ.js → chunk-OTRZBTFQ.js} +2 -2
  22. package/dist/{chunk-BIS4QRX7.js → chunk-PLCHNOXL.js} +1321 -657
  23. package/dist/chunk-PLCHNOXL.js.map +1 -0
  24. package/dist/{chunk-TVIGLNNI.js → chunk-QWGJ5TEG.js} +4 -1
  25. package/dist/chunk-QWGJ5TEG.js.map +1 -0
  26. package/dist/{chunk-3EAANCKF.js → chunk-RHTZAODZ.js} +2 -2
  27. package/dist/{chunk-P2BCMPTX.js → chunk-SPZJCTBV.js} +3 -3
  28. package/dist/{chunk-SQTSLCMV.js → chunk-T6PEJFRP.js} +2 -2
  29. package/dist/{chunk-Y57VNTVM.js → chunk-Y5M6Q6WX.js} +2 -2
  30. package/dist/context-mention-palette/index.js +8 -8
  31. package/dist/i18n/index.d.ts +10 -2
  32. package/dist/i18n/index.js +2 -2
  33. package/dist/index.d.ts +4 -4
  34. package/dist/index.js +15 -15
  35. package/dist/index.js.map +1 -1
  36. package/dist/mention-search.js +6 -6
  37. package/dist/workbench/contribution.js +2 -2
  38. package/dist/workbench/index.js +5 -5
  39. package/dist/workbench/launch.js +1 -1
  40. package/dist/workbench/sessionTitle.js +3 -3
  41. package/dist/workspace-agent-generated-files.js +4 -4
  42. package/package.json +12 -12
  43. package/dist/chunk-AAFTWZV7.js.map +0 -1
  44. package/dist/chunk-BIS4QRX7.js.map +0 -1
  45. package/dist/chunk-K2NURZ7V.js.map +0 -1
  46. package/dist/chunk-TVIGLNNI.js.map +0 -1
  47. /package/dist/{chunk-AO2FDYAL.js.map → chunk-3NOJFKDV.js.map} +0 -0
  48. /package/dist/{chunk-XGGKHIQA.js.map → chunk-4ROALW3K.js.map} +0 -0
  49. /package/dist/{chunk-4VBKQY24.js.map → chunk-63BE6RGM.js.map} +0 -0
  50. /package/dist/{chunk-4YVGHJIE.js.map → chunk-CPUEPDF7.js.map} +0 -0
  51. /package/dist/{chunk-NRJEKWLY.js.map → chunk-GAD6Y3BF.js.map} +0 -0
  52. /package/dist/{chunk-3RYZYA72.js.map → chunk-J7ZYAUPC.js.map} +0 -0
  53. /package/dist/{chunk-RE4AXS27.js.map → chunk-MRRICFWA.js.map} +0 -0
  54. /package/dist/{chunk-74CPYRWJ.js.map → chunk-OTRZBTFQ.js.map} +0 -0
  55. /package/dist/{chunk-3EAANCKF.js.map → chunk-RHTZAODZ.js.map} +0 -0
  56. /package/dist/{chunk-P2BCMPTX.js.map → chunk-SPZJCTBV.js.map} +0 -0
  57. /package/dist/{chunk-SQTSLCMV.js.map → chunk-T6PEJFRP.js.map} +0 -0
  58. /package/dist/{chunk-Y57VNTVM.js.map → chunk-Y5M6Q6WX.js.map} +0 -0
@@ -9,7 +9,7 @@ import {
9
9
  resolveAgentGuiSessionProviderFlatIconUrl,
10
10
  resolveNextAgentGUIConversationRailWidthPx,
11
11
  shouldAutoCollapseAgentGUIConversationRail
12
- } from "./chunk-RE4AXS27.js";
12
+ } from "./chunk-MRRICFWA.js";
13
13
  import {
14
14
  AGENT_PROVIDERS,
15
15
  AGENT_PROVIDER_LABEL,
@@ -20,7 +20,7 @@ import {
20
20
  resolveAgentGUIExplicitConversationTitle,
21
21
  resolveAgentGUIProviderDisplayLabel,
22
22
  resolveAgentGUIProviderIdentity
23
- } from "./chunk-XGGKHIQA.js";
23
+ } from "./chunk-4ROALW3K.js";
24
24
  import {
25
25
  resolveAgentGuiWorkbenchProviderLabel
26
26
  } from "./chunk-L3GMMGRS.js";
@@ -64,14 +64,14 @@ import {
64
64
  toLocalShortDateTime,
65
65
  updateAgentComposerDraft,
66
66
  useProjectedAgentConversation
67
- } from "./chunk-AAFTWZV7.js";
67
+ } from "./chunk-7M77BK6K.js";
68
68
  import {
69
69
  openAgentEnvPanel
70
70
  } from "./chunk-7BXWPI4F.js";
71
71
  import {
72
72
  AgentFileMentionPalette,
73
73
  agentMentionItemKey
74
- } from "./chunk-3RYZYA72.js";
74
+ } from "./chunk-J7ZYAUPC.js";
75
75
  import {
76
76
  normalizeAgentGUIAgents,
77
77
  projectAgentGUIAgentsToInternalTargets
@@ -80,10 +80,10 @@ import {
80
80
  AGENT_MENTION_FILTER_TAB_ORDER,
81
81
  AgentMentionSearchController,
82
82
  DEFAULT_AGENT_MENTION_FILTER
83
- } from "./chunk-AO2FDYAL.js";
83
+ } from "./chunk-3NOJFKDV.js";
84
84
  import {
85
85
  buildWorkspaceAgentActivityListViewModel
86
- } from "./chunk-4VBKQY24.js";
86
+ } from "./chunk-63BE6RGM.js";
87
87
  import {
88
88
  AGENT_RICH_TEXT_CARET_ANCHOR,
89
89
  createAgentSessionMarkdownLink,
@@ -93,7 +93,7 @@ import {
93
93
  mentionItemToAttrs,
94
94
  normalizeAgentSessionMentionTitle,
95
95
  parseMentionItemFromHref
96
- } from "./chunk-4YVGHJIE.js";
96
+ } from "./chunk-CPUEPDF7.js";
97
97
  import {
98
98
  AgentInteractivePromptSurface,
99
99
  PLAN_IMPLEMENTATION_ACTION_FEEDBACK,
@@ -104,7 +104,7 @@ import {
104
104
  latestPlanTurnId,
105
105
  planImplementationPromptFromPlanTurn,
106
106
  useEngineSelector
107
- } from "./chunk-P2BCMPTX.js";
107
+ } from "./chunk-SPZJCTBV.js";
108
108
  import {
109
109
  AgentMessageMarkdown,
110
110
  AgentTargetPresentationProvider,
@@ -113,7 +113,7 @@ import {
113
113
  resolveAgentTargetPresentation,
114
114
  resolveWorkspaceLinkAction,
115
115
  useAgentTargetPresentations
116
- } from "./chunk-SQTSLCMV.js";
116
+ } from "./chunk-T6PEJFRP.js";
117
117
  import {
118
118
  resolveWorkspaceAgentSessionSortTimeUnixMs
119
119
  } from "./chunk-YMXYBG7U.js";
@@ -136,7 +136,7 @@ import {
136
136
  AgentGuiI18nProvider,
137
137
  translate,
138
138
  useTranslation
139
- } from "./chunk-3EAANCKF.js";
139
+ } from "./chunk-RHTZAODZ.js";
140
140
  import {
141
141
  migratedAgentGUIProviderIdentityCatalog,
142
142
  resolveAgentGUIProviderCatalogIdentity,
@@ -152,7 +152,7 @@ import { memo as memo15 } from "react";
152
152
  import { TooltipProvider as TooltipProvider5 } from "@tutti-os/ui-system";
153
153
 
154
154
  // agent-gui/agentGuiNode/AgentGUINode.tsx
155
- import { memo as memo14, useCallback as useCallback50, useEffect as useEffect38, useMemo as useMemo38 } from "react";
155
+ import { memo as memo14, useCallback as useCallback50, useEffect as useEffect39, useMemo as useMemo39 } from "react";
156
156
  import { createWorkspaceUserProjectI18nRuntime } from "@tutti-os/workspace-user-project/i18n";
157
157
  import { createWorkspaceFileManagerI18nRuntime } from "@tutti-os/workspace-file-manager";
158
158
 
@@ -2003,7 +2003,7 @@ var trafficLightIconPathByName = {
2003
2003
 
2004
2004
  // agent-gui/agentGuiNode/controller/useAgentGUINodeController.ts
2005
2005
  import { selectWorkspaceAgentConsumerSessions as selectWorkspaceAgentConsumerSessions2 } from "@tutti-os/agent-activity-core";
2006
- import { useCallback as useCallback24, useEffect as useEffect14, useMemo as useMemo17, useRef as useRef16 } from "react";
2006
+ import { useCallback as useCallback24, useEffect as useEffect14, useMemo as useMemo18, useRef as useRef16 } from "react";
2007
2007
 
2008
2008
  // host/agentHostAccountStore.ts
2009
2009
  import { create as create2 } from "zustand";
@@ -4052,12 +4052,15 @@ function sanitizeComposerSettingsForOptions(settings, options) {
4052
4052
  const reasoningEffort = normalizeOptionalText(settings.reasoningEffort);
4053
4053
  const speed = normalizeOptionalText(settings.speed);
4054
4054
  const permissionModeId = normalizeOptionalText(settings.permissionModeId);
4055
- const modelReasoningProfile = model ? options.reasoningOptionsByModel?.[model] : void 0;
4056
- const modelReasoningValues = modelReasoningProfile ? composerOptionValues(modelReasoningProfile.options) : null;
4055
+ const modelReasoningSelection = reasoningSelectionForModelFromComposerOptions(
4056
+ options,
4057
+ reasoningEffort,
4058
+ model
4059
+ );
4057
4060
  return {
4058
4061
  ...settings,
4059
4062
  model: options.behavior?.modelOptionsAuthoritative === true && model && modelValues.size > 0 && !modelValues.has(model) ? null : model,
4060
- reasoningEffort: options.reasoningConfigurable !== true ? null : reasoningEffort && modelReasoningValues !== null ? modelReasoningValues.has(reasoningEffort) ? reasoningEffort : null : reasoningEffort && reasoningValues.size > 0 && !reasoningValues.has(reasoningEffort) ? null : reasoningEffort,
4063
+ reasoningEffort: modelReasoningSelection !== null ? modelReasoningSelection.currentValue : options.reasoningConfigurable !== true ? null : reasoningEffort && reasoningValues.size > 0 && !reasoningValues.has(reasoningEffort) ? null : reasoningEffort,
4061
4064
  speed: speed && speedValues.size > 0 && !speedValues.has(speed) ? null : speed,
4062
4065
  permissionModeId: permissionModeId && permissionValues.size > 0 && !permissionValues.has(permissionModeId) ? null : permissionModeId
4063
4066
  };
@@ -4186,6 +4189,7 @@ function agentGUISessionStateDiagnosticDetails(state) {
4186
4189
  var AGENT_PROVIDER_SESSION_NOT_FOUND_ERROR = "agent.provider_session_not_found";
4187
4190
  var AGENT_RESUME_SESSION_NOT_LOCAL_ERROR = "agent.resume_session_not_local";
4188
4191
  var AGENT_SETTINGS_REQUIRE_NEW_SESSION_ERROR = "agent.settings_require_new_session";
4192
+ var AGENT_SESSION_TITLE_TOO_LONG_REASON = "workspace_agent_session_title_too_long";
4189
4193
  var AGENT_PROVIDER_SESSION_NOT_FOUND_FALLBACK_MESSAGE = "The previous agent session can no longer be restored.";
4190
4194
  var AGENT_RESUME_SESSION_NOT_LOCAL_FALLBACK_MESSAGE = "The previous agent session is not available on this machine.";
4191
4195
  var AGENT_GUI_CAUGHT_ERROR_STACK_LIMIT = 4e3;
@@ -4287,6 +4291,10 @@ function getAgentGUIErrorMessage(error) {
4287
4291
  return translate("messages.agentResumeSessionNotLocal");
4288
4292
  if (isSettingsRequireNewSessionErrorCode(code))
4289
4293
  return translate("messages.agentSettingsRequireNewSession");
4294
+ if (getAgentGUIErrorReason(error) === AGENT_SESSION_TITLE_TOO_LONG_REASON) {
4295
+ const maxCharacters = getAgentGUIErrorNumberParam(error, "maxCharacters");
4296
+ return maxCharacters === null ? translate("messages.agentSessionTitleTooLongWithoutLimit") : translate("messages.agentSessionTitleTooLong", { maxCharacters });
4297
+ }
4290
4298
  if (error && typeof error === "object") {
4291
4299
  const debugMessage = error.debugMessage;
4292
4300
  if (typeof debugMessage === "string" && debugMessage.trim())
@@ -4294,6 +4302,13 @@ function getAgentGUIErrorMessage(error) {
4294
4302
  }
4295
4303
  return error instanceof Error ? error.message : String(error);
4296
4304
  }
4305
+ function getAgentGUIErrorNumberParam(error, key) {
4306
+ if (!error || typeof error !== "object") return null;
4307
+ const params = error.params;
4308
+ if (!params || typeof params !== "object") return null;
4309
+ const value = params[key];
4310
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
4311
+ }
4297
4312
  function getAgentGUIRawErrorMessage(error) {
4298
4313
  if (error && typeof error === "object") {
4299
4314
  const debugMessage = error.debugMessage;
@@ -4348,7 +4363,57 @@ function token(value) {
4348
4363
  }
4349
4364
 
4350
4365
  // agent-gui/agentGuiNode/controller/useAgentConversationMessagePaging.ts
4351
- import { useCallback as useCallback2, useRef as useRef3 } from "react";
4366
+ import { useCallback as useCallback2, useMemo as useMemo2, useRef as useRef3 } from "react";
4367
+
4368
+ // agent-gui/agentGuiNode/controller/AgentConversationOlderPagingState.ts
4369
+ var AgentConversationOlderPagingState = class {
4370
+ entries = /* @__PURE__ */ new Map();
4371
+ nextRequestId = 0;
4372
+ begin(agentSessionId, beforeVersion) {
4373
+ const current = this.entries.get(agentSessionId);
4374
+ if (current?.phase === "in_flight" || current?.phase === "exhausted" || current?.beforeVersion === beforeVersion) {
4375
+ return { kind: "suppressed", entry: current };
4376
+ }
4377
+ const request = {
4378
+ agentSessionId,
4379
+ beforeVersion,
4380
+ requestId: ++this.nextRequestId
4381
+ };
4382
+ this.entries.set(agentSessionId, { ...request, phase: "in_flight" });
4383
+ return { kind: "started", request };
4384
+ }
4385
+ abandon(request) {
4386
+ if (!this.isCurrent(request)) return false;
4387
+ this.entries.delete(request.agentSessionId);
4388
+ return true;
4389
+ }
4390
+ fail(request) {
4391
+ if (!this.isCurrent(request)) return false;
4392
+ this.entries.set(request.agentSessionId, { ...request, phase: "failed" });
4393
+ return true;
4394
+ }
4395
+ resolve(request, exhausted) {
4396
+ if (!this.isCurrent(request)) return false;
4397
+ if (exhausted) {
4398
+ this.entries.set(request.agentSessionId, {
4399
+ ...request,
4400
+ phase: "exhausted"
4401
+ });
4402
+ } else {
4403
+ this.entries.delete(request.agentSessionId);
4404
+ }
4405
+ return true;
4406
+ }
4407
+ reset(agentSessionId) {
4408
+ this.entries.delete(agentSessionId);
4409
+ }
4410
+ isCurrent(request) {
4411
+ const current = this.entries.get(request.agentSessionId);
4412
+ return current?.phase === "in_flight" && current.beforeVersion === request.beforeVersion && current.requestId === request.requestId;
4413
+ }
4414
+ };
4415
+
4416
+ // agent-gui/agentGuiNode/controller/useAgentConversationMessagePaging.ts
4352
4417
  var PAGE_SIZE = 100;
4353
4418
  function minFiniteMessageVersion(messages) {
4354
4419
  let result = null;
@@ -4412,14 +4477,20 @@ function sessionHasRenderableMessages(input) {
4412
4477
  function useAgentConversationMessagePaging(input) {
4413
4478
  const inputRef = useRef3(input);
4414
4479
  inputRef.current = input;
4415
- const olderLoadSequenceRef = useRef3(0);
4416
- const failedOlderCursorBySessionIdRef = useRef3(/* @__PURE__ */ new Map());
4417
- const loadInitialMessages = useCallback2(async (agentSessionId) => {
4418
- const normalized = agentSessionId.trim();
4419
- if (!normalized) return;
4420
- const current = inputRef.current;
4421
- current.reload.reconcileDetail(normalized);
4422
- }, []);
4480
+ const olderPagingState = useMemo2(
4481
+ () => new AgentConversationOlderPagingState(),
4482
+ []
4483
+ );
4484
+ const loadInitialMessages = useCallback2(
4485
+ async (agentSessionId) => {
4486
+ const normalized = agentSessionId.trim();
4487
+ if (!normalized) return;
4488
+ olderPagingState.reset(normalized);
4489
+ const current = inputRef.current;
4490
+ current.reload.reconcileDetail(normalized);
4491
+ },
4492
+ [olderPagingState]
4493
+ );
4423
4494
  const loadOlderMessages = useCallback2(
4424
4495
  async (agentSessionId) => {
4425
4496
  const current = inputRef.current;
@@ -4431,7 +4502,7 @@ function useAgentConversationMessagePaging(input) {
4431
4502
  current.getCanonicalMessages(normalized)
4432
4503
  );
4433
4504
  const oldestLoadedVersion = view?.oldestLoadedVersion ?? canonicalOldestVersion;
4434
- const hasOlderMessages = view?.hasOlderMessages === true || canonicalOldestVersion !== null && canonicalOldestVersion > 1;
4505
+ const hasOlderMessages = view?.hasOlderMessages === true || view?.oldestLoadedVersion == null && canonicalOldestVersion !== null && canonicalOldestVersion > 1;
4435
4506
  if (!hasOlderMessages || view?.isLoadingOlderMessages === true || oldestLoadedVersion === null || current.getActiveSessionId() !== normalized) {
4436
4507
  current.diagnostics.page({
4437
4508
  agentSessionId: normalized,
@@ -4447,16 +4518,36 @@ function useAgentConversationMessagePaging(input) {
4447
4518
  return;
4448
4519
  }
4449
4520
  const beforeVersion = oldestLoadedVersion;
4450
- if (failedOlderCursorBySessionIdRef.current.get(normalized) === beforeVersion) {
4451
- current.diagnostics.page({
4452
- agentSessionId: normalized,
4521
+ const beginResult = olderPagingState.begin(normalized, beforeVersion);
4522
+ if (beginResult.kind === "suppressed") {
4523
+ const { entry } = beginResult;
4524
+ const suppression = entry.phase === "in_flight" ? {
4525
+ details: {
4526
+ beforeVersion,
4527
+ inFlightBeforeVersion: entry.beforeVersion,
4528
+ inFlightRequestId: entry.requestId,
4529
+ reason: "in_flight_request"
4530
+ },
4531
+ event: "agent.gui.messages.older.suppressed_in_flight",
4532
+ level: void 0
4533
+ } : entry.phase === "exhausted" ? {
4534
+ details: { beforeVersion, reason: "exhausted_cursor" },
4535
+ event: "agent.gui.messages.older.suppressed_exhausted_cursor",
4536
+ level: void 0
4537
+ } : {
4453
4538
  details: { beforeVersion, reason: "previous_cursor_error" },
4454
4539
  event: "agent.gui.messages.older.suppressed_after_error",
4455
4540
  level: "warn"
4541
+ };
4542
+ current.diagnostics.page({
4543
+ agentSessionId: normalized,
4544
+ details: suppression.details,
4545
+ event: suppression.event,
4546
+ level: suppression.level
4456
4547
  });
4457
4548
  return;
4458
4549
  }
4459
- const requestId = ++olderLoadSequenceRef.current;
4550
+ const { request } = beginResult;
4460
4551
  current.view.setOlderMessagesLoading(ref, true);
4461
4552
  try {
4462
4553
  current.diagnostics.page({
@@ -4465,7 +4556,7 @@ function useAgentConversationMessagePaging(input) {
4465
4556
  beforeVersion,
4466
4557
  limit: PAGE_SIZE,
4467
4558
  order: "desc",
4468
- requestId
4559
+ requestId: request.requestId
4469
4560
  },
4470
4561
  event: "agent.gui.messages.older.requested"
4471
4562
  });
@@ -4477,8 +4568,10 @@ function useAgentConversationMessagePaging(input) {
4477
4568
  limit: PAGE_SIZE,
4478
4569
  order: "desc"
4479
4570
  });
4480
- if (!current.isMounted() || current.getActiveSessionId() !== normalized || olderLoadSequenceRef.current !== requestId) {
4481
- current.view.setOlderMessagesLoading(ref, false);
4571
+ if (!current.isMounted() || current.getActiveSessionId() !== normalized) {
4572
+ if (olderPagingState.abandon(request)) {
4573
+ current.view.setOlderMessagesLoading(ref, false);
4574
+ }
4482
4575
  return;
4483
4576
  }
4484
4577
  current.diagnostics.page({
@@ -4487,31 +4580,39 @@ function useAgentConversationMessagePaging(input) {
4487
4580
  beforeVersion,
4488
4581
  hasMore: page.hasMore,
4489
4582
  latestVersion: page.latestVersion,
4490
- requestId
4583
+ requestId: request.requestId
4491
4584
  },
4492
4585
  event: "agent.gui.messages.older.resolved",
4493
4586
  messages: page.messages
4494
4587
  });
4495
- failedOlderCursorBySessionIdRef.current.delete(normalized);
4588
+ if (!olderPagingState.resolve(
4589
+ request,
4590
+ !page.hasMore || page.messages.length === 0
4591
+ )) {
4592
+ return;
4593
+ }
4496
4594
  current.view.mergeOlder(ref, page.messages, {
4497
4595
  hasOlderMessages: page.hasMore && page.messages.length > 0
4498
4596
  });
4597
+ current.view.setOlderMessagesLoading(ref, false);
4499
4598
  } catch (error) {
4500
- if (!current.isMounted() || current.getActiveSessionId() !== normalized || olderLoadSequenceRef.current !== requestId) {
4501
- current.view.setOlderMessagesLoading(ref, false);
4599
+ if (!current.isMounted() || current.getActiveSessionId() !== normalized) {
4600
+ if (olderPagingState.abandon(request)) {
4601
+ current.view.setOlderMessagesLoading(ref, false);
4602
+ }
4502
4603
  return;
4503
4604
  }
4504
- failedOlderCursorBySessionIdRef.current.set(normalized, beforeVersion);
4605
+ if (!olderPagingState.fail(request)) return;
4505
4606
  current.diagnostics.error({
4506
4607
  agentSessionId: normalized,
4507
- context: { beforeVersion, requestId },
4608
+ context: { beforeVersion, requestId: request.requestId },
4508
4609
  error,
4509
4610
  phase: "load_session_messages"
4510
4611
  });
4511
4612
  current.view.setOlderMessagesLoading(ref, false);
4512
4613
  }
4513
4614
  },
4514
- []
4615
+ [olderPagingState]
4515
4616
  );
4516
4617
  const reloadSelectedConversation = useCallback2(
4517
4618
  (agentSessionId, options) => {
@@ -5430,7 +5531,7 @@ import {
5430
5531
  selectSessionActivationPresentations,
5431
5532
  sessionActivationPresentationMapsEqual
5432
5533
  } from "@tutti-os/agent-activity-core";
5433
- import { useCallback as useCallback4, useMemo as useMemo2, useRef as useRef5 } from "react";
5534
+ import { useCallback as useCallback4, useMemo as useMemo3, useRef as useRef5 } from "react";
5434
5535
  var ACTIVATION_EXPIRY_MS = 45e3;
5435
5536
  function isPendingNewConversationActivation(activation) {
5436
5537
  return activation?.mode === "new" && (activation.status === "requested" || activation.status === "uncertain");
@@ -5567,7 +5668,7 @@ function useAgentGUIActivation({
5567
5668
  (agentSessionId) => (agentSessionId ? presentations[agentSessionId]?.errorCode : null) ?? null,
5568
5669
  [presentations]
5569
5670
  );
5570
- return useMemo2(
5671
+ return useMemo3(
5571
5672
  () => ({
5572
5673
  activate,
5573
5674
  clearFailure,
@@ -5590,7 +5691,7 @@ function useAgentGUIActivation({
5590
5691
  }
5591
5692
 
5592
5693
  // agent-gui/agentGuiNode/controller/useAgentGUIActiveMessages.ts
5593
- import { useMemo as useMemo3 } from "react";
5694
+ import { useMemo as useMemo4 } from "react";
5594
5695
 
5595
5696
  // host/workspaceAgentSessionMessages.ts
5596
5697
  import {
@@ -5635,7 +5736,7 @@ function useAgentGUIActiveMessages(input) {
5635
5736
  storedMessages,
5636
5737
  workspaceId
5637
5738
  } = input;
5638
- const activeMessages = useMemo3(() => {
5739
+ const activeMessages = useMemo4(() => {
5639
5740
  if (!activeConversationId) return storedMessages;
5640
5741
  const visibleQueuedSubmitIds = new Set(
5641
5742
  activeQueuedPrompts.map(
@@ -5679,7 +5780,7 @@ function useAgentGUIActiveMessages(input) {
5679
5780
  storedMessages,
5680
5781
  workspaceId
5681
5782
  ]);
5682
- const activeTimelineItems = useMemo3(
5783
+ const activeTimelineItems = useMemo4(
5683
5784
  () => projectAgentGUIMessagesToTimelineItems(activeMessages),
5684
5785
  [activeMessages]
5685
5786
  );
@@ -6090,10 +6191,10 @@ function useAgentGUIConversationSelectionController(input) {
6090
6191
  import {
6091
6192
  selectAttentionReadState
6092
6193
  } from "@tutti-os/agent-activity-core";
6093
- import { useMemo as useMemo5, useRef as useRef7, useState as useState3 } from "react";
6194
+ import { useMemo as useMemo6, useRef as useRef7, useState as useState3 } from "react";
6094
6195
 
6095
6196
  // contexts/workspace/presentation/renderer/agentGuiConversationList/useAgentGuiConversationList.ts
6096
- import { useMemo as useMemo4 } from "react";
6197
+ import { useMemo as useMemo5 } from "react";
6097
6198
  import {
6098
6199
  selectWorkspaceAgentConsumerSessions,
6099
6200
  selectPendingActivations,
@@ -6143,7 +6244,7 @@ function useAgentGuiConversationList(engine, query, agentTargets = []) {
6143
6244
  selectPendingActivations,
6144
6245
  pendingActivationsEqual
6145
6246
  );
6146
- return useMemo4(() => {
6247
+ return useMemo5(() => {
6147
6248
  if (!query) return null;
6148
6249
  const canonicalIds = new Set(
6149
6250
  sessions.map((item) => item.session.agentSessionId)
@@ -6256,7 +6357,7 @@ function useAgentGUIConversationListState({
6256
6357
  );
6257
6358
  const conversationFilterRef = useRef7(conversationFilter);
6258
6359
  conversationFilterRef.current = conversationFilter;
6259
- const conversationListQuery = useMemo5(() => {
6360
+ const conversationListQuery = useMemo6(() => {
6260
6361
  const userId = currentUserId?.trim() ?? "";
6261
6362
  const provider = data.provider?.trim() ?? "";
6262
6363
  if (!workspaceId.trim() || !userId || !provider) {
@@ -6286,7 +6387,7 @@ function useAgentGUIConversationListState({
6286
6387
  sessionEngine,
6287
6388
  (state) => selectAttentionReadState(state, currentUserId)
6288
6389
  );
6289
- const conversations = useMemo5(() => {
6390
+ const conversations = useMemo6(() => {
6290
6391
  return canonicalConversations.map((conversation) => {
6291
6392
  const projectedTitle = resolveAgentGUIConversationTitleFromTimelineItems({
6292
6393
  conversation,
@@ -6325,16 +6426,19 @@ import {
6325
6426
  resolveAgentActivityCapability as resolveAgentActivityCapability2,
6326
6427
  resolveAgentActivityUsage
6327
6428
  } from "@tutti-os/agent-activity-core";
6328
- import { useMemo as useMemo6 } from "react";
6429
+ import { useMemo as useMemo7 } from "react";
6329
6430
 
6330
6431
  // agent-gui/agentGuiNode/model/composerSettingsSupport.ts
6331
6432
  import {
6332
6433
  resolveAgentActivityCapability
6333
6434
  } from "@tutti-os/agent-activity-core";
6334
6435
  function composerSettingsSupportFromOptions(composerOptions, sessionCapabilities) {
6436
+ const hasModelReasoningOptions = Object.values(
6437
+ composerOptions?.reasoningOptionsByModel ?? {}
6438
+ ).some((profile) => profile.options.length > 0);
6335
6439
  return {
6336
6440
  model: composerOptions?.modelConfigurable ?? false,
6337
- reasoning: composerOptions?.reasoningConfigurable ?? false,
6441
+ reasoning: (composerOptions?.reasoningConfigurable ?? false) || hasModelReasoningOptions,
6338
6442
  speed: composerOptions?.speedConfigurable ?? false,
6339
6443
  permission: composerOptions?.permissionConfig?.configurable ?? false,
6340
6444
  plan: resolveAgentActivityCapability("planMode", {
@@ -6406,7 +6510,7 @@ function useAgentGUIComposerCapabilities(input) {
6406
6510
  const selectedModelImageInputSupported = !modelImageInputRequired ? true : selectedModelForPromptImages !== null && (providerComposerOptions?.models.find(
6407
6511
  (option) => option.value === selectedModelForPromptImages
6408
6512
  )?.supportsImageInput ?? false);
6409
- const composerSupport = useMemo6(() => {
6513
+ const composerSupport = useMemo7(() => {
6410
6514
  const fallback = composerSettingsSupportFromOptions(
6411
6515
  providerComposerOptions,
6412
6516
  sessionCapabilities
@@ -6421,6 +6525,11 @@ function useAgentGUIComposerCapabilities(input) {
6421
6525
  planImplementation: sessionCapabilities?.planImplementation ?? fallback.planImplementation
6422
6526
  };
6423
6527
  }, [providerComposerOptions, sessionCapabilities]);
6528
+ const usageSource = input.activeEngineSession?.usage ?? null;
6529
+ const usage = useMemo7(
6530
+ () => resolveAgentActivityUsage({ sessionUsage: usageSource }),
6531
+ [usageSource]
6532
+ );
6424
6533
  return {
6425
6534
  backgroundAgentCount: input.activeEngineSession?.backgroundAgents?.count ?? 0,
6426
6535
  compactSupported: sessionCapabilities?.compact ?? resolveAgentActivityCapability2("compact", {
@@ -6437,9 +6546,7 @@ function useAgentGUIComposerCapabilities(input) {
6437
6546
  }) ?? false,
6438
6547
  promptImagesSupported: (resolvedPromptImagesSupported ?? true) && selectedModelImageInputSupported,
6439
6548
  providerComposerOptions,
6440
- usage: resolveAgentActivityUsage({
6441
- sessionUsage: input.activeEngineSession?.usage ?? null
6442
- })
6549
+ usage
6443
6550
  };
6444
6551
  }
6445
6552
 
@@ -7156,6 +7263,7 @@ function useAgentGUIContinueConversation(input) {
7156
7263
  import {
7157
7264
  useCallback as useCallback10
7158
7265
  } from "react";
7266
+ import { flushSync } from "react-dom";
7159
7267
  function useAgentGUIConversationBatchDeletion(input) {
7160
7268
  const {
7161
7269
  isDeletingProjectConversations,
@@ -7176,7 +7284,6 @@ function useAgentGUIConversationBatchDeletion(input) {
7176
7284
  removeConversations,
7177
7285
  workspaceId,
7178
7286
  setIsDeletingProjectConversations,
7179
- setAgentSessionViewMessagesLoading,
7180
7287
  agentActivityRuntime,
7181
7288
  dataRef,
7182
7289
  agentHostApi
@@ -7205,31 +7312,15 @@ function useAgentGUIConversationBatchDeletion(input) {
7205
7312
  type: "queue/sessionCleaned"
7206
7313
  });
7207
7314
  }
7208
- const nextConversations = conversationsRef.current.filter(
7209
- (conversation) => !targetIds.has(conversation.id)
7210
- );
7211
- const currentActiveId = activeConversationIdRef.current;
7212
- if (currentActiveId && targetIds.has(currentActiveId)) {
7213
- const nextActive = nextConversations[0]?.id ?? null;
7214
- if (nextActive) {
7215
- markSelectedConversationDetailPending(nextActive);
7216
- setIntent({ tag: "active", id: nextActive });
7217
- } else {
7218
- setIsLoadingMessages(false);
7219
- setIntent({ tag: "home" });
7220
- }
7221
- activeConversationIdRef.current = nextActive;
7222
- setActiveConversationId(nextActive);
7223
- persistActiveConversation(nextActive);
7224
- }
7225
7315
  removeConversations([...targetIds]);
7226
7316
  },
7227
7317
  [
7228
- markSelectedConversationDetailPending,
7229
- persistActiveConversation,
7318
+ deleteAgentSessionView,
7319
+ removeConversations,
7230
7320
  sessionEngine,
7231
7321
  sessionViewRef,
7232
- removeConversations
7322
+ setDraftByScopeKey,
7323
+ submittedDraftSnapshotsRef
7233
7324
  ]
7234
7325
  );
7235
7326
  const confirmDeleteProjectConversations = useCallback10(
@@ -7292,11 +7383,23 @@ function useAgentGUIConversationBatchDeletion(input) {
7292
7383
  setListError(null);
7293
7384
  const activeDeletedConversationId = activeConversationIdRef.current;
7294
7385
  if (activeDeletedConversationId && targetIds.has(activeDeletedConversationId)) {
7295
- setIsLoadingMessages(true);
7296
- setAgentSessionViewMessagesLoading(
7297
- sessionViewRef(activeDeletedConversationId),
7298
- true
7299
- );
7386
+ const nextActive = conversationsRef.current.find(
7387
+ (conversation) => !targetIds.has(conversation.id)
7388
+ )?.id ?? null;
7389
+ if (nextActive) {
7390
+ markSelectedConversationDetailPending(nextActive);
7391
+ }
7392
+ activeConversationIdRef.current = nextActive;
7393
+ flushSync(() => {
7394
+ if (nextActive) {
7395
+ setIntent({ tag: "active", id: nextActive });
7396
+ } else {
7397
+ setIsLoadingMessages(false);
7398
+ setIntent({ tag: "home" });
7399
+ }
7400
+ setActiveConversationId(nextActive);
7401
+ });
7402
+ persistActiveConversation(nextActive);
7300
7403
  }
7301
7404
  void deleteSessionsBatch({
7302
7405
  sessionIds: [...targetIds],
@@ -7319,23 +7422,26 @@ function useAgentGUIConversationBatchDeletion(input) {
7319
7422
  });
7320
7423
  setListError(message);
7321
7424
  showAgentGUIControllerErrorToast(agentHostApi.toast, message);
7322
- if (activeDeletedConversationId && activeConversationIdRef.current === activeDeletedConversationId) {
7323
- setIsLoadingMessages(false);
7324
- setAgentSessionViewMessagesLoading(
7325
- sessionViewRef(activeDeletedConversationId),
7326
- false
7327
- );
7328
- }
7329
7425
  }).finally(() => {
7330
7426
  setIsDeletingProjectConversations(false);
7331
7427
  });
7332
7428
  },
7333
7429
  [
7430
+ activeConversationIdRef,
7334
7431
  agentActivityRuntime,
7432
+ agentHostApi.toast,
7433
+ conversationsRef,
7434
+ dataRef,
7335
7435
  finalizeConversationBatchDeletion,
7336
7436
  isDeletingProjectConversations,
7337
- sessionViewRef,
7338
- agentHostApi.toast,
7437
+ markSelectedConversationDetailPending,
7438
+ persistActiveConversation,
7439
+ setActiveConversationId,
7440
+ setDetailError,
7441
+ setIntent,
7442
+ setIsDeletingProjectConversations,
7443
+ setIsLoadingMessages,
7444
+ setListError,
7339
7445
  workspaceId
7340
7446
  ]
7341
7447
  );
@@ -7349,6 +7455,7 @@ function useAgentGUIConversationBatchDeletion(input) {
7349
7455
  import {
7350
7456
  useCallback as useCallback11
7351
7457
  } from "react";
7458
+ import { flushSync as flushSync2 } from "react-dom";
7352
7459
  function useAgentGUIConversationDeletion(input) {
7353
7460
  const {
7354
7461
  isDeletingConversation,
@@ -7359,7 +7466,6 @@ function useAgentGUIConversationDeletion(input) {
7359
7466
  setIsDeletingConversation,
7360
7467
  activeConversationIdRef,
7361
7468
  setIsLoadingMessages,
7362
- setAgentSessionViewMessagesLoading,
7363
7469
  sessionViewRef,
7364
7470
  activation,
7365
7471
  agentActivityRuntime,
@@ -7374,7 +7480,6 @@ function useAgentGUIConversationDeletion(input) {
7374
7480
  persistActiveConversation,
7375
7481
  removeConversations,
7376
7482
  agentHostApi,
7377
- conversationListQuery,
7378
7483
  workspaceId
7379
7484
  } = input;
7380
7485
  const requestDeleteConversation = useCallback11(
@@ -7408,8 +7513,28 @@ function useAgentGUIConversationDeletion(input) {
7408
7513
  setIsDeletingConversation(true);
7409
7514
  setDetailError(null);
7410
7515
  if (activeConversationIdRef.current === target.id) {
7411
- setIsLoadingMessages(true);
7412
- setAgentSessionViewMessagesLoading(sessionViewRef(target.id), true);
7516
+ const currentConversations = conversationsRef.current;
7517
+ const targetIndex = currentConversations.findIndex(
7518
+ (conversation) => conversation.id === target.id
7519
+ );
7520
+ const nextConversations = currentConversations.filter(
7521
+ (conversation) => conversation.id !== target.id
7522
+ );
7523
+ const nextActive = nextConversations[Math.max(0, targetIndex)]?.id ?? nextConversations[Math.max(0, targetIndex - 1)]?.id ?? null;
7524
+ if (nextActive) {
7525
+ markSelectedConversationDetailPending(nextActive);
7526
+ }
7527
+ activeConversationIdRef.current = nextActive;
7528
+ flushSync2(() => {
7529
+ if (nextActive) {
7530
+ setIntent({ tag: "active", id: nextActive });
7531
+ } else {
7532
+ setIsLoadingMessages(false);
7533
+ setIntent({ tag: "home" });
7534
+ }
7535
+ setActiveConversationId(nextActive);
7536
+ });
7537
+ persistActiveConversation(nextActive);
7413
7538
  }
7414
7539
  void activation.unactivate(target.id).then(
7415
7540
  () => agentActivityRuntime.deleteSession({
@@ -7435,26 +7560,6 @@ function useAgentGUIConversationDeletion(input) {
7435
7560
  type: "queue/sessionCleaned"
7436
7561
  });
7437
7562
  deleteAgentSessionView(sessionViewRef(target.id));
7438
- const currentConversations = conversationsRef.current;
7439
- const targetIndex = currentConversations.findIndex(
7440
- (conversation) => conversation.id === target.id
7441
- );
7442
- const nextConversations = currentConversations.filter(
7443
- (conversation) => conversation.id !== target.id
7444
- );
7445
- if (activeConversationIdRef.current === target.id) {
7446
- const nextActive = nextConversations[Math.max(0, targetIndex)]?.id ?? nextConversations[Math.max(0, targetIndex - 1)]?.id ?? null;
7447
- if (nextActive) {
7448
- markSelectedConversationDetailPending(nextActive);
7449
- setIntent({ tag: "active", id: nextActive });
7450
- } else {
7451
- setIsLoadingMessages(false);
7452
- setIntent({ tag: "home" });
7453
- }
7454
- activeConversationIdRef.current = nextActive;
7455
- setActiveConversationId(nextActive);
7456
- persistActiveConversation(nextActive);
7457
- }
7458
7563
  removeConversations([target.id]);
7459
7564
  setPendingDeleteConversation(null);
7460
7565
  }).catch((error) => {
@@ -7468,26 +7573,32 @@ function useAgentGUIConversationDeletion(input) {
7468
7573
  workspaceId
7469
7574
  });
7470
7575
  showAgentGUIControllerErrorToast(agentHostApi.toast, message);
7471
- if (activeConversationIdRef.current === target.id) {
7472
- setIsLoadingMessages(false);
7473
- setAgentSessionViewMessagesLoading(sessionViewRef(target.id), false);
7474
- }
7475
7576
  }).finally(() => {
7476
7577
  setIsDeletingConversation(false);
7477
7578
  });
7478
7579
  }, [
7479
7580
  activation,
7480
- conversationListQuery,
7581
+ activeConversationIdRef,
7582
+ agentActivityRuntime,
7583
+ agentHostApi.toast,
7584
+ conversationsRef,
7585
+ deleteAgentSessionView,
7481
7586
  isDeletingConversation,
7482
- pendingDeleteConversation,
7483
7587
  markSelectedConversationDetailPending,
7588
+ pendingDeleteConversation,
7484
7589
  persistActiveConversation,
7485
- workspaceId,
7486
- sessionViewRef,
7487
- agentActivityRuntime,
7488
- agentHostApi.toast,
7590
+ removeConversations,
7489
7591
  sessionEngine,
7490
- removeConversations
7592
+ sessionViewRef,
7593
+ setActiveConversationId,
7594
+ setDetailError,
7595
+ setDraftByScopeKey,
7596
+ setIntent,
7597
+ setIsDeletingConversation,
7598
+ setIsLoadingMessages,
7599
+ setPendingDeleteConversation,
7600
+ submittedDraftSnapshotsRef,
7601
+ workspaceId
7491
7602
  ]);
7492
7603
  return {
7493
7604
  requestDeleteConversation,
@@ -8809,12 +8920,12 @@ function useAgentGUIOperationActions(input) {
8809
8920
  }
8810
8921
 
8811
8922
  // agent-gui/agentGuiNode/controller/useAgentGUIViewAssembly.ts
8812
- import { useMemo as useMemo13 } from "react";
8923
+ import { useMemo as useMemo14 } from "react";
8813
8924
 
8814
8925
  // agent-gui/agentGuiNode/model/useAgentGUIViewModel.ts
8815
- import { useMemo as useMemo7 } from "react";
8926
+ import { useMemo as useMemo8 } from "react";
8816
8927
  function useAgentGUIViewModel(candidate) {
8817
- const shell = useMemo7(
8928
+ const shell = useMemo8(
8818
8929
  () => candidate.shell,
8819
8930
  [
8820
8931
  candidate.shell.currentUserId,
@@ -8823,7 +8934,7 @@ function useAgentGUIViewModel(candidate) {
8823
8934
  candidate.shell.workspacePath
8824
8935
  ]
8825
8936
  );
8826
- const rail = useMemo7(
8937
+ const rail = useMemo8(
8827
8938
  () => candidate.rail,
8828
8939
  [
8829
8940
  candidate.rail.activeConversation,
@@ -8840,7 +8951,7 @@ function useAgentGUIViewModel(candidate) {
8840
8951
  candidate.rail.userProjects
8841
8952
  ]
8842
8953
  );
8843
- const detail = useMemo7(
8954
+ const detail = useMemo8(
8844
8955
  () => candidate.detail,
8845
8956
  [
8846
8957
  candidate.detail.availability,
@@ -8855,7 +8966,7 @@ function useAgentGUIViewModel(candidate) {
8855
8966
  candidate.detail.usage
8856
8967
  ]
8857
8968
  );
8858
- const composer = useMemo7(
8969
+ const composer = useMemo8(
8859
8970
  () => candidate.composer,
8860
8971
  [
8861
8972
  candidate.composer.availableCommands,
@@ -8878,7 +8989,7 @@ function useAgentGUIViewModel(candidate) {
8878
8989
  candidate.composer.queuedPrompts
8879
8990
  ]
8880
8991
  );
8881
- const interaction = useMemo7(
8992
+ const interaction = useMemo8(
8882
8993
  () => candidate.interaction,
8883
8994
  [
8884
8995
  candidate.interaction.inlineNotice,
@@ -8888,7 +8999,7 @@ function useAgentGUIViewModel(candidate) {
8888
8999
  candidate.interaction.sessionChrome
8889
9000
  ]
8890
9001
  );
8891
- const readiness = useMemo7(
9002
+ const readiness = useMemo8(
8892
9003
  () => candidate.readiness,
8893
9004
  [
8894
9005
  candidate.readiness.activationError,
@@ -8897,7 +9008,7 @@ function useAgentGUIViewModel(candidate) {
8897
9008
  candidate.readiness.providerReadinessGate
8898
9009
  ]
8899
9010
  );
8900
- const operations = useMemo7(
9011
+ const operations = useMemo8(
8901
9012
  () => candidate.operations,
8902
9013
  [
8903
9014
  candidate.operations.isDeletingConversation,
@@ -8906,7 +9017,7 @@ function useAgentGUIViewModel(candidate) {
8906
9017
  candidate.operations.pendingDeleteProjectConversations
8907
9018
  ]
8908
9019
  );
8909
- return useMemo7(
9020
+ return useMemo8(
8910
9021
  () => ({
8911
9022
  shell,
8912
9023
  rail,
@@ -8921,7 +9032,7 @@ function useAgentGUIViewModel(candidate) {
8921
9032
  }
8922
9033
 
8923
9034
  // agent-gui/agentGuiNode/controller/useAgentGUIComposerPresentation.ts
8924
- import { useEffect as useEffect8, useMemo as useMemo8 } from "react";
9035
+ import { useEffect as useEffect8, useMemo as useMemo9 } from "react";
8925
9036
 
8926
9037
  // agent-gui/agentGuiNode/model/agentBrowserUseSubmit.ts
8927
9038
  var TUTTI_BROWSER_USE_SUBMIT_PREFIX = "Use the injected browser-use skill and only the tutti browser CLI. Do not use any other browser skill, CDP scripts, or direct browser automation.";
@@ -9443,7 +9554,7 @@ function useAgentGUIComposerPresentation(input) {
9443
9554
  const draftSpeed = normalizeOptionalText(
9444
9555
  draftSettings.speed
9445
9556
  );
9446
- const activeSessionReasoningSelection = useMemo8(
9557
+ const activeSessionReasoningSelection = useMemo9(
9447
9558
  () => reasoningSelectionFromComposerOptions(
9448
9559
  input.providerComposerOptions,
9449
9560
  draftReasoningEffort,
@@ -9451,21 +9562,22 @@ function useAgentGUIComposerPresentation(input) {
9451
9562
  ),
9452
9563
  [draftModel, draftReasoningEffort, input.providerComposerOptions]
9453
9564
  );
9454
- const activeSessionModelSelection = useMemo8(
9565
+ const presentedReasoningEffort = activeSessionReasoningSelection ? activeSessionReasoningSelection.currentValue : draftReasoningEffort;
9566
+ const activeSessionModelSelection = useMemo9(
9455
9567
  () => modelSelectionFromComposerOptions(
9456
9568
  input.providerComposerOptions,
9457
9569
  draftModel
9458
9570
  ),
9459
9571
  [draftModel, input.providerComposerOptions]
9460
9572
  );
9461
- const activeSessionSpeedSelection = useMemo8(
9573
+ const activeSessionSpeedSelection = useMemo9(
9462
9574
  () => speedSelectionFromComposerOptions(
9463
9575
  input.providerComposerOptions,
9464
9576
  draftSpeed
9465
9577
  ),
9466
9578
  [draftSpeed, input.providerComposerOptions]
9467
9579
  );
9468
- const composerSettings = useMemo8(() => {
9580
+ const composerSettings = useMemo9(() => {
9469
9581
  const permissionConfig = permissionConfigFromComposerOptions(
9470
9582
  input.providerComposerOptions
9471
9583
  );
@@ -9479,7 +9591,7 @@ function useAgentGUIComposerPresentation(input) {
9479
9591
  sessionSettings,
9480
9592
  draftSettings: {
9481
9593
  model: draftModel,
9482
- reasoningEffort: draftReasoningEffort,
9594
+ reasoningEffort: presentedReasoningEffort,
9483
9595
  speed: draftSpeed,
9484
9596
  planMode: Boolean(draftSettings.planMode),
9485
9597
  browserUse: draftSettings.browserUse ?? true,
@@ -9512,7 +9624,7 @@ function useAgentGUIComposerPresentation(input) {
9512
9624
  speedUnavailable: input.activeConversationId !== null && sessionSettings === null && input.composerSupport.speed && draftSpeed === null,
9513
9625
  permissionModeUnavailable: input.activeConversationId !== null && sessionSettings === null && supportsPermissionMode && selectedPermissionModeValue === null,
9514
9626
  selectedModelValue: draftModel,
9515
- selectedReasoningEffortValue: activeSessionReasoningSelection?.currentValue ?? draftReasoningEffort,
9627
+ selectedReasoningEffortValue: presentedReasoningEffort,
9516
9628
  selectedSpeedValue: draftSpeed,
9517
9629
  selectedPermissionModeValue,
9518
9630
  permissionConfig,
@@ -9541,6 +9653,7 @@ function useAgentGUIComposerPresentation(input) {
9541
9653
  input.composerTargetProvider,
9542
9654
  input.providerComposerOptions,
9543
9655
  input.selectedProjectPath,
9656
+ presentedReasoningEffort,
9544
9657
  sessionSettings
9545
9658
  ]);
9546
9659
  return {
@@ -9554,7 +9667,7 @@ function useAgentGUIComposerPresentation(input) {
9554
9667
  }
9555
9668
 
9556
9669
  // agent-gui/agentGuiNode/controller/useAgentGUIControllerActions.ts
9557
- import { useMemo as useMemo9 } from "react";
9670
+ import { useMemo as useMemo10 } from "react";
9558
9671
  function useAgentGUIControllerActions(actions) {
9559
9672
  const updateConversationFilter = useStableControllerEventCallback(
9560
9673
  actions.updateConversationFilter
@@ -9640,7 +9753,7 @@ function useAgentGUIControllerActions(actions) {
9640
9753
  const confirmDeleteConversation = useStableControllerEventCallback(
9641
9754
  actions.confirmDeleteConversation
9642
9755
  );
9643
- return useMemo9(
9756
+ return useMemo10(
9644
9757
  () => ({
9645
9758
  updateConversationFilter,
9646
9759
  selectConversationFilterTarget,
@@ -9712,13 +9825,13 @@ function useAgentGUIControllerActions(actions) {
9712
9825
  import {
9713
9826
  selectEngineAvailableCommands
9714
9827
  } from "@tutti-os/agent-activity-core";
9715
- import { useEffect as useEffect9, useMemo as useMemo10, useRef as useRef10 } from "react";
9828
+ import { useEffect as useEffect9, useMemo as useMemo11, useRef as useRef10 } from "react";
9716
9829
  function useAgentGUIConversationDetail(input) {
9717
9830
  const projectionConversationRef = useRef10(null);
9718
9831
  const activeCanonicalLiveTurn = Boolean(
9719
9832
  input.activeTurn && input.activeTurn.phase !== "settled"
9720
9833
  );
9721
- const projectionConversation = useMemo10(() => {
9834
+ const projectionConversation = useMemo11(() => {
9722
9835
  if (!input.activeConversation) {
9723
9836
  projectionConversationRef.current = null;
9724
9837
  return null;
@@ -9751,17 +9864,17 @@ function useAgentGUIConversationDetail(input) {
9751
9864
  input.sessionEngine,
9752
9865
  (state) => selectEngineAvailableCommands(state, input.activeConversationId)
9753
9866
  );
9754
- const availableCommands = useMemo10(
9867
+ const availableCommands = useMemo11(
9755
9868
  () => (engineAvailableCommands.length > 0 ? engineAvailableCommands : input.providerComposerOptions?.commands ?? []).map((command) => ({ ...command })),
9756
- [engineAvailableCommands, input.providerComposerOptions]
9869
+ [engineAvailableCommands, input.providerComposerOptions?.commands]
9757
9870
  );
9758
9871
  const availableSkills = useStableProviderSkillOptions(
9759
- useMemo10(
9872
+ useMemo11(
9760
9873
  () => providerSkillsFromComposerOptions(input.providerComposerOptions),
9761
9874
  [input.providerComposerOptions]
9762
9875
  )
9763
9876
  );
9764
- const conversationModels = useMemo10(
9877
+ const conversationModels = useMemo11(
9765
9878
  () => projectionConversation ? buildAgentGUIConversationModels({
9766
9879
  timelineItems: input.activeTimelineItems,
9767
9880
  conversation: projectionConversation,
@@ -9778,7 +9891,7 @@ function useAgentGUIConversationDetail(input) {
9778
9891
  const conversationDetail = useStableConversationDetail(
9779
9892
  conversationModels.detail
9780
9893
  );
9781
- const conversation = useMemo10(() => {
9894
+ const conversation = useMemo11(() => {
9782
9895
  if (!conversationModels.conversation) return null;
9783
9896
  if (conversationDetail && (conversationModels.conversation.sourceDetail !== conversationDetail || conversationModels.conversation.activity !== conversationDetail.activity)) {
9784
9897
  return {
@@ -9840,20 +9953,23 @@ function useAgentGUIConversationDetail(input) {
9840
9953
  const activationError = input.errorFor(input.activeConversationId);
9841
9954
  const activationErrorCode = input.codeFor(input.activeConversationId);
9842
9955
  const hasProviderSessionNotFoundError = isNonRetryableResumeErrorCode(activationErrorCode);
9843
- const rawPendingApproval = useMemo10(() => {
9956
+ const rawPendingApproval = useMemo11(() => {
9844
9957
  const interaction = [...input.activePendingInteractions].reverse().find((candidate) => candidate.kind === "approval") ?? null;
9845
9958
  return interactiveApprovalFromInteraction(interaction);
9846
9959
  }, [input.activePendingInteractions]);
9847
- const rawPendingInteractivePrompt = useMemo10(() => {
9960
+ const rawPendingInteractivePrompt = useMemo11(() => {
9848
9961
  const interaction = [...input.activePendingInteractions].reverse().find((candidate) => candidate.kind !== "approval") ?? null;
9849
9962
  return interactivePromptFromInteraction(interaction);
9850
9963
  }, [input.activePendingInteractions]);
9851
- const queuedPrompts = input.activeConversationId ? input.activeQueuedPrompts.map((prompt) => ({
9852
- id: prompt.id,
9853
- content: [...prompt.content],
9854
- ...prompt.displayPrompt ? { displayPrompt: prompt.displayPrompt } : {},
9855
- createdAtUnixMs: prompt.createdAtUnixMs
9856
- })) : [];
9964
+ const queuedPrompts = useMemo11(
9965
+ () => input.activeConversationId ? input.activeQueuedPrompts.map((prompt) => ({
9966
+ id: prompt.id,
9967
+ content: [...prompt.content],
9968
+ ...prompt.displayPrompt ? { displayPrompt: prompt.displayPrompt } : {},
9969
+ createdAtUnixMs: prompt.createdAtUnixMs
9970
+ })) : [],
9971
+ [input.activeConversationId, input.activeQueuedPrompts]
9972
+ );
9857
9973
  return {
9858
9974
  activeLiveState,
9859
9975
  activationError,
@@ -9877,19 +9993,54 @@ function useAgentGUIConversationDetail(input) {
9877
9993
  }
9878
9994
 
9879
9995
  // agent-gui/agentGuiNode/controller/useAgentGUIConversationPresentation.ts
9880
- import { useEffect as useEffect10, useMemo as useMemo11, useRef as useRef11 } from "react";
9996
+ import { useEffect as useEffect10, useMemo as useMemo12, useRef as useRef11 } from "react";
9881
9997
  function useAgentGUIConversationPresentation(input) {
9882
- const activeConversation = useMemo11(() => {
9883
- const resolvedConversation = resolveConversationSummaryById(
9998
+ const visibleConversationsRef = useRef11(
9999
+ null
10000
+ );
10001
+ const conversationProjection = useMemo12(() => {
10002
+ const source = mergeVisibleConversations(
9884
10003
  input.conversations,
9885
- input.activeConversationId,
9886
10004
  input.transientConversation
9887
10005
  );
9888
- const resolved = resolvedConversation ? applyAgentGUIConversationProjects(
9889
- [resolvedConversation],
9890
- input.userProjects,
9891
- { isNoProjectPath: input.isNoProjectPath }
9892
- )[0] ?? resolvedConversation : null;
10006
+ const mapped = source.map((conversation) => {
10007
+ const activityBusyStatus = conversationBusyStatusFromAgentActivityDisplayStatus(
10008
+ input.activityDisplayStatuses.get(conversation.id)
10009
+ );
10010
+ return activityBusyStatus && conversation.status !== activityBusyStatus ? { ...conversation, status: activityBusyStatus } : conversation;
10011
+ });
10012
+ const next = applyAgentGUIConversationProjects(mapped, input.userProjects, {
10013
+ isNoProjectPath: input.isNoProjectPath
10014
+ });
10015
+ const visibleConversations2 = stableConversationSummaryList(
10016
+ visibleConversationsRef.current,
10017
+ next
10018
+ );
10019
+ visibleConversationsRef.current = visibleConversations2;
10020
+ return { semanticConversations: next, visibleConversations: visibleConversations2 };
10021
+ }, [
10022
+ input.activityDisplayStatuses,
10023
+ input.conversations,
10024
+ input.isNoProjectPath,
10025
+ input.transientConversation,
10026
+ input.userProjects
10027
+ ]);
10028
+ const visibleConversations = conversationProjection.visibleConversations;
10029
+ const activeConversationRef = useRef11(
10030
+ null
10031
+ );
10032
+ const activeConversation = useMemo12(() => {
10033
+ const stabilize = (next) => {
10034
+ const previous = activeConversationRef.current?.[0] ?? null;
10035
+ const canReusePrevious = previous !== null && next !== null && conversationSummariesRenderEqual(previous, next) && previous.agentTargetId === next.agentTargetId && previous.resumable === next.resumable;
10036
+ const stable = next ? [canReusePrevious ? previous : next] : [];
10037
+ activeConversationRef.current = stable;
10038
+ return stable[0] ?? null;
10039
+ };
10040
+ const resolved = resolveConversationSummaryById(
10041
+ conversationProjection.semanticConversations,
10042
+ input.activeConversationId
10043
+ );
9893
10044
  if (resolved) {
9894
10045
  const activityDisplayStatus = input.activityDisplayStatuses.get(
9895
10046
  resolved.id
@@ -9899,9 +10050,11 @@ function useAgentGUIConversationPresentation(input) {
9899
10050
  );
9900
10051
  const hasCanonicalTerminalStatus = activityDisplayStatus === "completed" || activityDisplayStatus === "failed" || activityDisplayStatus === "canceled";
9901
10052
  const status = (input.isSubmitting || input.hasUnconfirmedSubmit ? "working" : hasCanonicalTerminalStatus ? activityDisplayStatus : activityBusyStatus2) ?? (resolved.status === "ready" && (input.activeLatestPendingSubmitTurnId || input.isSubmitting) ? "working" : resolved.status);
9902
- return status === resolved.status ? resolved : { ...resolved, status };
10053
+ return stabilize(
10054
+ status === resolved.status ? resolved : { ...resolved, status }
10055
+ );
9903
10056
  }
9904
- if (!input.activeConversationId) return null;
10057
+ if (!input.activeConversationId) return stabilize(null);
9905
10058
  const providerLabel = AGENT_PROVIDER_LABEL[input.data.provider] ?? input.data.provider ?? translate("sidebar.fallbackAgentLabel");
9906
10059
  const fallbackStatus = input.isSubmitting || input.isCreatingConversation || Object.prototype.hasOwnProperty.call(
9907
10060
  input.draftByScopeKey,
@@ -9912,8 +10065,9 @@ function useAgentGUIConversationPresentation(input) {
9912
10065
  const activityBusyStatus = conversationBusyStatusFromAgentActivityDisplayStatus(
9913
10066
  input.activityDisplayStatuses.get(input.activeConversationId)
9914
10067
  );
9915
- const fallbackUpdatedAtUnixMs = Date.now();
9916
- return {
10068
+ const previousActiveConversation = activeConversationRef.current?.[0];
10069
+ const fallbackUpdatedAtUnixMs = previousActiveConversation?.id === input.activeConversationId ? previousActiveConversation.updatedAtUnixMs : Date.now();
10070
+ return stabilize({
9917
10071
  id: input.activeConversationId,
9918
10072
  userId: input.currentUserId?.trim() || void 0,
9919
10073
  provider: input.data.provider,
@@ -9928,12 +10082,11 @@ function useAgentGUIConversationPresentation(input) {
9928
10082
  ),
9929
10083
  sortTimeUnixMs: fallbackUpdatedAtUnixMs,
9930
10084
  updatedAtUnixMs: fallbackUpdatedAtUnixMs
9931
- };
10085
+ });
9932
10086
  }, [
9933
10087
  input.activeConversationId,
9934
10088
  input.activeLatestPendingSubmitTurnId,
9935
10089
  input.activityDisplayStatuses,
9936
- input.conversations,
9937
10090
  input.currentUserId,
9938
10091
  input.data.provider,
9939
10092
  input.draftByScopeKey,
@@ -9941,8 +10094,8 @@ function useAgentGUIConversationPresentation(input) {
9941
10094
  input.isCreatingConversation,
9942
10095
  input.isNoProjectPath,
9943
10096
  input.isSubmitting,
9944
- input.transientConversation,
9945
10097
  input.userProjects,
10098
+ conversationProjection.semanticConversations,
9946
10099
  input.workspacePath
9947
10100
  ]);
9948
10101
  useEffect10(() => {
@@ -9998,36 +10151,6 @@ function useAgentGUIConversationPresentation(input) {
9998
10151
  input.shouldUseStaticProviderTargets,
9999
10152
  input.transientConversation
10000
10153
  ]);
10001
- const visibleConversationsRef = useRef11(
10002
- null
10003
- );
10004
- const visibleConversations = useMemo11(() => {
10005
- const source = mergeVisibleConversations(
10006
- input.conversations,
10007
- input.transientConversation
10008
- );
10009
- const mapped = source.map((conversation) => {
10010
- const activityBusyStatus = conversationBusyStatusFromAgentActivityDisplayStatus(
10011
- input.activityDisplayStatuses.get(conversation.id)
10012
- );
10013
- return activityBusyStatus && conversation.status !== activityBusyStatus ? { ...conversation, status: activityBusyStatus } : conversation;
10014
- });
10015
- const next = applyAgentGUIConversationProjects(mapped, input.userProjects, {
10016
- isNoProjectPath: input.isNoProjectPath
10017
- });
10018
- const stableNext = stableConversationSummaryList(
10019
- visibleConversationsRef.current,
10020
- next
10021
- );
10022
- visibleConversationsRef.current = stableNext;
10023
- return stableNext;
10024
- }, [
10025
- input.activityDisplayStatuses,
10026
- input.conversations,
10027
- input.isNoProjectPath,
10028
- input.transientConversation,
10029
- input.userProjects
10030
- ]);
10031
10154
  return { activeConversation, visibleConversations };
10032
10155
  }
10033
10156
 
@@ -10289,7 +10412,7 @@ import {
10289
10412
  selectPlanDecisionForTurn,
10290
10413
  selectPlanTurnDismissed
10291
10414
  } from "@tutti-os/agent-activity-core";
10292
- import { useEffect as useEffect12, useMemo as useMemo12 } from "react";
10415
+ import { useEffect as useEffect12, useMemo as useMemo13 } from "react";
10293
10416
  function useAgentGUISessionPresentation(input) {
10294
10417
  const latestTimelinePlanTurnId = latestPlanTurnId(input.activeTimelineItems);
10295
10418
  const planImplementationTurnId = input.activeConversationId !== null && input.composerSupport.planImplementation && input.composerSupport.plan && input.activeEngineLatestTurn?.phase === "settled" && input.activeEngineLatestTurn.outcome === "completed" && input.activeEngineLatestTurn.turnId === latestTimelinePlanTurnId ? latestTimelinePlanTurnId : null;
@@ -10342,7 +10465,14 @@ function useAgentGUISessionPresentation(input) {
10342
10465
  const activeSessionResumable = input.activeEngineSession?.resumable ?? input.activeConversation?.resumable ?? input.activeSessionState?.resumable;
10343
10466
  const activeConversationRequiresResume = input.activeConversationId !== null && input.activationState !== "active";
10344
10467
  const activeConversationResumeUnavailable = activeConversationRequiresResume && activeSessionResumable === false;
10345
- const sessionChrome = useMemo12(() => {
10468
+ const sessionChromeRawState = useMemo13(
10469
+ () => input.activeEngineSession ? {
10470
+ agentSessionId: input.activeEngineSession.agentSessionId,
10471
+ goal: input.activeEngineSession.goal
10472
+ } : null,
10473
+ [input.activeEngineSession?.agentSessionId, input.activeEngineSession?.goal]
10474
+ );
10475
+ const sessionChrome = useMemo13(() => {
10346
10476
  const normalizedError = input.activationError?.trim() ?? "";
10347
10477
  const authState = input.activeSessionState?.authState?.trim() ?? "";
10348
10478
  const providerSessionMissing = isNonRetryableResumeErrorCode(
@@ -10370,7 +10500,7 @@ function useAgentGUISessionPresentation(input) {
10370
10500
  message: recoveryMessage,
10371
10501
  canRetry: !providerSessionMissing
10372
10502
  } : null,
10373
- rawState: input.activeEngineSession
10503
+ rawState: sessionChromeRawState
10374
10504
  };
10375
10505
  }, [
10376
10506
  activeConversationResumeUnavailable,
@@ -10378,11 +10508,11 @@ function useAgentGUISessionPresentation(input) {
10378
10508
  input.activationError,
10379
10509
  input.activationErrorCode,
10380
10510
  input.activeConversationId,
10381
- input.activeEngineSession,
10382
10511
  input.activeLiveState,
10383
10512
  input.activeSessionState,
10384
10513
  input.activePendingActivation?.mode,
10385
- input.pendingApproval
10514
+ input.pendingApproval,
10515
+ sessionChromeRawState
10386
10516
  ]);
10387
10517
  const canSubmit = !input.agentTargetsLoading && input.activeLiveState !== "activating" && input.activeLiveState !== "failed" && !activeConversationResumeUnavailable && input.pendingApproval === null && pendingInteractivePrompt === null && sessionChrome.auth === null && !activeConversationBusy && !input.isCreatingConversation && !input.isSubmitting && !input.isInterrupting;
10388
10518
  const canQueueWhileBusy = input.activeConversationId !== null && (activeConversationBusy || input.isSubmitting || input.activeEngineHasPendingInteractions);
@@ -10480,15 +10610,24 @@ function useAgentGUISessionPresentation(input) {
10480
10610
  // agent-gui/agentGuiNode/controller/useAgentGUIViewAssembly.ts
10481
10611
  function useAgentGUIViewAssembly(input) {
10482
10612
  const { activeConversation, visibleConversations } = useAgentGUIConversationPresentation(input);
10483
- const detail = useAgentGUIConversationDetail({
10484
- ...input,
10485
- activeConversation,
10486
- activeSessionView: input.activeSessionView ? {
10613
+ const stableActiveSessionViewProjection = useMemo14(
10614
+ () => input.activeSessionView ? {
10487
10615
  hasOlderMessages: input.activeSessionView.hasOlderMessages,
10488
10616
  isLoadingOlderMessages: input.activeSessionView.isLoadingOlderMessages,
10489
10617
  olderMessageCount: input.activeSessionView.olderMessages.length,
10490
10618
  oldestLoadedVersion: input.activeSessionView.oldestLoadedVersion
10491
- } : null
10619
+ } : null,
10620
+ [
10621
+ input.activeSessionView?.hasOlderMessages,
10622
+ input.activeSessionView?.isLoadingOlderMessages,
10623
+ input.activeSessionView?.olderMessages.length,
10624
+ input.activeSessionView?.oldestLoadedVersion
10625
+ ]
10626
+ );
10627
+ const detail = useAgentGUIConversationDetail({
10628
+ ...input,
10629
+ activeConversation,
10630
+ activeSessionView: stableActiveSessionViewProjection
10492
10631
  });
10493
10632
  const { stableComposerSettings } = useAgentGUIComposerPresentation({
10494
10633
  ...input,
@@ -10530,7 +10669,7 @@ function useAgentGUIViewAssembly(input) {
10530
10669
  comingSoonProviders: input.normalizedComingSoonProviders,
10531
10670
  conversationFilter: input.conversationFilter,
10532
10671
  conversations: visibleConversations,
10533
- userProjects: [...input.userProjects],
10672
+ userProjects: input.userProjects,
10534
10673
  activeConversation,
10535
10674
  activeConversationId: input.activeConversationId,
10536
10675
  isLoadingConversations: input.isLoadingConversations,
@@ -10593,14 +10732,14 @@ function useAgentGUIViewAssembly(input) {
10593
10732
  pendingDeleteProjectConversations: input.pendingDeleteProjectConversations
10594
10733
  }
10595
10734
  });
10596
- return useMemo13(
10735
+ return useMemo14(
10597
10736
  () => ({ viewModel, actions: controllerActions }),
10598
10737
  [controllerActions, viewModel]
10599
10738
  );
10600
10739
  }
10601
10740
 
10602
10741
  // agent-gui/agentGuiNode/controller/useAgentGUIProviderCatalogSelection.ts
10603
- import { useEffect as useEffect13, useMemo as useMemo14, useState as useState4 } from "react";
10742
+ import { useEffect as useEffect13, useMemo as useMemo15, useState as useState4 } from "react";
10604
10743
  function useAgentGUIProviderCatalogSelection(input) {
10605
10744
  const {
10606
10745
  comingSoonProviders,
@@ -10611,12 +10750,12 @@ function useAgentGUIProviderCatalogSelection(input) {
10611
10750
  agentTargets,
10612
10751
  agentTargetsLoading
10613
10752
  } = input;
10614
- const normalizedComingSoonProviders = useMemo14(
10753
+ const normalizedComingSoonProviders = useMemo15(
10615
10754
  () => comingSoonProviders && comingSoonProviders.length > 0 ? [...comingSoonProviders] : emptyComingSoonProviders,
10616
10755
  [comingSoonProviders]
10617
10756
  );
10618
10757
  const isExactProviderRailMode = providerRailMode === "exact";
10619
- const normalizedExplicitProviderTargets = useMemo14(() => {
10758
+ const normalizedExplicitProviderTargets = useMemo15(() => {
10620
10759
  const normalized = normalizeAgentGUIAgentTargets(agentTargets, {
10621
10760
  includeDisabledPlaceholders: !isExactProviderRailMode,
10622
10761
  useStaticCatalog: false
@@ -10626,7 +10765,7 @@ function useAgentGUIProviderCatalogSelection(input) {
10626
10765
  normalizedComingSoonProviders
10627
10766
  );
10628
10767
  }, [isExactProviderRailMode, normalizedComingSoonProviders, agentTargets]);
10629
- const normalizedProviderTargets = useMemo14(() => {
10768
+ const normalizedProviderTargets = useMemo15(() => {
10630
10769
  if (agentTargetsLoading) return [];
10631
10770
  if (!isExactProviderRailMode && (agentTargets === void 0 || normalizedExplicitProviderTargets.length === 0)) {
10632
10771
  return applyComingSoonProviderTargets(
@@ -10645,13 +10784,13 @@ function useAgentGUIProviderCatalogSelection(input) {
10645
10784
  agentTargetsLoading
10646
10785
  ]);
10647
10786
  const shouldUseStaticProviderTargets = !isExactProviderRailMode && !agentTargetsLoading && (agentTargets === void 0 || normalizedExplicitProviderTargets.length === 0);
10648
- const handoffAgentTargets = useMemo14(
10787
+ const handoffAgentTargets = useMemo15(
10649
10788
  () => agentTargetsLoading ? [] : normalizedExplicitProviderTargets.filter(
10650
10789
  (target) => target.disabled !== true
10651
10790
  ),
10652
10791
  [normalizedExplicitProviderTargets, agentTargetsLoading]
10653
10792
  );
10654
- const selectedAgentTarget = useMemo14(
10793
+ const selectedAgentTarget = useMemo15(
10655
10794
  () => resolveAgentGUIAgentTarget({
10656
10795
  agentTargetId: data.agentTargetId,
10657
10796
  defaultAgentTargetId,
@@ -10673,14 +10812,14 @@ function useAgentGUIProviderCatalogSelection(input) {
10673
10812
  shouldUseStaticProviderTargets
10674
10813
  ]
10675
10814
  );
10676
- const selectedAgentTargetIsExplicit = useMemo14(
10815
+ const selectedAgentTargetIsExplicit = useMemo15(
10677
10816
  () => normalizedExplicitProviderTargets.some(
10678
10817
  (target) => target.provider === selectedAgentTarget.provider && target.targetId === selectedAgentTarget.targetId && agentGUIAgentTargetRefsEqual(target.ref, selectedAgentTarget.ref)
10679
10818
  ),
10680
10819
  [normalizedExplicitProviderTargets, selectedAgentTarget]
10681
10820
  );
10682
10821
  const [homeComposerTargetOverride, setHomeComposerTargetOverride] = useState4(null);
10683
- const homeComposerTargetOverrideIsExplicit = useMemo14(
10822
+ const homeComposerTargetOverrideIsExplicit = useMemo15(
10684
10823
  () => homeComposerTargetOverride ? normalizedExplicitProviderTargets.some(
10685
10824
  (target) => target.provider === homeComposerTargetOverride.provider && target.targetId === homeComposerTargetOverride.targetId && agentGUIAgentTargetRefsEqual(
10686
10825
  target.ref,
@@ -10690,14 +10829,14 @@ function useAgentGUIProviderCatalogSelection(input) {
10690
10829
  [homeComposerTargetOverride, normalizedExplicitProviderTargets]
10691
10830
  );
10692
10831
  const effectiveSelectedProviderTarget = homeComposerTargetOverride ?? selectedAgentTarget;
10693
- const firstReadyHomeComposerProviderTarget = useMemo14(
10832
+ const firstReadyHomeComposerProviderTarget = useMemo15(
10694
10833
  () => providerReadinessGates ? normalizedProviderTargets.find(
10695
10834
  (target) => target.disabled !== true && providerReadinessGates[target.provider] === null
10696
10835
  ) ?? null : null,
10697
10836
  [normalizedProviderTargets, providerReadinessGates]
10698
10837
  );
10699
10838
  const nodeComposerTargetResolvedByProviderTarget = agentGUINodeDataHasComposerTarget(data) && normalizeOptionalText(data.agentTargetId) !== null && selectedAgentTarget.agentTargetId === normalizeOptionalText(data.agentTargetId);
10700
- const selectedComposerTargetData = useMemo14(
10839
+ const selectedComposerTargetData = useMemo15(
10701
10840
  () => homeComposerTargetOverride ? composerTargetDataFromProviderTarget({
10702
10841
  current: data,
10703
10842
  isExplicit: homeComposerTargetOverrideIsExplicit,
@@ -10769,7 +10908,7 @@ import {
10769
10908
  selectSessionHasUnconfirmedSubmit,
10770
10909
  selectSessionIsSubmitting
10771
10910
  } from "@tutti-os/agent-activity-core";
10772
- import { useMemo as useMemo15 } from "react";
10911
+ import { useMemo as useMemo16 } from "react";
10773
10912
 
10774
10913
  // agent-gui/agentGuiNode/controller/agentGuiQueueStatus.ts
10775
10914
  function agentGUIQueueStatusFromPromptQueue(record) {
@@ -10783,9 +10922,12 @@ function useAgentGUISessionEngineState(input) {
10783
10922
  sessionEngine,
10784
10923
  (state) => selectEnginePromptQueue(state, activeConversationId)
10785
10924
  );
10786
- const activeQueuedPrompts = activeQueuedPromptSnapshot?.prompts.filter(
10787
- (prompt) => prompt.visibleInQueue !== false && prompt.id !== activeQueuedPromptSnapshot.inFlight?.promptId && prompt.id !== activeQueuedPromptSnapshot.sendNextPromptId
10788
- ) ?? EMPTY_QUEUED_PROMPTS;
10925
+ const activeQueuedPrompts = useMemo16(
10926
+ () => activeQueuedPromptSnapshot?.prompts.filter(
10927
+ (prompt) => prompt.visibleInQueue !== false && prompt.id !== activeQueuedPromptSnapshot.inFlight?.promptId && prompt.id !== activeQueuedPromptSnapshot.sendNextPromptId
10928
+ ) ?? EMPTY_QUEUED_PROMPTS,
10929
+ [activeQueuedPromptSnapshot]
10930
+ );
10789
10931
  const activePendingSubmits = useEngineSelector(
10790
10932
  sessionEngine,
10791
10933
  (state) => selectPendingSubmitsForSession3(state, activeConversationId),
@@ -10837,7 +10979,7 @@ function useAgentGUISessionEngineState(input) {
10837
10979
  sessionEngine,
10838
10980
  (state) => selectEngineLatestTurn(state, activeConversationId)
10839
10981
  );
10840
- const activeCanonicalComposerSettings = useMemo15(
10982
+ const activeCanonicalComposerSettings = useMemo16(
10841
10983
  () => ({
10842
10984
  model: activeEngineSession?.settings?.model ?? void 0,
10843
10985
  permissionModeId: activeEngineSession?.settings?.permissionModeId ?? void 0,
@@ -10848,7 +10990,7 @@ function useAgentGUISessionEngineState(input) {
10848
10990
  }),
10849
10991
  [activeEngineSession?.settings]
10850
10992
  );
10851
- const activeSessionState = useMemo15(() => {
10993
+ const activeSessionState = useMemo16(() => {
10852
10994
  if (!activeEngineSession) return null;
10853
10995
  return {
10854
10996
  workspaceId: activeEngineSession.workspaceId,
@@ -10936,7 +11078,7 @@ function useAgentGUISessionEngineState(input) {
10936
11078
  import {
10937
11079
  selectLatestActivationForSession as selectLatestActivationForSession5
10938
11080
  } from "@tutti-os/agent-activity-core";
10939
- import { useCallback as useCallback23, useMemo as useMemo16 } from "react";
11081
+ import { useCallback as useCallback23, useMemo as useMemo17 } from "react";
10940
11082
 
10941
11083
  // contexts/workspace/presentation/renderer/agentSessions/useAgentSessionControllerState.ts
10942
11084
  import { useCallback as useCallback22 } from "react";
@@ -11119,7 +11261,7 @@ function useAgentSessionControllerState(activeRef, canonicalMessages = []) {
11119
11261
  const canonicalOldestVersion = oldestVersion2(canonicalMessages);
11120
11262
  const activeSessionView = storedActiveView ? {
11121
11263
  ...storedActiveView,
11122
- hasOlderMessages: storedActiveView.hasOlderMessages || canonicalOldestVersion !== null && canonicalOldestVersion > 1,
11264
+ hasOlderMessages: storedActiveView.hasOlderMessages || storedActiveView.oldestLoadedVersion === null && canonicalOldestVersion !== null && canonicalOldestVersion > 1,
11123
11265
  oldestLoadedVersion: storedActiveView.oldestLoadedVersion === null ? canonicalOldestVersion : canonicalOldestVersion === null ? storedActiveView.oldestLoadedVersion : Math.min(
11124
11266
  storedActiveView.oldestLoadedVersion,
11125
11267
  canonicalOldestVersion
@@ -11191,7 +11333,7 @@ function useAgentGUISessionDetailTransport(input) {
11191
11333
  loadSessionState,
11192
11334
  reconcileSessionDetail,
11193
11335
  refreshMessagesFromSnapshot
11194
- } = useMemo16(() => {
11336
+ } = useMemo17(() => {
11195
11337
  const reconcileSession = (agentSessionId, scope) => {
11196
11338
  const normalized = agentSessionId.trim();
11197
11339
  if (!normalized) return;
@@ -11367,7 +11509,7 @@ function useAgentGUINodeController({
11367
11509
  }) {
11368
11510
  const agentActivityRuntime = useAgentActivityRuntime();
11369
11511
  const agentActivityRuntimeOrigin = agentActivityRuntime.origin?.trim() || AGENT_GUI_RUNTIME_SESSION_ORIGIN;
11370
- const sessionEngine = useMemo17(() => {
11512
+ const sessionEngine = useMemo18(() => {
11371
11513
  const engine = agentActivityRuntime.getSessionEngine(workspaceId);
11372
11514
  if (engine.identity.workspaceId !== workspaceId || engine.identity.origin !== agentActivityRuntimeOrigin) {
11373
11515
  throw new Error(
@@ -11555,7 +11697,7 @@ function useAgentGUINodeController({
11555
11697
  storedMessages: storedActiveMessages,
11556
11698
  workspaceId
11557
11699
  });
11558
- const transientConversation = useMemo17(() => {
11700
+ const transientConversation = useMemo18(() => {
11559
11701
  const session = activeEngineSession;
11560
11702
  if (!session || session.visible === false || conversations.some(
11561
11703
  (conversation) => conversation.id === session.agentSessionId
@@ -11857,9 +11999,9 @@ function useAgentGUINodeController({
11857
11999
  // agent-gui/agentGuiNode/AgentGUINodeView.tsx
11858
12000
  import {
11859
12001
  useCallback as useCallback48,
11860
- useEffect as useEffect36,
11861
- useMemo as useMemo36,
11862
- useRef as useRef39,
12002
+ useEffect as useEffect37,
12003
+ useMemo as useMemo37,
12004
+ useRef as useRef41,
11863
12005
  useState as useState34
11864
12006
  } from "react";
11865
12007
  import {
@@ -12101,7 +12243,7 @@ var styles = {
12101
12243
  var AgentGUINode_styles_default = styles;
12102
12244
 
12103
12245
  // agent-gui/agentGuiNode/view/agentGUIViewUtils.ts
12104
- import { useCallback as useCallback25, useLayoutEffect, useMemo as useMemo18, useRef as useRef17 } from "react";
12246
+ import { useCallback as useCallback25, useLayoutEffect, useMemo as useMemo19, useRef as useRef17 } from "react";
12105
12247
  function objectRecord(value) {
12106
12248
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
12107
12249
  }
@@ -12130,7 +12272,7 @@ function useOptionalStableEventCallback(callback) {
12130
12272
  useLayoutEffect(() => {
12131
12273
  callbackRef.current = callback;
12132
12274
  }, [callback]);
12133
- return useMemo18(() => {
12275
+ return useMemo19(() => {
12134
12276
  if (callback == null) {
12135
12277
  return void 0;
12136
12278
  }
@@ -12752,7 +12894,7 @@ function AgentGUIConfigMenu({
12752
12894
  import {
12753
12895
  memo as memo4,
12754
12896
  useCallback as useCallback40,
12755
- useMemo as useMemo29,
12897
+ useMemo as useMemo30,
12756
12898
  useRef as useRef31,
12757
12899
  useState as useState24
12758
12900
  } from "react";
@@ -12977,7 +13119,7 @@ function changeAgentGUIProviderManagerVisibility(input) {
12977
13119
  }
12978
13120
 
12979
13121
  // agent-gui/agentGuiNode/view/AgentGUIEmptyState.tsx
12980
- import { memo as memo3, useMemo as useMemo28 } from "react";
13122
+ import { memo as memo3, useMemo as useMemo29 } from "react";
12981
13123
  import {
12982
13124
  Select as Select3,
12983
13125
  SelectContent as SelectContent3,
@@ -13169,7 +13311,7 @@ var RECORD_FADE_CURVE = 1.45;
13169
13311
  var RECORD_EDGE_KILL_START_SLOTS = 1.2;
13170
13312
  var RECORD_EDGE_KILL_END_SLOTS = 2.05;
13171
13313
  var SPRING_STIFFNESS = 120;
13172
- var SPRING_DAMPING_RATIO = 0.78;
13314
+ var SPRING_DAMPING_RATIO = 0.92;
13173
13315
  var SPRING_MIN_LAUNCH_VELOCITY = 2.6;
13174
13316
  var SPRING_SETTLE_EPSILON = 1e-3;
13175
13317
  var SPRING_SETTLE_VELOCITY = 0.02;
@@ -13354,7 +13496,7 @@ var AgentGuiHeroCarouselScene = class _AgentGuiHeroCarouselScene {
13354
13496
  this.renderer.setSize(width, height, false);
13355
13497
  this.camera.aspect = width / height;
13356
13498
  this.camera.updateProjectionMatrix();
13357
- this.requestRender();
13499
+ this.renderer.render(this.scene, this.camera);
13358
13500
  }
13359
13501
  // Agent index of the tile slot the wheel is heading to.
13360
13502
  targetIndex() {
@@ -14807,7 +14949,7 @@ function AgentSlashStatusPanel({
14807
14949
  }
14808
14950
 
14809
14951
  // agent-gui/agentGuiNode/composer/useComposerDraftAttachments.ts
14810
- import { flushSync } from "react-dom";
14952
+ import { flushSync as flushSync3 } from "react-dom";
14811
14953
  import {
14812
14954
  useCallback as useCallback28,
14813
14955
  useRef as useRef19
@@ -14898,11 +15040,17 @@ function useComposerDraftAttachments({
14898
15040
  clearActiveFileMentionTrigger,
14899
15041
  onDraftContentChange,
14900
15042
  onPromptImagesUnsupported,
15043
+ onContentEntered,
14901
15044
  onRequestWorkspaceReferences,
14902
15045
  resolveDroppedFileReferences,
14903
15046
  onLinkAction
14904
15047
  }) {
14905
15048
  const agentActivityRuntime = useOptionalAgentActivityRuntime();
15049
+ const reportContentEntered = useStableEventCallback2(
15050
+ (contentType) => {
15051
+ onContentEntered?.(contentType);
15052
+ }
15053
+ );
14906
15054
  const publishScopedDraft = useStableEventCallback2(
14907
15055
  (sourceScopeKey, nextDraft) => {
14908
15056
  draftByScopeKeyRef.current[sourceScopeKey] = nextDraft;
@@ -15016,6 +15164,7 @@ function useComposerDraftAttachments({
15016
15164
  }));
15017
15165
  const nextDraftImages = [...currentDraftImages, ...nextImages];
15018
15166
  draftImagesRef.current = nextDraftImages;
15167
+ reportContentEntered("image");
15019
15168
  publishScopedDraft(
15020
15169
  draftScopeKey,
15021
15170
  buildAgentComposerDraft({
@@ -15113,6 +15262,7 @@ function useComposerDraftAttachments({
15113
15262
  onPromptImagesUnsupported,
15114
15263
  publishScopedDraft,
15115
15264
  promptImagesSupported,
15265
+ reportContentEntered,
15116
15266
  updateScopedDraft,
15117
15267
  workspaceId
15118
15268
  ]
@@ -15207,6 +15357,7 @@ ${item.text}` : item.text;
15207
15357
  if (!normalizedText.trim()) {
15208
15358
  return;
15209
15359
  }
15360
+ reportContentEntered("large_text");
15210
15361
  const stagePastedText = pastedTextStagingSupported ? agentActivityRuntime?.stagePastedText : void 0;
15211
15362
  const id = crypto.randomUUID();
15212
15363
  const name = `${AGENT_COMPOSER_PASTED_TEXT_FILE_PREFIX}.txt`;
@@ -15277,6 +15428,7 @@ ${item.text}` : item.text;
15277
15428
  draftScopeKey,
15278
15429
  pastedTextStagingSupported,
15279
15430
  publishScopedDraft,
15431
+ reportContentEntered,
15280
15432
  updateScopedDraft,
15281
15433
  workspaceId
15282
15434
  ]
@@ -15360,7 +15512,7 @@ ${item.text}` : item.text;
15360
15512
  }
15361
15513
  void onRequestWorkspaceReferences(entity).then((result) => {
15362
15514
  if (result.files.length > 0 || result.mentionItems.length > 0) {
15363
- flushSync(clearActiveFileMentionTrigger);
15515
+ flushSync3(clearActiveFileMentionTrigger);
15364
15516
  }
15365
15517
  return applyReferencePickResult(result);
15366
15518
  });
@@ -15410,7 +15562,7 @@ ${item.text}` : item.text;
15410
15562
  // agent-gui/agentGuiNode/composer/useComposerLayout.ts
15411
15563
  import {
15412
15564
  useLayoutEffect as useLayoutEffect2,
15413
- useMemo as useMemo19
15565
+ useMemo as useMemo20
15414
15566
  } from "react";
15415
15567
  var DOCK_COMPOSER_INPUT_MIN_HEIGHT = 56;
15416
15568
  var DOCK_COMPOSER_TEXT_LINE_HEIGHT = 24;
@@ -15628,11 +15780,11 @@ function useComposerLayout({
15628
15780
  isHeroLayout,
15629
15781
  paletteDraftPrompt
15630
15782
  ]);
15631
- const inputShellStyle = useMemo19(
15783
+ const inputShellStyle = useMemo20(
15632
15784
  () => showFileMentionPalette || showFloatingCommandMenu ? { zIndex: COMPOSER_PALETTE_Z_INDEX } : void 0,
15633
15785
  [showFileMentionPalette, showFloatingCommandMenu]
15634
15786
  );
15635
- const promptInputAreaStyle = useMemo19(
15787
+ const promptInputAreaStyle = useMemo20(
15636
15788
  () => isHeroLayout ? void 0 : {
15637
15789
  "--agent-gui-composer-attachment-height": `${dockComposerAttachmentHeight}px`,
15638
15790
  "--agent-gui-composer-input-height": `${dockComposerInputHeight}px`,
@@ -15665,7 +15817,7 @@ function useComposerLayout({
15665
15817
  }
15666
15818
 
15667
15819
  // agent-gui/agentGuiNode/composer/useComposerPaletteCatalog.ts
15668
- import { useMemo as useMemo20 } from "react";
15820
+ import { useMemo as useMemo21 } from "react";
15669
15821
 
15670
15822
  // agent-gui/agentGuiNode/composer/slashCommandDisplay.ts
15671
15823
  function slashCommandDescriptionForDisplay(command, labels) {
@@ -15746,7 +15898,7 @@ function useComposerPaletteCatalog({
15746
15898
  const promptBeforeSelection = editorHandleRef.current?.getPromptTextBeforeSelection() ?? "";
15747
15899
  const skillQueryDraft = promptBeforeSelection || paletteDraftPrompt;
15748
15900
  const skillQueryMatch = getAgentComposerTriggerQueryMatch(skillQueryDraft);
15749
- const resolvedSlashCommands = useMemo20(
15901
+ const resolvedSlashCommands = useMemo21(
15750
15902
  () => resolveSlashCommandsForProvider({
15751
15903
  provider,
15752
15904
  policy: slashCommandPolicy,
@@ -15771,11 +15923,11 @@ function useComposerPaletteCatalog({
15771
15923
  slashCommandPolicy
15772
15924
  ]
15773
15925
  );
15774
- const filteredCommands = useMemo20(
15926
+ const filteredCommands = useMemo21(
15775
15927
  () => slashQuery === null ? [] : filterSlashCommands(resolvedSlashCommands, slashQuery),
15776
15928
  [resolvedSlashCommands, slashQuery]
15777
15929
  );
15778
- const filteredSkills = useMemo20(
15930
+ const filteredSkills = useMemo21(
15779
15931
  () => skillQueryMatch === null ? [] : filterProviderSkillsForTrigger({
15780
15932
  skills: availableSkills,
15781
15933
  query: skillQueryMatch.query,
@@ -15783,7 +15935,7 @@ function useComposerPaletteCatalog({
15783
15935
  }),
15784
15936
  [availableSkills, skillQueryMatch]
15785
15937
  );
15786
- const availableCapabilities = useMemo20(() => {
15938
+ const availableCapabilities = useMemo21(() => {
15787
15939
  const entries = [];
15788
15940
  if (composerSettings.supportsBrowser) {
15789
15941
  entries.push({
@@ -15808,7 +15960,7 @@ function useComposerPaletteCatalog({
15808
15960
  labels.browserUseCapabilityLabel,
15809
15961
  labels.computerUseCapabilityLabel
15810
15962
  ]);
15811
- const slashPaletteEntries = useMemo20(() => {
15963
+ const slashPaletteEntries = useMemo21(() => {
15812
15964
  const commandEntries = filteredCommands.flatMap((command) => {
15813
15965
  if (isSlashCommandCapability(command)) {
15814
15966
  const browserConnectionMode = capabilityMenuState?.browserUse?.connectionMode ?? null;
@@ -15911,7 +16063,7 @@ function useComposerPaletteCatalog({
15911
16063
  import {
15912
16064
  useCallback as useCallback30,
15913
16065
  useLayoutEffect as useLayoutEffect3,
15914
- useMemo as useMemo21,
16066
+ useMemo as useMemo22,
15915
16067
  useState as useState11
15916
16068
  } from "react";
15917
16069
 
@@ -16378,7 +16530,7 @@ function useMentionPaletteFrame(inputShellRef, showFileMentionPalette) {
16378
16530
  window.removeEventListener("scroll", syncMentionPaletteFrame, true);
16379
16531
  };
16380
16532
  }, [showFileMentionPalette, syncMentionPaletteFrame]);
16381
- const mentionPaletteStyle = useMemo21(
16533
+ const mentionPaletteStyle = useMemo22(
16382
16534
  () => ({
16383
16535
  position: "fixed",
16384
16536
  left: `${mentionPaletteFrame?.left ?? 0}px`,
@@ -16399,7 +16551,7 @@ function useMentionPaletteFrame(inputShellRef, showFileMentionPalette) {
16399
16551
  // agent-gui/agentGuiNode/composer/useComposerSlashActions.ts
16400
16552
  import {
16401
16553
  useCallback as useCallback31,
16402
- useMemo as useMemo22,
16554
+ useMemo as useMemo23,
16403
16555
  useRef as useRef21
16404
16556
  } from "react";
16405
16557
 
@@ -16497,7 +16649,7 @@ function useComposerSlashActions(input) {
16497
16649
  },
16498
16650
  [clearSlashCommandDraft, onSubmit]
16499
16651
  );
16500
- const reviewBranchLoader = useMemo22(() => {
16652
+ const reviewBranchLoader = useMemo23(() => {
16501
16653
  if (!onRequestGitBranches) {
16502
16654
  return null;
16503
16655
  }
@@ -17163,7 +17315,7 @@ function useComposerMentionActions(input) {
17163
17315
  }
17164
17316
 
17165
17317
  // agent-gui/agentGuiNode/composer/useComposerProviderTargets.ts
17166
- import { useMemo as useMemo23 } from "react";
17318
+ import { useMemo as useMemo24 } from "react";
17167
17319
  function useComposerProviderTargets(input) {
17168
17320
  const {
17169
17321
  layoutMode,
@@ -17187,7 +17339,7 @@ function useComposerProviderTargets(input) {
17187
17339
  };
17188
17340
  const isHeroLayout = layoutMode === "hero";
17189
17341
  const composerClassName = isHeroLayout ? AgentGUINode_styles_default.composerHero : AgentGUINode_styles_default.composer;
17190
- const providerSwitchTargets = useMemo23(
17342
+ const providerSwitchTargets = useMemo24(
17191
17343
  () => agentTargets.filter(Boolean),
17192
17344
  [agentTargets]
17193
17345
  );
@@ -17198,7 +17350,7 @@ function useComposerProviderTargets(input) {
17198
17350
  const providerMenuTargets = selectedProviderSwitchTarget && !providerSwitchTargets.some(
17199
17351
  (target) => target.targetId === selectedProviderSwitchTarget.targetId
17200
17352
  ) ? [selectedProviderSwitchTarget, ...providerSwitchTargets] : providerSwitchTargets;
17201
- const enabledHandoffProviderTargets = useMemo23(
17353
+ const enabledHandoffProviderTargets = useMemo24(
17202
17354
  () => (handoffAgentTargets ?? providerMenuTargets).filter(
17203
17355
  (target) => target.disabled !== true
17204
17356
  ),
@@ -19022,7 +19174,7 @@ function optionsWithSelectedValue(options, selectedValue) {
19022
19174
  }
19023
19175
 
19024
19176
  // agent-gui/agentGuiNode/AgentComposerProjectMenu.tsx
19025
- import { useMemo as useMemo24 } from "react";
19177
+ import { useMemo as useMemo25 } from "react";
19026
19178
  import { ChevronDown } from "lucide-react";
19027
19179
  import {
19028
19180
  WorkspaceUserProjectSelect,
@@ -19051,11 +19203,11 @@ function AgentProjectDropdown({
19051
19203
  }) {
19052
19204
  "use memo";
19053
19205
  const agentHostApi = useAgentHostApi();
19054
- const resolvedLabels = useMemo24(
19206
+ const resolvedLabels = useMemo25(
19055
19207
  () => resolveWorkspaceUserProjectSelectLabels(i18n, labels),
19056
19208
  [i18n, labels]
19057
19209
  );
19058
- const userProjectApi = useMemo24(
19210
+ const userProjectApi = useMemo25(
19059
19211
  () => !previewMode && agentHostApi.userProjects ? {
19060
19212
  ...agentHostApi.userProjects,
19061
19213
  selectDirectory: selectProjectDirectory ?? agentHostApi.workspace.selectDirectory
@@ -19663,7 +19815,7 @@ import {
19663
19815
  forwardRef as forwardRef3,
19664
19816
  useCallback as useCallback36,
19665
19817
  useEffect as useEffect24,
19666
- useMemo as useMemo25,
19818
+ useMemo as useMemo26,
19667
19819
  useRef as useRef25,
19668
19820
  useState as useState17
19669
19821
  } from "react";
@@ -19851,21 +20003,67 @@ function moveSelectionOverCaretAnchor(state, dispatch, key) {
19851
20003
  }
19852
20004
  return false;
19853
20005
  }
19854
- function createAgentRichTextPlaceholderExtension(getPlaceholder) {
19855
- return Extension.create({
19856
- name: "agentRichTextPlaceholder",
19857
- addProseMirrorPlugins() {
19858
- return [
19859
- new Plugin({
19860
- key: new PluginKey("agentRichTextPlaceholder"),
19861
- props: {
19862
- decorations(state) {
19863
- const firstNode = state.doc.firstChild;
19864
- const isEmptyPrompt = state.doc.childCount === 1 && firstNode?.type.name === "paragraph" && firstNode.content.size === 0;
19865
- if (!firstNode || !isEmptyPrompt) {
19866
- return DecorationSet.empty;
19867
- }
19868
- return DecorationSet.create(state.doc, [
20006
+ function deleteLineStartMentionWithCaretAnchor(state, dispatch, key) {
20007
+ const { doc, selection } = state;
20008
+ if (!selection.empty) {
20009
+ return false;
20010
+ }
20011
+ if (key === "Backspace") {
20012
+ const mention2 = selection.$from.nodeBefore;
20013
+ if (mention2?.type.name !== "agentFileMention") {
20014
+ return false;
20015
+ }
20016
+ const mentionFrom2 = selection.from - mention2.nodeSize;
20017
+ const anchorFrom2 = mentionFrom2 - AGENT_RICH_TEXT_CARET_ANCHOR.length;
20018
+ if (anchorFrom2 < 1 || doc.textBetween(anchorFrom2, mentionFrom2) !== AGENT_RICH_TEXT_CARET_ANCHOR) {
20019
+ return false;
20020
+ }
20021
+ const nextNode2 = selection.$from.nodeAfter;
20022
+ dispatch(
20023
+ state.tr.delete(
20024
+ nextNode2?.type.name === "agentFileMention" ? mentionFrom2 : anchorFrom2,
20025
+ selection.from
20026
+ )
20027
+ );
20028
+ return true;
20029
+ }
20030
+ if (key !== "Delete") {
20031
+ return false;
20032
+ }
20033
+ const anchorFrom = selection.from;
20034
+ const mentionFrom = anchorFrom + AGENT_RICH_TEXT_CARET_ANCHOR.length;
20035
+ if (doc.textBetween(anchorFrom, mentionFrom) !== AGENT_RICH_TEXT_CARET_ANCHOR) {
20036
+ return false;
20037
+ }
20038
+ const mention = doc.resolve(mentionFrom).nodeAfter;
20039
+ if (mention?.type.name !== "agentFileMention") {
20040
+ return false;
20041
+ }
20042
+ const mentionTo = mentionFrom + mention.nodeSize;
20043
+ const nextNode = doc.resolve(mentionTo).nodeAfter;
20044
+ dispatch(
20045
+ state.tr.delete(
20046
+ nextNode?.type.name === "agentFileMention" ? mentionFrom : anchorFrom,
20047
+ mentionTo
20048
+ )
20049
+ );
20050
+ return true;
20051
+ }
20052
+ function createAgentRichTextPlaceholderExtension(getPlaceholder) {
20053
+ return Extension.create({
20054
+ name: "agentRichTextPlaceholder",
20055
+ addProseMirrorPlugins() {
20056
+ return [
20057
+ new Plugin({
20058
+ key: new PluginKey("agentRichTextPlaceholder"),
20059
+ props: {
20060
+ decorations(state) {
20061
+ const firstNode = state.doc.firstChild;
20062
+ const isEmptyPrompt = state.doc.childCount === 1 && firstNode?.type.name === "paragraph" && firstNode.content.size === 0;
20063
+ if (!firstNode || !isEmptyPrompt) {
20064
+ return DecorationSet.empty;
20065
+ }
20066
+ return DecorationSet.create(state.doc, [
19869
20067
  Decoration.node(0, firstNode.nodeSize, {
19870
20068
  class: "agent-rich-text-placeholder-node",
19871
20069
  "data-agent-rich-text-placeholder": getPlaceholder()
@@ -19887,9 +20085,17 @@ function createAgentRichTextCaretAnchorExtension() {
19887
20085
  key: new PluginKey("agentRichTextCaretAnchor"),
19888
20086
  props: {
19889
20087
  handleKeyDown(view, event) {
19890
- if (event.key !== "ArrowLeft" && event.key !== "ArrowRight" || event.shiftKey || event.metaKey || event.ctrlKey || event.altKey) {
20088
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight" && event.key !== "Backspace" && event.key !== "Delete" || event.shiftKey || event.metaKey || event.ctrlKey || event.altKey) {
19891
20089
  return false;
19892
20090
  }
20091
+ if (deleteLineStartMentionWithCaretAnchor(
20092
+ view.state,
20093
+ (transaction) => view.dispatch(transaction),
20094
+ event.key
20095
+ )) {
20096
+ event.preventDefault();
20097
+ return true;
20098
+ }
19893
20099
  if (moveSelectionOverCaretAnchor(
19894
20100
  view.state,
19895
20101
  (transaction) => view.dispatch(transaction),
@@ -20015,6 +20221,30 @@ async function readPlainTextFromClipboard() {
20015
20221
 
20016
20222
  // agent-gui/agentGuiNode/agentRichText/useAgentRichTextEditorHandle.ts
20017
20223
  import { useImperativeHandle as useImperativeHandle2 } from "react";
20224
+
20225
+ // agent-gui/agentGuiNode/agentRichText/agentRichTextEngagement.ts
20226
+ import { isHistoryTransaction } from "@tiptap/pm/history";
20227
+ var AGENT_RICH_TEXT_SKIP_USER_CONTENT_EVENT_META = "agentRichTextSkipUserContentEvent";
20228
+ function isAgentRichTextUserContentInsertion(transaction) {
20229
+ if (transaction.getMeta(AGENT_RICH_TEXT_SKIP_USER_CONTENT_EVENT_META) === true || isHistoryTransaction(transaction)) {
20230
+ return false;
20231
+ }
20232
+ return transaction.steps.some((step) => {
20233
+ let inserted = false;
20234
+ step.getMap().forEach((_oldStart, _oldEnd, newStart, newEnd) => {
20235
+ if (newEnd > newStart) inserted = true;
20236
+ });
20237
+ return inserted;
20238
+ });
20239
+ }
20240
+ function markAgentRichTextPointerFocus(ref) {
20241
+ ref.current = "pointer";
20242
+ queueMicrotask(() => {
20243
+ if (ref.current === "pointer") ref.current = null;
20244
+ });
20245
+ }
20246
+
20247
+ // agent-gui/agentGuiNode/agentRichText/useAgentRichTextEditorHandle.ts
20018
20248
  function useAgentRichTextEditorHandle(input) {
20019
20249
  useImperativeHandle2(
20020
20250
  input.ref,
@@ -20024,6 +20254,7 @@ function useAgentRichTextEditorHandle(input) {
20024
20254
  if (!currentEditor || currentEditor.isDestroyed) {
20025
20255
  return;
20026
20256
  }
20257
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20027
20258
  currentEditor.chain().focus().setTextSelection(1).scrollIntoView().run();
20028
20259
  },
20029
20260
  focusAtEnd() {
@@ -20032,6 +20263,7 @@ function useAgentRichTextEditorHandle(input) {
20032
20263
  return;
20033
20264
  }
20034
20265
  const end = currentEditor.state.doc.content.size;
20266
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20035
20267
  currentEditor.chain().focus().setTextSelection(end).run();
20036
20268
  },
20037
20269
  getPromptTextBeforeSelection() {
@@ -20054,13 +20286,15 @@ function useAgentRichTextEditorHandle(input) {
20054
20286
  const triggerText = isMentionTriggerBoundaryBeforeSelection(
20055
20287
  currentEditor
20056
20288
  ) ? "@" : " @";
20057
- currentEditor.chain().focus().insertContent(triggerText).run();
20289
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20290
+ currentEditor.chain().focus().setMeta(AGENT_RICH_TEXT_SKIP_USER_CONTENT_EVENT_META, true).insertContent(triggerText).run();
20058
20291
  },
20059
20292
  insertWorkspaceReferences(items) {
20060
20293
  const currentEditor = input.editorRef.current;
20061
20294
  if (!currentEditor || currentEditor.isDestroyed || items.length === 0) {
20062
20295
  return;
20063
20296
  }
20297
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20064
20298
  currentEditor.chain().focus().insertContent(
20065
20299
  createAgentFileMentionContent(items, {
20066
20300
  prefixCaretAnchor: isPromptVisualLineStart(
@@ -20075,6 +20309,7 @@ function useAgentRichTextEditorHandle(input) {
20075
20309
  if (!currentEditor || currentEditor.isDestroyed || items.length === 0) {
20076
20310
  return;
20077
20311
  }
20312
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20078
20313
  currentEditor.chain().focus().insertContent(
20079
20314
  createAgentMentionContent(items, {
20080
20315
  prefixCaretAnchor: isPromptVisualLineStart(
@@ -20091,6 +20326,7 @@ function useAgentRichTextEditorHandle(input) {
20091
20326
  }
20092
20327
  const to = currentEditor.state.selection.from;
20093
20328
  const from = Math.max(1, to - length);
20329
+ if (!currentEditor.isFocused) input.onBeforeProgrammaticFocus?.();
20094
20330
  currentEditor.chain().focus().insertContentAt(
20095
20331
  { from, to },
20096
20332
  plainTextToAgentRichTextInlineContent(text, {
@@ -20106,7 +20342,10 @@ function useAgentRichTextEditorHandle(input) {
20106
20342
  }
20107
20343
 
20108
20344
  // agent-gui/agentGuiNode/agentRichText/AgentRichTextEditorSurface.tsx
20109
- import { useCallback as useCallback35, useRef as useRef24 } from "react";
20345
+ import {
20346
+ useCallback as useCallback35,
20347
+ useRef as useRef24
20348
+ } from "react";
20110
20349
  import { createPortal as createPortal2 } from "react-dom";
20111
20350
  import { EditorContent } from "@tiptap/react";
20112
20351
  import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
@@ -20118,66 +20357,75 @@ function AgentRichTextEditorSurface({
20118
20357
  disabled,
20119
20358
  editor,
20120
20359
  handleKeyDownCapture,
20360
+ handlePointerDownCapture,
20121
20361
  pasteClipboardText,
20122
20362
  placeholder,
20123
20363
  t
20124
20364
  }) {
20125
- return /* @__PURE__ */ jsxs20("div", { className: "relative min-w-0", onKeyDownCapture: handleKeyDownCapture, children: [
20126
- editor ? /* @__PURE__ */ jsx27(EditorContent, { editor }) : /* @__PURE__ */ jsx27(
20127
- "div",
20128
- {
20129
- role: "textbox",
20130
- "aria-label": placeholder,
20131
- "aria-disabled": disabled ? "true" : "false",
20132
- "aria-multiline": "true",
20133
- className: cn(
20134
- className,
20135
- "overflow-y-auto whitespace-pre-wrap break-words [&_p]:m-0 [&_p]:min-h-[1.45em]"
20136
- )
20137
- }
20138
- ),
20139
- contextMenu ? createPortal2(
20140
- /* @__PURE__ */ jsxs20(
20141
- "div",
20142
- {
20143
- role: "menu",
20144
- "aria-label": t("agentHost.agentGui.composerTextMenu"),
20145
- className: "fixed z-[var(--z-popover)] min-w-[132px] rounded-[8px] border border-[var(--line-1)] bg-[var(--background-panel)] p-1 text-[13px] text-[var(--text-primary)] shadow-[0_14px_34px_rgb(0_0_0_/_0.28)]",
20146
- "data-agent-composer-text-menu": "true",
20147
- style: { left: contextMenu.x, top: contextMenu.y },
20148
- onContextMenu: (event) => event.preventDefault(),
20149
- onPointerDown: (event) => event.stopPropagation(),
20150
- children: [
20151
- /* @__PURE__ */ jsx27(
20152
- AgentRichTextContextMenuButton,
20153
- {
20154
- disabled: !contextMenu.canEdit || !contextMenu.hasSelection,
20155
- label: t("common.cut"),
20156
- onSelect: cutSelection
20157
- }
20158
- ),
20159
- /* @__PURE__ */ jsx27(
20160
- AgentRichTextContextMenuButton,
20161
- {
20162
- disabled: !contextMenu.hasSelection,
20163
- label: t("common.copy"),
20164
- onSelect: copySelection
20165
- }
20166
- ),
20167
- /* @__PURE__ */ jsx27(
20168
- AgentRichTextContextMenuButton,
20169
- {
20170
- disabled: !contextMenu.canEdit,
20171
- label: t("common.paste"),
20172
- onSelect: pasteClipboardText
20173
- }
20365
+ return /* @__PURE__ */ jsxs20(
20366
+ "div",
20367
+ {
20368
+ className: "relative min-w-0",
20369
+ onKeyDownCapture: handleKeyDownCapture,
20370
+ onPointerDownCapture: handlePointerDownCapture,
20371
+ children: [
20372
+ editor ? /* @__PURE__ */ jsx27(EditorContent, { editor }) : /* @__PURE__ */ jsx27(
20373
+ "div",
20374
+ {
20375
+ role: "textbox",
20376
+ "aria-label": placeholder,
20377
+ "aria-disabled": disabled ? "true" : "false",
20378
+ "aria-multiline": "true",
20379
+ className: cn(
20380
+ className,
20381
+ "overflow-y-auto whitespace-pre-wrap break-words [&_p]:m-0 [&_p]:min-h-[1.45em]"
20174
20382
  )
20175
- ]
20176
- }
20177
- ),
20178
- document.body
20179
- ) : null
20180
- ] });
20383
+ }
20384
+ ),
20385
+ contextMenu ? createPortal2(
20386
+ /* @__PURE__ */ jsxs20(
20387
+ "div",
20388
+ {
20389
+ role: "menu",
20390
+ "aria-label": t("agentHost.agentGui.composerTextMenu"),
20391
+ 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)]",
20392
+ "data-agent-composer-text-menu": "true",
20393
+ style: { left: contextMenu.x, top: contextMenu.y },
20394
+ onContextMenu: (event) => event.preventDefault(),
20395
+ onPointerDown: (event) => event.stopPropagation(),
20396
+ children: [
20397
+ /* @__PURE__ */ jsx27(
20398
+ AgentRichTextContextMenuButton,
20399
+ {
20400
+ disabled: !contextMenu.canEdit || !contextMenu.hasSelection,
20401
+ label: t("common.cut"),
20402
+ onSelect: cutSelection
20403
+ }
20404
+ ),
20405
+ /* @__PURE__ */ jsx27(
20406
+ AgentRichTextContextMenuButton,
20407
+ {
20408
+ disabled: !contextMenu.hasSelection,
20409
+ label: t("common.copy"),
20410
+ onSelect: copySelection
20411
+ }
20412
+ ),
20413
+ /* @__PURE__ */ jsx27(
20414
+ AgentRichTextContextMenuButton,
20415
+ {
20416
+ disabled: !contextMenu.canEdit,
20417
+ label: t("common.paste"),
20418
+ onSelect: pasteClipboardText
20419
+ }
20420
+ )
20421
+ ]
20422
+ }
20423
+ ),
20424
+ document.body
20425
+ ) : null
20426
+ ]
20427
+ }
20428
+ );
20181
20429
  }
20182
20430
  function AgentRichTextContextMenuButton({
20183
20431
  disabled,
@@ -20265,6 +20513,8 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20265
20513
  removeMentionLabel,
20266
20514
  className,
20267
20515
  onChange,
20516
+ onFocus,
20517
+ onUserContentChange,
20268
20518
  onSubmit,
20269
20519
  onSubmitGuidance,
20270
20520
  availableCapabilities = [],
@@ -20287,6 +20537,9 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20287
20537
  const lastEmittedPromptRef = useRef25(value);
20288
20538
  const editorRef = useRef25(null);
20289
20539
  const onChangeRef = useRef25(onChange);
20540
+ const onFocusRef = useRef25(onFocus);
20541
+ const onUserContentChangeRef = useRef25(onUserContentChange);
20542
+ const pendingFocusMethodRef = useRef25(null);
20290
20543
  const onSubmitRef = useRef25(onSubmit);
20291
20544
  const onSubmitGuidanceRef = useRef25(onSubmitGuidance);
20292
20545
  const onKeyDownForPaletteRef = useRef25(onKeyDownForPalette);
@@ -20324,9 +20577,7 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20324
20577
  }
20325
20578
  suppressPastedAtSuggestionRef.current = text.includes("@") && !text.endsWith("@");
20326
20579
  if (suppressPastedAtSuggestionRef.current) {
20327
- window.setTimeout(() => {
20328
- suppressPastedAtSuggestionRef.current = false;
20329
- }, 0);
20580
+ releasePastedAtSuggestionSuppression(suppressPastedAtSuggestionRef);
20330
20581
  }
20331
20582
  currentEditor.chain().focus().insertContent(
20332
20583
  plainTextToAgentRichTextInlineContent(text, {
@@ -20394,7 +20645,7 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20394
20645
  scrollEditorSelectionIntoView(currentEditor);
20395
20646
  });
20396
20647
  };
20397
- const extensions = useMemo25(
20648
+ const extensions = useMemo26(
20398
20649
  () => [
20399
20650
  ...createAgentRichTextInputExtensions(
20400
20651
  {
@@ -20413,6 +20664,8 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20413
20664
  [enableFileMentionSuggestions]
20414
20665
  );
20415
20666
  onChangeRef.current = onChange;
20667
+ onFocusRef.current = onFocus;
20668
+ onUserContentChangeRef.current = onUserContentChange;
20416
20669
  onSubmitRef.current = onSubmit;
20417
20670
  onSubmitGuidanceRef.current = onSubmitGuidance;
20418
20671
  onKeyDownForPaletteRef.current = onKeyDownForPalette;
@@ -20603,9 +20856,7 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20603
20856
  }
20604
20857
  suppressPastedAtSuggestionRef.current = text.includes("@") && !text.endsWith("@");
20605
20858
  if (suppressPastedAtSuggestionRef.current) {
20606
- window.setTimeout(() => {
20607
- suppressPastedAtSuggestionRef.current = false;
20608
- }, 0);
20859
+ releasePastedAtSuggestionSuppression(suppressPastedAtSuggestionRef);
20609
20860
  }
20610
20861
  currentEditor.commands.insertContent(
20611
20862
  plainTextToAgentRichTextInlineContent(text, {
@@ -20735,7 +20986,7 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20735
20986
  }
20736
20987
  }
20737
20988
  },
20738
- onUpdate: ({ editor: nextEditor }) => {
20989
+ onUpdate: ({ editor: nextEditor, transaction }) => {
20739
20990
  editorRef.current = nextEditor;
20740
20991
  scheduleSelectionScroll(nextEditor);
20741
20992
  const nextPrompt = editorToPromptText(nextEditor);
@@ -20743,8 +20994,20 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20743
20994
  return;
20744
20995
  }
20745
20996
  lastEmittedPromptRef.current = nextPrompt;
20997
+ if (isAgentRichTextUserContentInsertion(transaction)) {
20998
+ onUserContentChangeRef.current?.(nextPrompt);
20999
+ }
20746
21000
  onChangeRef.current(nextPrompt);
20747
21001
  },
21002
+ onFocus: ({ editor: nextEditor }) => {
21003
+ const pendingMethod = pendingFocusMethodRef.current;
21004
+ const focusMethod = pendingMethod ?? (nextEditor.view.dom.matches(":focus-visible") ? "keyboard" : "programmatic");
21005
+ pendingFocusMethodRef.current = null;
21006
+ onFocusRef.current?.(focusMethod);
21007
+ },
21008
+ onBlur: () => {
21009
+ pendingFocusMethodRef.current = null;
21010
+ },
20748
21011
  onCreate: ({ editor: nextEditor }) => {
20749
21012
  editorRef.current = nextEditor;
20750
21013
  nextEditor.commands.setTextSelection(nextEditor.state.doc.content.size);
@@ -20760,9 +21023,6 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20760
21023
  submitOnEnter
20761
21024
  });
20762
21025
  };
20763
- useEffect24(() => {
20764
- editorRef.current = editor;
20765
- }, [editor]);
20766
21026
  useEffect24(
20767
21027
  () => () => {
20768
21028
  if (scrollFrameRef.current !== null && typeof window.cancelAnimationFrame === "function") {
@@ -20794,6 +21054,9 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20794
21054
  availableCapabilitiesRef,
20795
21055
  availableSkillsRef,
20796
21056
  editorRef,
21057
+ onBeforeProgrammaticFocus: () => {
21058
+ pendingFocusMethodRef.current = "programmatic";
21059
+ },
20797
21060
  ref
20798
21061
  });
20799
21062
  useEffect24(() => {
@@ -20836,12 +21099,18 @@ var AgentRichTextEditor = forwardRef3(function AgentRichTextEditor2({
20836
21099
  disabled,
20837
21100
  editor,
20838
21101
  handleKeyDownCapture,
21102
+ handlePointerDownCapture: () => markAgentRichTextPointerFocus(pendingFocusMethodRef),
20839
21103
  pasteClipboardText,
20840
21104
  placeholder,
20841
21105
  t
20842
21106
  }
20843
21107
  );
20844
21108
  });
21109
+ function releasePastedAtSuggestionSuppression(ref) {
21110
+ window.setTimeout(() => {
21111
+ ref.current = false;
21112
+ }, 0);
21113
+ }
20845
21114
 
20846
21115
  // agent-gui/agentGuiNode/AgentSlashCommandPalette.tsx
20847
21116
  import { Fragment as Fragment8, useEffect as useEffect25, useRef as useRef26 } from "react";
@@ -21089,7 +21358,7 @@ function slashPaletteEntryIcon(entry) {
21089
21358
  }
21090
21359
 
21091
21360
  // agent-gui/agentGuiNode/AgentReviewPickerPanel.tsx
21092
- import { useCallback as useCallback37, useEffect as useEffect26, useMemo as useMemo26, useRef as useRef27, useState as useState18 } from "react";
21361
+ import { useCallback as useCallback37, useEffect as useEffect26, useMemo as useMemo27, useRef as useRef27, useState as useState18 } from "react";
21093
21362
  import { menuItemClassName } from "@tutti-os/ui-system";
21094
21363
 
21095
21364
  // agent-gui/agentGuiNode/AgentReviewBranchController.ts
@@ -21259,7 +21528,7 @@ function AgentReviewPickerPanel({
21259
21528
  }, []);
21260
21529
  const trimmedQuery = query.trim();
21261
21530
  const normalizedQuery = trimmedQuery.toLowerCase();
21262
- const entries = useMemo26(() => {
21531
+ const entries = useMemo27(() => {
21263
21532
  if (stage === "root") {
21264
21533
  const options = [
21265
21534
  {
@@ -21453,7 +21722,7 @@ import {
21453
21722
  useCallback as useCallback38,
21454
21723
  useEffect as useEffect27,
21455
21724
  useLayoutEffect as useLayoutEffect5,
21456
- useMemo as useMemo27,
21725
+ useMemo as useMemo28,
21457
21726
  useRef as useRef28,
21458
21727
  useState as useState19
21459
21728
  } from "react";
@@ -21662,7 +21931,7 @@ var ComposerFloatingMenuSurface = forwardRef4(function ComposerFloatingMenuSurfa
21662
21931
  window.removeEventListener("blur", onDismiss);
21663
21932
  };
21664
21933
  }, [anchorRef, dismissBoundaryRef, onDismiss, open]);
21665
- const style = useMemo27(() => {
21934
+ const style = useMemo28(() => {
21666
21935
  const baseStyle = {
21667
21936
  position: "fixed",
21668
21937
  left: `${frame?.left ?? 0}px`,
@@ -22351,8 +22620,10 @@ function AgentComposerView(input) {
22351
22620
  slashStatus = null,
22352
22621
  usage = null,
22353
22622
  draftContent,
22623
+ engagement,
22354
22624
  availableSkills = EMPTY_PROVIDER_SKILLS,
22355
22625
  composerSettings,
22626
+ workspaceId,
22356
22627
  queueStatus = "active",
22357
22628
  queuedPrompts,
22358
22629
  drainingQueuedPromptId,
@@ -22382,6 +22653,7 @@ function AgentComposerView(input) {
22382
22653
  hasCompactableContext = true
22383
22654
  } = input.props;
22384
22655
  const draftImages = agentComposerDraftImages(draftContent);
22656
+ const slashStatusAgentSessionId = slashStatus?.agentSessionId ?? null;
22385
22657
  const { availableCapabilities, slashPaletteEntries, slashQuery } = input.paletteCatalog;
22386
22658
  const { mentionPaletteFrame, mentionPaletteHeightPx, mentionPaletteStyle } = input.mentionFrame;
22387
22659
  const {
@@ -22531,7 +22803,9 @@ function AgentComposerView(input) {
22531
22803
  onSendQueuedPromptNext,
22532
22804
  onRemoveQueuedPrompt,
22533
22805
  onEditQueuedPrompt,
22806
+ agentSessionId: slashStatusAgentSessionId,
22534
22807
  onLinkClick: handleLinkClick,
22808
+ workspaceId,
22535
22809
  workspaceAppIcons
22536
22810
  }
22537
22811
  )
@@ -22634,6 +22908,19 @@ function AgentComposerView(input) {
22634
22908
  disabled: inputDisabled,
22635
22909
  className: AgentGUINode_styles_default.composerTextarea,
22636
22910
  onChange: handleDraftChange,
22911
+ onFocus: (method) => engagement?.focused(method),
22912
+ onUserContentChange: (nextPrompt) => {
22913
+ if (agentComposerDraftHasContent(
22914
+ updateAgentComposerDraft(draftContent, {
22915
+ prompt: nextPrompt
22916
+ })
22917
+ )) {
22918
+ engagement?.contentEntered({
22919
+ contentType: "text",
22920
+ hadPrefill: agentComposerDraftHasContent(draftContent)
22921
+ });
22922
+ }
22923
+ },
22637
22924
  onSubmit: submitCurrentPrompt,
22638
22925
  onSubmitGuidance: () => submitCurrentPrompt({ guidance: true }),
22639
22926
  availableSkills,
@@ -22901,6 +23188,7 @@ function AgentComposer(props) {
22901
23188
  provider,
22902
23189
  slashStatus = null,
22903
23190
  draftContent,
23191
+ engagement,
22904
23192
  draftScopeKey = "current",
22905
23193
  availableCommands,
22906
23194
  hasCompactableContext = true,
@@ -22971,6 +23259,12 @@ function AgentComposer(props) {
22971
23259
  const pastedTextStagingSupported = Boolean(
22972
23260
  canUploadAttachment && agentActivityRuntime?.stagePastedText
22973
23261
  );
23262
+ const reportContentEntered = (contentType) => {
23263
+ engagement?.contentEntered({
23264
+ contentType,
23265
+ hadPrefill: agentComposerDraftHasContent(draftContent)
23266
+ });
23267
+ };
22974
23268
  const [isPaletteOpen, setIsPaletteOpen] = useState20(true);
22975
23269
  const [isReviewPickerOpen, setIsReviewPickerOpen] = useState20(false);
22976
23270
  const [isHandoffIconPlaying, setIsHandoffIconPlaying] = useState20(false);
@@ -23245,6 +23539,7 @@ function AgentComposer(props) {
23245
23539
  clearActiveFileMentionTrigger,
23246
23540
  onDraftContentChange,
23247
23541
  onPromptImagesUnsupported,
23542
+ onContentEntered: reportContentEntered,
23248
23543
  onRequestWorkspaceReferences,
23249
23544
  resolveDroppedFileReferences,
23250
23545
  onLinkAction
@@ -23774,7 +24069,7 @@ var AgentGUIEmptyHomePane = memo3(function AgentGUIEmptyHomePane2({
23774
24069
  const providerLabel = selectedAgentTarget?.label ?? runtimeProviderLabel;
23775
24070
  const baseLabel = labels.emptyForProvider?.(provider) ?? labels.empty;
23776
24071
  const emptyLabel = runtimeProviderLabel ? baseLabel.replace(runtimeProviderLabel, providerLabel) : baseLabel;
23777
- const avatarPresentations = useMemo28(
24072
+ const avatarPresentations = useMemo29(
23778
24073
  () => agentTargets.length ? agentTargets.map(projectAgentGUIAgentTargetAvatar) : selectedAgentTarget ? [projectAgentGUIAgentTargetAvatar(selectedAgentTarget)] : [
23779
24074
  createFallbackAgentGUIAgentAvatar({
23780
24075
  provider,
@@ -24882,7 +25177,7 @@ var AgentGUIProviderRail = memo4(function AgentGUIProviderRail2({
24882
25177
  },
24883
25178
  []
24884
25179
  );
24885
- const railProviderTargets = useMemo29(
25180
+ const railProviderTargets = useMemo30(
24886
25181
  () => agentGUIProviderRailTargets(
24887
25182
  agentTargets,
24888
25183
  agentTargetsLoading,
@@ -24891,7 +25186,7 @@ var AgentGUIProviderRail = memo4(function AgentGUIProviderRail2({
24891
25186
  ),
24892
25187
  [comingSoonProviders, providerRailMode, agentTargets, agentTargetsLoading]
24893
25188
  );
24894
- const providerTiles = useMemo29(() => {
25189
+ const providerTiles = useMemo30(() => {
24895
25190
  const targets = [...railProviderTargets];
24896
25191
  const orderedTargets = providerRailMode === "exact" ? targets : (() => {
24897
25192
  const originalIndexByTarget = /* @__PURE__ */ new Map();
@@ -24931,7 +25226,7 @@ var AgentGUIProviderRail = memo4(function AgentGUIProviderRail2({
24931
25226
  agentTargets: providerTiles,
24932
25227
  conversations
24933
25228
  });
24934
- const visibleProviderTiles = useMemo29(
25229
+ const visibleProviderTiles = useMemo30(
24935
25230
  () => applyAgentGUIProviderRailVisibility(
24936
25231
  providerTiles,
24937
25232
  effectiveHiddenTargetIds
@@ -25356,7 +25651,7 @@ import {
25356
25651
  useCallback as useCallback43,
25357
25652
  useEffect as useEffect30,
25358
25653
  useLayoutEffect as useLayoutEffect6,
25359
- useMemo as useMemo31,
25654
+ useMemo as useMemo32,
25360
25655
  useRef as useRef33,
25361
25656
  useState as useState27
25362
25657
  } from "react";
@@ -25845,7 +26140,10 @@ function projectConversationRailSectionsWithActiveConversation(input) {
25845
26140
  if (loadedSection) {
25846
26141
  return {
25847
26142
  activeOverlay: {
25848
- conversation: loadedSection.kind === "project" ? { ...activeConversation, project: loadedSection.project } : activeConversation,
26143
+ conversation: loadedSection.kind === "project" ? conversationWithRailProject(
26144
+ activeConversation,
26145
+ loadedSection.project
26146
+ ) : activeConversation,
25849
26147
  sectionId: loadedSection.id
25850
26148
  },
25851
26149
  sections: input.sections
@@ -25865,7 +26163,10 @@ function projectConversationRailSectionsWithActiveConversation(input) {
25865
26163
  const matchingSection = input.sections[matchingSectionIndex];
25866
26164
  return {
25867
26165
  activeOverlay: {
25868
- conversation: matchingSection?.kind === "project" ? { ...activeConversation, project: matchingSection.project } : activeConversation,
26166
+ conversation: matchingSection?.kind === "project" ? conversationWithRailProject(
26167
+ activeConversation,
26168
+ matchingSection.project
26169
+ ) : activeConversation,
25869
26170
  sectionId: activeSection.id
25870
26171
  },
25871
26172
  sections: input.sections
@@ -25899,6 +26200,9 @@ function projectConversationRailSectionsWithActiveConversation(input) {
25899
26200
  sections
25900
26201
  };
25901
26202
  }
26203
+ function conversationWithRailProject(conversation, project) {
26204
+ return conversationProjectsRenderEqual2(conversation.project, project) ? conversation : { ...conversation, project };
26205
+ }
25902
26206
  function planRuntimeRailMembershipRefresh(input) {
25903
26207
  const previousPendingIds = new Set(
25904
26208
  input.previous.flatMap((conversation) => {
@@ -26140,7 +26444,7 @@ import {
26140
26444
  import {
26141
26445
  memo as memo5,
26142
26446
  useCallback as useCallback41,
26143
- useMemo as useMemo30,
26447
+ useMemo as useMemo31,
26144
26448
  useRef as useRef32,
26145
26449
  useState as useState25
26146
26450
  } from "react";
@@ -26206,6 +26510,7 @@ var AgentGUIConversationRailItem = memo5(
26206
26510
  active,
26207
26511
  isPendingDeleteConversation,
26208
26512
  isDeletingConversation,
26513
+ isRailInteractionLocked,
26209
26514
  currentTimeMs,
26210
26515
  labels,
26211
26516
  previewMode,
@@ -26242,63 +26547,89 @@ var AgentGUIConversationRailItem = memo5(
26242
26547
  const contextMenuCopySessionLinkRequestedRef = useRef32(false);
26243
26548
  const agentHostApi = useOptionalAgentHostApi();
26244
26549
  const handleMouseLeave = useCallback41(() => {
26245
- if (isPendingDeleteConversation) {
26550
+ if (isPendingDeleteConversation && !isRailInteractionLocked()) {
26246
26551
  onCancelDeleteConversation();
26247
26552
  }
26248
- }, [isPendingDeleteConversation, onCancelDeleteConversation]);
26553
+ }, [
26554
+ isPendingDeleteConversation,
26555
+ isRailInteractionLocked,
26556
+ onCancelDeleteConversation
26557
+ ]);
26249
26558
  const handleSelect = useCallback41(() => {
26559
+ if (isRailInteractionLocked()) return;
26250
26560
  onSelectConversation(item.id);
26251
- }, [item.id, onSelectConversation]);
26561
+ }, [isRailInteractionLocked, item.id, onSelectConversation]);
26252
26562
  const handleTogglePinned = useCallback41(() => {
26563
+ if (isRailInteractionLocked()) return;
26253
26564
  onToggleConversationPinned(item.id, !pinned);
26254
- }, [item.id, onToggleConversationPinned, pinned]);
26565
+ }, [isRailInteractionLocked, item.id, onToggleConversationPinned, pinned]);
26255
26566
  const canMarkUnread = Boolean(
26256
26567
  !previewMode && !item.hasUnreadCompletion && item.isImported !== true && (item.unreadCompletionKey || item.status === "completed" || item.status === "ready")
26257
26568
  );
26258
26569
  const handleMarkUnread = useCallback41(() => {
26259
- if (!canMarkUnread) {
26570
+ if (!canMarkUnread || isRailInteractionLocked()) {
26260
26571
  return;
26261
26572
  }
26262
26573
  onMarkConversationUnread(item.id);
26263
- }, [canMarkUnread, item.id, onMarkConversationUnread]);
26574
+ }, [
26575
+ canMarkUnread,
26576
+ isRailInteractionLocked,
26577
+ item.id,
26578
+ onMarkConversationUnread
26579
+ ]);
26264
26580
  const handleOpenConversationWindow = useCallback41(() => {
26581
+ if (isRailInteractionLocked()) return;
26265
26582
  onOpenConversationWindow?.(item.id);
26266
- }, [item.id, onOpenConversationWindow]);
26583
+ }, [isRailInteractionLocked, item.id, onOpenConversationWindow]);
26267
26584
  const handleRequestDelete = useCallback41(() => {
26585
+ if (isRailInteractionLocked()) return;
26268
26586
  onRequestDeleteConversation(item.id);
26269
- }, [item.id, onRequestDeleteConversation]);
26587
+ }, [isRailInteractionLocked, item.id, onRequestDeleteConversation]);
26270
26588
  const handleRequestRename = useCallback41(() => {
26589
+ if (isRailInteractionLocked()) return;
26271
26590
  onRequestRenameConversation(item);
26272
- }, [item, onRequestRenameConversation]);
26591
+ }, [isRailInteractionLocked, item, onRequestRenameConversation]);
26273
26592
  const handleContextMenuRename = useCallback41(() => {
26274
- if (contextMenuRenameRequestedRef.current) {
26593
+ if (isRailInteractionLocked() || contextMenuRenameRequestedRef.current) {
26275
26594
  return;
26276
26595
  }
26277
26596
  contextMenuRenameRequestedRef.current = true;
26278
26597
  setContextMenuResetKey((key) => key + 1);
26279
26598
  window.setTimeout(() => {
26599
+ if (isRailInteractionLocked()) {
26600
+ contextMenuRenameRequestedRef.current = false;
26601
+ return;
26602
+ }
26280
26603
  handleRequestRename();
26281
26604
  contextMenuRenameRequestedRef.current = false;
26282
26605
  }, 0);
26283
- }, [handleRequestRename]);
26606
+ }, [handleRequestRename, isRailInteractionLocked]);
26284
26607
  const handleContextMenuOpenConversationWindow = useCallback41(() => {
26285
- if (contextMenuOpenConversationWindowRequestedRef.current) {
26608
+ if (isRailInteractionLocked() || contextMenuOpenConversationWindowRequestedRef.current) {
26286
26609
  return;
26287
26610
  }
26288
26611
  contextMenuOpenConversationWindowRequestedRef.current = true;
26289
26612
  setContextMenuResetKey((key) => key + 1);
26290
26613
  window.setTimeout(() => {
26614
+ if (isRailInteractionLocked()) {
26615
+ contextMenuOpenConversationWindowRequestedRef.current = false;
26616
+ return;
26617
+ }
26291
26618
  handleOpenConversationWindow();
26292
26619
  contextMenuOpenConversationWindowRequestedRef.current = false;
26293
26620
  }, 0);
26294
- }, [handleOpenConversationWindow]);
26621
+ }, [handleOpenConversationWindow, isRailInteractionLocked]);
26295
26622
  const handleContextMenuCopySessionLink = useCallback41(() => {
26296
- if (contextMenuCopySessionLinkRequestedRef.current) {
26623
+ if (isRailInteractionLocked() || contextMenuCopySessionLinkRequestedRef.current) {
26297
26624
  return;
26298
26625
  }
26299
26626
  contextMenuCopySessionLinkRequestedRef.current = true;
26300
26627
  setContextMenuResetKey((key) => key + 1);
26301
26628
  window.setTimeout(() => {
26629
+ if (isRailInteractionLocked()) {
26630
+ contextMenuCopySessionLinkRequestedRef.current = false;
26631
+ return;
26632
+ }
26302
26633
  if (!agentHostApi?.clipboard?.writeText) {
26303
26634
  contextMenuCopySessionLinkRequestedRef.current = false;
26304
26635
  return;
@@ -26315,7 +26646,14 @@ var AgentGUIConversationRailItem = memo5(
26315
26646
  contextMenuCopySessionLinkRequestedRef.current = false;
26316
26647
  });
26317
26648
  }, 0);
26318
- }, [agentHostApi, item, labels, uiLanguage, workspaceId]);
26649
+ }, [
26650
+ agentHostApi,
26651
+ isRailInteractionLocked,
26652
+ item,
26653
+ labels,
26654
+ uiLanguage,
26655
+ workspaceId
26656
+ ]);
26319
26657
  const row = /* @__PURE__ */ jsxs33(
26320
26658
  "div",
26321
26659
  {
@@ -26325,6 +26663,12 @@ var AgentGUIConversationRailItem = memo5(
26325
26663
  "data-pinned": pinned,
26326
26664
  "data-pending-delete": isPendingDeleteConversation,
26327
26665
  "data-testid": `agent-gui-conversation-item-${item.id}`,
26666
+ onContextMenuCapture: (event) => {
26667
+ if (isRailInteractionLocked()) {
26668
+ event.preventDefault();
26669
+ event.stopPropagation();
26670
+ }
26671
+ },
26328
26672
  onMouseLeave: handleMouseLeave,
26329
26673
  children: [
26330
26674
  /* @__PURE__ */ jsxs33(
@@ -26365,7 +26709,9 @@ var AgentGUIConversationRailItem = memo5(
26365
26709
  disabled: isDeletingConversation,
26366
26710
  onClick: (event) => {
26367
26711
  event.stopPropagation();
26368
- onConfirmDeleteConversation();
26712
+ if (!isRailInteractionLocked()) {
26713
+ onConfirmDeleteConversation();
26714
+ }
26369
26715
  },
26370
26716
  children: /* @__PURE__ */ jsx46("span", { className: AgentGUINode_styles_default.conversationDeleteConfirmText, children: labels.deleteSessionConfirm })
26371
26717
  }
@@ -26502,13 +26848,14 @@ var AgentGUIConversationRailItem = memo5(
26502
26848
  }
26503
26849
  );
26504
26850
  function AgentGUIProjectRailHeader({
26851
+ disabled,
26505
26852
  labels,
26506
26853
  selectProjectDirectory,
26507
26854
  workspaceUserProjectI18n
26508
26855
  }) {
26509
26856
  "use memo";
26510
26857
  const agentHostApi = useAgentHostApi();
26511
- const userProjectApi = useMemo30(
26858
+ const userProjectApi = useMemo31(
26512
26859
  () => agentHostApi.userProjects ? {
26513
26860
  ...agentHostApi.userProjects,
26514
26861
  selectDirectory: selectProjectDirectory ?? agentHostApi.workspace.selectDirectory
@@ -26543,6 +26890,7 @@ function AgentGUIProjectRailHeader({
26543
26890
  contentAlign: "end",
26544
26891
  contentSide: "bottom",
26545
26892
  contentSideOffset: 6,
26893
+ disabled,
26546
26894
  i18n: workspaceUserProjectI18n,
26547
26895
  labels: {
26548
26896
  addProject: labels.projectRailCreateProject,
@@ -26601,6 +26949,7 @@ var AgentGUIConversationRailSection = memo6(
26601
26949
  isRequestingBatchDeletion,
26602
26950
  isConversationSearchActive,
26603
26951
  isLoadingMoreConversations,
26952
+ isRailInteractionLocked,
26604
26953
  sectionHasMore,
26605
26954
  sectionTotalCount,
26606
26955
  createConversationDisabled,
@@ -26663,6 +27012,7 @@ var AgentGUIConversationRailSection = memo6(
26663
27012
  const canShowMore = !isSectionCollapsed && visibleCountTowardTotal < sectionTotalCount && (visibleItemCount < pageableItems.length || sectionHasMore);
26664
27013
  const canShowLess = !isSectionCollapsed && visibleItemCount > AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE;
26665
27014
  const showMoreConversations = useCallback42(() => {
27015
+ if (isRailInteractionLocked()) return;
26666
27016
  if (visibleItemCount >= pageableItems.length && sectionHasMore) {
26667
27017
  onLoadMoreConversations(section);
26668
27018
  setVisibleItemLimitState((current) => ({
@@ -26680,6 +27030,7 @@ var AgentGUIConversationRailSection = memo6(
26680
27030
  }));
26681
27031
  }, [
26682
27032
  onLoadMoreConversations,
27033
+ isRailInteractionLocked,
26683
27034
  pageableItems.length,
26684
27035
  paginationScopeKey,
26685
27036
  section,
@@ -26687,14 +27038,16 @@ var AgentGUIConversationRailSection = memo6(
26687
27038
  visibleItemCount
26688
27039
  ]);
26689
27040
  const showLessConversations = useCallback42(() => {
27041
+ if (isRailInteractionLocked()) return;
26690
27042
  setVisibleItemLimitState({
26691
27043
  limit: AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE,
26692
27044
  scopeKey: paginationScopeKey
26693
27045
  });
26694
- }, [paginationScopeKey]);
27046
+ }, [isRailInteractionLocked, paginationScopeKey]);
26695
27047
  const canCreateConversationFromSection = section.kind === "conversations" || Boolean(projectPath);
26696
27048
  const createConversationLabel = projectPath ? labels.projectSectionEdit : labels.newConversation;
26697
27049
  const handleCreateConversation = useCallback42(() => {
27050
+ if (isRailInteractionLocked()) return;
26698
27051
  if (projectPath) {
26699
27052
  onCreateConversation({ projectPath, source: "project_section" });
26700
27053
  return;
@@ -26703,7 +27056,7 @@ var AgentGUIConversationRailSection = memo6(
26703
27056
  projectPath: null,
26704
27057
  source: "unscoped_section"
26705
27058
  });
26706
- }, [onCreateConversation, projectPath]);
27059
+ }, [isRailInteractionLocked, onCreateConversation, projectPath]);
26707
27060
  return /* @__PURE__ */ jsxs34(
26708
27061
  "section",
26709
27062
  {
@@ -26718,7 +27071,11 @@ var AgentGUIConversationRailSection = memo6(
26718
27071
  type: "button",
26719
27072
  className: AgentGUINode_styles_default.conversationSectionToggle,
26720
27073
  "aria-expanded": !isSectionCollapsed,
26721
- onClick: () => onToggleProjectSectionCollapsed(section.id),
27074
+ onClick: () => {
27075
+ if (!isRailInteractionLocked()) {
27076
+ onToggleProjectSectionCollapsed(section.id);
27077
+ }
27078
+ },
26722
27079
  children: [
26723
27080
  /* @__PURE__ */ jsx47(
26724
27081
  ChevronRight2,
@@ -26839,6 +27196,7 @@ var AgentGUIConversationRailSection = memo6(
26839
27196
  className: `${AgentGUINode_styles_default.composerMenuItem} nodrag [-webkit-app-region:no-drag]`,
26840
27197
  disabled: !onOpenProjectFiles,
26841
27198
  onSelect: () => {
27199
+ if (isRailInteractionLocked()) return;
26842
27200
  onOpenProjectFiles?.({
26843
27201
  directoryPath: projectPath,
26844
27202
  mode: "open-directory",
@@ -26856,7 +27214,11 @@ var AgentGUIConversationRailSection = memo6(
26856
27214
  {
26857
27215
  className: `${AgentGUINode_styles_default.composerMenuItem} nodrag [-webkit-app-region:no-drag]`,
26858
27216
  disabled: isConversationSearchActive || section.items.length === 0 && !sectionHasMore || isDeletingProjectConversations || isRequestingBatchDeletion,
26859
- onSelect: () => onRequestSectionBatchDeletion(section),
27217
+ onSelect: () => {
27218
+ if (!isRailInteractionLocked()) {
27219
+ onRequestSectionBatchDeletion(section);
27220
+ }
27221
+ },
26860
27222
  children: /* @__PURE__ */ jsx47("span", { children: labels.batchDeleteProjectSessions })
26861
27223
  }
26862
27224
  ),
@@ -26865,6 +27227,7 @@ var AgentGUIConversationRailSection = memo6(
26865
27227
  {
26866
27228
  className: `${AgentGUINode_styles_default.composerMenuItem} nodrag [-webkit-app-region:no-drag]`,
26867
27229
  onSelect: () => {
27230
+ if (isRailInteractionLocked()) return;
26868
27231
  const label = projectLabel || projectPath;
26869
27232
  setPendingProjectAction({
26870
27233
  kind: "remove",
@@ -26931,7 +27294,11 @@ var AgentGUIConversationRailSection = memo6(
26931
27294
  {
26932
27295
  className: `${AgentGUINode_styles_default.composerMenuItem} nodrag [-webkit-app-region:no-drag]`,
26933
27296
  disabled: isConversationSearchActive || section.items.length === 0 && !sectionHasMore || isDeletingProjectConversations || isRequestingBatchDeletion,
26934
- onSelect: () => onRequestSectionBatchDeletion(section),
27297
+ onSelect: () => {
27298
+ if (!isRailInteractionLocked()) {
27299
+ onRequestSectionBatchDeletion(section);
27300
+ }
27301
+ },
26935
27302
  children: /* @__PURE__ */ jsx47("span", { children: labels.batchDeleteConversations })
26936
27303
  }
26937
27304
  )
@@ -26954,6 +27321,7 @@ var AgentGUIConversationRailSection = memo6(
26954
27321
  currentTimeMs,
26955
27322
  isDeletingConversation,
26956
27323
  isPendingDeleteConversation: pendingDeleteConversationId === item.id,
27324
+ isRailInteractionLocked,
26957
27325
  item,
26958
27326
  labels,
26959
27327
  previewMode,
@@ -27068,9 +27436,11 @@ var AgentGUIConversationRailPane = memo7(
27068
27436
  );
27069
27437
  const activeConversationScrollCompletedRef = useRef33(null);
27070
27438
  const previousActiveConversationIdRef = useRef33(null);
27439
+ const railActiveConversationRef = useRef33([]);
27071
27440
  const groupedConversationsRef = useRef33(null);
27072
27441
  const {
27073
27442
  loadMoreSectionConversations,
27443
+ isInteractionLocked,
27074
27444
  runtimeSectionsEnabled,
27075
27445
  runtimeRailConversations,
27076
27446
  runtimeRailMemberships,
@@ -27090,6 +27460,7 @@ var AgentGUIConversationRailPane = memo7(
27090
27460
  const railConversationEntities = [...railConversationEntitiesById.values()];
27091
27461
  const hasConversationQuery = conversationQuery.trim().length > 0;
27092
27462
  const backendSearchActive = hasConversationQuery && railSearch.enabled;
27463
+ const railInteractionsLocked = runtimeRailSectionsPending && !backendSearchActive;
27093
27464
  const backendSearchConversations = backendSearchActive ? railSearch.sessionIds.flatMap((id) => {
27094
27465
  const conversation = railConversationEntitiesById.get(id);
27095
27466
  return conversation ? [conversation] : [];
@@ -27099,11 +27470,17 @@ var AgentGUIConversationRailPane = memo7(
27099
27470
  labels,
27100
27471
  sections: runtimeRailMemberships
27101
27472
  }) : null;
27102
- const railActiveConversation = resolveConversationRailActiveConversation({
27473
+ const railActiveConversationCandidate = resolveConversationRailActiveConversation({
27103
27474
  activeConversation,
27104
27475
  activeConversationId,
27105
27476
  conversations: railConversationEntities
27106
27477
  });
27478
+ const stableRailActiveConversation = stabilizeConversationSectionItems(
27479
+ railActiveConversationRef.current,
27480
+ railActiveConversationCandidate ? [railActiveConversationCandidate] : []
27481
+ );
27482
+ railActiveConversationRef.current = stableRailActiveConversation;
27483
+ const railActiveConversation = stableRailActiveConversation[0] ?? null;
27107
27484
  const runtimeSectionsWithTransientConversations = projectConversationRailSectionsWithTransientConversations({
27108
27485
  conversations,
27109
27486
  labels,
@@ -27125,7 +27502,7 @@ var AgentGUIConversationRailPane = memo7(
27125
27502
  window.clearInterval(timer);
27126
27503
  };
27127
27504
  }, []);
27128
- const displayConversations = useMemo31(() => {
27505
+ const displayConversations = useMemo32(() => {
27129
27506
  if (backendSearchActive) {
27130
27507
  return backendSearchConversations;
27131
27508
  }
@@ -27146,7 +27523,7 @@ var AgentGUIConversationRailPane = memo7(
27146
27523
  runtimeRailSections,
27147
27524
  runtimeSectionsEnabled
27148
27525
  ]);
27149
- const filteredConversationResult = useMemo31(() => {
27526
+ const filteredConversationResult = useMemo32(() => {
27150
27527
  const startedAtMs = agentGuiPerfNowMs();
27151
27528
  const query = conversationQuery.trim().toLowerCase();
27152
27529
  const items = backendSearchActive ? displayConversations : !query ? displayConversations : displayConversations.filter(
@@ -27164,7 +27541,7 @@ var AgentGUIConversationRailPane = memo7(
27164
27541
  uiLanguage
27165
27542
  ]);
27166
27543
  const filteredConversations = filteredConversationResult.items;
27167
- const groupedConversationResult = useMemo31(() => {
27544
+ const groupedConversationResult = useMemo32(() => {
27168
27545
  const startedAtMs = agentGuiPerfNowMs();
27169
27546
  const query = conversationQuery.trim();
27170
27547
  const rawGroups = backendSearchActive ? groupConversations(filteredConversations, labels, userProjects, {
@@ -27216,7 +27593,7 @@ var AgentGUIConversationRailPane = memo7(
27216
27593
  return next;
27217
27594
  });
27218
27595
  }, []);
27219
- const groupedConversationIdentityKey = useMemo31(
27596
+ const groupedConversationIdentityKey = useMemo32(
27220
27597
  () => `${groupedConversations.map(
27221
27598
  (section) => `${section.id}:${section.items.map((item) => item.id).join(",")}`
27222
27599
  ).join("|")}|active:${railActiveOverlay?.conversation.id ?? ""}`,
@@ -27225,7 +27602,7 @@ var AgentGUIConversationRailPane = memo7(
27225
27602
  const sectionAgentTargetId = conversationFilter.kind === "agentTarget" ? conversationFilter.agentTargetId.trim() : sectionAgentTargetFallbackId?.trim() ?? "";
27226
27603
  const requestSectionBatchDeletion = useCallback43(
27227
27604
  (section) => {
27228
- if (isDeletingProjectConversations || isRequestingBatchDeletion) {
27605
+ if (isInteractionLocked() || isDeletingProjectConversations || isRequestingBatchDeletion) {
27229
27606
  return;
27230
27607
  }
27231
27608
  setIsRequestingBatchDeletion(true);
@@ -27233,7 +27610,7 @@ var AgentGUIConversationRailPane = memo7(
27233
27610
  section.id,
27234
27611
  sectionAgentTargetId || void 0
27235
27612
  ).then((sessionIds) => {
27236
- if (sessionIds.length === 0) {
27613
+ if (isInteractionLocked() || sessionIds.length === 0) {
27237
27614
  return;
27238
27615
  }
27239
27616
  setPendingProjectAction({
@@ -27247,6 +27624,7 @@ var AgentGUIConversationRailPane = memo7(
27247
27624
  [
27248
27625
  isDeletingProjectConversations,
27249
27626
  isRequestingBatchDeletion,
27627
+ isInteractionLocked,
27250
27628
  onConfirmDeleteProjectConversations,
27251
27629
  sectionAgentTargetId
27252
27630
  ]
@@ -27347,87 +27725,96 @@ var AgentGUIConversationRailPane = memo7(
27347
27725
  children: labels.retrySearch
27348
27726
  }
27349
27727
  )
27350
- ] }) : shouldShowConversationEmptyState ? /* @__PURE__ */ jsx48("div", { className: AgentGUINode_styles_default.emptyState, children: /* @__PURE__ */ jsx48("span", { children: conversationQuery.trim() ? labels.searchNoConversations : conversations.length === 0 ? labels.noConversations : labels.conversationUnavailable }) }) : groupedConversations.map((section, sectionIndex) => {
27351
- const projectPath = section.kind === "project" ? section.project?.path ?? "" : "";
27352
- const projectLabel = section.kind === "project" ? section.label : "";
27353
- const isProjectSection = section.kind === "project";
27354
- const showProjectRailHeader = !conversationQuery.trim() && section.kind !== "pinned" && (sectionIndex === 0 || groupedConversations[sectionIndex - 1]?.kind === "pinned");
27355
- const isSectionCollapsed = isProjectSection && collapsedProjectSectionIds.has(section.id);
27356
- const sectionPageState = sectionPageStates.get(section.id);
27357
- const searchSectionHasMore = backendSearchActive && sectionIndex === groupedConversations.length - 1 && railSearch.hasMore;
27358
- const activeOverlayConversation = !backendSearchActive && railActiveOverlay?.sectionId === section.id && (!conversationQuery.trim() || filteredConversations.some(
27359
- (conversation) => conversation.id === railActiveOverlay.conversation.id
27360
- )) ? railActiveOverlay.conversation : null;
27361
- const activeOverlayIsCanonical = Boolean(
27362
- activeOverlayConversation && section.items.some(
27363
- (item) => item.projectionSource !== "pending_activation" && item.id === activeOverlayConversation.id
27364
- )
27365
- );
27366
- const activeOverlayCountsTowardTotal = Boolean(
27367
- activeOverlayConversation && activeOverlayConversation.projectionSource !== "pending_activation" && matchesAgentGUIConversationSummaryFilter(
27368
- activeOverlayConversation,
27369
- conversationFilter
27370
- )
27371
- );
27372
- const sectionTotalCount = backendSearchActive ? section.items.length + (searchSectionHasMore ? 1 : 0) : sectionPageState?.totalCount ?? section.items.filter(
27373
- (item) => item.projectionSource !== "pending_activation"
27374
- ).length + (activeOverlayCountsTowardTotal && !activeOverlayIsCanonical ? 1 : 0);
27375
- const sectionHasMore = searchSectionHasMore || !conversationQuery.trim() && sectionPageState?.hasMore === true;
27376
- return /* @__PURE__ */ jsxs35(Fragment13, { children: [
27377
- showProjectRailHeader ? /* @__PURE__ */ jsx48(
27378
- AgentGUIProjectRailHeader,
27379
- {
27380
- labels,
27381
- selectProjectDirectory,
27382
- workspaceUserProjectI18n
27383
- }
27384
- ) : null,
27385
- /* @__PURE__ */ jsx48(
27386
- AgentGUIConversationRailSection,
27387
- {
27388
- activeConversation: activeOverlayConversation,
27389
- activeConversationCountsTowardTotal: activeOverlayCountsTowardTotal,
27390
- activeConversationId,
27391
- createConversationDisabled,
27392
- currentTimeMs,
27393
- isDeletingConversation,
27394
- isDeletingProjectConversations,
27395
- isRequestingBatchDeletion,
27396
- isConversationSearchActive: Boolean(
27397
- conversationQuery.trim()
27398
- ),
27399
- isLoadingMoreConversations: backendSearchActive ? railSearch.loadingMore : runtimeRailSectionsPending || (sectionPageState?.isLoading ?? false),
27400
- isSectionCollapsed,
27401
- labels,
27402
- pendingDeleteConversationId,
27403
- paginationScopeKey: sectionPaginationScopeKey,
27404
- previewMode,
27405
- projectLabel,
27406
- projectPath,
27407
- registerItemElement: registerConversationItemElement,
27408
- section,
27409
- sectionHasMore,
27410
- sectionTotalCount,
27411
- uiLanguage,
27412
- workspaceId,
27413
- onCancelDeleteConversation,
27414
- onConfirmDeleteConversation,
27415
- onCreateConversation,
27416
- onLoadMoreConversations: backendSearchActive ? railSearch.loadMore : loadMoreSectionConversations,
27417
- onRequestDeleteConversation,
27418
- onRequestRenameConversation,
27419
- onSelectConversation,
27420
- onRequestSectionBatchDeletion: requestSectionBatchDeletion,
27421
- setPendingProjectAction,
27422
- onToggleConversationPinned,
27423
- onMarkConversationUnread,
27424
- onOpenProjectFiles,
27425
- onOpenConversationWindow,
27426
- onToggleProjectSectionCollapsed: toggleProjectSectionCollapsed
27427
- }
27428
- )
27429
- ] }, section.id);
27430
- })
27728
+ ] }) : 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(
27729
+ "fieldset",
27730
+ {
27731
+ className: "contents",
27732
+ disabled: runtimeRailSectionsPending && !backendSearchActive,
27733
+ children: groupedConversations.map((section, sectionIndex) => {
27734
+ const projectPath = section.kind === "project" ? section.project?.path ?? "" : "";
27735
+ const projectLabel = section.kind === "project" ? section.label : "";
27736
+ const isProjectSection = section.kind === "project";
27737
+ const showProjectRailHeader = !conversationQuery.trim() && section.kind !== "pinned" && (sectionIndex === 0 || groupedConversations[sectionIndex - 1]?.kind === "pinned");
27738
+ const isSectionCollapsed = isProjectSection && collapsedProjectSectionIds.has(section.id);
27739
+ const sectionPageState = sectionPageStates.get(section.id);
27740
+ const searchSectionHasMore = backendSearchActive && sectionIndex === groupedConversations.length - 1 && railSearch.hasMore;
27741
+ const activeOverlayConversation = !backendSearchActive && railActiveOverlay?.sectionId === section.id && (!conversationQuery.trim() || filteredConversations.some(
27742
+ (conversation) => conversation.id === railActiveOverlay.conversation.id
27743
+ )) ? railActiveOverlay.conversation : null;
27744
+ const activeOverlayIsCanonical = Boolean(
27745
+ activeOverlayConversation && section.items.some(
27746
+ (item) => item.projectionSource !== "pending_activation" && item.id === activeOverlayConversation.id
27747
+ )
27748
+ );
27749
+ const activeOverlayCountsTowardTotal = Boolean(
27750
+ activeOverlayConversation && activeOverlayConversation.projectionSource !== "pending_activation" && matchesAgentGUIConversationSummaryFilter(
27751
+ activeOverlayConversation,
27752
+ conversationFilter
27753
+ )
27754
+ );
27755
+ const sectionTotalCount = backendSearchActive ? section.items.length + (searchSectionHasMore ? 1 : 0) : sectionPageState?.totalCount ?? section.items.filter(
27756
+ (item) => item.projectionSource !== "pending_activation"
27757
+ ).length + (activeOverlayCountsTowardTotal && !activeOverlayIsCanonical ? 1 : 0);
27758
+ const sectionHasMore = searchSectionHasMore || !conversationQuery.trim() && sectionPageState?.hasMore === true;
27759
+ return /* @__PURE__ */ jsxs35(Fragment13, { children: [
27760
+ showProjectRailHeader ? /* @__PURE__ */ jsx48(
27761
+ AgentGUIProjectRailHeader,
27762
+ {
27763
+ disabled: railInteractionsLocked,
27764
+ labels,
27765
+ selectProjectDirectory,
27766
+ workspaceUserProjectI18n
27767
+ }
27768
+ ) : null,
27769
+ /* @__PURE__ */ jsx48(
27770
+ AgentGUIConversationRailSection,
27771
+ {
27772
+ activeConversation: activeOverlayConversation,
27773
+ activeConversationCountsTowardTotal: activeOverlayCountsTowardTotal,
27774
+ activeConversationId,
27775
+ createConversationDisabled,
27776
+ currentTimeMs,
27777
+ isDeletingConversation,
27778
+ isDeletingProjectConversations,
27779
+ isRequestingBatchDeletion,
27780
+ isConversationSearchActive: Boolean(
27781
+ conversationQuery.trim()
27782
+ ),
27783
+ isLoadingMoreConversations: backendSearchActive ? railSearch.loadingMore : sectionPageState?.isLoading ?? false,
27784
+ isRailInteractionLocked: isInteractionLocked,
27785
+ isSectionCollapsed,
27786
+ labels,
27787
+ pendingDeleteConversationId,
27788
+ paginationScopeKey: sectionPaginationScopeKey,
27789
+ previewMode,
27790
+ projectLabel,
27791
+ projectPath,
27792
+ registerItemElement: registerConversationItemElement,
27793
+ section,
27794
+ sectionHasMore,
27795
+ sectionTotalCount,
27796
+ uiLanguage,
27797
+ workspaceId,
27798
+ onCancelDeleteConversation,
27799
+ onConfirmDeleteConversation,
27800
+ onCreateConversation,
27801
+ onLoadMoreConversations: backendSearchActive ? railSearch.loadMore : loadMoreSectionConversations,
27802
+ onRequestDeleteConversation,
27803
+ onRequestRenameConversation,
27804
+ onSelectConversation,
27805
+ onRequestSectionBatchDeletion: requestSectionBatchDeletion,
27806
+ setPendingProjectAction,
27807
+ onToggleConversationPinned,
27808
+ onMarkConversationUnread,
27809
+ onOpenProjectFiles,
27810
+ onOpenConversationWindow,
27811
+ onToggleProjectSectionCollapsed: toggleProjectSectionCollapsed
27812
+ }
27813
+ )
27814
+ ] }, section.id);
27815
+ })
27816
+ }
27817
+ )
27431
27818
  }
27432
27819
  ),
27433
27820
  footer ? /* @__PURE__ */ jsx48("div", { className: "shrink-0 pb-2", children: footer }) : null,
@@ -27437,6 +27824,7 @@ var AgentGUIConversationRailPane = memo7(
27437
27824
  cancelLabel: labels.cancel,
27438
27825
  className: AGENT_GUI_CONFIRMATION_DIALOG_CLASS_NAME,
27439
27826
  confirmBusy: (pendingProjectAction?.kind === "batch-delete" || pendingProjectAction?.kind === "batch-delete-conversations") && isDeletingProjectConversations,
27827
+ confirmDisabled: railInteractionsLocked,
27440
27828
  confirmLabel: pendingProjectAction?.kind === "batch-delete" ? labels.batchDeleteProjectSessionsConfirm : pendingProjectAction?.kind === "batch-delete-conversations" ? labels.batchDeleteConversationsConfirm : labels.removeProject,
27441
27829
  description: pendingProjectAction?.kind === "batch-delete" ? labels.batchDeleteProjectSessionsBody(
27442
27830
  pendingProjectAction.conversationCount,
@@ -27448,6 +27836,7 @@ var AgentGUIConversationRailPane = memo7(
27448
27836
  ) : void 0,
27449
27837
  onCancel: () => setPendingProjectAction(null),
27450
27838
  onConfirm: () => {
27839
+ if (isInteractionLocked()) return;
27451
27840
  const action = pendingProjectAction;
27452
27841
  setPendingProjectAction(null);
27453
27842
  if (!action) {
@@ -27481,8 +27870,10 @@ var AgentGUIConversationRailPane = memo7(
27481
27870
  );
27482
27871
 
27483
27872
  // agent-gui/agentGuiNode/controller/useAgentGUIConversationRailQuery.ts
27484
- import { selectWorkspaceAgentConsumerSessions as selectWorkspaceAgentConsumerSessions4 } from "@tutti-os/agent-activity-core";
27485
- import { useDeferredValue, useEffect as useEffect31, useMemo as useMemo32, useRef as useRef34 } from "react";
27873
+ import {
27874
+ selectWorkspaceAgentConsumerSessions as selectWorkspaceAgentConsumerSessions4
27875
+ } from "@tutti-os/agent-activity-core";
27876
+ import { useDeferredValue, useEffect as useEffect31, useMemo as useMemo33, useRef as useRef34 } from "react";
27486
27877
 
27487
27878
  // agent-gui/agentGuiNode/controller/AgentGUIConversationRailQueryController.ts
27488
27879
  import {
@@ -27510,6 +27901,7 @@ var EMPTY_QUERY_STATE = {
27510
27901
  };
27511
27902
  var AgentGUIConversationRailQueryController = class {
27512
27903
  getSnapshot = () => this.snapshot;
27904
+ isInteractionLocked = () => this.snapshot.runtimeRailSectionsPending && !(this.searchQuery && this.snapshot.railSearch.enabled);
27513
27905
  subscribe = (listener) => {
27514
27906
  this.listeners.add(listener);
27515
27907
  return () => this.listeners.delete(listener);
@@ -27589,7 +27981,7 @@ var AgentGUIConversationRailQueryController = class {
27589
27981
  this.searchQuery = query;
27590
27982
  this.requestSearch();
27591
27983
  }
27592
- loadMoreSectionConversations(section) {
27984
+ loadMoreSectionConversations = (section) => {
27593
27985
  const scopeKey = this.railSectionQueryKey;
27594
27986
  if (this.scope?.previewMode || !scopeKey || this.queryState.pending || this.queryState.resolvedScopeKey !== scopeKey) {
27595
27987
  return;
@@ -27676,8 +28068,8 @@ var AgentGUIConversationRailQueryController = class {
27676
28068
  this.pagingAbortControllers.delete(section.id);
27677
28069
  }
27678
28070
  });
27679
- }
27680
- loadMoreSearchResults() {
28071
+ };
28072
+ loadMoreSearchResults = () => {
27681
28073
  const listSessionsPage = this.runtime.listSessionsPage;
27682
28074
  if (!this.searchEnabled() || !listSessionsPage || this.searchState.pending || this.searchState.loadingMore || !this.searchState.hasMore || !this.searchState.nextCursor || this.searchState.requestKey !== this.searchRequestKey || this.searchState.resolvedQuery !== this.searchQuery) {
27683
28075
  return;
@@ -27723,11 +28115,11 @@ var AgentGUIConversationRailQueryController = class {
27723
28115
  };
27724
28116
  this.emit();
27725
28117
  });
27726
- }
27727
- retrySearchResults() {
28118
+ };
28119
+ retrySearchResults = () => {
27728
28120
  if (!this.searchQuery || !this.searchEnabled()) return;
27729
28121
  this.requestSearch();
27730
- }
28122
+ };
27731
28123
  handleEngineState(state) {
27732
28124
  const next = membershipRecords(state);
27733
28125
  if (this.ingestingSessions || !this.runtimeSectionsEnabled()) {
@@ -27992,14 +28384,14 @@ function useAgentGUIConversationRailQuery({
27992
28384
  workspaceId
27993
28385
  }) {
27994
28386
  const runtime = useAgentActivityRuntime();
27995
- const engine = useMemo32(
28387
+ const engine = useMemo33(
27996
28388
  () => runtime.getSessionEngine(workspaceId),
27997
28389
  [runtime, workspaceId]
27998
28390
  );
27999
28391
  const activeConversationIdRef = useRef34(activeConversationId);
28000
28392
  activeConversationIdRef.current = activeConversationId;
28001
28393
  const deferredConversationQuery = useDeferredValue(conversationQuery);
28002
- const controller = useMemo32(
28394
+ const controller = useMemo33(
28003
28395
  () => new AgentGUIConversationRailQueryController({
28004
28396
  engine,
28005
28397
  getActiveConversationId: () => activeConversationIdRef.current,
@@ -28030,28 +28422,37 @@ function useAgentGUIConversationRailQuery({
28030
28422
  identitySnapshot,
28031
28423
  Object.is
28032
28424
  );
28033
- const engineConsumerSessions = useEngineSelector(
28425
+ const runtimeRailConversations = useEngineSelector(
28034
28426
  engine,
28035
- selectWorkspaceAgentConsumerSessions4
28036
- );
28037
- const runtimeRailConversations = useMemo32(
28038
- () => projectCanonicalAgentGUIConversationSummaries(engineConsumerSessions),
28039
- [engineConsumerSessions]
28427
+ selectRuntimeRailConversations,
28428
+ conversationSummaryListsRenderEqual
28040
28429
  );
28041
- return useMemo32(
28430
+ return useMemo33(
28042
28431
  () => ({
28043
28432
  ...querySnapshot,
28044
- loadMoreSectionConversations: (section) => controller.loadMoreSectionConversations(section),
28433
+ isInteractionLocked: controller.isInteractionLocked,
28434
+ loadMoreSectionConversations: controller.loadMoreSectionConversations,
28045
28435
  railSearch: {
28046
28436
  ...querySnapshot.railSearch,
28047
- loadMore: () => controller.loadMoreSearchResults(),
28048
- retry: () => controller.retrySearchResults()
28437
+ loadMore: controller.loadMoreSearchResults,
28438
+ retry: controller.retrySearchResults
28049
28439
  },
28050
28440
  runtimeRailConversations
28051
28441
  }),
28052
28442
  [controller, querySnapshot, runtimeRailConversations]
28053
28443
  );
28054
28444
  }
28445
+ function selectRuntimeRailConversations(state) {
28446
+ return projectCanonicalAgentGUIConversationSummaries(
28447
+ selectWorkspaceAgentConsumerSessions4(state)
28448
+ );
28449
+ }
28450
+ function conversationSummaryListsRenderEqual(left, right) {
28451
+ return left.length === right.length && left.every((conversation, index) => {
28452
+ const other = right[index];
28453
+ return other !== void 0 && conversationSummariesRenderEqual2(conversation, other);
28454
+ });
28455
+ }
28055
28456
  function identitySnapshot(snapshot) {
28056
28457
  return snapshot;
28057
28458
  }
@@ -28087,7 +28488,7 @@ import {
28087
28488
  memo as memo12,
28088
28489
  useCallback as useCallback45,
28089
28490
  useEffect as useEffect34,
28090
- useMemo as useMemo34,
28491
+ useMemo as useMemo35,
28091
28492
  useRef as useRef36,
28092
28493
  useState as useState31
28093
28494
  } from "react";
@@ -28096,6 +28497,18 @@ import { ScrollArea as ScrollArea2 } from "@tutti-os/ui-system/components";
28096
28497
 
28097
28498
  // agent-gui/agentGuiNode/view/agentGUIDetailModelHelpers.ts
28098
28499
  import { useRef as useRef35 } from "react";
28500
+ function commandAppSource(command) {
28501
+ if (!command || typeof command !== "object" || !("source" in command)) {
28502
+ return null;
28503
+ }
28504
+ const source = command.source;
28505
+ if (!source || typeof source !== "object") return null;
28506
+ const sourceRecord = source;
28507
+ return sourceRecord.kind === "app" ? sourceRecord : null;
28508
+ }
28509
+ function workspaceAppIconKey(appId, workspaceId) {
28510
+ return `${workspaceId}\0${appId}`;
28511
+ }
28099
28512
  function isDifferentKnownConversationOwner(input) {
28100
28513
  const conversationUserId = input.conversationUserId?.trim() ?? "";
28101
28514
  const currentUserId = input.currentUserId?.trim() ?? "";
@@ -29019,7 +29432,7 @@ function useAgentGUIDetailScroll(input) {
29019
29432
  }
29020
29433
 
29021
29434
  // agent-gui/agentGuiNode/view/useAgentGUIDetailModel.tsx
29022
- import { useMemo as useMemo33 } from "react";
29435
+ import { useMemo as useMemo34 } from "react";
29023
29436
 
29024
29437
  // app/renderer/components/icons/UnavailableChatIcon.tsx
29025
29438
  import { jsx as jsx54 } from "react/jsx-runtime";
@@ -29061,11 +29474,11 @@ function useAgentGUIDetailModel(input) {
29061
29474
  const emptyProviderReadinessGate = !hasActiveConversation ? selectedAgentTargetComingSoon ? { status: "coming_soon" } : viewModel.readiness.providerReadinessGate : null;
29062
29475
  const activePrompt = viewModel.interaction.pendingInteractivePrompt ?? viewModel.interaction.pendingApproval;
29063
29476
  const activePromptRequestId = activePrompt?.requestId ?? null;
29064
- const sessionChrome = useMemo33(
29477
+ const sessionChrome = useMemo34(
29065
29478
  () => ({ ...viewModel.interaction.sessionChrome, approval: null }),
29066
29479
  [viewModel.interaction.sessionChrome]
29067
29480
  );
29068
- const rawSlashStatus = useMemo33(
29481
+ const rawSlashStatus = useMemo34(
29069
29482
  () => resolveSlashStatus({
29070
29483
  rawState: viewModel.interaction.sessionChrome.rawState,
29071
29484
  limits: slashStatusLimits,
@@ -29082,7 +29495,7 @@ function useAgentGUIDetailModel(input) {
29082
29495
  ]
29083
29496
  );
29084
29497
  const slashStatus = useStableSlashStatus(rawSlashStatus);
29085
- const displayedInlineNotice = useMemo33(() => {
29498
+ const displayedInlineNotice = useMemo34(() => {
29086
29499
  const inlineNotice = viewModel.interaction.inlineNotice;
29087
29500
  const inlineNoticeMessage = inlineNotice?.message.trim() ?? "";
29088
29501
  if (!inlineNotice || inlineNoticeMessage === "") {
@@ -29106,7 +29519,7 @@ function useAgentGUIDetailModel(input) {
29106
29519
  viewModel.readiness.activeLiveState,
29107
29520
  viewModel.interaction.inlineNotice
29108
29521
  ]);
29109
- const inlineNoticeChrome = useMemo33(() => {
29522
+ const inlineNoticeChrome = useMemo34(() => {
29110
29523
  if (!displayedInlineNotice) {
29111
29524
  return null;
29112
29525
  }
@@ -29150,7 +29563,7 @@ function useAgentGUIDetailModel(input) {
29150
29563
  const submitDisabled = hasNonRetryableRecoveryFailure || isCollaboratorConversation || !isAgentProviderReady || !viewModel.composer.canSubmit && !canQueueWhileBusy;
29151
29564
  const composerDisabled = hasNonRetryableRecoveryFailure || isCollaboratorConversation || !isAgentProviderReady || !canQueueWhileBusy && (viewModel.interaction.pendingApproval !== null || viewModel.interaction.pendingInteractivePrompt !== null || viewModel.composer.isSubmitting || viewModel.composer.isInterrupting || viewModel.composer.isCreatingConversation);
29152
29565
  const showStopButton = !viewModel.composer.isSubmitting && viewModel.readiness.activeLiveState !== "failed" && sessionChrome.auth === null && (activeConversationTurnBusy || viewModel.interaction.pendingApproval !== null || viewModel.interaction.pendingInteractivePrompt !== null || viewModel.composer.isInterrupting);
29153
- const conversationFlowLabels = useMemo33(
29566
+ const conversationFlowLabels = useMemo34(
29154
29567
  () => ({
29155
29568
  thinkingLabel: labels.thinkingLabel,
29156
29569
  toolCallsLabel: labels.toolCallsLabel,
@@ -29166,7 +29579,7 @@ function useAgentGUIDetailModel(input) {
29166
29579
  labels.userMessageLocator
29167
29580
  ]
29168
29581
  );
29169
- const conversationFlowEmpty = useMemo33(
29582
+ const conversationFlowEmpty = useMemo34(
29170
29583
  () => showUnavailableChatEmpty ? /* @__PURE__ */ jsxs40(
29171
29584
  "div",
29172
29585
  {
@@ -29180,7 +29593,7 @@ function useAgentGUIDetailModel(input) {
29180
29593
  ) : /* @__PURE__ */ jsx55(Fragment15, {}),
29181
29594
  [labels.conversationUnavailable, showUnavailableChatEmpty]
29182
29595
  );
29183
- const chromeLabels = useMemo33(
29596
+ const chromeLabels = useMemo34(
29184
29597
  () => ({
29185
29598
  approvalRequired: labels.approvalRequired,
29186
29599
  authRequired: labels.authRequired,
@@ -29201,7 +29614,7 @@ function useAgentGUIDetailModel(input) {
29201
29614
  viewModel.composer.isCancelPending
29202
29615
  ]
29203
29616
  );
29204
- const goalBannerLabels = useMemo33(
29617
+ const goalBannerLabels = useMemo34(
29205
29618
  () => ({
29206
29619
  titleActive: labels.goalTitleActive,
29207
29620
  titlePaused: labels.goalTitlePaused,
@@ -29231,7 +29644,7 @@ function useAgentGUIDetailModel(input) {
29231
29644
  labels.goalClearAction
29232
29645
  ]
29233
29646
  );
29234
- const interactivePromptLabels = useMemo33(
29647
+ const interactivePromptLabels = useMemo34(
29235
29648
  () => ({
29236
29649
  approvalLead: labels.approvalRequired,
29237
29650
  planLead: labels.planLead,
@@ -29269,7 +29682,7 @@ function useAgentGUIDetailModel(input) {
29269
29682
  labels.planImplementationSkip
29270
29683
  ]
29271
29684
  );
29272
- const composerLabels = useMemo33(
29685
+ const composerLabels = useMemo34(
29273
29686
  () => ({
29274
29687
  send: labels.send,
29275
29688
  modelLabel: labels.modelLabel,
@@ -29595,22 +30008,9 @@ function mergeWorkspaceAppIconsFromCommands(input) {
29595
30008
  }
29596
30009
  return next ?? input.workspaceAppIcons;
29597
30010
  }
29598
- function commandAppSource(command) {
29599
- if (!command || typeof command !== "object" || !("source" in command)) {
29600
- return null;
29601
- }
29602
- const source = command.source;
29603
- if (!source || typeof source !== "object") {
29604
- return null;
29605
- }
29606
- const sourceRecord = source;
29607
- return sourceRecord.kind === "app" ? sourceRecord : null;
29608
- }
29609
- function workspaceAppIconKey(appId, workspaceId) {
29610
- return `${workspaceId}\0${appId}`;
29611
- }
29612
30011
  var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29613
30012
  viewModel,
30013
+ composerEngagement,
29614
30014
  actions,
29615
30015
  labels,
29616
30016
  workspaceUserProjectI18n,
@@ -29814,7 +30214,24 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29814
30214
  const agentTargetId = viewModel.shell.data.agentTargetId;
29815
30215
  return !agentTargetId || target.targetId === agentTargetId || target.agentTargetId === agentTargetId;
29816
30216
  }) ?? viewModel.rail.selectedAgentTarget;
29817
- const bottomDockComposerProps = useMemo34(
30217
+ const stableHandoffConversation = useOptionalStableEventCallback(
30218
+ onHandoffConversation && viewModel.rail.activeConversationId !== null ? (target) => onHandoffConversation({
30219
+ agentTargetId: target.agentTargetId ?? target.targetId,
30220
+ draftPrompt: buildAgentConversationHandoffPrompt({
30221
+ activeConversation: viewModel.rail.activeConversation,
30222
+ currentUserId: viewModel.shell.currentUserId,
30223
+ labels,
30224
+ selectedAgentTarget: composerSelectedProviderTarget,
30225
+ uiLanguage,
30226
+ workspaceId: viewModel.shell.workspaceId
30227
+ }),
30228
+ provider: target.provider,
30229
+ userProjectPath: handoffProjectPathForConversation(
30230
+ viewModel.rail.activeConversation
30231
+ )
30232
+ }) : void 0
30233
+ );
30234
+ const bottomDockComposerProps = useMemo35(
29818
30235
  () => ({
29819
30236
  workspaceId: viewModel.shell.workspaceId,
29820
30237
  workspacePath: viewModel.shell.workspacePath,
@@ -29824,6 +30241,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29824
30241
  onSlashStatusOpen,
29825
30242
  usage: viewModel.detail.usage,
29826
30243
  draftContent: viewModel.composer.draftContent,
30244
+ engagement: composerEngagement,
29827
30245
  draftScopeKey: resolveAgentComposerDraftScopeKey({
29828
30246
  agentSessionId: viewModel.rail.activeConversationId
29829
30247
  }),
@@ -29849,8 +30267,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29849
30267
  showStopButton,
29850
30268
  previewMode,
29851
30269
  workspaceReferencePickerOpen,
29852
- // Plan decisions replace the composer via bottomDockReplacementPrompt;
29853
- // approval / ask-user embed here (composerActivePrompt encodes that).
30270
+ // Plan decisions replace the composer; approval / ask-user embed here.
29854
30271
  activePrompt: composerActivePrompt,
29855
30272
  backgroundAgentStatusText,
29856
30273
  activePromptKeyboardShortcutsEnabled: isActive,
@@ -29881,21 +30298,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29881
30298
  onSubmitInteractivePrompt: submitInteractivePrompt,
29882
30299
  onCapabilitySettingsRequest,
29883
30300
  onLinkAction: stableLinkAction,
29884
- onHandoffConversation: onHandoffConversation && viewModel.rail.activeConversationId !== null ? (target) => onHandoffConversation({
29885
- agentTargetId: target.agentTargetId ?? target.targetId,
29886
- draftPrompt: buildAgentConversationHandoffPrompt({
29887
- activeConversation: viewModel.rail.activeConversation,
29888
- currentUserId: viewModel.shell.currentUserId,
29889
- labels,
29890
- selectedAgentTarget: composerSelectedProviderTarget,
29891
- uiLanguage,
29892
- workspaceId: viewModel.shell.workspaceId
29893
- }),
29894
- provider: target.provider,
29895
- userProjectPath: handoffProjectPathForConversation(
29896
- viewModel.rail.activeConversation
29897
- )
29898
- }) : void 0,
30301
+ onHandoffConversation: stableHandoffConversation,
29899
30302
  onRequestWorkspaceReferences: stableRequestWorkspaceReferences,
29900
30303
  resolveDroppedFileReferences,
29901
30304
  selectProjectDirectory: stableSelectProjectDirectory,
@@ -29910,6 +30313,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29910
30313
  composerDisabled,
29911
30314
  composerDisabledReason,
29912
30315
  composerFocusRequestSequence,
30316
+ composerEngagement,
29913
30317
  composerHandoffProviderTargets,
29914
30318
  composerLabels,
29915
30319
  composerProviderTargets,
@@ -29925,7 +30329,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29925
30329
  labels.promptTips,
29926
30330
  labels.providerSwitchLabel,
29927
30331
  labels,
29928
- onHandoffConversation,
30332
+ stableHandoffConversation,
29929
30333
  onSlashStatusOpen,
29930
30334
  previewMode,
29931
30335
  workspaceReferencePickerOpen,
@@ -29976,7 +30380,7 @@ var AgentGUIDetailPane = memo12(function AgentGUIDetailPane2({
29976
30380
  selectHomeComposerAgentTargetAndFocus
29977
30381
  ]
29978
30382
  );
29979
- const emptyHeroComposerProps = useMemo34(
30383
+ const emptyHeroComposerProps = useMemo35(
29980
30384
  () => ({
29981
30385
  ...bottomDockComposerProps,
29982
30386
  layoutMode: "hero"
@@ -30170,10 +30574,14 @@ var AgentGUIRenameConversationDialog = memo13(
30170
30574
  "use memo";
30171
30575
  const [title, setTitle] = useState32("");
30172
30576
  const [isSaving, setIsSaving] = useState32(false);
30577
+ const isSavingRef = useRef37(false);
30578
+ const armedPointerActionRef = useRef37(null);
30173
30579
  const inputRef = useRef37(null);
30174
30580
  const trimmedTitle = title.trim();
30175
30581
  useEffect35(() => {
30176
30582
  if (!open || !conversation) {
30583
+ isSavingRef.current = false;
30584
+ armedPointerActionRef.current = null;
30177
30585
  setTitle("");
30178
30586
  setIsSaving(false);
30179
30587
  return;
@@ -30191,23 +30599,25 @@ var AgentGUIRenameConversationDialog = memo13(
30191
30599
  return () => window.clearTimeout(timer);
30192
30600
  }, [open, conversation?.id]);
30193
30601
  const closeRenameDialog = useCallback46(() => {
30194
- if (!isSaving) {
30602
+ if (!isSavingRef.current) {
30195
30603
  onOpenChange(false);
30196
30604
  }
30197
- }, [isSaving, onOpenChange]);
30605
+ }, [onOpenChange]);
30198
30606
  const confirmRename = useCallback46(() => {
30199
- if (!conversation || isSaving || !trimmedTitle) {
30607
+ if (!conversation || isSavingRef.current || !trimmedTitle) {
30200
30608
  return;
30201
30609
  }
30610
+ isSavingRef.current = true;
30202
30611
  setIsSaving(true);
30203
30612
  void onRename(conversation.id, trimmedTitle).then(() => {
30204
30613
  onOpenChange(false);
30205
30614
  }).catch(() => {
30206
30615
  inputRef.current?.focus();
30207
30616
  }).finally(() => {
30617
+ isSavingRef.current = false;
30208
30618
  setIsSaving(false);
30209
30619
  });
30210
- }, [conversation, isSaving, onOpenChange, onRename, trimmedTitle]);
30620
+ }, [conversation, onOpenChange, onRename, trimmedTitle]);
30211
30621
  return /* @__PURE__ */ jsx57(
30212
30622
  ConfirmationDialog2,
30213
30623
  {
@@ -30226,8 +30636,30 @@ var AgentGUIRenameConversationDialog = memo13(
30226
30636
  type: "button",
30227
30637
  variant: "ghost",
30228
30638
  onClick: closeRenameDialog,
30229
- onPointerUp: (event) => {
30639
+ onLostPointerCapture: () => {
30640
+ if (armedPointerActionRef.current === "cancel") {
30641
+ armedPointerActionRef.current = null;
30642
+ }
30643
+ },
30644
+ onPointerCancel: () => {
30645
+ if (armedPointerActionRef.current === "cancel") {
30646
+ armedPointerActionRef.current = null;
30647
+ }
30648
+ },
30649
+ onPointerDown: (event) => {
30230
30650
  if (event.button === 0) {
30651
+ armedPointerActionRef.current = "cancel";
30652
+ }
30653
+ },
30654
+ onPointerLeave: () => {
30655
+ if (armedPointerActionRef.current === "cancel") {
30656
+ armedPointerActionRef.current = null;
30657
+ }
30658
+ },
30659
+ onPointerUp: (event) => {
30660
+ const isArmed = armedPointerActionRef.current === "cancel";
30661
+ armedPointerActionRef.current = null;
30662
+ if (event.button === 0 && isArmed) {
30231
30663
  closeRenameDialog();
30232
30664
  }
30233
30665
  },
@@ -30242,7 +30674,45 @@ var AgentGUIRenameConversationDialog = memo13(
30242
30674
  size: "dialog",
30243
30675
  type: "button",
30244
30676
  variant: "default",
30245
- onClick: confirmRename,
30677
+ onClick: (event) => {
30678
+ if (event.detail !== 0) {
30679
+ return;
30680
+ }
30681
+ confirmRename();
30682
+ },
30683
+ onKeyDown: (event) => {
30684
+ if ((event.key === "Enter" || event.key === " ") && !event.repeat) {
30685
+ event.preventDefault();
30686
+ confirmRename();
30687
+ }
30688
+ },
30689
+ onLostPointerCapture: () => {
30690
+ if (armedPointerActionRef.current === "confirm") {
30691
+ armedPointerActionRef.current = null;
30692
+ }
30693
+ },
30694
+ onPointerCancel: () => {
30695
+ if (armedPointerActionRef.current === "confirm") {
30696
+ armedPointerActionRef.current = null;
30697
+ }
30698
+ },
30699
+ onPointerDown: (event) => {
30700
+ if (event.button === 0) {
30701
+ armedPointerActionRef.current = "confirm";
30702
+ }
30703
+ },
30704
+ onPointerLeave: () => {
30705
+ if (armedPointerActionRef.current === "confirm") {
30706
+ armedPointerActionRef.current = null;
30707
+ }
30708
+ },
30709
+ onPointerUp: (event) => {
30710
+ const isArmed = armedPointerActionRef.current === "confirm";
30711
+ armedPointerActionRef.current = null;
30712
+ if (event.button === 0 && isArmed) {
30713
+ confirmRename();
30714
+ }
30715
+ },
30246
30716
  children: labels.renameSessionSave
30247
30717
  }
30248
30718
  )
@@ -30274,7 +30744,7 @@ var AgentGUIRenameConversationDialog = memo13(
30274
30744
  );
30275
30745
 
30276
30746
  // agent-gui/agentGuiNode/view/useAgentGUIWorkspaceReferencePicker.ts
30277
- import { useCallback as useCallback47, useMemo as useMemo35, useRef as useRef38, useState as useState33 } from "react";
30747
+ import { useCallback as useCallback47, useMemo as useMemo36, useRef as useRef38, useState as useState33 } from "react";
30278
30748
  import { createRichTextMentionHref } from "@tutti-os/ui-rich-text/core";
30279
30749
  function useAgentGUIWorkspaceReferencePicker(input) {
30280
30750
  const {
@@ -30290,7 +30760,7 @@ function useAgentGUIWorkspaceReferencePicker(input) {
30290
30760
  const [workspaceReferencePickerOpen, setWorkspaceReferencePickerOpen] = useState33(false);
30291
30761
  const [workspaceReferencePickerTarget, setWorkspaceReferencePickerTarget] = useState33(null);
30292
30762
  const workspaceReferencePickerResolverRef = useRef38(null);
30293
- const emptyReferencePickResult = useMemo35(
30763
+ const emptyReferencePickResult = useMemo36(
30294
30764
  () => ({ files: [], mentionItems: [] }),
30295
30765
  []
30296
30766
  );
@@ -30403,9 +30873,256 @@ function useAgentGUIWorkspaceReferencePicker(input) {
30403
30873
  };
30404
30874
  }
30405
30875
 
30876
+ // agent-gui/agentGuiNode/engagement/useAgentGUINodeEngagement.ts
30877
+ import { useRef as useRef40 } from "react";
30878
+
30879
+ // agent-gui/agentGuiNode/engagement/projectAgentGUIEngagementContext.ts
30880
+ function projectAgentGUIEngagementContext(viewModel, composerReady) {
30881
+ const agentSessionId = viewModel.rail.activeConversationId;
30882
+ const provider = viewModel.rail.activeConversation?.provider ?? viewModel.rail.selectedAgentTarget.provider ?? viewModel.shell.data.provider;
30883
+ const agentTargetId = viewModel.rail.activeConversation?.agentTargetId ?? viewModel.rail.selectedAgentTarget.agentTargetId ?? viewModel.rail.selectedAgentTarget.targetId ?? null;
30884
+ return {
30885
+ context: {
30886
+ agentSessionId,
30887
+ agentTargetId,
30888
+ composerReady,
30889
+ conversationState: agentSessionId ? "existing" : "new",
30890
+ provider
30891
+ },
30892
+ contextKey: createAgentGUIEngagementContextKey({
30893
+ agentSessionId,
30894
+ agentTargetId,
30895
+ provider
30896
+ })
30897
+ };
30898
+ }
30899
+ function createAgentGUIEngagementContextKey(input) {
30900
+ return JSON.stringify([
30901
+ input.agentSessionId ? "session" : "home",
30902
+ input.agentSessionId,
30903
+ input.provider,
30904
+ input.agentTargetId
30905
+ ]);
30906
+ }
30907
+
30908
+ // agent-gui/agentGuiNode/engagement/useAgentGUIPanelEngagement.ts
30909
+ import { useEffect as useEffect36, useRef as useRef39 } from "react";
30910
+
30911
+ // agent-gui/agentGuiNode/engagement/AgentGUIPanelEngagementController.ts
30912
+ var AGENT_GUI_PANEL_EXPOSURE_DWELL_MS = 1e3;
30913
+ var AGENT_GUI_PANEL_EXPOSURE_INTERSECTION_RATIO = 0.5;
30914
+ var AgentGUIPanelEngagementController = class {
30915
+ constructor(options) {
30916
+ this.options = options;
30917
+ this.intersectionRatio = options.initialIntersectionRatio;
30918
+ }
30919
+ options;
30920
+ documentFocused = documentHasFocus();
30921
+ documentVisible = documentIsVisible();
30922
+ intersectionObserver = null;
30923
+ intersectionRatio;
30924
+ visit = null;
30925
+ attach() {
30926
+ document.addEventListener("visibilitychange", this.updateDocumentState);
30927
+ window.addEventListener("blur", this.updateDocumentState);
30928
+ window.addEventListener("focus", this.updateDocumentState);
30929
+ if (typeof IntersectionObserver === "undefined") {
30930
+ this.intersectionRatio = 0;
30931
+ } else {
30932
+ this.intersectionObserver = new IntersectionObserver(
30933
+ this.updateIntersection,
30934
+ {
30935
+ threshold: [0, AGENT_GUI_PANEL_EXPOSURE_INTERSECTION_RATIO, 1]
30936
+ }
30937
+ );
30938
+ this.intersectionObserver.observe(this.options.element);
30939
+ }
30940
+ this.reconcileVisit();
30941
+ }
30942
+ dispose() {
30943
+ document.removeEventListener("visibilitychange", this.updateDocumentState);
30944
+ window.removeEventListener("blur", this.updateDocumentState);
30945
+ window.removeEventListener("focus", this.updateDocumentState);
30946
+ this.intersectionObserver?.disconnect();
30947
+ this.endVisit();
30948
+ return this.intersectionRatio;
30949
+ }
30950
+ focused(focusMethod) {
30951
+ this.reconcileVisit();
30952
+ const visit = this.visit;
30953
+ if (!visit || visit.pendingFocusMethod) return;
30954
+ visit.pendingFocusMethod = focusMethod;
30955
+ if (!visit.exposed) return;
30956
+ this.report({
30957
+ ...this.eventForVisit(visit, "composer_focused"),
30958
+ focusMethod
30959
+ });
30960
+ }
30961
+ contentEntered(content) {
30962
+ this.reconcileVisit();
30963
+ const visit = this.visit;
30964
+ if (!visit || visit.pendingContentEntered) return;
30965
+ visit.pendingContentEntered = content;
30966
+ if (!visit.exposed) return;
30967
+ this.report({
30968
+ ...this.eventForVisit(visit, "composer_content_entered"),
30969
+ ...content
30970
+ });
30971
+ }
30972
+ updateDocumentState = () => {
30973
+ this.documentFocused = documentHasFocus();
30974
+ this.documentVisible = documentIsVisible();
30975
+ this.reconcileVisit();
30976
+ };
30977
+ updateIntersection = (entries) => {
30978
+ const entry = entries.find(
30979
+ (candidate) => candidate.target === this.options.element
30980
+ );
30981
+ this.intersectionRatio = entry?.intersectionRatio ?? 0;
30982
+ this.reconcileVisit();
30983
+ };
30984
+ reconcileVisit() {
30985
+ if (!this.isExposureEligible()) {
30986
+ this.endVisit();
30987
+ return;
30988
+ }
30989
+ if (this.visit) return;
30990
+ const visit = {
30991
+ exposed: false,
30992
+ id: createPanelVisitId(),
30993
+ pendingContentEntered: null,
30994
+ pendingFocusMethod: null,
30995
+ timeoutId: null
30996
+ };
30997
+ this.visit = visit;
30998
+ visit.timeoutId = setTimeout(
30999
+ () => this.exposeVisit(visit),
31000
+ AGENT_GUI_PANEL_EXPOSURE_DWELL_MS
31001
+ );
31002
+ }
31003
+ exposeVisit(visit) {
31004
+ if (this.visit !== visit || !this.isExposureEligible()) return;
31005
+ visit.timeoutId = null;
31006
+ visit.exposed = true;
31007
+ this.report(this.eventForVisit(visit, "panel_exposed"));
31008
+ if (visit.pendingFocusMethod) {
31009
+ this.report({
31010
+ ...this.eventForVisit(visit, "composer_focused"),
31011
+ focusMethod: visit.pendingFocusMethod
31012
+ });
31013
+ }
31014
+ if (visit.pendingContentEntered) {
31015
+ this.report({
31016
+ ...this.eventForVisit(visit, "composer_content_entered"),
31017
+ ...visit.pendingContentEntered
31018
+ });
31019
+ }
31020
+ }
31021
+ endVisit() {
31022
+ if (this.visit?.timeoutId !== null && this.visit?.timeoutId !== void 0) {
31023
+ clearTimeout(this.visit.timeoutId);
31024
+ }
31025
+ this.visit = null;
31026
+ }
31027
+ isExposureEligible() {
31028
+ const input = this.options.getInput();
31029
+ 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;
31030
+ }
31031
+ eventForVisit(visit, type) {
31032
+ return {
31033
+ ...this.options.getInput().context,
31034
+ panelVisitId: visit.id,
31035
+ type
31036
+ };
31037
+ }
31038
+ report(event) {
31039
+ const sink = this.options.getInput().onEvent;
31040
+ if (!sink) return;
31041
+ try {
31042
+ void Promise.resolve(sink(event)).catch(reportEngagementFailure);
31043
+ } catch (error) {
31044
+ reportEngagementFailure(error);
31045
+ }
31046
+ }
31047
+ };
31048
+ function reportEngagementFailure(error) {
31049
+ console.warn("[agent-gui] engagement event reporting failed", error);
31050
+ }
31051
+ function createPanelVisitId() {
31052
+ return globalThis.crypto?.randomUUID?.() ?? `agent-gui-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
31053
+ }
31054
+ function documentHasFocus() {
31055
+ return typeof document !== "undefined" && document.hasFocus();
31056
+ }
31057
+ function documentIsVisible() {
31058
+ return typeof document !== "undefined" && document.visibilityState === "visible";
31059
+ }
31060
+
31061
+ // agent-gui/agentGuiNode/engagement/useAgentGUIPanelEngagement.ts
31062
+ function useAgentGUIPanelEngagement(input) {
31063
+ const inputRef = useRef39(input);
31064
+ const controllerRef = useRef39(null);
31065
+ const intersectionRatioRef = useRef39(0);
31066
+ const engagementRef = useRef39(null);
31067
+ inputRef.current = input;
31068
+ if (!engagementRef.current) {
31069
+ engagementRef.current = {
31070
+ contentEntered(content) {
31071
+ controllerRef.current?.contentEntered(content);
31072
+ },
31073
+ focused(focusMethod) {
31074
+ controllerRef.current?.focused(focusMethod);
31075
+ }
31076
+ };
31077
+ }
31078
+ const engagementEnabled = Boolean(input.onEvent) && !input.previewMode;
31079
+ useEffect36(() => {
31080
+ const element = input.elementRef.current;
31081
+ if (!engagementEnabled || !element) return void 0;
31082
+ const controller = new AgentGUIPanelEngagementController({
31083
+ element,
31084
+ getInput: () => inputRef.current,
31085
+ initialIntersectionRatio: intersectionRatioRef.current,
31086
+ visitContextKey: input.contextKey
31087
+ });
31088
+ controllerRef.current = controller;
31089
+ controller.attach();
31090
+ return () => {
31091
+ intersectionRatioRef.current = controller.dispose();
31092
+ if (controllerRef.current === controller) controllerRef.current = null;
31093
+ };
31094
+ }, [
31095
+ engagementEnabled,
31096
+ input.contextKey,
31097
+ input.elementRef,
31098
+ input.isActive,
31099
+ input.isVisible
31100
+ ]);
31101
+ return engagementEnabled ? engagementRef.current : void 0;
31102
+ }
31103
+
31104
+ // agent-gui/agentGuiNode/engagement/useAgentGUINodeEngagement.ts
31105
+ function useAgentGUINodeEngagement(input) {
31106
+ const layoutElementRef = useRef40(null);
31107
+ const projected = projectAgentGUIEngagementContext(
31108
+ input.viewModel,
31109
+ input.composerReady
31110
+ );
31111
+ return {
31112
+ composerEngagement: useAgentGUIPanelEngagement({
31113
+ ...projected,
31114
+ elementRef: layoutElementRef,
31115
+ isActive: input.isActive,
31116
+ isVisible: input.isVisible,
31117
+ onEvent: input.onEvent,
31118
+ previewMode: input.previewMode
31119
+ }),
31120
+ layoutElementRef
31121
+ };
31122
+ }
31123
+
30406
31124
  // agent-gui/agentGuiNode/AgentGUINodeView.tsx
30407
31125
  import { jsx as jsx58, jsxs as jsxs43 } from "react/jsx-runtime";
30408
- var EMPTY_WORKSPACE_APP_ICONS5 = [];
30409
31126
  function AgentGUINodeView({
30410
31127
  viewModel,
30411
31128
  renderSidebarFooter,
@@ -30417,6 +31134,8 @@ function AgentGUINodeView({
30417
31134
  capabilityMenuState,
30418
31135
  onCapabilitySettingsRequest,
30419
31136
  isActive = true,
31137
+ isVisible = true,
31138
+ onEngagementEvent,
30420
31139
  composerFocusRequestSequence = null,
30421
31140
  newConversationRequestSequence = null,
30422
31141
  isAgentProviderReady,
@@ -30458,12 +31177,19 @@ function AgentGUINodeView({
30458
31177
  resolveWorkspaceReferenceEntryIconUrl,
30459
31178
  resolveMentionReferenceTarget = null,
30460
31179
  resolveWorkspaceReferenceInitialTarget = null,
30461
- workspaceAppIcons = EMPTY_WORKSPACE_APP_ICONS5
31180
+ workspaceAppIcons = EMPTY_WORKSPACE_APP_ICONS4
30462
31181
  }) {
30463
31182
  "use memo";
30464
- const layoutElementRef = useRef39(null);
31183
+ const { composerEngagement, layoutElementRef } = useAgentGUINodeEngagement({
31184
+ composerReady: isAgentProviderReady,
31185
+ isActive,
31186
+ isVisible,
31187
+ onEvent: onEngagementEvent,
31188
+ previewMode,
31189
+ viewModel
31190
+ });
30465
31191
  const [providerManagerOpen, setProviderManagerOpen] = useState34(false);
30466
- const railResizeInteractionRef = useRef39(null);
31192
+ const railResizeInteractionRef = useRef41(null);
30467
31193
  const [isRailResizing, setIsRailResizing] = useState34(false);
30468
31194
  const [railResizeWidthPx, setRailResizeWidthPx] = useState34(
30469
31195
  null
@@ -30472,7 +31198,7 @@ function AgentGUINodeView({
30472
31198
  localComposerFocusRequestSequence,
30473
31199
  setLocalComposerFocusRequestSequence
30474
31200
  ] = useState34(0);
30475
- const handledNewConversationRequestSequenceRef = useRef39(
31201
+ const handledNewConversationRequestSequenceRef = useRef41(
30476
31202
  newConversationRequestSequence
30477
31203
  );
30478
31204
  const {
@@ -30550,7 +31276,7 @@ function AgentGUINodeView({
30550
31276
  viewModel.composer.composerSettings.selectedProjectPath
30551
31277
  ]
30552
31278
  );
30553
- useEffect36(() => {
31279
+ useEffect37(() => {
30554
31280
  if (newConversationRequestSequence === null || handledNewConversationRequestSequenceRef.current === newConversationRequestSequence) {
30555
31281
  return;
30556
31282
  }
@@ -30563,7 +31289,7 @@ function AgentGUINodeView({
30563
31289
  newConversationRequestSequence,
30564
31290
  requestCreateConversation
30565
31291
  ]);
30566
- const effectiveWorkspaceAppIcons = useMemo36(
31292
+ const effectiveWorkspaceAppIcons = useMemo37(
30567
31293
  () => mergeWorkspaceAppIconsFromCommands({
30568
31294
  commands: viewModel.composer.availableCommands,
30569
31295
  workspaceAppIcons,
@@ -30644,7 +31370,7 @@ function AgentGUINodeView({
30644
31370
  },
30645
31371
  [onConversationRailWidthChanged]
30646
31372
  );
30647
- useEffect36(() => {
31373
+ useEffect37(() => {
30648
31374
  if (isRailResizing || railResizeWidthPx === null) {
30649
31375
  return;
30650
31376
  }
@@ -30701,7 +31427,7 @@ function AgentGUINodeView({
30701
31427
  const environmentSetupVisible = !!resolveAgentGUIProviderCatalogIdentity(
30702
31428
  effectiveRailConfigProvider ?? ""
30703
31429
  );
30704
- const effectiveProviderAuthAccountLabel = useMemo36(() => {
31430
+ const effectiveProviderAuthAccountLabel = useMemo37(() => {
30705
31431
  const provider = (effectiveRailConfigProvider ?? viewModel.shell.data.provider)?.trim() ?? "";
30706
31432
  if (!provider) {
30707
31433
  return null;
@@ -30732,7 +31458,7 @@ function AgentGUINodeView({
30732
31458
  },
30733
31459
  []
30734
31460
  );
30735
- const conversationRailStoreState = useMemo36(
31461
+ const conversationRailStoreState = useMemo37(
30736
31462
  () => ({
30737
31463
  activeConversation: viewModel.rail.activeConversation,
30738
31464
  activeConversationId: viewModel.rail.activeConversationId,
@@ -30801,7 +31527,7 @@ function AgentGUINodeView({
30801
31527
  workspaceUserProjectI18n
30802
31528
  ]
30803
31529
  );
30804
- const agentTargetPresentations = useMemo36(
31530
+ const agentTargetPresentations = useMemo37(
30805
31531
  () => viewModel.rail.agentTargets.flatMap(
30806
31532
  (target) => target.agentTargetId ? [
30807
31533
  {
@@ -30971,6 +31697,7 @@ function AgentGUINodeView({
30971
31697
  AgentGUIDetailPane,
30972
31698
  {
30973
31699
  viewModel,
31700
+ composerEngagement,
30974
31701
  actions,
30975
31702
  labels,
30976
31703
  uiLanguage,
@@ -31223,9 +31950,9 @@ function appendDockProbeUsageLines(probe, lines, isLoadingUsage, t) {
31223
31950
  import { Info as Info3 } from "lucide-react";
31224
31951
  import {
31225
31952
  useCallback as useCallback49,
31226
- useEffect as useEffect37,
31953
+ useEffect as useEffect38,
31227
31954
  useLayoutEffect as useLayoutEffect8,
31228
- useRef as useRef40,
31955
+ useRef as useRef42,
31229
31956
  useState as useState35
31230
31957
  } from "react";
31231
31958
  import { createPortal as createPortal5 } from "react-dom";
@@ -31263,8 +31990,8 @@ function AgentProbeInfoPopover({
31263
31990
  onOpen
31264
31991
  }) {
31265
31992
  "use memo";
31266
- const anchorRef = useRef40(null);
31267
- const popoverRef = useRef40(null);
31993
+ const anchorRef = useRef42(null);
31994
+ const popoverRef = useRef42(null);
31268
31995
  const [isOpen, setIsOpen] = useState35(false);
31269
31996
  const [popoverStyle, setPopoverStyle] = useState35(null);
31270
31997
  const openPopover = useCallback49(() => {
@@ -31306,7 +32033,7 @@ function AgentProbeInfoPopover({
31306
32033
  maxWidth: availableWidth
31307
32034
  });
31308
32035
  }, []);
31309
- useEffect37(() => {
32036
+ useEffect38(() => {
31310
32037
  if (!isOpen) {
31311
32038
  return;
31312
32039
  }
@@ -31592,11 +32319,11 @@ function areAgentGUINodePropsEqual(previous, next) {
31592
32319
  const pc = previous.hostCapabilities, nc = next.hostCapabilities;
31593
32320
  const pa = previous.hostActions, na = next.hostActions;
31594
32321
  const ps = previous.renderSlots, ns = next.renderSlots;
31595
- return pi.nodeId === ni.nodeId && pi.workspaceId === ni.workspaceId && pi.currentUserId === ni.currentUserId && pi.title === ni.title && pw.path === nw.path && pw.fileReferenceAdapter === nw.fileReferenceAdapter && pw.onRequestGitBranches === nw.onRequestGitBranches && pw.selectProjectDirectory === nw.selectProjectDirectory && pw.resolveDroppedFileReferences === nw.resolveDroppedFileReferences && pw.referenceSourceAggregator === nw.referenceSourceAggregator && pw.resolveReferenceEntryIconUrl === nw.resolveReferenceEntryIconUrl && pw.resolveMentionReferenceTarget === nw.resolveMentionReferenceTarget && pw.resolveReferenceInitialTarget === nw.resolveReferenceInitialTarget && pw.onFileReferencesAdded === nw.onFileReferencesAdded && pw.agentSettings.avoidGroupingEdits === nw.agentSettings.avoidGroupingEdits && agentGuiStateEquals(previous.state, next.state) && pf.position.x === nf.position.x && pf.position.y === nf.position.y && pf.width === nf.width && pf.height === nf.height && pf.desktopSize.width === nf.desktopSize.width && pf.desktopSize.height === nf.desktopSize.height && pf.isMaximized === nf.isMaximized && pf.isActive === nf.isActive && pf.embedded === nf.embedded && pf.previewMode === nf.previewMode && pf.conversationRailAutoCollapseWidthPx === nf.conversationRailAutoCollapseWidthPx && pr.composerFocusSequence === nr.composerFocusSequence && pr.newConversationSequence === nr.newConversationSequence && pr.openSession === nr.openSession && pr.prefillPrompt === nr.prefillPrompt && pr.agentProbes === nr.agentProbes && pr.onProbeDemandChange === nr.onProbeDemandChange && pr.onProbeRefreshRequest === nr.onProbeRefreshRequest && pc.capabilityMenuState === nc.capabilityMenuState && pc.accountMenuState === nc.accountMenuState && pc.agentTargets === nc.agentTargets && pc.agentTargetsLoading === nc.agentTargetsLoading && pc.providerRailAllPresentation?.iconUrl === nc.providerRailAllPresentation?.iconUrl && pc.providerRailMode === nc.providerRailMode && pc.comingSoonProviders === nc.comingSoonProviders && pc.providerReadinessGates === nc.providerReadinessGates && pc.defaultAgentTargetId === nc.defaultAgentTargetId && pc.providerAuthAccountLabels === nc.providerAuthAccountLabels && pc.managedAgentsState === nc.managedAgentsState && pc.contextMentionProviders === nc.contextMentionProviders && pc.workspaceAppIcons === nc.workspaceAppIcons && pc.disabledHomeSuggestions === nc.disabledHomeSuggestions && pa.onLinkAction === na.onLinkAction && pa.onHandoffConversation === na.onHandoffConversation && pa.onCapabilitySettingsRequest === na.onCapabilitySettingsRequest && pa.onAgentProviderLogin === na.onAgentProviderLogin && pa.onOpenConversationWindow === na.onOpenConversationWindow && pa.onClose === na.onClose && pa.onResize === na.onResize && pa.onUpdateNode === na.onUpdateNode && pa.onRememberComposerDefaults === na.onRememberComposerDefaults && pa.isMuted === na.isMuted && pa.onMinimize === na.onMinimize && pa.onToggleMaximize === na.onToggleMaximize && pa.onShowMessage === na.onShowMessage && ps.providerRailEmpty === ns.providerRailEmpty && ps.providerUnavailableState === ns.providerUnavailableState && ps.sidebarFooter === ns.sidebarFooter;
32322
+ return pi.nodeId === ni.nodeId && pi.workspaceId === ni.workspaceId && pi.currentUserId === ni.currentUserId && pi.title === ni.title && pw.path === nw.path && pw.fileReferenceAdapter === nw.fileReferenceAdapter && pw.onRequestGitBranches === nw.onRequestGitBranches && pw.selectProjectDirectory === nw.selectProjectDirectory && pw.resolveDroppedFileReferences === nw.resolveDroppedFileReferences && pw.referenceSourceAggregator === nw.referenceSourceAggregator && pw.resolveReferenceEntryIconUrl === nw.resolveReferenceEntryIconUrl && pw.resolveMentionReferenceTarget === nw.resolveMentionReferenceTarget && pw.resolveReferenceInitialTarget === nw.resolveReferenceInitialTarget && pw.onFileReferencesAdded === nw.onFileReferencesAdded && pw.agentSettings.avoidGroupingEdits === nw.agentSettings.avoidGroupingEdits && agentGuiStateEquals(previous.state, next.state) && pf.position.x === nf.position.x && pf.position.y === nf.position.y && pf.width === nf.width && pf.height === nf.height && pf.desktopSize.width === nf.desktopSize.width && pf.desktopSize.height === nf.desktopSize.height && pf.isMaximized === nf.isMaximized && pf.isActive === nf.isActive && pf.isVisible === nf.isVisible && pf.embedded === nf.embedded && pf.previewMode === nf.previewMode && pf.conversationRailAutoCollapseWidthPx === nf.conversationRailAutoCollapseWidthPx && pr.composerFocusSequence === nr.composerFocusSequence && pr.newConversationSequence === nr.newConversationSequence && pr.openSession === nr.openSession && pr.prefillPrompt === nr.prefillPrompt && pr.agentProbes === nr.agentProbes && pr.onProbeDemandChange === nr.onProbeDemandChange && pr.onProbeRefreshRequest === nr.onProbeRefreshRequest && pc.capabilityMenuState === nc.capabilityMenuState && pc.accountMenuState === nc.accountMenuState && pc.agentTargets === nc.agentTargets && pc.agentTargetsLoading === nc.agentTargetsLoading && pc.providerRailAllPresentation?.iconUrl === nc.providerRailAllPresentation?.iconUrl && pc.providerRailMode === nc.providerRailMode && pc.comingSoonProviders === nc.comingSoonProviders && pc.providerReadinessGates === nc.providerReadinessGates && pc.defaultAgentTargetId === nc.defaultAgentTargetId && pc.providerAuthAccountLabels === nc.providerAuthAccountLabels && pc.managedAgentsState === nc.managedAgentsState && pc.contextMentionProviders === nc.contextMentionProviders && pc.workspaceAppIcons === nc.workspaceAppIcons && pc.disabledHomeSuggestions === nc.disabledHomeSuggestions && pa.onLinkAction === na.onLinkAction && pa.onHandoffConversation === na.onHandoffConversation && pa.onCapabilitySettingsRequest === na.onCapabilitySettingsRequest && pa.onAgentProviderLogin === na.onAgentProviderLogin && pa.onOpenConversationWindow === na.onOpenConversationWindow && pa.onClose === na.onClose && pa.onResize === na.onResize && pa.onUpdateNode === na.onUpdateNode && pa.onRememberComposerDefaults === na.onRememberComposerDefaults && pa.isMuted === na.isMuted && pa.onMinimize === na.onMinimize && pa.onToggleMaximize === na.onToggleMaximize && pa.onShowMessage === na.onShowMessage && pa.onEngagementEvent === na.onEngagementEvent && ps.providerRailEmpty === ns.providerRailEmpty && ps.providerUnavailableState === ns.providerUnavailableState && ps.sidebarFooter === ns.sidebarFooter;
31596
32323
  }
31597
32324
 
31598
32325
  // agent-gui/agentGuiNode/AgentGUINode.labels.ts
31599
- import { useMemo as useMemo37 } from "react";
32326
+ import { useMemo as useMemo38 } from "react";
31600
32327
 
31601
32328
  // agent-gui/agentGuiNode/model/agentHomeSuggestions.ts
31602
32329
  import { createRichTextMentionHref as createRichTextMentionHref2 } from "@tutti-os/ui-rich-text/core";
@@ -31743,7 +32470,7 @@ function useAgentGUIViewLabels(input) {
31743
32470
  workspaceAppIcons,
31744
32471
  workspaceId
31745
32472
  } = input;
31746
- return useMemo37(
32473
+ return useMemo38(
31747
32474
  () => ({
31748
32475
  initialPlaceholder: t("agentHost.agentGui.initialPlaceholder", {
31749
32476
  provider: displayProviderLabel
@@ -32338,7 +33065,7 @@ function useAgentGUIViewLabels(input) {
32338
33065
  );
32339
33066
  }
32340
33067
  function useAgentGUIWorkspaceFileReferenceCopy(t) {
32341
- return useMemo37(
33068
+ return useMemo38(
32342
33069
  () => ({
32343
33070
  t(key, values) {
32344
33071
  const localeKey = workspaceFileReferenceLocaleKeyByPickerKey[key];
@@ -32409,69 +33136,6 @@ function slashStatusLimitsFromQuotas(quotas, selectedModel, t) {
32409
33136
  };
32410
33137
  }).filter((limit) => limit !== null);
32411
33138
  }
32412
- function slashStatusQuotasFromCanonicalUsage(usage) {
32413
- if (!usage) {
32414
- return [];
32415
- }
32416
- return usage.quotas.map((quota) => {
32417
- const record = objectRecord2(quota);
32418
- const quotaType = agentUsageQuotaTypeValue(record?.quotaType);
32419
- if (!record || !quotaType) {
32420
- return null;
32421
- }
32422
- const normalized = { quotaType };
32423
- const percentRemaining = numberValue2(record.percentRemaining);
32424
- if (percentRemaining !== null) {
32425
- normalized.percentRemaining = percentRemaining;
32426
- }
32427
- const resetsAtUnixMs = numberValue2(record.resetsAtUnixMs);
32428
- if (resetsAtUnixMs !== null) {
32429
- normalized.resetsAtUnixMs = resetsAtUnixMs;
32430
- }
32431
- const resetText = stringValue3(record.resetText);
32432
- if (resetText) {
32433
- normalized.resetText = resetText;
32434
- }
32435
- const dollarRemaining = numberValue2(record.dollarRemaining);
32436
- if (dollarRemaining !== null) {
32437
- normalized.dollarRemaining = dollarRemaining;
32438
- }
32439
- const modelName = stringValue3(record.modelName);
32440
- if (modelName) {
32441
- normalized.modelName = modelName;
32442
- }
32443
- return normalized;
32444
- }).filter((quota) => quota !== null);
32445
- }
32446
- function agentUsageQuotaTypeValue(value) {
32447
- switch (stringValue3(value)) {
32448
- case "session":
32449
- case "weekly":
32450
- case "monthly":
32451
- case "daily":
32452
- case "model":
32453
- case "cost":
32454
- return stringValue3(value);
32455
- default:
32456
- return null;
32457
- }
32458
- }
32459
- function objectRecord2(value) {
32460
- return value && typeof value === "object" ? value : null;
32461
- }
32462
- function numberValue2(value) {
32463
- if (typeof value === "number" && Number.isFinite(value)) {
32464
- return value;
32465
- }
32466
- if (typeof value === "string" && value.trim()) {
32467
- const parsed = Number(value);
32468
- return Number.isFinite(parsed) ? parsed : null;
32469
- }
32470
- return null;
32471
- }
32472
- function stringValue3(value) {
32473
- return typeof value === "string" ? value.trim() : "";
32474
- }
32475
33139
  function filterSlashStatusQuotasForModel(quotas, selectedModel) {
32476
33140
  const normalizedSelectedModel = normalizeSlashStatusModelName(selectedModel);
32477
33141
  const baseQuotas = (quotas ?? []).filter(
@@ -32499,6 +33163,7 @@ function resolveAgentGUIRailStatusProvider(input) {
32499
33163
 
32500
33164
  // agent-gui/agentGuiNode/AgentGUINode.tsx
32501
33165
  import { jsx as jsx60, jsxs as jsxs45 } from "react/jsx-runtime";
33166
+ var EMPTY_SLASH_STATUS_QUOTAS = [];
32502
33167
  var AgentGUINode = memo14(function AgentGUINode2({
32503
33168
  identity,
32504
33169
  workspace,
@@ -32531,6 +33196,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32531
33196
  desktopSize,
32532
33197
  isMaximized = false,
32533
33198
  isActive,
33199
+ isVisible = true,
32534
33200
  embedded = false,
32535
33201
  previewMode = false,
32536
33202
  conversationRailAutoCollapseWidthPx = null
@@ -32574,7 +33240,8 @@ var AgentGUINode = memo14(function AgentGUINode2({
32574
33240
  isMuted = false,
32575
33241
  onMinimize,
32576
33242
  onToggleMaximize,
32577
- onShowMessage
33243
+ onShowMessage,
33244
+ onEngagementEvent
32578
33245
  } = hostActions;
32579
33246
  const {
32580
33247
  providerRailEmpty: renderProviderRailEmpty,
@@ -32582,22 +33249,19 @@ var AgentGUINode = memo14(function AgentGUINode2({
32582
33249
  sidebarFooter: renderSidebarFooter
32583
33250
  } = renderSlots;
32584
33251
  const { i18n, locale, t } = useTranslation();
32585
- const workspaceUserProjectI18n = useMemo38(
33252
+ const workspaceUserProjectI18n = useMemo39(
32586
33253
  () => createWorkspaceUserProjectI18nRuntime(i18n),
32587
33254
  [i18n]
32588
33255
  );
32589
- const workspaceFileManagerI18n = useMemo38(
33256
+ const workspaceFileManagerI18n = useMemo39(
32590
33257
  () => typeof i18n?.t === "function" ? createWorkspaceFileManagerI18nRuntime(i18n) : null,
32591
33258
  [i18n]
32592
33259
  );
32593
33260
  const handleLinkAction = useCallback50(
32594
33261
  (action) => {
32595
- const agentTargetId = state.agentTargetId?.trim() || null;
32596
- onLinkAction?.(
32597
- action.type === "open-agent-session" && !action.agentTargetId && agentTargetId ? { ...action, agentTargetId } : action
32598
- );
33262
+ onLinkAction?.(action);
32599
33263
  },
32600
- [onLinkAction, state.agentTargetId]
33264
+ [onLinkAction]
32601
33265
  );
32602
33266
  const handleAgentProviderLogin = useCallback50(
32603
33267
  (provider) => {
@@ -32651,7 +33315,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32651
33315
  const isConversationRailManuallyCollapsed = state.conversationRailCollapsed === true;
32652
33316
  const isConversationRailAutoCollapsed = shouldAutoCollapseAgentGUIConversationRail(width, railAutoCollapseWidthPx);
32653
33317
  const isConversationRailCollapsed = isConversationRailManuallyCollapsed || isConversationRailAutoCollapsed;
32654
- const minSize = useMemo38(
33318
+ const minSize = useMemo39(
32655
33319
  () => ({
32656
33320
  ...resolveCanonicalNodeMinSize("agentGui"),
32657
33321
  width: AGENT_GUI_COLLAPSED_MIN_WIDTH_PX
@@ -32739,7 +33403,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32739
33403
  },
32740
33404
  [actions, onUpdateNode, previewMode]
32741
33405
  );
32742
- const viewActions = useMemo38(
33406
+ const viewActions = useMemo39(
32743
33407
  () => ({
32744
33408
  ...actions,
32745
33409
  createConversation: handleCreateConversation
@@ -32762,28 +33426,28 @@ var AgentGUINode = memo14(function AgentGUINode2({
32762
33426
  const workspaceFileReferenceCopy = useAgentGUIWorkspaceFileReferenceCopy(t);
32763
33427
  const windowTitle = title;
32764
33428
  const activeProbeProvider = activeProvider;
32765
- const railStatusProvider = useMemo38(
33429
+ const railStatusProvider = useMemo39(
32766
33430
  () => resolveAgentGUIRailStatusProvider({
32767
33431
  conversationFilter: viewModel.rail.conversationFilter,
32768
33432
  agentTargets: viewModel.rail.agentTargets
32769
33433
  }),
32770
33434
  [viewModel.rail.conversationFilter, viewModel.rail.agentTargets]
32771
33435
  );
32772
- const activeAgentProbe = useMemo38(
33436
+ const activeAgentProbe = useMemo39(
32773
33437
  () => findWorkspaceAgentProbeForDockProvider(
32774
33438
  workspaceAgentProbes?.snapshot ?? null,
32775
33439
  activeProbeProvider
32776
33440
  ),
32777
33441
  [activeProbeProvider, workspaceAgentProbes?.snapshot]
32778
33442
  );
32779
- const railAgentProbe = useMemo38(
33443
+ const railAgentProbe = useMemo39(
32780
33444
  () => railStatusProvider ? findWorkspaceAgentProbeForDockProvider(
32781
33445
  workspaceAgentProbes?.snapshot ?? null,
32782
33446
  railStatusProvider
32783
33447
  ) : null,
32784
33448
  [railStatusProvider, workspaceAgentProbes?.snapshot]
32785
33449
  );
32786
- const isActiveAgentProviderReady = useMemo38(() => {
33450
+ const isActiveAgentProviderReady = useMemo39(() => {
32787
33451
  const managedAgent = getAgentHostManagedToolchainAgentByName(
32788
33452
  activeReadinessProvider
32789
33453
  );
@@ -32798,11 +33462,9 @@ var AgentGUINode = memo14(function AgentGUINode2({
32798
33462
  managedAgentsState
32799
33463
  ) === "installed";
32800
33464
  }, [activeReadinessProvider, managedAgentsState]);
32801
- const canonicalSlashStatusQuotas = slashStatusQuotasFromCanonicalUsage(
32802
- viewModel.detail.usage
32803
- );
32804
- const slashStatusQuotaSource = canonicalSlashStatusQuotas.length > 0 ? canonicalSlashStatusQuotas : activeAgentProbe?.usage?.quotas && activeAgentProbe.usage.quotas.length > 0 ? activeAgentProbe.usage.quotas : [];
32805
- const slashStatusLimits = useMemo38(
33465
+ const canonicalSlashStatusQuotas = viewModel.detail.usage?.quotas ?? EMPTY_SLASH_STATUS_QUOTAS;
33466
+ const slashStatusQuotaSource = canonicalSlashStatusQuotas.length > 0 ? canonicalSlashStatusQuotas : activeAgentProbe?.usage?.quotas && activeAgentProbe.usage.quotas.length > 0 ? activeAgentProbe.usage.quotas : EMPTY_SLASH_STATUS_QUOTAS;
33467
+ const slashStatusLimits = useMemo39(
32806
33468
  () => slashStatusLimitsFromQuotas(
32807
33469
  slashStatusQuotaSource,
32808
33470
  viewModel.composer.composerSettings.selectedModelValue ?? viewModel.composer.composerSettings.draftSettings.model,
@@ -32816,8 +33478,8 @@ var AgentGUINode = memo14(function AgentGUINode2({
32816
33478
  ]
32817
33479
  );
32818
33480
  const slashStatusLimitsUnavailable = slashStatusLimits.length === 0 && canonicalSlashStatusQuotas.length === 0 && !(workspaceAgentProbes?.isLoadingUsage ?? false) && (Boolean(activeAgentProbe?.usage) || Boolean(activeAgentProbe?.lastError));
32819
- const railSlashStatusQuotaSource = railStatusProvider && railAgentProbe?.usage?.quotas && railAgentProbe.usage.quotas.length > 0 ? railAgentProbe.usage.quotas : [];
32820
- const railSlashStatusLimits = useMemo38(
33481
+ const railSlashStatusQuotaSource = railStatusProvider && railAgentProbe?.usage?.quotas && railAgentProbe.usage.quotas.length > 0 ? railAgentProbe.usage.quotas : EMPTY_SLASH_STATUS_QUOTAS;
33482
+ const railSlashStatusLimits = useMemo39(
32821
33483
  () => slashStatusLimitsFromQuotas(railSlashStatusQuotaSource, null, t),
32822
33484
  [railSlashStatusQuotaSource, t]
32823
33485
  );
@@ -32825,7 +33487,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32825
33487
  const slashStatusUsageCapturedAtUnixMs = slashStatusUsageProbe?.usage?.capturedAtUnixMs ?? null;
32826
33488
  const slashStatusUsageDidFail = workspaceAgentProbes?.usageLoadFailed ?? false;
32827
33489
  const slashStatusUsageAttempted = Boolean(slashStatusUsageProbe?.usage) || Boolean(slashStatusUsageProbe?.lastError);
32828
- const agentProbeLines = useMemo38(() => {
33490
+ const agentProbeLines = useMemo39(() => {
32829
33491
  return buildDockAgentProbeTooltipLines(
32830
33492
  activeAgentProbe,
32831
33493
  workspaceAgentProbes?.isLoadingAvailability ?? false,
@@ -32841,7 +33503,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32841
33503
  workspaceAgentProbes?.isLoadingUsage,
32842
33504
  t
32843
33505
  ]);
32844
- useEffect38(() => {
33506
+ useEffect39(() => {
32845
33507
  if (previewMode || !onAgentProbeDemandChange) {
32846
33508
  return;
32847
33509
  }
@@ -32851,7 +33513,7 @@ var AgentGUINode = memo14(function AgentGUINode2({
32851
33513
  onAgentProbeDemandChange(null, probeSourceId);
32852
33514
  };
32853
33515
  }, [activeProbeProvider, nodeId, onAgentProbeDemandChange, previewMode]);
32854
- useEffect38(() => {
33516
+ useEffect39(() => {
32855
33517
  if (previewMode || !onAgentProbeDemandChange || !railStatusProvider || railStatusProvider === activeProbeProvider) {
32856
33518
  return;
32857
33519
  }
@@ -32975,6 +33637,8 @@ var AgentGUINode = memo14(function AgentGUINode2({
32975
33637
  providerRailAllPresentation,
32976
33638
  actions: viewActions,
32977
33639
  isActive,
33640
+ isVisible,
33641
+ onEngagementEvent,
32978
33642
  composerFocusRequestSequence,
32979
33643
  newConversationRequestSequence,
32980
33644
  isAgentProviderReady: isActiveAgentProviderReady,
@@ -33084,4 +33748,4 @@ export {
33084
33748
  resolveAgentGUIAgentTarget,
33085
33749
  AgentGUI
33086
33750
  };
33087
- //# sourceMappingURL=chunk-BIS4QRX7.js.map
33751
+ //# sourceMappingURL=chunk-PLCHNOXL.js.map