dsh-continual-evolve 0.15.11 → 0.15.13
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 +13 -7
- package/README.zh.md +13 -7
- package/lib/chain.d.ts +30 -0
- package/lib/chain.js +29 -0
- package/lib/extraction-ring.d.ts +20 -0
- package/lib/extraction-ring.js +299 -0
- package/lib/extraction.d.ts +9 -5
- package/lib/extraction.js +31 -256
- package/lib/index.js +40 -3
- package/lib/llm-call.d.ts +168 -0
- package/lib/llm-call.js +284 -0
- package/lib/review-candidates.d.ts +25 -0
- package/lib/review-candidates.js +113 -0
- package/lib/review-prompt.d.ts +16 -2
- package/lib/review-prompt.js +19 -4
- package/lib/review-ring.d.ts +52 -0
- package/lib/review-ring.js +257 -0
- package/lib/review.d.ts +15 -33
- package/lib/review.js +48 -359
- package/lib/store.d.ts +2 -0
- package/lib/store.js +19 -4
- package/lib/subagent-defs.d.ts +43 -0
- package/lib/subagent-defs.js +85 -0
- package/lib/subagent.d.ts +81 -0
- package/lib/subagent.js +52 -0
- package/package.json +1 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every subagent this plugin runs, declared in one table.
|
|
3
|
+
*
|
|
4
|
+
* A definition carries the job's identity, its whole instruction (system
|
|
5
|
+
* prompt), its output-budget fallback and its answer parser. Feature code
|
|
6
|
+
* loads definitions from here and never writes a prompt or a budget inline;
|
|
7
|
+
* adding a job means adding a row, and a job with no row cannot be called.
|
|
8
|
+
*
|
|
9
|
+
* The four review jobs are separate definitions on purpose: the memory rubric
|
|
10
|
+
* requires a memory to survive having its repo name stripped, while a project
|
|
11
|
+
* skill is *supposed* to be repo-bound, so one prompt cannot serve both.
|
|
12
|
+
*/
|
|
13
|
+
import { EXTRACTION_CHEAP_SYSTEM_PROMPT, EXTRACTION_SYSTEM_PROMPT, parseCheapAnswer, parseExtractionAnswer, } from "./extraction-prompt.js";
|
|
14
|
+
import { parseEvolveAnswer, parseGateAnswer, REVIEW_MEMORY_CHEAP_SYSTEM_PROMPT, REVIEW_MEMORY_SYSTEM_PROMPT, REVIEW_SKILL_CHEAP_SYSTEM_PROMPT, REVIEW_SKILL_SYSTEM_PROMPT, } from "./review-prompt.js";
|
|
15
|
+
/**
|
|
16
|
+
* Output-budget fallbacks, used only for adapters that advertise no
|
|
17
|
+
* per-request cap of their own. A gate verdict is one JSON object plus the
|
|
18
|
+
* reasoning a thinking model spends before emitting it; the evolve/proposal
|
|
19
|
+
* calls additionally carry full replacement bodies.
|
|
20
|
+
*/
|
|
21
|
+
export const GATE_MAX_TOKENS = 1024;
|
|
22
|
+
export const EVOLVE_MAX_TOKENS = 4096;
|
|
23
|
+
export const EXTRACTION_MAX_TOKENS = 4096;
|
|
24
|
+
/** The memory cheap gate: is this entry worth a close look at all? */
|
|
25
|
+
export const reviewGateMemory = {
|
|
26
|
+
id: "review-gate-memory",
|
|
27
|
+
system: REVIEW_MEMORY_CHEAP_SYSTEM_PROMPT,
|
|
28
|
+
maxTokens: GATE_MAX_TOKENS,
|
|
29
|
+
parse: (text) => parseGateAnswer(text),
|
|
30
|
+
};
|
|
31
|
+
/** The skill cheap gate: same question, scope-relative home rules. */
|
|
32
|
+
export const reviewGateSkill = {
|
|
33
|
+
id: "review-gate-skill",
|
|
34
|
+
system: REVIEW_SKILL_CHEAP_SYSTEM_PROMPT,
|
|
35
|
+
maxTokens: GATE_MAX_TOKENS,
|
|
36
|
+
parse: (text) => parseGateAnswer(text),
|
|
37
|
+
};
|
|
38
|
+
/** The memory evolve pass: five-dimension judgment plus the proposed rewrite. */
|
|
39
|
+
export const reviewEvolveMemory = {
|
|
40
|
+
id: "review-evolve-memory",
|
|
41
|
+
system: REVIEW_MEMORY_SYSTEM_PROMPT,
|
|
42
|
+
maxTokens: EVOLVE_MAX_TOKENS,
|
|
43
|
+
parse: (text) => parseEvolveAnswer(text),
|
|
44
|
+
};
|
|
45
|
+
/** The skill evolve pass: scope-relative reuse, executability, duplication. */
|
|
46
|
+
export const reviewEvolveSkill = {
|
|
47
|
+
id: "review-evolve-skill",
|
|
48
|
+
system: REVIEW_SKILL_SYSTEM_PROMPT,
|
|
49
|
+
maxTokens: EVOLVE_MAX_TOKENS,
|
|
50
|
+
parse: (text) => parseEvolveAnswer(text),
|
|
51
|
+
};
|
|
52
|
+
/** The extraction pre-gate: does this increment hold anything worth proposing? */
|
|
53
|
+
export const extractionGate = {
|
|
54
|
+
id: "extraction-gate",
|
|
55
|
+
system: EXTRACTION_CHEAP_SYSTEM_PROMPT,
|
|
56
|
+
maxTokens: GATE_MAX_TOKENS,
|
|
57
|
+
parse: (text) => parseCheapAnswer(text),
|
|
58
|
+
};
|
|
59
|
+
/** The extraction proposal call: the run's one expensive call. */
|
|
60
|
+
export const extractionMain = {
|
|
61
|
+
id: "extraction-main",
|
|
62
|
+
system: EXTRACTION_SYSTEM_PROMPT,
|
|
63
|
+
maxTokens: EXTRACTION_MAX_TOKENS,
|
|
64
|
+
parse: (text) => parseExtractionAnswer(text),
|
|
65
|
+
};
|
|
66
|
+
/** Every definition, for the "which jobs exist" read and the id-uniqueness check. */
|
|
67
|
+
export const SUBAGENT_DEFINITIONS = [
|
|
68
|
+
reviewGateMemory,
|
|
69
|
+
reviewGateSkill,
|
|
70
|
+
reviewEvolveMemory,
|
|
71
|
+
reviewEvolveSkill,
|
|
72
|
+
extractionGate,
|
|
73
|
+
extractionMain,
|
|
74
|
+
];
|
|
75
|
+
/** The gate definition one review candidate loads, by item kind. */
|
|
76
|
+
export const REVIEW_GATE_BY_KIND = {
|
|
77
|
+
memory: reviewGateMemory,
|
|
78
|
+
skill: reviewGateSkill,
|
|
79
|
+
};
|
|
80
|
+
/** The evolve definition one review candidate loads, by item kind. */
|
|
81
|
+
export const REVIEW_EVOLVE_BY_KIND = {
|
|
82
|
+
memory: reviewEvolveMemory,
|
|
83
|
+
skill: reviewEvolveSkill,
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=subagent-defs.js.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The generic subagent and its loader: the only path from plugin feature code
|
|
3
|
+
* to an LLM call.
|
|
4
|
+
*
|
|
5
|
+
* A subagent is data — a strategy holding its identity, system prompt, output
|
|
6
|
+
* budget fallback and answer parser. The loader binds that strategy to one
|
|
7
|
+
* route and session, then runs it through one fixed skeleton (the template
|
|
8
|
+
* method): assemble the call, stream it, parse the answer, account for what
|
|
9
|
+
* happened. Failure accounting rides the same skeleton as success: the route
|
|
10
|
+
* and the usage a stream reported before it died come back on the thrown
|
|
11
|
+
* error, so a failed call can be audited exactly like a successful one.
|
|
12
|
+
*
|
|
13
|
+
* The structure is the point. "Which subagents exist and what each one is
|
|
14
|
+
* told" is readable in one table (`subagent-defs.ts`) instead of being spread
|
|
15
|
+
* across call sites, and a job that has no definition cannot be called.
|
|
16
|
+
*/
|
|
17
|
+
import { SubagentCallError, type LlmRuntime, type ModelSelection } from "./llm-call.js";
|
|
18
|
+
/** One subagent definition: everything that distinguishes one job from another. */
|
|
19
|
+
export interface SubagentDefinition<Answer> {
|
|
20
|
+
/** The job's name, for diagnostics; unique across the registry (asserted by test). */
|
|
21
|
+
readonly id: string;
|
|
22
|
+
/** The job's entire instruction, sent as the system prompt — nothing is appended at the call site. */
|
|
23
|
+
readonly system: string;
|
|
24
|
+
/** Output budget fallback; the exact model's advertised cap wins when it has one. */
|
|
25
|
+
readonly maxTokens: number;
|
|
26
|
+
/**
|
|
27
|
+
* Parse the answer text into this definition's answer type. A parser that
|
|
28
|
+
* can miss (`parseGateAnswer`, `parseCheapAnswer` …) includes `null` in its
|
|
29
|
+
* answer type: "no answer in the agreed shape" is a value, not a throw.
|
|
30
|
+
*/
|
|
31
|
+
readonly parse: (text: string) => Answer;
|
|
32
|
+
}
|
|
33
|
+
/** What one call is bound to: the LLM service, the exact route, the session identity. */
|
|
34
|
+
export interface SubagentCall {
|
|
35
|
+
llm: LlmRuntime | undefined;
|
|
36
|
+
route: ModelSelection;
|
|
37
|
+
sessionId: string | undefined;
|
|
38
|
+
}
|
|
39
|
+
/** One finished call: the parsed answer, the raw text, and the observed call facts. */
|
|
40
|
+
export interface SubagentAnswer<Answer> {
|
|
41
|
+
answer: Answer;
|
|
42
|
+
text: string;
|
|
43
|
+
/** The provider's usage payload, exactly as observed; `undefined` when it reported none. */
|
|
44
|
+
usage: unknown;
|
|
45
|
+
/** The terminal finish kind (`stop`, `max-tokens`, …); `undefined` when the stream omitted it. */
|
|
46
|
+
finish: string | undefined;
|
|
47
|
+
}
|
|
48
|
+
/** The loader feature code holds: bound to one route/session, it runs definitions. */
|
|
49
|
+
export interface SubagentLoader {
|
|
50
|
+
/**
|
|
51
|
+
* Run one definition once.
|
|
52
|
+
*
|
|
53
|
+
* @param definition - The subagent strategy to run.
|
|
54
|
+
* @param prompt - This call's user prompt.
|
|
55
|
+
* @returns The parsed answer plus the observed usage and finish kind.
|
|
56
|
+
* @throws On call failures (a `SubagentCallError` carries the observed usage and route) or a missing route.
|
|
57
|
+
*/
|
|
58
|
+
run<Answer>(definition: SubagentDefinition<Answer>, prompt: string): Promise<SubagentAnswer<Answer>>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build the loader for one call context — the simple factory: the context
|
|
62
|
+
* produces the bound runner, the definitions table produces the strategies.
|
|
63
|
+
*
|
|
64
|
+
* @param call - The LLM service, the exact route, and the session identity to send.
|
|
65
|
+
* @returns A loader whose `run` is the only LLM entry point a feature needs.
|
|
66
|
+
*/
|
|
67
|
+
export declare function subagentLoaderFor(call: SubagentCall): SubagentLoader;
|
|
68
|
+
/**
|
|
69
|
+
* Reject one answer as a failed call because the stream was cut.
|
|
70
|
+
*
|
|
71
|
+
* A cut answer is unusable by design — a half-written body must never become a
|
|
72
|
+
* verdict, and a gate that produced no verdict is not an approval. The error
|
|
73
|
+
* carries the facts the call already reported, so the failure is accounted
|
|
74
|
+
* exactly like a transport failure instead of vanishing.
|
|
75
|
+
*
|
|
76
|
+
* @param answer - The cut answer.
|
|
77
|
+
* @param route - The route it ran on.
|
|
78
|
+
* @returns The error to throw.
|
|
79
|
+
*/
|
|
80
|
+
export declare function cutFailureOf<Answer>(answer: SubagentAnswer<Answer>, route: ModelSelection): SubagentCallError;
|
|
81
|
+
//# sourceMappingURL=subagent.d.ts.map
|
package/lib/subagent.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The generic subagent and its loader: the only path from plugin feature code
|
|
3
|
+
* to an LLM call.
|
|
4
|
+
*
|
|
5
|
+
* A subagent is data — a strategy holding its identity, system prompt, output
|
|
6
|
+
* budget fallback and answer parser. The loader binds that strategy to one
|
|
7
|
+
* route and session, then runs it through one fixed skeleton (the template
|
|
8
|
+
* method): assemble the call, stream it, parse the answer, account for what
|
|
9
|
+
* happened. Failure accounting rides the same skeleton as success: the route
|
|
10
|
+
* and the usage a stream reported before it died come back on the thrown
|
|
11
|
+
* error, so a failed call can be audited exactly like a successful one.
|
|
12
|
+
*
|
|
13
|
+
* The structure is the point. "Which subagents exist and what each one is
|
|
14
|
+
* told" is readable in one table (`subagent-defs.ts`) instead of being spread
|
|
15
|
+
* across call sites, and a job that has no definition cannot be called.
|
|
16
|
+
*/
|
|
17
|
+
import { SubagentCallError, streamOnce } from "./llm-call.js";
|
|
18
|
+
/**
|
|
19
|
+
* Build the loader for one call context — the simple factory: the context
|
|
20
|
+
* produces the bound runner, the definitions table produces the strategies.
|
|
21
|
+
*
|
|
22
|
+
* @param call - The LLM service, the exact route, and the session identity to send.
|
|
23
|
+
* @returns A loader whose `run` is the only LLM entry point a feature needs.
|
|
24
|
+
*/
|
|
25
|
+
export function subagentLoaderFor(call) {
|
|
26
|
+
return {
|
|
27
|
+
async run(definition, prompt) {
|
|
28
|
+
const result = await streamOnce(call.llm, call.route, call.sessionId, definition.system, prompt, definition.maxTokens);
|
|
29
|
+
return { answer: definition.parse(result.text), text: result.text, usage: result.usage, finish: result.finish };
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Reject one answer as a failed call because the stream was cut.
|
|
35
|
+
*
|
|
36
|
+
* A cut answer is unusable by design — a half-written body must never become a
|
|
37
|
+
* verdict, and a gate that produced no verdict is not an approval. The error
|
|
38
|
+
* carries the facts the call already reported, so the failure is accounted
|
|
39
|
+
* exactly like a transport failure instead of vanishing.
|
|
40
|
+
*
|
|
41
|
+
* @param answer - The cut answer.
|
|
42
|
+
* @param route - The route it ran on.
|
|
43
|
+
* @returns The error to throw.
|
|
44
|
+
*/
|
|
45
|
+
export function cutFailureOf(answer, route) {
|
|
46
|
+
return new SubagentCallError(`stream finished with ${answer.finish ?? "unknown"}`, {
|
|
47
|
+
usage: answer.usage,
|
|
48
|
+
finish: answer.finish,
|
|
49
|
+
route,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=subagent.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-continual-evolve",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.13",
|
|
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": {
|