@tutti-os/agent-gui 0.0.11 → 0.0.12

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.
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  mergeWorkspaceAgentActivityDurableAndOverlayMessages,
19
19
  normalizeOptionalWorkspaceAgentStatus,
20
20
  selectWorkspaceAgentActivityOverlayMessages
21
- } from "./chunk-ITMKZRCT.js";
21
+ } from "./chunk-PKCJR6GC.js";
22
22
  import {
23
23
  AgentInteractivePromptSurface,
24
24
  MANAGED_AGENT_ICON_FALLBACK_URL,
@@ -29,7 +29,7 @@ import {
29
29
  normalizeManagedAgentProvider,
30
30
  user_avatar_placeholder_default,
31
31
  workspaceAgentActivityStatusLabel
32
- } from "./chunk-CGBRAWTD.js";
32
+ } from "./chunk-Y5O7BVGU.js";
33
33
  import "./chunk-4ASBZ4X7.js";
34
34
  import {
35
35
  resolveWorkspaceAgentSessionSortTimeUnixMs
@@ -58,7 +58,7 @@ import {
58
58
  skillDescriptionForDisplay,
59
59
  skillTriggerForPrefix,
60
60
  useProjectedAgentConversation
61
- } from "./chunk-ZEFETOTS.js";
61
+ } from "./chunk-72YSPOHX.js";
62
62
  import "./chunk-XJ34OIEQ.js";
63
63
  import {
64
64
  AgentActivityHostProvider,
@@ -75,11 +75,11 @@ import {
75
75
  useAgentActivitySnapshot,
76
76
  useAgentHostApi,
77
77
  useOptionalAgentActivityRuntime
78
- } from "./chunk-QTZALZIV.js";
78
+ } from "./chunk-PONEQEJ5.js";
79
79
  import "./chunk-TYGL25EL.js";
80
80
  import {
81
81
  AGENT_GUI_MENTION_PROVIDER_IDS
82
- } from "./chunk-77HBKGHF.js";
82
+ } from "./chunk-KCC3GNPB.js";
83
83
  import {
84
84
  normalizeAgentTitleText
85
85
  } from "./chunk-GCBDIQDX.js";
@@ -90,7 +90,7 @@ import {
90
90
  getActiveUiLanguage,
91
91
  translate,
92
92
  useTranslation
93
- } from "./chunk-B7K776UD.js";
93
+ } from "./chunk-Y3AQGWJA.js";
94
94
  import {
95
95
  resolveAgentMentionFileThumbnailUrl,
96
96
  resolveAgentMentionFileVisualKind
@@ -2219,7 +2219,14 @@ function WorkspaceNodeWindow({
2219
2219
  }
2220
2220
 
2221
2221
  // agent-gui/agentGuiNode/controller/useAgentGUINodeController.ts
2222
- import { useCallback as useCallback4, useEffect as useEffect4, useMemo as useMemo4, useRef as useRef4, useState as useState4 } from "react";
2222
+ import {
2223
+ useCallback as useCallback4,
2224
+ useEffect as useEffect4,
2225
+ useId,
2226
+ useMemo as useMemo4,
2227
+ useRef as useRef4,
2228
+ useState as useState4
2229
+ } from "react";
2223
2230
  import { toast } from "@tutti-os/ui-system";
2224
2231
  import {
2225
2232
  resolveAgentActivityCapability as resolveAgentActivityCapability2,
@@ -2922,9 +2929,10 @@ function messageRole(message) {
2922
2929
  return null;
2923
2930
  }
2924
2931
  function messageText(message) {
2932
+ const payloadDisplayPrompt = typeof message.payload?.displayPrompt === "string" ? message.payload.displayPrompt : "";
2925
2933
  const payloadContent = typeof message.payload?.content === "string" ? message.payload.content : "";
2926
2934
  const payloadText = typeof message.payload?.text === "string" ? message.payload.text : "";
2927
- return (payloadContent || payloadText).replace(/\s+/g, " ").trim();
2935
+ return (payloadDisplayPrompt || payloadText || payloadContent).replace(/\s+/g, " ").trim();
2928
2936
  }
2929
2937
  function compareMessagesAscending(left, right) {
2930
2938
  const leftTime = left.occurredAtUnixMs ?? left.completedAtUnixMs ?? left.startedAtUnixMs ?? 0;
@@ -2953,9 +2961,10 @@ function timelineItemRole(item) {
2953
2961
  return null;
2954
2962
  }
2955
2963
  function timelineItemText(item) {
2964
+ const payloadDisplayPrompt = typeof item.payload?.displayPrompt === "string" ? item.payload.displayPrompt : "";
2956
2965
  const payloadContent = typeof item.payload?.content === "string" ? item.payload.content : "";
2957
2966
  const payloadText = typeof item.payload?.text === "string" ? item.payload.text : "";
2958
- return (payloadContent || item.content || payloadText).replace(/\s+/g, " ").trim();
2967
+ return (payloadDisplayPrompt || payloadText || item.content || payloadContent).replace(/\s+/g, " ").trim();
2959
2968
  }
2960
2969
  function compareTimelineItemsAscending(left, right) {
2961
2970
  const leftTime = left.occurredAtUnixMs ?? left.createdAtUnixMs ?? 0;
@@ -3039,7 +3048,7 @@ function isOptimisticUserPromptItem(item) {
3039
3048
  return item.payload?.__agentGuiOptimisticPrompt === true;
3040
3049
  }
3041
3050
  function normalizedTimelineItemBody(item) {
3042
- const content = typeof item.content === "string" && item.content.trim() ? item.content : typeof item.payload?.content === "string" && item.payload.content.trim() ? item.payload.content : typeof item.payload?.text === "string" ? item.payload.text : "";
3051
+ const content = typeof item.payload?.displayPrompt === "string" && item.payload.displayPrompt.trim() ? item.payload.displayPrompt : typeof item.payload?.text === "string" && item.payload.text.trim() ? item.payload.text : typeof item.payload?.content === "string" && item.payload.content.trim() ? item.payload.content : typeof item.content === "string" ? item.content : "";
3043
3052
  return content.trim();
3044
3053
  }
3045
3054
  function timelineItemMergeKey(item) {
@@ -3357,6 +3366,7 @@ function messageText2(message) {
3357
3366
  const payload = normalizedPayload(message.payload);
3358
3367
  const title = messagePayloadString(message, "title");
3359
3368
  return firstNonEmptyString(
3369
+ stringValue(payload.displayPrompt),
3360
3370
  stringValue(payload.text),
3361
3371
  stringValue(payload.content),
3362
3372
  stringValue(payload.message),
@@ -4508,6 +4518,7 @@ var requestIdByQueryKey = /* @__PURE__ */ new Map();
4508
4518
  var localCreatedConversationIdsByQueryKey = /* @__PURE__ */ new Map();
4509
4519
  var deletedConversationIdsByQueryKey = /* @__PURE__ */ new Map();
4510
4520
  var runtimeRefreshUnsubscribeByWorkspaceId = /* @__PURE__ */ new Map();
4521
+ var activeConversationIdsByQueryKey = /* @__PURE__ */ new Map();
4511
4522
  function normalizeQuery(input) {
4512
4523
  const workspaceId = input.workspaceId.trim();
4513
4524
  const userId = input.userId.trim();
@@ -4599,6 +4610,22 @@ function getQueryState(query) {
4599
4610
  const queryKey = createAgentGUIConversationListQueryKey(normalized);
4600
4611
  return snapshot2.statesByQueryKey[queryKey] ?? null;
4601
4612
  }
4613
+ function hasActiveConversationOwner(queryKey, conversationId) {
4614
+ const normalizedConversationId = conversationId.trim();
4615
+ if (!normalizedConversationId) {
4616
+ return false;
4617
+ }
4618
+ const activeByOwner = activeConversationIdsByQueryKey.get(queryKey);
4619
+ if (!activeByOwner) {
4620
+ return false;
4621
+ }
4622
+ for (const activeConversationId of activeByOwner.values()) {
4623
+ if (activeConversationId === normalizedConversationId) {
4624
+ return true;
4625
+ }
4626
+ }
4627
+ return false;
4628
+ }
4602
4629
  function describeError(error) {
4603
4630
  if (error instanceof Error) {
4604
4631
  return error.message;
@@ -4719,7 +4746,7 @@ function areConversationProjectsEqual(left, right) {
4719
4746
  if (!left || !right) {
4720
4747
  return false;
4721
4748
  }
4722
- return left.id === right.id && left.path === right.path && left.label === right.label;
4749
+ return left.id === right.id && left.path === right.path && left.label === right.label && left.createdAtUnixMs === right.createdAtUnixMs && left.updatedAtUnixMs === right.updatedAtUnixMs && left.lastUsedAtUnixMs === right.lastUsedAtUnixMs;
4723
4750
  }
4724
4751
  function areConversationsEqual(left, right) {
4725
4752
  return left.id === right.id && left.userId === right.userId && left.provider === right.provider && left.title === right.title && left.status === right.status && left.cwd === right.cwd && areConversationProjectsEqual(left.project, right.project) && left.sortTimeUnixMs === right.sortTimeUnixMs && left.updatedAtUnixMs === right.updatedAtUnixMs && (left.pinnedAtUnixMs ?? 0) === (right.pinnedAtUnixMs ?? 0) && left.hasUnreadCompletion === right.hasUnreadCompletion && areConversationTitleFallbacksEqual(
@@ -5087,6 +5114,91 @@ function updateAgentGUIConversationListConversations(query, updater) {
5087
5114
  };
5088
5115
  });
5089
5116
  }
5117
+ function setAgentGUIConversationListActiveConversation(input) {
5118
+ const ownerKey = input.ownerKey.trim();
5119
+ if (!ownerKey) {
5120
+ return;
5121
+ }
5122
+ const queryState = ensureQueryState(input.query);
5123
+ if (!queryState) {
5124
+ return;
5125
+ }
5126
+ const conversationId = input.conversationId?.trim() ?? "";
5127
+ const activeByOwner = activeConversationIdsByQueryKey.get(queryState.queryKey) ?? /* @__PURE__ */ new Map();
5128
+ const previousConversationId = activeByOwner.get(ownerKey) ?? null;
5129
+ if (!conversationId) {
5130
+ if (previousConversationId === null) {
5131
+ return;
5132
+ }
5133
+ activeByOwner.delete(ownerKey);
5134
+ if (activeByOwner.size === 0) {
5135
+ activeConversationIdsByQueryKey.delete(queryState.queryKey);
5136
+ } else {
5137
+ activeConversationIdsByQueryKey.set(queryState.queryKey, activeByOwner);
5138
+ }
5139
+ return;
5140
+ }
5141
+ if (previousConversationId !== conversationId) {
5142
+ activeByOwner.set(ownerKey, conversationId);
5143
+ activeConversationIdsByQueryKey.set(queryState.queryKey, activeByOwner);
5144
+ }
5145
+ clearAgentGUIConversationUnreadCompletion({
5146
+ query: input.query,
5147
+ conversationId
5148
+ });
5149
+ }
5150
+ function clearAgentGUIConversationUnreadCompletion(input) {
5151
+ const conversationId = input.conversationId.trim();
5152
+ if (!conversationId) {
5153
+ return;
5154
+ }
5155
+ updateAgentGUIConversationListConversations(input.query, (current) => {
5156
+ let changed = false;
5157
+ const next = current.map((conversation) => {
5158
+ if (conversation.id !== conversationId || conversation.hasUnreadCompletion !== true) {
5159
+ return conversation;
5160
+ }
5161
+ changed = true;
5162
+ return {
5163
+ ...conversation,
5164
+ hasUnreadCompletion: false
5165
+ };
5166
+ });
5167
+ return changed ? next : current;
5168
+ });
5169
+ }
5170
+ function markAgentGUIConversationCompletionObserved(input) {
5171
+ const conversationId = input.conversationId.trim();
5172
+ if (!conversationId) {
5173
+ return;
5174
+ }
5175
+ const queryState = ensureQueryState(input.query);
5176
+ if (!queryState) {
5177
+ return;
5178
+ }
5179
+ const shouldMarkUnread = !hasActiveConversationOwner(
5180
+ queryState.queryKey,
5181
+ conversationId
5182
+ );
5183
+ updateAgentGUIConversationListConversations(input.query, (current) => {
5184
+ let changed = false;
5185
+ const next = current.map((conversation) => {
5186
+ if (conversation.id !== conversationId) {
5187
+ return conversation;
5188
+ }
5189
+ const hasUnreadCompletion = conversation.status === "completed" && shouldMarkUnread;
5190
+ if (conversation.hasUnreadCompletion === hasUnreadCompletion) {
5191
+ return conversation;
5192
+ }
5193
+ changed = true;
5194
+ return {
5195
+ ...conversation,
5196
+ hasUnreadCompletion
5197
+ };
5198
+ });
5199
+ return changed ? next : current;
5200
+ });
5201
+ }
5090
5202
  function upsertLocalCreatedAgentGUIConversation(input) {
5091
5203
  const queryState = ensureQueryState(input.query);
5092
5204
  if (!queryState) {
@@ -5369,6 +5481,7 @@ function composerSettingsSupportFromOptions(composerOptions, sessionRuntimeConte
5369
5481
  return {
5370
5482
  model: composerOptions?.modelConfigurable ?? false,
5371
5483
  reasoning: composerOptions?.reasoningConfigurable ?? false,
5484
+ speed: composerOptions?.speedConfigurable ?? false,
5372
5485
  permission: composerOptions?.permissionConfig?.configurable ?? false,
5373
5486
  plan: resolveAgentActivityCapability("planMode", {
5374
5487
  composerOptions,
@@ -5436,6 +5549,7 @@ var AGENT_SESSION_ACTIVE_TURN_CONFLICT_MESSAGE = "agent session already has an a
5436
5549
  var AGENT_PROVIDER_SESSION_NOT_FOUND_FALLBACK_MESSAGE = "The previous agent session can no longer be restored.";
5437
5550
  var AGENT_RESUME_SESSION_NOT_LOCAL_FALLBACK_MESSAGE = "The previous agent session is not available on this machine.";
5438
5551
  var AGENT_GUI_CAUGHT_ERROR_STACK_LIMIT = 4e3;
5552
+ var SELECTED_SESSION_NOT_FOUND_RETRY_DELAY_MS = 150;
5439
5553
  function reportAgentGUIRuntimeError(input) {
5440
5554
  const reportDiagnostic = input.runtime.reportDiagnostic;
5441
5555
  if (!reportDiagnostic) {
@@ -5998,6 +6112,9 @@ function normalizeConfigOptionValue(value) {
5998
6112
  function reasoningConfigOptionIdForProvider(provider) {
5999
6113
  return provider === "codex" ? "reasoning_effort" : "effort";
6000
6114
  }
6115
+ function speedConfigOptionIdForProvider(provider) {
6116
+ return provider === "codex" ? "service_tier" : "fast";
6117
+ }
6001
6118
  function composerSettingOptionsFromActivity(options) {
6002
6119
  return options.map((option) => ({ ...option }));
6003
6120
  }
@@ -6019,6 +6136,15 @@ function reasoningSelectionFromComposerOptions(options, currentValue) {
6019
6136
  currentValue
6020
6137
  };
6021
6138
  }
6139
+ function speedSelectionFromComposerOptions(options, currentValue) {
6140
+ if (!options) {
6141
+ return null;
6142
+ }
6143
+ return {
6144
+ options: composerSettingOptionsFromActivity(options.speeds ?? []),
6145
+ currentValue
6146
+ };
6147
+ }
6022
6148
  function providerSkillsFromComposerOptions(options) {
6023
6149
  return options?.skills.map((skill) => ({ ...skill })) ?? [];
6024
6150
  }
@@ -6066,6 +6192,9 @@ function resolveEffectiveComposerSettings(input) {
6066
6192
  reasoningEffort: normalizeOptionalText(
6067
6193
  input.settings.reasoningEffort
6068
6194
  ) ?? null,
6195
+ speed: normalizeOptionalText(
6196
+ input.settings.speed
6197
+ ) ?? null,
6069
6198
  planMode: Boolean(input.settings.planMode),
6070
6199
  permissionModeId: normalizePermissionModeId(input.settings.permissionModeId)
6071
6200
  };
@@ -6074,6 +6203,9 @@ function runtimeConfigKeyForSetting(provider, setting) {
6074
6203
  if (setting === "reasoningEffort") {
6075
6204
  return reasoningConfigOptionIdForProvider(provider);
6076
6205
  }
6206
+ if (setting === "speed") {
6207
+ return speedConfigOptionIdForProvider(provider);
6208
+ }
6077
6209
  if (setting === "permissionModeId") {
6078
6210
  return "mode";
6079
6211
  }
@@ -6086,6 +6218,9 @@ function shouldUpdateRuntimeConfigOption(provider, id, setting) {
6086
6218
  if (setting === "permissionModeId") {
6087
6219
  return id === "mode";
6088
6220
  }
6221
+ if (setting === "speed") {
6222
+ return id === speedConfigOptionIdForProvider(provider) || id === "service_tier" || id === "speed" || id === "fast";
6223
+ }
6089
6224
  return id === reasoningConfigOptionIdForProvider(provider) || id === "model_reasoning_effort" || id === "reasoning_effort" || id === "effort";
6090
6225
  }
6091
6226
  function mergeRuntimeContextComposerSettings(provider, runtimeContext, settings) {
@@ -6105,6 +6240,11 @@ function mergeRuntimeContextComposerSettings(provider, runtimeContext, settings)
6105
6240
  runtimeConfigPatch[runtimeConfigKeyForSetting(provider, "reasoningEffort")] = value;
6106
6241
  optionPatches.push({ setting: "reasoningEffort", value });
6107
6242
  }
6243
+ if (settings.speed !== void 0) {
6244
+ const value = normalizeOptionalText(settings.speed);
6245
+ runtimeConfigPatch[runtimeConfigKeyForSetting(provider, "speed")] = value;
6246
+ optionPatches.push({ setting: "speed", value });
6247
+ }
6108
6248
  if (settings.permissionModeId !== void 0) {
6109
6249
  const value = normalizeOptionalText(settings.permissionModeId);
6110
6250
  runtimeConfigPatch[runtimeConfigKeyForSetting(provider, "permissionModeId")] = value;
@@ -6144,7 +6284,7 @@ function cloneComposerSettings(settings) {
6144
6284
  return { ...settings };
6145
6285
  }
6146
6286
  function sameComposerSettings(left, right) {
6147
- 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);
6287
+ return (left?.model ?? null) === (right?.model ?? null) && (left?.reasoningEffort ?? null) === (right?.reasoningEffort ?? null) && (left?.speed ?? null) === (right?.speed ?? null) && Boolean(left?.planMode) === Boolean(right?.planMode) && (left?.permissionModeId ?? null) === (right?.permissionModeId ?? null);
6148
6288
  }
6149
6289
  function useStableComposerSettings(settings) {
6150
6290
  const settingsRef = useRef4(null);
@@ -6181,6 +6321,21 @@ function promptRequestId(prompt) {
6181
6321
  function conversationBusyStatus2(status) {
6182
6322
  return status === "working" || status === "waiting";
6183
6323
  }
6324
+ function stringArraysEqual(first, second) {
6325
+ if (!first || !second) {
6326
+ return first === second;
6327
+ }
6328
+ return first.length === second.length && first.every((value, index) => value === second[index]);
6329
+ }
6330
+ function useStableStringArrayByValue(values) {
6331
+ const valuesRef = useRef4(null);
6332
+ const currentValues = valuesRef.current;
6333
+ if (!stringArraysEqual(currentValues, values)) {
6334
+ valuesRef.current = values;
6335
+ return values;
6336
+ }
6337
+ return currentValues ?? values;
6338
+ }
6184
6339
  function agentSessionStatusBusy(input) {
6185
6340
  const normalized = normalizeOptionalWorkspaceAgentStatus(input);
6186
6341
  return normalized?.kind === "working" || normalized?.kind === "waiting";
@@ -6210,6 +6365,9 @@ function buildNodeDefaultComposerSettings(data, options) {
6210
6365
  reasoningEffort: normalizeOptionalText(
6211
6366
  composerOverrides.reasoningEffort
6212
6367
  ) ?? options?.defaultReasoningEffort ?? null,
6368
+ speed: normalizeOptionalText(
6369
+ composerOverrides.speed
6370
+ ) ?? options?.defaultSpeed ?? null,
6213
6371
  planMode: Boolean(composerOverrides.planMode),
6214
6372
  permissionModeId: normalizePermissionModeId(
6215
6373
  composerOverrides.permissionModeId
@@ -6225,6 +6383,7 @@ function composerSupportForProvider(provider) {
6225
6383
  model: true,
6226
6384
  permission: provider === "claude-code" || provider === "codex",
6227
6385
  reasoning: true,
6386
+ speed: provider === "claude-code" || provider === "codex",
6228
6387
  plan: false
6229
6388
  };
6230
6389
  }
@@ -6232,6 +6391,7 @@ function composerSupportForProvider(provider) {
6232
6391
  model: false,
6233
6392
  permission: provider === "nexight",
6234
6393
  reasoning: false,
6394
+ speed: false,
6235
6395
  plan: false
6236
6396
  };
6237
6397
  }
@@ -6249,6 +6409,7 @@ function nodeDataFromComposerSettings(current, settings) {
6249
6409
  const composerOverrides = {
6250
6410
  model: normalizeOptionalText(settings.model),
6251
6411
  reasoningEffort: normalizeOptionalText(settings.reasoningEffort),
6412
+ speed: normalizeOptionalText(settings.speed),
6252
6413
  planMode: Boolean(settings.planMode),
6253
6414
  permissionModeId: normalizePermissionModeId(settings.permissionModeId)
6254
6415
  };
@@ -6365,6 +6526,11 @@ function mergeSessionControlStatePatch(current, patch) {
6365
6526
  patch.settings.reasoningEffort
6366
6527
  );
6367
6528
  }
6529
+ if (patch.settings.speed !== void 0) {
6530
+ nextSettings.speed = normalizeOptionalText(
6531
+ patch.settings.speed
6532
+ );
6533
+ }
6368
6534
  if (patch.settings.planMode !== void 0) {
6369
6535
  nextSettings.planMode = Boolean(patch.settings.planMode);
6370
6536
  }
@@ -6582,6 +6748,7 @@ function useAgentGUINodeController({
6582
6748
  const agentActivityRuntime = useAgentActivityRuntime();
6583
6749
  const agentHostApi = useAgentHostApi();
6584
6750
  const agentActivitySnapshot = useAgentActivitySnapshot(workspaceId);
6751
+ const generatedControllerOwnerKey = useId();
6585
6752
  const conversationListQuery = useMemo4(() => {
6586
6753
  const userId = currentUserId?.trim() ?? "";
6587
6754
  const provider = data.provider?.trim() ?? "";
@@ -6599,6 +6766,7 @@ function useAgentGUINodeController({
6599
6766
  conversationListQuery
6600
6767
  );
6601
6768
  const pendingCreateOwnerKey = nodeId?.trim() ?? "";
6769
+ const conversationListActiveOwnerKey = pendingCreateOwnerKey || generatedControllerOwnerKey;
6602
6770
  const resolvePendingCreateConversationId = useCallback4(
6603
6771
  () => conversationListQuery && pendingCreateOwnerKey ? getAgentGUIConversationCreatePending({
6604
6772
  query: conversationListQuery,
@@ -6860,12 +7028,24 @@ function useAgentGUINodeController({
6860
7028
  },
6861
7029
  []
6862
7030
  );
6863
- const backgroundBusyConversationIds = useMemo4(
7031
+ const projectedBackgroundBusyConversationIds = useMemo4(
6864
7032
  () => conversations.filter(
6865
7033
  (conversation2) => conversation2.id !== activeConversationId && conversationBusyStatus2(conversation2.status)
6866
- ).map((conversation2) => conversation2.id),
7034
+ ).map((conversation2) => conversation2.id).sort(),
7035
+ [activeConversationId, conversations]
7036
+ );
7037
+ const backgroundBusyConversationIds = useStableStringArrayByValue(
7038
+ projectedBackgroundBusyConversationIds
7039
+ );
7040
+ const projectedReleasedBackgroundConversationIds = useMemo4(
7041
+ () => conversations.filter(
7042
+ (conversation2) => conversation2.id === activeConversationId || conversation2.status === "completed" || conversation2.status === "failed" || conversation2.status === "canceled"
7043
+ ).map((conversation2) => conversation2.id).sort(),
6867
7044
  [activeConversationId, conversations]
6868
7045
  );
7046
+ const releasedBackgroundConversationIds = useStableStringArrayByValue(
7047
+ projectedReleasedBackgroundConversationIds
7048
+ );
6869
7049
  const [
6870
7050
  retainedBackgroundConversationIds,
6871
7051
  setRetainedBackgroundConversationIds
@@ -6874,26 +7054,24 @@ function useAgentGUINodeController({
6874
7054
  if (previewMode) {
6875
7055
  return;
6876
7056
  }
7057
+ if (backgroundBusyConversationIds.length === 0 && releasedBackgroundConversationIds.length === 0) {
7058
+ return;
7059
+ }
6877
7060
  setRetainedBackgroundConversationIds((current) => {
6878
7061
  const next = new Set(current);
6879
7062
  for (const conversationId of backgroundBusyConversationIds) {
6880
7063
  next.add(conversationId);
6881
7064
  }
6882
- for (const conversation2 of conversations) {
6883
- if (conversation2.id === activeConversationId || conversation2.status === "completed" || conversation2.status === "failed" || conversation2.status === "canceled") {
6884
- next.delete(conversation2.id);
6885
- }
7065
+ for (const conversationId of releasedBackgroundConversationIds) {
7066
+ next.delete(conversationId);
6886
7067
  }
6887
7068
  const nextIds = [...next].sort();
6888
- return nextIds.length === current.length && nextIds.every(
6889
- (conversationId, index) => conversationId === current[index]
6890
- ) ? current : nextIds;
7069
+ return stringArraysEqual(nextIds, current) ? current : nextIds;
6891
7070
  });
6892
7071
  }, [
6893
- activeConversationId,
6894
7072
  backgroundBusyConversationIds,
6895
- conversations,
6896
- previewMode
7073
+ previewMode,
7074
+ releasedBackgroundConversationIds
6897
7075
  ]);
6898
7076
  const backgroundWatchedConversationIds = useMemo4(
6899
7077
  () => previewMode ? [] : [
@@ -6955,7 +7133,19 @@ function useAgentGUINodeController({
6955
7133
  const stateReloadInFlightRef = useRef4(false);
6956
7134
  const stateReloadQueuedRef = useRef4(false);
6957
7135
  const stateReloadTargetSessionIdRef = useRef4(null);
7136
+ const selectedConversationMessageLoadSeqRef = useRef4(0);
7137
+ const selectedConversationPendingMessageLoadIdsRef = useRef4(
7138
+ /* @__PURE__ */ new Set()
7139
+ );
7140
+ const selectedConversationInitialStateLoadedIdsRef = useRef4(
7141
+ /* @__PURE__ */ new Set()
7142
+ );
7143
+ const selectedConversationInitialMessagesLoadedIdsRef = useRef4(
7144
+ /* @__PURE__ */ new Set()
7145
+ );
6958
7146
  const stateReloadCauseRef = useRef4(null);
7147
+ const selectedConversationNotFoundRetryIdsRef = useRef4(/* @__PURE__ */ new Set());
7148
+ const selectedConversationNotFoundRetryTimerRef = useRef4(null);
6959
7149
  const sessionStateSnapshotCauseBySessionIdRef = useRef4({});
6960
7150
  const blockedActivityStreamStateReloadSessionIdsRef = useRef4(
6961
7151
  /* @__PURE__ */ new Set()
@@ -7050,6 +7240,7 @@ function useAgentGUINodeController({
7050
7240
  if (snapshotConversations.length === 0) {
7051
7241
  return;
7052
7242
  }
7243
+ const completedConversationIds = /* @__PURE__ */ new Set();
7053
7244
  updateConversationList((current) => {
7054
7245
  const currentById = new Map(
7055
7246
  current.map((conversation2) => [conversation2.id, conversation2])
@@ -7063,7 +7254,7 @@ function useAgentGUINodeController({
7063
7254
  if (!existing) {
7064
7255
  return {
7065
7256
  ...conversation2,
7066
- hasUnreadCompletion: conversation2.hasUnreadCompletion ?? (conversation2.status === "completed" && activeConversationIdRef.current !== conversation2.id)
7257
+ hasUnreadCompletion: conversation2.hasUnreadCompletion ?? false
7067
7258
  };
7068
7259
  }
7069
7260
  const titleFields = hasPromptConversationTitle2(existing) && isWorkspaceAgentUntitledTask(conversation2.title) ? {
@@ -7076,11 +7267,14 @@ function useAgentGUINodeController({
7076
7267
  const incomingWouldSettleBusyStatus = conversationBusyStatus2(existing.status) && !conversationBusyStatus2(conversation2.status);
7077
7268
  const shouldKeepExistingStatus = existing.updatedAtUnixMs > conversation2.updatedAtUnixMs && incomingWouldSettleBusyStatus;
7078
7269
  const status = shouldKeepExistingStatus ? existing.status : conversation2.status;
7270
+ if (status === "completed" && existing.status !== "completed") {
7271
+ completedConversationIds.add(conversation2.id);
7272
+ }
7079
7273
  const syncState = conversation2.syncState && shouldApplySyncState(existing.syncState, conversation2.syncState) && !syncStateRenderFieldsEqual(
7080
7274
  existing.syncState,
7081
7275
  conversation2.syncState
7082
7276
  ) ? conversation2.syncState : existing.syncState;
7083
- const hasUnreadCompletion = conversation2.status === "completed" ? activeConversationIdRef.current !== conversation2.id : existing.hasUnreadCompletion ?? false;
7277
+ const hasUnreadCompletion = conversation2.status === "completed" ? existing.hasUnreadCompletion ?? conversation2.hasUnreadCompletion ?? false : false;
7084
7278
  return {
7085
7279
  ...existing,
7086
7280
  ...conversation2,
@@ -7101,6 +7295,12 @@ function useAgentGUINodeController({
7101
7295
  isNoProjectPath
7102
7296
  });
7103
7297
  });
7298
+ for (const conversationId of completedConversationIds) {
7299
+ markAgentGUIConversationCompletionObserved({
7300
+ query: conversationListQuery,
7301
+ conversationId
7302
+ });
7303
+ }
7104
7304
  }, [
7105
7305
  agentActivitySnapshot,
7106
7306
  conversationListQuery,
@@ -7136,7 +7336,6 @@ function useAgentGUINodeController({
7136
7336
  })[0] ?? current : current
7137
7337
  );
7138
7338
  }, [
7139
- conversations,
7140
7339
  isNoProjectPath,
7141
7340
  previewMode,
7142
7341
  setTransientConversation,
@@ -7248,6 +7447,28 @@ function useAgentGUINodeController({
7248
7447
  useEffect4(() => {
7249
7448
  activeConversationIdRef.current = activeConversationId;
7250
7449
  }, [activeConversationId]);
7450
+ useEffect4(() => {
7451
+ if (previewMode || !conversationListQuery) {
7452
+ return void 0;
7453
+ }
7454
+ setAgentGUIConversationListActiveConversation({
7455
+ query: conversationListQuery,
7456
+ ownerKey: conversationListActiveOwnerKey,
7457
+ conversationId: activeConversationId
7458
+ });
7459
+ return () => {
7460
+ setAgentGUIConversationListActiveConversation({
7461
+ query: conversationListQuery,
7462
+ ownerKey: conversationListActiveOwnerKey,
7463
+ conversationId: null
7464
+ });
7465
+ };
7466
+ }, [
7467
+ activeConversationId,
7468
+ conversationListActiveOwnerKey,
7469
+ conversationListQuery,
7470
+ previewMode
7471
+ ]);
7251
7472
  useEffect4(() => {
7252
7473
  selectedProjectPathRef.current = selectedProjectPath;
7253
7474
  }, [selectedProjectPath]);
@@ -7301,6 +7522,58 @@ function useAgentGUINodeController({
7301
7522
  },
7302
7523
  []
7303
7524
  );
7525
+ const clearSelectedConversationNotFoundRetry = useCallback4(() => {
7526
+ if (selectedConversationNotFoundRetryTimerRef.current !== null) {
7527
+ window.clearTimeout(selectedConversationNotFoundRetryTimerRef.current);
7528
+ selectedConversationNotFoundRetryTimerRef.current = null;
7529
+ }
7530
+ }, []);
7531
+ const clearSelectedConversationNotFoundRetryWhenInitialLoadsSettled = useCallback4((agentSessionId) => {
7532
+ const normalizedAgentSessionId = agentSessionId.trim();
7533
+ if (normalizedAgentSessionId && selectedConversationInitialStateLoadedIdsRef.current.has(
7534
+ normalizedAgentSessionId
7535
+ ) && selectedConversationInitialMessagesLoadedIdsRef.current.has(
7536
+ normalizedAgentSessionId
7537
+ )) {
7538
+ selectedConversationNotFoundRetryIdsRef.current.delete(
7539
+ normalizedAgentSessionId
7540
+ );
7541
+ selectedConversationInitialStateLoadedIdsRef.current.delete(
7542
+ normalizedAgentSessionId
7543
+ );
7544
+ selectedConversationInitialMessagesLoadedIdsRef.current.delete(
7545
+ normalizedAgentSessionId
7546
+ );
7547
+ }
7548
+ }, []);
7549
+ const markSelectedConversationDetailPending = useCallback4(
7550
+ (agentSessionId) => {
7551
+ const normalizedAgentSessionId = agentSessionId.trim();
7552
+ if (!normalizedAgentSessionId) {
7553
+ return null;
7554
+ }
7555
+ clearSelectedConversationNotFoundRetry();
7556
+ selectedConversationNotFoundRetryIdsRef.current.add(
7557
+ normalizedAgentSessionId
7558
+ );
7559
+ selectedConversationInitialStateLoadedIdsRef.current.delete(
7560
+ normalizedAgentSessionId
7561
+ );
7562
+ selectedConversationInitialMessagesLoadedIdsRef.current.delete(
7563
+ normalizedAgentSessionId
7564
+ );
7565
+ selectedConversationPendingMessageLoadIdsRef.current.add(
7566
+ normalizedAgentSessionId
7567
+ );
7568
+ setIsLoadingMessages(true);
7569
+ setAgentSessionViewMessagesLoading(
7570
+ sessionViewRef(normalizedAgentSessionId),
7571
+ true
7572
+ );
7573
+ return normalizedAgentSessionId;
7574
+ },
7575
+ [clearSelectedConversationNotFoundRetry, sessionViewRef]
7576
+ );
7304
7577
  const updateSelectedProjectPath = useCallback4(
7305
7578
  (path, metadata) => {
7306
7579
  const normalizedPath = normalizeProjectDraftPath(path);
@@ -7369,6 +7642,9 @@ function useAgentGUINodeController({
7369
7642
  activatedConversationIdsRef.current.delete(previous);
7370
7643
  void activation.unactivate(previous);
7371
7644
  }
7645
+ if (previous !== normalized) {
7646
+ markSelectedConversationDetailPending(normalized);
7647
+ }
7372
7648
  if (pendingNewConversationId && pendingNewConversationId !== normalized) {
7373
7649
  activatedConversationIdsRef.current.delete(pendingNewConversationId);
7374
7650
  void activation.unactivate(pendingNewConversationId);
@@ -7391,11 +7667,12 @@ function useAgentGUINodeController({
7391
7667
  reloadDetail: true
7392
7668
  });
7393
7669
  }
7394
- updateConversationList(
7395
- (current) => current.map(
7396
- (conversation2) => conversation2.id === normalized ? { ...conversation2, hasUnreadCompletion: false } : conversation2
7397
- )
7398
- );
7670
+ if (conversationListQuery) {
7671
+ clearAgentGUIConversationUnreadCompletion({
7672
+ query: conversationListQuery,
7673
+ conversationId: normalized
7674
+ });
7675
+ }
7399
7676
  if (transientConversationRef.current?.id === normalized) {
7400
7677
  setTransientConversation(
7401
7678
  (current) => current?.id === normalized ? { ...current, hasUnreadCompletion: false } : current
@@ -7403,7 +7680,12 @@ function useAgentGUINodeController({
7403
7680
  }
7404
7681
  persistActiveConversation(normalized);
7405
7682
  },
7406
- [activation, persistActiveConversation]
7683
+ [
7684
+ activation,
7685
+ conversationListQuery,
7686
+ markSelectedConversationDetailPending,
7687
+ persistActiveConversation
7688
+ ]
7407
7689
  );
7408
7690
  const syncConversationListProjection = useCallback4(
7409
7691
  async (_preferredSessionId) => {
@@ -7421,6 +7703,62 @@ function useAgentGUINodeController({
7421
7703
  },
7422
7704
  [conversationListQuery, persistActiveConversation]
7423
7705
  );
7706
+ const scheduleSelectedConversationNotFoundRetry = useCallback4(
7707
+ (agentSessionId) => {
7708
+ const normalizedAgentSessionId = agentSessionId.trim();
7709
+ if (!normalizedAgentSessionId || !selectedConversationNotFoundRetryIdsRef.current.has(
7710
+ normalizedAgentSessionId
7711
+ )) {
7712
+ return false;
7713
+ }
7714
+ setAgentSessionViewError(sessionViewRef(normalizedAgentSessionId), null);
7715
+ setAgentSessionViewMessagesLoading(
7716
+ sessionViewRef(normalizedAgentSessionId),
7717
+ true
7718
+ );
7719
+ if (activeConversationIdRef.current === normalizedAgentSessionId) {
7720
+ setIsLoadingMessages(true);
7721
+ }
7722
+ if (conversationListQuery) {
7723
+ scheduleAgentGUIConversationListProjection(
7724
+ conversationListQuery,
7725
+ "projection-sync"
7726
+ );
7727
+ }
7728
+ selectedConversationPendingMessageLoadIdsRef.current.add(
7729
+ normalizedAgentSessionId
7730
+ );
7731
+ clearSelectedConversationNotFoundRetry();
7732
+ selectedConversationNotFoundRetryTimerRef.current = window.setTimeout(
7733
+ () => {
7734
+ selectedConversationNotFoundRetryTimerRef.current = null;
7735
+ selectedConversationNotFoundRetryIdsRef.current.delete(
7736
+ normalizedAgentSessionId
7737
+ );
7738
+ selectedConversationInitialStateLoadedIdsRef.current.delete(
7739
+ normalizedAgentSessionId
7740
+ );
7741
+ selectedConversationInitialMessagesLoadedIdsRef.current.delete(
7742
+ normalizedAgentSessionId
7743
+ );
7744
+ if (!isMountedRef.current || activeConversationIdRef.current !== normalizedAgentSessionId) {
7745
+ return;
7746
+ }
7747
+ reloadSelectedConversationRef.current(normalizedAgentSessionId, {
7748
+ reloadConversations: false,
7749
+ reloadDetail: true
7750
+ });
7751
+ },
7752
+ SELECTED_SESSION_NOT_FOUND_RETRY_DELAY_MS
7753
+ );
7754
+ return true;
7755
+ },
7756
+ [
7757
+ clearSelectedConversationNotFoundRetry,
7758
+ conversationListQuery,
7759
+ sessionViewRef
7760
+ ]
7761
+ );
7424
7762
  useEffect4(() => {
7425
7763
  const requestedConversationId = data.lastActiveAgentSessionId?.trim() ?? "";
7426
7764
  const requestedConversationExists = requestedConversationId !== "" ? resolveConversationSummaryById(
@@ -7564,7 +7902,7 @@ function useAgentGUINodeController({
7564
7902
  false
7565
7903
  );
7566
7904
  },
7567
- [agentActivityRuntime, sessionViewRef, updateConversationList, workspaceId]
7905
+ [sessionViewRef, updateConversationList]
7568
7906
  );
7569
7907
  const applySessionStateSnapshot = useCallback4(
7570
7908
  (snapshot3, cause) => {
@@ -7616,11 +7954,17 @@ function useAgentGUINodeController({
7616
7954
  source: cause?.source
7617
7955
  }
7618
7956
  ),
7619
- hasUnreadCompletion: status === "completed" && activeConversationIdRef.current !== agentSessionId
7957
+ hasUnreadCompletion: status === "completed" ? conversation2.hasUnreadCompletion ?? false : false
7620
7958
  };
7621
7959
  return nextConversation;
7622
7960
  })
7623
7961
  );
7962
+ if (nextStatus === "completed" && conversationListQuery) {
7963
+ markAgentGUIConversationCompletionObserved({
7964
+ query: conversationListQuery,
7965
+ conversationId: agentSessionId
7966
+ });
7967
+ }
7624
7968
  const transient = transientConversationRef.current;
7625
7969
  if (transient?.id === agentSessionId) {
7626
7970
  const timelineItems = projectAgentGUIMessagesToTimelineItems(
@@ -7653,7 +7997,7 @@ function useAgentGUINodeController({
7653
7997
  });
7654
7998
  }
7655
7999
  },
7656
- [sessionViewRef, setTransientConversation]
8000
+ [conversationListQuery, sessionViewRef, setTransientConversation]
7657
8001
  );
7658
8002
  useEffect4(() => {
7659
8003
  const snapshot3 = activeSessionView?.controlState ?? null;
@@ -7699,6 +8043,12 @@ function useAgentGUINodeController({
7699
8043
  return;
7700
8044
  }
7701
8045
  clearFailedLiveState(agentSessionId);
8046
+ selectedConversationInitialStateLoadedIdsRef.current.add(
8047
+ agentSessionId
8048
+ );
8049
+ clearSelectedConversationNotFoundRetryWhenInitialLoadsSettled(
8050
+ agentSessionId
8051
+ );
7702
8052
  blockedActivityStreamStateReloadSessionIdsRef.current.delete(
7703
8053
  agentSessionId
7704
8054
  );
@@ -7718,6 +8068,14 @@ function useAgentGUINodeController({
7718
8068
  return;
7719
8069
  }
7720
8070
  const errorCode = getAgentGUIErrorCode(error);
8071
+ if (isSessionNotFoundErrorCode(errorCode) && cause?.source === "conversation-selected" && scheduleSelectedConversationNotFoundRetry(agentSessionId)) {
8072
+ return;
8073
+ }
8074
+ if (cause?.source === "conversation-selected") {
8075
+ selectedConversationNotFoundRetryIdsRef.current.delete(
8076
+ agentSessionId
8077
+ );
8078
+ }
7721
8079
  reportAgentGUIRuntimeError({
7722
8080
  agentSessionId,
7723
8081
  context: {
@@ -7788,14 +8146,101 @@ function useAgentGUINodeController({
7788
8146
  }
7789
8147
  },
7790
8148
  [
8149
+ agentActivityRuntime,
7791
8150
  applySessionStateSnapshot,
7792
8151
  clearFailedLiveState,
8152
+ clearSelectedConversationNotFoundRetryWhenInitialLoadsSettled,
7793
8153
  markFailedLiveState,
7794
8154
  persistActiveConversation,
8155
+ scheduleSelectedConversationNotFoundRetry,
7795
8156
  workspaceId,
8157
+ conversationListQuery,
7796
8158
  sessionViewRef
7797
8159
  ]
7798
8160
  );
8161
+ const loadSelectedConversationMessages = useCallback4(
8162
+ async (agentSessionId) => {
8163
+ const normalizedAgentSessionId = agentSessionId.trim();
8164
+ if (!normalizedAgentSessionId) {
8165
+ return;
8166
+ }
8167
+ const requestId = ++selectedConversationMessageLoadSeqRef.current;
8168
+ setDetailError(null);
8169
+ setAgentSessionViewError(sessionViewRef(normalizedAgentSessionId), null);
8170
+ setAgentSessionViewMessagesLoading(
8171
+ sessionViewRef(normalizedAgentSessionId),
8172
+ true
8173
+ );
8174
+ if (activeConversationIdRef.current === normalizedAgentSessionId) {
8175
+ setIsLoadingMessages(true);
8176
+ }
8177
+ try {
8178
+ const page = await agentActivityRuntime.listSessionMessages({
8179
+ workspaceId,
8180
+ agentSessionId: normalizedAgentSessionId
8181
+ });
8182
+ if (!isMountedRef.current || activeConversationIdRef.current !== normalizedAgentSessionId || selectedConversationMessageLoadSeqRef.current !== requestId) {
8183
+ return;
8184
+ }
8185
+ selectedConversationInitialMessagesLoadedIdsRef.current.add(
8186
+ normalizedAgentSessionId
8187
+ );
8188
+ clearSelectedConversationNotFoundRetryWhenInitialLoadsSettled(
8189
+ normalizedAgentSessionId
8190
+ );
8191
+ const durableMessages = mergeWorkspaceAgentMessages(
8192
+ [],
8193
+ agentActivitySnapshotRef.current.sessionMessagesById[normalizedAgentSessionId] ?? []
8194
+ );
8195
+ const currentOverlayMessages = getAgentSessionView(sessionViewRef(normalizedAgentSessionId))?.overlayMessages ?? [];
8196
+ const localMessages = mergeWorkspaceAgentMessages(
8197
+ currentOverlayMessages,
8198
+ page.messages
8199
+ );
8200
+ const overlayMessages = selectWorkspaceAgentActivityOverlayMessages({
8201
+ durableMessages,
8202
+ localMessages
8203
+ });
8204
+ setAgentSessionViewOverlayMessages(
8205
+ sessionViewRef(normalizedAgentSessionId),
8206
+ overlayMessages
8207
+ );
8208
+ refreshMessagesFromSnapshot(normalizedAgentSessionId);
8209
+ } catch (error) {
8210
+ if (!isMountedRef.current || activeConversationIdRef.current !== normalizedAgentSessionId || selectedConversationMessageLoadSeqRef.current !== requestId) {
8211
+ return;
8212
+ }
8213
+ const errorCode = getAgentGUIErrorCode(error);
8214
+ if (isSessionNotFoundErrorCode(errorCode) && scheduleSelectedConversationNotFoundRetry(normalizedAgentSessionId)) {
8215
+ return;
8216
+ }
8217
+ selectedConversationNotFoundRetryIdsRef.current.delete(
8218
+ normalizedAgentSessionId
8219
+ );
8220
+ reportAgentGUIRuntimeError({
8221
+ agentSessionId: normalizedAgentSessionId,
8222
+ error,
8223
+ phase: "load_session_messages",
8224
+ provider: dataRef.current.provider,
8225
+ runtime: agentActivityRuntime,
8226
+ workspaceId
8227
+ });
8228
+ setAgentSessionViewMessagesLoading(
8229
+ sessionViewRef(normalizedAgentSessionId),
8230
+ false
8231
+ );
8232
+ setIsLoadingMessages(false);
8233
+ }
8234
+ },
8235
+ [
8236
+ agentActivityRuntime,
8237
+ clearSelectedConversationNotFoundRetryWhenInitialLoadsSettled,
8238
+ refreshMessagesFromSnapshot,
8239
+ scheduleSelectedConversationNotFoundRetry,
8240
+ sessionViewRef,
8241
+ workspaceId
8242
+ ]
8243
+ );
7799
8244
  const reloadSelectedConversation = useCallback4(
7800
8245
  (agentSessionId, options) => {
7801
8246
  if (!agentSessionId) {
@@ -7811,7 +8256,15 @@ function useAgentGUINodeController({
7811
8256
  void syncConversationListProjection(agentSessionId);
7812
8257
  }
7813
8258
  if (options.reloadDetail) {
7814
- void refreshMessagesFromSnapshot(agentSessionId);
8259
+ const normalizedAgentSessionId = agentSessionId.trim();
8260
+ const hadPendingMessageLoad = selectedConversationPendingMessageLoadIdsRef.current.delete(
8261
+ normalizedAgentSessionId
8262
+ );
8263
+ if (hadPendingMessageLoad) {
8264
+ void loadSelectedConversationMessages(normalizedAgentSessionId);
8265
+ } else {
8266
+ void refreshMessagesFromSnapshot(normalizedAgentSessionId);
8267
+ }
7815
8268
  void loadSessionState(agentSessionId, {
7816
8269
  source: "conversation-selected"
7817
8270
  });
@@ -7819,6 +8272,7 @@ function useAgentGUINodeController({
7819
8272
  },
7820
8273
  [
7821
8274
  syncConversationListProjection,
8275
+ loadSelectedConversationMessages,
7822
8276
  refreshMessagesFromSnapshot,
7823
8277
  loadSessionState
7824
8278
  ]
@@ -8183,7 +8637,7 @@ function useAgentGUINodeController({
8183
8637
  status: nextStatus ?? conversation2.status,
8184
8638
  timelineItems
8185
8639
  });
8186
- const hasUnreadCompletion = status === "completed" && activeConversationIdRef.current !== agentSessionId;
8640
+ const hasUnreadCompletion = status === "completed" ? conversation2.hasUnreadCompletion ?? false : false;
8187
8641
  if (titleFields.title === conversation2.title && titleFields.titleFallback === conversation2.titleFallback && status === conversation2.status && hasUnreadCompletion === conversation2.hasUnreadCompletion && !clearedPendingSubmittedTurn) {
8188
8642
  return conversation2;
8189
8643
  }
@@ -8197,6 +8651,12 @@ function useAgentGUINodeController({
8197
8651
  });
8198
8652
  return changed ? next : current;
8199
8653
  });
8654
+ if (nextStatus === "completed" && conversationListQuery) {
8655
+ markAgentGUIConversationCompletionObserved({
8656
+ query: conversationListQuery,
8657
+ conversationId: agentSessionId
8658
+ });
8659
+ }
8200
8660
  const transient = transientConversationRef.current;
8201
8661
  if (transient?.id === agentSessionId) {
8202
8662
  const transientTitleFields = mergeConversationTitleUpdateFields(
@@ -8224,6 +8684,7 @@ function useAgentGUINodeController({
8224
8684
  setTransientConversation,
8225
8685
  statePatchErrorBySessionId,
8226
8686
  agentActivityRuntime,
8687
+ conversationListQuery,
8227
8688
  workspaceId
8228
8689
  ]
8229
8690
  );
@@ -8356,6 +8817,7 @@ function useAgentGUINodeController({
8356
8817
  isMountedRef.current = true;
8357
8818
  return () => {
8358
8819
  clearPendingSessionStateReload();
8820
+ clearSelectedConversationNotFoundRetry();
8359
8821
  const current = activeConversationIdRef.current;
8360
8822
  const pendingNewConversationId = startingConversationIdRef.current;
8361
8823
  isMountedRef.current = false;
@@ -8369,7 +8831,7 @@ function useAgentGUINodeController({
8369
8831
  void unactivateRef.current(pendingNewConversationId);
8370
8832
  }
8371
8833
  };
8372
- }, [clearPendingSessionStateReload]);
8834
+ }, [clearPendingSessionStateReload, clearSelectedConversationNotFoundRetry]);
8373
8835
  const startConversation = useCallback4(
8374
8836
  (initialContentInput) => {
8375
8837
  if (isCreatingConversation || data.provider === "openclaw" && openclawGateway?.status !== "ready") {
@@ -9452,6 +9914,7 @@ function useAgentGUINodeController({
9452
9914
  ...currentDefaults,
9453
9915
  model: sessionSettings2?.model ?? currentDefaults.model,
9454
9916
  reasoningEffort: sessionSettings2?.reasoningEffort ?? currentDefaults.reasoningEffort,
9917
+ speed: sessionSettings2?.speed ?? currentDefaults.speed,
9455
9918
  planMode: sessionSettings2?.planMode ?? currentDefaults.planMode,
9456
9919
  permissionModeId: sessionSettings2?.permissionModeId ?? currentDefaults.permissionModeId
9457
9920
  };
@@ -9459,6 +9922,7 @@ function useAgentGUINodeController({
9459
9922
  ...baseDefaultsFromSession,
9460
9923
  model: supportedNextSettings.model !== void 0 ? supportedNextSettings.model : baseDefaultsFromSession.model,
9461
9924
  reasoningEffort: supportedNextSettings.reasoningEffort !== void 0 ? supportedNextSettings.reasoningEffort : baseDefaultsFromSession.reasoningEffort,
9925
+ speed: supportedNextSettings.speed !== void 0 ? supportedNextSettings.speed : baseDefaultsFromSession.speed,
9462
9926
  planMode: supportedNextSettings.planMode ?? baseDefaultsFromSession.planMode,
9463
9927
  permissionModeId: supportedNextSettings.permissionModeId !== void 0 ? supportedNextSettings.permissionModeId : baseDefaultsFromSession.permissionModeId
9464
9928
  };
@@ -9482,6 +9946,8 @@ function useAgentGUINodeController({
9482
9946
  const currentModel = normalizeOptionalText(sessionSettings2?.model);
9483
9947
  const nextReasoningEffort = supportedNextSettings.reasoningEffort !== void 0 ? supportedNextSettings.reasoningEffort ?? null : void 0;
9484
9948
  const currentReasoningEffort = sessionSettings2?.reasoningEffort ?? null;
9949
+ const nextSpeed = supportedNextSettings.speed !== void 0 ? supportedNextSettings.speed ?? null : void 0;
9950
+ const currentSpeed = sessionSettings2?.speed ?? null;
9485
9951
  const nextPlanMode = supportedNextSettings.planMode;
9486
9952
  const currentPlanMode = resolveEffectivePlanModeFromStates({
9487
9953
  sessionPlanModeState: planModeStateFromSessionState(activeSessionState2),
@@ -9495,6 +9961,9 @@ function useAgentGUINodeController({
9495
9961
  if (nextReasoningEffort !== void 0 && nextReasoningEffort !== currentReasoningEffort) {
9496
9962
  sessionSettingsPatch.reasoningEffort = nextReasoningEffort;
9497
9963
  }
9964
+ if (nextSpeed !== void 0 && nextSpeed !== currentSpeed) {
9965
+ sessionSettingsPatch.speed = nextSpeed;
9966
+ }
9498
9967
  if (nextPlanMode !== void 0 && nextPlanMode !== currentPlanMode) {
9499
9968
  sessionSettingsPatch.planMode = nextPlanMode;
9500
9969
  }
@@ -9972,6 +10441,11 @@ function useAgentGUINodeController({
9972
10441
  }
9973
10442
  setIsDeletingConversation(true);
9974
10443
  setDetailError(null);
10444
+ if (activeConversationIdRef.current === target.id) {
10445
+ clearSelectedConversationNotFoundRetry();
10446
+ setIsLoadingMessages(true);
10447
+ setAgentSessionViewMessagesLoading(sessionViewRef(target.id), true);
10448
+ }
9975
10449
  void activation.unactivate(target.id).then(
9976
10450
  () => agentActivityRuntime.deleteSession({
9977
10451
  workspaceId,
@@ -10030,21 +10504,28 @@ function useAgentGUINodeController({
10030
10504
  return next;
10031
10505
  });
10032
10506
  deleteAgentSessionView(sessionViewRef(target.id));
10033
- updateConversationList((current) => {
10034
- const targetIndex = current.findIndex(
10035
- (conversation2) => conversation2.id === target.id
10036
- );
10037
- const next = current.filter(
10038
- (conversation2) => conversation2.id !== target.id
10039
- );
10040
- if (activeConversationIdRef.current === target.id) {
10041
- const nextActive = next[Math.max(0, targetIndex)]?.id ?? next[Math.max(0, targetIndex - 1)]?.id ?? null;
10042
- activeConversationIdRef.current = nextActive;
10043
- setActiveConversationId(nextActive);
10044
- persistActiveConversation(nextActive);
10507
+ const currentConversations = conversationsRef.current;
10508
+ const targetIndex = currentConversations.findIndex(
10509
+ (conversation2) => conversation2.id === target.id
10510
+ );
10511
+ const nextConversations = currentConversations.filter(
10512
+ (conversation2) => conversation2.id !== target.id
10513
+ );
10514
+ if (activeConversationIdRef.current === target.id) {
10515
+ const nextActive = nextConversations[Math.max(0, targetIndex)]?.id ?? nextConversations[Math.max(0, targetIndex - 1)]?.id ?? null;
10516
+ if (nextActive) {
10517
+ markSelectedConversationDetailPending(nextActive);
10518
+ } else {
10519
+ clearSelectedConversationNotFoundRetry();
10520
+ setIsLoadingMessages(false);
10045
10521
  }
10046
- return next;
10047
- });
10522
+ activeConversationIdRef.current = nextActive;
10523
+ setActiveConversationId(nextActive);
10524
+ persistActiveConversation(nextActive);
10525
+ }
10526
+ updateConversationList(
10527
+ (current) => current.filter((conversation2) => conversation2.id !== target.id)
10528
+ );
10048
10529
  setPendingDeleteConversation(null);
10049
10530
  }).catch((error) => {
10050
10531
  const message = getAgentGUIErrorMessage(error);
@@ -10058,17 +10539,25 @@ function useAgentGUINodeController({
10058
10539
  });
10059
10540
  toast.error(message);
10060
10541
  setDetailError(message);
10542
+ if (activeConversationIdRef.current === target.id) {
10543
+ setIsLoadingMessages(false);
10544
+ setAgentSessionViewMessagesLoading(sessionViewRef(target.id), false);
10545
+ }
10061
10546
  }).finally(() => {
10062
10547
  setIsDeletingConversation(false);
10063
10548
  });
10064
10549
  }, [
10065
10550
  activation,
10551
+ conversationListQuery,
10066
10552
  isDeletingConversation,
10067
10553
  pendingDeleteConversation,
10554
+ clearSelectedConversationNotFoundRetry,
10555
+ markSelectedConversationDetailPending,
10068
10556
  persistActiveConversation,
10069
10557
  workspaceId,
10070
10558
  sessionViewRef,
10071
- agentActivityRuntime
10559
+ agentActivityRuntime,
10560
+ updateConversationList
10072
10561
  ]);
10073
10562
  const confirmDeleteProjectConversations = useCallback4(
10074
10563
  (path) => {
@@ -10100,6 +10589,15 @@ function useAgentGUINodeController({
10100
10589
  setIsDeletingProjectConversations(true);
10101
10590
  setDetailError(null);
10102
10591
  setListError(null);
10592
+ const activeDeletedConversationId = activeConversationIdRef.current;
10593
+ if (activeDeletedConversationId && targetIds.has(activeDeletedConversationId)) {
10594
+ clearSelectedConversationNotFoundRetry();
10595
+ setIsLoadingMessages(true);
10596
+ setAgentSessionViewMessagesLoading(
10597
+ sessionViewRef(activeDeletedConversationId),
10598
+ true
10599
+ );
10600
+ }
10103
10601
  void Promise.all(
10104
10602
  targetConversations.map(async (conversation2) => {
10105
10603
  await activation.unactivate(conversation2.id);
@@ -10143,19 +10641,25 @@ function useAgentGUINodeController({
10143
10641
  setQueuedPromptRetryBlockBySessionId(
10144
10642
  (current) => omitConversationLocalState(current, targetIds)
10145
10643
  );
10146
- updateConversationList((current) => {
10147
- const next = current.filter(
10148
- (conversation2) => !targetIds.has(conversation2.id)
10149
- );
10150
- const currentActiveId = activeConversationIdRef.current;
10151
- if (currentActiveId && targetIds.has(currentActiveId)) {
10152
- const nextActive = next[0]?.id ?? null;
10153
- activeConversationIdRef.current = nextActive;
10154
- setActiveConversationId(nextActive);
10155
- persistActiveConversation(nextActive);
10644
+ const nextConversations = conversationsRef.current.filter(
10645
+ (conversation2) => !targetIds.has(conversation2.id)
10646
+ );
10647
+ const currentActiveId = activeConversationIdRef.current;
10648
+ if (currentActiveId && targetIds.has(currentActiveId)) {
10649
+ const nextActive = nextConversations[0]?.id ?? null;
10650
+ if (nextActive) {
10651
+ markSelectedConversationDetailPending(nextActive);
10652
+ } else {
10653
+ clearSelectedConversationNotFoundRetry();
10654
+ setIsLoadingMessages(false);
10156
10655
  }
10157
- return next;
10158
- });
10656
+ activeConversationIdRef.current = nextActive;
10657
+ setActiveConversationId(nextActive);
10658
+ persistActiveConversation(nextActive);
10659
+ }
10660
+ updateConversationList(
10661
+ (current) => current.filter((conversation2) => !targetIds.has(conversation2.id))
10662
+ );
10159
10663
  setPendingDeleteProjectConversations(null);
10160
10664
  }).catch((error) => {
10161
10665
  const message = getAgentGUIErrorMessage(error);
@@ -10173,6 +10677,13 @@ function useAgentGUINodeController({
10173
10677
  setListError(message);
10174
10678
  toast.error(message);
10175
10679
  setDetailError(message);
10680
+ if (activeDeletedConversationId && activeConversationIdRef.current === activeDeletedConversationId) {
10681
+ setIsLoadingMessages(false);
10682
+ setAgentSessionViewMessagesLoading(
10683
+ sessionViewRef(activeDeletedConversationId),
10684
+ false
10685
+ );
10686
+ }
10176
10687
  }).finally(() => {
10177
10688
  setIsDeletingProjectConversations(false);
10178
10689
  });
@@ -10181,7 +10692,9 @@ function useAgentGUINodeController({
10181
10692
  activation,
10182
10693
  agentActivityRuntime,
10183
10694
  conversationListQuery,
10695
+ clearSelectedConversationNotFoundRetry,
10184
10696
  isDeletingProjectConversations,
10697
+ markSelectedConversationDetailPending,
10185
10698
  pendingDeleteProjectConversations,
10186
10699
  persistActiveConversation,
10187
10700
  sessionViewRef,
@@ -10508,6 +11021,9 @@ function useAgentGUINodeController({
10508
11021
  const draftReasoningEffort = normalizeOptionalText(
10509
11022
  draftSettings.reasoningEffort
10510
11023
  );
11024
+ const draftSpeed = normalizeOptionalText(
11025
+ draftSettings.speed
11026
+ );
10511
11027
  const planImplementationTurnId = activeConversationId !== null && dataRef.current.provider === "codex" && composerSupport.plan && Boolean(draftSettings.planMode) && activeConversation?.status !== "working" ? latestPlanTurnId(activeTimelineItems) : null;
10512
11028
  planImplementationTurnIdRef.current = planImplementationTurnId;
10513
11029
  const planImplementationPromptVM = planImplementationTurnId !== null && activeConversationId !== null && dismissedPlanTurnIdBySessionId[activeConversationId] !== planImplementationTurnId ? planImplementationPromptFromPlanTurn(
@@ -10574,6 +11090,10 @@ function useAgentGUINodeController({
10574
11090
  () => modelSelectionFromComposerOptions(providerComposerOptions, draftModel),
10575
11091
  [draftModel, providerComposerOptions]
10576
11092
  );
11093
+ const activeSessionSpeedSelection = useMemo4(
11094
+ () => speedSelectionFromComposerOptions(providerComposerOptions, draftSpeed),
11095
+ [draftSpeed, providerComposerOptions]
11096
+ );
10577
11097
  const effectivePlanMode = useMemo4(
10578
11098
  () => resolveEffectivePlanModeFromStates({
10579
11099
  sessionPlanModeState,
@@ -10594,12 +11114,14 @@ function useAgentGUINodeController({
10594
11114
  const isSettingsLoading = !hasACPSettings;
10595
11115
  const selectedModelValue = draftModel;
10596
11116
  const selectedReasoningEffortValue = draftReasoningEffort;
11117
+ const selectedSpeedValue = draftSpeed;
10597
11118
  const selectedPermissionModeValue = normalizePermissionModeId(draftSettings.permissionModeId) ?? normalizePermissionModeId(permissionConfig?.defaultValue);
10598
11119
  return {
10599
11120
  sessionSettings,
10600
11121
  draftSettings: {
10601
11122
  model: draftModel,
10602
11123
  reasoningEffort: draftReasoningEffort,
11124
+ speed: draftSpeed,
10603
11125
  planMode: Boolean(draftSettings.planMode),
10604
11126
  permissionModeId: normalizePermissionModeId(
10605
11127
  draftSettings.permissionModeId
@@ -10608,21 +11130,25 @@ function useAgentGUINodeController({
10608
11130
  effectivePlanMode: composerSupport.plan ? effectivePlanMode : false,
10609
11131
  supportsModel: composerSupport.model,
10610
11132
  supportsReasoningEffort: composerSupport.reasoning,
11133
+ supportsSpeed: composerSupport.speed,
10611
11134
  supportsPermissionMode,
10612
11135
  supportsPlanMode: composerSupport.plan,
10613
11136
  isSettingsLoading,
10614
11137
  modelUnavailable: activeConversationId !== null && sessionSettings === null && composerSupport.model && draftModel === null,
10615
11138
  reasoningUnavailable: activeConversationId !== null && sessionSettings === null && composerSupport.reasoning && draftReasoningEffort === null,
11139
+ speedUnavailable: activeConversationId !== null && sessionSettings === null && composerSupport.speed && draftSpeed === null,
10616
11140
  permissionModeUnavailable: activeConversationId !== null && sessionSettings === null && supportsPermissionMode && selectedPermissionModeValue === null,
10617
11141
  planUnavailable: activeConversationId !== null && sessionSettings === null && composerSupport.plan && !effectivePlanMode,
10618
11142
  selectedModelValue,
10619
11143
  selectedReasoningEffortValue,
11144
+ selectedSpeedValue,
10620
11145
  selectedPermissionModeValue,
10621
11146
  permissionConfig,
10622
11147
  selectedProjectPath: activeConversationId !== null ? activeConversation?.cwd ?? null : selectedProjectPath,
10623
11148
  projectLocked: activeConversationId !== null,
10624
11149
  availableModels: composerSupport.model && hasOptionsSource && activeSessionModelSelection !== null ? activeSessionModelSelection.options : [],
10625
11150
  availableReasoningEfforts: composerSupport.reasoning && hasOptionsSource && activeSessionReasoningSelection !== null ? activeSessionReasoningSelection.options : [],
11151
+ availableSpeeds: composerSupport.speed && hasOptionsSource && activeSessionSpeedSelection !== null ? activeSessionSpeedSelection.options : [],
10626
11152
  availablePermissionModes: supportsPermissionMode ? permissionModeOptions(data.provider, permissionConfig) : []
10627
11153
  };
10628
11154
  }, [
@@ -10630,6 +11156,7 @@ function useAgentGUINodeController({
10630
11156
  activeConversation?.cwd,
10631
11157
  activeSessionModelSelection,
10632
11158
  activeSessionReasoningSelection,
11159
+ activeSessionSpeedSelection,
10633
11160
  draftSettings.permissionModeId,
10634
11161
  draftSettings.planMode,
10635
11162
  effectivePlanMode,
@@ -10639,7 +11166,8 @@ function useAgentGUINodeController({
10639
11166
  composerSupport,
10640
11167
  timelinePlanModeState,
10641
11168
  draftModel,
10642
- draftReasoningEffort
11169
+ draftReasoningEffort,
11170
+ draftSpeed
10643
11171
  ]);
10644
11172
  const stableCreateConversation = useStableControllerEventCallback(createConversation);
10645
11173
  const stableSelectConversation = useStableControllerEventCallback(selectConversation);
@@ -11002,7 +11530,7 @@ import {
11002
11530
  useLayoutEffect as useLayoutEffect4,
11003
11531
  useMemo as useMemo8,
11004
11532
  useRef as useRef12,
11005
- useState as useState9
11533
+ useState as useState10
11006
11534
  } from "react";
11007
11535
  import { useSnapshot } from "valtio";
11008
11536
  import { ChevronRight as ChevronRight2, Info, X as X2 } from "lucide-react";
@@ -12144,7 +12672,7 @@ import {
12144
12672
  useLayoutEffect as useLayoutEffect3,
12145
12673
  useMemo as useMemo7,
12146
12674
  useRef as useRef11,
12147
- useState as useState8,
12675
+ useState as useState9,
12148
12676
  Fragment as Fragment6
12149
12677
  } from "react";
12150
12678
  import { createPortal } from "react-dom";
@@ -12169,13 +12697,7 @@ import {
12169
12697
  } from "@tutti-os/ui-system";
12170
12698
 
12171
12699
  // agent-gui/agentGuiNode/AgentComposer.tsx
12172
- import {
12173
- AddIcon,
12174
- Select as Select2,
12175
- SelectContent as SelectContent2,
12176
- SelectItem as SelectItem2,
12177
- SelectTrigger as SelectTrigger2
12178
- } from "@tutti-os/ui-system";
12700
+ import { AddIcon, Select as Select2, SelectTrigger as SelectTrigger2 } from "@tutti-os/ui-system";
12179
12701
  import { X } from "lucide-react";
12180
12702
 
12181
12703
  // agent-gui/agentGuiNode/model/agentSlashCommands.ts
@@ -12272,6 +12794,7 @@ function labelForSlashCommand(command) {
12272
12794
  var CODEX_IMMEDIATE_SLASH_COMMANDS = /* @__PURE__ */ new Set(["init", "compact"]);
12273
12795
  var PROVIDER_NATIVE_IMMEDIATE_COMMANDS = /* @__PURE__ */ new Set(["compact"]);
12274
12796
  var LOCAL_STATUS_COMMANDS = /* @__PURE__ */ new Set(["status"]);
12797
+ var LOCAL_TOGGLE_SPEED_COMMANDS = /* @__PURE__ */ new Set(["fast"]);
12275
12798
  var CLAUDE_CODE_PROVIDER_NATIVE_COMMANDS = /* @__PURE__ */ new Set([
12276
12799
  "compact",
12277
12800
  "context",
@@ -12279,11 +12802,13 @@ var CLAUDE_CODE_PROVIDER_NATIVE_COMMANDS = /* @__PURE__ */ new Set([
12279
12802
  ]);
12280
12803
  var CODEX_FALLBACK_COMMANDS = [
12281
12804
  { name: "compact" },
12282
- { name: "status" }
12805
+ { name: "status" },
12806
+ { name: "fast" }
12283
12807
  ];
12284
12808
  var CLAUDE_CODE_FALLBACK_COMMANDS = [
12285
12809
  { name: "compact" },
12286
- { name: "status" }
12810
+ { name: "status" },
12811
+ { name: "fast" }
12287
12812
  ];
12288
12813
  function resolveSlashCommandsForProvider({
12289
12814
  provider,
@@ -12313,6 +12838,9 @@ function resolveSlashCommandSelectionEffect({
12313
12838
  if (isBlockedSlashCommand(provider, commandName)) {
12314
12839
  return { kind: "blockCommand" };
12315
12840
  }
12841
+ if (isLocalToggleSpeedCommand(provider, commandName)) {
12842
+ return { kind: "toggleSpeed" };
12843
+ }
12316
12844
  if (isLocalStatusCommand(provider, commandName)) {
12317
12845
  return { kind: "showStatus" };
12318
12846
  }
@@ -12352,6 +12880,9 @@ function resolveSlashCommandSubmitEffect({
12352
12880
  return null;
12353
12881
  }
12354
12882
  const commandName = normalizedCommandName(command);
12883
+ if (isLocalToggleSpeedCommand(provider, commandName)) {
12884
+ return { kind: "toggleSpeed" };
12885
+ }
12355
12886
  if (isLocalStatusCommand(provider, commandName)) {
12356
12887
  return { kind: "showStatus" };
12357
12888
  }
@@ -12384,6 +12915,9 @@ function fallbackCommandsForProvider(provider) {
12384
12915
  function isLocalStatusCommand(provider, commandName) {
12385
12916
  return (provider === "codex" || provider === "claude-code") && LOCAL_STATUS_COMMANDS.has(commandName);
12386
12917
  }
12918
+ function isLocalToggleSpeedCommand(provider, commandName) {
12919
+ return (provider === "codex" || provider === "claude-code") && LOCAL_TOGGLE_SPEED_COMMANDS.has(commandName);
12920
+ }
12387
12921
  function isProviderNativeImmediateCommand(provider, commandName) {
12388
12922
  if (PROVIDER_NATIVE_IMMEDIATE_COMMANDS.has(commandName)) {
12389
12923
  return true;
@@ -12883,28 +13417,218 @@ function AgentQueuedPromptPanel({
12883
13417
  }
12884
13418
 
12885
13419
  // agent-gui/agentGuiNode/AgentComposerSettingsMenus.tsx
12886
- import { useEffect as useEffect7, useMemo as useMemo5 } from "react";
13420
+ import { useEffect as useEffect7, useMemo as useMemo5, useState as useState7 } from "react";
12887
13421
  import {
12888
13422
  WorkspaceUserProjectSelect
12889
13423
  } from "@tutti-os/workspace-user-project/ui";
12890
13424
  import { prepareWorkspaceUserProjectSelection } from "@tutti-os/workspace-user-project/core";
12891
13425
  import {
13426
+ CheckIcon,
13427
+ ChevronDownIcon,
13428
+ DropdownMenu as DropdownMenu2,
13429
+ DropdownMenuContent as DropdownMenuContent2,
13430
+ DropdownMenuItem as DropdownMenuItem2,
13431
+ DropdownMenuLabel as DropdownMenuLabel2,
13432
+ DropdownMenuSeparator as DropdownMenuSeparator2,
13433
+ DropdownMenuSub as DropdownMenuSub2,
13434
+ DropdownMenuSubContent as DropdownMenuSubContent2,
13435
+ DropdownMenuSubTrigger as DropdownMenuSubTrigger2,
13436
+ DropdownMenuTrigger as DropdownMenuTrigger2,
12892
13437
  NewWorkspaceLinedIcon,
12893
13438
  RoomsHintIcon,
12894
13439
  Select,
12895
13440
  SelectContent,
12896
13441
  SelectItem,
12897
- SelectSplitColumn,
12898
- SelectSplitColumnItems,
12899
- SelectSplitColumnLabel,
12900
- SelectSplitDivider,
12901
- SelectSplitLayout,
12902
13442
  SelectTrigger,
12903
13443
  Tooltip as Tooltip2,
12904
13444
  TooltipContent as TooltipContent2,
12905
13445
  TooltipTrigger as TooltipTrigger2,
12906
13446
  cn as cn2
12907
13447
  } from "@tutti-os/ui-system";
13448
+
13449
+ // agent-gui/agentGuiNode/model/composerSettingsMenuModel.ts
13450
+ function buildComposerModelMenuModel(composerSettings, labels) {
13451
+ const modelItems = modelOptionsWithSelectedValue(composerSettings);
13452
+ const reasoningItems = reasoningOptionsWithSelectedValue(composerSettings);
13453
+ const speedItems = speedOptionsWithSelectedValue(composerSettings);
13454
+ const showModel = composerSettings.supportsModel && modelItems.length > 0 && !composerSettings.modelUnavailable;
13455
+ const showReasoning = composerSettings.supportsReasoningEffort && reasoningItems.length > 0 && !composerSettings.reasoningUnavailable;
13456
+ const showSpeed = composerSettings.supportsSpeed && speedItems.length > 0 && !composerSettings.speedUnavailable;
13457
+ const selectedModelValue = selectedComposerModelValue(composerSettings) ?? "";
13458
+ const selectedReasoningValue = selectedComposerReasoningValue(composerSettings) ?? "";
13459
+ const selectedSpeedValue = selectedComposerSpeedValue(composerSettings) ?? "";
13460
+ const modelLabel = resolveSelectedModelLabel(composerSettings, labels);
13461
+ const reasoningLabel = resolveSelectedReasoningLabel(
13462
+ composerSettings,
13463
+ labels
13464
+ );
13465
+ const disabled = composerSettings.isSettingsLoading || !showModel && !showReasoning && !showSpeed;
13466
+ return {
13467
+ disabled,
13468
+ trigger: {
13469
+ isFast: selectedSpeedValue === "fast",
13470
+ modelLabel,
13471
+ reasoningLabel,
13472
+ combinedLabel: modelLabel === reasoningLabel ? modelLabel : `${modelLabel} ${reasoningLabel}`.trim(),
13473
+ showCombined: modelLabel === reasoningLabel || reasoningLabel.length === 0
13474
+ },
13475
+ model: {
13476
+ show: showModel,
13477
+ selectedValue: selectedModelValue,
13478
+ selectedLabel: modelLabel,
13479
+ options: modelItems.map((option) => ({
13480
+ value: option.value,
13481
+ label: formatModelDisplayLabel(option.label),
13482
+ description: resolveModelDescription(option.description, labels)
13483
+ }))
13484
+ },
13485
+ reasoning: {
13486
+ show: showReasoning,
13487
+ selectedValue: selectedReasoningValue,
13488
+ selectedLabel: reasoningLabel,
13489
+ options: reasoningItems.map((option) => ({
13490
+ value: option.value,
13491
+ label: resolveReasoningOptionLabel(option.value, labels)
13492
+ }))
13493
+ },
13494
+ speed: {
13495
+ show: showSpeed,
13496
+ selectedValue: selectedSpeedValue,
13497
+ selectedLabel: resolveSpeedOptionLabel(selectedSpeedValue, labels),
13498
+ options: speedItems.map((option) => ({
13499
+ value: option.value,
13500
+ label: resolveSpeedOptionLabel(option.value, labels),
13501
+ description: option.description
13502
+ }))
13503
+ }
13504
+ };
13505
+ }
13506
+ function formatModelDisplayLabel(label) {
13507
+ const trimmed = label.trim();
13508
+ if (!trimmed) {
13509
+ return label;
13510
+ }
13511
+ return `${trimmed.charAt(0).toUpperCase()}${trimmed.slice(1)}`;
13512
+ }
13513
+ function resolveModelDescription(description, labels) {
13514
+ switch (description) {
13515
+ case "Frontier model for complex coding, research, and real-world work.":
13516
+ return labels.modelDescriptions.frontierComplexCoding;
13517
+ case "Strong model for everyday coding.":
13518
+ return labels.modelDescriptions.everydayCoding;
13519
+ case "Small, fast, and cost-efficient model for simpler coding tasks.":
13520
+ return labels.modelDescriptions.smallFastCostEfficient;
13521
+ case "Coding-optimized model.":
13522
+ return labels.modelDescriptions.codingOptimized;
13523
+ case "Ultra-fast coding model.":
13524
+ return labels.modelDescriptions.ultraFastCoding;
13525
+ case "Optimized for professional work and long-running agents.":
13526
+ return labels.modelDescriptions.professionalLongRunning;
13527
+ default:
13528
+ return description;
13529
+ }
13530
+ }
13531
+ function resolveSelectedModelLabel(composerSettings, labels) {
13532
+ const selectedValue = selectedComposerModelValue(composerSettings);
13533
+ const selected = modelOptionsWithSelectedValue(composerSettings).find(
13534
+ (option) => option.value === selectedValue
13535
+ );
13536
+ if (selected) {
13537
+ return formatModelDisplayLabel(selected.label);
13538
+ }
13539
+ if (composerSettings.modelUnavailable) {
13540
+ return labels.inheritedUnavailable;
13541
+ }
13542
+ if (composerSettings.isSettingsLoading) {
13543
+ return labels.loadingSettings;
13544
+ }
13545
+ const firstAvailableModel = composerSettings.availableModels[0]?.label;
13546
+ if (firstAvailableModel) {
13547
+ return formatModelDisplayLabel(firstAvailableModel);
13548
+ }
13549
+ return labels.defaultModel;
13550
+ }
13551
+ function resolveSelectedReasoningLabel(composerSettings, labels) {
13552
+ const selectedValue = selectedComposerReasoningValue(composerSettings);
13553
+ const selected = reasoningOptionsWithSelectedValue(composerSettings).find(
13554
+ (option) => option.value === selectedValue
13555
+ );
13556
+ if (selected) {
13557
+ const resolved = resolveReasoningOptionLabel(selected.value, labels);
13558
+ return resolved === selected.value && selected.label ? selected.label : resolved;
13559
+ }
13560
+ if (composerSettings.reasoningUnavailable) {
13561
+ return labels.inheritedUnavailable;
13562
+ }
13563
+ if (composerSettings.isSettingsLoading) {
13564
+ return "";
13565
+ }
13566
+ if (composerSettings.availableReasoningEfforts.length === 0) {
13567
+ return "";
13568
+ }
13569
+ return labels.reasoningLabel;
13570
+ }
13571
+ function resolveReasoningOptionLabel(value, labels) {
13572
+ switch (value) {
13573
+ case "minimal":
13574
+ return labels.reasoningOptionMinimal;
13575
+ case "low":
13576
+ return labels.reasoningOptionLow;
13577
+ case "medium":
13578
+ return labels.reasoningOptionMedium;
13579
+ case "high":
13580
+ return labels.reasoningOptionHigh;
13581
+ case "xhigh":
13582
+ return labels.reasoningOptionXHigh;
13583
+ default:
13584
+ return value;
13585
+ }
13586
+ }
13587
+ function resolveSpeedOptionLabel(value, labels) {
13588
+ switch (value) {
13589
+ case "standard":
13590
+ return labels.speedOptionStandard;
13591
+ case "fast":
13592
+ return labels.speedOptionFast;
13593
+ default:
13594
+ return value;
13595
+ }
13596
+ }
13597
+ function selectedComposerModelValue(composerSettings) {
13598
+ return composerSettings.selectedModelValue ?? composerSettings.draftSettings.model ?? null;
13599
+ }
13600
+ function selectedComposerReasoningValue(composerSettings) {
13601
+ return composerSettings.selectedReasoningEffortValue ?? composerSettings.draftSettings.reasoningEffort ?? null;
13602
+ }
13603
+ function selectedComposerSpeedValue(composerSettings) {
13604
+ return composerSettings.selectedSpeedValue ?? composerSettings.draftSettings.speed ?? null;
13605
+ }
13606
+ function modelOptionsWithSelectedValue(composerSettings) {
13607
+ return optionsWithSelectedValue(
13608
+ composerSettings.availableModels,
13609
+ selectedComposerModelValue(composerSettings)
13610
+ );
13611
+ }
13612
+ function reasoningOptionsWithSelectedValue(composerSettings) {
13613
+ return optionsWithSelectedValue(
13614
+ composerSettings.availableReasoningEfforts,
13615
+ selectedComposerReasoningValue(composerSettings)
13616
+ );
13617
+ }
13618
+ function speedOptionsWithSelectedValue(composerSettings) {
13619
+ return optionsWithSelectedValue(
13620
+ composerSettings.availableSpeeds,
13621
+ selectedComposerSpeedValue(composerSettings)
13622
+ );
13623
+ }
13624
+ function optionsWithSelectedValue(options, selectedValue) {
13625
+ if (!selectedValue || options.some((o) => o.value === selectedValue)) {
13626
+ return [...options];
13627
+ }
13628
+ return [{ value: selectedValue, label: selectedValue }, ...options];
13629
+ }
13630
+
13631
+ // agent-gui/agentGuiNode/AgentComposerSettingsMenus.tsx
12908
13632
  import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs9 } from "react/jsx-runtime";
12909
13633
  function AgentProjectDropdown({
12910
13634
  composerSettings,
@@ -12965,6 +13689,7 @@ function AgentPermissionModeDropdown({
12965
13689
  onSettingsChange
12966
13690
  }) {
12967
13691
  "use memo";
13692
+ const [isSelectOpen, setIsSelectOpen] = useState7(false);
12968
13693
  const availableOptions = composerSettings.availablePermissionModes ?? [];
12969
13694
  const planModeActive = Boolean(
12970
13695
  composerSettings.supportsPlanMode && (composerSettings.effectivePlanMode ?? composerSettings.draftSettings.planMode)
@@ -13003,8 +13728,10 @@ function AgentPermissionModeDropdown({
13003
13728
  return /* @__PURE__ */ jsxs9(
13004
13729
  Select,
13005
13730
  {
13731
+ open: isSelectOpen,
13006
13732
  value: selectedValue ?? void 0,
13007
13733
  disabled: selectDisabled,
13734
+ onOpenChange: setIsSelectOpen,
13008
13735
  onValueChange: applyPermissionModeId,
13009
13736
  children: [
13010
13737
  /* @__PURE__ */ jsx21(
@@ -13021,7 +13748,7 @@ function AgentPermissionModeDropdown({
13021
13748
  children: /* @__PURE__ */ jsx21("span", { className: "flex min-w-0 flex-1 items-center", children: /* @__PURE__ */ jsx21("span", { className: "truncate", children: triggerLabel }) })
13022
13749
  }
13023
13750
  ),
13024
- /* @__PURE__ */ jsx21(
13751
+ isSelectOpen ? /* @__PURE__ */ jsx21(
13025
13752
  SelectContent,
13026
13753
  {
13027
13754
  align: "end",
@@ -13047,7 +13774,7 @@ function AgentPermissionModeDropdown({
13047
13774
  option.value
13048
13775
  ))
13049
13776
  }
13050
- )
13777
+ ) : null
13051
13778
  ]
13052
13779
  }
13053
13780
  );
@@ -13129,111 +13856,6 @@ function PermissionModeOptionInfo({
13129
13856
  /* @__PURE__ */ jsx21(TooltipContent2, { side: "right", className: "max-w-[240px] whitespace-normal", children: description })
13130
13857
  ] });
13131
13858
  }
13132
- function resolveSelectedModelLabel(composerSettings, labels) {
13133
- const selectedValue = selectedComposerModelValue(composerSettings);
13134
- const selected = modelOptionsWithSelectedValue(composerSettings).find(
13135
- (option) => option.value === selectedValue
13136
- );
13137
- if (selected) {
13138
- return formatModelDisplayLabel(selected.label);
13139
- }
13140
- if (composerSettings.modelUnavailable) {
13141
- return labels.inheritedUnavailable;
13142
- }
13143
- if (composerSettings.isSettingsLoading) {
13144
- return labels.loadingSettings;
13145
- }
13146
- const firstAvailableModel = composerSettings.availableModels[0]?.label;
13147
- if (firstAvailableModel) {
13148
- return formatModelDisplayLabel(firstAvailableModel);
13149
- }
13150
- return labels.defaultModel;
13151
- }
13152
- function resolveSelectedReasoningLabel(composerSettings, labels) {
13153
- const selectedValue = selectedComposerReasoningValue(composerSettings);
13154
- const selected = reasoningOptionsWithSelectedValue(composerSettings).find(
13155
- (option) => option.value === selectedValue
13156
- );
13157
- if (selected) {
13158
- switch (selected.value) {
13159
- case "minimal":
13160
- return labels.reasoningOptionMinimal;
13161
- case "low":
13162
- return labels.reasoningOptionLow;
13163
- case "medium":
13164
- return labels.reasoningOptionMedium;
13165
- case "high":
13166
- return labels.reasoningOptionHigh;
13167
- case "xhigh":
13168
- return labels.reasoningOptionXHigh;
13169
- default:
13170
- return selected.label;
13171
- }
13172
- }
13173
- if (composerSettings.reasoningUnavailable) {
13174
- return labels.inheritedUnavailable;
13175
- }
13176
- if (composerSettings.isSettingsLoading) {
13177
- return "";
13178
- }
13179
- if (composerSettings.availableReasoningEfforts.length === 0) {
13180
- return "";
13181
- }
13182
- return labels.reasoningLabel;
13183
- }
13184
- function selectedComposerModelValue(composerSettings) {
13185
- return composerSettings.selectedModelValue ?? composerSettings.draftSettings.model ?? null;
13186
- }
13187
- function selectedComposerReasoningValue(composerSettings) {
13188
- return composerSettings.selectedReasoningEffortValue ?? composerSettings.draftSettings.reasoningEffort ?? null;
13189
- }
13190
- function modelOptionsWithSelectedValue(composerSettings) {
13191
- const selectedValue = selectedComposerModelValue(composerSettings);
13192
- if (!selectedValue || composerSettings.availableModels.some(
13193
- (option) => option.value === selectedValue
13194
- )) {
13195
- return composerSettings.availableModels;
13196
- }
13197
- return [
13198
- { value: selectedValue, label: selectedValue },
13199
- ...composerSettings.availableModels
13200
- ];
13201
- }
13202
- function reasoningOptionsWithSelectedValue(composerSettings) {
13203
- const selectedValue = selectedComposerReasoningValue(composerSettings);
13204
- if (!selectedValue || composerSettings.availableReasoningEfforts.some(
13205
- (option) => option.value === selectedValue
13206
- )) {
13207
- return composerSettings.availableReasoningEfforts;
13208
- }
13209
- return [
13210
- { value: selectedValue, label: selectedValue },
13211
- ...composerSettings.availableReasoningEfforts
13212
- ];
13213
- }
13214
- function resolveReasoningOptionLabel(value, labels) {
13215
- switch (value) {
13216
- case "minimal":
13217
- return labels.reasoningOptionMinimal;
13218
- case "low":
13219
- return labels.reasoningOptionLow;
13220
- case "medium":
13221
- return labels.reasoningOptionMedium;
13222
- case "high":
13223
- return labels.reasoningOptionHigh;
13224
- case "xhigh":
13225
- return labels.reasoningOptionXHigh;
13226
- default:
13227
- return value;
13228
- }
13229
- }
13230
- function formatModelDisplayLabel(label) {
13231
- const trimmed = label.trim();
13232
- if (!trimmed) {
13233
- return label;
13234
- }
13235
- return `${trimmed.charAt(0).toUpperCase()}${trimmed.slice(1)}`;
13236
- }
13237
13859
  function resolvePermissionModeTriggerTone(value) {
13238
13860
  switch (normalizePermissionModeValue(value)) {
13239
13861
  case "read-only":
@@ -13256,24 +13878,6 @@ function normalizePermissionModeValue(value) {
13256
13878
  const normalized = value?.trim().toLowerCase().replace(/\s+/g, "-");
13257
13879
  return normalized || void 0;
13258
13880
  }
13259
- function resolveModelDescription(description, labels) {
13260
- switch (description) {
13261
- case "Frontier model for complex coding, research, and real-world work.":
13262
- return labels.modelDescriptions.frontierComplexCoding;
13263
- case "Strong model for everyday coding.":
13264
- return labels.modelDescriptions.everydayCoding;
13265
- case "Small, fast, and cost-efficient model for simpler coding tasks.":
13266
- return labels.modelDescriptions.smallFastCostEfficient;
13267
- case "Coding-optimized model.":
13268
- return labels.modelDescriptions.codingOptimized;
13269
- case "Ultra-fast coding model.":
13270
- return labels.modelDescriptions.ultraFastCoding;
13271
- case "Optimized for professional work and long-running agents.":
13272
- return labels.modelDescriptions.professionalLongRunning;
13273
- default:
13274
- return description;
13275
- }
13276
- }
13277
13881
  function AgentModelReasoningDropdown({
13278
13882
  composerSettings,
13279
13883
  disabled = false,
@@ -13281,193 +13885,161 @@ function AgentModelReasoningDropdown({
13281
13885
  onSettingsChange
13282
13886
  }) {
13283
13887
  "use memo";
13284
- const selectedModelLabel = resolveSelectedModelLabel(
13285
- composerSettings,
13286
- labels
13287
- );
13288
- const selectedReasoningLabel = resolveSelectedReasoningLabel(
13289
- composerSettings,
13290
- labels
13291
- );
13292
- const triggerLabel = selectedModelLabel === selectedReasoningLabel ? selectedModelLabel : `${selectedModelLabel} ${selectedReasoningLabel}`.trim();
13293
- const modelItems = modelOptionsWithSelectedValue(composerSettings);
13294
- const reasoningItems = reasoningOptionsWithSelectedValue(composerSettings);
13295
- const triggerDisabled = disabled || composerSettings.isSettingsLoading || !composerSettings.supportsModel && !composerSettings.supportsReasoningEffort;
13296
- const showReasoningSection = composerSettings.supportsReasoningEffort && reasoningItems.length > 0 && !composerSettings.reasoningUnavailable;
13297
- const showModelSection = composerSettings.supportsModel && modelItems.length > 0 && !composerSettings.modelUnavailable;
13298
- const selectedReasoningValue = selectedComposerReasoningValue(composerSettings) ?? "";
13299
- const selectedModelValue = selectedComposerModelValue(composerSettings) ?? "";
13300
- const selectDisabled = triggerDisabled || !showModelSection && !showReasoningSection;
13301
- const selectedModelSelectValue = selectedModelValue ? `model:${selectedModelValue}` : "";
13302
- const selectedReasoningSelectValue = selectedReasoningValue ? `reasoning:${selectedReasoningValue}` : "";
13303
- const selectValue = showModelSection ? selectedModelSelectValue : selectedReasoningSelectValue;
13304
- const applySettingsValue = (nextValue) => {
13305
- if (selectDisabled) {
13306
- return;
13307
- }
13308
- if (nextValue.startsWith("reasoning:")) {
13309
- onSettingsChange({
13310
- reasoningEffort: nextValue.slice("reasoning:".length)
13311
- });
13312
- return;
13313
- }
13314
- if (nextValue.startsWith("model:")) {
13315
- onSettingsChange({ model: nextValue.slice("model:".length) });
13316
- }
13317
- };
13318
- const handleSelectedItemPointerDown = (event, optionValue) => {
13319
- if (selectDisabled || event.button !== 0 || event.ctrlKey) {
13320
- return;
13321
- }
13322
- applySettingsValue(optionValue);
13888
+ const [menuOpen, setMenuOpen] = useState7(false);
13889
+ const menu = buildComposerModelMenuModel(composerSettings, labels);
13890
+ const menuDisabled = disabled || menu.disabled;
13891
+ const applySettingsChange = (patch) => {
13892
+ onSettingsChange(patch);
13893
+ setMenuOpen(false);
13323
13894
  };
13324
- return /* @__PURE__ */ jsxs9(
13325
- Select,
13326
- {
13327
- value: selectValue,
13328
- disabled: selectDisabled,
13329
- onValueChange: applySettingsValue,
13330
- children: [
13331
- /* @__PURE__ */ jsx21(
13332
- SelectTrigger,
13333
- {
13334
- className: cn2(
13335
- "w-auto",
13336
- AgentGUINode_styles_default.composerMenuTrigger,
13337
- selectDisabled && "cursor-not-allowed text-[var(--agent-gui-text-tertiary)] opacity-60 hover:text-[var(--agent-gui-text-tertiary)]",
13338
- composerSettings.isSettingsLoading && "animate-pulse"
13339
- ),
13340
- "aria-label": `${labels.modelLabel} / ${labels.reasoningLabel}`,
13341
- "data-agent-model-reasoning-trigger": "true",
13342
- children: /* @__PURE__ */ jsx21("span", { className: "flex min-w-0 flex-1 items-center gap-2 overflow-hidden", children: selectedModelLabel === selectedReasoningLabel || selectedReasoningLabel.length === 0 ? /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate", children: triggerLabel }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
13343
- /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate", children: selectedModelLabel }),
13344
- /* @__PURE__ */ jsx21("span", { className: "shrink-0", children: selectedReasoningLabel })
13345
- ] }) })
13346
- }
13895
+ return /* @__PURE__ */ jsxs9(DropdownMenu2, { open: menuOpen, onOpenChange: setMenuOpen, children: [
13896
+ /* @__PURE__ */ jsx21(DropdownMenuTrigger2, { asChild: true, disabled: menuDisabled, children: /* @__PURE__ */ jsxs9(
13897
+ "button",
13898
+ {
13899
+ type: "button",
13900
+ className: cn2(
13901
+ "w-auto",
13902
+ AgentGUINode_styles_default.composerMenuTrigger,
13903
+ menuDisabled && "cursor-not-allowed text-[var(--agent-gui-text-tertiary)] opacity-60 hover:text-[var(--agent-gui-text-tertiary)]",
13904
+ composerSettings.isSettingsLoading && "animate-pulse"
13347
13905
  ),
13348
- /* @__PURE__ */ jsx21(
13349
- SelectContent,
13350
- {
13351
- align: "end",
13352
- side: "top",
13353
- sideOffset: 4,
13354
- collisionPadding: 16,
13355
- className: cn2(
13356
- AgentGUINode_styles_default.composerMenuContent,
13357
- "data-[side=top]:!translate-y-0",
13358
- showReasoningSection && showModelSection ? "w-[430px] max-w-[calc(100vw-32px)]" : "w-max min-w-[240px] max-w-[calc(100vw-32px)]"
13906
+ "aria-label": `${labels.modelLabel} / ${labels.reasoningLabel}`,
13907
+ "data-agent-model-reasoning-trigger": "true",
13908
+ children: [
13909
+ /* @__PURE__ */ jsxs9("span", { className: "flex min-w-0 flex-1 items-center gap-2 overflow-hidden", children: [
13910
+ menu.speed.show && menu.trigger.isFast ? /* @__PURE__ */ jsx21(
13911
+ "span",
13912
+ {
13913
+ "aria-hidden": true,
13914
+ className: "shrink-0",
13915
+ "data-agent-speed-indicator": "fast",
13916
+ children: "\u26A1"
13917
+ }
13918
+ ) : null,
13919
+ menu.trigger.showCombined ? /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate", children: menu.trigger.combinedLabel }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
13920
+ /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate", children: menu.trigger.modelLabel }),
13921
+ /* @__PURE__ */ jsx21("span", { className: "shrink-0", children: menu.trigger.reasoningLabel })
13922
+ ] })
13923
+ ] }),
13924
+ /* @__PURE__ */ jsx21(ChevronDownIcon, { "aria-hidden": true, className: "ml-1 size-3 shrink-0" })
13925
+ ]
13926
+ }
13927
+ ) }),
13928
+ /* @__PURE__ */ jsxs9(
13929
+ DropdownMenuContent2,
13930
+ {
13931
+ align: "end",
13932
+ side: "top",
13933
+ sideOffset: 4,
13934
+ collisionPadding: 16,
13935
+ className: cn2(
13936
+ AgentGUINode_styles_default.composerMenuContent,
13937
+ "w-max min-w-[240px] max-w-[calc(100vw-32px)] data-[side=top]:!translate-y-0"
13938
+ ),
13939
+ "data-agent-composer-settings-layout": "model-primary",
13940
+ children: [
13941
+ menu.model.show ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
13942
+ /* @__PURE__ */ jsx21(DropdownMenuLabel2, { children: labels.modelSelectionLabel }),
13943
+ /* @__PURE__ */ jsx21(
13944
+ ComposerMenuOptionItems,
13945
+ {
13946
+ options: menu.model.options,
13947
+ selectedValue: menu.model.selectedValue,
13948
+ withDescription: true,
13949
+ onSelect: (value) => applySettingsChange({ model: value })
13950
+ }
13951
+ )
13952
+ ] }) : null,
13953
+ menu.model.show && (menu.reasoning.show || menu.speed.show) ? /* @__PURE__ */ jsx21(DropdownMenuSeparator2, {}) : null,
13954
+ menu.reasoning.show ? /* @__PURE__ */ jsxs9(DropdownMenuSub2, { children: [
13955
+ /* @__PURE__ */ jsxs9(
13956
+ DropdownMenuSubTrigger2,
13957
+ {
13958
+ className: AgentGUINode_styles_default.composerMenuItem,
13959
+ "data-agent-reasoning-submenu-trigger": "true",
13960
+ children: [
13961
+ /* @__PURE__ */ jsx21("span", { className: "min-w-0 flex-1 truncate", children: labels.reasoningLabel }),
13962
+ /* @__PURE__ */ jsx21("span", { className: "pl-3 text-[var(--text-tertiary)]", children: menu.reasoning.selectedLabel })
13963
+ ]
13964
+ }
13359
13965
  ),
13360
- children: showReasoningSection && showModelSection ? /* @__PURE__ */ jsxs9(SelectSplitLayout, { "data-agent-composer-settings-layout": "split", children: [
13361
- /* @__PURE__ */ jsxs9(SelectSplitColumn, { children: [
13362
- /* @__PURE__ */ jsx21(SelectSplitColumnLabel, { children: labels.modelSelectionLabel }),
13363
- /* @__PURE__ */ jsx21(SelectSplitColumnItems, { children: /* @__PURE__ */ jsx21(
13364
- ComposerSettingsModelItems,
13365
- {
13366
- disabled: selectDisabled,
13367
- labels,
13368
- models: modelItems,
13369
- onSelectedItemPointerDown: handleSelectedItemPointerDown
13370
- }
13371
- ) })
13372
- ] }),
13373
- /* @__PURE__ */ jsx21(SelectSplitDivider, {}),
13374
- /* @__PURE__ */ jsxs9(SelectSplitColumn, { children: [
13375
- /* @__PURE__ */ jsx21(SelectSplitColumnLabel, { children: labels.reasoningDegreeLabel }),
13376
- /* @__PURE__ */ jsx21(SelectSplitColumnItems, { children: /* @__PURE__ */ jsx21(
13377
- ComposerSettingsReasoningItems,
13378
- {
13379
- composerSettings,
13380
- disabled: selectDisabled,
13381
- labels,
13382
- reasoningEfforts: reasoningItems,
13383
- showManualSelectedIndicator: true,
13384
- onSelectedItemPointerDown: handleSelectedItemPointerDown
13385
- }
13386
- ) })
13387
- ] })
13388
- ] }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
13389
- showModelSection ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
13390
- /* @__PURE__ */ jsx21("div", { className: AgentGUINode_styles_default.composerMenuLabel, children: labels.modelSelectionLabel }),
13391
- /* @__PURE__ */ jsx21(
13392
- ComposerSettingsModelItems,
13966
+ /* @__PURE__ */ jsx21(
13967
+ DropdownMenuSubContent2,
13968
+ {
13969
+ className: cn2(AgentGUINode_styles_default.composerMenuContent, "min-w-[160px]"),
13970
+ children: /* @__PURE__ */ jsx21(
13971
+ ComposerMenuOptionItems,
13393
13972
  {
13394
- disabled: selectDisabled,
13395
- labels,
13396
- models: modelItems,
13397
- onSelectedItemPointerDown: handleSelectedItemPointerDown
13973
+ options: menu.reasoning.options,
13974
+ selectedValue: menu.reasoning.selectedValue,
13975
+ onSelect: (value) => applySettingsChange({ reasoningEffort: value })
13398
13976
  }
13399
13977
  )
13400
- ] }) : null,
13401
- showReasoningSection ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
13402
- /* @__PURE__ */ jsx21("div", { className: AgentGUINode_styles_default.composerMenuLabel, children: labels.reasoningDegreeLabel }),
13403
- /* @__PURE__ */ jsx21(
13404
- ComposerSettingsReasoningItems,
13978
+ }
13979
+ )
13980
+ ] }) : null,
13981
+ menu.speed.show ? /* @__PURE__ */ jsxs9(DropdownMenuSub2, { children: [
13982
+ /* @__PURE__ */ jsxs9(
13983
+ DropdownMenuSubTrigger2,
13984
+ {
13985
+ className: AgentGUINode_styles_default.composerMenuItem,
13986
+ "data-agent-speed-submenu-trigger": "true",
13987
+ children: [
13988
+ /* @__PURE__ */ jsx21("span", { className: "min-w-0 flex-1 truncate", children: labels.speedLabel }),
13989
+ /* @__PURE__ */ jsx21("span", { className: "pl-3 text-[var(--text-tertiary)]", children: menu.speed.selectedLabel })
13990
+ ]
13991
+ }
13992
+ ),
13993
+ /* @__PURE__ */ jsx21(
13994
+ DropdownMenuSubContent2,
13995
+ {
13996
+ className: cn2(AgentGUINode_styles_default.composerMenuContent, "min-w-[200px]"),
13997
+ children: /* @__PURE__ */ jsx21(
13998
+ ComposerMenuOptionItems,
13405
13999
  {
13406
- composerSettings,
13407
- disabled: selectDisabled,
13408
- labels,
13409
- reasoningEfforts: reasoningItems,
13410
- showManualSelectedIndicator: false,
13411
- onSelectedItemPointerDown: handleSelectedItemPointerDown
14000
+ options: menu.speed.options,
14001
+ selectedValue: menu.speed.selectedValue,
14002
+ withDescription: true,
14003
+ onSelect: (value) => applySettingsChange({ speed: value })
13412
14004
  }
13413
14005
  )
13414
- ] }) : null
13415
- ] })
13416
- }
13417
- )
13418
- ]
13419
- }
13420
- );
14006
+ }
14007
+ )
14008
+ ] }) : null
14009
+ ]
14010
+ }
14011
+ )
14012
+ ] });
13421
14013
  }
13422
- function ComposerSettingsModelItems({
13423
- disabled,
13424
- labels,
13425
- models,
13426
- onSelectedItemPointerDown
14014
+ function ComposerMenuOptionItems({
14015
+ options,
14016
+ selectedValue,
14017
+ withDescription = false,
14018
+ onSelect
13427
14019
  }) {
13428
- return /* @__PURE__ */ jsx21(Fragment4, { children: models.map((model) => {
13429
- const optionValue = `model:${model.value}`;
13430
- return /* @__PURE__ */ jsx21(
13431
- SelectItem,
13432
- {
13433
- value: optionValue,
13434
- disabled,
13435
- className: AgentGUINode_styles_default.composerMenuItem,
13436
- onPointerDown: (event) => onSelectedItemPointerDown(event, optionValue),
13437
- children: /* @__PURE__ */ jsxs9("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
13438
- /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate", children: formatModelDisplayLabel(model.label) }),
13439
- model.description ? /* @__PURE__ */ jsx21("span", { className: "whitespace-normal text-[11px] leading-[1.3] text-[var(--text-tertiary)]", children: resolveModelDescription(model.description, labels) }) : null
13440
- ] })
14020
+ return /* @__PURE__ */ jsx21(Fragment4, { children: options.map((option) => /* @__PURE__ */ jsxs9(
14021
+ DropdownMenuItem2,
14022
+ {
14023
+ className: AgentGUINode_styles_default.composerMenuItem,
14024
+ onPointerDown: (event) => {
14025
+ if (event.button === 0 && !event.ctrlKey) {
14026
+ event.preventDefault();
14027
+ onSelect(option.value);
14028
+ }
13441
14029
  },
13442
- model.value
13443
- );
13444
- }) });
13445
- }
13446
- function ComposerSettingsReasoningItems({
13447
- composerSettings,
13448
- disabled,
13449
- labels,
13450
- reasoningEfforts,
13451
- showManualSelectedIndicator,
13452
- onSelectedItemPointerDown
13453
- }) {
13454
- const selectedReasoningValue = composerSettings.selectedReasoningEffortValue ?? composerSettings.draftSettings.reasoningEffort ?? "";
13455
- return /* @__PURE__ */ jsx21(Fragment4, { children: reasoningEfforts.map((option) => {
13456
- const optionValue = `reasoning:${option.value}`;
13457
- const isSelected = selectedReasoningValue === option.value;
13458
- return /* @__PURE__ */ jsx21(
13459
- SelectItem,
13460
- {
13461
- value: optionValue,
13462
- disabled,
13463
- className: AgentGUINode_styles_default.composerMenuItem,
13464
- forceSelectedIndicator: showManualSelectedIndicator && isSelected,
13465
- onPointerDown: (event) => onSelectedItemPointerDown(event, optionValue),
13466
- children: /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate", children: resolveReasoningOptionLabel(option.value, labels) })
14030
+ onSelect: () => {
14031
+ onSelect(option.value);
13467
14032
  },
13468
- option.value
13469
- );
13470
- }) });
14033
+ children: [
14034
+ /* @__PURE__ */ jsxs9("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
14035
+ /* @__PURE__ */ jsx21("span", { className: "min-w-0 truncate", children: option.label }),
14036
+ withDescription && option.description ? /* @__PURE__ */ jsx21("span", { className: "whitespace-normal text-[11px] leading-[1.3] text-[var(--text-tertiary)]", children: option.description }) : null
14037
+ ] }),
14038
+ option.value === selectedValue ? /* @__PURE__ */ jsx21(CheckIcon, { className: "ml-2 size-3.5 shrink-0 text-[var(--tutti-purple)]" }) : null
14039
+ ]
14040
+ },
14041
+ option.value
14042
+ )) });
13471
14043
  }
13472
14044
 
13473
14045
  // agent-gui/agentGuiNode/agentRichText/AgentRichTextEditor.tsx
@@ -14410,11 +14982,7 @@ var DEFAULT_DEBOUNCE_MS = 120;
14410
14982
  var DEFAULT_FILE_LIMIT = 30;
14411
14983
  var DEFAULT_ISSUE_LIMIT = 25;
14412
14984
  var DEFAULT_SESSION_LIMIT = 30;
14413
- var WORKSPACE_APP_REFERENCE_PAGE_SIZE = 5;
14414
- var EMPTY_PROVIDER_REFERENCE_ITEMS_RESULT = {
14415
- items: [],
14416
- nextCursor: null
14417
- };
14985
+ var DEFAULT_PROVIDER_TIMEOUT_MS = 3500;
14418
14986
  var BROWSE_CATEGORIES = AGENT_MENTION_FILTER_TAB_ORDER.map((id) => ({ id }));
14419
14987
  var {
14420
14988
  agentGeneratedFile: AGENT_GENERATED_FILE_PROVIDER_ID,
@@ -14428,6 +14996,7 @@ var AgentMentionSearchController = class {
14428
14996
  debounceMs;
14429
14997
  fileLimit;
14430
14998
  issueLimit;
14999
+ providerTimeoutMs;
14431
15000
  listeners = /* @__PURE__ */ new Set();
14432
15001
  expandedCounts = {};
14433
15002
  totalCounts = {};
@@ -14441,7 +15010,6 @@ var AgentMentionSearchController = class {
14441
15010
  currentFileSearchLimit;
14442
15011
  currentIssueSearchLimit;
14443
15012
  agentGeneratedBrowsePath = null;
14444
- workspaceAppReferenceSources = /* @__PURE__ */ new Map();
14445
15013
  rawGroups = {
14446
15014
  apps: [],
14447
15015
  opened_files: [],
@@ -14469,6 +15037,7 @@ var AgentMentionSearchController = class {
14469
15037
  this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
14470
15038
  this.fileLimit = options.fileLimit ?? DEFAULT_FILE_LIMIT;
14471
15039
  this.issueLimit = options.issueLimit ?? DEFAULT_ISSUE_LIMIT;
15040
+ this.providerTimeoutMs = options.providerTimeoutMs ?? DEFAULT_PROVIDER_TIMEOUT_MS;
14472
15041
  this.currentFileSearchLimit = this.fileLimit;
14473
15042
  this.currentIssueSearchLimit = this.issueLimit;
14474
15043
  }
@@ -14489,7 +15058,6 @@ var AgentMentionSearchController = class {
14489
15058
  this.clearTimer();
14490
15059
  const requestId = ++this.requestId;
14491
15060
  this.resetAgentGeneratedBrowsePath();
14492
- this.resetWorkspaceAppReferenceSources();
14493
15061
  this.resetExpandedCounts();
14494
15062
  this.resetSearchLimits();
14495
15063
  if (!this.activeWorkspaceId) {
@@ -14673,35 +15241,11 @@ var AgentMentionSearchController = class {
14673
15241
  error: null
14674
15242
  });
14675
15243
  }
14676
- expandWorkspaceAppReferences(appId) {
14677
- const normalizedAppId = compactText(appId);
14678
- if (this.disposed || !normalizedAppId) {
14679
- return;
14680
- }
14681
- const source = this.workspaceAppReferenceSources.get(normalizedAppId);
14682
- if (!source || !source.nextCursor || source.workspaceId !== this.activeWorkspaceId || source.query !== this.currentQuery || this.isWorkspaceAppReferenceLoading(normalizedAppId)) {
14683
- return;
14684
- }
14685
- const requestId = this.requestId;
14686
- const cursor = source.nextCursor;
14687
- this.updateWorkspaceAppReferenceItem(normalizedAppId, (item) => ({
14688
- ...item,
14689
- referenceItemsLoading: true
14690
- }));
14691
- this.emitCurrentState();
14692
- void this.loadMoreWorkspaceAppReferences({
14693
- appId: normalizedAppId,
14694
- cursor,
14695
- requestId,
14696
- source
14697
- });
14698
- }
14699
15244
  close() {
14700
15245
  this.clearTimer();
14701
15246
  this.requestId += 1;
14702
15247
  this.currentFilter = "all";
14703
15248
  this.resetAgentGeneratedBrowsePath();
14704
- this.resetWorkspaceAppReferenceSources();
14705
15249
  this.resetExpandedCounts();
14706
15250
  this.resetSearchLimits();
14707
15251
  this.rawGroups = {
@@ -14734,11 +15278,9 @@ var AgentMentionSearchController = class {
14734
15278
  this.clearTimer();
14735
15279
  this.listeners.clear();
14736
15280
  this.requestId += 1;
14737
- this.resetWorkspaceAppReferenceSources();
14738
15281
  }
14739
15282
  startBrowseModeFetch(filter) {
14740
15283
  if (!this.activeWorkspaceId || !shouldPrefetchBrowseFilter(filter)) {
14741
- this.resetWorkspaceAppReferenceSources();
14742
15284
  this.rawGroups = {
14743
15285
  apps: [],
14744
15286
  opened_files: [],
@@ -14752,7 +15294,6 @@ var AgentMentionSearchController = class {
14752
15294
  }
14753
15295
  this.clearTimer();
14754
15296
  const requestId = ++this.requestId;
14755
- this.resetWorkspaceAppReferenceSources();
14756
15297
  this.rawGroups = {
14757
15298
  apps: [],
14758
15299
  opened_files: [],
@@ -14769,68 +15310,8 @@ var AgentMentionSearchController = class {
14769
15310
  filter
14770
15311
  });
14771
15312
  }
14772
- async loadMoreWorkspaceAppReferences(input) {
14773
- try {
14774
- const referenceResult = await Promise.resolve(
14775
- input.source.provider.getItemReferenceItems?.(input.source.item, {
14776
- keyword: input.source.query,
14777
- maxResults: WORKSPACE_APP_REFERENCE_PAGE_SIZE,
14778
- cursor: input.cursor,
14779
- context: {
14780
- metadata: {
14781
- currentUserId: input.source.currentUserId,
14782
- target: "agent-gui",
14783
- workspaceId: input.source.workspaceId
14784
- }
14785
- }
14786
- }) ?? []
14787
- ).then(normalizeProviderReferenceItemsResult);
14788
- if (!this.canApply(
14789
- input.requestId,
14790
- input.source.workspaceId,
14791
- input.source.query
14792
- )) {
14793
- return;
14794
- }
14795
- const currentSource = this.workspaceAppReferenceSources.get(input.appId);
14796
- if (!currentSource || currentSource.nextCursor !== input.cursor) {
14797
- return;
14798
- }
14799
- const fileReferenceItems = referenceResult.items.map(providerReferenceItemToFileMentionItem).filter(
14800
- (referenceItem) => referenceItem !== null
14801
- );
14802
- this.workspaceAppReferenceSources.set(input.appId, {
14803
- ...currentSource,
14804
- nextCursor: referenceResult.nextCursor
14805
- });
14806
- this.updateWorkspaceAppReferenceItem(input.appId, (item) => ({
14807
- ...item,
14808
- referenceItems: mergeWorkspaceAppReferenceItems(
14809
- item.referenceItems ?? [],
14810
- fileReferenceItems
14811
- ),
14812
- referenceItemsLoading: false,
14813
- referenceNextCursor: referenceResult.nextCursor
14814
- }));
14815
- this.emitCurrentState();
14816
- } catch {
14817
- if (!this.canApply(
14818
- input.requestId,
14819
- input.source.workspaceId,
14820
- input.source.query
14821
- )) {
14822
- return;
14823
- }
14824
- this.updateWorkspaceAppReferenceItem(input.appId, (item) => ({
14825
- ...item,
14826
- referenceItemsLoading: false
14827
- }));
14828
- this.emitCurrentState();
14829
- }
14830
- }
14831
15313
  async runSearch(input) {
14832
15314
  try {
14833
- const appReferenceSources = [];
14834
15315
  const [fileItems, appItems, issueItems, sessionItems] = await Promise.all(
14835
15316
  [
14836
15317
  this.queryProviderMentionItemsById({
@@ -14845,8 +15326,7 @@ var AgentMentionSearchController = class {
14845
15326
  workspaceId: input.workspaceId,
14846
15327
  currentUserId: input.currentUserId,
14847
15328
  query: input.query,
14848
- limit: DEFAULT_MENTION_GROUP_PAGE_SIZE,
14849
- workspaceAppReferenceSources: appReferenceSources
15329
+ limit: DEFAULT_MENTION_GROUP_PAGE_SIZE
14850
15330
  }),
14851
15331
  this.queryProviderMentionItemsById({
14852
15332
  providerId: WORKSPACE_ISSUE_PROVIDER_ID,
@@ -14867,7 +15347,6 @@ var AgentMentionSearchController = class {
14867
15347
  if (!this.canApply(input.requestId, input.workspaceId, input.query)) {
14868
15348
  return;
14869
15349
  }
14870
- this.replaceWorkspaceAppReferenceSources(appReferenceSources);
14871
15350
  this.rawGroups = {
14872
15351
  apps: appItems.filter((item) => item.kind === "workspace-app"),
14873
15352
  opened_files: fileItems.filter((item) => item.kind === "file"),
@@ -14949,19 +15428,16 @@ var AgentMentionSearchController = class {
14949
15428
  this.totalCounts.collab_sessions = 0;
14950
15429
  this.totalCounts.issues = 0;
14951
15430
  } else if (input.filter === "app") {
14952
- const appReferenceSources = [];
14953
15431
  const appItems = await this.queryProviderMentionItemsById({
14954
15432
  providerId: WORKSPACE_APP_PROVIDER_ID,
14955
15433
  workspaceId: input.workspaceId,
14956
15434
  currentUserId: input.currentUserId,
14957
15435
  query: "",
14958
- limit: DEFAULT_MENTION_GROUP_PAGE_SIZE,
14959
- workspaceAppReferenceSources: appReferenceSources
15436
+ limit: DEFAULT_MENTION_GROUP_PAGE_SIZE
14960
15437
  });
14961
15438
  if (!this.canApply(input.requestId, input.workspaceId, "")) {
14962
15439
  return;
14963
15440
  }
14964
- this.replaceWorkspaceAppReferenceSources(appReferenceSources);
14965
15441
  this.rawGroups = {
14966
15442
  apps: appItems.filter((item) => item.kind === "workspace-app"),
14967
15443
  opened_files: [],
@@ -15035,7 +15511,6 @@ var AgentMentionSearchController = class {
15035
15511
  this.totalCounts.collab_sessions = this.rawGroups.collab_sessions.length;
15036
15512
  this.totalCounts.issues = 0;
15037
15513
  } else {
15038
- const appReferenceSources = [];
15039
15514
  const [
15040
15515
  appItems,
15041
15516
  fileItems,
@@ -15048,8 +15523,7 @@ var AgentMentionSearchController = class {
15048
15523
  workspaceId: input.workspaceId,
15049
15524
  currentUserId: input.currentUserId,
15050
15525
  query: "",
15051
- limit: DEFAULT_MENTION_GROUP_PAGE_SIZE,
15052
- workspaceAppReferenceSources: appReferenceSources
15526
+ limit: DEFAULT_MENTION_GROUP_PAGE_SIZE
15053
15527
  }),
15054
15528
  this.queryProviderMentionItemsById({
15055
15529
  providerId: FILE_PROVIDER_ID,
@@ -15083,7 +15557,6 @@ var AgentMentionSearchController = class {
15083
15557
  if (!this.canApply(input.requestId, input.workspaceId, "")) {
15084
15558
  return;
15085
15559
  }
15086
- this.replaceWorkspaceAppReferenceSources(appReferenceSources);
15087
15560
  this.rawGroups = {
15088
15561
  apps: appItems.filter((item) => item.kind === "workspace-app"),
15089
15562
  opened_files: fileItems.filter((item) => item.kind === "file"),
@@ -15130,127 +15603,93 @@ var AgentMentionSearchController = class {
15130
15603
  }
15131
15604
  }
15132
15605
  async queryProviderMentionItems(input) {
15133
- const providerContext = {
15134
- metadata: {
15135
- currentUserId: input.currentUserId,
15136
- target: "agent-gui",
15137
- workspaceId: input.workspaceId
15138
- }
15139
- };
15140
- const directItems = await input.provider.query({
15606
+ const items = await input.provider.query({
15141
15607
  keyword: input.query,
15142
15608
  maxResults: input.limit,
15143
- context: providerContext
15144
- });
15145
- const itemCandidates = directItems.map(
15146
- (item) => ({
15147
- includeWorkspaceAppWithoutReferences: true,
15148
- item
15149
- })
15150
- );
15151
- if (input.provider.id === WORKSPACE_APP_PROVIDER_ID && input.query.trim() && input.provider.getItemReferenceItems) {
15152
- const seenKeys = new Set(
15153
- directItems.map((item) => compactText(input.provider.getItemKey(item))).filter(Boolean)
15154
- );
15155
- const referenceCandidateItems = await input.provider.query({
15156
- keyword: "",
15157
- context: providerContext
15158
- });
15159
- for (const item of referenceCandidateItems) {
15160
- const key = compactText(input.provider.getItemKey(item));
15161
- if (key && seenKeys.has(key)) {
15162
- continue;
15163
- }
15164
- if (key) {
15165
- seenKeys.add(key);
15609
+ abortSignal: input.abortSignal,
15610
+ context: {
15611
+ metadata: {
15612
+ currentUserId: input.currentUserId,
15613
+ target: "agent-gui",
15614
+ workspaceId: input.workspaceId
15166
15615
  }
15167
- itemCandidates.push({
15168
- includeWorkspaceAppWithoutReferences: false,
15169
- item
15170
- });
15171
15616
  }
15617
+ });
15618
+ if (input.abortSignal.aborted) {
15619
+ return [];
15172
15620
  }
15173
15621
  const mentionItems = await Promise.all(
15174
- itemCandidates.map(
15175
- async ({ includeWorkspaceAppWithoutReferences, item }) => {
15176
- const mentionItem = providerItemToAgentMentionItem({
15177
- currentUserId: input.currentUserId,
15178
- insertResult: input.provider.toInsertResult(item),
15179
- label: input.provider.getItemLabel(item),
15180
- providerId: input.provider.id,
15181
- subtitle: input.provider.getItemSubtitle?.(item) ?? "",
15182
- workspaceId: input.workspaceId
15183
- });
15184
- if (mentionItem?.kind === "workspace-app") {
15185
- const referenceResult = await Promise.resolve(
15186
- input.provider.getItemReferenceItems?.(item, {
15187
- keyword: input.query,
15188
- maxResults: WORKSPACE_APP_REFERENCE_PAGE_SIZE,
15189
- context: providerContext
15190
- }) ?? []
15191
- ).then(normalizeProviderReferenceItemsResult).catch(() => EMPTY_PROVIDER_REFERENCE_ITEMS_RESULT);
15192
- const fileReferenceItems = referenceResult.items.map(providerReferenceItemToFileMentionItem).filter(
15193
- (referenceItem) => referenceItem !== null
15194
- );
15195
- const resolvedMentionItem = fileReferenceItems.length > 0 ? {
15196
- ...mentionItem,
15197
- referenceItems: fileReferenceItems,
15198
- referenceNextCursor: referenceResult.nextCursor
15199
- } : includeWorkspaceAppWithoutReferences ? {
15200
- ...mentionItem,
15201
- referenceNextCursor: referenceResult.nextCursor
15202
- } : null;
15203
- if (resolvedMentionItem) {
15204
- input.workspaceAppReferenceSources?.push({
15205
- appId: resolvedMentionItem.appId,
15206
- currentUserId: input.currentUserId,
15207
- item,
15208
- nextCursor: referenceResult.nextCursor,
15209
- provider: input.provider,
15210
- query: input.query,
15211
- workspaceId: input.workspaceId
15212
- });
15213
- }
15214
- return resolvedMentionItem;
15215
- }
15216
- if (!mentionItem || mentionItem.kind !== "file") {
15217
- return mentionItem;
15218
- }
15219
- const thumbnailUrl = await Promise.resolve(
15220
- input.provider.getItemThumbnailUrl?.(item) ?? null
15221
- ).catch(() => null);
15222
- const resolvedThumbnailUrl = resolveAgentMentionFileThumbnailUrl({
15223
- ...mentionItem,
15224
- thumbnailUrl
15225
- });
15226
- if (!resolvedThumbnailUrl) {
15227
- return mentionItem;
15228
- }
15229
- return {
15230
- ...mentionItem,
15231
- thumbnailUrl: resolvedThumbnailUrl
15232
- };
15622
+ items.map(async (item) => {
15623
+ const mentionItem = providerItemToAgentMentionItem({
15624
+ currentUserId: input.currentUserId,
15625
+ insertResult: input.provider.toInsertResult(item),
15626
+ label: input.provider.getItemLabel(item),
15627
+ providerId: input.provider.id,
15628
+ subtitle: input.provider.getItemSubtitle?.(item) ?? "",
15629
+ workspaceId: input.workspaceId
15630
+ });
15631
+ if (!mentionItem || mentionItem.kind !== "file") {
15632
+ return mentionItem;
15233
15633
  }
15234
- )
15634
+ const thumbnailUrl = await Promise.resolve(
15635
+ input.provider.getItemThumbnailUrl?.(item) ?? null
15636
+ ).catch(() => null);
15637
+ const resolvedThumbnailUrl = resolveAgentMentionFileThumbnailUrl({
15638
+ ...mentionItem,
15639
+ thumbnailUrl
15640
+ });
15641
+ if (!resolvedThumbnailUrl) {
15642
+ return mentionItem;
15643
+ }
15644
+ return {
15645
+ ...mentionItem,
15646
+ thumbnailUrl: resolvedThumbnailUrl
15647
+ };
15648
+ })
15235
15649
  );
15236
- const resolvedItems = mentionItems.filter(
15650
+ return mentionItems.filter(
15237
15651
  (item) => item !== null
15238
15652
  );
15239
- return input.provider.id === WORKSPACE_APP_PROVIDER_ID ? sortMentionItemsByMatchScore(resolvedItems, input.query) : resolvedItems;
15240
15653
  }
15241
15654
  async queryProviderMentionItemsById(input) {
15242
15655
  const provider = this.richTextAtProviders.get(input.providerId);
15243
15656
  if (!provider) {
15244
15657
  return [];
15245
15658
  }
15246
- return this.queryProviderMentionItems({
15247
- provider,
15248
- workspaceId: input.workspaceId,
15249
- currentUserId: input.currentUserId,
15250
- query: input.query,
15251
- limit: input.limit,
15252
- workspaceAppReferenceSources: input.workspaceAppReferenceSources
15659
+ return this.runProviderQuery(
15660
+ (abortSignal) => this.queryProviderMentionItems({
15661
+ provider,
15662
+ workspaceId: input.workspaceId,
15663
+ currentUserId: input.currentUserId,
15664
+ query: input.query,
15665
+ limit: input.limit,
15666
+ abortSignal
15667
+ }),
15668
+ []
15669
+ );
15670
+ }
15671
+ async runProviderQuery(query, fallback) {
15672
+ const abortController = new AbortController();
15673
+ const queryPromise = Promise.resolve().then(
15674
+ () => query(abortController.signal)
15675
+ );
15676
+ if (this.providerTimeoutMs <= 0 || !Number.isFinite(this.providerTimeoutMs)) {
15677
+ return queryPromise;
15678
+ }
15679
+ let timeout = null;
15680
+ const timeoutPromise = new Promise((resolve) => {
15681
+ timeout = setTimeout(() => {
15682
+ abortController.abort();
15683
+ resolve(fallback);
15684
+ }, this.providerTimeoutMs);
15253
15685
  });
15686
+ try {
15687
+ return await Promise.race([queryPromise, timeoutPromise]);
15688
+ } finally {
15689
+ if (timeout !== null) {
15690
+ clearTimeout(timeout);
15691
+ }
15692
+ }
15254
15693
  }
15255
15694
  groupsFromRawGroups() {
15256
15695
  const orderedGroupIds = groupIdsForFilter(this.currentFilter);
@@ -15338,48 +15777,6 @@ var AgentMentionSearchController = class {
15338
15777
  resetAgentGeneratedBrowsePath() {
15339
15778
  this.agentGeneratedBrowsePath = null;
15340
15779
  }
15341
- resetWorkspaceAppReferenceSources() {
15342
- this.workspaceAppReferenceSources.clear();
15343
- }
15344
- replaceWorkspaceAppReferenceSources(sources) {
15345
- this.workspaceAppReferenceSources.clear();
15346
- for (const source of sources) {
15347
- this.workspaceAppReferenceSources.set(source.appId, source);
15348
- }
15349
- }
15350
- isWorkspaceAppReferenceLoading(appId) {
15351
- return this.rawGroups.apps.some(
15352
- (item) => item.kind === "workspace-app" && item.appId === appId && item.referenceItemsLoading === true
15353
- );
15354
- }
15355
- updateWorkspaceAppReferenceItem(appId, updater) {
15356
- let updated = false;
15357
- const apps = this.rawGroups.apps.map((item) => {
15358
- if (item.kind !== "workspace-app" || item.appId !== appId) {
15359
- return item;
15360
- }
15361
- updated = true;
15362
- return updater(item);
15363
- });
15364
- if (updated) {
15365
- this.rawGroups = {
15366
- ...this.rawGroups,
15367
- apps
15368
- };
15369
- }
15370
- return updated;
15371
- }
15372
- emitCurrentState() {
15373
- this.setState({
15374
- status: this.state.status === "loading" ? "loading" : "ready",
15375
- query: this.currentQuery,
15376
- mode: this.currentQuery ? "results" : "browse",
15377
- filter: this.currentFilter,
15378
- categories: BROWSE_CATEGORIES,
15379
- groups: this.groupsFromRawGroups(),
15380
- error: null
15381
- });
15382
- }
15383
15780
  setState(state) {
15384
15781
  this.state = state;
15385
15782
  for (const listener of this.listeners) {
@@ -15416,71 +15813,14 @@ function mentionGroupBestMatchScore(group, query) {
15416
15813
  0
15417
15814
  );
15418
15815
  }
15419
- function normalizeProviderReferenceItemsResult(result) {
15420
- return "items" in result ? {
15421
- items: result.items,
15422
- nextCursor: normalizeOptionalCursor(result.nextCursor)
15423
- } : {
15424
- items: result,
15425
- nextCursor: null
15426
- };
15427
- }
15428
- function normalizeOptionalCursor(value) {
15429
- const trimmed = value?.trim() ?? "";
15430
- return trimmed ? trimmed : null;
15431
- }
15432
- function mergeWorkspaceAppReferenceItems(existingItems, nextItems) {
15433
- const seen = new Set(existingItems.map(workspaceAppReferenceItemKey));
15434
- const merged = [...existingItems];
15435
- for (const item of nextItems) {
15436
- const key = workspaceAppReferenceItemKey(item);
15437
- if (seen.has(key)) {
15438
- continue;
15439
- }
15440
- seen.add(key);
15441
- merged.push(item);
15442
- }
15443
- return merged;
15444
- }
15445
- function workspaceAppReferenceItemKey(item) {
15446
- return item.sourceKey?.trim() || item.href;
15447
- }
15448
- function sortMentionItemsByMatchScore(items, query) {
15449
- const normalizedQuery = normalizeQuery2(query).toLowerCase();
15450
- if (!normalizedQuery) {
15451
- return items;
15452
- }
15453
- return items.map((item, index) => ({
15454
- index,
15455
- item,
15456
- score: mentionItemMatchScore(item, normalizedQuery)
15457
- })).sort((left, right) => {
15458
- if (left.score !== right.score) {
15459
- return right.score - left.score;
15460
- }
15461
- return left.index - right.index;
15462
- }).map((entry) => entry.item);
15463
- }
15464
15816
  function mentionItemMatchScore(item, query) {
15465
15817
  const primary = [];
15466
15818
  const secondary = [];
15467
15819
  let kindBoost = 0;
15468
15820
  if (item.kind === "workspace-app") {
15469
15821
  kindBoost = 8;
15470
- primary.push(
15471
- item.name,
15472
- item.appId,
15473
- item.targetId,
15474
- ...(item.referenceItems ?? []).map((referenceItem) => referenceItem.name)
15475
- );
15476
- secondary.push(
15477
- item.description ?? "",
15478
- ...(item.referenceItems ?? []).flatMap((referenceItem) => [
15479
- referenceItem.path,
15480
- referenceItem.directoryPath,
15481
- referenceItem.sourceKey ?? ""
15482
- ])
15483
- );
15822
+ primary.push(item.name, item.appId, item.targetId);
15823
+ secondary.push(item.description ?? "");
15484
15824
  } else if (item.kind === "file") {
15485
15825
  primary.push(item.name);
15486
15826
  secondary.push(item.path, item.directoryPath);
@@ -15628,46 +15968,6 @@ function providerItemToAgentMentionItem(input) {
15628
15968
  }
15629
15969
  return null;
15630
15970
  }
15631
- function providerReferenceItemToFileMentionItem(referenceItem) {
15632
- const label = compactText(referenceItem.label);
15633
- if (!label || referenceItem.insertResult.kind !== "markdown-link") {
15634
- return null;
15635
- }
15636
- const href = referenceItem.insertResult.href.trim();
15637
- if (!href) {
15638
- return null;
15639
- }
15640
- if (!isProviderReferenceFileHref(href)) {
15641
- return null;
15642
- }
15643
- const entryKind = href.endsWith("/") ? "directory" : "unknown";
15644
- const directoryPath = dirnameFromProviderWorkspaceFileHref(href);
15645
- const thumbnailUrl = referenceItem.thumbnailUrl?.trim() || resolveAgentMentionFileThumbnailUrl({
15646
- href,
15647
- path: href,
15648
- name: label,
15649
- entryKind
15650
- });
15651
- return {
15652
- kind: "file",
15653
- href,
15654
- path: href,
15655
- name: label,
15656
- entryKind,
15657
- directoryPath,
15658
- ...referenceItem.key?.trim() ? { sourceKey: referenceItem.key.trim() } : {},
15659
- ...thumbnailUrl ? { thumbnailUrl } : {}
15660
- };
15661
- }
15662
- function isProviderReferenceFileHref(href) {
15663
- if (href.startsWith("#")) {
15664
- return false;
15665
- }
15666
- if (/^[A-Za-z]:[\\/]/u.test(href)) {
15667
- return true;
15668
- }
15669
- return !/^[A-Za-z][A-Za-z\d+.-]*:/u.test(href);
15670
- }
15671
15971
  function normalizeSessionInitiatorDisplayName(value) {
15672
15972
  const trimmed = value.trim();
15673
15973
  return trimmed.toLowerCase() === "local" ? "User" : trimmed;
@@ -15701,7 +16001,7 @@ import {
15701
16001
  useCallback as useCallback7,
15702
16002
  useEffect as useEffect9,
15703
16003
  useRef as useRef10,
15704
- useState as useState7
16004
+ useState as useState8
15705
16005
  } from "react";
15706
16006
  import {
15707
16007
  normalizeAgentActivityDisplayStatus
@@ -15810,29 +16110,11 @@ function flattenAgentMentionPaletteEntries(state) {
15810
16110
  for (const group of state.groups) {
15811
16111
  for (const item of group.items) {
15812
16112
  entries.push({
15813
- key: mentionPaletteItemKey(group.id, item),
16113
+ key: `${group.id}:${item.kind}:${item.kind === "file" ? agentGeneratedMentionItemKey(item) : item.targetId}`,
15814
16114
  type: "item",
15815
16115
  groupId: group.id,
15816
16116
  item
15817
16117
  });
15818
- if (item.kind === "workspace-app") {
15819
- for (const referenceItem of item.referenceItems ?? []) {
15820
- entries.push({
15821
- key: mentionPaletteReferenceItemKey(group.id, item, referenceItem),
15822
- type: "item",
15823
- groupId: group.id,
15824
- item: referenceItem
15825
- });
15826
- }
15827
- if (item.referenceNextCursor) {
15828
- entries.push({
15829
- key: mentionPaletteReferenceExpandKey(group.id, item),
15830
- type: "app-reference-expand",
15831
- appId: item.appId,
15832
- groupId: group.id
15833
- });
15834
- }
15835
- }
15836
16118
  }
15837
16119
  if (group.hasMore) {
15838
16120
  entries.push({
@@ -15844,15 +16126,6 @@ function flattenAgentMentionPaletteEntries(state) {
15844
16126
  }
15845
16127
  return entries;
15846
16128
  }
15847
- function mentionPaletteItemKey(groupId, item) {
15848
- return `${groupId}:${item.kind}:${item.kind === "file" ? agentGeneratedMentionItemKey(item) : item.targetId}`;
15849
- }
15850
- function mentionPaletteReferenceItemKey(groupId, parentItem, referenceItem) {
15851
- return `${groupId}:workspace-app-reference:${parentItem.appId}:${referenceItem.sourceKey ?? referenceItem.href}`;
15852
- }
15853
- function mentionPaletteReferenceExpandKey(groupId, parentItem) {
15854
- return `${groupId}:workspace-app-reference-expand:${parentItem.appId}`;
15855
- }
15856
16129
  function AgentFileMentionPalette({
15857
16130
  state,
15858
16131
  highlightedKey,
@@ -15868,7 +16141,6 @@ function AgentFileMentionPalette({
15868
16141
  onSelectCategory,
15869
16142
  onSelectFilter,
15870
16143
  onExpandGroup,
15871
- onExpandWorkspaceAppReferences = () => void 0,
15872
16144
  onCycleFilter,
15873
16145
  onMoveSelection
15874
16146
  }) {
@@ -15879,7 +16151,7 @@ function AgentFileMentionPalette({
15879
16151
  const loadingHideTimerRef = useRef10(
15880
16152
  null
15881
16153
  );
15882
- const [loadingIndicatorVisible, setLoadingIndicatorVisible] = useState7(
16154
+ const [loadingIndicatorVisible, setLoadingIndicatorVisible] = useState8(
15883
16155
  state.status === "loading"
15884
16156
  );
15885
16157
  const browseFilter = state.filter;
@@ -15987,7 +16259,6 @@ function AgentFileMentionPalette({
15987
16259
  highlightedOptionRef,
15988
16260
  mode: state.mode,
15989
16261
  onExpandGroup,
15990
- onExpandWorkspaceAppReferences,
15991
16262
  onHighlightChange,
15992
16263
  onSelectItem,
15993
16264
  query: state.query
@@ -16048,7 +16319,6 @@ function AgentFileMentionPalette({
16048
16319
  highlightedOptionRef,
16049
16320
  mode: state.mode,
16050
16321
  onExpandGroup,
16051
- onExpandWorkspaceAppReferences,
16052
16322
  onHighlightChange,
16053
16323
  onSelectItem,
16054
16324
  query: state.query
@@ -16215,12 +16485,12 @@ function MentionPaletteScrollbar({
16215
16485
  "use memo";
16216
16486
  const trackRef = useRef10(null);
16217
16487
  const dragStateRef = useRef10(null);
16218
- const [scrollbarState, setScrollbarState] = useState7({
16488
+ const [scrollbarState, setScrollbarState] = useState8({
16219
16489
  scrollable: false,
16220
16490
  thumbHeight: 0,
16221
16491
  thumbTop: 0
16222
16492
  });
16223
- const [dragging, setDragging] = useState7(false);
16493
+ const [dragging, setDragging] = useState8(false);
16224
16494
  const hideScrollbar = useCallback7(() => {
16225
16495
  setScrollbarState(
16226
16496
  (previous) => previous.scrollable || previous.thumbHeight !== 0 || previous.thumbTop !== 0 ? MENTION_PALETTE_SCROLLBAR_HIDDEN_STATE : previous
@@ -16403,8 +16673,7 @@ function renderMentionPaletteGroups(input) {
16403
16673
  input.highlightedOptionRef,
16404
16674
  input.onHighlightChange,
16405
16675
  input.onSelectItem,
16406
- input.onExpandGroup,
16407
- input.onExpandWorkspaceAppReferences
16676
+ input.onExpandGroup
16408
16677
  ),
16409
16678
  shouldShowFileSearchMoreHint(input) ? /* @__PURE__ */ jsx25(MentionFileSearchMoreHint, {}) : null
16410
16679
  ] });
@@ -16420,7 +16689,7 @@ function MentionFileSearchMoreHint() {
16420
16689
  }
16421
16690
  );
16422
16691
  }
16423
- function renderMentionGroups(groups, query, filter, highlightedKey, highlightedOptionRef, onHighlightChange, onSelectItem, onExpandGroup, onExpandWorkspaceAppReferences) {
16692
+ function renderMentionGroups(groups, query, filter, highlightedKey, highlightedOptionRef, onHighlightChange, onSelectItem, onExpandGroup) {
16424
16693
  return groups.map((group, index) => {
16425
16694
  const followsMySessions = group.id === "collab_sessions" && groups[index - 1]?.id === "my_sessions";
16426
16695
  const showGroupLabel = shouldRenderMentionGroupLabel({
@@ -16447,82 +16716,26 @@ function renderMentionGroups(groups, query, filter, highlightedKey, highlightedO
16447
16716
  /* @__PURE__ */ jsxs10("div", { className: "grid gap-1", children: [
16448
16717
  group.items.length === 0 && !shouldSuppressFileSearchGroupChrome(filter, query) ? /* @__PURE__ */ jsx25("div", { className: "px-3 py-1 text-[13px] font-normal text-[var(--text-tertiary)]", children: agentMentionEmptyGroupLabel(group.id, query) }) : null,
16449
16718
  group.items.map((item) => {
16450
- const itemKey = mentionPaletteItemKey(group.id, item);
16719
+ const itemKey = `${group.id}:${item.kind}:${item.kind === "file" ? agentGeneratedMentionItemKey(item) : item.targetId}`;
16451
16720
  const isHighlighted = itemKey === highlightedKey;
16452
- return /* @__PURE__ */ jsxs10("div", { className: "grid gap-1", children: [
16453
- /* @__PURE__ */ jsx25(
16454
- "button",
16455
- {
16456
- ref: isHighlighted ? highlightedOptionRef : null,
16457
- type: "button",
16458
- className: cn(
16459
- paletteStyles2.rowButton,
16460
- isHighlighted && "bg-[var(--transparency-block)]"
16461
- ),
16462
- role: "option",
16463
- "aria-selected": isHighlighted,
16464
- onMouseEnter: () => onHighlightChange(itemKey),
16465
- onMouseDown: (event) => event.preventDefault(),
16466
- onClick: () => onSelectItem(item),
16467
- children: renderMentionRow(item)
16468
- }
16469
- ),
16470
- item.kind === "workspace-app" ? /* @__PURE__ */ jsxs10(Fragment5, { children: [
16471
- (item.referenceItems ?? []).map((referenceItem) => {
16472
- const referenceKey = mentionPaletteReferenceItemKey(
16473
- group.id,
16474
- item,
16475
- referenceItem
16476
- );
16477
- const isReferenceHighlighted = referenceKey === highlightedKey;
16478
- return /* @__PURE__ */ jsx25(
16479
- "button",
16480
- {
16481
- ref: isReferenceHighlighted ? highlightedOptionRef : null,
16482
- type: "button",
16483
- className: cn(
16484
- paletteStyles2.rowButton,
16485
- "pl-8",
16486
- isReferenceHighlighted && "bg-[var(--transparency-block)]"
16487
- ),
16488
- role: "option",
16489
- "aria-selected": isReferenceHighlighted,
16490
- onMouseEnter: () => onHighlightChange(referenceKey),
16491
- onMouseDown: (event) => event.preventDefault(),
16492
- onClick: () => onSelectItem(referenceItem),
16493
- children: renderMentionRow(referenceItem)
16494
- },
16495
- referenceKey
16496
- );
16497
- }),
16498
- item.referenceNextCursor ? /* @__PURE__ */ jsx25(
16499
- "button",
16500
- {
16501
- ref: mentionPaletteReferenceExpandKey(group.id, item) === highlightedKey ? highlightedOptionRef : null,
16502
- type: "button",
16503
- disabled: item.referenceItemsLoading === true,
16504
- className: cn(
16505
- paletteStyles2.expandButton,
16506
- "ml-8 w-[calc(100%-2rem)]",
16507
- item.referenceItemsLoading === true && "opacity-60",
16508
- mentionPaletteReferenceExpandKey(group.id, item) === highlightedKey && "bg-[var(--transparency-block)] text-[var(--text-primary)]"
16509
- ),
16510
- onMouseEnter: () => onHighlightChange(
16511
- mentionPaletteReferenceExpandKey(group.id, item)
16512
- ),
16513
- onMouseDown: (event) => event.preventDefault(),
16514
- onClick: () => onExpandWorkspaceAppReferences(item.appId),
16515
- children: translate(
16516
- "agentHost.agentGui.contextPickerExpandMore",
16517
- {
16518
- count: WORKSPACE_APP_REFERENCE_PAGE_SIZE
16519
- }
16520
- )
16521
- },
16522
- mentionPaletteReferenceExpandKey(group.id, item)
16523
- ) : null
16524
- ] }) : null
16525
- ] }, itemKey);
16721
+ return /* @__PURE__ */ jsx25(
16722
+ "button",
16723
+ {
16724
+ ref: isHighlighted ? highlightedOptionRef : null,
16725
+ type: "button",
16726
+ className: cn(
16727
+ paletteStyles2.rowButton,
16728
+ isHighlighted && "bg-[var(--transparency-block)]"
16729
+ ),
16730
+ role: "option",
16731
+ "aria-selected": isHighlighted,
16732
+ onMouseEnter: () => onHighlightChange(itemKey),
16733
+ onMouseDown: (event) => event.preventDefault(),
16734
+ onClick: () => onSelectItem(item),
16735
+ children: renderMentionRow(item)
16736
+ },
16737
+ itemKey
16738
+ );
16526
16739
  }),
16527
16740
  group.hasMore ? /* @__PURE__ */ jsx25(
16528
16741
  "button",
@@ -17170,27 +17383,27 @@ function AgentComposer({
17170
17383
  richTextAtProviders = EMPTY_RICH_TEXT_AT_PROVIDERS
17171
17384
  }) {
17172
17385
  "use memo";
17173
- const [isPaletteOpen, setIsPaletteOpen] = useState8(true);
17174
- const [highlightedIndex, setHighlightedIndex] = useState8(0);
17175
- const [mentionHighlightedKey, setMentionHighlightedKey] = useState8(null);
17176
- const [shouldCenterMentionHighlight, setShouldCenterMentionHighlight] = useState8(false);
17386
+ const [isPaletteOpen, setIsPaletteOpen] = useState9(true);
17387
+ const [highlightedIndex, setHighlightedIndex] = useState9(0);
17388
+ const [mentionHighlightedKey, setMentionHighlightedKey] = useState9(null);
17389
+ const [shouldCenterMentionHighlight, setShouldCenterMentionHighlight] = useState9(false);
17177
17390
  const [
17178
17391
  shouldResetMentionHighlightToFilter,
17179
17392
  setShouldResetMentionHighlightToFilter
17180
- ] = useState8(false);
17181
- const [paletteDraftPrompt, setPaletteDraftPrompt] = useState8(draftPrompt);
17182
- const [fileMentionSuggestion, setFileMentionSuggestion] = useState8(null);
17183
- const [isSelectedProjectMissing, setIsSelectedProjectMissing] = useState8(false);
17184
- const [draftImages, setDraftImages] = useState8([]);
17185
- const [submittedImagePreview, setSubmittedImagePreview] = useState8([]);
17186
- const [isSlashStatusPanelOpen, setIsSlashStatusPanelOpen] = useState8(false);
17393
+ ] = useState9(false);
17394
+ const [paletteDraftPrompt, setPaletteDraftPrompt] = useState9(draftPrompt);
17395
+ const [fileMentionSuggestion, setFileMentionSuggestion] = useState9(null);
17396
+ const [isSelectedProjectMissing, setIsSelectedProjectMissing] = useState9(false);
17397
+ const [draftImages, setDraftImages] = useState9([]);
17398
+ const [submittedImagePreview, setSubmittedImagePreview] = useState9([]);
17399
+ const [isSlashStatusPanelOpen, setIsSlashStatusPanelOpen] = useState9(false);
17187
17400
  const slashStatusAgentSessionId = slashStatus?.agentSessionId ?? null;
17188
17401
  const previousSlashStatusAgentSessionIdRef = useRef11(
17189
17402
  slashStatusAgentSessionId
17190
17403
  );
17191
17404
  const selectedProjectPath = composerSettings.selectedProjectPath?.trim() ?? "";
17192
17405
  const previousSelectedProjectPathRef = useRef11(selectedProjectPath);
17193
- const [mentionSearchState, setMentionSearchState] = useState8({
17406
+ const [mentionSearchState, setMentionSearchState] = useState9({
17194
17407
  status: "idle",
17195
17408
  query: "",
17196
17409
  mode: "browse",
@@ -17212,7 +17425,7 @@ function AgentComposer({
17212
17425
  const wasActiveRef = useRef11(isActive);
17213
17426
  const lastComposerFocusRequestRef = useRef11(null);
17214
17427
  const autoMentionHighlightedKeyRef = useRef11(null);
17215
- const [isPromptTipOverflowing, setIsPromptTipOverflowing] = useState8(false);
17428
+ const [isPromptTipOverflowing, setIsPromptTipOverflowing] = useState9(false);
17216
17429
  const slashQuery = getSlashCommandQuery(paletteDraftPrompt);
17217
17430
  const promptBeforeSelection = editorHandleRef.current?.getPromptTextBeforeSelection() ?? "";
17218
17431
  const skillQueryDraft = promptBeforeSelection || paletteDraftPrompt;
@@ -17276,8 +17489,8 @@ function AgentComposer({
17276
17489
  () => flattenAgentMentionPaletteEntries(mentionSearchState),
17277
17490
  [mentionSearchState]
17278
17491
  );
17279
- const [mentionPaletteFrame, setMentionPaletteFrame] = useState8(null);
17280
- const [slashPaletteFrame, setSlashPaletteFrame] = useState8(null);
17492
+ const [mentionPaletteFrame, setMentionPaletteFrame] = useState9(null);
17493
+ const [slashPaletteFrame, setSlashPaletteFrame] = useState9(null);
17281
17494
  useEffect10(() => {
17282
17495
  setHighlightedIndex(0);
17283
17496
  }, [skillQueryMatch?.prefix, skillQueryMatch?.query, slashQuery]);
@@ -17365,6 +17578,16 @@ function AgentComposer({
17365
17578
  });
17366
17579
  return;
17367
17580
  }
17581
+ if (effect.kind === "toggleSpeed") {
17582
+ clearSlashCommandDraft();
17583
+ if (composerSettings.supportsSpeed) {
17584
+ const currentSpeed = composerSettings.selectedSpeedValue ?? composerSettings.draftSettings.speed ?? "standard";
17585
+ onSettingsChange({
17586
+ speed: currentSpeed === "fast" ? "standard" : "fast"
17587
+ });
17588
+ }
17589
+ return;
17590
+ }
17368
17591
  const nextDraft = effect.draft;
17369
17592
  draftPromptRef.current = nextDraft;
17370
17593
  setPaletteDraftPrompt(nextDraft);
@@ -17374,6 +17597,9 @@ function AgentComposer({
17374
17597
  [
17375
17598
  clearSlashCommandDraft,
17376
17599
  composerSettings.draftSettings.planMode,
17600
+ composerSettings.draftSettings.speed,
17601
+ composerSettings.selectedSpeedValue,
17602
+ composerSettings.supportsSpeed,
17377
17603
  onDraftChange,
17378
17604
  onSettingsChange,
17379
17605
  onSubmit
@@ -17445,6 +17671,9 @@ function AgentComposer({
17445
17671
  setSubmittedImagePreview([]);
17446
17672
  submittedImagePreviewObservedBusyRef.current = false;
17447
17673
  }
17674
+ draftPromptRef.current = "";
17675
+ setPaletteDraftPrompt("");
17676
+ onDraftChange("");
17448
17677
  setDraftImages([]);
17449
17678
  };
17450
17679
  const submit = (event) => {
@@ -17615,10 +17844,6 @@ function AgentComposer({
17615
17844
  mentionControllerRef.current?.setFilter(activeEntry.categoryId);
17616
17845
  } else if (activeEntry.type === "expand" && activeEntry.groupId) {
17617
17846
  mentionControllerRef.current?.expandGroup(activeEntry.groupId);
17618
- } else if (activeEntry.type === "app-reference-expand" && activeEntry.appId) {
17619
- mentionControllerRef.current?.expandWorkspaceAppReferences(
17620
- activeEntry.appId
17621
- );
17622
17847
  } else if (activeEntry.type === "item" && activeEntry.item) {
17623
17848
  selectFileMention(activeEntry.item);
17624
17849
  }
@@ -18148,7 +18373,7 @@ function AgentComposer({
18148
18373
  const sendButtonBusy = isSendingTurn && !isQueueMode;
18149
18374
  const settingsControlsDisabled = isSendingTurn || isSubmittingPrompt || showStopButton;
18150
18375
  const activePromptRequestId = activePrompt?.requestId ?? null;
18151
- const [dismissedPromptRequestId, setDismissedPromptRequestId] = useState8(null);
18376
+ const [dismissedPromptRequestId, setDismissedPromptRequestId] = useState9(null);
18152
18377
  const visibleActivePrompt = activePrompt && dismissedPromptRequestId !== activePromptRequestId ? activePrompt : null;
18153
18378
  const disabledReasonText = disabledReason?.trim() ?? "";
18154
18379
  const effectivePlaceholder = disabledReasonText || placeholder;
@@ -18429,9 +18654,6 @@ function AgentComposer({
18429
18654
  onSelectCategory: (filter) => mentionControllerRef.current?.setFilter(filter),
18430
18655
  onSelectFilter: (filter) => mentionControllerRef.current?.setFilter(filter),
18431
18656
  onExpandGroup: (groupId) => mentionControllerRef.current?.expandGroup(groupId),
18432
- onExpandWorkspaceAppReferences: (appId) => mentionControllerRef.current?.expandWorkspaceAppReferences(
18433
- appId
18434
- ),
18435
18657
  onCycleFilter: cycleFileMentionFilter,
18436
18658
  onMoveSelection: moveFileMentionSelection
18437
18659
  }
@@ -18473,7 +18695,7 @@ function AgentComposer({
18473
18695
  }
18474
18696
  ),
18475
18697
  /* @__PURE__ */ jsxs11("div", { className: AgentGUINode_styles_default.composerFooter, children: [
18476
- /* @__PURE__ */ jsx26("div", { className: composerStyles.footerGroup, children: /* @__PURE__ */ jsxs11(
18698
+ /* @__PURE__ */ jsx26("div", { className: composerStyles.footerGroup, children: /* @__PURE__ */ jsx26(
18477
18699
  Select2,
18478
18700
  {
18479
18701
  open: false,
@@ -18489,47 +18711,27 @@ function AgentComposer({
18489
18711
  void handleWorkspaceReferencePicker();
18490
18712
  }
18491
18713
  },
18492
- children: [
18493
- /* @__PURE__ */ jsx26(
18494
- SelectTrigger2,
18495
- {
18496
- size: "sm",
18497
- "aria-label": labels.referenceWorkspaceFiles,
18498
- title: labels.referenceWorkspaceFiles,
18499
- className: cn(
18500
- AgentGUINode_styles_default.composerMenuTrigger,
18501
- AgentGUINode_styles_default.composerReferenceTrigger,
18502
- "w-auto justify-center px-1 text-[var(--agent-gui-text-secondary)] [&>svg:last-child]:hidden [&_svg]:shrink-0"
18503
- ),
18504
- children: /* @__PURE__ */ jsx26(
18505
- AddIcon,
18506
- {
18507
- "aria-hidden": true,
18508
- className: "size-3.5",
18509
- "data-agent-reference-add-icon": "true"
18510
- }
18511
- )
18512
- }
18513
- ),
18514
- /* @__PURE__ */ jsx26(
18515
- SelectContent2,
18516
- {
18517
- align: "start",
18518
- side: "top",
18519
- sideOffset: 8,
18520
- collisionPadding: 16,
18521
- className: cn(AgentGUINode_styles_default.composerMenuContent, "min-w-[180px]"),
18522
- children: /* @__PURE__ */ jsx26(
18523
- SelectItem2,
18524
- {
18525
- value: workspaceReferenceOptionValue,
18526
- className: AgentGUINode_styles_default.composerMenuItem,
18527
- children: labels.referenceWorkspaceFiles
18528
- }
18529
- )
18530
- }
18531
- )
18532
- ]
18714
+ children: /* @__PURE__ */ jsx26(
18715
+ SelectTrigger2,
18716
+ {
18717
+ size: "sm",
18718
+ "aria-label": labels.referenceWorkspaceFiles,
18719
+ title: labels.referenceWorkspaceFiles,
18720
+ className: cn(
18721
+ AgentGUINode_styles_default.composerMenuTrigger,
18722
+ AgentGUINode_styles_default.composerReferenceTrigger,
18723
+ "w-auto justify-center px-1 text-[var(--agent-gui-text-secondary)] [&>svg:last-child]:hidden [&_svg]:shrink-0"
18724
+ ),
18725
+ children: /* @__PURE__ */ jsx26(
18726
+ AddIcon,
18727
+ {
18728
+ "aria-hidden": true,
18729
+ className: "size-3.5",
18730
+ "data-agent-reference-add-icon": "true"
18731
+ }
18732
+ )
18733
+ }
18734
+ )
18533
18735
  }
18534
18736
  ) }),
18535
18737
  /* @__PURE__ */ jsxs11("div", { className: composerStyles.footerGroupRight, children: [
@@ -18561,6 +18763,10 @@ function AgentComposer({
18561
18763
  reasoningOptionMedium: labels.reasoningOptionMedium,
18562
18764
  reasoningOptionHigh: labels.reasoningOptionHigh,
18563
18765
  reasoningOptionXHigh: labels.reasoningOptionXHigh,
18766
+ speedLabel: labels.speedLabel,
18767
+ speedSelectionLabel: labels.speedSelectionLabel,
18768
+ speedOptionStandard: labels.speedOptionStandard,
18769
+ speedOptionFast: labels.speedOptionFast,
18564
18770
  permissionLabel: labels.permissionLabel,
18565
18771
  modelDescriptions: labels.modelDescriptions,
18566
18772
  defaultModel: labels.defaultModel,
@@ -19270,12 +19476,12 @@ function AgentGUINodeView({
19270
19476
  }) {
19271
19477
  "use memo";
19272
19478
  const railResizeInteractionRef = useRef12(null);
19273
- const [isRailResizing, setIsRailResizing] = useState9(false);
19274
- const [workspaceReferencePickerOpen, setWorkspaceReferencePickerOpen] = useState9(false);
19479
+ const [isRailResizing, setIsRailResizing] = useState10(false);
19480
+ const [workspaceReferencePickerOpen, setWorkspaceReferencePickerOpen] = useState10(false);
19275
19481
  const [
19276
19482
  localComposerFocusRequestSequence,
19277
19483
  setLocalComposerFocusRequestSequence
19278
- ] = useState9(0);
19484
+ ] = useState10(0);
19279
19485
  const workspaceReferencePickerResolverRef = useRef12(null);
19280
19486
  const requestWorkspaceReferences = useCallback9(async () => {
19281
19487
  if (previewMode) {
@@ -19605,7 +19811,7 @@ var AgentGUIDetailPane = memo(function AgentGUIDetailPane2({
19605
19811
  const [
19606
19812
  bottomDockDismissedPromptRequestId,
19607
19813
  setBottomDockDismissedPromptRequestId
19608
- ] = useState9(null);
19814
+ ] = useState10(null);
19609
19815
  const conversation = useProjectedAgentConversation({
19610
19816
  conversation: viewModel.conversation,
19611
19817
  detail: viewModel.conversationDetail,
@@ -19807,6 +20013,10 @@ var AgentGUIDetailPane = memo(function AgentGUIDetailPane2({
19807
20013
  reasoningOptionMedium: labels.reasoningOptionMedium,
19808
20014
  reasoningOptionHigh: labels.reasoningOptionHigh,
19809
20015
  reasoningOptionXHigh: labels.reasoningOptionXHigh,
20016
+ speedLabel: labels.speedLabel,
20017
+ speedSelectionLabel: labels.speedSelectionLabel,
20018
+ speedOptionStandard: labels.speedOptionStandard,
20019
+ speedOptionFast: labels.speedOptionFast,
19810
20020
  permissionLabel: labels.permissionLabel,
19811
20021
  permissionModeReadOnly: labels.permissionModeReadOnly,
19812
20022
  permissionModeAuto: labels.permissionModeAuto,
@@ -19887,6 +20097,10 @@ var AgentGUIDetailPane = memo(function AgentGUIDetailPane2({
19887
20097
  labels.reasoningOptionMedium,
19888
20098
  labels.reasoningOptionMinimal,
19889
20099
  labels.reasoningOptionXHigh,
20100
+ labels.speedLabel,
20101
+ labels.speedSelectionLabel,
20102
+ labels.speedOptionStandard,
20103
+ labels.speedOptionFast,
19890
20104
  labels.send,
19891
20105
  labels.sendQueuedPromptNext,
19892
20106
  labels.slashCommandPalette,
@@ -20432,7 +20646,7 @@ function AgentGUICompactButton({
20432
20646
  onSubmitCompact
20433
20647
  }) {
20434
20648
  "use memo";
20435
- const [pendingConversationId, setPendingConversationId] = useState9(null);
20649
+ const [pendingConversationId, setPendingConversationId] = useState10(null);
20436
20650
  const lastStatusRef = useRef12(status);
20437
20651
  useEffect11(() => {
20438
20652
  const previousStatus = lastStatusRef.current;
@@ -20812,10 +21026,10 @@ var AgentGUIConversationRailPane = memo(
20812
21026
  onConfirmDeleteConversation
20813
21027
  }) {
20814
21028
  "use memo";
20815
- const [conversationQuery, setConversationQuery] = useState9("");
20816
- const [collapsedProjectSectionIds, setCollapsedProjectSectionIds] = useState9(() => /* @__PURE__ */ new Set());
20817
- const [currentTimeMs, setCurrentTimeMs] = useState9(() => Date.now());
20818
- const [pendingProjectAction, setPendingProjectAction] = useState9(null);
21029
+ const [conversationQuery, setConversationQuery] = useState10("");
21030
+ const [collapsedProjectSectionIds, setCollapsedProjectSectionIds] = useState10(() => /* @__PURE__ */ new Set());
21031
+ const [currentTimeMs, setCurrentTimeMs] = useState10(() => Date.now());
21032
+ const [pendingProjectAction, setPendingProjectAction] = useState10(null);
20819
21033
  const railElementRef = useRef12(null);
20820
21034
  const conversationListRef = useRef12(null);
20821
21035
  const conversationItemElementsRef = useRef12(
@@ -21551,7 +21765,7 @@ import {
21551
21765
  useEffect as useEffect12,
21552
21766
  useLayoutEffect as useLayoutEffect5,
21553
21767
  useRef as useRef13,
21554
- useState as useState10
21768
+ useState as useState11
21555
21769
  } from "react";
21556
21770
  import { createPortal as createPortal2 } from "react-dom";
21557
21771
  import { Fragment as Fragment10, jsx as jsx30, jsxs as jsxs14 } from "react/jsx-runtime";
@@ -21589,8 +21803,8 @@ function AgentProbeInfoPopover({
21589
21803
  "use memo";
21590
21804
  const anchorRef = useRef13(null);
21591
21805
  const popoverRef = useRef13(null);
21592
- const [isOpen, setIsOpen] = useState10(false);
21593
- const [popoverStyle, setPopoverStyle] = useState10(null);
21806
+ const [isOpen, setIsOpen] = useState11(false);
21807
+ const [popoverStyle, setPopoverStyle] = useState11(null);
21594
21808
  const closeIfPointerLeavesPopover = useCallback10((event) => {
21595
21809
  const nextTarget = event.relatedTarget;
21596
21810
  if (nextTarget instanceof Node && (anchorRef.current?.contains(nextTarget) || popoverRef.current?.contains(nextTarget))) {
@@ -22231,6 +22445,10 @@ var AgentGUINode = memo2(function AgentGUINode2({
22231
22445
  reasoningOptionMedium: t("agentHost.agentGui.reasoningOptionMedium"),
22232
22446
  reasoningOptionHigh: t("agentHost.agentGui.reasoningOptionHigh"),
22233
22447
  reasoningOptionXHigh: t("agentHost.agentGui.reasoningOptionXHigh"),
22448
+ speedLabel: t("agentHost.agentGui.speedLabel"),
22449
+ speedSelectionLabel: t("agentHost.agentGui.speedSelectionLabel"),
22450
+ speedOptionStandard: t("agentHost.agentGui.speedOptionStandard"),
22451
+ speedOptionFast: t("agentHost.agentGui.speedOptionFast"),
22234
22452
  permissionLabel: t("agentHost.agentGui.permissionLabel"),
22235
22453
  permissionModeReadOnly: t("agentHost.agentGui.permissionModeReadOnly"),
22236
22454
  permissionModeAuto: t("agentHost.agentGui.permissionModeAuto"),