@studious-lms/server 1.14.0 → 1.15.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.
- package/.github/workflows/deploy.yml +1 -1
- package/dist/instrument.js +3 -3
- package/dist/instrument.js.map +1 -1
- package/dist/lib/inferDocumentFormat.d.ts +10 -0
- package/dist/lib/inferDocumentFormat.d.ts.map +1 -0
- package/dist/lib/inferDocumentFormat.js +48 -0
- package/dist/lib/inferDocumentFormat.js.map +1 -0
- package/dist/lib/legal.d.ts +3 -0
- package/dist/lib/legal.d.ts.map +1 -0
- package/dist/lib/legal.js +6 -0
- package/dist/lib/legal.js.map +1 -0
- package/dist/models/announcement.d.ts +47 -45
- package/dist/models/announcement.d.ts.map +1 -1
- package/dist/models/assignment.d.ts +75 -75
- package/dist/models/auth.d.ts +8 -0
- package/dist/models/auth.d.ts.map +1 -1
- package/dist/models/auth.js +4 -2
- package/dist/models/auth.js.map +1 -1
- package/dist/models/class.d.ts +13 -13
- package/dist/models/comment.d.ts +6 -6
- package/dist/models/conversation.d.ts +23 -23
- package/dist/models/event.d.ts +20 -18
- package/dist/models/event.d.ts.map +1 -1
- package/dist/models/file.d.ts +33 -9
- package/dist/models/file.d.ts.map +1 -1
- package/dist/models/labChat.d.ts +4 -4
- package/dist/models/marketing.d.ts +2 -15
- package/dist/models/marketing.d.ts.map +1 -1
- package/dist/models/marketing.js +12 -4
- package/dist/models/marketing.js.map +1 -1
- package/dist/models/message.d.ts +13 -13
- package/dist/models/newtonChat.d.ts +3 -3
- package/dist/models/notification.d.ts +4 -4
- package/dist/models/worksheet.d.ts +121 -121
- package/dist/pipelines/aiLabChat.d.ts +7 -1
- package/dist/pipelines/aiLabChat.d.ts.map +1 -1
- package/dist/pipelines/aiLabChat.js +153 -67
- package/dist/pipelines/aiLabChat.js.map +1 -1
- package/dist/pipelines/aiLabChatContract.d.ts +34 -195
- package/dist/pipelines/aiLabChatContract.d.ts.map +1 -1
- package/dist/pipelines/aiLabChatContract.js +9 -19
- package/dist/pipelines/aiLabChatContract.js.map +1 -1
- package/dist/pipelines/gradeWorksheet.d.ts +6 -6
- package/dist/pipelines/labChatPrompt.d.ts +8 -3
- package/dist/pipelines/labChatPrompt.d.ts.map +1 -1
- package/dist/pipelines/labChatPrompt.js +52 -14
- package/dist/pipelines/labChatPrompt.js.map +1 -1
- package/dist/pipelines/pdfToWorksheet.d.ts +1 -1
- package/dist/routers/_app.d.ts +750 -546
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/announcement.d.ts +40 -40
- package/dist/routers/assignment.d.ts +131 -121
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/auth.d.ts +2 -0
- package/dist/routers/auth.d.ts.map +1 -1
- package/dist/routers/auth.js +15 -2
- package/dist/routers/auth.js.map +1 -1
- package/dist/routers/class.d.ts +12 -8
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/comment.d.ts +5 -5
- package/dist/routers/conversation.d.ts +6 -6
- package/dist/routers/discussion.d.ts +3 -3
- package/dist/routers/embedding.d.ts +6 -2
- package/dist/routers/embedding.d.ts.map +1 -1
- package/dist/routers/embedding.js +44 -36
- package/dist/routers/embedding.js.map +1 -1
- package/dist/routers/event.d.ts +20 -18
- package/dist/routers/event.d.ts.map +1 -1
- package/dist/routers/file.d.ts +2 -2
- package/dist/routers/labChat.d.ts +3 -3
- package/dist/routers/marketing.d.ts +0 -13
- package/dist/routers/marketing.d.ts.map +1 -1
- package/dist/routers/notifications.d.ts +4 -4
- package/dist/routers/school.d.ts +4 -0
- package/dist/routers/school.d.ts.map +1 -1
- package/dist/routers/search.d.ts +2 -2
- package/dist/routers/user.d.ts +89 -0
- package/dist/routers/user.d.ts.map +1 -1
- package/dist/routers/user.js +19 -2
- package/dist/routers/user.js.map +1 -1
- package/dist/routers/worksheet.d.ts +44 -44
- package/dist/routes/aiStream.d.ts.map +1 -1
- package/dist/routes/aiStream.js +41 -11
- package/dist/routes/aiStream.js.map +1 -1
- package/dist/seedDatabase.d.ts +3 -1
- package/dist/seedDatabase.d.ts.map +1 -1
- package/dist/services/aiChatStream.d.ts +20 -0
- package/dist/services/aiChatStream.d.ts.map +1 -1
- package/dist/services/aiChatStream.js +110 -13
- package/dist/services/aiChatStream.js.map +1 -1
- package/dist/services/aiModifierTools.d.ts +0 -16
- package/dist/services/aiModifierTools.d.ts.map +1 -1
- package/dist/services/aiModifierTools.js +112 -3
- package/dist/services/aiModifierTools.js.map +1 -1
- package/dist/services/aiProposalTools.d.ts.map +1 -1
- package/dist/services/aiProposalTools.js +25 -25
- package/dist/services/aiProposalTools.js.map +1 -1
- package/dist/services/aiTools.js +3 -3
- package/dist/services/aiTools.js.map +1 -1
- package/dist/services/announcement.d.ts +34 -34
- package/dist/services/assignment.d.ts +121 -111
- package/dist/services/assignment.d.ts.map +1 -1
- package/dist/services/assignment.js +4 -2
- package/dist/services/assignment.js.map +1 -1
- package/dist/services/auth.d.ts +2 -0
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/auth.js +13 -4
- package/dist/services/auth.js.map +1 -1
- package/dist/services/class.d.ts +10 -6
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +7 -3
- package/dist/services/class.js.map +1 -1
- package/dist/services/comment.d.ts +5 -5
- package/dist/services/conversation.d.ts +6 -6
- package/dist/services/discussion.d.ts.map +1 -1
- package/dist/services/discussion.js +9 -2
- package/dist/services/discussion.js.map +1 -1
- package/dist/services/embedding.d.ts +19 -1
- package/dist/services/embedding.d.ts.map +1 -1
- package/dist/services/embedding.js +154 -8
- package/dist/services/embedding.js.map +1 -1
- package/dist/services/event.d.ts +20 -18
- package/dist/services/event.d.ts.map +1 -1
- package/dist/services/file.d.ts +4 -4
- package/dist/services/folder.d.ts.map +1 -1
- package/dist/services/folder.js +32 -2
- package/dist/services/folder.js.map +1 -1
- package/dist/services/labChat.d.ts +3 -3
- package/dist/services/marketing.d.ts +1 -14
- package/dist/services/marketing.d.ts.map +1 -1
- package/dist/services/marketing.js +5 -5
- package/dist/services/marketing.js.map +1 -1
- package/dist/services/notification.d.ts +4 -4
- package/dist/services/openaiDocumentGen.d.ts +37 -0
- package/dist/services/openaiDocumentGen.d.ts.map +1 -0
- package/dist/services/openaiDocumentGen.js +262 -0
- package/dist/services/openaiDocumentGen.js.map +1 -0
- package/dist/services/school.d.ts +4 -0
- package/dist/services/school.d.ts.map +1 -1
- package/dist/services/search.d.ts +1 -1
- package/dist/services/search.d.ts.map +1 -1
- package/dist/services/search.js +27 -2
- package/dist/services/search.js.map +1 -1
- package/dist/services/userPrivacy.d.ts +86 -0
- package/dist/services/userPrivacy.d.ts.map +1 -0
- package/dist/services/userPrivacy.js +184 -0
- package/dist/services/userPrivacy.js.map +1 -0
- package/dist/services/worksheet.d.ts +66 -49
- package/dist/services/worksheet.d.ts.map +1 -1
- package/dist/services/worksheet.js +48 -3
- package/dist/services/worksheet.js.map +1 -1
- package/dist/utils/email.d.ts.map +1 -1
- package/dist/utils/email.js +7 -3
- package/dist/utils/email.js.map +1 -1
- package/dist/workers/processors/embedContent.d.ts.map +1 -1
- package/dist/workers/processors/embedContent.js +16 -25
- package/dist/workers/processors/embedContent.js.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/20260610140000_expand_embedding_source_types/migration.sql +4 -0
- package/prisma/migrations/20260611120000_add_user_terms_acceptance/migration.sql +3 -0
- package/prisma/schema.prisma +6 -0
- package/src/instrument.ts +1 -1
- package/src/lib/inferDocumentFormat.ts +58 -0
- package/src/lib/legal.ts +2 -0
- package/src/models/auth.ts +4 -0
- package/src/models/marketing.ts +10 -2
- package/src/pipelines/aiLabChat.ts +198 -74
- package/src/pipelines/aiLabChatContract.ts +7 -17
- package/src/pipelines/labChatPrompt.ts +64 -14
- package/src/routers/auth.ts +13 -0
- package/src/routers/embedding.ts +44 -39
- package/src/routers/user.ts +26 -0
- package/src/routes/aiStream.ts +47 -9
- package/src/services/aiChatStream.ts +133 -11
- package/src/services/aiModifierTools.ts +154 -1
- package/src/services/aiProposalTools.ts +27 -25
- package/src/services/aiTools.ts +1 -1
- package/src/services/assignment.ts +3 -0
- package/src/services/auth.ts +14 -2
- package/src/services/class.ts +7 -1
- package/src/services/discussion.ts +13 -0
- package/src/services/embedding.ts +167 -6
- package/src/services/folder.ts +31 -0
- package/src/services/marketing.ts +3 -3
- package/src/services/openaiDocumentGen.ts +319 -0
- package/src/services/search.ts +25 -1
- package/src/services/userPrivacy.ts +196 -0
- package/src/services/worksheet.ts +68 -1
- package/src/utils/email.ts +5 -1
- package/src/workers/processors/embedContent.ts +18 -22
- package/tests/helpers/registerInput.ts +20 -0
- package/tests/integration/globalSetup.ts +10 -18
- package/tests/integration/routers/auth.test.ts +13 -18
- package/tests/unit/lib/inferDocumentFormat.test.ts +33 -0
- package/tests/unit/services/aiChatStream.test.ts +92 -0
- package/tests/unit/services/openaiDocumentGen.test.ts +65 -0
|
@@ -15,10 +15,11 @@
|
|
|
15
15
|
* "excessively deep" compiler blow-up on nested schemas.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
!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]="
|
|
18
|
+
!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]="ed55e709-4194-573d-b522-7077f5d6d6bf")}catch(e){}}();
|
|
19
|
+
import { randomUUID } from 'node:crypto';
|
|
19
20
|
import { jsonSchema } from 'ai';
|
|
20
21
|
import { updateAssignmentRecord } from './assignment.js';
|
|
21
|
-
import { updateWorksheetRecord } from './worksheet.js';
|
|
22
|
+
import { addQuestionToWorksheet, deleteWorksheetQuestionRecord, updateWorksheetQuestionRecord, updateWorksheetRecord, } from './worksheet.js';
|
|
22
23
|
const ASSIGNMENT_TYPES = [
|
|
23
24
|
'HOMEWORK', 'QUIZ', 'TEST', 'PROJECT', 'ESSAY', 'DISCUSSION', 'PRESENTATION', 'LAB', 'OTHER',
|
|
24
25
|
];
|
|
@@ -43,6 +44,44 @@ const ASSIGNMENT_FIELDS = {
|
|
|
43
44
|
const WORKSHEET_FIELDS = {
|
|
44
45
|
name: { label: 'name', type: 'string' },
|
|
45
46
|
};
|
|
47
|
+
const WORKSHEET_QUESTION_TYPES = [
|
|
48
|
+
'MULTIPLE_CHOICE', 'TRUE_FALSE', 'SHORT_ANSWER', 'LONG_ANSWER', 'MATH_EXPRESSION', 'ESSAY',
|
|
49
|
+
];
|
|
50
|
+
/** Attach stable ids to model-supplied MCQ options (matches the editor's shape). */
|
|
51
|
+
function buildOptions(options) {
|
|
52
|
+
if (!options || options.length === 0)
|
|
53
|
+
return undefined;
|
|
54
|
+
return options.map((o) => ({
|
|
55
|
+
id: randomUUID(),
|
|
56
|
+
text: o.text,
|
|
57
|
+
isCorrect: Boolean(o.isCorrect),
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
const QUESTION_PROPERTIES = {
|
|
61
|
+
question: { type: 'string', description: 'The question text shown to students.' },
|
|
62
|
+
answer: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'The correct answer. For TRUE_FALSE use "true"/"false". For MULTIPLE_CHOICE leave it empty and mark the correct option instead.',
|
|
65
|
+
},
|
|
66
|
+
type: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
enum: [...WORKSHEET_QUESTION_TYPES],
|
|
69
|
+
description: 'The question type.',
|
|
70
|
+
},
|
|
71
|
+
points: { type: 'number', description: 'Points the question is worth.' },
|
|
72
|
+
options: {
|
|
73
|
+
type: 'array',
|
|
74
|
+
description: 'Answer choices, only for MULTIPLE_CHOICE questions. Mark exactly one as correct.',
|
|
75
|
+
items: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
text: { type: 'string', description: 'The option text.' },
|
|
79
|
+
isCorrect: { type: 'boolean', description: 'Whether this option is the correct answer.' },
|
|
80
|
+
},
|
|
81
|
+
required: ['text'],
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
};
|
|
46
85
|
/** Coerce a model-supplied string value into the type a field expects. */
|
|
47
86
|
function coerceValue(raw, spec) {
|
|
48
87
|
switch (spec.type) {
|
|
@@ -159,7 +198,77 @@ export function worksheetModifierTools(worksheetId, userId, onFieldUpdate) {
|
|
|
159
198
|
return `Updated ${spec.label}.`;
|
|
160
199
|
},
|
|
161
200
|
},
|
|
201
|
+
add_worksheet_question: {
|
|
202
|
+
description: 'Add a new question to the worksheet and save it immediately. ' +
|
|
203
|
+
'Call this once per question to add.',
|
|
204
|
+
inputSchema: jsonSchema({
|
|
205
|
+
type: 'object',
|
|
206
|
+
properties: QUESTION_PROPERTIES,
|
|
207
|
+
required: ['question', 'answer', 'type'],
|
|
208
|
+
}),
|
|
209
|
+
execute: async ({ question, answer, type, points, options, }) => {
|
|
210
|
+
const created = await addQuestionToWorksheet(worksheetId, userId, {
|
|
211
|
+
question,
|
|
212
|
+
answer,
|
|
213
|
+
type,
|
|
214
|
+
points,
|
|
215
|
+
options: buildOptions(options),
|
|
216
|
+
});
|
|
217
|
+
await onFieldUpdate({
|
|
218
|
+
field: 'questions',
|
|
219
|
+
value: { action: 'added', questionId: created.id },
|
|
220
|
+
label: `question "${question.slice(0, 60)}"`,
|
|
221
|
+
});
|
|
222
|
+
return `Added question (id ${created.id}).`;
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
update_worksheet_question: {
|
|
226
|
+
description: 'Update an existing worksheet question by its Q_ID and save it immediately. ' +
|
|
227
|
+
'Only pass the fields that should change.',
|
|
228
|
+
inputSchema: jsonSchema({
|
|
229
|
+
type: 'object',
|
|
230
|
+
properties: {
|
|
231
|
+
questionId: { type: 'string', description: 'The Q_ID of the question to update.' },
|
|
232
|
+
...QUESTION_PROPERTIES,
|
|
233
|
+
},
|
|
234
|
+
required: ['questionId'],
|
|
235
|
+
}),
|
|
236
|
+
execute: async ({ questionId, question, answer, type, points, options, }) => {
|
|
237
|
+
await updateWorksheetQuestionRecord(worksheetId, questionId, userId, {
|
|
238
|
+
...(question !== undefined && { question }),
|
|
239
|
+
...(answer !== undefined && { answer }),
|
|
240
|
+
...(type !== undefined && { type }),
|
|
241
|
+
...(points !== undefined && { points }),
|
|
242
|
+
...(options !== undefined && { options: buildOptions(options) }),
|
|
243
|
+
});
|
|
244
|
+
await onFieldUpdate({
|
|
245
|
+
field: 'questions',
|
|
246
|
+
value: { action: 'updated', questionId },
|
|
247
|
+
label: 'a question',
|
|
248
|
+
});
|
|
249
|
+
return `Updated question ${questionId}.`;
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
delete_worksheet_question: {
|
|
253
|
+
description: 'Delete a worksheet question by its Q_ID. This is permanent.',
|
|
254
|
+
inputSchema: jsonSchema({
|
|
255
|
+
type: 'object',
|
|
256
|
+
properties: {
|
|
257
|
+
questionId: { type: 'string', description: 'The Q_ID of the question to delete.' },
|
|
258
|
+
},
|
|
259
|
+
required: ['questionId'],
|
|
260
|
+
}),
|
|
261
|
+
execute: async ({ questionId }) => {
|
|
262
|
+
await deleteWorksheetQuestionRecord(worksheetId, questionId, userId);
|
|
263
|
+
await onFieldUpdate({
|
|
264
|
+
field: 'questions',
|
|
265
|
+
value: { action: 'deleted', questionId },
|
|
266
|
+
label: 'a question',
|
|
267
|
+
});
|
|
268
|
+
return `Deleted question ${questionId}.`;
|
|
269
|
+
},
|
|
270
|
+
},
|
|
162
271
|
};
|
|
163
272
|
}
|
|
164
273
|
//# sourceMappingURL=aiModifierTools.js.map
|
|
165
|
-
//# debugId=
|
|
274
|
+
//# debugId=ed55e709-4194-573d-b522-7077f5d6d6bf
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiModifierTools.js","sources":["services/aiModifierTools.ts"],"sourceRoot":"/","sourcesContent":["/**\n * AI modifier \"field-update\" tools.\n *\n * Unlike the Lab-chat proposal tools (which only *record* a payload for the\n * teacher to accept later), these tools DIRECTLY edit a single key of an\n * existing assignment or worksheet and persist it immediately via the normal\n * service layer. The modifier route locks the resource (Redis flag + Pusher\n * `modifier-started`) while the stream runs, and each successful field write\n * fires a callback so the route can broadcast `modifier-field-updated` to every\n * open editor — they apply the change live and stay read-only until the run\n * completes or fails.\n *\n * NOTE: like `aiTools.ts` / `aiProposalTools.ts`, these intentionally use\n * `jsonSchema()` rather than the zod `tool()` helper to avoid the TS2589\n * \"excessively deep\" compiler blow-up on nested schemas.\n */\nimport { jsonSchema, type ToolSet } from 'ai';\nimport { updateAssignmentRecord } from './assignment.js';\nimport { updateWorksheetRecord } from './worksheet.js';\n\n/** A single field write that was applied to a resource. */\nexport interface ModifierFieldUpdate {\n field: string;\n value: unknown;\n /** Human-readable label for the change, e.g. \"title\" or \"due date\". */\n label: string;\n}\n\nconst ASSIGNMENT_TYPES = [\n 'HOMEWORK', 'QUIZ', 'TEST', 'PROJECT', 'ESSAY', 'DISCUSSION', 'PRESENTATION', 'LAB', 'OTHER',\n] as const;\n\n/**\n * Editable scalar keys of an assignment, with the coercion + human label used\n * when the model passes a (string) value. Keys map 1:1 to\n * `updateAssignmentRecord` input fields.\n */\nconst ASSIGNMENT_FIELDS: Record<\n string,\n { label: string; type: 'string' | 'number' | 'boolean' | 'date' | 'enum'; enumValues?: readonly string[] }\n> = {\n title: { label: 'title', type: 'string' },\n instructions: { label: 'instructions', type: 'string' },\n dueDate: { label: 'due date', type: 'date' },\n type: { label: 'type', type: 'enum', enumValues: ASSIGNMENT_TYPES },\n maxGrade: { label: 'max grade', type: 'number' },\n graded: { label: 'graded', type: 'boolean' },\n weight: { label: 'weight', type: 'number' },\n acceptFiles: { label: 'file submissions', type: 'boolean' },\n acceptExtendedResponse: { label: 'extended response', type: 'boolean' },\n acceptWorksheet: { label: 'worksheet submissions', type: 'boolean' },\n aiPolicyLevel: { label: 'AI policy level', type: 'number' },\n};\n\nconst WORKSHEET_FIELDS: Record<string, { label: string; type: 'string' }> = {\n name: { label: 'name', type: 'string' },\n};\n\n/** Coerce a model-supplied string value into the type a field expects. */\nfunction coerceValue(\n raw: string,\n spec: { type: 'string' | 'number' | 'boolean' | 'date' | 'enum'; enumValues?: readonly string[] },\n): unknown {\n switch (spec.type) {\n case 'number': {\n const n = Number(raw);\n if (Number.isNaN(n)) throw new Error(`Expected a number but got \"${raw}\"`);\n return n;\n }\n case 'boolean': {\n const v = raw.trim().toLowerCase();\n if (['true', 'yes', '1'].includes(v)) return true;\n if (['false', 'no', '0'].includes(v)) return false;\n throw new Error(`Expected a boolean but got \"${raw}\"`);\n }\n case 'date': {\n const d = new Date(raw);\n if (Number.isNaN(d.getTime())) throw new Error(`Expected an ISO date but got \"${raw}\"`);\n return d.toISOString();\n }\n case 'enum': {\n const v = raw.trim().toUpperCase();\n if (spec.enumValues && !spec.enumValues.includes(v)) {\n throw new Error(`Expected one of ${spec.enumValues.join(', ')} but got \"${raw}\"`);\n }\n return v;\n }\n default:\n return raw;\n }\n}\n\n/**\n * Build the field-update tool for an assignment. The `onFieldUpdate` callback\n * runs after a successful persist so the route can broadcast the change.\n */\nexport function assignmentModifierTools(\n userId: string,\n assignmentId: string,\n classId: string,\n onFieldUpdate: (update: ModifierFieldUpdate) => Promise<void> | void,\n): ToolSet {\n const fieldNames = Object.keys(ASSIGNMENT_FIELDS);\n return {\n update_assignment_field: {\n description:\n 'Directly update a single field of the assignment and save it immediately. ' +\n 'Call this once per field the teacher wants changed. The assignment is locked ' +\n 'for editing until you finish.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n field: {\n type: 'string',\n enum: fieldNames,\n description: 'The assignment field to update.',\n },\n value: {\n type: 'string',\n description:\n 'The new value as a string. Booleans use \"true\"/\"false\", numbers as digits, ' +\n 'dates as ISO 8601, type as one of the allowed enum values.',\n },\n },\n required: ['field', 'value'],\n }),\n execute: async ({ field, value }: { field: string; value: string }) => {\n const spec = ASSIGNMENT_FIELDS[field];\n if (!spec) {\n return `Unknown field \"${field}\". Allowed: ${fieldNames.join(', ')}.`;\n }\n let coerced: unknown;\n try {\n coerced = coerceValue(value, spec);\n } catch (err) {\n return `Could not update ${spec.label}: ${(err as Error).message}`;\n }\n const updateInput: Parameters<typeof updateAssignmentRecord>[1] = {\n id: assignmentId,\n classId,\n };\n (updateInput as Record<string, unknown>)[field] = coerced;\n await updateAssignmentRecord(userId, updateInput);\n await onFieldUpdate({ field, value: coerced, label: spec.label });\n return `Updated ${spec.label}.`;\n },\n },\n };\n}\n\n/** Build the field-update tool for a worksheet. */\nexport function worksheetModifierTools(\n worksheetId: string,\n userId: string,\n onFieldUpdate: (update: ModifierFieldUpdate) => Promise<void> | void,\n): ToolSet {\n const fieldNames = Object.keys(WORKSHEET_FIELDS);\n return {\n update_worksheet_field: {\n description:\n 'Directly update a single field of the worksheet and save it immediately. ' +\n 'The worksheet is locked for editing until you finish.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n field: {\n type: 'string',\n enum: fieldNames,\n description: 'The worksheet field to update.',\n },\n value: { type: 'string', description: 'The new value as a string.' },\n },\n required: ['field', 'value'],\n }),\n execute: async ({ field, value }: { field: string; value: string }) => {\n const spec = WORKSHEET_FIELDS[field];\n if (!spec) {\n return `Unknown field \"${field}\". Allowed: ${fieldNames.join(', ')}.`;\n }\n const updateInput: Parameters<typeof updateWorksheetRecord>[2] = {};\n (updateInput as Record<string, unknown>)[field] = value;\n await updateWorksheetRecord(worksheetId, userId, updateInput);\n await onFieldUpdate({ field, value, label: spec.label });\n return `Updated ${spec.label}.`;\n },\n },\n };\n}\n"],"names":[],"mappings":"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","debug_id":"d1f30ff9-5af3-5e92-b758-96498a1a819d"}
|
|
1
|
+
{"version":3,"file":"aiModifierTools.js","sources":["services/aiModifierTools.ts"],"sourceRoot":"/","sourcesContent":["/**\n * AI modifier \"field-update\" tools.\n *\n * Unlike the Lab-chat proposal tools (which only *record* a payload for the\n * teacher to accept later), these tools DIRECTLY edit a single key of an\n * existing assignment or worksheet and persist it immediately via the normal\n * service layer. The modifier route locks the resource (Redis flag + Pusher\n * `modifier-started`) while the stream runs, and each successful field write\n * fires a callback so the route can broadcast `modifier-field-updated` to every\n * open editor — they apply the change live and stay read-only until the run\n * completes or fails.\n *\n * NOTE: like `aiTools.ts` / `aiProposalTools.ts`, these intentionally use\n * `jsonSchema()` rather than the zod `tool()` helper to avoid the TS2589\n * \"excessively deep\" compiler blow-up on nested schemas.\n */\nimport { randomUUID } from 'node:crypto';\nimport { jsonSchema, type ToolSet } from 'ai';\nimport type { JSONSchema7Definition } from 'json-schema';\nimport type { WorksheetQuestionType } from '@prisma/client';\nimport { updateAssignmentRecord } from './assignment.js';\nimport {\n addQuestionToWorksheet,\n deleteWorksheetQuestionRecord,\n updateWorksheetQuestionRecord,\n updateWorksheetRecord,\n} from './worksheet.js';\n\n/** A single field write that was applied to a resource. */\nexport interface ModifierFieldUpdate {\n field: string;\n value: unknown;\n /** Human-readable label for the change, e.g. \"title\" or \"due date\". */\n label: string;\n}\n\nconst ASSIGNMENT_TYPES = [\n 'HOMEWORK', 'QUIZ', 'TEST', 'PROJECT', 'ESSAY', 'DISCUSSION', 'PRESENTATION', 'LAB', 'OTHER',\n] as const;\n\n/**\n * Editable scalar keys of an assignment, with the coercion + human label used\n * when the model passes a (string) value. Keys map 1:1 to\n * `updateAssignmentRecord` input fields.\n */\nconst ASSIGNMENT_FIELDS: Record<\n string,\n { label: string; type: 'string' | 'number' | 'boolean' | 'date' | 'enum'; enumValues?: readonly string[] }\n> = {\n title: { label: 'title', type: 'string' },\n instructions: { label: 'instructions', type: 'string' },\n dueDate: { label: 'due date', type: 'date' },\n type: { label: 'type', type: 'enum', enumValues: ASSIGNMENT_TYPES },\n maxGrade: { label: 'max grade', type: 'number' },\n graded: { label: 'graded', type: 'boolean' },\n weight: { label: 'weight', type: 'number' },\n acceptFiles: { label: 'file submissions', type: 'boolean' },\n acceptExtendedResponse: { label: 'extended response', type: 'boolean' },\n acceptWorksheet: { label: 'worksheet submissions', type: 'boolean' },\n aiPolicyLevel: { label: 'AI policy level', type: 'number' },\n};\n\nconst WORKSHEET_FIELDS: Record<string, { label: string; type: 'string' }> = {\n name: { label: 'name', type: 'string' },\n};\n\nconst WORKSHEET_QUESTION_TYPES = [\n 'MULTIPLE_CHOICE', 'TRUE_FALSE', 'SHORT_ANSWER', 'LONG_ANSWER', 'MATH_EXPRESSION', 'ESSAY',\n] as const;\n\ninterface QuestionOptionInput {\n text: string;\n isCorrect?: boolean;\n}\n\n/** Attach stable ids to model-supplied MCQ options (matches the editor's shape). */\nfunction buildOptions(options: QuestionOptionInput[] | undefined) {\n if (!options || options.length === 0) return undefined;\n return options.map((o) => ({\n id: randomUUID(),\n text: o.text,\n isCorrect: Boolean(o.isCorrect),\n }));\n}\n\nconst QUESTION_PROPERTIES: Record<string, JSONSchema7Definition> = {\n question: { type: 'string', description: 'The question text shown to students.' },\n answer: {\n type: 'string',\n description:\n 'The correct answer. For TRUE_FALSE use \"true\"/\"false\". For MULTIPLE_CHOICE leave it empty and mark the correct option instead.',\n },\n type: {\n type: 'string',\n enum: [...WORKSHEET_QUESTION_TYPES],\n description: 'The question type.',\n },\n points: { type: 'number', description: 'Points the question is worth.' },\n options: {\n type: 'array',\n description: 'Answer choices, only for MULTIPLE_CHOICE questions. Mark exactly one as correct.',\n items: {\n type: 'object',\n properties: {\n text: { type: 'string', description: 'The option text.' },\n isCorrect: { type: 'boolean', description: 'Whether this option is the correct answer.' },\n },\n required: ['text'],\n },\n },\n};\n\n/** Coerce a model-supplied string value into the type a field expects. */\nfunction coerceValue(\n raw: string,\n spec: { type: 'string' | 'number' | 'boolean' | 'date' | 'enum'; enumValues?: readonly string[] },\n): unknown {\n switch (spec.type) {\n case 'number': {\n const n = Number(raw);\n if (Number.isNaN(n)) throw new Error(`Expected a number but got \"${raw}\"`);\n return n;\n }\n case 'boolean': {\n const v = raw.trim().toLowerCase();\n if (['true', 'yes', '1'].includes(v)) return true;\n if (['false', 'no', '0'].includes(v)) return false;\n throw new Error(`Expected a boolean but got \"${raw}\"`);\n }\n case 'date': {\n const d = new Date(raw);\n if (Number.isNaN(d.getTime())) throw new Error(`Expected an ISO date but got \"${raw}\"`);\n return d.toISOString();\n }\n case 'enum': {\n const v = raw.trim().toUpperCase();\n if (spec.enumValues && !spec.enumValues.includes(v)) {\n throw new Error(`Expected one of ${spec.enumValues.join(', ')} but got \"${raw}\"`);\n }\n return v;\n }\n default:\n return raw;\n }\n}\n\n/**\n * Build the field-update tool for an assignment. The `onFieldUpdate` callback\n * runs after a successful persist so the route can broadcast the change.\n */\nexport function assignmentModifierTools(\n userId: string,\n assignmentId: string,\n classId: string,\n onFieldUpdate: (update: ModifierFieldUpdate) => Promise<void> | void,\n): ToolSet {\n const fieldNames = Object.keys(ASSIGNMENT_FIELDS);\n return {\n update_assignment_field: {\n description:\n 'Directly update a single field of the assignment and save it immediately. ' +\n 'Call this once per field the teacher wants changed. The assignment is locked ' +\n 'for editing until you finish.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n field: {\n type: 'string',\n enum: fieldNames,\n description: 'The assignment field to update.',\n },\n value: {\n type: 'string',\n description:\n 'The new value as a string. Booleans use \"true\"/\"false\", numbers as digits, ' +\n 'dates as ISO 8601, type as one of the allowed enum values.',\n },\n },\n required: ['field', 'value'],\n }),\n execute: async ({ field, value }: { field: string; value: string }) => {\n const spec = ASSIGNMENT_FIELDS[field];\n if (!spec) {\n return `Unknown field \"${field}\". Allowed: ${fieldNames.join(', ')}.`;\n }\n let coerced: unknown;\n try {\n coerced = coerceValue(value, spec);\n } catch (err) {\n return `Could not update ${spec.label}: ${(err as Error).message}`;\n }\n const updateInput: Parameters<typeof updateAssignmentRecord>[1] = {\n id: assignmentId,\n classId,\n };\n (updateInput as Record<string, unknown>)[field] = coerced;\n await updateAssignmentRecord(userId, updateInput);\n await onFieldUpdate({ field, value: coerced, label: spec.label });\n return `Updated ${spec.label}.`;\n },\n },\n };\n}\n\n/** Build the field-update tool for a worksheet. */\nexport function worksheetModifierTools(\n worksheetId: string,\n userId: string,\n onFieldUpdate: (update: ModifierFieldUpdate) => Promise<void> | void,\n): ToolSet {\n const fieldNames = Object.keys(WORKSHEET_FIELDS);\n return {\n update_worksheet_field: {\n description:\n 'Directly update a single field of the worksheet and save it immediately. ' +\n 'The worksheet is locked for editing until you finish.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n field: {\n type: 'string',\n enum: fieldNames,\n description: 'The worksheet field to update.',\n },\n value: { type: 'string', description: 'The new value as a string.' },\n },\n required: ['field', 'value'],\n }),\n execute: async ({ field, value }: { field: string; value: string }) => {\n const spec = WORKSHEET_FIELDS[field];\n if (!spec) {\n return `Unknown field \"${field}\". Allowed: ${fieldNames.join(', ')}.`;\n }\n const updateInput: Parameters<typeof updateWorksheetRecord>[2] = {};\n (updateInput as Record<string, unknown>)[field] = value;\n await updateWorksheetRecord(worksheetId, userId, updateInput);\n await onFieldUpdate({ field, value, label: spec.label });\n return `Updated ${spec.label}.`;\n },\n },\n add_worksheet_question: {\n description:\n 'Add a new question to the worksheet and save it immediately. ' +\n 'Call this once per question to add.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: QUESTION_PROPERTIES,\n required: ['question', 'answer', 'type'],\n }),\n execute: async ({\n question,\n answer,\n type,\n points,\n options,\n }: {\n question: string;\n answer: string;\n type: WorksheetQuestionType;\n points?: number;\n options?: QuestionOptionInput[];\n }) => {\n const created = await addQuestionToWorksheet(worksheetId, userId, {\n question,\n answer,\n type,\n points,\n options: buildOptions(options),\n });\n await onFieldUpdate({\n field: 'questions',\n value: { action: 'added', questionId: created.id },\n label: `question \"${question.slice(0, 60)}\"`,\n });\n return `Added question (id ${created.id}).`;\n },\n },\n update_worksheet_question: {\n description:\n 'Update an existing worksheet question by its Q_ID and save it immediately. ' +\n 'Only pass the fields that should change.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n questionId: { type: 'string', description: 'The Q_ID of the question to update.' },\n ...QUESTION_PROPERTIES,\n },\n required: ['questionId'],\n }),\n execute: async ({\n questionId,\n question,\n answer,\n type,\n points,\n options,\n }: {\n questionId: string;\n question?: string;\n answer?: string;\n type?: WorksheetQuestionType;\n points?: number;\n options?: QuestionOptionInput[];\n }) => {\n await updateWorksheetQuestionRecord(worksheetId, questionId, userId, {\n ...(question !== undefined && { question }),\n ...(answer !== undefined && { answer }),\n ...(type !== undefined && { type }),\n ...(points !== undefined && { points }),\n ...(options !== undefined && { options: buildOptions(options) }),\n });\n await onFieldUpdate({\n field: 'questions',\n value: { action: 'updated', questionId },\n label: 'a question',\n });\n return `Updated question ${questionId}.`;\n },\n },\n delete_worksheet_question: {\n description:\n 'Delete a worksheet question by its Q_ID. This is permanent.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n questionId: { type: 'string', description: 'The Q_ID of the question to delete.' },\n },\n required: ['questionId'],\n }),\n execute: async ({ questionId }: { questionId: string }) => {\n await deleteWorksheetQuestionRecord(worksheetId, questionId, userId);\n await onFieldUpdate({\n field: 'questions',\n value: { action: 'deleted', questionId },\n label: 'a question',\n });\n return `Deleted question ${questionId}.`;\n },\n },\n };\n}\n"],"names":[],"mappings":"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","debug_id":"ed55e709-4194-573d-b522-7077f5d6d6bf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiProposalTools.d.ts","sourceRoot":"/","sources":["services/aiProposalTools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,IAAI,CAAC;AAE9C,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,WAAW,EACZ,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"aiProposalTools.d.ts","sourceRoot":"/","sources":["services/aiProposalTools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,IAAI,CAAC;AAE9C,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,WAAW,EACZ,MAAM,mCAAmC,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAClC,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,IAAI,EAAE,WAAW,EAAE,CAAC;CACrB;AAED,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD;AAuDD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAmLjE"}
|
|
@@ -16,7 +16,7 @@
|
|
|
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]="
|
|
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]="0c9ff67f-a8a4-5232-b858-905d3275b385")}catch(e){}}();
|
|
20
20
|
import { jsonSchema } from 'ai';
|
|
21
21
|
import { v4 } from 'uuid';
|
|
22
22
|
export function createLabProposals() {
|
|
@@ -170,38 +170,38 @@ export function labProposalTools(proposals) {
|
|
|
170
170
|
},
|
|
171
171
|
},
|
|
172
172
|
generate_document: {
|
|
173
|
-
description: 'Generate a
|
|
173
|
+
description: 'Generate a downloadable file and attach it to this message. You are NOT limited to PDF — pick the best format for the request (pptx for slides/presentations, xlsx/csv for data, docx for editable handouts, pdf for print-ready docs, png for diagrams, etc.). Always set format explicitly.',
|
|
174
174
|
inputSchema: jsonSchema({
|
|
175
175
|
type: 'object',
|
|
176
176
|
properties: {
|
|
177
|
-
title: { type: 'string' },
|
|
178
|
-
|
|
179
|
-
type: '
|
|
180
|
-
description: '
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
description: 'Optional styling metadata',
|
|
191
|
-
},
|
|
192
|
-
},
|
|
193
|
-
required: ['format', 'content'],
|
|
194
|
-
},
|
|
177
|
+
title: { type: 'string', description: 'Document title' },
|
|
178
|
+
content: {
|
|
179
|
+
type: 'string',
|
|
180
|
+
description: 'Full body — markdown or plain text with headings, lists, tables, slide notes, etc.',
|
|
181
|
+
},
|
|
182
|
+
format: {
|
|
183
|
+
type: 'string',
|
|
184
|
+
description: 'Output file type. REQUIRED. pptx=slides/presentation, xlsx/csv=spreadsheet/data, docx=Word handout, pdf=printable doc, md/txt/html=text, png/jpeg/gif=image, py/js/ts=code.',
|
|
185
|
+
enum: [
|
|
186
|
+
'pdf', 'docx', 'doc', 'xlsx', 'pptx', 'csv', 'md', 'html', 'txt',
|
|
187
|
+
'json', 'xml', 'tex', 'png', 'jpeg', 'jpg', 'gif', 'zip', 'tar',
|
|
188
|
+
'py', 'js', 'ts', 'css', 'sh',
|
|
189
|
+
],
|
|
195
190
|
},
|
|
196
191
|
},
|
|
197
|
-
required: ['title', '
|
|
192
|
+
required: ['title', 'content', 'format'],
|
|
198
193
|
}),
|
|
199
|
-
execute: async ({ title,
|
|
200
|
-
proposals.docs.push({
|
|
201
|
-
|
|
194
|
+
execute: async ({ title, content, format }) => {
|
|
195
|
+
proposals.docs.push({
|
|
196
|
+
title,
|
|
197
|
+
content: content.trim(),
|
|
198
|
+
format: (format ?? 'pdf'),
|
|
199
|
+
});
|
|
200
|
+
const ext = (format ?? 'pdf').toUpperCase();
|
|
201
|
+
return `Document "${title}" queued for ${ext} generation.`;
|
|
202
202
|
},
|
|
203
203
|
},
|
|
204
204
|
};
|
|
205
205
|
}
|
|
206
206
|
//# sourceMappingURL=aiProposalTools.js.map
|
|
207
|
-
//# debugId=
|
|
207
|
+
//# debugId=0c9ff67f-a8a4-5232-b858-905d3275b385
|
|
@@ -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';\nimport type { DocumentBlock } from '../lib/jsonStyles.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 blocks: DocumentBlock[];\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 document (rendered to a PDF and attached to the message). Provide the document title and an ordered list of formatting blocks.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n title: { type: 'string' },\n blocks: {\n type: 'array',\n description: 'Ordered list of document formatting blocks',\n items: {\n type: 'object',\n properties: {\n format: { type: 'number', description: 'Block format id (0-12)' },\n content: {\n description: 'String, or array of strings for list blocks',\n },\n metadata: {\n type: 'object',\n description: 'Optional styling metadata',\n },\n },\n required: ['format', 'content'],\n },\n },\n },\n required: ['title', 'blocks'],\n }),\n execute: async ({ title, blocks }: GenerateDocumentArgs) => {\n proposals.docs.push({ title, blocks } as unknown as DocToCreate);\n return `Document \"${title}\" queued for 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;AAgB1B,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;AAoCX;;;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,2IAA2I;YAC7I,WAAW,EAAE,UAAU,CAAC;gBACtB,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBACzB,MAAM,EAAE;wBACN,IAAI,EAAE,OAAO;wBACb,WAAW,EAAE,4CAA4C;wBACzD,KAAK,EAAE;4BACL,IAAI,EAAE,QAAQ;4BACd,UAAU,EAAE;gCACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,wBAAwB,EAAE;gCACjE,OAAO,EAAE;oCACP,WAAW,EAAE,6CAA6C;iCAC3D;gCACD,QAAQ,EAAE;oCACR,IAAI,EAAE,QAAQ;oCACd,WAAW,EAAE,2BAA2B;iCACzC;6BACF;4BACD,QAAQ,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC;yBAChC;qBACF;iBACF;gBACD,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC;aAC9B,CAAC;YACF,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAwB,EAAE,EAAE;gBACzD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAA4B,CAAC,CAAC;gBACjE,OAAO,aAAa,KAAK,0BAA0B,CAAC;YACtD,CAAC;SACF;KACF,CAAC;AACJ,CAAC","debug_id":"68fcd1e0-9203-516c-abb8-0ea09e76afca"}
|
|
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. You are NOT limited to PDF — pick the best format for the request (pptx for slides/presentations, xlsx/csv for data, docx for editable handouts, pdf for print-ready docs, png for diagrams, etc.). 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 — markdown or plain text with headings, lists, tables, slide notes, etc.',\n },\n format: {\n type: 'string',\n description:\n 'Output file type. REQUIRED. pptx=slides/presentation, xlsx/csv=spreadsheet/data, docx=Word handout, pdf=printable doc, md/txt/html=text, png/jpeg/gif=image, py/js/ts=code.',\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":"0c9ff67f-a8a4-5232-b858-905d3275b385"}
|
package/dist/services/aiTools.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* and web search tools.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!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]="
|
|
7
|
+
!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]="92c04dcc-74fa-5dc9-90cb-1ee91299efe7")}catch(e){}}();
|
|
8
8
|
import { jsonSchema } from 'ai';
|
|
9
9
|
import OpenAI from 'openai';
|
|
10
10
|
import { searchEmbeddings } from './embedding.js';
|
|
@@ -240,7 +240,7 @@ export function aiTools(classId) {
|
|
|
240
240
|
const client = new OpenAI();
|
|
241
241
|
const response = await client.responses.create({
|
|
242
242
|
model: 'gpt-4o-mini',
|
|
243
|
-
tools: [{ type: '
|
|
243
|
+
tools: [{ type: 'web_search' }],
|
|
244
244
|
input: query,
|
|
245
245
|
});
|
|
246
246
|
const messageOutput = response.output.find((item) => item.type === 'message');
|
|
@@ -268,4 +268,4 @@ export function aiTools(classId) {
|
|
|
268
268
|
};
|
|
269
269
|
}
|
|
270
270
|
//# sourceMappingURL=aiTools.js.map
|
|
271
|
-
//# debugId=
|
|
271
|
+
//# debugId=92c04dcc-74fa-5dc9-90cb-1ee91299efe7
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiTools.js","sources":["services/aiTools.ts"],"sourceRoot":"/","sourcesContent":["/**\n * AI Tool definitions and execution for agent tool calls.\n * Provides RAG search, assignment lookup, worksheet creation, student progress,\n * and web search tools.\n */\nimport { jsonSchema, type ToolSet } from 'ai';\nimport OpenAI from 'openai';\nimport { searchEmbeddings } from './embedding.js';\nimport { prisma } from '../lib/prisma.js';\nimport { logger } from '../utils/logger.js';\n\nexport interface ToolCallResult {\n toolName: string;\n result: unknown;\n}\n\n/**\n * Build the tool set for a given class context.\n * Tools are scoped to a specific class for security.\n */\nexport function aiTools(classId: string): ToolSet {\n return {\n search_materials: {\n description: 'Search class materials, files, assignments, worksheets, and announcements using semantic similarity. Use this to find relevant context for answering questions.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n query: { type: 'string', description: 'The search query to find relevant materials' },\n limit: { type: 'number', description: 'Maximum results (1-10)', default: 5 },\n },\n required: ['query'],\n }),\n execute: async ({ query, limit = 5 }: { query: string; limit?: number }) => {\n try {\n const results = await searchEmbeddings({ classId, query, limit });\n return results.map((r) => ({\n sourceType: r.sourceType,\n sourceId: r.sourceId,\n content: r.content.slice(0, 500),\n similarity: Math.round(r.similarity * 100) / 100,\n metadata: r.metadata,\n }));\n } catch (error) {\n logger.error('search_materials tool failed', { error, classId, query });\n return [];\n }\n },\n },\n\n search_assignments: {\n description: 'Search existing assignments by title, instructions, or type. Returns assignment details including due dates and submission types.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Search query for assignments' },\n limit: { type: 'number', description: 'Maximum results (1-10)', default: 5 },\n },\n required: ['query'],\n }),\n execute: async ({ query, limit = 5 }: { query: string; limit?: number }) => {\n try {\n const results = await searchEmbeddings({\n classId,\n query,\n limit,\n sourceTypes: ['ASSIGNMENT'],\n });\n\n const assignmentIds = results.map((r) => r.sourceId);\n const assignments = await prisma.assignment.findMany({\n where: { id: { in: assignmentIds } },\n select: {\n id: true,\n title: true,\n instructions: true,\n type: true,\n dueDate: true,\n maxGrade: true,\n section: { select: { name: true } },\n },\n });\n\n return assignments.map((a) => ({\n id: a.id,\n title: a.title,\n instructions: a.instructions?.slice(0, 200) ?? null,\n type: a.type,\n dueDate: a.dueDate.toISOString(),\n maxGrade: a.maxGrade,\n section: a.section?.name ?? null,\n }));\n } catch (error) {\n logger.error('search_assignments tool failed', { error, classId, query });\n return [];\n }\n },\n },\n\n get_student_progress: {\n description: 'Get progress summary for a specific student in this class, including grades and submission status.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n studentId: { type: 'string', description: 'The student user ID' },\n },\n required: ['studentId'],\n }),\n execute: async ({ studentId }: { studentId: string }) => {\n try {\n const submissions = await prisma.submission.findMany({\n where: {\n studentId,\n assignment: { classId },\n },\n select: {\n id: true,\n gradeReceived: true,\n submittedAt: true,\n assignment: {\n select: {\n title: true,\n maxGrade: true,\n type: true,\n },\n },\n },\n orderBy: { submittedAt: 'desc' },\n take: 20,\n });\n\n const totalAssignments = await prisma.assignment.count({\n where: { classId },\n });\n\n const submitted = submissions.filter((s) => s.submittedAt);\n const graded = submissions.filter((s) => s.gradeReceived !== null);\n const avgGrade = graded.length > 0\n ? graded.reduce((sum, s) => sum + (s.gradeReceived || 0), 0) / graded.length\n : null;\n\n return {\n studentId,\n totalAssignments,\n submittedCount: submitted.length,\n gradedCount: graded.length,\n averageGrade: avgGrade ? Math.round(avgGrade * 10) / 10 : null,\n recentSubmissions: submissions.slice(0, 5).map((s) => ({\n assignment: s.assignment.title,\n gradeReceived: s.gradeReceived,\n maxGrade: s.assignment.maxGrade,\n submittedAt: s.submittedAt?.toISOString() ?? null,\n })),\n };\n } catch (error) {\n logger.error('get_student_progress tool failed', { error, classId, studentId });\n return { error: 'Failed to fetch student progress' };\n }\n },\n },\n\n get_worksheet_details: {\n description: 'Get full details of a worksheet including all questions, answers, and mark schemes.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n worksheetId: { type: 'string', description: 'The worksheet ID to look up' },\n },\n required: ['worksheetId'],\n }),\n execute: async ({ worksheetId }: { worksheetId: string }) => {\n try {\n const worksheet = await prisma.worksheet.findUnique({\n where: { id: worksheetId, classId },\n include: {\n questions: {\n orderBy: { order: 'asc' },\n },\n },\n });\n\n if (!worksheet) {\n return { error: 'Worksheet not found' };\n }\n\n return {\n id: worksheet.id,\n name: worksheet.name,\n questions: worksheet.questions.map((q) => ({\n id: q.id,\n type: q.type,\n question: q.question,\n answer: q.answer,\n options: q.options,\n points: q.points,\n order: q.order,\n })),\n };\n } catch (error) {\n logger.error('get_worksheet_details tool failed', { error, classId, worksheetId });\n return { error: 'Failed to fetch worksheet' };\n }\n },\n },\n\n get_mark_scheme: {\n description: 'Get a mark scheme (rubric) by ID, including criteria and point allocations.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n markSchemeId: { type: 'string', description: 'The mark scheme ID' },\n },\n required: ['markSchemeId'],\n }),\n execute: async ({ markSchemeId }: { markSchemeId: string }) => {\n try {\n const markScheme = await prisma.markScheme.findUnique({\n where: { id: markSchemeId },\n select: { id: true, name: true, structured: true },\n });\n\n if (!markScheme) {\n return { error: 'Mark scheme not found' };\n }\n\n let parsed: unknown = {};\n try { parsed = JSON.parse(markScheme.structured || '{}'); } catch { /* noop */ }\n\n return {\n id: markScheme.id,\n name: markScheme.name,\n structured: parsed,\n };\n } catch (error) {\n logger.error('get_mark_scheme tool failed', { error, classId, markSchemeId });\n return { error: 'Failed to fetch mark scheme' };\n }\n },\n },\n\n web_search: {\n description: 'Search the web for current information on a topic. Use this when you need up-to-date facts, definitions, explanations, or context beyond the class materials.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n query: { type: 'string', description: 'The search query to look up on the web' },\n },\n required: ['query'],\n }),\n execute: async ({ query }: { query: string }) => {\n try {\n const client = new OpenAI();\n const response = await client.responses.create({\n model: 'gpt-4o-mini',\n tools: [{ type: 'web_search_preview' }],\n input: query,\n });\n\n const messageOutput = response.output.find(\n (item) => item.type === 'message',\n );\n if (!messageOutput || messageOutput.type !== 'message') {\n return { summary: 'No results found.', sources: [] };\n }\n\n const textContent = messageOutput.content.find(\n (c) => c.type === 'output_text',\n );\n if (!textContent || textContent.type !== 'output_text') {\n return { summary: 'No results found.', sources: [] };\n }\n\n const sources = textContent.annotations\n .filter(\n (a): a is Extract<typeof a, { type: 'url_citation' }> =>\n a.type === 'url_citation',\n )\n .map((a) => ({ url: a.url, title: a.title }));\n\n return {\n summary: textContent.text.slice(0, 2000),\n sources: sources.slice(0, 5),\n };\n } catch (error) {\n logger.error('web_search tool failed', { error, query });\n return { summary: 'Web search failed. Please try again.', sources: [] };\n }\n },\n },\n };\n}\n"],"names":[],"mappings":"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","debug_id":"08e8556c-8e72-5041-a040-17a623b35c7c"}
|
|
1
|
+
{"version":3,"file":"aiTools.js","sources":["services/aiTools.ts"],"sourceRoot":"/","sourcesContent":["/**\n * AI Tool definitions and execution for agent tool calls.\n * Provides RAG search, assignment lookup, worksheet creation, student progress,\n * and web search tools.\n */\nimport { jsonSchema, type ToolSet } from 'ai';\nimport OpenAI from 'openai';\nimport { searchEmbeddings } from './embedding.js';\nimport { prisma } from '../lib/prisma.js';\nimport { logger } from '../utils/logger.js';\n\nexport interface ToolCallResult {\n toolName: string;\n result: unknown;\n}\n\n/**\n * Build the tool set for a given class context.\n * Tools are scoped to a specific class for security.\n */\nexport function aiTools(classId: string): ToolSet {\n return {\n search_materials: {\n description: 'Search class materials, files, assignments, worksheets, and announcements using semantic similarity. Use this to find relevant context for answering questions.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n query: { type: 'string', description: 'The search query to find relevant materials' },\n limit: { type: 'number', description: 'Maximum results (1-10)', default: 5 },\n },\n required: ['query'],\n }),\n execute: async ({ query, limit = 5 }: { query: string; limit?: number }) => {\n try {\n const results = await searchEmbeddings({ classId, query, limit });\n return results.map((r) => ({\n sourceType: r.sourceType,\n sourceId: r.sourceId,\n content: r.content.slice(0, 500),\n similarity: Math.round(r.similarity * 100) / 100,\n metadata: r.metadata,\n }));\n } catch (error) {\n logger.error('search_materials tool failed', { error, classId, query });\n return [];\n }\n },\n },\n\n search_assignments: {\n description: 'Search existing assignments by title, instructions, or type. Returns assignment details including due dates and submission types.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Search query for assignments' },\n limit: { type: 'number', description: 'Maximum results (1-10)', default: 5 },\n },\n required: ['query'],\n }),\n execute: async ({ query, limit = 5 }: { query: string; limit?: number }) => {\n try {\n const results = await searchEmbeddings({\n classId,\n query,\n limit,\n sourceTypes: ['ASSIGNMENT'],\n });\n\n const assignmentIds = results.map((r) => r.sourceId);\n const assignments = await prisma.assignment.findMany({\n where: { id: { in: assignmentIds } },\n select: {\n id: true,\n title: true,\n instructions: true,\n type: true,\n dueDate: true,\n maxGrade: true,\n section: { select: { name: true } },\n },\n });\n\n return assignments.map((a) => ({\n id: a.id,\n title: a.title,\n instructions: a.instructions?.slice(0, 200) ?? null,\n type: a.type,\n dueDate: a.dueDate.toISOString(),\n maxGrade: a.maxGrade,\n section: a.section?.name ?? null,\n }));\n } catch (error) {\n logger.error('search_assignments tool failed', { error, classId, query });\n return [];\n }\n },\n },\n\n get_student_progress: {\n description: 'Get progress summary for a specific student in this class, including grades and submission status.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n studentId: { type: 'string', description: 'The student user ID' },\n },\n required: ['studentId'],\n }),\n execute: async ({ studentId }: { studentId: string }) => {\n try {\n const submissions = await prisma.submission.findMany({\n where: {\n studentId,\n assignment: { classId },\n },\n select: {\n id: true,\n gradeReceived: true,\n submittedAt: true,\n assignment: {\n select: {\n title: true,\n maxGrade: true,\n type: true,\n },\n },\n },\n orderBy: { submittedAt: 'desc' },\n take: 20,\n });\n\n const totalAssignments = await prisma.assignment.count({\n where: { classId },\n });\n\n const submitted = submissions.filter((s) => s.submittedAt);\n const graded = submissions.filter((s) => s.gradeReceived !== null);\n const avgGrade = graded.length > 0\n ? graded.reduce((sum, s) => sum + (s.gradeReceived || 0), 0) / graded.length\n : null;\n\n return {\n studentId,\n totalAssignments,\n submittedCount: submitted.length,\n gradedCount: graded.length,\n averageGrade: avgGrade ? Math.round(avgGrade * 10) / 10 : null,\n recentSubmissions: submissions.slice(0, 5).map((s) => ({\n assignment: s.assignment.title,\n gradeReceived: s.gradeReceived,\n maxGrade: s.assignment.maxGrade,\n submittedAt: s.submittedAt?.toISOString() ?? null,\n })),\n };\n } catch (error) {\n logger.error('get_student_progress tool failed', { error, classId, studentId });\n return { error: 'Failed to fetch student progress' };\n }\n },\n },\n\n get_worksheet_details: {\n description: 'Get full details of a worksheet including all questions, answers, and mark schemes.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n worksheetId: { type: 'string', description: 'The worksheet ID to look up' },\n },\n required: ['worksheetId'],\n }),\n execute: async ({ worksheetId }: { worksheetId: string }) => {\n try {\n const worksheet = await prisma.worksheet.findUnique({\n where: { id: worksheetId, classId },\n include: {\n questions: {\n orderBy: { order: 'asc' },\n },\n },\n });\n\n if (!worksheet) {\n return { error: 'Worksheet not found' };\n }\n\n return {\n id: worksheet.id,\n name: worksheet.name,\n questions: worksheet.questions.map((q) => ({\n id: q.id,\n type: q.type,\n question: q.question,\n answer: q.answer,\n options: q.options,\n points: q.points,\n order: q.order,\n })),\n };\n } catch (error) {\n logger.error('get_worksheet_details tool failed', { error, classId, worksheetId });\n return { error: 'Failed to fetch worksheet' };\n }\n },\n },\n\n get_mark_scheme: {\n description: 'Get a mark scheme (rubric) by ID, including criteria and point allocations.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n markSchemeId: { type: 'string', description: 'The mark scheme ID' },\n },\n required: ['markSchemeId'],\n }),\n execute: async ({ markSchemeId }: { markSchemeId: string }) => {\n try {\n const markScheme = await prisma.markScheme.findUnique({\n where: { id: markSchemeId },\n select: { id: true, name: true, structured: true },\n });\n\n if (!markScheme) {\n return { error: 'Mark scheme not found' };\n }\n\n let parsed: unknown = {};\n try { parsed = JSON.parse(markScheme.structured || '{}'); } catch { /* noop */ }\n\n return {\n id: markScheme.id,\n name: markScheme.name,\n structured: parsed,\n };\n } catch (error) {\n logger.error('get_mark_scheme tool failed', { error, classId, markSchemeId });\n return { error: 'Failed to fetch mark scheme' };\n }\n },\n },\n\n web_search: {\n description: 'Search the web for current information on a topic. Use this when you need up-to-date facts, definitions, explanations, or context beyond the class materials.',\n inputSchema: jsonSchema({\n type: 'object',\n properties: {\n query: { type: 'string', description: 'The search query to look up on the web' },\n },\n required: ['query'],\n }),\n execute: async ({ query }: { query: string }) => {\n try {\n const client = new OpenAI();\n const response = await client.responses.create({\n model: 'gpt-4o-mini',\n tools: [{ type: 'web_search' }],\n input: query,\n });\n\n const messageOutput = response.output.find(\n (item) => item.type === 'message',\n );\n if (!messageOutput || messageOutput.type !== 'message') {\n return { summary: 'No results found.', sources: [] };\n }\n\n const textContent = messageOutput.content.find(\n (c) => c.type === 'output_text',\n );\n if (!textContent || textContent.type !== 'output_text') {\n return { summary: 'No results found.', sources: [] };\n }\n\n const sources = textContent.annotations\n .filter(\n (a): a is Extract<typeof a, { type: 'url_citation' }> =>\n a.type === 'url_citation',\n )\n .map((a) => ({ url: a.url, title: a.title }));\n\n return {\n summary: textContent.text.slice(0, 2000),\n sources: sources.slice(0, 5),\n };\n } catch (error) {\n logger.error('web_search tool failed', { error, query });\n return { summary: 'Web search failed. Please try again.', sources: [] };\n }\n },\n },\n };\n}\n"],"names":[],"mappings":"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","debug_id":"92c04dcc-74fa-5dc9-90cb-1ee91299efe7"}
|
|
@@ -6,6 +6,15 @@ export declare function getAllAnnouncements(classId: string): Promise<{
|
|
|
6
6
|
id: string;
|
|
7
7
|
createdAt: Date;
|
|
8
8
|
remarks: string;
|
|
9
|
+
attachments: {
|
|
10
|
+
path: string;
|
|
11
|
+
type: string;
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
size: number | null;
|
|
15
|
+
uploadedAt: Date | null;
|
|
16
|
+
thumbnailId: string | null;
|
|
17
|
+
}[];
|
|
9
18
|
modifiedAt: Date | null;
|
|
10
19
|
teacher: {
|
|
11
20
|
id: string;
|
|
@@ -16,6 +25,13 @@ export declare function getAllAnnouncements(classId: string): Promise<{
|
|
|
16
25
|
profilePictureThumbnail: string | null;
|
|
17
26
|
} | null;
|
|
18
27
|
};
|
|
28
|
+
}[];
|
|
29
|
+
}>;
|
|
30
|
+
export declare function getAnnouncement(id: string, classId: string): Promise<{
|
|
31
|
+
announcement: {
|
|
32
|
+
id: string;
|
|
33
|
+
createdAt: Date;
|
|
34
|
+
remarks: string;
|
|
19
35
|
attachments: {
|
|
20
36
|
path: string;
|
|
21
37
|
type: string;
|
|
@@ -25,13 +41,6 @@ export declare function getAllAnnouncements(classId: string): Promise<{
|
|
|
25
41
|
uploadedAt: Date | null;
|
|
26
42
|
thumbnailId: string | null;
|
|
27
43
|
}[];
|
|
28
|
-
}[];
|
|
29
|
-
}>;
|
|
30
|
-
export declare function getAnnouncement(id: string, classId: string): Promise<{
|
|
31
|
-
announcement: {
|
|
32
|
-
id: string;
|
|
33
|
-
createdAt: Date;
|
|
34
|
-
remarks: string;
|
|
35
44
|
modifiedAt: Date | null;
|
|
36
45
|
teacher: {
|
|
37
46
|
id: string;
|
|
@@ -42,15 +51,6 @@ export declare function getAnnouncement(id: string, classId: string): Promise<{
|
|
|
42
51
|
profilePictureThumbnail: string | null;
|
|
43
52
|
} | null;
|
|
44
53
|
};
|
|
45
|
-
attachments: {
|
|
46
|
-
path: string;
|
|
47
|
-
type: string;
|
|
48
|
-
id: string;
|
|
49
|
-
name: string;
|
|
50
|
-
size: number | null;
|
|
51
|
-
uploadedAt: Date | null;
|
|
52
|
-
thumbnailId: string | null;
|
|
53
|
-
}[];
|
|
54
54
|
};
|
|
55
55
|
}>;
|
|
56
56
|
export declare function createAnnouncementRecord(userId: string, input: {
|
|
@@ -67,6 +67,15 @@ export declare function createAnnouncementRecord(userId: string, input: {
|
|
|
67
67
|
id: string;
|
|
68
68
|
createdAt: Date;
|
|
69
69
|
remarks: string;
|
|
70
|
+
attachments: {
|
|
71
|
+
path: string;
|
|
72
|
+
type: string;
|
|
73
|
+
id: string;
|
|
74
|
+
name: string;
|
|
75
|
+
size: number | null;
|
|
76
|
+
uploadedAt: Date | null;
|
|
77
|
+
thumbnailId: string | null;
|
|
78
|
+
}[];
|
|
70
79
|
modifiedAt: Date | null;
|
|
71
80
|
teacher: {
|
|
72
81
|
id: string;
|
|
@@ -77,15 +86,6 @@ export declare function createAnnouncementRecord(userId: string, input: {
|
|
|
77
86
|
profilePictureThumbnail: string | null;
|
|
78
87
|
} | null;
|
|
79
88
|
};
|
|
80
|
-
attachments: {
|
|
81
|
-
path: string;
|
|
82
|
-
type: string;
|
|
83
|
-
id: string;
|
|
84
|
-
name: string;
|
|
85
|
-
size: number | null;
|
|
86
|
-
uploadedAt: Date | null;
|
|
87
|
-
thumbnailId: string | null;
|
|
88
|
-
}[];
|
|
89
89
|
};
|
|
90
90
|
uploadFiles: DirectUploadFile[] | undefined;
|
|
91
91
|
}>;
|
|
@@ -107,6 +107,15 @@ export declare function updateAnnouncementRecord(userId: string, input: {
|
|
|
107
107
|
id: string;
|
|
108
108
|
createdAt: Date;
|
|
109
109
|
remarks: string;
|
|
110
|
+
attachments: {
|
|
111
|
+
path: string;
|
|
112
|
+
type: string;
|
|
113
|
+
id: string;
|
|
114
|
+
name: string;
|
|
115
|
+
size: number | null;
|
|
116
|
+
uploadedAt: Date | null;
|
|
117
|
+
thumbnailId: string | null;
|
|
118
|
+
}[];
|
|
110
119
|
modifiedAt: Date | null;
|
|
111
120
|
teacher: {
|
|
112
121
|
id: string;
|
|
@@ -117,15 +126,6 @@ export declare function updateAnnouncementRecord(userId: string, input: {
|
|
|
117
126
|
profilePictureThumbnail: string | null;
|
|
118
127
|
} | null;
|
|
119
128
|
};
|
|
120
|
-
attachments: {
|
|
121
|
-
path: string;
|
|
122
|
-
type: string;
|
|
123
|
-
id: string;
|
|
124
|
-
name: string;
|
|
125
|
-
size: number | null;
|
|
126
|
-
uploadedAt: Date | null;
|
|
127
|
-
thumbnailId: string | null;
|
|
128
|
-
}[];
|
|
129
129
|
};
|
|
130
130
|
uploadFiles: DirectUploadFile[] | undefined;
|
|
131
131
|
}>;
|