dsh-continual-evolve 0.10.5 → 0.10.6
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 +1 -0
- package/README.zh.md +1 -0
- package/lib/approval.d.ts +17 -5
- package/lib/approval.js +73 -12
- package/lib/auto.js +1 -0
- package/lib/command.d.ts +3 -0
- package/lib/command.js +2 -2
- package/lib/index.js +5 -1
- package/lib/memory-agent.d.ts +3 -1
- package/lib/memory-agent.js +1 -1
- package/lib/tool.d.ts +7 -0
- package/lib/tool.js +3 -3
- package/lib/wrapup-command.d.ts +2 -1
- package/lib/wrapup-command.js +7 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -91,6 +91,7 @@ Injection shape: prompt notes and delegation specs inject with content (≤6/kin
|
|
|
91
91
|
| `reviewBudgetTokens` | `4096` | output budget for the gate call |
|
|
92
92
|
| `notifyOnAutoReview` | `true` | visible follow-up notice after an applied gate run |
|
|
93
93
|
| `requireGlobalApproval` | `true` | global and project edits ask for explicit approval |
|
|
94
|
+
| `recordLanguage` | `auto` | authoring **and dialog** language: `auto` follows the DSH client preference, then the session's own user text, then `en`; `zh`/`en` pin it |
|
|
94
95
|
| `localFate` | `false` | optional local-entry promote/archive fate assessment; unreachable while the listener runs memory-only, so it only affects direct/full callers |
|
|
95
96
|
| `fateIntervalTurns` | follows `reviewIntervalTurns` | minimum turns between fate assessments |
|
|
96
97
|
| `goalBlockedWrapupTurns` | `3` | consecutive blocked-goal gate runs trigger one fate assessment (`0` disables) |
|
package/README.zh.md
CHANGED
|
@@ -91,6 +91,7 @@ dsh plugin add ZK-Andy/dsh-continual-evolve
|
|
|
91
91
|
| `reviewBudgetTokens` | `4096` | 门禁调用输出预算 |
|
|
92
92
|
| `notifyOnAutoReview` | `true` | 门禁应用后发可见跟进通知 |
|
|
93
93
|
| `requireGlobalApproval` | `true` | 全局与项目写入需明确批准 |
|
|
94
|
+
| `recordLanguage` | `auto` | 记录**与弹窗**语言:`auto` 依次跟随 DSH 客户端偏好 → 会话自身用户文本 → `en`;`zh`/`en` 固定 |
|
|
94
95
|
| `localFate` | `false` | 可选的本地条目晋升/归档 fate 评估;listener 以 memory-only 运行时不可达,只对直接/完整调用者生效 |
|
|
95
96
|
| `fateIntervalTurns` | 跟随 `reviewIntervalTurns` | 归宿评估的最小回合间隔 |
|
|
96
97
|
| `goalBlockedWrapupTurns` | `3` | 连续阻塞目标的门禁轮数触发一次归宿评估(`0` 关闭) |
|
package/lib/approval.d.ts
CHANGED
|
@@ -6,8 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { Context } from "@deepseek-ai/cordis";
|
|
8
8
|
import type { Agent } from "@deepseek-ai/dsh-agent";
|
|
9
|
-
import type
|
|
9
|
+
import { type RecordLanguagePreference } from "./record-language.js";
|
|
10
10
|
export type ScopeApprovalDecision = "approved" | "declined";
|
|
11
|
+
/** Labels the approval dialog offers for each decision (parser contract). */
|
|
12
|
+
export declare const APPROVE_LABELS: readonly ["批准", "Approve"];
|
|
13
|
+
export declare const DECLINE_LABELS: readonly ["拒绝", "Decline"];
|
|
11
14
|
export interface QuestionService {
|
|
12
15
|
ask(request: {
|
|
13
16
|
questions: {
|
|
@@ -24,6 +27,7 @@ export interface QuestionService {
|
|
|
24
27
|
answers?: {
|
|
25
28
|
id: string;
|
|
26
29
|
selected?: string[];
|
|
30
|
+
custom?: string;
|
|
27
31
|
}[];
|
|
28
32
|
}>;
|
|
29
33
|
}
|
|
@@ -41,20 +45,28 @@ export declare function questionServiceOf(ctx: Context): QuestionService | undef
|
|
|
41
45
|
* Copy follows the headline → details → impact shape in the resolved dialog
|
|
42
46
|
* language; labels stay literal per language for parser compatibility.
|
|
43
47
|
*
|
|
48
|
+
* Language resolution runs the full record-language chain — explicit config,
|
|
49
|
+
* then the durable client preference, then the session's own recent user text
|
|
50
|
+
* — because an approval dialog raised from a tool call DOES have a session
|
|
51
|
+
* behind it. Stopping at the durable tier gave a Chinese-speaking user English
|
|
52
|
+
* dialogs whenever the stored preference was unset (2026-10-01).
|
|
53
|
+
*
|
|
44
54
|
* @param ctx Cordis context carrying the userQuestions service.
|
|
45
55
|
* @param agent Agent prompting the question, if any.
|
|
46
56
|
* @param signal Abort signal for the question, if any.
|
|
47
57
|
* @param scope Target persistent scope.
|
|
48
58
|
* @param what Edit summary; truncated to 300 chars with "…" when longer.
|
|
49
|
-
* @param
|
|
50
|
-
*
|
|
59
|
+
* @param configured Plugin `recordLanguage` preference; `auto`/absent defers
|
|
60
|
+
* to the durable preference and the session's user text.
|
|
51
61
|
* @returns "approved" when the user picks the approval label, otherwise "declined".
|
|
52
62
|
* @throws When the service is missing or the answer is not unique/explicit.
|
|
53
63
|
*/
|
|
54
|
-
export declare function requestScopeApproval(ctx: Context, agent: Agent | undefined, signal: AbortSignal | undefined, scope: "project" | "global", what: string,
|
|
64
|
+
export declare function requestScopeApproval(ctx: Context, agent: Agent | undefined, signal: AbortSignal | undefined, scope: "project" | "global", what: string, configured?: RecordLanguagePreference): Promise<ScopeApprovalDecision>;
|
|
55
65
|
/**
|
|
56
66
|
* Ask the user to approve a global edit. Throws when the service is missing,
|
|
57
67
|
* the user declines, or the question cannot be answered.
|
|
68
|
+
*
|
|
69
|
+
* @param configured Plugin `recordLanguage` preference (see {@link requestScopeApproval}).
|
|
58
70
|
*/
|
|
59
|
-
export declare function requireGlobalApproval(ctx: Context, agent: Agent | undefined, signal: AbortSignal | undefined, what: string): Promise<void>;
|
|
71
|
+
export declare function requireGlobalApproval(ctx: Context, agent: Agent | undefined, signal: AbortSignal | undefined, what: string, configured?: RecordLanguagePreference): Promise<void>;
|
|
60
72
|
//# sourceMappingURL=approval.d.ts.map
|
package/lib/approval.js
CHANGED
|
@@ -1,4 +1,39 @@
|
|
|
1
|
-
import { approvalCopy
|
|
1
|
+
import { approvalCopy } from "./copy.js";
|
|
2
|
+
import { normalizeRecordLanguage, resolveRecordLanguage } from "./record-language.js";
|
|
3
|
+
import { recentUserText } from "./inject.js";
|
|
4
|
+
/** Labels the approval dialog offers for each decision (parser contract). */
|
|
5
|
+
export const APPROVE_LABELS = ["批准", "Approve"];
|
|
6
|
+
export const DECLINE_LABELS = ["拒绝", "Decline"];
|
|
7
|
+
/**
|
|
8
|
+
* Typed ("Other") answers accepted as an explicit decision once normalized.
|
|
9
|
+
* Deliberately exact: a substring rule would read "不批准" as approval, and a
|
|
10
|
+
* misread decision is far worse than asking the human to click the button.
|
|
11
|
+
*/
|
|
12
|
+
const TYPED_APPROVALS = new Set(["批准", "approve"]);
|
|
13
|
+
const TYPED_DECLINES = new Set(["拒绝", "decline"]);
|
|
14
|
+
/** Trim case/quotes/trailing punctuation and a trailing 吧/了 from a typed answer. */
|
|
15
|
+
function normalizeTypedAnswer(text) {
|
|
16
|
+
return text
|
|
17
|
+
.trim()
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.replace(/^[\s"'“”「」]+/, "")
|
|
20
|
+
.replace(/[\s"'“”「」。!!,,、]+$/, "")
|
|
21
|
+
.replace(/[吧了]$/, "");
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read a free-text answer as a decision, or `undefined` when it matches no
|
|
25
|
+
* label exactly. Never guesses.
|
|
26
|
+
*/
|
|
27
|
+
function typedDecision(custom) {
|
|
28
|
+
if (typeof custom !== "string")
|
|
29
|
+
return undefined;
|
|
30
|
+
const normalized = normalizeTypedAnswer(custom);
|
|
31
|
+
if (TYPED_APPROVALS.has(normalized))
|
|
32
|
+
return "approved";
|
|
33
|
+
if (TYPED_DECLINES.has(normalized))
|
|
34
|
+
return "declined";
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
2
37
|
/**
|
|
3
38
|
* Lazily resolve the userQuestions service from the context.
|
|
4
39
|
* Returns undefined when the service is not loaded — callers decide
|
|
@@ -15,22 +50,30 @@ export function questionServiceOf(ctx) {
|
|
|
15
50
|
* Copy follows the headline → details → impact shape in the resolved dialog
|
|
16
51
|
* language; labels stay literal per language for parser compatibility.
|
|
17
52
|
*
|
|
53
|
+
* Language resolution runs the full record-language chain — explicit config,
|
|
54
|
+
* then the durable client preference, then the session's own recent user text
|
|
55
|
+
* — because an approval dialog raised from a tool call DOES have a session
|
|
56
|
+
* behind it. Stopping at the durable tier gave a Chinese-speaking user English
|
|
57
|
+
* dialogs whenever the stored preference was unset (2026-10-01).
|
|
58
|
+
*
|
|
18
59
|
* @param ctx Cordis context carrying the userQuestions service.
|
|
19
60
|
* @param agent Agent prompting the question, if any.
|
|
20
61
|
* @param signal Abort signal for the question, if any.
|
|
21
62
|
* @param scope Target persistent scope.
|
|
22
63
|
* @param what Edit summary; truncated to 300 chars with "…" when longer.
|
|
23
|
-
* @param
|
|
24
|
-
*
|
|
64
|
+
* @param configured Plugin `recordLanguage` preference; `auto`/absent defers
|
|
65
|
+
* to the durable preference and the session's user text.
|
|
25
66
|
* @returns "approved" when the user picks the approval label, otherwise "declined".
|
|
26
67
|
* @throws When the service is missing or the answer is not unique/explicit.
|
|
27
68
|
*/
|
|
28
|
-
export async function requestScopeApproval(ctx, agent, signal, scope, what,
|
|
69
|
+
export async function requestScopeApproval(ctx, agent, signal, scope, what, configured) {
|
|
29
70
|
const userQuestions = questionServiceOf(ctx);
|
|
30
71
|
if (!userQuestions) {
|
|
31
72
|
throw new Error("global evolution edits require the userQuestions service (load @deepseek-ai/dsh-user-questions)");
|
|
32
73
|
}
|
|
33
|
-
const
|
|
74
|
+
const lang = normalizeRecordLanguage(configured) ??
|
|
75
|
+
resolveRecordLanguage({ ctx, trajectoryText: recentUserText(agent) });
|
|
76
|
+
const copy = approvalCopy(scope, what, lang);
|
|
34
77
|
const answer = await userQuestions.ask({
|
|
35
78
|
questions: [
|
|
36
79
|
{
|
|
@@ -46,20 +89,38 @@ export async function requestScopeApproval(ctx, agent, signal, scope, what, lang
|
|
|
46
89
|
if (matching.length !== 1 || !Array.isArray(matching[0]?.selected)) {
|
|
47
90
|
throw new Error("evolution approval returned no unique explicit decision");
|
|
48
91
|
}
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
92
|
+
const entry = matching[0];
|
|
93
|
+
const selected = [...new Set(entry.selected)];
|
|
94
|
+
if (selected.length === 0) {
|
|
95
|
+
// A typed "Other" answer counts only when it matches a dialog label
|
|
96
|
+
// exactly; anything fuzzier stays an error, so a lost or ambiguous
|
|
97
|
+
// reply is never recorded as a durable rejection.
|
|
98
|
+
const typed = typedDecision(entry.custom);
|
|
99
|
+
if (typed !== undefined) {
|
|
100
|
+
return typed;
|
|
101
|
+
}
|
|
102
|
+
throw new Error(`evolution approval needs one clicked option (${APPROVE_LABELS.join("/")} or ${DECLINE_LABELS.join("/")}) — a typed reply cannot serve as a decision`);
|
|
103
|
+
}
|
|
104
|
+
if (selected.length !== 1) {
|
|
53
105
|
throw new Error(`evolution approval returned an invalid decision: ${JSON.stringify(selected)}`);
|
|
54
106
|
}
|
|
55
|
-
|
|
107
|
+
const label = selected[0];
|
|
108
|
+
if (APPROVE_LABELS.includes(label)) {
|
|
109
|
+
return "approved";
|
|
110
|
+
}
|
|
111
|
+
if (DECLINE_LABELS.includes(label)) {
|
|
112
|
+
return "declined";
|
|
113
|
+
}
|
|
114
|
+
throw new Error(`evolution approval returned an unknown decision label: ${JSON.stringify(label)}`);
|
|
56
115
|
}
|
|
57
116
|
/**
|
|
58
117
|
* Ask the user to approve a global edit. Throws when the service is missing,
|
|
59
118
|
* the user declines, or the question cannot be answered.
|
|
119
|
+
*
|
|
120
|
+
* @param configured Plugin `recordLanguage` preference (see {@link requestScopeApproval}).
|
|
60
121
|
*/
|
|
61
|
-
export async function requireGlobalApproval(ctx, agent, signal, what) {
|
|
62
|
-
if ((await requestScopeApproval(ctx, agent, signal, "global", what)) !== "approved") {
|
|
122
|
+
export async function requireGlobalApproval(ctx, agent, signal, what, configured) {
|
|
123
|
+
if ((await requestScopeApproval(ctx, agent, signal, "global", what, configured)) !== "approved") {
|
|
63
124
|
throw new Error("global evolution edit rejected by the user");
|
|
64
125
|
}
|
|
65
126
|
}
|
package/lib/auto.js
CHANGED
|
@@ -504,6 +504,7 @@ export async function runMemoryExtractionPhase(ctx, engine, agent, config, state
|
|
|
504
504
|
decisionCursor: memorySnapshot.cursor,
|
|
505
505
|
scopeDecisions: state.memoryDecisions,
|
|
506
506
|
onScopeDecision: (key, decision) => rememberMemoryDecision(state, key, decision),
|
|
507
|
+
...(config.recordLanguage !== undefined ? { recordLanguage: config.recordLanguage } : {}),
|
|
507
508
|
...(signal ? { signal } : {}),
|
|
508
509
|
});
|
|
509
510
|
for (const result of application.results) {
|
package/lib/command.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { Context } from "@deepseek-ai/cordis";
|
|
|
6
6
|
import type { HarnessEntry, HarnessState, RefinementKind } from "./types.js";
|
|
7
7
|
import type { EvolutionEngine } from "./service.js";
|
|
8
8
|
import type { PromotionPolicy } from "./promotion.js";
|
|
9
|
+
import type { RecordLanguagePreference } from "./record-language.js";
|
|
9
10
|
export interface CommandGateOptions {
|
|
10
11
|
requireGlobalApproval: boolean;
|
|
11
12
|
}
|
|
@@ -22,6 +23,8 @@ export interface CommandRuntimeOptions {
|
|
|
22
23
|
* registered; this is not a registration gate.
|
|
23
24
|
*/
|
|
24
25
|
autoReview?: boolean;
|
|
26
|
+
/** Plugin `recordLanguage` preference for dialog copy (see `approval.ts`). */
|
|
27
|
+
recordLanguage?: RecordLanguagePreference;
|
|
25
28
|
}
|
|
26
29
|
export declare function registerEvolveCommand(ctx: Context, engine: EvolutionEngine, opts: CommandGateOptions, runtime: CommandRuntimeOptions): void;
|
|
27
30
|
/**
|
package/lib/command.js
CHANGED
|
@@ -364,7 +364,7 @@ async function executeEvolveCommand(ctx, engine, invocation, opts, runtime) {
|
|
|
364
364
|
skillsRoot: join(engine.baseDir, "skills"),
|
|
365
365
|
});
|
|
366
366
|
if ((scope === "global" || scope === "project") && opts.requireGlobalApproval && proposal.edits.length > 0) {
|
|
367
|
-
await requireGlobalApproval(ctx, invocation.agent, invocation.signal, `/evolve plan ${scope} 将应用 ${proposal.edits.length} 条编辑到${scope === "project" ? "本项目" : "跨会话"} store:${proposal.summary}
|
|
367
|
+
await requireGlobalApproval(ctx, invocation.agent, invocation.signal, `/evolve plan ${scope} 将应用 ${proposal.edits.length} 条编辑到${scope === "project" ? "本项目" : "跨会话"} store:${proposal.summary}`, runtime.recordLanguage);
|
|
368
368
|
}
|
|
369
369
|
const result = engine.apply(scope, storeIdForCommand(scope, invocation), proposal, {
|
|
370
370
|
scope,
|
|
@@ -374,7 +374,7 @@ async function executeEvolveCommand(ctx, engine, invocation, opts, runtime) {
|
|
|
374
374
|
return success(renderResult(result));
|
|
375
375
|
}
|
|
376
376
|
case "wrapup": {
|
|
377
|
-
return await executeWrapupCommand(ctx, engine, invocation, runtime.promotionPolicy);
|
|
377
|
+
return await executeWrapupCommand(ctx, engine, invocation, runtime.promotionPolicy, runtime.recordLanguage);
|
|
378
378
|
}
|
|
379
379
|
case "pause":
|
|
380
380
|
case "resume": {
|
package/lib/index.js
CHANGED
|
@@ -209,7 +209,10 @@ export function apply(ctx, config) {
|
|
|
209
209
|
text: (context) => frozenMemories.textFor(context.agent, (agent) => memoryIndexSectionText(engine, agent, { maxChars: memoryIndexMaxChars, guide: memoryIndexGuide })),
|
|
210
210
|
});
|
|
211
211
|
}
|
|
212
|
-
const gate = {
|
|
212
|
+
const gate = {
|
|
213
|
+
requireGlobalApproval: config.requireGlobalApproval ?? true,
|
|
214
|
+
...(config.recordLanguage !== undefined ? { recordLanguage: config.recordLanguage } : {}),
|
|
215
|
+
};
|
|
213
216
|
const promotionPolicy = resolvePromotionPolicy({
|
|
214
217
|
blockPatterns: config.promotionBlockPatterns,
|
|
215
218
|
minPromoteChars: config.promotionMinChars,
|
|
@@ -222,6 +225,7 @@ export function apply(ctx, config) {
|
|
|
222
225
|
autoCase: config.autoCase ?? true,
|
|
223
226
|
promotionPolicy,
|
|
224
227
|
autoReview: config.autoReview ?? false,
|
|
228
|
+
...(config.recordLanguage !== undefined ? { recordLanguage: config.recordLanguage } : {}),
|
|
225
229
|
});
|
|
226
230
|
// Plugin-owned file logging: every cordis log message lands in
|
|
227
231
|
// <baseDir>/evolve/plugin.log regardless of how dsh web was launched —
|
package/lib/memory-agent.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { type LlmSessionId } from "./llm-text.js";
|
|
|
15
15
|
import { type PrefixCacheOptions } from "./prefix-cache.js";
|
|
16
16
|
import { type EvolutionEngine } from "./service.js";
|
|
17
17
|
import { type TokenUsageTarget } from "./token-usage.js";
|
|
18
|
-
import { type RecordLanguage } from "./record-language.js";
|
|
18
|
+
import { type RecordLanguage, type RecordLanguagePreference } from "./record-language.js";
|
|
19
19
|
import type { EntrySource, HarnessEntry, HarnessScope, HarnessState, RefinementEdit, RefinementProposal, RefinementResult } from "./types.js";
|
|
20
20
|
/** ZCode parity: the extractor may inspect memory and propose at most five times. */
|
|
21
21
|
export declare const MEMORY_AGENT_MAX_TURNS = 5;
|
|
@@ -110,6 +110,8 @@ export interface ApplyMemoryProposalOptions {
|
|
|
110
110
|
scopeDecisions?: Readonly<Record<string, ScopeApprovalDecision>>;
|
|
111
111
|
/** Persist each decision before a later scope can fail. */
|
|
112
112
|
onScopeDecision?: (key: string, decision: ScopeApprovalDecision) => void;
|
|
113
|
+
/** Plugin `recordLanguage` preference for the approval dialog copy. */
|
|
114
|
+
recordLanguage?: RecordLanguagePreference;
|
|
113
115
|
}
|
|
114
116
|
/**
|
|
115
117
|
* Render the authoritative persistent-scope diff shown to the human. Model
|
package/lib/memory-agent.js
CHANGED
|
@@ -362,7 +362,7 @@ export async function applyMemoryExtractionProposal(ctx, engine, proposal, optio
|
|
|
362
362
|
declinedScopes.push(scope);
|
|
363
363
|
continue;
|
|
364
364
|
}
|
|
365
|
-
const approved = await requestScopeApproval(ctx, options.agent, options.signal, scope, renderMemoryApprovalDetails(proposal, scope, baseline));
|
|
365
|
+
const approved = await requestScopeApproval(ctx, options.agent, options.signal, scope, renderMemoryApprovalDetails(proposal, scope, baseline), options.recordLanguage);
|
|
366
366
|
if (decisionKey !== undefined)
|
|
367
367
|
options.onScopeDecision?.(decisionKey, approved);
|
|
368
368
|
if (approved === "approved")
|
package/lib/tool.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* the engine. `global: true` is required explicitly for cross-session edits.
|
|
5
5
|
*/
|
|
6
6
|
import type { Context } from "@deepseek-ai/cordis";
|
|
7
|
+
import type { RecordLanguagePreference } from "./record-language.js";
|
|
7
8
|
import type { HarnessScope } from "./types.js";
|
|
8
9
|
import type { EvolutionEngine } from "./service.js";
|
|
9
10
|
/**
|
|
@@ -22,6 +23,12 @@ export declare function scopeOf(value: unknown, fallback: HarnessScope): Harness
|
|
|
22
23
|
export declare function collectDeleteIds(id: unknown, ids: unknown): string[];
|
|
23
24
|
export interface ToolGateOptions {
|
|
24
25
|
requireGlobalApproval: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Plugin `recordLanguage` preference for the approval dialog copy;
|
|
28
|
+
* `auto`/absent defers to the durable client preference and the session's
|
|
29
|
+
* own user text (see `approval.ts`).
|
|
30
|
+
*/
|
|
31
|
+
recordLanguage?: RecordLanguagePreference;
|
|
25
32
|
}
|
|
26
33
|
export declare function registerEvolveTools(ctx: Context, engine: EvolutionEngine, opts: ToolGateOptions): void;
|
|
27
34
|
//# sourceMappingURL=tool.d.ts.map
|
package/lib/tool.js
CHANGED
|
@@ -186,7 +186,7 @@ export function registerEvolveTools(ctx, engine, opts) {
|
|
|
186
186
|
const targetState = engine.load(scope, storeId);
|
|
187
187
|
const hit = mostSimilarEntry(Object.values(targetState.entries[args.kind]), args.title ?? "", args.content ?? "", CONFLICT_WARN_SCORE);
|
|
188
188
|
const conflictNote = hit ? ` ⚠️ ${buildConflictNotice(hit)}——建议改用 evolve_update` : "";
|
|
189
|
-
await requireGlobalApproval(ctx, exec.agent, exec.signal, `evolve_add ${args.kind} "${args.title}" → ${storeLabel(scope)}${conflictNote}
|
|
189
|
+
await requireGlobalApproval(ctx, exec.agent, exec.signal, `evolve_add ${args.kind} "${args.title}" → ${storeLabel(scope)}${conflictNote}`, opts.recordLanguage);
|
|
190
190
|
}
|
|
191
191
|
const edit = {
|
|
192
192
|
action: "create",
|
|
@@ -228,7 +228,7 @@ export function registerEvolveTools(ctx, engine, opts) {
|
|
|
228
228
|
const scope = scopeOf(args.scope ?? args.global, "local");
|
|
229
229
|
const storeId = storeIdFor(scope, exec);
|
|
230
230
|
if (needsApproval(scope) && opts.requireGlobalApproval) {
|
|
231
|
-
await requireGlobalApproval(ctx, exec.agent, exec.signal, `evolve_update ${args.kind}:${args.id} → ${storeLabel(scope)}
|
|
231
|
+
await requireGlobalApproval(ctx, exec.agent, exec.signal, `evolve_update ${args.kind}:${args.id} → ${storeLabel(scope)}`, opts.recordLanguage);
|
|
232
232
|
}
|
|
233
233
|
const edit = { action: "update", kind: args.kind, id: args.id };
|
|
234
234
|
if (args.title !== undefined)
|
|
@@ -263,7 +263,7 @@ export function registerEvolveTools(ctx, engine, opts) {
|
|
|
263
263
|
const storeId = storeIdFor(scope, exec);
|
|
264
264
|
const ids = collectDeleteIds(args.id, args.ids);
|
|
265
265
|
if (needsApproval(scope) && opts.requireGlobalApproval) {
|
|
266
|
-
await requireGlobalApproval(ctx, exec.agent, exec.signal, `evolve_delete ${args.kind}:${ids.length > 1 ? `${ids.length} entries (${ids.join(", ")})` : ids[0]} → ${storeLabel(scope)}
|
|
266
|
+
await requireGlobalApproval(ctx, exec.agent, exec.signal, `evolve_delete ${args.kind}:${ids.length > 1 ? `${ids.length} entries (${ids.join(", ")})` : ids[0]} → ${storeLabel(scope)}`, opts.recordLanguage);
|
|
267
267
|
}
|
|
268
268
|
const edits = ids.map((id) => ({ action: "delete", kind: args.kind, id }));
|
|
269
269
|
return textResult(applyEditsText(engine, scope, storeId, edits, exec.agent, sessionIdOf(exec)));
|
package/lib/wrapup-command.d.ts
CHANGED
|
@@ -5,5 +5,6 @@ import type { Context } from "@deepseek-ai/cordis";
|
|
|
5
5
|
import type { CommandInvocation, CommandResult } from "@deepseek-ai/dsh-commands";
|
|
6
6
|
import type { EvolutionEngine } from "./service.js";
|
|
7
7
|
import { type PromotionPolicy } from "./promotion.js";
|
|
8
|
-
|
|
8
|
+
import { type RecordLanguagePreference } from "./record-language.js";
|
|
9
|
+
export declare function executeWrapupCommand(ctx: Context, engine: EvolutionEngine, invocation: CommandInvocation, policy?: PromotionPolicy, recordLanguage?: RecordLanguagePreference): Promise<CommandResult>;
|
|
9
10
|
//# sourceMappingURL=wrapup-command.d.ts.map
|
package/lib/wrapup-command.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { questionServiceOf, requireGlobalApproval } from "./approval.js";
|
|
2
|
-
import {
|
|
2
|
+
import { wrapupArchiveCopy } from "./copy.js";
|
|
3
3
|
import { assessLocalEntries, candidateKey, filterPromotable, listLocalCandidates, splitArchiveGuards, splitPromoteBlocked, splitPromoteProposals, valenceStampProposal, wholePromoteProposals } from "./wrapup.js";
|
|
4
4
|
import { DEFAULT_PROMOTION_POLICY } from "./promotion.js";
|
|
5
|
+
import { normalizeRecordLanguage, resolveRecordLanguage } from "./record-language.js";
|
|
6
|
+
import { recentUserText } from "./inject.js";
|
|
5
7
|
function success(text) {
|
|
6
8
|
return { kind: "success", text };
|
|
7
9
|
}
|
|
8
|
-
export async function executeWrapupCommand(ctx, engine, invocation, policy = DEFAULT_PROMOTION_POLICY) {
|
|
10
|
+
export async function executeWrapupCommand(ctx, engine, invocation, policy = DEFAULT_PROMOTION_POLICY, recordLanguage) {
|
|
9
11
|
const sessionId = invocation.agent.id;
|
|
10
12
|
const localState = engine.load("local", sessionId);
|
|
11
13
|
const globalState = engine.load("global", undefined);
|
|
@@ -102,7 +104,7 @@ export async function executeWrapupCommand(ctx, engine, invocation, policy = DEF
|
|
|
102
104
|
].join("\n")}`;
|
|
103
105
|
let promoteAllowed = true;
|
|
104
106
|
try {
|
|
105
|
-
await requireGlobalApproval(ctx, invocation.agent, invocation.signal, what);
|
|
107
|
+
await requireGlobalApproval(ctx, invocation.agent, invocation.signal, what, recordLanguage);
|
|
106
108
|
}
|
|
107
109
|
catch (cause) {
|
|
108
110
|
promoteAllowed = false;
|
|
@@ -187,7 +189,8 @@ export async function executeWrapupCommand(ctx, engine, invocation, policy = DEF
|
|
|
187
189
|
const questionId = "evolve-wrapup-archive-review";
|
|
188
190
|
let archiveConfirmed = false;
|
|
189
191
|
try {
|
|
190
|
-
const copy = wrapupArchiveCopy(candidate.title,
|
|
192
|
+
const copy = wrapupArchiveCopy(candidate.title, normalizeRecordLanguage(recordLanguage) ??
|
|
193
|
+
resolveRecordLanguage({ ctx, trajectoryText: recentUserText(invocation.agent) }));
|
|
191
194
|
const answer = await userQuestions.ask({
|
|
192
195
|
questions: [
|
|
193
196
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-continual-evolve",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.6",
|
|
4
4
|
"description": "Continual self-evolution plugin for DeepSeek Harness: versioned, auditable, rollback-safe harness state (prompt notes, memories, skills, subagent specs) refined from session trajectories.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|