@lmzhen/dsh-evolution-learning-graph 0.1.0-rc.2 → 0.1.0-rc.21
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/lib/index.js +104 -11
- package/lib/types/index.d.ts +23 -1
- package/package.json +3 -2
package/lib/index.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { SKILL_NAME_RE, SkillLibrary, evolutionIoAdapter } from "@lmzhen/dsh-evolution-core";
|
|
1
2
|
//#region lib/types/index.js
|
|
2
3
|
/**
|
|
3
|
-
* Learning graph over skills and memory
|
|
4
|
+
* Learning graph over skills and memory, plus node-level commands
|
|
5
|
+
* (`/evolution graph [detail|edit|delete] <nodeId>`) aligned with the Hermes
|
|
6
|
+
* journey surface: a skill node is its name, a memory node is
|
|
7
|
+
* `memory:<source>:<index>` (source = memory|user, index = position in that
|
|
8
|
+
* file's entries).
|
|
4
9
|
* @module @lmzhen/dsh-evolution-learning-graph
|
|
5
10
|
*/
|
|
6
11
|
/** Build a small deterministic graph from usage records and memory entries. */
|
|
@@ -40,24 +45,112 @@ function buildLearningGraph(usage, memoryEntries) {
|
|
|
40
45
|
edges
|
|
41
46
|
};
|
|
42
47
|
}
|
|
48
|
+
/** Parse a graph node id: skill names pass through; `memory:<source>:<index>` becomes a memory node. */
|
|
49
|
+
function parseGraphNodeId(id) {
|
|
50
|
+
const memory = /^memory:(memory|user):(\d+)$/.exec(id);
|
|
51
|
+
if (memory) return {
|
|
52
|
+
kind: "memory",
|
|
53
|
+
source: memory[1],
|
|
54
|
+
index: Number(memory[2])
|
|
55
|
+
};
|
|
56
|
+
if (SKILL_NAME_RE.test(id)) return {
|
|
57
|
+
kind: "skill",
|
|
58
|
+
name: id
|
|
59
|
+
};
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
/** Resolve a parsed node to its current content (read-only). */
|
|
63
|
+
async function resolveGraphNode(parsed, repository) {
|
|
64
|
+
if (parsed.kind === "skill") {
|
|
65
|
+
const content = await repository.readSkill(parsed.name);
|
|
66
|
+
return content === null ? {
|
|
67
|
+
ok: false,
|
|
68
|
+
message: `Skill "${parsed.name}" not found.`
|
|
69
|
+
} : {
|
|
70
|
+
ok: true,
|
|
71
|
+
message: content
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const entries = await repository.readMemory(parsed.source);
|
|
75
|
+
const entry = entries[parsed.index];
|
|
76
|
+
return entry === void 0 ? {
|
|
77
|
+
ok: false,
|
|
78
|
+
message: `Memory ${parsed.source}[${parsed.index}] does not exist (${entries.length} entries).`
|
|
79
|
+
} : {
|
|
80
|
+
ok: true,
|
|
81
|
+
message: entry
|
|
82
|
+
};
|
|
83
|
+
}
|
|
43
84
|
const name = "evolution-learning-graph";
|
|
44
85
|
function apply(ctx) {
|
|
45
86
|
ctx.inject(["commands"], (commandCtx) => {
|
|
46
87
|
commandCtx.commands.register({
|
|
47
88
|
name: "evolution graph",
|
|
48
|
-
description: "Show the
|
|
89
|
+
description: "Show the learning graph, or act on a node: evolution graph [detail|edit|delete] <nodeId>",
|
|
49
90
|
recordInput: false,
|
|
50
|
-
handler: async () => {
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
|
|
91
|
+
handler: async (invocation) => {
|
|
92
|
+
const usageService = ctx.get("skillUsage");
|
|
93
|
+
const memoryService = ctx.get("memory");
|
|
94
|
+
const ioService = ctx.get("evolutionIo");
|
|
95
|
+
if (!usageService || !memoryService || !ioService) return { text: "skill-usage, memory or evolution-io service is not mounted." };
|
|
96
|
+
const usage = usageService;
|
|
97
|
+
const memory = memoryService;
|
|
98
|
+
const io = ioService;
|
|
99
|
+
const directory = await renderGraph();
|
|
100
|
+
const input = (invocation.rawInput ?? "").trim();
|
|
101
|
+
const detail = /^detail\s+(\S+)$/.exec(input);
|
|
102
|
+
if (detail && detail[1]) return await nodeDetail(detail[1]);
|
|
103
|
+
const edit = /^edit\s+(\S+)\s+([\s\S]+)$/.exec(input);
|
|
104
|
+
if (edit && edit[1] && edit[2] !== void 0) return await nodeEdit(edit[1], edit[2]);
|
|
105
|
+
const remove = /^delete\s+(\S+)$/.exec(input);
|
|
106
|
+
if (remove && remove[1]) return await nodeDelete(remove[1]);
|
|
107
|
+
if (input !== "") return { text: `Unknown graph subcommand "${input.split(" ")[0]}". ${directory}` };
|
|
108
|
+
return { text: directory };
|
|
109
|
+
async function renderGraph() {
|
|
110
|
+
const graph = buildLearningGraph(await usage.report(), await memory.read("memory"));
|
|
111
|
+
const lines = graph.nodes.map((node) => (node.kind === "memory" ? "◆" : "●") + " " + node.label);
|
|
112
|
+
const edges = graph.edges.map((edge) => edge.from + " --" + edge.type + "--> " + edge.to);
|
|
113
|
+
return lines.join("\n") + "\n\n" + edges.join("\n");
|
|
114
|
+
}
|
|
115
|
+
function withSkills() {
|
|
116
|
+
return new SkillLibrary(void 0, evolutionIoAdapter(() => io.provider()));
|
|
117
|
+
}
|
|
118
|
+
async function nodeDetail(id) {
|
|
119
|
+
const parsed = parseGraphNodeId(id);
|
|
120
|
+
if (parsed === null) return { text: `Invalid node id "${id}". Skill names or memory:<source>:<index> expected.` };
|
|
121
|
+
return { text: (await resolveGraphNode(parsed, {
|
|
122
|
+
readSkill: (name) => withSkills().read(name),
|
|
123
|
+
readMemory: (target) => memory.read(target)
|
|
124
|
+
})).message };
|
|
125
|
+
}
|
|
126
|
+
async function nodeEdit(id, content) {
|
|
127
|
+
const parsed = parseGraphNodeId(id);
|
|
128
|
+
if (parsed === null) return { text: `Invalid node id "${id}". Skill names or memory:<source>:<index> expected.` };
|
|
129
|
+
if (parsed.kind === "skill") return { text: (await withSkills().update(parsed.name, content, "foreground")).message };
|
|
130
|
+
const entries = await memory.read(parsed.source);
|
|
131
|
+
const entry = entries[parsed.index];
|
|
132
|
+
if (entry === void 0) return { text: `Memory ${parsed.source}[${parsed.index}] does not exist (${entries.length} entries).` };
|
|
133
|
+
return { text: (await memory.applyBatch(parsed.source, [{
|
|
134
|
+
action: "replace",
|
|
135
|
+
old_text: entry,
|
|
136
|
+
facts: content
|
|
137
|
+
}])).message };
|
|
138
|
+
}
|
|
139
|
+
async function nodeDelete(id) {
|
|
140
|
+
const parsed = parseGraphNodeId(id);
|
|
141
|
+
if (parsed === null) return { text: `Invalid node id "${id}". Skill names or memory:<source>:<index> expected.` };
|
|
142
|
+
if (parsed.kind === "skill") return { text: (await withSkills().archive(parsed.name)).message };
|
|
143
|
+
const entries = await memory.read(parsed.source);
|
|
144
|
+
const entry = entries[parsed.index];
|
|
145
|
+
if (entry === void 0) return { text: `Memory ${parsed.source}[${parsed.index}] does not exist (${entries.length} entries).` };
|
|
146
|
+
return { text: (await memory.applyBatch(parsed.source, [{
|
|
147
|
+
action: "remove",
|
|
148
|
+
old_text: entry
|
|
149
|
+
}])).message };
|
|
150
|
+
}
|
|
58
151
|
}
|
|
59
152
|
});
|
|
60
153
|
});
|
|
61
154
|
}
|
|
62
155
|
//#endregion
|
|
63
|
-
export { apply, buildLearningGraph, name };
|
|
156
|
+
export { apply, buildLearningGraph, name, parseGraphNodeId, resolveGraphNode };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Learning graph over skills and memory
|
|
2
|
+
* Learning graph over skills and memory, plus node-level commands
|
|
3
|
+
* (`/evolution graph [detail|edit|delete] <nodeId>`) aligned with the Hermes
|
|
4
|
+
* journey surface: a skill node is its name, a memory node is
|
|
5
|
+
* `memory:<source>:<index>` (source = memory|user, index = position in that
|
|
6
|
+
* file's entries).
|
|
3
7
|
* @module @deepseek-ai/dsh-evolution-learning-graph
|
|
4
8
|
*/
|
|
5
9
|
import type { Context } from '@deepseek-ai/cordis';
|
|
@@ -22,6 +26,24 @@ export declare function buildLearningGraph(usage: ReadonlyMap<string, {
|
|
|
22
26
|
use_count?: number;
|
|
23
27
|
pinned?: boolean;
|
|
24
28
|
}>, memoryEntries: readonly string[]): LearningGraph;
|
|
29
|
+
export type GraphNodeId = {
|
|
30
|
+
kind: 'skill';
|
|
31
|
+
name: string;
|
|
32
|
+
} | {
|
|
33
|
+
kind: 'memory';
|
|
34
|
+
source: 'memory' | 'user';
|
|
35
|
+
index: number;
|
|
36
|
+
};
|
|
37
|
+
/** Parse a graph node id: skill names pass through; `memory:<source>:<index>` becomes a memory node. */
|
|
38
|
+
export declare function parseGraphNodeId(id: string): GraphNodeId | null;
|
|
39
|
+
/** Resolve a parsed node to its current content (read-only). */
|
|
40
|
+
export declare function resolveGraphNode(parsed: GraphNodeId, repository: {
|
|
41
|
+
readSkill(name: string): Promise<string | null>;
|
|
42
|
+
readMemory(target: 'memory' | 'user'): Promise<string[]>;
|
|
43
|
+
}): Promise<{
|
|
44
|
+
ok: boolean;
|
|
45
|
+
message: string;
|
|
46
|
+
}>;
|
|
25
47
|
export declare const name = "evolution-learning-graph";
|
|
26
48
|
export declare function apply(ctx: Context): void;
|
|
27
49
|
//# sourceMappingURL=index.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-learning-graph",
|
|
3
3
|
"description": "Learning graph over skills and memory (community build)",
|
|
4
|
-
"version": "0.1.0-rc.
|
|
4
|
+
"version": "0.1.0-rc.21",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
],
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@deepseek-ai/schemastery": "^3.18.1"
|
|
35
|
+
"@deepseek-ai/schemastery": "^3.18.1",
|
|
36
|
+
"@lmzhen/dsh-evolution-core": "^0.1.0-rc.21"
|
|
36
37
|
},
|
|
37
38
|
"peerDependencies": {
|
|
38
39
|
"@deepseek-ai/dsh-invariants": "^0.1.0-rc.6",
|