progmune-runtime 2.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/dist/action-runtime.js +96 -0
- package/dist/actions.js +2 -0
- package/dist/consolidate.js +9 -0
- package/dist/emitter.js +166 -0
- package/dist/extract-ir-python.js +55 -0
- package/dist/extract-ir.js +143 -0
- package/dist/failure-corpus.js +113 -0
- package/dist/feedback.js +73 -0
- package/dist/generate.js +119 -0
- package/dist/generate_500.js +112 -0
- package/dist/llm.js +24 -0
- package/dist/main.js +142 -0
- package/dist/mcp-server.js +55 -0
- package/dist/mcp-server.mjs +76 -0
- package/dist/memory-layer.js +150 -0
- package/dist/p0_ssg_demo.js +64 -0
- package/dist/planner.js +224 -0
- package/dist/python-emitter.js +149 -0
- package/dist/rule-miner.js +10 -0
- package/dist/runtime.js +58 -0
- package/dist/search-planner.js +177 -0
- package/dist/semantic-validator.js +71 -0
- package/dist/semantic_guard_test.js +106 -0
- package/dist/ssg-validator.js +32 -0
- package/dist/test_failure_corpus.js +16 -0
- package/dist/utils.js +22 -0
- package/dist/validator.js +196 -0
- package/package.json +26 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ssg_validator_1 = require("./ssg-validator");
|
|
4
|
+
const authProtocol = [
|
|
5
|
+
{
|
|
6
|
+
function: 'verify_password',
|
|
7
|
+
protocol: {
|
|
8
|
+
pre_states: ['UNAUTHENTICATED'],
|
|
9
|
+
post_states: ['AUTHENTICATED'],
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
function: 'generate_jwt',
|
|
14
|
+
protocol: {
|
|
15
|
+
pre_states: ['AUTHENTICATED'],
|
|
16
|
+
post_states: ['TOKEN_ISSUED'],
|
|
17
|
+
invalidate: ['AUTHENTICATED']
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
function: 'create_session',
|
|
22
|
+
protocol: {
|
|
23
|
+
pre_states: ['TOKEN_ISSUED'],
|
|
24
|
+
post_states: ['SESSION_ACTIVE'],
|
|
25
|
+
invalidate: ['TOKEN_ISSUED']
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
];
|
|
29
|
+
function runDemo() {
|
|
30
|
+
console.log('═══ Semantic State Graph (SSG) 原型演示 ═══\n');
|
|
31
|
+
console.log('场景1:合法序列 (verify_password → generate_jwt → create_session)');
|
|
32
|
+
const legalSequence = ['verify_password', 'generate_jwt', 'create_session'];
|
|
33
|
+
const validator1 = new ssg_validator_1.StateMachineValidator(authProtocol, 'UNAUTHENTICATED');
|
|
34
|
+
let allPassed = true;
|
|
35
|
+
for (const fn of legalSequence) {
|
|
36
|
+
const result = validator1.apply(fn);
|
|
37
|
+
if (!result.valid) {
|
|
38
|
+
console.log(` ❌ ${fn} 被拦截:${result.error}`);
|
|
39
|
+
allPassed = false;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
console.log(` ✅ ${fn} 通过,当前状态:[${result.statesAfter}]`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (allPassed)
|
|
47
|
+
console.log(' ✔ 合法序列全部通过\n');
|
|
48
|
+
console.log('场景2:非法序列 (generate_jwt → verify_password)');
|
|
49
|
+
const illegalSequence = ['generate_jwt', 'verify_password'];
|
|
50
|
+
const validator2 = new ssg_validator_1.StateMachineValidator(authProtocol, 'UNAUTHENTICATED');
|
|
51
|
+
for (const fn of illegalSequence) {
|
|
52
|
+
const result = validator2.apply(fn);
|
|
53
|
+
if (!result.valid) {
|
|
54
|
+
console.log(` 🚫 ${fn} 被拦截:${result.error}`);
|
|
55
|
+
console.log(' 🛡️ SSG 成功阻止了非法状态跃迁!');
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.log(` ✅ ${fn} 通过,当前状态:[${result.statesAfter}]`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
console.log('\n═══ 演示完成 ═══');
|
|
63
|
+
}
|
|
64
|
+
runDemo();
|
package/dist/planner.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.plan = plan;
|
|
37
|
+
const llm_1 = require("./llm");
|
|
38
|
+
const action_runtime_1 = require("./action-runtime");
|
|
39
|
+
const validator_1 = require("./validator");
|
|
40
|
+
const semantic_validator_1 = require("./semantic-validator");
|
|
41
|
+
const feedback_1 = require("./feedback");
|
|
42
|
+
const utils_1 = require("./utils");
|
|
43
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
44
|
+
const memory_layer_1 = require("./memory-layer");
|
|
45
|
+
const fs = __importStar(require("fs"));
|
|
46
|
+
function enrichActions(actions, ir) {
|
|
47
|
+
return actions.map(a => {
|
|
48
|
+
if (!a || !a.kind)
|
|
49
|
+
return a;
|
|
50
|
+
if (a.kind === "call" && a.function && a.args) {
|
|
51
|
+
const def = ir.find(f => f.name === a.function);
|
|
52
|
+
if (def) {
|
|
53
|
+
a.args = a.args.map((arg, i) => {
|
|
54
|
+
if (!arg)
|
|
55
|
+
return { name: `p${i}`, type: 'any', value: null };
|
|
56
|
+
const paramDef = def.params[i];
|
|
57
|
+
if (typeof arg === 'object' && arg.value !== undefined) {
|
|
58
|
+
return { name: paramDef?.name || `p${i}`, type: paramDef?.type || 'any', value: arg.value };
|
|
59
|
+
}
|
|
60
|
+
return { name: paramDef?.name || `p${i}`, type: paramDef?.type || 'any', value: arg };
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (a.kind === "if") {
|
|
65
|
+
a.thenActions = enrichActions(a.thenActions || [], ir);
|
|
66
|
+
a.elseActions = enrichActions(a.elseActions || [], ir);
|
|
67
|
+
}
|
|
68
|
+
return a;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function determineSVL(errors) {
|
|
72
|
+
if (errors.some(e => e.includes("不存在")))
|
|
73
|
+
return "SVL-1";
|
|
74
|
+
if (errors.some(e => e.includes("类型不匹配") || e.includes("参数数量")))
|
|
75
|
+
return "SVL-2";
|
|
76
|
+
if (errors.some(e => e.includes("变量") && (e.includes("未定义") || e.includes("引用自身"))))
|
|
77
|
+
return "SVL-3";
|
|
78
|
+
if (errors.some(e => e.includes("协议") || e.includes("状态")))
|
|
79
|
+
return "SVL-4";
|
|
80
|
+
return "SVL-1";
|
|
81
|
+
}
|
|
82
|
+
function determineConstraintType(svl) {
|
|
83
|
+
switch (svl) {
|
|
84
|
+
case "SVL-1": return "symbol_existence";
|
|
85
|
+
case "SVL-2": return "type_mismatch";
|
|
86
|
+
case "SVL-3": return "dataflow";
|
|
87
|
+
case "SVL-4": return "protocol";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function plan(userIntent) {
|
|
91
|
+
(0, llm_1.resetCallCount)();
|
|
92
|
+
const ir = JSON.parse(fs.readFileSync("ir.json", "utf-8"));
|
|
93
|
+
// ========== 语义模板快速通道 ==========
|
|
94
|
+
const cachedTemplate = (0, memory_layer_1.findSemanticTemplate)(userIntent);
|
|
95
|
+
if (cachedTemplate && cachedTemplate.successRate >= 0.8 && cachedTemplate.useCount >= 2) {
|
|
96
|
+
console.log("⚡ 命中语义模板,直接复用已验证序列");
|
|
97
|
+
(0, memory_layer_1.recordEpisode)({ intent: userIntent, actions: cachedTemplate.actionSequence, success: true });
|
|
98
|
+
return cachedTemplate.actionSequence;
|
|
99
|
+
}
|
|
100
|
+
// ====================================
|
|
101
|
+
const keywords = (0, utils_1.extractKeywords)(userIntent);
|
|
102
|
+
const scored = ir.map((f) => {
|
|
103
|
+
let score = 0;
|
|
104
|
+
for (const kw of keywords) {
|
|
105
|
+
score += (0, utils_1.jaccardSimilarity)(f.name.toLowerCase(), kw);
|
|
106
|
+
if (f.name.toLowerCase().includes(kw))
|
|
107
|
+
score += 0.5;
|
|
108
|
+
}
|
|
109
|
+
return { ...f, score };
|
|
110
|
+
});
|
|
111
|
+
scored.sort((a, b) => b.score - a.score);
|
|
112
|
+
const topFuncs = scored.slice(0, 15);
|
|
113
|
+
const funcList = topFuncs.map((f) => {
|
|
114
|
+
const rate = (0, feedback_1.getFunctionSuccessRate)(f.name);
|
|
115
|
+
const star = rate > 0.8 ? "⭐" : rate > 0.5 ? "👍" : "⚠️";
|
|
116
|
+
const params = f.params.map((p) => `${p.name}: ${p.type}`).join(", ");
|
|
117
|
+
return `${star} ${f.name}(${params}) [${f.params.length}个参数] -> ${f.returnType} (成功率: ${(rate * 100).toFixed(0)}%)`;
|
|
118
|
+
}).join("\n");
|
|
119
|
+
const matchFunc = userIntent.match(/(?:实现|implement|编写|创建)\s*(\w+)\s*(?:函数|function)?/i);
|
|
120
|
+
const forbiddenFuncs = [];
|
|
121
|
+
if (matchFunc) {
|
|
122
|
+
const targetName = matchFunc[1];
|
|
123
|
+
if (ir.find((f) => f.name.toLowerCase() === targetName.toLowerCase())) {
|
|
124
|
+
forbiddenFuncs.push(targetName);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const exampleCode = `assign("query_key", "user:123")
|
|
128
|
+
callAssign("cache_get", "cached_data", "query_key")
|
|
129
|
+
ifElse("cached_data", () => {
|
|
130
|
+
output("cached_data")
|
|
131
|
+
}, () => {
|
|
132
|
+
callAssign("query_data", "fresh_data", "query_key")
|
|
133
|
+
call("cache_set", "query_key", "fresh_data")
|
|
134
|
+
output("fresh_data")
|
|
135
|
+
})`;
|
|
136
|
+
const basePrompt = `你能使用的函数:
|
|
137
|
+
${funcList}
|
|
138
|
+
|
|
139
|
+
绝对禁止调用列表外函数。
|
|
140
|
+
|
|
141
|
+
示例(缓存查询,注意 assign 先于条件):
|
|
142
|
+
${exampleCode}
|
|
143
|
+
|
|
144
|
+
全局函数及用法规则:
|
|
145
|
+
- 声明变量:assign("变量名", "值") 或 callAssign("函数", "变量名", ...)
|
|
146
|
+
- 条件分支:ifElse("变量名", () => { ... }, () => { ... })
|
|
147
|
+
- 简单分支:ifBlock("变量名", () => { ... })
|
|
148
|
+
- 调用:call("函数", "arg1", ...)
|
|
149
|
+
- 返回:output("值或变量名")
|
|
150
|
+
|
|
151
|
+
铁律:
|
|
152
|
+
1. 必须先 assign 或 callAssign 再使用变量。
|
|
153
|
+
2. 参数数量必须与函数声明一致。
|
|
154
|
+
3. 条件括号内只能是已声明的变量名。
|
|
155
|
+
|
|
156
|
+
需求:
|
|
157
|
+
${userIntent}
|
|
158
|
+
|
|
159
|
+
只输出代码。`;
|
|
160
|
+
let finalActions = [];
|
|
161
|
+
let currentPrompt = basePrompt;
|
|
162
|
+
for (let r = 0; r < 3; r++) {
|
|
163
|
+
let text;
|
|
164
|
+
try {
|
|
165
|
+
text = await (0, llm_1.generate)(currentPrompt);
|
|
166
|
+
}
|
|
167
|
+
catch (e) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (!text)
|
|
171
|
+
continue;
|
|
172
|
+
text = text.replace(/```javascript\s*/gi, '').replace(/```\s*/g, '').trim();
|
|
173
|
+
console.log("📝 LLM 生成的代码:\n", text);
|
|
174
|
+
const rawActions = (0, action_runtime_1.executeActionCode)(text);
|
|
175
|
+
if (!rawActions || rawActions.length === 0) {
|
|
176
|
+
console.log("⚠️ 代码执行失败,重试...");
|
|
177
|
+
currentPrompt = basePrompt + "\n上一次代码无效,请严格模仿示例。";
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const enriched = enrichActions(rawActions, ir);
|
|
181
|
+
const filtered = enriched.filter(a => !forbiddenFuncs.includes(a.function || ''));
|
|
182
|
+
const seqResult = (0, validator_1.validateActionSequence)(filtered);
|
|
183
|
+
if (!seqResult.valid) {
|
|
184
|
+
const errorsFlat = seqResult.errors.flat();
|
|
185
|
+
console.log("⚠️ 序列校验失败:", errorsFlat.join(", "));
|
|
186
|
+
const svl = determineSVL(errorsFlat);
|
|
187
|
+
(0, failure_corpus_1.recordFailure)({
|
|
188
|
+
intent: userIntent,
|
|
189
|
+
projectFunctions: ir.map((f) => f.name),
|
|
190
|
+
violatedSVL: svl,
|
|
191
|
+
constraintType: determineConstraintType(svl),
|
|
192
|
+
actionSequence: filtered,
|
|
193
|
+
errorDetail: errorsFlat.join("; "),
|
|
194
|
+
});
|
|
195
|
+
(0, memory_layer_1.recordEpisode)({ intent: userIntent, actions: filtered, success: false, svlViolated: svl });
|
|
196
|
+
currentPrompt = basePrompt + `\n错误:${errorsFlat.join(";")}。请修正。`;
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
const semResult = (0, semantic_validator_1.checkSemantic)(userIntent, filtered);
|
|
200
|
+
if (!semResult.valid) {
|
|
201
|
+
console.log("⚠️ 语义校验失败:", semResult.errors.join(", "));
|
|
202
|
+
(0, failure_corpus_1.recordFailure)({
|
|
203
|
+
intent: userIntent,
|
|
204
|
+
projectFunctions: ir.map((f) => f.name),
|
|
205
|
+
violatedSVL: "SVL-4",
|
|
206
|
+
constraintType: "protocol",
|
|
207
|
+
actionSequence: filtered,
|
|
208
|
+
errorDetail: semResult.errors.join("; "),
|
|
209
|
+
});
|
|
210
|
+
(0, memory_layer_1.recordEpisode)({ intent: userIntent, actions: filtered, success: false, svlViolated: "SVL-4" });
|
|
211
|
+
currentPrompt = basePrompt + `\n错误:${semResult.errors.join(";")}。请修正。`;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
finalActions = filtered;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
if (finalActions.length > 0) {
|
|
218
|
+
(0, memory_layer_1.recordEpisode)({ intent: userIntent, actions: finalActions, success: true });
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
(0, memory_layer_1.recordEpisode)({ intent: userIntent, actions: [], success: false });
|
|
222
|
+
}
|
|
223
|
+
return finalActions;
|
|
224
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.emitPython = emitPython;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
function toPythonModule(filePath) {
|
|
39
|
+
let module = filePath.replace(/\.py$/, "").replace(/\//g, ".");
|
|
40
|
+
module = module.replace(/\.$/, "").replace(/\.__init__$/, "");
|
|
41
|
+
return module;
|
|
42
|
+
}
|
|
43
|
+
function pythonValue(val) {
|
|
44
|
+
if (typeof val === 'string')
|
|
45
|
+
return JSON.stringify(val);
|
|
46
|
+
if (typeof val === 'number' || typeof val === 'boolean')
|
|
47
|
+
return String(val);
|
|
48
|
+
if (val === null || val === undefined)
|
|
49
|
+
return 'None';
|
|
50
|
+
if (typeof val === 'object') {
|
|
51
|
+
const entries = Object.entries(val).map(([k, v]) => `${JSON.stringify(k)}: ${pythonValue(v)}`);
|
|
52
|
+
return `{${entries.join(', ')}}`;
|
|
53
|
+
}
|
|
54
|
+
return 'None';
|
|
55
|
+
}
|
|
56
|
+
function emitPython(actions) {
|
|
57
|
+
const ir = JSON.parse(fs.readFileSync("ir.json", "utf-8"));
|
|
58
|
+
const funcToFile = new Map();
|
|
59
|
+
const funcToParams = new Map();
|
|
60
|
+
for (const f of ir) {
|
|
61
|
+
funcToFile.set(f.name, f.file);
|
|
62
|
+
funcToParams.set(f.name, f.params || []);
|
|
63
|
+
}
|
|
64
|
+
const imports = new Map();
|
|
65
|
+
const collectImports = (action) => {
|
|
66
|
+
if (action.kind === "call" && action.function) {
|
|
67
|
+
const file = funcToFile.get(action.function);
|
|
68
|
+
if (file) {
|
|
69
|
+
const mod = toPythonModule(file);
|
|
70
|
+
if (!imports.has(mod))
|
|
71
|
+
imports.set(mod, new Set());
|
|
72
|
+
imports.get(mod).add(action.function);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else if (action.kind === "if") {
|
|
76
|
+
(action.thenActions || []).forEach(collectImports);
|
|
77
|
+
(action.elseActions || []).forEach(collectImports);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
for (const a of actions)
|
|
81
|
+
collectImports(a);
|
|
82
|
+
let code = "";
|
|
83
|
+
for (const [mod, funcs] of imports) {
|
|
84
|
+
code += `from ${mod} import ${Array.from(funcs).join(", ")}\n`;
|
|
85
|
+
}
|
|
86
|
+
code += "\n\ndef main():\n";
|
|
87
|
+
// 使用全局变量跟踪已声明的变量
|
|
88
|
+
const declaredVars = new Set();
|
|
89
|
+
const argToPython = (val) => {
|
|
90
|
+
if (typeof val === 'string') {
|
|
91
|
+
if (declaredVars.has(val))
|
|
92
|
+
return val;
|
|
93
|
+
return JSON.stringify(val);
|
|
94
|
+
}
|
|
95
|
+
return pythonValue(val);
|
|
96
|
+
};
|
|
97
|
+
// 转换为 Python 代码行,使用数字缩进级别以确保一致性
|
|
98
|
+
const convertLines = (action, indentLevel) => {
|
|
99
|
+
const indent = " ".repeat(indentLevel);
|
|
100
|
+
if (!action || !action.kind)
|
|
101
|
+
return [];
|
|
102
|
+
if (action.kind === "call") {
|
|
103
|
+
const fname = action.function || "unknown";
|
|
104
|
+
const args = (action.args || []).map((a) => argToPython(a.value)).join(", ");
|
|
105
|
+
const resultVar = action.assignTo || `_res`;
|
|
106
|
+
declaredVars.add(resultVar);
|
|
107
|
+
return [`${indent}${resultVar} = ${fname}(${args})`];
|
|
108
|
+
}
|
|
109
|
+
if (action.kind === "if") {
|
|
110
|
+
const lines = [];
|
|
111
|
+
lines.push(`${indent}if ${action.condition}:`);
|
|
112
|
+
const thenActions = action.thenActions || [];
|
|
113
|
+
const elseActions = action.elseActions || [];
|
|
114
|
+
if (thenActions.length > 0) {
|
|
115
|
+
for (const a of thenActions) {
|
|
116
|
+
lines.push(...convertLines(a, indentLevel + 1));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// 防止空块
|
|
121
|
+
lines.push(`${indent} pass`);
|
|
122
|
+
}
|
|
123
|
+
if (elseActions.length > 0) {
|
|
124
|
+
lines.push(`${indent}else:`);
|
|
125
|
+
for (const a of elseActions) {
|
|
126
|
+
lines.push(...convertLines(a, indentLevel + 1));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return lines;
|
|
130
|
+
}
|
|
131
|
+
if (action.kind === "return") {
|
|
132
|
+
const val = action.value;
|
|
133
|
+
if (typeof val === 'string') {
|
|
134
|
+
if (declaredVars.has(val))
|
|
135
|
+
return [`${indent}return ${val}`];
|
|
136
|
+
return [`${indent}return ${JSON.stringify(val)}`];
|
|
137
|
+
}
|
|
138
|
+
return [`${indent}return ${pythonValue(val)}`];
|
|
139
|
+
}
|
|
140
|
+
return [];
|
|
141
|
+
};
|
|
142
|
+
const lines = [];
|
|
143
|
+
for (const a of actions) {
|
|
144
|
+
lines.push(...convertLines(a, 1));
|
|
145
|
+
}
|
|
146
|
+
code += lines.join("\n") + "\n";
|
|
147
|
+
code += "\nif __name__ == '__main__':\n main()\n";
|
|
148
|
+
return code;
|
|
149
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
4
|
+
console.log("═══ 失败模式分析 ═══");
|
|
5
|
+
const patterns = (0, failure_corpus_1.getTopFailurePatterns)(5);
|
|
6
|
+
console.log("Top 5 失败模式:");
|
|
7
|
+
patterns.forEach(p => console.log(` ${p.pattern}: ${p.count} 次`));
|
|
8
|
+
console.log("\n候选规则建议:");
|
|
9
|
+
const rules = (0, failure_corpus_1.generateCandidateRules)();
|
|
10
|
+
rules.forEach(r => console.log(` - ${r}`));
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runAndCheck = runAndCheck;
|
|
37
|
+
const child_process_1 = require("child_process");
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
function runAndCheck(code) {
|
|
41
|
+
// 把临时文件写入 test-login 目录,使用它的 tsconfig 编译
|
|
42
|
+
const tmpDir = path.resolve("test-login");
|
|
43
|
+
const tmpFile = path.join(tmpDir, "_temp_check.ts");
|
|
44
|
+
fs.writeFileSync(tmpFile, code);
|
|
45
|
+
try {
|
|
46
|
+
(0, child_process_1.execSync)(`npx ts-node --project ${tmpDir}/tsconfig.json ${tmpFile}`, {
|
|
47
|
+
timeout: 5000,
|
|
48
|
+
encoding: "utf-8",
|
|
49
|
+
});
|
|
50
|
+
fs.unlinkSync(tmpFile);
|
|
51
|
+
return { success: true };
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
if (fs.existsSync(tmpFile))
|
|
55
|
+
fs.unlinkSync(tmpFile);
|
|
56
|
+
return { success: false, error: e.stderr?.toString() || e.toString() };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.searchPlan = searchPlan;
|
|
37
|
+
const validator_1 = require("./validator");
|
|
38
|
+
const llm_1 = require("./llm");
|
|
39
|
+
const feedback_1 = require("./feedback");
|
|
40
|
+
const utils_1 = require("./utils");
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
// ⚖️ 可调权重(修改这些值后重新运行压力测试即可)
|
|
43
|
+
const WEIGHT_STATIC_SCORE = 0.3; // 静态文本相似度的权重
|
|
44
|
+
const WEIGHT_LLM_SCORE = 0.7; // LLM 评分的权重
|
|
45
|
+
const WEIGHT_HISTORY = 0.4; // 反馈系统成功率的权重
|
|
46
|
+
const WEIGHT_GOAL_COMPLETION = 0.5; // 目标完成奖励
|
|
47
|
+
const STATIC_HIGH_THRESHOLD = 0.6; // 静态评分超过此值时,跳过LLM调用
|
|
48
|
+
function loadIR() {
|
|
49
|
+
return JSON.parse(fs.readFileSync("ir.json", "utf-8"));
|
|
50
|
+
}
|
|
51
|
+
const staticScoreCache = new Map();
|
|
52
|
+
function getStaticScore(funcName, goal) {
|
|
53
|
+
const key = `${funcName}|${goal}`;
|
|
54
|
+
if (staticScoreCache.has(key))
|
|
55
|
+
return staticScoreCache.get(key);
|
|
56
|
+
let s = 0;
|
|
57
|
+
const combined = funcName.toLowerCase();
|
|
58
|
+
const goalWords = goal.toLowerCase().split(/\s+/);
|
|
59
|
+
for (const w of goalWords) {
|
|
60
|
+
if (combined.includes(w))
|
|
61
|
+
s += 0.3;
|
|
62
|
+
s += (0, utils_1.jaccardSimilarity)(combined, w) * 0.1;
|
|
63
|
+
}
|
|
64
|
+
s = Math.min(1, s);
|
|
65
|
+
staticScoreCache.set(key, s);
|
|
66
|
+
return s;
|
|
67
|
+
}
|
|
68
|
+
async function decomposeGoals(intent, functions) {
|
|
69
|
+
const funcNames = functions.map(f => f.name).join(", ");
|
|
70
|
+
const prompt = `将以下需求分解为2-3个独立的子目标,每个子目标必须是一个简短的动词短语。绝对不能合并。\n需求:${intent}\n可用函数:${funcNames}\n只返回JSON字符串数组,如 ["验证密码","生成JWT","返回错误"]`;
|
|
71
|
+
const text = await (0, llm_1.generate)(prompt);
|
|
72
|
+
try {
|
|
73
|
+
let cleaned = text.replace(/```json\s*/gi, '[').replace(/```\s*/g, ']');
|
|
74
|
+
const match = cleaned.match(/\[([\s\S]*)\]/);
|
|
75
|
+
if (match) {
|
|
76
|
+
let parsed = JSON.parse(match[0]);
|
|
77
|
+
if (Array.isArray(parsed) && parsed.length > 0 && typeof parsed[0] === 'object') {
|
|
78
|
+
parsed = parsed.map((o) => o.description || o.subgoal || String(o));
|
|
79
|
+
}
|
|
80
|
+
if (typeof parsed === 'string')
|
|
81
|
+
parsed = [parsed];
|
|
82
|
+
const result = [];
|
|
83
|
+
for (const item of parsed) {
|
|
84
|
+
if (typeof item === 'string' && item.includes(','))
|
|
85
|
+
result.push(...item.split(',').map(s => s.trim()).filter(s => s));
|
|
86
|
+
else if (typeof item === 'string')
|
|
87
|
+
result.push(item);
|
|
88
|
+
}
|
|
89
|
+
return result.slice(0, 3);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch { }
|
|
93
|
+
return [intent];
|
|
94
|
+
}
|
|
95
|
+
async function functionMatchesGoal(funcName, goal, staticScore) {
|
|
96
|
+
if (staticScore > STATIC_HIGH_THRESHOLD)
|
|
97
|
+
return staticScore;
|
|
98
|
+
const prompt = `函数 ${funcName} 对 "${goal}" 的贡献度(0-10整数),只返回数字:`;
|
|
99
|
+
const resp = await (0, llm_1.generate)(prompt);
|
|
100
|
+
const s = parseFloat(resp.trim());
|
|
101
|
+
return isNaN(s) ? 0.3 : Math.min(1, s / 10);
|
|
102
|
+
}
|
|
103
|
+
async function searchPlan(intent, beamWidth = 2, maxDepth = 6) {
|
|
104
|
+
(0, llm_1.resetCallCount)();
|
|
105
|
+
staticScoreCache.clear();
|
|
106
|
+
const ir = loadIR();
|
|
107
|
+
const goals = await decomposeGoals(intent, ir);
|
|
108
|
+
console.log("🎯 目标栈:", goals);
|
|
109
|
+
let beam = [{
|
|
110
|
+
actions: [],
|
|
111
|
+
declaredVars: new Map(),
|
|
112
|
+
currentGoalIndex: 0,
|
|
113
|
+
score: 0,
|
|
114
|
+
}];
|
|
115
|
+
let bestCandidate = null;
|
|
116
|
+
for (let step = 0; step < maxDepth; step++) {
|
|
117
|
+
const newCandidates = [];
|
|
118
|
+
for (const cand of beam) {
|
|
119
|
+
if (cand.currentGoalIndex >= goals.length) {
|
|
120
|
+
newCandidates.push(cand);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const currentGoal = goals[cand.currentGoalIndex];
|
|
124
|
+
const scoredFuncs = ir.map((f) => ({
|
|
125
|
+
...f,
|
|
126
|
+
staticScore: getStaticScore(f.name, currentGoal)
|
|
127
|
+
})).filter((f) => f.staticScore > 0.05)
|
|
128
|
+
.sort((a, b) => b.staticScore - a.staticScore)
|
|
129
|
+
.slice(0, 5);
|
|
130
|
+
for (const func of scoredFuncs) {
|
|
131
|
+
const alreadyUsed = cand.actions.some(a => a.kind === "call" && a.function === func.name && a._goalIndex === cand.currentGoalIndex);
|
|
132
|
+
if (alreadyUsed)
|
|
133
|
+
continue;
|
|
134
|
+
const relevance = await functionMatchesGoal(func.name, currentGoal, func.staticScore);
|
|
135
|
+
if (relevance < 0.2)
|
|
136
|
+
continue;
|
|
137
|
+
const args = func.params.map((p) => ({
|
|
138
|
+
name: p.name,
|
|
139
|
+
type: p.type,
|
|
140
|
+
value: findCompatibleVar(cand.declaredVars, p.type) || `input_${step}_${p.name}`,
|
|
141
|
+
}));
|
|
142
|
+
const action = { kind: "call", function: func.name, args, assignTo: `var_${step}_${func.name}` };
|
|
143
|
+
action._goalIndex = cand.currentGoalIndex;
|
|
144
|
+
const validation = (0, validator_1.validateAction)(action);
|
|
145
|
+
if (!validation.valid)
|
|
146
|
+
continue;
|
|
147
|
+
const newVars = new Map(cand.declaredVars);
|
|
148
|
+
if (action.assignTo)
|
|
149
|
+
newVars.set(action.assignTo, func.returnType);
|
|
150
|
+
const goalCompleted = relevance > 0.5; // 降低目标完成门槛
|
|
151
|
+
const nextGoalIndex = goalCompleted ? cand.currentGoalIndex + 1 : cand.currentGoalIndex;
|
|
152
|
+
const successRate = (0, feedback_1.getFunctionSuccessRate)(func.name);
|
|
153
|
+
const finalRelevance = (func.staticScore * WEIGHT_STATIC_SCORE + relevance * WEIGHT_LLM_SCORE) / (WEIGHT_STATIC_SCORE + WEIGHT_LLM_SCORE);
|
|
154
|
+
const newScore = cand.score + successRate * WEIGHT_HISTORY + finalRelevance * (1 - WEIGHT_HISTORY) + (goalCompleted ? WEIGHT_GOAL_COMPLETION : 0);
|
|
155
|
+
newCandidates.push({ actions: [...cand.actions, action], declaredVars: newVars, currentGoalIndex: nextGoalIndex, score: newScore });
|
|
156
|
+
if (newCandidates.length > beamWidth * 10)
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
newCandidates.sort((a, b) => b.score - a.score);
|
|
161
|
+
beam = newCandidates.slice(0, beamWidth);
|
|
162
|
+
const complete = beam.find(c => c.currentGoalIndex >= goals.length);
|
|
163
|
+
if (complete && (!bestCandidate || complete.score > bestCandidate.score))
|
|
164
|
+
bestCandidate = complete;
|
|
165
|
+
if (beam.length === 0)
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
const winner = bestCandidate || beam[0];
|
|
169
|
+
return winner ? winner.actions : [];
|
|
170
|
+
}
|
|
171
|
+
function findCompatibleVar(declaredVars, neededType) {
|
|
172
|
+
for (const [name, type] of declaredVars) {
|
|
173
|
+
if (type === neededType || neededType === "any" || type === "any")
|
|
174
|
+
return name;
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|