dsh-live-compact 1.1.1 → 1.1.2

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/shell.js CHANGED
@@ -3,16 +3,19 @@
3
3
  * Thin entry. This file must evaluate even when the engine cannot load.
4
4
  * A throw here leaves stock disabled and /compact waiting.
5
5
  *
6
- * 配置预先检查失败时不构造引擎,也不再构造原版,避免报错被盖成「服务已被注册」。
7
- * On a preflight failure, construct neither engine. Stock would register and hide the real error.
6
+ * 预检查只解析配置,校验交给实际引擎;构造失败时释放本次注册,不重试原版盖掉报错。
7
+ * Resolve config before construction; let the engine validate it and preserve its actual error.
8
8
  */
9
- import { loadBase, loadCompaction } from "./adapter.js";
9
+ import { loadBase, loadCompaction, loadSchema } from "./adapter.js";
10
+ import { configSchema, engineConfig } from "./settings.js";
11
+ import { installPresetGate } from "./gate.js";
10
12
 
11
13
  let Engine = null;
12
14
  let Stock = null;
13
15
  let CompactionEngine = null;
14
16
  let ManualCompactionError = null;
15
17
  let loadError = null;
18
+ let Schema = null;
16
19
 
17
20
  if (process.env.SPINE_ENGINE_FAIL === "import") {
18
21
  loadError = new Error("spine: engine import refused");
@@ -40,32 +43,35 @@ try {
40
43
  if (!loadError) loadError = error instanceof Error ? error : new Error(String(error));
41
44
  }
42
45
 
46
+ // 官方设置界面按这份 schema 自动生成表单。拿不到 schemastery 就退回 stock 的 schema。
47
+ try {
48
+ const schema = await loadSchema();
49
+ Schema = configSchema(schema.default, Stock?.Config);
50
+ } catch {
51
+ Schema = null;
52
+ }
53
+
43
54
  function reasonText(error) {
44
55
  return error instanceof Error ? error.message : String(error);
45
56
  }
46
57
 
47
58
  export function preflightConfig(config = {}) {
48
- if (!config || typeof config !== "object") return;
49
- const threshold = config.thresholdRatio;
50
- if (typeof threshold !== "number") return;
51
- if (config.retainTokens !== undefined) return;
52
- const ratio = config.retainRatio ?? 0.16;
53
- if (ratio >= threshold) {
54
- throw new Error(`BasicCompactionConfig: retainRatio (${ratio}) must be less than the resolved thresholdRatio (${threshold})`);
55
- }
59
+ return engineConfig(config);
56
60
  }
57
61
 
58
- function releaseCompaction(ctx) {
62
+ function compactionRecord(ctx) {
63
+ const key = ctx?.[Symbol.for("cordis.isolate")]?.compaction;
64
+ return key === undefined ? undefined : ctx?.reflect?.store?.[key];
65
+ }
66
+
67
+ function releaseCompaction(ctx, previous) {
59
68
  const store = ctx?.reflect?.store;
60
- if (!store) return false;
61
- const keys = [...Object.getOwnPropertySymbols(store), ...Object.keys(store)];
62
- for (const key of keys) {
63
- if (store[key]?.name !== "compaction") continue;
64
- delete store[key];
65
- if (ctx.fiber?.store) delete ctx.fiber.store.compaction;
66
- return true;
67
- }
68
- return false;
69
+ const key = ctx?.[Symbol.for("cordis.isolate")]?.compaction;
70
+ const current = compactionRecord(ctx);
71
+ if (!current || current === previous || current.fiber !== ctx.fiber) return false;
72
+ delete store[key];
73
+ if (ctx.fiber?.store?.compaction === current) delete ctx.fiber.store.compaction;
74
+ return true;
69
75
  }
70
76
 
71
77
  function visibleTakeover(ctx, reason) {
@@ -98,15 +104,18 @@ const UnavailableCompaction = CompactionEngine
98
104
 
99
105
  export default class LiveCompactEntry {
100
106
  static inject = ["llm", "tokenMeter", "sessions"];
101
- static Config = Stock?.Config || Engine?.Config;
107
+ static Config = Schema || Stock?.Config || Engine?.Config;
102
108
 
103
109
  constructor(ctx, config) {
110
+ installPresetGate(ctx, config);
111
+ const previousCompaction = compactionRecord(ctx);
104
112
  let cause = loadError;
113
+ let resolvedConfig;
105
114
  let skipStock = process.env.SPINE_ENGINE_FAIL === "construct";
106
115
  if (skipStock) cause = new Error("spine: constructor refused");
107
116
  if (!loadError && !skipStock) {
108
117
  try {
109
- preflightConfig(config);
118
+ resolvedConfig = preflightConfig(config);
110
119
  } catch (error) {
111
120
  cause = error instanceof Error ? error : new Error(String(error));
112
121
  skipStock = true;
@@ -114,10 +123,10 @@ export default class LiveCompactEntry {
114
123
  }
115
124
  if (!loadError && !skipStock && Engine) {
116
125
  try {
117
- return new Engine(ctx, config);
126
+ return new Engine(ctx, config, resolvedConfig);
118
127
  } catch (error) {
119
128
  cause = error instanceof Error ? error : new Error(String(error));
120
- releaseCompaction(ctx);
129
+ releaseCompaction(ctx, previousCompaction);
121
130
  skipStock = true;
122
131
  }
123
132
  }
@@ -125,10 +134,10 @@ export default class LiveCompactEntry {
125
134
  if (!skipStock && process.env.SPINE_STOCK_FAIL !== "1" && Stock) {
126
135
  try {
127
136
  visibleTakeover(ctx, `这一轮用原版压缩。${reasonText(cause)}`);
128
- return new Stock(ctx, config);
137
+ return new Stock(ctx, engineConfig(config));
129
138
  } catch (error) {
130
139
  cause = error instanceof Error ? error : new Error(String(error));
131
- releaseCompaction(ctx);
140
+ releaseCompaction(ctx, previousCompaction);
132
141
  }
133
142
  }
134
143
  visibleTakeover(ctx, reasonText(cause));