@tangle-network/sandbox-ui 0.96.0 → 0.97.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 +18 -2
- package/dist/chat.js +1 -1
- package/dist/{chunk-I5HGKZCB.js → chunk-A4AABEX4.js} +446 -326
- package/dist/globals.css +3 -6
- package/dist/index.js +1 -1
- package/dist/styles.css +3 -6
- package/package.json +1 -1
|
@@ -191,18 +191,38 @@ import {
|
|
|
191
191
|
reasoningEffortsFor
|
|
192
192
|
} from "@tangle-network/agent-interface";
|
|
193
193
|
import * as DropdownMenu2 from "@radix-ui/react-dropdown-menu";
|
|
194
|
-
import { ChevronDown as ChevronDown3,
|
|
194
|
+
import { ChevronDown as ChevronDown3, SlidersHorizontal } from "lucide-react";
|
|
195
|
+
import * as React5 from "react";
|
|
196
|
+
|
|
197
|
+
// src/chat/harness-model-compat.ts
|
|
198
|
+
import {
|
|
199
|
+
harnessSupportsModel,
|
|
200
|
+
snapModelToHarness as snapModelIdToHarness
|
|
201
|
+
} from "@tangle-network/agent-interface";
|
|
202
|
+
import { modelProvider, snapHarnessToModel } from "@tangle-network/agent-interface";
|
|
203
|
+
function isModelCompatibleWithHarness(harness, modelId) {
|
|
204
|
+
return harnessSupportsModel(harness, modelId);
|
|
205
|
+
}
|
|
206
|
+
function snapModelToHarness(harness, modelId, models) {
|
|
207
|
+
return snapModelIdToHarness(harness, modelId, models.map(canonicalModelId));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/chat/informative-lock.tsx
|
|
211
|
+
import { Lock, Plus } from "lucide-react";
|
|
195
212
|
import * as React3 from "react";
|
|
196
213
|
|
|
197
214
|
// src/lib/use-click-outside.ts
|
|
198
215
|
import * as React from "react";
|
|
199
|
-
function useClickOutside(onOutside) {
|
|
216
|
+
function useClickOutside(onOutside, extras) {
|
|
200
217
|
const ref = React.useRef(null);
|
|
218
|
+
const extrasRef = React.useRef(extras);
|
|
219
|
+
extrasRef.current = extras;
|
|
201
220
|
React.useEffect(() => {
|
|
202
221
|
function handler(event) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
222
|
+
const target = event.target;
|
|
223
|
+
if (!ref.current || ref.current.contains(target)) return;
|
|
224
|
+
if (extrasRef.current?.some((extra) => extra.current?.contains(target))) return;
|
|
225
|
+
onOutside();
|
|
206
226
|
}
|
|
207
227
|
document.addEventListener("mousedown", handler);
|
|
208
228
|
return () => document.removeEventListener("mousedown", handler);
|
|
@@ -210,23 +230,178 @@ function useClickOutside(onOutside) {
|
|
|
210
230
|
return ref;
|
|
211
231
|
}
|
|
212
232
|
|
|
213
|
-
// src/chat/
|
|
214
|
-
import
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
233
|
+
// src/chat/anchored-popover.tsx
|
|
234
|
+
import * as React2 from "react";
|
|
235
|
+
import { createPortal } from "react-dom";
|
|
236
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
237
|
+
var AnchoredPopover = React2.forwardRef(
|
|
238
|
+
function AnchoredPopover2({ anchorRef, side, children, className, style, ...rest }, forwardedRef) {
|
|
239
|
+
const innerRef = React2.useRef(null);
|
|
240
|
+
const setRefs = (node) => {
|
|
241
|
+
innerRef.current = node;
|
|
242
|
+
if (typeof forwardedRef === "function") forwardedRef(node);
|
|
243
|
+
else if (forwardedRef) forwardedRef.current = node;
|
|
244
|
+
};
|
|
245
|
+
const [position, setPosition] = React2.useState(null);
|
|
246
|
+
const place = React2.useCallback(() => {
|
|
247
|
+
const anchor = anchorRef.current;
|
|
248
|
+
if (!anchor) return;
|
|
249
|
+
const rect = anchor.getBoundingClientRect();
|
|
250
|
+
const width = innerRef.current?.offsetWidth ?? 0;
|
|
251
|
+
const margin = 8;
|
|
252
|
+
const left = Math.max(
|
|
253
|
+
margin,
|
|
254
|
+
Math.min(rect.left, window.innerWidth - width - margin)
|
|
255
|
+
);
|
|
256
|
+
setPosition(
|
|
257
|
+
side === "top" ? { left, bottom: window.innerHeight - rect.top + margin } : { left, top: rect.bottom + margin }
|
|
258
|
+
);
|
|
259
|
+
}, [anchorRef, side]);
|
|
260
|
+
React2.useLayoutEffect(() => {
|
|
261
|
+
place();
|
|
262
|
+
window.addEventListener("resize", place);
|
|
263
|
+
window.addEventListener("scroll", place, true);
|
|
264
|
+
return () => {
|
|
265
|
+
window.removeEventListener("resize", place);
|
|
266
|
+
window.removeEventListener("scroll", place, true);
|
|
267
|
+
};
|
|
268
|
+
}, [place]);
|
|
269
|
+
return createPortal(
|
|
270
|
+
/* @__PURE__ */ jsx2(
|
|
271
|
+
"div",
|
|
272
|
+
{
|
|
273
|
+
...rest,
|
|
274
|
+
ref: setRefs,
|
|
275
|
+
className: cn("fixed z-50", className),
|
|
276
|
+
style: {
|
|
277
|
+
...style,
|
|
278
|
+
pointerEvents: "auto",
|
|
279
|
+
...position ?? { visibility: "hidden", left: 0, top: 0 }
|
|
280
|
+
},
|
|
281
|
+
children
|
|
282
|
+
}
|
|
283
|
+
),
|
|
284
|
+
document.body
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
// src/chat/informative-lock.tsx
|
|
290
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
291
|
+
function InformativeLock({
|
|
292
|
+
children,
|
|
293
|
+
ariaLabel,
|
|
294
|
+
lockTitle,
|
|
295
|
+
lockBody,
|
|
296
|
+
newChatLabel,
|
|
297
|
+
onNewChat,
|
|
298
|
+
className,
|
|
299
|
+
triggerClassName,
|
|
300
|
+
popoverClassName,
|
|
301
|
+
side = "top"
|
|
302
|
+
}) {
|
|
303
|
+
const [open, setOpen] = React3.useState(false);
|
|
304
|
+
const closeTimer = React3.useRef(null);
|
|
305
|
+
const popoverRef = React3.useRef(null);
|
|
306
|
+
const ref = useClickOutside(() => setOpen(false), [popoverRef]);
|
|
307
|
+
const cancelClose = React3.useCallback(() => {
|
|
308
|
+
if (closeTimer.current) {
|
|
309
|
+
clearTimeout(closeTimer.current);
|
|
310
|
+
closeTimer.current = null;
|
|
311
|
+
}
|
|
312
|
+
}, []);
|
|
313
|
+
const scheduleClose = React3.useCallback(() => {
|
|
314
|
+
cancelClose();
|
|
315
|
+
closeTimer.current = setTimeout(() => setOpen(false), 150);
|
|
316
|
+
}, [cancelClose]);
|
|
317
|
+
React3.useEffect(() => cancelClose, [cancelClose]);
|
|
318
|
+
return /* @__PURE__ */ jsxs2(
|
|
319
|
+
"div",
|
|
320
|
+
{
|
|
321
|
+
ref,
|
|
322
|
+
className: cn("relative inline-flex", className),
|
|
323
|
+
onMouseEnter: () => {
|
|
324
|
+
cancelClose();
|
|
325
|
+
setOpen(true);
|
|
326
|
+
},
|
|
327
|
+
onMouseLeave: scheduleClose,
|
|
328
|
+
onKeyDown: (event) => {
|
|
329
|
+
if (event.key === "Escape") setOpen(false);
|
|
330
|
+
},
|
|
331
|
+
children: [
|
|
332
|
+
/* @__PURE__ */ jsx3(
|
|
333
|
+
"button",
|
|
334
|
+
{
|
|
335
|
+
type: "button",
|
|
336
|
+
onClick: () => setOpen(true),
|
|
337
|
+
"data-state": open ? "open" : "closed",
|
|
338
|
+
"aria-label": ariaLabel,
|
|
339
|
+
"aria-haspopup": "dialog",
|
|
340
|
+
"aria-expanded": open,
|
|
341
|
+
className: cn(
|
|
342
|
+
"inline-flex h-8 items-center gap-1.5 rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container px-2.5 opacity-60",
|
|
343
|
+
"text-xs font-medium text-foreground shadow-sm transition-colors",
|
|
344
|
+
"hover:border-[var(--md3-outline-variant)] hover:bg-surface-container-high focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
345
|
+
"data-[state=open]:border-[var(--md3-outline-variant)] data-[state=open]:bg-surface-container-high",
|
|
346
|
+
triggerClassName
|
|
347
|
+
),
|
|
348
|
+
children
|
|
349
|
+
}
|
|
350
|
+
),
|
|
351
|
+
open && /* @__PURE__ */ jsxs2(
|
|
352
|
+
AnchoredPopover,
|
|
353
|
+
{
|
|
354
|
+
ref: popoverRef,
|
|
355
|
+
anchorRef: ref,
|
|
356
|
+
side,
|
|
357
|
+
role: "dialog",
|
|
358
|
+
onMouseEnter: () => {
|
|
359
|
+
cancelClose();
|
|
360
|
+
setOpen(true);
|
|
361
|
+
},
|
|
362
|
+
onMouseLeave: scheduleClose,
|
|
363
|
+
className: cn(
|
|
364
|
+
"w-72 rounded-[var(--radius-md)] border border-[var(--md3-outline-variant)] bg-surface-container-highest p-3",
|
|
365
|
+
"shadow-[0_8px_30px_rgba(0,0,0,0.45)] ring-1 ring-[#ffffff14]",
|
|
366
|
+
popoverClassName
|
|
367
|
+
),
|
|
368
|
+
children: [
|
|
369
|
+
/* @__PURE__ */ jsxs2("p", { className: "flex items-start gap-2 text-sm font-medium text-foreground", children: [
|
|
370
|
+
/* @__PURE__ */ jsx3(Lock, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
371
|
+
/* @__PURE__ */ jsx3("span", { children: lockTitle })
|
|
372
|
+
] }),
|
|
373
|
+
/* @__PURE__ */ jsx3("p", { className: "mt-1.5 text-xs text-muted-foreground", children: lockBody }),
|
|
374
|
+
/* @__PURE__ */ jsxs2(
|
|
375
|
+
"button",
|
|
376
|
+
{
|
|
377
|
+
type: "button",
|
|
378
|
+
onClick: () => {
|
|
379
|
+
setOpen(false);
|
|
380
|
+
onNewChat();
|
|
381
|
+
},
|
|
382
|
+
className: cn(
|
|
383
|
+
"mt-3 flex w-full items-center justify-center gap-1.5 rounded-md px-2.5 py-2 text-sm font-medium text-foreground",
|
|
384
|
+
"bg-primary/10 ring-1 ring-inset ring-primary/25 transition-colors",
|
|
385
|
+
"hover:bg-primary/15 focus:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
386
|
+
),
|
|
387
|
+
children: [
|
|
388
|
+
/* @__PURE__ */ jsx3(Plus, { className: "h-4 w-4" }),
|
|
389
|
+
newChatLabel
|
|
390
|
+
]
|
|
391
|
+
}
|
|
392
|
+
)
|
|
393
|
+
]
|
|
394
|
+
}
|
|
395
|
+
)
|
|
396
|
+
]
|
|
397
|
+
}
|
|
398
|
+
);
|
|
224
399
|
}
|
|
225
400
|
|
|
226
401
|
// src/chat/agent-profile-picker.tsx
|
|
227
|
-
import { Bot, Check, ChevronDown as ChevronDown2, Pencil, Plus, Trash2 } from "lucide-react";
|
|
228
|
-
import * as
|
|
229
|
-
import { jsx as
|
|
402
|
+
import { Bot, Check, ChevronDown as ChevronDown2, Pencil, Plus as Plus2, Trash2 } from "lucide-react";
|
|
403
|
+
import * as React4 from "react";
|
|
404
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
230
405
|
function profileSubtitle(profile) {
|
|
231
406
|
if (profile.description) return profile.description;
|
|
232
407
|
const count = profile.capabilities?.length ?? 0;
|
|
@@ -241,21 +416,33 @@ function AgentProfilePicker({
|
|
|
241
416
|
onUpdate,
|
|
242
417
|
onDelete,
|
|
243
418
|
disabled,
|
|
419
|
+
locked,
|
|
420
|
+
lockReason,
|
|
421
|
+
onNewChat,
|
|
244
422
|
className,
|
|
423
|
+
triggerClassName,
|
|
424
|
+
popoverClassName,
|
|
245
425
|
side = "top"
|
|
246
426
|
}) {
|
|
247
|
-
const [open, setOpen] =
|
|
248
|
-
const [composing, setComposing] =
|
|
427
|
+
const [open, setOpen] = React4.useState(false);
|
|
428
|
+
const [composing, setComposing] = React4.useState(
|
|
249
429
|
null
|
|
250
430
|
);
|
|
431
|
+
const popoverRef = React4.useRef(null);
|
|
251
432
|
const ref = useClickOutside(() => {
|
|
252
433
|
setOpen(false);
|
|
253
434
|
setComposing(null);
|
|
254
|
-
});
|
|
435
|
+
}, [popoverRef]);
|
|
255
436
|
const canAuthor = Boolean(capabilities && (onCreate || onUpdate));
|
|
256
437
|
const builtins = profiles.filter((profile) => profile.builtin);
|
|
257
438
|
const custom = profiles.filter((profile) => !profile.builtin);
|
|
258
439
|
const selected = profiles.find((profile) => profile.id === value);
|
|
440
|
+
const selectedName = selected?.name ?? value;
|
|
441
|
+
React4.useEffect(() => {
|
|
442
|
+
if (!locked) return;
|
|
443
|
+
setOpen(false);
|
|
444
|
+
setComposing(null);
|
|
445
|
+
}, [locked]);
|
|
259
446
|
function select(id) {
|
|
260
447
|
onChange(id);
|
|
261
448
|
setOpen(false);
|
|
@@ -265,38 +452,64 @@ function AgentProfilePicker({
|
|
|
265
452
|
else await onCreate?.(draft);
|
|
266
453
|
setComposing(null);
|
|
267
454
|
}
|
|
268
|
-
|
|
269
|
-
/* @__PURE__ */
|
|
455
|
+
if (locked && onNewChat) {
|
|
456
|
+
return /* @__PURE__ */ jsxs3(
|
|
457
|
+
InformativeLock,
|
|
458
|
+
{
|
|
459
|
+
ariaLabel: "Agent profile (locked)",
|
|
460
|
+
lockTitle: `Profile fixed to ${selectedName} for this conversation.`,
|
|
461
|
+
lockBody: "Conversations stay on one profile.",
|
|
462
|
+
newChatLabel: "New chat to switch profile",
|
|
463
|
+
onNewChat,
|
|
464
|
+
className,
|
|
465
|
+
triggerClassName,
|
|
466
|
+
popoverClassName,
|
|
467
|
+
side,
|
|
468
|
+
children: [
|
|
469
|
+
/* @__PURE__ */ jsx4(Bot, { className: "h-3.5 w-3.5 text-muted-foreground" }),
|
|
470
|
+
/* @__PURE__ */ jsx4("span", { className: "max-w-[140px] truncate", children: selectedName })
|
|
471
|
+
]
|
|
472
|
+
}
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
return /* @__PURE__ */ jsxs3("div", { ref, className: cn("relative inline-flex", className), children: [
|
|
476
|
+
/* @__PURE__ */ jsxs3(
|
|
270
477
|
"button",
|
|
271
478
|
{
|
|
272
479
|
type: "button",
|
|
273
|
-
disabled,
|
|
480
|
+
disabled: disabled || locked,
|
|
481
|
+
title: locked ? lockReason : void 0,
|
|
274
482
|
onClick: () => setOpen((v) => !v),
|
|
275
483
|
className: cn(
|
|
276
484
|
"inline-flex h-8 items-center gap-1.5 rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container px-2.5",
|
|
277
485
|
"text-xs font-medium text-foreground shadow-sm transition-colors",
|
|
278
486
|
"hover:border-[var(--md3-outline-variant)] hover:bg-surface-container-high focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
279
487
|
"data-[state=open]:border-[var(--md3-outline-variant)] data-[state=open]:bg-surface-container-high",
|
|
280
|
-
"disabled:cursor-not-allowed disabled:opacity-60"
|
|
488
|
+
"disabled:cursor-not-allowed disabled:opacity-60",
|
|
489
|
+
triggerClassName
|
|
281
490
|
),
|
|
282
491
|
"data-state": open ? "open" : "closed",
|
|
283
492
|
"aria-label": "Agent profile",
|
|
284
493
|
children: [
|
|
285
|
-
/* @__PURE__ */
|
|
286
|
-
/* @__PURE__ */
|
|
287
|
-
/* @__PURE__ */
|
|
494
|
+
/* @__PURE__ */ jsx4(Bot, { className: "h-3.5 w-3.5 text-muted-foreground" }),
|
|
495
|
+
/* @__PURE__ */ jsx4("span", { className: "max-w-[140px] truncate", children: selectedName }),
|
|
496
|
+
!locked && /* @__PURE__ */ jsx4(ChevronDown2, { className: "ml-auto h-3.5 w-3.5 shrink-0 text-muted-foreground" })
|
|
288
497
|
]
|
|
289
498
|
}
|
|
290
499
|
),
|
|
291
|
-
open && /* @__PURE__ */
|
|
292
|
-
|
|
500
|
+
open && !locked && /* @__PURE__ */ jsx4(
|
|
501
|
+
AnchoredPopover,
|
|
293
502
|
{
|
|
503
|
+
ref: popoverRef,
|
|
504
|
+
anchorRef: ref,
|
|
505
|
+
side,
|
|
294
506
|
className: cn(
|
|
295
|
-
"
|
|
507
|
+
"w-[min(320px,calc(100vw-2rem))] overflow-hidden rounded-[var(--radius-md)] border border-[var(--md3-outline-variant)] bg-surface-container-highest p-1",
|
|
296
508
|
"shadow-[0_8px_30px_rgba(0,0,0,0.45)] ring-1 ring-[#ffffff14]",
|
|
297
|
-
|
|
509
|
+
popoverClassName
|
|
298
510
|
),
|
|
299
|
-
|
|
511
|
+
"data-testid": "agent-profile-popover",
|
|
512
|
+
children: composing ? /* @__PURE__ */ jsx4(
|
|
300
513
|
ProfileForm,
|
|
301
514
|
{
|
|
302
515
|
capabilities: capabilities ?? [],
|
|
@@ -304,9 +517,9 @@ function AgentProfilePicker({
|
|
|
304
517
|
onCancel: () => setComposing(null),
|
|
305
518
|
onSave: save
|
|
306
519
|
}
|
|
307
|
-
) : /* @__PURE__ */
|
|
308
|
-
/* @__PURE__ */
|
|
309
|
-
builtins.map((profile) => /* @__PURE__ */
|
|
520
|
+
) : /* @__PURE__ */ jsxs3("div", { className: "max-h-[min(60vh,420px)] overflow-y-auto", children: [
|
|
521
|
+
/* @__PURE__ */ jsx4(SectionHeader, { children: "Modes" }),
|
|
522
|
+
builtins.map((profile) => /* @__PURE__ */ jsx4(
|
|
310
523
|
ProfileRow,
|
|
311
524
|
{
|
|
312
525
|
active: profile.id === value,
|
|
@@ -316,8 +529,8 @@ function AgentProfilePicker({
|
|
|
316
529
|
},
|
|
317
530
|
profile.id
|
|
318
531
|
)),
|
|
319
|
-
custom.length > 0 && /* @__PURE__ */
|
|
320
|
-
custom.map((profile) => /* @__PURE__ */
|
|
532
|
+
custom.length > 0 && /* @__PURE__ */ jsx4(SectionHeader, { children: "Your agents" }),
|
|
533
|
+
custom.map((profile) => /* @__PURE__ */ jsx4(
|
|
321
534
|
ProfileRow,
|
|
322
535
|
{
|
|
323
536
|
active: profile.id === value,
|
|
@@ -329,14 +542,14 @@ function AgentProfilePicker({
|
|
|
329
542
|
},
|
|
330
543
|
profile.id
|
|
331
544
|
)),
|
|
332
|
-
canAuthor && /* @__PURE__ */
|
|
545
|
+
canAuthor && /* @__PURE__ */ jsxs3(
|
|
333
546
|
"button",
|
|
334
547
|
{
|
|
335
548
|
type: "button",
|
|
336
549
|
onClick: () => setComposing("new"),
|
|
337
550
|
className: "mt-1 flex w-full items-center gap-2 rounded-md px-2.5 py-2 text-left text-sm text-[var(--accent-text)] transition-colors hover:bg-accent/40",
|
|
338
551
|
children: [
|
|
339
|
-
/* @__PURE__ */
|
|
552
|
+
/* @__PURE__ */ jsx4(Plus2, { className: "h-4 w-4" }),
|
|
340
553
|
" New agent\u2026"
|
|
341
554
|
]
|
|
342
555
|
}
|
|
@@ -347,7 +560,7 @@ function AgentProfilePicker({
|
|
|
347
560
|
] });
|
|
348
561
|
}
|
|
349
562
|
function SectionHeader({ children }) {
|
|
350
|
-
return /* @__PURE__ */
|
|
563
|
+
return /* @__PURE__ */ jsx4("div", { className: "px-2.5 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/70", children });
|
|
351
564
|
}
|
|
352
565
|
function ProfileRow({
|
|
353
566
|
active,
|
|
@@ -357,7 +570,7 @@ function ProfileRow({
|
|
|
357
570
|
onEdit,
|
|
358
571
|
onDelete
|
|
359
572
|
}) {
|
|
360
|
-
return /* @__PURE__ */
|
|
573
|
+
return /* @__PURE__ */ jsxs3(
|
|
361
574
|
"div",
|
|
362
575
|
{
|
|
363
576
|
className: cn(
|
|
@@ -365,40 +578,40 @@ function ProfileRow({
|
|
|
365
578
|
active ? "bg-[var(--accent-surface-soft)] text-[var(--accent-text)]" : "hover:bg-accent/40"
|
|
366
579
|
),
|
|
367
580
|
children: [
|
|
368
|
-
/* @__PURE__ */
|
|
581
|
+
/* @__PURE__ */ jsxs3(
|
|
369
582
|
"button",
|
|
370
583
|
{
|
|
371
584
|
type: "button",
|
|
372
585
|
onClick: onSelect,
|
|
373
586
|
className: "flex min-w-0 flex-1 items-center gap-2 text-left",
|
|
374
587
|
children: [
|
|
375
|
-
/* @__PURE__ */
|
|
376
|
-
/* @__PURE__ */
|
|
377
|
-
/* @__PURE__ */
|
|
378
|
-
/* @__PURE__ */
|
|
588
|
+
/* @__PURE__ */ jsx4("span", { className: "flex h-4 w-4 shrink-0 items-center justify-center", children: active && /* @__PURE__ */ jsx4(Check, { className: "h-3.5 w-3.5" }) }),
|
|
589
|
+
/* @__PURE__ */ jsxs3("span", { className: "min-w-0", children: [
|
|
590
|
+
/* @__PURE__ */ jsx4("span", { className: "block truncate font-medium", children: title }),
|
|
591
|
+
/* @__PURE__ */ jsx4("span", { className: "block truncate text-xs text-muted-foreground", children: subtitle })
|
|
379
592
|
] })
|
|
380
593
|
]
|
|
381
594
|
}
|
|
382
595
|
),
|
|
383
|
-
(onEdit || onDelete) && /* @__PURE__ */
|
|
384
|
-
onEdit && /* @__PURE__ */
|
|
596
|
+
(onEdit || onDelete) && /* @__PURE__ */ jsxs3("span", { className: "flex shrink-0 items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100", children: [
|
|
597
|
+
onEdit && /* @__PURE__ */ jsx4(
|
|
385
598
|
"button",
|
|
386
599
|
{
|
|
387
600
|
type: "button",
|
|
388
601
|
onClick: onEdit,
|
|
389
602
|
title: "Edit",
|
|
390
603
|
className: "rounded p-1 text-muted-foreground hover:text-foreground",
|
|
391
|
-
children: /* @__PURE__ */
|
|
604
|
+
children: /* @__PURE__ */ jsx4(Pencil, { className: "h-3 w-3" })
|
|
392
605
|
}
|
|
393
606
|
),
|
|
394
|
-
onDelete && /* @__PURE__ */
|
|
607
|
+
onDelete && /* @__PURE__ */ jsx4(
|
|
395
608
|
"button",
|
|
396
609
|
{
|
|
397
610
|
type: "button",
|
|
398
611
|
onClick: onDelete,
|
|
399
612
|
title: "Delete",
|
|
400
613
|
className: "rounded p-1 text-muted-foreground hover:text-[var(--status-error,#ff4d6d)]",
|
|
401
|
-
children: /* @__PURE__ */
|
|
614
|
+
children: /* @__PURE__ */ jsx4(Trash2, { className: "h-3 w-3" })
|
|
402
615
|
}
|
|
403
616
|
)
|
|
404
617
|
] })
|
|
@@ -412,16 +625,16 @@ function ProfileForm({
|
|
|
412
625
|
onCancel,
|
|
413
626
|
onSave
|
|
414
627
|
}) {
|
|
415
|
-
const [name, setName] =
|
|
416
|
-
const [caps, setCaps] =
|
|
628
|
+
const [name, setName] = React4.useState(initial?.name ?? "");
|
|
629
|
+
const [caps, setCaps] = React4.useState(
|
|
417
630
|
initial?.capabilities ? [...initial.capabilities] : capabilities.map((c) => c.id)
|
|
418
631
|
);
|
|
419
|
-
const [instructions, setInstructions] =
|
|
632
|
+
const [instructions, setInstructions] = React4.useState(initial?.instructions ?? "");
|
|
420
633
|
const toggle = (id) => setCaps(
|
|
421
634
|
(prev) => prev.includes(id) ? prev.filter((c) => c !== id) : [...prev, id]
|
|
422
635
|
);
|
|
423
|
-
return /* @__PURE__ */
|
|
424
|
-
/* @__PURE__ */
|
|
636
|
+
return /* @__PURE__ */ jsxs3("div", { className: "space-y-3 p-2.5", children: [
|
|
637
|
+
/* @__PURE__ */ jsx4(
|
|
425
638
|
"input",
|
|
426
639
|
{
|
|
427
640
|
autoFocus: true,
|
|
@@ -431,14 +644,14 @@ function ProfileForm({
|
|
|
431
644
|
className: "w-full rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container px-3 py-2 text-sm outline-none focus:border-primary"
|
|
432
645
|
}
|
|
433
646
|
),
|
|
434
|
-
capabilities.length > 0 && /* @__PURE__ */
|
|
435
|
-
/* @__PURE__ */
|
|
436
|
-
/* @__PURE__ */
|
|
647
|
+
capabilities.length > 0 && /* @__PURE__ */ jsxs3("div", { children: [
|
|
648
|
+
/* @__PURE__ */ jsx4("p", { className: "mb-1.5 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/70", children: "Tools" }),
|
|
649
|
+
/* @__PURE__ */ jsx4("div", { className: "space-y-0.5", children: capabilities.map((cap) => /* @__PURE__ */ jsxs3(
|
|
437
650
|
"label",
|
|
438
651
|
{
|
|
439
652
|
className: "flex cursor-pointer items-start gap-2 rounded-md px-2 py-1.5 hover:bg-accent/40",
|
|
440
653
|
children: [
|
|
441
|
-
/* @__PURE__ */
|
|
654
|
+
/* @__PURE__ */ jsx4(
|
|
442
655
|
"input",
|
|
443
656
|
{
|
|
444
657
|
type: "checkbox",
|
|
@@ -447,16 +660,16 @@ function ProfileForm({
|
|
|
447
660
|
className: "mt-0.5"
|
|
448
661
|
}
|
|
449
662
|
),
|
|
450
|
-
/* @__PURE__ */
|
|
451
|
-
/* @__PURE__ */
|
|
452
|
-
cap.description && /* @__PURE__ */
|
|
663
|
+
/* @__PURE__ */ jsxs3("span", { className: "min-w-0", children: [
|
|
664
|
+
/* @__PURE__ */ jsx4("span", { className: "block text-sm font-medium", children: cap.label }),
|
|
665
|
+
cap.description && /* @__PURE__ */ jsx4("span", { className: "block text-xs text-muted-foreground", children: cap.description })
|
|
453
666
|
] })
|
|
454
667
|
]
|
|
455
668
|
},
|
|
456
669
|
cap.id
|
|
457
670
|
)) })
|
|
458
671
|
] }),
|
|
459
|
-
/* @__PURE__ */
|
|
672
|
+
/* @__PURE__ */ jsx4(
|
|
460
673
|
"textarea",
|
|
461
674
|
{
|
|
462
675
|
value: instructions,
|
|
@@ -466,8 +679,8 @@ function ProfileForm({
|
|
|
466
679
|
className: "w-full resize-none rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container px-3 py-2 text-sm outline-none focus:border-primary"
|
|
467
680
|
}
|
|
468
681
|
),
|
|
469
|
-
/* @__PURE__ */
|
|
470
|
-
/* @__PURE__ */
|
|
682
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-2", children: [
|
|
683
|
+
/* @__PURE__ */ jsx4(
|
|
471
684
|
"button",
|
|
472
685
|
{
|
|
473
686
|
type: "button",
|
|
@@ -476,7 +689,7 @@ function ProfileForm({
|
|
|
476
689
|
children: "Cancel"
|
|
477
690
|
}
|
|
478
691
|
),
|
|
479
|
-
/* @__PURE__ */
|
|
692
|
+
/* @__PURE__ */ jsx4(
|
|
480
693
|
"button",
|
|
481
694
|
{
|
|
482
695
|
type: "button",
|
|
@@ -496,7 +709,7 @@ function ProfileForm({
|
|
|
496
709
|
}
|
|
497
710
|
|
|
498
711
|
// src/chat/agent-session-controls.tsx
|
|
499
|
-
import { Fragment as Fragment2, jsx as
|
|
712
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
500
713
|
function harnessAutonomyNote(harness) {
|
|
501
714
|
const ownModel = !harnessHonorsModel(harness);
|
|
502
715
|
const ownEffort = !harnessHonorsEffort(harness);
|
|
@@ -520,108 +733,6 @@ function harnessGroup(option) {
|
|
|
520
733
|
return harnessAutonomyNote(option.type) === null ? "steerable" : "fixed";
|
|
521
734
|
}
|
|
522
735
|
var HARNESS_SEARCH_THRESHOLD = 7;
|
|
523
|
-
function InformativeLock({
|
|
524
|
-
type,
|
|
525
|
-
label,
|
|
526
|
-
lockTitle,
|
|
527
|
-
lockBody,
|
|
528
|
-
newChatLabel,
|
|
529
|
-
onNewChat,
|
|
530
|
-
triggerClassName
|
|
531
|
-
}) {
|
|
532
|
-
const [open, setOpen] = React3.useState(false);
|
|
533
|
-
const closeTimer = React3.useRef(null);
|
|
534
|
-
const ref = useClickOutside(() => setOpen(false));
|
|
535
|
-
const cancelClose = React3.useCallback(() => {
|
|
536
|
-
if (closeTimer.current) {
|
|
537
|
-
clearTimeout(closeTimer.current);
|
|
538
|
-
closeTimer.current = null;
|
|
539
|
-
}
|
|
540
|
-
}, []);
|
|
541
|
-
const scheduleClose = React3.useCallback(() => {
|
|
542
|
-
cancelClose();
|
|
543
|
-
closeTimer.current = setTimeout(() => setOpen(false), 150);
|
|
544
|
-
}, [cancelClose]);
|
|
545
|
-
React3.useEffect(() => cancelClose, [cancelClose]);
|
|
546
|
-
return /* @__PURE__ */ jsxs3(
|
|
547
|
-
"div",
|
|
548
|
-
{
|
|
549
|
-
ref,
|
|
550
|
-
className: "relative inline-flex",
|
|
551
|
-
onMouseEnter: () => {
|
|
552
|
-
cancelClose();
|
|
553
|
-
setOpen(true);
|
|
554
|
-
},
|
|
555
|
-
onMouseLeave: scheduleClose,
|
|
556
|
-
onKeyDown: (event) => {
|
|
557
|
-
if (event.key === "Escape") setOpen(false);
|
|
558
|
-
},
|
|
559
|
-
children: [
|
|
560
|
-
/* @__PURE__ */ jsxs3(
|
|
561
|
-
"button",
|
|
562
|
-
{
|
|
563
|
-
type: "button",
|
|
564
|
-
onClick: () => setOpen(true),
|
|
565
|
-
"data-state": open ? "open" : "closed",
|
|
566
|
-
"aria-label": "Agent harness (locked)",
|
|
567
|
-
"aria-haspopup": "dialog",
|
|
568
|
-
"aria-expanded": open,
|
|
569
|
-
className: cn(
|
|
570
|
-
// Dimmed to read as locked (the harness is bound to this session),
|
|
571
|
-
// matching the disabled model picker — the logo stays so the chip is
|
|
572
|
-
// still recognizably this harness; the popover explains the lock.
|
|
573
|
-
"inline-flex h-8 items-center gap-1.5 rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container px-2.5 opacity-60",
|
|
574
|
-
"text-xs font-medium text-foreground shadow-sm transition-colors",
|
|
575
|
-
"hover:border-[var(--md3-outline-variant)] hover:bg-surface-container-high focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
576
|
-
"data-[state=open]:border-[var(--md3-outline-variant)] data-[state=open]:bg-surface-container-high",
|
|
577
|
-
triggerClassName
|
|
578
|
-
),
|
|
579
|
-
children: [
|
|
580
|
-
/* @__PURE__ */ jsx3(HarnessLogo, { type, size: 16 }),
|
|
581
|
-
/* @__PURE__ */ jsx3("span", { children: label })
|
|
582
|
-
]
|
|
583
|
-
}
|
|
584
|
-
),
|
|
585
|
-
open && /* @__PURE__ */ jsxs3(
|
|
586
|
-
"div",
|
|
587
|
-
{
|
|
588
|
-
role: "dialog",
|
|
589
|
-
className: cn(
|
|
590
|
-
"absolute bottom-full left-0 z-50 mb-2 w-72 rounded-[var(--radius-md)] border border-[var(--md3-outline-variant)] bg-surface-container-highest p-3",
|
|
591
|
-
"shadow-[0_8px_30px_rgba(0,0,0,0.45)] ring-1 ring-[#ffffff14]"
|
|
592
|
-
),
|
|
593
|
-
children: [
|
|
594
|
-
/* @__PURE__ */ jsxs3("p", { className: "flex items-start gap-2 text-sm font-medium text-foreground", children: [
|
|
595
|
-
/* @__PURE__ */ jsx3(Lock, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
596
|
-
/* @__PURE__ */ jsx3("span", { children: lockTitle ?? `Agent fixed to ${label} for this conversation.` })
|
|
597
|
-
] }),
|
|
598
|
-
/* @__PURE__ */ jsx3("p", { className: "mt-1.5 text-xs text-muted-foreground", children: lockBody ?? "Conversations stay on one agent." }),
|
|
599
|
-
/* @__PURE__ */ jsxs3(
|
|
600
|
-
"button",
|
|
601
|
-
{
|
|
602
|
-
type: "button",
|
|
603
|
-
onClick: () => {
|
|
604
|
-
setOpen(false);
|
|
605
|
-
onNewChat();
|
|
606
|
-
},
|
|
607
|
-
className: cn(
|
|
608
|
-
"mt-3 flex w-full items-center justify-center gap-1.5 rounded-md px-2.5 py-2 text-sm font-medium text-foreground",
|
|
609
|
-
"bg-primary/10 ring-1 ring-inset ring-primary/25 transition-colors",
|
|
610
|
-
"hover:bg-primary/15 focus:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
611
|
-
),
|
|
612
|
-
children: [
|
|
613
|
-
/* @__PURE__ */ jsx3(Plus2, { className: "h-4 w-4" }),
|
|
614
|
-
newChatLabel ?? "New chat to switch agent"
|
|
615
|
-
]
|
|
616
|
-
}
|
|
617
|
-
)
|
|
618
|
-
]
|
|
619
|
-
}
|
|
620
|
-
)
|
|
621
|
-
]
|
|
622
|
-
}
|
|
623
|
-
);
|
|
624
|
-
}
|
|
625
736
|
function HarnessDropdown({
|
|
626
737
|
value,
|
|
627
738
|
onChange,
|
|
@@ -643,16 +754,16 @@ function HarnessDropdown({
|
|
|
643
754
|
);
|
|
644
755
|
const options = HARNESS_OPTIONS.filter((h) => allowed.has(h.type));
|
|
645
756
|
const selected = options.find((option) => option.type === value);
|
|
646
|
-
const [query, setQuery] =
|
|
757
|
+
const [query, setQuery] = React5.useState("");
|
|
647
758
|
const showSearch = options.length > HARNESS_SEARCH_THRESHOLD;
|
|
648
|
-
const filtered =
|
|
759
|
+
const filtered = React5.useMemo(() => {
|
|
649
760
|
const q = query.trim().toLowerCase();
|
|
650
761
|
if (!q) return options;
|
|
651
762
|
return options.filter(
|
|
652
763
|
(o) => o.label.toLowerCase().includes(q) || o.type.toLowerCase().includes(q) || (o.description?.toLowerCase() ?? "").includes(q)
|
|
653
764
|
);
|
|
654
765
|
}, [options, query]);
|
|
655
|
-
const sections =
|
|
766
|
+
const sections = React5.useMemo(() => {
|
|
656
767
|
const byGroup = /* @__PURE__ */ new Map();
|
|
657
768
|
for (const option of filtered) {
|
|
658
769
|
const key = harnessGroup(option);
|
|
@@ -667,27 +778,31 @@ function HarnessDropdown({
|
|
|
667
778
|
})).filter((section) => section.items.length > 0);
|
|
668
779
|
}, [filtered]);
|
|
669
780
|
if (locked && onNewChat) {
|
|
670
|
-
|
|
781
|
+
const label = selected?.label ?? value;
|
|
782
|
+
return /* @__PURE__ */ jsxs4(
|
|
671
783
|
InformativeLock,
|
|
672
784
|
{
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
newChatLabel,
|
|
785
|
+
ariaLabel: "Agent harness (locked)",
|
|
786
|
+
lockTitle: lockTitle ?? `Agent fixed to ${label} for this conversation.`,
|
|
787
|
+
lockBody: lockBody ?? "Conversations stay on one agent.",
|
|
788
|
+
newChatLabel: newChatLabel ?? "New chat to switch agent",
|
|
678
789
|
onNewChat,
|
|
679
|
-
triggerClassName
|
|
790
|
+
triggerClassName,
|
|
791
|
+
children: [
|
|
792
|
+
/* @__PURE__ */ jsx5(HarnessLogo, { type: value, size: 16 }),
|
|
793
|
+
/* @__PURE__ */ jsx5("span", { children: label })
|
|
794
|
+
]
|
|
680
795
|
}
|
|
681
796
|
);
|
|
682
797
|
}
|
|
683
|
-
return /* @__PURE__ */
|
|
798
|
+
return /* @__PURE__ */ jsxs4(
|
|
684
799
|
DropdownMenu2.Root,
|
|
685
800
|
{
|
|
686
801
|
onOpenChange: (nextOpen) => {
|
|
687
802
|
if (!nextOpen) setQuery("");
|
|
688
803
|
},
|
|
689
804
|
children: [
|
|
690
|
-
/* @__PURE__ */
|
|
805
|
+
/* @__PURE__ */ jsx5(DropdownMenu2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs4(
|
|
691
806
|
"button",
|
|
692
807
|
{
|
|
693
808
|
type: "button",
|
|
@@ -703,13 +818,13 @@ function HarnessDropdown({
|
|
|
703
818
|
),
|
|
704
819
|
"aria-label": "Agent harness",
|
|
705
820
|
children: [
|
|
706
|
-
/* @__PURE__ */
|
|
707
|
-
/* @__PURE__ */
|
|
708
|
-
!locked && /* @__PURE__ */
|
|
821
|
+
/* @__PURE__ */ jsx5(HarnessLogo, { type: value, size: 16, className: "shrink-0" }),
|
|
822
|
+
/* @__PURE__ */ jsx5("span", { className: "truncate", children: selected?.label ?? value }),
|
|
823
|
+
!locked && /* @__PURE__ */ jsx5(ChevronDown3, { className: "ml-auto h-3.5 w-3.5 shrink-0 text-muted-foreground" })
|
|
709
824
|
]
|
|
710
825
|
}
|
|
711
826
|
) }),
|
|
712
|
-
/* @__PURE__ */
|
|
827
|
+
/* @__PURE__ */ jsx5(DropdownMenu2.Portal, { children: /* @__PURE__ */ jsxs4(
|
|
713
828
|
DropdownMenu2.Content,
|
|
714
829
|
{
|
|
715
830
|
side,
|
|
@@ -719,7 +834,7 @@ function HarnessDropdown({
|
|
|
719
834
|
sideOffset: 6,
|
|
720
835
|
className: pickerMenuContentClass,
|
|
721
836
|
children: [
|
|
722
|
-
showSearch && /* @__PURE__ */
|
|
837
|
+
showSearch && /* @__PURE__ */ jsx5(
|
|
723
838
|
PickerMenuSearch,
|
|
724
839
|
{
|
|
725
840
|
value: query,
|
|
@@ -727,7 +842,7 @@ function HarnessDropdown({
|
|
|
727
842
|
placeholder: "Search agents..."
|
|
728
843
|
}
|
|
729
844
|
),
|
|
730
|
-
/* @__PURE__ */
|
|
845
|
+
/* @__PURE__ */ jsx5("div", { className: pickerMenuBodyClass, children: sections.length === 0 ? /* @__PURE__ */ jsx5("div", { className: "px-3 py-8 text-center text-xs text-muted-foreground", children: "No agents match." }) : sections.map((section) => /* @__PURE__ */ jsx5(PickerMenuSection, { label: section.label, children: section.items.map((option) => /* @__PURE__ */ jsxs4(
|
|
731
846
|
DropdownMenu2.Item,
|
|
732
847
|
{
|
|
733
848
|
onSelect: (event) => {
|
|
@@ -738,7 +853,7 @@ function HarnessDropdown({
|
|
|
738
853
|
active: option.type === value
|
|
739
854
|
}),
|
|
740
855
|
children: [
|
|
741
|
-
/* @__PURE__ */
|
|
856
|
+
/* @__PURE__ */ jsx5(
|
|
742
857
|
HarnessLogo,
|
|
743
858
|
{
|
|
744
859
|
type: option.type,
|
|
@@ -746,18 +861,18 @@ function HarnessDropdown({
|
|
|
746
861
|
className: "mt-0.5"
|
|
747
862
|
}
|
|
748
863
|
),
|
|
749
|
-
/* @__PURE__ */
|
|
750
|
-
/* @__PURE__ */
|
|
751
|
-
/* @__PURE__ */
|
|
752
|
-
harnessAutonomyNote(option.type) && /* @__PURE__ */
|
|
864
|
+
/* @__PURE__ */ jsxs4("div", { className: "min-w-0 flex-1", children: [
|
|
865
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-1.5", children: [
|
|
866
|
+
/* @__PURE__ */ jsx5("span", { className: "min-w-0 truncate text-sm font-medium", children: option.label }),
|
|
867
|
+
harnessAutonomyNote(option.type) && /* @__PURE__ */ jsx5(PickerMenuTag, { children: harnessAutonomyNote(option.type) })
|
|
753
868
|
] }),
|
|
754
|
-
/* @__PURE__ */
|
|
869
|
+
/* @__PURE__ */ jsx5(PickerMenuMeta, { parts: [option.description] })
|
|
755
870
|
] })
|
|
756
871
|
]
|
|
757
872
|
},
|
|
758
873
|
option.type
|
|
759
874
|
)) }, section.key)) }),
|
|
760
|
-
showSearch && /* @__PURE__ */
|
|
875
|
+
showSearch && /* @__PURE__ */ jsxs4(PickerMenuFooter, { children: [
|
|
761
876
|
filtered.length,
|
|
762
877
|
" of ",
|
|
763
878
|
options.length,
|
|
@@ -850,7 +965,7 @@ function AgentSessionControls({
|
|
|
850
965
|
const modelTriggerClass = collapsed ? cn(collapsedTriggerClass, "h-8 rounded-lg px-2.5 text-xs") : void 0;
|
|
851
966
|
const inlineForceDown = menuPlacement === "down" && layout === "inline";
|
|
852
967
|
const avoidCollisions = inlineForceDown ? false : void 0;
|
|
853
|
-
const harnessNode = harness && /* @__PURE__ */
|
|
968
|
+
const harnessNode = harness && /* @__PURE__ */ jsx5(
|
|
854
969
|
HarnessDropdown,
|
|
855
970
|
{
|
|
856
971
|
...harness,
|
|
@@ -862,7 +977,7 @@ function AgentSessionControls({
|
|
|
862
977
|
triggerClassName: secondaryTriggerClass
|
|
863
978
|
}
|
|
864
979
|
);
|
|
865
|
-
const profileNode = profile && /* @__PURE__ */
|
|
980
|
+
const profileNode = profile && /* @__PURE__ */ jsx5(
|
|
866
981
|
AgentProfilePicker,
|
|
867
982
|
{
|
|
868
983
|
value: profile.value,
|
|
@@ -873,10 +988,15 @@ function AgentSessionControls({
|
|
|
873
988
|
onUpdate: profile.onUpdate,
|
|
874
989
|
onDelete: profile.onDelete,
|
|
875
990
|
disabled: profile.disabled,
|
|
876
|
-
|
|
991
|
+
locked: profile.locked,
|
|
992
|
+
lockReason: profile.lockReason,
|
|
993
|
+
onNewChat: profile.onNewChat,
|
|
994
|
+
side: inlineForceDown || collapsed ? "bottom" : "top",
|
|
995
|
+
triggerClassName: secondaryTriggerClass,
|
|
996
|
+
popoverClassName: collapsed ? "w-full" : void 0
|
|
877
997
|
}
|
|
878
998
|
);
|
|
879
|
-
const modelNode = model && /* @__PURE__ */
|
|
999
|
+
const modelNode = model && /* @__PURE__ */ jsx5(
|
|
880
1000
|
ModelPicker,
|
|
881
1001
|
{
|
|
882
1002
|
variant: "pill",
|
|
@@ -897,7 +1017,7 @@ function AgentSessionControls({
|
|
|
897
1017
|
);
|
|
898
1018
|
const modelReasoning = modelReasoningCapability(model?.models, model?.value);
|
|
899
1019
|
const reasoningOptions = (harness && HARNESS_REASONING_OPTIONS[harness.value]) ?? reasoning?.options;
|
|
900
|
-
const reasoningNode = reasoning && /* @__PURE__ */
|
|
1020
|
+
const reasoningNode = reasoning && /* @__PURE__ */ jsx5(
|
|
901
1021
|
ReasoningLevelPicker,
|
|
902
1022
|
{
|
|
903
1023
|
value: reasoning.value,
|
|
@@ -911,7 +1031,7 @@ function AgentSessionControls({
|
|
|
911
1031
|
}
|
|
912
1032
|
);
|
|
913
1033
|
if (layout === "gear") {
|
|
914
|
-
return /* @__PURE__ */
|
|
1034
|
+
return /* @__PURE__ */ jsx5(
|
|
915
1035
|
GearControls,
|
|
916
1036
|
{
|
|
917
1037
|
className,
|
|
@@ -930,8 +1050,8 @@ function AgentSessionControls({
|
|
|
930
1050
|
segments.push({
|
|
931
1051
|
key: "harness",
|
|
932
1052
|
label: harnessLabel,
|
|
933
|
-
node: /* @__PURE__ */
|
|
934
|
-
/* @__PURE__ */
|
|
1053
|
+
node: /* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-1.5", children: [
|
|
1054
|
+
/* @__PURE__ */ jsx5(HarnessLogo, { type: harness.value, size: 16, className: "shrink-0" }),
|
|
935
1055
|
harnessLabel
|
|
936
1056
|
] })
|
|
937
1057
|
});
|
|
@@ -948,8 +1068,8 @@ function AgentSessionControls({
|
|
|
948
1068
|
segments.push({
|
|
949
1069
|
key: "model",
|
|
950
1070
|
label: modelLabel,
|
|
951
|
-
node: /* @__PURE__ */
|
|
952
|
-
identity && /* @__PURE__ */
|
|
1071
|
+
node: /* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-1.5", children: [
|
|
1072
|
+
identity && /* @__PURE__ */ jsx5(ModelBrandStack, { identity, size: "sm" }),
|
|
953
1073
|
modelLabel
|
|
954
1074
|
] })
|
|
955
1075
|
});
|
|
@@ -961,14 +1081,14 @@ function AgentSessionControls({
|
|
|
961
1081
|
segments.push({
|
|
962
1082
|
key: "effort",
|
|
963
1083
|
label: effortLabel,
|
|
964
|
-
node: /* @__PURE__ */
|
|
965
|
-
/* @__PURE__ */
|
|
1084
|
+
node: /* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-1.5", children: [
|
|
1085
|
+
/* @__PURE__ */ jsx5("span", { className: "flex w-3.5 shrink-0 justify-center", children: /* @__PURE__ */ jsx5(ReasoningGlyph, { level: reasoning.value }) }),
|
|
966
1086
|
effortLabel
|
|
967
1087
|
] })
|
|
968
1088
|
});
|
|
969
1089
|
}
|
|
970
|
-
const summary = /* @__PURE__ */
|
|
971
|
-
index > 0 && /* @__PURE__ */
|
|
1090
|
+
const summary = /* @__PURE__ */ jsx5("span", { className: "flex items-center gap-1.5", children: segments.map((segment, index) => /* @__PURE__ */ jsxs4(React5.Fragment, { children: [
|
|
1091
|
+
index > 0 && /* @__PURE__ */ jsx5(
|
|
972
1092
|
"span",
|
|
973
1093
|
{
|
|
974
1094
|
className: "text-base leading-none text-muted-foreground/60",
|
|
@@ -978,7 +1098,7 @@ function AgentSessionControls({
|
|
|
978
1098
|
),
|
|
979
1099
|
segment.node
|
|
980
1100
|
] }, segment.key)) });
|
|
981
|
-
return /* @__PURE__ */
|
|
1101
|
+
return /* @__PURE__ */ jsx5(
|
|
982
1102
|
SummaryControls,
|
|
983
1103
|
{
|
|
984
1104
|
className,
|
|
@@ -993,7 +1113,7 @@ function AgentSessionControls({
|
|
|
993
1113
|
}
|
|
994
1114
|
);
|
|
995
1115
|
}
|
|
996
|
-
return /* @__PURE__ */
|
|
1116
|
+
return /* @__PURE__ */ jsxs4(
|
|
997
1117
|
"div",
|
|
998
1118
|
{
|
|
999
1119
|
className: cn("flex flex-wrap items-center gap-2", className),
|
|
@@ -1003,7 +1123,7 @@ function AgentSessionControls({
|
|
|
1003
1123
|
harnessNode,
|
|
1004
1124
|
modelNode,
|
|
1005
1125
|
reasoningNode,
|
|
1006
|
-
trailing && /* @__PURE__ */
|
|
1126
|
+
trailing && /* @__PURE__ */ jsx5("div", { className: "ml-auto flex items-center gap-2", children: trailing })
|
|
1007
1127
|
]
|
|
1008
1128
|
}
|
|
1009
1129
|
);
|
|
@@ -1016,11 +1136,11 @@ function GearControls({
|
|
|
1016
1136
|
reasoningNode,
|
|
1017
1137
|
trailing
|
|
1018
1138
|
}) {
|
|
1019
|
-
return /* @__PURE__ */
|
|
1139
|
+
return /* @__PURE__ */ jsx5(
|
|
1020
1140
|
CollapsibleControls,
|
|
1021
1141
|
{
|
|
1022
1142
|
className,
|
|
1023
|
-
trigger: /* @__PURE__ */
|
|
1143
|
+
trigger: /* @__PURE__ */ jsx5(SlidersHorizontal, { className: "h-4 w-4 text-muted-foreground" }),
|
|
1024
1144
|
triggerClassName: cn(
|
|
1025
1145
|
"inline-flex h-8 w-8 items-center justify-center rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container",
|
|
1026
1146
|
"text-foreground shadow-sm transition-colors",
|
|
@@ -1044,8 +1164,8 @@ function GearSection({
|
|
|
1044
1164
|
label,
|
|
1045
1165
|
children
|
|
1046
1166
|
}) {
|
|
1047
|
-
return /* @__PURE__ */
|
|
1048
|
-
/* @__PURE__ */
|
|
1167
|
+
return /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-1", children: [
|
|
1168
|
+
/* @__PURE__ */ jsx5("span", { className: "px-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground/70", children: label }),
|
|
1049
1169
|
children
|
|
1050
1170
|
] });
|
|
1051
1171
|
}
|
|
@@ -1060,13 +1180,13 @@ function SummaryControls({
|
|
|
1060
1180
|
reasoningNode,
|
|
1061
1181
|
trailing
|
|
1062
1182
|
}) {
|
|
1063
|
-
return /* @__PURE__ */
|
|
1183
|
+
return /* @__PURE__ */ jsx5(
|
|
1064
1184
|
CollapsibleControls,
|
|
1065
1185
|
{
|
|
1066
1186
|
className,
|
|
1067
|
-
trigger: /* @__PURE__ */
|
|
1187
|
+
trigger: /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1068
1188
|
summary,
|
|
1069
|
-
/* @__PURE__ */
|
|
1189
|
+
/* @__PURE__ */ jsx5(ChevronDown3, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" })
|
|
1070
1190
|
] }),
|
|
1071
1191
|
triggerTitle: title,
|
|
1072
1192
|
triggerClassName: cn(
|
|
@@ -1101,15 +1221,15 @@ function CollapsibleControls({
|
|
|
1101
1221
|
reasoningNode,
|
|
1102
1222
|
trailing
|
|
1103
1223
|
}) {
|
|
1104
|
-
return /* @__PURE__ */
|
|
1224
|
+
return /* @__PURE__ */ jsxs4(
|
|
1105
1225
|
"div",
|
|
1106
1226
|
{
|
|
1107
1227
|
className: cn("flex items-center gap-2", className),
|
|
1108
1228
|
"data-testid": "agent-session-controls",
|
|
1109
1229
|
children: [
|
|
1110
|
-
trailing && /* @__PURE__ */
|
|
1111
|
-
/* @__PURE__ */
|
|
1112
|
-
/* @__PURE__ */
|
|
1230
|
+
trailing && /* @__PURE__ */ jsx5("div", { className: "flex items-center gap-2", children: trailing }),
|
|
1231
|
+
/* @__PURE__ */ jsxs4(DropdownMenu2.Root, { children: [
|
|
1232
|
+
/* @__PURE__ */ jsx5(DropdownMenu2.Trigger, { asChild: true, children: /* @__PURE__ */ jsx5(
|
|
1113
1233
|
"button",
|
|
1114
1234
|
{
|
|
1115
1235
|
type: "button",
|
|
@@ -1119,7 +1239,7 @@ function CollapsibleControls({
|
|
|
1119
1239
|
children: trigger
|
|
1120
1240
|
}
|
|
1121
1241
|
) }),
|
|
1122
|
-
/* @__PURE__ */
|
|
1242
|
+
/* @__PURE__ */ jsx5(DropdownMenu2.Portal, { children: /* @__PURE__ */ jsxs4(
|
|
1123
1243
|
DropdownMenu2.Content,
|
|
1124
1244
|
{
|
|
1125
1245
|
side: contentSide,
|
|
@@ -1141,10 +1261,10 @@ function CollapsibleControls({
|
|
|
1141
1261
|
contentClassName
|
|
1142
1262
|
),
|
|
1143
1263
|
children: [
|
|
1144
|
-
profileNode && /* @__PURE__ */
|
|
1145
|
-
harnessNode && /* @__PURE__ */
|
|
1146
|
-
modelNode && /* @__PURE__ */
|
|
1147
|
-
reasoningNode && /* @__PURE__ */
|
|
1264
|
+
profileNode && /* @__PURE__ */ jsx5(GearSection, { label: "Agent", children: profileNode }),
|
|
1265
|
+
harnessNode && /* @__PURE__ */ jsx5(GearSection, { label: "Harness", children: harnessNode }),
|
|
1266
|
+
modelNode && /* @__PURE__ */ jsx5(GearSection, { label: "Model", children: modelNode }),
|
|
1267
|
+
reasoningNode && /* @__PURE__ */ jsx5(GearSection, { label: "Effort", children: reasoningNode })
|
|
1148
1268
|
]
|
|
1149
1269
|
}
|
|
1150
1270
|
) })
|
|
@@ -1165,7 +1285,7 @@ import {
|
|
|
1165
1285
|
Upload,
|
|
1166
1286
|
X
|
|
1167
1287
|
} from "lucide-react";
|
|
1168
|
-
import * as
|
|
1288
|
+
import * as React6 from "react";
|
|
1169
1289
|
|
|
1170
1290
|
// src/chat/attachment-validation.ts
|
|
1171
1291
|
function isAcceptedType(file, accept) {
|
|
@@ -1219,7 +1339,7 @@ function validateComposerFiles(files, config) {
|
|
|
1219
1339
|
}
|
|
1220
1340
|
|
|
1221
1341
|
// src/chat/agent-composer.tsx
|
|
1222
|
-
import { Fragment as Fragment3, jsx as
|
|
1342
|
+
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1223
1343
|
var IMAGE_EXTENSION_BY_MIME = {
|
|
1224
1344
|
"image/png": "png",
|
|
1225
1345
|
"image/jpeg": "jpg",
|
|
@@ -1238,7 +1358,7 @@ function imageExtension(file) {
|
|
|
1238
1358
|
const fromName = /\.([a-z0-9]+)$/i.exec(file.name)?.[1];
|
|
1239
1359
|
return fromName?.toLowerCase() ?? "png";
|
|
1240
1360
|
}
|
|
1241
|
-
var MentionEditor =
|
|
1361
|
+
var MentionEditor = React6.lazy(() => import("./mention-editor-3Q6MYOIU.js"));
|
|
1242
1362
|
function AgentComposer({
|
|
1243
1363
|
value,
|
|
1244
1364
|
onChange,
|
|
@@ -1273,24 +1393,24 @@ function AgentComposer({
|
|
|
1273
1393
|
sendLabel = "Send",
|
|
1274
1394
|
autoFocus
|
|
1275
1395
|
}) {
|
|
1276
|
-
const textareaRef =
|
|
1277
|
-
const richFocusRef =
|
|
1278
|
-
const fileInputRef =
|
|
1279
|
-
const folderInputRef =
|
|
1280
|
-
const [dragOver, setDragOver] =
|
|
1281
|
-
const dragDepth =
|
|
1282
|
-
const pastedImageCount =
|
|
1283
|
-
const resize =
|
|
1396
|
+
const textareaRef = React6.useRef(null);
|
|
1397
|
+
const richFocusRef = React6.useRef(null);
|
|
1398
|
+
const fileInputRef = React6.useRef(null);
|
|
1399
|
+
const folderInputRef = React6.useRef(null);
|
|
1400
|
+
const [dragOver, setDragOver] = React6.useState(false);
|
|
1401
|
+
const dragDepth = React6.useRef(0);
|
|
1402
|
+
const pastedImageCount = React6.useRef(0);
|
|
1403
|
+
const resize = React6.useCallback(
|
|
1284
1404
|
(el) => {
|
|
1285
1405
|
el.style.height = "auto";
|
|
1286
1406
|
el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`;
|
|
1287
1407
|
},
|
|
1288
1408
|
[maxHeight]
|
|
1289
1409
|
);
|
|
1290
|
-
|
|
1410
|
+
React6.useEffect(() => {
|
|
1291
1411
|
if (textareaRef.current) resize(textareaRef.current);
|
|
1292
1412
|
}, [value, resize]);
|
|
1293
|
-
|
|
1413
|
+
React6.useEffect(() => {
|
|
1294
1414
|
if (!focusShortcut || disabled) return;
|
|
1295
1415
|
function onKeyDown(event) {
|
|
1296
1416
|
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "l") {
|
|
@@ -1307,7 +1427,7 @@ function AgentComposer({
|
|
|
1307
1427
|
if (!canSend) return;
|
|
1308
1428
|
onSubmit();
|
|
1309
1429
|
};
|
|
1310
|
-
const registerRichFocus =
|
|
1430
|
+
const registerRichFocus = React6.useCallback((focus) => {
|
|
1311
1431
|
richFocusRef.current = focus;
|
|
1312
1432
|
}, []);
|
|
1313
1433
|
const dropEnabled = Boolean(onAttach);
|
|
@@ -1382,13 +1502,13 @@ function AgentComposer({
|
|
|
1382
1502
|
"hover:bg-surface-container-highest hover:text-foreground focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
1383
1503
|
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
1384
1504
|
);
|
|
1385
|
-
return /* @__PURE__ */
|
|
1386
|
-
dragOver && /* @__PURE__ */
|
|
1387
|
-
/* @__PURE__ */
|
|
1388
|
-
/* @__PURE__ */
|
|
1389
|
-
/* @__PURE__ */
|
|
1505
|
+
return /* @__PURE__ */ jsxs5("div", { className: cn("relative", className), children: [
|
|
1506
|
+
dragOver && /* @__PURE__ */ jsx6("div", { className: "pointer-events-none absolute inset-0 z-10 flex items-center justify-center rounded-2xl border-2 border-dashed border-primary/50 bg-surface-container-high/95", children: /* @__PURE__ */ jsxs5("div", { className: "text-center", children: [
|
|
1507
|
+
/* @__PURE__ */ jsx6("span", { className: "mx-auto mb-2 flex size-11 items-center justify-center rounded-xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx6(Upload, { className: "size-5" }) }),
|
|
1508
|
+
/* @__PURE__ */ jsx6("p", { className: "font-semibold text-foreground text-sm", children: dropTitle }),
|
|
1509
|
+
/* @__PURE__ */ jsx6("p", { className: "mt-0.5 text-muted-foreground text-xs", children: dropDescription })
|
|
1390
1510
|
] }) }),
|
|
1391
|
-
/* @__PURE__ */
|
|
1511
|
+
/* @__PURE__ */ jsxs5(
|
|
1392
1512
|
"div",
|
|
1393
1513
|
{
|
|
1394
1514
|
"data-testid": "agent-composer",
|
|
@@ -1402,10 +1522,10 @@ function AgentComposer({
|
|
|
1402
1522
|
disabled && "opacity-60"
|
|
1403
1523
|
),
|
|
1404
1524
|
children: [
|
|
1405
|
-
attachments.length > 0 && /* @__PURE__ */
|
|
1525
|
+
attachments.length > 0 && /* @__PURE__ */ jsx6("div", { className: "flex flex-wrap gap-1.5", children: [...folderChips, ...fileChips].map((file) => {
|
|
1406
1526
|
const isError = file.status === "error";
|
|
1407
1527
|
const isPending = file.status === "pending";
|
|
1408
|
-
return /* @__PURE__ */
|
|
1528
|
+
return /* @__PURE__ */ jsxs5(
|
|
1409
1529
|
"span",
|
|
1410
1530
|
{
|
|
1411
1531
|
title: isError ? file.errorMessage : void 0,
|
|
@@ -1415,40 +1535,40 @@ function AgentComposer({
|
|
|
1415
1535
|
isPending && "opacity-60"
|
|
1416
1536
|
),
|
|
1417
1537
|
children: [
|
|
1418
|
-
file.kind !== "folder" && file.previewUrl ? /* @__PURE__ */
|
|
1538
|
+
file.kind !== "folder" && file.previewUrl ? /* @__PURE__ */ jsx6(
|
|
1419
1539
|
"img",
|
|
1420
1540
|
{
|
|
1421
1541
|
src: file.previewUrl,
|
|
1422
1542
|
alt: "",
|
|
1423
1543
|
className: "size-8 rounded object-cover"
|
|
1424
1544
|
}
|
|
1425
|
-
) : file.kind === "folder" ? /* @__PURE__ */
|
|
1426
|
-
/* @__PURE__ */
|
|
1427
|
-
file.fileCount !== void 0 && /* @__PURE__ */
|
|
1545
|
+
) : file.kind === "folder" ? /* @__PURE__ */ jsx6(Folder, { className: "size-3 shrink-0" }) : /* @__PURE__ */ jsx6(Paperclip, { className: "size-3 shrink-0" }),
|
|
1546
|
+
/* @__PURE__ */ jsx6("span", { className: "max-w-[150px] truncate", children: file.name }),
|
|
1547
|
+
file.fileCount !== void 0 && /* @__PURE__ */ jsxs5("span", { className: "text-muted-foreground", children: [
|
|
1428
1548
|
"(",
|
|
1429
1549
|
file.fileCount,
|
|
1430
1550
|
")"
|
|
1431
1551
|
] }),
|
|
1432
|
-
file.status === "uploading" && /* @__PURE__ */
|
|
1433
|
-
isError && file.errorMessage && /* @__PURE__ */
|
|
1434
|
-
isError && onRetryFile && /* @__PURE__ */
|
|
1552
|
+
file.status === "uploading" && /* @__PURE__ */ jsx6(Loader2, { className: "size-3 animate-spin" }),
|
|
1553
|
+
isError && file.errorMessage && /* @__PURE__ */ jsx6("span", { className: "max-w-[150px] truncate text-[var(--status-error,#ff4d6d)]/80", children: file.errorMessage }),
|
|
1554
|
+
isError && onRetryFile && /* @__PURE__ */ jsx6(
|
|
1435
1555
|
"button",
|
|
1436
1556
|
{
|
|
1437
1557
|
type: "button",
|
|
1438
1558
|
"aria-label": `Retry upload ${file.name}`,
|
|
1439
1559
|
onClick: () => onRetryFile(file.id),
|
|
1440
1560
|
className: "rounded p-0.5 text-muted-foreground transition-colors hover:text-foreground focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
1441
|
-
children: /* @__PURE__ */
|
|
1561
|
+
children: /* @__PURE__ */ jsx6(RotateCcw, { className: "size-3" })
|
|
1442
1562
|
}
|
|
1443
1563
|
),
|
|
1444
|
-
onRemoveFile && /* @__PURE__ */
|
|
1564
|
+
onRemoveFile && /* @__PURE__ */ jsx6(
|
|
1445
1565
|
"button",
|
|
1446
1566
|
{
|
|
1447
1567
|
type: "button",
|
|
1448
1568
|
"aria-label": `Remove ${file.name}`,
|
|
1449
1569
|
onClick: () => onRemoveFile(file.id),
|
|
1450
1570
|
className: "rounded p-0.5 text-muted-foreground transition-colors hover:text-foreground focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
1451
|
-
children: /* @__PURE__ */
|
|
1571
|
+
children: /* @__PURE__ */ jsx6(X, { className: "size-3" })
|
|
1452
1572
|
}
|
|
1453
1573
|
)
|
|
1454
1574
|
]
|
|
@@ -1456,10 +1576,10 @@ function AgentComposer({
|
|
|
1456
1576
|
file.id
|
|
1457
1577
|
);
|
|
1458
1578
|
}) }),
|
|
1459
|
-
mention ? /* @__PURE__ */
|
|
1460
|
-
|
|
1579
|
+
mention ? /* @__PURE__ */ jsx6(
|
|
1580
|
+
React6.Suspense,
|
|
1461
1581
|
{
|
|
1462
|
-
fallback: /* @__PURE__ */
|
|
1582
|
+
fallback: /* @__PURE__ */ jsx6(
|
|
1463
1583
|
"textarea",
|
|
1464
1584
|
{
|
|
1465
1585
|
rows: minRows,
|
|
@@ -1473,7 +1593,7 @@ function AgentComposer({
|
|
|
1473
1593
|
)
|
|
1474
1594
|
}
|
|
1475
1595
|
),
|
|
1476
|
-
children: /* @__PURE__ */
|
|
1596
|
+
children: /* @__PURE__ */ jsx6(
|
|
1477
1597
|
MentionEditor,
|
|
1478
1598
|
{
|
|
1479
1599
|
value,
|
|
@@ -1490,7 +1610,7 @@ function AgentComposer({
|
|
|
1490
1610
|
}
|
|
1491
1611
|
)
|
|
1492
1612
|
}
|
|
1493
|
-
) : /* @__PURE__ */
|
|
1613
|
+
) : /* @__PURE__ */ jsx6(
|
|
1494
1614
|
"textarea",
|
|
1495
1615
|
{
|
|
1496
1616
|
ref: textareaRef,
|
|
@@ -1515,9 +1635,9 @@ function AgentComposer({
|
|
|
1515
1635
|
)
|
|
1516
1636
|
}
|
|
1517
1637
|
),
|
|
1518
|
-
/* @__PURE__ */
|
|
1519
|
-
onAttach && /* @__PURE__ */
|
|
1520
|
-
/* @__PURE__ */
|
|
1638
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-end gap-2", children: [
|
|
1639
|
+
onAttach && /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
1640
|
+
/* @__PURE__ */ jsx6(
|
|
1521
1641
|
"button",
|
|
1522
1642
|
{
|
|
1523
1643
|
type: "button",
|
|
@@ -1526,10 +1646,10 @@ function AgentComposer({
|
|
|
1526
1646
|
"aria-label": "Attach files",
|
|
1527
1647
|
title: "Attach files",
|
|
1528
1648
|
className: attachButtonClass,
|
|
1529
|
-
children: /* @__PURE__ */
|
|
1649
|
+
children: /* @__PURE__ */ jsx6(Paperclip, { className: "size-4" })
|
|
1530
1650
|
}
|
|
1531
1651
|
),
|
|
1532
|
-
/* @__PURE__ */
|
|
1652
|
+
/* @__PURE__ */ jsx6(
|
|
1533
1653
|
"input",
|
|
1534
1654
|
{
|
|
1535
1655
|
ref: fileInputRef,
|
|
@@ -1545,8 +1665,8 @@ function AgentComposer({
|
|
|
1545
1665
|
}
|
|
1546
1666
|
)
|
|
1547
1667
|
] }),
|
|
1548
|
-
onAttachFolder && /* @__PURE__ */
|
|
1549
|
-
/* @__PURE__ */
|
|
1668
|
+
onAttachFolder && /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
1669
|
+
/* @__PURE__ */ jsx6(
|
|
1550
1670
|
"button",
|
|
1551
1671
|
{
|
|
1552
1672
|
type: "button",
|
|
@@ -1555,10 +1675,10 @@ function AgentComposer({
|
|
|
1555
1675
|
"aria-label": "Attach folder",
|
|
1556
1676
|
title: "Attach folder",
|
|
1557
1677
|
className: attachButtonClass,
|
|
1558
|
-
children: /* @__PURE__ */
|
|
1678
|
+
children: /* @__PURE__ */ jsx6(Folder, { className: "size-4" })
|
|
1559
1679
|
}
|
|
1560
1680
|
),
|
|
1561
|
-
/* @__PURE__ */
|
|
1681
|
+
/* @__PURE__ */ jsx6(
|
|
1562
1682
|
"input",
|
|
1563
1683
|
{
|
|
1564
1684
|
ref: folderInputRef,
|
|
@@ -1574,8 +1694,8 @@ function AgentComposer({
|
|
|
1574
1694
|
}
|
|
1575
1695
|
)
|
|
1576
1696
|
] }),
|
|
1577
|
-
/* @__PURE__ */
|
|
1578
|
-
controls ?? /* @__PURE__ */
|
|
1697
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 flex-1 items-center gap-2 overflow-x-auto overscroll-x-contain [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: [
|
|
1698
|
+
controls ?? /* @__PURE__ */ jsx6(
|
|
1579
1699
|
AgentSessionControls,
|
|
1580
1700
|
{
|
|
1581
1701
|
context,
|
|
@@ -1585,9 +1705,9 @@ function AgentComposer({
|
|
|
1585
1705
|
reasoning
|
|
1586
1706
|
}
|
|
1587
1707
|
),
|
|
1588
|
-
trailing && /* @__PURE__ */
|
|
1708
|
+
trailing && /* @__PURE__ */ jsx6("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: trailing })
|
|
1589
1709
|
] }),
|
|
1590
|
-
busy && onCancel ? /* @__PURE__ */
|
|
1710
|
+
busy && onCancel ? /* @__PURE__ */ jsx6(
|
|
1591
1711
|
"button",
|
|
1592
1712
|
{
|
|
1593
1713
|
type: "button",
|
|
@@ -1598,9 +1718,9 @@ function AgentComposer({
|
|
|
1598
1718
|
"bg-[var(--status-error,#ff4d6d)]/15 text-[var(--status-error,#ff4d6d)] transition-colors",
|
|
1599
1719
|
"hover:bg-[var(--status-error,#ff4d6d)]/25"
|
|
1600
1720
|
),
|
|
1601
|
-
children: /* @__PURE__ */
|
|
1721
|
+
children: /* @__PURE__ */ jsx6(Square, { className: "size-3.5 fill-current" })
|
|
1602
1722
|
}
|
|
1603
|
-
) : /* @__PURE__ */
|
|
1723
|
+
) : /* @__PURE__ */ jsx6(
|
|
1604
1724
|
"button",
|
|
1605
1725
|
{
|
|
1606
1726
|
type: "button",
|
|
@@ -1611,26 +1731,26 @@ function AgentComposer({
|
|
|
1611
1731
|
"flex size-9 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground",
|
|
1612
1732
|
"transition-opacity hover:opacity-90 disabled:opacity-40"
|
|
1613
1733
|
),
|
|
1614
|
-
children: busy ? /* @__PURE__ */
|
|
1734
|
+
children: busy ? /* @__PURE__ */ jsx6(Loader2, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsx6(ArrowUp, { className: "size-4" })
|
|
1615
1735
|
}
|
|
1616
1736
|
)
|
|
1617
1737
|
] })
|
|
1618
1738
|
]
|
|
1619
1739
|
}
|
|
1620
1740
|
),
|
|
1621
|
-
focusShortcut && /* @__PURE__ */
|
|
1622
|
-
/* @__PURE__ */
|
|
1623
|
-
/* @__PURE__ */
|
|
1624
|
-
/* @__PURE__ */
|
|
1741
|
+
focusShortcut && /* @__PURE__ */ jsx6("div", { className: "mt-1.5 flex justify-end px-1", children: /* @__PURE__ */ jsxs5("span", { className: "text-muted-foreground text-xs", children: [
|
|
1742
|
+
/* @__PURE__ */ jsx6("kbd", { className: "rounded border border-[var(--md3-outline-variant)] bg-surface-container px-1 py-0.5 text-[10px]", children: "Cmd" }),
|
|
1743
|
+
/* @__PURE__ */ jsx6("kbd", { className: "ml-0.5 rounded border border-[var(--md3-outline-variant)] bg-surface-container px-1 py-0.5 text-[10px]", children: "L" }),
|
|
1744
|
+
/* @__PURE__ */ jsx6("span", { className: "ml-1", children: "to focus" })
|
|
1625
1745
|
] }) })
|
|
1626
1746
|
] });
|
|
1627
1747
|
}
|
|
1628
1748
|
|
|
1629
1749
|
// src/chat/artifact-agent-dock.tsx
|
|
1630
|
-
import * as
|
|
1750
|
+
import * as React7 from "react";
|
|
1631
1751
|
import { Sparkles as Sparkles2, Send, Square as Square2, X as X2 } from "lucide-react";
|
|
1632
1752
|
import { ChatMessage } from "@tangle-network/ui/chat";
|
|
1633
|
-
import { jsx as
|
|
1753
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1634
1754
|
function defaultScopeLabel(scope) {
|
|
1635
1755
|
if (scope.label) return scope.label;
|
|
1636
1756
|
switch (scope.kind) {
|
|
@@ -1676,23 +1796,23 @@ function ArtifactAgentDock({
|
|
|
1676
1796
|
onError,
|
|
1677
1797
|
className
|
|
1678
1798
|
}) {
|
|
1679
|
-
const [threadId, setThreadId] =
|
|
1680
|
-
const [messages, setMessages] =
|
|
1681
|
-
const [composer, setComposer] =
|
|
1682
|
-
const [streamContent, setStreamContent] =
|
|
1683
|
-
const [sending, setSending] =
|
|
1684
|
-
const [loading, setLoading] =
|
|
1685
|
-
const abortRef =
|
|
1686
|
-
const scrollRef =
|
|
1687
|
-
const scopeTokenRef =
|
|
1688
|
-
const reportError =
|
|
1799
|
+
const [threadId, setThreadId] = React7.useState(null);
|
|
1800
|
+
const [messages, setMessages] = React7.useState([]);
|
|
1801
|
+
const [composer, setComposer] = React7.useState(defaultPrompt ?? "");
|
|
1802
|
+
const [streamContent, setStreamContent] = React7.useState("");
|
|
1803
|
+
const [sending, setSending] = React7.useState(false);
|
|
1804
|
+
const [loading, setLoading] = React7.useState(false);
|
|
1805
|
+
const abortRef = React7.useRef(null);
|
|
1806
|
+
const scrollRef = React7.useRef(null);
|
|
1807
|
+
const scopeTokenRef = React7.useRef(0);
|
|
1808
|
+
const reportError = React7.useCallback(
|
|
1689
1809
|
(message) => {
|
|
1690
1810
|
if (onError) onError(message);
|
|
1691
1811
|
else if (typeof console !== "undefined") console.error("[ArtifactAgentDock]", message);
|
|
1692
1812
|
},
|
|
1693
1813
|
[onError]
|
|
1694
1814
|
);
|
|
1695
|
-
|
|
1815
|
+
React7.useEffect(() => {
|
|
1696
1816
|
if (!open) return;
|
|
1697
1817
|
scopeTokenRef.current += 1;
|
|
1698
1818
|
abortRef.current?.abort();
|
|
@@ -1728,11 +1848,11 @@ function ArtifactAgentDock({
|
|
|
1728
1848
|
cancelled = true;
|
|
1729
1849
|
};
|
|
1730
1850
|
}, [open, scope.kind, scope.key, transport, reportError]);
|
|
1731
|
-
|
|
1851
|
+
React7.useEffect(() => {
|
|
1732
1852
|
if (!scrollRef.current) return;
|
|
1733
1853
|
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
|
1734
1854
|
}, [messages.length, streamContent]);
|
|
1735
|
-
const send =
|
|
1855
|
+
const send = React7.useCallback(async () => {
|
|
1736
1856
|
const text = composer.trim();
|
|
1737
1857
|
if (!text || !threadId || sending) return;
|
|
1738
1858
|
const token = scopeTokenRef.current;
|
|
@@ -1782,7 +1902,7 @@ function ArtifactAgentDock({
|
|
|
1782
1902
|
if (abortRef.current === controller) abortRef.current = null;
|
|
1783
1903
|
}
|
|
1784
1904
|
}, [composer, threadId, sending, transport, reportError]);
|
|
1785
|
-
const cancel =
|
|
1905
|
+
const cancel = React7.useCallback(() => {
|
|
1786
1906
|
if (threadId && transport.cancel) {
|
|
1787
1907
|
try {
|
|
1788
1908
|
void Promise.resolve(transport.cancel({ threadId })).catch(() => {
|
|
@@ -1796,7 +1916,7 @@ function ArtifactAgentDock({
|
|
|
1796
1916
|
}, [threadId, transport]);
|
|
1797
1917
|
if (!open) return null;
|
|
1798
1918
|
const heading = defaultScopeLabel(scope);
|
|
1799
|
-
return /* @__PURE__ */
|
|
1919
|
+
return /* @__PURE__ */ jsxs6(
|
|
1800
1920
|
"aside",
|
|
1801
1921
|
{
|
|
1802
1922
|
className: cn(
|
|
@@ -1805,38 +1925,38 @@ function ArtifactAgentDock({
|
|
|
1805
1925
|
),
|
|
1806
1926
|
"aria-label": `Agent chat about ${heading}`,
|
|
1807
1927
|
children: [
|
|
1808
|
-
/* @__PURE__ */
|
|
1809
|
-
/* @__PURE__ */
|
|
1810
|
-
/* @__PURE__ */
|
|
1811
|
-
/* @__PURE__ */
|
|
1812
|
-
/* @__PURE__ */
|
|
1813
|
-
/* @__PURE__ */
|
|
1928
|
+
/* @__PURE__ */ jsxs6("header", { className: "flex items-center justify-between border-b border-[var(--md3-outline-variant)] bg-surface-container-low px-4 py-3", children: [
|
|
1929
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1930
|
+
/* @__PURE__ */ jsx7(Sparkles2, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
|
|
1931
|
+
/* @__PURE__ */ jsxs6("div", { className: "min-w-0", children: [
|
|
1932
|
+
/* @__PURE__ */ jsx7("div", { className: "text-[10px] font-medium uppercase tracking-wider text-muted-foreground", children: "Discussing" }),
|
|
1933
|
+
/* @__PURE__ */ jsx7("div", { className: "truncate text-sm font-semibold text-foreground", children: heading })
|
|
1814
1934
|
] })
|
|
1815
1935
|
] }),
|
|
1816
|
-
/* @__PURE__ */
|
|
1936
|
+
/* @__PURE__ */ jsx7(
|
|
1817
1937
|
"button",
|
|
1818
1938
|
{
|
|
1819
1939
|
type: "button",
|
|
1820
1940
|
onClick: () => onOpenChange(false),
|
|
1821
1941
|
"aria-label": "Close artifact chat",
|
|
1822
1942
|
className: "rounded-md p-1 text-muted-foreground transition-colors hover:bg-surface-container-high hover:text-foreground",
|
|
1823
|
-
children: /* @__PURE__ */
|
|
1943
|
+
children: /* @__PURE__ */ jsx7(X2, { className: "h-4 w-4" })
|
|
1824
1944
|
}
|
|
1825
1945
|
)
|
|
1826
1946
|
] }),
|
|
1827
|
-
/* @__PURE__ */
|
|
1828
|
-
/* @__PURE__ */
|
|
1829
|
-
/* @__PURE__ */
|
|
1947
|
+
/* @__PURE__ */ jsx7("div", { ref: scrollRef, className: "flex-1 overflow-y-auto px-3 py-4", children: loading ? /* @__PURE__ */ jsx7("div", { className: "px-3 py-8 text-center text-xs text-muted-foreground", children: "Loading conversation\u2026" }) : messages.length === 0 && !streamContent ? /* @__PURE__ */ jsxs6("div", { className: "px-3 py-12 text-center", children: [
|
|
1948
|
+
/* @__PURE__ */ jsx7(Sparkles2, { className: "mx-auto mb-3 h-5 w-5 text-muted-foreground/40" }),
|
|
1949
|
+
/* @__PURE__ */ jsxs6("p", { className: "text-sm text-foreground", children: [
|
|
1830
1950
|
"Ask the agent about this ",
|
|
1831
1951
|
scope.kind === "vault-file" ? "document" : scope.kind,
|
|
1832
1952
|
"."
|
|
1833
1953
|
] }),
|
|
1834
|
-
/* @__PURE__ */
|
|
1835
|
-
] }) : /* @__PURE__ */
|
|
1836
|
-
messages.map((m) => /* @__PURE__ */
|
|
1837
|
-
streamContent && /* @__PURE__ */
|
|
1954
|
+
/* @__PURE__ */ jsx7("p", { className: "mt-1 text-xs text-muted-foreground", children: "It can read the current contents and propose edits, rewrites, or follow-ups." })
|
|
1955
|
+
] }) : /* @__PURE__ */ jsxs6("div", { className: "space-y-3", children: [
|
|
1956
|
+
messages.map((m) => /* @__PURE__ */ jsx7(ChatMessage, { role: m.role, content: m.content, timestamp: m.createdAt }, m.id)),
|
|
1957
|
+
streamContent && /* @__PURE__ */ jsx7(ChatMessage, { role: "assistant", content: streamContent, isStreaming: true })
|
|
1838
1958
|
] }) }),
|
|
1839
|
-
/* @__PURE__ */
|
|
1959
|
+
/* @__PURE__ */ jsx7(
|
|
1840
1960
|
"form",
|
|
1841
1961
|
{
|
|
1842
1962
|
className: "border-t border-[var(--md3-outline-variant)] bg-surface-container-low p-3",
|
|
@@ -1844,8 +1964,8 @@ function ArtifactAgentDock({
|
|
|
1844
1964
|
e.preventDefault();
|
|
1845
1965
|
void send();
|
|
1846
1966
|
},
|
|
1847
|
-
children: /* @__PURE__ */
|
|
1848
|
-
/* @__PURE__ */
|
|
1967
|
+
children: /* @__PURE__ */ jsxs6("div", { className: "flex items-end gap-2", children: [
|
|
1968
|
+
/* @__PURE__ */ jsx7(
|
|
1849
1969
|
"textarea",
|
|
1850
1970
|
{
|
|
1851
1971
|
value: composer,
|
|
@@ -1862,23 +1982,23 @@ function ArtifactAgentDock({
|
|
|
1862
1982
|
className: "min-h-[44px] flex-1 resize-none rounded-[20px] border border-[var(--md3-outline-variant)] bg-surface-dim px-3.5 py-2 text-sm text-foreground placeholder:text-muted-foreground transition-colors focus:outline-none focus:border-[var(--border-accent)] disabled:opacity-50"
|
|
1863
1983
|
}
|
|
1864
1984
|
),
|
|
1865
|
-
sending ? /* @__PURE__ */
|
|
1985
|
+
sending ? /* @__PURE__ */ jsx7(
|
|
1866
1986
|
"button",
|
|
1867
1987
|
{
|
|
1868
1988
|
type: "button",
|
|
1869
1989
|
onClick: cancel,
|
|
1870
1990
|
"aria-label": "Cancel",
|
|
1871
1991
|
className: "inline-flex h-9 w-9 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-surface-container-high hover:text-foreground",
|
|
1872
|
-
children: /* @__PURE__ */
|
|
1992
|
+
children: /* @__PURE__ */ jsx7(Square2, { className: "h-4 w-4" })
|
|
1873
1993
|
}
|
|
1874
|
-
) : /* @__PURE__ */
|
|
1994
|
+
) : /* @__PURE__ */ jsx7(
|
|
1875
1995
|
"button",
|
|
1876
1996
|
{
|
|
1877
1997
|
type: "submit",
|
|
1878
1998
|
disabled: !composer.trim() || !threadId,
|
|
1879
1999
|
"aria-label": "Send",
|
|
1880
2000
|
className: "inline-flex h-9 w-9 items-center justify-center rounded-full bg-primary text-primary-foreground transition-colors hover:bg-primary/90 disabled:opacity-50",
|
|
1881
|
-
children: /* @__PURE__ */
|
|
2001
|
+
children: /* @__PURE__ */ jsx7(Send, { className: "h-4 w-4" })
|
|
1882
2002
|
}
|
|
1883
2003
|
)
|
|
1884
2004
|
] })
|