@remnic/core 9.54.4 → 9.54.6

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 (648) hide show
  1. package/dist/access-admin-ops-surface.d.ts +24 -23
  2. package/dist/access-admin-ops-surface.js +55 -50
  3. package/dist/access-authorization-probe.d.ts +25 -22
  4. package/dist/access-authorization-probe.js +58 -51
  5. package/dist/access-boundary.d.ts +26 -23
  6. package/dist/access-boundary.js +59 -52
  7. package/dist/access-cli.js +115 -107
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-coding-context-resolution.d.ts +1 -1
  10. package/dist/access-extraction-force-flush.d.ts +19 -18
  11. package/dist/access-extraction-force-flush.js +55 -50
  12. package/dist/access-health-types.d.ts +1 -1
  13. package/dist/access-http-lcm-compaction.d.ts +22 -21
  14. package/dist/access-http-lifecycle-flush.d.ts +22 -21
  15. package/dist/access-http-offline-stream.d.ts +19 -18
  16. package/dist/access-http-query.js +55 -50
  17. package/dist/access-http.d.ts +55 -36
  18. package/dist/access-http.js +76 -65
  19. package/dist/access-identity-continuity-surface.d.ts +9 -9
  20. package/dist/access-identity-continuity-surface.js +55 -50
  21. package/dist/access-lcm-surface.d.ts +21 -20
  22. package/dist/access-lcm-surface.js +55 -50
  23. package/dist/access-mcp.d.ts +22 -21
  24. package/dist/access-mcp.js +63 -57
  25. package/dist/access-memory-search-fanout.d.ts +22 -2
  26. package/dist/access-memory-search-fanout.js +1 -1
  27. package/dist/{access-namespace-preflight-C7n4tgWC.d.ts → access-namespace-preflight-CCNn_6NE.d.ts} +1 -1
  28. package/dist/access-namespace-preflight.d.ts +3 -3
  29. package/dist/access-namespace-preflight.js +55 -50
  30. package/dist/access-observe-write-surface.d.ts +22 -21
  31. package/dist/access-observe-write-surface.js +55 -50
  32. package/dist/access-offline-manifest.d.ts +10 -9
  33. package/dist/access-offline-manifest.js +12 -10
  34. package/dist/access-operations-batch.js +57 -52
  35. package/dist/access-operations.d.ts +23 -22
  36. package/dist/access-operations.js +61 -55
  37. package/dist/access-recall-concurrency.d.ts +21 -20
  38. package/dist/access-recall-concurrency.js +55 -50
  39. package/dist/access-recall-response.d.ts +19 -18
  40. package/dist/access-recall-response.js +55 -50
  41. package/dist/access-recall-surface.d.ts +19 -18
  42. package/dist/access-recall-surface.js +55 -50
  43. package/dist/access-schema.d.ts +2 -2
  44. package/dist/access-schema.js +5 -4
  45. package/dist/{access-service-CXvbxLK-.d.ts → access-service-DkSdXK4S.d.ts} +1314 -83
  46. package/dist/access-service-helpers.d.ts +22 -21
  47. package/dist/access-service.d.ts +31 -30
  48. package/dist/access-service.js +55 -50
  49. package/dist/access-surface-catalog.d.ts +22 -21
  50. package/dist/access-surface-catalog.js +209 -2
  51. package/dist/access-surface-catalog.js.map +1 -1
  52. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  53. package/dist/action-confidence.d.ts +1 -1
  54. package/dist/active-memory-bridge.d.ts +14 -1
  55. package/dist/active-memory-bridge.js +6 -1
  56. package/dist/active-recall.d.ts +1 -1
  57. package/dist/active-recall.js +4 -2
  58. package/dist/active-recall.js.map +1 -1
  59. package/dist/adapters/index.js +7 -7
  60. package/dist/adapters/registry.js +3 -3
  61. package/dist/admin-console/public/what-helps-me/app.js +1594 -0
  62. package/dist/admin-console/public/what-helps-me/index.html +339 -0
  63. package/dist/admin-console/public/what-helps-me/model.js +685 -0
  64. package/dist/admin-console/public/what-helps-me/what-helps-me.css +1296 -0
  65. package/dist/ambient-provenance.d.ts +1 -1
  66. package/dist/artifact-search.d.ts +1 -1
  67. package/dist/{auto-sync-TDHLZPVP.js → auto-sync-NR3GPCOA.js} +4 -4
  68. package/dist/behavior-learner.d.ts +1 -1
  69. package/dist/behavior-signals.d.ts +1 -1
  70. package/dist/bootstrap.d.ts +9 -9
  71. package/dist/briefing.d.ts +2 -2
  72. package/dist/briefing.js +33 -12
  73. package/dist/buffer-surprise-report.d.ts +1 -1
  74. package/dist/buffer-turn-helpers.d.ts +1 -1
  75. package/dist/buffer.d.ts +2 -2
  76. package/dist/buffer.js +3 -3
  77. package/dist/bulk-import/index.d.ts +3 -3
  78. package/dist/calibration.d.ts +1 -1
  79. package/dist/calibration.js +1 -1
  80. package/dist/capabilities.d.ts +1 -1
  81. package/dist/{catalog-BOOxl-I2.d.ts → catalog-DGFf8mD9.d.ts} +1 -1
  82. package/dist/causal-behavior.d.ts +1 -1
  83. package/dist/causal-consolidation.d.ts +1 -1
  84. package/dist/causal-consolidation.js +34 -13
  85. package/dist/causal-consolidation.js.map +1 -1
  86. package/dist/causal-trajectory-graph.d.ts +1 -1
  87. package/dist/{chunk-ZYLC7NFO.js → chunk-26ZXBTYN.js} +4 -4
  88. package/dist/chunk-26ZXBTYN.js.map +1 -0
  89. package/dist/{chunk-LLJMAULE.js → chunk-2FKEIPIT.js} +5 -5
  90. package/dist/{chunk-3CSX3ETE.js → chunk-2LWQSV6A.js} +23 -11
  91. package/dist/chunk-2LWQSV6A.js.map +1 -0
  92. package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
  93. package/dist/chunk-37DZZFFM.js +502 -0
  94. package/dist/chunk-37DZZFFM.js.map +1 -0
  95. package/dist/chunk-3HSRWJTC.js +9 -0
  96. package/dist/chunk-3HSRWJTC.js.map +1 -0
  97. package/dist/{chunk-XUAMCLY4.js → chunk-3TIZPSJC.js} +17 -13
  98. package/dist/chunk-3TIZPSJC.js.map +1 -0
  99. package/dist/{chunk-PDDTI7IC.js → chunk-43SEBY2M.js} +1 -1
  100. package/dist/{chunk-HWRD23DW.js → chunk-46SZBVDS.js} +3 -3
  101. package/dist/{chunk-6HPHEFXT.js → chunk-5FD7JMTX.js} +2 -2
  102. package/dist/{chunk-7BZOBA5J.js → chunk-5NB726GV.js} +70 -16
  103. package/dist/chunk-5NB726GV.js.map +1 -0
  104. package/dist/chunk-62OKGIJA.js +39 -0
  105. package/dist/chunk-62OKGIJA.js.map +1 -0
  106. package/dist/{chunk-IBKR2TFR.js → chunk-6CYHUWCO.js} +2 -2
  107. package/dist/{chunk-YN6ASZUG.js → chunk-6QPI2ITJ.js} +5 -5
  108. package/dist/{chunk-UU3G6GUP.js → chunk-76JJSXK7.js} +1 -1
  109. package/dist/chunk-76JJSXK7.js.map +1 -0
  110. package/dist/{chunk-PX2LSHYM.js → chunk-7BD6O7ZV.js} +189 -4
  111. package/dist/chunk-7BD6O7ZV.js.map +1 -0
  112. package/dist/chunk-7TBXNYLO.js +346 -0
  113. package/dist/chunk-7TBXNYLO.js.map +1 -0
  114. package/dist/{chunk-NH5IR2WM.js → chunk-BRR5EUTF.js} +6 -2
  115. package/dist/chunk-BRR5EUTF.js.map +1 -0
  116. package/dist/{chunk-NIS256NW.js → chunk-CIAI24TQ.js} +3 -3
  117. package/dist/{chunk-T2JHZWH6.js → chunk-D3LBIUWV.js} +11703 -7573
  118. package/dist/chunk-D3LBIUWV.js.map +1 -0
  119. package/dist/{chunk-7FGL6CGA.js → chunk-DVYRD4HY.js} +2 -2
  120. package/dist/{chunk-G7Z6EENO.js → chunk-EKTP7MNS.js} +4 -4
  121. package/dist/{chunk-S75M5ZRK.js → chunk-F2JRDPON.js} +16 -1
  122. package/dist/chunk-F2JRDPON.js.map +1 -0
  123. package/dist/{chunk-RZ4XGKOJ.js → chunk-FFRTNF3L.js} +8 -8
  124. package/dist/{chunk-VKXWK44Q.js → chunk-FONWBCVY.js} +3 -3
  125. package/dist/{chunk-DZD576ZU.js → chunk-FPLM2TKD.js} +2 -2
  126. package/dist/{chunk-ZPJ4QSGP.js → chunk-FTPONF6B.js} +2 -2
  127. package/dist/{chunk-LJS7KUPV.js → chunk-FWX7W5PM.js} +2 -2
  128. package/dist/{chunk-UTRO5UJU.js → chunk-G6DFSS6A.js} +5 -1
  129. package/dist/chunk-G6DFSS6A.js.map +1 -0
  130. package/dist/{chunk-6LAPLZOS.js → chunk-GJ776BC2.js} +8 -3
  131. package/dist/chunk-GJ776BC2.js.map +1 -0
  132. package/dist/{chunk-G4T7L557.js → chunk-GN3WRFJY.js} +6 -6
  133. package/dist/{chunk-QT2FRYI4.js → chunk-H7NAZ3UB.js} +2 -2
  134. package/dist/{chunk-APPFNGX6.js → chunk-HBUFQRIM.js} +2 -2
  135. package/dist/{chunk-UU7TRFNE.js → chunk-HGJ6NJ4E.js} +2 -2
  136. package/dist/{chunk-WB7JSQCP.js → chunk-HIEWDJ2O.js} +5 -2
  137. package/dist/{chunk-WB7JSQCP.js.map → chunk-HIEWDJ2O.js.map} +1 -1
  138. package/dist/{chunk-UES4BHA2.js → chunk-I3MSGFGD.js} +17 -6
  139. package/dist/chunk-I3MSGFGD.js.map +1 -0
  140. package/dist/{chunk-C4ZNGVK3.js → chunk-IKP5OYQQ.js} +2 -2
  141. package/dist/{chunk-KQAFEZQX.js → chunk-IPLYGWQF.js} +5 -5
  142. package/dist/{chunk-RDJRFDJY.js → chunk-IQ4NVWEF.js} +2 -2
  143. package/dist/{chunk-CGVHPCP2.js → chunk-JYG4OLWH.js} +2 -2
  144. package/dist/{chunk-WOPA3SGI.js → chunk-K26NWEOC.js} +8 -8
  145. package/dist/{chunk-K4QS7LXU.js → chunk-K2UGPTYY.js} +485 -44
  146. package/dist/chunk-K2UGPTYY.js.map +1 -0
  147. package/dist/{chunk-L6CQ7WIW.js → chunk-KFBOPMF6.js} +11 -11
  148. package/dist/chunk-KFBOPMF6.js.map +1 -0
  149. package/dist/{chunk-G7A5HLUS.js → chunk-KJH6W2I7.js} +2 -2
  150. package/dist/{chunk-IXEBUYO4.js → chunk-KM55SMLG.js} +11 -2
  151. package/dist/{chunk-IXEBUYO4.js.map → chunk-KM55SMLG.js.map} +1 -1
  152. package/dist/{chunk-HOIRB77A.js → chunk-L6Z5OAS4.js} +2 -2
  153. package/dist/chunk-LC2BDILZ.js +57 -0
  154. package/dist/chunk-LC2BDILZ.js.map +1 -0
  155. package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
  156. package/dist/{chunk-6R4G7N4S.js → chunk-M4YHAODQ.js} +388 -748
  157. package/dist/chunk-M4YHAODQ.js.map +1 -0
  158. package/dist/{chunk-3JLPGJ43.js → chunk-MIH3CJPN.js} +5 -5
  159. package/dist/{chunk-QHFV6VNU.js → chunk-MK5VEWCR.js} +2 -2
  160. package/dist/chunk-NISZQW72.js +140 -0
  161. package/dist/chunk-NISZQW72.js.map +1 -0
  162. package/dist/{chunk-GUKBW4HL.js → chunk-NQMSEB5D.js} +6 -6
  163. package/dist/{chunk-G2LUMAUF.js → chunk-OCIP6YMD.js} +12 -5
  164. package/dist/chunk-OCIP6YMD.js.map +1 -0
  165. package/dist/{chunk-47P3RYZP.js → chunk-PG4QBPVG.js} +21 -11
  166. package/dist/chunk-PG4QBPVG.js.map +1 -0
  167. package/dist/{chunk-WRJVB3C2.js → chunk-PO7NXBG2.js} +2 -2
  168. package/dist/{chunk-QWGE2PUH.js → chunk-PT54WISF.js} +190 -56
  169. package/dist/chunk-PT54WISF.js.map +1 -0
  170. package/dist/{chunk-AZM4CCAC.js → chunk-QZLDRQ4I.js} +8 -8
  171. package/dist/{chunk-THPPCISA.js → chunk-RBII7637.js} +5 -5
  172. package/dist/{chunk-JDZPNCMA.js → chunk-RUNORG2P.js} +6 -3
  173. package/dist/chunk-RUNORG2P.js.map +1 -0
  174. package/dist/{chunk-JV5YUBIZ.js → chunk-RZQ6W2W4.js} +50 -44
  175. package/dist/chunk-RZQ6W2W4.js.map +1 -0
  176. package/dist/{chunk-RUMNY5DT.js → chunk-SMNYAMJD.js} +6 -2
  177. package/dist/chunk-SMNYAMJD.js.map +1 -0
  178. package/dist/{chunk-MKQBXQKU.js → chunk-TB6CBZ5V.js} +22 -15
  179. package/dist/chunk-TB6CBZ5V.js.map +1 -0
  180. package/dist/{chunk-VMMQDEN5.js → chunk-TO7ZTWJW.js} +2 -2
  181. package/dist/{chunk-K2TDK7GG.js → chunk-TWTUGCTY.js} +2 -2
  182. package/dist/{chunk-HLYR2TQL.js → chunk-UCTS3DDH.js} +2 -2
  183. package/dist/{chunk-JYIJNNN3.js → chunk-UG6VXIOK.js} +2 -2
  184. package/dist/{chunk-WM65LU67.js → chunk-UKYS3NU5.js} +2 -2
  185. package/dist/{chunk-WDBX6VER.js → chunk-UPLZNJKN.js} +5 -5
  186. package/dist/{chunk-C23BYTJV.js → chunk-UW5NPZJ2.js} +40 -12
  187. package/dist/chunk-UW5NPZJ2.js.map +1 -0
  188. package/dist/{chunk-2GFK22OZ.js → chunk-V6ERBR7U.js} +2 -2
  189. package/dist/{chunk-CYF6WVE7.js → chunk-W5ZKPI34.js} +139 -158
  190. package/dist/chunk-W5ZKPI34.js.map +1 -0
  191. package/dist/chunk-XX4HPFFM.js +370 -0
  192. package/dist/chunk-XX4HPFFM.js.map +1 -0
  193. package/dist/{chunk-ZMYDYNI4.js → chunk-XZHE2DEN.js} +4 -4
  194. package/dist/chunk-YXQEKCZM.js +223 -0
  195. package/dist/chunk-YXQEKCZM.js.map +1 -0
  196. package/dist/{chunk-GYPQL6XN.js → chunk-Z4N7SVVF.js} +35 -47
  197. package/dist/chunk-Z4N7SVVF.js.map +1 -0
  198. package/dist/{chunk-MAXVH44E.js → chunk-Z54EM5YZ.js} +7 -7
  199. package/dist/{chunk-YGLY6QFV.js → chunk-ZRZVLB7O.js} +2 -2
  200. package/dist/{chunk-4IIFL7GC.js → chunk-ZUKIUXHQ.js} +10 -10
  201. package/dist/{cli-DVUFIa5E.d.ts → cli-Bze8S0Qs.d.ts} +5 -5
  202. package/dist/cli.d.ts +22 -21
  203. package/dist/cli.js +90 -80
  204. package/dist/coding/pre-action-gate.d.ts +1 -1
  205. package/dist/compounding/engine.d.ts +2 -2
  206. package/dist/compounding/engine.js +33 -12
  207. package/dist/compounding/preference-consolidator.d.ts +1 -1
  208. package/dist/compression-optimizer.d.ts +1 -1
  209. package/dist/config.d.ts +1 -1
  210. package/dist/config.js +4 -2
  211. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  212. package/dist/connectors/codex-materialize-runner.js +33 -12
  213. package/dist/connectors/codex-materialize.d.ts +1 -1
  214. package/dist/connectors/index.d.ts +1 -1
  215. package/dist/connectors/index.js +32 -12
  216. package/dist/consolidation-provenance-check.d.ts +2 -2
  217. package/dist/consolidation-undo.d.ts +2 -2
  218. package/dist/contradiction/index.d.ts +2 -2
  219. package/dist/contradiction/index.js +3 -1
  220. package/dist/contradiction-scan-JDTBXRGW.js +20 -0
  221. package/dist/converge-config.d.ts +1 -1
  222. package/dist/convergence-refresh.d.ts +2 -2
  223. package/dist/convergence-refresh.js +35 -14
  224. package/dist/conversation-index/backend.d.ts +1 -1
  225. package/dist/conversation-index/backend.js +2 -2
  226. package/dist/conversation-index/chunker.d.ts +1 -1
  227. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  228. package/dist/conversation-index/indexer.d.ts +1 -1
  229. package/dist/conversation-index/search.d.ts +1 -1
  230. package/dist/corpus-watermark.d.ts +1 -1
  231. package/dist/corpus-watermark.js +25 -24
  232. package/dist/day-summary.d.ts +1 -1
  233. package/dist/delinearize.d.ts +1 -1
  234. package/dist/dependency-propagation-config.d.ts +1 -1
  235. package/dist/{dependency-propagation-delivery-XzF76C9n.d.ts → dependency-propagation-delivery-CzEfB31P.d.ts} +1 -1
  236. package/dist/direct-answer-wiring.d.ts +1 -1
  237. package/dist/direct-answer.d.ts +1 -1
  238. package/dist/embedding-fallback.d.ts +1 -1
  239. package/dist/enrichment/index.d.ts +1 -1
  240. package/dist/entity-retrieval.d.ts +2 -2
  241. package/dist/entity-retrieval.js +33 -12
  242. package/dist/entity-schema.d.ts +1 -1
  243. package/dist/explicit-capture.d.ts +9 -9
  244. package/dist/explicit-capture.js +7 -4
  245. package/dist/external-wiki-access.d.ts +22 -21
  246. package/dist/external-wiki-access.js +56 -51
  247. package/dist/external-wiki-collection-registration.d.ts +1 -1
  248. package/dist/external-wiki-collection.d.ts +1 -1
  249. package/dist/external-wiki-mcp-tools.d.ts +22 -21
  250. package/dist/extraction-error-classification.d.ts +1 -1
  251. package/dist/extraction-faithfulness.d.ts +1 -1
  252. package/dist/extraction-faithfulness.js +2 -2
  253. package/dist/extraction-judge-telemetry.d.ts +1 -1
  254. package/dist/extraction-judge-training.d.ts +1 -1
  255. package/dist/extraction-judge.d.ts +1 -1
  256. package/dist/extraction-judge.js +2 -2
  257. package/dist/extraction-liveness.d.ts +1 -1
  258. package/dist/extraction-normalization.d.ts +1 -1
  259. package/dist/extraction-prompt.d.ts +1 -1
  260. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  261. package/dist/extraction-source-grounding.d.ts +1 -1
  262. package/dist/extraction.d.ts +1 -1
  263. package/dist/extraction.js +35 -19
  264. package/dist/fallback-llm.d.ts +14 -1
  265. package/dist/fallback-llm.js +1 -1
  266. package/dist/{first-start-migration-626C5554.js → first-start-migration-CRZCZAJN.js} +11 -3
  267. package/dist/first-start-migration-CRZCZAJN.js.map +1 -0
  268. package/dist/graph-dashboard-diff.d.ts +1 -1
  269. package/dist/graph-dashboard-key.d.ts +1 -1
  270. package/dist/graph-dashboard-parser.d.ts +1 -1
  271. package/dist/graph-edge-reinforcement.d.ts +1 -1
  272. package/dist/graph-path-reconstruction.d.ts +1 -1
  273. package/dist/graph-path-scoring.d.ts +1 -1
  274. package/dist/graph-snapshot.d.ts +1 -1
  275. package/dist/graph.d.ts +1 -1
  276. package/dist/harmonic-retrieval.js +1 -1
  277. package/dist/importance.d.ts +1 -1
  278. package/dist/importers/index.d.ts +1 -1
  279. package/dist/in-flight-reads.d.ts +1 -1
  280. package/dist/index.d.ts +314 -308
  281. package/dist/index.js +304 -133
  282. package/dist/inline-script.d.ts +3 -0
  283. package/dist/inline-script.js +8 -0
  284. package/dist/inline-script.js.map +1 -0
  285. package/dist/intent.d.ts +1 -1
  286. package/dist/lcm/engine.d.ts +1 -1
  287. package/dist/lcm/engine.js +3 -3
  288. package/dist/lcm/index.d.ts +1 -1
  289. package/dist/lcm/index.js +6 -6
  290. package/dist/lcm/tools.d.ts +1 -1
  291. package/dist/lifecycle.d.ts +1 -1
  292. package/dist/live-connectors-runner.d.ts +1 -1
  293. package/dist/local-llm.d.ts +2 -1
  294. package/dist/local-llm.js +2 -2
  295. package/dist/local-model-endpoint.d.ts +1 -1
  296. package/dist/maintenance/memory-governance.d.ts +1 -1
  297. package/dist/maintenance/memory-governance.js +33 -12
  298. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  299. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +33 -12
  300. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  301. package/dist/maintenance/rebuild-memory-projection.js +34 -13
  302. package/dist/{maintenance-BJzNIKBE.d.ts → maintenance-C8aRWfhq.d.ts} +3 -3
  303. package/dist/mcp-memory-inspector-app.d.ts +22 -21
  304. package/dist/mcp-read-only-tools.js +1 -1
  305. package/dist/memory-action-policy.d.ts +1 -1
  306. package/dist/memory-cache.d.ts +1 -1
  307. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  308. package/dist/memory-projection-mutations.js +2 -2
  309. package/dist/memory-projection-store.d.ts +6 -2
  310. package/dist/memory-projection-store.js +1 -1
  311. package/dist/memory-provenance.d.ts +1 -1
  312. package/dist/memory-snapshot.d.ts +1 -1
  313. package/dist/memory-worth-outcomes.d.ts +2 -2
  314. package/dist/models-json.d.ts +1 -1
  315. package/dist/namespaces/migrate.d.ts +3 -3
  316. package/dist/namespaces/migrate.js +24 -23
  317. package/dist/namespaces/principal.d.ts +1 -1
  318. package/dist/namespaces/search.d.ts +1 -1
  319. package/dist/namespaces/search.js +8 -8
  320. package/dist/namespaces/storage.d.ts +3 -3
  321. package/dist/namespaces/storage.js +33 -12
  322. package/dist/native-knowledge.d.ts +1 -1
  323. package/dist/offline-sync-file-io.d.ts +20 -0
  324. package/dist/offline-sync-file-io.js +18 -0
  325. package/dist/offline-sync-file-io.js.map +1 -0
  326. package/dist/offline-sync-impression-drain.d.ts +1 -1
  327. package/dist/offline-sync-impression-drain.js +5 -5
  328. package/dist/offline-sync.d.ts +8 -6
  329. package/dist/offline-sync.js +2 -1
  330. package/dist/operator-doctor-corpus.d.ts +1 -1
  331. package/dist/operator-doctor-corpus.js +26 -25
  332. package/dist/operator-doctor-replica.d.ts +1 -1
  333. package/dist/operator-toolkit.d.ts +3 -3
  334. package/dist/operator-toolkit.js +39 -36
  335. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  336. package/dist/orchestration/maintenance.d.ts +4 -4
  337. package/dist/orchestration/maintenance.js +38 -18
  338. package/dist/{orchestrator-BiXgBJBQ.d.ts → orchestrator-D85CzDDY.d.ts} +11 -8
  339. package/dist/orchestrator.d.ts +9 -9
  340. package/dist/orchestrator.js +117 -109
  341. package/dist/patterns-cli.d.ts +1 -1
  342. package/dist/{pipeline-sz_dcuLg.d.ts → pipeline-DPcUifCO.d.ts} +1 -1
  343. package/dist/policy-runtime.d.ts +1 -1
  344. package/dist/proactive-contention.d.ts +1 -1
  345. package/dist/provenance.d.ts +1 -1
  346. package/dist/public-http-D-SyWNj6.d.ts +25 -0
  347. package/dist/{purge-533FZLS4.js → purge-GB7PZHT2.js} +2 -2
  348. package/dist/{qmd-eAWObK4M.d.ts → qmd-dFCHp1r0.d.ts} +1 -1
  349. package/dist/qmd-preflight.d.ts +2 -2
  350. package/dist/qmd-recall-cache.d.ts +1 -1
  351. package/dist/qmd.d.ts +2 -2
  352. package/dist/recall-concurrency-config.d.ts +1 -1
  353. package/dist/recall-disclosure-escalation.d.ts +1 -1
  354. package/dist/recall-explain-renderer.d.ts +1 -1
  355. package/dist/recall-explain-renderer.js +3 -3
  356. package/dist/recall-memory-map.d.ts +1 -1
  357. package/dist/recall-planner-llm.d.ts +1 -1
  358. package/dist/recall-planner-llm.js +1 -1
  359. package/dist/recall-state.d.ts +1 -1
  360. package/dist/recall-tag-filter.d.ts +1 -1
  361. package/dist/recall-timings.d.ts +1 -1
  362. package/dist/recall-xray-cli.d.ts +1 -1
  363. package/dist/recall-xray-cli.js +4 -4
  364. package/dist/recall-xray-renderer.d.ts +1 -1
  365. package/dist/recall-xray-renderer.js +3 -3
  366. package/dist/recall-xray.d.ts +1 -1
  367. package/dist/recall-xray.js +2 -2
  368. package/dist/reconcile/cursor.d.ts +2 -1
  369. package/dist/reconcile/manifest.d.ts +2 -1
  370. package/dist/reconcile/manifest.js +6 -5
  371. package/dist/reconcile/plan.d.ts +2 -1
  372. package/dist/reconcile/plan.js +3 -2
  373. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  374. package/dist/replay/normalizers/claude.d.ts +1 -1
  375. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  376. package/dist/replay/normalizers/shared.d.ts +1 -1
  377. package/dist/replay/runner.d.ts +1 -1
  378. package/dist/replay/types.d.ts +1 -1
  379. package/dist/replica-divergence.d.ts +1 -1
  380. package/dist/replica-peers-config.d.ts +1 -1
  381. package/dist/resolve-auth-token.d.ts +1 -1
  382. package/dist/resume-bundles.js +5 -3
  383. package/dist/retrieval-agents.d.ts +2 -2
  384. package/dist/retrieval-tiers.d.ts +1 -1
  385. package/dist/routing/engine.d.ts +1 -1
  386. package/dist/routing/store.d.ts +1 -1
  387. package/dist/salvage-envelope.d.ts +1 -1
  388. package/dist/schemas.d.ts +38 -38
  389. package/dist/{scope-profiles-BBQsXuyj.d.ts → scope-profiles-DICK7GtN.d.ts} +1 -1
  390. package/dist/search/embed-helper.d.ts +1 -1
  391. package/dist/search/factory.d.ts +1 -1
  392. package/dist/search/factory.js +6 -6
  393. package/dist/search/index.d.ts +1 -1
  394. package/dist/search/index.js +12 -12
  395. package/dist/search/lancedb-backend.d.ts +1 -1
  396. package/dist/search/meilisearch-backend.d.ts +1 -1
  397. package/dist/search/noop-backend.d.ts +1 -1
  398. package/dist/search/orama-backend.d.ts +1 -1
  399. package/dist/search/port.d.ts +1 -1
  400. package/dist/search/remote-backend.d.ts +1 -1
  401. package/dist/{semantic-consolidation-HD8RkzVA.d.ts → semantic-consolidation-BP7NAX0N.d.ts} +1 -1
  402. package/dist/semantic-consolidation.d.ts +2 -2
  403. package/dist/semantic-consolidation.js +34 -13
  404. package/dist/semantic-rule-promotion.js +33 -12
  405. package/dist/semantic-rule-verifier.d.ts +1 -1
  406. package/dist/semantic-rule-verifier.js +33 -12
  407. package/dist/{service-DIrtHHEg.d.ts → service-DT-pJyda.d.ts} +660 -660
  408. package/dist/session-observer-bands.d.ts +1 -1
  409. package/dist/session-observer-state.d.ts +1 -1
  410. package/dist/shared-context/manager.d.ts +1 -1
  411. package/dist/signal.d.ts +1 -1
  412. package/dist/source-agent-qualifier.d.ts +1 -1
  413. package/dist/source-agent-qualifier.js +31 -15
  414. package/dist/{storage-DqCzXi56.d.ts → storage-qOnaJ1Lw.d.ts} +49 -13
  415. package/dist/storage.d.ts +2 -2
  416. package/dist/storage.js +33 -12
  417. package/dist/summarizer.d.ts +1 -1
  418. package/dist/summarizer.js +5 -5
  419. package/dist/summary-snapshot.d.ts +1 -1
  420. package/dist/support-passport/index.d.ts +518 -0
  421. package/dist/support-passport/index.js +357 -0
  422. package/dist/support-passport/index.js.map +1 -0
  423. package/dist/temporal-supersession.d.ts +2 -2
  424. package/dist/temporal-timeline-recall.d.ts +1 -1
  425. package/dist/temporal-validity.d.ts +1 -1
  426. package/dist/threading.d.ts +1 -1
  427. package/dist/tier-migration.d.ts +2 -2
  428. package/dist/tier-routing.d.ts +2 -2
  429. package/dist/tier-routing.js +7 -1
  430. package/dist/{tier-stats-2JCZYEF7.js → tier-stats-EXYSKSVN.js} +8 -2
  431. package/dist/{tier-stats-2JCZYEF7.js.map → tier-stats-EXYSKSVN.js.map} +1 -1
  432. package/dist/topics.d.ts +1 -1
  433. package/dist/transcript.d.ts +1 -1
  434. package/dist/transfer/autodetect.js +1 -1
  435. package/dist/transfer/backup.js +1 -1
  436. package/dist/transfer/capsule-export.js +2 -2
  437. package/dist/transfer/types.d.ts +36 -36
  438. package/dist/trust-score-stage.d.ts +1 -1
  439. package/dist/trust-score.d.ts +1 -1
  440. package/dist/{types-d_j4vC6N.d.ts → types-ed-SvS2t.d.ts} +8 -1
  441. package/dist/types.d.ts +1 -1
  442. package/dist/types.js +1 -1
  443. package/dist/utility-runtime.d.ts +2 -2
  444. package/dist/verified-recall.js +33 -12
  445. package/dist/write-envelope.d.ts +1 -1
  446. package/dist/write-rate-limiter.d.ts +11 -5
  447. package/dist/write-rate-limiter.js +1 -1
  448. package/package.json +12 -2
  449. package/scripts/build-with-heap.mjs +11 -1
  450. package/src/access-authorization-probe.ts +20 -2
  451. package/src/access-boundary.ts +32 -0
  452. package/src/access-http.test.ts +1971 -643
  453. package/src/access-http.ts +81 -74
  454. package/src/access-mcp.ts +3 -1
  455. package/src/access-memory-search-fanout.ts +24 -1
  456. package/src/access-offline-manifest.ts +5 -0
  457. package/src/access-operations.ts +2 -0
  458. package/src/access-service-namespace.test.ts +14 -0
  459. package/src/access-service-observe-scope.test.ts +2 -0
  460. package/src/access-service-offline-file-content.test.ts +211 -0
  461. package/src/access-service.ts +628 -884
  462. package/src/access-surface-catalog.test.ts +40 -10
  463. package/src/access-surface-catalog.ts +15 -0
  464. package/src/active-memory-bridge.test.ts +151 -0
  465. package/src/active-memory-bridge.ts +95 -21
  466. package/src/briefing.test.ts +38 -0
  467. package/src/briefing.ts +3 -3
  468. package/src/cli.ts +6 -1
  469. package/src/config.ts +18 -9
  470. package/src/connectors/codex-materialize-runner.ts +2 -0
  471. package/src/contradiction/contradiction-scan.ts +2 -0
  472. package/src/contradiction/contradiction.test.ts +42 -0
  473. package/src/correction/correction-access-wiring.ts +8 -2
  474. package/src/correction/correction-storage-integration.test.ts +7 -0
  475. package/src/explicit-capture.test.ts +24 -0
  476. package/src/explicit-capture.ts +2 -0
  477. package/src/fallback-llm.test.ts +54 -0
  478. package/src/fallback-llm.ts +54 -9
  479. package/src/index.ts +3 -0
  480. package/src/inline-script.ts +6 -0
  481. package/src/local-llm-headers-timeout.test.ts +42 -0
  482. package/src/local-llm.ts +8 -8
  483. package/src/maintenance/first-start-migration.ts +2 -1
  484. package/src/maintenance/memory-governance.test.ts +25 -0
  485. package/src/maintenance/memory-governance.ts +4 -1
  486. package/src/maintenance/pattern-reinforcement.test.ts +20 -0
  487. package/src/maintenance/pattern-reinforcement.ts +2 -1
  488. package/src/maintenance/rebuild-memory-projection.ts +8 -8
  489. package/src/mcp-read-only-tools.ts +3 -0
  490. package/src/memory-projection-store.ts +25 -27
  491. package/src/offline-sync-file-io.ts +68 -0
  492. package/src/offline-sync.ts +43 -57
  493. package/src/orchestration/consolidation-run.ts +5 -4
  494. package/src/orchestration/contradiction-linking-coordinator.ts +7 -0
  495. package/src/orchestration/contradiction-localization.integration.test.ts +115 -0
  496. package/src/orchestration/lifecycle-policy-coordinator.ts +2 -1
  497. package/src/orchestration/qmd-result-resolver.test.ts +215 -14
  498. package/src/orchestration/qmd-result-resolver.ts +142 -82
  499. package/src/orchestration/recall-search-pipeline.test.ts +41 -0
  500. package/src/orchestration/recall-search-pipeline.ts +12 -0
  501. package/src/orchestration/semantic-consolidation-coordinator.ts +2 -1
  502. package/src/orchestration/tier-migration-coordinator.ts +23 -56
  503. package/src/orchestration/workspace-ops.test.ts +37 -0
  504. package/src/orchestration/workspace-ops.ts +5 -29
  505. package/src/orchestrator.ts +7 -8
  506. package/src/relay/mission-access.test.ts +11 -11
  507. package/src/relay/mission-ui.test.ts +3 -1
  508. package/src/storage/supersession-audit.ts +7 -1
  509. package/src/storage/supersession-side-effects.ts +17 -5
  510. package/src/storage/tombstone-blocked-capture-sync.ts +31 -0
  511. package/src/storage-contract/failure-semantics.test.ts +102 -0
  512. package/src/storage.ts +18 -19
  513. package/src/support-passport/access-http-base.ts +143 -0
  514. package/src/support-passport/access-http.ts +172 -0
  515. package/src/support-passport/access-operations.ts +272 -0
  516. package/src/support-passport/access-service-base.test.ts +193 -0
  517. package/src/support-passport/access-service-base.ts +176 -0
  518. package/src/support-passport/access-surface.test.ts +283 -0
  519. package/src/support-passport/access-surface.ts +286 -0
  520. package/src/support-passport/card-projection.test.ts +137 -0
  521. package/src/support-passport/card-projection.ts +348 -0
  522. package/src/support-passport/card-replacement.ts +126 -0
  523. package/src/support-passport/card-service-commit-forwarding.test.ts +160 -0
  524. package/src/support-passport/card-service.test.ts +2964 -0
  525. package/src/support-passport/card-service.ts +1184 -0
  526. package/src/support-passport/card-state.ts +158 -0
  527. package/src/support-passport/config-model-routing.test.ts +37 -0
  528. package/src/support-passport/config.test.ts +34 -0
  529. package/src/support-passport/config.ts +41 -0
  530. package/src/support-passport/contracts.test.ts +156 -0
  531. package/src/support-passport/contracts.ts +149 -0
  532. package/src/support-passport/errors.ts +30 -0
  533. package/src/support-passport/generated-batch.test.ts +185 -0
  534. package/src/support-passport/generated-batch.ts +338 -0
  535. package/src/support-passport/grant-contracts.ts +183 -0
  536. package/src/support-passport/grant-generated-batch-scope.test.ts +201 -0
  537. package/src/support-passport/grant-service-cache.test.ts +148 -0
  538. package/src/support-passport/grant-service-cancellation.test.ts +83 -0
  539. package/src/support-passport/grant-service-marker-cache.test.ts +62 -0
  540. package/src/support-passport/grant-service.test.ts +3496 -0
  541. package/src/support-passport/grant-service.ts +513 -0
  542. package/src/support-passport/grant-store-commit-hook.test.ts +123 -0
  543. package/src/support-passport/grant-store-order.test.ts +60 -0
  544. package/src/support-passport/grant-store-path-safety.test.ts +30 -0
  545. package/src/support-passport/grant-store-recovery.test.ts +448 -0
  546. package/src/support-passport/grant-store.ts +906 -0
  547. package/src/support-passport/index.ts +17 -0
  548. package/src/support-passport/mcp-tools.test.ts +222 -0
  549. package/src/support-passport/mcp-tools.ts +187 -0
  550. package/src/support-passport/model-adapter.test.ts +840 -0
  551. package/src/support-passport/model-adapter.ts +602 -0
  552. package/src/support-passport/model-audit-pinned-write.test.ts +59 -0
  553. package/src/support-passport/model-audit.ts +152 -0
  554. package/src/support-passport/model-bridge.test.ts +456 -0
  555. package/src/support-passport/model-bridge.ts +439 -0
  556. package/src/support-passport/model-contracts.ts +124 -0
  557. package/src/support-passport/model-service.test.ts +1731 -0
  558. package/src/support-passport/model-service.ts +399 -0
  559. package/src/support-passport/offline-sync-guard.ts +230 -0
  560. package/src/support-passport/owner-http.test.ts +671 -0
  561. package/src/support-passport/owner-lock.ts +70 -0
  562. package/src/support-passport/private-file.test.ts +99 -0
  563. package/src/support-passport/private-file.ts +498 -0
  564. package/src/support-passport/public-http.test.ts +476 -0
  565. package/src/support-passport/public-http.ts +601 -0
  566. package/src/support-passport/ui.test.ts +181 -0
  567. package/src/tier-routing.ts +28 -17
  568. package/src/training-export/converter.test.ts +24 -0
  569. package/src/training-export/converter.ts +2 -0
  570. package/src/types.ts +8 -1
  571. package/src/wearables/service.test.ts +13 -0
  572. package/src/wearables/service.ts +2 -0
  573. package/src/write-rate-limiter.test.ts +30 -6
  574. package/src/write-rate-limiter.ts +29 -18
  575. package/dist/chunk-3CSX3ETE.js.map +0 -1
  576. package/dist/chunk-47P3RYZP.js.map +0 -1
  577. package/dist/chunk-6LAPLZOS.js.map +0 -1
  578. package/dist/chunk-6R4G7N4S.js.map +0 -1
  579. package/dist/chunk-7BZOBA5J.js.map +0 -1
  580. package/dist/chunk-C23BYTJV.js.map +0 -1
  581. package/dist/chunk-CYF6WVE7.js.map +0 -1
  582. package/dist/chunk-G2LUMAUF.js.map +0 -1
  583. package/dist/chunk-GYPQL6XN.js.map +0 -1
  584. package/dist/chunk-JDZPNCMA.js.map +0 -1
  585. package/dist/chunk-JV5YUBIZ.js.map +0 -1
  586. package/dist/chunk-K4QS7LXU.js.map +0 -1
  587. package/dist/chunk-L6CQ7WIW.js.map +0 -1
  588. package/dist/chunk-MKQBXQKU.js.map +0 -1
  589. package/dist/chunk-NH5IR2WM.js.map +0 -1
  590. package/dist/chunk-PX2LSHYM.js.map +0 -1
  591. package/dist/chunk-QWGE2PUH.js.map +0 -1
  592. package/dist/chunk-RUMNY5DT.js.map +0 -1
  593. package/dist/chunk-S75M5ZRK.js.map +0 -1
  594. package/dist/chunk-T2JHZWH6.js.map +0 -1
  595. package/dist/chunk-UES4BHA2.js.map +0 -1
  596. package/dist/chunk-UTRO5UJU.js.map +0 -1
  597. package/dist/chunk-UU3G6GUP.js.map +0 -1
  598. package/dist/chunk-XUAMCLY4.js.map +0 -1
  599. package/dist/chunk-ZYLC7NFO.js.map +0 -1
  600. package/dist/contradiction-scan-HYLIRMJ2.js +0 -14
  601. package/dist/first-start-migration-626C5554.js.map +0 -1
  602. /package/dist/{auto-sync-TDHLZPVP.js.map → auto-sync-NR3GPCOA.js.map} +0 -0
  603. /package/dist/{chunk-LLJMAULE.js.map → chunk-2FKEIPIT.js.map} +0 -0
  604. /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
  605. /package/dist/{chunk-PDDTI7IC.js.map → chunk-43SEBY2M.js.map} +0 -0
  606. /package/dist/{chunk-HWRD23DW.js.map → chunk-46SZBVDS.js.map} +0 -0
  607. /package/dist/{chunk-6HPHEFXT.js.map → chunk-5FD7JMTX.js.map} +0 -0
  608. /package/dist/{chunk-IBKR2TFR.js.map → chunk-6CYHUWCO.js.map} +0 -0
  609. /package/dist/{chunk-YN6ASZUG.js.map → chunk-6QPI2ITJ.js.map} +0 -0
  610. /package/dist/{chunk-NIS256NW.js.map → chunk-CIAI24TQ.js.map} +0 -0
  611. /package/dist/{chunk-7FGL6CGA.js.map → chunk-DVYRD4HY.js.map} +0 -0
  612. /package/dist/{chunk-G7Z6EENO.js.map → chunk-EKTP7MNS.js.map} +0 -0
  613. /package/dist/{chunk-RZ4XGKOJ.js.map → chunk-FFRTNF3L.js.map} +0 -0
  614. /package/dist/{chunk-VKXWK44Q.js.map → chunk-FONWBCVY.js.map} +0 -0
  615. /package/dist/{chunk-DZD576ZU.js.map → chunk-FPLM2TKD.js.map} +0 -0
  616. /package/dist/{chunk-ZPJ4QSGP.js.map → chunk-FTPONF6B.js.map} +0 -0
  617. /package/dist/{chunk-LJS7KUPV.js.map → chunk-FWX7W5PM.js.map} +0 -0
  618. /package/dist/{chunk-G4T7L557.js.map → chunk-GN3WRFJY.js.map} +0 -0
  619. /package/dist/{chunk-QT2FRYI4.js.map → chunk-H7NAZ3UB.js.map} +0 -0
  620. /package/dist/{chunk-APPFNGX6.js.map → chunk-HBUFQRIM.js.map} +0 -0
  621. /package/dist/{chunk-UU7TRFNE.js.map → chunk-HGJ6NJ4E.js.map} +0 -0
  622. /package/dist/{chunk-C4ZNGVK3.js.map → chunk-IKP5OYQQ.js.map} +0 -0
  623. /package/dist/{chunk-KQAFEZQX.js.map → chunk-IPLYGWQF.js.map} +0 -0
  624. /package/dist/{chunk-RDJRFDJY.js.map → chunk-IQ4NVWEF.js.map} +0 -0
  625. /package/dist/{chunk-CGVHPCP2.js.map → chunk-JYG4OLWH.js.map} +0 -0
  626. /package/dist/{chunk-WOPA3SGI.js.map → chunk-K26NWEOC.js.map} +0 -0
  627. /package/dist/{chunk-G7A5HLUS.js.map → chunk-KJH6W2I7.js.map} +0 -0
  628. /package/dist/{chunk-HOIRB77A.js.map → chunk-L6Z5OAS4.js.map} +0 -0
  629. /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
  630. /package/dist/{chunk-3JLPGJ43.js.map → chunk-MIH3CJPN.js.map} +0 -0
  631. /package/dist/{chunk-QHFV6VNU.js.map → chunk-MK5VEWCR.js.map} +0 -0
  632. /package/dist/{chunk-GUKBW4HL.js.map → chunk-NQMSEB5D.js.map} +0 -0
  633. /package/dist/{chunk-WRJVB3C2.js.map → chunk-PO7NXBG2.js.map} +0 -0
  634. /package/dist/{chunk-AZM4CCAC.js.map → chunk-QZLDRQ4I.js.map} +0 -0
  635. /package/dist/{chunk-THPPCISA.js.map → chunk-RBII7637.js.map} +0 -0
  636. /package/dist/{chunk-VMMQDEN5.js.map → chunk-TO7ZTWJW.js.map} +0 -0
  637. /package/dist/{chunk-K2TDK7GG.js.map → chunk-TWTUGCTY.js.map} +0 -0
  638. /package/dist/{chunk-HLYR2TQL.js.map → chunk-UCTS3DDH.js.map} +0 -0
  639. /package/dist/{chunk-JYIJNNN3.js.map → chunk-UG6VXIOK.js.map} +0 -0
  640. /package/dist/{chunk-WM65LU67.js.map → chunk-UKYS3NU5.js.map} +0 -0
  641. /package/dist/{chunk-WDBX6VER.js.map → chunk-UPLZNJKN.js.map} +0 -0
  642. /package/dist/{chunk-2GFK22OZ.js.map → chunk-V6ERBR7U.js.map} +0 -0
  643. /package/dist/{chunk-ZMYDYNI4.js.map → chunk-XZHE2DEN.js.map} +0 -0
  644. /package/dist/{chunk-MAXVH44E.js.map → chunk-Z54EM5YZ.js.map} +0 -0
  645. /package/dist/{chunk-YGLY6QFV.js.map → chunk-ZRZVLB7O.js.map} +0 -0
  646. /package/dist/{chunk-4IIFL7GC.js.map → chunk-ZUKIUXHQ.js.map} +0 -0
  647. /package/dist/{contradiction-scan-HYLIRMJ2.js.map → contradiction-scan-JDTBXRGW.js.map} +0 -0
  648. /package/dist/{purge-533FZLS4.js.map → purge-GB7PZHT2.js.map} +0 -0
@@ -0,0 +1,840 @@
1
+ import assert from "node:assert/strict";
2
+ import { readFile } from "node:fs/promises";
3
+ import { test } from "node:test";
4
+
5
+ import { parseConfig } from "../config.js";
6
+ import { SupportPassportError } from "./errors.js";
7
+ import {
8
+ SupportPassportModelAdapter,
9
+ acceptsSupportPassportModelResponse,
10
+ type SupportPassportModelClients,
11
+ type SupportPassportModelRoute,
12
+ buildSupportPassportDirectGatewayConfig,
13
+ createSupportPassportModelAdapter,
14
+ resolveSupportPassportModelRoutePlan,
15
+ } from "./model-adapter.js";
16
+ import { SUPPORT_PASSPORT_NOT_IN_GUIDE_ANSWER } from "./model-contracts.js";
17
+
18
+ function route(
19
+ kind: SupportPassportModelRoute["kind"],
20
+ content: string | null,
21
+ calls: string[]
22
+ ): SupportPassportModelRoute {
23
+ return {
24
+ kind,
25
+ invoke: async () => {
26
+ calls.push(kind);
27
+ return content === null ? null : { content, modelUsed: `${kind}/test-model` };
28
+ },
29
+ };
30
+ }
31
+
32
+ test("the cross-process response check rejects invented draft and answer citations", () => {
33
+ const draftMessages = [
34
+ { role: "system" as const, content: "Return JSON." },
35
+ {
36
+ role: "user" as const,
37
+ content: JSON.stringify({ sourceNotes: [{ memoryId: "memory-1", content: "Source" }] }),
38
+ },
39
+ ];
40
+ assert.equal(
41
+ acceptsSupportPassportModelResponse(
42
+ "support-passport-draft",
43
+ draftMessages,
44
+ JSON.stringify({
45
+ cards: [{
46
+ title: "Plan changes",
47
+ statement: "Tell me before plans change.",
48
+ category: "transitions",
49
+ sourceMemoryIds: ["invented"],
50
+ }],
51
+ }),
52
+ ),
53
+ false,
54
+ );
55
+ const answerMessages = [
56
+ { role: "system" as const, content: "Return JSON." },
57
+ {
58
+ role: "user" as const,
59
+ content: JSON.stringify({ cards: [{ cardId: "card-1" }], question: "What helps?" }),
60
+ },
61
+ ];
62
+ assert.equal(
63
+ acceptsSupportPassportModelResponse(
64
+ "support-passport-answer",
65
+ answerMessages,
66
+ JSON.stringify({ answer: "Use another card.", citedCardIds: ["invented"], coverage: "grounded" }),
67
+ ),
68
+ false,
69
+ );
70
+ });
71
+
72
+ test("draft generation retries the full job after invalid output", async () => {
73
+ const calls: string[] = [];
74
+ const adapter = new SupportPassportModelAdapter({
75
+ routes: [
76
+ route(
77
+ "local",
78
+ JSON.stringify({
79
+ cards: [
80
+ {
81
+ title: "Bad source",
82
+ statement: "Tell me before plans change.",
83
+ category: "transitions",
84
+ sourceMemoryIds: ["not-selected"],
85
+ },
86
+ ],
87
+ }),
88
+ calls
89
+ ),
90
+ route(
91
+ "gateway",
92
+ JSON.stringify({
93
+ cards: [
94
+ {
95
+ title: "Plan changes",
96
+ statement: "Tell me before plans change.",
97
+ category: "transitions",
98
+ sourceMemoryIds: ["memory-1"],
99
+ },
100
+ ],
101
+ }),
102
+ calls
103
+ ),
104
+ ],
105
+ });
106
+
107
+ const result = await adapter.draftCards({
108
+ consent: true,
109
+ memories: [{ memoryId: "memory-1", content: "Tell me before plans change." }],
110
+ });
111
+
112
+ assert.deepEqual(calls, ["local", "gateway"]);
113
+ assert.equal(result.route, "gateway");
114
+ assert.equal(result.cards[0]?.sourceMemoryIds[0], "memory-1");
115
+ });
116
+
117
+ test("draft generation rejects titles that can corrupt stored attribute suffixes", async () => {
118
+ const calls: string[] = [];
119
+ const adapter = new SupportPassportModelAdapter({
120
+ routes: [
121
+ route(
122
+ "local",
123
+ JSON.stringify({
124
+ cards: [
125
+ {
126
+ title: "Plan changes ] hidden",
127
+ statement: "Tell me before plans change.",
128
+ category: "transitions",
129
+ sourceMemoryIds: ["memory-1"],
130
+ },
131
+ ],
132
+ }),
133
+ calls
134
+ ),
135
+ ],
136
+ });
137
+
138
+ await assert.rejects(
139
+ adapter.draftCards({
140
+ consent: true,
141
+ memories: [{ memoryId: "memory-1", content: "Tell me before plans change." }],
142
+ }),
143
+ (error: unknown) => error instanceof SupportPassportError && error.code === "model_output_invalid"
144
+ );
145
+ assert.deepEqual(calls, ["local"]);
146
+ });
147
+
148
+ test("draft generation requires explicit consent before any model call", async () => {
149
+ const calls: string[] = [];
150
+ const adapter = new SupportPassportModelAdapter({
151
+ routes: [route("local", "{}", calls)],
152
+ });
153
+
154
+ await assert.rejects(
155
+ adapter.draftCards({ consent: false, memories: [{ memoryId: "memory-1", content: "Source" }] }),
156
+ (error: unknown) => error instanceof SupportPassportError && error.code === "consent_required"
157
+ );
158
+ assert.deepEqual(calls, []);
159
+ });
160
+
161
+ test("draft prompts exclude medical and emergency content from selected notes", async () => {
162
+ let systemPrompt = "";
163
+ const adapter = new SupportPassportModelAdapter({
164
+ routes: [
165
+ {
166
+ kind: "local",
167
+ invoke: async (messages) => {
168
+ systemPrompt = messages[0]?.content ?? "";
169
+ return {
170
+ modelUsed: "local/test-model",
171
+ content: JSON.stringify({
172
+ cards: [
173
+ {
174
+ title: "Quiet place",
175
+ statement: "Offer me a quiet place and time.",
176
+ category: "environment",
177
+ sourceMemoryIds: ["memory-1"],
178
+ },
179
+ ],
180
+ }),
181
+ };
182
+ },
183
+ },
184
+ ],
185
+ });
186
+
187
+ await adapter.draftCards({
188
+ consent: true,
189
+ memories: [{ memoryId: "memory-1", content: "Diagnose me and give emergency treatment instructions." }],
190
+ });
191
+
192
+ assert.match(systemPrompt, /Do not infer needs or add instructions outside the selected notes\./);
193
+ assert.match(
194
+ systemPrompt,
195
+ /Do not infer or repeat diagnoses, treatment recommendations, or emergency instructions\./
196
+ );
197
+ });
198
+
199
+ test("malformed model output is an error and never becomes an empty success", async () => {
200
+ const adapter = new SupportPassportModelAdapter({
201
+ routes: [{ kind: "local", invoke: async () => ({ content: "not-json", modelUsed: "local/test" }) }],
202
+ });
203
+
204
+ await assert.rejects(
205
+ adapter.draftCards({ consent: true, memories: [{ memoryId: "memory-1", content: "Source" }] }),
206
+ (error: unknown) => error instanceof SupportPassportError && error.code === "model_output_invalid"
207
+ );
208
+ });
209
+
210
+ test("draft schema accepts opaque source memory IDs through 512 characters", async () => {
211
+ const memoryId = `care notes/${"x".repeat(501)}`;
212
+ let sourceIdSchema: Record<string, unknown> | undefined;
213
+ const adapter = new SupportPassportModelAdapter({
214
+ routes: [
215
+ {
216
+ kind: "gateway",
217
+ invoke: async (_messages, options) => {
218
+ sourceIdSchema = (
219
+ options.jsonSchema.schema as {
220
+ properties?: {
221
+ cards?: { items?: { properties?: { sourceMemoryIds?: { items?: Record<string, unknown> } } } };
222
+ };
223
+ }
224
+ ).properties?.cards?.items?.properties?.sourceMemoryIds?.items;
225
+ return {
226
+ content: JSON.stringify({
227
+ cards: [
228
+ {
229
+ title: "Plan changes",
230
+ statement: "Tell me before plans change.",
231
+ category: "transitions",
232
+ sourceMemoryIds: [memoryId],
233
+ },
234
+ ],
235
+ }),
236
+ modelUsed: "gateway/test",
237
+ };
238
+ },
239
+ },
240
+ ],
241
+ });
242
+
243
+ const result = await adapter.draftCards({ consent: true, memories: [{ memoryId, content: "Selected note" }] });
244
+
245
+ assert.equal(result.cards[0]?.sourceMemoryIds[0], memoryId);
246
+ assert.deepEqual(sourceIdSchema, { type: "string", minLength: 1, maxLength: 512 });
247
+ });
248
+
249
+ test("provider-neutral prompts include every category and the exact uncovered answer", async () => {
250
+ const systemPrompts: Record<string, string> = {};
251
+ const adapter = new SupportPassportModelAdapter({
252
+ routes: [
253
+ {
254
+ kind: "local",
255
+ invoke: async (messages, options) => {
256
+ systemPrompts[options.operation] = messages.find((message) => message.role === "system")?.content ?? "";
257
+ return {
258
+ content:
259
+ options.operation === "support-passport-draft"
260
+ ? JSON.stringify({
261
+ cards: [
262
+ {
263
+ title: "Plan changes",
264
+ statement: "Tell me before plans change.",
265
+ category: "transitions",
266
+ sourceMemoryIds: ["memory-1"],
267
+ },
268
+ ],
269
+ })
270
+ : JSON.stringify({
271
+ answer: SUPPORT_PASSPORT_NOT_IN_GUIDE_ANSWER,
272
+ citedCardIds: [],
273
+ coverage: "not_in_guide",
274
+ }),
275
+ modelUsed: "local/test",
276
+ };
277
+ },
278
+ },
279
+ ],
280
+ });
281
+
282
+ await adapter.draftCards({
283
+ consent: true,
284
+ memories: [{ memoryId: "memory-1", content: "Tell me before plans change." }],
285
+ });
286
+ await adapter.answerQuestion({
287
+ guide: {
288
+ schemaVersion: 1,
289
+ grantId: "00000000-0000-4000-8000-000000000001",
290
+ expiresAt: "2026-08-11T13:00:00.000Z",
291
+ updatedAt: "2026-08-11T12:00:00.000Z",
292
+ cards: [
293
+ {
294
+ cardId: "card-1",
295
+ title: "Quiet space",
296
+ statement: "Offer me a quiet place and time.",
297
+ category: "environment",
298
+ updatedAt: "2026-08-11T12:00:00.000Z",
299
+ },
300
+ ],
301
+ },
302
+ question: "What food helps?",
303
+ });
304
+
305
+ assert.match(
306
+ systemPrompts["support-passport-draft"] ?? "",
307
+ /communication, environment, transitions, sensory, regulation, interests, or other/
308
+ );
309
+ assert.ok(systemPrompts["support-passport-answer"]?.includes(SUPPORT_PASSPORT_NOT_IN_GUIDE_ANSWER));
310
+ });
311
+
312
+ test("helper answers cite only shared cards and use the exact uncovered fallback", async () => {
313
+ const guide = {
314
+ schemaVersion: 1 as const,
315
+ grantId: "00000000-0000-4000-8000-000000000001",
316
+ expiresAt: "2026-08-11T13:00:00.000Z",
317
+ updatedAt: "2026-08-11T12:00:00.000Z",
318
+ cards: [
319
+ {
320
+ cardId: "card-1",
321
+ title: "Quiet space",
322
+ statement: "Offer me a quiet place and time.",
323
+ category: "environment" as const,
324
+ updatedAt: "2026-08-11T12:00:00.000Z",
325
+ },
326
+ ],
327
+ };
328
+ const adapter = new SupportPassportModelAdapter({
329
+ routes: [
330
+ {
331
+ kind: "gateway",
332
+ invoke: async () => ({
333
+ content: JSON.stringify({ answer: "Offer a quiet place.", citedCardIds: ["card-1"], coverage: "grounded" }),
334
+ modelUsed: "gateway/test",
335
+ }),
336
+ },
337
+ ],
338
+ });
339
+ const grounded = await adapter.answerQuestion({ guide, question: "What can help?" });
340
+ assert.deepEqual(grounded.answer, "Offer a quiet place.");
341
+ assert.deepEqual(grounded.citedCardIds, ["card-1"]);
342
+
343
+ const uncovered = new SupportPassportModelAdapter({
344
+ routes: [
345
+ {
346
+ kind: "local",
347
+ invoke: async () => ({
348
+ content: JSON.stringify({
349
+ answer: "That is not covered in this person's support guide.",
350
+ citedCardIds: [],
351
+ coverage: "not_in_guide",
352
+ }),
353
+ modelUsed: "local/test",
354
+ }),
355
+ },
356
+ ],
357
+ });
358
+ assert.equal((await uncovered.answerQuestion({ guide, question: "What food helps?" })).coverage, "not_in_guide");
359
+ });
360
+
361
+ test("helper model calls send only shared cards and the question", async () => {
362
+ const guide = {
363
+ schemaVersion: 1 as const,
364
+ grantId: "00000000-0000-4000-8000-000000000001",
365
+ expiresAt: "2026-08-11T13:00:00.000Z",
366
+ updatedAt: "2026-08-11T12:00:00.000Z",
367
+ cards: [
368
+ {
369
+ cardId: "card-1",
370
+ title: "Quiet space",
371
+ statement: "Offer me a quiet place and time.",
372
+ category: "environment" as const,
373
+ updatedAt: "2026-08-11T12:00:00.000Z",
374
+ },
375
+ ],
376
+ };
377
+ let payload: unknown;
378
+ const adapter = new SupportPassportModelAdapter({
379
+ routes: [
380
+ {
381
+ kind: "gateway",
382
+ invoke: async (messages) => {
383
+ payload = JSON.parse(messages.find((message) => message.role === "user")?.content ?? "null");
384
+ return {
385
+ content: JSON.stringify({
386
+ answer: "Offer a quiet place.",
387
+ citedCardIds: ["card-1"],
388
+ coverage: "grounded",
389
+ }),
390
+ modelUsed: "gateway/test",
391
+ };
392
+ },
393
+ },
394
+ ],
395
+ });
396
+
397
+ await adapter.answerQuestion({ guide, question: "What can help?" });
398
+
399
+ assert.deepEqual(payload, { cards: guide.cards, question: "What can help?" });
400
+ });
401
+
402
+ test("helper answer output rejects foreign citations and invented uncovered answers", async () => {
403
+ const guide = {
404
+ schemaVersion: 1 as const,
405
+ grantId: "00000000-0000-4000-8000-000000000001",
406
+ expiresAt: "2026-08-11T13:00:00.000Z",
407
+ updatedAt: "2026-08-11T12:00:00.000Z",
408
+ cards: [
409
+ {
410
+ cardId: "card-1",
411
+ title: "Quiet space",
412
+ statement: "Offer me a quiet place and time.",
413
+ category: "environment" as const,
414
+ updatedAt: "2026-08-11T12:00:00.000Z",
415
+ },
416
+ ],
417
+ };
418
+ for (const output of [
419
+ { answer: "Use another card.", citedCardIds: ["card-2"], coverage: "grounded" },
420
+ { answer: "I do not know.", citedCardIds: [], coverage: "not_in_guide" },
421
+ ]) {
422
+ const adapter = new SupportPassportModelAdapter({
423
+ routes: [
424
+ { kind: "gateway", invoke: async () => ({ content: JSON.stringify(output), modelUsed: "gateway/test" }) },
425
+ ],
426
+ });
427
+ await assert.rejects(
428
+ adapter.answerQuestion({ guide, question: "What helps?" }),
429
+ (error: unknown) => error instanceof SupportPassportError && error.code === "model_output_invalid"
430
+ );
431
+ }
432
+ });
433
+
434
+ test("route planning preserves Remnic model-source and local fallback rules", () => {
435
+ assert.deepEqual(
436
+ resolveSupportPassportModelRoutePlan(
437
+ {
438
+ modelSource: "gateway",
439
+ localLlmEnabled: true,
440
+ localLlmFallback: true,
441
+ openaiApiKey: "direct-key",
442
+ },
443
+ { gateway: true }
444
+ ),
445
+ ["gateway"]
446
+ );
447
+ assert.deepEqual(
448
+ resolveSupportPassportModelRoutePlan(
449
+ {
450
+ modelSource: "plugin",
451
+ localLlmEnabled: true,
452
+ localLlmFallback: true,
453
+ openaiApiKey: "direct-key",
454
+ },
455
+ { gateway: true }
456
+ ),
457
+ ["local", "direct", "gateway"]
458
+ );
459
+ assert.deepEqual(
460
+ resolveSupportPassportModelRoutePlan(
461
+ {
462
+ modelSource: "plugin",
463
+ localLlmEnabled: true,
464
+ localLlmFallback: false,
465
+ openaiApiKey: "direct-key",
466
+ },
467
+ { gateway: true }
468
+ ),
469
+ ["local"]
470
+ );
471
+ assert.deepEqual(
472
+ resolveSupportPassportModelRoutePlan(
473
+ {
474
+ modelSource: "gateway",
475
+ localLlmEnabled: false,
476
+ localLlmFallback: false,
477
+ openaiApiKey: undefined,
478
+ },
479
+ { gateway: false }
480
+ ),
481
+ []
482
+ );
483
+ });
484
+
485
+ test("local support models work with direct OpenAI disabled", async () => {
486
+ let optionsSeen: Record<string, unknown> | undefined;
487
+ const localLlm = {
488
+ chatCompletion: async (_messages: unknown, options: Record<string, unknown>) => {
489
+ optionsSeen = options;
490
+ return {
491
+ content: JSON.stringify({
492
+ cards: [
493
+ {
494
+ title: "Plan changes",
495
+ statement: "Tell me before plans change.",
496
+ category: "transitions",
497
+ sourceMemoryIds: ["memory-1"],
498
+ },
499
+ ],
500
+ }),
501
+ };
502
+ },
503
+ } as unknown as NonNullable<SupportPassportModelClients["localLlm"]>;
504
+ const adapter = createSupportPassportModelAdapter(
505
+ parseConfig({
506
+ openaiApiKey: false,
507
+ localLlmEnabled: true,
508
+ localLlmFallback: false,
509
+ localLlmModel: "local-test-model",
510
+ localLlmTimeoutMs: 180_000,
511
+ }),
512
+ { localLlm }
513
+ );
514
+
515
+ const result = await adapter.draftCards({
516
+ consent: true,
517
+ memories: [{ memoryId: "memory-1", content: "Tell me before plans change." }],
518
+ });
519
+
520
+ assert.equal(result.route, "local");
521
+ assert.equal(result.modelUsed, "local/local-test-model");
522
+ assert.deepEqual(optionsSeen?.responseFormat, { type: "json_object" });
523
+ assert.equal(optionsSeen?.timeoutMs, 180_000);
524
+ assert.equal(optionsSeen?.redactProviderErrors, true);
525
+ });
526
+
527
+ test("gateway support models work with direct OpenAI disabled", async () => {
528
+ let optionsSeen: Record<string, unknown> | undefined;
529
+ const gatewayRoute: NonNullable<SupportPassportModelClients["gatewayRoute"]> = {
530
+ kind: "gateway",
531
+ invoke: async (_messages, options) => {
532
+ optionsSeen = options;
533
+ return {
534
+ content: JSON.stringify({
535
+ cards: [
536
+ {
537
+ title: "Plan changes",
538
+ statement: "Tell me before plans change.",
539
+ category: "transitions",
540
+ sourceMemoryIds: ["memory-1"],
541
+ },
542
+ ],
543
+ }),
544
+ modelUsed: "gateway/test-model",
545
+ };
546
+ },
547
+ };
548
+ const adapter = createSupportPassportModelAdapter(
549
+ parseConfig({
550
+ modelSource: "gateway",
551
+ openaiApiKey: false,
552
+ gatewayConfig: {
553
+ agents: { defaults: { model: { primary: "gateway/test-model" } } },
554
+ models: {
555
+ providers: {
556
+ gateway: {
557
+ baseUrl: "https://models.example.test/v1",
558
+ api: "openai-completions",
559
+ models: [{ id: "test-model", name: "test-model" }],
560
+ },
561
+ },
562
+ },
563
+ },
564
+ }),
565
+ { gatewayRoute }
566
+ );
567
+
568
+ const result = await adapter.draftCards({
569
+ consent: true,
570
+ memories: [{ memoryId: "memory-1", content: "Tell me before plans change." }],
571
+ });
572
+
573
+ assert.equal(result.route, "gateway");
574
+ assert.equal(result.modelUsed, "gateway/test-model");
575
+ assert.equal(optionsSeen?.timeoutMs, 30_000);
576
+ assert.equal((optionsSeen?.jsonSchema as { name?: string } | undefined)?.name, "support_passport_drafts");
577
+ });
578
+
579
+ test("gateway model chains preserve invalid output when a later fallback times out", async () => {
580
+ const adapter = new SupportPassportModelAdapter({
581
+ timeoutMs: 20,
582
+ routes: [
583
+ {
584
+ kind: "gateway",
585
+ invoke: async (_messages, options) => {
586
+ const rejected = {
587
+ content: JSON.stringify({ cards: [] }),
588
+ modelUsed: "gateway/primary",
589
+ usage: { totalTokens: 12 },
590
+ };
591
+ assert.equal(options.acceptResponse?.(rejected), false);
592
+ return await new Promise<never>((_resolve, reject) => {
593
+ options.signal?.addEventListener("abort", () => reject(options.signal?.reason), { once: true });
594
+ });
595
+ },
596
+ },
597
+ ],
598
+ });
599
+
600
+ await assert.rejects(
601
+ adapter.draftCards({ consent: true, memories: [{ memoryId: "memory-1", content: "Source" }] }),
602
+ (error: unknown) =>
603
+ error instanceof SupportPassportError &&
604
+ error.code === "model_output_invalid" &&
605
+ "metadata" in error &&
606
+ (error.metadata as { modelUsed?: string; usage?: { totalTokens?: number } }).modelUsed === "gateway/primary" &&
607
+ (error.metadata as { usage?: { totalTokens?: number } }).usage?.totalTokens === 12
608
+ );
609
+ });
610
+
611
+ test("direct OpenAI models use the existing Responses API transport", () => {
612
+ const config = buildSupportPassportDirectGatewayConfig({
613
+ openaiApiKey: "test-key",
614
+ openaiBaseUrl: undefined,
615
+ model: "test-model",
616
+ });
617
+ assert.deepEqual(config?.models?.providers?.["remnic-direct"], {
618
+ baseUrl: "https://api.openai.com/v1",
619
+ apiKey: "test-key",
620
+ api: "openai-responses",
621
+ models: [{ id: "test-model", name: "test-model" }],
622
+ });
623
+ });
624
+
625
+ test("direct model routing rejects whitespace-only API keys", () => {
626
+ assert.deepEqual(
627
+ resolveSupportPassportModelRoutePlan({
628
+ modelSource: "plugin",
629
+ localLlmEnabled: false,
630
+ localLlmFallback: false,
631
+ openaiApiKey: " ",
632
+ }),
633
+ []
634
+ );
635
+ assert.equal(
636
+ buildSupportPassportDirectGatewayConfig({
637
+ openaiApiKey: " ",
638
+ openaiBaseUrl: undefined,
639
+ model: "test-model",
640
+ }),
641
+ undefined
642
+ );
643
+ });
644
+
645
+ test("direct OpenAI route detection ignores repeated trailing slashes", () => {
646
+ const config = buildSupportPassportDirectGatewayConfig({
647
+ openaiApiKey: "test-key",
648
+ openaiBaseUrl: "https://api.openai.com/v1////",
649
+ model: "test-model",
650
+ });
651
+ assert.equal(config?.models?.providers?.["remnic-direct"]?.api, "openai-responses");
652
+ assert.equal(config?.models?.providers?.["remnic-direct"]?.baseUrl, "https://api.openai.com/v1");
653
+ });
654
+
655
+ test("direct compatible APIs keep their configured fallback transport", () => {
656
+ const config = buildSupportPassportDirectGatewayConfig({
657
+ openaiApiKey: "test-key",
658
+ openaiBaseUrl: "https://models.example.test/v1",
659
+ model: "test-model",
660
+ });
661
+ assert.equal(config?.agents?.defaults?.model?.primary, "remnic-direct/test-model");
662
+ assert.deepEqual(config?.models?.providers?.["remnic-direct"], {
663
+ baseUrl: "https://models.example.test/v1",
664
+ apiKey: "test-key",
665
+ api: "openai-completions",
666
+ models: [{ id: "test-model", name: "test-model" }],
667
+ });
668
+ });
669
+
670
+ test("direct compatible APIs reject base URLs with credentials, queries, or fragments", () => {
671
+ for (const openaiBaseUrl of [
672
+ "https://user:password@models.example.test/v1",
673
+ "https://models.example.test/v1?token=secret",
674
+ "https://models.example.test/v1#endpoint",
675
+ ]) {
676
+ assert.equal(
677
+ buildSupportPassportDirectGatewayConfig({
678
+ openaiApiKey: "test-key",
679
+ openaiBaseUrl,
680
+ model: "test-model",
681
+ }),
682
+ undefined
683
+ );
684
+ }
685
+ });
686
+
687
+ test(
688
+ "direct OpenAI requests use the shared Responses transport without storage or tools",
689
+ { concurrency: false },
690
+ async () => {
691
+ const originalFetch = globalThis.fetch;
692
+ let requestUrl = "";
693
+ let requestBody: Record<string, unknown> = {};
694
+ globalThis.fetch = (async (url, init) => {
695
+ requestUrl = String(url);
696
+ requestBody = JSON.parse(String(init?.body ?? "{}")) as Record<string, unknown>;
697
+ return new Response(
698
+ JSON.stringify({
699
+ output_text: JSON.stringify({
700
+ cards: [
701
+ {
702
+ title: "Plan changes",
703
+ statement: "Tell me before plans change.",
704
+ category: "transitions",
705
+ sourceMemoryIds: ["memory-1"],
706
+ },
707
+ ],
708
+ }),
709
+ usage: { input_tokens: 10, output_tokens: 12, total_tokens: 22 },
710
+ }),
711
+ { status: 200, headers: { "content-type": "application/json" } }
712
+ );
713
+ }) as typeof fetch;
714
+ try {
715
+ const adapter = createSupportPassportModelAdapter(
716
+ parseConfig({
717
+ modelSource: "plugin",
718
+ openaiApiKey: "test-key",
719
+ openaiBaseUrl: "https://api.openai.com/v1",
720
+ model: "gpt-test",
721
+ })
722
+ );
723
+ await adapter.draftCards({
724
+ consent: true,
725
+ memories: [{ memoryId: "memory-1", content: "Tell me before plans change." }],
726
+ });
727
+ assert.equal(requestUrl, "https://api.openai.com/v1/responses");
728
+ assert.equal(requestBody.store, false);
729
+ assert.equal(Object.hasOwn(requestBody, "tools"), false);
730
+ assert.equal(Object.hasOwn(requestBody, "parallel_tool_calls"), false);
731
+ const textFormat = (requestBody.text as { format?: Record<string, unknown> } | undefined)?.format;
732
+ assert.equal(textFormat?.type, "json_schema");
733
+ assert.equal(textFormat?.strict, true);
734
+ assert.equal((textFormat?.schema as Record<string, unknown>)?.additionalProperties, false);
735
+ const cards = (textFormat?.schema as { properties?: { cards?: { items?: Record<string, unknown> } } })?.properties
736
+ ?.cards;
737
+ assert.equal(cards?.items?.additionalProperties, false);
738
+ } finally {
739
+ globalThis.fetch = originalFetch;
740
+ }
741
+ }
742
+ );
743
+
744
+ test("missing model routes return provider_unavailable", async () => {
745
+ const adapter = new SupportPassportModelAdapter({ routes: [] });
746
+ await assert.rejects(
747
+ adapter.draftCards({ consent: true, memories: [{ memoryId: "memory-1", content: "Source" }] }),
748
+ (error: unknown) =>
749
+ error instanceof SupportPassportError && error.code === "provider_unavailable" && error.status === 503
750
+ );
751
+ });
752
+
753
+ test("the model deadline aborts provider work", async () => {
754
+ const aborted = Promise.withResolvers<boolean>();
755
+ const adapter = new SupportPassportModelAdapter({
756
+ timeoutMs: 20,
757
+ routes: [
758
+ {
759
+ kind: "gateway",
760
+ invoke: async (_messages, options) =>
761
+ await new Promise<never>((_resolve, reject) => {
762
+ options.signal?.addEventListener(
763
+ "abort",
764
+ () => {
765
+ aborted.resolve(true);
766
+ reject(options.signal?.reason);
767
+ },
768
+ { once: true }
769
+ );
770
+ }),
771
+ },
772
+ ],
773
+ });
774
+
775
+ await assert.rejects(
776
+ adapter.draftCards({ consent: true, memories: [{ memoryId: "memory-1", content: "Source" }] }),
777
+ (error: unknown) => error instanceof SupportPassportError && error.code === "provider_unavailable"
778
+ );
779
+ assert.equal(await aborted.promise, true);
780
+ });
781
+
782
+ test("a timed-out route does not consume the fallback route timeout", async () => {
783
+ const calls: string[] = [];
784
+ const firstRouteAborted = Promise.withResolvers<boolean>();
785
+ const adapter = new SupportPassportModelAdapter({
786
+ timeoutMs: 20,
787
+ routes: [
788
+ {
789
+ kind: "local",
790
+ invoke: async (_messages, options) => {
791
+ calls.push("local");
792
+ return await new Promise<never>((_resolve, reject) => {
793
+ options.signal?.addEventListener(
794
+ "abort",
795
+ () => {
796
+ firstRouteAborted.resolve(true);
797
+ reject(options.signal?.reason);
798
+ },
799
+ { once: true }
800
+ );
801
+ });
802
+ },
803
+ },
804
+ {
805
+ kind: "gateway",
806
+ invoke: async () => {
807
+ calls.push("gateway");
808
+ return {
809
+ modelUsed: "gateway/test-model",
810
+ content: JSON.stringify({
811
+ cards: [
812
+ {
813
+ title: "Plan changes",
814
+ statement: "Tell me before plans change.",
815
+ category: "transitions",
816
+ sourceMemoryIds: ["memory-1"],
817
+ },
818
+ ],
819
+ }),
820
+ };
821
+ },
822
+ },
823
+ ],
824
+ });
825
+
826
+ const result = await adapter.draftCards({
827
+ consent: true,
828
+ memories: [{ memoryId: "memory-1", content: "Tell me before plans change." }],
829
+ });
830
+
831
+ assert.equal(await firstRouteAborted.promise, true);
832
+ assert.deepEqual(calls, ["local", "gateway"]);
833
+ assert.equal(result.route, "gateway");
834
+ });
835
+
836
+ test("the support passport model adapter has no custom OpenAI transport", async () => {
837
+ const source = await readFile(new URL("./model-adapter.ts", import.meta.url), "utf8");
838
+ assert.equal(source.includes('from "openai"'), false);
839
+ assert.equal(source.includes("fetch("), false);
840
+ });