@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
@@ -0,0 +1,17 @@
1
+ import type { Context } from "hono";
2
+ import type { CortexAppEnv } from "../types";
3
+ /**
4
+ * Loads a thread and asserts it belongs to both the caller and the agent in the
5
+ * path. A thread owned by another agent 404s rather than 403 on purpose — a 403
6
+ * would confirm the thread exists, making cross-agent ids probeable.
7
+ */
8
+ export declare function requireOwnedThread(c: Context<CortexAppEnv>, threadId: string): Promise<{
9
+ id: string;
10
+ userId: string;
11
+ agentId: string;
12
+ title: string | null;
13
+ session: Record<string, unknown> | null;
14
+ contextMeta: import("..").ThreadContextMeta | null;
15
+ createdAt: Date;
16
+ updatedAt: Date;
17
+ }>;
@@ -1,3 +1,3 @@
1
1
  import { Hono } from "hono";
2
- import type { CortexAppEnv } from "../types.ts";
2
+ import type { CortexAppEnv } from "../types";
3
3
  export declare function createThreadRoutes(): Hono<CortexAppEnv, import("hono/types").BlankSchema, "/">;
@@ -1,5 +1,5 @@
1
1
  import { Hono } from "hono";
2
- import type { AppEnv } from "../types.ts";
2
+ import type { AppEnv } from "../types";
3
3
  type WsRouteOptions = {
4
4
  useAgentParam?: boolean;
5
5
  };
@@ -1,42 +1,15 @@
1
+ import type { MessagePart } from "@tanstack/ai";
1
2
  import type { ResolvedCortexAgentConfig } from "./config";
2
3
  import type { InferSelectModel } from "drizzle-orm";
3
- import type { messages, threads } from "./db/schema";
4
+ import type { attachments, messages, threads } from "./db/schema.mssql";
5
+ export type { CortexMessage, MessageMetadata, ThreadSummary, TokenUsage, } from "../../contracts/wire";
6
+ import type { CortexMessage } from "../../contracts/wire";
7
+ /** A message as cortex persists and serves it: SDK parts plus cortex's envelope. */
8
+ export type ChatMessage = CortexMessage<MessagePart>;
4
9
  export type Thread = InferSelectModel<typeof threads>;
5
10
  export type StoredMessage = InferSelectModel<typeof messages>;
6
- export type ThreadSummary = {
7
- id: string;
8
- title?: string;
9
- createdAt: Date;
10
- updatedAt: Date;
11
- isRunning: boolean;
12
- };
13
- export type TokenUsage = {
14
- input: {
15
- noCache: number;
16
- cacheRead: number;
17
- cacheWrite: number;
18
- total: number;
19
- };
20
- output: {
21
- reasoning: number;
22
- text: number;
23
- total: number;
24
- };
25
- total: number;
26
- };
27
- export type MessageMetadata = {
28
- modelId: string;
29
- providerMetadata: unknown;
30
- isAborted?: boolean;
31
- tokenUsage?: TokenUsage;
32
- };
33
- export type CapturedFileInput = {
34
- id: string;
35
- file: {
36
- name: string;
37
- bytes: string;
38
- };
39
- };
11
+ export type Attachment = InferSelectModel<typeof attachments>;
12
+ export type NewAttachment = typeof attachments.$inferInsert;
40
13
  export type AppEnv = {
41
14
  Bindings: {};
42
15
  Variables: {
@@ -66,10 +39,20 @@ export type CortexAppEnv = {
66
39
  agentId: string;
67
40
  };
68
41
  };
42
+ /** Maps a stored row to the wire shape. Dates become ISO strings — the same bytes
43
+ * `JSON.stringify` would have produced, but now the type says so. */
69
44
  export declare function toThreadSummary(thread: Thread, isRunning: boolean): {
70
45
  id: string;
71
46
  title: string | undefined;
72
- createdAt: Date;
73
- updatedAt: Date;
47
+ createdAt: string;
48
+ updatedAt: string;
74
49
  isRunning: boolean;
75
50
  };
51
+ export declare function toAttachmentSummary(attachment: Attachment): {
52
+ id: string;
53
+ filename: string;
54
+ contentType: string;
55
+ sizeBytes: number;
56
+ status: "pending" | "described" | "failed" | "skipped";
57
+ description: string | undefined;
58
+ };
@@ -1,4 +1,5 @@
1
1
  import type { WSContext } from "hono/ws";
2
+ import type { WsEvent } from "../../../contracts/wire";
2
3
  export declare function addConnection(userId: string, agentId: string, ws: WSContext): void;
3
4
  export declare function removeConnection(userId: string, agentId: string, ws: WSContext): void;
4
- export declare function getConnections(userId: string, agentId: string): WSContext<unknown>[];
5
+ export declare function notify(userId: string, agentId: string, event: WsEvent): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m6d/cortex-server",
3
- "version": "1.8.0",
3
+ "version": "2.0.1",
4
4
  "description": "Reusable AI agent chat server library for Hono + Bun",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -16,43 +16,58 @@
16
16
  "files": [
17
17
  "dist",
18
18
  "src",
19
+ "contracts",
19
20
  "index.ts",
20
- "README.md"
21
+ "README.md",
22
+ "tsconfig.json",
23
+ "!src/**/*.test.ts",
24
+ "!src/**/*.mock.ts"
21
25
  ],
22
26
  "scripts": {
23
- "build": "tsc -p tsconfig.build.json",
24
- "db:generate": "drizzle-kit generate",
25
- "db:migrate": "drizzle-kit migrate",
26
- "db:sample:generate": "drizzle-kit generate --config ./src/sample/drizzle.config.ts",
27
- "db:sample:migrate": "drizzle-kit migrate --config ./src/sample/drizzle.config.ts",
28
- "dev": "bun run --hot src/sample/index.ts"
27
+ "build": "bun run vendor && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && rm -rf contracts",
28
+ "check": "tsc --noEmit",
29
+ "db:generate:mssql": "drizzle-kit generate --config=src/lib/db/drizzle.config.mssql.ts",
30
+ "db:generate:pg": "drizzle-kit generate --config=src/lib/db/drizzle.config.pg.ts",
31
+ "db:migrate:mssql": "drizzle-kit migrate --config=src/lib/db/drizzle.config.mssql.ts",
32
+ "db:migrate:pg": "drizzle-kit migrate --config=src/lib/db/drizzle.config.pg.ts",
33
+ "prepack": "bun run vendor",
34
+ "postpack": "rm -rf contracts",
35
+ "test": "bun test",
36
+ "vendor": "rm -rf contracts && cp -R ../../internal/contracts contracts && rm contracts/package.json contracts/tsconfig.json"
29
37
  },
30
38
  "dependencies": {
31
- "@ai-sdk/provider": "^3.0.0",
32
- "@hono/zod-validator": "^0.5.0",
33
- "drizzle-orm": "^1.0.0-beta.15-859cf75",
39
+ "@hono/zod-validator": "^0.9.0",
40
+ "@hyzyla/pdfium": "^2.1.13",
41
+ "drizzle-orm": "1.0.0-beta.15-859cf75",
42
+ "ioredis": "^5.9.2",
43
+ "jpeg-js": "^0.4.4",
34
44
  "minio": "^8.0.7",
35
45
  "mssql": "^12.2.0",
46
+ "pg": "^8.16.3",
36
47
  "quickjs-emscripten": "^0.32.0"
37
48
  },
38
49
  "devDependencies": {
39
- "@ai-sdk/openai-compatible": "^2.0.0",
50
+ "@tanstack/ai": "^0.43.1",
51
+ "@tanstack/ai-openai": "^0.18.0",
40
52
  "@types/bun": "latest",
41
53
  "@types/minio": "^7.1.1",
42
54
  "@types/mssql": "^9.1.5",
43
- "ai": "^6.0.104",
44
- "drizzle-kit": "^1.0.0-beta.15-859cf75",
55
+ "@types/pg": "^8.15.6",
56
+ "drizzle-kit": "1.0.0-beta.15-859cf75",
45
57
  "hono": "^4.12.3",
46
58
  "jose": "^6.1.3",
47
- "typescript": "^5",
59
+ "openai": "^6",
60
+ "tsc-alias": "^1.9.1",
61
+ "typescript": "~5.9.3",
48
62
  "zod": "^4.3.6"
49
63
  },
50
64
  "peerDependencies": {
51
- "@ai-sdk/openai-compatible": "^2.0.0",
52
- "ai": "^6.0.0",
65
+ "@tanstack/ai": "^0.43.1",
66
+ "@tanstack/ai-openai": "^0.18.0",
53
67
  "hono": "^4.12.3",
54
68
  "jose": "^6.1.3",
55
- "zod": "^3.24.0"
69
+ "openai": "^6",
70
+ "zod": "^4.1.8"
56
71
  },
57
72
  "engines": {
58
73
  "bun": ">=1.0.0"
@@ -0,0 +1,78 @@
1
+ import type {
2
+ Attachment,
3
+ ChatMessage,
4
+ NewAttachment,
5
+ StoredMessage,
6
+ Thread,
7
+ TokenUsage,
8
+ } from "@/types";
9
+ import type { ThreadContextMeta } from "@/ai/context/types";
10
+
11
+ /**
12
+ * The persistence contract, implemented once per dialect under `mssql/` and
13
+ * `postgres/`.
14
+ *
15
+ * Those two trees are near-identical on purpose. Drizzle types its query
16
+ * builders per dialect, so a shared body is not expressible — `.top`/`.limit`,
17
+ * `.output`/`.returning` and the row-lock hint differ down in the query, not at
18
+ * a seam that could be factored out. What is *not* SQL lives in
19
+ * `message-content.ts` instead, so the rules the two must agree on are stated
20
+ * once.
21
+ *
22
+ * Drift is guarded rather than prevented: `db/schema.parity.test.ts` asserts the
23
+ * two schemas still infer the same rows, and the adapter tests beside this file
24
+ * run against both implementations. The `code-duplication` suppressions in
25
+ * `postgres/` record the same decision for fallow.
26
+ */
27
+ export type DatabaseAdapter = {
28
+ threads: {
29
+ list(userId: string, agentId: string): Promise<Thread[]>;
30
+ getById(userId: string, threadId: string): Promise<Thread | null>;
31
+ create(userId: string, agentId: string): Promise<Thread>;
32
+ delete(userId: string, threadId: string): Promise<void>;
33
+ touch(threadId: string): Promise<Thread>;
34
+ updateTitle(threadId: string, title: string): Promise<void>;
35
+ updateSession(threadId: string, session: Record<string, unknown>): Promise<void>;
36
+ updateContextMeta(threadId: string, meta: ThreadContextMeta): Promise<void>;
37
+ };
38
+ messages: {
39
+ list(userId: string, threadId: string, opts?: { limit?: number }): Promise<StoredMessage[]>;
40
+ upsert(
41
+ threadId: string,
42
+ messages: ChatMessage[],
43
+ options?: { replaceAttachments?: boolean },
44
+ ): Promise<void>;
45
+ };
46
+ llmRequests: {
47
+ insert(
48
+ requests: {
49
+ messageId: string;
50
+ stepNumber: number;
51
+ prompt: string;
52
+ output: string | null;
53
+ tokenUsage: TokenUsage | null;
54
+ }[],
55
+ ): Promise<void>;
56
+ listByMessageId(messageId: string): Promise<
57
+ {
58
+ id: string;
59
+ prompt: string;
60
+ output: string | null;
61
+ tokenUsage: TokenUsage | null;
62
+ }[]
63
+ >;
64
+ };
65
+ attachments: {
66
+ createPending(row: NewAttachment, limit: number): Promise<Attachment | undefined>;
67
+ getById(id: string, userId: string): Promise<Attachment | undefined>;
68
+ listByThread(threadId: string, userId: string): Promise<Attachment[]>;
69
+ claimForMessage(threadId: string, userId: string, messageId: string): Promise<Attachment[]>;
70
+ setDescription(
71
+ id: string,
72
+ userId: string,
73
+ status: Attachment["status"],
74
+ description?: string,
75
+ ): Promise<void>;
76
+ remove(id: string, userId: string): Promise<Attachment | undefined>;
77
+ };
78
+ };
@@ -0,0 +1,39 @@
1
+ import type { ChatMessage } from "@/types";
2
+
3
+ /**
4
+ * The parts of `messages.upsert` that are decisions rather than SQL. Each
5
+ * dialect writes its own queries, but they must agree on what gets written —
6
+ * so the rules live here and neither repository restates them.
7
+ */
8
+
9
+ /** Denormalized alongside the JSON content so the column is searchable. */
10
+ export function textOf(message: ChatMessage) {
11
+ return message.parts.find((part) => part.type === "text")?.content;
12
+ }
13
+
14
+ /**
15
+ * Attachments are the server's to assign: a caller may name them but never
16
+ * establish them. Only a turn that has just claimed them may carry them in.
17
+ */
18
+ export function withOwnedAttachments(messages: ChatMessage[], replaceAttachments?: boolean) {
19
+ if (replaceAttachments) return messages;
20
+
21
+ return messages.map((message) => {
22
+ if (!message.metadata) return message;
23
+
24
+ const { attachments: _, ...metadata } = message.metadata;
25
+ return { ...message, metadata };
26
+ });
27
+ }
28
+
29
+ /**
30
+ * The envelope is the server's — usage, model id and the attachments it claimed
31
+ * are facts no caller carries in full, so an update only contributes the fields
32
+ * it actually set. Attachments were already stripped from anything that must
33
+ * not replace them.
34
+ */
35
+ export function mergeStoredContent(existing: ChatMessage, incoming: ChatMessage) {
36
+ return existing.metadata
37
+ ? { ...incoming, metadata: { ...existing.metadata, ...incoming.metadata } }
38
+ : incoming;
39
+ }
@@ -0,0 +1,90 @@
1
+ // fallow-ignore-file duplicate-export -- mssql twin of the postgres repository, same factory name by design
2
+ import { and, asc, count, eq, isNull, or, sql } from "drizzle-orm";
3
+ import { attachments, threads } from "@/db/schema.mssql";
4
+ import type { DatabaseAdapter } from "@/adapters/database/index";
5
+ import type { MssqlDb } from "./client";
6
+
7
+ export function createAttachmentsRepository(db: MssqlDb) {
8
+ return {
9
+ async createPending(row, limit) {
10
+ return await db.transaction(async function (tx) {
11
+ await tx.execute(
12
+ sql`SELECT 1 FROM ${threads} WITH (UPDLOCK, HOLDLOCK) WHERE ${threads.id} = ${row.threadId}`,
13
+ );
14
+ const pending = await tx
15
+ .select({ value: count() })
16
+ .from(attachments)
17
+ .where(
18
+ and(
19
+ eq(attachments.threadId, row.threadId),
20
+ eq(attachments.userId, row.userId),
21
+ isNull(attachments.messageId),
22
+ ),
23
+ )
24
+ .execute()
25
+ .then((rows) => rows[0]!.value);
26
+ if (pending >= limit) return undefined;
27
+
28
+ return await tx
29
+ .insert(attachments)
30
+ .output()
31
+ .values(row)
32
+ .execute()
33
+ .then((rows) => rows[0]!);
34
+ });
35
+ },
36
+
37
+ async getById(id, userId) {
38
+ return await db
39
+ .select()
40
+ .top(1)
41
+ .from(attachments)
42
+ .where(and(eq(attachments.id, id), eq(attachments.userId, userId)))
43
+ .execute()
44
+ .then((rows) => rows[0]);
45
+ },
46
+
47
+ async listByThread(threadId, userId) {
48
+ return await db
49
+ .select()
50
+ .from(attachments)
51
+ .where(and(eq(attachments.threadId, threadId), eq(attachments.userId, userId)))
52
+ .orderBy(asc(attachments.createdAt), asc(attachments.id))
53
+ .execute();
54
+ },
55
+
56
+ async claimForMessage(threadId, userId, messageId) {
57
+ // ponytail: retries only this message's pending rows; add claim timestamps for cross-message recovery.
58
+ return await db
59
+ .update(attachments)
60
+ .set({ messageId })
61
+ .where(
62
+ and(
63
+ eq(attachments.threadId, threadId),
64
+ eq(attachments.userId, userId),
65
+ eq(attachments.status, "pending"),
66
+ or(isNull(attachments.messageId), eq(attachments.messageId, messageId)),
67
+ ),
68
+ )
69
+ .output()
70
+ .execute();
71
+ },
72
+
73
+ async setDescription(id, userId, status, description) {
74
+ await db
75
+ .update(attachments)
76
+ .set(description === undefined ? { status } : { status, description })
77
+ .where(and(eq(attachments.id, id), eq(attachments.userId, userId)))
78
+ .execute();
79
+ },
80
+
81
+ async remove(id, userId) {
82
+ return await db
83
+ .delete(attachments)
84
+ .where(and(eq(attachments.id, id), eq(attachments.userId, userId)))
85
+ .output()
86
+ .execute()
87
+ .then((rows) => rows[0]);
88
+ },
89
+ } satisfies DatabaseAdapter["attachments"];
90
+ }
@@ -0,0 +1,11 @@
1
+ import { drizzle } from "drizzle-orm/node-mssql";
2
+
3
+ /**
4
+ * Global snake_case mapping means schema columns are never spelled out twice —
5
+ * the TypeScript name is the source of truth and Drizzle derives the column.
6
+ */
7
+ export function createMssqlDb(connectionString: string) {
8
+ return drizzle(connectionString, { casing: "snake_case" });
9
+ }
10
+
11
+ export type MssqlDb = ReturnType<typeof createMssqlDb>;
@@ -0,0 +1,23 @@
1
+ import type { DatabaseAdapter } from "@/adapters/database/index";
2
+ import type { StorageAdapter } from "@/adapters/storage/index";
3
+ import { createMssqlDb } from "./client";
4
+ import { createThreadsRepository } from "./threads";
5
+ import { createMessagesRepository } from "./messages";
6
+ import { createLlmRequestsRepository } from "./llm-requests";
7
+ import { createAttachmentsRepository } from "./attachments";
8
+
9
+ /**
10
+ * The MSSQL implementation of the database contract. One repository per table;
11
+ * only threads takes storage, because deleting a thread is the one operation
12
+ * that also has to reach into object storage.
13
+ */
14
+ export function createMssqlAdapter(connectionString: string, storage?: StorageAdapter) {
15
+ const db = createMssqlDb(connectionString);
16
+
17
+ return {
18
+ threads: createThreadsRepository(db, storage),
19
+ messages: createMessagesRepository(db),
20
+ llmRequests: createLlmRequestsRepository(db),
21
+ attachments: createAttachmentsRepository(db),
22
+ } satisfies DatabaseAdapter;
23
+ }
@@ -0,0 +1,43 @@
1
+ import { asc, eq, type InferInsertModel } from "drizzle-orm";
2
+ import { llmRequests } from "@/db/schema.mssql";
3
+ import type { DatabaseAdapter } from "@/adapters/database/index";
4
+ import type { MssqlDb } from "./client";
5
+
6
+ export function createLlmRequestsRepository(db: MssqlDb) {
7
+ return {
8
+ async insert(requests) {
9
+ if (!requests.length) return;
10
+
11
+ await db
12
+ .insert(llmRequests)
13
+ .values(
14
+ requests.map(
15
+ (r) =>
16
+ ({
17
+ messageId: r.messageId,
18
+ stepNumber: r.stepNumber,
19
+ prompt: r.prompt,
20
+ output: r.output,
21
+ tokenUsage: r.tokenUsage,
22
+ }) satisfies InferInsertModel<typeof llmRequests>,
23
+ ),
24
+ )
25
+ .execute();
26
+ },
27
+
28
+ /** Ordered by step so the inspector replays a turn in the order it ran. */
29
+ async listByMessageId(messageId) {
30
+ return await db
31
+ .select({
32
+ id: llmRequests.id,
33
+ prompt: llmRequests.prompt,
34
+ output: llmRequests.output,
35
+ tokenUsage: llmRequests.tokenUsage,
36
+ })
37
+ .from(llmRequests)
38
+ .where(eq(llmRequests.messageId, messageId))
39
+ .orderBy(asc(llmRequests.stepNumber))
40
+ .execute();
41
+ },
42
+ } satisfies DatabaseAdapter["llmRequests"];
43
+ }
@@ -0,0 +1,92 @@
1
+ // fallow-ignore-file duplicate-export -- mssql twin of the postgres repository, same factory name by design
2
+ import { and, desc, eq, getColumns, inArray, type InferInsertModel } from "drizzle-orm";
3
+ import { threads, messages } from "@/db/schema.mssql";
4
+ import type { ChatMessage } from "@/types";
5
+ import type { DatabaseAdapter } from "@/adapters/database/index";
6
+ import {
7
+ mergeStoredContent,
8
+ textOf,
9
+ withOwnedAttachments,
10
+ } from "@/adapters/database/message-content";
11
+ import type { MssqlDb } from "./client";
12
+
13
+ const DEFAULT_MESSAGE_LIMIT = 100;
14
+
15
+ export function createMessagesRepository(db: MssqlDb) {
16
+ return {
17
+ /**
18
+ * Fetches the newest N and reverses, so a limit keeps the most recent
19
+ * messages while callers still receive them oldest-first.
20
+ */
21
+ async list(userId, threadId, opts) {
22
+ return await db
23
+ .select(getColumns(messages))
24
+ .from(messages)
25
+ .innerJoin(threads, eq(threads.id, messages.threadId))
26
+ .where(and(eq(threads.userId, userId), eq(threads.id, threadId)))
27
+ .orderBy(desc(messages.createdAt), desc(messages.ordinal))
28
+ .offset(0)
29
+ .fetch(opts?.limit ?? DEFAULT_MESSAGE_LIMIT)
30
+ .then((x) => x.reverse());
31
+ },
32
+
33
+ /**
34
+ * Ids are client-generated, so a turn mixes new messages with edits to
35
+ * ones already stored. Splitting on existence lets the new ones go in as
36
+ * a single insert; the rest are updated individually.
37
+ */
38
+ async upsert(
39
+ threadId: string,
40
+ messagesToUpsert: ChatMessage[],
41
+ options?: { replaceAttachments?: boolean },
42
+ ) {
43
+ const incomingMessages = withOwnedAttachments(
44
+ messagesToUpsert,
45
+ options?.replaceAttachments,
46
+ );
47
+ const existingMessages = await db
48
+ .select({ id: messages.id, content: messages.content })
49
+ .from(messages)
50
+ .where(
51
+ inArray(
52
+ messages.id,
53
+ incomingMessages.map((x) => x.id),
54
+ ),
55
+ )
56
+ .execute();
57
+ const existingById = new Map(
58
+ existingMessages.map((message) => [message.id, message.content]),
59
+ );
60
+
61
+ const newMessages = incomingMessages.filter((x) => !existingById.has(x.id));
62
+ if (newMessages.length) {
63
+ await db
64
+ .insert(messages)
65
+ .values(
66
+ newMessages.map(
67
+ (x, ordinal) =>
68
+ ({
69
+ id: x.id,
70
+ role: x.role,
71
+ threadId,
72
+ content: x,
73
+ text: textOf(x),
74
+ ordinal,
75
+ }) satisfies InferInsertModel<typeof messages>,
76
+ ),
77
+ )
78
+ .execute();
79
+ }
80
+
81
+ for (const message of incomingMessages.filter((x) => existingById.has(x.id))) {
82
+ const content = mergeStoredContent(existingById.get(message.id)!, message);
83
+
84
+ await db
85
+ .update(messages)
86
+ .set({ content, text: textOf(content) })
87
+ .where(eq(messages.id, message.id))
88
+ .execute();
89
+ }
90
+ },
91
+ } satisfies DatabaseAdapter["messages"];
92
+ }
@@ -0,0 +1,83 @@
1
+ import { and, desc, eq } from "drizzle-orm";
2
+ import { attachments, threads } from "@/db/schema.mssql";
3
+ import type { Thread } from "@/types";
4
+ import type { ThreadContextMeta } from "@/ai/context/types";
5
+ import type { DatabaseAdapter } from "@/adapters/database/index";
6
+ import type { MssqlDb } from "./client";
7
+ import type { StorageAdapter } from "@/adapters/storage/index";
8
+
9
+ export function createThreadsRepository(db: MssqlDb, storage?: StorageAdapter) {
10
+ return {
11
+ async list(userId, agentId) {
12
+ return await db
13
+ .select()
14
+ .from(threads)
15
+ .where(and(eq(threads.userId, userId), eq(threads.agentId, agentId)))
16
+ .orderBy(desc(threads.updatedAt), desc(threads.createdAt));
17
+ },
18
+
19
+ async getById(userId, threadId) {
20
+ const result = await db
21
+ .select()
22
+ .top(1)
23
+ .from(threads)
24
+ .where(and(eq(threads.id, threadId), eq(threads.userId, userId)))
25
+ .execute();
26
+ return result.length ? (result[0] as Thread) : null;
27
+ },
28
+
29
+ async create(userId, agentId) {
30
+ const result = await db.insert(threads).output().values({ userId, agentId }).execute();
31
+ return result[0] as Thread;
32
+ },
33
+
34
+ /** Object storage has no foreign keys, so attachment paths must be swept before row cascade. */
35
+ async delete(userId, threadId) {
36
+ const attachmentPaths = await db
37
+ .select({ storageKey: attachments.storageKey })
38
+ .from(attachments)
39
+ .where(and(eq(attachments.threadId, threadId), eq(attachments.userId, userId)))
40
+ .execute()
41
+ .then((rows) => rows.map((row) => row.storageKey));
42
+
43
+ if (storage && attachmentPaths.length) {
44
+ await storage.delete(attachmentPaths);
45
+ }
46
+
47
+ // Avoid SQL Server error 547 from the NO ACTION attachments.message_id constraint.
48
+ await db.delete(attachments).where(eq(attachments.threadId, threadId)).execute();
49
+
50
+ await db
51
+ .delete(threads)
52
+ .where(and(eq(threads.id, threadId), eq(threads.userId, userId)))
53
+ .execute();
54
+ },
55
+
56
+ async touch(threadId) {
57
+ const result = await db
58
+ .update(threads)
59
+ .set({ updatedAt: new Date() })
60
+ .where(eq(threads.id, threadId))
61
+ .output()
62
+ .execute();
63
+
64
+ return result[0] as Thread;
65
+ },
66
+
67
+ async updateTitle(threadId, title) {
68
+ await db.update(threads).set({ title }).where(eq(threads.id, threadId)).execute();
69
+ },
70
+
71
+ async updateSession(threadId, session) {
72
+ await db.update(threads).set({ session }).where(eq(threads.id, threadId)).execute();
73
+ },
74
+
75
+ async updateContextMeta(threadId, meta: ThreadContextMeta) {
76
+ await db
77
+ .update(threads)
78
+ .set({ contextMeta: meta })
79
+ .where(eq(threads.id, threadId))
80
+ .execute();
81
+ },
82
+ } satisfies DatabaseAdapter["threads"];
83
+ }