lingshu-solver 1.0.0 → 1.0.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 +9 -6
- package/mcp-server.js +55 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ Krawczyk 算子做解认证,并尽力穷尽多解。
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
```
|
|
59
|
-
> `npx`
|
|
59
|
+
> `npx` 版已发布到 npm,现在即可一键 `npx -y lingshu-solver`。如需最新源码也可 `git clone` 后用方式 C。
|
|
60
60
|
|
|
61
61
|
**方式 C · 本地 clone + 指定路径**
|
|
62
62
|
```bash
|
|
@@ -111,7 +111,7 @@ node test/regression.js # 跑回归测试(28 用例)
|
|
|
111
111
|
| 形态 | 端点 / 命令 | 适用 |
|
|
112
112
|
|---|---|---|
|
|
113
113
|
| **远程 HTTP(已上线)** | `http://159.75.154.206:3000/mcp` | 任何支持 Streamable HTTP 的 MCP 客户端,零安装 |
|
|
114
|
-
| 本地 stdio(npx) | `npx -y lingshu-solver` | 本机已装 Node,npm
|
|
114
|
+
| 本地 stdio(npx) | `npx -y lingshu-solver` | 本机已装 Node,npm 已发布,直接可用 |
|
|
115
115
|
| 本地 stdio(clone) | `node mcp-server.js` | 开发者 / 离线自托管 |
|
|
116
116
|
|
|
117
117
|
**远程 HTTP 服务端代码**:`http-mcp-server.js`(零依赖,仅用 Node 内置模块;与 `mcp-server.js` 共享 `solver-core.js` 求解核心,结果同源一致)。如需自托管远程服务:
|
|
@@ -132,7 +132,7 @@ PORT=3000 node http-mcp-server.js
|
|
|
132
132
|
}
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
-
**本地 stdio · 一行命令(npm
|
|
135
|
+
**本地 stdio · 一行命令(npm 已发布,直接可用):**
|
|
136
136
|
```json
|
|
137
137
|
{
|
|
138
138
|
"mcpServers": {
|
|
@@ -143,7 +143,7 @@ PORT=3000 node http-mcp-server.js
|
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
```
|
|
146
|
-
> 注:`npx lingshu-solver`
|
|
146
|
+
> 注:`npx -y lingshu-solver` 已发布到 npm,直接可用。如需指定本地路径,用下方「手动指定本地路径」版(先 clone 仓库)。
|
|
147
147
|
|
|
148
148
|
**备选 · 手动指定本地路径(已 clone 仓库时):**
|
|
149
149
|
```json
|
|
@@ -184,12 +184,15 @@ PORT=3000 node http-mcp-server.js
|
|
|
184
184
|
"truncated": false,
|
|
185
185
|
"precisionDecimals": 6,
|
|
186
186
|
"solutionCount": 2,
|
|
187
|
-
"
|
|
188
|
-
"
|
|
187
|
+
"summary": "找到 2 个实数解(全部经 Krawczyk 区间认证)。",
|
|
188
|
+
"recommended": { "values": [3, 4], "tier": "proven", "certified": true, "text": "x=3.000000, y=4.000000", "internals": { "residual": 0, "certifiedRadius": 0.00001 } },
|
|
189
|
+
"solutions": [ { "values": [3, 4], "tier": "proven", "certified": true, "text": "x=3.000000, y=4.000000", "internals": { "residual": 0, "certifiedRadius": 0.00001 } }, ... ],
|
|
189
190
|
"warnings": []
|
|
190
191
|
}
|
|
191
192
|
```
|
|
192
193
|
- `resultType`:`1=empty(无解)` / `2=finite(有限解)` / `3=infinite(无限解集,仅给距原点最近的推荐解)`。
|
|
194
|
+
- `summary`:中文一句话总览,适合直接展示给用户或日志。
|
|
195
|
+
- 每解字段:`values`(6 位小数数值数组)、`tier`、`certified`、`text`(人类可读,如 `"x=3.000000, y=4.000000"`);残差等内部数值收在 `internals` 子块,机器可整块跳过以降低 token 噪音。
|
|
193
196
|
- `tier`:`proven`(Krawczyk 认证)/ `candidate`(未证但可能为解)/ `structural`(结构推导)。
|
|
194
197
|
|
|
195
198
|
### 工具二:`give_feedback`
|
package/mcp-server.js
CHANGED
|
@@ -36,9 +36,18 @@ function appendLog(p) {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// ---- 求解结果整理 ----
|
|
39
|
+
// 数值格式化:固定 6 位小数(产品规格「6位小数有限网格」),与界面一致。
|
|
40
|
+
// 解点 values 经 roundToGrid 吸附到 6 位网格,实际残差通常 ≤ 1e-9。
|
|
41
|
+
const fmt6 = (v) => (typeof v === 'number' && isFinite(v)) ? v.toFixed(6) : String(v);
|
|
42
|
+
|
|
39
43
|
function shapeResult(r) {
|
|
40
44
|
const sols = Array.isArray(r.solutions) ? r.solutions : [];
|
|
41
45
|
const meta = r.meta || {};
|
|
46
|
+
// 变量名:优先用求解器识别结果,否则退化为 x1/x2/...
|
|
47
|
+
const varNames = (Array.isArray(r.varNames) && r.varNames.length)
|
|
48
|
+
? r.varNames
|
|
49
|
+
: (sols[0] && Array.isArray(sols[0].values) ? sols[0].values.map((_, i) => 'x' + (i + 1)) : []);
|
|
50
|
+
|
|
42
51
|
// 推荐解:取范数最小者(与界面"距原点最近"一致)
|
|
43
52
|
let recommended = null;
|
|
44
53
|
let best = Infinity;
|
|
@@ -51,19 +60,58 @@ function shapeResult(r) {
|
|
|
51
60
|
const tierSet = new Set(sols.map(s => (s && s.tier) || 'unknown'));
|
|
52
61
|
const allProven = sols.length > 0 && [...tierSet].every(t => t === 'proven');
|
|
53
62
|
const typeName = r.resultType === 1 ? 'empty' : r.resultType === 3 ? 'infinite' : 'finite';
|
|
63
|
+
|
|
64
|
+
// 每个解:保留机器友好字段(values/tier/certified)+ 人类可读 text;
|
|
65
|
+
// 内部数值(residual/certifiedRadius)收进 internals,机器可整块跳过。
|
|
66
|
+
const cleanSols = sols.map((s) => {
|
|
67
|
+
const vals = Array.isArray(s.values) ? s.values : [];
|
|
68
|
+
const text = varNames.map((vn, i) => `${vn}=${fmt6(vals[i])}`).join(', ');
|
|
69
|
+
return {
|
|
70
|
+
values: vals,
|
|
71
|
+
tier: s.tier || 'unknown',
|
|
72
|
+
certified: !!s.certified,
|
|
73
|
+
text: text,
|
|
74
|
+
internals: {
|
|
75
|
+
residual: (typeof s.residual === 'number') ? s.residual : null,
|
|
76
|
+
certifiedRadius: (typeof s.certifiedRadius === 'number') ? s.certifiedRadius : null
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
const recommendedClean = recommended ? cleanSols[sols.indexOf(recommended)] : null;
|
|
81
|
+
|
|
82
|
+
// 人类可读总览(A)
|
|
83
|
+
let summary;
|
|
84
|
+
if (typeName === 'empty') {
|
|
85
|
+
summary = '严格证明:该方程组无实数解。';
|
|
86
|
+
} else if (typeName === 'infinite') {
|
|
87
|
+
summary = `无限解集;给出距原点最近的推荐解(共展示 ${sols.length} 个候选)。`;
|
|
88
|
+
} else {
|
|
89
|
+
summary = `找到 ${sols.length} 个实数解${allProven ? '(全部经 Krawczyk 区间认证)' : ''}。`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 诊断信息(B):仅精选对调用方有用的少量字段,不再透传 meta 中 19 个内部运维字段,
|
|
93
|
+
// 以降低机器侧 token 噪音。如需完整内部轨迹,可另接调试端点。
|
|
94
|
+
const diagnostics = {
|
|
95
|
+
solverVersion: meta.solverVersion || null,
|
|
96
|
+
truncated: !!(r.truncated || meta.truncated),
|
|
97
|
+
terminatedBy: meta.terminatedBy || null,
|
|
98
|
+
elapsedMs: (typeof meta.elapsedMs === 'number') ? meta.elapsedMs : (typeof r.timeMs === 'number' ? r.timeMs : null),
|
|
99
|
+
provenCount: (typeof r.provenCount === 'number') ? r.provenCount : null,
|
|
100
|
+
completeness: (typeof r.completeness === 'number') ? r.completeness : null
|
|
101
|
+
};
|
|
102
|
+
|
|
54
103
|
return {
|
|
55
104
|
resultType: r.resultType,
|
|
56
105
|
resultTypeName: typeName,
|
|
57
106
|
certified: allProven,
|
|
58
|
-
truncated:
|
|
59
|
-
// 输出精度固定 6 位小数(产品规格「6位小数有限网格」),与界面一致,不提供位数切换。
|
|
60
|
-
// 解点 values 经 roundToGrid 吸附到 6 位网格,实际残差通常 ≤ 1e-9。
|
|
107
|
+
truncated: diagnostics.truncated,
|
|
61
108
|
precisionDecimals: 6,
|
|
62
109
|
solutionCount: sols.length,
|
|
63
|
-
|
|
64
|
-
|
|
110
|
+
summary: summary,
|
|
111
|
+
recommended: recommendedClean,
|
|
112
|
+
solutions: cleanSols,
|
|
65
113
|
warnings: r.warnings || [],
|
|
66
|
-
diagnostics:
|
|
114
|
+
diagnostics: diagnostics
|
|
67
115
|
};
|
|
68
116
|
}
|
|
69
117
|
|
|
@@ -103,7 +151,7 @@ const TOOLS = [
|
|
|
103
151
|
'不适用:纯符号推导/闭式证明、微分方程初值问题、整数/必不等于等强制约束(暂不支持)。' +
|
|
104
152
|
'输入:equations 为含 "=" 的方程字符串数组,如 ["x^2+y^2=25","x+y=7"];variables 可选(不填自动识别,最多6个);domain 可选(如 {"x":[-30,30]}),否则默认每变量 ±1e6。' +
|
|
105
153
|
'硬限制:变量 ≤6;方程 1–64 条且数量须 ≥ 变量数;单次方程文本 ≤100KB;输出固定 6 位小数(不可切换)。' +
|
|
106
|
-
'输出(JSON):resultType=empty(严格证无实数解)/finite(有限已验证解)/infinite(无限解集,仅给距原点最近推荐解);solutions[] 每解含 values[]
|
|
154
|
+
'输出(JSON):resultType=empty(严格证无实数解)/finite(有限已验证解)/infinite(无限解集,仅给距原点最近推荐解);summary=中文一句话总览;solutions[] 每解含 values[](6位小数数值)、tier(proven=Krawczyk已认证/likely/candidate)、certified、text(人类可读如"x=4.000000, y=3.000000"),残差等内部数值收在 internals 子块(机器可跳过);certified=是否全proven;recommended=距原点最近解的精简结构。' +
|
|
107
155
|
'truncated=true:预算内未完成全局分支判定、未证明已穷尽——不等于一定漏解,多数情况全部真解已找到;极端病态下可能遗漏个别解,可缩 domain 或提高 budget 重试。' +
|
|
108
156
|
'错误返回 error.type(invalid_input=输入不合法/超限,internal_error=内部异常)。遇卡点或认为结果有误,请调用 give_feedback(内容仅落本地日志,不外传)。相同输入永远返回完全相同结果,可安全缓存与重复调用。',
|
|
109
157
|
inputSchema: {
|
package/package.json
CHANGED