dsh-continual-evolve 0.15.3 → 0.15.4
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 +2 -2
- package/README.zh.md +2 -2
- package/lib/extraction.d.ts +5 -2
- package/lib/extraction.js +84 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ English | [中文](README.zh.md)
|
|
|
7
7
|
[](https://github.com/ZK-Andy/dsh-continual-evolve/actions/workflows/ci.yml)
|
|
8
8
|
[](LICENSE)
|
|
9
9
|
[](package.json)
|
|
10
|
-
[]()
|
|
11
11
|
[]()
|
|
12
12
|
[]()
|
|
13
13
|
[]()
|
|
@@ -71,7 +71,7 @@ Profile patch example:
|
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
73
|
pnpm install && pnpm build # deps + clean build -> lib/
|
|
74
|
-
pnpm test # vitest (
|
|
74
|
+
pnpm test # vitest (199 tests)
|
|
75
75
|
pnpm test:coverage # v8 coverage, CI-enforced thresholds
|
|
76
76
|
pnpm lint # oxlint src test client
|
|
77
77
|
pnpm check:pack # published-artifact consistency (also runs on prepack)
|
package/README.zh.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://github.com/ZK-Andy/dsh-continual-evolve/actions/workflows/ci.yml)
|
|
8
8
|
[](LICENSE)
|
|
9
9
|
[](package.json)
|
|
10
|
-
[]()
|
|
11
11
|
[]()
|
|
12
12
|
[]()
|
|
13
13
|
[]()
|
|
@@ -71,7 +71,7 @@ profile patch 示例:
|
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
73
|
pnpm install && pnpm build # 依赖 + 干净构建 -> lib/
|
|
74
|
-
pnpm test # vitest(
|
|
74
|
+
pnpm test # vitest(199 例)
|
|
75
75
|
pnpm test:coverage # v8 覆盖率,CI 强制阈值
|
|
76
76
|
pnpm lint # oxlint src test client
|
|
77
77
|
pnpm check:pack # 发布产物一致性(prepack 也会跑)
|
package/lib/extraction.d.ts
CHANGED
|
@@ -34,8 +34,11 @@ export interface RunOptions {
|
|
|
34
34
|
incrementMaxChars?: number;
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
|
-
* Run one extraction pass for a target. Never throws
|
|
38
|
-
* is
|
|
37
|
+
* Run one extraction pass for a target. Never throws unless the ledger
|
|
38
|
+
* itself is unwritable: every terminal path is either a landed application,
|
|
39
|
+
* a ledgered skip, or a ledgered failure — anything that escapes the
|
|
40
|
+
* per-stage handling inside lands a failed `unexpected-error` ledger row
|
|
41
|
+
* here, so no failure ends as a scheduler warn without an account trace.
|
|
39
42
|
*/
|
|
40
43
|
export declare function runExtraction(deps: ExtractionDeps, target: ExtractionTarget, opts: RunOptions): Promise<ExtractionResult>;
|
|
41
44
|
/** The event wiring surface (duck-typed cordis context). */
|
package/lib/extraction.js
CHANGED
|
@@ -3,11 +3,57 @@ import { EXTRACTION_SYSTEM_PROMPT, extractionPrompt, manifestLineOf, parseExtrac
|
|
|
3
3
|
import { cwdOf } from "./memory-section.js";
|
|
4
4
|
/** Head length of a failed run's raw answer kept in the ledger `files` column. */
|
|
5
5
|
const FAILURE_RAW_MAX = 2048;
|
|
6
|
+
/** Head length of an unexpected error's message/stack trace kept in the ledger `files` column. */
|
|
7
|
+
const UNEXPECTED_ERROR_RAW_MAX = 2048;
|
|
8
|
+
/** Head length of an error message embedded in a ledger `skip_reason`. */
|
|
9
|
+
const ERROR_REASON_MAX = 300;
|
|
10
|
+
/** Split an unexpected throw into a ledger-sized reason head and file body. */
|
|
11
|
+
function errorText(error) {
|
|
12
|
+
const message = error instanceof Error && error.message.length > 0 ? error.message : String(error);
|
|
13
|
+
const stack = error instanceof Error && typeof error.stack === "string" ? error.stack : message;
|
|
14
|
+
return { message, detail: `${message}\n${stack}`.slice(0, UNEXPECTED_ERROR_RAW_MAX) };
|
|
15
|
+
}
|
|
6
16
|
/**
|
|
7
|
-
* Run one extraction pass for a target. Never throws
|
|
8
|
-
* is
|
|
17
|
+
* Run one extraction pass for a target. Never throws unless the ledger
|
|
18
|
+
* itself is unwritable: every terminal path is either a landed application,
|
|
19
|
+
* a ledgered skip, or a ledgered failure — anything that escapes the
|
|
20
|
+
* per-stage handling inside lands a failed `unexpected-error` ledger row
|
|
21
|
+
* here, so no failure ends as a scheduler warn without an account trace.
|
|
9
22
|
*/
|
|
10
23
|
export async function runExtraction(deps, target, opts) {
|
|
24
|
+
const started = Date.now();
|
|
25
|
+
try {
|
|
26
|
+
return await runExtractionInner(deps, target, opts);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
const { message, detail } = errorText(error);
|
|
30
|
+
const reason = `unexpected-error: ${message.slice(0, ERROR_REASON_MAX)}`;
|
|
31
|
+
try {
|
|
32
|
+
deps.store.logSkipped({
|
|
33
|
+
sessionId: target.sessionId,
|
|
34
|
+
workspaceId: target.workspaceId,
|
|
35
|
+
trigger: opts.trigger,
|
|
36
|
+
skipReason: reason,
|
|
37
|
+
status: "failed",
|
|
38
|
+
model: target.model,
|
|
39
|
+
durationMs: Date.now() - started,
|
|
40
|
+
files: detail,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (ledgerError) {
|
|
44
|
+
// The ledger itself is down — nothing left to write to. Chain
|
|
45
|
+
// both errors so the scheduler's last-resort row keeps the
|
|
46
|
+
// triggering failure, not just the ledger fault.
|
|
47
|
+
throw new Error(`extraction failed (${message}); failure ledger write also failed (${errorText(ledgerError).message})`);
|
|
48
|
+
}
|
|
49
|
+
return { status: "failed", skipReason: reason };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The pipeline body: one bounded increment of one session, one LLM call, one
|
|
54
|
+
* gated transactional application, one ledger row, one cursor.
|
|
55
|
+
*/
|
|
56
|
+
async function runExtractionInner(deps, target, opts) {
|
|
11
57
|
const { store } = deps;
|
|
12
58
|
const ledgerBase = {
|
|
13
59
|
sessionId: target.sessionId,
|
|
@@ -37,8 +83,14 @@ export async function runExtraction(deps, target, opts) {
|
|
|
37
83
|
all = Array.isArray(snapshot.events) ? snapshot.events : [];
|
|
38
84
|
}
|
|
39
85
|
catch (error) {
|
|
40
|
-
|
|
41
|
-
|
|
86
|
+
const { message, detail } = errorText(error);
|
|
87
|
+
try {
|
|
88
|
+
store.logSkipped({ ...ledgerBase, skipReason: "surface-read-failed", status: "failed", files: detail });
|
|
89
|
+
}
|
|
90
|
+
catch (ledgerError) {
|
|
91
|
+
throw new Error(`surface read failed (${message}); failure ledger write also failed (${errorText(ledgerError).message})`);
|
|
92
|
+
}
|
|
93
|
+
return { status: "failed", skipReason: `surface read failed: ${message}` };
|
|
42
94
|
}
|
|
43
95
|
const events = eventsAfterCursor(all, cursor === undefined ? undefined : `seq:${cursor}`);
|
|
44
96
|
const slice = evaluateSlice({ events, internalAgent: false });
|
|
@@ -72,8 +124,14 @@ export async function runExtraction(deps, target, opts) {
|
|
|
72
124
|
usage = answer.usage;
|
|
73
125
|
}
|
|
74
126
|
catch (error) {
|
|
75
|
-
|
|
76
|
-
|
|
127
|
+
const { message, detail } = errorText(error);
|
|
128
|
+
try {
|
|
129
|
+
store.logSkipped({ ...ledgerBase, skipReason: "llm-failed", status: "failed", durationMs: Date.now() - started, files: detail });
|
|
130
|
+
}
|
|
131
|
+
catch (ledgerError) {
|
|
132
|
+
throw new Error(`llm call failed (${message}); failure ledger write also failed (${errorText(ledgerError).message})`);
|
|
133
|
+
}
|
|
134
|
+
return { status: "failed", skipReason: `llm call failed: ${message}` };
|
|
77
135
|
}
|
|
78
136
|
const parsed = parseExtractionAnswer(text);
|
|
79
137
|
if (parsed.decision === "error") {
|
|
@@ -213,7 +271,26 @@ export function createExtractionScheduler(host, deps) {
|
|
|
213
271
|
provider: target.provider,
|
|
214
272
|
model: target.model,
|
|
215
273
|
}, { trigger }).catch((error) => {
|
|
216
|
-
|
|
274
|
+
// Last resort: runExtraction ledgers its own unexpected failures,
|
|
275
|
+
// so this fires only when even that failed (the ledger write
|
|
276
|
+
// threw) — retry one ledger row here before the warn, so the
|
|
277
|
+
// failure still has an account trace.
|
|
278
|
+
const { message, detail } = errorText(error);
|
|
279
|
+
try {
|
|
280
|
+
deps.store.logSkipped({
|
|
281
|
+
sessionId: target.sessionId,
|
|
282
|
+
workspaceId: cwdOf(target.agent),
|
|
283
|
+
trigger,
|
|
284
|
+
skipReason: `unexpected-error: ${message.slice(0, ERROR_REASON_MAX)}`,
|
|
285
|
+
status: "failed",
|
|
286
|
+
model: target.model,
|
|
287
|
+
files: detail,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
// The ledger is down — the warn below is the last resort.
|
|
292
|
+
}
|
|
293
|
+
host.logger("continual-evolve").warn(`extraction run failed unexpectedly: ${message}`);
|
|
217
294
|
}).finally(() => {
|
|
218
295
|
slot.running = false;
|
|
219
296
|
if (slot.pending !== null) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-continual-evolve",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.4",
|
|
4
4
|
"description": "ZCode-style workspace memory for DeepSeek Harness: one central SQLite store partitioned by workspace, index injection, and sole-writer gated writes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|