feat: KBDB-graph 插件獨立 — 全面改寫成走基本盤 API(API-as-Wall)
按 leo 鐵律(2026-06-14)把插件從「直接 SQL 操作基本盤表」改寫成 「只透過基本盤 arcrun/kbdb HTTP API 讀寫」。零建表、零 migration、零 SQL。 - 新增 src/lib/kbdb-client.ts:唯一對外通道,封裝 entries/templates/records API - 新增 src/lib/templates.ts:triplet/entity template 定義(替代建表) - 改寫 21 個違規 action(triplet/graph/entity/search)→ 走 client,圖在插件層記憶體組裝 - 移除所有 migrations、D1/Vectorize/AI 綁定;embedding/語意搜尋歸基本盤 optional 模組 - index.ts 只掛 triplets/graph/entities/search 路由;基本盤路由歸 arcrun/kbdb - 測試改走 mock client(純 node);裁剪 CLAUDE.md 只留 graph 插件 + 鐵律 - 修正 SDD design.md「讀現狀推翻鐵律」的錯誤判斷(共用 D1 → API-as-Wall) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
// 插件用到的基本盤 template 定義(= 替代建表)。
|
||||
// 鐵律:插件新類型只能建 template,不建表。這裡集中宣告 slot schema,
|
||||
// 任何寫入前先 client.ensureTemplate 確保存在。
|
||||
|
||||
import type { KbdbClient } from './kbdb-client';
|
||||
import type { Triplet, Entity } from '../types';
|
||||
import type { BaseRecord } from './kbdb-client';
|
||||
|
||||
export const TPL_TRIPLET = 'triplet';
|
||||
export const TPL_ENTITY = 'entity';
|
||||
export const TPL_ENTITY_PENDING = 'entity_pending';
|
||||
|
||||
export const TRIPLET_SLOTS = [
|
||||
'subject', 'predicate', 'object', 'source_block_id',
|
||||
'confidence', 'clusters_json', 'bridge_score',
|
||||
'subject_entity_type', 'object_entity_type',
|
||||
];
|
||||
export const ENTITY_SLOTS = ['canonical', 'aliases_json', 'entity_type', 'owner'];
|
||||
export const ENTITY_PENDING_SLOTS = [
|
||||
'raw_name', 'candidate_entity_id', 'candidate_canonical', 'similarity',
|
||||
];
|
||||
|
||||
/** 確保插件三個 template 存在(idempotent,走 API)。 */
|
||||
export async function ensurePluginTemplates(client: KbdbClient): Promise<void> {
|
||||
await client.ensureTemplate(TPL_TRIPLET, TRIPLET_SLOTS, 'knowledge graph triplet (S-P-O)');
|
||||
await client.ensureTemplate(TPL_ENTITY, ENTITY_SLOTS, 'normalized entity (canonical + aliases)');
|
||||
await client.ensureTemplate(TPL_ENTITY_PENDING, ENTITY_PENDING_SLOTS, 'pending entity alias for review');
|
||||
}
|
||||
|
||||
/** 基本盤 record → 插件 Triplet 型別。 */
|
||||
export function recordToTriplet(rec: BaseRecord): Triplet {
|
||||
const v = rec.values;
|
||||
return {
|
||||
id: rec.record_id,
|
||||
subject: v.subject ?? '',
|
||||
predicate: v.predicate ?? '',
|
||||
object: v.object ?? '',
|
||||
source_block_id: v.source_block_id ?? null,
|
||||
confidence: parseFloat(v.confidence ?? '1.0'),
|
||||
clusters: safeArr(v.clusters_json),
|
||||
bridge_score: parseInt(v.bridge_score ?? '0', 10),
|
||||
subject_entity_type: (v.subject_entity_type as Triplet['subject_entity_type']) || null,
|
||||
object_entity_type: (v.object_entity_type as Triplet['object_entity_type']) || null,
|
||||
created_at: 0,
|
||||
updated_at: 0,
|
||||
};
|
||||
}
|
||||
|
||||
/** 基本盤 record → 插件 Entity 型別。 */
|
||||
export function recordToEntity(rec: BaseRecord): Entity {
|
||||
return {
|
||||
id: rec.record_id,
|
||||
canonical: rec.values.canonical ?? '',
|
||||
aliases: safeArr(rec.values.aliases_json),
|
||||
};
|
||||
}
|
||||
|
||||
function safeArr(json?: string): string[] {
|
||||
try {
|
||||
const p = JSON.parse(json || '[]');
|
||||
return Array.isArray(p) ? p : [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user