feat: 提交 task-045 至 task-058 收口产物
- 收口 rust final closure checklist,推进页面/块系统/Mindmap/CLI/AI tools 到最终 cutover 状态 - 按 ai-frontend-simplification-plan-v1 接入 Hermes bridge,合并 AI 面板并清理旧前端编排残留 - 补充 harness 任务与进度记录,加入 CLI smoke 夹具/脚本,并修正文档页 bridge SSR 自请求回退逻辑
This commit is contained in:
@@ -48,7 +48,8 @@ export const createDocsServerTools = (args: {
|
||||
supabase?: DocsSupabaseClient;
|
||||
ctx: DocsToolContext;
|
||||
allowedToolIds: Set<string>;
|
||||
// 说明:Convex 迁移阶段用于“去 Supabase 化”。如果提供该能力,则完全不依赖 Supabase。
|
||||
// 说明:该文件现在主要服务于非 Convex 模式或兼容兜底;Convex 主链下 docs_* 已改由 Rust runtime 产出结果。
|
||||
// 说明:如果提供该能力,则走本地兼容 transport,不依赖 Supabase。
|
||||
searchDocs?: (args: {
|
||||
userId: string;
|
||||
query: string;
|
||||
|
||||
@@ -446,10 +446,10 @@ export const createMindmapServerTools = (args: {
|
||||
invocationKind: "command",
|
||||
toolArgs: withMindmapIds({ ops: normalized, reason }),
|
||||
data: base,
|
||||
target: mindmapTarget(doc),
|
||||
target: mindmapTarget(loaded.doc),
|
||||
reason,
|
||||
});
|
||||
await persistResultData(doc, result);
|
||||
await persistResultData(loaded.doc, result);
|
||||
return result;
|
||||
}
|
||||
const { data: nextData, applied, errors } = applyMindmapOps(base, normalized);
|
||||
@@ -460,7 +460,7 @@ export const createMindmapServerTools = (args: {
|
||||
opCount: normalized.length,
|
||||
});
|
||||
}
|
||||
await persistMindmap(doc, nextData);
|
||||
await persistMindmap(loaded.doc, nextData);
|
||||
return { ok: true, applied, errors, data: nextData, meta: { reason } };
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { applyMindmapOps, ensureMindmapUids, type MindmapOp, type MindmapTreeNode, type NodeRef } from "@/lib/mindmap/mindmapOps";
|
||||
import { ensureMindmapUids, type MindmapOp, type MindmapTreeNode, type NodeRef } from "@/lib/mindmap/mindmapOps";
|
||||
import { readMindmapLocal, writeMindmapLocal } from "@/lib/mindmap/mindmapLocalStore";
|
||||
import { buildDocumentBridgeContextWithActor } from "@/lib/documents/bridge";
|
||||
import { executeRustBridgeTool } from "@/lib/documents/rust-runtime";
|
||||
|
||||
type SupabaseRouteClient = {
|
||||
from: (table: string) => any;
|
||||
@@ -229,6 +231,21 @@ export const createOnlyOfficeServerTools = (args: {
|
||||
ctx: OnlyOfficeToolContext;
|
||||
allowedToolIds: Set<string>;
|
||||
}) => {
|
||||
const buildRustContext = () =>
|
||||
buildDocumentBridgeContextWithActor({
|
||||
request: new Request("http://localhost"),
|
||||
actor: {
|
||||
actorType: "service",
|
||||
actorId: "onlyoffice-asset-to-mindmap",
|
||||
sessionId: null,
|
||||
},
|
||||
workspaceId: null,
|
||||
source: {
|
||||
channel: "onlyoffice-asset-to-mindmap",
|
||||
client: "wolai-frontend",
|
||||
},
|
||||
});
|
||||
|
||||
const asset_extract_outline = async (toolArgs: Record<string, unknown>) => {
|
||||
const assetId = String(toolArgs.assetId ?? "").trim();
|
||||
const attachmentRef = String(toolArgs.attachmentRef ?? "").trim();
|
||||
@@ -308,11 +325,13 @@ export const createOnlyOfficeServerTools = (args: {
|
||||
};
|
||||
|
||||
const asset_to_mindmap = async (toolArgs: Record<string, unknown>) => {
|
||||
// 说明:附件大纲提取仍在 TS/MinerU 侧,真正的导图写入由 Rust mindmap_apply_ops 负责。
|
||||
const mindmapId = String(toolArgs.mindmapId ?? "").trim();
|
||||
if (!mindmapId) throw new Error("缺少 mindmapId");
|
||||
const parentUidArg = String(toolArgs.parentUid ?? "").trim();
|
||||
const maxItemsRaw = Number(toolArgs.maxItems ?? 120);
|
||||
const maxItems = Number.isFinite(maxItemsRaw) ? Math.max(10, Math.min(600, Math.floor(maxItemsRaw))) : 120;
|
||||
const reason = String(toolArgs.reason ?? "").trim() || null;
|
||||
|
||||
const documentId = String(args.ctx.documentId ?? "").trim();
|
||||
if (!documentId) throw new Error("缺少 documentId 上下文(OnlyOffice 工具需要落盘到指定文档)");
|
||||
@@ -356,8 +375,39 @@ export const createOnlyOfficeServerTools = (args: {
|
||||
if (!findNodeByUid(base, parentUid)) throw new Error("未找到 parentUid 对应节点");
|
||||
|
||||
const ops = buildOutlineOps({ parentUid, items, attachment });
|
||||
const { data: nextData, applied, errors } = applyMindmapOps(base, ops);
|
||||
await writeMindmapLocal(documentId, mindmapId, nextData, "OnlyOffice 生成导图");
|
||||
|
||||
const rustContext = buildRustContext();
|
||||
const rustResult = await executeRustBridgeTool<{
|
||||
ok: boolean;
|
||||
applied?: number;
|
||||
errors?: string[];
|
||||
data?: unknown;
|
||||
meta?: { reason?: string | null } | null;
|
||||
}>({
|
||||
context: rustContext,
|
||||
toolName: "mindmap_apply_ops",
|
||||
invocationKind: "command",
|
||||
args: {
|
||||
ops,
|
||||
reason,
|
||||
},
|
||||
data: base,
|
||||
target: {
|
||||
pageId: documentId,
|
||||
workspaceId: null,
|
||||
blockId: mindmapId,
|
||||
},
|
||||
reason,
|
||||
});
|
||||
|
||||
const resultData = rustResult.result && typeof rustResult.result === "object" ? (rustResult.result as Record<string, unknown>).data : null;
|
||||
const nextData = resultData && typeof resultData === "object" && !Array.isArray(resultData) ? (resultData as MindmapTreeNode) : base;
|
||||
await writeMindmapLocal(documentId, mindmapId, nextData, "OnlyOffice 生成导图(Rust)");
|
||||
|
||||
const applied = Number((rustResult.result as Record<string, unknown> | undefined)?.applied ?? ops.length) || 0;
|
||||
const errors = Array.isArray((rustResult.result as Record<string, unknown> | undefined)?.errors)
|
||||
? ((rustResult.result as Record<string, unknown>).errors as string[])
|
||||
: [];
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
@@ -371,6 +421,8 @@ export const createOnlyOfficeServerTools = (args: {
|
||||
fileName: attachment.title,
|
||||
items: items.length,
|
||||
strategy: String(outlineResult.strategy ?? ""),
|
||||
rustOwner: "mindmap_apply_ops",
|
||||
rustReason: reason,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// 遗留兼容:builtin 声明仍保留给历史兼容与文档对照,前端主链不再从这里继续扩展 Hermes 前置编排。
|
||||
import type { AiAgentTool, AiAgentToolSet } from "../types";
|
||||
|
||||
export const builtinTools: AiAgentTool[] = [
|
||||
@@ -409,6 +410,18 @@ export type BuiltinRustCutoverBinding = {
|
||||
* 完整的一一对应矩阵见 `design/ai-tool-cutover-matrix.md`。
|
||||
*/
|
||||
export const builtinRustCutoverBindings: Record<string, BuiltinRustCutoverBinding> = {
|
||||
docs_search: {
|
||||
rustToolsetId: "toolset.docs_read",
|
||||
rustToolName: "docs_search",
|
||||
status: "rust",
|
||||
note: "跨页文档搜索已切到 Rust runtime,TS 仅负责拉取搜索数据集 transport。",
|
||||
},
|
||||
docs_read: {
|
||||
rustToolsetId: "toolset.docs_read",
|
||||
rustToolName: "docs_read",
|
||||
status: "rust",
|
||||
note: "跨页文档读取结果已由 Rust runtime 统一裁剪与归一化,TS 仅负责读取目标文档 transport。",
|
||||
},
|
||||
search_web: {
|
||||
rustToolsetId: "toolset.readonly",
|
||||
rustToolName: "search_web",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// 遗留兼容:当前 AI 主链已转到 Hermes bridge,这里的 registry 仅保留给历史测试/兼容调用,不再作为前端主编排入口。
|
||||
import type { AiAgentTool, AiAgentToolSet, ToolPermissions } from "./types";
|
||||
|
||||
export type ToolRegistry = {
|
||||
|
||||
Reference in New Issue
Block a user