@happyvertical/smrt-education 0.57.46 → 0.57.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/AGENTS.md +5 -0
  2. package/README.md +7 -1
  3. package/agents/learner-service.md +31 -2
  4. package/agents/question-extraction.md +108 -0
  5. package/agents/submission-service.md +15 -0
  6. package/dist/chunks/{workbook-photo-service-DKgoUHeb.js → workbook-photo-service-B7Tujv__.js} +6494 -1153
  7. package/dist/chunks/workbook-photo-service-B7Tujv__.js.map +1 -0
  8. package/dist/collections.d.ts +4 -1
  9. package/dist/collections.d.ts.map +1 -1
  10. package/dist/course-authoring-contracts.d.ts +1 -1
  11. package/dist/course-authoring-contracts.d.ts.map +1 -1
  12. package/dist/index.d.ts +11 -5
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1049 -4628
  15. package/dist/index.js.map +1 -1
  16. package/dist/ingestion.d.ts +2 -0
  17. package/dist/ingestion.d.ts.map +1 -1
  18. package/dist/ingestion.js +197 -2
  19. package/dist/ingestion.js.map +1 -1
  20. package/dist/learner-history.d.ts +50 -0
  21. package/dist/learner-history.d.ts.map +1 -0
  22. package/dist/learner-service.d.ts +78 -2
  23. package/dist/learner-service.d.ts.map +1 -1
  24. package/dist/manifest.json +4255 -1444
  25. package/dist/question-extraction-contracts.d.ts +231 -0
  26. package/dist/question-extraction-contracts.d.ts.map +1 -0
  27. package/dist/question-extraction-ingestion.d.ts +44 -0
  28. package/dist/question-extraction-ingestion.d.ts.map +1 -0
  29. package/dist/question-extraction-models.d.ts +56 -0
  30. package/dist/question-extraction-models.d.ts.map +1 -0
  31. package/dist/question-extraction-service.d.ts +71 -0
  32. package/dist/question-extraction-service.d.ts.map +1 -0
  33. package/dist/question-extraction.d.ts +317 -0
  34. package/dist/question-extraction.d.ts.map +1 -0
  35. package/dist/smrt-knowledge.json +961 -143
  36. package/dist/submission-service.d.ts +34 -1
  37. package/dist/submission-service.d.ts.map +1 -1
  38. package/dist/submissions.d.ts +25 -1
  39. package/dist/submissions.d.ts.map +1 -1
  40. package/package.json +10 -10
  41. package/dist/chunks/workbook-photo-service-DKgoUHeb.js.map +0 -1
@@ -73,6 +73,7 @@ export declare function captureEducationIntake(input: {
73
73
  }>;
74
74
  awaitingParentRelease?: boolean;
75
75
  sourceRequiresParentRelease?: boolean;
76
+ selfReported?: boolean;
76
77
  grade: null | {
77
78
  id: string;
78
79
  graderKind: import("./submissions.js").Grade["graderKind"];
@@ -138,5 +139,6 @@ export declare function preserveWorkbookIntakeAnalysis(input: {
138
139
  }): Promise<WorkbookPreservationResult>;
139
140
  export { receiveFamilyIntake, retainFamilyIntakeReceipt, } from './family-intake-ingestion.js';
140
141
  export { FamilyIntakeService } from './family-intake-service.js';
142
+ export { educationQuestionExtractionHandler, preserveQuestionExtractionAnalysis, QUESTION_EXTRACTION_HANDLER_ID, questionExtractionGrounding, } from './question-extraction-ingestion.js';
141
143
  export { preserveWorkbookPhotoIdentification, processWorkbookPhotoAnalysis, receiveWorkbookPhotoIntake, retainWorkbookPhotoReceipt, WORKBOOK_PHOTO_HANDLER, workbookPhotoIntakeHandlers, workbookPhotoIntakeTargetResolver, } from './workbook-photo-ingestion.js';
142
144
  //# sourceMappingURL=ingestion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ingestion.d.ts","sourceRoot":"","sources":["../src/ingestion.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ingestion.d.ts","sourceRoot":"","sources":["../src/ingestion.ts"],"names":[],"mappings":"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"}
package/dist/ingestion.js CHANGED
@@ -1,4 +1,4 @@
1
- import { B as validateWorkbookAssessment, I as WORKBOOK_MATH_VOCABULARY, L as WorkbookAssessmentValidationError, Q as FamilyIntakeCollection, V as workbookAggregateFeedback, Z as FamilyIntakeAssetCollection, d as WorkbookPhotoIntakeCollection, et as FamilyIntakeDecisionCollection, f as validateWorkbookPhotoIdentification, m as normalizeWorkbookAnswerRegions, n as preservePhotoProposal, p as normalizeWorkbookObservedLayout, r as WorkbookService, s as WorkbookPhotoAssetCollection, t as WorkbookPhotoService, tt as familyIntakeScopeId, v as LearnerAuthorizationError, z as aggregateWorkbookQuestions } from "./chunks/workbook-photo-service-DKgoUHeb.js";
1
+ import { $ as LearnerAuthorizationError, At as workbookAggregateFeedback, Bt as FamilyIntakeAssetCollection, D as QUESTION_EXTRACTION_ARGS_SCHEMA, Et as WorkbookAssessmentValidationError, Ot as aggregateWorkbookQuestions, S as questionExtractionProposalDigest, Tt as WORKBOOK_MATH_VOCABULARY, Ut as FamilyIntakeDecisionCollection, Vt as FamilyIntakeCollection, Wt as familyIntakeScopeId, X as QuestionExtractionValidationError, Y as QuestionExtractionPendingError, d as WorkbookPhotoIntakeCollection, f as validateWorkbookPhotoIdentification, kt as validateWorkbookAssessment, m as normalizeWorkbookAnswerRegions, n as preservePhotoProposal, p as normalizeWorkbookObservedLayout, r as WorkbookService, s as WorkbookPhotoAssetCollection, t as WorkbookPhotoService } from "./chunks/workbook-photo-service-B7Tujv__.js";
2
2
  import { getCurrentTenant, withTenant } from "@happyvertical/smrt-tenancy";
3
3
  import { withPrivateAssetAccess } from "@happyvertical/smrt-assets";
4
4
  import { registerPermissionDefinitions } from "@happyvertical/smrt-users";
@@ -438,6 +438,201 @@ var FamilyIntakeService = class FamilyIntakeService extends WorkbookPhotoService
438
438
  }
439
439
  };
440
440
  //#endregion
441
+ //#region src/question-extraction-ingestion.ts
442
+ var QUESTION_EXTRACTION_HANDLER_ID = "@happyvertical/smrt-education:extract-questions";
443
+ var QUESTION = "@happyvertical/smrt-education:Question";
444
+ var MEDIA_TYPES = [
445
+ "image/jpeg",
446
+ "image/png",
447
+ "image/webp",
448
+ "application/pdf"
449
+ ];
450
+ registerPermissionDefinitions([{
451
+ slug: "questions.create",
452
+ collection: "questions",
453
+ qualifiedName: QUESTION,
454
+ name: "Apply reviewed question extractions"
455
+ }]);
456
+ var DESCRIPTION = "Extract the printed questions of a scanned worksheet or imported course file as structured data for extraction review. Report every source page in pages with its role (exercise, example, instructions, cover, answer_key, mixed, unknown) and readability; never drop a page. questions holds printed task text only: prompt, numbering exactly as printed, subparts, choices, section, diagram/table/image references and any answer key or rubric printed in the source (origin source). Mark anything you supply yourself origin inferred; never present an inferred key, type or points as printed. Unreadable or unsupported tasks keep their key and numbering with status unreadable/unsupported and prompt null; content you cannot extract goes in omissions. Worked examples use role example. Learner handwriting goes only in studentWork (observed text, or null when illegible), never in prompts or keys; never solve a task and report it as observed work. Keys: printed numbering path (for example 3, 3b), else u:<short printed-task slug>:<occurrence>. worksheetVersionId only when a wsv1- id is printed on the page. Anchors cite original evidenceId, the physical source page (1-based, or null when unknown; printed page numbers are not pages) and regionId only from that evidence observedRegions catalog, else null; never coordinates. Applying needs a human extraction decision; it creates or links question records and never grades or attaches learner work.";
457
+ function bound(request, context, work) {
458
+ if (context.scope.tenantId !== request.tenantId || context.scope.actorId !== request.actorUserId || !context.policy.requireReview) throw new Error("Question extraction scope mismatch");
459
+ if (!context.principal) return work();
460
+ const tenant = getCurrentTenant();
461
+ if (!tenant || tenant.tenantId !== request.tenantId || tenant.userId !== context.principal.context.userId || context.principal.context.tenantId !== request.tenantId) throw new Error("Question extraction principal tenant mismatch");
462
+ return withTenant({
463
+ ...tenant,
464
+ tenantId: request.tenantId,
465
+ userId: request.actorUserId,
466
+ superAdminBypass: false
467
+ }, work);
468
+ }
469
+ function summary(view) {
470
+ const count = (outcome) => view.match.questions.filter((m) => m.outcome === outcome).length;
471
+ return {
472
+ extractionId: view.extractionId,
473
+ sourceKind: view.extraction.sourceKind,
474
+ worksheetVersionId: view.match.worksheetVersionId,
475
+ worksheetKnown: view.match.worksheetKnown,
476
+ questions: view.extraction.questions.length,
477
+ matched: count("matched"),
478
+ ambiguous: count("ambiguous"),
479
+ unmatched: count("unmatched"),
480
+ unreadable: view.extraction.questions.filter((q) => q.status === "unreadable" || q.status === "unsupported").length,
481
+ studentWork: view.studentWork.length,
482
+ omissions: view.extraction.omissions.length,
483
+ sourceWarnings: view.extraction.sourceWarnings,
484
+ extractionReviewRequired: true
485
+ };
486
+ }
487
+ function educationQuestionExtractionHandler(input) {
488
+ const { extractions, request } = input;
489
+ const preserved = async (args, context) => {
490
+ const view = await bound(request, context, () => extractions.withExecutor(context.db).findExtraction({
491
+ ...request,
492
+ intakeItemId: context.itemId,
493
+ proposalDigest: questionExtractionProposalDigest(args)
494
+ }));
495
+ if (!view) throw new Error("Question extraction must be preserved before review");
496
+ return view;
497
+ };
498
+ return {
499
+ id: QUESTION_EXTRACTION_HANDLER_ID,
500
+ version: "1",
501
+ label: "Extract questions",
502
+ description: DESCRIPTION,
503
+ operation: {
504
+ model: QUESTION,
505
+ action: "create",
506
+ version: "1"
507
+ },
508
+ capability: {
509
+ effect: "write",
510
+ idempotent: true,
511
+ openWorld: false
512
+ },
513
+ argsSchema: QUESTION_EXTRACTION_ARGS_SCHEMA,
514
+ resultSchema: {
515
+ type: "object",
516
+ additionalProperties: false,
517
+ required: ["extractionId"],
518
+ properties: { extractionId: {
519
+ type: "string",
520
+ minLength: 1,
521
+ maxLength: 64
522
+ } }
523
+ },
524
+ resultModels: {},
525
+ discovery: {
526
+ mediaTypes: MEDIA_TYPES,
527
+ references: {}
528
+ },
529
+ validate: async (args, context) => {
530
+ await preserved(args, context);
531
+ return { ok: true };
532
+ },
533
+ preview: async (args, context) => ({
534
+ display: summary(await preserved(args, context)),
535
+ normalizedArgs: args,
536
+ targetPreconditions: []
537
+ }),
538
+ execution: {
539
+ kind: "database",
540
+ apply: async (args, context) => {
541
+ const view = await preserved(args, context);
542
+ await bound(request, context, () => extractions.withExecutor(context.db).applyExtraction({
543
+ ...request,
544
+ extractionId: view.extractionId
545
+ }));
546
+ return { extractionId: view.extractionId };
547
+ }
548
+ }
549
+ };
550
+ }
551
+ function questionExtractionGrounding(snapshot, warnings = []) {
552
+ const results = Array.isArray(snapshot.result.output?.results) ? snapshot.result.output.results : [];
553
+ const originals = intakeOriginalEvidence(snapshot.evidence ?? []).filter((e) => e.mediaType !== "application/json");
554
+ const pagesOf = (location) => {
555
+ const valid = (n) => Number.isSafeInteger(n) && n > 0;
556
+ if (location?.kind === "page" && valid(location.page)) return [location.page];
557
+ if (location?.kind === "pages" && valid(location.startPage) && valid(location.endPage) && location.endPage >= location.startPage) {
558
+ if (location.endPage - location.startPage >= 1e3) throw new QuestionExtractionValidationError("Too many source pages");
559
+ return Array.from({ length: location.endPage - location.startPage + 1 }, (_, i) => location.startPage + i);
560
+ }
561
+ return [];
562
+ };
563
+ const sources = originals.map((evidence) => {
564
+ const base = {
565
+ evidenceId: evidence.id,
566
+ sha256: evidence.contentHash,
567
+ mediaType: evidence.mediaType
568
+ };
569
+ const result = results.find((value) => !!value && typeof value === "object" && value.evidence?.id === evidence.id && value.evidence?.contentHash === evidence.contentHash);
570
+ if (!result) return {
571
+ ...base,
572
+ pages: [],
573
+ extracted: false
574
+ };
575
+ const segments = Array.isArray(result.segments) ? result.segments : [];
576
+ const failed = [...Array.isArray(result.omitted) ? result.omitted : [], ...Array.isArray(result.errors) ? result.errors.map((e) => e?.location) : []];
577
+ const extractedPages = segments.flatMap((s) => pagesOf(s.location));
578
+ const omittedPages = [...new Set(failed.flatMap((l) => pagesOf(l)))].filter((p) => !extractedPages.includes(p)).sort((a, b) => a - b);
579
+ const pages = [.../* @__PURE__ */ new Set([...extractedPages, ...omittedPages])].sort((a, b) => a - b);
580
+ if (pages.length > 1e3) throw new QuestionExtractionValidationError("Too many source pages");
581
+ const catalogs = evidence.mediaType.startsWith("image/") ? segments.filter((s) => s.location?.kind === "source").map((s) => normalizeObservedImageRegions(s.observedRegions)).filter((c) => c !== void 0) : [];
582
+ const incomplete = result.truncated === true || failed.length > 0;
583
+ return {
584
+ ...base,
585
+ pages,
586
+ ...omittedPages.length ? { omittedPages } : {},
587
+ ...incomplete ? { incomplete: true } : {},
588
+ ...catalogs.length === 1 ? { observedRegions: catalogs[0] } : {}
589
+ };
590
+ });
591
+ const codes = [.../* @__PURE__ */ new Set([...warnings.filter((w) => /^[a-z][a-z0-9_.-]{0,47}$/.test(w)), ...snapshot.result.output?.truncated === true ? ["source_incomplete"] : []])].sort().slice(0, 16);
592
+ return {
593
+ version: 1,
594
+ extractionAttemptId: snapshot.attemptId,
595
+ ...codes.length ? { warnings: codes } : {},
596
+ sources
597
+ };
598
+ }
599
+ async function preserveQuestionExtractionAnalysis(input) {
600
+ let snapshot;
601
+ try {
602
+ snapshot = await input.ingestion.getCompletedAnalysis(input.itemId);
603
+ } catch (error) {
604
+ if (error instanceof Error && error.message === "Analysis unavailable") throw new QuestionExtractionPendingError("pending");
605
+ throw error;
606
+ }
607
+ if (snapshot.configuration.stage !== "interpret" || !["completed", "partial"].includes(snapshot.result.status)) throw new QuestionExtractionPendingError("pending");
608
+ const generation = snapshot.result.output.proposals;
609
+ if (generation?.version !== 1 || !Array.isArray(generation.suggestions)) throw new QuestionExtractionValidationError("Malformed generation output");
610
+ if (generation.outcome === "ambiguous") throw new QuestionExtractionPendingError("ambiguous");
611
+ if (!["proposals", "needs_review"].includes(generation.outcome)) throw new QuestionExtractionPendingError("no_proposal");
612
+ const suggestions = generation.suggestions.filter((s) => s.handlerId === QUESTION_EXTRACTION_HANDLER_ID);
613
+ if (!suggestions.length) throw new QuestionExtractionPendingError("no_proposal");
614
+ if (suggestions.length > 1) throw new QuestionExtractionPendingError("ambiguous");
615
+ const suggestion = suggestions[0];
616
+ if (suggestion.missingFields.length) throw new QuestionExtractionValidationError("Incomplete question extraction");
617
+ const generative = generation.provenance.generative;
618
+ return input.extractions.preserveExtraction({
619
+ ...input.request,
620
+ intakeItemId: input.itemId,
621
+ analysisAttemptId: snapshot.attemptId,
622
+ grounding: questionExtractionGrounding(snapshot, generation.warnings ?? []),
623
+ extractor: {
624
+ provider: generative.provider,
625
+ model: generative.model,
626
+ version: generative.version,
627
+ configurationVersion: generation.provenance.configurationVersion,
628
+ promptVersion: generation.provenance.promptVersion
629
+ },
630
+ extraction: suggestion.args,
631
+ ...input.expectedWorksheetVersionId ? { expectedWorksheetVersionId: input.expectedWorksheetVersionId } : {},
632
+ ...input.worksheets ? { worksheets: input.worksheets } : {}
633
+ });
634
+ }
635
+ //#endregion
441
636
  //#region src/workbook-photo-ingestion.ts
442
637
  var MODEL = "@happyvertical/smrt-education:WorkbookPhotoIntake";
443
638
  var WORKBOOK_PHOTO_HANDLER = "@happyvertical/smrt-education:identify-workbook-photo";
@@ -1581,6 +1776,6 @@ async function preserveWorkbookIntakeAnalysis(input) {
1581
1776
  }
1582
1777
  }
1583
1778
  //#endregion
1584
- export { FamilyIntakeService, WORKBOOK_PHOTO_HANDLER, captureEducationIntake, educationIntakeHandlers, educationIntakeTargetResolver, preserveWorkbookIntakeAnalysis, preserveWorkbookPhotoIdentification, processEducationAnalysis, processWorkbookPhotoAnalysis, queueEducationExtraction, receiveFamilyIntake, receiveWorkbookPhotoIntake, requireIngestionMemoryLimit, retainFamilyIntakeReceipt, retainWorkbookPhotoReceipt, workbookPhotoIntakeHandlers, workbookPhotoIntakeTargetResolver };
1779
+ export { FamilyIntakeService, QUESTION_EXTRACTION_HANDLER_ID, WORKBOOK_PHOTO_HANDLER, captureEducationIntake, educationIntakeHandlers, educationIntakeTargetResolver, educationQuestionExtractionHandler, preserveQuestionExtractionAnalysis, preserveWorkbookIntakeAnalysis, preserveWorkbookPhotoIdentification, processEducationAnalysis, processWorkbookPhotoAnalysis, questionExtractionGrounding, queueEducationExtraction, receiveFamilyIntake, receiveWorkbookPhotoIntake, requireIngestionMemoryLimit, retainFamilyIntakeReceipt, retainWorkbookPhotoReceipt, workbookPhotoIntakeHandlers, workbookPhotoIntakeTargetResolver };
1585
1780
 
1586
1781
  //# sourceMappingURL=ingestion.js.map