@talkpilot/core-db 1.3.84 → 1.3.85

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 (264) hide show
  1. package/.cursor/rules/development.mdc +65 -65
  2. package/AGENTS.md +49 -49
  3. package/DEVELOPMENT.md +141 -141
  4. package/README.md +846 -847
  5. package/dist/configuration/gptLive.seed.d.ts +2 -0
  6. package/dist/configuration/gptLive.seed.d.ts.map +1 -0
  7. package/dist/configuration/gptLive.seed.js +59 -0
  8. package/dist/configuration/gptLive.seed.js.map +1 -0
  9. package/dist/municipal/muniIssues/index.d.ts +2 -3
  10. package/dist/municipal/muniIssues/index.d.ts.map +1 -1
  11. package/dist/municipal/muniIssues/index.js +1 -4
  12. package/dist/municipal/muniIssues/index.js.map +1 -1
  13. package/dist/municipal/muniIssues/muniIssues.constants.d.ts +0 -2
  14. package/dist/municipal/muniIssues/muniIssues.constants.d.ts.map +1 -1
  15. package/dist/municipal/muniIssues/muniIssues.constants.js +1 -8
  16. package/dist/municipal/muniIssues/muniIssues.constants.js.map +1 -1
  17. package/dist/municipal/muniIssues/muniIssues.getters.d.ts +1 -4
  18. package/dist/municipal/muniIssues/muniIssues.getters.d.ts.map +1 -1
  19. package/dist/municipal/muniIssues/muniIssues.getters.js +1 -35
  20. package/dist/municipal/muniIssues/muniIssues.getters.js.map +1 -1
  21. package/dist/municipal/muniIssues/muniIssues.schema.d.ts.map +1 -1
  22. package/dist/municipal/muniIssues/muniIssues.schema.js +0 -17
  23. package/dist/municipal/muniIssues/muniIssues.schema.js.map +1 -1
  24. package/dist/municipal/muniIssues/muniIssues.setters.d.ts +1 -3
  25. package/dist/municipal/muniIssues/muniIssues.setters.d.ts.map +1 -1
  26. package/dist/municipal/muniIssues/muniIssues.setters.js +2 -46
  27. package/dist/municipal/muniIssues/muniIssues.setters.js.map +1 -1
  28. package/dist/municipal/muniIssues/muniIssues.types.d.ts +2 -22
  29. package/dist/municipal/muniIssues/muniIssues.types.d.ts.map +1 -1
  30. package/dist/talkpilot/clients/clients.quota.constants.d.ts +2 -0
  31. package/dist/talkpilot/clients/clients.quota.constants.d.ts.map +1 -0
  32. package/dist/talkpilot/clients/clients.quota.constants.js +5 -0
  33. package/dist/talkpilot/clients/clients.quota.constants.js.map +1 -0
  34. package/dist/talkpilot/clients/clients.quota.utils.d.ts +8 -0
  35. package/dist/talkpilot/clients/clients.quota.utils.d.ts.map +1 -0
  36. package/dist/talkpilot/clients/clients.quota.utils.js +45 -0
  37. package/dist/talkpilot/clients/clients.quota.utils.js.map +1 -0
  38. package/dist/talkpilot/contextNotes/contextNotes.getters.d.ts +7 -1
  39. package/dist/talkpilot/contextNotes/contextNotes.getters.d.ts.map +1 -1
  40. package/dist/talkpilot/contextNotes/contextNotes.getters.js +37 -1
  41. package/dist/talkpilot/contextNotes/contextNotes.getters.js.map +1 -1
  42. package/dist/talkpilot/contextNotes/contextNotes.types.d.ts +6 -0
  43. package/dist/talkpilot/contextNotes/contextNotes.types.d.ts.map +1 -1
  44. package/jest.config.js +20 -20
  45. package/package.json +46 -46
  46. package/src/__tests__/setup.ts +20 -20
  47. package/src/bulkWrite/__tests__/bulkWrite.spec.ts +65 -65
  48. package/src/bulkWrite/bulkWrite.ops.ts +45 -45
  49. package/src/bulkWrite/bulkWrite.types.ts +4 -4
  50. package/src/bulkWrite/index.ts +2 -2
  51. package/src/config.ts +9 -9
  52. package/src/configuration/index.ts +17 -17
  53. package/src/configuration/internalModels/index.ts +3 -3
  54. package/src/configuration/internalModels/internalModels.constants.ts +1 -1
  55. package/src/configuration/internalModels/internalModels.getters.ts +33 -33
  56. package/src/configuration/internalModels/internalModels.types.ts +12 -12
  57. package/src/configuration/models/__tests__/models.getters.spec.ts +67 -67
  58. package/src/configuration/models/index.ts +27 -27
  59. package/src/configuration/models/models.constants.ts +20 -20
  60. package/src/configuration/models/models.getters.ts +71 -71
  61. package/src/configuration/models/models.types.ts +80 -80
  62. package/src/configuration/mongodb-client.ts +62 -62
  63. package/src/configuration/prompts/index.ts +2 -2
  64. package/src/configuration/prompts/prompts.getters.ts +49 -49
  65. package/src/configuration/prompts/prompts.types.ts +11 -11
  66. package/src/connection.ts +81 -81
  67. package/src/index.ts +48 -48
  68. package/src/municipal/__tests__/validation.spec.ts +62 -62
  69. package/src/municipal/cities/cities.getters.ts +50 -50
  70. package/src/municipal/cities/cities.types.ts +11 -11
  71. package/src/municipal/cities/index.ts +2 -2
  72. package/src/municipal/departmentsSubjects/__tests__/departmentsSubjects.spec.ts +272 -272
  73. package/src/municipal/departmentsSubjects/departmentsSubjects.getters.ts +317 -317
  74. package/src/municipal/departmentsSubjects/departmentsSubjects.types.ts +73 -73
  75. package/src/municipal/departmentsSubjects/index.ts +9 -9
  76. package/src/municipal/index.ts +23 -23
  77. package/src/municipal/mongodb-client.ts +61 -61
  78. package/src/municipal/muniIssues/__tests__/muniIssues.setters.spec.ts +94 -219
  79. package/src/municipal/muniIssues/__tests__/muniIssues.setup.spec.ts +92 -93
  80. package/src/municipal/muniIssues/index.ts +17 -24
  81. package/src/municipal/muniIssues/muniIssues.constants.ts +18 -27
  82. package/src/municipal/muniIssues/muniIssues.getters.ts +24 -73
  83. package/src/municipal/muniIssues/muniIssues.schema.ts +66 -85
  84. package/src/municipal/muniIssues/muniIssues.setters.ts +24 -87
  85. package/src/municipal/muniIssues/muniIssues.setup.ts +65 -65
  86. package/src/municipal/muniIssues/muniIssues.types.ts +37 -67
  87. package/src/municipal/residents/__tests__/residents.spec.ts +92 -92
  88. package/src/municipal/residents/index.ts +4 -4
  89. package/src/municipal/residents/residents.constants.ts +2 -2
  90. package/src/municipal/residents/residents.getters.ts +42 -42
  91. package/src/municipal/residents/residents.schema.ts +28 -28
  92. package/src/municipal/residents/residents.types.ts +17 -17
  93. package/src/municipal/streets/__tests__/streets.spec.ts +253 -253
  94. package/src/municipal/streets/index.ts +2 -2
  95. package/src/municipal/streets/streets.getters.ts +140 -140
  96. package/src/municipal/streets/streets.types.ts +19 -19
  97. package/src/municipal/systemInstructions/__tests__/getters.spec.ts +113 -113
  98. package/src/municipal/systemInstructions/__tests__/setters.spec.ts +274 -274
  99. package/src/municipal/systemInstructions/index.ts +7 -7
  100. package/src/municipal/systemInstructions/instructions.getters.ts +57 -57
  101. package/src/municipal/systemInstructions/instructions.setters.ts +119 -119
  102. package/src/municipal/systemInstructions/instructions.types.ts +30 -30
  103. package/src/municipal/tickets/__tests__/tickets.getters.spec.ts +30 -30
  104. package/src/municipal/tickets/__tests__/tickets.statistics.spec.ts +99 -99
  105. package/src/municipal/tickets/index.ts +9 -9
  106. package/src/municipal/tickets/tickets.constants.ts +8 -8
  107. package/src/municipal/tickets/tickets.getters.ts +121 -121
  108. package/src/municipal/tickets/tickets.statistics.aggregation.ts +110 -110
  109. package/src/municipal/tickets/tickets.statistics.getters.ts +145 -145
  110. package/src/municipal/tickets/tickets.types.ts +54 -54
  111. package/src/municipal/utils/types.ts +11 -11
  112. package/src/talkpilot/__tests__/db.spec.ts +38 -38
  113. package/src/talkpilot/__tests__/mongodb-client.spec.ts +18 -18
  114. package/src/talkpilot/__tests__/validation.spec.ts +68 -68
  115. package/src/talkpilot/agents/__tests__/agents.getters.spec.ts +29 -29
  116. package/src/talkpilot/agents/agents.getters.ts +34 -34
  117. package/src/talkpilot/agents/agents.types.ts +14 -14
  118. package/src/talkpilot/agents/index.ts +2 -2
  119. package/src/talkpilot/backgroundToolResults/__tests__/backgroundToolResults.getters.spec.ts +147 -147
  120. package/src/talkpilot/backgroundToolResults/backgroundToolResults.getters.ts +65 -65
  121. package/src/talkpilot/backgroundToolResults/backgroundToolResults.types.ts +23 -23
  122. package/src/talkpilot/backgroundToolResults/index.ts +2 -2
  123. package/src/talkpilot/callTokenUsage/__tests__/callTokenUsage.getters.spec.ts +57 -57
  124. package/src/talkpilot/callTokenUsage/callTokenUsage.getters.ts +42 -42
  125. package/src/talkpilot/callTokenUsage/callTokenUsage.types.ts +28 -28
  126. package/src/talkpilot/callTokenUsage/index.ts +2 -2
  127. package/src/talkpilot/calls/__tests__/callStats.utils.spec.ts +128 -128
  128. package/src/talkpilot/calls/__tests__/calls.dashboard.spec.ts +229 -229
  129. package/src/talkpilot/calls/__tests__/calls.spec.ts +519 -519
  130. package/src/talkpilot/calls/__tests__/calls.statistics.spec.ts +483 -483
  131. package/src/talkpilot/calls/calls.constants.ts +57 -57
  132. package/src/talkpilot/calls/calls.getters.ts +295 -295
  133. package/src/talkpilot/calls/calls.statistics.getters.ts +668 -668
  134. package/src/talkpilot/calls/calls.statistics.types.ts +48 -48
  135. package/src/talkpilot/calls/calls.types.ts +168 -168
  136. package/src/talkpilot/calls/dashboard/calls.dashboard.ts +295 -295
  137. package/src/talkpilot/calls/dashboard/calls.dashboard.types.ts +57 -57
  138. package/src/talkpilot/calls/index.ts +6 -6
  139. package/src/talkpilot/clientAudioBuffers/__tests__/clientAudioBuffer.getters.spec.ts +160 -160
  140. package/src/talkpilot/clientAudioBuffers/clientAudioBuffer.getters.ts +117 -117
  141. package/src/talkpilot/clientAudioBuffers/clientsAudioBuffers.types.ts +25 -25
  142. package/src/talkpilot/clientAudioBuffers/index.ts +2 -2
  143. package/src/talkpilot/clients/__tests__/clients.quota.spec.ts +123 -123
  144. package/src/talkpilot/clients/clients.getters.ts +19 -19
  145. package/src/talkpilot/clients/clients.quota.getters.ts +119 -119
  146. package/src/talkpilot/clients/clients.quota.types.ts +27 -27
  147. package/src/talkpilot/clients/clients.types.ts +18 -18
  148. package/src/talkpilot/clients/index.ts +4 -4
  149. package/src/talkpilot/clientsConfig/__tests__/clientsConfig.getters.spec.ts +423 -423
  150. package/src/talkpilot/clientsConfig/__tests__/clientsConfig.spec.ts +212 -212
  151. package/src/talkpilot/clientsConfig/clientsConfig.constants.ts +2 -2
  152. package/src/talkpilot/clientsConfig/clientsConfig.getters.ts +247 -247
  153. package/src/talkpilot/clientsConfig/clientsConfig.types.ts +137 -137
  154. package/src/talkpilot/clientsConfig/index.ts +3 -3
  155. package/src/talkpilot/contextNotes/__tests__/contextNotes.getters.spec.ts +358 -217
  156. package/src/talkpilot/contextNotes/contextNotes.getters.ts +159 -85
  157. package/src/talkpilot/contextNotes/contextNotes.types.ts +27 -20
  158. package/src/talkpilot/contextNotes/index.ts +2 -2
  159. package/src/talkpilot/flows/__tests__/flows.schema.spec.ts +152 -152
  160. package/src/talkpilot/flows/flows.getter.ts +34 -34
  161. package/src/talkpilot/flows/flows.schema.ts +196 -196
  162. package/src/talkpilot/flows/flows.types.ts +220 -220
  163. package/src/talkpilot/flows/index.ts +7 -7
  164. package/src/talkpilot/groups/__tests__/groups.spec.ts +90 -90
  165. package/src/talkpilot/groups/__tests__/phone.utils.spec.ts +32 -32
  166. package/src/talkpilot/groups/groups.getters.ts +30 -30
  167. package/src/talkpilot/groups/groups.types.ts +29 -29
  168. package/src/talkpilot/groups/index.ts +3 -3
  169. package/src/talkpilot/groups/phone.utils.ts +46 -46
  170. package/src/talkpilot/index.ts +32 -32
  171. package/src/talkpilot/leads/index.ts +2 -2
  172. package/src/talkpilot/leads/leads.getter.ts +6 -6
  173. package/src/talkpilot/leads/leads.schema.ts +33 -33
  174. package/src/talkpilot/leads/leads.types.ts +20 -20
  175. package/src/talkpilot/mongodb-client.ts +78 -78
  176. package/src/talkpilot/phone_numbers/__tests__/phone_numbers.spec.ts +530 -530
  177. package/src/talkpilot/phone_numbers/index.ts +2 -2
  178. package/src/talkpilot/phone_numbers/phone_numbers.getter.ts +240 -240
  179. package/src/talkpilot/phone_numbers/phone_numbers.schema.ts +17 -17
  180. package/src/talkpilot/phone_numbers/phone_numbers.types.ts +30 -30
  181. package/src/talkpilot/phone_numbers/phone_numbers.utils.ts +9 -9
  182. package/src/talkpilot/plans/__tests__/plans.spec.ts +70 -70
  183. package/src/talkpilot/plans/index.ts +2 -2
  184. package/src/talkpilot/plans/plans.getters.ts +132 -132
  185. package/src/talkpilot/plans/plans.types.ts +89 -89
  186. package/src/talkpilot/products/__tests__/products.getters.spec.ts +44 -44
  187. package/src/talkpilot/products/index.ts +2 -2
  188. package/src/talkpilot/products/products.getters.ts +12 -12
  189. package/src/talkpilot/products/products.types.ts +9 -9
  190. package/src/talkpilot/results/index.ts +7 -7
  191. package/src/talkpilot/results/results.getter.ts +39 -39
  192. package/src/talkpilot/results/results.schema.ts +25 -25
  193. package/src/talkpilot/results/results.types.ts +34 -34
  194. package/src/talkpilot/retry_analyze/__tests__/retryAnalyze.getters.spec.ts +156 -156
  195. package/src/talkpilot/retry_analyze/index.ts +2 -2
  196. package/src/talkpilot/retry_analyze/retryAnalyze.getters.ts +84 -84
  197. package/src/talkpilot/retry_analyze/retryAnalyze.types.ts +13 -13
  198. package/src/talkpilot/sessions/__tests__/sessions.spec.ts +147 -147
  199. package/src/talkpilot/sessions/index.ts +2 -2
  200. package/src/talkpilot/sessions/sessions.getter.ts +92 -92
  201. package/src/talkpilot/sessions/sessions.schema.ts +34 -34
  202. package/src/talkpilot/sessions/sessions.types.ts +30 -30
  203. package/src/talkpilot/subscriptions/__tests__/subscriptions.getters.utils.spec.ts +45 -45
  204. package/src/talkpilot/subscriptions/index.ts +3 -3
  205. package/src/talkpilot/subscriptions/subscriptions.getters.ts +146 -146
  206. package/src/talkpilot/subscriptions/subscriptions.getters.utils.ts +33 -33
  207. package/src/talkpilot/subscriptions/subscriptions.types.ts +66 -66
  208. package/src/talkpilot/utils/__tests__/query.utils.spec.ts +49 -49
  209. package/src/talkpilot/utils/query.utils.ts +21 -21
  210. package/src/test-utils/db-utils.ts +33 -33
  211. package/src/test-utils/factories/index.ts +19 -19
  212. package/src/test-utils/factories/municipal/cities.ts +16 -16
  213. package/src/test-utils/factories/municipal/departmentsSubjects.ts +37 -37
  214. package/src/test-utils/factories/municipal/muniIssues.ts +32 -32
  215. package/src/test-utils/factories/municipal/residents.ts +20 -20
  216. package/src/test-utils/factories/municipal/streets.ts +22 -22
  217. package/src/test-utils/factories/municipal/tickets.ts +39 -39
  218. package/src/test-utils/factories/talkpilot/agents.ts +19 -19
  219. package/src/test-utils/factories/talkpilot/calls.ts +37 -37
  220. package/src/test-utils/factories/talkpilot/clientAudioBuffers.ts +20 -20
  221. package/src/test-utils/factories/talkpilot/clientsConfig.ts +18 -18
  222. package/src/test-utils/factories/talkpilot/contextNotes.ts +40 -40
  223. package/src/test-utils/factories/talkpilot/flows.ts +33 -33
  224. package/src/test-utils/factories/talkpilot/groups.ts +33 -33
  225. package/src/test-utils/factories/talkpilot/phone_numbers.ts +22 -22
  226. package/src/test-utils/factories/talkpilot/sessions.ts +35 -35
  227. package/src/test-utils/factories/websitalk/knowledgeDocuments.ts +29 -29
  228. package/src/test-utils/factories/websitalk/scanResources.ts +26 -26
  229. package/src/test-utils/factories/websitalk/scans.ts +30 -30
  230. package/src/test-utils/factories/websitalk/websiteUrls.ts +17 -17
  231. package/src/utils/date.utils.ts +126 -126
  232. package/src/utils/shared.types.ts +4 -4
  233. package/src/utils/validation.ts +23 -23
  234. package/src/websitalk/index.ts +18 -18
  235. package/src/websitalk/knowledgeDocuments/__tests__/knowledgeDocuments.spec.ts +238 -238
  236. package/src/websitalk/knowledgeDocuments/index.ts +3 -3
  237. package/src/websitalk/knowledgeDocuments/knowledgeDocuments.constants.ts +26 -26
  238. package/src/websitalk/knowledgeDocuments/knowledgeDocuments.getters.ts +95 -95
  239. package/src/websitalk/knowledgeDocuments/knowledgeDocuments.types.ts +75 -75
  240. package/src/websitalk/mongodb-client.ts +61 -61
  241. package/src/websitalk/scanResources/__tests__/scanResources.spec.ts +267 -267
  242. package/src/websitalk/scanResources/index.ts +4 -4
  243. package/src/websitalk/scanResources/scanResources.constants.ts +60 -60
  244. package/src/websitalk/scanResources/scanResources.getters.ts +128 -128
  245. package/src/websitalk/scanResources/scanResources.types.ts +105 -105
  246. package/src/websitalk/scanResources/scanResources.utils.ts +31 -31
  247. package/src/websitalk/scans/__tests__/scans.spec.ts +362 -362
  248. package/src/websitalk/scans/index.ts +4 -4
  249. package/src/websitalk/scans/scans.constants.ts +18 -18
  250. package/src/websitalk/scans/scans.getters.ts +172 -172
  251. package/src/websitalk/scans/scans.types.ts +58 -58
  252. package/src/websitalk/scans/scans.utils.ts +5 -5
  253. package/src/websitalk/websiteUrls/__tests__/websiteUrls.spec.ts +77 -77
  254. package/src/websitalk/websiteUrls/index.ts +2 -2
  255. package/src/websitalk/websiteUrls/websiteUrls.getters.ts +65 -65
  256. package/src/websitalk/websiteUrls/websiteUrls.types.ts +13 -13
  257. package/tsconfig.json +23 -23
  258. package/dist/municipal/muniIssues/muniIssues.utils.d.ts +0 -3
  259. package/dist/municipal/muniIssues/muniIssues.utils.d.ts.map +0 -1
  260. package/dist/municipal/muniIssues/muniIssues.utils.js +0 -6
  261. package/dist/municipal/muniIssues/muniIssues.utils.js.map +0 -1
  262. package/src/municipal/muniIssues/__tests__/muniIssues.getters.spec.ts +0 -87
  263. package/src/municipal/muniIssues/__tests__/muniIssues.utils.spec.ts +0 -17
  264. package/src/municipal/muniIssues/muniIssues.utils.ts +0 -6
@@ -1,85 +1,159 @@
1
- import { Collection, ObjectId, WithId } from "mongodb";
2
- import { getDb } from "../index";
3
- import type { ContextNote, ContextNoteEntry } from "./contextNotes.types";
4
-
5
- export const getContextNotesCollection = (): Collection<ContextNote> => {
6
- return getDb().collection<ContextNote>("contextNotes");
7
- };
8
-
9
- /** Returns all context note documents matching a clientId and product. */
10
- export const getContextNotes = (
11
- clientId: string,
12
- product: string,
13
- ): Promise<WithId<ContextNote>[]> => {
14
- return getContextNotesCollection().find({ clientId, product }).toArray();
15
- };
16
-
17
- /** Returns all currently active note entries across matching documents */
18
- export const getActiveContextNotes = async (
19
- clientId: string,
20
- product: string,
21
- ): Promise<ContextNoteEntry[]> => {
22
- const docs = await getContextNotes(clientId, product);
23
- const now = new Date();
24
- return docs.flatMap((doc) =>
25
- doc.notes.filter(
26
- (note) =>
27
- note.activeFrom <= now &&
28
- (note.expiresAt === null || note.expiresAt > now),
29
- ),
30
- );
31
- };
32
-
33
- /** Creates a new context note document. */
34
- export const createContextNote = (
35
- data: Omit<ContextNote, "_id">,
36
- ): Promise<ObjectId> => {
37
- return getContextNotesCollection()
38
- .insertOne({ ...data, _id: new ObjectId() } as ContextNote)
39
- .then((r) => r.insertedId);
40
- };
41
-
42
- /** Replaces the full notes array on a context note document. */
43
- export const setContextNoteEntries = async (
44
- id: ObjectId,
45
- clientId: string,
46
- notes: ContextNoteEntry[],
47
- ): Promise<boolean> => {
48
- const result = await getContextNotesCollection().updateOne(
49
- { _id: id, clientId },
50
- { $set: { notes } },
51
- );
52
- return result.matchedCount > 0;
53
- };
54
-
55
- /** Updates the configuration fields (systemPrompt, product) on a context note document. */
56
- export const setContextNoteConfig = async (
57
- id: ObjectId,
58
- clientId: string,
59
- config: { systemPrompt?: string; product?: string },
60
- ): Promise<boolean> => {
61
- const fields: Partial<ContextNote> = {};
62
- if (config.systemPrompt !== undefined)
63
- fields.systemPrompt = config.systemPrompt;
64
- if (config.product !== undefined) fields.product = config.product;
65
- if (!Object.keys(fields).length) return false;
66
-
67
- const result = await getContextNotesCollection().updateOne(
68
- { _id: id, clientId },
69
- { $set: fields },
70
- );
71
- return result.matchedCount > 0;
72
- };
73
-
74
- /** Removes a single note entry from a document by its _id. */
75
- export const deleteContextNoteEntry = async (
76
- id: ObjectId,
77
- clientId: string,
78
- noteId: ObjectId,
79
- ): Promise<boolean> => {
80
- const result = await getContextNotesCollection().updateOne(
81
- { _id: id, clientId },
82
- { $pull: { notes: { _id: noteId } as any } },
83
- );
84
- return result.modifiedCount > 0;
85
- };
1
+ import { Collection, ObjectId, WithId } from "mongodb";
2
+ import { getDb } from "../index";
3
+ import type {
4
+ ContextNote,
5
+ ContextNoteEntry,
6
+ ContextNoteEntryWrite,
7
+ } from "./contextNotes.types";
8
+
9
+ export const getContextNotesCollection = (): Collection<ContextNote> => {
10
+ return getDb().collection<ContextNote>("contextNotes");
11
+ };
12
+
13
+ /** Returns all context note documents matching a clientId and product. */
14
+ export const getContextNotes = (
15
+ clientId: string,
16
+ product: string,
17
+ ): Promise<WithId<ContextNote>[]> => {
18
+ return getContextNotesCollection().find({ clientId, product }).toArray();
19
+ };
20
+
21
+ /** Returns all currently active note entries across matching documents */
22
+ export const getActiveContextNotes = async (
23
+ clientId: string,
24
+ product: string,
25
+ ): Promise<ContextNoteEntry[]> => {
26
+ const docs = await getContextNotes(clientId, product);
27
+ const now = new Date();
28
+ return docs.flatMap((doc) =>
29
+ doc.notes.filter(
30
+ (note) =>
31
+ note.activeFrom <= now &&
32
+ (note.expiresAt === null || note.expiresAt > now),
33
+ ),
34
+ );
35
+ };
36
+
37
+ /** Creates a new context note document. */
38
+ export const createContextNote = (
39
+ data: Omit<ContextNote, "_id">,
40
+ ): Promise<ObjectId> => {
41
+ return getContextNotesCollection()
42
+ .insertOne({ ...data, _id: new ObjectId() } as ContextNote)
43
+ .then((r) => r.insertedId);
44
+ };
45
+
46
+ /** Replaces the full notes array on a context note document. */
47
+ export const setContextNoteEntries = async (
48
+ id: ObjectId,
49
+ clientId: string,
50
+ notes: ContextNoteEntry[],
51
+ ): Promise<boolean> => {
52
+ const result = await getContextNotesCollection().updateOne(
53
+ { _id: id, clientId },
54
+ { $set: { notes } },
55
+ );
56
+ return result.matchedCount > 0;
57
+ };
58
+
59
+ /** Updates the configuration fields (systemPrompt, product) on a context note document. */
60
+ export const setContextNoteConfig = async (
61
+ id: ObjectId,
62
+ clientId: string,
63
+ config: { systemPrompt?: string; product?: string },
64
+ ): Promise<boolean> => {
65
+ const fields: Partial<ContextNote> = {};
66
+ if (config.systemPrompt !== undefined)
67
+ fields.systemPrompt = config.systemPrompt;
68
+ if (config.product !== undefined) fields.product = config.product;
69
+ if (!Object.keys(fields).length) return false;
70
+
71
+ const result = await getContextNotesCollection().updateOne(
72
+ { _id: id, clientId },
73
+ { $set: fields },
74
+ );
75
+ return result.matchedCount > 0;
76
+ };
77
+
78
+ const findNoteEntryById = (
79
+ doc: WithId<ContextNote> | null,
80
+ noteId: ObjectId,
81
+ ): ContextNoteEntry | null =>
82
+ doc?.notes.find((note) => note._id.equals(noteId)) ?? null;
83
+
84
+ /** Appends one note. Other notes on the document are left untouched. */
85
+ export const appendContextNoteEntry = async (
86
+ clientId: string,
87
+ product: string,
88
+ entry: ContextNoteEntryWrite,
89
+ now: Date = new Date(),
90
+ ): Promise<ContextNoteEntry> => {
91
+ const note: ContextNoteEntry = {
92
+ _id: new ObjectId(),
93
+ title: entry.title,
94
+ content: entry.content,
95
+ activeFrom: entry.activeFrom,
96
+ expiresAt: entry.expiresAt,
97
+ createdAt: now,
98
+ updatedAt: now,
99
+ };
100
+
101
+ const saved = await getContextNotesCollection().findOneAndUpdate(
102
+ { clientId, product },
103
+ { $push: { notes: note } },
104
+ { upsert: true, returnDocument: "after" },
105
+ );
106
+
107
+ return findNoteEntryById(saved, note._id) ?? note;
108
+ };
109
+
110
+ /** Replaces one note's fields. Other notes on the document are left untouched. */
111
+ export const updateContextNoteEntryFields = async (
112
+ clientId: string,
113
+ product: string,
114
+ noteId: ObjectId,
115
+ entry: ContextNoteEntryWrite,
116
+ now: Date = new Date(),
117
+ ): Promise<ContextNoteEntry | null> => {
118
+ const saved = await getContextNotesCollection().findOneAndUpdate(
119
+ { clientId, product, "notes._id": noteId },
120
+ {
121
+ $set: {
122
+ "notes.$.title": entry.title,
123
+ "notes.$.content": entry.content,
124
+ "notes.$.activeFrom": entry.activeFrom,
125
+ "notes.$.expiresAt": entry.expiresAt,
126
+ "notes.$.updatedAt": now,
127
+ },
128
+ },
129
+ { returnDocument: "after" },
130
+ );
131
+
132
+ return findNoteEntryById(saved, noteId);
133
+ };
134
+
135
+ /** Removes one note by id. Other notes on the document are left untouched. */
136
+ export const pullContextNoteEntry = async (
137
+ clientId: string,
138
+ product: string,
139
+ noteId: ObjectId,
140
+ ): Promise<boolean> => {
141
+ const result = await getContextNotesCollection().updateOne(
142
+ { clientId, product, "notes._id": noteId },
143
+ { $pull: { notes: { _id: noteId } } },
144
+ );
145
+ return result.modifiedCount > 0;
146
+ };
147
+
148
+ /** Removes a single note entry from a document by its _id. */
149
+ export const deleteContextNoteEntry = async (
150
+ id: ObjectId,
151
+ clientId: string,
152
+ noteId: ObjectId,
153
+ ): Promise<boolean> => {
154
+ const result = await getContextNotesCollection().updateOne(
155
+ { _id: id, clientId },
156
+ { $pull: { notes: { _id: noteId } as any } },
157
+ );
158
+ return result.modifiedCount > 0;
159
+ };
@@ -1,20 +1,27 @@
1
- import { ObjectId } from "mongodb";
2
-
3
- export type ContextNoteEntry = {
4
- _id: ObjectId;
5
- title: string;
6
- content: string;
7
- activeFrom: Date;
8
- expiresAt: Date | null;
9
- createdAt: Date;
10
- updatedAt: Date;
11
- };
12
-
13
- export type ContextNote = {
14
- _id: ObjectId;
15
- clientId: string;
16
- product: string;
17
- notes: ContextNoteEntry[];
18
- /** instructions for how the LLM should treat context info */
19
- systemPrompt?: string;
20
- };
1
+ import { ObjectId } from "mongodb";
2
+
3
+ export type ContextNoteEntry = {
4
+ _id: ObjectId;
5
+ title: string;
6
+ content: string;
7
+ activeFrom: Date;
8
+ expiresAt: Date | null;
9
+ createdAt: Date;
10
+ updatedAt: Date;
11
+ };
12
+
13
+ export type ContextNoteEntryWrite = {
14
+ title: string;
15
+ content: string;
16
+ activeFrom: Date;
17
+ expiresAt: Date | null;
18
+ };
19
+
20
+ export type ContextNote = {
21
+ _id: ObjectId;
22
+ clientId: string;
23
+ product: string;
24
+ notes: ContextNoteEntry[];
25
+ /** instructions for how the LLM should treat context info */
26
+ systemPrompt?: string;
27
+ };
@@ -1,2 +1,2 @@
1
- export * from "./contextNotes.types";
2
- export * from "./contextNotes.getters";
1
+ export * from "./contextNotes.types";
2
+ export * from "./contextNotes.getters";
@@ -1,152 +1,152 @@
1
- import { Document } from "mongodb";
2
- import { getDb } from "../../index";
3
- import { flowMongoSchema } from "../flows.schema";
4
-
5
- describe("flowMongoSchema", () => {
6
- it("defines disableGenericPrompt as optional bool", () => {
7
- const schema: any = flowMongoSchema;
8
-
9
- expect(schema.properties).toHaveProperty("disableGenericPrompt");
10
- expect(schema.properties.disableGenericPrompt.bsonType).toBe("bool");
11
- expect(schema.required).not.toContain("disableGenericPrompt");
12
- });
13
-
14
- it("allows legacy flows without disableGenericPrompt", async () => {
15
- const collection = await getDb().createCollection("legacy_flows", {
16
- validator: { $jsonSchema: flowMongoSchema as Document },
17
- });
18
-
19
- await expect(
20
- collection.insertOne({
21
- flowName: "Legacy Flow",
22
- systemInstructions: "Use the default instructions.",
23
- initialSentence: "Hello",
24
- interactions: [],
25
- }),
26
- ).resolves.toBeDefined();
27
- });
28
-
29
- it("defines conversationSettings as optional object or null", () => {
30
- const schema: any = flowMongoSchema;
31
-
32
- expect(schema.properties).toHaveProperty("conversationSettings");
33
- expect(schema.properties.conversationSettings.bsonType).toEqual([
34
- "object",
35
- "null",
36
- ]);
37
- expect(schema.required).not.toContain("conversationSettings");
38
- expect(schema.additionalProperties).toBe(false);
39
- });
40
-
41
- it("defines conversationSettings with expected nested properties", () => {
42
- const schema: any = flowMongoSchema;
43
- const convSettings = schema.properties.conversationSettings.properties;
44
-
45
- expect(convSettings).toHaveProperty("interruptions");
46
- expect(convSettings.interruptions.bsonType).toEqual(["object", "null"]);
47
-
48
- const interruptions = convSettings.interruptions.properties;
49
- expect(interruptions.enableInterruptionDetection.bsonType).toEqual("bool");
50
- expect(interruptions.interruptionWindowSeconds.bsonType).toEqual("number");
51
- expect(interruptions.interruptionThresholdSeconds.bsonType).toEqual(
52
- "number",
53
- );
54
- expect(interruptions.interruptionInstruction.bsonType).toEqual("string");
55
-
56
- expect(convSettings).toHaveProperty("silence");
57
- expect(convSettings.silence.bsonType).toEqual(["object", "null"]);
58
-
59
- const silence = convSettings.silence.properties;
60
- expect(silence.enableSilenceDetection.bsonType).toEqual("bool");
61
- expect(silence.firstWarningSilenceSeconds.bsonType).toEqual("number");
62
- expect(silence.firstWarningInstruction.bsonType).toEqual("string");
63
- expect(silence.secondWarningSilenceSeconds.bsonType).toEqual("number");
64
- expect(silence.secondWarningInstruction.bsonType).toEqual("string");
65
- expect(silence.disconnectSilenceSeconds.bsonType).toEqual("number");
66
- expect(convSettings).toHaveProperty("liveTimeUpdates");
67
- expect(convSettings.liveTimeUpdates.bsonType).toEqual("bool");
68
- });
69
-
70
- it("should define tools schema and return a backgroundToolType enum with allowed values", () => {
71
- const schema: any = flowMongoSchema;
72
-
73
- expect(schema.properties).toHaveProperty("tools");
74
- expect(schema.properties.tools.bsonType).toEqual(["array", "null"]);
75
-
76
- const toolItem = schema.properties.tools.items;
77
- expect(toolItem.bsonType).toBe("object");
78
-
79
- expect(toolItem.properties).toHaveProperty("runInBackground");
80
- expect(toolItem.properties.runInBackground.bsonType).toBe("bool");
81
-
82
- expect(toolItem.properties).toHaveProperty("useRedisTranscription");
83
- expect(toolItem.properties.useRedisTranscription.bsonType).toBe("bool");
84
-
85
- expect(toolItem.properties).toHaveProperty("backgroundToolType");
86
- expect(toolItem.properties.backgroundToolType.bsonType).toBe("string");
87
- expect(toolItem.properties.backgroundToolType.enum).toEqual([
88
- "backgroundToolAlways",
89
- "backgroundToolOnce",
90
- ]);
91
-
92
- expect(toolItem.properties).toHaveProperty(
93
- "backgroundContinuationInstructions",
94
- );
95
- expect(
96
- toolItem.properties.backgroundContinuationInstructions.bsonType,
97
- ).toBe("string");
98
- });
99
-
100
- it("defines internalTools as an optional map of tool configs", () => {
101
- const schema: any = flowMongoSchema;
102
-
103
- expect(schema.properties).toHaveProperty("internalTools");
104
- expect(schema.required).not.toContain("internalTools");
105
- expect(schema.properties.internalTools.bsonType).toEqual([
106
- "object",
107
- "null",
108
- ]);
109
-
110
- const toolConfig = schema.properties.internalTools.additionalProperties;
111
- expect(toolConfig.required).toEqual(["enabled"]);
112
- expect(toolConfig.properties.enabled.bsonType).toBe("bool");
113
- expect(toolConfig.properties.maxCalls.bsonType).toEqual(["number", "null"]);
114
-
115
- const param = toolConfig.properties.params.additionalProperties;
116
- expect(param.properties.value.bsonType).toEqual([
117
- "string",
118
- "number",
119
- "bool",
120
- "array",
121
- "null",
122
- ]);
123
- });
124
-
125
- it("defines beforeCallEvent as an optional object with url, and afterCallEvent as optional string or null", () => {
126
- const schema: any = flowMongoSchema;
127
-
128
- expect(schema.properties).toHaveProperty("beforeCallEvent");
129
- expect(schema.properties.beforeCallEvent.bsonType).toEqual(["object", "null"]);
130
- expect(schema.properties.beforeCallEvent.required).toEqual(["url"]);
131
- expect(schema.properties.beforeCallEvent.properties).toEqual(
132
- expect.objectContaining({
133
- url: { bsonType: "string" },
134
- timeoutMs: { bsonType: ["number", "null"] },
135
- sendUserAuthToken: { bsonType: ["bool", "null"] },
136
- wait: { bsonType: ["bool", "null"] },
137
- })
138
- );
139
- expect(schema.properties.beforeCallEvent.properties.allowedKeys).toEqual({
140
- bsonType: ["array", "null"],
141
- items: { bsonType: "string" },
142
- });
143
- expect(schema.required).not.toContain("beforeCallEvent");
144
-
145
- expect(schema.properties).toHaveProperty("afterCallEvent");
146
- expect(schema.properties.afterCallEvent.bsonType).toEqual([
147
- "string",
148
- "null",
149
- ]);
150
- expect(schema.required).not.toContain("afterCallEvent");
151
- });
152
- });
1
+ import { Document } from "mongodb";
2
+ import { getDb } from "../../index";
3
+ import { flowMongoSchema } from "../flows.schema";
4
+
5
+ describe("flowMongoSchema", () => {
6
+ it("defines disableGenericPrompt as optional bool", () => {
7
+ const schema: any = flowMongoSchema;
8
+
9
+ expect(schema.properties).toHaveProperty("disableGenericPrompt");
10
+ expect(schema.properties.disableGenericPrompt.bsonType).toBe("bool");
11
+ expect(schema.required).not.toContain("disableGenericPrompt");
12
+ });
13
+
14
+ it("allows legacy flows without disableGenericPrompt", async () => {
15
+ const collection = await getDb().createCollection("legacy_flows", {
16
+ validator: { $jsonSchema: flowMongoSchema as Document },
17
+ });
18
+
19
+ await expect(
20
+ collection.insertOne({
21
+ flowName: "Legacy Flow",
22
+ systemInstructions: "Use the default instructions.",
23
+ initialSentence: "Hello",
24
+ interactions: [],
25
+ }),
26
+ ).resolves.toBeDefined();
27
+ });
28
+
29
+ it("defines conversationSettings as optional object or null", () => {
30
+ const schema: any = flowMongoSchema;
31
+
32
+ expect(schema.properties).toHaveProperty("conversationSettings");
33
+ expect(schema.properties.conversationSettings.bsonType).toEqual([
34
+ "object",
35
+ "null",
36
+ ]);
37
+ expect(schema.required).not.toContain("conversationSettings");
38
+ expect(schema.additionalProperties).toBe(false);
39
+ });
40
+
41
+ it("defines conversationSettings with expected nested properties", () => {
42
+ const schema: any = flowMongoSchema;
43
+ const convSettings = schema.properties.conversationSettings.properties;
44
+
45
+ expect(convSettings).toHaveProperty("interruptions");
46
+ expect(convSettings.interruptions.bsonType).toEqual(["object", "null"]);
47
+
48
+ const interruptions = convSettings.interruptions.properties;
49
+ expect(interruptions.enableInterruptionDetection.bsonType).toEqual("bool");
50
+ expect(interruptions.interruptionWindowSeconds.bsonType).toEqual("number");
51
+ expect(interruptions.interruptionThresholdSeconds.bsonType).toEqual(
52
+ "number",
53
+ );
54
+ expect(interruptions.interruptionInstruction.bsonType).toEqual("string");
55
+
56
+ expect(convSettings).toHaveProperty("silence");
57
+ expect(convSettings.silence.bsonType).toEqual(["object", "null"]);
58
+
59
+ const silence = convSettings.silence.properties;
60
+ expect(silence.enableSilenceDetection.bsonType).toEqual("bool");
61
+ expect(silence.firstWarningSilenceSeconds.bsonType).toEqual("number");
62
+ expect(silence.firstWarningInstruction.bsonType).toEqual("string");
63
+ expect(silence.secondWarningSilenceSeconds.bsonType).toEqual("number");
64
+ expect(silence.secondWarningInstruction.bsonType).toEqual("string");
65
+ expect(silence.disconnectSilenceSeconds.bsonType).toEqual("number");
66
+ expect(convSettings).toHaveProperty("liveTimeUpdates");
67
+ expect(convSettings.liveTimeUpdates.bsonType).toEqual("bool");
68
+ });
69
+
70
+ it("should define tools schema and return a backgroundToolType enum with allowed values", () => {
71
+ const schema: any = flowMongoSchema;
72
+
73
+ expect(schema.properties).toHaveProperty("tools");
74
+ expect(schema.properties.tools.bsonType).toEqual(["array", "null"]);
75
+
76
+ const toolItem = schema.properties.tools.items;
77
+ expect(toolItem.bsonType).toBe("object");
78
+
79
+ expect(toolItem.properties).toHaveProperty("runInBackground");
80
+ expect(toolItem.properties.runInBackground.bsonType).toBe("bool");
81
+
82
+ expect(toolItem.properties).toHaveProperty("useRedisTranscription");
83
+ expect(toolItem.properties.useRedisTranscription.bsonType).toBe("bool");
84
+
85
+ expect(toolItem.properties).toHaveProperty("backgroundToolType");
86
+ expect(toolItem.properties.backgroundToolType.bsonType).toBe("string");
87
+ expect(toolItem.properties.backgroundToolType.enum).toEqual([
88
+ "backgroundToolAlways",
89
+ "backgroundToolOnce",
90
+ ]);
91
+
92
+ expect(toolItem.properties).toHaveProperty(
93
+ "backgroundContinuationInstructions",
94
+ );
95
+ expect(
96
+ toolItem.properties.backgroundContinuationInstructions.bsonType,
97
+ ).toBe("string");
98
+ });
99
+
100
+ it("defines internalTools as an optional map of tool configs", () => {
101
+ const schema: any = flowMongoSchema;
102
+
103
+ expect(schema.properties).toHaveProperty("internalTools");
104
+ expect(schema.required).not.toContain("internalTools");
105
+ expect(schema.properties.internalTools.bsonType).toEqual([
106
+ "object",
107
+ "null",
108
+ ]);
109
+
110
+ const toolConfig = schema.properties.internalTools.additionalProperties;
111
+ expect(toolConfig.required).toEqual(["enabled"]);
112
+ expect(toolConfig.properties.enabled.bsonType).toBe("bool");
113
+ expect(toolConfig.properties.maxCalls.bsonType).toEqual(["number", "null"]);
114
+
115
+ const param = toolConfig.properties.params.additionalProperties;
116
+ expect(param.properties.value.bsonType).toEqual([
117
+ "string",
118
+ "number",
119
+ "bool",
120
+ "array",
121
+ "null",
122
+ ]);
123
+ });
124
+
125
+ it("defines beforeCallEvent as an optional object with url, and afterCallEvent as optional string or null", () => {
126
+ const schema: any = flowMongoSchema;
127
+
128
+ expect(schema.properties).toHaveProperty("beforeCallEvent");
129
+ expect(schema.properties.beforeCallEvent.bsonType).toEqual(["object", "null"]);
130
+ expect(schema.properties.beforeCallEvent.required).toEqual(["url"]);
131
+ expect(schema.properties.beforeCallEvent.properties).toEqual(
132
+ expect.objectContaining({
133
+ url: { bsonType: "string" },
134
+ timeoutMs: { bsonType: ["number", "null"] },
135
+ sendUserAuthToken: { bsonType: ["bool", "null"] },
136
+ wait: { bsonType: ["bool", "null"] },
137
+ })
138
+ );
139
+ expect(schema.properties.beforeCallEvent.properties.allowedKeys).toEqual({
140
+ bsonType: ["array", "null"],
141
+ items: { bsonType: "string" },
142
+ });
143
+ expect(schema.required).not.toContain("beforeCallEvent");
144
+
145
+ expect(schema.properties).toHaveProperty("afterCallEvent");
146
+ expect(schema.properties.afterCallEvent.bsonType).toEqual([
147
+ "string",
148
+ "null",
149
+ ]);
150
+ expect(schema.required).not.toContain("afterCallEvent");
151
+ });
152
+ });