@lincoln504/pi-research 0.1.13 → 1.0.1

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 (248) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +55 -138
  3. package/dist/cli.mjs +23375 -0
  4. package/dist/prompts/research-knowledge-relevance-triage.md +35 -0
  5. package/dist/prompts/research-knowledge-search-extractor.md +41 -0
  6. package/dist/prompts/research-tool-usage.md +92 -0
  7. package/dist/prompts/researcher.md +89 -0
  8. package/dist/prompts/system-coordinator.md +75 -0
  9. package/dist/prompts/system-lead-evaluator.md +118 -0
  10. package/dist/thread-worker.mjs +2611 -0
  11. package/dist/webgpu-probe.mjs +80 -0
  12. package/docs/AGENT-SKILL.md +130 -0
  13. package/docs/ARCHITECTURE.md +306 -80
  14. package/docs/CONFIGURATION.md +249 -0
  15. package/docs/KNOWLEDGE-STORE.md +211 -0
  16. package/docs/PI-EXTENSION.md +91 -0
  17. package/docs/SDK.md +122 -0
  18. package/docs/THIRD-PARTY-NOTICES.md +66 -0
  19. package/package.json +102 -36
  20. package/scripts/build.cjs +140 -0
  21. package/scripts/cleanup.cjs +149 -0
  22. package/scripts/prepare.cjs +28 -0
  23. package/scripts/setup.cjs +134 -0
  24. package/skills/pi-research/README.md +90 -0
  25. package/skills/pi-research/SKILL.md +102 -0
  26. package/skills/pi-research/references/configuration.md +77 -0
  27. package/skills/pi-research/scripts/run.mjs +237 -0
  28. package/src/cleanup/research-cleanup.ts +140 -0
  29. package/src/cli.ts +1195 -0
  30. package/src/config.ts +1032 -155
  31. package/src/constants.ts +115 -84
  32. package/src/core/health-check-service.ts +265 -0
  33. package/src/core/interfaces/health-check-interfaces.ts +50 -0
  34. package/src/core/interfaces/knowledge-interfaces.ts +190 -0
  35. package/src/core/interfaces/observer-interfaces.ts +67 -0
  36. package/src/core/interfaces/orchestration-interfaces.ts +86 -0
  37. package/src/core/interfaces/planning-interfaces.ts +100 -0
  38. package/src/core/interfaces/process-interfaces.ts +37 -0
  39. package/src/core/interfaces/research-plan-types.ts +52 -0
  40. package/src/core/interfaces/scheduler-interfaces.ts +91 -0
  41. package/src/core/interfaces/service-names.ts +39 -0
  42. package/src/core/interfaces/state-manager-interfaces.ts +29 -0
  43. package/src/core/interfaces/steering-interfaces.ts +31 -0
  44. package/src/core/llm/agentic-repair.ts +169 -0
  45. package/src/core/llm/inject-date.ts +52 -0
  46. package/src/core/llm/llm-timeout.ts +64 -0
  47. package/src/core/llm/llm-utils.ts +86 -0
  48. package/src/core/llm/model-registry-factory.ts +287 -0
  49. package/src/core/llm/pi-ai-completion.ts +29 -0
  50. package/src/core/llm/prompts.ts +50 -0
  51. package/src/core/llm/research-model-resolver.ts +91 -0
  52. package/src/core/planning-constants.ts +13 -0
  53. package/src/core/planning-service.ts +649 -0
  54. package/src/core/planning-utils.ts +299 -0
  55. package/src/core/scheduler-factory.ts +48 -0
  56. package/src/core/scheduler-service.ts +123 -0
  57. package/src/core/service-initialization.ts +194 -0
  58. package/src/core/service-interfaces.ts +48 -0
  59. package/src/core/service-registry.ts +659 -0
  60. package/src/healthcheck/index.ts +271 -265
  61. package/src/healthcheck/registry.ts +130 -0
  62. package/src/index.ts +639 -50
  63. package/src/infrastructure/browser/browser-cleanup.ts +309 -0
  64. package/src/infrastructure/browser/browser-client.ts +199 -0
  65. package/src/infrastructure/browser/browser-error-utils.ts +160 -0
  66. package/src/infrastructure/browser/browser-lifecycle.ts +120 -0
  67. package/src/infrastructure/browser/browser-server.ts +174 -0
  68. package/src/infrastructure/browser/browser-task-scheduler.ts +461 -0
  69. package/src/infrastructure/browser/cleanup-utils.ts +155 -0
  70. package/src/infrastructure/browser/client-agent.ts +31 -0
  71. package/src/infrastructure/browser/config.ts +288 -0
  72. package/src/infrastructure/browser/ensure-browser.ts +205 -0
  73. package/src/infrastructure/browser/index.ts +37 -0
  74. package/src/infrastructure/browser/priority-task-queue.ts +226 -0
  75. package/src/infrastructure/browser/scheduler-factory.ts +354 -0
  76. package/src/infrastructure/browser/task-execution-service.ts +209 -0
  77. package/src/infrastructure/browser/thread-worker-browser.ts +282 -0
  78. package/src/infrastructure/browser/thread-worker-lifecycle.ts +323 -0
  79. package/src/infrastructure/browser/thread-worker-messaging.ts +662 -0
  80. package/src/infrastructure/browser/thread-worker-types.ts +25 -0
  81. package/src/infrastructure/browser/thread-worker.mjs +2611 -0
  82. package/src/infrastructure/browser/thread-worker.ts +168 -0
  83. package/src/infrastructure/browser/worker-pool-manager.ts +449 -0
  84. package/src/infrastructure/embedding/embedding-client.ts +205 -0
  85. package/src/infrastructure/embedding/embedding-factory.ts +324 -0
  86. package/src/infrastructure/embedding/embedding-server.ts +535 -0
  87. package/src/infrastructure/file-lock-service.ts +592 -0
  88. package/src/infrastructure/gpu-resource-service.ts +191 -0
  89. package/src/infrastructure/knowledge-store-service.ts +475 -0
  90. package/src/infrastructure/metrics-service.ts +129 -0
  91. package/src/infrastructure/process-lifecycle-service.ts +253 -0
  92. package/src/infrastructure/scheduler-factory-service.ts +58 -0
  93. package/src/infrastructure/service-initialization.ts +292 -0
  94. package/src/infrastructure/state/state-backup-manager.ts +290 -0
  95. package/src/infrastructure/state/state-browser-api.ts +62 -0
  96. package/src/infrastructure/state/state-browser-manager.ts +70 -0
  97. package/src/infrastructure/state/state-manager-service.ts +264 -0
  98. package/src/infrastructure/state/state-manager.ts +547 -0
  99. package/src/infrastructure/state/state-metrics.ts +92 -0
  100. package/src/infrastructure/state/state-migration.ts +103 -0
  101. package/src/infrastructure/state/state-path-configuration.ts +119 -0
  102. package/src/infrastructure/state/state-session-api.ts +94 -0
  103. package/src/infrastructure/state/state-session-manager.ts +127 -0
  104. package/src/infrastructure/state/state-validator.ts +93 -0
  105. package/src/infrastructure/types/state-types.ts +85 -0
  106. package/src/knowledge/chunker.ts +157 -0
  107. package/src/knowledge/embedder-init.ts +413 -0
  108. package/src/knowledge/embedder-utils.ts +296 -0
  109. package/src/knowledge/embedder.ts +592 -0
  110. package/src/knowledge/index.ts +126 -0
  111. package/src/knowledge/lancedb-loader.ts +35 -0
  112. package/src/knowledge/migration.ts +17 -0
  113. package/src/knowledge/model-config.ts +132 -0
  114. package/src/knowledge/onnx-env.ts +48 -0
  115. package/src/knowledge/store-operations.ts +291 -0
  116. package/src/knowledge/store-schema.ts +79 -0
  117. package/src/knowledge/store.ts +1251 -0
  118. package/src/knowledge/transformers-loader.ts +31 -0
  119. package/src/knowledge/webgpu-probe.mjs +80 -0
  120. package/src/knowledge/webgpu-viability.ts +255 -0
  121. package/src/knowledge/writer-queue.ts +252 -0
  122. package/src/logger.ts +316 -122
  123. package/src/observers/research-observer-impl.ts +459 -0
  124. package/src/orchestration/deep-research-orchestrator.ts +524 -773
  125. package/src/orchestration/deep-research-types.ts +47 -35
  126. package/src/orchestration/headless-observer.ts +114 -0
  127. package/src/orchestration/orchestration-types.ts +33 -0
  128. package/src/orchestration/quick-research-orchestrator.ts +463 -0
  129. package/src/orchestration/research-orchestration-service.ts +549 -0
  130. package/src/orchestration/research-session-service.ts +178 -0
  131. package/src/orchestration/research-synthesis-service.ts +348 -0
  132. package/src/orchestration/researcher-executor.ts +394 -0
  133. package/src/orchestration/researcher.ts +115 -42
  134. package/src/orchestration/service-initialization.ts +109 -0
  135. package/src/orchestration/session-context.ts +7 -3
  136. package/src/orchestration/session-state.ts +672 -0
  137. package/src/prompts/research-knowledge-relevance-triage.md +35 -0
  138. package/src/prompts/research-knowledge-search-extractor.md +41 -0
  139. package/src/prompts/research-tool-usage.md +63 -16
  140. package/src/prompts/researcher.md +59 -136
  141. package/src/prompts/system-coordinator.md +64 -13
  142. package/src/prompts/system-lead-evaluator.md +82 -189
  143. package/src/research-config.ts +872 -0
  144. package/src/sdk.ts +847 -0
  145. package/src/security/cisa-kev.ts +72 -9
  146. package/src/security/cvss.ts +92 -0
  147. package/src/security/ecosystem.ts +45 -0
  148. package/src/security/github-advisories.ts +168 -428
  149. package/src/security/github-advisory-types.ts +282 -0
  150. package/src/security/index.ts +63 -177
  151. package/src/security/nvd-client.ts +550 -0
  152. package/src/security/nvd-types.ts +179 -0
  153. package/src/security/osv-client.ts +246 -0
  154. package/src/security/osv-types.ts +285 -0
  155. package/src/security/types.ts +67 -53
  156. package/src/skill-install/skill-installer.ts +519 -0
  157. package/src/stackexchange/index.ts +81 -27
  158. package/src/stackexchange/output/compact.ts +7 -6
  159. package/src/stackexchange/output/table.ts +11 -7
  160. package/src/stackexchange/queries.ts +0 -10
  161. package/src/stackexchange/rest-client.ts +141 -66
  162. package/src/stackexchange/types.ts +0 -17
  163. package/src/tool.ts +15 -423
  164. package/src/tools/grep.ts +32 -310
  165. package/src/tools/health-tool-definition.ts +101 -0
  166. package/src/tools/index.ts +38 -9
  167. package/src/tools/research-knowledge-search.ts +974 -0
  168. package/src/tools/research-knowledge-types.ts +77 -0
  169. package/src/tools/research-tool-definition.ts +494 -0
  170. package/src/tools/scrape.ts +286 -388
  171. package/src/tools/search.ts +98 -153
  172. package/src/tools/security.ts +107 -80
  173. package/src/tools/stackexchange.ts +58 -35
  174. package/src/tools/youtube-transcript.ts +163 -0
  175. package/src/tui/knowledge-search-panel.ts +86 -0
  176. package/src/tui/pulse.ts +86 -0
  177. package/src/tui/research-health.ts +124 -0
  178. package/src/tui/research-panel-color-utils.ts +340 -0
  179. package/src/tui/research-panel-format.ts +54 -0
  180. package/src/tui/research-panel-state.ts +404 -0
  181. package/src/tui/research-panel-wave.ts +280 -0
  182. package/src/tui/research-panel.ts +339 -435
  183. package/src/tui/research-tui-manager.ts +233 -0
  184. package/src/tui/tui-controller.ts +137 -0
  185. package/src/types/extension-context.ts +18 -49
  186. package/src/types/index.ts +61 -0
  187. package/src/types/llm.ts +68 -29
  188. package/src/types/research-panel-types.ts +61 -0
  189. package/src/utils/circuit-breaker.ts +146 -0
  190. package/src/utils/citation-utils.ts +97 -0
  191. package/src/utils/disk-space-checker.ts +55 -0
  192. package/src/utils/error-tracker.ts +265 -0
  193. package/src/utils/host-config.ts +45 -0
  194. package/src/utils/input-validation.ts +8 -10
  195. package/src/utils/json-utils.ts +150 -16
  196. package/src/utils/llm-usage.ts +54 -0
  197. package/src/utils/log-rotation.ts +125 -0
  198. package/src/utils/log-utils.ts +159 -0
  199. package/src/utils/make-resource-loader.ts +3 -1
  200. package/src/utils/metrics-summary.ts +459 -0
  201. package/src/utils/metrics.ts +302 -0
  202. package/src/utils/research-export.ts +28 -12
  203. package/src/utils/safe-unref.ts +31 -0
  204. package/src/utils/shared-links.ts +195 -90
  205. package/src/utils/shutdown-manager.ts +65 -0
  206. package/src/utils/stdio-capture.ts +407 -0
  207. package/src/utils/text-utils.ts +258 -11
  208. package/src/utils/tool-usage-tracker.ts +83 -16
  209. package/src/utils/url-utils.ts +255 -0
  210. package/src/utils/user-agent.ts +28 -0
  211. package/src/web-research/browser-search.ts +179 -0
  212. package/src/web-research/retry-utils.ts +173 -77
  213. package/src/web-research/scraper-types.ts +72 -0
  214. package/src/web-research/scraper-utils.ts +434 -0
  215. package/src/web-research/search.ts +78 -218
  216. package/src/web-research/types.ts +9 -24
  217. package/src/web-research/utils.ts +2 -143
  218. package/src/web-research/web-scraper.ts +477 -0
  219. package/src/youtube/index.ts +154 -0
  220. package/src/youtube/potoken.ts +259 -0
  221. package/src/youtube/transcript-client.ts +390 -0
  222. package/src/youtube/video-id.ts +118 -0
  223. package/config/searxng/default-settings.yml +0 -189
  224. package/config/searxng/limiter.toml +0 -34
  225. package/config/tooling/eslint.config.js +0 -73
  226. package/config/tooling/vitest.config.integration.ts +0 -17
  227. package/config/tooling/vitest.config.ts +0 -40
  228. package/config/tooling/vitest.config.unit.ts +0 -12
  229. package/docs/assets/README-banner.jpg +0 -0
  230. package/scripts/setup.js +0 -212
  231. package/src/infrastructure/searxng-lifecycle.ts +0 -644
  232. package/src/infrastructure/searxng-manager.ts +0 -1183
  233. package/src/infrastructure/state-manager.ts +0 -918
  234. package/src/orchestration/deep-research-reducer.ts +0 -129
  235. package/src/orchestration/id-utils.ts +0 -63
  236. package/src/security/nvd.ts +0 -532
  237. package/src/security/osv.ts +0 -487
  238. package/src/stackexchange/cache.ts +0 -111
  239. package/src/stackexchange/output/index.ts +0 -7
  240. package/src/stackexchange/output/json.ts +0 -21
  241. package/src/tui/searxng-status.ts +0 -80
  242. package/src/utils/inject-date.ts +0 -29
  243. package/src/utils/research-error.ts +0 -205
  244. package/src/utils/searxng-config.ts +0 -94
  245. package/src/utils/session-state.ts +0 -295
  246. package/src/web-research/dependencies.ts +0 -20
  247. package/src/web-research/scrapers.ts +0 -935
  248. package/tsconfig.json +0 -40
@@ -0,0 +1,296 @@
1
+ /**
2
+ * Embedder Utilities
3
+ *
4
+ * Utility functions for the embedder module
5
+ */
6
+
7
+ import path from 'node:path';
8
+ import * as os from 'node:os';
9
+
10
+ import { logger } from '../logger.ts';
11
+ import { withTimeout as retryWithTimeout } from '../web-research/retry-utils.ts';
12
+
13
+ import { shutdownManager } from '../utils/shutdown-manager.ts';
14
+
15
+ /**
16
+ * Timeout wrapper for promises (re-exports from retry-utils.ts)
17
+ */
18
+ export function withTimeout<T>(promise: Promise<T>, timeoutMs: number, errorMessage: string): Promise<T> {
19
+ // Normalize via Promise.resolve() to handle HuggingFace pipeline thenables
20
+ // that are not standard Promises (retry-utils calls .then() directly).
21
+ return retryWithTimeout(Promise.resolve(promise), timeoutMs, errorMessage, undefined);
22
+ }
23
+
24
+ /**
25
+ * Detect whether an embedding call failed because the embedding *leader* is
26
+ * transiently gone — a dead/stepped-down leader, a poisoned queue, or a
27
+ * connection that was reset when the leader tore down its HTTP server. In every
28
+ * case a fresh leader is immediately electable, so the caller should reconnect
29
+ * and retry rather than drop the work.
30
+ *
31
+ * Signatures, and why each must be matched:
32
+ * - "ECONNREFUSED" the leader's HTTP endpoint is gone (dead/stepped-down
33
+ * leader, or an assertServing() refusal after step-down).
34
+ * - "embedder poisoned" an in-flight/queued embed fast-failed when the leader
35
+ * poisoned its queue on a permanently-hung inference;
36
+ * this rejection carries NO ECONNREFUSED.
37
+ * - ECONNRESET / "socket hang up" / "aborted" / "other side closed":
38
+ * the leader closed the connection mid-request during an
39
+ * ORDINARY shutdown — EmbeddingServer.shutdown() calls
40
+ * closeAllConnections() not just on the poison path but on
41
+ * normal leadership loss and process teardown. Without these,
42
+ * a document in flight during a leader handoff is silently
43
+ * dropped instead of retried against the new leader.
44
+ *
45
+ * Pure string/code matching — safe to call from native-import-free modules.
46
+ */
47
+ export function isEmbedderUnreachable(err: unknown): boolean {
48
+ const code = (err as NodeJS.ErrnoException)?.code;
49
+ const msg = err instanceof Error ? err.message : String(err);
50
+ if (code === 'ECONNREFUSED' || code === 'ECONNRESET' || code === 'ECONNABORTED') return true;
51
+ return (
52
+ msg.includes('ECONNREFUSED') ||
53
+ msg.includes('ECONNRESET') ||
54
+ msg.includes('embedder poisoned') ||
55
+ msg.includes('socket hang up') ||
56
+ msg.includes('other side closed') ||
57
+ /\baborted\b/i.test(msg)
58
+ );
59
+ }
60
+
61
+ /**
62
+ * Detect whether an error indicates the native ML/vector stack is unavailable on
63
+ * this platform — i.e. a prebuilt native binding is genuinely missing, not a
64
+ * transient/logic failure. This is the case on platforms the upstream packages
65
+ * do not ship binaries for (e.g. Intel macOS / darwin-x64, where onnxruntime-node
66
+ * has no prebuilt and @lancedb/lancedb's optional native binding is absent).
67
+ *
68
+ * Such an error is a permanent capability gap, not a fault: callers should treat
69
+ * the knowledge store as DISABLED (degrade gracefully) rather than UNHEALTHY, so
70
+ * research still runs without the optional embedding/vector cache.
71
+ *
72
+ * Pure string matching — safe to call from native-import-free modules.
73
+ * Matched signatures (observed in the wild):
74
+ * - onnxruntime-node: "Cannot find module '.../bin/napi-v6/darwin/x64/onnxruntime_binding.node'"
75
+ * - @lancedb/lancedb: "Cannot find native binding. npm has a bug related to optional dependencies"
76
+ * - jiti-masked module-eval failure of the above surfaces as:
77
+ * "KnowledgeStoreService is not a constructor"
78
+ */
79
+ export function isNativeStackUnavailableError(err: unknown): boolean {
80
+ if (!err) return false;
81
+ const msg = (err instanceof Error ? `${err.message} ${err.stack ?? ''}` : String(err)).toLowerCase();
82
+
83
+ // Prefer the error CODE where present: it is stable across upstream message
84
+ // rewording, unlike the substring checks below. A failed dlopen of a native
85
+ // .node addon is unambiguously a missing/broken native binding. A
86
+ // module-not-found is only treated as a native-stack gap when it names one of
87
+ // our native packages — an unrelated missing module must NOT be misclassified
88
+ // as "this platform has no native stack".
89
+ // `err` is already known truthy (guarded above), so no `err &&` here.
90
+ const code = (typeof err === 'object' && 'code' in err) ? String((err as { code?: unknown }).code) : '';
91
+ if (code === 'ERR_DLOPEN_FAILED') return true;
92
+ if ((code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND') &&
93
+ (msg.includes('onnxruntime') || msg.includes('lancedb'))) {
94
+ return true;
95
+ }
96
+
97
+ return (
98
+ msg.includes('cannot find native binding') ||
99
+ msg.includes('onnxruntime_binding.node') ||
100
+ /cannot find module '[^']*onnxruntime/.test(msg) ||
101
+ /cannot find module '[^']*lancedb/.test(msg) ||
102
+ msg.includes('knowledgestoreservice is not a constructor')
103
+ );
104
+ }
105
+
106
+ /**
107
+ * Get the model cache directory
108
+ */
109
+ export function getModelCacheDir(): string {
110
+ // Per the XDG spec, XDG_CACHE_HOME is honored only when set to an ABSOLUTE path; an empty or
111
+ // relative value must be ignored (an empty `??`-fallback would otherwise yield a cache dir
112
+ // relative to cwd, scattering/--rm-ing models under whatever directory the process started in).
113
+ const xdgCache = process.env['XDG_CACHE_HOME'];
114
+ const base = xdgCache && path.isAbsolute(xdgCache) ? xdgCache : path.join(os.homedir(), '.cache');
115
+ return path.join(base, 'pi-research', 'models');
116
+ }
117
+
118
+ // Module-level flag to track if any embedder instance has fallen back to CPU due to WebGPU errors
119
+ // This prevents retrying with WebGPU after it's been proven to fail
120
+ let hasWebGpuFallbackOccurred = false;
121
+
122
+ /**
123
+ * Reset the WebGPU fallback flag (useful for testing or if WebGPU becomes available)
124
+ */
125
+ export function resetWebGpuFallbackFlag(): void {
126
+ hasWebGpuFallbackOccurred = false;
127
+ dawnInitialized = false; // Allow Dawn re-initialization after reset
128
+ }
129
+
130
+ /**
131
+ * Check if WebGPU fallback has occurred
132
+ */
133
+ export function hasWebGpuFallback(): boolean {
134
+ return hasWebGpuFallbackOccurred;
135
+ }
136
+
137
+ /**
138
+ * Mark that WebGPU fallback has occurred
139
+ */
140
+ export function markWebGpuFallback(): void {
141
+ hasWebGpuFallbackOccurred = true;
142
+ }
143
+
144
+ // Global embedder reference for process-exit cleanup.
145
+ let globalEmbedderRef: { dispose: () => Promise<void> } | null = null;
146
+
147
+ // Instances that have already registered a shutdown-manager task. ShutdownManager
148
+ // dedups by task IDENTITY, and each registerGlobalEmbedder call would otherwise pass a
149
+ // fresh closure — so re-registering the same instance (e.g. on the idle→active revive
150
+ // that restores globalEmbedderRef) must NOT add a second, never-removed task. The
151
+ // WeakSet lets a disposed instance be GC'd without leaking an entry.
152
+ const embeddersWithShutdownTask = new WeakSet<object>();
153
+
154
+ /**
155
+ * Register an Embedder instance for process-exit cleanup.
156
+ * Called by the Embedder constructor AND on each idle→active revive in initialize(),
157
+ * so it must be idempotent: the ref is always (re-)pointed, but the shutdown task is
158
+ * registered at most once per instance.
159
+ */
160
+ export function registerGlobalEmbedder(e: { dispose: () => Promise<void> }): void {
161
+ globalEmbedderRef = e;
162
+
163
+ if (embeddersWithShutdownTask.has(e)) return;
164
+ embeddersWithShutdownTask.add(e);
165
+
166
+ // Register with shutdown manager for graceful extension shutdown.
167
+ shutdownManager.register(async () => {
168
+ if (globalEmbedderRef === e) {
169
+ const ref = globalEmbedderRef;
170
+ globalEmbedderRef = null;
171
+ try { await ref.dispose(); } catch { /* ignore */ }
172
+ }
173
+ });
174
+ }
175
+
176
+ /**
177
+ * Unregister the global Embedder reference.
178
+ * Called by Embedder.dispose() once cleanup is complete.
179
+ */
180
+ export function unregisterGlobalEmbedder(): void {
181
+ globalEmbedderRef = null;
182
+ }
183
+
184
+ // Last-resort safety net: during beforeExit the C++ ORT LoggingManager is still
185
+ // alive, so async disposal is safe. session_shutdown should have already disposed
186
+ // the embedder; this only fires if somehow it didn't (e.g. a crash path).
187
+ // We do NOT register on 'exit' — by then C++ statics may already be destroyed.
188
+ const beforeExitHandler = () => {
189
+ if (globalEmbedderRef) {
190
+ const ref = globalEmbedderRef;
191
+ globalEmbedderRef = null;
192
+ // Fire async dispose — beforeExit allows scheduling async tasks.
193
+ ref.dispose().catch(() => {
194
+ // Silently ignore — process is shutting down, OS reclaims memory.
195
+ });
196
+ }
197
+ };
198
+
199
+ /**
200
+ * Register the beforeExit safety-net handler.
201
+ * Must be called during each extension activation because deactivate()
202
+ * strips all registered event listeners. Module-level registration is
203
+ * insufficient — after a Pi reload the handler would be missing.
204
+ */
205
+ export function registerBeforeExitSafetyNet(): void {
206
+ shutdownManager.registerEventListener(process, 'beforeExit', beforeExitHandler);
207
+ }
208
+
209
+ // ONNX / transformers.js env setup (getHFEnv, initializeONNXEnv) lives in
210
+ // ./onnx-env.ts so that this utility module stays free of the native
211
+ // @huggingface/transformers import — keeping it safe to load from src/index.ts.
212
+
213
+ let dawnInitialized = false;
214
+
215
+
216
+ /**
217
+ * Names that identify a software / paravirtual / fallback GPU adapter — i.e. one
218
+ * on which onnxruntime-node's bundled Dawn will load but then SIGSEGV during the
219
+ * first compute dispatch. Matched case-insensitively against adapter info fields.
220
+ */
221
+ const SOFTWARE_ADAPTER_PATTERNS = [
222
+ 'llvmpipe',
223
+ 'lavapipe',
224
+ 'swiftshader',
225
+ 'softpipe',
226
+ 'basic render', // "Microsoft Basic Render Driver"
227
+ 'microsoft basic',
228
+ 'software',
229
+ 'virtio', // virtio-gpu paravirtual (VMs)
230
+ 'venus', // Mesa venus (virtio-gpu Vulkan)
231
+ 'llvm',
232
+ ];
233
+
234
+ /**
235
+ * Verify WebGPU availability for the current Node.js environment.
236
+ *
237
+ * onnxruntime-node bundles Dawn natively as its WebGPU execution provider; on
238
+ * Linux this uses Vulkan. On hardware GPUs this works. On software/paravirtual
239
+ * Vulkan adapters (llvmpipe/lavapipe, virtio/venus, SwiftShader, ...) Dawn LOADS
240
+ * the pipeline but then crashes natively (SIGSEGV) on the first compute dispatch.
241
+ *
242
+ * This function is the in-process secondary guard for the FORCED 'webgpu' path
243
+ * (the 'auto' path is gated earlier by an out-of-process probe). When the
244
+ * optional 'webgpu' package is present we inspect the adapter and RETURN FALSE if
245
+ * it is a software/fallback adapter, so the caller can downgrade to CPU before
246
+ * any native compute runs. If the 'webgpu' package is absent we cannot inspect
247
+ * the adapter in-process and proceed (the out-of-process probe remains the real
248
+ * safeguard for 'auto').
249
+ *
250
+ * @returns true if WebGPU may proceed; false if a software/fallback adapter was
251
+ * detected and the caller should use CPU instead.
252
+ */
253
+ export async function initializeDawnWebGPU(): Promise<boolean> {
254
+ if (dawnInitialized) return true;
255
+
256
+ try {
257
+ // @ts-ignore — optional dependency
258
+ const { create, globals } = await import('webgpu');
259
+ Object.assign(globalThis, globals);
260
+ // Use Object.defineProperty — Node.js defines navigator as a configurable getter
261
+ Object.defineProperty(globalThis, 'navigator', {
262
+ value: { gpu: create([]) },
263
+ writable: true,
264
+ configurable: true,
265
+ });
266
+ const adapter = await (globalThis as any).navigator.gpu.requestAdapter({ powerPreference: 'high-performance' });
267
+
268
+ if (!adapter) {
269
+ logger.warn('[embedder] No WebGPU adapter available — using CPU.');
270
+ return false;
271
+ }
272
+
273
+ const info = adapter.info ?? {};
274
+ const haystack = [info.vendor, info.architecture, info.device, info.description]
275
+ .filter(Boolean)
276
+ .join(' ')
277
+ .toLowerCase();
278
+
279
+ if (adapter.isFallbackAdapter === true || SOFTWARE_ADAPTER_PATTERNS.some((p) => haystack.includes(p))) {
280
+ logger.warn(
281
+ `[embedder] WebGPU adapter is software/paravirtual (${haystack || 'fallback'}) — Dawn would crash on compute; using CPU.`,
282
+ );
283
+ return false;
284
+ }
285
+
286
+ logger.info(`[embedder] WebGPU adapter: ${info.vendor ?? '?'} ${info.device ?? info.architecture ?? '?'}`);
287
+ } catch {
288
+ // 'webgpu' package not installed — cannot inspect the adapter in-process.
289
+ // onnxruntime-node's bundled Dawn EP still works without it on real hardware;
290
+ // for 'auto' the out-of-process probe already validated viability.
291
+ }
292
+
293
+ dawnInitialized = true;
294
+ logger.info('[embedder] WebGPU ready via onnxruntime-node bundled Dawn');
295
+ return true;
296
+ }