@wei840222/qmd 2026.8.23

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.
Files changed (94) hide show
  1. package/CHANGELOG.md +1373 -0
  2. package/LICENSE +45 -0
  3. package/README.md +1439 -0
  4. package/THIRD_PARTY_NOTICES.md +31 -0
  5. package/bin/qmd +192 -0
  6. package/dist/ast.d.ts +65 -0
  7. package/dist/ast.js +334 -0
  8. package/dist/bench/bench.d.ts +35 -0
  9. package/dist/bench/bench.js +338 -0
  10. package/dist/bench/cjk-baseline.d.ts +36 -0
  11. package/dist/bench/cjk-baseline.js +111 -0
  12. package/dist/bench/fixture.d.ts +2 -0
  13. package/dist/bench/fixture.js +84 -0
  14. package/dist/bench/score.d.ts +38 -0
  15. package/dist/bench/score.js +107 -0
  16. package/dist/bench/types.d.ts +110 -0
  17. package/dist/bench/types.js +8 -0
  18. package/dist/cli/build-info.json +4 -0
  19. package/dist/cli/embed-lock.d.ts +24 -0
  20. package/dist/cli/embed-lock.js +94 -0
  21. package/dist/cli/embedding-owner.d.ts +10 -0
  22. package/dist/cli/embedding-owner.js +20 -0
  23. package/dist/cli/formatter.d.ts +120 -0
  24. package/dist/cli/formatter.js +355 -0
  25. package/dist/cli/mcp-pid.d.ts +25 -0
  26. package/dist/cli/mcp-pid.js +86 -0
  27. package/dist/cli/qmd.d.ts +72 -0
  28. package/dist/cli/qmd.js +4806 -0
  29. package/dist/cli/version.d.ts +42 -0
  30. package/dist/cli/version.js +80 -0
  31. package/dist/collections.d.ts +200 -0
  32. package/dist/collections.js +433 -0
  33. package/dist/db.d.ts +65 -0
  34. package/dist/db.js +143 -0
  35. package/dist/diagnostics.d.ts +62 -0
  36. package/dist/diagnostics.js +260 -0
  37. package/dist/embedding/config.d.ts +52 -0
  38. package/dist/embedding/config.js +229 -0
  39. package/dist/embedding/identity.d.ts +58 -0
  40. package/dist/embedding/identity.js +321 -0
  41. package/dist/embedding/local-identity.d.ts +1 -0
  42. package/dist/embedding/local-identity.js +15 -0
  43. package/dist/embedding/local.d.ts +34 -0
  44. package/dist/embedding/local.js +290 -0
  45. package/dist/embedding/openai.d.ts +79 -0
  46. package/dist/embedding/openai.js +477 -0
  47. package/dist/embedding/owner.d.ts +13 -0
  48. package/dist/embedding/owner.js +36 -0
  49. package/dist/embedding/provider.d.ts +68 -0
  50. package/dist/embedding/provider.js +16 -0
  51. package/dist/embedding/remote-chunking.d.ts +22 -0
  52. package/dist/embedding/remote-chunking.js +83 -0
  53. package/dist/embedding/remote-embedding.d.ts +15 -0
  54. package/dist/embedding/remote-embedding.js +77 -0
  55. package/dist/hybrid-llm.d.ts +18 -0
  56. package/dist/hybrid-llm.js +53 -0
  57. package/dist/index.d.ts +244 -0
  58. package/dist/index.js +418 -0
  59. package/dist/llm.d.ts +566 -0
  60. package/dist/llm.js +1847 -0
  61. package/dist/maintenance.d.ts +33 -0
  62. package/dist/maintenance.js +52 -0
  63. package/dist/mcp/origin-guard.d.ts +67 -0
  64. package/dist/mcp/origin-guard.js +137 -0
  65. package/dist/mcp/server.d.ts +116 -0
  66. package/dist/mcp/server.js +919 -0
  67. package/dist/paths.d.ts +1 -0
  68. package/dist/paths.js +4 -0
  69. package/dist/remote-llm.d.ts +52 -0
  70. package/dist/remote-llm.js +464 -0
  71. package/dist/search/cjk-analyzer.d.ts +33 -0
  72. package/dist/search/cjk-analyzer.js +158 -0
  73. package/dist/search/cjk-index.d.ts +104 -0
  74. package/dist/search/cjk-index.js +1031 -0
  75. package/dist/search/jieba-loader.d.ts +23 -0
  76. package/dist/search/jieba-loader.js +79 -0
  77. package/dist/search/query-expansion.d.ts +23 -0
  78. package/dist/search/query-expansion.js +43 -0
  79. package/dist/search/zh-dict.txt +624013 -0
  80. package/dist/store.d.ts +1218 -0
  81. package/dist/store.js +6076 -0
  82. package/dist/trust.d.ts +152 -0
  83. package/dist/trust.js +249 -0
  84. package/package.json +139 -0
  85. package/scripts/build.mjs +83 -0
  86. package/scripts/check-package-grammars.mjs +29 -0
  87. package/scripts/package-smoke.mjs +205 -0
  88. package/scripts/sync-zh-dict.mjs +187 -0
  89. package/scripts/test-all.mjs +45 -0
  90. package/skills/qmd/SKILL.md +324 -0
  91. package/skills/qmd/references/mcp-setup.md +119 -0
  92. package/skills/release/SKILL.md +141 -0
  93. package/skills/release/scripts/install-hooks.sh +38 -0
  94. package/skills/release/scripts/release-context.sh +129 -0
package/dist/llm.d.ts ADDED
@@ -0,0 +1,566 @@
1
+ /**
2
+ * llm.ts - LLM abstraction layer for QMD using node-llama-cpp
3
+ *
4
+ * Provides embeddings, text generation, and reranking using local GGUF models.
5
+ */
6
+ import type { Llama, Token as LlamaToken } from "node-llama-cpp";
7
+ type NodeLlamaCppModule = {
8
+ getLlama: (options: Record<string, unknown>) => Promise<Llama>;
9
+ getLlamaGpuTypes?: (include?: "supported" | "allValid") => Promise<LlamaGpuMode[]>;
10
+ resolveModelFile: (model: string, optionsOrDirectory?: string | {
11
+ directory?: string;
12
+ cli?: boolean;
13
+ }) => Promise<string>;
14
+ LlamaChatSession: new (options: {
15
+ contextSequence: unknown;
16
+ }) => {
17
+ prompt: (prompt: string, options?: Record<string, unknown>) => Promise<string>;
18
+ };
19
+ LlamaLogLevel: {
20
+ error: unknown;
21
+ };
22
+ };
23
+ export declare function setNodeLlamaCppModuleForTest(module: NodeLlamaCppModule | null): void;
24
+ /**
25
+ * Some node-llama-cpp native build/probe paths write library noise to stdout.
26
+ * JSON APIs must reserve stdout for machine-readable payloads, so route that
27
+ * noise to stderr while native llama initialization is in progress.
28
+ */
29
+ export declare function withNativeStdoutRedirectedToStderr<T>(fn: () => Promise<T>): Promise<T>;
30
+ /**
31
+ * Detect if a model URI uses the Qwen3-Embedding format.
32
+ * Qwen3-Embedding uses a different prompting style than nomic/embeddinggemma.
33
+ */
34
+ export declare function isQwen3EmbeddingModel(modelUri: string): boolean;
35
+ /**
36
+ * Format a query for embedding.
37
+ * Uses nomic-style task prefix format for embeddinggemma (default).
38
+ * Uses Qwen3-Embedding instruct format when a Qwen embedding model is active.
39
+ */
40
+ export declare function formatQueryForEmbedding(query: string, modelUri?: string): string;
41
+ /**
42
+ * Format a document for embedding.
43
+ * Uses nomic-style format with title and text fields (default).
44
+ * Qwen3-Embedding encodes documents as raw text without special prefixes.
45
+ */
46
+ export declare function formatDocForEmbedding(text: string, title?: string, modelUri?: string): string;
47
+ export declare function setLlamaDirWritableForTest(writable: boolean | undefined): void;
48
+ /** Whether node-llama-cpp can write to its llama/ directory (false on NixOS). */
49
+ export declare function canWriteLlamaDir(pkgDir?: string): boolean;
50
+ /**
51
+ * Token with log probability
52
+ */
53
+ export type TokenLogProb = {
54
+ token: string;
55
+ logprob: number;
56
+ };
57
+ /**
58
+ * Embedding result
59
+ */
60
+ export type EmbeddingResult = {
61
+ embedding: number[];
62
+ model: string;
63
+ };
64
+ /**
65
+ * Generation result with optional logprobs
66
+ */
67
+ export type GenerateResult = {
68
+ text: string;
69
+ model: string;
70
+ logprobs?: TokenLogProb[];
71
+ done: boolean;
72
+ };
73
+ /**
74
+ * Rerank result for a single document
75
+ */
76
+ export type RerankDocumentResult = {
77
+ file: string;
78
+ score: number;
79
+ index: number;
80
+ };
81
+ /**
82
+ * Batch rerank result
83
+ */
84
+ export type RerankResult = {
85
+ results: RerankDocumentResult[];
86
+ model: string;
87
+ };
88
+ /**
89
+ * Model info
90
+ */
91
+ export type ModelInfo = {
92
+ name: string;
93
+ exists: boolean;
94
+ path?: string;
95
+ };
96
+ /**
97
+ * Options for embedding
98
+ */
99
+ export type EmbedOptions = {
100
+ model?: string;
101
+ isQuery?: boolean;
102
+ title?: string;
103
+ };
104
+ /**
105
+ * Options for text generation
106
+ */
107
+ export type GenerateOptions = {
108
+ model?: string;
109
+ maxTokens?: number;
110
+ temperature?: number;
111
+ };
112
+ /**
113
+ * Options for reranking
114
+ */
115
+ export type RerankOptions = {
116
+ model?: string;
117
+ };
118
+ /**
119
+ * Options for LLM sessions
120
+ */
121
+ export type LLMSessionOptions = {
122
+ /** Max session duration in ms (default: 10 minutes) */
123
+ maxDuration?: number;
124
+ /** External abort signal */
125
+ signal?: AbortSignal;
126
+ /** Debug name for logging */
127
+ name?: string;
128
+ };
129
+ /**
130
+ * Session interface for scoped LLM access with lifecycle guarantees
131
+ */
132
+ export interface ILLMSession {
133
+ /** Embedding model actually loaded by the session owner. */
134
+ readonly embeddingModel: string;
135
+ embed(text: string, options?: EmbedOptions): Promise<EmbeddingResult | null>;
136
+ embedBatch(texts: string[], options?: EmbedOptions): Promise<(EmbeddingResult | null)[]>;
137
+ expandQuery(query: string, options?: {
138
+ context?: string;
139
+ includeLexical?: boolean;
140
+ }): Promise<Queryable[]>;
141
+ rerank(query: string, documents: RerankDocument[], options?: RerankOptions): Promise<RerankResult>;
142
+ /** Whether this session is still valid (not released or aborted) */
143
+ readonly isValid: boolean;
144
+ /** Abort signal for this session (aborts on release or maxDuration) */
145
+ readonly signal: AbortSignal;
146
+ }
147
+ /**
148
+ * Supported query types for different search backends
149
+ */
150
+ export type QueryType = 'lex' | 'vec' | 'hyde';
151
+ /**
152
+ * A single query and its target backend type
153
+ */
154
+ export type Queryable = {
155
+ type: QueryType;
156
+ text: string;
157
+ };
158
+ /**
159
+ * Document to rerank
160
+ */
161
+ export type RerankDocument = {
162
+ file: string;
163
+ text: string;
164
+ title?: string;
165
+ };
166
+ export declare const LFM2_GENERATE_MODEL = "hf:LiquidAI/LFM2-1.2B-GGUF/LFM2-1.2B-Q4_K_M.gguf";
167
+ export declare const LFM2_INSTRUCT_MODEL = "hf:LiquidAI/LFM2.5-1.2B-Instruct-GGUF/LFM2.5-1.2B-Instruct-Q4_K_M.gguf";
168
+ export declare const DEFAULT_EMBED_MODEL_URI = "hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf";
169
+ export declare const DEFAULT_RERANK_MODEL_URI = "hf:ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF/qwen3-reranker-0.6b-q8_0.gguf";
170
+ export declare const DEFAULT_GENERATE_MODEL_URI = "hf:tobil/qmd-query-expansion-1.7B-gguf/qmd-query-expansion-1.7B-q4_k_m.gguf";
171
+ export type ModelResolutionConfig = {
172
+ embed?: string;
173
+ generate?: string;
174
+ rerank?: string;
175
+ embed_api_model?: string;
176
+ generate_api_model?: string;
177
+ rerank_api_model?: string;
178
+ embed_api_url?: string;
179
+ generate_api_url?: string;
180
+ generate_url?: string;
181
+ generate_base_url?: string;
182
+ rerank_api_url?: string;
183
+ rerank_url?: string;
184
+ rerank_base_url?: string;
185
+ [key: string]: any;
186
+ };
187
+ export declare function resolveEmbedModel(config?: ModelResolutionConfig): string;
188
+ export declare function resolveGenerateModel(config?: ModelResolutionConfig): string;
189
+ export declare function resolveRerankModel(config?: ModelResolutionConfig): string;
190
+ export declare function resolveModels(config?: ModelResolutionConfig): Required<Pick<ModelResolutionConfig, "embed" | "generate" | "rerank">>;
191
+ export declare const DEFAULT_MODEL_CACHE_DIR: string;
192
+ export type PullResult = {
193
+ model: string;
194
+ path: string;
195
+ sizeBytes: number;
196
+ refreshed: boolean;
197
+ };
198
+ export type GgufFileInspection = {
199
+ exists: boolean;
200
+ valid: boolean;
201
+ kind: "missing" | "gguf" | "html" | "invalid";
202
+ sizeBytes?: number;
203
+ magic?: string;
204
+ details: string;
205
+ };
206
+ /**
207
+ * Inspect a potential GGUF model file without mutating it.
208
+ * Used by doctor for early diagnostics and by runtime validation before load.
209
+ */
210
+ export declare function inspectGgufFile(filePath: string): GgufFileInspection;
211
+ export declare function pullModels(models: string[], options?: {
212
+ refresh?: boolean;
213
+ cacheDir?: string;
214
+ cli?: boolean;
215
+ }): Promise<PullResult[]>;
216
+ /**
217
+ * Abstract LLM interface - implement this for different backends
218
+ */
219
+ export interface LLM {
220
+ /**
221
+ * Get embeddings for text
222
+ */
223
+ embed(text: string, options?: EmbedOptions): Promise<EmbeddingResult | null>;
224
+ /**
225
+ * Generate text completion
226
+ */
227
+ generate(prompt: string, options?: GenerateOptions): Promise<GenerateResult | null>;
228
+ /**
229
+ * Check if a model exists/is available
230
+ */
231
+ modelExists(model: string): Promise<ModelInfo>;
232
+ /**
233
+ * Expand a search query into multiple variations for different backends.
234
+ * Returns a list of Queryable objects.
235
+ */
236
+ expandQuery(query: string, options?: {
237
+ context?: string;
238
+ includeLexical?: boolean;
239
+ }): Promise<Queryable[]>;
240
+ /**
241
+ * Rerank documents by relevance to a query
242
+ * Returns list of documents with relevance scores (higher = more relevant)
243
+ */
244
+ rerank(query: string, documents: RerankDocument[], options?: RerankOptions): Promise<RerankResult>;
245
+ /**
246
+ * Dispose of resources
247
+ */
248
+ dispose(): Promise<void>;
249
+ }
250
+ export type LlamaCppConfig = {
251
+ embedModel?: string;
252
+ generateModel?: string;
253
+ rerankModel?: string;
254
+ modelCacheDir?: string;
255
+ /**
256
+ * Context size used for query expansion generation contexts.
257
+ * Default: 2048. Can also be set via QMD_EXPAND_CONTEXT_SIZE.
258
+ */
259
+ expandContextSize?: number;
260
+ /**
261
+ * Inactivity timeout in ms before unloading contexts (default: 2 minutes, 0 to disable).
262
+ *
263
+ * Per node-llama-cpp lifecycle guidance, we prefer keeping models loaded and only disposing
264
+ * contexts when idle, since contexts (and their sequences) are the heavy per-session objects.
265
+ * @see https://node-llama-cpp.withcat.ai/guide/objects-lifecycle
266
+ */
267
+ inactivityTimeoutMs?: number;
268
+ /**
269
+ * Whether to dispose models on inactivity (default: false).
270
+ *
271
+ * Keeping models loaded avoids repeated VRAM thrash; set to true only if you need aggressive
272
+ * memory reclaim.
273
+ */
274
+ disposeModelsOnInactivity?: boolean;
275
+ };
276
+ export type LlamaGpuMode = "auto" | "metal" | "vulkan" | "cuda" | false;
277
+ type ParallelismOptions = {
278
+ gpu: string | false;
279
+ platform?: NodeJS.Platform;
280
+ computed: number;
281
+ envValue?: string;
282
+ };
283
+ export declare function resolveParallelismOverride(envValue?: string | undefined): number | undefined;
284
+ export declare function resolveSafeParallelism(options: ParallelismOptions): number;
285
+ /** Measured nomic-embed / embeddinggemma-300M embedding-context cost at 2048 tokens. */
286
+ export declare const BASELINE_EMBED_CONTEXT_MB = 150;
287
+ /**
288
+ * VRAM to leave free when sizing the embedding-context pool so `query` can
289
+ * still create a rerank context afterwards. Matches the 1000 MB figure
290
+ * `ensureRerankContexts` already uses as its per-context cost.
291
+ */
292
+ export declare const EMBED_POOL_RERANK_RESERVE_MB = 1000;
293
+ /**
294
+ * GPU embedding-context pool size from free VRAM.
295
+ *
296
+ * Uses 25% of (free − reserve), then clamps to `[1, cap]`. The reserve keeps
297
+ * the pool from consuming the memory `query` needs next for the reranker (#799).
298
+ */
299
+ export declare function computeGpuContextPoolSize(options: {
300
+ freeMB: number;
301
+ perContextMB: number;
302
+ reserveMB?: number;
303
+ cap?: number;
304
+ }): number;
305
+ /**
306
+ * Estimate one embedding context's VRAM from the GGUF weight-file size.
307
+ *
308
+ * Small models (nomic / embeddinggemma-class, ≲350 MB) stay at the measured
309
+ * 150 MB baseline so default `qmd embed` throughput is unchanged. Larger
310
+ * files — Qwen3-Embedding-0.6B-Q8 is ~640 MB — were measured at ~1190 MB per
311
+ * 2048-token context, about 1.85× the weight file, because the KV cache
312
+ * dominates (#799).
313
+ */
314
+ export declare function estimateEmbedContextMB(options: {
315
+ modelBytes: number;
316
+ contextSize?: number;
317
+ }): number;
318
+ export declare function resolveLlamaGpuMode(envValue?: string | undefined, forceCpuValue?: string | undefined): LlamaGpuMode;
319
+ export declare class LlamaCpp implements LLM {
320
+ private readonly _ciMode;
321
+ private llama;
322
+ private embedModel;
323
+ private embedModelPath;
324
+ private embedContexts;
325
+ private generateModel;
326
+ private rerankModel;
327
+ private rerankContexts;
328
+ private embedModelUri;
329
+ private generateModelUri;
330
+ private rerankModelUri;
331
+ private modelCacheDir;
332
+ private expandContextSize;
333
+ private embedModelLoadPromise;
334
+ private generateModelLoadPromise;
335
+ private rerankModelLoadPromise;
336
+ private rerankContextsCreatePromise;
337
+ private llamaLoadPromise;
338
+ private inactivityTimer;
339
+ private idleUnloadPromise;
340
+ private inactivityTimeoutMs;
341
+ private disposeModelsOnInactivity;
342
+ private closing;
343
+ private disposed;
344
+ private disposePromise;
345
+ constructor(config?: LlamaCppConfig);
346
+ get embedModelName(): string;
347
+ get generateModelName(): string;
348
+ get rerankModelName(): string;
349
+ /**
350
+ * Reset the inactivity timer. Called after each model operation.
351
+ * When timer fires, models are unloaded to free memory (if no active sessions).
352
+ */
353
+ private touchActivity;
354
+ /**
355
+ * Check if any contexts are currently loaded (and therefore worth unloading on inactivity).
356
+ */
357
+ private hasLoadedContexts;
358
+ /**
359
+ * Unload idle resources but keep the instance alive for future use.
360
+ *
361
+ * By default, this disposes contexts (and their dependent sequences), while keeping models loaded.
362
+ * This matches the intended lifecycle: model → context → sequence, where contexts are per-session.
363
+ */
364
+ unloadIdleResources(): Promise<void>;
365
+ /** Wait for an inactivity unload that already owns this instance's resources. */
366
+ waitForIdleUnload(): Promise<void>;
367
+ /**
368
+ * Acquire a lease without yielding between the idle-unload check and the
369
+ * caller's synchronous lease registration.
370
+ */
371
+ acquireAfterIdleUnload<T>(acquire: () => T): Promise<T>;
372
+ private disposeIdleResources;
373
+ /**
374
+ * Ensure model cache directory exists
375
+ */
376
+ private ensureModelCacheDir;
377
+ /**
378
+ * Initialize the llama instance (lazy)
379
+ */
380
+ private ensureLlama;
381
+ private loadLlamaRuntime;
382
+ private isCpuOffloadForced;
383
+ private modelLoadOptions;
384
+ /**
385
+ * Resolve a model URI to a local path, downloading if needed.
386
+ * Validates the downloaded file is actually a GGUF model (not an HTML error page
387
+ * from a proxy or firewall).
388
+ */
389
+ private resolveModel;
390
+ /**
391
+ * Load embedding model (lazy)
392
+ */
393
+ private ensureEmbedModel;
394
+ /**
395
+ * Compute how many parallel contexts to create.
396
+ *
397
+ * GPU: constrained by VRAM (25% of free, capped at 8).
398
+ * CPU: constrained by cores. Splitting threads across contexts enables
399
+ * true parallelism (each context runs on its own cores). Use at most
400
+ * half the math cores, with at least 4 threads per context.
401
+ */
402
+ private computeParallelism;
403
+ /**
404
+ * Get the number of threads each context should use, given N parallel contexts.
405
+ * Splits available math cores evenly across contexts.
406
+ */
407
+ private threadsPerContext;
408
+ /**
409
+ * Load embedding contexts (lazy). Creates multiple for parallel embedding.
410
+ * Uses promise guard to prevent concurrent context creation race condition.
411
+ */
412
+ private embedContextsCreatePromise;
413
+ private ensureEmbedContexts;
414
+ /**
415
+ * Get a single embed context (for single-embed calls). Uses first from pool.
416
+ */
417
+ private ensureEmbedContext;
418
+ /**
419
+ * Load generation model (lazy) - context is created fresh per call
420
+ */
421
+ private ensureGenerateModel;
422
+ /**
423
+ * Load rerank model (lazy)
424
+ */
425
+ private ensureRerankModel;
426
+ /**
427
+ * Load rerank contexts (lazy). Creates multiple contexts for parallel ranking.
428
+ * Each context has its own sequence, so they can evaluate independently.
429
+ *
430
+ * VRAM per context is governed by contextSize alone —
431
+ * LlamaRankingContextOptions has no flashAttention option.
432
+ */
433
+ private static readonly RERANK_CONTEXT_SIZE;
434
+ private static readonly EMBED_CONTEXT_SIZE;
435
+ private ensureRerankContexts;
436
+ /**
437
+ * Tokenize text using the embedding model's tokenizer
438
+ * Returns tokenizer tokens (opaque type from node-llama-cpp)
439
+ */
440
+ tokenize(text: string): Promise<readonly LlamaToken[]>;
441
+ /**
442
+ * Count tokens in text using the embedding model's tokenizer
443
+ */
444
+ countTokens(text: string): Promise<number>;
445
+ /**
446
+ * Detokenize token IDs back to text
447
+ */
448
+ detokenize(tokens: readonly LlamaToken[]): Promise<string>;
449
+ /**
450
+ * Truncate text to fit within the embedding model's context window.
451
+ * Uses the model's own tokenizer for accurate token counting, then
452
+ * detokenizes back to text if truncation is needed.
453
+ * Returns the (possibly truncated) text and whether truncation occurred.
454
+ */
455
+ private resolveEmbedTokenLimit;
456
+ private truncateToContextSize;
457
+ embed(text: string, options?: EmbedOptions): Promise<EmbeddingResult | null>;
458
+ /**
459
+ * Batch embed multiple texts efficiently
460
+ * Uses Promise.all for parallel embedding - node-llama-cpp handles batching internally
461
+ */
462
+ embedBatch(texts: string[], options?: EmbedOptions): Promise<(EmbeddingResult | null)[]>;
463
+ generate(prompt: string, options?: GenerateOptions): Promise<GenerateResult | null>;
464
+ modelExists(modelUri: string): Promise<ModelInfo>;
465
+ expandQuery(query: string, options?: {
466
+ context?: string;
467
+ includeLexical?: boolean;
468
+ }): Promise<Queryable[]>;
469
+ private static readonly RERANK_TEMPLATE_OVERHEAD;
470
+ private static readonly RERANK_TARGET_DOCS_PER_CONTEXT;
471
+ rerank(query: string, documents: RerankDocument[], options?: RerankOptions): Promise<RerankResult>;
472
+ /**
473
+ * Get device/GPU info for status display.
474
+ * Initializes llama if not already done.
475
+ */
476
+ getDeviceInfo(options?: {
477
+ allowBuild?: boolean;
478
+ }): Promise<{
479
+ gpu: string | false;
480
+ gpuOffloading: boolean;
481
+ gpuDevices: string[];
482
+ vram?: {
483
+ total: number;
484
+ used: number;
485
+ free: number;
486
+ };
487
+ cpuCores: number;
488
+ }>;
489
+ dispose(): Promise<void>;
490
+ private disposeAfterDrain;
491
+ }
492
+ /**
493
+ * Error thrown when an operation is attempted on a released or aborted session.
494
+ */
495
+ export declare class SessionReleasedError extends Error {
496
+ constructor(message?: string);
497
+ }
498
+ /**
499
+ * Execute a function with a scoped LLM session.
500
+ * The session provides lifecycle guarantees - resources won't be disposed mid-operation.
501
+ *
502
+ * @example
503
+ * ```typescript
504
+ * await withLLMSession(async (session) => {
505
+ * const expanded = await session.expandQuery(query);
506
+ * const embeddings = await session.embedBatch(texts);
507
+ * const reranked = await session.rerank(query, docs);
508
+ * return reranked;
509
+ * }, { maxDuration: 10 * 60 * 1000, name: 'querySearch' });
510
+ * ```
511
+ */
512
+ export declare function withLLMSession<T>(fn: (session: ILLMSession) => Promise<T>, options?: LLMSessionOptions): Promise<T>;
513
+ /**
514
+ * Execute a function with a scoped LLM session using a specific LlamaCpp instance.
515
+ * Unlike withLLMSession, this does not use the global singleton.
516
+ */
517
+ export declare function withLLMSessionForLlm<T>(llm: LlamaCpp, fn: (session: ILLMSession) => Promise<T>, options?: LLMSessionOptions): Promise<T>;
518
+ /** Wait until all scoped sessions using a specific LlamaCpp instance have settled. */
519
+ export declare function waitForLLMSessionsToDrain(llm: LlamaCpp): Promise<void>;
520
+ /**
521
+ * Check if idle unload is safe (no active sessions or operations).
522
+ * Used internally by LlamaCpp idle timer.
523
+ */
524
+ export declare function canUnloadLLM(llm?: LlamaCpp): boolean;
525
+ /**
526
+ * Whether QMD's darwin Metal exit-crash mitigation is active in this process:
527
+ * true → residency sets disabled, process exit completes silently
528
+ * false → either non-darwin, or `QMD_METAL_KEEP_RESIDENCY=1` overrode it,
529
+ * in which case the libggml-metal teardown assertion may fire
530
+ */
531
+ export declare function isDarwinMetalMitigationActive(): boolean;
532
+ /**
533
+ * Compatibility shim: previous releases installed a `process.on('exit')` hook
534
+ * that tried to skip the C++ static destructor by calling `process.reallyExit`.
535
+ * That mechanism didn't work on Node (Environment::Exit still calls libc
536
+ * `exit()`), so it was replaced by `GGML_METAL_NO_RESIDENCY=1` from bin/qmd.
537
+ * Kept as a no-op for code paths that still call it; safe to remove once no
538
+ * production launcher predates the residency-set fix.
539
+ */
540
+ export declare function installDarwinExitGuard(): void;
541
+ /** @deprecated Replaced by isDarwinMetalMitigationActive. */
542
+ export declare function isDarwinExitGuardInstalled(): boolean;
543
+ /**
544
+ * Get the default LlamaCpp instance (creates one if needed). The LlamaCpp
545
+ * constructor installs the darwin exit guard, so any code path that obtains
546
+ * the singleton is protected.
547
+ */
548
+ export declare function getDefaultLlamaCpp(): LlamaCpp;
549
+ /**
550
+ * Set a custom default LlamaCpp instance (useful for testing). Setting a
551
+ * non-null instance also ensures the darwin exit guard is installed — keeps
552
+ * the invariant intact for test doubles that didn't go through the real
553
+ * constructor.
554
+ */
555
+ export declare function setDefaultLlamaCpp(llm: LlamaCpp | null): void;
556
+ /**
557
+ * Peek at the default LlamaCpp instance without instantiating one. Used by
558
+ * doctor and lifecycle diagnostics.
559
+ */
560
+ export declare function hasDefaultLlamaCpp(): boolean;
561
+ /**
562
+ * Dispose the default LlamaCpp instance if it exists.
563
+ * Call this before process exit to prevent NAPI crashes.
564
+ */
565
+ export declare function disposeDefaultLlamaCpp(): Promise<void>;
566
+ export {};