@gmickel/gno 1.46.0 → 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 (230) 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/spa-production.json.gz +0 -0
  5. package/browser-extension/artifacts/gno-browser-clipper-v2.0.0.zip +0 -0
  6. package/browser-extension/artifacts/gno-browser-clipper-v2.0.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 +21 -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/globals.built.css +1 -1
  100. package/src/serve/public/lib/shiki-language-ids.ts +14 -0
  101. package/src/serve/resident-admission.ts +36 -36
  102. package/src/serve/resident-background-work.ts +20 -2
  103. package/src/serve/resident-request.ts +11 -5
  104. package/src/serve/resident-runtime.ts +97 -61
  105. package/src/serve/resident-shutdown.ts +153 -0
  106. package/src/serve/routes/api.ts +3 -1
  107. package/src/serve/server.ts +47 -26
  108. package/src/store/migrations/028-vector-variants.ts +54 -0
  109. package/src/store/migrations/029-graph-reference-state.ts +77 -0
  110. package/src/store/migrations/index.ts +4 -0
  111. package/src/store/sqlite/adapter.ts +251 -183
  112. package/src/store/sqlite/eligibility.ts +174 -0
  113. package/src/store/sqlite/graph-edge-application.ts +66 -0
  114. package/src/store/sqlite/graph-reference-state.ts +194 -0
  115. package/src/store/sqlite/legacy-vector-ownership.ts +79 -0
  116. package/src/store/types.ts +80 -12
  117. package/src/store/vector/eligibility.ts +36 -0
  118. package/src/store/vector/freshness.ts +33 -6
  119. package/src/store/vector/lazy.ts +81 -0
  120. package/src/store/vector/sqlite-vec.ts +106 -54
  121. package/src/store/vector/stats.ts +14 -3
  122. package/src/store/vector/types.ts +35 -2
  123. package/src/store/vector/variant-search.ts +192 -0
  124. package/src/store/vector/variants.ts +451 -0
  125. package/vendor/converters/markitdown-ts/LICENSE +21 -0
  126. package/vendor/converters/markitdown-ts/dist/index.cjs +1180 -0
  127. package/vendor/converters/markitdown-ts/dist/index.d.cts +46 -0
  128. package/vendor/converters/markitdown-ts/dist/index.d.mts +46 -0
  129. package/vendor/converters/markitdown-ts/dist/index.d.ts +46 -0
  130. package/vendor/converters/markitdown-ts/dist/index.mjs +1152 -0
  131. package/vendor/converters/markitdown-ts/package.json +77 -0
  132. package/vendor/converters/officeparser/LICENSE +21 -0
  133. package/vendor/converters/officeparser/dist/OfficeConverter.d.ts +47 -0
  134. package/vendor/converters/officeparser/dist/OfficeConverter.js +76 -0
  135. package/vendor/converters/officeparser/dist/OfficeGenerator.d.ts +23 -0
  136. package/vendor/converters/officeparser/dist/OfficeGenerator.js +73 -0
  137. package/vendor/converters/officeparser/dist/OfficeParser.d.ts +106 -0
  138. package/vendor/converters/officeparser/dist/OfficeParser.js +332 -0
  139. package/vendor/converters/officeparser/dist/cli.d.ts +28 -0
  140. package/vendor/converters/officeparser/dist/cli.js +381 -0
  141. package/vendor/converters/officeparser/dist/defaults.d.ts +41 -0
  142. package/vendor/converters/officeparser/dist/defaults.js +218 -0
  143. package/vendor/converters/officeparser/dist/generators/BaseGenerator.d.ts +107 -0
  144. package/vendor/converters/officeparser/dist/generators/BaseGenerator.js +248 -0
  145. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.d.ts +82 -0
  146. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.js +797 -0
  147. package/vendor/converters/officeparser/dist/generators/CsvGenerator.d.ts +38 -0
  148. package/vendor/converters/officeparser/dist/generators/CsvGenerator.js +245 -0
  149. package/vendor/converters/officeparser/dist/generators/EpubGenerator.d.ts +43 -0
  150. package/vendor/converters/officeparser/dist/generators/EpubGenerator.js +315 -0
  151. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.d.ts +59 -0
  152. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.js +1942 -0
  153. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.d.ts +96 -0
  154. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.js +1175 -0
  155. package/vendor/converters/officeparser/dist/generators/PdfGenerator.d.ts +22 -0
  156. package/vendor/converters/officeparser/dist/generators/PdfGenerator.js +194 -0
  157. package/vendor/converters/officeparser/dist/generators/RtfGenerator.d.ts +29 -0
  158. package/vendor/converters/officeparser/dist/generators/RtfGenerator.js +316 -0
  159. package/vendor/converters/officeparser/dist/generators/TextGenerator.d.ts +13 -0
  160. package/vendor/converters/officeparser/dist/generators/TextGenerator.js +201 -0
  161. package/vendor/converters/officeparser/dist/index.d.ts +60 -0
  162. package/vendor/converters/officeparser/dist/index.js +72 -0
  163. package/vendor/converters/officeparser/dist/index.mjs +18 -0
  164. package/vendor/converters/officeparser/dist/officeparser.browser.d.ts +2621 -0
  165. package/vendor/converters/officeparser/dist/officeparser.browser.iife.js +1336 -0
  166. package/vendor/converters/officeparser/dist/officeparser.browser.mjs +1335 -0
  167. package/vendor/converters/officeparser/dist/officeparser.browser.slim.d.ts +2621 -0
  168. package/vendor/converters/officeparser/dist/officeparser.browser.slim.iife.js +1336 -0
  169. package/vendor/converters/officeparser/dist/officeparser.browser.slim.mjs +1335 -0
  170. package/vendor/converters/officeparser/dist/parsers/CsvParser.d.ts +9 -0
  171. package/vendor/converters/officeparser/dist/parsers/CsvParser.js +115 -0
  172. package/vendor/converters/officeparser/dist/parsers/EpubParser.d.ts +8 -0
  173. package/vendor/converters/officeparser/dist/parsers/EpubParser.js +217 -0
  174. package/vendor/converters/officeparser/dist/parsers/ExcelParser.d.ts +32 -0
  175. package/vendor/converters/officeparser/dist/parsers/ExcelParser.js +736 -0
  176. package/vendor/converters/officeparser/dist/parsers/HtmlParser.d.ts +2 -0
  177. package/vendor/converters/officeparser/dist/parsers/HtmlParser.js +1287 -0
  178. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.d.ts +2 -0
  179. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.js +1272 -0
  180. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.d.ts +31 -0
  181. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.js +1819 -0
  182. package/vendor/converters/officeparser/dist/parsers/PdfParser.d.ts +67 -0
  183. package/vendor/converters/officeparser/dist/parsers/PdfParser.js +848 -0
  184. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.d.ts +32 -0
  185. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.js +950 -0
  186. package/vendor/converters/officeparser/dist/parsers/RtfParser.d.ts +187 -0
  187. package/vendor/converters/officeparser/dist/parsers/RtfParser.js +1801 -0
  188. package/vendor/converters/officeparser/dist/parsers/WordParser.d.ts +79 -0
  189. package/vendor/converters/officeparser/dist/parsers/WordParser.js +1177 -0
  190. package/vendor/converters/officeparser/dist/sbom.cdx.json +1763 -0
  191. package/vendor/converters/officeparser/dist/types.d.ts +2507 -0
  192. package/vendor/converters/officeparser/dist/types.js +107 -0
  193. package/vendor/converters/officeparser/dist/utils/astUtils.d.ts +16 -0
  194. package/vendor/converters/officeparser/dist/utils/astUtils.js +33 -0
  195. package/vendor/converters/officeparser/dist/utils/chartUtils.d.ts +6 -0
  196. package/vendor/converters/officeparser/dist/utils/chartUtils.js +257 -0
  197. package/vendor/converters/officeparser/dist/utils/configUtils.d.ts +44 -0
  198. package/vendor/converters/officeparser/dist/utils/configUtils.js +315 -0
  199. package/vendor/converters/officeparser/dist/utils/dateUtils.d.ts +17 -0
  200. package/vendor/converters/officeparser/dist/utils/dateUtils.js +69 -0
  201. package/vendor/converters/officeparser/dist/utils/envUtils.d.ts +29 -0
  202. package/vendor/converters/officeparser/dist/utils/envUtils.js +152 -0
  203. package/vendor/converters/officeparser/dist/utils/errorUtils.d.ts +72 -0
  204. package/vendor/converters/officeparser/dist/utils/errorUtils.js +245 -0
  205. package/vendor/converters/officeparser/dist/utils/imageUtils.d.ts +66 -0
  206. package/vendor/converters/officeparser/dist/utils/imageUtils.js +133 -0
  207. package/vendor/converters/officeparser/dist/utils/mathUtils.d.ts +42 -0
  208. package/vendor/converters/officeparser/dist/utils/mathUtils.js +385 -0
  209. package/vendor/converters/officeparser/dist/utils/moduleLoader.d.ts +18 -0
  210. package/vendor/converters/officeparser/dist/utils/moduleLoader.js +106 -0
  211. package/vendor/converters/officeparser/dist/utils/ocrUtils.d.ts +42 -0
  212. package/vendor/converters/officeparser/dist/utils/ocrUtils.js +428 -0
  213. package/vendor/converters/officeparser/dist/utils/sanitize.d.ts +148 -0
  214. package/vendor/converters/officeparser/dist/utils/sanitize.js +344 -0
  215. package/vendor/converters/officeparser/dist/utils/sheetUtils.d.ts +7 -0
  216. package/vendor/converters/officeparser/dist/utils/sheetUtils.js +35 -0
  217. package/vendor/converters/officeparser/dist/utils/styleMapper.d.ts +36 -0
  218. package/vendor/converters/officeparser/dist/utils/styleMapper.js +224 -0
  219. package/vendor/converters/officeparser/dist/utils/xmlUtils.d.ts +163 -0
  220. package/vendor/converters/officeparser/dist/utils/xmlUtils.js +461 -0
  221. package/vendor/converters/officeparser/dist/utils/zipUtils.d.ts +134 -0
  222. package/vendor/converters/officeparser/dist/utils/zipUtils.js +337 -0
  223. package/vendor/converters/officeparser/package.json +147 -0
  224. package/vendor/converters/upstream-manifest.json +124 -0
  225. package/vendor/dependency-fixes/README.md +77 -0
  226. package/vendor/dependency-fixes/vendor-converters.py +83 -0
  227. package/browser-extension/artifacts/gno-browser-clipper-v1.46.0.zip +0 -0
  228. package/browser-extension/artifacts/gno-browser-clipper-v1.46.0.zip.sha256 +0 -1
  229. package/browser-extension/dist/chunk-627emwpj.js +0 -75
  230. /package/browser-extension/dist/{chunk-ydfx5d7p.css → chunk-z74y8n8c.css} +0 -0
@@ -0,0 +1,141 @@
1
+ import type { InferenceSettlement } from "../inference-cancellation";
2
+ import type { LlmResult } from "../types";
3
+ import type { OwnedExitControl } from "./owned-exit";
4
+ import type {
5
+ NativeRequest,
6
+ NativeResponse,
7
+ NativeRequestLedger,
8
+ NativeFrameDecoder,
9
+ } from "./protocol";
10
+
11
+ import { NativeWorkerError } from "./errors";
12
+ import { NATIVE_QUEUE_LIMIT } from "./protocol";
13
+ import { wireError } from "./runtime-config";
14
+
15
+ export function wireResult(
16
+ result: LlmResult<Extract<NativeResponse["result"], { ok: true }>["value"]>
17
+ ): NativeResponse["result"] {
18
+ return result.ok ? result : { ok: false, error: wireError(result.error) };
19
+ }
20
+
21
+ type Child = ReturnType<typeof Bun.spawn>;
22
+ export interface Pending {
23
+ background: boolean;
24
+ request: NativeRequest;
25
+ settlement: InferenceSettlement<
26
+ Extract<NativeResponse["result"], { ok: true }>["value"]
27
+ >;
28
+ resolve(value: NativeResponse["result"]): void;
29
+ executionStarted?: boolean;
30
+ loadDeadline?: number;
31
+ cancelTimer?: ReturnType<typeof setTimeout>;
32
+ }
33
+ export interface Owner {
34
+ foregroundCompletions: number;
35
+ generation: number;
36
+ child: Child;
37
+ ledger: NativeRequestLedger;
38
+ decoder: NativeFrameDecoder;
39
+ pending: Pending[];
40
+ ready: boolean;
41
+ busy: boolean;
42
+ quarantined: boolean;
43
+ waiters: Set<() => void>;
44
+ retiring: boolean;
45
+ timer?: ReturnType<typeof setTimeout>;
46
+ retirement?: Promise<void>;
47
+ retirementControl?: OwnedExitControl;
48
+ drain: Set<() => void>;
49
+ }
50
+
51
+ /** Only waiting work may move; the active request remains pending[0] through ACK. */
52
+ export function selectNext(owner: Owner): void {
53
+ if (owner.busy) return;
54
+ const backgroundIndex = owner.pending.findIndex((entry) => entry.background);
55
+ const foregroundIndex = owner.pending.findIndex((entry) => !entry.background);
56
+ const index =
57
+ backgroundIndex >= 0 &&
58
+ (foregroundIndex < 0 || owner.foregroundCompletions >= 8)
59
+ ? backgroundIndex
60
+ : foregroundIndex;
61
+ if (index > 0) owner.pending.unshift(owner.pending.splice(index, 1)[0]!);
62
+ }
63
+
64
+ export function recordCompletion(owner: Owner, pending: Pending): void {
65
+ // Metadata prepares a batch but does not perform inference or pay its debt.
66
+ if (pending.request.op === "init" || pending.request.op === "dispose") return;
67
+ if (pending.background) owner.foregroundCompletions = 0;
68
+ else if (owner.pending.some((entry) => entry.background))
69
+ owner.foregroundCompletions = Math.min(8, owner.foregroundCompletions + 1);
70
+ // Preserve earned service across a metadata/partition preparation gap. Only
71
+ // actual background inference pays it; an empty queue is not completed work.
72
+ }
73
+ export function cancelPending(
74
+ owner: Owner,
75
+ pending: Pending,
76
+ fail: (owner: Owner, error: NativeWorkerError) => void,
77
+ sendNext: (owner: Owner) => void
78
+ ): void {
79
+ const index = owner.pending.indexOf(pending);
80
+ if (index < 0 || owner.retiring) return;
81
+ if (index === 0 && owner.busy) {
82
+ owner.quarantined = true;
83
+ clearTimeout(owner.timer);
84
+ try {
85
+ owner.child.send({
86
+ version: 1,
87
+ generation: owner.generation,
88
+ requestId: pending.request.requestId,
89
+ cancel:
90
+ pending.settlement.signal.reason?.name === "TimeoutError"
91
+ ? "timeout"
92
+ : "abort",
93
+ });
94
+ } catch {
95
+ fail(owner, new NativeWorkerError("exited"));
96
+ return;
97
+ }
98
+ // This owner runs exactly one native operation. Quarantine it until that
99
+ // operation settles; after grace, only this owned child may be retired.
100
+ pending.cancelTimer = setTimeout(
101
+ () => fail(owner, new NativeWorkerError("timeout")),
102
+ 5000
103
+ );
104
+ } else {
105
+ owner.pending.splice(index, 1);
106
+ owner.ledger.cancelQueued(pending.request.requestId);
107
+ void pending.settlement.completion.then((result) =>
108
+ pending.resolve(wireResult(result))
109
+ );
110
+ if (!owner.busy) {
111
+ if (!owner.pending.length) {
112
+ for (const resolve of owner.drain) resolve();
113
+ owner.drain.clear();
114
+ }
115
+ sendNext(owner);
116
+ }
117
+ }
118
+ }
119
+
120
+ /** Admission remains bounded while a canceled owner cannot accept new work. */
121
+ export function waitForQuarantine(
122
+ owner: Owner,
123
+ settlement: Pending["settlement"]
124
+ ): Promise<void> {
125
+ if (owner.ledger.size + owner.waiters.size >= NATIVE_QUEUE_LIMIT + 1)
126
+ throw new NativeWorkerError("overloaded");
127
+ return new Promise((resolve) => {
128
+ const finish = () => {
129
+ owner.waiters.delete(finish);
130
+ settlement.signal.removeEventListener("abort", finish);
131
+ resolve();
132
+ };
133
+ owner.waiters.add(finish);
134
+ settlement.signal.addEventListener("abort", finish, { once: true });
135
+ if (settlement.signal.aborted) finish();
136
+ });
137
+ }
138
+ export function releaseQuarantine(owner: Owner): void {
139
+ owner.quarantined = false;
140
+ for (const finish of owner.waiters) finish();
141
+ }
@@ -0,0 +1,317 @@
1
+ import { z } from "zod";
2
+
3
+ import type { InferenceOptions } from "../types";
4
+ import type {
5
+ EmbeddingPort,
6
+ EmbeddingIdentity,
7
+ GenerationPort,
8
+ GenParams,
9
+ LlmResult,
10
+ RerankPort,
11
+ RerankScore,
12
+ } from "../types";
13
+ import type { NativeWorkerClient } from "./client";
14
+ import type { NativeResponse } from "./protocol";
15
+
16
+ import { inferenceOptions, finishInferenceCleanup } from "../inference-scope";
17
+ import { NativeWorkerError } from "./errors";
18
+ import { EmbeddingIdentitySchema } from "./protocol";
19
+
20
+ const vector = z.array(z.number().finite()).min(1);
21
+ const scores = z.array(
22
+ z.strictObject({
23
+ index: z.number().int().nonnegative(),
24
+ score: z.number().finite(),
25
+ rank: z.number().int().positive(),
26
+ })
27
+ );
28
+ const metadata = z.object({
29
+ dimensions: z.number().int().positive(),
30
+ embeddingIdentity: EmbeddingIdentitySchema,
31
+ });
32
+
33
+ function decode<T>(
34
+ result: NativeResponse["result"],
35
+ schema: z.ZodType<T>
36
+ ): LlmResult<T> {
37
+ if (!result.ok) return result;
38
+ const parsed = schema.safeParse(result.value);
39
+ return parsed.success
40
+ ? { ok: true, value: parsed.data }
41
+ : { ok: false, error: new NativeWorkerError("protocol").detail };
42
+ }
43
+
44
+ class NativePort {
45
+ constructor(
46
+ protected readonly client: NativeWorkerClient,
47
+ protected readonly modelId: string,
48
+ readonly modelUri: string
49
+ ) {}
50
+
51
+ async dispose(): Promise<void> {
52
+ // Disposing an unused/retired port must not launch a child.
53
+ if (this.client.processId === undefined) return;
54
+ return finishInferenceCleanup(async () => {
55
+ const result = await this.client.request({
56
+ op: "dispose",
57
+ modelId: this.modelId,
58
+ });
59
+ if (!result.ok) throw new Error(result.error.message);
60
+ });
61
+ }
62
+ }
63
+
64
+ /** Metadata and complete vectors cross IPC; no tokenizer/native objects in parent. */
65
+ export class NativeEmbeddingPort extends NativePort implements EmbeddingPort {
66
+ private dims: number | undefined;
67
+ private generation = 0;
68
+ private identity?: EmbeddingIdentity;
69
+ private initializing?: Promise<LlmResult<void>>;
70
+ private version = 0;
71
+ private disposing = false;
72
+
73
+ async init(options?: InferenceOptions): Promise<LlmResult<void>> {
74
+ return this.withIdentity(
75
+ async () => ({ ok: true, value: undefined }),
76
+ options
77
+ );
78
+ }
79
+
80
+ private async loadIdentity(
81
+ version: number,
82
+ options?: InferenceOptions
83
+ ): Promise<LlmResult<void>> {
84
+ const result = decode(
85
+ await this.client.request(
86
+ { op: "init", modelId: this.modelId },
87
+ undefined,
88
+ options
89
+ ),
90
+ metadata
91
+ );
92
+ if (!result.ok) return result;
93
+ if (
94
+ version !== this.version ||
95
+ this.disposing ||
96
+ this.client.processId === undefined
97
+ )
98
+ return {
99
+ ok: false,
100
+ error: new NativeWorkerError("stale_generation").detail,
101
+ };
102
+ this.dims = result.value.dimensions;
103
+ this.identity = result.value.embeddingIdentity;
104
+ this.generation = this.client.currentGeneration;
105
+ return { ok: true, value: undefined };
106
+ }
107
+
108
+ private async ensureIdentity(
109
+ options?: InferenceOptions
110
+ ): Promise<LlmResult<void>> {
111
+ if (this.getIdentity()) return { ok: true, value: undefined };
112
+ if (options?.signal || options?.deadlineAt !== undefined)
113
+ return this.loadIdentity(this.version, options);
114
+ if (this.initializing) return this.initializing;
115
+ this.identity = undefined;
116
+ this.dims = undefined;
117
+ const pending = this.loadIdentity(this.version);
118
+ this.initializing = pending;
119
+ try {
120
+ return await pending;
121
+ } finally {
122
+ if (this.initializing === pending) this.initializing = undefined;
123
+ }
124
+ }
125
+
126
+ private async withIdentity<T>(
127
+ operation: (generation: number) => Promise<LlmResult<T>>,
128
+ options?: InferenceOptions
129
+ ): Promise<LlmResult<T>> {
130
+ let lease: { release(): void } | undefined;
131
+ const version = this.version;
132
+ try {
133
+ lease = this.client.acquireLease();
134
+ if (this.disposing)
135
+ return {
136
+ ok: false,
137
+ error: new NativeWorkerError("stale_generation").detail,
138
+ };
139
+ options = inferenceOptions(options);
140
+ const initialized = await this.ensureIdentity(options);
141
+ if (!initialized.ok) return initialized;
142
+ if (version !== this.version || this.disposing)
143
+ return {
144
+ ok: false,
145
+ error: new NativeWorkerError("stale_generation").detail,
146
+ };
147
+ const generation = this.generation;
148
+ const identity = this.identity;
149
+ const result = await operation(generation);
150
+ if (!result.ok) {
151
+ this.identity = undefined;
152
+ return result;
153
+ }
154
+ if (
155
+ version !== this.version ||
156
+ generation !== this.client.currentGeneration ||
157
+ this.client.processId === undefined
158
+ ) {
159
+ this.identity = undefined;
160
+ return {
161
+ ok: false,
162
+ error: new NativeWorkerError("stale_generation").detail,
163
+ };
164
+ }
165
+ this.identity = identity;
166
+ return result;
167
+ } catch (cause) {
168
+ this.identity = undefined;
169
+ return {
170
+ ok: false,
171
+ error: (cause instanceof NativeWorkerError
172
+ ? cause
173
+ : new NativeWorkerError("exited")
174
+ ).detail,
175
+ };
176
+ } finally {
177
+ lease?.release();
178
+ }
179
+ }
180
+
181
+ private acceptDimensions(length: number): boolean {
182
+ return (
183
+ this.generation === this.client.currentGeneration && this.dims === length
184
+ );
185
+ }
186
+
187
+ async embed(
188
+ text: string,
189
+ options?: InferenceOptions
190
+ ): Promise<LlmResult<number[]>> {
191
+ return this.withIdentity(async (generation) => {
192
+ const result = decode(
193
+ await this.client.request(
194
+ { op: "embed", modelId: this.modelId, text },
195
+ generation,
196
+ options
197
+ ),
198
+ vector
199
+ );
200
+ if (result.ok && !this.acceptDimensions(result.value.length)) {
201
+ await this.client.disposeModel(this.modelUri);
202
+ return { ok: false, error: new NativeWorkerError("protocol").detail };
203
+ }
204
+ return result;
205
+ }, options);
206
+ }
207
+
208
+ async embedBatch(
209
+ texts: string[],
210
+ options?: InferenceOptions
211
+ ): Promise<LlmResult<number[][]>> {
212
+ if (!texts.length) return { ok: true, value: [] };
213
+ return this.withIdentity(async (generation) => {
214
+ const result = decode(
215
+ await this.client.request(
216
+ {
217
+ op: "embedBatch",
218
+ modelId: this.modelId,
219
+ texts,
220
+ },
221
+ generation,
222
+ options
223
+ ),
224
+ z.array(vector).length(texts.length)
225
+ );
226
+ if (
227
+ result.ok &&
228
+ result.value.some((item) => !this.acceptDimensions(item.length))
229
+ ) {
230
+ await this.client.disposeModel(this.modelUri);
231
+ return { ok: false, error: new NativeWorkerError("protocol").detail };
232
+ }
233
+ return result;
234
+ }, options);
235
+ }
236
+
237
+ dimensions(): number {
238
+ if (this.dims === undefined)
239
+ throw new Error("Call init() or embed() first to initialize dimensions");
240
+ return this.dims;
241
+ }
242
+
243
+ getIdentity(): EmbeddingIdentity | undefined {
244
+ if (
245
+ this.generation !== this.client.currentGeneration ||
246
+ this.client.processId === undefined ||
247
+ this.disposing
248
+ )
249
+ return;
250
+ return this.identity && { ...this.identity };
251
+ }
252
+
253
+ override async dispose(): Promise<void> {
254
+ this.version++;
255
+ this.disposing = true;
256
+ this.initializing = undefined;
257
+ this.dims = undefined;
258
+ this.identity = undefined;
259
+ try {
260
+ await super.dispose();
261
+ } finally {
262
+ this.disposing = false;
263
+ }
264
+ }
265
+ }
266
+
267
+ export class NativeGenerationPort extends NativePort implements GenerationPort {
268
+ readonly structuredOutput = "json_schema" as const;
269
+
270
+ async generate(
271
+ prompt: string,
272
+ params?: GenParams,
273
+ options?: InferenceOptions
274
+ ): Promise<LlmResult<string>> {
275
+ const schema = z
276
+ .record(z.string(), z.json())
277
+ .optional()
278
+ .safeParse(params?.jsonSchema);
279
+ if (!schema.success)
280
+ return { ok: false, error: new NativeWorkerError("protocol").detail };
281
+ return decode(
282
+ await this.client.request(
283
+ {
284
+ op: "generate",
285
+ modelId: this.modelId,
286
+ prompt,
287
+ params: params && { ...params, jsonSchema: schema.data },
288
+ },
289
+ undefined,
290
+ options
291
+ ),
292
+ z.string()
293
+ );
294
+ }
295
+ }
296
+
297
+ export class NativeRerankPort extends NativePort implements RerankPort {
298
+ async rerank(
299
+ query: string,
300
+ documents: string[],
301
+ options?: InferenceOptions
302
+ ): Promise<LlmResult<RerankScore[]>> {
303
+ return decode(
304
+ await this.client.request(
305
+ {
306
+ op: "rerank",
307
+ modelId: this.modelId,
308
+ query,
309
+ documents,
310
+ },
311
+ undefined,
312
+ options
313
+ ),
314
+ scores.length(documents.length)
315
+ );
316
+ }
317
+ }