@intellectif/lk-core 1.3.0 → 1.5.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/CHANGELOG.md +59 -0
- package/README.md +2 -0
- package/dist/{ai-B222dtHH.d.ts → ai-BYryFkF9.d.cts} +462 -5
- package/dist/ai-BYryFkF9.d.cts.map +1 -0
- package/dist/{ai-B222dtHH.d.cts → ai-BYryFkF9.d.ts} +462 -5
- package/dist/ai-BYryFkF9.d.ts.map +1 -0
- package/dist/ai-check.cjs +274 -23
- package/dist/ai-check.cjs.map +1 -1
- package/dist/ai-check.d.cts +13 -5
- package/dist/ai-check.d.cts.map +1 -1
- package/dist/ai-check.d.ts +13 -5
- package/dist/ai-check.d.ts.map +1 -1
- package/dist/ai-check.js +274 -23
- package/dist/ai-check.js.map +1 -1
- package/dist/{ai-writing-DCVkv4Zj.cjs → ai-writing-Cen7-3qs.cjs} +520 -58
- package/dist/ai-writing-Cen7-3qs.cjs.map +1 -0
- package/dist/{ai-writing-CCBjTOM3.js → ai-writing-D8PdhJJz.js} +513 -75
- package/dist/ai-writing-D8PdhJJz.js.map +1 -0
- package/dist/{index-Dyu66R4-.d.cts → index-Bg0aeWtM.d.cts} +327 -3
- package/dist/index-Bg0aeWtM.d.cts.map +1 -0
- package/dist/{index-BWPRPIXL.d.ts → index-CxpiWedW.d.ts} +7 -217
- package/dist/index-CxpiWedW.d.ts.map +1 -0
- package/dist/{index-CXyOV8sm.d.cts → index-D7R3Ll8R.d.cts} +2 -2
- package/dist/{index-CXyOV8sm.d.cts.map → index-D7R3Ll8R.d.cts.map} +1 -1
- package/dist/{index-UGxRSopE.d.ts → index-DUaW1Tj5.d.ts} +327 -3
- package/dist/index-DUaW1Tj5.d.ts.map +1 -0
- package/dist/{index-O4_ExlAD.d.cts → index-qMbxed1B.d.cts} +7 -217
- package/dist/index-qMbxed1B.d.cts.map +1 -0
- package/dist/{index-CegM8o15.d.ts → index-wMc1E_aM.d.ts} +2 -2
- package/dist/{index-CegM8o15.d.ts.map → index-wMc1E_aM.d.ts.map} +1 -1
- package/dist/index.cjs +32 -130
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +115 -97
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +115 -97
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -117
- package/dist/index.js.map +1 -1
- package/dist/{item-group-DroFXgLb.cjs → item-group-DEB7nLID.cjs} +2 -2
- package/dist/{item-group-DroFXgLb.cjs.map → item-group-DEB7nLID.cjs.map} +1 -1
- package/dist/{item-group-DXiR8nOr.js → item-group-DdSUCUjM.js} +2 -2
- package/dist/{item-group-DXiR8nOr.js.map → item-group-DdSUCUjM.js.map} +1 -1
- package/dist/{registry-DVi0LR_i.cjs → registry-Ce00A_OW.cjs} +184 -4
- package/dist/registry-Ce00A_OW.cjs.map +1 -0
- package/dist/{registry-Dsx9mNsS.js → registry-DaZRpqjW.js} +155 -5
- package/dist/registry-DaZRpqjW.js.map +1 -0
- package/dist/{schemas-Bdw0nGPo.js → schemas-BioKFf3F.js} +3 -3
- package/dist/{schemas-Bdw0nGPo.js.map → schemas-BioKFf3F.js.map} +1 -1
- package/dist/{schemas-DVbAOrtd.cjs → schemas-DksueYsu.cjs} +3 -3
- package/dist/{schemas-DVbAOrtd.cjs.map → schemas-DksueYsu.cjs.map} +1 -1
- package/dist/schemas.cjs +2 -2
- package/dist/schemas.d.cts +1 -1
- package/dist/schemas.d.ts +1 -1
- package/dist/schemas.js +2 -2
- package/dist/{scoring-BZqUkuDF.js → scoring-BKNNTz-s.js} +657 -3
- package/dist/scoring-BKNNTz-s.js.map +1 -0
- package/dist/{scoring-B2_HEhMT.cjs → scoring-lKQVYsxy.cjs} +722 -2
- package/dist/scoring-lKQVYsxy.cjs.map +1 -0
- package/dist/scoring.cjs +8 -2
- package/dist/scoring.d.cts +3 -3
- package/dist/scoring.d.ts +3 -3
- package/dist/scoring.js +3 -3
- package/dist/{xapi-DNzkSJ0S.cjs → xapi-NYrTlpID.cjs} +2 -2
- package/dist/{xapi-DNzkSJ0S.cjs.map → xapi-NYrTlpID.cjs.map} +1 -1
- package/dist/{xapi-CMTph7wG.js → xapi-wR6gu4qS.js} +2 -2
- package/dist/{xapi-CMTph7wG.js.map → xapi-wR6gu4qS.js.map} +1 -1
- package/dist/xapi.cjs +1 -1
- package/dist/xapi.d.cts +1 -1
- package/dist/xapi.d.ts +1 -1
- package/dist/xapi.js +1 -2
- package/package.json +2 -2
- package/vectors/README.md +24 -1
- package/vectors/scoring.json +18182 -1
- package/dist/ai-B222dtHH.d.cts.map +0 -1
- package/dist/ai-B222dtHH.d.ts.map +0 -1
- package/dist/ai-writing-CCBjTOM3.js.map +0 -1
- package/dist/ai-writing-DCVkv4Zj.cjs.map +0 -1
- package/dist/index-BWPRPIXL.d.ts.map +0 -1
- package/dist/index-Dyu66R4-.d.cts.map +0 -1
- package/dist/index-O4_ExlAD.d.cts.map +0 -1
- package/dist/index-UGxRSopE.d.ts.map +0 -1
- package/dist/registry-DVi0LR_i.cjs.map +0 -1
- package/dist/registry-Dsx9mNsS.js.map +0 -1
- package/dist/scoring-B2_HEhMT.cjs.map +0 -1
- package/dist/scoring-BZqUkuDF.js.map +0 -1
|
@@ -2732,6 +2732,97 @@ function countWords(text) {
|
|
|
2732
2732
|
if (trimmed === "") return 0;
|
|
2733
2733
|
return trimmed.split(/\s+/).length;
|
|
2734
2734
|
}
|
|
2735
|
+
/** A label as labels are compared: composed, trimmed, its spacing collapsed, lower-cased. */
|
|
2736
|
+
function levelKey(label) {
|
|
2737
|
+
return label.normalize("NFC").trim().replace(/\s+/gu, " ").toLowerCase();
|
|
2738
|
+
}
|
|
2739
|
+
/**
|
|
2740
|
+
* The levels in `value`, or the first reason they cannot be used. `null` or
|
|
2741
|
+
* absent means the criterion has no levels, which is not a problem: it is
|
|
2742
|
+
* judged on a score.
|
|
2743
|
+
*
|
|
2744
|
+
* Each element and each field is read once, so a getter cannot pass the check
|
|
2745
|
+
* with one value and hand the grader another. The levels come back as written.
|
|
2746
|
+
*/
|
|
2747
|
+
function readRubricLevels(value) {
|
|
2748
|
+
if (value === void 0 || value === null) return {
|
|
2749
|
+
ok: true,
|
|
2750
|
+
levels: null
|
|
2751
|
+
};
|
|
2752
|
+
if (!Array.isArray(value)) return {
|
|
2753
|
+
ok: false,
|
|
2754
|
+
problem: "not-a-list"
|
|
2755
|
+
};
|
|
2756
|
+
const count = value.length;
|
|
2757
|
+
if (count < 2) return {
|
|
2758
|
+
ok: false,
|
|
2759
|
+
problem: "too-few"
|
|
2760
|
+
};
|
|
2761
|
+
if (count > 10) return {
|
|
2762
|
+
ok: false,
|
|
2763
|
+
problem: "too-many"
|
|
2764
|
+
};
|
|
2765
|
+
const levels = [];
|
|
2766
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2767
|
+
for (let index = 0; index < count; index += 1) {
|
|
2768
|
+
const entry = value[index];
|
|
2769
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) return {
|
|
2770
|
+
ok: false,
|
|
2771
|
+
problem: "not-a-level",
|
|
2772
|
+
index
|
|
2773
|
+
};
|
|
2774
|
+
const record = entry;
|
|
2775
|
+
const label = record.label;
|
|
2776
|
+
const description = record.description;
|
|
2777
|
+
if (typeof label !== "string" || label.trim() === "") return {
|
|
2778
|
+
ok: false,
|
|
2779
|
+
problem: "no-label",
|
|
2780
|
+
index
|
|
2781
|
+
};
|
|
2782
|
+
if (description !== void 0 && typeof description !== "string") return {
|
|
2783
|
+
ok: false,
|
|
2784
|
+
problem: "bad-description",
|
|
2785
|
+
index
|
|
2786
|
+
};
|
|
2787
|
+
const key = levelKey(label);
|
|
2788
|
+
if (seen.has(key)) return {
|
|
2789
|
+
ok: false,
|
|
2790
|
+
problem: "duplicate-label",
|
|
2791
|
+
index
|
|
2792
|
+
};
|
|
2793
|
+
seen.add(key);
|
|
2794
|
+
levels.push({
|
|
2795
|
+
label,
|
|
2796
|
+
...description !== void 0 ? { description } : {}
|
|
2797
|
+
});
|
|
2798
|
+
}
|
|
2799
|
+
return {
|
|
2800
|
+
ok: true,
|
|
2801
|
+
levels
|
|
2802
|
+
};
|
|
2803
|
+
}
|
|
2804
|
+
/**
|
|
2805
|
+
* How far level probabilities may sum from 1 and still be a distribution:
|
|
2806
|
+
* rounding in a grader's output, not a different judgement.
|
|
2807
|
+
*/
|
|
2808
|
+
const LEVEL_PROBABILITY_TOLERANCE = 1e-6;
|
|
2809
|
+
/**
|
|
2810
|
+
* `values` as a distribution over `count` levels whose likeliest is level
|
|
2811
|
+
* `chosen`, a tie for likeliest included: each a finite number from 0 to 1,
|
|
2812
|
+
* together 1 within {@link LEVEL_PROBABILITY_TOLERANCE}. `null` when they are
|
|
2813
|
+
* not one.
|
|
2814
|
+
*
|
|
2815
|
+
* The AI check refuses a reply whose probabilities are not a distribution, and
|
|
2816
|
+
* calibration and routing read a grade's the same way, so probabilities the
|
|
2817
|
+
* check let through are never ignored downstream. Each element is read once,
|
|
2818
|
+
* a hole as `undefined`, into the copy returned.
|
|
2819
|
+
*/
|
|
2820
|
+
function levelDistribution(values, count, chosen) {
|
|
2821
|
+
const read = Array.from(values);
|
|
2822
|
+
if (read.length !== count || !read.every((p) => typeof p === "number" && p >= 0 && p <= 1)) return null;
|
|
2823
|
+
const sum = read.reduce((total, p) => total + p, 0);
|
|
2824
|
+
return Math.abs(sum - 1) <= 1e-6 && read[chosen] === Math.max(...read) ? read : null;
|
|
2825
|
+
}
|
|
2735
2826
|
//#endregion
|
|
2736
2827
|
//#region src/scoring/strategies/all-or-nothing.ts
|
|
2737
2828
|
/**
|
|
@@ -2948,6 +3039,7 @@ const ITEM_FINDING_SEVERITY = {
|
|
|
2948
3039
|
gs_bank_no_distractor: "warning",
|
|
2949
3040
|
gs_answer_in_passage: "warning",
|
|
2950
3041
|
wr_criterion_name_duplicate: "warning",
|
|
3042
|
+
wr_levels_unreadable: "warning",
|
|
2951
3043
|
ra_text_long_for_time: "warning",
|
|
2952
3044
|
set_key_position_same: "warning"
|
|
2953
3045
|
};
|
|
@@ -3198,14 +3290,38 @@ function critiqueGapSelect(draft) {
|
|
|
3198
3290
|
});
|
|
3199
3291
|
return findings;
|
|
3200
3292
|
}
|
|
3293
|
+
/** Why a criterion's levels cannot be graded on, said to the author. */
|
|
3294
|
+
const LEVELS_PROBLEM = {
|
|
3295
|
+
"not-a-list": (criterion) => `Criterion ${criterion}'s levels are not a list`,
|
|
3296
|
+
"too-few": (criterion) => `Criterion ${criterion} has fewer than 2 levels`,
|
|
3297
|
+
"too-many": (criterion) => `Criterion ${criterion} has more than 10 levels`,
|
|
3298
|
+
"not-a-level": (criterion, level) => `Level ${level} of criterion ${criterion} is not a level`,
|
|
3299
|
+
"no-label": (criterion, level) => `Level ${level} of criterion ${criterion} has no label`,
|
|
3300
|
+
"bad-description": (criterion, level) => `Level ${level} of criterion ${criterion} has a description that is not text`,
|
|
3301
|
+
"duplicate-label": (criterion, level) => `Level ${level} of criterion ${criterion} has the label of an earlier level`
|
|
3302
|
+
};
|
|
3201
3303
|
function critiqueWrittenResponse(draft) {
|
|
3202
3304
|
const rubric = isRecord(draft.rubric) ? draft.rubric : void 0;
|
|
3203
|
-
|
|
3305
|
+
const criteria = rubric === void 0 ? [] : listOf(rubric.criteria);
|
|
3306
|
+
const names = duplicates(criteria, (criterion) => isRecord(criterion) ? written(criterion.name) : void 0).map(({ first, second }) => finding("wr_criterion_name_duplicate", [
|
|
3204
3307
|
"rubric",
|
|
3205
3308
|
"criteria",
|
|
3206
3309
|
second,
|
|
3207
3310
|
"name"
|
|
3208
3311
|
], `Criteria ${ordinal(first)} and ${ordinal(second)} have the same name. Feedback and grades name a criterion, so one of them cannot be told apart.`));
|
|
3312
|
+
const levels = criteria.flatMap((criterion, index) => {
|
|
3313
|
+
if (!isRecord(criterion)) return [];
|
|
3314
|
+
const read = readRubricLevels(criterion.levels);
|
|
3315
|
+
if (read.ok) return [];
|
|
3316
|
+
const level = ordinal(read.index ?? 0);
|
|
3317
|
+
return [finding("wr_levels_unreadable", [
|
|
3318
|
+
"rubric",
|
|
3319
|
+
"criteria",
|
|
3320
|
+
index,
|
|
3321
|
+
"levels"
|
|
3322
|
+
], `${LEVELS_PROBLEM[read.problem](ordinal(index), level)}, so a grader cannot judge against them.`)];
|
|
3323
|
+
});
|
|
3324
|
+
return [...names, ...levels];
|
|
3209
3325
|
}
|
|
3210
3326
|
/** 150 words a minute: a fluent adult reading aloud. A learner is slower. */
|
|
3211
3327
|
const WORDS_PER_SECOND = 2.5;
|
|
@@ -4387,7 +4503,11 @@ const WrittenResponseRubricSchema = z.looseObject({
|
|
|
4387
4503
|
const RedactedWrittenResponseRubricCriterionSchema = z.strictObject({
|
|
4388
4504
|
name: z.string().min(1),
|
|
4389
4505
|
description: z.string().optional(),
|
|
4390
|
-
weight: z.number().min(0)
|
|
4506
|
+
weight: z.number().min(0),
|
|
4507
|
+
levels: z.array(z.strictObject({
|
|
4508
|
+
label: z.string().min(1),
|
|
4509
|
+
description: z.string().optional()
|
|
4510
|
+
})).min(2).max(10).optional()
|
|
4391
4511
|
});
|
|
4392
4512
|
const RedactedWrittenResponseRubricSchema = z.strictObject({
|
|
4393
4513
|
label: z.string().optional(),
|
|
@@ -4829,6 +4949,32 @@ function defineActivityType(descriptor) {
|
|
|
4829
4949
|
return descriptor;
|
|
4830
4950
|
}
|
|
4831
4951
|
//#endregion
|
|
4952
|
+
//#region src/registry/keep-when.ts
|
|
4953
|
+
/**
|
|
4954
|
+
* A nested field policy that keeps its field only when the field's value
|
|
4955
|
+
* passes a test. Internal: the symbol is never exported, so no host policy can
|
|
4956
|
+
* carry one, and `FieldPolicy`'s string keys never see it.
|
|
4957
|
+
*
|
|
4958
|
+
* It can only drop a field the policy would otherwise emit, never emit one it
|
|
4959
|
+
* would drop, so redaction stays fail-closed. It exists for a field
|
|
4960
|
+
* `validateActivity` does not check in 1.x — a rubric criterion's `levels` —
|
|
4961
|
+
* whose malformed values would otherwise reach the strict redacted schema and
|
|
4962
|
+
* make `redact()` throw on content it accepted before.
|
|
4963
|
+
*/
|
|
4964
|
+
const KEEP_WHEN = Symbol("lk.keepWhen");
|
|
4965
|
+
/** `policy`, kept only for values `test` accepts. */
|
|
4966
|
+
function keepWhen(policy, test) {
|
|
4967
|
+
const guarded = {
|
|
4968
|
+
...policy,
|
|
4969
|
+
[KEEP_WHEN]: test
|
|
4970
|
+
};
|
|
4971
|
+
return Object.freeze(guarded);
|
|
4972
|
+
}
|
|
4973
|
+
/** The test a nested policy keeps its field by, when it has one. */
|
|
4974
|
+
function guardOf(policy) {
|
|
4975
|
+
return policy[KEEP_WHEN];
|
|
4976
|
+
}
|
|
4977
|
+
//#endregion
|
|
4832
4978
|
//#region src/registry/builtins.ts
|
|
4833
4979
|
/**
|
|
4834
4980
|
* Field-sensitivity policies for the built-in types (R7). Fail-closed:
|
|
@@ -5046,7 +5192,11 @@ const RUBRIC_FIELD_POLICY = {
|
|
|
5046
5192
|
criteria: {
|
|
5047
5193
|
name: "public",
|
|
5048
5194
|
description: "public",
|
|
5049
|
-
weight: "public"
|
|
5195
|
+
weight: "public",
|
|
5196
|
+
levels: keepWhen({
|
|
5197
|
+
label: "public",
|
|
5198
|
+
description: "public"
|
|
5199
|
+
}, (value) => readRubricLevels(value).ok)
|
|
5050
5200
|
}
|
|
5051
5201
|
};
|
|
5052
5202
|
const WRITTEN_RESPONSE_FIELD_POLICY = {
|
|
@@ -5444,6 +5594,6 @@ function registeredActivityTypes() {
|
|
|
5444
5594
|
return [...registry.keys()];
|
|
5445
5595
|
}
|
|
5446
5596
|
//#endregion
|
|
5447
|
-
export {
|
|
5597
|
+
export { RedactedScoringError as $, levenshteinDistance as A, covers as B, READ_ALOUD_MAX_TAKES as C, RedactedMediaSchema as Ct, MultipleChoiceOptionMediaSchema as D, MultipleChoiceDataSchema as E, readRubricLevels as F, issue as G, isRecord as H, countWords as I, DictationDataSchema as J, pathKey as K, DRAFT_ISSUE_SEVERITY as L, LEVEL_PROBABILITY_TOLERANCE as M, levelDistribution as N, keyPositionFinding as O, levelKey as P, DeferredScoringError as Q, checkMedia as R, READ_ALOUD_MAX_SECONDS as S, MediaSchema as St, SPEECH_ASSESSMENT_MAX_WORDS as T, isUnset as U, isMissingId as V, isUnwritten as W, groupCaptionsField as X, GROUP_CAPTIONS_REVEAL_DICTATION as Y, ActivitySchemaError as Z, GapSelectDataSchema as _, fold as _t, readSchema as a, DICTATION_MAX_ACCEPTED_TRANSCRIPTS as at, READ_ALOUD_MAX_DIMENSION_WEIGHT as b, revealsAnswer as bt, dictationType as c, DICTATION_MAX_TEXT_LENGTH as ct, multipleChoiceType as d, normalizeDictationText as dt, UnknownActivityTypeError as et, readAloudType as f, withValidationScope as ft, WrittenResponseDataSchema as g, containsWords as gt, defineActivityType as h, isBuiltInActivityType as ht, isOwnSchema as i, dictationReferenceWords as it, matchText as j, normaliseFinding as k, fillInTheBlanksType as l, DICTATION_MAX_TRANSCRIPT_LENGTH as lt, guardOf as m, everyBuiltInTypeHandled as mt, registerActivityType as n, alignDictation as nt, standardJsonSchemaOf as o, DICTATION_MAX_EQUIVALENCES as ot, writtenResponseType as p, BUILT_IN_ACTIVITY_TYPES as pt, refusesEmpty as q, registeredActivityTypes as r, alignSequences as rt, MEDIA_FIELD_POLICY as s, DICTATION_MAX_EQUIVALENCE_LENGTH as st, getActivityTypeDescriptor as t, STEP as tt, gapSelectType as u, codePointLength as ut, ReadAloudDataSchema as v, numberedPassage as vt, SPEECH_ASSESSMENT_MAX_TEXT_LENGTH as w, maxUnits as wt, READ_ALOUD_MAX_REFERENCE_LENGTH as x, FillInTheBlanksDataSchema as xt, CANONICAL_LOCALE_RE as y, placeholderOrder as yt, coveredPathsOf as z };
|
|
5448
5598
|
|
|
5449
|
-
//# sourceMappingURL=registry-
|
|
5599
|
+
//# sourceMappingURL=registry-DaZRpqjW.js.map
|