@tutti-os/agent-gui 0.0.3 → 0.0.5

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 (62) hide show
  1. package/dist/agent-message-center/index.js +3 -2
  2. package/dist/agent-message-center/index.js.map +1 -1
  3. package/dist/app/renderer/agentactivity.css +7 -0
  4. package/dist/app/renderer/assets/icons/arrow-left-filled.svg +1 -0
  5. package/dist/{chunk-RORLLV27.js → chunk-3735XYFZ.js} +2 -40
  6. package/dist/chunk-3735XYFZ.js.map +1 -0
  7. package/dist/{chunk-IVPB4MLI.js → chunk-6AZ2KF6R.js} +1 -1
  8. package/dist/chunk-6AZ2KF6R.js.map +1 -0
  9. package/dist/{chunk-UKQIGNN3.js → chunk-7ICAFTA2.js} +2 -2
  10. package/dist/{chunk-HSR5DI6O.js → chunk-BHCCGKOP.js} +3 -1
  11. package/dist/chunk-BHCCGKOP.js.map +1 -0
  12. package/dist/{chunk-ZX5PDYAS.js → chunk-C63Z2JWT.js} +8 -10
  13. package/dist/chunk-C63Z2JWT.js.map +1 -0
  14. package/dist/chunk-F55LU7IJ.js +3470 -0
  15. package/dist/chunk-F55LU7IJ.js.map +1 -0
  16. package/dist/{chunk-ZP7P7DYO.js → chunk-GEXHKJK5.js} +6 -47
  17. package/dist/chunk-GEXHKJK5.js.map +1 -0
  18. package/dist/{chunk-UJWUGMWC.js → chunk-GYG57VTA.js} +17 -32
  19. package/dist/{chunk-UJWUGMWC.js.map → chunk-GYG57VTA.js.map} +1 -1
  20. package/dist/{chunk-BABBC24I.js → chunk-LUGELG5V.js} +4 -1
  21. package/dist/chunk-LUGELG5V.js.map +1 -0
  22. package/dist/chunk-ZU3FKYMG.js +47 -0
  23. package/dist/chunk-ZU3FKYMG.js.map +1 -0
  24. package/dist/i18n/index.d.ts +2 -0
  25. package/dist/i18n/index.js +1 -1
  26. package/dist/index.d.ts +2 -11
  27. package/dist/index.js +880 -215
  28. package/dist/index.js.map +1 -1
  29. package/dist/mention-file-presentation.d.ts +2 -1
  30. package/dist/mention-file-presentation.js +1 -1
  31. package/dist/workbench/contribution.js +6 -5
  32. package/dist/workbench/index.d.ts +1 -1
  33. package/dist/workbench/index.js +6 -5
  34. package/dist/workbench/launch.d.ts +1 -7
  35. package/dist/workbench/launch.js +2 -2
  36. package/dist/workbench/state.js +1 -1
  37. package/dist/workbench/types.d.ts +1 -12
  38. package/dist/workbench/types.js +1 -1
  39. package/dist/workspace-agent-generated-files.js +2 -2
  40. package/package.json +11 -10
  41. package/dist/chunk-AF5CXBJN.js +0 -3075
  42. package/dist/chunk-AF5CXBJN.js.map +0 -1
  43. package/dist/chunk-BABBC24I.js.map +0 -1
  44. package/dist/chunk-HSR5DI6O.js.map +0 -1
  45. package/dist/chunk-IVPB4MLI.js.map +0 -1
  46. package/dist/chunk-RORLLV27.js.map +0 -1
  47. package/dist/chunk-ZP7P7DYO.js.map +0 -1
  48. package/dist/chunk-ZX5PDYAS.js.map +0 -1
  49. package/dist/claude-rounded-F6VPQETB.png +0 -0
  50. package/dist/codex-rounded-SC63MZAW.png +0 -0
  51. package/dist/gemini-rounded-O4KAJFIM.png +0 -0
  52. package/dist/hermes-rounded-QGDHBNRJ.png +0 -0
  53. package/dist/manage-agent-claude-code-F6VPQETB.png +0 -0
  54. package/dist/manage-agent-codex-SC63MZAW.png +0 -0
  55. package/dist/manage-agent-gemini-O4KAJFIM.png +0 -0
  56. package/dist/manage-agent-hermes-QGDHBNRJ.png +0 -0
  57. package/dist/manage-agent-nextop-UFAQ22K2.png +0 -0
  58. package/dist/manage-agent-openclaw-24U7O6CA.png +0 -0
  59. package/dist/nextop-doc-rounded-UFAQ22K2.png +0 -0
  60. package/dist/openclaw-rounded-24U7O6CA.png +0 -0
  61. package/dist/user-avatar-placeholder-WP2373TS.png +0 -0
  62. /package/dist/{chunk-UKQIGNN3.js.map → chunk-7ICAFTA2.js.map} +0 -0
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  mergeWorkspaceAgentActivityDurableAndOverlayMessages,
8
8
  normalizeOptionalWorkspaceAgentStatus,
9
9
  selectWorkspaceAgentActivityOverlayMessages
10
- } from "./chunk-UKQIGNN3.js";
10
+ } from "./chunk-7ICAFTA2.js";
11
11
  import {
12
12
  AgentActivityHostProvider,
13
13
  AgentActivityRuntimeProvider,
@@ -39,7 +39,7 @@ import {
39
39
  useOptionalAgentHostApi,
40
40
  user_avatar_placeholder_default,
41
41
  workspaceAgentActivityStatusLabel
42
- } from "./chunk-AF5CXBJN.js";
42
+ } from "./chunk-F55LU7IJ.js";
43
43
  import {
44
44
  resolveWorkspaceAgentSessionSortTimeUnixMs,
45
45
  workspaceAgentProviderLabel
@@ -57,11 +57,11 @@ import {
57
57
  getActiveUiLanguage,
58
58
  translate,
59
59
  useTranslation
60
- } from "./chunk-HSR5DI6O.js";
60
+ } from "./chunk-BHCCGKOP.js";
61
61
  import {
62
62
  resolveAgentMentionFileThumbnailUrl,
63
63
  resolveAgentMentionFileVisualKind
64
- } from "./chunk-BABBC24I.js";
64
+ } from "./chunk-LUGELG5V.js";
65
65
  import "./chunk-PJP5BUU6.js";
66
66
  import {
67
67
  AGENT_GUI_COLLAPSED_MIN_WIDTH_PX,
@@ -74,7 +74,8 @@ import {
74
74
  resolveAgentGUIExpandedWindowFrame,
75
75
  resolveNextAgentGUIConversationRailWidthPx,
76
76
  shouldAutoCollapseAgentGUIConversationRail
77
- } from "./chunk-UJWUGMWC.js";
77
+ } from "./chunk-GYG57VTA.js";
78
+ import "./chunk-ZU3FKYMG.js";
78
79
 
79
80
  // shared/agentActivitySnapshotProjection.ts
80
81
  import {
@@ -237,7 +238,7 @@ function agentHostTurnPhaseFromCore(status) {
237
238
  import { TooltipProvider as TooltipProvider3 } from "@tutti-os/ui-system";
238
239
 
239
240
  // agent-gui/agentGuiNode/AgentGUINode.tsx
240
- import { memo as memo6, useCallback as useCallback20, useEffect as useEffect23, useMemo as useMemo16, useRef as useRef22 } from "react";
241
+ import { memo as memo6, useCallback as useCallback20, useEffect as useEffect23, useMemo as useMemo16 } from "react";
241
242
  import { createWorkspaceUserProjectI18nRuntime } from "@tutti-os/workspace-user-project/i18n";
242
243
 
243
244
  // shared/errors/appError.ts
@@ -5236,6 +5237,7 @@ function computeAgentToolGroups(sequence, {
5236
5237
  }) {
5237
5238
  const groups = /* @__PURE__ */ new Map();
5238
5239
  const groupedIndices = /* @__PURE__ */ new Set();
5240
+ const suppressedIndices = allowTrailingFinalization ? /* @__PURE__ */ new Set() : findActiveTailSuppressedToolIndices(sequence);
5239
5241
  let currentCalls = [];
5240
5242
  let currentEntries = [];
5241
5243
  let currentIndices = [];
@@ -5265,6 +5267,9 @@ function computeAgentToolGroups(sequence, {
5265
5267
  if (!item) {
5266
5268
  continue;
5267
5269
  }
5270
+ if (suppressedIndices.has(index)) {
5271
+ continue;
5272
+ }
5268
5273
  if (item.kind === "tool-call" && isGroupableToolCall2(item.call)) {
5269
5274
  if (avoidGroupingEdits && isEditBoundaryToolCall(item.call)) {
5270
5275
  finalizeGroup();
@@ -5301,7 +5306,8 @@ function computeAgentToolGroups(sequence, {
5301
5306
  }
5302
5307
  return {
5303
5308
  groups,
5304
- groupedIndices
5309
+ groupedIndices,
5310
+ suppressedIndices
5305
5311
  };
5306
5312
  }
5307
5313
  function projectAgentToolGroupRowFromGroup(turnId, group) {
@@ -5318,12 +5324,12 @@ function projectAgentToolGroupRowFromGroup(turnId, group) {
5318
5324
  occurredAtUnixMs: group.calls.map((call) => call.occurredAtUnixMs ?? 0).reduce((latest, value) => value > latest ? value : latest, 0) || null
5319
5325
  };
5320
5326
  }
5321
- function projectAgentSingleToolRow(call) {
5327
+ function projectAgentSingleToolRow(call, turnId = call.turnId) {
5322
5328
  return {
5323
5329
  kind: "tool-group",
5324
5330
  id: `tool-row:${call.id}`,
5325
- expansionKey: `tool-row:${call.id}`,
5326
- turnId: call.turnId,
5331
+ expansionKey: `tool-group:${turnId}:${call.id}`,
5332
+ turnId,
5327
5333
  grouped: false,
5328
5334
  calls: [call],
5329
5335
  summary: null,
@@ -5337,6 +5343,7 @@ function projectMessage(message, turnId) {
5337
5343
  id: message.id,
5338
5344
  turnId: message.turnId ?? turnId,
5339
5345
  body: message.body,
5346
+ statusKind: message.statusKind ?? null,
5340
5347
  occurredAtUnixMs: message.occurredAtUnixMs ?? null,
5341
5348
  visibleError: message.visibleError ?? null,
5342
5349
  systemNotice: message.systemNotice ?? null
@@ -5375,6 +5382,50 @@ function isGroupableToolCall2(call) {
5375
5382
  return true;
5376
5383
  }
5377
5384
  }
5385
+ function findActiveTailSuppressedToolIndices(sequence) {
5386
+ const suppressedIndices = /* @__PURE__ */ new Set();
5387
+ let latestTailToolIndex = -1;
5388
+ for (let index = sequence.length - 1; index >= 0; index -= 1) {
5389
+ const item = sequence[index];
5390
+ if (!item) {
5391
+ continue;
5392
+ }
5393
+ if (item.kind !== "tool-call") {
5394
+ break;
5395
+ }
5396
+ latestTailToolIndex = Math.max(latestTailToolIndex, index);
5397
+ }
5398
+ if (latestTailToolIndex < 0) {
5399
+ return suppressedIndices;
5400
+ }
5401
+ const latestTailTool = sequence[latestTailToolIndex];
5402
+ if (latestTailTool?.kind !== "tool-call" || !isSuppressingActiveTailTool(latestTailTool.call)) {
5403
+ return suppressedIndices;
5404
+ }
5405
+ for (let index = latestTailToolIndex - 1; index >= 0; index -= 1) {
5406
+ const item = sequence[index];
5407
+ if (!item) {
5408
+ continue;
5409
+ }
5410
+ if (item.kind !== "tool-call") {
5411
+ break;
5412
+ }
5413
+ suppressedIndices.add(index);
5414
+ }
5415
+ return suppressedIndices;
5416
+ }
5417
+ function isSuppressingActiveTailTool(call) {
5418
+ switch (call.rendererKind) {
5419
+ case "approval":
5420
+ case "ask-user":
5421
+ case "plan-enter":
5422
+ case "plan-exit":
5423
+ case "task":
5424
+ return false;
5425
+ default:
5426
+ return true;
5427
+ }
5428
+ }
5378
5429
  function isEditBoundaryToolCall(call) {
5379
5430
  return call.rendererKind === "edit" || call.rendererKind === "write";
5380
5431
  }
@@ -6605,6 +6656,7 @@ function mergeAdjacentAssistantMessageRows(rows) {
6605
6656
  const nextMessage = row.messages[0];
6606
6657
  if (lastMessage && nextMessage) {
6607
6658
  lastMessage.body += nextMessage.body;
6659
+ lastMessage.statusKind = nextMessage.statusKind ?? lastMessage.statusKind ?? null;
6608
6660
  lastMessage.occurredAtUnixMs = nextMessage.occurredAtUnixMs ?? lastMessage.occurredAtUnixMs;
6609
6661
  }
6610
6662
  if (row.messages.length > 1) {
@@ -6777,7 +6829,11 @@ function userPromptContentBlocks(message, fallbackWorkspaceId) {
6777
6829
  }
6778
6830
  function projectTurnAgentRows(turn, options) {
6779
6831
  const sequence = buildAgentTurnSequenceItems(turn);
6780
- const { groups, groupedIndices } = computeAgentToolGroups(sequence, options);
6832
+ const { groups, groupedIndices, suppressedIndices } = computeAgentToolGroups(
6833
+ sequence,
6834
+ options
6835
+ );
6836
+ const skippedIndices = /* @__PURE__ */ new Set([...groupedIndices, ...suppressedIndices]);
6781
6837
  const rows = [];
6782
6838
  let pendingThinking = [];
6783
6839
  const flushThinking = () => {
@@ -6807,13 +6863,13 @@ function projectTurnAgentRows(turn, options) {
6807
6863
  index = group.endIndex;
6808
6864
  continue;
6809
6865
  }
6810
- if (groupedIndices.has(index)) {
6866
+ if (skippedIndices.has(index)) {
6811
6867
  continue;
6812
6868
  }
6813
6869
  if (item.kind === "thinking") {
6814
6870
  const next = nextUngroupedSequenceItem(
6815
6871
  sequence,
6816
- groupedIndices,
6872
+ skippedIndices,
6817
6873
  index + 1
6818
6874
  );
6819
6875
  if (next?.kind === "assistant-message") {
@@ -6838,7 +6894,7 @@ function projectTurnAgentRows(turn, options) {
6838
6894
  continue;
6839
6895
  }
6840
6896
  flushThinking();
6841
- rows.push(projectAgentSingleToolRow(item.call));
6897
+ rows.push(projectAgentSingleToolRow(item.call, turn.id));
6842
6898
  }
6843
6899
  flushThinking();
6844
6900
  return rows;
@@ -7105,6 +7161,8 @@ function isUserTimelineItem(item) {
7105
7161
 
7106
7162
  // agent-gui/agentGuiNode/model/agentGuiConversationModel.ts
7107
7163
  var AGENT_GUI_RUNTIME_SESSION_ORIGIN = WORKSPACE_AGENT_ACTIVITY_RUNTIME_SESSION_ORIGIN;
7164
+ var AGENT_GUI_CONVERSATION_PROJECT_SUMMARY_CACHE_LIMIT = 512;
7165
+ var agentGUIConversationProjectSummaryCache = /* @__PURE__ */ new Map();
7108
7166
  function resolveAgentGUIConversationSortTimeUnixMs(conversation) {
7109
7167
  return conversation.sortTimeUnixMs ?? conversation.updatedAtUnixMs;
7110
7168
  }
@@ -7282,7 +7340,7 @@ function resolveAgentGUIConversationProject(cwd, userProjects = []) {
7282
7340
  if (matchedProject.lastUsedAtUnixMs !== void 0) {
7283
7341
  summary.lastUsedAtUnixMs = matchedProject.lastUsedAtUnixMs;
7284
7342
  }
7285
- return summary;
7343
+ return cachedAgentGUIConversationProjectSummary(summary);
7286
7344
  }
7287
7345
  function applyAgentGUIConversationProjects(conversations, userProjects = []) {
7288
7346
  let changed = false;
@@ -7386,6 +7444,28 @@ function normalizeAgentGUIProjectPath(path) {
7386
7444
  }
7387
7445
  return normalized.replace(/\/+$/, "") || "/";
7388
7446
  }
7447
+ function cachedAgentGUIConversationProjectSummary(summary) {
7448
+ const key = [
7449
+ summary.id,
7450
+ summary.path,
7451
+ summary.label,
7452
+ summary.createdAtUnixMs ?? "",
7453
+ summary.updatedAtUnixMs ?? "",
7454
+ summary.lastUsedAtUnixMs ?? ""
7455
+ ].join("");
7456
+ const cached = agentGUIConversationProjectSummaryCache.get(key);
7457
+ if (cached) {
7458
+ return cached;
7459
+ }
7460
+ if (agentGUIConversationProjectSummaryCache.size >= AGENT_GUI_CONVERSATION_PROJECT_SUMMARY_CACHE_LIMIT) {
7461
+ const oldestKey = agentGUIConversationProjectSummaryCache.keys().next().value;
7462
+ if (oldestKey) {
7463
+ agentGUIConversationProjectSummaryCache.delete(oldestKey);
7464
+ }
7465
+ }
7466
+ agentGUIConversationProjectSummaryCache.set(key, summary);
7467
+ return summary;
7468
+ }
7389
7469
  function isSameAgentGUIConversationProject(left, right) {
7390
7470
  if (!left && !right) {
7391
7471
  return true;
@@ -8387,6 +8467,7 @@ var STREAM_LINGER_MS = 15e3;
8387
8467
  var EMPTY_AGENT_SESSION_VIEW_STORE_SNAPSHOT = {
8388
8468
  sessionViewsBySessionKey: {}
8389
8469
  };
8470
+ var MESSAGE_UPDATE_BATCH_DELAY_MS = 33;
8390
8471
  var snapshot = EMPTY_AGENT_SESSION_VIEW_STORE_SNAPSHOT;
8391
8472
  var storeListeners = /* @__PURE__ */ new Set();
8392
8473
  var ignoreEmptyViewUpdatesAfterTestReset = false;
@@ -8427,6 +8508,7 @@ function watchAgentSession(payload, options = {}) {
8427
8508
  payload: normalizedPayload3,
8428
8509
  listeners: /* @__PURE__ */ new Set(),
8429
8510
  lingerTimer: null,
8511
+ pendingMessageBatch: null,
8430
8512
  releaseRuntimeEvents: null,
8431
8513
  retainPromise: null
8432
8514
  };
@@ -8597,10 +8679,7 @@ function ensureWorkspaceSessionEventListener(workspaceId) {
8597
8679
  return;
8598
8680
  }
8599
8681
  for (const entry of entries) {
8600
- recordAgentSessionStreamEvent(entry, event);
8601
- for (const listener of entry.listeners) {
8602
- listener(event);
8603
- }
8682
+ receiveAgentSessionStreamEvent(entry, event);
8604
8683
  }
8605
8684
  }
8606
8685
  );
@@ -8671,6 +8750,80 @@ function clearEntryLingerTimer(entry) {
8671
8750
  clearTimeout(entry.lingerTimer);
8672
8751
  entry.lingerTimer = null;
8673
8752
  }
8753
+ function receiveAgentSessionStreamEvent(entry, event) {
8754
+ if (event.eventType !== "message_update" || isImmediateMessageUpdateEvent(event)) {
8755
+ flushPendingMessageBatch(entry);
8756
+ dispatchAgentSessionStreamEvent(entry, event);
8757
+ return;
8758
+ }
8759
+ enqueueMessageUpdateEvent(entry, event);
8760
+ }
8761
+ function enqueueMessageUpdateEvent(entry, event) {
8762
+ let batch = entry.pendingMessageBatch;
8763
+ if (!batch) {
8764
+ batch = {
8765
+ events: [],
8766
+ incomingCount: 0,
8767
+ timer: null
8768
+ };
8769
+ entry.pendingMessageBatch = batch;
8770
+ }
8771
+ batch.incomingCount += 1;
8772
+ upsertCoalescedMessageUpdate(batch.events, event);
8773
+ if (batch.timer !== null) {
8774
+ return;
8775
+ }
8776
+ batch.timer = setTimeout(
8777
+ () => flushPendingMessageBatch(entry),
8778
+ MESSAGE_UPDATE_BATCH_DELAY_MS
8779
+ );
8780
+ }
8781
+ function flushPendingMessageBatch(entry) {
8782
+ const batch = entry.pendingMessageBatch;
8783
+ if (!batch) {
8784
+ return;
8785
+ }
8786
+ clearPendingMessageBatch(entry);
8787
+ if (batch.events.length === 0) {
8788
+ return;
8789
+ }
8790
+ recordAgentSessionStreamEvents(entry, batch.events);
8791
+ for (const event of batch.events) {
8792
+ for (const listener of entry.listeners) {
8793
+ listener(event);
8794
+ }
8795
+ }
8796
+ reportMessageBatchDiagnostics(entry, batch);
8797
+ }
8798
+ function clearPendingMessageBatch(entry) {
8799
+ const batch = entry.pendingMessageBatch;
8800
+ if (!batch) {
8801
+ return;
8802
+ }
8803
+ if (batch.timer !== null) {
8804
+ clearTimeout(batch.timer);
8805
+ batch.timer = null;
8806
+ }
8807
+ entry.pendingMessageBatch = null;
8808
+ }
8809
+ function dispatchAgentSessionStreamEvent(entry, event) {
8810
+ recordAgentSessionStreamEvent(entry, event);
8811
+ for (const listener of entry.listeners) {
8812
+ listener(event);
8813
+ }
8814
+ }
8815
+ function upsertCoalescedMessageUpdate(events, event) {
8816
+ const messageId = event.data.messageId.trim();
8817
+ const existingIndex = events.findIndex(
8818
+ (candidate) => candidate.eventType === "message_update" && candidate.data.messageId.trim() === messageId
8819
+ );
8820
+ if (existingIndex >= 0) {
8821
+ events.splice(existingIndex, 1);
8822
+ events.push(event);
8823
+ return;
8824
+ }
8825
+ events.push(event);
8826
+ }
8674
8827
  function normalizeSubscribePayload(payload) {
8675
8828
  const workspaceId = payload.workspaceId?.trim();
8676
8829
  const agentSessionId = payload.agentSessionId.trim();
@@ -8714,10 +8867,20 @@ function findEntriesForEvent(event) {
8714
8867
  );
8715
8868
  }
8716
8869
  function recordAgentSessionStreamEvent(entry, event) {
8717
- const occurredAtUnixMs = "occurredAtUnixMs" in event.data && typeof event.data.occurredAtUnixMs === "number" ? event.data.occurredAtUnixMs : Date.now();
8870
+ recordAgentSessionStreamEvents(entry, [event]);
8871
+ }
8872
+ function recordAgentSessionStreamEvents(entry, events) {
8873
+ const latestEvent = events.at(-1);
8874
+ if (!latestEvent) {
8875
+ return;
8876
+ }
8877
+ const occurredAtUnixMs = "occurredAtUnixMs" in latestEvent.data && typeof latestEvent.data.occurredAtUnixMs === "number" ? latestEvent.data.occurredAtUnixMs : Date.now();
8718
8878
  updateAgentSessionView(entry.payload, (current) => {
8719
8879
  let next = current;
8720
- if (event.eventType === "available_commands_update") {
8880
+ for (const event of events) {
8881
+ if (event.eventType !== "available_commands_update") {
8882
+ continue;
8883
+ }
8721
8884
  next = {
8722
8885
  ...next,
8723
8886
  controlCommands: [...event.data.commands]
@@ -8731,6 +8894,36 @@ function recordAgentSessionStreamEvent(entry, event) {
8731
8894
  };
8732
8895
  });
8733
8896
  }
8897
+ function isImmediateMessageUpdateEvent(event) {
8898
+ if (event.eventType !== "message_update") {
8899
+ return true;
8900
+ }
8901
+ if (typeof event.data.completedAtUnixMs === "number") {
8902
+ return true;
8903
+ }
8904
+ const status = event.data.status?.trim().toLowerCase() ?? "";
8905
+ return status === "completed" || status === "failed" || status === "canceled" || status === "cancelled" || status === "error" || status === "waiting";
8906
+ }
8907
+ function reportMessageBatchDiagnostics(entry, batch) {
8908
+ if (batch.incomingCount <= 1 && batch.events.length <= 1) {
8909
+ return;
8910
+ }
8911
+ const runtime = getOptionalAgentActivityRuntime();
8912
+ try {
8913
+ void runtime?.reportDiagnostic?.({
8914
+ details: {
8915
+ agentSessionId: entry.payload.agentSessionId,
8916
+ coalescedCount: batch.events.length,
8917
+ incomingCount: batch.incomingCount
8918
+ },
8919
+ event: "agent.session_view.message_update_batch_flushed",
8920
+ level: "debug",
8921
+ source: "agent-gui",
8922
+ workspaceId: entry.payload.workspaceId
8923
+ });
8924
+ } catch {
8925
+ }
8926
+ }
8734
8927
  function isAgentSessionActivityStreamEvent(value) {
8735
8928
  if (!value || typeof value !== "object") {
8736
8929
  return false;
@@ -11071,6 +11264,68 @@ function reportAgentGUIRuntimeError(input) {
11071
11264
  } catch {
11072
11265
  }
11073
11266
  }
11267
+ function reportAgentGUICancelDiagnostic(input) {
11268
+ if (input.result.canceled) {
11269
+ return;
11270
+ }
11271
+ const reportDiagnostic = input.runtime.reportDiagnostic;
11272
+ if (!reportDiagnostic) {
11273
+ return;
11274
+ }
11275
+ try {
11276
+ void Promise.resolve(
11277
+ reportDiagnostic.call(input.runtime, {
11278
+ details: {
11279
+ agentSessionId: input.agentSessionId,
11280
+ busySource: input.busySource ?? "unknown",
11281
+ canceled: input.result.canceled,
11282
+ cancelReason: input.result.reason,
11283
+ currentSessionStatus: input.currentSessionStatus ?? null,
11284
+ phase: input.phase,
11285
+ provider: input.provider ?? null,
11286
+ returnedSessionNonBusy: cancelResultSessionStatusIsNonBusy(
11287
+ input.result
11288
+ ),
11289
+ returnedSessionStatus: input.result.session.status
11290
+ },
11291
+ event: "agent.gui.cancel.noop",
11292
+ level: "info",
11293
+ source: "agent-gui",
11294
+ workspaceId: input.workspaceId
11295
+ })
11296
+ ).catch(() => {
11297
+ });
11298
+ } catch {
11299
+ }
11300
+ }
11301
+ function cancelResultSessionStatusIsNonBusy(result) {
11302
+ const status = normalizeOptionalWorkspaceAgentStatus({
11303
+ currentPhase: result.session.currentPhase,
11304
+ status: result.session.status
11305
+ });
11306
+ return status !== null && status.kind !== "working" && status.kind !== "waiting";
11307
+ }
11308
+ function cancelBusySource(input) {
11309
+ if (input.hasActivePrompt) {
11310
+ return "interactive_prompt";
11311
+ }
11312
+ if (agentSessionStatusBusy({
11313
+ status: input.conversationStatus ?? void 0
11314
+ })) {
11315
+ return "conversation_status";
11316
+ }
11317
+ if (agentSessionStatusBusy({
11318
+ status: input.runtimeSessionStatus ?? void 0
11319
+ })) {
11320
+ return "runtime_session";
11321
+ }
11322
+ if (agentSessionStatusBusy({
11323
+ status: input.sessionStateStatus ?? void 0
11324
+ })) {
11325
+ return "session_state";
11326
+ }
11327
+ return "unknown";
11328
+ }
11074
11329
  function normalizeAgentGUIDiagnosticError(error) {
11075
11330
  const record = error && typeof error === "object" ? error : null;
11076
11331
  const appErrorCode = getAgentGUIErrorCode(error);
@@ -11261,6 +11516,17 @@ function mergeVisibleConversations(conversations, transientConversation) {
11261
11516
  }
11262
11517
  return [transientConversation, ...conversations];
11263
11518
  }
11519
+ function stableConversationSummaryList(previous, next) {
11520
+ if (previous?.length !== next.length) {
11521
+ return next;
11522
+ }
11523
+ for (let index = 0; index < next.length; index += 1) {
11524
+ if (previous[index] !== next[index]) {
11525
+ return next;
11526
+ }
11527
+ }
11528
+ return previous;
11529
+ }
11264
11530
  function mergeConversationTitleUpdateFields(current, incomingTitle) {
11265
11531
  const title = incomingTitle.trim();
11266
11532
  if (!title) {
@@ -11556,6 +11822,14 @@ function reasoningSelectionFromComposerOptions(options, currentValue) {
11556
11822
  function providerSkillsFromComposerOptions(options) {
11557
11823
  return options?.skills.map((skill) => ({ ...skill })) ?? [];
11558
11824
  }
11825
+ function areProviderSkillOptionsEqual(left, right) {
11826
+ return left.name === right.name && left.trigger === right.trigger && left.sourceKind === right.sourceKind && left.description === right.description && left.pluginName === right.pluginName;
11827
+ }
11828
+ function areProviderSkillOptionListsEqual(left, right) {
11829
+ return left.length === right.length && left.every(
11830
+ (skill, index) => areProviderSkillOptionsEqual(skill, right[index])
11831
+ );
11832
+ }
11559
11833
  function permissionConfigFromComposerOptions(options) {
11560
11834
  const config = options?.permissionConfig;
11561
11835
  if (!config) {
@@ -11672,6 +11946,25 @@ function cloneComposerSettings(settings) {
11672
11946
  function sameComposerSettings(left, right) {
11673
11947
  return (left?.model ?? null) === (right?.model ?? null) && (left?.reasoningEffort ?? null) === (right?.reasoningEffort ?? null) && Boolean(left?.planMode) === Boolean(right?.planMode) && (left?.permissionModeId ?? null) === (right?.permissionModeId ?? null);
11674
11948
  }
11949
+ function useStableComposerSettings(settings) {
11950
+ const settingsRef = useRef4(null);
11951
+ if (settingsRef.current === null || !sameComposerSettings(settingsRef.current.value, settings)) {
11952
+ settingsRef.current = { value: settings };
11953
+ }
11954
+ return settingsRef.current.value;
11955
+ }
11956
+ function useStableProviderSkillOptions(skills) {
11957
+ const skillsRef = useRef4(null);
11958
+ if (skillsRef.current === null || !areProviderSkillOptionListsEqual(skillsRef.current, skills)) {
11959
+ skillsRef.current = skills;
11960
+ }
11961
+ return skillsRef.current;
11962
+ }
11963
+ function useStableControllerEventCallback(callback) {
11964
+ const callbackRef = useRef4(callback);
11965
+ callbackRef.current = callback;
11966
+ return useCallback4((...args) => callbackRef.current(...args), []);
11967
+ }
11675
11968
  function pendingApprovalFromState(state) {
11676
11969
  return state?.pendingInteractive?.kind === "approval" ? state.pendingInteractive : null;
11677
11970
  }
@@ -14573,6 +14866,27 @@ function useAgentGUINodeController({
14573
14866
  if (!result || !isCurrentConversation(agentSessionId)) {
14574
14867
  return;
14575
14868
  }
14869
+ const conversationStatus = resolveConversationSummaryById(
14870
+ conversations,
14871
+ agentSessionId,
14872
+ transientConversationRef.current
14873
+ )?.status ?? null;
14874
+ const runtimeSessionStatus = runtimeSessionsBySessionId.get(agentSessionId)?.status ?? null;
14875
+ reportAgentGUICancelDiagnostic({
14876
+ agentSessionId,
14877
+ busySource: cancelBusySource({
14878
+ conversationStatus,
14879
+ hasActivePrompt: activePendingPrompt?.sessionId === agentSessionId,
14880
+ runtimeSessionStatus,
14881
+ sessionStateStatus: activeSessionState?.status ?? null
14882
+ }),
14883
+ currentSessionStatus: activeSessionState?.status ?? runtimeSessionStatus,
14884
+ phase: "interrupt_current_turn",
14885
+ provider: dataRef.current.provider,
14886
+ result,
14887
+ runtime: agentActivityRuntime,
14888
+ workspaceId
14889
+ });
14576
14890
  void refreshMessagesFromSnapshot(agentSessionId);
14577
14891
  void loadSessionState(agentSessionId);
14578
14892
  void syncConversationListProjection(agentSessionId);
@@ -14613,6 +14927,9 @@ function useAgentGUINodeController({
14613
14927
  syncConversationListProjection,
14614
14928
  loadSessionState,
14615
14929
  refreshMessagesFromSnapshot,
14930
+ conversations,
14931
+ runtimeSessionsBySessionId,
14932
+ activeSessionState,
14616
14933
  workspaceId,
14617
14934
  agentActivityRuntime
14618
14935
  ]
@@ -14947,6 +15264,21 @@ function useAgentGUINodeController({
14947
15264
  if (!result || !isCurrentConversation(activeConversationId)) {
14948
15265
  return;
14949
15266
  }
15267
+ reportAgentGUICancelDiagnostic({
15268
+ agentSessionId: activeConversationId,
15269
+ busySource: cancelBusySource({
15270
+ conversationStatus: activeConversationSummary?.status ?? null,
15271
+ hasActivePrompt: false,
15272
+ runtimeSessionStatus: runtimeSessionsBySessionId.get(activeConversationId)?.status ?? null,
15273
+ sessionStateStatus: activeSessionState2?.status ?? null
15274
+ }),
15275
+ currentSessionStatus: activeSessionState2?.status ?? null,
15276
+ phase: "drain_queued_prompt_interrupt",
15277
+ provider: dataRef.current.provider,
15278
+ result,
15279
+ runtime: agentActivityRuntime,
15280
+ workspaceId
15281
+ });
14950
15282
  void refreshMessagesFromSnapshot(activeConversationId);
14951
15283
  void loadSessionState(activeConversationId);
14952
15284
  void syncConversationListProjection(activeConversationId);
@@ -14983,6 +15315,7 @@ function useAgentGUINodeController({
14983
15315
  loadSessionState,
14984
15316
  refreshMessagesFromSnapshot,
14985
15317
  queuedPromptsBySessionId,
15318
+ runtimeSessionsBySessionId,
14986
15319
  workspaceId,
14987
15320
  sessionViewRef,
14988
15321
  sendNextQueuedPromptIdBySessionId,
@@ -15523,23 +15856,32 @@ function useAgentGUINodeController({
15523
15856
  userProjects,
15524
15857
  workspacePath
15525
15858
  ]);
15526
- const visibleConversations = useMemo4(
15527
- () => (isLoadingConversations ? mergeVisibleConversations(
15859
+ const visibleConversationsRef = useRef4(
15860
+ null
15861
+ );
15862
+ const visibleConversations = useMemo4(() => {
15863
+ const source = isLoadingConversations ? mergeVisibleConversations(
15528
15864
  conversations,
15529
15865
  transientConversationRef.current
15530
- ) : conversations).map(
15866
+ ) : conversations;
15867
+ const next = source.map(
15531
15868
  (conversation2) => mergeConversationSummaryWithRuntimeSession({
15532
15869
  conversation: conversation2,
15533
15870
  runtimeSyncState: stableRuntimeSyncStateBySessionId[conversation2.id]
15534
15871
  })
15535
- ),
15536
- [
15537
- conversations,
15538
- isLoadingConversations,
15539
- stableRuntimeSyncStateBySessionId,
15540
- transientConversation
15541
- ]
15542
- );
15872
+ );
15873
+ const stableNext = stableConversationSummaryList(
15874
+ visibleConversationsRef.current,
15875
+ next
15876
+ );
15877
+ visibleConversationsRef.current = stableNext;
15878
+ return stableNext;
15879
+ }, [
15880
+ conversations,
15881
+ isLoadingConversations,
15882
+ stableRuntimeSyncStateBySessionId,
15883
+ transientConversation
15884
+ ]);
15543
15885
  const conversationUserIds = useMemo4(
15544
15886
  () => [
15545
15887
  ...new Set(
@@ -15605,9 +15947,11 @@ function useAgentGUINodeController({
15605
15947
  () => planModeStateFromSessionState(activeSessionState),
15606
15948
  [activeSessionState]
15607
15949
  );
15608
- const availableSkills = useMemo4(
15609
- () => providerSkillsFromComposerOptions(providerComposerOptions),
15610
- [providerComposerOptions]
15950
+ const availableSkills = useStableProviderSkillOptions(
15951
+ useMemo4(
15952
+ () => providerSkillsFromComposerOptions(providerComposerOptions),
15953
+ [providerComposerOptions]
15954
+ )
15611
15955
  );
15612
15956
  const conversationDetail = useMemo4(
15613
15957
  () => projectionConversation ? buildAgentGUIConversationDetail({
@@ -15691,24 +16035,28 @@ function useAgentGUINodeController({
15691
16035
  [activeConversationId, queuedPromptsBySessionId]
15692
16036
  );
15693
16037
  const drainingQueuedPromptId = drainingQueuedPromptSessionId === activeConversationId ? queuedPrompts[0]?.id ?? null : null;
15694
- const sessionSettings = cloneComposerSettings(
15695
- activeSessionState?.settings ?? null
16038
+ const sessionSettings = useStableComposerSettings(
16039
+ cloneComposerSettings(activeSessionState?.settings ?? null)
16040
+ );
16041
+ const storedNodeDefaultSettings = useStableComposerSettings(
16042
+ readNodeDefaultDraftSettings({
16043
+ data,
16044
+ defaultReasoningEffort,
16045
+ drafts: draftSettingsBySessionId
16046
+ })
16047
+ );
16048
+ const homeComposerSettings = useStableComposerSettings(
16049
+ resolveEffectiveComposerSettings({
16050
+ settings: storedNodeDefaultSettings
16051
+ })
15696
16052
  );
15697
- const storedNodeDefaultSettings = readNodeDefaultDraftSettings({
15698
- data,
15699
- defaultReasoningEffort,
15700
- drafts: draftSettingsBySessionId
15701
- });
15702
- const homeComposerSettings = resolveEffectiveComposerSettings({
15703
- settings: storedNodeDefaultSettings
15704
- });
15705
16053
  const activeConversationDraftSettings = activeConversationId ? draftSettingsBySessionId[activeConversationId] ?? null : null;
15706
- const defaultConversationDraftSettings = {
16054
+ const defaultConversationDraftSettings = useStableComposerSettings({
15707
16055
  ...activeConversationDraftSettings ?? homeComposerSettings,
15708
16056
  permissionModeId: normalizePermissionModeId(activeSessionState?.permissionModeId) ?? normalizePermissionModeId(
15709
16057
  (activeConversationDraftSettings ?? homeComposerSettings).permissionModeId
15710
16058
  )
15711
- };
16059
+ });
15712
16060
  const draftSettings = activeConversationId ? sessionSettings ?? defaultConversationDraftSettings : homeComposerSettings;
15713
16061
  const draftModel = normalizeOptionalText(draftSettings.model);
15714
16062
  const draftReasoningEffort = normalizeOptionalText(
@@ -15773,6 +16121,14 @@ function useAgentGUINodeController({
15773
16121
  () => modelSelectionFromComposerOptions(providerComposerOptions, draftModel),
15774
16122
  [draftModel, providerComposerOptions]
15775
16123
  );
16124
+ const effectivePlanMode = useMemo4(
16125
+ () => resolveEffectivePlanModeFromStates({
16126
+ sessionPlanModeState,
16127
+ timelinePlanModeState,
16128
+ fallbackPlanMode: Boolean(draftSettings.planMode)
16129
+ }),
16130
+ [draftSettings.planMode, sessionPlanModeState, timelinePlanModeState]
16131
+ );
15776
16132
  const composerSettings = useMemo4(() => {
15777
16133
  const permissionConfig = permissionConfigFromComposerOptions(
15778
16134
  providerComposerOptions
@@ -15786,11 +16142,6 @@ function useAgentGUINodeController({
15786
16142
  const selectedModelValue = draftModel;
15787
16143
  const selectedReasoningEffortValue = draftReasoningEffort;
15788
16144
  const selectedPermissionModeValue = normalizePermissionModeId(draftSettings.permissionModeId) ?? normalizePermissionModeId(permissionConfig?.defaultValue);
15789
- const effectivePlanMode = resolveEffectivePlanModeFromStates({
15790
- sessionPlanModeState,
15791
- timelinePlanModeState,
15792
- fallbackPlanMode: Boolean(draftSettings.planMode)
15793
- });
15794
16145
  return {
15795
16146
  sessionSettings,
15796
16147
  draftSettings: {
@@ -15828,18 +16179,115 @@ function useAgentGUINodeController({
15828
16179
  activeSessionReasoningSelection,
15829
16180
  draftSettings.permissionModeId,
15830
16181
  draftSettings.planMode,
16182
+ effectivePlanMode,
15831
16183
  providerComposerOptions,
15832
- sessionPlanModeState,
15833
16184
  sessionSettings,
15834
16185
  selectedProjectPath,
15835
16186
  supports.model,
15836
16187
  supports.permission,
15837
16188
  supports.plan,
15838
16189
  supports.reasoning,
15839
- timelinePlanModeState,
15840
16190
  draftModel,
15841
16191
  draftReasoningEffort
15842
16192
  ]);
16193
+ const stableCreateConversation = useStableControllerEventCallback(createConversation);
16194
+ const stableSelectConversation = useStableControllerEventCallback(selectConversation);
16195
+ const stableSubmitPrompt = useStableControllerEventCallback(submitPrompt);
16196
+ const stableShowPromptImagesUnsupported = useStableControllerEventCallback(
16197
+ showPromptImagesUnsupported
16198
+ );
16199
+ const stableSubmitApprovalOption = useStableControllerEventCallback(submitApprovalOption);
16200
+ const stableSubmitInteractivePrompt = useStableControllerEventCallback(
16201
+ submitInteractivePrompt
16202
+ );
16203
+ const stableInterruptCurrentTurn = useStableControllerEventCallback(interruptCurrentTurn);
16204
+ const stableUpdateDraftPrompt = useStableControllerEventCallback(updateDraftPrompt);
16205
+ const stableUpdateSelectedProjectPath = useStableControllerEventCallback(
16206
+ updateSelectedProjectPath
16207
+ );
16208
+ const stableUpdateComposerSettings = useStableControllerEventCallback(
16209
+ updateComposerSettings
16210
+ );
16211
+ const stableSendQueuedPromptNext = useStableControllerEventCallback(sendQueuedPromptNext);
16212
+ const stableRemoveQueuedPrompt = useStableControllerEventCallback(removeQueuedPrompt);
16213
+ const stableEditQueuedPrompt = useStableControllerEventCallback(editQueuedPrompt);
16214
+ const stableRemoveProject = useStableControllerEventCallback(removeProject);
16215
+ const stableRequestDeleteProjectConversations = useStableControllerEventCallback(requestDeleteProjectConversations);
16216
+ const stableCancelDeleteProjectConversations = useStableControllerEventCallback(cancelDeleteProjectConversations);
16217
+ const stableConfirmDeleteProjectConversations = useStableControllerEventCallback(confirmDeleteProjectConversations);
16218
+ const stableToggleConversationPinned = useStableControllerEventCallback(
16219
+ toggleConversationPinned
16220
+ );
16221
+ const stableRequestDeleteConversation = useStableControllerEventCallback(
16222
+ requestDeleteConversation
16223
+ );
16224
+ const stableRetryActivation = useStableControllerEventCallback(retryActivation);
16225
+ const stableContinueInNewConversation = useStableControllerEventCallback(
16226
+ continueInNewConversation
16227
+ );
16228
+ const stableCancelDeleteConversation = useStableControllerEventCallback(
16229
+ cancelDeleteConversation
16230
+ );
16231
+ const stableConfirmDeleteConversation = useStableControllerEventCallback(
16232
+ confirmDeleteConversation
16233
+ );
16234
+ const stableRetryOpenclawGateway = useStableControllerEventCallback(
16235
+ ensureOpenclawGateway
16236
+ );
16237
+ const controllerActions = useMemo4(
16238
+ () => ({
16239
+ createConversation: stableCreateConversation,
16240
+ selectConversation: stableSelectConversation,
16241
+ submitPrompt: stableSubmitPrompt,
16242
+ showPromptImagesUnsupported: stableShowPromptImagesUnsupported,
16243
+ submitApprovalOption: stableSubmitApprovalOption,
16244
+ submitInteractivePrompt: stableSubmitInteractivePrompt,
16245
+ interruptCurrentTurn: stableInterruptCurrentTurn,
16246
+ updateDraftPrompt: stableUpdateDraftPrompt,
16247
+ updateSelectedProjectPath: stableUpdateSelectedProjectPath,
16248
+ updateComposerSettings: stableUpdateComposerSettings,
16249
+ sendQueuedPromptNext: stableSendQueuedPromptNext,
16250
+ removeQueuedPrompt: stableRemoveQueuedPrompt,
16251
+ editQueuedPrompt: stableEditQueuedPrompt,
16252
+ removeProject: stableRemoveProject,
16253
+ requestDeleteProjectConversations: stableRequestDeleteProjectConversations,
16254
+ cancelDeleteProjectConversations: stableCancelDeleteProjectConversations,
16255
+ confirmDeleteProjectConversations: stableConfirmDeleteProjectConversations,
16256
+ toggleConversationPinned: stableToggleConversationPinned,
16257
+ requestDeleteConversation: stableRequestDeleteConversation,
16258
+ retryActivation: stableRetryActivation,
16259
+ continueInNewConversation: stableContinueInNewConversation,
16260
+ cancelDeleteConversation: stableCancelDeleteConversation,
16261
+ confirmDeleteConversation: stableConfirmDeleteConversation,
16262
+ retryOpenclawGateway: stableRetryOpenclawGateway
16263
+ }),
16264
+ [
16265
+ stableCancelDeleteConversation,
16266
+ stableCancelDeleteProjectConversations,
16267
+ stableConfirmDeleteConversation,
16268
+ stableConfirmDeleteProjectConversations,
16269
+ stableContinueInNewConversation,
16270
+ stableCreateConversation,
16271
+ stableEditQueuedPrompt,
16272
+ stableInterruptCurrentTurn,
16273
+ stableRemoveProject,
16274
+ stableRemoveQueuedPrompt,
16275
+ stableRequestDeleteConversation,
16276
+ stableRequestDeleteProjectConversations,
16277
+ stableRetryActivation,
16278
+ stableRetryOpenclawGateway,
16279
+ stableSelectConversation,
16280
+ stableSendQueuedPromptNext,
16281
+ stableShowPromptImagesUnsupported,
16282
+ stableSubmitApprovalOption,
16283
+ stableSubmitInteractivePrompt,
16284
+ stableSubmitPrompt,
16285
+ stableToggleConversationPinned,
16286
+ stableUpdateComposerSettings,
16287
+ stableUpdateDraftPrompt,
16288
+ stableUpdateSelectedProjectPath
16289
+ ]
16290
+ );
15843
16291
  return useMemo4(
15844
16292
  () => ({
15845
16293
  viewModel: {
@@ -15889,32 +16337,7 @@ function useAgentGUINodeController({
15889
16337
  } : null,
15890
16338
  detailError
15891
16339
  },
15892
- actions: {
15893
- createConversation,
15894
- selectConversation,
15895
- submitPrompt,
15896
- showPromptImagesUnsupported,
15897
- submitApprovalOption,
15898
- submitInteractivePrompt,
15899
- interruptCurrentTurn,
15900
- updateDraftPrompt,
15901
- updateSelectedProjectPath,
15902
- updateComposerSettings,
15903
- sendQueuedPromptNext,
15904
- removeQueuedPrompt,
15905
- editQueuedPrompt,
15906
- removeProject,
15907
- requestDeleteProjectConversations,
15908
- cancelDeleteProjectConversations,
15909
- confirmDeleteProjectConversations,
15910
- toggleConversationPinned,
15911
- requestDeleteConversation,
15912
- retryActivation,
15913
- continueInNewConversation,
15914
- cancelDeleteConversation,
15915
- confirmDeleteConversation,
15916
- retryOpenclawGateway: ensureOpenclawGateway
15917
- }
16340
+ actions: controllerActions
15918
16341
  }),
15919
16342
  [
15920
16343
  activeConversation,
@@ -15929,12 +16352,10 @@ function useAgentGUINodeController({
15929
16352
  composerSettings,
15930
16353
  conversation,
15931
16354
  conversationDetail,
15932
- conversations,
15933
- createConversation,
16355
+ controllerActions,
15934
16356
  data,
15935
16357
  detailError,
15936
16358
  draftPrompt,
15937
- continueInNewConversation,
15938
16359
  isCreatingConversation,
15939
16360
  openclawGateway,
15940
16361
  promptImagesSupported,
@@ -15953,34 +16374,12 @@ function useAgentGUINodeController({
15953
16374
  pendingInteractivePrompt,
15954
16375
  queuedPrompts,
15955
16376
  drainingQueuedPromptId,
15956
- sendQueuedPromptNext,
15957
- removeQueuedPrompt,
15958
- editQueuedPrompt,
15959
- removeProject,
15960
- requestDeleteProjectConversations,
15961
- cancelDeleteProjectConversations,
15962
- confirmDeleteProjectConversations,
15963
- submitApprovalOption,
15964
- submitInteractivePrompt,
15965
- interruptCurrentTurn,
15966
- toggleConversationPinned,
15967
- requestDeleteConversation,
15968
- retryActivation,
15969
16377
  currentUserId,
15970
16378
  workspaceId,
15971
16379
  workspacePath,
15972
16380
  sessionChrome,
15973
- selectConversation,
15974
- showPromptImagesUnsupported,
15975
- submitPrompt,
15976
16381
  userProjects,
15977
- visibleConversations,
15978
- updateComposerSettings,
15979
- updateDraftPrompt,
15980
- updateSelectedProjectPath,
15981
- cancelDeleteConversation,
15982
- confirmDeleteConversation,
15983
- ensureOpenclawGateway
16382
+ visibleConversations
15984
16383
  ]
15985
16384
  );
15986
16385
  }
@@ -16141,6 +16540,7 @@ import {
16141
16540
  useRef as useRef20,
16142
16541
  useState as useState26
16143
16542
  } from "react";
16543
+ import { useSnapshot } from "valtio";
16144
16544
  import { ChevronRight as ChevronRight9, Info as Info2 } from "lucide-react";
16145
16545
  import { WorkspaceFileReferencePicker } from "@tutti-os/workspace-file-reference/ui";
16146
16546
  import {
@@ -17672,7 +18072,8 @@ function AgentMessageBlock({
17672
18072
  },
17673
18073
  workspaceAppIcons,
17674
18074
  deferLongContentRender: true,
17675
- enableImageZoom: true
18075
+ enableImageZoom: true,
18076
+ streaming: message.statusKind === "working"
17676
18077
  }
17677
18078
  );
17678
18079
  if (rawTimelineJson2) {
@@ -22848,9 +23249,124 @@ var AgentTranscriptItemView = memo2(function AgentTranscriptItemView2({
22848
23249
  }
22849
23250
  });
22850
23251
 
23252
+ // shared/agentConversation/components/agentTranscriptComplexity.ts
23253
+ var AGENT_TRANSCRIPT_COMPLEXITY_VIRTUALIZATION_SCORE = 40;
23254
+ var AGENT_TRANSCRIPT_COMPLEXITY_SINGLE_TURN_SCORE = 24;
23255
+ var AGENT_TRANSCRIPT_COMPLEXITY_TURN_COUNT = 30;
23256
+ function assessAgentTranscriptComplexity(turnGroups) {
23257
+ const complexity = calculateAgentTranscriptComplexity(turnGroups);
23258
+ return {
23259
+ ...complexity,
23260
+ shouldVirtualize: shouldVirtualizeAgentTranscript({
23261
+ turnCount: turnGroups.length,
23262
+ complexity
23263
+ }),
23264
+ turnCount: turnGroups.length
23265
+ };
23266
+ }
23267
+ function calculateAgentTranscriptComplexity(turnGroups) {
23268
+ const turnScores = turnGroups.map((group) => calculateTurnScore(group.rows));
23269
+ const totalScore = turnScores.reduce((total, score) => total + score, 0);
23270
+ return {
23271
+ totalScore,
23272
+ maxTurnScore: Math.max(0, ...turnScores),
23273
+ turnScores
23274
+ };
23275
+ }
23276
+ function shouldVirtualizeAgentTranscript(input) {
23277
+ return input.turnCount >= AGENT_TRANSCRIPT_COMPLEXITY_TURN_COUNT || input.complexity.totalScore >= AGENT_TRANSCRIPT_COMPLEXITY_VIRTUALIZATION_SCORE || input.complexity.maxTurnScore >= AGENT_TRANSCRIPT_COMPLEXITY_SINGLE_TURN_SCORE;
23278
+ }
23279
+ function calculateTurnScore(rows) {
23280
+ let rowCount = 0;
23281
+ let charCount = 0;
23282
+ let codeFenceCount = 0;
23283
+ let tableCount = 0;
23284
+ let toolCallCount = 0;
23285
+ let thinkingBlockCount = 0;
23286
+ let imageCount = 0;
23287
+ for (const { row } of rows) {
23288
+ rowCount += 1;
23289
+ if (row.kind === "message") {
23290
+ for (const message of row.messages) {
23291
+ charCount += message.body.length;
23292
+ codeFenceCount += countCodeFences(message.body);
23293
+ tableCount += countMarkdownTables(message.body);
23294
+ imageCount += (message.images?.length ?? 0) + countMarkdownImages(message.body);
23295
+ }
23296
+ for (const thinking of row.thinking) {
23297
+ thinkingBlockCount += 1;
23298
+ charCount += thinking.body.length;
23299
+ codeFenceCount += countCodeFences(thinking.body);
23300
+ }
23301
+ continue;
23302
+ }
23303
+ if (row.kind === "tool-group") {
23304
+ toolCallCount += row.calls.length;
23305
+ thinkingBlockCount += row.entries.filter(
23306
+ (entry) => entry.kind === "thinking"
23307
+ ).length;
23308
+ charCount += (row.summary ?? "").length;
23309
+ continue;
23310
+ }
23311
+ if (row.kind === "turn-summary") {
23312
+ charCount += row.files.reduce(
23313
+ (total, file) => total + file.label.length + file.path.length + (file.unifiedDiff?.length ?? 0) + (file.content?.length ?? 0),
23314
+ 0
23315
+ );
23316
+ }
23317
+ }
23318
+ return rowCount + charCount / 1200 + codeFenceCount * 4 + tableCount * 5 + toolCallCount * 2 + thinkingBlockCount * 2 + imageCount * 4;
23319
+ }
23320
+ function countCodeFences(value) {
23321
+ let count = 0;
23322
+ for (const line of value.split("\n")) {
23323
+ const trimmed = line.trimStart();
23324
+ if (trimmed.startsWith("```") || trimmed.startsWith("~~~")) {
23325
+ count += 1;
23326
+ }
23327
+ }
23328
+ return Math.ceil(count / 2);
23329
+ }
23330
+ function countMarkdownTables(value) {
23331
+ const lines = value.split("\n");
23332
+ let count = 0;
23333
+ for (let index = 1; index < lines.length; index += 1) {
23334
+ if (looksLikeTableSeparator(lines[index] ?? "") && lines[index - 1]?.includes("|")) {
23335
+ count += 1;
23336
+ }
23337
+ }
23338
+ return count;
23339
+ }
23340
+ function countMarkdownImages(value) {
23341
+ let count = 0;
23342
+ let index = 0;
23343
+ while (index < value.length) {
23344
+ const imageStart = value.indexOf("![", index);
23345
+ if (imageStart < 0) {
23346
+ break;
23347
+ }
23348
+ const labelEnd = value.indexOf("]", imageStart + 2);
23349
+ const targetStart = labelEnd >= 0 ? value.indexOf("(", labelEnd) : -1;
23350
+ const targetEnd = targetStart >= 0 ? value.indexOf(")", targetStart) : -1;
23351
+ if (labelEnd >= 0 && targetStart === labelEnd + 1 && targetEnd > targetStart) {
23352
+ count += 1;
23353
+ index = targetEnd + 1;
23354
+ continue;
23355
+ }
23356
+ index = imageStart + 2;
23357
+ }
23358
+ return count;
23359
+ }
23360
+ function looksLikeTableSeparator(line) {
23361
+ const cells = line.split("|").map((cell) => cell.trim()).filter(Boolean);
23362
+ return cells.length > 0 && cells.every((cell) => {
23363
+ const normalized = cell.replace(/:/gu, "");
23364
+ return normalized.length >= 3 && [...normalized].every((char) => char === "-");
23365
+ });
23366
+ }
23367
+
22851
23368
  // shared/agentConversation/components/AgentTranscriptView.tsx
22852
23369
  import { Fragment as Fragment8, jsx as jsx71, jsxs as jsxs46 } from "react/jsx-runtime";
22853
- var AGENT_TRANSCRIPT_VIRTUALIZATION_TURN_THRESHOLD = 30;
22854
23370
  var AGENT_TRANSCRIPT_VIRTUALIZATION_OVERSCAN = 6;
22855
23371
  var AGENT_TRANSCRIPT_ESTIMATED_TURN_HEIGHT_PX = 280;
22856
23372
  var AGENT_TRANSCRIPT_TURN_GAP_PX = 12;
@@ -22921,7 +23437,10 @@ var AgentTranscriptView = memo3(function AgentTranscriptView2({
22921
23437
  );
22922
23438
  const basePath = conversation.sourceDetail.cwd;
22923
23439
  const workspaceRoot = conversation.workspaceRoot;
22924
- const shouldVirtualize = turnGroups.length >= AGENT_TRANSCRIPT_VIRTUALIZATION_TURN_THRESHOLD;
23440
+ const shouldVirtualize = useMemo10(
23441
+ () => assessAgentTranscriptComplexity(turnGroups).shouldVirtualize,
23442
+ [turnGroups]
23443
+ );
22925
23444
  const rowVirtualizer = useVirtualizer({
22926
23445
  count: turnGroups.length,
22927
23446
  estimateSize: () => AGENT_TRANSCRIPT_ESTIMATED_TURN_HEIGHT_PX,
@@ -27382,6 +27901,8 @@ function roomIssueStatusLabel(status, t) {
27382
27901
  return translateFn("agentHost.roomIssueNode.issueStatusNotStarted");
27383
27902
  case "running":
27384
27903
  return translateFn("agentHost.roomIssueNode.issueStatusRunning");
27904
+ case "in_progress":
27905
+ return translateFn("agentHost.roomIssueNode.issueStatusInProgress");
27385
27906
  case "pending_acceptance":
27386
27907
  return translateFn(
27387
27908
  "agentHost.roomIssueNode.issueStatusPendingAcceptance"
@@ -28098,7 +28619,13 @@ function shouldRenderMentionGroupLabel(input) {
28098
28619
  }
28099
28620
  function renderMentionRow(item) {
28100
28621
  if (item.kind === "file") {
28101
- const visualKind = resolveAgentMentionFileVisualKind(item);
28622
+ const visualKind = resolveAgentMentionFileVisualKind({
28623
+ entryKind: item.entryKind,
28624
+ href: item.href,
28625
+ mentionNavigation: item.mentionNavigation,
28626
+ name: item.name,
28627
+ path: item.path
28628
+ });
28102
28629
  const childCountLabel = item.mentionNavigation === "agent-generated-folder" && typeof item.childCount === "number" && item.childCount > 0 ? translate("agentHost.agentGui.mentionAgentGeneratedFolderFileCount", {
28103
28630
  count: item.childCount
28104
28631
  }) : null;
@@ -28110,6 +28637,7 @@ function renderMentionRow(item) {
28110
28637
  "data-agent-mention-kind": "file",
28111
28638
  "data-agent-file-entry-kind": item.entryKind,
28112
28639
  "data-agent-file-visual-kind": visualKind,
28640
+ ...item.mentionNavigation ? { "data-agent-mention-navigation": item.mentionNavigation } : {},
28113
28641
  children: [
28114
28642
  /* @__PURE__ */ jsx82(MentionFileIcon, { item, visualKind }),
28115
28643
  /* @__PURE__ */ jsxs53("span", { className: "flex min-w-0 items-baseline gap-1 overflow-hidden", children: [
@@ -30177,6 +30705,21 @@ function SendFilledIcon() {
30177
30705
  );
30178
30706
  }
30179
30707
 
30708
+ // agent-gui/agentGuiNode/AgentGUIBottomDockStore.ts
30709
+ import { proxy } from "valtio/vanilla";
30710
+ function createAgentGUIBottomDockStore(initialState) {
30711
+ return proxy(initialState);
30712
+ }
30713
+ function syncAgentGUIBottomDockStore(store, next) {
30714
+ if (agentGUIBottomDockStoreSnapshotsEqual(store, next)) {
30715
+ return;
30716
+ }
30717
+ Object.assign(store, next);
30718
+ }
30719
+ function agentGUIBottomDockStoreSnapshotsEqual(current, next) {
30720
+ return current.bottomDockActivePrompt === next.bottomDockActivePrompt && current.composerProps === next.composerProps && current.inlineNoticeChrome === next.inlineNoticeChrome && current.isRespondingApproval === next.isRespondingApproval && current.sessionChrome === next.sessionChrome;
30721
+ }
30722
+
30180
30723
  // agent-gui/agentGuiNode/AgentConversationListSkeleton.tsx
30181
30724
  import { jsx as jsx84, jsxs as jsxs55 } from "react/jsx-runtime";
30182
30725
  var SKELETON_ROWS = [
@@ -30855,6 +31398,7 @@ function AgentGUINodeView({
30855
31398
  labels,
30856
31399
  workspaceUserProjectI18n,
30857
31400
  uiLanguage,
31401
+ showProjectSelector,
30858
31402
  createConversationDisabled,
30859
31403
  openclawGateway,
30860
31404
  isCollapsed: conversationRailCollapsed,
@@ -31294,14 +31838,170 @@ var AgentGUIDetailPane = memo5(function AgentGUIDetailPane2({
31294
31838
  );
31295
31839
  const handleInterruptCurrentTurn = useCallback18(() => {
31296
31840
  actions.interruptCurrentTurn(labels.noRunningResponse);
31297
- }, [actions, labels.noRunningResponse]);
31841
+ }, [actions.interruptCurrentTurn, labels.noRunningResponse]);
31842
+ const submitApprovalOption = useStableEventCallback(
31843
+ actions.submitApprovalOption
31844
+ );
31845
+ const retryActivation = useStableEventCallback(actions.retryActivation);
31846
+ const continueInNewConversation = useStableEventCallback(
31847
+ actions.continueInNewConversation
31848
+ );
31849
+ const updateDraftPrompt = useStableEventCallback(actions.updateDraftPrompt);
31850
+ const updateSelectedProjectPath = useOptionalStableEventCallback(
31851
+ actions.updateSelectedProjectPath
31852
+ );
31853
+ const updateComposerSettings = useStableEventCallback(
31854
+ actions.updateComposerSettings
31855
+ );
31856
+ const submitPrompt = useStableEventCallback(actions.submitPrompt);
31857
+ const showPromptImagesUnsupported = useStableEventCallback(
31858
+ actions.showPromptImagesUnsupported
31859
+ );
31860
+ const sendQueuedPromptNext = useStableEventCallback(
31861
+ actions.sendQueuedPromptNext
31862
+ );
31863
+ const removeQueuedPrompt = useStableEventCallback(actions.removeQueuedPrompt);
31864
+ const editQueuedPrompt = useStableEventCallback(actions.editQueuedPrompt);
31865
+ const submitInteractivePrompt = useStableEventCallback(
31866
+ actions.submitInteractivePrompt
31867
+ );
31868
+ const stableLinkAction = useOptionalStableEventCallback(onLinkAction);
31869
+ const stableRequestWorkspaceReferences = useOptionalStableEventCallback(
31870
+ onRequestWorkspaceReferences
31871
+ );
31872
+ const authLogin = useOptionalStableEventCallback(onAgentProviderLogin);
31298
31873
  const submitBottomDockInteractivePrompt = useCallback18(
31299
31874
  (input) => {
31300
- actions.submitInteractivePrompt(input);
31875
+ submitInteractivePrompt(input);
31301
31876
  setBottomDockDismissedPromptRequestId(input.requestId);
31302
31877
  },
31303
- [actions]
31878
+ [submitInteractivePrompt]
31304
31879
  );
31880
+ const bottomDockComposerProps = useMemo15(
31881
+ () => ({
31882
+ workspaceId: viewModel.workspaceId,
31883
+ workspacePath: viewModel.workspacePath,
31884
+ currentUserId: viewModel.currentUserId,
31885
+ provider: viewModel.data.provider,
31886
+ slashStatus,
31887
+ draftPrompt: viewModel.draftPrompt,
31888
+ availableCommands: viewModel.availableCommands,
31889
+ hasCompactableContext: viewModel.hasSentUserMessage,
31890
+ availableSkills: viewModel.availableSkills,
31891
+ disabled: composerDisabled,
31892
+ disabledReason: composerDisabledReason,
31893
+ submitDisabled,
31894
+ composerSettings: viewModel.composerSettings,
31895
+ queuedPrompts: viewModel.queuedPrompts,
31896
+ drainingQueuedPromptId: viewModel.drainingQueuedPromptId,
31897
+ workspaceAppIcons,
31898
+ canQueueWhileBusy,
31899
+ placeholder: viewModel.hasSentUserMessage ? labels.followupPlaceholder : labels.initialPlaceholder,
31900
+ showStopButton,
31901
+ activePrompt: shouldLiftActivePromptAboveInlineNotice ? null : activePrompt,
31902
+ activePromptKeyboardShortcutsEnabled: isActive,
31903
+ promptTips: labels.promptTips,
31904
+ composerFocusRequestSequence,
31905
+ isActive,
31906
+ promptImagesSupported: viewModel.promptImagesSupported,
31907
+ showProjectSelector,
31908
+ isInterrupting: viewModel.isInterrupting,
31909
+ isSendingTurn: isComposerSending,
31910
+ isSubmittingPrompt: viewModel.isRespondingApproval,
31911
+ labels: composerLabels,
31912
+ workspaceUserProjectI18n,
31913
+ onDraftChange: updateDraftPrompt,
31914
+ onProjectPathChange: updateSelectedProjectPath,
31915
+ onSettingsChange: updateComposerSettings,
31916
+ onSubmit: submitPrompt,
31917
+ onPromptImagesUnsupported: showPromptImagesUnsupported,
31918
+ onSendQueuedPromptNext: sendQueuedPromptNext,
31919
+ onRemoveQueuedPrompt: removeQueuedPrompt,
31920
+ onEditQueuedPrompt: editQueuedPrompt,
31921
+ onInterruptCurrentTurn: handleInterruptCurrentTurn,
31922
+ onSubmitInteractivePrompt: submitInteractivePrompt,
31923
+ onLinkAction: stableLinkAction,
31924
+ onRequestWorkspaceReferences: stableRequestWorkspaceReferences,
31925
+ richTextAtProviders
31926
+ }),
31927
+ [
31928
+ activePrompt,
31929
+ canQueueWhileBusy,
31930
+ composerDisabled,
31931
+ composerDisabledReason,
31932
+ composerFocusRequestSequence,
31933
+ composerLabels,
31934
+ handleInterruptCurrentTurn,
31935
+ isActive,
31936
+ isComposerSending,
31937
+ labels.followupPlaceholder,
31938
+ labels.initialPlaceholder,
31939
+ labels.promptTips,
31940
+ editQueuedPrompt,
31941
+ richTextAtProviders,
31942
+ removeQueuedPrompt,
31943
+ sendQueuedPromptNext,
31944
+ shouldLiftActivePromptAboveInlineNotice,
31945
+ showPromptImagesUnsupported,
31946
+ showProjectSelector,
31947
+ showStopButton,
31948
+ slashStatus,
31949
+ submitDisabled,
31950
+ submitInteractivePrompt,
31951
+ submitPrompt,
31952
+ stableLinkAction,
31953
+ stableRequestWorkspaceReferences,
31954
+ updateComposerSettings,
31955
+ updateDraftPrompt,
31956
+ updateSelectedProjectPath,
31957
+ viewModel.availableCommands,
31958
+ viewModel.availableSkills,
31959
+ viewModel.composerSettings,
31960
+ viewModel.currentUserId,
31961
+ viewModel.data.provider,
31962
+ viewModel.draftPrompt,
31963
+ viewModel.drainingQueuedPromptId,
31964
+ viewModel.hasSentUserMessage,
31965
+ viewModel.isInterrupting,
31966
+ viewModel.isRespondingApproval,
31967
+ viewModel.promptImagesSupported,
31968
+ viewModel.queuedPrompts,
31969
+ viewModel.workspaceId,
31970
+ viewModel.workspacePath,
31971
+ workspaceUserProjectI18n,
31972
+ workspaceAppIcons
31973
+ ]
31974
+ );
31975
+ const bottomDockStoreState = useMemo15(
31976
+ () => ({
31977
+ bottomDockActivePrompt,
31978
+ composerProps: bottomDockComposerProps,
31979
+ inlineNoticeChrome,
31980
+ isRespondingApproval: viewModel.isRespondingApproval,
31981
+ sessionChrome
31982
+ }),
31983
+ [
31984
+ bottomDockActivePrompt,
31985
+ bottomDockComposerProps,
31986
+ inlineNoticeChrome,
31987
+ sessionChrome,
31988
+ viewModel.isRespondingApproval
31989
+ ]
31990
+ );
31991
+ const bottomDockStoreRef = useRef20(null);
31992
+ if (bottomDockStoreRef.current === null) {
31993
+ bottomDockStoreRef.current = createAgentGUIBottomDockStore(bottomDockStoreState);
31994
+ }
31995
+ const bottomDockStore = bottomDockStoreRef.current;
31996
+ syncAgentGUIBottomDockStore(bottomDockStore, bottomDockStoreState);
31997
+ const bottomDockStoreRevision = [
31998
+ bottomDockActivePrompt?.requestId ?? "",
31999
+ inlineNoticeChrome?.recovery?.message ?? "",
32000
+ sessionChrome.auth?.message ?? "",
32001
+ sessionChrome.recovery?.kind ?? "",
32002
+ sessionChrome.recovery?.message ?? "",
32003
+ viewModel.isRespondingApproval ? "1" : "0"
32004
+ ].join("|");
31305
32005
  useEffect21(() => {
31306
32006
  setBottomDockDismissedPromptRequestId(null);
31307
32007
  }, [activePromptRequestId]);
@@ -31432,6 +32132,7 @@ var AgentGUIDetailPane = memo5(function AgentGUIDetailPane2({
31432
32132
  /* @__PURE__ */ jsx86(
31433
32133
  ScrollArea,
31434
32134
  {
32135
+ scrollbarMode: "native",
31435
32136
  className: "min-h-0 flex-1 [&_[data-orientation=vertical][data-slot=scroll-area-scrollbar]]:opacity-100",
31436
32137
  viewportRef: timelineRef,
31437
32138
  viewportTestId: "agent-gui-timeline",
@@ -31445,10 +32146,10 @@ var AgentGUIDetailPane = memo5(function AgentGUIDetailPane2({
31445
32146
  emptyProvider: labels.emptyProvider ?? "",
31446
32147
  inlineNoticeChrome,
31447
32148
  isRespondingApproval: viewModel.isRespondingApproval,
31448
- onSubmitApprovalOption: actions.submitApprovalOption,
31449
- onRetryActivation: actions.retryActivation,
31450
- onAuthLogin: onAgentProviderLogin,
31451
- onContinueInNewConversation: actions.continueInNewConversation,
32149
+ onSubmitApprovalOption: submitApprovalOption,
32150
+ onRetryActivation: retryActivation,
32151
+ onAuthLogin: authLogin,
32152
+ onContinueInNewConversation: continueInNewConversation,
31452
32153
  chromeLabels,
31453
32154
  composerProps: {
31454
32155
  workspaceId: viewModel.workspaceId,
@@ -31482,18 +32183,18 @@ var AgentGUIDetailPane = memo5(function AgentGUIDetailPane2({
31482
32183
  isSubmittingPrompt: viewModel.isRespondingApproval,
31483
32184
  labels: composerLabels,
31484
32185
  workspaceUserProjectI18n,
31485
- onDraftChange: actions.updateDraftPrompt,
31486
- onProjectPathChange: actions.updateSelectedProjectPath,
31487
- onSettingsChange: actions.updateComposerSettings,
31488
- onSubmit: actions.submitPrompt,
31489
- onPromptImagesUnsupported: actions.showPromptImagesUnsupported,
31490
- onSendQueuedPromptNext: actions.sendQueuedPromptNext,
31491
- onRemoveQueuedPrompt: actions.removeQueuedPrompt,
31492
- onEditQueuedPrompt: actions.editQueuedPrompt,
32186
+ onDraftChange: updateDraftPrompt,
32187
+ onProjectPathChange: updateSelectedProjectPath,
32188
+ onSettingsChange: updateComposerSettings,
32189
+ onSubmit: submitPrompt,
32190
+ onPromptImagesUnsupported: showPromptImagesUnsupported,
32191
+ onSendQueuedPromptNext: sendQueuedPromptNext,
32192
+ onRemoveQueuedPrompt: removeQueuedPrompt,
32193
+ onEditQueuedPrompt: editQueuedPrompt,
31493
32194
  onInterruptCurrentTurn: handleInterruptCurrentTurn,
31494
- onSubmitInteractivePrompt: actions.submitInteractivePrompt,
31495
- onLinkAction,
31496
- onRequestWorkspaceReferences,
32195
+ onSubmitInteractivePrompt: submitInteractivePrompt,
32196
+ onLinkAction: stableLinkAction,
32197
+ onRequestWorkspaceReferences: stableRequestWorkspaceReferences,
31497
32198
  richTextAtProviders
31498
32199
  }
31499
32200
  }
@@ -31504,8 +32205,8 @@ var AgentGUIDetailPane = memo5(function AgentGUIDetailPane2({
31504
32205
  isLoading: showTimelineSkeleton,
31505
32206
  loadingLabel: labels.loadingConversation,
31506
32207
  empty: conversationFlowEmpty,
31507
- onLinkAction,
31508
- onAuthLogin: onAgentProviderLogin,
32208
+ onLinkAction: stableLinkAction,
32209
+ onAuthLogin: authLogin,
31509
32210
  availableSkills: viewModel.availableSkills,
31510
32211
  workspaceAppIcons,
31511
32212
  labels: conversationFlowLabels
@@ -31517,63 +32218,15 @@ var AgentGUIDetailPane = memo5(function AgentGUIDetailPane2({
31517
32218
  AgentGUIBottomDockPane,
31518
32219
  {
31519
32220
  bottomDockRef,
31520
- activePrompt,
31521
- bottomDockActivePrompt,
32221
+ store: bottomDockStore,
32222
+ storeRevision: bottomDockStoreRevision,
31522
32223
  keyboardShortcutsEnabled: isActive,
31523
- inlineNoticeChrome,
31524
- sessionChrome,
31525
- isRespondingApproval: viewModel.isRespondingApproval,
31526
- composerProps: {
31527
- workspaceId: viewModel.workspaceId,
31528
- workspacePath: viewModel.workspacePath,
31529
- currentUserId: viewModel.currentUserId,
31530
- provider: viewModel.data.provider,
31531
- slashStatus,
31532
- draftPrompt: viewModel.draftPrompt,
31533
- availableCommands: viewModel.availableCommands,
31534
- hasCompactableContext: viewModel.hasSentUserMessage,
31535
- availableSkills: viewModel.availableSkills,
31536
- disabled: composerDisabled,
31537
- disabledReason: composerDisabledReason,
31538
- submitDisabled,
31539
- composerSettings: viewModel.composerSettings,
31540
- queuedPrompts: viewModel.queuedPrompts,
31541
- drainingQueuedPromptId: viewModel.drainingQueuedPromptId,
31542
- workspaceAppIcons,
31543
- canQueueWhileBusy,
31544
- placeholder: viewModel.hasSentUserMessage ? labels.followupPlaceholder : labels.initialPlaceholder,
31545
- showStopButton,
31546
- activePrompt: shouldLiftActivePromptAboveInlineNotice ? null : activePrompt,
31547
- activePromptKeyboardShortcutsEnabled: isActive,
31548
- composerFocusRequestSequence,
31549
- isActive,
31550
- promptImagesSupported: viewModel.promptImagesSupported,
31551
- showProjectSelector,
31552
- isInterrupting: viewModel.isInterrupting,
31553
- isSendingTurn: isComposerSending,
31554
- isSubmittingPrompt: viewModel.isRespondingApproval,
31555
- labels: composerLabels,
31556
- workspaceUserProjectI18n,
31557
- onDraftChange: actions.updateDraftPrompt,
31558
- onProjectPathChange: actions.updateSelectedProjectPath,
31559
- onSettingsChange: actions.updateComposerSettings,
31560
- onSubmit: actions.submitPrompt,
31561
- onPromptImagesUnsupported: actions.showPromptImagesUnsupported,
31562
- onSendQueuedPromptNext: actions.sendQueuedPromptNext,
31563
- onRemoveQueuedPrompt: actions.removeQueuedPrompt,
31564
- onEditQueuedPrompt: actions.editQueuedPrompt,
31565
- onInterruptCurrentTurn: handleInterruptCurrentTurn,
31566
- onSubmitInteractivePrompt: actions.submitInteractivePrompt,
31567
- onLinkAction,
31568
- onRequestWorkspaceReferences,
31569
- richTextAtProviders
31570
- },
31571
32224
  chromeLabels,
31572
32225
  promptLabels: interactivePromptLabels,
31573
- onSubmitApprovalOption: actions.submitApprovalOption,
31574
- onRetryActivation: actions.retryActivation,
31575
- onAuthLogin: onAgentProviderLogin,
31576
- onContinueInNewConversation: actions.continueInNewConversation,
32226
+ onSubmitApprovalOption: submitApprovalOption,
32227
+ onRetryActivation: retryActivation,
32228
+ onAuthLogin: authLogin,
32229
+ onContinueInNewConversation: continueInNewConversation,
31577
32230
  onSubmitBottomDockInteractivePrompt: submitBottomDockInteractivePrompt
31578
32231
  }
31579
32232
  ) : null
@@ -31657,6 +32310,25 @@ function AgentRunPathInfo({ path }) {
31657
32310
  )
31658
32311
  ] });
31659
32312
  }
32313
+ function useStableEventCallback(callback) {
32314
+ const callbackRef = useRef20(callback);
32315
+ useLayoutEffect6(() => {
32316
+ callbackRef.current = callback;
32317
+ }, [callback]);
32318
+ return useCallback18((...args) => callbackRef.current(...args), []);
32319
+ }
32320
+ function useOptionalStableEventCallback(callback) {
32321
+ const callbackRef = useRef20(callback);
32322
+ useLayoutEffect6(() => {
32323
+ callbackRef.current = callback;
32324
+ }, [callback]);
32325
+ return useMemo15(() => {
32326
+ if (callback == null) {
32327
+ return void 0;
32328
+ }
32329
+ return (...args) => callbackRef.current?.(...args);
32330
+ }, [callback != null]);
32331
+ }
31660
32332
  var AgentGUIEmptyHeroPane = memo5(function AgentGUIEmptyHeroPane2({
31661
32333
  provider,
31662
32334
  emptyLabel,
@@ -31716,12 +32388,9 @@ function EmptyHeroTitle({
31716
32388
  }
31717
32389
  var AgentGUIBottomDockPane = memo5(function AgentGUIBottomDockPane2({
31718
32390
  bottomDockRef,
31719
- bottomDockActivePrompt,
32391
+ store,
32392
+ storeRevision: _storeRevision,
31720
32393
  keyboardShortcutsEnabled,
31721
- inlineNoticeChrome,
31722
- sessionChrome,
31723
- isRespondingApproval,
31724
- composerProps,
31725
32394
  chromeLabels,
31726
32395
  promptLabels,
31727
32396
  onSubmitApprovalOption,
@@ -31731,6 +32400,14 @@ var AgentGUIBottomDockPane = memo5(function AgentGUIBottomDockPane2({
31731
32400
  onSubmitBottomDockInteractivePrompt
31732
32401
  }) {
31733
32402
  "use memo";
32403
+ const state = useSnapshot(store);
32404
+ const {
32405
+ bottomDockActivePrompt,
32406
+ composerProps,
32407
+ inlineNoticeChrome,
32408
+ isRespondingApproval,
32409
+ sessionChrome
32410
+ } = state;
31734
32411
  return /* @__PURE__ */ jsxs56(
31735
32412
  "div",
31736
32413
  {
@@ -31805,6 +32482,7 @@ var AgentGUIConversationRailPane = memo5(
31805
32482
  labels,
31806
32483
  workspaceUserProjectI18n,
31807
32484
  uiLanguage,
32485
+ showProjectSelector,
31808
32486
  createConversationDisabled,
31809
32487
  openclawGateway,
31810
32488
  isCollapsed,
@@ -31942,6 +32620,7 @@ var AgentGUIConversationRailPane = memo5(
31942
32620
  /* @__PURE__ */ jsx86(
31943
32621
  ScrollArea,
31944
32622
  {
32623
+ scrollbarMode: "native",
31945
32624
  className: "min-h-0 flex-1 [&_[data-orientation=vertical][data-slot=scroll-area-scrollbar]]:opacity-100",
31946
32625
  viewportRef: conversationListRef,
31947
32626
  viewportClassName: AgentGUINode_styles_default.conversationList,
@@ -31954,7 +32633,7 @@ var AgentGUIConversationRailPane = memo5(
31954
32633
  const projectPath = section.kind === "project" ? section.project?.path ?? "" : "";
31955
32634
  const projectLabel = section.kind === "project" ? section.label : "";
31956
32635
  const isProjectSection = section.kind === "project";
31957
- const showProjectRailHeader = !conversationQuery.trim() && section.kind !== "pinned" && (sectionIndex === 0 || groupedConversations[sectionIndex - 1]?.kind === "pinned");
32636
+ const showProjectRailHeader = showProjectSelector && !conversationQuery.trim() && section.kind !== "pinned" && (sectionIndex === 0 || groupedConversations[sectionIndex - 1]?.kind === "pinned");
31958
32637
  const isSectionCollapsed = isProjectSection && collapsedProjectSectionIds.has(section.id);
31959
32638
  const projectConversationCount = projectPath ? conversations.filter(
31960
32639
  (conversation) => normalizeConversationRailProjectPath(
@@ -33006,7 +33685,7 @@ function normalizeSlashStatusModelName(value) {
33006
33685
  return value?.trim().toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "") ?? "";
33007
33686
  }
33008
33687
  function agentGuiStateEquals(left, right) {
33009
- return left === right || left.provider === right.provider && left.lastActiveAgentSessionId === right.lastActiveAgentSessionId && (left.pendingHandoff?.requestId ?? null) === (right.pendingHandoff?.requestId ?? null) && (left.pendingHandoff?.prompt ?? null) === (right.pendingHandoff?.prompt ?? null) && (left.pendingHandoff?.title ?? null) === (right.pendingHandoff?.title ?? null) && left.lastActiveConversationTitle === right.lastActiveConversationTitle && left.conversationRailWidthPx === right.conversationRailWidthPx && left.conversationRailCollapsed === right.conversationRailCollapsed && (left.composerOverrides?.model ?? null) === (right.composerOverrides?.model ?? null) && (left.composerOverrides?.reasoningEffort ?? null) === (right.composerOverrides?.reasoningEffort ?? null) && (left.composerOverrides?.planMode ?? null) === (right.composerOverrides?.planMode ?? null) && (left.composerOverrides?.permissionModeId ?? null) === (right.composerOverrides?.permissionModeId ?? null) && composerOverridesByProviderEqual(
33688
+ return left === right || left.provider === right.provider && left.lastActiveAgentSessionId === right.lastActiveAgentSessionId && left.lastActiveConversationTitle === right.lastActiveConversationTitle && left.conversationRailWidthPx === right.conversationRailWidthPx && left.conversationRailCollapsed === right.conversationRailCollapsed && (left.composerOverrides?.model ?? null) === (right.composerOverrides?.model ?? null) && (left.composerOverrides?.reasoningEffort ?? null) === (right.composerOverrides?.reasoningEffort ?? null) && (left.composerOverrides?.planMode ?? null) === (right.composerOverrides?.planMode ?? null) && (left.composerOverrides?.permissionModeId ?? null) === (right.composerOverrides?.permissionModeId ?? null) && composerOverridesByProviderEqual(
33010
33689
  left.composerOverridesByProvider,
33011
33690
  right.composerOverridesByProvider
33012
33691
  );
@@ -33073,7 +33752,6 @@ var AgentGUINode = memo6(function AgentGUINode2({
33073
33752
  () => createWorkspaceUserProjectI18nRuntime(i18n),
33074
33753
  [i18n]
33075
33754
  );
33076
- const handledHandoffRequestIdRef = useRef22(null);
33077
33755
  const handleLinkAction = useCallback20(
33078
33756
  (action) => {
33079
33757
  onLinkAction?.(
@@ -33091,6 +33769,15 @@ var AgentGUINode = memo6(function AgentGUINode2({
33091
33769
  },
33092
33770
  [onAgentProviderLogin, state.provider]
33093
33771
  );
33772
+ const handleWorkspaceFileReferencesAdded = useCallback20(
33773
+ (references) => {
33774
+ onWorkspaceFileReferencesAdded?.({
33775
+ provider: state.provider,
33776
+ references
33777
+ });
33778
+ },
33779
+ [onWorkspaceFileReferencesAdded, state.provider]
33780
+ );
33094
33781
  const handleDataChange = useCallback20(
33095
33782
  (updater) => {
33096
33783
  onUpdateNode(updater);
@@ -33176,25 +33863,6 @@ var AgentGUINode = memo6(function AgentGUINode2({
33176
33863
  onDataChange: handleDataChange,
33177
33864
  onShowMessage
33178
33865
  });
33179
- useEffect23(() => {
33180
- const pendingHandoff = state.pendingHandoff;
33181
- const requestId = pendingHandoff?.requestId?.trim() ?? "";
33182
- const prompt = pendingHandoff?.prompt?.trim() ?? "";
33183
- if (!requestId || !prompt || handledHandoffRequestIdRef.current === requestId) {
33184
- return;
33185
- }
33186
- handledHandoffRequestIdRef.current = requestId;
33187
- actions.createConversation();
33188
- actions.updateDraftPrompt(prompt);
33189
- onUpdateNode(
33190
- (current) => current.pendingHandoff?.requestId === requestId ? { ...current, pendingHandoff: null } : current
33191
- );
33192
- }, [
33193
- actions.createConversation,
33194
- actions.updateDraftPrompt,
33195
- onUpdateNode,
33196
- state.pendingHandoff
33197
- ]);
33198
33866
  const fallbackAgentTitle = t("sidebar.fallbackAgentLabel");
33199
33867
  const activeProvider = viewModel.activeConversation?.provider ?? state.provider;
33200
33868
  const displayProviderLabel = resolveAgentGUIProviderDisplayLabel(
@@ -33630,10 +34298,7 @@ var AgentGUINode = memo6(function AgentGUINode2({
33630
34298
  ),
33631
34299
  detailMinWidthPx: AGENT_GUI_DETAIL_MIN_WIDTH_PX,
33632
34300
  uiLanguage: locale,
33633
- onWorkspaceFileReferencesAdded: onWorkspaceFileReferencesAdded ? (references) => onWorkspaceFileReferencesAdded({
33634
- provider: state.provider,
33635
- references
33636
- }) : void 0,
34301
+ onWorkspaceFileReferencesAdded: onWorkspaceFileReferencesAdded ? handleWorkspaceFileReferencesAdded : void 0,
33637
34302
  onConversationRailWidthChanged: handleConversationRailWidthChanged,
33638
34303
  labels,
33639
34304
  workspaceUserProjectI18n,