@tutti-os/agent-gui 0.0.18 → 0.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/{AgentMentionSearchController-DqssJ2-b.d.ts → AgentMentionSearchController-2Vjvmzh3.d.ts} +0 -1
  2. package/dist/agent-conversation/index.d.ts +2 -2
  3. package/dist/agent-conversation/index.js +4 -4
  4. package/dist/agent-message-center/index.d.ts +1 -1
  5. package/dist/agent-message-center/index.js +3 -3
  6. package/dist/{agentConversationVM-BVe64P2E.d.ts → agentConversationVM-D09Aw-Ei.d.ts} +4 -0
  7. package/dist/{chunk-FEWMACBN.js → chunk-5H4ISRJQ.js} +3 -3
  8. package/dist/{chunk-4RUK7VPA.js → chunk-7IFIA3DC.js} +35 -13
  9. package/dist/chunk-7IFIA3DC.js.map +1 -0
  10. package/dist/{chunk-S5GS4GRM.js → chunk-7THDJWRR.js} +32 -48
  11. package/dist/chunk-7THDJWRR.js.map +1 -0
  12. package/dist/{chunk-DT4W5Z2A.js → chunk-DIBNU26G.js} +32 -11
  13. package/dist/chunk-DIBNU26G.js.map +1 -0
  14. package/dist/{chunk-O5TUTXHT.js → chunk-IEBWFP7O.js} +1 -1
  15. package/dist/chunk-IEBWFP7O.js.map +1 -0
  16. package/dist/{chunk-HIREVEZM.js → chunk-JM24HADP.js} +1 -1
  17. package/dist/chunk-JM24HADP.js.map +1 -0
  18. package/dist/{chunk-5Z5HILKT.js → chunk-XAQQN6MP.js} +50 -184
  19. package/dist/chunk-XAQQN6MP.js.map +1 -0
  20. package/dist/context-mention-palette/index.d.ts +2 -2
  21. package/dist/context-mention-palette/index.js +4 -4
  22. package/dist/context-mention-provider.d.ts +4 -40
  23. package/dist/context-mention-provider.js +1 -1
  24. package/dist/index.d.ts +38 -3
  25. package/dist/index.js +229 -50
  26. package/dist/index.js.map +1 -1
  27. package/dist/plan-decision-ops.d.ts +1 -1
  28. package/package.json +12 -12
  29. package/dist/chunk-4RUK7VPA.js.map +0 -1
  30. package/dist/chunk-5Z5HILKT.js.map +0 -1
  31. package/dist/chunk-DT4W5Z2A.js.map +0 -1
  32. package/dist/chunk-HIREVEZM.js.map +0 -1
  33. package/dist/chunk-O5TUTXHT.js.map +0 -1
  34. package/dist/chunk-S5GS4GRM.js.map +0 -1
  35. /package/dist/{chunk-FEWMACBN.js.map → chunk-5H4ISRJQ.js.map} +0 -0
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  import {
14
14
  AgentInteractivePromptSurface,
15
15
  approvalOptionDisplayLabel
16
- } from "./chunk-FEWMACBN.js";
16
+ } from "./chunk-5H4ISRJQ.js";
17
17
  import {
18
18
  PLAN_IMPLEMENTATION_ACTION_FEEDBACK,
19
19
  PLAN_IMPLEMENTATION_ACTION_IMPLEMENT,
@@ -37,12 +37,13 @@ import {
37
37
  skillDescriptionForDisplay,
38
38
  skillTriggerForPrefix,
39
39
  useProjectedAgentConversation
40
- } from "./chunk-DT4W5Z2A.js";
40
+ } from "./chunk-DIBNU26G.js";
41
41
  import {
42
42
  AgentMessageMarkdown,
43
+ ZoomableImage,
43
44
  cn,
44
45
  resolveWorkspaceLinkAction
45
- } from "./chunk-S5GS4GRM.js";
46
+ } from "./chunk-7THDJWRR.js";
46
47
  import {
47
48
  AGENT_MENTION_FILTER_TAB_ORDER,
48
49
  AgentFileMentionPalette,
@@ -50,7 +51,7 @@ import {
50
51
  DEFAULT_AGENT_MENTION_FILTER,
51
52
  flattenAgentMentionPaletteEntries,
52
53
  preloadAgentMentionBrowse
53
- } from "./chunk-4RUK7VPA.js";
54
+ } from "./chunk-7IFIA3DC.js";
54
55
  import {
55
56
  WORKSPACE_AGENT_ACTIVITY_RUNTIME_SESSION_ORIGIN,
56
57
  buildWorkspaceAgentActivityListViewModel,
@@ -71,14 +72,12 @@ import {
71
72
  resolveWorkspaceAgentSessionSortTimeUnixMs
72
73
  } from "./chunk-IBIMGLCD.js";
73
74
  import {
74
- buildAgentSessionMentionHref,
75
- buildAgentWorkspaceReferenceMentionHref,
76
75
  exitAgentFileMentionSuggestion,
77
76
  formatAgentMentionMarkdown,
78
77
  mentionItemToAttrs,
79
78
  normalizeAgentSessionMentionTitle,
80
79
  parseMentionItemFromHref
81
- } from "./chunk-5Z5HILKT.js";
80
+ } from "./chunk-XAQQN6MP.js";
82
81
  import "./chunk-XJ34OIEQ.js";
83
82
  import {
84
83
  AgentActivityHostProvider,
@@ -92,11 +91,11 @@ import {
92
91
  useAgentActivitySnapshot,
93
92
  useAgentHostApi,
94
93
  useOptionalAgentActivityRuntime
95
- } from "./chunk-O5TUTXHT.js";
94
+ } from "./chunk-IEBWFP7O.js";
96
95
  import "./chunk-TYGL25EL.js";
97
96
  import {
98
97
  AGENT_CONTEXT_MENTION_PROVIDER_IDS
99
- } from "./chunk-HIREVEZM.js";
98
+ } from "./chunk-JM24HADP.js";
100
99
  import {
101
100
  normalizeAgentTitleText
102
101
  } from "./chunk-GCBDIQDX.js";
@@ -3171,13 +3170,17 @@ function normalizeAgentPromptContentBlocks(content) {
3171
3170
  if (block.type === "image") {
3172
3171
  const mimeType = block.mimeType?.trim();
3173
3172
  const data = block.data?.trim();
3174
- if (!data || mimeType !== "image/png" && mimeType !== "image/jpeg" && mimeType !== "image/webp") {
3173
+ const imagePath = block.path?.trim();
3174
+ if (!data && !imagePath || mimeType !== "image/png" && mimeType !== "image/jpeg" && mimeType !== "image/webp") {
3175
3175
  continue;
3176
3176
  }
3177
3177
  result.push({
3178
3178
  type: "image",
3179
3179
  mimeType,
3180
- data,
3180
+ ...imagePath ? { path: imagePath } : { data },
3181
+ ...block.uri?.trim() ? { uri: block.uri.trim() } : {},
3182
+ ...block.uploadStatus?.trim() ? { uploadStatus: block.uploadStatus.trim() } : {},
3183
+ ...block.assetId?.trim() ? { assetId: block.assetId.trim() } : {},
3181
3184
  ...block.name?.trim() ? { name: block.name.trim() } : {}
3182
3185
  });
3183
3186
  continue;
@@ -3200,7 +3203,7 @@ function agentPromptContentHasImage(content) {
3200
3203
  }
3201
3204
  function agentPromptContentImageBlocks(content) {
3202
3205
  return normalizeAgentPromptContentBlocks(content).filter(
3203
- (block) => block.type === "image" && typeof block.data === "string" && typeof block.mimeType === "string"
3206
+ (block) => block.type === "image" && (typeof block.data === "string" || typeof block.path === "string") && typeof block.mimeType === "string"
3204
3207
  );
3205
3208
  }
3206
3209
  function agentPromptContentToComposerDraft(content, idPrefix) {
@@ -3225,10 +3228,13 @@ function agentComposerDraftToPromptContent(input) {
3225
3228
  provider: input.provider,
3226
3229
  skills: input.skills
3227
3230
  }),
3228
- ...input.draft.images.slice(0, MAX_AGENT_COMPOSER_DRAFT_IMAGES).map((image) => ({
3231
+ ...input.draft.images.slice(0, MAX_AGENT_COMPOSER_DRAFT_IMAGES).filter((image) => !image.uploading && !image.uploadError).map((image) => ({
3229
3232
  type: "image",
3230
3233
  mimeType: image.mimeType,
3231
- data: image.data,
3234
+ ...image.path ? { path: image.path } : { data: image.data },
3235
+ ...image.uri ? { uri: image.uri } : {},
3236
+ ...image.uploadStatus ? { uploadStatus: image.uploadStatus } : {},
3237
+ ...image.assetId ? { assetId: image.assetId } : {},
3232
3238
  name: image.name
3233
3239
  }))
3234
3240
  ]);
@@ -3271,7 +3277,11 @@ function agentPromptImageBlockToDraftImage(image, idPrefix, index) {
3271
3277
  name: image.name?.trim() || `image-${index + 1}`,
3272
3278
  mimeType: image.mimeType,
3273
3279
  data: image.data,
3274
- previewUrl: `data:${image.mimeType};base64,${image.data}`
3280
+ path: image.path,
3281
+ uri: image.uri,
3282
+ uploadStatus: image.uploadStatus,
3283
+ assetId: image.assetId,
3284
+ previewUrl: typeof image.data === "string" && image.data ? `data:${image.mimeType};base64,${image.data}` : image.path ?? ""
3275
3285
  };
3276
3286
  }
3277
3287
 
@@ -5846,6 +5856,9 @@ function useAgentGUIActivation({
5846
5856
  );
5847
5857
  }
5848
5858
 
5859
+ // agent-gui/agentGuiNode/controller/useAgentGUINodeController.ts
5860
+ import { createRichTextMentionHref } from "@tutti-os/ui-rich-text/core";
5861
+
5849
5862
  // agent-gui/agentGuiNode/model/composerSettingsSupport.ts
5850
5863
  import {
5851
5864
  resolveAgentActivityCapability
@@ -6340,11 +6353,12 @@ function buildContinueInNewConversationPrompt(input) {
6340
6353
  const normalizedCurrentUserId = input.currentUserId?.trim() ?? "";
6341
6354
  const initiatorName = normalizedConversationUserId && input.userProfilesByUserId[normalizedConversationUserId]?.name?.trim() || normalizedCurrentUserId && input.userProfilesByUserId[normalizedCurrentUserId]?.name?.trim() || normalizedConversationUserId || normalizedCurrentUserId || translate("messages.agentThisSessionMentionLabel").trim();
6342
6355
  const mentionLabel = `${initiatorName} & ${providerLabel}${normalizedTitle ? ` ${normalizedTitle}` : ""}`.trim();
6343
- const href = buildAgentSessionMentionHref(
6344
- input.workspaceId,
6345
- input.agentSessionId,
6346
- input.provider
6347
- );
6356
+ const href = createRichTextMentionHref({
6357
+ providerId: "agent-session",
6358
+ entityId: input.agentSessionId,
6359
+ label: mentionLabel,
6360
+ scope: { workspaceId: input.workspaceId }
6361
+ });
6348
6362
  const mention = formatAgentMentionMarkdown({
6349
6363
  kind: "session",
6350
6364
  href,
@@ -6658,6 +6672,20 @@ function normalizeOptionalText2(value) {
6658
6672
  const trimmed = value.trim();
6659
6673
  return trimmed ? trimmed : null;
6660
6674
  }
6675
+ function resolveSameProviderActiveSessionModel(input) {
6676
+ const agentSessionId = normalizeOptionalText2(input.agentSessionId);
6677
+ if (agentSessionId === null) {
6678
+ return null;
6679
+ }
6680
+ const runtimeSession = input.runtime.getSnapshot(input.workspaceId).sessions.find(
6681
+ (candidate) => candidate.agentSessionId.trim() === agentSessionId
6682
+ ) ?? null;
6683
+ const activeProvider = normalizeOptionalText2(runtimeSession?.provider) ?? normalizeOptionalText2(input.activeProvider);
6684
+ if (activeProvider !== input.provider) {
6685
+ return null;
6686
+ }
6687
+ return normalizeOptionalText2(input.sessionState?.settings?.model) ?? normalizeOptionalText2(runtimeSession?.model);
6688
+ }
6661
6689
  function normalizeOptionalPrompt(value) {
6662
6690
  return typeof value === "string" ? value.trim() : "";
6663
6691
  }
@@ -7534,6 +7562,7 @@ function useAgentGUINodeController({
7534
7562
  const startingConversationIdRef = useRef4(null);
7535
7563
  const activatedConversationIdsRef = useRef4(/* @__PURE__ */ new Set());
7536
7564
  const failedNewConversationIdsRef = useRef4(/* @__PURE__ */ new Set());
7565
+ const lastActiveModelByProviderRef = useRef4({});
7537
7566
  const pendingTurnIdBySessionIdRef = useRef4({});
7538
7567
  const conversationIdsRef = useRef4(
7539
7568
  new Set(conversations.map((conversation2) => conversation2.id))
@@ -9136,6 +9165,23 @@ function useAgentGUINodeController({
9136
9165
  const initialSettings = resolveEffectiveComposerSettings({
9137
9166
  settings: initialNodeSettings
9138
9167
  });
9168
+ const currentActiveConversationId = activeConversationIdRef.current;
9169
+ const currentActiveConversation = currentActiveConversationId ? resolveConversationSummaryById(
9170
+ conversationsRef.current,
9171
+ currentActiveConversationId,
9172
+ transientConversationRef.current
9173
+ ) : null;
9174
+ const inheritedModel = normalizeOptionalText2(initialNodeSettings.model) === null ? resolveSameProviderActiveSessionModel({
9175
+ activeProvider: currentActiveConversation?.provider ?? null,
9176
+ agentSessionId: currentActiveConversationId,
9177
+ provider,
9178
+ runtime: agentActivityRuntime,
9179
+ sessionState: activeSessionState,
9180
+ workspaceId
9181
+ }) ?? normalizeOptionalText2(
9182
+ lastActiveModelByProviderRef.current[provider]
9183
+ ) : null;
9184
+ const effectiveInitialSettings = inheritedModel === null ? initialSettings : { ...initialSettings, model: inheritedModel };
9139
9185
  const snapshotComposerOptions = agentActivityRuntime.getSnapshot(workspaceId).composerOptionsByProvider?.[provider] ?? null;
9140
9186
  const snapshotDraftAgentSessionId = normalizedInitialContent.length > 0 && provider === "claude-code" ? draftAgentSessionIdFromComposerOptions(snapshotComposerOptions) : null;
9141
9187
  const draftAgentSessionId = snapshotDraftAgentSessionId && !activatedConversationIdsRef.current.has(
@@ -9175,11 +9221,11 @@ function useAgentGUINodeController({
9175
9221
  startingConversationIdRef.current = agentSessionId;
9176
9222
  draftSettingsBySessionIdRef.current = {
9177
9223
  ...draftSettingsBySessionIdRef.current,
9178
- [agentSessionId]: initialSettings
9224
+ [agentSessionId]: effectiveInitialSettings
9179
9225
  };
9180
9226
  setDraftSettingsBySessionId((current) => ({
9181
9227
  ...current,
9182
- [agentSessionId]: initialSettings
9228
+ [agentSessionId]: effectiveInitialSettings
9183
9229
  }));
9184
9230
  setIsLoadingMessages(true);
9185
9231
  return activation.activate({
@@ -9190,7 +9236,7 @@ function useAgentGUINodeController({
9190
9236
  initialContent: normalizedInitialContent,
9191
9237
  initialDisplayPrompt,
9192
9238
  title: initialConversationTitle,
9193
- settings: initialSettings,
9239
+ settings: effectiveInitialSettings,
9194
9240
  openclawGatewayReady: provider === "openclaw" ? openclawGateway?.status === "ready" : void 0
9195
9241
  });
9196
9242
  })().then((result) => {
@@ -9346,6 +9392,7 @@ function useAgentGUINodeController({
9346
9392
  });
9347
9393
  },
9348
9394
  [
9395
+ activeSessionState,
9349
9396
  currentUserId,
9350
9397
  data,
9351
9398
  defaultReasoningEffort,
@@ -11395,6 +11442,27 @@ function useAgentGUINodeController({
11395
11442
  ) : null;
11396
11443
  const pendingInteractivePrompt = serverInteractivePrompt ?? planImplementationPromptVM;
11397
11444
  const activeRuntimeSession = runtimeSessionsBySessionId.get(activeConversationId ?? "") ?? null;
11445
+ useEffect4(() => {
11446
+ const provider = normalizeOptionalText2(
11447
+ activeRuntimeSession?.provider ?? activeConversation?.provider
11448
+ );
11449
+ if (provider === null) {
11450
+ return;
11451
+ }
11452
+ const model = normalizeOptionalText2(activeSessionState?.settings?.model) ?? normalizeOptionalText2(activeRuntimeSession?.model);
11453
+ if (model === null) {
11454
+ return;
11455
+ }
11456
+ lastActiveModelByProviderRef.current = {
11457
+ ...lastActiveModelByProviderRef.current,
11458
+ [provider]: model
11459
+ };
11460
+ }, [
11461
+ activeConversation?.provider,
11462
+ activeRuntimeSession?.model,
11463
+ activeRuntimeSession?.provider,
11464
+ activeSessionState?.settings?.model
11465
+ ]);
11398
11466
  const activeActivityDisplayStatus = activeConversationId ? agentActivityDisplayStatuses.get(activeConversationId) ?? null : null;
11399
11467
  const activeHasPendingSubmittedTurn = activeConversationId ? Boolean(pendingTurnIdBySessionIdRef.current[activeConversationId]) : false;
11400
11468
  const activeConversationBusy = agentActivityDisplayStatusBusy(activeActivityDisplayStatus) || activeHasPendingSubmittedTurn;
@@ -11984,6 +12052,10 @@ function UnavailableChatIcon(props) {
11984
12052
  import { StatusDot } from "@tutti-os/ui-system";
11985
12053
 
11986
12054
  // shared/utils/agentSessionMentionText.ts
12055
+ import {
12056
+ isRichTextMentionHref,
12057
+ parseRichTextMentionHref
12058
+ } from "@tutti-os/ui-rich-text/core";
11987
12059
  var MARKDOWN_LINK_PATTERN = /\[((?:\\.|[^\]\\])*)\]\(([^)\s]+)\)/g;
11988
12060
  var MARKDOWN_LABEL_ESCAPE_PATTERN = /\\([\\[\]()])/g;
11989
12061
  var SESSION_MENTION_DISPLAY_PREFIX_BY_LANGUAGE = {
@@ -12011,20 +12083,20 @@ function formatAgentSessionMentionText(value, options = {}) {
12011
12083
  const withSessionMentionsNormalized = trimmed.replace(
12012
12084
  MARKDOWN_LINK_PATTERN,
12013
12085
  (fullMatch, rawLabel, href) => {
12014
- const normalizedHref = href.trim().toLowerCase();
12015
- if (normalizedHref.startsWith("mention://agent-session")) {
12016
- return formatSessionLabel(
12017
- unescapeMarkdownLabel(rawLabel),
12018
- sessionMentionDisplayPrefix
12019
- );
12086
+ const label = unescapeMarkdownLabel(rawLabel);
12087
+ const mention = parseRichTextMentionHref(href, label);
12088
+ if (!mention) {
12089
+ return isRichTextMentionHref(href) ? label : fullMatch;
12020
12090
  }
12021
- if (normalizedHref.startsWith("mention://workspace-issue")) {
12022
- return formatIssueLabel(unescapeMarkdownLabel(rawLabel));
12091
+ const providerId = mention.providerId.trim().toLowerCase();
12092
+ const displayLabel = label || mention.label;
12093
+ if (providerId === "agent-session") {
12094
+ return formatSessionLabel(displayLabel, sessionMentionDisplayPrefix);
12023
12095
  }
12024
- if (!normalizedHref.startsWith("mention://")) {
12025
- return fullMatch;
12096
+ if (providerId === "workspace-issue") {
12097
+ return formatIssueLabel(displayLabel);
12026
12098
  }
12027
- return unescapeMarkdownLabel(rawLabel);
12099
+ return displayLabel;
12028
12100
  }
12029
12101
  );
12030
12102
  const normalized = normalizeAgentTitleText(withSessionMentionsNormalized);
@@ -16648,6 +16720,7 @@ function AgentComposer({
16648
16720
  "use memo";
16649
16721
  const draftPrompt = draftContent.prompt;
16650
16722
  const draftImages = draftContent.images;
16723
+ const agentActivityRuntime = useOptionalAgentActivityRuntime();
16651
16724
  const [isPaletteOpen, setIsPaletteOpen] = useState10(true);
16652
16725
  const [isReviewPickerOpen, setIsReviewPickerOpen] = useState10(false);
16653
16726
  const [highlightedIndex, setHighlightedIndex] = useState10(0);
@@ -16682,6 +16755,7 @@ function AgentComposer({
16682
16755
  const promptInputAreaRef = useRef12(null);
16683
16756
  const paletteContentRef = useRef12(null);
16684
16757
  const draftPromptRef = useRef12(draftPrompt);
16758
+ const draftImagesRef = useRef12(draftImages);
16685
16759
  const submittedImagePreviewObservedBusyRef = useRef12(false);
16686
16760
  const promptTipRef = useRef12(null);
16687
16761
  const mentionControllerRef = useRef12(
@@ -16885,6 +16959,9 @@ function AgentComposer({
16885
16959
  });
16886
16960
  }
16887
16961
  }, [draftPrompt]);
16962
+ useEffect11(() => {
16963
+ draftImagesRef.current = draftImages;
16964
+ }, [draftImages]);
16888
16965
  useEffect11(() => {
16889
16966
  if (previousSlashStatusAgentSessionIdRef.current === slashStatusAgentSessionId) {
16890
16967
  return;
@@ -17064,7 +17141,9 @@ function AgentComposer({
17064
17141
  );
17065
17142
  const submitCurrentPrompt = useStableEventCallback(() => {
17066
17143
  const canSubmitWhileSending = canQueueWhileBusy && isSendingTurn;
17067
- if (isSelectedProjectMissing || submitDisabled || disabled && !canQueueWhileBusy || isSendingTurn && !canSubmitWhileSending) {
17144
+ const hasUploadingImages = draftImages.some((image) => image.uploading);
17145
+ const hasFailedImages = draftImages.some((image) => image.uploadError);
17146
+ if (isSelectedProjectMissing || submitDisabled || hasUploadingImages || hasFailedImages || disabled && !canQueueWhileBusy || isSendingTurn && !canSubmitWhileSending) {
17068
17147
  return;
17069
17148
  }
17070
17149
  const nextPrompt = draftPromptRef.current;
@@ -17435,30 +17514,92 @@ function AgentComposer({
17435
17514
  }
17436
17515
  setSubmittedImagePreview([]);
17437
17516
  submittedImagePreviewObservedBusyRef.current = false;
17517
+ const currentDraftImages = draftImagesRef.current;
17438
17518
  const remainingSlots = Math.max(
17439
17519
  0,
17440
- MAX_AGENT_COMPOSER_DRAFT_IMAGES - draftImages.length
17520
+ MAX_AGENT_COMPOSER_DRAFT_IMAGES - currentDraftImages.length
17441
17521
  );
17442
17522
  if (remainingSlots === 0) {
17443
17523
  return;
17444
17524
  }
17525
+ const uploadPromptContent = agentActivityRuntime?.uploadPromptContent;
17445
17526
  const nextImages = images.slice(0, remainingSlots).map((image) => ({
17446
17527
  id: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`,
17447
17528
  name: image.name,
17448
17529
  mimeType: image.mimeType,
17449
17530
  data: image.data,
17450
- previewUrl: `data:${image.mimeType};base64,${image.data}`
17531
+ previewUrl: `data:${image.mimeType};base64,${image.data}`,
17532
+ uploading: Boolean(uploadPromptContent)
17451
17533
  }));
17534
+ const nextDraftImages = [...currentDraftImages, ...nextImages];
17535
+ draftImagesRef.current = nextDraftImages;
17452
17536
  onDraftContentChange({
17453
17537
  prompt: draftPromptRef.current,
17454
- images: [...draftImages, ...nextImages]
17538
+ images: nextDraftImages
17455
17539
  });
17540
+ if (!uploadPromptContent) {
17541
+ return;
17542
+ }
17543
+ for (const draftImage of nextImages) {
17544
+ void uploadPromptContent({
17545
+ workspaceId,
17546
+ content: [
17547
+ {
17548
+ type: "image",
17549
+ mimeType: draftImage.mimeType,
17550
+ data: draftImage.data,
17551
+ name: draftImage.name
17552
+ }
17553
+ ]
17554
+ }).then((result) => {
17555
+ const uploadedImage = result.content.find(
17556
+ (block) => block.type === "image"
17557
+ );
17558
+ const uploadedPath = uploadedImage?.path?.trim() ?? "";
17559
+ if (!uploadedPath) {
17560
+ throw new Error("Prompt image upload completed without path.");
17561
+ }
17562
+ const uploadedDraftImages = draftImagesRef.current.map(
17563
+ (image) => image.id === draftImage.id ? {
17564
+ id: image.id,
17565
+ name: image.name,
17566
+ mimeType: image.mimeType,
17567
+ path: uploadedPath,
17568
+ ...uploadedImage?.uri ? { uri: uploadedImage.uri } : {},
17569
+ ...uploadedImage?.uploadStatus ? { uploadStatus: uploadedImage.uploadStatus } : {},
17570
+ ...uploadedImage?.assetId ? { assetId: uploadedImage.assetId } : {},
17571
+ previewUrl: image.previewUrl,
17572
+ uploading: false
17573
+ } : image
17574
+ );
17575
+ draftImagesRef.current = uploadedDraftImages;
17576
+ onDraftContentChange({
17577
+ prompt: draftPromptRef.current,
17578
+ images: uploadedDraftImages
17579
+ });
17580
+ }).catch((error) => {
17581
+ const message = error instanceof Error ? error.message : String(error);
17582
+ const failedDraftImages = draftImagesRef.current.map(
17583
+ (image) => image.id === draftImage.id ? {
17584
+ ...image,
17585
+ uploading: false,
17586
+ uploadError: message
17587
+ } : image
17588
+ );
17589
+ draftImagesRef.current = failedDraftImages;
17590
+ onDraftContentChange({
17591
+ prompt: draftPromptRef.current,
17592
+ images: failedDraftImages
17593
+ });
17594
+ });
17595
+ }
17456
17596
  },
17457
17597
  [
17458
- draftImages,
17598
+ agentActivityRuntime,
17459
17599
  onDraftContentChange,
17460
17600
  onPromptImagesUnsupported,
17461
- promptImagesSupported
17601
+ promptImagesSupported,
17602
+ workspaceId
17462
17603
  ]
17463
17604
  );
17464
17605
  const handlePastedImages = useCallback9(
@@ -17469,12 +17610,16 @@ function AgentComposer({
17469
17610
  );
17470
17611
  const removeDraftImage = useCallback9(
17471
17612
  (id) => {
17613
+ const nextDraftImages = draftImagesRef.current.filter(
17614
+ (image) => image.id !== id
17615
+ );
17616
+ draftImagesRef.current = nextDraftImages;
17472
17617
  onDraftContentChange({
17473
17618
  prompt: draftPromptRef.current,
17474
- images: draftImages.filter((image) => image.id !== id)
17619
+ images: nextDraftImages
17475
17620
  });
17476
17621
  },
17477
- [draftImages, onDraftContentChange]
17622
+ [onDraftContentChange]
17478
17623
  );
17479
17624
  const applyReferencePickResult = useCallback9(
17480
17625
  (result) => {
@@ -17730,6 +17875,8 @@ function AgentComposer({
17730
17875
  [showFileMentionPalette, showFloatingCommandMenu]
17731
17876
  );
17732
17877
  const hasDraftContent = agentComposerDraftHasContent(draftContent);
17878
+ const hasUploadingDraftImages = draftImages.some((image) => image.uploading);
17879
+ const hasFailedDraftImages = draftImages.some((image) => image.uploadError);
17733
17880
  const isQueueMode = canQueueWhileBusy && hasDraftContent;
17734
17881
  const shouldShowStopButton = showStopButton && !isQueueMode;
17735
17882
  const sendButtonState = isQueueMode ? "queue" : shouldShowStopButton ? isInterrupting ? "stopping" : "interrupt" : isSendingTurn ? "loading" : "send";
@@ -17930,10 +18077,17 @@ function AgentComposer({
17930
18077
  children: visibleDraftImages.map((image) => /* @__PURE__ */ jsxs13(
17931
18078
  "div",
17932
18079
  {
17933
- className: "group relative aspect-square min-w-0 overflow-hidden rounded-[6px] border border-[var(--line-1)] bg-[var(--background-fronted)]",
18080
+ className: cn(
18081
+ "group relative aspect-square min-w-0 overflow-hidden rounded-[6px] border border-[var(--line-1)] bg-[var(--background-fronted)]",
18082
+ "[&>[data-rmiz]]:block [&>[data-rmiz]]:size-full",
18083
+ "[&>[data-rmiz]>[data-rmiz-content]]:block [&>[data-rmiz]>[data-rmiz-content]]:size-full",
18084
+ image.uploadError && "border-[color:color-mix(in_srgb,var(--danger)_55%,var(--line-1))]"
18085
+ ),
18086
+ "data-uploading": image.uploading ? "true" : void 0,
18087
+ "data-upload-error": image.uploadError ? "true" : void 0,
17934
18088
  children: [
17935
18089
  /* @__PURE__ */ jsx26(
17936
- "img",
18090
+ ZoomableImage,
17937
18091
  {
17938
18092
  src: image.previewUrl,
17939
18093
  alt: image.name,
@@ -17941,6 +18095,23 @@ function AgentComposer({
17941
18095
  draggable: false
17942
18096
  }
17943
18097
  ),
18098
+ image.uploading ? /* @__PURE__ */ jsx26(
18099
+ "div",
18100
+ {
18101
+ className: "absolute inset-0 grid place-items-center bg-[color-mix(in_srgb,var(--background-fronted)_62%,transparent)]",
18102
+ "data-testid": "agent-gui-composer-image-uploading",
18103
+ children: /* @__PURE__ */ jsx26(
18104
+ Spinner,
18105
+ {
18106
+ className: "text-[var(--text-primary)]",
18107
+ size: 18,
18108
+ strokeWidth: 2.4,
18109
+ trackColor: "var(--transparency-hover)",
18110
+ testId: "agent-gui-composer-image-upload-spinner"
18111
+ }
18112
+ )
18113
+ }
18114
+ ) : null,
17944
18115
  showingSubmittedImagePreview ? null : /* @__PURE__ */ jsx26(
17945
18116
  "button",
17946
18117
  {
@@ -18271,7 +18442,7 @@ function AgentComposer({
18271
18442
  type: "submit",
18272
18443
  className: AgentGUINode_styles_default.composerSendButton,
18273
18444
  "data-state": sendButtonState,
18274
- disabled: isSelectedProjectMissing || submitDisabled || !hasDraftContent || sendButtonBusy,
18445
+ disabled: isSelectedProjectMissing || submitDisabled || !hasDraftContent || hasUploadingDraftImages || hasFailedDraftImages || sendButtonBusy,
18275
18446
  "aria-label": labels.send,
18276
18447
  title: labels.send,
18277
18448
  "aria-busy": sendButtonBusy,
@@ -18671,6 +18842,7 @@ function AttentionGlyph() {
18671
18842
  }
18672
18843
 
18673
18844
  // agent-gui/agentGuiNode/AgentGUINodeView.tsx
18845
+ import { createRichTextMentionHref as createRichTextMentionHref2 } from "@tutti-os/ui-rich-text/core";
18674
18846
  import { Fragment as Fragment8, jsx as jsx29, jsxs as jsxs15 } from "react/jsx-runtime";
18675
18847
  var AGENT_GUI_STICK_TO_BOTTOM_THRESHOLD_PX = 24;
18676
18848
  var AGENT_GUI_CONVERSATION_RAIL_SECTION_PAGE_SIZE = 5;
@@ -18983,11 +19155,18 @@ function AgentGUINodeView({
18983
19155
  const bundleIconUrl = bundle.iconUrl ?? void 0;
18984
19156
  return {
18985
19157
  kind: "workspace-reference",
18986
- href: buildAgentWorkspaceReferenceMentionHref(
18987
- viewModel.workspaceId,
18988
- handle,
18989
- { iconUrl: bundleIconUrl, fileCount: bundle.fileCount }
18990
- ),
19158
+ href: createRichTextMentionHref2({
19159
+ providerId: "workspace-reference",
19160
+ entityId: handle.id,
19161
+ label: bundle.displayName,
19162
+ scope: {
19163
+ workspaceId: viewModel.workspaceId,
19164
+ source: handle.source,
19165
+ ...handle.groupId?.trim() ? { groupId: handle.groupId.trim() } : {},
19166
+ ...bundleIconUrl ? { icon: bundleIconUrl } : {},
19167
+ ...bundle.fileCount > 0 ? { count: String(bundle.fileCount) } : {}
19168
+ }
19169
+ }),
18991
19170
  workspaceId: viewModel.workspaceId,
18992
19171
  targetId: handle.id,
18993
19172
  source: handle.source,