@lmzhen/dsh-evolution-skill-discovery 0.31.1 → 0.32.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/main-entry.js +2517 -5
- package/lib/types/assignment-queue.d.ts +3 -1
- package/lib/types/assignment-sidecar.d.ts +4 -1
- package/lib/types/awareness.d.ts +4 -1
- package/lib/types/catalog-codec.d.ts +5 -0
- package/lib/types/index.d.ts +0 -12
- package/lib/types/main-entry.d.ts +4 -1
- package/lib/types/projection-journal.d.ts +2 -0
- package/lib/types/tool.d.ts +4 -1
- package/package.json +7 -17
- package/lib/domain-description-3MIOYgVH.js +0 -2105
- package/lib/index.js +0 -764
- package/lib/search-entry.js +0 -88
- package/lib/tool-CvUTwKvW.js +0 -446
- package/lib/types/adapter.d.ts +0 -48
- package/lib/types/domain-metrics.d.ts +0 -41
- package/lib/types/domain-view.d.ts +0 -15
- package/lib/types/features.d.ts +0 -11
- package/lib/types/maintenance.d.ts +0 -62
- package/lib/types/plugin.d.ts +0 -31
- package/lib/types/runtime.d.ts +0 -42
- package/lib/types/search-entry.d.ts +0 -19
- package/lib/types/search-judge.d.ts +0 -26
- package/lib/types/session-projection.d.ts +0 -19
- package/lib/types/session-store.d.ts +0 -22
- package/lib/types/stages.d.ts +0 -6
- package/lib/types/ui.d.ts +0 -69
package/lib/index.js
DELETED
|
@@ -1,764 +0,0 @@
|
|
|
1
|
-
import { $ as DomainMapCorruptError, A as ViewStateRegistry, B as renderProjectionContext, C as DOMAIN_GENERATION_PROMPT, D as DOMAIN_GENERATION_PROMPT_VERSION, E as DOMAIN_GENERATION_PROMPT_V2, F as applyProjectedDecision, G as restoreCatalog, H as captureCatalog, I as applyReplacementDecision, J as projectCatalog, K as buildDomainProjection, L as applyRestoreUpdate, M as canProject, N as deriveViewState, O as buildDomainGenerationPrompt, P as applyCapturedProjection, Q as DOMAIN_MAP_SCHEMA_VERSION, R as captureDecisionCatalog, S as parseDomainGenerationProposal, T as DOMAIN_GENERATION_PROMPT_V1, U as renderCatalog, V as restoreCapturedProjection, W as renderCatalogUpdate, X as evaluateDomainQuality, Y as sanitizeUntrustedText, Z as ProjectionJournal, _ as buildGenerationRequest, a as DISCOVERY_AWARENESS, at as mergeDomainPolicy, b as DomainGenerationError, c as AssignmentWorker, ct as bootstrapDomainMapWithFacts, d as MemoryAssignmentQueue, dt as validateDomainGeneration, et as DomainMapFileStore, f as assignmentKey, g as ViewSnapshotStore, h as validateProposal, i as shouldRegenerateDescription, it as DomainPolicyValidationError, j as canHide, k as ProjectionRuntime, l as JsonAssignmentQueue, lt as domainGenerationMode, m as proposalDigest, n as descriptionIsServable, nt as DomainMapVersionConflict, o as installDiscoveryAwareness, ot as DomainGenerationCoordinator, p as coveredByDomain, q as hiddenRecoverable, r as renderDomainDescription, rt as DomainPolicyStore, s as installAssignmentSidecar, st as bootstrapDomainMap, t as descriptionHashOf, tt as DomainMapValidationError, u as DomainAssignmentService, ut as mintDomainId, v as resolveGenerationPort, w as DOMAIN_GENERATION_PROMPT_HASH, x as LlmDomainGenerationPort, y as bootstrapFactsFromRows, z as findCatalogMessage } from "./domain-description-3MIOYgVH.js";
|
|
2
|
-
import { _ as skillKeyOf, a as SKILL_SEARCH_FIELDS, b as viewKeyOf, c as SkillSearchCache, d as SkillIndex, f as catalogRevisionOf, g as skillIndexRowOf, h as searchIndexKeyOf, i as searchWithDegraded, l as SkillSearchIndex, m as projectionDigestOf, n as isSkillSearch, o as SKILL_SEARCH_INDEX_SCHEMA_VERSION, p as policyDigestOf, r as registerSkillSearchTool, s as SKILL_SEARCH_TOKENIZER_VERSION, t as SKILL_SEARCH_DESCRIPTION, u as searchTerms, v as threeFieldHashOf, y as viewCatalogDigestOf } from "./tool-CvUTwKvW.js";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { authorityFrom, evolutionIoAdapter, evolutionRoot, newSkillLibrary } from "@lmzhen/dsh-evolution-core";
|
|
5
|
-
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
6
|
-
//#region lib/types/adapter.js
|
|
7
|
-
/** @returns true for the platform catalog message. */
|
|
8
|
-
function isCatalogMessage(message) {
|
|
9
|
-
return message.source.kind === "skill-catalog";
|
|
10
|
-
}
|
|
11
|
-
function escapeData(value) {
|
|
12
|
-
return sanitizeUntrustedText(value, 2e3).text;
|
|
13
|
-
}
|
|
14
|
-
function renderCatalog$1(entries) {
|
|
15
|
-
if (entries.length === 0) return [];
|
|
16
|
-
return [
|
|
17
|
-
"<system-reminder>",
|
|
18
|
-
"A skill is a reusable set of task-specific instructions. The following skills are available in this session:",
|
|
19
|
-
"<available_skills>",
|
|
20
|
-
...entries.map((entry) => "- " + escapeData(entry.name) + ": " + escapeData(entry.description)),
|
|
21
|
-
"</available_skills>",
|
|
22
|
-
"Call the skill tool with the exact name before acting.",
|
|
23
|
-
"</system-reminder>"
|
|
24
|
-
];
|
|
25
|
-
}
|
|
26
|
-
/** Build the plugin-owned replacement message from a complete projection. */
|
|
27
|
-
function projectionPresent(agent, digest) {
|
|
28
|
-
try {
|
|
29
|
-
const visible = new Set(agent.session.surface.nodes);
|
|
30
|
-
for (const event of agent.session.snapshotEvents()) {
|
|
31
|
-
if (event.type !== "user/message") continue;
|
|
32
|
-
const data = event.data;
|
|
33
|
-
if (data?.source?.kind !== "evolution-skill-projection" || data.source.digest !== digest) continue;
|
|
34
|
-
if (visible.has(event.seq)) return true;
|
|
35
|
-
}
|
|
36
|
-
} catch {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
function renderProjection(result) {
|
|
42
|
-
const text = [...renderCatalog$1(result.catalogEntries), ...result.context === "" ? [] : [result.context]].join("\n");
|
|
43
|
-
if (text === "") return void 0;
|
|
44
|
-
return createUserMessage({
|
|
45
|
-
content: [{
|
|
46
|
-
type: "text",
|
|
47
|
-
text
|
|
48
|
-
}],
|
|
49
|
-
source: {
|
|
50
|
-
kind: "evolution-skill-projection",
|
|
51
|
-
entries: result.catalogEntries,
|
|
52
|
-
hiddenNames: result.hiddenNames,
|
|
53
|
-
digest: result.digest
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Atomically replace one platform catalog message with the plugin projection.
|
|
59
|
-
* @param decision - the waterfall decision; only enter decisions are changed.
|
|
60
|
-
* @param result - a complete projection; incomplete results are ignored.
|
|
61
|
-
* @returns a new decision, or the original when no safe replacement exists.
|
|
62
|
-
*/
|
|
63
|
-
function applyCatalogProjection(decision, result) {
|
|
64
|
-
if (decision.kind !== "enter" || !result.complete) return decision;
|
|
65
|
-
const index = decision.messages.findIndex(isCatalogMessage);
|
|
66
|
-
if (index < 0) return decision;
|
|
67
|
-
const replacement = renderProjection(result);
|
|
68
|
-
const messages = [...decision.messages];
|
|
69
|
-
if (replacement === void 0) messages.splice(index, 1);
|
|
70
|
-
else messages[index] = replacement;
|
|
71
|
-
return {
|
|
72
|
-
...decision,
|
|
73
|
-
messages
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Install the thin pre-step adapter. The listener is outer; it always calls
|
|
78
|
-
* next, only touches the platform catalog message, and fails open.
|
|
79
|
-
* @param ctx - plugin context.
|
|
80
|
-
* @param provider - projection provider backed by SkillIndex/DomainMap.
|
|
81
|
-
* @returns disposer from ctx.on.
|
|
82
|
-
*/
|
|
83
|
-
function installCatalogProjection(ctx, provider, digestStore) {
|
|
84
|
-
const projectedDigest = /* @__PURE__ */ new Map();
|
|
85
|
-
return ctx.on("agent/pre-step", async ({ agent }, next) => {
|
|
86
|
-
const decision = await next();
|
|
87
|
-
if (decision.kind !== "enter") return decision;
|
|
88
|
-
const catalog = decision.messages.find(isCatalogMessage);
|
|
89
|
-
if (catalog === void 0) return decision;
|
|
90
|
-
try {
|
|
91
|
-
if (provider.shouldProject !== void 0 && !await provider.shouldProject(agent)) return decision;
|
|
92
|
-
const result = await provider.project({
|
|
93
|
-
agent,
|
|
94
|
-
catalogEntries: catalog.source.entries
|
|
95
|
-
});
|
|
96
|
-
if (!result.complete) return decision;
|
|
97
|
-
const agentKey = String(agent.id);
|
|
98
|
-
if ((projectedDigest.get(agentKey) ?? await digestStore?.get(agentKey)) === result.digest && projectionPresent(agent, result.digest)) return {
|
|
99
|
-
...decision,
|
|
100
|
-
messages: decision.messages.filter((message) => !isCatalogMessage(message))
|
|
101
|
-
};
|
|
102
|
-
const nextDecision = applyCatalogProjection(decision, result);
|
|
103
|
-
if (nextDecision !== decision) {
|
|
104
|
-
projectedDigest.set(agentKey, result.digest);
|
|
105
|
-
await digestStore?.set(agentKey, result.digest);
|
|
106
|
-
}
|
|
107
|
-
return nextDecision;
|
|
108
|
-
} catch {
|
|
109
|
-
return decision;
|
|
110
|
-
}
|
|
111
|
-
}, { prepend: true });
|
|
112
|
-
}
|
|
113
|
-
//#endregion
|
|
114
|
-
//#region lib/types/features.js
|
|
115
|
-
const V0_DISCOVERY_FEATURES = Object.freeze({
|
|
116
|
-
projectionEnabled: false,
|
|
117
|
-
searchEnabled: false,
|
|
118
|
-
createClassificationEnabled: false,
|
|
119
|
-
discoveryMode: "off"
|
|
120
|
-
});
|
|
121
|
-
function canClassifyAtCreate(config, hasCreateDomainCards) {
|
|
122
|
-
return config.createClassificationEnabled && hasCreateDomainCards;
|
|
123
|
-
}
|
|
124
|
-
//#endregion
|
|
125
|
-
//#region lib/types/stages.js
|
|
126
|
-
/** Ordered implementation stages from PLAN-DISC-001. */
|
|
127
|
-
const DISCOVERY_STAGES = [
|
|
128
|
-
"G0-projection",
|
|
129
|
-
"G1-domain",
|
|
130
|
-
"G2-projection",
|
|
131
|
-
"G3-search",
|
|
132
|
-
"G4-assignment",
|
|
133
|
-
"G5-maintenance",
|
|
134
|
-
"G6-ui",
|
|
135
|
-
"G7-migration",
|
|
136
|
-
"G8-release"
|
|
137
|
-
];
|
|
138
|
-
function stageIndex(stage) {
|
|
139
|
-
return DISCOVERY_STAGES.indexOf(stage);
|
|
140
|
-
}
|
|
141
|
-
function mayAdvance(current, next) {
|
|
142
|
-
return stageIndex(next) === stageIndex(current) + 1;
|
|
143
|
-
}
|
|
144
|
-
//#endregion
|
|
145
|
-
//#region lib/types/domain-view.js
|
|
146
|
-
/**
|
|
147
|
-
* Count visible skills by active domain membership.
|
|
148
|
-
* @param snapshot - global domain facts.
|
|
149
|
-
* @param visibleSkillKeys - skill keys visible in this view.
|
|
150
|
-
* @returns per-domain member counts plus the unclassified virtual count.
|
|
151
|
-
*/
|
|
152
|
-
function domainViewCounts(snapshot, visibleSkillKeys) {
|
|
153
|
-
const byDomain = /* @__PURE__ */ new Map();
|
|
154
|
-
const classified = /* @__PURE__ */ new Set();
|
|
155
|
-
for (const edge of snapshot.edges) {
|
|
156
|
-
if (edge.status !== "active" || !visibleSkillKeys.has(edge.skillKey)) continue;
|
|
157
|
-
const set = byDomain.get(edge.domainId) ?? /* @__PURE__ */ new Set();
|
|
158
|
-
set.add(edge.skillKey);
|
|
159
|
-
byDomain.set(edge.domainId, set);
|
|
160
|
-
if (edge.role === "primary") classified.add(edge.skillKey);
|
|
161
|
-
}
|
|
162
|
-
const counts = /* @__PURE__ */ new Map();
|
|
163
|
-
for (const [domainId, members] of byDomain) counts.set(domainId, members.size);
|
|
164
|
-
return {
|
|
165
|
-
byDomain: counts,
|
|
166
|
-
unclassified: [...visibleSkillKeys].filter((key) => !classified.has(key)).length
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
//#endregion
|
|
170
|
-
//#region lib/types/domain-metrics.js
|
|
171
|
-
/**
|
|
172
|
-
* @param snapshot - domain facts.
|
|
173
|
-
* @param visibleSkillKeys - skills visible in this view.
|
|
174
|
-
* @param labels - optional assignment labels.
|
|
175
|
-
* @returns metrics; null means the denominator is zero/unmeasured.
|
|
176
|
-
*/
|
|
177
|
-
function computeDomainMetrics(snapshot, visibleSkillKeys, labels, counters) {
|
|
178
|
-
const visible = visibleSkillKeys.size;
|
|
179
|
-
const primary = /* @__PURE__ */ new Set();
|
|
180
|
-
const domainsWithActiveMembers = /* @__PURE__ */ new Set();
|
|
181
|
-
let activeEdges = 0;
|
|
182
|
-
let pendingEdges = 0;
|
|
183
|
-
const memberships = /* @__PURE__ */ new Map();
|
|
184
|
-
for (const edge of snapshot.edges) {
|
|
185
|
-
if (edge.status === "pending") pendingEdges += 1;
|
|
186
|
-
if (edge.status !== "active") continue;
|
|
187
|
-
activeEdges += 1;
|
|
188
|
-
if (!visibleSkillKeys.has(edge.skillKey)) continue;
|
|
189
|
-
if (edge.role === "primary") primary.add(edge.skillKey);
|
|
190
|
-
domainsWithActiveMembers.add(edge.domainId);
|
|
191
|
-
memberships.set(edge.skillKey, (memberships.get(edge.skillKey) ?? 0) + 1);
|
|
192
|
-
}
|
|
193
|
-
const crossDomain = [...memberships.values()].filter((count) => count > 1).length;
|
|
194
|
-
const emptyDomainCount = snapshot.domains.filter((domain) => !domainsWithActiveMembers.has(domain.id)).length;
|
|
195
|
-
const assignmentAccuracy = labels === void 0 ? null : accuracy(labels);
|
|
196
|
-
const staleDescriptions = snapshot.domains.filter((domain) => domain.descriptionStatus === "stale").length;
|
|
197
|
-
const overAssigned = counters?.maxDomainsPerSkill === void 0 ? null : [...memberships.values()].filter((count) => count > counters.maxDomainsPerSkill).length;
|
|
198
|
-
return {
|
|
199
|
-
measured: visible > 0,
|
|
200
|
-
visibleSkills: visible,
|
|
201
|
-
coverage: visible === 0 ? null : primary.size / visible,
|
|
202
|
-
unclassifiedRatio: visible === 0 ? null : (visible - primary.size) / visible,
|
|
203
|
-
emptyDomainCount,
|
|
204
|
-
crossDomainRatio: primary.size === 0 ? null : crossDomain / primary.size,
|
|
205
|
-
pendingRate: activeEdges + pendingEdges === 0 ? null : pendingEdges / (activeEdges + pendingEdges),
|
|
206
|
-
assignmentAccuracy,
|
|
207
|
-
newDomainPrecision: labels?.newDomainIds === void 0 || labels.predictedNewDomainIds === void 0 || labels.newDomainIds.length === 0 ? null : precision(labels.newDomainIds, labels.predictedNewDomainIds),
|
|
208
|
-
descriptionRewriteRate: counters?.descriptionEligible === void 0 || counters.descriptionEligible === 0 ? null : (counters.descriptionRewritten ?? 0) / counters.descriptionEligible,
|
|
209
|
-
staleDescriptionRatio: snapshot.domains.length === 0 ? null : staleDescriptions / snapshot.domains.length,
|
|
210
|
-
overAssignmentRate: overAssigned === null || visible === 0 ? null : overAssigned / visible,
|
|
211
|
-
refusalRate: counters?.assignmentAttempts === void 0 || counters.assignmentAttempts === 0 ? null : (counters.refusedAssignments ?? 0) / counters.assignmentAttempts
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
function accuracy(labels) {
|
|
215
|
-
const keys = Object.keys(labels.expectedBySkill).filter((key) => labels.predictedBySkill[key] !== void 0);
|
|
216
|
-
if (keys.length === 0) return null;
|
|
217
|
-
return keys.filter((key) => labels.expectedBySkill[key] === labels.predictedBySkill[key]).length / keys.length;
|
|
218
|
-
}
|
|
219
|
-
function precision(expected, predicted) {
|
|
220
|
-
if (predicted.length === 0) return null;
|
|
221
|
-
const wanted = new Set(expected);
|
|
222
|
-
return predicted.filter((id) => wanted.has(id)).length / predicted.length;
|
|
223
|
-
}
|
|
224
|
-
//#endregion
|
|
225
|
-
//#region lib/types/session-projection.js
|
|
226
|
-
/** @returns true only for a new, fully-enabled session in the current epoch. */
|
|
227
|
-
function shouldHideCatalog(meta, currentFeatureEpoch) {
|
|
228
|
-
return meta?.discoveryMode === "on" && meta.featureEpoch === currentFeatureEpoch;
|
|
229
|
-
}
|
|
230
|
-
/** @returns true when awareness may be emitted (shadow or on). */
|
|
231
|
-
function shouldEmitAwareness(meta, currentFeatureEpoch) {
|
|
232
|
-
return (meta?.discoveryMode === "on" || meta?.discoveryMode === "shadow") && meta.featureEpoch === currentFeatureEpoch;
|
|
233
|
-
}
|
|
234
|
-
/** @returns false when the same digest was already emitted in this session. */
|
|
235
|
-
function shouldEmitDigest(previousDigest, nextDigest) {
|
|
236
|
-
return previousDigest !== nextDigest;
|
|
237
|
-
}
|
|
238
|
-
/** @returns off at <=2200 tokens, on at >=3000, shadow between. */
|
|
239
|
-
function projectionBudgetMode(catalogTokens, promoted = false) {
|
|
240
|
-
if (catalogTokens <= 2200) return "off";
|
|
241
|
-
if (promoted && catalogTokens >= 3e3) return "on";
|
|
242
|
-
return "shadow";
|
|
243
|
-
}
|
|
244
|
-
/** @returns true when a resumed session already enabled discovery. */
|
|
245
|
-
function shouldInstallAwarenessOnResume(record, featureEpoch) {
|
|
246
|
-
return record !== void 0 && record.discoveryMode !== "off" && record.featureEpoch === featureEpoch;
|
|
247
|
-
}
|
|
248
|
-
//#endregion
|
|
249
|
-
//#region lib/types/maintenance.js
|
|
250
|
-
/** Maintenance defaults from PLAN/MAP-009. */
|
|
251
|
-
const MAINTENANCE_DEFAULTS = Object.freeze({
|
|
252
|
-
splitSkillThreshold: 25,
|
|
253
|
-
coarsenDomainCount: 12,
|
|
254
|
-
maxVisibleDepth: 3,
|
|
255
|
-
minChildren: 2,
|
|
256
|
-
minMembersPerChild: 3,
|
|
257
|
-
coarsenMinDomains: 3,
|
|
258
|
-
coarsenMaxDomains: 8
|
|
259
|
-
});
|
|
260
|
-
function directMembers(snapshot, domainId) {
|
|
261
|
-
return new Set(snapshot.edges.filter((edge) => edge.status === "active" && edge.domainId === domainId).map((edge) => edge.skillKey));
|
|
262
|
-
}
|
|
263
|
-
function descendants(snapshot, domainId) {
|
|
264
|
-
const result = /* @__PURE__ */ new Set();
|
|
265
|
-
const queue = [domainId];
|
|
266
|
-
while (queue.length > 0) {
|
|
267
|
-
const current = queue.shift();
|
|
268
|
-
for (const node of snapshot.domains) {
|
|
269
|
-
if (!node.parentIds.includes(current) || result.has(node.id)) continue;
|
|
270
|
-
result.add(node.id);
|
|
271
|
-
queue.push(node.id);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
return result;
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Audit domain definitions/structure without mutating the map.
|
|
278
|
-
* @param snapshot - domain facts.
|
|
279
|
-
* @param visibleSkillKeys - optional view skills for unclassified count.
|
|
280
|
-
* @returns per-domain audit plus map-level counts.
|
|
281
|
-
*/
|
|
282
|
-
function auditDomainMap(snapshot, visibleSkillKeys) {
|
|
283
|
-
const ids = new Set(snapshot.domains.map((node) => node.id));
|
|
284
|
-
const primary = /* @__PURE__ */ new Set();
|
|
285
|
-
for (const edge of snapshot.edges) if (edge.status === "active" && edge.role === "primary") primary.add(edge.skillKey);
|
|
286
|
-
const domains = snapshot.domains.map((node) => {
|
|
287
|
-
const direct = directMembers(snapshot, node.id);
|
|
288
|
-
const indirect = /* @__PURE__ */ new Set();
|
|
289
|
-
for (const child of descendants(snapshot, node.id)) for (const member of directMembers(snapshot, child)) indirect.add(member);
|
|
290
|
-
const definitionComplete = node.purpose.trim().length > 0 && node.inScope.length > 0 && node.outOfScope.length > 0 && node.triggers.length > 0;
|
|
291
|
-
return {
|
|
292
|
-
domainId: node.id,
|
|
293
|
-
definitionComplete,
|
|
294
|
-
childCount: snapshot.domains.filter((child) => child.parentIds.includes(node.id)).length,
|
|
295
|
-
directSkillCount: direct.size,
|
|
296
|
-
indirectSkillCount: indirect.size,
|
|
297
|
-
empty: direct.size === 0,
|
|
298
|
-
orphan: node.parentIds.some((parent) => !ids.has(parent)),
|
|
299
|
-
lastUpdated: node.updatedAt
|
|
300
|
-
};
|
|
301
|
-
});
|
|
302
|
-
const unclassifiedCount = [...visibleSkillKeys ?? new Set(snapshot.edges.map((edge) => edge.skillKey))].filter((key) => !primary.has(key)).length;
|
|
303
|
-
return {
|
|
304
|
-
domains,
|
|
305
|
-
domainCount: domains.length,
|
|
306
|
-
unclassifiedCount
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* Find split candidates; no child domains are created and no skills are reassigned.
|
|
311
|
-
* @param snapshot - domain facts.
|
|
312
|
-
* @param threshold - minimum direct members to consider.
|
|
313
|
-
* @returns candidates with blockers.
|
|
314
|
-
*/
|
|
315
|
-
function splitCandidates(snapshot, threshold = MAINTENANCE_DEFAULTS.splitSkillThreshold) {
|
|
316
|
-
return snapshot.domains.flatMap((node) => {
|
|
317
|
-
const direct = directMembers(snapshot, node.id).size;
|
|
318
|
-
if (direct < threshold) return [];
|
|
319
|
-
const children = Math.min(MAINTENANCE_DEFAULTS.coarsenMaxDomains, Math.floor(direct / MAINTENANCE_DEFAULTS.minMembersPerChild));
|
|
320
|
-
const blockers = [];
|
|
321
|
-
if (children < MAINTENANCE_DEFAULTS.minChildren) blockers.push("fewer-than-2-children");
|
|
322
|
-
return [{
|
|
323
|
-
domainId: node.id,
|
|
324
|
-
directSkillCount: direct,
|
|
325
|
-
children,
|
|
326
|
-
blockers
|
|
327
|
-
}];
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* Find coarsen groups; only structure candidates, never edge rewrites.
|
|
332
|
-
* @param snapshot - domain facts.
|
|
333
|
-
* @param maxDomains - above this count coarsening is considered.
|
|
334
|
-
* @returns groups of 3–8 domains, at least 2 groups.
|
|
335
|
-
*/
|
|
336
|
-
function coarsenCandidates(snapshot, maxDomains = MAINTENANCE_DEFAULTS.coarsenDomainCount) {
|
|
337
|
-
if (snapshot.domains.length <= maxDomains) return [];
|
|
338
|
-
const ids = snapshot.domains.map((node) => node.id).sort();
|
|
339
|
-
const size = Math.min(MAINTENANCE_DEFAULTS.coarsenMaxDomains, Math.max(MAINTENANCE_DEFAULTS.coarsenMinDomains, Math.ceil(ids.length / 2)));
|
|
340
|
-
const groups = [];
|
|
341
|
-
for (let index = 0; index < ids.length; index += size) groups.push({ domainIds: ids.slice(index, index + size) });
|
|
342
|
-
return groups.length >= 2 ? groups : [];
|
|
343
|
-
}
|
|
344
|
-
//#endregion
|
|
345
|
-
//#region lib/types/ui.js
|
|
346
|
-
const POLICY_KEYS = new Set([
|
|
347
|
-
"mode",
|
|
348
|
-
"maxCards",
|
|
349
|
-
"tokenBudget",
|
|
350
|
-
"staleAfterHours",
|
|
351
|
-
"pinDomains",
|
|
352
|
-
"disableDomains"
|
|
353
|
-
]);
|
|
354
|
-
const MODES = new Set([
|
|
355
|
-
"auto",
|
|
356
|
-
"off",
|
|
357
|
-
"on"
|
|
358
|
-
]);
|
|
359
|
-
/** @returns true when the policy only edits supported fields. */
|
|
360
|
-
function isDiscoveryUserPolicy(value) {
|
|
361
|
-
if (typeof value !== "object" || value === null) return false;
|
|
362
|
-
const record = value;
|
|
363
|
-
if (Object.keys(record).some((key) => !POLICY_KEYS.has(key))) return false;
|
|
364
|
-
if (record.mode !== void 0 && (typeof record.mode !== "string" || !MODES.has(record.mode))) return false;
|
|
365
|
-
if (record.maxCards !== void 0 && (typeof record.maxCards !== "number" || !Number.isSafeInteger(record.maxCards) || record.maxCards < 1)) return false;
|
|
366
|
-
if (record.tokenBudget !== void 0 && (typeof record.tokenBudget !== "number" || !Number.isSafeInteger(record.tokenBudget) || record.tokenBudget < 1)) return false;
|
|
367
|
-
if (record.staleAfterHours !== void 0 && (typeof record.staleAfterHours !== "number" || record.staleAfterHours <= 0)) return false;
|
|
368
|
-
if (record.pinDomains !== void 0 && !Array.isArray(record.pinDomains)) return false;
|
|
369
|
-
if (record.disableDomains !== void 0 && !Array.isArray(record.disableDomains)) return false;
|
|
370
|
-
return true;
|
|
371
|
-
}
|
|
372
|
-
/** Static skill_manage description; no dynamic domain list/count/tree. */
|
|
373
|
-
const SKILL_MANAGE_DESCRIPTION = "Manage skill content. create may include an optional domain proposal when create-side domain cards are available; no proposal means unclassified. Domain assignment never blocks skill creation and is stored as a sidecar.";
|
|
374
|
-
/** @returns recomputable behavior metrics; null means no denominator. */
|
|
375
|
-
function computeBehaviorMetrics(observations) {
|
|
376
|
-
const total = observations.length;
|
|
377
|
-
const shown = observations.filter((item) => item.awarenessShown).length;
|
|
378
|
-
const searched = observations.filter((item) => item.searched).length;
|
|
379
|
-
const successes = observations.filter((item) => item.taskSuccess).length;
|
|
380
|
-
return {
|
|
381
|
-
awarenessRecall: shown === 0 ? null : observations.filter((item) => item.awarenessShown && item.awarenessRecalled).length / shown,
|
|
382
|
-
silentMissRate: shown === 0 ? null : observations.filter((item) => item.silentMiss).length / shown,
|
|
383
|
-
overSearchRate: searched === 0 ? null : observations.filter((item) => item.searched && item.overSearch).length / searched,
|
|
384
|
-
underSearchRate: searched === 0 ? null : observations.filter((item) => item.searched && item.underSearch).length / searched,
|
|
385
|
-
wrongLoadRate: searched === 0 ? null : observations.filter((item) => item.searched && item.wrongLoad).length / searched,
|
|
386
|
-
taskSuccess: total === 0 ? null : successes / total,
|
|
387
|
-
tokens: observations.reduce((sum, item) => sum + item.tokens, 0),
|
|
388
|
-
fallbackRate: searched === 0 ? null : observations.filter((item) => item.searched && item.fallback).length / searched,
|
|
389
|
-
total
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
//#endregion
|
|
393
|
-
//#region lib/types/session-store.js
|
|
394
|
-
/** Plugin-side session metadata; platform SessionHeader has no discovery fields. */
|
|
395
|
-
var DiscoverySessionStore = class {
|
|
396
|
-
io;
|
|
397
|
-
path;
|
|
398
|
-
constructor(io, path) {
|
|
399
|
-
this.io = io;
|
|
400
|
-
this.path = path;
|
|
401
|
-
}
|
|
402
|
-
async read() {
|
|
403
|
-
const content = await this.io.readText(this.path);
|
|
404
|
-
if (content === null) return {
|
|
405
|
-
schemaVersion: 1,
|
|
406
|
-
sessions: {}
|
|
407
|
-
};
|
|
408
|
-
try {
|
|
409
|
-
const parsed = JSON.parse(content);
|
|
410
|
-
return parsed.schemaVersion === 1 && typeof parsed.sessions === "object" && parsed.sessions !== null ? {
|
|
411
|
-
schemaVersion: 1,
|
|
412
|
-
sessions: parsed.sessions
|
|
413
|
-
} : {
|
|
414
|
-
schemaVersion: 1,
|
|
415
|
-
sessions: {}
|
|
416
|
-
};
|
|
417
|
-
} catch {
|
|
418
|
-
return {
|
|
419
|
-
schemaVersion: 1,
|
|
420
|
-
sessions: {}
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
/** @returns persisted metadata for one session. */
|
|
425
|
-
async get(sessionId) {
|
|
426
|
-
const entry = (await this.read()).sessions[sessionId];
|
|
427
|
-
return entry === void 0 ? void 0 : {
|
|
428
|
-
sessionId,
|
|
429
|
-
...entry
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
/** Persist one session's mode/epoch; later writes win. */
|
|
433
|
-
async put(record) {
|
|
434
|
-
const current = await this.read();
|
|
435
|
-
const previous = current.sessions[record.sessionId];
|
|
436
|
-
const projectionDigest = record.projectionDigest ?? previous?.projectionDigest;
|
|
437
|
-
const sessions = {
|
|
438
|
-
...current.sessions,
|
|
439
|
-
[record.sessionId]: {
|
|
440
|
-
discoveryMode: record.discoveryMode,
|
|
441
|
-
featureEpoch: record.featureEpoch,
|
|
442
|
-
...projectionDigest === void 0 ? {} : { projectionDigest }
|
|
443
|
-
}
|
|
444
|
-
};
|
|
445
|
-
await this.io.writeText(this.path, JSON.stringify({
|
|
446
|
-
schemaVersion: 1,
|
|
447
|
-
sessions
|
|
448
|
-
}));
|
|
449
|
-
}
|
|
450
|
-
};
|
|
451
|
-
/** @returns true only for a persisted enabled session in the current feature epoch. */
|
|
452
|
-
async function shouldProjectPersistedSession(store, sessionId, currentFeatureEpoch) {
|
|
453
|
-
return shouldHideCatalog(await store.get(sessionId), currentFeatureEpoch);
|
|
454
|
-
}
|
|
455
|
-
//#endregion
|
|
456
|
-
//#region lib/types/runtime.js
|
|
457
|
-
/** G2 adapter provider wired from ports; no global platform dependency. */
|
|
458
|
-
var DiscoveryRuntime = class {
|
|
459
|
-
ports;
|
|
460
|
-
constructor(ports) {
|
|
461
|
-
this.ports = ports;
|
|
462
|
-
}
|
|
463
|
-
/** @returns true only when persisted session metadata allows projection. */
|
|
464
|
-
async shouldProject(agent) {
|
|
465
|
-
return shouldEmitAwareness(await this.ports.sessionStore.get(agent.session.id), this.ports.featureEpoch);
|
|
466
|
-
}
|
|
467
|
-
/** @returns a complete projection for this agent's catalog entries. */
|
|
468
|
-
async project(input) {
|
|
469
|
-
const view = await new SkillIndex(this.ports.skillIndexSource).read({
|
|
470
|
-
cwd: input.agent.session.header.cwd ?? "",
|
|
471
|
-
scopeKey: String(input.agent.id),
|
|
472
|
-
scope: input.agent
|
|
473
|
-
});
|
|
474
|
-
const snapshot = await this.ports.map.read();
|
|
475
|
-
const estimatedTokens = Math.ceil(input.catalogEntries.reduce((sum, entry) => sum + entry.name.length + entry.description.length, 0) / 4);
|
|
476
|
-
const promoted = typeof this.ports.promoted === "function" ? this.ports.promoted() : this.ports.promoted === true;
|
|
477
|
-
const autoMode = this.ports.autoMode === true ? projectionBudgetMode(estimatedTokens, promoted) : this.ports.mode;
|
|
478
|
-
const result = buildDomainProjection({
|
|
479
|
-
entries: input.catalogEntries,
|
|
480
|
-
rows: view.rows,
|
|
481
|
-
complete: view.complete,
|
|
482
|
-
snapshot,
|
|
483
|
-
policy: this.ports.policy,
|
|
484
|
-
viewKey: view.viewKey,
|
|
485
|
-
scope: String(input.agent.id),
|
|
486
|
-
mapVersion: snapshot.mapVersion,
|
|
487
|
-
policyDigest: this.ports.policyDigest,
|
|
488
|
-
viewCatalogDigest: view.viewCatalogDigest,
|
|
489
|
-
adapterVersion: this.ports.adapterVersion,
|
|
490
|
-
projectionSchemaVersion: this.ports.projectionSchemaVersion,
|
|
491
|
-
discoveryMode: this.ports.autoMode === true ? autoMode ?? "shadow" : this.ports.discoveryMode,
|
|
492
|
-
maxCards: this.ports.maxCards,
|
|
493
|
-
tokenBudget: this.ports.tokenBudget,
|
|
494
|
-
staleAfterHours: this.ports.staleAfterHours,
|
|
495
|
-
maxVisibleDepth: this.ports.maxVisibleDepth,
|
|
496
|
-
now: Date.now(),
|
|
497
|
-
mode: autoMode,
|
|
498
|
-
mapStale: this.ports.mapStale,
|
|
499
|
-
searchAvailable: this.ports.searchAvailable
|
|
500
|
-
});
|
|
501
|
-
this.ports.onProjection?.(result);
|
|
502
|
-
return result;
|
|
503
|
-
}
|
|
504
|
-
};
|
|
505
|
-
//#endregion
|
|
506
|
-
//#region lib/types/search-judge.js
|
|
507
|
-
/** Validate a judge packet without accepting partial query coverage. */
|
|
508
|
-
function validateJudgeRecord(record, expectedQueryIds) {
|
|
509
|
-
const errors = [];
|
|
510
|
-
if (record.schemaVersion !== 1 || record.querySet !== "eval-010" || record.judgeKind !== "model" && record.judgeKind !== "human") errors.push("schema-invalid");
|
|
511
|
-
if (record.judgeId.trim().length === 0) errors.push("judge-id-missing");
|
|
512
|
-
const seen = /* @__PURE__ */ new Set();
|
|
513
|
-
for (const observation of record.observations) {
|
|
514
|
-
if (!expectedQueryIds.includes(observation.queryId)) errors.push("unknown-query:" + observation.queryId);
|
|
515
|
-
if (seen.has(observation.queryId)) errors.push("duplicate-query:" + observation.queryId);
|
|
516
|
-
seen.add(observation.queryId);
|
|
517
|
-
}
|
|
518
|
-
for (const id of expectedQueryIds) if (!seen.has(id)) errors.push("missing-query:" + id);
|
|
519
|
-
return errors;
|
|
520
|
-
}
|
|
521
|
-
/** @returns aggregate over model/human records; agreement only for shared queries. */
|
|
522
|
-
function aggregateJudge(records, expectedQueryIds) {
|
|
523
|
-
const model = records.find((record) => record.judgeKind === "model");
|
|
524
|
-
const human = records.find((record) => record.judgeKind === "human");
|
|
525
|
-
const modelLabels = new Map(model?.observations.map((item) => [item.queryId, item.relevant]) ?? []);
|
|
526
|
-
const humanLabels = new Map(human?.observations.map((item) => [item.queryId, item.relevant]) ?? []);
|
|
527
|
-
const union = [...new Set([...modelLabels.keys(), ...humanLabels.keys()])];
|
|
528
|
-
const relevant = union.filter((id) => (modelLabels.get(id) ?? humanLabels.get(id)) === true).length;
|
|
529
|
-
const shared = [...modelLabels.keys()].filter((id) => humanLabels.has(id));
|
|
530
|
-
return {
|
|
531
|
-
queryCount: expectedQueryIds.length,
|
|
532
|
-
relevantRate: union.length === 0 ? null : relevant / union.length,
|
|
533
|
-
agreementRate: shared.length === 0 ? null : shared.filter((id) => modelLabels.get(id) === humanLabels.get(id)).length / shared.length,
|
|
534
|
-
hasModel: model !== void 0,
|
|
535
|
-
hasHuman: human !== void 0
|
|
536
|
-
};
|
|
537
|
-
}
|
|
538
|
-
//#endregion
|
|
539
|
-
//#region lib/types/domain-generation-service.js
|
|
540
|
-
/**
|
|
541
|
-
* Generate and persist the initial map only when the map has no domains.
|
|
542
|
-
* @param store - map owner.
|
|
543
|
-
* @param port - external LLM adapter.
|
|
544
|
-
* @param skills - name/description/whenToUse facts.
|
|
545
|
-
* @param skillKeys - evidence name -> stable key.
|
|
546
|
-
* @param expectedMapVersion - CAS precondition.
|
|
547
|
-
* @returns committed snapshot, or existing snapshot when already bootstrapped.
|
|
548
|
-
*/
|
|
549
|
-
async function initialDomainMap(store, port, skills, skillKeys, expectedMapVersion, signal, prompt = DOMAIN_GENERATION_PROMPT) {
|
|
550
|
-
const current = await store.read();
|
|
551
|
-
if (current.domains.length > 0) return current;
|
|
552
|
-
return bootstrapDomainMap(store, await port.generate({
|
|
553
|
-
skills,
|
|
554
|
-
prompt,
|
|
555
|
-
...signal === void 0 ? {} : { signal }
|
|
556
|
-
}), skillKeys, expectedMapVersion);
|
|
557
|
-
}
|
|
558
|
-
//#endregion
|
|
559
|
-
//#region lib/types/plugin.js
|
|
560
|
-
const name = "evolution-skill-discovery";
|
|
561
|
-
const inject = [
|
|
562
|
-
"skills",
|
|
563
|
-
"evolutionIo",
|
|
564
|
-
"systemPrompt",
|
|
565
|
-
"tools"
|
|
566
|
-
];
|
|
567
|
-
var PlatformSkillIndexSource = class {
|
|
568
|
-
ctx;
|
|
569
|
-
library;
|
|
570
|
-
constructor(ctx, library) {
|
|
571
|
-
this.ctx = ctx;
|
|
572
|
-
this.library = library;
|
|
573
|
-
}
|
|
574
|
-
async snapshot(query) {
|
|
575
|
-
const snapshot = await this.ctx.skills.snapshot({
|
|
576
|
-
cwd: query.cwd,
|
|
577
|
-
...query.scope === void 0 ? {} : { scope: query.scope }
|
|
578
|
-
});
|
|
579
|
-
return {
|
|
580
|
-
skills: snapshot.skills,
|
|
581
|
-
complete: snapshot.complete
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
async managedSkillKeys() {
|
|
585
|
-
const summaries = await this.library.list();
|
|
586
|
-
return new Set(summaries.filter((summary) => summary.managed).map((summary) => skillKeyOf({
|
|
587
|
-
provider: "dsh-evolution",
|
|
588
|
-
source: "user-dsh",
|
|
589
|
-
name: summary.name
|
|
590
|
-
})));
|
|
591
|
-
}
|
|
592
|
-
async protectedSkillKeys() {
|
|
593
|
-
const summaries = await this.library.list();
|
|
594
|
-
return new Set(summaries.filter((summary) => summary.protectedBy !== null || summary.protectionUnknown).map((summary) => skillKeyOf({
|
|
595
|
-
provider: "dsh-evolution",
|
|
596
|
-
source: "user-dsh",
|
|
597
|
-
name: summary.name
|
|
598
|
-
})));
|
|
599
|
-
}
|
|
600
|
-
async pinnedSkillKeys() {
|
|
601
|
-
const summaries = await this.library.list();
|
|
602
|
-
return new Set(summaries.filter((summary) => summary.protectedBy === "pinned").map((summary) => skillKeyOf({
|
|
603
|
-
provider: "dsh-evolution",
|
|
604
|
-
source: "user-dsh",
|
|
605
|
-
name: summary.name
|
|
606
|
-
})));
|
|
607
|
-
}
|
|
608
|
-
};
|
|
609
|
-
/** Compose discovery services from platform ports; no catalog/provider replacement. */
|
|
610
|
-
function apply(ctx, config) {
|
|
611
|
-
if (typeof config.featureEpoch !== "string" || config.featureEpoch.length === 0) throw new Error("evolution-skill-discovery: featureEpoch is required");
|
|
612
|
-
if (config.provisionalThreshold !== void 0 && (!Number.isSafeInteger(config.provisionalThreshold) || config.provisionalThreshold < 1)) throw new Error("evolution-skill-discovery: provisionalThreshold must be a positive integer");
|
|
613
|
-
const evolutionIo = ctx.evolutionIo;
|
|
614
|
-
const io = evolutionIoAdapter(() => evolutionIo.provider());
|
|
615
|
-
const source = new PlatformSkillIndexSource(ctx, newSkillLibrary({
|
|
616
|
-
config: {},
|
|
617
|
-
io,
|
|
618
|
-
ctx,
|
|
619
|
-
authority: authorityFrom({ origin: "foreground" })
|
|
620
|
-
}));
|
|
621
|
-
const dshHome = evolutionRoot();
|
|
622
|
-
const map = new DomainMapFileStore(io, config.domainMapPath ?? join(dshHome, "evolution", "domain-map.json"));
|
|
623
|
-
if (config.domainGeneration !== void 0 && config.domainGenerationSkills !== void 0 && config.domainGenerationSkillKeys !== void 0) initialDomainMap(map, config.domainGeneration, config.domainGenerationSkills, config.domainGenerationSkillKeys, "0", void 0, buildDomainGenerationPrompt({
|
|
624
|
-
...config.domainMinDomains === void 0 ? {} : { minDomains: config.domainMinDomains },
|
|
625
|
-
...config.domainMaxDomains === void 0 ? {} : { maxDomains: config.domainMaxDomains }
|
|
626
|
-
})).catch(() => {});
|
|
627
|
-
if (config.bootstrapDomains !== void 0 && config.bootstrapSkillKeys !== void 0) bootstrapDomainMap(map, config.bootstrapDomains, config.bootstrapSkillKeys, "0").catch(() => {});
|
|
628
|
-
const sessions = new DiscoverySessionStore(io, config.sessionPath ?? join(dshHome, "evolution", "discovery-sessions.json"));
|
|
629
|
-
const policy = mergeDomainPolicy({
|
|
630
|
-
mode: config.mode === "shadow" || config.mode === void 0 || config.mode === "auto" ? "auto" : config.mode,
|
|
631
|
-
pinDomains: config.pinDomains,
|
|
632
|
-
disableDomains: config.disableDomains
|
|
633
|
-
});
|
|
634
|
-
const policyDigest = policyDigestOf({
|
|
635
|
-
globalPolicyRevision: "config",
|
|
636
|
-
effectivePolicy: {
|
|
637
|
-
mode: policy.mode,
|
|
638
|
-
pinned: policy.pinned,
|
|
639
|
-
disabled: policy.disabled
|
|
640
|
-
}
|
|
641
|
-
});
|
|
642
|
-
const runtime = new DiscoveryRuntime({
|
|
643
|
-
skillIndexSource: source,
|
|
644
|
-
map,
|
|
645
|
-
policy,
|
|
646
|
-
sessionStore: sessions,
|
|
647
|
-
featureEpoch: config.featureEpoch,
|
|
648
|
-
mapVersion: "0",
|
|
649
|
-
policyDigest,
|
|
650
|
-
adapterVersion: "1",
|
|
651
|
-
projectionSchemaVersion: "1",
|
|
652
|
-
discoveryMode: config.mode === "auto" ? "shadow" : config.mode ?? "off",
|
|
653
|
-
maxCards: config.maxCards,
|
|
654
|
-
tokenBudget: config.tokenBudget ?? 1200,
|
|
655
|
-
staleAfterHours: config.staleAfterHours,
|
|
656
|
-
mode: config.mode === "auto" ? "shadow" : config.mode === "shadow" ? "shadow" : config.mode === "on" ? "on" : "off",
|
|
657
|
-
autoMode: config.mode === "auto",
|
|
658
|
-
mapStale: config.mapStale ?? false,
|
|
659
|
-
searchAvailable: config.searchAvailable ?? true
|
|
660
|
-
});
|
|
661
|
-
if (config.mode !== "off") installDiscoveryAwareness(ctx);
|
|
662
|
-
ctx.on("agent/created", async ({ agent, source }) => {
|
|
663
|
-
try {
|
|
664
|
-
if (source === "startup") await sessions.put({
|
|
665
|
-
sessionId: String(agent.session.id),
|
|
666
|
-
discoveryMode: config.mode === "on" ? "on" : config.mode === "shadow" || config.mode === "auto" ? "shadow" : "off",
|
|
667
|
-
featureEpoch: config.featureEpoch
|
|
668
|
-
});
|
|
669
|
-
} catch {}
|
|
670
|
-
});
|
|
671
|
-
installCatalogProjection(ctx, runtime, {
|
|
672
|
-
async get(agentKey) {
|
|
673
|
-
return (await sessions.get(agentKey))?.projectionDigest;
|
|
674
|
-
},
|
|
675
|
-
async set(agentKey, digest) {
|
|
676
|
-
const record = await sessions.get(agentKey);
|
|
677
|
-
if (record !== void 0) await sessions.put({
|
|
678
|
-
...record,
|
|
679
|
-
projectionDigest: digest
|
|
680
|
-
});
|
|
681
|
-
}
|
|
682
|
-
});
|
|
683
|
-
const queue = new JsonAssignmentQueue(io, join(dshHome, "evolution", "assignment-queue.json"));
|
|
684
|
-
const assignment = new DomainAssignmentService(queue, map, {
|
|
685
|
-
createClassificationEnabled: config.createClassificationEnabled ?? false,
|
|
686
|
-
...config.provisionalThreshold === void 0 ? {} : { provisionalThreshold: config.provisionalThreshold },
|
|
687
|
-
now: Date.now
|
|
688
|
-
});
|
|
689
|
-
const worker = new AssignmentWorker(assignment, queue);
|
|
690
|
-
queue.load().then(() => worker.drain()).catch(() => {});
|
|
691
|
-
installAssignmentSidecar(ctx, assignment, { onSubmitted: () => {
|
|
692
|
-
worker.drain().catch(() => {});
|
|
693
|
-
} });
|
|
694
|
-
const commandRuntime = ctx.get("commands");
|
|
695
|
-
if (commandRuntime !== void 0) ctx.effect(() => commandRuntime.register({
|
|
696
|
-
name: "skill-domain",
|
|
697
|
-
description: "List provisional skill domains or confirm one by id.",
|
|
698
|
-
async handler({ rawInput }) {
|
|
699
|
-
const [action, domainId] = rawInput.trim().split(/\s+/);
|
|
700
|
-
if (action === "list" || action === void 0) {
|
|
701
|
-
const provisional = (await map.read()).domains.filter((node) => node.status === "provisional");
|
|
702
|
-
return {
|
|
703
|
-
kind: "success",
|
|
704
|
-
text: provisional.length === 0 ? "No provisional domains." : "Provisional domains:\n" + provisional.map((node) => "- " + node.id + ": " + node.name).join("\n")
|
|
705
|
-
};
|
|
706
|
-
}
|
|
707
|
-
if (action === "confirm" && domainId !== void 0) return await assignment.confirm(domainId) ? {
|
|
708
|
-
kind: "success",
|
|
709
|
-
text: "Confirmed domain " + domainId + "."
|
|
710
|
-
} : {
|
|
711
|
-
kind: "error",
|
|
712
|
-
text: "Unknown or non-provisional domain: " + domainId
|
|
713
|
-
};
|
|
714
|
-
return {
|
|
715
|
-
kind: "error",
|
|
716
|
-
text: "Usage: /skill-domain list | /skill-domain confirm <id>"
|
|
717
|
-
};
|
|
718
|
-
}
|
|
719
|
-
}));
|
|
720
|
-
const searchCache = new SkillSearchCache();
|
|
721
|
-
ctx.on("evolution/skill-mutated", () => {
|
|
722
|
-
searchCache.clear();
|
|
723
|
-
});
|
|
724
|
-
registerSkillSearchTool(ctx, {
|
|
725
|
-
async allowedSkillKeys(agent) {
|
|
726
|
-
const view = await new SkillIndex(source).read({
|
|
727
|
-
cwd: agent?.session.header.cwd ?? process.cwd(),
|
|
728
|
-
scopeKey: agent === void 0 ? "tool" : String(agent.id),
|
|
729
|
-
...agent === void 0 ? {} : { scope: agent }
|
|
730
|
-
});
|
|
731
|
-
const snapshot = await map.read();
|
|
732
|
-
const blocked = new Set(snapshot.edges.filter((edge) => edge.status === "active" && policy.disabled.has(edge.domainId)).map((edge) => edge.skillKey));
|
|
733
|
-
return new Set(view.rows.filter((row) => row.modelInvocable && !blocked.has(row.skillKey)).map((row) => row.skillKey));
|
|
734
|
-
},
|
|
735
|
-
async search(query, options, agent) {
|
|
736
|
-
const cwd = agent?.session.header.cwd ?? process.cwd();
|
|
737
|
-
const view = await new SkillIndex(source).read({
|
|
738
|
-
cwd,
|
|
739
|
-
scopeKey: agent === void 0 ? "tool" : String(agent.id),
|
|
740
|
-
...agent === void 0 ? {} : { scope: agent }
|
|
741
|
-
});
|
|
742
|
-
const cacheKey = {
|
|
743
|
-
viewKey: view.viewKey,
|
|
744
|
-
viewCatalogDigest: view.viewCatalogDigest,
|
|
745
|
-
policyDigest,
|
|
746
|
-
discoveryMode: config.mode ?? "auto"
|
|
747
|
-
};
|
|
748
|
-
const cached = await searchCache.get(cacheKey, view.rows);
|
|
749
|
-
if (cached === void 0) return {
|
|
750
|
-
results: [],
|
|
751
|
-
truncated: false,
|
|
752
|
-
degraded: true,
|
|
753
|
-
hint: "Skill search index is unavailable. Use skill(name) or the full catalog."
|
|
754
|
-
};
|
|
755
|
-
const result = await cached.index.search(query, options);
|
|
756
|
-
return result.stale || cached.stale ? {
|
|
757
|
-
...result,
|
|
758
|
-
stale: true
|
|
759
|
-
} : result;
|
|
760
|
-
}
|
|
761
|
-
});
|
|
762
|
-
}
|
|
763
|
-
//#endregion
|
|
764
|
-
export { AssignmentWorker, DISCOVERY_AWARENESS, DISCOVERY_STAGES, DOMAIN_GENERATION_PROMPT, DOMAIN_GENERATION_PROMPT_HASH, DOMAIN_GENERATION_PROMPT_V1, DOMAIN_GENERATION_PROMPT_V2, DOMAIN_GENERATION_PROMPT_VERSION, DOMAIN_MAP_SCHEMA_VERSION, DiscoveryRuntime, DiscoverySessionStore, DomainAssignmentService, DomainGenerationCoordinator, DomainGenerationError, DomainMapCorruptError, DomainMapFileStore, DomainMapValidationError, DomainMapVersionConflict, DomainPolicyStore, DomainPolicyValidationError, JsonAssignmentQueue, LlmDomainGenerationPort, MAINTENANCE_DEFAULTS, MemoryAssignmentQueue, ProjectionJournal, ProjectionRuntime, SKILL_MANAGE_DESCRIPTION, SKILL_SEARCH_DESCRIPTION, SKILL_SEARCH_FIELDS, SKILL_SEARCH_INDEX_SCHEMA_VERSION, SKILL_SEARCH_TOKENIZER_VERSION, SkillIndex, SkillSearchCache, SkillSearchIndex, V0_DISCOVERY_FEATURES, ViewSnapshotStore, ViewStateRegistry, aggregateJudge, apply, applyCapturedProjection, applyCatalogProjection, applyProjectedDecision, applyReplacementDecision, applyRestoreUpdate, assignmentKey, auditDomainMap, bootstrapDomainMap, bootstrapDomainMapWithFacts, bootstrapFactsFromRows, buildDomainGenerationPrompt, buildDomainProjection, buildGenerationRequest, canClassifyAtCreate, canHide, canProject, captureCatalog, captureDecisionCatalog, catalogRevisionOf, coarsenCandidates, computeBehaviorMetrics, computeDomainMetrics, coveredByDomain, deriveViewState, descriptionHashOf, descriptionIsServable, domainGenerationMode, domainViewCounts, evaluateDomainQuality, findCatalogMessage, hiddenRecoverable, initialDomainMap, inject, installAssignmentSidecar, installCatalogProjection, installDiscoveryAwareness, isDiscoveryUserPolicy, isSkillSearch, mayAdvance, mergeDomainPolicy, mintDomainId, name, parseDomainGenerationProposal, policyDigestOf, projectCatalog, projectionBudgetMode, projectionDigestOf, proposalDigest, registerSkillSearchTool, renderCatalog, renderCatalogUpdate, renderDomainDescription, renderProjectionContext, resolveGenerationPort, restoreCapturedProjection, restoreCatalog, sanitizeUntrustedText, searchIndexKeyOf, searchTerms, searchWithDegraded, shouldEmitAwareness, shouldEmitDigest, shouldHideCatalog, shouldInstallAwarenessOnResume, shouldProjectPersistedSession, shouldRegenerateDescription, skillIndexRowOf, skillKeyOf, splitCandidates, stageIndex, threeFieldHashOf, validateDomainGeneration, validateJudgeRecord, validateProposal, viewCatalogDigestOf, viewKeyOf };
|