@gmickel/gno 1.46.0 → 2.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.
Files changed (235) hide show
  1. package/README.md +17 -5
  2. package/THIRD_PARTY_NOTICES.md +46 -0
  3. package/assets/skill/SKILL.md +7 -6
  4. package/assets/spa-production.json.gz +0 -0
  5. package/browser-extension/artifacts/gno-browser-clipper-v2.1.0.zip +0 -0
  6. package/browser-extension/artifacts/gno-browser-clipper-v2.1.0.zip.sha256 +1 -0
  7. package/browser-extension/dist/chunk-4tc9v0ja.js +74 -0
  8. package/browser-extension/dist/manifest.json +1 -1
  9. package/browser-extension/dist/preview.html +1 -1
  10. package/browser-extension/dist/service-worker.js +32 -33
  11. package/bunfig.toml +2 -0
  12. package/package.json +40 -26
  13. package/spec/cli.md +29 -4
  14. package/spec/db/schema.sql +146 -1
  15. package/spec/mcp.md +26 -0
  16. package/src/app/context-runtime-types.ts +3 -0
  17. package/src/app/context-runtime.ts +2 -0
  18. package/src/cli/commands/ask.ts +6 -1
  19. package/src/cli/commands/daemon.ts +21 -8
  20. package/src/cli/commands/embed.ts +77 -41
  21. package/src/cli/detach.ts +3 -2
  22. package/src/config/types.ts +3 -3
  23. package/src/converters/adapters/markitdownTs/adapter.ts +1 -2
  24. package/src/converters/adapters/officeparser/adapter.ts +1 -2
  25. package/src/converters/versions.ts +6 -8
  26. package/src/core/context-evidence.ts +8 -4
  27. package/src/core/job-manager.ts +95 -13
  28. package/src/core/network-boundary-inventory.ts +10 -0
  29. package/src/core/shutdown-budget.ts +45 -0
  30. package/src/embed/backlog.ts +107 -4
  31. package/src/embed/batch.ts +42 -2
  32. package/src/embed/fingerprint.ts +16 -0
  33. package/src/embed/retry.ts +113 -5
  34. package/src/embed/variant-backlog.ts +105 -0
  35. package/src/embed/variant-plan.ts +62 -0
  36. package/src/embed/variant-retry.ts +113 -0
  37. package/src/ingestion/graph-reconciliation.ts +327 -0
  38. package/src/ingestion/sync.ts +9 -272
  39. package/src/llm/http-inference.ts +6 -0
  40. package/src/llm/httpEmbedding.ts +37 -6
  41. package/src/llm/httpGeneration.ts +18 -3
  42. package/src/llm/httpRerank.ts +23 -5
  43. package/src/llm/inference-cancellation.ts +168 -0
  44. package/src/llm/inference-scope.ts +202 -0
  45. package/src/llm/lazy-ports.ts +115 -0
  46. package/src/llm/native-worker/client.ts +541 -0
  47. package/src/llm/native-worker/dispatcher.ts +228 -0
  48. package/src/llm/native-worker/embedding-identity.ts +33 -0
  49. package/src/llm/native-worker/entry.ts +173 -0
  50. package/src/llm/native-worker/errors.ts +32 -0
  51. package/src/llm/native-worker/evaluation.ts +16 -0
  52. package/src/llm/native-worker/owned-exit.ts +108 -0
  53. package/src/llm/native-worker/owner.ts +141 -0
  54. package/src/llm/native-worker/ports.ts +317 -0
  55. package/src/llm/native-worker/protocol.ts +442 -0
  56. package/src/llm/native-worker/runtime-config.ts +92 -0
  57. package/src/llm/nodeLlamaCpp/adapter.ts +77 -20
  58. package/src/llm/nodeLlamaCpp/embedding.ts +130 -46
  59. package/src/llm/nodeLlamaCpp/generation.ts +34 -5
  60. package/src/llm/nodeLlamaCpp/lifecycle-options.ts +99 -0
  61. package/src/llm/nodeLlamaCpp/lifecycle.ts +209 -204
  62. package/src/llm/nodeLlamaCpp/rerank-capacity.ts +111 -0
  63. package/src/llm/nodeLlamaCpp/rerank.ts +118 -27
  64. package/src/llm/nodeLlamaCpp/simulator-handle.ts +73 -0
  65. package/src/llm/nodeLlamaCpp/simulator-install.ts +124 -0
  66. package/src/llm/nodeLlamaCpp/simulator-session.ts +240 -0
  67. package/src/llm/nodeLlamaCpp/simulator-types.ts +80 -0
  68. package/src/llm/types.ts +35 -5
  69. package/src/mcp/context.ts +27 -0
  70. package/src/mcp/http-transport.ts +12 -10
  71. package/src/mcp/server.ts +3 -0
  72. package/src/mcp/tool-profile.ts +30 -8
  73. package/src/mcp/tools/context.ts +8 -11
  74. package/src/mcp/tools/embed.ts +1 -1
  75. package/src/mcp/tools/index-cmd.ts +1 -1
  76. package/src/mcp/tools/index.ts +10 -8
  77. package/src/mcp/tools/query.ts +14 -30
  78. package/src/mcp/tools/vsearch.ts +1 -1
  79. package/src/pipeline/answer.ts +23 -3
  80. package/src/pipeline/claim-verifier.ts +6 -0
  81. package/src/pipeline/expansion.ts +43 -40
  82. package/src/pipeline/explain.ts +6 -2
  83. package/src/pipeline/filters.ts +63 -0
  84. package/src/pipeline/fusion.ts +29 -9
  85. package/src/pipeline/graph-retrieval.ts +29 -9
  86. package/src/pipeline/hybrid.ts +198 -55
  87. package/src/pipeline/hydration.ts +161 -0
  88. package/src/pipeline/owner-fusion.ts +87 -0
  89. package/src/pipeline/rerank.ts +35 -11
  90. package/src/pipeline/search.ts +13 -2
  91. package/src/pipeline/types.ts +5 -3
  92. package/src/pipeline/vsearch.ts +87 -7
  93. package/src/sdk/client.ts +47 -3
  94. package/src/sdk/embed.ts +63 -39
  95. package/src/serve/background-runtime.ts +1 -1
  96. package/src/serve/context.ts +41 -56
  97. package/src/serve/embed-scheduler.ts +58 -35
  98. package/src/serve/public/components/IndexingProgress.tsx +46 -60
  99. package/src/serve/public/components/PublishExportDialog.tsx +266 -0
  100. package/src/serve/public/globals.built.css +1 -1
  101. package/src/serve/public/globals.css +35 -0
  102. package/src/serve/public/lib/publish-export.ts +81 -1
  103. package/src/serve/public/lib/shiki-language-ids.ts +14 -0
  104. package/src/serve/public/pages/Collections.tsx +12 -46
  105. package/src/serve/public/pages/DocView.tsx +14 -52
  106. package/src/serve/resident-admission.ts +36 -36
  107. package/src/serve/resident-background-work.ts +20 -2
  108. package/src/serve/resident-request.ts +11 -5
  109. package/src/serve/resident-runtime.ts +97 -61
  110. package/src/serve/resident-shutdown.ts +153 -0
  111. package/src/serve/routes/api.ts +3 -1
  112. package/src/serve/server.ts +47 -26
  113. package/src/store/migrations/028-vector-variants.ts +54 -0
  114. package/src/store/migrations/029-graph-reference-state.ts +77 -0
  115. package/src/store/migrations/index.ts +4 -0
  116. package/src/store/sqlite/adapter.ts +251 -183
  117. package/src/store/sqlite/eligibility.ts +174 -0
  118. package/src/store/sqlite/graph-edge-application.ts +66 -0
  119. package/src/store/sqlite/graph-reference-state.ts +194 -0
  120. package/src/store/sqlite/legacy-vector-ownership.ts +79 -0
  121. package/src/store/types.ts +80 -12
  122. package/src/store/vector/eligibility.ts +36 -0
  123. package/src/store/vector/freshness.ts +33 -6
  124. package/src/store/vector/lazy.ts +81 -0
  125. package/src/store/vector/sqlite-vec.ts +106 -54
  126. package/src/store/vector/stats.ts +14 -3
  127. package/src/store/vector/types.ts +35 -2
  128. package/src/store/vector/variant-search.ts +192 -0
  129. package/src/store/vector/variants.ts +451 -0
  130. package/vendor/converters/markitdown-ts/LICENSE +21 -0
  131. package/vendor/converters/markitdown-ts/dist/index.cjs +1180 -0
  132. package/vendor/converters/markitdown-ts/dist/index.d.cts +46 -0
  133. package/vendor/converters/markitdown-ts/dist/index.d.mts +46 -0
  134. package/vendor/converters/markitdown-ts/dist/index.d.ts +46 -0
  135. package/vendor/converters/markitdown-ts/dist/index.mjs +1152 -0
  136. package/vendor/converters/markitdown-ts/package.json +77 -0
  137. package/vendor/converters/officeparser/LICENSE +21 -0
  138. package/vendor/converters/officeparser/dist/OfficeConverter.d.ts +47 -0
  139. package/vendor/converters/officeparser/dist/OfficeConverter.js +76 -0
  140. package/vendor/converters/officeparser/dist/OfficeGenerator.d.ts +23 -0
  141. package/vendor/converters/officeparser/dist/OfficeGenerator.js +73 -0
  142. package/vendor/converters/officeparser/dist/OfficeParser.d.ts +106 -0
  143. package/vendor/converters/officeparser/dist/OfficeParser.js +332 -0
  144. package/vendor/converters/officeparser/dist/cli.d.ts +28 -0
  145. package/vendor/converters/officeparser/dist/cli.js +381 -0
  146. package/vendor/converters/officeparser/dist/defaults.d.ts +41 -0
  147. package/vendor/converters/officeparser/dist/defaults.js +218 -0
  148. package/vendor/converters/officeparser/dist/generators/BaseGenerator.d.ts +107 -0
  149. package/vendor/converters/officeparser/dist/generators/BaseGenerator.js +248 -0
  150. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.d.ts +82 -0
  151. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.js +797 -0
  152. package/vendor/converters/officeparser/dist/generators/CsvGenerator.d.ts +38 -0
  153. package/vendor/converters/officeparser/dist/generators/CsvGenerator.js +245 -0
  154. package/vendor/converters/officeparser/dist/generators/EpubGenerator.d.ts +43 -0
  155. package/vendor/converters/officeparser/dist/generators/EpubGenerator.js +315 -0
  156. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.d.ts +59 -0
  157. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.js +1942 -0
  158. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.d.ts +96 -0
  159. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.js +1175 -0
  160. package/vendor/converters/officeparser/dist/generators/PdfGenerator.d.ts +22 -0
  161. package/vendor/converters/officeparser/dist/generators/PdfGenerator.js +194 -0
  162. package/vendor/converters/officeparser/dist/generators/RtfGenerator.d.ts +29 -0
  163. package/vendor/converters/officeparser/dist/generators/RtfGenerator.js +316 -0
  164. package/vendor/converters/officeparser/dist/generators/TextGenerator.d.ts +13 -0
  165. package/vendor/converters/officeparser/dist/generators/TextGenerator.js +201 -0
  166. package/vendor/converters/officeparser/dist/index.d.ts +60 -0
  167. package/vendor/converters/officeparser/dist/index.js +72 -0
  168. package/vendor/converters/officeparser/dist/index.mjs +18 -0
  169. package/vendor/converters/officeparser/dist/officeparser.browser.d.ts +2621 -0
  170. package/vendor/converters/officeparser/dist/officeparser.browser.iife.js +1336 -0
  171. package/vendor/converters/officeparser/dist/officeparser.browser.mjs +1335 -0
  172. package/vendor/converters/officeparser/dist/officeparser.browser.slim.d.ts +2621 -0
  173. package/vendor/converters/officeparser/dist/officeparser.browser.slim.iife.js +1336 -0
  174. package/vendor/converters/officeparser/dist/officeparser.browser.slim.mjs +1335 -0
  175. package/vendor/converters/officeparser/dist/parsers/CsvParser.d.ts +9 -0
  176. package/vendor/converters/officeparser/dist/parsers/CsvParser.js +115 -0
  177. package/vendor/converters/officeparser/dist/parsers/EpubParser.d.ts +8 -0
  178. package/vendor/converters/officeparser/dist/parsers/EpubParser.js +217 -0
  179. package/vendor/converters/officeparser/dist/parsers/ExcelParser.d.ts +32 -0
  180. package/vendor/converters/officeparser/dist/parsers/ExcelParser.js +736 -0
  181. package/vendor/converters/officeparser/dist/parsers/HtmlParser.d.ts +2 -0
  182. package/vendor/converters/officeparser/dist/parsers/HtmlParser.js +1287 -0
  183. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.d.ts +2 -0
  184. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.js +1272 -0
  185. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.d.ts +31 -0
  186. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.js +1819 -0
  187. package/vendor/converters/officeparser/dist/parsers/PdfParser.d.ts +67 -0
  188. package/vendor/converters/officeparser/dist/parsers/PdfParser.js +848 -0
  189. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.d.ts +32 -0
  190. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.js +950 -0
  191. package/vendor/converters/officeparser/dist/parsers/RtfParser.d.ts +187 -0
  192. package/vendor/converters/officeparser/dist/parsers/RtfParser.js +1801 -0
  193. package/vendor/converters/officeparser/dist/parsers/WordParser.d.ts +79 -0
  194. package/vendor/converters/officeparser/dist/parsers/WordParser.js +1177 -0
  195. package/vendor/converters/officeparser/dist/sbom.cdx.json +1763 -0
  196. package/vendor/converters/officeparser/dist/types.d.ts +2507 -0
  197. package/vendor/converters/officeparser/dist/types.js +107 -0
  198. package/vendor/converters/officeparser/dist/utils/astUtils.d.ts +16 -0
  199. package/vendor/converters/officeparser/dist/utils/astUtils.js +33 -0
  200. package/vendor/converters/officeparser/dist/utils/chartUtils.d.ts +6 -0
  201. package/vendor/converters/officeparser/dist/utils/chartUtils.js +257 -0
  202. package/vendor/converters/officeparser/dist/utils/configUtils.d.ts +44 -0
  203. package/vendor/converters/officeparser/dist/utils/configUtils.js +315 -0
  204. package/vendor/converters/officeparser/dist/utils/dateUtils.d.ts +17 -0
  205. package/vendor/converters/officeparser/dist/utils/dateUtils.js +69 -0
  206. package/vendor/converters/officeparser/dist/utils/envUtils.d.ts +29 -0
  207. package/vendor/converters/officeparser/dist/utils/envUtils.js +152 -0
  208. package/vendor/converters/officeparser/dist/utils/errorUtils.d.ts +72 -0
  209. package/vendor/converters/officeparser/dist/utils/errorUtils.js +245 -0
  210. package/vendor/converters/officeparser/dist/utils/imageUtils.d.ts +66 -0
  211. package/vendor/converters/officeparser/dist/utils/imageUtils.js +133 -0
  212. package/vendor/converters/officeparser/dist/utils/mathUtils.d.ts +42 -0
  213. package/vendor/converters/officeparser/dist/utils/mathUtils.js +385 -0
  214. package/vendor/converters/officeparser/dist/utils/moduleLoader.d.ts +18 -0
  215. package/vendor/converters/officeparser/dist/utils/moduleLoader.js +106 -0
  216. package/vendor/converters/officeparser/dist/utils/ocrUtils.d.ts +42 -0
  217. package/vendor/converters/officeparser/dist/utils/ocrUtils.js +428 -0
  218. package/vendor/converters/officeparser/dist/utils/sanitize.d.ts +148 -0
  219. package/vendor/converters/officeparser/dist/utils/sanitize.js +344 -0
  220. package/vendor/converters/officeparser/dist/utils/sheetUtils.d.ts +7 -0
  221. package/vendor/converters/officeparser/dist/utils/sheetUtils.js +35 -0
  222. package/vendor/converters/officeparser/dist/utils/styleMapper.d.ts +36 -0
  223. package/vendor/converters/officeparser/dist/utils/styleMapper.js +224 -0
  224. package/vendor/converters/officeparser/dist/utils/xmlUtils.d.ts +163 -0
  225. package/vendor/converters/officeparser/dist/utils/xmlUtils.js +461 -0
  226. package/vendor/converters/officeparser/dist/utils/zipUtils.d.ts +134 -0
  227. package/vendor/converters/officeparser/dist/utils/zipUtils.js +337 -0
  228. package/vendor/converters/officeparser/package.json +147 -0
  229. package/vendor/converters/upstream-manifest.json +124 -0
  230. package/vendor/dependency-fixes/README.md +77 -0
  231. package/vendor/dependency-fixes/vendor-converters.py +83 -0
  232. package/browser-extension/artifacts/gno-browser-clipper-v1.46.0.zip +0 -0
  233. package/browser-extension/artifacts/gno-browser-clipper-v1.46.0.zip.sha256 +0 -1
  234. package/browser-extension/dist/chunk-627emwpj.js +0 -75
  235. /package/browser-extension/dist/{chunk-ydfx5d7p.css → chunk-z74y8n8c.css} +0 -0
@@ -0,0 +1,541 @@
1
+ import type { ModelLifecycleStats } from "../nodeLlamaCpp/lifecycle";
2
+ import type { InferenceOptions } from "../types";
3
+ import type { Owner, Pending } from "./owner";
4
+ import type { ApprovedModel, NativeRequest, NativeResponse } from "./protocol";
5
+ import type { NativeRuntimeConfig } from "./runtime-config";
6
+
7
+ import { InferenceSettlement } from "../inference-cancellation";
8
+ import {
9
+ inferenceOptions,
10
+ recordInferenceTimeout,
11
+ isBackgroundInference,
12
+ } from "../inference-scope";
13
+ import { NativeWorkerError } from "./errors";
14
+ import { retireOwnedChild, type NativeDisposeOptions } from "./owned-exit";
15
+ import {
16
+ cancelPending,
17
+ wireResult,
18
+ waitForQuarantine,
19
+ releaseQuarantine,
20
+ selectNext,
21
+ recordCompletion,
22
+ } from "./owner";
23
+ import {
24
+ frameNativeMessage,
25
+ NativeFrameDecoder,
26
+ NativeRequestLedger,
27
+ parseNativeRequest,
28
+ NativeExecutionStartedSchema,
29
+ } from "./protocol";
30
+ import {
31
+ nativeWorkerEnvironment,
32
+ NativeRuntimeConfigSchema,
33
+ NativeRegistrationSchema,
34
+ wireError,
35
+ } from "./runtime-config";
36
+
37
+ type Input = NativeRequest extends infer R
38
+ ? R extends NativeRequest
39
+ ? Omit<R, "version" | "generation" | "requestId">
40
+ : never
41
+ : never;
42
+ export interface NativeWorkerClientOptions {
43
+ models: readonly ApprovedModel[];
44
+ loadTimeout: number;
45
+ inferenceTimeout: number;
46
+ warmModelTtl?: number;
47
+ /** Internal fault-test launch seam; never populated from caller configuration. */
48
+ entryPath?: string;
49
+ }
50
+
51
+ /** One process generation, one active operation and 64 waiting logical calls. */
52
+ export class NativeWorkerClient {
53
+ private owner?: Owner;
54
+ private lifecycle?: ModelLifecycleStats;
55
+ private generation = 0;
56
+ private requestId = 0;
57
+ private closed = false;
58
+ private leases = 0;
59
+ private idleOwner?: Owner;
60
+ private registration: Promise<void> = Promise.resolve();
61
+ private readonly options: NativeWorkerClientOptions;
62
+
63
+ constructor(options: NativeWorkerClientOptions) {
64
+ this.options = { ...options, models: structuredClone(options.models) };
65
+ process.once("exit", this.onParentExit);
66
+ }
67
+
68
+ private readonly onParentExit = (): void => {
69
+ this.owner?.child.kill("SIGKILL");
70
+ };
71
+
72
+ get processId(): number | undefined {
73
+ return this.owner?.child.pid;
74
+ }
75
+ get currentGeneration(): number {
76
+ return this.generation;
77
+ }
78
+
79
+ /** Last child-reported snapshot; reading it sends no IPC and cannot extend idle. */
80
+ getLifecycleStats(): ModelLifecycleStats {
81
+ const snapshot = this.lifecycle ?? {
82
+ activeLeases: 0,
83
+ leaseAcquisitions: 0,
84
+ leaseReleases: 0,
85
+ loadedModels: 0,
86
+ loadAttempts: 0,
87
+ loadSuccesses: 0,
88
+ loadFailures: 0,
89
+ inflightLoads: 0,
90
+ };
91
+ return this.owner
92
+ ? { ...snapshot }
93
+ : {
94
+ ...snapshot,
95
+ activeLeases: 0,
96
+ loadedModels: 0,
97
+ inflightLoads: 0,
98
+ };
99
+ }
100
+
101
+ acquireLease(): { release(): void } {
102
+ if (this.closed) throw new NativeWorkerError("exited");
103
+ this.leases++;
104
+ let released = false;
105
+ return {
106
+ release: () => {
107
+ if (released) return;
108
+ released = true;
109
+ this.leases--;
110
+ const owner = this.idleOwner;
111
+ if (
112
+ !this.leases &&
113
+ owner &&
114
+ this.owner === owner &&
115
+ !owner.pending.length &&
116
+ !owner.busy
117
+ )
118
+ void this.retire(owner).catch((error: unknown) =>
119
+ console.error(error)
120
+ );
121
+ },
122
+ };
123
+ }
124
+
125
+ async disposeModel(uri: string): Promise<void> {
126
+ const operation = this.registration.then(async () => {
127
+ const owner = this.owner;
128
+ if (
129
+ !owner ||
130
+ !this.options.models.some((entry) => entry.modelUri === uri)
131
+ )
132
+ return;
133
+ if (owner.retiring) {
134
+ await owner.retirement;
135
+ return;
136
+ }
137
+ if (owner.pending.length || owner.busy)
138
+ await new Promise<void>((resolve) => owner.drain.add(resolve));
139
+ // Explicit disposal reclaims the complete process allocation. Individual
140
+ // model idle timers may already have evicted weights within this owner.
141
+ await this.retire(owner);
142
+ });
143
+ this.registration = operation.catch(() => {});
144
+ await operation;
145
+ }
146
+
147
+ /** Only the parent model-selection/policy layer may approve these descriptors. */
148
+ registerModel(model: ApprovedModel): Promise<void> {
149
+ const descriptor = NativeRegistrationSchema.parse({
150
+ register: model,
151
+ }).register;
152
+ const operation = this.registration.then(async () => {
153
+ if (this.closed) throw new NativeWorkerError("exited");
154
+ const existing = this.options.models.find(
155
+ (entry) => entry.id === descriptor.id
156
+ );
157
+ if (existing && JSON.stringify(existing) === JSON.stringify(descriptor))
158
+ return;
159
+ const models = [
160
+ ...this.options.models.filter((entry) => entry.id !== descriptor.id),
161
+ descriptor,
162
+ ];
163
+ NativeRuntimeConfigSchema.parse({
164
+ generation: Math.max(1, this.generation),
165
+ models,
166
+ loadTimeout: this.options.loadTimeout,
167
+ inferenceTimeout: this.options.inferenceTimeout,
168
+ warmModelTtl: this.options.warmModelTtl ?? 300_000,
169
+ });
170
+ const owner = this.owner;
171
+ if (owner?.retiring) await owner.retirement;
172
+ if (existing && owner) {
173
+ if (owner.pending.length || owner.busy)
174
+ await new Promise<void>((resolve) => owner.drain.add(resolve));
175
+ await this.retire(owner);
176
+ } else if (owner && !owner.retiring) {
177
+ owner.child.send({ register: descriptor });
178
+ }
179
+ this.options.models = models;
180
+ });
181
+ this.registration = operation.catch(() => {});
182
+ return operation;
183
+ }
184
+
185
+ async request(
186
+ input: Input,
187
+ expectedGeneration?: number,
188
+ options?: InferenceOptions
189
+ ): Promise<NativeResponse["result"]> {
190
+ const operational = inferenceOptions({
191
+ ...options,
192
+ deadlineAt: options?.deadlineAt ?? input.deadlineAt,
193
+ });
194
+ const settlement = new InferenceSettlement<
195
+ Extract<NativeResponse["result"], { ok: true }>["value"]
196
+ >(operational, this.options.inferenceTimeout);
197
+ void this.enqueue(
198
+ { ...input, deadlineAt: operational.deadlineAt },
199
+ expectedGeneration,
200
+ settlement
201
+ ).catch(() => {
202
+ settlement.fail(new NativeWorkerError("exited").detail);
203
+ });
204
+ return settlement.completion.then((result) => {
205
+ if (!result.ok && result.error.code === "TIMEOUT")
206
+ recordInferenceTimeout();
207
+ return wireResult(result);
208
+ });
209
+ }
210
+
211
+ private async enqueue(
212
+ input: Input,
213
+ expectedGeneration: number | undefined,
214
+ settlement: Pending["settlement"]
215
+ ): Promise<void> {
216
+ const result = await this.admit(input, expectedGeneration, settlement);
217
+ if (settlement.phase === "queued") settlement.startNative();
218
+ settlement.nativeSettled(result);
219
+ settlement.publish();
220
+ }
221
+
222
+ private async admit(
223
+ input: Input,
224
+ expectedGeneration: number | undefined,
225
+ settlement: Pending["settlement"]
226
+ ): Promise<NativeResponse["result"]> {
227
+ await this.registration;
228
+ if (settlement.signal.aborted)
229
+ return settlement.completion.then(wireResult);
230
+ if (this.closed)
231
+ return {
232
+ ok: false,
233
+ error: wireError(new NativeWorkerError("exited").detail),
234
+ };
235
+ while (this.owner?.quarantined && !this.owner.retiring) {
236
+ try {
237
+ await waitForQuarantine(this.owner, settlement);
238
+ } catch (cause) {
239
+ return {
240
+ ok: false,
241
+ error: wireError(
242
+ (cause instanceof NativeWorkerError
243
+ ? cause
244
+ : new NativeWorkerError("exited")
245
+ ).detail
246
+ ),
247
+ };
248
+ }
249
+ if (settlement.signal.aborted)
250
+ return settlement.completion.then(wireResult);
251
+ }
252
+ if (this.owner?.retiring) await this.owner.retirement;
253
+ if (this.closed)
254
+ return {
255
+ ok: false,
256
+ error: wireError(new NativeWorkerError("exited").detail),
257
+ };
258
+ if (settlement.signal.aborted)
259
+ return settlement.completion.then(wireResult);
260
+ if (input.op === "dispose" && !this.owner) return { ok: true, value: null };
261
+ try {
262
+ // Metadata-dependent inference must never start/replay on a replacement
263
+ // owner. All asynchronous registration/retirement waits precede this fence.
264
+ if (
265
+ expectedGeneration !== undefined &&
266
+ (!this.owner ||
267
+ this.owner.retiring ||
268
+ this.owner.generation !== expectedGeneration)
269
+ )
270
+ throw new NativeWorkerError("stale_generation");
271
+ const owner = this.owner ?? this.start();
272
+ const request = parseNativeRequest(
273
+ {
274
+ ...input,
275
+ deadlineAt: input.deadlineAt,
276
+ version: 1,
277
+ generation: owner.generation,
278
+ requestId: ++this.requestId,
279
+ },
280
+ owner.generation,
281
+ this.options.models
282
+ );
283
+ owner.ledger.admit(request);
284
+ return new Promise((resolve) => {
285
+ const pending: Pending = {
286
+ request,
287
+ resolve,
288
+ settlement,
289
+ background: isBackgroundInference(),
290
+ };
291
+ owner.pending.push(pending);
292
+ settlement.signal.addEventListener(
293
+ "abort",
294
+ () => this.cancel(owner, pending),
295
+ { once: true }
296
+ );
297
+ if (settlement.signal.aborted) this.cancel(owner, pending);
298
+ if (owner.pending.length === 1 && owner.ready) this.sendNext(owner);
299
+ });
300
+ } catch (cause) {
301
+ return {
302
+ ok: false,
303
+ error: wireError(
304
+ (cause instanceof NativeWorkerError
305
+ ? cause
306
+ : new NativeWorkerError("exited")
307
+ ).detail
308
+ ),
309
+ };
310
+ }
311
+ }
312
+
313
+ private start(): Owner {
314
+ this.lifecycle = undefined;
315
+ // A compiled executable cannot interpret an external TS entry: invoking it
316
+ // here would recursively launch the CLI. npm/desktop ship the source runtime.
317
+ if (import.meta.dir.includes("$bunfs"))
318
+ throw new NativeWorkerError("exited");
319
+ const config: NativeRuntimeConfig = NativeRuntimeConfigSchema.parse({
320
+ generation: ++this.generation,
321
+ models: this.options.models,
322
+ loadTimeout: this.options.loadTimeout,
323
+ inferenceTimeout: this.options.inferenceTimeout,
324
+ warmModelTtl: this.options.warmModelTtl ?? 300_000,
325
+ });
326
+ // IPC callbacks execute after this synchronous ownership publication.
327
+ const child = Bun.spawn({
328
+ cmd: [
329
+ process.execPath,
330
+ "--no-env-file",
331
+ this.options.entryPath ?? `${import.meta.dir}/entry.ts`,
332
+ JSON.stringify(config),
333
+ ],
334
+ env: nativeWorkerEnvironment(),
335
+ stdin: "ignore",
336
+ stdout: "ignore",
337
+ stderr: "inherit",
338
+ serialization: "advanced",
339
+ ipc: (message) => this.receive(owner, message),
340
+ });
341
+ const owner: Owner = {
342
+ generation: config.generation,
343
+ child,
344
+ ledger: new NativeRequestLedger(config.generation),
345
+ decoder: new NativeFrameDecoder(config.generation),
346
+ pending: [],
347
+ foregroundCompletions: 0,
348
+ ready: false,
349
+ busy: false,
350
+ quarantined: false,
351
+ waiters: new Set(),
352
+ retiring: false,
353
+ drain: new Set(),
354
+ };
355
+ this.owner = owner;
356
+ owner.timer = setTimeout(
357
+ () => this.fail(owner, new NativeWorkerError("timeout")),
358
+ this.options.loadTimeout
359
+ );
360
+ void child.exited.then(() => {
361
+ this.fail(owner, new NativeWorkerError("exited"));
362
+ this.finishOwner(owner, new NativeWorkerError("exited"));
363
+ if (this.owner === owner) this.owner = undefined;
364
+ releaseQuarantine(owner);
365
+ });
366
+ return owner;
367
+ }
368
+
369
+ private receive(owner: Owner, message: unknown): void {
370
+ if (owner.retiring || this.owner !== owner) return;
371
+ try {
372
+ if (message === "ready") {
373
+ if (owner.ready) throw new NativeWorkerError("protocol");
374
+ owner.ready = true;
375
+ clearTimeout(owner.timer);
376
+ this.sendNext(owner);
377
+ return;
378
+ }
379
+ if (message === "idle") {
380
+ this.idleOwner = owner;
381
+ if (!this.leases && !owner.pending.length && !owner.busy)
382
+ void this.retire(owner).catch((error: unknown) =>
383
+ console.error(error)
384
+ );
385
+ return;
386
+ }
387
+ if (
388
+ typeof message === "object" &&
389
+ message !== null &&
390
+ "executionStarted" in message
391
+ ) {
392
+ const parsed = NativeExecutionStartedSchema.safeParse(message);
393
+ const pending = owner.pending[0];
394
+ if (
395
+ !parsed.success ||
396
+ !owner.busy ||
397
+ !pending ||
398
+ pending.executionStarted ||
399
+ ["init", "dispose"].includes(pending.request.op) ||
400
+ parsed.data.generation !== owner.generation ||
401
+ parsed.data.requestId !== pending.request.requestId
402
+ )
403
+ throw new NativeWorkerError("protocol");
404
+ if (
405
+ pending.loadDeadline !== undefined &&
406
+ performance.now() >= pending.loadDeadline
407
+ )
408
+ pending.settlement.cancel("timeout");
409
+ pending.loadDeadline = undefined;
410
+ pending.executionStarted = true;
411
+ clearTimeout(owner.timer);
412
+ pending.settlement.startExecution();
413
+ return;
414
+ }
415
+ if (!(message instanceof Uint8Array))
416
+ throw new NativeWorkerError("protocol");
417
+ const decoded = owner.decoder.push(message);
418
+ if (decoded === undefined) return;
419
+ const response = owner.ledger.settle(decoded);
420
+ const pending = owner.pending[0];
421
+ if (pending?.request.requestId !== response.requestId)
422
+ throw new NativeWorkerError("protocol");
423
+ clearTimeout(owner.timer);
424
+ if (
425
+ pending.loadDeadline !== undefined &&
426
+ performance.now() >= pending.loadDeadline
427
+ )
428
+ pending.settlement.cancel("timeout");
429
+ clearTimeout(pending.cancelTimer);
430
+ owner.pending.shift();
431
+ recordCompletion(owner, pending);
432
+ releaseQuarantine(owner);
433
+ if (response.lifecycle) this.lifecycle = response.lifecycle;
434
+ pending.resolve(response.result);
435
+ // Promise delivery has been queued before acknowledging settlement.
436
+ queueMicrotask(() => {
437
+ if (owner.retiring) return;
438
+ try {
439
+ owner.child.send({ ack: response.requestId });
440
+ owner.busy = false;
441
+ if (!owner.pending.length) {
442
+ for (const resolve of owner.drain) resolve();
443
+ owner.drain.clear();
444
+ }
445
+ this.sendNext(owner);
446
+ } catch {
447
+ this.fail(owner, new NativeWorkerError("exited"));
448
+ }
449
+ });
450
+ } catch (cause) {
451
+ this.fail(
452
+ owner,
453
+ cause instanceof NativeWorkerError
454
+ ? cause
455
+ : new NativeWorkerError("protocol")
456
+ );
457
+ }
458
+ }
459
+
460
+ private sendNext(owner: Owner): void {
461
+ if (!owner.ready || owner.retiring || owner.busy) return;
462
+ selectNext(owner);
463
+ const pending = owner.pending[0];
464
+ if (!pending) return;
465
+ this.idleOwner = undefined;
466
+ if (!pending.settlement.startNative()) {
467
+ this.cancel(owner, pending);
468
+ return;
469
+ }
470
+ owner.busy = true;
471
+ pending.loadDeadline = performance.now() + this.options.loadTimeout;
472
+ clearTimeout(owner.timer);
473
+ owner.timer = setTimeout(
474
+ () => pending.settlement.cancel("timeout"),
475
+ this.options.loadTimeout
476
+ );
477
+ try {
478
+ for (const frame of frameNativeMessage(pending.request))
479
+ owner.child.send(frame);
480
+ } catch {
481
+ this.fail(owner, new NativeWorkerError("exited"));
482
+ }
483
+ }
484
+
485
+ private cancel(owner: Owner, pending: Pending): void {
486
+ cancelPending(
487
+ owner,
488
+ pending,
489
+ (current, error) => this.fail(current, error),
490
+ (current) => this.sendNext(current)
491
+ );
492
+ }
493
+
494
+ private fail(owner: Owner, error: NativeWorkerError): void {
495
+ if (owner.retiring) return;
496
+ // Delivery can fail now; ownership is acknowledged only after child exit.
497
+ for (const pending of owner.pending) {
498
+ clearTimeout(pending.cancelTimer);
499
+ pending.settlement.fail(error.detail);
500
+ }
501
+ void this.retire(owner, { force: true }).catch((cause: unknown) =>
502
+ console.error(cause)
503
+ );
504
+ }
505
+
506
+ private retire(
507
+ owner: Owner,
508
+ options: NativeDisposeOptions = {}
509
+ ): Promise<void> {
510
+ return retireOwnedChild(owner, options).then(() => {
511
+ if (this.owner === owner) this.owner = undefined;
512
+ releaseQuarantine(owner);
513
+ });
514
+ }
515
+
516
+ async dispose(options: NativeDisposeOptions = {}): Promise<void> {
517
+ this.closed = true;
518
+ const owner = this.owner;
519
+ if (!owner) {
520
+ process.removeListener("exit", this.onParentExit);
521
+ return;
522
+ }
523
+ const failure = new NativeWorkerError("exited");
524
+ for (const pending of owner.pending) {
525
+ clearTimeout(pending.cancelTimer);
526
+ pending.settlement.fail(failure.detail);
527
+ }
528
+ await this.retire(owner, options);
529
+ process.removeListener("exit", this.onParentExit);
530
+ this.finishOwner(owner, failure);
531
+ }
532
+
533
+ private finishOwner(owner: Owner, failure: NativeWorkerError): void {
534
+ for (const response of owner.ledger.failAll(failure))
535
+ owner.pending
536
+ .find((entry) => entry.request.requestId === response.requestId)
537
+ ?.resolve(response.result);
538
+ owner.pending.length = 0;
539
+ owner.busy = false;
540
+ }
541
+ }