@tangle-network/sandbox-ui 0.79.0 → 0.80.0
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/chat.d.ts +86 -5
- package/dist/chat.js +8 -3
- package/dist/{chunk-UQXDIQWD.js → chunk-UFVXAJSA.js} +168 -33
- package/dist/globals.css +6 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +20 -16
- package/dist/styles.css +6 -0
- package/package.json +1 -1
package/dist/chat.d.ts
CHANGED
|
@@ -269,6 +269,44 @@ interface AgentSessionControlsProps {
|
|
|
269
269
|
*/
|
|
270
270
|
declare function AgentSessionControls({ harness, profile, model, reasoning, filterModelsToHarness, trailing, className, context, layout, menuPlacement, }: AgentSessionControlsProps): react_jsx_runtime.JSX.Element | null;
|
|
271
271
|
|
|
272
|
+
/** Limits applied when staging files onto a composer. */
|
|
273
|
+
interface ComposerFileValidationConfig {
|
|
274
|
+
/** Reject any single file larger than this. */
|
|
275
|
+
maxSizeBytes?: number;
|
|
276
|
+
/** Reject files once the staged count would exceed this. */
|
|
277
|
+
maxCount?: number;
|
|
278
|
+
/** Files already staged, counted against `maxCount` before this batch. */
|
|
279
|
+
currentCount?: number;
|
|
280
|
+
/**
|
|
281
|
+
* Comma-separated accept list, same grammar as the native `<input accept>`
|
|
282
|
+
* attribute: file extensions (`.png`), exact MIME types (`image/png`), and
|
|
283
|
+
* MIME wildcards (`image/*`).
|
|
284
|
+
*/
|
|
285
|
+
accept?: string;
|
|
286
|
+
}
|
|
287
|
+
/** A file that failed validation, paired with a human-readable reason. */
|
|
288
|
+
interface ComposerFileRejection {
|
|
289
|
+
file: File;
|
|
290
|
+
reason: string;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Checks a single file against a comma-separated `accept` list using the same
|
|
294
|
+
* grammar as the native `<input accept>` attribute. An undefined or empty
|
|
295
|
+
* `accept` accepts everything.
|
|
296
|
+
*/
|
|
297
|
+
declare function isAcceptedType(file: File, accept?: string): boolean;
|
|
298
|
+
/**
|
|
299
|
+
* Splits a batch of files into what's safe to stage and what's rejected,
|
|
300
|
+
* checking accept type, then size, then the running count against
|
|
301
|
+
* `currentCount` + `maxCount`. Each rejection carries a reason naming the
|
|
302
|
+
* file and the limit it broke. Pure data in, pure data out — no throwing,
|
|
303
|
+
* no console noise, so callers decide how to surface rejections.
|
|
304
|
+
*/
|
|
305
|
+
declare function validateComposerFiles(files: File[] | FileList, config: ComposerFileValidationConfig): {
|
|
306
|
+
accepted: File[];
|
|
307
|
+
rejected: ComposerFileRejection[];
|
|
308
|
+
};
|
|
309
|
+
|
|
272
310
|
/** A staged attachment shown as a chip above the input. */
|
|
273
311
|
interface ComposerFile {
|
|
274
312
|
id: string;
|
|
@@ -278,6 +316,14 @@ interface ComposerFile {
|
|
|
278
316
|
/** File count for a folder chip. */
|
|
279
317
|
fileCount?: number;
|
|
280
318
|
status: "pending" | "uploading" | "ready" | "error";
|
|
319
|
+
/**
|
|
320
|
+
* Object URL for an image thumbnail. The app owns creation and revocation
|
|
321
|
+
* (e.g. `URL.createObjectURL` on stage, `URL.revokeObjectURL` on remove) —
|
|
322
|
+
* the composer only ever reads it.
|
|
323
|
+
*/
|
|
324
|
+
previewUrl?: string;
|
|
325
|
+
/** Shown on the chip when `status === "error"`. */
|
|
326
|
+
errorMessage?: string;
|
|
281
327
|
}
|
|
282
328
|
interface AgentComposerProps {
|
|
283
329
|
/** Composer text (controlled). */
|
|
@@ -324,9 +370,42 @@ interface AgentComposerProps {
|
|
|
324
370
|
onAttachFolder?: (files: FileList) => void;
|
|
325
371
|
attachments?: ReadonlyArray<ComposerFile>;
|
|
326
372
|
onRemoveFile?: (id: string) => void;
|
|
373
|
+
/** When set, chips with `status === "error"` render a retry button. */
|
|
374
|
+
onRetryFile?: (id: string) => void;
|
|
375
|
+
/**
|
|
376
|
+
* File types the composer takes, in the native `<input accept>` grammar.
|
|
377
|
+
* Enforced on every ingress path — the picker dialog, drag-and-drop, and
|
|
378
|
+
* clipboard paste — so a type the picker won't offer can't arrive by another
|
|
379
|
+
* route. Non-matching files go to `onRejectFiles` and never reach
|
|
380
|
+
* `onAttach`. Folder attach is exempt (directory selection has no native
|
|
381
|
+
* accept semantics); size/count limits are the app's job in `onAttach`.
|
|
382
|
+
*/
|
|
327
383
|
accept?: string;
|
|
384
|
+
/**
|
|
385
|
+
* Called with the files `accept` filtered out of a drop/paste/pick, each
|
|
386
|
+
* with a human-readable reason. Without it rejection is silent — the same
|
|
387
|
+
* feedback the native picker gives for a type it won't offer.
|
|
388
|
+
*/
|
|
389
|
+
onRejectFiles?: (rejections: ComposerFileRejection[]) => void;
|
|
328
390
|
dropTitle?: string;
|
|
329
391
|
dropDescription?: string;
|
|
392
|
+
/**
|
|
393
|
+
* `canSend` ignores `busy` so Enter/onSubmit keep firing while a turn is
|
|
394
|
+
* streaming. For composers that queue the next turn instead of blocking on
|
|
395
|
+
* the current one — the Stop-button rendering rule (`busy && onCancel`) is
|
|
396
|
+
* unaffected, so the button still flips to Stop while this is set. Default
|
|
397
|
+
* false.
|
|
398
|
+
*/
|
|
399
|
+
canSubmitWhileBusy?: boolean;
|
|
400
|
+
/**
|
|
401
|
+
* Allow submitting with empty text when at least one attachment is staged
|
|
402
|
+
* (an image-only message). Counts attachments of ANY status — a gate on
|
|
403
|
+
* `ready` would make Enter silently dead while an upload is in flight,
|
|
404
|
+
* with no way for the app to explain why. The app's onSubmit owns the send
|
|
405
|
+
* policy (block, queue, or toast on pending/errored files) and what the
|
|
406
|
+
* message body becomes. Default false.
|
|
407
|
+
*/
|
|
408
|
+
canSubmitAttachmentsOnly?: boolean;
|
|
330
409
|
/** Cmd/Ctrl+L focuses the input and shows a hint. Default false. */
|
|
331
410
|
focusShortcut?: boolean;
|
|
332
411
|
/** Minimum textarea rows before it grows. Default 2. */
|
|
@@ -346,11 +425,13 @@ interface AgentComposerProps {
|
|
|
346
425
|
* router-backed composer (no harness) and the sandbox-backed one (with harness).
|
|
347
426
|
*
|
|
348
427
|
* Opt-in extras make it the superset of every app's hand-rolled composer:
|
|
349
|
-
* file/folder attachments with drag-and-drop + chips
|
|
350
|
-
* (`
|
|
351
|
-
* a
|
|
428
|
+
* file/folder attachments with drag-and-drop + chips + clipboard paste
|
|
429
|
+
* (`onAttach` also gates pasting files onto the textarea, auto-naming
|
|
430
|
+
* generic clipboard image blobs `pasted-image-<n>.<ext>`), a streaming Stop
|
|
431
|
+
* button (`busy` + `onCancel`), a `controls` override slot for bespoke
|
|
432
|
+
* picker rows, and a Cmd/Ctrl+L focus shortcut.
|
|
352
433
|
*/
|
|
353
|
-
declare function AgentComposer({ value, onChange, onSubmit, placeholder, disabled, busy, onCancel, harness, profile, model, reasoning, context, controls, trailing, onAttach, onAttachFolder, attachments, onRemoveFile, accept, dropTitle, dropDescription, focusShortcut, minRows, maxHeight, className, sendLabel, autoFocus, }: AgentComposerProps): react_jsx_runtime.JSX.Element;
|
|
434
|
+
declare function AgentComposer({ value, onChange, onSubmit, placeholder, disabled, busy, onCancel, harness, profile, model, reasoning, context, controls, trailing, onAttach, onAttachFolder, attachments, onRemoveFile, onRetryFile, accept, onRejectFiles, dropTitle, dropDescription, canSubmitWhileBusy, canSubmitAttachmentsOnly, focusShortcut, minRows, maxHeight, className, sendLabel, autoFocus, }: AgentComposerProps): react_jsx_runtime.JSX.Element;
|
|
354
435
|
|
|
355
436
|
/**
|
|
356
437
|
* Whether `harness` can run `modelId`. Router-backed harnesses, and provider-less
|
|
@@ -464,4 +545,4 @@ declare function createFetchTransport(opts: {
|
|
|
464
545
|
fetchImpl?: typeof fetch;
|
|
465
546
|
}): ArtifactAgentDockTransport;
|
|
466
547
|
|
|
467
|
-
export { AgentComposer, type AgentComposerProps, type AgentProfileCapability, type AgentProfileDraft, type AgentProfileOption, AgentProfilePicker, type AgentProfilePickerProps, AgentSessionControls, type AgentSessionControlsProps, type AgentSessionHarnessControl, type AgentSessionModelControl, type AgentSessionProfileControl, type AgentSessionReasoningControl, ArtifactAgentDock, type ArtifactAgentDockProps, type ArtifactAgentDockTransport, type ArtifactDockMessage, type ArtifactDockStreamEvent, type ArtifactKind, type ArtifactScope, type ComposerFile, DEFAULT_REASONING_LEVEL_OPTIONS, HARNESS_REASONING_OPTIONS, type ReasoningLevel, type ReasoningLevelOption, ReasoningLevelPicker, type ReasoningLevelPickerProps, createFetchTransport, isModelCompatibleWithHarness, snapModelToHarness };
|
|
548
|
+
export { AgentComposer, type AgentComposerProps, type AgentProfileCapability, type AgentProfileDraft, type AgentProfileOption, AgentProfilePicker, type AgentProfilePickerProps, AgentSessionControls, type AgentSessionControlsProps, type AgentSessionHarnessControl, type AgentSessionModelControl, type AgentSessionProfileControl, type AgentSessionReasoningControl, ArtifactAgentDock, type ArtifactAgentDockProps, type ArtifactAgentDockTransport, type ArtifactDockMessage, type ArtifactDockStreamEvent, type ArtifactKind, type ArtifactScope, type ComposerFile, type ComposerFileRejection, type ComposerFileValidationConfig, DEFAULT_REASONING_LEVEL_OPTIONS, HARNESS_REASONING_OPTIONS, type ReasoningLevel, type ReasoningLevelOption, ReasoningLevelPicker, type ReasoningLevelPickerProps, createFetchTransport, isAcceptedType, isModelCompatibleWithHarness, snapModelToHarness, validateComposerFiles };
|
package/dist/chat.js
CHANGED
|
@@ -13,11 +13,14 @@ import {
|
|
|
13
13
|
ThinkingIndicator,
|
|
14
14
|
UserMessage,
|
|
15
15
|
createFetchTransport,
|
|
16
|
+
isAcceptedType,
|
|
16
17
|
isModelCompatibleWithHarness,
|
|
17
18
|
modelProvider,
|
|
18
19
|
snapHarnessToModel,
|
|
19
|
-
snapModelToHarness
|
|
20
|
-
|
|
20
|
+
snapModelToHarness,
|
|
21
|
+
validateComposerFiles
|
|
22
|
+
} from "./chunk-UFVXAJSA.js";
|
|
23
|
+
import "./chunk-TK46XFLM.js";
|
|
21
24
|
import "./chunk-IWIZ7RZE.js";
|
|
22
25
|
import "./chunk-L62ZT6RS.js";
|
|
23
26
|
import "./chunk-EI44GEQ5.js";
|
|
@@ -37,8 +40,10 @@ export {
|
|
|
37
40
|
ThinkingIndicator,
|
|
38
41
|
UserMessage,
|
|
39
42
|
createFetchTransport,
|
|
43
|
+
isAcceptedType,
|
|
40
44
|
isModelCompatibleWithHarness,
|
|
41
45
|
modelProvider,
|
|
42
46
|
snapHarnessToModel,
|
|
43
|
-
snapModelToHarness
|
|
47
|
+
snapModelToHarness,
|
|
48
|
+
validateComposerFiles
|
|
44
49
|
};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatBytes
|
|
3
|
+
} from "./chunk-TK46XFLM.js";
|
|
1
4
|
import {
|
|
2
5
|
HARNESS_OPTIONS,
|
|
3
6
|
HarnessLogo,
|
|
@@ -1064,12 +1067,84 @@ import {
|
|
|
1064
1067
|
Folder,
|
|
1065
1068
|
Loader2,
|
|
1066
1069
|
Paperclip,
|
|
1070
|
+
RotateCcw,
|
|
1067
1071
|
Square,
|
|
1068
1072
|
Upload,
|
|
1069
1073
|
X
|
|
1070
1074
|
} from "lucide-react";
|
|
1071
1075
|
import * as React4 from "react";
|
|
1076
|
+
|
|
1077
|
+
// src/chat/attachment-validation.ts
|
|
1078
|
+
function isAcceptedType(file, accept) {
|
|
1079
|
+
if (!accept || accept.trim().length === 0) return true;
|
|
1080
|
+
const patterns = accept.split(",").map((pattern) => pattern.trim()).filter((pattern) => pattern.length > 0);
|
|
1081
|
+
if (patterns.length === 0) return true;
|
|
1082
|
+
const name = file.name.toLowerCase();
|
|
1083
|
+
const type = (file.type || "").toLowerCase();
|
|
1084
|
+
return patterns.some((pattern) => {
|
|
1085
|
+
const lowerPattern = pattern.toLowerCase();
|
|
1086
|
+
if (lowerPattern.startsWith(".")) {
|
|
1087
|
+
return name.endsWith(lowerPattern);
|
|
1088
|
+
}
|
|
1089
|
+
if (lowerPattern.endsWith("/*")) {
|
|
1090
|
+
const prefix = lowerPattern.slice(0, -1);
|
|
1091
|
+
return type.startsWith(prefix);
|
|
1092
|
+
}
|
|
1093
|
+
return type === lowerPattern;
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
function validateComposerFiles(files, config) {
|
|
1097
|
+
const { maxSizeBytes, maxCount, currentCount = 0, accept } = config;
|
|
1098
|
+
const list = Array.isArray(files) ? files : Array.from(files);
|
|
1099
|
+
const accepted = [];
|
|
1100
|
+
const rejected = [];
|
|
1101
|
+
for (const file of list) {
|
|
1102
|
+
if (!isAcceptedType(file, accept)) {
|
|
1103
|
+
rejected.push({
|
|
1104
|
+
file,
|
|
1105
|
+
reason: `"${file.name}" is not an accepted file type (${accept}).`
|
|
1106
|
+
});
|
|
1107
|
+
continue;
|
|
1108
|
+
}
|
|
1109
|
+
if (maxSizeBytes !== void 0 && file.size > maxSizeBytes) {
|
|
1110
|
+
rejected.push({
|
|
1111
|
+
file,
|
|
1112
|
+
reason: `"${file.name}" (${formatBytes(file.size)}) exceeds the ${formatBytes(maxSizeBytes)} limit.`
|
|
1113
|
+
});
|
|
1114
|
+
continue;
|
|
1115
|
+
}
|
|
1116
|
+
if (maxCount !== void 0 && currentCount + accepted.length >= maxCount) {
|
|
1117
|
+
rejected.push({
|
|
1118
|
+
file,
|
|
1119
|
+
reason: `"${file.name}" was not added \u2014 the ${maxCount}-file limit is already reached.`
|
|
1120
|
+
});
|
|
1121
|
+
continue;
|
|
1122
|
+
}
|
|
1123
|
+
accepted.push(file);
|
|
1124
|
+
}
|
|
1125
|
+
return { accepted, rejected };
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// src/chat/agent-composer.tsx
|
|
1072
1129
|
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1130
|
+
var IMAGE_EXTENSION_BY_MIME = {
|
|
1131
|
+
"image/png": "png",
|
|
1132
|
+
"image/jpeg": "jpg",
|
|
1133
|
+
"image/jpg": "jpg",
|
|
1134
|
+
"image/gif": "gif",
|
|
1135
|
+
"image/webp": "webp",
|
|
1136
|
+
"image/bmp": "bmp",
|
|
1137
|
+
"image/svg+xml": "svg"
|
|
1138
|
+
};
|
|
1139
|
+
function isGenericImageName(name) {
|
|
1140
|
+
return /^(image)?(\.[a-z0-9]+)?$/i.test(name.trim());
|
|
1141
|
+
}
|
|
1142
|
+
function imageExtension(file) {
|
|
1143
|
+
const fromMime = IMAGE_EXTENSION_BY_MIME[file.type.toLowerCase()];
|
|
1144
|
+
if (fromMime) return fromMime;
|
|
1145
|
+
const fromName = /\.([a-z0-9]+)$/i.exec(file.name)?.[1];
|
|
1146
|
+
return fromName?.toLowerCase() ?? "png";
|
|
1147
|
+
}
|
|
1073
1148
|
function AgentComposer({
|
|
1074
1149
|
value,
|
|
1075
1150
|
onChange,
|
|
@@ -1089,9 +1164,13 @@ function AgentComposer({
|
|
|
1089
1164
|
onAttachFolder,
|
|
1090
1165
|
attachments = [],
|
|
1091
1166
|
onRemoveFile,
|
|
1167
|
+
onRetryFile,
|
|
1092
1168
|
accept,
|
|
1169
|
+
onRejectFiles,
|
|
1093
1170
|
dropTitle = "Drop files to add context",
|
|
1094
1171
|
dropDescription = "They attach to your next message.",
|
|
1172
|
+
canSubmitWhileBusy = false,
|
|
1173
|
+
canSubmitAttachmentsOnly = false,
|
|
1095
1174
|
focusShortcut = false,
|
|
1096
1175
|
minRows = 2,
|
|
1097
1176
|
maxHeight = 200,
|
|
@@ -1104,6 +1183,7 @@ function AgentComposer({
|
|
|
1104
1183
|
const folderInputRef = React4.useRef(null);
|
|
1105
1184
|
const [dragOver, setDragOver] = React4.useState(false);
|
|
1106
1185
|
const dragDepth = React4.useRef(0);
|
|
1186
|
+
const pastedImageCount = React4.useRef(0);
|
|
1107
1187
|
const resize = React4.useCallback(
|
|
1108
1188
|
(el) => {
|
|
1109
1189
|
el.style.height = "auto";
|
|
@@ -1125,7 +1205,7 @@ function AgentComposer({
|
|
|
1125
1205
|
document.addEventListener("keydown", onKeyDown);
|
|
1126
1206
|
return () => document.removeEventListener("keydown", onKeyDown);
|
|
1127
1207
|
}, [focusShortcut, disabled]);
|
|
1128
|
-
const canSend = !disabled && !busy && value.trim().length > 0;
|
|
1208
|
+
const canSend = !disabled && (!busy || canSubmitWhileBusy) && (value.trim().length > 0 || canSubmitAttachmentsOnly && attachments.length > 0);
|
|
1129
1209
|
const submit = () => {
|
|
1130
1210
|
if (!canSend) return;
|
|
1131
1211
|
onSubmit();
|
|
@@ -1154,6 +1234,15 @@ function AgentComposer({
|
|
|
1154
1234
|
event.stopPropagation();
|
|
1155
1235
|
if (event.dataTransfer) event.dataTransfer.dropEffect = "copy";
|
|
1156
1236
|
};
|
|
1237
|
+
const deliverFiles = (files) => {
|
|
1238
|
+
if (!onAttach || files.length === 0) return;
|
|
1239
|
+
const { accepted, rejected } = validateComposerFiles(files, { accept });
|
|
1240
|
+
if (rejected.length > 0) onRejectFiles?.(rejected);
|
|
1241
|
+
if (accepted.length === 0) return;
|
|
1242
|
+
const dt = new DataTransfer();
|
|
1243
|
+
for (const file of accepted) dt.items.add(file);
|
|
1244
|
+
onAttach(dt.files);
|
|
1245
|
+
};
|
|
1157
1246
|
const handleDrop = (event) => {
|
|
1158
1247
|
if (!dropEnabled) return;
|
|
1159
1248
|
event.preventDefault();
|
|
@@ -1161,7 +1250,25 @@ function AgentComposer({
|
|
|
1161
1250
|
dragDepth.current = 0;
|
|
1162
1251
|
setDragOver(false);
|
|
1163
1252
|
const files = event.dataTransfer?.files;
|
|
1164
|
-
if (files?.length)
|
|
1253
|
+
if (files?.length) deliverFiles(Array.from(files));
|
|
1254
|
+
};
|
|
1255
|
+
const handlePaste = (event) => {
|
|
1256
|
+
if (!onAttach) return;
|
|
1257
|
+
const clipboardFiles = event.clipboardData?.files;
|
|
1258
|
+
if (!clipboardFiles || clipboardFiles.length === 0) return;
|
|
1259
|
+
event.preventDefault();
|
|
1260
|
+
const files = Array.from(clipboardFiles).map((file) => {
|
|
1261
|
+
if (file.type.startsWith("image/") && isGenericImageName(file.name)) {
|
|
1262
|
+
pastedImageCount.current += 1;
|
|
1263
|
+
return new File(
|
|
1264
|
+
[file],
|
|
1265
|
+
`pasted-image-${pastedImageCount.current}.${imageExtension(file)}`,
|
|
1266
|
+
{ type: file.type }
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
return file;
|
|
1270
|
+
});
|
|
1271
|
+
deliverFiles(files);
|
|
1165
1272
|
};
|
|
1166
1273
|
const folderChips = attachments.filter((file) => file.kind === "folder");
|
|
1167
1274
|
const fileChips = attachments.filter((file) => file.kind !== "folder");
|
|
@@ -1190,36 +1297,60 @@ function AgentComposer({
|
|
|
1190
1297
|
disabled && "opacity-60"
|
|
1191
1298
|
),
|
|
1192
1299
|
children: [
|
|
1193
|
-
attachments.length > 0 && /* @__PURE__ */ jsx4("div", { className: "flex flex-wrap gap-1.5", children: [...folderChips, ...fileChips].map((file) =>
|
|
1194
|
-
"
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
"
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1300
|
+
attachments.length > 0 && /* @__PURE__ */ jsx4("div", { className: "flex flex-wrap gap-1.5", children: [...folderChips, ...fileChips].map((file) => {
|
|
1301
|
+
const isError = file.status === "error";
|
|
1302
|
+
const isPending = file.status === "pending";
|
|
1303
|
+
return /* @__PURE__ */ jsxs4(
|
|
1304
|
+
"span",
|
|
1305
|
+
{
|
|
1306
|
+
title: isError ? file.errorMessage : void 0,
|
|
1307
|
+
className: cn(
|
|
1308
|
+
"inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs",
|
|
1309
|
+
isError ? "border-[var(--status-error,#ff4d6d)]/40 text-[var(--status-error,#ff4d6d)]" : "border-[var(--md3-outline-variant)] bg-surface-container text-foreground",
|
|
1310
|
+
isPending && "opacity-60"
|
|
1311
|
+
),
|
|
1312
|
+
children: [
|
|
1313
|
+
file.kind !== "folder" && file.previewUrl ? /* @__PURE__ */ jsx4(
|
|
1314
|
+
"img",
|
|
1315
|
+
{
|
|
1316
|
+
src: file.previewUrl,
|
|
1317
|
+
alt: "",
|
|
1318
|
+
className: "size-8 rounded object-cover"
|
|
1319
|
+
}
|
|
1320
|
+
) : file.kind === "folder" ? /* @__PURE__ */ jsx4(Folder, { className: "size-3 shrink-0" }) : /* @__PURE__ */ jsx4(Paperclip, { className: "size-3 shrink-0" }),
|
|
1321
|
+
/* @__PURE__ */ jsx4("span", { className: "max-w-[150px] truncate", children: file.name }),
|
|
1322
|
+
file.fileCount !== void 0 && /* @__PURE__ */ jsxs4("span", { className: "text-muted-foreground", children: [
|
|
1323
|
+
"(",
|
|
1324
|
+
file.fileCount,
|
|
1325
|
+
")"
|
|
1326
|
+
] }),
|
|
1327
|
+
file.status === "uploading" && /* @__PURE__ */ jsx4(Loader2, { className: "size-3 animate-spin" }),
|
|
1328
|
+
isError && file.errorMessage && /* @__PURE__ */ jsx4("span", { className: "max-w-[150px] truncate text-[var(--status-error,#ff4d6d)]/80", children: file.errorMessage }),
|
|
1329
|
+
isError && onRetryFile && /* @__PURE__ */ jsx4(
|
|
1330
|
+
"button",
|
|
1331
|
+
{
|
|
1332
|
+
type: "button",
|
|
1333
|
+
"aria-label": `Retry upload ${file.name}`,
|
|
1334
|
+
onClick: () => onRetryFile(file.id),
|
|
1335
|
+
className: "rounded p-0.5 text-muted-foreground transition-colors hover:text-foreground focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
1336
|
+
children: /* @__PURE__ */ jsx4(RotateCcw, { className: "size-3" })
|
|
1337
|
+
}
|
|
1338
|
+
),
|
|
1339
|
+
onRemoveFile && /* @__PURE__ */ jsx4(
|
|
1340
|
+
"button",
|
|
1341
|
+
{
|
|
1342
|
+
type: "button",
|
|
1343
|
+
"aria-label": `Remove ${file.name}`,
|
|
1344
|
+
onClick: () => onRemoveFile(file.id),
|
|
1345
|
+
className: "rounded p-0.5 text-muted-foreground transition-colors hover:text-foreground focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
1346
|
+
children: /* @__PURE__ */ jsx4(X, { className: "size-3" })
|
|
1347
|
+
}
|
|
1348
|
+
)
|
|
1349
|
+
]
|
|
1350
|
+
},
|
|
1351
|
+
file.id
|
|
1352
|
+
);
|
|
1353
|
+
}) }),
|
|
1223
1354
|
/* @__PURE__ */ jsx4(
|
|
1224
1355
|
"textarea",
|
|
1225
1356
|
{
|
|
@@ -1230,6 +1361,7 @@ function AgentComposer({
|
|
|
1230
1361
|
autoFocus,
|
|
1231
1362
|
onChange: (event) => onChange(event.target.value),
|
|
1232
1363
|
onInput: (event) => resize(event.currentTarget),
|
|
1364
|
+
onPaste: handlePaste,
|
|
1233
1365
|
onKeyDown: (event) => {
|
|
1234
1366
|
if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing && event.keyCode !== 229) {
|
|
1235
1367
|
event.preventDefault();
|
|
@@ -1277,7 +1409,8 @@ function AgentComposer({
|
|
|
1277
1409
|
className: "hidden",
|
|
1278
1410
|
accept,
|
|
1279
1411
|
onChange: (event) => {
|
|
1280
|
-
if (event.target.files?.length)
|
|
1412
|
+
if (event.target.files?.length)
|
|
1413
|
+
deliverFiles(Array.from(event.target.files));
|
|
1281
1414
|
event.target.value = "";
|
|
1282
1415
|
}
|
|
1283
1416
|
}
|
|
@@ -1700,6 +1833,8 @@ export {
|
|
|
1700
1833
|
snapHarnessToModel,
|
|
1701
1834
|
AgentProfilePicker,
|
|
1702
1835
|
AgentSessionControls,
|
|
1836
|
+
isAcceptedType,
|
|
1837
|
+
validateComposerFiles,
|
|
1703
1838
|
AgentComposer,
|
|
1704
1839
|
ArtifactAgentDock,
|
|
1705
1840
|
createFetchTransport,
|
package/dist/globals.css
CHANGED
|
@@ -3185,6 +3185,12 @@
|
|
|
3185
3185
|
.text-\[var\(--status-error\,\#ff4d6d\)\] {
|
|
3186
3186
|
color: var(--status-error,#ff4d6d);
|
|
3187
3187
|
}
|
|
3188
|
+
.text-\[var\(--status-error\,\#ff4d6d\)\]\/80 {
|
|
3189
|
+
color: var(--status-error,#ff4d6d);
|
|
3190
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
3191
|
+
color: color-mix(in oklab, var(--status-error,#ff4d6d) 80%, transparent);
|
|
3192
|
+
}
|
|
3193
|
+
}
|
|
3188
3194
|
.text-\[var\(--surface-danger-text\)\] {
|
|
3189
3195
|
color: var(--surface-danger-text);
|
|
3190
3196
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { AgentWorkbench, ApprovalConfidenceStat, ApprovalItem, ApprovalQueue, Ap
|
|
|
5
5
|
export { ArtifactView, BRAND_PRISM_THEME, CodeSurface, CodeSurfaceProps, CodeView, CodeViewProps, DiffStats, DiffView, DiffViewProps, FileBreadcrumb, FileBreadcrumbProps, GitStatusBadge, PanelHeader, PanelHeaderProps, PillTabItem, PillTabs, PillTabsProps, PreviewView, PreviewViewProps, SandboxArtifact, SandboxArtifactPane, SandboxArtifactPaneProps, SandboxArtifactTerminal, buildUnifiedPatch, computeDiffStats, resolveLanguage } from './workbench.js';
|
|
6
6
|
export { OpenUIAction, OpenUIActionsNode, OpenUIArtifactRenderer, OpenUIArtifactRendererProps, OpenUIBadgeNode, OpenUICardNode, OpenUICodeNode, OpenUIComponentNode, OpenUIGridNode, OpenUIHeadingNode, OpenUIKeyValueNode, OpenUIMarkdownNode, OpenUIPrimitive, OpenUISeparatorNode, OpenUIStackNode, OpenUIStatNode, OpenUITableNode, OpenUITextNode } from '@tangle-network/ui/openui';
|
|
7
7
|
export { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem, ChatContainer, ChatContainerProps, ChatMessage, ChatMessageProps, MessageList, MessageListProps, MessageRole, ThinkingIndicator, ThinkingIndicatorProps, UserMessage, UserMessageProps } from '@tangle-network/ui/chat';
|
|
8
|
-
export { AgentComposer, AgentComposerProps, AgentProfileCapability, AgentProfileDraft, AgentProfileOption, AgentProfilePicker, AgentProfilePickerProps, AgentSessionControls, AgentSessionControlsProps, AgentSessionHarnessControl, AgentSessionModelControl, AgentSessionProfileControl, AgentSessionReasoningControl, ArtifactAgentDock, ArtifactAgentDockProps, ArtifactAgentDockTransport, ArtifactDockMessage, ArtifactDockStreamEvent, ArtifactKind, ArtifactScope, ComposerFile, DEFAULT_REASONING_LEVEL_OPTIONS, HARNESS_REASONING_OPTIONS, ReasoningLevel, ReasoningLevelOption, ReasoningLevelPicker, ReasoningLevelPickerProps, createFetchTransport, isModelCompatibleWithHarness, snapModelToHarness } from './chat.js';
|
|
8
|
+
export { AgentComposer, AgentComposerProps, AgentProfileCapability, AgentProfileDraft, AgentProfileOption, AgentProfilePicker, AgentProfilePickerProps, AgentSessionControls, AgentSessionControlsProps, AgentSessionHarnessControl, AgentSessionModelControl, AgentSessionProfileControl, AgentSessionReasoningControl, ArtifactAgentDock, ArtifactAgentDockProps, ArtifactAgentDockTransport, ArtifactDockMessage, ArtifactDockStreamEvent, ArtifactKind, ArtifactScope, ComposerFile, ComposerFileRejection, ComposerFileValidationConfig, DEFAULT_REASONING_LEVEL_OPTIONS, HARNESS_REASONING_OPTIONS, ReasoningLevel, ReasoningLevelOption, ReasoningLevelPicker, ReasoningLevelPickerProps, createFetchTransport, isAcceptedType, isModelCompatibleWithHarness, snapModelToHarness, validateComposerFiles } from './chat.js';
|
|
9
9
|
export { ExpandedToolDetail, ExpandedToolDetailProps, InlineThinkingItem, InlineThinkingItemProps, InlineToolItem, InlineToolItemProps, LiveDuration, RunGroup, RunGroupProps } from '@tangle-network/ui/run';
|
|
10
10
|
export { CommandPreview, DiffPreview, GlobResultsPreview, GrepResultsPreview, QuestionPreview, WebSearchPreview, WriteFilePreview } from '@tangle-network/ui/tool-previews';
|
|
11
11
|
export { FileArtifactPane, FileArtifactPaneProps, FileNode, FilePreview, FilePreviewProps, FileTabData, FileTabs, FileTabsProps, FileTree, FileTreeProps, FileTreeVisibilityOptions, RichFileTree, RichFileTreeGitEntry, RichFileTreeGitStatus, RichFileTreeProps, RichFileTreeThemeVars, filterFileTree } from '@tangle-network/ui/files';
|
package/dist/index.js
CHANGED
|
@@ -63,19 +63,6 @@ import {
|
|
|
63
63
|
useTotalRunningSessions
|
|
64
64
|
} from "./chunk-WID73FPH.js";
|
|
65
65
|
import "./chunk-2BUPSB7O.js";
|
|
66
|
-
import {
|
|
67
|
-
TOOL_CATEGORY_ICONS,
|
|
68
|
-
cn,
|
|
69
|
-
copyText,
|
|
70
|
-
formatBytes,
|
|
71
|
-
formatDuration,
|
|
72
|
-
formatUptime,
|
|
73
|
-
getToolCategory,
|
|
74
|
-
getToolDisplayMetadata,
|
|
75
|
-
getToolErrorText,
|
|
76
|
-
timeAgo,
|
|
77
|
-
truncateText
|
|
78
|
-
} from "./chunk-TK46XFLM.js";
|
|
79
66
|
import {
|
|
80
67
|
AuthHeader,
|
|
81
68
|
GitHubLoginButton,
|
|
@@ -98,11 +85,26 @@ import {
|
|
|
98
85
|
ThinkingIndicator,
|
|
99
86
|
UserMessage,
|
|
100
87
|
createFetchTransport,
|
|
88
|
+
isAcceptedType,
|
|
101
89
|
isModelCompatibleWithHarness,
|
|
102
90
|
modelProvider,
|
|
103
91
|
snapHarnessToModel,
|
|
104
|
-
snapModelToHarness
|
|
105
|
-
|
|
92
|
+
snapModelToHarness,
|
|
93
|
+
validateComposerFiles
|
|
94
|
+
} from "./chunk-UFVXAJSA.js";
|
|
95
|
+
import {
|
|
96
|
+
TOOL_CATEGORY_ICONS,
|
|
97
|
+
cn,
|
|
98
|
+
copyText,
|
|
99
|
+
formatBytes,
|
|
100
|
+
formatDuration,
|
|
101
|
+
formatUptime,
|
|
102
|
+
getToolCategory,
|
|
103
|
+
getToolDisplayMetadata,
|
|
104
|
+
getToolErrorText,
|
|
105
|
+
timeAgo,
|
|
106
|
+
truncateText
|
|
107
|
+
} from "./chunk-TK46XFLM.js";
|
|
106
108
|
import {
|
|
107
109
|
ExpandedToolDetail,
|
|
108
110
|
InlineThinkingItem,
|
|
@@ -605,6 +607,7 @@ export {
|
|
|
605
607
|
getToolErrorText,
|
|
606
608
|
getTotalRunningSessionCount,
|
|
607
609
|
hasBackgroundRunningSessions,
|
|
610
|
+
isAcceptedType,
|
|
608
611
|
isModelCompatibleWithHarness,
|
|
609
612
|
isStreamingAtom,
|
|
610
613
|
messagesAtom,
|
|
@@ -660,5 +663,6 @@ export {
|
|
|
660
663
|
useTheme,
|
|
661
664
|
useToast,
|
|
662
665
|
useToolCallStream,
|
|
663
|
-
useTotalRunningSessions
|
|
666
|
+
useTotalRunningSessions,
|
|
667
|
+
validateComposerFiles
|
|
664
668
|
};
|
package/dist/styles.css
CHANGED
|
@@ -3185,6 +3185,12 @@
|
|
|
3185
3185
|
.text-\[var\(--status-error\,\#ff4d6d\)\] {
|
|
3186
3186
|
color: var(--status-error,#ff4d6d);
|
|
3187
3187
|
}
|
|
3188
|
+
.text-\[var\(--status-error\,\#ff4d6d\)\]\/80 {
|
|
3189
|
+
color: var(--status-error,#ff4d6d);
|
|
3190
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
3191
|
+
color: color-mix(in oklab, var(--status-error,#ff4d6d) 80%, transparent);
|
|
3192
|
+
}
|
|
3193
|
+
}
|
|
3188
3194
|
.text-\[var\(--surface-danger-text\)\] {
|
|
3189
3195
|
color: var(--surface-danger-text);
|
|
3190
3196
|
}
|
package/package.json
CHANGED