@dogsbay/plugin-ask 0.2.0-beta.82 → 0.2.0-beta.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.js +21 -7
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/md.d.ts +14 -0
- package/dist/md.d.ts.map +1 -0
- package/dist/md.js +115 -0
- package/dist/md.js.map +1 -0
- package/dist/protocol.d.ts +13 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +51 -0
- package/dist/protocol.js.map +1 -1
- package/package.json +2 -2
- package/src/client.ts +25 -7
- package/src/styles.css +31 -1
package/dist/client.js
CHANGED
|
@@ -12,8 +12,17 @@
|
|
|
12
12
|
*/
|
|
13
13
|
// @ts-expect-error: virtual module resolved by the Dogsbay Vite alias at build.
|
|
14
14
|
import config from "virtual:dogsbay-plugin-config/@dogsbay/plugin-ask";
|
|
15
|
-
import { buildAskRequest, extractText } from "./protocol.js";
|
|
15
|
+
import { buildAskRequest, extractText, parseSources } from "./protocol.js";
|
|
16
|
+
import { renderMarkdown, escapeHtml } from "./md.js";
|
|
16
17
|
const cfg = config;
|
|
18
|
+
function sourcesHtml(sources) {
|
|
19
|
+
const items = sources
|
|
20
|
+
.map((s) => s.href
|
|
21
|
+
? `<li><a href="${escapeHtml(s.href)}" target="_blank" rel="noopener noreferrer">${escapeHtml(s.label)}</a></li>`
|
|
22
|
+
: `<li>${escapeHtml(s.label)}</li>`)
|
|
23
|
+
.join("");
|
|
24
|
+
return `<div class="dba-sources"><div class="dba-sources-title">Sources</div><ul>${items}</ul></div>`;
|
|
25
|
+
}
|
|
17
26
|
const ROOT_ID = "dba-root";
|
|
18
27
|
function mount() {
|
|
19
28
|
if (typeof document === "undefined")
|
|
@@ -77,22 +86,27 @@ function mount() {
|
|
|
77
86
|
answer.dataset.state = "streaming";
|
|
78
87
|
const reader = res.body.getReader();
|
|
79
88
|
const decoder = new TextDecoder();
|
|
80
|
-
let buf = "";
|
|
89
|
+
let buf = ""; // line buffer (don't parse a frame split across reads)
|
|
90
|
+
let rawAll = ""; // whole stream, for the trailing `event: chunks` sources
|
|
91
|
+
let answerMd = ""; // accumulated answer markdown
|
|
81
92
|
for (;;) {
|
|
82
93
|
const { value, done } = await reader.read();
|
|
83
94
|
if (done)
|
|
84
95
|
break;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
96
|
+
const text = decoder.decode(value, { stream: true });
|
|
97
|
+
rawAll += text;
|
|
98
|
+
buf += text;
|
|
88
99
|
const nl = buf.lastIndexOf("\n");
|
|
89
100
|
if (nl >= 0) {
|
|
90
|
-
|
|
101
|
+
answerMd += extractText(buf.slice(0, nl + 1));
|
|
91
102
|
buf = buf.slice(nl + 1);
|
|
103
|
+
answer.innerHTML = renderMarkdown(answerMd);
|
|
92
104
|
}
|
|
93
105
|
}
|
|
94
106
|
if (buf)
|
|
95
|
-
|
|
107
|
+
answerMd += extractText(buf);
|
|
108
|
+
const sources = parseSources(rawAll, cfg.linkBase);
|
|
109
|
+
answer.innerHTML = renderMarkdown(answerMd) + (sources.length ? sourcesHtml(sources) : "");
|
|
96
110
|
answer.dataset.state = "done";
|
|
97
111
|
}
|
|
98
112
|
catch (err) {
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,gFAAgF;AAChF,OAAO,MAAM,MAAM,mDAAmD,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAS5D,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAS5D,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,aAAa,CA8B7D"}
|
package/dist/index.js
CHANGED
|
@@ -35,7 +35,7 @@ export default function ask(input) {
|
|
|
35
35
|
styles() {
|
|
36
36
|
return [STYLES_PATH];
|
|
37
37
|
},
|
|
38
|
-
defineClientConfig() {
|
|
38
|
+
defineClientConfig(ctx) {
|
|
39
39
|
// JSON-safe runtime config exposed at
|
|
40
40
|
// virtual:dogsbay-plugin-config/@dogsbay/plugin-ask
|
|
41
41
|
return {
|
|
@@ -46,6 +46,8 @@ export default function ask(input) {
|
|
|
46
46
|
title: opts.title,
|
|
47
47
|
placeholder: opts.placeholder,
|
|
48
48
|
position: opts.position,
|
|
49
|
+
// Base URL used to turn cited doc paths into links.
|
|
50
|
+
linkBase: ctx.config.site.url ?? "",
|
|
49
51
|
};
|
|
50
52
|
},
|
|
51
53
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAmB,MAAM,aAAa,CAAC;AAE5D,6EAA6E;AAC7E,oEAAoE;AACpE,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AACpD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AACvD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;AAIjE,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,KAAkB;IAC5C,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAEjC,OAAO;QACL,IAAI,EAAE,qBAAqB;QAE3B,aAAa;YACX,OAAO,CAAC,WAAW,CAAC,CAAC;QACvB,CAAC;QAED,MAAM;YACJ,OAAO,CAAC,WAAW,CAAC,CAAC;QACvB,CAAC;QAED,kBAAkB;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAmB,MAAM,aAAa,CAAC;AAE5D,6EAA6E;AAC7E,oEAAoE;AACpE,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AACpD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AACvD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;AAIjE,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,KAAkB;IAC5C,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAEjC,OAAO;QACL,IAAI,EAAE,qBAAqB;QAE3B,aAAa;YACX,OAAO,CAAC,WAAW,CAAC,CAAC;QACvB,CAAC;QAED,MAAM;YACJ,OAAO,CAAC,WAAW,CAAC,CAAC;QACvB,CAAC;QAED,kBAAkB,CAAC,GAAG;YACpB,sCAAsC;YACtC,oDAAoD;YACpD,OAAO;gBACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,oDAAoD;gBACpD,QAAQ,EAAG,GAAG,CAAC,MAAM,CAAC,IAAyB,CAAC,GAAG,IAAI,EAAE;aAC1D,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/md.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal, dependency-free, XSS-safe Markdown → HTML renderer for LLM answers.
|
|
3
|
+
*
|
|
4
|
+
* Safety model: the entire source is HTML-escaped FIRST, so any markup in the
|
|
5
|
+
* answer becomes inert text; only the tags this renderer emits are real. Link
|
|
6
|
+
* targets are restricted to http(s)/relative/anchor (no javascript: etc.).
|
|
7
|
+
*
|
|
8
|
+
* Scope: headings, bold, italic, inline code, fenced code, ordered/unordered
|
|
9
|
+
* lists, links, paragraphs — enough for documentation answers. Unsupported
|
|
10
|
+
* constructs degrade to readable text.
|
|
11
|
+
*/
|
|
12
|
+
export declare function escapeHtml(s: string): string;
|
|
13
|
+
export declare function renderMarkdown(src: string): string;
|
|
14
|
+
//# sourceMappingURL=md.d.ts.map
|
package/dist/md.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"md.d.ts","sourceRoot":"","sources":["../src/md.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAM5C;AAmBD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAuClD"}
|
package/dist/md.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal, dependency-free, XSS-safe Markdown → HTML renderer for LLM answers.
|
|
3
|
+
*
|
|
4
|
+
* Safety model: the entire source is HTML-escaped FIRST, so any markup in the
|
|
5
|
+
* answer becomes inert text; only the tags this renderer emits are real. Link
|
|
6
|
+
* targets are restricted to http(s)/relative/anchor (no javascript: etc.).
|
|
7
|
+
*
|
|
8
|
+
* Scope: headings, bold, italic, inline code, fenced code, ordered/unordered
|
|
9
|
+
* lists, links, paragraphs — enough for documentation answers. Unsupported
|
|
10
|
+
* constructs degrade to readable text.
|
|
11
|
+
*/
|
|
12
|
+
export function escapeHtml(s) {
|
|
13
|
+
return s
|
|
14
|
+
.replace(/&/g, "&")
|
|
15
|
+
.replace(/</g, "<")
|
|
16
|
+
.replace(/>/g, ">")
|
|
17
|
+
.replace(/"/g, """);
|
|
18
|
+
}
|
|
19
|
+
function isSafeUrl(u) {
|
|
20
|
+
// u is already HTML-escaped. Allow absolute http(s), root/relative, anchors.
|
|
21
|
+
return /^(https?:\/\/|\/|#|\.\/|[A-Za-z0-9._~-]+\/)/.test(u) && !/^\s*javascript:/i.test(u);
|
|
22
|
+
}
|
|
23
|
+
// Inline formatting on already-escaped text.
|
|
24
|
+
function inline(text) {
|
|
25
|
+
let t = text.replace(/`([^`]+)`/g, (_m, c) => `<code>${c}</code>`);
|
|
26
|
+
t = t.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, (_m, label, url) => isSafeUrl(url) ? `<a href="${url}" target="_blank" rel="noopener noreferrer">${label}</a>` : label);
|
|
27
|
+
t = t.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
|
|
28
|
+
t = t.replace(/(^|[^*])\*([^*\n]+)\*/g, "$1<em>$2</em>");
|
|
29
|
+
t = t.replace(/(^|[^_])_([^_\n]+)_/g, "$1<em>$2</em>");
|
|
30
|
+
return t;
|
|
31
|
+
}
|
|
32
|
+
export function renderMarkdown(src) {
|
|
33
|
+
const lines = escapeHtml(src).split(/\r?\n/);
|
|
34
|
+
let html = "";
|
|
35
|
+
let ul = false;
|
|
36
|
+
let ol = false;
|
|
37
|
+
const closeLists = () => {
|
|
38
|
+
if (ul) {
|
|
39
|
+
html += "</ul>";
|
|
40
|
+
ul = false;
|
|
41
|
+
}
|
|
42
|
+
if (ol) {
|
|
43
|
+
html += "</ol>";
|
|
44
|
+
ol = false;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
let i = 0;
|
|
48
|
+
while (i < lines.length) {
|
|
49
|
+
const line = lines[i];
|
|
50
|
+
if (/^\s*```/.test(line)) {
|
|
51
|
+
closeLists();
|
|
52
|
+
i++;
|
|
53
|
+
let code = "";
|
|
54
|
+
while (i < lines.length && !/^\s*```/.test(lines[i])) {
|
|
55
|
+
code += lines[i] + "\n";
|
|
56
|
+
i++;
|
|
57
|
+
}
|
|
58
|
+
i++; // closing fence
|
|
59
|
+
html += `<pre><code>${code}</code></pre>`;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const h = line.match(/^(#{1,6})\s+(.*)$/);
|
|
63
|
+
if (h) {
|
|
64
|
+
closeLists();
|
|
65
|
+
const lvl = h[1].length;
|
|
66
|
+
html += `<h${lvl}>${inline(h[2])}</h${lvl}>`;
|
|
67
|
+
i++;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const uli = line.match(/^\s*[-*+]\s+(.*)$/);
|
|
71
|
+
if (uli) {
|
|
72
|
+
if (ol) {
|
|
73
|
+
html += "</ol>";
|
|
74
|
+
ol = false;
|
|
75
|
+
}
|
|
76
|
+
if (!ul) {
|
|
77
|
+
html += "<ul>";
|
|
78
|
+
ul = true;
|
|
79
|
+
}
|
|
80
|
+
html += `<li>${inline(uli[1])}</li>`;
|
|
81
|
+
i++;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const oli = line.match(/^\s*\d+\.\s+(.*)$/);
|
|
85
|
+
if (oli) {
|
|
86
|
+
if (ul) {
|
|
87
|
+
html += "</ul>";
|
|
88
|
+
ul = false;
|
|
89
|
+
}
|
|
90
|
+
if (!ol) {
|
|
91
|
+
html += "<ol>";
|
|
92
|
+
ol = true;
|
|
93
|
+
}
|
|
94
|
+
html += `<li>${inline(oli[1])}</li>`;
|
|
95
|
+
i++;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (line.trim() === "") {
|
|
99
|
+
closeLists();
|
|
100
|
+
i++;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
closeLists();
|
|
104
|
+
let para = line;
|
|
105
|
+
i++;
|
|
106
|
+
while (i < lines.length && lines[i].trim() !== "" && !/^(\s*```|#{1,6}\s|\s*[-*+]\s|\s*\d+\.\s)/.test(lines[i])) {
|
|
107
|
+
para += " " + lines[i];
|
|
108
|
+
i++;
|
|
109
|
+
}
|
|
110
|
+
html += `<p>${inline(para)}</p>`;
|
|
111
|
+
}
|
|
112
|
+
closeLists();
|
|
113
|
+
return html;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=md.js.map
|
package/dist/md.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"md.js","sourceRoot":"","sources":["../src/md.ts"],"names":[],"mappings":"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"}
|
package/dist/protocol.d.ts
CHANGED
|
@@ -22,4 +22,17 @@ export declare function buildAskRequest(site: string, query: string, mode: AskMo
|
|
|
22
22
|
* instance — see README "Streaming format".
|
|
23
23
|
*/
|
|
24
24
|
export declare function extractText(chunk: string): string;
|
|
25
|
+
export interface Source {
|
|
26
|
+
key: string;
|
|
27
|
+
label: string;
|
|
28
|
+
href: string | null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Map an AI Search item key (a "__"-encoded doc path) back to a doc link.
|
|
32
|
+
* Non-lossy keys reverse to `<linkBase>/<path>`; lossy (hash-suffixed) keys
|
|
33
|
+
* can't be reconstructed, so they get a readable label with no href.
|
|
34
|
+
*/
|
|
35
|
+
export declare function sourceLink(key: string, linkBase: string): Source;
|
|
36
|
+
/** Find the AI Search `event: chunks` frame in a raw stream and map it to deduped sources. */
|
|
37
|
+
export declare function parseSources(rawStream: string, linkBase: string): Source[];
|
|
25
38
|
//# sourceMappingURL=protocol.d.ts.map
|
package/dist/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACf;AAED,8DAA8D;AAC9D,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,UAAU,CAEtF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA8BjD"}
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACf;AAED,8DAA8D;AAC9D,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,UAAU,CAEtF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA8BjD;AAED,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAUD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUhE;AAED,8FAA8F;AAC9F,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAsB1E"}
|
package/dist/protocol.js
CHANGED
|
@@ -48,4 +48,55 @@ export function extractText(chunk) {
|
|
|
48
48
|
})
|
|
49
49
|
.join("");
|
|
50
50
|
}
|
|
51
|
+
// Ingest-script lossy shortener produces `<head>__<leaf>__<8hex>.md` for paths
|
|
52
|
+
// too long to fit the filename limit — those can't be reversed to a real URL.
|
|
53
|
+
const LOSSY = /__[0-9a-f]{8}\.md$/;
|
|
54
|
+
function humanize(seg) {
|
|
55
|
+
return seg.replace(/[-_]+/g, " ").trim();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Map an AI Search item key (a "__"-encoded doc path) back to a doc link.
|
|
59
|
+
* Non-lossy keys reverse to `<linkBase>/<path>`; lossy (hash-suffixed) keys
|
|
60
|
+
* can't be reconstructed, so they get a readable label with no href.
|
|
61
|
+
*/
|
|
62
|
+
export function sourceLink(key, linkBase) {
|
|
63
|
+
const base = (linkBase || "").replace(/\/+$/, "");
|
|
64
|
+
if (LOSSY.test(key)) {
|
|
65
|
+
const parts = key.replace(/\.md$/, "").split("__");
|
|
66
|
+
const leaf = parts.length >= 2 ? parts[parts.length - 2] : parts[0];
|
|
67
|
+
return { key, label: humanize(leaf), href: null };
|
|
68
|
+
}
|
|
69
|
+
const path = key.replace(/\.md$/, "").split("__").join("/");
|
|
70
|
+
const leaf = path.split("/").pop() || path;
|
|
71
|
+
return { key, label: humanize(leaf), href: base ? `${base}/${path}` : `/${path}` };
|
|
72
|
+
}
|
|
73
|
+
/** Find the AI Search `event: chunks` frame in a raw stream and map it to deduped sources. */
|
|
74
|
+
export function parseSources(rawStream, linkBase) {
|
|
75
|
+
for (const raw of rawStream.split(/\r?\n/)) {
|
|
76
|
+
const line = raw.trimStart();
|
|
77
|
+
if (!line.startsWith("data:"))
|
|
78
|
+
continue;
|
|
79
|
+
const payload = line.slice("data:".length).trim();
|
|
80
|
+
if (!payload.startsWith("["))
|
|
81
|
+
continue;
|
|
82
|
+
try {
|
|
83
|
+
const arr = JSON.parse(payload);
|
|
84
|
+
const seen = new Set();
|
|
85
|
+
const out = [];
|
|
86
|
+
for (const c of arr) {
|
|
87
|
+
const key = typeof c.item === "string" ? c.item : c.item?.key;
|
|
88
|
+
if (!key || seen.has(key))
|
|
89
|
+
continue;
|
|
90
|
+
seen.add(key);
|
|
91
|
+
out.push(sourceLink(key, linkBase));
|
|
92
|
+
}
|
|
93
|
+
if (out.length)
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// not the chunks frame; keep scanning
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
51
102
|
//# sourceMappingURL=protocol.js.map
|
package/dist/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAYA,8DAA8D;AAC9D,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,KAAa,EAAE,IAAa;IACxE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC;AAC7C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,KAAK;SACT,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QACjC,IAAI,OAAO,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC;QAC9B,sEAAsE;QACtE,uEAAuE;QACvE,uDAAuD;QACvD,IAAI,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,EAAE,CAAC;QAC7E,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QACrD,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QACtD,kEAAkE;QAClE,oDAAoD;QACpD,6DAA6D;QAC7D,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAwB,CAAC;YACvD,MAAM,KAAK,GACT,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO;gBAChC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO;gBAClC,GAAG,CAAC,QAAQ;gBACZ,GAAG,CAAC,IAAI;gBACR,GAAG,CAAC,KAAK,CAAC;YACZ,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC"}
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dogsbay/plugin-ask",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.83",
|
|
4
4
|
"description": "Floating \"Ask AI\" widget for Dogsbay docs sites — calls a shared AI Search proxy (dogsbay-ask).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"README.md"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@dogsbay/types": "0.2.0-beta.
|
|
25
|
+
"@dogsbay/types": "0.2.0-beta.83"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"typescript": "^5.7.0",
|
package/src/client.ts
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
*/
|
|
13
13
|
// @ts-expect-error: virtual module resolved by the Dogsbay Vite alias at build.
|
|
14
14
|
import config from "virtual:dogsbay-plugin-config/@dogsbay/plugin-ask";
|
|
15
|
-
import { buildAskRequest, extractText } from "./protocol.js";
|
|
15
|
+
import { buildAskRequest, extractText, parseSources, type Source } from "./protocol.js";
|
|
16
|
+
import { renderMarkdown, escapeHtml } from "./md.js";
|
|
16
17
|
import type { AskMode, AskPosition } from "./schema.js";
|
|
17
18
|
|
|
18
19
|
interface RuntimeConfig {
|
|
@@ -23,10 +24,22 @@ interface RuntimeConfig {
|
|
|
23
24
|
title: string;
|
|
24
25
|
placeholder: string;
|
|
25
26
|
position: AskPosition;
|
|
27
|
+
linkBase: string;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
const cfg = config as RuntimeConfig;
|
|
29
31
|
|
|
32
|
+
function sourcesHtml(sources: Source[]): string {
|
|
33
|
+
const items = sources
|
|
34
|
+
.map((s) =>
|
|
35
|
+
s.href
|
|
36
|
+
? `<li><a href="${escapeHtml(s.href)}" target="_blank" rel="noopener noreferrer">${escapeHtml(s.label)}</a></li>`
|
|
37
|
+
: `<li>${escapeHtml(s.label)}</li>`,
|
|
38
|
+
)
|
|
39
|
+
.join("");
|
|
40
|
+
return `<div class="dba-sources"><div class="dba-sources-title">Sources</div><ul>${items}</ul></div>`;
|
|
41
|
+
}
|
|
42
|
+
|
|
30
43
|
const ROOT_ID = "dba-root";
|
|
31
44
|
|
|
32
45
|
function mount(): void {
|
|
@@ -96,20 +109,25 @@ function mount(): void {
|
|
|
96
109
|
answer.dataset.state = "streaming";
|
|
97
110
|
const reader = res.body.getReader();
|
|
98
111
|
const decoder = new TextDecoder();
|
|
99
|
-
let buf = "";
|
|
112
|
+
let buf = ""; // line buffer (don't parse a frame split across reads)
|
|
113
|
+
let rawAll = ""; // whole stream, for the trailing `event: chunks` sources
|
|
114
|
+
let answerMd = ""; // accumulated answer markdown
|
|
100
115
|
for (;;) {
|
|
101
116
|
const { value, done } = await reader.read();
|
|
102
117
|
if (done) break;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
118
|
+
const text = decoder.decode(value, { stream: true });
|
|
119
|
+
rawAll += text;
|
|
120
|
+
buf += text;
|
|
106
121
|
const nl = buf.lastIndexOf("\n");
|
|
107
122
|
if (nl >= 0) {
|
|
108
|
-
|
|
123
|
+
answerMd += extractText(buf.slice(0, nl + 1));
|
|
109
124
|
buf = buf.slice(nl + 1);
|
|
125
|
+
answer.innerHTML = renderMarkdown(answerMd);
|
|
110
126
|
}
|
|
111
127
|
}
|
|
112
|
-
if (buf)
|
|
128
|
+
if (buf) answerMd += extractText(buf);
|
|
129
|
+
const sources = parseSources(rawAll, cfg.linkBase);
|
|
130
|
+
answer.innerHTML = renderMarkdown(answerMd) + (sources.length ? sourcesHtml(sources) : "");
|
|
113
131
|
answer.dataset.state = "done";
|
|
114
132
|
} catch (err) {
|
|
115
133
|
answer.dataset.state = "error";
|
package/src/styles.css
CHANGED
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
|
|
70
70
|
.dba-answer {
|
|
71
71
|
min-height: 2rem; max-height: 50vh; overflow-y: auto;
|
|
72
|
-
padding: 0.75rem;
|
|
72
|
+
padding: 0.75rem; line-height: 1.55;
|
|
73
73
|
background: color-mix(in srgb, var(--dba-text) 4%, transparent);
|
|
74
74
|
border-radius: var(--dba-radius);
|
|
75
75
|
}
|
|
@@ -80,3 +80,33 @@
|
|
|
80
80
|
.dba-dialog[open] { animation: dba-in 0.12s ease-out; }
|
|
81
81
|
}
|
|
82
82
|
@keyframes dba-in { from { transform: translateY(6px); opacity: 0; } to { transform: none; opacity: 1; } }
|
|
83
|
+
|
|
84
|
+
/* Rendered Markdown inside the answer */
|
|
85
|
+
.dba-answer h1, .dba-answer h2, .dba-answer h3, .dba-answer h4 {
|
|
86
|
+
margin: 0.8em 0 0.3em; line-height: 1.25; font-weight: 600;
|
|
87
|
+
}
|
|
88
|
+
.dba-answer h1 { font-size: 1.2rem; }
|
|
89
|
+
.dba-answer h2 { font-size: 1.1rem; }
|
|
90
|
+
.dba-answer h3 { font-size: 1rem; }
|
|
91
|
+
.dba-answer h4 { font-size: 0.95rem; }
|
|
92
|
+
.dba-answer p { margin: 0.5em 0; }
|
|
93
|
+
.dba-answer ul, .dba-answer ol { margin: 0.5em 0; padding-left: 1.4em; }
|
|
94
|
+
.dba-answer li { margin: 0.15em 0; }
|
|
95
|
+
.dba-answer a { color: var(--dba-accent); text-decoration: underline; }
|
|
96
|
+
.dba-answer code {
|
|
97
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.9em;
|
|
98
|
+
padding: 0.1em 0.3em; border-radius: 4px;
|
|
99
|
+
background: color-mix(in srgb, var(--dba-text) 9%, transparent);
|
|
100
|
+
}
|
|
101
|
+
.dba-answer pre {
|
|
102
|
+
margin: 0.6em 0; padding: 0.7em 0.8em; overflow-x: auto; border-radius: var(--dba-radius);
|
|
103
|
+
background: color-mix(in srgb, var(--dba-text) 9%, transparent);
|
|
104
|
+
}
|
|
105
|
+
.dba-answer pre code { padding: 0; background: none; }
|
|
106
|
+
|
|
107
|
+
/* Sources list */
|
|
108
|
+
.dba-sources { margin-top: 1em; padding-top: 0.6em; border-top: 1px solid var(--dba-border); }
|
|
109
|
+
.dba-sources-title { font-size: 0.8rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; opacity: 0.7; margin-bottom: 0.3em; }
|
|
110
|
+
.dba-sources ul { margin: 0; padding-left: 1.2em; }
|
|
111
|
+
.dba-sources li { margin: 0.1em 0; font-size: 0.9em; }
|
|
112
|
+
.dba-sources a { color: var(--dba-accent); }
|