@snoai/memory 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (478) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +7 -2
  3. package/config/b-profile-section-registry.json +118 -0
  4. package/config/llm/compiled/2026-05-19T230932Z/manifest.json +25 -0
  5. package/config/llm/compiled/2026-05-19T230932Z/registry-root.json +67 -0
  6. package/config/llm/compiled/2026-05-19T230932Z/resolved/mem_claw/openai_gpt_5_nano.json +5 -0
  7. package/config/llm/compiled/2026-05-19T230932Z/resolved/mem_claw/openrouter_auto.json +5 -0
  8. package/config/llm/compiled/2026-05-19T230932Z/resolved/mem_claw/sno_ai_extract.json +5 -0
  9. package/config/llm/compiled/2026-05-19T230932Z/source/mem_claw/openai_gpt_5_nano.mda +24 -0
  10. package/config/llm/compiled/2026-05-19T230932Z/source/mem_claw/openrouter_auto.mda +24 -0
  11. package/config/llm/compiled/2026-05-19T230932Z/source/mem_claw/sno_ai_extract.mda +24 -0
  12. package/config/llm/compiled/2026-07-21T001311Z/manifest.json +43 -0
  13. package/config/llm/compiled/2026-07-21T001311Z/registry-root.json +97 -0
  14. package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/openai_gpt_5_nano.json +5 -0
  15. package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/openrouter_auto.json +5 -0
  16. package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/sno_ai_extract.json +5 -0
  17. package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/sno_conflict_verdict.json +10 -0
  18. package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/sno_extract_chat.json +10 -0
  19. package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/sno_extract_profile.json +10 -0
  20. package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/openai_gpt_5_nano.mda +24 -0
  21. package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/openrouter_auto.mda +24 -0
  22. package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/sno_ai_extract.mda +24 -0
  23. package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/sno_conflict_verdict.mda +27 -0
  24. package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/sno_extract_chat.mda +27 -0
  25. package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/sno_extract_profile.mda +27 -0
  26. package/config/llm/compiled/2026-08-29T060335Z/manifest.json +43 -0
  27. package/config/llm/compiled/2026-08-29T060335Z/registry-root.json +97 -0
  28. package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/openai_gpt_5_nano.json +5 -0
  29. package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/openrouter_auto.json +5 -0
  30. package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/sno_ai_extract.json +5 -0
  31. package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/sno_conflict_verdict.json +10 -0
  32. package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/sno_extract_chat.json +10 -0
  33. package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/sno_extract_profile.json +10 -0
  34. package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/openai_gpt_5_nano.mda +24 -0
  35. package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/openrouter_auto.mda +24 -0
  36. package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/sno_ai_extract.mda +24 -0
  37. package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/sno_conflict_verdict.mda +27 -0
  38. package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/sno_extract_chat.mda +27 -0
  39. package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/sno_extract_profile.mda +27 -0
  40. package/config/llm/compiled/2026-09-04T004828Z/manifest.json +43 -0
  41. package/config/llm/compiled/2026-09-04T004828Z/registry-root.json +97 -0
  42. package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/openai_gpt_5_nano.json +5 -0
  43. package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/openrouter_auto.json +5 -0
  44. package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/sno_ai_extract.json +5 -0
  45. package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/sno_conflict_verdict.json +10 -0
  46. package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/sno_extract_chat.json +10 -0
  47. package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/sno_extract_profile.json +10 -0
  48. package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/openai_gpt_5_nano.mda +24 -0
  49. package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/openrouter_auto.mda +24 -0
  50. package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/sno_ai_extract.mda +24 -0
  51. package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/sno_conflict_verdict.mda +27 -0
  52. package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/sno_extract_chat.mda +27 -0
  53. package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/sno_extract_profile.mda +27 -0
  54. package/config/llm/current.json +4 -0
  55. package/config/llm/source/mem_claw/openai_gpt_5_nano.mda +24 -0
  56. package/config/llm/source/mem_claw/openrouter_auto.mda +24 -0
  57. package/config/llm/source/mem_claw/sno_ai_extract.mda +24 -0
  58. package/config/llm/source/mem_claw/sno_conflict_verdict.mda +27 -0
  59. package/config/llm/source/mem_claw/sno_extract_chat.mda +27 -0
  60. package/config/llm/source/mem_claw/sno_extract_profile.mda +27 -0
  61. package/config/llm.trust.json +37 -0
  62. package/dist/_types-CUKHSRkS.d.ts +103 -0
  63. package/dist/access-tracker-CSc21GtV.d.ts +110 -0
  64. package/dist/adapter-DMEmCTKo.d.ts +69 -0
  65. package/dist/adapter-XaRHZWZ2.js +333 -0
  66. package/dist/agent-llm-port-5oXgBpzJ.d.ts +53 -0
  67. package/dist/all-resources-BQK2ugjB.js +6379 -0
  68. package/dist/all-resources-Dij6l5h0.d.ts +18 -0
  69. package/dist/ambient-learning-text-normalizer-CxjATmMp.js +170 -0
  70. package/dist/ambient-learning-text-normalizer-_fH3LeuK.d.ts +10 -0
  71. package/dist/atomic-extraction-reply-BJ9XV_9s.js +863 -0
  72. package/dist/atomic-extraction-skill-CcXmuCqL.js +56 -0
  73. package/dist/atomic-memory-extraction-BpOUWPJM.d.ts +327 -0
  74. package/dist/atomic-memory-extraction-sdNf1-B1.js +3605 -0
  75. package/dist/b-profile-section-dictionary-provider-BHkoNqgk.js +1812 -0
  76. package/dist/b-profile-section-dictionary-provider-BxbksLj3.d.ts +62 -0
  77. package/dist/best-effort-BPZSzKk0.d.ts +9 -0
  78. package/dist/calendar-instruction-CzqZbAPG.js +194 -0
  79. package/dist/capture-policy-detector-CHz5GOPA.d.ts +53 -0
  80. package/dist/capture-policy-detector-DaMfy9CZ.js +357 -0
  81. package/dist/classifier-C96uH9OF.d.ts +272 -0
  82. package/dist/client.d.ts +34 -0
  83. package/dist/client.js +305 -0
  84. package/dist/coding-skin.d.ts +51 -0
  85. package/dist/coding-skin.js +55 -0
  86. package/dist/config-tSrvLXgV.js +2577 -0
  87. package/dist/connection-DAbzki8K.d.ts +391 -0
  88. package/dist/connection-DliCOBB2.js +297 -0
  89. package/dist/daily-log-generator-CH_KuWHs.js +469 -0
  90. package/dist/daily-log-generator-CsQPHl4A.d.ts +73 -0
  91. package/dist/daily-spend-estimator-DiwzBlo1.d.ts +8 -0
  92. package/dist/data-bootstrap-CYniFp8b.js +172 -0
  93. package/dist/data-bootstrap-CcJUwkqf.d.ts +30 -0
  94. package/dist/data-paths-C7sNdqvP.d.ts +22 -0
  95. package/dist/derived-suppression-cache-C7bGARc0.d.ts +36 -0
  96. package/dist/diagnostic-encoder.d.ts +6 -0
  97. package/dist/diagnostic-encoder.js +29 -0
  98. package/dist/embedding-provider-client-Q_hJonK9.js +294 -0
  99. package/dist/embedding-provider-client-vynZMuit.d.ts +94 -0
  100. package/dist/entry-metadata-parser-BIVSMCIk.js +20 -0
  101. package/dist/error-D-wb-rZw.js +23 -0
  102. package/dist/error-signals-D8_3vYu4.d.ts +28 -0
  103. package/dist/error-signals-lMH2uAdV.js +134 -0
  104. package/dist/errors-CeVRxf9V.d.ts +49 -0
  105. package/dist/extraction-text-sanitizer-B_AhIecT.d.ts +32 -0
  106. package/dist/i18n-text-DbD6Qify.d.ts +13 -0
  107. package/dist/index-BsMap4It.d.ts +650 -0
  108. package/dist/index-DL8AVj0Z.d.ts +571 -0
  109. package/dist/index-DQ7VL6d3.d.ts +350 -0
  110. package/dist/index.d.ts +65 -0
  111. package/dist/index.js +1201 -0
  112. package/dist/intent-analyzer-B5XVrWwe.d.ts +28 -0
  113. package/dist/internal/config/index.d.ts +2 -0
  114. package/dist/internal/config/index.js +581 -0
  115. package/dist/internal/config/plugin-config-schema.d.ts +2 -0
  116. package/dist/internal/config/plugin-config-schema.js +2 -0
  117. package/dist/internal/config/product-mode.d.ts +2 -0
  118. package/dist/internal/config/product-mode.js +36 -0
  119. package/dist/internal/config/settings.d.ts +2 -0
  120. package/dist/internal/config/settings.js +265 -0
  121. package/dist/internal/config/skill-categories.d.ts +4 -0
  122. package/dist/internal/config/skill-categories.js +68 -0
  123. package/dist/internal/config/skin-defaults.d.ts +6 -0
  124. package/dist/internal/config/skin-defaults.js +6 -0
  125. package/dist/internal/contract/discovery.d.ts +10 -0
  126. package/dist/internal/contract/discovery.js +53 -0
  127. package/dist/internal/contract/profile.d.ts +2 -0
  128. package/dist/internal/contract/profile.js +44 -0
  129. package/dist/internal/contract/routes.d.ts +2 -0
  130. package/dist/internal/contract/routes.js +61 -0
  131. package/dist/internal/engine/bindings/memory-cli-shared.d.ts +47 -0
  132. package/dist/internal/engine/bindings/memory-cli-shared.js +84 -0
  133. package/dist/internal/engine/bindings/memory-forget-tool.d.ts +5 -0
  134. package/dist/internal/engine/bindings/memory-forget-tool.js +66 -0
  135. package/dist/internal/engine/bindings/memory-list-tool.d.ts +5 -0
  136. package/dist/internal/engine/bindings/memory-list-tool.js +57 -0
  137. package/dist/internal/engine/bindings/memory-recall-tool.d.ts +10 -0
  138. package/dist/internal/engine/bindings/memory-recall-tool.js +283 -0
  139. package/dist/internal/engine/bindings/memory-reflection-resolve-tool.d.ts +5 -0
  140. package/dist/internal/engine/bindings/memory-reflection-resolve-tool.js +150 -0
  141. package/dist/internal/engine/bindings/memory-stats-tool.d.ts +5 -0
  142. package/dist/internal/engine/bindings/memory-stats-tool.js +43 -0
  143. package/dist/internal/engine/bindings/memory-store-tool.d.ts +5 -0
  144. package/dist/internal/engine/bindings/memory-store-tool.js +165 -0
  145. package/dist/internal/engine/bindings/memory-tool-access.d.ts +16 -0
  146. package/dist/internal/engine/bindings/memory-tool-access.js +46 -0
  147. package/dist/internal/engine/bindings/memory-tool-formatting.d.ts +62 -0
  148. package/dist/internal/engine/bindings/memory-tool-formatting.js +106 -0
  149. package/dist/internal/engine/bindings/memory-tool-results.d.ts +8 -0
  150. package/dist/internal/engine/bindings/memory-tool-results.js +41 -0
  151. package/dist/internal/engine/bindings/memory-tool-schemas.d.ts +109 -0
  152. package/dist/internal/engine/bindings/memory-tool-schemas.js +75 -0
  153. package/dist/internal/engine/bindings/memory-update-tool.d.ts +5 -0
  154. package/dist/internal/engine/bindings/memory-update-tool.js +127 -0
  155. package/dist/internal/engine/bindings/sno-station-mem-ambient-learning-hook.d.ts +14 -0
  156. package/dist/internal/engine/bindings/sno-station-mem-ambient-learning-hook.js +248 -0
  157. package/dist/internal/engine/bindings/sno-station-mem-auto-recall-hook.d.ts +12 -0
  158. package/dist/internal/engine/bindings/sno-station-mem-auto-recall-hook.js +324 -0
  159. package/dist/internal/engine/bindings/sno-station-mem-hook-types.d.ts +56 -0
  160. package/dist/internal/engine/bindings/sno-station-mem-hook-types.js +1 -0
  161. package/dist/internal/engine/bindings/sno-station-mem-insight-distill-factory.d.ts +14 -0
  162. package/dist/internal/engine/bindings/sno-station-mem-insight-distill-factory.js +119 -0
  163. package/dist/internal/engine/bindings/sno-station-mem-message-transcript.d.ts +52 -0
  164. package/dist/internal/engine/bindings/sno-station-mem-message-transcript.js +145 -0
  165. package/dist/internal/engine/bindings/sno-station-mem-reset-hook.d.ts +10 -0
  166. package/dist/internal/engine/bindings/sno-station-mem-reset-hook.js +9 -0
  167. package/dist/internal/engine/bindings/sno-station-mem-runtime-mode.d.ts +37 -0
  168. package/dist/internal/engine/bindings/sno-station-mem-runtime-mode.js +105 -0
  169. package/dist/internal/engine/bindings/sno-station-mem-session-state.d.ts +10 -0
  170. package/dist/internal/engine/bindings/sno-station-mem-session-state.js +27 -0
  171. package/dist/internal/engine/eval/trace.d.ts +2 -0
  172. package/dist/internal/engine/eval/trace.js +151 -0
  173. package/dist/internal/engine/extraction/ambient-learning-text-normalizer.d.ts +2 -0
  174. package/dist/internal/engine/extraction/ambient-learning-text-normalizer.js +2 -0
  175. package/dist/internal/engine/extraction/atomic-memory-extraction.d.ts +2 -0
  176. package/dist/internal/engine/extraction/atomic-memory-extraction.js +2 -0
  177. package/dist/internal/engine/extraction/b-profile-section-dictionary-provider.d.ts +2 -0
  178. package/dist/internal/engine/extraction/b-profile-section-dictionary-provider.js +2 -0
  179. package/dist/internal/engine/extraction/b-profile-section-rekey.d.ts +49 -0
  180. package/dist/internal/engine/extraction/b-profile-section-rekey.js +730 -0
  181. package/dist/internal/engine/extraction/capture-policy-detector.d.ts +2 -0
  182. package/dist/internal/engine/extraction/capture-policy-detector.js +2 -0
  183. package/dist/internal/engine/extraction/embedding-provider-client.d.ts +2 -0
  184. package/dist/internal/engine/extraction/embedding-provider-client.js +2 -0
  185. package/dist/internal/engine/extraction/extraction-text-sanitizer.d.ts +2 -0
  186. package/dist/internal/engine/extraction/extraction-text-sanitizer.js +114 -0
  187. package/dist/internal/engine/extraction/memory-metadata-codec.d.ts +3 -0
  188. package/dist/internal/engine/extraction/memory-metadata-codec.js +2 -0
  189. package/dist/internal/engine/extraction/memory-temporality-classifier.d.ts +2 -0
  190. package/dist/internal/engine/extraction/memory-temporality-classifier.js +2 -0
  191. package/dist/internal/engine/i18n/all-resources.d.ts +2 -0
  192. package/dist/internal/engine/i18n/all-resources.js +2 -0
  193. package/dist/internal/engine/i18n/locales.d.ts +2 -0
  194. package/dist/internal/engine/i18n/locales.js +19 -0
  195. package/dist/internal/engine/i18n/res/_types.d.ts +2 -0
  196. package/dist/internal/engine/i18n/res/_types.js +11 -0
  197. package/dist/internal/engine/observability/adapter.d.ts +2 -0
  198. package/dist/internal/engine/observability/adapter.js +2 -0
  199. package/dist/internal/engine/observability/best-effort.d.ts +2 -0
  200. package/dist/internal/engine/observability/best-effort.js +41 -0
  201. package/dist/internal/engine/observability/early-diagnostics.js +2 -0
  202. package/dist/internal/engine/observability/memory-snapshot.d.ts +2 -0
  203. package/dist/internal/engine/observability/memory-snapshot.js +44 -0
  204. package/dist/internal/engine/observability/observable-embedder.d.ts +2 -0
  205. package/dist/internal/engine/observability/observable-embedder.js +43 -0
  206. package/dist/internal/engine/observability/observable-llm-client.d.ts +2 -0
  207. package/dist/internal/engine/observability/observable-llm-client.js +98 -0
  208. package/dist/internal/engine/observability/observable-memory-store.d.ts +2 -0
  209. package/dist/internal/engine/observability/observable-memory-store.js +701 -0
  210. package/dist/internal/engine/observability/observable-retriever.d.ts +2 -0
  211. package/dist/internal/engine/observability/observable-retriever.js +95 -0
  212. package/dist/internal/engine/observability/runtime-diagnostics.d.ts +13 -0
  213. package/dist/internal/engine/observability/runtime-diagnostics.js +96 -0
  214. package/dist/internal/engine/observability/session-registry.d.ts +2 -0
  215. package/dist/internal/engine/observability/session-registry.js +58 -0
  216. package/dist/internal/engine/observability/version-metadata.d.ts +7 -0
  217. package/dist/internal/engine/observability/version-metadata.js +59 -0
  218. package/dist/internal/engine/operations/daily-spend-estimator.d.ts +2 -0
  219. package/dist/internal/engine/operations/daily-spend-estimator.js +97 -0
  220. package/dist/internal/engine/operations/learning-file-maintenance.d.ts +2 -0
  221. package/dist/internal/engine/operations/learning-file-maintenance.js +255 -0
  222. package/dist/internal/engine/operations/memory-tier-promoter.d.ts +2 -0
  223. package/dist/internal/engine/operations/memory-tier-promoter.js +95 -0
  224. package/dist/internal/engine/operations/runtime-audit-log.d.ts +3 -0
  225. package/dist/internal/engine/operations/runtime-audit-log.js +3 -0
  226. package/dist/internal/engine/provider/canonical-memory-corpus.d.ts +38 -0
  227. package/dist/internal/engine/provider/canonical-memory-corpus.js +253 -0
  228. package/dist/internal/engine/provider/provider-registration.d.ts +39 -0
  229. package/dist/internal/engine/provider/provider-registration.js +2 -0
  230. package/dist/internal/engine/provider/provider-row-renderer.d.ts +7 -0
  231. package/dist/internal/engine/provider/provider-row-renderer.js +53 -0
  232. package/dist/internal/engine/provider/provider-types.d.ts +2 -0
  233. package/dist/internal/engine/provider/provider-types.js +1 -0
  234. package/dist/internal/engine/reflection/daily-log-generator.d.ts +2 -0
  235. package/dist/internal/engine/reflection/daily-log-generator.js +2 -0
  236. package/dist/internal/engine/reflection/reflection-command-hooks.d.ts +2 -0
  237. package/dist/internal/engine/reflection/reflection-command-hooks.js +2 -0
  238. package/dist/internal/engine/reflection/reflection-deps.d.ts +2 -0
  239. package/dist/internal/engine/reflection/reflection-deps.js +1 -0
  240. package/dist/internal/engine/reflection/reflection-embedded-generator.d.ts +2 -0
  241. package/dist/internal/engine/reflection/reflection-embedded-generator.js +2 -0
  242. package/dist/internal/engine/reflection/reflection-injection-hooks.d.ts +2 -0
  243. package/dist/internal/engine/reflection/reflection-injection-hooks.js +219 -0
  244. package/dist/internal/engine/reflection/reflection-lifecycle-hooks.d.ts +2 -0
  245. package/dist/internal/engine/reflection/reflection-lifecycle-hooks.js +63 -0
  246. package/dist/internal/engine/reflection/strategy-hook-runner.d.ts +4 -0
  247. package/dist/internal/engine/reflection/strategy-hook-runner.js +3 -0
  248. package/dist/internal/engine/rem/classifier.d.ts +2 -0
  249. package/dist/internal/engine/rem/classifier.js +180 -0
  250. package/dist/internal/engine/rem/index.d.ts +4 -0
  251. package/dist/internal/engine/rem/index.js +2551 -0
  252. package/dist/internal/engine/rem/types.d.ts +2 -0
  253. package/dist/internal/engine/rem/types.js +40 -0
  254. package/dist/internal/engine/retrieval/access-tracker.d.ts +2 -0
  255. package/dist/internal/engine/retrieval/access-tracker.js +314 -0
  256. package/dist/internal/engine/retrieval/intent-analyzer.d.ts +2 -0
  257. package/dist/internal/engine/retrieval/intent-analyzer.js +27 -0
  258. package/dist/internal/engine/retrieval/retrieval-gate.d.ts +2 -0
  259. package/dist/internal/engine/retrieval/retrieval-gate.js +47 -0
  260. package/dist/internal/engine/retrieval/retriever.d.ts +2 -0
  261. package/dist/internal/engine/retrieval/retriever.js +2 -0
  262. package/dist/internal/engine/security/memory-scope-policy.d.ts +2 -0
  263. package/dist/internal/engine/security/memory-scope-policy.js +2 -0
  264. package/dist/internal/engine/security/redact.d.ts +2 -0
  265. package/dist/internal/engine/security/redact.js +34 -0
  266. package/dist/internal/engine/security/scopes.d.ts +3 -0
  267. package/dist/internal/engine/security/scopes.js +3 -0
  268. package/dist/internal/engine/shared/errors.d.ts +2 -0
  269. package/dist/internal/engine/shared/errors.js +66 -0
  270. package/dist/internal/engine/shared/i18n-text.d.ts +2 -0
  271. package/dist/internal/engine/shared/i18n-text.js +58 -0
  272. package/dist/internal/engine/shared/iso-date-time.d.ts +16 -0
  273. package/dist/internal/engine/shared/iso-date-time.js +40 -0
  274. package/dist/internal/engine/shared/lru.d.ts +2 -0
  275. package/dist/internal/engine/shared/lru.js +30 -0
  276. package/dist/internal/engine/shared/memory-kind-policy.d.ts +2 -0
  277. package/dist/internal/engine/shared/memory-kind-policy.js +64 -0
  278. package/dist/internal/engine/shared/paths.d.ts +3 -0
  279. package/dist/internal/engine/shared/paths.js +2 -0
  280. package/dist/internal/engine/shared/types.d.ts +3 -0
  281. package/dist/internal/engine/shared/types.js +25 -0
  282. package/dist/internal/engine/shared/utils.d.ts +2 -0
  283. package/dist/internal/engine/shared/utils.js +175 -0
  284. package/dist/internal/engine/telemetry/memory-telemetry-api.d.ts +134 -0
  285. package/dist/internal/engine/telemetry/memory-telemetry-api.js +730 -0
  286. package/dist/internal/engine/telemetry/memory-telemetry-observability.d.ts +24 -0
  287. package/dist/internal/engine/telemetry/memory-telemetry-observability.js +133 -0
  288. package/dist/internal/engine/telemetry/memory-telemetry-outbox.d.ts +2 -0
  289. package/dist/internal/engine/telemetry/memory-telemetry-outbox.js +443 -0
  290. package/dist/internal/engine/telemetry/memory-telemetry-types.d.ts +2 -0
  291. package/dist/internal/engine/telemetry/memory-telemetry-types.js +21 -0
  292. package/dist/internal/engine/telemetry/observe-ledger.d.ts +30 -0
  293. package/dist/internal/engine/telemetry/observe-ledger.js +111 -0
  294. package/dist/internal/model/agent-llm-port.d.ts +2 -0
  295. package/dist/internal/model/agent-llm-port.js +1 -0
  296. package/dist/internal/model/llm-client.d.ts +3 -0
  297. package/dist/internal/model/llm-client.js +3 -0
  298. package/dist/internal/model/llm-failure.d.ts +26 -0
  299. package/dist/internal/model/llm-failure.js +63 -0
  300. package/dist/internal/model/llm-mode-routing.d.ts +22 -0
  301. package/dist/internal/model/llm-mode-routing.js +37 -0
  302. package/dist/internal/store/atomic-memory-cutover-sql.d.ts +13 -0
  303. package/dist/internal/store/atomic-memory-cutover-sql.js +237 -0
  304. package/dist/internal/store/connection.d.ts +2 -0
  305. package/dist/internal/store/connection.js +2 -0
  306. package/dist/internal/store/data-bootstrap.d.ts +2 -0
  307. package/dist/internal/store/data-bootstrap.js +2 -0
  308. package/dist/internal/store/data-paths.d.ts +2 -0
  309. package/dist/internal/store/data-paths.js +65 -0
  310. package/dist/internal/store/maintenance.d.ts +75 -0
  311. package/dist/internal/store/maintenance.js +1401 -0
  312. package/dist/internal/store/memory-kinds-cutover-migrator.d.ts +28 -0
  313. package/dist/internal/store/memory-kinds-cutover-migrator.js +415 -0
  314. package/dist/internal/store/migrations.d.ts +27 -0
  315. package/dist/internal/store/migrations.js +201 -0
  316. package/dist/internal/store/sqlite-runtime.d.ts +2 -0
  317. package/dist/internal/store/sqlite-runtime.js +109 -0
  318. package/dist/internal/store/store.d.ts +3 -0
  319. package/dist/internal/store/store.js +2 -0
  320. package/dist/learning-file-maintenance-9b-Ut6Kv.d.ts +30 -0
  321. package/dist/llm-client-B7Xoxqou.js +1378 -0
  322. package/dist/llm-client-DOTSGzhe.d.ts +51 -0
  323. package/dist/locales-JxGmkG6t.d.ts +7 -0
  324. package/dist/log-site-catalog.generated-B9WYdnAM.js +2321 -0
  325. package/dist/log-site-catalog.json +1 -0
  326. package/dist/lru-DyoaTyIs.d.ts +14 -0
  327. package/dist/memdump.d.ts +52 -0
  328. package/dist/memdump.js +163 -0
  329. package/dist/memory-entry-projector-DHo8jH10.js +1015 -0
  330. package/dist/memory-kind-policy-LKt0u3gy.d.ts +23 -0
  331. package/dist/memory-metadata-codec-C3oQd47V.d.ts +68 -0
  332. package/dist/memory-metadata-codec-DL1sbJiN.js +577 -0
  333. package/dist/memory-runtime-BZtREuwW.js +19459 -0
  334. package/dist/memory-scope-policy-1gg5QlWZ.d.ts +67 -0
  335. package/dist/memory-scope-policy-DICSCURA.js +283 -0
  336. package/dist/memory-snapshot-3e44ND2i.d.ts +16 -0
  337. package/dist/memory-source-order-BtrIxaIt.js +134 -0
  338. package/dist/memory-store-base-XRA4S9Xl.d.ts +1095 -0
  339. package/dist/memory-store-shared-DeIDkhLj.js +158 -0
  340. package/dist/memory-store-write-validation-B_hDG2zf.js +243 -0
  341. package/dist/memory-telemetry-incidents-BWA9kcZx.js +8 -0
  342. package/dist/memory-telemetry-metadata-CA7W8tK6.js +77 -0
  343. package/dist/memory-telemetry-outbox-ddTdImt7.d.ts +74 -0
  344. package/dist/memory-telemetry-receipts-MAJecvXQ.d.ts +34 -0
  345. package/dist/memory-telemetry-receipts-YsxbwOAf.js +91 -0
  346. package/dist/memory-telemetry-types-CufVmrCs.d.ts +14 -0
  347. package/dist/memory-temporality-classifier-CEdRTN5J.d.ts +43 -0
  348. package/dist/memory-temporality-classifier-CKiTAHXe.js +184 -0
  349. package/dist/memory-tier-promoter-DbTpahkP.d.ts +43 -0
  350. package/dist/memory-tool-dependencies-CLODycUw.js +19 -0
  351. package/dist/memory-tool-dependencies-N69chrQc.d.ts +14 -0
  352. package/dist/model-call-table-CspopkBg.js +563 -0
  353. package/dist/model-reply-text-CKopStP2.js +334 -0
  354. package/dist/observable-embedder-DQnNgf9O.d.ts +17 -0
  355. package/dist/observable-llm-client-uwqPADpN.d.ts +21 -0
  356. package/dist/observable-memory-store-BaZKbhgq.d.ts +73 -0
  357. package/dist/observable-retriever-Dt_NUxAA.d.ts +23 -0
  358. package/dist/operation-cancellation-CTKWwNHk.js +81 -0
  359. package/dist/paths-qVF-5uBq.d.ts +1 -0
  360. package/dist/plugin-config-schema-C0UUbOmG.d.ts +413 -0
  361. package/dist/plugin-config-schema-YJLyIIcJ.js +361 -0
  362. package/dist/profile-TWPJ_myr.d.ts +13 -0
  363. package/dist/profile-section-writer-hIphqpUY.js +2149 -0
  364. package/dist/provider-registration-CF1tg8Xy.js +721 -0
  365. package/dist/provider-runtime-types-DFhtdA6d.d.ts +134 -0
  366. package/dist/provider-types-CZGm6v88.d.ts +23 -0
  367. package/dist/redact-BTIZcHQL.d.ts +5 -0
  368. package/dist/reflection-command-hooks-BeQiJI9-.js +644 -0
  369. package/dist/reflection-command-hooks-C1Vxgb-O.d.ts +32 -0
  370. package/dist/reflection-deps-RpLPFrSc.d.ts +19 -0
  371. package/dist/reflection-embedded-generator-CDUhgV96.js +130 -0
  372. package/dist/reflection-embedded-generator-CxOex5xK.d.ts +14 -0
  373. package/dist/reflection-injection-hooks-DfUgqu8f.d.ts +43 -0
  374. package/dist/reflection-lifecycle-hooks-Ct5HBdSG.d.ts +27 -0
  375. package/dist/relation-dictionary-Cev1kyLe.js +4248 -0
  376. package/dist/release-download.d.ts +8 -0
  377. package/dist/release-download.js +32 -0
  378. package/dist/relevant-memories-context-m8nuFZcM.js +23 -0
  379. package/dist/rem-batch-executor-Cbm5gfSe.js +31644 -0
  380. package/dist/rem-batch-executor-bc0IFlp2.js +2 -0
  381. package/dist/rem-consumer-retrieval-CRpvG8KS.js +246 -0
  382. package/dist/rem-trigger-BTxkcjgT.js +729 -0
  383. package/dist/resolver-Dy-hnjCR.js +103 -0
  384. package/dist/results-C3ZLroMb.js +140 -0
  385. package/dist/retrieval-gate-Bx2Zg7jD.d.ts +31 -0
  386. package/dist/retriever-CygHBazG.js +1757 -0
  387. package/dist/retriever-Ruk3zp7_.d.ts +469 -0
  388. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  389. package/dist/routes-Ce7SQKec.js +59 -0
  390. package/dist/runtime-audit-log-BCeujlEp.js +430 -0
  391. package/dist/runtime-audit-log-zpQiR9HT.d.ts +149 -0
  392. package/dist/scopes-CSOn6zdd.js +71 -0
  393. package/dist/scopes-CtrY-YQ3.d.ts +23 -0
  394. package/dist/server-BPAY4NTG.js +1410 -0
  395. package/dist/session-registry-DBoE7AvZ.d.ts +14 -0
  396. package/dist/sidecar/main.d.ts +1 -0
  397. package/dist/sidecar/main.js +56 -0
  398. package/dist/signed-registry-constants-Bv0fgZ8Q.d.ts +12 -0
  399. package/dist/signed-registry-constants-yq3DlG3B.js +82 -0
  400. package/dist/sno-station-mem-runtime-dependencies-Bu-MiqPX.d.ts +31 -0
  401. package/dist/sno-station-mem-runtime-dependencies-DjLOhB45.js +30 -0
  402. package/dist/sqlite-runtime-L_ywirTm.d.ts +58 -0
  403. package/dist/store-2pM0-dZg.d.ts +27 -0
  404. package/dist/store-DzpZBMEm.js +5830 -0
  405. package/dist/strategy-hook-runner-gBtU47tX.d.ts +16 -0
  406. package/dist/strategy-hook-runner-zmdIYOmQ.js +110 -0
  407. package/dist/token-counter-BD1f48Km.js +73 -0
  408. package/dist/trace-1t1n_wUm.d.ts +86 -0
  409. package/dist/types-DxKqU60b.d.ts +477 -0
  410. package/dist/types-pVomjzqR.d.ts +132 -0
  411. package/dist/unplaced-candidate-migration-CbQHzcEM.js +940 -0
  412. package/dist/utils-Ctb9aevJ.d.ts +34 -0
  413. package/drizzle/0000_initial.sql +10 -0
  414. package/drizzle/0001_virtual_tables.sql +34 -0
  415. package/drizzle/0002_add_indexes.sql +11 -0
  416. package/drizzle/0003_content_hash_lookup_index.sql +2 -0
  417. package/drizzle/0004_chunk_swap.sql +60 -0
  418. package/drizzle/0005_drop_legacy_vec_fts.sql +10 -0
  419. package/drizzle/0006_fts_simple.sql +45 -0
  420. package/drizzle/0007_restore_simple_fts.sql +40 -0
  421. package/drizzle/0008_widen_memory_hash_unique_index.sql +4 -0
  422. package/drizzle/0009_memory_telemetry.sql +109 -0
  423. package/drizzle/0010_provider_mappings.sql +27 -0
  424. package/drizzle/0011_db_optimization.sql +82 -0
  425. package/drizzle/0012_b_profile_lanes.sql +9 -0
  426. package/drizzle/0013_extraction_timestamps.sql +6 -0
  427. package/drizzle/0014_extraction_timestamp_source.sql +3 -0
  428. package/drizzle/0015_task_lifecycle_state.sql +101 -0
  429. package/drizzle/0016_task_lifecycle_legacy_migration.sql +144 -0
  430. package/drizzle/0017_unplaced_candidates.sql +15 -0
  431. package/drizzle/0018_rem_batch_chassis.sql +71 -0
  432. package/drizzle/0019_profile_recovery_entries.sql +17 -0
  433. package/drizzle/0020_rem_scan_retry_progress.down.sql +14 -0
  434. package/drizzle/0020_rem_scan_retry_progress.sql +24 -0
  435. package/drizzle/0021_rem_two_facet_storage.down.sql +14 -0
  436. package/drizzle/0021_rem_two_facet_storage.sql +42 -0
  437. package/drizzle/0022_rem_facet_chunk_versions.down.sql +4 -0
  438. package/drizzle/0022_rem_facet_chunk_versions.sql +4 -0
  439. package/drizzle/0023_rem_defect_ledger.sql +40 -0
  440. package/drizzle/0024_rem_unbuilt_foundations.down.sql +13 -0
  441. package/drizzle/0024_rem_unbuilt_foundations.sql +65 -0
  442. package/drizzle/0025_rem_journal_operation_constraint.sql +28 -0
  443. package/drizzle/0026_rem_journal_detail.sql +1 -0
  444. package/drizzle/0027_legacy_nodix_namespace.sql +3 -0
  445. package/drizzle/0028_memory_timezone.sql +23 -0
  446. package/drizzle/0029_rem_write_hash_symmetry.sql +17 -0
  447. package/drizzle/0030_atomic_memory_additive.sql +105 -0
  448. package/drizzle/0031_atomic_extraction_ledger.sql +23 -0
  449. package/drizzle/0032_atomic_memory_entities.sql +12 -0
  450. package/drizzle/0033_todo_own_store.sql +99 -0
  451. package/drizzle/meta/0000_snapshot.json +87 -0
  452. package/drizzle/meta/_journal.json +244 -0
  453. package/generated/rem-operations.json +1 -0
  454. package/package.json +126 -4
  455. package/scripts/download-simple-tokenizer.mjs +254 -0
  456. package/settings.default.json +243 -0
  457. package/skills/extract-atomic-memory/SKILL.md +298 -0
  458. package/skills/extract-atomic-memory/references/account-for-turns.md +9 -0
  459. package/skills/extract-atomic-memory/references/calendar-meaning.md +64 -0
  460. package/skills/extract-atomic-memory/references/capture.md +120 -0
  461. package/skills/extract-atomic-memory/references/enrichment.md +92 -0
  462. package/skills/extract-atomic-memory/references/missing-durable-half.md +6 -0
  463. package/skills/extract-atomic-memory/references/progress-classification.md +21 -0
  464. package/skills/extract-atomic-memory/references/resolve-subject.md +19 -0
  465. package/skills/extract-atomic-memory/references/surrounding-context.md +10 -0
  466. package/skills/extract-atomic-memory/references/user-subject-guard.md +29 -0
  467. package/skills/judge-group-closure/SKILL.md +25 -0
  468. package/skills/judge-rem-memory-updates/SKILL.md +56 -0
  469. package/skills/judge-rem-memory-updates/agents/openai.yaml +4 -0
  470. package/skills/judge-retired-position/SKILL.md +25 -0
  471. package/skills/judge-task-lifecycle/SKILL.md +45 -0
  472. package/skills/key-state-attribute/SKILL.md +16 -0
  473. package/skills/resolve-entity-identity/SKILL.md +24 -0
  474. package/skills/resolve-relative-time/SKILL.md +22 -0
  475. package/sqlite-extensions/LICENSE-simple-tokenizer +28 -0
  476. package/sqlite-extensions/LICENSE-sqlite-vec +21 -0
  477. package/sqlite-extensions/linux-arm64/vec0.so +0 -0
  478. package/sqlite-extensions/linux-x64/vec0.so +0 -0
@@ -0,0 +1,1378 @@
1
+ import { ct as FIXED_PROTOCOL_VALUE_69, d as FIXED_EXTERNAL_VALUE_8, f as FIXED_EXTERNAL_VALUE_9 } from "./signed-registry-constants-yq3DlG3B.js";
2
+ import { i as memoryOperationSignal, r as memoryOperationId, t as checkMemoryOperation } from "./operation-cancellation-CTKWwNHk.js";
3
+ import { t as MODEL_CALLS } from "./model-call-table-CspopkBg.js";
4
+ import { classifyLlmFailure, isCredentialFailure, isTransientLlmStatus } from "./internal/model/llm-failure.js";
5
+ import { a as repairCommonJson, i as previewText, n as readModelReplyJson, r as extractJsonFromResponse } from "./model-reply-text-CKopStP2.js";
6
+ import { resolveLlmRoute } from "./internal/model/llm-mode-routing.js";
7
+ import { countTokens } from "@snoai/chunking";
8
+ import { createLogger, withLogContext } from "@snoai/utils/logger";
9
+ import path from "node:path";
10
+ import { createHash, createPublicKey, randomUUID, verify } from "node:crypto";
11
+ import { AsyncLocalStorage } from "node:async_hooks";
12
+ import { existsSync } from "node:fs";
13
+ import { CallPipeline, ConfigRegistryManager, KeyPool, loadLlmixTrustManifest, registryRootOptionsFromTrustManifest } from "@snoai/llmix";
14
+ import { Buffer } from "node:buffer";
15
+ import { fileURLToPath } from "node:url";
16
+ //#region src/model/llmix-registry.ts
17
+ /** @file llmix-registry.ts
18
+ * @purpose Loads the bundled signed LLMIx registry for sno-station-mem.
19
+ * @boundary Trust-anchor verification and package-relative asset resolution only.
20
+ */
21
+ const SNO_STATION_MEM_RELEASE_ANCHOR_URL = FIXED_EXTERNAL_VALUE_8;
22
+ const SNO_STATION_MEM_RELEASE_KEY_ID = FIXED_EXTERNAL_VALUE_9;
23
+ const SNO_STATION_MEM_RELEASE_ANCHOR_ATTEMPTS = 2;
24
+ const SNO_STATION_MEM_RELEASE_ANCHOR_RETRY_DELAY_MS = 50;
25
+ const ALLOWED_HTTP_ENDPOINT_HOSTS = /* @__PURE__ */ new Set([
26
+ "localhost",
27
+ "127.0.0.1",
28
+ "100.100.200.71"
29
+ ]);
30
+ function parsePresetId(preset) {
31
+ const [module, presetName] = preset.split("/");
32
+ if (!module || !presetName) throw new Error(`sno-station-mem llm-client: invalid LLMIx preset id "${preset}"`);
33
+ return {
34
+ module,
35
+ preset: presetName
36
+ };
37
+ }
38
+ function assertSupportedProvider(provider) {
39
+ if (provider === "openai" || provider === "openrouter" || provider === "sno-gpu") return provider;
40
+ throw new Error(`sno-station-mem llm-client: unsupported LLMIx provider "${provider}"`);
41
+ }
42
+ function resolveEndpointBase(baseSource, preservePath) {
43
+ let parsed;
44
+ try {
45
+ parsed = new URL(baseSource);
46
+ } catch {
47
+ throw new Error(`sno-station-mem llm-client: invalid extraction.llm.baseURL "${baseSource}"`);
48
+ }
49
+ if (parsed.protocol !== "https:" && !ALLOWED_HTTP_ENDPOINT_HOSTS.has(parsed.hostname)) throw new Error("sno-station-mem llm-client: extraction.llm.baseURL must use https");
50
+ if (parsed.protocol === "https:" && parsed.hostname.toLowerCase() === "api.openai.com") throw new Error("sno-station-mem llm-client: direct api.openai.com transport is forbidden; use local ccproxy or an explicit custom endpoint");
51
+ if (!preservePath) return parsed.origin;
52
+ const base = parsed.toString();
53
+ return base.endsWith("/") ? base : `${base}/`;
54
+ }
55
+ function packageRootFromImportMeta() {
56
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
57
+ const bundledRoot = path.resolve(moduleDir, "..");
58
+ return [bundledRoot, path.resolve(moduleDir, "../..")].find(hasBundledRegistryAssets) ?? bundledRoot;
59
+ }
60
+ function hasBundledRegistryAssets(packageRoot) {
61
+ return existsSync(path.join(packageRoot, "config", "llm", "current.json")) && existsSync(path.join(packageRoot, "config", "llm.trust.json"));
62
+ }
63
+ function resolveBundledLlmixRegistryPaths(packageRoot = packageRootFromImportMeta()) {
64
+ const registryDir = path.join(packageRoot, "config", "llm");
65
+ const trustManifestPath = path.join(packageRoot, "config", "llm.trust.json");
66
+ if (!hasBundledRegistryAssets(packageRoot)) throw new Error("sno-station-mem LLMIx registry assets are missing from the installed package");
67
+ return {
68
+ registryDir,
69
+ trustManifestPath
70
+ };
71
+ }
72
+ function isJsonObject(value) {
73
+ return typeof value === "object" && value !== null && !Array.isArray(value);
74
+ }
75
+ function readPublicKeyJwk(document) {
76
+ if (!isJsonObject(document) || document.id !== "did:web:www.sno.ai") return null;
77
+ const methods = document.verificationMethod;
78
+ if (!Array.isArray(methods)) return null;
79
+ for (const method of methods) {
80
+ if (!isJsonObject(method) || method.id !== SNO_STATION_MEM_RELEASE_KEY_ID) continue;
81
+ const jwk = method.publicKeyJwk;
82
+ if (isJsonObject(jwk) && jwk.kty === "OKP" && jwk.crv === "Ed25519" && typeof jwk.x === "string") return jwk;
83
+ }
84
+ return null;
85
+ }
86
+ function verifyEd25519(jwk, paeBytes, signature) {
87
+ const publicKey = createPublicKey({
88
+ key: jwk,
89
+ format: "jwk"
90
+ });
91
+ return verify(null, Buffer.from(paeBytes), publicKey, Buffer.from(signature, "base64"));
92
+ }
93
+ function releaseAnchorFailureMessage(error) {
94
+ if (!isJsonObject(error) || !isJsonObject(error.details)) return null;
95
+ const cause = error.details.cause;
96
+ if (typeof cause !== "string") return null;
97
+ return cause.includes("sno-station-mem LLMIx release anchor fetch") ? cause : null;
98
+ }
99
+ async function fetchReleaseAnchorOnce(fetchImpl, timeoutMs) {
100
+ const controller = new AbortController();
101
+ let timeout;
102
+ const timeoutPromise = new Promise((_resolve, reject) => {
103
+ timeout = setTimeout(() => {
104
+ controller.abort();
105
+ reject(/* @__PURE__ */ new Error(`sno-station-mem LLMIx release anchor fetch timed out after ${timeoutMs}ms`));
106
+ }, timeoutMs);
107
+ });
108
+ try {
109
+ return await Promise.race([fetchImpl(SNO_STATION_MEM_RELEASE_ANCHOR_URL, { signal: controller.signal }), timeoutPromise]);
110
+ } finally {
111
+ if (timeout !== void 0) clearTimeout(timeout);
112
+ }
113
+ }
114
+ function isTransientAnchorResponse(response) {
115
+ return isTransientLlmStatus(response.status);
116
+ }
117
+ async function fetchReleaseAnchor(fetchImpl, timeoutMs) {
118
+ for (let attempt = 1; attempt <= SNO_STATION_MEM_RELEASE_ANCHOR_ATTEMPTS; attempt++) {
119
+ try {
120
+ const response = await fetchReleaseAnchorOnce(fetchImpl, timeoutMs);
121
+ if (attempt === SNO_STATION_MEM_RELEASE_ANCHOR_ATTEMPTS || !isTransientAnchorResponse(response)) return response;
122
+ } catch (error) {
123
+ if (attempt === SNO_STATION_MEM_RELEASE_ANCHOR_ATTEMPTS) throw error;
124
+ }
125
+ await new Promise((resolve) => setTimeout(resolve, SNO_STATION_MEM_RELEASE_ANCHOR_RETRY_DELAY_MS));
126
+ }
127
+ throw new Error("sno-station-mem LLMIx release anchor fetch exhausted");
128
+ }
129
+ function createSnoMemSnoStationMemDidWebVerifier(fetchImpl = globalThis.fetch, options = {}) {
130
+ const anchorTimeoutMs = options.anchorTimeoutMs ?? 5e3;
131
+ return { async verify(input) {
132
+ if (input.domain !== "www.sno.ai" || input.keyId !== SNO_STATION_MEM_RELEASE_KEY_ID) return false;
133
+ if (input.algorithm !== "ed25519") return false;
134
+ const response = await fetchReleaseAnchor(fetchImpl, anchorTimeoutMs);
135
+ if (!response.ok) return false;
136
+ const jwk = readPublicKeyJwk(await response.json());
137
+ if (jwk === null) return false;
138
+ return verifyEd25519(jwk, input.paeBytes, input.signature);
139
+ } };
140
+ }
141
+ async function openBundledLlmixRegistry(packageRoot, fetchImpl = globalThis.fetch, options = {}) {
142
+ const paths = resolveBundledLlmixRegistryPaths(packageRoot);
143
+ const trustManifest = await loadLlmixTrustManifest(paths.trustManifestPath);
144
+ const signedRoot = registryRootOptionsFromTrustManifest(trustManifest, { didWebVerifier: createSnoMemSnoStationMemDidWebVerifier(fetchImpl, options) });
145
+ try {
146
+ return await ConfigRegistryManager.open(paths.registryDir, { signedRoot });
147
+ } catch (error) {
148
+ const anchorFailure = releaseAnchorFailureMessage(error);
149
+ if (anchorFailure !== null) throw new Error(anchorFailure, { cause: error });
150
+ throw error;
151
+ }
152
+ }
153
+ async function resolveBundledLlmixPreset(presetId) {
154
+ return loadBundledLlmixPreset(await openBundledLlmixRegistry(), presetId);
155
+ }
156
+ async function loadBundledLlmixPreset(registry, presetId) {
157
+ const id = parsePresetId(presetId);
158
+ const preset = await registry.getPreset(id.module, id.preset);
159
+ return {
160
+ preset: presetId,
161
+ provider: assertSupportedProvider(preset.provider),
162
+ model: preset.model,
163
+ ...preset.providerOptions ? { providerOptions: preset.providerOptions } : {},
164
+ ...preset.timeout?.totalTime ? { timeoutMs: preset.timeout.totalTime * 1e3 } : {}
165
+ };
166
+ }
167
+ function materializeBundledLlmixEndpoint(input) {
168
+ const path = input.preset.provider === "sno-gpu" ? input.preset.providerOptions?.["sno-gpu"]?.gpuPath : "chat/completions";
169
+ if (!path) throw new Error(`sno-station-mem llm-client: signed endpoint path missing from preset ${input.preset.preset}`);
170
+ return {
171
+ url: new URL(path, resolveEndpointBase(input.baseSource, input.preset.provider !== "sno-gpu")).toString(),
172
+ preset: input.preset
173
+ };
174
+ }
175
+ async function resolveConfiguredBundledLlmixEndpoint(input) {
176
+ const registry = await openBundledLlmixRegistry();
177
+ const configured = await loadBundledLlmixPreset(registry, input.configuredPresetId);
178
+ const endpointPresetId = input.selectEndpointPreset(configured.provider);
179
+ return materializeBundledLlmixEndpoint({
180
+ preset: endpointPresetId === input.configuredPresetId ? configured : await loadBundledLlmixPreset(registry, endpointPresetId),
181
+ baseSource: input.selectBaseSource(configured.provider)
182
+ });
183
+ }
184
+ //#endregion
185
+ //#region src/model/llm-endpoint-resolution.ts
186
+ const SNO_GPU_ORIGIN = "https://rt3-llm.sno.ai";
187
+ const PROVIDER_API_BASES = {
188
+ openai: FIXED_PROTOCOL_VALUE_69,
189
+ openrouter: "https://openrouter.ai/api/v1"
190
+ };
191
+ async function resolveSignedPreset(presetId) {
192
+ return resolveBundledLlmixPreset(presetId);
193
+ }
194
+ function selectEndpointPreset(input) {
195
+ return input.provider === "sno-gpu" ? MODEL_CALLS[input.callId].snoPreset : input.configuredPreset;
196
+ }
197
+ async function resolveLlmEndpoint(input) {
198
+ return {
199
+ ...await resolveConfiguredBundledLlmixEndpoint({
200
+ configuredPresetId: input.configuredPreset,
201
+ selectEndpointPreset: (provider) => {
202
+ if (input.transport !== "chat-completions" && provider !== "sno-gpu") throw new Error(`sno-station-mem llm-client: ${provider} does not support ${input.transport}`);
203
+ return selectEndpointPreset({
204
+ configuredPreset: input.configuredPreset,
205
+ provider,
206
+ callId: input.callId
207
+ });
208
+ },
209
+ selectBaseSource: (provider) => input.baseOverride ?? (provider === "sno-gpu" ? SNO_GPU_ORIGIN : PROVIDER_API_BASES[provider])
210
+ }),
211
+ userBaseUrlOverride: input.baseOverride !== void 0
212
+ };
213
+ }
214
+ //#endregion
215
+ //#region src/model/llm-provider-transport.ts
216
+ const log$1 = createLogger("sno-station-mem:llm-provider-transport");
217
+ const routeInFlight = /* @__PURE__ */ new Map();
218
+ const providerResponses = new AsyncLocalStorage();
219
+ async function observeRequest(input, run) {
220
+ const route = createHash("sha256").update(input.endpoint).digest("hex");
221
+ const inFlight = (routeInFlight.get(route) ?? 0) + 1;
222
+ routeInFlight.set(route, inFlight);
223
+ const diagnostic = { started: performance.now() };
224
+ return withLogContext({ attempt_id: randomUUID() }, async () => {
225
+ let outcome = "failed";
226
+ let failure;
227
+ try {
228
+ const result = await run(diagnostic);
229
+ outcome = typeof result === "object" && result !== null && "content" in result && result.content === "" ? "empty_success" : "success";
230
+ return result;
231
+ } catch (error) {
232
+ failure = error;
233
+ outcome = getProviderTerminalCategory(error) ?? "failed";
234
+ throw error;
235
+ } finally {
236
+ const remaining = (routeInFlight.get(route) ?? 1) - 1;
237
+ if (remaining === 0) routeInFlight.delete(route);
238
+ else routeInFlight.set(route, remaining);
239
+ log$1.info("Model request completed", {
240
+ outcome,
241
+ error: failure,
242
+ call_id: input.slot ?? "unavailable",
243
+ destination: input.label ?? "unavailable",
244
+ route_hash: route,
245
+ transport: input.transport,
246
+ requested_model: input.model,
247
+ returned_model: diagnostic.returnedModel ?? "unavailable",
248
+ prompt_template_hash: input.promptTemplateHash ?? "unavailable",
249
+ extraction_skill_hash: input.extractionSkillHash ?? "unavailable",
250
+ prompt_template_unavailable_reason: input.promptTemplateHash ? void 0 : "caller_does_not_provide_template_identity",
251
+ config_hash: createHash("sha256").update(JSON.stringify({
252
+ ...input,
253
+ endpoint: route
254
+ })).digest("hex"),
255
+ output_cap: input.cap ?? "unavailable",
256
+ timeout_ms: input.timeout,
257
+ sampling: {
258
+ source: Object.keys(input.sampling).length ? "sent" : "unknown",
259
+ values: input.sampling
260
+ },
261
+ in_flight_at_dispatch: inFlight,
262
+ status_code: diagnostic.status ?? "unavailable",
263
+ duration_ms: performance.now() - diagnostic.started,
264
+ dispatch_to_headers_ms: diagnostic.headersAt === void 0 ? "unavailable" : diagnostic.headersAt - diagnostic.started,
265
+ headers_to_body_ms: diagnostic.headersAt === void 0 || diagnostic.bodyAt === void 0 ? "unavailable" : diagnostic.bodyAt - diagnostic.headersAt,
266
+ first_token_ms: "unavailable",
267
+ first_token_reason: "non_streaming_transport",
268
+ server_queue_ms: "unavailable",
269
+ server_service_ms: "unavailable",
270
+ finish_reason: diagnostic.finishReason ?? "unavailable",
271
+ usage: diagnostic.usage ? {
272
+ source: diagnostic.usage.estimated ? "estimated" : "provider_reported",
273
+ ...diagnostic.usage
274
+ } : { source: "unavailable" }
275
+ }, {
276
+ event_name: "llm.request.completed",
277
+ file: "packages/memory/src/model/llm-provider-transport.ts",
278
+ function: "observeRequest",
279
+ site_id: "llm.transport.request.completed"
280
+ });
281
+ }
282
+ });
283
+ }
284
+ const CCPROXY_OPENAI_BASE_URL = FIXED_PROTOCOL_VALUE_69;
285
+ const CCPROXY_PLACEHOLDER_API_KEY = "ccproxy-placeholder";
286
+ /** Keys from pipeline kwargs that belong in the chat/completions POST body. */
287
+ const FORWARDED_KWARGS = [
288
+ "temperature",
289
+ "top_p",
290
+ "max_tokens",
291
+ "max_completion_tokens",
292
+ "seed",
293
+ "response_format"
294
+ ];
295
+ /** Assembles call body from validated inputs for deterministic LLM transport. */
296
+ function buildCallBody(kwargs, provider) {
297
+ const body = {};
298
+ for (const key of FORWARDED_KWARGS) {
299
+ if (provider === "sno-gpu" && key === "temperature") continue;
300
+ if (kwargs[key] != null) body[key] = kwargs[key];
301
+ }
302
+ return body;
303
+ }
304
+ function hasAbortSignalShape$1(value) {
305
+ return typeof value === "object" && value !== null && typeof value.aborted === "boolean" && typeof value.addEventListener === "function";
306
+ }
307
+ function requestAbortSignal(timeoutMs, callerSignal) {
308
+ const timeoutSignal = AbortSignal.timeout(Math.floor(timeoutMs));
309
+ if (!hasAbortSignalShape$1(callerSignal)) return {
310
+ signal: timeoutSignal,
311
+ timeoutSignal
312
+ };
313
+ return {
314
+ signal: callerSignal.aborted ? callerSignal : AbortSignal.any([timeoutSignal, callerSignal]),
315
+ timeoutSignal,
316
+ callerSignal
317
+ };
318
+ }
319
+ const PROVIDER_TERMINAL_ERROR_PREFIX = "sno-station-mem provider terminal";
320
+ var ProviderTerminalError = class extends Error {
321
+ category;
322
+ statusCode;
323
+ constructor(category, message, statusCode) {
324
+ super(`${PROVIDER_TERMINAL_ERROR_PREFIX} ${category}: ${message}`);
325
+ this.category = category;
326
+ this.name = "ProviderTerminalError";
327
+ this.statusCode = statusCode;
328
+ }
329
+ };
330
+ /** Recovers terminal transport semantics after CallPipeline serializes an error to text. */
331
+ function getProviderTerminalCategory(error) {
332
+ if (error instanceof ProviderTerminalError) return error.category;
333
+ const message = error instanceof Error ? error.message : String(error);
334
+ const match = new RegExp(`^${PROVIDER_TERMINAL_ERROR_PREFIX} (cancelled|timeout|auth):`).exec(message);
335
+ return match?.[1] === "cancelled" || match?.[1] === "timeout" || match?.[1] === "auth" ? match[1] : null;
336
+ }
337
+ function abortedProviderCategory(requestAbort) {
338
+ if (requestAbort.callerSignal?.aborted) return "cancelled";
339
+ if (requestAbort.timeoutSignal.aborted) return "timeout";
340
+ return null;
341
+ }
342
+ function throwTerminalAbort(error, requestAbort) {
343
+ const category = abortedProviderCategory(requestAbort);
344
+ if (category) throw new ProviderTerminalError(category, error instanceof Error ? error.message : String(error), 499);
345
+ throw error;
346
+ }
347
+ function estimateTokens(text) {
348
+ return Math.max(1, countTokens(text));
349
+ }
350
+ function estimateUsage(messages, content) {
351
+ const inputTokens = estimateTokens(JSON.stringify(messages));
352
+ const outputTokens = estimateTokens(content);
353
+ return {
354
+ inputTokens,
355
+ outputTokens,
356
+ totalTokens: inputTokens + outputTokens,
357
+ estimated: true
358
+ };
359
+ }
360
+ function readProviderUsage(usage) {
361
+ if (typeof usage?.prompt_tokens === "number" && typeof usage.completion_tokens === "number" && typeof usage.total_tokens === "number") return {
362
+ inputTokens: usage.prompt_tokens,
363
+ outputTokens: usage.completion_tokens,
364
+ totalTokens: usage.total_tokens
365
+ };
366
+ }
367
+ function normalizeProviderUsage(usage, messages, content) {
368
+ return readProviderUsage(usage) ?? estimateUsage(messages, content);
369
+ }
370
+ function readProviderRequestId(bodyId, headers) {
371
+ return [bodyId, headers.get("x-request-id")].find((value) => typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(value));
372
+ }
373
+ function notifyProviderResponse(callback, response) {
374
+ providerResponses.getStore()?.push(response);
375
+ callback?.(response);
376
+ }
377
+ /** A call that ended without an answer is still a trace for the request in flight. */
378
+ function recordProviderFailure(response) {
379
+ providerResponses.getStore()?.push(response);
380
+ }
381
+ /**
382
+ * The status line alone does not say what the provider objected to, and a 400 always does — it is
383
+ * the one class of failure where the server knows the answer and we were throwing it away. Measured
384
+ * 2026-08-12: a REM wave died on `B-profile extraction returned HTTP 400`, and the reason for it was
385
+ * unreachable without editing this file and re-running.
386
+ *
387
+ * Read only for a non-auth status: an auth failure's body is the one that can carry credential
388
+ * material back, and it is also the one status that needs no explanation.
389
+ */
390
+ async function describeProviderFailure(response, diagnostic) {
391
+ let detail;
392
+ try {
393
+ detail = (await response.text()).trim();
394
+ if (diagnostic) diagnostic.bodyAt = performance.now();
395
+ } catch {
396
+ return `HTTP ${response.status}`;
397
+ }
398
+ if (detail.length === 0) return `HTTP ${response.status}`;
399
+ const collapsed = detail.replace(/\s+/g, " ");
400
+ const shown = collapsed.length > 500 ? `${collapsed.slice(0, 500)}…` : collapsed;
401
+ return `HTTP ${response.status}: ${shown}`;
402
+ }
403
+ /** Calls the fixed B-profile raw-completions route without transport-level retries. */
404
+ async function callSnoProfileCompletion(request) {
405
+ return observeRequest({
406
+ endpoint: request.endpointUrl,
407
+ model: request.model,
408
+ transport: "raw-completions",
409
+ slot: request.callId,
410
+ label: request.destination,
411
+ timeout: request.timeoutMs,
412
+ cap: request.singleTokenVerdict ? 1 : request.maxTokens,
413
+ sampling: {},
414
+ promptTemplateHash: request.promptTemplateHash,
415
+ extractionSkillHash: request.extractionSkillHash
416
+ }, async (diagnostic) => {
417
+ const requestAbort = requestAbortSignal(request.timeoutMs, request.signal);
418
+ let response;
419
+ try {
420
+ response = await fetch(request.endpointUrl, {
421
+ method: "POST",
422
+ signal: requestAbort.signal,
423
+ headers: {
424
+ "Content-Type": "application/json",
425
+ "X-Internal-Token": request.apiKey,
426
+ ...request.requestId ? { "X-Request-ID": request.requestId } : {},
427
+ ...request.operationId ? { "X-Sno-Operation": request.operationId } : {}
428
+ },
429
+ body: JSON.stringify({
430
+ model: request.model,
431
+ prompt: request.prompt,
432
+ ...request.singleTokenVerdict ? { max_tokens: 1 } : request.maxTokens ? { max_tokens: request.maxTokens } : {}
433
+ })
434
+ });
435
+ diagnostic.headersAt = performance.now();
436
+ diagnostic.status = response.status;
437
+ } catch (error) {
438
+ throwTerminalAbort(error, requestAbort);
439
+ }
440
+ if (!response.ok) {
441
+ if (classifyLlmFailure({ status: response.status }).category === "auth") throw new ProviderTerminalError("auth", `B-profile extraction returned HTTP ${response.status}`, response.status);
442
+ const error = /* @__PURE__ */ new Error(`B-profile extraction returned ${await describeProviderFailure(response, diagnostic)}`);
443
+ error.statusCode = response.status;
444
+ throw error;
445
+ }
446
+ let body;
447
+ try {
448
+ body = await response.json();
449
+ diagnostic.bodyAt = performance.now();
450
+ } catch (error) {
451
+ throwTerminalAbort(error, requestAbort);
452
+ }
453
+ const content = body.choices?.[0]?.text;
454
+ if (typeof content !== "string") throw new Error("B-profile extraction response is missing choices[0].text");
455
+ const model = typeof body.model === "string" && body.model.trim() ? body.model : void 0;
456
+ const usage = readProviderUsage(body.usage);
457
+ diagnostic.returnedModel = model;
458
+ diagnostic.finishReason = body.choices?.[0]?.finish_reason;
459
+ diagnostic.usage = normalizeProviderUsage(body.usage, [request.prompt], content);
460
+ const requestId = readProviderRequestId(body.id, response.headers);
461
+ if (request.callId && request.destination) notifyProviderResponse(request.onProviderResponse, {
462
+ durationMs: performance.now() - diagnostic.started,
463
+ callId: request.callId,
464
+ destination: request.destination,
465
+ provider: "sno-gpu",
466
+ ...requestId ? { requestId } : {},
467
+ ...model ? { model } : {},
468
+ ...usage ? { usage } : {}
469
+ });
470
+ return {
471
+ content,
472
+ model: model ?? request.model,
473
+ usage: normalizeProviderUsage(body.usage, [request.prompt], content)
474
+ };
475
+ });
476
+ }
477
+ function isCcproxyOpenAiBaseUrl(value) {
478
+ if (!value) return false;
479
+ try {
480
+ const configured = new URL(value);
481
+ const expected = new URL(CCPROXY_OPENAI_BASE_URL);
482
+ return configured.origin === expected.origin && configured.pathname.replace(/\/+$/, "") === expected.pathname.replace(/\/+$/, "");
483
+ } catch {
484
+ return false;
485
+ }
486
+ }
487
+ async function snoStationMemDispatch(ctx) {
488
+ const cfgExt = ctx.config;
489
+ const provider = ctx.provider;
490
+ if (provider !== "openai" && provider !== "openrouter" && provider !== "sno-gpu") throw new Error(`sno-station-mem llm-client: unsupported provider "${provider}"`);
491
+ const endpointUrl = cfgExt.endpointUrl;
492
+ if (typeof endpointUrl !== "string") throw new Error("sno-station-mem llm-client: resolved endpointUrl is required");
493
+ const timeoutMs = cfgExt.timeoutMs ?? 3e4;
494
+ const callBody = buildCallBody(ctx.kwargs, provider);
495
+ const sampling = Object.fromEntries([
496
+ "temperature",
497
+ "top_p",
498
+ "seed"
499
+ ].flatMap((key) => callBody[key] === void 0 ? [] : [[key, callBody[key]]]));
500
+ return observeRequest({
501
+ endpoint: endpointUrl,
502
+ model: ctx.model,
503
+ transport: "chat-completions",
504
+ slot: cfgExt.callId,
505
+ label: cfgExt.destination,
506
+ timeout: timeoutMs,
507
+ cap: typeof callBody.max_tokens === "number" ? callBody.max_tokens : typeof callBody.max_completion_tokens === "number" ? callBody.max_completion_tokens : void 0,
508
+ sampling,
509
+ promptTemplateHash: cfgExt.promptTemplateHash,
510
+ extractionSkillHash: cfgExt.extractionSkillHash,
511
+ forwardedConfigHash: createHash("sha256").update(JSON.stringify({
512
+ response_format: callBody.response_format,
513
+ seed: callBody.seed,
514
+ max_tokens: callBody.max_tokens,
515
+ max_completion_tokens: callBody.max_completion_tokens,
516
+ temperature: callBody.temperature,
517
+ top_p: callBody.top_p
518
+ })).digest("hex")
519
+ }, async (diagnostic) => {
520
+ const requestAbort = requestAbortSignal(timeoutMs, cfgExt.signal);
521
+ const headers = { "Content-Type": "application/json" };
522
+ if (typeof cfgExt.requestId === "string") headers["X-Request-ID"] = cfgExt.requestId;
523
+ if (provider === "sno-gpu") {
524
+ headers["X-Internal-Token"] = ctx.apiKey;
525
+ if (typeof cfgExt.operationId === "string") headers["X-Sno-Operation"] = cfgExt.operationId;
526
+ } else headers.Authorization = `Bearer ${ctx.apiKey}`;
527
+ let response;
528
+ try {
529
+ response = await fetch(endpointUrl, {
530
+ method: "POST",
531
+ signal: requestAbort.signal,
532
+ headers,
533
+ body: JSON.stringify({
534
+ model: ctx.model,
535
+ messages: ctx.messages,
536
+ ...callBody
537
+ })
538
+ });
539
+ diagnostic.headersAt = performance.now();
540
+ diagnostic.status = response.status;
541
+ } catch (error) {
542
+ const category = abortedProviderCategory(requestAbort);
543
+ if (category) throw new ProviderTerminalError(category, error instanceof Error ? error.message : String(error), 499);
544
+ throw error;
545
+ }
546
+ if (!response.ok) {
547
+ if (classifyLlmFailure({ status: response.status }).category === "auth") throw new ProviderTerminalError("auth", `HTTP ${response.status}`, response.status);
548
+ const err = new Error(await describeProviderFailure(response, diagnostic));
549
+ err.statusCode = response.status;
550
+ throw err;
551
+ }
552
+ let body;
553
+ try {
554
+ body = await response.json();
555
+ diagnostic.bodyAt = performance.now();
556
+ } catch (parseErr) {
557
+ if (abortedProviderCategory(requestAbort)) throwTerminalAbort(parseErr, requestAbort);
558
+ const err = /* @__PURE__ */ new Error(`Malformed response body: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`);
559
+ err.statusCode = 502;
560
+ throw err;
561
+ }
562
+ const rawContent = body.choices?.[0]?.message?.content;
563
+ if (typeof rawContent !== "string") {
564
+ const err = /* @__PURE__ */ new Error("Chat completion response is missing choices[0].message.content");
565
+ err.statusCode = 502;
566
+ throw err;
567
+ }
568
+ const content = rawContent;
569
+ const model = typeof body.model === "string" && body.model.trim() ? body.model : void 0;
570
+ const usage = readProviderUsage(body.usage);
571
+ diagnostic.returnedModel = model;
572
+ diagnostic.finishReason = body.choices?.[0]?.finish_reason;
573
+ diagnostic.usage = normalizeProviderUsage(body.usage, ctx.messages, content);
574
+ const requestId = readProviderRequestId(body.id, response.headers);
575
+ const onProviderResponse = cfgExt.onProviderResponse;
576
+ if (cfgExt.callId && cfgExt.destination) notifyProviderResponse(typeof onProviderResponse === "function" ? onProviderResponse : void 0, {
577
+ durationMs: performance.now() - diagnostic.started,
578
+ callId: cfgExt.callId,
579
+ destination: cfgExt.destination,
580
+ provider,
581
+ ...requestId ? { requestId } : {},
582
+ ...model ? { model } : {},
583
+ ...usage ? { usage } : {}
584
+ });
585
+ return {
586
+ content,
587
+ model: model ?? ctx.model,
588
+ usage: normalizeProviderUsage(body.usage, ctx.messages, content)
589
+ };
590
+ });
591
+ }
592
+ async function callProvider(ctx) {
593
+ const cfgExt = ctx.config;
594
+ const rawCompletion = cfgExt.rawCompletion;
595
+ if (typeof rawCompletion === "object" && rawCompletion !== null) {
596
+ const raw = rawCompletion;
597
+ if (typeof raw.endpointUrl !== "string" || typeof raw.prompt !== "string" || typeof raw.timeoutMs !== "number") throw new Error("sno-station-mem llm-client: invalid raw profile completion config");
598
+ return {
599
+ ...await callSnoProfileCompletion({
600
+ ...cfgExt.promptTemplateHash ? { promptTemplateHash: cfgExt.promptTemplateHash } : {},
601
+ ...cfgExt.extractionSkillHash ? { extractionSkillHash: cfgExt.extractionSkillHash } : {},
602
+ endpointUrl: raw.endpointUrl,
603
+ model: ctx.model,
604
+ apiKey: ctx.apiKey,
605
+ prompt: raw.prompt,
606
+ timeoutMs: raw.timeoutMs,
607
+ ...cfgExt.callId ? { callId: cfgExt.callId } : {},
608
+ ...cfgExt.destination ? { destination: cfgExt.destination } : {},
609
+ ...cfgExt.onProviderResponse ? { onProviderResponse: cfgExt.onProviderResponse } : {},
610
+ ...typeof raw.requestId === "string" ? { requestId: raw.requestId } : {},
611
+ ...typeof raw.operationId === "string" ? { operationId: raw.operationId } : {},
612
+ ...typeof raw.maxTokens === "number" ? { maxTokens: raw.maxTokens } : {},
613
+ ...raw.singleTokenVerdict === true ? { singleTokenVerdict: true } : {},
614
+ ...hasAbortSignalShape$1(raw.signal) ? { signal: raw.signal } : {}
615
+ }),
616
+ success: true
617
+ };
618
+ }
619
+ return {
620
+ ...await snoStationMemDispatch(ctx),
621
+ success: true
622
+ };
623
+ }
624
+ function resolveProviderApiKey(config, resolved, userBaseUrlOverride) {
625
+ if (config.apiKey?.trim()) return config.apiKey;
626
+ if (resolved.provider === "openai" && (!userBaseUrlOverride || isCcproxyOpenAiBaseUrl(config.baseURL?.trim()))) return CCPROXY_PLACEHOLDER_API_KEY;
627
+ throw new Error(`sno-station-mem llm-client: missing API key for preset ${config.preset}; set snoGpu.apiKey`);
628
+ }
629
+ //#endregion
630
+ //#region src/model/llm-client.ts
631
+ const log = createLogger("sno-station-mem:llm-client");
632
+ let hostRequestsInFlight = 0;
633
+ /**
634
+ * Last-resort output cap for a raw-completion caller that set none. Every use is logged as an
635
+ * error naming the caller, because this exists to keep a broken call alive, not to spare anyone
636
+ * from choosing their own budget.
637
+ */
638
+ const RAW_COMPLETION_FALLBACK_MAX_TOKENS = 4096;
639
+ /**
640
+ * How many times one request may be asked before an empty reply is accepted as the answer.
641
+ *
642
+ * The serving side answers an otherwise valid request with an empty body often enough to matter:
643
+ * measured 2026-08-17 against the live endpoint, 25% of 36 paired calls with `enable_thinking`
644
+ * and 31% without (llm-provider-transport.ts:242, where that fault is recorded as still open).
645
+ * An empty body is not a transport error, so the call pipeline never retried it, and every caller
646
+ * turned it into `null`. The REM replace clause stage then journals that null as
647
+ * `clause_parse_failed` and releases the pair, so the memory is never updated at all — measured
648
+ * 2026-08-26, 2 of 4 identical runs of `rem-replace-roundtrip-reopen` died that way on a
649
+ * two-clause fixture the model answers correctly 12 times out of 12 when asked directly.
650
+ *
651
+ * Asking again is all this does. It is bounded by attempt count AND by the caller's own deadline,
652
+ * so a slow endpoint cannot turn one request into three timeouts. It does not repair the
653
+ * serving-side fault and must not be read as having repaired it.
654
+ */
655
+ const EMPTY_REPLY_ATTEMPTS = 3;
656
+ const JSON_SYSTEM_CONTENT = "You are a memory extraction assistant. Always respond with valid JSON only.";
657
+ const JSON_REPAIR_INSTRUCTION = "Your previous reply was not valid JSON. Respond with ONLY the JSON object, no prose.";
658
+ const REFLECTION_TEXT_SYSTEM_CONTENT = "You are a memory reflection assistant. Return concise plain text only.";
659
+ const CONFLICT_ADJUDICATION_SYSTEM_CONTENT = "You adjudicate memory conflicts. Follow the verdict contract and return only the requested JSON object or verdict token.";
660
+ var LlmClientTerminalError = class extends Error {
661
+ category;
662
+ requestTimedOut;
663
+ constructor(category, message, requestTimedOut = false) {
664
+ super(message);
665
+ this.category = category;
666
+ this.requestTimedOut = requestTimedOut;
667
+ this.name = "LlmClientTerminalError";
668
+ }
669
+ };
670
+ var ModelCallRefusedError = class extends Error {
671
+ callId;
672
+ destination;
673
+ reason;
674
+ constructor(callId, destination, reason) {
675
+ super(reason);
676
+ this.callId = callId;
677
+ this.destination = destination;
678
+ this.reason = reason;
679
+ this.name = "ModelCallRefusedError";
680
+ }
681
+ };
682
+ /**
683
+ * Whether a failure ends the whole run rather than costing one call.
684
+ *
685
+ * A real cancellation and an auth failure are terminal: nothing downstream should keep spending
686
+ * model time or, worse, keep writing. A timeout is NOT — the transport aborts on its own deadline
687
+ * and reports `cancelled` with `requestTimedOut` set, and treating that as a cancellation once
688
+ * cost an entire conversation for one slow call.
689
+ *
690
+ * SOURCE OF TRUTH. The same predicate is spelled out by hand in memory-extraction-pipeline.ts,
691
+ * task-lifecycle-route.ts, profile-section-writer.ts and b-profile-extraction.ts; those copies
692
+ * should be replaced by this import, and are flagged rather than changed here.
693
+ */
694
+ function isTerminalLlmFailure(error) {
695
+ return error instanceof LlmClientTerminalError && (error.category === "cancelled" && !error.requestTimedOut || error.category === "auth");
696
+ }
697
+ function parseJsonResponse(raw, accept) {
698
+ const parsedValue = readModelReplyJson(raw, (value) => accept === void 0 || accept(value) ? { value } : void 0);
699
+ if (parsedValue !== void 0) return {
700
+ ok: true,
701
+ value: parsedValue.value
702
+ };
703
+ const jsonStr = extractJsonFromResponse(raw);
704
+ if (!jsonStr) return {
705
+ ok: false,
706
+ error: `no JSON found (chars=${raw.length}, preview=${JSON.stringify(previewText(raw))})`
707
+ };
708
+ try {
709
+ const value = JSON.parse(jsonStr);
710
+ if (accept && !accept(value)) return {
711
+ ok: false,
712
+ error: "caller check rejected payload"
713
+ };
714
+ return {
715
+ ok: true,
716
+ value
717
+ };
718
+ } catch (error) {
719
+ const repairedJsonStr = repairCommonJson(jsonStr);
720
+ if (repairedJsonStr !== jsonStr) try {
721
+ const value = JSON.parse(repairedJsonStr);
722
+ if (accept && !accept(value)) return {
723
+ ok: false,
724
+ error: "caller check rejected payload"
725
+ };
726
+ return {
727
+ ok: true,
728
+ value
729
+ };
730
+ } catch {
731
+ return {
732
+ ok: false,
733
+ error: `JSON.parse failed: ${error instanceof Error ? error.message : String(error)}; repair also failed (chars=${jsonStr.length})`
734
+ };
735
+ }
736
+ return {
737
+ ok: false,
738
+ error: `JSON.parse failed: ${error instanceof Error ? error.message : String(error)} (chars=${jsonStr.length})`
739
+ };
740
+ }
741
+ }
742
+ function buildPipelineConfig(preset, config, endpoint, request, destination, operationId) {
743
+ return {
744
+ provider: preset.provider,
745
+ model: preset.model,
746
+ ...preset.providerOptions ? { providerOptions: preset.providerOptions } : {},
747
+ timeout: { totalTime: Math.ceil((request.timeoutMs ?? config.timeoutMs ?? preset.timeoutMs ?? 3e4) / 1e3) },
748
+ common: {
749
+ enableThinking: request.enableThinking ?? false,
750
+ maxOutputTokens: request.maxTokens ?? 4096
751
+ },
752
+ caching: { strategy: "disabled" },
753
+ preset: preset.preset,
754
+ baseUrl: endpoint.url,
755
+ endpointUrl: endpoint.url,
756
+ ...endpoint.userBaseUrlOverride ? { userBaseUrlOverride: endpoint.userBaseUrlOverride } : {},
757
+ timeoutMs: request.timeoutMs ?? config.timeoutMs ?? preset.timeoutMs ?? 3e4,
758
+ callId: request.callId,
759
+ destination,
760
+ ...request.requestId ? { requestId: request.requestId } : {},
761
+ ...operationId ? { operationId } : {},
762
+ ...request.promptTemplateHash ? { promptTemplateHash: request.promptTemplateHash } : {},
763
+ ...request.extractionSkillHash ? { extractionSkillHash: request.extractionSkillHash } : {},
764
+ ...request.signal ? { signal: request.signal } : {},
765
+ ...config.onProviderResponse ? { onProviderResponse: config.onProviderResponse } : {}
766
+ };
767
+ }
768
+ function hasAbortSignalShape(value) {
769
+ return typeof value === "object" && value !== null && typeof value.aborted === "boolean" && typeof value.addEventListener === "function";
770
+ }
771
+ function readRequiredString(request, field) {
772
+ const value = request[field];
773
+ if (typeof value !== "string" || !value.trim()) throw new Error(`sno-station-mem llm-client: ${field} is required`);
774
+ return value;
775
+ }
776
+ function normalizeMemoryLlmRequest(value) {
777
+ if (typeof value !== "object" || value === null) throw new Error("sno-station-mem llm-client: structured request object is required");
778
+ const raw = value;
779
+ const prompt = readRequiredString(raw, "prompt");
780
+ const callId = readRequiredString(raw, "callId");
781
+ if (!(callId in MODEL_CALLS)) throw new Error(`Unknown model call id ${callId}`);
782
+ const timeoutMs = raw.timeoutMs;
783
+ if (timeoutMs !== void 0 && (!Number.isFinite(timeoutMs) || Number(timeoutMs) <= 0)) throw new Error("sno-station-mem llm-client: timeoutMs must be a positive number");
784
+ const maxTokens = raw.maxTokens;
785
+ if (maxTokens !== void 0 && (!Number.isInteger(maxTokens) || Number(maxTokens) <= 0)) throw new Error("sno-station-mem llm-client: maxTokens must be a positive integer");
786
+ const emptyReplyAttempts = raw.emptyReplyAttempts;
787
+ if (emptyReplyAttempts !== void 0 && (!Number.isInteger(emptyReplyAttempts) || Number(emptyReplyAttempts) < 1 || Number(emptyReplyAttempts) > EMPTY_REPLY_ATTEMPTS)) throw new Error(`sno-station-mem llm-client: emptyReplyAttempts must be an integer from 1 to ${EMPTY_REPLY_ATTEMPTS}`);
788
+ const enableThinking = raw.enableThinking;
789
+ if (enableThinking !== void 0 && typeof enableThinking !== "boolean") throw new Error("sno-station-mem llm-client: enableThinking must be a boolean");
790
+ const signal = raw.signal;
791
+ if (signal !== void 0 && !hasAbortSignalShape(signal)) throw new Error("sno-station-mem llm-client: signal must be an AbortSignal");
792
+ const requestId = raw.requestId;
793
+ if (requestId !== void 0 && (typeof requestId !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(requestId))) throw new Error("sno-station-mem llm-client: requestId must be a content-free correlation token");
794
+ return {
795
+ prompt,
796
+ ...typeof raw.hostPrompt === "string" ? { hostPrompt: raw.hostPrompt } : {},
797
+ callId,
798
+ ...timeoutMs !== void 0 ? { timeoutMs: Number(timeoutMs) } : {},
799
+ ...maxTokens !== void 0 ? { maxTokens: Number(maxTokens) } : {},
800
+ ...emptyReplyAttempts !== void 0 ? { emptyReplyAttempts: Number(emptyReplyAttempts) } : {},
801
+ ...enableThinking !== void 0 ? { enableThinking } : {},
802
+ ...requestId !== void 0 ? { requestId } : {},
803
+ ...typeof raw.promptTemplateHash === "string" && /^[a-f0-9]{64}$/.test(raw.promptTemplateHash) ? { promptTemplateHash: raw.promptTemplateHash } : {},
804
+ ...typeof raw.extractionSkillHash === "string" && /^[a-f0-9]{64}$/.test(raw.extractionSkillHash) ? { extractionSkillHash: raw.extractionSkillHash } : {},
805
+ ...signal ? { signal } : {}
806
+ };
807
+ }
808
+ function textSystemContent(request) {
809
+ return MODEL_CALLS[request.callId].occasion === "conflictAdjudication" ? CONFLICT_ADJUDICATION_SYSTEM_CONTENT : REFLECTION_TEXT_SYSTEM_CONTENT;
810
+ }
811
+ /** Creates the LLM client facade with provider routing, key rotation, and JSON parsing. */
812
+ function createLlmClient(config) {
813
+ let presetPromise = null;
814
+ const getPreset = () => {
815
+ presetPromise ??= resolveSignedPreset(config.preset).catch((error) => {
816
+ presetPromise = null;
817
+ throw error;
818
+ });
819
+ return presetPromise;
820
+ };
821
+ const endpointPromises = /* @__PURE__ */ new Map();
822
+ const getEndpoint = (callId, transport) => {
823
+ const key = `${callId}:${transport}`;
824
+ let endpointPromise = endpointPromises.get(key);
825
+ if (!endpointPromise) {
826
+ endpointPromise = resolveLlmEndpoint({
827
+ configuredPreset: config.preset,
828
+ callId,
829
+ transport,
830
+ ...config.baseURL ? { baseOverride: config.baseURL } : {}
831
+ }).catch((error) => {
832
+ endpointPromises.delete(key);
833
+ throw error;
834
+ });
835
+ endpointPromises.set(key, endpointPromise);
836
+ }
837
+ return endpointPromise;
838
+ };
839
+ const pipeline = new CallPipeline({
840
+ dispatch: callProvider,
841
+ maxRetries: 2,
842
+ retryBaseMs: 100,
843
+ retryMaxDelayMs: 500,
844
+ transformKwargsOverrides: { "sno-gpu": (_context, kwargs) => kwargs }
845
+ });
846
+ let lastError = null;
847
+ let lastUsage = null;
848
+ const resolveRequestTimeoutMs = (request) => request.timeoutMs ?? config.timeoutMs ?? 3e4;
849
+ const destinationFor = (request) => {
850
+ if (!config.routing) return "host";
851
+ const route = resolveLlmRoute({
852
+ callId: request.callId,
853
+ config: config.routing
854
+ });
855
+ return "off" in route ? "off" : route.destination;
856
+ };
857
+ /**
858
+ * Resolves the transport this facade can dispatch. A routed-OFF request is
859
+ * a graceful no-op (not an error), and an unavailable transport also skips.
860
+ * Neither case substitutes another tier.
861
+ */
862
+ const resolveRequestTransport = (state, request) => {
863
+ if (!config.routing) return "chat-completions";
864
+ const decision = resolveLlmRoute({
865
+ callId: request.callId,
866
+ config: config.routing
867
+ });
868
+ if ("off" in decision) {
869
+ log.debug("Model client request diagnostic", {
870
+ call_id: request.callId,
871
+ destination: destinationFor(request),
872
+ error: `sno-station-mem: llm-client [${request.callId}] routed off (${decision.reason}); deterministic fallback applies`
873
+ }, {
874
+ event_name: "memory.llm_client.diagnostic",
875
+ file: "packages/memory/src/model/llm-client.ts",
876
+ function: "resolveRequestTransport",
877
+ site_id: "shared.llm-client.resolveRequestTransport.8f631601af"
878
+ });
879
+ return null;
880
+ }
881
+ if (decision.transport === "agent-host-seam") {
882
+ if (config.agentPort) return "agent-host-seam";
883
+ state.error = `sno-station-mem: llm-client [${request.callId}] routed to agent-host-seam but AgentLlmPort is unavailable`;
884
+ log.warn("Model client request diagnostic", {
885
+ call_id: request.callId,
886
+ destination: destinationFor(request),
887
+ error: state.error
888
+ }, {
889
+ event_name: "memory.llm_client.diagnostic",
890
+ file: "packages/memory/src/model/llm-client.ts",
891
+ function: "resolveRequestTransport",
892
+ site_id: "shared.llm-client.resolveRequestTransport.ffa933b519"
893
+ });
894
+ return null;
895
+ }
896
+ return decision.transport;
897
+ };
898
+ const requestContent = async (state, request, systemContent, prompt = request.prompt, forcedDestination) => {
899
+ checkMemoryOperation();
900
+ state.error = null;
901
+ state.usage = null;
902
+ const transport = forcedDestination === "host" ? "agent-host-seam" : resolveRequestTransport(state, request);
903
+ if (!transport) return null;
904
+ const route = config.routing ? resolveLlmRoute({
905
+ callId: request.callId,
906
+ config: config.routing
907
+ }) : null;
908
+ const destination = forcedDestination ?? (route && "destination" in route ? route.destination : "host");
909
+ if (transport === "agent-host-seam") {
910
+ const agentPort = config.agentPort;
911
+ if (!agentPort) throw new LlmClientTerminalError("transport", `sno-station-mem: llm-client [${request.callId}] AgentLlmPort is unavailable`);
912
+ config.onTransportAttempt?.({
913
+ callId: request.callId,
914
+ destination,
915
+ transport
916
+ });
917
+ const hostStarted = performance.now();
918
+ const hostInFlight = ++hostRequestsInFlight;
919
+ const result = await withLogContext({ attempt_id: randomUUID() }, async () => {
920
+ let outcome = "failed";
921
+ try {
922
+ const completion = await agentPort.complete({
923
+ system: systemContent,
924
+ prompt,
925
+ maxTokens: request.maxTokens ?? 4096,
926
+ ...request.enableThinking !== void 0 ? { enableThinking: request.enableThinking } : {},
927
+ timeoutMs: resolveRequestTimeoutMs(request),
928
+ ...request.signal ? { signal: request.signal } : {}
929
+ });
930
+ outcome = completion.kind;
931
+ return completion;
932
+ } finally {
933
+ hostRequestsInFlight -= 1;
934
+ log.info("Host model request completed", {
935
+ outcome,
936
+ transport: "agent-host-seam",
937
+ call_id: request.callId,
938
+ destination,
939
+ duration_ms: performance.now() - hostStarted,
940
+ in_flight_at_dispatch: hostInFlight,
941
+ requested_model: "unavailable",
942
+ returned_model: "unavailable",
943
+ usage: { source: "unavailable" },
944
+ prompt_template_hash: request.promptTemplateHash ?? "unavailable",
945
+ extraction_skill_hash: request.extractionSkillHash ?? "unavailable",
946
+ prompt_template_unavailable_reason: request.promptTemplateHash ? void 0 : "caller_does_not_provide_template_identity",
947
+ config_hash: createHash("sha256").update(JSON.stringify({
948
+ transport,
949
+ maxTokens: request.maxTokens ?? 4096,
950
+ timeoutMs: resolveRequestTimeoutMs(request)
951
+ })).digest("hex"),
952
+ output_cap: "unavailable",
953
+ passed_output_cap: request.maxTokens ?? 4096,
954
+ output_cap_reason: "host_may_strip_requested_cap",
955
+ timeout_ms: resolveRequestTimeoutMs(request),
956
+ sampling: { source: "unknown" },
957
+ finish_reason: "unavailable",
958
+ route: "agent-host-seam",
959
+ dispatch_to_headers_ms: "unavailable",
960
+ headers_to_body_ms: "unavailable",
961
+ first_token_ms: "unavailable",
962
+ provider_unavailable_reason: "host_port_does_not_report_provider_fields"
963
+ }, {
964
+ event_name: "llm.request.completed",
965
+ file: "packages/memory/src/model/llm-client.ts",
966
+ function: "requestContent",
967
+ site_id: "llm.host.request.completed"
968
+ });
969
+ }
970
+ });
971
+ if (result.kind === "cancelled") {
972
+ state.error = `[${request.callId}] agent-llm cancelled (${result.reason})`;
973
+ log.warn("Host model request cancelled", {
974
+ call_id: request.callId,
975
+ destination,
976
+ error: state.error
977
+ }, {
978
+ event_name: "memory.llm_client.diagnostic",
979
+ file: "packages/memory/src/model/llm-client.ts",
980
+ function: "requestContent",
981
+ site_id: "llm.client.host_cancelled"
982
+ });
983
+ throw new LlmClientTerminalError("cancelled", state.error, result.reason === "deadline" && !request.signal?.aborted);
984
+ }
985
+ if (result.kind === "error") {
986
+ state.error = `[${request.callId}] agent-llm ${result.category}: ${result.message}`;
987
+ recordProviderFailure({
988
+ callId: request.callId,
989
+ destination: "host",
990
+ provider: "agent-host-seam",
991
+ failure: `host_${result.category}`,
992
+ durationMs: performance.now() - hostStarted
993
+ });
994
+ log.warn("Host model request failed", {
995
+ call_id: request.callId,
996
+ destination,
997
+ failure_category: result.category,
998
+ error: state.error
999
+ }, {
1000
+ event_name: "memory.llm_client.diagnostic",
1001
+ file: "packages/memory/src/model/llm-client.ts",
1002
+ function: "requestContent",
1003
+ site_id: "llm.client.host_error"
1004
+ });
1005
+ if (config.refuseOnUnavailable && ([
1006
+ "auth",
1007
+ "credential-expired",
1008
+ "credential-revoked",
1009
+ "exhausted",
1010
+ "throttle"
1011
+ ].includes(result.category) || result.message === "no-agent-endpoint" || result.message.includes("HTTP 503") || result.message.includes("worker-not-ready") || result.message.includes("stale-binding"))) throw new ModelCallRefusedError(request.callId, "host", result.message);
1012
+ if (isCredentialFailure(result.category)) throw new LlmClientTerminalError("auth", state.error);
1013
+ return null;
1014
+ }
1015
+ return {
1016
+ raw: result.text,
1017
+ transport
1018
+ };
1019
+ }
1020
+ const endpoint = await getEndpoint(request.callId, transport);
1021
+ checkMemoryOperation();
1022
+ const preset = endpoint.preset;
1023
+ const apiKey = resolveProviderApiKey(config, preset, endpoint.userBaseUrlOverride);
1024
+ const operationId = config.operationId ?? memoryOperationId();
1025
+ if (transport === "raw-completions") {
1026
+ if (preset.provider !== "sno-gpu") throw new Error("raw completion requires the sno-gpu provider");
1027
+ if (MODEL_CALLS[request.callId].replyParser.snoGpu !== "single-token-verdict" && !request.maxTokens) log.error("Model client request diagnostic", {
1028
+ call_id: request.callId,
1029
+ destination,
1030
+ error: `sno-station-mem llm-client: raw completion [${request.callId}] set no maxTokens; sending ${RAW_COMPLETION_FALLBACK_MAX_TOKENS} so the call still runs. Fix the caller — without a cap the serving side truncates at 16 tokens.`
1031
+ }, {
1032
+ event_name: "memory.llm_client.diagnostic",
1033
+ file: "packages/memory/src/model/llm-client.ts",
1034
+ function: "requestContent",
1035
+ site_id: "shared.llm-client.requestContent.ff17976562"
1036
+ });
1037
+ const pipelineConfig = {
1038
+ ...buildPipelineConfig(preset, config, endpoint, request, destination, operationId),
1039
+ rawCompletion: {
1040
+ endpointUrl: endpoint.url,
1041
+ prompt,
1042
+ timeoutMs: resolveRequestTimeoutMs(request),
1043
+ maxTokens: request.maxTokens ?? RAW_COMPLETION_FALLBACK_MAX_TOKENS,
1044
+ ...request.requestId ? { requestId: request.requestId } : {},
1045
+ ...operationId ? { operationId } : {},
1046
+ ...MODEL_CALLS[request.callId].replyParser.snoGpu === "single-token-verdict" ? { singleTokenVerdict: true } : {},
1047
+ ...request.signal ? { signal: request.signal } : {}
1048
+ }
1049
+ };
1050
+ pipeline.setKeyPool(preset.provider, new KeyPool(apiKey.split(",")));
1051
+ config.onTransportAttempt?.({
1052
+ callId: request.callId,
1053
+ destination,
1054
+ transport
1055
+ });
1056
+ const response = await pipeline.call({
1057
+ config: pipelineConfig,
1058
+ messages: [prompt]
1059
+ });
1060
+ if (!response.success) {
1061
+ state.error = `sno-station-mem: llm-client [${request.callId}] pipeline error: ${response.error}`;
1062
+ log.warn("Raw model request failed", {
1063
+ call_id: request.callId,
1064
+ destination,
1065
+ error: state.error
1066
+ }, {
1067
+ event_name: "memory.llm_client.diagnostic",
1068
+ file: "packages/memory/src/model/llm-client.ts",
1069
+ function: "requestContent",
1070
+ site_id: "llm.client.raw_pipeline_failed"
1071
+ });
1072
+ const category = getProviderTerminalCategory(response.error);
1073
+ if (config.refuseOnUnavailable && (category === "auth" || classifyLlmFailure({ message: response.error }).category === "auth" || /(?:ECONNREFUSED|\b5\d\d\b)/i.test(response.error ?? ""))) throw new ModelCallRefusedError(request.callId, "sno-gpu", response.error ?? "model unavailable");
1074
+ if (category) throw new LlmClientTerminalError(category, state.error);
1075
+ return null;
1076
+ }
1077
+ state.usage = response.usage;
1078
+ return {
1079
+ raw: response.content,
1080
+ transport
1081
+ };
1082
+ }
1083
+ const pipelineConfig = buildPipelineConfig(preset, config, endpoint, request, destination, operationId);
1084
+ pipeline.setKeyPool(preset.provider, new KeyPool(apiKey.split(",")));
1085
+ config.onTransportAttempt?.({
1086
+ callId: request.callId,
1087
+ destination,
1088
+ transport
1089
+ });
1090
+ const response = await pipeline.call({
1091
+ config: pipelineConfig,
1092
+ messages: [{
1093
+ role: "system",
1094
+ content: systemContent
1095
+ }, {
1096
+ role: "user",
1097
+ content: prompt
1098
+ }]
1099
+ });
1100
+ if (!response.success) {
1101
+ state.error = `sno-station-mem: llm-client [${request.callId}] pipeline error: ${response.error}`;
1102
+ log.warn("Chat model request failed", {
1103
+ call_id: request.callId,
1104
+ destination,
1105
+ error: state.error
1106
+ }, {
1107
+ event_name: "memory.llm_client.diagnostic",
1108
+ file: "packages/memory/src/model/llm-client.ts",
1109
+ function: "requestContent",
1110
+ site_id: "llm.client.chat_pipeline_failed"
1111
+ });
1112
+ const category = getProviderTerminalCategory(response.error);
1113
+ if (config.refuseOnUnavailable && (category === "auth" || classifyLlmFailure({ message: response.error }).category === "auth" || /(?:ECONNREFUSED|\b5\d\d\b)/i.test(response.error ?? ""))) throw new ModelCallRefusedError(request.callId, "sno-gpu", response.error ?? "model unavailable");
1114
+ if (category) throw new LlmClientTerminalError(category, state.error);
1115
+ return null;
1116
+ }
1117
+ state.usage = response.usage;
1118
+ const raw = response.content;
1119
+ if (!raw) {
1120
+ state.error = `sno-station-mem: llm-client [${request.callId}] empty response from preset ${config.preset}`;
1121
+ log.warn("Model reply empty", {
1122
+ call_id: request.callId,
1123
+ destination,
1124
+ error: state.error
1125
+ }, {
1126
+ event_name: "memory.llm_client.diagnostic",
1127
+ file: "packages/memory/src/model/llm-client.ts",
1128
+ function: "requestContent",
1129
+ site_id: "llm.client.empty_reply"
1130
+ });
1131
+ return {
1132
+ raw: "",
1133
+ transport
1134
+ };
1135
+ }
1136
+ return {
1137
+ raw,
1138
+ transport
1139
+ };
1140
+ };
1141
+ const addUsage = (total, more) => total && more ? {
1142
+ inputTokens: total.inputTokens + more.inputTokens,
1143
+ outputTokens: total.outputTokens + more.outputTokens,
1144
+ totalTokens: total.totalTokens + more.totalTokens
1145
+ } : total ?? more;
1146
+ /**
1147
+ * Wraps `requestContent` with the bounded re-ask described on `EMPTY_REPLY_ATTEMPTS`. A `null`
1148
+ * result is returned untouched — it means no call was made, not that the model said nothing.
1149
+ */
1150
+ const requestContentRetryingEmpty = async (state, request, systemContent, deadlineMs, prompt = request.prompt) => {
1151
+ let content = await requestContent(state, request, systemContent, prompt);
1152
+ let usage = state.usage;
1153
+ try {
1154
+ checkMemoryOperation();
1155
+ const attemptLimit = request.emptyReplyAttempts ?? EMPTY_REPLY_ATTEMPTS;
1156
+ for (let attempt = 2; attempt <= attemptLimit; attempt += 1) {
1157
+ if (content === null || content.raw.trim().length > 0) break;
1158
+ const remainingMs = deadlineMs - performance.now();
1159
+ if (remainingMs <= 0) break;
1160
+ log.debug("Retrying empty model reply", {
1161
+ call_id: request.callId,
1162
+ destination: destinationFor(request),
1163
+ attempt,
1164
+ attempt_limit: attemptLimit
1165
+ }, {
1166
+ event_name: "memory.llm_client.diagnostic",
1167
+ file: "packages/memory/src/model/llm-client.ts",
1168
+ function: "requestContentRetryingEmpty",
1169
+ site_id: "shared.llm-client.requestContentRetryingEmpty.cd874fefff"
1170
+ });
1171
+ content = await requestContent(state, {
1172
+ ...request,
1173
+ timeoutMs: remainingMs
1174
+ }, systemContent, prompt);
1175
+ usage = addUsage(usage, state.usage);
1176
+ checkMemoryOperation();
1177
+ }
1178
+ } finally {
1179
+ state.usage = usage;
1180
+ }
1181
+ return content;
1182
+ };
1183
+ const requestContentWithHostFallback = async (state, request, systemContent, deadlineMs) => {
1184
+ let content = null;
1185
+ let snoError;
1186
+ try {
1187
+ content = await requestContentRetryingEmpty(state, request, systemContent, deadlineMs);
1188
+ } catch (error) {
1189
+ snoError = error;
1190
+ }
1191
+ if (destinationFor(request) !== "sno-gpu" || content?.raw.trim()) {
1192
+ if (snoError !== void 0) throw snoError;
1193
+ return content;
1194
+ }
1195
+ if (request.signal?.aborted || snoError instanceof LlmClientTerminalError && snoError.category === "cancelled" && !snoError.requestTimedOut) {
1196
+ if (snoError !== void 0) throw snoError;
1197
+ return content;
1198
+ }
1199
+ const originalLastError = state.error;
1200
+ const originalLastUsage = state.usage;
1201
+ const source = snoError instanceof Error ? snoError.message : originalLastError ?? "";
1202
+ const status = /\bHTTP ([1-5]\d\d)\b/.exec(source)?.[1];
1203
+ let snoFailure = "transport";
1204
+ if (status) snoFailure = `HTTP ${status}`;
1205
+ else if (content) snoFailure = "empty_reply";
1206
+ else if (snoError instanceof LlmClientTerminalError) snoFailure = snoError.category;
1207
+ else if (!config.apiKey?.trim()) snoFailure = "missing_key";
1208
+ const operationId = config.operationId ?? memoryOperationId();
1209
+ let hostFailure = "empty_reply";
1210
+ if (!config.agentPort) hostFailure = "port_unavailable";
1211
+ else if ([
1212
+ "E10",
1213
+ "P1",
1214
+ "REM1"
1215
+ ].includes(request.callId) && !request.hostPrompt) hostFailure = "host_prompt_missing";
1216
+ else try {
1217
+ const host = await requestContent(state, request, systemContent, request.hostPrompt ?? request.prompt, "host");
1218
+ if (host?.raw.trim()) {
1219
+ log.info("Sno model call answered by host", {
1220
+ call_id: request.callId,
1221
+ operation_id: operationId,
1222
+ sno_failure: snoFailure,
1223
+ host_outcome: "answered",
1224
+ timeout_ms: resolveRequestTimeoutMs(request)
1225
+ }, {
1226
+ event_name: "memory.llm_client.fallback",
1227
+ file: "packages/memory/src/model/llm-client.ts",
1228
+ function: "requestContentWithHostFallback",
1229
+ site_id: "llm.client.fallback.answered"
1230
+ });
1231
+ state.usage = addUsage(originalLastUsage, state.usage);
1232
+ return host;
1233
+ }
1234
+ if (host === null) hostFailure = "host_error";
1235
+ } catch (error) {
1236
+ if (request.signal?.aborted) throw error;
1237
+ hostFailure = error instanceof LlmClientTerminalError ? error.category : "transport";
1238
+ }
1239
+ state.error = originalLastError;
1240
+ state.usage = originalLastUsage;
1241
+ log.warn("Sno model call and host fallback failed", {
1242
+ call_id: request.callId,
1243
+ operation_id: operationId,
1244
+ sno_failure: snoFailure,
1245
+ host_failure: hostFailure
1246
+ }, {
1247
+ event_name: "memory.llm_client.fallback",
1248
+ file: "packages/memory/src/model/llm-client.ts",
1249
+ function: "requestContentWithHostFallback",
1250
+ site_id: "llm.client.fallback.failed"
1251
+ });
1252
+ if (snoError !== void 0) throw snoError;
1253
+ return content;
1254
+ };
1255
+ return {
1256
+ /** Implements complete json as the local LLM transport operation. */
1257
+ async completeJson(input) {
1258
+ const state = {
1259
+ error: null,
1260
+ usage: null
1261
+ };
1262
+ const request = normalizeMemoryLlmRequest({
1263
+ ...input,
1264
+ signal: memoryOperationSignal(input.signal)
1265
+ });
1266
+ checkMemoryOperation();
1267
+ const deadlineMs = performance.now() + resolveRequestTimeoutMs(request);
1268
+ try {
1269
+ let content = await requestContentWithHostFallback(state, request, JSON_SYSTEM_CONTENT, deadlineMs);
1270
+ if (content === null) return null;
1271
+ let parsed = parseJsonResponse(content.raw, input.accept);
1272
+ if (parsed.ok) return parsed.value;
1273
+ if (content.transport === "agent-host-seam" && destinationFor(request) !== "sno-gpu") {
1274
+ const remainingTimeoutMs = Math.floor(deadlineMs - performance.now());
1275
+ if (remainingTimeoutMs <= 0) {
1276
+ state.error = `sno-station-mem: llm-client [${request.callId}] deadline exhausted before JSON repair`;
1277
+ log.warn("Model repair deadline exhausted", {
1278
+ call_id: request.callId,
1279
+ destination: destinationFor(request),
1280
+ error: state.error
1281
+ }, {
1282
+ event_name: "memory.llm_client.diagnostic",
1283
+ file: "packages/memory/src/model/llm-client.ts",
1284
+ function: "completeJson",
1285
+ site_id: "llm.client.json.deadline_exhausted"
1286
+ });
1287
+ throw new LlmClientTerminalError("cancelled", state.error, true);
1288
+ }
1289
+ content = await requestContentRetryingEmpty(state, {
1290
+ ...request,
1291
+ timeoutMs: remainingTimeoutMs
1292
+ }, JSON_SYSTEM_CONTENT, deadlineMs, `${request.prompt}\n\n${JSON_REPAIR_INSTRUCTION}`);
1293
+ if (content === null) return null;
1294
+ parsed = parseJsonResponse(content.raw, input.accept);
1295
+ if (parsed.ok) return parsed.value;
1296
+ }
1297
+ state.error = `sno-station-mem: llm-client [${request.callId}] ${parsed.error}`;
1298
+ log.warn("Model client request diagnostic", {
1299
+ operation: "completeJson",
1300
+ call_id: request.callId,
1301
+ destination: destinationFor(request),
1302
+ error: state.error
1303
+ }, {
1304
+ event_name: "memory.llm_client.diagnostic",
1305
+ file: "packages/memory/src/model/llm-client.ts",
1306
+ function: "completeJson",
1307
+ site_id: "shared.llm-client.completeJson.e04c8e7e82"
1308
+ });
1309
+ return null;
1310
+ } catch (err) {
1311
+ checkMemoryOperation();
1312
+ if (err instanceof LlmClientTerminalError || err instanceof ModelCallRefusedError) throw err;
1313
+ state.error = `sno-station-mem: llm-client [${request.callId}] request failed for preset ${config.preset}: ${err instanceof Error ? err.message : String(err)}`;
1314
+ log.warn("Model request failed", {
1315
+ call_id: request.callId,
1316
+ destination: destinationFor(request),
1317
+ error: state.error
1318
+ }, {
1319
+ event_name: "memory.llm_client.diagnostic",
1320
+ file: "packages/memory/src/model/llm-client.ts",
1321
+ function: "completeJson",
1322
+ site_id: "llm.client.json.request_failed"
1323
+ });
1324
+ return null;
1325
+ } finally {
1326
+ lastError = state.error;
1327
+ lastUsage = state.usage;
1328
+ }
1329
+ },
1330
+ async completeText(input) {
1331
+ const state = {
1332
+ error: null,
1333
+ usage: null
1334
+ };
1335
+ const request = normalizeMemoryLlmRequest({
1336
+ ...input,
1337
+ signal: memoryOperationSignal(input.signal)
1338
+ });
1339
+ checkMemoryOperation();
1340
+ const deadlineMs = performance.now() + resolveRequestTimeoutMs(request);
1341
+ try {
1342
+ const text = (await requestContentWithHostFallback(state, request, textSystemContent(request), deadlineMs))?.raw.trim();
1343
+ return text && text.length > 0 ? text : null;
1344
+ } catch (err) {
1345
+ checkMemoryOperation();
1346
+ if (err instanceof LlmClientTerminalError || err instanceof ModelCallRefusedError) throw err;
1347
+ state.error = `sno-station-mem: llm-client [${request.callId}] request failed for preset ${config.preset}: ${err instanceof Error ? err.message : String(err)}`;
1348
+ log.warn("Model client request diagnostic", {
1349
+ call_id: request.callId,
1350
+ destination: destinationFor(request),
1351
+ error: state.error
1352
+ }, {
1353
+ event_name: "memory.llm_client.diagnostic",
1354
+ file: "packages/memory/src/model/llm-client.ts",
1355
+ function: "completeText",
1356
+ site_id: "shared.llm-client.completeText.ffa933b519"
1357
+ });
1358
+ return null;
1359
+ } finally {
1360
+ lastError = state.error;
1361
+ lastUsage = state.usage;
1362
+ }
1363
+ },
1364
+ getResolvedConfig() {
1365
+ return getPreset();
1366
+ },
1367
+ /** Returns last error from LLM transport state without side effects. */
1368
+ getLastError() {
1369
+ return lastError;
1370
+ },
1371
+ /** Returns provider usage from the last successful provider response. */
1372
+ getLastUsage() {
1373
+ return lastUsage;
1374
+ }
1375
+ };
1376
+ }
1377
+ //#endregion
1378
+ export { isTerminalLlmFailure as a, createLlmClient as i, LlmClientTerminalError as n, ModelCallRefusedError as r, JSON_SYSTEM_CONTENT as t };