@m6d/cortex-server 1.8.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/README.md +8 -3
  2. package/contracts/README.md +23 -0
  3. package/contracts/graph/embed.ts +50 -0
  4. package/{src/lib → contracts}/graph/helpers.ts +4 -10
  5. package/{src/lib → contracts}/graph/neo4j.ts +14 -27
  6. package/contracts/graph/schema.ts +65 -0
  7. package/{src/lib → contracts}/graph/types.ts +2 -29
  8. package/contracts/graph.ts +36 -0
  9. package/contracts/rich-text.ts +207 -0
  10. package/contracts/runtime.ts +243 -0
  11. package/contracts/wire.ts +143 -0
  12. package/dist/contracts/graph/embed.d.ts +22 -0
  13. package/dist/{src/lib → contracts}/graph/helpers.d.ts +16 -14
  14. package/dist/{src/lib → contracts}/graph/neo4j.d.ts +5 -5
  15. package/dist/contracts/graph/schema.d.ts +62 -0
  16. package/dist/{src/lib → contracts}/graph/types.d.ts +1 -1
  17. package/dist/contracts/graph.d.ts +14 -0
  18. package/dist/contracts/rich-text.d.ts +32 -0
  19. package/dist/contracts/runtime.d.ts +310 -0
  20. package/dist/contracts/wire.d.ts +120 -0
  21. package/dist/src/lib/adapters/database/index.d.ts +61 -0
  22. package/dist/src/lib/adapters/database/message-content.d.ts +30 -0
  23. package/dist/src/lib/adapters/database/mssql/attachments.d.ts +100 -0
  24. package/dist/src/lib/adapters/database/mssql/client.d.ts +8 -0
  25. package/dist/src/lib/adapters/database/mssql/index.d.ts +194 -0
  26. package/dist/src/lib/adapters/database/mssql/llm-requests.d.ts +17 -0
  27. package/dist/src/lib/adapters/database/mssql/messages.d.ts +37 -0
  28. package/dist/src/lib/adapters/database/mssql/threads.d.ts +50 -0
  29. package/dist/src/lib/adapters/database/postgres/attachments.d.ts +113 -0
  30. package/dist/src/lib/adapters/database/postgres/client.d.ts +8 -0
  31. package/dist/src/lib/adapters/database/postgres/index.d.ts +207 -0
  32. package/dist/src/lib/adapters/database/postgres/llm-requests.d.ts +17 -0
  33. package/dist/src/lib/adapters/database/postgres/messages.d.ts +37 -0
  34. package/dist/src/lib/adapters/database/postgres/threads.d.ts +50 -0
  35. package/{src/lib/adapters/storage.ts → dist/src/lib/adapters/storage/index.d.ts} +1 -1
  36. package/dist/src/lib/adapters/{minio.d.ts → storage/minio.d.ts} +1 -1
  37. package/dist/src/lib/ai/active-runs.d.ts +63 -0
  38. package/dist/src/lib/ai/attachments.d.ts +30 -0
  39. package/dist/src/lib/ai/backend-url.d.ts +16 -0
  40. package/dist/src/lib/ai/cc-runtime.d.ts +61 -0
  41. package/dist/src/lib/ai/commit-gate.d.ts +21 -0
  42. package/dist/src/lib/ai/context/builder.d.ts +6 -7
  43. package/dist/src/lib/ai/context/compression-middleware.d.ts +15 -0
  44. package/dist/src/lib/ai/context/compressor.d.ts +2 -13
  45. package/dist/src/lib/ai/context/intra-turn-compressor.d.ts +9 -9
  46. package/dist/src/lib/ai/context/optimize-thread-context.d.ts +9 -0
  47. package/dist/src/lib/ai/context/summarizer.d.ts +3 -3
  48. package/dist/src/lib/ai/context/token-estimator.d.ts +5 -8
  49. package/dist/src/lib/ai/fetch.d.ts +1 -1
  50. package/dist/src/lib/ai/finish-turn.d.ts +23 -0
  51. package/dist/src/lib/ai/helpers.d.ts +37 -4
  52. package/dist/src/lib/ai/index.d.ts +6 -3
  53. package/dist/src/lib/ai/inspector.d.ts +41 -0
  54. package/dist/src/lib/ai/interceptors/request-interceptor.d.ts +6 -5
  55. package/dist/src/lib/ai/prompt.d.ts +5 -4
  56. package/dist/src/lib/ai/redis-runs.d.ts +41 -0
  57. package/dist/src/lib/ai/redis-stream-log.d.ts +39 -0
  58. package/dist/src/lib/ai/tools/execute-code.tool.d.ts +18 -4
  59. package/dist/src/lib/ai/tools/query-graph.tool.d.ts +13 -5
  60. package/dist/src/lib/ai/tools/read-attachment.tool.d.ts +21 -0
  61. package/dist/src/lib/ai/tools/search-common.d.ts +17 -0
  62. package/dist/src/lib/ai/tools/search-knowledge.tool.d.ts +15 -0
  63. package/dist/src/lib/ai/tools/search-services.tool.d.ts +12 -0
  64. package/dist/src/lib/ai/tools/search-tools.tool.d.ts +12 -0
  65. package/dist/src/lib/ai/turn-tools.d.ts +39 -0
  66. package/dist/src/lib/ai/vision/rasterize-pdf.d.ts +26 -0
  67. package/dist/src/lib/ai/vision/rasterize-pdf.worker.d.ts +1 -0
  68. package/dist/src/lib/ai/vision/vision-reader.d.ts +45 -0
  69. package/dist/src/lib/cc/client.d.ts +183 -0
  70. package/dist/src/lib/cc/config-cache.d.ts +20 -0
  71. package/dist/src/lib/cc/format.d.ts +23 -0
  72. package/dist/src/lib/cc/registry.d.ts +34 -0
  73. package/dist/src/lib/cc/types.d.ts +27 -0
  74. package/dist/src/lib/config.d.ts +81 -64
  75. package/dist/src/lib/db/drizzle.config.mssql.d.ts +2 -0
  76. package/dist/src/lib/db/drizzle.config.pg.d.ts +2 -0
  77. package/dist/src/lib/db/migrate.d.ts +7 -1
  78. package/dist/src/lib/db/{schema.d.ts → schema.mssql.d.ts} +138 -29
  79. package/dist/src/lib/db/schema.pg.d.ts +546 -0
  80. package/dist/src/lib/factory.d.ts +2 -12
  81. package/dist/src/lib/graph/index.d.ts +10 -11
  82. package/dist/src/lib/graph/resolver.d.ts +2 -3
  83. package/dist/src/lib/index.d.ts +3 -3
  84. package/dist/src/lib/redis.d.ts +19 -0
  85. package/dist/src/lib/routes/chat.d.ts +1 -1
  86. package/dist/src/lib/routes/files.d.ts +1 -1
  87. package/dist/src/lib/routes/owned-thread.d.ts +17 -0
  88. package/dist/src/lib/routes/threads.d.ts +1 -1
  89. package/dist/src/lib/routes/ws.d.ts +1 -1
  90. package/dist/src/lib/types.d.ts +20 -37
  91. package/dist/src/lib/ws/connections.d.ts +2 -1
  92. package/package.json +33 -18
  93. package/src/lib/adapters/database/index.ts +78 -0
  94. package/src/lib/adapters/database/message-content.ts +39 -0
  95. package/src/lib/adapters/database/mssql/attachments.ts +90 -0
  96. package/src/lib/adapters/database/mssql/client.ts +11 -0
  97. package/src/lib/adapters/database/mssql/index.ts +23 -0
  98. package/src/lib/adapters/database/mssql/llm-requests.ts +43 -0
  99. package/src/lib/adapters/database/mssql/messages.ts +92 -0
  100. package/src/lib/adapters/database/mssql/threads.ts +83 -0
  101. package/src/lib/adapters/database/postgres/attachments.ts +88 -0
  102. package/src/lib/adapters/database/postgres/client.ts +11 -0
  103. package/src/lib/adapters/database/postgres/index.ts +23 -0
  104. package/src/lib/adapters/database/postgres/llm-requests.ts +45 -0
  105. package/src/lib/adapters/database/postgres/messages.ts +92 -0
  106. package/src/lib/adapters/database/postgres/threads.ts +84 -0
  107. package/{dist/src/lib/adapters/storage.d.ts → src/lib/adapters/storage/index.ts} +1 -1
  108. package/src/lib/adapters/{minio.ts → storage/minio.ts} +5 -5
  109. package/src/lib/ai/active-runs.ts +157 -0
  110. package/src/lib/ai/attachments.ts +144 -0
  111. package/src/lib/ai/backend-url.ts +27 -0
  112. package/src/lib/ai/cc-runtime.ts +63 -0
  113. package/src/lib/ai/commit-gate.ts +116 -0
  114. package/src/lib/ai/context/builder.ts +12 -14
  115. package/src/lib/ai/context/compression-middleware.ts +44 -0
  116. package/src/lib/ai/context/compressor.ts +67 -59
  117. package/src/lib/ai/context/intra-turn-compressor.ts +121 -204
  118. package/src/lib/ai/context/optimize-thread-context.ts +50 -0
  119. package/src/lib/ai/context/summarizer.ts +28 -30
  120. package/src/lib/ai/context/token-estimator.ts +35 -30
  121. package/src/lib/ai/fetch.ts +10 -5
  122. package/src/lib/ai/finish-turn.ts +75 -0
  123. package/src/lib/ai/helpers.ts +83 -15
  124. package/src/lib/ai/index.ts +366 -329
  125. package/src/lib/ai/inspector.ts +112 -0
  126. package/src/lib/ai/interceptors/request-interceptor.ts +70 -42
  127. package/src/lib/ai/prompt.ts +126 -125
  128. package/src/lib/ai/redis-runs.ts +167 -0
  129. package/src/lib/ai/redis-stream-log.ts +219 -0
  130. package/src/lib/ai/tools/execute-code.tool.ts +178 -67
  131. package/src/lib/ai/tools/query-graph.tool.ts +7 -8
  132. package/src/lib/ai/tools/read-attachment.tool.ts +59 -0
  133. package/src/lib/ai/tools/search-common.ts +15 -0
  134. package/src/lib/ai/tools/search-knowledge.tool.ts +33 -0
  135. package/src/lib/ai/tools/search-services.tool.ts +31 -0
  136. package/src/lib/ai/tools/search-tools.tool.ts +29 -0
  137. package/src/lib/ai/turn-tools.ts +154 -0
  138. package/src/lib/ai/vision/rasterize-pdf.ts +69 -0
  139. package/src/lib/ai/vision/rasterize-pdf.worker.ts +81 -0
  140. package/src/lib/ai/vision/vision-reader.ts +130 -0
  141. package/src/lib/auth/middleware.ts +5 -3
  142. package/src/lib/cc/client.ts +273 -0
  143. package/src/lib/cc/config-cache.ts +32 -0
  144. package/src/lib/cc/format.ts +92 -0
  145. package/src/lib/cc/registry.ts +62 -0
  146. package/src/lib/cc/types.ts +44 -0
  147. package/src/lib/config.ts +102 -71
  148. package/src/lib/db/drizzle.config.mssql.ts +9 -0
  149. package/src/lib/db/drizzle.config.pg.ts +9 -0
  150. package/src/lib/db/migrate.ts +45 -10
  151. package/src/lib/db/migrations/mssql/20260729092726_talented_wilson_fisk/migration.sql +20 -0
  152. package/src/lib/db/migrations/mssql/20260729092726_talented_wilson_fisk/snapshot.json +497 -0
  153. package/src/lib/db/migrations/mssql/20260801003652_perpetual_blue_shield/migration.sql +1 -0
  154. package/src/lib/db/migrations/mssql/20260801003652_perpetual_blue_shield/snapshot.json +516 -0
  155. package/src/lib/db/migrations/mssql/20260812174642_user_id_text/migration.sql +2 -0
  156. package/src/lib/db/migrations/mssql/20260812174642_user_id_text/snapshot.json +516 -0
  157. package/src/lib/db/migrations/pg/20260801084117_thick_ben_grimm/migration.sql +53 -0
  158. package/src/lib/db/migrations/pg/20260801084117_thick_ben_grimm/snapshot.json +584 -0
  159. package/src/lib/db/migrations/pg/20260812174622_user_id_text/migration.sql +2 -0
  160. package/src/lib/db/migrations/pg/20260812174622_user_id_text/snapshot.json +584 -0
  161. package/src/lib/db/{schema.ts → schema.mssql.ts} +29 -18
  162. package/src/lib/db/schema.pg.ts +95 -0
  163. package/src/lib/factory.ts +44 -89
  164. package/src/lib/graph/index.ts +12 -40
  165. package/src/lib/graph/resolver.ts +146 -116
  166. package/src/lib/index.ts +11 -4
  167. package/src/lib/redis.ts +44 -0
  168. package/src/lib/routes/chat.ts +91 -62
  169. package/src/lib/routes/files.ts +105 -83
  170. package/src/lib/routes/owned-thread.ts +17 -0
  171. package/src/lib/routes/threads.ts +14 -30
  172. package/src/lib/routes/ws.ts +9 -3
  173. package/src/lib/types.ts +37 -36
  174. package/src/lib/ws/connections.ts +9 -1
  175. package/tsconfig.json +48 -0
  176. package/dist/src/lib/adapters/database.d.ts +0 -45
  177. package/dist/src/lib/adapters/mssql.d.ts +0 -3
  178. package/dist/src/lib/ai/active-streams.d.ts +0 -14
  179. package/dist/src/lib/ai/context/index.d.ts +0 -16
  180. package/dist/src/lib/ai/tools/capture-files.tool.d.ts +0 -6
  181. package/dist/src/lib/cli/extract-endpoints.d.ts +0 -6
  182. package/dist/src/lib/graph/expand-domains.d.ts +0 -2
  183. package/dist/src/lib/graph/generate-cypher.d.ts +0 -22
  184. package/dist/src/lib/graph/seed.d.ts +0 -19
  185. package/dist/src/lib/graph/validate.d.ts +0 -2
  186. package/dist/src/lib/routes/index.d.ts +0 -4
  187. package/dist/src/lib/ws/events.d.ts +0 -39
  188. package/dist/src/lib/ws/index.d.ts +0 -3
  189. package/dist/src/lib/ws/notify.d.ts +0 -2
  190. package/src/lib/adapters/database.ts +0 -48
  191. package/src/lib/adapters/mssql.ts +0 -231
  192. package/src/lib/ai/active-streams.ts +0 -123
  193. package/src/lib/ai/context/index.ts +0 -80
  194. package/src/lib/ai/tools/capture-files.tool.ts +0 -20
  195. package/src/lib/cli/extract-endpoints.ts +0 -550
  196. package/src/lib/graph/expand-domains.ts +0 -276
  197. package/src/lib/graph/generate-cypher.ts +0 -192
  198. package/src/lib/graph/seed.ts +0 -162
  199. package/src/lib/graph/validate.ts +0 -78
  200. package/src/lib/routes/index.ts +0 -4
  201. package/src/lib/ws/events.ts +0 -39
  202. package/src/lib/ws/index.ts +0 -11
  203. package/src/lib/ws/notify.ts +0 -9
  204. package/src/sample/db/client.ts +0 -9
  205. package/src/sample/db/migrations/20260411023125_rich_purple_man/migration.sql +0 -5
  206. package/src/sample/db/migrations/20260411023125_rich_purple_man/snapshot.json +0 -50
  207. package/src/sample/db/schema.ts +0 -10
  208. package/src/sample/domains/account/concepts/session.concept.ts +0 -17
  209. package/src/sample/domains/account/endpoints/listCurrentSessions.endpoint.ts +0 -31
  210. package/src/sample/domains/account/endpoints/revokeAllOtherSessions.endpoint.ts +0 -22
  211. package/src/sample/domains/account/endpoints/revokeCurrentSession.endpoint.ts +0 -33
  212. package/src/sample/domains/account/index.ts +0 -18
  213. package/src/sample/domains/appraisals/concepts/appraisalCycle.concept.ts +0 -15
  214. package/src/sample/domains/appraisals/concepts/appraisalRecord.concept.ts +0 -20
  215. package/src/sample/domains/appraisals/concepts/appraisalRecordCompetency.concept.ts +0 -10
  216. package/src/sample/domains/appraisals/concepts/appraisalRecordFunctionalRequirement.concept.ts +0 -10
  217. package/src/sample/domains/appraisals/concepts/appraisalRecordGoal.concept.ts +0 -17
  218. package/src/sample/domains/appraisals/endpoints/getAppraisalRecordById.endpoint.ts +0 -321
  219. package/src/sample/domains/appraisals/endpoints/getAppraisalRecordCompetencies.endpoint.ts +0 -120
  220. package/src/sample/domains/appraisals/endpoints/getAppraisalRecordFunctionalRequirements.endpoint.ts +0 -126
  221. package/src/sample/domains/appraisals/endpoints/getAppraisalRecordGoals.endpoint.ts +0 -104
  222. package/src/sample/domains/appraisals/endpoints/getAppraisalRecordScore.endpoint.ts +0 -58
  223. package/src/sample/domains/appraisals/endpoints/listAppraisalCyclesSimple.endpoint.ts +0 -52
  224. package/src/sample/domains/appraisals/endpoints/listAppraisalRecords.endpoint.ts +0 -245
  225. package/src/sample/domains/appraisals/endpoints/listAppraisalTemplatesSimple.endpoint.ts +0 -52
  226. package/src/sample/domains/appraisals/index.ts +0 -40
  227. package/src/sample/domains/appraisals/rules/appraisalRecordScoping.rule.ts +0 -7
  228. package/src/sample/domains/attendance/concepts/attendancePermission.concept.ts +0 -17
  229. package/src/sample/domains/attendance/concepts/attendanceTransaction.concept.ts +0 -17
  230. package/src/sample/domains/attendance/concepts/publicHoliday.concept.ts +0 -10
  231. package/src/sample/domains/attendance/concepts/punch.concept.ts +0 -19
  232. package/src/sample/domains/attendance/endpoints/getAttendanceTransactionById.endpoint.ts +0 -444
  233. package/src/sample/domains/attendance/endpoints/getCurrentAttendanceProfile.endpoint.ts +0 -886
  234. package/src/sample/domains/attendance/endpoints/getCurrentAttendanceStatistics.endpoint.ts +0 -49
  235. package/src/sample/domains/attendance/endpoints/listAttendancePermissions.endpoint.ts +0 -176
  236. package/src/sample/domains/attendance/endpoints/listAttendanceTransactionStates.endpoint.ts +0 -26
  237. package/src/sample/domains/attendance/endpoints/listAttendanceTransactions.endpoint.ts +0 -373
  238. package/src/sample/domains/attendance/endpoints/listPublicHolidaysSimple.endpoint.ts +0 -52
  239. package/src/sample/domains/attendance/endpoints/listPunchTypes.endpoint.ts +0 -25
  240. package/src/sample/domains/attendance/endpoints/listPunches.endpoint.ts +0 -178
  241. package/src/sample/domains/attendance/index.ts +0 -41
  242. package/src/sample/domains/attendance/services/attendancePermissions.service.ts +0 -15
  243. package/src/sample/domains/employees/concepts/employee.concept.ts +0 -20
  244. package/src/sample/domains/employees/concepts/employeeBankAccount.concept.ts +0 -19
  245. package/src/sample/domains/employees/concepts/employeeChild.concept.ts +0 -19
  246. package/src/sample/domains/employees/concepts/employeeDocument.concept.ts +0 -21
  247. package/src/sample/domains/employees/concepts/employeeEvent.concept.ts +0 -21
  248. package/src/sample/domains/employees/concepts/employeeExperience.concept.ts +0 -18
  249. package/src/sample/domains/employees/concepts/employeeJobLevelChange.concept.ts +0 -21
  250. package/src/sample/domains/employees/concepts/employeeMedal.concept.ts +0 -20
  251. package/src/sample/domains/employees/concepts/employeeQualification.concept.ts +0 -20
  252. package/src/sample/domains/employees/concepts/employeeSpouse.concept.ts +0 -21
  253. package/src/sample/domains/employees/concepts/employeeViolation.concept.ts +0 -19
  254. package/src/sample/domains/employees/endpoints/getCurrentEmployee.endpoint.ts +0 -1651
  255. package/src/sample/domains/employees/endpoints/getCurrentIdentity.endpoint.ts +0 -197
  256. package/src/sample/domains/employees/endpoints/getCurrentManagers.endpoint.ts +0 -142
  257. package/src/sample/domains/employees/endpoints/getEmployeeById.endpoint.ts +0 -1659
  258. package/src/sample/domains/employees/endpoints/getEmployeeStatistics.endpoint.ts +0 -43
  259. package/src/sample/domains/employees/endpoints/listBankAccounts.endpoint.ts +0 -223
  260. package/src/sample/domains/employees/endpoints/listChildren.endpoint.ts +0 -211
  261. package/src/sample/domains/employees/endpoints/listDocuments.endpoint.ts +0 -222
  262. package/src/sample/domains/employees/endpoints/listEmployeesSimple.endpoint.ts +0 -156
  263. package/src/sample/domains/employees/endpoints/listEvents.endpoint.ts +0 -120
  264. package/src/sample/domains/employees/endpoints/listExperiences.endpoint.ts +0 -188
  265. package/src/sample/domains/employees/endpoints/listJobLevelChanges.endpoint.ts +0 -240
  266. package/src/sample/domains/employees/endpoints/listMedals.endpoint.ts +0 -266
  267. package/src/sample/domains/employees/endpoints/listQualifications.endpoint.ts +0 -265
  268. package/src/sample/domains/employees/endpoints/listSpouses.endpoint.ts +0 -278
  269. package/src/sample/domains/employees/endpoints/listViolations.endpoint.ts +0 -245
  270. package/src/sample/domains/employees/index.ts +0 -75
  271. package/src/sample/domains/employees/services/employees.service.ts +0 -181
  272. package/src/sample/domains/index.ts +0 -10
  273. package/src/sample/domains/leaves/concepts/leave.concept.ts +0 -21
  274. package/src/sample/domains/leaves/concepts/leaveBalance.concept.ts +0 -17
  275. package/src/sample/domains/leaves/concepts/leaveBalanceTransaction.concept.ts +0 -16
  276. package/src/sample/domains/leaves/concepts/leaveType.concept.ts +0 -13
  277. package/src/sample/domains/leaves/concepts/leaveTypes.concept.ts +0 -205
  278. package/src/sample/domains/leaves/endpoints/getBalance.endpoint.ts +0 -53
  279. package/src/sample/domains/leaves/endpoints/getLeaveById.endpoint.ts +0 -53
  280. package/src/sample/domains/leaves/endpoints/listBalanceTransactions.endpoint.ts +0 -196
  281. package/src/sample/domains/leaves/endpoints/listBalanceTypes.endpoint.ts +0 -26
  282. package/src/sample/domains/leaves/endpoints/listBalances.endpoint.ts +0 -201
  283. package/src/sample/domains/leaves/endpoints/listLeaveTypes.endpoint.ts +0 -28
  284. package/src/sample/domains/leaves/endpoints/listLeaves.endpoint.ts +0 -234
  285. package/src/sample/domains/leaves/index.ts +0 -38
  286. package/src/sample/domains/leaves/services/leaveRequests.service.ts +0 -232
  287. package/src/sample/domains/notifications/concepts/notification.concept.ts +0 -19
  288. package/src/sample/domains/notifications/endpoints/countMyNotifications.endpoint.ts +0 -21
  289. package/src/sample/domains/notifications/endpoints/getMyNotification.endpoint.ts +0 -57
  290. package/src/sample/domains/notifications/endpoints/listMyNotifications.endpoint.ts +0 -59
  291. package/src/sample/domains/notifications/endpoints/markMyNotificationAsRead.endpoint.ts +0 -32
  292. package/src/sample/domains/notifications/index.ts +0 -20
  293. package/src/sample/domains/payroll/concepts/payslip.concept.ts +0 -18
  294. package/src/sample/domains/payroll/concepts/salaryCertificate.concept.ts +0 -17
  295. package/src/sample/domains/payroll/concepts/salaryCertificateRequestingEntity.concept.ts +0 -8
  296. package/src/sample/domains/payroll/endpoints/getPayslipById.endpoint.ts +0 -238
  297. package/src/sample/domains/payroll/endpoints/listPayslips.endpoint.ts +0 -216
  298. package/src/sample/domains/payroll/endpoints/listSalaryCertificateLanguages.endpoint.ts +0 -25
  299. package/src/sample/domains/payroll/endpoints/listSalaryCertificateRequestingEntities.endpoint.ts +0 -62
  300. package/src/sample/domains/payroll/endpoints/listSalaryCertificateTypes.endpoint.ts +0 -24
  301. package/src/sample/domains/payroll/endpoints/listSalaryCertificates.endpoint.ts +0 -122
  302. package/src/sample/domains/payroll/endpoints/previewSalaryCertificate.endpoint.ts +0 -45
  303. package/src/sample/domains/payroll/index.ts +0 -32
  304. package/src/sample/domains/payroll/rules/payrollEmployeeContext.rule.ts +0 -7
  305. package/src/sample/domains/payroll/services/salaryCertificates.service.ts +0 -15
  306. package/src/sample/domains/servicing/concepts/service.concept.ts +0 -6
  307. package/src/sample/domains/servicing/concepts/serviceRequest.concept.ts +0 -12
  308. package/src/sample/domains/servicing/concepts/serviceRequestApproval.concept.ts +0 -9
  309. package/src/sample/domains/servicing/endpoints/cancelServiceRequest.endpoint.ts +0 -21
  310. package/src/sample/domains/servicing/endpoints/createServiceRequest.endpoint.ts +0 -511
  311. package/src/sample/domains/servicing/endpoints/getServiceRequest.endpoint.ts +0 -352
  312. package/src/sample/domains/servicing/endpoints/getServiceRequestFormItems.endpoint.ts +0 -219
  313. package/src/sample/domains/servicing/endpoints/getServiceRequestTransactionFormItems.endpoint.ts +0 -216
  314. package/src/sample/domains/servicing/endpoints/getServiceStates.endpoint.ts +0 -47
  315. package/src/sample/domains/servicing/endpoints/invokeServiceRequestAction.endpoint.ts +0 -139
  316. package/src/sample/domains/servicing/endpoints/listServiceRequests.endpoint.ts +0 -292
  317. package/src/sample/domains/servicing/endpoints/listServices.endpoint.ts +0 -108
  318. package/src/sample/domains/servicing/endpoints/updateServiceRequest.endpoint.ts +0 -355
  319. package/src/sample/domains/servicing/index.ts +0 -44
  320. package/src/sample/domains/servicing/rules/checkValidActions.rule.ts +0 -7
  321. package/src/sample/domains/servicing/rules/createServiceRequest.rule.ts +0 -7
  322. package/src/sample/domains/servicing/rules/filterServiceRequestsByState.rule.ts +0 -7
  323. package/src/sample/domains/servicing/rules/passingOptionFields.rule.ts +0 -7
  324. package/src/sample/domains/shared/rules/pagination.rule.ts +0 -7
  325. package/src/sample/domains/suggestions/concepts/suggestion.concept.ts +0 -19
  326. package/src/sample/domains/suggestions/concepts/suggestionCategory.concept.ts +0 -7
  327. package/src/sample/domains/suggestions/concepts/suggestionImpactLevel.concept.ts +0 -7
  328. package/src/sample/domains/suggestions/endpoints/createSuggestion.endpoint.ts +0 -705
  329. package/src/sample/domains/suggestions/endpoints/deleteSuggestion.endpoint.ts +0 -32
  330. package/src/sample/domains/suggestions/endpoints/getSuggestionById.endpoint.ts +0 -635
  331. package/src/sample/domains/suggestions/endpoints/listSuggestionCategories.endpoint.ts +0 -62
  332. package/src/sample/domains/suggestions/endpoints/listSuggestionImpactLevels.endpoint.ts +0 -62
  333. package/src/sample/domains/suggestions/endpoints/listSuggestionStates.endpoint.ts +0 -24
  334. package/src/sample/domains/suggestions/endpoints/listSuggestions.endpoint.ts +0 -132
  335. package/src/sample/domains/suggestions/endpoints/updateSuggestion.endpoint.ts +0 -690
  336. package/src/sample/domains/suggestions/endpoints/updateSuggestionState.endpoint.ts +0 -39
  337. package/src/sample/domains/suggestions/index.ts +0 -34
  338. package/src/sample/domains/suggestions/rules/suggestionScope.rule.ts +0 -7
  339. package/src/sample/domains/surveys/concepts/survey.concept.ts +0 -10
  340. package/src/sample/domains/surveys/concepts/surveyResponse.concept.ts +0 -14
  341. package/src/sample/domains/surveys/endpoints/getSurveyResponseById.endpoint.ts +0 -131
  342. package/src/sample/domains/surveys/endpoints/getTargetedSurvey.endpoint.ts +0 -129
  343. package/src/sample/domains/surveys/endpoints/listTargetedSurveys.endpoint.ts +0 -160
  344. package/src/sample/domains/surveys/endpoints/respondToSurvey.endpoint.ts +0 -144
  345. package/src/sample/domains/surveys/index.ts +0 -21
  346. package/src/sample/drizzle.config.ts +0 -11
  347. package/src/sample/index.bak.ts +0 -341
  348. package/src/sample/index.ts +0 -318
  349. package/src/sample/official-statements/defaults.ts +0 -57
  350. package/src/sample/official-statements/routes.ts +0 -137
  351. package/src/sample/official-statements/service.ts +0 -148
  352. package/src/sample/official-statements/types.ts +0 -23
  353. /package/src/lib/db/migrations/{20260326231647_nice_speedball → mssql/20260326231647_nice_speedball}/migration.sql +0 -0
  354. /package/src/lib/db/migrations/{20260326231647_nice_speedball → mssql/20260326231647_nice_speedball}/snapshot.json +0 -0
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # @m6d/cortex-server
2
2
 
3
- Multi-agent AI chat server built on Hono + Bun. Supports MSSQL persistence, MinIO file storage, Neo4j knowledge graphs, and AI streaming with tool execution.
3
+ Multi-agent AI chat server built on Hono + Bun. Supports MSSQL or Postgres persistence, MinIO file storage, Neo4j knowledge graphs, and AI streaming with tool execution.
4
+
5
+ This package is a **runtime** library: it serves requests, resolves against the knowledge graph on every prompt, and exports the `define*` helpers you author domains with. Generation and seeding are not here — seeding the graph and generating endpoint schemas from Swagger are [`@m6d/cortex-cli`](https://www.npmjs.com/package/@m6d/cortex-cli) commands (`cortex graph seed`, `cortex swagger sync`). What the two share is the graph contract — `GRAPH_SCHEMA`, `GRAPH_SCHEMA_VERSION`, the `define*` helpers and their types, the Neo4j client and the embedder — which lives in the private `@cortex/contracts` workspace package (`internal/contracts`) and is vendored into this package's tarball at pack time. It is all re-exported from here, so authoring your domains stays one import. The CLI stamps the schema version it seeded onto the graph; this package reads that stamp on its first resolve and refuses a graph it cannot read, instead of quietly retrieving nothing.
4
6
 
5
7
  ## Usage
6
8
 
@@ -9,6 +11,7 @@ import { createCortex } from "@m6d/cortex-server";
9
11
 
10
12
  const cortex = createCortex({
11
13
  database: {
14
+ // Or `type: "postgres"` with a postgres:// connection string.
12
15
  type: "mssql",
13
16
  connectionString: process.env.DB_CONNECTION_STRING!,
14
17
  },
@@ -35,7 +38,7 @@ const cortex = createCortex({
35
38
  dimension: 1536,
36
39
  },
37
40
  neo4j: {
38
- url: "bolt://localhost:7687",
41
+ url: "http://localhost:7474",
39
42
  user: "neo4j",
40
43
  password: "password",
41
44
  },
@@ -55,7 +58,9 @@ export default {
55
58
  };
56
59
  ```
57
60
 
58
- `cortex.serve()` is async — it runs database migrations on startup.
61
+ `cortex.serve()` is async — it runs database migrations on startup, from the migration history belonging to the configured dialect.
62
+
63
+ Only `database`, `model`, and `agents` are required for a minimal setup. `storage` enables attachment uploads/downloads, `embedding` is only required when `neo4j` graph features are configured, and agent `systemPrompt` defaults to an empty prompt when omitted. An optional `redis: { url, streamTtlSeconds? }` backs resumable streams with Redis so runs survive reconnects, reloads, and multiple server instances; without it an in-memory, single-process fallback is used.
59
64
 
60
65
  Each key in `agents` becomes a route prefix (e.g. `assistant` → `/agents/assistant/...`). Agents can define per-agent `systemPrompt`, `tools`, `backendFetch`, `loadSessionData`, `resolveRequestContext`, and lifecycle hooks (`onToolCall`, `onStreamFinish`).
61
66
 
@@ -0,0 +1,23 @@
1
+ # @cortex/contracts
2
+
3
+ The shapes both sides of a cortex boundary must agree on. Private on purpose —
4
+ it never publishes; each publishable package carries its own copy:
5
+
6
+ - `@m6d/cortex-server` and `@m6d/cortex-cli` publish raw source, so their
7
+ `prepack` vendors a copy of this directory into the tarball (`contracts/` and
8
+ `src/contracts/` respectively), resolved there by their shipped tsconfig paths.
9
+ - `@m6d/cortex-angular` and `@m6d/cortex-react` compile the parts they import
10
+ into their build artifacts.
11
+
12
+ Three boundaries, one subpath each:
13
+
14
+ | import | boundary |
15
+ | --------------------------- | ------------------------------------------------------------- |
16
+ | `@cortex/contracts/wire` | chat client ↔ server (HTTP/WebSocket types) |
17
+ | `@cortex/contracts/runtime` | cortex-cc console ↔ server runtime API (zod schemas) |
18
+ | `@cortex/contracts/graph` | graph authoring (cli) ↔ server (vocabulary, helpers, clients) |
19
+
20
+ Everything is consumed as TypeScript source — no build, no dist. Nothing here
21
+ has a runtime dependency beyond zod (for `/runtime`), and nothing here may grow
22
+ one: these files are compiled into an Angular library, a React library, a CLI
23
+ and a Bun server alike.
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Embeddings, which both halves of the graph need: `@m6d/cortex-cli` embeds every
3
+ * concept description as it seeds, `@m6d/cortex-server` embeds every prompt as it
4
+ * resolves. Two embedders would mean two vector spaces, so there is one.
5
+ *
6
+ * TanStack AI removed embeddings, and the graph only ever needed the plain
7
+ * OpenAI-compatible `/embeddings` call cortex is already configured for — so this
8
+ * is a bare `fetch`, and this package keeps its zero dependencies.
9
+ *
10
+ * Everything under `./graph` is written to the oldest target any consumer builds
11
+ * against — an Angular library compiles these sources directly — and imports
12
+ * siblings by their `.js` specifier so one emit serves both `dist` and source.
13
+ */
14
+
15
+ /** Everything cortex needs to reach one OpenAI-compatible embeddings endpoint. */
16
+ export type EmbeddingProviderConfig = {
17
+ baseURL: string;
18
+ apiKey: string;
19
+ modelName: string;
20
+ };
21
+
22
+ /** Turns a batch of strings into their vectors, in the order given. */
23
+ export type EmbedFn = (values: string[]) => Promise<number[][]>;
24
+
25
+ export function createEmbedder(config: EmbeddingProviderConfig) {
26
+ const url = `${config.baseURL.replace(/\/+$/, "")}/embeddings`;
27
+
28
+ return async function embed(values: string[]) {
29
+ const response = await fetch(url, {
30
+ method: "POST",
31
+ headers: {
32
+ "Content-Type": "application/json",
33
+ Authorization: `Bearer ${config.apiKey}`,
34
+ },
35
+ body: JSON.stringify({ model: config.modelName, input: values }),
36
+ });
37
+
38
+ if (!response.ok) {
39
+ throw new Error(
40
+ `Embedding request failed (${response.status}): ${await response.text()}`,
41
+ );
42
+ }
43
+
44
+ // The API is free to return entries out of order; `index` is authoritative.
45
+ const body = (await response.json()) as { data: { index: number; embedding: number[] }[] };
46
+ return [...body.data]
47
+ .sort((left, right) => left.index - right.index)
48
+ .map((entry) => entry.embedding);
49
+ };
50
+ }
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Helper functions for building knowledge graph seed data.
2
+ * Helper functions for building knowledge graph seed data. Projects author
3
+ * domains with these; `@m6d/cortex-server` re-exports them so authoring needs
4
+ * exactly one import path.
3
5
  */
4
6
 
5
7
  import type {
@@ -9,11 +11,7 @@ import type {
9
11
  EndpointInput,
10
12
  RuleDef,
11
13
  ServiceDef,
12
- } from "./types.ts";
13
-
14
- // ---------------------------------------------------------------------------
15
- // Identity helpers
16
- // ---------------------------------------------------------------------------
14
+ } from "./types";
17
15
 
18
16
  export function defineConcept(def: Omit<ConceptDef, "__brand">) {
19
17
  return { __brand: "concept" as const, ...def };
@@ -31,10 +29,6 @@ export function defineDomain(def: Omit<DomainDef, "__brand">) {
31
29
  return { __brand: "domain" as const, ...def };
32
30
  }
33
31
 
34
- // ---------------------------------------------------------------------------
35
- // Endpoint builder
36
- // ---------------------------------------------------------------------------
37
-
38
32
  export function defineEndpoint(input: EndpointInput) {
39
33
  const propertiesDescriptions = Object.fromEntries(
40
34
  Object.entries({
@@ -1,16 +1,11 @@
1
1
  /**
2
- * Configurable Neo4j HTTP client.
2
+ * Configurable Neo4j HTTP client, shared by the graph's writer and its reader.
3
3
  *
4
- * Replaces the hardcoded process.env-based client from packages/sample-backend.
5
- * All configuration is passed explicitly no environment variables are read.
4
+ * All configuration is passed explicitly no environment variables are read —
5
+ * and the transport is `fetch`, so this package stays dependency-free.
6
6
  */
7
7
 
8
- import type { EmbeddingModel } from "ai";
9
- import { embed } from "ai";
10
-
11
- // ---------------------------------------------------------------------------
12
- // Config types
13
- // ---------------------------------------------------------------------------
8
+ import type { EmbedFn } from "./embed";
14
9
 
15
10
  export type Neo4jConfig = {
16
11
  url: string;
@@ -22,33 +17,21 @@ export type Neo4jClient = {
22
17
  query(cypher: string, parameters?: Record<string, unknown>): Promise<string>;
23
18
  };
24
19
 
25
- // ---------------------------------------------------------------------------
26
- // Client factory
27
- // ---------------------------------------------------------------------------
28
-
29
- export function createNeo4jClient(config: Neo4jConfig, embeddingModel?: EmbeddingModel) {
20
+ export function createNeo4jClient(config: Neo4jConfig, embed?: EmbedFn) {
30
21
  async function query(cypher: string, parameters?: Record<string, unknown>) {
31
22
  // Auto-embed parameters whose keys start with '#'
32
23
  const embeddedParams = Object.keys(parameters ?? {}).filter((x) => x.startsWith("#"));
33
24
 
34
25
  if (embeddedParams.length) {
35
- if (!embeddingModel) {
36
- throw new Error("An embedding model is required when using # parameters");
26
+ if (!embed) {
27
+ throw new Error("An embedder is required when using # parameters");
37
28
  }
38
29
 
39
- const embeddingResults = await Promise.all(
40
- embeddedParams.map(
41
- async (x) =>
42
- await embed({
43
- model: embeddingModel,
44
- value: parameters![x] as string,
45
- }),
46
- ),
47
- );
30
+ const embeddings = await embed(embeddedParams.map((k) => parameters![k] as string));
48
31
 
49
32
  embeddedParams.forEach((k, idx) => {
50
33
  delete parameters![k];
51
- parameters![k.slice(1)] = embeddingResults[idx]!.embedding;
34
+ parameters![k.slice(1)] = embeddings[idx]!;
52
35
  });
53
36
  }
54
37
 
@@ -77,13 +60,17 @@ export function createNeo4jClient(config: Neo4jConfig, embeddingModel?: Embeddin
77
60
  }
78
61
 
79
62
  const result = (await response.json()) as {
80
- errors?: { message: string }[];
63
+ errors?: { code?: string; message: string }[];
81
64
  results: { columns: string[]; data: { row: unknown[] }[] }[];
82
65
  };
83
66
 
84
67
  if (result.errors && result.errors.length > 0) {
68
+ // `code` rides alongside the message rather than inside it: it is the
69
+ // one-line identifier a report shows, and existing readers of
70
+ // `message` keep seeing exactly what they saw before.
85
71
  return JSON.stringify({
86
72
  error: true,
73
+ code: result.errors[0]!.code,
87
74
  message: result.errors.map((e) => e.message).join("; "),
88
75
  });
89
76
  }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The contract between the graph's writer and its reader.
3
+ *
4
+ * Seeding lives in `@m6d/cortex-cli` and resolution lives in `@m6d/cortex-server`,
5
+ * two packages a project installs and upgrades separately. The labels, relationship
6
+ * types, property names and index name they agree on are this module, here, so
7
+ * neither side owns the vocabulary the other has to match.
8
+ *
9
+ * A mismatch between the two is invisible at runtime: the resolver's Cypher
10
+ * matches nothing and retrieval comes back empty rather than failing. That is what
11
+ * `GRAPH_SCHEMA_VERSION` is for — bump it on any change to the shape below. The
12
+ * CLI stamps the version it wrote onto the graph and the server checks that stamp
13
+ * on its first resolve, so skew surfaces as an error instead of as silence.
14
+ */
15
+
16
+ export const GRAPH_SCHEMA_VERSION = 1;
17
+
18
+ export const GRAPH_SCHEMA = {
19
+ label: {
20
+ domain: "Domain",
21
+ concept: "Concept",
22
+ endpoint: "Endpoint",
23
+ service: "Service",
24
+ rule: "Rule",
25
+ /** Stamped with the version above, so a stale graph is detectable later. */
26
+ marker: "CortexGraph",
27
+ },
28
+ rel: {
29
+ belongsTo: "BELONGS_TO",
30
+ specializes: "SPECIALIZES",
31
+ queriedVia: "QUERIED_VIA",
32
+ mutatedVia: "MUTATED_VIA",
33
+ returns: "RETURNS",
34
+ dependsOn: "DEPENDS_ON",
35
+ governs: "GOVERNS",
36
+ requestedVia: "REQUESTED_VIA",
37
+ },
38
+ prop: {
39
+ name: "name",
40
+ description: "description",
41
+ aliases: "aliases",
42
+ metadata: "metadata",
43
+ path: "path",
44
+ method: "method",
45
+ params: "params",
46
+ body: "body",
47
+ response: "response",
48
+ propertiesDescriptions: "propertiesDescriptions",
49
+ successStatus: "successStatus",
50
+ errorStatuses: "errorStatuses",
51
+ builtInId: "builtInId",
52
+ embedding: "embedding",
53
+ /** On a RETURNS edge: which part of the response carries the concept. */
54
+ field: "field",
55
+ /** On a DEPENDS_ON edge. */
56
+ paramName: "paramName",
57
+ fromField: "fromField",
58
+ /** On the marker node. */
59
+ version: "version",
60
+ },
61
+ /** Created by the CLI's seeder, queried by name in the resolver's first hop. */
62
+ conceptEmbeddingsIndex: "concept_embeddings",
63
+ } as const;
64
+
65
+ export type GraphSchema = typeof GRAPH_SCHEMA;
@@ -7,10 +7,6 @@
7
7
  * - Services are concept associations (no hardcoded endpoint steps).
8
8
  */
9
9
 
10
- // ---------------------------------------------------------------------------
11
- // Endpoint property model (v2)
12
- // ---------------------------------------------------------------------------
13
-
14
10
  export type EndpointScalarType =
15
11
  | "uuid"
16
12
  | "number"
@@ -24,7 +20,8 @@ export type EndpointScalarType =
24
20
  export type EndpointProperty = {
25
21
  readonly name: string;
26
22
  readonly required: boolean;
27
- readonly type: EndpointScalarType | string;
23
+ // NonNullable<unknown> keeps the literal union visible to autocomplete.
24
+ readonly type: EndpointScalarType | (string & NonNullable<unknown>);
28
25
  readonly isArray?: boolean;
29
26
  readonly properties?: readonly EndpointProperty[];
30
27
  readonly description?: string;
@@ -41,10 +38,6 @@ export type AutoGenerated = {
41
38
  readonly responseKind?: ResponseKind;
42
39
  };
43
40
 
44
- // ---------------------------------------------------------------------------
45
- // Concept descriptor
46
- // ---------------------------------------------------------------------------
47
-
48
41
  export type ConceptDef = {
49
42
  readonly __brand: "concept";
50
43
  name: string;
@@ -55,10 +48,6 @@ export type ConceptDef = {
55
48
  metadata?: Record<string, unknown>;
56
49
  };
57
50
 
58
- // ---------------------------------------------------------------------------
59
- // Endpoint descriptor (v2)
60
- // ---------------------------------------------------------------------------
61
-
62
51
  export type EndpointDef = {
63
52
  readonly __brand: "endpoint";
64
53
  name: string;
@@ -88,10 +77,6 @@ export type EndpointDef = {
88
77
  metadata?: Record<string, unknown>;
89
78
  };
90
79
 
91
- // ---------------------------------------------------------------------------
92
- // EndpointInput
93
- // ---------------------------------------------------------------------------
94
-
95
80
  export type EndpointInput = {
96
81
  name: string;
97
82
  path: string;
@@ -117,10 +102,6 @@ export type EndpointInput = {
117
102
  metadata?: Record<string, unknown>;
118
103
  };
119
104
 
120
- // ---------------------------------------------------------------------------
121
- // Service descriptor (v2)
122
- // ---------------------------------------------------------------------------
123
-
124
105
  export type ServiceDef = {
125
106
  readonly __brand: "service";
126
107
  name: string;
@@ -131,10 +112,6 @@ export type ServiceDef = {
131
112
  metadata?: Record<string, unknown>;
132
113
  };
133
114
 
134
- // ---------------------------------------------------------------------------
135
- // Rule descriptor
136
- // ---------------------------------------------------------------------------
137
-
138
115
  export type RuleDef = {
139
116
  readonly __brand: "rule";
140
117
  name: string;
@@ -142,10 +119,6 @@ export type RuleDef = {
142
119
  metadata?: Record<string, unknown>;
143
120
  };
144
121
 
145
- // ---------------------------------------------------------------------------
146
- // Domain descriptor
147
- // ---------------------------------------------------------------------------
148
-
149
122
  export type DomainDef = {
150
123
  readonly __brand: "domain";
151
124
  name: string;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The graph contract — the knowledge-graph vocabulary, authoring types and
3
+ * clients that `@m6d/cortex-cli` writes with and `@m6d/cortex-server` reads
4
+ * with. `@m6d/cortex-server` re-exports all of it, so a project authoring
5
+ * domains still has exactly one import path.
6
+ */
7
+
8
+ export type { GraphSchema } from "./graph/schema";
9
+ export { GRAPH_SCHEMA, GRAPH_SCHEMA_VERSION } from "./graph/schema";
10
+
11
+ export type {
12
+ EndpointScalarType,
13
+ EndpointProperty,
14
+ ResponseKind,
15
+ AutoGenerated,
16
+ ConceptDef,
17
+ EndpointDef,
18
+ EndpointInput,
19
+ ServiceDef,
20
+ RuleDef,
21
+ DomainDef,
22
+ } from "./graph/types";
23
+
24
+ export {
25
+ defineConcept,
26
+ defineRule,
27
+ defineService,
28
+ defineDomain,
29
+ defineEndpoint,
30
+ } from "./graph/helpers";
31
+
32
+ export type { Neo4jConfig, Neo4jClient } from "./graph/neo4j";
33
+ export { createNeo4jClient } from "./graph/neo4j";
34
+
35
+ export type { EmbedFn, EmbeddingProviderConfig } from "./graph/embed";
36
+ export { createEmbedder } from "./graph/embed";
@@ -0,0 +1,207 @@
1
+ /*
2
+ * The grammar and rendering pipeline for user-authored rich text that reaches
3
+ * the LLM (agent prompts, service descriptions). Both sides of the wire share
4
+ * it: the console edits and validates these strings, the console's runtime API
5
+ * pre-renders them (mentions + heading demotion), and `@m6d/cortex-server`
6
+ * applies per-request variable values. Two token grammars live here:
7
+ *
8
+ * - Tool mentions `@[name](uuid)` — the uuid is authoritative; the inline name
9
+ * is only a display cache refreshed on save ({@link normalizeMentions}) and
10
+ * resolved live when text is rendered for the LLM ({@link renderMentions}).
11
+ * - Variables `{{name}}` — validated against a known list at authoring time
12
+ * ({@link analyzeVariables}) and substituted per request on the server
13
+ * ({@link substituteVariables}).
14
+ */
15
+
16
+ /** One mention token, unanchored and flagless — the editor's tokenizer anchors it, the helpers below add `g`. */
17
+ export const MENTION_PATTERN_SOURCE = String.raw`@\[([^\]\n]*)\]\(([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\)`;
18
+
19
+ const MENTION_PATTERN = new RegExp(MENTION_PATTERN_SOURCE, "g");
20
+
21
+ const VARIABLE_PATTERN = /{{\s*([^{}]*?)\s*}}/g;
22
+
23
+ export function extractMentionedToolIds(text: string) {
24
+ const ids: string[] = [];
25
+ for (const match of text.matchAll(MENTION_PATTERN)) {
26
+ const id = match[2];
27
+ if (id && !ids.includes(id)) ids.push(id);
28
+ }
29
+ return ids;
30
+ }
31
+
32
+ /** Replaces each mention token with the tool's current name (falling back to the cached inline name). */
33
+ export function renderMentions(text: string, toolNameById: ReadonlyMap<string, string>) {
34
+ return text.replace(MENTION_PATTERN, (_, cachedName: string, toolId: string) => {
35
+ return toolNameById.get(toolId) ?? cachedName;
36
+ });
37
+ }
38
+
39
+ /** Refreshes stale display names inside stored text, keeping the tokens intact. */
40
+ export function normalizeMentions(text: string, toolNameById: ReadonlyMap<string, string>) {
41
+ return text.replace(MENTION_PATTERN, (token, _cachedName: string, toolId: string) => {
42
+ const name = toolNameById.get(toolId);
43
+ return name === undefined ? token : `@[${name}](${toolId})`;
44
+ });
45
+ }
46
+
47
+ /** Splits the `{{variables}}` referenced in a text into known and unknown ones. */
48
+ export function analyzeVariables<Variable extends string>(
49
+ text: string,
50
+ known: ReadonlyArray<Variable>,
51
+ ) {
52
+ const referenced = new Set(
53
+ Array.from(text.matchAll(VARIABLE_PATTERN), ([, name]) => name?.trim()),
54
+ );
55
+
56
+ return {
57
+ variables: known.filter((variable) => referenced.has(variable)),
58
+ unknownVariables: [...referenced].filter(
59
+ (variable): variable is string =>
60
+ variable !== undefined &&
61
+ !known.some((knownVariable) => knownVariable === variable),
62
+ ),
63
+ };
64
+ }
65
+
66
+ /** Fills `{{variables}}` with per-request values; unknown names stay verbatim. */
67
+ export function substituteVariables(text: string, values: Record<string, string>) {
68
+ return text.replace(/\{\{(\w+)\}\}/g, (match, name: string) => values[name] ?? match);
69
+ }
70
+
71
+ /**
72
+ * Line-by-line fence state, following CommonMark's fence rules: a fence line
73
+ * is indented at most three spaces; an opening backtick fence's info string
74
+ * may not contain backticks; and a fence closes only on the same marker
75
+ * character, with at least the opening run's length, followed by nothing but
76
+ * whitespace — so a `~~~` line, a shorter same-marker run, or a ```` ```js ````
77
+ * info line inside a backtick fence all stay code content.
78
+ */
79
+ function fenceTracker() {
80
+ let fence: { marker: string; length: number } | null = null;
81
+ return (line: string) => {
82
+ const match = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line);
83
+ const delimiter = match?.[1];
84
+ const rest = match?.[2] ?? "";
85
+ if (delimiter) {
86
+ const marker = delimiter.charAt(0);
87
+ if (fence) {
88
+ if (
89
+ marker === fence.marker &&
90
+ delimiter.length >= fence.length &&
91
+ rest.trim() === ""
92
+ ) {
93
+ fence = null;
94
+ return "close";
95
+ }
96
+ return "inside";
97
+ }
98
+ if (marker === "`" && rest.includes("`")) return "outside";
99
+ fence = { marker, length: delimiter.length };
100
+ return "open";
101
+ }
102
+ return fence ? "inside" : "outside";
103
+ };
104
+ }
105
+
106
+ /** ATX heading, CommonMark-style: up to three leading spaces, `#` run closed by space or line end. */
107
+ const ATX_HEADING = /^( {0,3})(#{1,6})(?=[ \t]|$)/;
108
+
109
+ /** Setext underline: a run of `=` or `-` alone on its line, up to three leading spaces. */
110
+ const SETEXT_UNDERLINE = /^ {0,3}(=+|-+)[ \t]*$/;
111
+
112
+ /** The skeleton owns `##` and `###`, so user headings start three levels below it. */
113
+ function demotedHashes(level: number) {
114
+ return "#".repeat(Math.min(level + 3, 6));
115
+ }
116
+
117
+ /**
118
+ * Whether a line can be the text of a setext heading — i.e. it is an ordinary
119
+ * paragraph line, not a blank, a fence, another heading, or the start of a
120
+ * different block (quote/list), in which case the underline below it is a
121
+ * thematic break or list content rather than a heading marker.
122
+ */
123
+ function isSetextText(line: string) {
124
+ return (
125
+ line.trim() !== "" &&
126
+ !ATX_HEADING.test(line) &&
127
+ !SETEXT_UNDERLINE.test(line) &&
128
+ !/^ {0,3}(`{3,}|~{3,})/.test(line) &&
129
+ !/^ {0,3}(>|[-*+][ \t]|\d+[.)][ \t])/.test(line)
130
+ );
131
+ }
132
+
133
+ /**
134
+ * Shifts user-authored headings down so they can never collide with the prompt
135
+ * skeleton, which owns `##` (sections) and `###` (card titles): `#` becomes
136
+ * `####`, deeper levels cap at `######`. Setext headings are rewritten as the
137
+ * equivalent demoted ATX heading, since two-level setext cannot express the
138
+ * shift. Fenced code is left alone.
139
+ */
140
+ export function demoteHeadings(text: string) {
141
+ const lineState = fenceTracker();
142
+ const output: string[] = [];
143
+ for (const line of text.split("\n")) {
144
+ if (lineState(line) !== "outside") {
145
+ output.push(line);
146
+ continue;
147
+ }
148
+
149
+ const underline = SETEXT_UNDERLINE.exec(line)?.[1];
150
+ const previous = output[output.length - 1];
151
+ if (underline !== undefined && previous !== undefined && isSetextText(previous)) {
152
+ const level = underline.startsWith("=") ? 1 : 2;
153
+ output[output.length - 1] = `${demotedHashes(level)} ${previous.trim()}`;
154
+ continue;
155
+ }
156
+
157
+ output.push(
158
+ line.replace(ATX_HEADING, (_, indent: string, hashes: string) => {
159
+ return `${indent}${demotedHashes(hashes.length)}`;
160
+ }),
161
+ );
162
+ }
163
+ return output.join("\n");
164
+ }
165
+
166
+ /** The one render step for LLM-bound rich text: resolve mentions, then demote headings. */
167
+ export function renderRichText(text: string, toolNameById: ReadonlyMap<string, string>) {
168
+ return demoteHeadings(renderMentions(text, toolNameById));
169
+ }
170
+
171
+ /**
172
+ * Reduces rich text to plain prose for embeddings: mentions become tool names
173
+ * (cached inline names when no map is given) and markdown syntax is dropped.
174
+ * ponytail: a regex stripper, not a markdown parser — nested emphasis or exotic
175
+ * constructs may leave residue; swap in a real parser if retrieval quality
176
+ * ever shows it.
177
+ */
178
+ export function stripToPlaintext(
179
+ text: string,
180
+ toolNameById: ReadonlyMap<string, string> = new Map(),
181
+ ) {
182
+ const lineState = fenceTracker();
183
+ return renderMentions(text, toolNameById)
184
+ .split("\n")
185
+ .filter((line) => {
186
+ const state = lineState(line);
187
+ return state !== "open" && state !== "close";
188
+ })
189
+ .map((line) =>
190
+ line
191
+ .replace(/^ {0,3}#{1,6}[ \t]+/, "")
192
+ .replace(SETEXT_UNDERLINE, "")
193
+ .replace(/^\s{0,3}(>\s?)+/, "")
194
+ .replace(/^(\s*)([-*+]|\d+[.)])\s+/, "$1")
195
+ .replace(/^\s*([-*_]\s*){3,}$/, ""),
196
+ )
197
+ .join("\n")
198
+ .replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1")
199
+ .replace(/\[([^\]]*)\]\([^)]*\)/g, "$1")
200
+ .replace(/(\*\*|__)([^*_]+)\1/g, "$2")
201
+ .replace(/(^|\W)[*_]([^*_]+)[*_](?=\W|$)/gm, "$1$2")
202
+ .replace(/~~([^~]+)~~/g, "$1")
203
+ .replace(/`([^`]*)`/g, "$1")
204
+ .replace(/\\([\\*_#[\]()>!`~+.-])/g, "$1")
205
+ .replace(/\n{3,}/g, "\n\n")
206
+ .trim();
207
+ }