跳到內容

Core API

Core 是不需要畫面的完整詞彙:它把 Markdown 剖析成片段、寫成純文字,並編碼使用者給的答案。它不碰 DOM 也不碰 node API,所以只要有 JavaScript 的地方都能跑。

import { parse, toText, inline, encodeAnswer, checkBlocks } from "pi-better-show";
parse(markdown: string): Segment[]

依序把文件切成 {type: "markdown", text}、{type: "block", kind, data, index} 與 {type: "invalid", kind, source, error} 片段。data 依種類有型別(BlockDataMap)。index 從 0 開始,數文件中每一種區塊;無效的區塊不佔編號。index 就是答案用來定位區塊的位址。

告訴作者一個檔案的區塊哪裡有問題,而 parse 只會繼續往下剖析。

checkBlocks(markdown: string, options?: { mermaid?: (source: string) => string | undefined }): BlockProblem[]
formatProblems(name: string, problems: BlockProblem[]): string
interface BlockProblem {
kind: BlockKind;
line: number; // 1-based, in the Markdown file
path: string; // e.g. form question "o5" choice 1 label
message: string;
severity: "error" | "warning";
}
哪些是 error,哪些是 warning

error:區塊無效,頁面會顯示它的原始碼(YAML 錯誤會回報在造成它的那一行;被沒加引號的 # 弄斷的 flow collection,會指向開啟它的那一行)。warning:區塊畫得出來,但寫下的內容有一部分遺失:被 # 截短的純值(YAML 把後面讀成註解;訊息會指出鍵的路徑並提醒加引號)、區塊在那一層不讀的鍵(附上已知的鍵,差一點打對時還有「你是不是要寫」的提示),或是一直沒有關閉的 fence。Core 沒有 Mermaid 剖析器:傳入 options.mermaid(回傳圖的原始碼哪裡有問題),也能檢查圖。它是純函式,載入的東西不比 parse 多。

為無法畫區塊的介面轉譯文件:Discord、LINE、終端機。

toText(segments: Segment[], profile: TextProfile): string
interface TextProfile {
flavor: "discord" | "line" | "plain"; // Discord Markdown, or plain text
width?: number; // columns a diagram may take; default 60
mermaid?: (source: string, width: number) => string | undefined;
keep?: readonly BlockKind[]; // kinds emitted as their `raw` text instead of converted
lang?: "en" | "zh-TW"; // language of the reply instructions; default "en", anything else is "en"
}
回覆指示、`raw` 與圖的 hook

互動種類(options、form、review、suggest 與 checklist)以一行回覆指示收尾:「Reply with a number.」、「Reply in text, one line per question, like 1: b.」等等。lang: "zh-TW" 會以繁體中文寫出;知道對話語言時請傳入。區塊的內容絕不翻譯。

每個 BlockSegment 與 InvalidSegment 都帶 raw:區塊一字不差的原文,包含 fence(或 alert 整段 > 引用)。列在 keep 的種類,不論有效或無效,都以 raw 原樣輸出,給自己會畫它們的介面;其他種類照常轉換。DISPLAY_KINDS(alert、cards、mermaid、mindmap、diff、table、steps、stats、tree)是這類介面常用的 keep 清單;INTERACTIVE_KINDS(options、suggest、form、checklist、review)是使用者會作答的種類,無法畫出它們的介面會拿到回覆指示。沒有 keep 時,輸出不變。

為無法畫區塊的介面轉譯文件。圖會經過 mermaid hook;沒有 hook、或它回傳 undefined 或比 width 更寬的圖時,輸出是程式碼區塊中的 Mermaid 原始碼,加上指向網頁版的提示。輸出裡不會留下任何區塊種類的 fence,Discord 原生的 diff 除外。

答案是一個種類加上一串 [name, value] 欄位;encodeAnswer 把它變成 agent 讀的文字。

inline(text: string): InlineToken[] // restricted inline Markdown, tokenized, never HTML
inlinePlain(text: string): string // the same text without markers
displayWidth(text: string): number // terminal columns: CJK counts 2
reviewItemName(item): string // "B (dark header)"
interface Answer {
kind: "form" | "review" | "feedback" | "pick" | "suggest" | "checklist";
title?: string;
fields: [name: string, value: string][];
ref?: { doc?: string; block: number };
}
encodeAnswer(answer: Answer): string

encodeAnswer 產生 agent 讀的文字。對 form、review 與 feedback,給同樣的欄位時,它與 pi-herdr-doc-review 的 formMessage、reviewMessage 與 pageFeedbackMessage 位元組相容(舊的 pi-kind 欄位會被忽略)。ref 是給宿主定位區塊用的,不會出現在文字裡。pi-note 欄位(見下)會以 Other comments: … 附在後面。

種類 fields 文字
form 每個問題一個 [name, value] User submitted a form ... 後面接 - name: value 各行
review title、picked、成對的 item/comment、silent User reviewed "title": …
feedback page、成對的 quote/comment、overall User feedback on the page "page": …(quote 是選取的段落,或圖上的元素,見 Markdown 頁面)
pick [["picked", option]] User picked "option" for "title".
suggest [["text", text]] 文字本身
checklist 每個項目一個 [name, "checked" | "unchecked"] User updated the checklist "title": 後面接 ☑/☐ 各行

給從不受信任的用戶端收到 Answer 的宿主:validateAnswer 判斷它是否符合所稱要回答的區塊。

validateAnswer(block: BlockSegment, answer: Answer): { ok: true } | { ok: false; reason: string }
接受什麼

validateAnswer 是給從不受信任的用戶端收到 Answer 的宿主用的。答案的 kind 符合區塊(options 收 pick,其他收自己的種類)、每個欄位都指名該區塊的問題、選項或項目,且最多 64 個欄位、每個最多 1,024 個字元時,它才接受。同一個名稱的多個值,只有 multi 的表單問題才接受(以重複的欄位,或表單元素送出的合併值);single 或 text 問題、挑選與建議都只收一個。必填的問題必須有答案(空值或 (no answer) 不算答案)。沒有 other 欄位的 form 問題,值必須是它的選項之一。checklist 的欄位是項目名稱各出現一次、加上 checked 或 unchecked;review 只有在區塊有 pick 時才能帶 picked。被拒絕時 reason 會說明原因,給宿主的錯誤回覆用。不接受答案的區塊(顯示用的種類)一律拒絕。