Files
kbdb-graph-plugin/src/actions/node-persist.ts
T
uncle6 13db97bb54 fix(ingest): receiver Zod 追上 contract — 補向量化打標欄位 (issue #1 補對齊) (#3)
契約漂移修補:T3 的 strict Zod 鏡射舊 contract,ingest 照新 contract(ingest#1
升格)送向量化打標欄位會被 .strict() 擋成 422。方向 A:顯式加合法新欄位、保留
strict。

- 同步 contracts/ingest-candidate.json 副本到頂層單一真相源(mira-dissolve)。
- NodeSchema 加 id?/aliases?/embed?;EdgeSchema 加 predicate_embed?。strict() 保留
  → bridge_score/clusters 等 graph 領域禁送欄位仍 422。
- 落地:predicate_embed 透傳進 triplet slot;node 打標(embed/gloss/aliases)存進
  entity slot,供 base/KBDB embed 模組讀標執行(graph 不算向量,鐵律一致)。
- id 作 node 去重鍵:同卡多邊指到只存一筆 entity。
- persistNodes 拆成獨立 action(triplet-ingest.ts 回到 95 行,守樂高 100 行限制)。
- 測試 +4:帶向量化欄位通過、bridge_score/clusters 仍 422、同 id 去重。
  vitest 23 passed。零 SQL / 無 D1·Vectorize·AI 綁定 / dry-run 乾淨。

Co-authored-by: richblack <leo21c@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 20:28:13 +08:00

51 lines
1.7 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';
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,
): 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,
);
}
}