@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 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
- buf += decoder.decode(value, { stream: true });
86
- // Only process complete lines; keep any partial line buffered so a
87
- // `data:` frame split across reads isn't parsed half-formed.
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
- answer.textContent += extractText(buf.slice(0, nl + 1));
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
- answer.textContent += extractText(buf);
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) {
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -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,CA4B7D"}
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;YAChB,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;aACxB,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
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
@@ -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, "&amp;")
15
+ .replace(/</g, "&lt;")
16
+ .replace(/>/g, "&gt;")
17
+ .replace(/"/g, "&quot;");
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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"}
@@ -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
@@ -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
@@ -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.82",
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.82"
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
- buf += decoder.decode(value, { stream: true });
104
- // Only process complete lines; keep any partial line buffered so a
105
- // `data:` frame split across reads isn't parsed half-formed.
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
- answer.textContent += extractText(buf.slice(0, nl + 1));
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) answer.textContent += extractText(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; white-space: pre-wrap; line-height: 1.55;
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); }