@tutti-os/agent-gui 0.0.26 → 0.0.27

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
@@ -13,7 +13,7 @@ import {
13
13
  import {
14
14
  AgentInteractivePromptSurface,
15
15
  approvalOptionDisplayLabel
16
- } from "./chunk-4MOHKNXA.js";
16
+ } from "./chunk-OSBLVO4N.js";
17
17
  import {
18
18
  PLAN_IMPLEMENTATION_ACTION_FEEDBACK,
19
19
  PLAN_IMPLEMENTATION_ACTION_IMPLEMENT,
@@ -36,13 +36,13 @@ import {
36
36
  skillDescriptionForDisplay,
37
37
  skillTriggerForPrefix,
38
38
  useProjectedAgentConversation
39
- } from "./chunk-7JW4OAKS.js";
39
+ } from "./chunk-MLHARLOS.js";
40
40
  import {
41
41
  AgentMessageMarkdown,
42
42
  ZoomableImage,
43
43
  cn,
44
44
  resolveWorkspaceLinkAction
45
- } from "./chunk-BUBD5E4F.js";
45
+ } from "./chunk-VNRRXUI3.js";
46
46
  import {
47
47
  AGENT_MENTION_FILTER_TAB_ORDER,
48
48
  AgentFileMentionPalette,
@@ -50,7 +50,7 @@ import {
50
50
  DEFAULT_AGENT_MENTION_FILTER,
51
51
  agentMentionItemKey,
52
52
  preloadAgentMentionBrowse
53
- } from "./chunk-Q6QE7JNG.js";
53
+ } from "./chunk-5PIXN7UF.js";
54
54
  import {
55
55
  WORKSPACE_AGENT_ACTIVITY_RUNTIME_SESSION_ORIGIN,
56
56
  buildWorkspaceAgentActivityListViewModel,
@@ -90,7 +90,7 @@ import {
90
90
  useAgentActivitySnapshot,
91
91
  useAgentHostApi,
92
92
  useOptionalAgentActivityRuntime
93
- } from "./chunk-CCI6EK5W.js";
93
+ } from "./chunk-YHRJD6HA.js";
94
94
  import "./chunk-TYGL25EL.js";
95
95
  import {
96
96
  AGENT_CONTEXT_MENTION_PROVIDER_IDS
@@ -3171,10 +3171,10 @@ function compareTimelineItemsForMerge(left, right) {
3171
3171
  // agent-gui/agentGuiNode/model/agentComposerDraft.ts
3172
3172
  var MAX_AGENT_COMPOSER_DRAFT_IMAGES = 8;
3173
3173
  function emptyAgentComposerDraft() {
3174
- return { prompt: "", images: [] };
3174
+ return { prompt: "", images: [], files: [] };
3175
3175
  }
3176
3176
  function agentComposerDraftHasContent(draft) {
3177
- return draft.prompt.trim() !== "" || draft.images.length > 0;
3177
+ return draft.prompt.trim() !== "" || draft.images.length > 0 || (draft.files?.length ?? 0) > 0;
3178
3178
  }
3179
3179
  function normalizeAgentPromptContentBlocks(content) {
3180
3180
  const result = [];
@@ -3201,6 +3201,26 @@ function normalizeAgentPromptContentBlocks(content) {
3201
3201
  });
3202
3202
  continue;
3203
3203
  }
3204
+ if (block.type === "file") {
3205
+ const filePath = block.path?.trim();
3206
+ const hostPath = block.hostPath?.trim();
3207
+ if (!filePath && !hostPath) {
3208
+ continue;
3209
+ }
3210
+ result.push({
3211
+ type: "file",
3212
+ ...block.mimeType?.trim() ? { mimeType: block.mimeType.trim() } : {},
3213
+ ...filePath ? { path: filePath } : {},
3214
+ ...hostPath ? { hostPath } : {},
3215
+ ...block.name?.trim() ? { name: block.name.trim() } : {},
3216
+ ...block.uri?.trim() ? { uri: block.uri.trim() } : {},
3217
+ ...block.uploadStatus?.trim() ? { uploadStatus: block.uploadStatus.trim() } : {},
3218
+ ...block.assetId?.trim() ? { assetId: block.assetId.trim() } : {},
3219
+ ...typeof block.sizeBytes === "number" ? { sizeBytes: block.sizeBytes } : {},
3220
+ kind: "file"
3221
+ });
3222
+ continue;
3223
+ }
3204
3224
  if (block.type === "skill" || block.type === "mention") {
3205
3225
  const name = block.name?.trim();
3206
3226
  const path = block.path?.trim();
@@ -3228,6 +3248,9 @@ function agentPromptContentToComposerDraft(content, idPrefix) {
3228
3248
  prompt: agentPromptContentDisplayText(normalizedContent),
3229
3249
  images: agentPromptContentImageBlocks(normalizedContent).slice(0, MAX_AGENT_COMPOSER_DRAFT_IMAGES).map(
3230
3250
  (image, index) => agentPromptImageBlockToDraftImage(image, idPrefix, index)
3251
+ ),
3252
+ files: agentPromptFileBlocks(normalizedContent).map(
3253
+ (file, index) => agentPromptFileBlockToDraftFile(file, idPrefix, index)
3231
3254
  )
3232
3255
  };
3233
3256
  }
@@ -3249,9 +3272,24 @@ function agentComposerDraftToPromptContent(input) {
3249
3272
  mimeType: image.mimeType,
3250
3273
  ...image.path ? { path: image.path } : { data: image.data },
3251
3274
  name: image.name
3275
+ })),
3276
+ ...(input.draft.files ?? []).filter((file) => !file.uploading && !file.uploadError).map((file) => ({
3277
+ type: "file",
3278
+ ...file.mimeType ? { mimeType: file.mimeType } : {},
3279
+ ...file.path ? { path: file.path } : {},
3280
+ ...file.hostPath ? { hostPath: file.hostPath } : {},
3281
+ ...file.assetId ? { assetId: file.assetId } : {},
3282
+ ...file.sizeBytes ? { sizeBytes: file.sizeBytes } : {},
3283
+ name: file.name,
3284
+ kind: "file"
3252
3285
  }))
3253
3286
  ]);
3254
3287
  }
3288
+ function agentPromptFileBlocks(content) {
3289
+ return normalizeAgentPromptContentBlocks(content).filter(
3290
+ (block) => block.type === "file" && (typeof block.path === "string" || typeof block.hostPath === "string")
3291
+ );
3292
+ }
3255
3293
  function promptItemBlocksForProviderSkills(input) {
3256
3294
  if (input.provider.trim() !== "codex") {
3257
3295
  return [];
@@ -3289,11 +3327,22 @@ function agentPromptImageBlockToDraftImage(image, idPrefix, index) {
3289
3327
  id: `${idPrefix}:image:${index}`,
3290
3328
  name: image.name?.trim() || `image-${index + 1}`,
3291
3329
  mimeType: image.mimeType,
3292
- data: image.data,
3293
- path: image.path,
3330
+ ...image.data ? { data: image.data } : {},
3331
+ ...image.path ? { path: image.path } : {},
3294
3332
  previewUrl: typeof image.data === "string" && image.data ? `data:${image.mimeType};base64,${image.data}` : image.path ?? ""
3295
3333
  };
3296
3334
  }
3335
+ function agentPromptFileBlockToDraftFile(file, idPrefix, index) {
3336
+ return {
3337
+ id: `${idPrefix}:file:${index}`,
3338
+ name: file.name?.trim() || `file-${index + 1}`,
3339
+ mimeType: file.mimeType,
3340
+ path: file.path,
3341
+ hostPath: file.hostPath,
3342
+ assetId: file.assetId,
3343
+ sizeBytes: file.sizeBytes
3344
+ };
3345
+ }
3297
3346
 
3298
3347
  // shared/agentConversation/projection/workspaceAgentMessageProjection.ts
3299
3348
  function projectWorkspaceAgentMessagesToTimelineItems(messages) {
@@ -17010,6 +17059,7 @@ var MENTION_PALETTE_MIN_HEIGHT_PX = 280;
17010
17059
  var MENTION_PALETTE_MAX_HEIGHT_PX = 320;
17011
17060
  var MENTION_PALETTE_GAP_PX = 8;
17012
17061
  var MENTION_PALETTE_VIEWPORT_PADDING_PX = 8;
17062
+ var promptFileUploadUnsupportedError = "Prompt file uploads are not supported by this agent runtime.";
17013
17063
  var EMPTY_CONTEXT_MENTION_PROVIDERS = [];
17014
17064
  var EMPTY_PROMPT_TIPS = [];
17015
17065
  var EMPTY_PROVIDER_SKILLS = [];
@@ -17108,6 +17158,7 @@ function AgentComposer({
17108
17158
  "use memo";
17109
17159
  const draftPrompt = draftContent.prompt;
17110
17160
  const draftImages = draftContent.images;
17161
+ const draftFiles = draftContent.files ?? [];
17111
17162
  const agentActivityRuntime = useOptionalAgentActivityRuntime();
17112
17163
  const [isPaletteOpen, setIsPaletteOpen] = useState10(true);
17113
17164
  const [isReviewPickerOpen, setIsReviewPickerOpen] = useState10(false);
@@ -17144,6 +17195,7 @@ function AgentComposer({
17144
17195
  const paletteContentRef = useRef12(null);
17145
17196
  const draftPromptRef = useRef12(draftPrompt);
17146
17197
  const draftImagesRef = useRef12(draftImages);
17198
+ const draftFilesRef = useRef12(draftFiles);
17147
17199
  const submittedImagePreviewObservedBusyRef = useRef12(false);
17148
17200
  const promptTipRef = useRef12(null);
17149
17201
  const mentionControllerRef = useRef12(
@@ -17350,6 +17402,9 @@ function AgentComposer({
17350
17402
  useEffect11(() => {
17351
17403
  draftImagesRef.current = draftImages;
17352
17404
  }, [draftImages]);
17405
+ useEffect11(() => {
17406
+ draftFilesRef.current = draftFiles;
17407
+ }, [draftFiles]);
17353
17408
  useEffect11(() => {
17354
17409
  if (previousSlashStatusAgentSessionIdRef.current === slashStatusAgentSessionId) {
17355
17410
  return;
@@ -17531,7 +17586,9 @@ function AgentComposer({
17531
17586
  const canSubmitWhileSending = canQueueWhileBusy && isSendingTurn;
17532
17587
  const hasUploadingImages = draftImages.some((image) => image.uploading);
17533
17588
  const hasFailedImages = draftImages.some((image) => image.uploadError);
17534
- if (isSelectedProjectMissing || submitDisabled || hasUploadingImages || hasFailedImages || disabled && !canQueueWhileBusy || isSendingTurn && !canSubmitWhileSending) {
17589
+ const hasUploadingFiles = draftFiles.some((file) => file.uploading);
17590
+ const hasFailedFiles = draftFiles.some((file) => file.uploadError);
17591
+ if (isSelectedProjectMissing || submitDisabled || hasUploadingImages || hasFailedImages || hasUploadingFiles || hasFailedFiles || disabled && !canQueueWhileBusy || isSendingTurn && !canSubmitWhileSending) {
17535
17592
  return;
17536
17593
  }
17537
17594
  const nextPrompt = draftPromptRef.current;
@@ -17901,7 +17958,8 @@ function AgentComposer({
17901
17958
  draftImagesRef.current = nextDraftImages;
17902
17959
  onDraftContentChange({
17903
17960
  prompt: draftPromptRef.current,
17904
- images: nextDraftImages
17961
+ images: nextDraftImages,
17962
+ files: draftFilesRef.current
17905
17963
  });
17906
17964
  if (!uploadPromptContent) {
17907
17965
  return;
@@ -17938,7 +17996,8 @@ function AgentComposer({
17938
17996
  draftImagesRef.current = uploadedDraftImages;
17939
17997
  onDraftContentChange({
17940
17998
  prompt: draftPromptRef.current,
17941
- images: uploadedDraftImages
17999
+ images: uploadedDraftImages,
18000
+ files: draftFilesRef.current
17942
18001
  });
17943
18002
  }).catch((error) => {
17944
18003
  const message = error instanceof Error ? error.message : String(error);
@@ -17952,7 +18011,8 @@ function AgentComposer({
17952
18011
  draftImagesRef.current = failedDraftImages;
17953
18012
  onDraftContentChange({
17954
18013
  prompt: draftPromptRef.current,
17955
- images: failedDraftImages
18014
+ images: failedDraftImages,
18015
+ files: draftFilesRef.current
17956
18016
  });
17957
18017
  });
17958
18018
  }
@@ -17979,7 +18039,104 @@ function AgentComposer({
17979
18039
  draftImagesRef.current = nextDraftImages;
17980
18040
  onDraftContentChange({
17981
18041
  prompt: draftPromptRef.current,
17982
- images: nextDraftImages
18042
+ images: nextDraftImages,
18043
+ files: draftFilesRef.current
18044
+ });
18045
+ },
18046
+ [onDraftContentChange]
18047
+ );
18048
+ const addDraftFiles = useCallback9(
18049
+ (attachments) => {
18050
+ if (attachments.length === 0) {
18051
+ return;
18052
+ }
18053
+ const uploadPromptContent = agentActivityRuntime?.uploadPromptContent;
18054
+ const nextFiles = attachments.map((attachment) => ({
18055
+ id: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`,
18056
+ name: attachment.name,
18057
+ mimeType: attachment.mimeType?.trim() || "application/octet-stream",
18058
+ hostPath: attachment.hostPath,
18059
+ uploading: Boolean(uploadPromptContent),
18060
+ ...uploadPromptContent ? {} : { uploadError: promptFileUploadUnsupportedError }
18061
+ }));
18062
+ const nextDraftFiles = [...draftFilesRef.current, ...nextFiles];
18063
+ draftFilesRef.current = nextDraftFiles;
18064
+ onDraftContentChange({
18065
+ prompt: draftPromptRef.current,
18066
+ images: draftImagesRef.current,
18067
+ files: nextDraftFiles
18068
+ });
18069
+ if (!uploadPromptContent) {
18070
+ return;
18071
+ }
18072
+ for (const draftFile of nextFiles) {
18073
+ void uploadPromptContent({
18074
+ workspaceId,
18075
+ content: [
18076
+ {
18077
+ type: "file",
18078
+ mimeType: draftFile.mimeType,
18079
+ hostPath: draftFile.hostPath,
18080
+ name: draftFile.name,
18081
+ kind: "file"
18082
+ }
18083
+ ]
18084
+ }).then((result) => {
18085
+ const uploadedFile = result.content.find(
18086
+ (block) => block.type === "file"
18087
+ );
18088
+ const uploadedPath = uploadedFile?.path?.trim() ?? "";
18089
+ if (!uploadedPath) {
18090
+ throw new Error("Prompt file upload completed without path.");
18091
+ }
18092
+ const uploadedDraftFiles = draftFilesRef.current.map(
18093
+ (file) => file.id === draftFile.id ? {
18094
+ id: file.id,
18095
+ name: uploadedFile?.name ?? file.name,
18096
+ mimeType: uploadedFile?.mimeType ?? file.mimeType,
18097
+ path: uploadedPath,
18098
+ hostPath: uploadedFile?.hostPath ?? file.hostPath,
18099
+ assetId: uploadedFile?.assetId,
18100
+ sizeBytes: uploadedFile?.sizeBytes,
18101
+ uploading: false
18102
+ } : file
18103
+ );
18104
+ draftFilesRef.current = uploadedDraftFiles;
18105
+ onDraftContentChange({
18106
+ prompt: draftPromptRef.current,
18107
+ images: draftImagesRef.current,
18108
+ files: uploadedDraftFiles
18109
+ });
18110
+ }).catch((error) => {
18111
+ const message = error instanceof Error ? error.message : String(error);
18112
+ const failedDraftFiles = draftFilesRef.current.map(
18113
+ (file) => file.id === draftFile.id ? {
18114
+ ...file,
18115
+ uploading: false,
18116
+ uploadError: message
18117
+ } : file
18118
+ );
18119
+ draftFilesRef.current = failedDraftFiles;
18120
+ onDraftContentChange({
18121
+ prompt: draftPromptRef.current,
18122
+ images: draftImagesRef.current,
18123
+ files: failedDraftFiles
18124
+ });
18125
+ });
18126
+ }
18127
+ },
18128
+ [agentActivityRuntime, onDraftContentChange, workspaceId]
18129
+ );
18130
+ const removeDraftFile = useCallback9(
18131
+ (id) => {
18132
+ const nextDraftFiles = draftFilesRef.current.filter(
18133
+ (file) => file.id !== id
18134
+ );
18135
+ draftFilesRef.current = nextDraftFiles;
18136
+ onDraftContentChange({
18137
+ prompt: draftPromptRef.current,
18138
+ images: draftImagesRef.current,
18139
+ files: nextDraftFiles
17983
18140
  });
17984
18141
  },
17985
18142
  [onDraftContentChange]
@@ -17992,8 +18149,11 @@ function AgentComposer({
17992
18149
  if (result.mentionItems.length > 0) {
17993
18150
  editorHandleRef.current?.insertMentionItems(result.mentionItems);
17994
18151
  }
18152
+ if (result.hostAttachments && result.hostAttachments.length > 0) {
18153
+ addDraftFiles(result.hostAttachments);
18154
+ }
17995
18155
  },
17996
- []
18156
+ [addDraftFiles]
17997
18157
  );
17998
18158
  const handleWorkspaceReferencePicker = useCallback9(async () => {
17999
18159
  if (!onRequestWorkspaceReferences) {
@@ -18249,6 +18409,8 @@ function AgentComposer({
18249
18409
  const hasDraftContent = agentComposerDraftHasContent(draftContent);
18250
18410
  const hasUploadingDraftImages = draftImages.some((image) => image.uploading);
18251
18411
  const hasFailedDraftImages = draftImages.some((image) => image.uploadError);
18412
+ const hasUploadingDraftFiles = draftFiles.some((file) => file.uploading);
18413
+ const hasFailedDraftFiles = draftFiles.some((file) => file.uploadError);
18252
18414
  const isQueueMode = canQueueWhileBusy && hasDraftContent;
18253
18415
  const shouldShowStopButton = showStopButton && !isQueueMode;
18254
18416
  const sendButtonState = isQueueMode ? "queue" : shouldShowStopButton ? isInterrupting ? "stopping" : "interrupt" : isSendingTurn ? "loading" : "send";
@@ -18260,6 +18422,7 @@ function AgentComposer({
18260
18422
  const effectivePlaceholder = disabledReasonText || placeholder;
18261
18423
  const showingSubmittedImagePreview = draftImages.length === 0 && submittedImagePreview.length > 0;
18262
18424
  const visibleDraftImages = draftImages.length > 0 ? draftImages : submittedImagePreview;
18425
+ const visibleDraftFiles = draftFiles;
18263
18426
  useEffect11(() => {
18264
18427
  if (submittedImagePreview.length === 0) {
18265
18428
  submittedImagePreviewObservedBusyRef.current = false;
@@ -18502,6 +18665,56 @@ function AgentComposer({
18502
18665
  ))
18503
18666
  }
18504
18667
  ) : null,
18668
+ visibleDraftFiles.length > 0 ? /* @__PURE__ */ jsx26(
18669
+ "div",
18670
+ {
18671
+ className: "mb-2 flex max-w-[520px] flex-wrap gap-2",
18672
+ "data-testid": "agent-gui-composer-file-drafts",
18673
+ children: visibleDraftFiles.map((file) => /* @__PURE__ */ jsxs13(
18674
+ "div",
18675
+ {
18676
+ className: cn(
18677
+ "group inline-flex max-w-full items-center gap-2 rounded-[6px] border border-[var(--line-1)] bg-[var(--background-fronted)] px-2 py-1 text-xs text-[var(--text-primary)]",
18678
+ file.uploadError && "border-[color:color-mix(in_srgb,var(--danger)_55%,var(--line-1))]"
18679
+ ),
18680
+ "data-uploading": file.uploading ? "true" : void 0,
18681
+ "data-upload-error": file.uploadError ? "true" : void 0,
18682
+ title: file.hostPath ?? file.path ?? file.name,
18683
+ children: [
18684
+ file.uploading ? /* @__PURE__ */ jsx26(
18685
+ Spinner,
18686
+ {
18687
+ className: "shrink-0 text-[var(--text-primary)]",
18688
+ size: 14,
18689
+ strokeWidth: 2.4,
18690
+ trackColor: "var(--transparency-hover)",
18691
+ testId: "agent-gui-composer-file-upload-spinner"
18692
+ }
18693
+ ) : /* @__PURE__ */ jsx26(
18694
+ "span",
18695
+ {
18696
+ className: "size-2 shrink-0 rounded-full bg-[var(--text-tertiary)]",
18697
+ "aria-hidden": true
18698
+ }
18699
+ ),
18700
+ /* @__PURE__ */ jsx26("span", { className: "min-w-0 max-w-[220px] truncate", children: file.name }),
18701
+ /* @__PURE__ */ jsx26(
18702
+ "button",
18703
+ {
18704
+ type: "button",
18705
+ className: "inline-flex size-5 shrink-0 items-center justify-center rounded-full text-[var(--text-secondary)] transition hover:bg-[var(--transparency-hover)] hover:text-[var(--text-primary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:color-mix(in_srgb,var(--text-primary)_34%,transparent)]",
18706
+ "aria-label": labels.removeMention,
18707
+ title: labels.removeMention,
18708
+ onClick: () => removeDraftFile(file.id),
18709
+ children: /* @__PURE__ */ jsx26(X, { size: 12, strokeWidth: 2.4, "aria-hidden": true })
18710
+ }
18711
+ )
18712
+ ]
18713
+ },
18714
+ file.id
18715
+ ))
18716
+ }
18717
+ ) : null,
18505
18718
  /* @__PURE__ */ jsx26(
18506
18719
  AgentRichTextEditor,
18507
18720
  {
@@ -18836,7 +19049,7 @@ function AgentComposer({
18836
19049
  type: "submit",
18837
19050
  className: AgentGUINode_styles_default.composerSendButton,
18838
19051
  "data-state": sendButtonState,
18839
- disabled: isSelectedProjectMissing || submitDisabled || !hasDraftContent || hasUploadingDraftImages || hasFailedDraftImages || sendButtonBusy,
19052
+ disabled: isSelectedProjectMissing || submitDisabled || !hasDraftContent || hasUploadingDraftImages || hasFailedDraftImages || hasUploadingDraftFiles || hasFailedDraftFiles || sendButtonBusy,
18840
19053
  "aria-label": labels.send,
18841
19054
  title: labels.send,
18842
19055
  "aria-busy": sendButtonBusy,
@@ -19492,6 +19705,7 @@ function AgentGUINodeView({
19492
19705
  workspaceAppIcons = EMPTY_WORKSPACE_APP_ICONS3
19493
19706
  }) {
19494
19707
  "use memo";
19708
+ const agentHostApi = useAgentHostApi();
19495
19709
  const layoutElementRef = useRef13(null);
19496
19710
  const railResizeInteractionRef = useRef13(null);
19497
19711
  const [isRailResizing, setIsRailResizing] = useState11(false);
@@ -19509,18 +19723,127 @@ function AgentGUINodeView({
19509
19723
  );
19510
19724
  const workspaceReferencePickerResolverRef = useRef13(null);
19511
19725
  const emptyReferencePickResult = useMemo10(
19512
- () => ({ files: [], mentionItems: [] }),
19726
+ () => ({ files: [], mentionItems: [], hostAttachments: [] }),
19513
19727
  []
19514
19728
  );
19729
+ const hostLocalFileLabel = uiLanguage === "zh-CN" ? "\u672C\u5730\u6587\u4EF6(\u5BBF\u4E3B\u673A)" : "Local files (Host)";
19730
+ const hostLocalFileSelectLabel = uiLanguage === "zh-CN" ? "\u4ECE\u7535\u8111\u9009\u62E9\u2026" : "Choose from computer\u2026";
19731
+ const hostLocalFileActionPath = "host-local-file://select";
19732
+ const referenceSourceAggregatorWithHostLocalFile = useMemo10(() => {
19733
+ if (!referenceSourceAggregator) {
19734
+ return null;
19735
+ }
19736
+ const sourceId = "host-local-file";
19737
+ const actionNode = {
19738
+ ref: { sourceId, nodeId: "select-files" },
19739
+ kind: "file",
19740
+ displayName: hostLocalFileSelectLabel
19741
+ };
19742
+ const rootNode = {
19743
+ ref: { sourceId, nodeId: "\0source-root" },
19744
+ kind: "folder",
19745
+ displayName: hostLocalFileLabel,
19746
+ hasChildren: true
19747
+ };
19748
+ let hostProvidedLocalFileSource = false;
19749
+ return {
19750
+ ...referenceSourceAggregator,
19751
+ async listSources(scope) {
19752
+ const sources = await referenceSourceAggregator.listSources(scope);
19753
+ hostProvidedLocalFileSource = sources.some(
19754
+ (source) => source.sourceId === sourceId
19755
+ );
19756
+ if (hostProvidedLocalFileSource) {
19757
+ return sources;
19758
+ }
19759
+ return [
19760
+ ...sources,
19761
+ {
19762
+ sourceId,
19763
+ label: hostLocalFileLabel,
19764
+ icon: "file",
19765
+ capabilities: {
19766
+ searchable: false,
19767
+ previewable: false,
19768
+ paginated: false,
19769
+ navigable: false,
19770
+ filterable: false
19771
+ }
19772
+ }
19773
+ ];
19774
+ },
19775
+ async listRoot(scope) {
19776
+ const root = await referenceSourceAggregator.listRoot(scope);
19777
+ if (hostProvidedLocalFileSource) {
19778
+ return root;
19779
+ }
19780
+ return [...root, rootNode];
19781
+ },
19782
+ async listChildren(scope, node, input) {
19783
+ if (node.sourceId === sourceId && !hostProvidedLocalFileSource) {
19784
+ return { entries: [actionNode], nextCursor: null };
19785
+ }
19786
+ return await referenceSourceAggregator.listChildren(scope, node, input);
19787
+ },
19788
+ async search(scope, currentSourceId, input) {
19789
+ if (currentSourceId === sourceId && !hostProvidedLocalFileSource) {
19790
+ return { entries: [], nextCursor: null };
19791
+ }
19792
+ return await referenceSourceAggregator.search(
19793
+ scope,
19794
+ currentSourceId,
19795
+ input
19796
+ );
19797
+ },
19798
+ async open(scope, node) {
19799
+ if (node.ref.sourceId === sourceId && !hostProvidedLocalFileSource) {
19800
+ return;
19801
+ }
19802
+ await referenceSourceAggregator.open(scope, node);
19803
+ },
19804
+ async readPreview(scope, node) {
19805
+ if (node.ref.sourceId === sourceId && !hostProvidedLocalFileSource) {
19806
+ return null;
19807
+ }
19808
+ return await referenceSourceAggregator.readPreview(scope, node);
19809
+ },
19810
+ resolveSelection(node) {
19811
+ if (node.ref.sourceId === sourceId && !hostProvidedLocalFileSource) {
19812
+ return {
19813
+ path: hostLocalFileActionPath,
19814
+ kind: "file",
19815
+ displayName: actionNode.displayName
19816
+ };
19817
+ }
19818
+ return referenceSourceAggregator.resolveSelection(node);
19819
+ },
19820
+ async locateTarget(scope, currentSourceId, params) {
19821
+ if (currentSourceId === sourceId && !hostProvidedLocalFileSource) {
19822
+ return null;
19823
+ }
19824
+ return await referenceSourceAggregator.locateTarget(
19825
+ scope,
19826
+ currentSourceId,
19827
+ params
19828
+ );
19829
+ },
19830
+ getLoadedSource(currentSourceId) {
19831
+ if (currentSourceId === sourceId && !hostProvidedLocalFileSource) {
19832
+ return void 0;
19833
+ }
19834
+ return referenceSourceAggregator.getLoadedSource(currentSourceId);
19835
+ }
19836
+ };
19837
+ }, [hostLocalFileLabel, hostLocalFileSelectLabel, referenceSourceAggregator]);
19515
19838
  const requestWorkspaceReferences = useCallback10(
19516
19839
  async (entity) => {
19517
19840
  if (previewMode) {
19518
19841
  return emptyReferencePickResult;
19519
19842
  }
19520
- if (!workspaceFileReferenceAdapter && !referenceSourceAggregator || !workspaceFileReferenceCopy) {
19843
+ if (!workspaceFileReferenceAdapter && !referenceSourceAggregatorWithHostLocalFile || !workspaceFileReferenceCopy) {
19521
19844
  return emptyReferencePickResult;
19522
19845
  }
19523
- const target = entity && referenceSourceAggregator ? resolveMentionReferenceTarget?.(entity) ?? null : referenceSourceAggregator ? resolveWorkspaceReferenceInitialTarget?.({
19846
+ const target = entity && referenceSourceAggregatorWithHostLocalFile ? resolveMentionReferenceTarget?.(entity) ?? null : referenceSourceAggregatorWithHostLocalFile ? resolveWorkspaceReferenceInitialTarget?.({
19524
19847
  activeConversation: viewModel.activeConversation,
19525
19848
  composerSelectedProjectPath: viewModel.composerSettings.selectedProjectPath ?? null,
19526
19849
  userProjects: viewModel.userProjects
@@ -19534,7 +19857,7 @@ function AgentGUINodeView({
19534
19857
  [
19535
19858
  emptyReferencePickResult,
19536
19859
  previewMode,
19537
- referenceSourceAggregator,
19860
+ referenceSourceAggregatorWithHostLocalFile,
19538
19861
  resolveMentionReferenceTarget,
19539
19862
  resolveWorkspaceReferenceInitialTarget,
19540
19863
  viewModel.activeConversation,
@@ -19563,10 +19886,32 @@ function AgentGUINodeView({
19563
19886
  [onWorkspaceFileReferencesAdded]
19564
19887
  );
19565
19888
  const confirmWorkspaceReferencePicker = useCallback10(
19566
- (refs) => {
19567
- settleReferencePicker({ files: refs, mentionItems: [] }, refs);
19889
+ async (refs) => {
19890
+ const wantsHostFiles = refs.some(
19891
+ (ref) => ref.path === hostLocalFileActionPath
19892
+ );
19893
+ if (!wantsHostFiles) {
19894
+ settleReferencePicker(
19895
+ { files: refs, mentionItems: [], hostAttachments: [] },
19896
+ refs
19897
+ );
19898
+ return;
19899
+ }
19900
+ const workspaceRefs = refs.filter(
19901
+ (ref) => ref.path !== hostLocalFileActionPath
19902
+ );
19903
+ const selected = await agentHostApi.workspace.selectFiles();
19904
+ const hostAttachments = selected.map((file) => ({
19905
+ hostPath: file.path,
19906
+ name: file.name || file.path.split("/").pop() || file.path,
19907
+ mimeType: null
19908
+ }));
19909
+ settleReferencePicker(
19910
+ { files: workspaceRefs, mentionItems: [], hostAttachments },
19911
+ workspaceRefs
19912
+ );
19568
19913
  },
19569
- [settleReferencePicker]
19914
+ [agentHostApi.workspace, settleReferencePicker]
19570
19915
  );
19571
19916
  const confirmWorkspaceReferenceBundles = useCallback10(
19572
19917
  (result) => {
@@ -19597,7 +19942,7 @@ function AgentGUINodeView({
19597
19942
  };
19598
19943
  });
19599
19944
  settleReferencePicker(
19600
- { files: result.files, mentionItems },
19945
+ { files: result.files, mentionItems, hostAttachments: [] },
19601
19946
  result.files
19602
19947
  );
19603
19948
  },
@@ -19943,10 +20288,10 @@ function AgentGUINodeView({
19943
20288
  ]
19944
20289
  }
19945
20290
  ),
19946
- referenceSourceAggregator ? /* @__PURE__ */ jsx29(
20291
+ referenceSourceAggregatorWithHostLocalFile ? /* @__PURE__ */ jsx29(
19947
20292
  ReferenceSourcePicker,
19948
20293
  {
19949
- aggregator: referenceSourceAggregator,
20294
+ aggregator: referenceSourceAggregatorWithHostLocalFile,
19950
20295
  copy: workspaceFileReferenceCopy ?? fallbackWorkspaceFileReferenceCopy,
19951
20296
  initialTarget: workspaceReferencePickerTarget,
19952
20297
  open: workspaceReferencePickerOpen,