mcp-probe-kit 3.0.19 → 3.0.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/README.md +12 -5
- package/build/index.js +3 -1
- package/build/lib/__tests__/agents-md-template.unit.test.js +2 -0
- package/build/lib/__tests__/memory-config.unit.test.js +9 -0
- package/build/lib/__tests__/memory-injection.unit.test.d.ts +1 -0
- package/build/lib/__tests__/memory-injection.unit.test.js +51 -0
- package/build/lib/__tests__/memory-orchestration.unit.test.d.ts +1 -0
- package/build/lib/__tests__/memory-orchestration.unit.test.js +84 -0
- package/build/lib/__tests__/memory-payload.unit.test.d.ts +1 -0
- package/build/lib/__tests__/memory-payload.unit.test.js +35 -0
- package/build/lib/agents-md-template.js +7 -5
- package/build/lib/memory-client.d.ts +8 -1
- package/build/lib/memory-client.js +53 -44
- package/build/lib/memory-config.d.ts +8 -0
- package/build/lib/memory-config.js +19 -0
- package/build/lib/memory-orchestration.d.ts +7 -2
- package/build/lib/memory-orchestration.js +81 -8
- package/build/lib/memory-payload.d.ts +21 -0
- package/build/lib/memory-payload.js +65 -0
- package/build/resources/ui-ux-data/metadata.json +1 -1
- package/build/schemas/index.d.ts +38 -9
- package/build/schemas/memory-tools.d.ts +38 -9
- package/build/schemas/memory-tools.js +24 -9
- package/build/tools/index.d.ts +1 -0
- package/build/tools/index.js +1 -0
- package/build/tools/memorize_asset.js +12 -0
- package/build/tools/scan_and_extract_patterns.js +7 -7
- package/build/tools/search_memory.d.ts +7 -0
- package/build/tools/search_memory.js +57 -0
- package/build/tools/start_bugfix.js +3 -3
- package/build/tools/start_feature.js +3 -3
- package/build/tools/start_ui.js +3 -3
- package/docs/data/tools.js +18 -0
- package/docs/i18n/all-tools/en.json +6 -1
- package/docs/i18n/all-tools/ja.json +2 -1
- package/docs/i18n/all-tools/ko.json +2 -1
- package/docs/i18n/all-tools/zh-CN.json +7 -2
- package/docs/i18n/en.json +5 -5
- package/docs/i18n/ja.json +2 -2
- package/docs/i18n/ko.json +2 -2
- package/docs/i18n/zh-CN.json +7 -7
- package/docs/memory-local-setup.md +1 -1
- package/docs/memory-local-setup.zh-CN.md +5 -2
- package/docs/pages/getting-started.html +3 -2
- package/package.json +2 -2
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
import { createMemoryClient } from './memory-client.js';
|
|
2
|
-
|
|
2
|
+
import { getMemoryConfig } from './memory-config.js';
|
|
3
|
+
function kindSearchPreferences(kind) {
|
|
4
|
+
switch (kind) {
|
|
5
|
+
case 'bugfix':
|
|
6
|
+
return { preferTypes: ['bugfix'], preferTags: ['bugfix', 'root-cause'] };
|
|
7
|
+
case 'ui':
|
|
8
|
+
return { preferTypes: ['component', 'pattern'], preferTags: ['ui', 'pattern'] };
|
|
9
|
+
case 'feature':
|
|
10
|
+
return { preferTypes: ['pattern', 'code'], preferTags: ['feature', 'pattern'] };
|
|
11
|
+
default:
|
|
12
|
+
return { preferTypes: [], preferTags: [] };
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function truncateInjectionText(value, maxChars) {
|
|
16
|
+
if (value.length <= maxChars) {
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
return `${value.slice(0, Math.max(0, maxChars - 3))}...`;
|
|
20
|
+
}
|
|
21
|
+
async function loadFullAssets(results) {
|
|
22
|
+
const client = createMemoryClient();
|
|
23
|
+
if (!client.isReadEnabled() || results.length === 0) {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
const entries = await Promise.all(results.map(async (item) => {
|
|
27
|
+
const asset = await client.getAsset(item.id);
|
|
28
|
+
return asset ? [item.id, asset] : null;
|
|
29
|
+
}));
|
|
30
|
+
return Object.fromEntries(entries.filter((entry) => entry !== null));
|
|
31
|
+
}
|
|
32
|
+
export async function loadMemoryInjectionContext(query, kind = 'default') {
|
|
3
33
|
const client = createMemoryClient();
|
|
4
34
|
if (!client.isEnabled()) {
|
|
5
35
|
return {
|
|
@@ -8,16 +38,23 @@ export async function loadMemoryInjectionContext(query) {
|
|
|
8
38
|
degraded: false,
|
|
9
39
|
query,
|
|
10
40
|
results: [],
|
|
41
|
+
assetsById: {},
|
|
11
42
|
};
|
|
12
43
|
}
|
|
13
44
|
try {
|
|
14
|
-
const
|
|
45
|
+
const prefs = kindSearchPreferences(kind);
|
|
46
|
+
const results = await client.search(query, {
|
|
47
|
+
preferTypes: prefs.preferTypes,
|
|
48
|
+
preferTags: prefs.preferTags,
|
|
49
|
+
});
|
|
50
|
+
const assetsById = await loadFullAssets(results);
|
|
15
51
|
return {
|
|
16
52
|
enabled: true,
|
|
17
53
|
available: true,
|
|
18
54
|
degraded: false,
|
|
19
55
|
query,
|
|
20
56
|
results,
|
|
57
|
+
assetsById,
|
|
21
58
|
};
|
|
22
59
|
}
|
|
23
60
|
catch (error) {
|
|
@@ -27,6 +64,7 @@ export async function loadMemoryInjectionContext(query) {
|
|
|
27
64
|
degraded: true,
|
|
28
65
|
query,
|
|
29
66
|
results: [],
|
|
67
|
+
assetsById: {},
|
|
30
68
|
error: error instanceof Error ? error.message : String(error),
|
|
31
69
|
};
|
|
32
70
|
}
|
|
@@ -39,7 +77,44 @@ function formatMemoryResultLabel(item) {
|
|
|
39
77
|
: '历史资产';
|
|
40
78
|
return `${item.name} [${item.type}] (${kind})`;
|
|
41
79
|
}
|
|
80
|
+
export function shouldShowSourceInSearch(item, config = getMemoryConfig()) {
|
|
81
|
+
if (config.searchShowSource) {
|
|
82
|
+
return Boolean(item.sourcePath);
|
|
83
|
+
}
|
|
84
|
+
if (!config.repoId || !item.sourceProject || !item.sourcePath) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
return item.sourceProject === config.repoId;
|
|
88
|
+
}
|
|
89
|
+
function formatSourceHint(item, config) {
|
|
90
|
+
if (!shouldShowSourceInSearch(item, config)) {
|
|
91
|
+
return '';
|
|
92
|
+
}
|
|
93
|
+
return `\n - 来源: ${item.sourcePath}`;
|
|
94
|
+
}
|
|
95
|
+
function formatAssetBody(asset, config) {
|
|
96
|
+
const lines = [
|
|
97
|
+
`### ${asset.name}`,
|
|
98
|
+
`- asset_id: ${asset.id}`,
|
|
99
|
+
asset.description ? `- 描述: ${asset.description}` : '',
|
|
100
|
+
asset.usage ? `- 适用: ${asset.usage}` : '',
|
|
101
|
+
asset.tags.length > 0 ? `- 标签: ${asset.tags.join(', ')}` : '',
|
|
102
|
+
'',
|
|
103
|
+
truncateInjectionText(asset.content, config.injectionContentMaxChars),
|
|
104
|
+
].filter(Boolean);
|
|
105
|
+
return lines.join('\n');
|
|
106
|
+
}
|
|
107
|
+
function formatResultBlock(item, index, context, config) {
|
|
108
|
+
const label = formatMemoryResultLabel(item);
|
|
109
|
+
const asset = context.assetsById[item.id];
|
|
110
|
+
const header = `${index + 1}. ${label} score=${item.score.toFixed(3)}\n - 摘要: ${item.summary}${formatSourceHint(item, config)}`;
|
|
111
|
+
if (asset?.content) {
|
|
112
|
+
return `${header}\n\n${formatAssetBody(asset, config)}\n`;
|
|
113
|
+
}
|
|
114
|
+
return `${header}\n - 全文加载失败,可手动: read_memory_asset {"asset_id": "${item.id}"}\n`;
|
|
115
|
+
}
|
|
42
116
|
export function renderMemoryGuideSection(context) {
|
|
117
|
+
const config = getMemoryConfig();
|
|
43
118
|
if (!context.enabled) {
|
|
44
119
|
return '';
|
|
45
120
|
}
|
|
@@ -49,13 +124,11 @@ export function renderMemoryGuideSection(context) {
|
|
|
49
124
|
if (context.results.length === 0) {
|
|
50
125
|
return `\n\n## 🧠 记忆系统\n- 状态: 已启用\n- 检索结果: 未找到高相关记录(含历史 Bug 修复与可复用模式)\n- 处理: 继续主流程;Bug 修复验证通过后必须 \`memorize_asset\` 沉淀;功能/UI 有可复用产出再沉淀\n`;
|
|
51
126
|
}
|
|
127
|
+
const loadedCount = context.results.filter((item) => context.assetsById[item.id]?.content).length;
|
|
52
128
|
const items = context.results
|
|
53
|
-
.map((item, index) =>
|
|
54
|
-
const label = formatMemoryResultLabel(item);
|
|
55
|
-
return `${index + 1}. ${label} score=${item.score.toFixed(3)}\n - 摘要: ${item.summary}\n - 读取: read_memory_asset {\"asset_id\": \"${item.id}\"}${item.sourcePath ? `\n - 来源: ${item.sourcePath}` : ''}`;
|
|
56
|
-
})
|
|
129
|
+
.map((item, index) => formatResultBlock(item, index, context, config))
|
|
57
130
|
.join('\n');
|
|
58
|
-
return `\n\n## 🧠 记忆系统\n- 状态: 已启用\n- 指令:
|
|
131
|
+
return `\n\n## 🧠 记忆系统\n- 状态: 已启用\n- 指令: 下列为已自动加载的历史经验全文(${loadedCount}/${context.results.length} 条);开干前直接复用,无需再调 \`read_memory_asset\`\n- 检索结果:\n${items}`;
|
|
59
132
|
}
|
|
60
133
|
export function buildMemoryPlanStep(kind = 'default') {
|
|
61
134
|
if (kind === 'bugfix') {
|
|
@@ -68,7 +141,7 @@ export function buildMemoryPlanStep(kind = 'default') {
|
|
|
68
141
|
type: 'bugfix',
|
|
69
142
|
description: '[现象、报错信息、复现条件]',
|
|
70
143
|
summary: '[检索用:关键词 + 根因 + 修复要点,一句话]',
|
|
71
|
-
content: '【现象】...\n【根因】...\n
|
|
144
|
+
content: '【现象】...\n【根因】...\n【修复】具体改动与关键代码/配置\n【验证】如何确认已修好',
|
|
72
145
|
usage: '[再次遇到何种症状时可参考]',
|
|
73
146
|
tags: ['bugfix', 'root-cause'],
|
|
74
147
|
confidence: 0.85,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unify legacy Qdrant payloads (kind/title/source) with the current asset schema.
|
|
3
|
+
*/
|
|
4
|
+
export declare function normalizeMemoryPayload(payload: Record<string, unknown>): Record<string, unknown>;
|
|
5
|
+
export declare function payloadToMemoryFields(payload: Record<string, unknown>): {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
type: string;
|
|
9
|
+
description: string;
|
|
10
|
+
summary: string;
|
|
11
|
+
content: string;
|
|
12
|
+
tags: string[];
|
|
13
|
+
confidence: number;
|
|
14
|
+
sourceProject?: string;
|
|
15
|
+
sourcePath?: string;
|
|
16
|
+
usage?: string;
|
|
17
|
+
contentHash?: string;
|
|
18
|
+
normalizedContentHash?: string;
|
|
19
|
+
createdAt: string;
|
|
20
|
+
updatedAt: string;
|
|
21
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
function truncate(value, maxChars) {
|
|
2
|
+
if (value.length <= maxChars) {
|
|
3
|
+
return value;
|
|
4
|
+
}
|
|
5
|
+
return `${value.slice(0, Math.max(0, maxChars - 3))}...`;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Unify legacy Qdrant payloads (kind/title/source) with the current asset schema.
|
|
9
|
+
*/
|
|
10
|
+
export function normalizeMemoryPayload(payload) {
|
|
11
|
+
const normalized = { ...payload };
|
|
12
|
+
if (!normalized.name && typeof normalized.title === 'string') {
|
|
13
|
+
normalized.name = normalized.title;
|
|
14
|
+
}
|
|
15
|
+
if (!normalized.type && typeof normalized.kind === 'string') {
|
|
16
|
+
const kind = normalized.kind;
|
|
17
|
+
normalized.type = kind === 'extracted_pattern' ? 'pattern' : kind;
|
|
18
|
+
}
|
|
19
|
+
if (!normalized.description) {
|
|
20
|
+
if (typeof normalized.title === 'string') {
|
|
21
|
+
normalized.description = normalized.title;
|
|
22
|
+
}
|
|
23
|
+
else if (typeof normalized.source === 'string') {
|
|
24
|
+
normalized.description = `Legacy memory from ${normalized.source}`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (!normalized.summary && typeof normalized.content === 'string') {
|
|
28
|
+
normalized.summary = truncate(normalized.content, 280);
|
|
29
|
+
}
|
|
30
|
+
if (!normalized.createdAt && typeof normalized.created_at === 'string') {
|
|
31
|
+
normalized.createdAt = normalized.created_at;
|
|
32
|
+
}
|
|
33
|
+
if (!normalized.updatedAt) {
|
|
34
|
+
if (typeof normalized.updated_at === 'string') {
|
|
35
|
+
normalized.updatedAt = normalized.updated_at;
|
|
36
|
+
}
|
|
37
|
+
else if (typeof normalized.createdAt === 'string') {
|
|
38
|
+
normalized.updatedAt = normalized.createdAt;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return normalized;
|
|
42
|
+
}
|
|
43
|
+
export function payloadToMemoryFields(payload) {
|
|
44
|
+
const p = normalizeMemoryPayload(payload);
|
|
45
|
+
const tags = Array.isArray(p.tags)
|
|
46
|
+
? p.tags.filter((item) => typeof item === 'string' && item.trim().length > 0)
|
|
47
|
+
: [];
|
|
48
|
+
return {
|
|
49
|
+
id: String(p.id || ''),
|
|
50
|
+
name: String(p.name || ''),
|
|
51
|
+
type: String(p.type || ''),
|
|
52
|
+
description: String(p.description || ''),
|
|
53
|
+
summary: String(p.summary || ''),
|
|
54
|
+
content: String(p.content || ''),
|
|
55
|
+
tags,
|
|
56
|
+
confidence: typeof p.confidence === 'number' && Number.isFinite(p.confidence) ? p.confidence : 0.5,
|
|
57
|
+
sourceProject: typeof p.sourceProject === 'string' ? p.sourceProject : undefined,
|
|
58
|
+
sourcePath: typeof p.sourcePath === 'string' ? p.sourcePath : undefined,
|
|
59
|
+
usage: typeof p.usage === 'string' ? p.usage : undefined,
|
|
60
|
+
contentHash: typeof p.contentHash === 'string' ? p.contentHash : undefined,
|
|
61
|
+
normalizedContentHash: typeof p.normalizedContentHash === 'string' ? p.normalizedContentHash : undefined,
|
|
62
|
+
createdAt: String(p.createdAt || ''),
|
|
63
|
+
updatedAt: String(p.updatedAt || ''),
|
|
64
|
+
};
|
|
65
|
+
}
|
package/build/schemas/index.d.ts
CHANGED
|
@@ -688,6 +688,35 @@ export declare const allToolSchemas: ({
|
|
|
688
688
|
};
|
|
689
689
|
required: never[];
|
|
690
690
|
};
|
|
691
|
+
} | {
|
|
692
|
+
readonly name: "search_memory";
|
|
693
|
+
readonly description: "按语义检索共享记忆库。适合在 start_* 之外主动查找历史 Bug 修复或可复用模式;命中后用 read_memory_asset 读取全文。";
|
|
694
|
+
readonly inputSchema: {
|
|
695
|
+
readonly type: "object";
|
|
696
|
+
readonly properties: {
|
|
697
|
+
readonly query: {
|
|
698
|
+
readonly type: "string";
|
|
699
|
+
readonly description: "检索 query(现象、报错、关键词、功能描述等)";
|
|
700
|
+
};
|
|
701
|
+
readonly type: {
|
|
702
|
+
readonly type: "string";
|
|
703
|
+
readonly description: "优先匹配的资产类型,如 bugfix、pattern、component";
|
|
704
|
+
};
|
|
705
|
+
readonly tags: {
|
|
706
|
+
readonly type: "array";
|
|
707
|
+
readonly items: {
|
|
708
|
+
readonly type: "string";
|
|
709
|
+
};
|
|
710
|
+
readonly description: "优先匹配的标签";
|
|
711
|
+
};
|
|
712
|
+
readonly limit: {
|
|
713
|
+
readonly type: "number";
|
|
714
|
+
readonly description: "返回条数,默认 MEMORY_SEARCH_LIMIT";
|
|
715
|
+
};
|
|
716
|
+
};
|
|
717
|
+
readonly required: readonly ["query"];
|
|
718
|
+
readonly additionalProperties: true;
|
|
719
|
+
};
|
|
691
720
|
} | {
|
|
692
721
|
readonly name: "read_memory_asset";
|
|
693
722
|
readonly description: "当编排阶段已检索到记忆摘要,且 AI 需要查看完整沉淀代码或详细规范时使用。根据 asset_id 读取记忆资产详情。";
|
|
@@ -704,7 +733,7 @@ export declare const allToolSchemas: ({
|
|
|
704
733
|
};
|
|
705
734
|
} | {
|
|
706
735
|
readonly name: "memorize_asset";
|
|
707
|
-
readonly description: "
|
|
736
|
+
readonly description: "沉淀可检索资产到共享记忆库。Bug 修复后必须 type=bugfix,content 含【现象】【根因】【修复】【验证】。跨仓库共享时勿填 source_project/source_path,路径写入 content 即可。";
|
|
708
737
|
readonly inputSchema: {
|
|
709
738
|
readonly type: "object";
|
|
710
739
|
readonly properties: {
|
|
@@ -714,7 +743,7 @@ export declare const allToolSchemas: ({
|
|
|
714
743
|
};
|
|
715
744
|
readonly type: {
|
|
716
745
|
readonly type: "string";
|
|
717
|
-
readonly description: "
|
|
746
|
+
readonly description: "资产类型:bugfix / pattern / component / code 等";
|
|
718
747
|
};
|
|
719
748
|
readonly description: {
|
|
720
749
|
readonly type: "string";
|
|
@@ -722,11 +751,11 @@ export declare const allToolSchemas: ({
|
|
|
722
751
|
};
|
|
723
752
|
readonly summary: {
|
|
724
753
|
readonly type: "string";
|
|
725
|
-
readonly description: "
|
|
754
|
+
readonly description: "检索用一句话摘要(关键词 + 根因/要点)";
|
|
726
755
|
};
|
|
727
756
|
readonly content: {
|
|
728
757
|
readonly type: "string";
|
|
729
|
-
readonly description: "
|
|
758
|
+
readonly description: "完整内容(bugfix 建议结构化四段)";
|
|
730
759
|
};
|
|
731
760
|
readonly code_snippet: {
|
|
732
761
|
readonly type: "string";
|
|
@@ -734,15 +763,15 @@ export declare const allToolSchemas: ({
|
|
|
734
763
|
};
|
|
735
764
|
readonly file_path: {
|
|
736
765
|
readonly type: "string";
|
|
737
|
-
readonly description: "
|
|
766
|
+
readonly description: "已废弃:勿用于跨仓库沉淀,路径写入 content";
|
|
738
767
|
};
|
|
739
768
|
readonly source_project: {
|
|
740
769
|
readonly type: "string";
|
|
741
|
-
readonly description: "
|
|
770
|
+
readonly description: "已废弃:仅同仓库追溯时可选";
|
|
742
771
|
};
|
|
743
772
|
readonly source_path: {
|
|
744
773
|
readonly type: "string";
|
|
745
|
-
readonly description: "
|
|
774
|
+
readonly description: "已废弃:仅同仓库追溯时可选";
|
|
746
775
|
};
|
|
747
776
|
readonly usage: {
|
|
748
777
|
readonly type: "string";
|
|
@@ -757,7 +786,7 @@ export declare const allToolSchemas: ({
|
|
|
757
786
|
readonly items: {
|
|
758
787
|
readonly type: "string";
|
|
759
788
|
};
|
|
760
|
-
readonly description: "
|
|
789
|
+
readonly description: "标签列表,如 bugfix, root-cause";
|
|
761
790
|
};
|
|
762
791
|
};
|
|
763
792
|
readonly required: readonly ["name", "description", "summary"];
|
|
@@ -779,7 +808,7 @@ export declare const allToolSchemas: ({
|
|
|
779
808
|
};
|
|
780
809
|
readonly project_name: {
|
|
781
810
|
readonly type: "string";
|
|
782
|
-
readonly description: "
|
|
811
|
+
readonly description: "已废弃,扫描结果不再写入 source_project";
|
|
783
812
|
};
|
|
784
813
|
readonly directory_path: {
|
|
785
814
|
readonly type: "string";
|
|
@@ -1,4 +1,33 @@
|
|
|
1
1
|
export declare const memoryToolSchemas: readonly [{
|
|
2
|
+
readonly name: "search_memory";
|
|
3
|
+
readonly description: "按语义检索共享记忆库。适合在 start_* 之外主动查找历史 Bug 修复或可复用模式;命中后用 read_memory_asset 读取全文。";
|
|
4
|
+
readonly inputSchema: {
|
|
5
|
+
readonly type: "object";
|
|
6
|
+
readonly properties: {
|
|
7
|
+
readonly query: {
|
|
8
|
+
readonly type: "string";
|
|
9
|
+
readonly description: "检索 query(现象、报错、关键词、功能描述等)";
|
|
10
|
+
};
|
|
11
|
+
readonly type: {
|
|
12
|
+
readonly type: "string";
|
|
13
|
+
readonly description: "优先匹配的资产类型,如 bugfix、pattern、component";
|
|
14
|
+
};
|
|
15
|
+
readonly tags: {
|
|
16
|
+
readonly type: "array";
|
|
17
|
+
readonly items: {
|
|
18
|
+
readonly type: "string";
|
|
19
|
+
};
|
|
20
|
+
readonly description: "优先匹配的标签";
|
|
21
|
+
};
|
|
22
|
+
readonly limit: {
|
|
23
|
+
readonly type: "number";
|
|
24
|
+
readonly description: "返回条数,默认 MEMORY_SEARCH_LIMIT";
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
readonly required: readonly ["query"];
|
|
28
|
+
readonly additionalProperties: true;
|
|
29
|
+
};
|
|
30
|
+
}, {
|
|
2
31
|
readonly name: "read_memory_asset";
|
|
3
32
|
readonly description: "当编排阶段已检索到记忆摘要,且 AI 需要查看完整沉淀代码或详细规范时使用。根据 asset_id 读取记忆资产详情。";
|
|
4
33
|
readonly inputSchema: {
|
|
@@ -14,7 +43,7 @@ export declare const memoryToolSchemas: readonly [{
|
|
|
14
43
|
};
|
|
15
44
|
}, {
|
|
16
45
|
readonly name: "memorize_asset";
|
|
17
|
-
readonly description: "
|
|
46
|
+
readonly description: "沉淀可检索资产到共享记忆库。Bug 修复后必须 type=bugfix,content 含【现象】【根因】【修复】【验证】。跨仓库共享时勿填 source_project/source_path,路径写入 content 即可。";
|
|
18
47
|
readonly inputSchema: {
|
|
19
48
|
readonly type: "object";
|
|
20
49
|
readonly properties: {
|
|
@@ -24,7 +53,7 @@ export declare const memoryToolSchemas: readonly [{
|
|
|
24
53
|
};
|
|
25
54
|
readonly type: {
|
|
26
55
|
readonly type: "string";
|
|
27
|
-
readonly description: "
|
|
56
|
+
readonly description: "资产类型:bugfix / pattern / component / code 等";
|
|
28
57
|
};
|
|
29
58
|
readonly description: {
|
|
30
59
|
readonly type: "string";
|
|
@@ -32,11 +61,11 @@ export declare const memoryToolSchemas: readonly [{
|
|
|
32
61
|
};
|
|
33
62
|
readonly summary: {
|
|
34
63
|
readonly type: "string";
|
|
35
|
-
readonly description: "
|
|
64
|
+
readonly description: "检索用一句话摘要(关键词 + 根因/要点)";
|
|
36
65
|
};
|
|
37
66
|
readonly content: {
|
|
38
67
|
readonly type: "string";
|
|
39
|
-
readonly description: "
|
|
68
|
+
readonly description: "完整内容(bugfix 建议结构化四段)";
|
|
40
69
|
};
|
|
41
70
|
readonly code_snippet: {
|
|
42
71
|
readonly type: "string";
|
|
@@ -44,15 +73,15 @@ export declare const memoryToolSchemas: readonly [{
|
|
|
44
73
|
};
|
|
45
74
|
readonly file_path: {
|
|
46
75
|
readonly type: "string";
|
|
47
|
-
readonly description: "
|
|
76
|
+
readonly description: "已废弃:勿用于跨仓库沉淀,路径写入 content";
|
|
48
77
|
};
|
|
49
78
|
readonly source_project: {
|
|
50
79
|
readonly type: "string";
|
|
51
|
-
readonly description: "
|
|
80
|
+
readonly description: "已废弃:仅同仓库追溯时可选";
|
|
52
81
|
};
|
|
53
82
|
readonly source_path: {
|
|
54
83
|
readonly type: "string";
|
|
55
|
-
readonly description: "
|
|
84
|
+
readonly description: "已废弃:仅同仓库追溯时可选";
|
|
56
85
|
};
|
|
57
86
|
readonly usage: {
|
|
58
87
|
readonly type: "string";
|
|
@@ -67,7 +96,7 @@ export declare const memoryToolSchemas: readonly [{
|
|
|
67
96
|
readonly items: {
|
|
68
97
|
readonly type: "string";
|
|
69
98
|
};
|
|
70
|
-
readonly description: "
|
|
99
|
+
readonly description: "标签列表,如 bugfix, root-cause";
|
|
71
100
|
};
|
|
72
101
|
};
|
|
73
102
|
readonly required: readonly ["name", "description", "summary"];
|
|
@@ -89,7 +118,7 @@ export declare const memoryToolSchemas: readonly [{
|
|
|
89
118
|
};
|
|
90
119
|
readonly project_name: {
|
|
91
120
|
readonly type: "string";
|
|
92
|
-
readonly description: "
|
|
121
|
+
readonly description: "已废弃,扫描结果不再写入 source_project";
|
|
93
122
|
};
|
|
94
123
|
readonly directory_path: {
|
|
95
124
|
readonly type: "string";
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
export const memoryToolSchemas = [
|
|
2
|
+
{
|
|
3
|
+
name: 'search_memory',
|
|
4
|
+
description: '按语义检索共享记忆库。适合在 start_* 之外主动查找历史 Bug 修复或可复用模式;命中后用 read_memory_asset 读取全文。',
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: 'object',
|
|
7
|
+
properties: {
|
|
8
|
+
query: { type: 'string', description: '检索 query(现象、报错、关键词、功能描述等)' },
|
|
9
|
+
type: { type: 'string', description: '优先匹配的资产类型,如 bugfix、pattern、component' },
|
|
10
|
+
tags: { type: 'array', items: { type: 'string' }, description: '优先匹配的标签' },
|
|
11
|
+
limit: { type: 'number', description: '返回条数,默认 MEMORY_SEARCH_LIMIT' },
|
|
12
|
+
},
|
|
13
|
+
required: ['query'],
|
|
14
|
+
additionalProperties: true,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
2
17
|
{
|
|
3
18
|
name: 'read_memory_asset',
|
|
4
19
|
description: '当编排阶段已检索到记忆摘要,且 AI 需要查看完整沉淀代码或详细规范时使用。根据 asset_id 读取记忆资产详情。',
|
|
@@ -16,22 +31,22 @@ export const memoryToolSchemas = [
|
|
|
16
31
|
},
|
|
17
32
|
{
|
|
18
33
|
name: 'memorize_asset',
|
|
19
|
-
description: '
|
|
34
|
+
description: '沉淀可检索资产到共享记忆库。Bug 修复后必须 type=bugfix,content 含【现象】【根因】【修复】【验证】。跨仓库共享时勿填 source_project/source_path,路径写入 content 即可。',
|
|
20
35
|
inputSchema: {
|
|
21
36
|
type: 'object',
|
|
22
37
|
properties: {
|
|
23
38
|
name: { type: 'string', description: '资产名称' },
|
|
24
|
-
type: { type: 'string', description: '
|
|
39
|
+
type: { type: 'string', description: '资产类型:bugfix / pattern / component / code 等' },
|
|
25
40
|
description: { type: 'string', description: '资产描述' },
|
|
26
|
-
summary: { type: 'string', description: '
|
|
27
|
-
content: { type: 'string', description: '
|
|
41
|
+
summary: { type: 'string', description: '检索用一句话摘要(关键词 + 根因/要点)' },
|
|
42
|
+
content: { type: 'string', description: '完整内容(bugfix 建议结构化四段)' },
|
|
28
43
|
code_snippet: { type: 'string', description: '代码片段,content 的别名' },
|
|
29
|
-
file_path: { type: 'string', description: '
|
|
30
|
-
source_project: { type: 'string', description: '
|
|
31
|
-
source_path: { type: 'string', description: '
|
|
44
|
+
file_path: { type: 'string', description: '已废弃:勿用于跨仓库沉淀,路径写入 content' },
|
|
45
|
+
source_project: { type: 'string', description: '已废弃:仅同仓库追溯时可选' },
|
|
46
|
+
source_path: { type: 'string', description: '已废弃:仅同仓库追溯时可选' },
|
|
32
47
|
usage: { type: 'string', description: '适用场景/使用方式' },
|
|
33
48
|
confidence: { type: 'number', description: '置信度,0-1' },
|
|
34
|
-
tags: { type: 'array', items: { type: 'string' }, description: '
|
|
49
|
+
tags: { type: 'array', items: { type: 'string' }, description: '标签列表,如 bugfix, root-cause' },
|
|
35
50
|
},
|
|
36
51
|
required: ['name', 'description', 'summary'],
|
|
37
52
|
additionalProperties: true,
|
|
@@ -45,7 +60,7 @@ export const memoryToolSchemas = [
|
|
|
45
60
|
properties: {
|
|
46
61
|
content: { type: 'string', description: '待分析的代码或文本内容。传入该字段时走单段分析模式' },
|
|
47
62
|
file_path: { type: 'string', description: '来源文件路径。单段分析时作为来源路径使用' },
|
|
48
|
-
project_name: { type: 'string', description: '
|
|
63
|
+
project_name: { type: 'string', description: '已废弃,扫描结果不再写入 source_project' },
|
|
49
64
|
directory_path: { type: 'string', description: '要扫描的目录路径。最佳实践是传相对 `project_root` 的路径,例如 `app/utils`;如果拿不到 `project_root`,才传目录绝对路径。不要传带项目名的半相对路径,例如 `font-miniapp-api/app/utils`。' },
|
|
50
65
|
project_root: { type: 'string', description: '项目根目录绝对路径。目录扫描时建议始终传入;传入后,`directory_path` 应写成相对项目根的路径。' },
|
|
51
66
|
max_files: { type: 'number', description: '最多扫描多少个文件,默认 30,最大 200' },
|
package/build/tools/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export { interview } from "./interview.js";
|
|
|
16
16
|
export { askUser } from "./ask_user.js";
|
|
17
17
|
export { uiDesignSystem, uiSearch, syncUiData } from "./ui-ux-tools.js";
|
|
18
18
|
export { startUi } from "./start_ui.js";
|
|
19
|
+
export { searchMemory } from "./search_memory.js";
|
|
19
20
|
export { readMemoryAsset } from "./read_memory_asset.js";
|
|
20
21
|
export { memorizeAsset } from "./memorize_asset.js";
|
|
21
22
|
export { scanAndExtractPatterns } from "./scan_and_extract_patterns.js";
|
package/build/tools/index.js
CHANGED
|
@@ -20,6 +20,7 @@ export { askUser } from "./ask_user.js";
|
|
|
20
20
|
export { uiDesignSystem, uiSearch, syncUiData } from "./ui-ux-tools.js";
|
|
21
21
|
export { startUi } from "./start_ui.js";
|
|
22
22
|
// 记忆工具
|
|
23
|
+
export { searchMemory } from "./search_memory.js";
|
|
23
24
|
export { readMemoryAsset } from "./read_memory_asset.js";
|
|
24
25
|
export { memorizeAsset } from "./memorize_asset.js";
|
|
25
26
|
export { scanAndExtractPatterns } from "./scan_and_extract_patterns.js";
|
|
@@ -42,6 +42,17 @@ export async function memorizeAsset(args) {
|
|
|
42
42
|
if (!client.isEnabled()) {
|
|
43
43
|
return okStructured('记忆服务未开启,已跳过沉淀。', { enabled: false, stored: false });
|
|
44
44
|
}
|
|
45
|
+
const warnings = [];
|
|
46
|
+
if (type === 'bugfix') {
|
|
47
|
+
const requiredSections = ['【现象】', '【根因】', '【修复】'];
|
|
48
|
+
const missing = requiredSections.filter((section) => !content.includes(section));
|
|
49
|
+
if (missing.length > 0) {
|
|
50
|
+
warnings.push(`建议 content 包含 ${missing.join('、')},便于跨仓库检索与复用`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (sourceProject || sourcePath) {
|
|
54
|
+
warnings.push('跨仓库共享记忆时请勿依赖 source_project/source_path;路径请写入 content 正文(可选)');
|
|
55
|
+
}
|
|
45
56
|
const asset = await client.upsertAsset({
|
|
46
57
|
name,
|
|
47
58
|
type,
|
|
@@ -58,6 +69,7 @@ export async function memorizeAsset(args) {
|
|
|
58
69
|
enabled: true,
|
|
59
70
|
stored: true,
|
|
60
71
|
asset,
|
|
72
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
61
73
|
});
|
|
62
74
|
}
|
|
63
75
|
catch (error) {
|
|
@@ -108,21 +108,22 @@ function summarizeContent(content, maxChars = 200) {
|
|
|
108
108
|
.trim()
|
|
109
109
|
.slice(0, maxChars);
|
|
110
110
|
}
|
|
111
|
-
function buildPattern(content, filePath
|
|
111
|
+
function buildPattern(content, filePath) {
|
|
112
112
|
const normalized = content.trim();
|
|
113
113
|
const candidateNames = collectCandidateNames(normalized);
|
|
114
114
|
const primaryName = candidateNames[0] || (filePath ? path.basename(filePath) : 'snippet');
|
|
115
115
|
const type = detectPatternType(normalized, filePath);
|
|
116
116
|
const summary = summarizeContent(normalized);
|
|
117
|
+
const fileHint = filePath ? `(摘录自 ${filePath})` : '';
|
|
117
118
|
return {
|
|
118
119
|
name: primaryName,
|
|
119
120
|
type,
|
|
120
|
-
description: filePath
|
|
121
|
+
description: filePath
|
|
122
|
+
? `从 ${filePath} 提取的可复用模式${fileHint}`
|
|
123
|
+
: '从代码片段提取的可复用模式',
|
|
121
124
|
summary,
|
|
122
125
|
content: normalized,
|
|
123
126
|
tags: inferTags(normalized, filePath),
|
|
124
|
-
sourcePath: filePath || undefined,
|
|
125
|
-
sourceProject: projectName || undefined,
|
|
126
127
|
confidence: filePath ? 0.62 : 0.55,
|
|
127
128
|
candidateNames,
|
|
128
129
|
};
|
|
@@ -271,7 +272,6 @@ export async function scanAndExtractPatterns(args) {
|
|
|
271
272
|
});
|
|
272
273
|
const content = getString(parsed.content);
|
|
273
274
|
const filePath = getString(parsed.file_path);
|
|
274
|
-
const projectName = getString(parsed.project_name);
|
|
275
275
|
const directoryPath = getString(parsed.directory_path);
|
|
276
276
|
const projectRoot = resolveWorkspaceRoot(getString(parsed.project_root));
|
|
277
277
|
const maxFiles = Math.max(1, Math.min(200, getNumber(parsed.max_files, 30)));
|
|
@@ -282,7 +282,7 @@ export async function scanAndExtractPatterns(args) {
|
|
|
282
282
|
.map((item) => item.startsWith('.') ? item.toLowerCase() : `.${item.toLowerCase()}`)
|
|
283
283
|
: DEFAULT_INCLUDE_EXTENSIONS);
|
|
284
284
|
if (content) {
|
|
285
|
-
const pattern = buildPattern(content, filePath
|
|
285
|
+
const pattern = buildPattern(content, filePath);
|
|
286
286
|
return okStructured(`已提取 1 个候选模式${filePath ? `: ${filePath}` : ''}`, {
|
|
287
287
|
mode: 'single',
|
|
288
288
|
patterns: [pattern],
|
|
@@ -331,7 +331,7 @@ export async function scanAndExtractPatterns(args) {
|
|
|
331
331
|
continue;
|
|
332
332
|
}
|
|
333
333
|
const relativePath = toRelativePath(absoluteFile, projectRoot).replace(/\\/g, '/');
|
|
334
|
-
patterns.push(buildPattern(normalized, relativePath
|
|
334
|
+
patterns.push(buildPattern(normalized, relativePath));
|
|
335
335
|
}
|
|
336
336
|
return okStructured(`已扫描 ${files.length} 个文件,提取 ${patterns.length} 个候选模式`, {
|
|
337
337
|
mode: 'directory',
|