@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
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
// src/behaviors/ai-core.ts
|
|
2
|
+
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
|
+
var ICON_TERMINAL = svg('<path d="m4 17 6-6-6-6"/><path d="M12 19h8"/>');
|
|
4
|
+
var ICON_FILE = svg(
|
|
5
|
+
'<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/>'
|
|
6
|
+
);
|
|
7
|
+
var ICON_FILE_PEN = svg(
|
|
8
|
+
'<path d="M12.5 22H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8l5 5v3.5"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M19 6.5 16.5 4"/><path d="M21.378 16.626a1 1 0 0 0-3.004-3.004l-4.01 4.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z"/>'
|
|
9
|
+
);
|
|
10
|
+
var ICON_FILE_PLUS = svg(
|
|
11
|
+
'<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M9 15h6"/><path d="M12 12v6"/>'
|
|
12
|
+
);
|
|
13
|
+
var ICON_TRASH = svg(
|
|
14
|
+
'<path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M10 11v6"/><path d="M14 11v6"/>'
|
|
15
|
+
);
|
|
16
|
+
var ICON_SEARCH = svg('<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>');
|
|
17
|
+
var ICON_FOLDER_SEARCH = svg(
|
|
18
|
+
'<path d="M11 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v4"/><circle cx="17" cy="17" r="3"/><path d="m21 21-1.9-1.9"/>'
|
|
19
|
+
);
|
|
20
|
+
var ICON_SCAN_SEARCH = svg(
|
|
21
|
+
'<path d="M3 7V5a2 2 0 0 1 2-2h2"/><path d="M17 3h2a2 2 0 0 1 2 2v2"/><path d="M21 17v2a2 2 0 0 1-2 2h-2"/><path d="M7 21H5a2 2 0 0 1-2-2v-2"/><circle cx="12" cy="12" r="3"/><path d="m16 16-1.9-1.9"/>'
|
|
22
|
+
);
|
|
23
|
+
var ICON_GLOBE = svg(
|
|
24
|
+
'<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/>'
|
|
25
|
+
);
|
|
26
|
+
var ICON_DOWNLOAD = svg(
|
|
27
|
+
'<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/><path d="M12 15V3"/>'
|
|
28
|
+
);
|
|
29
|
+
var ICON_BLOCKS = svg(
|
|
30
|
+
'<rect width="7" height="7" x="4" y="4" rx="1"/><rect width="7" height="7" x="13" y="4" rx="1"/><rect width="7" height="7" x="4" y="13" rx="1"/><rect width="7" height="7" x="13" y="13" rx="1"/>'
|
|
31
|
+
);
|
|
32
|
+
var ICON_ZAP = svg(
|
|
33
|
+
'<path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/>'
|
|
34
|
+
);
|
|
35
|
+
var ICON_LIST = svg(
|
|
36
|
+
'<path d="M3 12h.01"/><path d="M3 18h.01"/><path d="M3 6h.01"/><path d="M8 12h13"/><path d="M8 18h13"/><path d="M8 6h13"/>'
|
|
37
|
+
);
|
|
38
|
+
var ICON_LIST_CHECKS = svg(
|
|
39
|
+
'<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"/>'
|
|
40
|
+
);
|
|
41
|
+
var ICON_BOT = svg(
|
|
42
|
+
'<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"/>'
|
|
43
|
+
);
|
|
44
|
+
var ICON_CHART = svg(
|
|
45
|
+
'<path d="M3 3v18h18"/><path d="M7 15l4-6 3 4 5-8"/>'
|
|
46
|
+
);
|
|
47
|
+
var ICON_FILE_TEXT = svg(
|
|
48
|
+
'<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/>'
|
|
49
|
+
);
|
|
50
|
+
function isObj(v) {
|
|
51
|
+
return typeof v === "object" && v !== null;
|
|
52
|
+
}
|
|
53
|
+
function pickStr(input, keys) {
|
|
54
|
+
if (!isObj(input)) return void 0;
|
|
55
|
+
for (const k of keys) {
|
|
56
|
+
const v = input[k];
|
|
57
|
+
if (typeof v === "string" && v) return v;
|
|
58
|
+
}
|
|
59
|
+
return void 0;
|
|
60
|
+
}
|
|
61
|
+
function pickNum(src, keys) {
|
|
62
|
+
if (!isObj(src)) return void 0;
|
|
63
|
+
for (const k of keys) {
|
|
64
|
+
const v = src[k];
|
|
65
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
66
|
+
}
|
|
67
|
+
return void 0;
|
|
68
|
+
}
|
|
69
|
+
function firstLine(s, max = 80) {
|
|
70
|
+
const line = s.split("\n", 1)[0]?.trim() ?? "";
|
|
71
|
+
return line.length > max ? `${line.slice(0, max)}\u2026` : line;
|
|
72
|
+
}
|
|
73
|
+
function filePathOf(input) {
|
|
74
|
+
return pickStr(input, ["file_path", "path", "file", "filename"]);
|
|
75
|
+
}
|
|
76
|
+
var summarizePath = (input) => filePathOf(input);
|
|
77
|
+
function summarizeRead(input) {
|
|
78
|
+
const p = filePathOf(input);
|
|
79
|
+
if (!p) return void 0;
|
|
80
|
+
const offset = pickNum(input, ["offset", "start_line"]);
|
|
81
|
+
if (offset == null) return p;
|
|
82
|
+
const limit = pickNum(input, ["limit", "end_line"]);
|
|
83
|
+
return limit != null ? `${p}:${offset}-${offset + limit}` : `${p}:${offset}`;
|
|
84
|
+
}
|
|
85
|
+
function summarizeShell(input) {
|
|
86
|
+
const cmd = typeof input === "string" ? input : pickStr(input, ["command", "cmd", "script"]);
|
|
87
|
+
return cmd ? firstLine(cmd) : void 0;
|
|
88
|
+
}
|
|
89
|
+
function summarizeGrep(input) {
|
|
90
|
+
const pattern = pickStr(input, ["pattern", "regex", "query"]);
|
|
91
|
+
const p = filePathOf(input);
|
|
92
|
+
if (pattern) return p ? `${firstLine(pattern, 40)} \xB7 ${p}` : firstLine(pattern);
|
|
93
|
+
return p;
|
|
94
|
+
}
|
|
95
|
+
var sum = (fn) => {
|
|
96
|
+
return (input) => fn(input) ?? "";
|
|
97
|
+
};
|
|
98
|
+
var BUILTIN_KINDS = {
|
|
99
|
+
shell: { label: "\u547D\u4EE4", icon: ICON_TERMINAL, tint: "accent", summarize: sum(summarizeShell) },
|
|
100
|
+
read: { label: "\u8BFB\u53D6", icon: ICON_FILE, tint: "info", summarize: sum(summarizeRead) },
|
|
101
|
+
edit: { label: "\u7F16\u8F91", icon: ICON_FILE_PEN, tint: "warning", summarize: sum(summarizePath) },
|
|
102
|
+
write: { label: "\u5199\u5165", icon: ICON_FILE_PLUS, tint: "warning", summarize: sum(summarizePath) },
|
|
103
|
+
rm: { label: "\u5220\u9664", icon: ICON_TRASH, tint: "error", summarize: sum(summarizePath) },
|
|
104
|
+
grep: { label: "\u641C\u7D22", icon: ICON_SEARCH, tint: "info", summarize: sum(summarizeGrep) },
|
|
105
|
+
glob: { label: "\u5339\u914D", icon: ICON_FOLDER_SEARCH, tint: "info", summarize: sum((i) => pickStr(i, ["pattern", "glob", "path"])) },
|
|
106
|
+
browser: { label: "\u6D4F\u89C8", icon: ICON_GLOBE, tint: "accent", summarize: sum((i) => pickStr(i, ["url", "uri", "target"])) },
|
|
107
|
+
search: { label: "\u68C0\u7D22", icon: ICON_SCAN_SEARCH, tint: "accent", summarize: sum((i) => pickStr(i, ["query", "q", "pattern"])) },
|
|
108
|
+
fetch: { label: "\u8BF7\u6C42", icon: ICON_DOWNLOAD, tint: "info", summarize: sum((i) => pickStr(i, ["url", "uri", "endpoint"])) },
|
|
109
|
+
mcp: { label: "MCP", icon: ICON_BLOCKS, tint: "muted", summarize: sum((i) => pickStr(i, ["tool", "method", "name"])) },
|
|
110
|
+
skill: { label: "\u6280\u80FD", icon: ICON_ZAP, tint: "accent", summarize: sum((i) => pickStr(i, ["skill", "name", "command"])) },
|
|
111
|
+
todo: {
|
|
112
|
+
label: "\u5F85\u529E",
|
|
113
|
+
icon: ICON_LIST,
|
|
114
|
+
tint: "info",
|
|
115
|
+
summarize: sum((input) => {
|
|
116
|
+
const items = input && typeof input === "object" && Array.isArray(input.items) ? input.items : Array.isArray(input) ? input : [];
|
|
117
|
+
const done = items.filter((it) => it?.status === "done").length;
|
|
118
|
+
return items.length > 0 ? `${done}/${items.length} \u5B8C\u6210` : "";
|
|
119
|
+
})
|
|
120
|
+
},
|
|
121
|
+
plan: { label: "\u8BA1\u5212", icon: ICON_LIST_CHECKS, tint: "info" },
|
|
122
|
+
subagent: { label: "\u5B50\u4EE3\u7406", icon: ICON_BOT, tint: "accent", summarize: sum((i) => pickStr(i, ["task", "description", "prompt", "message", "subagent_type"])) },
|
|
123
|
+
note: { label: "\u7B14\u8BB0", icon: ICON_FILE_TEXT, tint: "muted" },
|
|
124
|
+
chart: { label: "\u56FE\u8868", icon: ICON_CHART, tint: "info", summarize: sum((i) => pickStr(i, ["title", "name"])) }
|
|
125
|
+
};
|
|
126
|
+
var kindRegistry = new Map(Object.entries(BUILTIN_KINDS));
|
|
127
|
+
function h(tag, className, text) {
|
|
128
|
+
const node = document.createElement(tag);
|
|
129
|
+
if (className) node.className = className;
|
|
130
|
+
if (text != null) node.textContent = text;
|
|
131
|
+
return node;
|
|
132
|
+
}
|
|
133
|
+
function svgIcon(svg2) {
|
|
134
|
+
if (typeof document === "undefined" || typeof DOMParser === "undefined") return null;
|
|
135
|
+
let parsed;
|
|
136
|
+
try {
|
|
137
|
+
parsed = new DOMParser().parseFromString(svg2, "image/svg+xml");
|
|
138
|
+
} catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
const root = parsed.documentElement;
|
|
142
|
+
if (!root || root.tagName.toLowerCase() !== "svg" || parsed.querySelector("parsererror")) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
const sanitize = (el) => {
|
|
146
|
+
for (const attr of Array.from(el.attributes)) {
|
|
147
|
+
const name = attr.name.toLowerCase();
|
|
148
|
+
if (name.startsWith("on")) el.removeAttribute(attr.name);
|
|
149
|
+
if ((name === "href" || name === "xlink:href") && attr.value.trim().toLowerCase().startsWith("javascript:")) {
|
|
150
|
+
el.removeAttribute(attr.name);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
for (const child of Array.from(el.children)) {
|
|
154
|
+
const tag = child.tagName.toLowerCase();
|
|
155
|
+
if (tag === "script" || tag === "foreignobject") {
|
|
156
|
+
child.remove();
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
sanitize(child);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
sanitize(root);
|
|
163
|
+
return document.importNode(root, true);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/behaviors/kb-core.ts
|
|
167
|
+
var ic = (label, d) => ({ label, icon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">${d}</svg>` });
|
|
168
|
+
var BUILTIN_SOURCE_TYPES = {
|
|
169
|
+
doc: ic("\u6587\u6863", '<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"/>'),
|
|
170
|
+
web: ic("\u7F51\u9875", '<circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15 15 0 0 1 0 20 15 15 0 0 1 0-20z"/>'),
|
|
171
|
+
wiki: ic("\u77E5\u8BC6\u5E93", '<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/>'),
|
|
172
|
+
sheet: ic("\u8868\u683C", '<rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M3 15h18M9 3v18M15 3v18"/>'),
|
|
173
|
+
db: ic("\u6570\u636E\u5E93", '<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14c0 1.7 4 3 9 3s9-1.3 9-3V5"/><path d="M3 12c0 1.7 4 3 9 3s9-1.3 9-3"/>'),
|
|
174
|
+
ticket: ic("\u5DE5\u5355", '<path d="M3 9V7a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v2a2 2 0 0 0 0 6v2a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2a2 2 0 0 0 0-6z"/><path d="M13 5v14"/>'),
|
|
175
|
+
code: ic("\u4EE3\u7801", '<path d="m16 18 6-6-6-6"/><path d="m8 6-6 6 6 6"/>'),
|
|
176
|
+
api: ic("\u63A5\u53E3", '<path d="M4 7a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3a2 2 0 0 0 0 4v3a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-3a2 2 0 0 0 0-4z"/>'),
|
|
177
|
+
image: ic("\u56FE\u7247", '<rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-4.6-4.6a2 2 0 0 0-2.8 0L3 21"/>'),
|
|
178
|
+
mail: ic("\u90AE\u4EF6", '<rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-10 7L2 7"/>')
|
|
179
|
+
};
|
|
180
|
+
var sourceTypeRegistry = new Map(Object.entries(BUILTIN_SOURCE_TYPES));
|
|
181
|
+
var LOWER_IS_BETTER = /* @__PURE__ */ new Set(["l2"]);
|
|
182
|
+
function scoreHigherIsBetter(kind) {
|
|
183
|
+
return kind != null && LOWER_IS_BETTER.has(kind) ? false : true;
|
|
184
|
+
}
|
|
185
|
+
function formatScore(v, digits = 3) {
|
|
186
|
+
if (v == null || !Number.isFinite(v)) return "\u2014";
|
|
187
|
+
return v.toFixed(digits).replace(/\.?0+$/, (s) => s.includes(".") ? "" : s);
|
|
188
|
+
}
|
|
189
|
+
function scorePercent(v, kind, max = 1) {
|
|
190
|
+
if (v == null || !Number.isFinite(v)) return null;
|
|
191
|
+
const pct = scoreHigherIsBetter(kind) ? v / max * 100 : (1 - v / max) * 100;
|
|
192
|
+
return Math.max(0, Math.min(100, pct));
|
|
193
|
+
}
|
|
194
|
+
function normalizeHit(raw) {
|
|
195
|
+
const score = typeof raw.score === "number" && Number.isFinite(raw.score) ? raw.score : null;
|
|
196
|
+
return {
|
|
197
|
+
chunkId: String(raw.chunkId ?? raw.id ?? ""),
|
|
198
|
+
documentId: typeof raw.documentId === "string" ? raw.documentId : void 0,
|
|
199
|
+
title: typeof raw.title === "string" ? raw.title : void 0,
|
|
200
|
+
snippet: String(raw.snippet ?? raw.content ?? ""),
|
|
201
|
+
score,
|
|
202
|
+
scoreKind: raw.scoreKind,
|
|
203
|
+
vectorPart: typeof raw.vectorPart === "number" ? raw.vectorPart : void 0,
|
|
204
|
+
keywordPart: typeof raw.keywordPart === "number" ? raw.keywordPart : void 0,
|
|
205
|
+
explain: typeof raw.explain === "string" ? raw.explain : void 0,
|
|
206
|
+
page: typeof raw.page === "number" ? raw.page : void 0,
|
|
207
|
+
meta: raw.meta && typeof raw.meta === "object" ? raw.meta : void 0
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function normalizeRetrievalParams(raw) {
|
|
211
|
+
const r = raw ?? {};
|
|
212
|
+
return {
|
|
213
|
+
topK: typeof r.topK === "number" && r.topK > 0 ? Math.floor(r.topK) : 5,
|
|
214
|
+
mode: r.mode === "vector" || r.mode === "keyword" || r.mode === "hybrid" ? r.mode : "hybrid",
|
|
215
|
+
alpha: typeof r.alpha === "number" ? Math.max(0, Math.min(1, r.alpha)) : 0.5,
|
|
216
|
+
rerank: r.rerank === true,
|
|
217
|
+
rerankModel: typeof r.rerankModel === "string" ? r.rerankModel : void 0,
|
|
218
|
+
threshold: typeof r.threshold === "number" ? r.threshold : null
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function kbVisibilityLabel(v) {
|
|
222
|
+
return v === "hidden" ? "\u4E0D\u53EF\u89C1" : v === "metadata" ? "\u4EC5\u5143\u6570\u636E" : v === "restricted" ? "\u53D7\u9650" : v === "summary" ? "\u4EC5\u6458\u8981" : "\u53EF\u89C1";
|
|
223
|
+
}
|
|
224
|
+
function normalizeIdentity(raw) {
|
|
225
|
+
const r = raw;
|
|
226
|
+
return {
|
|
227
|
+
user: String(r.user ?? ""),
|
|
228
|
+
groups: Array.isArray(r.groups) ? r.groups.map(String) : [],
|
|
229
|
+
label: typeof r.label === "string" ? r.label : void 0,
|
|
230
|
+
note: typeof r.note === "string" ? r.note : void 0
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// src/behaviors/events.ts
|
|
235
|
+
function emitIcen(source, type, detail) {
|
|
236
|
+
return source.dispatchEvent(
|
|
237
|
+
new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable: true })
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// src/behaviors/kb-retrieval.ts
|
|
242
|
+
var MODES = [
|
|
243
|
+
["vector", "\u5411\u91CF"],
|
|
244
|
+
["keyword", "\u5173\u952E\u8BCD"],
|
|
245
|
+
["hybrid", "\u6DF7\u5408"]
|
|
246
|
+
];
|
|
247
|
+
var TOP_K_MIN = 1;
|
|
248
|
+
var TOP_K_MAX = 50;
|
|
249
|
+
var HIGHLIGHT_TERM_LIMIT = 6;
|
|
250
|
+
var ICON_RUN = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 4 14 8-14 8z"/></svg>';
|
|
251
|
+
var ICON_COPY = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';
|
|
252
|
+
var LAYER_ORDER = ["pre", "post", "none"];
|
|
253
|
+
var LAYER_LABEL = { pre: "pre \u2713", post: "post \u26A0", none: "none \u2715" };
|
|
254
|
+
var LAYER_TITLE = {
|
|
255
|
+
pre: "pre-filter\uFF1AACL \u5728\u68C0\u7D22\u6267\u884C\u4F53\u5185\u751F\u6548\u2014\u2014\u5B89\u5168\u57FA\u7EBF",
|
|
256
|
+
post: "post-filter\uFF1A\u5206\u6570\u5DF2\u53EF\u89C2\u5BDF\u2014\u2014\u7F3A\u9677\u5C42\uFF0C\u4EC5\u6F14\u793A",
|
|
257
|
+
none: "none\uFF1Afail-open\uFF0C\u65E0\u8EAB\u4EFD\u8FC7\u6EE4\u8FD4\u56DE\u5168\u90E8\u2014\u2014\u5371\u9669\uFF0C\u4EC5\u6F14\u793A"
|
|
258
|
+
};
|
|
259
|
+
var stubHandle = () => ({
|
|
260
|
+
getParams: () => normalizeRetrievalParams(),
|
|
261
|
+
setParams: () => {
|
|
262
|
+
},
|
|
263
|
+
renderHits: () => {
|
|
264
|
+
},
|
|
265
|
+
setBusy: () => {
|
|
266
|
+
},
|
|
267
|
+
setThreshold: () => {
|
|
268
|
+
},
|
|
269
|
+
getFilterLayer: () => "pre",
|
|
270
|
+
setFilterLayer: () => {
|
|
271
|
+
},
|
|
272
|
+
destroy: () => {
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
function escapeRe(s) {
|
|
276
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
277
|
+
}
|
|
278
|
+
function tokenizeQuery(query) {
|
|
279
|
+
const seen = /* @__PURE__ */ new Set();
|
|
280
|
+
const out = [];
|
|
281
|
+
for (const raw of query.trim().split(/\s+/)) {
|
|
282
|
+
const t = raw.trim();
|
|
283
|
+
if (!t || seen.has(t)) continue;
|
|
284
|
+
if (t.length < 2 && !/[\u4e00-\u9fff]/.test(t)) continue;
|
|
285
|
+
seen.add(t);
|
|
286
|
+
out.push(t);
|
|
287
|
+
if (out.length >= HIGHLIGHT_TERM_LIMIT) break;
|
|
288
|
+
}
|
|
289
|
+
return out;
|
|
290
|
+
}
|
|
291
|
+
function highlightTerms(text, terms) {
|
|
292
|
+
let nodes = [document.createTextNode(text)];
|
|
293
|
+
for (let ti = 0; ti < terms.length; ti++) {
|
|
294
|
+
const re = new RegExp(escapeRe(terms[ti]), "gi");
|
|
295
|
+
const next = [];
|
|
296
|
+
for (const node of nodes) {
|
|
297
|
+
if (!(node instanceof Text)) {
|
|
298
|
+
next.push(node);
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
const seg = node.data;
|
|
302
|
+
let last = 0;
|
|
303
|
+
let m;
|
|
304
|
+
re.lastIndex = 0;
|
|
305
|
+
while ((m = re.exec(seg)) !== null) {
|
|
306
|
+
if (m[0].length === 0) {
|
|
307
|
+
re.lastIndex++;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (m.index > last) next.push(document.createTextNode(seg.slice(last, m.index)));
|
|
311
|
+
const mark = document.createElement("mark");
|
|
312
|
+
mark.dataset.hit = String(ti % 3);
|
|
313
|
+
mark.textContent = m[0];
|
|
314
|
+
next.push(mark);
|
|
315
|
+
last = m.index + m[0].length;
|
|
316
|
+
}
|
|
317
|
+
if (last < seg.length) next.push(document.createTextNode(seg.slice(last)));
|
|
318
|
+
}
|
|
319
|
+
nodes = next;
|
|
320
|
+
}
|
|
321
|
+
return nodes;
|
|
322
|
+
}
|
|
323
|
+
function copyText(text) {
|
|
324
|
+
try {
|
|
325
|
+
if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
|
|
326
|
+
void navigator.clipboard.writeText(text);
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
if (typeof document === "undefined") return false;
|
|
330
|
+
const ta = document.createElement("textarea");
|
|
331
|
+
ta.value = text;
|
|
332
|
+
ta.setAttribute("readonly", "");
|
|
333
|
+
ta.style.position = "fixed";
|
|
334
|
+
ta.style.opacity = "0";
|
|
335
|
+
document.body.appendChild(ta);
|
|
336
|
+
ta.select();
|
|
337
|
+
const ok = document.execCommand("copy");
|
|
338
|
+
ta.remove();
|
|
339
|
+
return ok;
|
|
340
|
+
} catch {
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
function createKbRetrieval(el, opts = {}) {
|
|
345
|
+
if (typeof document === "undefined" || !el) return stubHandle();
|
|
346
|
+
const marked = el;
|
|
347
|
+
if (marked.__icenKbRetrieval) return marked.__icenKbRetrieval;
|
|
348
|
+
const ctrl = new AbortController();
|
|
349
|
+
const listen = (target, type, fn, options) => {
|
|
350
|
+
target.addEventListener(type, fn, { ...options, signal: ctrl.signal });
|
|
351
|
+
};
|
|
352
|
+
let params = normalizeRetrievalParams(opts.params);
|
|
353
|
+
const thresholdMax = typeof opts.thresholdMax === "number" && opts.thresholdMax > 0 ? opts.thresholdMax : 1;
|
|
354
|
+
let hits = [];
|
|
355
|
+
let busy = false;
|
|
356
|
+
let destroyed = false;
|
|
357
|
+
let thresholdValue = params.threshold ?? 0;
|
|
358
|
+
let copyTimer = null;
|
|
359
|
+
let layer = opts.layer === "post" || opts.layer === "none" ? opts.layer : "pre";
|
|
360
|
+
const idnList = (Array.isArray(opts.identities) ? opts.identities : []).map(normalizeIdentity).filter((i) => i.user || i.label);
|
|
361
|
+
const adminAcl = opts.admin === true && typeof opts.aclOf === "function" ? opts.aclOf : null;
|
|
362
|
+
el.classList.add("kb-retrieval");
|
|
363
|
+
el.dataset.kbRetrieval = "";
|
|
364
|
+
el.textContent = "";
|
|
365
|
+
const bar = h("div", "kb-retrieval-bar");
|
|
366
|
+
const queryInput = h("input", "kb-retrieval-query");
|
|
367
|
+
queryInput.type = "text";
|
|
368
|
+
queryInput.placeholder = "\u68C0\u7D22\u95EE\u9898\uFF0CEnter \u8FD0\u884C";
|
|
369
|
+
queryInput.setAttribute("aria-label", "\u68C0\u7D22\u95EE\u9898");
|
|
370
|
+
const modes = h("div", "kb-modes");
|
|
371
|
+
modes.role = "radiogroup";
|
|
372
|
+
modes.setAttribute("aria-label", "\u68C0\u7D22\u6A21\u5F0F");
|
|
373
|
+
const modeButtons = /* @__PURE__ */ new Map();
|
|
374
|
+
for (const [mode, label] of MODES) {
|
|
375
|
+
const btn = h("button", "kb-mode-item", label);
|
|
376
|
+
btn.type = "button";
|
|
377
|
+
btn.dataset.mode = mode;
|
|
378
|
+
btn.role = "radio";
|
|
379
|
+
modes.appendChild(btn);
|
|
380
|
+
modeButtons.set(mode, btn);
|
|
381
|
+
}
|
|
382
|
+
const topKDown = h("button", "kb-step-btn", "\u2212");
|
|
383
|
+
topKDown.type = "button";
|
|
384
|
+
topKDown.dataset.step = "-1";
|
|
385
|
+
topKDown.setAttribute("aria-label", "\u51CF\u5C11 topK");
|
|
386
|
+
const topKValue = h("span", "kb-step-value kb-num");
|
|
387
|
+
const topKUp = h("button", "kb-step-btn", "+");
|
|
388
|
+
topKUp.type = "button";
|
|
389
|
+
topKUp.dataset.step = "1";
|
|
390
|
+
topKUp.setAttribute("aria-label", "\u589E\u52A0 topK");
|
|
391
|
+
const step = h("div", "kb-step");
|
|
392
|
+
step.append(topKDown, topKValue, topKUp);
|
|
393
|
+
const stepLabel = h("span", "kb-step-label kb-meta", "topK");
|
|
394
|
+
step.setAttribute("aria-label", "topK");
|
|
395
|
+
const alphaEndL = h("span", "kb-alpha-end", "\u8BED\u4E49");
|
|
396
|
+
alphaEndL.title = "\u8BED\u4E49\uFF1A\u8DE8\u8BED\u8A00/\u65E0\u7CBE\u786E\u8BCD";
|
|
397
|
+
const alphaRange = h("input", "kb-range kb-alpha-range");
|
|
398
|
+
alphaRange.type = "range";
|
|
399
|
+
alphaRange.min = "0";
|
|
400
|
+
alphaRange.max = "1";
|
|
401
|
+
alphaRange.step = "0.05";
|
|
402
|
+
alphaRange.setAttribute("aria-label", "\u6DF7\u5408\u6743\u91CD\uFF08\u5DE6\u8BED\u4E49\u53F3\u5173\u952E\u8BCD\uFF09");
|
|
403
|
+
const alphaEndR = h("span", "kb-alpha-end", "\u5173\u952E\u8BCD");
|
|
404
|
+
alphaEndR.title = "\u5173\u952E\u8BCD\uFF1A\u5927\u5E93\u5FEB\u901F\u7CBE\u786E";
|
|
405
|
+
const alpha = h("div", "kb-alpha");
|
|
406
|
+
alpha.append(alphaEndL, alphaRange, alphaEndR);
|
|
407
|
+
const rerankSwitch = h("button", "kb-switch");
|
|
408
|
+
rerankSwitch.type = "button";
|
|
409
|
+
rerankSwitch.role = "switch";
|
|
410
|
+
rerankSwitch.setAttribute("aria-label", "\u91CD\u6392");
|
|
411
|
+
const rerankText = h("span", "kb-toggle-label", "\u91CD\u6392");
|
|
412
|
+
const rerankToggle = h("span", "kb-toggle");
|
|
413
|
+
rerankToggle.append(rerankSwitch, rerankText);
|
|
414
|
+
const thresholdRange = h("input", "kb-range kb-threshold-range");
|
|
415
|
+
thresholdRange.type = "range";
|
|
416
|
+
thresholdRange.min = "0";
|
|
417
|
+
thresholdRange.max = "1";
|
|
418
|
+
thresholdRange.step = "0.05";
|
|
419
|
+
thresholdRange.setAttribute("aria-label", "\u5206\u6570\u9608\u503C");
|
|
420
|
+
const thresholdCount = h("span", "kb-threshold-count kb-meta");
|
|
421
|
+
const threshold = h("div", "kb-threshold");
|
|
422
|
+
threshold.append(thresholdRange, thresholdCount);
|
|
423
|
+
const runBtn = h("button", "kb-run", "\u8FD0\u884C");
|
|
424
|
+
runBtn.type = "button";
|
|
425
|
+
const runIcon = svgIcon(ICON_RUN);
|
|
426
|
+
if (runIcon) runBtn.prepend(runIcon);
|
|
427
|
+
let idnSelect = null;
|
|
428
|
+
let idnGroup = null;
|
|
429
|
+
if (idnList.length) {
|
|
430
|
+
idnSelect = h("select", "kb-retrieval-idn");
|
|
431
|
+
idnSelect.setAttribute("aria-label", "\u68C0\u7D22\u8EAB\u4EFD");
|
|
432
|
+
for (const idn of idnList) {
|
|
433
|
+
const opt = h("option", void 0, idn.label ?? idn.user);
|
|
434
|
+
opt.value = idn.user;
|
|
435
|
+
idnSelect.appendChild(opt);
|
|
436
|
+
}
|
|
437
|
+
idnGroup = h("span", "kb-retrieval-idn-group");
|
|
438
|
+
idnGroup.append(h("span", "kb-meta", "\u8EAB\u4EFD"), idnSelect);
|
|
439
|
+
}
|
|
440
|
+
const layerChip = h("button", "kb-chip kb-layer-chip");
|
|
441
|
+
layerChip.type = "button";
|
|
442
|
+
layerChip.setAttribute("aria-label", "\u8FC7\u6EE4\u5C42");
|
|
443
|
+
const paintLayer = () => {
|
|
444
|
+
layerChip.dataset.layer = layer;
|
|
445
|
+
layerChip.textContent = LAYER_LABEL[layer];
|
|
446
|
+
layerChip.title = LAYER_TITLE[layer];
|
|
447
|
+
};
|
|
448
|
+
paintLayer();
|
|
449
|
+
const adminBadge = adminAcl ? h("span", "kb-badge kb-badge--admin", "admin") : null;
|
|
450
|
+
bar.append(queryInput, modes, stepLabel, step, alpha, rerankToggle, threshold);
|
|
451
|
+
if (idnGroup) bar.appendChild(idnGroup);
|
|
452
|
+
bar.append(runBtn, layerChip);
|
|
453
|
+
if (adminBadge) bar.appendChild(adminBadge);
|
|
454
|
+
const paramsText = h("code", "kb-params-text kb-meta");
|
|
455
|
+
const paramsCopy = h("button", "kb-params-copy");
|
|
456
|
+
paramsCopy.type = "button";
|
|
457
|
+
paramsCopy.title = "\u590D\u5236\u53C2\u6570 JSON";
|
|
458
|
+
paramsCopy.setAttribute("aria-label", "\u590D\u5236\u53C2\u6570 JSON");
|
|
459
|
+
const copyIcon = svgIcon(ICON_COPY);
|
|
460
|
+
if (copyIcon) paramsCopy.appendChild(copyIcon);
|
|
461
|
+
const paramsRow = h("div", "kb-params");
|
|
462
|
+
paramsRow.append(paramsCopy, paramsText);
|
|
463
|
+
const layerNotice = h("div", "kb-notice");
|
|
464
|
+
layerNotice.hidden = true;
|
|
465
|
+
const paintLayerNotice = () => {
|
|
466
|
+
if (layer === "none") {
|
|
467
|
+
layerNotice.textContent = "fail-open\uFF1A\u5F53\u524D\u67E5\u8BE2\u672A\u643A\u5E26\u8EAB\u4EFD\u8FC7\u6EE4\uFF0C\u5C06\u8FD4\u56DE\u5168\u90E8\u5019\u9009\uFF08\u4EC5\u9650\u8C03\u8BD5\uFF09";
|
|
468
|
+
layerNotice.hidden = false;
|
|
469
|
+
} else if (layer === "post") {
|
|
470
|
+
layerNotice.textContent = "post-filter\uFF1A\u5206\u6570\u5DF2\u5728\u8FC7\u6EE4\u524D\u4EA7\u751F\uFF08\u7F3A\u9677\u5C42\u6F14\u793A\uFF09";
|
|
471
|
+
layerNotice.hidden = false;
|
|
472
|
+
} else {
|
|
473
|
+
layerNotice.textContent = "";
|
|
474
|
+
layerNotice.hidden = true;
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
paintLayerNotice();
|
|
478
|
+
const hitsBox = h("div", "kb-hits");
|
|
479
|
+
el.append(bar, layerNotice, paramsRow, hitsBox);
|
|
480
|
+
function currentQueryText() {
|
|
481
|
+
return queryInput.value.trim();
|
|
482
|
+
}
|
|
483
|
+
function projectThreshold() {
|
|
484
|
+
return params.rerank && thresholdValue > 0 ? thresholdValue : null;
|
|
485
|
+
}
|
|
486
|
+
function buildQueryObject() {
|
|
487
|
+
const p = { ...params, threshold: projectThreshold() };
|
|
488
|
+
return { query: currentQueryText(), params: p };
|
|
489
|
+
}
|
|
490
|
+
function syncBar() {
|
|
491
|
+
for (const [mode, btn] of modeButtons) {
|
|
492
|
+
const active = mode === params.mode;
|
|
493
|
+
btn.classList.toggle("is-active", active);
|
|
494
|
+
btn.setAttribute("aria-checked", active ? "true" : "false");
|
|
495
|
+
}
|
|
496
|
+
topKValue.textContent = String(params.topK);
|
|
497
|
+
const alphaOn = params.mode === "hybrid";
|
|
498
|
+
alphaRange.disabled = !alphaOn;
|
|
499
|
+
alphaRange.value = String(params.alpha ?? 0.5);
|
|
500
|
+
alphaEndL.textContent = `\u8BED\u4E49 ${(params.alpha ?? 0.5).toFixed(2)}`;
|
|
501
|
+
alpha.classList.toggle("is-off", !alphaOn);
|
|
502
|
+
rerankSwitch.setAttribute("aria-checked", params.rerank ? "true" : "false");
|
|
503
|
+
thresholdRange.disabled = !params.rerank;
|
|
504
|
+
thresholdRange.value = String(thresholdValue);
|
|
505
|
+
threshold.classList.toggle("is-off", !params.rerank);
|
|
506
|
+
}
|
|
507
|
+
function updateSurvival() {
|
|
508
|
+
thresholdCount.title = "\u5206\u6BCD\u672A\u8FC7\u6EE4\u524D\u8BA1\u6570\u5C5E\u6CC4\u9732\uFF0C\u4E0D\u663E\u793A";
|
|
509
|
+
if (!params.rerank) {
|
|
510
|
+
thresholdCount.textContent = "\u9608\u503C N/A";
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
const t = thresholdValue;
|
|
514
|
+
if (!(t > 0)) {
|
|
515
|
+
thresholdCount.textContent = `\u9608\u503C \u5173 \xB7 \u5B58\u6D3B ${hits.length}`;
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
let alive = 0;
|
|
519
|
+
for (const hit of hits) {
|
|
520
|
+
const pct = scorePercent(hit.score, hit.scoreKind, thresholdMax);
|
|
521
|
+
if (pct != null && pct >= t * 100 - 1e-9) alive++;
|
|
522
|
+
}
|
|
523
|
+
thresholdCount.textContent = `\u9608\u503C ${t.toFixed(2)} \xB7 \u5B58\u6D3B ${alive}`;
|
|
524
|
+
}
|
|
525
|
+
function updateParamsLine() {
|
|
526
|
+
const q = buildQueryObject();
|
|
527
|
+
paramsText.textContent = JSON.stringify(q);
|
|
528
|
+
}
|
|
529
|
+
function refreshDerived() {
|
|
530
|
+
syncBar();
|
|
531
|
+
updateParamsLine();
|
|
532
|
+
updateSurvival();
|
|
533
|
+
}
|
|
534
|
+
function renderScoreSide(hit, side) {
|
|
535
|
+
const score = h("span", "kb-score");
|
|
536
|
+
const pct = scorePercent(hit.score, hit.scoreKind, thresholdMax);
|
|
537
|
+
if (pct != null) {
|
|
538
|
+
const barEl = h("span", "kb-score-bar");
|
|
539
|
+
const fill = h("i");
|
|
540
|
+
fill.style.width = `${pct.toFixed(1)}%`;
|
|
541
|
+
barEl.appendChild(fill);
|
|
542
|
+
score.appendChild(barEl);
|
|
543
|
+
}
|
|
544
|
+
const value = h("span", "kb-score-value", formatScore(hit.score));
|
|
545
|
+
score.appendChild(value);
|
|
546
|
+
side.appendChild(score);
|
|
547
|
+
const kind = h("span", "kb-chip kb-chip--kind", hit.scoreKind ?? "\u672A\u6807");
|
|
548
|
+
side.appendChild(kind);
|
|
549
|
+
if (hit.vectorPart != null && hit.keywordPart != null) {
|
|
550
|
+
const dual = h("span", "kb-score-dual");
|
|
551
|
+
const vec = h("i", "kb-score-dual-vec");
|
|
552
|
+
const kw = h("i", "kb-score-dual-kw");
|
|
553
|
+
const sum2 = hit.vectorPart + hit.keywordPart;
|
|
554
|
+
const vecPct = sum2 > 0 ? hit.vectorPart / sum2 * 100 : 50;
|
|
555
|
+
vec.style.width = `${Math.max(0, Math.min(100, vecPct)).toFixed(1)}%`;
|
|
556
|
+
kw.style.flex = "1 1 auto";
|
|
557
|
+
dual.append(vec, kw);
|
|
558
|
+
dual.title = `\u5411\u91CF ${vecPct.toFixed(0)}% / \u5173\u952E\u8BCD ${(100 - vecPct).toFixed(0)}%`;
|
|
559
|
+
side.appendChild(dual);
|
|
560
|
+
}
|
|
561
|
+
if (hit.explain) {
|
|
562
|
+
const fold = h("div", "kb-hit-explain-fold");
|
|
563
|
+
const toggle = h("button", "kb-hit-explain-toggle", "\u62C6\u89E3");
|
|
564
|
+
toggle.type = "button";
|
|
565
|
+
toggle.setAttribute("aria-expanded", "false");
|
|
566
|
+
const body = h("div", "kb-hit-explain kb-meta", hit.explain);
|
|
567
|
+
body.hidden = true;
|
|
568
|
+
fold.append(toggle, body);
|
|
569
|
+
side.appendChild(fold);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
function renderMetaChips(hit, box) {
|
|
573
|
+
if (hit.page != null) box.appendChild(h("span", "kb-chip", `\u7B2C ${hit.page} \u9875`));
|
|
574
|
+
if (hit.documentId) box.appendChild(h("span", "kb-chip", hit.documentId));
|
|
575
|
+
if (hit.meta) {
|
|
576
|
+
for (const [k, v] of Object.entries(hit.meta).slice(0, 4)) {
|
|
577
|
+
box.appendChild(h("span", "kb-chip", `${k}: ${String(v)}`));
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
function renderHitRow(hit, index) {
|
|
582
|
+
const row = h("div", "kb-hit");
|
|
583
|
+
const rank = h("div", "kb-hit-rank kb-num", String(index + 1));
|
|
584
|
+
const main = h("div", "kb-hit-main");
|
|
585
|
+
const title = h("div", "kb-hit-title", hit.title ?? hit.documentId ?? hit.chunkId);
|
|
586
|
+
const snippet = h("div", "kb-hit-snippet");
|
|
587
|
+
for (const node of highlightTerms(hit.snippet ?? "", tokenizeQuery(currentQueryText()))) {
|
|
588
|
+
snippet.appendChild(node);
|
|
589
|
+
}
|
|
590
|
+
const metaBox = h("div", "kb-hit-meta");
|
|
591
|
+
renderMetaChips(hit, metaBox);
|
|
592
|
+
main.append(title, snippet, metaBox);
|
|
593
|
+
const side = h("div", "kb-hit-side");
|
|
594
|
+
renderScoreSide(hit, side);
|
|
595
|
+
if (adminAcl) side.appendChild(h("span", "kb-chip", kbVisibilityLabel(adminAcl(hit))));
|
|
596
|
+
row.append(rank, main, side);
|
|
597
|
+
return row;
|
|
598
|
+
}
|
|
599
|
+
function renderEmpty() {
|
|
600
|
+
const empty = h("div", "kb-empty", "\u8F93\u5165\u95EE\u9898\u5E76\u8FD0\u884C\uFF0C\u547D\u4E2D\u7ED3\u679C\u5C06\u51FA\u73B0\u5728\u8FD9\u91CC");
|
|
601
|
+
hitsBox.appendChild(empty);
|
|
602
|
+
}
|
|
603
|
+
function run() {
|
|
604
|
+
if (busy || destroyed) return;
|
|
605
|
+
const query = buildQueryObject();
|
|
606
|
+
emitIcen(el, "icen:kb-retrieval-run", { query });
|
|
607
|
+
opts.onRun?.(query);
|
|
608
|
+
}
|
|
609
|
+
listen(queryInput, "input", () => {
|
|
610
|
+
updateParamsLine();
|
|
611
|
+
});
|
|
612
|
+
listen(queryInput, "keydown", (ev) => {
|
|
613
|
+
const e = ev;
|
|
614
|
+
if (e.key === "Enter" && !e.isComposing) {
|
|
615
|
+
e.preventDefault();
|
|
616
|
+
run();
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
listen(modes, "click", (ev) => {
|
|
620
|
+
const btn = ev.target?.closest?.(".kb-mode-item");
|
|
621
|
+
if (!(btn instanceof HTMLButtonElement) || btn.disabled) return;
|
|
622
|
+
const mode = btn.dataset.mode;
|
|
623
|
+
if (!mode || mode === params.mode) return;
|
|
624
|
+
params = normalizeRetrievalParams({ ...params, mode });
|
|
625
|
+
refreshDerived();
|
|
626
|
+
});
|
|
627
|
+
listen(step, "click", (ev) => {
|
|
628
|
+
const btn = ev.target?.closest?.(".kb-step-btn");
|
|
629
|
+
if (!(btn instanceof HTMLButtonElement) || btn.disabled) return;
|
|
630
|
+
const dir = Number(btn.dataset.step) || 0;
|
|
631
|
+
if (!dir) return;
|
|
632
|
+
const next = Math.max(TOP_K_MIN, Math.min(TOP_K_MAX, params.topK + dir));
|
|
633
|
+
if (next === params.topK) return;
|
|
634
|
+
params = normalizeRetrievalParams({ ...params, topK: next });
|
|
635
|
+
refreshDerived();
|
|
636
|
+
});
|
|
637
|
+
listen(alphaRange, "input", () => {
|
|
638
|
+
params = normalizeRetrievalParams({ ...params, alpha: Number(alphaRange.value) });
|
|
639
|
+
refreshDerived();
|
|
640
|
+
});
|
|
641
|
+
listen(rerankSwitch, "click", () => {
|
|
642
|
+
params = normalizeRetrievalParams({ ...params, rerank: !params.rerank });
|
|
643
|
+
refreshDerived();
|
|
644
|
+
});
|
|
645
|
+
listen(thresholdRange, "input", () => {
|
|
646
|
+
thresholdValue = Number(thresholdRange.value);
|
|
647
|
+
updateSurvival();
|
|
648
|
+
updateParamsLine();
|
|
649
|
+
});
|
|
650
|
+
listen(runBtn, "click", () => run());
|
|
651
|
+
function applyLayer(next) {
|
|
652
|
+
if (destroyed || next === layer) return;
|
|
653
|
+
layer = next;
|
|
654
|
+
paintLayer();
|
|
655
|
+
paintLayerNotice();
|
|
656
|
+
emitIcen(el, "icen:kb-visibility-layer", { layer });
|
|
657
|
+
}
|
|
658
|
+
listen(layerChip, "click", () => {
|
|
659
|
+
const idx = LAYER_ORDER.indexOf(layer);
|
|
660
|
+
applyLayer(LAYER_ORDER[(idx + 1) % LAYER_ORDER.length]);
|
|
661
|
+
});
|
|
662
|
+
if (idnSelect) {
|
|
663
|
+
const select = idnSelect;
|
|
664
|
+
listen(select, "change", () => {
|
|
665
|
+
const identity = idnList.find((i) => i.user === select.value);
|
|
666
|
+
if (identity) emitIcen(el, "icen:kb-visibility-identity", { identity });
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
listen(hitsBox, "click", (ev) => {
|
|
670
|
+
const btn = ev.target?.closest?.(".kb-hit-explain-toggle");
|
|
671
|
+
if (!(btn instanceof HTMLButtonElement)) return;
|
|
672
|
+
const body = btn.parentElement?.querySelector(".kb-hit-explain");
|
|
673
|
+
if (!body) return;
|
|
674
|
+
const open = body.hasAttribute("hidden");
|
|
675
|
+
body.toggleAttribute("hidden", !open);
|
|
676
|
+
btn.setAttribute("aria-expanded", open ? "true" : "false");
|
|
677
|
+
});
|
|
678
|
+
listen(paramsCopy, "click", () => {
|
|
679
|
+
if (destroyed) return;
|
|
680
|
+
const ok = copyText(paramsText.textContent ?? "");
|
|
681
|
+
if (ok) {
|
|
682
|
+
paramsCopy.classList.add("is-copied");
|
|
683
|
+
paramsCopy.title = "\u5DF2\u590D\u5236";
|
|
684
|
+
if (copyTimer) clearTimeout(copyTimer);
|
|
685
|
+
copyTimer = setTimeout(() => {
|
|
686
|
+
if (destroyed) return;
|
|
687
|
+
paramsCopy.classList.remove("is-copied");
|
|
688
|
+
paramsCopy.title = "\u590D\u5236\u53C2\u6570 JSON";
|
|
689
|
+
}, 1200);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
const handle = {
|
|
693
|
+
getParams() {
|
|
694
|
+
return normalizeRetrievalParams({ ...params, threshold: projectThreshold() });
|
|
695
|
+
},
|
|
696
|
+
setParams(patch) {
|
|
697
|
+
params = normalizeRetrievalParams({ ...params, ...patch });
|
|
698
|
+
thresholdValue = params.threshold ?? thresholdValue;
|
|
699
|
+
refreshDerived();
|
|
700
|
+
},
|
|
701
|
+
renderHits(next) {
|
|
702
|
+
hits = next.map((hit) => normalizeHit(hit)).filter((hit) => hit.chunkId || hit.snippet);
|
|
703
|
+
hitsBox.textContent = "";
|
|
704
|
+
if (!hits.length) renderEmpty();
|
|
705
|
+
else for (let i = 0; i < hits.length; i++) hitsBox.appendChild(renderHitRow(hits[i], i));
|
|
706
|
+
updateSurvival();
|
|
707
|
+
},
|
|
708
|
+
setBusy(next) {
|
|
709
|
+
busy = next && !destroyed;
|
|
710
|
+
el.classList.toggle("is-busy", busy);
|
|
711
|
+
runBtn.disabled = busy;
|
|
712
|
+
runBtn.setAttribute("aria-busy", busy ? "true" : "false");
|
|
713
|
+
runBtn.textContent = busy ? "\u8FD0\u884C\u4E2D\u2026" : "\u8FD0\u884C";
|
|
714
|
+
if (!busy) {
|
|
715
|
+
const icon = svgIcon(ICON_RUN);
|
|
716
|
+
if (icon) runBtn.prepend(icon);
|
|
717
|
+
}
|
|
718
|
+
},
|
|
719
|
+
setThreshold(next) {
|
|
720
|
+
thresholdValue = typeof next === "number" && Number.isFinite(next) ? Math.max(0, Math.min(1, next)) : 0;
|
|
721
|
+
refreshDerived();
|
|
722
|
+
},
|
|
723
|
+
getFilterLayer() {
|
|
724
|
+
return layer;
|
|
725
|
+
},
|
|
726
|
+
setFilterLayer(l) {
|
|
727
|
+
applyLayer(l === "post" || l === "none" ? l : "pre");
|
|
728
|
+
},
|
|
729
|
+
destroy() {
|
|
730
|
+
if (destroyed) return;
|
|
731
|
+
destroyed = true;
|
|
732
|
+
ctrl.abort();
|
|
733
|
+
if (copyTimer) clearTimeout(copyTimer);
|
|
734
|
+
el.classList.remove("kb-retrieval", "is-busy");
|
|
735
|
+
delete el.dataset.kbRetrieval;
|
|
736
|
+
el.textContent = "";
|
|
737
|
+
delete el.__icenKbRetrieval;
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
refreshDerived();
|
|
741
|
+
marked.__icenKbRetrieval = handle;
|
|
742
|
+
return handle;
|
|
743
|
+
}
|
|
744
|
+
export {
|
|
745
|
+
createKbRetrieval
|
|
746
|
+
};
|