@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,442 @@
1
+ /** Internal protocol only. Dedicated IPC carries frames; stdout/stderr are diagnostics.
2
+ * Bounds reject overload, never truncate retrieval inputs or outputs. Parent selects
3
+ * and approves canonical local paths; the child must recheck filesystem identity
4
+ * before loading. No model discovery, download, policy or native imports live here.
5
+ */
6
+ import { z } from "zod";
7
+
8
+ import { NativeWorkerError } from "./errors";
9
+
10
+ export const NATIVE_PROTOCOL_VERSION = 1;
11
+ export const NATIVE_QUEUE_LIMIT = 64;
12
+ export const NATIVE_FRAME_BYTES = 8 * 1024 * 1024;
13
+ export const NATIVE_LOGICAL_BYTES = 64 * 1024 * 1024;
14
+ const id = z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
15
+ const finite = z.number().finite();
16
+ const localPath = z
17
+ .string()
18
+ .min(1)
19
+ .refine(
20
+ (path) =>
21
+ !path.includes("\0") &&
22
+ (path.startsWith("/") || /^[A-Za-z]:[\\/]/.test(path))
23
+ );
24
+
25
+ export const ApprovedModelSchema = z.strictObject({
26
+ id: z.string().min(1),
27
+ modelUri: z.string().min(1),
28
+ path: localPath,
29
+ type: z.enum(["embed", "rerank", "gen", "expand"]),
30
+ });
31
+ export type ApprovedModel = z.infer<typeof ApprovedModelSchema>;
32
+ const params = z.strictObject({
33
+ temperature: finite.optional(),
34
+ seed: finite.optional(),
35
+ maxTokens: finite.optional(),
36
+ contextSize: finite.optional(),
37
+ stop: z.array(z.string()).optional(),
38
+ jsonSchema: z.record(z.string(), z.json()).optional(),
39
+ });
40
+ const envelope = { version: z.literal(1), generation: id, requestId: id };
41
+ // AbortSignal is process-local. The deadline travels with the request; subsequent
42
+ // cancellation targets the same generation/request identity on the control lane.
43
+ const model = {
44
+ ...envelope,
45
+ modelId: z.string().min(1),
46
+ deadlineAt: z
47
+ .number()
48
+ .int()
49
+ .nonnegative()
50
+ .max(Number.MAX_SAFE_INTEGER)
51
+ .optional(),
52
+ };
53
+ export const NativeCancellationSchema = z.strictObject({
54
+ ...envelope,
55
+ cancel: z.enum(["abort", "timeout"]),
56
+ });
57
+ export type NativeCancellation = z.infer<typeof NativeCancellationSchema>;
58
+ /** Execution starts after load/context creation, never at queue admission. */
59
+ export const NativeExecutionStartedSchema = z.strictObject({
60
+ ...envelope,
61
+ executionStarted: z.literal(true),
62
+ });
63
+ export const NativeRequestSchema = z.discriminatedUnion("op", [
64
+ z.strictObject({ ...model, op: z.literal("init") }),
65
+ z.strictObject({ ...model, op: z.literal("embed"), text: z.string() }),
66
+ z.strictObject({
67
+ ...model,
68
+ op: z.literal("embedBatch"),
69
+ texts: z.array(z.string()),
70
+ }),
71
+ z.strictObject({
72
+ ...model,
73
+ op: z.literal("rerank"),
74
+ query: z.string(),
75
+ documents: z.array(z.string()),
76
+ }),
77
+ z.strictObject({
78
+ ...model,
79
+ op: z.literal("generate"),
80
+ prompt: z.string(),
81
+ params: params.optional(),
82
+ }),
83
+ z.strictObject({ ...model, op: z.literal("dispose") }),
84
+ ]);
85
+ export type NativeRequest = z.infer<typeof NativeRequestSchema>;
86
+ const error = z.strictObject({
87
+ code: z.enum([
88
+ "MODEL_NOT_FOUND",
89
+ "MODEL_NOT_CACHED",
90
+ "MODEL_DOWNLOAD_FAILED",
91
+ "MODEL_LOAD_FAILED",
92
+ "MODEL_CORRUPTED",
93
+ "INVALID_MODEL_FILE",
94
+ "MODEL_DOWNLOAD_INTERCEPTED",
95
+ "INFERENCE_FAILED",
96
+ "EGRESS_DENIED",
97
+ "TIMEOUT",
98
+ "OUT_OF_MEMORY",
99
+ "INVALID_URI",
100
+ "LOCK_FAILED",
101
+ "AUTO_DOWNLOAD_DISABLED",
102
+ "STRUCTURED_OUTPUT_UNAVAILABLE",
103
+ ]),
104
+ message: z.string(),
105
+ retryable: z.boolean(),
106
+ modelUri: z.string().optional(),
107
+ cause: z.json().optional(),
108
+ suggestion: z.string().optional(),
109
+ });
110
+ export const EmbeddingIdentitySchema = z.strictObject({
111
+ contextSize: id,
112
+ truncationPolicy: z.string().min(1),
113
+ modelFingerprint: z.string().regex(/^[a-f0-9]{64}$/),
114
+ runtimeFingerprint: z.string().regex(/^[a-f0-9]{64}$/),
115
+ });
116
+ const metadata = z.strictObject({
117
+ dimensions: id.optional(),
118
+ structuredOutput: z.enum(["json_schema", "none"]),
119
+ embeddingIdentity: EmbeddingIdentitySchema.optional(),
120
+ });
121
+ const score = z.strictObject({
122
+ index: z.number().int().nonnegative(),
123
+ score: finite,
124
+ rank: id,
125
+ });
126
+ export const NativeLifecycleStatsSchema = z.strictObject({
127
+ activeLeases: z.number().int().nonnegative(),
128
+ leaseAcquisitions: z.number().int().nonnegative(),
129
+ leaseReleases: z.number().int().nonnegative(),
130
+ loadedModels: z.number().int().nonnegative(),
131
+ loadAttempts: z.number().int().nonnegative(),
132
+ loadSuccesses: z.number().int().nonnegative(),
133
+ loadFailures: z.number().int().nonnegative(),
134
+ inflightLoads: z.number().int().nonnegative(),
135
+ });
136
+ export const NativeResponseSchema = z.strictObject({
137
+ ...envelope,
138
+ op: z.enum(["init", "embed", "embedBatch", "rerank", "generate", "dispose"]),
139
+ lifecycle: NativeLifecycleStatsSchema.optional(),
140
+ result: z.discriminatedUnion("ok", [
141
+ z.strictObject({ ok: z.literal(false), error }),
142
+ z.strictObject({
143
+ ok: z.literal(true),
144
+ value: z.union([
145
+ z.null(),
146
+ metadata,
147
+ z.string(),
148
+ z.array(finite),
149
+ z.array(z.array(finite)),
150
+ z.array(score),
151
+ ]),
152
+ }),
153
+ ]),
154
+ });
155
+ export type NativeResponse = z.infer<typeof NativeResponseSchema>;
156
+
157
+ function parse<T>(schema: z.ZodType<T>, input: unknown): T {
158
+ const parsed = schema.safeParse(input);
159
+ if (!parsed.success) throw new NativeWorkerError("protocol");
160
+ return parsed.data;
161
+ }
162
+
163
+ /** JSON size is measured in UTF-8 bytes, including escaping and envelope. */
164
+ export function encodeNativeMessage(input: unknown): Uint8Array {
165
+ let json: string | undefined;
166
+ try {
167
+ json = JSON.stringify(input);
168
+ } catch {
169
+ throw new NativeWorkerError("protocol");
170
+ }
171
+ if (json === undefined) throw new NativeWorkerError("protocol");
172
+ const bytes = new TextEncoder().encode(json);
173
+ if (bytes.length > NATIVE_LOGICAL_BYTES)
174
+ throw new NativeWorkerError("oversized");
175
+ return bytes;
176
+ }
177
+
178
+ export function parseNativeRequest(
179
+ input: unknown,
180
+ generation: number,
181
+ approved: readonly ApprovedModel[]
182
+ ): NativeRequest {
183
+ encodeNativeMessage(input);
184
+ const request = parse(NativeRequestSchema, input);
185
+ if (request.generation !== generation)
186
+ throw new NativeWorkerError("stale_generation");
187
+ const descriptor = approved.find((entry) => entry.id === request.modelId);
188
+ if (!descriptor) throw new NativeWorkerError("protocol");
189
+ parse(ApprovedModelSchema, descriptor);
190
+ const compatible =
191
+ request.op === "init" ||
192
+ request.op === "dispose" ||
193
+ (request.op === "embed" || request.op === "embedBatch"
194
+ ? descriptor.type === "embed"
195
+ : request.op === "rerank"
196
+ ? descriptor.type === "rerank"
197
+ : descriptor.type === "gen" || descriptor.type === "expand");
198
+ if (!compatible) throw new NativeWorkerError("protocol");
199
+ return request;
200
+ }
201
+
202
+ export function parseNativeResponse(
203
+ input: unknown,
204
+ request: NativeRequest
205
+ ): NativeResponse {
206
+ encodeNativeMessage(input);
207
+ const response = parse(NativeResponseSchema, input);
208
+ if (response.generation !== request.generation)
209
+ throw new NativeWorkerError("stale_generation");
210
+ if (response.requestId !== request.requestId || response.op !== request.op)
211
+ throw new NativeWorkerError("protocol");
212
+ if (!response.result.ok) return response;
213
+ const value = response.result.value;
214
+ switch (request.op) {
215
+ case "init":
216
+ parse(metadata, value);
217
+ break;
218
+ case "dispose":
219
+ parse(z.null(), value);
220
+ break;
221
+ case "generate":
222
+ parse(z.string(), value);
223
+ break;
224
+ case "embed":
225
+ parse(z.array(finite).min(1), value);
226
+ break;
227
+ case "embedBatch": {
228
+ const vectors = parse(
229
+ z.array(z.array(finite).min(1)).length(request.texts.length),
230
+ value
231
+ );
232
+ if (vectors.some((vector) => vector.length !== vectors[0]?.length))
233
+ throw new NativeWorkerError("protocol");
234
+ break;
235
+ }
236
+ case "rerank": {
237
+ const scores = parse(
238
+ z.array(score).length(request.documents.length),
239
+ value
240
+ );
241
+ if (
242
+ new Set(scores.map((entry) => entry.index)).size !== scores.length ||
243
+ new Set(scores.map((entry) => entry.rank)).size !== scores.length ||
244
+ scores.some(
245
+ (entry) => entry.index >= scores.length || entry.rank > scores.length
246
+ )
247
+ )
248
+ throw new NativeWorkerError("protocol");
249
+ break;
250
+ }
251
+ default:
252
+ throw new NativeWorkerError("protocol");
253
+ }
254
+ return response;
255
+ }
256
+
257
+ /** Binary frame header: version, generation, requestId (float64 safe integers),
258
+ * total logical bytes, byte offset (uint32). Transport preserves frame boundaries.
259
+ * One ordered logical message at a time per direction; diagnostics are never frames.
260
+ */
261
+ const HEADER_BYTES = 32;
262
+ export function frameNativeMessage(
263
+ message: NativeRequest | NativeResponse
264
+ ): Uint8Array[] {
265
+ const bytes = encodeNativeMessage(message);
266
+ const frames: Uint8Array[] = [];
267
+ for (
268
+ let offset = 0;
269
+ offset < bytes.length;
270
+ offset += NATIVE_FRAME_BYTES - HEADER_BYTES
271
+ ) {
272
+ const part = bytes.subarray(
273
+ offset,
274
+ offset + NATIVE_FRAME_BYTES - HEADER_BYTES
275
+ );
276
+ const frame = new Uint8Array(HEADER_BYTES + part.length);
277
+ const view = new DataView(frame.buffer);
278
+ view.setFloat64(0, NATIVE_PROTOCOL_VERSION);
279
+ view.setFloat64(8, message.generation);
280
+ view.setFloat64(16, message.requestId);
281
+ view.setUint32(24, bytes.length);
282
+ view.setUint32(28, offset);
283
+ frame.set(part, HEADER_BYTES);
284
+ frames.push(frame);
285
+ }
286
+ return frames;
287
+ }
288
+
289
+ export class NativeFrameDecoder {
290
+ private bytes?: Uint8Array;
291
+ private received = 0;
292
+ private requestId = 0;
293
+
294
+ constructor(private readonly generation: number) {
295
+ parse(id, generation);
296
+ }
297
+
298
+ reset(): void {
299
+ this.bytes = undefined;
300
+ this.received = 0;
301
+ this.requestId = 0;
302
+ }
303
+
304
+ push(frame: Uint8Array): unknown {
305
+ try {
306
+ return this.accept(frame);
307
+ } catch (cause) {
308
+ this.reset();
309
+ throw cause;
310
+ }
311
+ }
312
+
313
+ private accept(frame: Uint8Array): unknown {
314
+ if (frame.length <= HEADER_BYTES || frame.length > NATIVE_FRAME_BYTES)
315
+ throw new NativeWorkerError("oversized");
316
+ const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
317
+ if (view.getFloat64(0) !== NATIVE_PROTOCOL_VERSION)
318
+ throw new NativeWorkerError("protocol");
319
+ if (view.getFloat64(8) !== this.generation)
320
+ throw new NativeWorkerError("stale_generation");
321
+ const requestId = parse(id, view.getFloat64(16));
322
+ const total = view.getUint32(24);
323
+ const offset = view.getUint32(28);
324
+ const part = frame.subarray(HEADER_BYTES);
325
+ if (!total || total > NATIVE_LOGICAL_BYTES)
326
+ throw new NativeWorkerError("oversized");
327
+ if (offset !== this.received || offset + part.length > total)
328
+ throw new NativeWorkerError("protocol");
329
+ if (!this.bytes) {
330
+ this.bytes = new Uint8Array(total);
331
+ this.requestId = requestId;
332
+ }
333
+ if (this.bytes.length !== total || this.requestId !== requestId)
334
+ throw new NativeWorkerError("protocol");
335
+ this.bytes.set(part, offset);
336
+ this.received += part.length;
337
+ if (this.received !== total) return;
338
+ let decoded: unknown;
339
+ try {
340
+ decoded = JSON.parse(
341
+ new TextDecoder("utf-8", { fatal: true }).decode(this.bytes)
342
+ );
343
+ } catch {
344
+ throw new NativeWorkerError("protocol");
345
+ }
346
+ const identity = parse(z.object(envelope), decoded);
347
+ if (
348
+ identity.generation !== this.generation ||
349
+ identity.requestId !== requestId
350
+ )
351
+ throw new NativeWorkerError("protocol");
352
+ this.reset();
353
+ return decoded;
354
+ }
355
+ }
356
+
357
+ /** Split only between texts, retaining order and exact text. The complete original
358
+ * operation must fit the logical ceiling. Each part fits a single transport frame.
359
+ * Large individual texts remain intact and use byte framing instead of truncation.
360
+ */
361
+ export function splitEmbeddingRequest(
362
+ request: Extract<NativeRequest, { op: "embedBatch" }>
363
+ ): string[][] {
364
+ encodeNativeMessage(request);
365
+ const overhead = encodeNativeMessage({ ...request, texts: [] }).length;
366
+ const batches: string[][] = [];
367
+ let batch: string[] = [];
368
+ let size = overhead;
369
+ for (const text of request.texts) {
370
+ const length = encodeNativeMessage(text).length;
371
+ if (batch.length && size + length + 1 > NATIVE_FRAME_BYTES - HEADER_BYTES) {
372
+ batches.push(batch);
373
+ batch = [];
374
+ size = overhead;
375
+ }
376
+ size += length + (batch.length ? 1 : 0);
377
+ batch.push(text);
378
+ }
379
+ if (batch.length || !batches.length) batches.push(batch);
380
+ return batches;
381
+ }
382
+
383
+ /** Admission counts one active + 64 queued logical operations, never batch parts.
384
+ * Monotonic IDs prohibit reuse without an unbounded completed-ID cache. Runtime
385
+ * serializes execution and delivers each returned response once; timeout/exit drains
386
+ * pending entries, so late responses cannot resolve a replacement generation.
387
+ */
388
+ export class NativeRequestLedger {
389
+ private readonly pending = new Map<number, NativeRequest>();
390
+ private highestId = 0;
391
+ constructor(readonly generation: number) {
392
+ parse(id, generation);
393
+ }
394
+ get size(): number {
395
+ return this.pending.size;
396
+ }
397
+
398
+ admit(request: NativeRequest): void {
399
+ const snapshot = parse(NativeRequestSchema, request);
400
+ if (request.generation !== this.generation)
401
+ throw new NativeWorkerError("stale_generation");
402
+ if (request.requestId <= this.highestId)
403
+ throw new NativeWorkerError("duplicate_completion");
404
+ if (this.pending.size >= NATIVE_QUEUE_LIMIT + 1)
405
+ throw new NativeWorkerError("overloaded");
406
+ encodeNativeMessage(request);
407
+ this.highestId = request.requestId;
408
+ this.pending.set(request.requestId, snapshot);
409
+ }
410
+
411
+ /** Only the client queue owner may remove an operation never dispatched. */
412
+ cancelQueued(requestId: number): void {
413
+ if (!this.pending.delete(requestId))
414
+ throw new NativeWorkerError("protocol");
415
+ }
416
+
417
+ settle(input: unknown): NativeResponse {
418
+ const identity = parse(z.object(envelope), input);
419
+ if (identity.generation !== this.generation)
420
+ throw new NativeWorkerError("stale_generation");
421
+ const request = this.pending.get(identity.requestId);
422
+ if (!request) throw new NativeWorkerError("duplicate_completion");
423
+ const response = parseNativeResponse(input, request);
424
+ this.pending.delete(request.requestId);
425
+ return response;
426
+ }
427
+
428
+ failAll(failure: NativeWorkerError): NativeResponse[] {
429
+ const responses = Array.from(
430
+ this.pending.values(),
431
+ (request): NativeResponse => ({
432
+ version: 1,
433
+ generation: this.generation,
434
+ requestId: request.requestId,
435
+ op: request.op,
436
+ result: { ok: false, error: parse(error, failure.detail) },
437
+ })
438
+ );
439
+ this.pending.clear();
440
+ return responses;
441
+ }
442
+ }
@@ -0,0 +1,92 @@
1
+ // Bun has no synchronous canonical-directory identity API for spawn environments.
2
+ import { realpathSync, statSync } from "node:fs";
3
+ import { isAbsolute } from "node:path";
4
+ import { z } from "zod";
5
+
6
+ import type { LlmError } from "../errors";
7
+ import type { NativeResponse } from "./protocol";
8
+
9
+ import { ApprovedModelSchema, encodeNativeMessage } from "./protocol";
10
+
11
+ // Bootstrap travels in argv; controls use single IPC messages. Bound both below
12
+ // platform argv limits and far below the framed inference transport ceiling.
13
+ const CONTROL_BYTES = 16 * 1024;
14
+ function controlFits(value: unknown): boolean {
15
+ return encodeNativeMessage(value).length <= CONTROL_BYTES;
16
+ }
17
+
18
+ export function wireError(
19
+ error: LlmError
20
+ ): Extract<NativeResponse["result"], { ok: false }>["error"] {
21
+ const { cause, ...detail } = error;
22
+ const parsed = z.json().safeParse(cause);
23
+ return parsed.success ? { ...detail, cause: parsed.data } : detail;
24
+ }
25
+
26
+ /** Private launch contract. Deliberately excludes presets, stores and credentials. */
27
+ export const NativeRuntimeConfigSchema = z
28
+ .strictObject({
29
+ generation: z.number().int().positive(),
30
+ models: z.array(ApprovedModelSchema),
31
+ loadTimeout: z.number().int().min(1).max(2_147_483_647),
32
+ inferenceTimeout: z.number().int().min(1).max(2_147_483_647),
33
+ warmModelTtl: z.number().finite().nonnegative().default(300_000),
34
+ })
35
+ .refine(controlFits, "Native bootstrap exceeds control capacity")
36
+ .refine(
37
+ (config) =>
38
+ new Set(config.models.map((model) => model.id)).size ===
39
+ config.models.length,
40
+ "Duplicate native model IDs"
41
+ );
42
+ export type NativeRuntimeConfig = z.infer<typeof NativeRuntimeConfigSchema>;
43
+
44
+ export const NativeRegistrationSchema = z
45
+ .strictObject({
46
+ register: ApprovedModelSchema,
47
+ })
48
+ .refine(controlFits, "Native registration exceeds control capacity");
49
+ export const NativeAckSchema = z.strictObject({
50
+ ack: z.number().int().positive(),
51
+ });
52
+
53
+ /** Native tuning only; never inherit auth, proxy, DB or download configuration. */
54
+ export function nativeWorkerEnvironment(): Record<string, string> {
55
+ const env: Record<string, string> = {
56
+ GNO_OFFLINE: "1",
57
+ GNO_ALLOW_DOWNLOAD: "0",
58
+ GNO_LLAMA_BUILD: "never",
59
+ };
60
+ for (const key of [
61
+ "PATH",
62
+ "SystemRoot",
63
+ "WINDIR",
64
+ "TMPDIR",
65
+ "TEMP",
66
+ "TMP",
67
+ "GNO_LLAMA_GPU",
68
+ "NODE_LLAMA_CPP_GPU",
69
+ "GNO_LLAMA_INIT_TIMEOUT_MS",
70
+ "GNO_EMBED_CONTEXTS",
71
+ "GNO_EMBED_THREADS",
72
+ "GNO_EMBED_CONTEXT_SIZE",
73
+ "CUDA_VISIBLE_DEVICES",
74
+ "GGML_VK_VISIBLE_DEVICES",
75
+ ]) {
76
+ const value = process.env[key];
77
+ if (value !== undefined) env[key] = value;
78
+ }
79
+ const cudaPath = process.env.CUDA_PATH;
80
+ if (cudaPath && isAbsolute(cudaPath)) {
81
+ try {
82
+ if (
83
+ realpathSync(cudaPath) === cudaPath &&
84
+ statSync(cudaPath).isDirectory()
85
+ )
86
+ env.CUDA_PATH = cudaPath;
87
+ } catch {
88
+ /* Unvalidated native search paths never enter the child. */
89
+ }
90
+ }
91
+ return env;
92
+ }