urlHosted mode: If using hosted OpenMAIC (open.maic.chat), all preconditions (repo, startup, provider keys) are already satisfied. Include
Authorization: Bearer <access-code>header on all requests below. See hosted-mode.md for details.
If the user has already clearly asked to generate the classroom and the preconditions are satisfied, submit the generation job immediately. Do not ask for a second confirmation just before calling /api/generate-classroom.
Submit the job with:
POST {url}/api/generate-classroom
Request body:
{
"requirement": "Create an introductory classroom on quantum mechanics for high school students"
}
Only send supported content fields:
requirement (required)pdfContentlanguage ("zh-CN" | "en-US", defaults to "zh-CN") — any other value silently falls back to "zh-CN"enableWebSearch (boolean) — include web search context in outline generationenableImageGeneration (boolean) — allow image generation metadata in outlinesenableVideoGeneration (boolean) — allow video generation metadata in outlinesenableTTS (boolean) — enable server-side TTS audio generation for speech actionsagentMode ("default" | "generate") — controls agent profile strategy:
"default" (or omitted): uses built-in default agents"generate": uses LLM to generate custom agent profiles tailored to the course contentAll optional boolean fields default to false when omitted. Omitting them preserves backward compatibility.
Before sending optional feature flags, query GET {url}/api/health and check the capabilities object:
{
"status": "ok",
"version": "...",
"capabilities": {
"webSearch": true,
"imageGeneration": false,
"videoGeneration": false,
"tts": true
}
}
Only set a feature flag to true if the corresponding capability is true. If the server does not return capabilities (older version), do not send the new fields.
Do not rely on request-time model or provider override parameters.
Treat the POST response as job submission only. Expect fields such as:
{
"success": true,
"jobId": "abc123",
"status": "queued",
"step": "queued",
"pollUrl": "http://localhost:3000/api/generate-classroom/abc123",
"pollIntervalMs": 5000
}
Parse the PDF first:
POST {url}/api/parse-pdf
Then send requirement plus pdfContent to:
POST {url}/api/generate-classroom
After the job is submitted:
jobId, pollUrl, and pollIntervalMs.queued or running.Poll:
GET {pollUrl}
Prefer a conservative polling cadence of about 60 seconds between polls for classroom generation jobs, even if pollIntervalMs is shorter.
Treat queued and running as in-progress states.
Stop only when status becomes succeeded or failed.
5xx, wait about 60 seconds and retry the same pollUrl.jobId and pollUrl so a later turn can continue checking without resubmitting.status, step, or visible progress meaningfully changes. Do not spam every poll result.failed, surface the server error and include the jobId.succeeded, use result.classroomId and result.url from the final poll response.If the job is still running when you stop active polling for this turn, tell the user that the classroom generation is still running in the background and invite them to come back a little later to continue checking the same job.
Use natural phrasing such as:
The classroom generation is still running in the background.
Job ID: abc123
Check back with me in a little while and I can continue tracking this same job without starting over.
Return the generated classroom ID plus a directly clickable classroom URL.
Output the URL as a raw absolute URL on its own line.
Do not wrap the URL in:
**...**[title](url)`...`<...>Use a compact format like:
Classroom ID: Uyh82Y32ZK
Classroom URL:
http://localhost:3001/classroom/Uyh82Y32ZK
If the job fails, return the job ID plus the server error.
If generation fails, surface the server error directly instead of paraphrasing it away.
If the error suggests a provider or model configuration problem, explicitly tell the user to update .env.local or server-providers.yml instead of attempting a runtime override.