nodedex 0.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 (469) hide show
  1. package/adapters/claude-code-watcher.mjs +336 -0
  2. package/adapters/hermes-statedb-watcher.mjs +234 -0
  3. package/adapters/nodedex-capture-core.mjs +129 -0
  4. package/adapters/nodedex-capture.mjs +169 -0
  5. package/dist/agent-protocol.d.ts +7 -0
  6. package/dist/agent-protocol.d.ts.map +1 -0
  7. package/dist/agent-protocol.js +38 -0
  8. package/dist/agent-protocol.js.map +1 -0
  9. package/dist/api-server.d.ts +5 -0
  10. package/dist/api-server.d.ts.map +1 -0
  11. package/dist/api-server.js +351 -0
  12. package/dist/api-server.js.map +1 -0
  13. package/dist/boot-env.d.ts +2 -0
  14. package/dist/boot-env.d.ts.map +1 -0
  15. package/dist/boot-env.js +12 -0
  16. package/dist/boot-env.js.map +1 -0
  17. package/dist/engine/__tests__/search-core.test.d.ts +2 -0
  18. package/dist/engine/__tests__/search-core.test.d.ts.map +1 -0
  19. package/dist/engine/__tests__/search-core.test.js +139 -0
  20. package/dist/engine/__tests__/search-core.test.js.map +1 -0
  21. package/dist/engine/ai-provider.d.ts +45 -0
  22. package/dist/engine/ai-provider.d.ts.map +1 -0
  23. package/dist/engine/ai-provider.js +5 -0
  24. package/dist/engine/ai-provider.js.map +1 -0
  25. package/dist/engine/embeddings.d.ts +51 -0
  26. package/dist/engine/embeddings.d.ts.map +1 -0
  27. package/dist/engine/embeddings.js +89 -0
  28. package/dist/engine/embeddings.js.map +1 -0
  29. package/dist/engine/providers/__tests__/failure-policy.test.d.ts +2 -0
  30. package/dist/engine/providers/__tests__/failure-policy.test.d.ts.map +1 -0
  31. package/dist/engine/providers/__tests__/failure-policy.test.js +134 -0
  32. package/dist/engine/providers/__tests__/failure-policy.test.js.map +1 -0
  33. package/dist/engine/providers/__tests__/model-caps.test.d.ts +2 -0
  34. package/dist/engine/providers/__tests__/model-caps.test.d.ts.map +1 -0
  35. package/dist/engine/providers/__tests__/model-caps.test.js +38 -0
  36. package/dist/engine/providers/__tests__/model-caps.test.js.map +1 -0
  37. package/dist/engine/providers/__tests__/openai-structured.test.d.ts +2 -0
  38. package/dist/engine/providers/__tests__/openai-structured.test.d.ts.map +1 -0
  39. package/dist/engine/providers/__tests__/openai-structured.test.js +73 -0
  40. package/dist/engine/providers/__tests__/openai-structured.test.js.map +1 -0
  41. package/dist/engine/providers/__tests__/usage-ledger.test.d.ts +2 -0
  42. package/dist/engine/providers/__tests__/usage-ledger.test.d.ts.map +1 -0
  43. package/dist/engine/providers/__tests__/usage-ledger.test.js +108 -0
  44. package/dist/engine/providers/__tests__/usage-ledger.test.js.map +1 -0
  45. package/dist/engine/providers/anthropic.d.ts +17 -0
  46. package/dist/engine/providers/anthropic.d.ts.map +1 -0
  47. package/dist/engine/providers/anthropic.js +125 -0
  48. package/dist/engine/providers/anthropic.js.map +1 -0
  49. package/dist/engine/providers/failure-policy.d.ts +56 -0
  50. package/dist/engine/providers/failure-policy.d.ts.map +1 -0
  51. package/dist/engine/providers/failure-policy.js +120 -0
  52. package/dist/engine/providers/failure-policy.js.map +1 -0
  53. package/dist/engine/providers/gemini.d.ts +22 -0
  54. package/dist/engine/providers/gemini.d.ts.map +1 -0
  55. package/dist/engine/providers/gemini.js +180 -0
  56. package/dist/engine/providers/gemini.js.map +1 -0
  57. package/dist/engine/providers/index.d.ts +8 -0
  58. package/dist/engine/providers/index.d.ts.map +1 -0
  59. package/dist/engine/providers/index.js +67 -0
  60. package/dist/engine/providers/index.js.map +1 -0
  61. package/dist/engine/providers/local.d.ts +12 -0
  62. package/dist/engine/providers/local.d.ts.map +1 -0
  63. package/dist/engine/providers/local.js +46 -0
  64. package/dist/engine/providers/local.js.map +1 -0
  65. package/dist/engine/providers/model-caps.d.ts +6 -0
  66. package/dist/engine/providers/model-caps.d.ts.map +1 -0
  67. package/dist/engine/providers/model-caps.js +49 -0
  68. package/dist/engine/providers/model-caps.js.map +1 -0
  69. package/dist/engine/providers/openai.d.ts +30 -0
  70. package/dist/engine/providers/openai.d.ts.map +1 -0
  71. package/dist/engine/providers/openai.js +309 -0
  72. package/dist/engine/providers/openai.js.map +1 -0
  73. package/dist/engine/providers/usage-ledger.d.ts +69 -0
  74. package/dist/engine/providers/usage-ledger.d.ts.map +1 -0
  75. package/dist/engine/providers/usage-ledger.js +209 -0
  76. package/dist/engine/providers/usage-ledger.js.map +1 -0
  77. package/dist/engine/search-core.d.ts +40 -0
  78. package/dist/engine/search-core.d.ts.map +1 -0
  79. package/dist/engine/search-core.js +109 -0
  80. package/dist/engine/search-core.js.map +1 -0
  81. package/dist/engine/vector-math.d.ts +5 -0
  82. package/dist/engine/vector-math.d.ts.map +1 -0
  83. package/dist/engine/vector-math.js +25 -0
  84. package/dist/engine/vector-math.js.map +1 -0
  85. package/dist/home-env.d.ts +26 -0
  86. package/dist/home-env.d.ts.map +1 -0
  87. package/dist/home-env.js +87 -0
  88. package/dist/home-env.js.map +1 -0
  89. package/dist/mcp-server.d.ts +13 -0
  90. package/dist/mcp-server.d.ts.map +1 -0
  91. package/dist/mcp-server.js +79 -0
  92. package/dist/mcp-server.js.map +1 -0
  93. package/dist/middleware/auth.d.ts +23 -0
  94. package/dist/middleware/auth.d.ts.map +1 -0
  95. package/dist/middleware/auth.js +104 -0
  96. package/dist/middleware/auth.js.map +1 -0
  97. package/dist/middleware/auto-recall.d.ts +7 -0
  98. package/dist/middleware/auto-recall.d.ts.map +1 -0
  99. package/dist/middleware/auto-recall.js +257 -0
  100. package/dist/middleware/auto-recall.js.map +1 -0
  101. package/dist/middleware/auto-reflect.d.ts +4 -0
  102. package/dist/middleware/auto-reflect.d.ts.map +1 -0
  103. package/dist/middleware/auto-reflect.js +5 -0
  104. package/dist/middleware/auto-reflect.js.map +1 -0
  105. package/dist/middleware/reflect/apply-flag-verdict.d.ts +27 -0
  106. package/dist/middleware/reflect/apply-flag-verdict.d.ts.map +1 -0
  107. package/dist/middleware/reflect/apply-flag-verdict.js +57 -0
  108. package/dist/middleware/reflect/apply-flag-verdict.js.map +1 -0
  109. package/dist/middleware/reflect/arc-entity-resolve.d.ts +29 -0
  110. package/dist/middleware/reflect/arc-entity-resolve.d.ts.map +1 -0
  111. package/dist/middleware/reflect/arc-entity-resolve.js +356 -0
  112. package/dist/middleware/reflect/arc-entity-resolve.js.map +1 -0
  113. package/dist/middleware/reflect/arc-inactivity-timer.d.ts +47 -0
  114. package/dist/middleware/reflect/arc-inactivity-timer.d.ts.map +1 -0
  115. package/dist/middleware/reflect/arc-inactivity-timer.js +175 -0
  116. package/dist/middleware/reflect/arc-inactivity-timer.js.map +1 -0
  117. package/dist/middleware/reflect/arc-pipeline.d.ts +33 -0
  118. package/dist/middleware/reflect/arc-pipeline.d.ts.map +1 -0
  119. package/dist/middleware/reflect/arc-pipeline.js +498 -0
  120. package/dist/middleware/reflect/arc-pipeline.js.map +1 -0
  121. package/dist/middleware/reflect/comprehend-pergroup.d.ts +100 -0
  122. package/dist/middleware/reflect/comprehend-pergroup.d.ts.map +1 -0
  123. package/dist/middleware/reflect/comprehend-pergroup.js +610 -0
  124. package/dist/middleware/reflect/comprehend-pergroup.js.map +1 -0
  125. package/dist/middleware/reflect/comprehend.d.ts +237 -0
  126. package/dist/middleware/reflect/comprehend.d.ts.map +1 -0
  127. package/dist/middleware/reflect/comprehend.js +706 -0
  128. package/dist/middleware/reflect/comprehend.js.map +1 -0
  129. package/dist/middleware/reflect/config.d.ts +34 -0
  130. package/dist/middleware/reflect/config.d.ts.map +1 -0
  131. package/dist/middleware/reflect/config.js +131 -0
  132. package/dist/middleware/reflect/config.js.map +1 -0
  133. package/dist/middleware/reflect/context.d.ts +138 -0
  134. package/dist/middleware/reflect/context.d.ts.map +1 -0
  135. package/dist/middleware/reflect/context.js +619 -0
  136. package/dist/middleware/reflect/context.js.map +1 -0
  137. package/dist/middleware/reflect/cost-breakdown.d.ts +69 -0
  138. package/dist/middleware/reflect/cost-breakdown.d.ts.map +1 -0
  139. package/dist/middleware/reflect/cost-breakdown.js +63 -0
  140. package/dist/middleware/reflect/cost-breakdown.js.map +1 -0
  141. package/dist/middleware/reflect/cost-guard.d.ts +102 -0
  142. package/dist/middleware/reflect/cost-guard.d.ts.map +1 -0
  143. package/dist/middleware/reflect/cost-guard.js +243 -0
  144. package/dist/middleware/reflect/cost-guard.js.map +1 -0
  145. package/dist/middleware/reflect/cost-pricing.d.ts +54 -0
  146. package/dist/middleware/reflect/cost-pricing.d.ts.map +1 -0
  147. package/dist/middleware/reflect/cost-pricing.js +148 -0
  148. package/dist/middleware/reflect/cost-pricing.js.map +1 -0
  149. package/dist/middleware/reflect/cross-group-link.d.ts +61 -0
  150. package/dist/middleware/reflect/cross-group-link.d.ts.map +1 -0
  151. package/dist/middleware/reflect/cross-group-link.js +212 -0
  152. package/dist/middleware/reflect/cross-group-link.js.map +1 -0
  153. package/dist/middleware/reflect/dedup-by-source-and-value.d.ts +70 -0
  154. package/dist/middleware/reflect/dedup-by-source-and-value.d.ts.map +1 -0
  155. package/dist/middleware/reflect/dedup-by-source-and-value.js +0 -0
  156. package/dist/middleware/reflect/dedup-by-source-and-value.js.map +1 -0
  157. package/dist/middleware/reflect/describe-roots.d.ts +58 -0
  158. package/dist/middleware/reflect/describe-roots.d.ts.map +1 -0
  159. package/dist/middleware/reflect/describe-roots.js +266 -0
  160. package/dist/middleware/reflect/describe-roots.js.map +1 -0
  161. package/dist/middleware/reflect/flag-reviewer-startup.d.ts +16 -0
  162. package/dist/middleware/reflect/flag-reviewer-startup.d.ts.map +1 -0
  163. package/dist/middleware/reflect/flag-reviewer-startup.js +107 -0
  164. package/dist/middleware/reflect/flag-reviewer-startup.js.map +1 -0
  165. package/dist/middleware/reflect/flag-reviewer.d.ts +69 -0
  166. package/dist/middleware/reflect/flag-reviewer.d.ts.map +1 -0
  167. package/dist/middleware/reflect/flag-reviewer.js +520 -0
  168. package/dist/middleware/reflect/flag-reviewer.js.map +1 -0
  169. package/dist/middleware/reflect/inline-dedup.d.ts +26 -0
  170. package/dist/middleware/reflect/inline-dedup.d.ts.map +1 -0
  171. package/dist/middleware/reflect/inline-dedup.js +131 -0
  172. package/dist/middleware/reflect/inline-dedup.js.map +1 -0
  173. package/dist/middleware/reflect/justify-decisions.d.ts +37 -0
  174. package/dist/middleware/reflect/justify-decisions.d.ts.map +1 -0
  175. package/dist/middleware/reflect/justify-decisions.js +159 -0
  176. package/dist/middleware/reflect/justify-decisions.js.map +1 -0
  177. package/dist/middleware/reflect/nl-accept.d.ts +35 -0
  178. package/dist/middleware/reflect/nl-accept.d.ts.map +1 -0
  179. package/dist/middleware/reflect/nl-accept.js +167 -0
  180. package/dist/middleware/reflect/nl-accept.js.map +1 -0
  181. package/dist/middleware/reflect/pass0.d.ts +20 -0
  182. package/dist/middleware/reflect/pass0.d.ts.map +1 -0
  183. package/dist/middleware/reflect/pass0.js +423 -0
  184. package/dist/middleware/reflect/pass0.js.map +1 -0
  185. package/dist/middleware/reflect/pass1.d.ts +17 -0
  186. package/dist/middleware/reflect/pass1.d.ts.map +1 -0
  187. package/dist/middleware/reflect/pass1.js +241 -0
  188. package/dist/middleware/reflect/pass1.js.map +1 -0
  189. package/dist/middleware/reflect/pass2-quarantine.d.ts +129 -0
  190. package/dist/middleware/reflect/pass2-quarantine.d.ts.map +1 -0
  191. package/dist/middleware/reflect/pass2-quarantine.js +272 -0
  192. package/dist/middleware/reflect/pass2-quarantine.js.map +1 -0
  193. package/dist/middleware/reflect/pass2-seams.d.ts +205 -0
  194. package/dist/middleware/reflect/pass2-seams.d.ts.map +1 -0
  195. package/dist/middleware/reflect/pass2-seams.js +279 -0
  196. package/dist/middleware/reflect/pass2-seams.js.map +1 -0
  197. package/dist/middleware/reflect/pass2-split-orchestrator.d.ts +37 -0
  198. package/dist/middleware/reflect/pass2-split-orchestrator.d.ts.map +1 -0
  199. package/dist/middleware/reflect/pass2-split-orchestrator.js +531 -0
  200. package/dist/middleware/reflect/pass2-split-orchestrator.js.map +1 -0
  201. package/dist/middleware/reflect/pass2.d.ts +17 -0
  202. package/dist/middleware/reflect/pass2.d.ts.map +1 -0
  203. package/dist/middleware/reflect/pass2.js +324 -0
  204. package/dist/middleware/reflect/pass2.js.map +1 -0
  205. package/dist/middleware/reflect/pass2a.d.ts +141 -0
  206. package/dist/middleware/reflect/pass2a.d.ts.map +1 -0
  207. package/dist/middleware/reflect/pass2a.js +404 -0
  208. package/dist/middleware/reflect/pass2a.js.map +1 -0
  209. package/dist/middleware/reflect/pass2b.d.ts +108 -0
  210. package/dist/middleware/reflect/pass2b.d.ts.map +1 -0
  211. package/dist/middleware/reflect/pass2b.js +480 -0
  212. package/dist/middleware/reflect/pass2b.js.map +1 -0
  213. package/dist/middleware/reflect/pass2c.d.ts +113 -0
  214. package/dist/middleware/reflect/pass2c.d.ts.map +1 -0
  215. package/dist/middleware/reflect/pass2c.js +360 -0
  216. package/dist/middleware/reflect/pass2c.js.map +1 -0
  217. package/dist/middleware/reflect/pass3-batch.d.ts +62 -0
  218. package/dist/middleware/reflect/pass3-batch.d.ts.map +1 -0
  219. package/dist/middleware/reflect/pass3-batch.js +139 -0
  220. package/dist/middleware/reflect/pass3-batch.js.map +1 -0
  221. package/dist/middleware/reflect/pass3.d.ts +23 -0
  222. package/dist/middleware/reflect/pass3.d.ts.map +1 -0
  223. package/dist/middleware/reflect/pass3.js +371 -0
  224. package/dist/middleware/reflect/pass3.js.map +1 -0
  225. package/dist/middleware/reflect/pass4-slice.d.ts +25 -0
  226. package/dist/middleware/reflect/pass4-slice.d.ts.map +1 -0
  227. package/dist/middleware/reflect/pass4-slice.js +315 -0
  228. package/dist/middleware/reflect/pass4-slice.js.map +1 -0
  229. package/dist/middleware/reflect/pass4.d.ts +30 -0
  230. package/dist/middleware/reflect/pass4.d.ts.map +1 -0
  231. package/dist/middleware/reflect/pass4.js +193 -0
  232. package/dist/middleware/reflect/pass4.js.map +1 -0
  233. package/dist/middleware/reflect/pass5.d.ts +22 -0
  234. package/dist/middleware/reflect/pass5.d.ts.map +1 -0
  235. package/dist/middleware/reflect/pass5.js +178 -0
  236. package/dist/middleware/reflect/pass5.js.map +1 -0
  237. package/dist/middleware/reflect/pass_judge.d.ts +44 -0
  238. package/dist/middleware/reflect/pass_judge.d.ts.map +1 -0
  239. package/dist/middleware/reflect/pass_judge.js +263 -0
  240. package/dist/middleware/reflect/pass_judge.js.map +1 -0
  241. package/dist/middleware/reflect/pipeline-flags.d.ts +140 -0
  242. package/dist/middleware/reflect/pipeline-flags.d.ts.map +1 -0
  243. package/dist/middleware/reflect/pipeline-flags.js +314 -0
  244. package/dist/middleware/reflect/pipeline-flags.js.map +1 -0
  245. package/dist/middleware/reflect/pipeline.d.ts +237 -0
  246. package/dist/middleware/reflect/pipeline.d.ts.map +1 -0
  247. package/dist/middleware/reflect/pipeline.js +3114 -0
  248. package/dist/middleware/reflect/pipeline.js.map +1 -0
  249. package/dist/middleware/reflect/promptOverride.d.ts +14 -0
  250. package/dist/middleware/reflect/promptOverride.d.ts.map +1 -0
  251. package/dist/middleware/reflect/promptOverride.js +28 -0
  252. package/dist/middleware/reflect/promptOverride.js.map +1 -0
  253. package/dist/middleware/reflect/provenance-check.d.ts +48 -0
  254. package/dist/middleware/reflect/provenance-check.d.ts.map +1 -0
  255. package/dist/middleware/reflect/provenance-check.js +180 -0
  256. package/dist/middleware/reflect/provenance-check.js.map +1 -0
  257. package/dist/middleware/reflect/provenance-reviewer.d.ts +52 -0
  258. package/dist/middleware/reflect/provenance-reviewer.d.ts.map +1 -0
  259. package/dist/middleware/reflect/provenance-reviewer.js +253 -0
  260. package/dist/middleware/reflect/provenance-reviewer.js.map +1 -0
  261. package/dist/middleware/reflect/prune-collapsed-types.d.ts +11 -0
  262. package/dist/middleware/reflect/prune-collapsed-types.d.ts.map +1 -0
  263. package/dist/middleware/reflect/prune-collapsed-types.js +32 -0
  264. package/dist/middleware/reflect/prune-collapsed-types.js.map +1 -0
  265. package/dist/middleware/reflect/recognize-root.d.ts +75 -0
  266. package/dist/middleware/reflect/recognize-root.d.ts.map +1 -0
  267. package/dist/middleware/reflect/recognize-root.js +204 -0
  268. package/dist/middleware/reflect/recognize-root.js.map +1 -0
  269. package/dist/middleware/reflect/render-agent-flag.d.ts +25 -0
  270. package/dist/middleware/reflect/render-agent-flag.d.ts.map +1 -0
  271. package/dist/middleware/reflect/render-agent-flag.js +39 -0
  272. package/dist/middleware/reflect/render-agent-flag.js.map +1 -0
  273. package/dist/middleware/reflect/retrieve-graph-slice.d.ts +54 -0
  274. package/dist/middleware/reflect/retrieve-graph-slice.d.ts.map +1 -0
  275. package/dist/middleware/reflect/retrieve-graph-slice.js +173 -0
  276. package/dist/middleware/reflect/retrieve-graph-slice.js.map +1 -0
  277. package/dist/middleware/reflect/root-relatedness.d.ts +31 -0
  278. package/dist/middleware/reflect/root-relatedness.d.ts.map +1 -0
  279. package/dist/middleware/reflect/root-relatedness.js +92 -0
  280. package/dist/middleware/reflect/root-relatedness.js.map +1 -0
  281. package/dist/middleware/reflect/schema-heal.d.ts +22 -0
  282. package/dist/middleware/reflect/schema-heal.d.ts.map +1 -0
  283. package/dist/middleware/reflect/schema-heal.js +119 -0
  284. package/dist/middleware/reflect/schema-heal.js.map +1 -0
  285. package/dist/middleware/reflect/schema-validator.d.ts +85 -0
  286. package/dist/middleware/reflect/schema-validator.d.ts.map +1 -0
  287. package/dist/middleware/reflect/schema-validator.js +196 -0
  288. package/dist/middleware/reflect/schema-validator.js.map +1 -0
  289. package/dist/middleware/reflect/stage-audit-graph.d.ts +115 -0
  290. package/dist/middleware/reflect/stage-audit-graph.d.ts.map +1 -0
  291. package/dist/middleware/reflect/stage-audit-graph.js +563 -0
  292. package/dist/middleware/reflect/stage-audit-graph.js.map +1 -0
  293. package/dist/middleware/reflect/stage-d-resolve-graph.d.ts +87 -0
  294. package/dist/middleware/reflect/stage-d-resolve-graph.d.ts.map +1 -0
  295. package/dist/middleware/reflect/stage-d-resolve-graph.js +256 -0
  296. package/dist/middleware/reflect/stage-d-resolve-graph.js.map +1 -0
  297. package/dist/middleware/reflect/synthesizeFromSceneCard.d.ts +15 -0
  298. package/dist/middleware/reflect/synthesizeFromSceneCard.d.ts.map +1 -0
  299. package/dist/middleware/reflect/synthesizeFromSceneCard.js +91 -0
  300. package/dist/middleware/reflect/synthesizeFromSceneCard.js.map +1 -0
  301. package/dist/middleware/reflect/types.d.ts +261 -0
  302. package/dist/middleware/reflect/types.d.ts.map +1 -0
  303. package/dist/middleware/reflect/types.js +3 -0
  304. package/dist/middleware/reflect/types.js.map +1 -0
  305. package/dist/middleware/reflect/v2-integrate.d.ts +120 -0
  306. package/dist/middleware/reflect/v2-integrate.d.ts.map +1 -0
  307. package/dist/middleware/reflect/v2-integrate.js +388 -0
  308. package/dist/middleware/reflect/v2-integrate.js.map +1 -0
  309. package/dist/middleware/reflect/v2-judge.d.ts +44 -0
  310. package/dist/middleware/reflect/v2-judge.d.ts.map +1 -0
  311. package/dist/middleware/reflect/v2-judge.js +191 -0
  312. package/dist/middleware/reflect/v2-judge.js.map +1 -0
  313. package/dist/relation-sets.d.ts +2 -0
  314. package/dist/relation-sets.d.ts.map +1 -0
  315. package/dist/relation-sets.js +35 -0
  316. package/dist/relation-sets.js.map +1 -0
  317. package/dist/routes/__tests__/flags.test.d.ts +2 -0
  318. package/dist/routes/__tests__/flags.test.d.ts.map +1 -0
  319. package/dist/routes/__tests__/flags.test.js +257 -0
  320. package/dist/routes/__tests__/flags.test.js.map +1 -0
  321. package/dist/routes/__tests__/models-catalog.test.d.ts +2 -0
  322. package/dist/routes/__tests__/models-catalog.test.d.ts.map +1 -0
  323. package/dist/routes/__tests__/models-catalog.test.js +130 -0
  324. package/dist/routes/__tests__/models-catalog.test.js.map +1 -0
  325. package/dist/routes/__tests__/reflect-pause-drain.test.d.ts +2 -0
  326. package/dist/routes/__tests__/reflect-pause-drain.test.d.ts.map +1 -0
  327. package/dist/routes/__tests__/reflect-pause-drain.test.js +38 -0
  328. package/dist/routes/__tests__/reflect-pause-drain.test.js.map +1 -0
  329. package/dist/routes/__tests__/spend-pause-drain.test.d.ts +2 -0
  330. package/dist/routes/__tests__/spend-pause-drain.test.d.ts.map +1 -0
  331. package/dist/routes/__tests__/spend-pause-drain.test.js +38 -0
  332. package/dist/routes/__tests__/spend-pause-drain.test.js.map +1 -0
  333. package/dist/routes/admin.d.ts +49 -0
  334. package/dist/routes/admin.d.ts.map +1 -0
  335. package/dist/routes/admin.js +471 -0
  336. package/dist/routes/admin.js.map +1 -0
  337. package/dist/routes/blocks.d.ts +4 -0
  338. package/dist/routes/blocks.d.ts.map +1 -0
  339. package/dist/routes/blocks.js +893 -0
  340. package/dist/routes/blocks.js.map +1 -0
  341. package/dist/routes/chat-proxy.d.ts +5 -0
  342. package/dist/routes/chat-proxy.d.ts.map +1 -0
  343. package/dist/routes/chat-proxy.js +225 -0
  344. package/dist/routes/chat-proxy.js.map +1 -0
  345. package/dist/routes/conversations.d.ts +4 -0
  346. package/dist/routes/conversations.d.ts.map +1 -0
  347. package/dist/routes/conversations.js +139 -0
  348. package/dist/routes/conversations.js.map +1 -0
  349. package/dist/routes/flags.d.ts +4 -0
  350. package/dist/routes/flags.d.ts.map +1 -0
  351. package/dist/routes/flags.js +151 -0
  352. package/dist/routes/flags.js.map +1 -0
  353. package/dist/routes/inject.d.ts +4 -0
  354. package/dist/routes/inject.d.ts.map +1 -0
  355. package/dist/routes/inject.js +183 -0
  356. package/dist/routes/inject.js.map +1 -0
  357. package/dist/routes/mcp-http.d.ts +5 -0
  358. package/dist/routes/mcp-http.d.ts.map +1 -0
  359. package/dist/routes/mcp-http.js +94 -0
  360. package/dist/routes/mcp-http.js.map +1 -0
  361. package/dist/routes/quarantine.d.ts +4 -0
  362. package/dist/routes/quarantine.d.ts.map +1 -0
  363. package/dist/routes/quarantine.js +66 -0
  364. package/dist/routes/quarantine.js.map +1 -0
  365. package/dist/routes/recall.d.ts +5 -0
  366. package/dist/routes/recall.d.ts.map +1 -0
  367. package/dist/routes/recall.js +573 -0
  368. package/dist/routes/recall.js.map +1 -0
  369. package/dist/routes/reflect.d.ts +5 -0
  370. package/dist/routes/reflect.d.ts.map +1 -0
  371. package/dist/routes/reflect.js +231 -0
  372. package/dist/routes/reflect.js.map +1 -0
  373. package/dist/routes/session.d.ts +4 -0
  374. package/dist/routes/session.d.ts.map +1 -0
  375. package/dist/routes/session.js +418 -0
  376. package/dist/routes/session.js.map +1 -0
  377. package/dist/routes/state.d.ts +116 -0
  378. package/dist/routes/state.d.ts.map +1 -0
  379. package/dist/routes/state.js +621 -0
  380. package/dist/routes/state.js.map +1 -0
  381. package/dist/routes/usage.d.ts +3 -0
  382. package/dist/routes/usage.d.ts.map +1 -0
  383. package/dist/routes/usage.js +141 -0
  384. package/dist/routes/usage.js.map +1 -0
  385. package/dist/routes/workspace.d.ts +5 -0
  386. package/dist/routes/workspace.d.ts.map +1 -0
  387. package/dist/routes/workspace.js +435 -0
  388. package/dist/routes/workspace.js.map +1 -0
  389. package/dist/server.d.ts +13 -0
  390. package/dist/server.d.ts.map +1 -0
  391. package/dist/server.js +298 -0
  392. package/dist/server.js.map +1 -0
  393. package/dist/store/__tests__/backup.test.d.ts +2 -0
  394. package/dist/store/__tests__/backup.test.d.ts.map +1 -0
  395. package/dist/store/__tests__/backup.test.js +53 -0
  396. package/dist/store/__tests__/backup.test.js.map +1 -0
  397. package/dist/store/__tests__/quality.test.d.ts +2 -0
  398. package/dist/store/__tests__/quality.test.d.ts.map +1 -0
  399. package/dist/store/__tests__/quality.test.js +75 -0
  400. package/dist/store/__tests__/quality.test.js.map +1 -0
  401. package/dist/store/backup.d.ts +14 -0
  402. package/dist/store/backup.d.ts.map +1 -0
  403. package/dist/store/backup.js +95 -0
  404. package/dist/store/backup.js.map +1 -0
  405. package/dist/store/database.d.ts +407 -0
  406. package/dist/store/database.d.ts.map +1 -0
  407. package/dist/store/database.js +2004 -0
  408. package/dist/store/database.js.map +1 -0
  409. package/dist/store/quality.d.ts +25 -0
  410. package/dist/store/quality.d.ts.map +1 -0
  411. package/dist/store/quality.js +48 -0
  412. package/dist/store/quality.js.map +1 -0
  413. package/dist/tools/__tests__/assemble-block-chains.test.d.ts +2 -0
  414. package/dist/tools/__tests__/assemble-block-chains.test.d.ts.map +1 -0
  415. package/dist/tools/__tests__/assemble-block-chains.test.js +118 -0
  416. package/dist/tools/__tests__/assemble-block-chains.test.js.map +1 -0
  417. package/dist/tools/__tests__/filter-roots-by-concepts.test.d.ts +2 -0
  418. package/dist/tools/__tests__/filter-roots-by-concepts.test.d.ts.map +1 -0
  419. package/dist/tools/__tests__/filter-roots-by-concepts.test.js +68 -0
  420. package/dist/tools/__tests__/filter-roots-by-concepts.test.js.map +1 -0
  421. package/dist/tools/__tests__/flag-surface.test.d.ts +2 -0
  422. package/dist/tools/__tests__/flag-surface.test.d.ts.map +1 -0
  423. package/dist/tools/__tests__/flag-surface.test.js +130 -0
  424. package/dist/tools/__tests__/flag-surface.test.js.map +1 -0
  425. package/dist/tools/core.d.ts +5 -0
  426. package/dist/tools/core.d.ts.map +1 -0
  427. package/dist/tools/core.js +962 -0
  428. package/dist/tools/core.js.map +1 -0
  429. package/dist/tools/derive.d.ts +5 -0
  430. package/dist/tools/derive.d.ts.map +1 -0
  431. package/dist/tools/derive.js +182 -0
  432. package/dist/tools/derive.js.map +1 -0
  433. package/dist/tools/flag-surface.d.ts +26 -0
  434. package/dist/tools/flag-surface.d.ts.map +1 -0
  435. package/dist/tools/flag-surface.js +59 -0
  436. package/dist/tools/flag-surface.js.map +1 -0
  437. package/dist/tools/helpers.d.ts +99 -0
  438. package/dist/tools/helpers.d.ts.map +1 -0
  439. package/dist/tools/helpers.js +243 -0
  440. package/dist/tools/helpers.js.map +1 -0
  441. package/dist/tools/projects.d.ts +5 -0
  442. package/dist/tools/projects.d.ts.map +1 -0
  443. package/dist/tools/projects.js +175 -0
  444. package/dist/tools/projects.js.map +1 -0
  445. package/dist/tools/system.d.ts +5 -0
  446. package/dist/tools/system.d.ts.map +1 -0
  447. package/dist/tools/system.js +1361 -0
  448. package/dist/tools/system.js.map +1 -0
  449. package/dist/tools/tasks.d.ts +5 -0
  450. package/dist/tools/tasks.d.ts.map +1 -0
  451. package/dist/tools/tasks.js +289 -0
  452. package/dist/tools/tasks.js.map +1 -0
  453. package/package.json +69 -0
  454. package/scripts/nodedex-entry.mjs +396 -0
  455. package/tui-dist/App.js +185 -0
  456. package/tui-dist/api.js +197 -0
  457. package/tui-dist/cli.js +53 -0
  458. package/tui-dist/components.js +63 -0
  459. package/tui-dist/config.js +242 -0
  460. package/tui-dist/connect-snippets.js +98 -0
  461. package/tui-dist/feed.js +51 -0
  462. package/tui-dist/health.js +465 -0
  463. package/tui-dist/hooks.js +23 -0
  464. package/tui-dist/memory.js +220 -0
  465. package/tui-dist/onboarding.js +498 -0
  466. package/tui-dist/review.js +193 -0
  467. package/tui-dist/servers.js +556 -0
  468. package/tui-dist/smoke.js +15 -0
  469. package/tui-dist/theme.js +106 -0
@@ -0,0 +1,125 @@
1
+ import Anthropic from "@anthropic-ai/sdk";
2
+ import { EmptyResponseError, classifyGenError, llmTimeoutMs, decideEmptyOrTimeoutAction, isInsufficientCreditError } from "./failure-policy.js";
3
+ export class AnthropicProvider {
4
+ client;
5
+ model;
6
+ fallbackModel;
7
+ constructor(apiKey) {
8
+ this.client = apiKey ? new Anthropic({ apiKey }) : null;
9
+ this.model = process.env.AI_MODEL ?? "claude-opus-4-6";
10
+ const fb = process.env.NODEDEX_FALLBACK_MODEL ?? "";
11
+ this.fallbackModel = fb && fb !== this.model ? fb : null;
12
+ }
13
+ isAvailable() { return this.client !== null; }
14
+ getName() { return "anthropic"; }
15
+ async generateStructured(systemPrompt, userInput, schema, options) {
16
+ if (!this.client)
17
+ return { result: null, rateLimited: false };
18
+ const modelsToTry = options?.modelOverride
19
+ ? [options.modelOverride]
20
+ : this.fallbackModel ? [this.model, this.fallbackModel] : [this.model];
21
+ const attempts = [];
22
+ for (let i = 0; i < modelsToTry.length; i++) {
23
+ const modelName = modelsToTry[i];
24
+ const isFallback = i > 0;
25
+ let emptyRetried = false;
26
+ while (true) {
27
+ try {
28
+ const response = await this.client.messages.create({
29
+ model: modelName,
30
+ max_tokens: options?.maxOutputTokens ?? 8192,
31
+ system: systemPrompt,
32
+ messages: [{ role: "user", content: userInput }],
33
+ tools: [{
34
+ name: "save_result",
35
+ description: "Save the structured extraction result",
36
+ input_schema: schema,
37
+ }],
38
+ tool_choice: { type: "tool", name: "save_result" },
39
+ }, { timeout: llmTimeoutMs() });
40
+ const toolUse = response.content.find((c) => c.type === "tool_use");
41
+ // No tool_use block = the model produced no structured content = EMPTY/hung
42
+ // (see ./failure-policy). Raise it so the catch retries/escalates rather than
43
+ // failing the pass outright (the old behavior — no retry, no fallback).
44
+ if (!toolUse)
45
+ throw new EmptyResponseError(modelName);
46
+ if (isFallback)
47
+ console.log(`[anthropic] escalated to fallback model ${modelName}`);
48
+ attempts.push({ model: modelName, outcome: "ok" });
49
+ return {
50
+ result: toolUse.input,
51
+ rateLimited: false,
52
+ usage: { input: response.usage.input_tokens, thinking: 0, output: response.usage.output_tokens },
53
+ model: modelName,
54
+ attempts,
55
+ };
56
+ }
57
+ catch (e) {
58
+ // Out-of-credit (402) — surface DEFINITIVELY (see openai.ts): the reflect queue
59
+ // pauses-the-spend + requeues instead of swallowing it into a generic null.
60
+ if (isInsufficientCreditError(e)) {
61
+ attempts.push({ model: modelName, outcome: "error" });
62
+ console.error(`[anthropic] ${modelName} insufficient credit (status=${e?.status ?? "?"}) — credit exhausted; not retrying/escalating (account unfunded)`);
63
+ return { result: null, rateLimited: false, creditExhausted: true, model: modelName, attempts };
64
+ }
65
+ const kind = classifyGenError(e);
66
+ const rateLimited = kind === "rate_limited";
67
+ const hasNextModel = i + 1 < modelsToTry.length;
68
+ // EMPTY/TIMEOUT → shared escalate-first policy (./failure-policy): a fallback model
69
+ // is the likeliest recovery for an input-specific empty (and skips the slow same-
70
+ // model draw); only a single-key setup retries the SAME model once.
71
+ if (kind === "empty" || kind === "timeout") {
72
+ const action = decideEmptyOrTimeoutAction({ kind, hasNextModel, emptyRetried });
73
+ attempts.push({ model: modelName, outcome: kind === "timeout" ? "timeout" : "empty" });
74
+ if (action === "escalate") {
75
+ console.log(`[anthropic] ${modelName} ${kind} — escalating to fallback ${modelsToTry[i + 1]}`);
76
+ break; // exit while; outer for tries the next model
77
+ }
78
+ if (action === "retry_same") {
79
+ console.warn(`[anthropic] ${modelName} returned no structured content — no fallback; retrying same model once`);
80
+ emptyRetried = true;
81
+ continue; // retry same model
82
+ }
83
+ if (kind === "timeout") {
84
+ console.error(`[anthropic] generateStructured TIMEOUT (${modelName}): ${llmTimeoutMs()}ms — pipeline continues`);
85
+ }
86
+ return { result: null, rateLimited: false, model: modelName, attempts };
87
+ }
88
+ // RATE-LIMIT / other → escalate to the next model if one remains, else degrade.
89
+ // (No same-model bump: anthropic returns structured tool input directly, not
90
+ // parsed JSON, so there is no truncation-retry rung.)
91
+ attempts.push({ model: modelName, outcome: rateLimited ? "rate_limited" : "error" });
92
+ if (rateLimited && hasNextModel) {
93
+ console.log(`[anthropic] ${modelName} rate-limited — escalating to fallback ${modelsToTry[i + 1]}`);
94
+ break; // exit while; outer for tries the next model
95
+ }
96
+ if (!rateLimited) {
97
+ console.error(`[anthropic] generateStructured error (${modelName}): status=${e?.status} msg=${String(e?.message ?? e).slice(0, 200)}`);
98
+ }
99
+ return { result: null, rateLimited, model: modelName, attempts };
100
+ }
101
+ }
102
+ }
103
+ return { result: null, rateLimited: true, attempts };
104
+ }
105
+ async generate(prompt) {
106
+ if (!this.client)
107
+ return null;
108
+ try {
109
+ const response = await this.client.messages.create({
110
+ model: this.model,
111
+ max_tokens: 2048,
112
+ messages: [{ role: "user", content: prompt }],
113
+ });
114
+ const textBlock = response.content.find((c) => c.type === "text");
115
+ return textBlock?.text ?? null;
116
+ }
117
+ catch {
118
+ return null;
119
+ }
120
+ }
121
+ async ping() {
122
+ return (await this.generate("Say OK")) !== null;
123
+ }
124
+ }
125
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/engine/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAE1C,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,YAAY,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAEhJ,MAAM,OAAO,iBAAiB;IACpB,MAAM,CAAmB;IACzB,KAAK,CAAS;IACd,aAAa,CAAgB;IAErC,YAAY,MAAc;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACxD,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,iBAAiB,CAAC;QACvD,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,EAAE,CAAC;QACpD,IAAI,CAAC,aAAa,GAAG,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3D,CAAC;IAED,WAAW,KAAc,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC;IACvD,OAAO,KAAa,OAAO,WAAW,CAAC,CAAC,CAAC;IAEzC,KAAK,CAAC,kBAAkB,CACtB,YAAoB,EACpB,SAAiB,EACjB,MAAc,EACd,OAAuF;QAEvF,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;QAC9D,MAAM,WAAW,GAAG,OAAO,EAAE,aAAa;YACxC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;YACzB,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEzE,MAAM,QAAQ,GAA+C,EAAE,CAAC;QAChE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,CAAC;YACzB,IAAI,YAAY,GAAG,KAAK,CAAC;YACzB,OAAO,IAAI,EAAE,CAAC;gBACb,IAAI,CAAC;oBACJ,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;wBACjD,KAAK,EAAE,SAAS;wBAChB,UAAU,EAAE,OAAO,EAAE,eAAe,IAAI,IAAI;wBAC5C,MAAM,EAAE,YAAY;wBACpB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;wBAChD,KAAK,EAAE,CAAC;gCACN,IAAI,EAAE,aAAa;gCACnB,WAAW,EAAE,uCAAuC;gCACpD,YAAY,EAAE,MAAwC;6BACvD,CAAC;wBACF,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE;qBACnD,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;oBAChC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CACnC,CAAC,CAAC,EAA+B,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAC1D,CAAC;oBACF,4EAA4E;oBAC5E,8EAA8E;oBAC9E,wEAAwE;oBACxE,IAAI,CAAC,OAAO;wBAAE,MAAM,IAAI,kBAAkB,CAAC,SAAS,CAAC,CAAC;oBAEtD,IAAI,UAAU;wBAAE,OAAO,CAAC,GAAG,CAAC,2CAA2C,SAAS,EAAE,CAAC,CAAC;oBACpF,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;oBACnD,OAAO;wBACL,MAAM,EAAE,OAAO,CAAC,KAAU;wBAC1B,WAAW,EAAE,KAAK;wBAClB,KAAK,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,EAAE;wBAChG,KAAK,EAAE,SAAS;wBAChB,QAAQ;qBACT,CAAC;gBACH,CAAC;gBAAC,OAAO,CAAM,EAAE,CAAC;oBACjB,gFAAgF;oBAChF,4EAA4E;oBAC5E,IAAI,yBAAyB,CAAC,CAAC,CAAC,EAAE,CAAC;wBACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;wBACtD,OAAO,CAAC,KAAK,CAAC,eAAe,SAAS,gCAAgC,CAAC,EAAE,MAAM,IAAI,GAAG,kEAAkE,CAAC,CAAC;wBAC1J,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;oBACjG,CAAC;oBACD,MAAM,IAAI,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;oBACjC,MAAM,WAAW,GAAG,IAAI,KAAK,cAAc,CAAC;oBAC5C,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC;oBAEhD,oFAAoF;oBACpF,kFAAkF;oBAClF,oEAAoE;oBACpE,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;wBAC3C,MAAM,MAAM,GAAG,0BAA0B,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC,CAAC;wBAChF,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;wBACvF,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;4BAC1B,OAAO,CAAC,GAAG,CAAC,eAAe,SAAS,IAAI,IAAI,6BAA6B,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;4BAC/F,MAAM,CAAC,6CAA6C;wBACtD,CAAC;wBACD,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;4BAC5B,OAAO,CAAC,IAAI,CAAC,eAAe,SAAS,yEAAyE,CAAC,CAAC;4BAChH,YAAY,GAAG,IAAI,CAAC;4BACpB,SAAS,CAAC,mBAAmB;wBAC/B,CAAC;wBACD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;4BACvB,OAAO,CAAC,KAAK,CAAC,2CAA2C,SAAS,MAAM,YAAY,EAAE,yBAAyB,CAAC,CAAC;wBACnH,CAAC;wBACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;oBAC1E,CAAC;oBAED,gFAAgF;oBAChF,6EAA6E;oBAC7E,sDAAsD;oBACtD,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;oBACrF,IAAI,WAAW,IAAI,YAAY,EAAE,CAAC;wBAChC,OAAO,CAAC,GAAG,CAAC,eAAe,SAAS,0CAA0C,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;wBACpG,MAAM,CAAC,6CAA6C;oBACtD,CAAC;oBACD,IAAI,CAAC,WAAW,EAAE,CAAC;wBACjB,OAAO,CAAC,KAAK,CAAC,yCAAyC,SAAS,aAAa,CAAC,EAAE,MAAM,QAAQ,MAAM,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;oBACzI,CAAC;oBACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;gBAClE,CAAC;YACF,CAAC;QACH,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,MAAc;QAC3B,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACjD,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,UAAU,EAAE,IAAI;gBAChB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;aAC9C,CAAC,CAAC;YACH,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CACrC,CAAC,CAAC,EAA4B,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CACnD,CAAC;YACF,OAAO,SAAS,EAAE,IAAI,IAAI,IAAI,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI;QACR,OAAO,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,CAAC;IAClD,CAAC;CACF"}
@@ -0,0 +1,56 @@
1
+ /** Empty/hung response: the model returned NO content (text="" / 0 tokens, often
2
+ * after a long hang). DISTINCT from truncation — there is no partial classification,
3
+ * so a max_tokens bump is a no-op and escalating to a fallback model is SAFE (the
4
+ * determinism trap does not apply when there was no classification at all). */
5
+ export declare class EmptyResponseError extends Error {
6
+ readonly model: string;
7
+ constructor(model: string);
8
+ }
9
+ /** True when an extracted completion body has no usable content. */
10
+ export declare function isEmptyResult(text: string | null | undefined): boolean;
11
+ /** Bound an LLM call so a hung provider can't stall the pipeline indefinitely.
12
+ * Promise.race — the underlying request continues in the background on timeout but
13
+ * the pipeline unblocks. Providers whose SDK has a native per-request timeout
14
+ * (openai, anthropic) use that instead; gemini's SDK does not, so it wraps with this.
15
+ * (debt-4 Stage A, promoted from gemini.ts so the bound is shared.) */
16
+ export declare function withTimeout<T>(p: Promise<T>, ms: number, label: string): Promise<T>;
17
+ /** The shared call-timeout bound (ms). 180s is generous: a healthy Pass 3 (~60-80s)
18
+ * and Pass 2c (~100-150s) fit; it caps the worst case (~3min) AND the ~200s empty-
19
+ * hang we observed (Run 12, 2026-06-06). Configurable via NODEDEX_LLM_TIMEOUT_MS;
20
+ * <=0 disables the bound. */
21
+ export declare function llmTimeoutMs(): number;
22
+ export type GenFailureKind = "empty" | "timeout" | "rate_limited" | "truncated" | "mechanism_or_other";
23
+ /** Classify a generateStructured() failure so every provider's retry policy branches
24
+ * identically. Order matters: the explicit EmptyResponseError must win over the
25
+ * SyntaxError that an empty body would otherwise produce. */
26
+ export declare function classifyGenError(e: unknown): GenFailureKind;
27
+ /** Out-of-credit / billing failure — DISTINCT from a transient rate-limit. The account
28
+ * can't pay for the call (HTTP 402, or an "insufficient credit/funds/balance/quota" body),
29
+ * so retrying the same model OR escalating to a fallback is pointless — every model on the
30
+ * account is equally unfunded. The pipeline treats this as a PAUSE-the-spend trigger
31
+ * (preserve + requeue the turn, auto-resume on top-up), NOT a per-turn failure that counts
32
+ * toward the drop cap. Accepts an Error, an OpenRouter/OpenAI SDK error ({status,code,message}),
33
+ * or a plain reason string (so the reflect queue can classify a swallowed-null reason too).
34
+ * Checked separately from classifyGenError so a billing-out never masquerades as a
35
+ * rate-limit (which would wastefully escalate to an equally-unfunded fallback model). */
36
+ export declare function isInsufficientCreditError(e: unknown): boolean;
37
+ export type RetryAction = "escalate" | "retry_same" | "degrade";
38
+ /** Decide what to do with an EMPTY or TIMEOUT failure, given the retry state. This is
39
+ * the "escalate-first-when-a-fallback-exists" policy (2026-06-06, Run 14 finding):
40
+ * - escalate : a fallback model remains → try it. For an empty, a DIFFERENT model is
41
+ * the likeliest recovery (the empty tends to be input-specific to one
42
+ * model) and it skips the slow same-model draw; for a timeout, don't pay
43
+ * the bound twice on the same model.
44
+ * - retry_same : NO fallback remains AND this is an un-retried empty → give the SAME
45
+ * model one more independent draw. This is a single-key user's ONLY
46
+ * recovery path (empties are probabilistic — a 2nd draw sometimes wins).
47
+ * - degrade : nothing left to try (no fallback + already retried, or a timeout with
48
+ * no fallback — we never re-pay a timeout on the same model).
49
+ * Neither empty nor timeout ever bumps max_tokens (no partial output to grow) and both
50
+ * are SAFE to escalate (no determinism trap — there was no classification to contradict). */
51
+ export declare function decideEmptyOrTimeoutAction(opts: {
52
+ kind: "empty" | "timeout";
53
+ hasNextModel: boolean;
54
+ emptyRetried: boolean;
55
+ }): RetryAction;
56
+ //# sourceMappingURL=failure-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failure-policy.d.ts","sourceRoot":"","sources":["../../../src/engine/providers/failure-policy.ts"],"names":[],"mappings":"AAoBA;;;gFAGgF;AAChF,qBAAa,kBAAmB,SAAQ,KAAK;aACf,KAAK,EAAE,MAAM;gBAAb,KAAK,EAAE,MAAM;CAI1C;AAED,oEAAoE;AACpE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEtE;AAED;;;;wEAIwE;AACxE,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAOnF;AAED;;;8BAG8B;AAC9B,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,SAAS,GAAG,cAAc,GAAG,WAAW,GAAG,oBAAoB,CAAC;AAEvG;;8DAE8D;AAC9D,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,cAAc,CAa3D;AAED;;;;;;;;0FAQ0F;AAC1F,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAY7D;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC;AAEhE;;;;;;;;;;;;8FAY8F;AAC9F,wBAAgB,0BAA0B,CAAC,IAAI,EAAE;IAC/C,IAAI,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1B,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;CACvB,GAAG,WAAW,CAId"}
@@ -0,0 +1,120 @@
1
+ // ── Shared LLM-call failure policy (2026-06-06) ──────────────────────────────────
2
+ // The three providers (openai/gemini/anthropic) differ only in SDK CALL MECHANICS.
3
+ // "What to do when a call empties / hangs / truncates / rate-limits" is the SAME
4
+ // policy and must hold on EVERY real-world provider path — a developer may run
5
+ // Nodedex on any provider with their own key, not just our OpenRouter setup. This
6
+ // module owns the provider-agnostic pieces (failure classification, empty-detection,
7
+ // the call timeout); each provider maps its SDK errors into classifyGenError() and
8
+ // applies the one canonical retry policy:
9
+ //
10
+ // empty → retry SAME model once (transient glitch; the only recovery a
11
+ // single-key user has) → escalate to fallback model if configured
12
+ // → else degrade. Never bump max_tokens (no output to grow).
13
+ // timeout → escalate to fallback model → else degrade. No same-model retry
14
+ // (the call already paid the full timeout; don't pay it twice).
15
+ // rate_limited → escalate to fallback model → else degrade (capacity problem).
16
+ // truncated → retry SAME model once with a bigger budget → else degrade. NEVER
17
+ // swap models (a different model yields a different classification =
18
+ // the determinism trap).
19
+ // mechanism_or_other → provider-specific (openai: one prompt-JSON retry; others degrade).
20
+ /** Empty/hung response: the model returned NO content (text="" / 0 tokens, often
21
+ * after a long hang). DISTINCT from truncation — there is no partial classification,
22
+ * so a max_tokens bump is a no-op and escalating to a fallback model is SAFE (the
23
+ * determinism trap does not apply when there was no classification at all). */
24
+ export class EmptyResponseError extends Error {
25
+ model;
26
+ constructor(model) {
27
+ super(`empty/hung response from ${model}`);
28
+ this.model = model;
29
+ this.name = "EmptyResponseError";
30
+ }
31
+ }
32
+ /** True when an extracted completion body has no usable content. */
33
+ export function isEmptyResult(text) {
34
+ return (text ?? "").trim() === "";
35
+ }
36
+ /** Bound an LLM call so a hung provider can't stall the pipeline indefinitely.
37
+ * Promise.race — the underlying request continues in the background on timeout but
38
+ * the pipeline unblocks. Providers whose SDK has a native per-request timeout
39
+ * (openai, anthropic) use that instead; gemini's SDK does not, so it wraps with this.
40
+ * (debt-4 Stage A, promoted from gemini.ts so the bound is shared.) */
41
+ export function withTimeout(p, ms, label) {
42
+ return Promise.race([
43
+ p,
44
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`${label} timeout after ${ms}ms`)), ms)),
45
+ ]);
46
+ }
47
+ /** The shared call-timeout bound (ms). 180s is generous: a healthy Pass 3 (~60-80s)
48
+ * and Pass 2c (~100-150s) fit; it caps the worst case (~3min) AND the ~200s empty-
49
+ * hang we observed (Run 12, 2026-06-06). Configurable via NODEDEX_LLM_TIMEOUT_MS;
50
+ * <=0 disables the bound. */
51
+ export function llmTimeoutMs() {
52
+ const n = Number(process.env.NODEDEX_LLM_TIMEOUT_MS ?? "180000");
53
+ return Number.isFinite(n) ? n : 180000;
54
+ }
55
+ /** Classify a generateStructured() failure so every provider's retry policy branches
56
+ * identically. Order matters: the explicit EmptyResponseError must win over the
57
+ * SyntaxError that an empty body would otherwise produce. */
58
+ export function classifyGenError(e) {
59
+ if (e instanceof EmptyResponseError)
60
+ return "empty";
61
+ const msg = String(e?.message ?? "");
62
+ const status = e?.status;
63
+ // Capacity / rate-limit: 429, 503 (overloaded), 529 (Anthropic overloaded), quota.
64
+ if (status === 429 || status === 503 || status === 529 ||
65
+ /\b429\b|\b503\b|\b529\b|quota|RESOURCE_EXHAUSTED|high demand/i.test(msg))
66
+ return "rate_limited";
67
+ const name = String(e?.name ?? "");
68
+ // Timeout: openai/anthropic SDK throw APIConnectionTimeoutError; withTimeout() throws "... timeout after Nms".
69
+ if (name === "APIConnectionTimeoutError" || /timeout after|timed?\s?out|timeout/i.test(msg))
70
+ return "timeout";
71
+ // Truncation: JSON.parse threw on a NON-empty body (cut mid-structure at max_tokens).
72
+ if (e instanceof SyntaxError || msg.includes("Unterminated") || msg.includes("position"))
73
+ return "truncated";
74
+ return "mechanism_or_other";
75
+ }
76
+ /** Out-of-credit / billing failure — DISTINCT from a transient rate-limit. The account
77
+ * can't pay for the call (HTTP 402, or an "insufficient credit/funds/balance/quota" body),
78
+ * so retrying the same model OR escalating to a fallback is pointless — every model on the
79
+ * account is equally unfunded. The pipeline treats this as a PAUSE-the-spend trigger
80
+ * (preserve + requeue the turn, auto-resume on top-up), NOT a per-turn failure that counts
81
+ * toward the drop cap. Accepts an Error, an OpenRouter/OpenAI SDK error ({status,code,message}),
82
+ * or a plain reason string (so the reflect queue can classify a swallowed-null reason too).
83
+ * Checked separately from classifyGenError so a billing-out never masquerades as a
84
+ * rate-limit (which would wastefully escalate to an equally-unfunded fallback model). */
85
+ export function isInsufficientCreditError(e) {
86
+ if (e == null)
87
+ return false;
88
+ const status = e?.status ?? e?.code;
89
+ if (status === 402 || status === "402")
90
+ return true;
91
+ const msg = typeof e === "string" ? e : String(e?.message ?? "");
92
+ // 402 / "insufficient credit" = account out of funds. ALSO treat a provider SPEND-CAP as the
93
+ // same class so it routes through the pause-spend + TUI alert + auto-resume path instead of a
94
+ // silent generic-failure fail-clean: OpenRouter returns 403 "Key limit exceeded (total limit)"
95
+ // when a key's spend ceiling is hit. Deliberately NOT a transient 429 rate-limit (that backs
96
+ // off + retries — pausing-till-topup would be wrong) and NOT a bare 403 (auth/permission) —
97
+ // only the limit-exceeded TEXT, which "rate limit exceeded" does not match.
98
+ return /\b402\b|payment required|insufficient[\s_-]*(credit|fund|balance|quota)|negative\s+(credit|balance)|requires?\s+(more|additional)\s+credit|out of credit|add (more )?credit|key\s+limit\s+exceeded|\btotal\s+limit\b|credit\s+limit\b/i.test(msg);
99
+ }
100
+ /** Decide what to do with an EMPTY or TIMEOUT failure, given the retry state. This is
101
+ * the "escalate-first-when-a-fallback-exists" policy (2026-06-06, Run 14 finding):
102
+ * - escalate : a fallback model remains → try it. For an empty, a DIFFERENT model is
103
+ * the likeliest recovery (the empty tends to be input-specific to one
104
+ * model) and it skips the slow same-model draw; for a timeout, don't pay
105
+ * the bound twice on the same model.
106
+ * - retry_same : NO fallback remains AND this is an un-retried empty → give the SAME
107
+ * model one more independent draw. This is a single-key user's ONLY
108
+ * recovery path (empties are probabilistic — a 2nd draw sometimes wins).
109
+ * - degrade : nothing left to try (no fallback + already retried, or a timeout with
110
+ * no fallback — we never re-pay a timeout on the same model).
111
+ * Neither empty nor timeout ever bumps max_tokens (no partial output to grow) and both
112
+ * are SAFE to escalate (no determinism trap — there was no classification to contradict). */
113
+ export function decideEmptyOrTimeoutAction(opts) {
114
+ if (opts.hasNextModel)
115
+ return "escalate";
116
+ if (opts.kind === "empty" && !opts.emptyRetried)
117
+ return "retry_same";
118
+ return "degrade";
119
+ }
120
+ //# sourceMappingURL=failure-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failure-policy.js","sourceRoot":"","sources":["../../../src/engine/providers/failure-policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { LLMProvider, EmbeddingProvider, GenerateResult } from "../ai-provider.js";
2
+ export declare class GeminiProvider implements LLMProvider {
3
+ private genAI;
4
+ constructor(apiKey: string);
5
+ isAvailable(): boolean;
6
+ getName(): string;
7
+ generateStructured<T>(systemPrompt: string, userInput: string, schema: object, options?: {
8
+ thinkingBudget?: number;
9
+ maxOutputTokens?: number;
10
+ modelOverride?: string;
11
+ }): Promise<GenerateResult<T>>;
12
+ generate(prompt: string): Promise<string | null>;
13
+ ping(): Promise<boolean>;
14
+ }
15
+ export declare class GeminiEmbeddingProvider implements EmbeddingProvider {
16
+ private genAI;
17
+ private readonly embModel;
18
+ constructor(apiKey: string);
19
+ isAvailable(): boolean;
20
+ embed(text: string): Promise<number[] | null>;
21
+ }
22
+ //# sourceMappingURL=gemini.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../../src/engine/providers/gemini.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAkBxF,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,KAAK,CAA4B;gBAE7B,MAAM,EAAE,MAAM;IAI1B,WAAW,IAAI,OAAO;IACtB,OAAO,IAAI,MAAM;IAEX,kBAAkB,CAAC,CAAC,EACxB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GACtF,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IAmIvB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAgBhD,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;CAG/B;AAED,qBAAa,uBAAwB,YAAW,iBAAiB;IAC/D,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiE;gBAE9E,MAAM,EAAE,MAAM;IAI1B,WAAW,IAAI,OAAO;IAEhB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;CAiBpD"}
@@ -0,0 +1,180 @@
1
+ import { GoogleGenerativeAI } from "@google/generative-ai";
2
+ import { EmptyResponseError, classifyGenError, isEmptyResult, withTimeout, llmTimeoutMs, decideEmptyOrTimeoutAction, isInsufficientCreditError } from "./failure-policy.js";
3
+ // Default + fallback model resolved LIVE from env per call. A const frozen at
4
+ // MODULE LOAD would ignore a web-UI / config-endpoint model change until a full
5
+ // restart (resetProviders can't refresh a module-level const) — so these are
6
+ // functions read at call time.
7
+ function primaryModel() {
8
+ return process.env.AI_MODEL ?? process.env.NODEDEX_PRIMARY_MODEL ?? "gemini-2.5-flash";
9
+ }
10
+ function fallbackModel() {
11
+ return process.env.NODEDEX_FALLBACK_MODEL ?? "gemini-2.5-pro";
12
+ }
13
+ // Failure handling (timeout bound, empty-detection, failure classification) is now
14
+ // shared across all providers — see ./failure-policy.ts. The 180s call bound
15
+ // (debt-4 Stage A) lives there as llmTimeoutMs() / withTimeout().
16
+ export class GeminiProvider {
17
+ genAI;
18
+ constructor(apiKey) {
19
+ this.genAI = apiKey ? new GoogleGenerativeAI(apiKey) : null;
20
+ }
21
+ isAvailable() { return this.genAI !== null; }
22
+ getName() { return "gemini"; }
23
+ async generateStructured(systemPrompt, userInput, schema, options) {
24
+ if (!this.genAI)
25
+ return { result: null, rateLimited: false };
26
+ const primary = primaryModel(), fallback = fallbackModel();
27
+ const modelsToTry = options?.modelOverride
28
+ ? [options.modelOverride]
29
+ : primary === fallback ? [primary] : [primary, fallback];
30
+ const attempts = [];
31
+ for (let i = 0; i < modelsToTry.length; i++) {
32
+ const modelName = modelsToTry[i];
33
+ const isFallback = i > 0;
34
+ // gemini-2.5-pro requires non-zero thinking budget
35
+ const budget = isFallback
36
+ ? Math.max(512, options?.thinkingBudget ?? 0)
37
+ : (options?.thinkingBudget ?? 0);
38
+ const genConfig = {
39
+ thinkingConfig: { thinkingBudget: budget },
40
+ responseMimeType: "application/json",
41
+ responseSchema: schema,
42
+ };
43
+ if (options?.maxOutputTokens)
44
+ genConfig.maxOutputTokens = options.maxOutputTokens;
45
+ // Deterministic extraction → default temperature 0 (cuts run-to-run variance).
46
+ // Gemini thinking models accept temperature. Configurable via NODEDEX_REFLECT_TEMPERATURE.
47
+ {
48
+ const tEnv = process.env.NODEDEX_REFLECT_TEMPERATURE;
49
+ genConfig.temperature = tEnv !== undefined && tEnv !== "" && Number.isFinite(Number(tEnv)) ? Number(tEnv) : 0;
50
+ }
51
+ const model = this.genAI.getGenerativeModel({
52
+ model: modelName,
53
+ systemInstruction: systemPrompt,
54
+ generationConfig: genConfig,
55
+ });
56
+ let emptyRetried = false;
57
+ while (true) {
58
+ try {
59
+ const response = await withTimeout(model.generateContent(userInput), llmTimeoutMs(), `generateStructured(${modelName})`);
60
+ const usageMeta = response.response.usageMetadata ?? {};
61
+ // Extract non-thinking output parts (pass3 reads thinking separately)
62
+ const parts = response.response.candidates?.[0]?.content?.parts ?? [];
63
+ const rawText = (parts.length > 0
64
+ ? parts.filter((p) => !p.thought).map((p) => p.text ?? "").join("")
65
+ : response.response.text()).trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/i, "").trim();
66
+ const thinking = parts
67
+ .filter((p) => p.thought === true)
68
+ .map((p) => p.text ?? "")
69
+ .join("\n")
70
+ .trim();
71
+ // EMPTY/HUNG guard BEFORE JSON.parse — a distinct failure (see ./failure-policy):
72
+ // JSON.parse("") would look like truncation; raise it explicitly so the catch
73
+ // retries/escalates instead of mislabeling it.
74
+ if (isEmptyResult(rawText))
75
+ throw new EmptyResponseError(modelName);
76
+ const result = JSON.parse(rawText);
77
+ attempts.push({ model: modelName, outcome: "ok" });
78
+ return {
79
+ result,
80
+ rateLimited: false,
81
+ thinking,
82
+ usage: {
83
+ input: usageMeta.promptTokenCount ?? 0,
84
+ thinking: usageMeta.thoughtsTokenCount ?? 0,
85
+ output: usageMeta.candidatesTokenCount ?? 0,
86
+ },
87
+ model: modelName,
88
+ attempts,
89
+ };
90
+ }
91
+ catch (e) {
92
+ // Out-of-credit (402) — surface DEFINITIVELY (see openai.ts): the reflect queue
93
+ // pauses-the-spend + requeues instead of swallowing it into a generic null.
94
+ if (isInsufficientCreditError(e)) {
95
+ attempts.push({ model: modelName, outcome: "error" });
96
+ console.error(`[gemini] ${modelName} insufficient credit (status=${e?.status ?? "?"}) — credit exhausted; not retrying/escalating (account unfunded)`);
97
+ return { result: null, rateLimited: false, creditExhausted: true, model: modelName, attempts };
98
+ }
99
+ const kind = classifyGenError(e);
100
+ const rateLimited = kind === "rate_limited";
101
+ const hasNextModel = i + 1 < modelsToTry.length;
102
+ // EMPTY/TIMEOUT → shared escalate-first policy (./failure-policy): a fallback
103
+ // model is the likeliest recovery for an input-specific empty (and skips the slow
104
+ // same-model draw); only a single-key setup retries the SAME model once.
105
+ if (kind === "empty" || kind === "timeout") {
106
+ const action = decideEmptyOrTimeoutAction({ kind, hasNextModel, emptyRetried });
107
+ attempts.push({ model: modelName, outcome: kind === "timeout" ? "timeout" : "empty" });
108
+ if (action === "escalate") {
109
+ console.warn(`[gemini] ${modelName} ${kind} — escalating to fallback`);
110
+ break; // exit while; outer for tries the next model
111
+ }
112
+ if (action === "retry_same") {
113
+ console.warn(`[gemini] ${modelName} returned EMPTY/hung response — no fallback; retrying same model once`);
114
+ emptyRetried = true;
115
+ continue; // retry same model
116
+ }
117
+ if (kind === "timeout") {
118
+ console.error(`[gemini] generateStructured TIMEOUT (${modelName}): ${llmTimeoutMs()}ms — pipeline continues, request may still be running at provider`);
119
+ }
120
+ return { result: null, rateLimited: false, model: modelName, attempts };
121
+ }
122
+ // RATE-LIMIT / TRUNCATED → escalate to the next model if one remains, else degrade.
123
+ // (Truncation→fallback preserves gemini's long-standing behavior; openai's stricter
124
+ // same-model-only truncation policy is left provider-specific to keep this tight.)
125
+ attempts.push({ model: modelName, outcome: kind === "truncated" ? "truncated" :
126
+ rateLimited ? "rate_limited" : "error" });
127
+ if ((kind === "truncated" || rateLimited) && hasNextModel) {
128
+ console.warn(`[gemini] ${modelName} ${kind} — escalating to fallback`);
129
+ break; // exit while; outer for tries the next model
130
+ }
131
+ if (!rateLimited) {
132
+ console.error(`[gemini] generateStructured error (${modelName}): ${String(e?.message ?? e).slice(0, 300)}`);
133
+ }
134
+ return { result: null, rateLimited, model: modelName, attempts };
135
+ }
136
+ }
137
+ }
138
+ return { result: null, rateLimited: true, attempts };
139
+ }
140
+ async generate(prompt) {
141
+ if (!this.genAI)
142
+ return null;
143
+ try {
144
+ const primary = primaryModel();
145
+ const model = this.genAI.getGenerativeModel({ model: primary });
146
+ const result = await withTimeout(model.generateContent(prompt), llmTimeoutMs(), `generate(${primary})`);
147
+ return result.response.text().trim();
148
+ }
149
+ catch {
150
+ return null;
151
+ }
152
+ }
153
+ async ping() {
154
+ return (await this.generate("Say OK")) !== null;
155
+ }
156
+ }
157
+ export class GeminiEmbeddingProvider {
158
+ genAI;
159
+ embModel = process.env.NODEDEX_EMBEDDING_MODEL ?? "gemini-embedding-001";
160
+ constructor(apiKey) {
161
+ this.genAI = apiKey ? new GoogleGenerativeAI(apiKey) : null;
162
+ }
163
+ isAvailable() { return this.genAI !== null; }
164
+ async embed(text) {
165
+ if (!this.genAI)
166
+ return null;
167
+ try {
168
+ const model = this.genAI.getGenerativeModel({ model: this.embModel });
169
+ // Provider-level timeout: belt-and-suspenders with EmbeddingEngine.embed
170
+ // wrapper (which also times out at 30s + records stats). This catches
171
+ // direct provider calls if they ever happen without the engine.
172
+ const result = await withTimeout(model.embedContent(text), 30_000, `embed(${this.embModel})`);
173
+ return result.embedding.values;
174
+ }
175
+ catch {
176
+ return null;
177
+ }
178
+ }
179
+ }
180
+ //# sourceMappingURL=gemini.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../../src/engine/providers/gemini.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { LLMProvider, EmbeddingProvider } from "../ai-provider.js";
2
+ /** Returns the singleton LLM provider (lazy-initialized from env vars). */
3
+ export declare function getLLMProvider(): LLMProvider;
4
+ /** Returns the singleton embedding provider (lazy-initialized from env vars). */
5
+ export declare function getEmbeddingProvider(): EmbeddingProvider;
6
+ /** Reset singletons — used in tests after env var changes. */
7
+ export declare function resetProviders(): void;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAUxE,2EAA2E;AAC3E,wBAAgB,cAAc,IAAI,WAAW,CAoB5C;AAED,iFAAiF;AACjF,wBAAgB,oBAAoB,IAAI,iBAAiB,CAiCxD;AAED,8DAA8D;AAC9D,wBAAgB,cAAc,IAAI,IAAI,CAGrC"}
@@ -0,0 +1,67 @@
1
+ import { GeminiProvider, GeminiEmbeddingProvider } from "./gemini.js";
2
+ import { OpenAIProvider, OpenAIEmbeddingProvider } from "./openai.js";
3
+ import { AnthropicProvider } from "./anthropic.js";
4
+ import { LocalEmbeddingProvider } from "./local.js";
5
+ import { wrapWithUsageLedger } from "./usage-ledger.js";
6
+ let _llm = null;
7
+ let _embeddings = null;
8
+ /** Returns the singleton LLM provider (lazy-initialized from env vars). */
9
+ export function getLLMProvider() {
10
+ if (_llm)
11
+ return _llm;
12
+ const name = (process.env.AI_PROVIDER ?? "gemini").toLowerCase();
13
+ if (name === "openai" || name === "openai-compatible") {
14
+ _llm = new OpenAIProvider(process.env.OPENAI_API_KEY ?? "", process.env.OPENAI_BASE_URL);
15
+ }
16
+ else if (name === "anthropic") {
17
+ _llm = new AnthropicProvider(process.env.ANTHROPIC_API_KEY ?? "");
18
+ }
19
+ else {
20
+ _llm = new GeminiProvider(process.env.GEMINI_API_KEY ?? "");
21
+ }
22
+ // Meter every structured key call at the single seam — wrap once so the cached
23
+ // provider (and all callers) route generateStructured() through the usage ledger.
24
+ _llm = wrapWithUsageLedger(_llm);
25
+ return _llm;
26
+ }
27
+ /** Returns the singleton embedding provider (lazy-initialized from env vars). */
28
+ export function getEmbeddingProvider() {
29
+ if (_embeddings)
30
+ return _embeddings;
31
+ // Embeddings default to LOCAL (bundled bge-small, offline, $0, no key) when
32
+ // EMBEDDING_PROVIDER is unset — the shipped release default. A fresh install gets
33
+ // working semantic search with zero setup; set EMBEDDING_PROVIDER=gemini|openai|
34
+ // anthropic for hosted embeddings. (Decoupled from AI_PROVIDER on purpose: a chat
35
+ // model like owl/openai-compatible is a poor embedder.)
36
+ const embName = (process.env.EMBEDDING_PROVIDER ?? "local").toLowerCase();
37
+ if (embName === "local") {
38
+ // Local, free, offline embeddings (transformers.js) — no API/quota.
39
+ _embeddings = new LocalEmbeddingProvider();
40
+ }
41
+ else if (embName === "openai" || embName === "openai-compatible") {
42
+ _embeddings = new OpenAIEmbeddingProvider(process.env.OPENAI_API_KEY ?? "", process.env.OPENAI_BASE_URL);
43
+ }
44
+ else if (embName === "anthropic") {
45
+ // Anthropic has no embeddings API — cascade to Gemini, then OpenAI
46
+ if (process.env.GEMINI_API_KEY) {
47
+ _embeddings = new GeminiEmbeddingProvider(process.env.GEMINI_API_KEY);
48
+ }
49
+ else if (process.env.OPENAI_API_KEY) {
50
+ _embeddings = new OpenAIEmbeddingProvider(process.env.OPENAI_API_KEY);
51
+ }
52
+ else {
53
+ _embeddings = { embed: async () => null, isAvailable: () => false };
54
+ }
55
+ }
56
+ else {
57
+ // gemini (default)
58
+ _embeddings = new GeminiEmbeddingProvider(process.env.GEMINI_API_KEY ?? "");
59
+ }
60
+ return _embeddings;
61
+ }
62
+ /** Reset singletons — used in tests after env var changes. */
63
+ export function resetProviders() {
64
+ _llm = null;
65
+ _embeddings = null;
66
+ }
67
+ //# sourceMappingURL=index.js.map