dsh-continual-evolve 0.11.0 → 0.12.1
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 +42 -115
- package/README.zh.md +33 -93
- package/client/client.js +253 -0
- package/cordis.patch.yml +2 -2
- package/lib/card-routes.d.ts +32 -0
- package/lib/card-routes.js +92 -0
- package/lib/index.d.ts +65 -217
- package/lib/index.js +74 -234
- package/lib/known-workspaces.d.ts +22 -0
- package/lib/known-workspaces.js +42 -0
- package/lib/memory-guide.d.ts +13 -14
- package/lib/memory-guide.js +34 -21
- package/lib/memory-section.d.ts +77 -0
- package/lib/memory-section.js +189 -0
- package/lib/memory-snapshot.d.ts +54 -0
- package/lib/memory-snapshot.js +125 -0
- package/package.json +8 -17
- package/lib/apply.d.ts +0 -22
- package/lib/apply.js +0 -157
- package/lib/approval.d.ts +0 -73
- package/lib/approval.js +0 -127
- package/lib/audit-log.d.ts +0 -19
- package/lib/audit-log.js +0 -52
- 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-util.d.ts +0 -70
- package/lib/command-util.js +0 -123
- package/lib/command.d.ts +0 -13
- package/lib/command.js +0 -134
- package/lib/consolidate.d.ts +0 -90
- package/lib/consolidate.js +0 -180
- package/lib/copy.d.ts +0 -37
- package/lib/copy.js +0 -58
- package/lib/declines.d.ts +0 -103
- package/lib/declines.js +0 -179
- 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 -60
- package/lib/extraction-phase.d.ts +0 -132
- package/lib/extraction-phase.js +0 -236
- 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 -90
- package/lib/inject.js +0 -164
- package/lib/injection-caps.d.ts +0 -4
- package/lib/injection-caps.js +0 -4
- package/lib/injection-directory.d.ts +0 -29
- package/lib/injection-directory.js +0 -78
- package/lib/injection-rank.d.ts +0 -85
- package/lib/injection-rank.js +0 -161
- package/lib/listener.d.ts +0 -45
- package/lib/listener.js +0 -199
- 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/maintenance-commands.d.ts +0 -23
- package/lib/maintenance-commands.js +0 -136
- package/lib/memory-agent.d.ts +0 -93
- package/lib/memory-agent.js +0 -300
- package/lib/memory-apply.d.ts +0 -44
- package/lib/memory-apply.js +0 -202
- 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/memory-manifest.d.ts +0 -16
- package/lib/memory-manifest.js +0 -70
- 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 -48
- package/lib/notify.js +0 -57
- package/lib/plan-command.d.ts +0 -12
- package/lib/plan-command.js +0 -38
- 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 -79
- 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 -183
- 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-commands.d.ts +0 -14
- package/lib/runtime-commands.js +0 -115
- 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 -63
- package/lib/service.js +0 -253
- 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 -61
- 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 -78
- package/lib/turn-snapshot.js +0 -252
- package/lib/types.d.ts +0 -218
- package/lib/types.js +0 -133
- 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-candidates.d.ts +0 -127
- package/lib/wrapup-candidates.js +0 -161
- package/lib/wrapup-command.d.ts +0 -10
- package/lib/wrapup-command.js +0 -243
- package/lib/wrapup-proposals.d.ts +0 -101
- package/lib/wrapup-proposals.js +0 -281
- package/lib/wrapup.d.ts +0 -56
- package/lib/wrapup.js +0 -105
package/lib/fate.js
DELETED
|
@@ -1,350 +0,0 @@
|
|
|
1
|
-
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
2
|
-
import { EVOLVE_MESSAGE_SOURCE } from "./message-source.js";
|
|
3
|
-
import { DEFAULT_PROMOTION_POLICY } from "./promotion.js";
|
|
4
|
-
import { questionServiceOf } from "./approval.js";
|
|
5
|
-
import { fateConsultCopy, resolveDialogLanguage } from "./copy.js";
|
|
6
|
-
import { resolveRecordLanguage } from "./record-language.js";
|
|
7
|
-
import { assessLocalEntries, candidateKey, filterPromotable, listLocalCandidates, splitArchiveGuards, splitPromoteBlocked, splitPromoteProposals, wholePromoteProposals, } from "./wrapup.js";
|
|
8
|
-
/** Turns a declined local-fate proposal stays silent before being offered again. */
|
|
9
|
-
export const FATE_CONSULT_COOLDOWN_TURNS = 10;
|
|
10
|
-
/**
|
|
11
|
-
* Partition an assessed wrap-up classification into concrete fate actions,
|
|
12
|
-
* re-running the deterministic guards against the LIVE global store (state
|
|
13
|
-
* may have changed while the LLM call was in flight). Pure and unit-tested;
|
|
14
|
-
* mirrors the partition step of the wrap-up command.
|
|
15
|
-
*/
|
|
16
|
-
export function planLocalFates(items, candidates, globalState, policy = DEFAULT_PROMOTION_POLICY) {
|
|
17
|
-
const byKey = new Map(candidates.map((candidate) => [candidateKey(candidate.kind, candidate.id), candidate]));
|
|
18
|
-
const { promotable, skipped } = filterPromotable(items, globalState, candidates, policy);
|
|
19
|
-
const promoteItems = promotable.filter((item) => item.verdict === "promote");
|
|
20
|
-
const archiveItems = items.filter((item) => item.verdict === "archive");
|
|
21
|
-
const splits = [];
|
|
22
|
-
const splitSkipped = [];
|
|
23
|
-
for (const item of archiveItems) {
|
|
24
|
-
if (!item.promote)
|
|
25
|
-
continue;
|
|
26
|
-
const candidate = byKey.get(item.key);
|
|
27
|
-
if (!candidate) {
|
|
28
|
-
splitSkipped.push({ key: item.key, reason: "not in the audited candidate list" });
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
const blocked = splitPromoteBlocked(item, globalState, candidate.kind, policy, candidate.metadata);
|
|
32
|
-
if (blocked) {
|
|
33
|
-
splitSkipped.push({ key: item.key, reason: blocked });
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
splits.push({ item, candidate });
|
|
37
|
-
}
|
|
38
|
-
const plainArchives = archiveItems.filter((item) => !item.promote);
|
|
39
|
-
const { silent: silentArchives, review: reviewArchives } = splitArchiveGuards(plainArchives, candidates);
|
|
40
|
-
return { candidates, promotable: promoteItems, splits, silentArchives, reviewArchives, skipped, splitSkipped };
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* The cooldown key of a candidate set: the sorted `kind:id` list. The set is
|
|
44
|
-
* the unit of consultation — a declined proposal is not offered again within
|
|
45
|
-
* the cooldown window, and a changed set (new entries appeared) starts a
|
|
46
|
-
* fresh consultation.
|
|
47
|
-
*/
|
|
48
|
-
export function fateSetKey(candidates) {
|
|
49
|
-
return candidates
|
|
50
|
-
.map((candidate) => candidateKey(candidate.kind, candidate.id))
|
|
51
|
-
.sort()
|
|
52
|
-
.join("|");
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Whether the local-fate dimension is due for this gate run. Turn-interval
|
|
56
|
-
* gates respect the fate cadence (an independent counter — goal-driven
|
|
57
|
-
* sessions run the review EVERY round, the fate assessment must not);
|
|
58
|
-
* compaction is unconditional: experiences about to be summarized away get
|
|
59
|
-
* their fate check regardless. Goal-blocked assessments are unconditional
|
|
60
|
-
* here too — the gate's own streak counter (auto.ts runGoalBlockedFate)
|
|
61
|
-
* already gates their frequency, so the cadence must not re-block them.
|
|
62
|
-
*/
|
|
63
|
-
export function fateCadenceDue(state, reason, intervalTurns) {
|
|
64
|
-
// Compact and goal-blocked assessments bypass the cadence (see header).
|
|
65
|
-
if (reason === "compact" || reason === "goal_blocked")
|
|
66
|
-
return true;
|
|
67
|
-
return state.turns - state.lastFateAt >= intervalTurns;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Ask the user whether to execute the gate's local-fate proposal. ONE dialog
|
|
71
|
-
* covers every governed action (promotes, split promotions, review-required
|
|
72
|
-
* archives) — the gate never spams questions. Conservative on every edge:
|
|
73
|
-
* no question service → not approved; the question call fails → not approved;
|
|
74
|
-
* the same candidate set was declined within the cooldown → not asked again.
|
|
75
|
-
* A decline records the cooldown (the consultSkillEdits pattern).
|
|
76
|
-
*/
|
|
77
|
-
export async function consultLocalFates(ctx, agent, plan, gate, language) {
|
|
78
|
-
const needsDialog = plan.promotable.length + plan.splits.length + plan.reviewArchives.length > 0;
|
|
79
|
-
if (!needsDialog) {
|
|
80
|
-
return { approved: true, asked: false, reason: "nothing-to-ask" };
|
|
81
|
-
}
|
|
82
|
-
const setKey = fateSetKey(plan.candidates);
|
|
83
|
-
const lastReject = gate.fateRejects.get(setKey);
|
|
84
|
-
if (lastReject !== undefined && gate.turns - lastReject < FATE_CONSULT_COOLDOWN_TURNS) {
|
|
85
|
-
return { approved: false, asked: false, reason: "cooldown" };
|
|
86
|
-
}
|
|
87
|
-
const userQuestions = questionServiceOf(ctx);
|
|
88
|
-
if (!userQuestions) {
|
|
89
|
-
return { approved: false, asked: false, reason: "unavailable" };
|
|
90
|
-
}
|
|
91
|
-
const lang = language ?? resolveDialogLanguage(ctx);
|
|
92
|
-
try {
|
|
93
|
-
const copy = fateConsultCopy(sectionsOf(plan, lang), lang);
|
|
94
|
-
const answer = await userQuestions.ask({
|
|
95
|
-
questions: [
|
|
96
|
-
{
|
|
97
|
-
id: "evolve-fate-consult",
|
|
98
|
-
question: copy.question,
|
|
99
|
-
options: copy.options,
|
|
100
|
-
},
|
|
101
|
-
],
|
|
102
|
-
agent,
|
|
103
|
-
});
|
|
104
|
-
const selected = answer.answers?.find((entry) => entry.id === "evolve-fate-consult")?.selected ?? [];
|
|
105
|
-
const approved = selected.includes("执行") || selected.includes("Proceed");
|
|
106
|
-
if (!approved) {
|
|
107
|
-
gate.fateRejects.set(setKey, gate.turns);
|
|
108
|
-
}
|
|
109
|
-
return { approved, asked: true, reason: approved ? "consented" : "declined" };
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
return { approved: false, asked: true, reason: "error" };
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
/** Split a fate plan into pre-rendered per-group lines for the dialog copy. */
|
|
116
|
-
function sectionsOf(plan, lang) {
|
|
117
|
-
const byKey = new Map(plan.candidates.map((candidate) => [candidateKey(candidate.kind, candidate.id), candidate]));
|
|
118
|
-
const promotable = [];
|
|
119
|
-
const splits = [];
|
|
120
|
-
const reviewArchives = [];
|
|
121
|
-
for (const item of plan.promotable) {
|
|
122
|
-
promotable.push(`- ${item.key}「${byKey.get(item.key)?.title ?? item.key}」 — ${item.reason}`);
|
|
123
|
-
}
|
|
124
|
-
for (const { item } of plan.splits) {
|
|
125
|
-
splits.push(lang === "zh"
|
|
126
|
-
? `- ${item.key} → 拆出提升「${item.promote?.title}」(原条目随之归档)`
|
|
127
|
-
: `- ${item.key} → split-promote "${item.promote?.title}" (original archived alongside)`);
|
|
128
|
-
}
|
|
129
|
-
for (const item of plan.reviewArchives) {
|
|
130
|
-
reviewArchives.push(`- ${item.key}「${byKey.get(item.key)?.title ?? item.key}」 — ${item.reason}`);
|
|
131
|
-
}
|
|
132
|
-
return { promotable, splits, reviewArchives };
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Deterministically apply the fate plan. `"full"` applies everything
|
|
136
|
-
* (promotes, splits, silent + review archives); `"silent-only"` applies only
|
|
137
|
-
* the deterministic silent archives (the compaction path — nothing governed).
|
|
138
|
-
* Promotes go through the SAME proposals as the wrap-up command
|
|
139
|
-
* (wholePromoteProposals / splitPromoteProposals), so both paths write
|
|
140
|
-
* identical global entries and local retirement stamps.
|
|
141
|
-
*/
|
|
142
|
-
export function applyLocalFates(engine, sessionId, plan, localState, mode) {
|
|
143
|
-
const applied = [];
|
|
144
|
-
const results = [];
|
|
145
|
-
const byKey = new Map(plan.candidates.map((candidate) => [candidateKey(candidate.kind, candidate.id), candidate]));
|
|
146
|
-
if (mode === "full") {
|
|
147
|
-
for (const item of plan.promotable) {
|
|
148
|
-
const candidate = byKey.get(item.key);
|
|
149
|
-
if (!candidate)
|
|
150
|
-
continue;
|
|
151
|
-
const proposals = wholePromoteProposals(item, candidate, sessionId);
|
|
152
|
-
const globalResult = engine.apply("global", undefined, proposals.global, { scope: "global" });
|
|
153
|
-
const createdId = globalResult.appliedEdits.find((edit) => edit.applied)?.id ?? candidate.id;
|
|
154
|
-
const localResult = engine.apply("local", sessionId, proposals.localStamp(createdId), {
|
|
155
|
-
scope: "local",
|
|
156
|
-
baselineState: localState,
|
|
157
|
-
});
|
|
158
|
-
results.push(globalResult, localResult);
|
|
159
|
-
applied.push(`提升 ${item.key} → 全局 store(global:${createdId},本地副本已归档)`);
|
|
160
|
-
}
|
|
161
|
-
for (const { item, candidate } of plan.splits) {
|
|
162
|
-
if (!item.promote)
|
|
163
|
-
continue;
|
|
164
|
-
const proposals = splitPromoteProposals(item, candidate, sessionId);
|
|
165
|
-
const globalResult = engine.apply("global", undefined, proposals.global, { scope: "global" });
|
|
166
|
-
const createdId = globalResult.appliedEdits.find((edit) => edit.applied)?.id ?? candidate.id;
|
|
167
|
-
const localResult = engine.apply("local", sessionId, proposals.localStamp(createdId), {
|
|
168
|
-
scope: "local",
|
|
169
|
-
baselineState: localState,
|
|
170
|
-
});
|
|
171
|
-
results.push(globalResult, localResult);
|
|
172
|
-
applied.push(`拆解 ${item.key} → 清洗「${item.promote.title}」入全局(原条目已归档)`);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
const archives = mode === "full" ? [...plan.silentArchives, ...plan.reviewArchives] : plan.silentArchives;
|
|
176
|
-
for (const item of archives) {
|
|
177
|
-
const candidate = byKey.get(item.key);
|
|
178
|
-
if (!candidate)
|
|
179
|
-
continue;
|
|
180
|
-
const proposal = {
|
|
181
|
-
summary: `gate fate: archive local ${item.key} — ${item.reason}`,
|
|
182
|
-
rationale: item.reason,
|
|
183
|
-
expectedOutcome: "The entry stops being injected but stays restorable.",
|
|
184
|
-
edits: [{ action: "archive", kind: candidate.kind, id: candidate.id }],
|
|
185
|
-
};
|
|
186
|
-
const result = engine.apply("local", sessionId, proposal, { scope: "local", baselineState: localState });
|
|
187
|
-
results.push(result);
|
|
188
|
-
applied.push(`归档 ${item.key}「${candidate.title}」`);
|
|
189
|
-
}
|
|
190
|
-
return { applied, results };
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* The gate's local-fate phase. Runs after the review phase on every gate
|
|
194
|
-
* trigger (turn_snapshot / compact), subject to cadence and cooldown. All
|
|
195
|
-
* failures are contained and recorded — a broken fate dimension never
|
|
196
|
-
* disturbs the agent loop.
|
|
197
|
-
*/
|
|
198
|
-
export async function runLocalFatePhase(ctx, engine, agent, config, state, reason, record) {
|
|
199
|
-
if (!config.localFate)
|
|
200
|
-
return;
|
|
201
|
-
const logger = ctx.logger("continual-evolve");
|
|
202
|
-
const sessionId = agent.id;
|
|
203
|
-
const tokenUsage = {
|
|
204
|
-
baseDir: engine.baseDir,
|
|
205
|
-
sessionId,
|
|
206
|
-
retain: engine.retention.tokenUsage,
|
|
207
|
-
onError: (cause) => logger.warn(`token-usage ledger failed for ${sessionId}: ${cause instanceof Error ? cause.message : String(cause)}`),
|
|
208
|
-
};
|
|
209
|
-
const localState = engine.load("local", sessionId);
|
|
210
|
-
const globalState = engine.load("global", undefined);
|
|
211
|
-
const candidates = listLocalCandidates(localState, globalState, engine.baseDir);
|
|
212
|
-
if (candidates.length === 0)
|
|
213
|
-
return;
|
|
214
|
-
if (!fateCadenceDue(state, reason, config.fateIntervalTurns))
|
|
215
|
-
return;
|
|
216
|
-
const setKey = fateSetKey(candidates);
|
|
217
|
-
const lastReject = state.fateRejects.get(setKey);
|
|
218
|
-
if (lastReject !== undefined && state.turns - lastReject < FATE_CONSULT_COOLDOWN_TURNS) {
|
|
219
|
-
logger.info(`auto-review local-fate skipped [${sessionId}]: candidate set declined ${state.turns - lastReject} turns ago (cooldown)`);
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
const turnsSinceFate = state.turns - state.lastFateAt;
|
|
223
|
-
state.lastFateAt = state.turns;
|
|
224
|
-
let assessment;
|
|
225
|
-
const fateLanguage = resolveRecordLanguage({ configured: config.recordLanguage, ctx });
|
|
226
|
-
try {
|
|
227
|
-
assessment = await assessLocalEntries(ctx, agent, candidates, { tokenUsage, tokenUsagePhase: "fate", language: fateLanguage });
|
|
228
|
-
}
|
|
229
|
-
catch (cause) {
|
|
230
|
-
const message = cause instanceof Error ? cause.message : String(cause);
|
|
231
|
-
logger.warn(`auto-review local-fate failed for ${sessionId}: ${message}`);
|
|
232
|
-
record({
|
|
233
|
-
sessionId,
|
|
234
|
-
reason,
|
|
235
|
-
turnsSinceLastReview: turnsSinceFate,
|
|
236
|
-
outcome: "failed",
|
|
237
|
-
rationale: `fate assessment error: ${message}`,
|
|
238
|
-
});
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
const plan = planLocalFates(assessment.items, candidates, globalState, config.promotionPolicy);
|
|
242
|
-
const needsDialog = plan.promotable.length + plan.splits.length + plan.reviewArchives.length > 0;
|
|
243
|
-
let consent = { approved: false, asked: false, reason: "nothing-to-ask" };
|
|
244
|
-
// Turn-path tightening (2026-09-25): turn_snapshot/turn_interval never open
|
|
245
|
-
// a dialog — governed actions are deferred to `/evolve wrapup`. Only an
|
|
246
|
-
// explicit goal_blocked signal (own streak counter) may consult.
|
|
247
|
-
if (reason === "goal_blocked" && needsDialog) {
|
|
248
|
-
consent = await consultLocalFates(ctx, agent, plan, state, fateLanguage);
|
|
249
|
-
}
|
|
250
|
-
if (consent.approved) {
|
|
251
|
-
const { applied, results } = applyLocalFates(engine, sessionId, plan, localState, "full");
|
|
252
|
-
logger.info(`auto-review local-fate approved (${reason}) [${sessionId}]: ${plan.promotable.length} promoted, ${plan.splits.length} split, ${plan.reviewArchives.length} review-archived, ${plan.silentArchives.length} silent-archived — ${assessment.rationale}`);
|
|
253
|
-
record({
|
|
254
|
-
sessionId,
|
|
255
|
-
reason,
|
|
256
|
-
turnsSinceLastReview: turnsSinceFate,
|
|
257
|
-
outcome: "approved",
|
|
258
|
-
rationale: `fate: ${assessment.rationale} (${applied.join("; ")})`,
|
|
259
|
-
refinementId: results.map((result) => result.id).join(","),
|
|
260
|
-
});
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
if (consent.reason === "declined" || consent.reason === "unavailable" || consent.reason === "error") {
|
|
264
|
-
const withheld = consent.reason;
|
|
265
|
-
const outcome = withheld === "declined" ? "declined" : "deferred";
|
|
266
|
-
logger.info(`auto-review local-fate ${outcome} (${reason}) [${sessionId}]: ${plan.promotable.length} promotes, ${plan.splits.length} splits, ${plan.reviewArchives.length} review-archives withheld — ${assessment.rationale}`);
|
|
267
|
-
record({
|
|
268
|
-
sessionId,
|
|
269
|
-
reason,
|
|
270
|
-
turnsSinceLastReview: turnsSinceFate,
|
|
271
|
-
outcome,
|
|
272
|
-
rationale: `fate ${withheld}: ${assessment.rationale} (${plan.promotable.length} promotes, ${plan.splits.length} splits, ${plan.reviewArchives.length} review-archives withheld)`,
|
|
273
|
-
});
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
if (needsDialog && reason !== "goal_blocked") {
|
|
277
|
-
// Turn/compact path: no dialog. Only deterministic silent archives apply;
|
|
278
|
-
// governed actions are deferred with an audit record pointing at wrapup.
|
|
279
|
-
const { applied, results } = applyLocalFates(engine, sessionId, plan, localState, "silent-only");
|
|
280
|
-
if (applied.length > 0) {
|
|
281
|
-
logger.info(`auto-review local-fate (${reason}) [${sessionId}]: silent-archived ${applied.length} — ${assessment.rationale}`);
|
|
282
|
-
record({
|
|
283
|
-
sessionId,
|
|
284
|
-
reason,
|
|
285
|
-
turnsSinceLastReview: turnsSinceFate,
|
|
286
|
-
outcome: "approved",
|
|
287
|
-
rationale: `fate (${reason}): ${assessment.rationale} (${applied.join("; ")})`,
|
|
288
|
-
refinementId: results.map((result) => result.id).join(","),
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
record({
|
|
292
|
-
sessionId,
|
|
293
|
-
reason,
|
|
294
|
-
turnsSinceLastReview: turnsSinceFate,
|
|
295
|
-
outcome: "deferred",
|
|
296
|
-
rationale: `fate (${reason}): ${plan.promotable.length} promotes, ${plan.splits.length} splits, ${plan.reviewArchives.length} review-archives deferred — run /evolve wrapup for a full session exit`,
|
|
297
|
-
});
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
// Silent archives on a plain turn-interval gate with nothing to ask.
|
|
301
|
-
if (plan.silentArchives.length > 0) {
|
|
302
|
-
const { applied, results } = applyLocalFates(engine, sessionId, plan, localState, "silent-only");
|
|
303
|
-
logger.info(`auto-review local-fate (${reason}) [${sessionId}]: silent-archived ${applied.length} covered/operational entries — ${assessment.rationale}`);
|
|
304
|
-
record({
|
|
305
|
-
sessionId,
|
|
306
|
-
reason,
|
|
307
|
-
turnsSinceLastReview: turnsSinceFate,
|
|
308
|
-
outcome: "approved",
|
|
309
|
-
rationale: `fate: ${assessment.rationale} (${applied.join("; ")})`,
|
|
310
|
-
refinementId: results.map((result) => result.id).join(","),
|
|
311
|
-
});
|
|
312
|
-
if (config.notifyOnAutoReview && (reason === "turn_snapshot" || reason === "turn_interval")) {
|
|
313
|
-
notifyFateApplied(ctx, agent, applied);
|
|
314
|
-
}
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
// Assessed, nothing to do.
|
|
318
|
-
logger.info(`auto-review local-fate assessed (${reason}) [${sessionId}]: ${candidates.length} candidates, no action — ${assessment.rationale}`);
|
|
319
|
-
record({
|
|
320
|
-
sessionId,
|
|
321
|
-
reason,
|
|
322
|
-
turnsSinceLastReview: turnsSinceFate,
|
|
323
|
-
outcome: "assessed",
|
|
324
|
-
rationale: `fate: ${assessment.rationale} (${candidates.length} candidates, no action)`,
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
/** The user-visible notice after the gate applied local-fate actions. */
|
|
328
|
-
export function buildFateNotice(applied) {
|
|
329
|
-
return [
|
|
330
|
-
"🔎 自动进化门禁:本会话 local 条目归宿处理完成:",
|
|
331
|
-
applied.map((line) => `- ${line}`).join("\n"),
|
|
332
|
-
"查看全部条目:/evolve list;撤销:/evolve rollback <refinement id>",
|
|
333
|
-
"请用一句话简短确认即可,不要调用任何工具。",
|
|
334
|
-
].join("\n");
|
|
335
|
-
}
|
|
336
|
-
/** Queue the follow-up notice turn (successful-turn path only). */
|
|
337
|
-
function notifyFateApplied(ctx, agent, applied) {
|
|
338
|
-
try {
|
|
339
|
-
agent.followup(createUserMessage({
|
|
340
|
-
content: [{ type: "text", text: buildFateNotice(applied) }],
|
|
341
|
-
source: EVOLVE_MESSAGE_SOURCE,
|
|
342
|
-
}));
|
|
343
|
-
}
|
|
344
|
-
catch (cause) {
|
|
345
|
-
ctx
|
|
346
|
-
.logger("continual-evolve")
|
|
347
|
-
.warn(`local-fate notice failed for ${agent.id}: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
//# sourceMappingURL=fate.js.map
|
package/lib/goal-command.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The `/evolve goal` subcommand handler. Extracted from command.ts (P2-2).
|
|
3
|
-
*/
|
|
4
|
-
import type { Context } from "@deepseek-ai/cordis";
|
|
5
|
-
import type { CommandInvocation, CommandResult } from "@deepseek-ai/dsh-commands";
|
|
6
|
-
export declare function executeGoalCommand(ctx: Context, invocation: CommandInvocation, rest: string[]): CommandResult;
|
|
7
|
-
//# sourceMappingURL=goal-command.d.ts.map
|
package/lib/goal-command.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { blockEvolutionGoal, completeEvolutionGoal, goalServiceOf, goalStatusText, upsertEvolutionGoal } from "./goal.js";
|
|
2
|
-
function success(text) {
|
|
3
|
-
return { kind: "success", text };
|
|
4
|
-
}
|
|
5
|
-
function error(text) {
|
|
6
|
-
return { kind: "error", text };
|
|
7
|
-
}
|
|
8
|
-
export function executeGoalCommand(ctx, invocation, rest) {
|
|
9
|
-
const agent = invocation.agent;
|
|
10
|
-
const goals = goalServiceOf(ctx);
|
|
11
|
-
if (!goals) {
|
|
12
|
-
return error(`/evolve goal requires the goals service (load @deepseek-ai/dsh-goal)`);
|
|
13
|
-
}
|
|
14
|
-
const sub = rest[0] ?? "";
|
|
15
|
-
try {
|
|
16
|
-
if (sub === "done") {
|
|
17
|
-
const view = completeEvolutionGoal(ctx, agent);
|
|
18
|
-
return view ? success(`evolution goal completed: ${goalStatusText(view)}`) : success("(no goal to complete)");
|
|
19
|
-
}
|
|
20
|
-
if (sub === "block") {
|
|
21
|
-
const reason = rest.slice(1).join(" ") || "user requested block";
|
|
22
|
-
const view = blockEvolutionGoal(ctx, agent, reason);
|
|
23
|
-
return view ? success(`evolution goal blocked: ${goalStatusText(view)}`) : success("(no active goal to block)");
|
|
24
|
-
}
|
|
25
|
-
if (sub.length === 0) {
|
|
26
|
-
const current = goals.get(agent);
|
|
27
|
-
return current ? success(goalStatusText(current)) : success("(no evolution goal — /evolve goal <objective> to create one)");
|
|
28
|
-
}
|
|
29
|
-
const objective = rest.join(" ");
|
|
30
|
-
const view = upsertEvolutionGoal(ctx, agent, objective);
|
|
31
|
-
return success(`evolution goal ready: ${goalStatusText(view)}\n(active goal drives the review gate every round)`);
|
|
32
|
-
}
|
|
33
|
-
catch (cause) {
|
|
34
|
-
return error(cause instanceof Error ? cause.message : String(cause));
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=goal-command.js.map
|
package/lib/goal.d.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Goal-driven evolution rounds (v3 optional item, design.md §6): a
|
|
3
|
-
* same-session goal turns the auto-review into a per-round driver — while a
|
|
4
|
-
* goal is active, the review gate runs every round instead of every
|
|
5
|
-
* `reviewIntervalTurns`, so the "continual evolution loop" is driven by the
|
|
6
|
-
* goal's round machine (goal-round-driver keeps the session continuing) and
|
|
7
|
-
* stops when the goal is completed or blocked.
|
|
8
|
-
*
|
|
9
|
-
* The goal service (`ctx.goals`) is resolved lazily and never required
|
|
10
|
-
* (FAQ #1 discipline): without it, `/evolve goal` reports the feature
|
|
11
|
-
* unavailable and auto-review keeps its plain interval.
|
|
12
|
-
*/
|
|
13
|
-
import type { Context } from "@deepseek-ai/cordis";
|
|
14
|
-
import type { Agent } from "@deepseek-ai/dsh-agent";
|
|
15
|
-
/** The durable goal phases we drive on. */
|
|
16
|
-
export type GoalPhase = "active" | "paused" | "blocked" | "complete";
|
|
17
|
-
/** Minimal structural view of a goal view (duck-typed against dsh-goal). */
|
|
18
|
-
export interface GoalViewLike {
|
|
19
|
-
readonly id: string;
|
|
20
|
-
readonly revision: number;
|
|
21
|
-
readonly objective: string;
|
|
22
|
-
readonly phase: GoalPhase;
|
|
23
|
-
readonly maxGoalRounds: number;
|
|
24
|
-
}
|
|
25
|
-
export interface GoalRefLike {
|
|
26
|
-
readonly id: string;
|
|
27
|
-
readonly revision: number;
|
|
28
|
-
}
|
|
29
|
-
export interface GoalServiceLike {
|
|
30
|
-
get(agent: Agent): GoalViewLike | undefined;
|
|
31
|
-
create(agent: Agent, request: {
|
|
32
|
-
objective: string;
|
|
33
|
-
maxGoalRounds?: number;
|
|
34
|
-
}): GoalViewLike;
|
|
35
|
-
edit(agent: Agent, ref: GoalRefLike, request: {
|
|
36
|
-
objective?: string;
|
|
37
|
-
maxGoalRounds?: number;
|
|
38
|
-
}): GoalViewLike;
|
|
39
|
-
complete(agent: Agent, ref: GoalRefLike): GoalViewLike;
|
|
40
|
-
block?(agent: Agent, ref: GoalRefLike, reason: {
|
|
41
|
-
code: string;
|
|
42
|
-
reason: string;
|
|
43
|
-
}): GoalViewLike;
|
|
44
|
-
}
|
|
45
|
-
/** The default objective used by `/evolve goal` without an explicit one. */
|
|
46
|
-
export declare const DEFAULT_EVOLVE_GOAL_OBJECTIVE = "\u6301\u7EED\u8FDB\u5316\u672C\u4F1A\u8BDD harness \u72B6\u6001\uFF1A\u6BCF\u8F6E\u6C89\u6DC0\u53EF\u590D\u7528\u7ECF\u9A8C\uFF08\u5931\u8D25/\u6218\u672F/\u4E8B\u5B9E/\u59D4\u6D3E\u89C4\u683C\uFF09\uFF0C\u4FDD\u6301\u6761\u76EE\u5C0F\u800C\u5E26\u8BC1\u636E";
|
|
47
|
-
/**
|
|
48
|
-
* Resolve the goal service lazily; undefined when the profile lacks it.
|
|
49
|
-
* Uses `ctx.get("goals")` (the global service registry) — a direct property
|
|
50
|
-
* access like `ctx.goals` walks only the caller's fiber ancestor chain and
|
|
51
|
-
* throws "cannot get property \"goals\" without inject" for services
|
|
52
|
-
* provided by sibling plugin entries (the goal plugin is a sibling of this
|
|
53
|
-
* one in the profile tree).
|
|
54
|
-
*/
|
|
55
|
-
export declare function goalServiceOf(ctx: Context): GoalServiceLike | undefined;
|
|
56
|
-
/** True when a goal view exists and is in a round-driving phase (active). */
|
|
57
|
-
export declare function goalDrivesRounds(view: GoalViewLike | undefined): boolean;
|
|
58
|
-
/** True when a goal exists at all (any phase) — used to gate create vs edit. */
|
|
59
|
-
export declare function goalExists(view: GoalViewLike | undefined): view is GoalViewLike;
|
|
60
|
-
/** Human-readable one-line status for a goal view. */
|
|
61
|
-
export declare function goalStatusText(view: GoalViewLike): string;
|
|
62
|
-
/**
|
|
63
|
-
* Create or edit the session's evolution goal. With no current goal: create.
|
|
64
|
-
* With a current goal: edit its objective (create-on-first-use semantics are
|
|
65
|
-
* enforced by the goal service itself; completed goals may be replaced).
|
|
66
|
-
*/
|
|
67
|
-
export declare function upsertEvolutionGoal(ctx: Context, agent: Agent, objective?: string): GoalViewLike;
|
|
68
|
-
/** Complete the current goal, returning the completed view or undefined. */
|
|
69
|
-
export declare function completeEvolutionGoal(ctx: Context, agent: Agent): GoalViewLike | undefined;
|
|
70
|
-
/** Block the current goal with a reason (when the service supports it). */
|
|
71
|
-
export declare function blockEvolutionGoal(ctx: Context, agent: Agent, reason: string): GoalViewLike | undefined;
|
|
72
|
-
//# sourceMappingURL=goal.d.ts.map
|
package/lib/goal.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/** The default objective used by `/evolve goal` without an explicit one. */
|
|
2
|
-
export const DEFAULT_EVOLVE_GOAL_OBJECTIVE = "持续进化本会话 harness 状态:每轮沉淀可复用经验(失败/战术/事实/委派规格),保持条目小而带证据";
|
|
3
|
-
/**
|
|
4
|
-
* Resolve the goal service lazily; undefined when the profile lacks it.
|
|
5
|
-
* Uses `ctx.get("goals")` (the global service registry) — a direct property
|
|
6
|
-
* access like `ctx.goals` walks only the caller's fiber ancestor chain and
|
|
7
|
-
* throws "cannot get property \"goals\" without inject" for services
|
|
8
|
-
* provided by sibling plugin entries (the goal plugin is a sibling of this
|
|
9
|
-
* one in the profile tree).
|
|
10
|
-
*/
|
|
11
|
-
export function goalServiceOf(ctx) {
|
|
12
|
-
return ctx.get("goals");
|
|
13
|
-
}
|
|
14
|
-
/** True when a goal view exists and is in a round-driving phase (active). */
|
|
15
|
-
export function goalDrivesRounds(view) {
|
|
16
|
-
return view?.phase === "active";
|
|
17
|
-
}
|
|
18
|
-
/** True when a goal exists at all (any phase) — used to gate create vs edit. */
|
|
19
|
-
export function goalExists(view) {
|
|
20
|
-
return view !== undefined;
|
|
21
|
-
}
|
|
22
|
-
/** Human-readable one-line status for a goal view. */
|
|
23
|
-
export function goalStatusText(view) {
|
|
24
|
-
const rounds = typeof view.roundsStarted === "number"
|
|
25
|
-
? String(view.roundsStarted)
|
|
26
|
-
: "?";
|
|
27
|
-
return `[${view.phase}] ${view.objective} (rounds=${rounds}/${view.maxGoalRounds}, revision=${view.revision})`;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Create or edit the session's evolution goal. With no current goal: create.
|
|
31
|
-
* With a current goal: edit its objective (create-on-first-use semantics are
|
|
32
|
-
* enforced by the goal service itself; completed goals may be replaced).
|
|
33
|
-
*/
|
|
34
|
-
export function upsertEvolutionGoal(ctx, agent, objective) {
|
|
35
|
-
const goals = goalServiceOf(ctx);
|
|
36
|
-
if (!goals) {
|
|
37
|
-
throw new Error("evolve: /evolve goal requires the goals service (load @deepseek-ai/dsh-goal)");
|
|
38
|
-
}
|
|
39
|
-
const current = goals.get(agent);
|
|
40
|
-
const nextObjective = objective && objective.length > 0 ? objective : DEFAULT_EVOLVE_GOAL_OBJECTIVE;
|
|
41
|
-
if (goalExists(current)) {
|
|
42
|
-
if (current.phase === "active" || current.phase === "paused") {
|
|
43
|
-
return goals.edit(agent, { id: current.id, revision: current.revision }, { objective: nextObjective });
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return goals.create(agent, { objective: nextObjective });
|
|
47
|
-
}
|
|
48
|
-
/** Complete the current goal, returning the completed view or undefined. */
|
|
49
|
-
export function completeEvolutionGoal(ctx, agent) {
|
|
50
|
-
const goals = goalServiceOf(ctx);
|
|
51
|
-
if (!goals) {
|
|
52
|
-
throw new Error("evolve: /evolve goal requires the goals service (load @deepseek-ai/dsh-goal)");
|
|
53
|
-
}
|
|
54
|
-
const current = goals.get(agent);
|
|
55
|
-
if (!goalExists(current) || current.phase === "complete") {
|
|
56
|
-
return current;
|
|
57
|
-
}
|
|
58
|
-
return goals.complete(agent, { id: current.id, revision: current.revision });
|
|
59
|
-
}
|
|
60
|
-
/** Block the current goal with a reason (when the service supports it). */
|
|
61
|
-
export function blockEvolutionGoal(ctx, agent, reason) {
|
|
62
|
-
const goals = goalServiceOf(ctx);
|
|
63
|
-
if (!goals || typeof goals.block !== "function") {
|
|
64
|
-
return undefined;
|
|
65
|
-
}
|
|
66
|
-
const current = goals.get(agent);
|
|
67
|
-
if (!goalExists(current) || current.phase !== "active") {
|
|
68
|
-
return current;
|
|
69
|
-
}
|
|
70
|
-
return goals.block(agent, { id: current.id, revision: current.revision }, { code: "evolve-blocked", reason });
|
|
71
|
-
}
|
|
72
|
-
//# sourceMappingURL=goal.js.map
|
package/lib/inject.d.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Real prompt/spec injection: the dynamic system-prompt section that makes
|
|
3
|
-
* `prompt` entries visible to the model without a tool call, and `subagent`
|
|
4
|
-
* entries available as reusable delegation specs at the delegation seam.
|
|
5
|
-
*
|
|
6
|
-
* Design (design.md §7 Phase 2):
|
|
7
|
-
* - the section text is a provider evaluated at every assembly with the
|
|
8
|
-
* assembling agent; a section that renders to "" is dropped by the prompt
|
|
9
|
-
* renderer, so an empty store costs zero tokens;
|
|
10
|
-
* - prompt entries render as an additive section (the base system prompt is
|
|
11
|
-
* never touched); subagent entries render as delegation specs the parent
|
|
12
|
-
* follows when delegating, and are inherited by child agents through the
|
|
13
|
-
* `SessionHeader.parentSession` chain so a freshly spawned subagent carries
|
|
14
|
-
* its parent's specs without any provider wrapping;
|
|
15
|
-
* - every cap mirrors render.ts (6 entries/kind, 180 chars/entry, stable
|
|
16
|
-
* sort), keeping the injected cost bounded no matter how the store grows;
|
|
17
|
-
* - full text stays one `evolve_list` call away: the injected block is a
|
|
18
|
-
* summary index, not a duplicate of the store.
|
|
19
|
-
*
|
|
20
|
-
* Split (2026-10-03 refactor): ranking lives in `injection-rank.ts`, the
|
|
21
|
-
* entry directory in `injection-directory.ts`, shared caps in
|
|
22
|
-
* `injection-caps.ts`; this module owns section rendering and the
|
|
23
|
-
* three-store merge. Moved symbols are re-exported here so the public
|
|
24
|
-
* surface stays on one module.
|
|
25
|
-
*/
|
|
26
|
-
import type { HarnessEntry, HarnessState } from "./types.js";
|
|
27
|
-
import type { EvolutionEngine } from "./service.js";
|
|
28
|
-
import { type AgentLike } from "./injection-rank.js";
|
|
29
|
-
/** Compat surface: ranking + directory + caps moved out 2026-10-03. */
|
|
30
|
-
export { rankEntries, recencyScore, recentUserText, sessionEventsOf, tokenize } from "./injection-rank.js";
|
|
31
|
-
export type { AgentLike, UserMessageEventLike } from "./injection-rank.js";
|
|
32
|
-
export { RECENCY_HALF_LIFE_MS, MAX_QUERY_MESSAGES, MAX_QUERY_CHARS } from "./injection-rank.js";
|
|
33
|
-
export { directoryLine, formatEntriesDirectory, formatEntriesDirectoryCapped, formatEntriesDirectoryRanked, rankedDirectoryEntries, DEFAULT_DIRECTORY_LINES, } from "./injection-directory.js";
|
|
34
|
-
export { MAX_INJECTED_ENTRIES_PER_KIND, MAX_INJECTED_CONTENT_LENGTH } from "./injection-caps.js";
|
|
35
|
-
/** How many `parentSession` hops a child walks to inherit entries. */
|
|
36
|
-
export declare const MAX_PARENT_CHAIN_DEPTH = 8;
|
|
37
|
-
/** The section-provider context shape we consume (subset of AssembleContext). */
|
|
38
|
-
export interface InjectContext {
|
|
39
|
-
agent?: AgentLike;
|
|
40
|
-
}
|
|
41
|
-
/** True when the state carries at least one entry of any kind. */
|
|
42
|
-
export declare function hasAnyEntries(state: HarnessState): boolean;
|
|
43
|
-
/** The additive prompt-notes block (empty when there are no visible prompt entries). */
|
|
44
|
-
export declare function formatPromptEntriesSection(entries: readonly HarnessEntry[], query?: string): string;
|
|
45
|
-
/** The reusable delegation-specs block (empty when there are no visible subagent entries). */
|
|
46
|
-
export declare function formatSubagentSpecsSection(entries: readonly HarnessEntry[], query?: string): string;
|
|
47
|
-
/**
|
|
48
|
-
* Walk the parent-session chain from `agent` upward and return the nearest
|
|
49
|
-
* session whose local store is non-empty, if any. Children inherit their
|
|
50
|
-
* ancestor's prompt notes and delegation specs; the chain walk stops at the
|
|
51
|
-
* first store that has entries (deep descendants do not re-inject ancestors
|
|
52
|
-
* beyond the nearest carrying store).
|
|
53
|
-
*/
|
|
54
|
-
export declare function nearestLocalStateWithEntries(engine: EvolutionEngine, agent: AgentLike): HarnessState | undefined;
|
|
55
|
-
/**
|
|
56
|
-
* The single three-store merge every injection path reads from: the global
|
|
57
|
-
* store merged with this project's store (when the session cwd resolves one)
|
|
58
|
-
* and the nearest carrying local store (precedence global < project < local —
|
|
59
|
-
* see {@link mergeHarnessStates}). One home, so the memory section and the
|
|
60
|
-
* entry directory can never disagree about what the model can see.
|
|
61
|
-
*/
|
|
62
|
-
export declare function mergedInjectionState(engine: EvolutionEngine, agent: AgentLike, opts?: {
|
|
63
|
-
projectKey?: string;
|
|
64
|
-
}): HarnessState;
|
|
65
|
-
/**
|
|
66
|
-
* Compose the full injected block for one assembling agent: global entries
|
|
67
|
-
* merged with this project's store (when the session cwd resolves one) and
|
|
68
|
-
* the nearest carrying local store (precedence global < project < local).
|
|
69
|
-
* The optional `query` — when absent, derived from the agent's most recent
|
|
70
|
-
* direct user messages — ranks which entries fill the per-kind cap
|
|
71
|
-
* (relevance first, then recency; see {@link rankEntries}). Returns "" when
|
|
72
|
-
* nothing is injectable — the prompt renderer then drops the section, so an
|
|
73
|
-
* empty store adds zero tokens to every assembly.
|
|
74
|
-
*
|
|
75
|
-
* `opts.directoryLines` caps the entry-directory index (2026-08-22 throttle);
|
|
76
|
-
* `opts.projectKey` pins the project layer explicitly (tests, tools) —
|
|
77
|
-
* otherwise it is derived from the agent's session cwd, best-effort.
|
|
78
|
-
* `opts.includeMemoryDirectory` (default true) drops memory lines from the
|
|
79
|
-
* directory when the memory section already carries them (evolve v2) — one
|
|
80
|
-
* fact, one home, so the same memories are never paid for twice.
|
|
81
|
-
* Usage recording covers ALL kinds — memories and skills appear as directory
|
|
82
|
-
* lines, prompts/subagents as content — and is deduped per session so the
|
|
83
|
-
* counts read "how many sessions saw this", not "how many prompt builds".
|
|
84
|
-
*/
|
|
85
|
-
export declare function entriesSectionText(engine: EvolutionEngine, agent: AgentLike | undefined, query?: string, opts?: {
|
|
86
|
-
directoryLines?: number;
|
|
87
|
-
projectKey?: string;
|
|
88
|
-
includeMemoryDirectory?: boolean;
|
|
89
|
-
}): string;
|
|
90
|
-
//# sourceMappingURL=inject.d.ts.map
|