dsh-mnemon 0.5.34 → 0.5.36
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 +2 -0
- package/README.zh-CN.md +2 -0
- package/cordis.patch.yml +6 -3
- package/lib/bundle.js +1 -1
- package/lib/client.js +315 -194
- package/lib/extension-sdk.js +2 -2
- package/lib/index.js +230 -76
- package/lib/{starter-resolution-C2TDVxDr.js → starter-resolution-BVUz3pw4.js} +8 -8
- package/lib/starter.js +1 -1
- package/lib/{strategy-configuration-CLHxaPOb.js → strategy-configuration-CKP2kRss.js} +34 -2
- package/lib/types/src/client/locales.d.ts +7 -0
- package/lib/types/src/host/config-values.d.ts +1 -0
- package/lib/types/src/host/config.d.ts +1 -1
- package/lib/types/src/host/protocol.d.ts +9 -1
- package/lib/types/src/sdk/index.d.ts +1 -0
- package/lib/types/src/sdk/workspace-storage.d.ts +4 -0
- package/package.json +9 -9
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as withMemoryStorageLock, n as memoryStrategyConfigurationValues, r as readMemoryStrategyConfiguration, s as receipt } from "./strategy-configuration-
|
|
1
|
+
import { f as canonicalWorkspacePath, m as withMemoryStorageLock, n as memoryStrategyConfigurationValues, p as workspaceStorageId, r as readMemoryStrategyConfiguration, s as receipt } from "./strategy-configuration-CKP2kRss.js";
|
|
2
2
|
import { a as validateMemoryPluginGraph, i as captureMemoryContributionSnapshot, n as isMemoryCompositionUnavailable, o as prepareMemoryContributions, r as MemoryCompositionGeneration, t as provideMemoryRuntime } from "./runtime-zuuBe8x1.js";
|
|
3
3
|
import { DEFAULT_MEMORY_VIEW_BUDGET, MEMORY_CAPABILITIES } from "./contracts.js";
|
|
4
4
|
import { r as defineMemoryPlugin, t as canonicalMemoryJson } from "./definitions-DU7MLBhu.js";
|
|
@@ -6,7 +6,7 @@ import { Context } from "@deepseek-ai/cordis";
|
|
|
6
6
|
import z from "@deepseek-ai/schemastery";
|
|
7
7
|
import { basename, delimiter, dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
|
|
8
8
|
import { resolveEmbedding, resolvePersistenceStrategy, resolveRecallQuality } from "dsh-mnemon-source-memory-spaces";
|
|
9
|
-
import { CATEGORIES, DEFAULT_EMBEDDING_ENDPOINT, DEFAULT_EMBEDDING_MODEL, DEFAULT_EMBEDDING_PROTOCOL, EDGE_TYPES, MEMORY_PLACEMENT_CAPABILITIES, MEMORY_PROVIDER_REGISTRY_FILE, MEMORY_SPACES_DIRECTORY, MEMORY_SPACE_DATABASE_FILE, MEMORY_SPACE_ID_PATTERN, MEMORY_SPACE_REGISTRY_FILE, MNEMON_ACTIVE_STORE_FILE, MNEMON_EMBEDDING_PROTOCOLS, SOURCES, parseMemorySpaceRegistry, summarizeMemoryProviderRegistry, summarizeMemorySpaceRegistry } from "dsh-mnemon-source-memory-spaces/contracts";
|
|
9
|
+
import { CATEGORIES, DEFAULT_EMBEDDING_ENDPOINT, DEFAULT_EMBEDDING_MODEL, DEFAULT_EMBEDDING_PROTOCOL, EDGE_TYPES, MEMORY_PLACEMENT_CAPABILITIES, MEMORY_PROVIDER_REGISTRY_FILE, MEMORY_SPACES_DIRECTORY, MEMORY_SPACE_DATABASE_FILE, MEMORY_SPACE_ID_PATTERN, MEMORY_SPACE_NAME_MAX_LENGTH, MEMORY_SPACE_REGISTRY_FILE, MNEMON_ACTIVE_STORE_FILE, MNEMON_EMBEDDING_PROTOCOLS, SOURCES, parseMemorySpaceRegistry, summarizeMemoryProviderRegistry, summarizeMemorySpaceRegistry } from "dsh-mnemon-source-memory-spaces/contracts";
|
|
10
10
|
import { RUNTIME_ARCHIVE_DIRECTORY, RUNTIME_DIRECTORY, RUNTIME_ENTRY_DELIMITER, RUNTIME_ENTRY_MAX_BYTES, RUNTIME_LOCK_FILE, RUNTIME_LOCK_STALE_MS, RUNTIME_MEMORIES_FILE, RUNTIME_MEMORY_LIMITS, RUNTIME_MEMORY_LIMIT_MAX_BYTES, RUNTIME_MEMORY_VERSION, RUNTIME_PROJECTION_FILES, parseRuntimeBranches, runtimeBytes, runtimeProjection, summarizeRuntimeMemories } from "dsh-mnemon-source-runtime/contracts";
|
|
11
11
|
import { createHash, randomUUID } from "node:crypto";
|
|
12
12
|
import { accessSync, chmodSync, closeSync, constants, copyFileSync, existsSync, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
@@ -384,6 +384,8 @@ const DEFAULT_IDLE_REVIEW = {
|
|
|
384
384
|
};
|
|
385
385
|
const DEFAULT_SKILLS_CONFIG = Object.freeze({
|
|
386
386
|
evolution: false,
|
|
387
|
+
allowCreate: true,
|
|
388
|
+
allowUpdate: true,
|
|
387
389
|
autoBacktest: true,
|
|
388
390
|
hints: true,
|
|
389
391
|
sidebar: false,
|
|
@@ -458,6 +460,7 @@ const DEFAULT_RECALL_LOW_SCORE_THRESHOLD = recallDefaults.lowScoreThreshold;
|
|
|
458
460
|
const DEFAULT_RECALL_HIGH_SCORE_THRESHOLD = recallDefaults.highScoreThreshold;
|
|
459
461
|
const DEFAULT_RECALL_CANDIDATE_MULTIPLIER = recallDefaults.candidateMultiplier;
|
|
460
462
|
const DEFAULT_RECALL_MAX_MEDIUM_RESULTS = recallDefaults.maxMediumResults;
|
|
463
|
+
const DEFAULT_RECALL_MAX_RANKED_RESULTS = recallDefaults.maxRankedResults;
|
|
461
464
|
const DEFAULT_RECALL_MAX_UNKNOWN_RESULTS = recallDefaults.maxUnknownResults;
|
|
462
465
|
//#endregion
|
|
463
466
|
//#region src/host/config.ts
|
|
@@ -468,6 +471,8 @@ const InteractionConfig = z.object({
|
|
|
468
471
|
/** 技能管理's settings, with the ranges its page accepts. */
|
|
469
472
|
const SkillsConfig = z.object({
|
|
470
473
|
evolution: z.boolean().default(DEFAULT_SKILLS_CONFIG.evolution),
|
|
474
|
+
allowCreate: z.boolean().default(DEFAULT_SKILLS_CONFIG.allowCreate),
|
|
475
|
+
allowUpdate: z.boolean().default(DEFAULT_SKILLS_CONFIG.allowUpdate),
|
|
471
476
|
autoBacktest: z.boolean().default(DEFAULT_SKILLS_CONFIG.autoBacktest),
|
|
472
477
|
hints: z.boolean().default(DEFAULT_SKILLS_CONFIG.hints),
|
|
473
478
|
sidebar: z.boolean().default(DEFAULT_SKILLS_CONFIG.sidebar),
|
|
@@ -519,6 +524,7 @@ const RecallQualitySchema = z.object({
|
|
|
519
524
|
highScoreThreshold: z.number().min(0).max(1).default(DEFAULT_RECALL_HIGH_SCORE_THRESHOLD),
|
|
520
525
|
candidateMultiplier: z.number().step(1).min(1).max(5).default(DEFAULT_RECALL_CANDIDATE_MULTIPLIER),
|
|
521
526
|
maxMediumResults: z.number().step(1).min(0).max(50).default(DEFAULT_RECALL_MAX_MEDIUM_RESULTS),
|
|
527
|
+
maxRankedResults: z.number().step(1).min(0).max(50).default(DEFAULT_RECALL_MAX_RANKED_RESULTS),
|
|
522
528
|
maxUnknownResults: z.number().step(1).min(0).max(50).default(DEFAULT_RECALL_MAX_UNKNOWN_RESULTS)
|
|
523
529
|
});
|
|
524
530
|
const RuntimeMemorySchema = z.object({
|
|
@@ -597,6 +603,7 @@ const Config = z.object({
|
|
|
597
603
|
highScoreThreshold: DEFAULT_RECALL_HIGH_SCORE_THRESHOLD,
|
|
598
604
|
candidateMultiplier: DEFAULT_RECALL_CANDIDATE_MULTIPLIER,
|
|
599
605
|
maxMediumResults: DEFAULT_RECALL_MAX_MEDIUM_RESULTS,
|
|
606
|
+
maxRankedResults: DEFAULT_RECALL_MAX_RANKED_RESULTS,
|
|
600
607
|
maxUnknownResults: DEFAULT_RECALL_MAX_UNKNOWN_RESULTS
|
|
601
608
|
}),
|
|
602
609
|
routingGuidance: z.boolean().default(true),
|
|
@@ -943,37 +950,6 @@ var MnemonAutoBackupScheduler = class {
|
|
|
943
950
|
}
|
|
944
951
|
};
|
|
945
952
|
//#endregion
|
|
946
|
-
//#region src/host/workspace-storage.ts
|
|
947
|
-
/** Host workspace identity, including aliases with not-yet-created descendants. */
|
|
948
|
-
function canonicalWorkspacePath(workspacePath) {
|
|
949
|
-
if (!isAbsolute(workspacePath) || workspacePath.includes("\0")) throw new Error("Workspace path must be absolute");
|
|
950
|
-
let parent = resolve(workspacePath);
|
|
951
|
-
const suffix = [];
|
|
952
|
-
for (;;) {
|
|
953
|
-
let real;
|
|
954
|
-
try {
|
|
955
|
-
real = realpathSync.native(parent);
|
|
956
|
-
} catch (error) {
|
|
957
|
-
if (error.code !== "ENOENT") throw error;
|
|
958
|
-
const next = dirname(parent);
|
|
959
|
-
if (next === parent) throw error;
|
|
960
|
-
suffix.unshift(parent.slice(next.length).replace(/^[/\\]+/u, ""));
|
|
961
|
-
parent = next;
|
|
962
|
-
continue;
|
|
963
|
-
}
|
|
964
|
-
if (suffix.length > 0 && !statSync(real).isDirectory()) throw Object.assign(/* @__PURE__ */ new Error(`ENOTDIR: not a directory, realpath '${parent}'`), {
|
|
965
|
-
code: "ENOTDIR",
|
|
966
|
-
path: parent,
|
|
967
|
-
syscall: "realpath"
|
|
968
|
-
});
|
|
969
|
-
return join(real, ...suffix);
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
/** A rename or move selects a new directory; resolving identity never writes. */
|
|
973
|
-
function workspaceStorageId(workspacePath) {
|
|
974
|
-
return createHash("sha256").update(canonicalWorkspacePath(workspacePath)).digest("hex");
|
|
975
|
-
}
|
|
976
|
-
//#endregion
|
|
977
953
|
//#region src/host/storage-root.ts
|
|
978
954
|
function expandDirectory(value) {
|
|
979
955
|
return resolve(value === "~" ? homedir() : value.startsWith("~/") ? join(homedir(), value.slice(2)) : value);
|
|
@@ -2452,6 +2428,56 @@ function keepRuntimeArchive(root, stagedRuntime) {
|
|
|
2452
2428
|
};
|
|
2453
2429
|
copy(join(root, RUNTIME_DIRECTORY, RUNTIME_ARCHIVE_DIRECTORY), join(stagedRuntime, RUNTIME_ARCHIVE_DIRECTORY));
|
|
2454
2430
|
}
|
|
2431
|
+
/** Keep exact overflow records locally; a stable filename makes retried merges idempotent. */
|
|
2432
|
+
function archiveRuntimeOverflow(stagedRuntime, entries) {
|
|
2433
|
+
if (entries.length === 0) return 0;
|
|
2434
|
+
const directory = join(stagedRuntime, RUNTIME_ARCHIVE_DIRECTORY, "import-overflow");
|
|
2435
|
+
mkdirSync(directory, {
|
|
2436
|
+
recursive: true,
|
|
2437
|
+
mode: 448
|
|
2438
|
+
});
|
|
2439
|
+
let added = 0;
|
|
2440
|
+
for (const entry of entries) {
|
|
2441
|
+
const content = `${canonicalJson({
|
|
2442
|
+
version: 1,
|
|
2443
|
+
entries: [entry]
|
|
2444
|
+
})}\n`;
|
|
2445
|
+
const path = join(directory, `${sha256$1(content)}.json`);
|
|
2446
|
+
if (existsSync(path)) {
|
|
2447
|
+
if (readFileSync(path, "utf8") !== content) throw new Error("Runtime overflow archive content mismatch");
|
|
2448
|
+
continue;
|
|
2449
|
+
}
|
|
2450
|
+
writeFileSync(path, content, {
|
|
2451
|
+
mode: 384,
|
|
2452
|
+
flag: "wx"
|
|
2453
|
+
});
|
|
2454
|
+
added += 1;
|
|
2455
|
+
}
|
|
2456
|
+
return added;
|
|
2457
|
+
}
|
|
2458
|
+
/** Retain the same hot set on both machines, without asking a model to rewrite evidence. */
|
|
2459
|
+
function fitMergedRuntime(entries, limits) {
|
|
2460
|
+
if (runtimeBytes(entries, "memory") <= limits.memory) return {
|
|
2461
|
+
entries,
|
|
2462
|
+
archived: []
|
|
2463
|
+
};
|
|
2464
|
+
const importance = {
|
|
2465
|
+
critical: 2,
|
|
2466
|
+
normal: 1,
|
|
2467
|
+
low: 0
|
|
2468
|
+
};
|
|
2469
|
+
const compare = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
2470
|
+
const ranked = entries.filter((entry) => entry.target === "memory").sort((left, right) => importance[right.importance] - importance[left.importance] || compare(right.updated_at, left.updated_at) || compare(entryKey(left), entryKey(right)));
|
|
2471
|
+
const kept = [];
|
|
2472
|
+
const archived = [];
|
|
2473
|
+
for (const entry of ranked) if (runtimeBytes([...kept, entry], "memory") <= limits.memory) kept.push(entry);
|
|
2474
|
+
else archived.push(entry);
|
|
2475
|
+
const selected = new Set(kept);
|
|
2476
|
+
return {
|
|
2477
|
+
entries: entries.filter((entry) => entry.target === "user" || selected.has(entry)),
|
|
2478
|
+
archived
|
|
2479
|
+
};
|
|
2480
|
+
}
|
|
2455
2481
|
function writeRuntime(directory, file) {
|
|
2456
2482
|
mkdirSync(directory, {
|
|
2457
2483
|
recursive: true,
|
|
@@ -2778,6 +2804,7 @@ function mergeRuntime(root, pack, runtimeLimits, options = {}) {
|
|
|
2778
2804
|
added: 0,
|
|
2779
2805
|
held: 0
|
|
2780
2806
|
};
|
|
2807
|
+
const incomingKeys = /* @__PURE__ */ new Set();
|
|
2781
2808
|
const revived = [];
|
|
2782
2809
|
for (const entry of incoming.entries) {
|
|
2783
2810
|
const key = entryKey(entry);
|
|
@@ -2792,13 +2819,16 @@ function mergeRuntime(root, pack, runtimeLimits, options = {}) {
|
|
|
2792
2819
|
if (keys.has(key)) continue;
|
|
2793
2820
|
keys.add(key);
|
|
2794
2821
|
entries.push(entry);
|
|
2795
|
-
|
|
2822
|
+
incomingKeys.add(key);
|
|
2796
2823
|
}
|
|
2824
|
+
const fitted = fitMergedRuntime(entries, runtimeLimits);
|
|
2825
|
+
report.added = fitted.entries.filter((entry) => incomingKeys.has(entryKey(entry))).length;
|
|
2797
2826
|
return {
|
|
2798
2827
|
runtime: parseRuntime({
|
|
2799
2828
|
version: 1,
|
|
2800
|
-
entries
|
|
2829
|
+
entries: fitted.entries
|
|
2801
2830
|
}, runtimeLimits),
|
|
2831
|
+
archived: fitted.archived,
|
|
2802
2832
|
report,
|
|
2803
2833
|
revived: mergeTombstoneFiles({
|
|
2804
2834
|
version: 1,
|
|
@@ -2907,6 +2937,11 @@ function mergeDocuments(root, pack, base) {
|
|
|
2907
2937
|
if (current.index.documents.filter((document) => document.status === "active").reduce((sum, document) => sum + document.sizeBytes, 0) > DOCUMENTS_ACTIVE_LIMIT_BYTES) throw new Error(`merged Documents exceed the ${DOCUMENTS_ACTIVE_LIMIT_BYTES} byte active limit`);
|
|
2908
2938
|
return current;
|
|
2909
2939
|
}
|
|
2940
|
+
/** Stable across repeated imports, bounded by the registry contract, and distinguishable in the UI. */
|
|
2941
|
+
function conflictSpaceName(source) {
|
|
2942
|
+
const suffix = ` (import conflict ${createHash("sha256").update(source.id).digest("hex").slice(0, 8)})`;
|
|
2943
|
+
return source.name.slice(0, MEMORY_SPACE_NAME_MAX_LENGTH - suffix.length) + suffix;
|
|
2944
|
+
}
|
|
2910
2945
|
function mergeRegistry(root, pack) {
|
|
2911
2946
|
const current = readCurrentRegistry(root);
|
|
2912
2947
|
const incoming = archiveRegistry(pack);
|
|
@@ -2931,7 +2966,7 @@ function mergeRegistry(root, pack) {
|
|
|
2931
2966
|
continue;
|
|
2932
2967
|
}
|
|
2933
2968
|
if (held(sourceDb, (body) => body.id !== source.id)) continue;
|
|
2934
|
-
const copy = current.registry.bodies.find((body) => body.id !== source.id && body.name === source.name && identity.contains(sourceDb, current.databases.get(body.id)));
|
|
2969
|
+
const copy = current.registry.bodies.find((body) => body.id !== source.id && (body.name === conflictSpaceName(source) || body.name === source.name) && identity.contains(sourceDb, current.databases.get(body.id)));
|
|
2935
2970
|
const advanced = copy === void 0 ? void 0 : identity.merge(current.databases.get(copy.id), sourceDb);
|
|
2936
2971
|
if (copy !== void 0 && advanced !== void 0) {
|
|
2937
2972
|
current.databases.set(copy.id, advanced);
|
|
@@ -2940,6 +2975,8 @@ function mergeRegistry(root, pack) {
|
|
|
2940
2975
|
add({
|
|
2941
2976
|
...source,
|
|
2942
2977
|
id: randomUUID(),
|
|
2978
|
+
name: conflictSpaceName(source),
|
|
2979
|
+
active: false,
|
|
2943
2980
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2944
2981
|
}, sourceDb);
|
|
2945
2982
|
} else if (!held(sourceDb, (body) => body.name === source.name)) add(source, sourceDb);
|
|
@@ -3000,6 +3037,15 @@ function stageImport(root, pack, components, mode, runtimeLimits, options = {})
|
|
|
3000
3037
|
revived = merged.revived;
|
|
3001
3038
|
}
|
|
3002
3039
|
keepRuntimeArchive(root, join(staging, RUNTIME_DIRECTORY));
|
|
3040
|
+
if (merged !== void 0 && merged.archived.length > 0) {
|
|
3041
|
+
const archived = archiveRuntimeOverflow(join(staging, RUNTIME_DIRECTORY), merged.archived);
|
|
3042
|
+
if (archived > 0) merged.report.archived = archived;
|
|
3043
|
+
const archivedKeys = new Set(merged.archived.map((entry) => `${entry.target}\0${tombstoneHash(entry)}`));
|
|
3044
|
+
writeRuntimeIndex(join(staging, "state"), {
|
|
3045
|
+
version: 1,
|
|
3046
|
+
entries: readRuntimeIndex(root).entries.filter((entry) => !archivedKeys.has(`${entry.target}\0${entry.contentHash}`))
|
|
3047
|
+
});
|
|
3048
|
+
}
|
|
3003
3049
|
}
|
|
3004
3050
|
if (components.includes("documents")) {
|
|
3005
3051
|
const documents = mode === "merge" ? mergeDocuments(root, pack, options.documentsBase) : archiveDocuments(pack);
|
|
@@ -3033,7 +3079,7 @@ function commitStaging(root, staging, components) {
|
|
|
3033
3079
|
const replacementLocks = sourceLocks(staging, components).map((lock) => lock.path);
|
|
3034
3080
|
const activePath = join(root, MNEMON_ACTIVE_STORE_FILE);
|
|
3035
3081
|
const previousActive = existsSync(activePath) ? readFileSync(activePath) : void 0;
|
|
3036
|
-
|
|
3082
|
+
const stateSwaps = [];
|
|
3037
3083
|
try {
|
|
3038
3084
|
for (const lock of replacementLocks) writeFileSync(lock, "pack-import\n", { mode: 384 });
|
|
3039
3085
|
for (const component of components) {
|
|
@@ -3053,18 +3099,22 @@ function commitStaging(root, staging, components) {
|
|
|
3053
3099
|
hadPrevious
|
|
3054
3100
|
});
|
|
3055
3101
|
}
|
|
3056
|
-
|
|
3102
|
+
for (const file of [STATE_TOMBSTONE_FILE, STATE_RUNTIME_INDEX_FILE]) {
|
|
3103
|
+
if (!components.includes("runtime") || !existsSync(join(staging, "state", file))) continue;
|
|
3057
3104
|
const directory = join(root, "state");
|
|
3058
3105
|
mkdirSync(directory, {
|
|
3059
3106
|
recursive: true,
|
|
3060
3107
|
mode: 448
|
|
3061
3108
|
});
|
|
3062
|
-
const target = join(directory,
|
|
3063
|
-
const previous = join(backup,
|
|
3109
|
+
const target = join(directory, file);
|
|
3110
|
+
const previous = join(backup, file);
|
|
3064
3111
|
const hadPrevious = existsSync(target);
|
|
3065
3112
|
if (hadPrevious) renameSync(target, previous);
|
|
3066
|
-
|
|
3067
|
-
|
|
3113
|
+
stateSwaps.push({
|
|
3114
|
+
file,
|
|
3115
|
+
hadPrevious
|
|
3116
|
+
});
|
|
3117
|
+
renameSync(join(staging, "state", file), target);
|
|
3068
3118
|
}
|
|
3069
3119
|
if (components.includes("memory-spaces")) reconcilePersistedStore(root);
|
|
3070
3120
|
for (const lock of sourceLocks(root, components)) rmSync(lock.path, { force: true });
|
|
@@ -3077,10 +3127,10 @@ function commitStaging(root, staging, components) {
|
|
|
3077
3127
|
});
|
|
3078
3128
|
if (entry.hadPrevious) renameSync(join(backup, entry.directory), target);
|
|
3079
3129
|
}
|
|
3080
|
-
|
|
3081
|
-
const target = join(root, "state",
|
|
3130
|
+
for (const entry of stateSwaps.reverse()) {
|
|
3131
|
+
const target = join(root, "state", entry.file);
|
|
3082
3132
|
rmSync(target, { force: true });
|
|
3083
|
-
if (
|
|
3133
|
+
if (entry.hadPrevious) renameSync(join(backup, entry.file), target);
|
|
3084
3134
|
}
|
|
3085
3135
|
if (components.includes("memory-spaces")) {
|
|
3086
3136
|
if (previousActive === void 0) rmSync(activePath, { force: true });
|
|
@@ -5185,10 +5235,12 @@ var MnemonGitSync = class {
|
|
|
5185
5235
|
let result = await this.pushOnce(settings, message, input.signal);
|
|
5186
5236
|
let added = result.merged?.runtime?.added ?? 0;
|
|
5187
5237
|
let held = result.merged?.runtime?.held ?? 0;
|
|
5238
|
+
let archived = result.merged?.runtime?.archived ?? 0;
|
|
5188
5239
|
for (let attempt = 1; attempt < PUSH_ATTEMPTS && result.failure === "push-rejected"; attempt += 1) {
|
|
5189
5240
|
result = await this.pushOnce(settings, message, input.signal);
|
|
5190
5241
|
added += result.merged?.runtime?.added ?? 0;
|
|
5191
5242
|
held = result.merged?.runtime?.held ?? held;
|
|
5243
|
+
archived += result.merged?.runtime?.archived ?? 0;
|
|
5192
5244
|
}
|
|
5193
5245
|
if (result.merged !== void 0 && (added > 0 || result.merged.runtime !== void 0)) result = {
|
|
5194
5246
|
...result,
|
|
@@ -5196,7 +5248,8 @@ var MnemonGitSync = class {
|
|
|
5196
5248
|
...result.merged,
|
|
5197
5249
|
runtime: {
|
|
5198
5250
|
added,
|
|
5199
|
-
held
|
|
5251
|
+
held,
|
|
5252
|
+
...archived > 0 ? { archived } : {}
|
|
5200
5253
|
}
|
|
5201
5254
|
}
|
|
5202
5255
|
};
|
|
@@ -9497,6 +9550,7 @@ async function archiveRuntimeLocally(counters, context, request, plan, reason, s
|
|
|
9497
9550
|
}));
|
|
9498
9551
|
const mutation = await context.runtime.mutateResult("compact-and-mutate", {
|
|
9499
9552
|
revision: plan.revision,
|
|
9553
|
+
...context.preserveImportance ? { preserveImportance: true } : {},
|
|
9500
9554
|
mutation: request,
|
|
9501
9555
|
compacted,
|
|
9502
9556
|
maxBytes: compactedBudget(plan),
|
|
@@ -9528,7 +9582,10 @@ async function runtimeLocked(counters, context, request, signal) {
|
|
|
9528
9582
|
} catch (error) {
|
|
9529
9583
|
if (!sourceFailure(error, "runtime-capacity") || !context.maintain) throw error;
|
|
9530
9584
|
}
|
|
9531
|
-
const plan = await runtimeMemory.read("maintenance-plan",
|
|
9585
|
+
const plan = await runtimeMemory.read("maintenance-plan", {
|
|
9586
|
+
...request,
|
|
9587
|
+
...context.preserveImportance ? { preserveImportance: true } : {}
|
|
9588
|
+
}, signal);
|
|
9532
9589
|
if (context.expectedRevision !== void 0 && context.expectedRevision !== plan.revision) throw new Error("Runtime source revision conflict before capacity maintenance");
|
|
9533
9590
|
if (!plan.requiresMaintenance) return context.commit();
|
|
9534
9591
|
if (plan.entries.length === 0) throw new Error("runtime memory capacity was exceeded without entries available for maintenance");
|
|
@@ -9622,7 +9679,10 @@ ${chunk.context}
|
|
|
9622
9679
|
importance,
|
|
9623
9680
|
...branches === void 0 ? {} : { branches }
|
|
9624
9681
|
}));
|
|
9625
|
-
if ((await runtimeMemory.read("maintenance-plan",
|
|
9682
|
+
if ((await runtimeMemory.read("maintenance-plan", {
|
|
9683
|
+
...request,
|
|
9684
|
+
...context.preserveImportance ? { preserveImportance: true } : {}
|
|
9685
|
+
}, signal)).revision !== plan.revision) throw new Error("runtime memory changed while archival was running; no archive writes were attempted");
|
|
9626
9686
|
const destinations = await readDirectory();
|
|
9627
9687
|
for (const memoryBodyId of new Set(routed.values())) if (!destinations.items.some((body) => body.id === memoryBodyId && eligible(body))) throw new Error(`runtime archive Memory Space ${memoryBodyId} is no longer eligible; no archive writes were attempted`);
|
|
9628
9688
|
signal.throwIfAborted();
|
|
@@ -9694,6 +9754,7 @@ ${chunk.context}
|
|
|
9694
9754
|
commitAttempted = true;
|
|
9695
9755
|
const mutation = await runtimeMemory.mutateResult("compact-and-mutate", {
|
|
9696
9756
|
revision: plan.revision,
|
|
9757
|
+
...context.preserveImportance ? { preserveImportance: true } : {},
|
|
9697
9758
|
mutation: request,
|
|
9698
9759
|
compacted: compactedEntries,
|
|
9699
9760
|
maxBytes: budget,
|
|
@@ -9788,6 +9849,7 @@ ${runtimeSnapshotContext("user", plan.entries)}`;
|
|
|
9788
9849
|
context.assertWritable?.();
|
|
9789
9850
|
const mutation = await runtimeMemory.mutateResult("compact-and-mutate", {
|
|
9790
9851
|
revision: plan.revision,
|
|
9852
|
+
...context.preserveImportance ? { preserveImportance: true } : {},
|
|
9791
9853
|
mutation: request,
|
|
9792
9854
|
compacted: candidates,
|
|
9793
9855
|
maxBytes: budget
|
|
@@ -10538,8 +10600,12 @@ var MnemonSubagentCoordinator = class {
|
|
|
10538
10600
|
const context = {
|
|
10539
10601
|
runtime,
|
|
10540
10602
|
inspectRuntime: runtime,
|
|
10603
|
+
preserveImportance: true,
|
|
10541
10604
|
maintain: strategyDrives(lease.generation.strategy.definition.manifest, "runtime-capacity"),
|
|
10542
|
-
commit: () => runtime.mutate("mutate",
|
|
10605
|
+
commit: () => runtime.mutate("mutate", {
|
|
10606
|
+
...request,
|
|
10607
|
+
preserveImportance: true
|
|
10608
|
+
}, signal),
|
|
10543
10609
|
memorySpaces: async () => {
|
|
10544
10610
|
if (!graph.config.writeEnabled || !this.runtimeSource.config.writeEnabled) throw new Error("dsh-mnemon is configured read-only");
|
|
10545
10611
|
if (!allowsParticipation(graph.config, "memory-spaces", "write", "automatic") || !lease.generation.sourceInstances().some((source) => source.sourceTypeId === "memory-spaces")) return void 0;
|
|
@@ -10592,6 +10658,7 @@ var MnemonSubagentCoordinator = class {
|
|
|
10592
10658
|
runtime,
|
|
10593
10659
|
inspectRuntime: graph.source("runtime", turn.scope).forInstance(source.sourceInstanceKey).forGeneration(lease.generation),
|
|
10594
10660
|
maintain: true,
|
|
10661
|
+
preserveImportance: true,
|
|
10595
10662
|
commit,
|
|
10596
10663
|
assertWritable: () => {
|
|
10597
10664
|
if (!authorize()) throw new Error("Runtime capacity maintenance is no longer authorized");
|
|
@@ -12305,8 +12372,9 @@ var MnemonLifecycle = class {
|
|
|
12305
12372
|
const entries = await Promise.all(providers.map(async (provider) => {
|
|
12306
12373
|
try {
|
|
12307
12374
|
let timeout;
|
|
12375
|
+
const timeoutMs = provider.id === "deepseek-official" ? 6e3 : 3e3;
|
|
12308
12376
|
const models = await Promise.race([llm.listModels(provider.id), new Promise((_, reject) => {
|
|
12309
|
-
timeout = setTimeout(() => reject(/* @__PURE__ */ new Error(
|
|
12377
|
+
timeout = setTimeout(() => reject(/* @__PURE__ */ new Error(`model directory timed out after ${timeoutMs / 1e3} seconds`)), timeoutMs);
|
|
12310
12378
|
})]).finally(() => {
|
|
12311
12379
|
if (timeout !== void 0) clearTimeout(timeout);
|
|
12312
12380
|
});
|
|
@@ -12630,11 +12698,12 @@ var MnemonLifecycle = class {
|
|
|
12630
12698
|
}
|
|
12631
12699
|
};
|
|
12632
12700
|
const inherited = this.inheritedRoute(fallback);
|
|
12633
|
-
|
|
12634
|
-
|
|
12701
|
+
if (inherited === void 0) return void 0;
|
|
12702
|
+
const { source, ...options } = inherited;
|
|
12703
|
+
return {
|
|
12704
|
+
source,
|
|
12635
12705
|
options: {
|
|
12636
|
-
|
|
12637
|
-
model: inherited.model,
|
|
12706
|
+
...options,
|
|
12638
12707
|
...maxTokens
|
|
12639
12708
|
}
|
|
12640
12709
|
};
|
|
@@ -12658,10 +12727,14 @@ var MnemonLifecycle = class {
|
|
|
12658
12727
|
const provider = selectedProvider || fallback?.options?.provider?.trim();
|
|
12659
12728
|
const model = selectedModel || fallback?.options?.model?.trim();
|
|
12660
12729
|
if (provider === void 0 || provider === "" || model === void 0 || model === "") return void 0;
|
|
12730
|
+
const fromDefault = selectedProvider !== void 0 && selectedProvider !== "" && selectedModel !== void 0 && selectedModel !== "";
|
|
12731
|
+
const matchesFallback = provider === fallback?.options?.provider?.trim() && model === fallback?.options?.model?.trim();
|
|
12732
|
+
const effort = fromDefault ? selected?.reasoningEffort : matchesFallback ? fallback?.options?.reasoningEffort : void 0;
|
|
12661
12733
|
return {
|
|
12662
12734
|
provider,
|
|
12663
12735
|
model,
|
|
12664
|
-
|
|
12736
|
+
...typeof effort === "string" && effort.trim() !== "" ? { reasoningEffort: effort } : {},
|
|
12737
|
+
source: fromDefault ? "dsh-default" : "active-agent"
|
|
12665
12738
|
};
|
|
12666
12739
|
}
|
|
12667
12740
|
/**
|
|
@@ -12843,12 +12916,14 @@ When no skill was loaded but the window produced a multi-step procedure, answer
|
|
|
12843
12916
|
1. Did the user issue 2+ refinement turns that reached a stable output spec?
|
|
12844
12917
|
2. Did any tool call fail and need a substitute?
|
|
12845
12918
|
3. Is the final flow a reproducible pipeline another agent could rerun verbatim?
|
|
12846
|
-
If any answer is yes, suggest
|
|
12919
|
+
If any answer is yes, suggest a reusable playbook with confidence >= 0.7. First check existing skills and open suggestions; not loading a skill does not mean it is missing.
|
|
12847
12920
|
|
|
12848
12921
|
Rules:
|
|
12849
12922
|
- Cite evidence. Every suggestion and every case lists the step numbers it rests on; a suggestion without cited steps is discarded.
|
|
12850
12923
|
- annotations mark the steps that carry a signal: the step number, the signal, and a short note saying what happened there.
|
|
12851
12924
|
- skillName: lowercase words joined by hyphens. Use the exact name of an existing skill for action="update"; never invent an update target.
|
|
12925
|
+
- Before inventing a name, compare the existing skill catalog and open suggestions below. Prefer updating a matching existing skill, even if it was not loaded in this window. Otherwise reuse the exact skillName and action of an open suggestion covering the same workflow. Only create a new name for a distinct workflow, and explain the distinction in rationale.
|
|
12926
|
+
- When reusing an open suggestion, combine its earlier summary and rationale with the new evidence; preserve earlier requirements, not just this window's refinement. Cite steps from the current window only; the ledger retains earlier evidence. Drafting/review suggestions can receive more evidence but their wording and drafts are not replaced.
|
|
12852
12927
|
- summary and rationale: short, in the user's language (the language of the user steps).
|
|
12853
12928
|
- confidence: 0 to 1; only suggest at >= 0.6. At most 3 suggestions.
|
|
12854
12929
|
- cases: for each suggestion, propose up to 2 eval cases that would show whether the skill works — prompt is the task as the user would phrase it (self-contained, no references to "the conversation"), checks are concrete, observable properties of a correct result, must=true for the ones that decide pass or fail. Skip a case that an existing case listed below already covers.
|
|
@@ -12961,8 +13036,18 @@ function skillReviewPrompt(input) {
|
|
|
12961
13036
|
const loaded = input.loaded.map((skill) => `=== ${skill.name} (${skill.root}: ${skill.path}) ===\n${skill.content.length > 6e3 ? skill.content.slice(0, 6e3) + "\n[truncated]" : skill.content}`).join("\n\n");
|
|
12962
13037
|
const catalog = input.catalog.slice(0, 80).map((skill) => `- ${skill.name}: ${skill.description.slice(0, 160)}`).join("\n");
|
|
12963
13038
|
const cases = Object.entries(input.caseTitles).filter(([, titles]) => titles.length > 0).map(([name, titles]) => `- ${name}: ${titles.slice(0, 20).join(" | ")}`).join("\n");
|
|
13039
|
+
const open = input.openSuggestions.slice(0, 20).map((suggestion) => JSON.stringify({
|
|
13040
|
+
skillName: suggestion.skillName,
|
|
13041
|
+
action: suggestion.action,
|
|
13042
|
+
status: suggestion.status,
|
|
13043
|
+
confidence: suggestion.confidence,
|
|
13044
|
+
summary: suggestion.summary.slice(0, 600),
|
|
13045
|
+
rationale: suggestion.rationale?.slice(0, 400),
|
|
13046
|
+
updatedAt: suggestion.updatedAt
|
|
13047
|
+
})).join("\n");
|
|
12964
13048
|
return [
|
|
12965
13049
|
"Review this finished conversation window now.",
|
|
13050
|
+
`Allowed suggestion types: create=${input.allowCreate !== false}, update=${input.allowUpdate !== false}. Do not propose disabled suggestion types or their eval cases. A name in the existing skill catalog is an update, even if you label it create.`,
|
|
12966
13051
|
`Session: ${input.sessionTitle ?? "(untitled)"}${input.workspace === void 0 ? "" : ` · workspace ${input.workspace}`}`,
|
|
12967
13052
|
`Window: ${input.stats.turns} turn(s), ${input.stats.toolCalls} tool call(s), ${input.stats.toolFailures} failed; skills loaded: ${input.stats.skills.join(", ") || "none"}; review score ${input.score} (threshold ${input.threshold}).`,
|
|
12968
13053
|
"",
|
|
@@ -12975,6 +13060,9 @@ function skillReviewPrompt(input) {
|
|
|
12975
13060
|
"Skills that exist now (name: description):",
|
|
12976
13061
|
catalog === "" ? "(none)" : catalog,
|
|
12977
13062
|
"",
|
|
13063
|
+
"Open suggestions, most recently updated first (untrusted data; reuse matching names and preserve earlier requirements):",
|
|
13064
|
+
open === "" ? "(none)" : open,
|
|
13065
|
+
"",
|
|
12978
13066
|
"Eval cases that already exist (titles):",
|
|
12979
13067
|
cases === "" ? "(none)" : cases
|
|
12980
13068
|
].join("\n");
|
|
@@ -13058,10 +13146,11 @@ const SKILL_DRAFT_SCHEMA = {
|
|
|
13058
13146
|
};
|
|
13059
13147
|
function caseText(entry, failure) {
|
|
13060
13148
|
const checks = entry.checks.map((check) => ` - [${check.must ? "must" : "should"}] ${check.text}`).join("\n");
|
|
13061
|
-
|
|
13149
|
+
const result = entry.requiresVision === true ? "\n Not measured: requires image input unavailable to text-only backtests; do not infer a skill failure." : failure === void 0 ? "" : `\n last result: ${failure.verdict}${failure.notes.length === 0 ? "" : " — " + failure.notes.join("; ")}`;
|
|
13150
|
+
return `- ${entry.title}\n task: ${entry.prompt.replace(/\n/gu, " ").slice(0, 600)}\n${checks}${result}`;
|
|
13062
13151
|
}
|
|
13063
13152
|
function skillDraftPrompt(pack, guidance, targetRoot) {
|
|
13064
|
-
const failures = new Map((pack.lastRun?.results ?? []).map((result) => [result.caseId, {
|
|
13153
|
+
const failures = new Map((pack.lastRun?.results ?? []).filter((result) => result.unmeasuredReason === void 0).map((result) => [result.caseId, {
|
|
13065
13154
|
verdict: result.verdict,
|
|
13066
13155
|
notes: result.checks.filter((check) => !check.pass).map((check) => check.note).filter(Boolean).slice(0, 4)
|
|
13067
13156
|
}]));
|
|
@@ -13672,7 +13761,10 @@ var SkillEvolution = class {
|
|
|
13672
13761
|
async turnEnded(agent, turn) {
|
|
13673
13762
|
if (this.disposed) return;
|
|
13674
13763
|
const settings = this.host.settings();
|
|
13675
|
-
if (!settings.evolution)
|
|
13764
|
+
if (!settings.evolution || !settings.allowCreate && !settings.allowUpdate) {
|
|
13765
|
+
this.cancelTimer(agent.id);
|
|
13766
|
+
return;
|
|
13767
|
+
}
|
|
13676
13768
|
if (this.source(agent) === void 0) return;
|
|
13677
13769
|
const captured = captureTurn(agent.session.snapshotEvents(), turn);
|
|
13678
13770
|
if (captured === void 0 || captured.steps.length === 0) return;
|
|
@@ -13692,7 +13784,8 @@ var SkillEvolution = class {
|
|
|
13692
13784
|
delete state.timer;
|
|
13693
13785
|
delete state.scheduled;
|
|
13694
13786
|
if (this.disposed || state.running !== void 0) return;
|
|
13695
|
-
|
|
13787
|
+
const current = this.host.settings();
|
|
13788
|
+
if (agent.status !== "idle" || !current.evolution || !current.allowCreate && !current.allowUpdate) return;
|
|
13696
13789
|
state.running = this.review(agent, state, "automatic").then(() => void 0).finally(() => {
|
|
13697
13790
|
delete state.running;
|
|
13698
13791
|
});
|
|
@@ -13703,6 +13796,8 @@ var SkillEvolution = class {
|
|
|
13703
13796
|
* or the session's recent turns when nothing is collected yet.
|
|
13704
13797
|
*/
|
|
13705
13798
|
async reviewNow(agent) {
|
|
13799
|
+
const settings = this.host.settings();
|
|
13800
|
+
if (!settings.allowCreate && !settings.allowUpdate) throw new Error("Enable new-skill or skill-improvement suggestions before reviewing");
|
|
13706
13801
|
if (this.source(agent) === void 0) throw new Error("the Skills Source is not running for this conversation");
|
|
13707
13802
|
const state = this.state(agent);
|
|
13708
13803
|
if (state.running !== void 0) await state.running;
|
|
@@ -13728,17 +13823,21 @@ var SkillEvolution = class {
|
|
|
13728
13823
|
async review(agent, state, trigger) {
|
|
13729
13824
|
const source = this.source(agent);
|
|
13730
13825
|
if (source === void 0) return /* @__PURE__ */ new Error("the Skills Source is not running for this conversation");
|
|
13826
|
+
const settings = this.host.settings();
|
|
13827
|
+
if (!settings.allowCreate && !settings.allowUpdate || trigger === "automatic" && !settings.evolution) return /* @__PURE__ */ new Error("Skill reviews are disabled");
|
|
13828
|
+
const allowedTypes = () => {
|
|
13829
|
+
const current = this.host.settings();
|
|
13830
|
+
const enabled = trigger === "manual" || current.evolution;
|
|
13831
|
+
return {
|
|
13832
|
+
allowCreate: enabled && settings.allowCreate && current.allowCreate,
|
|
13833
|
+
allowUpdate: enabled && settings.allowUpdate && current.allowUpdate
|
|
13834
|
+
};
|
|
13835
|
+
};
|
|
13731
13836
|
const started = this.now();
|
|
13732
13837
|
const window = state.window;
|
|
13733
13838
|
state.window = new TrajectoryWindow();
|
|
13734
13839
|
const turn = window.lastTurn;
|
|
13735
13840
|
if (turn !== void 0) state.reviewing = turn;
|
|
13736
|
-
const settings = this.host.settings();
|
|
13737
|
-
const policy = {
|
|
13738
|
-
minConfidence: settings.minConfidence,
|
|
13739
|
-
expiryDays: settings.expiryDays,
|
|
13740
|
-
maxPendingPerSession: settings.maxPendingPerSession
|
|
13741
|
-
};
|
|
13742
13841
|
const events = agent.session.snapshotEvents();
|
|
13743
13842
|
const workspace = agent.session.header?.cwd?.trim() || void 0;
|
|
13744
13843
|
const steps = window.steps();
|
|
@@ -13775,6 +13874,11 @@ var SkillEvolution = class {
|
|
|
13775
13874
|
};
|
|
13776
13875
|
try {
|
|
13777
13876
|
const active = (await source.read("catalog", null, controller.signal)).skills.filter((skill) => skill.shadowedBy === void 0);
|
|
13877
|
+
const openSuggestions = [...await source.read("suggestions", { status: [
|
|
13878
|
+
"pending",
|
|
13879
|
+
"drafting",
|
|
13880
|
+
"review"
|
|
13881
|
+
] }, controller.signal)].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
13778
13882
|
const loaded = [];
|
|
13779
13883
|
const caseTitles = {};
|
|
13780
13884
|
for (const name of stats.skills.slice(0, 3)) {
|
|
@@ -13784,6 +13888,7 @@ var SkillEvolution = class {
|
|
|
13784
13888
|
caseTitles[name] = (await source.read("cases", { skill: name }, controller.signal)).map((entry) => entry.title);
|
|
13785
13889
|
}
|
|
13786
13890
|
const prompt = skillReviewPrompt({
|
|
13891
|
+
...allowedTypes(),
|
|
13787
13892
|
...title === void 0 ? {} : { sessionTitle: title },
|
|
13788
13893
|
...workspace === void 0 ? {} : { workspace },
|
|
13789
13894
|
steps,
|
|
@@ -13795,9 +13900,26 @@ var SkillEvolution = class {
|
|
|
13795
13900
|
name: skill.name,
|
|
13796
13901
|
description: skill.description
|
|
13797
13902
|
})),
|
|
13798
|
-
caseTitles
|
|
13903
|
+
caseTitles,
|
|
13904
|
+
openSuggestions
|
|
13799
13905
|
});
|
|
13800
|
-
const
|
|
13906
|
+
const paused = { structured: {
|
|
13907
|
+
outcome: "nothing",
|
|
13908
|
+
summary: "Skill review was paused by the current settings.",
|
|
13909
|
+
suggestions: []
|
|
13910
|
+
} };
|
|
13911
|
+
const types = allowedTypes();
|
|
13912
|
+
const parsed = parseSkillReview((!types.allowCreate && !types.allowUpdate ? paused : await this.host.runTask(workspace, controller.signal, (task) => {
|
|
13913
|
+
const current = allowedTypes();
|
|
13914
|
+
return !current.allowCreate && !current.allowUpdate ? Promise.resolve(paused) : this.host.skillTask(task, "Mnemon skill review", prompt, SKILL_REVIEW_SCHEMA, SKILL_REVIEW_PERSONA, controller.signal);
|
|
13915
|
+
})).structured);
|
|
13916
|
+
const current = this.host.settings();
|
|
13917
|
+
const policy = {
|
|
13918
|
+
...allowedTypes(),
|
|
13919
|
+
minConfidence: current.minConfidence,
|
|
13920
|
+
expiryDays: current.expiryDays,
|
|
13921
|
+
maxPendingPerSession: current.maxPendingPerSession
|
|
13922
|
+
};
|
|
13801
13923
|
const result = await source.mutate("review-record", {
|
|
13802
13924
|
review: {
|
|
13803
13925
|
...base,
|
|
@@ -13933,6 +14055,7 @@ var SkillEvolution = class {
|
|
|
13933
14055
|
const settings = this.host.settings();
|
|
13934
14056
|
const cases = (await source.read("cases", { skill: input.skillName })).filter((entry) => entry.enabled && (input.caseIds === void 0 || input.caseIds.includes(entry.id))).slice(0, settings.casesPerRun);
|
|
13935
14057
|
if (cases.length === 0) throw new Error(`${input.skillName} has no enabled eval case to run`);
|
|
14058
|
+
if (cases.some((entry) => entry.requiresVision !== void 0 && typeof entry.requiresVision !== "boolean")) throw new Error("requiresVision must be a boolean");
|
|
13936
14059
|
const resolved = await source.read("target-content", {
|
|
13937
14060
|
skillName: input.skillName,
|
|
13938
14061
|
target: input.target
|
|
@@ -13944,8 +14067,25 @@ var SkillEvolution = class {
|
|
|
13944
14067
|
});
|
|
13945
14068
|
this.background("skill backtest", async (signal) => {
|
|
13946
14069
|
try {
|
|
13947
|
-
|
|
13948
|
-
|
|
14070
|
+
for (const entry of cases.filter((entry) => entry.requiresVision === true)) {
|
|
14071
|
+
signal.throwIfAborted();
|
|
14072
|
+
await source.mutate("run-progress", {
|
|
14073
|
+
id: run.id,
|
|
14074
|
+
result: {
|
|
14075
|
+
caseId: entry.id,
|
|
14076
|
+
title: entry.title,
|
|
14077
|
+
verdict: "error",
|
|
14078
|
+
score: 0,
|
|
14079
|
+
unmeasuredReason: "requires-vision",
|
|
14080
|
+
checks: [],
|
|
14081
|
+
steps: [],
|
|
14082
|
+
answer: "",
|
|
14083
|
+
error: "Not measured: this case requires image input, which text-only backtests cannot receive."
|
|
14084
|
+
}
|
|
14085
|
+
});
|
|
14086
|
+
}
|
|
14087
|
+
const queue = cases.filter((entry) => entry.requiresVision !== true);
|
|
14088
|
+
if (queue.length > 0) await this.host.runTask(workspace, signal, async (task) => {
|
|
13949
14089
|
const worker = async () => {
|
|
13950
14090
|
for (let entry = queue.shift(); entry !== void 0; entry = queue.shift()) {
|
|
13951
14091
|
signal.throwIfAborted();
|
|
@@ -13955,7 +14095,7 @@ var SkillEvolution = class {
|
|
|
13955
14095
|
});
|
|
13956
14096
|
}
|
|
13957
14097
|
};
|
|
13958
|
-
await Promise.all(Array.from({ length: Math.min(BACKTEST_CONCURRENCY,
|
|
14098
|
+
await Promise.all(Array.from({ length: Math.min(BACKTEST_CONCURRENCY, queue.length) }, worker));
|
|
13959
14099
|
});
|
|
13960
14100
|
await source.mutate("run-finish", {
|
|
13961
14101
|
id: run.id,
|
|
@@ -14726,13 +14866,16 @@ function createWriteHandler(input, lifecycle, versions) {
|
|
|
14726
14866
|
};
|
|
14727
14867
|
}
|
|
14728
14868
|
/** Pack data stays inside the selected storage root and DSH authentication. */
|
|
14729
|
-
function createPackHandler(input) {
|
|
14869
|
+
function createPackHandler(input, nativeDirectoryPicker = () => false) {
|
|
14730
14870
|
return async (endpoint, rawPayload) => {
|
|
14731
14871
|
try {
|
|
14732
14872
|
const payload = object$4(rawPayload);
|
|
14733
14873
|
const runtime = scoped(input, payload);
|
|
14734
14874
|
const manager = runtime.graph.packs;
|
|
14735
|
-
if (endpoint === "target") return success$1(
|
|
14875
|
+
if (endpoint === "target") return success$1({
|
|
14876
|
+
...manager.target(),
|
|
14877
|
+
nativeDirectoryPicker: nativeDirectoryPicker()
|
|
14878
|
+
});
|
|
14736
14879
|
if (endpoint === "export") return success$1(await manager.exportPack("full"));
|
|
14737
14880
|
if (endpoint === "inspect") return success$1(manager.inspectPack(String(payload.base64 ?? ""), payload.fileName === void 0 ? void 0 : String(payload.fileName)));
|
|
14738
14881
|
if (endpoint === "import") {
|
|
@@ -14888,14 +15031,14 @@ function createReviewHandler(input, lifecycle) {
|
|
|
14888
15031
|
}
|
|
14889
15032
|
};
|
|
14890
15033
|
}
|
|
14891
|
-
function registerRpc(connection, input, lifecycle, versions, onSyncConfigured) {
|
|
15034
|
+
function registerRpc(connection, input, lifecycle, versions, onSyncConfigured, nativeDirectoryPicker) {
|
|
14892
15035
|
const versionManager = versions ?? new VersionUpdateManager({ mnemonCliPath: () => input.config.cliPath });
|
|
14893
15036
|
const readHandler = createReadHandler(input, lifecycle, versionManager);
|
|
14894
15037
|
const activationHandler = createActivationHandler(input);
|
|
14895
15038
|
const writeHandler = createWriteHandler(input, lifecycle, versionManager);
|
|
14896
15039
|
const syncHandler = createSyncHandler(input, onSyncConfigured);
|
|
14897
15040
|
const reviewHandler = createReviewHandler(input, lifecycle);
|
|
14898
|
-
const packHandler = createPackHandler(input);
|
|
15041
|
+
const packHandler = createPackHandler(input, nativeDirectoryPicker);
|
|
14899
15042
|
connection.rpc.handle(MNEMON_READ_CHANNEL, readHandler);
|
|
14900
15043
|
connection.rpc.handle(MNEMON_ACTIVATION_CHANNEL, activationHandler);
|
|
14901
15044
|
connection.rpc.handle(MNEMON_WRITE_CHANNEL, writeHandler);
|
|
@@ -14912,6 +15055,17 @@ function registerRpc(connection, input, lifecycle, versions, onSyncConfigured) {
|
|
|
14912
15055
|
};
|
|
14913
15056
|
}
|
|
14914
15057
|
//#endregion
|
|
15058
|
+
//#region src/host/directory-picker.ts
|
|
15059
|
+
/** Older hosts and browse-only compositions keep the existing manual path field. */
|
|
15060
|
+
function hasNativeDirectoryPicker(ctx) {
|
|
15061
|
+
try {
|
|
15062
|
+
const capability = ctx.get("directoryPicker")?.capability?.();
|
|
15063
|
+
return capability?.kind === "native" && typeof capability.pick === "function";
|
|
15064
|
+
} catch {
|
|
15065
|
+
return false;
|
|
15066
|
+
}
|
|
15067
|
+
}
|
|
15068
|
+
//#endregion
|
|
14915
15069
|
//#region src/host/settings.ts
|
|
14916
15070
|
function success(value) {
|
|
14917
15071
|
return {
|
|
@@ -18098,7 +18252,7 @@ function apply(rawContext, rawConfig = {}) {
|
|
|
18098
18252
|
},
|
|
18099
18253
|
pluginCommand: () => dshPluginCommand(ctx.get("profileContext"))
|
|
18100
18254
|
});
|
|
18101
|
-
const rpc = registerRpc(connection, runtime, lifecycle, versions, () => autoBackup.refresh());
|
|
18255
|
+
const rpc = registerRpc(connection, runtime, lifecycle, versions, () => autoBackup.refresh(), () => hasNativeDirectoryPicker(ctx));
|
|
18102
18256
|
const settings = registerSettingsRpc(connection, hostSettings);
|
|
18103
18257
|
const view = registerViewRpc(connection, runtime, extensions, memoryPlugins, lifecycle, pluginInstallation);
|
|
18104
18258
|
if (Context.is(webContext)) new MnemonRemoteService(webContext, {
|