@tangle-network/agent-app 0.45.35 → 0.45.36
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/{agent-session-controls-1q1XR3j8.d.ts → agent-session-controls-CCeu5QLS.d.ts} +59 -5
- package/dist/assistant/index.d.ts +1 -1
- package/dist/assistant/index.js +2 -2
- package/dist/chat-react/index.d.ts +1 -1
- package/dist/chat-react/index.js +1 -1
- package/dist/{chunk-MIZMWCKW.js → chunk-3AXSERRK.js} +258 -110
- package/dist/chunk-3AXSERRK.js.map +1 -0
- package/dist/{chunk-AIHKKLKY.js → chunk-H3LYJIAQ.js} +2 -2
- package/dist/chunk-H3LYJIAQ.js.map +1 -0
- package/dist/web-react/index.d.ts +1 -1
- package/dist/web-react/index.js +6 -2
- package/package.json +6 -2
- package/dist/chunk-AIHKKLKY.js.map +0 -1
- package/dist/chunk-MIZMWCKW.js.map +0 -1
|
@@ -56,7 +56,16 @@ function ProviderLogo({ provider, size = 16 }) {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
// src/web-react/controls.tsx
|
|
59
|
-
import {
|
|
59
|
+
import {
|
|
60
|
+
useCallback,
|
|
61
|
+
useEffect,
|
|
62
|
+
useId,
|
|
63
|
+
useLayoutEffect,
|
|
64
|
+
useMemo,
|
|
65
|
+
useRef,
|
|
66
|
+
useState
|
|
67
|
+
} from "react";
|
|
68
|
+
import { createPortal } from "react-dom";
|
|
60
69
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
61
70
|
function ChevronDown({ className }) {
|
|
62
71
|
return /* @__PURE__ */ jsx2("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx2("path", { d: "m6 9 6 6 6-6" }) });
|
|
@@ -88,10 +97,18 @@ function CheckGlyph({ className }) {
|
|
|
88
97
|
function usePopover(open, setOpen) {
|
|
89
98
|
const containerRef = useRef(null);
|
|
90
99
|
const triggerRef = useRef(null);
|
|
100
|
+
const panelRef = useRef(null);
|
|
91
101
|
useEffect(() => {
|
|
92
102
|
if (!open) return;
|
|
93
103
|
function onMouseDown(e) {
|
|
94
|
-
|
|
104
|
+
const target = e.target;
|
|
105
|
+
if (containerRef.current?.contains(target)) return;
|
|
106
|
+
const panel = panelRef.current;
|
|
107
|
+
if (panel?.contains(target)) return;
|
|
108
|
+
const ownPath = panel?.getAttribute(POPOVER_SURFACE_ATTR);
|
|
109
|
+
const hitPath = target instanceof Element ? target.closest(`[${POPOVER_SURFACE_ATTR}]`)?.getAttribute(POPOVER_SURFACE_ATTR) : null;
|
|
110
|
+
if (ownPath && hitPath && (hitPath === ownPath || hitPath.startsWith(`${ownPath}${POPOVER_PATH_SEPARATOR}`))) return;
|
|
111
|
+
setOpen(false);
|
|
95
112
|
}
|
|
96
113
|
function onKeyDown(e) {
|
|
97
114
|
if (e.key === "Escape") {
|
|
@@ -109,6 +126,7 @@ function usePopover(open, setOpen) {
|
|
|
109
126
|
return {
|
|
110
127
|
containerRef,
|
|
111
128
|
triggerRef,
|
|
129
|
+
panelRef,
|
|
112
130
|
triggerProps: {
|
|
113
131
|
ref: triggerRef,
|
|
114
132
|
"aria-haspopup": true,
|
|
@@ -116,6 +134,91 @@ function usePopover(open, setOpen) {
|
|
|
116
134
|
}
|
|
117
135
|
};
|
|
118
136
|
}
|
|
137
|
+
var POPOVER_GAP = 8;
|
|
138
|
+
var POPOVER_VIEWPORT_MARGIN = 16;
|
|
139
|
+
var POPOVER_MIN_HEIGHT = 120;
|
|
140
|
+
var POPOVER_SURFACE_ATTR = "data-agent-app-popover";
|
|
141
|
+
var POPOVER_PATH_SEPARATOR = "/";
|
|
142
|
+
var useBrowserLayoutEffect = typeof document !== "undefined" ? useLayoutEffect : useEffect;
|
|
143
|
+
function PopoverSurface({
|
|
144
|
+
open,
|
|
145
|
+
triggerRef,
|
|
146
|
+
panelRef,
|
|
147
|
+
className,
|
|
148
|
+
role,
|
|
149
|
+
id,
|
|
150
|
+
matchTriggerWidth,
|
|
151
|
+
children
|
|
152
|
+
}) {
|
|
153
|
+
const surfaceId = useId();
|
|
154
|
+
const [style, setStyle] = useState(() => ({
|
|
155
|
+
position: "fixed",
|
|
156
|
+
top: 0,
|
|
157
|
+
left: 0,
|
|
158
|
+
visibility: "hidden"
|
|
159
|
+
}));
|
|
160
|
+
const place = useCallback(() => {
|
|
161
|
+
const trigger = triggerRef.current;
|
|
162
|
+
const panel = panelRef.current;
|
|
163
|
+
if (!trigger || !panel) return;
|
|
164
|
+
const anchor = trigger.getBoundingClientRect();
|
|
165
|
+
const viewportWidth = window.innerWidth;
|
|
166
|
+
const viewportHeight = window.innerHeight;
|
|
167
|
+
const contentHeight = panel.scrollHeight;
|
|
168
|
+
const panelWidth = panel.offsetWidth;
|
|
169
|
+
const roomAbove = anchor.top - POPOVER_GAP - POPOVER_VIEWPORT_MARGIN;
|
|
170
|
+
const roomBelow = viewportHeight - anchor.bottom - POPOVER_GAP - POPOVER_VIEWPORT_MARGIN;
|
|
171
|
+
const above = contentHeight <= roomAbove || roomAbove >= roomBelow;
|
|
172
|
+
const maxHeight = Math.max(POPOVER_MIN_HEIGHT, above ? roomAbove : roomBelow);
|
|
173
|
+
const height = Math.min(contentHeight, maxHeight);
|
|
174
|
+
const top = above ? Math.max(POPOVER_VIEWPORT_MARGIN, anchor.top - POPOVER_GAP - height) : anchor.bottom + POPOVER_GAP;
|
|
175
|
+
const rightBound = Math.max(POPOVER_VIEWPORT_MARGIN, viewportWidth - panelWidth - POPOVER_VIEWPORT_MARGIN);
|
|
176
|
+
const left = Math.min(Math.max(POPOVER_VIEWPORT_MARGIN, anchor.left), rightBound);
|
|
177
|
+
setStyle({
|
|
178
|
+
position: "fixed",
|
|
179
|
+
top,
|
|
180
|
+
left,
|
|
181
|
+
maxHeight,
|
|
182
|
+
visibility: "visible",
|
|
183
|
+
...matchTriggerWidth ? { minWidth: anchor.width } : {}
|
|
184
|
+
});
|
|
185
|
+
}, [matchTriggerWidth, panelRef, triggerRef]);
|
|
186
|
+
useBrowserLayoutEffect(() => {
|
|
187
|
+
if (!open) {
|
|
188
|
+
setStyle({ position: "fixed", top: 0, left: 0, visibility: "hidden" });
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
place();
|
|
192
|
+
}, [open, place]);
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
if (!open) return;
|
|
195
|
+
const onViewportChange = () => place();
|
|
196
|
+
window.addEventListener("scroll", onViewportChange, true);
|
|
197
|
+
window.addEventListener("resize", onViewportChange);
|
|
198
|
+
return () => {
|
|
199
|
+
window.removeEventListener("scroll", onViewportChange, true);
|
|
200
|
+
window.removeEventListener("resize", onViewportChange);
|
|
201
|
+
};
|
|
202
|
+
}, [open, place]);
|
|
203
|
+
if (!open || typeof document === "undefined") return null;
|
|
204
|
+
const ownerPath = triggerRef.current?.closest?.(`[${POPOVER_SURFACE_ATTR}]`)?.getAttribute(POPOVER_SURFACE_ATTR);
|
|
205
|
+
const path = ownerPath ? `${ownerPath}${POPOVER_PATH_SEPARATOR}${surfaceId}` : surfaceId;
|
|
206
|
+
return createPortal(
|
|
207
|
+
/* @__PURE__ */ jsx2(
|
|
208
|
+
"div",
|
|
209
|
+
{
|
|
210
|
+
ref: panelRef,
|
|
211
|
+
id,
|
|
212
|
+
role,
|
|
213
|
+
style,
|
|
214
|
+
...{ [POPOVER_SURFACE_ATTR]: path },
|
|
215
|
+
className: `z-[1000] ${className ?? ""}`,
|
|
216
|
+
children
|
|
217
|
+
}
|
|
218
|
+
),
|
|
219
|
+
document.body
|
|
220
|
+
);
|
|
221
|
+
}
|
|
119
222
|
var POPOVER_OPTION_FOCUS = "focus-visible:[outline-offset:-2px]";
|
|
120
223
|
var OVERLAY_SHADOW = "shadow-[0_1px_2px_hsl(var(--foreground)/0.05),0_12px_28px_hsl(var(--foreground)/0.07)] dark:shadow-[0_1px_2px_hsl(var(--foreground)/0.14),0_12px_28px_hsl(var(--foreground)/0.22)]";
|
|
121
224
|
function usePending() {
|
|
@@ -191,19 +294,12 @@ function ModelRow({
|
|
|
191
294
|
function ModelPicker({ value, onChange, models, loading, renderProviderBadge, recommendedLabel = "Recommended", priorityGroup }) {
|
|
192
295
|
const [open, setOpen] = useState(false);
|
|
193
296
|
const [query, setQuery] = useState("");
|
|
194
|
-
const { containerRef, triggerProps } = usePopover(open, setOpen);
|
|
297
|
+
const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen);
|
|
195
298
|
const inputRef = useRef(null);
|
|
196
|
-
const
|
|
299
|
+
const panelId = useId();
|
|
197
300
|
useEffect(() => {
|
|
198
301
|
if (open) inputRef.current?.focus();
|
|
199
302
|
}, [open]);
|
|
200
|
-
useEffect(() => {
|
|
201
|
-
if (!open) return;
|
|
202
|
-
const el = popoverRef.current;
|
|
203
|
-
if (!el) return;
|
|
204
|
-
const overflowRight = el.getBoundingClientRect().right - (window.innerWidth - 16);
|
|
205
|
-
el.style.transform = overflowRight > 0 ? `translateX(-${Math.ceil(overflowRight)}px)` : "";
|
|
206
|
-
}, [open]);
|
|
207
303
|
const selected = models.find((m) => m.id === value);
|
|
208
304
|
const filtered = useMemo(() => {
|
|
209
305
|
const q = query.trim().toLowerCase();
|
|
@@ -236,6 +332,7 @@ function ModelPicker({ value, onChange, models, loading, renderProviderBadge, re
|
|
|
236
332
|
{
|
|
237
333
|
type: "button",
|
|
238
334
|
...triggerProps,
|
|
335
|
+
"aria-controls": open ? panelId : void 0,
|
|
239
336
|
onClick: () => setOpen(!open),
|
|
240
337
|
className: "inline-flex items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent",
|
|
241
338
|
children: [
|
|
@@ -245,44 +342,54 @@ function ModelPicker({ value, onChange, models, loading, renderProviderBadge, re
|
|
|
245
342
|
]
|
|
246
343
|
}
|
|
247
344
|
),
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
/* @__PURE__ */ jsx2(
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
345
|
+
/* @__PURE__ */ jsxs2(
|
|
346
|
+
PopoverSurface,
|
|
347
|
+
{
|
|
348
|
+
open,
|
|
349
|
+
id: panelId,
|
|
350
|
+
triggerRef,
|
|
351
|
+
panelRef,
|
|
352
|
+
className: `flex w-[420px] max-w-[calc(100vw-2rem)] flex-col overflow-hidden rounded-xl border border-border bg-popover ${OVERLAY_SHADOW}`,
|
|
353
|
+
children: [
|
|
354
|
+
/* @__PURE__ */ jsx2("div", { className: "shrink-0 border-b border-border px-3 py-2", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 rounded-lg border border-border bg-background px-3 py-2", children: [
|
|
355
|
+
/* @__PURE__ */ jsx2(SearchGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
|
|
356
|
+
/* @__PURE__ */ jsx2(
|
|
357
|
+
"input",
|
|
358
|
+
{
|
|
359
|
+
ref: inputRef,
|
|
360
|
+
type: "text",
|
|
361
|
+
value: query,
|
|
362
|
+
onChange: (e) => setQuery(e.target.value),
|
|
363
|
+
placeholder: "Search models...",
|
|
364
|
+
className: "flex-1 bg-transparent text-sm placeholder:text-muted-foreground"
|
|
365
|
+
}
|
|
366
|
+
)
|
|
367
|
+
] }) }),
|
|
368
|
+
/* @__PURE__ */ jsxs2("div", { className: "max-h-[400px] min-h-0 overflow-y-auto p-1 pb-2", children: [
|
|
369
|
+
loading && /* @__PURE__ */ jsx2("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "Loading models..." }),
|
|
370
|
+
!loading && filtered && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
371
|
+
filtered.length === 0 && /* @__PURE__ */ jsx2("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No models match your search" }),
|
|
372
|
+
filtered.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
|
|
373
|
+
] }),
|
|
374
|
+
!loading && !filtered && models.length === 0 && /* @__PURE__ */ jsx2("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No models available" }),
|
|
375
|
+
!loading && !filtered && models.length > 0 && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
376
|
+
priorityGroup && sections.priority.length > 0 && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
377
|
+
/* @__PURE__ */ jsx2(SectionHeader, { children: priorityGroup.label }),
|
|
378
|
+
sections.priority.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
|
|
379
|
+
] }),
|
|
380
|
+
sections.recommended.length > 0 && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
381
|
+
/* @__PURE__ */ jsx2(SectionHeader, { children: recommendedLabel }),
|
|
382
|
+
sections.recommended.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
|
|
383
|
+
] }),
|
|
384
|
+
sections.byProvider.map((g) => /* @__PURE__ */ jsxs2("div", { children: [
|
|
385
|
+
/* @__PURE__ */ jsx2(SectionHeader, { children: g.provider }),
|
|
386
|
+
g.items.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
|
|
387
|
+
] }, g.provider))
|
|
388
|
+
] })
|
|
389
|
+
] })
|
|
390
|
+
]
|
|
391
|
+
}
|
|
392
|
+
)
|
|
286
393
|
] });
|
|
287
394
|
}
|
|
288
395
|
var DEFAULT_EFFORT_LEVELS = [
|
|
@@ -314,7 +421,8 @@ function EffortMeter({ fill, className }) {
|
|
|
314
421
|
}
|
|
315
422
|
function EffortPicker({ value, onChange, levels = DEFAULT_EFFORT_LEVELS, label = "Thinking" }) {
|
|
316
423
|
const [open, setOpen] = useState(false);
|
|
317
|
-
const { containerRef, triggerProps } = usePopover(open, setOpen);
|
|
424
|
+
const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen);
|
|
425
|
+
const panelId = useId();
|
|
318
426
|
const selected = levels.find((l) => l.id === value) ?? levels[2] ?? levels[0];
|
|
319
427
|
return /* @__PURE__ */ jsxs2("div", { ref: containerRef, className: "relative inline-flex", children: [
|
|
320
428
|
/* @__PURE__ */ jsxs2(
|
|
@@ -322,6 +430,7 @@ function EffortPicker({ value, onChange, levels = DEFAULT_EFFORT_LEVELS, label =
|
|
|
322
430
|
{
|
|
323
431
|
type: "button",
|
|
324
432
|
...triggerProps,
|
|
433
|
+
"aria-controls": open ? panelId : void 0,
|
|
325
434
|
onClick: () => setOpen(!open),
|
|
326
435
|
title: label ? `${label} \u2014 how hard the agent reasons before answering` : "Reasoning effort",
|
|
327
436
|
className: "inline-flex min-h-[36px] items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent",
|
|
@@ -339,31 +448,42 @@ function EffortPicker({ value, onChange, levels = DEFAULT_EFFORT_LEVELS, label =
|
|
|
339
448
|
]
|
|
340
449
|
}
|
|
341
450
|
),
|
|
342
|
-
|
|
343
|
-
|
|
451
|
+
/* @__PURE__ */ jsx2(
|
|
452
|
+
PopoverSurface,
|
|
344
453
|
{
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
"
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
454
|
+
open,
|
|
455
|
+
id: panelId,
|
|
456
|
+
role: "menu",
|
|
457
|
+
triggerRef,
|
|
458
|
+
panelRef,
|
|
459
|
+
className: `w-44 overflow-y-auto rounded-xl border border-border bg-popover p-1 ${OVERLAY_SHADOW}`,
|
|
460
|
+
children: levels.map((l) => /* @__PURE__ */ jsxs2(
|
|
461
|
+
"button",
|
|
462
|
+
{
|
|
463
|
+
type: "button",
|
|
464
|
+
role: "menuitemradio",
|
|
465
|
+
"aria-checked": l.id === value,
|
|
466
|
+
onClick: () => {
|
|
467
|
+
onChange(l.id);
|
|
468
|
+
setOpen(false);
|
|
469
|
+
},
|
|
470
|
+
className: `flex min-h-[40px] w-full items-center gap-2 rounded-md px-3 py-2 text-left text-sm transition ${POPOVER_OPTION_FOCUS} ${l.id === value ? "bg-primary/10 font-medium" : "hover:bg-accent"}`,
|
|
471
|
+
children: [
|
|
472
|
+
/* @__PURE__ */ jsx2(BrainGlyph, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
473
|
+
/* @__PURE__ */ jsx2("span", { className: "truncate", children: l.label }),
|
|
474
|
+
/* @__PURE__ */ jsx2(EffortMeter, { fill: effortMeterFill(l.id, levels), className: "ml-auto text-foreground" }),
|
|
475
|
+
l.id === value && /* @__PURE__ */ jsx2(CheckGlyph, { className: "h-3.5 w-3.5 shrink-0 text-primary" })
|
|
476
|
+
]
|
|
477
|
+
},
|
|
478
|
+
l.id
|
|
479
|
+
))
|
|
480
|
+
}
|
|
481
|
+
)
|
|
362
482
|
] });
|
|
363
483
|
}
|
|
364
484
|
|
|
365
485
|
// src/web-react/use-composer-attachments.ts
|
|
366
|
-
import { useCallback, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
486
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
367
487
|
function newId() {
|
|
368
488
|
const cryptoObject = globalThis.crypto;
|
|
369
489
|
if (typeof cryptoObject?.randomUUID === "function") return cryptoObject.randomUUID();
|
|
@@ -416,7 +536,7 @@ function useComposerAttachments(options) {
|
|
|
416
536
|
const [staged, setStagedState] = useState2([]);
|
|
417
537
|
const stagedRef = useRef2([]);
|
|
418
538
|
const controllersRef = useRef2(/* @__PURE__ */ new Map());
|
|
419
|
-
const setStaged =
|
|
539
|
+
const setStaged = useCallback2(
|
|
420
540
|
(updater) => {
|
|
421
541
|
const next = typeof updater === "function" ? updater(stagedRef.current) : updater;
|
|
422
542
|
stagedRef.current = next;
|
|
@@ -424,7 +544,7 @@ function useComposerAttachments(options) {
|
|
|
424
544
|
},
|
|
425
545
|
[]
|
|
426
546
|
);
|
|
427
|
-
const upload =
|
|
547
|
+
const upload = useCallback2(
|
|
428
548
|
async (id, file, name) => {
|
|
429
549
|
const opts = optionsRef.current;
|
|
430
550
|
setStaged(
|
|
@@ -487,7 +607,7 @@ function useComposerAttachments(options) {
|
|
|
487
607
|
},
|
|
488
608
|
[setStaged]
|
|
489
609
|
);
|
|
490
|
-
const addFiles =
|
|
610
|
+
const addFiles = useCallback2(
|
|
491
611
|
async (files) => {
|
|
492
612
|
const opts = optionsRef.current;
|
|
493
613
|
const enabled2 = opts.enabled ?? true;
|
|
@@ -567,7 +687,7 @@ function useComposerAttachments(options) {
|
|
|
567
687
|
},
|
|
568
688
|
[setStaged, upload]
|
|
569
689
|
);
|
|
570
|
-
const retry =
|
|
690
|
+
const retry = useCallback2(
|
|
571
691
|
(id) => {
|
|
572
692
|
const entry = stagedRef.current.find((s) => s.id === id);
|
|
573
693
|
if (!entry) return;
|
|
@@ -575,7 +695,7 @@ function useComposerAttachments(options) {
|
|
|
575
695
|
},
|
|
576
696
|
[upload]
|
|
577
697
|
);
|
|
578
|
-
const removeAttachment =
|
|
698
|
+
const removeAttachment = useCallback2(
|
|
579
699
|
(id) => {
|
|
580
700
|
controllersRef.current.get(id)?.abort();
|
|
581
701
|
controllersRef.current.delete(id);
|
|
@@ -585,7 +705,7 @@ function useComposerAttachments(options) {
|
|
|
585
705
|
},
|
|
586
706
|
[setStaged]
|
|
587
707
|
);
|
|
588
|
-
const clear =
|
|
708
|
+
const clear = useCallback2(() => {
|
|
589
709
|
for (const controller of controllersRef.current.values()) controller.abort();
|
|
590
710
|
controllersRef.current.clear();
|
|
591
711
|
for (const entry of stagedRef.current) {
|
|
@@ -723,7 +843,7 @@ function HarnessGlyph({ harness, className }) {
|
|
|
723
843
|
}
|
|
724
844
|
|
|
725
845
|
// src/web-react/agent-session-controls.tsx
|
|
726
|
-
import { useMemo as useMemo3, useState as useState3 } from "react";
|
|
846
|
+
import { useId as useId2, useMemo as useMemo3, useState as useState3 } from "react";
|
|
727
847
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
728
848
|
var HARNESS_LABELS = {
|
|
729
849
|
opencode: "OpenCode (any model)",
|
|
@@ -759,7 +879,8 @@ function HarnessPicker({
|
|
|
759
879
|
available
|
|
760
880
|
}) {
|
|
761
881
|
const [open, setOpen] = useState3(false);
|
|
762
|
-
const { containerRef, triggerProps } = usePopover(open, setOpen);
|
|
882
|
+
const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen);
|
|
883
|
+
const panelId = useId2();
|
|
763
884
|
const options = available ?? Object.keys(HARNESS_LABELS);
|
|
764
885
|
return /* @__PURE__ */ jsxs4("div", { ref: containerRef, className: "relative inline-flex", children: [
|
|
765
886
|
/* @__PURE__ */ jsxs4(
|
|
@@ -767,6 +888,7 @@ function HarnessPicker({
|
|
|
767
888
|
{
|
|
768
889
|
type: "button",
|
|
769
890
|
...triggerProps,
|
|
891
|
+
"aria-controls": open ? panelId : void 0,
|
|
770
892
|
onClick: () => setOpen(!open),
|
|
771
893
|
title: "Agent backend",
|
|
772
894
|
className: `inline-flex w-full items-center justify-between gap-1.5 rounded-lg border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent ${FOCUS_RING}`,
|
|
@@ -779,25 +901,37 @@ function HarnessPicker({
|
|
|
779
901
|
]
|
|
780
902
|
}
|
|
781
903
|
),
|
|
782
|
-
|
|
783
|
-
|
|
904
|
+
/* @__PURE__ */ jsx4(
|
|
905
|
+
PopoverSurface,
|
|
784
906
|
{
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
"
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
907
|
+
open,
|
|
908
|
+
id: panelId,
|
|
909
|
+
role: "menu",
|
|
910
|
+
triggerRef,
|
|
911
|
+
panelRef,
|
|
912
|
+
matchTriggerWidth: true,
|
|
913
|
+
className: `max-h-64 min-w-[248px] overflow-y-auto rounded-xl border border-border bg-popover p-1 ${OVERLAY_SHADOW}`,
|
|
914
|
+
children: options.map((h) => /* @__PURE__ */ jsxs4(
|
|
915
|
+
"button",
|
|
916
|
+
{
|
|
917
|
+
type: "button",
|
|
918
|
+
role: "menuitemradio",
|
|
919
|
+
"aria-checked": h === value,
|
|
920
|
+
onClick: () => {
|
|
921
|
+
onChange(h);
|
|
922
|
+
setOpen(false);
|
|
923
|
+
},
|
|
924
|
+
className: `flex w-full items-center gap-2.5 rounded-md px-3 py-2 text-left text-sm transition ${FOCUS_RING} ${h === value ? "bg-primary/10 font-medium" : "hover:bg-accent"}`,
|
|
925
|
+
children: [
|
|
926
|
+
/* @__PURE__ */ jsx4(HarnessGlyph, { harness: h, className: "h-4 w-4 shrink-0 text-foreground" }),
|
|
927
|
+
/* @__PURE__ */ jsx4("span", { className: "truncate", children: harnessLabel(h) }),
|
|
928
|
+
h === value && /* @__PURE__ */ jsx4(CheckGlyph, { className: "ml-auto h-3.5 w-3.5 shrink-0 text-primary" })
|
|
929
|
+
]
|
|
930
|
+
},
|
|
931
|
+
h
|
|
932
|
+
))
|
|
933
|
+
}
|
|
934
|
+
)
|
|
801
935
|
] });
|
|
802
936
|
}
|
|
803
937
|
function useCoherentHandlers(props) {
|
|
@@ -832,7 +966,8 @@ function AgentSessionControls(props) {
|
|
|
832
966
|
} = props;
|
|
833
967
|
const { onModel, onHarness } = useCoherentHandlers(props);
|
|
834
968
|
const [open, setOpen] = useState3(false);
|
|
835
|
-
const { containerRef: popoverRef, triggerProps } = usePopover(open, setOpen);
|
|
969
|
+
const { containerRef: popoverRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen);
|
|
970
|
+
const panelId = useId2();
|
|
836
971
|
const selectedModel = models.find((m) => m.id === model);
|
|
837
972
|
const showEffort = selectedModel?.supportsReasoning ?? true;
|
|
838
973
|
const modelPicker = /* @__PURE__ */ jsx4(
|
|
@@ -861,6 +996,7 @@ function AgentSessionControls(props) {
|
|
|
861
996
|
{
|
|
862
997
|
type: "button",
|
|
863
998
|
...triggerProps,
|
|
999
|
+
"aria-controls": open ? panelId : void 0,
|
|
864
1000
|
onClick: () => setOpen(!open),
|
|
865
1001
|
title: "Model settings \u2014 pick the agent backend and how hard it thinks",
|
|
866
1002
|
className: `flex h-8 w-8 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground data-[state=open]:bg-muted ${FOCUS_RING}`,
|
|
@@ -868,18 +1004,28 @@ function AgentSessionControls(props) {
|
|
|
868
1004
|
children: /* @__PURE__ */ jsx4(GearGlyph, { className: "h-4 w-4" })
|
|
869
1005
|
}
|
|
870
1006
|
),
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
1007
|
+
/* @__PURE__ */ jsxs4(
|
|
1008
|
+
PopoverSurface,
|
|
1009
|
+
{
|
|
1010
|
+
open,
|
|
1011
|
+
id: panelId,
|
|
1012
|
+
triggerRef,
|
|
1013
|
+
panelRef,
|
|
1014
|
+
className: `w-72 space-y-3 overflow-y-auto rounded-xl border border-border bg-popover p-3 ${OVERLAY_SHADOW}`,
|
|
1015
|
+
children: [
|
|
1016
|
+
showHarness && /* @__PURE__ */ jsxs4("div", { className: "space-y-1.5", children: [
|
|
1017
|
+
/* @__PURE__ */ jsx4("p", { className: "text-xs font-medium text-foreground", children: "Agent backend" }),
|
|
1018
|
+
/* @__PURE__ */ jsx4(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
|
|
1019
|
+
/* @__PURE__ */ jsx4("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "The engine that runs the agent. Switching it keeps your model choice compatible." })
|
|
1020
|
+
] }),
|
|
1021
|
+
showEffort && /* @__PURE__ */ jsxs4("div", { className: "space-y-1.5", children: [
|
|
1022
|
+
/* @__PURE__ */ jsx4("p", { className: "text-xs font-medium text-foreground", children: "Thinking" }),
|
|
1023
|
+
/* @__PURE__ */ jsx4(EffortPicker, { value: effort, onChange: onEffortChange, levels: effortLevels, label: "" }),
|
|
1024
|
+
/* @__PURE__ */ jsx4("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "How hard the agent thinks before answering. Higher is slower but more thorough." })
|
|
1025
|
+
] })
|
|
1026
|
+
]
|
|
1027
|
+
}
|
|
1028
|
+
)
|
|
883
1029
|
] })
|
|
884
1030
|
] });
|
|
885
1031
|
}
|
|
@@ -888,6 +1034,8 @@ export {
|
|
|
888
1034
|
ProviderLogo,
|
|
889
1035
|
ChevronDown,
|
|
890
1036
|
usePopover,
|
|
1037
|
+
POPOVER_SURFACE_ATTR,
|
|
1038
|
+
PopoverSurface,
|
|
891
1039
|
POPOVER_OPTION_FOCUS,
|
|
892
1040
|
OVERLAY_SHADOW,
|
|
893
1041
|
usePending,
|
|
@@ -901,4 +1049,4 @@ export {
|
|
|
901
1049
|
HarnessGlyph,
|
|
902
1050
|
AgentSessionControls
|
|
903
1051
|
};
|
|
904
|
-
//# sourceMappingURL=chunk-
|
|
1052
|
+
//# sourceMappingURL=chunk-3AXSERRK.js.map
|