@columenlabs/lumen-ui 0.1.216 → 0.1.218
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.
|
@@ -6,7 +6,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
6
6
|
// with Stop, a queued message and the chat's cost and context under it.
|
|
7
7
|
import { ASSISTANT_IMAGES_MAX, ASSISTANT_IMAGE_CHARS, } from '@columenlabs/lumen-ui-types/assistant';
|
|
8
8
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|
9
|
-
import { ArrowUpIcon, CheckIcon, ChevronRightIcon, CircleAlertIcon, CopyIcon, CornerDownRightIcon, CrosshairIcon, FileTextIcon, LightbulbIcon, ListPlusIcon, MonitorIcon, PencilIcon, PlusIcon, ReceiptIcon, SparklesIcon, SquareIcon, TriangleAlertIcon, Undo2Icon, WrenchIcon, XIcon, ZapIcon, } from 'lucide-react';
|
|
9
|
+
import { ArrowUpIcon, CheckIcon, ChevronRightIcon, CircleAlertIcon, CopyIcon, CornerDownRightIcon, CrosshairIcon, FileTextIcon, GlobeIcon, LightbulbIcon, ListPlusIcon, MonitorIcon, PencilIcon, PlusIcon, ReceiptIcon, SearchIcon, SparklesIcon, SquareIcon, TriangleAlertIcon, Undo2Icon, WrenchIcon, XIcon, ZapIcon, } from 'lucide-react';
|
|
10
10
|
import { Fragment, createContext, useContext, useEffect, useRef, useState, } from 'react';
|
|
11
11
|
import { LumenAssistantButton, LumenAssistantChats, LumenAssistantPanel, assistantOpen, useAssistantHotkey, } from '../assistant-panel.js';
|
|
12
12
|
import { screenMapFor, useAssistantScreen } from '../assistant-screen.js';
|
|
@@ -242,7 +242,7 @@ function Items({ items, onSettle, busy, turns, }) {
|
|
|
242
242
|
if (turns)
|
|
243
243
|
return (_jsx("div", { className: "flex flex-col gap-3", children: chatTurns(items).map((t) => {
|
|
244
244
|
const open = busy && t.from + t.items.length === items.length;
|
|
245
|
-
return (_jsxs("div", { "data-slot": "assistant-turn", className: "group/turn flex flex-col gap-3", children: [_jsx(Items, { items: t.items, onSettle: onSettle, busy: busy }), !open && (_jsx("div", { className: "-mt-2 flex justify-end opacity-0 transition-opacity group-hover/turn:opacity-100 focus-within:opacity-100 [@media(hover:none)]:opacity-100", children: _jsx(IconButton, { icon: CopyIcon, label: "Copy this turn", className: "size-6 text-muted-foreground", onClick: () => copyMarkdown(turnMarkdown(t.items, name), 'Turn') }) }))] }, t.from));
|
|
245
|
+
return (_jsxs("div", { "data-slot": "assistant-turn", className: "group/turn flex flex-col gap-3", children: [_jsx(Items, { items: t.items, onSettle: onSettle, busy: busy }), !open && _jsx(WebSources, { items: t.items }), !open && (_jsx("div", { className: "-mt-2 flex justify-end opacity-0 transition-opacity group-hover/turn:opacity-100 focus-within:opacity-100 [@media(hover:none)]:opacity-100", children: _jsx(IconButton, { icon: CopyIcon, label: "Copy this turn", className: "size-6 text-muted-foreground", onClick: () => copyMarkdown(turnMarkdown(t.items, name), 'Turn') }) }))] }, t.from));
|
|
246
246
|
}) }));
|
|
247
247
|
// Cards drafted one after another sit in one stack, so many of them skim as lines.
|
|
248
248
|
const rows = [];
|
|
@@ -326,7 +326,64 @@ function ScreenChip({ item }) {
|
|
|
326
326
|
return (_jsxs("div", { "data-slot": "assistant-screen", "data-status": status, className: "flex min-w-0 items-center gap-2 rounded-lg border bg-muted/30 px-3 py-1.5 text-muted-foreground text-xs", children: [status === 'running' ? (_jsx(Spinner, { className: "size-3.5" })) : status === 'done' ? (_jsx(CheckIcon, { className: "size-3.5 shrink-0 text-edge" })) : status === 'failed' ? (_jsx(TriangleAlertIcon, { className: "size-3.5 shrink-0 text-loss" })) : status === 'undone' ? (_jsx(Undo2Icon, { className: "size-3.5 shrink-0" })) : (_jsx(MonitorIcon, { className: "size-3.5 shrink-0" })), _jsxs("span", { className: "min-w-0 flex-1 truncate", title: `${item.label} · ${movesText(item.moves)}`, children: [_jsx("span", { className: cn(status === 'undone' ? 'line-through' : 'text-foreground'), children: item.label }), said && _jsxs("span", { children: [" \u00B7 ", said] })] }), status === 'done' && c?.canUndo(item.id) && (_jsx(IconButton, { icon: Undo2Icon, label: "Undo", size: "icon-xs", onClick: () => c.undo(item.id) })), status === 'waiting' && c && (_jsx(IconButton, { icon: MonitorIcon, label: "Go now", variant: "outline", size: "icon-xs", onClick: () => c.go(item) }))] }));
|
|
327
327
|
}
|
|
328
328
|
const Rule = ({ children }) => (_jsx("p", { className: "flex items-center gap-2 text-muted-foreground text-xs before:h-px before:flex-1 before:bg-border after:h-px after:flex-1 after:bg-border", children: children }));
|
|
329
|
+
/** A page's host without `www.`, or the address when it has none. */
|
|
330
|
+
function hostOf(url) {
|
|
331
|
+
try {
|
|
332
|
+
return new URL(url).hostname.replace(/^www\./, '');
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
return url;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
/** A page's path after its host, for a read's line. */
|
|
339
|
+
function pathOf(url) {
|
|
340
|
+
try {
|
|
341
|
+
const u = new URL(url);
|
|
342
|
+
const p = decodeURIComponent(u.pathname).replace(/\/$/, '');
|
|
343
|
+
return p.split('/').pop() || '';
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
return '';
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
/** A web step: a search, its results folded under it, or one page read. */
|
|
350
|
+
function WebStep({ step, live }) {
|
|
351
|
+
const web = step.web ?? {};
|
|
352
|
+
const results = web.results ?? [];
|
|
353
|
+
const icon = live ? (_jsx(Spinner, { className: "size-3" })) : !step.ok ? (_jsx(CircleAlertIcon, { className: "size-3.5 shrink-0" })) : web.read ? (_jsx(GlobeIcon, { className: "size-3.5 shrink-0" })) : (_jsx(SearchIcon, { className: "size-3.5 shrink-0" }));
|
|
354
|
+
const line = (_jsxs(_Fragment, { children: [icon, web.tried ? (_jsxs("span", { className: "truncate", title: web.tried.url, children: ["Could not open ", _jsx("span", { className: "text-foreground", children: hostOf(web.tried.url) })] })) : web.read ? (_jsxs("span", { className: "truncate", title: web.read.title ?? web.read.url, children: ["Read ", _jsx("span", { className: "text-foreground", children: hostOf(web.read.url) }), pathOf(web.read.url) && ` · ${pathOf(web.read.url)}`] })) : (_jsxs("span", { className: "truncate", title: web.query, children: ["Searched the web", web.query ? ': ' : '', web.query && _jsx("span", { className: "text-foreground", children: web.query })] })), !live && !web.read && !web.tried && step.ok && (_jsxs("span", { className: "ml-auto shrink-0 tabular-nums", children: [results.length, " result", results.length === 1 ? '' : 's'] })), step.error && _jsxs("span", { className: "truncate", children: ["\u00B7 ", step.error] })] }));
|
|
355
|
+
const cls = cn('flex min-w-0 items-center gap-1.5 text-xs', step.ok ? 'text-muted-foreground' : 'text-loss');
|
|
356
|
+
if (!results.length)
|
|
357
|
+
return _jsx("p", { className: cls, children: line });
|
|
358
|
+
return (_jsxs(Collapsible, { children: [_jsxs(CollapsibleTrigger, { className: cn(cls, 'group/web w-full text-left'), children: [line, _jsx(ChevronRightIcon, { className: "size-3.5 shrink-0 transition-transform group-data-[state=open]/web:rotate-90" })] }), _jsx(CollapsibleContent, { children: _jsx("ul", { className: "mt-1 ml-1.5 flex flex-col gap-0.5 border-l pl-3 text-muted-foreground text-xs", children: results.map((r) => (_jsx("li", { className: "min-w-0 truncate", children: _jsxs("a", { href: r.url, target: "_blank", rel: "noopener noreferrer", title: r.url, className: "hover:underline", children: [_jsx("span", { className: "text-foreground", children: r.title || hostOf(r.url) }), " \u00B7", ' ', hostOf(r.url)] }) }, r.url))) }) })] }));
|
|
359
|
+
}
|
|
360
|
+
/** The pages a turn read, once each, in the order read: the numbers its answer cites. */
|
|
361
|
+
function turnPages(items) {
|
|
362
|
+
const pages = [];
|
|
363
|
+
const walk = (list) => {
|
|
364
|
+
for (const i of list) {
|
|
365
|
+
if (i.kind === 'handoff')
|
|
366
|
+
walk(i.items);
|
|
367
|
+
else if (i.kind === 'step' && i.web?.read && !pages.some((p) => p.url === i.web?.read?.url))
|
|
368
|
+
pages.push(i.web.read);
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
walk(items);
|
|
372
|
+
return pages;
|
|
373
|
+
}
|
|
374
|
+
/** The pages a turn read, as numbered chips under its answer; each opens in a new tab. */
|
|
375
|
+
function WebSources({ items }) {
|
|
376
|
+
const pages = turnPages(items);
|
|
377
|
+
if (!pages.length)
|
|
378
|
+
return null;
|
|
379
|
+
return (_jsx("ol", { "aria-label": "Sources", className: "flex min-w-0 flex-wrap gap-1.5", children: pages.map((p, n) => (_jsx("li", { className: "min-w-0 max-w-full", children: _jsxs("a", { href: p.url, target: "_blank", rel: "noopener noreferrer", title: p.title ? `${p.title} · ${p.url}` : p.url, className: "flex h-6 min-w-0 items-center gap-1.5 rounded-full border pr-2.5 pl-1 text-xs hover:bg-muted", children: [_jsx("span", { className: "grid size-4 shrink-0 place-items-center rounded-full bg-primary/15 font-medium text-primary text-xs tabular-nums", children: n + 1 }), _jsx("span", { className: "truncate", children: hostOf(p.url) })] }) }, p.url))) }));
|
|
380
|
+
}
|
|
329
381
|
function Step({ step, live }) {
|
|
382
|
+
if (step.web)
|
|
383
|
+
return _jsx(WebStep, { step: step, live: live });
|
|
384
|
+
return _jsx(ToolStep, { step: step, live: live });
|
|
385
|
+
}
|
|
386
|
+
function ToolStep({ step, live }) {
|
|
330
387
|
const undo = useContext(UndoWrite);
|
|
331
388
|
const [undoing, setUndoing] = useState(false);
|
|
332
389
|
const w = step.write;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@columenlabs/lumen-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.218",
|
|
4
4
|
"description": "Lumen: shared React components (frame, views, widgets, charts, drawers).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@codemirror/lang-javascript": "6.2.5",
|
|
50
50
|
"@codemirror/lang-json": "6.0.2",
|
|
51
51
|
"@codemirror/lang-sql": "6.10.0",
|
|
52
|
-
"@columenlabs/lumen-ui-types": "0.1.
|
|
52
|
+
"@columenlabs/lumen-ui-types": "0.1.218",
|
|
53
53
|
"@dnd-kit/core": "6.3.1",
|
|
54
54
|
"@dnd-kit/sortable": "10.0.0",
|
|
55
55
|
"@dnd-kit/utilities": "3.2.2",
|