@m6d/cortex-server 1.8.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (352) 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/runtime.ts +208 -0
  10. package/contracts/wire.ts +143 -0
  11. package/dist/contracts/graph/embed.d.ts +22 -0
  12. package/dist/{src/lib → contracts}/graph/helpers.d.ts +16 -14
  13. package/dist/{src/lib → contracts}/graph/neo4j.d.ts +5 -5
  14. package/dist/contracts/graph/schema.d.ts +62 -0
  15. package/dist/{src/lib → contracts}/graph/types.d.ts +1 -1
  16. package/dist/contracts/graph.d.ts +14 -0
  17. package/dist/contracts/runtime.d.ts +278 -0
  18. package/dist/contracts/wire.d.ts +120 -0
  19. package/dist/src/lib/adapters/database/index.d.ts +61 -0
  20. package/dist/src/lib/adapters/database/message-content.d.ts +30 -0
  21. package/dist/src/lib/adapters/database/mssql/attachments.d.ts +100 -0
  22. package/dist/src/lib/adapters/database/mssql/client.d.ts +8 -0
  23. package/dist/src/lib/adapters/database/mssql/index.d.ts +194 -0
  24. package/dist/src/lib/adapters/database/mssql/llm-requests.d.ts +17 -0
  25. package/dist/src/lib/adapters/database/mssql/messages.d.ts +37 -0
  26. package/dist/src/lib/adapters/database/mssql/threads.d.ts +50 -0
  27. package/dist/src/lib/adapters/database/postgres/attachments.d.ts +113 -0
  28. package/dist/src/lib/adapters/database/postgres/client.d.ts +8 -0
  29. package/dist/src/lib/adapters/database/postgres/index.d.ts +207 -0
  30. package/dist/src/lib/adapters/database/postgres/llm-requests.d.ts +17 -0
  31. package/dist/src/lib/adapters/database/postgres/messages.d.ts +37 -0
  32. package/dist/src/lib/adapters/database/postgres/threads.d.ts +50 -0
  33. package/{src/lib/adapters/storage.ts → dist/src/lib/adapters/storage/index.d.ts} +1 -1
  34. package/dist/src/lib/adapters/{minio.d.ts → storage/minio.d.ts} +1 -1
  35. package/dist/src/lib/ai/active-runs.d.ts +63 -0
  36. package/dist/src/lib/ai/attachments.d.ts +30 -0
  37. package/dist/src/lib/ai/backend-url.d.ts +16 -0
  38. package/dist/src/lib/ai/cc-runtime.d.ts +61 -0
  39. package/dist/src/lib/ai/commit-gate.d.ts +21 -0
  40. package/dist/src/lib/ai/context/builder.d.ts +6 -7
  41. package/dist/src/lib/ai/context/compression-middleware.d.ts +15 -0
  42. package/dist/src/lib/ai/context/compressor.d.ts +2 -13
  43. package/dist/src/lib/ai/context/intra-turn-compressor.d.ts +9 -9
  44. package/dist/src/lib/ai/context/optimize-thread-context.d.ts +9 -0
  45. package/dist/src/lib/ai/context/summarizer.d.ts +3 -3
  46. package/dist/src/lib/ai/context/token-estimator.d.ts +5 -8
  47. package/dist/src/lib/ai/fetch.d.ts +1 -1
  48. package/dist/src/lib/ai/finish-turn.d.ts +23 -0
  49. package/dist/src/lib/ai/helpers.d.ts +37 -4
  50. package/dist/src/lib/ai/index.d.ts +6 -3
  51. package/dist/src/lib/ai/inspector.d.ts +41 -0
  52. package/dist/src/lib/ai/interceptors/request-interceptor.d.ts +6 -5
  53. package/dist/src/lib/ai/prompt.d.ts +5 -4
  54. package/dist/src/lib/ai/redis-runs.d.ts +41 -0
  55. package/dist/src/lib/ai/redis-stream-log.d.ts +39 -0
  56. package/dist/src/lib/ai/tools/execute-code.tool.d.ts +18 -4
  57. package/dist/src/lib/ai/tools/query-graph.tool.d.ts +13 -5
  58. package/dist/src/lib/ai/tools/read-attachment.tool.d.ts +21 -0
  59. package/dist/src/lib/ai/tools/search-common.d.ts +17 -0
  60. package/dist/src/lib/ai/tools/search-knowledge.tool.d.ts +15 -0
  61. package/dist/src/lib/ai/tools/search-services.tool.d.ts +12 -0
  62. package/dist/src/lib/ai/tools/search-tools.tool.d.ts +12 -0
  63. package/dist/src/lib/ai/turn-tools.d.ts +39 -0
  64. package/dist/src/lib/ai/vision/rasterize-pdf.d.ts +26 -0
  65. package/dist/src/lib/ai/vision/rasterize-pdf.worker.d.ts +1 -0
  66. package/dist/src/lib/ai/vision/vision-reader.d.ts +45 -0
  67. package/dist/src/lib/cc/client.d.ts +183 -0
  68. package/dist/src/lib/cc/config-cache.d.ts +20 -0
  69. package/dist/src/lib/cc/format.d.ts +23 -0
  70. package/dist/src/lib/cc/registry.d.ts +34 -0
  71. package/dist/src/lib/cc/types.d.ts +27 -0
  72. package/dist/src/lib/config.d.ts +81 -64
  73. package/dist/src/lib/db/drizzle.config.mssql.d.ts +2 -0
  74. package/dist/src/lib/db/drizzle.config.pg.d.ts +2 -0
  75. package/dist/src/lib/db/migrate.d.ts +7 -1
  76. package/dist/src/lib/db/{schema.d.ts → schema.mssql.d.ts} +138 -29
  77. package/dist/src/lib/db/schema.pg.d.ts +546 -0
  78. package/dist/src/lib/factory.d.ts +2 -12
  79. package/dist/src/lib/graph/index.d.ts +10 -11
  80. package/dist/src/lib/graph/resolver.d.ts +2 -3
  81. package/dist/src/lib/index.d.ts +3 -3
  82. package/dist/src/lib/redis.d.ts +19 -0
  83. package/dist/src/lib/routes/chat.d.ts +1 -1
  84. package/dist/src/lib/routes/files.d.ts +1 -1
  85. package/dist/src/lib/routes/owned-thread.d.ts +17 -0
  86. package/dist/src/lib/routes/threads.d.ts +1 -1
  87. package/dist/src/lib/routes/ws.d.ts +1 -1
  88. package/dist/src/lib/types.d.ts +20 -37
  89. package/dist/src/lib/ws/connections.d.ts +2 -1
  90. package/package.json +33 -18
  91. package/src/lib/adapters/database/index.ts +78 -0
  92. package/src/lib/adapters/database/message-content.ts +39 -0
  93. package/src/lib/adapters/database/mssql/attachments.ts +90 -0
  94. package/src/lib/adapters/database/mssql/client.ts +11 -0
  95. package/src/lib/adapters/database/mssql/index.ts +23 -0
  96. package/src/lib/adapters/database/mssql/llm-requests.ts +43 -0
  97. package/src/lib/adapters/database/mssql/messages.ts +92 -0
  98. package/src/lib/adapters/database/mssql/threads.ts +83 -0
  99. package/src/lib/adapters/database/postgres/attachments.ts +88 -0
  100. package/src/lib/adapters/database/postgres/client.ts +11 -0
  101. package/src/lib/adapters/database/postgres/index.ts +23 -0
  102. package/src/lib/adapters/database/postgres/llm-requests.ts +45 -0
  103. package/src/lib/adapters/database/postgres/messages.ts +92 -0
  104. package/src/lib/adapters/database/postgres/threads.ts +84 -0
  105. package/{dist/src/lib/adapters/storage.d.ts → src/lib/adapters/storage/index.ts} +1 -1
  106. package/src/lib/adapters/{minio.ts → storage/minio.ts} +5 -5
  107. package/src/lib/ai/active-runs.ts +157 -0
  108. package/src/lib/ai/attachments.ts +144 -0
  109. package/src/lib/ai/backend-url.ts +27 -0
  110. package/src/lib/ai/cc-runtime.ts +63 -0
  111. package/src/lib/ai/commit-gate.ts +116 -0
  112. package/src/lib/ai/context/builder.ts +12 -14
  113. package/src/lib/ai/context/compression-middleware.ts +44 -0
  114. package/src/lib/ai/context/compressor.ts +67 -59
  115. package/src/lib/ai/context/intra-turn-compressor.ts +121 -204
  116. package/src/lib/ai/context/optimize-thread-context.ts +50 -0
  117. package/src/lib/ai/context/summarizer.ts +28 -30
  118. package/src/lib/ai/context/token-estimator.ts +35 -30
  119. package/src/lib/ai/fetch.ts +10 -5
  120. package/src/lib/ai/finish-turn.ts +75 -0
  121. package/src/lib/ai/helpers.ts +83 -15
  122. package/src/lib/ai/index.ts +359 -329
  123. package/src/lib/ai/inspector.ts +112 -0
  124. package/src/lib/ai/interceptors/request-interceptor.ts +70 -42
  125. package/src/lib/ai/prompt.ts +126 -125
  126. package/src/lib/ai/redis-runs.ts +167 -0
  127. package/src/lib/ai/redis-stream-log.ts +219 -0
  128. package/src/lib/ai/tools/execute-code.tool.ts +178 -67
  129. package/src/lib/ai/tools/query-graph.tool.ts +7 -8
  130. package/src/lib/ai/tools/read-attachment.tool.ts +59 -0
  131. package/src/lib/ai/tools/search-common.ts +15 -0
  132. package/src/lib/ai/tools/search-knowledge.tool.ts +33 -0
  133. package/src/lib/ai/tools/search-services.tool.ts +31 -0
  134. package/src/lib/ai/tools/search-tools.tool.ts +29 -0
  135. package/src/lib/ai/turn-tools.ts +154 -0
  136. package/src/lib/ai/vision/rasterize-pdf.ts +69 -0
  137. package/src/lib/ai/vision/rasterize-pdf.worker.ts +81 -0
  138. package/src/lib/ai/vision/vision-reader.ts +130 -0
  139. package/src/lib/auth/middleware.ts +5 -3
  140. package/src/lib/cc/client.ts +273 -0
  141. package/src/lib/cc/config-cache.ts +32 -0
  142. package/src/lib/cc/format.ts +96 -0
  143. package/src/lib/cc/registry.ts +62 -0
  144. package/src/lib/cc/types.ts +44 -0
  145. package/src/lib/config.ts +102 -71
  146. package/src/lib/db/drizzle.config.mssql.ts +9 -0
  147. package/src/lib/db/drizzle.config.pg.ts +9 -0
  148. package/src/lib/db/migrate.ts +45 -10
  149. package/src/lib/db/migrations/mssql/20260729092726_talented_wilson_fisk/migration.sql +20 -0
  150. package/src/lib/db/migrations/mssql/20260729092726_talented_wilson_fisk/snapshot.json +497 -0
  151. package/src/lib/db/migrations/mssql/20260801003652_perpetual_blue_shield/migration.sql +1 -0
  152. package/src/lib/db/migrations/mssql/20260801003652_perpetual_blue_shield/snapshot.json +516 -0
  153. package/src/lib/db/migrations/mssql/20260812174642_user_id_text/migration.sql +2 -0
  154. package/src/lib/db/migrations/mssql/20260812174642_user_id_text/snapshot.json +516 -0
  155. package/src/lib/db/migrations/pg/20260801084117_thick_ben_grimm/migration.sql +53 -0
  156. package/src/lib/db/migrations/pg/20260801084117_thick_ben_grimm/snapshot.json +584 -0
  157. package/src/lib/db/migrations/pg/20260812174622_user_id_text/migration.sql +2 -0
  158. package/src/lib/db/migrations/pg/20260812174622_user_id_text/snapshot.json +584 -0
  159. package/src/lib/db/{schema.ts → schema.mssql.ts} +29 -18
  160. package/src/lib/db/schema.pg.ts +95 -0
  161. package/src/lib/factory.ts +44 -89
  162. package/src/lib/graph/index.ts +12 -40
  163. package/src/lib/graph/resolver.ts +146 -116
  164. package/src/lib/index.ts +11 -4
  165. package/src/lib/redis.ts +44 -0
  166. package/src/lib/routes/chat.ts +91 -62
  167. package/src/lib/routes/files.ts +105 -83
  168. package/src/lib/routes/owned-thread.ts +17 -0
  169. package/src/lib/routes/threads.ts +14 -30
  170. package/src/lib/routes/ws.ts +9 -3
  171. package/src/lib/types.ts +37 -36
  172. package/src/lib/ws/connections.ts +9 -1
  173. package/tsconfig.json +48 -0
  174. package/dist/src/lib/adapters/database.d.ts +0 -45
  175. package/dist/src/lib/adapters/mssql.d.ts +0 -3
  176. package/dist/src/lib/ai/active-streams.d.ts +0 -14
  177. package/dist/src/lib/ai/context/index.d.ts +0 -16
  178. package/dist/src/lib/ai/tools/capture-files.tool.d.ts +0 -6
  179. package/dist/src/lib/cli/extract-endpoints.d.ts +0 -6
  180. package/dist/src/lib/graph/expand-domains.d.ts +0 -2
  181. package/dist/src/lib/graph/generate-cypher.d.ts +0 -22
  182. package/dist/src/lib/graph/seed.d.ts +0 -19
  183. package/dist/src/lib/graph/validate.d.ts +0 -2
  184. package/dist/src/lib/routes/index.d.ts +0 -4
  185. package/dist/src/lib/ws/events.d.ts +0 -39
  186. package/dist/src/lib/ws/index.d.ts +0 -3
  187. package/dist/src/lib/ws/notify.d.ts +0 -2
  188. package/src/lib/adapters/database.ts +0 -48
  189. package/src/lib/adapters/mssql.ts +0 -231
  190. package/src/lib/ai/active-streams.ts +0 -123
  191. package/src/lib/ai/context/index.ts +0 -80
  192. package/src/lib/ai/tools/capture-files.tool.ts +0 -20
  193. package/src/lib/cli/extract-endpoints.ts +0 -550
  194. package/src/lib/graph/expand-domains.ts +0 -276
  195. package/src/lib/graph/generate-cypher.ts +0 -192
  196. package/src/lib/graph/seed.ts +0 -162
  197. package/src/lib/graph/validate.ts +0 -78
  198. package/src/lib/routes/index.ts +0 -4
  199. package/src/lib/ws/events.ts +0 -39
  200. package/src/lib/ws/index.ts +0 -11
  201. package/src/lib/ws/notify.ts +0 -9
  202. package/src/sample/db/client.ts +0 -9
  203. package/src/sample/db/migrations/20260411023125_rich_purple_man/migration.sql +0 -5
  204. package/src/sample/db/migrations/20260411023125_rich_purple_man/snapshot.json +0 -50
  205. package/src/sample/db/schema.ts +0 -10
  206. package/src/sample/domains/account/concepts/session.concept.ts +0 -17
  207. package/src/sample/domains/account/endpoints/listCurrentSessions.endpoint.ts +0 -31
  208. package/src/sample/domains/account/endpoints/revokeAllOtherSessions.endpoint.ts +0 -22
  209. package/src/sample/domains/account/endpoints/revokeCurrentSession.endpoint.ts +0 -33
  210. package/src/sample/domains/account/index.ts +0 -18
  211. package/src/sample/domains/appraisals/concepts/appraisalCycle.concept.ts +0 -15
  212. package/src/sample/domains/appraisals/concepts/appraisalRecord.concept.ts +0 -20
  213. package/src/sample/domains/appraisals/concepts/appraisalRecordCompetency.concept.ts +0 -10
  214. package/src/sample/domains/appraisals/concepts/appraisalRecordFunctionalRequirement.concept.ts +0 -10
  215. package/src/sample/domains/appraisals/concepts/appraisalRecordGoal.concept.ts +0 -17
  216. package/src/sample/domains/appraisals/endpoints/getAppraisalRecordById.endpoint.ts +0 -321
  217. package/src/sample/domains/appraisals/endpoints/getAppraisalRecordCompetencies.endpoint.ts +0 -120
  218. package/src/sample/domains/appraisals/endpoints/getAppraisalRecordFunctionalRequirements.endpoint.ts +0 -126
  219. package/src/sample/domains/appraisals/endpoints/getAppraisalRecordGoals.endpoint.ts +0 -104
  220. package/src/sample/domains/appraisals/endpoints/getAppraisalRecordScore.endpoint.ts +0 -58
  221. package/src/sample/domains/appraisals/endpoints/listAppraisalCyclesSimple.endpoint.ts +0 -52
  222. package/src/sample/domains/appraisals/endpoints/listAppraisalRecords.endpoint.ts +0 -245
  223. package/src/sample/domains/appraisals/endpoints/listAppraisalTemplatesSimple.endpoint.ts +0 -52
  224. package/src/sample/domains/appraisals/index.ts +0 -40
  225. package/src/sample/domains/appraisals/rules/appraisalRecordScoping.rule.ts +0 -7
  226. package/src/sample/domains/attendance/concepts/attendancePermission.concept.ts +0 -17
  227. package/src/sample/domains/attendance/concepts/attendanceTransaction.concept.ts +0 -17
  228. package/src/sample/domains/attendance/concepts/publicHoliday.concept.ts +0 -10
  229. package/src/sample/domains/attendance/concepts/punch.concept.ts +0 -19
  230. package/src/sample/domains/attendance/endpoints/getAttendanceTransactionById.endpoint.ts +0 -444
  231. package/src/sample/domains/attendance/endpoints/getCurrentAttendanceProfile.endpoint.ts +0 -886
  232. package/src/sample/domains/attendance/endpoints/getCurrentAttendanceStatistics.endpoint.ts +0 -49
  233. package/src/sample/domains/attendance/endpoints/listAttendancePermissions.endpoint.ts +0 -176
  234. package/src/sample/domains/attendance/endpoints/listAttendanceTransactionStates.endpoint.ts +0 -26
  235. package/src/sample/domains/attendance/endpoints/listAttendanceTransactions.endpoint.ts +0 -373
  236. package/src/sample/domains/attendance/endpoints/listPublicHolidaysSimple.endpoint.ts +0 -52
  237. package/src/sample/domains/attendance/endpoints/listPunchTypes.endpoint.ts +0 -25
  238. package/src/sample/domains/attendance/endpoints/listPunches.endpoint.ts +0 -178
  239. package/src/sample/domains/attendance/index.ts +0 -41
  240. package/src/sample/domains/attendance/services/attendancePermissions.service.ts +0 -15
  241. package/src/sample/domains/employees/concepts/employee.concept.ts +0 -20
  242. package/src/sample/domains/employees/concepts/employeeBankAccount.concept.ts +0 -19
  243. package/src/sample/domains/employees/concepts/employeeChild.concept.ts +0 -19
  244. package/src/sample/domains/employees/concepts/employeeDocument.concept.ts +0 -21
  245. package/src/sample/domains/employees/concepts/employeeEvent.concept.ts +0 -21
  246. package/src/sample/domains/employees/concepts/employeeExperience.concept.ts +0 -18
  247. package/src/sample/domains/employees/concepts/employeeJobLevelChange.concept.ts +0 -21
  248. package/src/sample/domains/employees/concepts/employeeMedal.concept.ts +0 -20
  249. package/src/sample/domains/employees/concepts/employeeQualification.concept.ts +0 -20
  250. package/src/sample/domains/employees/concepts/employeeSpouse.concept.ts +0 -21
  251. package/src/sample/domains/employees/concepts/employeeViolation.concept.ts +0 -19
  252. package/src/sample/domains/employees/endpoints/getCurrentEmployee.endpoint.ts +0 -1651
  253. package/src/sample/domains/employees/endpoints/getCurrentIdentity.endpoint.ts +0 -197
  254. package/src/sample/domains/employees/endpoints/getCurrentManagers.endpoint.ts +0 -142
  255. package/src/sample/domains/employees/endpoints/getEmployeeById.endpoint.ts +0 -1659
  256. package/src/sample/domains/employees/endpoints/getEmployeeStatistics.endpoint.ts +0 -43
  257. package/src/sample/domains/employees/endpoints/listBankAccounts.endpoint.ts +0 -223
  258. package/src/sample/domains/employees/endpoints/listChildren.endpoint.ts +0 -211
  259. package/src/sample/domains/employees/endpoints/listDocuments.endpoint.ts +0 -222
  260. package/src/sample/domains/employees/endpoints/listEmployeesSimple.endpoint.ts +0 -156
  261. package/src/sample/domains/employees/endpoints/listEvents.endpoint.ts +0 -120
  262. package/src/sample/domains/employees/endpoints/listExperiences.endpoint.ts +0 -188
  263. package/src/sample/domains/employees/endpoints/listJobLevelChanges.endpoint.ts +0 -240
  264. package/src/sample/domains/employees/endpoints/listMedals.endpoint.ts +0 -266
  265. package/src/sample/domains/employees/endpoints/listQualifications.endpoint.ts +0 -265
  266. package/src/sample/domains/employees/endpoints/listSpouses.endpoint.ts +0 -278
  267. package/src/sample/domains/employees/endpoints/listViolations.endpoint.ts +0 -245
  268. package/src/sample/domains/employees/index.ts +0 -75
  269. package/src/sample/domains/employees/services/employees.service.ts +0 -181
  270. package/src/sample/domains/index.ts +0 -10
  271. package/src/sample/domains/leaves/concepts/leave.concept.ts +0 -21
  272. package/src/sample/domains/leaves/concepts/leaveBalance.concept.ts +0 -17
  273. package/src/sample/domains/leaves/concepts/leaveBalanceTransaction.concept.ts +0 -16
  274. package/src/sample/domains/leaves/concepts/leaveType.concept.ts +0 -13
  275. package/src/sample/domains/leaves/concepts/leaveTypes.concept.ts +0 -205
  276. package/src/sample/domains/leaves/endpoints/getBalance.endpoint.ts +0 -53
  277. package/src/sample/domains/leaves/endpoints/getLeaveById.endpoint.ts +0 -53
  278. package/src/sample/domains/leaves/endpoints/listBalanceTransactions.endpoint.ts +0 -196
  279. package/src/sample/domains/leaves/endpoints/listBalanceTypes.endpoint.ts +0 -26
  280. package/src/sample/domains/leaves/endpoints/listBalances.endpoint.ts +0 -201
  281. package/src/sample/domains/leaves/endpoints/listLeaveTypes.endpoint.ts +0 -28
  282. package/src/sample/domains/leaves/endpoints/listLeaves.endpoint.ts +0 -234
  283. package/src/sample/domains/leaves/index.ts +0 -38
  284. package/src/sample/domains/leaves/services/leaveRequests.service.ts +0 -232
  285. package/src/sample/domains/notifications/concepts/notification.concept.ts +0 -19
  286. package/src/sample/domains/notifications/endpoints/countMyNotifications.endpoint.ts +0 -21
  287. package/src/sample/domains/notifications/endpoints/getMyNotification.endpoint.ts +0 -57
  288. package/src/sample/domains/notifications/endpoints/listMyNotifications.endpoint.ts +0 -59
  289. package/src/sample/domains/notifications/endpoints/markMyNotificationAsRead.endpoint.ts +0 -32
  290. package/src/sample/domains/notifications/index.ts +0 -20
  291. package/src/sample/domains/payroll/concepts/payslip.concept.ts +0 -18
  292. package/src/sample/domains/payroll/concepts/salaryCertificate.concept.ts +0 -17
  293. package/src/sample/domains/payroll/concepts/salaryCertificateRequestingEntity.concept.ts +0 -8
  294. package/src/sample/domains/payroll/endpoints/getPayslipById.endpoint.ts +0 -238
  295. package/src/sample/domains/payroll/endpoints/listPayslips.endpoint.ts +0 -216
  296. package/src/sample/domains/payroll/endpoints/listSalaryCertificateLanguages.endpoint.ts +0 -25
  297. package/src/sample/domains/payroll/endpoints/listSalaryCertificateRequestingEntities.endpoint.ts +0 -62
  298. package/src/sample/domains/payroll/endpoints/listSalaryCertificateTypes.endpoint.ts +0 -24
  299. package/src/sample/domains/payroll/endpoints/listSalaryCertificates.endpoint.ts +0 -122
  300. package/src/sample/domains/payroll/endpoints/previewSalaryCertificate.endpoint.ts +0 -45
  301. package/src/sample/domains/payroll/index.ts +0 -32
  302. package/src/sample/domains/payroll/rules/payrollEmployeeContext.rule.ts +0 -7
  303. package/src/sample/domains/payroll/services/salaryCertificates.service.ts +0 -15
  304. package/src/sample/domains/servicing/concepts/service.concept.ts +0 -6
  305. package/src/sample/domains/servicing/concepts/serviceRequest.concept.ts +0 -12
  306. package/src/sample/domains/servicing/concepts/serviceRequestApproval.concept.ts +0 -9
  307. package/src/sample/domains/servicing/endpoints/cancelServiceRequest.endpoint.ts +0 -21
  308. package/src/sample/domains/servicing/endpoints/createServiceRequest.endpoint.ts +0 -511
  309. package/src/sample/domains/servicing/endpoints/getServiceRequest.endpoint.ts +0 -352
  310. package/src/sample/domains/servicing/endpoints/getServiceRequestFormItems.endpoint.ts +0 -219
  311. package/src/sample/domains/servicing/endpoints/getServiceRequestTransactionFormItems.endpoint.ts +0 -216
  312. package/src/sample/domains/servicing/endpoints/getServiceStates.endpoint.ts +0 -47
  313. package/src/sample/domains/servicing/endpoints/invokeServiceRequestAction.endpoint.ts +0 -139
  314. package/src/sample/domains/servicing/endpoints/listServiceRequests.endpoint.ts +0 -292
  315. package/src/sample/domains/servicing/endpoints/listServices.endpoint.ts +0 -108
  316. package/src/sample/domains/servicing/endpoints/updateServiceRequest.endpoint.ts +0 -355
  317. package/src/sample/domains/servicing/index.ts +0 -44
  318. package/src/sample/domains/servicing/rules/checkValidActions.rule.ts +0 -7
  319. package/src/sample/domains/servicing/rules/createServiceRequest.rule.ts +0 -7
  320. package/src/sample/domains/servicing/rules/filterServiceRequestsByState.rule.ts +0 -7
  321. package/src/sample/domains/servicing/rules/passingOptionFields.rule.ts +0 -7
  322. package/src/sample/domains/shared/rules/pagination.rule.ts +0 -7
  323. package/src/sample/domains/suggestions/concepts/suggestion.concept.ts +0 -19
  324. package/src/sample/domains/suggestions/concepts/suggestionCategory.concept.ts +0 -7
  325. package/src/sample/domains/suggestions/concepts/suggestionImpactLevel.concept.ts +0 -7
  326. package/src/sample/domains/suggestions/endpoints/createSuggestion.endpoint.ts +0 -705
  327. package/src/sample/domains/suggestions/endpoints/deleteSuggestion.endpoint.ts +0 -32
  328. package/src/sample/domains/suggestions/endpoints/getSuggestionById.endpoint.ts +0 -635
  329. package/src/sample/domains/suggestions/endpoints/listSuggestionCategories.endpoint.ts +0 -62
  330. package/src/sample/domains/suggestions/endpoints/listSuggestionImpactLevels.endpoint.ts +0 -62
  331. package/src/sample/domains/suggestions/endpoints/listSuggestionStates.endpoint.ts +0 -24
  332. package/src/sample/domains/suggestions/endpoints/listSuggestions.endpoint.ts +0 -132
  333. package/src/sample/domains/suggestions/endpoints/updateSuggestion.endpoint.ts +0 -690
  334. package/src/sample/domains/suggestions/endpoints/updateSuggestionState.endpoint.ts +0 -39
  335. package/src/sample/domains/suggestions/index.ts +0 -34
  336. package/src/sample/domains/suggestions/rules/suggestionScope.rule.ts +0 -7
  337. package/src/sample/domains/surveys/concepts/survey.concept.ts +0 -10
  338. package/src/sample/domains/surveys/concepts/surveyResponse.concept.ts +0 -14
  339. package/src/sample/domains/surveys/endpoints/getSurveyResponseById.endpoint.ts +0 -131
  340. package/src/sample/domains/surveys/endpoints/getTargetedSurvey.endpoint.ts +0 -129
  341. package/src/sample/domains/surveys/endpoints/listTargetedSurveys.endpoint.ts +0 -160
  342. package/src/sample/domains/surveys/endpoints/respondToSurvey.endpoint.ts +0 -144
  343. package/src/sample/domains/surveys/index.ts +0 -21
  344. package/src/sample/drizzle.config.ts +0 -11
  345. package/src/sample/index.bak.ts +0 -341
  346. package/src/sample/index.ts +0 -318
  347. package/src/sample/official-statements/defaults.ts +0 -57
  348. package/src/sample/official-statements/routes.ts +0 -137
  349. package/src/sample/official-statements/service.ts +0 -148
  350. package/src/sample/official-statements/types.ts +0 -23
  351. /package/src/lib/db/migrations/{20260326231647_nice_speedball → mssql/20260326231647_nice_speedball}/migration.sql +0 -0
  352. /package/src/lib/db/migrations/{20260326231647_nice_speedball → mssql/20260326231647_nice_speedball}/snapshot.json +0 -0
@@ -0,0 +1,112 @@
1
+ import type { ChatMiddleware, TokenUsage as ProviderTokenUsage } from "@tanstack/ai";
2
+ import type { TokenUsage } from "@/types";
3
+
4
+ /** One model call's raw exchange, as the LLM request inspector renders it. */
5
+ export type CapturedStep = {
6
+ prompt: string;
7
+ output: string | null;
8
+ tokenUsage: TokenUsage | null;
9
+ };
10
+
11
+ /**
12
+ * Watches one turn's model calls. The SDK's `debug` logger reports call metadata
13
+ * but never raw bodies, so the raw exchange is captured where it actually
14
+ * exists — on the HTTP client — while usage arrives through middleware.
15
+ */
16
+ export function createInspector() {
17
+ const steps: CapturedStep[] = [];
18
+ let modelId = "";
19
+ let tokenUsage: TokenUsage | undefined;
20
+
21
+ async function capturingFetch(input: string | URL | Request, init?: RequestInit) {
22
+ const step: CapturedStep = {
23
+ prompt: typeof init?.body === "string" ? init.body : "",
24
+ output: null,
25
+ tokenUsage: null,
26
+ };
27
+ steps.push(step);
28
+
29
+ const response = await fetch(input, init);
30
+ // Drain a tee rather than the response itself: the model call must keep
31
+ // streaming at full speed, and losing debug data must never fail a turn.
32
+ void response
33
+ .clone()
34
+ .text()
35
+ .then(function (text) {
36
+ step.output = text;
37
+ })
38
+ .catch(() => undefined);
39
+
40
+ return response;
41
+ }
42
+
43
+ const middleware: ChatMiddleware = {
44
+ name: "cortex-inspector",
45
+ onUsage(ctx, usage) {
46
+ modelId = ctx.model;
47
+ const stepUsage = toTokenUsage(usage);
48
+ const lastStep = steps.at(-1);
49
+ if (lastStep) lastStep.tokenUsage = stepUsage;
50
+ tokenUsage = addTokenUsage(tokenUsage, stepUsage);
51
+ },
52
+ };
53
+
54
+ return {
55
+ steps,
56
+ middleware,
57
+ // Bun's fetch type carries preconnect; delegate so the client accepts the shim.
58
+ fetch: Object.assign(capturingFetch, { preconnect: fetch.preconnect }),
59
+ get modelId() {
60
+ return modelId;
61
+ },
62
+ get tokenUsage() {
63
+ return tokenUsage;
64
+ },
65
+ };
66
+ }
67
+
68
+ /**
69
+ * Flattens the provider's usage shape into ours. The provider reports cached and
70
+ * cache-written prompt tokens but no uncached counter, so that dimension is the
71
+ * remainder — which is what makes the client's breakdown add up to the total.
72
+ */
73
+ export function toTokenUsage(usage: ProviderTokenUsage) {
74
+ const cacheRead = usage.promptTokensDetails?.cachedTokens ?? 0;
75
+ const cacheWrite = usage.promptTokensDetails?.cacheWriteTokens ?? 0;
76
+ const reasoning = usage.completionTokensDetails?.reasoningTokens ?? 0;
77
+
78
+ return {
79
+ input: {
80
+ noCache: Math.max(usage.promptTokens - cacheRead - cacheWrite, 0),
81
+ cacheRead,
82
+ cacheWrite,
83
+ total: usage.promptTokens,
84
+ },
85
+ output: {
86
+ reasoning,
87
+ text: usage.completionTokensDetails?.textTokens ?? usage.completionTokens - reasoning,
88
+ total: usage.completionTokens,
89
+ },
90
+ total: usage.totalTokens,
91
+ } satisfies TokenUsage;
92
+ }
93
+
94
+ /** The agent loop reports usage per iteration; a turn's cost is their sum. */
95
+ function addTokenUsage(left: TokenUsage | undefined, right: TokenUsage) {
96
+ if (!left) return right;
97
+
98
+ return {
99
+ input: {
100
+ noCache: left.input.noCache + right.input.noCache,
101
+ cacheRead: left.input.cacheRead + right.input.cacheRead,
102
+ cacheWrite: left.input.cacheWrite + right.input.cacheWrite,
103
+ total: left.input.total + right.input.total,
104
+ },
105
+ output: {
106
+ reasoning: left.output.reasoning + right.output.reasoning,
107
+ text: left.output.text + right.output.text,
108
+ total: left.output.total + right.output.total,
109
+ },
110
+ total: left.total + right.total,
111
+ } satisfies TokenUsage;
112
+ }
@@ -1,6 +1,6 @@
1
- import type { DatabaseAdapter } from "../../adapters/database.ts";
2
- import type { StorageAdapter } from "../../adapters/storage.ts";
3
- import { streamToBase64, tokenToUserId } from "../helpers.ts";
1
+ import type { DatabaseAdapter } from "@/adapters/database/index";
2
+ import type { StorageAdapter } from "@/adapters/storage/index";
3
+ import { streamToBase64 } from "@/ai/helpers";
4
4
 
5
5
  export type ResolvedFile = {
6
6
  name: string;
@@ -14,48 +14,76 @@ export type RequestInterceptorOptions = {
14
14
  export function createRequestInterceptor(
15
15
  db: DatabaseAdapter,
16
16
  storage: StorageAdapter,
17
- options?: RequestInterceptorOptions,
17
+ options: RequestInterceptorOptions & { threadId: string; userId: string },
18
18
  ) {
19
- const transformFile = options?.transformFile ?? ((file: ResolvedFile) => file);
20
-
21
- return async function resolveRequestBody(
22
- body: Record<string, unknown>,
23
- context: { token: string },
24
- ) {
25
- const userId = tokenToUserId(context.token);
26
-
27
- async function traverse(obj: Record<string, unknown>) {
28
- await Promise.all(
29
- Object.keys(obj).map(async (key) => {
30
- const value = obj[key];
31
- if (typeof value === "string" && value.startsWith("capturedFile")) {
32
- const [_, uploadId] = value.split("#");
33
- const file = await db.capturedFiles.getById(uploadId!, userId);
34
- if (file) {
35
- const fileStream = await storage.stream(`captured_files/${uploadId}`);
36
- const bytes = await streamToBase64(fileStream);
37
- obj[key] = transformFile({ name: file.name, bytes });
38
- }
39
- }
40
-
41
- if (Array.isArray(value)) {
42
- await Promise.all(
43
- value.map(async (child) => {
44
- if (typeof child === "object" && child !== null) {
45
- await traverse(child as Record<string, unknown>);
46
- }
47
- }),
48
- );
49
- }
50
-
51
- if (typeof value === "object" && value !== null && !Array.isArray(value)) {
52
- await traverse(value as Record<string, unknown>);
53
- }
54
- }),
55
- );
19
+ const transformFile = options.transformFile ?? ((file: ResolvedFile) => file);
20
+
21
+ return async function resolveRequestBody(body: Record<string, unknown>) {
22
+ const resolvedAttachments = new Map<string, { value: unknown }>();
23
+ const pending = Object.entries(body).map(([key, value]) => ({
24
+ value,
25
+ replace: (resolved: unknown) => {
26
+ body[key] = resolved;
27
+ },
28
+ }));
29
+
30
+ async function resolveAttachment(id: string) {
31
+ const cached = resolvedAttachments.get(id);
32
+ if (cached) return cached;
33
+
34
+ const attachment = await db.attachments.getById(id, options.userId);
35
+ if (!attachment || attachment.threadId !== options.threadId) {
36
+ throw new Error(`Attachment "${id}" is not available in this thread`);
37
+ }
38
+
39
+ let bytes: string;
40
+ try {
41
+ bytes = await streamToBase64(await storage.stream(attachment.storageKey));
42
+ } catch (error) {
43
+ throw new Error(`Attachment "${id}" could not be loaded from storage`, {
44
+ cause: error,
45
+ });
46
+ }
47
+ const resolved = { value: transformFile({ name: attachment.filename, bytes }) };
48
+ resolvedAttachments.set(id, resolved);
49
+ return resolved;
50
+ }
51
+
52
+ while (pending.length) {
53
+ const { value, replace } = pending.pop()!;
54
+
55
+ if (Array.isArray(value)) {
56
+ const items: unknown[] = value;
57
+ pending.push(
58
+ ...items.map((child, index) => ({
59
+ value: child,
60
+ replace: (resolved: unknown) => {
61
+ items[index] = resolved;
62
+ },
63
+ })),
64
+ );
65
+ continue;
66
+ }
67
+
68
+ if (typeof value === "object" && value !== null) {
69
+ const object = value as Record<string, unknown>;
70
+ pending.push(
71
+ ...Object.entries(object).map(([key, child]) => ({
72
+ value: child,
73
+ replace: (resolved: unknown) => {
74
+ object[key] = resolved;
75
+ },
76
+ })),
77
+ );
78
+ continue;
79
+ }
80
+
81
+ if (typeof value !== "string" || !value.startsWith("attachment#")) continue;
82
+
83
+ const resolved = await resolveAttachment(value.slice("attachment#".length));
84
+ replace(resolved.value);
56
85
  }
57
86
 
58
- await traverse(body);
59
87
  return body;
60
88
  };
61
89
  }
@@ -1,6 +1,8 @@
1
- import type { ResolvedContext, ResolvedEndpoint, ResolvedService } from "../graph/resolver.ts";
2
- import type { PromptContext, ResolvedCortexAgentConfig } from "../config.ts";
3
- import type { Thread } from "../types.ts";
1
+ import type { ResolvedContext, ResolvedEndpoint, ResolvedService } from "@/graph/resolver";
2
+ import type { PromptContext, ResolvedCortexAgentConfig } from "@/config";
3
+ import type { Thread } from "@/types";
4
+ import type { CcPromptInput } from "@/cc/format";
5
+ import { buildCcSection } from "@/cc/format";
4
6
 
5
7
  /**
6
8
  * Resolves session data for the thread, loading from the configured
@@ -27,29 +29,37 @@ export async function buildSystemPrompt(
27
29
  config: ResolvedCortexAgentConfig,
28
30
  resolved: ResolvedContext | null,
29
31
  promptContext: PromptContext,
32
+ cc?: CcPromptInput,
33
+ attachmentListing?: string,
30
34
  ) {
31
35
  // Resolve the consumer's base system prompt
32
36
  let basePrompt: string;
33
37
  if (typeof config.systemPrompt === "function") {
34
38
  basePrompt = await config.systemPrompt(promptContext);
35
39
  } else {
36
- basePrompt = config.systemPrompt;
40
+ basePrompt = config.systemPrompt ?? "";
37
41
  }
38
42
 
39
- const sections: string[] = [basePrompt];
43
+ const sections: string[] = basePrompt ? [basePrompt] : [];
40
44
 
41
45
  // Pre-resolved endpoints from knowledge graph
42
46
  if (resolved) {
43
47
  sections.push(buildResolvedSection(resolved));
44
48
  }
45
49
 
50
+ // Control Center: published prompt + per-turn resolved catalog section
51
+ if (cc) {
52
+ const ccSection = buildCcSection(cc);
53
+ if (ccSection) sections.push(ccSection);
54
+ }
55
+
56
+ if (attachmentListing) {
57
+ sections.push(attachmentListing);
58
+ }
59
+
46
60
  return sections.join("\n");
47
61
  }
48
62
 
49
- // ---------------------------------------------------------------------------
50
- // Schema field type (parsed from endpoint JSON strings)
51
- // ---------------------------------------------------------------------------
52
-
53
63
  type SchemaField = {
54
64
  name: string;
55
65
  required?: boolean;
@@ -58,11 +68,7 @@ type SchemaField = {
58
68
  properties?: SchemaField[];
59
69
  };
60
70
 
61
- // ---------------------------------------------------------------------------
62
- // Layer 2: Schema compression
63
- // ---------------------------------------------------------------------------
64
-
65
- /** Compact param/body: `name?: type, nested?: {a: string, b: number}[]` */
71
+ /** Compression layer 2. Compact param/body: `name?: type, nested?: {a: string, b: number}[]` */
66
72
  function compactParamFields(fields: SchemaField[]): string {
67
73
  return fields
68
74
  .map((f) => {
@@ -109,14 +115,48 @@ function compactResponse(jsonStr: string) {
109
115
  }
110
116
  }
111
117
 
112
- // ---------------------------------------------------------------------------
113
- // Layer 1: Group endpoints by method + path
114
- // ---------------------------------------------------------------------------
115
-
118
+ /**
119
+ * Compression layer 1. Endpoints reached via several concepts arrive as
120
+ * duplicates sharing one method+path; collapsing them first means every later
121
+ * layer works on one entry per real endpoint.
122
+ */
116
123
  type GroupedEndpoint = Omit<ResolvedEndpoint, "concept"> & {
117
124
  concepts: string[];
118
125
  };
119
126
 
127
+ function addUnique<T>(list: T[], value: T, matches: (a: T, b: T) => boolean = Object.is) {
128
+ if (!list.some((item) => matches(item, value))) {
129
+ list.push(value);
130
+ }
131
+ }
132
+
133
+ /** Folds a second endpoint sharing this method and path into the group already collected. */
134
+ function mergeEndpoint(existing: GroupedEndpoint, ep: ResolvedEndpoint) {
135
+ addUnique(existing.concepts, ep.concept);
136
+
137
+ for (const rule of ep.rules) {
138
+ addUnique(existing.rules, rule);
139
+ }
140
+ for (const dep of ep.dependencies) {
141
+ addUnique(
142
+ existing.dependencies,
143
+ dep,
144
+ (a, b) => a.depPath === b.depPath && a.paramName === b.paramName,
145
+ );
146
+ }
147
+ }
148
+
149
+ /** The arrays are copied because merging mutates them, and the source endpoint is shared. */
150
+ function toGroup(ep: ResolvedEndpoint) {
151
+ const { concept, ...rest } = ep;
152
+ return {
153
+ ...rest,
154
+ concepts: [concept],
155
+ dependencies: [...ep.dependencies],
156
+ rules: [...ep.rules],
157
+ };
158
+ }
159
+
120
160
  function groupEndpointsBySignature(endpoints: ResolvedEndpoint[]) {
121
161
  const groups = new Map<string, GroupedEndpoint>();
122
162
 
@@ -125,46 +165,19 @@ function groupEndpointsBySignature(endpoints: ResolvedEndpoint[]) {
125
165
  const existing = groups.get(key);
126
166
 
127
167
  if (existing) {
128
- if (!existing.concepts.includes(ep.concept)) {
129
- existing.concepts.push(ep.concept);
130
- }
131
- for (const rule of ep.rules) {
132
- if (!existing.rules.includes(rule)) {
133
- existing.rules.push(rule);
134
- }
135
- }
136
- for (const dep of ep.dependencies) {
137
- const isDuplicate = existing.dependencies.some(
138
- (d) => d.depPath === dep.depPath && d.paramName === dep.paramName,
139
- );
140
- if (!isDuplicate) {
141
- existing.dependencies.push(dep);
142
- }
143
- }
168
+ mergeEndpoint(existing, ep);
144
169
  } else {
145
- groups.set(key, {
146
- concepts: [ep.concept],
147
- relation: ep.relation,
148
- name: ep.name,
149
- path: ep.path,
150
- method: ep.method,
151
- params: ep.params,
152
- body: ep.body,
153
- response: ep.response,
154
- dependencies: [...ep.dependencies],
155
- rules: [...ep.rules],
156
- metadata: ep.metadata,
157
- });
170
+ groups.set(key, toGroup(ep));
158
171
  }
159
172
  }
160
173
 
161
174
  return Array.from(groups.values());
162
175
  }
163
176
 
164
- // ---------------------------------------------------------------------------
165
- // Layer 3: Extract shared rules into a global section
166
- // ---------------------------------------------------------------------------
167
-
177
+ /**
178
+ * Compression layer 3. Hoists rules repeated across endpoints into one global
179
+ * section, so a rule governing twenty endpoints is stated once, not twenty times.
180
+ */
168
181
  function extractSharedRules(groups: GroupedEndpoint[], services: ResolvedService[]) {
169
182
  const ruleCounts = new Map<string, number>();
170
183
 
@@ -198,16 +211,16 @@ function extractSharedRules(groups: GroupedEndpoint[], services: ResolvedService
198
211
  };
199
212
  }
200
213
 
201
- // ---------------------------------------------------------------------------
202
- // Layer 4: Deduplicate identical response schemas across endpoints
203
- // ---------------------------------------------------------------------------
204
-
214
+ /**
215
+ * Compression layer 4. Endpoints returning an identical response schema get one
216
+ * named shape definition and a reference each, instead of repeating the schema.
217
+ */
205
218
  type ResponseShapeRefs = {
206
219
  shapeDefs: { name: string; content: string }[];
207
220
  refMap: Map<string, string>;
208
221
  };
209
222
 
210
- function buildResponseShapeRefs(groups: GroupedEndpoint[]): ResponseShapeRefs {
223
+ function buildResponseShapeRefs(groups: GroupedEndpoint[]) {
211
224
  // Key on the raw JSON string (byte-identical for endpoints sharing the same
212
225
  // Endpoint node in Neo4j). Fall back to the compact string for cases where
213
226
  // different raw JSON produces the same compact shape.
@@ -258,9 +271,50 @@ function buildResponseShapeRefs(groups: GroupedEndpoint[]): ResponseShapeRefs {
258
271
  return { shapeDefs, refMap };
259
272
  }
260
273
 
261
- // ---------------------------------------------------------------------------
262
- // Pre-resolved section builder
263
- // ---------------------------------------------------------------------------
274
+ /** A heading and its lines, or nothing at all when there are no lines to show. */
275
+ function renderSection(heading: string, lines: string[]) {
276
+ if (lines.length === 0) return [];
277
+ return [`\n### ${heading}`, ...lines.map((line) => `\n${line}`)];
278
+ }
279
+
280
+ function renderEndpoint(ep: GroupedEndpoint, refMap: ResponseShapeRefs["refMap"]) {
281
+ const compactResp = compactResponse(ep.response);
282
+ const body = compactParams(ep.body);
283
+
284
+ const lines = [
285
+ `\n### ${ep.name} — ${ep.method} ${ep.path} (${ep.relation})`,
286
+ `\n- Concepts: ${ep.concepts.join(", ")}`,
287
+ `\n- Params: ${compactParams(ep.params)}`,
288
+ body === "(none)" ? "" : `\n- Body: ${body}`,
289
+ `\n- Response: ${refMap.get(compactResp) ?? compactResp}`,
290
+ ep.rules.length > 0 ? `\n Rules: ${ep.rules.join("; ")}` : "",
291
+ renderDependencies(ep.dependencies),
292
+ ep.metadata === "{}" ? "" : `\n Metadata: ${ep.metadata}`,
293
+ ];
294
+
295
+ return lines.join("");
296
+ }
297
+
298
+ function renderDependencies(dependencies: GroupedEndpoint["dependencies"]) {
299
+ if (dependencies.length === 0) return "";
300
+
301
+ const calls = dependencies.map(
302
+ (d) =>
303
+ ` - Call ${d.depMethod} ${d.depPath} first → use its "${d.fromField}" as "${d.paramName}"`,
304
+ );
305
+ return `\n Dependencies:\n${calls.join("\n")}`;
306
+ }
307
+
308
+ function renderService(svc: ResolvedService) {
309
+ const rules = svc.rules.length > 0 ? `\n Rules: ${svc.rules.join("; ")}` : "";
310
+ const meta = svc.metadata === "{}" ? "" : `\n- Metadata: ${svc.metadata}`;
311
+
312
+ return (
313
+ `\n### ${svc.concept} via ${svc.serviceName} (service)` +
314
+ `\n- Built-in ID: ${svc.builtInId}` +
315
+ `\n- Description: ${svc.description || "N/A"}${rules}${meta}`
316
+ );
317
+ }
264
318
 
265
319
  function buildResolvedSection(resolved: ResolvedContext) {
266
320
  const allEndpoints = [...resolved.readEndpoints, ...resolved.writeEndpoints];
@@ -282,73 +336,20 @@ function buildResolvedSection(resolved: ResolvedContext) {
282
336
  // Layer 4: deduplicate identical response schemas
283
337
  const { shapeDefs, refMap } = buildResponseShapeRefs(cleanedGroups);
284
338
 
285
- const parts: string[] = [
339
+ return [
286
340
  `
287
341
  ## Pre-resolved API Endpoints
288
342
  The following endpoints were automatically matched to the user's message.`,
289
- ];
290
-
291
- // Shared rules
292
- if (sharedRules.length > 0) {
293
- parts.push("\n### General Rules");
294
- for (const rule of sharedRules) {
295
- parts.push(`\n- ${rule}`);
296
- }
297
- }
298
-
299
- // Response shape definitions
300
- if (shapeDefs.length > 0) {
301
- parts.push("\n### Response Shapes");
302
- for (const def of shapeDefs) {
303
- parts.push(`\n${def.name}: ${def.content}`);
304
- }
305
- }
306
-
307
- // Endpoints (Layer 2: compact schemas)
308
- for (const ep of cleanedGroups) {
309
- const concepts = ep.concepts.join(", ");
310
- const params = compactParams(ep.params);
311
- const body = compactParams(ep.body);
312
- const compactResp = compactResponse(ep.response);
313
- const response = refMap.get(compactResp) ?? compactResp;
314
-
315
- const rules = ep.rules.length > 0 ? `\n Rules: ${ep.rules.join("; ")}` : "";
316
- const deps =
317
- ep.dependencies.length > 0
318
- ? "\n Dependencies:\n" +
319
- ep.dependencies
320
- .map(
321
- (d) =>
322
- ` - Call ${d.depMethod} ${d.depPath} first → use its "${d.fromField}" as "${d.paramName}"`,
323
- )
324
- .join("\n")
325
- : "";
326
- const meta = ep.metadata !== "{}" ? `\n Metadata: ${ep.metadata}` : "";
327
-
328
- let block = `\n### ${ep.name} — ${ep.method} ${ep.path} (${ep.relation})`;
329
- block += `\n- Concepts: ${concepts}`;
330
- block += `\n- Params: ${params}`;
331
- if (body !== "(none)") {
332
- block += `\n- Body: ${body}`;
333
- }
334
- block += `\n- Response: ${response}`;
335
- block += rules;
336
- block += deps;
337
- block += meta;
338
-
339
- parts.push(block);
340
- }
341
-
342
- // Services
343
- for (const svc of cleanedServices) {
344
- const rules = svc.rules.length > 0 ? `\n Rules: ${svc.rules.join("; ")}` : "";
345
- const meta = svc.metadata !== "{}" ? `\n- Metadata: ${svc.metadata}` : "";
346
- parts.push(
347
- `\n### ${svc.concept} via ${svc.serviceName} (service)` +
348
- `\n- Built-in ID: ${svc.builtInId}` +
349
- `\n- Description: ${svc.description || "N/A"}${rules}${meta}`,
350
- );
351
- }
352
-
353
- return parts.join("");
343
+ ...renderSection(
344
+ "General Rules",
345
+ sharedRules.map((rule) => `- ${rule}`),
346
+ ),
347
+ ...renderSection(
348
+ "Response Shapes",
349
+ shapeDefs.map((def) => `${def.name}: ${def.content}`),
350
+ ),
351
+ // Layer 2: compact schemas
352
+ ...cleanedGroups.map((ep) => renderEndpoint(ep, refMap)),
353
+ ...cleanedServices.map(renderService),
354
+ ].join("");
354
355
  }