@avantf/dsh-mem 0.1.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/LICENSE +21 -0
- package/README.md +140 -0
- package/lib/client.js +5901 -0
- package/lib/client.js.map +1 -0
- package/lib/dsh-build.json +7 -0
- package/lib/index.js +14329 -0
- package/lib/types/client/domains.d.ts +52 -0
- package/lib/types/client/domains.d.ts.map +1 -0
- package/lib/types/client/domains.js +25 -0
- package/lib/types/client/domains.js.map +1 -0
- package/lib/types/client/index.d.ts +35 -0
- package/lib/types/client/index.d.ts.map +1 -0
- package/lib/types/client/index.js +1351 -0
- package/lib/types/client/index.js.map +1 -0
- package/lib/types/client/ingest.d.ts +24 -0
- package/lib/types/client/ingest.d.ts.map +1 -0
- package/lib/types/client/ingest.js +30 -0
- package/lib/types/client/ingest.js.map +1 -0
- package/lib/types/client/paging.d.ts +30 -0
- package/lib/types/client/paging.d.ts.map +1 -0
- package/lib/types/client/paging.js +36 -0
- package/lib/types/client/paging.js.map +1 -0
- package/lib/types/client/summarize.d.ts +11 -0
- package/lib/types/client/summarize.d.ts.map +1 -0
- package/lib/types/client/summarize.js +79 -0
- package/lib/types/client/summarize.js.map +1 -0
- package/lib/types/envinit-bootstrap.d.ts +43 -0
- package/lib/types/envinit-bootstrap.js +323 -0
- package/lib/types/envinit.d.ts +145 -0
- package/lib/types/envinit.d.ts.map +1 -0
- package/lib/types/envinit.js +495 -0
- package/lib/types/envinit.js.map +1 -0
- package/lib/types/hints.d.ts +42 -0
- package/lib/types/hints.d.ts.map +1 -0
- package/lib/types/hints.js +54 -0
- package/lib/types/hints.js.map +1 -0
- package/lib/types/index.d.ts +74 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +708 -0
- package/lib/types/index.js.map +1 -0
- package/lib/types/inject.d.ts +14 -0
- package/lib/types/inject.d.ts.map +1 -0
- package/lib/types/inject.js +14 -0
- package/lib/types/inject.js.map +1 -0
- package/lib/types/open.d.ts +27 -0
- package/lib/types/open.d.ts.map +1 -0
- package/lib/types/open.js +133 -0
- package/lib/types/open.js.map +1 -0
- package/lib/types/prompt.d.ts +49 -0
- package/lib/types/prompt.d.ts.map +1 -0
- package/lib/types/prompt.js +65 -0
- package/lib/types/prompt.js.map +1 -0
- package/lib/types/provision.d.ts +117 -0
- package/lib/types/provision.d.ts.map +1 -0
- package/lib/types/provision.js +233 -0
- package/lib/types/provision.js.map +1 -0
- package/lib/types/remote.d.ts +17 -0
- package/lib/types/remote.d.ts.map +1 -0
- package/lib/types/remote.js +233 -0
- package/lib/types/remote.js.map +1 -0
- package/lib/types/tool_schema.d.ts +40 -0
- package/lib/types/tool_schema.d.ts.map +1 -0
- package/lib/types/tool_schema.js +149 -0
- package/lib/types/tool_schema.js.map +1 -0
- package/package.json +109 -0
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment initialisation for the memory plugin, through the family framework
|
|
3
|
+
* `@avantf/dsh-envinit`.
|
|
4
|
+
*
|
|
5
|
+
* The shape is fixed by the framework's DESIGN §7.2 and is the same for every plugin:
|
|
6
|
+
*
|
|
7
|
+
* bootstrap (inlined) → load the framework → register + declare → wait for the `blocking` set →
|
|
8
|
+
* dispatch the `background` set → the plugin's own pre-mount check.
|
|
9
|
+
*
|
|
10
|
+
* What this plugin needs, in three phases:
|
|
11
|
+
*
|
|
12
|
+
* 1. **`mem:compat`** (`npm-package`, `startup: 'blocking'`) — the family compatibility gate
|
|
13
|
+
* `@avantf/dsh-compat`. It has to be there BEFORE anything is registered, because a proven
|
|
14
|
+
* incompatible host must refuse the mount with nothing half-registered. This replaces the
|
|
15
|
+
* bespoke self-heal the plugin used to run itself (`@avantf/mem-provision`'s
|
|
16
|
+
* `ensureCompatBase`), whose private root (`<dataHome>/dsh-compat/**`) the framework
|
|
17
|
+
* deliberately does not read.
|
|
18
|
+
* 2. **`mem:pandoc`** (`binary-archive`, `startup: 'background'`) — the documented "expensive but
|
|
19
|
+
* not startup-blocking" resource. It is declared AFTER the runtime exists, because its spec
|
|
20
|
+
* comes from the resolved config (`tools.auto_install`, `tools.mirror`), and it is dispatched
|
|
21
|
+
* without waiting: the caller continues its own initialisation and hooks the outcome through
|
|
22
|
+
* `onSettled`.
|
|
23
|
+
* 3. **`mem:model`** (`model-cache`, `startup: 'background'`) — the embedding model. It uses the
|
|
24
|
+
* framework's `flat` layout, whose files land at `<root>/<repo>/<file>` — exactly the shape
|
|
25
|
+
* `@huggingface/transformers` reads under its `cacheDir` — so the runtime loads the framework's
|
|
26
|
+
* copy instead of fetching a second one. For the default repo the file list is the narrow set
|
|
27
|
+
* the runtime actually opens (see {@link MODEL_FILES}); any other repo omits the list, because
|
|
28
|
+
* a fixed six-file list made the item fail for a repo whose file set differs. The endpoint is
|
|
29
|
+
* the mirror only the operator (env) can move. It is NOT declared when the runtime reads its
|
|
30
|
+
* models elsewhere (`AVANTF_MEM_MODEL_CACHE`) — that would install a second, never-read copy.
|
|
31
|
+
* A model that cannot be fetched is a WARNING: the semantic path degrades to FTS+entity, it
|
|
32
|
+
* never refuses the mount.
|
|
33
|
+
*
|
|
34
|
+
* Two hard rules:
|
|
35
|
+
*
|
|
36
|
+
* - **The framework is never statically imported.** Only `import type` and the inlined bootstrap
|
|
37
|
+
* are static; the value comes from `loadFramework()`. A top-level value import would throw before
|
|
38
|
+
* the bootstrap ran — exactly the broken-tree case the bootstrap exists for.
|
|
39
|
+
* - **Nothing here refuses the mount.** "Cannot tell" is not "incompatible": a missing framework,
|
|
40
|
+
* an unavailable gate or a failed resource is a WARNING, and the plugin mounts with its tools,
|
|
41
|
+
* service, prompt and Remote face intact.
|
|
42
|
+
*
|
|
43
|
+
* @module @avantf/dsh-mem/envinit
|
|
44
|
+
*/
|
|
45
|
+
import { readFile } from 'node:fs/promises';
|
|
46
|
+
import { createRequire } from 'node:module';
|
|
47
|
+
import { homedir } from 'node:os';
|
|
48
|
+
import { dirname, join, resolve } from 'node:path';
|
|
49
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
50
|
+
import { envAutoDownload, expandHome } from '@avantf/mem-contract';
|
|
51
|
+
import { PANDOC_ARTIFACT_ID, PANDOC_BINARY, PANDOC_PACKS, PANDOC_VERSION } from '@avantf/mem-provision';
|
|
52
|
+
import { loadFramework, readDependencyRange } from './envinit-bootstrap.js';
|
|
53
|
+
import { COMPAT_PACKAGE, compatRange, reasonOf, runtimeFromCompat, warn, } from './provision.js';
|
|
54
|
+
/** The framework package, as declared in this plugin's `peerDependencies`. */
|
|
55
|
+
const FRAMEWORK_PACKAGE = '@avantf/dsh-envinit';
|
|
56
|
+
/** The plugin namespace every item is declared under (`<plugin>:<name>`, framework DESIGN §13.4). */
|
|
57
|
+
const PLUGIN = 'mem';
|
|
58
|
+
/**
|
|
59
|
+
* The item ids. `resolve()` / `onSettled` are keyed by them, so the DSH plugin compares against these
|
|
60
|
+
* names rather than re-spelling literals.
|
|
61
|
+
*/
|
|
62
|
+
export const COMPAT_ITEM = 'mem:compat';
|
|
63
|
+
export const PANDOC_ITEM = 'mem:pandoc';
|
|
64
|
+
export const MODEL_ITEM = 'mem:model';
|
|
65
|
+
/**
|
|
66
|
+
* The default ONNX embedding repository — the one `semantic.local_model` defaults to and the one
|
|
67
|
+
* {@link MODEL_FILES} describes. A DIFFERENT repo is a different file set, which is why the item
|
|
68
|
+
* omits `spec.files` for it (see {@link managedModelSpec}).
|
|
69
|
+
*/
|
|
70
|
+
export const DEFAULT_MODEL_REPO = 'Xenova/bge-small-zh-v1.5';
|
|
71
|
+
/**
|
|
72
|
+
* The files the local embedding runtime actually requests for the DEFAULT ONNX model.
|
|
73
|
+
*
|
|
74
|
+
* Measured, not guessed: with an empty cache, `@huggingface/transformers@4.x` resolving
|
|
75
|
+
* `feature-extraction` for `Xenova/bge-small-zh-v1.5` fetches exactly these four — `config.json`,
|
|
76
|
+
* `tokenizer.json`, `tokenizer_config.json` and the fp32 `onnx/model.onnx`. The repo ALSO carries
|
|
77
|
+
* `special_tokens_map.json`, `vocab.txt` and seven other ONNX quantisations the default run never
|
|
78
|
+
* opens; declaring them would download hundreds of megabytes of dead weight. The list stays narrow
|
|
79
|
+
* to what is read.
|
|
80
|
+
*/
|
|
81
|
+
export const MODEL_FILES = [
|
|
82
|
+
'config.json',
|
|
83
|
+
'tokenizer.json',
|
|
84
|
+
'tokenizer_config.json',
|
|
85
|
+
'onnx/model.onnx',
|
|
86
|
+
];
|
|
87
|
+
/** Startup budget for the blocking set; the framework's default is the same. */
|
|
88
|
+
const DEADLINE_MS = 15_000;
|
|
89
|
+
/** This module's warning token, so one grep finds every environment-initialisation line. */
|
|
90
|
+
const OWN_PREFIX = 'envinit:';
|
|
91
|
+
/**
|
|
92
|
+
* The model item the framework should own, or `undefined` when it should not.
|
|
93
|
+
*
|
|
94
|
+
* Two refusals, both deliberate:
|
|
95
|
+
*
|
|
96
|
+
* 1. **Not a local backend** — nothing to provision.
|
|
97
|
+
* 2. **The runtime reads its models from elsewhere** — `semantic.cache_dir` is not the framework's
|
|
98
|
+
* `<home>/models`. That happens through the operator escape hatch `AVANTF_MEM_MODEL_CACHE`
|
|
99
|
+
* (env layer ④): the runtime loads from that directory, so a `mem:model` item would install a
|
|
100
|
+
* full second copy under `<home>/models` that nothing ever reads (~190 MB). Declaring nothing
|
|
101
|
+
* is the fix; the caller warms from the override directory instead.
|
|
102
|
+
*
|
|
103
|
+
* `files` is the narrow {@link MODEL_FILES} set only for the DEFAULT repo; a user-changed repo has a
|
|
104
|
+
* different file set, and a stale six-file list would make the item `failed` while the runtime could
|
|
105
|
+
* serve it. Empty means "omit `spec.files`": the framework then installs the repository's own file
|
|
106
|
+
* list.
|
|
107
|
+
*/
|
|
108
|
+
export function managedModelSpec(semantic, modelsRoot) {
|
|
109
|
+
if (semantic.backend !== 'local_bge')
|
|
110
|
+
return undefined;
|
|
111
|
+
if (!sameDir(semantic.cache_dir, modelsRoot))
|
|
112
|
+
return undefined;
|
|
113
|
+
return {
|
|
114
|
+
repo: semantic.local_model,
|
|
115
|
+
files: semantic.local_model === DEFAULT_MODEL_REPO ? MODEL_FILES : [],
|
|
116
|
+
endpoint: semantic.mirror,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/** Same directory, after `~/` expansion and normalisation (a trailing slash is not a difference). */
|
|
120
|
+
function sameDir(a, b) {
|
|
121
|
+
return resolve(expandHome(a)) === resolve(expandHome(b));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* The family root: `$AVANTF_HOME`, else `~/.avantf/env`.
|
|
125
|
+
*
|
|
126
|
+
* `AVANTF_HOME` is the same variable the engine uses for its DATA home (`memory/`, `knowledge/`),
|
|
127
|
+
* and that is deliberate: setting it redirects a whole tree (data AND managed resources), which is
|
|
128
|
+
* exactly what a test or a sandboxed host needs. Unset — the normal case — the family root is the
|
|
129
|
+
* framework's documented default and the data home stays `~/.avantf`.
|
|
130
|
+
*/
|
|
131
|
+
function resolveHome() {
|
|
132
|
+
const configured = process.env['AVANTF_HOME'];
|
|
133
|
+
return configured !== undefined && configured.trim() !== '' ? configured : join(homedir(), '.avantf', 'env');
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The download gate. Off when EITHER switch is off:
|
|
137
|
+
*
|
|
138
|
+
* - `AVANTF_MEM_AUTO_DOWNLOAD=0` — this project's documented kill switch (the CLI, the MCP server
|
|
139
|
+
* and every test honour it);
|
|
140
|
+
* - `AVANTF_ENVINIT_AUTO_DOWNLOAD=0` — the family framework's switch, so an operator can turn the
|
|
141
|
+
* whole family's provisioning off in one place.
|
|
142
|
+
*
|
|
143
|
+
* The two-variable rule lives in ONE place (`@avantf/mem-contract`'s `envAutoDownload`), which the
|
|
144
|
+
* config loader and both model adapters also call: a family switch that stops the framework but not
|
|
145
|
+
* the runtime's own fetch is exactly the bug that duplication would reintroduce.
|
|
146
|
+
*/
|
|
147
|
+
function envDownloadsAllowed() {
|
|
148
|
+
return envAutoDownload() ?? true;
|
|
149
|
+
}
|
|
150
|
+
/** A `ProvisionLogger` over the plugin's own logger (the framework also wants `debug`). */
|
|
151
|
+
function provisionLogger(log) {
|
|
152
|
+
return {
|
|
153
|
+
debug: (message) => { log?.info(message); },
|
|
154
|
+
info: (message) => { log?.info(message); },
|
|
155
|
+
warn: (message) => { log?.warn(message); },
|
|
156
|
+
error: (message) => { log?.error(message); },
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* The file URL to `import()` for a managed npm copy.
|
|
161
|
+
*
|
|
162
|
+
* The framework hands back the package DIRECTORY (`<version dir>/node_modules/<name>`), and a
|
|
163
|
+
* directory is not importable, so the entry is read from the copy's own manifest the way Node would:
|
|
164
|
+
* `exports["."]` first, then `main`.
|
|
165
|
+
*/
|
|
166
|
+
async function entryUrlOf(packageDir) {
|
|
167
|
+
let manifest;
|
|
168
|
+
try {
|
|
169
|
+
manifest = JSON.parse(await readFile(join(packageDir, 'package.json'), 'utf8'));
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
const dot = manifest.exports?.['.'];
|
|
175
|
+
const fromExports = typeof dot === 'string'
|
|
176
|
+
? dot
|
|
177
|
+
: dot?.default;
|
|
178
|
+
const entry = typeof fromExports === 'string'
|
|
179
|
+
? fromExports
|
|
180
|
+
: typeof manifest.main === 'string' ? manifest.main : './index.js';
|
|
181
|
+
return pathToFileURL(join(packageDir, entry)).href;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* The resolved directory of a peer in THIS plugin's tree.
|
|
185
|
+
*
|
|
186
|
+
* The framework must reuse the host's own copy for identity-sensitive peers, and it cannot find them
|
|
187
|
+
* by itself: its resolver looks at `process.cwd()` and at its own module URL — neither is the
|
|
188
|
+
* plugin's tree. So the caller hands the directory over explicitly (`NpmPackageSpec.peers[].dir`);
|
|
189
|
+
* without it the item fails with `peer/unsatisfied`.
|
|
190
|
+
*/
|
|
191
|
+
function peerDirOf(name) {
|
|
192
|
+
const require = createRequire(import.meta.url);
|
|
193
|
+
try {
|
|
194
|
+
return dirname(require.resolve(`${name}/package.json`));
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// A package that does not export `./package.json`: walk up from its entry instead.
|
|
198
|
+
try {
|
|
199
|
+
let dir = dirname(require.resolve(name));
|
|
200
|
+
for (let depth = 0; depth < 6; depth += 1) {
|
|
201
|
+
if (dir.endsWith(`/${name}`))
|
|
202
|
+
return dir;
|
|
203
|
+
const parent = dirname(dir);
|
|
204
|
+
if (parent === dir)
|
|
205
|
+
break;
|
|
206
|
+
dir = parent;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// Not resolvable from this tree; the framework reports `peer/unsatisfied`.
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
/** The `mem:compat` item: the family compatibility gate, waited for before anything registers. */
|
|
216
|
+
function compatItem(framework, range, zodDir) {
|
|
217
|
+
return {
|
|
218
|
+
id: COMPAT_ITEM,
|
|
219
|
+
kind: framework.NPM_PACKAGE_KIND,
|
|
220
|
+
spec: {
|
|
221
|
+
name: COMPAT_PACKAGE,
|
|
222
|
+
range,
|
|
223
|
+
// The host's own `zod`, by directory: identity-sensitive, and the framework cannot find it
|
|
224
|
+
// from its own tree (see `peerDirOf`).
|
|
225
|
+
peers: [{ name: 'zod', ...(zodDir === undefined ? {} : { dir: zodDir }) }],
|
|
226
|
+
},
|
|
227
|
+
target: { root: 'runtime' },
|
|
228
|
+
// Never refuse: an unavailable gate must not take the memory engine down.
|
|
229
|
+
onMissing: { atStartup: 'degrade', atUse: 'degrade' },
|
|
230
|
+
startup: 'blocking',
|
|
231
|
+
schemaVersion: framework.ITEM_SCHEMA_VERSION,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* The `mem:pandoc` item: the pinned pandoc release as a `binary-archive`.
|
|
236
|
+
*
|
|
237
|
+
* The packs are `@avantf/mem-provision`'s (`PANDOC_PACKS`), the single source of the URLs and the
|
|
238
|
+
* measured digests; this only re-spells them in the framework's vocabulary (`format` → `archive`,
|
|
239
|
+
* and the binary as a NAME the archive search finds rather than a path inside the archive). The
|
|
240
|
+
* framework installs it to `<home>/tools/pandoc/3.11/bin/pandoc` — the same layout the converter
|
|
241
|
+
* already resolves, which is what makes the handover a config change and not a code change.
|
|
242
|
+
*/
|
|
243
|
+
function pandocItem(framework) {
|
|
244
|
+
const packs = {};
|
|
245
|
+
for (const [key, pack] of Object.entries(PANDOC_PACKS)) {
|
|
246
|
+
if (pack === undefined)
|
|
247
|
+
continue;
|
|
248
|
+
packs[key] = { url: pack.url, sha256: pack.sha256, archive: pack.format };
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
id: PANDOC_ITEM,
|
|
252
|
+
kind: framework.BINARY_ARCHIVE_KIND,
|
|
253
|
+
spec: {
|
|
254
|
+
id: PANDOC_ARTIFACT_ID,
|
|
255
|
+
version: PANDOC_VERSION,
|
|
256
|
+
binary: PANDOC_BINARY,
|
|
257
|
+
packs,
|
|
258
|
+
},
|
|
259
|
+
target: { root: 'tools' },
|
|
260
|
+
// A missing converter degrades the knowledge base's document ingestion, never the mount.
|
|
261
|
+
onMissing: { atStartup: 'degrade', atUse: 'error' },
|
|
262
|
+
startup: 'background',
|
|
263
|
+
schemaVersion: framework.ITEM_SCHEMA_VERSION,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* The `mem:model` item: the embedding model as a `model-cache` in the framework's `flat` layout.
|
|
268
|
+
*
|
|
269
|
+
* `flat` places the files at `<home>/models/<repo>/<file>` — the same tree `semantic.cache_dir`
|
|
270
|
+
* points at (the framework root, through `managedRoots`) and the same shape the local runtime reads.
|
|
271
|
+
* `files` is the narrow default-repo set (see {@link MODEL_FILES}); it is OMITTED for any other repo,
|
|
272
|
+
* whose file set this build cannot know, so the framework installs the repository's own list instead
|
|
273
|
+
* of failing on a missing fixed path. `endpoint` is the mirror resolved from the operator's env
|
|
274
|
+
* escape hatch, so neither the landing site nor the source is chosen by an end user's `config.yaml`.
|
|
275
|
+
*
|
|
276
|
+
* A missing model is a degraded semantic path, NOT a refused mount: both `onMissing` axes are
|
|
277
|
+
* `degrade`, and the engine falls back to FTS+entity.
|
|
278
|
+
*/
|
|
279
|
+
function modelItem(framework, model) {
|
|
280
|
+
return {
|
|
281
|
+
id: MODEL_ITEM,
|
|
282
|
+
kind: framework.MODEL_CACHE_KIND,
|
|
283
|
+
spec: {
|
|
284
|
+
repo: model.repo,
|
|
285
|
+
revision: 'main',
|
|
286
|
+
layout: 'flat',
|
|
287
|
+
...(model.files.length === 0 ? {} : { files: [...model.files] }),
|
|
288
|
+
endpoint: model.endpoint,
|
|
289
|
+
},
|
|
290
|
+
target: { root: 'models' },
|
|
291
|
+
onMissing: { atStartup: 'degrade', atUse: 'degrade' },
|
|
292
|
+
startup: 'background',
|
|
293
|
+
schemaVersion: framework.ITEM_SCHEMA_VERSION,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
let loaded;
|
|
297
|
+
let loading;
|
|
298
|
+
/**
|
|
299
|
+
* Ensure the framework, then the compatibility base, then dispatch the expensive resources.
|
|
300
|
+
*
|
|
301
|
+
* Never throws. Returns `undefined` when the framework cannot be loaded — the caller then warns and
|
|
302
|
+
* mounts on the legacy provisioning path (the engine's own `@avantf/mem-provision` sweep, whose
|
|
303
|
+
* default directories are the pre-migration ones). A framework that loads but cannot provide the
|
|
304
|
+
* base still returns a runtime, with `compat: undefined`: the mount must continue, and the resource
|
|
305
|
+
* items are still worth dispatching.
|
|
306
|
+
*
|
|
307
|
+
* The result is cached per process; a FAILED load is not, so a profile reload retries instead of
|
|
308
|
+
* replaying the first failure for the whole process lifetime.
|
|
309
|
+
*
|
|
310
|
+
* @param options - logger, family root, download policy and the test seams.
|
|
311
|
+
* @returns the loaded runtime, or `undefined` when the framework itself is unavailable.
|
|
312
|
+
*/
|
|
313
|
+
export async function loadEnvinit(options = {}) {
|
|
314
|
+
if (loaded !== undefined)
|
|
315
|
+
return loaded;
|
|
316
|
+
if (loading !== undefined)
|
|
317
|
+
return loading;
|
|
318
|
+
loading = loadGuarded(options).then((runtime) => {
|
|
319
|
+
// A failure is "cannot tell", not a verdict — and it may be transient (offline at boot,
|
|
320
|
+
// registry hiccup). Drop the cache so a profile reload, or a second instance in the same
|
|
321
|
+
// process, retries instead of replaying the first failure for the whole process lifetime.
|
|
322
|
+
if (runtime === undefined)
|
|
323
|
+
loading = undefined;
|
|
324
|
+
else
|
|
325
|
+
loaded = runtime;
|
|
326
|
+
return runtime;
|
|
327
|
+
}, () => {
|
|
328
|
+
loading = undefined;
|
|
329
|
+
return undefined;
|
|
330
|
+
});
|
|
331
|
+
return loading;
|
|
332
|
+
}
|
|
333
|
+
/** The guard that makes "never throws" true: every failure is a warning plus `undefined`. */
|
|
334
|
+
async function loadGuarded(options) {
|
|
335
|
+
try {
|
|
336
|
+
return await loadOnce(options);
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
warn(options.log, `${OWN_PREFIX} WARNING — environment initialisation failed (${reasonOf(error)}); the framework is SKIPPED and the plugin will mount anyway`);
|
|
340
|
+
return undefined;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/** The body of {@link loadEnvinit}; the cache above makes it run at most once per process. */
|
|
344
|
+
async function loadOnce(options) {
|
|
345
|
+
const home = options.home ?? resolveHome();
|
|
346
|
+
const range = await readDependencyRange(fileURLToPath(import.meta.url));
|
|
347
|
+
const autoDownload = options.autoDownload ?? envDownloadsAllowed();
|
|
348
|
+
const deadlineMs = options.deadlineMs ?? DEADLINE_MS;
|
|
349
|
+
// Step 1–2: bootstrap → the framework itself (the package manager's copy, zero download). The
|
|
350
|
+
// plugin's declared range is not judged here; it goes to `envinitRange` below, per manifest.
|
|
351
|
+
const framework = options.framework ?? await loadFramework({
|
|
352
|
+
logger: {
|
|
353
|
+
warn: (message) => { warn(options.log, `${FRAMEWORK_PACKAGE}: ${message}`); },
|
|
354
|
+
info: (message) => { options.log?.info(`${FRAMEWORK_PACKAGE}: ${message}`); },
|
|
355
|
+
},
|
|
356
|
+
});
|
|
357
|
+
if (framework === undefined) {
|
|
358
|
+
warn(options.log, `${OWN_PREFIX} WARNING — ${FRAMEWORK_PACKAGE} could not be made available; the plugin falls back to its own provisioning and mounts anyway`);
|
|
359
|
+
return undefined;
|
|
360
|
+
}
|
|
361
|
+
// Step 3–4: declare the blocking set and wait for it.
|
|
362
|
+
const provisioner = framework.createProvisioner({
|
|
363
|
+
home,
|
|
364
|
+
envinitRange: range,
|
|
365
|
+
logger: provisionLogger(options.log),
|
|
366
|
+
policy: { autoDownload, deadlineMs },
|
|
367
|
+
});
|
|
368
|
+
provisioner.register(framework.npmPackageProvider());
|
|
369
|
+
provisioner.declare({
|
|
370
|
+
plugin: PLUGIN,
|
|
371
|
+
items: [compatItem(framework, await compatRange(), peerDirOf('zod'))],
|
|
372
|
+
});
|
|
373
|
+
await provisioner.ensure({
|
|
374
|
+
only: [COMPAT_ITEM],
|
|
375
|
+
deadlineMs,
|
|
376
|
+
onSettled: (entry) => {
|
|
377
|
+
if (entry.action === 'failed') {
|
|
378
|
+
warn(options.log, `${OWN_PREFIX} WARNING — ${COMPAT_ITEM} failed (${String(entry.code)}): ${entry.reason ?? ''}`);
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
const disposers = [provisioner];
|
|
383
|
+
let compat;
|
|
384
|
+
const state = provisioner.resolve(COMPAT_ITEM);
|
|
385
|
+
if (state.state !== 'ready') {
|
|
386
|
+
warn(options.log, `${OWN_PREFIX} WARNING — ${COMPAT_PACKAGE} is unavailable (${describeState(state)}); the compatibility gate is SKIPPED and the plugin will mount anyway`);
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
try {
|
|
390
|
+
const module = options.compatModule ?? await importCompat(state.handle.dir);
|
|
391
|
+
if (module === undefined) {
|
|
392
|
+
warn(options.log, `${OWN_PREFIX} WARNING — ${COMPAT_PACKAGE} has no readable entry at ${state.handle.dir}; the compatibility gate is SKIPPED`);
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
compat = runtimeFromCompat(module);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
warn(options.log, `${OWN_PREFIX} WARNING — ${COMPAT_PACKAGE} could not be imported (${reasonOf(error)}); the compatibility gate is SKIPPED and the plugin will mount anyway`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
let disposed = false;
|
|
403
|
+
return {
|
|
404
|
+
home,
|
|
405
|
+
compat,
|
|
406
|
+
roots: { tools: join(home, 'tools'), models: join(home, 'models') },
|
|
407
|
+
provisionResources(plan, onSettled) {
|
|
408
|
+
if (disposed)
|
|
409
|
+
return;
|
|
410
|
+
const items = [];
|
|
411
|
+
if (plan.pandoc)
|
|
412
|
+
items.push(pandocItem(framework));
|
|
413
|
+
if (plan.model !== undefined)
|
|
414
|
+
items.push(modelItem(framework, plan.model));
|
|
415
|
+
if (items.length === 0)
|
|
416
|
+
return;
|
|
417
|
+
// A SECOND provisioner, on purpose: `policy.mirrors.archive` is the engine's `tools.mirror`,
|
|
418
|
+
// which is only known after the runtime resolved its config — while the compat provisioner had
|
|
419
|
+
// to exist before that, to run the gate. Two instances sharing one family root are supported by
|
|
420
|
+
// design (framework DESIGN §13.1), and their item sets are disjoint.
|
|
421
|
+
//
|
|
422
|
+
// `autoDownload` is per KIND: the env kill switches turn everything off, otherwise the model
|
|
423
|
+
// follows `semantic.auto_download` while pandoc keeps its own gate (`tools.auto_install`,
|
|
424
|
+
// which decides whether it is declared at all). Folding the two into one boolean would let
|
|
425
|
+
// `semantic.auto_download: false` skip a pandoc the operator explicitly asked for — or, the
|
|
426
|
+
// other way round, let a disabled model still hit the network.
|
|
427
|
+
const resources = framework.createProvisioner({
|
|
428
|
+
home,
|
|
429
|
+
envinitRange: range,
|
|
430
|
+
logger: provisionLogger(options.log),
|
|
431
|
+
policy: {
|
|
432
|
+
autoDownload: autoDownload ? { [framework.MODEL_CACHE_KIND]: plan.modelAutoDownload } : false,
|
|
433
|
+
deadlineMs,
|
|
434
|
+
mirrors: { archive: [...plan.archiveMirrors] },
|
|
435
|
+
},
|
|
436
|
+
});
|
|
437
|
+
resources.register(framework.binaryArchiveProvider());
|
|
438
|
+
resources.register(framework.modelCacheProvider());
|
|
439
|
+
resources.declare({ plugin: PLUGIN, items });
|
|
440
|
+
disposers.push(resources);
|
|
441
|
+
// Dispatched, not awaited: `startup: 'background'` items never occupy the ensure budget.
|
|
442
|
+
// The `.catch` is not decoration: an unhandled rejection is FATAL on a strict host (Node's
|
|
443
|
+
// default `--unhandled-rejections=throw`), and a memory plugin must not be able to take the
|
|
444
|
+
// host down over a resource it could not fetch. The compat ensure above is awaited instead,
|
|
445
|
+
// so its rejection is handled by `loadGuarded`.
|
|
446
|
+
void resources.ensure({
|
|
447
|
+
only: items.map(item => item.id),
|
|
448
|
+
onSettled: (entry) => {
|
|
449
|
+
try {
|
|
450
|
+
onSettled(entry);
|
|
451
|
+
}
|
|
452
|
+
catch (error) {
|
|
453
|
+
warn(options.log, `${OWN_PREFIX} WARNING — the onSettled callback failed (${reasonOf(error)})`);
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
}).catch((error) => {
|
|
457
|
+
warn(options.log, `${OWN_PREFIX} WARNING — declaring the background resources failed (${reasonOf(error)}); the plugin continues (tools stay registered)`);
|
|
458
|
+
});
|
|
459
|
+
},
|
|
460
|
+
dispose() {
|
|
461
|
+
if (disposed)
|
|
462
|
+
return;
|
|
463
|
+
disposed = true;
|
|
464
|
+
for (const instance of disposers.splice(0)) {
|
|
465
|
+
try {
|
|
466
|
+
instance.dispose();
|
|
467
|
+
}
|
|
468
|
+
catch {
|
|
469
|
+
// Disposal is best-effort; a throwing release must not break unmount.
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
loaded = undefined;
|
|
473
|
+
loading = undefined;
|
|
474
|
+
},
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
/** One line describing why a non-ready item is not ready, safe to put in a WARNING. */
|
|
478
|
+
function describeState(state) {
|
|
479
|
+
if (state.state === 'ready')
|
|
480
|
+
return `ready (${state.handle.source})`;
|
|
481
|
+
if (state.state === 'failed' || state.state === 'skipped') {
|
|
482
|
+
return `${state.state}: ${state.code}${state.detail === undefined ? '' : ` (${state.detail})`}`;
|
|
483
|
+
}
|
|
484
|
+
if (state.state === 'pending')
|
|
485
|
+
return 'pending (still being fetched)';
|
|
486
|
+
return state.state;
|
|
487
|
+
}
|
|
488
|
+
/** Load the managed copy's entry by file URL; `undefined` when it has no readable entry. */
|
|
489
|
+
async function importCompat(packageDir) {
|
|
490
|
+
const url = await entryUrlOf(packageDir);
|
|
491
|
+
if (url === undefined)
|
|
492
|
+
return undefined;
|
|
493
|
+
return (await import(url));
|
|
494
|
+
}
|
|
495
|
+
//# sourceMappingURL=envinit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envinit.js","sourceRoot":"","sources":["../../src/envinit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { RelevanceHit } from '@avantf/mem';
|
|
2
|
+
/**
|
|
3
|
+
* The plugin's CONDITIONAL hints: one line per store, contributed only when that store already
|
|
4
|
+
* holds something relevant to what the user just sent (DESIGN §12).
|
|
5
|
+
*
|
|
6
|
+
* These are deliberately NOT part of the always-on usage sections. A usage section says WHEN a
|
|
7
|
+
* store is worth consulting and therefore has to be paid for on every step of every session; this
|
|
8
|
+
* says "there is something here, right now", which is only true sometimes. The two layers compose:
|
|
9
|
+
* the section is the fallback for the paraphrase the lexical probe misses, and the hint is the
|
|
10
|
+
* concrete nudge for the case it catches.
|
|
11
|
+
*
|
|
12
|
+
* ONE LINE PER STORE, never a merged sentence. The two stores answer different questions and
|
|
13
|
+
* either can be the relevant one, so `RelevanceHit` is a closed four-valued answer and each store
|
|
14
|
+
* gets its own contribution — a caller can then see, and later tune or drop, one without the other.
|
|
15
|
+
*
|
|
16
|
+
* WHY EACH LINE NAMES THE PLUGIN. This text is injected as runtime context, and the harness
|
|
17
|
+
* materialises that as a USER-role snapshot in the conversation (`dsh-agent-loop`'s
|
|
18
|
+
* `runtimeContext.project`). Without an author, a line like "记忆里有相关内容" reads as something
|
|
19
|
+
* the user said. The `[avantf-mem 插件]` prefix is what keeps the provenance honest.
|
|
20
|
+
*/
|
|
21
|
+
export declare const MEMORY_HINT = "[avantf-mem \u63D2\u4EF6] \u8BB0\u5FC6\u91CC\u6709\u4E0E\u672C\u6B21\u63D0\u95EE\u76F8\u5173\u7684\u4E8B\u5B9E\uFF1B\u9700\u8981\u65F6\u7528 `mem_recall` \u68C0\u7D22\u3002";
|
|
22
|
+
export declare const KNOWLEDGE_HINT = "[avantf-mem \u63D2\u4EF6] \u77E5\u8BC6\u5E93\u91CC\u6709\u4E0E\u672C\u6B21\u63D0\u95EE\u76F8\u5173\u7684\u5185\u5BB9\uFF1B\u9700\u8981\u65F6\u7528 `kb_query` \u68C0\u7D22\u3002";
|
|
23
|
+
/**
|
|
24
|
+
* Map one answer to the two contributions, as text.
|
|
25
|
+
*
|
|
26
|
+
* An empty string is the "contribute nothing" value: `renderPrompt`/`renderContextSections` drop
|
|
27
|
+
* empty text, so `none` (and the missing half of `memory`/`knowledge`) costs no tokens at all.
|
|
28
|
+
*/
|
|
29
|
+
export declare function hintLines(hit: RelevanceHit): {
|
|
30
|
+
memory: string;
|
|
31
|
+
knowledge: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* The plain text of an inbox message, or `''` when it carries none.
|
|
35
|
+
*
|
|
36
|
+
* `dsh-agent-loop`'s own extractor returns `undefined` unless the message is exactly ONE text
|
|
37
|
+
* block; a steered or multi-part message would then silently produce no hint. Concatenating the
|
|
38
|
+
* text blocks keeps the probe working for those, and non-text blocks (images) are simply skipped —
|
|
39
|
+
* the probe is lexical, so it has nothing to say about them anyway.
|
|
40
|
+
*/
|
|
41
|
+
export declare function messageText(message: unknown): string;
|
|
42
|
+
//# sourceMappingURL=hints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hints.d.ts","sourceRoot":"","sources":["../../src/hints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/C;;;;;;;;;;;;;;;;;;GAkBG;AAEH,eAAO,MAAM,WAAW,iLAAyD,CAAA;AAEjF,eAAO,MAAM,cAAc,qLAAwD,CAAA;AAEnF;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAKlF;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAUpD"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plugin's CONDITIONAL hints: one line per store, contributed only when that store already
|
|
3
|
+
* holds something relevant to what the user just sent (DESIGN §12).
|
|
4
|
+
*
|
|
5
|
+
* These are deliberately NOT part of the always-on usage sections. A usage section says WHEN a
|
|
6
|
+
* store is worth consulting and therefore has to be paid for on every step of every session; this
|
|
7
|
+
* says "there is something here, right now", which is only true sometimes. The two layers compose:
|
|
8
|
+
* the section is the fallback for the paraphrase the lexical probe misses, and the hint is the
|
|
9
|
+
* concrete nudge for the case it catches.
|
|
10
|
+
*
|
|
11
|
+
* ONE LINE PER STORE, never a merged sentence. The two stores answer different questions and
|
|
12
|
+
* either can be the relevant one, so `RelevanceHit` is a closed four-valued answer and each store
|
|
13
|
+
* gets its own contribution — a caller can then see, and later tune or drop, one without the other.
|
|
14
|
+
*
|
|
15
|
+
* WHY EACH LINE NAMES THE PLUGIN. This text is injected as runtime context, and the harness
|
|
16
|
+
* materialises that as a USER-role snapshot in the conversation (`dsh-agent-loop`'s
|
|
17
|
+
* `runtimeContext.project`). Without an author, a line like "记忆里有相关内容" reads as something
|
|
18
|
+
* the user said. The `[avantf-mem 插件]` prefix is what keeps the provenance honest.
|
|
19
|
+
*/
|
|
20
|
+
export const MEMORY_HINT = '[avantf-mem 插件] 记忆里有与本次提问相关的事实;需要时用 `mem_recall` 检索。';
|
|
21
|
+
export const KNOWLEDGE_HINT = '[avantf-mem 插件] 知识库里有与本次提问相关的内容;需要时用 `kb_query` 检索。';
|
|
22
|
+
/**
|
|
23
|
+
* Map one answer to the two contributions, as text.
|
|
24
|
+
*
|
|
25
|
+
* An empty string is the "contribute nothing" value: `renderPrompt`/`renderContextSections` drop
|
|
26
|
+
* empty text, so `none` (and the missing half of `memory`/`knowledge`) costs no tokens at all.
|
|
27
|
+
*/
|
|
28
|
+
export function hintLines(hit) {
|
|
29
|
+
return {
|
|
30
|
+
memory: hit === 'memory' || hit === 'both' ? MEMORY_HINT : '',
|
|
31
|
+
knowledge: hit === 'knowledge' || hit === 'both' ? KNOWLEDGE_HINT : '',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The plain text of an inbox message, or `''` when it carries none.
|
|
36
|
+
*
|
|
37
|
+
* `dsh-agent-loop`'s own extractor returns `undefined` unless the message is exactly ONE text
|
|
38
|
+
* block; a steered or multi-part message would then silently produce no hint. Concatenating the
|
|
39
|
+
* text blocks keeps the probe working for those, and non-text blocks (images) are simply skipped —
|
|
40
|
+
* the probe is lexical, so it has nothing to say about them anyway.
|
|
41
|
+
*/
|
|
42
|
+
export function messageText(message) {
|
|
43
|
+
const content = message?.content;
|
|
44
|
+
if (!Array.isArray(content))
|
|
45
|
+
return '';
|
|
46
|
+
return content
|
|
47
|
+
.map((block) => {
|
|
48
|
+
const b = block;
|
|
49
|
+
return b?.type === 'text' && typeof b.text === 'string' ? b.text : '';
|
|
50
|
+
})
|
|
51
|
+
.filter(Boolean)
|
|
52
|
+
.join('\n');
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=hints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hints.js","sourceRoot":"","sources":["../../src/hints.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,sDAAsD,CAAA;AAEjF,MAAM,CAAC,MAAM,cAAc,GAAG,qDAAqD,CAAA;AAEnF;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,GAAiB;IACzC,OAAO;QACL,MAAM,EAAE,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;QAC7D,SAAS,EAAE,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE;KACvE,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,OAAgB;IAC1C,MAAM,OAAO,GAAI,OAAwC,EAAE,OAAO,CAAA;IAClE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAA;IACtC,OAAO,OAAO;SACX,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,MAAM,CAAC,GAAG,KAA0C,CAAA;QACpD,OAAO,CAAC,EAAE,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;IACvE,CAAC,CAAC;SACD,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,CAAC"}
|