@icen.ai/ui 0.8.0 → 0.9.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/AGENTS.md +63 -14
- package/README.md +17 -9
- package/dist/base.css +4 -3
- package/dist/behaviors/accordion.d.mts +5 -2
- package/dist/behaviors/accordion.mjs +36 -11
- package/dist/behaviors/ai-branch.d.mts +19 -0
- package/dist/behaviors/ai-branch.mjs +217 -0
- package/dist/behaviors/ai-chat.d.mts +11 -7
- package/dist/behaviors/ai-chat.mjs +134 -51
- package/dist/behaviors/ai-composer.d.mts +28 -3
- package/dist/behaviors/ai-composer.mjs +399 -229
- package/dist/behaviors/ai-core.d.mts +9 -4
- package/dist/behaviors/ai-core.mjs +21 -8
- package/dist/behaviors/ai-diff.d.mts +2 -2
- package/dist/behaviors/ai-diff.mjs +172 -41
- package/dist/behaviors/ai-feedback.d.mts +26 -0
- package/dist/behaviors/ai-feedback.mjs +303 -0
- package/dist/behaviors/ai-panel.d.mts +26 -9
- package/dist/behaviors/ai-panel.mjs +211 -110
- package/dist/behaviors/ai-provider.mjs +54 -48
- package/dist/behaviors/ai-threads.d.mts +38 -0
- package/dist/behaviors/ai-threads.mjs +319 -0
- package/dist/behaviors/ai-tool.d.mts +12 -4
- package/dist/behaviors/ai-tool.mjs +316 -263
- package/dist/behaviors/ai-tools.d.mts +9 -6
- package/dist/behaviors/ai-tools.mjs +264 -155
- package/dist/behaviors/back-top.mjs +16 -1
- package/dist/behaviors/carousel.d.mts +5 -2
- package/dist/behaviors/carousel.mjs +53 -26
- package/dist/behaviors/charts.d.mts +170 -22
- package/dist/behaviors/charts.mjs +1016 -150
- package/dist/behaviors/command-palette.d.mts +40 -6
- package/dist/behaviors/command-palette.mjs +143 -15
- package/dist/behaviors/context-menu.d.mts +21 -4
- package/dist/behaviors/context-menu.mjs +122 -38
- package/dist/behaviors/controls.d.mts +59 -0
- package/dist/behaviors/controls.mjs +601 -0
- package/dist/behaviors/copy.d.mts +5 -2
- package/dist/behaviors/copy.mjs +37 -12
- package/dist/behaviors/datatable.d.mts +12 -0
- package/dist/behaviors/datatable.mjs +226 -43
- package/dist/behaviors/date-picker.d.mts +2 -2
- package/dist/behaviors/date-picker.mjs +171 -32
- package/dist/behaviors/dropdown.d.mts +6 -2
- package/dist/behaviors/dropdown.mjs +164 -25
- package/dist/behaviors/events.d.mts +523 -0
- package/dist/behaviors/events.mjs +208 -0
- package/dist/behaviors/input.mjs +25 -12
- package/dist/behaviors/kb-access.d.mts +34 -0
- package/dist/behaviors/kb-access.mjs +569 -0
- package/dist/behaviors/kb-acl.d.mts +50 -0
- package/dist/behaviors/kb-acl.mjs +405 -0
- package/dist/behaviors/kb-answer.d.mts +38 -0
- package/dist/behaviors/kb-answer.mjs +2055 -0
- package/dist/behaviors/kb-audit.d.mts +23 -0
- package/dist/behaviors/kb-audit.mjs +375 -0
- package/dist/behaviors/kb-canvas.d.mts +44 -0
- package/dist/behaviors/kb-canvas.mjs +589 -0
- package/dist/behaviors/kb-chain.d.mts +15 -0
- package/dist/behaviors/kb-chain.mjs +270 -0
- package/dist/behaviors/kb-checkpoint.d.mts +16 -0
- package/dist/behaviors/kb-checkpoint.mjs +342 -0
- package/dist/behaviors/kb-chunks.d.mts +31 -0
- package/dist/behaviors/kb-chunks.mjs +475 -0
- package/dist/behaviors/kb-citation.d.mts +38 -0
- package/dist/behaviors/kb-citation.mjs +677 -0
- package/dist/behaviors/kb-clarify.d.mts +20 -0
- package/dist/behaviors/kb-clarify.mjs +248 -0
- package/dist/behaviors/kb-conflict.d.mts +22 -0
- package/dist/behaviors/kb-conflict.mjs +284 -0
- package/dist/behaviors/kb-connector.d.mts +17 -0
- package/dist/behaviors/kb-connector.mjs +375 -0
- package/dist/behaviors/kb-core.d.mts +529 -0
- package/dist/behaviors/kb-core.mjs +890 -0
- package/dist/behaviors/kb-eval.d.mts +22 -0
- package/dist/behaviors/kb-eval.mjs +408 -0
- package/dist/behaviors/kb-explain.d.mts +11 -0
- package/dist/behaviors/kb-explain.mjs +243 -0
- package/dist/behaviors/kb-filter.d.mts +31 -0
- package/dist/behaviors/kb-filter.mjs +587 -0
- package/dist/behaviors/kb-gap.d.mts +27 -0
- package/dist/behaviors/kb-gap.mjs +273 -0
- package/dist/behaviors/kb-hittest.d.mts +34 -0
- package/dist/behaviors/kb-hittest.mjs +409 -0
- package/dist/behaviors/kb-metadata.d.mts +29 -0
- package/dist/behaviors/kb-metadata.mjs +326 -0
- package/dist/behaviors/kb-passage.d.mts +41 -0
- package/dist/behaviors/kb-passage.mjs +529 -0
- package/dist/behaviors/kb-pipeline.d.mts +18 -0
- package/dist/behaviors/kb-pipeline.mjs +381 -0
- package/dist/behaviors/kb-qa.d.mts +26 -0
- package/dist/behaviors/kb-qa.mjs +332 -0
- package/dist/behaviors/kb-rerank.d.mts +20 -0
- package/dist/behaviors/kb-rerank.mjs +315 -0
- package/dist/behaviors/kb-retrieval.d.mts +49 -0
- package/dist/behaviors/kb-retrieval.mjs +746 -0
- package/dist/behaviors/kb-review.d.mts +44 -0
- package/dist/behaviors/kb-review.mjs +451 -0
- package/dist/behaviors/kb-sandbox.d.mts +33 -0
- package/dist/behaviors/kb-sandbox.mjs +325 -0
- package/dist/behaviors/kb-segment.d.mts +32 -0
- package/dist/behaviors/kb-segment.mjs +499 -0
- package/dist/behaviors/kb-sources.d.mts +27 -0
- package/dist/behaviors/kb-sources.mjs +373 -0
- package/dist/behaviors/kb-sql.d.mts +43 -0
- package/dist/behaviors/kb-sql.mjs +948 -0
- package/dist/behaviors/kb-trace.d.mts +16 -0
- package/dist/behaviors/kb-trace.mjs +414 -0
- package/dist/behaviors/kb-visibility.d.mts +44 -0
- package/dist/behaviors/kb-visibility.mjs +403 -0
- package/dist/behaviors/kb-who-can.d.mts +32 -0
- package/dist/behaviors/kb-who-can.mjs +379 -0
- package/dist/behaviors/modal.d.mts +24 -5
- package/dist/behaviors/modal.mjs +76 -10
- package/dist/behaviors/nav.d.mts +1 -1
- package/dist/behaviors/nav.mjs +33 -7
- package/dist/behaviors/notification.d.mts +20 -4
- package/dist/behaviors/notification.mjs +53 -73
- package/dist/behaviors/popover.d.mts +39 -3
- package/dist/behaviors/popover.mjs +90 -4
- package/dist/behaviors/select.d.mts +4 -2
- package/dist/behaviors/select.mjs +161 -24
- package/dist/behaviors/sidebar.d.mts +5 -2
- package/dist/behaviors/sidebar.mjs +43 -13
- package/dist/behaviors/slider.d.mts +5 -2
- package/dist/behaviors/slider.mjs +54 -43
- package/dist/behaviors/split-pane.d.mts +6 -2
- package/dist/behaviors/split-pane.mjs +62 -21
- package/dist/behaviors/tabs.d.mts +3 -2
- package/dist/behaviors/tabs.mjs +65 -14
- package/dist/behaviors/tag-input.d.mts +5 -2
- package/dist/behaviors/tag-input.mjs +61 -21
- package/dist/behaviors/theme.d.mts +13 -2
- package/dist/behaviors/theme.mjs +48 -4
- package/dist/behaviors/toast.d.mts +30 -8
- package/dist/behaviors/toast.mjs +74 -7
- package/dist/behaviors/tree.d.mts +5 -2
- package/dist/behaviors/tree.mjs +38 -15
- package/dist/behaviors/upload.mjs +21 -23
- package/dist/cli.mjs +1 -1
- package/dist/components/ai-branch.mjs +3 -0
- package/dist/components/ai-chat.css +295 -0
- package/dist/components/ai-feedback.mjs +3 -0
- package/dist/components/ai-panel.css +218 -1
- package/dist/components/ai-threads.mjs +3 -0
- package/dist/components/ai-tool-call.mjs +1 -1
- package/dist/components/badge.css +1 -1
- package/dist/components/breadcrumb.css +0 -32
- package/dist/components/chart-calendar.mjs +1 -2
- package/dist/components/chart-graph.css +57 -0
- package/dist/components/chart-graph.mjs +4 -0
- package/dist/components/chart-map.mjs +3 -0
- package/dist/components/chart-pie.css +0 -6
- package/dist/components/chart-scatter.mjs +1 -1
- package/dist/components/charts.css +33 -1
- package/dist/components/charts.mjs +1 -0
- package/dist/components/content.css +3 -16
- package/dist/components/datatable.css +1 -1
- package/dist/components/date-picker.css +1 -1
- package/dist/components/kb-access.mjs +4 -0
- package/dist/components/kb-acl.mjs +4 -0
- package/dist/components/kb-agent.css +481 -0
- package/dist/components/kb-answer.mjs +4 -0
- package/dist/components/kb-audit.mjs +4 -0
- package/dist/components/kb-canvas.mjs +4 -0
- package/dist/components/kb-chain.mjs +4 -0
- package/dist/components/kb-checkpoint.mjs +4 -0
- package/dist/components/kb-chunks.mjs +4 -0
- package/dist/components/kb-citation.mjs +4 -0
- package/dist/components/kb-clarify.mjs +4 -0
- package/dist/components/kb-conflict.mjs +4 -0
- package/dist/components/kb-connector.mjs +4 -0
- package/dist/components/kb-data.css +649 -0
- package/dist/components/kb-eval.mjs +4 -0
- package/dist/components/kb-explain.mjs +4 -0
- package/dist/components/kb-filter.mjs +4 -0
- package/dist/components/kb-gap.mjs +4 -0
- package/dist/components/kb-ground.css +566 -0
- package/dist/components/kb-hittest.mjs +4 -0
- package/dist/components/kb-ingest.css +898 -0
- package/dist/components/kb-metadata.mjs +4 -0
- package/dist/components/kb-ops.css +548 -0
- package/dist/components/kb-passage.mjs +4 -0
- package/dist/components/kb-perm.css +444 -0
- package/dist/components/kb-pipeline.mjs +4 -0
- package/dist/components/kb-qa.mjs +4 -0
- package/dist/components/kb-rerank.mjs +4 -0
- package/dist/components/kb-retrieval.mjs +4 -0
- package/dist/components/kb-review.mjs +4 -0
- package/dist/components/kb-sandbox.mjs +4 -0
- package/dist/components/kb-search.css +940 -0
- package/dist/components/kb-segment.mjs +4 -0
- package/dist/components/kb-sources.mjs +4 -0
- package/dist/components/kb-sql.mjs +4 -0
- package/dist/components/kb-trace.mjs +4 -0
- package/dist/components/kb-visibility.mjs +4 -0
- package/dist/components/kb-who-can.mjs +4 -0
- package/dist/components/kb.css +252 -0
- package/dist/components/kb.mjs +9 -0
- package/dist/components/notification.css +2 -3
- package/dist/components/pagination.css +3 -1
- package/dist/components/pagination.mjs +1 -0
- package/dist/components/rating.mjs +1 -0
- package/dist/components/segmented.css +9 -1
- package/dist/components/segmented.mjs +1 -1
- package/dist/components/select.css +67 -4
- package/dist/components/steps.css +13 -3
- package/dist/components/steps.mjs +1 -0
- package/dist/components/switch.css +3 -1
- package/dist/components/switch.mjs +1 -0
- package/dist/components/table.mjs +1 -0
- package/dist/components/tabs.css +23 -0
- package/dist/components/tag-input.css +1 -6
- package/dist/components/upload.css +0 -15
- package/dist/index.d.mts +48 -11
- package/dist/index.mjs +13205 -3615
- package/dist/registry.json +366 -15
- package/dist/retro-effects.css +3 -16
- package/dist/tokens/retro-effects.css +3 -16
- package/dist/tokens/style-profiles.css +3 -2
- package/dist/tokens/typography.css +2 -0
- package/dist/tokens.css +5 -2
- package/dist/ui.css +5713 -267
- package/docs/research/2026-10-03-ai-kb-components.md +392 -0
- package/docs/research/2026-10-03-kb-permissions.md +992 -0
- package/docs/spec/ai-native.md +7 -4
- package/docs/spec/kb-family.md +443 -0
- package/package.json +2 -2
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
// src/behaviors/ai-core.ts
|
|
2
|
+
var USAGE_KEYS = ["input", "output", "cacheRead", "cacheWrite", "reasoning", "total"];
|
|
3
|
+
function addUsage(sum2, u) {
|
|
4
|
+
const out = { ...sum2 };
|
|
5
|
+
for (const k of USAGE_KEYS) {
|
|
6
|
+
const v = u[k];
|
|
7
|
+
if (typeof v === "number" && Number.isFinite(v)) out[k] = (out[k] ?? 0) + v;
|
|
8
|
+
}
|
|
9
|
+
return out;
|
|
10
|
+
}
|
|
2
11
|
var svg = (body) => `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${body}</svg>`;
|
|
3
12
|
var ICON_TERMINAL = svg('<path d="m4 17 6-6-6-6"/><path d="M12 19h8"/>');
|
|
4
13
|
var ICON_FILE = svg(
|
|
@@ -159,9 +168,9 @@ function formatDuration(ms) {
|
|
|
159
168
|
const m = Math.floor(ms / 6e4);
|
|
160
169
|
const s = Math.round(ms % 6e4 / 1e3);
|
|
161
170
|
if (ms < 36e5) return s > 0 ? `${m}m${s}s` : `${m}m`;
|
|
162
|
-
const
|
|
171
|
+
const h2 = Math.floor(ms / 36e5);
|
|
163
172
|
const rm = Math.round(ms % 36e5 / 6e4);
|
|
164
|
-
return rm > 0 ? `${
|
|
173
|
+
return rm > 0 ? `${h2}h${rm}m` : `${h2}h`;
|
|
165
174
|
}
|
|
166
175
|
function aiContentUrl(part) {
|
|
167
176
|
if (part.type === "text" || part.type === "resource-link") return void 0;
|
|
@@ -175,6 +184,12 @@ function contextEstimate(usage) {
|
|
|
175
184
|
const u = normalizeUsage(usage);
|
|
176
185
|
return (u.input ?? 0) + (u.cacheRead ?? 0) + (u.cacheWrite ?? 0) + (u.output ?? 0) + (u.reasoning ?? 0);
|
|
177
186
|
}
|
|
187
|
+
function h(tag, className, text) {
|
|
188
|
+
const node = document.createElement(tag);
|
|
189
|
+
if (className) node.className = className;
|
|
190
|
+
if (text != null) node.textContent = text;
|
|
191
|
+
return node;
|
|
192
|
+
}
|
|
178
193
|
function svgIcon(svg2) {
|
|
179
194
|
if (typeof document === "undefined" || typeof DOMParser === "undefined") return null;
|
|
180
195
|
let parsed;
|
|
@@ -187,15 +202,15 @@ function svgIcon(svg2) {
|
|
|
187
202
|
if (!root || root.tagName.toLowerCase() !== "svg" || parsed.querySelector("parsererror")) {
|
|
188
203
|
return null;
|
|
189
204
|
}
|
|
190
|
-
const sanitize = (
|
|
191
|
-
for (const attr of Array.from(
|
|
205
|
+
const sanitize = (el) => {
|
|
206
|
+
for (const attr of Array.from(el.attributes)) {
|
|
192
207
|
const name = attr.name.toLowerCase();
|
|
193
|
-
if (name.startsWith("on"))
|
|
208
|
+
if (name.startsWith("on")) el.removeAttribute(attr.name);
|
|
194
209
|
if ((name === "href" || name === "xlink:href") && attr.value.trim().toLowerCase().startsWith("javascript:")) {
|
|
195
|
-
|
|
210
|
+
el.removeAttribute(attr.name);
|
|
196
211
|
}
|
|
197
212
|
}
|
|
198
|
-
for (const child of Array.from(
|
|
213
|
+
for (const child of Array.from(el.children)) {
|
|
199
214
|
const tag = child.tagName.toLowerCase();
|
|
200
215
|
if (tag === "script" || tag === "foreignobject") {
|
|
201
216
|
child.remove();
|
|
@@ -209,6 +224,44 @@ function svgIcon(svg2) {
|
|
|
209
224
|
}
|
|
210
225
|
|
|
211
226
|
// src/behaviors/popover.ts
|
|
227
|
+
var PANEL_SIZING_ATTRS = {
|
|
228
|
+
width: "data-panel-width",
|
|
229
|
+
minWidth: "data-panel-min",
|
|
230
|
+
maxWidth: "data-panel-max",
|
|
231
|
+
minHeight: "data-panel-min-height",
|
|
232
|
+
maxHeight: "data-panel-max-height"
|
|
233
|
+
};
|
|
234
|
+
function readPanelSizing(el) {
|
|
235
|
+
const out = {};
|
|
236
|
+
if (!el) return out;
|
|
237
|
+
for (const key of Object.keys(PANEL_SIZING_ATTRS)) {
|
|
238
|
+
const raw = el.getAttribute(PANEL_SIZING_ATTRS[key]);
|
|
239
|
+
if (raw == null) continue;
|
|
240
|
+
const n = Number(raw);
|
|
241
|
+
if (Number.isFinite(n) && n > 0) out[key] = n;
|
|
242
|
+
}
|
|
243
|
+
return out;
|
|
244
|
+
}
|
|
245
|
+
function resolvePanelSizing(el, overrides) {
|
|
246
|
+
const base = readPanelSizing(el);
|
|
247
|
+
if (!overrides) return base;
|
|
248
|
+
for (const key of Object.keys(overrides)) {
|
|
249
|
+
const v = overrides[key];
|
|
250
|
+
if (typeof v === "number" && Number.isFinite(v) && v > 0) base[key] = v;
|
|
251
|
+
}
|
|
252
|
+
return base;
|
|
253
|
+
}
|
|
254
|
+
function sizingToLayout(sizing, opts) {
|
|
255
|
+
const out = { ...opts };
|
|
256
|
+
if (sizing.minWidth != null) out.minWidth = sizing.minWidth;
|
|
257
|
+
if (sizing.maxWidth != null) out.maxWidth = sizing.maxWidth;
|
|
258
|
+
if (sizing.width != null) {
|
|
259
|
+
out.minWidth = sizing.width;
|
|
260
|
+
out.maxWidth = sizing.width;
|
|
261
|
+
}
|
|
262
|
+
if (sizing.maxHeight != null) out.maxHeight = sizing.maxHeight;
|
|
263
|
+
return out;
|
|
264
|
+
}
|
|
212
265
|
var DEFAULT_MIN_WIDTH = 220;
|
|
213
266
|
var DEFAULT_MAX_WIDTH = 420;
|
|
214
267
|
var DEFAULT_MIN_HEIGHT = 120;
|
|
@@ -233,13 +286,35 @@ function horizontalAnchor(anchor, width, align) {
|
|
|
233
286
|
function computePopoverLayout(anchor, viewport, opts = {}) {
|
|
234
287
|
const margin = opts.margin ?? 12;
|
|
235
288
|
const offset = opts.offset ?? 8;
|
|
289
|
+
const preferredSide = opts.side ?? "top";
|
|
290
|
+
const align = opts.align ?? "start";
|
|
291
|
+
if (preferredSide === "left" || preferredSide === "right") {
|
|
292
|
+
const availableLeft = Math.max(0, anchor.left - margin - offset);
|
|
293
|
+
const availableRight = Math.max(0, viewport.width - anchor.right - margin - offset);
|
|
294
|
+
const side2 = (preferredSide === "left" ? availableLeft : availableRight) >= DEFAULT_MIN_WIDTH ? preferredSide : preferredSide === "left" ? "right" : "left";
|
|
295
|
+
const minWidth2 = Math.max(1, opts.minWidth ?? DEFAULT_MIN_WIDTH);
|
|
296
|
+
const maxWidth2 = Math.min(
|
|
297
|
+
Math.max(opts.maxWidth ?? DEFAULT_MAX_WIDTH, minWidth2),
|
|
298
|
+
side2 === "left" ? availableLeft : availableRight
|
|
299
|
+
);
|
|
300
|
+
const width2 = minWidth2;
|
|
301
|
+
const left2 = clamp(
|
|
302
|
+
side2 === "left" ? anchor.left - offset - width2 : anchor.right + offset,
|
|
303
|
+
margin,
|
|
304
|
+
viewport.width - margin - width2
|
|
305
|
+
);
|
|
306
|
+
const availableHeight2 = Math.max(80, viewport.height - margin * 2);
|
|
307
|
+
const maxHeight2 = Math.min(opts.maxHeight ?? DEFAULT_MAX_HEIGHT, availableHeight2);
|
|
308
|
+
const desired = clamp(opts.contentHeightHint ?? Math.min(anchor.height, maxHeight2), 40, maxHeight2);
|
|
309
|
+
const anchorTop = align === "center" ? anchor.top + anchor.height / 2 - desired / 2 : align === "end" ? anchor.bottom - desired : anchor.top;
|
|
310
|
+
const top2 = clamp(anchorTop, margin, viewport.height - margin - desired);
|
|
311
|
+
return { side: side2, left: left2, top: top2, width: width2, maxHeight: maxHeight2 };
|
|
312
|
+
}
|
|
236
313
|
const availableWidth = Math.max(80, viewport.width - margin * 2);
|
|
237
314
|
const requestedMinWidth = Math.max(1, opts.minWidth ?? DEFAULT_MIN_WIDTH);
|
|
238
315
|
const requestedMaxWidth = Math.max(requestedMinWidth, opts.maxWidth ?? DEFAULT_MAX_WIDTH);
|
|
239
316
|
const maxWidth = Math.min(requestedMaxWidth, availableWidth);
|
|
240
317
|
const minWidth = Math.min(requestedMinWidth, maxWidth);
|
|
241
|
-
const preferredSide = opts.side ?? "top";
|
|
242
|
-
const align = opts.align ?? "start";
|
|
243
318
|
const availableTop = Math.max(0, anchor.top - margin - offset);
|
|
244
319
|
const availableBottom = Math.max(0, viewport.height - anchor.bottom - margin - offset);
|
|
245
320
|
const availableHeight = Math.max(80, viewport.height - margin * 2);
|
|
@@ -263,8 +338,8 @@ function computePopoverLayout(anchor, viewport, opts = {}) {
|
|
|
263
338
|
return { side, left, top, width, maxHeight };
|
|
264
339
|
}
|
|
265
340
|
var openPanels = /* @__PURE__ */ new Map();
|
|
266
|
-
function rectFromElement(
|
|
267
|
-
const r =
|
|
341
|
+
function rectFromElement(el) {
|
|
342
|
+
const r = el.getBoundingClientRect();
|
|
268
343
|
return { left: r.left, top: r.top, right: r.right, bottom: r.bottom, width: r.width, height: r.height };
|
|
269
344
|
}
|
|
270
345
|
function resolveAnchor(state) {
|
|
@@ -317,7 +392,8 @@ function onKeyDown(e) {
|
|
|
317
392
|
function openPopover(panel, options) {
|
|
318
393
|
if (typeof document === "undefined") return;
|
|
319
394
|
if (openPanels.has(panel)) closePopover(panel);
|
|
320
|
-
const { anchor, onClose, ...
|
|
395
|
+
const { anchor, onClose, sizing, ...rest } = options;
|
|
396
|
+
const layoutOpts = sizingToLayout(resolvePanelSizing(panel, sizing), rest);
|
|
321
397
|
const placeholder = document.createComment("popover-anchor");
|
|
322
398
|
panel.parentNode?.insertBefore(placeholder, panel);
|
|
323
399
|
const wasHidden = panel.hidden;
|
|
@@ -369,17 +445,18 @@ function closePopover(panel) {
|
|
|
369
445
|
state.onClose?.();
|
|
370
446
|
}
|
|
371
447
|
|
|
372
|
-
// src/behaviors/
|
|
373
|
-
function
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
return node;
|
|
448
|
+
// src/behaviors/events.ts
|
|
449
|
+
function emitIcen(source, type, detail) {
|
|
450
|
+
return source.dispatchEvent(
|
|
451
|
+
new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
|
|
452
|
+
);
|
|
378
453
|
}
|
|
454
|
+
|
|
455
|
+
// src/behaviors/ai-panel.ts
|
|
379
456
|
function buildTodoHead(done, total) {
|
|
380
|
-
const head =
|
|
381
|
-
head.appendChild(
|
|
382
|
-
const bar =
|
|
457
|
+
const head = h("div", "ai-todo-head");
|
|
458
|
+
head.appendChild(h("span", "ai-todo-progress", `${done}/${total}`));
|
|
459
|
+
const bar = h("div", "ai-todo-bar");
|
|
383
460
|
bar.setAttribute("role", "progressbar");
|
|
384
461
|
bar.setAttribute("aria-valuemin", "0");
|
|
385
462
|
bar.setAttribute("aria-valuemax", String(total));
|
|
@@ -391,27 +468,46 @@ function buildTodoHead(done, total) {
|
|
|
391
468
|
head.appendChild(bar);
|
|
392
469
|
return head;
|
|
393
470
|
}
|
|
471
|
+
var ICON_TODO_CHECK = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m3.5 12.5 5 5L20.5 6" pathLength="1"/></svg>';
|
|
394
472
|
function buildTodoItem(item, index) {
|
|
395
|
-
const row =
|
|
473
|
+
const row = h("div", `ai-todo-item is-${item.status}`);
|
|
396
474
|
row.dataset.index = String(index);
|
|
397
|
-
row.appendChild(
|
|
398
|
-
|
|
399
|
-
|
|
475
|
+
row.appendChild(h("span", "ai-item-status"));
|
|
476
|
+
const check = h("span", "ai-todo-check is-anim");
|
|
477
|
+
check.setAttribute("aria-hidden", "true");
|
|
478
|
+
const checkSvg = svgIcon(ICON_TODO_CHECK);
|
|
479
|
+
if (checkSvg) check.appendChild(checkSvg);
|
|
480
|
+
row.appendChild(check);
|
|
481
|
+
row.appendChild(h("span", "ai-todo-text", item.content));
|
|
482
|
+
row.appendChild(h("span", "ai-todo-active", item.activeForm ?? item.content));
|
|
400
483
|
return row;
|
|
401
484
|
}
|
|
402
|
-
function renderAiTodo(
|
|
403
|
-
if (typeof document === "undefined") return;
|
|
404
|
-
|
|
405
|
-
const root =
|
|
485
|
+
function renderAiTodo(el, items) {
|
|
486
|
+
if (typeof document === "undefined") return el;
|
|
487
|
+
el.textContent = "";
|
|
488
|
+
const root = h("div", "ai-todo");
|
|
406
489
|
const list = Array.isArray(items) ? items : [];
|
|
407
490
|
const done = list.filter((i) => i.status === "done").length;
|
|
408
491
|
root.appendChild(buildTodoHead(done, list.length));
|
|
409
492
|
list.forEach((item, i) => root.appendChild(buildTodoItem(item, i)));
|
|
410
493
|
if (list.length > 0 && done === list.length) root.classList.add("is-complete");
|
|
411
|
-
|
|
494
|
+
el.appendChild(root);
|
|
495
|
+
return el;
|
|
412
496
|
}
|
|
413
|
-
function
|
|
414
|
-
|
|
497
|
+
function metricField(src, key) {
|
|
498
|
+
return typeof src === "object" && src !== null ? src[key] : void 0;
|
|
499
|
+
}
|
|
500
|
+
function metricNum(v) {
|
|
501
|
+
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
502
|
+
}
|
|
503
|
+
function metricStr(v) {
|
|
504
|
+
return typeof v === "string" && v ? v : void 0;
|
|
505
|
+
}
|
|
506
|
+
function trimNum(v) {
|
|
507
|
+
return String(Math.round(v * 10) / 10);
|
|
508
|
+
}
|
|
509
|
+
function renderAiUsage(el, usage, opts = {}) {
|
|
510
|
+
if (typeof document === "undefined") return el;
|
|
415
511
|
const u = normalizeUsage(usage);
|
|
416
512
|
const segs = [
|
|
417
513
|
{ key: "input", className: "ai-usage-seg--input", label: "\u8F93\u5165", value: u.input ?? 0 },
|
|
@@ -423,9 +519,9 @@ function renderAiUsage(elm, usage, opts = {}) {
|
|
|
423
519
|
const activeSegs = segs.filter((s) => s.value > 0);
|
|
424
520
|
const sum2 = activeSegs.reduce((acc, s) => acc + s.value, 0);
|
|
425
521
|
const total = u.total ?? sum2;
|
|
426
|
-
|
|
427
|
-
const root =
|
|
428
|
-
const bar =
|
|
522
|
+
el.textContent = "";
|
|
523
|
+
const root = h("div", "ai-usage");
|
|
524
|
+
const bar = h("div", "ai-usage-bar");
|
|
429
525
|
const summary = activeSegs.length > 0 ? activeSegs.map((s) => `${s.label} ${formatTokens(s.value)}`).join("\uFF0C") : "\u6682\u65E0\u7528\u91CF";
|
|
430
526
|
bar.setAttribute("role", "img");
|
|
431
527
|
bar.setAttribute("aria-label", `\u7528\u91CF\uFF1A${summary}`);
|
|
@@ -437,19 +533,27 @@ function renderAiUsage(elm, usage, opts = {}) {
|
|
|
437
533
|
}
|
|
438
534
|
root.appendChild(bar);
|
|
439
535
|
if (activeSegs.length > 0) {
|
|
440
|
-
const legend =
|
|
536
|
+
const legend = h("div", "ai-usage-legend");
|
|
441
537
|
for (const s of activeSegs) {
|
|
442
|
-
const item =
|
|
538
|
+
const item = h("span", "ai-usage-legend-item");
|
|
443
539
|
const dot = document.createElement("i");
|
|
444
540
|
dot.className = `ai-usage-dot ${s.className}`;
|
|
445
541
|
dot.setAttribute("aria-hidden", "true");
|
|
446
542
|
item.appendChild(dot);
|
|
447
|
-
item.appendChild(
|
|
448
|
-
item.appendChild(
|
|
543
|
+
item.appendChild(h("span", "ai-usage-legend-label", s.label));
|
|
544
|
+
item.appendChild(h("span", "ai-usage-legend-value", formatTokens(s.value)));
|
|
449
545
|
legend.appendChild(item);
|
|
450
546
|
}
|
|
451
547
|
root.appendChild(legend);
|
|
452
548
|
}
|
|
549
|
+
const ttft = metricNum(opts.metrics?.ttftMs) ?? metricNum(metricField(usage, "ttftMs"));
|
|
550
|
+
const tps = metricNum(opts.metrics?.tokensPerSec) ?? metricNum(metricField(usage, "tokensPerSec"));
|
|
551
|
+
const finish = metricStr(opts.metrics?.finishReason) ?? metricStr(metricField(usage, "finishReason"));
|
|
552
|
+
const metricBits = [];
|
|
553
|
+
if (ttft != null) metricBits.push(`TTFT ${formatDuration(ttft)}`);
|
|
554
|
+
if (tps != null && tps > 0) metricBits.push(`${trimNum(tps)} tok/s`);
|
|
555
|
+
if (finish) metricBits.push(`finish: ${finish}`);
|
|
556
|
+
if (metricBits.length > 0) root.appendChild(h("div", "ai-usage-metrics", metricBits.join(" \xB7 ")));
|
|
453
557
|
const totalParts = [formatTokens(total)];
|
|
454
558
|
if (typeof opts.total === "number" && opts.total > 0) {
|
|
455
559
|
const pct = Math.min(100, Math.round(total / opts.total * 100));
|
|
@@ -458,17 +562,18 @@ function renderAiUsage(elm, usage, opts = {}) {
|
|
|
458
562
|
if (typeof opts.cost === "number" && Number.isFinite(opts.cost)) {
|
|
459
563
|
totalParts.push(` \xB7 $${opts.cost.toFixed(4)}`);
|
|
460
564
|
}
|
|
461
|
-
root.appendChild(
|
|
462
|
-
|
|
565
|
+
root.appendChild(h("div", "ai-usage-total", totalParts.join("")));
|
|
566
|
+
el.appendChild(root);
|
|
567
|
+
return el;
|
|
463
568
|
}
|
|
464
|
-
function renderAiUsageRing(
|
|
465
|
-
if (typeof document === "undefined") return;
|
|
569
|
+
function renderAiUsageRing(el, usage, opts = {}) {
|
|
570
|
+
if (typeof document === "undefined") return el;
|
|
466
571
|
const u = normalizeUsage(usage);
|
|
467
572
|
const used = u.total ?? (u.input ?? 0) + (u.output ?? 0) + (u.cacheRead ?? 0) + (u.cacheWrite ?? 0) + (u.reasoning ?? 0);
|
|
468
573
|
const hasLimit = typeof opts.total === "number" && opts.total > 0;
|
|
469
574
|
const pct = hasLimit ? Math.min(100, Math.max(0, Math.round(used / opts.total * 100))) : 0;
|
|
470
|
-
|
|
471
|
-
const btn =
|
|
575
|
+
el.textContent = "";
|
|
576
|
+
const btn = h("button", "ai-usage-ring");
|
|
472
577
|
btn.type = "button";
|
|
473
578
|
btn.classList.add(pct >= 85 ? "is-hot" : pct >= 60 ? "is-warn" : "is-ok");
|
|
474
579
|
btn.setAttribute("aria-haspopup", "true");
|
|
@@ -492,7 +597,7 @@ function renderAiUsageRing(elm, usage, opts = {}) {
|
|
|
492
597
|
svg2.appendChild(c);
|
|
493
598
|
}
|
|
494
599
|
btn.appendChild(svg2);
|
|
495
|
-
btn.appendChild(
|
|
600
|
+
btn.appendChild(h("span", "ai-usage-ring-pct", hasLimit ? `${pct}%` : formatTokens(used)));
|
|
496
601
|
let panel = null;
|
|
497
602
|
const closePanel = () => {
|
|
498
603
|
if (!panel) return;
|
|
@@ -506,10 +611,10 @@ function renderAiUsageRing(elm, usage, opts = {}) {
|
|
|
506
611
|
closePanel();
|
|
507
612
|
return;
|
|
508
613
|
}
|
|
509
|
-
const p =
|
|
614
|
+
const p = h("div", "popover ai-usage-popover");
|
|
510
615
|
p.hidden = true;
|
|
511
|
-
p.appendChild(
|
|
512
|
-
const body =
|
|
616
|
+
p.appendChild(h("div", "ai-usage-popover-title", opts.title ?? "\u4E0A\u4E0B\u6587\u7A97\u53E3"));
|
|
617
|
+
const body = h("div", "ai-usage-popover-body");
|
|
513
618
|
renderAiUsage(body, usage, opts);
|
|
514
619
|
p.appendChild(body);
|
|
515
620
|
openPopover(p, {
|
|
@@ -523,7 +628,8 @@ function renderAiUsageRing(elm, usage, opts = {}) {
|
|
|
523
628
|
});
|
|
524
629
|
panel = p;
|
|
525
630
|
});
|
|
526
|
-
|
|
631
|
+
el.appendChild(btn);
|
|
632
|
+
return el;
|
|
527
633
|
}
|
|
528
634
|
var svgWrap = (inner) => `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${inner}</svg>`;
|
|
529
635
|
var FILE_OUTLINE = '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/>';
|
|
@@ -546,46 +652,108 @@ var ICON_SPARKLES = svgWrap(
|
|
|
546
652
|
// src/behaviors/ai-chat.ts
|
|
547
653
|
var ICON_COPY = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="8" y="2" width="8" height="4" rx="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/></svg>';
|
|
548
654
|
var ICON_RETRY = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>';
|
|
549
|
-
function
|
|
550
|
-
|
|
655
|
+
function emit(target, name, detail) {
|
|
656
|
+
emitIcen(target, name, detail);
|
|
657
|
+
}
|
|
658
|
+
var REASONING_AUTO_CLOSE_MS = 1e3;
|
|
659
|
+
function setReasoningOpen(reasoning, open) {
|
|
660
|
+
const head = reasoning.querySelector(".ai-reasoning-head");
|
|
661
|
+
const body = reasoning.querySelector(".ai-reasoning-body");
|
|
662
|
+
head?.setAttribute("aria-expanded", String(open));
|
|
663
|
+
reasoning.classList.toggle("is-open", open);
|
|
664
|
+
if (body) body.hidden = !open;
|
|
665
|
+
}
|
|
666
|
+
function clearContinueSlot(scope) {
|
|
667
|
+
scope?.querySelectorAll(".ai-msg-continue").forEach((n) => n.remove());
|
|
668
|
+
}
|
|
669
|
+
function createAiStream(el) {
|
|
670
|
+
const reasoning = el.closest(".ai-reasoning");
|
|
671
|
+
const msgBody = el.closest(".ai-msg-body");
|
|
672
|
+
const msg = el.closest(".ai-msg");
|
|
551
673
|
const startedAt = Date.now();
|
|
552
674
|
let state = "streaming";
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
reasoning
|
|
675
|
+
el.classList.add("is-streaming");
|
|
676
|
+
el.setAttribute("aria-busy", "true");
|
|
677
|
+
if (reasoning) {
|
|
678
|
+
reasoning.classList.add("is-streaming");
|
|
679
|
+
setReasoningOpen(reasoning, true);
|
|
680
|
+
const head = reasoning.querySelector(".ai-reasoning-head");
|
|
681
|
+
if (head && head.dataset.reasoningStart == null) head.dataset.reasoningStart = String(startedAt);
|
|
682
|
+
}
|
|
683
|
+
clearContinueSlot(msg ?? msgBody ?? el);
|
|
684
|
+
const fillReasoningTime = () => {
|
|
685
|
+
if (!reasoning) return;
|
|
686
|
+
const time = reasoning.querySelector(".ai-reasoning-time");
|
|
687
|
+
if (!time) return;
|
|
688
|
+
const head = reasoning.querySelector(".ai-reasoning-head");
|
|
689
|
+
const raw = Number(head?.dataset.reasoningStart ?? "");
|
|
690
|
+
const t0 = Number.isFinite(raw) && raw > 0 ? raw : startedAt;
|
|
691
|
+
time.textContent = `\u601D\u8003 ${formatDuration(Math.max(0, Date.now() - t0))}`;
|
|
692
|
+
};
|
|
693
|
+
const scheduleReasoningAutoClose = () => {
|
|
694
|
+
if (!reasoning) return;
|
|
695
|
+
const r = reasoning;
|
|
696
|
+
if (r.__icenReasonUserTouched || r.__icenReasonAutoClosed) return;
|
|
697
|
+
const close = () => {
|
|
698
|
+
if (r.__icenReasonUserTouched || r.__icenReasonAutoClosed) return;
|
|
699
|
+
r.__icenReasonAutoClosed = true;
|
|
700
|
+
setReasoningOpen(r, false);
|
|
701
|
+
};
|
|
702
|
+
if (typeof window === "undefined") {
|
|
703
|
+
close();
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
window.setTimeout(close, REASONING_AUTO_CLOSE_MS);
|
|
707
|
+
};
|
|
708
|
+
const appendContinueSlot = () => {
|
|
709
|
+
if (typeof document === "undefined") return;
|
|
710
|
+
const mount = msgBody ?? msg ?? (el.parentElement instanceof HTMLElement ? el.parentElement : null);
|
|
711
|
+
if (!mount || mount.querySelector(":scope > .ai-msg-continue")) return;
|
|
712
|
+
const btn = document.createElement("button");
|
|
713
|
+
btn.type = "button";
|
|
714
|
+
btn.className = "ai-msg-continue";
|
|
715
|
+
btn.textContent = "\u7EE7\u7EED\u751F\u6210";
|
|
716
|
+
btn.addEventListener("click", () => {
|
|
717
|
+
const target = msg ?? btn;
|
|
718
|
+
emit(target, "icen:ai-retry", { el: target });
|
|
719
|
+
});
|
|
720
|
+
mount.appendChild(btn);
|
|
721
|
+
};
|
|
556
722
|
const settle = (finished) => {
|
|
557
723
|
if (state !== "streaming") return;
|
|
558
724
|
state = finished ? "done" : "cancelled";
|
|
559
|
-
|
|
560
|
-
|
|
725
|
+
el.classList.remove("is-streaming");
|
|
726
|
+
el.removeAttribute("aria-busy");
|
|
561
727
|
if (!reasoning) return;
|
|
562
728
|
reasoning.classList.remove("is-streaming");
|
|
563
729
|
if (!finished) return;
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
head?.setAttribute("aria-expanded", "false");
|
|
567
|
-
if (body) body.hidden = true;
|
|
568
|
-
const time = reasoning.querySelector(".ai-reasoning-time");
|
|
569
|
-
if (time) time.textContent = formatDuration(Date.now() - startedAt);
|
|
730
|
+
fillReasoningTime();
|
|
731
|
+
scheduleReasoningAutoClose();
|
|
570
732
|
};
|
|
571
733
|
return {
|
|
572
734
|
append(text) {
|
|
573
735
|
if (state !== "streaming" || !text) return;
|
|
574
|
-
|
|
736
|
+
el.textContent += text;
|
|
575
737
|
},
|
|
576
738
|
done() {
|
|
577
739
|
settle(true);
|
|
578
740
|
},
|
|
579
741
|
cancel() {
|
|
580
742
|
settle(false);
|
|
743
|
+
appendContinueSlot();
|
|
581
744
|
},
|
|
582
745
|
fail() {
|
|
583
746
|
if (state !== "streaming") return;
|
|
584
747
|
state = "error";
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
reasoning
|
|
748
|
+
el.classList.remove("is-streaming");
|
|
749
|
+
el.removeAttribute("aria-busy");
|
|
750
|
+
el.classList.add("is-error");
|
|
751
|
+
if (reasoning) {
|
|
752
|
+
reasoning.classList.remove("is-streaming");
|
|
753
|
+
fillReasoningTime();
|
|
754
|
+
scheduleReasoningAutoClose();
|
|
755
|
+
}
|
|
756
|
+
appendContinueSlot();
|
|
589
757
|
}
|
|
590
758
|
};
|
|
591
759
|
}
|
|
@@ -600,15 +768,9 @@ function safeHref(uri) {
|
|
|
600
768
|
if (s.startsWith("javascript:") || s.startsWith("data:text/html")) return void 0;
|
|
601
769
|
return uri;
|
|
602
770
|
}
|
|
603
|
-
function el2(tag, className, text) {
|
|
604
|
-
const node = document.createElement(tag);
|
|
605
|
-
if (className) node.className = className;
|
|
606
|
-
if (text != null) node.textContent = text;
|
|
607
|
-
return node;
|
|
608
|
-
}
|
|
609
771
|
function renderAiContentPart(part) {
|
|
610
772
|
if (part.type === "text") {
|
|
611
|
-
const span =
|
|
773
|
+
const span = h("span", "ai-msg-text");
|
|
612
774
|
span.textContent = part.text;
|
|
613
775
|
if (part.state === "streaming") span.classList.add("is-streaming");
|
|
614
776
|
return span;
|
|
@@ -643,8 +805,8 @@ function renderAiContentPart(part) {
|
|
|
643
805
|
return video;
|
|
644
806
|
}
|
|
645
807
|
if (part.type === "file") {
|
|
646
|
-
const chip =
|
|
647
|
-
chip.appendChild(
|
|
808
|
+
const chip = h("span", "ai-msg-file");
|
|
809
|
+
chip.appendChild(h("span", "ai-msg-file-name", part.filename ?? "\u6587\u4EF6"));
|
|
648
810
|
const href2 = part.url ? safeHref(part.url) : void 0;
|
|
649
811
|
if (href2 && /^(https?:|data:)/i.test(href2)) {
|
|
650
812
|
const a2 = document.createElement("a");
|
|
@@ -665,9 +827,18 @@ function renderAiContentPart(part) {
|
|
|
665
827
|
return a;
|
|
666
828
|
}
|
|
667
829
|
function renderAiMessage(scrollEl, model) {
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
830
|
+
if (typeof document === "undefined") {
|
|
831
|
+
return {
|
|
832
|
+
el: scrollEl,
|
|
833
|
+
body: scrollEl,
|
|
834
|
+
setMeta: () => void 0,
|
|
835
|
+
setError: () => void 0,
|
|
836
|
+
stream: () => createAiStream(scrollEl)
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
const row = h("div", `ai-msg ai-msg--${model.role}`);
|
|
840
|
+
const avatar = h("span", "ai-msg-avatar", ROLE_AVATAR[model.role] ?? "");
|
|
841
|
+
const body = h("div", "ai-msg-body");
|
|
671
842
|
row.appendChild(avatar);
|
|
672
843
|
row.appendChild(body);
|
|
673
844
|
const parts = typeof model.content === "string" ? [{ type: "text", text: model.content }] : model.content;
|
|
@@ -675,18 +846,18 @@ function renderAiMessage(scrollEl, model) {
|
|
|
675
846
|
const node = renderAiContentPart(part);
|
|
676
847
|
if (node) body.appendChild(node);
|
|
677
848
|
}
|
|
678
|
-
if (model.model) body.appendChild(
|
|
679
|
-
const metaEl =
|
|
849
|
+
if (model.model) body.appendChild(h("span", "ai-msg-model", model.model));
|
|
850
|
+
const metaEl = h("div", "ai-msg-meta");
|
|
680
851
|
if (model.meta != null) metaEl.textContent = model.meta;
|
|
681
852
|
row.appendChild(metaEl);
|
|
682
|
-
const actions =
|
|
683
|
-
const copyBtn =
|
|
853
|
+
const actions = h("div", "ai-msg-actions");
|
|
854
|
+
const copyBtn = h("button", "ai-msg-action");
|
|
684
855
|
copyBtn.type = "button";
|
|
685
856
|
copyBtn.setAttribute("data-ai-msg-action", "copy");
|
|
686
857
|
copyBtn.setAttribute("aria-label", "\u590D\u5236");
|
|
687
858
|
const copyIcon = svgIcon(ICON_COPY);
|
|
688
859
|
if (copyIcon) copyBtn.appendChild(copyIcon);
|
|
689
|
-
const retryBtn =
|
|
860
|
+
const retryBtn = h("button", "ai-msg-action");
|
|
690
861
|
retryBtn.type = "button";
|
|
691
862
|
retryBtn.setAttribute("data-ai-msg-action", "retry");
|
|
692
863
|
retryBtn.setAttribute("aria-label", "\u91CD\u8BD5");
|
|
@@ -704,13 +875,13 @@ function renderAiMessage(scrollEl, model) {
|
|
|
704
875
|
row.classList.add("ai-msg--error");
|
|
705
876
|
let errEl = row.querySelector(".ai-msg-error-text");
|
|
706
877
|
if (!errEl) {
|
|
707
|
-
errEl =
|
|
878
|
+
errEl = h("div", "ai-msg-error-text");
|
|
708
879
|
body.appendChild(errEl);
|
|
709
880
|
}
|
|
710
881
|
errEl.textContent = message;
|
|
711
882
|
},
|
|
712
883
|
stream() {
|
|
713
|
-
const span =
|
|
884
|
+
const span = h("span", "ai-msg-stream-text");
|
|
714
885
|
body.appendChild(span);
|
|
715
886
|
return createAiStream(span);
|
|
716
887
|
}
|
|
@@ -744,19 +915,35 @@ var ICON_DOC = svgWrap2(
|
|
|
744
915
|
var ICON_BOT2 = svgWrap2(
|
|
745
916
|
'<path d="M12 8V4H8"/><rect width="16" height="12" x="4" y="8" rx="2"/><path d="M2 14h2"/><path d="M20 14h2"/><path d="M15 13v2"/><path d="M9 13v2"/>'
|
|
746
917
|
);
|
|
747
|
-
var
|
|
748
|
-
file: "\u6587\u4EF6",
|
|
749
|
-
folder: "\u6587\u4EF6\u5939",
|
|
750
|
-
doc: "\u6587\u6863",
|
|
751
|
-
agent: "\u4EE3\u7406"
|
|
918
|
+
var REF_KIND_BUILTIN = {
|
|
919
|
+
file: { label: "\u6587\u4EF6", icon: ICON_FILE3, order: 0 },
|
|
920
|
+
folder: { label: "\u6587\u4EF6\u5939", icon: ICON_FOLDER, order: 1 },
|
|
921
|
+
doc: { label: "\u6587\u6863", icon: ICON_DOC, order: 2 },
|
|
922
|
+
agent: { label: "\u4EE3\u7406", icon: ICON_BOT2, order: 3 }
|
|
752
923
|
};
|
|
753
|
-
var
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
}
|
|
759
|
-
|
|
924
|
+
var REF_KIND_ORDER_LAST = Number.MAX_SAFE_INTEGER;
|
|
925
|
+
var REF_KIND_REGISTRY = /* @__PURE__ */ new Map();
|
|
926
|
+
function registerRefKind(kind, def) {
|
|
927
|
+
const key = kind.trim();
|
|
928
|
+
if (key) REF_KIND_REGISTRY.set(key, def);
|
|
929
|
+
}
|
|
930
|
+
function getRefKindDef(kind) {
|
|
931
|
+
const reg = REF_KIND_REGISTRY.get(kind);
|
|
932
|
+
const builtin = REF_KIND_BUILTIN[kind];
|
|
933
|
+
return {
|
|
934
|
+
label: reg?.label ?? builtin?.label ?? kind,
|
|
935
|
+
icon: reg?.icon ?? builtin?.icon ?? ICON_DOC,
|
|
936
|
+
order: reg && typeof reg.order === "number" && Number.isFinite(reg.order) ? reg.order : builtin?.order ?? REF_KIND_ORDER_LAST
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
function knownRefKinds(sources) {
|
|
940
|
+
const kinds = new Set(Object.keys(REF_KIND_BUILTIN));
|
|
941
|
+
for (const key of REF_KIND_REGISTRY.keys()) kinds.add(key);
|
|
942
|
+
for (const s of sources) {
|
|
943
|
+
if (typeof s?.kind === "string" && s.kind) kinds.add(s.kind);
|
|
944
|
+
}
|
|
945
|
+
return Array.from(kinds).sort((a, b) => getRefKindDef(a).order - getRefKindDef(b).order);
|
|
946
|
+
}
|
|
760
947
|
var RUNNING = /* @__PURE__ */ new WeakMap();
|
|
761
948
|
var QUEUES = /* @__PURE__ */ new WeakMap();
|
|
762
949
|
var MODELS = /* @__PURE__ */ new WeakMap();
|
|
@@ -765,18 +952,19 @@ var COMMANDS = /* @__PURE__ */ new WeakMap();
|
|
|
765
952
|
var REF_SOURCES = /* @__PURE__ */ new WeakMap();
|
|
766
953
|
var ACTIVE_REFS = /* @__PURE__ */ new WeakMap();
|
|
767
954
|
var USAGE = /* @__PURE__ */ new WeakMap();
|
|
768
|
-
var
|
|
955
|
+
var TODO_STATES = /* @__PURE__ */ new WeakMap();
|
|
769
956
|
var HISTORIES = /* @__PURE__ */ new WeakMap();
|
|
770
957
|
var POPUP = /* @__PURE__ */ new WeakMap();
|
|
771
958
|
var SUBMITS = /* @__PURE__ */ new WeakMap();
|
|
959
|
+
var POPUP_SIZING = /* @__PURE__ */ new WeakMap();
|
|
772
960
|
function isBrowser() {
|
|
773
961
|
return typeof document !== "undefined" && typeof window !== "undefined";
|
|
774
962
|
}
|
|
775
|
-
function
|
|
776
|
-
target
|
|
963
|
+
function emit2(target, name, detail) {
|
|
964
|
+
emitIcen(target, name, detail);
|
|
777
965
|
}
|
|
778
|
-
function resolveComposer(
|
|
779
|
-
return
|
|
966
|
+
function resolveComposer(el) {
|
|
967
|
+
return el.closest("[data-ai-composer]");
|
|
780
968
|
}
|
|
781
969
|
function getTextarea(composer) {
|
|
782
970
|
return composer.querySelector(".ai-composer-input");
|
|
@@ -841,8 +1029,8 @@ function renderQueueChips(composer) {
|
|
|
841
1029
|
queueEl.replaceChildren(...queue.map((text, i) => makeChip(text, true, `\u79FB\u9664\u6392\u961F\u6D88\u606F ${i + 1}`)));
|
|
842
1030
|
queueEl.hidden = queue.length === 0;
|
|
843
1031
|
}
|
|
844
|
-
function setComposerRunning(
|
|
845
|
-
const composer = resolveComposer(
|
|
1032
|
+
function setComposerRunning(el, running) {
|
|
1033
|
+
const composer = resolveComposer(el);
|
|
846
1034
|
if (!composer) return;
|
|
847
1035
|
RUNNING.set(composer, running);
|
|
848
1036
|
composer.classList.toggle("is-running", running);
|
|
@@ -1006,6 +1194,13 @@ function settlePopup(s) {
|
|
|
1006
1194
|
s.emptyEl.hidden = visibleOptions(s).length > 0;
|
|
1007
1195
|
setPopupFocus(s, 0);
|
|
1008
1196
|
}
|
|
1197
|
+
function filterPopupOptions(s, q) {
|
|
1198
|
+
const needle = q.trim().toLowerCase();
|
|
1199
|
+
for (const opt of s.options) {
|
|
1200
|
+
opt.hidden = needle !== "" && !(opt.dataset.hay ?? "").includes(needle);
|
|
1201
|
+
}
|
|
1202
|
+
settlePopup(s);
|
|
1203
|
+
}
|
|
1009
1204
|
function popupKeydown(composer, s, e) {
|
|
1010
1205
|
if (e.isComposing) return;
|
|
1011
1206
|
switch (e.key) {
|
|
@@ -1045,13 +1240,16 @@ function closePopup(composer, restoreFocus = true) {
|
|
|
1045
1240
|
}
|
|
1046
1241
|
if (s.mode === "model") {
|
|
1047
1242
|
composer.querySelector("[data-ai-model-open]")?.setAttribute("aria-expanded", "false");
|
|
1048
|
-
}
|
|
1049
|
-
if (s.mode !== "model") {
|
|
1243
|
+
} else {
|
|
1050
1244
|
getTextarea(composer)?.setAttribute("aria-expanded", "false");
|
|
1051
1245
|
}
|
|
1052
1246
|
closePopover(s.panel);
|
|
1053
1247
|
if (restoreFocus && s.returnFocus && s.returnFocus.isConnected) s.returnFocus.focus();
|
|
1054
1248
|
}
|
|
1249
|
+
function resolvePopupSizing(composer, defaults) {
|
|
1250
|
+
const explicit = resolvePanelSizing(composer, POPUP_SIZING.get(composer));
|
|
1251
|
+
return { ...defaults, ...explicit };
|
|
1252
|
+
}
|
|
1055
1253
|
function mountPopup(composer, init) {
|
|
1056
1254
|
closePopup(composer, false);
|
|
1057
1255
|
const panel = document.createElement("div");
|
|
@@ -1076,9 +1274,7 @@ function mountPopup(composer, init) {
|
|
|
1076
1274
|
side: "top",
|
|
1077
1275
|
align: "start",
|
|
1078
1276
|
offset: 8,
|
|
1079
|
-
|
|
1080
|
-
maxWidth: init.maxWidth,
|
|
1081
|
-
maxHeight: init.maxHeight,
|
|
1277
|
+
sizing: resolvePopupSizing(composer, init.sizing),
|
|
1082
1278
|
onClose: () => {
|
|
1083
1279
|
if (POPUP.get(composer) === session) POPUP.delete(composer);
|
|
1084
1280
|
panel.remove();
|
|
@@ -1101,6 +1297,16 @@ function mountPopup(composer, init) {
|
|
|
1101
1297
|
});
|
|
1102
1298
|
return session;
|
|
1103
1299
|
}
|
|
1300
|
+
function appendPopupEmpty(s, text) {
|
|
1301
|
+
s.emptyEl.className = "ai-composer-popup-empty";
|
|
1302
|
+
s.emptyEl.textContent = text;
|
|
1303
|
+
s.emptyEl.hidden = true;
|
|
1304
|
+
s.panel.appendChild(s.emptyEl);
|
|
1305
|
+
}
|
|
1306
|
+
function popupSizingFor(box) {
|
|
1307
|
+
const w = box.getBoundingClientRect().width;
|
|
1308
|
+
return { minWidth: Math.min(Math.max(w, 200), 320), maxWidth: 360, maxHeight: 320 };
|
|
1309
|
+
}
|
|
1104
1310
|
function openModelPopup(composer) {
|
|
1105
1311
|
const cfg = MODELS.get(composer);
|
|
1106
1312
|
if (!cfg) return;
|
|
@@ -1110,9 +1316,7 @@ function openModelPopup(composer) {
|
|
|
1110
1316
|
const session = mountPopup(composer, {
|
|
1111
1317
|
mode: "model",
|
|
1112
1318
|
anchor,
|
|
1113
|
-
minWidth: 220,
|
|
1114
|
-
maxWidth: 320,
|
|
1115
|
-
maxHeight: 340,
|
|
1319
|
+
sizing: { minWidth: 220, maxWidth: 320, maxHeight: 340 },
|
|
1116
1320
|
returnFocus: btn ?? ta,
|
|
1117
1321
|
pick: (opt) => {
|
|
1118
1322
|
const provider = opt.dataset.provider ?? "";
|
|
@@ -1126,7 +1330,7 @@ function openModelPopup(composer) {
|
|
|
1126
1330
|
MODEL_CTX.delete(composer);
|
|
1127
1331
|
}
|
|
1128
1332
|
updateModelButton(composer);
|
|
1129
|
-
|
|
1333
|
+
emit2(composer, "icen:ai-model-change", { provider, model, label, context });
|
|
1130
1334
|
refreshUsageRing(composer);
|
|
1131
1335
|
closePopup(composer);
|
|
1132
1336
|
},
|
|
@@ -1164,6 +1368,7 @@ function openModelPopup(composer) {
|
|
|
1164
1368
|
opt.dataset.providerLabel = p.label;
|
|
1165
1369
|
opt.dataset.model = m.id;
|
|
1166
1370
|
opt.dataset.label = m.label;
|
|
1371
|
+
opt.dataset.hay = `${m.label} ${p.label}`.toLowerCase();
|
|
1167
1372
|
if (typeof m.context === "number") opt.dataset.context = String(m.context);
|
|
1168
1373
|
const selected = cfg.current.provider === p.id && cfg.current.model === m.id;
|
|
1169
1374
|
opt.setAttribute("aria-selected", String(selected));
|
|
@@ -1188,10 +1393,7 @@ function openModelPopup(composer) {
|
|
|
1188
1393
|
s.groups.push(group);
|
|
1189
1394
|
}
|
|
1190
1395
|
s.panel.appendChild(list);
|
|
1191
|
-
s
|
|
1192
|
-
s.emptyEl.textContent = "\u65E0\u5339\u914D\u6A21\u578B";
|
|
1193
|
-
s.emptyEl.hidden = true;
|
|
1194
|
-
s.panel.appendChild(s.emptyEl);
|
|
1396
|
+
appendPopupEmpty(s, "\u65E0\u5339\u914D\u6A21\u578B");
|
|
1195
1397
|
const foot = document.createElement("div");
|
|
1196
1398
|
foot.className = "ai-composer-popup-foot";
|
|
1197
1399
|
const usageCfg = USAGE.get(composer);
|
|
@@ -1211,12 +1413,7 @@ function openModelPopup(composer) {
|
|
|
1211
1413
|
s.keydownHandler = (e) => popupKeydown(composer, s, e);
|
|
1212
1414
|
input.addEventListener("keydown", s.keydownHandler);
|
|
1213
1415
|
input.addEventListener("input", () => {
|
|
1214
|
-
|
|
1215
|
-
for (const opt of s.options) {
|
|
1216
|
-
const hay = `${opt.dataset.label ?? ""} ${opt.dataset.providerLabel ?? ""}`.toLowerCase();
|
|
1217
|
-
opt.hidden = q !== "" && !hay.includes(q);
|
|
1218
|
-
}
|
|
1219
|
-
settlePopup(s);
|
|
1416
|
+
filterPopupOptions(s, input.value);
|
|
1220
1417
|
});
|
|
1221
1418
|
}
|
|
1222
1419
|
});
|
|
@@ -1228,13 +1425,10 @@ function openCommandPopup(composer, token) {
|
|
|
1228
1425
|
if (!commands || commands.length === 0) return;
|
|
1229
1426
|
const box = composer.querySelector(".ai-composer-box") ?? composer;
|
|
1230
1427
|
const ta = getTextarea(composer);
|
|
1231
|
-
const boxRect = box.getBoundingClientRect();
|
|
1232
1428
|
const session = mountPopup(composer, {
|
|
1233
1429
|
mode: "command",
|
|
1234
1430
|
anchor: box,
|
|
1235
|
-
|
|
1236
|
-
maxWidth: 360,
|
|
1237
|
-
maxHeight: 320,
|
|
1431
|
+
sizing: popupSizingFor(box),
|
|
1238
1432
|
returnFocus: ta,
|
|
1239
1433
|
pick: (opt) => {
|
|
1240
1434
|
const name = opt.dataset.name ?? "";
|
|
@@ -1244,7 +1438,7 @@ function openCommandPopup(composer, token) {
|
|
|
1244
1438
|
ta.value = "";
|
|
1245
1439
|
autosizeTa(ta);
|
|
1246
1440
|
}
|
|
1247
|
-
|
|
1441
|
+
emit2(composer, "icen:ai-command", { name, args });
|
|
1248
1442
|
closePopup(composer);
|
|
1249
1443
|
},
|
|
1250
1444
|
build: (s) => {
|
|
@@ -1286,25 +1480,15 @@ function openCommandPopup(composer, token) {
|
|
|
1286
1480
|
list.appendChild(group);
|
|
1287
1481
|
s.groups.push(group);
|
|
1288
1482
|
s.panel.appendChild(list);
|
|
1289
|
-
s
|
|
1290
|
-
s.emptyEl.textContent = "\u65E0\u5339\u914D\u547D\u4EE4";
|
|
1291
|
-
s.emptyEl.hidden = true;
|
|
1292
|
-
s.panel.appendChild(s.emptyEl);
|
|
1483
|
+
appendPopupEmpty(s, "\u65E0\u5339\u914D\u547D\u4EE4");
|
|
1293
1484
|
}
|
|
1294
1485
|
});
|
|
1295
1486
|
ta?.setAttribute("aria-expanded", "true");
|
|
1296
|
-
|
|
1487
|
+
filterPopupOptions(session, token);
|
|
1297
1488
|
}
|
|
1298
1489
|
function commandToken(value) {
|
|
1299
1490
|
return value.slice(1).split(/\s/, 1)[0] ?? "";
|
|
1300
1491
|
}
|
|
1301
|
-
function filterCommandOptions(s, token) {
|
|
1302
|
-
const q = token.trim().toLowerCase();
|
|
1303
|
-
for (const opt of s.options) {
|
|
1304
|
-
opt.hidden = q !== "" && !(opt.dataset.hay ?? "").includes(q);
|
|
1305
|
-
}
|
|
1306
|
-
settlePopup(s);
|
|
1307
|
-
}
|
|
1308
1492
|
function updateCommandPopup(composer, s) {
|
|
1309
1493
|
const ta = getTextarea(composer);
|
|
1310
1494
|
const value = ta?.value ?? "";
|
|
@@ -1313,20 +1497,17 @@ function updateCommandPopup(composer, s) {
|
|
|
1313
1497
|
maybeOpenTriggerPopups(composer);
|
|
1314
1498
|
return;
|
|
1315
1499
|
}
|
|
1316
|
-
|
|
1500
|
+
filterPopupOptions(s, commandToken(value));
|
|
1317
1501
|
}
|
|
1318
1502
|
function openRefPopup(composer, range, filter) {
|
|
1319
1503
|
const sources = REF_SOURCES.get(composer);
|
|
1320
1504
|
if (!sources || sources.length === 0) return;
|
|
1321
1505
|
const box = composer.querySelector(".ai-composer-box") ?? composer;
|
|
1322
1506
|
const ta = getTextarea(composer);
|
|
1323
|
-
const boxRect = box.getBoundingClientRect();
|
|
1324
1507
|
const session = mountPopup(composer, {
|
|
1325
1508
|
mode: "ref",
|
|
1326
1509
|
anchor: box,
|
|
1327
|
-
|
|
1328
|
-
maxWidth: 360,
|
|
1329
|
-
maxHeight: 320,
|
|
1510
|
+
sizing: popupSizingFor(box),
|
|
1330
1511
|
returnFocus: ta,
|
|
1331
1512
|
refRange: range,
|
|
1332
1513
|
pick: (opt) => {
|
|
@@ -1349,7 +1530,8 @@ function openRefPopup(composer, range, filter) {
|
|
|
1349
1530
|
list.className = "ai-composer-popup-list";
|
|
1350
1531
|
list.setAttribute("role", "listbox");
|
|
1351
1532
|
list.setAttribute("aria-label", "\u5F15\u7528");
|
|
1352
|
-
for (const kind of
|
|
1533
|
+
for (const kind of knownRefKinds(sources)) {
|
|
1534
|
+
const def = getRefKindDef(kind);
|
|
1353
1535
|
const items = sources.filter((r) => r.kind === kind);
|
|
1354
1536
|
if (items.length === 0) continue;
|
|
1355
1537
|
const group = document.createElement("div");
|
|
@@ -1357,7 +1539,7 @@ function openRefPopup(composer, range, filter) {
|
|
|
1357
1539
|
group.dataset.kind = kind;
|
|
1358
1540
|
group.appendChild(Object.assign(document.createElement("div"), {
|
|
1359
1541
|
className: "ai-composer-popup-group-label",
|
|
1360
|
-
textContent:
|
|
1542
|
+
textContent: def.label
|
|
1361
1543
|
}));
|
|
1362
1544
|
for (const r of items) {
|
|
1363
1545
|
const opt = document.createElement("button");
|
|
@@ -1368,7 +1550,7 @@ function openRefPopup(composer, range, filter) {
|
|
|
1368
1550
|
opt.dataset.hay = `${r.label} ${r.sub ?? ""}`.toLowerCase();
|
|
1369
1551
|
const icon = document.createElement("span");
|
|
1370
1552
|
icon.className = "ai-composer-popup-option-icon";
|
|
1371
|
-
const svg2 = svgIcon(
|
|
1553
|
+
const svg2 = svgIcon(def.icon);
|
|
1372
1554
|
if (svg2) icon.appendChild(svg2);
|
|
1373
1555
|
const label = document.createElement("span");
|
|
1374
1556
|
label.className = "ai-composer-popup-option-label";
|
|
@@ -1387,21 +1569,11 @@ function openRefPopup(composer, range, filter) {
|
|
|
1387
1569
|
s.groups.push(group);
|
|
1388
1570
|
}
|
|
1389
1571
|
s.panel.appendChild(list);
|
|
1390
|
-
s
|
|
1391
|
-
s.emptyEl.textContent = "\u65E0\u5339\u914D\u5F15\u7528";
|
|
1392
|
-
s.emptyEl.hidden = true;
|
|
1393
|
-
s.panel.appendChild(s.emptyEl);
|
|
1572
|
+
appendPopupEmpty(s, "\u65E0\u5339\u914D\u5F15\u7528");
|
|
1394
1573
|
}
|
|
1395
1574
|
});
|
|
1396
1575
|
ta?.setAttribute("aria-expanded", "true");
|
|
1397
|
-
|
|
1398
|
-
}
|
|
1399
|
-
function filterRefOptions(s, filter) {
|
|
1400
|
-
const q = filter.trim().toLowerCase();
|
|
1401
|
-
for (const opt of s.options) {
|
|
1402
|
-
opt.hidden = q !== "" && !(opt.dataset.hay ?? "").includes(q);
|
|
1403
|
-
}
|
|
1404
|
-
settlePopup(s);
|
|
1576
|
+
filterPopupOptions(session, filter);
|
|
1405
1577
|
}
|
|
1406
1578
|
function updateRefPopup(composer, s) {
|
|
1407
1579
|
const ta = getTextarea(composer);
|
|
@@ -1412,7 +1584,7 @@ function updateRefPopup(composer, s) {
|
|
|
1412
1584
|
return;
|
|
1413
1585
|
}
|
|
1414
1586
|
s.refRange = { start: t.start, end: t.end };
|
|
1415
|
-
|
|
1587
|
+
filterPopupOptions(s, t.filter);
|
|
1416
1588
|
}
|
|
1417
1589
|
function findRefToken(ta) {
|
|
1418
1590
|
const value = ta.value;
|
|
@@ -1469,7 +1641,7 @@ function addActiveRef(composer, source) {
|
|
|
1469
1641
|
actives.push(source);
|
|
1470
1642
|
ACTIVE_REFS.set(composer, actives);
|
|
1471
1643
|
renderRefs(composer);
|
|
1472
|
-
|
|
1644
|
+
emit2(composer, "icen:ai-ref", { action: "add", ref: source });
|
|
1473
1645
|
}
|
|
1474
1646
|
function removeActiveRef(composer, source) {
|
|
1475
1647
|
const actives = ACTIVE_REFS.get(composer) ?? [];
|
|
@@ -1489,24 +1661,24 @@ function removeActiveRef(composer, source) {
|
|
|
1489
1661
|
autosizeTa(ta);
|
|
1490
1662
|
}
|
|
1491
1663
|
}
|
|
1492
|
-
|
|
1664
|
+
emit2(composer, "icen:ai-ref", { action: "remove", ref: source });
|
|
1493
1665
|
}
|
|
1494
1666
|
function pushHistory(composer, text) {
|
|
1495
|
-
const
|
|
1496
|
-
if (
|
|
1497
|
-
|
|
1498
|
-
if (
|
|
1667
|
+
const h2 = HISTORIES.get(composer) ?? { items: [], index: -1 };
|
|
1668
|
+
if (h2.items[h2.items.length - 1] !== text) {
|
|
1669
|
+
h2.items.push(text);
|
|
1670
|
+
if (h2.items.length > HISTORY_LIMIT) h2.items.shift();
|
|
1499
1671
|
}
|
|
1500
|
-
|
|
1501
|
-
HISTORIES.set(composer,
|
|
1672
|
+
h2.index = -1;
|
|
1673
|
+
HISTORIES.set(composer, h2);
|
|
1502
1674
|
}
|
|
1503
1675
|
function setupComposer(composer) {
|
|
1504
|
-
const
|
|
1505
|
-
if (
|
|
1506
|
-
|
|
1676
|
+
const el = composer;
|
|
1677
|
+
if (el.__icenAiComposerInit) return void 0;
|
|
1678
|
+
el.__icenAiComposerInit = true;
|
|
1507
1679
|
const ta = getTextarea(composer);
|
|
1508
1680
|
if (!ta) {
|
|
1509
|
-
|
|
1681
|
+
el.__icenAiComposerInit = false;
|
|
1510
1682
|
return void 0;
|
|
1511
1683
|
}
|
|
1512
1684
|
const queueEl = composer.querySelector(".ai-composer-queue");
|
|
@@ -1530,10 +1702,10 @@ function setupComposer(composer) {
|
|
|
1530
1702
|
autosizeTa(ta);
|
|
1531
1703
|
if (isRunning()) {
|
|
1532
1704
|
enqueue(text);
|
|
1533
|
-
|
|
1705
|
+
emit2(composer, "icen:ai-queue", { text });
|
|
1534
1706
|
} else {
|
|
1535
1707
|
pushHistory(composer, text);
|
|
1536
|
-
|
|
1708
|
+
emit2(composer, "icen:ai-send", { text });
|
|
1537
1709
|
}
|
|
1538
1710
|
};
|
|
1539
1711
|
SUBMITS.set(composer, submit);
|
|
@@ -1541,28 +1713,28 @@ function setupComposer(composer) {
|
|
|
1541
1713
|
const queue = QUEUES.get(composer) ?? [];
|
|
1542
1714
|
if (queue.length === 0) return;
|
|
1543
1715
|
const index = queue.length - 1;
|
|
1544
|
-
const text = queue.pop();
|
|
1716
|
+
const text = queue.pop() ?? "";
|
|
1545
1717
|
QUEUES.set(composer, queue);
|
|
1546
1718
|
renderQueue();
|
|
1547
1719
|
ta.value = text;
|
|
1548
1720
|
autosizeTa(ta);
|
|
1549
|
-
|
|
1721
|
+
emit2(composer, "icen:ai-dequeue", { index });
|
|
1550
1722
|
};
|
|
1551
1723
|
const browseHistory = (delta) => {
|
|
1552
|
-
const
|
|
1553
|
-
if (!
|
|
1724
|
+
const h2 = HISTORIES.get(composer);
|
|
1725
|
+
if (!h2 || h2.items.length === 0) return;
|
|
1554
1726
|
if (delta === -1) {
|
|
1555
|
-
|
|
1727
|
+
h2.index = h2.index === -1 ? h2.items.length - 1 : Math.max(0, h2.index - 1);
|
|
1556
1728
|
} else {
|
|
1557
|
-
|
|
1558
|
-
if (
|
|
1559
|
-
|
|
1729
|
+
h2.index += 1;
|
|
1730
|
+
if (h2.index >= h2.items.length) {
|
|
1731
|
+
h2.index = -1;
|
|
1560
1732
|
ta.value = "";
|
|
1561
1733
|
autosizeTa(ta);
|
|
1562
1734
|
return;
|
|
1563
1735
|
}
|
|
1564
1736
|
}
|
|
1565
|
-
ta.value =
|
|
1737
|
+
ta.value = h2.items[h2.index] ?? "";
|
|
1566
1738
|
autosizeTa(ta);
|
|
1567
1739
|
};
|
|
1568
1740
|
const onKeydown = (e) => {
|
|
@@ -1578,15 +1750,15 @@ function setupComposer(composer) {
|
|
|
1578
1750
|
return;
|
|
1579
1751
|
}
|
|
1580
1752
|
if (e.key === "ArrowUp") {
|
|
1581
|
-
const
|
|
1582
|
-
const browsing = (
|
|
1753
|
+
const h2 = HISTORIES.get(composer);
|
|
1754
|
+
const browsing = (h2?.index ?? -1) >= 0;
|
|
1583
1755
|
if (ta.value === "") {
|
|
1584
1756
|
if (isRunning() && (QUEUES.get(composer) ?? []).length > 0) {
|
|
1585
1757
|
e.preventDefault();
|
|
1586
1758
|
takeBackLastQueued();
|
|
1587
1759
|
return;
|
|
1588
1760
|
}
|
|
1589
|
-
if (
|
|
1761
|
+
if (h2 && h2.items.length > 0) {
|
|
1590
1762
|
e.preventDefault();
|
|
1591
1763
|
browseHistory(-1);
|
|
1592
1764
|
}
|
|
@@ -1597,8 +1769,8 @@ function setupComposer(composer) {
|
|
|
1597
1769
|
return;
|
|
1598
1770
|
}
|
|
1599
1771
|
if (e.key === "ArrowDown") {
|
|
1600
|
-
const
|
|
1601
|
-
if (
|
|
1772
|
+
const h2 = HISTORIES.get(composer);
|
|
1773
|
+
if (h2 && h2.index >= 0) {
|
|
1602
1774
|
e.preventDefault();
|
|
1603
1775
|
browseHistory(1);
|
|
1604
1776
|
}
|
|
@@ -1606,8 +1778,8 @@ function setupComposer(composer) {
|
|
|
1606
1778
|
};
|
|
1607
1779
|
const onInput = () => {
|
|
1608
1780
|
autosizeTa(ta);
|
|
1609
|
-
const
|
|
1610
|
-
if (
|
|
1781
|
+
const h2 = HISTORIES.get(composer);
|
|
1782
|
+
if (h2 && h2.index >= 0 && ta.value !== h2.items[h2.index]) h2.index = -1;
|
|
1611
1783
|
const session = POPUP.get(composer);
|
|
1612
1784
|
if (session) {
|
|
1613
1785
|
if (session.mode === "command") updateCommandPopup(composer, session);
|
|
@@ -1625,7 +1797,7 @@ function setupComposer(composer) {
|
|
|
1625
1797
|
};
|
|
1626
1798
|
const onSendClick = () => {
|
|
1627
1799
|
if (isRunning()) {
|
|
1628
|
-
|
|
1800
|
+
emit2(composer, "icen:ai-stop", {});
|
|
1629
1801
|
} else {
|
|
1630
1802
|
submit();
|
|
1631
1803
|
}
|
|
@@ -1639,7 +1811,7 @@ function setupComposer(composer) {
|
|
|
1639
1811
|
queue.splice(index, 1);
|
|
1640
1812
|
QUEUES.set(composer, queue);
|
|
1641
1813
|
renderQueue();
|
|
1642
|
-
|
|
1814
|
+
emit2(composer, "icen:ai-dequeue", { index });
|
|
1643
1815
|
}
|
|
1644
1816
|
};
|
|
1645
1817
|
const onRefsClick = (e) => {
|
|
@@ -1668,7 +1840,7 @@ function setupComposer(composer) {
|
|
|
1668
1840
|
}
|
|
1669
1841
|
attachEl.hidden = false;
|
|
1670
1842
|
}
|
|
1671
|
-
|
|
1843
|
+
emit2(composer, "icen:ai-attach", { files });
|
|
1672
1844
|
};
|
|
1673
1845
|
const onFileChange = () => {
|
|
1674
1846
|
const files = Array.from(fileInput.files ?? []);
|
|
@@ -1735,7 +1907,7 @@ function setupComposer(composer) {
|
|
|
1735
1907
|
composer.querySelector("[data-ai-attach]")?.removeEventListener("click", onAttachClick);
|
|
1736
1908
|
fileInput.removeEventListener("change", onFileChange);
|
|
1737
1909
|
fileInput.remove();
|
|
1738
|
-
|
|
1910
|
+
el.__icenAiComposerInit = false;
|
|
1739
1911
|
};
|
|
1740
1912
|
}
|
|
1741
1913
|
function initAiComposer(root) {
|
|
@@ -1757,9 +1929,9 @@ function initAiComposer(root) {
|
|
|
1757
1929
|
cleanups.length = 0;
|
|
1758
1930
|
};
|
|
1759
1931
|
}
|
|
1760
|
-
function setComposerModels(
|
|
1932
|
+
function setComposerModels(el, providers, current) {
|
|
1761
1933
|
if (!isBrowser()) return;
|
|
1762
|
-
const composer = resolveComposer(
|
|
1934
|
+
const composer = resolveComposer(el);
|
|
1763
1935
|
if (!composer) return;
|
|
1764
1936
|
const list = (Array.isArray(providers) ? providers : []).filter(
|
|
1765
1937
|
(p) => p && Array.isArray(p.models) && p.models.length > 0
|
|
@@ -1786,9 +1958,9 @@ function setComposerModels(el3, providers, current) {
|
|
|
1786
1958
|
updateModelButton(composer);
|
|
1787
1959
|
refreshUsageRing(composer);
|
|
1788
1960
|
}
|
|
1789
|
-
function setComposerCommands(
|
|
1961
|
+
function setComposerCommands(el, commands) {
|
|
1790
1962
|
if (!isBrowser()) return;
|
|
1791
|
-
const composer = resolveComposer(
|
|
1963
|
+
const composer = resolveComposer(el);
|
|
1792
1964
|
if (!composer) return;
|
|
1793
1965
|
const list = (Array.isArray(commands) ? commands : []).filter((c) => c && typeof c.name === "string" && c.name);
|
|
1794
1966
|
if (list.length === 0) {
|
|
@@ -1799,9 +1971,9 @@ function setComposerCommands(el3, commands) {
|
|
|
1799
1971
|
}
|
|
1800
1972
|
COMMANDS.set(composer, list);
|
|
1801
1973
|
}
|
|
1802
|
-
function setComposerRefs(
|
|
1974
|
+
function setComposerRefs(el, sources) {
|
|
1803
1975
|
if (!isBrowser()) return;
|
|
1804
|
-
const composer = resolveComposer(
|
|
1976
|
+
const composer = resolveComposer(el);
|
|
1805
1977
|
if (!composer) return;
|
|
1806
1978
|
const list = (Array.isArray(sources) ? sources : []).filter((s) => s && typeof s.label === "string" && s.label);
|
|
1807
1979
|
REF_SOURCES.set(composer, list);
|
|
@@ -1812,9 +1984,9 @@ function setComposerRefs(el3, sources) {
|
|
|
1812
1984
|
ensureRefsRow(composer);
|
|
1813
1985
|
renderRefs(composer);
|
|
1814
1986
|
}
|
|
1815
|
-
function setComposerUsage(
|
|
1987
|
+
function setComposerUsage(el, usage, opts = {}) {
|
|
1816
1988
|
if (!isBrowser()) return;
|
|
1817
|
-
const composer = resolveComposer(
|
|
1989
|
+
const composer = resolveComposer(el);
|
|
1818
1990
|
if (!composer) return;
|
|
1819
1991
|
if (!usage) {
|
|
1820
1992
|
USAGE.delete(composer);
|
|
@@ -1827,24 +1999,24 @@ function setComposerUsage(el3, usage, opts = {}) {
|
|
|
1827
1999
|
syncToolbar(composer);
|
|
1828
2000
|
refreshUsageRing(composer);
|
|
1829
2001
|
}
|
|
1830
|
-
function setComposerTodo(
|
|
2002
|
+
function setComposerTodo(el, items) {
|
|
1831
2003
|
if (!isBrowser()) return;
|
|
1832
|
-
const composer = resolveComposer(
|
|
2004
|
+
const composer = resolveComposer(el);
|
|
1833
2005
|
if (!composer) return;
|
|
1834
2006
|
let chip = composer.querySelector(".ai-composer-todo");
|
|
1835
2007
|
if (!items || items.length === 0) {
|
|
1836
|
-
|
|
2008
|
+
TODO_STATES.delete(composer);
|
|
1837
2009
|
chip?.remove();
|
|
1838
2010
|
return;
|
|
1839
2011
|
}
|
|
1840
|
-
|
|
2012
|
+
TODO_STATES.set(composer, items);
|
|
1841
2013
|
if (!chip) {
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
const cur =
|
|
2014
|
+
const btn = document.createElement("button");
|
|
2015
|
+
btn.type = "button";
|
|
2016
|
+
btn.className = "ai-composer-todo";
|
|
2017
|
+
btn.setAttribute("aria-haspopup", "true");
|
|
2018
|
+
btn.addEventListener("click", () => {
|
|
2019
|
+
const cur = TODO_STATES.get(composer);
|
|
1848
2020
|
if (!cur) return;
|
|
1849
2021
|
const p = document.createElement("div");
|
|
1850
2022
|
p.className = "popover ai-composer-todo-pop";
|
|
@@ -1857,12 +2029,13 @@ function setComposerTodo(el3, items) {
|
|
|
1857
2029
|
renderAiTodo(body, cur);
|
|
1858
2030
|
p.append(title, body);
|
|
1859
2031
|
openPopover(p, {
|
|
1860
|
-
anchor:
|
|
2032
|
+
anchor: btn,
|
|
1861
2033
|
side: "top",
|
|
1862
2034
|
align: "end",
|
|
1863
2035
|
onClose: () => p.remove()
|
|
1864
2036
|
});
|
|
1865
2037
|
});
|
|
2038
|
+
chip = btn;
|
|
1866
2039
|
const icon = svgIcon(
|
|
1867
2040
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m3 17 2 2 4-4"/><path d="m3 7 2 2 4-4"/><path d="M13 6h8"/><path d="M13 12h8"/><path d="M13 18h8"/></svg>'
|
|
1868
2041
|
);
|
|
@@ -1885,21 +2058,14 @@ function setComposerTodo(el3, items) {
|
|
|
1885
2058
|
if (label) label.textContent = `${done}/${items.length}`;
|
|
1886
2059
|
}
|
|
1887
2060
|
var BOUND = /* @__PURE__ */ new WeakSet();
|
|
1888
|
-
|
|
1889
|
-
function accumulateUsage(acc, add) {
|
|
1890
|
-
if (!add) return;
|
|
1891
|
-
for (const k of USAGE_KEYS) {
|
|
1892
|
-
const v = add[k];
|
|
1893
|
-
if (typeof v === "number" && Number.isFinite(v)) acc[k] = (acc[k] ?? 0) + v;
|
|
1894
|
-
}
|
|
1895
|
-
}
|
|
1896
|
-
function bindComposer(el3, opts = {}) {
|
|
2061
|
+
function bindComposer(el, opts = {}) {
|
|
1897
2062
|
const noop = () => void 0;
|
|
1898
2063
|
if (!isBrowser()) return { unbind: noop };
|
|
1899
|
-
const composer = resolveComposer(
|
|
2064
|
+
const composer = resolveComposer(el);
|
|
1900
2065
|
if (!composer) return { unbind: noop };
|
|
1901
2066
|
if (BOUND.has(composer)) return { unbind: noop };
|
|
1902
2067
|
BOUND.add(composer);
|
|
2068
|
+
if (opts.popoverSizing) POPUP_SIZING.set(composer, opts.popoverSizing);
|
|
1903
2069
|
const disposers = [];
|
|
1904
2070
|
const usageCfg = opts.usage;
|
|
1905
2071
|
const manageRunning = opts.running ?? true;
|
|
@@ -1922,7 +2088,7 @@ function bindComposer(el3, opts = {}) {
|
|
|
1922
2088
|
total: contextEstimate(u)
|
|
1923
2089
|
};
|
|
1924
2090
|
} else if (usageCfg.from === "billing") {
|
|
1925
|
-
|
|
2091
|
+
billing = addUsage(billing, detail.usage);
|
|
1926
2092
|
usage = billing;
|
|
1927
2093
|
} else {
|
|
1928
2094
|
usage = usageCfg.from.summary();
|
|
@@ -1935,6 +2101,9 @@ function bindComposer(el3, opts = {}) {
|
|
|
1935
2101
|
document.addEventListener("icen:ai-done", onDone);
|
|
1936
2102
|
disposers.push(() => document.removeEventListener("icen:ai-done", onDone));
|
|
1937
2103
|
}
|
|
2104
|
+
if (opts.client && !opts.messages) {
|
|
2105
|
+
console.warn("[ai-composer] client \u6A21\u5F0F\u9700\u8981 opts.messages\uFF0C\u5DF2\u964D\u7EA7\u4E3A\u7EAF\u72B6\u6001\u7ED1\u5B9A");
|
|
2106
|
+
}
|
|
1938
2107
|
if (opts.client && opts.messages) {
|
|
1939
2108
|
const client = opts.client;
|
|
1940
2109
|
const messages = opts.messages;
|
|
@@ -1975,10 +2144,10 @@ function bindComposer(el3, opts = {}) {
|
|
|
1975
2144
|
setComposerRunning(composer, false);
|
|
1976
2145
|
const queue = QUEUES.get(composer) ?? [];
|
|
1977
2146
|
if (queue.length > 0) {
|
|
1978
|
-
const next = queue.shift();
|
|
2147
|
+
const next = queue.shift() ?? "";
|
|
1979
2148
|
QUEUES.set(composer, queue);
|
|
1980
2149
|
renderQueueChips(composer);
|
|
1981
|
-
|
|
2150
|
+
emit2(composer, "icen:ai-dequeue", { index: 0 });
|
|
1982
2151
|
send(next);
|
|
1983
2152
|
}
|
|
1984
2153
|
})();
|
|
@@ -2023,6 +2192,7 @@ function bindComposer(el3, opts = {}) {
|
|
|
2023
2192
|
export {
|
|
2024
2193
|
bindComposer,
|
|
2025
2194
|
initAiComposer,
|
|
2195
|
+
registerRefKind,
|
|
2026
2196
|
setComposerCommands,
|
|
2027
2197
|
setComposerModels,
|
|
2028
2198
|
setComposerRefs,
|