feat: productionize learning engine and classroom

This commit is contained in:
inman
2026-08-16 21:44:52 +08:00
parent 2d04197f3f
commit ba35adfbfa
124 changed files with 9071 additions and 796 deletions

View File

@@ -28,6 +28,7 @@ import { USER_AVATAR } from '@/lib/types/roundtable';
import { StreamBuffer } from '@/lib/buffer/stream-buffer';
import type { AgentStartItem, ActionItem } from '@/lib/buffer/stream-buffer';
import { runAgentLoop, type AgentLoopStoreState } from '@/lib/chat/agent-loop';
import { fetchMakeloreLearningAgent } from '@/lib/makelore-runtime/browser-bridge';
import { ActionEngine } from '@/lib/action/engine';
import {
buildQuizResultsForStoreState,
@@ -1142,6 +1143,33 @@ export function useChatSessions(options: UseChatSessionsOptions = {}) {
requestTemplate.config.agentConfigs = generatedConfigs;
}
if (window.__MAKELORE_OFFLINE_PLAYER__) {
const streamConsumer = createStatelessStreamConsumer(sessionId, controller, sessionType);
const storeState = await buildFreshAgentLoopStoreState();
const response = await fetchMakeloreLearningAgent({
messages: requestTemplate.messages,
storeState,
}, controller.signal);
if (!response.ok) throw new Error(await response.text());
const reader = response.body?.getReader();
if (!reader) throw new Error('助教没有返回内容');
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const chunk = await reader.read();
if (chunk.done) break;
buffer += decoder.decode(chunk.value, { stream: true });
const frames = buffer.split('\n\n');
buffer = frames.pop() || '';
for (const frame of frames) {
const data = frame.split('\n').find((line) => line.startsWith('data: '));
if (data) streamConsumer.onEvent(JSON.parse(data.slice(6)) as StatelessEvent);
}
}
await streamConsumer.onIterationEnd();
return;
}
if (isPiChatEnabled()) {
// Pi bypasses runAgentLoop's per-iteration getStoreState, so its single
// request needs the snapshot built here — /api/chat/pi rejects bodies