diff --git a/lib/agent-tools-common.js b/lib/agent-tools-common.js index 681b622..4b52ae1 100644 --- a/lib/agent-tools-common.js +++ b/lib/agent-tools-common.js @@ -672,6 +672,11 @@ function watchKbContext(listener) { var str = (description) => ({ type: "string", ...description ? { description } : {} }); var bool = (description) => ({ type: "boolean", ...description ? { description } : {} }); var num = (description) => ({ type: "number", ...description ? { description } : {} }); +var reqStr = (description) => ({ + type: "string", + required: true, + ...description ? { description } : {} +}); function renderJson(_args, value) { return [{ type: "text", text: JSON.stringify(value, null, 0) }]; } @@ -708,20 +713,16 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { return () => {}; const entries = [ tool("netx__kbWriteMemory", `Create (or overwrite) one diary-style memory markdown under ${localRoot}/memories/. ` + "bucket: note→日常笔记, rca_review→排障复盘, ai_trace→AI思维链. " + "Default create-only; set overwrite=true to replace same filename. " + "Do not use workspace Write — KB is outside the sandbox.", { - type: "object", - additionalProperties: false, - required: ["bucket", "slug", "body"], - properties: { - bucket: { - type: "string", - enum: ["note", "rca_review", "ai_trace"], - description: "Memory subdirectory" - }, - slug: str("Short filename stem (no path separators)"), - body: str("Full markdown body"), - date: str("Optional YYYY-MM-DD (default today)"), - overwrite: bool("Replace if the target file already exists") - } + bucket: { + type: "string", + required: true, + enum: ["note", "rca_review", "ai_trace"], + description: "Memory subdirectory" + }, + slug: reqStr("Short filename stem (no path separators)"), + body: reqStr("Full markdown body"), + date: str("Optional YYYY-MM-DD (default today)"), + overwrite: bool("Replace if the target file already exists") }, (args) => createMemory(liveSnapshot(), { bucket: args.bucket, slug: String(args.slug ?? ""), @@ -730,16 +731,11 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbWriteDraft", `Create (or overwrite) a DRAFT case under ${localRoot}/drafts/. ` + "Filename is forced to DRAFT-YYYYMMDD-…; body gets status: draft frontmatter if missing. " + "Set overwrite=true to replace. Not for identity/ or formal RCA.", { - type: "object", - additionalProperties: false, - required: ["slug", "body"], - properties: { - slug: str("Case stem (DRAFT- prefix added if missing)"), - body: str("Markdown body (RCA-ish draft)"), - domain: str("Optional fault-domain subfolder under drafts/"), - date: str("Optional event date YYYY-MM-DD or YYYYMMDD"), - overwrite: bool("Replace if the target file already exists") - } + slug: reqStr("Case stem (DRAFT- prefix added if missing)"), + body: reqStr("Markdown body (RCA-ish draft)"), + domain: str("Optional fault-domain subfolder under drafts/"), + date: str("Optional event date YYYY-MM-DD or YYYYMMDD"), + overwrite: bool("Replace if the target file already exists") }, (args) => createDraft(liveSnapshot(), { slug: String(args.slug ?? ""), body: String(args.body ?? ""), @@ -748,20 +744,16 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbWriteSuggestion", `Create (or overwrite) a suggestion under ${localRoot}/suggestions/{theory|improvement}/. ` + "Use for theory corrections or tool/process improvements — never rewrite identity/.", { - type: "object", - additionalProperties: false, - required: ["kind", "slug", "body"], - properties: { - kind: { - type: "string", - enum: ["theory", "improvement"], - description: "theory = knowledge fix; improvement = tools/skills/process" - }, - slug: str("Short filename stem"), - body: str("Full markdown body"), - date: str("Optional YYYY-MM-DD (default today)"), - overwrite: bool("Replace if the target file already exists") - } + kind: { + type: "string", + required: true, + enum: ["theory", "improvement"], + description: "theory = knowledge fix; improvement = tools/skills/process" + }, + slug: reqStr("Short filename stem"), + body: reqStr("Full markdown body"), + date: str("Optional YYYY-MM-DD (default today)"), + overwrite: bool("Replace if the target file already exists") }, (args) => createSuggestion(liveSnapshot(), { kind: args.kind, slug: String(args.slug ?? ""), @@ -770,38 +762,24 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbUpdateLocal", `Replace the body of an existing file under memories|drafts|suggestions ` + `(absolute path or path relative to ${localRoot}). ` + "Cannot touch identity/ or outside paths.local. Drafts keep status: draft.", { - type: "object", - additionalProperties: false, - required: ["path", "body"], - properties: { - path: str("Absolute path or path relative to KB local root"), - body: str("New full markdown body") - } + path: reqStr("Absolute path or path relative to KB local root"), + body: reqStr("New full markdown body") }, (args) => updateLocalFile(liveSnapshot(), { path: String(args.path ?? ""), body: String(args.body ?? "") })), tool("netx__kbDeleteLocal", `Delete one existing markdown under memories|drafts|suggestions ` + `(absolute or relative to ${localRoot}). Refuses identity/ and escapes.`, { - type: "object", - additionalProperties: false, - required: ["path"], - properties: { - path: str("Absolute path or path relative to KB local root") - } + path: reqStr("Absolute path or path relative to KB local root") }, (args) => deleteLocalFile(liveSnapshot(), { path: String(args.path ?? "") })), tool("netx__kbListLocal", `List recent .md files under ${localRoot} memories|drafts|suggestions (newest first). ` + "Does not include identity/. Read contents via absolute paths from the listing.", { - type: "object", - additionalProperties: false, - properties: { - root: { - type: "string", - enum: ["memories", "drafts", "suggestions", "all"], - description: "Subtree to list (default all writable)" - }, - limit: num("Max entries 1–200 (default 50)") - } + root: { + type: "string", + enum: ["memories", "drafts", "suggestions", "all"], + description: "Subtree to list (default all writable)" + }, + limit: num("Max entries 1–200 (default 50)") }, (args) => listLocalFiles(liveSnapshot(), { root: args.root ?? "all", limit: typeof args.limit === "number" ? args.limit : undefined diff --git a/lib/agent-tools-nms.js b/lib/agent-tools-nms.js index ec63a46..39829c8 100644 --- a/lib/agent-tools-nms.js +++ b/lib/agent-tools-nms.js @@ -672,6 +672,11 @@ function watchKbContext(listener) { var str = (description) => ({ type: "string", ...description ? { description } : {} }); var bool = (description) => ({ type: "boolean", ...description ? { description } : {} }); var num = (description) => ({ type: "number", ...description ? { description } : {} }); +var reqStr = (description) => ({ + type: "string", + required: true, + ...description ? { description } : {} +}); function renderJson(_args, value) { return [{ type: "text", text: JSON.stringify(value, null, 0) }]; } @@ -708,20 +713,16 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { return () => {}; const entries = [ tool("netx__kbWriteMemory", `Create (or overwrite) one diary-style memory markdown under ${localRoot}/memories/. ` + "bucket: note→日常笔记, rca_review→排障复盘, ai_trace→AI思维链. " + "Default create-only; set overwrite=true to replace same filename. " + "Do not use workspace Write — KB is outside the sandbox.", { - type: "object", - additionalProperties: false, - required: ["bucket", "slug", "body"], - properties: { - bucket: { - type: "string", - enum: ["note", "rca_review", "ai_trace"], - description: "Memory subdirectory" - }, - slug: str("Short filename stem (no path separators)"), - body: str("Full markdown body"), - date: str("Optional YYYY-MM-DD (default today)"), - overwrite: bool("Replace if the target file already exists") - } + bucket: { + type: "string", + required: true, + enum: ["note", "rca_review", "ai_trace"], + description: "Memory subdirectory" + }, + slug: reqStr("Short filename stem (no path separators)"), + body: reqStr("Full markdown body"), + date: str("Optional YYYY-MM-DD (default today)"), + overwrite: bool("Replace if the target file already exists") }, (args) => createMemory(liveSnapshot(), { bucket: args.bucket, slug: String(args.slug ?? ""), @@ -730,16 +731,11 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbWriteDraft", `Create (or overwrite) a DRAFT case under ${localRoot}/drafts/. ` + "Filename is forced to DRAFT-YYYYMMDD-…; body gets status: draft frontmatter if missing. " + "Set overwrite=true to replace. Not for identity/ or formal RCA.", { - type: "object", - additionalProperties: false, - required: ["slug", "body"], - properties: { - slug: str("Case stem (DRAFT- prefix added if missing)"), - body: str("Markdown body (RCA-ish draft)"), - domain: str("Optional fault-domain subfolder under drafts/"), - date: str("Optional event date YYYY-MM-DD or YYYYMMDD"), - overwrite: bool("Replace if the target file already exists") - } + slug: reqStr("Case stem (DRAFT- prefix added if missing)"), + body: reqStr("Markdown body (RCA-ish draft)"), + domain: str("Optional fault-domain subfolder under drafts/"), + date: str("Optional event date YYYY-MM-DD or YYYYMMDD"), + overwrite: bool("Replace if the target file already exists") }, (args) => createDraft(liveSnapshot(), { slug: String(args.slug ?? ""), body: String(args.body ?? ""), @@ -748,20 +744,16 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbWriteSuggestion", `Create (or overwrite) a suggestion under ${localRoot}/suggestions/{theory|improvement}/. ` + "Use for theory corrections or tool/process improvements — never rewrite identity/.", { - type: "object", - additionalProperties: false, - required: ["kind", "slug", "body"], - properties: { - kind: { - type: "string", - enum: ["theory", "improvement"], - description: "theory = knowledge fix; improvement = tools/skills/process" - }, - slug: str("Short filename stem"), - body: str("Full markdown body"), - date: str("Optional YYYY-MM-DD (default today)"), - overwrite: bool("Replace if the target file already exists") - } + kind: { + type: "string", + required: true, + enum: ["theory", "improvement"], + description: "theory = knowledge fix; improvement = tools/skills/process" + }, + slug: reqStr("Short filename stem"), + body: reqStr("Full markdown body"), + date: str("Optional YYYY-MM-DD (default today)"), + overwrite: bool("Replace if the target file already exists") }, (args) => createSuggestion(liveSnapshot(), { kind: args.kind, slug: String(args.slug ?? ""), @@ -770,38 +762,24 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbUpdateLocal", `Replace the body of an existing file under memories|drafts|suggestions ` + `(absolute path or path relative to ${localRoot}). ` + "Cannot touch identity/ or outside paths.local. Drafts keep status: draft.", { - type: "object", - additionalProperties: false, - required: ["path", "body"], - properties: { - path: str("Absolute path or path relative to KB local root"), - body: str("New full markdown body") - } + path: reqStr("Absolute path or path relative to KB local root"), + body: reqStr("New full markdown body") }, (args) => updateLocalFile(liveSnapshot(), { path: String(args.path ?? ""), body: String(args.body ?? "") })), tool("netx__kbDeleteLocal", `Delete one existing markdown under memories|drafts|suggestions ` + `(absolute or relative to ${localRoot}). Refuses identity/ and escapes.`, { - type: "object", - additionalProperties: false, - required: ["path"], - properties: { - path: str("Absolute path or path relative to KB local root") - } + path: reqStr("Absolute path or path relative to KB local root") }, (args) => deleteLocalFile(liveSnapshot(), { path: String(args.path ?? "") })), tool("netx__kbListLocal", `List recent .md files under ${localRoot} memories|drafts|suggestions (newest first). ` + "Does not include identity/. Read contents via absolute paths from the listing.", { - type: "object", - additionalProperties: false, - properties: { - root: { - type: "string", - enum: ["memories", "drafts", "suggestions", "all"], - description: "Subtree to list (default all writable)" - }, - limit: num("Max entries 1–200 (default 50)") - } + root: { + type: "string", + enum: ["memories", "drafts", "suggestions", "all"], + description: "Subtree to list (default all writable)" + }, + limit: num("Max entries 1–200 (default 50)") }, (args) => listLocalFiles(liveSnapshot(), { root: args.root ?? "all", limit: typeof args.limit === "number" ? args.limit : undefined diff --git a/lib/agent-tools-ops.js b/lib/agent-tools-ops.js index 0050eab..72b1002 100644 --- a/lib/agent-tools-ops.js +++ b/lib/agent-tools-ops.js @@ -672,6 +672,11 @@ function watchKbContext(listener) { var str = (description) => ({ type: "string", ...description ? { description } : {} }); var bool = (description) => ({ type: "boolean", ...description ? { description } : {} }); var num = (description) => ({ type: "number", ...description ? { description } : {} }); +var reqStr = (description) => ({ + type: "string", + required: true, + ...description ? { description } : {} +}); function renderJson(_args, value) { return [{ type: "text", text: JSON.stringify(value, null, 0) }]; } @@ -708,20 +713,16 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { return () => {}; const entries = [ tool("netx__kbWriteMemory", `Create (or overwrite) one diary-style memory markdown under ${localRoot}/memories/. ` + "bucket: note→日常笔记, rca_review→排障复盘, ai_trace→AI思维链. " + "Default create-only; set overwrite=true to replace same filename. " + "Do not use workspace Write — KB is outside the sandbox.", { - type: "object", - additionalProperties: false, - required: ["bucket", "slug", "body"], - properties: { - bucket: { - type: "string", - enum: ["note", "rca_review", "ai_trace"], - description: "Memory subdirectory" - }, - slug: str("Short filename stem (no path separators)"), - body: str("Full markdown body"), - date: str("Optional YYYY-MM-DD (default today)"), - overwrite: bool("Replace if the target file already exists") - } + bucket: { + type: "string", + required: true, + enum: ["note", "rca_review", "ai_trace"], + description: "Memory subdirectory" + }, + slug: reqStr("Short filename stem (no path separators)"), + body: reqStr("Full markdown body"), + date: str("Optional YYYY-MM-DD (default today)"), + overwrite: bool("Replace if the target file already exists") }, (args) => createMemory(liveSnapshot(), { bucket: args.bucket, slug: String(args.slug ?? ""), @@ -730,16 +731,11 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbWriteDraft", `Create (or overwrite) a DRAFT case under ${localRoot}/drafts/. ` + "Filename is forced to DRAFT-YYYYMMDD-…; body gets status: draft frontmatter if missing. " + "Set overwrite=true to replace. Not for identity/ or formal RCA.", { - type: "object", - additionalProperties: false, - required: ["slug", "body"], - properties: { - slug: str("Case stem (DRAFT- prefix added if missing)"), - body: str("Markdown body (RCA-ish draft)"), - domain: str("Optional fault-domain subfolder under drafts/"), - date: str("Optional event date YYYY-MM-DD or YYYYMMDD"), - overwrite: bool("Replace if the target file already exists") - } + slug: reqStr("Case stem (DRAFT- prefix added if missing)"), + body: reqStr("Markdown body (RCA-ish draft)"), + domain: str("Optional fault-domain subfolder under drafts/"), + date: str("Optional event date YYYY-MM-DD or YYYYMMDD"), + overwrite: bool("Replace if the target file already exists") }, (args) => createDraft(liveSnapshot(), { slug: String(args.slug ?? ""), body: String(args.body ?? ""), @@ -748,20 +744,16 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbWriteSuggestion", `Create (or overwrite) a suggestion under ${localRoot}/suggestions/{theory|improvement}/. ` + "Use for theory corrections or tool/process improvements — never rewrite identity/.", { - type: "object", - additionalProperties: false, - required: ["kind", "slug", "body"], - properties: { - kind: { - type: "string", - enum: ["theory", "improvement"], - description: "theory = knowledge fix; improvement = tools/skills/process" - }, - slug: str("Short filename stem"), - body: str("Full markdown body"), - date: str("Optional YYYY-MM-DD (default today)"), - overwrite: bool("Replace if the target file already exists") - } + kind: { + type: "string", + required: true, + enum: ["theory", "improvement"], + description: "theory = knowledge fix; improvement = tools/skills/process" + }, + slug: reqStr("Short filename stem"), + body: reqStr("Full markdown body"), + date: str("Optional YYYY-MM-DD (default today)"), + overwrite: bool("Replace if the target file already exists") }, (args) => createSuggestion(liveSnapshot(), { kind: args.kind, slug: String(args.slug ?? ""), @@ -770,38 +762,24 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbUpdateLocal", `Replace the body of an existing file under memories|drafts|suggestions ` + `(absolute path or path relative to ${localRoot}). ` + "Cannot touch identity/ or outside paths.local. Drafts keep status: draft.", { - type: "object", - additionalProperties: false, - required: ["path", "body"], - properties: { - path: str("Absolute path or path relative to KB local root"), - body: str("New full markdown body") - } + path: reqStr("Absolute path or path relative to KB local root"), + body: reqStr("New full markdown body") }, (args) => updateLocalFile(liveSnapshot(), { path: String(args.path ?? ""), body: String(args.body ?? "") })), tool("netx__kbDeleteLocal", `Delete one existing markdown under memories|drafts|suggestions ` + `(absolute or relative to ${localRoot}). Refuses identity/ and escapes.`, { - type: "object", - additionalProperties: false, - required: ["path"], - properties: { - path: str("Absolute path or path relative to KB local root") - } + path: reqStr("Absolute path or path relative to KB local root") }, (args) => deleteLocalFile(liveSnapshot(), { path: String(args.path ?? "") })), tool("netx__kbListLocal", `List recent .md files under ${localRoot} memories|drafts|suggestions (newest first). ` + "Does not include identity/. Read contents via absolute paths from the listing.", { - type: "object", - additionalProperties: false, - properties: { - root: { - type: "string", - enum: ["memories", "drafts", "suggestions", "all"], - description: "Subtree to list (default all writable)" - }, - limit: num("Max entries 1–200 (default 50)") - } + root: { + type: "string", + enum: ["memories", "drafts", "suggestions", "all"], + description: "Subtree to list (default all writable)" + }, + limit: num("Max entries 1–200 (default 50)") }, (args) => listLocalFiles(liveSnapshot(), { root: args.root ?? "all", limit: typeof args.limit === "number" ? args.limit : undefined diff --git a/lib/agent-tools-topology.js b/lib/agent-tools-topology.js index f709df5..c9d1803 100644 --- a/lib/agent-tools-topology.js +++ b/lib/agent-tools-topology.js @@ -672,6 +672,11 @@ function watchKbContext(listener) { var str = (description) => ({ type: "string", ...description ? { description } : {} }); var bool = (description) => ({ type: "boolean", ...description ? { description } : {} }); var num = (description) => ({ type: "number", ...description ? { description } : {} }); +var reqStr = (description) => ({ + type: "string", + required: true, + ...description ? { description } : {} +}); function renderJson(_args, value) { return [{ type: "text", text: JSON.stringify(value, null, 0) }]; } @@ -708,20 +713,16 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { return () => {}; const entries = [ tool("netx__kbWriteMemory", `Create (or overwrite) one diary-style memory markdown under ${localRoot}/memories/. ` + "bucket: note→日常笔记, rca_review→排障复盘, ai_trace→AI思维链. " + "Default create-only; set overwrite=true to replace same filename. " + "Do not use workspace Write — KB is outside the sandbox.", { - type: "object", - additionalProperties: false, - required: ["bucket", "slug", "body"], - properties: { - bucket: { - type: "string", - enum: ["note", "rca_review", "ai_trace"], - description: "Memory subdirectory" - }, - slug: str("Short filename stem (no path separators)"), - body: str("Full markdown body"), - date: str("Optional YYYY-MM-DD (default today)"), - overwrite: bool("Replace if the target file already exists") - } + bucket: { + type: "string", + required: true, + enum: ["note", "rca_review", "ai_trace"], + description: "Memory subdirectory" + }, + slug: reqStr("Short filename stem (no path separators)"), + body: reqStr("Full markdown body"), + date: str("Optional YYYY-MM-DD (default today)"), + overwrite: bool("Replace if the target file already exists") }, (args) => createMemory(liveSnapshot(), { bucket: args.bucket, slug: String(args.slug ?? ""), @@ -730,16 +731,11 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbWriteDraft", `Create (or overwrite) a DRAFT case under ${localRoot}/drafts/. ` + "Filename is forced to DRAFT-YYYYMMDD-…; body gets status: draft frontmatter if missing. " + "Set overwrite=true to replace. Not for identity/ or formal RCA.", { - type: "object", - additionalProperties: false, - required: ["slug", "body"], - properties: { - slug: str("Case stem (DRAFT- prefix added if missing)"), - body: str("Markdown body (RCA-ish draft)"), - domain: str("Optional fault-domain subfolder under drafts/"), - date: str("Optional event date YYYY-MM-DD or YYYYMMDD"), - overwrite: bool("Replace if the target file already exists") - } + slug: reqStr("Case stem (DRAFT- prefix added if missing)"), + body: reqStr("Markdown body (RCA-ish draft)"), + domain: str("Optional fault-domain subfolder under drafts/"), + date: str("Optional event date YYYY-MM-DD or YYYYMMDD"), + overwrite: bool("Replace if the target file already exists") }, (args) => createDraft(liveSnapshot(), { slug: String(args.slug ?? ""), body: String(args.body ?? ""), @@ -748,20 +744,16 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbWriteSuggestion", `Create (or overwrite) a suggestion under ${localRoot}/suggestions/{theory|improvement}/. ` + "Use for theory corrections or tool/process improvements — never rewrite identity/.", { - type: "object", - additionalProperties: false, - required: ["kind", "slug", "body"], - properties: { - kind: { - type: "string", - enum: ["theory", "improvement"], - description: "theory = knowledge fix; improvement = tools/skills/process" - }, - slug: str("Short filename stem"), - body: str("Full markdown body"), - date: str("Optional YYYY-MM-DD (default today)"), - overwrite: bool("Replace if the target file already exists") - } + kind: { + type: "string", + required: true, + enum: ["theory", "improvement"], + description: "theory = knowledge fix; improvement = tools/skills/process" + }, + slug: reqStr("Short filename stem"), + body: reqStr("Full markdown body"), + date: str("Optional YYYY-MM-DD (default today)"), + overwrite: bool("Replace if the target file already exists") }, (args) => createSuggestion(liveSnapshot(), { kind: args.kind, slug: String(args.slug ?? ""), @@ -770,38 +762,24 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbUpdateLocal", `Replace the body of an existing file under memories|drafts|suggestions ` + `(absolute path or path relative to ${localRoot}). ` + "Cannot touch identity/ or outside paths.local. Drafts keep status: draft.", { - type: "object", - additionalProperties: false, - required: ["path", "body"], - properties: { - path: str("Absolute path or path relative to KB local root"), - body: str("New full markdown body") - } + path: reqStr("Absolute path or path relative to KB local root"), + body: reqStr("New full markdown body") }, (args) => updateLocalFile(liveSnapshot(), { path: String(args.path ?? ""), body: String(args.body ?? "") })), tool("netx__kbDeleteLocal", `Delete one existing markdown under memories|drafts|suggestions ` + `(absolute or relative to ${localRoot}). Refuses identity/ and escapes.`, { - type: "object", - additionalProperties: false, - required: ["path"], - properties: { - path: str("Absolute path or path relative to KB local root") - } + path: reqStr("Absolute path or path relative to KB local root") }, (args) => deleteLocalFile(liveSnapshot(), { path: String(args.path ?? "") })), tool("netx__kbListLocal", `List recent .md files under ${localRoot} memories|drafts|suggestions (newest first). ` + "Does not include identity/. Read contents via absolute paths from the listing.", { - type: "object", - additionalProperties: false, - properties: { - root: { - type: "string", - enum: ["memories", "drafts", "suggestions", "all"], - description: "Subtree to list (default all writable)" - }, - limit: num("Max entries 1–200 (default 50)") - } + root: { + type: "string", + enum: ["memories", "drafts", "suggestions", "all"], + description: "Subtree to list (default all writable)" + }, + limit: num("Max entries 1–200 (default 50)") }, (args) => listLocalFiles(liveSnapshot(), { root: args.root ?? "all", limit: typeof args.limit === "number" ? args.limit : undefined diff --git a/lib/agent-tools.js b/lib/agent-tools.js index ff64468..6faf0f6 100644 --- a/lib/agent-tools.js +++ b/lib/agent-tools.js @@ -672,6 +672,11 @@ function watchKbContext(listener) { var str = (description) => ({ type: "string", ...description ? { description } : {} }); var bool = (description) => ({ type: "boolean", ...description ? { description } : {} }); var num = (description) => ({ type: "number", ...description ? { description } : {} }); +var reqStr = (description) => ({ + type: "string", + required: true, + ...description ? { description } : {} +}); function renderJson(_args, value) { return [{ type: "text", text: JSON.stringify(value, null, 0) }]; } @@ -708,20 +713,16 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { return () => {}; const entries = [ tool("netx__kbWriteMemory", `Create (or overwrite) one diary-style memory markdown under ${localRoot}/memories/. ` + "bucket: note→日常笔记, rca_review→排障复盘, ai_trace→AI思维链. " + "Default create-only; set overwrite=true to replace same filename. " + "Do not use workspace Write — KB is outside the sandbox.", { - type: "object", - additionalProperties: false, - required: ["bucket", "slug", "body"], - properties: { - bucket: { - type: "string", - enum: ["note", "rca_review", "ai_trace"], - description: "Memory subdirectory" - }, - slug: str("Short filename stem (no path separators)"), - body: str("Full markdown body"), - date: str("Optional YYYY-MM-DD (default today)"), - overwrite: bool("Replace if the target file already exists") - } + bucket: { + type: "string", + required: true, + enum: ["note", "rca_review", "ai_trace"], + description: "Memory subdirectory" + }, + slug: reqStr("Short filename stem (no path separators)"), + body: reqStr("Full markdown body"), + date: str("Optional YYYY-MM-DD (default today)"), + overwrite: bool("Replace if the target file already exists") }, (args) => createMemory(liveSnapshot(), { bucket: args.bucket, slug: String(args.slug ?? ""), @@ -730,16 +731,11 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbWriteDraft", `Create (or overwrite) a DRAFT case under ${localRoot}/drafts/. ` + "Filename is forced to DRAFT-YYYYMMDD-…; body gets status: draft frontmatter if missing. " + "Set overwrite=true to replace. Not for identity/ or formal RCA.", { - type: "object", - additionalProperties: false, - required: ["slug", "body"], - properties: { - slug: str("Case stem (DRAFT- prefix added if missing)"), - body: str("Markdown body (RCA-ish draft)"), - domain: str("Optional fault-domain subfolder under drafts/"), - date: str("Optional event date YYYY-MM-DD or YYYYMMDD"), - overwrite: bool("Replace if the target file already exists") - } + slug: reqStr("Case stem (DRAFT- prefix added if missing)"), + body: reqStr("Markdown body (RCA-ish draft)"), + domain: str("Optional fault-domain subfolder under drafts/"), + date: str("Optional event date YYYY-MM-DD or YYYYMMDD"), + overwrite: bool("Replace if the target file already exists") }, (args) => createDraft(liveSnapshot(), { slug: String(args.slug ?? ""), body: String(args.body ?? ""), @@ -748,20 +744,16 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbWriteSuggestion", `Create (or overwrite) a suggestion under ${localRoot}/suggestions/{theory|improvement}/. ` + "Use for theory corrections or tool/process improvements — never rewrite identity/.", { - type: "object", - additionalProperties: false, - required: ["kind", "slug", "body"], - properties: { - kind: { - type: "string", - enum: ["theory", "improvement"], - description: "theory = knowledge fix; improvement = tools/skills/process" - }, - slug: str("Short filename stem"), - body: str("Full markdown body"), - date: str("Optional YYYY-MM-DD (default today)"), - overwrite: bool("Replace if the target file already exists") - } + kind: { + type: "string", + required: true, + enum: ["theory", "improvement"], + description: "theory = knowledge fix; improvement = tools/skills/process" + }, + slug: reqStr("Short filename stem"), + body: reqStr("Full markdown body"), + date: str("Optional YYYY-MM-DD (default today)"), + overwrite: bool("Replace if the target file already exists") }, (args) => createSuggestion(liveSnapshot(), { kind: args.kind, slug: String(args.slug ?? ""), @@ -770,38 +762,24 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbUpdateLocal", `Replace the body of an existing file under memories|drafts|suggestions ` + `(absolute path or path relative to ${localRoot}). ` + "Cannot touch identity/ or outside paths.local. Drafts keep status: draft.", { - type: "object", - additionalProperties: false, - required: ["path", "body"], - properties: { - path: str("Absolute path or path relative to KB local root"), - body: str("New full markdown body") - } + path: reqStr("Absolute path or path relative to KB local root"), + body: reqStr("New full markdown body") }, (args) => updateLocalFile(liveSnapshot(), { path: String(args.path ?? ""), body: String(args.body ?? "") })), tool("netx__kbDeleteLocal", `Delete one existing markdown under memories|drafts|suggestions ` + `(absolute or relative to ${localRoot}). Refuses identity/ and escapes.`, { - type: "object", - additionalProperties: false, - required: ["path"], - properties: { - path: str("Absolute path or path relative to KB local root") - } + path: reqStr("Absolute path or path relative to KB local root") }, (args) => deleteLocalFile(liveSnapshot(), { path: String(args.path ?? "") })), tool("netx__kbListLocal", `List recent .md files under ${localRoot} memories|drafts|suggestions (newest first). ` + "Does not include identity/. Read contents via absolute paths from the listing.", { - type: "object", - additionalProperties: false, - properties: { - root: { - type: "string", - enum: ["memories", "drafts", "suggestions", "all"], - description: "Subtree to list (default all writable)" - }, - limit: num("Max entries 1–200 (default 50)") - } + root: { + type: "string", + enum: ["memories", "drafts", "suggestions", "all"], + description: "Subtree to list (default all writable)" + }, + limit: num("Max entries 1–200 (default 50)") }, (args) => listLocalFiles(liveSnapshot(), { root: args.root ?? "all", limit: typeof args.limit === "number" ? args.limit : undefined diff --git a/lib/index.js b/lib/index.js index bf912fd..bbe596d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1526,6 +1526,11 @@ function resetKbContext() { var str = (description) => ({ type: "string", ...description ? { description } : {} }); var bool = (description) => ({ type: "boolean", ...description ? { description } : {} }); var num = (description) => ({ type: "number", ...description ? { description } : {} }); +var reqStr = (description) => ({ + type: "string", + required: true, + ...description ? { description } : {} +}); function renderJson(_args, value) { return [{ type: "text", text: JSON.stringify(value, null, 0) }]; } @@ -1562,20 +1567,16 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { return () => {}; const entries = [ tool("netx__kbWriteMemory", `Create (or overwrite) one diary-style memory markdown under ${localRoot}/memories/. ` + "bucket: note→日常笔记, rca_review→排障复盘, ai_trace→AI思维链. " + "Default create-only; set overwrite=true to replace same filename. " + "Do not use workspace Write — KB is outside the sandbox.", { - type: "object", - additionalProperties: false, - required: ["bucket", "slug", "body"], - properties: { - bucket: { - type: "string", - enum: ["note", "rca_review", "ai_trace"], - description: "Memory subdirectory" - }, - slug: str("Short filename stem (no path separators)"), - body: str("Full markdown body"), - date: str("Optional YYYY-MM-DD (default today)"), - overwrite: bool("Replace if the target file already exists") - } + bucket: { + type: "string", + required: true, + enum: ["note", "rca_review", "ai_trace"], + description: "Memory subdirectory" + }, + slug: reqStr("Short filename stem (no path separators)"), + body: reqStr("Full markdown body"), + date: str("Optional YYYY-MM-DD (default today)"), + overwrite: bool("Replace if the target file already exists") }, (args) => createMemory(liveSnapshot(), { bucket: args.bucket, slug: String(args.slug ?? ""), @@ -1584,16 +1585,11 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbWriteDraft", `Create (or overwrite) a DRAFT case under ${localRoot}/drafts/. ` + "Filename is forced to DRAFT-YYYYMMDD-…; body gets status: draft frontmatter if missing. " + "Set overwrite=true to replace. Not for identity/ or formal RCA.", { - type: "object", - additionalProperties: false, - required: ["slug", "body"], - properties: { - slug: str("Case stem (DRAFT- prefix added if missing)"), - body: str("Markdown body (RCA-ish draft)"), - domain: str("Optional fault-domain subfolder under drafts/"), - date: str("Optional event date YYYY-MM-DD or YYYYMMDD"), - overwrite: bool("Replace if the target file already exists") - } + slug: reqStr("Case stem (DRAFT- prefix added if missing)"), + body: reqStr("Markdown body (RCA-ish draft)"), + domain: str("Optional fault-domain subfolder under drafts/"), + date: str("Optional event date YYYY-MM-DD or YYYYMMDD"), + overwrite: bool("Replace if the target file already exists") }, (args) => createDraft(liveSnapshot(), { slug: String(args.slug ?? ""), body: String(args.body ?? ""), @@ -1602,20 +1598,16 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbWriteSuggestion", `Create (or overwrite) a suggestion under ${localRoot}/suggestions/{theory|improvement}/. ` + "Use for theory corrections or tool/process improvements — never rewrite identity/.", { - type: "object", - additionalProperties: false, - required: ["kind", "slug", "body"], - properties: { - kind: { - type: "string", - enum: ["theory", "improvement"], - description: "theory = knowledge fix; improvement = tools/skills/process" - }, - slug: str("Short filename stem"), - body: str("Full markdown body"), - date: str("Optional YYYY-MM-DD (default today)"), - overwrite: bool("Replace if the target file already exists") - } + kind: { + type: "string", + required: true, + enum: ["theory", "improvement"], + description: "theory = knowledge fix; improvement = tools/skills/process" + }, + slug: reqStr("Short filename stem"), + body: reqStr("Full markdown body"), + date: str("Optional YYYY-MM-DD (default today)"), + overwrite: bool("Replace if the target file already exists") }, (args) => createSuggestion(liveSnapshot(), { kind: args.kind, slug: String(args.slug ?? ""), @@ -1624,38 +1616,24 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) { overwrite: args.overwrite === true })), tool("netx__kbUpdateLocal", `Replace the body of an existing file under memories|drafts|suggestions ` + `(absolute path or path relative to ${localRoot}). ` + "Cannot touch identity/ or outside paths.local. Drafts keep status: draft.", { - type: "object", - additionalProperties: false, - required: ["path", "body"], - properties: { - path: str("Absolute path or path relative to KB local root"), - body: str("New full markdown body") - } + path: reqStr("Absolute path or path relative to KB local root"), + body: reqStr("New full markdown body") }, (args) => updateLocalFile(liveSnapshot(), { path: String(args.path ?? ""), body: String(args.body ?? "") })), tool("netx__kbDeleteLocal", `Delete one existing markdown under memories|drafts|suggestions ` + `(absolute or relative to ${localRoot}). Refuses identity/ and escapes.`, { - type: "object", - additionalProperties: false, - required: ["path"], - properties: { - path: str("Absolute path or path relative to KB local root") - } + path: reqStr("Absolute path or path relative to KB local root") }, (args) => deleteLocalFile(liveSnapshot(), { path: String(args.path ?? "") })), tool("netx__kbListLocal", `List recent .md files under ${localRoot} memories|drafts|suggestions (newest first). ` + "Does not include identity/. Read contents via absolute paths from the listing.", { - type: "object", - additionalProperties: false, - properties: { - root: { - type: "string", - enum: ["memories", "drafts", "suggestions", "all"], - description: "Subtree to list (default all writable)" - }, - limit: num("Max entries 1–200 (default 50)") - } + root: { + type: "string", + enum: ["memories", "drafts", "suggestions", "all"], + description: "Subtree to list (default all writable)" + }, + limit: num("Max entries 1–200 (default 50)") }, (args) => listLocalFiles(liveSnapshot(), { root: args.root ?? "all", limit: typeof args.limit === "number" ? args.limit : undefined diff --git a/package.json b/package.json index e78849d..3b75b50 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dsh-netxops", - "version": "0.1.34", + "version": "0.1.35", "description": "DeepSeek Harness Netx Ops: ops/topology + IM delivery + session export + knowledge-base MANIFEST/_skills + localSkills", "license": "MIT", "type": "module", diff --git a/src/netx/kb-local-tools.ts b/src/netx/kb-local-tools.ts index 57ce322..77ff825 100644 --- a/src/netx/kb-local-tools.ts +++ b/src/netx/kb-local-tools.ts @@ -20,6 +20,11 @@ import { getKbContext } from './kb-runtime.ts' const str = (description?: string) => ({ type: 'string' as const, ...(description ? { description } : {}) }) const bool = (description?: string) => ({ type: 'boolean' as const, ...(description ? { description } : {}) }) const num = (description?: string) => ({ type: 'number' as const, ...(description ? { description } : {}) }) +const reqStr = (description?: string) => ({ + type: 'string' as const, + required: true as const, + ...(description ? { description } : {}), +}) function renderJson(_args: unknown, value: unknown) { return [{ type: 'text' as const, text: JSON.stringify(value, null, 0) }] @@ -37,6 +42,7 @@ function liveSnapshot(): KbSnapshot { function tool( name: string, description: string, + /** DSH `defineTool` expects a flat property map — not a full JSON Schema object. */ parameters: Record, execute: (args: Record) => Promise | unknown, ) { @@ -79,20 +85,16 @@ export function registerKbLocalTools( + 'Default create-only; set overwrite=true to replace same filename. ' + 'Do not use workspace Write — KB is outside the sandbox.', { - type: 'object', - additionalProperties: false, - required: ['bucket', 'slug', 'body'], - properties: { - bucket: { - type: 'string', - enum: ['note', 'rca_review', 'ai_trace'], - description: 'Memory subdirectory', - }, - slug: str('Short filename stem (no path separators)'), - body: str('Full markdown body'), - date: str('Optional YYYY-MM-DD (default today)'), - overwrite: bool('Replace if the target file already exists'), + bucket: { + type: 'string' as const, + required: true as const, + enum: ['note', 'rca_review', 'ai_trace'], + description: 'Memory subdirectory', }, + slug: reqStr('Short filename stem (no path separators)'), + body: reqStr('Full markdown body'), + date: str('Optional YYYY-MM-DD (default today)'), + overwrite: bool('Replace if the target file already exists'), }, (args) => createMemory(liveSnapshot(), { bucket: args.bucket as 'note' | 'rca_review' | 'ai_trace', @@ -108,16 +110,11 @@ export function registerKbLocalTools( + 'Filename is forced to DRAFT-YYYYMMDD-…; body gets status: draft frontmatter if missing. ' + 'Set overwrite=true to replace. Not for identity/ or formal RCA.', { - type: 'object', - additionalProperties: false, - required: ['slug', 'body'], - properties: { - slug: str('Case stem (DRAFT- prefix added if missing)'), - body: str('Markdown body (RCA-ish draft)'), - domain: str('Optional fault-domain subfolder under drafts/'), - date: str('Optional event date YYYY-MM-DD or YYYYMMDD'), - overwrite: bool('Replace if the target file already exists'), - }, + slug: reqStr('Case stem (DRAFT- prefix added if missing)'), + body: reqStr('Markdown body (RCA-ish draft)'), + domain: str('Optional fault-domain subfolder under drafts/'), + date: str('Optional event date YYYY-MM-DD or YYYYMMDD'), + overwrite: bool('Replace if the target file already exists'), }, (args) => createDraft(liveSnapshot(), { slug: String(args.slug ?? ''), @@ -132,20 +129,16 @@ export function registerKbLocalTools( `Create (or overwrite) a suggestion under ${localRoot}/suggestions/{theory|improvement}/. ` + 'Use for theory corrections or tool/process improvements — never rewrite identity/.', { - type: 'object', - additionalProperties: false, - required: ['kind', 'slug', 'body'], - properties: { - kind: { - type: 'string', - enum: ['theory', 'improvement'], - description: 'theory = knowledge fix; improvement = tools/skills/process', - }, - slug: str('Short filename stem'), - body: str('Full markdown body'), - date: str('Optional YYYY-MM-DD (default today)'), - overwrite: bool('Replace if the target file already exists'), + kind: { + type: 'string' as const, + required: true as const, + enum: ['theory', 'improvement'], + description: 'theory = knowledge fix; improvement = tools/skills/process', }, + slug: reqStr('Short filename stem'), + body: reqStr('Full markdown body'), + date: str('Optional YYYY-MM-DD (default today)'), + overwrite: bool('Replace if the target file already exists'), }, (args) => createSuggestion(liveSnapshot(), { kind: args.kind as 'theory' | 'improvement', @@ -161,13 +154,8 @@ export function registerKbLocalTools( + `(absolute path or path relative to ${localRoot}). ` + 'Cannot touch identity/ or outside paths.local. Drafts keep status: draft.', { - type: 'object', - additionalProperties: false, - required: ['path', 'body'], - properties: { - path: str('Absolute path or path relative to KB local root'), - body: str('New full markdown body'), - }, + path: reqStr('Absolute path or path relative to KB local root'), + body: reqStr('New full markdown body'), }, (args) => updateLocalFile(liveSnapshot(), { path: String(args.path ?? ''), @@ -179,12 +167,7 @@ export function registerKbLocalTools( `Delete one existing markdown under memories|drafts|suggestions ` + `(absolute or relative to ${localRoot}). Refuses identity/ and escapes.`, { - type: 'object', - additionalProperties: false, - required: ['path'], - properties: { - path: str('Absolute path or path relative to KB local root'), - }, + path: reqStr('Absolute path or path relative to KB local root'), }, (args) => deleteLocalFile(liveSnapshot(), { path: String(args.path ?? ''), @@ -195,16 +178,12 @@ export function registerKbLocalTools( `List recent .md files under ${localRoot} memories|drafts|suggestions (newest first). ` + 'Does not include identity/. Read contents via absolute paths from the listing.', { - type: 'object', - additionalProperties: false, - properties: { - root: { - type: 'string', - enum: ['memories', 'drafts', 'suggestions', 'all'], - description: 'Subtree to list (default all writable)', - }, - limit: num('Max entries 1–200 (default 50)'), + root: { + type: 'string' as const, + enum: ['memories', 'drafts', 'suggestions', 'all'], + description: 'Subtree to list (default all writable)', }, + limit: num('Max entries 1–200 (default 50)'), }, (args) => listLocalFiles(liveSnapshot(), { root: (args.root as 'memories' | 'drafts' | 'suggestions' | 'all' | undefined) ?? 'all',