@lmzhen/dsh-evolution-merge 0.37.1 → 0.38.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/lib/index.js CHANGED
@@ -1,12 +1,14 @@
1
1
  import { dirname, join } from "node:path";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { pairKeyOf, screen, selectCandidates } from "@lmzhen/dsh-evolution-merge-engine";
4
+ import { createUserMessage } from "@deepseek-ai/dsh-llm";
4
5
  import { DEFAULT_SKILL_LIMITS, SkillLibrary, UnitTransactions, authorityFrom, contentHash, createSubagentChannel, errorText, evolutionHome, evolutionIoAdapter, executeUnitUndo, isPresent, isProcessAlive, newRunRegistry, newSkillLibrary, parseFrontmatter, planUnitUndoAcross, policyStageLimits, probeAbsent, probeList, probePresent, probeText, probeUnknown, readTreeLock, readUnitEvidence, readUnitJournal, registerOwnerSettings, reportsSweepLockTarget, revisionAnchorOf, revisionFingerprint, revisionSupportDigest, runsFile, scanContentThreats, skillLibraryUnitBackend, supportRefs, sweepReports, transactIo, validateFrontmatter, validateSupportPath } from "@lmzhen/dsh-evolution-core";
5
6
  import { HOST_ROUTES, json, methodNotAllowed, registerHostRoutes } from "@lmzhen/dsh-evolution-core/http-routes";
6
7
  import { createHash, randomUUID } from "node:crypto";
7
8
  import { chmod, mkdir, open, readFile, stat, unlink } from "node:fs/promises";
8
9
  import { aliasRegistration, buildSurface, parseCommand } from "@lmzhen/dsh-evolution-commands";
9
10
  import { readFileSync } from "node:fs";
11
+ import { defineTool } from "@lmzhen/dsh-evolution-core/platform";
10
12
  //#region lib/types/adapters/select.js
11
13
  /** Host selector correction: engine selector does not route judge errors to candidates. */
12
14
  function selectWithErrors(report) {
@@ -101,56 +103,32 @@ function normalizeProviderKey(value) {
101
103
  //#endregion
102
104
  //#region lib/types/adapters/model-runner.js
103
105
  /**
104
- * DeepSeek judge runner over the platform llm service. The engine calls
105
- * runner(prompt, cfg) and expects raw model text; the platform owns provider
106
- * selection, usage accounting and transport.
106
+ * DeepSeek judge runner over the family LLM runtime. The engine calls
107
+ * runner(prompt, cfg) and expects raw model text; the runtime owns provider
108
+ * selection, purpose, transport and timeout.
107
109
  */
108
- function append(chunk, text) {
109
- if (chunk.type === "text-delta" || chunk.type === "text") return text + (chunk.text ?? "");
110
- if (chunk.type === "finish" && chunk.reason?.kind === "error") throw new Error("model call failed: " + (chunk.reason.failure?.message ?? "unknown"));
111
- return text;
112
- }
113
110
  function createEngineRunner(llm, route) {
114
111
  return async (prompt, cfg, runSignal) => {
112
+ if (!llm.available()) throw new Error("llm service unavailable: evolutionLlm is degraded");
115
113
  const selection = route();
116
114
  const timeout = Number(cfg?.timeoutMs);
117
- const timeoutSignal = Number.isFinite(timeout) && timeout > 0 ? AbortSignal.timeout(timeout) : void 0;
118
- const signal = runSignal === void 0 ? timeoutSignal : timeoutSignal === void 0 ? runSignal : typeof AbortSignal.any === "function" ? AbortSignal.any([runSignal, timeoutSignal]) : runSignal;
119
- let text = "";
120
- if (llm.stream !== void 0) {
121
- for await (const chunk of llm.stream({
115
+ return await llm.text({
116
+ purpose: "evolution-merge-engine",
117
+ route: {
122
118
  provider: normalizeProviderKey(selection.provider),
123
- model: selection.model,
124
- messages: [{
125
- role: "user",
126
- content: [{
127
- type: "text",
128
- text: prompt
129
- }]
130
- }],
131
- temperature: 0,
132
- ...signal === void 0 ? {} : { signal }
133
- })) text = append(chunk, text);
134
- return text;
135
- }
136
- if (llm.prepareCall === void 0) throw new Error("llm service has neither stream nor prepareCall");
137
- const call = await llm.prepareCall({
138
- provider: normalizeProviderKey(selection.provider),
139
- model: selection.model,
140
- temperature: 0
141
- }, signal);
142
- for await (const chunk of call.stream({
143
- ...call.config,
144
- messages: [{
145
- role: "user",
119
+ model: selection.model
120
+ },
121
+ messages: [createUserMessage({
146
122
  content: [{
147
123
  type: "text",
148
124
  text: prompt
149
- }]
150
- }],
151
- ...signal === void 0 ? {} : { signal }
152
- })) text = append(chunk, text);
153
- return text;
125
+ }],
126
+ source: { kind: "user" }
127
+ })],
128
+ temperature: 0,
129
+ ...runSignal === void 0 ? {} : { signal: runSignal },
130
+ ...Number.isFinite(timeout) && timeout > 0 ? { timeoutMs: timeout } : {}
131
+ });
154
132
  };
155
133
  }
156
134
  //#endregion
@@ -10307,33 +10285,29 @@ function operation(args) {
10307
10285
  return shapeError("op must be list/read/write/copy");
10308
10286
  }
10309
10287
  function createMergeStageTool(io, home, context, diagnose) {
10310
- return {
10288
+ return defineTool({
10311
10289
  name: MERGE_STAGE_TOOL_NAME,
10312
10290
  description: "Read source copies and write the merged skill into the staging tree. list/read use area=sources|merged plus source (for sources); write/copy paths are relative to merged/<target> (for example path=SKILL.md, from=SKILL.md, to=references/x.md). Write/copy are only allowed in the author phase.",
10313
10291
  parameters: {
10314
- type: "object",
10315
- properties: {
10316
- op: {
10317
- type: "string",
10318
- enum: [
10319
- "list",
10320
- "read",
10321
- "write",
10322
- "copy"
10323
- ]
10324
- },
10325
- area: {
10326
- type: "string",
10327
- enum: ["sources", "merged"]
10328
- },
10329
- path: { type: "string" },
10330
- source: { type: "string" },
10331
- content: { type: "string" },
10332
- from: { type: "string" },
10333
- to: { type: "string" }
10292
+ op: {
10293
+ type: "string",
10294
+ required: true,
10295
+ enum: [
10296
+ "list",
10297
+ "read",
10298
+ "write",
10299
+ "copy"
10300
+ ]
10334
10301
  },
10335
- required: ["op"],
10336
- additionalProperties: false
10302
+ area: {
10303
+ type: "string",
10304
+ enum: ["sources", "merged"]
10305
+ },
10306
+ path: { type: "string" },
10307
+ source: { type: "string" },
10308
+ content: { type: "string" },
10309
+ from: { type: "string" },
10310
+ to: { type: "string" }
10337
10311
  },
10338
10312
  output: {
10339
10313
  schema: { type: "string" },
@@ -10354,7 +10328,7 @@ function createMergeStageTool(io, home, context, diagnose) {
10354
10328
  });
10355
10329
  return JSON.stringify(await applyStageTool(io, home, ctx, op));
10356
10330
  }
10357
- };
10331
+ });
10358
10332
  }
10359
10333
  //#endregion
10360
10334
  //#region lib/types/supersede.js
@@ -10762,7 +10736,7 @@ function apply(ctx, rawConfig = {}) {
10762
10736
  const stage = new StageToolRegistry();
10763
10737
  const engineInput = resolveEngineInput({ modelsRoot: startupParams.mergeModelsRoot });
10764
10738
  const engineConfig = engineConfigFromRoot(engineInput.modelsRoot);
10765
- const llm = ctx.get("llm");
10739
+ const llm = ctx.get("evolutionLlm");
10766
10740
  const defaultModel = ctx.get("agentDefaultModel");
10767
10741
  const runner = llm === void 0 || defaultModel === void 0 ? void 0 : createEngineRunner(llm, () => defaultModel.currentSelection());
10768
10742
  const engineScreening = createEngineScreening({
@@ -1,23 +1,24 @@
1
+ /**
2
+ * DeepSeek judge runner over the family LLM runtime. The engine calls
3
+ * runner(prompt, cfg) and expects raw model text; the runtime owns provider
4
+ * selection, purpose, transport and timeout.
5
+ */
6
+ import { createUserMessage } from '@deepseek-ai/dsh-llm';
1
7
  export interface ModelRoute {
2
8
  readonly provider: string;
3
9
  readonly model: string;
4
10
  }
5
- export interface LlmChunkLike {
6
- readonly type: string;
7
- readonly text?: string;
8
- readonly reason?: {
9
- readonly kind?: string;
10
- readonly failure?: {
11
- readonly message?: string;
12
- };
13
- };
11
+ /** The runtime service surface the merge engine consumes. */
12
+ export interface EvolutionLlmLike {
13
+ available(): boolean;
14
+ text(input: {
15
+ readonly purpose: 'evolution-merge-engine';
16
+ readonly route: ModelRoute;
17
+ readonly messages: ReturnType<typeof createUserMessage>[];
18
+ readonly temperature: number;
19
+ readonly signal?: AbortSignal | undefined;
20
+ readonly timeoutMs?: number | undefined;
21
+ }): Promise<string>;
14
22
  }
15
- export interface LlmServiceLike {
16
- stream?(options: Record<string, unknown>): AsyncIterable<LlmChunkLike>;
17
- prepareCall?(config: Record<string, unknown>, signal?: AbortSignal): Promise<{
18
- readonly config: Record<string, unknown>;
19
- stream(input: Record<string, unknown>): AsyncIterable<LlmChunkLike>;
20
- }>;
21
- }
22
- export declare function createEngineRunner(llm: LlmServiceLike, route: () => ModelRoute): (prompt: string, cfg?: Record<string, unknown>, signal?: AbortSignal | undefined) => Promise<string>;
23
+ export declare function createEngineRunner(llm: EvolutionLlmLike, route: () => ModelRoute): (prompt: string, cfg?: Record<string, unknown>, signal?: AbortSignal | undefined) => Promise<string>;
23
24
  //# sourceMappingURL=model-runner.d.ts.map
@@ -1,45 +1,24 @@
1
1
  /**
2
- * DeepSeek judge runner over the platform llm service. The engine calls
3
- * runner(prompt, cfg) and expects raw model text; the platform owns provider
4
- * selection, usage accounting and transport.
2
+ * DeepSeek judge runner over the family LLM runtime. The engine calls
3
+ * runner(prompt, cfg) and expects raw model text; the runtime owns provider
4
+ * selection, purpose, transport and timeout.
5
5
  */
6
+ import { createUserMessage } from '@deepseek-ai/dsh-llm';
6
7
  import { normalizeProviderKey } from "../domain/provider-key.js";
7
- function append(chunk, text) {
8
- if (chunk.type === 'text-delta' || chunk.type === 'text')
9
- return text + (chunk.text ?? '');
10
- if (chunk.type === 'finish' && chunk.reason?.kind === 'error') {
11
- throw new Error('model call failed: ' + (chunk.reason.failure?.message ?? 'unknown'));
12
- }
13
- return text;
14
- }
15
8
  export function createEngineRunner(llm, route) {
16
9
  return async (prompt, cfg, runSignal) => {
10
+ if (!llm.available())
11
+ throw new Error('llm service unavailable: evolutionLlm is degraded');
17
12
  const selection = route();
18
13
  const timeout = Number(cfg?.timeoutMs);
19
- const timeoutSignal = Number.isFinite(timeout) && timeout > 0 ? AbortSignal.timeout(timeout) : undefined;
20
- const signal = runSignal === undefined ? timeoutSignal : timeoutSignal === undefined ? runSignal : (typeof AbortSignal.any === 'function' ? AbortSignal.any([runSignal, timeoutSignal]) : runSignal);
21
- let text = '';
22
- if (llm.stream !== undefined) {
23
- for await (const chunk of llm.stream({
24
- provider: normalizeProviderKey(selection.provider),
25
- model: selection.model,
26
- messages: [{ role: 'user', content: [{ type: 'text', text: prompt }] }],
27
- temperature: 0,
28
- ...(signal === undefined ? {} : { signal }),
29
- }))
30
- text = append(chunk, text);
31
- return text;
32
- }
33
- if (llm.prepareCall === undefined)
34
- throw new Error('llm service has neither stream nor prepareCall');
35
- const call = await llm.prepareCall({ provider: normalizeProviderKey(selection.provider), model: selection.model, temperature: 0 }, signal);
36
- for await (const chunk of call.stream({
37
- ...call.config,
38
- messages: [{ role: 'user', content: [{ type: 'text', text: prompt }] }],
39
- ...(signal === undefined ? {} : { signal }),
40
- }))
41
- text = append(chunk, text);
42
- return text;
14
+ return await llm.text({
15
+ purpose: 'evolution-merge-engine',
16
+ route: { provider: normalizeProviderKey(selection.provider), model: selection.model },
17
+ messages: [createUserMessage({ content: [{ type: 'text', text: prompt }], source: { kind: 'user' } })],
18
+ temperature: 0,
19
+ ...(runSignal === undefined ? {} : { signal: runSignal }),
20
+ ...(Number.isFinite(timeout) && timeout > 0 ? { timeoutMs: timeout } : {}),
21
+ });
43
22
  };
44
23
  }
45
24
  //# sourceMappingURL=model-runner.js.map
@@ -254,7 +254,7 @@ export function apply(ctx, rawConfig = {}) {
254
254
  const stage = new StageToolRegistry();
255
255
  const engineInput = resolveEngineInput({ modelsRoot: startupParams.mergeModelsRoot });
256
256
  const engineConfig = engineConfigFromRoot(engineInput.modelsRoot);
257
- const llm = ctx.get('llm');
257
+ const llm = ctx.get('evolutionLlm');
258
258
  const defaultModel = ctx.get('agentDefaultModel');
259
259
  const runner = llm === undefined || defaultModel === undefined
260
260
  ? undefined
@@ -3,20 +3,8 @@
3
3
  * this module owns the argument schema and the JSON result. All policy remains in applyStageTool.
4
4
  */
5
5
  import type { EvolutionIoLike } from '@lmzhen/dsh-evolution-core';
6
+ import { defineTool } from '@lmzhen/dsh-evolution-core/platform';
6
7
  import { type StageToolContext } from './stage-tool.ts';
7
8
  export declare const MERGE_STAGE_TOOL_NAME = "merge_stage";
8
- export interface ToolDefinitionLike {
9
- readonly name: string;
10
- readonly description: string;
11
- readonly parameters: Record<string, unknown>;
12
- readonly output: {
13
- readonly schema: Record<string, unknown>;
14
- readonly render: (args: unknown, value: string) => readonly {
15
- readonly type: 'text';
16
- readonly text: string;
17
- }[];
18
- };
19
- readonly execute: (args: Record<string, unknown>, exec: unknown) => Promise<string>;
20
- }
21
- export declare function createMergeStageTool(io: EvolutionIoLike, home: string, context: (exec: unknown) => StageToolContext | undefined, diagnose?: (exec: unknown) => unknown): ToolDefinitionLike;
9
+ export declare function createMergeStageTool(io: EvolutionIoLike, home: string, context: (exec: unknown) => StageToolContext | undefined, diagnose?: (exec: unknown) => unknown): ReturnType<typeof defineTool>;
22
10
  //# sourceMappingURL=merge-tool.d.ts.map
@@ -1,3 +1,4 @@
1
+ import { defineTool } from '@lmzhen/dsh-evolution-core/platform';
1
2
  import { applyStageTool } from "./stage-tool.js";
2
3
  export const MERGE_STAGE_TOOL_NAME = 'merge_stage';
3
4
  function shapeError(message) {
@@ -34,22 +35,17 @@ function operation(args) {
34
35
  return shapeError('op must be list/read/write/copy');
35
36
  }
36
37
  export function createMergeStageTool(io, home, context, diagnose) {
37
- return {
38
+ return defineTool({
38
39
  name: MERGE_STAGE_TOOL_NAME,
39
40
  description: 'Read source copies and write the merged skill into the staging tree. list/read use area=sources|merged plus source (for sources); write/copy paths are relative to merged/<target> (for example path=SKILL.md, from=SKILL.md, to=references/x.md). Write/copy are only allowed in the author phase.',
40
41
  parameters: {
41
- type: 'object',
42
- properties: {
43
- op: { type: 'string', enum: ['list', 'read', 'write', 'copy'] },
44
- area: { type: 'string', enum: ['sources', 'merged'] },
45
- path: { type: 'string' },
46
- source: { type: 'string' },
47
- content: { type: 'string' },
48
- from: { type: 'string' },
49
- to: { type: 'string' },
50
- },
51
- required: ['op'],
52
- additionalProperties: false,
42
+ op: { type: 'string', required: true, enum: ['list', 'read', 'write', 'copy'] },
43
+ area: { type: 'string', enum: ['sources', 'merged'] },
44
+ path: { type: 'string' },
45
+ source: { type: 'string' },
46
+ content: { type: 'string' },
47
+ from: { type: 'string' },
48
+ to: { type: 'string' },
53
49
  },
54
50
  output: {
55
51
  schema: { type: 'string' },
@@ -64,6 +60,6 @@ export function createMergeStageTool(io, home, context, diagnose) {
64
60
  return JSON.stringify({ ok: false, code: 'not-merge-child', message: 'merge_stage is only available to an active merge child', ...(diagnose === undefined ? {} : { diagnostic: diagnose(exec) }) });
65
61
  return JSON.stringify(await applyStageTool(io, home, ctx, op));
66
62
  },
67
- };
63
+ });
68
64
  }
69
65
  //# sourceMappingURL=merge-tool.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-merge",
3
3
  "description": "Skill auto-merge domain: screening, two-round authoring, queues and commit orchestration (community build)",
4
- "version": "0.37.1",
4
+ "version": "0.38.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -32,14 +32,15 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@deepseek-ai/schemastery": "^3.18.5",
35
- "@lmzhen/dsh-evolution-core": "^0.37.1",
36
- "@lmzhen/dsh-evolution-commands": "^0.37.1",
37
- "@lmzhen/dsh-evolution-merge-engine": "0.37.1"
35
+ "@lmzhen/dsh-evolution-core": "^0.38.0",
36
+ "@lmzhen/dsh-evolution-commands": "^0.38.0",
37
+ "@lmzhen/dsh-evolution-merge-engine": "0.38.0"
38
38
  },
39
39
  "peerDependencies": {
40
- "@deepseek-ai/cordis": "^4.0.5"
40
+ "@deepseek-ai/cordis": "^4.0.5",
41
+ "@deepseek-ai/dsh-llm": "^0.2.2-rc.0"
41
42
  },
42
43
  "engines": {
43
- "dsh": ">=0.2.1-rc.2 <0.2.2-0"
44
+ "dsh": ">=0.2.2-rc.0 <0.2.3-0"
44
45
  }
45
46
  }