@goscribe/server 1.3.4 → 1.5.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 (378) hide show
  1. package/.env.example +12 -0
  2. package/.vscode/settings.json +3 -0
  3. package/REFACTOR_NOTES.md +60 -0
  4. package/TESTING_PROMPT.md +225 -0
  5. package/dist/controllers/admin.controller.d.ts +715 -0
  6. package/dist/controllers/admin.controller.js +9 -0
  7. package/dist/controllers/annotations.controller.d.ts +439 -0
  8. package/dist/controllers/annotations.controller.js +9 -0
  9. package/dist/controllers/app-router.controller.d.ts +3011 -0
  10. package/dist/controllers/app-router.controller.js +38 -0
  11. package/dist/controllers/app-router.controller.test.d.ts +1 -0
  12. package/dist/controllers/app-router.controller.test.js +36 -0
  13. package/dist/controllers/auth.controller.d.ts +323 -0
  14. package/dist/controllers/auth.controller.js +9 -0
  15. package/dist/controllers/base.controller.d.ts +4 -0
  16. package/dist/controllers/base.controller.js +5 -0
  17. package/dist/controllers/chat.controller.d.ts +341 -0
  18. package/dist/controllers/chat.controller.js +9 -0
  19. package/dist/controllers/copilot.controller.d.ts +397 -0
  20. package/dist/controllers/copilot.controller.js +9 -0
  21. package/dist/controllers/flashcards.controller.d.ts +651 -0
  22. package/dist/controllers/flashcards.controller.js +9 -0
  23. package/dist/controllers/members.controller.d.ts +339 -0
  24. package/dist/controllers/members.controller.js +9 -0
  25. package/dist/controllers/notifications.controller.d.ts +199 -0
  26. package/dist/controllers/notifications.controller.js +9 -0
  27. package/dist/controllers/payment.controller.d.ts +181 -0
  28. package/dist/controllers/payment.controller.js +9 -0
  29. package/dist/controllers/podcast.controller.d.ts +575 -0
  30. package/dist/controllers/podcast.controller.js +9 -0
  31. package/dist/controllers/router-module.controller.d.ts +5 -0
  32. package/dist/controllers/router-module.controller.js +6 -0
  33. package/dist/controllers/studyguide.controller.d.ts +73 -0
  34. package/dist/controllers/studyguide.controller.js +9 -0
  35. package/dist/controllers/worksheets.controller.d.ts +829 -0
  36. package/dist/controllers/worksheets.controller.js +9 -0
  37. package/dist/controllers/workspace.controller.d.ts +1207 -0
  38. package/dist/controllers/workspace.controller.js +9 -0
  39. package/dist/lib/activity_human_description.test.js +16 -15
  40. package/dist/lib/activity_log_service.test.js +28 -23
  41. package/dist/lib/ai/config.d.ts +20 -0
  42. package/dist/lib/ai/config.js +31 -0
  43. package/dist/lib/ai/embedding-client.d.ts +8 -0
  44. package/dist/lib/ai/embedding-client.js +30 -0
  45. package/dist/lib/ai/index.d.ts +47 -0
  46. package/dist/lib/ai/index.js +28 -0
  47. package/dist/lib/ai/inference-backend/client.d.ts +28 -0
  48. package/dist/lib/ai/inference-backend/client.js +301 -0
  49. package/dist/lib/ai/inference-backend/mocks.d.ts +12 -0
  50. package/dist/lib/ai/inference-backend/mocks.js +133 -0
  51. package/dist/lib/ai/inference-backend/types.d.ts +44 -0
  52. package/dist/lib/ai/inference-backend/types.js +1 -0
  53. package/dist/lib/ai/json-parse.d.ts +2 -0
  54. package/dist/lib/ai/json-parse.js +34 -0
  55. package/dist/lib/ai/llm-client.d.ts +6 -0
  56. package/dist/lib/ai/llm-client.js +19 -0
  57. package/dist/lib/ai/mock.d.ts +2 -0
  58. package/dist/lib/ai/mock.js +10 -0
  59. package/dist/lib/ai/types.d.ts +9 -0
  60. package/dist/lib/ai/types.js +1 -0
  61. package/dist/lib/chunking.d.ts +19 -0
  62. package/dist/lib/chunking.js +47 -0
  63. package/dist/lib/curated-kb-seed.d.ts +12 -0
  64. package/dist/lib/curated-kb-seed.js +155 -0
  65. package/dist/lib/email.js +67 -108
  66. package/dist/lib/embeddings.d.ts +2 -0
  67. package/dist/lib/embeddings.js +1 -0
  68. package/dist/lib/ensure-curated-kb-catalog.d.ts +6 -0
  69. package/dist/lib/ensure-curated-kb-catalog.js +53 -0
  70. package/dist/lib/env.d.ts +1 -5
  71. package/dist/lib/env.js +2 -7
  72. package/dist/lib/inference.d.ts +1 -8
  73. package/dist/lib/inference.js +1 -19
  74. package/dist/lib/kb-meta.d.ts +8 -0
  75. package/dist/lib/kb-meta.js +77 -0
  76. package/dist/lib/note-text.d.ts +1 -0
  77. package/dist/lib/note-text.js +47 -0
  78. package/dist/lib/notification-service.test.js +37 -36
  79. package/dist/lib/pdf.d.ts +11 -0
  80. package/dist/lib/pdf.js +11 -0
  81. package/dist/lib/usage_service.d.ts +2 -1
  82. package/dist/lib/usage_service.js +30 -12
  83. package/dist/lib/worksheet-generation.js +4 -4
  84. package/dist/lib/worksheet-generation.test.js +32 -17
  85. package/dist/lib/workspace-kb.d.ts +5 -0
  86. package/dist/lib/workspace-kb.js +7 -0
  87. package/dist/models/controller-context.model.d.ts +8 -0
  88. package/dist/models/controller-context.model.js +1 -0
  89. package/dist/repositories/artifact.repository.d.ts +60 -0
  90. package/dist/repositories/artifact.repository.js +40 -0
  91. package/dist/repositories/base.repository.d.ts +14 -0
  92. package/dist/repositories/base.repository.js +14 -0
  93. package/dist/repositories/invitation.repository.d.ts +94 -0
  94. package/dist/repositories/invitation.repository.js +44 -0
  95. package/dist/repositories/notification.repository.d.ts +72 -0
  96. package/dist/repositories/notification.repository.js +44 -0
  97. package/dist/repositories/router-module.repository.d.ts +10 -0
  98. package/dist/repositories/router-module.repository.js +14 -0
  99. package/dist/repositories/user.repository.d.ts +74 -0
  100. package/dist/repositories/user.repository.js +37 -0
  101. package/dist/repositories/workspace-member.repository.d.ts +31 -0
  102. package/dist/repositories/workspace-member.repository.js +31 -0
  103. package/dist/repositories/workspace.repository.d.ts +97 -0
  104. package/dist/repositories/workspace.repository.js +79 -0
  105. package/dist/routers/_app.d.ts +528 -33
  106. package/dist/routers/_app.js +4 -0
  107. package/dist/routers/admin.d.ts +0 -4
  108. package/dist/routers/admin.js +21 -549
  109. package/dist/routers/annotations.js +12 -170
  110. package/dist/routers/artifactVersions.d.ts +65 -0
  111. package/dist/routers/artifactVersions.js +14 -0
  112. package/dist/routers/auth.d.ts +0 -6
  113. package/dist/routers/auth.js +36 -421
  114. package/dist/routers/chat.js +15 -229
  115. package/dist/routers/copilot.d.ts +14 -13
  116. package/dist/routers/copilot.js +13 -532
  117. package/dist/routers/flashcards.d.ts +5 -5
  118. package/dist/routers/flashcards.js +23 -349
  119. package/dist/routers/knowledgeBase.d.ts +421 -0
  120. package/dist/routers/knowledgeBase.js +118 -0
  121. package/dist/routers/members.d.ts +0 -41
  122. package/dist/routers/members.js +22 -710
  123. package/dist/routers/notes.d.ts +94 -0
  124. package/dist/routers/notes.js +37 -0
  125. package/dist/routers/notifications.js +7 -109
  126. package/dist/routers/payment.d.ts +3 -2
  127. package/dist/routers/payment.js +11 -393
  128. package/dist/routers/podcast.d.ts +1 -1
  129. package/dist/routers/podcast.js +11 -784
  130. package/dist/routers/studyguide.js +3 -129
  131. package/dist/routers/worksheets.d.ts +29 -14
  132. package/dist/routers/worksheets.js +49 -628
  133. package/dist/routers/workspace.d.ts +0 -4
  134. package/dist/routers/workspace.js +28 -922
  135. package/dist/scripts/purge-deleted-users.js +2 -2
  136. package/dist/server.js +10 -3
  137. package/dist/services/activity/activity-human-description.service.d.ts +13 -0
  138. package/dist/services/activity/activity-human-description.service.js +221 -0
  139. package/dist/services/activity/activity-human-description.service.test.d.ts +1 -0
  140. package/dist/services/activity/activity-human-description.service.test.js +16 -0
  141. package/dist/services/activity/activity-log.service.d.ts +87 -0
  142. package/dist/services/activity/activity-log.service.js +276 -0
  143. package/dist/services/activity/activity-log.service.test.d.ts +1 -0
  144. package/dist/services/activity/activity-log.service.test.js +27 -0
  145. package/dist/services/activity-human-description.service.d.ts +13 -0
  146. package/dist/services/activity-human-description.service.js +221 -0
  147. package/dist/services/activity-human-description.service.test.d.ts +1 -0
  148. package/dist/services/activity-human-description.service.test.js +16 -0
  149. package/dist/services/activity-log.service.d.ts +87 -0
  150. package/dist/services/activity-log.service.js +276 -0
  151. package/dist/services/activity-log.service.test.d.ts +1 -0
  152. package/dist/services/activity-log.service.test.js +27 -0
  153. package/dist/services/admin/admin.service.d.ts +270 -0
  154. package/dist/services/admin/admin.service.js +476 -0
  155. package/dist/services/admin.service.d.ts +270 -0
  156. package/dist/services/admin.service.js +476 -0
  157. package/dist/services/ai/ai-session.service.d.ts +5 -0
  158. package/dist/services/ai/ai-session.service.js +4 -0
  159. package/dist/services/ai-session.service.d.ts +60 -0
  160. package/dist/services/ai-session.service.js +561 -0
  161. package/dist/services/annotation.service.d.ts +177 -0
  162. package/dist/services/annotation.service.js +154 -0
  163. package/dist/services/artifact-notification.service.d.ts +14 -0
  164. package/dist/services/artifact-notification.service.js +20 -0
  165. package/dist/services/artifact-version.service.d.ts +38 -0
  166. package/dist/services/artifact-version.service.js +129 -0
  167. package/dist/services/artifacts/annotation.service.d.ts +177 -0
  168. package/dist/services/artifacts/annotation.service.js +154 -0
  169. package/dist/services/artifacts/artifact-version.service.d.ts +38 -0
  170. package/dist/services/artifacts/artifact-version.service.js +129 -0
  171. package/dist/services/artifacts/chat.service.d.ts +127 -0
  172. package/dist/services/artifacts/chat.service.js +182 -0
  173. package/dist/services/artifacts/study-guide.service.d.ts +18 -0
  174. package/dist/services/artifacts/study-guide.service.js +65 -0
  175. package/dist/services/auth/auth.service.d.ts +94 -0
  176. package/dist/services/auth/auth.service.js +368 -0
  177. package/dist/services/auth.service.d.ts +94 -0
  178. package/dist/services/auth.service.js +368 -0
  179. package/dist/services/base.service.d.ts +14 -0
  180. package/dist/services/base.service.js +14 -0
  181. package/dist/services/billing/payment.service.d.ts +55 -0
  182. package/dist/services/billing/payment.service.js +368 -0
  183. package/dist/services/billing/subscription.service.d.ts +37 -0
  184. package/dist/services/billing/subscription.service.js +654 -0
  185. package/dist/services/billing/usage.service.d.ts +27 -0
  186. package/dist/services/billing/usage.service.js +77 -0
  187. package/dist/services/chat.service.d.ts +127 -0
  188. package/dist/services/chat.service.js +182 -0
  189. package/dist/services/content/copilot.service.d.ts +113 -0
  190. package/dist/services/content/copilot.service.js +453 -0
  191. package/dist/services/content/flashcard-progress.service.d.ts +159 -0
  192. package/dist/services/content/flashcard-progress.service.js +432 -0
  193. package/dist/services/content/flashcard.service.d.ts +140 -0
  194. package/dist/services/content/flashcard.service.js +326 -0
  195. package/dist/services/content/media-analysis.service.d.ts +23 -0
  196. package/dist/services/content/media-analysis.service.js +404 -0
  197. package/dist/services/content/podcast.service.d.ts +267 -0
  198. package/dist/services/content/podcast.service.js +653 -0
  199. package/dist/services/content/worksheet-content.service.d.ts +37 -0
  200. package/dist/services/content/worksheet-content.service.js +84 -0
  201. package/dist/services/content/worksheet-content.service.test.d.ts +1 -0
  202. package/dist/services/content/worksheet-content.service.test.js +69 -0
  203. package/dist/services/content/worksheet-generation.service.d.ts +91 -0
  204. package/dist/services/content/worksheet-generation.service.js +95 -0
  205. package/dist/services/content/worksheet-generation.service.test.d.ts +1 -0
  206. package/dist/services/content/worksheet-generation.service.test.js +20 -0
  207. package/dist/services/content/worksheet.service.d.ts +347 -0
  208. package/dist/services/content/worksheet.service.js +599 -0
  209. package/dist/services/copilot.service.d.ts +116 -0
  210. package/dist/services/copilot.service.js +447 -0
  211. package/dist/services/flashcard-progress.service.d.ts +2 -2
  212. package/dist/services/flashcard-progress.service.js +3 -2
  213. package/dist/services/flashcard.service.d.ts +140 -0
  214. package/dist/services/flashcard.service.js +325 -0
  215. package/dist/services/invitation.service.d.ts +66 -0
  216. package/dist/services/invitation.service.js +348 -0
  217. package/dist/services/knowledge/knowledge-base.service.d.ts +316 -0
  218. package/dist/services/knowledge/knowledge-base.service.js +544 -0
  219. package/dist/services/knowledge-base.service.d.ts +316 -0
  220. package/dist/services/knowledge-base.service.js +536 -0
  221. package/dist/services/media-analysis.service.d.ts +23 -0
  222. package/dist/services/media-analysis.service.js +384 -0
  223. package/dist/services/member.service.d.ts +36 -0
  224. package/dist/services/member.service.js +193 -0
  225. package/dist/services/members/invitation.service.d.ts +66 -0
  226. package/dist/services/members/invitation.service.js +348 -0
  227. package/dist/services/members/member.service.d.ts +36 -0
  228. package/dist/services/members/member.service.js +193 -0
  229. package/dist/services/note.service.d.ts +55 -0
  230. package/dist/services/note.service.js +111 -0
  231. package/dist/services/notification.service.d.ts +214 -0
  232. package/dist/services/notification.service.js +550 -0
  233. package/dist/services/notification.service.test.d.ts +1 -0
  234. package/dist/services/notification.service.test.js +87 -0
  235. package/dist/services/notifications/notification.service.d.ts +214 -0
  236. package/dist/services/notifications/notification.service.js +550 -0
  237. package/dist/services/notifications/notification.service.test.d.ts +1 -0
  238. package/dist/services/notifications/notification.service.test.js +87 -0
  239. package/dist/services/payment.service.d.ts +55 -0
  240. package/dist/services/payment.service.js +368 -0
  241. package/dist/services/podcast.service.d.ts +267 -0
  242. package/dist/services/podcast.service.js +654 -0
  243. package/dist/services/router-module.service.d.ts +7 -0
  244. package/dist/services/router-module.service.js +10 -0
  245. package/dist/services/study-guide.service.d.ts +18 -0
  246. package/dist/services/study-guide.service.js +65 -0
  247. package/dist/services/subscription.service.d.ts +37 -0
  248. package/dist/services/subscription.service.js +654 -0
  249. package/dist/services/usage-limit-policy.service.d.ts +12 -0
  250. package/dist/services/usage-limit-policy.service.js +22 -0
  251. package/dist/services/usage-limit-policy.service.test.d.ts +1 -0
  252. package/dist/services/usage-limit-policy.service.test.js +46 -0
  253. package/dist/services/usage.service.d.ts +27 -0
  254. package/dist/services/usage.service.js +77 -0
  255. package/dist/services/worksheet-content.service.d.ts +42 -0
  256. package/dist/services/worksheet-content.service.js +84 -0
  257. package/dist/services/worksheet-content.service.test.d.ts +1 -0
  258. package/dist/services/worksheet-content.service.test.js +69 -0
  259. package/dist/services/worksheet-generation.service.d.ts +91 -0
  260. package/dist/services/worksheet-generation.service.js +95 -0
  261. package/dist/services/worksheet-generation.service.test.d.ts +1 -0
  262. package/dist/services/worksheet-generation.service.test.js +20 -0
  263. package/dist/services/worksheet.service.d.ts +385 -0
  264. package/dist/services/worksheet.service.js +596 -0
  265. package/dist/services/workspace/workspace-analytics.service.d.ts +24 -0
  266. package/dist/services/workspace/workspace-analytics.service.js +95 -0
  267. package/dist/services/workspace/workspace-kb.service.d.ts +40 -0
  268. package/dist/services/workspace/workspace-kb.service.js +184 -0
  269. package/dist/services/workspace/workspace.service.d.ts +307 -0
  270. package/dist/services/workspace/workspace.service.js +394 -0
  271. package/dist/services/workspace-analytics.service.d.ts +24 -0
  272. package/dist/services/workspace-analytics.service.js +95 -0
  273. package/dist/services/workspace-kb.service.d.ts +40 -0
  274. package/dist/services/workspace-kb.service.js +184 -0
  275. package/dist/services/workspace-progress.service.d.ts +27 -0
  276. package/dist/services/workspace-progress.service.js +56 -0
  277. package/dist/services/workspace-progress.service.test.d.ts +1 -0
  278. package/dist/services/workspace-progress.service.test.js +49 -0
  279. package/dist/services/workspace.service.d.ts +307 -0
  280. package/dist/services/workspace.service.js +390 -0
  281. package/dist/trpc.js +2 -2
  282. package/package.json +5 -6
  283. package/prisma/migrations/20260509000001_add_knowledge_base/migration.sql +99 -0
  284. package/prisma/migrations/20260509000002_curate_knowledge_base/migration.sql +52 -0
  285. package/prisma/migrations/20260522000000_add_notes/migration.sql +27 -0
  286. package/prisma/migrations/20260524000000_remove_notes/migration.sql +3 -0
  287. package/prisma/schema.prisma +150 -48
  288. package/prisma/seed.mjs +67 -0
  289. package/scripts/debug/README.md +4 -0
  290. package/src/README.md +63 -0
  291. package/src/lib/ai/config.ts +34 -0
  292. package/src/lib/ai/embedding-client.ts +47 -0
  293. package/src/lib/ai/index.ts +62 -0
  294. package/src/lib/ai/inference-backend/client.ts +479 -0
  295. package/src/lib/ai/inference-backend/mocks.ts +171 -0
  296. package/src/lib/ai/inference-backend/types.ts +50 -0
  297. package/src/lib/ai/json-parse.ts +35 -0
  298. package/src/lib/ai/llm-client.ts +31 -0
  299. package/src/lib/ai/mock.ts +12 -0
  300. package/src/lib/ai/types.ts +11 -0
  301. package/src/lib/chunking.ts +81 -0
  302. package/src/lib/curated-kb-seed.ts +164 -0
  303. package/src/lib/email.ts +77 -115
  304. package/src/lib/embeddings.ts +9 -0
  305. package/src/lib/ensure-curated-kb-catalog.ts +60 -0
  306. package/src/lib/env.ts +2 -7
  307. package/src/lib/inference.ts +1 -21
  308. package/src/lib/kb-meta.ts +81 -0
  309. package/src/lib/pdf.ts +23 -0
  310. package/src/lib/workspace-kb.ts +7 -0
  311. package/src/repositories/artifact.repository.ts +55 -0
  312. package/src/repositories/base.repository.ts +19 -0
  313. package/src/repositories/invitation.repository.ts +53 -0
  314. package/src/repositories/notification.repository.ts +53 -0
  315. package/src/repositories/user.repository.ts +44 -0
  316. package/src/repositories/workspace-member.repository.ts +38 -0
  317. package/src/repositories/workspace.repository.ts +89 -0
  318. package/src/routers/_app.ts +4 -0
  319. package/src/routers/admin.ts +124 -692
  320. package/src/routers/annotations.ts +25 -203
  321. package/src/routers/artifactVersions.ts +32 -0
  322. package/src/routers/auth.ts +81 -519
  323. package/src/routers/chat.ts +42 -245
  324. package/src/routers/copilot.ts +41 -666
  325. package/src/routers/flashcards.ts +108 -404
  326. package/src/routers/knowledgeBase.ts +216 -0
  327. package/src/routers/members.ts +60 -782
  328. package/src/routers/notifications.ts +15 -117
  329. package/src/routers/payment.ts +37 -446
  330. package/src/routers/podcast.ts +36 -898
  331. package/src/routers/studyguide.ts +5 -144
  332. package/src/routers/worksheets.ts +171 -735
  333. package/src/routers/workspace.ts +138 -1109
  334. package/src/scripts/purge-deleted-users.ts +2 -2
  335. package/src/server.ts +10 -3
  336. package/src/{lib/activity_human_description.test.ts → services/activity/activity-human-description.service.test.ts} +1 -1
  337. package/src/{lib/activity_log_service.test.ts → services/activity/activity-log.service.test.ts} +1 -1
  338. package/src/{lib/activity_log_service.ts → services/activity/activity-log.service.ts} +2 -2
  339. package/src/services/admin/admin.service.ts +612 -0
  340. package/src/services/ai/ai-session.service.ts +5 -0
  341. package/src/services/artifacts/annotation.service.ts +189 -0
  342. package/src/services/artifacts/artifact-version.service.ts +151 -0
  343. package/src/services/artifacts/chat.service.ts +197 -0
  344. package/src/services/artifacts/study-guide.service.ts +72 -0
  345. package/src/services/auth/auth.service.ts +473 -0
  346. package/src/services/base.service.ts +19 -0
  347. package/src/services/billing/payment.service.ts +436 -0
  348. package/src/{lib/subscription_service.ts → services/billing/subscription.service.ts} +5 -5
  349. package/src/{lib/usage_service.ts → services/billing/usage.service.ts} +32 -12
  350. package/src/services/content/copilot.service.ts +596 -0
  351. package/src/services/{flashcard-progress.service.ts → content/flashcard-progress.service.ts} +6 -3
  352. package/src/services/content/flashcard.service.ts +394 -0
  353. package/src/services/content/media-analysis.service.ts +556 -0
  354. package/src/services/content/podcast.service.ts +777 -0
  355. package/src/services/content/worksheet-content.service.test.ts +83 -0
  356. package/src/services/content/worksheet-content.service.ts +117 -0
  357. package/src/{lib/worksheet-generation.test.ts → services/content/worksheet-generation.service.test.ts} +1 -1
  358. package/src/services/content/worksheet.service.ts +751 -0
  359. package/src/services/knowledge/knowledge-base.service.ts +705 -0
  360. package/src/services/members/invitation.service.ts +427 -0
  361. package/src/services/members/member.service.ts +241 -0
  362. package/src/{lib/notification-service.test.ts → services/notifications/notification.service.test.ts} +2 -2
  363. package/src/{lib/notification-service.ts → services/notifications/notification.service.ts} +102 -1
  364. package/src/services/workspace/workspace-analytics.service.ts +107 -0
  365. package/src/services/workspace/workspace-kb.service.ts +273 -0
  366. package/src/services/workspace/workspace.service.ts +481 -0
  367. package/src/trpc.ts +2 -2
  368. package/src/lib/ai-session.ts +0 -704
  369. package/src/lib/workspace-access.ts +0 -13
  370. /package/{check-difficulty.cjs → scripts/debug/check-difficulty.cjs} +0 -0
  371. /package/{check-questions.cjs → scripts/debug/check-questions.cjs} +0 -0
  372. /package/{db-summary.cjs → scripts/debug/db-summary.cjs} +0 -0
  373. /package/{mcq-test.cjs → scripts/debug/mcq-test.cjs} +0 -0
  374. /package/{test-generate.js → scripts/debug/test-generate.js} +0 -0
  375. /package/{test-ratio.cjs → scripts/debug/test-ratio.cjs} +0 -0
  376. /package/{zod-test.cjs → scripts/debug/zod-test.cjs} +0 -0
  377. /package/src/{lib/activity_human_description.ts → services/activity/activity-human-description.service.ts} +0 -0
  378. /package/src/{lib/worksheet-generation.ts → services/content/worksheet-generation.service.ts} +0 -0
@@ -0,0 +1,35 @@
1
+ export function extractJson(content: string): Record<string, unknown> | null {
2
+ const fencedMatch = content.match(/```json\s*([\s\S]*?)```/i);
3
+ if (fencedMatch?.[1]) {
4
+ try {
5
+ return JSON.parse(fencedMatch[1]) as Record<string, unknown>;
6
+ } catch {
7
+ // fall through
8
+ }
9
+ }
10
+
11
+ const objectMatch = content.match(/\{[\s\S]*\}/);
12
+ if (objectMatch?.[0]) {
13
+ try {
14
+ return JSON.parse(objectMatch[0]) as Record<string, unknown>;
15
+ } catch {
16
+ return null;
17
+ }
18
+ }
19
+
20
+ return null;
21
+ }
22
+
23
+ export function parseJsonField<T>(value: unknown, field: string): T {
24
+ if (typeof value === 'string') {
25
+ return JSON.parse(value) as T;
26
+ }
27
+ if (value && typeof value === 'object' && field in (value as object)) {
28
+ const nested = (value as Record<string, unknown>)[field];
29
+ if (typeof nested === 'string') {
30
+ return JSON.parse(nested) as T;
31
+ }
32
+ return nested as T;
33
+ }
34
+ throw new Error(`Expected JSON field "${field}" in AI response`);
35
+ }
@@ -0,0 +1,31 @@
1
+ import OpenAI from 'openai';
2
+ import type { ChatCompletion } from 'openai/resources/chat/completions';
3
+ import { aiConfig } from './config.js';
4
+ import type { ChatMessage, CompleteOptions } from './types.js';
5
+
6
+ const client = new OpenAI({
7
+ apiKey: aiConfig.llm.apiKey,
8
+ baseURL: aiConfig.llm.baseUrl,
9
+ });
10
+
11
+ export async function complete(
12
+ messages: ChatMessage[],
13
+ options: CompleteOptions = {},
14
+ ): Promise<ChatCompletion> {
15
+ return client.chat.completions.create({
16
+ model: options.model ?? aiConfig.llm.model,
17
+ messages,
18
+ ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),
19
+ });
20
+ }
21
+
22
+ export async function completeText(
23
+ messages: ChatMessage[],
24
+ options: CompleteOptions = {},
25
+ ): Promise<string> {
26
+ const response = await complete(messages, options);
27
+ return response.choices?.[0]?.message?.content ?? '';
28
+ }
29
+
30
+ /** @deprecated Use `complete()` from the ai module instead. */
31
+ export default complete;
@@ -0,0 +1,12 @@
1
+ import { aiConfig } from './config.js';
2
+
3
+ export function isAiMockMode(): boolean {
4
+ return aiConfig.inferenceBackend.mockEnabled;
5
+ }
6
+
7
+ export async function mockDelay(): Promise<void> {
8
+ const delay = aiConfig.inferenceBackend.mockDelayMs;
9
+ if (delay > 0) {
10
+ await new Promise((resolve) => setTimeout(resolve, delay));
11
+ }
12
+ }
@@ -0,0 +1,11 @@
1
+ export type ChatRole = 'system' | 'user' | 'assistant';
2
+
3
+ export interface ChatMessage {
4
+ role: ChatRole;
5
+ content: string;
6
+ }
7
+
8
+ export interface CompleteOptions {
9
+ model?: string;
10
+ temperature?: number;
11
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Approximate text chunker for RAG indexing.
3
+ *
4
+ * Splits a long document into overlapping windows aimed at a target token
5
+ * count. We don't have a tokenizer dependency, so we approximate using
6
+ * `chars / 4` (a rule of thumb that matches GPT-style BPE within ~10-20%).
7
+ * Chunk boundaries snap to paragraph / sentence breaks when possible so we
8
+ * don't slice mid-thought.
9
+ */
10
+ export interface ChunkOptions {
11
+ targetTokens?: number;
12
+ overlapTokens?: number;
13
+ }
14
+
15
+ export interface Chunk {
16
+ index: number;
17
+ content: string;
18
+ approxTokens: number;
19
+ }
20
+
21
+ const CHARS_PER_TOKEN = 4;
22
+
23
+ export function chunkText(
24
+ text: string,
25
+ opts: ChunkOptions = {},
26
+ ): Chunk[] {
27
+ const targetTokens = opts.targetTokens ?? 500;
28
+ const overlapTokens = opts.overlapTokens ?? 60;
29
+
30
+ const targetChars = targetTokens * CHARS_PER_TOKEN;
31
+ const overlapChars = overlapTokens * CHARS_PER_TOKEN;
32
+
33
+ const cleaned = text.replace(/\r\n/g, '\n').replace(/[ \t]+/g, ' ').trim();
34
+ if (!cleaned) return [];
35
+
36
+ const chunks: Chunk[] = [];
37
+ let cursor = 0;
38
+ let index = 0;
39
+
40
+ while (cursor < cleaned.length) {
41
+ const hardEnd = Math.min(cleaned.length, cursor + targetChars);
42
+ let end = hardEnd;
43
+
44
+ if (hardEnd < cleaned.length) {
45
+ // Prefer a paragraph break, then a sentence break, then a space.
46
+ const window = cleaned.slice(cursor, hardEnd);
47
+ const lastPara = window.lastIndexOf('\n\n');
48
+ const lastSentence = Math.max(
49
+ window.lastIndexOf('. '),
50
+ window.lastIndexOf('! '),
51
+ window.lastIndexOf('? '),
52
+ window.lastIndexOf('.\n'),
53
+ );
54
+ const lastSpace = window.lastIndexOf(' ');
55
+
56
+ const minBreak = Math.floor(targetChars * 0.5);
57
+ if (lastPara >= minBreak) {
58
+ end = cursor + lastPara + 2;
59
+ } else if (lastSentence >= minBreak) {
60
+ end = cursor + lastSentence + 2;
61
+ } else if (lastSpace >= minBreak) {
62
+ end = cursor + lastSpace + 1;
63
+ }
64
+ }
65
+
66
+ const piece = cleaned.slice(cursor, end).trim();
67
+ if (piece) {
68
+ chunks.push({
69
+ index,
70
+ content: piece,
71
+ approxTokens: Math.max(1, Math.round(piece.length / CHARS_PER_TOKEN)),
72
+ });
73
+ index += 1;
74
+ }
75
+
76
+ if (end >= cleaned.length) break;
77
+ cursor = Math.max(end - overlapChars, cursor + 1);
78
+ }
79
+
80
+ return chunks;
81
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Curated AP & IB knowledge bases seeded on server startup.
3
+ * Each entry uses a stable slug in `meta` so the client can pick icons/colors.
4
+ */
5
+
6
+ export interface CuratedKbSeed {
7
+ slug: string;
8
+ name: string;
9
+ description: string;
10
+ category: 'AP' | 'IB';
11
+ subject: string;
12
+ }
13
+
14
+ export const CURATED_KB_SEEDS: CuratedKbSeed[] = [
15
+ // ── AP ──────────────────────────────────────────────────────────
16
+ {
17
+ slug: 'ap-biology',
18
+ name: 'AP Biology',
19
+ description: 'Cell biology, genetics, evolution, and ecology aligned with the AP Biology curriculum.',
20
+ category: 'AP',
21
+ subject: 'biology',
22
+ },
23
+ {
24
+ slug: 'ap-chemistry',
25
+ name: 'AP Chemistry',
26
+ description: 'Atomic structure, bonding, thermodynamics, and kinetics for AP Chemistry.',
27
+ category: 'AP',
28
+ subject: 'chemistry',
29
+ },
30
+ {
31
+ slug: 'ap-physics-1',
32
+ name: 'AP Physics 1',
33
+ description: 'Algebra-based mechanics, waves, and electricity for AP Physics 1.',
34
+ category: 'AP',
35
+ subject: 'physics',
36
+ },
37
+ {
38
+ slug: 'ap-calculus-ab',
39
+ name: 'AP Calculus AB',
40
+ description: 'Limits, derivatives, integrals, and the Fundamental Theorem of Calculus.',
41
+ category: 'AP',
42
+ subject: 'calculus',
43
+ },
44
+ {
45
+ slug: 'ap-calculus-bc',
46
+ name: 'AP Calculus BC',
47
+ description: 'Series, parametric equations, polar coordinates, and advanced integration.',
48
+ category: 'AP',
49
+ subject: 'calculus',
50
+ },
51
+ {
52
+ slug: 'ap-us-history',
53
+ name: 'AP US History',
54
+ description: 'Colonial America through the modern era with primary source analysis.',
55
+ category: 'AP',
56
+ subject: 'history',
57
+ },
58
+ {
59
+ slug: 'ap-world-history',
60
+ name: 'AP World History',
61
+ description: 'Global civilizations, trade networks, and historical thinking skills.',
62
+ category: 'AP',
63
+ subject: 'history',
64
+ },
65
+ {
66
+ slug: 'ap-english-lang',
67
+ name: 'AP English Language',
68
+ description: 'Rhetorical analysis, argumentation, and synthesis writing strategies.',
69
+ category: 'AP',
70
+ subject: 'english',
71
+ },
72
+ {
73
+ slug: 'ap-english-lit',
74
+ name: 'AP English Literature',
75
+ description: 'Literary analysis, poetry, prose fiction, and critical essay writing.',
76
+ category: 'AP',
77
+ subject: 'literature',
78
+ },
79
+ {
80
+ slug: 'ap-psychology',
81
+ name: 'AP Psychology',
82
+ description: 'Biological bases of behavior, cognition, development, and social psychology.',
83
+ category: 'AP',
84
+ subject: 'psychology',
85
+ },
86
+ {
87
+ slug: 'ap-environmental-science',
88
+ name: 'AP Environmental Science',
89
+ description: 'Ecosystems, biodiversity, pollution, and sustainability concepts.',
90
+ category: 'AP',
91
+ subject: 'environmental',
92
+ },
93
+ {
94
+ slug: 'ap-macroeconomics',
95
+ name: 'AP Macroeconomics',
96
+ description: 'GDP, inflation, fiscal and monetary policy, and international trade.',
97
+ category: 'AP',
98
+ subject: 'economics',
99
+ },
100
+ // ── IB ──────────────────────────────────────────────────────────
101
+ {
102
+ slug: 'ib-biology-hl',
103
+ name: 'IB Biology HL',
104
+ description: 'Higher Level biology: molecular biology, genetics, ecology, and human physiology.',
105
+ category: 'IB',
106
+ subject: 'biology',
107
+ },
108
+ {
109
+ slug: 'ib-chemistry-hl',
110
+ name: 'IB Chemistry HL',
111
+ description: 'Higher Level chemistry: organic, inorganic, physical, and analytical topics.',
112
+ category: 'IB',
113
+ subject: 'chemistry',
114
+ },
115
+ {
116
+ slug: 'ib-physics-hl',
117
+ name: 'IB Physics HL',
118
+ description: 'Higher Level physics: mechanics, fields, waves, and nuclear physics.',
119
+ category: 'IB',
120
+ subject: 'physics',
121
+ },
122
+ {
123
+ slug: 'ib-math-aa-hl',
124
+ name: 'IB Math AA HL',
125
+ description: 'Analysis & Approaches HL: calculus, proof, vectors, and complex numbers.',
126
+ category: 'IB',
127
+ subject: 'math',
128
+ },
129
+ {
130
+ slug: 'ib-math-ai-hl',
131
+ name: 'IB Math AI HL',
132
+ description: 'Applications & Interpretation HL: statistics, modelling, and technology use.',
133
+ category: 'IB',
134
+ subject: 'math',
135
+ },
136
+ {
137
+ slug: 'ib-history-hl',
138
+ name: 'IB History HL',
139
+ description: 'Higher Level history: 20th century world history and historical investigation.',
140
+ category: 'IB',
141
+ subject: 'history',
142
+ },
143
+ {
144
+ slug: 'ib-english-a-hl',
145
+ name: 'IB English A HL',
146
+ description: 'Language & Literature HL: textual analysis, comparative study, and IO prep.',
147
+ category: 'IB',
148
+ subject: 'literature',
149
+ },
150
+ {
151
+ slug: 'ib-economics-hl',
152
+ name: 'IB Economics HL',
153
+ description: 'Microeconomics, macroeconomics, international economics, and development.',
154
+ category: 'IB',
155
+ subject: 'economics',
156
+ },
157
+ {
158
+ slug: 'ib-psychology-hl',
159
+ name: 'IB Psychology HL',
160
+ description: 'Biological, cognitive, sociocultural, and abnormal psychology at HL depth.',
161
+ category: 'IB',
162
+ subject: 'psychology',
163
+ },
164
+ ];
package/src/lib/email.ts CHANGED
@@ -1,24 +1,46 @@
1
- import nodemailer from 'nodemailer';
1
+ import { Resend } from 'resend';
2
2
  import { logger } from './logger.js';
3
3
  import { env } from './env.js';
4
4
 
5
- // Commented out Resend flow as requested
6
- // import { Resend } from 'resend';
7
- // const resend = env.RESEND_API_KEY ? new Resend(env.RESEND_API_KEY) : null;
8
-
9
- const transporter = nodemailer.createTransport({
10
- host: env.SMTP_HOST,
11
- port: env.SMTP_PORT,
12
- secure: env.SMTP_SECURE,
13
- auth: {
14
- user: env.SMTP_USER,
15
- pass: env.SMTP_PASSWORD,
16
- },
17
- });
18
-
5
+ const resend = env.RESEND_API_KEY ? new Resend(env.RESEND_API_KEY) : null;
19
6
  const FROM_EMAIL = env.EMAIL_FROM;
20
7
  const APP_URL = env.FRONTEND_URL;
21
8
 
9
+ async function sendEmail(options: {
10
+ to: string;
11
+ subject: string;
12
+ html: string;
13
+ successLog: string;
14
+ missingConfigLog: string;
15
+ devLogDetail: string;
16
+ }): Promise<boolean> {
17
+ try {
18
+ if (!resend) {
19
+ logger.warn(`${options.missingConfigLog} Logging instead:`);
20
+ logger.info(options.devLogDetail);
21
+ return true;
22
+ }
23
+
24
+ const { data, error } = await resend.emails.send({
25
+ from: FROM_EMAIL,
26
+ to: options.to,
27
+ subject: options.subject,
28
+ html: options.html,
29
+ });
30
+
31
+ if (error) {
32
+ logger.error('Email send error:', error);
33
+ return false;
34
+ }
35
+
36
+ logger.info(options.successLog + (data?.id ? ` (id: ${data.id})` : ''));
37
+ return true;
38
+ } catch (err) {
39
+ logger.error('Email send error:', err);
40
+ return false;
41
+ }
42
+ }
43
+
22
44
  export async function sendVerificationEmail(
23
45
  email: string,
24
46
  token: string,
@@ -41,26 +63,14 @@ export async function sendVerificationEmail(
41
63
  </div>
42
64
  `;
43
65
 
44
- try {
45
- if (!env.SMTP_HOST) {
46
- logger.warn('Email service not configured (SMTP_HOST missing). Logging email content instead:');
47
- logger.info(`Verification Email to ${email}: ${verifyUrl}`);
48
- return true;
49
- }
50
-
51
- await transporter.sendMail({
52
- from: FROM_EMAIL,
53
- to: email,
54
- subject: 'Verify your email - Scribe',
55
- html,
56
- });
57
-
58
- logger.info(`Verification email sent to ${email}`);
59
- return true;
60
- } catch (err) {
61
- logger.error('Email send error:', err);
62
- return false;
63
- }
66
+ return sendEmail({
67
+ to: email,
68
+ subject: 'Verify your email - Scribe',
69
+ html,
70
+ successLog: `Verification email sent to ${email}`,
71
+ missingConfigLog: 'Email service not configured (RESEND_API_KEY missing).',
72
+ devLogDetail: `Verification Email to ${email}: ${verifyUrl}`,
73
+ });
64
74
  }
65
75
 
66
76
  export async function sendInvitationEmail(invitation: {
@@ -88,26 +98,14 @@ export async function sendInvitationEmail(invitation: {
88
98
  </div>
89
99
  `;
90
100
 
91
- try {
92
- if (!env.SMTP_HOST) {
93
- logger.warn('Email service not configured (SMTP_HOST missing). Logging invitation link instead:');
94
- logger.info(`Invitation Link for ${invitation.email}: ${inviteUrl}`);
95
- return true;
96
- }
97
-
98
- await transporter.sendMail({
99
- from: FROM_EMAIL,
100
- to: invitation.email,
101
- subject: `Invitation to join ${invitation.workspaceTitle} on Scribe`,
102
- html,
103
- });
104
-
105
- logger.info(`Invitation email sent to ${invitation.email}`);
106
- return true;
107
- } catch (err) {
108
- logger.error('Email send error:', err);
109
- return false;
110
- }
101
+ return sendEmail({
102
+ to: invitation.email,
103
+ subject: `Invitation to join ${invitation.workspaceTitle} on Scribe`,
104
+ html,
105
+ successLog: `Invitation email sent to ${invitation.email}`,
106
+ missingConfigLog: 'Email service not configured (RESEND_API_KEY missing).',
107
+ devLogDetail: `Invitation Link for ${invitation.email}: ${inviteUrl}`,
108
+ });
111
109
  }
112
110
 
113
111
  export async function sendAccountDeletionScheduledEmail(email: string, token: string): Promise<boolean> {
@@ -129,26 +127,14 @@ export async function sendAccountDeletionScheduledEmail(email: string, token: st
129
127
  </div>
130
128
  `;
131
129
 
132
- try {
133
- if (!env.SMTP_HOST) {
134
- logger.warn('Email service not configured (SMTP_HOST missing). Logging email content instead:');
135
- logger.info(`Account Deletion Scheduled Email to ${email}: ${restoreUrl}`);
136
- return true;
137
- }
138
-
139
- await transporter.sendMail({
140
- from: FROM_EMAIL,
141
- to: email,
142
- subject: 'Account Deletion Scheduled - Scribe',
143
- html,
144
- });
145
-
146
- logger.info(`Account deletion scheduled email sent to ${email}`);
147
- return true;
148
- } catch (err) {
149
- logger.error('Email send error:', err);
150
- return false;
151
- }
130
+ return sendEmail({
131
+ to: email,
132
+ subject: 'Account Deletion Scheduled - Scribe',
133
+ html,
134
+ successLog: `Account deletion scheduled email sent to ${email}`,
135
+ missingConfigLog: 'Email service not configured (RESEND_API_KEY missing).',
136
+ devLogDetail: `Account Deletion Scheduled Email to ${email}: ${restoreUrl}`,
137
+ });
152
138
  }
153
139
 
154
140
  export async function sendPasswordResetEmail(
@@ -172,26 +158,14 @@ export async function sendPasswordResetEmail(
172
158
  </div>
173
159
  `;
174
160
 
175
- try {
176
- if (!env.SMTP_HOST) {
177
- logger.warn('Email service not configured (SMTP_HOST missing). Logging reset link instead:');
178
- logger.info(`Password reset for ${email}: ${resetUrl}`);
179
- return true;
180
- }
181
-
182
- await transporter.sendMail({
183
- from: FROM_EMAIL,
184
- to: email,
185
- subject: 'Reset your password - Scribe',
186
- html,
187
- });
188
-
189
- logger.info(`Password reset email sent to ${email}`);
190
- return true;
191
- } catch (err) {
192
- logger.error('Email send error:', err);
193
- return false;
194
- }
161
+ return sendEmail({
162
+ to: email,
163
+ subject: 'Reset your password - Scribe',
164
+ html,
165
+ successLog: `Password reset email sent to ${email}`,
166
+ missingConfigLog: 'Email service not configured (RESEND_API_KEY missing).',
167
+ devLogDetail: `Password reset for ${email}: ${resetUrl}`,
168
+ });
195
169
  }
196
170
 
197
171
  export async function sendAccountRestoredEmail(email: string): Promise<boolean> {
@@ -207,24 +181,12 @@ export async function sendAccountRestoredEmail(email: string): Promise<boolean>
207
181
  </div>
208
182
  `;
209
183
 
210
- try {
211
- if (!env.SMTP_HOST) {
212
- logger.warn('Email service not configured (SMTP_HOST missing). Logging email content instead:');
213
- logger.info(`Account Restored Email to ${email}`);
214
- return true;
215
- }
216
-
217
- await transporter.sendMail({
218
- from: FROM_EMAIL,
219
- to: email,
220
- subject: 'Account Restored - Scribe',
221
- html,
222
- });
223
-
224
- logger.info(`Account restored email sent to ${email}`);
225
- return true;
226
- } catch (err) {
227
- logger.error('Email send error:', err);
228
- return false;
229
- }
184
+ return sendEmail({
185
+ to: email,
186
+ subject: 'Account Restored - Scribe',
187
+ html,
188
+ successLog: `Account restored email sent to ${email}`,
189
+ missingConfigLog: 'Email service not configured (RESEND_API_KEY missing).',
190
+ devLogDetail: `Account Restored Email to ${email}: ${loginUrl}`,
191
+ });
230
192
  }
@@ -0,0 +1,9 @@
1
+ export {
2
+ DEFAULT_EMBEDDING_DIM,
3
+ DEFAULT_EMBEDDING_MODEL,
4
+ embedQuery,
5
+ embedTexts,
6
+ toVectorLiteral,
7
+ } from './ai/embedding-client.js';
8
+
9
+ export type { EmbedOptions } from './ai/embedding-client.js';
@@ -0,0 +1,60 @@
1
+ import type { PrismaClient } from '@prisma/client';
2
+ import { CURATED_KB_SEEDS } from '../lib/curated-kb-seed.js';
3
+ import { logger } from '../lib/logger.js';
4
+
5
+ /**
6
+ * Ensures the curated AP/IB catalog exists. Idempotent — safe to call on every
7
+ * server boot. Matches existing KBs by slug stored in `meta.slug`.
8
+ */
9
+ export async function ensureCuratedKbCatalog(db: PrismaClient) {
10
+ let created = 0;
11
+
12
+ for (const seed of CURATED_KB_SEEDS) {
13
+ const existing =
14
+ (await db.knowledgeBase.findFirst({
15
+ where: {
16
+ meta: { path: ['slug'], equals: seed.slug },
17
+ },
18
+ })) ??
19
+ (await db.knowledgeBase.findFirst({
20
+ where: {
21
+ name: { equals: seed.name, mode: 'insensitive' },
22
+ },
23
+ }));
24
+
25
+ if (existing) {
26
+ await db.knowledgeBase.update({
27
+ where: { id: existing.id },
28
+ data: {
29
+ name: seed.name,
30
+ description: seed.description,
31
+ isCurated: true,
32
+ meta: {
33
+ slug: seed.slug,
34
+ category: seed.category,
35
+ subject: seed.subject,
36
+ },
37
+ },
38
+ });
39
+ continue;
40
+ }
41
+
42
+ await db.knowledgeBase.create({
43
+ data: {
44
+ name: seed.name,
45
+ description: seed.description,
46
+ isCurated: true,
47
+ meta: {
48
+ slug: seed.slug,
49
+ category: seed.category,
50
+ subject: seed.subject,
51
+ },
52
+ },
53
+ });
54
+ created += 1;
55
+ }
56
+
57
+ if (created > 0) {
58
+ logger.info(`Seeded ${created} curated knowledge base(s)`, 'KB');
59
+ }
60
+ }
package/src/lib/env.ts CHANGED
@@ -36,12 +36,8 @@ const envSchema = z.object({
36
36
  // CORS
37
37
  FRONTEND_URL: z.string().url().default('http://localhost:3000'),
38
38
 
39
- // Email
40
- SMTP_HOST: z.string(),
41
- SMTP_PORT: z.string().regex(/^\d+$/).default('587').transform(Number),
42
- SMTP_USER: z.string().optional(),
43
- SMTP_PASSWORD: z.string().optional(),
44
- SMTP_SECURE: z.enum(['true', 'false']).default('false').transform((v) => v === 'true'),
39
+ // Email (Resend)
40
+ RESEND_API_KEY: z.string().optional(),
45
41
  EMAIL_FROM: z.string().default('Scribe <hello@scribe.study>'),
46
42
  // Stripe
47
43
  STRIPE_SECRET_KEY: z.string().startsWith('sk_').optional(),
@@ -57,7 +53,6 @@ const envSchema = z.object({
57
53
  * Parsed and validated environment variables
58
54
  */
59
55
  export const env = envSchema.parse(process.env);
60
- // console.log('DEBUG: SMTP_HOST loaded:', env.SMTP_HOST ? 'Yes' : 'No');
61
56
 
62
57
  /**
63
58
  * Check if running in production
@@ -1,21 +1 @@
1
- import OpenAI from 'openai';
2
-
3
- const openai = new OpenAI({
4
- apiKey: process.env.INFERENCE_API_KEY,
5
- baseURL: process.env.INFERENCE_BASE_URL,
6
- });
7
-
8
- async function inference(messages: { role: 'system' | 'user' | 'assistant', content: string }[]) {
9
- try {
10
- const response = await openai.chat.completions.create({
11
- model: "command-a-03-2025",
12
- messages: messages,
13
- });
14
- return response;
15
- } catch (error) {
16
- // Inference error logged at call site
17
- throw error;
18
- }
19
- }
20
-
21
- export default inference;
1
+ export { complete as default, complete, completeText } from './ai/llm-client.js';