openlearn-next 0.4.0 → 0.4.2
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/dist/assets/{BatchPickerModal-BobcoTtn.js → BatchPickerModal-BpWu0Lil.js} +1 -1
- package/dist/assets/ClassesView-KbHEqJto.js +22 -0
- package/dist/assets/{ClassroomCountdownWidget-AWnCu4JJ.js → ClassroomCountdownWidget-96WFRO9A.js} +1 -1
- package/dist/assets/{CloudDriveModal-Dr4kDySU.js → CloudDriveModal-DEQ1nkNk.js} +1 -1
- package/dist/assets/{CourseManagement-DtInD0J-.js → CourseManagement-D3ZpxY0l.js} +1 -1
- package/dist/assets/{CourseWizardModal-B16QBckO.js → CourseWizardModal-Ck_-M8pk.js} +1 -1
- package/dist/assets/{Dashboard-D1gZ_4NI.js → Dashboard-CYbpbofV.js} +1 -1
- package/dist/assets/{ExportWeightModal-UPsVax6L.js → ExportWeightModal-DW2bu9Zz.js} +1 -1
- package/dist/assets/{HelpView-BryOHwLE.js → HelpView-CtzdqhBq.js} +1 -1
- package/dist/assets/{ImportLessonsModal-Dnx_QR0Z.js → ImportLessonsModal-jBuIK453.js} +1 -1
- package/dist/assets/InteractiveCoursewareViewer-Bj7ahXMs.js +1 -0
- package/dist/assets/{InteractiveWhiteboard-550JMFBu.js → InteractiveWhiteboard-B7JcJvDu.js} +1 -1
- package/dist/assets/{LazyCourseware-CLHWQJ8g.js → LazyCourseware-CuiPxhDg.js} +2 -2
- package/dist/assets/{LazyWhiteboard-DJWh6sdV.js → LazyWhiteboard-BJwCEZAU.js} +2 -2
- package/dist/assets/LessonEditorView-DFrOp2qp.js +1 -0
- package/dist/assets/{LiveClassroomView-DgN2Zqe6.js → LiveClassroomView-BZ5nGee3.js} +2 -2
- package/dist/assets/{NotificationDetailModal-CMKHpWX1.js → NotificationDetailModal-Baqnc5pU.js} +1 -1
- package/dist/assets/{PluginView-BQVWPofY.js → PluginView-CCbIuZ24.js} +1 -1
- package/dist/assets/{QuizGeneratorModal-BeaBRn1w.js → QuizGeneratorModal-BBEDssp7.js} +1 -1
- package/dist/assets/StudentAssignmentView-DgIjUsXz.js +1 -0
- package/dist/assets/{StudentLessonView-CMPqL1ia.js → StudentLessonView-CBJbI5x6.js} +1 -1
- package/dist/assets/{StudentPreviewModal-0QSLnD9u.js → StudentPreviewModal-Bh8OZs0t.js} +1 -1
- package/dist/assets/{StudentView-9pjzjJgG.js → StudentView--uGxc5TJ.js} +2 -2
- package/dist/assets/{SystemResourceLibraryModal-COrhUd53.js → SystemResourceLibraryModal-BVCclcqA.js} +1 -1
- package/dist/assets/{TeacherView-mP2YucVr.js → TeacherView-D4Zsc0eZ.js} +2 -2
- package/dist/assets/{index-C70OJPV_.js → index-BKBCBKvy.js} +29 -29
- package/dist/index.html +1 -1
- package/dist/server.cjs +87 -16
- package/package.json +1 -1
- package/dist/assets/ClassesView-DtO0PJXQ.js +0 -22
- package/dist/assets/InteractiveCoursewareViewer-BYMKvIHi.js +0 -1
- package/dist/assets/LessonEditorView-DRwi0sjA.js +0 -1
- package/dist/assets/StudentAssignmentView-Dn4Bgqr2.js +0 -1
package/dist/index.html
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<meta name="description" content="An AI-powered Learning Management System featuring interactive classrooms, stage management, real-time student response systems, lesson editor, auto-grading, and an extensible third-party plugin ecosystem." />
|
|
8
8
|
<meta property="og:title" content="OpenLearn Next" />
|
|
9
9
|
<meta property="og:description" content="An AI-powered Learning Management System featuring interactive classrooms, stage management, real-time student response systems, lesson editor, auto-grading, and an extensible third-party plugin ecosystem." />
|
|
10
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
+
<script type="module" crossorigin src="/assets/index-BKBCBKvy.js"></script>
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/vendor-utils-m0Urvtws.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react-B0t7H3hh.js">
|
|
13
13
|
<link rel="modulepreload" crossorigin href="/assets/vendor-icons-BRmhY6fg.js">
|
package/dist/server.cjs
CHANGED
|
@@ -686,8 +686,27 @@ var init_ai_service = __esm({
|
|
|
686
686
|
AIService = class {
|
|
687
687
|
constructor(db2) {
|
|
688
688
|
this.db = db2;
|
|
689
|
+
/**
|
|
690
|
+
* 注册插件 AI 上下文切片提供者(P2: ai.context.provider)。
|
|
691
|
+
* fn 为服务端闭包(Inline 插件直接传函数),Agent 对话时按 lessonId 调用。
|
|
692
|
+
* 注册表真源在 server/ai-context-registry.ts,kernel AIService 委托写入。
|
|
693
|
+
*/
|
|
694
|
+
this._contextDelegates = {};
|
|
689
695
|
this.gateway = new AIProviderGateway(new AIEventBus());
|
|
690
696
|
}
|
|
697
|
+
/** 由 server 启动时接线(server/ai-context-registry.ts 的注册表为真源) */
|
|
698
|
+
bindContextRegistry(delegates) {
|
|
699
|
+
this._contextDelegates = delegates;
|
|
700
|
+
}
|
|
701
|
+
registerAIContextProvider(id, fn) {
|
|
702
|
+
if (!this._contextDelegates.register) {
|
|
703
|
+
throw new Error("[AIService] AI context registry not bound (server boot required)");
|
|
704
|
+
}
|
|
705
|
+
this._contextDelegates.register(id, fn);
|
|
706
|
+
}
|
|
707
|
+
unregisterAIContextProvider(id) {
|
|
708
|
+
this._contextDelegates.unregister?.(id);
|
|
709
|
+
}
|
|
691
710
|
async generateText(prompt, options) {
|
|
692
711
|
const provider = this.db.prepare(
|
|
693
712
|
"SELECT id, name, api_url, api_key, model_name FROM ai_providers WHERE api_key IS NOT NULL AND api_key != '' LIMIT 1"
|
|
@@ -1499,16 +1518,16 @@ function wrapCapability(capabilityService) {
|
|
|
1499
1518
|
})
|
|
1500
1519
|
};
|
|
1501
1520
|
}
|
|
1502
|
-
function wrapPointsDimensionRegistry(
|
|
1521
|
+
function wrapPointsDimensionRegistry(registry2) {
|
|
1503
1522
|
return {
|
|
1504
1523
|
registerDimension: createSafeFunction((spec) => {
|
|
1505
|
-
return
|
|
1524
|
+
return registry2.registerDimension(spec);
|
|
1506
1525
|
}),
|
|
1507
1526
|
getDimension: createSafeFunction((id) => {
|
|
1508
|
-
return
|
|
1527
|
+
return registry2.getDimension(id);
|
|
1509
1528
|
}),
|
|
1510
1529
|
listDimensions: createSafeFunction(() => {
|
|
1511
|
-
return
|
|
1530
|
+
return registry2.listDimensions();
|
|
1512
1531
|
})
|
|
1513
1532
|
};
|
|
1514
1533
|
}
|
|
@@ -1579,7 +1598,14 @@ function wrapAI(aiService) {
|
|
|
1579
1598
|
throw e;
|
|
1580
1599
|
}
|
|
1581
1600
|
}
|
|
1582
|
-
)
|
|
1601
|
+
),
|
|
1602
|
+
// P2: ai.context.provider —— 插件注册 AI 上下文切片(可选方法)
|
|
1603
|
+
registerAIContextProvider: createSafeFunction((id, fn) => {
|
|
1604
|
+
return aiService.registerAIContextProvider?.(id, fn);
|
|
1605
|
+
}),
|
|
1606
|
+
unregisterAIContextProvider: createSafeFunction((id) => {
|
|
1607
|
+
return aiService.unregisterAIContextProvider?.(id);
|
|
1608
|
+
})
|
|
1583
1609
|
};
|
|
1584
1610
|
}
|
|
1585
1611
|
async function buildContext(serviceRegistry, tracker, pluginId, manifest, db2, skipTokens, contributionRegistry) {
|
|
@@ -18779,9 +18805,9 @@ var AnalyticsCapabilityProviderHandler = class {
|
|
|
18779
18805
|
|
|
18780
18806
|
// packages/core/capability/invocation/invocation-engine.ts
|
|
18781
18807
|
var InvocationEngine = class {
|
|
18782
|
-
constructor(
|
|
18808
|
+
constructor(registry2, pipeline, eventBus) {
|
|
18783
18809
|
this.cancelledInvocations = /* @__PURE__ */ new Set();
|
|
18784
|
-
this.registry =
|
|
18810
|
+
this.registry = registry2;
|
|
18785
18811
|
this.pipeline = pipeline;
|
|
18786
18812
|
this.eventBus = eventBus;
|
|
18787
18813
|
}
|
|
@@ -18821,8 +18847,8 @@ var InvocationEngine = class {
|
|
|
18821
18847
|
|
|
18822
18848
|
// packages/core/capability/sdk/capability-sdk.ts
|
|
18823
18849
|
var CapabilitySDK = class {
|
|
18824
|
-
constructor(
|
|
18825
|
-
this.registry =
|
|
18850
|
+
constructor(registry2, engine, eventBus) {
|
|
18851
|
+
this.registry = registry2;
|
|
18826
18852
|
this.engine = engine;
|
|
18827
18853
|
this.eventBus = eventBus;
|
|
18828
18854
|
}
|
|
@@ -20855,6 +20881,43 @@ function attachClassroomFeedService(feedService, eventBus) {
|
|
|
20855
20881
|
};
|
|
20856
20882
|
}
|
|
20857
20883
|
|
|
20884
|
+
// server/ai-context-registry.ts
|
|
20885
|
+
var registry = {
|
|
20886
|
+
providers: /* @__PURE__ */ new Map()
|
|
20887
|
+
};
|
|
20888
|
+
function registerAIContextProvider(id, fn, registeredBy) {
|
|
20889
|
+
if (!id?.trim() || typeof fn !== "function") {
|
|
20890
|
+
throw new Error("[AIContextRegistry] id and provider function are required");
|
|
20891
|
+
}
|
|
20892
|
+
registry.providers.set(id.trim(), { fn, registeredBy });
|
|
20893
|
+
}
|
|
20894
|
+
function unregisterAIContextProvider(id, registeredBy) {
|
|
20895
|
+
const entry = registry.providers.get(id.trim());
|
|
20896
|
+
if (entry && registeredBy && entry.registeredBy && entry.registeredBy !== registeredBy) return;
|
|
20897
|
+
registry.providers.delete(id.trim());
|
|
20898
|
+
}
|
|
20899
|
+
function collectAIContextSlices(lessonId) {
|
|
20900
|
+
const slices = [];
|
|
20901
|
+
for (const [id, entry] of registry.providers) {
|
|
20902
|
+
try {
|
|
20903
|
+
const slice = entry.fn(lessonId);
|
|
20904
|
+
if (typeof slice === "string" && slice.trim()) {
|
|
20905
|
+
slices.push(`[Plugin Context \xB7 ${id}]
|
|
20906
|
+
${slice.trim()}`);
|
|
20907
|
+
}
|
|
20908
|
+
} catch (err) {
|
|
20909
|
+
console.error(`[AIContextRegistry] provider "${id}" failed:`, err);
|
|
20910
|
+
}
|
|
20911
|
+
}
|
|
20912
|
+
return slices;
|
|
20913
|
+
}
|
|
20914
|
+
function bindAIContextRegistry(kernelAIService) {
|
|
20915
|
+
kernelAIService.bindContextRegistry({
|
|
20916
|
+
register: (id, fn) => registerAIContextProvider(id, fn),
|
|
20917
|
+
unregister: (id) => unregisterAIContextProvider(id)
|
|
20918
|
+
});
|
|
20919
|
+
}
|
|
20920
|
+
|
|
20858
20921
|
// server.ts
|
|
20859
20922
|
var import_helmet = __toESM(require("helmet"), 1);
|
|
20860
20923
|
var import_express_rate_limit = __toESM(require("express-rate-limit"), 1);
|
|
@@ -21588,7 +21651,7 @@ function simpleChecksum(text) {
|
|
|
21588
21651
|
|
|
21589
21652
|
// server/ai-agent.ts
|
|
21590
21653
|
var import_crypto4 = __toESM(require("crypto"), 1);
|
|
21591
|
-
var buildAgentSystemInstruction = (lang, currentLessonId) => {
|
|
21654
|
+
var buildAgentSystemInstruction = (lang, currentLessonId, pluginSlices) => {
|
|
21592
21655
|
let systemInstruction = lang === "zh" ? "\u4F60\u662F\u4E00\u4E2A\u6559\u80B2\u7CFB\u7EDF\u5E95\u5C42\u7684 OS Agent\u3002\u4F60\u9700\u8981\u7406\u89E3\u8001\u5E08\u7684\u6307\u4EE4\uFF0C\u5E76\u8C03\u7528\u53EF\u7528\u7684\u5DE5\u5177\uFF08\u547D\u4EE4\uFF09\u53BB\u6267\u884C\u8FD9\u4E9B\u64CD\u4F5C\u3002\u5982\u679C\u8001\u5E08\u8BA9\u4F60\u521B\u5EFA\u4E00\u8282\u8BFE\uFF0C\u8BF7\u52A1\u5FC5\u5229\u7528\u5DE5\u5177\u751F\u6210\u8BE6\u7EC6\u7684\u521D\u59CB\u8BFE\u7A0B\u5185\u5BB9\u3002\u5982\u679C\u8001\u5E08\u8981\u6C42\u7BA1\u7406\u8FDB\u7A0B/\u4EFB\u52A1\uFF0C\u8BF7\u4F7F\u7528 process.spawn, process.kill, process.list\u3002\u5982\u679C\u9700\u5B58\u50A8\u6587\u4EF6\u3001\u7D20\u6750\u6216\u521B\u5EFA\u76EE\u5F55\uFF0C\u8BF7\u4F7F\u7528 vfs.* \u5E76\u5728\u9700\u8981\u65F6\u7BA1\u7406\u73ED\u7EA7\u548C\u5B66\u751F\u3002\u4F60\u652F\u6301\u901A\u8FC7 class_create \u521B\u5EFA\u73ED\u7EA7, student_create \u521B\u5EFA\u5B66\u751F, class_add_student \u5C06\u5B66\u751F\u52A0\u5165\u73ED\u7EA7\u3002\u5F53\u8001\u5E08\u8981\u6C42\u4ECE\u63D0\u4F9B\u7684\u6570\u636E\uFF08\u5982CSV\u3001JSON\u3001Markdown\u6216\u5BF9\u8BDD\u4E2D\uFF09\u521B\u5EFA\u73ED\u7EA7\u6216\u5B66\u751F\u65F6\uFF0C\u8BF7\u4F9D\u6B21\u53D1\u51FA\u8FD9\u4E9B\u6307\u4EE4\u3002\u5982\u679C\u4E0A\u4E00\u9636\u6BB5\u8FD4\u56DE\u4E86\u521B\u5EFA\u6210\u529F\u7684\u73ED\u7EA7ID\u6216\u5B66\u751FID\uFF0C\u4F60\u9700\u8981\u5728\u540E\u7EED\uFFFD? functionCall \u4E2D\u5F15\u7528\u8FD9\u4E9BID\uFF08\u4F8B\u5982\uFF1A\u628A\u521A\u521B\u5EFA\u7684\u5B66\u751FID\u52A0\u5165\u5230\u521A\u521B\u5EFA\u7684\u73ED\u7EA7ID\u4E2D\uFF09\u3002\u901A\u8FC7\u5F80\u590D\u7684\u5DE5\u5177\u8C03\u7528\uFF0C\u4F60\u53EF\u4EE5\u81EA\u52A8\u5B8C\u6210\u5B8C\u6574\u7684\u6D41\u7A0B\uFFFD?" : "You are an educational OS kernel agent. You interpret teacher instructions and use your available tools (commands) to execute them. If the teacher asks to create a lesson, always generate some detailed initial content for it. If the teacher asks to spawn or kill processes, use process tools. Use vfs tools to store assets, and manage classes/students as necessary. You support class_create, student_create, class_add_student. Always use tool chaining if you need to create a class and enroll students: first call class_create/student_create, receive their returned IDs, and then call class_add_student in the next turn. Always answer with a helpful summary.";
|
|
21593
21656
|
if (currentLessonId) {
|
|
21594
21657
|
systemInstruction += `
|
|
@@ -21596,6 +21659,9 @@ var buildAgentSystemInstruction = (lang, currentLessonId) => {
|
|
|
21596
21659
|
|
|
21597
21660
|
Available tools (functions) can be used multiple times in sequence if needed.`;
|
|
21598
21661
|
}
|
|
21662
|
+
if (pluginSlices?.length) {
|
|
21663
|
+
systemInstruction += "\n\n" + pluginSlices.join("\n\n");
|
|
21664
|
+
}
|
|
21599
21665
|
return systemInstruction;
|
|
21600
21666
|
};
|
|
21601
21667
|
var buildAgentFinalMessage = (message, attachments) => {
|
|
@@ -21728,7 +21794,11 @@ var runGeminiAgentChat = async (request) => {
|
|
|
21728
21794
|
};
|
|
21729
21795
|
var runOpenAIAgentChat = async (provider, request) => {
|
|
21730
21796
|
const { message, lang = "zh", currentLessonId, attachments, callerRole, history } = request;
|
|
21731
|
-
const systemInstruction = buildAgentSystemInstruction(
|
|
21797
|
+
const systemInstruction = buildAgentSystemInstruction(
|
|
21798
|
+
lang,
|
|
21799
|
+
currentLessonId,
|
|
21800
|
+
collectAIContextSlices(currentLessonId ?? null)
|
|
21801
|
+
);
|
|
21732
21802
|
const finalMessage = buildAgentFinalMessage(message, attachments);
|
|
21733
21803
|
const tools = buildOpenAITools();
|
|
21734
21804
|
const chatUrl = buildOpenAIChatUrl(provider.api_url);
|
|
@@ -22389,13 +22459,13 @@ var OFFICIAL_ACTIVITY_DEFINITIONS = [
|
|
|
22389
22459
|
commandType: "assignment.create"
|
|
22390
22460
|
}
|
|
22391
22461
|
];
|
|
22392
|
-
function registerOfficialActivities(
|
|
22462
|
+
function registerOfficialActivities(registry2, actionRegistry) {
|
|
22393
22463
|
for (const def of OFFICIAL_ACTIVITY_DEFINITIONS) {
|
|
22394
22464
|
const descriptor = {
|
|
22395
22465
|
...def,
|
|
22396
22466
|
aiAction: aiActionFor(def)
|
|
22397
22467
|
};
|
|
22398
|
-
|
|
22468
|
+
registry2.registerProvider(new BaseActivityProvider({ descriptor }));
|
|
22399
22469
|
if (actionRegistry && descriptor.aiAction) {
|
|
22400
22470
|
actionRegistry.register(descriptor.aiAction);
|
|
22401
22471
|
}
|
|
@@ -23237,9 +23307,9 @@ var BLOCKED_EXTENSIONS = [".exe", ".sh", ".bat", ".cmd", ".dll", ".so", ".dylib"
|
|
|
23237
23307
|
function collectCoursewareRuntimeScripts(cwInfo) {
|
|
23238
23308
|
const empty = { head: "", bodyEnd: "" };
|
|
23239
23309
|
try {
|
|
23240
|
-
const
|
|
23241
|
-
if (!
|
|
23242
|
-
const scripts =
|
|
23310
|
+
const registry2 = kernelContainer?.serviceRegistry?.resolve?.(ICoursewareRuntimeScriptRegistryToken);
|
|
23311
|
+
if (!registry2 || typeof registry2.list !== "function") return empty;
|
|
23312
|
+
const scripts = registry2.list({ id: cwInfo.id, uuid: cwInfo.uuid }) || [];
|
|
23243
23313
|
if (!scripts.length) return empty;
|
|
23244
23314
|
let head = "";
|
|
23245
23315
|
let bodyEnd = "";
|
|
@@ -33366,6 +33436,7 @@ async function startServer() {
|
|
|
33366
33436
|
registerClassroomExtrasRoutes(ctx.app);
|
|
33367
33437
|
registerClassroomPeerReviewRoutes(ctx.app);
|
|
33368
33438
|
setupRealtimeBridge({ eventBus: kernelContainer.eventBus, io, db: kernelContainer.db });
|
|
33439
|
+
bindAIContextRegistry(kernelContainer.aiService);
|
|
33369
33440
|
setupPresence({
|
|
33370
33441
|
io,
|
|
33371
33442
|
eventBus: kernelContainer.eventBus,
|