Files
kbdb-graph-plugin/src/actions/node-persist.ts
T
Claude 4cc7057cea feat(graph): node gloss→base embeddable entry 橋——Arcrun#7 A1
修「打標≠讀標」:node gloss+embed 標在 entity record、但 base embed 只掃 entries.metadata.embed
→ persistNodes 另落一筆 content=canonical:gloss、metadata.embed=true 的 base entry(走 API/零SQL)。
- gloss-entry.ts: upsertGlossEntry 冪等(確定性 page_name + list-then-write)
- backfill-gloss-entries.ts + route: 對既有 entity record 補 gloss entry
- triplet-ingest 帶 source.uri 進 metadata;kbdb-client 暴露 metadata_json(base 早支援)
- vitest 30/30(+7);[→arcrun] base 缺 upsert entry 端點,暫以 list-then-write 冪等
2026-07-05 09:16:26 +00:00

60 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// node 層打標落地 — 把 envelope nodes[] 的向量化打標(embed/gloss/aliases)存進 entity slot。
// 向量化分工(ingest#1 升格,2026-06-26):ingest 打標、base/KBDB embed 模組讀標執行;graph 不算向量。
// 鐵律:走 base APIAPI-as-Wall)、零 SQL。
import type { KbdbClient } from '../lib/kbdb-client';
import { TPL_ENTITY, ensurePluginTemplates } from '../lib/templates';
import { upsertGlossEntry } from './gloss-entry';
export type IngestNode = {
name: string;
id?: string;
aliases?: string[];
gloss?: string;
embed?: boolean;
entity_type?: string;
};
/**
* 把 node 層打標存進 entity record,供 base embed 模組讀標執行 embedding。
* 去重:以 id(無則 name)為鍵,同鍵在這批內只存一筆——wikilink 卡被多條邊指到仍是一個 node。
* graph 不做 embedding,只負責透傳/落地打標。
*/
export async function persistNodes(
client: KbdbClient,
nodes: IngestNode[],
owner_id?: string,
source?: string, // envelope source.uri,帶進 gloss entry 的 metadata.source(供 base backfill 依 source 過濾)
): Promise<void> {
if (!nodes || nodes.length === 0) return;
await ensurePluginTemplates(client);
const seen = new Set<string>();
for (const n of nodes) {
const key = (n.id ?? n.name).toLowerCase().trim();
if (seen.has(key)) continue; // 同卡多邊指到 → 只存一次
seen.add(key);
await client.createRecord(
TPL_ENTITY,
{
canonical: n.name,
node_id: n.id ?? '',
aliases_json: JSON.stringify(n.aliases ?? []),
entity_type: n.entity_type ?? '',
gloss: n.gloss ?? '',
// contract 預設 true;只在明確 false 時存標(base 看 'false' 跳過 embed)。
embed: n.embed === false ? 'false' : 'true',
owner: owner_id ?? '',
},
owner_id,
);
// 另落一筆 embeddable base entrymetadata.embed=true)——record 的 gloss 標 base embed 讀不到,
// 必須也落成 entry base embed 模組才掃得到(打標≠讀標的修補)。只在要 embed(embed !== false)時落;
// 空 gloss 由 upsertGlossEntry 自行跳過。冪等:同 node 重複 ingest 不造重複 entry。
if (n.embed !== false) {
await upsertGlossEntry(client, { canonical: n.name, node_id: n.id, gloss: n.gloss, source }, owner_id);
}
}
}