// Grade a whole class overnight: one DebateWithJudge request per submission,
// submitted as a batch. Each proposed score lands in a review queue; the
// instructor confirms or changes every one before anything reaches the LMS.
const BATCH_API = "https://api.swarms.world/v1/swarm/batch/completions"
type Submission = { studentId: string; text: string }
type BatchResult = { output: unknown; usage: { input_tokens: number; output_tokens: number; total_tokens: number } }
const RUBRIC =
"Criterion: Use of evidence (0 to 4). 4: every claim is supported by a specific, correctly cited source " +
"and the student explains how it supports the claim. 3: most claims supported, explanation sometimes thin. " +
"2: evidence present but generic or unexplained. 1: little or no evidence."
const AGENTS = [
{ agent_name: "Criterion Advocate", system_prompt: "Argue the student met the criterion at the highest level the evidence supports. Quote the essay.", model_name: "claude-sonnet-5-5", max_loops: 1 },
{ agent_name: "Criterion Challenger", system_prompt: "Argue the essay falls short of the criterion. Quote the essay. Point to what is missing.", model_name: "gpt-5.4", max_loops: 1 },
{ agent_name: "Rubric Judge", system_prompt: "Weigh both arguments against the rubric text only. Return PROPOSED SCORE: n/4, the deciding evidence, and a one-line note for the instructor.", model_name: "claude-opus-5-5", max_loops: 1 },
]
export async function gradeClass(submissions: Submission[]) {
const batch = submissions.map((s) => ({
name: `Rubric Debate: Evidence ${s.studentId}`,
swarm_type: "DebateWithJudge",
task: `Decide how many points of 4 this essay earns on the criterion below. Quote the essay for every claim.\n\n${RUBRIC}\n\nESSAY:\n${s.text}`,
agents: AGENTS,
max_loops: 1,
}))
const res = await fetch(BATCH_API, {
method: "POST",
headers: {
"x-api-key": process.env.SWARMS_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify(batch),
})
if (!res.ok) throw new Error(`Swarms API ${res.status}: ${await res.text()}`)
const results = (await res.json()) as BatchResult[]
let tokens = 0
const queue = results.map((r, i) => {
tokens += r.usage.total_tokens
return { studentId: submissions[i].studentId, proposed: r.output, status: "awaiting instructor review" as const }
})
console.log(`${queue.length} proposed scores queued for review, ${tokens} tokens`)
return queue
}
gradeClass([
{ studentId: "s-0427", text: "Three districts that adopted uniforms reported ... [essay text]" },
{ studentId: "s-0431", text: "Uniforms are bad because everyone says so ... [essay text]" },
]).then((queue) => console.table(queue.map(({ studentId, status }) => ({ studentId, status }))))