pi-think-anchor 1.0.28 → 1.0.29

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.en.md CHANGED
@@ -1,53 +1,9 @@
1
1
  # pi-think-anchor
2
2
 
3
- Chain-of-thought drift monitor: reads a word-frequency fingerprint from thinking, classifies focused / mixed / reactive, and nudges when drifting.
3
+ Thinking-focus monitor with graded nudges, driven by a reproducible ratio test.
4
4
 
5
- ## Install
5
+ **English documentation:** [open the English section](README.md#english) · **中文文档:** [中文](README.md#zh)
6
6
 
7
- ```bash
8
- pi install npm:pi-think-anchor
9
- ```
7
+ pi install npm:pi-think-anchor
10
8
 
11
- ## Configuration
12
-
13
- Config file `~/.pi/think-anchor.json` (optional; defaults apply, invalid JSON falls back):
14
-
15
- | Key | Default | Description |
16
- | --- | --- | --- |
17
- | `enabled` | `true` | Master switch |
18
- | `score.minHits` | `3` | Fewer hits in a turn: no scoring, no intervention |
19
- | `score.spec` | `1.2` | Focused threshold |
20
- | `score.react` | `0.5` | Reactive threshold |
21
- | `score.alpha` | `1` | Alpha smoothing |
22
- | `windowSize` | `5` | Window size in messages |
23
- | `weights.beta` | `0.4` | Neutral-word weight in the numerator |
24
- | `weights.eps` | `0.5` | Denominator floor |
25
- | `intervention.l1CooldownMin` | `10` | L1 cooldown (minutes) |
26
- | `intervention.l2CooldownMin` | `15` | L2 cooldown (minutes) |
27
- | `intervention.maxL2` | `2` | Max L2 per session |
28
- | `lexicon.positive/negative/neutral` | built-in Chinese lexicon (28 focus / 18 drift) | Lexicon override |
29
- | `bands.spec/react` | `1.2 / 0.5` | Legacy keys (used when `score` is absent) |
30
-
31
- Also: `THINK_ANCHOR=0` hard off; log `~/.pi/think-anchor.jsonl` (1 MiB truncation, tail-preserving).
32
-
33
- ## Commands
34
-
35
- | Command | Purpose |
36
- | --- | --- |
37
- | `/think-anchor` | Current band, hits, drift share, last intervention result |
38
- | `/think-anchor stats` | Version, band distribution, actions, effectiveness, log size |
39
-
40
- ## What it does (source facts)
41
-
42
- - `turn_end`: reads assistant thinking -> fingerprint (pos/neg/neu) -> sliding window -> band; when hits < `minHits` it only advances the window.
43
- - State machine `healthy -> warning -> critical`; L1/L2 nudges are injected as `nextTurn` trailing messages.
44
- - No escalation: when the previous `eff >= 0`, L2 degrades to L1.
45
- - `session_start`: resets state, keeping only the last 3 samples and pending (cross-session settlement).
46
-
47
- ## Credits
48
-
49
- Distilled from the DSH plugin [`dsh-anchored-monitor`](https://dsh-plugin.org/zh/plugins/aik358/dsh-anchored-monitor) 0.3.1: the mechanism is upstream, the code is not (turn-level, no separate process).
50
-
51
- ## License
52
-
53
- MIT
9
+ Source: https://github.com/op15066212/pi-plugins-publish
package/README.md CHANGED
@@ -42,7 +42,7 @@ pi install npm:pi-think-anchor
42
42
  | `intervention.maxL2` | `2` | 每会话 L2 上限 |
43
43
  | `lexicon.positive/negative/neutral` | 专注 28 词 / 发散 18 词 / 中性 **默认空** | 词表覆盖 |
44
44
 
45
- 其他:日志 `~/.pi/think-anchor.jsonl`(1 MiB 截断,保留尾部整行)。
45
+ 其他:日志 `~/.pi/think-anchor.jsonl`(1 MiB 截断,保留尾部整行);日志里的 `ratio` 是**未平滑**的原始比率,而判定用的是 α 平滑后的比率(`(pos + beta·neu + alpha) / (neg + eps + alpha)`)——两者数值不同,别拿日志 ratio 当判定依据。
46
46
  **词表覆盖规则(源码事实)**
47
47
 
48
48
  - 三个键独立覆盖:只写想改的那个,其余保留默认(`lexicon` 按子键浅合并)。
@@ -224,7 +224,7 @@ Config file `~/.pi/think-anchor.json` (optional; defaults apply, invalid JSON fa
224
224
  | `intervention.maxL2` | `2` | Max L2 per session |
225
225
  | `lexicon.positive/negative/neutral` | 28 focus / 18 drift / neutral **empty by default** | Lexicon override |
226
226
 
227
- Also: log `~/.pi/think-anchor.jsonl` (1 MiB truncation, tail-preserving).
227
+ Also: log `~/.pi/think-anchor.jsonl` (1 MiB truncation, tail-preserving). The `ratio` in the log is the **unsmoothed** raw ratio; classification uses the `alpha`-smoothed ratio (`(pos + beta·neu + alpha) / (neg + eps + alpha)`). They differ — do not use the logged ratio as the decision value.
228
228
  **Lexicon override rules (from source)**
229
229
 
230
230
  - Keys merge independently: write only what you change; the rest keep defaults (`lexicon` merges per sub-key).
package/index.ts CHANGED
@@ -89,17 +89,12 @@ export function fingerprint(text: string, lex: { positive: string[]; negative: s
89
89
  };
90
90
  }
91
91
 
92
+
92
93
  /** 加权比率:专注度代理指标 */
93
94
  export function ratioOf(pos: number, neg: number, neu: number, w: { beta: number; eps: number } = DEF_CFG.weights): number {
94
95
  return (pos + w.beta * neu) / (neg + w.eps);
95
96
  }
96
97
 
97
- export function bandOf(ratio: number, t: { spec: number; react: number } = DEF_CFG.score): "spec" | "mixed" | "react" {
98
- if (ratio >= t.spec) return "spec";
99
- if (ratio >= t.react) return "mixed";
100
- return "react";
101
- }
102
-
103
98
  /**
104
99
  * v2.1 判据:证据门槛 + α 平滑的专注/发散比。
105
100
  * 回放 2069 条可评分日志:旧判据 react 占 18.3%(其中 57% 是命中 <3 的长而散);
@@ -328,7 +323,7 @@ export default function thinkAnchor(pi: ExtensionAPI): void {
328
323
  } else {
329
324
  // 被冷却/上限挡下:记 blocked,避免与「无需动作」混淆(实测 583 次 want=L2 只有 55 次真发)
330
325
  st.phase = prevPhase;
331
- if (d.level !== "none") acted = st.autoMuted ? "muted-" + d.level : "blocked-" + d.level;
326
+ acted = st.autoMuted ? "muted-" + d.level : "blocked-" + d.level;
332
327
  }
333
328
  if (band === "spec" && st.phase === "healthy") st.l2Tried = 0; // 恢复后重置 L2 计数
334
329
  // v3 效果闭环:干预后第 3 轮结算(pre = 干预前最近 3 轮 ratio 均值)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-think-anchor",
3
- "version": "1.0.28",
3
+ "version": "1.0.29",
4
4
  "description": "Monitors thinking focus drift and nudges the model back on track.",
5
5
  "type": "module",
6
6
  "license": "MIT",