@lmzhen/dsh-evolution-activity 0.3.17 → 0.3.19

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
@@ -1,6 +1,10 @@
1
1
  # @deepseek-ai/dsh-evolution-activity
2
2
 
3
- Session projection for self-evolution activity
3
+ Durable activity store for self-evolution plan outcomes
4
+
5
+ ## What it does
6
+
7
+ Subscribes to the process event `evolution/plan-applied` (payload v2, with sessionId) and persists every plan outcome to `$DSH_HOME/evolution/activity.json` through the evolution IO seam — the same best-effort sidecar posture as `feedback.json` and the curator reports. The sidecar is append-merge (load → fold → save under an in-process queue), so records survive host restarts and are readable without a session. The retired session projection is gone: a session log carrying `evolution/*` types is refused wholesale at resume, so plan-outcome durability lives here instead. A storage-domain table is deferred until a consumer needs domain routing.
4
8
 
5
9
  ## Model Experience
6
10
 
@@ -18,8 +22,11 @@ Zero direct token effect from this package; consumers add any model-visible toke
18
22
 
19
23
  Independent of request-prefix construction. This package does not alter the assembled prompt or tool list.
20
24
 
25
+ ## Configuration
26
+
27
+ - `maxItems`: bound on the retained activity sidecar (default `DEFAULT_MAX_ITEMS = 200`). A non-finite value falls back to the default (0.3.19, S6.4 guard).
28
+
21
29
  ## Known Limitations and Deferred Work
22
30
 
23
31
 
24
- - The projection registers BOTH contract generations — `stateSchema` + `wire.viewSchema` (DSH 0.1.1+ session-projection contract) and legacy `schema` + `view` (0.1.0-rc.6 era) — because each registry ignores the fields it does not know. When the legacy fields are removed, drop the old half of the dual registration.
25
- - On 0.1.1+ hosts the cold-read path (`restore`) calls `stateSchema.parse` on checkpointed rows; a registration missing `stateSchema` would throw on the first cold read, so the new half is load-bearing, not cosmetic.
32
+ - The sidecar is single-process safe only; two processes sharing `$DSH_HOME` can interleave append-merge cycles (same posture as `feedback.json` — a cross-process lock is deferred until a multi-process deployment exists).
package/lib/index.js CHANGED
@@ -21,6 +21,9 @@ import { join } from "node:path";
21
21
  */
22
22
  /** Version of the `activity.json` shape; writers always emit the current one. */
23
23
  const ACTIVITY_FILE_VERSION = 2;
24
+ /** Default bound on the retained sidecar (S6.4: also the fallback for a
25
+ * non-finite `maxItems`). */
26
+ const DEFAULT_MAX_ITEMS = 200;
24
27
  function activityFile(root) {
25
28
  return join(root, "activity.json");
26
29
  }
@@ -37,7 +40,7 @@ function applyActivityEvent(items, event, maxItems, at = Date.now()) {
37
40
  estimatedInputChars: event.estimatedInputChars,
38
41
  at
39
42
  };
40
- const cap = Math.max(1, maxItems);
43
+ const cap = Number.isFinite(maxItems) ? Math.max(1, maxItems) : 200;
41
44
  return [...items, record].slice(-cap);
42
45
  }
43
46
  /** Parse a raw sidecar into records; malformed content reads as empty (best-effort telemetry). */
@@ -62,28 +65,28 @@ async function saveActivity(root, items, io) {
62
65
  const name = "evolution-activity";
63
66
  const Config = z.object({ maxItems: z.number().default(200) });
64
67
  function apply(ctx, rawConfig = {}) {
65
- const maxItems = rawConfig.maxItems ?? 200;
66
- const ioRegistry = ctx.get("evolutionIo");
67
- if (!ioRegistry) {
68
- ctx.logger.warn("evolution-activity: no evolution IO provider mounted; plan outcomes will not be persisted");
69
- return;
70
- }
71
- const io = evolutionIoAdapter(() => ioRegistry.provider());
72
- const root = evolutionHome();
73
- let chain = Promise.resolve();
74
- ctx.on("evolution/plan-applied", (event) => {
75
- const run = chain.then(() => transactIo(io, activityFile(root), (current) => {
76
- const items = applyActivityEvent(parseActivityContent(current), event, maxItems);
77
- return Promise.resolve(JSON.stringify({
78
- version: 2,
79
- items
80
- }, null, 2));
81
- }));
82
- chain = run.then(() => void 0, () => void 0);
83
- run.catch((error) => {
84
- ctx.logger.warn(error instanceof Error ? error : String(error));
68
+ const configuredMaxItems = rawConfig.maxItems ?? 200;
69
+ const maxItems = Number.isFinite(configuredMaxItems) ? configuredMaxItems : 200;
70
+ if (!Number.isFinite(configuredMaxItems)) ctx.logger.warn(`evolution-activity: maxItems is not a finite number; falling back to the default 200`);
71
+ ctx.inject(["evolutionIo"], (ioCtx) => {
72
+ const ioRegistry = ioCtx.evolutionIo;
73
+ const io = evolutionIoAdapter(() => ioRegistry.provider());
74
+ const root = evolutionHome();
75
+ let chain = Promise.resolve();
76
+ ioCtx.on("evolution/plan-applied", (event) => {
77
+ const run = chain.then(() => transactIo(io, activityFile(root), (current) => {
78
+ const items = applyActivityEvent(parseActivityContent(current), event, maxItems);
79
+ return Promise.resolve(JSON.stringify({
80
+ version: 2,
81
+ items
82
+ }, null, 2));
83
+ }));
84
+ chain = run.then(() => void 0, () => void 0);
85
+ run.catch((error) => {
86
+ ioCtx.logger.warn(error instanceof Error ? error : String(error));
87
+ });
85
88
  });
86
89
  });
87
90
  }
88
91
  //#endregion
89
- export { ACTIVITY_FILE_VERSION, Config, activityFile, apply, applyActivityEvent, loadActivity, name, parseActivityContent, saveActivity };
92
+ export { ACTIVITY_FILE_VERSION, Config, DEFAULT_MAX_ITEMS, activityFile, apply, applyActivityEvent, loadActivity, name, parseActivityContent, saveActivity };
@@ -32,6 +32,9 @@ export interface EvolutionActivityRecord {
32
32
  }
33
33
  /** Version of the `activity.json` shape; writers always emit the current one. */
34
34
  export declare const ACTIVITY_FILE_VERSION = 2;
35
+ /** Default bound on the retained sidecar (S6.4: also the fallback for a
36
+ * non-finite `maxItems`). */
37
+ export declare const DEFAULT_MAX_ITEMS = 200;
35
38
  export declare function activityFile(root: string): string;
36
39
  /** Fold one plan-applied payload into a bounded record list (pure). */
37
40
  export declare function applyActivityEvent(items: EvolutionActivityRecord[], event: EvolutionPlanAppliedEvent, maxItems: number, at?: number): EvolutionActivityRecord[];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-activity",
3
3
  "description": "Session projection for self-evolution activity (community build)",
4
- "version": "0.3.17",
4
+ "version": "0.3.19",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -33,7 +33,7 @@
33
33
  "license": "MIT",
34
34
  "dependencies": {
35
35
  "@deepseek-ai/schemastery": "^3.18.1",
36
- "@lmzhen/dsh-evolution-core": "^0.3.17"
36
+ "@lmzhen/dsh-evolution-core": "^0.3.19"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@deepseek-ai/cordis": "^4.0.1",
@@ -42,8 +42,8 @@
42
42
  "devDependencies": {
43
43
  "@deepseek-ai/cordis": "^4.0.1",
44
44
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
45
- "@lmzhen/dsh-evolution-core": "^0.3.17",
46
- "@lmzhen/dsh-evolution-io": "^0.3.17",
47
- "@lmzhen/dsh-evolution-io-node": "^0.3.17"
45
+ "@lmzhen/dsh-evolution-core": "^0.3.19",
46
+ "@lmzhen/dsh-evolution-io": "^0.3.19",
47
+ "@lmzhen/dsh-evolution-io-node": "^0.3.19"
48
48
  }
49
49
  }