@studious-lms/server 1.13.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/.dockerignore +28 -0
- package/.env.example +5 -0
- package/.github/workflows/deploy.yml +123 -0
- package/Dockerfile +54 -0
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/instrument.js +3 -3
- package/dist/instrument.js.map +1 -1
- package/dist/lib/config/cors.d.ts.map +1 -1
- package/dist/lib/config/cors.js +31 -11
- package/dist/lib/config/cors.js.map +1 -1
- package/dist/lib/config/env.d.ts +17 -0
- package/dist/lib/config/env.d.ts.map +1 -1
- package/dist/lib/config/env.js +8 -2
- package/dist/lib/config/env.js.map +1 -1
- package/dist/lib/googleCloudStorage.d.ts +10 -0
- package/dist/lib/googleCloudStorage.d.ts.map +1 -1
- package/dist/lib/googleCloudStorage.js +22 -2
- package/dist/lib/googleCloudStorage.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/lib/prisma.d.ts +104 -5
- package/dist/lib/prisma.d.ts.map +1 -1
- package/dist/lib/prisma.js +33 -2
- package/dist/lib/prisma.js.map +1 -1
- package/dist/models/agenda.d.ts +20 -20
- package/dist/models/announcement.d.ts +211 -101
- package/dist/models/announcement.d.ts.map +1 -1
- package/dist/models/assignment.d.ts +560 -362
- package/dist/models/assignment.d.ts.map +1 -1
- package/dist/models/attendance.d.ts +197 -71
- package/dist/models/attendance.d.ts.map +1 -1
- package/dist/models/auth.d.ts +356 -114
- 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 +327 -201
- package/dist/models/class.d.ts.map +1 -1
- package/dist/models/class.js +2 -2
- package/dist/models/class.js.map +1 -1
- package/dist/models/cloudStorage.d.ts +146 -56
- package/dist/models/cloudStorage.d.ts.map +1 -1
- package/dist/models/comment.d.ts +262 -110
- package/dist/models/comment.d.ts.map +1 -1
- package/dist/models/conversation.d.ts +206 -80
- package/dist/models/conversation.d.ts.map +1 -1
- package/dist/models/department.d.ts +196 -70
- package/dist/models/department.d.ts.map +1 -1
- package/dist/models/event.d.ts +305 -141
- package/dist/models/event.d.ts.map +1 -1
- package/dist/models/file.d.ts +422 -272
- package/dist/models/file.d.ts.map +1 -1
- package/dist/models/folder.d.ts +433 -181
- package/dist/models/folder.d.ts.map +1 -1
- package/dist/models/labChat.d.ts +205 -79
- package/dist/models/labChat.d.ts.map +1 -1
- package/dist/models/marketing.d.ts +79 -38
- 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 +97 -43
- package/dist/models/message.d.ts.map +1 -1
- package/dist/models/newtonChat.d.ts +84 -30
- package/dist/models/newtonChat.d.ts.map +1 -1
- package/dist/models/notification.d.ts +57 -21
- package/dist/models/notification.d.ts.map +1 -1
- package/dist/models/school.d.ts +349 -133
- package/dist/models/school.d.ts.map +1 -1
- package/dist/models/section.d.ts +216 -72
- package/dist/models/section.d.ts.map +1 -1
- package/dist/models/tag.d.ts +156 -48
- package/dist/models/tag.d.ts.map +1 -1
- package/dist/models/user.d.ts +82 -28
- package/dist/models/user.d.ts.map +1 -1
- package/dist/models/worksheet.d.ts +1032 -423
- package/dist/models/worksheet.d.ts.map +1 -1
- package/dist/models/worksheet.js +8 -2
- package/dist/models/worksheet.js.map +1 -1
- package/dist/pipelines/aiLabChat.d.ts +7 -9
- package/dist/pipelines/aiLabChat.d.ts.map +1 -1
- package/dist/pipelines/aiLabChat.js +194 -125
- package/dist/pipelines/aiLabChat.js.map +1 -1
- package/dist/pipelines/aiLabChatContract.d.ts +233 -389
- package/dist/pipelines/aiLabChatContract.d.ts.map +1 -1
- package/dist/pipelines/aiLabChatContract.js +54 -70
- package/dist/pipelines/aiLabChatContract.js.map +1 -1
- package/dist/pipelines/aiNewtonChat.d.ts.map +1 -1
- package/dist/pipelines/aiNewtonChat.js +41 -41
- package/dist/pipelines/aiNewtonChat.js.map +1 -1
- package/dist/pipelines/gradeWorksheet.d.ts +8 -8
- package/dist/pipelines/labChatPrompt.d.ts +18 -11
- package/dist/pipelines/labChatPrompt.d.ts.map +1 -1
- package/dist/pipelines/labChatPrompt.js +93 -75
- package/dist/pipelines/labChatPrompt.js.map +1 -1
- package/dist/pipelines/pdfToWorksheet.d.ts +1 -1
- package/dist/routers/_app.d.ts +2601 -2151
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +4 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/admin.d.ts +13 -13
- package/dist/routers/agenda.d.ts +18 -18
- package/dist/routers/announcement.d.ts +60 -60
- package/dist/routers/assignment.d.ts +393 -383
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/attendance.d.ts +10 -10
- package/dist/routers/auth.d.ts +4 -2
- 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 +157 -153
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/comment.d.ts +18 -18
- package/dist/routers/conversation.d.ts +11 -11
- package/dist/routers/department.d.ts +34 -34
- package/dist/routers/discussion.d.ts +68 -56
- package/dist/routers/discussion.d.ts.map +1 -1
- package/dist/routers/discussion.js +6 -2
- package/dist/routers/discussion.js.map +1 -1
- package/dist/routers/embedding.d.ts +73 -0
- package/dist/routers/embedding.d.ts.map +1 -0
- package/dist/routers/embedding.js +151 -0
- package/dist/routers/embedding.js.map +1 -0
- package/dist/routers/event.d.ts +57 -55
- package/dist/routers/event.d.ts.map +1 -1
- package/dist/routers/file.d.ts +14 -14
- package/dist/routers/folder.d.ts +38 -38
- package/dist/routers/labChat.d.ts +16 -16
- package/dist/routers/marketing.d.ts +1 -14
- package/dist/routers/marketing.d.ts.map +1 -1
- package/dist/routers/message.d.ts +13 -13
- package/dist/routers/newtonChat.d.ts +4 -4
- package/dist/routers/notifications.d.ts +5 -5
- package/dist/routers/permissions.d.ts +14 -14
- package/dist/routers/school.d.ts +59 -55
- package/dist/routers/school.d.ts.map +1 -1
- package/dist/routers/search.d.ts +22 -1
- package/dist/routers/search.d.ts.map +1 -1
- package/dist/routers/search.js +9 -3
- package/dist/routers/search.js.map +1 -1
- package/dist/routers/section.d.ts +4 -4
- package/dist/routers/studentProgress.d.ts +1 -1
- package/dist/routers/tag.d.ts +7 -7
- package/dist/routers/user.d.ts +99 -10
- 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 +93 -55
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/routers/worksheet.js +26 -2
- package/dist/routers/worksheet.js.map +1 -1
- package/dist/routes/aiStream.d.ts +2 -0
- package/dist/routes/aiStream.d.ts.map +1 -0
- package/dist/routes/aiStream.js +726 -0
- package/dist/routes/aiStream.js.map +1 -0
- package/dist/seedDatabase.d.ts +3 -1
- package/dist/seedDatabase.d.ts.map +1 -1
- package/dist/seedDatabase.js +6 -6
- package/dist/seedDatabase.js.map +1 -1
- package/dist/services/adminInstitution.d.ts +8 -8
- package/dist/services/adminRunJob.d.ts +4 -4
- package/dist/services/agenda.d.ts +18 -18
- package/dist/services/aiChatStream.d.ts +88 -0
- package/dist/services/aiChatStream.d.ts.map +1 -0
- package/dist/services/aiChatStream.js +254 -0
- package/dist/services/aiChatStream.js.map +1 -0
- package/dist/services/aiModifierTools.d.ts +16 -0
- package/dist/services/aiModifierTools.d.ts.map +1 -0
- package/dist/services/aiModifierTools.js +274 -0
- package/dist/services/aiModifierTools.js.map +1 -0
- package/dist/services/aiProposalTools.d.ts +32 -0
- package/dist/services/aiProposalTools.d.ts.map +1 -0
- package/dist/services/aiProposalTools.js +207 -0
- package/dist/services/aiProposalTools.js.map +1 -0
- package/dist/services/aiStream.d.ts +22 -0
- package/dist/services/aiStream.d.ts.map +1 -0
- package/dist/services/aiStream.js +142 -0
- package/dist/services/aiStream.js.map +1 -0
- package/dist/services/aiTools.d.ts +16 -0
- package/dist/services/aiTools.d.ts.map +1 -0
- package/dist/services/aiTools.js +271 -0
- package/dist/services/aiTools.js.map +1 -0
- package/dist/services/announcement.d.ts +42 -42
- package/dist/services/announcement.d.ts.map +1 -1
- package/dist/services/announcement.js +7 -2
- package/dist/services/announcement.js.map +1 -1
- package/dist/services/assignment.d.ts +355 -345
- package/dist/services/assignment.d.ts.map +1 -1
- package/dist/services/assignment.js +30 -9
- package/dist/services/assignment.js.map +1 -1
- package/dist/services/attendance.d.ts +10 -10
- package/dist/services/auth.d.ts +4 -2
- 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 +146 -142
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +24 -4
- package/dist/services/class.js.map +1 -1
- package/dist/services/comment.d.ts +18 -18
- package/dist/services/conversation.d.ts +11 -11
- package/dist/services/department.d.ts +33 -33
- package/dist/services/discussion.d.ts +58 -58
- package/dist/services/discussion.d.ts.map +1 -1
- package/dist/services/discussion.js +15 -8
- package/dist/services/discussion.js.map +1 -1
- package/dist/services/discussionSummary.d.ts +21 -0
- package/dist/services/discussionSummary.d.ts.map +1 -0
- package/dist/services/discussionSummary.js +179 -0
- package/dist/services/discussionSummary.js.map +1 -0
- package/dist/services/embedding.d.ts +85 -0
- package/dist/services/embedding.d.ts.map +1 -0
- package/dist/services/embedding.js +372 -0
- package/dist/services/embedding.js.map +1 -0
- package/dist/services/event.d.ts +55 -53
- package/dist/services/event.d.ts.map +1 -1
- package/dist/services/file.d.ts +28 -28
- package/dist/services/folder.d.ts +36 -36
- 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 +16 -16
- package/dist/services/marketing.d.ts +2 -15
- 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/message.d.ts +11 -11
- package/dist/services/message.d.ts.map +1 -1
- package/dist/services/message.js +2 -2
- package/dist/services/message.js.map +1 -1
- package/dist/services/newtonChat.d.ts +4 -4
- package/dist/services/notification.d.ts +5 -5
- package/dist/services/notification.d.ts.map +1 -1
- 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/permissions.d.ts +14 -14
- package/dist/services/school.d.ts +54 -50
- package/dist/services/school.d.ts.map +1 -1
- package/dist/services/search.d.ts +13 -1
- package/dist/services/search.d.ts.map +1 -1
- package/dist/services/search.js +145 -2
- package/dist/services/search.js.map +1 -1
- package/dist/services/section.d.ts +3 -3
- package/dist/services/tag.d.ts +4 -4
- package/dist/services/user.d.ts +4 -4
- package/dist/services/user.d.ts.map +1 -1
- package/dist/services/user.js +10 -15
- package/dist/services/user.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 +86 -57
- package/dist/services/worksheet.d.ts.map +1 -1
- package/dist/services/worksheet.js +57 -5
- 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/utils/streamBroadcast.d.ts +11 -0
- package/dist/utils/streamBroadcast.d.ts.map +1 -0
- package/dist/utils/streamBroadcast.js +32 -0
- package/dist/utils/streamBroadcast.js.map +1 -0
- package/dist/workers/connection.d.ts +15 -0
- package/dist/workers/connection.d.ts.map +1 -1
- package/dist/workers/connection.js +20 -2
- package/dist/workers/connection.js.map +1 -1
- package/dist/workers/index.js +4 -2
- package/dist/workers/index.js.map +1 -1
- package/dist/workers/processors/createRunJobWorker.d.ts.map +1 -1
- package/dist/workers/processors/createRunJobWorker.js +31 -8
- package/dist/workers/processors/createRunJobWorker.js.map +1 -1
- package/dist/workers/processors/embedContent.d.ts +8 -0
- package/dist/workers/processors/embedContent.d.ts.map +1 -0
- package/dist/workers/processors/embedContent.js +67 -0
- package/dist/workers/processors/embedContent.js.map +1 -0
- package/dist/workers/queues.d.ts +6 -0
- package/dist/workers/queues.d.ts.map +1 -1
- package/dist/workers/queues.js +5 -3
- package/dist/workers/queues.js.map +1 -1
- package/package.json +5 -1
- package/prisma/migrations/20260609215135_init/migration.sql +1412 -0
- package/prisma/migrations/20260610130000_add_worksheet_tags/migration.sql +13 -0
- 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 +44 -7
- package/src/index.ts +4 -0
- package/src/instrument.ts +1 -1
- package/src/lib/config/cors.ts +32 -9
- package/src/lib/config/env.ts +6 -0
- package/src/lib/googleCloudStorage.ts +21 -0
- package/src/lib/inferDocumentFormat.ts +58 -0
- package/src/lib/legal.ts +2 -0
- package/src/lib/prisma.ts +40 -1
- package/src/models/auth.ts +4 -0
- package/src/models/class.ts +3 -2
- package/src/models/marketing.ts +10 -2
- package/src/models/worksheet.ts +5 -2
- package/src/pipelines/aiLabChat.ts +245 -146
- package/src/pipelines/aiLabChatContract.ts +59 -69
- package/src/pipelines/aiNewtonChat.ts +46 -43
- package/src/pipelines/labChatPrompt.ts +115 -90
- package/src/routers/_app.ts +2 -0
- package/src/routers/auth.ts +13 -0
- package/src/routers/discussion.ts +7 -0
- package/src/routers/embedding.ts +164 -0
- package/src/routers/search.ts +10 -1
- package/src/routers/user.ts +26 -0
- package/src/routers/worksheet.ts +27 -0
- package/src/routes/aiStream.ts +827 -0
- package/src/seedDatabase.ts +4 -4
- package/src/services/aiChatStream.ts +341 -0
- package/src/services/aiModifierTools.ts +341 -0
- package/src/services/aiProposalTools.ts +274 -0
- package/src/services/aiStream.ts +175 -0
- package/src/services/aiTools.ts +290 -0
- package/src/services/announcement.ts +7 -0
- package/src/services/assignment.ts +31 -7
- package/src/services/auth.ts +14 -2
- package/src/services/class.ts +27 -2
- package/src/services/discussion.ts +22 -8
- package/src/services/discussionSummary.ts +226 -0
- package/src/services/embedding.ts +446 -0
- package/src/services/folder.ts +31 -0
- package/src/services/marketing.ts +3 -3
- package/src/services/message.ts +2 -2
- package/src/services/openaiDocumentGen.ts +319 -0
- package/src/services/search.ts +163 -1
- package/src/services/user.ts +9 -17
- package/src/services/userPrivacy.ts +196 -0
- package/src/services/worksheet.ts +77 -3
- package/src/utils/email.ts +5 -1
- package/src/utils/streamBroadcast.ts +48 -0
- package/src/workers/connection.ts +19 -0
- package/src/workers/index.ts +2 -0
- package/src/workers/processors/createRunJobWorker.ts +32 -6
- package/src/workers/processors/embedContent.ts +86 -0
- package/src/workers/queues.ts +5 -1
- 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/pipelines/aiLabChatContract.test.ts +38 -21
- package/tests/unit/pipelines/labChatPrompt.test.ts +23 -36
- package/tests/unit/services/aiChatStream.test.ts +92 -0
- package/tests/unit/services/openaiDocumentGen.test.ts +65 -0
- package/prisma/migrations/20250807062924_init/migration.sql +0 -436
- package/prisma/migrations/20250919063704_init2/migration.sql +0 -24
- package/prisma/migrations/20250920143543_add_profile_fields/migration.sql +0 -15
- package/prisma/migrations/20250922165147_add_chat_models/migration.sql +0 -68
- package/prisma/migrations/20250922165314_add_chat_roles/migration.sql +0 -5
- package/prisma/migrations/20250922171242_refactor_notification_system/migration.sql +0 -20
- package/prisma/migrations/20250922172208_add_mentions_system/migration.sql +0 -21
- package/prisma/migrations/20250925072732_add_lab_chat_system/migration.sql +0 -25
- package/prisma/migrations/20251020151505_add_upload_tracking_fields/migration.sql +0 -57
- package/prisma/migrations/20251109122857_annuoncements_comments/migration.sql +0 -30
- package/prisma/migrations/20251109135555_reactions_announcements_comments/migration.sql +0 -35
- package/prisma/migrations/20260410124000_add_submission_recommendation_state/migration.sql +0 -14
- package/prisma/migrations/20260415103500_add_session_type/migration.sql +0 -33
- package/prisma/migrations/20260415133000_add_ai_usage_logs/migration.sql +0 -19
- package/prisma/migrations/20260417083000_add_conversation_member_hidden_at/migration.sql +0 -2
- package/prisma/migrations/20260502230500_assignment_submission_comments/migration.sql +0 -60
- package/prisma/migrations/20260504071500_school_memberships/migration.sql +0 -81
- package/prisma/migrations/20260506162500_consolidate_run_job_and_unify_job_status/migration.sql +0 -166
- package/prisma/migrations/20260509220000_institution_overhaul/migration.sql +0 -184
- package/prisma/migrations/20260510170000_add_folder_permissions/migration.sql +0 -93
- package/prisma/migrations/20260510183000_add_discussions/migration.sql +0 -151
- /package/.github/workflows/{npm.yml → npm-publish.yml} +0 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI modifier "field-update" tools.
|
|
3
|
+
*
|
|
4
|
+
* Unlike the Lab-chat proposal tools (which only *record* a payload for the
|
|
5
|
+
* teacher to accept later), these tools DIRECTLY edit a single key of an
|
|
6
|
+
* existing assignment or worksheet and persist it immediately via the normal
|
|
7
|
+
* service layer. The modifier route locks the resource (Redis flag + Pusher
|
|
8
|
+
* `modifier-started`) while the stream runs, and each successful field write
|
|
9
|
+
* fires a callback so the route can broadcast `modifier-field-updated` to every
|
|
10
|
+
* open editor — they apply the change live and stay read-only until the run
|
|
11
|
+
* completes or fails.
|
|
12
|
+
*
|
|
13
|
+
* NOTE: like `aiTools.ts` / `aiProposalTools.ts`, these intentionally use
|
|
14
|
+
* `jsonSchema()` rather than the zod `tool()` helper to avoid the TS2589
|
|
15
|
+
* "excessively deep" compiler blow-up on nested schemas.
|
|
16
|
+
*/
|
|
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]="ed55e709-4194-573d-b522-7077f5d6d6bf")}catch(e){}}();
|
|
19
|
+
import { randomUUID } from 'node:crypto';
|
|
20
|
+
import { jsonSchema } from 'ai';
|
|
21
|
+
import { updateAssignmentRecord } from './assignment.js';
|
|
22
|
+
import { addQuestionToWorksheet, deleteWorksheetQuestionRecord, updateWorksheetQuestionRecord, updateWorksheetRecord, } from './worksheet.js';
|
|
23
|
+
const ASSIGNMENT_TYPES = [
|
|
24
|
+
'HOMEWORK', 'QUIZ', 'TEST', 'PROJECT', 'ESSAY', 'DISCUSSION', 'PRESENTATION', 'LAB', 'OTHER',
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Editable scalar keys of an assignment, with the coercion + human label used
|
|
28
|
+
* when the model passes a (string) value. Keys map 1:1 to
|
|
29
|
+
* `updateAssignmentRecord` input fields.
|
|
30
|
+
*/
|
|
31
|
+
const ASSIGNMENT_FIELDS = {
|
|
32
|
+
title: { label: 'title', type: 'string' },
|
|
33
|
+
instructions: { label: 'instructions', type: 'string' },
|
|
34
|
+
dueDate: { label: 'due date', type: 'date' },
|
|
35
|
+
type: { label: 'type', type: 'enum', enumValues: ASSIGNMENT_TYPES },
|
|
36
|
+
maxGrade: { label: 'max grade', type: 'number' },
|
|
37
|
+
graded: { label: 'graded', type: 'boolean' },
|
|
38
|
+
weight: { label: 'weight', type: 'number' },
|
|
39
|
+
acceptFiles: { label: 'file submissions', type: 'boolean' },
|
|
40
|
+
acceptExtendedResponse: { label: 'extended response', type: 'boolean' },
|
|
41
|
+
acceptWorksheet: { label: 'worksheet submissions', type: 'boolean' },
|
|
42
|
+
aiPolicyLevel: { label: 'AI policy level', type: 'number' },
|
|
43
|
+
};
|
|
44
|
+
const WORKSHEET_FIELDS = {
|
|
45
|
+
name: { label: 'name', type: 'string' },
|
|
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
|
+
};
|
|
85
|
+
/** Coerce a model-supplied string value into the type a field expects. */
|
|
86
|
+
function coerceValue(raw, spec) {
|
|
87
|
+
switch (spec.type) {
|
|
88
|
+
case 'number': {
|
|
89
|
+
const n = Number(raw);
|
|
90
|
+
if (Number.isNaN(n))
|
|
91
|
+
throw new Error(`Expected a number but got "${raw}"`);
|
|
92
|
+
return n;
|
|
93
|
+
}
|
|
94
|
+
case 'boolean': {
|
|
95
|
+
const v = raw.trim().toLowerCase();
|
|
96
|
+
if (['true', 'yes', '1'].includes(v))
|
|
97
|
+
return true;
|
|
98
|
+
if (['false', 'no', '0'].includes(v))
|
|
99
|
+
return false;
|
|
100
|
+
throw new Error(`Expected a boolean but got "${raw}"`);
|
|
101
|
+
}
|
|
102
|
+
case 'date': {
|
|
103
|
+
const d = new Date(raw);
|
|
104
|
+
if (Number.isNaN(d.getTime()))
|
|
105
|
+
throw new Error(`Expected an ISO date but got "${raw}"`);
|
|
106
|
+
return d.toISOString();
|
|
107
|
+
}
|
|
108
|
+
case 'enum': {
|
|
109
|
+
const v = raw.trim().toUpperCase();
|
|
110
|
+
if (spec.enumValues && !spec.enumValues.includes(v)) {
|
|
111
|
+
throw new Error(`Expected one of ${spec.enumValues.join(', ')} but got "${raw}"`);
|
|
112
|
+
}
|
|
113
|
+
return v;
|
|
114
|
+
}
|
|
115
|
+
default:
|
|
116
|
+
return raw;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Build the field-update tool for an assignment. The `onFieldUpdate` callback
|
|
121
|
+
* runs after a successful persist so the route can broadcast the change.
|
|
122
|
+
*/
|
|
123
|
+
export function assignmentModifierTools(userId, assignmentId, classId, onFieldUpdate) {
|
|
124
|
+
const fieldNames = Object.keys(ASSIGNMENT_FIELDS);
|
|
125
|
+
return {
|
|
126
|
+
update_assignment_field: {
|
|
127
|
+
description: 'Directly update a single field of the assignment and save it immediately. ' +
|
|
128
|
+
'Call this once per field the teacher wants changed. The assignment is locked ' +
|
|
129
|
+
'for editing until you finish.',
|
|
130
|
+
inputSchema: jsonSchema({
|
|
131
|
+
type: 'object',
|
|
132
|
+
properties: {
|
|
133
|
+
field: {
|
|
134
|
+
type: 'string',
|
|
135
|
+
enum: fieldNames,
|
|
136
|
+
description: 'The assignment field to update.',
|
|
137
|
+
},
|
|
138
|
+
value: {
|
|
139
|
+
type: 'string',
|
|
140
|
+
description: 'The new value as a string. Booleans use "true"/"false", numbers as digits, ' +
|
|
141
|
+
'dates as ISO 8601, type as one of the allowed enum values.',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
required: ['field', 'value'],
|
|
145
|
+
}),
|
|
146
|
+
execute: async ({ field, value }) => {
|
|
147
|
+
const spec = ASSIGNMENT_FIELDS[field];
|
|
148
|
+
if (!spec) {
|
|
149
|
+
return `Unknown field "${field}". Allowed: ${fieldNames.join(', ')}.`;
|
|
150
|
+
}
|
|
151
|
+
let coerced;
|
|
152
|
+
try {
|
|
153
|
+
coerced = coerceValue(value, spec);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
return `Could not update ${spec.label}: ${err.message}`;
|
|
157
|
+
}
|
|
158
|
+
const updateInput = {
|
|
159
|
+
id: assignmentId,
|
|
160
|
+
classId,
|
|
161
|
+
};
|
|
162
|
+
updateInput[field] = coerced;
|
|
163
|
+
await updateAssignmentRecord(userId, updateInput);
|
|
164
|
+
await onFieldUpdate({ field, value: coerced, label: spec.label });
|
|
165
|
+
return `Updated ${spec.label}.`;
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/** Build the field-update tool for a worksheet. */
|
|
171
|
+
export function worksheetModifierTools(worksheetId, userId, onFieldUpdate) {
|
|
172
|
+
const fieldNames = Object.keys(WORKSHEET_FIELDS);
|
|
173
|
+
return {
|
|
174
|
+
update_worksheet_field: {
|
|
175
|
+
description: 'Directly update a single field of the worksheet and save it immediately. ' +
|
|
176
|
+
'The worksheet is locked for editing until you finish.',
|
|
177
|
+
inputSchema: jsonSchema({
|
|
178
|
+
type: 'object',
|
|
179
|
+
properties: {
|
|
180
|
+
field: {
|
|
181
|
+
type: 'string',
|
|
182
|
+
enum: fieldNames,
|
|
183
|
+
description: 'The worksheet field to update.',
|
|
184
|
+
},
|
|
185
|
+
value: { type: 'string', description: 'The new value as a string.' },
|
|
186
|
+
},
|
|
187
|
+
required: ['field', 'value'],
|
|
188
|
+
}),
|
|
189
|
+
execute: async ({ field, value }) => {
|
|
190
|
+
const spec = WORKSHEET_FIELDS[field];
|
|
191
|
+
if (!spec) {
|
|
192
|
+
return `Unknown field "${field}". Allowed: ${fieldNames.join(', ')}.`;
|
|
193
|
+
}
|
|
194
|
+
const updateInput = {};
|
|
195
|
+
updateInput[field] = value;
|
|
196
|
+
await updateWorksheetRecord(worksheetId, userId, updateInput);
|
|
197
|
+
await onFieldUpdate({ field, value, label: spec.label });
|
|
198
|
+
return `Updated ${spec.label}.`;
|
|
199
|
+
},
|
|
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
|
+
},
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=aiModifierTools.js.map
|
|
274
|
+
//# debugId=ed55e709-4194-573d-b522-7077f5d6d6bf
|
|
@@ -0,0 +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 { 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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lab-chat "proposal" tools.
|
|
3
|
+
*
|
|
4
|
+
* In the agentic Lab pipeline the model produces create-actions by *calling
|
|
5
|
+
* tools* (e.g. `propose_assignment`) instead of returning a JSON blob. Each
|
|
6
|
+
* tool records a structured payload into a shared accumulator and returns a
|
|
7
|
+
* short confirmation so the model can keep narrating. After the stream ends
|
|
8
|
+
* the pipeline turns the accumulator into the `message.meta.*ToCreate` shape
|
|
9
|
+
* the frontend accept-cards already consume — so the data contract is
|
|
10
|
+
* preserved while the generation becomes genuine inline tool calls.
|
|
11
|
+
*
|
|
12
|
+
* NOTE: these tools intentionally use `jsonSchema()` rather than the zod
|
|
13
|
+
* `tool()` helper. Zod-typed `tool()` definitions with deeply nested schemas
|
|
14
|
+
* make the TS compiler instantiate excessively deep types (TS2589) and OOM,
|
|
15
|
+
* so we mirror the existing `aiTools.ts` pattern (plain JSON Schema + manually
|
|
16
|
+
* typed execute args).
|
|
17
|
+
*/
|
|
18
|
+
import { type ToolSet } from 'ai';
|
|
19
|
+
import type { AssignmentToCreate, WorksheetToCreate, SectionToCreate, DocToCreate } from '../pipelines/aiLabChatContract.js';
|
|
20
|
+
export interface LabProposals {
|
|
21
|
+
assignments: AssignmentToCreate[];
|
|
22
|
+
worksheets: WorksheetToCreate[];
|
|
23
|
+
sections: SectionToCreate[];
|
|
24
|
+
docs: DocToCreate[];
|
|
25
|
+
}
|
|
26
|
+
export declare function createLabProposals(): LabProposals;
|
|
27
|
+
/**
|
|
28
|
+
* Build the set of proposal tools backed by the given accumulator.
|
|
29
|
+
* Merge these with the read-only RAG tools from `aiTools(classId)`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function labProposalTools(proposals: LabProposals): ToolSet;
|
|
32
|
+
//# sourceMappingURL=aiProposalTools.d.ts.map
|
|
@@ -0,0 +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;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"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lab-chat "proposal" tools.
|
|
3
|
+
*
|
|
4
|
+
* In the agentic Lab pipeline the model produces create-actions by *calling
|
|
5
|
+
* tools* (e.g. `propose_assignment`) instead of returning a JSON blob. Each
|
|
6
|
+
* tool records a structured payload into a shared accumulator and returns a
|
|
7
|
+
* short confirmation so the model can keep narrating. After the stream ends
|
|
8
|
+
* the pipeline turns the accumulator into the `message.meta.*ToCreate` shape
|
|
9
|
+
* the frontend accept-cards already consume — so the data contract is
|
|
10
|
+
* preserved while the generation becomes genuine inline tool calls.
|
|
11
|
+
*
|
|
12
|
+
* NOTE: these tools intentionally use `jsonSchema()` rather than the zod
|
|
13
|
+
* `tool()` helper. Zod-typed `tool()` definitions with deeply nested schemas
|
|
14
|
+
* make the TS compiler instantiate excessively deep types (TS2589) and OOM,
|
|
15
|
+
* so we mirror the existing `aiTools.ts` pattern (plain JSON Schema + manually
|
|
16
|
+
* typed execute args).
|
|
17
|
+
*/
|
|
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]="0c9ff67f-a8a4-5232-b858-905d3275b385")}catch(e){}}();
|
|
20
|
+
import { jsonSchema } from 'ai';
|
|
21
|
+
import { v4 } from 'uuid';
|
|
22
|
+
export function createLabProposals() {
|
|
23
|
+
return { assignments: [], worksheets: [], sections: [], docs: [] };
|
|
24
|
+
}
|
|
25
|
+
function normalizeDueDate(input) {
|
|
26
|
+
if (input) {
|
|
27
|
+
const parsed = new Date(input);
|
|
28
|
+
if (!Number.isNaN(parsed.getTime()))
|
|
29
|
+
return parsed.toISOString();
|
|
30
|
+
}
|
|
31
|
+
// Default: one week out.
|
|
32
|
+
return new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString();
|
|
33
|
+
}
|
|
34
|
+
const ASSIGNMENT_TYPES = [
|
|
35
|
+
'HOMEWORK', 'QUIZ', 'TEST', 'PROJECT', 'ESSAY', 'DISCUSSION', 'PRESENTATION', 'LAB', 'OTHER',
|
|
36
|
+
];
|
|
37
|
+
const QUESTION_TYPES = [
|
|
38
|
+
'MULTIPLE_CHOICE', 'TRUE_FALSE', 'SHORT_ANSWER', 'LONG_ANSWER', 'MATH_EXPRESSION', 'ESSAY',
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* Build the set of proposal tools backed by the given accumulator.
|
|
42
|
+
* Merge these with the read-only RAG tools from `aiTools(classId)`.
|
|
43
|
+
*/
|
|
44
|
+
export function labProposalTools(proposals) {
|
|
45
|
+
return {
|
|
46
|
+
propose_section: {
|
|
47
|
+
description: 'Propose a new section (folder) to organise class content. Call once per section you want to create.',
|
|
48
|
+
inputSchema: jsonSchema({
|
|
49
|
+
type: 'object',
|
|
50
|
+
properties: {
|
|
51
|
+
name: { type: 'string', description: 'Section name' },
|
|
52
|
+
color: { type: 'string', description: 'Optional hex color like #3b82f6' },
|
|
53
|
+
},
|
|
54
|
+
required: ['name'],
|
|
55
|
+
}),
|
|
56
|
+
execute: async ({ name, color }) => {
|
|
57
|
+
proposals.sections.push({ name, color: color ?? null });
|
|
58
|
+
return `Section "${name}" proposed.`;
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
propose_worksheet: {
|
|
62
|
+
description: 'Propose a worksheet of questions for the teacher to review and create. Include all questions in a single call.',
|
|
63
|
+
inputSchema: jsonSchema({
|
|
64
|
+
type: 'object',
|
|
65
|
+
properties: {
|
|
66
|
+
title: { type: 'string', description: 'Worksheet title' },
|
|
67
|
+
questions: {
|
|
68
|
+
type: 'array',
|
|
69
|
+
description: 'The list of questions',
|
|
70
|
+
items: {
|
|
71
|
+
type: 'object',
|
|
72
|
+
properties: {
|
|
73
|
+
type: { type: 'string', enum: QUESTION_TYPES },
|
|
74
|
+
question: { type: 'string' },
|
|
75
|
+
answer: { type: 'string' },
|
|
76
|
+
options: {
|
|
77
|
+
type: 'array',
|
|
78
|
+
description: 'For MULTIPLE_CHOICE/TRUE_FALSE questions',
|
|
79
|
+
items: {
|
|
80
|
+
type: 'object',
|
|
81
|
+
properties: {
|
|
82
|
+
text: { type: 'string' },
|
|
83
|
+
isCorrect: { type: 'boolean' },
|
|
84
|
+
},
|
|
85
|
+
required: ['text', 'isCorrect'],
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
markScheme: {
|
|
89
|
+
type: 'array',
|
|
90
|
+
items: {
|
|
91
|
+
type: 'object',
|
|
92
|
+
properties: {
|
|
93
|
+
points: { type: 'number' },
|
|
94
|
+
description: { type: 'string' },
|
|
95
|
+
},
|
|
96
|
+
required: ['points', 'description'],
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
points: { type: 'number' },
|
|
100
|
+
},
|
|
101
|
+
required: ['type', 'question'],
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
required: ['title', 'questions'],
|
|
106
|
+
}),
|
|
107
|
+
execute: async ({ title, questions }) => {
|
|
108
|
+
const worksheet = {
|
|
109
|
+
title,
|
|
110
|
+
questions: (questions ?? []).map((q, index) => ({
|
|
111
|
+
type: q.type,
|
|
112
|
+
question: q.question,
|
|
113
|
+
answer: q.answer ?? '',
|
|
114
|
+
options: (q.options ?? []).map((o) => ({
|
|
115
|
+
id: v4(),
|
|
116
|
+
text: o.text,
|
|
117
|
+
isCorrect: o.isCorrect,
|
|
118
|
+
})),
|
|
119
|
+
markScheme: (q.markScheme ?? []).map((m) => ({
|
|
120
|
+
id: v4(),
|
|
121
|
+
points: m.points,
|
|
122
|
+
description: m.description,
|
|
123
|
+
})),
|
|
124
|
+
points: q.points ?? 0,
|
|
125
|
+
order: index,
|
|
126
|
+
})),
|
|
127
|
+
};
|
|
128
|
+
proposals.worksheets.push(worksheet);
|
|
129
|
+
return `Worksheet "${title}" with ${worksheet.questions.length} question(s) proposed.`;
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
propose_assignment: {
|
|
133
|
+
description: 'Propose an assignment for the teacher to review and create. Call once per assignment.',
|
|
134
|
+
inputSchema: jsonSchema({
|
|
135
|
+
type: 'object',
|
|
136
|
+
properties: {
|
|
137
|
+
title: { type: 'string' },
|
|
138
|
+
instructions: { type: 'string' },
|
|
139
|
+
dueDate: {
|
|
140
|
+
type: 'string',
|
|
141
|
+
description: 'ISO 8601 datetime. Defaults to one week from now if omitted.',
|
|
142
|
+
},
|
|
143
|
+
type: { type: 'string', enum: ASSIGNMENT_TYPES },
|
|
144
|
+
maxGrade: { type: 'number' },
|
|
145
|
+
acceptFiles: { type: 'boolean' },
|
|
146
|
+
acceptExtendedResponse: { type: 'boolean' },
|
|
147
|
+
acceptWorksheet: { type: 'boolean' },
|
|
148
|
+
},
|
|
149
|
+
required: ['title', 'instructions'],
|
|
150
|
+
}),
|
|
151
|
+
execute: async ({ title, instructions, dueDate, type, maxGrade, acceptFiles, acceptExtendedResponse, acceptWorksheet, }) => {
|
|
152
|
+
const assignment = {
|
|
153
|
+
title,
|
|
154
|
+
instructions,
|
|
155
|
+
dueDate: normalizeDueDate(dueDate),
|
|
156
|
+
type: type ?? 'HOMEWORK',
|
|
157
|
+
maxGrade: maxGrade ?? 100,
|
|
158
|
+
acceptFiles: acceptFiles ?? true,
|
|
159
|
+
acceptExtendedResponse: acceptExtendedResponse ?? false,
|
|
160
|
+
acceptWorksheet: acceptWorksheet ?? false,
|
|
161
|
+
gradingBoundaryId: null,
|
|
162
|
+
markSchemeId: null,
|
|
163
|
+
worksheetIds: [],
|
|
164
|
+
studentIds: [],
|
|
165
|
+
sectionId: null,
|
|
166
|
+
attachments: [],
|
|
167
|
+
};
|
|
168
|
+
proposals.assignments.push(assignment);
|
|
169
|
+
return `Assignment "${title}" proposed.`;
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
generate_document: {
|
|
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
|
+
inputSchema: jsonSchema({
|
|
175
|
+
type: 'object',
|
|
176
|
+
properties: {
|
|
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
|
+
],
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
required: ['title', 'content', 'format'],
|
|
193
|
+
}),
|
|
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
|
+
},
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=aiProposalTools.js.map
|
|
207
|
+
//# debugId=0c9ff67f-a8a4-5232-b858-905d3275b385
|
|
@@ -0,0 +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. 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":"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,+RAA+R;YACjS,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,oFAAoF;qBACvF;oBACD,MAAM,EAAE;wBACN,IAAI,EAAE,QAAQ;wBACd,WAAW,EACT,6KAA6K;wBAC/K,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":"0c9ff67f-a8a4-5232-b858-905d3275b385"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Streaming service – handles streamed AI responses with tool calls.
|
|
3
|
+
* Uses Vercel AI SDK for streaming and Redis for temporary chunk caching.
|
|
4
|
+
*/
|
|
5
|
+
import { type ModelMessage } from 'ai';
|
|
6
|
+
export interface StreamOptions {
|
|
7
|
+
conversationId: string;
|
|
8
|
+
aiMessageId: string;
|
|
9
|
+
messages: ModelMessage[];
|
|
10
|
+
systemPrompt: string;
|
|
11
|
+
classId?: string;
|
|
12
|
+
enableTools?: boolean;
|
|
13
|
+
model?: string;
|
|
14
|
+
temperature?: number;
|
|
15
|
+
maxOutputTokens?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Stream an AI response, broadcasting chunks via Pusher and caching in Redis.
|
|
19
|
+
* On completion, persists the full response to the database.
|
|
20
|
+
*/
|
|
21
|
+
export declare function streamAIResponse(options: StreamOptions): Promise<void>;
|
|
22
|
+
//# sourceMappingURL=aiStream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiStream.d.ts","sourceRoot":"/","sources":["services/aiStream.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAA2B,KAAK,YAAY,EAAE,MAAM,IAAI,CAAC;AAahE,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA6I5E"}
|