@basicmemory/openclaw-basic-memory 0.24.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -12
- package/bm-client.ts +302 -112
- package/commands/cli.ts +5 -6
- package/commands/slash.ts +4 -4
- package/context-engine/basic-memory-context-engine.ts +74 -9
- package/context-engine/types.ts +21 -0
- package/dist/bm-client.d.ts +61 -12
- package/dist/bm-client.js +250 -101
- package/dist/commands/cli.d.ts +1 -1
- package/dist/commands/cli.js +5 -5
- package/dist/commands/slash.d.ts +1 -1
- package/dist/commands/slash.js +4 -3
- package/dist/context-engine/basic-memory-context-engine.d.ts +20 -1
- package/dist/context-engine/basic-memory-context-engine.js +50 -2
- package/dist/context-engine/types.d.ts +9 -0
- package/dist/context-engine/types.js +1 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.js +79 -69
- package/dist/memory/basic-memory-capability.d.ts +19 -0
- package/dist/memory/basic-memory-capability.js +190 -0
- package/dist/tools/build-context.d.ts +1 -1
- package/dist/tools/build-context.js +12 -4
- package/dist/tools/delete-note.d.ts +1 -1
- package/dist/tools/delete-note.js +2 -1
- package/dist/tools/edit-note.d.ts +1 -1
- package/dist/tools/edit-note.js +22 -12
- package/dist/tools/list-memory-projects.d.ts +1 -1
- package/dist/tools/list-memory-projects.js +2 -1
- package/dist/tools/list-workspaces.d.ts +1 -1
- package/dist/tools/list-workspaces.js +4 -4
- package/dist/tools/move-note.d.ts +1 -1
- package/dist/tools/move-note.js +2 -1
- package/dist/tools/read-note.d.ts +1 -1
- package/dist/tools/read-note.js +2 -1
- package/dist/tools/schema-diff.d.ts +1 -1
- package/dist/tools/schema-diff.js +2 -1
- package/dist/tools/schema-infer.d.ts +1 -1
- package/dist/tools/schema-infer.js +2 -1
- package/dist/tools/schema-validate.d.ts +1 -1
- package/dist/tools/schema-validate.js +2 -1
- package/dist/tools/search-notes.d.ts +1 -1
- package/dist/tools/search-notes.js +13 -6
- package/dist/tools/write-note.d.ts +1 -1
- package/dist/tools/write-note.js +11 -12
- package/index.ts +93 -84
- package/memory/basic-memory-capability.ts +253 -0
- package/openclaw.plugin.json +0 -2
- package/package.json +6 -5
- package/skills/manifest.json +5 -0
- package/skills/memory-agents/SKILL.md +23 -10
- package/skills/memory-capture/SKILL.md +29 -18
- package/skills/memory-comark/SKILL.md +17 -6
- package/skills/memory-continue/SKILL.md +47 -27
- package/skills/memory-curate/SKILL.md +40 -24
- package/skills/memory-defrag/SKILL.md +18 -7
- package/skills/memory-doctor/SKILL.md +93 -0
- package/skills/memory-ingest/SKILL.md +33 -17
- package/skills/memory-lifecycle/SKILL.md +35 -22
- package/skills/memory-literary-analysis/SKILL.md +112 -75
- package/skills/memory-metadata-search/SKILL.md +39 -28
- package/skills/memory-notes/SKILL.md +75 -50
- package/skills/memory-okf/SKILL.md +27 -15
- package/skills/memory-onboarding/SKILL.md +20 -9
- package/skills/memory-onboarding/references/assistant-setup.md +1 -1
- package/skills/memory-onboarding/references/conventions.md +4 -4
- package/skills/memory-onboarding/references/domain-playbooks.md +1 -1
- package/skills/memory-onboarding/references/schema-guide.md +9 -8
- package/skills/memory-quest/SKILL.md +18 -7
- package/skills/memory-reflect/SKILL.md +25 -13
- package/skills/memory-research/SKILL.md +28 -13
- package/skills/memory-schema/SKILL.md +36 -24
- package/skills/memory-tasks/SKILL.md +34 -22
- package/tools/build-context.ts +14 -5
- package/tools/delete-note.ts +2 -2
- package/tools/edit-note.ts +27 -14
- package/tools/list-memory-projects.ts +6 -2
- package/tools/list-workspaces.ts +8 -5
- package/tools/move-note.ts +2 -2
- package/tools/read-note.ts +2 -2
- package/tools/schema-diff.ts +2 -2
- package/tools/schema-infer.ts +2 -2
- package/tools/schema-validate.ts +2 -2
- package/tools/search-notes.ts +18 -7
- package/tools/write-note.ts +12 -12
- package/dist/tools/memory-provider.d.ts +0 -15
- package/dist/tools/memory-provider.js +0 -275
- package/tools/memory-provider.ts +0 -336
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { describeToolError } from "../bm-client.js";
|
|
2
3
|
import { log } from "../logger.js";
|
|
3
4
|
export function registerContextTool(api, client) {
|
|
4
5
|
api.registerTool({
|
|
@@ -42,8 +43,13 @@ export function registerContextTool(api, client) {
|
|
|
42
43
|
for (const result of ctx.results) {
|
|
43
44
|
const primary = result.primary_result;
|
|
44
45
|
sections.push(`## ${primary.title}\n${primary.content}`);
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
// The note body already contains its observations as
|
|
47
|
+
// "- [category] text" lines, so listing them again doubled the
|
|
48
|
+
// output. Only observations missing from the shown body (for
|
|
49
|
+
// example when the server truncates a long note) are listed.
|
|
50
|
+
const unseen = (result.observations ?? []).filter((o) => !primary.content?.includes(`[${o.category}] ${o.content}`));
|
|
51
|
+
if (unseen.length > 0) {
|
|
52
|
+
const obs = unseen
|
|
47
53
|
.map((o) => `- [${o.category}] ${o.content}`)
|
|
48
54
|
.join("\n");
|
|
49
55
|
sections.push(`### Observations\n${obs}`);
|
|
@@ -52,7 +58,9 @@ export function registerContextTool(api, client) {
|
|
|
52
58
|
const rels = result.related_results
|
|
53
59
|
.map((r) => {
|
|
54
60
|
if (r.type === "relation") {
|
|
55
|
-
return
|
|
61
|
+
return r.to_entity
|
|
62
|
+
? `- ${r.relation_type} → **${r.to_entity}**`
|
|
63
|
+
: `- ${r.relation_type} → **${r.to_name ?? "unknown"}** (no note yet)`;
|
|
56
64
|
}
|
|
57
65
|
const label = r.relation_type
|
|
58
66
|
? `${r.relation_type} → **${r.title}**`
|
|
@@ -85,7 +93,7 @@ export function registerContextTool(api, client) {
|
|
|
85
93
|
content: [
|
|
86
94
|
{
|
|
87
95
|
type: "text",
|
|
88
|
-
text: `Failed to build context for "${params.url}"
|
|
96
|
+
text: `Failed to build context for "${params.url}": ${describeToolError(err)}`,
|
|
89
97
|
},
|
|
90
98
|
],
|
|
91
99
|
details: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { describeNoteError } from "../bm-client.js";
|
|
2
3
|
import { log } from "../logger.js";
|
|
3
4
|
export function registerDeleteTool(api, client) {
|
|
4
5
|
api.registerTool({
|
|
@@ -38,7 +39,7 @@ export function registerDeleteTool(api, client) {
|
|
|
38
39
|
content: [
|
|
39
40
|
{
|
|
40
41
|
type: "text",
|
|
41
|
-
text: `Failed to delete "${params.identifier}"
|
|
42
|
+
text: `Failed to delete "${params.identifier}": ${describeNoteError(err)}`,
|
|
42
43
|
},
|
|
43
44
|
],
|
|
44
45
|
details: {
|
package/dist/tools/edit-note.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { describeNoteError, } from "../bm-client.js";
|
|
2
3
|
import { log } from "../logger.js";
|
|
3
4
|
export function registerEditTool(api, client) {
|
|
4
5
|
api.registerTool({
|
|
5
6
|
name: "edit_note",
|
|
6
7
|
label: "Edit Note",
|
|
7
8
|
description: "Incrementally edit an existing note in the Basic Memory knowledge graph. " +
|
|
8
|
-
"Supports append, prepend, find/replace,
|
|
9
|
-
"without rewriting the entire note.
|
|
9
|
+
"Supports append, prepend, find/replace, replacing a section, and inserting " +
|
|
10
|
+
"next to a section heading, without rewriting the entire note. To add to a " +
|
|
11
|
+
"specific section (for example a new observation), use insert_after_section " +
|
|
12
|
+
"with that heading; append always adds to the very end of the note. " +
|
|
13
|
+
"The result returns the note's " +
|
|
10
14
|
"permalink and file_path: cite those exact values when confirming " +
|
|
11
15
|
"the edit — never report a save that no tool call performed.",
|
|
12
16
|
parameters: Type.Object({
|
|
@@ -18,9 +22,13 @@ export function registerEditTool(api, client) {
|
|
|
18
22
|
Type.Literal("prepend"),
|
|
19
23
|
Type.Literal("find_replace"),
|
|
20
24
|
Type.Literal("replace_section"),
|
|
25
|
+
Type.Literal("insert_before_section"),
|
|
26
|
+
Type.Literal("insert_after_section"),
|
|
21
27
|
], {
|
|
22
|
-
description: "Edit operation: append (add to end), prepend (add to start), " +
|
|
23
|
-
"find_replace (replace matching text), replace_section (replace a heading section)"
|
|
28
|
+
description: "Edit operation: append (add to end of note), prepend (add to start), " +
|
|
29
|
+
"find_replace (replace matching text), replace_section (replace a heading section), " +
|
|
30
|
+
"insert_after_section (add directly below a heading, at the top of its section), " +
|
|
31
|
+
"insert_before_section (add directly above a heading, at the end of the section before it)",
|
|
24
32
|
}),
|
|
25
33
|
content: Type.String({
|
|
26
34
|
description: "New content to add or replace with",
|
|
@@ -29,7 +37,8 @@ export function registerEditTool(api, client) {
|
|
|
29
37
|
description: "Text to find (required for find_replace)",
|
|
30
38
|
})),
|
|
31
39
|
section: Type.Optional(Type.String({
|
|
32
|
-
description: "Section heading
|
|
40
|
+
description: "Section heading, e.g. 'Observations' (required for replace_section, " +
|
|
41
|
+
"insert_before_section and insert_after_section; not allowed with other operations)",
|
|
33
42
|
})),
|
|
34
43
|
expected_replacements: Type.Optional(Type.Number({
|
|
35
44
|
description: "Expected replacement count for find_replace (default: 1)",
|
|
@@ -55,7 +64,7 @@ export function registerEditTool(api, client) {
|
|
|
55
64
|
content: [
|
|
56
65
|
{
|
|
57
66
|
type: "text",
|
|
58
|
-
text: `Note updated: ${note.title} (${note.permalink})`,
|
|
67
|
+
text: `Note updated: ${note.title} (${note.permalink})\nFile: ${note.file_path}`,
|
|
59
68
|
},
|
|
60
69
|
],
|
|
61
70
|
details: {
|
|
@@ -69,13 +78,14 @@ export function registerEditTool(api, client) {
|
|
|
69
78
|
}
|
|
70
79
|
catch (err) {
|
|
71
80
|
log.error("edit_note failed", err);
|
|
81
|
+
// Trigger: any edit failure, including invalid arguments and
|
|
82
|
+
// checksum conflicts, not only a missing note.
|
|
83
|
+
// Why: a blanket "may not exist" sent agents hunting for the wrong
|
|
84
|
+
// problem; the server's message says what to change.
|
|
85
|
+
// Outcome: the agent sees the server's reason verbatim.
|
|
86
|
+
const text = `Failed to edit note "${params.identifier}": ${describeNoteError(err)}`;
|
|
72
87
|
return {
|
|
73
|
-
content: [
|
|
74
|
-
{
|
|
75
|
-
type: "text",
|
|
76
|
-
text: `Failed to edit note "${params.identifier}". It may not exist.`,
|
|
77
|
-
},
|
|
78
|
-
],
|
|
88
|
+
content: [{ type: "text", text }],
|
|
79
89
|
details: {
|
|
80
90
|
identifier: params.identifier,
|
|
81
91
|
operation: params.operation,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
|
|
2
|
-
import type
|
|
2
|
+
import { type BmClient } from "../bm-client.ts";
|
|
3
3
|
export declare function registerProjectListTool(api: OpenClawPluginApi, client: BmClient): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { describeToolError, } from "../bm-client.js";
|
|
2
3
|
import { log } from "../logger.js";
|
|
3
4
|
function normalizeProject(project) {
|
|
4
5
|
return {
|
|
@@ -88,7 +89,7 @@ export function registerProjectListTool(api, client) {
|
|
|
88
89
|
content: [
|
|
89
90
|
{
|
|
90
91
|
type: "text",
|
|
91
|
-
text:
|
|
92
|
+
text: `Failed to list Basic Memory projects: ${describeToolError(err)}`,
|
|
92
93
|
},
|
|
93
94
|
],
|
|
94
95
|
details: {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
|
|
2
|
-
import type
|
|
2
|
+
import { type BmClient } from "../bm-client.ts";
|
|
3
3
|
export declare function registerWorkspaceListTool(api: OpenClawPluginApi, client: BmClient): void;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { describeToolError, } from "../bm-client.js";
|
|
2
3
|
import { log } from "../logger.js";
|
|
3
4
|
function formatWorkspace(ws, idx) {
|
|
4
|
-
const subscription = ws.has_active_subscription ? "active" : "none";
|
|
5
5
|
return (`${idx + 1}. **${ws.name}**\n` +
|
|
6
|
-
` Type: ${ws.workspace_type
|
|
6
|
+
` Type: ${ws.workspace_type ?? "unknown"}`);
|
|
7
7
|
}
|
|
8
8
|
export function registerWorkspaceListTool(api, client) {
|
|
9
9
|
api.registerTool({
|
|
10
10
|
name: "list_workspaces",
|
|
11
11
|
label: "List Workspaces",
|
|
12
|
-
description: "List
|
|
12
|
+
description: "List workspaces represented by accessible Basic Memory projects. " +
|
|
13
13
|
"Use it to find the workspace to pass to list_memory_projects when the same " +
|
|
14
14
|
"project name may exist in more than one workspace.",
|
|
15
15
|
parameters: Type.Object({}),
|
|
@@ -51,7 +51,7 @@ export function registerWorkspaceListTool(api, client) {
|
|
|
51
51
|
content: [
|
|
52
52
|
{
|
|
53
53
|
type: "text",
|
|
54
|
-
text:
|
|
54
|
+
text: `Failed to list workspaces: ${describeToolError(err)}`,
|
|
55
55
|
},
|
|
56
56
|
],
|
|
57
57
|
details: {
|
package/dist/tools/move-note.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { describeNoteError } from "../bm-client.js";
|
|
2
3
|
import { log } from "../logger.js";
|
|
3
4
|
export function registerMoveTool(api, client) {
|
|
4
5
|
api.registerTool({
|
|
@@ -41,7 +42,7 @@ export function registerMoveTool(api, client) {
|
|
|
41
42
|
content: [
|
|
42
43
|
{
|
|
43
44
|
type: "text",
|
|
44
|
-
text: `Failed to move "${params.identifier}"
|
|
45
|
+
text: `Failed to move "${params.identifier}": ${describeNoteError(err)}`,
|
|
45
46
|
},
|
|
46
47
|
],
|
|
47
48
|
details: {
|
package/dist/tools/read-note.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { describeNoteError } from "../bm-client.js";
|
|
2
3
|
import { log } from "../logger.js";
|
|
3
4
|
export function registerReadTool(api, client) {
|
|
4
5
|
api.registerTool({
|
|
@@ -57,7 +58,7 @@ export function registerReadTool(api, client) {
|
|
|
57
58
|
content: [
|
|
58
59
|
{
|
|
59
60
|
type: "text",
|
|
60
|
-
text: `Could not read note "${params.identifier}"
|
|
61
|
+
text: `Could not read note "${params.identifier}": ${describeNoteError(err)}`,
|
|
61
62
|
},
|
|
62
63
|
],
|
|
63
64
|
details: {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
|
|
2
|
-
import type
|
|
2
|
+
import { type BmClient } from "../bm-client.ts";
|
|
3
3
|
export declare function registerSchemaDiffTool(api: OpenClawPluginApi, client: BmClient): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { describeToolError } from "../bm-client.js";
|
|
2
3
|
import { log } from "../logger.js";
|
|
3
4
|
export function registerSchemaDiffTool(api, client) {
|
|
4
5
|
api.registerTool({
|
|
@@ -67,7 +68,7 @@ export function registerSchemaDiffTool(api, client) {
|
|
|
67
68
|
content: [
|
|
68
69
|
{
|
|
69
70
|
type: "text",
|
|
70
|
-
text:
|
|
71
|
+
text: `Schema diff failed: ${describeToolError(err)}`,
|
|
71
72
|
},
|
|
72
73
|
],
|
|
73
74
|
details: {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
|
|
2
|
-
import type
|
|
2
|
+
import { type BmClient } from "../bm-client.ts";
|
|
3
3
|
export declare function registerSchemaInferTool(api: OpenClawPluginApi, client: BmClient): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { describeToolError } from "../bm-client.js";
|
|
2
3
|
import { log } from "../logger.js";
|
|
3
4
|
export function registerSchemaInferTool(api, client) {
|
|
4
5
|
api.registerTool({
|
|
@@ -51,7 +52,7 @@ export function registerSchemaInferTool(api, client) {
|
|
|
51
52
|
content: [
|
|
52
53
|
{
|
|
53
54
|
type: "text",
|
|
54
|
-
text:
|
|
55
|
+
text: `Schema inference failed: ${describeToolError(err)}`,
|
|
55
56
|
},
|
|
56
57
|
],
|
|
57
58
|
details: {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
|
|
2
|
-
import type
|
|
2
|
+
import { type BmClient } from "../bm-client.ts";
|
|
3
3
|
export declare function registerSchemaValidateTool(api: OpenClawPluginApi, client: BmClient): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { describeToolError } from "../bm-client.js";
|
|
2
3
|
import { log } from "../logger.js";
|
|
3
4
|
export function registerSchemaValidateTool(api, client) {
|
|
4
5
|
api.registerTool({
|
|
@@ -58,7 +59,7 @@ export function registerSchemaValidateTool(api, client) {
|
|
|
58
59
|
content: [
|
|
59
60
|
{
|
|
60
61
|
type: "text",
|
|
61
|
-
text:
|
|
62
|
+
text: `Schema validation failed: ${describeToolError(err)}`,
|
|
62
63
|
},
|
|
63
64
|
],
|
|
64
65
|
details: {
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { describeToolError, searchResultText, } from "../bm-client.js";
|
|
2
3
|
import { log } from "../logger.js";
|
|
4
|
+
// Long enough to show a whole captured conversation turn from the matched
|
|
5
|
+
// chunk, short enough that ten results stay readable.
|
|
6
|
+
const MAX_PREVIEW_CHARS = 500;
|
|
3
7
|
export function registerSearchTool(api, client) {
|
|
4
8
|
api.registerTool({
|
|
5
9
|
name: "search_notes",
|
|
@@ -7,8 +11,9 @@ export function registerSearchTool(api, client) {
|
|
|
7
11
|
description: "Search the Basic Memory knowledge graph for relevant notes, concepts, and connections. " +
|
|
8
12
|
"Returns matching notes with titles, content previews, and relevance scores. " +
|
|
9
13
|
"Optionally filter by frontmatter metadata fields, tags, or status, or target " +
|
|
10
|
-
"another project.
|
|
11
|
-
"
|
|
14
|
+
"another project. This is the search for long-term memory and earlier " +
|
|
15
|
+
"conversations; memory_search covers only the workspace MEMORY.md and memory/ " +
|
|
16
|
+
"files. Read a result in full with read_note, or follow its links with build_context.",
|
|
12
17
|
parameters: Type.Object({
|
|
13
18
|
query: Type.String({ description: "Search query" }),
|
|
14
19
|
limit: Type.Optional(Type.Number({ description: "Max results (default: 10)" })),
|
|
@@ -54,9 +59,11 @@ export function registerSearchTool(api, client) {
|
|
|
54
59
|
}
|
|
55
60
|
const text = results
|
|
56
61
|
.map((r, i) => {
|
|
57
|
-
const score = r.score ? ` (${
|
|
58
|
-
const
|
|
59
|
-
const preview =
|
|
62
|
+
const score = r.score ? ` (score ${r.score.toFixed(2)})` : "";
|
|
63
|
+
const text = searchResultText(r);
|
|
64
|
+
const preview = text.length > MAX_PREVIEW_CHARS
|
|
65
|
+
? `${text.slice(0, MAX_PREVIEW_CHARS)}...`
|
|
66
|
+
: text;
|
|
60
67
|
return `${i + 1}. **${r.title}**${score}\n ${preview}`;
|
|
61
68
|
})
|
|
62
69
|
.join("\n\n");
|
|
@@ -83,7 +90,7 @@ export function registerSearchTool(api, client) {
|
|
|
83
90
|
content: [
|
|
84
91
|
{
|
|
85
92
|
type: "text",
|
|
86
|
-
text:
|
|
93
|
+
text: `Search failed: ${describeToolError(err)}`,
|
|
87
94
|
},
|
|
88
95
|
],
|
|
89
96
|
details: {
|
package/dist/tools/write-note.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
-
import { NoteAlreadyExistsError, NoteRevisionConflictError, } from "../bm-client.js";
|
|
2
|
+
import { describeToolError, NoteAlreadyExistsError, NoteRevisionConflictError, } from "../bm-client.js";
|
|
3
3
|
import { log } from "../logger.js";
|
|
4
4
|
export function registerWriteTool(api, client) {
|
|
5
5
|
api.registerTool({
|
|
@@ -41,7 +41,7 @@ export function registerWriteTool(api, client) {
|
|
|
41
41
|
description: 'Note type stored in frontmatter. Defaults to "note".',
|
|
42
42
|
})),
|
|
43
43
|
expected_checksum: Type.Optional(Type.String({
|
|
44
|
-
description: "
|
|
44
|
+
description: "Implies overwrite=true. The checksum of the note as you read it; " +
|
|
45
45
|
"the note is replaced only while it is still that revision.",
|
|
46
46
|
})),
|
|
47
47
|
}),
|
|
@@ -65,7 +65,9 @@ export function registerWriteTool(api, client) {
|
|
|
65
65
|
const checksumSuffix = note.checksum
|
|
66
66
|
? `\nChecksum: ${note.checksum}`
|
|
67
67
|
: "";
|
|
68
|
-
|
|
68
|
+
// The description tells agents to cite permalink and file_path, so both
|
|
69
|
+
// must appear in the text the agent reads, not only in details.
|
|
70
|
+
const msg = `Note saved: ${note.title} (${note.permalink})\nFile: ${note.file_path}${checksumSuffix}`;
|
|
69
71
|
return {
|
|
70
72
|
content: [
|
|
71
73
|
{
|
|
@@ -84,13 +86,10 @@ export function registerWriteTool(api, client) {
|
|
|
84
86
|
catch (err) {
|
|
85
87
|
if (err instanceof NoteAlreadyExistsError) {
|
|
86
88
|
const hint = [
|
|
87
|
-
|
|
89
|
+
err.message,
|
|
88
90
|
"",
|
|
89
|
-
"
|
|
90
|
-
|
|
91
|
-
` - edit_note("${err.permalink}", operation="replace_section", section="...", content="...")`,
|
|
92
|
-
` - write_note("${params.title}", ..., overwrite=true) to fully replace`,
|
|
93
|
-
` - read_note("${err.permalink}", include_frontmatter=true) to inspect it first; pass its checksum as expected_checksum with overwrite=true to replace only that revision`,
|
|
91
|
+
"Use search_notes to locate the note, then read_note to inspect its current content and checksum.",
|
|
92
|
+
"Use edit_note for incremental changes, or write_note with overwrite=true and expected_checksum to replace the revision you read.",
|
|
94
93
|
].join("\n");
|
|
95
94
|
return {
|
|
96
95
|
content: [{ type: "text", text: hint }],
|
|
@@ -104,9 +103,9 @@ export function registerWriteTool(api, client) {
|
|
|
104
103
|
if (err instanceof NoteRevisionConflictError) {
|
|
105
104
|
const current = err.currentChecksum
|
|
106
105
|
? `Its current checksum is ${err.currentChecksum}.`
|
|
107
|
-
: "
|
|
106
|
+
: "Read the note to obtain its current checksum.";
|
|
108
107
|
const text = [
|
|
109
|
-
`Note revision conflict:
|
|
108
|
+
`Note revision conflict: ${err.message} ${current}`,
|
|
110
109
|
"",
|
|
111
110
|
"Read the note again, confirm it should still be replaced, then retry with the new checksum as expected_checksum.",
|
|
112
111
|
].join("\n");
|
|
@@ -125,7 +124,7 @@ export function registerWriteTool(api, client) {
|
|
|
125
124
|
content: [
|
|
126
125
|
{
|
|
127
126
|
type: "text",
|
|
128
|
-
text:
|
|
127
|
+
text: `Failed to write note: ${describeToolError(err)}`,
|
|
129
128
|
},
|
|
130
129
|
],
|
|
131
130
|
details: {
|