@studious-lms/server 1.26.0 → 1.28.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 (222) hide show
  1. package/.env.example +3 -1
  2. package/.github/workflows/npm-publish.yml +1 -0
  3. package/AGENTS.md +84 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +31 -4
  6. package/dist/index.js.map +1 -1
  7. package/dist/instrument.js +9 -4
  8. package/dist/instrument.js.map +1 -1
  9. package/dist/lib/fileUpload.d.ts +15 -0
  10. package/dist/lib/fileUpload.d.ts.map +1 -1
  11. package/dist/lib/fileUpload.js +43 -2
  12. package/dist/lib/fileUpload.js.map +1 -1
  13. package/dist/models/cloudStorage.d.ts +11 -0
  14. package/dist/models/cloudStorage.d.ts.map +1 -1
  15. package/dist/models/cloudStorage.js +18 -2
  16. package/dist/models/cloudStorage.js.map +1 -1
  17. package/dist/models/conversation.d.ts +1 -0
  18. package/dist/models/conversation.d.ts.map +1 -1
  19. package/dist/models/labChat.d.ts +40 -0
  20. package/dist/models/labChat.d.ts.map +1 -1
  21. package/dist/models/labChat.js +32 -2
  22. package/dist/models/labChat.js.map +1 -1
  23. package/dist/models/message.d.ts +3 -0
  24. package/dist/models/message.d.ts.map +1 -1
  25. package/dist/pipelines/aiLabChat.d.ts +2 -0
  26. package/dist/pipelines/aiLabChat.d.ts.map +1 -1
  27. package/dist/pipelines/aiLabChat.js +60 -16
  28. package/dist/pipelines/aiLabChat.js.map +1 -1
  29. package/dist/pipelines/aiLabChatContract.d.ts +170 -2
  30. package/dist/pipelines/aiLabChatContract.d.ts.map +1 -1
  31. package/dist/pipelines/aiLabChatContract.js +30 -2
  32. package/dist/pipelines/aiLabChatContract.js.map +1 -1
  33. package/dist/pipelines/aiNewtonChat.d.ts.map +1 -1
  34. package/dist/pipelines/aiNewtonChat.js +30 -5
  35. package/dist/pipelines/aiNewtonChat.js.map +1 -1
  36. package/dist/pipelines/generateVisualization.d.ts +33 -0
  37. package/dist/pipelines/generateVisualization.d.ts.map +1 -0
  38. package/dist/pipelines/generateVisualization.js +79 -0
  39. package/dist/pipelines/generateVisualization.js.map +1 -0
  40. package/dist/pipelines/labChatPrompt.d.ts +1 -1
  41. package/dist/pipelines/labChatPrompt.d.ts.map +1 -1
  42. package/dist/pipelines/labChatPrompt.js +13 -14
  43. package/dist/pipelines/labChatPrompt.js.map +1 -1
  44. package/dist/routers/_app.d.ts +1118 -70
  45. package/dist/routers/_app.d.ts.map +1 -1
  46. package/dist/routers/_app.js +4 -2
  47. package/dist/routers/_app.js.map +1 -1
  48. package/dist/routers/admin.d.ts +297 -1
  49. package/dist/routers/admin.d.ts.map +1 -1
  50. package/dist/routers/admin.js +43 -2
  51. package/dist/routers/admin.js.map +1 -1
  52. package/dist/routers/class.d.ts.map +1 -1
  53. package/dist/routers/class.js +16 -3
  54. package/dist/routers/class.js.map +1 -1
  55. package/dist/routers/conversation.d.ts +1 -0
  56. package/dist/routers/conversation.d.ts.map +1 -1
  57. package/dist/routers/labChat.d.ts +10 -0
  58. package/dist/routers/labChat.d.ts.map +1 -1
  59. package/dist/routers/labChat.js +6 -3
  60. package/dist/routers/labChat.js.map +1 -1
  61. package/dist/routers/message.d.ts +37 -4
  62. package/dist/routers/message.d.ts.map +1 -1
  63. package/dist/routers/message.js +24 -7
  64. package/dist/routers/message.js.map +1 -1
  65. package/dist/routers/module.d.ts +1 -1
  66. package/dist/routers/parent.d.ts +18 -0
  67. package/dist/routers/parent.d.ts.map +1 -1
  68. package/dist/routers/parent.js +10 -3
  69. package/dist/routers/parent.js.map +1 -1
  70. package/dist/routers/studentProgress.d.ts +44 -0
  71. package/dist/routers/studentProgress.d.ts.map +1 -1
  72. package/dist/routers/studentProgress.js +12 -3
  73. package/dist/routers/studentProgress.js.map +1 -1
  74. package/dist/routers/visualization.d.ts +124 -0
  75. package/dist/routers/visualization.d.ts.map +1 -0
  76. package/dist/routers/visualization.js +41 -0
  77. package/dist/routers/visualization.js.map +1 -0
  78. package/dist/routes/aiStream.js +32 -2
  79. package/dist/routes/aiStream.js.map +1 -1
  80. package/dist/seedDatabase.d.ts.map +1 -1
  81. package/dist/seedDatabase.js +107 -3
  82. package/dist/seedDatabase.js.map +1 -1
  83. package/dist/services/adminClass.d.ts +153 -0
  84. package/dist/services/adminClass.d.ts.map +1 -0
  85. package/dist/services/adminClass.js +196 -0
  86. package/dist/services/adminClass.js.map +1 -0
  87. package/dist/services/adminInstitution.d.ts +2 -0
  88. package/dist/services/adminInstitution.d.ts.map +1 -1
  89. package/dist/services/adminInstitution.js +11 -4
  90. package/dist/services/adminInstitution.js.map +1 -1
  91. package/dist/services/adminMetrics.d.ts +8 -0
  92. package/dist/services/adminMetrics.d.ts.map +1 -1
  93. package/dist/services/adminMetrics.js +30 -3
  94. package/dist/services/adminMetrics.js.map +1 -1
  95. package/dist/services/adminSpam.d.ts +76 -0
  96. package/dist/services/adminSpam.d.ts.map +1 -0
  97. package/dist/services/adminSpam.js +163 -0
  98. package/dist/services/adminSpam.js.map +1 -0
  99. package/dist/services/adminSql.d.ts +36 -0
  100. package/dist/services/adminSql.d.ts.map +1 -0
  101. package/dist/services/adminSql.js +172 -0
  102. package/dist/services/adminSql.js.map +1 -0
  103. package/dist/services/adminTelemetry.d.ts +56 -0
  104. package/dist/services/adminTelemetry.d.ts.map +1 -0
  105. package/dist/services/adminTelemetry.js +147 -0
  106. package/dist/services/adminTelemetry.js.map +1 -0
  107. package/dist/services/adminUser.d.ts +45 -1
  108. package/dist/services/adminUser.d.ts.map +1 -1
  109. package/dist/services/adminUser.js +53 -13
  110. package/dist/services/adminUser.js.map +1 -1
  111. package/dist/services/aiChatStream.d.ts +15 -0
  112. package/dist/services/aiChatStream.d.ts.map +1 -1
  113. package/dist/services/aiChatStream.js +144 -74
  114. package/dist/services/aiChatStream.js.map +1 -1
  115. package/dist/services/aiGeneration.d.ts +4 -0
  116. package/dist/services/aiGeneration.d.ts.map +1 -0
  117. package/dist/services/aiGeneration.js +88 -0
  118. package/dist/services/aiGeneration.js.map +1 -0
  119. package/dist/services/aiProposalTools.d.ts +4 -1
  120. package/dist/services/aiProposalTools.d.ts.map +1 -1
  121. package/dist/services/aiProposalTools.js +128 -3
  122. package/dist/services/aiProposalTools.js.map +1 -1
  123. package/dist/services/aiProposals.d.ts +70 -0
  124. package/dist/services/aiProposals.d.ts.map +1 -0
  125. package/dist/services/aiProposals.js +363 -0
  126. package/dist/services/aiProposals.js.map +1 -0
  127. package/dist/services/auth.d.ts.map +1 -1
  128. package/dist/services/auth.js +10 -4
  129. package/dist/services/auth.js.map +1 -1
  130. package/dist/services/conversation.d.ts +1 -0
  131. package/dist/services/conversation.d.ts.map +1 -1
  132. package/dist/services/fees.d.ts.map +1 -1
  133. package/dist/services/fees.js +7 -3
  134. package/dist/services/fees.js.map +1 -1
  135. package/dist/services/labChat.d.ts +10 -0
  136. package/dist/services/labChat.d.ts.map +1 -1
  137. package/dist/services/labChat.js +52 -3
  138. package/dist/services/labChat.js.map +1 -1
  139. package/dist/services/message.d.ts +24 -8
  140. package/dist/services/message.d.ts.map +1 -1
  141. package/dist/services/message.js +170 -117
  142. package/dist/services/message.js.map +1 -1
  143. package/dist/services/module.d.ts.map +1 -1
  144. package/dist/services/module.js +23 -4
  145. package/dist/services/module.js.map +1 -1
  146. package/dist/services/parentPortal.d.ts +14 -0
  147. package/dist/services/parentPortal.d.ts.map +1 -1
  148. package/dist/services/parentPortal.js +72 -2
  149. package/dist/services/parentPortal.js.map +1 -1
  150. package/dist/services/studentProgress.d.ts +50 -0
  151. package/dist/services/studentProgress.d.ts.map +1 -1
  152. package/dist/services/studentProgress.js +107 -2
  153. package/dist/services/studentProgress.js.map +1 -1
  154. package/dist/services/visualization.d.ts +72 -0
  155. package/dist/services/visualization.d.ts.map +1 -0
  156. package/dist/services/visualization.js +122 -0
  157. package/dist/services/visualization.js.map +1 -0
  158. package/dist/utils/inference.d.ts +10 -0
  159. package/dist/utils/inference.d.ts.map +1 -1
  160. package/dist/utils/inference.js +77 -2
  161. package/dist/utils/inference.js.map +1 -1
  162. package/dist/utils/sentryTrpc.d.ts +3 -0
  163. package/dist/utils/sentryTrpc.d.ts.map +1 -0
  164. package/dist/utils/sentryTrpc.js +26 -0
  165. package/dist/utils/sentryTrpc.js.map +1 -0
  166. package/dist/workers/processors/createRunJobWorker.js +17 -16
  167. package/dist/workers/processors/createRunJobWorker.js.map +1 -1
  168. package/package.json +1 -1
  169. package/prisma/migrations/20260811130000_add_ai_message_feedback/migration.sql +7 -0
  170. package/prisma/migrations/20261025120000_add_visualizations/migration.sql +27 -0
  171. package/prisma/schema.prisma +32 -0
  172. package/src/index.ts +30 -4
  173. package/src/instrument.ts +8 -2
  174. package/src/lib/fileUpload.ts +49 -0
  175. package/src/models/cloudStorage.ts +19 -0
  176. package/src/models/labChat.ts +34 -0
  177. package/src/pipelines/aiLabChat.ts +79 -18
  178. package/src/pipelines/aiLabChatContract.ts +35 -0
  179. package/src/pipelines/aiNewtonChat.ts +34 -2
  180. package/src/pipelines/generateVisualization.ts +107 -0
  181. package/src/pipelines/labChatPrompt.ts +11 -12
  182. package/src/routers/_app.ts +2 -0
  183. package/src/routers/admin.ts +72 -0
  184. package/src/routers/class.ts +14 -1
  185. package/src/routers/labChat.ts +5 -0
  186. package/src/routers/message.ts +34 -5
  187. package/src/routers/parent.ts +11 -0
  188. package/src/routers/studentProgress.ts +15 -0
  189. package/src/routers/visualization.ts +60 -0
  190. package/src/routes/aiStream.ts +32 -0
  191. package/src/seedDatabase.ts +107 -2
  192. package/src/services/adminClass.ts +222 -0
  193. package/src/services/adminInstitution.ts +9 -2
  194. package/src/services/adminMetrics.ts +35 -0
  195. package/src/services/adminSpam.ts +224 -0
  196. package/src/services/adminSql.ts +214 -0
  197. package/src/services/adminTelemetry.ts +194 -0
  198. package/src/services/adminUser.ts +66 -11
  199. package/src/services/aiChatStream.ts +83 -7
  200. package/src/services/aiGeneration.ts +92 -0
  201. package/src/services/aiProposalTools.ts +166 -1
  202. package/src/services/aiProposals.ts +428 -0
  203. package/src/services/auth.ts +8 -2
  204. package/src/services/fees.ts +5 -1
  205. package/src/services/labChat.ts +65 -0
  206. package/src/services/message.ts +205 -142
  207. package/src/services/module.ts +29 -2
  208. package/src/services/parentPortal.ts +85 -0
  209. package/src/services/studentProgress.ts +135 -0
  210. package/src/services/visualization.ts +147 -0
  211. package/src/utils/inference.ts +85 -0
  212. package/src/utils/sentryTrpc.ts +25 -0
  213. package/src/workers/processors/createRunJobWorker.ts +17 -17
  214. package/tests/unit/lib/fileUploadSession.test.ts +67 -0
  215. package/tests/unit/services/adminClass.test.ts +102 -0
  216. package/tests/unit/services/adminSpam.test.ts +108 -0
  217. package/tests/unit/services/adminSql.test.ts +56 -0
  218. package/tests/unit/services/adminTelemetry.test.ts +47 -0
  219. package/tests/unit/services/adminUser.test.ts +77 -0
  220. package/tests/unit/services/visualization.test.ts +130 -0
  221. package/tests/unit/utils/adminPanelAccess.test.ts +26 -0
  222. package/tests/unit/utils/sentryTrpc.test.ts +15 -0
@@ -16,11 +16,19 @@
16
16
  * typed execute args).
17
17
  */
18
18
 
19
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ee632b59-78dc-5c7c-9a1e-c59b510acb82")}catch(e){}}();
19
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="24c3d8ea-9dfb-548f-8573-00c77aa9309a")}catch(e){}}();
20
20
  import { jsonSchema } from 'ai';
21
21
  import { v4 } from 'uuid';
22
22
  export function createLabProposals() {
23
- return { assignments: [], worksheets: [], sections: [], docs: [] };
23
+ return {
24
+ assignments: [],
25
+ worksheets: [],
26
+ sections: [],
27
+ docs: [],
28
+ assignmentUpdates: [],
29
+ worksheetUpdates: [],
30
+ sectionUpdates: [],
31
+ };
24
32
  }
25
33
  function normalizeDueDate(input) {
26
34
  if (input) {
@@ -169,6 +177,123 @@ export function labProposalTools(proposals) {
169
177
  return `Assignment "${title}" proposed.`;
170
178
  },
171
179
  },
180
+ propose_update_assignment: {
181
+ description: 'Propose changes to an EXISTING assignment. Only pass the fields that should change; use the assignment id from CLASS CONTEXT.',
182
+ inputSchema: jsonSchema({
183
+ type: 'object',
184
+ properties: {
185
+ id: { type: 'string', description: 'Database id of the existing assignment' },
186
+ targetTitle: { type: 'string', description: "The assignment's current title (shown on the approval card)" },
187
+ title: { type: 'string', description: 'New title, if renaming' },
188
+ instructions: { type: 'string' },
189
+ dueDate: { type: 'string', description: 'ISO 8601 datetime' },
190
+ type: { type: 'string', enum: ASSIGNMENT_TYPES },
191
+ maxGrade: { type: 'number' },
192
+ acceptFiles: { type: 'boolean' },
193
+ acceptExtendedResponse: { type: 'boolean' },
194
+ acceptWorksheet: { type: 'boolean' },
195
+ sectionId: { type: 'string', description: 'Move to this section (id from CLASS CONTEXT)' },
196
+ },
197
+ required: ['id', 'targetTitle'],
198
+ }),
199
+ execute: async (args) => {
200
+ proposals.assignmentUpdates.push({
201
+ ...args,
202
+ dueDate: args.dueDate ? normalizeDueDate(args.dueDate) : undefined,
203
+ });
204
+ return `Update to assignment "${args.targetTitle}" proposed.`;
205
+ },
206
+ },
207
+ propose_update_worksheet: {
208
+ description: 'Propose changes to an EXISTING worksheet: rename it and/or append new questions. Use the worksheet id from CLASS CONTEXT.',
209
+ inputSchema: jsonSchema({
210
+ type: 'object',
211
+ properties: {
212
+ id: { type: 'string', description: 'Database id of the existing worksheet' },
213
+ targetTitle: { type: 'string', description: "The worksheet's current name (shown on the approval card)" },
214
+ name: { type: 'string', description: 'New name, if renaming' },
215
+ addQuestions: {
216
+ type: 'array',
217
+ description: 'New questions to append to the worksheet',
218
+ items: {
219
+ type: 'object',
220
+ properties: {
221
+ type: { type: 'string', enum: QUESTION_TYPES },
222
+ question: { type: 'string' },
223
+ answer: { type: 'string' },
224
+ options: {
225
+ type: 'array',
226
+ items: {
227
+ type: 'object',
228
+ properties: {
229
+ text: { type: 'string' },
230
+ isCorrect: { type: 'boolean' },
231
+ },
232
+ required: ['text', 'isCorrect'],
233
+ },
234
+ },
235
+ markScheme: {
236
+ type: 'array',
237
+ items: {
238
+ type: 'object',
239
+ properties: {
240
+ points: { type: 'number' },
241
+ description: { type: 'string' },
242
+ },
243
+ required: ['points', 'description'],
244
+ },
245
+ },
246
+ points: { type: 'number' },
247
+ },
248
+ required: ['type', 'question'],
249
+ },
250
+ },
251
+ },
252
+ required: ['id', 'targetTitle'],
253
+ }),
254
+ execute: async ({ id, targetTitle, name, addQuestions }) => {
255
+ proposals.worksheetUpdates.push({
256
+ id,
257
+ targetTitle,
258
+ name,
259
+ addQuestions: (addQuestions ?? []).map((q, index) => ({
260
+ type: q.type,
261
+ question: q.question,
262
+ answer: q.answer ?? '',
263
+ options: (q.options ?? []).map((o) => ({
264
+ id: v4(),
265
+ text: o.text,
266
+ isCorrect: o.isCorrect,
267
+ })),
268
+ markScheme: (q.markScheme ?? []).map((m) => ({
269
+ id: v4(),
270
+ points: m.points,
271
+ description: m.description,
272
+ })),
273
+ points: q.points ?? 0,
274
+ order: index,
275
+ })),
276
+ });
277
+ return `Update to worksheet "${targetTitle}" proposed.`;
278
+ },
279
+ },
280
+ propose_update_section: {
281
+ description: 'Propose changes to an EXISTING section (rename and/or recolor). Use the section id from CLASS CONTEXT. Always pass name (the resulting name, even if unchanged).',
282
+ inputSchema: jsonSchema({
283
+ type: 'object',
284
+ properties: {
285
+ id: { type: 'string', description: 'Database id of the existing section' },
286
+ targetTitle: { type: 'string', description: "The section's current name (shown on the approval card)" },
287
+ name: { type: 'string', description: 'Resulting section name (pass the current name if only changing color)' },
288
+ color: { type: 'string', description: 'Optional hex color like #3b82f6' },
289
+ },
290
+ required: ['id', 'targetTitle', 'name'],
291
+ }),
292
+ execute: async ({ id, targetTitle, name, color }) => {
293
+ proposals.sectionUpdates.push({ id, targetTitle, name, color: color ?? null });
294
+ return `Update to section "${targetTitle}" proposed.`;
295
+ },
296
+ },
172
297
  generate_document: {
173
298
  description: 'Generate a downloadable file and attach it to this message. Pick the best format for the request — pptx for slides, xlsx/csv for data, docx for editable handouts, pdf for print-ready docs, png/jpeg for charts/diagrams/figures (NOT pdf for visuals). Use py/js/ts only when the teacher explicitly wants source code. Always set format explicitly.',
174
299
  inputSchema: jsonSchema({
@@ -204,4 +329,4 @@ export function labProposalTools(proposals) {
204
329
  };
205
330
  }
206
331
  //# sourceMappingURL=aiProposalTools.js.map
207
- //# debugId=ee632b59-78dc-5c7c-9a1e-c59b510acb82
332
+ //# debugId=24c3d8ea-9dfb-548f-8573-00c77aa9309a
@@ -1 +1 @@
1
- {"version":3,"file":"aiProposalTools.js","sources":["services/aiProposalTools.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Lab-chat \"proposal\" tools.\n *\n * In the agentic Lab pipeline the model produces create-actions by *calling\n * tools* (e.g. `propose_assignment`) instead of returning a JSON blob. Each\n * tool records a structured payload into a shared accumulator and returns a\n * short confirmation so the model can keep narrating. After the stream ends\n * the pipeline turns the accumulator into the `message.meta.*ToCreate` shape\n * the frontend accept-cards already consume — so the data contract is\n * preserved while the generation becomes genuine inline tool calls.\n *\n * NOTE: these tools intentionally use `jsonSchema()` rather than the zod\n * `tool()` helper. Zod-typed `tool()` definitions with deeply nested schemas\n * make the TS compiler instantiate excessively deep types (TS2589) and OOM,\n * so we mirror the existing `aiTools.ts` pattern (plain JSON Schema + manually\n * typed execute args).\n */\nimport { jsonSchema, type ToolSet } from 'ai';\nimport { v4 } from 'uuid';\nimport type {\n AssignmentToCreate,\n WorksheetToCreate,\n SectionToCreate,\n DocToCreate,\n} from '../pipelines/aiLabChatContract.js';\n\nexport interface LabProposals {\n assignments: AssignmentToCreate[];\n worksheets: WorksheetToCreate[];\n sections: SectionToCreate[];\n docs: DocToCreate[];\n}\n\nexport function createLabProposals(): LabProposals {\n return { assignments: [], worksheets: [], sections: [], docs: [] };\n}\n\nfunction normalizeDueDate(input?: string | null): string {\n if (input) {\n const parsed = new Date(input);\n if (!Number.isNaN(parsed.getTime())) return parsed.toISOString();\n }\n // Default: one week out.\n return new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString();\n}\n\nconst ASSIGNMENT_TYPES = [\n 'HOMEWORK', 'QUIZ', 'TEST', 'PROJECT', 'ESSAY', 'DISCUSSION', 'PRESENTATION', 'LAB', 'OTHER',\n] as const;\ntype AssignmentType = (typeof ASSIGNMENT_TYPES)[number];\n\nconst QUESTION_TYPES = [\n 'MULTIPLE_CHOICE', 'TRUE_FALSE', 'SHORT_ANSWER', 'LONG_ANSWER', 'MATH_EXPRESSION', 'ESSAY',\n] as const;\ntype QuestionType = (typeof QUESTION_TYPES)[number];\n\ninterface ProposeSectionArgs {\n name: string;\n color?: string | null;\n}\n\ninterface ProposeWorksheetArgs {\n title: string;\n questions: Array<{\n type: QuestionType;\n question: string;\n answer?: string;\n options?: Array<{ text: string; isCorrect: boolean }>;\n markScheme?: Array<{ points: number; description: string }>;\n points?: number;\n }>;\n}\n\ninterface ProposeAssignmentArgs {\n title: string;\n instructions: string;\n dueDate?: string;\n type?: AssignmentType;\n maxGrade?: number;\n acceptFiles?: boolean;\n acceptExtendedResponse?: boolean;\n acceptWorksheet?: boolean;\n}\n\ninterface GenerateDocumentArgs {\n title: string;\n content: string;\n format?: string;\n}\n\n/**\n * Build the set of proposal tools backed by the given accumulator.\n * Merge these with the read-only RAG tools from `aiTools(classId)`.\n */\nexport function labProposalTools(proposals: LabProposals): ToolSet {\n return {\n propose_section: {\n description:\n 'Propose a new section (folder) to organise class content. Call once per section you want to create.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Section name' },\n color: { type: 'string', description: 'Optional hex color like #3b82f6' },\n },\n required: ['name'],\n }),\n execute: async ({ name, color }: ProposeSectionArgs) => {\n proposals.sections.push({ name, color: color ?? null });\n return `Section \"${name}\" proposed.`;\n },\n },\n\n propose_worksheet: {\n description:\n 'Propose a worksheet of questions for the teacher to review and create. Include all questions in a single call.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n title: { type: 'string', description: 'Worksheet title' },\n questions: {\n type: 'array',\n description: 'The list of questions',\n items: {\n type: 'object',\n properties: {\n type: { type: 'string', enum: QUESTION_TYPES as unknown as string[] },\n question: { type: 'string' },\n answer: { type: 'string' },\n options: {\n type: 'array',\n description: 'For MULTIPLE_CHOICE/TRUE_FALSE questions',\n items: {\n type: 'object',\n properties: {\n text: { type: 'string' },\n isCorrect: { type: 'boolean' },\n },\n required: ['text', 'isCorrect'],\n },\n },\n markScheme: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n points: { type: 'number' },\n description: { type: 'string' },\n },\n required: ['points', 'description'],\n },\n },\n points: { type: 'number' },\n },\n required: ['type', 'question'],\n },\n },\n },\n required: ['title', 'questions'],\n }),\n execute: async ({ title, questions }: ProposeWorksheetArgs) => {\n const worksheet: WorksheetToCreate = {\n title,\n questions: (questions ?? []).map((q, index) => ({\n type: q.type,\n question: q.question,\n answer: q.answer ?? '',\n options: (q.options ?? []).map((o) => ({\n id: v4(),\n text: o.text,\n isCorrect: o.isCorrect,\n })),\n markScheme: (q.markScheme ?? []).map((m) => ({\n id: v4(),\n points: m.points,\n description: m.description,\n })),\n points: q.points ?? 0,\n order: index,\n })),\n };\n proposals.worksheets.push(worksheet);\n return `Worksheet \"${title}\" with ${worksheet.questions.length} question(s) proposed.`;\n },\n },\n\n propose_assignment: {\n description:\n 'Propose an assignment for the teacher to review and create. Call once per assignment.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n title: { type: 'string' },\n instructions: { type: 'string' },\n dueDate: {\n type: 'string',\n description: 'ISO 8601 datetime. Defaults to one week from now if omitted.',\n },\n type: { type: 'string', enum: ASSIGNMENT_TYPES as unknown as string[] },\n maxGrade: { type: 'number' },\n acceptFiles: { type: 'boolean' },\n acceptExtendedResponse: { type: 'boolean' },\n acceptWorksheet: { type: 'boolean' },\n },\n required: ['title', 'instructions'],\n }),\n execute: async ({\n title,\n instructions,\n dueDate,\n type,\n maxGrade,\n acceptFiles,\n acceptExtendedResponse,\n acceptWorksheet,\n }: ProposeAssignmentArgs) => {\n const assignment: AssignmentToCreate = {\n title,\n instructions,\n dueDate: normalizeDueDate(dueDate),\n type: type ?? 'HOMEWORK',\n maxGrade: maxGrade ?? 100,\n acceptFiles: acceptFiles ?? true,\n acceptExtendedResponse: acceptExtendedResponse ?? false,\n acceptWorksheet: acceptWorksheet ?? false,\n gradingBoundaryId: null,\n markSchemeId: null,\n worksheetIds: [],\n studentIds: [],\n sectionId: null,\n attachments: [],\n };\n proposals.assignments.push(assignment);\n return `Assignment \"${title}\" proposed.`;\n },\n },\n\n generate_document: {\n description:\n 'Generate a downloadable file and attach it to this message. Pick the best format for the request — pptx for slides, xlsx/csv for data, docx for editable handouts, pdf for print-ready docs, png/jpeg for charts/diagrams/figures (NOT pdf for visuals). Use py/js/ts only when the teacher explicitly wants source code. Always set format explicitly.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n title: { type: 'string', description: 'Document title' },\n content: {\n type: 'string',\n description:\n 'Full body. Structure by format: pptx — separate slides with \"---\" or \"Slide N:\" headers; xlsx/csv — markdown tables or row data; png/jpeg — describe the visual in detail (shapes, labels, arrows, data points, colors); pdf/docx — headings, lists, tables; code formats — complete runnable source.',\n },\n format: {\n type: 'string',\n description:\n 'Output file type. REQUIRED. pptx=slides, xlsx/csv=spreadsheet, docx=Word, pdf=printable doc, png/jpeg/gif=chart/diagram/figure image, md/txt/html=text. py/js/ts/css/sh=source code only when requested.',\n enum: [\n 'pdf', 'docx', 'doc', 'xlsx', 'pptx', 'csv', 'md', 'html', 'txt',\n 'json', 'xml', 'tex', 'png', 'jpeg', 'jpg', 'gif', 'zip', 'tar',\n 'py', 'js', 'ts', 'css', 'sh',\n ],\n },\n },\n required: ['title', 'content', 'format'],\n }),\n execute: async ({ title, content, format }: GenerateDocumentArgs) => {\n proposals.docs.push({\n title,\n content: content.trim(),\n format: (format ?? 'pdf') as DocToCreate['format'],\n });\n const ext = (format ?? 'pdf').toUpperCase();\n return `Document \"${title}\" queued for ${ext} generation.`;\n },\n },\n };\n}\n"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;;;AACH,OAAO,EAAE,UAAU,EAAgB,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAe1B,MAAM,UAAU,kBAAkB;IAChC,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACrE,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAqB;IAC7C,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAAE,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC;IACnE,CAAC;IACD,yBAAyB;IACzB,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;AACtE,CAAC;AAED,MAAM,gBAAgB,GAAG;IACvB,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO;CACpF,CAAC;AAGX,MAAM,cAAc,GAAG;IACrB,iBAAiB,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,iBAAiB,EAAE,OAAO;CAClF,CAAC;AAqCX;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAuB;IACtD,OAAO;QACL,eAAe,EAAE;YACf,WAAW,EACT,qGAAqG;YACvG,WAAW,EAAE,UAAU,CAAC;gBACtB,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE;oBACrD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iCAAiC,EAAE;iBAC1E;gBACD,QAAQ,EAAE,CAAC,MAAM,CAAC;aACnB,CAAC;YACF,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAsB,EAAE,EAAE;gBACrD,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC;gBACxD,OAAO,YAAY,IAAI,aAAa,CAAC;YACvC,CAAC;SACF;QAED,iBAAiB,EAAE;YACjB,WAAW,EACT,gHAAgH;YAClH,WAAW,EAAE,UAAU,CAAC;gBACtB,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAE;oBACzD,SAAS,EAAE;wBACT,IAAI,EAAE,OAAO;wBACb,WAAW,EAAE,uBAAuB;wBACpC,KAAK,EAAE;4BACL,IAAI,EAAE,QAAQ;4BACd,UAAU,EAAE;gCACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAqC,EAAE;gCACrE,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gCAC5B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gCAC1B,OAAO,EAAE;oCACP,IAAI,EAAE,OAAO;oCACb,WAAW,EAAE,0CAA0C;oCACvD,KAAK,EAAE;wCACL,IAAI,EAAE,QAAQ;wCACd,UAAU,EAAE;4CACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;4CACxB,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;yCAC/B;wCACD,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC;qCAChC;iCACF;gCACD,UAAU,EAAE;oCACV,IAAI,EAAE,OAAO;oCACb,KAAK,EAAE;wCACL,IAAI,EAAE,QAAQ;wCACd,UAAU,EAAE;4CACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;4CAC1B,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;yCAChC;wCACD,QAAQ,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC;qCACpC;iCACF;gCACD,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;6BAC3B;4BACD,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC;yBAC/B;qBACF;iBACF;gBACD,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC;aACjC,CAAC;YACF,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAwB,EAAE,EAAE;gBAC5D,MAAM,SAAS,GAAsB;oBACnC,KAAK;oBACL,SAAS,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;wBAC9C,IAAI,EAAE,CAAC,CAAC,IAAI;wBACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;wBACpB,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;wBACtB,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;4BACrC,EAAE,EAAE,EAAE,EAAE;4BACR,IAAI,EAAE,CAAC,CAAC,IAAI;4BACZ,SAAS,EAAE,CAAC,CAAC,SAAS;yBACvB,CAAC,CAAC;wBACH,UAAU,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;4BAC3C,EAAE,EAAE,EAAE,EAAE;4BACR,MAAM,EAAE,CAAC,CAAC,MAAM;4BAChB,WAAW,EAAE,CAAC,CAAC,WAAW;yBAC3B,CAAC,CAAC;wBACH,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC;wBACrB,KAAK,EAAE,KAAK;qBACb,CAAC,CAAC;iBACJ,CAAC;gBACF,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACrC,OAAO,cAAc,KAAK,UAAU,SAAS,CAAC,SAAS,CAAC,MAAM,wBAAwB,CAAC;YACzF,CAAC;SACF;QAED,kBAAkB,EAAE;YAClB,WAAW,EACT,uFAAuF;YACzF,WAAW,EAAE,UAAU,CAAC;gBACtB,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBACzB,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAChC,OAAO,EAAE;wBACP,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,8DAA8D;qBAC5E;oBACD,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,gBAAuC,EAAE;oBACvE,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAC5B,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;oBAChC,sBAAsB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;oBAC3C,eAAe,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;iBACrC;gBACD,QAAQ,EAAE,CAAC,OAAO,EAAE,cAAc,CAAC;aACpC,CAAC;YACF,OAAO,EAAE,KAAK,EAAE,EACd,KAAK,EACL,YAAY,EACZ,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,WAAW,EACX,sBAAsB,EACtB,eAAe,GACO,EAAE,EAAE;gBAC1B,MAAM,UAAU,GAAuB;oBACrC,KAAK;oBACL,YAAY;oBACZ,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC;oBAClC,IAAI,EAAE,IAAI,IAAI,UAAU;oBACxB,QAAQ,EAAE,QAAQ,IAAI,GAAG;oBACzB,WAAW,EAAE,WAAW,IAAI,IAAI;oBAChC,sBAAsB,EAAE,sBAAsB,IAAI,KAAK;oBACvD,eAAe,EAAE,eAAe,IAAI,KAAK;oBACzC,iBAAiB,EAAE,IAAI;oBACvB,YAAY,EAAE,IAAI;oBAClB,YAAY,EAAE,EAAE;oBAChB,UAAU,EAAE,EAAE;oBACd,SAAS,EAAE,IAAI;oBACf,WAAW,EAAE,EAAE;iBAChB,CAAC;gBACF,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBACvC,OAAO,eAAe,KAAK,aAAa,CAAC;YAC3C,CAAC;SACF;QAED,iBAAiB,EAAE;YACjB,WAAW,EACT,yVAAyV;YAC3V,WAAW,EAAE,UAAU,CAAC;gBACtB,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE;oBACxD,OAAO,EAAE;wBACP,IAAI,EAAE,QAAQ;wBACd,WAAW,EACT,uSAAuS;qBAC1S;oBACD,MAAM,EAAE;wBACN,IAAI,EAAE,QAAQ;wBACd,WAAW,EACT,0MAA0M;wBAC5M,IAAI,EAAE;4BACJ,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK;4BAChE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;4BAC/D,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI;yBAC9B;qBACF;iBACF;gBACD,QAAQ,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC;aACzC,CAAC;YACF,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAwB,EAAE,EAAE;gBAClE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;oBAClB,KAAK;oBACL,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE;oBACvB,MAAM,EAAE,CAAC,MAAM,IAAI,KAAK,CAA0B;iBACnD,CAAC,CAAC;gBACH,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;gBAC5C,OAAO,aAAa,KAAK,gBAAgB,GAAG,cAAc,CAAC;YAC7D,CAAC;SACF;KACF,CAAC;AACJ,CAAC","debug_id":"ee632b59-78dc-5c7c-9a1e-c59b510acb82"}
1
+ {"version":3,"file":"aiProposalTools.js","sources":["services/aiProposalTools.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Lab-chat \"proposal\" tools.\n *\n * In the agentic Lab pipeline the model produces create-actions by *calling\n * tools* (e.g. `propose_assignment`) instead of returning a JSON blob. Each\n * tool records a structured payload into a shared accumulator and returns a\n * short confirmation so the model can keep narrating. After the stream ends\n * the pipeline turns the accumulator into the `message.meta.*ToCreate` shape\n * the frontend accept-cards already consume — so the data contract is\n * preserved while the generation becomes genuine inline tool calls.\n *\n * NOTE: these tools intentionally use `jsonSchema()` rather than the zod\n * `tool()` helper. Zod-typed `tool()` definitions with deeply nested schemas\n * make the TS compiler instantiate excessively deep types (TS2589) and OOM,\n * so we mirror the existing `aiTools.ts` pattern (plain JSON Schema + manually\n * typed execute args).\n */\nimport { jsonSchema, type ToolSet } from 'ai';\nimport { v4 } from 'uuid';\nimport type {\n AssignmentToCreate,\n WorksheetToCreate,\n SectionToCreate,\n DocToCreate,\n AssignmentUpdate,\n WorksheetUpdate,\n SectionUpdate,\n} from '../pipelines/aiLabChatContract.js';\n\nexport interface LabProposals {\n assignments: AssignmentToCreate[];\n worksheets: WorksheetToCreate[];\n sections: SectionToCreate[];\n docs: DocToCreate[];\n assignmentUpdates: AssignmentUpdate[];\n worksheetUpdates: WorksheetUpdate[];\n sectionUpdates: SectionUpdate[];\n}\n\nexport function createLabProposals(): LabProposals {\n return {\n assignments: [],\n worksheets: [],\n sections: [],\n docs: [],\n assignmentUpdates: [],\n worksheetUpdates: [],\n sectionUpdates: [],\n };\n}\n\nfunction normalizeDueDate(input?: string | null): string {\n if (input) {\n const parsed = new Date(input);\n if (!Number.isNaN(parsed.getTime())) return parsed.toISOString();\n }\n // Default: one week out.\n return new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString();\n}\n\nconst ASSIGNMENT_TYPES = [\n 'HOMEWORK', 'QUIZ', 'TEST', 'PROJECT', 'ESSAY', 'DISCUSSION', 'PRESENTATION', 'LAB', 'OTHER',\n] as const;\ntype AssignmentType = (typeof ASSIGNMENT_TYPES)[number];\n\nconst QUESTION_TYPES = [\n 'MULTIPLE_CHOICE', 'TRUE_FALSE', 'SHORT_ANSWER', 'LONG_ANSWER', 'MATH_EXPRESSION', 'ESSAY',\n] as const;\ntype QuestionType = (typeof QUESTION_TYPES)[number];\n\ninterface ProposeSectionArgs {\n name: string;\n color?: string | null;\n}\n\ninterface ProposeWorksheetArgs {\n title: string;\n questions: Array<{\n type: QuestionType;\n question: string;\n answer?: string;\n options?: Array<{ text: string; isCorrect: boolean }>;\n markScheme?: Array<{ points: number; description: string }>;\n points?: number;\n }>;\n}\n\ninterface ProposeAssignmentArgs {\n title: string;\n instructions: string;\n dueDate?: string;\n type?: AssignmentType;\n maxGrade?: number;\n acceptFiles?: boolean;\n acceptExtendedResponse?: boolean;\n acceptWorksheet?: boolean;\n}\n\ninterface ProposeUpdateAssignmentArgs {\n id: string;\n targetTitle: string;\n title?: string;\n instructions?: string;\n dueDate?: string;\n type?: AssignmentType;\n maxGrade?: number;\n acceptFiles?: boolean;\n acceptExtendedResponse?: boolean;\n acceptWorksheet?: boolean;\n sectionId?: string | null;\n}\n\ninterface ProposeUpdateWorksheetArgs {\n id: string;\n targetTitle: string;\n name?: string;\n addQuestions?: ProposeWorksheetArgs['questions'];\n}\n\ninterface ProposeUpdateSectionArgs {\n id: string;\n targetTitle: string;\n name: string;\n color?: string | null;\n}\n\ninterface GenerateDocumentArgs {\n title: string;\n content: string;\n format?: string;\n}\n\n/**\n * Build the set of proposal tools backed by the given accumulator.\n * Merge these with the read-only RAG tools from `aiTools(classId)`.\n */\nexport function labProposalTools(proposals: LabProposals): ToolSet {\n return {\n propose_section: {\n description:\n 'Propose a new section (folder) to organise class content. Call once per section you want to create.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Section name' },\n color: { type: 'string', description: 'Optional hex color like #3b82f6' },\n },\n required: ['name'],\n }),\n execute: async ({ name, color }: ProposeSectionArgs) => {\n proposals.sections.push({ name, color: color ?? null });\n return `Section \"${name}\" proposed.`;\n },\n },\n\n propose_worksheet: {\n description:\n 'Propose a worksheet of questions for the teacher to review and create. Include all questions in a single call.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n title: { type: 'string', description: 'Worksheet title' },\n questions: {\n type: 'array',\n description: 'The list of questions',\n items: {\n type: 'object',\n properties: {\n type: { type: 'string', enum: QUESTION_TYPES as unknown as string[] },\n question: { type: 'string' },\n answer: { type: 'string' },\n options: {\n type: 'array',\n description: 'For MULTIPLE_CHOICE/TRUE_FALSE questions',\n items: {\n type: 'object',\n properties: {\n text: { type: 'string' },\n isCorrect: { type: 'boolean' },\n },\n required: ['text', 'isCorrect'],\n },\n },\n markScheme: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n points: { type: 'number' },\n description: { type: 'string' },\n },\n required: ['points', 'description'],\n },\n },\n points: { type: 'number' },\n },\n required: ['type', 'question'],\n },\n },\n },\n required: ['title', 'questions'],\n }),\n execute: async ({ title, questions }: ProposeWorksheetArgs) => {\n const worksheet: WorksheetToCreate = {\n title,\n questions: (questions ?? []).map((q, index) => ({\n type: q.type,\n question: q.question,\n answer: q.answer ?? '',\n options: (q.options ?? []).map((o) => ({\n id: v4(),\n text: o.text,\n isCorrect: o.isCorrect,\n })),\n markScheme: (q.markScheme ?? []).map((m) => ({\n id: v4(),\n points: m.points,\n description: m.description,\n })),\n points: q.points ?? 0,\n order: index,\n })),\n };\n proposals.worksheets.push(worksheet);\n return `Worksheet \"${title}\" with ${worksheet.questions.length} question(s) proposed.`;\n },\n },\n\n propose_assignment: {\n description:\n 'Propose an assignment for the teacher to review and create. Call once per assignment.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n title: { type: 'string' },\n instructions: { type: 'string' },\n dueDate: {\n type: 'string',\n description: 'ISO 8601 datetime. Defaults to one week from now if omitted.',\n },\n type: { type: 'string', enum: ASSIGNMENT_TYPES as unknown as string[] },\n maxGrade: { type: 'number' },\n acceptFiles: { type: 'boolean' },\n acceptExtendedResponse: { type: 'boolean' },\n acceptWorksheet: { type: 'boolean' },\n },\n required: ['title', 'instructions'],\n }),\n execute: async ({\n title,\n instructions,\n dueDate,\n type,\n maxGrade,\n acceptFiles,\n acceptExtendedResponse,\n acceptWorksheet,\n }: ProposeAssignmentArgs) => {\n const assignment: AssignmentToCreate = {\n title,\n instructions,\n dueDate: normalizeDueDate(dueDate),\n type: type ?? 'HOMEWORK',\n maxGrade: maxGrade ?? 100,\n acceptFiles: acceptFiles ?? true,\n acceptExtendedResponse: acceptExtendedResponse ?? false,\n acceptWorksheet: acceptWorksheet ?? false,\n gradingBoundaryId: null,\n markSchemeId: null,\n worksheetIds: [],\n studentIds: [],\n sectionId: null,\n attachments: [],\n };\n proposals.assignments.push(assignment);\n return `Assignment \"${title}\" proposed.`;\n },\n },\n\n propose_update_assignment: {\n description:\n 'Propose changes to an EXISTING assignment. Only pass the fields that should change; use the assignment id from CLASS CONTEXT.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Database id of the existing assignment' },\n targetTitle: { type: 'string', description: \"The assignment's current title (shown on the approval card)\" },\n title: { type: 'string', description: 'New title, if renaming' },\n instructions: { type: 'string' },\n dueDate: { type: 'string', description: 'ISO 8601 datetime' },\n type: { type: 'string', enum: ASSIGNMENT_TYPES as unknown as string[] },\n maxGrade: { type: 'number' },\n acceptFiles: { type: 'boolean' },\n acceptExtendedResponse: { type: 'boolean' },\n acceptWorksheet: { type: 'boolean' },\n sectionId: { type: 'string', description: 'Move to this section (id from CLASS CONTEXT)' },\n },\n required: ['id', 'targetTitle'],\n }),\n execute: async (args: ProposeUpdateAssignmentArgs) => {\n proposals.assignmentUpdates.push({\n ...args,\n dueDate: args.dueDate ? normalizeDueDate(args.dueDate) : undefined,\n });\n return `Update to assignment \"${args.targetTitle}\" proposed.`;\n },\n },\n\n propose_update_worksheet: {\n description:\n 'Propose changes to an EXISTING worksheet: rename it and/or append new questions. Use the worksheet id from CLASS CONTEXT.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Database id of the existing worksheet' },\n targetTitle: { type: 'string', description: \"The worksheet's current name (shown on the approval card)\" },\n name: { type: 'string', description: 'New name, if renaming' },\n addQuestions: {\n type: 'array',\n description: 'New questions to append to the worksheet',\n items: {\n type: 'object',\n properties: {\n type: { type: 'string', enum: QUESTION_TYPES as unknown as string[] },\n question: { type: 'string' },\n answer: { type: 'string' },\n options: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n text: { type: 'string' },\n isCorrect: { type: 'boolean' },\n },\n required: ['text', 'isCorrect'],\n },\n },\n markScheme: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n points: { type: 'number' },\n description: { type: 'string' },\n },\n required: ['points', 'description'],\n },\n },\n points: { type: 'number' },\n },\n required: ['type', 'question'],\n },\n },\n },\n required: ['id', 'targetTitle'],\n }),\n execute: async ({ id, targetTitle, name, addQuestions }: ProposeUpdateWorksheetArgs) => {\n proposals.worksheetUpdates.push({\n id,\n targetTitle,\n name,\n addQuestions: (addQuestions ?? []).map((q, index) => ({\n type: q.type,\n question: q.question,\n answer: q.answer ?? '',\n options: (q.options ?? []).map((o) => ({\n id: v4(),\n text: o.text,\n isCorrect: o.isCorrect,\n })),\n markScheme: (q.markScheme ?? []).map((m) => ({\n id: v4(),\n points: m.points,\n description: m.description,\n })),\n points: q.points ?? 0,\n order: index,\n })),\n });\n return `Update to worksheet \"${targetTitle}\" proposed.`;\n },\n },\n\n propose_update_section: {\n description:\n 'Propose changes to an EXISTING section (rename and/or recolor). Use the section id from CLASS CONTEXT. Always pass name (the resulting name, even if unchanged).',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Database id of the existing section' },\n targetTitle: { type: 'string', description: \"The section's current name (shown on the approval card)\" },\n name: { type: 'string', description: 'Resulting section name (pass the current name if only changing color)' },\n color: { type: 'string', description: 'Optional hex color like #3b82f6' },\n },\n required: ['id', 'targetTitle', 'name'],\n }),\n execute: async ({ id, targetTitle, name, color }: ProposeUpdateSectionArgs) => {\n proposals.sectionUpdates.push({ id, targetTitle, name, color: color ?? null });\n return `Update to section \"${targetTitle}\" proposed.`;\n },\n },\n\n generate_document: {\n description:\n 'Generate a downloadable file and attach it to this message. Pick the best format for the request — pptx for slides, xlsx/csv for data, docx for editable handouts, pdf for print-ready docs, png/jpeg for charts/diagrams/figures (NOT pdf for visuals). Use py/js/ts only when the teacher explicitly wants source code. Always set format explicitly.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n title: { type: 'string', description: 'Document title' },\n content: {\n type: 'string',\n description:\n 'Full body. Structure by format: pptx — separate slides with \"---\" or \"Slide N:\" headers; xlsx/csv — markdown tables or row data; png/jpeg — describe the visual in detail (shapes, labels, arrows, data points, colors); pdf/docx — headings, lists, tables; code formats — complete runnable source.',\n },\n format: {\n type: 'string',\n description:\n 'Output file type. REQUIRED. pptx=slides, xlsx/csv=spreadsheet, docx=Word, pdf=printable doc, png/jpeg/gif=chart/diagram/figure image, md/txt/html=text. py/js/ts/css/sh=source code only when requested.',\n enum: [\n 'pdf', 'docx', 'doc', 'xlsx', 'pptx', 'csv', 'md', 'html', 'txt',\n 'json', 'xml', 'tex', 'png', 'jpeg', 'jpg', 'gif', 'zip', 'tar',\n 'py', 'js', 'ts', 'css', 'sh',\n ],\n },\n },\n required: ['title', 'content', 'format'],\n }),\n execute: async ({ title, content, format }: GenerateDocumentArgs) => {\n proposals.docs.push({\n title,\n content: content.trim(),\n format: (format ?? 'pdf') as DocToCreate['format'],\n });\n const ext = (format ?? 'pdf').toUpperCase();\n return `Document \"${title}\" queued for ${ext} generation.`;\n },\n },\n };\n}\n"],"names":[],"mappings":"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","debug_id":"24c3d8ea-9dfb-548f-8573-00c77aa9309a"}
@@ -0,0 +1,70 @@
1
+ import type { StreamPart } from "./aiChatStream.js";
2
+ import type { LabProposals } from "./aiProposalTools.js";
3
+ import type { AssignmentToCreate, WorksheetToCreate, SectionToCreate, AssignmentUpdate, WorksheetUpdate, SectionUpdate } from "../pipelines/aiLabChatContract.js";
4
+ export type PendingCreationStatus = "pending" | "approved" | "dismissed";
5
+ export type PendingCreation = {
6
+ id: string;
7
+ kind: "assignment";
8
+ title: string;
9
+ payload: AssignmentToCreate;
10
+ status: PendingCreationStatus;
11
+ createdId?: string;
12
+ } | {
13
+ id: string;
14
+ kind: "worksheet";
15
+ title: string;
16
+ payload: WorksheetToCreate;
17
+ status: PendingCreationStatus;
18
+ createdId?: string;
19
+ } | {
20
+ id: string;
21
+ kind: "section";
22
+ title: string;
23
+ payload: SectionToCreate;
24
+ status: PendingCreationStatus;
25
+ createdId?: string;
26
+ } | {
27
+ id: string;
28
+ kind: "assignmentUpdate";
29
+ title: string;
30
+ payload: AssignmentUpdate;
31
+ status: PendingCreationStatus;
32
+ createdId?: string;
33
+ } | {
34
+ id: string;
35
+ kind: "worksheetUpdate";
36
+ title: string;
37
+ payload: WorksheetUpdate;
38
+ status: PendingCreationStatus;
39
+ createdId?: string;
40
+ } | {
41
+ id: string;
42
+ kind: "sectionUpdate";
43
+ title: string;
44
+ payload: SectionUpdate;
45
+ status: PendingCreationStatus;
46
+ createdId?: string;
47
+ };
48
+ /**
49
+ * Turn the stream's accumulated proposals into pending creations and stamp
50
+ * each `propose_*` tool part with its proposal id so the client can render
51
+ * the confirmation card inline at the tool-call position.
52
+ */
53
+ export declare function buildPendingCreations(proposals: LabProposals, parts: StreamPart[]): {
54
+ pendingCreations: PendingCreation[];
55
+ parts: StreamPart[];
56
+ };
57
+ /**
58
+ * Approve or dismiss a pending AI creation proposal. Approval creates the
59
+ * entity server-side; both outcomes persist to message meta and broadcast a
60
+ * `message-updated` event so every client (and reloads) see the final state.
61
+ */
62
+ export declare function resolveAiProposal(userId: string, input: {
63
+ messageId: string;
64
+ proposalId: string;
65
+ action: "approve" | "dismiss";
66
+ }): Promise<{
67
+ status: PendingCreationStatus;
68
+ createdId: string | null;
69
+ }>;
70
+ //# sourceMappingURL=aiProposals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiProposals.d.ts","sourceRoot":"/","sources":["services/aiProposals.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,aAAa,EACd,MAAM,mCAAmC,CAAC;AAE3C,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;AAEzE,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACjI;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/H;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3H;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACrI;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACnI;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAWpI;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,YAAY,EACvB,KAAK,EAAE,UAAU,EAAE,GAClB;IAAE,gBAAgB,EAAE,eAAe,EAAE,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,CAAA;CAAE,CA4C9D;AAuMD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAAA;CAAE;;;GAkHhF"}