opencode-claude-memory 2.0.2 → 2.1.1
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 +67 -10
- package/dist/agents.d.ts +8 -10
- package/dist/agents.js +4 -43
- package/dist/extraction/ExtractionCoordinator.d.ts +10 -12
- package/dist/extraction/ExtractionCoordinator.js +66 -50
- package/dist/extraction/autodream.d.ts +2 -5
- package/dist/extraction/autodream.js +3 -7
- package/dist/host/types.d.ts +52 -0
- package/dist/host/types.js +6 -0
- package/dist/host/v1/agents.d.ts +11 -0
- package/dist/host/v1/agents.js +48 -0
- package/dist/host/v1/coordinators.d.ts +12 -0
- package/dist/host/v1/coordinators.js +43 -0
- package/dist/{extraction/forkSession.d.ts → host/v1/fork.d.ts} +3 -2
- package/dist/{extraction/forkSession.js → host/v1/fork.js} +2 -2
- package/dist/host/v1/host.d.ts +9 -0
- package/dist/host/v1/host.js +79 -0
- package/dist/{hooks → host/v1}/ignore.d.ts +2 -3
- package/dist/host/v1/ignore.js +29 -0
- package/dist/host/v1/log.d.ts +4 -0
- package/dist/host/v1/log.js +20 -0
- package/dist/{hooks → host/v1}/messages.d.ts +3 -2
- package/dist/{hooks → host/v1}/messages.js +3 -17
- package/dist/host/v1/plugin.d.ts +2 -0
- package/dist/host/v1/plugin.js +58 -0
- package/dist/host/v1/selector.d.ts +18 -0
- package/dist/host/v1/selector.js +12 -0
- package/dist/host/v1/tools.d.ts +5 -0
- package/dist/host/v1/tools.js +17 -0
- package/dist/host/v2/agents.d.ts +15 -0
- package/dist/host/v2/agents.js +83 -0
- package/dist/host/v2/events.d.ts +40 -0
- package/dist/host/v2/events.js +137 -0
- package/dist/host/v2/fork.d.ts +76 -0
- package/dist/host/v2/fork.js +136 -0
- package/dist/host/v2/host.d.ts +35 -0
- package/dist/host/v2/host.js +86 -0
- package/dist/host/v2/log.d.ts +4 -0
- package/dist/host/v2/log.js +40 -0
- package/dist/host/v2/plugin.d.ts +26 -0
- package/dist/host/v2/plugin.js +149 -0
- package/dist/host/v2/transcript.d.ts +3 -0
- package/dist/host/v2/transcript.js +50 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.js +5 -55
- package/dist/recall/RecallCoordinator.d.ts +15 -10
- package/dist/recall/RecallCoordinator.js +26 -35
- package/dist/recall/selector.d.ts +14 -19
- package/dist/recall/selector.js +37 -47
- package/dist/recall/turn.d.ts +4 -0
- package/dist/recall/turn.js +49 -0
- package/dist/tools.d.ts +16 -3
- package/dist/tools.js +59 -41
- package/dist/util/log.d.ts +0 -2
- package/dist/util/log.js +2 -18
- package/package.json +16 -4
- package/dist/hooks/ignore.js +0 -53
- /package/dist/{sdk.d.ts → host/v1/sdk.d.ts} +0 -0
- /package/dist/{sdk.js → host/v1/sdk.js} +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Host-independent text rules for a user turn: the "ignore memory" / "use memory again" phrases and
|
|
2
|
+
// the keys of memories already surfaced in a system prompt. The host adapters apply them to their
|
|
3
|
+
// own message shapes.
|
|
4
|
+
import { RECALLED_MEMORIES_HEADING } from "../prompt/systemPrompt.js";
|
|
5
|
+
// "Ignore memory" handling. Claude Code's semantics are session-scoped: once the user asks to
|
|
6
|
+
// ignore memory, it stays ignored until they explicitly ask for it back.
|
|
7
|
+
export function detectIgnoreMemory(query) {
|
|
8
|
+
if (!query)
|
|
9
|
+
return false;
|
|
10
|
+
const normalized = query.toLowerCase();
|
|
11
|
+
return (/(ignore|don't use|do not use|without|skip)\s+(the\s+|your\s+)?memory/.test(normalized) ||
|
|
12
|
+
/memory\s+(should be|must be)?\s*ignored/.test(normalized));
|
|
13
|
+
}
|
|
14
|
+
export function detectResumeMemory(query) {
|
|
15
|
+
if (!query)
|
|
16
|
+
return false;
|
|
17
|
+
const normalized = query.toLowerCase();
|
|
18
|
+
return (/(use|enable|resume|restore|bring back|turn on)\s+(the\s+|your\s+)?memory(\s+again)?/.test(normalized) ||
|
|
19
|
+
/memory\s+(back\s+)?on\b/.test(normalized) ||
|
|
20
|
+
/stop ignoring\s+(the\s+|your\s+)?memory/.test(normalized));
|
|
21
|
+
}
|
|
22
|
+
// Replays user queries in order and returns whether memory is ignored at the end. Used to rebuild
|
|
23
|
+
// session state the coordinator no longer holds (process restart, cache eviction), so an "ignore
|
|
24
|
+
// memory" said earlier in the session keeps applying without the user repeating it.
|
|
25
|
+
export function deriveIgnoredFromQueries(queries) {
|
|
26
|
+
let ignored = false;
|
|
27
|
+
for (const query of queries) {
|
|
28
|
+
if (detectIgnoreMemory(query))
|
|
29
|
+
ignored = true;
|
|
30
|
+
else if (ignored && detectResumeMemory(query))
|
|
31
|
+
ignored = false;
|
|
32
|
+
}
|
|
33
|
+
return ignored;
|
|
34
|
+
}
|
|
35
|
+
// Parses "### <name> (<type>)" headers from the ## Recalled Memories section
|
|
36
|
+
// of system prompts. After compaction old system messages disappear, so
|
|
37
|
+
// the returned set naturally shrinks — no manual reset needed.
|
|
38
|
+
export function extractSurfacedMemoryKeys(systemText) {
|
|
39
|
+
const keys = new Set();
|
|
40
|
+
const recalledSection = systemText.indexOf(RECALLED_MEMORIES_HEADING);
|
|
41
|
+
if (recalledSection === -1)
|
|
42
|
+
return keys;
|
|
43
|
+
const headerPattern = /^### (.+?) \((\w+)\)/gm;
|
|
44
|
+
const section = systemText.slice(recalledSection);
|
|
45
|
+
for (let match = headerPattern.exec(section); match !== null; match = headerPattern.exec(section)) {
|
|
46
|
+
keys.add(`${match[1]}|${match[2]}`);
|
|
47
|
+
}
|
|
48
|
+
return keys;
|
|
49
|
+
}
|
package/dist/tools.d.ts
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import type { MemoryToolName } from "./agents.js";
|
|
2
3
|
import type { ExtractionCoordinator } from "./extraction/ExtractionCoordinator.js";
|
|
3
4
|
import type { MemoryStore, SaveMemoryResult } from "./store/MemoryStore.js";
|
|
4
5
|
export declare function formatMemorySaveResult(outcome: SaveMemoryResult, savedThisRun?: readonly string[]): string;
|
|
5
6
|
export declare function memorySaveTitle(type: string, name: string): string | undefined;
|
|
6
7
|
export declare function memoryListTitle(count: number): string;
|
|
7
8
|
export declare function memorySearchTitle(query: string, count: number): string;
|
|
8
|
-
export type
|
|
9
|
-
|
|
9
|
+
export type MemoryToolResult = {
|
|
10
|
+
title?: string;
|
|
11
|
+
output: string;
|
|
12
|
+
};
|
|
13
|
+
export type MemoryToolContext = {
|
|
14
|
+
sessionID?: string;
|
|
15
|
+
};
|
|
16
|
+
export type MemoryToolSpec = {
|
|
17
|
+
name: MemoryToolName;
|
|
18
|
+
description: string;
|
|
19
|
+
args: z.ZodRawShape;
|
|
20
|
+
execute(args: Record<string, unknown>, ctx: MemoryToolContext): Promise<MemoryToolResult>;
|
|
21
|
+
};
|
|
22
|
+
export declare function buildMemoryToolSpecs(store: MemoryStore, extraction: Pick<ExtractionCoordinator, "recordSave">): MemoryToolSpec[];
|
package/dist/tools.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
// The five memory tools, defined once. Each host adapter wraps the specs into its own tool format
|
|
2
|
+
// (V1: `Hooks["tool"]`, V2: `ToolEditor.add`); results carry their own titles.
|
|
3
|
+
//
|
|
4
|
+
// Argument schemas use `zod/v4`: both hosts accept them (V1 duck-types Zod v4 schemas, V2 takes any
|
|
5
|
+
// Standard Schema), so the plugin needs no runtime import from either SDK.
|
|
6
|
+
import { z } from "zod/v4";
|
|
2
7
|
import { MEMORY_TYPES } from "./store/frontmatter.js";
|
|
3
8
|
// Tool result for memory_save. Inside an extraction fork, `savedThisRun` (file names already saved
|
|
4
9
|
// by this fork, in order) is appended as an explicit done-signal so the model does not lose track on
|
|
@@ -42,9 +47,14 @@ export function memorySearchTitle(query, count) {
|
|
|
42
47
|
return `"${query}" · ${plural(count, "match", "matches")}`;
|
|
43
48
|
}
|
|
44
49
|
const FILE_NAME_HINT = 'with or without the .md extension; sub-directories are allowed, e.g. "team/conventions"';
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
function str(args, key) {
|
|
51
|
+
const value = args[key];
|
|
52
|
+
return typeof value === "string" ? value : "";
|
|
53
|
+
}
|
|
54
|
+
export function buildMemoryToolSpecs(store, extraction) {
|
|
55
|
+
return [
|
|
56
|
+
{
|
|
57
|
+
name: "memory_save",
|
|
48
58
|
description: "Save or update a memory for future conversations. " +
|
|
49
59
|
"Each memory is stored as a markdown file with frontmatter. " +
|
|
50
60
|
"Use this when the user explicitly asks you to remember something, " +
|
|
@@ -52,52 +62,56 @@ export function buildMemoryTools(store, extraction) {
|
|
|
52
62
|
"(user preferences, feedback, project context, external references). " +
|
|
53
63
|
"Check existing memories first with memory_list or memory_search to avoid duplicates.",
|
|
54
64
|
args: {
|
|
55
|
-
file_name:
|
|
65
|
+
file_name: z
|
|
56
66
|
.string()
|
|
57
67
|
.describe('File name for the memory (without .md extension). Use snake_case, e.g. "user_role", "feedback_testing_style", "project_auth_rewrite"; a sub-directory prefix such as "team/conventions" is allowed'),
|
|
58
|
-
name:
|
|
59
|
-
description:
|
|
68
|
+
name: z.string().describe("Human-readable name for this memory"),
|
|
69
|
+
description: z
|
|
60
70
|
.string()
|
|
61
71
|
.describe("One-line description — used to decide relevance in future conversations, so be specific"),
|
|
62
|
-
type:
|
|
72
|
+
type: z
|
|
63
73
|
.enum(MEMORY_TYPES)
|
|
64
74
|
.describe("Memory type: user (about the person), feedback (guidance on approach), project (ongoing work context), reference (pointers to external systems)"),
|
|
65
|
-
content:
|
|
75
|
+
content: z
|
|
66
76
|
.string()
|
|
67
77
|
.describe("Memory content. For feedback/project types, structure as: rule/fact, then **Why:** and **How to apply:** lines"),
|
|
68
78
|
},
|
|
69
79
|
async execute(args, ctx) {
|
|
80
|
+
const type = str(args, "type");
|
|
70
81
|
const outcome = store.save({
|
|
71
|
-
fileName: args
|
|
72
|
-
name: args
|
|
73
|
-
description: args
|
|
74
|
-
type
|
|
75
|
-
content: args
|
|
82
|
+
fileName: str(args, "file_name"),
|
|
83
|
+
name: str(args, "name"),
|
|
84
|
+
description: str(args, "description"),
|
|
85
|
+
type,
|
|
86
|
+
content: str(args, "content"),
|
|
76
87
|
});
|
|
77
|
-
const savedThisRun = extraction.recordSave(ctx
|
|
88
|
+
const savedThisRun = extraction.recordSave(ctx.sessionID, outcome.fileName);
|
|
78
89
|
return {
|
|
79
|
-
title: memorySaveTitle(
|
|
90
|
+
title: memorySaveTitle(type, str(args, "name")),
|
|
80
91
|
output: formatMemorySaveResult(outcome, savedThisRun),
|
|
81
92
|
};
|
|
82
93
|
},
|
|
83
|
-
}
|
|
84
|
-
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "memory_delete",
|
|
85
97
|
description: "Delete a memory that is outdated, wrong, or no longer relevant. Also removes it from the index.",
|
|
86
98
|
args: {
|
|
87
|
-
file_name:
|
|
99
|
+
file_name: z.string().describe(`File name of the memory to delete (${FILE_NAME_HINT})`),
|
|
88
100
|
},
|
|
89
101
|
async execute(args) {
|
|
90
|
-
const
|
|
91
|
-
|
|
102
|
+
const fileName = str(args, "file_name");
|
|
103
|
+
const { deleted, trashedTo } = store.delete(fileName);
|
|
104
|
+
let output = `Memory "${fileName}" not found.`;
|
|
92
105
|
if (deleted) {
|
|
93
106
|
output = trashedTo
|
|
94
|
-
? `Memory "${
|
|
95
|
-
: `Memory "${
|
|
107
|
+
? `Memory "${fileName}" deleted (a copy was kept at ${trashedTo}).`
|
|
108
|
+
: `Memory "${fileName}" deleted.`;
|
|
96
109
|
}
|
|
97
|
-
return { title:
|
|
110
|
+
return { title: fileName, output };
|
|
98
111
|
},
|
|
99
|
-
}
|
|
100
|
-
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: "memory_list",
|
|
101
115
|
description: "List all saved memories with their names, types, and descriptions. " +
|
|
102
116
|
"Use this to check what memories exist before saving a new one (to avoid duplicates) " +
|
|
103
117
|
"or when you need to recall what's been stored.",
|
|
@@ -110,36 +124,40 @@ export function buildMemoryTools(store, extraction) {
|
|
|
110
124
|
const lines = entries.map((e) => `- **${e.name}** (${e.type}) [${e.filename}]: ${e.description}`);
|
|
111
125
|
return { title, output: `${entries.length} memories found:\n${lines.join("\n")}` };
|
|
112
126
|
},
|
|
113
|
-
}
|
|
114
|
-
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
name: "memory_search",
|
|
115
130
|
description: "Search memories by keyword. Searches across names, descriptions, and content. " +
|
|
116
131
|
"Use this to find relevant memories before answering questions or when the user references past conversations.",
|
|
117
132
|
args: {
|
|
118
|
-
query:
|
|
133
|
+
query: z.string().describe("Search query — searches across name, description, and content"),
|
|
119
134
|
},
|
|
120
135
|
async execute(args) {
|
|
121
|
-
const
|
|
122
|
-
const
|
|
136
|
+
const query = str(args, "query");
|
|
137
|
+
const results = store.search(query);
|
|
138
|
+
const title = memorySearchTitle(query, results.length);
|
|
123
139
|
if (results.length === 0)
|
|
124
|
-
return { title, output: `No memories matching "${
|
|
140
|
+
return { title, output: `No memories matching "${query}".` };
|
|
125
141
|
const lines = results.map((e) => `- **${e.name}** (${e.type}) [${e.filename}]: ${e.description}\n Content: ${e.body.slice(0, 200)}${e.body.length > 200 ? "..." : ""}`);
|
|
126
|
-
return { title, output: `${results.length} matches for "${
|
|
142
|
+
return { title, output: `${results.length} matches for "${query}":\n${lines.join("\n")}` };
|
|
127
143
|
},
|
|
128
|
-
}
|
|
129
|
-
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: "memory_read",
|
|
130
147
|
description: "Read the full content of a specific memory file.",
|
|
131
148
|
args: {
|
|
132
|
-
file_name:
|
|
149
|
+
file_name: z.string().describe(`File name of the memory to read (${FILE_NAME_HINT})`),
|
|
133
150
|
},
|
|
134
151
|
async execute(args) {
|
|
135
|
-
const
|
|
152
|
+
const fileName = str(args, "file_name");
|
|
153
|
+
const entry = store.read(fileName);
|
|
136
154
|
if (!entry)
|
|
137
|
-
return { title:
|
|
155
|
+
return { title: fileName, output: `Memory "${fileName}" not found.` };
|
|
138
156
|
return {
|
|
139
|
-
title:
|
|
157
|
+
title: fileName,
|
|
140
158
|
output: `# ${entry.name}\n**Type:** ${entry.type}\n**Description:** ${entry.description}\n\n${entry.body}`,
|
|
141
159
|
};
|
|
142
160
|
},
|
|
143
|
-
}
|
|
144
|
-
|
|
161
|
+
},
|
|
162
|
+
];
|
|
145
163
|
}
|
package/dist/util/log.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import type { OpencodeClient } from "../sdk.js";
|
|
2
1
|
export declare const LOG_SERVICE = "opencode-claude-memory";
|
|
3
2
|
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
4
3
|
export type Logger = (level: LogLevel, message: string, extra?: Record<string, unknown>) => void;
|
|
5
4
|
export declare function getErrorMessage(error: unknown): string;
|
|
6
|
-
export declare function createLogger(client: OpencodeClient | undefined, directory: string): Logger;
|
package/dist/util/log.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Host-independent logging types. Each host adapter supplies its own sink (V1: the OpenCode service
|
|
2
|
+
// log, V2: a file in the plugin state directory); stderr is never used because it ends up in the UI.
|
|
1
3
|
export const LOG_SERVICE = "opencode-claude-memory";
|
|
2
4
|
export function getErrorMessage(error) {
|
|
3
5
|
if (error instanceof Error)
|
|
@@ -9,21 +11,3 @@ export function getErrorMessage(error) {
|
|
|
9
11
|
}
|
|
10
12
|
return String(error);
|
|
11
13
|
}
|
|
12
|
-
// Logging goes through the OpenCode service log only. stderr is rendered into the chat UI, so a
|
|
13
|
-
// failing background task must never write there. Every call is best-effort and never throws.
|
|
14
|
-
export function createLogger(client, directory) {
|
|
15
|
-
return (level, message, extra) => {
|
|
16
|
-
const log = client?.app?.log;
|
|
17
|
-
if (typeof log !== "function")
|
|
18
|
-
return;
|
|
19
|
-
try {
|
|
20
|
-
void Promise.resolve(log.call(client?.app, {
|
|
21
|
-
body: { service: LOG_SERVICE, level, message, extra },
|
|
22
|
-
query: { directory },
|
|
23
|
-
})).catch(() => { });
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
// best-effort
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-claude-memory",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenCode plugin for Claude Code memory: persistent, local-first shared memory with Claude Code-compatible Markdown files, LLM recall, in-process auto extraction, and auto-dream consolidation",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"dist"
|
|
17
17
|
],
|
|
18
18
|
"engines": {
|
|
19
|
-
"opencode": ">=1.18.
|
|
19
|
+
"opencode": ">=1.18.29"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "tsc -p tsconfig.build.json",
|
|
@@ -58,14 +58,26 @@
|
|
|
58
58
|
],
|
|
59
59
|
"license": "MIT",
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"@opencode-ai/plugin": ">=1.18.
|
|
61
|
+
"@opencode-ai/plugin": ">=1.18.29",
|
|
62
|
+
"@opencode/plugin": ">=2.0.0"
|
|
63
|
+
},
|
|
64
|
+
"peerDependenciesMeta": {
|
|
65
|
+
"@opencode-ai/plugin": {
|
|
66
|
+
"optional": true
|
|
67
|
+
},
|
|
68
|
+
"@opencode/plugin": {
|
|
69
|
+
"optional": true
|
|
70
|
+
}
|
|
62
71
|
},
|
|
63
72
|
"dependencies": {
|
|
64
|
-
"zod": "^3.
|
|
73
|
+
"zod": "^3.25.0"
|
|
65
74
|
},
|
|
66
75
|
"devDependencies": {
|
|
67
76
|
"@biomejs/biome": "^2",
|
|
68
77
|
"@opencode-ai/plugin": "^1.18.16",
|
|
78
|
+
"@opencode/client": "2.0.22",
|
|
79
|
+
"@opencode/plugin": "2.0.22",
|
|
80
|
+
"@opencode/schema": "2.0.22",
|
|
69
81
|
"bun-types": "^1.3.11",
|
|
70
82
|
"conventional-changelog-conventionalcommits": "^9",
|
|
71
83
|
"typescript": "^6.0.2"
|
package/dist/hooks/ignore.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// "Ignore memory" handling. Claude Code's semantics are session-scoped: once the user asks to
|
|
2
|
-
// ignore memory, it stays ignored until they explicitly ask for it back.
|
|
3
|
-
import { AUTO_MEMORY_MARKER } from "../prompt/systemPrompt.js";
|
|
4
|
-
import { extractUserQuery, roleOf } from "./messages.js";
|
|
5
|
-
export function detectIgnoreMemory(query) {
|
|
6
|
-
if (!query)
|
|
7
|
-
return false;
|
|
8
|
-
const normalized = query.toLowerCase();
|
|
9
|
-
return (/(ignore|don't use|do not use|without|skip)\s+(the\s+|your\s+)?memory/.test(normalized) ||
|
|
10
|
-
/memory\s+(should be|must be)?\s*ignored/.test(normalized));
|
|
11
|
-
}
|
|
12
|
-
export function detectResumeMemory(query) {
|
|
13
|
-
if (!query)
|
|
14
|
-
return false;
|
|
15
|
-
const normalized = query.toLowerCase();
|
|
16
|
-
return (/(use|enable|resume|restore|bring back|turn on)\s+(the\s+|your\s+)?memory(\s+again)?/.test(normalized) ||
|
|
17
|
-
/memory\s+(back\s+)?on\b/.test(normalized) ||
|
|
18
|
-
/stop ignoring\s+(the\s+|your\s+)?memory/.test(normalized));
|
|
19
|
-
}
|
|
20
|
-
// Replays every user message in order and returns whether memory is ignored at the end. Used to
|
|
21
|
-
// rebuild session state that the coordinator no longer holds (process restart, cache eviction), so
|
|
22
|
-
// an "ignore memory" said earlier in the session keeps applying without the user repeating it.
|
|
23
|
-
export function deriveIgnoredFromHistory(messages) {
|
|
24
|
-
let ignored = false;
|
|
25
|
-
for (const message of messages) {
|
|
26
|
-
if (roleOf(message) !== "user")
|
|
27
|
-
continue;
|
|
28
|
-
const query = extractUserQuery(message);
|
|
29
|
-
if (detectIgnoreMemory(query))
|
|
30
|
-
ignored = true;
|
|
31
|
-
else if (ignored && detectResumeMemory(query))
|
|
32
|
-
ignored = false;
|
|
33
|
-
}
|
|
34
|
-
return ignored;
|
|
35
|
-
}
|
|
36
|
-
export function isAutoMemoryPart(part) {
|
|
37
|
-
if (!part || typeof part !== "object")
|
|
38
|
-
return false;
|
|
39
|
-
const text = part.text;
|
|
40
|
-
return typeof text === "string" && text.trimStart().startsWith(AUTO_MEMORY_MARKER);
|
|
41
|
-
}
|
|
42
|
-
// Drops the plugin's own system segment from system-role messages; messages left without parts
|
|
43
|
-
// are removed entirely.
|
|
44
|
-
export function stripAutoMemoryParts(messages) {
|
|
45
|
-
return messages
|
|
46
|
-
.map((message) => {
|
|
47
|
-
if (roleOf(message) !== "system" || !Array.isArray(message.parts))
|
|
48
|
-
return message;
|
|
49
|
-
const parts = message.parts.filter((part) => !isAutoMemoryPart(part));
|
|
50
|
-
return parts.length === message.parts.length ? message : { ...message, parts };
|
|
51
|
-
})
|
|
52
|
-
.filter((message) => !Array.isArray(message.parts) || message.parts.length > 0);
|
|
53
|
-
}
|
|
File without changes
|
|
File without changes
|