@2lab.ai/ui 0.1.1 → 0.2.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/README.md +1 -0
- package/dist/agent-inbox.js +1 -1
- package/dist/agent-queue.js +1 -1
- package/dist/agent-run.js +1 -1
- package/dist/ai-answer.js +1 -1
- package/dist/components/tool-call-card/index.d.ts +7 -0
- package/dist/components/tool-call-card/logic.d.ts +87 -0
- package/dist/components/tool-call-card/strings.d.ts +94 -0
- package/dist/components/tool-call-card/styles.d.ts +5 -0
- package/dist/components/tool-call-card/tool-call-card.d.ts +49 -0
- package/dist/components/tool-call-card/tool-call-group.d.ts +32 -0
- package/dist/context-window.js +1 -1
- package/dist/core/element.d.ts +2 -0
- package/dist/{html-DZWnrdcg.js → html-elD6Bb_u.js} +18 -10
- package/dist/html-elD6Bb_u.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/dist/memory-panel.js +1 -1
- package/dist/model-picker.js +1 -1
- package/dist/tool-call-card.js +1046 -0
- package/dist/tool-call-card.js.map +1 -0
- package/package.json +6 -2
- package/dist/html-DZWnrdcg.js.map +0 -1
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ Agent UI components from the 2lab soma-work dashboard, as **Web Components** wit
|
|
|
9
9
|
| Agent Run (screen) | `<ui-agent-run>` | What the agent is doing now, its plan, and what it needs from you |
|
|
10
10
|
| Agent Inbox | `<ui-agent-inbox>` | Which runs need you, which are running, which are done |
|
|
11
11
|
| AI Answer | `<ui-ai-answer>` | The answer, the links in it, copy, response time |
|
|
12
|
+
| Tool Call Card | `<ui-tool-call-card>`, `<ui-tool-call-group>` | What the agent called, with what, what came back, and how long it took |
|
|
12
13
|
| Agent Queue | `<ui-agent-queue>` | Provider capacity, rate limits, and the scheduled-job lane |
|
|
13
14
|
| Context Window | `<ui-context-window>` | How full the context is and how far auto-compaction is |
|
|
14
15
|
| Memory Panel | `<ui-memory-panel>` | What the agent remembers about you — search, edit, delete with undo |
|
package/dist/agent-inbox.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as define, U as UiElement, p as prefersReducedMotion, e as esc, f as escAttr } from "./html-
|
|
1
|
+
import { d as define, U as UiElement, p as prefersReducedMotion, e as esc, f as escAttr } from "./html-elD6Bb_u.js";
|
|
2
2
|
import { b as fmtDuration, f as fmtAgo, g as fmtUsd, d as fmtInt } from "./format-BBGWXPzk.js";
|
|
3
3
|
const styles = `
|
|
4
4
|
:host {
|
package/dist/agent-queue.js
CHANGED
package/dist/agent-run.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as define, U as UiElement, f as escAttr, e as esc } from "./html-
|
|
1
|
+
import { d as define, U as UiElement, f as escAttr, e as esc } from "./html-elD6Bb_u.js";
|
|
2
2
|
import { b as fmtDuration, a as fmtClock } from "./format-BBGWXPzk.js";
|
|
3
3
|
const styles = `
|
|
4
4
|
:host { --ar-wait-text: color-mix(in srgb, var(--st-wait) 74%, var(--text)); }
|
package/dist/ai-answer.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as define, U as UiElement, e as esc, f as escAttr, s as safeHref, p as prefersReducedMotion } from "./html-
|
|
1
|
+
import { d as define, U as UiElement, e as esc, f as escAttr, s as safeHref, p as prefersReducedMotion } from "./html-elD6Bb_u.js";
|
|
2
2
|
const styles = `
|
|
3
3
|
.ui-root { container: ans / inline-size; }
|
|
4
4
|
.ans-card { position: relative; padding: 12px 14px 10px; border: 1px solid var(--border); border-radius: 12px; background: var(--surface); color: var(--text); box-shadow: var(--ib-shadow); overflow: hidden; }
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { ToolCallData, ToolCallGroupData, ToolCallStatus, ToolIcon } from './logic.js';
|
|
2
|
+
export { formatToolClock, formatToolMs, groupStats, highlightJson, TOOL_ICONS, toCodeText, toolIcon, } from './logic.js';
|
|
3
|
+
export type { ToolCallLang, ToolCallStrings } from './strings.js';
|
|
4
|
+
export { toolCallStrings } from './strings.js';
|
|
5
|
+
export type { ToolCallActionDetail, ToolCallCopyDetail, ToolCallPart, ToolCallToggleDetail } from './tool-call-card.js';
|
|
6
|
+
export { normStatus, UiToolCallCard } from './tool-call-card.js';
|
|
7
|
+
export { callKeys, UiToolCallGroup } from './tool-call-group.js';
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `running` — the call is in flight. `success` / `error` — it returned. `interrupted` — the run ended (stopped turn,
|
|
3
|
+
* crashed process) before this call returned a result: neither running nor failed.
|
|
4
|
+
*/
|
|
5
|
+
export type ToolCallStatus = 'running' | 'success' | 'error' | 'interrupted';
|
|
6
|
+
export type ToolIcon = 'wrench' | 'search' | 'file' | 'edit' | 'terminal' | 'globe' | 'agent' | 'list' | 'plug';
|
|
7
|
+
export interface ToolCallData {
|
|
8
|
+
/** Tool name as the agent calls it, shown in mono — `Read`, `mcp__github__get_issue`. */
|
|
9
|
+
name: string;
|
|
10
|
+
/** One human line — `src/app.ts (lines 1-80)`. */
|
|
11
|
+
summary?: string;
|
|
12
|
+
/** Icon in the tile. Default `toolIcon(name)`. */
|
|
13
|
+
icon?: ToolIcon;
|
|
14
|
+
status: ToolCallStatus;
|
|
15
|
+
/** Object → pretty JSON; a JSON string is parsed; other text is shown as is. */
|
|
16
|
+
args?: unknown;
|
|
17
|
+
result?: unknown;
|
|
18
|
+
/** Shown when status is `error`. */
|
|
19
|
+
error?: string;
|
|
20
|
+
/** Epoch ms the call started — the live timer counts from here while running. */
|
|
21
|
+
startedAt?: number;
|
|
22
|
+
/** Final duration in ms. */
|
|
23
|
+
duration?: number;
|
|
24
|
+
/** Epoch ms clock time the call started, shown muted in the body as HH:MM:SS. */
|
|
25
|
+
at?: number;
|
|
26
|
+
/** Set → controlled; unset → the element keeps its own open state. */
|
|
27
|
+
open?: boolean;
|
|
28
|
+
/** Initial open state while uncontrolled (read on the first render only). */
|
|
29
|
+
defaultOpen?: boolean;
|
|
30
|
+
/** Default true: opens when the call turns to error, closes again on the next run unless toggled by hand. */
|
|
31
|
+
openOnError?: boolean;
|
|
32
|
+
/** Shows Retry next to the error → `ui-retry`. */
|
|
33
|
+
canRetry?: boolean;
|
|
34
|
+
/** Default 220 — taller blocks get a fade and Show all / Show less. */
|
|
35
|
+
maxCodeHeight?: number;
|
|
36
|
+
/** The host is fetching args/result: the body shows a quiet Loading… line. */
|
|
37
|
+
loading?: boolean;
|
|
38
|
+
/** The host's fetch failed: this message plus Try again → `ui-reload`. */
|
|
39
|
+
detailError?: string;
|
|
40
|
+
/** One muted line in the body (e.g. “Showing the first 256 KiB of 1.2 MB”). */
|
|
41
|
+
note?: string;
|
|
42
|
+
/** Default true; false → the header button is out of the tab order (the host runs a roving focus). */
|
|
43
|
+
focusable?: boolean;
|
|
44
|
+
/** Host key for the call, echoed as `detail.id` in every event (and used by the group to keep cards). */
|
|
45
|
+
id?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface ToolCallGroupData {
|
|
48
|
+
calls: ToolCallData[];
|
|
49
|
+
/** Label once every call is done. Default “Used N tools”. */
|
|
50
|
+
label?: string;
|
|
51
|
+
/** Label while any call runs. Default “Using tools…”. */
|
|
52
|
+
runningLabel?: string;
|
|
53
|
+
/** Total ms. Default: the sum of the calls' durations, or the time measured while running. */
|
|
54
|
+
duration?: number;
|
|
55
|
+
/** Set → controlled; unset → the element keeps its own open state. */
|
|
56
|
+
open?: boolean;
|
|
57
|
+
/** Initial open state while uncontrolled (read on the first render only). */
|
|
58
|
+
defaultOpen?: boolean;
|
|
59
|
+
/** Default true; false → the group's and the cards' header buttons are out of the tab order. */
|
|
60
|
+
focusable?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/** 0.4s · 12.3s · 2m 05s · 1h 02m. Live timers always show tenths below a minute; a final value under 1s reads 350ms. */
|
|
63
|
+
export declare function formatToolMs(ms: number, live?: boolean): string;
|
|
64
|
+
/** Clock time HH:MM:SS (24h) in the card's language; empty for a missing or invalid time. */
|
|
65
|
+
export declare function formatToolClock(at: number | undefined, lang?: 'en' | 'ko'): string;
|
|
66
|
+
/**
|
|
67
|
+
* What a code block shows: objects pretty-printed, a string that holds JSON parsed and pretty-printed, any other
|
|
68
|
+
* text as is. `json` says whether the text may be highlighted.
|
|
69
|
+
*/
|
|
70
|
+
export declare function toCodeText(value: unknown): {
|
|
71
|
+
text: string;
|
|
72
|
+
json: boolean;
|
|
73
|
+
};
|
|
74
|
+
/** JSON text → escaped HTML with `tc-k` (key), `tc-s` (string), `tc-n` (number), `tc-l` (literal) spans. */
|
|
75
|
+
export declare function highlightJson(text: string): string;
|
|
76
|
+
/** The tile icon for a tool name: Read/Write → file, Edit → edit, Bash → terminal, Grep/Glob/WebSearch → search,
|
|
77
|
+
* WebFetch → globe, Agent/Task → agent, TodoWrite → list, mcp__* → plug, anything else → wrench. */
|
|
78
|
+
export declare function toolIcon(name: string): ToolIcon;
|
|
79
|
+
/** Line count of a block (for the cap estimate when the layout cannot be measured). */
|
|
80
|
+
export declare function lineCount(text: string): number;
|
|
81
|
+
/** What the group line says about its calls. `interrupted` counts as neither running nor failed. */
|
|
82
|
+
export declare function groupStats(calls: ToolCallData[]): {
|
|
83
|
+
running: boolean;
|
|
84
|
+
failed: number;
|
|
85
|
+
sum: number | undefined;
|
|
86
|
+
};
|
|
87
|
+
export declare const TOOL_ICONS: Record<ToolIcon, string>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/** UI copy. English by default, Korean with `lang="ko"` (the soma-work 작업 로그 wording). */
|
|
2
|
+
declare const en: {
|
|
3
|
+
running: string;
|
|
4
|
+
done: string;
|
|
5
|
+
failed: string;
|
|
6
|
+
noResult: string;
|
|
7
|
+
args: string;
|
|
8
|
+
result: string;
|
|
9
|
+
waiting: string;
|
|
10
|
+
nothing: string;
|
|
11
|
+
failedDefault: string;
|
|
12
|
+
interrupted: string;
|
|
13
|
+
showAll: string;
|
|
14
|
+
showLess: string;
|
|
15
|
+
retry: string;
|
|
16
|
+
reload: string;
|
|
17
|
+
loading: string;
|
|
18
|
+
copy: (part: string) => string;
|
|
19
|
+
copied: string;
|
|
20
|
+
selected: string;
|
|
21
|
+
startedAt: (clock: string) => string;
|
|
22
|
+
sayRunning: (name: string) => string;
|
|
23
|
+
sayDone: (name: string) => string;
|
|
24
|
+
sayFailed: (name: string, error: string) => string;
|
|
25
|
+
sayInterrupted: (name: string) => string;
|
|
26
|
+
used: (n: number) => string;
|
|
27
|
+
using: string;
|
|
28
|
+
nFailed: (n: number) => string;
|
|
29
|
+
groupSay: (label: string, failed: number) => string;
|
|
30
|
+
};
|
|
31
|
+
export type ToolCallStrings = typeof en;
|
|
32
|
+
export declare const STRINGS: {
|
|
33
|
+
en: {
|
|
34
|
+
running: string;
|
|
35
|
+
done: string;
|
|
36
|
+
failed: string;
|
|
37
|
+
noResult: string;
|
|
38
|
+
args: string;
|
|
39
|
+
result: string;
|
|
40
|
+
waiting: string;
|
|
41
|
+
nothing: string;
|
|
42
|
+
failedDefault: string;
|
|
43
|
+
interrupted: string;
|
|
44
|
+
showAll: string;
|
|
45
|
+
showLess: string;
|
|
46
|
+
retry: string;
|
|
47
|
+
reload: string;
|
|
48
|
+
loading: string;
|
|
49
|
+
copy: (part: string) => string;
|
|
50
|
+
copied: string;
|
|
51
|
+
selected: string;
|
|
52
|
+
startedAt: (clock: string) => string;
|
|
53
|
+
sayRunning: (name: string) => string;
|
|
54
|
+
sayDone: (name: string) => string;
|
|
55
|
+
sayFailed: (name: string, error: string) => string;
|
|
56
|
+
sayInterrupted: (name: string) => string;
|
|
57
|
+
used: (n: number) => string;
|
|
58
|
+
using: string;
|
|
59
|
+
nFailed: (n: number) => string;
|
|
60
|
+
groupSay: (label: string, failed: number) => string;
|
|
61
|
+
};
|
|
62
|
+
ko: {
|
|
63
|
+
running: string;
|
|
64
|
+
done: string;
|
|
65
|
+
failed: string;
|
|
66
|
+
noResult: string;
|
|
67
|
+
args: string;
|
|
68
|
+
result: string;
|
|
69
|
+
waiting: string;
|
|
70
|
+
nothing: string;
|
|
71
|
+
failedDefault: string;
|
|
72
|
+
interrupted: string;
|
|
73
|
+
showAll: string;
|
|
74
|
+
showLess: string;
|
|
75
|
+
retry: string;
|
|
76
|
+
reload: string;
|
|
77
|
+
loading: string;
|
|
78
|
+
copy: (part: string) => string;
|
|
79
|
+
copied: string;
|
|
80
|
+
selected: string;
|
|
81
|
+
startedAt: (clock: string) => string;
|
|
82
|
+
sayRunning: (name: string) => string;
|
|
83
|
+
sayDone: (name: string) => string;
|
|
84
|
+
sayFailed: (name: string, error: string) => string;
|
|
85
|
+
sayInterrupted: (name: string) => string;
|
|
86
|
+
used: (n: number) => string;
|
|
87
|
+
using: string;
|
|
88
|
+
nFailed: (n: number) => string;
|
|
89
|
+
groupSay: (label: string, failed: number) => string;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
export type ToolCallLang = keyof typeof STRINGS;
|
|
93
|
+
export declare function toolCallStrings(lang: string | null | undefined): ToolCallStrings;
|
|
94
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Call Card + Group. Sizes and timings follow the affectUI Tool Call Card pattern; every colour is a dashboard
|
|
3
|
+
* token or a color-mix() of tokens, so light and dark both read.
|
|
4
|
+
*/
|
|
5
|
+
export declare const styles = "\n:host { --tc-ink: var(--text); --tc-text: var(--text-secondary); --tc-muted: var(--text-tertiary);\n --tc-bg: var(--surface); --tc-line: var(--border); --tc-tile: var(--surface-raised);\n --tc-hover: color-mix(in srgb, var(--text) 3.5%, var(--surface));\n --tc-code: color-mix(in srgb, var(--surface-raised) 60%, var(--surface));\n --tc-ring: var(--surface);\n --tc-red: var(--st-fail-text); --tc-red-bg: color-mix(in srgb, var(--st-fail) 7%, var(--surface));\n --tc-red-line: color-mix(in srgb, var(--st-fail) 24%, transparent);\n --tc-key: var(--text); --tc-str: color-mix(in srgb, var(--green) 62%, var(--accent)); --tc-num: var(--orange);\n --tc-lit: var(--purple); --tc-shine: var(--text);\n --tc-lift: 0 1px 2px color-mix(in srgb, var(--text) 6%, transparent);\n --tc-ease: var(--ease-out);\n min-width: 0; font-size: 13.5px; line-height: 1.4; letter-spacing: -0.006em; }\n[hidden] { display: none !important; }\nbutton { appearance: none; margin: 0; border: 0; background: none; text-align: left; letter-spacing: inherit; }\n\n/* Card */\n.tc { position: relative; border: 1px solid var(--tc-line); border-radius: 12px; background: var(--tc-bg); box-shadow: var(--tc-lift); }\n.tc-head { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 44px; padding: 8px 10px 8px 9px;\n border-radius: 11px; color: var(--tc-text); transition: background-color 160ms ease; }\n.tc[data-open] > .tc-head { border-radius: 11px 11px 0 0; }\n.tc-icon { display: grid; place-items: center; flex: none; width: 26px; height: 26px; border-radius: 7px;\n background: var(--tc-tile); box-shadow: inset 0 0 0 1px var(--tc-line); color: var(--tc-ink); }\n.tc-icon > svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }\n.tc-main { display: flex; align-items: baseline; gap: 8px; flex: 1; min-width: 0; }\n.tc-name { flex: 0 1 auto; max-width: 55%; overflow: hidden; color: var(--tc-ink); font-family: var(--mono); font-size: 12.5px;\n font-weight: 500; letter-spacing: 0; text-overflow: ellipsis; white-space: nowrap; }\n.tc-summary { flex: 1 1 0; min-width: 0; overflow: hidden; color: var(--tc-text); text-overflow: ellipsis; white-space: nowrap; }\n.tc-status { display: inline-flex; align-items: center; gap: 6px; flex: none; color: var(--tc-muted); font-size: 12.5px;\n font-variant-numeric: tabular-nums; white-space: nowrap; }\n.tc-status.is-in { animation: tc-in 360ms var(--tc-ease) both; }\n.tc[data-status=\"error\"] .tc-status { color: var(--tc-red); }\n.tc-status > svg { width: 14px; height: 14px; flex: none; fill: none; stroke-linecap: round; stroke-linejoin: round; }\n.tc-spin { animation: tc-spin 800ms linear infinite; }\n.tc-spin circle { stroke: currentColor; stroke-width: 1.6; opacity: 0.25; }\n.tc-spin path { stroke: var(--st-run); stroke-width: 1.6; }\n.tc-ok { stroke: var(--st-done); stroke-width: 1.8; }\n.is-in .tc-ok path { stroke-dasharray: 1; stroke-dashoffset: 1; animation: tc-draw 360ms var(--tc-ease) 80ms forwards; }\n.tc-err { stroke: var(--st-fail); stroke-width: 1.5; }\n.tc-stop { stroke: currentColor; stroke-width: 1.5; }\n.tc-chev { flex: none; width: 14px; height: 14px; fill: none; stroke: var(--tc-muted); stroke-width: 1.5; stroke-linecap: round;\n stroke-linejoin: round; transition: transform 360ms var(--tc-ease); }\n.tc[data-open] > .tc-head .tc-chev, .tcg[data-open] > .tcg-head .tc-chev { transform: rotate(180deg); }\n@media (hover: hover) {\n .tc-head:hover { background: var(--tc-hover); }\n .tc-head:hover .tc-chev { stroke: var(--tc-ink); }\n .tcg-head:hover { background: var(--tc-hover); color: var(--tc-ink); }\n .tc-copy:hover { background: var(--tc-hover); color: var(--tc-ink); }\n .tc-more:hover { color: var(--tc-ink); }\n .tc-btn:hover { background: var(--tc-hover); }\n}\n\n/* Body: 0fr \u2192 1fr, so the height animates without measuring */\n.tc-body { display: grid; grid-template-rows: 0fr; opacity: 0;\n transition: grid-template-rows 380ms var(--tc-ease), opacity 240ms ease; }\n.tc-body[data-open] { grid-template-rows: 1fr; opacity: 1; }\n.tc-clip { min-height: 0; overflow: hidden; }\n.tc-sections { display: grid; gap: 12px; padding: 12px; border-top: 1px solid var(--tc-line); }\n.tc-top { display: flex; justify-content: flex-end; margin: -2px 0 -6px; }\n.tc-line { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }\n.tc-line > p { min-width: 0; }\n.tc-head-end { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }\n.tc-at { flex: none; color: var(--tc-muted); font-size: 11.5px; line-height: 16px; font-variant-numeric: tabular-nums; }\n.tc-section { display: grid; gap: 6px; min-width: 0; }\n.tc-section-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 24px; }\n.tc-label { color: var(--tc-muted); font-size: 12px; font-weight: 500; }\n.tc-pending, .tc-note { margin: 0; color: var(--tc-muted); font-size: 12.5px; }\n.tc-note { font-size: 12px; }\n\n.tc-copy { position: relative; display: grid; place-items: center; flex: none; width: 24px; height: 24px; padding: 0;\n border-radius: 6px; color: var(--tc-muted); transition: background-color 160ms ease, color 160ms ease; }\n.tc-copy svg { position: absolute; width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.4;\n stroke-linecap: round; stroke-linejoin: round;\n transition: opacity 200ms ease, transform 320ms var(--tc-ease), filter 200ms ease; }\n.tc-copy-done { opacity: 0; transform: scale(0.6); filter: blur(2px); stroke-width: 1.7; }\n.tc-copy[data-copied] { color: var(--st-done); }\n.tc-copy[data-copied] .tc-copy-icon { opacity: 0; transform: scale(0.6); filter: blur(2px); }\n.tc-copy[data-copied] .tc-copy-done { opacity: 1; transform: none; filter: none; }\n\n/* Code wraps instead of scrolling sideways; a capped block fades out at the bottom */\n.tc-code { position: relative; margin: 0; padding: 10px 12px; overflow: hidden; border-radius: 8px; background: var(--tc-code);\n box-shadow: inset 0 0 0 1px var(--tc-line); color: var(--tc-text); font-family: var(--mono); font-size: 12px;\n line-height: 1.6; letter-spacing: 0; white-space: pre-wrap; overflow-wrap: anywhere; tab-size: 2;\n transition: max-height 420ms var(--tc-ease); }\n.tc-code[data-json] { color: var(--tc-muted); }\n.tc-code code { display: block; font: inherit; }\n.tc-code::after { content: \"\"; position: absolute; left: 1px; right: 1px; bottom: 1px; height: 56px; border-radius: 0 0 7px 7px;\n background: linear-gradient(to bottom, color-mix(in srgb, var(--tc-code) 0%, transparent), var(--tc-code));\n opacity: 0; transition: opacity 240ms ease; pointer-events: none; }\n.tc-code[data-capped]::after { opacity: 1; }\n.tc-k { color: var(--tc-key); }\n.tc-s { color: var(--tc-str); }\n.tc-n { color: var(--tc-num); }\n.tc-l { color: var(--tc-lit); }\n.tc-more { position: relative; justify-self: start; padding: 2px 4px; margin-left: -4px; border-radius: 5px; color: var(--tc-text);\n font-size: 12.5px; font-weight: 500; transition: color 160ms ease; }\n\n/* Error: the message and an optional Retry; a failed host fetch: the message and Try again */\n.tc-error { display: flex; align-items: flex-start; gap: 8px; padding: 9px 10px 9px 11px; border-radius: 8px;\n background: var(--tc-red-bg); box-shadow: inset 0 0 0 1px var(--tc-red-line); }\n.tc-error > svg { flex: none; width: 14px; height: 14px; margin-top: 2px; fill: none; stroke-linecap: round; }\n.tc-error-text { flex: 1; min-width: 0; margin: 0; color: var(--tc-red); font-size: 13px; line-height: 1.45;\n white-space: pre-wrap; overflow-wrap: anywhere; }\n.tc-reload-row { display: flex; align-items: center; gap: 8px; }\n.tc-reload-row > .tc-pending { flex: 1; min-width: 0; overflow-wrap: anywhere; }\n.tc-btn { position: relative; display: inline-flex; align-items: center; gap: 5px; flex: none; height: 26px; margin: -3px 0;\n padding: 0 10px 0 8px; border-radius: 7px; background: var(--tc-bg); box-shadow: inset 0 0 0 1px var(--tc-line), var(--tc-lift);\n color: var(--tc-ink); font-size: 12.5px; font-weight: 500; white-space: nowrap; transition: background-color 160ms ease; }\n.tc-btn svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round;\n stroke-linejoin: round; transition: transform 200ms var(--tc-ease); }\n.tc-btn:active svg { transform: rotate(-60deg); }\n\n/* Group: one quiet line with the tools' icons stacked, the cards below */\n.tcg { display: grid; }\n.tcg-head { display: flex; align-items: center; gap: 9px; justify-self: start; max-width: 100%; min-height: 36px;\n padding: 4px 10px 4px 5px; border-radius: 10px; color: var(--tc-text);\n transition: background-color 160ms ease, color 160ms ease; }\n.tcg-stack { display: flex; flex: none; }\n.tcg-stack .tc-icon { width: 24px; height: 24px; box-shadow: inset 0 0 0 1px var(--tc-line), 0 0 0 2px var(--tc-ring); }\n.tcg-stack .tc-icon.is-in { animation: tc-pop 420ms var(--tc-ease) both; }\n.tcg-stack .tc-icon + .tc-icon { margin-left: -5px; }\n.tcg-stack .tc-icon > svg { width: 13px; height: 13px; }\n.tcg-title { display: flex; align-items: baseline; gap: 5px; min-width: 0; white-space: nowrap; }\n.tcg-title.is-in { animation: tc-in 360ms var(--tc-ease) both; }\n.tcg-label { position: relative; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: inherit; font-weight: 500; }\n.tcg-failed { flex: none; color: var(--tc-red); }\n.tcg-time { flex: none; color: var(--tc-muted); font-variant-numeric: tabular-nums; }\n.tcg-list { display: grid; gap: 8px; padding-top: 8px; }\n\n/* A band of the text colour sweeping over \u201CUsing tools\u2026\u201D */\n.tc-shine::after { content: attr(data-text); content: attr(data-text) / \"\"; position: absolute; inset: 0; white-space: nowrap;\n color: transparent; background: linear-gradient(90deg, transparent 38%, var(--tc-shine) 50%, transparent 62%) 100% 0 / 300% 100% no-repeat;\n -webkit-background-clip: text; background-clip: text; animation: tc-sweep 1.8s linear infinite; pointer-events: none; }\n\n@keyframes tc-in { from { opacity: 0; transform: translateY(3px); filter: blur(2px); } to { opacity: 1; transform: none; filter: none; } }\n@keyframes tc-pop { from { opacity: 0; transform: scale(0.6); } to { opacity: 1; transform: none; } }\n@keyframes tc-spin { to { transform: rotate(360deg); } }\n@keyframes tc-draw { to { stroke-dashoffset: 0; } }\n@keyframes tc-sweep { from { background-position: 100% 0; } to { background-position: 0% 0; } }\n\n/* Touch: every control gets a 44px target without changing the layout */\n@media (pointer: coarse) {\n .tcg-head { min-height: 44px; }\n .tc-copy::before, .tc-more::before, .tc-btn::before { content: \"\"; position: absolute; inset: -10px; }\n .tc-more::before { inset: -12px -8px; }\n .tc-btn::before { inset: -9px -4px; }\n}\n@media (prefers-reduced-motion: reduce) {\n .tc-shine::after { display: none; }\n .tc-spin { animation: none; }\n .is-in .tc-ok path { animation: none; stroke-dashoffset: 0; }\n}\n";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { UiElement } from '../../core/element.js';
|
|
2
|
+
import { type ToolCallData, type ToolCallStatus } from './logic.js';
|
|
3
|
+
/** Which code block an event is about. */
|
|
4
|
+
export type ToolCallPart = 'args' | 'result';
|
|
5
|
+
export interface ToolCallToggleDetail {
|
|
6
|
+
open: boolean;
|
|
7
|
+
/** `data.id` when set. */
|
|
8
|
+
id?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ToolCallCopyDetail {
|
|
11
|
+
part: ToolCallPart;
|
|
12
|
+
text: string;
|
|
13
|
+
id?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ToolCallActionDetail {
|
|
16
|
+
id?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const SPIN_SVG = "<svg class=\"tc-spin\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><circle cx=\"8\" cy=\"8\" r=\"5.8\"/><path d=\"M8 2.2a5.8 5.8 0 0 1 5.8 5.8\"/></svg>";
|
|
19
|
+
export declare const CHEV_SVG = "<svg class=\"tc-chev\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><path d=\"m4.4 6.2 3.6 3.6 3.6-3.6\"/></svg>";
|
|
20
|
+
/** A status the card knows; anything else reads as `interrupted` (neutral, no timer). */
|
|
21
|
+
export declare function normStatus(s: unknown): ToolCallStatus;
|
|
22
|
+
/** The tile glyph for a call: its `icon` when it names one, else `toolIcon(name)`. */
|
|
23
|
+
export declare function callIconSvg(d: Pick<ToolCallData, 'name' | 'icon'>): string;
|
|
24
|
+
/**
|
|
25
|
+
* `<ui-tool-call-card>` — one tool call of an agent: icon, name, summary and status (spinner with a live timer, a
|
|
26
|
+
* drawn check with the duration, Failed, or No result) on one line; open it for the arguments and the result as
|
|
27
|
+
* highlighted JSON with copy buttons, long blocks capped with Show all, errors with Retry.
|
|
28
|
+
*/
|
|
29
|
+
export declare class UiToolCallCard extends UiElement<ToolCallData> {
|
|
30
|
+
#private;
|
|
31
|
+
static styles: string[];
|
|
32
|
+
static get observedAttributes(): string[];
|
|
33
|
+
constructor();
|
|
34
|
+
attributeChangedCallback(): void;
|
|
35
|
+
disconnectedCallback(): void;
|
|
36
|
+
/** Focus the header button (the card's one tab stop). */
|
|
37
|
+
/** Retry, Try again, a Show all that went away, an auto-closed body: focus stays on the card's header. */
|
|
38
|
+
protected focusFallback(): HTMLElement | null;
|
|
39
|
+
focus(options?: FocusOptions): void;
|
|
40
|
+
/** Whether the body is open now (controlled `data.open`, else the element's own state). */
|
|
41
|
+
get isOpen(): boolean;
|
|
42
|
+
protected render(): string;
|
|
43
|
+
protected updated(): void;
|
|
44
|
+
}
|
|
45
|
+
declare global {
|
|
46
|
+
interface HTMLElementTagNameMap {
|
|
47
|
+
'ui-tool-call-card': UiToolCallCard;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { UiElement } from '../../core/element.js';
|
|
2
|
+
import { type ToolCallData, type ToolCallGroupData } from './logic.js';
|
|
3
|
+
import { type UiToolCallCard } from './tool-call-card.js';
|
|
4
|
+
/** Stable keys for a group's calls: `id:<id>` when the call has an id, else `i:<index>` (duplicates get a suffix). */
|
|
5
|
+
export declare function callKeys(calls: ToolCallData[]): string[];
|
|
6
|
+
/**
|
|
7
|
+
* `<ui-tool-call-group>` — several tool calls folded into one quiet line: the last three tools' icons stacked,
|
|
8
|
+
* “Used 3 tools · 1 failed · 2.4s” (or “Using tools…” with a light sweep while any call runs). Open it for one
|
|
9
|
+
* `<ui-tool-call-card>` per call. The cards live in a list outside the re-rendered line and are reconciled by key,
|
|
10
|
+
* so a group update never re-creates them (open state, timers and copy checks survive).
|
|
11
|
+
*/
|
|
12
|
+
export declare class UiToolCallGroup extends UiElement<ToolCallGroupData> {
|
|
13
|
+
#private;
|
|
14
|
+
static styles: string[];
|
|
15
|
+
static get observedAttributes(): string[];
|
|
16
|
+
constructor();
|
|
17
|
+
attributeChangedCallback(): void;
|
|
18
|
+
disconnectedCallback(): void;
|
|
19
|
+
/** Focus the group's header button. */
|
|
20
|
+
focus(options?: FocusOptions): void;
|
|
21
|
+
/** Whether the list is open now (controlled `data.open`, else the element's own state). */
|
|
22
|
+
get isOpen(): boolean;
|
|
23
|
+
/** The card elements, in call order. */
|
|
24
|
+
get cards(): UiToolCallCard[];
|
|
25
|
+
protected render(): string;
|
|
26
|
+
protected updated(): void;
|
|
27
|
+
}
|
|
28
|
+
declare global {
|
|
29
|
+
interface HTMLElementTagNameMap {
|
|
30
|
+
'ui-tool-call-group': UiToolCallGroup;
|
|
31
|
+
}
|
|
32
|
+
}
|
package/dist/context-window.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as define, U as UiElement, f as escAttr, e as esc, p as prefersReducedMotion } from "./html-
|
|
1
|
+
import { d as define, U as UiElement, f as escAttr, e as esc, p as prefersReducedMotion } from "./html-elD6Bb_u.js";
|
|
2
2
|
import { e as fmtTokens } from "./format-BBGWXPzk.js";
|
|
3
3
|
const styles = `
|
|
4
4
|
:host { --cw-c1: var(--accent); --cw-c2: color-mix(in srgb, var(--accent) 42%, var(--ib-pill)); --cw-c3: var(--purple); --cw-c4: var(--green);
|
package/dist/core/element.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export declare abstract class UiElement<D = unknown> extends HTMLElement {
|
|
|
23
23
|
/** Render synchronously (tests, or right before measuring). Cancels a queued render. */
|
|
24
24
|
renderNow(): void;
|
|
25
25
|
protected update(): void;
|
|
26
|
+
/** Where focus goes when the focused element is gone after a render (its key no longer rendered). Default: nowhere. */
|
|
27
|
+
protected focusFallback(): HTMLElement | null;
|
|
26
28
|
/** The component's markup. */
|
|
27
29
|
protected abstract render(): string;
|
|
28
30
|
/** Hook after each render (wire listeners on fresh nodes, start timers). */
|
|
@@ -66,6 +66,11 @@ class UiElement extends HTMLElement {
|
|
|
66
66
|
this.requestRender();
|
|
67
67
|
}
|
|
68
68
|
connectedCallback() {
|
|
69
|
+
if (Object.hasOwn(this, "data")) {
|
|
70
|
+
const early = this.data;
|
|
71
|
+
delete this.data;
|
|
72
|
+
this.data = early;
|
|
73
|
+
}
|
|
69
74
|
this.requestRender();
|
|
70
75
|
}
|
|
71
76
|
disconnectedCallback() {
|
|
@@ -88,20 +93,23 @@ class UiElement extends HTMLElement {
|
|
|
88
93
|
this.update();
|
|
89
94
|
}
|
|
90
95
|
update() {
|
|
91
|
-
const
|
|
96
|
+
const focus = this.#focusState();
|
|
92
97
|
this.content.innerHTML = this.render();
|
|
93
|
-
if (key) {
|
|
94
|
-
const next = Array.from(this.content.querySelectorAll("[data-key]")).find(
|
|
95
|
-
(el) => el.dataset.key === key
|
|
96
|
-
);
|
|
97
|
-
next?.focus({ preventScroll: true });
|
|
98
|
-
}
|
|
99
98
|
this.updated();
|
|
99
|
+
if (!focus) return;
|
|
100
|
+
const next = focus.key === void 0 ? void 0 : Array.from(this.content.querySelectorAll("[data-key]")).find(
|
|
101
|
+
(el) => el.dataset.key === focus.key
|
|
102
|
+
);
|
|
103
|
+
(next ?? this.focusFallback())?.focus({ preventScroll: true });
|
|
104
|
+
}
|
|
105
|
+
/** Where focus goes when the focused element is gone after a render (its key no longer rendered). Default: nowhere. */
|
|
106
|
+
focusFallback() {
|
|
107
|
+
return null;
|
|
100
108
|
}
|
|
101
|
-
#
|
|
109
|
+
#focusState() {
|
|
102
110
|
try {
|
|
103
111
|
const active = this.root.activeElement;
|
|
104
|
-
return active && this.content.contains(active) ? active.dataset?.key : void 0;
|
|
112
|
+
return active && this.content.contains(active) ? { key: active.dataset?.key } : void 0;
|
|
105
113
|
} catch {
|
|
106
114
|
return void 0;
|
|
107
115
|
}
|
|
@@ -164,4 +172,4 @@ export {
|
|
|
164
172
|
safeHref as s,
|
|
165
173
|
tokensCss as t
|
|
166
174
|
};
|
|
167
|
-
//# sourceMappingURL=html-
|
|
175
|
+
//# sourceMappingURL=html-elD6Bb_u.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-elD6Bb_u.js","sources":["../src/core/tokens.ts","../src/core/element.ts","../src/core/html.ts"],"sourcesContent":["import tokens from './tokens.json';\n\n/**\n * Design tokens. Inside every component's shadow root the dashboard names (`--text`, `--surface`, `--st-run` …)\n * are defined on `:host` and read the public `--ui-*` property first, so a page themes every component by\n * setting `--ui-text` etc. (or loading `@2lab.ai/ui/tokens.css`). Without any page tokens a component follows\n * `prefers-color-scheme`, and the `theme=\"light|dark\"` attribute pins it.\n */\nexport type TokenSet = Record<string, string>;\nexport const LIGHT: TokenSet = tokens.light;\nexport const DARK: TokenSet = tokens.dark;\nexport const SHARED: TokenSet = tokens.shared;\n\nfunction hostVars(set: TokenSet): string {\n return Object.entries(set)\n .map(([k, v]) => `--${k}: var(--ui-${k}, ${v});`)\n .join(' ');\n}\n\nfunction pageVars(set: TokenSet): string {\n return Object.entries(set)\n .map(([k, v]) => `--ui-${k}: ${v};`)\n .join(' ');\n}\n\n/** Shared stylesheet prepended to every component's shadow root. */\nexport const baseCss = `\n:host { ${hostVars(SHARED)} ${hostVars(LIGHT)}\n display: block; box-sizing: border-box; color: var(--text); font-family: var(--font);\n font-size: 14px; line-height: 1.45; -webkit-font-smoothing: antialiased; color-scheme: light; }\n:host([theme=\"dark\"]) { ${hostVars(DARK)} color-scheme: dark; }\n@media (prefers-color-scheme: dark) { :host(:not([theme=\"light\"])) { ${hostVars(DARK)} color-scheme: dark; } }\n:host([hidden]) { display: none; }\n*, *::before, *::after { box-sizing: border-box; }\nbutton, input, textarea, select { font: inherit; color: inherit; }\nbutton { cursor: pointer; }\n:focus { outline: none; }\n:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 2px; }\n.sr-only { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;\n clip: rect(0 0 0 0); white-space: nowrap; border: 0; }\n.mono { font-family: var(--mono); }\n@media (prefers-reduced-motion: reduce) {\n *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important; scroll-behavior: auto !important; }\n}\n`;\n\n/** Optional page-level tokens (`@2lab.ai/ui/tokens.css`): `data-theme=\"dark|light\"` on any ancestor switches. */\nexport const tokensCss = `/* @2lab.ai/ui design tokens */\n:root, [data-theme=\"light\"] { ${pageVars(SHARED)} ${pageVars(LIGHT)} color-scheme: light; }\n[data-theme=\"dark\"] { ${pageVars(DARK)} color-scheme: dark; }\n@media (prefers-color-scheme: dark) { :root:not([data-theme=\"light\"]) { ${pageVars(DARK)} color-scheme: dark; } }\n`;\n","import { baseCss } from './tokens';\n\n/**\n * Base class for every @2lab.ai/ui component.\n *\n * - Open shadow root with `baseCss` + the subclass's `static styles`.\n * - Data in, events out: set `el.data = {...}` (or the component's own properties) → one batched render;\n * user intent leaves as a bubbling, composed `CustomEvent` (`ui-*`) that the host app handles.\n * - `render()` returns an HTML string; every dynamic value must go through `esc` / `escAttr` / `safeHref`.\n * - Focus survives a re-render when the focused element carries `data-key` (restored to the same key).\n * - Subclasses that tick (timers) should update text nodes in place instead of re-rendering.\n */\nexport abstract class UiElement<D = unknown> extends HTMLElement {\n static styles: string[] = [];\n\n protected readonly root: ShadowRoot;\n protected readonly content: HTMLElement;\n #data: D | undefined;\n #queued = false;\n #gen = 0;\n\n constructor() {\n super();\n this.root = this.attachShadow({ mode: 'open' });\n const ctor = this.constructor as typeof UiElement;\n const style = document.createElement('style');\n style.textContent = [baseCss, ...ctor.styles].join('\\n');\n this.content = document.createElement('div');\n this.content.setAttribute('part', 'root');\n this.content.className = 'ui-root';\n this.root.append(style, this.content);\n }\n\n get data(): D | undefined {\n return this.#data;\n }\n\n set data(value: D | undefined) {\n this.#data = value;\n this.requestRender();\n }\n\n connectedCallback(): void {\n // `data` set before this element was defined (its module loaded after the host's script ran) is an own\n // property that shadows the accessor: move it through the setter. Here, not in the constructor — a subclass\n // setter may use private fields that only exist once construction is done.\n if (Object.hasOwn(this, 'data')) {\n const early = (this as { data?: D }).data;\n delete (this as { data?: D }).data;\n this.data = early;\n }\n this.requestRender();\n }\n\n disconnectedCallback(): void {}\n\n /** Batch renders into one microtask. */\n requestRender(): void {\n if (this.#queued) return;\n this.#queued = true;\n const gen = this.#gen;\n queueMicrotask(() => {\n if (!this.#queued || gen !== this.#gen) return;\n this.#queued = false;\n if (this.isConnected) this.update();\n });\n }\n\n /** Render synchronously (tests, or right before measuring). Cancels a queued render. */\n renderNow(): void {\n this.#queued = false;\n this.#gen++;\n this.update();\n }\n\n protected update(): void {\n const focus = this.#focusState();\n this.content.innerHTML = this.render();\n // After updated(): a subclass may unhide or move what was focused there (a display:none element takes no focus).\n this.updated();\n if (!focus) return;\n // Compare dataset values instead of building a selector: keys may hold any characters.\n const next =\n focus.key === undefined\n ? undefined\n : Array.from(this.content.querySelectorAll<HTMLElement>('[data-key]')).find(\n (el) => el.dataset.key === focus.key,\n );\n (next ?? this.focusFallback())?.focus({ preventScroll: true });\n }\n\n /** Where focus goes when the focused element is gone after a render (its key no longer rendered). Default: nowhere. */\n protected focusFallback(): HTMLElement | null {\n return null;\n }\n\n #focusState(): { key: string | undefined } | undefined {\n try {\n const active = this.root.activeElement as HTMLElement | null;\n return active && this.content.contains(active) ? { key: active.dataset?.key } : undefined;\n } catch {\n return undefined;\n }\n }\n\n /** The component's markup. */\n protected abstract render(): string;\n\n /** Hook after each render (wire listeners on fresh nodes, start timers). */\n protected updated(): void {}\n\n /** Dispatch a bubbling, composed, cancelable event. Returns false when a listener called preventDefault(). */\n protected emit<T>(name: string, detail: T): boolean {\n return this.dispatchEvent(new CustomEvent<T>(name, { detail, bubbles: true, composed: true, cancelable: true }));\n }\n\n /** Query inside the shadow root. */\n protected $<E extends Element = HTMLElement>(selector: string): E | null {\n return this.root.querySelector<E>(selector);\n }\n\n protected $$<E extends Element = HTMLElement>(selector: string): E[] {\n return Array.from(this.root.querySelectorAll<E>(selector));\n }\n}\n\n/** Register a custom element once (safe to import twice). */\nexport function define(tag: string, ctor: CustomElementConstructor): void {\n if (typeof customElements !== 'undefined' && !customElements.get(tag)) customElements.define(tag, ctor);\n}\n\n/** True when the user asked for less motion. */\nexport function prefersReducedMotion(): boolean {\n return typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n","/** HTML-escape text for element content. Every model-, user- or tool-written string goes through this. */\nexport function esc(value: unknown): string {\n return String(value ?? '')\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n\n/** Escape for a double-quoted attribute value. */\nexport function escAttr(value: unknown): string {\n return esc(value).replace(/\"/g, '"').replace(/'/g, ''');\n}\n\nconst SAFE_SCHEMES = /^(https?:|mailto:)/i;\n\n/** A link target that cannot run script: http(s)/mailto only, otherwise `#`. */\nexport function safeHref(url: unknown): string {\n const s = String(url ?? '').trim();\n return SAFE_SCHEMES.test(s) ? escAttr(s) : '#';\n}\n\n/** Join class names, skipping falsy entries. */\nexport function cls(...names: Array<string | false | null | undefined>): string {\n return names.filter(Boolean).join(' ');\n}\n\n/** `key=\"value\"` pairs for truthy values, escaped. `true` renders a bare boolean attribute. */\nexport function attrs(map: Record<string, string | number | boolean | null | undefined>): string {\n let out = '';\n for (const [k, v] of Object.entries(map)) {\n if (v === false || v === null || v === undefined) continue;\n out += v === true ? ` ${k}` : ` ${k}=\"${escAttr(v)}\"`;\n }\n return out;\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './components/ai-answer/index.js';
|
|
|
9
9
|
export * from './components/context-window/index.js';
|
|
10
10
|
export * from './components/memory-panel/index.js';
|
|
11
11
|
export * from './components/model-picker/index.js';
|
|
12
|
+
export * from './components/tool-call-card/index.js';
|
|
12
13
|
export { define, prefersReducedMotion, UiElement } from './core/element.js';
|
|
13
14
|
export { clamp, fmtAgo, fmtClock, fmtDuration, fmtInt, fmtTokens, fmtUsd } from './core/format.js';
|
|
14
15
|
export { attrs, cls, esc, escAttr, safeHref } from './core/html.js';
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,8 @@ import { UiAiAnswer, answerCopyText, answerLinkInfo, answerLinkKey, answerLinkif
|
|
|
5
5
|
import { CELLS, UiContextWindow, cellMap, contextLevel, contextParts, markIndex } from "./context-window.js";
|
|
6
6
|
import { FOLD_MS, UNDO_MS, UiMemoryPanel, entryKeys, entryMatches, highlight, isSameEdit, shortText, storeUsed, usageAfterAdd, usageLevel } from "./memory-panel.js";
|
|
7
7
|
import { MODEL_EFFORT_LEVELS, UiModelPicker, anchorMoved, anchorSpot, fmtModelPrice, fmtModelTokens, meterSegments, modelEffortLabel, modelEffortLevels, modelGlyph, modelMeters, placeModelMenu, validModelPrice } from "./model-picker.js";
|
|
8
|
-
import {
|
|
8
|
+
import { TOOL_ICONS, UiToolCallCard, UiToolCallGroup, callKeys, formatToolClock, formatToolMs, groupStats, highlightJson, normStatus, toCodeText, toolCallStrings, toolIcon } from "./tool-call-card.js";
|
|
9
|
+
import { D, L, S, U, a, b, c, d, e, f, p, s, t } from "./html-elD6Bb_u.js";
|
|
9
10
|
import { c as c2, f as f2, a as a2, b as b2, d as d2, e as e2, g } from "./format-BBGWXPzk.js";
|
|
10
11
|
export {
|
|
11
12
|
ANNOUNCE_MS,
|
|
@@ -17,6 +18,7 @@ export {
|
|
|
17
18
|
LOW_PCT,
|
|
18
19
|
MODEL_EFFORT_LEVELS,
|
|
19
20
|
S as SHARED,
|
|
21
|
+
TOOL_ICONS,
|
|
20
22
|
UNDO_MS,
|
|
21
23
|
UiAgentInbox,
|
|
22
24
|
UiAgentQueue,
|
|
@@ -26,6 +28,8 @@ export {
|
|
|
26
28
|
U as UiElement,
|
|
27
29
|
UiMemoryPanel,
|
|
28
30
|
UiModelPicker,
|
|
31
|
+
UiToolCallCard,
|
|
32
|
+
UiToolCallGroup,
|
|
29
33
|
accountState,
|
|
30
34
|
advanceProvider,
|
|
31
35
|
agentDots,
|
|
@@ -42,6 +46,7 @@ export {
|
|
|
42
46
|
axisPos,
|
|
43
47
|
b as baseCss,
|
|
44
48
|
boardCounts,
|
|
49
|
+
callKeys,
|
|
45
50
|
capacityNews,
|
|
46
51
|
cellMap,
|
|
47
52
|
c2 as clamp,
|
|
@@ -67,7 +72,11 @@ export {
|
|
|
67
72
|
fmtPct,
|
|
68
73
|
e2 as fmtTokens,
|
|
69
74
|
g as fmtUsd,
|
|
75
|
+
formatToolClock,
|
|
76
|
+
formatToolMs,
|
|
77
|
+
groupStats,
|
|
70
78
|
highlight,
|
|
79
|
+
highlightJson,
|
|
71
80
|
holdLanes,
|
|
72
81
|
isSameEdit,
|
|
73
82
|
laneNews,
|
|
@@ -79,6 +88,7 @@ export {
|
|
|
79
88
|
modelMeters,
|
|
80
89
|
nextRefill,
|
|
81
90
|
niceMax,
|
|
91
|
+
normStatus,
|
|
82
92
|
normalize,
|
|
83
93
|
orderJobs,
|
|
84
94
|
placeHolds,
|
|
@@ -106,8 +116,11 @@ export {
|
|
|
106
116
|
storeUsed,
|
|
107
117
|
timeText,
|
|
108
118
|
timelineMarks,
|
|
119
|
+
toCodeText,
|
|
109
120
|
toMs,
|
|
110
121
|
t as tokensCss,
|
|
122
|
+
toolCallStrings,
|
|
123
|
+
toolIcon,
|
|
111
124
|
upNext,
|
|
112
125
|
usageAfterAdd,
|
|
113
126
|
usageLevel,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
|
package/dist/memory-panel.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as define, U as UiElement, e as esc, f as escAttr, p as prefersReducedMotion } from "./html-
|
|
1
|
+
import { d as define, U as UiElement, e as esc, f as escAttr, p as prefersReducedMotion } from "./html-elD6Bb_u.js";
|
|
2
2
|
import { d as fmtInt } from "./format-BBGWXPzk.js";
|
|
3
3
|
const styles = `
|
|
4
4
|
:host { --mm-fold: 320ms; --mm-warn: var(--yellow); --mm-danger-bg: color-mix(in srgb, var(--red) 11%, transparent);
|
package/dist/model-picker.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as define, U as UiElement, f as escAttr, e as esc, p as prefersReducedMotion } from "./html-
|
|
1
|
+
import { d as define, U as UiElement, f as escAttr, e as esc, p as prefersReducedMotion } from "./html-elD6Bb_u.js";
|
|
2
2
|
function morphInto(el, html) {
|
|
3
3
|
const tpl = document.createElement("template");
|
|
4
4
|
tpl.innerHTML = html;
|