dsh-continual-evolve 0.10.6 → 0.12.0
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 +35 -122
- package/README.zh.md +26 -97
- package/cordis.patch.yml +2 -2
- package/lib/index.d.ts +44 -241
- package/lib/index.js +30 -253
- package/lib/memory-guide.d.ts +13 -14
- package/lib/memory-guide.js +32 -21
- package/lib/memory-section.d.ts +77 -0
- package/lib/memory-section.js +189 -0
- package/package.json +2 -17
- package/lib/apply.d.ts +0 -22
- package/lib/apply.js +0 -157
- package/lib/approval.d.ts +0 -72
- package/lib/approval.js +0 -127
- package/lib/auto.d.ts +0 -236
- package/lib/auto.js +0 -773
- package/lib/autocase.d.ts +0 -38
- package/lib/autocase.js +0 -76
- package/lib/benchmark-command.d.ts +0 -9
- package/lib/benchmark-command.js +0 -357
- package/lib/benchmark.d.ts +0 -151
- package/lib/benchmark.js +0 -250
- package/lib/command.d.ts +0 -49
- package/lib/command.js +0 -568
- package/lib/consolidate.d.ts +0 -90
- package/lib/consolidate.js +0 -180
- package/lib/copy.d.ts +0 -74
- package/lib/copy.js +0 -160
- package/lib/declines.d.ts +0 -101
- package/lib/declines.js +0 -175
- package/lib/evaluate.d.ts +0 -74
- package/lib/evaluate.js +0 -271
- package/lib/evolve-event.d.ts +0 -40
- package/lib/evolve-event.js +0 -59
- package/lib/failures.d.ts +0 -42
- package/lib/failures.js +0 -171
- package/lib/fate.d.ts +0 -130
- package/lib/fate.js +0 -350
- package/lib/goal-command.d.ts +0 -7
- package/lib/goal-command.js +0 -37
- package/lib/goal.d.ts +0 -72
- package/lib/goal.js +0 -72
- package/lib/inject.d.ts +0 -196
- package/lib/inject.js +0 -412
- package/lib/llm-text.d.ts +0 -104
- package/lib/llm-text.js +0 -140
- package/lib/logfile.d.ts +0 -71
- package/lib/logfile.js +0 -159
- package/lib/memory-agent.d.ts +0 -129
- package/lib/memory-agent.js +0 -568
- package/lib/memory-benchmark.d.ts +0 -76
- package/lib/memory-benchmark.js +0 -170
- package/lib/memory-index.d.ts +0 -114
- package/lib/memory-index.js +0 -197
- package/lib/message-source.d.ts +0 -23
- package/lib/message-source.js +0 -12
- package/lib/mount-command.d.ts +0 -10
- package/lib/mount-command.js +0 -48
- package/lib/mount.d.ts +0 -42
- package/lib/mount.js +0 -212
- package/lib/notify.d.ts +0 -59
- package/lib/notify.js +0 -97
- package/lib/plan.d.ts +0 -16
- package/lib/plan.js +0 -126
- package/lib/planner.d.ts +0 -61
- package/lib/planner.js +0 -144
- package/lib/pool.d.ts +0 -7
- package/lib/pool.js +0 -25
- package/lib/prefix-cache.d.ts +0 -78
- package/lib/prefix-cache.js +0 -168
- package/lib/project.d.ts +0 -28
- package/lib/project.js +0 -66
- package/lib/projection.d.ts +0 -22
- package/lib/projection.js +0 -112
- package/lib/promotion.d.ts +0 -94
- package/lib/promotion.js +0 -171
- package/lib/recall.d.ts +0 -85
- package/lib/recall.js +0 -142
- package/lib/record-language.d.ts +0 -85
- package/lib/record-language.js +0 -152
- package/lib/render.d.ts +0 -13
- package/lib/render.js +0 -80
- package/lib/review-scheduler.d.ts +0 -38
- package/lib/review-scheduler.js +0 -191
- package/lib/review.d.ts +0 -60
- package/lib/review.js +0 -145
- package/lib/rollback.d.ts +0 -9
- package/lib/rollback.js +0 -68
- package/lib/rubric.d.ts +0 -29
- package/lib/rubric.js +0 -119
- package/lib/runtime.d.ts +0 -24
- package/lib/runtime.js +0 -87
- package/lib/score.d.ts +0 -64
- package/lib/score.js +0 -191
- package/lib/search.d.ts +0 -83
- package/lib/search.js +0 -136
- package/lib/service.d.ts +0 -49
- package/lib/service.js +0 -180
- package/lib/skill-render.d.ts +0 -23
- package/lib/skill-render.js +0 -69
- package/lib/skill.d.ts +0 -15
- package/lib/skill.js +0 -80
- package/lib/skillquality.d.ts +0 -85
- package/lib/skillquality.js +0 -320
- package/lib/source.d.ts +0 -30
- package/lib/source.js +0 -43
- package/lib/state.d.ts +0 -26
- package/lib/state.js +0 -151
- package/lib/store.d.ts +0 -62
- package/lib/store.js +0 -164
- package/lib/token-usage.d.ts +0 -68
- package/lib/token-usage.js +0 -211
- package/lib/tool.d.ts +0 -34
- package/lib/tool.js +0 -320
- package/lib/turn-snapshot.d.ts +0 -72
- package/lib/turn-snapshot.js +0 -238
- package/lib/types.d.ts +0 -208
- package/lib/types.js +0 -127
- package/lib/usage.d.ts +0 -36
- package/lib/usage.js +0 -98
- package/lib/validate.d.ts +0 -28
- package/lib/validate.js +0 -181
- package/lib/wrapup-command.d.ts +0 -10
- package/lib/wrapup-command.js +0 -243
- package/lib/wrapup.d.ts +0 -260
- package/lib/wrapup.js +0 -539
package/lib/turn-snapshot.js
DELETED
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import { sessionEventsOf } from "./inject.js";
|
|
2
|
-
import { projectKeyOf } from "./project.js";
|
|
3
|
-
/** ZCode's minimum user-prose threshold, counted as lexical words. */
|
|
4
|
-
export const MEMORY_MIN_USER_WORDS = 3;
|
|
5
|
-
const WORD_SEGMENTER = new Intl.Segmenter("und", { granularity: "word" });
|
|
6
|
-
function countUserWords(text) {
|
|
7
|
-
return [...WORD_SEGMENTER.segment(text)].filter((segment) => segment.isWordLike).length;
|
|
8
|
-
}
|
|
9
|
-
function containsEligibleUserProse(events, minUserWords) {
|
|
10
|
-
return events.some((event) => {
|
|
11
|
-
if (!isDirectUserEvent(event))
|
|
12
|
-
return false;
|
|
13
|
-
const row = event;
|
|
14
|
-
return countUserWords(contentText(row.data?.content)) >= minUserWords;
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Capture the current durable surface and select only rows after `cursor`.
|
|
19
|
-
* A seq-bearing session uses `seq:<n>`; older/test surfaces fall back to an
|
|
20
|
-
* event-count cursor so the scheduler still has a deterministic boundary.
|
|
21
|
-
*/
|
|
22
|
-
export async function captureTurnSnapshot(ctx, agent, opts) {
|
|
23
|
-
const allEvents = await readSurface(ctx, agent);
|
|
24
|
-
const cursor = boundaryCursor(allEvents);
|
|
25
|
-
const events = eventsAfterCursor(allEvents, opts.cursor);
|
|
26
|
-
const minUserWords = opts.minUserWords ?? MEMORY_MIN_USER_WORDS;
|
|
27
|
-
const eligibility = evaluateSnapshotEligibility(events, isInternalAgent(agent), minUserWords);
|
|
28
|
-
const projectKey = projectKeyOf(agent);
|
|
29
|
-
return {
|
|
30
|
-
sessionId: agent.id,
|
|
31
|
-
...(projectKey ? { projectKey } : {}),
|
|
32
|
-
turn: opts.turn,
|
|
33
|
-
reason: opts.reason,
|
|
34
|
-
cursor,
|
|
35
|
-
events,
|
|
36
|
-
trajectory: eligibility.eligible ? serializeSnapshotEvents(events, opts.maxChars) : "",
|
|
37
|
-
userText: eligibility.userText,
|
|
38
|
-
sourceSeqs: directUserSeqs(events),
|
|
39
|
-
maxChars: opts.maxChars,
|
|
40
|
-
minUserWords,
|
|
41
|
-
...(opts.cursor === undefined ? {} : { capturedAfterCursor: opts.cursor }),
|
|
42
|
-
eligible: eligibility.eligible,
|
|
43
|
-
...(eligibility.reason ? { skipReason: eligibility.reason } : {}),
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Rebase one captured snapshot onto a phase-specific cursor while preserving
|
|
48
|
-
* its outer boundary. The memory phase uses this after a downstream review or
|
|
49
|
-
* fate failure: already-processed evidence is removed, but newly captured rows
|
|
50
|
-
* remain available without moving the shared scheduler cursor backwards.
|
|
51
|
-
*/
|
|
52
|
-
export function sliceTurnSnapshot(snapshot, cursor) {
|
|
53
|
-
const events = sliceSnapshotEvents(snapshot, cursor);
|
|
54
|
-
const eligibility = evaluateSnapshotEligibility(events, false, snapshot.minUserWords);
|
|
55
|
-
return {
|
|
56
|
-
...snapshot,
|
|
57
|
-
events,
|
|
58
|
-
trajectory: eligibility.eligible ? serializeSnapshotEvents(events, snapshot.maxChars) : "",
|
|
59
|
-
userText: eligibility.userText,
|
|
60
|
-
sourceSeqs: directUserSeqs(events),
|
|
61
|
-
eligible: eligibility.eligible,
|
|
62
|
-
...(eligibility.reason ? { skipReason: eligibility.reason } : {}),
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Decide whether the incremental rows deserve a model call. This intentionally
|
|
67
|
-
* does not decide whether a fact is valuable; that remains the review model's
|
|
68
|
-
* job. It only removes mechanical noise before the scheduler spends tokens.
|
|
69
|
-
*/
|
|
70
|
-
export function evaluateSnapshotEligibility(events, internalAgent = false, minUserWords = MEMORY_MIN_USER_WORDS) {
|
|
71
|
-
if (internalAgent)
|
|
72
|
-
return { eligible: false, reason: "internal-agent", userText: "" };
|
|
73
|
-
if (events.length === 0)
|
|
74
|
-
return { eligible: false, reason: "no-new-events", userText: "" };
|
|
75
|
-
if (containsDirectMemoryWrite(events))
|
|
76
|
-
return { eligible: false, reason: "direct-memory-write", userText: "" };
|
|
77
|
-
const userText = directUserText(events);
|
|
78
|
-
if (!containsEligibleUserProse(events, minUserWords))
|
|
79
|
-
return { eligible: false, reason: "no-user-prose", userText };
|
|
80
|
-
return { eligible: true, userText };
|
|
81
|
-
}
|
|
82
|
-
/** True when an assistant row records an explicit evolve memory mutation. */
|
|
83
|
-
export function containsDirectMemoryWrite(events) {
|
|
84
|
-
for (const event of events) {
|
|
85
|
-
if (!event || typeof event !== "object")
|
|
86
|
-
continue;
|
|
87
|
-
const row = event;
|
|
88
|
-
if (row.type === "tool/call" || row.type === "tool-call") {
|
|
89
|
-
if (isMemoryMutationName(readNestedString(row.data, ["name", "tool", "toolName"])))
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
if (row.type === "assistant/message" && containsMemoryMutationName(row.data))
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
return false;
|
|
96
|
-
}
|
|
97
|
-
/** Serialize only user/assistant text, retaining the bounded tail. */
|
|
98
|
-
export function serializeSnapshotEvents(events, maxChars) {
|
|
99
|
-
const lines = [];
|
|
100
|
-
for (const raw of events) {
|
|
101
|
-
if (!raw || typeof raw !== "object")
|
|
102
|
-
continue;
|
|
103
|
-
const event = raw;
|
|
104
|
-
if (event.type === "user/message" && !isDirectUserEvent(raw))
|
|
105
|
-
continue;
|
|
106
|
-
const role = event.type === "user/message" ? "user" : event.type === "assistant/message" ? "assistant" : null;
|
|
107
|
-
if (role === null)
|
|
108
|
-
continue;
|
|
109
|
-
const text = contentText(event.data?.content).trim();
|
|
110
|
-
if (text.length > 0)
|
|
111
|
-
lines.push(`${role}: ${text}`);
|
|
112
|
-
}
|
|
113
|
-
const joined = lines.join("\n");
|
|
114
|
-
return joined.length <= maxChars ? joined : joined.slice(-maxChars);
|
|
115
|
-
}
|
|
116
|
-
/** A DSH subagent header is an internal source when its origin says so. */
|
|
117
|
-
export function isInternalAgent(agent) {
|
|
118
|
-
const header = agent?.session?.header;
|
|
119
|
-
return header?.origin === "subagent" || header?.origin === "internal" || header?.isSubagent === true;
|
|
120
|
-
}
|
|
121
|
-
async function readSurface(ctx, agent) {
|
|
122
|
-
const reader = ctx.sessionQuery;
|
|
123
|
-
if (reader) {
|
|
124
|
-
const snapshot = await reader.readSurface(agent.id);
|
|
125
|
-
return Array.isArray(snapshot.events) ? snapshot.events : [];
|
|
126
|
-
}
|
|
127
|
-
return sessionEventsOf(agent);
|
|
128
|
-
}
|
|
129
|
-
function boundaryCursor(events) {
|
|
130
|
-
const seqs = events.map(eventSeq).filter((seq) => seq !== undefined);
|
|
131
|
-
return seqs.length > 0 ? `seq:${Math.max(...seqs)}` : `index:${events.length}`;
|
|
132
|
-
}
|
|
133
|
-
function sliceSnapshotEvents(snapshot, cursor) {
|
|
134
|
-
if (snapshot.cursor.startsWith("index:") && cursor.startsWith("index:") && snapshot.capturedAfterCursor?.startsWith("index:")) {
|
|
135
|
-
const start = Number(snapshot.capturedAfterCursor.slice("index:".length));
|
|
136
|
-
const phaseBoundary = Number(cursor.slice("index:".length));
|
|
137
|
-
if (!Number.isInteger(start) || !Number.isInteger(phaseBoundary))
|
|
138
|
-
return snapshot.events;
|
|
139
|
-
const relative = phaseBoundary - start;
|
|
140
|
-
if (relative <= 0)
|
|
141
|
-
return snapshot.events;
|
|
142
|
-
return relative >= snapshot.events.length ? [] : snapshot.events.slice(relative);
|
|
143
|
-
}
|
|
144
|
-
return eventsAfterCursor(snapshot.events, cursor);
|
|
145
|
-
}
|
|
146
|
-
function eventsAfterCursor(events, cursor) {
|
|
147
|
-
if (cursor === undefined)
|
|
148
|
-
return events;
|
|
149
|
-
if (cursor.startsWith("seq:")) {
|
|
150
|
-
const boundary = Number(cursor.slice(4));
|
|
151
|
-
if (!Number.isFinite(boundary))
|
|
152
|
-
return events;
|
|
153
|
-
return events.filter((event) => {
|
|
154
|
-
const seq = eventSeq(event);
|
|
155
|
-
return seq === undefined || seq > boundary;
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
if (cursor.startsWith("index:")) {
|
|
159
|
-
const boundary = Number(cursor.slice(6));
|
|
160
|
-
return Number.isInteger(boundary) && boundary >= 0 ? events.slice(boundary) : events;
|
|
161
|
-
}
|
|
162
|
-
return events;
|
|
163
|
-
}
|
|
164
|
-
function directUserText(events) {
|
|
165
|
-
return events
|
|
166
|
-
.filter(isDirectUserEvent)
|
|
167
|
-
.map((event) => contentText(event.data?.content).trim())
|
|
168
|
-
.filter(Boolean)
|
|
169
|
-
.join("\n");
|
|
170
|
-
}
|
|
171
|
-
function directUserSeqs(events) {
|
|
172
|
-
return events
|
|
173
|
-
.filter(isDirectUserEvent)
|
|
174
|
-
.map(eventSeq)
|
|
175
|
-
.filter((seq) => seq !== undefined);
|
|
176
|
-
}
|
|
177
|
-
function isDirectUserEvent(event) {
|
|
178
|
-
if (!event || typeof event !== "object")
|
|
179
|
-
return false;
|
|
180
|
-
const row = event;
|
|
181
|
-
if (row.type !== "user/message")
|
|
182
|
-
return false;
|
|
183
|
-
if (row.data?.visibility === "model-only")
|
|
184
|
-
return false;
|
|
185
|
-
if (row.data?.source?.synthetic === true)
|
|
186
|
-
return false;
|
|
187
|
-
if (row.data?.source?.kind !== undefined && row.data.source.kind !== "user")
|
|
188
|
-
return false;
|
|
189
|
-
return contentText(row.data?.content).trim().length > 0;
|
|
190
|
-
}
|
|
191
|
-
function contentText(content) {
|
|
192
|
-
if (typeof content === "string")
|
|
193
|
-
return content;
|
|
194
|
-
if (!Array.isArray(content))
|
|
195
|
-
return "";
|
|
196
|
-
return content
|
|
197
|
-
.map((block) => {
|
|
198
|
-
if (typeof block === "string")
|
|
199
|
-
return block;
|
|
200
|
-
if (!block || typeof block !== "object")
|
|
201
|
-
return "";
|
|
202
|
-
const value = block;
|
|
203
|
-
if (value.synthetic === true || value.ignored === true || (value.type !== undefined && value.type !== "text"))
|
|
204
|
-
return "";
|
|
205
|
-
return typeof value.text === "string" ? value.text : "";
|
|
206
|
-
})
|
|
207
|
-
.filter(Boolean)
|
|
208
|
-
.join(" ");
|
|
209
|
-
}
|
|
210
|
-
function eventSeq(event) {
|
|
211
|
-
if (!event || typeof event !== "object")
|
|
212
|
-
return undefined;
|
|
213
|
-
const seq = event.seq;
|
|
214
|
-
return typeof seq === "number" && Number.isInteger(seq) ? seq : undefined;
|
|
215
|
-
}
|
|
216
|
-
function containsMemoryMutationName(value) {
|
|
217
|
-
if (typeof value === "string")
|
|
218
|
-
return isMemoryMutationName(value);
|
|
219
|
-
if (Array.isArray(value))
|
|
220
|
-
return value.some(containsMemoryMutationName);
|
|
221
|
-
if (!value || typeof value !== "object")
|
|
222
|
-
return false;
|
|
223
|
-
return Object.values(value).some(containsMemoryMutationName);
|
|
224
|
-
}
|
|
225
|
-
function isMemoryMutationName(value) {
|
|
226
|
-
return value === "evolve_add" || value === "evolve_update" || value === "evolve_delete";
|
|
227
|
-
}
|
|
228
|
-
function readNestedString(value, keys) {
|
|
229
|
-
if (!value || typeof value !== "object")
|
|
230
|
-
return undefined;
|
|
231
|
-
const row = value;
|
|
232
|
-
for (const key of keys) {
|
|
233
|
-
if (typeof row[key] === "string")
|
|
234
|
-
return row[key];
|
|
235
|
-
}
|
|
236
|
-
return undefined;
|
|
237
|
-
}
|
|
238
|
-
//# sourceMappingURL=turn-snapshot.js.map
|
package/lib/types.d.ts
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
/** What a harness entry can be. */
|
|
2
|
-
export type RefinementKind = "prompt" | "memory" | "skill" | "subagent";
|
|
3
|
-
/**
|
|
4
|
-
* Skill-entry form: `executable` skills carry a python reference contract
|
|
5
|
-
* and can be hot-mounted as tools; `guidance` skills are SKILL.md documents
|
|
6
|
-
* (no python reference) that materialize as discoverable skills for the
|
|
7
|
-
* `skill` tool — the form for recurring multi-step workflows. Absent means
|
|
8
|
-
* `executable` (backwards compatible with pre-guidance stores).
|
|
9
|
-
*/
|
|
10
|
-
export type SkillKind = "executable" | "guidance";
|
|
11
|
-
/** How an entry changes. */
|
|
12
|
-
export type RefinementAction = "create" | "update" | "delete" | "archive";
|
|
13
|
-
/** Where an entry lives: session staging, one project, or cross-project. */
|
|
14
|
-
export type HarnessScope = "local" | "project" | "global";
|
|
15
|
-
/**
|
|
16
|
-
* Memory-entry shape discipline (one fact per entry, typed like ZCode's
|
|
17
|
-
* memory frontmatter): every `memory` create must stamp one of these in
|
|
18
|
-
* `metadata[MEMORY_TYPE_KEY]` — the recall hook the directory shows.
|
|
19
|
-
*/
|
|
20
|
-
export declare const MEMORY_TYPE_KEY = "memoryType";
|
|
21
|
-
/** Closed memory-type set: user | feedback | project | reference. */
|
|
22
|
-
export declare const MEMORY_TYPES: readonly ["user", "feedback", "project", "reference"];
|
|
23
|
-
/** One of {@link MEMORY_TYPES}. */
|
|
24
|
-
export type MemoryRecallType = (typeof MEMORY_TYPES)[number];
|
|
25
|
-
/** True when the value is a closed-set memory type. */
|
|
26
|
-
export declare function isMemoryType(value: unknown): value is MemoryRecallType;
|
|
27
|
-
/**
|
|
28
|
-
* Metadata key recording which session an entry's content was distilled from
|
|
29
|
-
* (trajectory citation; see {@link EntrySource}).
|
|
30
|
-
*/
|
|
31
|
-
export declare const SOURCE_SESSION_KEY = "sourceSession";
|
|
32
|
-
/**
|
|
33
|
-
* Metadata key recording the session-log event seqs (of the direct user
|
|
34
|
-
* messages) the entry cites as its source (trajectory citation).
|
|
35
|
-
*/
|
|
36
|
-
export declare const SOURCE_SEQS_KEY = "sourceSeqs";
|
|
37
|
-
/**
|
|
38
|
-
* Metadata key recording when an entry was archived. Archived entries are
|
|
39
|
-
* hidden from injection but never deleted — the data stays in the store and
|
|
40
|
-
* the entry can be restored (unarchive) or rolled back like any other edit.
|
|
41
|
-
*/
|
|
42
|
-
export declare const ARCHIVED_AT_KEY = "archivedAt";
|
|
43
|
-
/**
|
|
44
|
-
* Metadata key stamped on a LOCAL entry that was promoted to the global
|
|
45
|
-
* store by a session wrap-up: the id of the global entry it became. Present
|
|
46
|
-
* means the entry's lifecycle is finished — it must not be offered for
|
|
47
|
-
* promotion again (the global copy is the live one, the local copy is a
|
|
48
|
-
* restorable trace).
|
|
49
|
-
*/
|
|
50
|
-
export declare const PROMOTED_TO_KEY = "promotedTo";
|
|
51
|
-
/**
|
|
52
|
-
* Metadata key recording when a local entry was promoted to the global
|
|
53
|
-
* store (companion of {@link PROMOTED_TO_KEY}).
|
|
54
|
-
*/
|
|
55
|
-
export declare const PROMOTED_AT_KEY = "promotedAt";
|
|
56
|
-
/**
|
|
57
|
-
* Metadata key stamped on a GLOBAL entry created by a session wrap-up
|
|
58
|
-
* promotion: `<sessionId>:<localEntryId>` — the反向 provenance link from the
|
|
59
|
-
* cross-session copy back to the session it was distilled from.
|
|
60
|
-
*/
|
|
61
|
-
export declare const SOURCED_FROM_KEY = "sourcedFromLocal";
|
|
62
|
-
/**
|
|
63
|
-
* Metadata key stamped on a GLOBAL entry that was created despite a
|
|
64
|
-
* moderate-similarity overlap with an existing entry (write-time conflict
|
|
65
|
-
* guard, warn tier): `<kind>:<id>:<score>` — points at the entry it may
|
|
66
|
-
* duplicate so wrapup/fate can consolidate later. Creates at/above the block
|
|
67
|
-
* threshold never reach this stamp; they are rejected outright.
|
|
68
|
-
*/
|
|
69
|
-
export declare const CONFLICT_HINT_KEY = "conflictHint";
|
|
70
|
-
/**
|
|
71
|
-
* Negative-valence counter (P1 效价反馈): how many times an assessment marked
|
|
72
|
-
* this entry contradicted by newer evidence (user correction, overridden
|
|
73
|
-
* fact). Injection ranking demotes entries with a positive counter and the
|
|
74
|
-
* wrapup/fate assessors see the count so they prefer archiving the entry.
|
|
75
|
-
*/
|
|
76
|
-
export declare const VALENCE_NEGATIVE_KEY = "valenceNegative";
|
|
77
|
-
/**
|
|
78
|
-
* Provenance of entries merged INTO this one by the consolidation command
|
|
79
|
-
* (P1 反膨胀): array of `<kind>:<id>` — the near-duplicate sources whose
|
|
80
|
-
* content was appended before they archived. The trail keeps an unarchive of
|
|
81
|
-
* the source explainable and lets audits find the merge provenance.
|
|
82
|
-
*/
|
|
83
|
-
export declare const MERGED_FROM_KEY = "mergedFrom";
|
|
84
|
-
/**
|
|
85
|
-
* True when the entry is archived (hidden from injection, restorable).
|
|
86
|
-
* Absent or empty archivedAt means the entry is active.
|
|
87
|
-
*/
|
|
88
|
-
export declare function isArchived(entry: HarnessEntry): boolean;
|
|
89
|
-
/**
|
|
90
|
-
* Trajectory citation attached to newly created entries: the session the
|
|
91
|
-
* content came from and the seqs of the direct user messages it was
|
|
92
|
-
* distilled from. Both fields are optional — when they cannot be determined
|
|
93
|
-
* the citation is simply omitted (never an error).
|
|
94
|
-
*/
|
|
95
|
-
export interface EntrySource {
|
|
96
|
-
sessionId?: string;
|
|
97
|
-
/** Event seqs of the source user messages, in log order. */
|
|
98
|
-
seqs?: number[];
|
|
99
|
-
}
|
|
100
|
-
/** A single persisted harness entry. */
|
|
101
|
-
export interface HarnessEntry {
|
|
102
|
-
id: string;
|
|
103
|
-
kind: RefinementKind;
|
|
104
|
-
title: string;
|
|
105
|
-
content: string;
|
|
106
|
-
path: string;
|
|
107
|
-
scope: HarnessScope;
|
|
108
|
-
/** Skill entries carry an executable contract; see {@link PythonReference}. */
|
|
109
|
-
reference: Record<string, unknown>;
|
|
110
|
-
/** Skill entries declare their accepted inputs here. */
|
|
111
|
-
arguments: Record<string, unknown>;
|
|
112
|
-
/** Skill form: "executable" (default) or "guidance" (SKILL.md document). */
|
|
113
|
-
skill_kind?: SkillKind;
|
|
114
|
-
metadata: Record<string, unknown>;
|
|
115
|
-
source: "evolve";
|
|
116
|
-
created_at: string;
|
|
117
|
-
updated_at: string;
|
|
118
|
-
version: number;
|
|
119
|
-
}
|
|
120
|
-
/** One entry of the append-only refinement history (the evidence trail). */
|
|
121
|
-
export interface HarnessRefinementEvent {
|
|
122
|
-
id: string;
|
|
123
|
-
trigger: string;
|
|
124
|
-
changes: string[];
|
|
125
|
-
/** Where the trajectory evidence for this refinement lives (e.g. seq ranges). */
|
|
126
|
-
evidence: string;
|
|
127
|
-
/** The falsifiable expectation recorded with the edit. */
|
|
128
|
-
outcome: string;
|
|
129
|
-
created_at: string;
|
|
130
|
-
}
|
|
131
|
-
/** The whole harness state file. */
|
|
132
|
-
export interface HarnessState {
|
|
133
|
-
schema: number;
|
|
134
|
-
entries: Record<RefinementKind, Record<string, HarnessEntry>>;
|
|
135
|
-
refinements: HarnessRefinementEvent[];
|
|
136
|
-
}
|
|
137
|
-
/** A model-proposed edit, before validation and application. */
|
|
138
|
-
export interface RefinementEdit {
|
|
139
|
-
action: RefinementAction;
|
|
140
|
-
kind: RefinementKind;
|
|
141
|
-
id?: string;
|
|
142
|
-
title?: string;
|
|
143
|
-
content?: string;
|
|
144
|
-
path?: string;
|
|
145
|
-
reference?: Record<string, unknown>;
|
|
146
|
-
arguments?: Record<string, unknown>;
|
|
147
|
-
/** Skill form: "guidance" for SKILL.md document skills; absent = executable. */
|
|
148
|
-
skill_kind?: SkillKind;
|
|
149
|
-
metadata?: Record<string, unknown>;
|
|
150
|
-
reason?: string;
|
|
151
|
-
/**
|
|
152
|
-
* Gap C2: blast-radius annotation — how broadly this edit applies.
|
|
153
|
-
* Values: "general" (cross-project tactical), "project" (single project),
|
|
154
|
-
* "session" (one-off session-specific). The review gate checks that
|
|
155
|
-
* local-scope edits are "session" or "project" and global-scope edits
|
|
156
|
-
* are "general" or "project".
|
|
157
|
-
*/
|
|
158
|
-
blastRadius?: "general" | "project" | "session";
|
|
159
|
-
}
|
|
160
|
-
/** The structured output of a planning pass. */
|
|
161
|
-
export interface RefinementProposal {
|
|
162
|
-
summary: string;
|
|
163
|
-
rationale: string;
|
|
164
|
-
edits: RefinementEdit[];
|
|
165
|
-
expectedOutcome: string;
|
|
166
|
-
}
|
|
167
|
-
/** An edit after the apply pass: before/after snapshots and outcome per edit. */
|
|
168
|
-
export interface AppliedRefinementEdit extends RefinementEdit {
|
|
169
|
-
id: string;
|
|
170
|
-
before?: HarnessEntry;
|
|
171
|
-
after?: HarnessEntry;
|
|
172
|
-
applied: boolean;
|
|
173
|
-
error?: string;
|
|
174
|
-
}
|
|
175
|
-
/** The result of applying one refinement. */
|
|
176
|
-
export interface RefinementResult {
|
|
177
|
-
id: string;
|
|
178
|
-
summary: string;
|
|
179
|
-
rationale: string;
|
|
180
|
-
expectedOutcome: string;
|
|
181
|
-
appliedEdits: AppliedRefinementEdit[];
|
|
182
|
-
harnessStatePath: string;
|
|
183
|
-
rollbackOf?: string;
|
|
184
|
-
scope?: HarnessScope;
|
|
185
|
-
}
|
|
186
|
-
/** The executable contract a skill entry must carry (python REPL skills). */
|
|
187
|
-
export interface PythonReference {
|
|
188
|
-
type: "python";
|
|
189
|
-
import?: string;
|
|
190
|
-
python_import?: string;
|
|
191
|
-
callable?: string;
|
|
192
|
-
call_pattern?: string;
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* A stable id derived from a title: ASCII runs become snake_case (unchanged
|
|
196
|
-
* legacy behavior). Titles with no ASCII content at all (e.g. pure Chinese)
|
|
197
|
-
* used to collapse onto the bare fallback, so distinct memories shared one
|
|
198
|
-
* id and every later create failed as "already exists". They now take
|
|
199
|
-
* `<fallback>_<sha256-8>` instead: distinct titles get distinct ids while
|
|
200
|
-
* identical titles still dedupe onto the same id. The fallback itself is
|
|
201
|
-
* assumed id-safe (callers pass entry kinds).
|
|
202
|
-
*/
|
|
203
|
-
export declare function slug(raw: string, fallback: string): string;
|
|
204
|
-
/** Fresh empty state with the current schema version. */
|
|
205
|
-
export declare function emptyHarnessState(): HarnessState;
|
|
206
|
-
/** Deep clone helper (state is plain JSON data). */
|
|
207
|
-
export declare function cloneEntry(entry: HarnessEntry | undefined): HarnessEntry | undefined;
|
|
208
|
-
//# sourceMappingURL=types.d.ts.map
|
package/lib/types.js
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type model for the continual-evolution harness state.
|
|
3
|
-
*
|
|
4
|
-
* Design provenance: the state model follows the continual-harness design
|
|
5
|
-
* validated in prime-agent's `/refine` subsystem (MIT): versioned entries
|
|
6
|
-
* keyed by kind, an append-only refinement history carrying an evidence
|
|
7
|
-
* trail, atomic persistence, and deterministic inverse-op rollback. The
|
|
8
|
-
* code here is an original implementation, written for the DeepSeek Harness
|
|
9
|
-
* plugin surface.
|
|
10
|
-
*/
|
|
11
|
-
import { createHash } from "node:crypto";
|
|
12
|
-
/**
|
|
13
|
-
* Memory-entry shape discipline (one fact per entry, typed like ZCode's
|
|
14
|
-
* memory frontmatter): every `memory` create must stamp one of these in
|
|
15
|
-
* `metadata[MEMORY_TYPE_KEY]` — the recall hook the directory shows.
|
|
16
|
-
*/
|
|
17
|
-
export const MEMORY_TYPE_KEY = "memoryType";
|
|
18
|
-
/** Closed memory-type set: user | feedback | project | reference. */
|
|
19
|
-
export const MEMORY_TYPES = ["user", "feedback", "project", "reference"];
|
|
20
|
-
/** True when the value is a closed-set memory type. */
|
|
21
|
-
export function isMemoryType(value) {
|
|
22
|
-
return typeof value === "string" && MEMORY_TYPES.includes(value);
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Metadata key recording which session an entry's content was distilled from
|
|
26
|
-
* (trajectory citation; see {@link EntrySource}).
|
|
27
|
-
*/
|
|
28
|
-
export const SOURCE_SESSION_KEY = "sourceSession";
|
|
29
|
-
/**
|
|
30
|
-
* Metadata key recording the session-log event seqs (of the direct user
|
|
31
|
-
* messages) the entry cites as its source (trajectory citation).
|
|
32
|
-
*/
|
|
33
|
-
export const SOURCE_SEQS_KEY = "sourceSeqs";
|
|
34
|
-
/**
|
|
35
|
-
* Metadata key recording when an entry was archived. Archived entries are
|
|
36
|
-
* hidden from injection but never deleted — the data stays in the store and
|
|
37
|
-
* the entry can be restored (unarchive) or rolled back like any other edit.
|
|
38
|
-
*/
|
|
39
|
-
export const ARCHIVED_AT_KEY = "archivedAt";
|
|
40
|
-
/**
|
|
41
|
-
* Metadata key stamped on a LOCAL entry that was promoted to the global
|
|
42
|
-
* store by a session wrap-up: the id of the global entry it became. Present
|
|
43
|
-
* means the entry's lifecycle is finished — it must not be offered for
|
|
44
|
-
* promotion again (the global copy is the live one, the local copy is a
|
|
45
|
-
* restorable trace).
|
|
46
|
-
*/
|
|
47
|
-
export const PROMOTED_TO_KEY = "promotedTo";
|
|
48
|
-
/**
|
|
49
|
-
* Metadata key recording when a local entry was promoted to the global
|
|
50
|
-
* store (companion of {@link PROMOTED_TO_KEY}).
|
|
51
|
-
*/
|
|
52
|
-
export const PROMOTED_AT_KEY = "promotedAt";
|
|
53
|
-
/**
|
|
54
|
-
* Metadata key stamped on a GLOBAL entry created by a session wrap-up
|
|
55
|
-
* promotion: `<sessionId>:<localEntryId>` — the反向 provenance link from the
|
|
56
|
-
* cross-session copy back to the session it was distilled from.
|
|
57
|
-
*/
|
|
58
|
-
export const SOURCED_FROM_KEY = "sourcedFromLocal";
|
|
59
|
-
/**
|
|
60
|
-
* Metadata key stamped on a GLOBAL entry that was created despite a
|
|
61
|
-
* moderate-similarity overlap with an existing entry (write-time conflict
|
|
62
|
-
* guard, warn tier): `<kind>:<id>:<score>` — points at the entry it may
|
|
63
|
-
* duplicate so wrapup/fate can consolidate later. Creates at/above the block
|
|
64
|
-
* threshold never reach this stamp; they are rejected outright.
|
|
65
|
-
*/
|
|
66
|
-
export const CONFLICT_HINT_KEY = "conflictHint";
|
|
67
|
-
/**
|
|
68
|
-
* Negative-valence counter (P1 效价反馈): how many times an assessment marked
|
|
69
|
-
* this entry contradicted by newer evidence (user correction, overridden
|
|
70
|
-
* fact). Injection ranking demotes entries with a positive counter and the
|
|
71
|
-
* wrapup/fate assessors see the count so they prefer archiving the entry.
|
|
72
|
-
*/
|
|
73
|
-
export const VALENCE_NEGATIVE_KEY = "valenceNegative";
|
|
74
|
-
/**
|
|
75
|
-
* Provenance of entries merged INTO this one by the consolidation command
|
|
76
|
-
* (P1 反膨胀): array of `<kind>:<id>` — the near-duplicate sources whose
|
|
77
|
-
* content was appended before they archived. The trail keeps an unarchive of
|
|
78
|
-
* the source explainable and lets audits find the merge provenance.
|
|
79
|
-
*/
|
|
80
|
-
export const MERGED_FROM_KEY = "mergedFrom";
|
|
81
|
-
/**
|
|
82
|
-
* True when the entry is archived (hidden from injection, restorable).
|
|
83
|
-
* Absent or empty archivedAt means the entry is active.
|
|
84
|
-
*/
|
|
85
|
-
export function isArchived(entry) {
|
|
86
|
-
const value = entry.metadata[ARCHIVED_AT_KEY];
|
|
87
|
-
return typeof value === "string" && value.length > 0;
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* A stable id derived from a title: ASCII runs become snake_case (unchanged
|
|
91
|
-
* legacy behavior). Titles with no ASCII content at all (e.g. pure Chinese)
|
|
92
|
-
* used to collapse onto the bare fallback, so distinct memories shared one
|
|
93
|
-
* id and every later create failed as "already exists". They now take
|
|
94
|
-
* `<fallback>_<sha256-8>` instead: distinct titles get distinct ids while
|
|
95
|
-
* identical titles still dedupe onto the same id. The fallback itself is
|
|
96
|
-
* assumed id-safe (callers pass entry kinds).
|
|
97
|
-
*/
|
|
98
|
-
export function slug(raw, fallback) {
|
|
99
|
-
const normalized = raw
|
|
100
|
-
.trim()
|
|
101
|
-
.toLowerCase()
|
|
102
|
-
.replace(/[^a-z0-9]+/g, "_")
|
|
103
|
-
.replace(/^_+|_+$/g, "")
|
|
104
|
-
.slice(0, 80);
|
|
105
|
-
if (normalized)
|
|
106
|
-
return normalized;
|
|
107
|
-
const digest = createHash("sha256").update(raw, "utf8").digest("hex").slice(0, 8);
|
|
108
|
-
return `${fallback}_${digest}`;
|
|
109
|
-
}
|
|
110
|
-
/** Fresh empty state with the current schema version. */
|
|
111
|
-
export function emptyHarnessState() {
|
|
112
|
-
return {
|
|
113
|
-
schema: 1,
|
|
114
|
-
entries: {
|
|
115
|
-
prompt: {},
|
|
116
|
-
memory: {},
|
|
117
|
-
skill: {},
|
|
118
|
-
subagent: {},
|
|
119
|
-
},
|
|
120
|
-
refinements: [],
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
/** Deep clone helper (state is plain JSON data). */
|
|
124
|
-
export function cloneEntry(entry) {
|
|
125
|
-
return entry ? JSON.parse(JSON.stringify(entry)) : undefined;
|
|
126
|
-
}
|
|
127
|
-
//# sourceMappingURL=types.js.map
|
package/lib/usage.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { RefinementKind } from "./types.js";
|
|
2
|
-
export interface UsageStore {
|
|
3
|
-
/** Injection count per entry key (`kind:id`). */
|
|
4
|
-
counts: Record<string, number>;
|
|
5
|
-
/** Session dedup marker: the last session id each key was counted in (v2). */
|
|
6
|
-
lastSession?: Record<string, string>;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Load the usage store from disk; returns an empty store when absent or
|
|
10
|
-
* corrupt. Accepts BOTH on-disk shapes:
|
|
11
|
-
* - legacy (≤0.3.x): a flat `{ "kind:id": count }` map,
|
|
12
|
-
* - v2: `{ version: 2, counts, lastSession }` with per-session dedup.
|
|
13
|
-
*/
|
|
14
|
-
export declare function loadUsage(baseDir: string): UsageStore;
|
|
15
|
-
/** Persist the usage store atomically (always the v2 shape). */
|
|
16
|
-
export declare function saveUsage(baseDir: string, store: UsageStore): void;
|
|
17
|
-
/** Build the usage key for an entry. */
|
|
18
|
-
export declare function usageKey(kind: RefinementKind, id: string): string;
|
|
19
|
-
/**
|
|
20
|
-
* Increment injection counts for the entries that were actually injected.
|
|
21
|
-
* Called after `entriesSectionText` renders the injected block. Keys not
|
|
22
|
-
* present in the store are initialized to 1.
|
|
23
|
-
*
|
|
24
|
-
* Session dedup (2026-08-22): with a sessionId, each key counts AT MOST
|
|
25
|
-
* ONCE per session — the old per-build counting produced meaningless
|
|
26
|
-
* numbers (one entry hit 2311× in a week) and hid the real "how many
|
|
27
|
-
* sessions found this useful" signal that staleness decay needs. Without
|
|
28
|
-
* a sessionId the call degrades to legacy always-increment behavior.
|
|
29
|
-
*/
|
|
30
|
-
export declare function recordInjection(baseDir: string, injectedKeys: readonly string[], sessionId?: string): void;
|
|
31
|
-
/**
|
|
32
|
-
* Get the injection count for a specific entry. Returns 0 when the entry
|
|
33
|
-
* has never been injected (absent from the store).
|
|
34
|
-
*/
|
|
35
|
-
export declare function getUsageCount(store: UsageStore, kind: RefinementKind, id: string): number;
|
|
36
|
-
//# sourceMappingURL=usage.d.ts.map
|