feat(y-log): 问答按 LLM 调用各记一条 + 全量补齐各 API 操作埋点

- 问答日志从「每轮 onFinish 一条」改为 useThreadStream onLangChainEvent
  监听 on_chat_model_end,每次大模型调用结束各上报一条(含子代理)
- 广覆盖各 API client 成功路径:查看(view)/查询(search)/新增(create)/
  编辑(edit)/删除(delete)/启停(enabled·disabled)/导入导出,补齐此前
  整模块零埋点与漏掉的单条详情 GET;跳过高频 typeahead/轮询/bootstrap

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
AdministratorandClaude Opus 4.8 committed 2026-06-23 20:42:54 +08:00
1 parent 320f2ef814
commit df9c59e21c
35 files changed
+1569 -224

No files matched your search

+139 -9
View File
@@ -56,9 +56,17 @@ export async function listKnowledgeNotes(params: KnowledgeListParams = {}) {
}
export async function getKnowledgeNote(noteId: string) {
return parseResponse<KnowledgeNote>(
const result = await parseResponse<KnowledgeNote>(
await apiFetch(`${baseUrl()}/notes/${encodeURIComponent(noteId)}`),
);
writeYLog({
optType: OptType.view,
optDetail: "B1-CM助手-知识库-查看",
url: `${baseUrl()}/notes/${encodeURIComponent(noteId)}`,
reqParam: { noteId },
returnParam: result,
});
return result;
}
export async function createKnowledgeNote(data: {
@@ -254,9 +262,17 @@ export async function resolveNoteWikilinks(noteId: string) {
/** Fetch a raw vault meta/hub Markdown page (no DB note) by its path. */
export async function fetchVaultPage(path: string) {
return parseResponse<VaultPage>(
const result = await parseResponse<VaultPage>(
await apiFetch(`${baseUrl()}/vault-page?path=${encodeURIComponent(path)}`),
);
writeYLog({
optType: OptType.view,
optDetail: "B1-CM助手-知识库-Vault页面查看",
url: `${baseUrl()}/vault-page?path=${encodeURIComponent(path)}`,
reqParam: { path },
returnParam: result,
});
return result;
}
export async function exportKnowledgeGraph() {
@@ -295,6 +311,13 @@ export async function listNoteVersions(noteId: string) {
const res = await parseResponse<{ items: KnowledgeVersion[] }>(
await apiFetch(`${baseUrl()}/notes/${encodeURIComponent(noteId)}/versions`),
);
writeYLog({
optType: OptType.search,
optDetail: "B1-CM助手-知识库-历史版本列表",
url: `${baseUrl()}/notes/${encodeURIComponent(noteId)}/versions`,
reqParam: { noteId },
returnParam: res.items,
});
return res.items;
}
@@ -307,23 +330,44 @@ export async function listDuplicates() {
const res = await parseResponse<{ groups: DuplicateGroup[] }>(
await apiFetch(`${baseUrl()}/duplicates`),
);
writeYLog({
optType: OptType.search,
optDetail: "B1-CM助手-知识库-重复项列表",
url: `${baseUrl()}/duplicates`,
returnParam: res.groups,
});
return res.groups;
}
export async function mergeKnowledgeNotes(primaryId: string, duplicateIds: string[]) {
return parseResponse<{ note: KnowledgeNote }>(
const result = await parseResponse<{ note: KnowledgeNote }>(
await apiFetch(`${baseUrl()}/merge`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ primary_id: primaryId, duplicate_ids: duplicateIds }),
}),
);
writeYLog({
optType: OptType.edit,
optDetail: "B1-CM助手-知识库-合并",
url: `${baseUrl()}/merge`,
reqParam: { primary_id: primaryId, duplicate_ids: duplicateIds },
returnParam: result,
});
return result;
}
export async function reindexKnowledge() {
return parseResponse<{ reindexed: number; embedding_enabled: number }>(
const result = await parseResponse<{ reindexed: number; embedding_enabled: number }>(
await apiFetch(`${baseUrl()}/reindex`, { method: "POST" }),
);
writeYLog({
optType: OptType.other,
optDetail: "B1-CM助手-知识库-重建索引",
url: `${baseUrl()}/reindex`,
returnParam: result,
});
return result;
}
export interface KnowledgeGraph {
@@ -332,7 +376,14 @@ export interface KnowledgeGraph {
}
export async function getKnowledgeGraph() {
return parseResponse<KnowledgeGraph>(await apiFetch(`${baseUrl()}/graph`));
const result = await parseResponse<KnowledgeGraph>(await apiFetch(`${baseUrl()}/graph`));
writeYLog({
optType: OptType.search,
optDetail: "B1-CM助手-知识库-图谱查看",
url: `${baseUrl()}/graph`,
returnParam: result,
});
return result;
}
// --- graph blacklist ---
@@ -348,26 +399,48 @@ export async function getGraphBlacklist() {
const res = await parseResponse<{ items: GraphBlacklistItem[] }>(
await apiFetch(`${baseUrl()}/graph/blacklist`),
);
writeYLog({
optType: OptType.search,
optDetail: "B1-CM助手-知识库-图谱黑名单列表",
url: `${baseUrl()}/graph/blacklist`,
returnParam: res.items,
});
return res.items;
}
/** Blacklist node labels (entity names / note titles); they disappear from the graph. */
export async function addGraphBlacklist(labels: string[]) {
return parseResponse<{ added: number; items: GraphBlacklistItem[] }>(
const result = await parseResponse<{ added: number; items: GraphBlacklistItem[] }>(
await apiFetch(`${baseUrl()}/graph/blacklist`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ labels }),
}),
);
writeYLog({
optType: OptType.create,
optDetail: "B1-CM助手-知识库-图谱黑名单新增",
url: `${baseUrl()}/graph/blacklist`,
reqParam: { labels },
returnParam: result,
});
return result;
}
export async function removeGraphBlacklist(entryId: string) {
return parseResponse<{ ok: boolean }>(
const result = await parseResponse<{ ok: boolean }>(
await apiFetch(`${baseUrl()}/graph/blacklist/${encodeURIComponent(entryId)}`, {
method: "DELETE",
}),
);
writeYLog({
optType: OptType.delete,
optDetail: "B1-CM助手-知识库-图谱黑名单删除",
url: `${baseUrl()}/graph/blacklist/${encodeURIComponent(entryId)}`,
reqParam: { entryId },
returnParam: result,
});
return result;
}
// --- folders (user-managed directories) ---
@@ -376,6 +449,12 @@ export async function listKnowledgeFolders() {
const res = await parseResponse<{ items: KnowledgeFolder[] }>(
await apiFetch(`${baseUrl()}/folders`),
);
writeYLog({
optType: OptType.search,
optDetail: "B1-CM助手-知识库-目录列表",
url: `${baseUrl()}/folders`,
returnParam: res.items,
});
return res.items;
}
@@ -387,6 +466,13 @@ export async function createKnowledgeFolder(path: string) {
body: JSON.stringify({ path }),
}),
);
writeYLog({
optType: OptType.create,
optDetail: "B1-CM助手-知识库-目录新建",
url: `${baseUrl()}/folders`,
reqParam: { path },
returnParam: res.folder,
});
return res.folder;
}
@@ -398,16 +484,31 @@ export async function renameKnowledgeFolder(folderId: string, path: string) {
body: JSON.stringify({ path }),
}),
);
writeYLog({
optType: OptType.edit,
optDetail: "B1-CM助手-知识库-目录重命名",
url: `${baseUrl()}/folders/${encodeURIComponent(folderId)}`,
reqParam: { folderId, path },
returnParam: res.folder,
});
return res.folder;
}
export async function deleteKnowledgeFolder(folderId: string, reassignTo?: string) {
const qs = reassignTo ? `?reassign_to=${encodeURIComponent(reassignTo)}` : "";
return parseResponse<{ ok: boolean }>(
const result = await parseResponse<{ ok: boolean }>(
await apiFetch(`${baseUrl()}/folders/${encodeURIComponent(folderId)}${qs}`, {
method: "DELETE",
}),
);
writeYLog({
optType: OptType.delete,
optDetail: "B1-CM助手-知识库-目录删除",
url: `${baseUrl()}/folders/${encodeURIComponent(folderId)}${qs}`,
reqParam: { folderId, reassignTo },
returnParam: result,
});
return result;
}
// --- extraction prompt templates ---
@@ -420,6 +521,13 @@ export async function listExtractTemplates(scope?: ExtractTemplateScope, enabled
const res = await parseResponse<{ items: KnowledgeExtractTemplate[] }>(
await apiFetch(`${baseUrl()}/extract-templates${q ? `?${q}` : ""}`),
);
writeYLog({
optType: OptType.search,
optDetail: "B1-CM助手-知识库-抽取模板列表",
url: `${baseUrl()}/extract-templates${q ? `?${q}` : ""}`,
reqParam: { scope, enabledOnly },
returnParam: res.items,
});
return res.items;
}
@@ -440,6 +548,13 @@ export async function createExtractTemplate(data: ExtractTemplateInput) {
body: JSON.stringify(data),
}),
);
writeYLog({
optType: OptType.create,
optDetail: "B1-CM助手-知识库-抽取模板新建",
url: `${baseUrl()}/extract-templates`,
reqParam: data,
returnParam: res.template,
});
return res.template;
}
@@ -454,13 +569,28 @@ export async function updateExtractTemplate(
body: JSON.stringify(data),
}),
);
writeYLog({
optType: OptType.edit,
optDetail: "B1-CM助手-知识库-抽取模板修改",
url: `${baseUrl()}/extract-templates/${encodeURIComponent(templateId)}`,
reqParam: { templateId, data },
returnParam: res.template,
});
return res.template;
}
export async function deleteExtractTemplate(templateId: string) {
return parseResponse<{ ok: boolean }>(
const result = await parseResponse<{ ok: boolean }>(
await apiFetch(`${baseUrl()}/extract-templates/${encodeURIComponent(templateId)}`, {
method: "DELETE",
}),
);
writeYLog({
optType: OptType.delete,
optDetail: "B1-CM助手-知识库-抽取模板删除",
url: `${baseUrl()}/extract-templates/${encodeURIComponent(templateId)}`,
reqParam: { templateId },
returnParam: result,
});
return result;
}