@gmickel/gno 1.45.1 → 2.0.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.
Files changed (236) hide show
  1. package/README.md +1 -1
  2. package/THIRD_PARTY_NOTICES.md +46 -0
  3. package/assets/skill/SKILL.md +7 -6
  4. package/assets/skill/cli-reference.md +14 -6
  5. package/assets/skill/mcp-reference.md +4 -1
  6. package/assets/spa-production.json.gz +0 -0
  7. package/browser-extension/artifacts/gno-browser-clipper-v2.0.0.zip +0 -0
  8. package/browser-extension/artifacts/gno-browser-clipper-v2.0.0.zip.sha256 +1 -0
  9. package/browser-extension/dist/chunk-4tc9v0ja.js +74 -0
  10. package/browser-extension/dist/manifest.json +1 -1
  11. package/browser-extension/dist/preview.html +1 -1
  12. package/browser-extension/dist/service-worker.js +32 -33
  13. package/bunfig.toml +2 -0
  14. package/package.json +40 -26
  15. package/spec/cli.md +30 -11
  16. package/spec/db/schema.sql +146 -1
  17. package/spec/mcp.md +26 -0
  18. package/src/app/context-runtime-types.ts +3 -0
  19. package/src/app/context-runtime.ts +2 -0
  20. package/src/cli/commands/ask.ts +6 -1
  21. package/src/cli/commands/daemon.ts +21 -8
  22. package/src/cli/commands/embed.ts +77 -41
  23. package/src/cli/commands/mcp/install.ts +20 -0
  24. package/src/cli/commands/mcp/paths.ts +25 -0
  25. package/src/cli/commands/mcp/status.ts +6 -0
  26. package/src/cli/detach.ts +3 -2
  27. package/src/cli/program.ts +6 -0
  28. package/src/config/types.ts +3 -3
  29. package/src/converters/adapters/markitdownTs/adapter.ts +1 -2
  30. package/src/converters/adapters/officeparser/adapter.ts +1 -2
  31. package/src/converters/versions.ts +6 -8
  32. package/src/core/context-evidence.ts +8 -4
  33. package/src/core/job-manager.ts +95 -13
  34. package/src/core/network-boundary-inventory.ts +10 -0
  35. package/src/core/shutdown-budget.ts +45 -0
  36. package/src/embed/backlog.ts +107 -4
  37. package/src/embed/batch.ts +42 -2
  38. package/src/embed/fingerprint.ts +16 -0
  39. package/src/embed/retry.ts +113 -5
  40. package/src/embed/variant-backlog.ts +105 -0
  41. package/src/embed/variant-plan.ts +62 -0
  42. package/src/embed/variant-retry.ts +113 -0
  43. package/src/ingestion/graph-reconciliation.ts +327 -0
  44. package/src/ingestion/sync.ts +9 -272
  45. package/src/llm/http-inference.ts +6 -0
  46. package/src/llm/httpEmbedding.ts +37 -6
  47. package/src/llm/httpGeneration.ts +18 -3
  48. package/src/llm/httpRerank.ts +23 -5
  49. package/src/llm/inference-cancellation.ts +168 -0
  50. package/src/llm/inference-scope.ts +202 -0
  51. package/src/llm/lazy-ports.ts +115 -0
  52. package/src/llm/native-worker/client.ts +541 -0
  53. package/src/llm/native-worker/dispatcher.ts +228 -0
  54. package/src/llm/native-worker/embedding-identity.ts +33 -0
  55. package/src/llm/native-worker/entry.ts +173 -0
  56. package/src/llm/native-worker/errors.ts +32 -0
  57. package/src/llm/native-worker/evaluation.ts +16 -0
  58. package/src/llm/native-worker/owned-exit.ts +108 -0
  59. package/src/llm/native-worker/owner.ts +141 -0
  60. package/src/llm/native-worker/ports.ts +317 -0
  61. package/src/llm/native-worker/protocol.ts +442 -0
  62. package/src/llm/native-worker/runtime-config.ts +92 -0
  63. package/src/llm/nodeLlamaCpp/adapter.ts +77 -20
  64. package/src/llm/nodeLlamaCpp/embedding.ts +130 -46
  65. package/src/llm/nodeLlamaCpp/generation.ts +34 -5
  66. package/src/llm/nodeLlamaCpp/lifecycle-options.ts +99 -0
  67. package/src/llm/nodeLlamaCpp/lifecycle.ts +209 -204
  68. package/src/llm/nodeLlamaCpp/rerank-capacity.ts +111 -0
  69. package/src/llm/nodeLlamaCpp/rerank.ts +118 -27
  70. package/src/llm/nodeLlamaCpp/simulator-handle.ts +73 -0
  71. package/src/llm/nodeLlamaCpp/simulator-install.ts +124 -0
  72. package/src/llm/nodeLlamaCpp/simulator-session.ts +240 -0
  73. package/src/llm/nodeLlamaCpp/simulator-types.ts +80 -0
  74. package/src/llm/types.ts +35 -5
  75. package/src/mcp/context.ts +27 -0
  76. package/src/mcp/http-transport.ts +12 -10
  77. package/src/mcp/server.ts +3 -0
  78. package/src/mcp/tool-profile.ts +30 -8
  79. package/src/mcp/tools/context.ts +8 -11
  80. package/src/mcp/tools/embed.ts +1 -1
  81. package/src/mcp/tools/index-cmd.ts +1 -1
  82. package/src/mcp/tools/index.ts +10 -8
  83. package/src/mcp/tools/query.ts +14 -30
  84. package/src/mcp/tools/vsearch.ts +1 -1
  85. package/src/pipeline/answer.ts +23 -3
  86. package/src/pipeline/claim-verifier.ts +6 -0
  87. package/src/pipeline/expansion.ts +43 -40
  88. package/src/pipeline/explain.ts +6 -2
  89. package/src/pipeline/filters.ts +63 -0
  90. package/src/pipeline/fusion.ts +29 -9
  91. package/src/pipeline/graph-retrieval.ts +29 -9
  92. package/src/pipeline/hybrid.ts +198 -55
  93. package/src/pipeline/hydration.ts +161 -0
  94. package/src/pipeline/owner-fusion.ts +87 -0
  95. package/src/pipeline/rerank.ts +35 -11
  96. package/src/pipeline/search.ts +13 -2
  97. package/src/pipeline/types.ts +5 -3
  98. package/src/pipeline/vsearch.ts +87 -7
  99. package/src/sdk/client.ts +47 -3
  100. package/src/sdk/embed.ts +63 -39
  101. package/src/serve/background-runtime.ts +1 -1
  102. package/src/serve/context.ts +41 -56
  103. package/src/serve/embed-scheduler.ts +58 -35
  104. package/src/serve/public/components/IndexingProgress.tsx +46 -60
  105. package/src/serve/public/globals.built.css +1 -1
  106. package/src/serve/public/lib/shiki-language-ids.ts +14 -0
  107. package/src/serve/resident-admission.ts +36 -36
  108. package/src/serve/resident-background-work.ts +20 -2
  109. package/src/serve/resident-request.ts +11 -5
  110. package/src/serve/resident-runtime.ts +97 -61
  111. package/src/serve/resident-shutdown.ts +153 -0
  112. package/src/serve/routes/api.ts +3 -1
  113. package/src/serve/server.ts +47 -26
  114. package/src/store/migrations/028-vector-variants.ts +54 -0
  115. package/src/store/migrations/029-graph-reference-state.ts +77 -0
  116. package/src/store/migrations/index.ts +4 -0
  117. package/src/store/sqlite/adapter.ts +251 -183
  118. package/src/store/sqlite/eligibility.ts +174 -0
  119. package/src/store/sqlite/graph-edge-application.ts +66 -0
  120. package/src/store/sqlite/graph-reference-state.ts +194 -0
  121. package/src/store/sqlite/legacy-vector-ownership.ts +79 -0
  122. package/src/store/types.ts +80 -12
  123. package/src/store/vector/eligibility.ts +36 -0
  124. package/src/store/vector/freshness.ts +33 -6
  125. package/src/store/vector/lazy.ts +81 -0
  126. package/src/store/vector/sqlite-vec.ts +106 -54
  127. package/src/store/vector/stats.ts +14 -3
  128. package/src/store/vector/types.ts +35 -2
  129. package/src/store/vector/variant-search.ts +192 -0
  130. package/src/store/vector/variants.ts +451 -0
  131. package/vendor/converters/markitdown-ts/LICENSE +21 -0
  132. package/vendor/converters/markitdown-ts/dist/index.cjs +1180 -0
  133. package/vendor/converters/markitdown-ts/dist/index.d.cts +46 -0
  134. package/vendor/converters/markitdown-ts/dist/index.d.mts +46 -0
  135. package/vendor/converters/markitdown-ts/dist/index.d.ts +46 -0
  136. package/vendor/converters/markitdown-ts/dist/index.mjs +1152 -0
  137. package/vendor/converters/markitdown-ts/package.json +77 -0
  138. package/vendor/converters/officeparser/LICENSE +21 -0
  139. package/vendor/converters/officeparser/dist/OfficeConverter.d.ts +47 -0
  140. package/vendor/converters/officeparser/dist/OfficeConverter.js +76 -0
  141. package/vendor/converters/officeparser/dist/OfficeGenerator.d.ts +23 -0
  142. package/vendor/converters/officeparser/dist/OfficeGenerator.js +73 -0
  143. package/vendor/converters/officeparser/dist/OfficeParser.d.ts +106 -0
  144. package/vendor/converters/officeparser/dist/OfficeParser.js +332 -0
  145. package/vendor/converters/officeparser/dist/cli.d.ts +28 -0
  146. package/vendor/converters/officeparser/dist/cli.js +381 -0
  147. package/vendor/converters/officeparser/dist/defaults.d.ts +41 -0
  148. package/vendor/converters/officeparser/dist/defaults.js +218 -0
  149. package/vendor/converters/officeparser/dist/generators/BaseGenerator.d.ts +107 -0
  150. package/vendor/converters/officeparser/dist/generators/BaseGenerator.js +248 -0
  151. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.d.ts +82 -0
  152. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.js +797 -0
  153. package/vendor/converters/officeparser/dist/generators/CsvGenerator.d.ts +38 -0
  154. package/vendor/converters/officeparser/dist/generators/CsvGenerator.js +245 -0
  155. package/vendor/converters/officeparser/dist/generators/EpubGenerator.d.ts +43 -0
  156. package/vendor/converters/officeparser/dist/generators/EpubGenerator.js +315 -0
  157. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.d.ts +59 -0
  158. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.js +1942 -0
  159. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.d.ts +96 -0
  160. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.js +1175 -0
  161. package/vendor/converters/officeparser/dist/generators/PdfGenerator.d.ts +22 -0
  162. package/vendor/converters/officeparser/dist/generators/PdfGenerator.js +194 -0
  163. package/vendor/converters/officeparser/dist/generators/RtfGenerator.d.ts +29 -0
  164. package/vendor/converters/officeparser/dist/generators/RtfGenerator.js +316 -0
  165. package/vendor/converters/officeparser/dist/generators/TextGenerator.d.ts +13 -0
  166. package/vendor/converters/officeparser/dist/generators/TextGenerator.js +201 -0
  167. package/vendor/converters/officeparser/dist/index.d.ts +60 -0
  168. package/vendor/converters/officeparser/dist/index.js +72 -0
  169. package/vendor/converters/officeparser/dist/index.mjs +18 -0
  170. package/vendor/converters/officeparser/dist/officeparser.browser.d.ts +2621 -0
  171. package/vendor/converters/officeparser/dist/officeparser.browser.iife.js +1336 -0
  172. package/vendor/converters/officeparser/dist/officeparser.browser.mjs +1335 -0
  173. package/vendor/converters/officeparser/dist/officeparser.browser.slim.d.ts +2621 -0
  174. package/vendor/converters/officeparser/dist/officeparser.browser.slim.iife.js +1336 -0
  175. package/vendor/converters/officeparser/dist/officeparser.browser.slim.mjs +1335 -0
  176. package/vendor/converters/officeparser/dist/parsers/CsvParser.d.ts +9 -0
  177. package/vendor/converters/officeparser/dist/parsers/CsvParser.js +115 -0
  178. package/vendor/converters/officeparser/dist/parsers/EpubParser.d.ts +8 -0
  179. package/vendor/converters/officeparser/dist/parsers/EpubParser.js +217 -0
  180. package/vendor/converters/officeparser/dist/parsers/ExcelParser.d.ts +32 -0
  181. package/vendor/converters/officeparser/dist/parsers/ExcelParser.js +736 -0
  182. package/vendor/converters/officeparser/dist/parsers/HtmlParser.d.ts +2 -0
  183. package/vendor/converters/officeparser/dist/parsers/HtmlParser.js +1287 -0
  184. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.d.ts +2 -0
  185. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.js +1272 -0
  186. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.d.ts +31 -0
  187. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.js +1819 -0
  188. package/vendor/converters/officeparser/dist/parsers/PdfParser.d.ts +67 -0
  189. package/vendor/converters/officeparser/dist/parsers/PdfParser.js +848 -0
  190. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.d.ts +32 -0
  191. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.js +950 -0
  192. package/vendor/converters/officeparser/dist/parsers/RtfParser.d.ts +187 -0
  193. package/vendor/converters/officeparser/dist/parsers/RtfParser.js +1801 -0
  194. package/vendor/converters/officeparser/dist/parsers/WordParser.d.ts +79 -0
  195. package/vendor/converters/officeparser/dist/parsers/WordParser.js +1177 -0
  196. package/vendor/converters/officeparser/dist/sbom.cdx.json +1763 -0
  197. package/vendor/converters/officeparser/dist/types.d.ts +2507 -0
  198. package/vendor/converters/officeparser/dist/types.js +107 -0
  199. package/vendor/converters/officeparser/dist/utils/astUtils.d.ts +16 -0
  200. package/vendor/converters/officeparser/dist/utils/astUtils.js +33 -0
  201. package/vendor/converters/officeparser/dist/utils/chartUtils.d.ts +6 -0
  202. package/vendor/converters/officeparser/dist/utils/chartUtils.js +257 -0
  203. package/vendor/converters/officeparser/dist/utils/configUtils.d.ts +44 -0
  204. package/vendor/converters/officeparser/dist/utils/configUtils.js +315 -0
  205. package/vendor/converters/officeparser/dist/utils/dateUtils.d.ts +17 -0
  206. package/vendor/converters/officeparser/dist/utils/dateUtils.js +69 -0
  207. package/vendor/converters/officeparser/dist/utils/envUtils.d.ts +29 -0
  208. package/vendor/converters/officeparser/dist/utils/envUtils.js +152 -0
  209. package/vendor/converters/officeparser/dist/utils/errorUtils.d.ts +72 -0
  210. package/vendor/converters/officeparser/dist/utils/errorUtils.js +245 -0
  211. package/vendor/converters/officeparser/dist/utils/imageUtils.d.ts +66 -0
  212. package/vendor/converters/officeparser/dist/utils/imageUtils.js +133 -0
  213. package/vendor/converters/officeparser/dist/utils/mathUtils.d.ts +42 -0
  214. package/vendor/converters/officeparser/dist/utils/mathUtils.js +385 -0
  215. package/vendor/converters/officeparser/dist/utils/moduleLoader.d.ts +18 -0
  216. package/vendor/converters/officeparser/dist/utils/moduleLoader.js +106 -0
  217. package/vendor/converters/officeparser/dist/utils/ocrUtils.d.ts +42 -0
  218. package/vendor/converters/officeparser/dist/utils/ocrUtils.js +428 -0
  219. package/vendor/converters/officeparser/dist/utils/sanitize.d.ts +148 -0
  220. package/vendor/converters/officeparser/dist/utils/sanitize.js +344 -0
  221. package/vendor/converters/officeparser/dist/utils/sheetUtils.d.ts +7 -0
  222. package/vendor/converters/officeparser/dist/utils/sheetUtils.js +35 -0
  223. package/vendor/converters/officeparser/dist/utils/styleMapper.d.ts +36 -0
  224. package/vendor/converters/officeparser/dist/utils/styleMapper.js +224 -0
  225. package/vendor/converters/officeparser/dist/utils/xmlUtils.d.ts +163 -0
  226. package/vendor/converters/officeparser/dist/utils/xmlUtils.js +461 -0
  227. package/vendor/converters/officeparser/dist/utils/zipUtils.d.ts +134 -0
  228. package/vendor/converters/officeparser/dist/utils/zipUtils.js +337 -0
  229. package/vendor/converters/officeparser/package.json +147 -0
  230. package/vendor/converters/upstream-manifest.json +124 -0
  231. package/vendor/dependency-fixes/README.md +77 -0
  232. package/vendor/dependency-fixes/vendor-converters.py +83 -0
  233. package/browser-extension/artifacts/gno-browser-clipper-v1.45.1.zip +0 -0
  234. package/browser-extension/artifacts/gno-browser-clipper-v1.45.1.zip.sha256 +0 -1
  235. package/browser-extension/dist/chunk-627emwpj.js +0 -75
  236. /package/browser-extension/dist/{chunk-ydfx5d7p.css → chunk-z74y8n8c.css} +0 -0
@@ -5,7 +5,11 @@
5
5
  * @module src/llm/nodeLlamaCpp/adapter
6
6
  */
7
7
 
8
+ // Bun has no canonical-path API. Approval binds the real file identity.
9
+ import { realpath } from "node:fs/promises";
10
+
8
11
  import type { Config } from "../../config/types";
12
+ import type { NativeDisposeOptions } from "../native-worker/owned-exit";
9
13
  import type { DownloadPolicy } from "../policy";
10
14
  import type {
11
15
  EmbeddingPort,
@@ -14,25 +18,26 @@ import type {
14
18
  ProgressCallback,
15
19
  RerankPort,
16
20
  } from "../types";
21
+ import type { ModelType } from "../types";
22
+ import type { ModelLease } from "./lifecycle";
17
23
 
18
24
  import { ModelCache } from "../cache";
19
25
  import { HttpEmbedding, isHttpModelUri } from "../httpEmbedding";
20
26
  import { HttpGeneration, isHttpGenUri } from "../httpGeneration";
21
27
  import { HttpRerank, isHttpRerankUri } from "../httpRerank";
28
+ import { NativeWorkerClient } from "../native-worker/client";
29
+ import { NativeWorkerError } from "../native-worker/errors";
30
+ import {
31
+ NativeEmbeddingPort,
32
+ NativeGenerationPort,
33
+ NativeRerankPort,
34
+ } from "../native-worker/ports";
22
35
  import {
23
36
  getActivePreset,
24
37
  getAnswerModelUri,
25
38
  getExpandModelUri,
26
39
  getModelConfig,
27
40
  } from "../registry";
28
- import { NodeLlamaCppEmbedding } from "./embedding";
29
- import { NodeLlamaCppGeneration } from "./generation";
30
- import {
31
- getModelManager,
32
- type ModelLease,
33
- type ModelManager,
34
- } from "./lifecycle";
35
- import { NodeLlamaCppRerank } from "./rerank";
36
41
 
37
42
  // ─────────────────────────────────────────────────────────────────────────────
38
43
  // Types
@@ -64,14 +69,19 @@ const resolveEgressCollectionNames = (
64
69
  // ─────────────────────────────────────────────────────────────────────────────
65
70
 
66
71
  export class LlmAdapter {
67
- private readonly manager: ModelManager;
72
+ private readonly worker: NativeWorkerClient;
68
73
  private readonly cache: ModelCache;
69
74
  private readonly config: Config;
70
75
 
71
76
  constructor(config: Config, cacheDir?: string) {
72
77
  this.config = config;
73
78
  const modelConfig = getModelConfig(config);
74
- this.manager = getModelManager(modelConfig);
79
+ this.worker = new NativeWorkerClient({
80
+ models: [],
81
+ loadTimeout: modelConfig.loadTimeout,
82
+ inferenceTimeout: modelConfig.inferenceTimeout,
83
+ warmModelTtl: modelConfig.warmModelTtl,
84
+ });
75
85
  this.cache = new ModelCache(cacheDir);
76
86
  }
77
87
 
@@ -91,6 +101,7 @@ export class LlmAdapter {
91
101
  // Use HTTP embedding for remote endpoints
92
102
  if (isHttpModelUri(uri)) {
93
103
  const httpEmbed = new HttpEmbedding(uri, {
104
+ inferenceTimeout: getModelConfig(this.config).inferenceTimeout,
94
105
  collections: this.config.collections,
95
106
  collectionNames: resolveEgressCollectionNames(
96
107
  this.config,
@@ -116,9 +127,11 @@ export class LlmAdapter {
116
127
  return resolved;
117
128
  }
118
129
 
130
+ const approved = await this.approve(uri, resolved.value, "embed");
131
+ if (!approved.ok) return approved;
119
132
  return {
120
133
  ok: true,
121
- value: new NodeLlamaCppEmbedding(this.manager, uri, resolved.value),
134
+ value: new NativeEmbeddingPort(this.worker, approved.value, uri),
122
135
  };
123
136
  }
124
137
 
@@ -137,6 +150,7 @@ export class LlmAdapter {
137
150
  // Use HTTP generation for remote endpoints
138
151
  if (isHttpGenUri(uri)) {
139
152
  const httpGen = new HttpGeneration(uri, {
153
+ inferenceTimeout: getModelConfig(this.config).inferenceTimeout,
140
154
  collections: this.config.collections,
141
155
  collectionNames: resolveEgressCollectionNames(
142
156
  this.config,
@@ -157,9 +171,11 @@ export class LlmAdapter {
157
171
  return resolved;
158
172
  }
159
173
 
174
+ const approved = await this.approve(uri, resolved.value, "gen");
175
+ if (!approved.ok) return approved;
160
176
  return {
161
177
  ok: true,
162
- value: new NodeLlamaCppGeneration(this.manager, uri, resolved.value),
178
+ value: new NativeGenerationPort(this.worker, approved.value, uri),
163
179
  };
164
180
  }
165
181
 
@@ -176,6 +192,7 @@ export class LlmAdapter {
176
192
 
177
193
  if (isHttpGenUri(uri)) {
178
194
  const httpGen = new HttpGeneration(uri, {
195
+ inferenceTimeout: getModelConfig(this.config).inferenceTimeout,
179
196
  collections: this.config.collections,
180
197
  collectionNames: resolveEgressCollectionNames(
181
198
  this.config,
@@ -195,9 +212,11 @@ export class LlmAdapter {
195
212
  return resolved;
196
213
  }
197
214
 
215
+ const approved = await this.approve(uri, resolved.value, "gen");
216
+ if (!approved.ok) return approved;
198
217
  return {
199
218
  ok: true,
200
- value: new NodeLlamaCppGeneration(this.manager, uri, resolved.value),
219
+ value: new NativeGenerationPort(this.worker, approved.value, uri),
201
220
  };
202
221
  }
203
222
 
@@ -217,6 +236,7 @@ export class LlmAdapter {
217
236
  // Use HTTP rerank for remote endpoints
218
237
  if (isHttpRerankUri(uri)) {
219
238
  const httpRerank = new HttpRerank(uri, {
239
+ inferenceTimeout: getModelConfig(this.config).inferenceTimeout,
220
240
  collections: this.config.collections,
221
241
  collectionNames: resolveEgressCollectionNames(
222
242
  this.config,
@@ -237,12 +257,39 @@ export class LlmAdapter {
237
257
  return resolved;
238
258
  }
239
259
 
260
+ const approved = await this.approve(uri, resolved.value, "rerank");
261
+ if (!approved.ok) return approved;
240
262
  return {
241
263
  ok: true,
242
- value: new NodeLlamaCppRerank(this.manager, uri, resolved.value),
264
+ value: new NativeRerankPort(this.worker, approved.value, uri),
243
265
  };
244
266
  }
245
267
 
268
+ private async approve(
269
+ uri: string,
270
+ path: string,
271
+ type: ModelType
272
+ ): Promise<LlmResult<string>> {
273
+ try {
274
+ const id = `${type}:${uri}`;
275
+ await this.worker.registerModel({
276
+ id,
277
+ modelUri: uri,
278
+ path: await realpath(path),
279
+ type,
280
+ });
281
+ return { ok: true, value: id };
282
+ } catch (cause) {
283
+ return {
284
+ ok: false,
285
+ error: (cause instanceof NativeWorkerError
286
+ ? cause
287
+ : new NativeWorkerError("protocol")
288
+ ).detail,
289
+ };
290
+ }
291
+ }
292
+
246
293
  /**
247
294
  * Get the model cache instance.
248
295
  */
@@ -251,22 +298,32 @@ export class LlmAdapter {
251
298
  }
252
299
 
253
300
  /**
254
- * Get the model manager instance.
301
+ * Native-free lifetime facade. Explicit model disposal retires the child.
255
302
  */
256
- getManager(): ModelManager {
257
- return this.manager;
303
+ getLifecycleStats() {
304
+ return this.worker.getLifecycleStats();
305
+ }
306
+
307
+ getManager(): {
308
+ dispose(uri: string): Promise<void>;
309
+ acquireLease(): ModelLease;
310
+ } {
311
+ return {
312
+ dispose: (uri) => this.worker.disposeModel(uri),
313
+ acquireLease: () => this.worker.acquireLease(),
314
+ };
258
315
  }
259
316
 
260
317
  /** Acquire an idempotent request lease without transferring manager ownership. */
261
318
  acquireModelLease(): ModelLease {
262
- return this.manager.acquireLease();
319
+ return this.worker.acquireLease();
263
320
  }
264
321
 
265
322
  /**
266
323
  * Dispose all resources.
267
324
  */
268
- async dispose(): Promise<void> {
269
- await this.manager.disposeAll();
325
+ async dispose(options?: NativeDisposeOptions): Promise<void> {
326
+ await this.worker.dispose(options);
270
327
  }
271
328
  }
272
329
 
@@ -1,19 +1,16 @@
1
+ import { platform, totalmem } from "node:os";
2
+
3
+ import type { NativeEvaluationOptions } from "../native-worker/evaluation";
1
4
  /**
2
5
  * Embedding port implementation using node-llama-cpp.
3
6
  *
4
7
  * @module src/llm/nodeLlamaCpp/embedding
5
8
  */
6
-
7
- import { platform, totalmem } from "node:os";
8
-
9
9
  import type { EmbeddingPort, LlmResult } from "../types";
10
10
  import type { ModelManager } from "./lifecycle";
11
11
 
12
12
  import { inferenceFailedError } from "../errors";
13
-
14
- // ─────────────────────────────────────────────────────────────────────────────
15
- // Types
16
- // ─────────────────────────────────────────────────────────────────────────────
13
+ import { checkEvaluation, startEvaluation } from "../native-worker/evaluation";
17
14
 
18
15
  // LlamaModel type from node-llama-cpp
19
16
  type LlamaModel = Awaited<
@@ -41,10 +38,6 @@ interface TokenizingModel {
41
38
 
42
39
  type EmbeddingInput = Parameters<LlamaEmbeddingContext["getEmbeddingFor"]>[0];
43
40
 
44
- // ─────────────────────────────────────────────────────────────────────────────
45
- // Constants
46
- // ─────────────────────────────────────────────────────────────────────────────
47
-
48
41
  // Aim for a small pool so CPU-only runs can exploit parallel contexts without
49
42
  // multiplying RAM usage too aggressively. Additional contexts fall back
50
43
  // gracefully if memory is tight.
@@ -147,10 +140,6 @@ export function resolveEmbeddingContextPoolSize(options: {
147
140
  return adaptivePoolSize;
148
141
  }
149
142
 
150
- // ─────────────────────────────────────────────────────────────────────────────
151
- // Implementation
152
- // ─────────────────────────────────────────────────────────────────────────────
153
-
154
143
  export class NodeLlamaCppEmbedding implements EmbeddingPort {
155
144
  private workers: EmbeddingWorker[] = [];
156
145
  private contextsPromise: Promise<LlmResult<LlamaEmbeddingContext[]>> | null =
@@ -171,16 +160,40 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
171
160
  this.modelPath = modelPath;
172
161
  }
173
162
 
174
- async init(): Promise<LlmResult<void>> {
175
- const contexts = await this.getContexts();
176
- if (!contexts.ok) {
177
- return contexts;
163
+ async init(options?: NativeEvaluationOptions): Promise<LlmResult<void>> {
164
+ const lease = this.manager.acquireLease(this.modelUri, false);
165
+ try {
166
+ checkEvaluation(options);
167
+ const contexts = await this.getContexts(options);
168
+ checkEvaluation(options);
169
+ if (!contexts.ok) {
170
+ return contexts;
171
+ }
172
+ return { ok: true, value: undefined };
173
+ } finally {
174
+ lease.release();
175
+ }
176
+ }
177
+
178
+ async embed(
179
+ text: string,
180
+ options?: NativeEvaluationOptions
181
+ ): Promise<LlmResult<number[]>> {
182
+ const lease = this.manager.acquireLease(this.modelUri);
183
+ try {
184
+ return await this.embedLeased(text, options);
185
+ } finally {
186
+ lease.release();
178
187
  }
179
- return { ok: true, value: undefined };
180
188
  }
181
189
 
182
- async embed(text: string): Promise<LlmResult<number[]>> {
183
- const contexts = await this.getContexts();
190
+ private async embedLeased(
191
+ text: string,
192
+ options?: NativeEvaluationOptions
193
+ ): Promise<LlmResult<number[]>> {
194
+ checkEvaluation(options);
195
+ const contexts = await this.getContexts(options);
196
+ checkEvaluation(options);
184
197
  if (!contexts.ok) {
185
198
  return contexts;
186
199
  }
@@ -190,9 +203,11 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
190
203
  if (!prepared.ok) {
191
204
  return { ok: false, error: prepared.error };
192
205
  }
206
+ startEvaluation(options);
193
207
  const embedding = await this.runOnWorker((worker) =>
194
208
  worker.context.getEmbeddingFor(prepared.value.input)
195
209
  );
210
+ checkEvaluation(options);
196
211
  const vector = embeddingVectorToArray(embedding.vector);
197
212
 
198
213
  // Cache dimensions on first call
@@ -206,8 +221,25 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
206
221
  }
207
222
  }
208
223
 
209
- async embedBatch(texts: string[]): Promise<LlmResult<number[][]>> {
210
- const contexts = await this.getContexts();
224
+ async embedBatch(
225
+ texts: string[],
226
+ options?: NativeEvaluationOptions
227
+ ): Promise<LlmResult<number[][]>> {
228
+ const lease = this.manager.acquireLease(this.modelUri);
229
+ try {
230
+ return await this.embedBatchLeased(texts, options);
231
+ } finally {
232
+ lease.release();
233
+ }
234
+ }
235
+
236
+ private async embedBatchLeased(
237
+ texts: string[],
238
+ options?: NativeEvaluationOptions
239
+ ): Promise<LlmResult<number[][]>> {
240
+ checkEvaluation(options);
241
+ const contexts = await this.getContexts(options);
242
+ checkEvaluation(options);
211
243
  if (!contexts.ok) {
212
244
  return contexts;
213
245
  }
@@ -235,6 +267,7 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
235
267
  const settled = await Promise.allSettled(
236
268
  this.workers.map(async (worker) => {
237
269
  while (true) {
270
+ checkEvaluation(options);
238
271
  const index = nextIndex;
239
272
  nextIndex += 1;
240
273
  if (index >= preparedInputs.length) {
@@ -245,6 +278,7 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
245
278
  if (input === undefined) {
246
279
  return;
247
280
  }
281
+ startEvaluation(options);
248
282
  const embedding = await this.runOnSpecificWorker(
249
283
  worker,
250
284
  (current) => current.context.getEmbeddingFor(input)
@@ -265,6 +299,7 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
265
299
  };
266
300
  }
267
301
 
302
+ checkEvaluation(options);
268
303
  // Cache dimensions from first result
269
304
  const firstResult = allResults[0];
270
305
  if (this.dims === null && firstResult !== undefined) {
@@ -284,25 +319,54 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
284
319
  return this.dims;
285
320
  }
286
321
 
322
+ /** Child-only effective tokenizer policy; never infer this from parent config. */
323
+ getContextIdentity(): {
324
+ contextSize: number;
325
+ truncationPolicy: string;
326
+ contextCount: number;
327
+ threadsPerContext: number;
328
+ } {
329
+ if (!this.llamaModel || !this.workers.length)
330
+ throw new Error("Embedding context not initialized");
331
+ const trainSize = this.llamaModel.trainContextSize;
332
+ const limit =
333
+ typeof trainSize === "number" &&
334
+ Number.isFinite(trainSize) &&
335
+ trainSize > 0
336
+ ? Math.min(Math.floor(trainSize), this.embeddingContextSize)
337
+ : this.embeddingContextSize;
338
+ return {
339
+ contextSize: this.embeddingContextSize,
340
+ truncationPolicy: `truncate-tail-tokens-v1:limit=${Math.max(1, limit - 4)}`,
341
+ contextCount: this.workers.length,
342
+ threadsPerContext: this.threadsPerContext,
343
+ };
344
+ }
345
+
287
346
  async dispose(): Promise<void> {
288
- this.lifecycleVersion += 1;
289
- this.contextsPromise = null;
290
- const workers = this.workers;
291
- this.workers = [];
292
-
293
- for (const worker of workers) {
294
- try {
295
- await worker.context.dispose();
296
- } catch {
297
- // Ignore disposal errors
347
+ const lease = this.manager.acquireLease(this.modelUri, false);
348
+ try {
349
+ this.lifecycleVersion += 1;
350
+ this.contextsPromise = null;
351
+ this.llamaModel = null;
352
+ this.dims = null;
353
+ this.warnedSingleTruncation = false;
354
+ this.warnedBatchTruncation = false;
355
+ const workers = this.workers;
356
+ this.workers = [];
357
+
358
+ for (const worker of workers) {
359
+ try {
360
+ await worker.context.dispose();
361
+ } catch {
362
+ // Ignore disposal errors
363
+ }
298
364
  }
365
+ } finally {
366
+ lease.release();
299
367
  }
300
368
  }
301
369
 
302
- // ───────────────────────────────────────────────────────────────────────────
303
- // Private
304
- // ───────────────────────────────────────────────────────────────────────────
305
-
306
370
  private async runOnWorker<T>(
307
371
  task: (worker: EmbeddingWorker) => Promise<T>
308
372
  ): Promise<T> {
@@ -337,7 +401,12 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
337
401
  return bestWorker;
338
402
  }
339
403
 
340
- private getContexts(): Promise<LlmResult<LlamaEmbeddingContext[]>> {
404
+ private async getContexts(
405
+ options?: NativeEvaluationOptions
406
+ ): Promise<LlmResult<LlamaEmbeddingContext[]>> {
407
+ if (this.workers.some((worker) => worker.context.disposed)) {
408
+ await this.dispose();
409
+ }
341
410
  if (this.workers.length > 0) {
342
411
  return Promise.resolve({
343
412
  ok: true,
@@ -349,7 +418,7 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
349
418
  return this.contextsPromise;
350
419
  }
351
420
 
352
- this.contextsPromise = this.createContexts();
421
+ this.contextsPromise = this.createContexts(options);
353
422
  return this.contextsPromise;
354
423
  }
355
424
 
@@ -360,6 +429,8 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
360
429
  });
361
430
  }
362
431
 
432
+ private threadsPerContext = 0;
433
+
363
434
  private resolveThreadsPerContext(llama: Llama, poolSize: number): number {
364
435
  if (llama.gpu !== false) {
365
436
  return 0;
@@ -373,11 +444,15 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
373
444
  return Math.max(1, Math.floor(Math.max(1, llama.cpuMathCores) / poolSize));
374
445
  }
375
446
 
376
- private async createContexts(): Promise<LlmResult<LlamaEmbeddingContext[]>> {
447
+ private async createContexts(
448
+ options?: NativeEvaluationOptions
449
+ ): Promise<LlmResult<LlamaEmbeddingContext[]>> {
450
+ const lifecycleVersion = this.lifecycleVersion;
377
451
  const model = await this.manager.loadModel(
378
452
  this.modelPath,
379
453
  this.modelUri,
380
- "embed"
454
+ "embed",
455
+ options?.signal
381
456
  );
382
457
  if (!model.ok) {
383
458
  this.contextsPromise = null;
@@ -386,9 +461,7 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
386
461
 
387
462
  try {
388
463
  const llamaModel = model.value.model as LlamaModel;
389
- this.llamaModel = llamaModel as TokenizingModel;
390
464
  const llama = await this.manager.getLlama();
391
- const lifecycleVersion = this.lifecycleVersion;
392
465
  this.embeddingContextSize =
393
466
  resolveEmbeddingContextSizeOverride() ?? DEFAULT_EMBEDDING_CONTEXT_SIZE;
394
467
  const targetPoolSize = this.resolveTargetPoolSize(llama);
@@ -396,6 +469,7 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
396
469
  llama,
397
470
  targetPoolSize
398
471
  );
472
+ this.threadsPerContext = threadsPerContext;
399
473
  const contextOptions =
400
474
  llama.gpu === false
401
475
  ? {
@@ -407,10 +481,19 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
407
481
 
408
482
  for (let i = 0; i < targetPoolSize; i += 1) {
409
483
  try {
410
- const context =
411
- await llamaModel.createEmbeddingContext(contextOptions);
484
+ const context = await llamaModel.createEmbeddingContext({
485
+ ...contextOptions,
486
+ createSignal: options?.signal,
487
+ });
412
488
  contexts.push(context);
413
489
  } catch (error) {
490
+ if (options?.signal?.aborted) {
491
+ await Promise.allSettled(
492
+ contexts.map((context) => context.dispose())
493
+ );
494
+ this.contextsPromise = null;
495
+ throw error;
496
+ }
414
497
  if (contexts.length === 0) {
415
498
  this.contextsPromise = null;
416
499
  return {
@@ -440,6 +523,7 @@ export class NodeLlamaCppEmbedding implements EmbeddingPort {
440
523
  }
441
524
 
442
525
  this.workers = contexts.map((context) => ({ context, pending: 0 }));
526
+ this.llamaModel = llamaModel as TokenizingModel;
443
527
 
444
528
  const size = llamaModel.embeddingVectorSize;
445
529
  if (this.dims === null && typeof size === "number" && size > 0) {
@@ -1,13 +1,14 @@
1
+ import type { NativeEvaluationOptions } from "../native-worker/evaluation";
2
+ import type { GenerationPort, GenParams, LlmResult } from "../types";
1
3
  /**
2
4
  * Generation port implementation using node-llama-cpp.
3
5
  *
4
6
  * @module src/llm/nodeLlamaCpp/generation
5
7
  */
6
-
7
- import type { GenerationPort, GenParams, LlmResult } from "../types";
8
8
  import type { ModelManager } from "./lifecycle";
9
9
 
10
10
  import { inferenceFailedError } from "../errors";
11
+ import { checkEvaluation, startEvaluation } from "../native-worker/evaluation";
11
12
 
12
13
  // ─────────────────────────────────────────────────────────────────────────────
13
14
  // Types
@@ -33,6 +34,8 @@ export interface StructuredPromptSession {
33
34
  seed: number;
34
35
  maxTokens: number;
35
36
  grammar?: JsonSchemaGrammarLike;
37
+ signal?: AbortSignal;
38
+ stopOnAbortSignal?: boolean;
36
39
  }
37
40
  ): Promise<string>;
38
41
  }
@@ -44,6 +47,8 @@ export const promptWithJsonSchemaGrammar = async (
44
47
  temperature: number;
45
48
  seed: number;
46
49
  maxTokens: number;
50
+ signal?: AbortSignal;
51
+ stopOnAbortSignal?: boolean;
47
52
  },
48
53
  grammar?: JsonSchemaGrammarLike
49
54
  ): Promise<string> => {
@@ -101,12 +106,28 @@ export class NodeLlamaCppGeneration implements GenerationPort {
101
106
 
102
107
  async generate(
103
108
  prompt: string,
104
- params?: GenParams
109
+ params?: GenParams,
110
+ options?: NativeEvaluationOptions
105
111
  ): Promise<LlmResult<string>> {
112
+ const lease = this.manager.acquireLease(this.modelUri);
113
+ try {
114
+ return await this.generateLeased(prompt, params, options);
115
+ } finally {
116
+ lease.release();
117
+ }
118
+ }
119
+
120
+ private async generateLeased(
121
+ prompt: string,
122
+ params?: GenParams,
123
+ options?: NativeEvaluationOptions
124
+ ): Promise<LlmResult<string>> {
125
+ checkEvaluation(options);
106
126
  const model = await this.manager.loadModel(
107
127
  this.modelPath,
108
128
  this.modelUri,
109
- "gen"
129
+ "gen",
130
+ options?.signal
110
131
  );
111
132
  if (!model.ok) {
112
133
  return model;
@@ -115,6 +136,7 @@ export class NodeLlamaCppGeneration implements GenerationPort {
115
136
  const llamaModel = model.value.model as LlamaModel;
116
137
  let context: Awaited<ReturnType<LlamaModel["createContext"]>> | null = null;
117
138
  try {
139
+ checkEvaluation(options);
118
140
  const grammar = params?.jsonSchema
119
141
  ? await (
120
142
  await this.manager.getLlama()
@@ -127,7 +149,10 @@ export class NodeLlamaCppGeneration implements GenerationPort {
127
149
  maxTokens: params?.maxTokens ?? DEFAULT_MAX_TOKENS,
128
150
  trainContextSize: llamaModel.trainContextSize,
129
151
  });
130
- context = await llamaModel.createContext({ contextSize });
152
+ context = await llamaModel.createContext({
153
+ contextSize,
154
+ createSignal: options?.signal,
155
+ });
131
156
  // Import LlamaChatSession dynamically
132
157
  const { LlamaChatSession } = await import("node-llama-cpp");
133
158
  const session = new LlamaChatSession({
@@ -135,10 +160,13 @@ export class NodeLlamaCppGeneration implements GenerationPort {
135
160
  });
136
161
 
137
162
  // Note: stop sequences not yet supported - requires stopOnTrigger API
163
+ startEvaluation(options);
138
164
  const response = await promptWithJsonSchemaGrammar(
139
165
  session as StructuredPromptSession,
140
166
  prompt,
141
167
  {
168
+ signal: options?.signal,
169
+ stopOnAbortSignal: false,
142
170
  temperature: params?.temperature ?? DEFAULT_TEMPERATURE,
143
171
  seed: params?.seed ?? DEFAULT_SEED,
144
172
  maxTokens: params?.maxTokens ?? DEFAULT_MAX_TOKENS,
@@ -146,6 +174,7 @@ export class NodeLlamaCppGeneration implements GenerationPort {
146
174
  grammar
147
175
  );
148
176
 
177
+ checkEvaluation(options);
149
178
  return { ok: true, value: response };
150
179
  } catch (e) {
151
180
  return { ok: false, error: inferenceFailedError(this.modelUri, e) };