@lmzhen/dsh-evolution-review 0.3.73 → 0.3.74

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 CHANGED
@@ -21,6 +21,7 @@ Independent of request-prefix construction. This package does not alter the asse
21
21
  ## Known Limitations and Deferred Work
22
22
 
23
23
 
24
+ - The review's model/context routing below applies to `reviewMode: 'subagent'` (opt-in since 0.3.74); in the default `'inject'` mode the review runs on the parent agent's model inside the parent thread.
24
25
  - Review subagents are spawned with the plain `skill` tool only (`reviewToolAllow` default and the host/preset config both = `[skill]` — the DSH tool catalog has no `skill_search`/`skill_load` discovery pair, so the Hermes-lineage Anchored Standard `skill_search`/`skill_load` allow-list does not exist here).
25
26
  - Review subagents run as `spawn` children on the deployment default preset rather than inheriting the parent agent's composition (`fork`): a fork child is always promoted by the Anchored Standard bootstrap and its narrowed resident catalog would drop the plain `skill` tool from the review allow-list.
26
27
  - The review request text is redacted for credential-shaped patterns before it reaches the subagent, but redaction is pattern-based and best-effort, not a security boundary.
@@ -38,7 +39,7 @@ Independent of request-prefix construction. This package does not alter the asse
38
39
 
39
40
  ### Review delivery contract (0.3.38-0.3.42)
40
41
 
41
- - **Both channels execute at conversation end only** (a `turn/end` with `reason.kind === 'completed'`): a cadence threshold fire mid-task merely latches the kind — no subagent spawn, no inject. The flush runs BEFORE the latch block (the completing turn may itself be a threshold-firing turn). `reviewMode` (`'subagent'` default / `'inject'`) selects how the flush delivers; the explicit `'inject'` mode's historical "immediate on threshold" contract was superseded in 0.3.39 — both modes are end-of-conversation.
42
+ - **Both channels execute at conversation end only** (a `turn/end` with `reason.kind === 'completed'`): a cadence threshold fire mid-task merely latches the kind — no subagent spawn, no inject. The flush runs BEFORE the latch block (the completing turn may itself be a threshold-firing turn). `reviewMode` selects how the flush delivers: **`'inject'` is the default since 0.3.74**, `'subagent'` is an explicit opt-in. Rationale: the parent session already holds a warm prefix cache, so an injected prompt costs the new tokens only, while a spawned child re-prefills its own system prompt plus a redacted, re-serialized conversation digest (`buildReviewRequest`) under a **different model** (`skillReviewModel`/`memoryReviewModel`) — no prefix is shared with the parent, so the whole child input is paid at full price. `'subagent'` remains the choice for deployments that want the parent context kept clean (a review's skill reads and plan do not join the parent thread) or a dedicated review model; the subagent-only knobs (`reviewProvider`, `reviewTimeoutMs`, `reviewMaxDepth`, `reviewToolAllow`, the review models) are inert in inject mode. The explicit `'inject'` mode's historical "immediate on threshold" contract was superseded in 0.3.39 — both modes are end-of-conversation.
42
43
  - **`skillReviewTrigger`** (default `'cadence'`): the cadence channel is **always on** (one end-of-conversation review from the cadence latch per task segment); the flag gates **only the completion channel** — `'cadence'` disables it, `'completion'` enables it (cadence still fires), `'both'` enables it on top of the always-on cadence. At one boundary a turn is served by exactly one review: the cadence flush runs first and returns, so `'both'` never double-sends a second task-complete prompt at the same boundary (V10-13).
43
44
  - **`reviewWakeInject`** (default `true`): deliveries use `agent.followup` (next-turn + wake — the model starts processing immediately) instead of the non-waking `agent.inject` (which waits for the next driver wake). The host falls back to `inject` when it has no followup or the option is `false`. **The wake primitive is always called ON the agent instance** — the platform's `Agent.followup`/`inject` are prototype methods that call `this.send(...)`, so extracting one into a local and calling the detached reference throws (0.3.73: that throw was caught and logged while the cadence reset still ran, silently consuming every segment's review from 2026-09-07). A refused delivery now returns `false` and the caller keeps its latch and counters, so the review retries at the next completed boundary instead of vanishing; `evolution-host/tests/wake-delivery-guard.spec.ts` pins the call form mechanically. The woken turn's own cadence fire is suppressed once (an injected review prompt alone must not re-trigger a review under `interval=1`); a restart clears the queue, so the loop cannot survive it.
44
45
  - **Counting window = injection-to-injection**: the `turnsSinceMemory`/`turnsSinceSkill` counters are monotonic across threshold fires (`resetOnFire: false`) and are zeroed at the flush delivery — a continued conversation starts a fresh segment from the injection. A threshold fire on the completing turn is caught by the flush (`pendingKind = latch ?? kind`). All deliveries (review prompt AND result notices) share the same waking channel; a failed counter-reset persist warns once per session (a stateful reload may re-deliver).
package/lib/index.js CHANGED
@@ -12,7 +12,7 @@ const name = "evolution-review";
12
12
  const inject = ["agents"];
13
13
  const Config = z.object({
14
14
  reviewEnabled: z.boolean().default(true),
15
- reviewMode: z.union([z.const("subagent"), z.const("inject")]).default("subagent"),
15
+ reviewMode: z.union([z.const("subagent"), z.const("inject")]).default("inject"),
16
16
  memoryInterval: z.number().min(1).default(DEFAULT_REVIEW_MEMORY_INTERVAL),
17
17
  skillInterval: z.number().min(1).default(DEFAULT_REVIEW_SKILL_INTERVAL),
18
18
  reviewToolAllow: z.array(z.string()).default(["skill"]),
@@ -8,6 +8,17 @@ export declare const name = "evolution-review";
8
8
  export declare const inject: string[];
9
9
  export interface Config {
10
10
  reviewEnabled?: boolean;
11
+ /** How the flush delivers the review: `'inject'` (default since 0.3.74) hands
12
+ * the review prompt to the PARENT agent — waking it through the same
13
+ * followup-first channel — so the review runs on the parent's model against
14
+ * the parent's already-cached prefix and no separate prefill is paid.
15
+ * `'subagent'` spawns a one-shot child instead: the parent context stays clean
16
+ * and the review can use a dedicated model, but the child re-prefills its own
17
+ * system prompt plus a re-serialized conversation digest
18
+ * (`buildReviewRequest`, redacted, header-prepended) on a DIFFERENT model —
19
+ * so no prefix cache is shared with the parent and the input tokens are paid
20
+ * at full price. Deployments that prefer the clean-context split opt back in
21
+ * per plugin row. */
11
22
  reviewMode?: 'subagent' | 'inject';
12
23
  memoryInterval?: number;
13
24
  skillInterval?: number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-review",
3
3
  "description": "Background review orchestration (community build)",
4
- "version": "0.3.73",
4
+ "version": "0.3.74",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -31,9 +31,9 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
33
  "@deepseek-ai/schemastery": "^3.18.1",
34
- "@lmzhen/dsh-evolution-approval": "^0.3.73",
35
- "@lmzhen/dsh-evolution-core": "^0.3.73",
36
- "@lmzhen/dsh-evolution-plan-validator": "^0.3.73"
34
+ "@lmzhen/dsh-evolution-approval": "^0.3.74",
35
+ "@lmzhen/dsh-evolution-core": "^0.3.74",
36
+ "@lmzhen/dsh-evolution-plan-validator": "^0.3.74"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@deepseek-ai/cordis": "^4.0.1",
@@ -42,8 +42,8 @@
42
42
  "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
43
43
  "@deepseek-ai/dsh-session": "^0.1.5-rc.2",
44
44
  "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
45
- "@lmzhen/dsh-evolution-state": "^0.3.73",
46
- "@lmzhen/dsh-evolution-policy": "^0.3.73"
45
+ "@lmzhen/dsh-evolution-state": "^0.3.74",
46
+ "@lmzhen/dsh-evolution-policy": "^0.3.74"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@deepseek-ai/dsh-agent": "^0.1.5-rc.2",
@@ -54,10 +54,10 @@
54
54
  "@deepseek-ai/dsh-session-persistence": "^0.1.5-rc.2",
55
55
  "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.5-rc.2",
56
56
  "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
57
- "@lmzhen/dsh-evolution-approval": "^0.3.73",
58
- "@lmzhen/dsh-evolution-core": "^0.3.73",
59
- "@lmzhen/dsh-evolution-curator": "^0.3.73",
60
- "@lmzhen/dsh-evolution-plan-validator": "^0.3.73",
61
- "@lmzhen/dsh-evolution-state": "^0.3.73"
57
+ "@lmzhen/dsh-evolution-approval": "^0.3.74",
58
+ "@lmzhen/dsh-evolution-core": "^0.3.74",
59
+ "@lmzhen/dsh-evolution-curator": "^0.3.74",
60
+ "@lmzhen/dsh-evolution-plan-validator": "^0.3.74",
61
+ "@lmzhen/dsh-evolution-state": "^0.3.74"
62
62
  }
63
63
  }