dsh-math-calculator 2.1.0 → 2.2.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +951 -0
  2. package/README.md +64 -50
  3. package/dsh.plugin.json +2 -2
  4. package/lib/__wtest.txt +1 -0
  5. package/lib/awareness.js +69 -20
  6. package/lib/format.js +522 -13
  7. package/lib/formula-library-em.js +428 -0
  8. package/lib/formulas.js +28 -1
  9. package/lib/guards.js +653 -0
  10. package/lib/help.js +509 -0
  11. package/lib/index.js +1367 -212
  12. package/lib/ops/shared.js +547 -6
  13. package/lib/ops/units-op.js +116 -10
  14. package/lib/ops/workspace-op.js +10 -0
  15. package/lib/playbook.js +32 -7
  16. package/lib/types/format.d.ts +31 -1
  17. package/lib/types/formula-library-em.d.ts +28 -0
  18. package/lib/types/formulas.d.ts +2 -0
  19. package/lib/types/guards.d.ts +255 -0
  20. package/lib/types/help.d.ts +70 -0
  21. package/lib/types/index.d.ts +34 -1
  22. package/lib/types/ops/shared.d.ts +87 -3
  23. package/lib/types/playbook.d.ts +28 -0
  24. package/lib/types/units-data.d.ts +253 -0
  25. package/lib/types/units.d.ts +54 -4
  26. package/lib/types/workspace.d.ts +50 -0
  27. package/lib/units-data.js +1037 -0
  28. package/lib/units.js +82 -117
  29. package/lib/workspace.js +54 -0
  30. package/package.json +1 -1
  31. package/src/awareness.ts +69 -20
  32. package/src/format.ts +520 -12
  33. package/src/formula-library-em.ts +435 -0
  34. package/src/formulas.ts +35 -4
  35. package/src/guards.ts +673 -0
  36. package/src/help.ts +543 -0
  37. package/src/index.ts +1502 -213
  38. package/src/ops/shared.ts +589 -9
  39. package/src/ops/units-op.ts +125 -9
  40. package/src/ops/workspace-op.ts +10 -0
  41. package/src/playbook.ts +32 -7
  42. package/src/units-data.ts +1128 -0
  43. package/src/units.ts +149 -130
  44. package/src/workspace.ts +65 -0
package/lib/units.js CHANGED
@@ -34,126 +34,30 @@
34
34
  *
35
35
  * @module dsh-math-calculator/units
36
36
  */
37
- /** 每个量纲的基准单位(factor = 1 的那个)。 */
38
- export const BASE_UNIT = {
39
- length: 'm',
40
- mass: 'kg',
41
- time: 's',
42
- area: 'm²',
43
- volume: 'm³',
44
- energy: 'J',
45
- power: 'W',
46
- temperature: 'K',
47
- speed: 'm/s',
48
- };
37
+ import { ALL_UNITS } from './units-data.js';
38
+ /**
39
+ * 每个量纲的基准单位(factor = 1 的那个)—— 即「公制中转点」。
40
+ *
41
+ * 定义在 `units-data.ts`,这里再导出,保持旧的导入路径可用。
42
+ */
43
+ import { DIMENSION_BASE, DIMENSION_LABEL, DIMENSION_ORDER } from './units-data.js';
44
+ /** 每个量纲的基准单位 —— 即「公制中转点」。 */
45
+ export const BASE_UNIT = DIMENSION_BASE;
49
46
  /** 量纲的中文名。 */
50
- export const DIMENSION_LABEL = {
51
- length: '长度',
52
- mass: '质量',
53
- time: '时间',
54
- area: '面积',
55
- volume: '体积',
56
- energy: '能量',
57
- power: '功率',
58
- temperature: '温度',
59
- speed: '速度',
60
- };
47
+ export { DIMENSION_LABEL, DIMENSION_ORDER };
61
48
  /**
62
49
  * 内置单位表。
63
50
  *
64
51
  * ⚠️ 中文古制的换算**历朝不同**,这里用最常见的近似值并在 note 里标注。
65
52
  * 作者若需要精确到某个朝代,用 `customUnits` 覆盖。
66
53
  */
67
- export const UNITS = [
68
- // ── 长度 ──
69
- { name: 'm', dimension: 'length', factor: 1, note: '基准单位' },
70
- { name: 'km', dimension: 'length', factor: 1000 },
71
- { name: 'cm', dimension: 'length', factor: 0.01 },
72
- { name: 'mm', dimension: 'length', factor: 0.001 },
73
- {
74
- name: '里',
75
- dimension: 'length',
76
- factor: 500,
77
- note: '市里 = 500 m。周制约 415 m、汉制约 415 m、清制 576 m——写古代按朝代覆盖',
78
- },
79
- { name: '丈', dimension: 'length', factor: 3.2, note: '市丈 = 3.2 m(10 尺)' },
80
- { name: '尺', dimension: 'length', factor: 0.32, note: '市尺 ≈ 32 cm。汉尺约 23 cm、明清营造尺约 32 cm' },
81
- { name: '寸', dimension: 'length', factor: 0.032, note: '市寸 = 1/10 尺' },
82
- { name: '步', dimension: 'length', factor: 1.6, note: '古代一步 ≈ 5 尺 ≈ 1.6 m(「百步穿杨」约 160 m)' },
83
- { name: 'mile', aliases: ['英里', 'mi'], dimension: 'length', factor: 1609.344 },
84
- { name: 'ft', aliases: ['英尺'], dimension: 'length', factor: 0.3048 },
85
- { name: 'in', aliases: ['英寸'], dimension: 'length', factor: 0.0254 },
86
- { name: 'nmi', aliases: ['海里'], dimension: 'length', factor: 1852 },
87
- { name: 'AU', aliases: ['天文单位'], dimension: 'length', factor: 1.495978707e11, note: '日地平均距离' },
88
- { name: 'ly', aliases: ['光年'], dimension: 'length', factor: 9.4607304725808e15 },
89
- { name: 'pc', aliases: ['秒差距'], dimension: 'length', factor: 3.0856775814913673e16 },
90
- { name: 'Rearth', aliases: ['地球半径'], dimension: 'length', factor: 6.371e6 },
91
- { name: 'Rsun', aliases: ['太阳半径'], dimension: 'length', factor: 6.957e8 },
92
- // ── 质量 ──
93
- { name: 'kg', dimension: 'mass', factor: 1, note: '基准单位' },
94
- { name: 'g', dimension: 'mass', factor: 0.001 },
95
- { name: 't', aliases: ['吨'], dimension: 'mass', factor: 1000 },
96
- { name: '斤', dimension: 'mass', factor: 0.5, note: '市斤 = 500 g(10 两)' },
97
- { name: '两', dimension: 'mass', factor: 0.05, note: '市两 = 50 g' },
98
- { name: '石', dimension: 'mass', factor: 60, note: '容量/重量混用单位,此处按「一石米约 60 kg」估' },
99
- { name: 'lb', aliases: ['磅'], dimension: 'mass', factor: 0.45359237 },
100
- { name: 'oz', aliases: ['盎司'], dimension: 'mass', factor: 0.028349523125 },
101
- { name: 'Mearth', aliases: ['地球质量'], dimension: 'mass', factor: 5.972e24 },
102
- { name: 'Msun', aliases: ['太阳质量'], dimension: 'mass', factor: 1.989e30 },
103
- // ── 时间 ──
104
- { name: 's', dimension: 'time', factor: 1, note: '基准单位' },
105
- { name: 'min', aliases: ['分钟'], dimension: 'time', factor: 60 },
106
- { name: 'h', aliases: ['小时'], dimension: 'time', factor: 3600, note: '与普朗克常数 h 同名,单位换算里按小时理解' },
107
- { name: 'day', aliases: ['天', '日'], dimension: 'time', factor: 86400 },
108
- { name: 'year', aliases: ['年'], dimension: 'time', factor: 3.15576e7, note: '儒略年 = 365.25 天' },
109
- { name: 'Gyr', aliases: ['十亿年'], dimension: 'time', factor: 3.15576e16 },
110
- { name: '刻', dimension: 'time', factor: 900, note: '古代一刻 ≈ 15 分钟(百刻制一天)' },
111
- { name: '时辰', dimension: 'time', factor: 7200, note: '一个时辰 = 2 小时(十二时辰制)' },
112
- { name: '更', dimension: 'time', factor: 7200, note: '一夜五更,每更约 2 小时' },
113
- // ── 面积 ──
114
- { name: 'm²', dimension: 'area', factor: 1, note: '基准单位' },
115
- { name: 'km²', dimension: 'area', factor: 1e6 },
116
- { name: 'ha', aliases: ['公顷'], dimension: 'area', factor: 1e4 },
117
- { name: '亩', dimension: 'area', factor: 666.6666666666666, note: '市亩 ≈ 666.7 m²(15 亩 = 1 公顷)' },
118
- { name: '顷', dimension: 'area', factor: 66666.66666666667, note: '一顷 = 100 亩' },
119
- { name: 'acre', aliases: ['英亩'], dimension: 'area', factor: 4046.8564224 },
120
- // ── 体积 ──
121
- { name: 'm³', dimension: 'volume', factor: 1, note: '基准单位' },
122
- { name: 'L', aliases: ['升'], dimension: 'volume', factor: 0.001 },
123
- { name: '斗', dimension: 'volume', factor: 0.01, note: '市斗 = 10 L;古代一斗约 2—20 L,差异极大' },
124
- { name: 'gal', aliases: ['加仑'], dimension: 'volume', factor: 0.003785411784, note: '美制加仑' },
125
- // ── 能量 ──
126
- { name: 'J', dimension: 'energy', factor: 1, note: '基准单位' },
127
- { name: 'kJ', dimension: 'energy', factor: 1000 },
128
- { name: 'MJ', dimension: 'energy', factor: 1e6 },
129
- { name: 'GJ', dimension: 'energy', factor: 1e9 },
130
- { name: 'kWh', aliases: ['度'], dimension: 'energy', factor: 3.6e6, note: '一度电 = 3.6 MJ' },
131
- { name: 'cal', aliases: ['卡'], dimension: 'energy', factor: 4.184 },
132
- { name: 'kcal', aliases: ['大卡', '千卡'], dimension: 'energy', factor: 4184, note: '营养学的「卡路里」其实是大卡' },
133
- { name: 'TNT', dimension: 'energy', factor: 4.184e9, note: '1 吨 TNT 当量' },
134
- { name: 'eV', dimension: 'energy', factor: 1.602176634e-19 },
135
- { name: 'eVperBond', aliases: [], dimension: 'energy', factor: 1.602176634e-19 },
136
- // ── 功率 ──
137
- { name: 'W', dimension: 'power', factor: 1, note: '基准单位' },
138
- { name: 'kW', dimension: 'power', factor: 1000 },
139
- { name: 'MW', dimension: 'power', factor: 1e6 },
140
- { name: 'GW', dimension: 'power', factor: 1e9 },
141
- { name: 'TW', dimension: 'power', factor: 1e12 },
142
- { name: 'hp', aliases: ['马力'], dimension: 'power', factor: 745.6998715822702 },
143
- { name: '人', aliases: ['人力'], dimension: 'power', factor: 75, note: '一个成年人持续体力输出约 75—100 W(长时间)' },
144
- { name: '畜', aliases: ['畜力'], dimension: 'power', factor: 500, note: '一头上等役畜持续输出约 500 W' },
145
- // ── 温度 ──
146
- // 温度是仿射换算(有偏移),不能只用系数;见 convert() 里的专门分支
147
- { name: 'K', dimension: 'temperature', factor: 1, note: '基准单位,无偏移' },
148
- { name: '°C', aliases: ['℃', '摄氏度'], dimension: 'temperature', factor: 1, note: 'K = °C + 273.15' },
149
- { name: '°F', aliases: ['℉', '华氏度'], dimension: 'temperature', factor: 5 / 9, note: 'K = (°F + 459.67) × 5/9' },
150
- // ── 速度 ──
151
- { name: 'm/s', dimension: 'speed', factor: 1, note: '基准单位' },
152
- { name: 'km/h', dimension: 'speed', factor: 1 / 3.6 },
153
- { name: 'mph', aliases: ['英里每小时'], dimension: 'speed', factor: 0.44704 },
154
- { name: 'mach', aliases: ['马赫'], dimension: 'speed', factor: 340.29, note: '按海平面 15°C 声速折算;高空声速更低' },
155
- { name: 'c', aliases: ['光速'], dimension: 'speed', factor: 299792458 },
156
- ];
54
+ /**
55
+ * 内置单位表 —— 从 `units-data.ts` 导入(那里按体系分节,便于查阅与扩充)。
56
+ *
57
+ * 现在是 **288 条**:公制(含 SI 词头)、中国市制与古制、英制与美制、
58
+ * 航海、天文、日本、俄国、印度、古希腊罗马,外加数据量/角度/力/频率。
59
+ */
60
+ export const UNITS = ALL_UNITS;
157
61
  /**
158
62
  * 按名字查单位(含别名)。
159
63
  *
@@ -270,10 +174,71 @@ export function convert(value, fromName, toName, custom) {
270
174
  else {
271
175
  const inBase = value * from.factor;
272
176
  result = inBase / to.factor;
273
- steps.push('1 ' + from.name + ' = ' + from.factor + ' ' + BASE_UNIT[from.dimension]);
274
- steps.push(show(value) + ' ' + from.name + ' = ' + show(inBase) + ' ' + BASE_UNIT[from.dimension]);
275
- steps.push('1 ' + to.name + ' = ' + to.factor + ' ' + BASE_UNIT[to.dimension] +
276
- ',故结果 = ' + show(result) + ' ' + to.name);
177
+ /**
178
+ * 代入过程只写「有信息量」的步骤。
179
+ *
180
+ * ## 修的是什么
181
+ *
182
+ * 实测反馈(2026-11-06)原话:换算 kg → t 时「代入过程」里出现
183
+ * 「1 kg = 1 kg」「9.0000e+15 kg = 9.0000e+15 kg」这类**同义重复**,
184
+ * 属无效信息 —— 而且它让输出**看起来有内容,其实没有**。
185
+ *
186
+ * 根因:当 from 或 to 恰好是基准单位(factor = 1)时,
187
+ * 那一步就是「X = X」,什么都没说明。
188
+ *
189
+ * 现在的规则:
190
+ * · from.factor ≠ 1 时才写「1 from = N base」(否则 1 = 1,无信息)
191
+ * · from.factor ≠ 1 时才写「value from = inBase base」(上面那行是它的依据)
192
+ * · to.factor ≠ 1 时才写「1 to = M base」;无论哪种都写「故结果 = ...」
193
+ *
194
+ * 换算到基准单位时,过程就只剩一行结论 —— 那本来就是它的全部信息。
195
+ */
196
+ const fromIsBase = from.factor === 1;
197
+ const toIsBase = to.factor === 1;
198
+ const baseName = BASE_UNIT[from.dimension];
199
+ /**
200
+ * ## 合并成一行,避免同一个换算关系说两遍
201
+ *
202
+ * 踩过:`t → kg` 时先写「1 t = 1000 kg」,再写
203
+ * 「9.0000e+15 t = 9.0000e+15 kg」—— 两行说的是**同一件事**
204
+ * (因为 inBase 恰好等于 inBase,且 to 就是基准单位)。
205
+ *
206
+ * 现在按信息量分三种:
207
+ * · 源非基准、目标非基准 → 「1 from = N base,1 to = M base,故结果」
208
+ * · 源非基准、目标是基准 → 「value from = X base,故结果 = X to」
209
+ * · 源是基准、目标非基准 → 「1 to = M base,故结果」
210
+ * · 两者都是基准 → 只剩结论(其实同名,前面已处理)
211
+ */
212
+ if (!fromIsBase && !toIsBase) {
213
+ /**
214
+ * 两个都非基准 → 中间值**必须给**。
215
+ *
216
+ * 它是「30 里 = 15000 m = 15 km」这条链的中段:
217
+ * 少了它,调用方无法核对「500 × 30」这一步是否算对。
218
+ * 这与「去掉同义重复」不冲突 —— 重复指的是 `1 X = 1 X` 那种零信息行,
219
+ * 而中间值是真信息。
220
+ */
221
+ steps.push('1 ' + from.name + ' = ' + from.factor + ' ' + baseName);
222
+ steps.push(show(value) + ' ' + from.name + ' = ' + show(inBase) + ' ' + baseName);
223
+ steps.push('1 ' + to.name + ' = ' + to.factor + ' ' + baseName);
224
+ steps.push('故结果 = ' + show(result) + ' ' + to.name);
225
+ }
226
+ else if (!fromIsBase && toIsBase) {
227
+ steps.push(show(value) + ' ' + from.name + ' = ' + show(inBase) + ' ' + baseName);
228
+ steps.push('故结果 = ' + show(result) + ' ' + to.name);
229
+ }
230
+ else if (fromIsBase && !toIsBase) {
231
+ steps.push('1 ' + to.name + ' = ' + to.factor + ' ' + baseName);
232
+ steps.push('故结果 = ' + show(result) + ' ' + to.name);
233
+ }
234
+ else {
235
+ steps.push('故结果 = ' + show(result) + ' ' + to.name);
236
+ }
237
+ }
238
+ if (from.name === to.name) {
239
+ /** 源与目标同名:换算本身无操作,别编出一段过程。 */
240
+ steps.length = 0;
241
+ steps.push('源单位与目标单位同名,数值不变。');
277
242
  }
278
243
  if (from.note)
279
244
  warnings.push(from.name + ':' + from.note);
package/lib/workspace.js CHANGED
@@ -749,6 +749,60 @@ export function bindHostWorkspace(rawId, rawTitle, makeCurrent = true) {
749
749
  * @param name - 工作区名;省略用当前活动工作区
750
750
  * @returns 显示有效位数;未设置返回 undefined
751
751
  */
752
+ /**
753
+ * 读出当前工作区里登记的命名变量(`variables` 字段)。
754
+ *
755
+ * ## 这个函数为什么存在
756
+ *
757
+ * 工作区的 `variables` 字段、写入路径(`action2:"set"` + `workspaceVariables`)、
758
+ * 删除路径(`remove-variable`)、显示(`show`)**都已经有了**,
759
+ * 唯独**读取路径缺**——存进去的变量在计算里根本用不到。
760
+ *
761
+ * 实测:
762
+ *
763
+ * ```
764
+ * {action2:"set", workspaceVariables:{BTU_LB:1260000}} → 变量 2 个 ✓ 存住了
765
+ * {expression:"BTU_LB/1000"} → Undefined symbol ✗ 用不了
766
+ * ```
767
+ *
768
+ * 也就是说这是「能删不能加、加了用不了」的半成品,不是需要从头设计的新能力。
769
+ *
770
+ * ## 失败时返回空对象,不抛异常
771
+ *
772
+ * 读工作区失败(文件损坏、目录不可写)不该让一次正常计算失败。
773
+ * 但**空对象与「真的没有变量」无法区分**,所以缓存指纹那边
774
+ * 不能只靠这个函数的返回值 —— 见 `index.ts` 里的 `workspaceVariablesFingerprint`。
775
+ *
776
+ * @param name - 工作区名;省略则用当前工作区
777
+ * @returns 变量字典(数字形态);读不到时为空对象
778
+ */
779
+ export function workspaceVariablesOf(name) {
780
+ try {
781
+ const data = loadWorkspace(name ?? activeWorkspaceName);
782
+ const source = data.variables;
783
+ if (!source || typeof source !== 'object')
784
+ return {};
785
+ const result = {};
786
+ for (const [key, value] of Object.entries(source)) {
787
+ const numeric = typeof value === 'number' ? value : Number(value);
788
+ if (Number.isFinite(numeric))
789
+ result[key] = numeric;
790
+ }
791
+ return result;
792
+ }
793
+ catch {
794
+ return {};
795
+ }
796
+ }
797
+ /**
798
+ * 读当前工作区固化的**显示**精度(小数点后几位)。
799
+ *
800
+ * 未设或读到 0 时返回 undefined,调用方据此回落默认值。
801
+ * 语义与「本次调用传入的 displayPrecision」一致:都是小数点后位数。
802
+ *
803
+ * @param name - 工作区名;省略则用当前工作区
804
+ * @returns 显示位数;未设或读不到返回 undefined
805
+ */
752
806
  export function displayPrecisionOf(name) {
753
807
  try {
754
808
  const data = loadWorkspace(name ?? activeWorkspaceName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-math-calculator",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "private": false,
5
5
  "description": "DSH 原生的高精度数学计算器插件:BigNumber 64 位求值、符号微积分、线性代数(秩/零空间/奇异值/特征值)、统计概率与回归、微分方程、单位换算、395 条公式库(三轴标签)、物理常数推演。全部本地执行,不联网。附带一组可选的世界观推演工具。",
6
6
  "type": "module",
package/src/awareness.ts CHANGED
@@ -62,19 +62,48 @@ export function getPromptMode(): PromptMode {
62
62
  * 不能砍 —— 它们省下的重算远多于自身开销。
63
63
  */
64
64
  export const TOOL_DESCRIPTION = [
65
- '本地数学与物理推演引擎(BigNumber 64 位 + 符号代数 + 架空世界推演)。',
66
- '',
65
+ '本地数学与物理推演引擎(BigNumber 64 位 + 符号代数)。',
67
66
  '⚠️ 数值计算必须调用本工具:不要心算、不要用 bash 拼凑算术。',
68
- '触发场景:算术/三角、解方程、微积分、线代、统计、单位换算、公式求值、',
69
- '改常数看后果、推演星球/恒星/卫星/生命、势力收支。',
67
+ '触发:算术/三角、解方程、微积分、线代、统计、单位换算、公式求值、推演。',
68
+ '',
69
+ /**
70
+ * ## 为什么这条要放在正文最前
71
+ *
72
+ * 实测反馈(1107 报告 P0-1)的四起千倍级事故,共同形式都是
73
+ * **全部转成裸数字再算**:
74
+ *
75
+ * ```
76
+ * 0.907/(10*745.7/0.475/3.6/29.564)*60 ← 745.7 是瓦还是千瓦?
77
+ * 0.907/(10*0.7457/0.475/3.6/29.564)*60 ← 差 1000 倍,两条都宣告成功
78
+ * ```
79
+ *
80
+ * 工具没法从裸数字推断量纲,但**带单位时它自己会发现不对**:
81
+ * `10 hp + 3 kg` 直接报 unit_mismatch。
82
+ *
83
+ * 报告原话:「help 里确实有 `5 cm to inch`,但被埋在第 4 个例子,
84
+ * 且没有任何一句说『所有物理量计算都带单位』。」
85
+ */
86
+ '物理量一律带单位写(如 (10 hp/0.475) to kW):量纲错误当场拦下;',
87
+ '裸数字无从判断 745.7 是瓦还是千瓦,差 1000 倍也可能宣告成功。',
70
88
  '',
71
- 'operation 见参数 enum(30 个);不确定用 help。选法:一条式子用 evaluate,',
72
- '数据用 stats/dist,改设定后用 world/derivation。',
89
+ /**
90
+ * ## 为什么要把「查 help」写成一个明确的两步动作
91
+ *
92
+ * 旧版是一整块 5900 字符的能力清单,每次调用都付全量成本 ——
93
+ * 算一条 1/3 也要读 3039 字符的 world 字段表。现在改成目录:
94
+ *
95
+ * ```
96
+ * 目录 1731 字符(各节名 + 一句话简介)
97
+ * 单节 200—1900 字符,只在你真用那一节时才取
98
+ * ```
99
+ *
100
+ * 关键是**必须告诉 AI 这个两步动作存在**,否则它会以为 help 只给目录、
101
+ * 或者干脆不去查 —— 那功能就等于不存在。
102
+ */
103
+ '某功能不确定怎么用 → help 看目录(12 节带简介),再 helpTopic:"world" 取该节全文。',
73
104
  '',
74
- '读输出约定:',
75
- ' · [精确]/[标度]/[量级]/[仅方向] 是可信度标签,引用时保留;',
76
- ' · 【跨模块一致性】✓/⚠/✗,看到 ✗ 先修正设定;',
77
- ' · 【模型可信度】标出哪些数只是地球标定,常数偏离现实时会失真。',
105
+ '读输出:[精确]/[标度]/[量级]/[仅方向] 是可信度标签,引用时保留;',
106
+ '【跨模块一致性】✗ 先修正设定;【模型可信度】标出哪些数是地球标定。',
78
107
  '',
79
108
  '精度分两层:precision(计算,默认 64,调低会算错大数)不要为好看而动;',
80
109
  'displayPrecision(显示,**小数点后几位**,默认 8)只截小数、整数永远完整。',
@@ -134,24 +163,44 @@ export function buildSystemPromptSection(): string {
134
163
  /* 读不到就按 0 */
135
164
  }
136
165
 
166
+ /**
167
+ * brief 档:默认档,每轮下发。
168
+ *
169
+ * ## 分区按「频率 × 重要度」排
170
+ *
171
+ * 原来这一段是 817 字符,其中「能力清单」占 200 字符(罗列 12 类能力),
172
+ * 而最常问的「该用哪个 operation」一句都没写 —— 比例完全反了。
173
+ *
174
+ * 现在的取舍:
175
+ * ① **行为约束**放最前(40 字符)—— 它决定「调不调」,最重要
176
+ * ② **选哪个 operation**(70 字符)—— 高频且原先缺失
177
+ * ③ **可信度标签**(60 字符)—— 决定「数能不能引用」,最重要之一
178
+ * ④ **精度两层**(50 字符)—— 中频
179
+ * ⑤ **世界推演分工**(80 字符)—— 低频,压到极限
180
+ * ⑥ **能力全清单**不再列出 —— 已在 schema 的 enum 与 help 里,
181
+ * 同一份信息付两次钱是浪费(这条有实测依据:省 21% 定义长度)
182
+ */
137
183
  if (promptMode === 'brief') {
138
184
  return [
139
185
  '## 数学计算工具(math_execute)',
140
186
  '',
141
- '涉及任何数值计算时**必须**调用 math_execute,不要心算、不要用 bash 拼凑。',
187
+ '涉及数值计算时**必须**调用,不要心算、不要用 bash 拼凑。',
142
188
  '',
143
- '能算:高精度求值、解方程、符号微积分、矩阵/特征值/秩/奇异值、统计与分布、回归、',
144
- '微分方程、' + FORMULAS.length + ' 条自然科学公式、物理常数推演、星球/天空/恒星/卫星/生命推演、',
145
- '宏观文明极限(能量/材料/交通/技术树)、观测者体感、逆推校准、混沌概率云。',
189
+ '**选哪个 operation**:一条式子 → `evaluate`(多条用 `expressions` 批量,可带 label);',
190
+ '解方程 → `solve`;数据 → `stats`/`dist`/`regression`;公式 → `formula`(' + FORMULAS.length + ' 条,参数可覆盖);',
191
+ '单位 → `units`;改设定 → `world`/`constants`/`derivation`;不确定 → `help`。',
146
192
  '',
147
- '读输出:',
148
- '· [精确]/[标度]/[量级]/[仅方向] 是可信度标签——引用结论时请保留;',
149
- '· 【跨模块一致性】的 ✗ 表示设定自相矛盾,先修正再写;',
150
- '· 【模型可信度】标出哪些数字只是地球标定。',
193
+ '**读输出的约定**:',
194
+ '· `[精确]/[标度]/[量级]/[仅方向]` 是可信度标签,引用时保留,别当装饰;',
195
+ '· 【跨模块一致性】✗ 表示设定自相矛盾,先修正再写;',
196
+ '· 【模型可信度】标出哪些数只是地球标定 —— 常数偏离现实时它会失真。',
151
197
  '',
152
- buildBriefPlaybook({ changedConstants: changedConstants, customConstants: customConstantCount }),
198
+ '**精度分两层**:`precision`(计算,默认 64)调低会算错大数,不要为好看动它;',
199
+ '`displayPrecision`(**小数点后几位**,默认 8)只截小数,整数永远完整。',
200
+ '要更多位就单次传,或 `{operation:"workspace", action2:"set", displayPrecision:N}` 固化。',
153
201
  '',
154
- '不确定能力边界时先调 operation="help"。' + changedNote + tableNote,
202
+ buildBriefPlaybook({ changedConstants: changedConstants, customConstants: customConstantCount })
203
+ + changedNote + tableNote,
155
204
  ].join('\n')
156
205
  }
157
206